(1)引入模塊
import cv2
import numpy as np
import myutils
(2)圖像的基本操作
1.圖像讀取
img=cv2.imread("路徑")
2.圖像顯示
cv2.imshow("窗口名",圖像變量(img))
(3)圖像的輪廓檢測(cè)
1.圖像的灰度化
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
或直接img=cv2,imread("路徑",0)
2.圖像的二值化(黑白圖像)
ref=cv2.threshold(gray,10,255,cv2.THRESH_BINARY_INV)[1]
10,255:表示閾值(超過10取255,小于取0)
cv2.THRESH_BINARY_INV表示取法相反
3.尋找輪廓
refCnt,hierarchy=cv2.findContours(ref,cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
ref表示在輪廓檢測(cè)中要用二值圖像
cv2.RETR_EXTERNAL只尋外輪廓
draw_refCnt=cv2.drawContours(img.copy(),refCnt,-1,(0,0,255),3)
img.copy()為在畫輪廓時(shí)不印象原圖
reCnts表示輪廓
-1表示所有的輪廓
3表示通道3
結(jié)果:
4.模塊輪廓?jiǎng)澐趾团判?/p>
1.refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0]
將數(shù)字模板每個(gè)數(shù)字的輪廓計(jì)算出來肺然,并且排序艺蝴,reCnts可以看做輪廓合集
2.遍歷每個(gè)輪廓,得到模塊
for (i,c) in enumerate (reCnts)://遍歷每個(gè)輪廓
enumerate() 函數(shù)用于將一個(gè)可遍歷的數(shù)據(jù)對(duì)象(如列表杂穷、元組或字符串)組合為一個(gè)索引序列悍缠,同時(shí)列出數(shù)據(jù)和數(shù)據(jù)下標(biāo),一般用在 for 循環(huán)當(dāng)中耐量。
(x,y,w,h)=cv2.boundingrect(c)//獲得輪廓的外接矩形飞蚓,返回元組矩形左上坐標(biāo)和矩陣長寬
roi=ref[x:x+w,????y:y+h]//獲得roi感興趣部分
roi=cv2.resize(58,88)//轉(zhuǎn)化大小適用于模板匹配
4.定義卷積核
rectKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
sqKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
5.讀入銀行卡圖像,預(yù)處理(使其可以更準(zhǔn)確)
1.img2=cv2.imread("絕對(duì)路徑")
img2=myutils.resize(img2,width=300)//把寬變?yōu)?00,其高轉(zhuǎn)變?yōu)閷?duì)應(yīng)的長度
gray=cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)//灰度化
tophat=cv2.morphologyEx(gray,MORPH_TOPHAT,rectKernel)//禮帽處理廊蜒,使圖像變得更加明亮
6.sobel算子
gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0,? ksize=-1)# ksize=-1相當(dāng)于用3*3的
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)
sobel算子作用:Sobel算子根據(jù)像素點(diǎn)上下趴拧、左右鄰點(diǎn)灰度加權(quán)差溅漾,在邊緣處達(dá)到極值這一現(xiàn)象檢測(cè)邊緣。對(duì)噪聲具有平滑作用著榴,提供較為精確的邊緣方向信息添履,邊緣定位精度不夠高。當(dāng)對(duì)精度要求不是很高時(shí)兄渺,是一種較為常用的邊緣檢測(cè)方法缝龄。
7.進(jìn)行閉運(yùn)算【先腐后膨】(對(duì)輸入圖像沒有規(guī)定(灰度圖和二值圖像))
gradx=cv2.morphologyEX(gradX,0,255,cv2.MORPH_CLOSE,rectKernel)
作用:使圖像中的孔隙填充(先對(duì)圖像膨脹后腐蝕 作用:用來填充物體內(nèi)的小空洞,連接鄰近的物體,連接斷開的輪廓線,平滑其邊界的同時(shí)不改變面積)
8.二值化cv2.threshold
# THRESH_OTSU會(huì)自動(dòng)尋找合適的閾值,適合雙峰挂谍,需把閾值參數(shù)設(shè)置為0
thresh = cv2.threshold(gradX, 0, 255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
9.在進(jìn)行一個(gè)閉運(yùn)算
thresh=cv2.morphologyEX(thresh,0,255,cv2.MORPH_CLOSE,rectKernel)
10.尋找輪廓
threshcnts,hierarchy=cv2.foundContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts=theshcnts
11.遍歷輪廓數(shù)字組
locs=[]
for(i,c) in enumerate(cnts):
????(x,y,w,h)=cv2.boundingRect(c)
? ? ar=w/float(h)
? ??# 選擇合適的區(qū)域叔壤,根據(jù)實(shí)際任務(wù)來,這里的基本都是四個(gè)數(shù)字一組
? ??if ar >2.5 and ar <4.0://根據(jù)實(shí)際大小比例
????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 = []
12.遍歷數(shù)字輪廓(每個(gè)數(shù)字組中數(shù)字)
for(i,(gx,gy,gw,gh)) in enumberate(locs):
? ? groudOutput=[]//定義一個(gè)list
? ??# 根據(jù)坐標(biāo)提取每一個(gè)組
????group = gray[gY -5:gY + gH +5, gX -5:gX + gW +5]//截取灰度圖像
????cv_show('group', group)
????# 預(yù)處理
????group = cv2.threshold(group, 0, 255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
????cv_show('group', group)
????# 計(jì)算每一組的輪廓
????digitCnts, hierarchy = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL炼绘,
?????cv2.CHAIN_APPROX_SIMPLE)//輪廓檢測(cè)
????digitCnts = myutils.sort_contours(digitCnts,method="left-to-right")[0]? ? //為數(shù)字組中每個(gè)數(shù)字輪廓排序
? ? for (c) in (digitCnts):
? ? ? ? (x,y,w,h)=cv2.boundingRect(c)
? ? ? ? roi=(y:y+h,x:x+w)
? ? ? ? roi=cv2.resize(roi,(58,88))
? ? ? ? #?計(jì)算匹配得分
????????scores = []
? ??????# 在模板中計(jì)算每一個(gè)得分
????????for (digit, digitROI)in digits.items()://item()方法把字典中每對(duì)key和value組成一個(gè)元組妄田,并把這些元組放在列表中返回俺亮。digit為key,digitROI為value
? ? ? ? ?# 模板匹配
? ? ????????result = cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF_NORMED))#TM_CCOEFF_NORMED疟呐,1表示完美的匹配脚曾;-1表示最差的匹配。即表示越大越好
????????????(_, score, _, _) = cv2.minMaxLoc(result)????
????????????scores.append(score)//#result參數(shù)表示匹配結(jié)果圖像启具,必須是單通道32位浮點(diǎn),scorce參數(shù)表示返回的最大值//score可以大致認(rèn)為匹配度本讥,匹配度越大,越準(zhǔn)確
????????????# 得到最合適的數(shù)字
????????????groupOutput.append(str(np.argmax(scores)))//#numpy.argmax(array, axis) 用于返回一個(gè)numpy數(shù)組中最大值(最大可能性)的索引值(下標(biāo))
? ??????????# 畫出來
????????????cv2.rectangle(img2, (gX -5, gY -5),(gX + gW +5, gY + gH +5), (0, 0, 255), 1)
????????????cv2.putText(img2, "".join(groupOutput), (gX, gY -15),cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)
cv2.putText(img, str(i), (123,456)), font, 2, (0,255,0), 3)
各參數(shù)依次是:圖片鲁冯,添加的文字拷沸,左上角坐標(biāo),字體薯演,字體大小撞芍,顏色,字體粗細(xì)
Python join() 方法用于將序列中的元素以指定的字符連接生成一個(gè)新的字符串
print("Credit Card #: {}".format("".join(output)))//數(shù)字識(shí)別結(jié)果
cv2.imshow("Image", img2)
cv2.waitKey(0)
附言:這個(gè)小項(xiàng)目網(wǎng)上已經(jīng)有許多源代碼(本文只是代碼簡單說明)跨扮,本博客只是自己對(duì)這個(gè)項(xiàng)目的理解序无,希望對(duì)讀者有點(diǎn)幫助
銀行卡圖片:
模板圖片: