在 php 识别验证码(一)当中说了基本的识别验证码的方法,及其关键的代码,但是最后我们留下了一个问题,就是对于有旋转的验证码的识别率及其低下的问题,下面来解决这个问题。

标准化

解决类似于下面图片这种有旋转字符的验证码,我们首先要给出一种标准,让所有的分割后的图片都按照一个标准来摆放,最后对比的时候才能够统一

inImgTemp.png

如何标准化?

  • 我们对一个字符进行旋转,然后计算这个字符的宽度,当宽度最小时,我们认为它是一个标准字符,这样我们就能够得到比较好的结果了(通过观察这种验证码,发现一般只要左右旋转三十度即可)

  • 然后仅仅进行旋转还不够,为了能够和模板也就是特征值库进行对比,我们还需要,统一字符长度。也就是二值化之后的字符串长度,这时就需要画一张长宽固定的图片,把我们原来的图片按照比例拉伸压缩复制过去

    /**
     * 图像标准化,将旋转的图像标准化
     * @author mohuishou<1@lailin.xyz>
     * @param $img
     * @return resource 标准的图像资源句柄
     */
    public function imageStandard($img){
        $min_w=999;
        $oimg=$img;

        $c=imagecolorallocate($img, 255, 255, 255);
        for($i=-30;$i<30;$i++){
            $simg=imagerotate($img,$i,$c);
//            //计算字符宽度
            $simg_hash_data=$this->getWidth($simg);
            $w=count($simg_hash_data);
            if($w<$min_w){
                $oimg_hash_data=$simg_hash_data;
                $min_w=$w;
            }

        }

        $out_img_w=count($oimg_hash_data);
        $out_img_h=count($oimg_hash_data[0]);

        $out_img = imagecreatetruecolor($out_img_w,$out_img_h);//创建一幅真彩色图像
        $bg=imagecolorallocate($out_img, 255, 255, 255);//背景色画为白色
        imagefill($out_img, 0,0, $bg);

        //一列一列的进行画图
        foreach ($oimg_hash_data as $k=>$v){
            foreach ($v as $key=> $val){
                $color=255;
                if($val) $color=0;
                $c = imagecolorallocate($out_img, $color, $color, $color);
                imagesetpixel($out_img, $k,$key, $c);
            }
        }

//        imagepng($out_img,'./0.png');


        $hash_img = imagecreatetruecolor(self::HASH_W, self::HASH_H);
        imagecopyresized($hash_img, $out_img, 0, 0, 0, 0, self::HASH_W,self::HASH_H,$out_img_w,$out_img_h);


        return $hash_img;

    }

    /**
     * 获取图像的宽度
     * @author mohuishou<1@lailin.xyz>
     * @param $img 图像资源句柄
     * @return int
     */
    public function getWidth($img){
        //根据资源句柄获取整个图像的高与宽
        $img_w=imagesx($img);
        $img_h=imagesy($img);

        //图像二值化
        for($i = 0; $i <$img_h; $i++) {
            for ($j = 0; $j <$img_w; $j++) {
                $rgb = imagecolorat($img,$j,$i);
                if($rgb==0){
                    $data[$i][$j]=1;
                }else{
                    $data[$i][$j]=0;
                }
            }
        }

        //去掉零行
        $data=$this->removeZero($data);

        //按列取图像获取宽度
        for($i=0;$i<$img_w;$i++){
            $column=array_column($data,$i);
            if(implode("",$column)!=0){
                $data1[]=$column;
            }
        }


        //返回
        return $data1;


    }

看上方的代码发现会有一个去除零行的操作,也就是去除空白行,这一步操作的目的主要是为了出掉上下左右无用的空白部分,在我们进行模板对比的时候更加的精确

建立特征值库

之前提到了很多和模板或者是特征值库进行比较,那我们如何来建立这个库呢?下面说一下最简单的两种方法

  • 第一种,就是把你需要的数字可能还有 26 个字母,都先识别一遍然后存到一个文件当中,使用的时候包含这个文件进行对比就行了
  • 第二种,也差不多,可以写一个 study 文件,让上面的步骤稍微智能一点,直接输入之后,自动储存到数据库中

下面是我写的一个针对联通优选在沃的一个小的脚本,需要注意的是对于这种通过链接来识别的,一定要先将链接的图片保存下来,因为链接没获取一次图片就会改变一次

<?php
/**
 * Created by mohuishou<1@lailin.xyz>.
 * User: mohuishou<1@lailin.xyz>
 * Date: 2016/5/1 0001
 * Time: 20:44
 */
require_once 'Image.class.php';
require_once  'DB.class.php';
$db=new \ImageOCR\DB();
if(isset($_POST['send'])&&$_POST['send']=="send"){
    $image=new \ImageOCR\Image("./img/inImgTemp.png");
    $code=$_POST['code'];
    $code_arr=str_split($code);

    for($i=0;$i<$image::CHAR_NUM;$i++){
        $hash_img_data=implode("",$image->splitImage($i));
        $db->add($code_arr[$i],$hash_img_data);
    }

    echo "<script>location.href='./study.php';</script>";

}else{
    $image=new \ImageOCR\Image("http://www.169ol.com/Mall/Code/getCode&1462104790492");
    imagepng($image->_in_img,"./img/inImgTemp.png");
}

?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Study</title>
</head>
<body>
    <form action="" method="post">
        <img src="img/inImgTemp.png">
        <input type="text" name="code">
        <input name="send" type="submit" value="send" />
    </form>
</body>
</html>

开源代码

觉得不错,给个 star 呗

感谢

常见验证码的弱点与验证码识别

结束语

目前的识别效率可以达到 50%以上,基本可以投入正常使用,但是还有很大的进步空间,正在做下一步的优化,针对识别结果对特征库进行自动优化,自动去除使用率较低的特征值,自动保存,识别成功的特征值等等


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

Composer上线前的优化 上一篇
php利用curl保存图片 下一篇