需求描述:
通過(guò)OpenCV識(shí)別身份證照片上的身份證號(hào)碼(僅識(shí)別身份證號(hào)碼)
實(shí)現(xiàn)思路:
1.將身份證號(hào)中的0,1,2,3,4,5,6,7,8,9作為模板,與身份證照片中的身份證號(hào)碼區(qū)域進(jìn)行模板匹配。
2.先要制作一個(gè)身份證號(hào)碼模板,我這里弄了一個(gè),基本上可以用。
?3.識(shí)別出身份證照片身份證號(hào)區(qū)域,進(jìn)行圖像模板匹配。
? ?以下面這樣圖為例(你也可以替換為你要識(shí)別的圖片):
?4.識(shí)別出身份證號(hào)碼后,在圖中標(biāo)記出識(shí)別結(jié)果。
運(yùn)行效果:
Python源代碼(目前只能識(shí)別標(biāo)準(zhǔn)角度拍攝照片,拍攝角度變形的無(wú)法識(shí)別):
import cv2
import numpy as np
rectKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(15,15)) #kernel1 = np.ones((15, 15), np.uint8)
sqKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
#輪廓排序
def sort_contours(cnts,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
boundingBoxes=[cv2.boundingRect(c) for c in cnts] #外接矩形
(cnts,boundingBoxes)=zip(*sorted(zip(cnts,boundingBoxes),key=lambda b:b[1][i],reverse=reverse))
return cnts,boundingBoxes
# 第一步:預(yù)處理模板文件
templateImg = cv2.imread("template.jpg") #template.jpg 即為模板文件,上面那張0-9數(shù)字圖片
templateImg = cv2.resize(templateImg, (900, 200), interpolation=cv2.INTER_CUBIC)
#轉(zhuǎn)灰度圖
templateGray=cv2.cvtColor(templateImg,cv2.COLOR_BGR2GRAY)
cv2.imshow("1.1 templateGray",templateGray)
#二值處理
templateGray=cv2.threshold(templateGray,30,255,cv2.THRESH_BINARY_INV)[1]
# cvblackhat = cv2.morphologyEx(templateGray, cv2.MORPH_BLACKHAT, np.ones((50, 50), np.uint8))
# templateGray=cv2.threshold(cvblackhat,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
cv2.imshow("1.2 threshold",templateGray)
#提取輪廓(10個(gè)數(shù)字的外部輪廓)
templateContours,hierarchy=cv2.findContours(templateGray.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(templateImg,templateContours,-1,(0,0,255),3)
cv2.imshow("1.3 drawContours",templateImg)
templateContours=sort_contours(templateContours,method="left-to-right")[0]
#用于做模板匹配的圖像集合
templates={}
for(i,c) in enumerate(templateContours):
(x,y,w,h)=cv2.boundingRect(c) #外接矩形
roi=templateGray[y:y+h,x:x+w]
roi=cv2.resize(roi,(57,88))
templates[i]=roi
#第二步:處理身份證圖片
# 1.讀取原圖
idimg = cv2.imread("idcard.jpg") #需要進(jìn)行識(shí)別的圖片
idimg = cv2.resize(idimg, (509, 300), interpolation=cv2.INTER_CUBIC)
idimgok = idimg.copy()
cv2.imshow("1.origin", idimg)
#2.轉(zhuǎn)灰度圖
gray = cv2.cvtColor(idimg, cv2.COLOR_BGR2GRAY)
cv2.imshow("2.gray", gray)
#3.黑帽運(yùn)算:移除干擾項(xiàng)
cvblackhat = cv2.morphologyEx(gray, cv2.MORPH_BLACKHAT, rectKernel)
cv2.imshow("3.black", cvblackhat)
#4.頂帽運(yùn)算:突出輪廓
tophat=cv2.morphologyEx(cvblackhat,cv2.MORPH_TOPHAT,rectKernel)
cv2.imshow("4.tophat", tophat)
#5.邊緣檢測(cè)
sobel=cv2.Sobel(tophat,ddepth=cv2.CV_32F,dx=1,dy=0,ksize=-1)
sobel=np.absolute(sobel)
(min,max)=(np.min(sobel),np.max(sobel))
sobel=(255*((sobel-min)/(max-min)))
sobel=sobel.astype("uint8")
cv2.imshow("5.sobel", sobel)
#6.閉操作,先膨脹,再腐蝕
sobel=cv2.morphologyEx(sobel,cv2.MORPH_CLOSE,rectKernel)
cv2.imshow("6.close", sobel)
#7.二值化突出輪廓,自動(dòng)閾值范圍 cv2.THRESH_BINARY|cv2.THRESH_OTSU
thresh=cv2.threshold(sobel,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
cv2.imshow("7.thresh", thresh)
#8.再閉操作,先膨脹,再腐蝕
thresh=cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,sqKernel)
cv2.imshow("8.close2", thresh)
#9.提取輪廓,并在圖上標(biāo)記輪廓
cnts,hierarchy=cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
mark=idimg.copy()
cv2.drawContours(mark,cnts,-1,(0,0,255),2)
cv2.imshow("9.mark", mark)
#身份證區(qū)域,雖然只有一個(gè)輪廓,這里還是用集合來(lái)處理
pidArea=[]
for(i,c) in enumerate(cnts):
(x,y,w,h)=cv2.boundingRect(c)
ar=w/float(h)
if ar>12 and ar<40:
pidArea.append((x,y,w,h)) #身份證號(hào)區(qū)域長(zhǎng)寬比比較明顯,算是一個(gè)比較明顯的特征
break
#pidArea=sorted(pidArea,key=lambda x:x[0])#若有多個(gè)區(qū)域,需進(jìn)行從左到右排序
#10.模板匹配
output=[]
for(i,(gx,gy,gw,gh)) in enumerate(pidArea):
area=gray[gy-5:gy+gh+5,gx-5:gx+gw+5] #稍微擴(kuò)展點(diǎn)區(qū)域,保證內(nèi)容都能框住
cv2.imshow("9.matched", area)
#下面操作跟處理模板圖像一樣:
#先黑帽處理,移除干擾項(xiàng),再二值化處理(自動(dòng)閾值)
area = cv2.morphologyEx(area, cv2.MORPH_BLACKHAT, np.ones((10, 10), np.uint8))
area=cv2.threshold(area,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
cv2.imshow("10.threshold", area)
# 再檢測(cè)輪廓
numContours,hierarchy=cv2.findContours(area.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#注意:此處需判斷輪廓的個(gè)數(shù)是否是18個(gè),對(duì)應(yīng)18個(gè)數(shù)字
numContours=sort_contours(numContours,method="left-to-right")[0]
#11.遍歷輪廓,并逐個(gè)與模板圖像進(jìn)行匹配,將最高得分保留
for c in numContours:
(x,y,w,h)=cv2.boundingRect(c)
roi=area[y:y+h,x:x+w]
roi=cv2.resize(roi,(57,88)) #模板也做了縮放,相同尺寸進(jìn)行比較
scores=[]
#跟10張模板圖片進(jìn)行模板匹配
for (j,templateROI)in templates.items():
result=cv2.matchTemplate(roi,templateROI,cv2.TM_CCOEFF)
(_,score,_,_)=cv2.minMaxLoc(result)
scores.append(score) #scores中存放了當(dāng)前輪廓對(duì)應(yīng)0-10中每個(gè)數(shù)字的概率
#將分值最大的保留下來(lái)
num=np.argmax(scores) #np.argmax():獲取array的某一個(gè)維度中數(shù)值最大的那個(gè)元素的索引,索引即為對(duì)應(yīng)數(shù)字
output.append(str(num))
#12.在原圖上繪制識(shí)別結(jié)果
index=0
(gx,gy,gw,gh)=pidArea[0] #身份證區(qū)域位置
for c in numContours:
(x,y,w,h)=cv2.boundingRect(c) #數(shù)字輪廓位置
num=output[index]
cv2.putText(idimg,str(num),(gx+x-8 ,gy+y-15),cv2.FONT_HERSHEY_SIMPLEX,0.65,(0,0,255),2)
index=index+1
cv2.imshow("12.done", idimg)
print("識(shí)別結(jié)果:"+"".join(output))
cv2.waitKey(0)
?運(yùn)行結(jié)果:
模板處理
圖像處理
?特別說(shuō)明:
1.對(duì)輸入身份證照片有要求,必須是完全的身份證照片,不能有背景,不能變形。
2.只識(shí)別了身份證號(hào)區(qū)域,如需識(shí)別其他信息,可以自行修改代碼。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-506320.html
3.如無(wú)法識(shí)別你的圖片,請(qǐng)手動(dòng)調(diào)試代碼,注釋都在代碼里,修改對(duì)應(yīng)步驟參數(shù),多試幾次。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-506320.html
到了這里,關(guān)于8.OpenCV-識(shí)別身份證號(hào)碼(Python)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!