OpenCV学习(一)银行卡号识别

  • B站教学链接: 

银行卡号识别(OpenCV-Python)

代码:Card_Number_Recognition

1.方法

使用模板匹配的方法来识别银行卡号数字。具体来说,先通过图像预处理将图像中的银行卡号分割出来,再与提供的模板进行对比,从而完成银行卡号的识别。

2.代码

##############################
###   Bank card number identification
##############################import cv2
import numpy as npcard_GRAY=cv2.imread('bank_card41.jpg',0)
card_GRAY4=cv2.resize(card_GRAY,(4*card_GRAY.shape[1],4*card_GRAY.shape[0]))
#cv2.imshow('card_GRAY4',card_GRAY4)adaptiveThresh = cv2.adaptiveThreshold(card_GRAY4, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 13, 3)
#cv2.imshow('adaptiveThresh',adaptiveThresh)contours, hierarchy = cv2.findContours(adaptiveThresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
for i in range(len(contours)):if cv2.contourArea(contours[i])<160:adaptiveThresh = cv2.drawContours(adaptiveThresh, contours, i, (0,0,0), -1)
#cv2.imshow('adaptiveThresh2',adaptiveThresh)kernel = np.ones((15,15),dtype=np.uint8)
blackhat = cv2.morphologyEx(adaptiveThresh, cv2.MORPH_BLACKHAT, kernel)
#cv2.imshow('blackhat',blackhat)kernel = np.ones((3,3),dtype=np.uint8)
opening = cv2.morphologyEx(blackhat, cv2.MORPH_OPEN, kernel)
#cv2.imshow('opening',opening)contours, hierarchy = cv2.findContours(opening,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
for i in range(len(contours)):x,y,w,h = cv2.boundingRect(contours[i])aspect_ratio = float(w)/hArea = w * hif Area<1800 or Area>6000:opening = cv2.drawContours(opening, contours, i, (0,0,0), -1)else:if aspect_ratio>0.7 or aspect_ratio<0.5:opening = cv2.drawContours(opening, contours, i, (0,0,0), -1)
cv2.imshow('opening2',opening)kernel = np.ones((5,5),np.uint8)
dilation = cv2.dilate(opening,kernel,iterations = 1)
cv2.imshow('dilation',dilation)numTemplate=cv2.imread('bankCardNumTemplate.jpg')
numTemplate_GRAY=cv2.cvtColor(numTemplate,cv2.COLOR_BGR2GRAY)
ret,numTemplate_GRAY = cv2.threshold(numTemplate_GRAY,200,255,cv2.THRESH_BINARY)
cv2.imshow('numTemplate_GRAY',numTemplate_GRAY)def sequence_contours(image, width, height):contours, hierarchy = cv2.findContours(image,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)n = len(contours)RectBoxes0 = np.ones((n,4),dtype=int)for i in range(n):RectBoxes0[i] = cv2.boundingRect(contours[i])RectBoxes = np.ones((n,4),dtype=int)for i in range(n):sequence = 0for j in range(n):if RectBoxes0[i][0]>RectBoxes0[j][0]:sequence = sequence + 1RectBoxes[sequence] = RectBoxes0[i]ImgBoxes = [[] for i in range(n)]for i in range(n):x,y,w,h = RectBoxes[i]ROI = image[y:y+h,x:x+w]ROI = cv2.resize(ROI, (width, height))thresh_val, ROI = cv2.threshold(ROI, 200, 255, cv2.THRESH_BINARY)ImgBoxes[i] = ROIreturn RectBoxes, ImgBoxesRectBoxes_Temp, ImgBoxes_Temp = sequence_contours(numTemplate_GRAY, 50, 80)
print(RectBoxes_Temp)
cv2.imshow('ImgBoxes_Temp[1]',ImgBoxes_Temp[1])
RectBoxes, ImgBoxes = sequence_contours(dilation, 50, 80)result = []
for i in range(len(ImgBoxes)):score = np.zeros(len(ImgBoxes_Temp),dtype=int)for j in range(len(ImgBoxes_Temp)):score[j] = cv2.matchTemplate(ImgBoxes[i], ImgBoxes_Temp[j], cv2.TM_SQDIFF)min_val, max_val, min_indx, max_indx = cv2.minMaxLoc(score)result.append(min_indx[1])
print(result)cv2.waitKey(0)
cv2.destroyAllWindows()

