
簡介一份基于MATLAB的車牌識別課程論文與配套源碼資料面向數(shù)字圖像處理、智能交通相關(guān)課程設(shè)計與畢業(yè)設(shè)計人群覆蓋車牌定位、字符切割、字符識別等核心環(huán)節(jié)。文檔系統(tǒng)闡述車牌區(qū)域提取的灰度化、Roberts邊緣檢測、腐蝕平滑與邊界值計算以及字符切割中的去噪、膨脹處理和字符歸一化同時討論國內(nèi)車牌漢字、數(shù)字、字母混合和外部光照干擾等難點并給出數(shù)學形態(tài)法、彩色分割、垂直投影等定位與分割思路。配套部分包含圖像預處理、邊緣提取等程序流程說明、關(guān)鍵公式與運行效果圖可直接作為課程報告、論文寫作或MATLAB算法復現(xiàn)的參考。壓縮包為單個doc文件容量約594KB整體結(jié)構(gòu)清晰目前已有314人學習適合需要快速搭建車牌識別實驗框架的初學者。1. 一套能跑的 MATLAB 車牌識別從課程設(shè)計到實用項目的完整范本如果你正在做數(shù)字圖像處理課程設(shè)計或者在找一個能直接運行、每步都能可視化的車牌識別參考實現(xiàn)這份《MATLAB車牌識別論文加源碼》值得拆開讀一遍。整套方案沒有走深度學習路線而是把經(jīng)典圖像處理三板斧練了一遍灰度化與邊緣檢測做預處理數(shù)學形態(tài)學和雙向投影做車牌定位垂直投影切割字符最后用模板匹配輸出車牌號。它最大的價值在于算法透明、參數(shù)全暴露在腳本里適合新手理解識別鏈路也適合熟手把它當算法基線做二次改造。適用人群很明確寫圖像處理課程論文的學生、需要快速搭 Demo 驗證效果的開發(fā)者以及想把手寫字符識別流程徹底吃透的算法初學者。2. 圖像預處理鏈路灰度化、邊緣檢測與形態(tài)學操作車牌識別第一步不是直接找車牌而是把一張彩色車輛照片處理成干凈的、車牌區(qū)域能凸顯出來的二值圖。整條鏈路在源碼里是串行執(zhí)行的每一步都落一個中間變量方便在 MATLAB 里斷開調(diào)試。這一章的輸入是一張普通的車輛照片輸出是一張理論上只剩車牌區(qū)域前景點的二值圖后面的定位和字符切割全部建立在這張圖上。2.1 灰度化與線性灰度增強先統(tǒng)一色彩空間[filename, filepath] uigetfile(.jpg, 輸入一個需要識別的車牌圖像); I imread([filepath, filename]); % 拼出完整路徑并讀圖 I1 rgb2gray(I); % RGB彩色圖轉(zhuǎn)灰度圖 figure(name,灰度處理前), subplot(1,2,1), imshow(I1); subplot(1,2,2), imhist(I1); % 顯示灰度直方圖 I1 imadjust(I1, [0.3,0.7], []); % 線性灰度變換拉伸中間灰度區(qū)間 I1 medfilt2(I1); % 3x3中值濾波去噪這段是標準的圖像預處理好習慣先看直方圖再決定增強參數(shù)。imhist 打印灰度分布能直觀看出圖像是偏亮還是偏暗——如果峰值集中在 0.3 以下說明車牌區(qū)域和背景的對比度不足后面的邊緣檢測會漏掉很多字符邊緣。imadjust 的[0.3,0.7]參數(shù)是把原圖歸一化灰度在 0.3 到 0.7 之間的像素線性拉伸到 0 到 1 的完整區(qū)間小于 0.3 的像素變成 0大于 0.7 的變成 1。效果是讓中間灰度段的對比度翻倍車牌字符和底色的差距被放大。如果光照特別強或特別暗這個區(qū)間都要跟著調(diào)暗圖用[0.2,0.6]亮圖用[0.4,0.8]這是比較常用的經(jīng)驗值。medfilt2 是 3x3 中值濾波把每個像素替換成周圍 9 個像素的中值對椒鹽噪聲非常有效。它比均值濾波好在保留邊緣不模糊而邊緣正是車牌識別最依賴的特征。注意濾波放在 imadjust 之后而不是之前是因為線性灰度變換會放大噪聲先增強再濾波能一起處理掉增強后的殘留噪點。2.2 Roberts邊緣檢測找出字符與底色的跳變點I2 edge(I1, roberts, 0.25, both); % Roberts算子閾值0.25雙向檢測 figure(name,邊緣檢測), imshow(I2);edge 函數(shù)里roberts對應(yīng) Roberts 交叉梯度算子它的思路是用對角線相鄰像素的差值近似梯度水平方向梯度 Gxf(x,y)-f(x-1,y-1)垂直方向梯度 Gyf(x,y-1)-f(x-1,y)幅值 Gsqrt(Gx^2Gy^2)幅值超過 0.25 的像素被標為邊緣點。0.25 是歸一化后的閾值不是固定值——如果圖像噪聲大閾值要往上提不然邊緣圖會糊成一片如果車牌字符過淡閾值要降低。怎么判斷合不合適看邊緣圖里車牌區(qū)域是不是字符輪廓完整、背景區(qū)域有沒有大量白點。為什么這里選 Roberts 而不是 Sobel 或 Canny我拆這套代碼時對比過Sobel 對橫向邊緣響應(yīng)更強但車牌漢字橫豎筆畫都有會讓豎筆畫邊緣變?nèi)魿anny 的雙閾值會引入大量與牌照無關(guān)的紋理邊緣后續(xù)形態(tài)學處理更麻煩。Roberts 計算量最小、對細筆畫邊緣最敏感配合后續(xù)腐蝕操作反而能得到一個干凈的車牌輪廓。both參數(shù)表示水平和垂直兩個方向都做梯度運算缺省只做垂直方向?qū)h字這種橫豎交錯的字符必須雙向檢測。2.3 腐蝕與閉運算把字符邊緣連成連通域se [1;1;1]; % 豎直3x1結(jié)構(gòu)元素 I3 imerode(I2, se); % 腐蝕保留連續(xù)豎直邊緣 se strel(rectangle, [20,20]); % 20x20矩形結(jié)構(gòu)元素 I4 imclose(I3, se); % 閉運算連接鄰近前景塊第一次腐蝕的 se 是 3x1 豎直向量意思是輸出像素取輸入圖像 3x1 鄰域里的最小值只要這個豎直條里有一個像素不是前景輸出就是 0。效果是只有豎直方向上連續(xù) 3 個點都是邊緣才保留下來。車牌邊框的豎邊連續(xù)能留下來字符橫筆畫產(chǎn)生的橫向邊緣在豎直方向不連續(xù)被刪掉背景里零散噪點也基本被過濾。這一步的目的是簡化畫面讓后面投影定位時干擾更少。imclose 是閉運算先膨脹后腐蝕。20x20 矩形結(jié)構(gòu)元素決定“多近的前景會被連在一起”——兩個前景塊之間空隙小于 20 像素就會被膨脹填上再腐蝕回來時已經(jīng)連成整體。這正好匹配車牌的幾何特點字符間距和邊框間距通常小于 20 像素而整個車牌區(qū)域的寬遠大于 20 像素。閉運算的結(jié)果是出現(xiàn)一個或多個大塊的連通區(qū)域其中最大的那個通常是車牌。如果結(jié)構(gòu)元素太小字符邊緣連不成片太大車標和車身裝飾條也會被連進來。20x20 是原作者調(diào)的默認值換數(shù)據(jù)集時值得重新試驗。2.4 移除小對象濾掉車標和車身文字干擾I5 bwareaopen(I4, 1000); % 刪除面積小于1000像素的前景連通域 figure(name,移除小對象), imshow(I5);bwareaopen 遍歷二值圖像的所有連通對象統(tǒng)計每個對象的前景像素數(shù)小于給定值的整個填成背景。默認 8 鄰域連通也就是斜對角相鄰也算同一個對象。1000 這個閾值和圖像分辨率有關(guān)分辨率越高車牌區(qū)域的前景像素越多閾值可以越大。源碼注釋里寫了 2000實際跑的是 1000我建議在調(diào)試時用regionprops把所有連通域面積打出來看一下車牌區(qū)域的面積通常是第二名的好幾倍這時候閾值怎么定都不會錯。這一步處理完理論上畫面里只剩車牌這一塊前景可以直接進入投影定位。調(diào)試這段鏈路我一般這樣定位問題灰度圖對比度不夠就調(diào) imadjust邊緣圖太花就調(diào)高 edge 閾值腐蝕后還殘留橫線就調(diào)大腐蝕結(jié)構(gòu)元素閉運算連通不到一起就調(diào)大矩形尺寸。逐段判斷不要一上來就懷疑最后的結(jié)果。3. 車牌定位核心雙向投影與經(jīng)驗邊界校正預處理輸出 I5 理論上只剩車牌區(qū)域的前景像素但還沒有任何幾何信息。定位這一步要回答兩個問題車牌在圖片的哪幾行、哪幾列源碼用水平加垂直雙向投影來實現(xiàn)思路非常直接把前景像素分別往 x 軸和 y 軸方向累加得到一個投影曲線曲線峰值所在的位置就是車牌中心從峰值向兩側(cè)掃描到曲線跌落的位置就是邊界。3.1 水平投影找到車牌所在的行區(qū)間[y, x, z] size(I5); % 取圖像尺寸y行數(shù) x列數(shù) myI double(I5); % 轉(zhuǎn)double便于1判斷 Blue_y zeros(y, 1); % 每行前景像素計數(shù)數(shù)組 for i 1:y for j 1:x if myI(i, j, 1) 1 % 前景點為1 Blue_y(i, 1) Blue_y(i, 1) 1; end end end [temp, MaxY] max(Blue_y); % 前景像素最多的行這段代碼用雙重循環(huán)逐行統(tǒng)計前景點數(shù)量得到行投影向量 Blue_y。max 函數(shù)返回兩個值第一返回值 temp 是最大值本身第二返回值 MaxY 是它出現(xiàn)的行號也就是車牌中心行。需要提醒的是if myI(i,j,1)1判斷的是二值圖的前景源碼注釋寫“判斷藍色像素”容易誤導初學者。實際上預處理后已經(jīng)是黑白二值圖沒有顏色語義這里就是在數(shù)白色前景點真正的顏色信息要到后面定位裁剪時才從原圖取回來。統(tǒng)計完行投影后從中心行分別向上、向下掃描邊界PY1 MaxY; while (Blue_y(PY1, 1) 5) (PY1 1) PY1 PY1 - 1; end PY2 MaxY; while (Blue_y(PY2, 1) 5) (PY2 y) PY2 PY2 1; end兩個 while 循環(huán)的邏輯是從中心行往上走只要當前行的前景點數(shù)不小于 5就繼續(xù)往上直到某一行前景點數(shù)小于 5 或到達圖像邊緣為止。這個 5 像素閾值是經(jīng)驗值作用是容忍車牌區(qū)域內(nèi)可能出現(xiàn)的零星噪聲——正常情況下車牌每一行都有大量前景像素遠大于 5而邊界外的噪聲行通常只有 1、2 個前景點。如果閾值設(shè)成 1邊界會非常毛躁設(shè)成 10傾斜車牌或光照不均導致的行稀疏區(qū)域會被切掉。PY1 和 PY2 最終圈定了車牌在圖像中的行范圍。3.2 垂直投影限定列范圍行范圍確定后垂直投影只掃描 PY1 到 PY2 之間的行既減少計算量又避免把行范圍外的干擾算進來Blue_x zeros(1, x); for j 1:x for i PY1:PY2 % 只掃車牌行區(qū)間 if myI(i, j, 1) 1 Blue_x(1, j) Blue_x(1, j) 1; end end end PX1 1; while (Blue_x(1, PX1) 3) (PX1 x) PX1 PX1 1; end PX2 x; while (Blue_x(1, PX2) 3) (PX2 PX1) PX2 PX2 - 1; endBlue_x 統(tǒng)計每一列在車牌行區(qū)間里的前景像素總數(shù)。PX1 從左邊開始向右找第一個前景列數(shù)大于等于 3 的列PX2 從右邊向左同理。列閾值用 3 而不是 5是因為字符之間有間隙漢字和字母的筆畫在某幾列上可能只有 2、3 個前景點閾值太高會把字符起始列漏掉。兩個方向閾值不同的原因就在這行方向上整個車牌寬度都有字符覆蓋列方向上字符筆畫稀疏得多。到這里車牌的四個邊界都有了粗略估計。3.3 邊界校正與彩色車牌裁剪投影直接給的邊界往往太緊會切掉車牌的上邊框或字符的外沿。源碼在邊界外擴了幾個像素再從原圖裁剪PY1 PY1 - 2; % 上邊界向上擴2像素 PX1 PX1 - 2; % 左邊界向左擴2像素 PX2 PX2 3; % 右邊界向右擴3像素 PY2 PY2 10; % 下邊界向下擴10像素 dw I(PY1:PY2-8, PX1:PX2, :); % 從原彩色圖上裁剪車牌 imwrite(dw, dw.jpg);擴邊的思路是橫向投影時車牌下邊緣因為有螺絲、底框?qū)е逻吔缍ㄎ黄咚韵逻吔缍鄶U 10 像素再從底部剪掉 8 像素留下一個略寬松的車牌區(qū)域。PX2 加 3 是因為車牌的右側(cè)字符間距較大直接投影容易丟掉最后一個字符的右邊緣。這些數(shù)字沒有理論推導完全是原分辨率下的經(jīng)驗值。如果你換一張分辨率不同的測試圖應(yīng)該按比例調(diào)整比如分辨率翻倍擴邊像素也大致翻倍。定位效果直接看 dw 圖就能判斷理想結(jié)果是從原圖裁出一塊尺寸比例接近 3:1 的彩色區(qū)域包含完整的車牌字符。如果 dw 里缺字符或混入車身區(qū)域優(yōu)先回看 I5 是不是干凈的前景圖。定位最怕的是傾斜車牌純水平垂直投影對傾斜超過 5 度的車牌基本失效后面二次開發(fā)會提到怎么處理。4. 字符分割與識別從二值化到模板匹配的最后一公里定位得到彩色車牌 dw 之后剩余工作分兩步把車牌圖像切成 7 個獨立字符再用模板匹配逐個識別。這一章是整個流程里最瑣碎的部分也是參數(shù)最多、最容易翻車的地方。4.1 車牌二值化灰度閾值的選擇與自適應(yīng)膨脹腐蝕a imread(dw.jpg); % 讀回定位裁剪出的車牌 b rgb2gray(a); % 車牌彩色圖轉(zhuǎn)灰度 b imadjust(b, [0.3,0.7], []); % 再做一次線性灰度增強 d im2bw(b, 0.4); % 閾值0.4轉(zhuǎn)二值圖 d medfilt2(d); % 中值濾波去二值化后的毛刺車牌二值化和普通灰度圖二值化不一樣車牌字符和底色對比度本來就高理論上 0.3 到 0.6 之間的閾值都能把字符分出來。但光照不均時車牌的亮點和陰影會讓同一張圖里字符亮度不一致固定閾值 0.4 可能讓部分字符斷筆。原作在注釋里寫了更穩(wěn)妥的方案根據(jù)灰度最大最小值自動計算閾值Tround(g_max-(g_max-g_min)/3)也就是取灰度范圍偏亮的位置。這個公式的直覺是字符取高灰度、背景取低灰度閾值落在兩者之間偏上的位置避免把字符當成背景。二值化后源碼做了一步“看面積比決定膨脹還是腐蝕”的操作se eye(2); % 2x2單位矩陣作結(jié)構(gòu)元素 [m, n] size(d); if bwarea(d)/m/n 0.365 d imerode(d, se); % 前景占比過大腐蝕收縮 elseif bwarea(d)/m/n 0.235 d imdilate(d, se); % 前景占比過小膨脹加粗 endbwarea 計算二值圖前景總面積m*n 是圖像總像素數(shù)兩個的比值就是字符面積占車牌面積的比例。正常車牌字符筆畫面積占比集中在 0.235 到 0.365 之間。高于 0.365 說明前景太多可能是噪聲被當成字符用 imerode 把筆畫變細低于 0.235 說明前景太少字符可能斷筆太細用 imdilate 加粗。這個自適應(yīng)的思路很實用——它不需要知道圖像分辨率只看比例就能判斷當前二值化是否偏了。結(jié)構(gòu)元素取 eye(2) 是 2x2 單位矩陣腐蝕和膨脹的幅度很小一次處理不會過度改變筆畫粗細。4.2 垂直投影字符切割qiege與getword的配合切割是整個系統(tǒng)里最依賴圖像質(zhì)量的環(huán)節(jié)。源碼的策略是先用 qiege 子程序清理二值圖像的邊緣干擾再通過垂直投影把字符一個個切出來。qiege 在原素材里沒有單獨貼源碼但調(diào)用方式很明確它輸入二值圖輸出的是去掉上下左右多余邊框和離散噪點的干凈二值圖。常見實現(xiàn)是去掉四周與邊框相連的前景像素再做一次連通域篩選。getword 則是從圖左邊緣開始逐列掃描垂直投影遇到連續(xù)前景列就截成一個候選字符返回字符圖像和剩余圖像。主程序里的核心切割邏輯如下s sum(d); % 每列前景像素數(shù)垂直投影 while j ~ n while s(j) 0 % 跳過字符間隙的空白列 j j 1; end k1 j; % 字符起始列 while s(j) ~ 0 j n-1 % 繼續(xù)掃到字符結(jié)束列 j j 1; end k2 j - 1; % 字符結(jié)束列 if k2 - k1 round(n/6.5) % 寬度異常大說明可能是兩個字符粘連 [val, num] min(sum(d(:, [k15:k2-5]))); % 在投影谷底切開 d(:, k1num5) 0; end endsum(d) 對二值圖逐列求和每列的值表示該列有多少個前景像素。字符筆畫列前景像素多字符間隙列接近 0。內(nèi)層第一個 while 跳過空白列找到字符起始位置 k1第二個 while 掃描到投影落回 0 的位置得到結(jié)束位置 k2。正常情況下 7 個字符的寬度差別不大單個字符寬度約為整張圖寬度的 1/7所以round(n/6.5)作為“這個塊是不是太寬”的判斷閾值——比 1/7 略大允許漢字和數(shù)字正常寬度范圍。如果某個塊超過這個值說明可能有兩個字符粘在一起這時在塊內(nèi)找投影最小值的位置把這一列填成 0強行分成兩個字符。這就是垂直投影分割的經(jīng)典補丁正常用投影間隙切粘連時用投影谷底強行斷開。字符切割完成后前幾個字符還要去掉左側(cè)的干擾塊while flag 0 [m, n] size(d); wide 0; while sum(d(:, wide1)) ~ 0 % 統(tǒng)計左起連續(xù)前景列寬度 wide wide 1; end if wide 10 % 寬度小于10像素判定為左側(cè)干擾 d(:, 1:wide) 0; % 抹掉干擾列 d qiege(d); else temp qiege(imcrop(d, [1 1 wide m])); % 檢查這個塊的中間三分之二區(qū)域前景占比漢字通常很飽滿 two_thirds sum(sum(temp([round(m/3):2*round(m/3)], :))); if two_thirds/sum(sum(temp)) 0.25 flag 1; word1 temp; % 確認這是第一個字符 end d(:, 1:wide) 0; d qiege(d); end endwide 統(tǒng)計左側(cè)連續(xù)前景列的數(shù)量。車牌左側(cè)經(jīng)常殘留一塊定位時的背景邊緣寬度一般遠小于 10 像素直接抹掉。寬度大于 10 的塊不一定是干擾可能是真的第一個字符省份漢字這時用三分之二區(qū)域前景占比做二次判斷漢字筆畫集中在中間高度字符區(qū)域中間三分之二行的前景占比超過 0.25 就認為是合法字符。這段邏輯寫成 while 循環(huán)的原因是干擾可能有多塊需要多次切割才能碰到真正的漢字。0.25 這個值也是經(jīng)驗值筆畫粗的車牌可以放寬到 0.2。后續(xù)幾個字符直接調(diào)用[word2,d]getword(d)依次切出邏輯與上面一致。4.3 字符歸一化與模板匹配識別切出的字符大小不一致模板匹配前必須統(tǒng)一尺寸。源碼把所有字符縮放到 40x20word1 imresize(word1, [40 20], nearest); % 高度40 寬度20最近鄰插值 imwrite(word1, 1.jpg);imresize 第二參數(shù)[40 20]是輸出尺寸40 行 20 列模板庫里所有模板也是這個尺寸。插值方式用nearest是速度最快的最近鄰但會產(chǎn)生鋸齒對匹配結(jié)果有影響實測用bilinear雙線性插值識別率能提高一點代價是運行時間略微增加。每個字符還單獨寫成 1.jpg 到 7.jpg方便中途檢查切割效果。模板匹配本身就是一個逐像素比較的循環(huán)liccode char([0:9 A:Z 京遼桂陜蘇渝浙]); % 模板字符表 ... for k2 kmin:kmax fname strcat(字符模板\, liccode(k2), .jpg); SamBw2 imread(fname); % 讀一個模板 for i 1:40 for j 1:20 SubBw2(i,j) SegBw2(i,j) - SamBw2(i,j); % 逐像素做差 end end Dmax 0; for k1 1:40 for l1 1:20 if SubBw2(k1,l1) 10 || SubBw2(k1,l1) -10 Dmax Dmax 1; % 差異超過10算一個錯誤點 end end end Error(k2) Dmax; end Error1 Error(kmin:kmax); MinError min(Error1); findc find(Error1 MinError); % 取差異最小的模板 Code(l) liccode(findc(1) kmin - 1);這段做了三件事構(gòu)造模板索引、兩圖相減、統(tǒng)計差異點數(shù)。差異容限 10 像素的意思是允許字符邊緣有輕微偏移和噪聲超過 10 認為是實質(zhì)性差異。匹配范圍按車牌規(guī)則收縮第一位是省份漢字只遍歷 37 到 43第二位是英文字母遍歷 11 到 36第三位開始字母數(shù)字混合遍歷 1 到 36。這樣既不浪費時間也避免把數(shù)字 8 識別成漢字。Code 每識別一個字符追加一次第 3 位前插入兩個空格最終拼出類似“京A·12345”形式的字符串。模板匹配的識別率上限由模板庫質(zhì)量決定。這套源碼只提供了每個字符一張模板同一字符在不同字體、不同筆畫粗細下差異很大所以它對輸入圖像要求很苛刻——車牌必須正、清晰、字符筆畫粗細和模板相近。這也是二次開發(fā)最先要升級的地方。5. 避坑排查四個讓新手翻車的常見問題這套源碼能跑通但跑通和跑對是兩回事。我在拆它的過程中踩了不少坑整理成排查清單按現(xiàn)象到原因到解決的順序?qū)憽?.1 現(xiàn)象車牌定位框偏大或偏小甚至框到車身定位剪切后的 dw 圖里混入大量車身區(qū)域或者只剩半個車牌。原因在定位完全依賴 I5 的前景分布I5 里如果殘留車標、車身反光條的前景塊這些塊面積大于 1000 會被保留投影峰值被拉偏如果車牌本身亮度低邊緣檢測漏檢投影峰值反而落在別處。解決先用regionprops打印所有連通域面積確認車牌區(qū)域面積是第二名的 3 倍以上若車牌區(qū)域面積偏小把 imadjust 區(qū)間調(diào)低讓暗部細節(jié)出來若殘留干擾多把 bwareaopen 閾值從 1000 提到 3000 再試。調(diào)參順序不要亂從源頭往尾部走先看邊緣圖再決定動哪里。5.2 現(xiàn)象字符分割時兩個字粘連成一個塊切割出的 7 個字符里某兩個字符被合成一個寬度明顯是其他字符的 1.5 倍以上。原因多是 imclose 的 20x20 矩形結(jié)構(gòu)元素把字符間隙堵住了二值化時字符筆畫本身又被加粗也可能是輸入圖像分辨率較高字符間隙在圖像上超過 20 像素被膨脹連上。解決把 imclose 結(jié)構(gòu)元素從[20,20]降到[12,12]讓閉運算只連接真正的邊框和字符邊緣如果還粘連同時把 im2bw 閾值從 0.4 提高到 0.5讓字符筆畫變細、間隙更明顯。調(diào)這兩處要配對著改改完重新從定位開始跑看 I4 效果圖確認粘連是否解除。5.3 現(xiàn)象模板匹配把“8”識別成“B”、“0”識別成“O”識別結(jié)果字符串里數(shù)字位出現(xiàn)字母、字母位出現(xiàn)數(shù)字其他字符都對。原因一是模板只有一張40x20 的 nearest 縮放讓字符產(chǎn)生鋸齒8 和 B 的差異點集中在左下角開口處鋸齒會掩蓋這個差異二是二值化后字符粗細不均筆畫寬的 8 和窄的 B 更接近。解決把 imresize 插值改成bilinear讓邊緣更平滑更重要的是擴充模板庫每個字符存 2 到 3 套不同字形的模板匹配時取所有模板的最小差異。對 8 和 B 這類相似字符可以在差異點計數(shù)時給不同位置加權(quán)重字符下半部分的差異權(quán)重大于上半部分這樣 8 和 B 的差異就會被放大。5.4 現(xiàn)象運行到匹配階段報錯“找不到字符模板文件”報錯信息顯示字符模板\*.jpg不存在程序在 imread 處中斷。原因是相對路徑問題——腳本用strcat(字符模板\, liccode(k2), .jpg)拼路徑如果 MATLAB 當前工作目錄不在源碼目錄或者字符模板文件夾名不一致路徑就失效。解決用fullfile(pwd, 字符模板, [liccode(k2), .jpg])拼絕對路徑或者把字符模板文件夾添加到 MATLAB 路徑。更穩(wěn)妥的做法是在 main 開頭加一句cd(fileparts(mfilename(fullpath)))讓工作目錄始終切到腳本所在目錄。這個坑和算法無關(guān)但足以讓整個程序跑不起來。5.5 現(xiàn)象同一張圖跑兩次結(jié)果不穩(wěn)定有時候連續(xù)運行兩次識別結(jié)果或定位框不一樣。排除圖片選擇差異后最常見的元兇是工作區(qū)變量殘留——上一次運行的中間變量沒清干凈第二次運行時定位和切割拿到的還是舊值。原代碼開頭只寫了close all; clc沒有清變量。解決腳本第一行加clear all;確保每次運行是全新狀態(tài)。調(diào)試時養(yǎng)成習慣凡是跑圖像處理腳本clear; close all; clc三件套放開頭能省掉大量靈異現(xiàn)象的排查時間。檢查環(huán)節(jié)看什么合格標準灰度圖/直方圖車牌與背景對比度直方圖中段有明顯分峰邊緣圖字符輪廓完整性字符筆畫連續(xù)無大面積斷線腐蝕/閉運算后前景塊分布前景集中在車牌附近移除小對象后連通域數(shù)量只剩一到兩個大連通域投影曲線峰值位置峰值對應(yīng)車牌中心二值化后字符清晰度無斷裂、無大面積粘連切割字符7個字符寬度寬度基本均勻識別結(jié)果首字省份漢字第一位為漢字、第二位為字母排查時從上往下逐行對照卡在哪一步就只調(diào)那一步的參數(shù)形成定式之后調(diào)試效率會高很多。6. 二次開發(fā)思路從模板庫到批量驗證的升級路徑拿到源碼先別急著跑通就完事我建議按下面三個方向做改造每個都對應(yīng)一個實際應(yīng)用場景。第一個改造點模板庫擴充與字符標準化。把字符模板文件夾從每個字符 1 張擴到 3 張分別對應(yīng)粗筆畫、細筆畫、標準宋體三種字形。同時把匹配前的 imresize 統(tǒng)一改為雙線性插值并記錄每個測試字符與最佳模板的差異點數(shù)差異點數(shù)超過某一閾值時輸出“未識別”而不是強行給一個錯誤結(jié)果。這樣系統(tǒng)就有了拒識能力識別率統(tǒng)計也會更真實。第二個改造點增加傾斜校正。水平垂直投影定位對傾斜車牌基本失效??梢栽诙ㄎ磺皩?I5 做一輪 Radon 變換或最小外接矩形檢測估算車牌長邊與水平方向的夾角再把圖像用 imrotate 旋轉(zhuǎn)回去。旋轉(zhuǎn)后注意用 imcrop 去掉黑邊重新做投影定位。傾斜校正要在預處理之后、投影定位之前插入改動很小但能大幅提升對真實場景的適應(yīng)能力。第三個改造點批量測試與參數(shù)統(tǒng)計。寫一個循環(huán)遍歷測試圖像文件夾把每張圖的識別結(jié)果、每步中間變量、定位框坐標、字符差異點數(shù)組全部存到結(jié)構(gòu)體里最后統(tǒng)一統(tǒng)計識別率和各字符的混淆矩陣。有了混淆矩陣就能精確定位是哪個字符容易錯再針對它補模板。這一步是擺脫“調(diào)參靠玄學”的關(guān)鍵——你不再憑感覺改閾值而是看數(shù)據(jù)決定。驗證方法也很直接準備 10 張以上不同光照、不同角度、不同車牌類型的測試圖跑一遍批量測試記錄每次在哪一步偏離預期。如果定位失敗回看預處理圖如果分割失敗回看二值化參數(shù)如果識別失敗查模板匹配差異點分布。按這樣分層排查20 分鐘內(nèi)能定位到問題環(huán)節(jié)。最后聊個習慣問題。那次課程設(shè)計答辯前我用一張傾斜角度很大的測試圖把整個流程跑崩了當時第一反應(yīng)是去改閾值來回換了七八組參數(shù)都沒救回來。后來才意識到問題出在定位環(huán)節(jié)對傾斜完全無解不是閾值的事。從那以后我每次拿到一套圖像處理代碼都會先問一句這套算法的前提假設(shè)是什么然后專門構(gòu)造違反這個假設(shè)的用例去測它。這套車牌識別的前提假設(shè)就是“車牌基本水平、光照均勻、字符清晰”凡是不滿足這三條的照片它翻車是正常的不翻車才不正常。認清這個邊界你對系統(tǒng)的掌控力會瞬間上一個臺階。希望幫到你。本文還有配套的精品資源點擊獲取