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

opencv实战小结-银行卡号识别

实战1-银行卡号识别

项目来源:opencv入门

项目目的:识别传入的银行卡照片中的卡号

难点:银行卡上会有一些干扰项,如何排除这些干扰项,并且打印正确的号码是一个问题

在这里插入图片描述

最终效果如上图

实现这样的功能需要以下几个步骤:

  1. 首先必须有与银行卡中卡号数字基本一样的数字模板,将模板中的数字提取出来并存储起来(0-9)
  2. 将需要检测的银行卡图片中的数字提取出来
  3. 将银行卡的数字与模板数字一一对比,最终找到一个匹配度最高的数字,并把数字标注上

整个思路很简单,但是难点就在于如何将图片处理得更加容易让计算机识别数字,所以整个项目要围绕着图片得的处理来做

第一步-提取数字模板

这是事先准备好的数字模板

在这里插入图片描述

接下来要将图片中的数字都找到,也就是找到各个数字在整个图片上的像素点坐标(轮廓)

首先得到图片的灰度图,再进行二值化处理(这一切都是为了让图片中的数字更易于识别)

# 灰度图
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值图像
ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]#超过阈值部分取maxval ( 最大值 ),否则取0

然后会得到这样的图像
在这里插入图片描述

好了,现在图片已经很清晰了,不需要再进行其它的处理了,直接将其提取

那怎么提取呢?

可以通过cv2.findContours()找到数字的轮廓

函数 cv2.findContours() 有三个参数,第一个是输入图像,第二个是 轮廓检索模式,第三个是轮廓近似方法。返回值有三个,第一个是图像,第二个 是轮廓,第三个是(轮廓的)层析结构。轮廓(第二个返回值)是一个 Python 列表,其中存储这图像中的所有轮廓。每一个轮廓都是一个 Numpy 数组,包 含对象边界点(x,y)的坐标。

注意新版本中这个api的返回值有变化

返回两个参数contours和 hierarchy,contours就是每个数字的轮廓数组,包含边界点的坐标

其中cv2.RETR_EXTERNAL是获取外轮廓

contours, hierarchy = cv2.findContours(ref.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

接下来可以将轮廓画出来看看

会用到cv2.drawContours()函数

函数 cv2.drawContours() 可以被用来绘制轮廓。它可以根据你提供 的边界点绘制任何形状。它的第一个参数是原始图像,第二个参数是轮廓,一 个 Python 列表。第三个参数是轮廓的索引(在绘制独立轮廓是很有用,当设置 -1时绘制所有轮廓)。接下来的参数是轮廓的颜色和厚度等。

cv2.drawContours(img,contours,-1, (0, 0, 255), 3)

看下效果

在这里插入图片描述

好,现在轮廓都找到了,并且我们也有了轮廓的坐标,这个时候我们应该将每个数字的像素点位置都存起来(并不是将图片分割!,整个图片仍然没有任何变化)

好,现在有一个要注意的点,那就是我们在上面得到的contours数组并不是按图片中各个数字从左到右排列的,也就是说数组中第一个坐标可能是图片中8的坐标,那这个时候我们就必须对数组进行排序,排序顺序就是从左到右存

那排序怎么实现呢,其实就是根据x坐标从小到大排序就行了

排完序之后,contours中0下标存的就是数字0的模板,这里很好的利用了数组下标的优点

好的,排序完之后,我们就可以来存这个数字的模板了

思路是遍历contours数组,得到每个模板的坐标以及宽高,利用x+w就能得到图片的x轴范围,y+h就能得到y轴的范围,把他们存起来就得到一个数字的模板了

digits = {}
#遍历每一个轮廓
for (i,c) in enumerate(contours):#计算外接矩形并resize合适的大小(x, y, w, h) = cv2.boundingRect(c)# cv2.rectangle(img,(x,y),(x + w, y + h),(0, 0, 255), 2)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))

一个是9x3的矩阵,一个是5x5

下面对图像进行处理,老规矩,取灰度图

在这里插入图片描述

然后进行礼帽处理,目的是为了突出更明亮的区域

tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)

在这里插入图片描述

接下来再用 Sobel核子对图片进行卷积,目的的为了得到图像梯度,也就是边缘检测

我们现在要做的是把可能为数字的区域都找出来

gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)
gradX = np.absolute(gradX)
(minVal, maxVal) = (np.min(gradX), np.max(gradX))
gradX = (255 * ((gradX - minVal) / (maxVal - minVal)))
gradX = gradX.astype("uint8")

在这里插入图片描述

上图看上去更加模糊了,但是数字和非数字区域的明亮度变了

好的,接下来可以通过闭操作(先膨胀,再腐蚀),将数字连起来(是为了最后找到数字区域,因为卡号是4个数字连在一起的,我们把4个数字的区域找出来)

变成这样

在这里插入图片描述

再来一次阈值操作

thresh = cv2.threshold(gradX, 0, 255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]

变成这样

在这里插入图片描述

矩形区域好像白色没有填满,再来一次闭操作

在这里插入图片描述

ok了,现在疑似数字的区域都很明显了吧,那下一步就是将这个区域进行排除,找到真正为银行卡号的区域,其他的区域就不要了

那怎么做呢?我们先把他们的轮廓都找出来,然后判断这些轮廓的宽度,符合银行卡号区域宽的的留下,不符合的去掉就可以了

在这里插入图片描述

# 计算轮廓
contours_, hierarchy_ = cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = contours_
cur_img = image.copy()
cv2.drawContours(cur_img, cnts, -1, (0, 0, 255), 3)
cv_show('img', cur_img)
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))

得到卡号轮廓后,同样对其从左至右排序

好了,那接下来干嘛呢,我们刚刚得到的是四个数字组成的区域的轮廓,这个时候我们应该遍历这些区域,得到里面的四个数字的轮廓

同样也是个遍历操作

for (i, (gX, gY, gW, gH)) in enumerate(locs):groupOutput = []# 根据坐标提取每一个组group = gray[gY - 5:gY + gH + 5, gX - 5:gX + gW + 5]cv_show('group', group)

会得到四个这样的组

在这里插入图片描述

然后就获取这个组的轮廓,就像第一步骤一样,将数字提取出来就可以了

#计算每一组的轮廓digitCnts, hierarchy = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)# 从左到右排序digitCnts = myutils.sort_contours(digitCnts, method="left-to-right")[0]

好的,接下来就是最重要的第三部操作了,将模板与上面得到的数字匹配,找到匹配度最高的那个模板数字就是我们要找的数字了

 #计算每一组的每一个数值for c in digitCnts:# 找到当前数值的轮廓,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)# 计算匹配得分scores = []for (digit, digitROI) in digits.items():# 模板匹配result = cv2.matchTemplate(roi, digitROI,cv2.TM_CCOEFF)# print('result',result)# 获取匹配度最高的数值(_, score, _, _) = cv2.minMaxLoc(result)scores.append(score)print("scores",scores)# 得到最合适的数字groupOutput.append(str(np.argmax(scores)))print('groupOutput',groupOutput)

完成上述步骤之后,我们的groupOutput就存放了我们识别出来的银行卡号了,我们只需要在图片上将卡号绘制出来就可以了

  # 画出来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)

最终效果如下

在这里插入图片描述


好了,以上就是此小项目的实现过程

总结:这是我学cv的第一个小实战项目,确实感觉蛮有意思的,学之前觉得这个东西很神奇,学习之后会发现其实一切都是按照逻辑一步步来的,没有那么"高大上",继续努力吧

相关文章:

opencv实战小结-银行卡号识别

实战1-银行卡号识别 项目来源&#xff1a;opencv入门 项目目的&#xff1a;识别传入的银行卡照片中的卡号 难点&#xff1a;银行卡上会有一些干扰项&#xff0c;如何排除这些干扰项&#xff0c;并且打印正确的号码是一个问题 最终效果如上图 实现这样的功能需要以下几个步骤…...

