天天看點

OpenCV—python 字元分割

本部落客要探讨基于傳統方法的驗證碼識别,更多的是做粘連扭曲的驗證碼識别的各種分割技術,其實在驗證碼識别這一塊,深度學習做的已經非常好了,識别效率與速度都是不錯的。【驗證碼識别】​,我這裡隻是做一些技術探讨,關于​​【 基于投影的字元分割】​​ 請檢視。

一、基于連通域的字元分割

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")      

遞歸法

OpenCV—python 字元分割
OpenCV—python 字元分割
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)