OpenCV 之 实战项目:识别银行卡上的数字
引言
在日常生活中,银行卡的识别是一个常见的需求,特别是在金融领域。本实战项目旨在使用 OpenCV 库来识别银行卡上的数字。我们将通过模板匹配的方法,结合图像处理技术,来准确识别银行卡上的数字序列。
项目准备
本项目需要安装 Python 和 OpenCV 库。确保已经安装了必要的库,并准备好银行卡图像和数字模板图像。
实验素材
定义函数
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))
#zip(*...)使用星号操作符解包排序后的元组列表,并将其重新组合成两个列表:一个包含所有轮廓,另一个包含所有边界框。
return cnts, boundingBoxes
def resize(image,width=None,height=None ,inter=cv2.INTER_AREA):
dim = None
(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) #默认为cV2.INTER_AREA,即面积插值,适用于缩放图像。
return resized
传入参数
代码详解
-
导入库和设置参数
import numpy as np import argparse import cv2 import myutils ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", required=True, help="path to input image") ap.add_argument("-t", "--template", required=True, help="path to template OCR-A image") args = vars(ap.parse_args())
解释:
- 导入必要的库。
- 使用
argparse
库来设置命令行参数,包括输入图像路径和模板图像路径。 - 解析命令行参数并将结果存储在
args
字典中。
-
指定信用卡类型
FIRST_NUMBER = {"3": "American Express", "4": "Visa", "5": "MasterCard", "6": "Discover Card"}
解释:
- 定义一个字典,根据银行卡号的第一个数字来确定其类型。
-
模板图像处理
img = cv2.imread(args["template"]) ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1] _, refCnts, _ = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) refCnts = myutils.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
解释:
- 读取模板图像并转换为灰度图。
- 将灰度图转换为二值图。
- 计算模板图像中的轮廓,并按照从左到右的顺序排序。
- 提取每个数字的 ROI(感兴趣区域),并将其存储在
digits
字典中。
-
银行卡图像处理
image = cv2.imread(args["image"]) image = myutils.resize(image, width=300) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3)) sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel) closeX = cv2.morphologyEx(tophat, cv2.MORPH_CLOSE, rectKernel) thresh = cv2.threshold(closeX, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel) _, threshCnts, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = threshCnts locs = [] for (i, c) in enumerate(cnts): (x, y, w, h) = cv2.boundingRect(c) ar = w / float(h) if ar > 2.5 and ar < 4.0 and (w > 40 and w < 55) and (h > 10 and h < 20): locs.append((x, y, w, h)) locs = sorted(locs, key=lambda x: x[0])
解释:
- 读取银行卡图像并调整大小。
- 转换为灰度图。
- 使用顶帽操作增强图像中的数字区域。
- 使用形态学闭操作连接数字区域。
- 计算阈值并进一步处理图像。
- 计算图像中的轮廓,并筛选出符合条件的数字区域。
- 将数字区域按照从左到右的顺序排序。
-
数字识别
output = [] for (i, (gX, gY, gW, gH)) in enumerate(locs): groupOutput = [] group = gray[gY - 5:gY + gH + 5, gX - 5:gX + gW + 5] group = cv2.threshold(group, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] _, digitCnts, _ = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) digitCnts = myutils.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)) 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, (gX - 5, gY - 5), (gX + gW + 5, gY + gH + 5), (0, 0, 255), 1) cv2.putText(image, "".join(groupOutput), (gX, gY - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2) output.extend(groupOutput)
解释:
- 对每个数字区域进行处理,提取每个数字的 ROI。
- 使用模板匹配计算每个数字区域与模板的匹配得分。
- 将得分最高的模板对应的数字添加到结果中。
- 在图像上绘制矩形框和识别结果。
-
打印结果
print("Credit Card Type: {}".format(FIRST_NUMBER[output[0]])) print("Credit Card #:{}".format("".join(output))) cv2.imshow("Image", image) cv2.waitKey(0)
解释:
- 打印识别出的信用卡类型和号码。
- 显示处理后的图像。
-
输出结果:
总结
通过本实战项目,我们展示了如何使用 OpenCV 进行银行卡上数字的识别。整个过程包括模板图像处理、银行卡图像预处理、数字区域定位、模板匹配以及结果展示。这种技术在金融领域有着广泛的应用,可以帮助自动化处理大量的银行卡识别任务。通过适当的图像处理技术和模板匹配方法,我们可以准确地识别出银行卡上的数字序列。