from imutils import contours #
import numpy as np
import argparse
import cv2
import sys
sys.path.append(“C:\Users\Admin\Documents\Python Scripts\myModule\”)#引用自定义python模块
import myutils
def cv_show(name,img):#绘图展示
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
#步骤1:处理模板
img=cv2.imread(“C:\Users\Admin\Pictures\net\images\ocr_a_reference.png”)#输入模板图像,输出模板图像矩阵
ref=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#将模板灰度化
ref=cv2.threshold(ref,10,255,cv2.THRESH_BINARY_INV )[1]#将灰度化后的模板二值化
refCnts,hierachy=cv2.findContours(ref.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)#计算模板中10个数字的轮廓
refCnts=myutils.sort_contours(refCnts,method=“left-to-right”)[0]#?将模板中的数字轮廓排序
digits={}
for (i,c) in enumerate(refCnts):
(x,y,w,h)=cv2.boundingRect©#计算每个轮廓的起始坐标和大小
digitROI=ref[y:y+h,x:x+w]#从原始的二值化数据中提取数字轮廓
digitROI=cv2.resize(digitROI,(114,88))#标准化每个数字图像的大小
digits[i]=digitROI#标准化后的每个数字模板
#步骤2:处理图像
##步骤2.1:初始化卷积核
rectKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))#矩形卷积核
sqKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))#正方形卷积核
image=cv2.imread(“C:\Users\Admin\Pictures\net\images\credit_card_03.png”)#读取待识别图像
image=myutils.resize(image,width=300)#将图像大小标准化
gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)#灰度化
cv2.threshold(ref,0,255,cv2.THRESH_BINARY_INV )[1]
##步骤2.2:提取图片特征
tophat=cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,rectKernel)#礼帽突出特征
gradX=cv2.Sobel(tophat,ddepth=cv2.CV_32F,dx=1,dy=0,ksize=-1)#计算图像梯度,边缘检测
gradX=np.absolute(gradX)#图像梯度的绝对值
(minVal,maxVal)=(np.min(gradX),np.max(gradX))#图像梯度的最大值,最小值
gradX=(255*((gradX-minVal)/(maxVal-minVal)))#0-255之间标准化
gradX=gradX.astype(“uint8”)#将浮点数转换为整型
##步骤2.2关键点:将目标数字区域连成一片,便于下一步单独提取出来
gradX=cv2.morphologyEx(gradX,cv2.MORPH_CLOSE,rectKernel)#闭运算,将几个数字区域连成一块儿
thresh=cv2.threshold(gradX,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]#连得更紧密
thresh=cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,sqKernel)#闭运算,#连得越紧密
threshCnts,hierarchy=cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)#外轮廓检测,只保留检测矩形的四个点坐标
###步骤2.3从众多特征中提取出卡号区域
cnts=threshCnts#轮廓副本
cur_img=image.copy()#图像副本
cv2.drawContours(cur_img,cnts,-1,(0,0,255),3)#画出所有特征的轮廓
locs=[]#预定义卡号轮廓位置
for c in cnts:#遍历每一个轮廓
(x,y,w,h)=cv2.boundingRect©#定位到每一个轮廓
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])#将轮廓按顺序排列
##步骤3:特征与模板匹配
##步骤3.1:首先提取出图像中卡号中的每一个数字
output=[]
for (i,(gX,gY,gW,gH)) in enumerate(locs):
groupOutput=[]#initialize the list of group digits
group=gray[gY-5:gY+gH+5,gX-5:gX+gW+5]#提取原始图像的卡号区域
group=cv2.threshold(group,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]#二值化
digitCnts,hierarchy=cv2.findContours(group.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)#找出每个数字的轮廓,此时还是一组
digitCnts=contours.sort_contours(digitCnts,method=“left-to-right”)[0]#排好顺序
##步骤3.2:其次将卡号中的数字与模板进行逐一匹配
for c in digitCnts:
(x,y,w,h)=cv2.boundingRect©#每个数字轮廓的位置
roi=group[y:y+h,x:x+w]#提取每个数字
roi=cv2.resize(roi,(114,88))#将每个数字的大小标准化,与模板中的数字大小一致
roi=cv2.threshold(roi,0,255,cv2.THRESH_BINARY )[1]
scores=[]
for (digit,digitROI) in digits.items():
result=cv2.matchTemplate(roi,digitROI,cv2.TM_SQDIFF_NORMED)#采用归一化的平方差方法才识别出全部的数字出来
( score,_, _, _) = cv2.minMaxLoc(result)#取得最小偏差分数
scores.append(score)#形成最小偏差列表
groupOutput.append(str(np.argmin(scores)))#找到与模板中数值索引相同的数字
##步骤3.3:将匹配结果整理好
output.extend(groupOutput) #拼接列表并将其转成数组,所以要先将数组转成列表。
cv2.rectangle(image,(gX-5,gY-5),(gX+gW+5,gY+gH+5),(0,0,255),1)
#步骤4:结果输出
print(“卡号是: {}”.format("".join(output)))
cv_show(“Image”,image)