资讯详情

资讯详情

MATLAB车牌识别:从图像预处理到字符识别的完整技术链路

简介这是一份基于Matlab的车牌识别课程设计报告配有完整源代码面向信息科学与工程专业本科生及需要完成图像处理类课程设计的读者可直接用作报告撰写的结构参考与算法实现的对照材料。报告从车辆检测、图像采集到牌照识别三大模块展开系统阐述了车牌识别系统的设计目的、车辆检测与图像采集流程以及车牌定位、基于垂直投影的字符分割和模板匹配、神经网络两类字符识别算法整个设计融合图像处理、模式识别与机器学习知识除理论原理外还给出图像灰度化、背景差分增强、二值化等关键步骤的Matlab代码并包含设计结果分析、进度安排、设计体会和参考文献。针对实际场景中生锈污损、光照不均、车牌倾斜等干扰因素报告也提出了相应的优化思路。资源共1个docx文件压缩包约1.37MB已有116人学习下载适合课程报告撰写、算法复现与答辩准备。1. 车牌识别最难的不是识别字符而是先证明“这块区域是车牌”一个成熟的车牌识别系统最让开发者翻车的往往不是最后“读字母”那一步而是前面那句“它到底在哪”。人眼能瞬间挑出蓝底白字靠的是颜色、比例、纹理的先验MATLAB 程序没有它要面对天空、树荫、车灯、保险杠每一处都在抢注意力。这套基于灰度跳变、投影分析和模板匹配的实现把“找到车牌”拆成预处理、边缘检测、形态学滤波、宽高比筛选、投影峰谷分析五层每层都在做同一件事把车牌从背景里剥离开。搞懂这条链路比背一段 matlab 代码更有价值——换张图、换种光照坑全藏在机制里。2. 图像预处理链灰度化、背景差分与阈值二值化为什么能稳定分离字符自然场景下车牌照片的灰度不是一个固定值阳光直射时整个画面偏亮阴天偏暗树影还会在车身上拉出几条暗带。如果拿着一个固定阈值去切字符和背景几乎必然翻车。所以这套设计的预处理链刻意绕开了“定死一个数”的思路核心是三件事先降维减少计算量再用背景差分抹平光照最后才用阈值二值化把字符从灰度中捞出来。2.1 灰度化砍掉 2/3 的通道识别速度先提三倍rgb2gray 不是简单地对 RGB 三分量取平均而是加权求和权重 0.299R 0.587G 0.114B。这个权重来自人眼对亮度敏感度的实测曲线人对绿色最敏感蓝色最不敏感。对车牌识别来说颜色不是必要信息——蓝底白字在灰度图里表现为“暗底亮字”这个对比度关系在灰度空间里保留得非常好丢掉的两个颜色通道换来的是存储开销降到三分之一、后续所有矩阵运算速度大幅提升。Scolor imread(3.jpg); % 读入彩色原图 Sgray rgb2gray(Scolor); % 灰度化通道数从3降到1 s strel(disk, 13); % 圆形结构元素半径13 Bgray imopen(Sgray, s); % 开操作先腐蚀后膨胀估计背景亮度 Egray imsubtract(Sgray, Bgray); % 原图减背景抹平光照不均造成的亮度差 fmax1 double(max(max(Egray))); fmin1 double(min(min(Egray))); level (fmax1-(fmax1-fmin1)/3)/255; % 阈值偏向高灰度一侧 bw22 im2bw(Egray, level); % 全局阈值二值化 bw2 double(bw22);注意这里的 imopen 用的是 disk 半径 13 的圆形结构元素。它的作用是估算一个“缓慢变化的背景”圆形结构元素不会偏爱某个方向所以对车身的弧面反光、路面的渐变阴影估计得更均匀。半径 13 是个经验值太小会把字符当背景腐蚀掉太大则跟不上光照变化背景估计变成一块死板的平均值。这种“先估背景、再做减法”的操作本质上是一种白平衡补偿。2.2 背景差分为什么绕过固定阈值这条路很多人拿过图像第一反应是直接看直方图找双峰。但车牌的直方图在自然场景下往往没有干净的双峰背景里有绿化带、柏油路、车身贴纸灰度分布是连续的一大片。直接选谷底阈值选的其实是“整幅图的统计中心”而不是“字符和车牌的边界”。背景差分的好处是先把低频的背景去掉剩下的 Egray 里主要就是字符、车牌边框和少数高频噪声这时再取阈值信号占比高得多。这个思路不仅用于车牌识别工业上定位印刷缺陷、检测电路板焊点也常常用同样的“原图减背景”手法。理解它是理解后面一整套二值化参数的前提。2.3 阈值公式的玄学1/3 从哪来level 的取法是 fmax1 - (fmax1 - fmin1)/3再除以 255 归一化。翻译成人话就是阈值挂在灰度动态范围的上三分之一处。为什么不是中点和下三分之一因为蓝底白字车牌在灰度化之后车牌底色的灰度值偏低字符笔画灰度值偏高而且字符面积远小于底色面积所以像素灰度分布的重心落在低灰度一侧。把阈值往上抬宁可牺牲一点字符的粗度也要把底色彻底压成 0。这里有个代价如果画面里有强反光车灯或者白色车身fmax1 被这些无关高光点拉高阈值跟着上升字符笔画会被削细甚至断裂。课程设计的代码里没有做高光抑制这是它的朴素之处也是后续 Canny 边缘检测能容忍一部分断裂的原因——边缘检测要的是轮廓走向不是连通的笔画。2.4 Canny 边缘检测为什么一阶导数不如二阶零交叉可靠edge(bw2, canny) 这一步的输入已经是二值图再做边缘提取听起来像多此一举其实不然。二值图里的字符是实心块直接投影会得到一片模糊的宽度Canny 先把字符的轮廓抽出来后面的形态学滤波和连通域分析才有“边界”可用。Canny 算子内部做了四件事高斯平滑抑制噪声、计算梯度幅值与方向、非极大值抑制让边缘变细、双阈值滞后连接把断裂的强边缘补起来。相比 Sobel 那种“梯度超过阈值就算边缘”的做法Canny 对噪声更稳边缘也更封闭。车牌字符的笔画边缘是闭合曲线Canny 抽出来的轮廓同样接近闭合这为后面用闭运算把字符边缘“缝”成整块打下了基础。3. 车牌定位形态学滤波与宽高比先验怎么从复杂背景里圈出那块矩形边缘检测之后图像里到处都是轮廓车灯是圆弧、保险杠是长直线、树叶是碎块。这时的目标是保留“像车牌边框和字符块”的结构扔掉其他形状。形态学滤波在这里不是锦上添花而是定位逻辑的主干——用固定形状的“探针”去扫图像探针的形状就是你对车牌的预设。3.1 矩形结构元件的尺寸设计闭运算 [5,19]、开运算 [19,1] 各自的职责bg1 imclose(grd, strel(rectangle,[5,19])); % 横向闭运算把左右相邻边缘缝合成块 bg3 imopen(bg1, strel(rectangle,[5,19])); % 横向开运算滤掉细碎竖边 bg2 imopen(bg3, strel(rectangle,[19,1])); % 纵向开运算滤掉细碎横边闭运算是先膨胀后腐蚀。结构元素是 5 行 19 列的矩形19 这个数远大于 5意味着它主要在水平方向做连接。车牌上的字符是横向排开的相邻字符边缘之间的空隙不大膨胀一次就能把这些边缘“缝”成一块连续区域而车灯、文字贴纸这类零散边缘纵向长度够但横向往往凑不满 19 像素连接不起来。随后的两次开运算分工不同[5,19] 的开运算滤掉宽度小于 19 像素的细碎竖边相当于对横向结构做一次“宽度审查”[19,1] 是竖起来的矩形专门清掉细碎的横向短边。三行代码把车牌的矩形外框从杂乱边缘中保留下来代价是参数会敏感地依赖输入图像的分辨率——如果换一台摄像机19 这个数很可能要重调。3.2 连通域标记bwlabel 之后世界变成一张“属性表”[L, num] bwlabel(bg2, 8); % 8邻域连通标记num为连通域个数 Feastats imfeature(L, basic); % 提取面积、包围盒等基本特征 Area [Feastats.Area]; BoundingBox [Feastats.BoundingBox]; % 每行[x y width height]bwlabel 给每个独立的白色连通块发一个编号返回的 L 是编号矩阵num 告诉你图里一共有多少块。imfeature 随后针对每个编号统计面积和最小包围矩形。到这一步“图”已经被抽象成一张候选表后面所有判断都不再依赖像素坐标而是依赖这张表里的数字。顺带一提新版 MATLAB 里 imfeature 已经被 regionprops(basic) 取代字段结构完全一样课程报告里用的是老接口。理解算法的重点是字段本身——面积、包围盒的宽和高这三个数字足以支撑车牌筛选。3.3 宽高比先验一份“常识”如何变成过滤条件有了候选表筛选逻辑就直白了先按面积滤掉太小的噪点块再算每个包围盒的 width/height跟真实车牌的长宽比比较。我国蓝底白字车牌的宽高比大约在 3:1 到 4:1代码里挑“更接近实际车牌宽高比”的那一块本质上就是在这个区间里找最小值。这里真正值得琢磨的是“先粗筛再精筛”的次序。如果先比宽高比很多狭长的栏杆、排水沟边缘会混进来先按面积淘汰一批小噪点再比宽高比候选数通常会降到个位数。课程设计的流程图里画了“计算车牌长宽比、获取车牌二值子图”的完整路径实际运行时如果剩下多个候选还要再用蓝色像素占比做最终裁决——这个彩色验证在报告总结部分被明确提到是定位模块的兜底手段。4. 投影分析与倾斜校正峰谷分析的避坑排查车牌定位到了不等于能开始分割字符。真实照片里车牌经常是歪的车身有俯仰角、拍摄角度不正、路面有坡度几度的倾斜就会让字符行错位。投影分析是分割前的最后一道关也是踩坑最密集的地方。这一章按三个高频问题展开每个都按现象、原因、解决来拆。4.1 水平投影的峰谷含义从波形里读出边框、字符与间隙histrow sum(sbw1); % 每行白色像素数水平投影就是统计二值子图每一行有多少个白点。一个端正的车牌水平投影的波形从上到下依次是上边框的高峰、字符行的几个峰、字符间隙的小谷、下边框的高峰。峰谷分析要做的事情是把波形里的上升点、下降点、峰中心、谷宽、峰间距离全部提出来作为后续裁剪依据。这个波形是理解整个系统的钥匙。边框残留会让峰变得过宽字符沾连会让两个峰合并倾斜会让峰的高度被“摊平”。所以峰谷分析的代码要先求平均和最小值、再设阈值判断目的就是把波形的局部特征数值化而不是人眼去看。4.2 线性拟合旋转角poly1 拟合与 atan 换算的细节fresult fit(xdata, ydata, poly1); % 一次多项式拟合 y p1*x p2 p1 fresult.p1; angle atan(p1) * 180 / pi; % 弧度转角度 subcol imrotate(subcol1, angle, bilinear, crop);倾斜校正的思路是取车牌上边或下边图像值为 1 的像素点作为样本拟合一条直线直线的斜率 p1 就是 tan(θ)θ 就是相对水平轴的倾角。atan 的返回值范围是 -90° 到 90°换算成角度后直接传给 imrotate。插值方式选 bilinear 是为了旋转后边缘不发毛crop 选项保证输出图跟原图尺寸一致后续窗口定位不会越界。这段代码能不能跑对取决于喂给 fit 的点是不是“边缘像素”。如果边缘检测环节把车牌边框和背景噪声连在一起拟合直线会被带偏旋转角度自然不准。4.3 避坑一字符峰谷被倾斜“抹平”现象水平投影波形没有明显的峰谷交替看起来像一段平缓的坡找不到字符的上升点和下降点。原因车牌倾斜几度后同一行像素里既扫过字符、又扫过背景白点总数被平均化峰高被抹平。解决先做旋转校正再重新计算水平投影。这就是课程设计把旋转放在投影分析之后的工程原因——不是随意排的顺序。旋转后用 maxhight 重新定位字符高度峰谷才恢复清晰。4.4 避坑二边框残留产生伪峰现象投影峰谷数量对不上字符数第一个峰特别宽几乎覆盖整个车牌宽度。原因闭运算把上下边框和字符连成了同一个连通域投影时边框峰和字符峰合并波形里出现一个“假峰”。解决先用峰宽度判断哪些峰属于边框再按 rowtop 和 rowbot 截取字符行区间代码里的 sbw2 sbw(rowtop:rowbot, :) 就是在做这件事。去掉边框后重新投影接下来统计字符宽度才有意义。4.5 避坑三角度符号反了导致越转越歪现象旋转后字符反而更歪整块图像明显偏出原位置。原因拟合取点选的是上边框还是下边框直接决定 p1 的符号如果车牌是顺时针倾斜但取了下边框拟合正负号就会跟视觉方向相反。解决常见的实现思路是同时拟合上下两条边框取两个角度的平均值或者先用 minAreaRect 这类最小外接矩形方法估算整体倾角再决定旋转方向。课程设计代码里只拟合单个边所以它对边缘提取质量特别敏感——这是我反复强调 Canny 是全局瓶颈的原因。5. 字符分割与识别垂直投影找中心、22x14 标准化与模板匹配的误差逻辑字符分割最怕的不是算法复杂而是“位置切偏”。车牌字符有 7 位前两位是字母加省份汉字后面是字母和数字混排第二字符和第三字符之间还有圆点间隔。如果按固定间距从头切到尾圆点会把切分窗口带偏。所以这套实现的做法是通过投影找到每个字符的中心再以中心为基准开窗。5.1 垂直投影与字符中心为什么用“中心距离”而不是固定宽度切去掉水平边框后对 sbw2 做垂直投影字符间空隙处投影值接近 0波形局部最小值对应字符间隙。课程设计的代码进一步算出了上升点、下降点、字符宽度再算字符中心位置 markcol5(k) markcol3(k) - uint16(markcol4(k)/2)。这一步的关键不是找一个字符的开始和结束而是把每个字符的几何中心钉住。for k findmax-1:findmax5 cleft markcol5(k) - maxwidth/2; % 以字符中心为中心开窗 cright markcol5(k) maxwidth/2 - 2; if cleft 1, cleft 1; cright maxwidth; end if cright n2, cright n2; cleft n2-maxwidth; end SegBw1 sbw(rowtop:rowbot, cleft:cright); SegBw2 imresize(SegBw1, [22 14]); % 统一成22行14列 end以中心开窗比固定等距切多算了一步收益是切分位置对字符间距变化免疫。代码里的边界保护也值得看cleft 小于 1 时强制把窗口挪到图像起点cright 超出 n2 时反向收缩保证窗口永远落在图像范围内。窗口宽度取 maxwidth 是“最大字符宽度”的估计值数字 1 和小字母笔画窄按最大宽度开窗能完整包住笔画代价是相邻字符间隙可能混进窗口需要靠样本匹配时做二次判断。5.2 imresize 到 22x14把切割结果塞进“标准信封”的代价与收益22 行 14 列是模板库子图的统一尺寸。模板匹配要做逐像素相减两张图尺寸不一致根本无法计算差值和。imresize 把不同宽度的字符归一化到同一画布让误差对比成为可能。这是整个方案能跑通的前提也是最容易被忽略的精度瓶颈直接拉伸会改变笔画粗细数字 1 被拉宽后容易和 7 混淆数字 8 被压缩后笔画可能糊在一起。工程上常见的补救是先做细化再归一化或者按宽高比填充到信封里而不是无脑拉伸课程设计没有走到这一步所以它的识别结果里出现了 G/B、K/A、0/8 的混淆。5.3 模板匹配的误差最小化与 BP 网络的替代思路模板匹配的识别逻辑一句话就能讲完把待识别字符与样本库里每个字符的图像相减误差最小的那个就是结果。这篇报告在字符分割与识别里展示的命令本质上就是在做“逐样本测距离”。它的优点是实现简单、不需要训练缺点是每个字符只认最接近的样本字体变形大一点就翻车。报告中提到的神经网络路线是对模板匹配的替代一种思路是先提取字符特征再用特征训练一个分类器另一种是直接把归一化后的图像丢进网络让隐层自动学特征直到输出层给出字符类别。BP 网络对笔画的轻微变形、断笔、粘连天然有容忍度因为它学的是特征的统计规律而不是某个固定像素模板。课程设计最终采用了模板匹配路线识别结果里 G 误判成 B、K 误判成 A、0 误判成 8正是模板匹配对相似字形无能为力的直观证据——这几个字符在 22x14 的像素空间里灰度分布本来就非常接近。6. 设计取舍蓝底白字假设、灰度跳变与彩色分量定位的适用边界6.1 灰度跳变 vs 彩色像素统计两套定位哲学报告总结里明确提到了两种定位路线基于灰度跳变的定位作为主路径基于蓝色像素点统计的方法作为辅助验证。灰度跳变看的是“图像在这个位置灰度变化剧烈且结构成矩形”它对光照和颜色不敏感黑白摄像头也能用但容易把车身贴纸、广告牌误判成车牌。彩色统计直接统计蓝色像素占比思路更贴近人眼可它对色偏和反光很脆弱——黄昏时分的蓝底可能被偏色成灰蓝。组合起来才是完整方案灰度跳变先生成候选区蓝色统计再验证候选区这比任何单一特征都稳。6.2 模块复用边界换一种车牌底色需要改哪里课程设计只做了蓝底白字的完整链路但报告给出的边界判断很实用黑底白字可以直接套用整套算法白底黑字和黄底黑字需要先反转图像把“亮底暗字”重新变成“暗底亮字”同时调整车牌定位算法。这个结论隐含了系统耦合关系字符识别模块在最末端几乎不受底色影响最可替换定位和预处理要动。所以如果你拿到项目代码想改新能源绿牌或其他样式先改灰度差分和二值化方向不要一上来就动识别网络——那是黑匣子但坑往往在前面。我从这套课程设计里学到的教训是识别误差别急着甩锅给模板库先回头把“从原图到二值子图”的每一层输出都存下来看一遍分割窗口偏半像素和字符粘连造成的误判数量比想象中多得多。从那以后我每次做识别 Demo都强制自己先跑完完整预处理链路可视化存档再谈识别精度。希望帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →