驗證碼識別之圖片處理(基礎流程)

個人認爲驗證碼識別的核心並不是學習算法的實現,而是圖片的前期處理,處理的好直接丟進學習也能得到很高的識別成功率。

其實使用什麼語言沒有關係,原理都是一樣的,所以各位不用過於糾結是什麼語言實現,主要是思路。

本文代碼均用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拖動驗證碼處理',
]

 

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