• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

PHP之验证码识别

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

首先推荐几篇有关验证码识别的文章,觉得不错

php实现验证码的识别(初级篇)

关于bp神经网格识别验证码

一、思路

碰见一个验证码,如果我们想要识别它,我们需要的是做什么呢?
我们先观察几个验证码............


我们用人眼去观察,会很显然的认出验证码所包含的字符,那么人眼的“识别机理”是什么呢?
大概是验证码图片字符的背景的颜色区别吧,试想,如果字符和背景没有颜色区别,我们能够判断验证码吗,很显然不能。

所以,我们就可以从人出发。

先从图片的颜色着手,即图片的RGB信息。

RGB色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。

定义函数取得RGB信息

 1 //代码本来是一个类,现在拆开来写的,有可能有不严谨的地方,大家可以看得懂就好了
 2 
 3 /*
 4  *取得图片路径和图片尺寸
 5  */
 6 $this->ImagePath = $Image;
 7 $this->ImageSize = getimagesize($Image);
 8 
 9 /*
10  *获取图像标识符,保存到ImageInfo,只能处理bmp,png,jpg图片
11  *ImageCreateFromBmp是我自己定义的函数,最后会给出
12  */
13 function getInfo(){
14     $filetype = substr($this->ImagePath,-3);
15     if($filetype == 'bmp'){
16         $this->ImageInfo = $this->ImageCreateFromBmp($this->ImagePath);
17     }elseif($filetype == 'jpg'){
18         $this->ImageInfo = imagecreatefromjpeg($this->ImagePath);    
19     }elseif($filetype == 'png'){
20         $this->ImageInfo = imagecreatefrompng($this->ImagePath);    
21     }
22 }
23 
24 /*获取图片RGB信息*/
25 function getRgb(){
26     $rgbArray = array();
27     $res = $this->ImageInfo;
28     $size = $this->ImageSize;
29     $wid = $size['0'];
30     $hid = $size['1'];
31     for($i=0; $i < $hid; ++$i){
32         for($j=0; $j < $wid; ++$j){
33             $rgb = imagecolorat($res,$j,$i);
34             $rgbArray[$i][$j] = imagecolorsforindex($res, $rgb);
35         }
36     }
37     return $rgbArray;
38 }

 

 

二、二值化

因为人眼可以分别出验证码,所以验证码的RGB信息就会有一定的特点,这时候需要我们观察一下,直接打印RGB数组是不好观察的…………,好多数啊

php实现验证码的识别(初级篇)中,作者的判断依据是

无论验证数字颜色如何变化,该数字的 RGB 值总有一个值小于 125

我们先获取他的灰度,再判断

 1 /*
 2  *获取灰度信息
 3  */
 4 function getGray(){
 5     $grayArray = array();
 6     $size = $this->ImageSize;
 7     $rgbarray = $this->getRgb();
 8     $wid = $size['0'];
 9     $hid = $size['1'];
10     for($i=0; $i < $hid; ++$i){
11         for($j=0; $j < $wid; ++$j){
12             $grayArray[$i][$j] = (299*$rgbarray[$i][$j]['red']+587*$rgbarray[$i][$j]['green']+144*$rgbarray[$i][$j]['blue'])/1000;
13         }
14     }
15     return $grayArray;
16 }

 

 

然后我们根据灰度信息,打印图片,注意不是打印灰度信息

 1 /*根据灰度信息打印图片*/
 2 function printByGray(){
 3     $size = $this->ImageSize;    
 4     $grayArray = $this->getGray();
 5     $wid = $size['0'];
 6     $hid = $size['1'];
 7     for($k=0;$k<25;$k++){
 8         echo $k."\n";
 9         for($i=0; $i < $hid; ++$i){
10             for($j=0; $j < $wid; ++$j){
11                 if($grayArray[$i][$j] < $k*10){
12                     echo '■';
13                 }else{
14                     echo '□';
15                 }
16             }
17             echo "|\n";
18         }
19         echo "---------------------------------------------------------------------------------------------------------------\n";
20     }
21     
22 }

 

