OpenCV 之 实战项目:识别银行卡上的数字
引言
在日常生活中,银行卡的识别是一个常见的需求,特别是在金融领域。本实战项目旨在使用 OpenCV 库来识别银行卡上的数字。我们将通过模板匹配的方法,结合图像处理技术,来准确识别银行卡上的数字序列。
项目准备
本项目需要安装 Python 和 OpenCV 库。确保已经安装了必要的库,并准备好银行卡图像和数字模板图像。
实验素材
定义函数
import cv2def sort_contours(cnts ,method='left to-right'):reverse = Falsei = 0if method == 'right-to-left' or method == 'bottom-to-top':reverse = Trueif method == 'top-to-bottom' or method == 'bottom-to-top':i = 1boundingBoxes = [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, boundingBoxesdef 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 imageif 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 myutilsap = 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 进行银行卡上数字的识别。整个过程包括模板图像处理、银行卡图像预处理、数字区域定位、模板匹配以及结果展示。这种技术在金融领域有着广泛的应用,可以帮助自动化处理大量的银行卡识别任务。通过适当的图像处理技术和模板匹配方法,我们可以准确地识别出银行卡上的数字序列。