opencv练手项目:信用卡数字识别
Posted Y/ang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了opencv练手项目:信用卡数字识别相关的知识,希望对你有一定的参考价值。
整体思路:利用轮廓检测与模板匹配实现信用卡数字识别。
总体分为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=[] #绘制外接矩形,按照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
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个数字全部被从原始信用卡图像中提取出来。
#遍历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)
以上是关于opencv练手项目:信用卡数字识别的主要内容,如果未能解决你的问题,请参考以下文章