注意到,从$grayArray[$i][$j] < 80就会有显然的输出,我们观察选择了一个恰当的阈值,得到一个0101的数组,我们已经将我们的图片转化为了字符(1)和背景(0),即二值化。

 1 /*
 2  *根据自定义的规则,获取二值化二维数组
 3  *@return  图片高*宽的二值数组(0,1)
 4  */
 5 function getErzhi(){
 6     $erzhiArray = array();
 7     $size = $this->ImageSize;
 8     $grayArray = $this->getGray();
 9     $wid = $size['0'];
10     $hid = $size['1'];
11     for($i=0; $i < $hid; ++$i){
12         for($j=0; $j <$wid; ++$j){
13             if( $grayArray[$i][$j]    < 90 ){
14                 $erzhiArray[$i][$j]=1;
15             }else{
16                 $erzhiArray[$i][$j]=0;
17             }
18         }
19     }
20     return $erzhiArray;
21 }

 

 

三、去除噪点

但是我们发现有一些小点影响了我们的判断

我们可以注意到这些事干扰噪点,但是如果我们是机器的话,我们如何判断这些点是否是字符呢?

 

所以接下来,我们需要将这些字符去除。

我们判断,如果一个黑点的上下左右的八个点全部是白,我们就认为它是噪点,并予以清除,赋为白

 1 /*
 2  *二值化图片降噪
 3  *@param $erzhiArray二值化数组
 4  */
 5 function reduceZao($erzhiArray){
 6     $data = $erzhiArray;
 7     $gao = count($erzhiArray);
 8     $chang = count($erzhiArray['0']);
 9 
10     $jiangzaoErzhiArray = array();
11 
12     for($i=0;$i<$gao;$i++){
13         for($j=0;$j<$chang;$j++){
14             $num = 0;  
15             if($data[$i][$j] == 1)  
16             {
17                 //
18                 if(isset($data[$i-1][$j])){  
19                     $num = $num + $data[$i-1][$j];  
20                 }  
21                 //
22                 if(isset($data[$i+1][$j])){  
23                     $num = $num + $data[$i+1][$j];  
24                 }  
25                 //
26                 if(isset($data[$i][$j-1])){  
27                     $num = $num + $data[$i][$j-1];  
28                 }  
29                 //
30                 if(isset($data[$i][$j+1])){  
31                     $num = $num + $data[$i][$j+1];  
32                 }  
33                 // 上左  
34                 if(isset($data[$i-1][$j-1])){  
35                     $num = $num + $data[$i-1][$j-1];  
36                 }  
37                 // 上右  
38                 if(isset($data[$i-1][$j+1])){  
39                     $num = $num + $data[$i-1][$j+1];  
40                 }  
41                 // 下左  
42                 if(isset($data[$i+1][$j-1])){  
43                     $num = $num + $data[$i+1][$j-1];  
44                 }  
45                 // 下右  
46                 if(isset($data[$i+1][$j+1])){  
47                     $num = $num + $data[$i+1][$j+1];  
48                 }  
49             }
50 
51                 if($num < 1){  
52                     $jiangzaoErzhiArray[$i][$j] = 0;  
53                 }else{
54                     $jiangzaoErzhiArray[$i][$j] = 1;  
55                 }
56         }
57     }
58     return $jiangzaoErzhiArray;    
59 
60 }

 

 

我们发现噪点消失了。

 

四、分割

这个时候,我们就需要对单一数字字母进行操作了,我们先将数字提取出来。

有些验证码字符相连,特别难!!!

