'''
my utils module
'''
import cv2
"""
print a list recursively.
control the sublist indent with 'indent'
"""
def printList (itemList, indent):
for item in itemList:
if(isinstance(item, list)):
printList(item, indent + 1)
else:
for num in range(indent):
print('\t', end='')
print(item)
#对轮廓进行从小到大进行排序
def sort_Contours(contours,method="left-to-right"):
reverse=False
i=0
if method=="right-to-left" or method=="bottom-to-top":
reverse=True
if method=="top-to-bottom" or method=="bottom-to-top":
i=1
#把找到的形状用最小的矩形包起来,外接矩形,x,y,h,w
boundingBoxes=[cv2.boundingRect(c) for c in contours]
#直接用x来判断出来轮廓的排列顺序
(contours,boundingBoxes)=zip(*sorted(zip(contours,boundingBoxes),key=lambda b:b[1][i],reverse=reverse))
return contours,boundingBoxes
def resize(image, width=None, height=None, inter=cv2.INTER_AREA):
dim = None
(h, w) = image.shape[:2] # 获取图像的高度和宽度
if width is None and height is None:
return image
if width is None:
r = height / float(h)
dim = (int(w * r), height)
else:
r = width / float(w)
dim = (width, int(h * r))
resized = cv2.resize(image, dim, interpolation=inter) # 使用cv库的resize函数
return resized
import cv2
import numpy as np
import myutils
#模版图像的处理:
#读入模版图像,将模版图像处理成二值图像
#对二值图像进行轮廓检测,检测外轮廓,并在原始图像上绘制出外轮廓
#对检测到的二值图像的外轮廓进行从小到大的排序,得到排序完成的轮廓。
#遍历每个排序完成的轮廓,用最小的外包矩形包裹它们,得到x,y,w,h,
#然后根据x,y,w,h在二值图像上获取每个数字的最小外包矩形,再缩放到合适的大小,复制给存放数字模版的集合
#模版的灰度图像
img=cv2.imread("/Users/macbook/Desktop/Template.png")
ref=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#将模版图像转换成二值图像:数字变成白色,背景变成黑色
ref=cv2.threshold(ref,10,255,cv2.THRESH_BINARY_INV)[1]
cv2.imshow("original",img)#展示模版的原始图像
cv2.imshow("ref_image",ref)#展示模版的二值图像
#对模版的二值图像进行处理:检测外轮廓
refCnts,hierarchy=cv2.findContours(ref.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#在模版的原始图像上绘制轮廓:红色画笔,厚度3
img=cv2.drawContours(img,refCnts,-1,(0,0,255),3)
cv2.imshow("result1",img)
#对轮廓进行从小到大进行排序,方法返回的是排序完成的轮廓
refCnts=myutils.sort_Contours(refCnts,method="left-to-right")[0]
#做一个空白的字典:里面就是每一个数字模版
digits={}
#遍历每一个轮廓
for(i,c) in enumerate(refCnts):
(x,y,w,h)=cv2.boundingRect(c)#对每一个轮廓,绘制最小的外包矩形
roi=ref[y:y+h,x:x+w]#在二值图像上矩形的区域
roi=cv2.resize(roi,(57,88))#将区域缩放到合适的大小
#每一个数字对应一个模版
digits[i]=roi
#输入数据的处理:
#卷积核
rectKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
sqKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(7,7))
#将输入图像转换成灰度图像
image=cv2.imread("/Users/macbook/Desktop/pattern1.png")#输入银行卡的原始图像
image=myutils.resize(image,width=300)
gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)#将输入的银行卡图像转换成灰度图
cv2.imshow("image",gray)
#对输入图像进行顶帽操作:突出更加明亮的部分,突出银行卡上的字体部分
tophat=cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,rectKernel)
cv2.imshow("tophat",tophat)
#Sobel算子计算图像梯度:在这里只用x比用x+y效果更好
gradX=cv2.Sobel(tophat,ddepth=cv2.CV_32F,dx=1,dy=0)#卷积核默认三行三列
gradX=cv2.convertScaleAbs(gradX)
cv2.imshow("gradX",gradX)
#闭操作:先膨胀再腐蚀,将字体连成一块一块的
#先进行二值处理,转换成二值图像
#THRESH_OTSU会自动寻找阈值
thresh=cv2.threshold(gradX,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
cv2.imshow("thresh",thresh)
#对二值图像进行闭操作处理:
thresh=cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,sqKernel)
#对二值图像再进行一次闭操作处理:填充缝隙
thresh=cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,sqKernel)
cv2.imshow("thresh2",thresh)
#计算轮廓
threshCnts,hierarchy=cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cur_img=image.copy()
cv2.drawContours(cur_img,threshCnts,-1,(0,0,255),3)
cv2.imshow("img",cur_img)
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):
#获取四个轮廓在灰度图中对应的区域
groupOutput=[]
group=gray[gY-5:gY+gH+5,gX-5:gX+gW+5]
cv2.imshow("group",group)
#在每个轮廓中再进行二值化,获取更小的四个轮廓
group=cv2.threshold(group.copy(),0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]
digitCnts,hierarchy=cv2.findContours(group.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)#获取四个更小的轮廓
digitCnts=myutils.sort_Contours(digitCnts,method="left-to-right")[0]#对四个更小的轮廓进行排序
for c in digitCnts:
(x,y,w,h)=cv2.boundingRect(c)#绘制四个更小的轮廓的外包矩形
roi=group[y:y+h,x:x+w]#在四个大轮廓对应区域绘制四个更小的区域
roi=cv2.resize(roi,(57,88))#适应大小
cv2.imshow("roi",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)
cv2.imshow("result",image)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果