实现功能:在银行卡上识别出卡号数字部分,并在其上方写下数字,如下图所示。
模板图片如下图,
原始银行卡图片,
完整代码如下,在Pycharm中编写。
imutils库需要提前下载,在cmd中用命令 pip install imutils 下载。
1 import cv2 2 import numpy as np 3 import matplotlib.pyplot as plt 4 import imutils 5 from imutils import contours 6 7 # 处理模板图片 8 img = cv2.imread("C:\\Users\\lenovo\\Pictures\\moban.jpg") 9 #cv2.imshow("img_moban",img) 10 img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 11 #cv2.imshow("img_moban_gray ",img_gray) 12 ret,ref = cv2.threshold(img_gray,20,255,cv2.THRESH_BINARY_INV) 13 #cv2.imshow("binary", ref) 14 image,refCnts, hierarchy = cv2.findContours(ref.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) 15 contour = cv2.drawContours(img,refCnts,-1,(0,0,255),3) 16 cv2.namedWindow("img_moban_contours",cv2.WINDOW_NORMAL) 17 #cv2.imshow("img_moban_contours",contour) 18 19 #refCnts = refCnts[0] if imutils.is_cv2() else refCnts[1] 20 refCnts = contours.sort_contours(refCnts,method = "left-to-right")[0] #from imutils import contours 21 digits = {} 22 for (i,c) in enumerate(refCnts): # enumerate(refCnts)下标从0开始,返回值是0,第一个轮廓。1,第二个轮廓 23 (x,y,w,h) = cv2.boundingRect(c) # x,y是矩阵左上点的坐标,w,h是矩阵的宽和高 24 roi = ref[y:y+h,x:x+w] 25 roi = cv2.resize(roi,(57,88)) 26 digits[i] = roi 27 28 29 # 处理待检测图片 30 recKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(10,3)) 31 sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(2,2)) 32 33 image = cv2.imread("C:\\Users\\lenovo\\Pictures\\yinhangka.png") 34 image = cv2.resize(image,(250,200)) 35 36 gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) 37 cv2.imshow("imagesize",gray) 38 tophat = cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,recKernel) # 顶帽操作:突出明亮区域 39 cv2.imshow("imagetophat",tophat) 40 gradx = cv2.Sobel(tophat,ddepth=cv2.CV_32F,dx=1,dy=0,ksize=3) 41 gradx= np.absolute(gradx) 42 (minVal,maxVal) = (np.min(gradx),np.max(gradx)) 43 gradx = (255*((gradx-minVal)/(maxVal-minVal))) 44 gradx = gradx.astype("uint8") 45 46 gradx = cv2.morphologyEx(gradx,cv2.MORPH_CLOSE,recKernel) 47 cv2.imshow("imagegradx",gradx) 48 ret,thresh = cv2.threshold(gradx,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU) 49 thresh = cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,sqKernel) 50 imageprint,Cnts,hierarchy = cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) 51 cnts = Cnts # cnts是所有轮廓 52 curImage = image.copy() 53 contours = cv2.drawContours(curImage,cnts,-1,(0,0,255),3) 54 cv2.imshow("contours",contours) 55 locs = [] # 储存符合条件的数字模块 56 locsnum = [] 57 for (i,c) in enumerate(cnts): 58 (x,y,w,h) = cv2.boundingRect(c) 59 ar = w/float(h) 60 if (ar>2.5) and (ar<4): 61 if h>10: # 这里的条件要多试几次 62 locs.append((x,y,w,h)) 63 locs = sorted(locs,key=lambda x:x[0]) #排序方式按照中括号[]里面的维度进行排序,[0]按照第一维排序,[2]按照第三维排序 64 print(len(locs)) 65 output=[] 66 for (i,(gx,gy,gw,gh)) in enumerate(locs): 67 groupOutput = [] 68 group = gray[gy-5:gy+gh+5,gx-5:gx+gw+5] # 在灰度图中选取roi 69 group = cv2.threshold(group,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1] 70 # cv2.imshow("group", group) 71 imageing,digitCnts,hierarchy = cv2.findContours(group.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) 72 # digitCnts = contours.sort_contours(digitCnts,method = "left-to-right")[0] 73 for c in digitCnts: 74 (x,y,w,h) = cv2.boundingRect(c) 75 roi = group[y:y+h,x:x+w] 76 roi = cv2.resize(roi,(57,88)) 77 scores=[] 78 for (digit, digitROI) in digits.items(): # 在模板预处理中建立了数值的字典类型,一个为索引、一个为值 79 result = cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF) # 匹配,返回与之匹配度最高的数值 80 (min_val, score, min_index, max_index) = cv2.minMaxLoc(result) # 做10次匹配,取最大值(注意:取最大值还是最小值跟选取的模板匹配方法有关) 81 scores.append(score) 82 groupOutput.append(str(np.argmax(scores))) #argmax返回的是最大数的索引 83 cv2.rectangle(image, (gx - 5, gy - 5), (gx + gw + 5, gy + gh + 5), (0, 0, 255), 1) # 第一组的矩形框 84 groupOutput.reverse() 85 image = cv2.putText(image, str("".join(groupOutput)), (gx, gy - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2) 86 output.extend(groupOutput) 87 # print("Credit Card Type: {}".format(FIRST_NUMBER[output[0]])) 88 print("Credit Card #: {}".format("".join(output))) # 将output中的字符用双引号中间的符号连接起来 89 cv2.imshow("Image", image) 90 cv2.waitKey(0) 91 cv2.destroyAllWindows() 92 # . join(): 连接字符串数组。将字符串、元组、列表中的元素以指定的字符(分隔符)连接生成一个新的字符串