python opencv实现信用卡的数字识别
本项目利用python以及opencv实现信用卡的数字识别
前期准备
- 导入工具包
- 定义功能函数
模板图像处理
- 读取模板图像cv2.imread(img)
- 灰度化处理cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
- 二值化cv2.threshold()
- 轮廓-轮廓
信用卡图像处理
- 读取信用卡图像cv2.imread(img)
- 灰度化处理cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
- 礼帽处理cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,rectKernel)
- Sobel边缘检测cv2.Sobel(tophat,ddepth=cv2.CV_32F,dx=1,dy=0,ksize=-1)
- 闭操作cv2.morphologyEx(gradX,cv2.MORPH_CLOSE,rectKernel)
- 计算轮廓cv2.findContours
- 模板检测cv2.matchTemplate(roi,digitROI,cv2.TM_CCOEFF)
原始数据展示
结果展示
1前期准备
#导入工具包 #opencv读取图片的格式为bgr #matplotlib图片的格式为rgb importnumpyasnp importcv2 fromimutilsimportcontours importmatplotlib.pyplotasplt %matplotlibinline
#信用卡的位置 predict_card="images/credit_card_01.png" #模板的位置 template="images/ocr_a_reference.png"
#指定信用卡类型
FIRST_NUMBER={
"3":"AmericanExpress",
"4":"Visa",
"5":"MasterCard",
"6":"DiscoverCard"
}
#定义一些功能函数 #对框进行排序 defsort_contours(cnts,method="left-to-right"): reverse=False i=0 ifmethod=="right-to-left"ormethod=="bottom-to-top": reverse=True ifmethod=="top-to-bottom"ormethod=="bottom-to-top": i=1 boundingBoxes=[cv2.boundingRect(c)forcincnts]#用一个最小的矩形,把找到的形状包起来x,y,h,w (cnts,boundingBoxes)=zip(*sorted(zip(cnts,boundingBoxes), key=lambdab:b[1][i],reverse=reverse)) returncnts,boundingBoxes #调整图片尺寸大小 defresize(image,width=None,height=None,inter=cv2.INTER_AREA): dim=None (h,w)=image.shape[:2] ifwidthisNoneandheightisNone: returnimage ifwidthisNone: 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) returnresized #定义cv2展示函数 defcv_show(name,img): cv2.imshow(name,img) cv2.waitKey(0) cv2.destroyAllWindows()
2对模板图像进行预处理操作
读取模板图像
#读取模板图像
img=cv2.imread(template)
cv_show("img",img)
plt.imshow(img)
模板图像转灰度图像
#转灰度图
ref=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv_show("ref",ref)
plt.imshow(ref)
转为二值图像
ref=cv2.threshold(ref,10,255,cv2.THRESH_BINARY_INV)[1]
cv_show("ref",ref)
plt.imshow(ref)
计算轮廓
#cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),cv2.RETR_EXTERNAL只检测外轮廓,cv2.CHAIN_APPROX_SIMPLE只保留终点坐标
#返回的list中每个元素都是图像中的一个轮廓
#在二值化后的图像中计算轮廓
refCnts,hierarchy=cv2.findContours(ref.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#在原图上画出轮廓
cv2.drawContours(img,refCnts,-1,(0,0,255),3)
cv_show("img",img)
plt.imshow(img)
print(np.array(refCnts).shape)
#排序,从左到右,从上到下
refCnts=sort_contours(refCnts,method="left-to-right")[0]
digits={}
#遍历每一个轮廓
for(i,c)inenumerate(refCnts):
#计算外接矩形并且resize成合适大小
(x,y,w,h)=cv2.boundingRect(c)
roi=ref[y:y+h,x:x+w]
roi=cv2.resize(roi,(57,88))
#每一个数字对应每一个模板
digits[i]=roi
(10,)
3对信用卡进行处理
初始化卷积核
rectKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(9,3)) sqKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
读取信用卡
image=cv2.imread(predict_card)
cv_show("image",image)
plt.imshow(image)
对图像进行预处理操作
#先对图像进行resize操作
image=resize(image,width=300)
#灰度化处理
gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
cv_show("gray",gray)
plt.imshow(gray)
对图像礼帽操作
- 礼帽=原始输入-开运算结果
- 开运算:先腐蚀,再膨胀
- 突出更明亮的区域
tophat=cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,rectKernel)
cv_show("tophat",tophat)
plt.imshow(tophat)
用Sobel算子边缘检测
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)))
gradX=gradX.astype("uint8")
print(np.array(gradX).shape)
cv_show("gradX",gradX)
plt.imshow(gradX)
(189,300)
对图像闭操作
- 闭操作:先膨胀,再腐蚀
- 可以将数字连在一起
gradX=cv2.morphologyEx(gradX,cv2.MORPH_CLOSE,rectKernel)
cv_show("gradX",gradX)
plt.imshow(gradX)
#THRESH_OTSU会自动寻找合适的阈值,适合双峰,需把阈值参数设置为0
thresh=cv2.threshold(gradX,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
cv_show("thresh",thresh)
plt.imshow(thresh)
#再进行一次闭操作
thresh=cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,sqKernel)#再来一个闭操作
cv_show("thresh",thresh)
plt.imshow(thresh)
计算轮廓
threshCnts,hierarchy=cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts=threshCnts
cur_img=image.copy()
cv2.drawContours(cur_img,cnts,-1,(0,0,255),3)
cv_show("img",cur_img)
plt.imshow(cur_img)
locs=[] #遍历轮廓 for(i,c)inenumerate(cnts): #计算矩形 (x,y,w,h)=cv2.boundingRect(c) ar=w/float(h) #选择合适的区域,根据实际任务来,这里的基本都是四个数字一组 ifar>2.5andar<4.0: if(w>40andw<55)and(h>10andh<20): #符合的留下来 locs.append((x,y,w,h)) #将符合的轮廓从左到右排序 locs=sorted(locs,key=lambdax:x[0]) output=[]
模板匹配
#遍历每一个轮廓中的数字
for(i,(gX,gY,gW,gH))inenumerate(locs):
#initializethelistofgroupdigits
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=contours.sort_contours(digitCnts,method="left-to-right")[0]
#计算每一组中的每一个数值
forcindigitCnts:
#找到当前数值的轮廓,resize成合适的的大小
(x,y,w,h)=cv2.boundingRect(c)
roi=group[y:y+h,x:x+w]
roi=cv2.resize(roi,(57,88))
cv_show("roi",roi)
#计算匹配得分
scores=[]
#在模板中计算每一个得分
for(digit,digitROI)indigits.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)
#打印结果
print("CreditCardType:{}".format(FIRST_NUMBER[output[0]]))
print("CreditCard#:{}".format("".join(output)))
cv_show("Image",image)
plt.imshow(image)
CreditCardType:Visa CreditCard#:4000123456789010
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。