当前位置: 首页 > 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; 检查元素定位器:…...

oracle表锁

--oracle提醒记录被另一个用户锁住&#xff1a; --问题描述&#xff1a;你去修改数据时&#xff0c;报错“ --问题分析&#xff1a;你用select t.*,t.rowid from qxt_logsend_0728修改数据结果集时&#xff0c;计oracle会通过事务锁锁住这个记录&#xff0c;点击记录改变&#…...

父组件调用子组件方法(组合式 API版)

在 Vue 3 中&#xff0c;defineExpose 是一个用于在组合式 API (Composition API) 中暴露组件内部方法或属性的函数。它允许父组件通过 ref 引用子组件实例&#xff0c;并调用子组件暴露的方法或访问其属性。 以下是子组件和父组件如何使用 defineExpose 和 ref 的详细解释和示…...

【动手学深度学习】使用块的网络(VGG)的研究详情

目录 &#x1f30a;1. 研究目的 &#x1f30a;2. 研究准备 &#x1f30a;3. 研究内容 &#x1f30d;3.1 多层感知机模型选择、欠拟合和过拟合 &#x1f30d;3.2 练习 &#x1f30a;4. 研究体会 &#x1f30a;1. 研究目的 理解块的网络结构&#xff1b;比较块的网络与传统…...

JFinal学习07 控制器——接收数据之getBean()和getModel()

JFinal学习07 控制器——接收数据之getBean()和getModel() 视频来源https://www.bilibili.com/video/BV1Bt411H7J9/?spm_id_from333.337.search-card.all.click 文章目录 JFinal学习07 控制器——接收数据之getBean()和getModel()一、接收数据的类型二、getBean()和getModel()…...

二百三十九、Hive——Hive函数全篇

--创建测试数据库test show databases ; create database if not exists test; use test;一、关系运算 1、等值比较&#xff1a; select 1 where 1 1; --1 select 1 where 0 1; --NULL 2、不等值比较&#xff1a;<> select 1 where 1 <> 2; --1 sele…...

视频去水印电脑版,视频去水印软件

视频去水印怎么去&#xff0c;一直是视频编辑者们的热门话题。那么&#xff0c;如何去除频水印呢&#xff1f;接下来&#xff0c;我们将为您详细介绍视频去水印方法。 第一种方法&#xff1a; 首先通过浏览器打开 “ 51视频处理官网” 的网站。打开网站后&#xff0c;我们上传…...

北邮21硕后端开发笔记

blog 整理北邮21渣硕Java后端开发知识网络&#xff0c;阅读笔记以及技术博客&#xff0c;持续更新&#xff01;欢迎Star&#xff01; GitHub: https://github.com/WeiXiao-Hyy/blog Java 基础篇 一文带你搞懂final关键字 Java并发编程 fucking-java-concurrency解读你真…...

【Linux】系统优化:一键切换软件源与安装Docker

引言 在Linux系统安装完成后&#xff0c;进行一些必要的初始化设置是提升系统性能和用户体验的关键。本文将重点介绍两个实用的一键脚本&#xff1a;LinuxMirrors提供的软件源切换脚本和Docker安装脚本。这两个脚本将帮助我们简化配置安装过程。 一键切换软件源脚本 在Linux…...

【集装箱调度】基于粒子群算法实现考虑重量限制和时间约束的集装箱码头满载AGV自动化调度附matlab代码

% 交叉定位 - 最小二乘法定位算法模拟 % 参数设置 numIterations 1000; % 模拟迭代次数 maxDistance 1000; % 最远定位距离&#xff08;设定范围&#xff09; speedOfSound 343; % 声速&#xff08;单位&#xff1a;m/s&#xff09; % 预警机坐标 source [0, 0]; % 初始…...

使用 ESP32 和 PlatformIO (arduino框架)实现 Over-the-Air(OTA)固件更新

使用 ESP32 和 PlatformIO 实现 Over-the-Air&#xff08;OTA&#xff09;固件更新 摘要&#xff1a; 本文将介绍如何在 ESP32 上使用 PlatformIO 环境实现 OTA&#xff08;Over-the-Air&#xff09;固件更新。OTA 更新使得在设备部署在远程位置时&#xff0c;无需物理接触设…...

django网站开发源码/持啊传媒企业推广

推荐博客&#xff1a;付铭 day-01 HTML 1、HTML 基本语法 html标签 单标签 <img /> 、<img> 双标签 <html> </html> 属性 属于标签 <img src"图片的地址"><table width"100" height"200"></table> 1…...

微网站建设开发/上海seo搜索优化

这是一个iPhone Menu JSON文件的示例&#xff0c;您可能会看到该文件用于存储菜单配置设置以在移动设备上设置网站。 使用简单的JSON格式&#xff0c;可以轻松地在移动和Web组件之间共享它。 另外&#xff1a; 请参阅更多JSON示例。 {"menu": {"header": &…...

网站公告栏模板/富阳seo关键词优化

关于present页面&#xff0c;且UIViewController中WebView的H5弹出Camera/ImagePicker大致分3种情况&#xff0c;严格意义上是分2种情况&#xff1a;1.一个ViewController A present ViewController D2.把ViewController B放到一个UINavigationController中管理&#xff0c;Vie…...

简阳网站建设/班级优化大师免费下载学生版

手册4.32和4.33章节主要讲述了封装后修复的内容&#xff0c;之前在印象笔记中记录了Post Package Repair&#xff08;PPR&#xff09;的笔记&#xff0c;现在搬运至此&#xff0c;作为补充。 PPR全称为Post Package Repair&#xff0c;中文直译为封装后修复&#xff0c;其意为…...

用nas做网站服务器/市场营销策略包括哪些策略

MyBatis 真正的力量是在映射语句中。这里是奇迹发生的地方。对于所有的力量,SQL 映射的 XML 文件是相当的简单。当然如果你将它们和对等功能的 JDBC 代码来比较,你会发现映射文件节省了大约 95%的代码量。MyBatis 的构建就是聚焦于 SQL 的,使其远离于普通的方式。 SQL 映射文件…...

成都网站设计开发公司/百度搜索引擎广告位的投放

Ubuntu 3D目录了解 Ubuntu历史与发展过程特色Ubuntu的3D桌面开发意念安装设定从硬盘安装其他特色软件组件缺省套件私有版权软件的采用发布周期正式衍生版本非正式衍生版本中文译名各界评价免费获取Ubuntu CD软件组件缺省套件私有版权软件的采用发布周期正式衍生版本非正式衍生版…...