首先我们先来引入我们所需要的库和我们定义的图像显示(方便):
import cv2
import numpy as np
import imutils
from imutils import contours#显示图像
def cv_show(img,name="image"):cv2.imshow(name,img)cv2.waitKey(0)cv2.destroyWindow(name)
其次我们来引入银行卡数字的模板并进行预处理操作:
template=cv2.imread('TT.jpg')
# cv_show(template)
#化为灰度图
ref_template=cv2.cvtColor(template,cv2.COLOR_BGR2GRAY)
# cv_show(ref_template)
#化为二值图
ref_template=cv2.threshold(ref_template,10,255,cv2.THRESH_BINARY_INV)[1]
# cv_show(ref_template)#轮廓检测
##findContours 只接受二值图 RETR_EXTERNAL 只检测外轮廓 CHAIN_APPROX_SIMPLE 只保留终点坐标
BIT,refCnts,hierarchy=cv2.findContours(ref_template.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(template,refCnts,-1,(0,0,255),3)
# cv_show(template)
# print(np.array(refCnts).shape)
#轮廓排序
refCnts=contours.sort_contours(refCnts,method="left-to-right")[0]
# print(refCnts)digits={}
for (i,c) in enumerate(refCnts):#计算外接矩形(x,y,w,h)=cv2.boundingRect(c)roi=ref_template[y:y+h,x:x+w]#resize成合适大小roi=cv2.resize(roi,(57,88))# cv_show(roi)#每个数字对应一个模板digits[i]=roi
接下来把我们需要识别的银行卡引入并进行处理:
#初始化卷积核
rectKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
sqKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))#读取输入图像
image=cv2.imread('T1.jpg')# cv_show(image)
image=imutils.resize(image,width=300)
image_gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# cv_show(image_gray)#tophat顶帽操作,突出明亮区域
image_tophat=cv2.morphologyEx(image_gray,cv2.MORPH_TOPHAT,rectKernel)
# cv_show(image_tophat)#计算梯度 使得轮廓更加清晰
gradX=cv2.Sobel(image_tophat,ddepth=cv2.CV_32F,dx=1,dy=0,ksize=-1)#ksize=-1表示用3*3的和核
gradX=np.absolute(gradX)
(minVal,maxVal)=(np.min(gradX),np.max(gradX))
gradX=(255*(gradX-minVal)/(maxVal-minVal))
gradX=gradX.astype("uint8")
# print(np.array(gradX).shape)
# cv_show(gradX)#闭操作(先膨胀后腐蚀)把数字连在一起
gradX=cv2.morphologyEx(gradX,cv2.MORPH_CLOSE,rectKernel)
# cv_show(gradX)#二值化
image_thresh=cv2.threshold(gradX,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
# cv_show(image_thresh)#二值化后再次闭操作
image_thresh=cv2.morphologyEx(image_thresh,cv2.MORPH_CLOSE,sqKernel)
# cv_show(image_thresh)#计算轮廓
BITT,threshCnts,hierarchy=cv2.findContours(image_thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)cv2.drawContours(image.copy(),threshCnts,-1,(0,0,255),1)
# cv_show(image)
最后就是我们来匹配银行卡模板和数字模板的:
locs=[]
for (i,c) in enumerate(threshCnts):(x,y,w,h)=cv2.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):# gx,gy,gw,gh 代表 4000 这一片区域groupOutput=[]#提取每一组数字(一组包括4个数字)group=image_gray[gy-5:gy+gh+5,gx-5:gx+gw+5]# cv_show(group)group=cv2.threshold(group,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]# cv_show(group)B,digitsCnts,A=cv2.findContours(group.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)digitsCnts=imutils.contours.sort_contours(digitsCnts,method="left-to-right")[0]# print(digitsCnts)for c in digitsCnts: #遍历每一个数字 如4000 依次遍历4、0、0、0(x,y,w,h)=cv2.boundingRect(c)# print((x,y,w,h))roi=group[y:y+h,x:x+w]#把匹配图像设置成模板图像一致大小roi=cv2.resize(roi,(57,88))# cv_show(roi)#计算匹配得分scores=[]for (digit,digitROI) in digits.items():#模板匹配result=cv2.matchTemplate(roi,digitROI,cv2.TM_CCOEFF)(_,score,_,_)=cv2.minMaxLoc(result)scores.append(score)groupOutput.append(str(np.argmax(scores)))cv2.rectangle(image,(gx-5,gy-5),(gx+gw+5,gy+gh+5),(0,0,255),1)cv2.putText(image,"".join(groupOutput),(gx,gy-15),cv2.FONT_HERSHEY_SIMPLEX,0.65,(0,0,255),2)output.extend(groupOutput)cv_show(image)
print("".join(output))
最后所显示的结果。
完整代码奉上:
import cv2
import numpy as np
import imutils
from imutils import contours#显示图像
def cv_show(img,name="image"):cv2.imshow(name,img)cv2.waitKey(0)cv2.destroyWindow(name)template=cv2.imread('TT.jpg')
# cv_show(template)
#化为灰度图
ref_template=cv2.cvtColor(template,cv2.COLOR_BGR2GRAY)
# cv_show(ref_template)
#化为二值图
ref_template=cv2.threshold(ref_template,10,255,cv2.THRESH_BINARY_INV)[1]
# cv_show(ref_template)#轮廓检测
##findContours 只接受二值图 RETR_EXTERNAL 只检测外轮廓 CHAIN_APPROX_SIMPLE 只保留终点坐标
BIT,refCnts,hierarchy=cv2.findContours(ref_template.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(template,refCnts,-1,(0,0,255),3)
# cv_show(template)
# print(np.array(refCnts).shape)
#轮廓排序
refCnts=contours.sort_contours(refCnts,method="left-to-right")[0]
# print(refCnts)digits={}
for (i,c) in enumerate(refCnts):#计算外接矩形(x,y,w,h)=cv2.boundingRect(c)roi=ref_template[y:y+h,x:x+w]#resize成合适大小roi=cv2.resize(roi,(57,88))# cv_show(roi)#每个数字对应一个模板digits[i]=roi#初始化卷积核
rectKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
sqKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))#读取输入图像
image=cv2.imread('T1.jpg')# cv_show(image)
image=imutils.resize(image,width=300)
image_gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# cv_show(image_gray)#tophat顶帽操作,突出明亮区域
image_tophat=cv2.morphologyEx(image_gray,cv2.MORPH_TOPHAT,rectKernel)
# cv_show(image_tophat)#计算梯度 使得轮廓更加清晰
gradX=cv2.Sobel(image_tophat,ddepth=cv2.CV_32F,dx=1,dy=0,ksize=-1)#ksize=-1表示用3*3的和核
gradX=np.absolute(gradX)
(minVal,maxVal)=(np.min(gradX),np.max(gradX))
gradX=(255*(gradX-minVal)/(maxVal-minVal))
gradX=gradX.astype("uint8")
# print(np.array(gradX).shape)
# cv_show(gradX)#闭操作(先膨胀后腐蚀)把数字连在一起
gradX=cv2.morphologyEx(gradX,cv2.MORPH_CLOSE,rectKernel)
# cv_show(gradX)#二值化
image_thresh=cv2.threshold(gradX,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
# cv_show(image_thresh)#二值化后再次闭操作
image_thresh=cv2.morphologyEx(image_thresh,cv2.MORPH_CLOSE,sqKernel)
# cv_show(image_thresh)#计算轮廓
BITT,threshCnts,hierarchy=cv2.findContours(image_thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)cv2.drawContours(image.copy(),threshCnts,-1,(0,0,255),1)
# cv_show(image)locs=[]
for (i,c) in enumerate(threshCnts):(x,y,w,h)=cv2.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):# gx,gy,gw,gh 代表 4000 这一片区域groupOutput=[]#提取每一组数字(一组包括4个数字)group=image_gray[gy-5:gy+gh+5,gx-5:gx+gw+5]# cv_show(group)group=cv2.threshold(group,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]# cv_show(group)B,digitsCnts,A=cv2.findContours(group.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)digitsCnts=imutils.contours.sort_contours(digitsCnts,method="left-to-right")[0]# print(digitsCnts)for c in digitsCnts: #遍历每一个数字 如4000 依次遍历4、0、0、0(x,y,w,h)=cv2.boundingRect(c)# print((x,y,w,h))roi=group[y:y+h,x:x+w]#把匹配图像设置成模板图像一致大小roi=cv2.resize(roi,(57,88))# cv_show(roi)#计算匹配得分scores=[]for (digit,digitROI) in digits.items():#模板匹配result=cv2.matchTemplate(roi,digitROI,cv2.TM_CCOEFF)(_,score,_,_)=cv2.minMaxLoc(result)scores.append(score)groupOutput.append(str(np.argmax(scores)))cv2.rectangle(image,(gx-5,gy-5),(gx+gw+5,gy+gh+5),(0,0,255),1)cv2.putText(image,"".join(groupOutput),(gx,gy-15),cv2.FONT_HERSHEY_SIMPLEX,0.65,(0,0,255),2)output.extend(groupOutput)cv_show(image)
print("".join(output))
不同版本的findContours函数可能会有不同的使用方法,有些高版本的只需要两个返回值。
以上所用的都是以前opencv所学的知识,也可能会有一点没有学到的,