在對車牌識別過程中,常用的方法有:基於形狀、基於色調、基於紋理、基於文字特征等方法。首先基於形狀,在車牌中因為車牌為形狀規格的矩形,所以目的轉化為尋找矩形特征,常常是利用車牌長寬比例特征、占據圖像的比例等。基於色調,國內的車牌往往是藍底白字,可以采用圖像的色調或者飽和度特征,進入生成二值圖,定位車牌位置。基於紋理特征自己還沒有基礎到。基於文字特征往往是根據文字輪廓特征進行識別,原理是基於相鄰文字輪廓特征、比例進行定位車牌位置。
一、圖像二值化
正如前面文章所言,首先進行獲取圖像二值化特征,本文采取了根據圖像亮度特征,提高對比度,進行可以清晰獲取文字的圖像,為下一步的文字輪廓識別打好基礎。
1.1 算法流程
偽代碼
1、圖像轉化為HSV圖像,獲取V通道圖像
2、提高對比度
3、V圖像高斯濾波,去除噪聲
4、圖像二值化
程序源碼:
def get_colorvalue(image): height, width, shape = image.shape image_hsv = np.zeros((height,width), np.uint8) image_hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV) image_hue, image_saturation, image_value = cv2.split(image_hsv) return image_value def enhance_contrast(image): kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3)) img_tophat = cv2.morphologyEx(image, cv2.MORPH_TOPHAT,kernel) img_blackhat = cv2.morphologyEx(image, cv2.MORPH_BLACKHAT, kernel) image_plus_tophat = cv2.add(image, img_tophat) image_plus_blackhat_minus_blackhat = cv2.subtract(image_plus_tophat, img_blackhat) return image_plus_blackhat_minus_blackhat def preprocess(srcimage): image_value = get_colorvalue(srcimage) image_enhance = enhance_contrast(image_value) image_blur = cv2.GaussianBlur(image_enhance, (5,5), 0) # _, image_binary = cv2.threshold(image_blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
_, image_binary = cv2.threshold(image_blur, 100, 255, cv2.THRESH_BINARY ) cv2.imwrite('image_binary.png',image_binary) return image_binary
1.2 算法分析
在實驗中在獲取通道圖像時,發現可以利用圖像飽和度圖像進行定位。
1、通道圖像提取
image_hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)
image_hue, image_saturation, image_value = cv2.split(image_hsv)
上面分別為src、hue、saturation、value四副圖像,在其中saturatio中可以清晰獲取車牌相對於背景的飽和度大,則提取較value圖像則可視為灰度圖像,能保留圖像大部分圖像特征。
關於hsv的介紹可以參考這篇文章學習Opencv筆記(二)————hsv色系:文章簡單介紹hsv體系內容。
2、圖像對比度增強
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3)) img_tophat = cv2.morphologyEx(image, cv2.MORPH_TOPHAT,kernel) img_blackhat = cv2.morphologyEx(image, cv2.MORPH_BLACKHAT, kernel) image_plus_black = cv2.add(image, img_blackhat) image_plus_blackhat_minus_blackhat = cv2.subtract(image_plus_black, img_tophat)
(img_tophat) (img_blackhat)
(ima_plus_top_hat) (img_plus_black_top_hat)
圖像增強的目的是提高圖像的對比度,亮度地方更亮,暗的地方更暗。在形態學處理中,頂帽操作往往用來分離比鄰近點亮一些的板塊,在一幅圖像具有大幅背景而微小物品比較有規律的情況下,可以使用頂帽運算進行背景提取。黑帽運算后的效果圖突出了比原圖輪廓周圍的區域更暗的區域,這一操作也與選擇的核尺寸有關。
流程就是,加上黑帽,減去頂冒,其實通過實驗結果發現,貌似作用不大。
形態學處理詳細介紹可以參考:數字圖像處理-形態學研究:對形態學各種操作和理論進行了詳細的介紹
3.二值化
在獲取單通道圖像后,進行了圖像二值化操作,其中網上有個文章推薦使用adaptiveThreshold,其實真的不好用,我也采用了ostu算法,經過試驗驗證也不是很好用,經過多次驗證,初步定閾值為80,效果比較良好。
二、圖像位置初步定位
由於車輛圖像背景比較復雜,所以應該根據車牌的特征進行初次篩選,其特征還是根據中國車牌大小、比例等關系進行篩選。
上圖是自己找的關於車牌的標准,我們可以清晰知道寬:高 = 3.5 所以程序設置的最小比例是2,最大是5,然后就是根據圖像大小設定的面積,長寬等大小。
2.1、算法源碼
#contants for plate contour MIN_CONTOUR_WIDTH = 80 MIN_CONTOUR_HEIGHT = 30 MIN_CONTOUR_RATIO = 1.5 MAX_CONTOUR_RATIO = 5 MIN_CONTOURL_AREA = 1500 def get_external_contours(image_thresh): # Construct display images and display contours in images height, width = image_thresh.shape image_contour1 = np.zeros((height, width),np.uint8) image_contour2 = np.zeros((height, width),np.uint8) ## Custom 3*3 nuclei undergo expansion corrosion in the X direction kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) image_dilate= cv2.dilate(image_thresh,kernel,iterations =2) image_erode= cv2.erode(image_dilate, kernel, iterations = 4) image_dilate= cv2.dilate(image_erode,kernel,iterations = 2) # _, contours, hierarchy = cv2.findContours(image_dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) contour_filter = [] cv2.drawContours(image_contour1, contours, -1,(255, 255, 255 ),3) # choose the suite contour by the feature of special scence for contour in contours: contour_possible = PossibleContour(contour) if(check_external_contour(contour_possible)): cv2.rectangle(image_contour2, (contour_possible.rectX, contour_possible.rectY), (contour_possible.rectX + contour_possible.rectWidth, contour_possible.rectY + contour_possible.rectHeight),255) contour_filter.append(contour_possible) print("the length of origin contours is %d " %len(contour_filter)) cv2.imwrite("1_1contours.png",image_contour1) cv2.imwrite("1_2contours.png",image_contour2) return contour_filter # #According to the license plate area size, length and width ratio, the primary screening is carried out def check_external_contour(contour): if (contour.area > MIN_CONTOURL_AREA and contour.rectWidth > MIN_CONTOUR_WIDTH and contour.rectHeight > MIN_CONTOUR_HEIGHT and contour.whratio > MIN_CONTOUR_RATIO and contour.whratio < MAX_CONTOUR_RATIO): return True else: return False
2 .2、算法分析
上述算法核心是利用了findcontours函數,即在圖像中尋找目標輪廓,詳細的介紹可以參考這篇文章:
OpenCV-Python教程(11、輪廓檢測):文中很詳細介紹函數參數含義及應用
在獲取輪廓中,傳入自己定義的類中,獲取根據輪廓的矩形的面積、長寬等值,方便后續計算。
第二步就是根據上述理論分析,得到的函數。
上面四副圖片分別展示了經過篩選后的結果,對contour根據限制條件進行選擇,最終選擇符合條件的候選區域,並保存在list中。
三、圖像車牌精確定位
在中國車牌顏色為藍底白字,所以藍色數值會比較大,我們計算候選車牌區域藍色數值(均值)的最大值,確定最終的車牌區域。
3.1 算法源碼
def chack_plate_blueHue(contour_list, image_src): if len(contour_list) == 0: print('cannot find the plate contours') return None mean_list = [] # calculate the mean of each blue image and choose the max one,get the index for contour in contour_list: image = cv2.getRectSubPix(image_src, ( contour.rectWidth, contour.rectHeight),(contour.centerX, contour.centerY)) b , g, r = cv2.split(image) sum_pix = b.shape[0] * b.shape[1] b_mean = np.sum(np.array(b))/sum_pix mean_list.append(b_mean) index = np.argmax(np.array(mean_list)) contour_final = contour_list[index] return contour_final
3.2 算法分析
1、遍歷輪廓數組,根據前期獲取的候選車牌區域,通過getRectSubPix獲取其圖像
2、分離圖像,獲取blue通道圖像
3、計算圖像均值,並添加到list
4、尋找list的argmax,獲取其index
5、返回list中准確的contour