任务说明
将银行卡卡号打印输出
; 实现
一、思路
1、定位银行卡卡号数字区域
2、将银行卡每个卡号数字单独提取出来
3、处理模板图片,将每个模板数字单独提取出来
4、通过模板匹配来识别每个卡号
二、具体代码实现
1、处理模板
卡号数字模板
img_m = cv2.imread("ocr_a_reference.png",1)
img_m_g = cv2.cvtColor(img_m,cv2.COLOR_BGR2GRAY)
img_m_g = cv2.threshold(img_m_g,0,255,cv2.THRESH_OTSU|cv2.THRESH_BINARY_INV)[1]
img_m_g_con = cv2.findContours(img_m_g,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)[0]
img_m_g_dst = cv2.drawContours(img_m.copy(),img_m_g_con,-1,(0,0,255),2)
imshow(img_m_g_dst)
将每个模板数字分割开,并保存到字典中
l1 = []
for con in img_m_g_con:
(x,y,w,h) = cv2.boundingRect(con)
l1.append(x)
(img_m_g_con,l1) = zip(*sorted(zip(img_m_g_con,l1),key=lambda x :x[1],reverse=False))
digits = {}
for i,con in enumerate(img_m_g_con):
(x,y,w,h) = cv2.boundingRect(con)
roi = img_m_g[y:y+h,x:x+w]
digits[i] = cv2.resize(roi,(57,88))
2、处理银行卡图片
img_card = cv2.imread("credit_card_01.png",1)
img_card_gray = cv2.cvtColor(img_card,cv2.COLOR_BGR2GRAY)
kernel = np.ones((5,5))
tophat = cv2.morphologyEx(img_card_gray,cv2.MORPH_TOPHAT,kernel)
imshow(tophat)
求图像的梯度(边缘)的目的是方便之后的形态学操作,将目标区域连通在一起。
grady = cv2.Sobel(tophat,ddepth = cv2.CV_32F,dx=0,dy=1,ksize = 3)
grady = cv2.convertScaleAbs(grady)
gradx = cv2.Sobel(tophat,ddepth = cv2.CV_32F,dx=1,dy=0,ksize=3)
gradx = cv2.convertScaleAbs(gradx)
grad = cv2.addWeighted(gradx,0.5,grady,0.5,0)
imshow(grad)
形态学操作,将目标区域连通在一起
kernel = np.ones((3,3))
grad_close = cv2.morphologyEx(grad,cv2.MORPH_CLOSE,kernel,iterations = 1)
imshow(grad_close)
grad_dst = cv2.threshold(grad_close,0,255,cv2.THRESH_OTSU)[1]
grad_close = cv2.morphologyEx(grad_dst,cv2.MORPH_CLOSE,kernel,iterations=8)
imshow(grad_close)
闭操作执行的次数和银行卡的格式是严格相关的,不同格式的银行卡要设置不用的参数,参数值通过实验经验获得。
其主要目的是将目标区域联通在一起,并且要求连通后的区域不可以包含额外区域,比如参数设置过大会导致左侧目标区域与下方区域连通,设置过小会导致目标区域无法连通。
gradcon = cv2.findContours(grad_close,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)[0]
dst = cv2.drawContours(img_card.copy(),gradcon,-1,(0,0,255),2)
imshow(dst)
losc = []
for con in gradcon:
(x,y,w,h) = cv2.boundingRect(con)
ar = w/h
if ar >2.4 and ar <3.5:
if w>155 or w<85:
continue
losc.append((x,y,w,h))
sort_losc = sorted(losc,key = lambda x :x[0],reverse=False)
img_part = []
for i in sort_losc:
x,y,w,h = i[0],i[1],i[2],i[3]
con = np.array([[[x,y],[x+w,y],[x+w,y+h],[x,y+h]]])
img_part.append(img_card[y:y+h,x:x+w])
imshow(img_card[y:y+h,x:x+w])
再对每个小区域处理,获取每个卡号数字区域
digital = []
def f(img):
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img_2 = cv2.threshold(img_gray,0,255,cv2.THRESH_OTSU)[1]
imgcon = cv2.findContours(img_2,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)[0]
new_con = []
for con in imgcon:
(x,y,w,h) = cv2.boundingRect(con)
if h>35 or w<15:
continue
new_con.append((x,y,w,h))
sort_con = sorted(new_con,key = lambda x:x[0])
for i in sort_con:
x,y,w,h = i[0],i[1],i[2],i[3]
con = np.array([[[x,y],[x+w,y],[x+w,y+h],[x,y+h]]])
roi = img_2[y-1:y+h+1,x-1:x+w+1]
digital.append(cv2.resize(roi,(57,88)))
for i in img_part:
f(i)
…
3、模板匹配
ans = []
for img_dig in digital:
now = []
for (dig,digroi) in digits.items():
res = cv2.matchTemplate(img_dig,digroi,cv2.TM_CCOEFF_NORMED)
now.append(res.item())
ans.append(now.index(max(now)))
now.clear()
print(ans)
cv2.matchTemplate是用于模板匹配的函数,第一个参数为待匹配图像,第二个参数为模板图像,模板图像和原图像的大小要保持一致,第三个参数为匹配方式。返回值越大,相似度越高。
存在的问题:
1、不同格式的银行卡图片需要对参数进行幅度较大的改动。
2、没有考虑银行卡图片倾斜的情况,如果输入的银行卡图片在输入的图片中只是倾斜的,可以使用透视变换进行校正,具体做法可以参考上一篇blog(答题卡识别)
Original: https://blog.csdn.net/qq_44805233/article/details/123192913
Author: 棒子胡豆
Title: opencv项目实践二(银行卡卡号识别)
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/533234/
转载文章受原作者版权保护。转载请注明原作者出处!