项目介绍
在日常生活中,信用卡的使用越来越普遍。本项目的主要目标是通过图像处理技术自动识别信用卡号码,并根据信用卡号码的第一个数字判定信用卡的类型(如Visa、MasterCard等)。项目结合了图像预处理、轮廓检测、模板匹配等技术,实现了从输入图像中提取信用卡号码并识别其类型的功能。
项目展示
Credit Card Type: MasterCard
Credit Card #: 5476767898765432
项目的代码与讲解
1,读取模板图像并进行预处理
首先,读取模板图像,并将其转换为灰度图像和二值图像。然后,计算模板的轮廓并进行排序。
template_img = cv2.imread(template_path)
ref = cv2.cvtColor(template_img, cv2.COLOR_BGR2GRAY)
ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]
refCnts, _ = cv2.findContours(ref, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
refCnts = contours.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
2,读取输入图像并进行预处理
读取输入图像,调整大小,通过灰度化、二值化以及形态学操作(如顶帽变换和闭操作),我们增强了图像的对比度并突出了数字部分。通过Sobel算子计算了图像的梯度,使得数字轮廓更加清晰。
image = cv2.imread(image_path)
width = 300
(h, w) = image.shape[:2]
r = width / float(w)
dim = (width, int(h * r))
image = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)
gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)
gradX = np.absolute(gradX)
gradX = (255 * ((gradX - np.min(gradX)) / (np.max(gradX) - np.min(gradX))))
gradX = gradX.astype("uint8")
gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel)
thresh = cv2.threshold(gradX, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel)
3,检测数字轮廓
在预处理后的图像中检测数字轮廓,并根据轮廓的宽高比和大小进行筛选。
cnts, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
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])
4,匹配数字模板
对每个检测到的数字区域,使用模板匹配算法与模板图像中的数字进行匹配,并通过计算匹配的相似度(即相关系数)来识别每个数字。使用cv2.matchTemplate方法,我们能够准确地从检测区域中识别出每个数字,并将其按顺序拼接成完整的信用卡号码。
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, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
digitCnts = contours.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)
5,判定信用卡类型并显示结果
根据识别到的信用卡号码的第一个数字,判定信用卡的类型,并显示结果。
print(f"Credit Card Type: {FIRST_NUMBER[output[0]]}")
print("Credit Card #: {}".format("".join(output)))
display_image = np.hstack([origional_img, image])
cv2.imshow("Image", display_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
完整代码如下所示:
import cv2
import numpy as np
from imutils import contours
image_path = r"./images/creditcard_5.png"
template_path = r"reference.png"
# 指定信用卡类型
FIRST_NUMBER = {
"3": "American Express",
"4": "Visa",
"5": "MasterCard",
"6": "Discover Card"
}
# 读取模板图像并进行预处理
template_img = cv2.imread(template_path)
ref = cv2.cvtColor(template_img, cv2.COLOR_BGR2GRAY)
ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]
# 计算模板轮廓并进行排序
refCnts, _ = cv2.findContours(ref, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
refCnts = contours.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
# 初始化卷积核
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
# 读取输入图像并进行预处理
image = cv2.imread(image_path)
width = 300
(h, w) = image.shape[:2]
r = width / float(w)
dim = (width, int(h * r))
image = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)
origional_img = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 进行图像增强处理
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)
gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)
gradX = np.absolute(gradX)
gradX = (255 * ((gradX - np.min(gradX)) / (np.max(gradX) - np.min(gradX))))
gradX = gradX.astype("uint8")
# 通过闭操作连接数字并进行二值化处理
gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel)
thresh = cv2.threshold(gradX, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel)
cnts, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
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, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
digitCnts = contours.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)
print(f"Credit Card Type: {FIRST_NUMBER[output[0]]}")
print("Credit Card #: {}".format("".join(output)))
display_image = np.hstack([origional_img, image])
# cv2.imwrite("test.png", display_image)
cv2.imshow("Image", display_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
项目总结
本项目通过结合图像处理技术和模板匹配算法,成功实现了一个简单的信用卡号码识别与类型判定。