实验环境:anaconda、jupyter notebook(其它的ide也行)
实验用的包:numpy、matplotlib、opencv
实验目标:
识别信用卡的卡号
信用卡图片:
数字模板图片:
一、包引入
import cv2
import matplotlib.pyplot as plt
import numpy as np
二、数字模板特征提取
图片二值化处理
template = cv2.imread('template.png')
# 灰度处理
template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
# 二值处理
ret,template_bin = cv2.threshold(template_gray,127,255,cv2.THRESH_BINARY_INV)
plt.imshow(template_bin, 'gray')
plt.show()
检测数字模板外轮廓
# 只检测外轮廓
binary, template_contours, hierarchy = cv2.findContours(template_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
template_copy = template.copy()
template_contours_img = cv2.drawContours(template_copy, template_contours, -1, (0,0,255),1)
plt.imshow(template_contours_img)
plt.show()
找到外接矩形
# 外接矩形
tangles = []
template_copy = template.copy()
for cnt in template_contours:
x,y,w,h = cv2.boundingRect(cnt)
tangles.append((x,y,w,h))
template_copy = cv2.rectangle(template_copy, (x, y), (x + w, y + h), (0,255,0), 2)
plt.imshow(cv2.cvtColor(template_copy, cv2.COLOR_BGR2RGB))
plt.show()
# 根据x值狠狠排序
tangles.sort()
print(tangles)
通过外接矩形截取数字图片
# 拿到数字对应的图片
number_size = (50,100)
digits = {}
for i in range(len(tangles)):
(x,y,w,h) = tangles[i]
digits[i] = cv2.resize(template_bin[y:y+h, x: x+w], number_size)
plt.subplot(1,10,1 + i)
plt.xticks([])
plt.yticks([])
plt.imshow(digits[i],'gray')
plt.show()
三、信用卡卡面特征提取
初始化卷积核、处理卡片
# 初始化卷积核
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
# 读入信用卡图片
card = cv2.imread('card.png')
# 处理为灰度图
card_gray = cv2.cvtColor(card, cv2.COLOR_BGR2GRAY)
# 处理为礼帽处理
card_tophat = cv2.morphologyEx(card_gray, cv2.MORPH_TOPHAT, rectKernel)
plt.imshow(card_tophat,'gray')
plt.show()
对信用卡图片梯度处理
gradx = cv2.Sobel(card_tophat, ddepth=cv2.CV_32F, dx=1,dy=0, ksize=-1)
card_gradx = np.absolute(gradx)
(min_val,max_val) = (np.min(card_gradx), np.max(card_gradx))
card_gradx = (255 * ((card_gradx - min_val) / (max_val - min_val)))
card_gradx = card_gradx.astype('uint8')
plt.imshow(card_gradx,'gray')
plt.show()
把特征轮廓合成一片,方便提取
闭操作
card_closing = cv2.morphologyEx(card_gradx, cv2.MORPH_CLOSE,rectKernel)
plt.imshow(card_closing,'gray')
plt.show()
二值化
# 二值化,自动判断
ret,card_bin = cv2.threshold(card_closing,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)
plt.imshow(card_bin,'gray')
plt.show()
膨胀操作
# 膨胀操作,加强卡号特征
card_dilate = cv2.dilate(card_bin, rectKernel, iterations=1)
plt.imshow(card_dilate,'gray')
plt.show()
获取外轮廓
# 检测外轮廓
binary, card_contours, hierarchy = cv2.findContours(card_dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
card_copy = card.copy()
card_contours_img = cv2.drawContours(card_copy, card_contours, -1, (0,0,255),2)
plt.imshow(cv2.cvtColor(card_contours_img,cv2.COLOR_BGR2RGB))
plt.show()
此时拿到的外轮廓有很多不需要的地方
获取需要的外轮廓
card_copy = card.copy()
locs = []
for (i, sit) in enumerate(card_contours):
(x,y,w,h) = cv2.boundingRect(sit)
ar = w / float(h)
if ar > 2.5 and ar < 4.0:
if 65 < w < 70 and 15 < h < 25:
locs.append((x,y,w,h))
locs.sort()
for (x,y,w,h) in locs:
card_copy = cv2.rectangle(card_copy, (x, y), (x + w, y + h), (0,255,0), 2)
plt.imshow(cv2.cvtColor(card_copy, cv2.COLOR_BGR2RGB))
plt.show()
四、卡号识别
output = []
card_copy = card.copy()
for (i,(x,y,w,h)) in enumerate(locs):
group_output = []
# 获取每组卡号
group = card_gray[y - 5 : y + h + 5, x - 5 : x + w + 5]
# 转为二值图像
ret, group = cv2.threshold(group,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)
# 外轮廓检测
binary, group_contours, hierarchy = cv2.findContours(group, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
data_sites = []
for data_sit in group_contours:
data_sites.append(cv2.boundingRect(data_sit))
data_sites.sort()
for (gx, gy, gw, gh) in data_sites:
data = cv2.resize(group[gy : gy + gh, gx : gx + gw], number_size)
scores = []
# 计算分数
for (digit, digit_img) in digits.items():
result = cv2.matchTemplate(data, digit_img, cv2.TM_CCOEFF_NORMED)
(_,score,_,_) = cv2.minMaxLoc(result)
scores.append(score)
group_output.append(str(np.argmax(scores)))
cv2.rectangle(card_copy,(x - 5, y - 5), (x + w +5, y + h + 5), (0,255,0),2)
cv2.putText(card_copy, "".join(group_output), (x, y - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0,0,255),2)
output.extend(group_output)
plt.imshow(cv2.cvtColor(card_copy, cv2.COLOR_BGR2RGB))
plt.show()
print(output)
成功识别卡号