简单验证码的识别基本步骤:灰度读取、二值化、分割、CNN训练识别

加入干扰线的验证码识别:

若干扰线的颜色和字符不同,则直接将颜色不一致的线条所在像素修改为背景色

若干扰线的颜色和字符相同,考虑干扰线的粗细和字符粗细比较

若干扰线较细,可以通过这两种方法去掉:


若干扰线较粗,则可以类似第一种方法,计算干扰线附近像素点的数目,大于某个阈值就确定为干扰线的部分

若干扰线和字符颜色一致,大小相差不多,目前还没想出什么办法。。

加入倾斜的验证码识别:

一般考虑将倾斜的字母通过一定角度投影,计算投影的长度,当长度达到最小,则倾斜可以矫正,参考以下两篇:

http://www.doc88.com/p-9085440806713.html

https://blog.mythsman.com/2016/04/16/1/

加入噪音像素的验证码识别:

一般考虑中值滤波处理,参考这篇http://www.jianshu.com/p/41127bf90ca9

主要原理是这样的:把局部区域的像素按灰度等级进行排序,取该领域中灰度的中值作为当前像素的灰度值。

需要注意的是,中值滤波会使得图片模糊。


以下是一张验证码:

java GimpyEngine 验证码的干扰线 验证码干扰线去除算法_验证码识别

放大之后发现一个规律

java GimpyEngine 验证码的干扰线 验证码干扰线去除算法_像素点_02

干扰线的线条比较粗,并且通常呈现2行,可以发现规律将其去除,代码如下:

im = cv2.imread(path,0) #直接读为灰度图像
    #plt.subplot(111),plt.imshow(im),plt.title('oo')
    im=np.array(im)
  
    point = np.min(im)
    
    h,w=im.shape#40,100
    
    def change(black_point=0):
        for y in xrange(1,w-1):#1-39
            for x in xrange(1,h-1):#1-99
                mid_pixel = im[x,y] #中央像素点像素值
                if mid_pixel == point: #找出下、右、右下三个方向像素点像素值
                    right_pixel = im[x+1,y]
                    right_down_pixel = im[x+1,y+1]
                    down_pixel = im[x,y+1]
                    up_pixel=im[x-1,y]
        
                    #判断三个方向的黑色像素点总个数
                    if right_down_pixel == point:
                        black_point += 1
                    if up_pixel == point:
                        black_point += 1
                    if right_pixel == point:
                        black_point += 1
                    if down_pixel == point:
                        black_point += 1
                    if black_point >= 3:
                        im[x,y]=255
                        im[x+1,y]=255
                        im[x-1,y]=255
                    black_point = 0

去除之后发现有些噪点没有去掉,这些噪点通常只有一个像素点或者上下两个,这样的话同样修改以上函数就可以达到去除效果。


关于倾斜角度,原理跟我上面说的一样,需要用到仿射函数,代码如下:

def shadow(im):#传入图像im以及角度(角度制)angle,返回图像在该角度下的投影长度
    thresh,im=cv2.threshold(255-im,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)    
    y = {}
    height , width = im.shape
    for angle in np.linspace(45,135,91):
        pts1=np.float32([[width/2,height/2],[width/2,0],[0,height/2]])
        pts2=np.float32([[width/2,height/2],[width/2+height/2/math.tan(math.radians(angle)),0],[0,height/2]])
        M=cv2.getAffineTransform(pts1,pts2)
    
        dst=cv2.warpAffine(im,M,(width,height))
        x=[]
        for i in xrange(height):
            for j in xrange(width):
                if dst[i][j]==255:
                    x.append(j)
        x=np.array(x)
        y[angle] = x.max()-x.min()
#    return y
    return y.keys()[y.values().index(sort(y.values())[0])]