当先锋百科网

首页 1 2 3 4 5 6 7

整体思路:利用轮廓检测模板匹配实现信用卡数字识别。

总体分为3步:

  1. 使用轮廓检测实现数字0-9模板的存取。
  2. 检测到信用卡的数字部分区域并存储。
  3. 将信用卡数字依次与模板进行匹配,寻找到最合适的数字。

最终效果:
在这里插入图片描述
Step1:数字模板的获取
原始图片如下,需要通过轮廓检测获取每个单独的数字模板。
在这里插入图片描述
思路:通过轮廓检测获得各个数字的外轮廓,然后通过做出各个外轮廓的外接矩形并根据外接矩形的左上角点x的排序结果,确定对应数字所在的位置,然后用digit字典存储每一个数字的图象。

#获取模板,获得模板字典
templateRGB=cv.imread('ocr_a_reference.png',cv.IMREAD_COLOR)
templateGray=cv.cvtColor(templateRGB, cv.COLOR_BGR2GRAY)
(ret,templateGrayInv)=cv.threshold(templateGray, 127, 255,
									 cv.THRESH_BINARY_INV)
contours,hierarchy=cv.findContours(templateGrayInv.copy(), 
				cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)  

boundingBoxes=[]    #绘制外接矩形,按照x的大小排序,得到0-9的模板
for cnt in contours:
    boundingBoxes.append(cv.boundingRect(cnt))  #(x,y,w,h)
boundingBoxes=sort(boundingBoxes)
  
digits = {}	#此处可用字典也可用列表
for (i,c) in enumerate(boundingBoxes):
    (x,y,w,h)=boundingBoxes[i]  
    roi=templateGrayInv[y:y+h,x:x+w]
    roi=cv.resize(roi, (57,88))
    digits[i]=roi

Step2:检测到信用卡的数字部分区域并存储
难点在于如何检测到数字所在的区域。此处采用形态学闭操作的方法,将数字膨胀成连接在一起的明亮区域(4个为1个区域),然后通过轮廓检测做出外接矩形,根据限定矩形选择条件,比如长宽之比、长宽范围、矩形在图像中的整体位置等等选择出合适的外接矩形,其框选的内部即为所要的区域。

下图为闭操作之后的图像:
在这里插入图片描述
约束外接矩形条件后的结果:
在这里插入图片描述

#处理信用卡获取信用卡数字所在位置
creditCardBGR=cv.imread('credit_card_01.png',cv.IMREAD_COLOR)
creditCardGray = cv.cvtColor(creditCardBGR, cv.COLOR_BGR2GRAY)  
(ret,creditCardGrayThresh)=cv.threshold(creditCardGray, 127, 255, 
												cv.THRESH_BINARY)

kernel=np.ones((4,9))   #礼帽操作
tophat = cv.morphologyEx(creditCardGrayThresh, cv.MORPH_TOPHAT, kernel) 

kernel=np.ones((3,25))  #闭操作
close=cv.morphologyEx(tophat, cv.MORPH_CLOSE, kernel)
close=cv.morphologyEx(close, cv.MORPH_CLOSE, kernel)

contours, hierarchy = cv.findContours(close.copy(),      #依靠轮廓检测找到四段数字的区域
    cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)

boundingBoxes=[]
for cnt in contours:   
    (x,y,w,h)=cv.boundingRect(cnt) 
    ratio=w/h
    if ratio>3.3 and ratio<4.3:     #可以再加入条件进行约束
        boundingBoxes.append((x,y,w,h))
boundingBoxes=sort(boundingBoxes)

在获取4段数字区域之后,与Step1的做法相同,在各自数字区域内进行轮廓检测,并且根据外接矩形的x进行排序,获得各自内部数字的图像数据,自此16个数字全部被从原始信用卡图像中提取出来。

#遍历4段区域,找到16个数字的图像信息并存储
number=[]
for i in range(0,4):
    (x,y,w,h)=boundingBoxes[i]
    region=creditCardGrayThresh[y-3:y+h+3,x-3:x+w+3]    #存储当前段的图像内容

    interNums=[]
    contours, hierarchy = cv.findContours(region.copy(), #找到4个内部数字的区域
        cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
    for cnt in contours:
        (x,y,w,h)=cv.boundingRect(cnt)
        interNums.append((x,y,w,h))
    interNums=sort(interNums)
   
    for j in range(0,len(interNums)):   #依次存储到number列表中
        (x,y,w,h)=interNums[j]
        roi=region[y:y+h,x:x+w]
        roi=cv.resize(roi, (57,88))
        number.append(roi)

Step3:将信用卡数字依次与模板进行匹配,寻找到最合适的数字
将存储信用卡数字的number列表中的数字依次与Step1中得到的模板进行匹配,以得分高的做为最终结果。

#使用模板匹配得到最终结果
OCR_Rseult=''
for i in range(0,len(number)):
    scores=[]
    for j in range(0,len(digits)):
        result=cv.matchTemplate(number[i], digits[j], cv.TM_CCOEFF)
        (_, score, _, _) = cv.minMaxLoc(result)
        scores.append(score)
    OCR_Rseult+=str(np.argmax(scores))

最后显示效果:

print(OCR_Rseult)   #打印数字
image=creditCardBGR.copy()  #绘图
for (i,(x,y,w,h)) in enumerate(boundingBoxes) :
    cv.rectangle(image, (x- 5, y - 5),(x + w + 5, y + h + 5), (0, 0, 255), 1)
    cv.putText(image,OCR_Rseult[4*i:4*i+4],(x,y-10), cv.FONT_HERSHEY_COMPLEX, 0.7, (0, 0, 255))
cv_show('img', image)

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