验证码识别之图片处理(基础流程)

个人认为验证码识别的核心并不是学习算法的实现,而是图片的前期处理,处理的好直接丢进学习也能得到很高的识别成功率。

其实使用什么语言没有关系,原理都是一样的,所以各位不用过于纠结是什么语言实现,主要是思路。

本文代码均用python示例,源作者均为各博客,我只是拿来修改了部分,添加了一些可配置的参数,毕竟原代码已经写的很好了。

言归正传,让我们看看一张普通的图形验证码:

可以看到图片中有干扰线,干扰点,颜色不统一,位置不平均。

我们来分析一下需要怎么做才能提高我们后期机器学习的识别率:

1、黑白两色。

2、没有干扰线,干扰点,最好是图片中只有字母和背景。

3、分割为单独的数字或字母。

这也是处理一般的图形码需要做的事情,对应的处理方法就可以得出:

1、二值化。

2、去噪点,去干扰。

3、切割。

让我们一个个来看:

二值化:

我们知道,图片都是由一个个像素点组成的,每个点都有对应的颜色,组合起来就能看到一张图片了。

而二值化就是将图片转化为黑白两色,即RGB中的(255,255,255)和(0,0,0)两种颜色,用0,1表示,方便我们后续的处理。

所以这里很简单,我们只要指定对应的方法将每个点的颜色分类即可。

你可以取平均值大于某个值,或者指定某个颜色的权重稍微大一点,总归一点,深颜色变为黑色,浅颜色变为白色即可。

python代码如下,先灰度化再二值化:

img = img.convert('L') #灰度化
threshold = 125    
table = []
for i in range(256):
    if i < threshold:
        table.append(0)
    else:
        table.append(1)
img = img.point(table, '1')

灰度化后的图片:

二值化后的图片:

(这里还用到了一点点别的操作,待会再说)

去噪点,去干扰:

我们得到这种图片后,发现上面有一些不需要的杂质,我们需要将其去掉,但是在去掉的时候,又不能影响到本身的字母。

分析一下杂质和字母的区别:

很明显,杂质较为分散,字母都连在一起。

那处理方法就很简单了:

1、若连接在一起的点多于某个值,便认为是字母,少于某个值,则为杂质,变为白色。

2、若某个点周围的8个点中黑色点的数量少于某个值,便认为是杂质,变为白色。

(若干扰线很粗很长的话,我们需要另外处理,我们后续再说)

python代码:

# 去掉二值化处理后的图片中的噪声点
def cut_noise(image, pixel_node):

    rows, cols = image.size # 图片的宽度和高度
    change_pos = [] # 记录噪声点位置

    # 遍历图片中的每个点,除掉边缘
    for i in range(1, rows-1):
        for j in range(1, cols-1):
            # pixel_set用来记录该店附近的黑色像素的数量
            pixel_set = 0
            # 取该点的邻域为以该点为中心的九宫格
            for m in range(i-1, i+2):
                for n in range(j-1, j+2):
                    if image.getpixel((m, n)) != 1: # 1为白色,0位黑色
                        pixel_set += 1
            if pixel_set <= pixel_node:
                change_pos.append((i,j))
    for pos in change_pos:
        image.putpixel(pos, 1)
    return image 

去噪点后的图片:

可以发现,已经没有明显的小点点了。

切割图片:

得到这样的图片后,我们就可以切割为单个字母以提高识别率了。

切割图片一般都是找到单个字母左右两边界的y轴座标,然后按照这个座标来切割。

而我们得到这些切割线的y座标,就可以有两种思路:

1、遍历y轴座标,黑点多的区域内大概率为字母。(投影)

2、获取所有连接在一起的黑点,个数越多,是字母的概率越大。(连通域)

python代码如下:

投影:

def vertical(img, cut_node):
    """传入二值化后的图片进行垂直投影"""
    pixdata = img.load()
    w,h = img.size
    ver_list = []
    # 开始投影
    for x in range(w):
        black = 0
        for y in range(h):
            if pixdata[x,y] == 0:
                black += 1
        ver_list.append(black)
    # 判断边界
    l,r = 0,0
    flag = False
    cuts = []
    for i,count in enumerate(ver_list):
        # 阈值这里为0
        if flag is False and count > cut_node:
            l = i
            flag = True
        if flag and count <= cut_node:
            r = i-1
            flag = False
            cuts.append((l,r))
    for item in cuts:
        if item[1] - item[0] < cut_node:
            cuts.remove(item)
    return cuts

连通域:

def cfs(img, cut_pot):
    """传入二值化后的图片进行连通域分割"""
    pixdata = img.load()
    w,h = img.size
    visited = set()
    q = queue.Queue()
    offset = [(-1,-1),(0,-1),(1,-1),(-1,0),(1,0),(-1,1),(0,1),(1,1)]
    cuts = []
    for x in range(w):
        for y in range(h):
            x_axis = []
            #y_axis = []
            if pixdata[x,y] == 0 and (x,y) not in visited:
                q.put((x,y))
                visited.add((x,y))
            while not q.empty():
                x_p,y_p = q.get()
                for x_offset,y_offset in offset:
                    x_c,y_c = x_p+x_offset,y_p+y_offset
                    if (x_c,y_c) in visited:
                        continue
                    visited.add((x_c,y_c))
                    try:
                        if pixdata[x_c,y_c] == 0:
                            q.put((x_c,y_c))
                            x_axis.append(x_c)
                            #y_axis.append(y_c)
                    except:
                        pass
            if x_axis:
                min_x,max_x = min(x_axis),max(x_axis)
                if max_x - min_x > cut_pot:
                    # 宽度小于3的认为是噪点,根据需要修改
                    cuts.append((min_x,max_x))
    return cuts

处理后的图片:

            

这样就快乐地可以丢进学习算法中进行识别了。

 

以上均为较为简单的验证码处理,根据各验证码不同会有一些不同的算法,挖个坑,过两天来填上。

tasks = [
	'深色背景验证码图片',
	'又粗又长干扰线处理',
	'多处重合但颜色不同字母处理',
	'点击or拖动验证码处理',
]

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章