基于模板匹配的信用卡数字识别

news2025/1/18 6:25:45

文章目录

  • 一、项目介绍
  • 二、模板匹配的原理
  • 三、模板匹配的步骤
    • 模板图片处理
    • 信用卡图片处理
    • 进行模板匹配

一、项目介绍

模板识别(Template Matching)是一种基于图像匹配的技术,用于在较大图像中识别和定位小图像(模板)。相比使用人工智能(AI)算法训练识别信用卡数字,模板识别具有以下优势:

简单性:模板匹配算法相对简单,容易理解和实现。
计算效率:由于算法简单,模板匹配在计算上通常比深度学习等AI算法更高效。
低资源需求:模板匹配不需要大量的计算资源和训练数据,适合资源受限的环境。
快速部署:在一些应用场景中,模板匹配可以快速部署,而AI模型可能需要较长的时间来训练和优化。
可预测性:模板匹配的结果通常容易预测,因为它依赖于固定的模板和匹配算法。
特定场景下的高准确度:在图像质量高、背景简单、目标物体与模板高度相似的情况下,模板匹配可以提供较高的准确度。
抗干扰能力:如果目标图像与模板之间的变化较小(如旋转、缩放),模板匹配可以很好地工作。
无需大量标注数据:与需要大量标注数据训练的AI算法不同,模板匹配不需要大量的训练数据。
易于集成:模板匹配技术易于集成到现有的图像处理流程中,不需要复杂的模型训练和调优。
然而,模板匹配也有其局限性,例如对噪声敏感、难以处理图像中的遮挡和复杂变化等。而AI算法,尤其是基于深度学习的算法,通常在处理复杂场景和变化时表现更好,具有更好的泛化能力和适应性。

项目直接根据提供的数字模板识别信用卡的卡号。模板字体需要提前准备好,最好和信用卡字体保持一致。用到的图像处理框架为:opencv 版本4.9。

用到的模板:
在这里插入图片描述

模板


识别效果:


在这里插入图片描述

原图


在这里插入图片描述

识别出卡号的图

二、模板匹配的原理

模板匹配和卷积原理很像,模板在原图像上从原点开始滑动,计算模板与(图像被模板覆盖的地方)的差别程度,这个差别程度的计算方法在 opencv 里有6种,每次计算的结果放入一个矩阵里,作为结果输出。假如原图形是AxB大小,而模板是axb大小,则输出结果的矩阵是(A-a+1)x(B-b+1):

- TM_SQDIFF:计算平方不同,计算出来的值越小,越相关        
- TM_CCORR:计算相关性,计算出来的值越大,越相关
- TM_CCOEFF:计算相关系数,计算出来的值越大,越相关
- TM_SQDIFF_NORMED:计算归一化平方不同,计算出来的值越接近0,越相关
- TM_CCORR_NORMED:计算归一化相关性,计算出来的值越接近1,越相关
- TM_CCOEFF_NORMED:计算归一化相关系数,计算出来的值越接近1,越相关

建议使用归一化的计算方法会相对公平一些,方法:

- matchTemplate(image, templ, method[, result[, mask]]) 进行模板匹配
  - image是要匹配的图片
  - templ是模板图片
  - method是计算方式
  - result是进行匹配计算后得到的矩阵. 
  - mask是掩膜
- minMaxLoc(src[, mask])  获取最大值和最小值的位置
  - 返回四个值, 分别是最小值, 最大值, 最小值坐标, 最大值坐标

三、模板匹配的步骤

模板图片处理

1.首先对模板二值化


# 封装显示图片的函数
def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

# 先处理数字模板图片
import cv2
import numpy as np

# 读取模板图片
img = cv2.imread('./ocr_a_reference.png')
# print(img.shape)
# cv_show('img', img)
# 灰度化处理
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# cv_show('ref', ref)
print('ref', ref)
# 二值化处理
_, ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)
# cv_show('ref', ref)
print('ref2', ref)

在这里插入图片描述

逆二值化后的模板


2.找出每个数字的轮廓和外接矩形,将数字从图片中取出来

# 计算轮廓
ref_contours, _ = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 画出外轮廓
cv2.drawContours(img, ref_contours, -1, (0, 0, 255), 3)
# cv_show('img', img)
# 表示数字的轮廓
print(np.array(ref_contours, dtype='object').shape)

在这里插入图片描述

每个数字的轮廓


3.对轮廓进行排序, 按照数字大小进行排序, 方便后面使用
排序思路: 根据每个数字的最大外接矩形的x轴坐标进行排序