2.1 分割银行卡号码

目的:减少识别号码时的干扰。

方法:找到号码与其他区域的区别,通过这个区别将其他部分剪切掉。

以下为尝试,还没有真的实现,这张银行卡号码颜色和银行卡本身太接近了。

2.1.1 前景分割

一般而言,银行卡上有相应银行的名字,logo,和有标识度的建筑,银行卡号码一般在卡中间稍向下,凸出,且有一定反光的部分。因此,银行卡号与其他图像是一个前后景的关系,银行卡号是前景,其余图像是背景。所以通过前景分割来去除银行卡号无关的图像信息是可行的。

2.1.2 图像处理

通常情况下,银行卡号码的像素是有别于它周围的,使用灰度化和自适应阈值化后可以明显的观察到银行卡号和其他图像的,之后通过形态学变化来确定银行卡位置的形状,然后以银行卡号特有的长宽比例从银行卡上筛选出号码区域。

筛选出的号码区域:

2.2 图像预处理

因为识别的方法睡觉哦模板匹配,首先就需要尽可能地将图像处理得和模板相似,再通过模板清晰的图像来识别银行卡号码。

模板:

2.2.1 初步预处理

#读取图像

# 注意:这一步骤已经在读取图像时完成,因为使用了参数 0,将图像直接读取为灰度图像

card_GRAY=cv2.imread('bank_card41.jpg',0)

#将图像扩大四倍
card_GRAY4=cv2.resize(card_GRAY,(4*card_GRAY.shape[1],4*card_GRAY.shape[0]))
#自适应阈值化

adaptiveThresh = cv2.adaptiveThreshold(card_GRAY4, 255, cv2.ADAPTIVE_THRESH_MEAN_C, 
                                       cv2.THRESH_BINARY_INV, 13, 3)

  1. 灰度化:

    • 目的: 将彩色图像转换为灰度图像,即只包含灰度级别(0-255)的图像,而不包含颜色信息。
    • 原理: 灰度化过程会将彩色图像中的每个像素的红、绿、蓝(RGB)三个通道的值进行加权平均,从而得到一个单一的灰度值。常用的加权公式包括取平均值、加权平均值等。
    • 优势: 简化了图像,去除了颜色信息,使得图像处理更加高效和简单。在很多图像处理任务中,只需使用亮度信息而不需要颜色信息。
    • 应用: 在很多计算机视觉任务中广泛应用,如边缘检测、特征提取、图像分割等。

  1. 自适应阈值化:

    • 目的: 将图像分割成目标和背景,以便更容易地提取目标对象或执行其他后续处理任务。
    • 原理: 自适应阈值化根据图像的局部区域来确定每个像素的阈值,而不是使用全局固定的阈值。这样可以更好地处理图像中光照不均匀或对比度不一致的情况。
    • 优势: 自适应阈值化能够根据图像的局部特征动态调整阈值,从而更好地适应不同区域的光照和对比度变化,提高了图像处理的鲁棒性和准确性。
    • 应用: 在需要分割目标对象的图像中,如文本检测、目标检测、图像分割等任务中经常使用。

2.2.2 进一步处理 

#定义核大小

kernel = np.ones((15,15),dtype=np.uint8)

#黑帽
blackhat = cv2.morphologyEx(adaptiveThresh, cv2.MORPH_BLACKHAT, kernel)
#cv2.imshow('blackhat',blackhat)

#定义核大小

kernel = np.ones((3,3),dtype=np.uint8)

#顶帽
opening = cv2.morphologyEx(blackhat, cv2.MORPH_OPEN, kernel)
#cv2.imshow('opening',opening)

#搜集图像中形状的轮廓

contours, hierarchy = cv2.findContours(opening,cv2.RETR_TREE,
                                       cv2.CHAIN_APPROX_SIMPLE)

#过滤掉非目标形状轮廓
for i in range(len(contours)):
    x,y,w,h = cv2.boundingRect(contours[i])
    aspect_ratio = float(w)/h
    Area = w * h
    if Area<1800 or Area>6000:
        opening = cv2.drawContours(opening, contours, i, (0,0,0), -1)
    else:
        if aspect_ratio>0.7 or aspect_ratio<0.5:
            opening = cv2.drawContours(opening, contours, i, (0,0,0), -1)
cv2.imshow('opening2',opening)

