目录

信用卡数字识别系统:前言与代码解析

前言

项目代码

​​​​​​结果演示

代码模块解析

1. 参数解析模块

2. 轮廓排序函数

3. 图像预处理模块

4. 输入图像处理流程

5. 卡号区域定位

6. 数字识别与输出

系统优势


信用卡数字识别系统:前言与代码解析

前言

信用卡数字识别是金融自动化处理的核心技术之一,通过计算机视觉技术自动提取卡面信息,可应用于支付验证、身份认证等场景。本系统基于模板匹配和图像处理技术,实现对信用卡卡号的自动识别。系统通过预处理、轮廓检测和特征匹配三个关键阶段,准确识别信用卡上的16位数字,并自动判断发卡机构(Visa/MasterCard等)。以下将详细解析代码各模块功能。


项目代码

import argparse
import imutils
import numpy as np
import myutils
from imutils import contours
import cv2# 设置参数结果
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,help="path to input image containing credit card")
ap.add_argument("-t", "--template", required=True,help="path to input template image")
args = vars(ap.parse_args())# 指定信用卡类型
FIRST_NUMBER = {"3": "American Express","4": "Visa","5": "MasterCard","6": "Discover Card"
}def sort_contours(cnts, method="left-to-right"):reverse = Falsei = 0if method == "right-to-left" or method == "bottom-to-top":reverse = Trueif method == "top-to-bottom" or method == "bottom-to-top":i = 1boundingBoxes = [cv2.boundingRect(c) for c in cnts]  # 用一个最小的矩形,把找到的形状包起来x,y,h,w(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),key=lambda b: b[1][i], reverse=reverse))return cnts, boundingBoxesdef 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 imageif 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)return resized# 绘图展示
def cv_show(name,img):cv2.imshow(name,img)cv2.waitKey(0)cv2.destroyAllWindows()return None# 读取一个模板
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)# 计算轮廓果
ref_,refCnts = cv2.findContours(ref.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img,ref_,-1,(0,0,255),3)
cv_show("img",img)
print(np.array(refCnts).shape)
refCnts =sort_contours(ref_, method="left-to-right")[0]
digits = {}# 遍历模板轮廓
for (i,c) in enumerate(refCnts):(x,y,w,h) = cv2.boundingRect(c)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))
squareKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))# 读取输入图像、预处理
image = cv2.imread(args["image"])
cv_show("image",image)
image = resize(image,width=300)
gary= cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
cv_show("gary",gary)# 礼帽操作,突出更明亮的区域
tophat = cv2.morphologyEx(gary,cv2.MORPH_TOPHAT,rectKernel)
cv_show("tophat",tophat)
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")
print(np.array(gradx).shape)
cv_show("gradx",gradx)# 通过闭操作(先膨胀,再腐蚀)将数字连在一起
gradx = cv2.morphologyEx(gradx,cv2.MORPH_CLOSE,rectKernel)
cv_show("gradx",gradx)
# THRESH_OTSU会自动寻找全局阈值,适合双峰,需要把阈值参数设置为0
thresh = cv2.threshold(gradx,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv_show("thresh",thresh)# 再来一个闭操作
thresh = cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,squareKernel)
cv_show("thresh",thresh)# 计算轮廓
thresh_,threshCnts = cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = thresh_
cur_img=image.copy()
cv2.drawContours(cur_img,cnts,-1,(0,0,255),3)
cv_show("cur_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))
# 将符合条件的轮廓从左到右排序
locs = sorted(locs,key=lambda x:x[0])
output=[]
# 遍历每一个轮廓中的数字
for (i,(gx,gy,gw,gh)) in enumerate(locs):# initialzie the list of group digitsgroupOutput = []# 根据坐标提取数字的区域group = gary[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_,groupCnts = cv2.findContours(group.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)group_ = contours.sort_contours(group_,method="left-to-right")[0]# 计算每一个组中的数字for c in group_:(x,y,w,h) = cv2.boundingRect(c)digit = group[y:y+h,x:x+w]digit = cv2.resize(digit,(57,88))cv_show("digit",digit)# 计算匹配得分scores = []# 在模板中计算每一个得分for (digitt,digitTempl) in digits.items():result = cv2.matchTemplate(digit,digitTempl,cv2.TM_CCOEFF)(_,score,_,_) = cv2.minMaxLoc(result)scores.append(score)# 获得匹配得分最适合的数字groupOutput.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(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("Credit Card #: {}".format("".join(output)))
cv2.imshow("Image", image)
cv2.waitKey(0)

注意事项:

由于作者用于较新的PyCharm版本是2024版本,它与传统的PyCharm有区分,而且作者在学习过程中同样发现一些问题,这个代码前面可以不用写排序,而最新版本里面不知什么原因调用接口时候报错说没有这个模块函数,于是作者只能将排序等需要的模块分开出来,写入项目中。

​​​​​​结果演示

代码模块解析

1. 参数解析模块
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="输入信用卡图像路径")
ap.add_argument("-t", "--template", required=True, help="模板图像路径")
args = vars(ap.parse_args())
  • 功能:通过命令行参数接收输入图像和模板图像路径
  • 参数说明
    • -i/--image:待识别的信用卡图像
    • -t/--template:数字模板图像(包含0-9标准数字)

