
简介本资源是面向图像处理初学者与智能交通系统开发者的MATLAB实践教程聚焦夜间低照度场景下的车牌识别全流程实现解决光照不足导致的对比度低、噪声干扰强、定位困难等核心问题。压缩包共3个文件7.58MB含1段实操讲解MP4视频演示算法运行与效果对比、1个核心MATLAB脚本chepai.m完整实现预处理、Canny边缘检测定位、连通域分析分割、字符模板匹配识别四步流程及1张典型夜间车牌测试图用于本地验证与调试。已有128人学习下载内容紧扣工业应用需求覆盖直方图均衡化增强、高斯滤波降噪、二值化阈值选取、投影法字符切分等关键技巧并提供可直接运行的代码框架与可视化中间结果输出便于理解每一步图像变换原理并快速复现效果。 夜间车牌识别在MATLAB图像处理大作业里几乎是一个绕不开的经典题目。它不像白天识别那样简单拉个阈值就能完事也不像深度学习方案那样需要一堆标注数据和显卡而是把图像增强、边缘检测、形态学处理、字符分割这些最基础也最核心的知识点全部串了起来。我最早接到这个项目的时候用的是网上打包下载的“零基础源码”就是那种带GUI界面的.zip压缩包跑通一张图很简单但心里其实没底。后来花了两周时间把每一行都重新实现了一遍才算真正弄懂这套流程里什么地方容易翻车。这篇文章就把我踩过的坑和最终的实现思路完整写出来适合正在做图像处理课设、毕设或者想系统学习传统车牌识别流程的朋友参考。1. 项目整体设计与方案选型1.1 夜间车牌识别为什么比白天难很多人以为车牌识别就是把图像读进来边缘检测定位分割识别一气呵成。白天确实可以这么做但到了晚上同一套流程直接翻车。原因是夜间图像的成像条件和白天差别太大环境光弱导致整体灰度偏低车牌区域的字符和底色对比度被压缩车身、灯牌、路面反光会产生大量高光噪声再加上车灯直射造成的局部过曝会让车牌边缘变得模糊甚至断裂。这些干扰对传统图像处理算法的打击是致命的。白天用全局阈值二值化直方图双峰清晰阈值一卡就干净夜间直方图可能只有一个大峰整幅图黑压压一片车牌区域的像素灰度可能从40到220都有直接二值化会得到一块大花斑。另一个麻烦是色彩偏色。夜间照明光源复杂可能是黄橙色的路灯也可能是冷白色的LED白色车牌在两种光源下拍出来完全是两个色温如果直接依赖RGB颜色阈值找蓝色车牌很容易漏检。所以夜间车牌识别并不只是把白天的流程拿来跑一遍而是需要额外增加预处理环节并且对定位、分割参数做针对性设计。理解了这一点你就知道为什么这个题目值得单独拿来做一期了。1.2 传统图像处理方案的整体流程我最终采用的流程是图像增强 → 降噪 → 边缘检测 → 形态学闭运算 → 连通域候选筛选 → HSV颜色验证 → 车牌区域裁剪 → 二值化 → 字符分割 → 归一化 → 模板匹配。这套流程是典型的传统计算机视觉方案不依赖任何深度学习框架MATLAB自带的图像处理工具箱就能跑通。为什么选传统方案而不是YOLO最现实的原因是教学场景和大作业要求。绝大多数课程考核的是你是否理解图像处理的基本原理而不是让你调一个训练好的模型跑出精度。传统方案能够把每一步中间结果单独可视化出来定位失败也知道是哪一环节出的问题。另一个优势是部署成本低不需要GPU笔记本上打开MATLAB就能跑。缺点是鲁棒性确实比数据驱动的方案差尤其是遇到极端角度、遮挡、强过曝时容易翻车但作为入门和理解完整流程来说这套方案的价值非常高。如果你后来想进一步做深夜停车场、高速卡口的真实识别可以在传统流程的基础上加入帧间融合、多尺度检测或者直接换到深度学习方案但那已经是另一个维度的事情了这篇文章先把传统方案做到极致。1.3 运行环境与项目文件结构项目基于MATLAB R2021a及以后版本验证过使用到图像处理工具箱Image Processing Toolbox和计算机视觉工具箱Computer Vision Toolbox中的基础函数。打开压缩包后常见的目录结构是这样night_plate/ ├── main.m ├── preprocess.m ├── locatePlate.m ├── segmentChars.m ├── recognizeChars.m ├── templates/ │ ├── char_0.png │ ├── char_1.png │ ├── ... │ └── char_9.png └── test_images/ ├── night_01.jpg ├── night_02.jpg └── night_03.jpg压缩包名字里的“21”通常只是表示示例编号或者作者自己整理的第21个项目不用太纠结。关键是看里面有没有完整的模板库因为模板匹配的模板数量和质量直接影响识别准确率。如果你手里的压缩包只有代码没有templates目录建议先去找一套标准车牌字符模板或者稍后我会讲怎么用程序自动截取模板。2. 夜间图像预处理先把图像质量提上去2.1 灰度化与光照不均的应对夜间车牌识别第一步永远是灰度化。用rgb2gray函数就行本质是按亮度公式把三通道压缩成一维灰度Gray 0.299R 0.587G 0.114B。这个公式给绿色分量更高权重符合人眼对亮度敏感度的分布比简单平均三个通道更合理。灰度化之后你会立刻看到问题图像直方图集中在左侧低灰度区域整体对比度很差。这时候如果直接做边缘检测车牌的字符边缘亮度差异小Sobel或Canny算子计算出的梯度幅值会被周围噪声淹没。我一开始试着用imadjust做线性拉伸效果有一点但遇到车灯高光区域就会顾此失彼——拉伸太狠暗部是提亮了亮部也过曝了拉伸太轻暗部细节还是出不来。img imread(night_01.jpg); gray rgb2gray(img); % 线性对比度拉伸先看看效果 stretched imadjust(gray); imshowpair(gray, stretched, montage);运行这段代码你会发现线性拉伸只能解决“整体偏暗”的问题解决不了“局部过暗局部过曝”同时存在的问题。夜间场景恰恰是这种非均匀光照所以我们需要更聪明的增强方法。2.2 自适应直方图均衡化CLAHE真正好用的是自适应直方图均衡化MATLAB里对应adapthisteq函数。它会把图像划分成若干小块每个小块独立做直方图均衡化再做双线性插值消除块与块之间的边界同时通过ClipLimit限制对比度放大幅度避免过度放大噪声。% 对灰度图做CLAHE增强 enhanced adapthisteq(gray, NumTiles, [8 8], ClipLimit, 0.02);这里NumTiles设成[8 8]表示把图像分成8x8的网格ClipLimit控制在0.01到0.03之间比较合适。如果夜间图像实在太暗ClipLimit可以提高到0.05但要注意噪声也会被放大尤其是暗部区域的彩色噪声转成灰度后会变成颗粒感很强的纹理。我对比过histeq和adapthisteqhisteq做全局均衡化遇到大面积暗背景会把噪声一起拉高adapthisteq因为局部操作保留了车灯周围的亮部层次同时把车牌区域的字符与底色对比度拉得更开。这一步做完车牌区域的字符边缘明显锐利后续边缘检测的成功率提升了一大截。2.3 降噪处理中值滤波与高斯滤波的选择增强之后噪声也会被同步放大这时候必须降噪。夜间图像的噪声来源主要包括传感器暗电流噪声高斯型和个别亮点坏点脉冲型。我习惯把中值滤波和高斯滤波配合着用先用3x3的medfilt2去掉孤立亮点再用5x5的imgaussfilt平滑高斯噪声。% 先中值去孤立亮点 denoised medfilt2(enhanced, [3 3]); % 再高斯平滑 denoised imgaussfilt(denoised, 1.2);中值滤波核心优势是保边缘因为它是取邻域中值而不是均值车牌字符的锐利边缘不会被大面积磨平。高斯滤波的sigma设成1.2左右比较温和sigma太大会让字符边缘变粗定位时导致候选区域膨胀。要注意的是如果图像本身噪声不大降噪这步可以轻一点甚至跳过但夜间图像我建议保留因为后续边缘检测对噪声极其敏感一个孤立亮像素就会产生一条伪边缘线。预处理做到这里整张图已经从“一团黑”变成“细节看得清、噪声压得住”的状态了接下来就可以进入真正的车牌定位环节。3. 车牌定位从整张图里找到那块蓝色或黄色牌3.1 边缘检测为什么选Sobel而不是Canny车牌定位的经典思路是先找边缘再用形态学操作把边缘连成连通域。边缘检测算子有很多Sobel、Prewitt、Roberts、Canny但我带队做项目时一直推荐先用Sobel。Canny虽然精度高但阈值需要反复调夜间图像光照变化大固定高低阈值很容易把墙面纹理、路面裂缝全部检出来整个边缘图变得密密麻麻形态学闭运算之后根本分不清哪块是车牌。Sobel对横向边缘响应比较强而车牌字符区域正好是由大量横向笔画组成的用Sobel提取之后再用水平方向的结构元素做闭运算能把字符边缘和车牌边框连接成一块完整的矩形区域。代码如下edges edge(denoised, Sobel); % 显示边缘图检查是否存在大量断裂 imshow(edges);如果边缘图里车牌区域已经有比较明显的矩形轮廓说明预处理到位。接下来用形态学闭运算把断裂的边缘连起来。我这里用了一个比较扁的矩形结构元素宽度大于高度目的是优先连接水平方向的断裂。se strel(rect, [17 3]); closed imclose(edges, se);结构元素的尺寸是经验值我建议根据图像分辨率缩放。默认测试图如果是1920x1080[17 3]合适如果换成手机拍的1280x720结构元素宽高可以对应调整为[13 2]。选太大会把临近的多个物体融合成一个区域太小则连不上字符之间的空隙。闭运算做完图像里会留下几个白色块车牌的候选区就在其中。这还没完单纯边缘闭运算会把车灯、反光广告牌、白色车身也框进去下一步必须加约束过滤。3.2 HSV颜色特征二次过滤车牌颜色是固定先验蓝底白字、黄底黑字、新能源绿底黑字。夜间颜色偏色严重如果直接用RGB阈值亮度一变阈值就失效。正确的做法是转到HSV空间只保留色调H通道的信息因为色调对光照变化的敏感度远低于亮度通道。hsv rgb2hsv(img); % 注意这里用原始彩色图而不是灰度图 H hsv(:,:,1); S hsv(:,:,2); V hsv(:,:,3); % 蓝色车牌掩膜 blueMask (H 0.55 H 0.75) (S 0.3) (V 0.15); % 黄色车牌掩膜 yellowMask (H 0.08 H 0.16) (S 0.3) (V 0.15); % 新能源绿色车牌掩膜 greenMask (H 0.33 H 0.50) (S 0.3) (V 0.15);这里H取值在[0,1]之间蓝色对应的色相在0.55到0.75附近。夜间图像中蓝色车牌因为光线暗饱和度S不会太高所以阈值设到0.3白天则可以提高到0.4。V通道阈值设在0.15是为了过滤掉纯黑背景避免全图都变成候选。颜色掩膜要和边缘闭运算的结果做逻辑与只有既满足颜色条件又满足边缘形状的区域才是真正的车牌候选区。这一步能挡掉很多边缘闭运算造成的误检比如车灯区域的边缘很强烈但颜色往往偏白偏黄过不了蓝色掩膜。candidate closed imdilate(blueMask, se);这里先对blueMask做了膨胀因为夜间车牌颜色可能因为反光分散膨胀一下能让掩膜覆盖完整。3.3 连通域筛选的几何约束经过颜色过滤后还有可能有多个候选区域最后用几何规则筛选。我用regionprops提取连通域属性然后按以下条件过滤参数典型范围说明面积大于500像素过滤小噪点按图像分辨率调整宽高比2.0 ~ 5.0标准车牌宽高比约3.0夜间倾斜相机适当放宽填充率0.2 ~ 0.8车牌区域内字符和底色分布不均但不会低到空框高度图像高度的3% ~ 15%车牌不可能太小或太大props regionprops(candidate, BoundingBox, Area, FilledArea, Image); imgH size(img, 1); imgW size(img, 2); for i 1:length(props) bb props(i).BoundingBox; w bb(3); h bb(4); area props(i).Area; ratio w / h; fillRatio area / (w * h); if area 500 ratio 2.0 ratio 5.0 ... fillRatio 0.2 fillRatio 0.8 ... h 0.03 * imgH h 0.15 * imgH plateCandidates bb; end end我实际跑下来夜间图像最影响筛选的是“面积大于500”这个阈值。如果相机是高清图车牌可能占4000多像素这个阈值可以继续抬高如果图很小500又太高。建议先imshow画一下所有连通域外接矩形看哪些被过滤掉了再反推阈值。定位完成之后用imcrop把车牌区域裁出来最好多裁5到10像素的边距避免字符被切到。这个边距在后续字符分割时要先去掉。4. 字符分割与识别从定位到输出结果4.1 字符分割前的二值化处理车牌区域裁剪出来后先要把它转成黑白二值图才能继续做投影分割。夜间车牌区域虽然被预处理过但仍然可能存在局部反光直接全局二值化容易出问题。MATLAB里graythresh用的是大津法自动计算类间方差最大的阈值对双峰直方图效果很好但夜间车牌图像的直方图往往只有一个峰大津法会把大部分背景也归为前景。我的经验是结合局部自适应二值化用imbinarize的adaptive参数plateGray rgb2gray(imcrop(img, plateCandidates)); bw imbinarize(plateGray, adaptive, ForegroundPolarity, dark, Sensitivity, 0.4);注意这里我用了ForegroundPolarity, dark因为车牌字符是暗色蓝色、黑色背景是亮色白色或浅色。Sensitivity控制阈值灵敏度夜间图像调高一点到0.5能保住笔画但容易把污渍也当成前景白天调低到0.3比较稳。二值化后建议做一个中值滤波把孤立噪点去掉。4.2 投影法分割字符及干扰处理字符分割的核心方法是投影法把二值图像做垂直方向投影统计每一列的白色像素数连续为0的区间就是字符之间的缝隙。同理再做水平投影确定字符的上下边界。colProj sum(bw, 1); thresh min(colProj) 0.1 * range(colProj); charRegions colProj thresh; % 找出连续区域 d diff([0, charRegions, 0]); starts find(d 1); ends find(d -1) - 1;这里thresh不能直接设成0因为车牌边缘框、铆钉、字符笔画粘连都会导致投影不完全归零。取一个很小的阈值比如最小投影值加10%的极差能有效过滤细线干扰。真正的坑在字符粘连和铆钉。车牌中间有一个圆点分隔符它和字符之间通常有缝隙分割问题不大。但某些角度下两个字符的笔画会被边框连在一起投影时缝隙被白色像素填满。解决思路是在二值化之前先对车牌区域做一次形态学开运算用比较细的水平结构元素把边框和字符笔画断掉seLine strel(line, 5, 90); % 垂直方向短结构元素 bw imopen(bw, seLine);imopen先腐蚀后膨胀能去掉窄条噪声和细连接线对字符笔画的影响很小。经过这一步分割效果会稳定很多。4.3 字符归一化与模板匹配分割出来的每个字符图像大小不一样直接匹配模板很难匹配上。需要先做归一化把每个字符统一缩放到模板的尺寸比如40x20再和模板库里的所有字符计算相似度取最相似的作为识别结果。function result recognizeChar(charImg, templates) charImg imresize(charImg, [40 20]); % 二值化后与模板逐像素比较 charImg charImg(:); scores zeros(length(templates), 1); for i 1:length(templates) t templates{i}(:); % 用归一化互相关作为相似度 scores(i) sum(charImg .* t) / (norm(charImg) * norm(t) eps); end [~, idx] max(scores); result templates(idx).label; end模板匹配看起来简单实际使用时会遇到不少问题字符字体不同、倾斜、亮度不一致、粘连笔画被分割成两半。为了提升准确率我建议先做倾斜校正用radon变换或最小外接矩形角度旋转到水平再做一次粗分类比如根据字符的高宽比先分成数字、汉字、字母三类减少匹配范围。夜间字符可能边缘模糊匹配前最好对字符图像做一次膨胀或骨架化统一笔画粗细效果会改善很多。如果你手头的MATLAB版本比较新可以用内置的ocr函数做一个兜底验证。不过ocr对中文车牌字符识别能力一般作为结果输出前的好习惯是把模板匹配第一候选和ocr候选一起打印出来人工确认错误模式。% 简单粗暴的兜底方案 recognizedText ocr(bw, TextLayout, Block); disp(recognizedText.Text);5. 常见问题与排查技巧实录5.1 车灯强光导致车牌区域过曝这种情况在夜间单帧图像里几乎无解因为过曝区域已经丢失了字符结构信息任何增强算法都补不回来像素值。我的第一个建议是在采集时尽量规避直射光第二个建议是用多帧融合连续拍几帧取每帧灰度值最低的像素合成一张图因为车牌相对于车灯是静止的车辆在移动时多帧叠加可以保留暗部字符细节。如果你只能处理单帧那就把预处理里的CLAHE参数稍微压低一点防止把高光区域的噪声放大然后接受这个区域的识别率下降。5.2 蓝色车身或蓝色路牌导致定位误判颜色特征过滤后如果还是误检多半是车身边缘经过闭运算后和蓝色掩膜重叠了。解决思路是增加几何约束的权重尤其是宽高比和填充率。蓝色车身通常是一个大面积连通域宽高比远远大于5会在ratio限制那里被过滤掉。另外可以在找到多个候选区域时选面积最接近标准车牌尺寸且宽高比最接近3的那个而不是全图最大的区域。5.3 字符分割错位严重时的排查顺序分割错位最直接的表现是识别结果多一位或者少一位。这时候不要急着调匹配算法先把每一步中间结果都画出来看。我把这一步归为四个固定顺序看二值图是否干净看开运算是否切断了字符间粘连看垂直投影阈值是否过滤了边缘噪声看连续区域的宽度是否满足车牌的字符宽度经验范围。这四个环节里最容易出问题的是开运算结构元素宽度夜间反光会让字符笔画变宽原本宽度5能断开的连接反光时可能需要7或9。5.4 问题排查速查表现象可能原因排查方案定位不到车牌边缘杂点过多调整CLAHE的ClipLimit、增大形态学结构元素候选区域过多颜色阈值太宽松收紧HSV中饱和度S的范围加入几何约束字符分割粘连二值化后笔画过粗增大开运算结构元素宽度或使用局部阈值模板匹配错字字符倾斜/字体差异增加倾斜校正扩充模板集合车灯过曝区域漏检图像信息丢失多帧融合或拍摄时规避高光这套排查方法在调试时能节省大量时间。我每次都会把中间结果用subplot排在一个figure里像流水线一样从头看到尾基本一眼就能找到翻车环节。我个人在实际操作中的体会是夜间车牌识别最大的瓶颈其实不在识别算法本身而在图像质量。你预处理做到位后面每一步都能顺很多你预处理偷懒后面的定位和分割就要用无数奇怪参数去弥补最后还是补不干净。建议做这个项目的朋友先去拍几张、下载几张典型的夜间车辆图片把增强和定位两个环节反复对比等这两步稳定了再去碰模板匹配会少走很多弯路。最后再分享一个小技巧和白天图片相比夜间图片的二值化阈值、形态学结构元素尺寸都要适当调小因为暗光下边缘强度本身就弱再用白天的大尺寸结构元素会把车牌区域直接“膨胀”没了。本文还有配套的精品资源点击获取