Windows API 开发桌面应用程序,在窗口按下鼠标左键不放可以拖图,并且拖图期间鼠标图标变成手掌

在Windows API中&#xff0c;要实现鼠标左键按下并拖动以移动窗口中的某个图形&#xff0c;并且同时改变鼠标图标为“手掌”形状&#xff08;这通常指的是“拖动”或“移动”的图标&#xff09;&#xff0c;你需要执行几个步骤。 以下是一个基本的步骤指南&#xff0c;用于在W…...

Docker的网络管理

文章目录 一、Docker容器之间的通信1、直接互联&#xff08;默认Bridge网络&#xff09;1.1、Docker安装后默认的网络配置1.2、创建容器后的网络配置1.2.1、首先创建一个容器1.2.2、ip a 列出网卡变化信息1.2.3、查看新建容器后的桥接状态 1.3、容器内安装常见的工具1.4、容器间…...

【数据结构】平衡二叉树左旋右旋与红黑树

平衡二叉树左旋右旋与红黑树 平衡二叉树 定义 平衡二叉树是二叉搜索树的一种特殊形式。二叉搜索树&#xff08;Binary Search Tree&#xff0c;BST&#xff09;是一种具有以下性质的二叉树&#xff1a; 对于树中的每个节点&#xff0c;其左子树中的所有节点都小于该节点的值…...

2024蓝桥杯初赛决赛pwn题全解

蓝桥杯初赛决赛pwn题解 初赛第一题第二题 决赛getting_startedbabyheap 初赛 第一题 有system函数&#xff0c;并且能在bss上读入字符 而且存在栈溢出&#xff0c;只要过掉check函数即可 check函数中&#xff0c;主要是对system常规获取权限的参数&#xff0c;进行了过滤&…...

大模型多轮问答的两种方式

前言 大模型的多轮问答难点就是在于如何精确识别用户最新的提问的真实意图&#xff0c;而在常见的使用大模型进行多轮对话方式中&#xff0c;我接触到的只有两种方式&#xff1a; 一种是简单地直接使用 user 和 assistant 两个角色将一问一答的会话内容喂给大模型&#xff0c…...

【无标题】1877A

足球锦标赛中有 n支球队。每对队伍匹配一次。每场比赛结束后&#xff0c;Pak Chanek收到两个整数作为比赛结果&#xff0c;即两队在比赛中得分的数量。一支球队的效率等于本队每场比赛的总进球数减去对手每场比赛的总进球数。 比赛结束后&#xff0c;Pak Dengklek会计算每支球…...

直播美颜工具解析:美颜SDK核心技术与性能优化方法

本篇文章&#xff0c;小编将深入解析直播美颜SDK的核心技术及其性能优化方法&#xff0c;以期为开发者提供有价值的参考。 一、美颜SDK核心技术 1.实时人脸检测与识别 美颜SDK的核心技术之一是实时人脸检测与识别。这项技术基于深度学习算法&#xff0c;能够快速、准确地识别…...

YOLOv10开源,高效轻量实时端到端目标检测新标准,速度提升46%

前言 实时目标检测在自动驾驶、机器人导航、物体追踪等领域应用广泛&#xff0c;近年来&#xff0c;YOLO 系列模型凭借其高效的性能和实时性&#xff0c;成为了该领域的主流方法。但传统的 YOLO 模型通常采用非极大值抑制 (NMS) 进行后处理&#xff0c;这会增加推理延迟&#…...

如何解决访问网站时IP被限制的问题?

在互联网上&#xff0c;用户可能会面临一个令人困扰的问题——当尝试访问某个特定的网站时&#xff0c;却发现自己的IP地址被该网站屏蔽。 IP地址被网站屏蔽是一个相对常见的现象&#xff0c;而导致这种情况的原因多种多样&#xff0c;包括恶意行为、违规访问等。本文将解释IP地…...

springboot城市美发管理系统的设计与实现-计算机毕业设计源码71715

摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对城市美发管理系统等问题&#xff0c;对城市…...