PyCharm2024通过argparse模块操作命令行设置方法如下,接下来的步骤是中文展示,作者PyCharm已经汉化,若未汉化也可记作者选择按钮的位置点击:

第一步:将需要的图片存放在本人知道的文件路径

原图片如下:

模板图片如下:

我存放的路径如下:

第二步:右击项目代码,选择“更多运行/调试”后,在选择下拉列表中的“修改运行配置”

第三步:在新打开的对话框选择“运行”栏下最后一行点击“展开”

第四步:输入之前存放模板和原图片的路径

注:由于作者存放图片和模板与项目同一个文件夹目录下,因此可以省略具体的路径,若用户存放不在同一个文件夹目录下,那么需要你加上如下格式:

--image

盘符:\文件夹1名称\文件夹2名称\.....\图片名称和后缀名(.png,.jpg等等)

--template

盘符:\文件夹1名称\文件夹2名称\.....\图片名称和后缀名(.png,.jpg等等)

2. 轮廓排序函数
def sort_contours(cnts, method="left-to-right"):reverse = Falsei = 0if method == "right-to-left" or method == "bottom-to-top":reverse = Trueif method == "top-to-bottom" or method == "bottom-to-top":i = 1boundingBoxes = [cv2.boundingRect(c) for c in cnts]  # 用一个最小的矩形,把找到的形状包起来x,y,h,w(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),key=lambda b: b[1][i], reverse=reverse))return cnts, boundingBoxes

  • 功能:对检测到的轮廓按空间位置排序
  • 排序逻辑
    • 计算每个轮廓的边界框 (x,y,w,h)
    • method参数选择排序基准(X轴或Y轴坐标)
    • 支持四种排序方向:左→右、右→左、上→下、下→上
3. 图像预处理模块
# 模板预处理流程
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 灰度化
ref = cv2.threshold(ref,10,255,cv2.THRESH_BINARY_INV)[1]  # 二值化反转

  • 关键操作
    • 灰度转换:将RGB图像转为单通道灰度图
    • 二值化:通过阈值处理突出数字区域
    • 轮廓提取findContours定位每个数字的独立轮廓
    • 模板存储:将0-9数字按索引存入字典digits
4. 输入图像处理流程
# 核心处理链
image = resize(image, width=300)  # 尺寸标准化
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  # 灰度化
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)  # 顶帽运算
gradx = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0)  # Sobel边缘检测
gradx = cv2.morphologyEx(gradx, cv2.MORPH_CLOSE, rectKernel)  # 闭运算

  • 处理阶段
    1. 尺寸归一化:固定宽度为300像素,保持比例
    2. 顶帽运算:突出亮色区域(信用卡数字通常为亮色)
    3. Sobel算子:检测垂直边缘(数字的竖直笔画)
    4. 形态学闭操作:连接数字笔画形成连续区域
5. 卡号区域定位
# 数字区域筛选
for (i,c) in enumerate(cnts):(x,y,w,h) = cv2.boundingRect(c)ar = w / float(h)  # 宽高比if 2.5 < ar < 4.0 and 40<w<55 and 10<h<20:locs.append((x,y,w,h))  # 保存候选区域

  • 筛选条件
    • 宽高比 $2.5 < \frac{w}{h} < 4.0$(信用卡数字的典型比例)
    • 宽度 $40 < w < 55$ 像素
    • 高度 $10 < h < 20$ 像素
  • 结果:获得4组数字区域的坐标 locs
6. 数字识别与输出
# 模板匹配识别
for c in group_:digit = cv2.resize(roi, (57,88))  # 标准化尺寸scores = []for digitTempl in digits.values():score = cv2.matchTemplate(digit, digitTempl, cv2.TM_CCOEFF)scores.append(score)  # 存储匹配得分groupOutput.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(groupOutput), (gx,gy-15), cv2.FONT_HERSHEY_SIMPLEX, ...)
# 得到结果
output.extend(groupOutput)
# 打印结果
print("Credit Card Type: {}".format(FIRST_NUMBER[output[0]]))
print("Credit Card #: {}".format("".join(output)))
cv2.imshow("Image", image)
cv2.waitKey(0)

  • 识别流程
    1. 截取单个数字区域并缩放至模板尺寸
    2. 与0-9模板进行相似度匹配(TM_CCOEFF相关系数法)
    3. 选择最高匹配得分对应的数字
  • 输出形式
    • 红色矩形框标记数字组区域
    • 在区域上方显示识别出的4位数字

