opencv基于模板匹配的银行卡卡号识别项目实战

最近在恶补opencv,在前期不太那么认真的学习状态下,着手搞了一下这个小项目实战,基于模板匹配下的银行卡卡号识别。

整体思路:

首先对于该项目而言,我们所需要考虑的是,该如何让计算机成功识别到银行卡的卡号,并正确识别出每个卡号数字所对应的数字。那么我们在这里提供一种思路,首先通过对银行卡图像进行轮廓识别,然后拿到我们需要的对应的卡号的轮廓部分,然后再在轮廓中进行进一步轮廓识别,拿到每个数字的轮廓,最后通过画出每个数字的外接矩形,然后根据事先识别好的模板的外接矩形轮廓进行模板匹配,对应就能成功识别出正确的数字。

准备工作:

1.将图像转化为灰度图
2.对图像作二值化处理
3.画轮廓,根据轮廓比的不同拿到我们需要的轮廓部分(此处使用的是将轮廓的长宽进行相比,然后判断每个轮廓的长宽比,然后通过限定条件拿到正确的长宽比部分),同时过滤掉银行卡上的其他图像信息
4.最后再做一些形态学操作,比如一些开、闭合操作,将数字图像信息更明显,更精准
5.训练好模板,这里需要注意的是,我们针对银行卡卡号,需要找到与银行卡卡号数字样式相近的数字模板,不然会影响后续的匹配结果

匹配结果:

在这里插入图片描述
在这里插入图片描述

测试图以及模板图

在这里插入图片描述
在这里插入图片描述

处理过程:

模板图像处理

整个预处理的过程就是灰度图、二值化、轮廓查找、画轮廓、resize()轮廓的大小并将所有轮廓进行从0~9的顺序排序,以方便后续匹配完成后的数字获取;

完成上诉操作后的模板图:

在这里插入图片描述

相关代码

#1.读取模板
img=cv2.imread('number.png')
cv_show('number',img)
#2.模板转换为灰度图
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv_show('gray',gray)
#3.换为二值图像
ref,thre=cv2.threshold(gray,10,255,cv2.THRESH_BINARY_INV)
cv_show('ref',thre)
#4.计算轮廓
refCnts,hierarchy=cv2.findContours(thre.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img,refCnts,-1,(0,0,255),3)#画轮廓,此处只画外轮廓,一共10个轮廓0~9
cv_show('imgLK',img)
refCnts=sort(refCnts,"left-to-right")[0]
digits={}

#遍历每一个轮廓:
for(i,c) in enumerate(refCnts):#计算外接矩形并且resize成合适大小
    (x,y,w,h)=cv2.boundingRect(c)
    roi=thre[y:y+h,x:x+w]
    roi=cv2.resize(roi,(57,88))

    #每个数字都有一个模板
    digits[i]=roi#0~9的数字模板对应

原图像处理

原图像的处理相较模板而言,首要的操作一致,都是先灰度处理,然后二值化,多的就是一些形态学的操作,其主要目的是为了去噪点,然后强化轮廓和一些重要特征的强化,完成这些之后,我们通过轮廓的长宽比拿到我们需要的部分轮廓信息,拿到之后再继续进行轮廓处理,画外接矩形,对比,最后得到结果。
对原图进行灰度和二值化之后,我们做一次顶帽操作;
因为开运算带来的结果是放大了裂缝或者局部低亮度的区域,因此,从原图中减去开运算后的图,得到的效果图突出了比原图轮廓周围的区域更明亮的区域,且这一操作和选择的核的大小相关。
效果图:
在这里插入图片描述
然后求一次X方向的梯度,拿到上图中高亮的部分:
在这里插入图片描述
然后做一次闭操作,让高亮区域成块出现:
在这里插入图片描述
接着做一次二值化,让成块部分更高亮,同时去除一下图像中其他杂余信息:
在这里插入图片描述
随后做一次闭操作,补全区域的空白部分;

完成上述操作之后,便可以进行画轮廓,然后筛选轮廓,最后拿到需要的轮廓之后,再进行上述的操作,拿到每个轮廓里面的数据信息,然后进行模板匹配;

完整代码段:

import cv2
import numpy as np
from imutils import contours
from matplotlib import pyplot as plt
#银行卡实战小项目

def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

def sort(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

#1.读取模板
img=cv2.imread('number.png')
cv_show('number',img)
#2.模板转换为灰度图
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv_show('gray',gray)
#3.换为二值图像
ref,thre=cv2.threshold(gray,10,255,cv2.THRESH_BINARY_INV)
cv_show('ref',thre)
#4.计算轮廓
refCnts,hierarchy=cv2.findContours(thre.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img,refCnts,-1,(0,0,255),3)#画轮廓,此处只画外轮廓,一共10个轮廓0~9
cv_show('imgLK',img)
refCnts=sort(refCnts,"left-to-right")[0]
digits={}#用来存放模板数字对应的数字

#遍历每一个轮廓:
for(i,c) in enumerate(refCnts):#计算外接矩形并且resize成合适大小
    (x,y,w,h)=cv2.boundingRect(c)
    roi=thre[y:y+h,x:x+w]
    roi=cv2.resize(roi,(57,88))

    #每个数字都有一个模板
    digits[i]=roi#0~9的数字模板对应

#初始化卷积核,做形态学处理,核的大小可以自己定义,根据实际情况进行定义
rectKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
sqKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))

