对模板进行处理。要先对模板数字 进行轮廓查找
img = cv2.imread("moban.png", 1)
img1 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img1 = cv2.threshold(img1, 0, 255, cv2.THRESH_OTSU|cv2.THRESH_BINARY_INV)[1]
img1_con = cv2.findContours(img1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]
img1_dst = cv2.drawContours(img.copy(), img1_con, -1, (0, 0, 255), 2)
cv2.imshow('1', img1_dst)
然后再将模板数字分割开并保存方便后面进行模板匹配来识别银行卡号。代码如下
l = []
for con in img1_con:
(x, y, w, h) = cv2.boundingRect(con)
l.append(x)
# 将其包围盒按照x坐标排序
(img1_con, l) = zip(*sorted(zip(img1_con, l), key=lambda x: x[1], reverse=False))
# 将模板数字图像分割开
dig = {}
for i, con in enumerate(img1_con):
(x, y, w, h) = cv2.boundingRect(con)
roi = img1[y:y + h, x:x + w]
dig[i] = cv2.resize(roi, (57, 88))
银行卡图片为:
然后再进行银行卡图片的处理。处理的思路就是要获取原图中的数字区域,通过轮廓处理得到四串数字的轮廓,然后再将每一个数字都提取出来与模板里的数字进行识别。我的具体操作方法是先进行顶帽操作,然后求图像的梯度,再进行闭操作直到让数字区域连接到一起,以便于后面进行轮廓检测
card = cv2.imread("yinhangka.jpg", 1)
card1 = cv2.cvtColor(card, cv2.COLOR_BGR2GRAY)
kernel = np.ones((5, 5))
tophat = cv2.morphologyEx(card1, cv2.MORPH_TOPHAT, kernel)
cv2.imshow('2', tophat)
# 求梯度
grady = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=0, dy=1, ksize=3)
grady = cv2.convertScaleAbs(grady)
gradx = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=3)
gradx = cv2.convertScaleAbs(gradx)
# 将X方向的梯度和Y方向的梯度融合。
grad = cv2.addWeighted(gradx, 0.5, grady, 0.5, 0)
cv2.imshow('3', grad)
kernel = np.ones((3, 3))
grad_close = cv2.morphologyEx(grad, cv2.MORPH_CLOSE, kernel, iterations=1)
cv2.imshow('4', grad_close)
grad_dst = cv2.threshold(grad_close, 0, 255, cv2.THRESH_OTSU)[1]
grad_close = cv2.morphologyEx(grad_dst, cv2.MORPH_CLOSE, kernel, iterations=8)
cv2.imshow('5', grad_close)
进行闭操作后差不多是这个样子。
然后就进行轮廓检测
gradcon = cv2.findContours(grad_close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]
dst = cv2.drawContours(img_card.copy(), gradcon, -1, (0, 0, 255), 2)
cv2.imshow('6', dst)
# 筛选合适的轮廓
lunkuo = []
for con in gradcon:
(x, y, w, h) = cv2.boundingRect(con)
ar = w/h
if ar > 2.4 and ar < 3.5:
if w > 155 or w < 85:
continue
lunkuo.append((x, y, w, h))
再就是对轮廓的筛选和与模板数字进行比较识别了
具体代码
import cv2
import numpy as np
# 读取模板图片
img = cv2.imread("moban.png", 1)
img1 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img1 = cv2.threshold(img1, 0, 255, cv2.THRESH_OTSU|cv2.THRESH_BINARY_INV)[1]
img1_con = cv2.findContours(img1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]
img1_dst = cv2.drawContours(img.copy(), img1_con, -1, (0, 0, 255), 2)
cv2.imshow('1', img1_dst)
l = []
for con in img1_con:
(x, y, w, h) = cv2.boundingRect(con)
l.append(x)
# 将其包围盒按照x坐标排序
(img1_con, l) = zip(*sorted(zip(img1_con, l), key=lambda x: x[1], reverse=False))
# 将模板数字图像分割开
dig = {}
for i, con in enumerate(img1_con):
(x, y, w, h) = cv2.boundingRect(con)
roi = img1[y:y + h, x:x + w]
dig[i] = cv2.resize(roi, (57, 88))
# 加载
card = cv2.imread("yinhangka.jpg", 1)
card1 = cv2.cvtColor(card, cv2.COLOR_BGR2GRAY)
kernel = np.ones((5, 5))
tophat = cv2.morphologyEx(card1, cv2.MORPH_TOPHAT, kernel)
cv2.imshow('2', tophat)
# 求梯度
grady = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=0, dy=1, ksize=3)
grady = cv2.convertScaleAbs(grady)
gradx = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=3)
gradx = cv2.convertScaleAbs(gradx)
# 将X方向的梯度和Y方向的梯度融合。
grad = cv2.addWeighted(gradx, 0.5, grady, 0.5, 0)
cv2.imshow('3', grad)
kernel = np.ones((3, 3))
grad_close = cv2.morphologyEx(grad, cv2.MORPH_CLOSE, kernel, iterations=1)
cv2.imshow('4', grad_close)
grad_dst = cv2.threshold(grad_close, 0, 255, cv2.THRESH_OTSU)[1]
grad_close = cv2.morphologyEx(grad_dst, cv2.MORPH_CLOSE, kernel, iterations=8)
cv2.imshow('5', grad_close)
# 目标区域已经完全连通,接下来进行轮廓检测,画包围盒,然后再进行筛选
gradcon = cv2.findContours(grad_close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]
dst = cv2.drawContours(card.copy(), gradcon, -1, (0, 0, 255), 2)
cv2.imshow('6', dst)
# 筛选合适的轮廓
lunkuo = []
for con in gradcon:
(x, y, w, h) = cv2.boundingRect(con)
ar = w/h
if ar > 2.4 and ar < 3.5:
if w > 155 or w < 85:
continue
lunkuo.append((x, y, w, h))
# 对矩形包围框按照坐标进行排序,排序目的和前面对模板数字图片的排序目的相同。
sort_lunkuo = sorted(lunkuo, key=lambda x: x[0], reverse=False)
img_part = []
for i in sort_lunkuo:
x, y, w, h = i[0], i[1], i[2], i[3]
con = np.array([[[x, y], [x+w, y], [x+w, y+h], [x, y+h]]])
img_part.append(card[y:y+h, x:x+w])
cv2.imshow('7', card[y:y+h, x:x+w])
# 接下来获取每个数字。
digital = []
def huode(img):
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img2 = cv2.threshold(img_gray, 0, 255, cv2.THRESH_OTSU)[1]
imgcon = cv2.findContours(img2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]
new_con = []
# 筛选
for con in imgcon:
(x,y,w,h) = cv2.boundingRect(con)
if h > 35 or w < 15:
continue
new_con.append((x, y, w, h))
sort_con = sorted(new_con, key=lambda x: x[0])
for i in sort_con:
x, y, w, h = i[0], i[1], i[2], i[3]
con = np.array([[[x, y], [x+w, y], [x+w, y+h], [x, y+h]]])
roi = img2[y-1:y+h+1, x-1:x+w+1]
digital.append(cv2.resize(roi, (57, 88)))
for i in img_part:
huode(i)
# 模板匹配
shuzi = []
for img_dig in digital:
now = []
for (dig1, digroi) in dig.items():
res = cv2.matchTemplate(img_dig, digroi, cv2.TM_CCOEFF_NORMED)
now.append(res.item())
shuzi.append(now.index(max(now)))
now.clear()
cv2.waitKey(0)
print(shuzi)