OpenCV 银行卡卡号识别

银行卡卡号识别步骤

1.对模板数字进行处理,得到每个模板的数字。

代码如下(示例):

import cv2
import numpy as np

def sort_contours(cnts,method = 'left-to-right'):
    reverse = False
    i = 0
    if method =='right-to-left' or method =='bottom-to-top':
        reverse = True
    if method == 'top-to-bottom'or method =='bottom-to-top':
        i = 1
    boundingBoxes = [cv2.boundingRect(cnt)for cnt in cnts]
    (cnts,boundingBoxes) = zip(*sorted(zip(cnts,boundingBoxes),
                                    key = lambda b: b[1][i],
                                     reverse = reverse))
    return cnts,boundingBoxes
    
 def cv_show(name,img):#定义一个函数
    cv2.imshow(name,img)
    cv2.waitKey()
    cv2.destroyAllWindows()

img = cv2.imread('ocr_a_reference.png')#读模板
# cv_show('img',img)
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
                                #色彩空间转化,转化为灰度图
# cv_show('img_gray',img_gray)
ret,img_binary = cv2.threshold(img_gray,127,255,1)#二值化
cv_show('img_binary',img_binary)
   
cnts,hierarchy = cv2.findContours(img_binary,cv2.RETR_EXTERNAL,
                                  cv2.CHAIN_APPROX_SIMPLE)
                                    #查找外轮廓
img_rect = cv2.drawContours(img,cnts,-1,(0,0,255),2)# 绘制轮廓
cv_show('img_rect',img_rect)
cnts = sort_contours(cnts)[0]
number = {}

for (i,cnt) in enumerate(cnts):
    (x,y,w,h) = cv2.boundingRect(cnt)
    roi = img_binary[y:y+h,x:x+w]
    roi = cv2.resize(roi,(57,88))
    number[i] = roi
  

OpenCV 银行卡卡号识别_第1张图片


2.对银行卡上的数字进行选取

# 读取信用卡图片
cardImg = cv2.imread('credit_card_01.png')
cardImg = cv2.resize(cardImg,(300,int(float(300/cardImg.shape[1])
                                      *cardImg.shape[0]))
                    ,interpolation = cv2.INTER_AREA)
# cv_show('cardImg',cardImg)
cardImg_gray = cv2.cvtColor(cardImg,cv2.COLOR_RGB2GRAY)
# cv_show('cardImg_gray',cardImg_gray)
# 指定卷积恢大小
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(7,7))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
# 进行礼帽操作
cardImg_tophat = cv2.morphologyEx(cardImg_gray,cv2.MORPH_TOPHAT,rectKernel)
cv_show('cardImg_tophat',cardImg_tophat)
  

OpenCV 银行卡卡号识别_第2张图片


3.对非卡号数字进行剔除

# 使用sobel算子进行边缘检测,这里仅适用x方向的梯度。因为经过实验,适用x,y混合的梯度,效果并不理想
sobelx = cv2.Sobel(cardImg_tophat,cv2.CV_64F,1,0,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
(minX,maxX) = (np.min(sobelx),np.max(sobelx))
sobelx = (255*((sobelx-minX)/(maxX-minX)))
sobelx = sobelx.astype('uint8')
# cv_show('sobelx',sobelx)
# 进行数字闭运算,使相邻的数字连接起来,这样便于删选
cardImg_close = cv2.morphologyEx(sobelx,cv2.MORPH_CLOSE, rectKernel)
# cv_show('cardImg_close',cardImg_close)

cardImg_binary = cv2.threshold(cardImg_close,0,255,cv2.THRESH_OTSU | 
                               cv2.THRESH_BINARY)[1]
# cv_show('cardImg_binary',cardImg_binary)

cardImg_close = cv2.morphologyEx(cardImg_binary,cv2.MORPH_CLOSE,sqKernel)
cv_show('cardImg_close',cardImg_close)
# 轮廓检测,检测出每一个数字区块
cnts,hierarchy = cv2.findContours(cardImg_close,cv2.RETR_EXTERNAL,
                                 cv2.CHAIN_APPROX_SIMPLE)
cardImg_cnts = cv2.drawContours(cardImg.copy(),cnts,-1,(0,0,255),2)
cv_show('cardImg_cnts',cardImg_cnts)
# 对轮廓进行删选,根据边框的尺寸仅保留卡号区域
locs = []
for (i,c) in enumerate(cnts):
    (x,y,w,h) = cv2.boundingRect(c)
    ar = w/ float(h)
    
    if ar > 2.5 and ar <4.0:
        if (w>40 and w<55) and (h>10 and h<20):
            locs.append((x,y,w,h))
loce = sorted(locs,key = lambda x:x[0])

# for (x,y,w,h) in locs:
#     cv2.rectangle(cardImg_cnts,(x,y),(x+w,y+h),(0,0,0),1)
# cv_show('cardImg_cnts',cardImg_cnts)

OpenCV 银行卡卡号识别_第3张图片
OpenCV 银行卡卡号识别_第4张图片


4.将卡号进行数字划分,进行模板匹配,得到每个数字图像所对应的数字

output = []
# 对每4个数字块进行处理
for (i,(x,y,w,h)) in enumerate(locs):
    group_output = []
    group = cardImg_gray[y-5:y+h+5,x-5:x+w+5]
    group = cv2.threshold(group,0,255,cv2.THRESH_OTSU|cv2.THRESH_BINARY)[1]
    cv_show('group',group)
    group_cnts,group_hierarchy = cv2.findContours(group,cv2.RETR_EXTERNAL,
                                                 cv2.CHAIN_APPROX_SIMPLE)
    group_cnts = sort_contours(group_cnts,method='left-to-right')[0]
    # 分割每个数字
    for cnt in group_cnts:
        (nx,ny,nw,nh) = cv2.boundingRect(cnt)
        roi = group[ny:ny+nh,nx:nx+nw]
        roi = cv2.resize(roi,(57,88))
#         cv_show('roi',roi)
        score = []
        # 对每个数字进行模板匹配
        for (number_i,number_roi) in number.items():
            result = cv2.matchTemplate(roi,number_roi,cv2.TM_CCOEFF)
            score_ = cv2.minMaxLoc(result)[1]
            
            score.append(score_)
        group_output.append(str(np.argmax(score)))
    # 绘制每个数字    
    cv2.rectangle(cardImg,(x-5,y-5),(x+w+5,y+h+5),(0,0,255),1)
    cv2.putText(cardImg,"".join(group_output),(x,y-15),
                cv2.FONT_HERSHEY_SIMPLEX,0.65,(0,0,255),2)
    output.append(group_output)
cv_show('cardImg',cardImg)    

OpenCV 银行卡卡号识别_第5张图片

你可能感兴趣的:(python应用,机器视觉,opencv,python)