微软 Windows 10 22H2 发布可选更新 19045.4474,修复窗口显示问题等

微软今天面向 Windows 10 22H2 版本&#xff0c;发布了 KB5037849 非安全可选更新&#xff0c;用户安装后版本号升至 Build 19045.4474。 IT之家 5 月 30 日消息&#xff0c;微软今天面向 Windows 10 22H2 版本&#xff0c;发布了 KB5037849 非安全可选更新&#xff0c;用户安…...

代码随想录算法训练营第五十三天 | 309.最佳买卖股票时机含冷冻期、714.买卖股票的最佳时机含手续费

309.最佳买卖股票时机含冷冻期 视频讲解&#xff1a;动态规划来决定最佳时机&#xff0c;这次有冷冻期&#xff01;| LeetCode&#xff1a;309.买卖股票的最佳时机含冷冻期_哔哩哔哩_bilibili代码随想录 解题思路 1. dp[i][0] 第i天持有股票的状态 dp[i][1]第i天不持股的状…...

Polar Web【中等】反序列化

Polar Web【中等】反序列化 Contents Polar Web【中等】反序列化思路&探索EXPPHP生成PayloadGET传递参数 运行&总结 思路&探索 一个经典的反序列化问题&#xff0c;本文采用PHP代码辅助生成序列字符串的方式生成 Payload 来进行手动渗透。 打开站点&#xff0c;分析…...

测试工具链

缺陷管理 bug管理工具 devops---项目管理--缺陷管理 bug管理地址 https://devsecops.mychery.com:8443/chery/project?filterROLE&statusACTIVE bug管理环境 采用公司的devops平台&#xff0c;对每个项目的bug进行管理。目前在使用 接口测试和服务端性能测试 工具…...

【求助】ansible synchronize 问题

求助贴&#xff0c;不是解答贴哈 最近把一台服务器从centos7.9升级到alibaba cloud linux3之后&#xff0c;出现了一个ansible的问题。 版本是ansible8.3.0ansible-core-2.15.3&#xff0c;在使用synchronize模块时&#xff0c;我使用了别名&#xff08;比如web1&#xff09;会…...

sql server 把表的所有的null改为0,不要限制某列

DECLARE tableName NVARCHAR(256) Linear -- 替换为你的表名 DECLARE sql NVARCHAR(MAX) SELECT sql UPDATE tableName SET COLUMN_NAME 0 WHERE COLUMN_NAME IS NULL; FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME tableName AND TABLE_SCHEM…...

【C#】WinForm关闭新(二级)界面使主程序关闭

参考视频&#xff1a;https://www.bilibili.com/video/BV1JY4y1G7jo?p14&vd_source1c57ab1b2e551da5b65c0dfb0f05a493 1.背景介绍 主程序界面&#xff0c;点击弹出二级界面&#xff08;同时隐藏主界面&#xff09;&#xff0c;不做任何设置&#xff0c;这时关闭二级界面…...

光伏电站绘制软件的基本方法

随着可再生能源的快速发展&#xff0c;光伏电站的建设日益受到重视。为了提高光伏电站设计的效率和准确性&#xff0c;光伏电站绘制软件的应用变得至关重要。本文将介绍光伏电站绘制软件的基本方法&#xff0c;包括绘制屋顶、屋脊、障碍物和参照物&#xff0c;铺设光伏板&#…...

【Python】selenium使用find_element时解决【NoSuchElementException】问题的方法

NoSuchElementException 是 Selenium WebDriver 中的一种异常&#xff0c;我们在写selenium.find_element 的时候也比较常见&#xff0c;它会在我们要尝试定位一个不存在的元素时抛出这类错误。 以下是一些解决NoSuchElementException 的常用方法&#xff1a; 检查元素定位器:…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法&#xff1a;原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件&#xff0c;如包含恶意代码、敏感数据或欺诈内容的文档&#xff0c;在企业协同办公环境中&#xff08;如Teams、Google Workspace&#xff09;尤为重要。结合大模型技术&…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...