我们分别从左到右,从右到左,从上到下,从下到上,进行扫描,去除白点,找到边框。

 1 /*
 2  *归一化处理,针对一个个的数字,即去除字符周围的白点
 3  *@param $singleArray 二值化数组
 4  */
 5 function getJinsuo($singleArray){
 6     $dianCount = 0;
 7     $rearr = array();
 8     
 9     $gao = count($singleArray);
10     $kuan = count($singleArray['0']);
11     
12     $dianCount = 0;
13     $shangKuang = 0;
14     $xiaKuang = 0;
15     $zuoKuang = 0;
16     $youKuang = 0;
17     //从上到下扫描
18     for($i=0; $i < $gao; ++$i){
19         for($j=0; $j < $kuan; ++$j){
20             if( $singleArray[$i][$j] == 1){
21                 $dianCount++;
22             }
23         }
24         if($dianCount>1){
25             $shangKuang = $i;
26             $dianCount = 0;
27             break;
28         }
29     }
30     //从下到上扫描
31     for($i=$gao-1; $i > -1; $i--){
32         for($j=0; $j < $kuan; ++$j){
33             if( $singleArray[$i][$j] == 1){
34                 $dianCount++;
35             }
36         }
37         if($dianCount>1){
38             $xiaKuang = $i;
39             $dianCount = 0;
40             break;
41         }
42     }
43     //从左到右扫描
44     for($i=0; $i < $kuan; ++$i){
45         for($j=0; $j < $gao; ++$j){
46             if( $singleArray[$j][$i] == 1){
47                 $dianCount++;
48             }
49         }
50         if($dianCount>1){
51             $zuoKuang = $i;
52             $dianCount = 0;
53             break;
54         }
55     }
56     //从右到左扫描
57     for($i=$kuan-1; $i > -1; --$i){
58         for($j=0; $j < $gao; ++$j){
59             if( $singleArray[$j][$i] == 1){
60                 $dianCount++;
61             }
62         }
63         if($dianCount>1){
64             $youKuang = $i;
65             $dianCount = 0;
66             break;
67         }
68     }
69     for($i=0;$i<$xiaKuang-$shangKuang+1;$i++){
70         for($j=0;$j<$youKuang-$zuoKuang+1;$j++){
71             $rearr[$i][$j] = $singleArray[$shangKuang+$i][$zuoKuang+$j];
72         }
73     }
74     return $rearr;
75 }

 

 

然后从左到右扫描,找到字符的分割

返回三维数组,每一维就是一个字符。

 1 /*
 2  *切割成三维数组,每个小数字在一个数组里面
 3  *只适用四个数字一起的数组
 4  *@param 经过归一化处理的二值化数组
 5  */
 6 function cutSmall($erzhiArray){
 7     $doubleArray = array();
 8     $jieZouyou = array();
 9     
10     $gao = count($erzhiArray);
11     $kuan = count($erzhiArray['0']);
12     
13     $jie = 0;
14     $s = 0;
15     $jieZouyou[$s] = 0;
16     $s++;
17     //从左到右扫描
18     
19     for($i=0; $i < $kuan;){
20         for($j=0; $j < $gao; ++$j){
21             $jie = $jie + $erzhiArray[$j][$i];
22         }
23         //如果有一列全部是白,设置$jieZouyou,并且跳过中间空白部分
24         if($jie == 0){
25             $jieZouyou[$s] = $i+1;
26             do{
27                 $n = ++$i;
28                 $qian = 0;
29                 $hou = 0;
30                 for($m=0; $m < $gao; ++$m){
31                     $qian = $qian + $erzhiArray[$m][$n];
32                     $hou = $hou + $erzhiArray[$m][$n+1];                        
33                 }
34                 $jieZouyou[$s+1] = $n+1;
35             }
36             //当有两列同时全部为白,说明有间隙,循环,知道间隙没有了
37             while($qian == 0 && $hou == 0);
38             $s+=2;
39             $i++;
40         }else{
41             $i++;    
42         }
43         
44         $jie = 0;
45     }
46     $jieZouyou[] = $kuan;
47     //极端节点数量,(应该是字符个数)*2
48     $jieZouyouCount = count($jieZouyou);
49     
50     for($k=0;$k<$jieZouyouCount/2;$k++){
51         for($i=0; $i < $gao; $i++){
52             for($j=0; $j < $jieZouyou[$k*2+1]-$jieZouyou[$k*2]-1; ++$j){
53                 $doubleArray[$k][$i][$j] = $erzhiArray[$i][$j+$jieZouyou[$k*2]];
54             }
55         }
56         
57     }
58     return $doubleArray;
59 }

 

五、倾斜调整

我们发现第三个9有一点倾斜,

我们需要将倾斜的图片“正”过来

人怎么处理的呢,先眼睛观察“倾斜了多少度”,然后把图片扭过来多少度,并且观察->负反馈->大


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
PHPstream_wrapper_register发布时间:2022-07-10
下一篇:
WindowsServer2003IIS6.0+PHP5(FastCGI)+MySQL5环境搭建教程发布时间:2022-07-10
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap