rise前些天发了个dvbbs 5.5 的验证码过来讨论,

这些验证码有一个比较有特点的地方是进行了字符腐蚀,这样让一些字符上的线条和杂线有点难以区分,字符分割可能带来一定的干扰

步骤如下:
1、利用HSL中的亮度值进行阀值分割
2、去除杂线
3、分割字符
4、学习

作者: 4111y80y
目录: 验证码识别 at 8月 29th, 2008. 1 Comment.

首先我们要去除它的背景,对于这样稍微复杂的背景,用过去的方法很难做到,上图的例子还不是很明显,我发现很多图片背景色和字母色近似,而且字母颜色是不断变化的,背景也是不断变化的

那我初始的想法是找到图片中使用颜色最多的方法,于是我们用HSL表示各点颜色,接着进行统计,得到最大的几个峰值,这里便是图片中几个最丰富的颜色的L值得累加值

其余的都可以认为是噪音,我们对每个峰值进行分割,得到如下图片

你看这样就把单个颜色图片分割出来了,接下来就是找到图片中除去黑色和白色后的图片

然后进行灰化处理,阀值处理,降噪,得到

接着根据边界检测出来的最左侧x位置,来排序字母顺序

接下来的事情就轻车熟路了,把图片转成标准模板,通过少量学习就达到了95%以上的识别率

c:15 j:8 8:7 t:9 9:4 x:7 4:6 2:4 h:7 f:8 e:18 b:5 y:3 k:4 w:3 g:5 3:5 7:6 r:2 m:3 q:4 v:2 p:3 6:2
以上数据表示 c学习15次 j学习8次…

只要字符不粘连,大部分验证码干扰技术都是可以有办法,所以为什么google验证码看起来很简单,但是没有人能够很好的破解它得原因。

补充,
rise在留言中发现有一些字符加入杂点的问题,由于这种验证码不是很普遍,稍微做了研究

CY3E 这个图片3字中有杂点,其他没有,按照文章中介绍的办法,怎么知道这个3不是像其他颜色杂点一样的图片呢?

我觉得需要加入一个步骤,就是对每次过滤颜色生成出来的图片,进行填充
找到3的杂点原图:

然后我们进行算法填充

这个图片与其他全部是杂点的图片之间的差别进行过滤,我考虑可以通过以下方法:
1、连贯点的宽度
2、连贯点的个数
这样剩下的就只剩下CY3E的过滤后的图片

至于字符倾斜的问题,我觉得完全可以在机器学习过程中,我们自己旋转正在学习的图片一定角度,例如从-10到+10度,只不过这样的学习库会大一些,但是就10个数字的验证码来说,这点性能损失应该可以忽略不计。

作者: 4111y80y
目录: 验证码识别 at 7月 6th, 2008. 7 Comments.

博客园的验证码有一个波形变形,对于字符分割带来了一定难度,还好没有产生字符粘连,可以通过字符旋转,来找到最佳旋转角。

1、使用阀值和阀值去噪音

2、进行扭曲,测出那些时可以分割成4个字符的图形,进行学习

3、样本模板尺寸定位6*9,因为验证码可以通过以一个网址重复的到多次,所以我们对每个字符大概学习5000次后,验证码识别率可以大于%95

对于扭曲过的图片,使用神经网络比模板发应该要好很多,改进后将讲解详细算法。

C#相关算法如下:

/// <summary>
/// 正弦曲线Wave扭曲图片
/// </summary>
/// <param name=”srcBmp”></param>
/// <param name=”bXDir”></param>
/// <param name=”nMultValue”>波形的幅度倍数</param>
/// <param name=”dPhase”>波形的起始相位,取值区间[0-2*PI)</param>
/// <returns></returns>
public Bitmap TwistImage(Bitmap srcBmp, bool bXDir, double dMultValue, double dPhase)
{
    System.Drawing.Bitmap destBmp = new Bitmap(srcBmp.Width, srcBmp.Height);

    // 将位图背景填充为白色
    System.Drawing.Graphics graph = System.Drawing.Graphics.FromImage(destBmp);
    graph.FillRectangle(new SolidBrush(System.Drawing.Color.White), 0, 0, destBmp.Width, destBmp.Height);
    graph.Dispose();

    double dBaseAxisLen = bXDir ? (double)destBmp.Height : (double)destBmp.Width;

    for (int i = 0; i < destBmp.Width; i++)
    {
        for (int j = 0; j < destBmp.Height; j++)
        {
            double dx = 0;
            dx = bXDir ? (Math.PI * 2 * (double)j) / dBaseAxisLen : (Math.PI * 2 * (double)i) / dBaseAxisLen;
            dx += dPhase;
            double dy = Math.Sin(dx);

            // 取得当前点的颜色
            int nOldX = 0, nOldY = 0;
            nOldX = bXDir ? i + (int)(dy * dMultValue) : i;
            nOldY = bXDir ? j : j + (int)(dy * dMultValue);

            System.Drawing.Color color = srcBmp.GetPixel(i, j);
            if (nOldX >= 0 && nOldX < destBmp.Width
            && nOldY >= 0 && nOldY < destBmp.Height)
            {
                destBmp.SetPixel(nOldX, nOldY, color);
            }
        }
    }

    return destBmp;
}

作者: 4111y80y
目录: 验证码识别 at 6月 15th, 2008. No Comments.

1、分析Gif动画,得到总帧数,和每帧的相关信息

2、取出延迟时间最长的那一帧

3、用第一行的每个像素颜色来去除背景(要限制去除范围,不然可能去掉文字)

4、使用Closing降噪、阀值处理得到比较整洁的黑白验证码

5、利用字符间空白分割字符

          

6、提取样例特征进行机器学习

7、样例200个的情况下,识别率可以达到>80%,如果继续学习,识别率可以更高。

作者: 4111y80y
目录: 验证码识别 at 6月 9th, 2008. No Comments.

这是我研究的第1种类型的幅验证码图片,虽然简单,但是大家可以看到验证码识别的一般过程

一副验证码图片

我们首先对其进行对比度调节,你会发现干扰圈不见了

对比度处理后的验证码

我们对图片进行二值化,然后对字母进行边缘加强,然后去除噪点

彻底降噪后的验证码图片

接下来我们就对图片进行分割,得到单字符

分解到单个字符

然后对其进行区域扫描,根据所占区域的百分比,来算出字符的特征值(注:这里我没有对字符进行旋转处理,因为样本数不会很多,对于旋转处理,我会在下一个章节讨论)

例如6这个文字,特征码从下面可以看出:010100111101010

○■○
■○○
■■■
■○■
○■○

特征码的区域划分根据验证码的情况来划分,这里是划成了3*5的块。这样我们把很多样本的特征码保存起来,变成一个库,在一个未知的图片输入进来的时候,我们在列表中匹配,找到最相似的特征码,这样就知道图片是那个字符了。

我们希望的不是对单个验证码的识别,必须研究一套框架,便于识别大部分的验证码。
验证码识别框架

这里要注意,就是这里图片里的验证码情况比较简单,没有出现连字的情况,也就是说你可以很容易区分每个字符,例如像gmail这样的验证码,写这个验证码的工程师说,目前还没有发现能够达到写出识别这个验证码的人类

另外这种识别验证码的方式还比较原始,使用的是模板匹配的方式,另外还有Bayes分类、几何分类、神经网络分类来识别验证码,我也会在以后的帖子中和大家一起探讨这些方法。

 

 

作者: 4111y80y
目录: 验证码识别 at 6月 5th, 2008. No Comments.