日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

OpenCV(项目)车牌识别4 -- 总结篇

發(fā)布時(shí)間:2023/11/27 生活经验 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OpenCV(项目)车牌识别4 -- 总结篇 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

一、效果

1、成功案例

2、經(jīng)典失敗案例(單字符識(shí)別成類似字符)

3、其他失敗案例

二、總結(jié)

三、車牌識(shí)別總代碼


一、效果

1、成功案例

?

2、經(jīng)典失敗案例(單字符識(shí)別成類似字符)

?

3、其他失敗案例

二、總結(jié)

????????前面字符提取比較成功的,大多數(shù)的識(shí)別都沒太大問題,但是字符提取不到位,后面的識(shí)別工作自然也很難進(jìn)行。這次的測試失敗有很多都是前面的工作沒有做好,尤其是第一步的車牌提取,個(gè)人感覺車牌提取是本次項(xiàng)目最困難的地方

三、車牌識(shí)別總代碼

# 車牌識(shí)別
import cv2 as cv
import numpy as np
import os
from matplotlib import pyplot as plt
from PIL import Image, ImageDraw, ImageFont# 總文件夾
List = ['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', '云','京','冀','吉','寧','川','新','晉','桂','滬','津','浙','渝','湘','瓊','甘','皖','粵','蘇','蒙','藏','豫','貴','贛','遼','鄂','閩','陜','青','魯','黑']
# 車牌數(shù)字列表(10)
Num_List = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
# 車牌英文列表(24)
Eng_List = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q','R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
# 車牌漢字列表(31)
Chinese_List = ['云','京','冀','吉','寧','川','新','晉','桂','滬','津','浙','渝','湘','瓊','甘','皖','粵','蘇','蒙','藏','豫','貴','贛','遼','鄂','閩','陜','青','魯','黑']
final_result = []# 得到黑底白字(白色多則返回真)
def IsWhiteMore(binary):white = black = 0height, width = binary.shape# 遍歷每個(gè)像素for i in range(height):for j in range(width):if binary[i,j]==0:black+=1else:white+=1if white >= black:return Trueelse:return False# 限制圖像大小(車牌)
def Limit(image):height, width, channel = image.shape# 設(shè)置權(quán)重weight = width/300# 計(jì)算輸出圖像的寬和高last_width = int(width/weight)last_height = int(height/weight)image = cv.resize(image, (last_width, last_height))return image# 二-5、統(tǒng)計(jì)白色像素點(diǎn)(分別統(tǒng)計(jì)每一行、每一列)
def White_Statistic(image):ptx = []  # 每行白色像素個(gè)數(shù)pty = []  # 每列白色像素個(gè)數(shù)height, width = image.shape# 逐行遍歷for i in range(height):num = 0for j in range(width):if(image[i][j]==255):num = num+1ptx.append(num)# 逐列遍歷for i in range(width):num = 0for j in range(height):if (image[j][i] == 255):num = num + 1pty.append(num)return ptx, pty# 二-6、繪制直方圖
def Draw_Hist(ptx, pty):# 依次得到各行、列rows, cols = len(ptx), len(pty)row = [i for i in range(rows)]col = [j for j in range(cols)]# 橫向直方圖plt.barh(row, ptx, color='black', height=1)#       縱    橫# plt.show()# 縱向直方圖plt.bar(col, pty, color='black', width=1)#       橫    縱# plt.show()# 二-7-2、橫向分割:上下邊框
def Cut_X(ptx, rows):# 橫向切割(分為上下兩張圖,分別找其波谷,確定頂和底)# 1、下半圖波谷min, r = 300, 0for i in range(int(rows / 2)):if ptx[i] < min:min = ptx[i]r = ih1 = r  # 添加下行(作為頂)# 2、上半圖波谷min, r = 300, 0for i in range(int(rows / 2), rows):if ptx[i] < min:min = ptx[i]r = ih2 = r  # 添加上行(作為底)return h1, h2# 二-7-3、縱向分割:分割字符
def Cut_Y(pty, cols, h1, h2, binary):global con, final_resultWIDTH = 33          # 經(jīng)過測試,一個(gè)字符寬度約為32w = w1 = w2 = 0     # 前谷 字符開始 字符結(jié)束begin = False       # 字符開始標(biāo)記last = 10           # 上一次的值con = 0             # 計(jì)數(shù)(字符)final_result = []   # 清空已識(shí)別的車牌# 縱向切割(正式切割字符)for j in range(int(cols)):# 0、極大值判斷if pty[j] == max(pty):if j < 30:  # 左邊(跳過)w2 = jif begin == True:begin = Falsecontinueelif j > 270:  # 右邊(直接收尾)if begin == True:begin = Falsew2 = jb_copy = binary.copy()b_copy = b_copy[h1:h2, w1:w2]# cv.imshow('binary%d-%d' % (count, con), b_copy)cv.imwrite('car_characters/image%d-%d.jpg' % (count, con), b_copy)Template_Match(b_copy)con += 1break# 1、前谷(前面的波谷)if pty[j] < 12 and begin == False:  # 前谷判斷:像素?cái)?shù)量<12last = pty[j]w = j# 2、字符開始(上升)elif last < 12 and pty[j] > 20:last = pty[j]w1 = jbegin = True# 3、字符結(jié)束elif pty[j] < 13 and begin == True:begin = Falselast = pty[j]w2 = jwidth = w2 - w1# 3-1、分割并顯示(排除過小情況)if 10 < width < WIDTH + 3:  # 要排除掉干擾,又不能過濾掉字符”1“b_copy = binary.copy()b_copy = b_copy[h1:h2, w1:w2]# cv.imshow('binary%d-%d' % (count, con), b_copy)cv.imwrite('car_characters/image%d-%d.jpg' % (count, con), b_copy)Template_Match(b_copy)con += 1# 3-2、從多個(gè)貼合字符中提取單個(gè)字符elif width >= WIDTH + 3:# 統(tǒng)計(jì)貼合字符個(gè)數(shù)num = int(width / WIDTH + 0.5)  # 四舍五入for k in range(num):# w1和w2坐標(biāo)向后移(用w3、w4代替w1和w2)w3 = w1 + k * WIDTHw4 = w1 + (k + 1) * WIDTHb_copy = binary.copy()b_copy = b_copy[h1:h2, w3:w4]# cv.imshow('binary%d-%d' % (count, con), b_copy)cv.imwrite('car_characters/image%d-%d.jpg' % (count, con), b_copy)Template_Match(b_copy)con += 1# 4、分割尾部噪聲(距離過遠(yuǎn)默認(rèn)沒有字符了)elif begin == False and (j - w2) > 30:break# 最后檢查收尾情況if begin == True:w2 = 295b_copy = binary.copy()b_copy = b_copy[h1:h2, w1:w2]# cv.imshow('binary%d-%d' % (count, con), b_copy)cv.imwrite('car_characters/image%d-%d.jpg' % (count, con), b_copy)Template_Match(b_copy)# 顯示識(shí)別結(jié)果(圖像)Show_Result_Image()# 二-7、分割車牌圖像(根據(jù)直方圖)
def Cut_Image(ptx, pty, binary, dilate):h1 = h2 = 0#頂  底begin = False        #標(biāo)記開始/結(jié)束# 1、依次得到各行、列rows, cols = len(ptx), len(pty)row = [i for i in range(rows)]col = [j for j in range(cols)]# 2、橫向分割:上下邊框h1, h2 = Cut_X(ptx, rows)# cut_x = binary[h1:h2, :]# cv.imshow('cut_x', cut_x)# 3、縱向分割:分割字符Cut_Y(pty, cols, h1, h2, binary)# 顯示文字(中文)(用的PIL,RGB正常顯示,即和opencv的RGB相反)
def Text(image, text, p, color, size):# cv2讀取圖片# BGR轉(zhuǎn)RGB:cv2和PIL中顏色的hex碼的儲(chǔ)存順序不同cv2_image = cv.cvtColor(image, cv.COLOR_RGB2BGR)pil_image = Image.fromarray(cv2_image)# PIL圖片上打印漢字draw = ImageDraw.Draw(pil_image)  # 圖片上打印font = ImageFont.truetype("./simhei.ttf", size, encoding="utf-8")  # 參數(shù)1:字體文件路徑,參數(shù)2:字體大小draw.text((p[0]-60, p[1]-20), text, color, font=font)# PIL圖片轉(zhuǎn)cv2 圖片cv2_result = cv.cvtColor(np.array(pil_image), cv.COLOR_RGB2BGR)# cv2.imshow("圖片", cv2_result)      # 漢字窗口標(biāo)題顯示亂碼# cv.imshow("photo", cv2_result)     # 輸出漢字return cv2_result# 顯示識(shí)別結(jié)果(文字)
def Show_Result_Words(index):print(List[index])final_result.append(List[index])print(final_result)# 顯示識(shí)別結(jié)果(圖像)
def Show_Result_Image():p = image_rect[0], image_rect[1]w, h = image_rect[2] , image_rect[3]# 框出車牌cv.rectangle(img, (p[0],p[1]), (p[0]+w, p[1]+h), (0,0,255), 2)# 輸出字符(中文)result = Text(img, str(final_result), p, (255,0,0), 16)cv.imshow('result-%d'%count, result)# cv.waitKey(0)# 一、形態(tài)學(xué)提取車牌
def Get_Licenses(image):global image_rect       #待返回的矩形坐標(biāo)# 1、轉(zhuǎn)灰度圖gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)# cv.imshow('gray', gray)# 2、頂帽運(yùn)算# 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、自適應(yīng)二值化(閾值自己可調(diào))ret, binary = cv.threshold(absY, 75, 255, cv.THRESH_BINARY)# cv.imshow('binary', binary)# 5、開運(yùn)算分割(縱向去噪,分隔)kernel = cv.getStructuringElement(cv.MORPH_RECT, (1, 15))Open = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel)# cv.imshow('Open', Open)# 6、閉運(yùn)算合并,把圖像閉合、揉團(tuán),使圖像區(qū)域化,便于找到車牌區(qū)域,進(jìn)而得到輪廓kernel = cv.getStructuringElement(cv.MORPH_RECT, (41, 15))close = cv.morphologyEx(Open, cv.MORPH_CLOSE, kernel)# cv.imshow('close', close)# 7、膨脹/腐蝕(去噪得到車牌區(qū)域)# 中遠(yuǎn)距離車牌識(shí)別kernel_x = cv.getStructuringElement(cv.MORPH_RECT, (25, 7))kernel_y = cv.getStructuringElement(cv.MORPH_RECT, (1, 11))# 近距離車牌識(shí)別# 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 = image.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 = 0for contour in contours:# 10-1、得到矩形區(qū)域:左頂點(diǎn)坐標(biāo)、寬和高rect = cv.boundingRect(contour)# 10-2、判斷寬高比例是否符合車牌標(biāo)準(zhǔn),截取符合圖片if rect[2]>rect[3]*3 and rect[2]<rect[3]*7:# 截取車牌并顯示print(rect)image_rect = rectimg_copy = image.copy()image = image[(rect[1]):(rect[1]+rect[3]), (rect[0]):(rect[0]+rect[2])] #高,寬try:# 限制大小(按照比例限制)image = Limit(image)cv.imshow('license plate%d-%d' % (count, i), image)cv.imwrite('car_licenses/image%d-%d.jpg'%(count, i), image)i += 1return imageexcept:passreturn image# 二、直方圖提取字符
def Get_Character(image):# 清空final_result = []# 1、中值濾波mid = cv.medianBlur(image, 5)# 2、灰度化gray = cv.cvtColor(mid, cv.COLOR_BGR2GRAY)# 3、二值化ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_OTSU)# 統(tǒng)一得到黑底白字if(IsWhiteMore(binary)):     #白色部分多則為真,意味著背景是白色,需要黑底白字ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_OTSU | cv.THRESH_BINARY_INV)cv.imshow('binary', binary)# 4、膨脹(粘貼橫向字符)kernel = cv.getStructuringElement(cv.MORPH_RECT, (7,1))     #橫向連接字符dilate = cv.dilate(binary, kernel)# cv.imshow('dilate', dilate)# 5、統(tǒng)計(jì)各行各列白色像素個(gè)數(shù)(為了得到直方圖橫縱坐標(biāo))ptx, pty = White_Statistic(dilate)# 6、繪制直方圖(橫、縱)Draw_Hist(ptx, pty)# 7、分割(橫、縱)(橫向分割邊框、縱向分割字符)Cut_Image(ptx, pty, binary, dilate)# cv.waitKey(0)# 三、模板匹配
# 原圖和模板進(jìn)行對比,越匹配,得分越大
def Template_Match(image):# 單文件夾內(nèi)的最佳得分best_score = []# 遍歷所有文件夾(每一個(gè)文件夾匹配)# (1) 漢字(首個(gè)位置只能是漢字(省))(為了節(jié)約時(shí)間)if con == 0:# 遍歷34——65文件夾(漢字)for i in range(34,65):# 單個(gè)圖片的得分score = []ForderPath = 'Template/' + List[i]# 遍歷單文件夾(每一個(gè)文件匹配)for filename in os.listdir(ForderPath):# 路徑path = 'Template/' + List[i] + '/' + filename# 1、得到模板template = cv.imdecode(np.fromfile(path, dtype=np.uint8), 1)    #彩(類似imread)gray = cv.cvtColor(template, cv.COLOR_RGB2GRAY)                 #灰ret, template = cv.threshold(gray, 0, 255, cv.THRESH_OTSU)      #二值# 2、原圖限定大小(和模板相似)h, w = template.shapeimage = cv.resize(image, (w, h))# 3、模板匹配,得到得分(匹配度越高,得分越大)result = cv.matchTemplate(image, template, cv.TM_CCOEFF)score.append(result[0][0])          #得分(每張模板圖)# 4、保存子文件夾的最高得分(得分越高,匹配度越高)best_score.append(max(score))# 5、根據(jù)所有文件夾的最佳得分確定下標(biāo)index = best_score.index(max(best_score))+34# (2) 字母(第二個(gè)位置只能為字母)elif con == 1:# 遍歷10~34文件夾(字母文件夾)for i in range(10,34):# 單個(gè)圖片的得分score = []ForderPath = 'Template/' + List[i]# 遍歷單文件夾(每一個(gè)文件匹配)for filename in os.listdir(ForderPath):# 路徑path = 'Template/' + List[i] + '/' + filename# 模板template = cv.imdecode(np.fromfile(path, dtype=np.uint8), 1)    #彩(類似imread)gray = cv.cvtColor(template, cv.COLOR_RGB2GRAY)                 #灰ret, template = cv.threshold(gray, 0, 255, cv.THRESH_OTSU)      #二值h, w = template.shapeimage = cv.resize(image, (w, h))# 模板匹配,得到得分(匹配度越高,得分越大)result = cv.matchTemplate(image, template, cv.TM_CCOEFF)score.append(result[0][0])          #得分(每張模板圖)# 一個(gè)文件夾的最高得分(得分越高,匹配度越高)best_score.append(max(score))# 根據(jù)所有文件夾的最佳得分確定下標(biāo)index = best_score.index(max(best_score)) + 10# (3) 數(shù)字+字母else:# 遍歷0~34文件夾(數(shù)字+字母)for i in range(34):# 單個(gè)圖片的得分score = []ForderPath = 'Template/' + List[i]# 遍歷單文件夾(每一個(gè)文件匹配)for filename in os.listdir(ForderPath):# 路徑path = 'Template/' + List[i] + '/' + filename# 模板template = cv.imdecode(np.fromfile(path, dtype=np.uint8), 1)    #彩(類似imread)gray = cv.cvtColor(template, cv.COLOR_RGB2GRAY)                 #灰ret, template = cv.threshold(gray, 0, 255, cv.THRESH_OTSU)      #二值h, w = template.shapeimage = cv.resize(image, (w, h))# 模板匹配,得到得分(匹配度越高,得分越大)result = cv.matchTemplate(image, template, cv.TM_CCOEFF)score.append(result[0][0])          #得分(每張模板圖)# 一個(gè)文件夾的最高得分(得分越高,匹配度越高)best_score.append(max(score))# 根據(jù)所有文件夾的最佳得分確定下標(biāo)index = best_score.index(max(best_score))# 顯示結(jié)果(文字)(每識(shí)別一個(gè)顯示一次)Show_Result_Words(index)if __name__ == '__main__':global count, imgcount=0         #計(jì)數(shù):第幾張圖片# cv.waitKey(0)# 遍歷文件夾中的每張圖片(車)for car in os.listdir('cars'):# 1、獲取路徑path = 'cars/'+'car'+str(count)+'.jpg'# 2、獲取圖片img = cv.imread(path)image = img.copy()# cv.imshow('image', image)# 3、提取車牌image = Get_Licenses(image)         #形態(tài)學(xué)提取車牌# 4、分割字符Get_Character(image)count += 1cv.waitKey(0)

????????一張車牌約20秒,這些算法很多可能已經(jīng)逐漸被淘汰了,這里只是作為學(xué)習(xí)用途,沒有太高的實(shí)際應(yīng)用價(jià)值。(后期進(jìn)軍深度學(xué)習(xí)/機(jī)器學(xué)習(xí),可能會(huì)對這些進(jìn)行優(yōu)化)。有什么好的建議大家可以提出來,共同進(jìn)步,謝謝~

總結(jié)

以上是生活随笔為你收集整理的OpenCV(项目)车牌识别4 -- 总结篇的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。