精华内容
下载资源
问答
  • 这个php实现验证码中级篇,增加二值化去杂点的操作,解决两个字符粘连问题,可以识别旋转字符,并且具有一定的学习功能,并提供了bmp到jpeg的转换方法,目前这个方案应该可以应付90%的互联网验证码识别工作。...
  • PHP实现验证码自动识别(中级篇)PHP实现验证码自动识别(中级篇)
  • 使用php命令行运行 php index.php 即可看到效果
  • 简介 使用php识别验证码示例,简单的验证码还行,但是腾讯这类就不行了。 算法来自网络,以腾讯QQ验证码为例 但是验证速度和命中太差,求大神优化 ^_^ 参考: 联系: 网站: Q群:143263697
  • 也许只需要一段简单的小程序,你的验证码就会如同虚设。本文只是简单实现,不会太过深入。 有攻就有防 写这篇文章完全是因为同事的公众号发了一篇文章叫"实践-写个验证码",你简单写了一下,我就简单破解一下试试,...
    网站的登陆页、注册页等等等到处都是验证码,然而你的验证码真的安全么?也许只需要一段简单的小程序,你的验证码就会如同虚设。本文只是简单实现,不会太过深入。

    有攻就有防

    写这篇文章完全是因为同事的公众号发了一篇文章叫"实践-写个验证码",你简单写了一下,我就简单破解一下试试,生活处处有乐趣啊~

    生成验证码

    Copy代码,执行,生成如下验证码:

    图片描述

    如图我们能发现,这个验证码格式特别"规范",字体大小一样,颜色都是黑色,让我们省了不少事儿。

    二值化

    程序读图,二值化(关键点在于查找字体颜色的阈值,这个验证码都是黑色,so...),通过程序一个像素点一个像素点判断,将属于字体颜色的标记为*,非字体颜色标记为0

    图片描述

    <center>从上面的图,能够大概看出验证码的样子(YTAD)</center>

    分析图像,切割

    切割出字符串(先切绿线,再分别切蓝线,这样即使这个字符上下移动一下,也不太容易影响我们的切割)

    图片描述

    提取特征码

    将字符串拆分后,我们多次获取验证码,将a-z,A-Z,0-9等验证码的特征码全部记录下来。

    图片描述
    <center>这个是提取出来的字母Y</center>

    识别

    识别的过程就是重复上面的:二值化->切割->提取特征码,再加上和之前提取的特征码比对相似度,就OK了。

    PHP代码实现

    /**
     * 简单验证码识别
     * @author zhjx922
     */
    
    class vCode{
    
        //字符特征码
        private $_wordKeys = array (
            'A' => '000**00000****000**00**0**0000****0000****0000************0000****0000****0000**',
            'B' => '******00**000**0**0000****000**0******00**000**0**0000****0000****000**0******00',
            'C' => '00*****00**000****00000***000000**000000**000000**000000**00000*0**000**00*****0',
            'D' => '******00**000**0**0000****0000****0000****0000****0000****0000****000**0******00',
            'E' => '*********00000**00000**00000******0**00000**00000**00000**00000*******',
            'F' => '**********000000**000000**000000******00**000000**000000**000000**000000**000000',
            'G' => '00*****00**000****000000**000000**000000**000*****0000****0000**0**000**00*****0',
            'H' => '**0000****0000****0000****0000************0000****0000****0000****0000****0000**',
            'I' => '******00**0000**0000**0000**0000**0000**0000**0000**00******',
            'J' => '00****0000**0000**0000**0000**0000**0000***000****0**00***00',
            'K' => '**0000****000**0**00**00**0**000****0000****0000**0**000**00**00**000**0**0000**',
            'L' => '**00000**00000**00000**00000**00000**00000**00000**00000**00000*******',
            'M' => '**0000*****00*************0**0****0**0****0**0****0000****0000****0000****0000**',
            'N' => '**0000*****000******00******00****0**0****0**0****00******000*****000*****0000**',
            'P' => '*******0**0000****0000****0000*********0**000000**000000**000000**000000**000000',
            'Q' => '00****000**00**0**0000****0000****0000****0000****0**0****00****0**00**000****0*',
            'R' => '*******0**0000****0000****0000*********0*****000**00**00**000**0**0000****0000**',
            'S' => '0******0**0000****000000**0000000******0000000**000000**000000****0000**0******0',
            'T' => '********000**000000**000000**000000**000000**000000**000000**000000**000000**000',
            'U' => '**0000****0000****0000****0000****0000****0000****0000****0000**0**00**000****00',
            'V' => '**0000****0000****0000**0**00**00**00**00**00**000****0000****00000**000000**000',
            'W' => '**0000****0000****0000****0000****0**0****0**0****0**0*************00*****0000**',
            'X' => '**0000****0000**0**00**000****00000**000000**00000****000**00**0**0000****0000**',
            'Y' => '**0000****0000**0**00**000****00000**000000**000000**000000**000000**000000**000',
            'Z' => '*******00000**00000**0000**0000**0000**0000**0000**00000**00000*******',
            'a' => '00*****00**000**000000**0*********0000****000***0****0**',
            'b' => '**000000**000000**000000**0***00***00**0**0000****0000****0000*****00**0**0***00',
            'c' => '00*****00**000****000000**000000**0000000**000**00*****0',
            'd' => '000000**000000**000000**00***0**0**00*****0000****0000****0000**0**00***00***0**',
            'e' => '00****000**00**0**0000************0000000**000**00*****0',
            'f' => '000****000**00**00**00**00**000000**0000******0000**000000**000000**000000**0000',
            'g' => '0*****0***000*****000**0**000**00*****00**0000000******0**0000**0******0',
            'h' => '**000000**000000**000000**0***00***00**0**0000****0000****0000****0000****0000**',
            'i' => '00**0000**000000000***0000**0000**0000**0000**0000**00******',
            'k' => '**00000**00000**00000**00**0**0**00****000****000**0**00**00**0**000**',
            'l' => '***00**00**00**00**00**00**00**00**0****',
            'm' => '*0**0**0**0**0****0**0****0**0****0**0****0**0****0**0**',
            'n' => '**0***00***00**0**0000****0000****0000****0000****0000**',
            'o' => '00****000**00**0**0000****0000****0000**0**00**000****00',
            'p' => '**0***00***00**0**0000****0000****0000*****00**0**0***00**000000**000000',
            'q' => '00***0**0**00*****0000****0000****0000**0**00***00***0**000000**000000**',
            'r' => '**0****00***00**0**000000**000000**000000**000000**00000',
            's' => '0******0**0000****0000000******0000000****0000**0******0',
            't' => '00**000000**0000******0000**000000**000000**000000**000000**00**000****0',
            'u' => '**0000****0000****0000****0000****0000**0**00***00***0**',
            'v' => '**0000****0000**0**00**00**00**000****0000****00000**000',
            'w' => '**0000****0000****0**0****0**0****0**0**********0**00**0',
            'x' => '**0000**0**00**000****00000**00000****000**00**0**0000**',
            'y' => '**0000****0000****0000****0000****0000**0**00***00***0***00000**0******0',
            'z' => '******0000**000**000**000**000**0000******',
            '0' => '000**00000****000**00**0**0000****0000****0000****0000**0**00**000****00000**000',
            '1' => '00**000***00****0000**0000**0000**0000**0000**0000**00******',
            '2' => '00****000**00**0**0000**000000**00000**00000**00000**00000**00000**00000********',
            '3' => '0*****00**000**0000000**00000**0000***0000000**0000000**000000****000**00*****00',
            '4' => '00000**00000***0000****000**0**00**00**0**000**0********00000**000000**000000**0',
            '5' => '*******0**000000**000000**0***00***00**0000000**000000****0000**0**00**000****00',
            '6' => '00****000**00**0**0000*0**000000**0***00***00**0**0000****0000**0**00**000****00',
            '7' => '********000000**000000**00000**00000**00000**00000**00000**00000**000000**000000',
            '8' => '00****000**00**0**0000**0**00**000****000**00**0**0000****0000**0**00**000****00',
            '9' => '00****000**00**0**0000****0000**0**00***00***0**000000**0*0000**0**00**000****00',
        );
    
        /**
         * 生成验证码
         * @author 武老师
         */
        public function make($verCode = '') {
            if(empty($verCode)) {
                $baseChars     = 'ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789';
                $verCode       = '';
                $codeCharLenth = 4;
                for ($i = 1; $i <= $codeCharLenth; $i++) {
                    // 通过字符串下标形式随机获取
                    $verCode .= $baseChars{mt_rand(0, strlen($baseChars) - 1)};
                }
            }
    
            // 以下代码是将生成的验证码生成图片
            $font_size = 20;
            $width     = 60;
            $height    = 30;
            $img       = imagecreate($width, $height); // 新建一个基于调色板的图像
    
            $bgR        = mt_rand(50, 200); //r(ed)
            $bgG        = mt_rand(50, 200); //g(reen)
            $bgB        = mt_rand(50, 200); //b(lue)
            $background = imagecolorallocate($img, $bgR, $bgG, $bgB); // 背景色
            $black      = imagecolorallocate($img, 0, 0, 0);
    
            imagestring($img, 5, 9, 8, $verCode, $black); // 水平地画一行字符串
    
            ob_start();
            imagepng($img);
            $image = ob_get_contents();
            ob_end_clean();
    
            return array(
                'image' =>  $image,
                'code'  =>  $verCode
            );
        }
    
        /**
         * 获取原始图像数组
         * @param string $imageString
         * @return array
         */
        public function getImage($imageString) {
            $im = imagecreatefromstring($imageString);
    
            list($width, $height) = getimagesizefromstring($imageString);
    
            $image = array();
    
            for($x = 0;$x < $width;$x++) {
                for($y =0;$y < $height;$y++) {
                    $rgb = imagecolorat($im, $x, $y);
                    $rgb = imagecolorsforindex($im, $rgb);
                    if($rgb['red'] == 0 && $rgb['green'] == 0 && $rgb['blue'] == 0) {
                        $image[$y][$x] = '*';
                    } else {
                        $image[$y][$x] = 0;
                    }
                }
            }
    
            return $image;
        }
    
        /**
         * 移除无用数据
         * @param array $image
         * @return array
         */
        public function remove($image) {
            //计算x和y轴的
            $xCount = count($image[0]); //60
            $yCount = count($image); //30
    
            $xFilter = array();
            for($x = 0;$x < $xCount;$x++) {
                $filter = true;
                for($y = 0;$y < $yCount;$y++) {
                    $filter = $filter && ($image[$y][$x] == '0');
                }
                if($filter) {
                    $xFilter[] = $x;
                }
            }
    
            //有字符的列
            $xImage = array_values(array_diff(range(0, 59), $xFilter));
    
            //存放关键字
            $wordImage = array();
    
            $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][$x] = $image[$y][$x];
                }
            }
    
            foreach($wordImage as $key=>$image) {
                $wordImage[$key] = $this->removeByLine($image);
            }
    
    
            return $wordImage;
    
        }
    
        /**
         * 按行移除无用数据
         * @param array $image
         * @return array
         */
        public function removeByLine($image) {
    
            $isFilter = false;
            foreach($image as $y => $yImage) {
                if($isFilter == true || array_filter($yImage)) {
                    $isFilter = true;
                } else {
                    unset($image[$y]);
                }
            }
    
            krsort($image);
    
            $isFilter = false;
            foreach($image as $y => $yImage) {
                if($isFilter == true || array_filter($yImage)) {
                    $isFilter = true;
                } else {
                    unset($image[$y]);
                }
            }
    
            ksort($image);
    
            return $image;
        }
    
        /**
         * 获取关键字字符串
         * @param array $wordImage
         * @return string
         */
        public function getWordString($wordImage) {
            $wordString = '';
            foreach($wordImage as $image) {
                foreach($image as $string) {
                    $wordString .= $string;
                }
            }
    
            return $wordString;
        }
    
        /**
         * 匹配关键字
         * @param array $image
         * @return array
         */
        public function match($image) {
            $match = array(
                'min' => '',
                'key' => ''
            );
            foreach($this->_wordKeys as $k => $v) {
                $percent = 0.0;
                similar_text($this->getWordString($image), $v, $percent);
                if($match['min'] == '') {
                    $match['min'] = $percent;
                    $match['key'] = $k;
                } else {
                    if($percent > $match['min']) {
                        $match['min'] = $percent;
                        $match['key'] = $k;
                    }
                }
            }
    
            return $match;
        }
    
        /**
         * 终端显示验证码
         * @param $image
         */
        public function show($image) {
            foreach($image as $xImage) {
                foreach($xImage as $yImage) {
                    echo $yImage;
                }
                echo PHP_EOL;
            }
            echo PHP_EOL;
        }
    }
    
    
    $vCode = new vCode();
    
    $codeImage = $vCode->make();
    $imageString = $codeImage['image'];
    
    $image = $vCode->getImage($imageString);
    //原图
    $vCode->show($image);
    
    //去除干扰边框、拆字
    $newImage = $vCode->remove($image);
    $word = array();
    $code = '';
    foreach($newImage as $image) {
        $vCode->show($image);
        $code .= $vCode->match($image)['key'];
    }
    
    echo "生成的验证码为:{$codeImage['code']}" . PHP_EOL;
    echo "识别的验证码为:{$code}" . PHP_EOL;
    
    
    /*
    //用来批量生成验证码的特征码。识别他人网站验证码,需要自己采集多张,人肉标记特征码
    $vCode = new vCode();
    
    $string = 'ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789';
    
    $max = ceil(strlen($string) / 4);
    
    $wordKeys = array();
    
    for($i=0;$i<$max;$i++) {
        $code = substr($string, $i * 4, 4);
        $imageString = $vCode->make($code)['image'];
    
    
        $image = $vCode->getImage($imageString);
        $newImage = $vCode->remove($image);
        foreach($newImage as $key => $image) {
            $word = $vCode->getWordString($image);
            isset($code[$key]) && $wordKeys[$code[$key]] = $word;
        }
    }
    
    echo var_export($wordKeys);
    */
    

    运行结果:

    图片描述

    扫描二维码,一起交流学习~

    图片描述

    展开全文
  • 所谓验证码,就是将一串随机产生的数字或符号,生成一幅图片,图片里加上一些干扰象素(防止OCR),由用户肉眼识别其中的验证码信息,输入表单提交网站验证,验证成功后才能使用某项功能。学习验证码的破解/识别技术...
  • PHP验证码识别实例

    千次阅读 2020-05-04 20:02:07
    PHP验证码识别实例 PHP验证码识别实例,识别的过程包括对图像的二值化、降噪、补偿、切割、倾斜矫正、建库、匹配,最后会提供实例代码,能够直接运行识别。 简述 要识别的验证码相对比较简单,没有粘连字符,但是会...

    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;
        }
    
    1111111111111111111111111111011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111100000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111100100111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111100111111111111111111111111111111111111111111111111000111111111111111111111111111111111111111111100000011111111111111111111111111111111111111
    1111111111111111000000000000001111111111111111111111111111110000000011111111100000001111111111111111111111000000000000111111111111111111111111111111111111110000000000011111111111111111111111111111111111000000000000001111111111111111111111111111111111
    1111111111111111100000100000001111111111111111111111111111110000000111111111000000001111111111111111111110000000000000001111111111111111111111111111111111100000000000000111111111111111111111111111111110000000000000000111111111111111111111111111111111
    1111111111111111100000000000001111111111111111111111111111110000000111111111000000001111111111111111111100000000000000000111111111111111111111111111111110000000000000000011111111111111111111111111111100000000000000000001111111111111111111111111111111
    1111111111111111100000000011101111111111111111111111111111110000100111111111000000011111111111111111111000000111110000000111111111111111111111111111111110000000000000000001111111111111111111111111111000000000000000000001111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111100000100111111111000000011111111111111111111000011111111100000111111111111111111111111111111100000000000000000000111111111111111111111111111000000000010000000000111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111100000101111111111000000011111111111111111110000011111111110000011111111111111111111111111111000000001111110000000111111111111111111111111110000000111111110000000111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111100000001111111111000000011111111111111111110000011111111110000011111111111111111111111111111001000011111110000000011111111111111111111111110000000111111110000000011111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111100000001111111110000000011111111111111111110000011111111111111111111111111111111111111111110000000011111111000000011111111111111111111111110000000111111111001111111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111000000001111111110000000111111111111111111111000001111111111111111111111111111111111111111110000000111111111000000011111111111111111111111110000000000111111111111111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111000000011111111110000000111111111111111111111000000011111111111111111111111111111111111111110100000111111111100000001111111111111111111111111000000000001111111111111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111000000011111111110000000111111111111111111111000000000001111111111111111111111111111111111100000000001010111100000001111111111111111111111111000000000000000011111111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111000000011111111100000000111111111111111111111100000000000001111111111111111111111111111111100000000000000000000000001111111111111111111111111000000000000000000011111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111000000011111111100000001111111111111111111111110000000001000001111111111111111111111111111100000000000010110000011001111111111111111111111111100000000000000000000111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111000000011111111100000001111111111111111111111111100000000000000011111111111111111111111111100000000000000010000110001111111111111111111111111110000000000000110000111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111110000000011111111100000001111111111111111111111111111100000000000011111111111111111111111111110000000000000000000000001111111111111111111111111111100000000000000000011111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111110000000111111111000000001111111111111111111111111111111110000000001111111111111111111111111110000000111111111111111111111111111111111111111111111111110000000000000011111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111110000000111111111000000001111111111111111111111111111111111110000001111111111111111111111111110000000111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111100000001111111111000000001111111111111111111111110111111111111000001111111111111111111111111110000000111111111011111111111111111111111111111111111101111111111000000001111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111100000001111111110000000011111111111111111111110000111111111111100001111111111111111111111111110000000011111111000001011111111111111111111111100000000111111111001000011111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111100000001111111100000000011111111111111111111110000011111111111100001111111111111111111111111111000000011111110000000011111111111111111111111100000000111111111001000011111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111100000000111111000000000011111111111111111111110000011111111111000001111111111111111111111111111000000001111110000000011111111111111111111111100000000011111111000100011111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111100000000001000000000000111111111111111111111111000001111111110000011111111111111111111111111111000000000000000000000111111111111111111111111110000000000000000000000111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111110000000000000000000000111111111111111111111111000000001111100000011111111111111111111111111111100000100000000000000111111111111111111111111111000000000000000000000111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111110000000000000011000100111111111111111111111111100000000000000000011111111111111111111111111111110000000000000000001111111111111111111111111111100000000000000000001111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111000000000000110000000111111111111111111111111110001000010000001111111111111111111111111111111111100000000000000011111111111111111111111111111110000000000000000011111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111100000000001110000000111111111111111111111111111000000000000011111111111111111111111111111111111110000000000001111111111111111111111111111111111000000000000001111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111000011111111111111111111111111111111111111111111100000111111111111111111111111111111111111111111111000011111111111111111111111111111111111111111110000111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    

    降噪 补偿

    验证码经常会加入一些噪点,这些噪点一般都是单独的点,有时候会加入几个单像素点连成干扰线,降噪的时候就需要去掉噪点与干扰线,我采用了将每个像素点周围四个像素点的值取出,计算如果周围四个像素点有两个以上是背景,也就是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;
        }
    
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111100000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111100000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111111111111111111111111111111111111111111111111111111100111111111111111111111111111111111111111111111111000111111111111111111111111111111111111111111100000011111111111111111111111111111111111111
    1111111111111111100000000000001111111111111111111111111111110000000111111111100000001111111111111111111111000000000000111111111111111111111111111111111111110000000000011111111111111111111111111111111111000000000000001111111111111111111111111111111111
    1111111111111111100000000000001111111111111111111111111111110000000111111111000000001111111111111111111110000000000000001111111111111111111111111111111111100000000000000111111111111111111111111111111110000000000000000111111111111111111111111111111111
    1111111111111111100000000000001111111111111111111111111111110000000111111111000000001111111111111111111100000000000000000111111111111111111111111111111110000000000000000011111111111111111111111111111100000000000000000001111111111111111111111111111111
    1111111111111111100000000011111111111111111111111111111111110000000111111111000000011111111111111111111000000111110000000111111111111111111111111111111110000000000000000001111111111111111111111111111000000000000000000001111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111100000000111111111000000011111111111111111111000011111111100000111111111111111111111111111111100000000000000000000111111111111111111111111111000000000000000000000111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111100000001111111111000000011111111111111111110000011111111110000011111111111111111111111111111000000001111110000000111111111111111111111111110000000111111110000000111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111100000001111111111000000011111111111111111110000011111111110000011111111111111111111111111111000000011111110000000011111111111111111111111110000000111111110000000111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111100000001111111110000000011111111111111111110000011111111111111111111111111111111111111111110000000011111111000000011111111111111111111111110000000111111111001111111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111000000001111111110000000111111111111111111111000001111111111111111111111111111111111111111110000000111111111000000011111111111111111111111110000000000111111111111111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111000000011111111110000000111111111111111111111000000011111111111111111111111111111111111111110000000111111111100000001111111111111111111111111000000000001111111111111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111000000011111111110000000111111111111111111111000000000001111111111111111111111111111111111100000000000000111100000001111111111111111111111111000000000000000011111111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111000000011111111100000000111111111111111111111100000000000001111111111111111111111111111111100000000000000000000000001111111111111111111111111000000000000000000011111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111000000011111111100000001111111111111111111111110000000000000001111111111111111111111111111100000000000000000000010001111111111111111111111111100000000000000000000111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111000000011111111100000001111111111111111111111111100000000000000011111111111111111111111111100000000000000000000000001111111111111111111111111110000000000000000000111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111110000000011111111100000001111111111111111111111111111100000000000011111111111111111111111111110000000000000000000000001111111111111111111111111111100000000000000000011111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111110000000111111111000000001111111111111111111111111111111110000000001111111111111111111111111110000000111111111111111111111111111111111111111111111111110000000000000011111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111110000000111111111000000001111111111111111111111111111111111110000001111111111111111111111111110000000111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111100000001111111111000000001111111111111111111111111111111111111000001111111111111111111111111110000000111111111111111111111111111111111111111111111111111111111000000011111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111100000001111111110000000011111111111111111111110000111111111111100001111111111111111111111111110000000011111111000000011111111111111111111111100000000111111111000000011111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111100000001111111100000000011111111111111111111110000011111111111100001111111111111111111111111111000000011111110000000011111111111111111111111100000000111111111000000011111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111100000000111111000000000011111111111111111111110000011111111111000001111111111111111111111111111000000001111110000000011111111111111111111111100000000011111111000000011111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111100000000000000000000000111111111111111111111111000001111111110000011111111111111111111111111111000000000000000000000111111111111111111111111110000000000000000000000111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111110000000000000000000000111111111111111111111111000000001111100000011111111111111111111111111111100000000000000000000111111111111111111111111111000000000000000000000111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111110000000000000010000000111111111111111111111111100000000000000000011111111111111111111111111111110000000000000000001111111111111111111111111111100000000000000000001111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111000000000000110000000111111111111111111111111110000000000000001111111111111111111111111111111111100000000000000011111111111111111111111111111110000000000000000011111111111111111111111111111111
    1111111111111111111100000111111111111111111111111111111111100000000001110000000111111111111111111111111111000000000000011111111111111111111111111111111111110000000000001111111111111111111111111111111111000000000000001111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111000011111111111111111111111111111111111111111111100000111111111111111111111111111111111111111111111000011111111111111111111111111111111111111111110000111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    
    

    切割

    由于此验证码并没有粘连,对于字符的切割相对而言比较简单,纵向统计出切割字符的起始与终止位置,切割后分别置入数组中,然后将横向的空白去除,同样也是统计字符有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;
        }
    
    1111111111111000001111111
    1111111100000000000001111
    1111111000000000000000011
    1111110000000000000000011
    1111100000000000000000001
    1111000000001111000000001
    1110000000011111100000000
    1110000000111111110000000
    1111111111111111110000000
    1111111111111111110000000
    1111111111111111100000001
    1111111100000000000000001
    1111100000000000000000001
    1110000000000000000000001
    1100000000000000000000001
    1000000000000111100000011
    1000000001111111000000011
    1000000011111111000000011
    0000000111111111000000011
    0000000111111110000000111
    0000000111111100000000111
    0000000011111000000000111
    1000000001100000000000111
    1000000000000000000000111
    1000000000000000000000111
    1100000000000010000000111
    1111000000001110000000111
    1111100001111111111111111
    

    倾斜矫正

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

    线性回归

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

    $img = [
        [1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1],
        [1,1,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1],
        [1,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0],
        [1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
        [1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0],
        [1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0],
        [1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0],
        [1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0],
        [1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0],
        [1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0],
        [1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0],
        [1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1],
        [1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1],
        [1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1],
        [1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1],
        [1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1],
        [1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1],
        [1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1],
        [1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1],
        [1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1],
        [1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1],
        [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1],
        [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1],
        [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1],
        [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1],
    ];
    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);
    
    111110000111100000000011
    111110000111000000000001
    111100001110000000000000
    111100000000000111100000
    111100000000111111110000
    111100000001111111110000
    111100000011111111110000
    111000000111111111110000
    111000000111111111110000
    111000001111111111110000
    111000001111111111100000
    111000011111111111100000
    110000011111111111100001
    110000011111111111000001
    110000111111111111000001
    110000111111111111000001
    110000111111111111000001
    100000111111111111000011
    100000111111111111000011
    100000111111111110000011
    100001111111111110000011
    100001111111111110000011
    000011111111111110000111
    000011111111111110000111
    000011111111111100000111
    000011111111111100000111
    
    10000111100000000011
    10000111000000000001
    00001110000000000000
    00000000000111100000
    00000000111111110000
    10000000111111111000
    10000001111111111000
    00000011111111111000
    00000011111111111000
    00000111111111111000
    10000011111111111000
    10000111111111111000
    00000111111111111000
    00000111111111110000
    00001111111111110000
    10000111111111111000
    10000111111111111000
    00000111111111111000
    00000111111111111000
    00000111111111110000
    10000111111111111000
    10000111111111111000
    00001111111111111000
    00001111111111111000
    00001111111111110000
    10000111111111111000
    

    投影法

    由于直接线性拟合的方式对于一些字符的效果比较差,于是采用投影法的方式,字符如果进行旋转,那么他的宽度势必会增加,于是可以在一定范围内尝试旋转字符,取得旋转过程中宽度最小时的字符,就是矫正后的字符。由于直接将竖直的字符根据斜率旋转的话,因为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, $yCount, $xCount, $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;
        }
    
    1111111111111000001111111
    1111111100000000000001111
    1111111000000000000000011
    1111110000000000000000011
    1111100000000000000000001
    1111000000001111000000001
    1110000000011111100000000
    1110000000111111110000000
    1111111111111111110000000
    1111111111111111110000000
    1111111111111111100000001
    1111111100000000000000001
    1111100000000000000000001
    1110000000000000000000001
    1100000000000000000000001
    1000000000000111100000011
    1000000001111111000000011
    1000000011111111000000011
    0000000111111111000000011
    0000000111111110000000111
    0000000111111100000000111
    0000000011111000000000111
    1000000001100000000000111
    1000000000000000000000111
    1000000000000000000000111
    1100000000000010000000111
    1111000000001110000000111
    1111100001111111111111111
    
    111111111110000011111111
    111111000000000000011111
    111110000000000000000111
    111100000000000000000111
    111000000000000000000011
    110000000011110000000011
    100000000111111000000001
    100000001111111100000001
    111111111111111110000000
    111111111111111110000000
    111111111111111100000001
    111111100000000000000001
    111100000000000000000001
    110000000000000000000001
    100000000000000000000001
    000000000000111100000011
    000000001111111000000011
    000000011111111000000011
    000000011111111100000001
    000000011111111000000011
    000000011111110000000011
    000000001111100000000011
    100000000110000000000011
    100000000000000000000011
    100000000000000000000011
    110000000000001000000011
    111100000000111000000011
    111110000111111111111111
    

    建库

    将验证码矫正过后,就需要建立特征匹配库了,这里我直接使用了将二值化的数组转化为字符串全部作为特征写入一个特征匹配数组,再手动打码,若是识别出的字符与我手动打码的字符不符,就将其加入特征匹配数组,然后将字符数组序列化存储到文件中,然后将这个序列化后的字符串进行压缩,存储到文件中,我提取的特征数组有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吧 😃
    https://github.com/WindrunnerMax/Example
    
    展开全文
  • PHP版本验证码高级识别源码
  • PHP自动识别验证码

    2013-11-08 17:35:50
    网上达人写的代码,用php识别图片上的验证码。包里面有初级和中级,以及提交篇的源码。这个对字体变形的验证码没有办法,对常见的加干扰和文字粘连效果不错。
  • PHP实现验证码自动识别,测试已通过,此为测试案例!此为测试案例!
  • 2021年学习爬虫必须掌握的验证码识别技术

    千次阅读 多人点赞 2021-01-19 21:56:45
    目录一、字符验证码1.1 搭建 OCR 环境1.2 下载验证码图片1.3 识别验证码图片二、第三方验证码识别2.1 第三方打码平台中验证码识别过程三、滑动拼图验证码四、总结 验证码是许多网站都采取的反爬虫机制,随着技术的...

    验证码是许多网站都采取的反爬虫机制,随着技术的发展,验证码出现了各种各样的形态。从一开始的几个数字,发展到随机添加几个英文字母以及混淆曲线、彩色斑点、滑动拼图等,形态越来越复杂。本篇博文将介绍如何使用 OCR 技术实现字符验证码的识别、如何使用第三方验证码识别平台识别验证码以及滑动拼图验证码的校验工作。

    一、字符验证码

    字符验证码的特点就是验证码中包含数字、字母或者掺杂着斑点与混淆曲线的图片验证码。识别此类验证码,首先需要找到验证码图片在网页 HTML 代码中的位置,然后将验证码下载,最后再通过 OCR 技术进行验证码的识别工作。

    1.1 搭建 OCR 环境

    Tesseract-OCR 是一个免费、开源的 OCR 引擎,通过该引擎可以识别图片中的验证码,搭建 OCR 的具体步骤如下:
    (1) 点击 此处 打开 Tesseract-OCR下载地址,然后选择与自己操作系统匹配的版本(博主电脑为 Windows 64位操作系统),如下图所示。
    在这里插入图片描述
    (2) Tesseract-OCR 文件下载完成后,默认安装即可。
    (3) 找到 Tesseract-OCR 的安装路径(默认为 C:\Program Files\Tesseract-OCR\tessdata),然后将安装路径添加至系统环境变量中,首先右键单击 此电脑 依次选择属性 ⇒ 高级系统设置 ⇒ 环境变量,然后在上面的用户变量中单击 新建,在弹出的 新建用户变量 窗口中设置变量名与变量值,如下图所示。
    在这里插入图片描述
    说明:Tesseract-OCR 环境变量配置完成以后,请重新启动 Pycharm 开发工具。

    (4) 接下来需要安装 tesserocr 模块,安装命令如下:

    pip install tesserocr  # 读者可自行添加镜像加快下载速度
    如果使用的是 Anaconda 并在安装 tesserocr 模块时出现了错误,可以使用如下命令:
    conda install -c simonflueckiger tesserocr
    

    如果以上两种安装 tesserocr 模块的方式都遇到问题时,可以从下面百度网盘中下载 tesserocr-2.4.0-cp37-cp37m-win_amd64.whl,接着启动 命令提示符窗口,然后通过 pip install tesserocr-2.4.0-cp37-cp37m-win_amd64.whl 安装 tesserocr 模块。

    链接:https://pan.baidu.com/s/1uE0BwOnGkxzzXjMqyKtCnA 
    提取码:i19b 
    复制这段内容后打开百度网盘手机App,操作更方便哦--来自百度网盘超级会员V6的分享
    

    在这里插入图片描述

    1.2 下载验证码图片

    以下面地址对应的网页为例,下载网页中的验证码图片,具体步骤如下:

    测试网页地址:https://so.gushiwen.cn/user/login.aspx?from=http://so.gushiwen.cn/user/collect.aspx
    

    (1)使用浏览器打开测试网页的地址,将显示下图所示的字符验证码。
    在这里插入图片描述
    (2) 打开浏览器开发者工具,然后在 HTML 代码中获取验证码图片所在的位置,如下图所示。
    在这里插入图片描述
    (3) 对目标网页发送网络请求,并在返回的 HTML 代码中获取图片的下载地址,然后下载验证码图片。代码如下:

    # -*- coding: UTF-8 -*-
    """
    @author:AmoXiang
    @file:1.download_pic.py
    @time:2021/01/19
    """
    import requests  # 导入网络请求模块
    import urllib.request
    from bs4 import BeautifulSoup  # 导入解析HTML的模块
    
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                      "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36"}
    # 发送网络请求
    url = "https://so.gushiwen.cn/user/login.aspx?from=http://so.gushiwen.cn/user/collect.aspx"
    response = requests.get(url=url, headers=headers)
    html = BeautifulSoup(response.text, "lxml")
    img_src = html.select("#imgCode")[0].attrs["src"]  # 解析图片src
    # 组合验证码图片请求地址
    img_url = "https://so.gushiwen.cn/" + img_src
    # 下载并设置图片名称
    urllib.request.urlretrieve(img_url, "code.png")
    

    程序运行后项目文件夹中将自动生成下图所示的验证码图片。
    在这里插入图片描述

    1.3 识别验证码图片

    验证码下载完成以后,如果没有安装 pillow 模块,需要通过 pip install pillow 命令安装一下,然后导入 tesserocr 与 Image 模块,再通过 Image.open() 方法打开验证码图片,接着通过 tesserocr.image_to_text() 函数识别图片中的验证码信息即可。示例代码如下:

    # -*- coding: UTF-8 -*-
    """
    @author:AmoXiang
    @file:demo.py
    @time:2021/01/19
    """
    
    import tesserocr  # 导入tesserocr模块
    from PIL import Image  # 导入图像处理模块
    
    img = Image.open("code.png")  # 打开验证码图片
    code = tesserocr.image_to_text(img)  # 将图片中的验证码转换为文本
    
    print(f"验证码为: {code}")
    

    博主重新生成了一张验证码图片,程序运行结果如下:
    在这里插入图片描述
    OCR 的识别技术虽然很强大,但是并不是所有的验证码都可以这么轻松地识别出来,例如下图所示的验证码中就会掺杂着许多干扰线条,那么在识别这样的验证码信息时,就需要对验证码图片进行相应的处理并识别。
    在这里插入图片描述
    如果直接通过 OCR 识别,识别结果将会受到干扰线的影响。下面通过 OCR 直接识别测试一下,识别代码与效果如下:

    import tesserocr  # 导入tesserocr模块
    from PIL import Image  # 导入图像处理模块
    
    img = Image.open("code.png")  # 打开验证码图片
    code = tesserocr.image_to_text(img)  # 将图片中的验证码转换为文本
    
    print(f"验证码为: {code}")
    

    程序运行结果如下:
    在这里插入图片描述
    通过以上测试可以发现,直接通过 OCR 技术识别后为空,遇到此类情况首先可以将彩色的验证码图片转换为灰度图片再测试一下。示例代码如下:

    import tesserocr
    from PIL import Image
    
    img = Image.open("code.png")
    img = img.convert("L")
    t = 155
    table = []
    for i in range(256):
        if i < t:
            table.append(0)
        else:
            table.append(1)
    
    img = img.point(table, "1")
    img.show()
    code = tesserocr.image_to_text(img)  # 将图片中的验证码转换为文本
    print(f"验证码为: {code}")
    

    程序运行后将自动显示下图所示二值化处理后的验证码图片。
    在这里插入图片描述
    控制台中所识别的验证码如下:
    在这里插入图片描述

    二、第三方验证码识别

    虽然 OCR 可以识别验证码图片中的验证码信息,但是识别效率与准确度不高是 OCR 的缺点。所以使用第三方验证码识别平台是一个不错的选择,不仅可以解决验证码识别效率低的问题,还可以提高验证码识别的准确度。使用第三方平台识别验证码是非常简单的,平台提供了完善的 API 接口,根据平台对应的开发文档即可完成快速开发的需求,但每次验证码成功识别后平台会收取少量的费用。

    验证码识别平台一般分为两种,分别是打码平台和 AI 开发者平台。打码平台主要是由在线人员进行验证码的识别工作,然后在较短的时间内返回结果。AI 开发者平台主要是由人工智能来进行识别,例如,百度 AI。

    2.1 第三方打码平台中验证码识别过程

    下面以打码平台为例,演示验证码识别的具体过程。

    (1) 点击 此处 在浏览器中打开打码平台网页,并且单击首页的 用户注册 按钮,如下图所示。
    在这里插入图片描述
    (2) 然后在用户中心的页面中填写注册账号的基本信息,如下图所示。

    说明:账号注册完成以后可以联系平台的客服人员,申请免费测试的题分。

    (3) 账号注册完成以后,在网页的顶部导航栏中选择 开发文档,然后在常用开发语言示例下载中选择 Python 语言,如下图所示。

    (4) 在 Python 语言 Demo下载页面中,查看注意事项,然后单击 点击这里下载 超链接即可下载示例代码,如下图所示。
    在这里插入图片描述
    (5) 平台提供的示例代码中,已经将所有需要用到的功能代码进行了封装处理,封装后的代码如下:

    # -*- coding: UTF-8 -*-
    """
    @author:AmoXiang
    @file:2.chaojiying.py
    @time:2021/01/19
    """
    import requests  # 网络请求模块
    from hashlib import md5  # 加密
    
    
    class Chaojiying_Client(object):
    
        def __init__(self, username, password, soft_id):
            self.username = username  # 自己注册的账号
            password = password.encode('utf8')  # 自己注册的密码
            self.password = md5(password).hexdigest()
            self.soft_id = soft_id  # 软件ID
            self.base_params = {  # 组合表单数据
                'user': self.username,
                'pass2': self.password,
                'softid': self.soft_id,
            }
            self.headers = {  # 请求头信息
                'Connection': 'Keep-Alive',
                'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
            }
    
        def PostPic(self, im, codetype):
            """
            im: 图片字节
            codetype: 题目类型 参考 http://www.chaojiying.com/price.html
            """
            params = {
                'codetype': codetype,
            }
            params.update(self.base_params)  # 更新表单参数
            files = {'userfile': ('ccc.jpg', im)}  # 上传验证码图片
            r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files,
                              headers=self.headers)
            return r.json()  # 返回响应数据
    
        def ReportError(self, im_id):
            """
            im_id:报错题目的图片ID
            """
            params = {
                'id': im_id,
            }
            params.update(self.base_params)
            r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
            return r.json()
    

    (6) 在已经确保用户名完成充值的情况下,填写必要参数,然后创建实例代码中的实例对象,实现验证码的识别工作。代码如下:

    if __name__ == '__main__':
        # 用户中心>>软件ID 生成一个替换 96001
        chaojiying = Chaojiying_Client('超级鹰用户名', '超级鹰用户名的密码', '96001')
        im = open('a.jpg', 'rb').read()  # 本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
        # 1902 验证码类型  官方网站>>价格体系 3.4+版 print 后要加()
        print(chaojiying.PostPic(im, 1902))
    

    (7) 使用平台示例代码中所提供的验证码图片,运行以上示例代码,程序运行结果如下:

    {'err_no': 0, 'err_str': 'OK', 'pic_id': '6129521154616800019',
     'pic_str': '7261', 'md5': 'cc4e43a6905b3a447436b273a3ea121b'}
    

    说明:程序运行结果中 pic_str 所对应的值为返回的验证码识别信息。

    在发送识别验证码的网络请求时,代码中的 1902 表示验证码类型,该平台支持所有的常用验证码类型点击 此处 可进行查询。

    三、滑动拼图验证码

    滑动拼图验证码是在滑动验证码的基础上增加了滑动距离的校验,用户需要将图形滑块滑动至主图空缺滑块的位置,才能通过校验。下面以测试地址对应的网页为例,实现滑动拼图验证码的自动校验,具体步骤如下:

    测试网页地址如下:

    http://sck.rjkflm.com:666/spider/jigsaw/
    

    (1) 使用浏览器打开测试网页的地址,将显示如下图所示的滑动拼图验证码。

    (2) 打开浏览器开发者工具,单击按钮滑块,然后在 HTML 代码中依次获取 按钮滑块/图形滑块 以及 空缺滑块 所对应的 HTML 代码标签所在的位置,如下图所示。
    在这里插入图片描述
    (3) 拖动按钮滑块,完成滑动拼图验证码的校验,此时将显示如下图所示的 HTML 代码。
    在这里插入图片描述
    滑动的距离 = 空缺滑块到左侧的距离 - 圆形滑块到左侧的距离
    (4) 通过按钮滑块的 left 值可以确认需要滑动的距离,接下来只需要使用 selenium 框架模拟滑动的工作即可。实现代码如下:

    # -*- coding: UTF-8 -*-
    """
    @author:AmoXiang
    @file:demo3.py
    @time:2021/01/19
    """
    
    from selenium import webdriver  # 导入webdriver
    import re  # 导入正则模块
    
    driver = webdriver.Chrome()  # 谷歌浏览器
    driver.get('http://sck.rjkflm.com:666/spider/jigsaw/')  # 启动网页
    swiper = driver.find_element_by_xpath(
        '/html/body/div/div[2]/div[2]/span[1]')  # 获取按钮滑块
    action = webdriver.ActionChains(driver)  # 创建动作
    action.click_and_hold(swiper).perform()  # 单击并保证不松开
    # 滑动0距离,不松手,不执行该动作无法获取图形滑块left值
    action.move_by_offset(0, 0).perform()
    # 获取图形滑块样式
    verify_style = driver.find_element_by_xpath(
        '/html/body/div/div[2]/div[1]/div[1]').get_attribute('style')
    # 获取空缺滑块样式
    verified_style = driver.find_element_by_xpath(
        '/html/body/div/div[2]/div[1]/div[2]').get_attribute('style')
    # 获取空缺滑块left值
    verified_left = float(re.findall('left: (.*?)px;', verified_style)[0])
    # print(verified_left)
    # 获取图形滑块left值
    verify_left = float(re.findall('left: (.*?)px;', verify_style)[0])
    # print(verify_left)
    action.move_by_offset(verified_left - verify_left, 0)  # 滑动指定距离
    action.release().perform()  # 松开鼠标
    

    四、总结

    在这里插入图片描述
    感谢您阅读本篇博文,希望本文能成为您编程路上的领航者。祝您阅读愉快!


    在这里插入图片描述

        好书不厌读百回,熟读课思子自知。而我想要成为全场最靓的仔,就必须坚持通过学习来获取更多知识,用知识改变命运,用博客见证成长,用行动证明我在努力。
        如果我的博客对你有帮助、如果你喜欢我的博客内容,请 点赞评论收藏 一键三连哦!听说点赞的人运气不会太差,每一天都会元气满满呦!如果实在要白嫖的话,那祝你开心每一天,欢迎常来我博客看看。
     编码不易,大家的支持就是我坚持下去的动力。点赞后不要忘了 关注 我哦!

    展开全文
  • php实现验证码识别

    2018-02-09 11:28:28
    php实现验证码识别,另外:此代码切勿用于非法用处,违者引起的一切后果自负。
  • 本文实例讲述了php实现的数字验证码及数字运算验证码。分享给大家供大家参考。具体如下: 1. 数字验证码: <?php //第一个实例是数字验证码,最常见的验证码。多少个数字可以由自己决定。 //$num是生成的验证码...
  • php实现验证码识别(中级篇)

    千次阅读 2016-08-29 10:07:23
    在上篇文章 php实现验证码识别 (初级篇 ) > 中,讲了如何识别简单的验证,这里的简单只的是验证码有数字和字母组成,格式统一,每次出现位置固定。这篇文章将继续深入研究识别验证码,这次识别的目标是,...

    在上篇文章 <php实现验证码的识别 (初级篇 ) > 中,讲了如何识别简单的验证,这里的简单只的是验证码有数字和字母组成,格式统一,每次出现位置固定。这篇文章将继续深入研究识别验证码,这次识别的目标是,验证码有字符和数字组成,验证码存在旋转(可能左右都旋转),位置不固定,存在字符与字符之间的粘连,且验证码有更强的干扰素。这篇文章讲解的方法,并不是万能的解决方案,并且提供代码不能直接解决你的问题,这里仅仅是方法,具体需求读者自己解决,需要说明的是,识别验证码与具体的编程语言无关,这里只是使用 php 语言实现,使用这里介绍的方法,你可以使用任何语言实现。

     这篇文章逐步讲解识别验证码过程中的各个步骤。

     
     如上图,随后的讲解我们都围绕此图展开。
     一:拿到一个验证码的,第一眼我们首先要做的工作是,二值化。把验证码的部分用 1 表示,背景部分用 0 表示出来,识别方法很简单,我们打印出验证码正张图片的 RGB ,然后分析其规律即可,通过 RGB 码,我们很容易分辨出上面这张图片的 R 值大于 120 , G 和 B 的值小于 80 ,所以依据这个规则我们很容易把上面的图片二值化。再看初级篇中识别的两张图

     

      刚看上去,感觉很复杂。验证码的图片每次背景色都不相同,且不是单色,各个验证码数字的颜色每次也各不相同。貌似很难二值化,其实我们打印出其 RGB 值很容易就发现。无论验证数字颜色如何变化,该数字的 RGB 值总有一个值小于 125 ,所以通过如下判断

    $rgbarray['red'] < 125 || $rgbarray['green']<125|| $rgbarray['blue'] < 125

    我们就很容易分辨出哪里是数字,哪里是背景。

      我们能够找到这些规律的因素是,在制作验证码的干扰素时,为了使干扰素不影响数字的显示效果,必须使用干扰素的 RGB 和数字 RGB 相互独立,互不干扰。只要懂得这个规律,我们就很容易实现二值化。

      我们找到的 120 , 80 , 125 等阈值,可能和实际的 RGB 有出入,所以,有时二值化后,会有部分地方出现 1,对于验证码上固定位置显示数字,这种干扰没有太大意义。但是对于验证码位置不确定的图片来说,在我们切割字符时,很可能造成干扰。所以,在二值化后要进行去噪出来。

      二:接下来我们进行第二个步骤,出噪。出燥的原理很简单,就是把孤立的有效的值去掉,如果噪点比较高,要求的效率也比较高的话,这里面也有很多工作要做。幸好这里我们不要求这么高深,我们使用最简单的方法就可以,如果一个点为 1 则判断这个点的上下左右上左上右下左下右 8 个方位上数字是否为 1 ,如果不为 1 ,就认为是一个燥点,直接设置为 1 即可。

    如上图所示,我们使用此方法很容易发现红色方框部分的 1 为燥点,直接设置为 1 即可。

    在判断时我们使用了一个技巧,有时候的噪点可能是两个连续的 1 ,所以我们

    1. $num = 0;  
      if($data[$i][$j] == 1)  
      {  
          // 上  
          if(isset($data[$i-1][$j])){  
              $num = $num + $data[$i-1][$j];  
          }  
          // 下  
          if(isset($data[$i+1][$j])){  
              $num = $num + $data[$i+1][$j];  
          }  
          // 左  
          if(isset($data[$i][$j-1])){  
              $num = $num + $data[$i][$j-1];  
          }  
          // 右  
          if(isset($data[$i][$j+1])){  
              $num = $num + $data[$i][$j+1];  
          }  
          // 上左  
          if(isset($data[$i-1][$j-1])){  
              $num = $num + $data[$i-1][$j-1];  
          }  
          // 上右  
          if(isset($data[$i-1][$j+1])){  
              $num = $num + $data[$i-1][$j+1];  
          }  
          // 下左  
          if(isset($data[$i+1][$j-1])){  
              $num = $num + $data[$i+1][$j-1];  
          }  
          // 下右  
          if(isset($data[$i+1][$j+1])){  
              $num = $num + $data[$i+1][$j+1];  
          }  
      }  
      if($num == 0){  
          $data[$i][$j] = 0;  
      }  

    我们计算这个点的 8 个方向上的值之和,最后我们判断他们的和是否小于特定的阈值
     三:经过去噪后,我们就得到干净的二值化的数据,接下来要做的就是切割字符了。切割字符的方法有很多种,这里我采用最简单的一种,先垂直方向切割成为字符,然后在水平方向去掉多于的 0000 ,如下图

    第一步切割红线部分,第二步切割蓝线部分,这样就可以得到独立的字符了。但是像下面这种情况

     
    按上面的方法会把 dw 字符切割成一个字符,这是错误的切割,所以这里我们涉及到粘连字符的切割。
     四:粘连字符切割,制作验证码时,规则字符的粘连很容易分割开,如果字符本身有缩放,变形就很难处理,经过分析,我们可以发现,上面的字符粘连属于很简单的方式,只是规则字符的粘连,所以处理这种情况,我们也使用很简单的处理方式。当完成分割操作后,我们不能马上确定分割的部分就为一个字符,要进行验证,验证的关键因素就是,切割下来的字符的宽是否大于阈值,这个阈值的取舍标准是,一个字符无论怎么旋转变形都不会大于这个阈值,所以,如果我们切割的块大于这个阈值,就可以认为这是一个粘连字符;如果大于两个阈值之和,就认为是三个字符粘连,以此类推。知道这个规则后,切割粘连字符也就很简单了。如果我们发现是粘连字符块,直接平分这个块为两个或者多个新的块就可以。当然为了更好的还原字符,我一般都采用平分 +1 , -1 对字符块的部分进行适当的补充。
     五:经过上面四个步骤,我们就可以提取出比较纯的字符块了,接下来要做就是匹配字符了。对于旋转字符的特征码建立,有很多种方法,这里就不做深入研究了。我这里使用的最简单的方式,为所有字符的所有情况建立匹配库,所以在我提供的代码种增加了 study 操作,其目的就是,先有人手工识别图片的验证码,然后通过 study 方法,写入特征码库。这样写入的图片数据越多,验证识别的准确行也就越高。
     好了,经过以上步骤,我们基本上可以识别现在互联网上大部分的验证码,这里我们都是使用的最简单的方法,没有使用任何 OCR 知识。这些方法,应该属于非 OCR 领域的顶峰了,要想识别更加复杂的验证码,那就需要更多的 OCR 知识了。有机会的话,我会在高级篇中一一做介绍。
     下面是一些容易识别的验证码,希望引起网站管理者的重视。

       

      
    制作验证码的一些建议
     对于识别验证码的程序来说,最难得部分是验证字符的切割和特征码的建立,而国内很多程序员只做验证码时,总是喜欢在验证码加很多干扰素,干扰线,影响效果不说,还达不到很好的效果;所以,要想使自己验证码难于本识别,只做下面两点就够了 
    1 :字符粘连,最好所有的字符都有粘连的部分; 
    2 :不要使用规格字符,验证码的各个部分使用不同比例的缩放或者旋转。
    只要做到这两点,或者这两点的变形,识别程序就很难识别。我们看看, yahoo 和 google 的验证码就知道,白字黑底,却很难被识别。

    Goole:

     

    yahoo:

     

    源文件下:点击下载 

    展开全文
  • 资源介绍:简单调用亦思验证码识别验证码无声教程,没多大技术含量,勉强来看看吧!以前有个教程丢了,这段时间偶尔有易友问我要,今天我来做个简单识别教程!来找一个目标,呵呵 早有预谋注册地址:...
  • php实现验证码识别(初级篇)

    千次阅读 2015-08-27 09:04:57
    自动识别简单的不粘连验证码
  • 全自动区分计算机和人类的公开图灵测试(英语:Completely Automated Public Turing test to tell Computers and Humans Apart,简称CAPTCHA),俗称验证码,是一种区分用户是计算机和人的公共全自动程序。...
  • 全自动区分计算机和人类的公开图灵测试(英语:Completely Automated Public Turing test to tell Computers and Humans Apart,简称CAPTCHA),俗称验证码,是一种区分用户是计算机和人的公共全自动程序。...
  • 验证码的普通识别代码

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,775
精华内容 2,710
关键字:

php验证码识别