该代码用于从信用卡图像中自动识别和提取数字信息。该系统将识别信用卡类型,并输出信用卡上的数字序列。
1.创建命令行参数
数字模板
信用卡
# 创建命令行参数解析器
ap = argparse.ArgumentParser()
# 添加命令行参数 -i/--image,指定输入图像路径
ap.add_argument("-i", "--image", required=True, help="path to input image")
# 添加命令行参数 -t/--template,指定模板图像路径
ap.add_argument("-t", "--template", required=True, help="path to template OCR-A image")
# 解析命令行参数
args = vars(ap.parse_args())
2.指定信用卡类型
# 指定信用卡类型
FIRST_NUMBER = {"3": "American Express", "4": "Visa", "5": "MasterCard", "6": "Discover Card"}
3.将模板数字图像转换为二值图像
def cv_show(name, img): # 绘图展示
cv2.imshow(name, img)
cv2.waitKey(0)
# 读取模板图像
img = cv2.imread(args["template"])
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换为灰度图
ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1] # 二值图像
4.找到二值图像的轮廓
# 找到二值图像中的轮廓
_, refCnts, _ = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, refCnts, -1, (0, 0, 255), 3) # 在原始图像上绘制轮廓
5.使用自定义函数对轮廓进行排序
# 使用自定义函数对轮廓进行排序
refCnts = 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 # 每一个数字对应每一个模板
6.获取信用卡灰度图
# 读取信用卡图像
image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 转换为灰度图
7.使用形态学操作来增强图像中的数字
# 使用形态学操作来增强图像中的数字
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)
8.找到处理后的图像中的轮廓
# 找到处理后的图像中的轮廓
_, threshCnts, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = threshCnts
9.绘制轮廓
# 绘制轮廓
cur_img = image.copy()
cv2.drawContours(cur_img, cnts, -1, (0, 0, 255), 3)
10.存储所识别的排序后的数字
# 初始化一个空列表,用于存储检测到的数字的位置信息
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:
if (w > 40 and w < 55) and (h > 10 and h < 20):
locs.append((x, y, w, h))
# 根据x坐标对位置信息进行排序,确保从左到右识别数字
locs = sorted(locs, key=lambda x: x[0])
11.识别所有卡号的数字,并在原图上面写下卡号
# 初始化一个空列表,用于存储识别出的数字
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]
# 找到当前数字组中的每个数字的轮廓
group_, digitCnts, _ = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 对数字轮廓进行排序
digitCnts = 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)
12.打印信用卡类型和ID
# 打印信用卡类型和ID
print("card Type:{}".format(FIRST_NUMBER[output[0]]))
print("card ID:{}".format("".join(output)))
# 显示最终结果
cv2.imshow("image", image)
cv2.waitKey(0)