Opencv实现提取卡号(数字识别)

news2024/9/21 22:45:51

直接开始

实行方法

  1. 解析命令行参数:使用argparse库来解析命令行输入,确保用户提供了输入图像和模板图像的路径。

  2. 读取模板图像:使用cv2.imread()函数读取模板图像的路径,并显示原始图像。

  3. 图像预处理

    • 将图像转换为灰度图,以简化后续处理。
    • 应用二值化操作(使用阈值10)将图像转换为二值图像(黑白图),并通过cv2.THRESH_BINARY_INV反转颜色,使前景(数字)为白色,背景为黑色。
    • 显示预处理后的二值图像。
  4. 轮廓检测

    • 使用cv2.findContours()函数在二值图像上检测轮廓。这里只检测外部轮廓,并使用cv2.CHAIN_APPROX_SIMPLE方法来简化轮廓形状。
    • 在原始图像上绘制检测到的轮廓,并显示结果。
  5. 轮廓排序

    • 使用自定义的myutils.sort_contours()函数对检测到的轮廓进行排序,这里假设该函数按照从左到右的顺序排序轮廓。

自定义的myutils库

import cv2


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))
    return cnts, boundingBoxes


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. 数字模板提取

    • 遍历排序后的轮廓,对每个轮廓计算其外接矩形,并裁剪出相应的区域(ROI,Region of Interest)。
    • 将每个裁剪出的ROI区域缩放到固定大小(57x88),以便于后续与输入图像中的数字进行匹配。
    • 将每个缩放后的ROI存储到digits字典中,其中键为轮廓的索引,值为对应的数字模板图像。

接下来,你可能会想要使用这些数字模板与输入图像中的数字进行匹配,以确定输入图像中每个数字的具体值。这通常涉及到模板匹配技术,如使用cv2.matchTemplate()函数。

  • 读取输入图像。
  • 对输入图像进行类似的预处理步骤。
  • 在输入图像上检测可能的数字区域。
  • 对每个检测到的数字区域,使用提取的模板进行匹配,以确定其值。
  • 根据识别出的数字进行进一步的处理或分析(如确定信用卡类型等)。
import argparse
import cv2
import myutils

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 OCR-A image")
args = vars(ap.parse_args())

#创建ArgumentParser对象来解析命令行参数。
#添加两个必需的参数:-i/--image(输入图像路径)和-t/--template(模板图像路径)。
#使用parse_args()解析命令行输入,并将结果转换为字典存储在args中。

FIRST_NUMBER = {
    "3": "American Express",
    "4": "Visa",
    "5": "MasterCard",
    "6": "Discover Card"
}
#定义一个字典,将信用卡号码的首位数字映射到对应的信用卡类型。

def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
#一个简单的函数,用于在窗口中显示图像,并等待用户按键。

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)

#使用findContours函数检测二值图像中的轮廓。
#在原始图像上绘制检测到的轮廓。
#假设myutils.sort_contours函数存在,并按从左到右的顺序对轮廓进行排序。注意这里[0]可能是为了处理#sort_contours返回值的格式,具体取决于该函数的实现。
#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  # 每一个数字对应每一个模板
#遍历排序后的轮廓。
#对每个轮廓,计算其外接矩形,并裁剪出相应的区域(ROI)。
#将每个ROI缩放到固定大小(57x88)。
#将缩放后的ROI存储在digits字典中,键为轮廓的索引

代码效果:

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

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

相关文章

ARM——结构体系(处理器工作模式,CPSR,立即数,汇编语言函数调用)

1、处理器工作模式 ARM有7个基本工作模式: User:非特权模式,大部分任务执行在这种模式FIQ:当一个高优先级(fast)中断产生时将会进入这种模式 IRQ:当一个低优先级(normal)中断产生时将会进入这种模式 Supervisor:当复位或软中断指令执行时将会进入这种模式 Abort:当存…

CAN总线数据帧的帧结构

CAN总线中的信息是以固定格式的“帧”发送的,当总线为空闲时,任何已连接的节点都可以开始发送一个新的“帧”。 在一个CAN系统中,数据在节点之间的发送和接收主要通过四种不同类型的“帧”来执行和控制。这四种类型分别是数据帧、远程帧、错…

探索ArrayList的线程不安全性

文章目录 概要示例代码原因解决用 synchronized 保证安全添加元素其他方法 总结 概要 要测试ArrayList的线程不安全性,可以创建多个线程同时对 ArrayList 进行修改操作(如添加、删除元素),并观察是否会引发异常或数据不一致的问题…

Typescript实现react-redux的useSelector和useDispatch的状态定义

背景:react中使用typescript,在引入redux之后很多状态定义有问题,记录下来(文章记录学习react-redux过程中的踩坑)。 1.useSelector时,state语法报错,类型为unknown,如下图 我的store状态设置的很简单&am…

Luminar Neo for Mac智能图像处理软件【操作简单,轻松上手】

Mac分享吧 文章目录 效果一、下载软件二、开始安装1、双击运行软件,将其从左侧拖入右侧文件夹中,等待安装完毕2、应用程序显示软件图标,表示安装成功 三、运行测试安装完成!!! 效果 一、下载软件 下载软件…

【机器学习】LSTM(长短期记忆网络)详解

🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 ​💫个人格言: "如无必要,勿增实体" 文章目录 LSTM(长短期记忆网络)详解LSTM的基本思想LSTM的前向传播过程LSTM在实际任务中的…

