当前位置: 首页 > news >正文

opencv学习:信用卡卡号识别

该代码用于从信用卡图像中自动识别和提取数字信息。该系统将识别信用卡类型,并输出信用卡上的数字序列。

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)

13.实验结果

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 别总是“系统错误,请稍后重试!”了,解决问题要彻底!
  • 铲屎官都该知道的除浮毛神器——希喂、美的、352宠物空气净化器
  • Python VTK 绘制等高线初步
  • image.size()和image.shape包含的信息一样,那image.size()存在的意义是什么?
  • 2024.9.9(极客大挑战 2019]EasySQL,[极客大挑战 2019]Knife)
  • 什么是3PL EDI 集成?优化供应链指南
  • springboot请求传参常用模板
  • CSS属性选择器选择属性值中包含指定字符串的元素
  • Android 12系统源码_应用加载流程(一)资源加载
  • 服务网关工作原理,如何获取用户真实IP?
  • 分享6个我喜欢的常用网站,来看看有没有你感兴趣的!
  • fpga系列 HDL:全连接层InegrationFCpart.v的权重读取 $readmemh
  • Gemini vs Meta — 我给两个AI模型出了7个题,优胜者是...
  • 基于深度学习的基因组数据分析
  • 怎么抓住威士忌蓝海市场?
  • (ckeditor+ckfinder用法)Jquery,js获取ckeditor值
  • (三)从jvm层面了解线程的启动和停止
  • 【干货分享】SpringCloud微服务架构分布式组件如何共享session对象
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • Javascripit类型转换比较那点事儿,双等号(==)
  • Leetcode 27 Remove Element
  • React+TypeScript入门
  • 好的网址,关于.net 4.0 ,vs 2010
  • 聚簇索引和非聚簇索引
  • 实战:基于Spring Boot快速开发RESTful风格API接口
  • 因为阿里,他们成了“杭漂”
  • 应用生命周期终极 DevOps 工具包
  • ​【C语言】长篇详解,字符系列篇3-----strstr,strtok,strerror字符串函数的使用【图文详解​】
  • ​草莓熊python turtle绘图代码(玫瑰花版)附源代码
  • # Swust 12th acm 邀请赛# [ K ] 三角形判定 [题解]
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • ###C语言程序设计-----C语言学习(6)#
  • #1015 : KMP算法
  • #LLM入门|Prompt#1.7_文本拓展_Expanding
  • (6) 深入探索Python-Pandas库的核心数据结构:DataFrame全面解析
  • (7)STL算法之交换赋值
  • (C语言)逆序输出字符串
  • (M)unity2D敌人的创建、人物属性设置,遇敌掉血
  • (SERIES12)DM性能优化
  • (第一天)包装对象、作用域、创建对象
  • (附源码)ssm智慧社区管理系统 毕业设计 101635
  • (论文阅读40-45)图像描述1
  • (三)uboot源码分析
  • (算法)Travel Information Center
  • (转)JAVA中的堆栈
  • (转)创业的注意事项
  • (转载)深入super,看Python如何解决钻石继承难题
  • ***通过什么方式***网吧
  • ..thread“main“ com.fasterxml.jackson.databind.JsonMappingException: Jackson version is too old 2.3.1
  • .Net Web窗口页属性
  • .NET 中各种混淆(Obfuscation)的含义、原理、实际效果和不同级别的差异(使用 SmartAssembly)
  • .netcore 获取appsettings
  • .netcore 如何获取系统中所有session_如何把百度推广中获取的线索(基木鱼,电话,百度商桥等)同步到企业微信或者企业CRM等企业营销系统中...
  • /usr/bin/python: can't decompress data; zlib not available 的异常处理
  • [240727] Qt Creator 14 发布 | AMD 推迟 Ryzen 9000芯片发布