利用Python+Opencv實現(xiàn)車牌自動識別完整代碼
該篇文章將以實戰(zhàn)形式演示利用Python結合Opencv實現(xiàn)車牌識別,全程涉及圖像預處理、車牌定位、車牌分割、通過模板匹配識別結果輸出。該項目對于智能交通、車輛管理等領域具有實際應用價值。通過自動識別車牌號碼,可以實現(xiàn)車輛追蹤、違章查詢、停車場管理等功能,提高交通管理的效率和準確性。可用于車牌識別技術學習。
技術要點:
- OpenCV:用于圖像處理和計算機視覺任務。
- Python:作為編程語言,具有簡單易學、資源豐富等優(yōu)點。
- 圖像處理技術:如灰度化、噪聲去除、邊緣檢測、形態(tài)學操作、透視變換等。
1 導入相關模塊
import cv2 from matplotlib import pyplot as plt import os import numpy as np from PIL import ImageFont, ImageDraw, Image
2 相關功能函數(shù)定義
2.1 彩色圖片顯示函數(shù)(plt_show0)
def plt_show0(img): b,g,r = cv2.split(img) img = cv2.merge([r, g, b]) plt.imshow(img) plt.show()
cv2與plt的圖像通道不同:cv2為[b,g,r];plt為[r, g, b]
2.2 灰度圖片顯示函數(shù)(plt_show)
def plt_show(img): plt.imshow(img,cmap='gray') plt.show()
2.3 圖像去噪函數(shù)(gray_guss)
def gray_guss(image): image = cv2.GaussianBlur(image, (3, 3), 0) gray_image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) return gray_image
此處演示使用高斯模糊去噪。
cv2.GaussianBlur參數(shù)說明:
src
:輸入圖像,可以是任意數(shù)量的通道,這些通道可以獨立處理,但深度應為CV_8U
、CV_16U
、CV_16S
、CV_32F
或CV_64F
。ksize
:高斯核的大小,必須是正奇數(shù),例如 (3, 3)、(5, 5) 等。如果ksize
的值為零,那么它會根據(jù)sigmaX
和sigmaY
的值來計算。sigmaX
:X 方向上的高斯核標準偏差。dst
:輸出圖像,大小和類型與src
相同。sigmaY
:Y 方向上的高斯核標準偏差,如果sigmaY
是零,那么它會與sigmaX
的值相同。如果sigmaY
是負數(shù),那么它會從ksize.width
和ksize.height
計算得出。borderType
:像素外插法,有默認值。
2 圖像預處理
2.1 圖片讀取
origin_image = cv2.imread('D:/image/car3.jpg')
此處演示識別車牌原圖:
2.2 高斯去噪
origin_image = cv2.imread('D:/image/car3.jpg') # 復制一張圖片,在復制圖上進行圖像操作,保留原圖 image = origin_image.copy() gray_image = gray_guss(image)
2.3 邊緣檢測
Sobel_x = cv2.Sobel(gray_image, cv2.CV_16S, 1, 0) absX = cv2.convertScaleAbs(Sobel_x) image = absX
x方向上的邊緣檢測(增強邊緣信息)。
2.4 閾值化
# 圖像閾值化操作——獲得二值化圖 ret, image = cv2.threshold(image, 0, 255, cv2.THRESH_OTSU) # 顯示灰度圖像 plt_show(image)
運行結果:
3 車牌定位
3.1 區(qū)域選擇
kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (30, 10)) image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernelX,iterations = 1) # 顯示灰度圖像 plt_show(image)
從圖像中提取對表達和描繪區(qū)域形狀有意義的圖像分量。
運行結果:
3.2 形態(tài)學操作
# 腐蝕(erode)和膨脹(dilate) kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (50, 1)) kernelY = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 20)) #x方向進行閉操作(抑制暗細節(jié)) image = cv2.dilate(image, kernelX) image = cv2.erode(image, kernelX) #y方向的開操作 image = cv2.erode(image, kernelY) image = cv2.dilate(image, kernelY) # 中值濾波(去噪) image = cv2.medianBlur(image, 21) # 顯示灰度圖像 plt_show(image)
使用膨脹和腐蝕操作來突出車牌區(qū)域。
運行結果:
3.3 輪廓檢測
contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for item in contours: rect = cv2.boundingRect(item) x = rect[0] y = rect[1] weight = rect[2] height = rect[3] # 根據(jù)輪廓的形狀特點,確定車牌的輪廓位置并截取圖像 if (weight > (height * 3)) and (weight < (height * 4.5)): image = origin_image[y:y + height, x:x + weight] plt_show(image)
4 車牌字符分割
4.1 高斯去噪
# 圖像去噪灰度處理 gray_image = gray_guss(image)
4.2 閾值化
ret, image = cv2.threshold(gray_image, 0, 255, cv2.THRESH_OTSU) plt_show(image)
運行結果:
4.3 膨脹操作
#膨脹操作 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (4, 4)) image = cv2.dilate(image, kernel) plt_show(image)
運行結果:
4.4 車牌號排序
words = sorted(words,key=lambda s:s[0],reverse=False) i = 0 #word中存放輪廓的起始點和寬高 for word in words: # 篩選字符的輪廓 if (word[3] > (word[2] * 1.5)) and (word[3] < (word[2] * 5.5)) and (word[2] > 10): i = i+1 if word[2] < 15: splite_image = image[word[1]:word[1] + word[3], word[0]-word[2]:word[0] + word[2]*2] else: splite_image = image[word[1]:word[1] + word[3], word[0]:word[0] + word[2]] word_images.append(splite_image) print(i) print(words)
運行結果:
1 2 3 4 5 6 7 [[2, 0, 7, 70], [12, 6, 30, 55], [15, 7, 7, 9], [46, 6, 32, 55], [83, 30, 9, 9], [96, 7, 32, 55], [132, 8, 32, 55], [167, 8, 30, 54], [202, 62, 7, 6], [203, 7, 30, 55], [245, 7, 12, 54], [266, 0, 12, 70]]
4.5 分割效果
for i,j in enumerate(word_images): plt.subplot(1,7,i+1) plt.imshow(word_images[i],cmap='gray') plt.show()
運行結果:
5 模板匹配
5.1 準備模板
# 準備模板(template[0-9]為數(shù)字模板;) template = ['0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z', '藏','川','鄂','甘','贛','貴','桂','黑','滬','吉','冀','津','晉','京','遼','魯','蒙','閩','寧', '青','瓊','陜','蘇','皖','湘','新','渝','豫','粵','云','浙'] # 讀取一個文件夾下的所有圖片,輸入?yún)?shù)是文件名,返回模板文件地址列表 def read_directory(directory_name): referImg_list = [] for filename in os.listdir(directory_name): referImg_list.append(directory_name + "/" + filename) return referImg_list # 獲得中文模板列表(只匹配車牌的第一個字符) def get_chinese_words_list(): chinese_words_list = [] for i in range(34,64): #將模板存放在字典中 c_word = read_directory('D:/refer1/'+ template[i]) chinese_words_list.append(c_word) return chinese_words_list chinese_words_list = get_chinese_words_list() # 獲得英文模板列表(只匹配車牌的第二個字符) def get_eng_words_list(): eng_words_list = [] for i in range(10,34): e_word = read_directory('D:/refer1/'+ template[i]) eng_words_list.append(e_word) return eng_words_list eng_words_list = get_eng_words_list() # 獲得英文和數(shù)字模板列表(匹配車牌后面的字符) def get_eng_num_words_list(): eng_num_words_list = [] for i in range(0,34): word = read_directory('D:/refer1/'+ template[i]) eng_num_words_list.append(word) return eng_num_words_list eng_num_words_list = get_eng_num_words_list()
此處需提前準備各類字符模板。
5.2 匹配結果
# 獲得英文和數(shù)字模板列表(匹配車牌后面的字符) def get_eng_num_words_list(): eng_num_words_list = [] for i in range(0,34): word = read_directory('D:/refer1/'+ template[i]) eng_num_words_list.append(word) return eng_num_words_list eng_num_words_list = get_eng_num_words_list() # 讀取一個模板地址與圖片進行匹配,返回得分 def template_score(template,image): #將模板進行格式轉(zhuǎn)換 template_img=cv2.imdecode(np.fromfile(template,dtype=np.uint8),1) template_img = cv2.cvtColor(template_img, cv2.COLOR_RGB2GRAY) #模板圖像閾值化處理——獲得黑白圖 ret, template_img = cv2.threshold(template_img, 0, 255, cv2.THRESH_OTSU) # height, width = template_img.shape # image_ = image.copy() # image_ = cv2.resize(image_, (width, height)) image_ = image.copy() #獲得待檢測圖片的尺寸 height, width = image_.shape # 將模板resize至與圖像一樣大小 template_img = cv2.resize(template_img, (width, height)) # 模板匹配,返回匹配得分 result = cv2.matchTemplate(image_, template_img, cv2.TM_CCOEFF) return result[0][0] # 對分割得到的字符逐一匹配 def template_matching(word_images): results = [] for index,word_image in enumerate(word_images): if index==0: best_score = [] for chinese_words in chinese_words_list: score = [] for chinese_word in chinese_words: result = template_score(chinese_word,word_image) score.append(result) best_score.append(max(score)) i = best_score.index(max(best_score)) # print(template[34+i]) r = template[34+i] results.append(r) continue if index==1: best_score = [] for eng_word_list in eng_words_list: score = [] for eng_word in eng_word_list: result = template_score(eng_word,word_image) score.append(result) best_score.append(max(score)) i = best_score.index(max(best_score)) # print(template[10+i]) r = template[10+i] results.append(r) continue else: best_score = [] for eng_num_word_list in eng_num_words_list: score = [] for eng_num_word in eng_num_word_list: result = template_score(eng_num_word,word_image) score.append(result) best_score.append(max(score)) i = best_score.index(max(best_score)) # print(template[i]) r = template[i] results.append(r) continue return results word_images_ = word_images.copy() # 調(diào)用函數(shù)獲得結果 result = template_matching(word_images_) print(result) print( "".join(result))
運行結果:
['渝', 'B', 'F', 'U', '8', '7', '1'] 渝BFU871
“”.join(result)函數(shù)將列表轉(zhuǎn)換為拼接好的字符串,方便結果顯示
5.3 匹配效果展示
height,weight = origin_image.shape[0:2] print(height) print(weight) image_1 = origin_image.copy() cv2.rectangle(image_1, (int(0.2*weight), int(0.75*height)), (int(weight*0.9), int(height*0.95)), (0, 255, 0), 5) #設置需要顯示的字體 fontpath = "font/simsun.ttc" font = ImageFont.truetype(fontpath,64) img_pil = Image.fromarray(image_1) draw = ImageDraw.Draw(img_pil) #繪制文字信息 draw.text((int(0.2*weight)+25, int(0.75*height)), "".join(result), font = font, fill = (255, 255, 0)) bk_img = np.array(img_pil) print(result) print( "".join(result)) plt_show0(bk_img)
運行結果:
6完整代碼
# 導入所需模塊 import cv2 from matplotlib import pyplot as plt import os import numpy as np from PIL import ImageFont, ImageDraw, Image # plt顯示彩色圖片 def plt_show0(img): b,g,r = cv2.split(img) img = cv2.merge([r, g, b]) plt.imshow(img) plt.show() # plt顯示灰度圖片 def plt_show(img): plt.imshow(img,cmap='gray') plt.show() # 圖像去噪灰度處理 def gray_guss(image): image = cv2.GaussianBlur(image, (3, 3), 0) gray_image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) return gray_image # 讀取待檢測圖片 origin_image = cv2.imread('D:/image/car3.jpg') # 復制一張圖片,在復制圖上進行圖像操作,保留原圖 image = origin_image.copy() # 圖像去噪灰度處理 gray_image = gray_guss(image) # x方向上的邊緣檢測(增強邊緣信息) Sobel_x = cv2.Sobel(gray_image, cv2.CV_16S, 1, 0) absX = cv2.convertScaleAbs(Sobel_x) image = absX # 圖像閾值化操作——獲得二值化圖 ret, image = cv2.threshold(image, 0, 255, cv2.THRESH_OTSU) # 顯示灰度圖像 plt_show(image) # 形態(tài)學(從圖像中提取對表達和描繪區(qū)域形狀有意義的圖像分量)——閉操作 kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (30, 10)) image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernelX,iterations = 1) # 顯示灰度圖像 plt_show(image) # 腐蝕(erode)和膨脹(dilate) kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (50, 1)) kernelY = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 20)) #x方向進行閉操作(抑制暗細節(jié)) image = cv2.dilate(image, kernelX) image = cv2.erode(image, kernelX) #y方向的開操作 image = cv2.erode(image, kernelY) image = cv2.dilate(image, kernelY) # 中值濾波(去噪) image = cv2.medianBlur(image, 21) # 顯示灰度圖像 plt_show(image) # 獲得輪廓 contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for item in contours: rect = cv2.boundingRect(item) x = rect[0] y = rect[1] weight = rect[2] height = rect[3] # 根據(jù)輪廓的形狀特點,確定車牌的輪廓位置并截取圖像 if (weight > (height * 3)) and (weight < (height * 4.5)): image = origin_image[y:y + height, x:x + weight] plt_show(image) #車牌字符分割 # 圖像去噪灰度處理 gray_image = gray_guss(image) # 圖像閾值化操作——獲得二值化圖 ret, image = cv2.threshold(gray_image, 0, 255, cv2.THRESH_OTSU) plt_show(image) #膨脹操作 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (4, 4)) image = cv2.dilate(image, kernel) plt_show(image) # 查找輪廓 contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) words = [] word_images = [] #對所有輪廓逐一操作 for item in contours: word = [] rect = cv2.boundingRect(item) x = rect[0] y = rect[1] weight = rect[2] height = rect[3] word.append(x) word.append(y) word.append(weight) word.append(height) words.append(word) # 排序,車牌號有順序。words是一個嵌套列表 words = sorted(words,key=lambda s:s[0],reverse=False) i = 0 #word中存放輪廓的起始點和寬高 for word in words: # 篩選字符的輪廓 if (word[3] > (word[2] * 1.5)) and (word[3] < (word[2] * 5.5)) and (word[2] > 10): i = i+1 if word[2] < 15: splite_image = image[word[1]:word[1] + word[3], word[0]-word[2]:word[0] + word[2]*2] else: splite_image = image[word[1]:word[1] + word[3], word[0]:word[0] + word[2]] word_images.append(splite_image) print(i) print(words) for i,j in enumerate(word_images): plt.subplot(1,7,i+1) plt.imshow(word_images[i],cmap='gray') plt.show() #模版匹配 # 準備模板(template[0-9]為數(shù)字模板;) template = ['0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z', '藏','川','鄂','甘','贛','貴','桂','黑','滬','吉','冀','津','晉','京','遼','魯','蒙','閩','寧', '青','瓊','陜','蘇','皖','湘','新','渝','豫','粵','云','浙'] # 讀取一個文件夾下的所有圖片,輸入?yún)?shù)是文件名,返回模板文件地址列表 def read_directory(directory_name): referImg_list = [] for filename in os.listdir(directory_name): referImg_list.append(directory_name + "/" + filename) return referImg_list # 獲得中文模板列表(只匹配車牌的第一個字符) def get_chinese_words_list(): chinese_words_list = [] for i in range(34,64): #將模板存放在字典中 c_word = read_directory('D:/refer1/'+ template[i]) chinese_words_list.append(c_word) return chinese_words_list chinese_words_list = get_chinese_words_list() # 獲得英文模板列表(只匹配車牌的第二個字符) def get_eng_words_list(): eng_words_list = [] for i in range(10,34): e_word = read_directory('D:/refer1/'+ template[i]) eng_words_list.append(e_word) return eng_words_list eng_words_list = get_eng_words_list() # 獲得英文和數(shù)字模板列表(匹配車牌后面的字符) def get_eng_num_words_list(): eng_num_words_list = [] for i in range(0,34): word = read_directory('D:/refer1/'+ template[i]) eng_num_words_list.append(word) return eng_num_words_list eng_num_words_list = get_eng_num_words_list() # 讀取一個模板地址與圖片進行匹配,返回得分 def template_score(template,image): #將模板進行格式轉(zhuǎn)換 template_img=cv2.imdecode(np.fromfile(template,dtype=np.uint8),1) template_img = cv2.cvtColor(template_img, cv2.COLOR_RGB2GRAY) #模板圖像閾值化處理——獲得黑白圖 ret, template_img = cv2.threshold(template_img, 0, 255, cv2.THRESH_OTSU) # height, width = template_img.shape # image_ = image.copy() # image_ = cv2.resize(image_, (width, height)) image_ = image.copy() #獲得待檢測圖片的尺寸 height, width = image_.shape # 將模板resize至與圖像一樣大小 template_img = cv2.resize(template_img, (width, height)) # 模板匹配,返回匹配得分 result = cv2.matchTemplate(image_, template_img, cv2.TM_CCOEFF) return result[0][0] # 對分割得到的字符逐一匹配 def template_matching(word_images): results = [] for index,word_image in enumerate(word_images): if index==0: best_score = [] for chinese_words in chinese_words_list: score = [] for chinese_word in chinese_words: result = template_score(chinese_word,word_image) score.append(result) best_score.append(max(score)) i = best_score.index(max(best_score)) # print(template[34+i]) r = template[34+i] results.append(r) continue if index==1: best_score = [] for eng_word_list in eng_words_list: score = [] for eng_word in eng_word_list: result = template_score(eng_word,word_image) score.append(result) best_score.append(max(score)) i = best_score.index(max(best_score)) # print(template[10+i]) r = template[10+i] results.append(r) continue else: best_score = [] for eng_num_word_list in eng_num_words_list: score = [] for eng_num_word in eng_num_word_list: result = template_score(eng_num_word,word_image) score.append(result) best_score.append(max(score)) i = best_score.index(max(best_score)) # print(template[i]) r = template[i] results.append(r) continue return results word_images_ = word_images.copy() # 調(diào)用函數(shù)獲得結果 result = template_matching(word_images_) print(result) # "".join(result)函數(shù)將列表轉(zhuǎn)換為拼接好的字符串,方便結果顯示 print( "".join(result)) height,weight = origin_image.shape[0:2] print(height) print(weight) image_1 = origin_image.copy() cv2.rectangle(image_1, (int(0.2*weight), int(0.75*height)), (int(weight*0.9), int(height*0.95)), (0, 255, 0), 5) #設置需要顯示的字體 fontpath = "font/simsun.ttc" font = ImageFont.truetype(fontpath,64) img_pil = Image.fromarray(image_1) draw = ImageDraw.Draw(img_pil) #繪制文字信息 draw.text((int(0.2*weight)+25, int(0.75*height)), "".join(result), font = font, fill = (255, 255, 0)) bk_img = np.array(img_pil) print(result) print( "".join(result)) plt_show0(bk_img)
總結
到此這篇關于利用Python+Opencv實現(xiàn)車牌自動識別的文章就介紹到這了,更多相關Python+Opencv車牌自動識別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Pycharm Available Package無法顯示/安裝包的問題Error Loading Package Li
這篇文章主要介紹了Pycharm Available Package無法顯示/安裝包的問題Error Loading Package List解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-09-09Python三十行代碼實現(xiàn)簡單人臉識別的示例代碼
這篇文章主要介紹了Python三十行代碼實現(xiàn)簡單人臉識別的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-03-03使用Flask-Login模塊實現(xiàn)用戶身份驗證和安全性
當你想要在你的Flask應用中實現(xiàn)用戶身份驗證和安全性時,F(xiàn)lask-Login這個擴展將會是你的最佳伙伴,它提供了一組簡單而強大的工具來處理,下面我們就來看看具體的操作方法吧2023-08-08win7上tensorflow2.2.0安裝成功 引用DLL load failed時找不到指定模塊 tensorflo
這篇文章主要介紹了win7上tensorflow2.2.0安裝成功 引用時DLL load failed找不到指定模塊 tensorflow has no attribute xxx 解決方法,需要的朋友可以參考下2020-05-05