实战一、OpenCv识别银行卡卡号

本文介绍了使用Python的OpenCV库进行图像处理,包括读取和操作模版图像,轮廓检测,排序,以及模板匹配来识别数字。主要展示了如何对轮廓进行排序,对二值图像进行模板匹配以提取数字。
摘要由CSDN通过智能技术生成
'''
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()

运行结果

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值