若楠带你初识OpenCV(7) -- 轮廓检测之银行卡号识别

news2024/9/25 13:23:03

文章目录

  • 银行卡号识别
  • 详细流程
    • 一、设置参数
    • 二、函数准备
    • 三、具体步骤
      • 1. 得到每个数字的信息
      • 2. 银行卡处理
      • 3. 找到数字边框
      • 4. 模板匹配
  • 总结

银行卡号识别

经过了几篇关于轮廓检测的学习,本篇我们来尝试完成对银行卡号的检测识别:

目标,识别出下面银行卡的卡号:

在这里插入图片描述

识别主要流程:

  1. 得到每个数字的信息,为卡号的模板匹配做准备
  2. 定位到银行卡上卡号的位置
  3. 遍历卡号的每个数字,进行模板匹配

详细流程

一、设置参数

import numpy as np
import argparse #python内置库不太熟,自行学习
import cv2
import myutils
"""
-i card1.png
-t kahao.png
"""
ap = argparse.ArgumentParser()
ap.add_argument("-i","--image",required=True,
                help="path to input image")
ap.add_argument("-t","--template", required=True,
                help="path to template 0CR-A image")
args = vars(ap.parse_args())# vars()是Python中的一个内置函数,用于返回对象的属性和值的字典。# 指定信用卡类型
FIRST_NUMBER ={"3":"American Express",
               "4":"Visa",
               "5": "MasterCard",
               "6":"Discover Card"}

二、函数准备

  1. 图像展示
def cv_show(name,img):# 绘图展示
    cv2.imshow(name,img)
    cv2.waitKey(0)
  1. 排序
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=='top-to-bottom' or method=='bottom-to-top':
        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))#zip(*...)使用星号操作符解包排序后的元组列表,并将其重新组合成两个列表:一个包含所有轮廓,另一个包含所有边界框。
    return cnts,boundingBoxes
  1. 调整大小
def resize(image,width=None,height=None ,inter=cv2.INTER_AREA):
    dim=None
    (h,w)=image.shape[:2]
    if width is None and height is None:
        return image
    if width is None:
        r=height/float(h)
        dim=(int(w*r),height)
    else:
        r=width/float(w)
        dim=(width,int(h*r))
    resized=cv2.resize(image,dim,interpolation=inter)#默认为cV2.INTER_AREA,即面积插值,适用于缩放图像。
    return resized

三、具体步骤

1. 得到每个数字的信息

在这里插入图片描述

将以上图片中每个数字的信息都取出,等待进行模板匹配:

img = cv2.imread(args["template"])
cv_show('img',img)

ref =cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)# 灰度图
cv_show('ref', ref)
ref =cv2.threshold(ref,10,255,cv2.THRESH_BINARY_INV)[1] # 二值图像
cv_show('ref',ref)

# 计算轮廓:cv2.findcontours()函数接受的参数为二值图,即黑白的(不是灰度图)
# cv2.RETR_EXTERNAL只检测外轮廓,cv2.CHAIN_APPROX_SIMPLE只保留终点坐标
_,refCnts, hierarchy = cv2.findContours(ref.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img,refCnts,-1,(0,0,255),3)
cv_show('img',img)

refCnts = myutils.sort_contours(refCnts,method="left-to-right")[0] # 排序,从左到右,从上到下
digits = {} # 保存模板中每个数字对应的像素值
for (i,c) in enumerate(refCnts): # 遍历每一个轮廓
    (x,y,w,h)=cv2.boundingRect(c) #计算外接矩形并且resize成合适大小
    roi = ref[y:y + h,x:x + w] # 从二值图上截取区域图
    roi=cv2.resize(roi,(57,88))#缩放到指定的大小
    digits[i]= roi # 每一个数字对应每一个模板
print(digits)
-----------------举例输出:数字0对应它的像素信息
{0: array([[0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       ...,
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0]], dtype=uint8)}

2. 银行卡处理

对银行卡进行顶帽处理,突出比周围区域更亮的区域。

image = cv2.imread(args["image"])
cv_show('image',image)
image = myutils.resize(image,width=300)
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
cv_show('gray',gray)

# cv2.getStructuringElement()获取结构原件
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
# cv2.MORPH_TOPHAT它通过从原始图像中减去其开运算结果来实现,这样可以突出比周围区域更亮的区域。
tophat = cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,rectKernel)
cv_show('tophat',tophat)

3. 找到数字边框

目标效果:

在这里插入图片描述

通过闭操作将银行卡的信息都连接在一起,这样就可以得到一块块轮廓的区域:

# 通过闭操作(先膨胀后腐蚀)将数字连在一起
closeX = cv2.morphologyEx(tophat,cv2.MORPH_CLOSE,rectKernel)
cv_show('gradX',closeX)

