使用opencv的matchTemplate进行银行卡卡号识别

news2024/11/23 13:25:39

![字体文件](https://img-blog.csdnimg.cn/3a16c87cf4d34aceb0778c4b20ddadb2.png#pic_centere5628b04eb93564c23ed0f58a360a10.png

import cv2
import numpy as np


def show_img(img, name="temp"):
    img = cv2.resize(img, (0, 0), fx=3, fy=3)
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


def show_img_normal(img, name="temp"):
    img = cv2.resize(img, (0, 0), fx=0.5, fy=0.5)
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


# 排序方法
def sort_contours(cnts, method='left-to-right'):
    reverse = False
    i = 0
    if method == 'right-to-left' or method == 'bottom-to-top':
        reverse = True
    if method == 'bottom-to-top' or method == 'top-to-bottom':
        i = 1

    boundingBoxes = [cv2.boundingRect(c) for c in cnts]
    (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes), key=lambda b: b[1][i], reverse=reverse))
    return (cnts, boundingBoxes)


# 读取图像
number_o = cv2.imread("./source/e5628b04eb93564c23ed0f58a360a10.png")
# 转灰度图
number_gary = cv2.cvtColor(number_o, cv2.COLOR_BGR2GRAY)
# 二值化操作
_, number_threshold = cv2.threshold(number_gary, 100, 255, cv2.THRESH_BINARY_INV)
# show_img(number_threshold, "number_threshold")
# 轮廓检测,只检测外轮廓,绘制到原图上
contours, hierarchy = cv2.findContours(number_threshold, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
number_contours = cv2.drawContours(number_o, contours, -1, (0, 255, 0), 1)
# show_img(number_contours, "number_contours")

# 绘制所有轮廓的方形边界
number_boundingRect = number_o.copy()
number_imgs = []
contours = sort_contours(contours)[0]
# contours.sort_cont(key=cv2.INTER_AREA, reverse=True)
for cnt in contours:
    x, y, w, h = cv2.boundingRect(cnt)
    cv2.rectangle(number_boundingRect, (x, y), (x + w, y + h), (0, 0, 255), 1)

    # 显示每一个模板,作为单独图片
    number_one = number_threshold[y: y + h, x:x + w]
    number_one = cv2.resize(number_one, (35, 50))
    number_imgs.append(number_one)
    # show_img(number_one, "every")

# 显示每一个模板,所有.展示外边框信息数据
show_img(number_boundingRect, "number_boundingRect")

im_o = cv2.rotate(cv2.imread("./source/data/1.jpg"), cv2.ROTATE_90_COUNTERCLOCKWISE)
im_gary = cv2.cvtColor(im_o, cv2.COLOR_BGR2GRAY)
# show_img_normal(im_gary, "im_gary")

# 构建卷积核
kernel2 = cv2.getStructuringElement(cv2.MORPH_RECT, (8, 2))

# 执行礼帽操作,高亮一下有效信息
im_tophat = cv2.morphologyEx(im_gary, cv2.MORPH_TOPHAT, kernel=kernel2, iterations=1)
# show_img_normal(im_tophat, "im_tophat")

# 闭操作,将临近相似区域连起来
im_close = cv2.morphologyEx(im_tophat, cv2.MORPH_CLOSE, kernel2, iterations=8)
# show_img_normal(im_close, "im_close")

# 二值化,分离信息
_, im_threshold = cv2.threshold(im_close, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
# show_img_normal(im_threshold, "im_threshold")

# 中值滤波去除噪音点
im_medianBlur = cv2.medianBlur(im_threshold, 9)
# show_img_normal(im_medianBlur, "im_medianBlur")

# 再执行闭操作,连起来相似区域
im_close2 = cv2.morphologyEx(im_medianBlur, cv2.MORPH_CLOSE, kernel2, iterations=2)
# show_img_normal(im_close2, "im_close2")

# 执行轮廓提取
contours, hierarchy = cv2.findContours(im_close2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

validCnt = []
# 所有的边框边界
im_boundingRect_all = cv2.cvtColor(im_close2.copy(), cv2.COLOR_GRAY2BGR)
im_boundingRect_valid = cv2.cvtColor(im_close2.copy(), cv2.COLOR_GRAY2BGR)

# 记录所有的面积数据
area = np.empty((len(contours),))

# 遍历一下,填充面积,后面算平均值和标准差,来过滤过小数据
for index, cnt in enumerate(contours):
    area[index] = cv2.contourArea(cnt)

mean = np.mean(area)
std = np.std(area)

for cnt in contours:
    x, y, w, h = cv2.boundingRect(cnt)
    # 计算面积
    areaX = cv2.contourArea(cnt)
    # 计算长宽比
    aspectRatio = w / h
    # 绘制长宽比和值
    cv2.rectangle(im_boundingRect_all, (x, y), (x + w, y + h), (0, 255, 0), 2)
    cv2.putText(im_boundingRect_all, f"{aspectRatio:.3f}", (x, y), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 2)
    # 只有指定比例和面积不是过小的 > mean + std的,选出来
    if (2.8 < aspectRatio < 3.2 or 4.2 < aspectRatio < 5.8 or 8 < aspectRatio < 10) and (areaX > mean - 0 * std):
        validCnt.append(cnt)
        cv2.rectangle(im_boundingRect_valid, (x, y), (x + w, y + h), (0, 255, 255), 2)
        cv2.putText(im_boundingRect_valid, f"{aspectRatio:.3f}", (x, y), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 255), 2)

# show_img_normal(im_boundingRect_all, "im_boundingRect_all")
# show_img_normal(im_boundingRect_valid, "im_boundingRect_valid")

# 将有效区域定义出来ROI区域,进行边缘检测,拆分单个字符
for cnt in validCnt:
    x, y, w, h = cv2.boundingRect(cnt)
    # 显示roi区域
    im_roi = im_gary[y - 15:y + h + 5, x - 15:x + w + 5]
    # show_img(im_roi)

    # 二值化
    _, im_roi_threshold = cv2.threshold(im_roi, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
    # show_img(im_roi_threshold, "im_roi_threshold")

    # 闭操作合并一些边界
    k = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
    im_roi_close = cv2.morphologyEx(im_roi_threshold, cv2.MORPH_CLOSE, k, iterations=2)
    # show_img(im_roi_close, "im_roi_close")

    # 轮廓检测
    im_roi_bound = cv2.cvtColor(im_roi.copy(), cv2.COLOR_GRAY2BGR)
    im_roi_contours, hierarchy = cv2.findContours(im_roi_close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    im_roi_contours = sort_contours(im_roi_contours)[0]

    # im_roi_bound = im_roi_close.copy()
    for cnt_roi in im_roi_contours:
        xr, yr, wr, hr = cv2.boundingRect(cnt_roi)
        cv2.rectangle(im_roi_bound, (xr, yr), (xr + wr, yr + hr), (255, 0, 0), 1)
        im_roi_close_one = cv2.resize(im_roi_close[yr: yr + hr, xr:xr + wr], (35, 50))
        # 显示切分出来的单个数字
        # show_img(im_roi_close_one, "im_roi_close_one")
        # 和10个数字比
        scores = []
        for number_img_one in number_imgs:
            score = cv2.matchTemplate(im_roi_close_one, number_img_one, cv2.TM_CCOEFF_NORMED)
            scores.append(score)
        maxIndex = scores.index(max(scores))
        cv2.putText(im_o, str(maxIndex), (x + xr, y + yr), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 255), 2)
        cv2.putText(im_roi_bound, str(maxIndex), ( xr, yr + 10), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 255), 1)
    # 显示切分的轮廓
    # show_img(im_roi_bound, "im_roi_bound")
show_img_normal(im_o, "im_o")

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

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

相关文章

Windows10-用户账户控制、Windows远程桌面

Windows10用户账户控制怎么设置白名单 问题引出&#xff1a; 安装低版本搜狗输入法后经常弹出用户账户控制 解决方案&#xff1a; 全局模式&#xff1a; UAC控制最早出现在Windows Vista中&#xff0c;用户帐户控制&#xff08;UAC&#xff09;是一项旨在防止对您的计算机…

2024年进入-1/12的世界

1.从一段与AI的对话开始 cj: 1234...无限的&#xff0b;下去结果是无穷大吗&#xff1f; chatgpt: 是的&#xff0c;从常规的数学观点来看&#xff0c;级数 1234… 无限相加的结果是正无穷。 这是因为每一项都是正数&#xff0c;并且随着项数的增加&#xff0c;部分和会趋近…

校园虚拟化部署与横向扩展统一存储

项目背景 这所隶属教育部直属重点大学&#xff0c;学校设有11个学科体系&#xff0c;现有本硕博学生共29000余人&#xff0c;为积极响应“中国教育现代化2023战略部署”&#xff0c;校方制定教育信息化2.0发展目标&#xff0c;通过平台融合&#xff0c;数据驱动、技术赋能等措…

时间序列预测 — LSTM实现单变量滚动风电预测(Keras)

目录 1 数据处理 1.1 数据集简介 1.2 数据集处理 2 模型训练与预测 2.1 模型训练 2.2 模型滚动预测 2.3 结果可视化 1 数据处理 1.1 数据集简介 实验数据集采用数据集5&#xff1a;风电机组运行数据集&#xff08;下载链接&#xff09;&#xff0c;包括风速、风向、温…

【MySQL】binlog数据恢复

binlog概述 binlog二进制日志记录保存了所有执行过的修改操作语句&#xff0c;不保存查询操作。如果 MySQL 服务意外停止&#xff0c;可通过二进制日志文件排查&#xff0c;用户操作或表结构操作&#xff0c;从而来恢复数据库数据。binlog 是逻辑日志&#xff0c;记录的是这个…

网页设计--第5次课后作业

1、快速学习JavaScript的基本知识第1-10章 JavaScript入门 - 绿叶学习网 2、使用所学的知识完成以下练习。需求如下3个&#xff1a; 1&#xff09;点亮灯泡 2&#xff09;将所有的div标签的标签体内容后面加上&#xff1a; very good 3&#xff09;使所有的复选框呈现被选…

编程在现代社会中的重要性

文章目录 编程的重要性引言编程在现代社会中的重要性常见的编程应用场景结语 编程的重要性 引言 编程在现代社会中的重要性是不言而喻的&#xff0c;它可以让我们创造出各种有用的软件&#xff0c;解决各种复杂的问题&#xff0c;甚至改变世界。 编程在现代社会中的重要性 编…

【Unity细节】用代码控制Rigibody的约束RigidbodyConstraints(刚体约束)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 &#x1f636;‍&#x1f32b;️收录于专栏&#xff1a;unity细节和bug &#x1f636;‍&#x1f32b;️优质专栏 ⭐【…

我对自动化测试的一些认识

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

〔005〕虚幻 UE5 像素流多用户部署

✨ 目录 ▷ 为什么要部署多用户▷ 开启分发服务器▷ 配置启动多个信令服务器▷配置启动客户端▷多用户启动整体流程和预览▷注意事项▷ 为什么要部署多用户 之前的像素流部署,属于单用户,是有很大的弊端的打开多个窗口访问,可以看到当一个用户操作界面的时候,另一个界面也会…

软件工程--面向对象分析用通俗语言20小时爆肝总结!(包含用例图、活动图、类图、时序图......)

面向对象方法分为面向对象分析&#xff08;OOA&#xff09;、面向对象设计&#xff08;OOD&#xff09;、面向对象编程&#xff08;OOP&#xff09;&#xff0c;本文详细介绍面向对象分析 本文参考教材&#xff1a;沈备军老师的《软件工程原理》大多图片来源其中 目录 面向对…

51单片机项目(14)——基于51单片机的烟雾报警系统

1.设计内容 本次设计的系统功能描述如下&#xff1a; 1.可以测量烟雾浓度并且在屏幕显示&#xff0c;同时显示浓度阈值。 2.可以通过按键对阈值进行加减调节。 3.浓度大于阈值时&#xff0c;蜂鸣器报警&#xff0c;风扇转动&#xff0c;发送报警信息&#xff08;“to high”…

国标GB28181安防视频平台EasyGBS现场突发播放中断是什么原因?

视频流媒体安防监控国标GB28181平台EasyGBS视频能力丰富&#xff0c;部署灵活&#xff0c;既能作为业务平台使用&#xff0c;也能作为安防监控视频能力层被业务管理平台调用。国标GB28181视频EasyGBS平台可提供流媒体接入、处理、转发等服务&#xff0c;支持内网、公网的安防视…

自动驾驶中的LFM(LED 闪烁缓解)问题

自动驾驶中的LFM Reference: 自动驾驶系统如何跨越LFM这道坎&#xff1f; 从路灯、交通灯&#xff0c;到车载照明&#xff0c;低功耗、长寿命、高可靠的 LED 正在快速取代传统照明方式。但 LED 在道路上的普遍使用&#xff0c;却带来“LED闪烁”现象。“LED闪烁”是由 LED 驱…

【scipy 基础】--空间计算

scipy.spatial子模块提供了一系列用于处理和计算空间数据和几何形状的算法和工具&#xff0c;在许多领域都有广泛的应用&#xff0c;例如计算机视觉、地理信息系统、机器人学、医学影像分析等。 下面&#xff0c;来具体看看scipy.spatial子模块为我们提供的主要功能分类。 1. 主…

网络通信(架构与三要素)

一&#xff0c;通信架构 二&#xff0c;三要素 三&#xff0c;IP地址 四&#xff0c;域名 五&#xff0c;InetAddress&#xff08;操作IP地址的工具类&#xff09; 六&#xff0c;案例 import java.net.InetAddress; import java.net.UnknownHostException;public class IPInet…

计算机网络(超详解!) 第一节计算机网络的性能指标

1.速率 比特&#xff08;bit&#xff09;是计算机中数据量的单位&#xff0c;也是信息论中使用的信息量的单位。 比特&#xff08;bit&#xff09;来源于 binary digit&#xff0c;意思是一个“二进制数字”&#xff0c;因此一个比特就是二进制数字中的一个 1 或 0。 速率是…

探秘数字学习新兴:深度解析知识付费系统

在当今数字化时代&#xff0c;知识付费系统作为一种创新性的学习和知识分享模式正逐渐崭露头角。本文将深入探讨知识付费系统的概念、重要性&#xff0c;并提供一个简单而完整的示例&#xff0c;展示其核心技术和实现方式。 概念与重要性 知识付费系统是一种基于互联网平台的…

Verilog基础:时序调度中的竞争(二)

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 作为一个硬件描述语言&#xff0c;Verilog HDL常常需要使用语句描述并行执行的电路&#xff0c;但其实在仿真器的底层&#xff0c;这些并行执行的语句是有先后顺序…

2019年7月18日 Go生态洞察:新Go商店公告 ️

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…