mysql高级知识之集群

一、安装 源码编译MySQL,若需要MySQLtar包可私信我 #创建数据目录 mkdir /data/mysql -p#安装相关依赖 yum install libtirpc-devel-0.2.4-0.16.el7.x86_64.rpm yum install cmake gcc-c++ openssl-devel ncurses-devel.x86_64 libtirpc-devel-1.3.3-8.el9_4.x86_64.rpm rpcgen…

C++入门day3-面向对象编程(中)

前言:C入门day2-面向对象编程(上)-CSDN博客 运算符重载 我们接触过函数重载,就是同名的函数有不同的功能。那么运算符重载,顾名思义也是赋予运算符其他的功能。在这里,我个人以为,运算符就是特…

C/C++语言基础--函数基础(函数定义、调用、生命周期、递归)

本专栏目的 更新C/C的基础语法,包括C的一些新特性 前言 函数是语言的基本组成部分,也是面向对象编程的基石,他体现了封装的思想,代码的复用的功能。欢迎点赞 收藏 关注,本人将会持续更新 文章目录 函数什么是函数&am…

彩漩科技亮相第一届人工智能教育应用论坛,荣获AI教育科技产品TOP30奖项

近日,由中国教育发展战略学会人工智能与机器人教育专业委员会指导,北京教育信息化产业联盟主办的第一届人工智能教育应用论坛暨 AI 教育科技成果展在北京隆重举办。本次活动以“ AI 强校大时代 —— 用新质生产力打造金钥匙强校”为主题,汇聚…

vector 常见函数

目录 一.vector 构造函数 二 . Iterators 迭代器(random access iterator) 三.Capacity: 空间 3.1 resize 3.2 reserve 四.Element access: 元素访问 方式 4.1 operator[] 类似于数组的 [] 4.2 front 和back 五.Modifiers: 六.vector 的 二…

数据结构(单向链表)

单向链表代码 #ifndef _LINK_H_#define _LINK_H_typedef int DataType;typedef struct node {DataType data;struct node *pnext; }Link_Node_t;typedef struct link {Link_Node_t *phead;int clen; }Link_t;extern Link_t *link_creat(); extern int push_link_head(Link_t *…

智慧公厕技术应用、系统架构、应用功能有哪些?@卓振思众

智慧公厕的标准涵盖了多个方面,包括技术应用、系统架构、应用功能以及环保节能等。以下是【卓振思众】整理的一些标准要点: 技术应用‌物联网技术‌:通过无线传感器、监控设备等实时采集公厕内部环境数据。‌大数据与云计算‌:对数…

2157. 优秀的拆分(power)

代码 #include<bits/stdc.h> using namespace std; int a[10001]; int main() {int n,t1,k0;bool flagfalse;cin>>n;if(n%21) {cout<<-1;return 0;}while(n>0){if(n%21){k;a[k]t; }nn/2;tt*2;}if(k>1) {flagtrue;for(int ik;i>1;i--)cout<&l…

lit-llama代码解析

https://github.com/Lightning-AI/lit-llama/blob/main/README.md 下载的时候会报错误&#xff0c;因为网不行&#xff0c;一种方法就是多次尝试&#xff0c;另一种方法是终端连上代理下载 pycharm连接hugging face等网站_hugging face怎么连接-CSDN博客 根据指引下载权重 下…

springboot,maven多模块开发,子模块获取不到父模块添加的依赖,有多个root模块问题解决

错误示范 我以为放进去然后重载一下就是子模块了 导致后续在外层加的依赖&#xff0c;其article都接收不到 解决方案 需要在父模块的modules注册子模块 修改前后对比 此时子模块也能获取父模块的依赖

DDD设计方法-2-聚合、实体、值对象

前情提要&#xff1a;一共包含 如下六篇文章&#xff08;篇幅精简&#xff0c;快速入门&#xff09; 1、初识DDD 2、聚合、实体、值对象 3、仓储&#xff0c;封装持久化数据 4、端口和适配器 5、领域事件 6、领域服务&#xff0c;实现约定 DDD设计方法-2-聚合、实体、值对象&a…

基于mspm0g3507的智能送药小车(21年电赛f题,openmv寻迹,k210数字识别,并行pid调制)项目实验报告

2024年全国大学生电子设计竞赛&#xff08;TI杯&#xff09; 2024年7月17日 摘要&#xff1a;本项目由微处理器MSPM0G3507&#xff0c;编码器电机驱动&#xff0c;OPENMV、K210视觉处理单元&#xff0c;红外药品检测单元&#xff0c;ZIGBEE无限透传单元&#xff0c;OLED显示&am…

Docker数据卷和Dockerfile

1、什么是Docker数据卷 前言&#xff1a; 在下载的镜像中&#xff0c;我们不能够去改变它内部的一些配置&#xff0c;因为docker的镜像文件是已经配置好的&#xff0c;无法改变&#xff0c;我们只能改变镜像启动后的容器里面的内容&#xff0c;但是又因为&#xff0c;容器本来…

Java框架第四课(对Spring的补充Spring web)

目录 一.Spring web的认识 (1)Spring Web概念 (2)Spring web的特点 (3)Springweb运行的流程 (4)Springweb运行的流程图 二.搭建Spring web 三.自定义处理器类搭建 (1)处理器类配置 (2)处理器类接受请求 (3)获得请求数据 四.拦截器 (1)关于拦截器&#xff1a; (2)拦截器的…