#读取原始图像,预处理
image=cv2.imread('bank_testI.png')
cv_show('card',image)
image=cv2.resize(image,(300,200))
#灰度处理
image_gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
cv_show('gray',image_gray)
#顶帽操作,突出明亮区域
tophat=cv2.morphologyEx(image_gray,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")
cv_show('gradX',gradX)

#执行闭操作,让图像信息成块出现
gradX=cv2.morphologyEx(gradX,cv2.MORPH_CLOSE,rectKernel)
cv_show('gradX',gradX)

thresh=cv2.threshold(gradX,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]#阈值设为0是因为函数中设置了自动判断阈值,一般适用于双峰情况
cv_show('gradX_t',thresh)

#再进行一次闭操作,让图像信息成团出现,补齐空白部分
thresh=cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,sqKernel)
conts,hiera=cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cont=conts
curImag=image.copy()
tmp=cv2.drawContours(curImag,cont,-1,(0,0,255),3)#在经过一系列处理后的图像中画出轮廓
locs=[]

for(i,c) in enumerate(cont):
    (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):
    groupOuput=[]
    group=image_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]#再次对每个大框里面的数据进行二值化、测边界
    digitsCont,hieraD=cv2.findContours(group.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)#再进行轮廓检测
    digitsCont=sort(digitsCont,method="left-to-right")[0]
    for c in digitsCont:#计算每个小框的值
        (x,y,w,h)=cv2.boundingRect(c)#做同样操作,画外接矩形然后模式匹配
        roi=group[y:y+h,x:x+w]
        roi=cv2.resize(roi,(57,88))
        scores=[]
        for (digit,digitROI) in digits.items():
            result=cv2.matchTemplate(roi,digitROI,cv2.TM_CCOEFF)#进行匹配,返回的最高值
            (_,score,_,_)=cv2.minMaxLoc(result)#做10次匹配,取最大值
            scores.append(score)
        groupOuput.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(groupOuput),(gx,gy-15),cv2.FONT_HERSHEY_SIMPLEX,0.65,(0,0,255),2)
    output.extend(groupOuput)
print("The Card's number is :{}",format("".join(output)))
cv_show('image_result', image)

总结:

整个实战项目的难度不算很大,但对于我这个新手来说比较麻烦,毕竟是第一次实战,所以对整个流程还是处在一个模仿的阶段,整个流程没有自己独立的思考,更多的是对整个流程的个人理解和学习,故待到后续进行深入学习之后,可以再继续对项目进行进一步的改善。如果很幸运有大佬看到我的这篇文章,如果您有比较好的学习建议和意见,请在留言区留言哟~或者你有不理解的地方,也可以在留言区留言,一起探讨学习!!

参考

  1. 参考的大佬的文章
  2. B站实战视频
  3. 开闭合、顶帽、黑帽
  • 21
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
### 回答1: YOLOv3是一种高效的目标检测算法,通过基于深度卷积神经网络的技术,可以在图像或视频中对目标进行快速准确地识别。YOLOv3银行卡识别就是将这一算法应用到银行卡号的识别任务中。 银行卡号是银行卡的重要信息,而银行卡号的识别在银行、ATM、商超等场景中都非常重要。使用YOLOv3银行卡识别技术,可以自动检测卡号所在区域以及卡号的位置,实现对卡号的快速准确识别,提高银行卡交易的效率和安全性。 具体的实现过程是将训练好的YOLOv3模型应用到银行卡图片中,通过网络结构的输出,可以得到银行卡号所在的边框坐标和分类结果。然后,将边框坐标和分类结果结合起来,输出最终的银行卡识别结果。 虽然YOLOv3银行卡识别技术已经具备一定的准确率和稳定性,但在实际应用中,也需要考虑到一些因素,例如光线、角度、图像场景等因素对识别效果的影响。因此,为了提高系统的实用性和稳定性,也需要针对具体应用场景进行优化和调整。 ### 回答2: yolov3是一种用于目标检测的神经网络模型,在银行卡识别方面具有较高的准确率和效率。该模型可以自动识别图像中的银行卡,并定位出银行卡号码的位置。通过对图像进行预处理和训练,yolov3可以识别各种形状和大小的银行卡,并精准地检测出银行卡上的号码。 在使用yolov3进行银行卡识别时,需要先收集一定量的银行卡图片来进行训练和测试。在训练过程中,需要对图片进行标注,并对模型进行调参以提升识别准确率。在应用场景中,可以将训练好的模型嵌入到移动端或者其他设备中,以实现快速、准确的银行卡号码识别。 总的来说,yolov3作为一种先进的目标检测模型,在银行卡号码识别方面具有很高的应用价值,可以广泛应用于银行、商超等场景中,提升传统人工识别效率,提高客户服务效果。 ### 回答3: Yolov3银行卡识别是一种基于深度学习技术的自动识别方法,可以高效地实现银行卡号的识别和提取。Yolov3是一种卷积神经网络模型,它可以对输入的图像进行检测和分类,并输出每个物体的位置和类别信息。因此,使用Yolov3模型对银行卡图片进行识别,可以定位银行卡上的数字字符,并准确地提取出银行卡号。 实现银行卡识别的关键是训练模型,这需要大量的数据集和模型优化。首先,需要收集大量的银行卡图片,并手动标注银行卡号的位置和值。然后,将这些数据集输入到Yolov3模型中进行训练,通过迭代优化,可以不断提高模型的准确率。 Yolov3银行卡识别不仅可以在银行、ATM等金融领域应用,在其他领域也具有广泛的应用,如自助售货机、智能门禁等。它不仅能够节省人力成本,提高工作效率,在某些场景下也可以增加识别的准确性,从而带来更好的体验和服务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值