kernel = np.ones((5,5),np.uint8)
dilation = cv2.dilate(opening,kernel,iterations = 1)
cv2.imshow('dilation',dilation)

最终的输出:

输入:

 

形态学变换是一组基于图像形状的操作,通常用于图像预处理、特征提取和图像分析等任务。以下是常见的形态学变换操作:

腐蚀(Erosion):

腐蚀操作通过沿着图像边界移动的结构元素(通常是一个小的二值化核)来“侵蚀”图像的边界。如果结构元素与图像中的像素完全匹配,则保留像素值,否则将像素设置为0。腐蚀操作可以用于去除图像中的噪声、分离连接的对象等。

膨胀(Dilation):

膨胀操作与腐蚀相反,它通过将结构元素与图像中的像素进行匹配来“膨胀”图像的边界。如果结构元素的至少一个像素与图像中的像素匹配,则将像素设置为1。膨胀操作可以用于填充图像中的空洞、连接接近的对象等。

开运算(Opening):

开运算是先进行腐蚀操作,然后进行膨胀操作的组合。它可以用于去除图像中的小的干扰对象、平滑对象的边界等。

闭运算(Closing):

闭运算是先进行膨胀操作,然后进行腐蚀操作的组合。它可以用于填充对象的孔洞、连接相邻的对象等。

顶帽(Top Hat)和黑帽(Black Hat)变换:

顶帽变换是原始图像与开运算结果之间的差异,它可以用于提取图像中的小的亮区域。

黑帽变换是原始图像与闭运算结果之间的差异,它可以用于提取图像中的小的暗区域。

这些形态学变换操作通常用于图像的预处理和分析,能够改善图像的质量、增强图像的特征,并有助于后续的图像处理任务。

2.3 处理模板

#读取模板图像

numTemplate=cv2.imread('bankCardNumTemplate.jpg')

#灰度化
numTemplate_GRAY=cv2.cvtColor(numTemplate,cv2.COLOR_BGR2GRAY)

#自适应阈值化
ret,numTemplate_GRAY = cv2.threshold(numTemplate_GRAY,200,255,cv2.THRESH_BINARY)
cv2.imshow('numTemplate_GRAY',numTemplate_GRAY)

#搜集模板图像中数字形状,并将每一个形状命名

def sequence_contours(image, width, height):
    contours, hierarchy = cv2.findContours(image,cv2.RETR_EXTERNAL,
                                           cv2.CHAIN_APPROX_SIMPLE)

    n = len(contours)
    RectBoxes0 = np.ones((n,4),dtype=int)
    for i in range(n):
        RectBoxes0[i] = cv2.boundingRect(contours[i])
#重新排序,从小到大    
    RectBoxes = np.ones((n,4),dtype=int)
    for i in range(n):
        sequence = 0
        for j in range(n):
            if RectBoxes0[i][0]>RectBoxes0[j][0]:
                sequence = sequence + 1
        RectBoxes[sequence] = RectBoxes0[i]
 #获取形状
    ImgBoxes = [[] for i in range(n)]
    for i in range(n):
        x,y,w,h = RectBoxes[i]
        ROI = image[y:y+h,x:x+w]
        ROI = cv2.resize(ROI, (width, height))
        thresh_val, ROI = cv2.threshold(ROI, 200, 255, cv2.THRESH_BINARY)
        ImgBoxes[i] = ROI
        
    return RectBoxes, ImgBoxes

     contours, hierarchy = cv2.findContours(image,cv2.RETR_EXTERNAL,
                                           cv2.CHAIN_APPROX_SIMPLE)

这行代码使用OpenCV中的findContours函数来查找图像中的轮廓。让我解释一下这段代码的参数:

  • image: 这是输入的二值化图像,通常是经过阈值化处理后的图像,用于查找轮廓。
  • cv2.RETR_EXTERNAL: 这个参数指定了轮廓的检索模式。RETR_EXTERNAL表示只检索最外层的轮廓,不检索内部的轮廓。
  • cv2.CHAIN_APPROX_SIMPLE: 这个参数指定了轮廓的近似方法。CHAIN_APPROX_SIMPLE表示对轮廓的边界点进行压缩,只保留终点坐标,例如一个矩形轮廓只需四个角点。