# 二值化
# cv2.THRESH_OTSU会自动寻找合适的阈值,适合双峰,需要把阈值参数设置成0
thresh = cv2.threshold(closeX,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv_show('thresh',thresh)

# 再来一个闭操作
thresh = cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,sqKernel)
cv_show('thresh',thresh)

# 计算轮廓
t_,threshCnts,h = cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = threshCnts
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))

4. 模板匹配

遍历每一个符合的轮廓中的每一个数字,明明是一张图片,如何遍历数字呢?

在轮廓中,截取每一个数字所在的区域,将其同之前得到的digits字典对应的元素进行模板匹配,计算匹配得分,从而得到对应的数字。

# 将符合的轮廓,从左到右排序
locs = sorted(locs,key=lambda x:x[0])
output = []
# 遍历每一个轮廓中的数字
for (i,(gX,gY,gW,gH)) in enumerate(locs):# enumerate()返回序列中元素的索引(从0开始)和元素本身
    groupOutput = []
    group = gray[gY - 5:gY + gH + 5,gX - 5:gX + gW + 5] # 适当加一点边界
    cv_show('group',group)

    # 预处理
    group = cv2.threshold(group,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
    cv_show('group',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)
            (_,score,_,_) = cv2.minMaxLoc(result)
            scores.append(score)
        # 得到最合适的数字
        groupOutput.append(str(np.argmax(scores)))

     # 画出来
    cv2.rectangle(image,(gX - 5,gY - 5),(gX + gY + 5,gY + gH + 5),(0,0,255),1)

    # cv2.putText()是OpenCV库中的一个函数,用于图像上添加文本
    cv2.putText(image,"".join(groupOutput),(gX,gY - 15),cv2.FONT_HERSHEY_SIMPLEX,0.65,(0,0,255),2)

    # 得到结果  将一个列表的元素添加到另一个列表的末尾
    output.extend(groupOutput)
    
print("Credit Card Type:{}".format(FIRST_NUMBER[output[0]]))
print("Creadit Card #:{}".format("".join(output)))
cv2.imshow("Image",image)
cv2.waitKey(0)
---------------------
Credit Card Type:Visa
Creadit Card #:4020340002345678

在这里插入图片描述

这样我们就识别出了一个银行卡的卡号。

总结

本篇介绍了:

检测识别银行卡卡号的完整流程。

  1. 得到每个数字的信息,为卡号的模板匹配做准备
  2. 定位到银行卡上卡号的位置
  3. 遍历卡号的每个数字,进行模板匹配

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

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

相关文章

获取时间,并将时间按一定的格式输出

一、时间函数 1.获取秒数 CTS 北京时间 2.转换为需要个格式 系统时间的获取: 1.time 获得秒数 time_t time(time_t *t); time_t 类型变量 第一种 准备一个变量 time_t tm; time(&tm) 第二种 tm time(NULL); 功能: 获得1970年到现在的秒数 第一步&#xff0c;先获得秒…

OpenHarmony鸿蒙( Beta5.0)RTSPServer实现播放视频详解

鸿蒙开发往期必看&#xff1a; 一分钟了解”纯血版&#xff01;鸿蒙HarmonyOS Next应用开发&#xff01; “非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线&#xff01;&#xff08;从零基础入门到精通&#xff09; “一杯冰美式的时间” 了解鸿蒙HarmonyOS Next应用开发路…

JavaScript基础语法(超详细!)

为什么学JS&#xff1f; 1.页面动态效果 2.表单验证 可以包含在文档中的任何地方&#xff0c;只要保证这些代码在被使用前已读取并加载到内存即可 <script>… </script>网页中引用JavaScript的方式&#xff1a; 1.使用<script>标签外部JS文件 <scrip…

层归一化(201607)

Layer Normalization 层归一化 https://arxiv.org/abs/1607.06450 Abstract Training state-of-the-art, deep neural networks is computationally expensive. One way to reduce the training time is to normalize the activities of the neurons. A recently introduced…

gdb 前端:kdbg 安装使用

文章目录 1. 前言2. kdbg 安装使用2.1 安装 kdbg2.2 使用 kdbg 1. 前言 限于作者能力水平&#xff0c;本文可能存在谬误&#xff0c;因此而给读者带来的损失&#xff0c;作者不做任何承诺。 2. kdbg 安装使用 2.1 安装 kdbg kdbg 是 gdb 的图形化界面的前端&#xff0c;在 …

2018年系统架构师案例分析试题五

目录 案例 【题目】 【问题 1】(7 分) 【问题 2】(12 分) 【问题 3】(6 分) 【答案】 【问题 1】解析 【问题 2】解析 【问题 3】解析 相关推荐 案例 阅读以下关于 Web 系统设计的叙述&#xff0c;在答题纸上回答问题 1 至问题 3。 【题目】 某银行拟将以分行为主体…

多卡微调智谱glm-4-9b-chat

1 什么是微调&#xff1a; 大模型微调&#xff08;Fine-tuning of large models&#xff09;是一种通过对已经训练好的大规模预训练模型进行进一步训练的技术&#xff0c;以便让模型在特定任务或特定领域上表现得更好。微调通常是在已经有了一个通用的、经过大规模数据训练的基…

恐怖类游戏智能体————恐怖探险家

智能体名称&#xff1a;恐怖探险家 链接&#xff1a;文心智能体平台AgentBuilder | 想象即现实 (baidu.com)https://agents.baidu.com/center/agent/preview/MFhBvA0K9EXXVdjHCcUumadWmWesKvw2 角色与目标设定 &#x1f9d1;&#x1f3fb; 角色&#xff1a;恐怖探险家是一位…

2.快速部署一个Kubernetes集群

&#x1f482; 个人主页: Java程序鱼 &#x1f4ac; 如果文章对你有帮助&#xff0c;欢迎关注、点赞、收藏(一键三连)和订阅专栏 &#x1f464; 微信号&#xff1a;hzy1014211086&#xff0c;想加入技术交流群的小伙伴可以加我好友&#xff0c;群里会分享学习资料、学习方法…

Unity人工智能开发学习心得

在Unity中进行人工智能研究与应用主要集中在几个关键领域&#xff0c;包括使用Unity ML-Agents插件进行强化学习、利用神经网络技术和深度学习技术训练AI&#xff0c;以及基于行为树技术设计游戏人工智能。 ‌使用Unity ML-Agents插件进行强化学习‌&#xff1a;Unity ML-Agent…

网络安全 DVWA通关指南 DVWA Reflected Cross Site Scripting (反射型 XSS)

DVWA Reflected Cross Site Scripting (反射型 XSS) 文章目录 DVWA Reflected Cross Site Scripting (反射型 XSS)XSS跨站原理反射型 LowMediumHighImpossible 参考文献 WEB 安全靶场通关指南 XSS跨站原理 当应用程序发送给浏览器的页面中包含用户提交的数据&#xff0c;但没有…

Linux进阶命令-echodatealias

作者介绍&#xff1a;简历上没有一个精通的运维工程师。希望大家多多关注作者&#xff0c;下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 经过上一章Linux日志的讲解&#xff0c;我们对Linux系统自带的日志服务已经有了一些了解。我们接下来将讲解一些进阶命令&am…

自然语言处理系列六十九》搜索引擎项目实战》搜索框架技术选型

注&#xff1a;此文章内容均节选自充电了么创始人&#xff0c;CEO兼CTO陈敬雷老师的新书《自然语言处理原理与实战》&#xff08;人工智能科学与技术丛书&#xff09;【陈敬雷编著】【清华大学出版社】 文章目录 自然语言处理系列六十九搜索引擎项目实战》搜索框架技术选型搜索…

大模型结合知识库问答应用第一次实践

大模型结合知识库问答应用第一次实践 这份完整版的大模型 AI 学习资料已经上传CSDN&#xff0c;朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】 记录一次用大模型LLM和向量数据库&#xff0c;搭建垂直领域的知识库问答实践。上文已经介绍了文本如…

第151天:红队APT-钓鱼篇邮件钓鱼SPF绕过自建邮件系统SwaksGophish

案例一&#xff1a;邮件钓鱼-前置知识 现在很多大型网站的邮件服务器已经做的很安全了&#xff0c;文中的很多方法感觉已经不适用&#xff0c;学习思路遇到公司自己搭建的邮件服务器可以尝试把 SPF 发件人策略框架&#xff08; Sender Policy Framework &#xff09;电子邮件认…

移植案例与原理 - utils子系统之file文件操作部件

往期知识点记录&#xff1a; 往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 startup子系统之syspara_lite系统属性部件 &#xff08;1&#xff09; startup子系统之syspara_lite系统属性部件 &#xff…

基于ssm+vue+uniapp的电影交流平台小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…

海康IPC摄像头通过国标28181方式接入带域名的视频监控接入平台,视频通道无法上传到视频监控平台,导致无法获取视频资源的问题解决

目录 一、问题背景 二、域名介绍 1、域名详解 2、域名与IP的区别 三、解决过程 1、检查设备能力 2、升级摄像头的版本 3、通过域名进行连接 4、在视频监控平台观察接入情况 四、解决结果 一、问题背景 视频监控接入平台部署在内网环境&#xff0c;摄像头在公网或在另一个局…

【Linux C | 终端设备】Linux下 tty、ttyS*、ttyAMA*、console 的区别,以及系统输出重定向(附带代码)

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 2024-09-11 …

QT实现TCP/UDP通信

服务器端&#xff1a; 客户端&#xff1a; 服务器&#xff1a; widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTcpServer> #include <QTcpSocket> #include <QList> #include <QMessageBox> #include <QDebug&…