opencv进阶篇---银行卡数字识别

执行结果:
在这里插入图片描述
在这里插入图片描述

主要思想:对模板图像以及待检测图像进行外轮廓检测,并得到各自外接矩形,将模板图像的外接矩形做resize()操作,使其外接矩形的大小与待检测图像外接矩形的大小相一致,然后与待检测图形做模板匹配
准备工作:
1、转为为灰度图像
2、转化为二值图像,才能做轮廓检测
3、根据轮廓的长宽比例的不同,过滤掉一些银行卡上无用的干扰信息
4、上面的步骤仅能得到一些大致的轮廓,还需做一些形态学操作,然后对数字进行拆分,得到更为精确的数字信息
注意:在找模板时,应该找字体十分接近的字体作为模板

(1)模板预处理过程:将模板中的每一个数字分别进行灰度转换、二值化、轮廓查找、轮廓绘制、resize()轮廓的大小并且将每个数字的轮廓值(排好序的)存入字典类型的变量中
模板图:
在这里插入图片描述
预处理之后的模板图:
在这里插入图片描述
代码片段:

img=cv.imread("E:\OpenCVTests\Samples\sample/nine/template-matching-ocr\images\ocr_a_reference.png")
gray=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
ret,ref=cv.threshold(gray,10,255,cv.THRESH_BINARY_INV)#此步骤,应该加前面的ret,否则会报错
refCnts,hierarchy=cv.findContours(ref.copy(),cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
#后面还要继续使用ref,因此需使用ref.copy(),否则会对原图做出改变;第二个参数为指定检测外轮廓;第三个参数为轮廓逼近的一种方法
cv.drawContours(img,refCnts,-1,(0,0,255),3)#-1表示绘制所有轮廓,当指定为其他值时,只在图像中选择一个绘制单个轮廓
refCnts=contours.sort_contours(refCnts,method="left-to-right")[0]#返回排序完的轮廓
digits={}#建立一个字典类型,i是轮廓索引,c是轮廓----字典类型:每个索引号对应一个索引值
for(i,c)in enumerate(refCnts):#i是轮廓索引,c是对应轮廓,则完成了对检测出来的轮廓进行了排序
    (x,y,w,h)=cv.boundingRect(c)#得到没一个外接矩形的左上坐标点以及长度、宽度
    roi=ref[y:y+h,x:x+w]#每个数字的外接矩形的尺寸
    roi=cv.resize(roi,(57,88))#重置外接矩形的尺寸至合适大小
    digits[i]=roi#每个数字对应一个模板

(2)待检测图像预处理过程:主要包括形态学操作去噪点、灰度转换、二值化、Sobel()函数求梯度、轮廓相关操作(轮廓的查找、轮廓的绘制、外接轮廓、根据轮廓的长宽比来对轮廓就行筛选、排序)再到遍历每一块中的每一个数字
待检测图像原图:
在这里插入图片描述
执行一次顶帽操作:
在这里插入图片描述
执行一次Sobel()求X方向上的梯度操作:求图中较为明亮的区域
在这里插入图片描述
执行一次闭操作:使图像上的内容成块出现
在这里插入图片描述
执行一次二值化操作:过滤掉杂乱信息
在这里插入图片描述
再执行一次闭操作:填补白色块中的小黑块
在这里插入图片描述
执行轮廓检测、轮廓绘制:
在这里插入图片描述
后续再根据轮廓的长宽比对轮廓进行筛选,筛选出需要的轮廓信息,工寄检测出4组有用的轮廓信息,并循环遍历这四组轮廓中的每一个数字,方法与上面同。

完整代码:

import cv2 as cv
from imutils import contours
import matplotlib as plt
import numpy as np
FIRST_NUMBER = {
	"3": "American Express",
	"4": "Visa",
	"5": "MasterCard",
	"6": "Discover Card"
}
#对模板图像做预处理

img=cv.imread("E:\OpenCVTests\Samples\sample/nine/template-matching-ocr\images\ocr_a_reference.png")
gray=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
ret,ref=cv.threshold(gray,10,255,cv.THRESH_BINARY_INV)#此步骤,应该加前面的ret,否则会报错
refCnts,hierarchy=cv.findContours(ref.copy(),cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
#后面还要继续使用ref,因此需使用ref.copy(),否则会对原图做出改变;第二个参数为指定检测外轮廓;第三个参数为轮廓逼近的一种方法
cv.drawContours(img,refCnts,-1,(0,0,255),3)#-1表示绘制所有轮廓,当指定为其他值时,只在图像中选择一个绘制单个轮廓
refCnts=contours.sort_contours(refCnts,method="left-to-right")[0]#返回排序完的轮廓
digits={}#建立一个字典类型,i是轮廓索引,c是轮廓----字典类型:每个索引号对应一个索引值
for(i,c)in enumerate(refCnts):#i是轮廓索引,c是对应轮廓,则完成了对检测出来的轮廓进行了排序
    (x,y,w,h)=cv.boundingRect(c)#得到没一个外接矩形的左上坐标点以及长度、宽度
    roi=ref[y:y+h,x:x+w]#每个数字的外接矩形的尺寸
    roi=cv.resize(roi,(57,88))#重置外接矩形的尺寸至合适大小
    digits[i]=roi#每个数字对应一个模板

#对待检测图像做预处理
recKernel=cv.getStructuringElement(cv.MORPH_RECT,(10,3))#为保证检测信息准确,需去除银行卡页面杂乱信
sqKernel=cv.getStructuringElement(cv.MORPH_RECT,(2,2))#因此需要对图像做形态学操作,故在此设立卷积核

image=cv.imread("E:\OpenCVTests\Samples\sample/nine/template-matching-ocr\images\credit_card_01.png")
image=cv.resize(image,(250,200))
gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY)
tophat=cv.morphologyEx(gray,cv.MORPH_TOPHAT,recKernel)#根据字体的大小来选定合适的核;顶帽操作来突出明亮的区域

gradx=cv.Sobel(tophat,ddepth=cv.CV_32F,dx=1,dy=0,ksize=3)#对X还是对Y需要或者同时需要根据实际需要来设定,图像梯度
gradx=np.absolute(gradx)#取绝对值
(minVal,maxVal)=(np.min(gradx),np.max(gradx))#归一化
gradx=(255*((gradx-minVal)/(maxVal-minVal)))
gradx=gradx.astype("uint8")

gradx=cv.morphologyEx(gradx,cv.MORPH_CLOSE,recKernel)#执行闭操作,使图像上的内容成块出现
ret,thresh=cv.threshold(gradx,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)#低阈值之所以设为0,是因为后面的方法选用了OTSU自动设定阈值,适合双峰的图像操作
thresh=cv.morphologyEx(thresh,cv.MORPH_CLOSE,sqKernel)#本次闭操作是为了填补二值化图像中块中的不完整小块
Cnts,hierarchy=cv.findContours(thresh.copy(),cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
cnts=Cnts
curImage=image.copy()
cv.drawContours(curImage,cnts,-1,(0,0,255),3)#此处轮廓不是原图像的轮廓,而是经历了一些列运算之后的图像的轮廓
locs=[]
for (i,c)in enumerate(cnts):
    (x,y,w,h)=cv.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):#遍历每一块中的每一个数字
    groupOutput=[]
    group=gray[gy-5:gy+gh+5,gx-5:gx+gw+5]#取轮廓及其周围的区域
    cv.imshow("group",group)
    group=cv.threshold(group,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)[1]#后面的[]要加,否则会报错元组类型不能copy,下面再对每个块进行轮廓检测、绘制
    digitCnts,hierarchy=cv.findContours(group.copy(),cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)#每一个group再进行轮廓检测、绘制
    digitCnts=contours.sort_contours(digitCnts,method="left-to-right")[0]
    for c in digitCnts:#计算每一组数中的每一个数值
        (x,y,w,h)=cv.boundingRect(c)
        roi=group[y:y+h,x:x+w]
        roi=cv.resize(roi,(57,88))#尺寸需与模板的尺寸对应,得到每一个数字所在的区域
        scores=[]#新建一个空列表,用来存储检测到的数字
        for (digit,digitROI)in digits.items():#在模板预处理中建立了数值的字典类型,一个为索引、一个为值
            result=cv.matchTemplate(roi,digitROI,cv.TM_CCOEFF)#匹配,返回与之匹配度最高的数值
            (_,score,_,_)=cv.minMaxLoc(result)#做10次匹配,取最大值(注意:取最大值还是最小值跟选取的模板匹配方法有关)
            scores.append(score)
        groupOutput.append(str(np.argmax(scores)))
    cv.rectangle(image,(gx-5,gy-5),(gx+gw+5,gy+gh+5),(0,0,255),1)#第一组的矩形框
    cv.putText(image,"".join(groupOutput),(gx,gy-15),cv.FONT_HERSHEY_SIMPLEX,0.65,(0,0,255),2)
    output.extend(groupOutput)
print("Credit Card Type: {}".format(FIRST_NUMBER[output[0]]))
print("Credit Card #: {}".format("".join(output)))
cv.imshow("Image",image)

cv.waitKey(0)
cv.destroyAllWindows()
  • 2
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值