其實圖像識別技術與我們平時做的密碼驗證之類的沒有什么區別,都是事先把要校驗的數據入庫,然后使用時將錄入(識別)的數據與庫中的數據做對比,只不過圖像識別技術有一部分的容錯性,而我們平時的密碼驗證是要100%匹配。
前幾天,有朋友談到做游戲點擊抽獎,識別圖片中的文字,當時立馬想到的就是js控制或者flash做遮罩層,感覺這種辦法是最方便快捷效果好,而且節省服務器資源,但是那邊提的要求竟然是通過php識別圖像中的文字。
趕巧那兩天的新聞有:1、馬云人臉識別支付;2、12306使用新的驗證碼,說什么現在國內的搶票軟件都不能用了,發布不到一天就被破解。然后又很湊巧的那天早上看了一篇java的圖像識別技術文章。于是就琢磨著看一下php的圖像識別技術。
其實所謂的圖像識別,已經不是什么新技術了,起碼我找到的資料都是很早之前的了。只不過我一直沒涉及到這方面的工作,就一直沒看過。
先說下這次實驗的需求:有一張圖片,里面三個位置分別有三個數字,要求取出相應位置的數字的值。(眼尖的同學可能會看出下面的代碼是我拿的別人的,沒錯,的確是我直接copy別人并刪減的,畢竟我對這些也是淺嘗輒止,最后會貼出原作者的初始代碼)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
class gjphone { protected $imgpath ; // 圖片路徑 protected $imgsize ; // 圖片大小 protected $hecdata ; // 分離后數組 protected $hordata ; // 橫向整理的數據 protected $verdata ; // 縱向整理的數據 function __construct ( $path ) { $this ->imgpath = $path ; } public function gethec () { $size = getimagesize ( $this ->imgpath); $res = imagecreatefrompng( $this ->imgpath); for ( $i = 0; $i < $size [1]; ++ $i ) { for ( $j = 0; $j < $size [0]; ++ $j ) { $rgb = imagecolorat( $res , $j , $i ); $rgbarray = imagecolorsforindex( $res , $rgb ); if ( $rgbarray [ 'red' ] < 125 || $rgbarray [ 'green' ] < 125 || $rgbarray [ 'blue' ] < 125) { $data [ $i ][ $j ] = 1; } else { $data [ $i ][ $j ] = 0; } } } $this ->imgsize = $size ; $this ->hecdata = $data ; } public function maghordata () { $data = $this ->hecdata; $size = $this ->imgsize; $z = 0; for ( $i = 0; $i < $size [1]; ++ $i ) { if (in_array( '1' , $data [ $i ])) { $z ++; for ( $j = 0; $j < $size [0]; ++ $j ) { if ( $data [ $i ][ $j ] == '1' ) { $newdata [ $z ][ $j ] = 1; } else { $newdata [ $z ][ $j ] = 0; } } } } return $this ->hordata = $newdata ; } public function showphone ( $ndatas ) { error_reporting (0); $phone = null; $d = 0; foreach ( $ndatas as $key => $val ) { if (in_array(1, $val )) { foreach ( $val as $k => $v ) { $ndarr [ $d ] .= $v ; } } if (! in_array(1, $val )) { $d ++; } } foreach ( $ndarr as $key01 => $val01 ) { $phone .= $this ->initdata( $val01 ); } return $phone ; } /** * 初始數據 */ public function initdata ( $numstr ) { $result = null; $data = array ( '1' => '00000000111000000000000001110000000001001000100000000010100011000000000011000110000000000110000100000000010110011000000' , '5' => '00000000001000000000000000010000000000100100100000000000101001110000000000100000110000000011000000100000001101000010000' , '10' => '00000011100011100000000011001100100100100010010001000110000100100010001100001001000100011000010010001001001001100010100' ); foreach ( $data as $key => $val ) { similar_text( $numstr , $val , $pre ); if ( $pre > 95) { // 相似度95%以上 $result = $key ; break ; } } return $result ; } } $imgurl = 'jd.png' ; list ( $width , $heght , $type , $attr ) = getimagesize ( $imgurl ); $new_w = 17; $new_h = 11; $thisimage = imagecreatetruecolor( $new_w , $new_h ); // $new_w, $new_h 為裁剪后的圖片寬高 $background = imagecolorallocate( $thisimage , 255, 255, 255); imagefilledrectangle( $thisimage , 0, 0, $new_w , $new_h , $background ); $oldimg = imagecreatefrompng( $imgurl ); // 載入原始圖片 // 首先定位要取圖的位置(這里可以通過前端js或者其他手段定位,由于我這是測試,所以就ps定位并寫死了) $weizhi = array ( '1' => 165, '5' => 308, '10' => 456 ); foreach ( $weizhi as $wwzz ) { $src_y = 108; imagecopy( $thisimage , $oldimg , 0, 0, $wwzz , $src_y , $new_w , $new_h ); // $src_y,$new_w為原圖中裁剪區域的左上角坐標拷貝圖像的一部分將src_im圖像中坐標從src_x,src_y開始,寬度為src_w,高度為src_h的一部分拷貝到dst_im圖像中坐標為dst_x和dst_y的位置上。 $tem_png = 'tem_1.png' ; imagepng( $thisimage , __dir__ . '/' . $tem_png ); // 通過定位從原圖中copy出想要識別的位置并生成新的緩存圖,用以后面的圖像識別類使用。 $gjphone = new gjphone( $tem_png ); // 實例化類 $gjphone ->gethec(); // 進行圖像像素分離 $hordata = $gjphone ->maghordata(); // 將分離出是數據轉成01表示的圖像、這里可以根據自己喜好定 $phone = $gjphone ->showphone( $hordata ); // 將轉換好的01表示的數據與庫中的數據進行匹配,匹配度95以上就算成功,庫這里由于是做測試就直接寫了數組 echo '| ' . $phone . ' | ' ; } |
如此看來,其實12306驗證碼被破解也算是有情可原了,也沒必要那么的口誅筆伐了罷。只要不斷的抓驗證碼圖片并轉成自己程序可讀的數據存入庫里,然后驗證的時候進行匹配就可以了。那么阿里的人臉識別支付原理也算是理解了,只不過他們做的可能會很精細。
前端時間有看到阿里云的一個驗證碼形式,剛開始感覺可能會好點,現在看來,只要有心,其實也是可以破解的啊。
好了,下面是原作代碼。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
|
/** * 電話號碼識別. * @author by zsc for 2010.03.24 */ class gjphone { protected $imgpath ; // 圖片路徑 protected $imgsize ; // 圖片大小 protected $hecdata ; // 分離后數組 protected $hordata ; // 橫向整理的數據 protected $verdata ; // 縱向整理的數據 function __construct ( $path ) { $this ->imgpath = $path ; } /** * 顏色分離轉換... * * @param unknown_type $path * @return unknown */ public function gethec () { $size = getimagesize ( $this ->imgpath); $res = imagecreatefrompng( $this ->imgpath); for ( $i = 0; $i < $size [1]; ++ $i ) { for ( $j = 0; $j < $size [0]; ++ $j ) { $rgb = imagecolorat( $res , $j , $i ); $rgbarray = imagecolorsforindex( $res , $rgb ); if ( $rgbarray [ 'red' ] < 125 || $rgbarray [ 'green' ] < 125 || $rgbarray [ 'blue' ] < 125) { $data [ $i ][ $j ] = 1; } else { $data [ $i ][ $j ] = 0; } } } $this ->imgsize = $size ; $this ->hecdata = $data ; } /** * 顏色分離后的數據橫向整理... * * @return unknown */ public function maghordata () { $data = $this ->hecdata; $size = $this ->imgsize; $z = 0; for ( $i = 0; $i < $size [1]; ++ $i ) { if (in_array( '1' , $data [ $i ])) { $z ++; for ( $j = 0; $j < $size [0]; ++ $j ) { if ( $data [ $i ][ $j ] == '1' ) { $newdata [ $z ][ $j ] = 1; } else { $newdata [ $z ][ $j ] = 0; } } } } return $this ->hordata = $newdata ; } /** * 整理縱向數據... * * @return unknown */ public function magverdata ( $newdata ) { for ( $i = 0; $i < 132; ++ $i ) { for ( $j = 1; $j < 13; ++ $j ) { $ndata [ $i ][ $j ] = $newdata [ $j ][ $i ]; } } $sum = count ( $ndata ); $c = 0; for ( $a = 0; $a < $sum ; $a ++) { $value = $ndata [ $a ]; if (in_array(1, $value )) { $ndatas [ $c ] = $value ; $c ++; } elseif ( is_array ( $ndatas )) { $b = $c - 1; if (in_array(1, $ndatas [ $b ])) { $ndatas [ $c ] = $value ; $c ++; } } } return $this ->verdata = $ndatas ; } /** * 顯示電話號碼... * * @return unknown */ public function showphone ( $ndatas ) { $phone = null; $d = 0; foreach ( $ndatas as $key => $val ) { if (in_array(1, $val )) { foreach ( $val as $k => $v ) { $ndarr [ $d ] .= $v ; } } if (! in_array(1, $val )) { $d ++; } } foreach ( $ndarr as $key01 => $val01 ) { $phone .= $this ->initdata( $val01 ); } return $phone ; } /** * 分離顯示... * * @param unknown_type $dataarr */ function drawwh ( $dataarr ) { if ( is_array ( $dataarr )) { foreach ( $dataarr as $key => $val ) { foreach ( $val as $k => $v ) { if ( $v == 0) { $c .= "<font color='#ffffff'>" . $v . "</font>" ; } else { $c .= $v ; } } $c .= "<br/>" ; } } echo $c ; } /** * 初始數據... * * @param unknown_type $numstr * @return unknown */ public function initdata ( $numstr ) { $result = null; $data = array ( 0 => '000011111000001111111110011000000011110000000001110000000001110000000001110000000001011000000011011100000111000111111100000001110000' , 1 => '011000000000011000000000111111111111111111111111' , 2 => '001000000011011000000111110000001101110000011001110000011001110000110001111001100001011111100001000110000001' , 3 => '001000000010011000000011110000000001110000000001110000110001110000110001011001110011011111011111000110001100' , 4 => '000000001100000000111100000001111100000011101100000111001100001100001100011000001100111111111111111111111111000000001100000000000100' , 5 => '111111000001111111000001110001000001110001000001110001100001110001100001110000110011110000111111000000001100' , 6 => '000011111000001111111110011000110011110001100001110001100001110001100001110001100001010001110011010000111111000000001100' , 7 => '110000000000110000000111110000111111110001110000110111000000111100000000111000000000111000000000' , 8 => '000100011110011111111111110011100001110001100001110001100001110001100001110011100001011111111111000100011110' , 9 => '001111000000011111100001110000110001110000110001110000110001110000110001011000100001011111100111000111111110000001110000' ); foreach ( $data as $key => $val ) { similar_text( $numstr , $val , $pre ); if ( $pre > 95) { // 相似度95%以上 $result = $key ; break ; } } return $result ; } } $imgpath = "http://bj.ganji.com/tel/5463013757650d6c5e31093e563c51315b6c5c6c5237.png" ; $gjphone = new gjphone( $imgpath ); // 進行顏色分離 $gjphone ->gethec(); // 畫出橫向數據 $hordata = $gjphone ->maghordata(); echo "===============橫向數據==============<br/><br/><br/>" ; $gjphone ->drawwh( $hordata ); // 畫出縱向數據 $verdata = $gjphone ->magverdata( $hordata ); echo "<br/><br/><br/>===============縱向數據==============< br/><br/><br/>" ; $gjphone ->drawwh( $verdata ); // 輸出電話 $phone = $gjphone ->showphone( $verdata ); echo "<br/><br/><br/>===============電話==============<br /><br/><br/>" . $phone ; |
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。