目录
项目Introduce:
项目名称:
具体操作步骤以及代码:
实现结果展示:
代码整体展示:
项目Introduce:
项目名称:
通过导入模板数字,对银行卡面上的数字进行识别,提取出银行卡面上的银行卡号。
项目流程预览:
1.处理模板图像,获取模板数字
2.导入银行卡图像
3.提取银行卡上的ROI
4.将模板数字与ROI二者的二值图像进行模板匹配
5.将匹配结果展示在银行卡上
项目与知识衔接:
图像预处理、边缘检测、模板匹配......
具体操作步骤以及代码:
1.导入工具包(库)
from imutils import contours
import numpy as np
import argparse #用于添加参数
import imutils #依赖numpy
import cv2
import myutils #自设定的一个文件
myutils代码:
import cv2def sort_contours(cnts, method="left-to-right"):reverse = Falsei = 0if method == "right-to-left" or method == "bottom-to-top":reverse = Trueif method == "top-to-bottom" or method == "bottom-to-top":i = 1boundingBoxes = [cv2.boundingRect(c) for c in cnts] # 用一个最小的矩形,把找到的形状包起来x,y,h,w(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),key=lambda b: b[1][i], reverse=reverse))return cnts, boundingBoxesdef 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 imageif 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)return resized
2.调参
有两个参数需要处理(-i : 需要识别的图像、-t :模板)
#设置参数
ap = argparse.ArgumentParser()
ap.add_argument('-i','--image',required=True,help = 'path to input image')
ap.add_argument('-t','--template',required=True,help = 'path to template OCR-A image')
args = vars(ap.parse_args())#定义银行卡信息
FIRST_NUMBER = {'3':'American Express','4':'Viso','5':'MasterCard','6':'Discover Card'
}
#自定义创建窗口函数
def cv_show(name,img):cv2.imshow(name,img)cv2.waitKey(0)cv2.destroyAllWindows()
参数调完后需要输入形参数据,就是你想进行匹配的模板和待检测图像,Pycharm中可以进行如下操作:
1.右键文件点击Modify Run Configuration(修改运行配置)
2.找到Parameters(形参数据)
输入如下:(自行修改其中数据,第一个路径为待检测的银行卡图片路径,不含中字且将\改为/,第二个为模板数字图片的路径)
-i D:/works/pyton_pic/credit_card.png -t D:/works/pyton_pic/ocr_a_reference.png
点击Apply-OK
3.导入模板并处理
(1)读入模板图像
#读入模板图像
img = cv2.imread(args['template'])
cv_show('img',img)
(2)模板图像转换为灰度图
#灰度处理
ref = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv_show('ref',ref)
(3)灰度图转换为二值图
#二值处理
ref = cv2. threshold(ref,10,255,cv2.THRESH_BINARY_INV)[1]
#[1]代表取元组的第一位展示(本来应该是ref,TRESHOLD_BINARY_INV双参)
cv_show('ref',ref)
(4)找到所有数字的外轮廓
#轮廓检测
refCnts,hierarcy = cv2.findContours(ref.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#cv2.RETR_EXTERMAL是只检测外轮廓
#cv2.CHAIN_APPROX_SIMPLE 是保留坐标点
(5)将轮廓画出
#画出轮廓
cv2.drawContours(img,refCnts,-1,(0,0,255),3)
cv_show('img',img)
(6)对找到的轮廓排序,得到轮廓集合
#轮廓排序
refCnts = myutils.sort_contours(refCnts,method='left-to=right')[0]
(7)将每个数字制成一个模板
#定义一个空字典
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] = roicv_show('roi',roi)
4.导入银行卡图像并处理
(1)初始化卷积核
cv2.getStructingElement 是cv2中定义核的一个函数,MORPH_CROSS代表卷积核的形状是矩形,还有交叉形MORPH_ELLIPSE,(9,3)和(5,5)是卷积核的大小,默认(-1,-1)为中心点。
#初始化卷积核
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
(2)读取银行卡图像
#读取图像
image = cv2.imread(args['image'])
cv_show('image',image)
(3)银行卡图像转为灰度图
#调整图像的尺寸、并进行图像灰度化
image = myutils.resize(image,width=300)
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
cv_show('gray',gray)
(4)灰度图进行礼帽操作
#礼帽操作,使用(9,3)大小的卷积核
tophat = cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,rectKernel)
cv_show('tophat',tophat)
(5)利用Sobel算子进行边缘检测
#计算横向梯度 sobel边缘检测
gradX = cv2.Sobel(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')#把图像从CV_32F转化为uint8
cv_show('gradX',gradX)
(6)Sobel算子运算后的图像进行闭操作
#闭运算
gradX = cv2.morphologyEx(gradX,cv2.MORPH_CLOSE,rectKernel)
cv_show('gradX',gradX)
(7)闭操作后的图像进行二值化(threshold)
#二值处理
thresh = cv2.threshold(gradX,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
#cv2.cv2.THRESH_OTSU为自动判断合适值代替0
cv_show('thresh',thresh)
(8)二值化后的图像再次进行闭操作
#闭运算 目的是把区域中的黑色填充成白色
thresh = cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,sqKernel)
cv_show('thresh-close',thresh)
(9)找出并画出轮廓,对轮廓进行筛选得出ROI(根据数字区域的W/H;以及图像大小范围)
#计算轮廓
#轮廓检测
threshCnts,hierarcy = cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#cv2.RETR_EXTERMAL是只检测外轮廓
#cv2.CHAIN_APPROX_SIMPLE 是保留坐标点#画出轮廓
cur_img = image.copy()
cv2.drawContours(cur_img,threshCnts,-1,(0,0,255),3)
# cv_show('cur_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))print(locs)
遍历四个轮廓,找出外界轮廓位置图像:
#轮廓排序
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]# cv_show ('group',group)
二值化后:
#二值处理group = cv2.threshold(group,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]# cv_show('group',group)
(10)对ROI进行排序,提取ROI中的每一位数字进行模板匹配,筛选出最符合的数字
对ROI进行排序:
#检测轮廓并且排序digitCnts,hierarchy = cv2.findContours(group.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)digitCnts = imutils.contours.sort_contours(digitCnts,method = 'left-to-right')[0]#提取轮廓矩形获得ROIfor c in digitCnts:(x,y,w,h) = cv2.boundingRect(c)roi = group[y:y+h,x:x+w]roi = cv2.resize(roi,(57,99))cv_show('roi',roi)
进行模板匹配获得的数值,取每10个中最大的数值,加入groupOutput:
#对ROI进行模板匹配scores = []for (digit,digitROI) in digits.items():result = cv2.matchTemplate(roi,digitROI,cv2.TM_CCOEFF)(_,score, _, _) = cv2.minMaxLoc(result)scores.append(score)print(scores)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)cv_show('image',image)
5.展示结果
将模板匹配获得的索引放入output,然后根据output[0]判断银行卡类型,最后显示结果
output.extend(groupOutput)
# print(output)
print(FIRST_NUMBER[output[0]])
print(output)
cv_show('image',image)
实现结果展示:
代码整体展示:
#导入工具包
from imutils import contours
import numpy as np
import argparse
import imutils
import cv2
import myutils#设置参数
ap = argparse.ArgumentParser()
ap.add_argument('-i','--image',required=True,help = 'path to input image')
ap.add_argument('-t','--template',required=True,help = 'path to template OCR-A image')
args = vars(ap.parse_args())#定义银行卡信息
FIRST_NUMBER = {'3':'American Express','4':'Viso','5':'MasterCard','6':'Discover Card'
}
#自定义创建窗口函数
def cv_show(name,img):cv2.imshow(name,img)cv2.waitKey(0)cv2.destroyAllWindows()#处理模板#读入模板图像
img = cv2.imread(args['template'])
cv_show('img',img)#灰度处理
ref = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv_show('ref',ref)#二值处理
ref = cv2. threshold(ref,10,255,cv2.THRESH_BINARY_INV)[1] #[1]代表取元组的第一位展示(本来应该是ref,TRESHOLD_BINARY_INV双参)
cv_show('ref',ref)#轮廓检测
refCnts,hierarcy = cv2.findContours(ref.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#cv2.RETR_EXTERMAL是只检测外轮廓
#cv2.CHAIN_APPROX_SIMPLE 是保留坐标点#画出轮廓
cv2.drawContours(img,refCnts,-1,(0,0,255),3)
cv_show('img',img)
# print(np.array(refCnts).shape)#轮廓排序
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] = roicv_show('roi',roi)#处理图像
#初始化卷积核
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))#读取图像
image = cv2.imread(args['image'])
cv_show('image',image)#调整图像的尺寸、并进行图像灰度化
image = myutils.resize(image,width=300)
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
cv_show('gray',gray)#礼帽操作,使用(9,3)大小的卷积核
tophat = cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,rectKernel)
cv_show('tophat',tophat)#计算横向梯度 sobel边缘检测
gradX = cv2.Sobel(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')#把图像从CV_32F转化为uint8
cv_show('gradX',gradX)#闭运算
gradX = cv2.morphologyEx(gradX,cv2.MORPH_CLOSE,rectKernel)
cv_show('gradX',gradX)#二值处理
thresh = cv2.threshold(gradX,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
#cv2.cv2.THRESH_OTSU为自动判断合适值代替0
cv_show('thresh',thresh)#闭运算 目的是把区域中的黑色填充成白色
thresh = cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,sqKernel)
cv_show('thresh-close',thresh)
#计算轮廓
#轮廓检测
threshCnts,hierarcy = cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#cv2.RETR_EXTERMAL是只检测外轮廓
#cv2.CHAIN_APPROX_SIMPLE 是保留坐标点#画出轮廓
cur_img = image.copy()
cv2.drawContours(cur_img,threshCnts,-1,(0,0,255),3)
cv_show('cur_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))# print(locs)#轮廓排序
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]cv_show ('group',group)#二值处理group = cv2.threshold(group,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]cv_show('group',group)#检测轮廓并且排序digitCnts,hierarchy = cv2.findContours(group.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)digitCnts = imutils.contours.sort_contours(digitCnts,method = 'left-to-right')[0]#提取轮廓矩形获得ROIfor c in digitCnts:(x,y,w,h) = cv2.boundingRect(c)roi = group[y:y+h,x:x+w]roi = cv2.resize(roi,(57,99))cv_show('roi',roi)#对ROI进行模板匹配scores = []for (digit,digitROI) in digits.items():result = cv2.matchTemplate(roi,digitROI,cv2.TM_CCOEFF)(_,score, _, _) = cv2.minMaxLoc(result)scores.append(score)print(scores)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)cv_show('image',image)output.extend(groupOutput)
# print(output)
print(FIRST_NUMBER[output[0]])
print(output)
cv_show('image',image)