环境介绍
Python 3.6 + OpenCV 3.4.1.15
原理介绍
首先,提取出模板中每一个数字的轮廓,再对信用卡图像进行处理,提取其中的数字部分,将该部分数字与模板进行匹配,即可得到结果。
模板展示
完整代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
# !/usr/bin/env python # —*— coding: utf-8 —*— # @Time: 2020/1/11 14:57 # @Author: Martin # @File: utils.py # @Software:PyCharm import cv2 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(c) for c in cnts] (cnts, boundingboxes) = zip ( * sorted ( zip (cnts, boundingboxes), key = lambda b: b[ 1 ][i], reverse = reverse)) return cnts, boundingboxes def resize(image, width = None , height = None , inter = cv2.INTER_AREA): (h, w) = image.shape[: 2 ] if width is None and height is None : return image if width is None : r = height / float (h) dim = ( int (w * r), height) else : r = width / float (w) dim = (width, int (h * r)) resized = cv2.resize(image, dim, interpolation = inter) return resized # !/usr/bin/env python # —*— coding: utf-8 —*— # @Time: 2020/1/11 14:57 # @Author: Martin # @File: template_match.py # @Software:PyCharm """ 基于模板匹配的信用卡数字识别 """ import cv2 import utils import numpy as np # 指定信用卡类型 FIRST_NUMBER = { '3' : 'American Express' , '4' : 'Visa' , '5' : 'MasterCard' , '6' : 'Discover Card' } # 绘图显示 def cv_show(name, image): cv2.imshow(name, image) cv2.waitKey( 0 ) cv2.destroyAllWindows() # 读取模板图像 img = cv2.imread( './images/ocr_a_reference.png' ) cv_show( 'img' , img) # 转化成灰度图 ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) cv_show( 'ref' , ref) # 转化成二值图像 ref = cv2.threshold(ref, 10 , 255 , cv2.THRESH_BINARY_INV)[ 1 ] cv_show( 'ref' , ref) # 计算轮廓 ref_, refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cv2.drawContours(img, refCnts, - 1 , ( 0 , 0 , 255 ), 3 ) cv_show( 'img' , img) print (np.array(refCnts).shape) # 排序,从左到右,从上到下 refCnts = utils.sort_contours(refCnts, method = 'left-to-right' )[ 0 ] 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 , 88 )) digits[i] = roi # 初始化卷积核 rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, ( 9 , 3 )) sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, ( 5 , 5 )) # 读取输入图像,预处理 img_path = input ( "Input the path and image name: " ) image_input = cv2.imread(img_path) cv_show( 'image' , image_input) image_input = utils.resize(image_input, width = 300 ) gray = cv2.cvtColor(image_input, cv2.COLOR_BGR2GRAY) cv_show( 'gray' , gray) # 礼帽操作,突出更明亮的区域 tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel) cv_show( 'tophat' , tophat) gradX = cv2.Sobel(tophat, ddepth = cv2.CV_32F, dx = 1 , dy = 0 , ksize = - 1 ) gradX = np.absolute(gradX) (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 = cv2.threshold(gradX, 0 , 255 , cv2.THRESH_BINARY | cv2.THRESH_OTSU)[ 1 ] cv_show( 'thresh' , thresh) thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel) cv_show( 'thresh' , thresh) # 计算轮廓 thresh_, threshCnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = threshCnts cur_img = image_input.copy() cv2.drawContours(cur_img, cnts, - 1 , ( 0 , 0 , 255 ), 3 ) cv_show( 'img' , cur_img) locs = [] # 遍历轮廓 for (i, c) in enumerate (cnts): (x, y, w, h) = cv2.boundingRect(c) ar = w / float (h) if 2.5 < ar < 4.0 and ( 40 < w < 55 ) and ( 10 < h < 20 ): locs.append((x, y, w, h)) # 将符合的轮廓从左到右排序 locs = sorted (locs, key = lambda ix: ix[ 0 ]) output = [] # 遍历每一个轮廓中的数字 for (i, (gX, gY, gW, gH)) in enumerate (locs): groupOutput = [] group = gray[gY - 5 :gY + gH + 5 , gX - 5 : gX + gW + 5 ] cv_show( 'group' , group) # 预处理 group = cv2.threshold(group, 0 , 255 , cv2.THRESH_OTSU)[ 1 ] cv_show( 'group' , group) # 计算每一组轮廓 group_, digitCnts, hierarchy = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) digitCnts = utils.sort_contours(digitCnts, method = 'left-to-right' )[ 0 ] # 计算每一组的每个数值 for c in digitCnts: (x, y, w, h) = cv2.boundingRect(c) roi = group[y: y + h, x: x + w] roi = cv2.resize(roi, ( 57 , 88 )) 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) # 得到最合适的数字 groupOutput.append( str (np.argmax(scores))) cv2.rectangle(image_input, (gX - 5 , gY - 5 ), (gX + gW + 5 , gY + gH + 5 ), ( 0 , 0 , 255 ), 1 ) cv2.putText(image_input, "".join(groupOutput), (gX, gY - 15 ), cv2.FONT_HERSHEY_SIMPLEX, 0.65 , ( 0 , 0 , 255 ), 2 ) # 得到结果 output.extend(groupOutput) # 打印结果 print ( "Credit Card Type: {}" . format (FIRST_NUMBER[output[ 0 ]])) print ( "Credit Card #: {}" . format ("".join(output))) cv2.imshow( "Image" , image_input) cv2.waitKey( 0 ) cv2.destroyAllWindows() |
结果展示
1
2
|
Credit Card Type : Visa Credit Card #: 4020340002345678 |
总结
以上所述是小编给大家介绍的Python开发之基于模板匹配的信用卡数字识别功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!
原文链接:https://blog.csdn.net/Deep___Learning/article/details/103938052