首先我们先来引入我们所需要的库和我们定义的图像显示(方便):
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所学的知识,也可能会有一点没有学到的,