python-opencv信用卡号码识别
1、效果
2、代码
import cv2
import numpy as np
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] #用一个最小的矩形,把找到的形状包起来x,y,h,w
(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
key=lambda b: b[1][i], reverse=reverse))
return cnts, boundingBoxes
img_mode = cv2.imread("./4.png")
img_new = cv2.imread("./5.png")
img_new = cv2.resize(img_new,(500,200))
img_mode = cv2.resize(img_mode,(500,200))
img_gray_new = cv2.cvtColor(img_new,cv2.COLOR_BGR2GRAY) #灰色
img_gray_mode = cv2.cvtColor(img_mode,cv2.COLOR_BGR2GRAY)
ret, thresh1 = cv2.threshold(img_gray_new,127,255,cv2.THRESH_BINARY) #二值化
ret2, thresh2 = cv2.threshold(img_gray_mode,127,255,cv2.THRESH_BINARY_INV)
contours, hie = cv2.findContours(thresh1.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) #检测到边界
contours_, hie_ = cv2.findContours(thresh2.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img_mode, contours_,-1,(0,0,255),2) #画出边界
# cv2.imshow("img",img_mode)
contours_ = sort_contours(contours_,method="left-to-right")[0]
digit = []
for i in contours_:
x,y,z,w, = cv2.boundingRect(i)
# print(x,y,z,w)
roi =thresh2[y:y+w, x:x+z]
roi = cv2.resize(roi,(90,50))
# cv2.imshow("wewew",roi)
digit.append(roi) #将每个模板添加进去
#print(digit) #找到模板每个数字的x
rect = cv2.getStructuringElement(cv2.MORPH_RECT,(2,3)) #设置内核大小
sq = cv2.getStructuringElement(cv2.MORPH_RECT,(21,10))
top = cv2.morphologyEx(img_gray_new, cv2.MORPH_TOPHAT,rect)#顶帽操作,将大的东西去除掉
# cv2.imshow("img_top", top)
close = cv2.morphologyEx(top, cv2.MORPH_CLOSE,sq)
# cv2.imshow("img_close",close)
ret, thresh_close = cv2.threshold(close,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU) #二值化
# cv2.imshow("thresh_close", thresh_close)
cnts ,hirs = cv2.findContours(thresh_close.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
img_new_copy = img_new.copy()
cv2.drawContours(img_new_copy,cnts,-1,(0,0,225),3)
locs = []
for i in cnts:
x,y,w,z = cv2.boundingRect(i)
ar = w/float(z)
if (ar<5.26 and ar >5.06):
if(w > 80 and w < 85) and (z==16):
locs.append((x,y,z,w))
# print(locs)
group = []
output = []
# locs = sorted(locs, key=lambda x:x[0])
locs = sorted(locs, key=lambda x:x[0]) #四个边框的坐标
l = []
for (x,y,w,z) in locs: #将四个4个数字组合的方框中的数值提取处理
groupOutput = []
# print(x,y,w,z)
g = img_gray_new[y:y+w,x:x+z+5] # 将四个方框分割 第一个、第二个、第三个、第四个
# cv2.imshow("img_mode",img_gray_mode)
# cv2.imshow("g",g)
group = cv2.threshold(g, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] #将获取的四个数值的方框二值化
# cv2.imshow('g_', group)
digit_cnts ,hire = cv2.findContours(group.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) # 找到每个方框中4个数字的边界
k = []
for i in digit_cnts:
(q,w,e,r) = cv2.boundingRect(i) #找到方框
# print(q,w,e,r)
k.append((q,w,e,r))
k = sorted(k, key=lambda q: q[0])
for (q,w,e,r) in k:
# print(q,w,e,r)
roi = group[w:w + e, q:q + r] # 找到每个数值边框的长宽高,前面是y后面是x
roi = cv2.resize(roi, (90, 50))
# cv2.imshow("rio",roi)
scores = []
for digit_roi in digit:
# cv2.imshow("ssss",digit_roi)
result = cv2.matchTemplate(roi, digit_roi, cv2.TM_CCOEFF_NORMED) #最好匹配越大,越小越差
(_, score, _, _) = cv2.minMaxLoc(result)
scores.append(score)
groupOutput.append(str(scores.index(max(scores))))
l.append(groupOutput)
c = []
for i in l:
for j in range(4):
c.append(i[j])
c = "".join(c)
print("银行卡号码是:",c)
#
# imggray = np.vstack((img_gray_mode,img_gray_new))
# imgver = np.vstack((img_mode,img_new))
# imgthresh = np.vstack((thresh1,thresh2))
# print("Credit Card Type: {}".format(FIRST_NUMBER[output[0]]))
cv2.imshow("ssss",img_new)
# cv2.imshow("img",imgver)
# cv2.imshow("img_",imggray)
# cv2.imshow("img__",imgthresh)
cv2.waitKey(0)
2.1、图片