1.字符識別原理及其發(fā)展階段
匹配判別是字符識別的基本思想,與其他模式識別的應(yīng)用非常類似。字符識別的基本原理就是對字符圖像進(jìn)行預(yù)處理、模式表達(dá)、判別和字典學(xué)習(xí)。
字符識別一般可分為三個階段:
第一階段為初級階段,主要是應(yīng)用一維圖像的處理方法實(shí)現(xiàn)對二維圖像的識別。此階段主要涉及相關(guān)函數(shù)的構(gòu)造以及特征向量的抽取。目前,該階段的字符識別方法仍然在匹配方法的龐大家族中扮演著很重要的角色。
第二階段為對基礎(chǔ)理論進(jìn)行相關(guān)研究的階段。細(xì)化思想、鏈碼法以及對一些離散圖形上的拓?fù)湫匝芯吭谶@一階段進(jìn)行,其中細(xì)化思想主要用于結(jié)構(gòu)的分析,鏈碼法主要用于邊界的表示。本階段實(shí)現(xiàn)了抽取大范圍的孔、凹凸區(qū)域、連通性以及抽取局部特征等算法,同時還實(shí)現(xiàn)了對K-L展開法“特征抽取理論”作為核心相關(guān)工作的研究。
第三階段為發(fā)展階段。本階段在依據(jù)實(shí)際系統(tǒng)的要求以及設(shè)備難以提供的條件的基礎(chǔ)上提出更為復(fù)雜的技術(shù),主要研究工作是將技術(shù)與實(shí)際結(jié)合起來。另外,在以構(gòu)造解析法以及相關(guān)法為主的基礎(chǔ)上,許多各具特色且不同類的實(shí)用系統(tǒng)得以研究出來。
2.字符識別方法
目前字符識別方法主要有基于神經(jīng)網(wǎng)絡(luò)的識別方法、基于特征分析的匹配方法和基于模板的匹配方法。
(1)基于神經(jīng)網(wǎng)絡(luò)的識別方法
基于神經(jīng)網(wǎng)絡(luò)的識別方法主要包括4個步驟:預(yù)處理樣本字符、提取字符的特征、對神經(jīng)網(wǎng)絡(luò)進(jìn)行訓(xùn)練、神經(jīng)網(wǎng)絡(luò)接受經(jīng)過相關(guān)預(yù)處理和特征提取的字符并對這些字符進(jìn)行識別。
(2)基于特征分析的匹配方法
基于特征分析的匹配方法,主要利用特征平面來進(jìn)行字符匹配。與其他匹配方法進(jìn)行比較可知,它不但對噪聲具有不明顯的反應(yīng),而且可以獲得效果更好的字符特征。
(3)基于模板的匹配方法
基于模板的匹配方法也是字符識別的一種方法,主要權(quán)衡輸入模式與標(biāo)準(zhǔn)模式之間的相似程度。因此,從結(jié)果來看,輸入模式的類別其實(shí)也是標(biāo)準(zhǔn)模式,單從與輸入模式相似度的程度來講,這里提到的標(biāo)準(zhǔn)模式最高。對于離散輸入模式分類的實(shí)現(xiàn),此方法所起的作用非常明顯也非常奏效。
組成汽車牌照的字符大約有50個漢字、20多個英文字符和10個阿拉伯?dāng)?shù)字,相對而言,字符數(shù)比較少,所以可以使用模板匹配法識別這些字符。其中,用于匹配的模板的標(biāo)準(zhǔn)形式可由前面所述的字符制作而成。與其他的字符識別的方法進(jìn)行比較可知,模板匹配法具有相對來說較為簡單的識別過程和較快的字符識別速度,只不過準(zhǔn)確率不是很高。
3.英文、數(shù)字識別
目前,小波識別法、模板匹配法與神經(jīng)網(wǎng)絡(luò)法等常被作為汽車牌照字符識別的主要方法。數(shù)字字符是在汽車牌照的字符集中具有最小規(guī)模、最簡單結(jié)構(gòu)的子集。雖然字母字符相對于數(shù)字字符而言并不復(fù)雜,但是單從字符的結(jié)構(gòu)上來講,不難看出車牌字符集中的數(shù)字字符要相對簡單一些。一般采用模板匹配法來識別字母字符以及數(shù)字字符,只是有時采用模板匹配法不一定能取得理想的識別效果,例如字符存在劃傷破損、褪色、污跡等問題時。本章采用的匹配模式為兩級模板匹配,首先通過一級模板實(shí)現(xiàn)對字母數(shù)字字符的匹配,然后基于邊緣霍斯多夫距離對一級模板匹配不成功的字符進(jìn)行匹配。
真實(shí)的汽車圖像的采集主要通過CCD工業(yè)相機(jī)進(jìn)行的,輸入的汽車牌照的字符圖像在經(jīng)過汽車牌照的定位以及汽車牌照內(nèi)字符的分割之后形成,其中約有50%的高質(zhì)量的字符包含在3000個字符組成的字符集中,剩下的汽車牌照內(nèi)的字符質(zhì)量都有一定程度的降低。相較于傳統(tǒng)的模板匹配法和基于細(xì)化圖像霍斯多夫距離的模板匹配法,準(zhǔn)確率在基于邊緣霍斯多夫距離的模板匹配識別方法中表現(xiàn)得更高(為98%,字符的錯誤識別率只有2%)。
4.車牌定位實(shí)例
測試照片:
代碼實(shí)例:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
def stretch(img):
'''
圖像拉伸函數(shù)
'''
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 img
def dobinaryzation(img):
'''
二值化處理函數(shù)
'''
maxi=float(img.max())
mini=float(img.min())
x=maxi-((maxi-mini)/2)
#二值化,返回閾值ret 和 二值化操作后的圖像thresh
ret,thresh=cv2.threshold(img,x,255,cv2.THRESH_BINARY)
#返回二值化后的黑白圖像
return thresh
def 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):
'''
定位車牌號
'''
contours,hierarchy=cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#找出最大的三個區(qū)域
block=[]
for c in contours:
#找出輪廓的左上點(diǎn)和右下點(diǎn),由此計算它的面積和長度比
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個區(qū)域
block=sorted(block,key=lambda b: b[1])[-3:]
#使用顏色識別判斷找出最像車牌的區(qū)域
maxweight,maxindex=0,-1
for i in range(len(block)):
b=afterimg[block[i][0][1]:block[i][0][3],block[i][0][0]:block[i][0][2]]
#BGR轉(zhuǎn)HSV
hsv=cv2.cvtColor(b,cv2.COLOR_BGR2HSV)
#藍(lán)色車牌的范圍
lower=np.array([100,50,50])
upper=np.array([140,255,255])
#根據(jù)閾值構(gòu)建掩膜
mask=cv2.inRange(hsv,lower,upper)
#統(tǒng)計權(quán)值
w1=0
for m in mask:
w1+=m/255
w2=0
for n in w1:
w2+=n
#選出最大權(quán)值的區(qū)域
if w2>maxweight:
maxindex=i
maxweight=w2
return block[maxindex][0]
def find_license(img):
'''
預(yù)處理函數(shù)
'''
m=400*img.shape[0]/img.shape[1]
#壓縮圖像
img=cv2.resize(img,(400,int(m)),interpolation=cv2.INTER_CUBIC)
#BGR轉(zhuǎn)換為灰度圖像
gray_img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#灰度拉伸
stretchedimg=stretch(gray_img)
'''進(jìn)行開運(yùn)算,用來去除噪聲'''
r=16
h=w=r*2+1
kernel=np.zeros((h,w),np.uint8)
cv2.circle(kernel,(r,r),r,1,-1)
#開運(yùn)算
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])
'''消除小的區(qū)域,保留大塊的區(qū)域,從而定位車牌'''
#進(jìn)行閉運(yùn)算
kernel=np.ones((5,19),np.uint8)
closingimg=cv2.morphologyEx(canny,cv2.MORPH_CLOSE,kernel)
#進(jìn)行開運(yùn)算
openingimg=cv2.morphologyEx(closingimg,cv2.MORPH_OPEN,kernel)
#再次進(jìn)行開運(yùn)算
kernel=np.ones((11,5),np.uint8)
openingimg=cv2.morphologyEx(openingimg,cv2.MORPH_OPEN,kernel)
#消除小區(qū)域,定位車牌位置
rect=locate_license(openingimg,img)
return rect,img
def cut_license(afterimg,rect):
'''
圖像分割函數(shù)
'''
#轉(zhuǎn)換為寬度和高度
rect[2]=rect[2]-rect[0]
rect[3]=rect[3]-rect[1]
rect_copy=tuple(rect.copy())
rect=[0,0,0,0]
#創(chuàng)建掩膜
mask=np.zeros(afterimg.shape[:2],np.uint8)
#創(chuàng)建背景模型 大小只能為13*5,行數(shù)只能為1,單通道浮點(diǎn)型
bgdModel=np.zeros((1,65),np.float64)
#創(chuàng)建前景模型
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_show
def deal_license(licenseimg):
'''
車牌圖片二值化
'''
#車牌變?yōu)榛叶葓D像
gray_img=cv2.cvtColor(licenseimg,cv2.COLOR_BGR2GRAY)
#均值濾波 去除噪聲
kernel=np.ones((3,3),np.float32)/9
gray_img=cv2.filter2D(gray_img,-1,kernel)
#二值化處理
ret,thresh=cv2.threshold(gray_img,120,255,cv2.THRESH_BINARY)
return thresh
def find_end(start,arg,black,white,width,black_max,white_max):
end=start+1
for 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=m
break
return end
if __name__=='__main__':
img=cv2.imread('car.jpg',cv2.IMREAD_COLOR)
#預(yù)處理圖像
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.imwrite("cp.jpg",thresh)
cv2.waitKey(0)
#分割字符
'''
判斷底色和字色
'''
#記錄黑白像素總和
white=[]
black=[]
height=thresh.shape[0] #263
width=thresh.shape[1] #400
#print('height',height)
#print('width',width)
white_max=0
black_max=0
#計算每一列的黑白像素總和
for i in range(width):
line_white=0
line_black=0
for j in range(height):
if thresh[j][i]==255:
line_white+=1
if thresh[j][i]==0:
line_black+=1
white_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表示黑底白字,F(xiàn)alse為白底黑字
arg=True
if black_max<white_max:
arg=False
n=1
start=1
end=2
while n<width-2:
n+=1
#判斷是白底黑字還是黑底白字 0.05參數(shù)對應(yīng)上面的0.95 可作調(diào)整
if(white[n] if arg else black[n])>(0.02*white_max if arg else 0.02*black_max):
start=n
end=find_end(start,arg,black,white,width,black_max,white_max)
n=end
if end-start>5:
cj=thresh[1:height,start:end]
cv2.imshow('cutlicense',cj)
cv2.waitKey(0)
cv2.waitKey(0)
cv2.destroyAllWindows()
輸出結(jié)果:文章來源:http://www.zghlxwxcb.cn/news/detail-642914.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-642914.html
到了這里,關(guān)于OpenCV實(shí)例(八)車牌字符識別技術(shù)(二)字符識別的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!