加入收藏 | 设为首页 | 会员中心 | 我要投稿 北几岛 (https://www.beijidao.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

PHP验证码识别实例

发布时间:2021-05-21 08:38:59 所属栏目:大数据 来源: https://www.jb51.cc
导读:PHP验证码识别实例 PHP 验证码识别实例,识别的过程包括对图像的二值化、降噪、补偿、切割、倾斜矫正、建库、匹配,最后会提供实例代码,能够直接运行识别。 简述 要识别的验证码相对比较简单,没有粘连字符,但是会有几种不同程度的字体加粗,以及大约 0-30

PHP验证码识别实例

PHP验证码识别实例,识别的过程包括对图像的二值化、降噪、补偿、切割、倾斜矫正、建库、匹配,最后会提供实例代码,能够直接运行识别。

简述

在这里插入图片描述

要识别的验证码相对比较简单,没有粘连字符,但是会有几种不同程度的字体加粗,以及大约0-30度的倾斜,还有字符的个数会在4-5个之间变化,相对来说还是使用Python进行验证码识别比较简单,如果有需要可以参考文章
强智教务系统验证码识别 OpenCV
强智教务系统验证码识别 Tensorflow CNN

二值化

图像都是由各个像素点组成,每个像素点可以量化成为rgb三种颜色值,根据验证码的颜色,调整三种颜色的阈值,将背景与字符过滤出来,背景置1,字符置0

    // 二值化
    private static function binaryImage($image){
        $img = [];
        for($y = 0;$y < self::$width;$y++) {
            for($x =0;$x < self::$height;$x++) {
                if($y === 0 || $x === 0 || $y === self::$width - 1 || $x === self::$height - 1){
                    $img[$x][$y] = 1;
                    continue;
                }
                $rgb = imagecolorat($image,$y,$x);
                $rgb = imagecolorsforindex($image,$rgb);
                if($rgb['red'] < 255 && $rgb['green'] < 230 && $rgb['blue'] < 220) {
                    $img[$x][$y] = 0;
                } else {
                    $img[$x][$y] = 1;
                }
            }
        }
        return $img;
    }
2222222222222222222222222111022222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221
2222222222222222222211100000000022222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222111
2222222222222222222211000000000222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111
2222222222222222222210000000000222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111
2222222222222222222210000000000222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111
2222222222222222222200000022222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111
2222222222222222222200000222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
2222222222222222222200100222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222222222222222222222222222222222222222222222222222222222200222222222222222222222222222222222222222222222111000222222222222222222222222222222222222222211100000022222222222222222222222222222222222111
2222222222222221000000000000002222222222222222222222222222220000000022222111100000002222222222222222222211000000000000222222222222222222222222222222222221110000000000022222222222222222222222222222222222000000000000002222222222222222222222222222221111
2222222222222221100000100000002222222222222222222222222222220000000222221111000000002222222222222222222210000000000000002222222222222222222222222222222222200000000000000222222222222222222222222222222110000000000000000222222222222222222222222222222111
2222222222222221100000000000002222222222222222222222222222220000000222221111000000002222222222222222222200000000000000000222222222222222222222222222222110000000000000000022222222222222222222222222222200000000000000000002222222222222222222222222222221
2222222222222221100000000011102222222222222222222222222222220000100222221111000000022222222222222222222000000222220000000222222222222222222222222222222110000000000000000002222222222222222222222222111000000000000000000002222222222222222222222222222221
2222222222222222222200000222222222222222222222222222222111100000100222221111000000022222222222222222222000022222111100000222222222222222222222222222222100000000000000000000222222222222222222222222211000000000010000000000222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222111100000102222222222000000022222222222222211110000022222222220000022222222222222222222222221111000000002222210000000222222222222222222222222210000000222221110000000222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222111100000002222222222000000022222222222222211110000022222222220000022222222222222222222222221111001000022222110000000022222222222222222222222220000000222221110000000022222222222222222222222221111
2222222222222222222200000222222222222222222222222222222111100000002222211110000000022222222222222211110000022222222222222222222222222222222222222221110000000022222111000000022222222222222222222222220000000222221111002222222222222222222222222222221111
2222222222222222222200000222222222222222222222222222222111000000002222211110000000222222222222222222221000002222222222222222222222222222222222222222110000000222221111000000022222222222222222222222220000000000222222222222222222222222222222222222222211
2222222222222222222200000222222222222222222222222222222111000000022222222220000000222222222222222222221000000022222222222222222222222222222222222222220100000222222222200000002222222222222222222222222000000000002222222222222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222111000000022222222220000000222222222222222222221000000000002222222222222222222222222222222222200000000001010111100000002222222222222222222222222000000000000000022222222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222111000000022222111100000000222222222222222222221100000000000002222222222222222222222222222221100000000000000000000000002222222222222222222222222000000000000000000022222222222222222222222222222211
2222222222222222222200000222222222222222222222222222222111000000022222111100000002222222222222222222211110000000001000002222222222222222222222222111100000000000010110000011002222222222222222222222222100000000000000000000222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222111000000022222111100000002222222222222222222222222100000000000000022222222222222222222222221100000000000000010000110002222222222222222222222222110000000000000110000222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222110000000022222111100000002222222222222222222222222111100000000000022222222222222222222222221110000000000000000000000002222222222222222222222222111100000000000000000022222222222222222222222221111
2222222222222222222200000222222222222222222222222222222110000000222221111000000002222222222222222222222222222221110000000002222222222222222222222222110000000222222222222222222222222222222222222222222222222220000000000000022222222222222222222222221111
2222222222222222222200000222222222222222222222222222222110000000222221111000000002222222222222222222222222222222222210000002222222222222222222222222110000000222222222222222222222222222222222222222222222222221110000000000022222222222222222222222221111
2222222222222222222200000222222222222222222222222222222100000002222222222000000002222222222222222222211110222222222211000002222222222222222222222222110000000222221111022222222222222222222222222222222222102222222222000000002222222222222222222222222111
2222222222222222222200000222222222222222222222222222222100000002222211110000000022222222222222222222110000222222222211100002222222222222222222222222110000000022222111000001022222222222222222222111100000000222221111001000022222222222222222222222221111
2222222222222222222200000222222222222222222222222222222100000002222211100000000022222222222222222222110000022222222221100002222222222222222222222222111000000022222110000000022222222222222222222111100000000222221111001000022222222222222222222222221111
2222222222222222222200000222222222222222222222222222222100000000222221000000000022222222222222222222110000022222222221000002222222222222222222222222111000000002222210000000022222222222222222222111100000000022222111000100022222222222222222222222221111
2222222222222222222200000222222222222222222222222222222100000000001000000000000222222222222222222221111000002222211110000022222222222222222222222221111000000000000000000000222222222222222222222222210000000000000000000000222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222110000000000000000000000222222222222222222221111000000002222200000022222222222222222222222222222200000100000000000000222222222222222222222222211000000000000000000000222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222110000000000000011000100222222222222222222222222200000000000000000022222222222222222222222222222210000000000000000002222222222222222222222222111100000000000000000002222222222222222222222222222221
2222222222222222222200000222222222222222222222222222222111000000000000110000000222222222222222222222222210001000010000002222222222222222222222222222222222200000000000000022222222222222222222222222222210000000000000000022222222222222222222222222222211
2222222222222222222200000222222222222222222222222222222111100000000001110000000222222222222222222222222211000000000000022222222222222222222222222222222222110000000000002222222222222222222222222222221111000000000000002222222222222222222222222222221111
2222222222222222222222222222222222222222222222222222222222221000022222222222222222222222222222222222222222222200000222222222222222222222222222222222222222222222000022222222222222222222222222222222222222221110000222222222222222222222222222222222221111
2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222

降噪 补偿

验证码经常会加入一些噪点,这些噪点一般都是单独的点,有时候会加入几个单像素点连成干扰线,降噪的时候就需要去掉噪点与干扰线,我采用了将每个像素点周围四个像素点的值取出,计算如果周围四个像素点有两个以上是背景,也就是1的话,那么就认为这个是噪点,将其设为背景,也就是1
当二值化的时候,不可避免的会将字符中一些小像素点过滤成了背景,此时就需要补偿这个字符,也是同样采用将周围四个字符进行统计,如果周围四个像素点有两个以上都是字符,也就是0,那么就认为这个像素点也是字符像素点,将其设为字符,也就是0

    // 降噪 补偿
    private static function noiseReduce($img) {
        $xCount = count($img[0]);
        $yCount = count($img); 
        for ($i=1; $i < $yCount-1 ; $i++) { 
            for ($k=1; $k < $xCount-1; $k++) { 
                if($img[$i][$k] === 0){
                    $countOne = $img[$i][$k-1] + $img[$i][$k+1] + $img[$i+1][$k] + $img[$i-1][$k];
                    if($countOne > 2) $img[$i][$k] = 1;
                } 
                if($img[$i][$k] === 1){
                    $countZero = $img[$i][$k-1] + $img[$i][$k+1] + $img[$i+1][$k] + $img[$i-1][$k];
                    if($countZero < 2) $img[$i][$k] = 0;
                } 
            }
        }
        return $img;
    }
2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
2222222222222222222211100000000222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111
2222222222222222222211000000000222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111
2222222222222222222210000000000222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111
2222222222222222222210000000000222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111
2222222222222222222200000022222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111
2222222222222222222200000222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222222222222222222222222222222222222222222222222222222222200222222222222222222222222222222222222222222222111000222222222222222222222222222222222222222211100000022222222222222222222222222222222222111
2222222222222221100000000000002222222222222222222222222222220000000222222222200000002222222222222222222211000000000000222222222222222222222222222222222221110000000000022222222222222222222222222222222222000000000000002222222222222222222222222222221111
2222222222222221100000000000002222222222222222222222222222220000000222221111000000002222222222222222222210000000000000002222222222222222222222222222222222200000000000000222222222222222222222222222222110000000000000000222222222222222222222222222222111
2222222222222221100000000000002222222222222222222222222222220000000222221111000000002222222222222222222200000000000000000222222222222222222222222222222110000000000000000022222222222222222222222222222200000000000000000002222222222222222222222222222221
2222222222222221100000000022222222222222222222222222222211110000000222221111000000022222222222222222222000000222220000000222222222222222222222222222222110000000000000000002222222222222222222222222111000000000000000000002222222222222222222222222222221
2222222222222222222200000222222222222222222222222222222111100000000222221111000000022222222222222222222000022222111100000222222222222222222222222222222100000000000000000000222222222222222222222222211000000000000000000000222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222111100000002222222222000000022222222222222211110000022222222220000022222222222222222222222221111000000002222210000000222222222222222222222222210000000222221110000000222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222111100000002222222222000000022222222222222211110000022222222220000022222222222222222222222221111000000022222110000000022222222222222222222222220000000222221110000000222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222111100000002222211110000000022222222222222211110000022222222222222222222222222222222222222221110000000022222111000000022222222222222222222222220000000222221111002222222222222222222222222222221111
2222222222222222222200000222222222222222222222222222222111000000002222211110000000222222222222222222221000002222222222222222222222222222222222222222110000000222221111000000022222222222222222222222220000000000222222222222222222222222222222222222222211
2222222222222222222200000222222222222222222222222222222111000000022222222220000000222222222222222222221000000022222222222222222222222222222222222222220000000222222222200000002222222222222222222222222000000000002222222222222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222111000000022222222220000000222222222222222222221000000000002222222222222222222222222222222222200000000000000111100000002222222222222222222222222000000000000000022222222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222111000000022222111100000000222222222222222222221100000000000002222222222222222222222222222221100000000000000000000000002222222222222222222222222000000000000000000022222222222222222222222222222211
2222222222222222222200000222222222222222222222222222222111000000022222111100000002222222222222222222211110000000000000002222222222222222222222222111100000000000000000000010002222222222222222222222222100000000000000000000222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222111000000022222111100000002222222222222222222222222100000000000000022222222222222222222222221100000000000000000000000002222222222222222222222222110000000000000000000222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222110000000022222111100000002222222222222222222222222111100000000000022222222222222222222222221110000000000000000000000002222222222222222222222222111100000000000000000022222222222222222222222221111
2222222222222222222200000222222222222222222222222222222110000000222221111000000002222222222222222222222222222221110000000002222222222222222222222222110000000222222222222222222222222222222222222222222222222220000000000000022222222222222222222222221111
2222222222222222222200000222222222222222222222222222222110000000222221111000000002222222222222222222222222222222222210000002222222222222222222222222110000000222222222222222222222222222222222222222222222222221110000000000022222222222222222222222221111
2222222222222222222200000222222222222222222222222222222100000002222222222000000002222222222222222222222222222222222211000002222222222222222222222222110000000222222222222222222222222222222222222222222222222222222211000000022222222222222222222222221111
2222222222222222222200000222222222222222222222222222222100000002222211110000000022222222222222222222110000222222222211100002222222222222222222222222110000000022222111000000022222222222222222222111100000000222221111000000022222222222222222222222221111
2222222222222222222200000222222222222222222222222222222100000002222211100000000022222222222222222222110000022222222221100002222222222222222222222222111000000022222110000000022222222222222222222111100000000222221111000000022222222222222222222222221111
2222222222222222222200000222222222222222222222222222222100000000222221000000000022222222222222222222110000022222222221000002222222222222222222222222111000000002222210000000022222222222222222222111100000000022222111000000022222222222222222222222221111
2222222222222222222200000222222222222222222222222222222100000000000000000000000222222222222222222221111000002222211110000022222222222222222222222221111000000000000000000000222222222222222222222222210000000000000000000000222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222110000000000000000000000222222222222222222221111000000002222200000022222222222222222222222222222200000000000000000000222222222222222222222222211000000000000000000000222222222222222222222222222222
2222222222222222222200000222222222222222222222222222222110000000000000010000000222222222222222222222222200000000000000000022222222222222222222222222222210000000000000000002222222222222222222222222111100000000000000000002222222222222222222222222222221
2222222222222222222200000222222222222222222222222222222111000000000000110000000222222222222222222222222210000000000000002222222222222222222222222222222222200000000000000022222222222222222222222222222210000000000000000022222222222222222222222222222211
2222222222222222222200000222222222222222222222222222222111100000000001110000000222222222222222222222222211000000000000022222222222222222222222222222222222110000000000002222222222222222222222222222221111000000000000002222222222222222222222222222221111
2222222222222222222222222222222222222222222222222222222222221000022222222222222222222222222222222222222222222200000222222222222222222222222222222222222222222222000022222222222222222222222222222222222222221110000222222222222222222222222222222222221111
2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222

切割

由于此验证码并没有粘连,对于字符的切割相对而言比较简单,纵向统计出切割字符的起始与终止位置,切割后分别置入数组中,然后将横向的空白去除,同样也是统计字符有0值的起始行与终止行,再做切割,仅保留字符。

 	// 裁剪
    private static function cutImg($img){
        $xCount = count($img[0]);
        $yCount = count($img);
        $xFilter = [];
        for($x = 0;$x < $xCount;$x++) {
            $filter = true;
            for($y = 0;$y < $yCount;$y++)  $filter = $filter && ($img[$y][$x] === 1);
            if($filter) $xFilter[] = $x;
        }
        $xImage = array_values(array_diff(range(0,$xCount-1),$xFilter));
        $wordImage = [];
        $preX = $xImage[0] - 1;
        $wordCount = 0;
        foreach($xImage as $xKey => $x) {
            if($x != ($preX + 1))  $wordCount++;
            $preX = $x;
            for($y = 0;$y < $yCount;$y++) $wordImage[$wordCount][$y][] = $img[$y][$x];
        }
        $cutImg = [];
        foreach($wordImage as $i => $image) {
            $xCount = count($image[0]);
            $yCount = count($image);
            $start = 0;
            for ($j=0; $j < $yCount; ++$j) { 
                $stopFlag = false;
                for ($k=0; $k < $xCount; ++$k) { 
                    if ($image[$j][$k] === 0) {
                        $start = $j;
                        $stopFlag = true;
                        break;
                    }
                }
                if($stopFlag) break;
            }
            $stop = $yCount-1;
            for ($j=$yCount-1; $j >= 0; --$j) { 
                $stopFlag = false;
                for ($k=0; $k < $xCount; ++$k) { 
                    if ($image[$j][$k] === 0) {
                        $stop = $j;
                        $stopFlag = true;
                        break;
                    }
                }
                if($stopFlag) break;
            }
            for ($k=$start; $k <= $stop ; ++$k) { 
                $cutImg[$i][] = $image[$k];
            }
            // self::showImg($cutImg[$i]);
            $cutImg[$i] = self::adjustImg($cutImg[$i]);
            // self::showImg($cutImg[$i]);
        }
        return $cutImg;
    }
2222222222111000002222211
2222211100000000000001111
2222211000000000000000011
2222210000000000000000011
2222200000000000000000001
1111000000001111000000001
1110000000022222100000000
1110000000222221110000000
2222222222222221110000000
2222222222222221110000000
2222222222222221100000001
2222211100000000000000001
2222200000000000000000001
1110000000000000000000001
1100000000000000000000001
1000000000000111100000011
1000000002222211000000011
1000000022222111000000011
0000000222221111000000011
0000000222221110000000111
0000000222221100000000111
0000000022222000000000111
1000000001100000000000111
1000000000000000000000111
1000000000000000000000111
1100000000000010000000111
1111000000001110000000111
2222200002222222222222221

倾斜矫正

对于倾斜矫正我尝试了两种方案,一个是使用线性回归,另一个是使用投影法。

线性回归

使用线性回归,取得每一行上字符像素点的中点的坐标,使用最小二乘法拟合曲线,得到一个斜率,也就相当于得到了这个字符的倾斜角度,然后根据斜率来矫正这个字符的倾斜度,这个方式对于n这样的字符效果比较不错,但是对于j这样的字符效果就比较差。

$img = [
    [1,1,1],[1,0],[0,];
ImgIdenfy::showImg($img);
$mixX = 0.0;
$mixY = 0.0;
$mixXX = 0.0;
$mixXY = 0.0;
$yCount = count($img);
$xCount = count($img[0]);
foreach($img as $i => $line) {
    $x = 0;
    $xValidCount = 0;
    foreach($line as $k => $unit) {
        if($unit === 0) {
            $x += $k;
            ++$xValidCount;
        }
    }
    if($xValidCount) {
        $pointX = $x/$xValidCount;
        $pointY = $yCount - $i;
        $mixX += $pointX;
        $mixY += $pointY;
        $mixXX += ($pointX*$pointX);
        $mixXY += ($pointX*$pointY);
    }
}
$linearK = -($mixXY - $mixX*$mixY/$yCount) / ($mixXX - $mixX*$mixX/$yCount);
// if($linearK > -1 && $linearK < 1) return $img;
$whirlImg = [];
foreach($img as $i => $line) {
    $pointY = $i;
    if(!isset($whirlImg[$pointY])) $whirlImg[$pointY]=[];
    foreach($line as $pointX => $unit) {
        if(!isset($whirlImg[$pointY][$pointX])) $whirlImg[$pointY][$pointX]=1;
        // $newY = (int)($pointY*sqrt(1+$linearK*$linearK)/$linearK);
        $newY = (int)($pointY);
        $newX = (int)($pointX-$pointY/$linearK);
        if($newX >= 0 && $newX < $xCount && $newY >= 0 && $newY < $yCount) $whirlImg[$newY][$newX] = $unit;
    }
}

$finishedImg = [];
for ($i=0; $i < $xCount; ++$i) { 
    for($k=0; $k < $yCount; ++$k) {
        if($whirlImg[$k][$i] !== 1){
            for($y = 0;$y < $yCount;++$y) $finishedImg[$y][] = $whirlImg[$y][$i];
            break;
        }
    }
}
ImgIdenfy::showImg($finishedImg);
222220000111100000000011
222220000111000000000001
111100001110000000000000
111100000000000111100000
111100000000222221110000
111100000002222211110000
111100000022222222220000
111000000222222222210000
111000000222222222210000
111000002222222222110000
111000002222222222100000
111000022222222221100000
110000022222222221100001
110000022222222221000001
110000222222222211000001
110000222222222211000001
110000222222222211000001
100000222222222211000011
100000222222222211000011
100000222222222210000011
100002222222222110000011
100002222222222110000011
000022222222221110000111
000022222222221110000111
000022222222221100000111
000022222222221100000111

10000111100000000011
10000111000000000001
00001110000000000000
00000000000111100000
00000000222221110000
10000000222221111000
10000002222222222000
00000022222222221000
00000022222222221000
00000222222222211000
10000022222222221000
10000222222222211000
00000222222222211000
00000222222222210000
00002222222222110000
10000222222222211000
10000222222222211000
00000222222222211000
00000222222222211000
00000222222222210000
10000222222222211000
10000222222222211000
00002222222222111000
00002222222222111000
00002222222222110000
10000222222222211000

投影法

由于直接线性拟合的方式对于一些字符的效果比较差,于是采用投影法的方式,字符如果进行旋转,那么他的宽度势必会增加,于是可以在一定范围内尝试旋转字符,取得旋转过程中宽度最小时的字符,就是矫正后的字符。由于直接将竖直的字符根据斜率旋转的话,因为tan90°不存在,不好界定逆时针旋转的范围,于是首先将字符数组进行转置,然后就可以在斜率-0.5-0.5的范围内顺时针旋转,然后再将其转置回即可,我在实现的过程中有比较多的重复运算,这个主要是需要数学推算,而我是一步步实现的计算,还有就是旋转的过程中如果字符宽度由小到大变化的时候就可以逆向运算或者停止运算了,就像一个梯度下降的方式,此外我并没有使用矩阵方式的运算,如果使用矩阵的话实现会比较简单,PHP中有PHP-ML这样的机器学习库,其中就有矩阵运算方面的方法,当然也可以直接使用PHP-ML进行神经网络的训练。

    // 旋转
    private static function whirl($img,$yCount,$xCount,$linearK){
        $whirlImg = [];
        foreach($img as $i => $line) {
            $pointY = $yCount - $i - 1;
            if(!isset($whirlImg[$pointY])) $whirlImg[$pointY]=[];
            foreach($line as $pointX => $unit) {
                if(!isset($whirlImg[$pointY][$pointX])) $whirlImg[$pointY][$pointX]=1;
                $newY = (int)($pointY - $pointX*$linearK);
                $newX = (int)($pointX);
                if($unit === 0 && ($newY < 0 || $newY >= $yCount)) return [$yCount+1,$img];
                if($newX >= 0 && $newX < $xCount && $newY >= 0 && $newY < $yCount) $whirlImg[$newY][$newX] = $unit;
            }
        }
        $cutImg = [];
        $height = $yCount;
        foreach ($whirlImg as $j => $line) {
            foreach ($line as $k => $v) {
                if($v !== 1) {
                    --$height;
                    break;
                }
            }
        }
        return [$yCount - $height,$whirlImg];
    }

    // 倾斜调整
    private static function adjustImg($img){
        $reverseImg = [];
        $yCount = count($img);
        $xCount = count($img[0]);
        for ($i=0; $i < $yCount; ++$i) { 
            $pointY = $yCount - $i - 1;
            for($k=0; $k < $xCount; ++$k) {
                $reverseImg[$k][$i] = $img[$pointY][$k];
            }
        }
        list($yCount,$xCount) = [$xCount,$yCount];
        $min = $yCount;
        $minImg = $reverseImg;
        for ($k= -0.5 ; $k <= 0.5; $k = $k + 0.05) { 
            list($tempMin,$tempMinImg) = self::whirl($reverseImg,$k);
            if($tempMin < $min) {
                $min = $tempMin;
                $minImg = $tempMinImg;
            }
        }
        $removedImg = [];
        foreach ($minImg as $j => $line) {
            foreach ($line as $k => $v) {
                if($v !== 1) {
                    $removedImg[] = $line;
                    break;
                }
            }
        }
        $reverseImg = [];
        $xCount = count($removedImg[0]);
        $yCount = count($removedImg);
        $reverseImg = [];
        for ($i=0; $i < $xCount; ++$i) { 
            for($k=0; $k < $yCount; ++$k) {
                $pointX = $xCount - $i - 1;
                $reverseImg[$i][$k] = $removedImg[$k][$pointX];
            }
        }
        return $reverseImg;
    }
2222222222111000002222211
2222211100000000000001111
2222211000000000000000011
2222210000000000000000011
2222200000000000000000001
1111000000001111000000001
1110000000022222100000000
1110000000222221110000000
2222222222222221110000000
2222222222222221110000000
2222222222222221100000001
2222211100000000000000001
2222200000000000000000001
1110000000000000000000001
1100000000000000000000001
1000000000000111100000011
1000000002222211000000011
1000000022222111000000011
0000000222221111000000011
0000000222221110000000111
0000000222221100000000111
0000000022222000000000111
1000000001100000000000111
1000000000000000000000111
1000000000000000000000111
1100000000000010000000111
1111000000001110000000111
2222200002222222222222221

222222222210000022222111
222221000000000000022222
222220000000000000000111
111100000000000000000111
111000000000000000000011
110000000011110000000011
100000000222221000000001
100000002222211100000001
222222222222222110000000
222222222222222110000000
222222222222222100000001
222221100000000000000001
111100000000000000000001
110000000000000000000001
100000000000000000000001
000000000000111100000011
000000002222211000000011
000000022222111000000011
000000022222111100000001
000000022222111000000011
000000022222110000000011
000000002222200000000011
100000000110000000000011
100000000000000000000011
100000000000000000000011
110000000000001000000011
111100000000111000000011
222220000222222222222222

建库

将验证码矫正过后,就需要建立特征匹配库了,这里我直接使用了将二值化的数组转化为字符串全部作为特征写入一个特征匹配数组,再手动打码,若是识别出的字符与我手动打码的字符不符,就将其加入特征匹配数组,然后将字符数组序列化存储到文件中,然后将这个序列化后的字符串进行压缩,存储到文件中,我提取的特征数组有150个字符特征码,占用约8KB,注意我这是将PHP作为脚本使用的,配置好环境变量写入空数据后再使用PHP Build.PHP即可开始提取特征码。

// 写入空序列化数组
// $info = serialize([]);
// $library = fopen("library","w+");
// fwrite($library,gzcompress($info));
// fclose($library);

$library = fopen("library","r+");
$info = fread($library,filesize("library"));
if(!$info) $charMap = [];
else $charMap = unserialize(gzuncompress($info));
while (1) {
    $img = imagecreatefromjpeg("http://grdms.sdust.edu.cn:8081/security/jcaptcha.jpg"); //获取图片
    imagejpeg($img,"v.jpg"); // 写入硬盘
    list($result,$imgStringArr) = ImgIdenfy::build($img,$charMap,250,100);
    echo($result."n");
    $input = fgets(STDIN);
    if(isset($input[0]) && $input[0] === "$") break;
    $n = strlen($input) - 2;
    for ($i=0; $i < $n; $i++) {
        if(!isset($result[$i]) || $input[$i] !== $result[$i]) $charMap[$input[$i].mt_rand(1,10000)] = $imgStringArr[$i];
    }
    echo count($charMap)."n";
    ftruncate($library,0);
    rewind($library);
    fwrite($library,gzcompress(serialize($charMap)));
}
fclose($library);

匹配

由于是直接将全部的特征信息存入文件,直接使用循环对比字符串的值即可,为了提高准确率,我将两个对比字符串的第一个0进行对齐,然后再进行遍历,取得相同字符的数量,此外由于对比的字符串的长度不同,将字符串的长度信息乘以一定权值也作为一部分信息计入相似度中,当然PHP中提供了similar_text函数进行字符串相似度对比,使用此函数的话识别率会提升,但是由于字符串长度过长,对比匹配的时间比较慢,权衡时间消耗与正确率还是选择了自行匹配的方式。

    // 对比
    private static function comparedText($s1,$s2){
        $s1N = strlen($s1);
        $s2N = strlen($s2);
        $i = -1;
        $k = -1;
        $percent = -abs($s1N - $s2N) * 0.1;
        while(++$i<$s1N && $s1[$i]) {}
        while(++$k<$s2N && $s2[$k]) {}
        while ($i<$s1N && $k<$s2N) ($s1[$i++] === $s2[$k++]) ? $percent++ : "";
        return $percent;
        // $percent = 0;
        // $N = $s1N < $s2N ? $s1N : $s2N;
        // for ($i=0; $i < $N; ++$i) { 
        //     ($s1[$i] === $s2[$i]) ? $percent++ : "";
        // }
        // return $percent;
    }

    // 匹配
    private static function matchCode($imgGroup,$charMap){
        $record = "";
        $imgStringArr = [];
        foreach ($imgGroup as $img) {
            $maxMatch = 0;
            $tempRecord = "";
            $s = ImgIdenfy::getString($img);
            foreach ($charMap as $key => $value) {
                // similar_text(ImgIdenfy::getString($img),$value,$percent);
                $percent = self::comparedText($s,$value);
                if($percent > $maxMatch){
                    $maxMatch = $percent;
                    $tempRecord = $key[0];
                }
            }
            $record = $record.$tempRecord;
            $imgStringArr[] = $s;
        }
        return [$record,$imgStringArr];
    }

实例代码

如果觉得不错,点个star吧                        

(编辑:北几岛)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读