# 获取每个轮廓的外接矩形
bounding_boxes = [cv2.boundingRect(c) for c in ref_contours]
# print(bounding_boxes)
# print(sorted(bounding_boxes, key=lambda b: b[0]))
# 要把排序之后的外接矩形和轮廓建立对应关系.
(ref_contours, bounding_boxes) = zip(*sorted(zip(ref_contours, bounding_boxes), key=lambda b: b[1][0]))
digits = {}
for (i, c) in enumerate(ref_contours):
    # 重新计算外接矩形
    (x, y, w, h) = cv2.boundingRect(c)
    # region of interest 感兴趣的区域
    # 取出每个数字
    roi = ref[y:y + h, x: x + w]
    # resize成合适的大小
    # print('roi0', roi)
    roi = cv2.resize(roi, (57, 88))
    # cv_show('roi1', roi)
    # print('roi', roi)
    digits[i] = roi
# print(digits)

在这里插入图片描述

取出的数字0


信用卡图片处理

  1. 首先信用卡图片二值化
# 对信用卡图片进行处理
image = cv2.imread('./credit_card_03.png')
# cv_show('image', image)
# 对信用卡图片进行resize
# 为了保证原图不拉伸, 需要计算出原图的长宽比.
h, w = image.shape[:2]
width = 300
r = width / w
image = cv2.resize(image, (300, int(h * r)))
# cv_show('image', image)
# 灰度化处理
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv_show('gray', gray)

在这里插入图片描述

二值化后的图


2.接下来是形态学的各种操作,顶帽操作,突出更明亮的区域
顶帽操作是原图像与图像开运算结果之间的差,它把开运算“去掉”的细节显现出来。

# 初始化卷积核
rect_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rect_kernel)
cv_show('tophat', tophat)

在这里插入图片描述

顶帽操作后的图


3.直接应用闭操作可能就足够了,结合Sobel算子和其他图像处理技术可能会产生更好的效果

# sobel算子
grad_x = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)
# print(grad_x)
# 对grad_x进行处理
# 只用x轴方向的梯度
grad_x = np.absolute(grad_x)
# 再把grad_x变成0到255之间的整数
min_val, max_val = np.min(grad_x), np.max(grad_x)
grad_x = ((grad_x - min_val) / (max_val - min_val)) * 255
# 修改一下数据类型
grad_x = grad_x.astype('uint8')
cv_show('grad_x', grad_x)

在这里插入图片描述

sobel对水平方向梯度处理后的图


4.闭操作, 先膨胀, 再腐蚀, 可以把数字连在一起

grad_x = cv2.morphologyEx(grad_x, cv2.MORPH_CLOSE, rect_kernel)
cv_show('gradx', grad_x)

在这里插入图片描述

闭操作后的图


# 通过大津(OTSU)算法找到合适的阈值, 进行全局二值化操作.
_, thresh = cv2.threshold(grad_x, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
cv_show('thresh', thresh)

# 中间还有空洞, 再来一个闭操作
sq_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sq_kernel)
cv_show('thresh', thresh)

在这里插入图片描述

二次闭操作后的图


5.原图上找到对应轮廓

thresh_contours, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 在原图上画轮廓
image_copy = image.copy()
cv2.drawContours(image_copy, thresh_contours, -1, (0, 0, 255), 3)
cv_show('img', image_copy)

在这里插入图片描述

画出轮廓


6.遍历轮廓, 计算外接矩形, 然后根据实际信用卡数字区域的长宽比, 找到真正的数字区域

locs = []
output = []
for c in thresh_contours:
    # 计算外接矩形
    (x, y, w, h) = cv2.boundingRect(c)
    # 计算外接矩形的长宽比例
    ar = w / float(h)
    # 选择合适的区域
    #     print(ar)
    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))

# 对符合要求的轮廓进行从左到右的排序.
sorted(locs, key=lambda x: x[0])