系统优势

  1. 形态学操作链:通过顶帽、闭操作等组合优化数字区域提取
  2. 动态模板匹配:适应不同字体和尺寸的数字
  3. 空间约束:利用宽高比和尺寸过滤误检区域
  4. 实时可视化:各阶段结果可实时显示便于调试

该系统实现了从原始图像到卡号识别的完整流程,准确率依赖模板质量和图像清晰度,可通过优化预处理参数进一步提升性能。

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Adobe AI高效设计秘籍与创新思维进阶

开篇&#xff1a;十年设计征途&#xff0c;Adobe赋能创意飞翔 作为一名在设计领域耕耘十年的旅居职业设计师&#xff0c;我得益于英国帕维斯经济与音乐学院&#xff08;Parvis School of Economics and Music&#xff09;提供的Adobe正版教育订阅&#xff0c;得以持续探索技术…

vc formal实例

命令&#xff1a; module load gui 方式启动命令&#xff0c; 看一下cc_pinmux.tcl 里面有什么&#xff1a; 工具feature 的设置&#xff0c;不太懂 对特定模块做blackbox, library file, 一般是工具无法识别的模块&#xff0c;例如 IO lib,memory lib,analog lib, 内部有 …

JavaScript取值get的json/url/普通对象参考

dstore.on(datachanged,function(dstore){ for(i0;i<dstore.getCount();i){ var a dstore.getAt(i); var imp_infoa.get(imp_info); 上面这段JS代码&#xff0c;imp_info取到的是一长串KEY和VALUE组成的内容&#xff0c;我怎样可以准确获取其中一…

【C++】侦测按键事件

侦测按键事件可以用C的conio.h头文件&#xff0c;用到的函数&#xff1a; _CRTIMP int __cdecl _getch(void); 输入以下代码&#xff1a; #include <iostream> #include <conio.h> using namespace std;int main() {char key;while (true) {cout << "…

Coremail受邀亮相华为开发者大会

6月20-22日&#xff0c;为期三天的HDC.2025华为开发者大会在东莞举行&#xff0c;全球超过1.2万名开发者汇聚现场&#xff0c;聚焦鸿蒙生态、AI技术及产业合作。Coremail作为鸿蒙生态的核心伙伴和深度参与者受邀出席&#xff0c;并获得“智慧办公最佳产品合作伙伴”奖项。 HDC.…

视频断点续播全栈实现:基于HTML5前端与Spring Boot后端

文章目录 视频断点续播功能实现方案核心思路前端实现HTML结构JavaScript实现Spring Boot后端实现1.依赖配置(pom.xml)2.实体类3.存储库接口4.服务层5. 控制器实现要点视频断点续播功能构思图流程说明用户交互:前端核心功能:后端处理:数据存储:🌐 我的个人网站:乐乐主题创…

华为设备 QoS 流分类与流标记深度解析及实验脚本

一、引言 在复杂网络环境中&#xff0c;不同业务对网络质量需求各异。语音通话要求低时延、视频直播依赖高带宽、普通文件传输对丢包容忍度相对较高 。QoS&#xff08;Quality of Service&#xff0c;服务质量&#xff09;技术通过流分类、流标记等手段&#xff0c;为不同业务…

[论文阅读] 人工智能 + 软件工程 | 从软件工程视角看大语言模型:挑战与未来之路

从软件工程视角看大语言模型&#xff1a;挑战与未来之路 论文标题&#xff1a;Software Engineering for Large Language Models: Research Status, Challenges and the Road Ahead arXiv:2506.23762 Software Engineering for Large Language Models: Research Status, Chall…

【Docker基础】Docker容器管理:docker rm及其参数详解

目录 1 Docker容器生命周期概述 2 docker rm命令基础 2.1 命令基本语法 2.2 命令功能说明 2.3 基本使用示例 3 docker rm参数详解 3.1 -f, --force 3.2 -v, --volumes 3.3 -l, --link 3.4 --time 4 docker rm高级用法 4.1 批量删除容器 4.1.1 删除所有已停止的容器…

鸿蒙进阶——Mindspore Lite AI框架源码解读之模型加载详解(五)

文章大纲 引言一、LiteSession::CompileGraph(Model *model)二、LiteSession::CompileGraph(Model *model) 核心流程1、MindirModel::ConvertTensors1.1、遍历并执行MindirModel::ConvertTensor1.1.1、MindirModel::LoadTensorData 三、LiteSession::InitGraphInputTensors(mod…

WireShark网络取证分析第一集到第五集和dvwa靶场环境分析漏洞

文章目录 一、WireShark网络取证是什么?二、WireShark网络取证1.WireShark网络取证分析第一集Ann的即时通讯好友叫什么名字?在捕获的即时通讯对话中第一条评论是什么?Ann传输的文件叫什么名字?您想提取的文件的魔数是什么(前四个字节)?文件的MD5sum是多少?什么是秘密配方…

【51单片机按下按键1,8位共阴极数码管输出2022-606。按下按键2,8位共阴极数码管输出606-1132。】2022-6-10

缘由单片极的共阴极数码管按下按键1和按键2输出的内容-编程语言-CSDN问答 #include "REG52.h" unsigned char code smgduan[]{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0,64}; //共阴0~F消隐减号 unsigned char Js0, miao…

HDMI转12G- SDI GS12170+GS12281-富利威方案设计及技术支持

GS12281 是一款低功耗、多速率、重定时电缆驱动器&#xff0c;支持高达 12G UHD-SDI 的速率。它设计用于接收 100Ω 差分输入信号&#xff0c;自动从数字视频信号中恢复嵌入式时钟并重新定时输入数据&#xff0c;并通过 75Ω 同轴电缆传输重新定时的信号。 100Ω 走线输入支持…

自然语言处理:NLP入门

本文目录&#xff1a; 一、概念二、发展史三、核心任务和技术特别分享1&#xff1a;当前挑战和前沿方向特别分享2&#xff1a;大神名言启示 前言&#xff1a;从本章开始讲解自然语言处理&#xff08;NLP&#xff09;&#xff0c;今天先入个门~ 一、概念 自然语言处理&#xff…

用Fiddler中文版抓包工具掌控微服务架构中的接口调试:联合Postman与Charles的高效实践

随着微服务架构在项目中的广泛应用&#xff0c;系统被拆分成多个独立的服务&#xff0c;彼此通过API通信。虽然架构带来了灵活性&#xff0c;但也大幅增加了接口数量和调用链复杂度&#xff1a;一次用户操作可能触发跨多个服务的调用&#xff0c;导致前端调试难度飙升。要精准排…

MongoDB 更新文档指南

MongoDB 更新文档指南 引言 MongoDB 是一款高性能、可扩展的文档存储系统&#xff0c;它为存储和管理大量数据提供了强大的支持。在 MongoDB 中&#xff0c;更新文档是常见操作之一&#xff0c;它允许用户修改现有文档的内容。本文将详细讲解 MongoDB 中更新文档的各种方法&a…

Cursor + Serena MCP集成,更好的解析项目架构

项目地址&#xff0c;下到本地。 Serena可以更好的理解项目的架构并总结&#xff0c;而不是简单的阅读代码文件&#xff0c;可以直接用Cursor结合MCP的方式进行使用。&#xff1a;Serena 的语义代码分析功能建立在语言服务器上&#xff0c;使用广泛实施的语言服务器协议&#x…

【Python】numpy数组常用数据处理(测试代码+api例程)

目录 一、数列生成1.按照间隔生成数列&#xff08;np.array[]&#xff09;2.按照数列数字个数生成数列&#xff08;np.linspace&#xff09; 二、数列增删改查1.1 数组末尾添加数据&#xff08;np.append&#xff09;1.2 数组指定索引位置添加数据&#xff08;np.insert&#x…

CMU-15445(6)——PROJECT#2-BPlusTree-Task#1

PROJECT#2-BTree 在 PROJECT#2 中&#xff0c;我们需要实现一个B plus Tree&#xff0c;用过 MySQL 的同学肯定对它不陌生&#xff0c;BTree是实现高效数据检索的核心组件&#xff0c;其内部节点的作用是引导搜索过程&#xff0c;而实际的数据项则存于叶子节点中。该索引结构能…

向量数据库搜索原理解密:从暴力扫描到近似最近邻的演进之路

摘要 向量数据库已成为处理AI时代海量非结构化数据的核心基础设施。本文深入解析向量搜索的六大核心技术原理,涵盖暴力扫描、树结构索引、量化压缩、图导航算法等核心机制,通过10张架构图解与数学公式推导,揭示千万级向量毫秒级检索背后的工程奇迹。全文超5000字,包含Fais…