整体思路:利用轮廓检测与模板匹配实现信用卡数字识别。
总体分为3步:
- 使用轮廓检测实现数字1-9模板的存取。
- 检测到信用卡的数字部分区域并存储。
- 将信用卡数字依次与模板进行匹配,寻找到最合适的数字
最终效果: 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=[]
for cnt in contours:
boundingBoxes.append(cv.boundingRect(cnt))
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
result: digit={0:image of number 0,1:image of number 1,...,9:image of number 9}
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个数字全部被从原始信用卡图像中提取出来。
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(),
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)):
(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)
|