OpenCV+Python识别车牌和字符分割
生活随笔
收集整理的這篇文章主要介紹了
OpenCV+Python识别车牌和字符分割
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
本篇文章主要基于python語言和OpenCV庫(cv2)進行車牌區域識別和字符分割,開篇之前針對在python中安裝opencv的環境這里不做介紹,可以自行安裝配置!
車牌號檢測需要大致分為四個部分:
- 1.車輛圖像獲取
- 2.車牌定位、
- 3.車牌字符分割
- 4.車牌字符識別
具體介紹
車牌定位需要用到的是圖片二值化為黑白后進canny邊緣檢測后多次進行開運算與閉運算用于消除小塊的區域,保留大塊的區域,后用cv2.rectangle選取矩形框,從而定位車牌位置
車牌字符的分割前需要準備的是只保留車牌部分,將其他部分均變為黑色背景。這里我采用cv2.grabCut方法,可將圖像分割成前景與背景。分割完成后,再經過二值化為黑白圖后即可進行字符分割。由于圖像中只有黑色和白色像素,因此我們需要通過圖像的白色像素和黑色像素來分割開字符。即分別通過判斷每一行每一列的黑色白色像素值的位置,來定位出字符。
具體步驟如下:
- 1.灰度轉換:將彩色圖片轉換為灰度圖像,常見的R=G=B=像素平均值。
- 2.高斯平滑和中值濾波:去除噪聲。
- 3.Sobel算子:提取圖像邊緣輪廓,X方向和Y方向平方和開跟。
- 4.二值化處理:圖像轉換為黑白兩色,通常像素大于127設置為255,小于設置為0。
- 5.膨脹和細化:放大圖像輪廓,轉換為一個個區域,這些區域內包含車牌。
- 6.通過算法選擇合適的車牌位置,通常將較小的區域過濾掉或尋找藍色底的區域。
- 7.標注車牌位置
- 8.圖像切割和識別
通過代碼實現:
# -*- coding: utf-8 -*- """ @email:cuiran2001@163.com @author: cuiran """ import cv2 import numpy as np from PIL import Image import os.path from skimage import io,data def stretch(img):'''圖像拉伸函數'''maxi=float(img.max())mini=float(img.min())for i in range(img.shape[0]):for j in range(img.shape[1]):img[i,j]=(255/(maxi-mini)*img[i,j]-(255*mini)/(maxi-mini))return imgdef dobinaryzation(img):'''二值化處理函數'''maxi=float(img.max())mini=float(img.min())x=maxi-((maxi-mini)/2)#二值化,返回閾值ret 和 二值化操作后的圖像threshret,thresh=cv2.threshold(img,x,255,cv2.THRESH_BINARY)#返回二值化后的黑白圖像return threshdef find_rectangle(contour):'''尋找矩形輪廓'''y,x=[],[]for p in contour:y.append(p[0][0])x.append(p[0][1])return [min(y),min(x),max(y),max(x)]def locate_license(img,afterimg):'''定位車牌號'''img,contours,hierarchy=cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)#找出最大的三個區域block=[]for c in contours:#找出輪廓的左上點和右下點,由此計算它的面積和長度比r=find_rectangle(c)a=(r[2]-r[0])*(r[3]-r[1]) #面積s=(r[2]-r[0])*(r[3]-r[1]) #長度比block.append([r,a,s])#選出面積最大的3個區域block=sorted(block,key=lambda b: b[1])[-3:]#使用顏色識別判斷找出最像車牌的區域maxweight,maxindex=0,-1for i in range(len(block)):b=afterimg[block[i][0][1]:block[i][0][3],block[i][0][0]:block[i][0][2]]#BGR轉HSVhsv=cv2.cvtColor(b,cv2.COLOR_BGR2HSV)#藍色車牌的范圍lower=np.array([100,50,50])upper=np.array([140,255,255])#根據閾值構建掩膜mask=cv2.inRange(hsv,lower,upper)#統計權值w1=0for m in mask:w1+=m/255w2=0for n in w1:w2+=n#選出最大權值的區域if w2>maxweight:maxindex=imaxweight=w2return block[maxindex][0]def find_license(img):'''預處理函數'''m=400*img.shape[0]/img.shape[1]#壓縮圖像img=cv2.resize(img,(400,int(m)),interpolation=cv2.INTER_CUBIC)#BGR轉換為灰度圖像gray_img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#灰度拉伸stretchedimg=stretch(gray_img)'''進行開運算,用來去除噪聲'''r=16h=w=r*2+1kernel=np.zeros((h,w),np.uint8)cv2.circle(kernel,(r,r),r,1,-1)#開運算openingimg=cv2.morphologyEx(stretchedimg,cv2.MORPH_OPEN,kernel)#獲取差分圖,兩幅圖像做差 cv2.absdiff('圖像1','圖像2')strtimg=cv2.absdiff(stretchedimg,openingimg)#圖像二值化binaryimg=dobinaryzation(strtimg)#canny邊緣檢測canny=cv2.Canny(binaryimg,binaryimg.shape[0],binaryimg.shape[1])'''消除小的區域,保留大塊的區域,從而定位車牌'''#進行閉運算kernel=np.ones((5,19),np.uint8)closingimg=cv2.morphologyEx(canny,cv2.MORPH_CLOSE,kernel)#進行開運算openingimg=cv2.morphologyEx(closingimg,cv2.MORPH_OPEN,kernel)#再次進行開運算kernel=np.ones((11,5),np.uint8)openingimg=cv2.morphologyEx(openingimg,cv2.MORPH_OPEN,kernel)#消除小區域,定位車牌位置rect=locate_license(openingimg,img)return rect,imgdef cut_license(afterimg,rect):'''圖像分割函數'''#轉換為寬度和高度rect[2]=rect[2]-rect[0]rect[3]=rect[3]-rect[1]rect_copy=tuple(rect.copy())rect=[0,0,0,0]#創建掩膜mask=np.zeros(afterimg.shape[:2],np.uint8)#創建背景模型 大小只能為13*5,行數只能為1,單通道浮點型bgdModel=np.zeros((1,65),np.float64)#創建前景模型fgdModel=np.zeros((1,65),np.float64)#分割圖像cv2.grabCut(afterimg,mask,rect_copy,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)mask2=np.where((mask==2)|(mask==0),0,1).astype('uint8')img_show=afterimg*mask2[:,:,np.newaxis]return img_showdef deal_license(licenseimg):'''車牌圖片二值化'''#車牌變為灰度圖像gray_img=cv2.cvtColor(licenseimg,cv2.COLOR_BGR2GRAY)#均值濾波 去除噪聲kernel=np.ones((3,3),np.float32)/9gray_img=cv2.filter2D(gray_img,-1,kernel)#二值化處理ret,thresh=cv2.threshold(gray_img,120,255,cv2.THRESH_BINARY)return threshdef find_end(start,arg,black,white,width,black_max,white_max):end=start+1for m in range(start+1,width-1):if (black[m] if arg else white[m])>(0.98*black_max if arg else 0.98*white_max):end=mbreakreturn endif __name__=='__main__':img=cv2.imread('test_images/car001.jpg',cv2.IMREAD_COLOR)#預處理圖像rect,afterimg=find_license(img)#框出車牌號cv2.rectangle(afterimg,(rect[0],rect[1]),(rect[2],rect[3]),(0,255,0),2)cv2.imshow('afterimg',afterimg)#分割車牌與背景cutimg=cut_license(afterimg,rect)cv2.imshow('cutimg',cutimg)#二值化生成黑白圖thresh=deal_license(cutimg)cv2.imshow('thresh',thresh)cv2.waitKey(0)#分割字符'''判斷底色和字色'''#記錄黑白像素總和white=[]black=[]height=thresh.shape[0] #263width=thresh.shape[1] #400#print('height',height)#print('width',width)white_max=0black_max=0#計算每一列的黑白像素總和for i in range(width):line_white=0line_black=0for j in range(height):if thresh[j][i]==255:line_white+=1if thresh[j][i]==0:line_black+=1white_max=max(white_max,line_white)black_max=max(black_max,line_black)white.append(line_white)black.append(line_black)print('white',white)print('black',black)#arg為true表示黑底白字,False為白底黑字arg=Trueif black_max<white_max:arg=Falsen=1start=1end=2s_width=28s_height=28while n<width-2:n+=1#判斷是白底黑字還是黑底白字 0.05參數對應上面的0.95 可作調整if(white[n] if arg else black[n])>(0.02*white_max if arg else 0.02*black_max):start=nend=find_end(start,arg,black,white,width,black_max,white_max)n=endif end-start>5:cj=thresh[1:height,start:end]# new_image = cj.resize((s_width,s_height),Image.BILINEAR)# cj=cj.reshape(28, 28)print("result/%s.jpg" % (n))#保存分割的圖片 by cayden# cj.save("result/%s.jpg" % (n))infile="result/%s.jpg" % (n)io.imsave(infile,cj)# im = Image.open(infile)# out=im.resize((s_width,s_height),Image.BILINEAR)# out.save(infile)cv2.imshow('cutlicense',cj)cv2.waitKey(0)cv2.waitKey(0)cv2.destroyAllWindows()運行效果如圖所示
車牌定位并進行處理
車牌分割如圖所示
總結
以上是生活随笔為你收集整理的OpenCV+Python识别车牌和字符分割的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《欢乐颂2》狗血的剧情才是生活该有的模样
- 下一篇: aria2c 的基本配置,附带傻瓜式源码