目錄
一、形態學車牌提取(簡單:單情景)
(單圖片還不錯,但多圖片不準確)
1、讀取圖片,轉灰度圖
# 1、讀取圖片,轉灰度圖 img = cv.imread('Resource/car.jpg') gray = cv.cvtColor(img, cv.COLOR_RGB2GRAY) cv.imshow('gray', gray)
2、提取輪廓(Sobel算子提取y方向邊緣)
為什么對Y方向取邊緣:讓圖像變“瘦”,便于把車牌揉成一團。
# 2、提取輪廓(Sobel算子提取y方向) y = cv.Sobel(gray, cv.CV_16S, 1, 0) # 注:對x/y微分和得到x/y方向圖像相反 要得到x/y方向邊緣,就要求y/x方向的微分。 absY = cv.convertScaleAbs(y) cv.imshow('Y', absY)
3、自適應二值化
注:函數返回兩個參數,第二個參數才是二進制圖像!!!
# 3、自適應二值化 ret, binary = cv.threshold(absY, 0, 255, cv.THRESH_OTSU) cv.imshow('binary', binary)
4、閉運算處理,把圖像閉合、揉團,使圖像區域化
閉運算處理,圖像區域化,便于找到車牌區域,進而得到輪廓
測試多組圖片,發現(17, 5)的卷積核比較好,能達到目的。
# 4、閉運算處理,把圖像閉合、揉團,使圖像區域化,便于找到車牌區域,進而得到輪廓 kernel = cv.getStructuringElement(cv.MORPH_RECT, (17,5)) print('kernel= /n', kernel) close = cv.morphologyEx(binary, cv.MORPH_CLOSE, kernel) cv.imshow('close', close)
(這里采用矩形卷積核處理。)
5、腐蝕/膨脹去噪得到車牌區域
上面雖然得到了二進制圖像,且得到了大致區域,但是噪聲(雜質)仍然太多,下面通過腐蝕、膨脹去噪。
5-1、橫向腐蝕、膨脹
# 5-1、水平方向腐蝕/膨脹 erode = cv.morphologyEx(close, cv.MORPH_ERODE, kernel_x) cv.imshow('erode_x', erode) dilate = cv.morphologyEx(erode, cv.MORPH_DILATE, kernel_x) cv.imshow('dilate_x', dilate)
橫向處理完之后,繼續對縱向進行處理。
5-2、縱向腐蝕、膨脹
# 5-2、豎直方向腐蝕/膨脹 erode = cv.morphologyEx(dilate, cv.MORPH_ERODE, kernel_y) cv.imshow('erode_y', erode) dilate = cv.morphologyEx(erode, cv.MORPH_DILATE, kernel_y) cv.imshow('dilate_y', dilate)
如上圖,得到了想要的結果,基本只剩下幾個輪廓了,且車牌區域保留完好opencv中如何判別車牌是什么顏色opencv中如何判別車牌是什么顏色,不影響車牌的定位。
6、獲取外輪廓
這里想先把包括車牌輪廓的外輪廓一起顯示。
6-1、得到輪廓
# 6-1、得到輪廓 contours, hierarchy = cv.findContours(dilate_y, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
6-2、畫出輪廓并顯示
# 6-2、畫出輪廓 cv.drawContours(img_copy, contours, -1, (255,0,255), 2) cv.imshow('Contours', img_copy)
獲取輪廓代碼及效果:
# 6、獲取外輪廓 img_copy = img.copy() # 6-1、得到輪廓 contours, hierarchy = cv.findContours(dilate_y, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) # 6-2、畫出輪廓并顯示 cv.drawContours(img_copy, contours, -1, (255,0,255), 2) cv.imshow('Contours', img_copy)
7、截取得到車牌
首先判斷車牌的特征(比如寬:高一般在3~4),然后根據這個特征進行判斷,只保留符合特征的圖片(車牌)。
# 7、遍歷所有輪廓,找到車牌輪廓 for contour in contours: # 7-1、得到矩形區域:左頂點坐標、寬和高 rect = cv.boundingRect(contour) # 7-2、判斷寬高比例是否符合車牌標準,截取符合圖片 if rect[2]>rect[3]*3 and rect[2]
二、形態學車牌提取(優化:多情景) 1、轉灰度圖
gray = cv.cvtColor(img, cv.COLOR_RGB2GRAY) cv.imshow('gray', gray)
2、頂帽運算
把較亮部分提取出來,使得車牌區域更加明顯。
# 2、頂帽運算 # gray = cv.equalizeHist(gray) kernel = cv.getStructuringElement(cv.MORPH_RECT, (17,17)) tophat = cv.morphologyEx(gray, cv.MORPH_TOPHAT, kernel) cv.imshow('tophat', tophat)
3、Sobel算子提取Y方向邊緣
縱向化車牌區域,使車牌更加明顯。
# 3、Sobel算子提取y方向邊緣(揉成一坨) y = cv.Sobel(tophat, cv.CV_16S, 1, 0) absY = cv.convertScaleAbs(y) cv.imshow('absY', absY)
4、二值化圖像
根據自己的實際情況選取閾值,閾值越大,變成白色(255)的門檻越多,則白色部分越少。 (這里閾值比較小,但閾值大也有不少利弊)
# 4、自適應二值化(閾值自己可調) ret, binary = cv.threshold(absY, 75, 255, cv.THRESH_BINARY) cv.imshow('binary', binary)
5、開運算分割(縱向分割)
為了防止后面的閉運算錯誤連接外部的雜質,需要先用開運算把它們分隔開。
# 5、開運算處理(縱向去噪,分隔) kernel = cv.getStructuringElement(cv.MORPH_RECT, (1, 15)) Open = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel) cv.imshow('Open', Open)
分割前:
可以看出來,這寫雜質已經完全融入車牌中了,后續想要分離它們就十分困難了。
分割后:
雖然也有少部分的連接,但不是之前的那種大塊連接,相對 比較好去除。
6、閉運算合并
# 6、閉運算合并,把圖像閉合、揉團,使圖像區域化,便于找到車牌區域,進而得到輪廓 kernel = cv.getStructuringElement(cv.MORPH_RECT, (41, 15)) close = cv.morphologyEx(Open, cv.MORPH_CLOSE, kernel) cv.imshow('close', close)
效果上面有。
7、橫/縱方向腐蝕/膨脹
# 7、膨脹/腐蝕(去噪得到車牌區域) # 中遠距離車牌識別 kernel_x = cv.getStructuringElement(cv.MORPH_RECT, (25, 7)) kernel_y = cv.getStructuringElement(cv.MORPH_RECT, (1, 11)) # 近距離車牌識別 # kernel_x = cv.getStructuringElement(cv.MORPH_RECT, (91, 31)) # kernel_y = cv.getStructuringElement(cv.MORPH_RECT, (1, 31)) # 7-1、腐蝕、膨脹(去噪) erode_y = cv.morphologyEx(close, cv.MORPH_ERODE, kernel_y) cv.imshow('erode_y', erode_y) dilate_y = cv.morphologyEx(erode_y, cv.MORPH_DILATE, kernel_y) cv.imshow('dilate_y', dilate_y) # 7-1、膨脹、腐蝕(連接)(二次縫合) dilate_x = cv.morphologyEx(dilate_y, cv.MORPH_DILATE, kernel_x) cv.imshow('dilate_x', dilate_x) erode_x = cv.morphologyEx(dilate_x, cv.MORPH_ERODE, kernel_x) cv.imshow('erode_x', erode_x)
7-1、縱方向: 腐蝕+膨脹
分割上下距離比較近的物體。
7-2、橫方向:膨脹+腐蝕
進一步連接橫向的物體 (繼上面的閉運算,再次連接車牌的內容)
8、腐蝕膨脹:去噪
# 8、腐蝕、膨脹:去噪 kernel_e = cv.getStructuringElement(cv.MORPH_RECT, (25, 11)) erode = cv.morphologyEx(erode_x, cv.MORPH_ERODE, kernel_e) cv.imshow('erode', erode) kernel_d = cv.getStructuringElement(cv.MORPH_RECT, (25, 13)) dilate = cv.morphologyEx(erode, cv.MORPH_DILATE, kernel_d) cv.imshow('dilate', dilate)
9、獲取外輪廓
# 9、獲取外輪廓 img_copy = img.copy() # 9-1、得到輪廓 contours, hierarchy = cv.findContours(dilate, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) # 9-2、畫出輪廓并顯示 cv.drawContours(img_copy, contours, -1, (255, 0, 255), 2) cv.imshow('Contours', img_copy)
10、根據車牌特征找到車牌輪廓
車牌寬高比一般為3~4之間,但我這里首先是圖比較多,有些圖附帶的雜質沒有清除干凈,所以就設置在3~6.5之間。
# 10、遍歷所有輪廓,找到車牌輪廓 i = 0 for contour in contours: # 10-1、得到矩形區域:左頂點坐標、寬和高 rect = cv.boundingRect(contour) # 10-2、判斷寬高比例是否符合車牌標準,截取符合圖片 if rect[2]>rect[3]*3 and rect[2]
中遠距離:
正常車牌成功率:100%(測試了11例,均成功)
傾斜車牌成功率:67%(測試2例,,3車牌,最小的車牌識別失敗)(但是處理不是很好)
近距離車牌成功率:0%(測試2例,均失敗)
近距離:
(近距離成功率50%,因為只做了2個)
代碼
# 車牌識別import cv2 as cvimport numpy as npimport os# 提取車牌(形態學)def Morph_Distinguish(img): # 1、轉灰度圖 gray = cv.cvtColor(img, cv.COLOR_RGB2GRAY) cv.imshow('gray', gray) # 2、頂帽運算 # gray = cv.equalizeHist(gray) kernel = cv.getStructuringElement(cv.MORPH_RECT, (17,17)) tophat = cv.morphologyEx(gray, cv.MORPH_TOPHAT, kernel) cv.imshow('tophat', tophat) # 3、Sobel算子提取y方向邊緣(揉成一坨) y = cv.Sobel(tophat, cv.CV_16S, 1, 0) absY = cv.convertScaleAbs(y) cv.imshow('absY', absY) # 4、自適應二值化(閾值自己可調) ret, binary = cv.threshold(absY, 75, 255, cv.THRESH_BINARY) cv.imshow('binary', binary) # 5、開運算分割(縱向去噪,分隔) kernel = cv.getStructuringElement(cv.MORPH_RECT, (1, 15)) Open = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel) cv.imshow('Open', Open) # 6、閉運算合并,把圖像閉合、揉團,使圖像區域化,便于找到車牌區域,進而得到輪廓 kernel = cv.getStructuringElement(cv.MORPH_RECT, (41, 15)) close = cv.morphologyEx(Open, cv.MORPH_CLOSE, kernel) cv.imshow('close', close) # 7、膨脹/腐蝕(去噪得到車牌區域) # 中遠距離車牌識別 kernel_x = cv.getStructuringElement(cv.MORPH_RECT, (25, 7)) kernel_y = cv.getStructuringElement(cv.MORPH_RECT, (1, 11)) # 近距離車牌識別 # kernel_x = cv.getStructuringElement(cv.MORPH_RECT, (79, 15)) # kernel_y = cv.getStructuringElement(cv.MORPH_RECT, (1, 31)) # 7-1、腐蝕、膨脹(去噪) erode_y = cv.morphologyEx(close, cv.MORPH_ERODE, kernel_y) cv.imshow('erode_y', erode_y) dilate_y = cv.morphologyEx(erode_y, cv.MORPH_DILATE, kernel_y) cv.imshow('dilate_y', dilate_y) # 7-1、膨脹、腐蝕(連接)(二次縫合) dilate_x = cv.morphologyEx(dilate_y, cv.MORPH_DILATE, kernel_x) cv.imshow('dilate_x', dilate_x) erode_x = cv.morphologyEx(dilate_x, cv.MORPH_ERODE, kernel_x) cv.imshow('erode_x', erode_x) # 8、腐蝕、膨脹:去噪 kernel_e = cv.getStructuringElement(cv.MORPH_RECT, (25, 9)) erode = cv.morphologyEx(erode_x, cv.MORPH_ERODE, kernel_e) cv.imshow('erode', erode) kernel_d = cv.getStructuringElement(cv.MORPH_RECT, (25, 11)) dilate = cv.morphologyEx(erode, cv.MORPH_DILATE, kernel_d) cv.imshow('dilate', dilate) # 9、獲取外輪廓 img_copy = img.copy() # 9-1、得到輪廓 contours, hierarchy = cv.findContours(dilate, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) # 9-2、畫出輪廓并顯示 cv.drawContours(img_copy, contours, -1, (255, 0, 255), 2) cv.imshow('Contours', img_copy) # 10、遍歷所有輪廓,找到車牌輪廓 i = 0 for contour in contours: # 10-1、得到矩形區域:左頂點坐標、寬和高 rect = cv.boundingRect(contour) # 10-2、判斷寬高比例是否符合車牌標準,截取符合圖片 if rect[2]>rect[3]*3 and rect[2]
參考資料