执行结果:

主要思想:对模板图像以及待检测图像进行外轮廓检测,并得到各自外接矩形,将模板图像的外接矩形做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()

技术
©2019-2020 Toolsou All rights reserved,
Qt学习2——.pro文件和.h文件介绍LinkedHashMap基本用法&使用实现简单缓存pytorch之ResNet18(对cifar10数据进行分类准确度达到94%)华为Mate 40 Pro+ 5G曝光:徕卡电影镜头、陶瓷机身统计字母个数(java语言实现)JavaScript中的 Call 和 Apply1190 反转每对括号间的子串 leetcode记一次EventBus内存泄露导致的项目问题浅谈uni-app页面传值问题 Chrome OS,对程序员和Windows意味着什么?,互联网营销