该函数会返回两个值:

  • contours: 这是一个Python列表,包含了检测到的轮廓。每个轮廓都是一个包含点坐标的numpy数组。
  • hierarchy: 这是一个包含轮廓层级信息的数组。它可以用来确定轮廓之间的关系,如父子关系、内部轮廓等。

在这段代码中,我们使用RETR_EXTERNAL模式,因此contours列表中的每个元素都是图像中最外部的一个轮廓。然后我们可以对这些轮廓进行操作,如绘制、计算轮廓的面积等。

    for i in range(n):
        RectBoxes0[i] = cv2.boundingRect(contours[i])

在OpenCV中,contours列表中轮廓的排列顺序与它们的层级关系有关,而层级关系由hierarchy数组提供。hierarchy数组中每个元素对应于contours列表中的一个轮廓,它包含了关于该轮廓的层级信息。

hierarchy数组的每个元素都是一个四元组 [Next, Previous, First_Child, Parent],其中:

  • Next 表示后一个轮廓的索引,如果没有则为-1;
  • Previous 表示前一个轮廓的索引,如果没有则为-1;
  • First_Child 表示第一个子轮廓的索引,如果没有子轮廓则为-1;
  • Parent 表示父轮廓的索引,如果没有父轮廓则为-1。

根据这些信息,轮廓的排列顺序可以理解为:

  1. Next 表示的是在同一层级上下一个轮廓的索引,因此轮廓按照这个顺序排列。
  2. First_Child 表示的是子轮廓的索引,如果存在子轮廓,那么这些子轮廓将在父轮廓之后排列。

这意味着轮廓的排列顺序在一定程度上是根据它们在图像中的位置和相对关系确定的,而层级关系则决定了轮廓的嵌套和父子关系。

截取模板图像的示例

2.4 模板匹配

result = []
for i in range(len(ImgBoxes)):
    score = np.zeros(len(ImgBoxes_Temp),dtype=int)
    for j in range(len(ImgBoxes_Temp)):
        score[j] = cv2.matchTemplate(ImgBoxes[i], ImgBoxes_Temp[j], cv2.TM_SQDIFF)
    min_val, max_val, min_indx, max_indx = cv2.minMaxLoc(score)
    result.append(min_indx[1])
print(result)

         score[j] = cv2.matchTemplate(ImgBoxes[i], ImgBoxes_Temp[j], cv2.TM_SQDIFF)

这行代码使用了OpenCV中的matchTemplate函数,该函数用于在输入图像中寻找模板图像的匹配位置。让我解释一下这行代码的参数:

  • ImgBoxes[i]: 这是输入图像,通常是被搜索的大图像。
  • ImgBoxes_Temp[j]: 这是模板图像,是被用来在输入图像中搜索匹配位置的小图像。
  • cv2.TM_SQDIFF: 这是匹配方法,它指定了模板匹配的度量方式。TM_SQDIFF表示使用平方差匹配法,即通过计算输入图像和模板图像之间的像素差的平方来度量相似度,得到的值越小表示匹配度越高。

matchTemplate函数会返回一个二维数组,表示在输入图像中找到的与模板图像的匹配程度。在使用了TM_SQDIFF方法后,数组中的每个元素表示对应位置的像素值的平方差。通常,我们会找到这个数组中的最小值,以确定最佳匹配位置。

在你提供的代码中,score[j]被赋值为模板匹配结果,即输入图像中与模板图像最匹配的位置的匹配分数。

    min_val, max_val, min_indx, max_indx = cv2.minMaxLoc(score) 

这行代码使用了OpenCV中的minMaxLoc函数来找到匹配结果数组中的最小值和最大值,以及它们对应的位置。让我解释一下这行代码的参数:

  • score: 这是模板匹配的结果数组,即调用matchTemplate函数后得到的匹配分数数组。

minMaxLoc函数会返回四个值:

  • min_val: 这是匹配结果数组中的最小值。
  • max_val: 这是匹配结果数组中的最大值。
  • min_loc: 这是最小值的位置,即最佳匹配的位置之一。
  • max_loc: 这是最大值的位置,通常不会被使用。

在这行代码中,你选择了只接收最小值及其位置,因此min_val保存了匹配结果数组中的最小值,而min_indx保存了最小值的位置。这样你就可以确定在输入图像中最佳匹配的位置了。

 

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

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

相关文章

家装新宠!装修APP开发解决方案,为业主提供全新装修模式

