opencv进阶篇---银行卡数字识别
執行結果:
主要思想:對模板圖像以及待檢測圖像進行外輪廓檢測,并得到各自外接矩形,將模板圖像的外接矩形做resize()操作,使其外接矩形的大小與待檢測圖像外接矩形的大小相一致,然后與待檢測圖形做模板匹配
準備工作:
1、轉為為灰度圖像
2、轉化為二值圖像,才能做輪廓檢測
3、根據輪廓的長寬比例的不同,過濾掉一些銀行卡上無用的干擾信息
4、上面的步驟僅能得到一些大致的輪廓,還需做一些形態學操作,然后對數字進行拆分,得到更為精確的數字信息
注意:在找模板時,應該找字體十分接近的字體作為模板
(1)模板預處理過程:將模板中的每一個數字分別進行灰度轉換、二值化、輪廓查找、輪廓繪制、resize()輪廓的大小并且將每個數字的輪廓值(排好序的)存入字典類型的變量中
模板圖:
預處理之后的模板圖:
代碼片段:
(2)待檢測圖像預處理過程:主要包括形態學操作去噪點、灰度轉換、二值化、Sobel()函數求梯度、輪廓相關操作(輪廓的查找、輪廓的繪制、外接輪廓、根據輪廓的長寬比來對輪廓就行篩選、排序)再到遍歷每一塊中的每一個數字
待檢測圖像原圖:
執行一次頂帽操作:
執行一次Sobel()求X方向上的梯度操作:求圖中較為明亮的區域
執行一次閉操作:使圖像上的內容成塊出現
執行一次二值化操作:過濾掉雜亂信息
再執行一次閉操作:填補白色塊中的小黑塊
執行輪廓檢測、輪廓繪制:
后續再根據輪廓的長寬比對輪廓進行篩選,篩選出需要的輪廓信息,工寄檢測出4組有用的輪廓信息,并循環遍歷這四組輪廓中的每一個數字,方法與上面同。
完整代碼:
import cv2 as cv from imutils import contours import matplotlib as plt import numpy as np FIRST_NUMBER = {"3": "American Express","4": "Visa","5": "MasterCard","6": "Discover Card" } #對模板圖像做預處理img=cv.imread("E:\OpenCVTests\Samples\sample/nine/template-matching-ocr\images\ocr_a_reference.png") gray=cv.cvtColor(img,cv.COLOR_BGR2GRAY) ret,ref=cv.threshold(gray,10,255,cv.THRESH_BINARY_INV)#此步驟,應該加前面的ret,否則會報錯 refCnts,hierarchy=cv.findContours(ref.copy(),cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE) #后面還要繼續使用ref,因此需使用ref.copy(),否則會對原圖做出改變;第二個參數為指定檢測外輪廓;第三個參數為輪廓逼近的一種方法 cv.drawContours(img,refCnts,-1,(0,0,255),3)#-1表示繪制所有輪廓,當指定為其他值時,只在圖像中選擇一個繪制單個輪廓 refCnts=contours.sort_contours(refCnts,method="left-to-right")[0]#返回排序完的輪廓 digits={}#建立一個字典類型,i是輪廓索引,c是輪廓----字典類型:每個索引號對應一個索引值 for(i,c)in enumerate(refCnts):#i是輪廓索引,c是對應輪廓,則完成了對檢測出來的輪廓進行了排序(x,y,w,h)=cv.boundingRect(c)#得到沒一個外接矩形的左上坐標點以及長度、寬度roi=ref[y:y+h,x:x+w]#每個數字的外接矩形的尺寸roi=cv.resize(roi,(57,88))#重置外接矩形的尺寸至合適大小digits[i]=roi#每個數字對應一個模板#對待檢測圖像做預處理 recKernel=cv.getStructuringElement(cv.MORPH_RECT,(10,3))#為保證檢測信息準確,需去除銀行卡頁面雜亂信 sqKernel=cv.getStructuringElement(cv.MORPH_RECT,(2,2))#因此需要對圖像做形態學操作,故在此設立卷積核image=cv.imread("E:\OpenCVTests\Samples\sample/nine/template-matching-ocr\images\credit_card_01.png") image=cv.resize(image,(250,200)) gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY) tophat=cv.morphologyEx(gray,cv.MORPH_TOPHAT,recKernel)#根據字體的大小來選定合適的核;頂帽操作來突出明亮的區域gradx=cv.Sobel(tophat,ddepth=cv.CV_32F,dx=1,dy=0,ksize=3)#對X還是對Y需要或者同時需要根據實際需要來設定,圖像梯度 gradx=np.absolute(gradx)#取絕對值 (minVal,maxVal)=(np.min(gradx),np.max(gradx))#歸一化 gradx=(255*((gradx-minVal)/(maxVal-minVal))) gradx=gradx.astype("uint8")gradx=cv.morphologyEx(gradx,cv.MORPH_CLOSE,recKernel)#執行閉操作,使圖像上的內容成塊出現 ret,thresh=cv.threshold(gradx,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)#低閾值之所以設為0,是因為后面的方法選用了OTSU自動設定閾值,適合雙峰的圖像操作 thresh=cv.morphologyEx(thresh,cv.MORPH_CLOSE,sqKernel)#本次閉操作是為了填補二值化圖像中塊中的不完整小塊 Cnts,hierarchy=cv.findContours(thresh.copy(),cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE) cnts=Cnts curImage=image.copy() cv.drawContours(curImage,cnts,-1,(0,0,255),3)#此處輪廓不是原圖像的輪廓,而是經歷了一些列運算之后的圖像的輪廓 locs=[] for (i,c)in enumerate(cnts):(x,y,w,h)=cv.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]#取輪廓及其周圍的區域cv.imshow("group",group)group=cv.threshold(group,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)[1]#后面的[]要加,否則會報錯元組類型不能copy,下面再對每個塊進行輪廓檢測、繪制digitCnts,hierarchy=cv.findContours(group.copy(),cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)#每一個group再進行輪廓檢測、繪制digitCnts=contours.sort_contours(digitCnts,method="left-to-right")[0]for c in digitCnts:#計算每一組數中的每一個數值(x,y,w,h)=cv.boundingRect(c)roi=group[y:y+h,x:x+w]roi=cv.resize(roi,(57,88))#尺寸需與模板的尺寸對應,得到每一個數字所在的區域scores=[]#新建一個空列表,用來存儲檢測到的數字for (digit,digitROI)in digits.items():#在模板預處理中建立了數值的字典類型,一個為索引、一個為值result=cv.matchTemplate(roi,digitROI,cv.TM_CCOEFF)#匹配,返回與之匹配度最高的數值(_,score,_,_)=cv.minMaxLoc(result)#做10次匹配,取最大值(注意:取最大值還是最小值跟選取的模板匹配方法有關)scores.append(score)groupOutput.append(str(np.argmax(scores)))cv.rectangle(image,(gx-5,gy-5),(gx+gw+5,gy+gh+5),(0,0,255),1)#第一組的矩形框cv.putText(image,"".join(groupOutput),(gx,gy-15),cv.FONT_HERSHEY_SIMPLEX,0.65,(0,0,255),2)output.extend(groupOutput) print("Credit Card Type: {}".format(FIRST_NUMBER[output[0]])) print("Credit Card #: {}".format("".join(output))) cv.imshow("Image",image)cv.waitKey(0) cv.destroyAllWindows()總結
以上是生活随笔為你收集整理的opencv进阶篇---银行卡数字识别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: EyouCMS石材板材建筑材料公司网站模
- 下一篇: 第17家图商名落宽凳,正式获导航电子地图