银行卡号识别(模板匹配)
1、模板预处理
2、卡片图片预处理
3、模板匹配
import cv2
import numpy as np
import myutils
from imutils import contours
def cv_show(img,name):
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
#读取模板文件
img=cv2.imread(r"D:\pythonProject\NewProject\PIc\number.png")
#cv_show(img,'number')
#转换灰度图
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#cv_show(gray,'gray_number')
#转换为二值图
ret,ref=cv2.threshold(gray,10,255,cv2.THRESH_BINARY_INV)
#cv_show(ref,'ref')
#检测轮廓
refCnts,hierarchy=cv2.findContours(ref,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#绘制轮廓
res=cv2.drawContours(img.copy(),refCnts,-1,(0,0,255),2)
#cv_show(res,'res')
#检查绘制轮廓的数量
print(np.array(refCnts).shape)
#排序轮廓(从左到右),返回值:轮廓坐标,boundingBoxes
refCnts,boundingBoxes=contours.sort_contours(refCnts,method="left-to-right")
#print(refCnts)
digits={}
#遍历每一个轮廓
for (i,c) in enumerate(refCnts):
#计算外接矩形
(x,y,w,h)=cv2.boundingRect(c)
roi=ref[y:y+h,x:x+w]
#重设大小
roi=cv2.resize(roi,(57,58))
digits[i]=roi
#cv_show(digits[3],'1')
#print('------------',digits)
#输入文件处理
#初始化卷积核
rectKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
sqKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
#卡片图像读取
image=cv2.imread(r"D:\pythonProject\NewProject\PIc\card.png")
#cv_show(image,'image')
gray_image=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
high,width=gray_image.shape
gray_image=cv2.resize(gray_image,(int(width / 12), int(high / 12)))
#cv_show(gray_image,'gray_image')
print(gray_image.shape)
#礼帽操作(突出更明亮的区域)
tophat=cv2.morphologyEx(gray_image,cv2.MORPH_TOPHAT,rectKernel)
#cv_show(tophat,'tophat')
'''
#加转二值图
ret,ref1=cv2.threshold(tophat,10,255,cv2.THRESH_BINARY_INV)
cv_show(ref1,'ref')
'''
#Sobel算子 检测边缘,ksize=-1相当于3×3
gradX=cv2.Sobel(tophat,ddepth=cv2.CV_32F,dx=1,dy=0,ksize=-1)
#负数取绝对值,与cv2.convertScaleAbs类似
gradX=np.absolute(gradX)
#cv_show(gradX,'1')
#归一化
(minVal,maxVal)=(np.min(gradX),np.max(gradX))
gradX=(255*((gradX-minVal)/(maxVal-minVal)))
gradX=gradX.astype("uint8")
print(np.array(gradX).shape)
#cv_show(gradX,'gradX')
#闭操作,通过闭操作(先膨胀,在腐蚀)将数组按每四个一组连起
gradX=cv2.morphologyEx(gradX,cv2.MORPH_CLOSE,rectKernel)
#cv_show(gradX,'gradX')
#二值化处理:THRESH_OTSY会自动寻找合适阈值,适合双峰,需把阈值参数设成0
thresh=cv2.threshold(gradX,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
#cv_show(thresh,'thresh1')
#计算外轮廓
threshCnts,hierarchy=cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#画轮廓
image_res=cv2.drawContours(gray_image.copy(),threshCnts,-1,(0,0,255),2)
#cv_show(image_res,'image_res')
locs=[]
#遍历轮廓
for (i,c) in enumerate(threshCnts):
(x,y,w,h)=cv2.boundingRect(c)
ar = w/float(h)
#选择合适的轮廓区域
if ar > 3.5 and ar<4.0:
locs.append((x,y,w,h))
#im = cv2.drawContours(gray_image.copy(), c, -1, (0, 0, 255), 2)
#cv_show(im, 'im')
#排序
locs=sorted(locs,key=lambda x:x[0])
output=[]
#遍历每一个轮廓中数字
for (i,(gX,gY,gW,gH)) in enumerate(locs):
groupOutput=[]
#根据坐标提取每一个组(根据轮廓往外稍扩一些)
group=gray_image[gY-3:gY+gH+3,gX-3:gX+gW+3]
#cv_show(group,'group')
#预处理
#二值化
group = cv2.threshold(group, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
#cv_show(group, 'group')
#轮廓检测
groupCnts, hierarchy = cv2.findContours(group, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
#排序
cardCnts, boundingBoxes = contours.sort_contours(groupCnts, method="left-to-right")
#计算每一组中的每一个数值
for c in cardCnts:
#找到当前数值的轮廓,resize数值大小,与模板大小一致
(x,y,w,h)=cv2.boundingRect(c)
roi = thresh[y:y + h, x:x + w]
# 重设大小
roi = cv2.resize(roi, (57, 58))
#cv_show(roi,'roi')
scores=[]
#在模板中计算每一个的得分
for (digit,digitROI) in digits.items():
#模板匹配
result = cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF)
(_,score,_,_)=cv2.minMaxLoc(result)
scores.append(score)
#np.argmax,返回最大值的索引值
groupOutput.append(str(np.argmax(scores)))
#画出来
#cv2.rectangle(gray_image,())
cv2.putText(gray_image,"".join(groupOutput),(gX,gY-15),cv2.FONT_HERSHEY_SIMPLEX,0.35,(0,0,255),2)
output.extend(groupOutput)
print(output)
#cv_show(gray_image,'gray_imageend')