随着人们对家庭装修的需求度越来越高&#xff0c;装修APP开发也随之出现。如今装修APP开发可实现互联网与传统家装行业的信息结合&#xff0c;由传统的家装行业广告模式向移动端的互联网模式进行转移&#xff0c;实现传统家装行业与互联网的相辅相成&#xff0c;以此来推动家装…

xftp破解版?No!xftp平替开源工具✔

文章目录 一、背景说明二、WindTerm介绍三、简单使用说明3.1 新建一个ssh连接窗口![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/bfbe5114916e4a7e94ca0f9ceb05ca37.png)3.2 输入主机ip和端口号3.3 点击Continue3.4 输入密码3.5 登入成功3.6 下载文件到本地3.7 上…

定时任务执行 报错command not found 解决方案

目录 写在前面所需知识 问题复现解决方式方法1. 使用绝对路径的命令&#xff1a;方法2. 重新加载环境变量&#xff1a;成功解决截图 原理 写在前面 定时任务脚本出现command not found报错&#xff0c;解决方案。 所需知识 定时任务shell脚本环境变量 问题复现 编写了一个…

煤矿防爆气象传感器

TH-WFB5随着工业技术的不断发展&#xff0c;煤矿作为我国能源领域的重要组成部分&#xff0c;其安全生产问题一直备受关注。在煤矿生产过程中&#xff0c;井下环境复杂多变&#xff0c;瓦斯、煤尘等易燃易爆物质的存在使得井下安全工作尤为重要。为了提高煤矿生产的安全性&…

【桌面应用开发】Rust+Tauri框架项目打包操作

1.项目npm install下载项目依赖&#xff08;需要配置好node.js环境&#xff09; 可参考&#xff1a;https://blog.csdn.net/m0_64346565/article/details/138319651 2.自定义图标&#xff08;项目初始化开始第一次需要配置生成&#xff0c;后面可跳过这一步骤&#xff09; Ta…

Selenium定位方法汇总及举例

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

bcrypt.dll文件丢失怎么办?bcrypt.dll怎么修复?

在计算机系统运行过程中&#xff0c;如果发现无法找到或缺失bcrypt.dll文件&#xff0c;可能会引发一系列的问题与故障。首先&#xff0c;由于bcrypt.dll是系统中一个重要的动态链接库文件&#xff0c;它的主要功能可能涉及到系统核心服务、应用程序支持或者特定功能模块的运行…

activiti 工作流基本使用

Activiti 介绍 Activiti 是一个开源架构的工作流引擎&#xff0c;基于bpmn2.0 标准进行流程定义。其前身是JBPM&#xff0c;Activiti 通过嵌入到业务系统开发中进行使用。 官方是这样介绍 activiti的&#xff1a; Activiti 是领先的轻量级、以 Java 为中心的开源 BPMN 引擎&…

24数维杯ABC题思路已更新!!!!

24数维杯A题保姆级思路&#xff0b;配套代码&#xff0b;后续参考论文 简单麦麦https://www.jdmm.cc/file/2710639/ 24数维杯B题保姆级思路&#xff0b;可执行代码&#xff0b;后续参考论文 简单麦麦https://www.jdmm.cc/file/2710640/ 24数维杯C题保姆级思路&#xff0b;可执…

Kubernetes: 从零开始理解K8s架构

目录 一、简介 二、Kubernetes 架构原理 2.1 控制平面 2.2 Node 组件 2.3 Container Image 2.4 kubelet 2.5 Cluster 三、服务调用 四、总结 一、简介 Kubernetes 是一个开源的容器编排系统&#xff0c;用于自动化应用容器的部署、扩展和管理。它是Google基于Borg…

python中的数据可视化:二维直方图 hist2d()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 python中的数据可视化&#xff1a; 二维直方图 hist2d() 选择题 关于以下代码输出结果的说法中正确的是? import matplotlib.pyplot as plt import numpy as np x np.random.normal(0, 1, …

IQOO Neo7/7SE/PAD2解BL+完美root权限+LSPosed框架-可虚拟定位

QOO Neo7/Neo7SE/Pad/Pad2搭配的是天玑8200系列芯片&#xff0c;继810/920以后再次支持解锁BL&#xff0c;这给我们的玩机带来了很多可能。解锁BL有什么用途呢&#xff1f;最常见的就是获取root权限&#xff0c;刷入各种各种的magisk模块&#xff0c;使用自己喜欢的插件等&…