资讯动态

MATLAB车牌识别课设全流程:图像预处理、定位分割与识别

发布时间:2026/10/24 20:37:47 来源:尧图企业网站定制
简介一份基于Matlab的车牌识别课程设计报告附源代码面向高校信息科学与工程专业学生用于完成车牌识别课程设计或毕业设计也适合对图像处理与模式识别感兴趣的入门者。资源包仅含1个docx文档大小1.37MB报告将设计说明与核心Matlab程序相结合便于阅读、修改和运行调试已有116人学习。报告内容覆盖课程设计全流程先说明设计目的、系统组成与进度安排明确车辆检测、图像采集、牌照识别三部分的功能关系随后重点讲解车牌定位、字符分割、字符识别等关键算法包括大范围搜索确定候选区域、垂直投影法切割字符、模板匹配与BP神经网络识别等方法。同时给出车牌图像灰度化、背景差分、二值化、边缘提取等Matlab实现代码并配有设计结果展示、问题分析与总结体会。通过这份文档读者既能获取可直接复现的源码和调试思路又能学习如何撰写结构完整的课程设计报告对完成类似课题或参加竞赛也有参考价值。1. 车牌识别课设怎么做先用MATLAB经典图像处理链路跑通一版再说很多人一提到车牌识别就想到深度学习、YOLO、卷积神经网络但在课程设计和本科毕设的场景下最稳的路线反而是MATLAB经典图像处理管线灰度化、背景估计、增强、二值化、边缘检测、形态学开闭运算、候选区域筛选、投影分割、模板匹配。这套方案每一步都能用一幅中间结果图讲清楚答辩时老师问「这一步为什么这么做」你直接指着图说比端到端的黑匣子模型好讲得多。本文拆解的就是一份完整的Matlab车牌识别课程设计报告从图像读取到车牌定位、字符分割、字符识别全流程跑通并给出容易翻车的位置和验收方法。适合正在做车牌识别课设/毕设的学生也适合要快速交付一版可演示识别系统的开发者参考。2. 总体设计车牌识别的完整链路与图像预处理2.1 系统组成与设计原理一个完整的牌照识别系统硬件侧通常包含触发设备、摄像设备、照明设备、图像采集设备和识别处理机软件侧核心是三条算法链路车牌定位算法、车牌字符分割算法、光学字符识别算法。整体工作流程是车辆检测部分检测到车辆到达触发图像采集单元抓取当前视频帧牌照识别单元对图像做处理先定位出牌照位置再把牌照中的字符分割出来逐个识别后组成牌照号码输出。这里有一个容易被忽略的设计点识别率的下限不是由识别算法决定的而是由前面的图像质量决定的。车牌本身可能生锈、污损、油漆剥落、字体褪色、被遮挡、倾斜、高亮反光拍摄时又受环境亮度、车速影响。所以课程设计里通常的做法是把预处理链路做厚把定位和分割做稳识别算法哪怕是朴素的模板匹配也能跑出不错的效果。反之如果预处理偷工减料后面用什么高级分类器都救不回来。整个软件流程可以概括为读图 → 灰度化 → 开操作估计背景 → 背景相减增强 → 自适应阈值二值化 → Canny边缘检测 → 形态学开闭运算 → 连通域标记 → 宽高比筛选 → 水平投影峰谷分析 → 水平校正 → 去边框 → 垂直投影分割字符 → 归一化 → 样本匹配识别。下面按这个顺序逐步实现。2.2 图像读取、灰度化与背景估计第一步是读取待处理的彩色图像并做灰度化。代码很简单但两个细节值得注意一是imread直接读入的如果是彩色图后续存储开销和处理耗时都会翻倍二是灰度化之后像素动态范围会发生变化这直接决定后面阈值取值的形态。clear; close all; % Step1 读取彩色图像并显示原始图像 Scolor imread(3.jpg); figure, imshow(Scolor), title(原始图像); % Step2 彩色图像转灰度加快后续处理速度 Sgray rgb2gray(Scolor); figure, imshow(Sgray), title(原始黑白图像); % Step3 开操作估计图像背景 s strel(disk, 13); % 圆盘结构元素半径13 Bgray imopen(Sgray, s); figure, imshow(Bgray), title(背景图像);灰度化的意义在于去掉颜色维度只保留亮度梯度信息车牌区域和背景的区分主要靠灰度跳变不靠颜色本身。第三步用strel(disk,13)生成圆盘形结构元素做开操作效果是得到一张「没有字符、只有光照背景」的估计图。半径13这个参数在640×480左右的图像上表现稳定如果图像更大或更小需要等比调整这个在后面避坑部分会专门说。2.3 背景相减增强、自适应阈值二值化与Canny边缘检测拿到背景估计图之后用原灰度图减去背景相当于做了一次光照不均匀校正——背景中平缓的亮度变化被抹掉车牌的字符和边框这些高频细节被保留下来。之后再取增强图的动态范围按「最大值回退三分之一」的方式求阈值做二值化把灰度图变成黑白图。% Step4 灰度图与背景图相减增强前景目标 Egray imsubtract(Sgray, Bgray); figure, imshow(Egray), title(增强黑白图像); % Step5 根据最大最小值计算阈值并二值化 fmax1 double(max(max(Egray))); % 增强图最大值 fmin1 double(min(min(Egray))); % 增强图最小值 level (fmax1 - (fmax1 - fmin1) / 3) / 255; bw22 im2bw(Egray, level); bw2 double(bw22); figure, imshow(bw2), title(图像二值化); % Step6 用Canny算子提取边缘 grd edge(bw2, canny); figure, imshow(grd), title(图像边缘提取);阈值公式fmax1 - (fmax1 - fmin1)/3的意思是从最大灰度值向下退三分之一动态范围作为分割点。这样取阈值偏保守能保留较暗的字符笔画避免把车牌字符在二值化阶段就切碎。乘1/255是因为im2bw期望输入是 [0,1] 范围的 double 类型。二值化之后直接做Canny边缘检测把字符和边框的轮廓线提取出来。Canny对弱边缘保留好但也会产生大量碎边缘点所以下一步必须用形态学开闭运算做清理否则后面区域标记会得到几十个碎片区域。3. 车牌定位形态学滤波、候选区筛选与倾斜矫正3.1 开闭运算用矩形结构元素把车牌「焊」成连通域Canny边缘提取之后的图像是细碎线条车牌字符的边缘虽然已经显现但字符内部和字符之间并不连通直接做连通域标记会把同一个车牌拆成几十个小块。这里的关键操作用矩形结构元素先闭后开闭运算把断裂的轮廓线连接起来开运算削掉细小的孤立噪声。% 闭运算连接断裂轮廓消除小孔洞 bg1 imclose(grd, strel(rectangle, [5, 19])); figure, imshow(bg1), title(图像闭运算[5,19]); % 开运算消除细小物体平滑边界 bg3 imopen(bg1, strel(rectangle, [5, 19])); figure, imshow(bg3), title(图像开运算[5,19]); % 第二次开运算用竖直长条去掉细长竖线噪声 bg2 imopen(bg3, strel(rectangle, [19, 1])); figure, imshow(bg2), title(图像开运算[19,1]);为什么第一次闭运算和第一次开运算都用[5,19]的横向矩形因为车牌字符的笔画宽度远小于字符高度横向长条结构元素能把同一行内的字符边缘焊接成连通带同时不会把上下两行字连起来。第二次用[19,1]的竖向矩形作用是把车身散热格栅、车窗边缘这类竖长条噪声削掉。先闭后开的顺序不能反——先开会把细碎的边缘点先消掉闭运算就失去连接对象了。3.2 区域标记与宽高比筛选形态学操作做完图像里剩下的连通区域数量已经大幅减少但仍可能包含车灯、保险杠装饰条、文字广告等干扰区域。这时用bwlabel标记每个连通域再用imfeature计算区域面积和最小包含矩形最后根据车牌的先验知识做筛选。% 标记二进制图像中的连通区域 [L, num] bwlabel(bg2, 8); Feastats imfeature(L, basic); % 新版本MATLAB建议改用regionprops Area [Feastats.Area]; % 各区域面积 BoundingBox [Feastats.BoundingBox]; % [x y width height] % 根据先验知识筛选候选车牌区域 % 普通蓝底白字车牌宽高比约3:1考虑倾斜和透视后放宽到2.5~5.5 for i 1:num w BoundingBox(i, 3); h BoundingBox(i, 4); ratio w / h; if ratio 2.5 ratio 5.5 Area(i) 800 % 记录该区域截取灰度子图和二值子图备用 end end宽高比范围不能卡死在3:1因为车牌在画面里可能有小角度倾斜拍摄视角也不是完全正对取2.5到5.5更稳。面积下限800的作用是过滤掉远距离的小块噪声。这里我用的是示例循环体实际课设代码里通常会直接选出宽高比最接近标准车牌比例的那一个区域并记录其行列范围为后面的投影分析做准备。筛选完再做一次label2rgb假彩色标记能很直观地在答辩PPT里展示每个候选区域的样子。3.3 水平投影峰谷分析与倾斜角拟合车牌被定位出来之后还需要解决两个问题一是车牌在图像里可能带几度倾斜导致后续垂直投影的峰谷不明显二是要精确去掉上下边框才能得到干净的字符区域。这里先重新计算二值子图的水平投影分析峰谷位置再用线性拟合求倾斜角。% 计算水平投影每一行像素值的总和 histrow sum(sbw1); figure, bar(histrow); title(水平投影含边框); % 对水平投影做峰谷分析得到上边框峰、字符峰、下边框峰的位置 % 字符区的峰宽最大上下边框的峰较窄 % 取字符边缘点做线性拟合计算倾斜角度 fresult fit(xdata, ydata, poly1); % 一阶拟合 Y p1*x p2 p1 fresult.p1; angle atan(p1) * 180 / pi; % 斜率转角度 % 旋转车牌图像做水平校正 subcol imrotate(subcol1, angle, bilinear, crop); sbw imrotate(sbw1, angle, bilinear, crop); figure, imshow(sbw); title([车牌旋转角, num2str(angle), 度], Color, r);水平投影的物理意义很直观把二值图像每一行像素求和车牌区域的字符行会产生高峰上边框和下边框产生较窄的峰。峰谷分析就是找到这些峰的起点、终点、峰宽从而确定字符行所在的上下边界。倾斜矫正的核心思路是取车牌上边缘或下边缘灰度值为1的点集做线性拟合拟合直线的斜率就是倾斜角的正切值。旋转时选bilinear双线性插值是为了保留灰度过渡信息crop参数保证旋转后图像尺寸不变。这一步做完车牌在图像里基本是水平的字符分割才能稳定。4. 字符分割与识别垂直投影定位字符与样本库匹配4.1 去掉上下边框精准获取字符高度倾斜矫正之后车牌图像仍然包含上下边框。字符分割的第一步是把边框去掉拿到只含字符像素的区域。做法是对旋转后的二值图重新做水平投影找到峰宽最大的那一段——那一段就是字符主体。% 重新计算水平投影 histrow sum(sbw); % 从投影结果中找最大峰宽对应字符区域 maxhight max(markrow2); % 字符峰的最大宽度 findc find(markrow2 maxhight); % 找到该峰的索引 rowtop markrow(findc); % 字符区域上边界 rowbot markrow(findc 1) - markrow1(findc 1); % 下边界 % 截取只含字符的横向区域 sbw2 sbw(rowtop:rowbot, :); maxhight rowbot - rowtop 1; % 实际字符高度像素这里有一个容易踩的细节字符高度不能用固定值因为摄像头安装距离不同车牌在画面中的像素高度是变量。取投影峰宽最大的区域作为字符区是自适应做法即使图像缩放也能对得上。去掉上下边框后再用垂直投影做列方向的分析定位每个字符的左右边界。4.2 垂直投影峰谷分析与字符中心计算字符区域的垂直投影是按列求和每一列的像素和形成波形字符笔画经过的列投影值高字符间隙和字符内谷底的列投影值低。通过峰谷分析可以找到每个字符的上升点和下降点进而算出每个字符的宽度和中心位置。% 计算垂直投影 histcol sum(sbw2); figure, bar(histcol); title(垂直投影去水平边框后); % 对垂直投影做峰谷分析 % markcol 记录每个字符的上升点字符左边界 % markcol1 记录每个字符的下降点字符右边界 for k 1:n1 markcol3(k) markcol(k 1) - markcol1(k 1); % 字符下降点修正 markcol4(k) markcol3(k) - markcol(k); % 字符宽度 markcol5(k) markcol3(k) - uint16(markcol4(k) / 2); % 字符中心位置 end % 计算相邻字符中心距离最大值对应第二、三字符之间的分隔点 markcol6 diff(markcol5); maxs max(markcol6); % 最大间距 findmax find(markcol6 maxs); % 定位分隔符位置为什么字符中心距离的最大值出现在第二和第三个字符之间因为国内车牌第二个字符和第三个字符之间有一个分隔圆点这个间隔显著大于普通字符间距。找到这个位置后从findmax-1到findmax5正好覆盖7个字符分割起点就固定下来了。计算字符宽度时用uint16取整是防止后面索引计算出现小数这个细节在答辩时提一句老师会觉得你考虑得比较细。4.3 分割字符、归一化22×14并建立样本库定位到每个字符的中心位置后以中心为基准、以最大字符宽度为半宽向左右扩展就能把单个字符完整切出来。切出来的字符大小不一直接送进识别模块之前必须统一尺寸。这里统一缩放为22行14列的标准子图——22对应字符高度14对应字符宽度比例接近真实字符能最大限度保留笔画形状。l 1; [m2, n2] size(subcol); % 子图实际尺寸 for k findmax - 1 : findmax 5 cleft markcol5(k) - maxwidth / 2; % 左边界 cright markcol5(k) maxwidth / 2 - 2; % 右边界预留2像素 % 边界越界保护 if cleft 1 cleft 1; cright maxwidth; end if cright n2 cright n2; cleft n2 - maxwidth; end % 截取字符灰度图和二值图 SegGray sbw(rowtop:rowbot, cleft:cright); SegBw1 sbw(rowtop:rowbot, cleft:cright); % 统一缩放为22行14列标准子图 SegBw2 imresize(SegBw1, [22 14]); % 保存到样本库用于后续识别匹配 fname strcat(F:\MATLAB\work\sam\image, int2str(k), .jpg); imwrite(SegBw2, fname, jpg); l l 1; end识别阶段有两种主流做法。基于模板匹配的做法是把分割好的字符二值图与样本库中的每一张模板图做逐像素相减误差最小的模板对应的字符就是识别结果基于BP神经网络的做法是用汉字、字母、字母数字、数字四类样本分别训练四个子网络识别时把字符特征送入对应网络分类。这份课程设计实际走的是模板匹配路线代码里保留了神经网络训练的流程说明作为扩展方案。要注意的是样本库质量直接决定识别率建立样本库时每个字符至少要收集多张不同粗细、不同倾斜程度的样本只放一张模板的话稍微有点形变的字符就识别不了。5. 避坑指南误识别、阈值与算子兼容性的常见问题5.1 现象G被识别成B、K被识别成A、0被识别成8课程设计报告里有一组失败样例一张车牌把G误识别成BK误识别成A0误识别成8。这类错误几乎都出在字符分割阶段——字符被切得过宽或过窄归一化到22×14时笔画发生了形变。比如G的右下角开口如果被边框残留填满长得就像B0的中间如果有细小噪声点二值化后中间出现横线就会被匹配成8。原因通常是垂直投影的谷底检测阈值设得太浅或者去边框时残留了上下边框的像素导致投影波形粘连。解决的办法是先加大形态学开运算的力度把边框残留彻底清掉再检查垂直投影的谷底判定条件多个连续低投影值的列只能算一个字符间隙不能拆成两个。另外识别阶段对误差最小的结果可以加一个置信度判断如果最小误差和第二小误差非常接近说明这个字符识别不可靠宁可标记为待确认也不要硬输出一个错误结果。5.2 现象强光下二值化结果全黑或全白预处理链路里的阈值公式是fmax1 - (fmax1 - fmin1)/3这个公式在正常光线下表现不错但遇到车牌被强光直射、大面积反光时增强图的动态范围会被极端值拉满按三分之一回退算出的阈值可能把整个车牌区域全部判成背景二值化之后车牌字符消失。原因是阈值只依赖全局最大最小值对局部光照变化不敏感。解决思路有两个一是分块自适应阈值把图像切成若干小块分别计算阈值二是先对增强图做直方图均衡化再二值化把灰度分布拉开。课设时间有限的话至少要做到把阈值计算改成中位数加标准差的方式中位数对极端值不敏感比最大最小值稳定得多。5.3 现象候选区域筛选把真车牌漏掉了宽高比范围2.5到5.5、面积下限800这套参数不是普适的。如果测试图像里车牌离摄像头远像素面积只有四五百面积下限直接把它滤掉了如果拍摄角度侧一点车牌在图像里是斜平行四边形宽高比会明显偏离正常范围。原因是筛选参数和成像条件绑得太死。我一般会做一层多尺度兜底先用宽泛的宽高比范围比如1.5到7.0粗筛一轮再用形态学的矩形度、字符密度做第二轮打分而不是单一条件硬过滤。课程设计里可以在答辩时说清楚这个思路然后现场演示放宽参数后候选区数量从1个变成5个再说明为什么最终选定的是车牌区域这比直接展示一张完美识别图更可信。5.4 现象新版MATLAB运行报错imfeature不存在原报告代码里用了imfeature(L,basic)这个函数在老版本MATLAB的图像处理工具箱里能用但新版本已经被regionprops取代。直接复制代码跑新版MATLAB会在这一步报错很多同学第一反应是代码有问题其实是API变更。解决方法是做一行替换Feastats regionprops(L, Area, BoundingBox)然后访问方式从[Feastats.Area]改成[Feastats.Area]依然成立BoundingBox的字段结构也兼容改动成本很低。另外strel的组合写法在新版里有更简洁的offsetstrel但不影响运行不必强改。遇到这种兼容性问题不要慌优先查对应函数的官方文档通常只是函数换名。5.5 现象倾斜矫正拟合出的角度明显偏大或偏小用边缘点线性拟合求倾斜角时如果参与拟合的点集里混入了字符竖线或者边框拐角拟合直线的斜率会被带偏。比如车牌左边第一个字符的竖线很长这些点的x坐标集中在一小段范围却贡献了大量高y值拟合结果会比真实倾斜角大好几度。原因是拟合前没有对点集做提纯。通常的做法是只取车牌上边缘或下边缘附近两三个像素宽度内的点参与拟合远离边缘的字符点剔除后再做poly1拟合。另一个细节是拟合之后要检查旋转方向atan(p1)得到的是弧度制的正切角转成角度后如果是正值说明逆时针倾斜旋转时需要取负号方向搞反会让车牌更歪这一步出错时投影峰会变得比校正前更平。6. 验收与答辩用测试表和识别率数据证明方案可靠课程设计答辩和项目验收核心就一句话用数据说话而不是用一两张成功的图说话。我建议在验收前做一张测试记录表准备至少10张不同类型的测试图覆盖正常光照、强反光、倾斜车牌、远距离小尺寸车牌、有边框铆钉干扰的车牌每一张记录定位是否成功、分割是否成功、识别结果是否正确最后算出三个数字定位成功率、字符分割成功率、整牌识别率。演示顺序也很关键。先跑一张标准测试图展示完整链路和成功结果再跑一张失败案例主动说出失败原因对应第5章里的字符混淆问题最后用统计表说明整体识别率。答辩老师最反感的是「我的程序只能识别这一张图」所以一定要准备一张没在开发阶段反复调试过的真实验证图像当场跑一次。表格式的测试记录可以直接留在报告附录里评审老师翻到会认为你做测试做得很扎实。测试图编号场景描述定位结果分割结果识别结果备注01正常光照蓝底白字成功成功正确完整链路02强光反光失败——阈值需自适应03倾斜约3度成功成功正确拟合角2.8度04远距离小尺寸失败——面积筛选漏检还有一个答辩技巧把中间结果图串成一条流水线展示。每一张预处理图下面标注「这一步解决了什么问题」比如灰度化解决计算量、背景相减解决光照不均、闭运算解决边缘断裂、宽高比筛选解决候选区干扰、投影峰谷解决字符定位、归一化解决尺寸不一致。这会让老师觉得你不是在跑现成代码而是真的理解整条链路。这份方案对应的资源里包含完整的课程设计报告和可直接运行的MATLAB源代码报告里的流程图、结果分析、参考文献列表都齐全拿去做课设提交或者在此基础上扩展识别算法都很方便。做这个车牌识别课设我最大的教训是不要一开始就追求「所有图都能识别对」而是先把一条链路完整跑通再拿失败样本去反推哪个环节顶不住。从那以后我每次做图像类的课程设计验收都强制自己先跑失败案例再跑成功案例识别率统计表随身带着答辩基本没慌过。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