MATLAB车牌识别系统实战:定位、分割与模板匹配

发布时间:2026/10/27 11:37:29
MATLAB车牌识别系统实战:定位、分割与模板匹配 简介基于MATLAB的车牌识别系统设计资料包面向数字图像处理课程设计、本科毕业设计及答辩场景适合需要快速跑通车牌定位、字符分割与识别全流程的读者。压缩包共77个文件整体仅2.11MB包含53个bmp标准字符样本、19个jpg真实场景图、4个m源码文件与1份答辩PPTbmp样本覆盖多省汉字及数字字母jpg场景包括白底黑字等不同样式m源码负责核心算法可在MATLAB中直接运行调试。源码涉及图像灰度化、均值滤波、二值化、膨胀腐蚀、车牌区域提取及字符模板匹配等关键环节可帮助理解从预处理到识别的完整链路。资源目录清晰样本库与场景图分类存放便于替换测试数据或扩展字符集。目前已有2528人学习下载配套答辩PPT辅助成果展示是兼顾算法实现与汇报输出的实用资料。1. 基于MATLAB的车牌识别系统从课程设计到能扛光照变化的识别流程基于MATLAB的车牌识别系统在每年matlab图像处理大作业里几乎是固定嘉宾。你搜到的多数帖子都能跑出一张干净蓝牌但很少有人告诉你从大作业演示到能应对不同光照和角度的实拍车图中间隔着的不是算法难度而是定位和分割环节里一堆要手动磨的阈值。一套完整流程通常由预处理、车牌定位、字符分割、模板匹配识别四段组成适合课程设计、本科毕设以及想快速验证视觉方案的工程师。这套方案的核心结论是定位比识别更值钱前面环节做扎实识别其实只是收尾。2. MATLAB车牌识别整体流程与预处理灰度化、边缘检测和形态学的出场顺序2.1 为什么先灰度化而不是先做边缘检测颜色空间和通道选择很多新手拿到车拍图第一反应是直接做边缘检测结果会得到满屏树干、车窗和路沿的边缘车牌淹没在噪声里。常见做法是先把彩色图转成灰度再做边缘检测。原因很简单车牌区域的特征是“字符密集、边缘纹理丰富”灰度图足够表达这种纹理而彩色信息在强光、阴影下极易漂移。蓝底白字车牌虽然可以用 HSV 颜色空间提取蓝色掩膜但蓝色阈值对傍晚、路灯和车身蓝色漆非常敏感灰度路线更稳。% 读取图像并转灰度 img imread(car_scene.jpg); if size(img, 3) 3 gray rgb2gray(img); else gray img; end % 对比度拉伸减少光照波动 gray imadjust(gray, stretchlim(gray, 0.01), [0 1]); % 中值滤波去噪窗口不宜过大 gray medfilt2(gray, [3 3]);这段代码里 stretchlim(gray, 0.01) 取图像灰度直方图的 1% 和 99% 分位点做线性拉伸效果是把偏暗或偏亮的画面拉回正常范围。中值滤波窗口选 3x3 而不是 5x5是为了保留字符边缘的锐度窗口越大边缘越糊后续边缘检测反而吃亏。实测在逆光场景下这步能明显提升车牌区域和车漆之间的对比度。如果你的输入是 ROI 已裁好的车牌图可以跳过 medfilt2直接进二值化。2.2 边缘检测算子选择Sobel 稳还是 Canny 好预处理之后的核心操作是边缘检测。MATLAB 的 edge 函数内置多种算子车牌识别场景里我一般优先用 Sobel而不是很多人默认的 Canny。原因是 Canny 的双阈值会把字符内部细碎边缘也连起来导致后续形态学闭运算把整个车牌糊成一块白斑Sobel 只响应梯度较大的位置对字符笔画这种“粗边缘”更友好。Canny 的优势在弱边缘检测但车牌字符本身对比度高不需要这种优势。% Sobel 边缘检测阈值取经验值 edges edge(gray, sobel, 0.08); % 闭运算把字符边缘连成连通域 se strel(rectangle, [15, 15]); closeImg imclose(edges, se); % 填充内部空洞去掉字符笔画之间的缝隙 closeImg imfill(closeImg, holes);edge(gray, sobel, 0.08) 的第三个参数是梯度阈值低于该值的像素不算边缘。0.08 是从 800x600 左右的实拍图里调出来的图像分辨率越高、光照越强阈值可以往上抬到 0.1夜间图建议降到 0.05。结构元素 15x15 是闭运算的核心参数它决定“多近的边缘会被连成一块”。车牌字符高度在图中约占 20 到 30 像素时15x15 能刚好把整行字符连成长条又不会把旁边车身缝隙也并进来。这个参数没有标准答案需要按你的图像分辨率等比缩放。2.3 预处理参数速查光照不均、噪声和分辨率怎么配环节推荐参数作用失败表现灰度拉伸stretchlim 0.01压住过曝和过暗低对比度→定位框偏大中值滤波3x3去椒盐噪声窗口过大→字符边缘断开Sobel 阈值0.05 ~ 0.1控制边缘密度过低→噪声边缘爆炸闭运算结构元15x15 起调连通字符区域过小→车牌断成几块空洞填充默认补字符间隙不填→连通域面积偏小这些参数之间是联动的。我见过不少人把 Sobel 阈值调到 0.2 想压噪声结果车牌边缘也一起被滤掉后面 regionprops 根本找不到候选框。正确顺序是先固定分辨率再调 Sobel 阈值最后动结构元素尺寸。每次只改一个变量否则定位翻车时你分不清是哪一步导致的。预处理这块最忌讳把 MATLAB 当黑匣子每步都输出 imshow 看一眼中间结果能省下大量排错时间。3. 车牌定位的实现细节边缘密度、形态学闭运算与连通域三阈值3.1 车牌定位的三条路边缘密度、颜色掩膜和深度学习检测车牌定位有主流的三类做法。第一类是基于边缘密度加形态学筛选速度快、依赖少是 MATLAB 车牌识别系统里最常见的方案也是本方案的主角。第二类是基于 HSV 颜色空间提取蓝色掩膜再利用蓝色区域的外接矩形定位。它对蓝色车漆和夜晚路灯非常不友好唯一优点是能直接排除红车干扰。第三类是用深度学习目标检测比如在较新的 MATLAB 版本里通过 Deep Learning Toolbox 调 YOLO 系列模型精度高但需要标注数据和 GPU课程设计里性价比不高。做传统方案时我一般用边缘密度作为主筛条件。车牌区域在二值边缘图中表现为“横向纹理密集”的长条而车漆、玻璃、路面的边缘要么太稀疏要么方向杂乱。闭运算之后车牌的字符和边框会连成一个或两个大块连通域这是后续筛选的基础。需要说明的是闭运算的矩形结构元方向要水平尺寸要和车牌在画面中的比例匹配这部分逃不掉人工调参属于玄学之外的工程经验。3.2 用 regionprops 筛候选车牌宽高比、面积占比与填充率形态学处理之后画面里剩下的连通域可能还有十几个。此时用 regionprops 提取每个区域的几何属性再用三组阈值做粗筛。三组阈值分别是宽高比、面积和填充率。蓝底白字车牌的宽高比一般在 2.5 到 4.5 之间面积占整图的比例随拍摄距离变化但不会低于某个下限填充率反映的是“区域内边缘像素的密集程度”车牌区域因为字符密布填充率明显高于车身边缘。stats regionprops(closeImg, BoundingBox, Area, FilledArea); candidates []; for k 1:length(stats) w stats(k).BoundingBox(3); h stats(k).BoundingBox(4); ratio w / h; fillRatio stats(k).FilledArea / stats(k).Area; % 车牌候选框常见约束 if ratio 2.5 ratio 4.5 fillRatio 0.3 candidates(end1, :) stats(k).BoundingBox; %#okSAGROW end end % 取面积最大的候选框 if ~isempty(candidates) [~, idx] max(candidates(:,3) .* candidates(:,4)); plateBox candidates(idx, :); end区域填充率 fillRatio 是 FilledArea 和 Area 的比值它比单纯用面积稳定。因为面积受拍摄距离影响大而填充率描述的是这个连通域“内部实不实”。字符密集的车牌填充率通常在 0.3 以上而一段孤立的保险杠边缘填充率只有 0.1 左右。最后取面积最大候选框的操作隐含了一个假设车牌在画面里不会是占比最小的那个区域。如果你的测试图里车牌离得远面积阈值就要下调。3.3 车牌倾斜校正用霍夫变换求主角度定位得到的矩形框往往带一点倾斜角不校正直接分割会导致字符边界切歪。常见做法是用霍夫变换检测矩形里的长直线取最长的直线角度作为车牌倾斜角再用 imrotate 做旋转。注意霍夫变换的输入应该用原始灰度图的边缘图而不是形态学处理之后的连通域图否则长直线会被闭运算吞掉。% 从原图裁出车牌区域 plateGray imcrop(gray, plateBox); % 重新对车牌区域做边缘检测 plateEdge edge(plateGray, sobel, 0.08); % 霍夫变换检测直线 [H, theta, rho] hough(plateEdge); peaks houghpeaks(H, 5, Threshold, ceil(0.3 * max(H(:)))); lines houghlines(plateEdge, theta, rho, peaks, FillGap, 20, MinLength, 40); % 取最长的直线用其角度做旋转校正 if ~isempty(lines) angles [lines.angle]; angle mean(angles); plateGray imrotate(plateGray, angle, bilinear, crop); endhoughpeaks 的 Threshold 设为 max(H) 的 0.3 倍可以滤掉短直线干扰。FillGap 20 表示同一直线上间距小于 20 像素的断点会被连接MinLength 40 表示小于 40 像素的线段不参与统计。这段参数针对 800x600 图。车牌倾斜超过 10 度时imrotate 的 crop 选项会裁掉边缘字符此时建议改成 loose 再手动定位或者干脆在分割前对每行字符单独做水平校正。4. 字符分割与模板匹配识别投影法切字和归一化相关打分4.1 字符分割垂直投影法的谷底判定与峰值阈值车牌区域校正之后下一步是把 7 个字符逐个切出来。最常见的做法是投影法对二值车牌图做列求和字符列因为白色像素多形成峰值字符间隔处形成谷底通过谷底位置切分字符。但这一步最容易踩坑的是二值化方式。直接 imbinarize 用全局阈值在光照不均时会丢掉字符所以更可靠的输入是自适应二值化。% 自适应二值化蓝底白字选择 dark 前景 bw imbinarize(plateGray, adaptive, ... ForegroundPolarity, dark, Sensitivity, 0.5); % 去除上下边框干扰只保留中间 80% 行 bw bw(round(end*0.1):round(end*0.9), :); % 垂直投影统计每列前景像素数 colProj sum(~bw, 1); % 谷底判定低于峰值 10% 的列视为字符间隔 threshold max(colProj) * 0.1; validCol colProj threshold; startIdx find(diff([0, validCol]) 1); endIdx find(diff([validCol, 0]) -1);ForegroundPolarity 设为 dark是因为蓝底白字里字符是亮前景但经过取反后字符像素在 ~bw 中表现为 1所以投影前要对 bw 取反。Sensitivity 0.5 是自适应二值化的敏感度调大会保留更多细节调小则抗噪更强。字符断裂时优先提高 Sensitivity字符粘连时降低它。切出来的每个区间还要用字符宽度做过滤比如宽度小于中位数一半的区间直接丢弃通常是铆钉或噪点。4.2 模板匹配识别归一化相关与候选排序字符切片之后常见做法是归一化尺寸到固定大小然后和模板库逐张计算归一化相关系数。MATLAB 的 corr2 直接算两张图的皮尔逊相关系数相比绝对差值和它对照明变化不敏感适合字符内有轻微阴影的场景。每个字符的输出结果是所有模板里的最高分通常还会保留第二高分用于后续调试。% 模板库 templates 为 cell 数组charList 为对应字符 normSize [40, 20]; scores zeros(1, length(templates)); % 对每个字符切片归一化尺寸 charResized imresize(segChar, normSize); for t 1:length(templates) tmpl imresize(templates{t}, normSize); scores(t) corr2(double(charResized), double(tmpl)); end [sortedScores, idx] sort(scores, descend); bestChar charList{idx(1)}; secondChar charList{idx(2)}; % 当第一第二候选分差太小时标记为低置信度 if sortedScores(1) - sortedScores(2) 0.05 fprintf(低置信度字符: %s / %s\n, bestChar, secondChar); end这里的关键参数是置信度门限 0.05。分差小于这个值时说明两个模板都像后续宁可报警让人工复核也不要硬给一个结果。模板尺寸统一到 40x20 是经验值切出来的字符高度大约 30 像素上采样到 40 并不会增加信息只是让所有模板和切片处在同一尺度。注意 imresize 默认双线性插值即可不要用 nearest否则字符边缘会出现锯齿导致匹配分数波动。4.3 模板库怎么来用字体渲染生成训练样本模板匹配的效果上限取决于模板库质量。拍照采集真实车牌字符样本是最准的路径但需要几百张图才能覆盖各省简称、字母数字的粗细变化。更高效的常见做法是用字体渲染生成一套基础模板用 insertText 把字符画到背景上或直接通过 figure 绘制后用 getframe 截取。汉字字体用中文字体字母数字用 Arial 加粗这两类字体特征与实际车牌接近。% 用 insertText 生成简单模板 charSet 0123456789ABCDEFGHJKLMNPQRSTUVWXYZ京津沪渝冀豫云辽黑湘皖新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼; templateList {}; for i 1:length(charSet) c charSet(i); img insertText(zeros(60, 120, uint8), [10, 10], c, ... FontSize, 40, TextColor, white, BoxOpacity, 0); tmpl rgb2gray(img); tmpl tmpl 128; templateList{end1} tmpl; %#okSAGROW end生成模板时建议有意做几个变体加粗版、细体版、轻微模糊版。实际拍到的车牌字符经过摄像头采样后会有一定模糊模板太锐利反而匹配不上。注意车牌字符里没有字母 I 和 O避免混淆 1 和 0。模板库大小为每个字符 2 到 3 个变体就够堆太多变体反而会让低分模板抢到最高分。5. MATLAB车牌识别避坑手册从定位失败到字符断裂的 6 个高频问题5.1 定位翻车蓝色车漆、夜间光照和小目标现象形态学处理之后蓝色车漆和车窗边缘形成一个面积很大的连通域被误判成车牌真正的车牌反而没进候选框。原因蓝色车身在灰度图里和蓝底车牌灰度接近闭运算把车身边缘也连成了长条叠加填充率约束也无法区分。解决在筛选条件里补充颜色先验用 HSV 提取蓝色掩膜只保留同时满足“蓝色像素占比高”和“宽高比合理”的连通域。实际操作是在灰度图定位基础上对候选框区域计算蓝色像素比例低于 5% 的直接丢弃。这个办法能同时压制蓝色货车、绿色树木等干扰。现象夜间照片里车牌区域过暗Sobel 边缘图里车牌字符几乎不可见定位框完全缺失。原因夜间车牌在车灯照射下容易过曝或车牌本身处于阴影里灰度拉伸无法恢复字符对比度。解决针对暗图单独走颜色定位分支在 HSV 空间用较低的 V 阈值提取蓝色区域再对候选区做局部直方图均衡化。stretchlim 对全局图处理不了这种局部过暗需要 imlocalbrighten 或 adapthisteq 辅助。现象车牌在画面中占比小于 1%闭运算后车牌区域被当成噪声直接抹掉。原因结构元素 15x15 是按近距离图调的远距离车牌字符间距小但整个车牌面积也小闭运算后无法形成有效连通域。解决把输入图按照最长边缩放到固定尺度再做流程比如最长边 1000 像素。这样远近图都能落到同一参数区间比反复调结构元素尺寸省事。5.2 分割断裂铆钉、边框和投影谷底误判现象垂直投影切分时字符被切出多段比如“京A12345”切成了 10 个碎片或铆钉噪声让第一个字符被拦腰切开。原因车牌上下边框没有完全清除二值化后边框和字符连成一片投影谷底被边框抬高字符间隔无法形成明显谷底。解决先做水平投影定位字符行的上下边界把上下边框精确裁掉再做垂直投影。水平投影找到前景像素密度最高的一段连续行这段就是字符行其余行全部丢弃。现象字符“1”和“7”之间的间隔被投影谷底吞掉两个字符粘成一个宽块。原因自适应二值化的 Sensitivity 调太高字符边缘扩张间隔处的前景像素没降到阈值以下。解决把 Sensitivity 从 0.5 下调到 0.3然后观察二值化结果里字符间是否出现黑色缝隙。如果还粘连就改用固定阈值 imbinarize(bw, graythresh(plateGray)) 做对照实验。现象投影切出的字符块宽窄不一有的字符顶部被切掉一截。原因车牌倾斜校正角度算偏了字符行仍有少量旋转投影时字符顶部和底部不在同一列范围内。解决在切割前对二值图逐行动态校正常见做法是用形态学提取字符行的上下轮廓拟合两条包络线把字符按包络线逐段拉平。这个步骤代码量不大但对识别率提升非常明显。5.3 识别混淆模板风格不一致和低置信度硬选现象模板库里汉字用常规宋体生成实际车牌汉字是特殊字体匹配分数普遍偏低甚至误识别成“津”这种字形相近的字。原因模板风格和真实字符差异大corr2 对笔画粗细、起笔收笔的形状差异非常敏感。解决换用真实车牌字体生成模板或者找现场图裁剪出字符样本补充进模板库。没有现成字体时对基础模板做形态学腐蚀和膨胀各生成一套变体也能缓解风格不匹配。现象某帧图识别结果在几个字符间跳变比如“5”和“6”分差不稳单帧识别率不高。原因单帧图像里字符本身模糊模板匹配的分数差异被噪声放大。解决多帧投票。连续拍 3 到 5 帧每个字符位置取出现次数最多的结果。这个办法能直接把识别率从 90% 推到 97% 以上代价仅仅是延迟增加几百毫秒。现象调试时发现算法在 A 组图上表现好换到 B 组图定位框乱跳。原因没有固定一套验证集参数是针对记忆中的图片调的属于典型的过拟合调试。解决把测试图按白天、夜间、逆光、倾斜四类分别建文件夹每次调参跑全量测试集记录定位成功率和识别准确率用数字说话。6. 把识别率再往上推多帧投票、混淆矩阵与验证集划分识别率卡在某个位置不上不下时继续调 Sobel 阈值往往是浪费时间更有效的是从验证和集成两个方向入手。多帧投票是最容易实施的技巧它的思路是单帧识别会有随机性但同一辆车的连续几帧字符不会突变逐位取众数能把偶发抖动压掉。% voteMatrix: 帧数 x 字符数 的字符矩阵 finalResult ; for col 1:size(voteMatrix, 2) chars voteMatrix(:, col); finalResult(end1) mode(chars); %#okAGROW endmode 是众数函数少数服从多数。这个技巧要求车辆在画面里停留至少 3 帧对停车场闸机这类场景天然适用对单张抓拍则无效。另一个高性价比手段是人工检查混淆矩阵。把自己测试集上识别错的字符整理成表通常会发现错误集中在少数几对字符之间。混淆对常见原因应对措施0 和 O模板库里 O 太少去掉 O车牌不含 O1 和 I模板风格不统一统一去掉 I7 和 T分割时顶部缺失修正倾斜校正8 和 B下边缘模糊提高二值化敏感度最后是验证集划分。我早期做这项大作业时习惯把 50 张图来回调参最后在自认为不错的准确率上沾沾自喜换一批现场图立刻现原形。后来养成的习惯是预留 20% 的图完全不参与调参只在最终评估时跑一次。这个习惯帮我避开了大量自我感觉良好的翻车现场。整体思路就是让参数调整有反馈闭环让识别结果有置信度出口剩余的交给数据量说话。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询