# 遍历每一个外接矩形, 通过外接矩形可以把原图中的数字抠出来.
for (i, (gx, gy, gw, gh)) in enumerate(locs):
    # 抠出数字区域, 并且加点余量
    group = gray[gy - 5: gy + gh + 5, gx - 5: gx + gw + 5]
    cv_show('group', group)
    # 对取出灰色group做全局二值化处理
    group = cv2.threshold(group, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
    cv_show('group', group)

在这里插入图片描述

找到的一组数字

7.接下来和模板中取出数字区域的逻辑类似

    # 计算轮廓
    digit_contours, _ = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    # 对轮廓进行排序
    bounding_boxes = [cv2.boundingRect(c) for c in digit_contours]
    (digit_contours, _) = zip(*sorted(zip(digit_contours, bounding_boxes), key=lambda b: b[1][0]))

    # 定义每一组匹配到的数字的存放列表
    group_output = []
    print('digit_contours', digit_contours)

    image_copy = image.copy()
    cv2.drawContours(image_copy, digit_contours, -1, (0, 0, 255), 3)

    # 遍历排好序的轮廓
    for c in digit_contours:
        # 找到当前数字的轮廓, resize成合适的大小, 然后再进行模板匹配
        (x, y, w, h) = cv2.boundingRect(c)
        # 取出数字
        roi = group[y: y + h, x: x + w]
        roi = cv2.resize(roi, (57, 88))
        cv_show('roi', roi)  

在这里插入图片描述

取出了数字7

进行模板匹配

		
      
        # 定义保存匹配得分的列表
        scores = []
        for (digit, digit_roi) in digits.items():
            result = cv2.matchTemplate(roi, digit_roi, cv2.TM_CCOEFF)
            # 只要最大值, 即分数
            (_, score, _, _) = cv2.minMaxLoc(result)
            scores.append(score)
        # 找到分数最高的数字, 即我们匹配到的数字l
        group_output.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(group_output), (gx, gy - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
    output.extend(group_output)
cv2.imwrite('image.jpg', image)
cv_show('image', image)

最后将识别出的数字显示在原图上对应数字区域上方

在这里插入图片描述

识别效果图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1720052.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入理解Qt计算器应用的构建过程

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、数字按钮的信号与槽函数连接 二、运算符按钮的信号与槽函数连接 三、特殊按钮的信号与…

20 厂商文档学习资料查询

01 厂商介绍 新华三&#xff08;H3C&#xff09; 新华三是一家专注于IT基础设施产品和解决方案的公司&#xff0c;提供从网络设备到数据中心解决方案的全套服务。它是中国领先的网络解决方案供应商之一&#xff0c;业务涵盖企业网、数据中心、云计算等多个领域。 华为&#x…

音视频开发—视频相关概念:YUV与RGB

文章目录 YUV相关概念组成部分优点常见的 YUV 格式数据量的计算YUV4:2:0 存储格式平面模式&#xff08;planar):打包模式&#xff08;packed&#xff09; RGB 和 YUV 的定义关系与转换RGB 到 YUV 的转换YUV 到 RGB 的转换 使用场景优缺点 YUV相关概念 YUV 是一种颜色编码格式&…

3389,为了保障3389端口的安全,我们可以采取的措施

3389端口&#xff0c;作为远程桌面协议&#xff08;RDP&#xff09;的默认端口&#xff0c;广泛应用于Windows操作系统中&#xff0c;以实现远程管理和控制功能。然而&#xff0c;正因为其广泛使用&#xff0c;3389端口也成为许多潜在安全威胁的入口。因此&#xff0c;确保3389…

笔记:Context

Context 是上下文对象&#xff0c;是 Android 常用类 Activity、Service 和 Application 都间接继承 Context &#xff0c;Context 是一个抽象类&#xff0c;内部定义了很多方法和静态常量&#xff0c;具体实现类是 ContextImpl ContextImpl 和 ContextWrapper 继承子 Context…

用Python代码删除Word文档空白行

Word文档内容的整洁性与易读性是体现文档水平的关键因素之一。许多错误或不合理的内容&#xff0c;如多余的空白行&#xff0c;往往会影响阅读流畅度&#xff0c;或是干扰自动化数据处理的准确性。特别是在进行数据分析、报告生成及长文档编辑时&#xff0c;多余的空白行可能导…

赚钱其实没有秘密,多琢磨一下不丢人

为什么学了很多知识还是挣不到钱&#xff1f; 挣不到钱&#xff0c;是因为你不够稀缺&#xff1b;挣钱太少&#xff0c;是因为你不懂杠杆&#xff0c;用杠杆撬动稀缺&#xff0c;个人价值自然水涨船高。 学富五车&#xff0c;为何财库依旧空空&#xff1f;怎样才能提高挣钱的…

SpringBoot启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图(五)

SpringBoot启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图&#xff08;五&#xff09; 参考 目录 文章目录 SpringBoot启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图&#xff08;五&#xff09;1、设置sping.beaninfo.ignore属性2、…

Python自动化办公2.0 即将发布

第一节课&#xff1a;数据整理与清洗 第二节课&#xff1a;数据筛选、过滤与排序 第三节课&#xff1a;高级数据处理技巧 第四节课&#xff1a;数据可视化与实践案例 第五节课&#xff1a;统计分析与报表 第六节&#xff1a;常见的Excel报表 与下方的课程形成知识体系&…

『ZJUBCA MeetUP』 5月25日线下活动——Aptos 链的动态与应用

2024 求是创新 ZJUBCA Sponsored by the ALCOVE Community TIME&#xff1a;2024/05/25 ADD&#xff1a;浙江大学紫金港校区 --- Alcove 是 Aptos 公链与 Alibaba Cloud 共同打造的亚洲首个 Move 开发者社区&#xff0c;致力于支持开发者使用 Move 语言构建下一代 Web3 应用&am…

探索 Ollama: 你的本地 AI 助手

本期推荐的开源项目是 Ollama&#xff0c;它是一款本地大模型运行工具&#xff0c;可以帮助用户轻松下载和运行各种大型语言模型&#xff08;LLM&#xff09;&#xff0c;而无需将数据上传到云端。以下是关于 Ollama 的介绍以及安装和使用教程&#xff1a; Ollama 是什么&#…

springboot结合mybatis使用多数据源的方式

背景 最近有一个需求&#xff0c;有两个库需要做同步数据&#xff0c;一个Doris库&#xff0c;一个mysql库&#xff0c;两边的表结构一致&#xff0c;这里不能使用navicat等工具提供的数据传输之类的功能&#xff0c;只能使用代码做同步&#xff0c;springboot配置多数据…

公众号爆文全攻略:最新推荐机制与实战干货分享

期待已久的公众号爆文直播来了&#xff01;老规矩&#xff0c;免费&#xff0c;只讲干货&#xff01;全程不废话&#xff01; 本次直播你将收获&#xff1a; 深度拆解公众号最新推荐机制&#xff1a;掌握公众号运营的核心规则&#xff0c;精准把握推荐逻辑&#xff0c;让你的内…

云动态摘要 2024-05-31

给您带来云厂商的最新动态&#xff0c;最新产品资讯和最新优惠更新。 最新优惠与活动 [1.5折起]年中盛惠--AI分会场 腾讯云 2024-05-30 人脸核身、语音识别、文字识别、数智人、腾讯混元等热门AI产品特惠&#xff0c;1.5折起 云服务器ECS试用产品续用 阿里云 2024-04-14 云…

手写HTML字符串解析成对应的 AST语法树

先看效果 展示如下&#xff1a; HTML模版 转成ast语法树后 在学习之前&#xff0c;我们需要了解这么一个问题&#xff0c;为什么要将HTML字符串解析成对应的 AST语法树。 为什么&#xff1f; 语法分析&#xff1a;HTML字符串是一种标记语言&#xff0c;其中包含了大量的标签…

掀桌子、降价、免费...之后,国内大模型应用进入高速时代

5月15日&#xff0c;字节跳动打响大模型市场价格战第一枪&#xff1b;5月21日阿里云更狠&#xff0c;价格降了97%&#xff0c;比字节还便宜37.5%同日&#xff0c;百度更为激进&#xff0c;直接宣布其两款主力模型ENIRE Speed和ENIRE Lite全面免费&#xff1b;5月22号&#xff0…

Windows10专业版系统安装Hyper-V虚拟机软件

Windows10专业版系统安装Hyper-V虚拟机软件 适用于在Windows10专业版系统安装Hyper-v虚拟机软件。 1. 安装准备 1.1 安装平台 Windows 10 1.2. 软件信息 软件名称软件版本安装路径windowswindows 10 专业版Hyper-vHyper-v 2. Hyper-v搭建 2.1打开cmd软件 2.2打开控制面…

【PostgreSQL17新特性之-explain命令新增选项】

EXPLAIN是一个用于显示语句执行计划的命令&#xff0c;可用于显示以下语句类型之一的执行计划&#xff1a; - SELECT - INSERT - UPDATE - DELETE - VALUES - EXECUTE - DECLARE - CREATE TABLE AS - CREATE MATERIALIZED VIEWPostgreSQL17-beta1版本近日发布了&#xff0c;新…

使用Prompt,轻松实现你的第一个全栈项目

前言 还有程序员没有应用过大模型技术吗&#xff1f;是工具也可以&#xff01;如果你还未使用过大模型技术&#xff0c;那么我劝你尽早行动&#xff0c;它会成为你开发的一大神器。如果你对大模型感兴趣&#xff0c;同时想使用大模型技术来开发产品&#xff0c;我接下来这个实…

Ubuntu24.04 LTS安装中文输入法

前言 最近&#xff0c;windows玩没了&#xff0c;一怒之下决定换一个操作系统&#xff0c;当然就是最新的Ubuntu24.04 LTS.&#xff0c;其中魔法和咒语&#xff08;汉语&#xff09;是inux遇到的第一大难关&#xff0c;我权限不够教不了魔法&#xff0c;但我可以教你咒语(๑•…