本部落客要探讨基于傳統方法的驗證碼識别,更多的是做粘連扭曲的驗證碼識别的各種分割技術,其實在驗證碼識别這一塊,深度學習做的已經非常好了,識别效率與速度都是不錯的。【驗證碼識别】,我這裡隻是做一些技術探讨,關于【 基于投影的字元分割】 請檢視。
一、基于連通域的字元分割
import queue
from PIL import Image
def cfs(img):
"""傳入二值化後的圖檔進行連通域分割"""
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 = []
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)
except:
pass
if x_axis:
min_x, max_x = min(x_axis), max(x_axis)
if max_x - min_x > 3:
# 寬度小于3的認為是噪點,根據需要修改
cuts.append((min_x, max_x + 1))
return cuts
def binarizing(img, threshold):
"""傳入image對象進行灰階、二值處理"""
img = img.convert("L") # 轉灰階
pixdata = img.load()
w, h = img.size
# 周遊所有像素,大于門檻值的為黑色
for y in range(h):
for x in range(w):
if pixdata[x, y] < threshold:
pixdata[x, y] = 0
else:
pixdata[x, y] = 255
return img
img = Image.open('C98Q.png')
img = binarizing(img, 200)
cuts = cfs(img)
w, h = img.size
for i, item in enumerate(cuts):
box = (item[0], 0, item[1], h)
img.crop(box).save("./" + str(i+10) + ".png")
遞歸法
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5CM3ETM3EmZ1kTNhNDNzEDZyYzXyQjMzcTM1EzLcdDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
import numpy as np
import cv2
from PIL import Image
def getPoint(x,y,data,subdata=None):
a=[0,-1,0,1,0,-2,0,2,0,-3,0,3,0,-4,0,4,0,-5,0,5]
b=[1,0,-1,0,2,0,-2,0,3,0,-3,0,4,0,-4,0,5,0,-5,0]
width,height=data.shape
if subdata is None:
subdata=[]
if x>5 and y<height-5 and y>5 and x<width-5:
for i in range(20):
if data[x+a[i]][y+b[i]]==1:
subdata.append((x+a[i],y+b[i]))
data[x+a[i]][y+b[i]]=2
getPoint(x+a[i],y+b[i],data,subdata)
subdata.append((x,y))
def getcell(data):
list1=[]
index=0
flag=True
for y in range(data.shape[1]):
for x in range(data.shape[0]):
if data[x][y]==1:
if list1:
for i in range(len(list1)):
if (x,y) in list1[i]:
flag=False
if not flag:
continue
list1.append([])
getPoint(x,y,data,list1[index])#調用流水算法
index+=1
else :
continue
for index in range(len(list1)):
l=list1[index][0][0]
t=list1[index][0][1]
r=list1[index][0][0]
b=list1[index][0][1]
for i in list1[index]:
x=i[0]
y=i[1]
l=min(l,x)
t=min(t,y)
r=max(r,x)
b=max(b,y)
w=r-l+1
h=b-t+1
if (w*h <8):#去除小色塊
continue
img0=np.zeros([w,h])#建立全0矩陣
for x,y in list1[index]:
img0[x-l][y-t]=1
img0[img0<1]=255
img1=Image.fromarray(img0)
img1=img1.convert('RGB')
img1.save('img2/'+str(index)+'.png')
if __name__=="__main__":
filename='captcha1.png'
data=cv2.imread(filename,2)
allimg=getcell(data)