ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-11-25 14:30:35  阅读:183  来源: 互联网

标签:show cv2 opencv gradX 卡号 轮廓 cv 模板


最近在恶补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站实战视频

标签:show,cv2,opencv,gradX,卡号,轮廓,cv,模板
来源: https://blog.csdn.net/qq_44705939/article/details/121530420

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有