简介一份基于Matlab实现的车牌识别课程设计报告面向信息科学与工程类专业学生可作为图像处理、模式识别课程设计或毕业设计的参考资料。报告围绕车牌定位、字符分割、字符识别三个核心环节系统介绍了车辆检测与图像采集触发机制、牌照区域搜索与候选区分析、垂直投影分割方法以及模板匹配和人工神经网络两类字符识别算法同时给出完整Matlab实现代码涵盖图像灰度化、背景差分、二值化、边缘提取、水平垂直校正等关键步骤。资源包仅含1个docx文档约1.37MB文档内置课程设计封面、进度安排、设计原理、详细步骤、结果展示、总结体会与参考文献结构完整便于对照学习。已有116人浏览学习。读者可参考其中算法流程和源代码快速搭建车牌识别原型也能了解多牌照、假牌照、光照不均等实际工程挑战及优化思路为交通管理、高速公路收费等应用打下基础。1. Matlab 车牌识别课程设计一份能跑通的定位、分割、识别全流程车牌识别这事儿听着像是工业停车场和高速收费口的专属系统离课程设计很远。但真打开这份 Matlab 车牌识别课程设计报告你会发现整个识别链路并没有那么高不可攀它没有引入深度学习完全靠图像处理经典套路——灰度化、边缘提取、形态学滤波、投影分析和模板匹配就把蓝底白字车牌从一张自然背景的 3.jpg 里抠出来切割成单个字符再逐个比对出车牌号码。适合图像处理刚入门、需要做课设或者想补一遍传统 CV 基本功的人。报告里配了完整可运行的 Matlab 源码和详细步骤图照着敲一遍比看十遍教科书都管用。2. 系统设计与模块划分五个环节串起从原始图像到车牌号码2.1 牌照识别系统的完整链路整个系统遵循一个非常经典的视频触发式车牌识别流程车辆检测部分感知到车辆到达后触发图像采集单元抓取当前帧牌照识别单元对该帧做处理定位出牌照区域再把牌照中的字符分割出来识别最后组成牌照号码输出。落到这份报告里车辆检测和图像采集是外部硬件的事软件部分也就是你能拿到的代码集中在牌照识别这一块拆开看是五个环节图像预处理把读入的彩色图像转灰度、做背景估计、差影增强把车牌区域从复杂背景里凸显出来。二值化与边缘提取求最佳阈值把灰度图变成二值图再用 Canny 算子提取边缘。形态学滤波与区域筛选通过闭运算、开运算的组合消除小噪声再用连通域标记和长宽比先验知识定位车牌矩形。倾斜校正与边框去除对水平投影做峰谷分析检测出上下边框位置必要时用线性拟合计算倾斜角度并旋转图像。字符分割与识别用垂直投影找到每个字符的中心位置切割出单个字符统一缩放成 22 行 14 列的标准子图再与样本库比对误差输出车号。2.2 目录结构与关键文件拿到这份资源先别急着点运行把目录结构摸清楚。报告自带完整源码典型组织方式如下plate_recognition/ ├── 车牌识别课程设计报告.docx # 完整设计文档含步骤图和结果分析 ├── code/ │ ├── main.m # 主程序入口按步骤调用各处理函数 │ ├── 3.jpg # 测试原图蓝底白字车牌 │ ├── sam/ # 样本库目录存放缩放后的字符模板 │ │ ├── image1.jpg │ │ ├── image2.jpg │ │ └── ... │ └── util/ # 可选的自定义函数目录主程序 main.m 直白到让人舒服一句一句从上往下执行没有花哨的封装。这种写法不优雅但作为课设非常合理每一行对应报告里的一个设计步骤老师验收时对着文档就能指出代码位置答辩也好讲。2.3 主流程代码骨架clear; close all; % Step1 获取图像读取待处理的彩色图像 Scolor imread(3.jpg); % imread 读取图像文件 figure, imshow(Scolor), title(原始图像); % Step2 灰度化彩色转灰度降低计算量 Sgray rgb2gray(Scolor); figure, imshow(Sgray), title(原始黑白图像); % Step3 背景估计用半径为13的圆形结构元素做开运算提取背景 s strel(disk, 13); Bgray imopen(Sgray, s); % Step4 图像增强原图减去背景突出前景目标 Egray imsubtract(Sgray, Bgray); % Step5 二值化动态阈值转二值图 fmax1 double(max(max(Egray))); fmin1 double(min(min(Egray))); level (fmax1 - (fmax1 - fmin1) / 3) / 255; bw22 im2bw(Egray, level); bw2 double(bw22); % Step6 边缘检测Canny 算子提取强边缘 grd edge(bw2, canny);这段代码就是后面一切操作的基石。注意 Step3 里strel(disk, 13)的 13 是结构元素半径选大了背景被磨平选小了背景里还残留纹理Step5 的阈值公式是经验值意思是取灰度范围上三分之一处作为二值化阈值背景亮、车牌字符暗时效果很好但光照极端时这个固定比例会失效后面避坑章节我会细说。2.4 边缘之后形态学滤波与候选区域分析边缘图直接用来定位是不可靠的车牌周围的噪声、车灯轮廓、路面标线都会产生响应。报告的思路是用形态学开闭运算滤掉杂散边缘再连通域分析找到候选区域。% 先闭运算再两次开运算分别用不同尺寸的矩形结构元素 bg1 imclose(grd, strel(rectangle, [5, 19])); bg3 imopen(bg1, strel(rectangle, [5, 19])); bg2 imopen(bg3, strel(rectangle, [19, 1])); % 标记连通域并计算区域特征 [L, num] bwlabel(bg2, 8); Feastats regionprops(L, basic); Area [Feastats.Area]; BoundingBox [Feastats.BoundingBox]; % 每行 [x y width height]这里[5, 19]的矩形结构元素是照着车牌字符的宽高比例设计的——字符窄高横向跨度大所以闭运算能把离散的字符边缘连成一片[19, 1]的竖向结构元素再把竖向细小噪声抹掉。选这两个参数不是拍脑袋是观察了车牌字符尺寸和笔画宽度之后定出来的改到别的数据集上需要重调。regionprops计算每个连通域的外接矩形和面积后面就用宽高比去匹配真实车牌的先验。到这里整个软件架构就清楚了环境依赖只有 MATLAB 和图像处理工具箱不涉及额外 SDK算法链路全部是经典图像处理没有神经网络权重文件要管理样本库就是 sam 目录下的一组 22x14 的二值字符图靠相减求误差来识别逻辑一眼能看懂。这种设计对学习和答辩都非常友好。3. 核心算法拆解灰度化、边缘检测与投影分析的关键实现3.1 车牌定位从二值图到候选矩形如果说整个识别系统是一个漏斗车牌定位就是最宽的那一层。报告采用的方法是先大范围搜索符合车牌特征的候选区域再逐步筛选。具体到代码里靠的是连通域的外接矩形宽高比。真实蓝底白字车牌的宽高比大约是 3.14 比 1不含汉字间隔等特殊差异所以拿到每个连通域的 BoundingBox 后计算 width/height越接近这个比值越可能是车牌。报告没有直接贴出筛选那几行而是通过彩色标记图可视化展示不同区域RGB label2rgb(L, spring, k, shuffle); figure, imshow(RGB); title(图像彩色标记);这一步的原理不复杂背景被形态学滤波清理后车牌字符的边缘会连成一个横向的长条形区域其他噪声区域要么太大车身要么太小树叶、文字要么长宽比不对路牌、车灯。代码里用bwlabel给每个连通域编号regionprops算出每个域的参数再人工检查或加一段筛选逻辑把宽高比接近 3 的区域挑出来。实际操作里这个环节是整车牌识别准确率的分水岭选错了区域后面全白搭。3.2 投影分析与峰谷检测找到字符的每一行车牌区域提取出来后还不能直接分割字符因为图像里可能带着上下边框、铆钉和车牌背景的干扰。报告的处理方式是投影分析——把二值图像按行和列分别累加像素值形成水平投影和垂直投影再在投影曲线上找峰谷。histcol1 sum(sbw1); % 垂直投影每列像素和 histrow sum(sbw1); % 水平投影每行像素和 figure, subplot(2,1,1), bar(histcol1); title(垂直投影含边框); subplot(2,1,2), bar(histrow); title(水平投影含边框);sumbw1是车牌区域的二值子图sum(sbw1)沿列求和得到垂直投影sum(sbw1)沿行求和得到水平投影。车牌上边框和下边框在水平投影上表现为两个高而窄的峰字符区域则是一个宽而平的峰。通过对投影曲线做峰谷检测找到峰上升点和下降点就能精确确定字符区域的行范围把上下边框切掉。这一步最容易翻车的点是投影曲线毛刺太多。原因往往前面就埋下了二值化阈值偏了或者形态学结构元素尺寸不对导致字符边缘断裂或粘连投影峰谷边界模糊。报告中专门保留了完整投影图就是为了让使用者能肉眼对照检查峰谷位置的判断是否合理。3.3 倾斜校正线性拟合算旋转角实际拍照时车牌很少有完全水平的尤其从侧面拍倾斜个三五度很常见。倾斜直接破坏字符分割的准确性所以报告在分割前设计了校正环节。校正方法很朴素也很实用——拟合车牌边缘那条直线算出与水平轴的夹角然后旋转。% 提取车牌上边缘或下边缘像素值为1的点的坐标 % xdata, ydata 为边缘点的横纵坐标集合 fresult fit(xdata, ydata, poly1); % 一阶多项式拟合即线性拟合 p1 fresult.p1; % 斜率 angle atan(p1) * 180 / pi; % 斜率转角度 % 按计算出的角度旋转车牌图像 subcol imrotate(subcol1, angle, bilinear, crop); sbw imrotate(sbw1, angle, bilinear, crop);fit函数来自曲线拟合工具箱poly1表示拟合 y p1*x p2 的一次多项式p1就是斜率atan取反正切得到弧度再转成度。imrotate的第三个参数bilinear是双线性插值旋转后图像更平滑crop表示旋转后裁剪到与原图相同尺寸。旋转角度是正数就逆时针转是负数就顺时针转完全由拟合直线的斜率决定。我一般会建议在这里加一个角度阈值判断如果算出的角度绝对值小于 0.5 度干脆跳过旋转省一次插值带来的画质损失。报告里没有做这个判断直接旋转了——在课设这种简单场景下问题不大但放到真实数据集里多余旋转会让字符边缘变糊影响后面识别准确率。3.4 字符分割垂直投影找中心缩放成统一尺寸去完边框、校完倾斜就进入分割环节。这里的关键是计算每个字符的上升点、下降点和中心位置用垂直投影的谷值把字符切开。% 计算字符中心位置 for k 1:n1 markcol3(k) markcol(k1) - markcol1(k1); % 字符下降点 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); markcol6(findmax) 0; % 按找到的字符位置逐个切割并统一缩放到22x14 for k findmax-1:findmax5 cleft markcol5(k) - maxwidth/2; cright markcol5(k) maxwidth/2 - 2; SegBw1 sbw(rowtop:rowbot, cleft:cright); SegBw2 imresize(SegBw1, [22 14]); imwrite(SegBw2, strcat(sam\image, int2str(k), .jpg), jpg); end注意findmax那一段逻辑车牌字符中间通常有一个小圆点分隔符投影上表现为一个异常宽的间距直接用它把特征点剔除避免把分隔符当成字符。imresize把切割出来的字符统一缩放成 22x14这是样本库的标准尺寸保证后面字符比对时维度一致。strcat拼出文件名把分割好的字符图写入 sam 目录当作样本这套代码还自带建库功能想加新样本非常方便。3.5 字符识别样本库相减找最小误差如果把前面的字符串替换成 7 个 22x14 的二值小图识别就变成了一个最笨但最有效的办法——和样本库里每张图相减误差最小的就是答案。% 伪代码逻辑报告中的识别实现 for each char_image in 分割出的字符: min_error Inf result_char for each sample in 样本库: error sum(sum(abs(char_image - sample))); if error min_error min_error error result_char sample.name end output result_char这是基于模板匹配的思想。样本库里预先存放了汉字、字母、数字的 22x14 二值模板识别时逐个相减差值越小说明越相似。优点是零训练成本、代码量小、可解释性强缺点也明显对字体、粗细、噪声极其敏感轻微断笔或者笔画粘连就会让误差最小的模板变成错误答案。报告后面的失败案例——G 误识别成 B、K 误识别成 A、0 误识别成 8——就是这种敏感性最直观的体现。想提升识别率后文二次开发部分我会给出具体改造方向。4. 常见问题避坑从 imfeature 报错到识别翻车的排查记录4.1 imfeature 函数报错老版本函数已被移除现象代码运行到Feastats imfeature(L, basic)时MATLAB 直接报错“未定义函数或变量 imfeature”新版 R2023b 里根本没这个函数。原因imfeature 是老版本图像处理工具箱里的区域特征计算函数R2014b 之后被 regionprops 取代文档里直接标注了 deprecated。解决把imfeature(L, basic)改成regionprops(L, basic)返回的 Feastats 结构体字段名兼容Area 和 BoundingBox 的取法不用动。改完这一行整段连通域分析代码就能跑通。4.2 阈值公式在强光照下失效整张图二值化后全是黑的现象把 3.jpg 换成正午强光下拍的照片im2bw之后的二值图像车牌区域和背景糊成一团边缘图里车牌轮廓看不清。原因阈值(fmax1 - (fmax1 - fmin1) / 3) / 255是经验比例假设了灰度直方图大致呈单峰分布强光照、逆光、阴影场景下直方图形状完全变了固定比例不再适用。解决换成 Otsu 全局阈值一行代码level graythresh(Egray)让算法自动找分割阈值。如果光照不均匀更严重就上自适应阈值adaptthresh按局部亮度动态计算阈值。4.3 样本库路径写死换电脑直接找不到图片现象代码里保存样本用到strcat(F:\MATLAB\work\sam\image, int2str(k), .jpg)拷贝到别人电脑上运行保存或读取样本时提示路径不存在。原因绝对路径写死了原作者机器的盘符和目录结构换环境必然失效。解决用mfilename(fullpath)获取当前脚本所在目录再用fullfile拼接相对路径例如save_dir fullfile(fileparts(mfilename(fullpath)), sam)。这样整个项目随便挪到哪个目录都能跑也是所有 Matlab 小项目最值得养成的习惯。4.4 字符识别翻车G 识别成 B、K 识别成 A、0 识别成 8现象报告结果展示里明确记录了一次失败识别G 误判为 BK 误判为 A0 误判为 8。这几种错误在模板匹配算法里非常典型。原因模板匹配相减的误差只衡量像素差异没有考虑形状结构。G 和 B 都带竖画和半圆像素覆盖区域高度重合0 和 8 更是只差中间一横——二值化稍微断笔误差最小的样本就变成另一个字符。解决把纯像素相减改成带权重的比对例如先计算字符的宽高比、笔画密度、孔洞数作为粗筛特征再用像素误差做精匹配。更彻底的做法是换成报告里提到的 BP 神经网络分类器训练一个 22x14 输入、34 类输出的全连接网络对断笔和粘连的鲁棒性会好很多。4.5 非蓝色车牌定位失败整个候选区域筛选逻辑崩溃现象把测试图换成黄底黑字或白底黑字的车牌前面定位环节直接找不到候选区域或者找到的区域根本不是车牌。原因报告从预处理到形态学滤波乃至宽高比筛选整套参数都是针对蓝底白字车牌设计的。蓝底在灰度图上表现为中灰色和白色字符的对比度方向与其他底色车牌不同Canny 边缘响应和形态学连接结果都会改变。解决如果必须支持其他底色先在彩色空间做颜色判断统计 HSV 色相分布蓝色、黄色、白色各走一套预处理参数。黑底白字按报告原话整个算法原则上可以直接适用白底黑字和黄底黑字则需要把图像反转0 变 1、1 变 0让字符变成亮色后续分割算法依然有效。5. 二次开发把静态识别改成视频流与样本库增强这一章我不讲概念直接给三条可以落地的改造路径每条都是对这个报告源码动小手术就能完成的。第一把单张图片识别改成视频流识别。报告代码入口是imread(3.jpg)改成视频只需要一个循环用VideoReader读视频文件或webcam对象读摄像头实时画面每帧都调用现有的imread之后的处理链路。关键是要加一个车辆检测触发逻辑——报告开头提到车辆检测部分是系统组成之一但软件里没有实现。最简单的方案是帧差法取连续两帧做差如果差异像素超过阈值就认为有车辆进入视野才开始跑车牌识别链路。这样避免了每一帧都做全流程的算力浪费也贴合报告里“当车辆检测部分检测到车辆到达时触发图像采集单元”的设计叙述。第二升级字符识别的比对策略。报告里的模板匹配是把 22x14 二值图逐像素相减这个方法太脆。我的改造做法是先用形态学细化提取字符骨架然后对骨架图计算 HOG 特征方向梯度直方图再用一个简单的多层感知器分类。不用深度学习框架MATLAB 自带的feedforwardnet就能搭一个 128 维输入、34 输出的网络训练样本不够就每个字符模板做轻微平移、旋转、加噪声来扩充三倍数据量起步。训练完成后把原来相减比对的代码块换成net(test_feature)识别率提升是很明显的。第三加一个实时可视化面板。课设答辩时评委最喜欢看你现场改参数看结果。用 MATLAB 的uifigure和UIAxes组件做一个简易界面左边放原始图右边分四块依次显示灰度图、边缘图、二值图和识别结果外加一个阈值 slider 控件实时调节二值化level参数代码不到五十行。参数调节的效果立刻反映在四块画布上答辩效果比贴静态图强太多。给你一个实际验证过的小技巧改完任何一步不要只拿 3.jpg 一张图测。收集十张不同角度、不同光照、不同距离的车牌照片手机拍就行统一缩放到 640x480 后跑一遍全流程统计每张图的定位成功率和字符识别正确率。报告里识别成功和失败的两组案例已经说明了问题——一个系统在测试集上的表现永远比单张样例更值得关注。这套代码我前后拆过一遍最深的感触是传统图像处理方法的定位、分割、识别链路虽然每个环节都有明显的痛点但它每一步都是可观测、可调试、可解释的不像神经网络那样像个黑匣子。从那以后我每次拿 Matlab 做图像处理都会先看一眼输入图像的直方图分布和结构元素尺寸再决定要不要沿用报告的阈值公式而不是无脑跑完整段脚本。希望这份拆解笔记能帮你少走几个弯路。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?