最近在恶补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=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]#用一个最小的矩形,把找到的形状包起来,然后对最小坐标进行排序(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. 开闭合、顶帽、黑帽

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

  1. 学习Opencv+Python之银行卡卡号识别

    学习Opencv+Python之银行卡卡号识别 思路: 获取模板轮廓 获取模板中每个数字的轮廓 获取银行卡卡号轮廓 分别提取卡号中的每个数字的轮廓 对比识别 代码: # 导入工具包 from imut ...

  2. python opencv数字识别_基于模板匹配的手写数字识别(python+opencv)

    智能计算课第一周的实验是做基于模板匹配的手写数字识别,光听见就很感兴趣,于是决定认真做做这个实验,本实验基于python3+opencv的python版本,所用到的知识都比较简单,基本上边学边做,技术 ...

  3. 招商银行信用卡卡号识别项目(第一篇),Python OpenCV 图像处理取经之旅第 53 篇

    Python OpenCV 365 天学习计划,与橡皮擦一起进入图像领域吧.本篇博客是这个系列的第 53 篇. 该系列文章导航参考:https://blog.csdn.net/hihell/categ ...

  4. 基于模板匹配的数字电表数字识别(python)

    模板匹配可以说是比较传统的数学方法去做图像识别,以往的模板匹配往往只是让原图像与模板图像做减运算,最后选出最小误差的那张,但在实际识别中,这一方法识别的效果并不是很有效,特别对于两张数字类型并不是很相 ...

  5. python-openCV实现银行卡卡号识别

    实现效果: code import cv2 as cv import numpy as np# 轮廓排序 默认从左到右 # --cnts 待排序的轮廓列表 # --method 排序方法 自上而下,从 ...

  6. 【项目实战】Python基于OpenCV和卷积神经网络CNN进行车牌号码识别项目实战

    说明:这是一个机器学习实战项目(附带数据+代码+文档+视频讲解),如需数据+代码+文档+视频讲解可以直接到文章最后获取. 1.项目背景 车牌识别系统(Vehicle License Plate Rec ...

  7. 【项目实战二】基于模板匹配和形态学操作的信用卡卡号识别(OpenCV+Python)

    前言:信用卡卡号识别技术的发展有利于提高银行系统的业务水平和办事效率.相信此次通过学习使用OpenCV中的图像处理方法来实现信用卡卡号识别的项目,能让大家清楚地了解图像处理技术的一般方法与步骤以及如何 ...

  8. 基于Python的Opencv 自动识别银行卡卡号系统

    一. 摘要 此应用功能为自动识别并获取银行卡卡号,通过导入需要识别的银行卡图片,以及跟银行卡上卡号的数字相一致的数字模型,则可以成功实现识别并获取银行卡卡号的功能.如果你对此感兴趣的话,下面将会详细介 ...

  9. Python+OpenCV 识别银行卡卡号

    Python+OpenCV 识别银行卡卡号 今天尝试一下用python+OpenCV,使用模板匹配的方式做个简单地识别银行卡卡号(大部分参考网上的,自己改了一部分,代码写的有点不太好,但是思路很清晰, ...

  10. 银行卡三元素检测 根据姓名+身份证号+银行卡卡号验证信息是否匹配

    银行卡检测api,根据姓名+身份证号+银行卡卡号验证信息是否匹配. 接口名称:银行卡检测api 接口平台:聚合数据 接口地址:http://v.juhe.cn/verifybankcard3/quer ...

最新文章

  1. fillrect不填充被覆盖的区域 mfc_纹理和图案填充
  2. 【训练平台】mmdetection训练自己的标注数据, 以faster RCNN ,yolo为例子
  3. Lambda表达式只是一颗语法糖?
  4. pom文件无法加载ojdbc14-10.2.0.4.0.jar
  5. [RTMP协议]常用直播流地址
  6. /proc文件系统详解
  7. [网络安全提高篇] 一一二.DataCon Coremail邮件安全竞赛之钓鱼邮件识别及分类
  8. LeetCode 739. 每日温度 | Python
  9. 30岁前如何规划自己的人生?这9本书告诉你
  10. 不需要个人信息的云服务器,那些云服务器不需要实名
  11. unity-粒子系统参数
  12. 计算机网络统考outlook操作视频,网络教育计算机统考Outlook
  13. 华为云鲲鹏服务器部署文档--java微服务
  14. 《你好,放大器》----学习记录(三)
  15. quot;title_activity_distquot; is not translated in quot;zh-rCNquot; (Chinese: China)
  16. 哈希算法(Hash函数)简单介绍
  17. 连续语音信号的短时倒谱分析及其参数用途
  18. Mysql 备份工具XtraBackup全量备份
  19. LinQ的初步学习与总结
  20. 安发生物|醒醒吧!不吃晚饭=增肥!来听听钟南山院士的建议......

热门文章

  1. 推荐几个很实用的编程网站
  2. 一个Android项目被360报毒的解决方案
  3. 洛谷 P1251 餐巾计划问题 题解
  4. python的PIL库
  5. 数据结构习题集1-8:总结篇
  6. android float 百分比,如何在android中计算百分比
  7. 2017年第22届中国国际涂料、油墨及粘合剂展览会会刊(参展商名录)
  8. K60 FTM定时器 定时中断
  9. Unity URP Reflection
  10. 误格式化硬盘数据怎么恢复好