实现功能:在银行卡上识别出卡号数字部分,并在其上方写下数字,如下图所示。

模板图片如下图,

原始银行卡图片,

完整代码如下,在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():    连接字符串数组。将字符串、元组、列表中的元素以指定的字符(分隔符)连接生成一个新的字符串
完整代码
01-22 08:58