
简介这份资源是面向高校数字图像处理、模式识别等课程的学生及初学者的一套车牌识别课程设计完整材料围绕MATLAB平台从图像采集、预处理、边缘检测到字符识别的全流程给出方案与源代码可用于课程设计、实验报告撰写及图像处理入门练手。压缩包共1个文件为一份docx文档约1.69MB内含系统设计目标、总体方案、功能模块实现与主要函数说明如imerode、imdilate、strel、edge等函数的用法与参数解释并给出车牌定位、字符分割、模板匹配的实现思路还涉及Canny、Sobel、霍夫变换等经典算法的应用场景与调试要点。目前已有599人学习下载适合需要参考完整课设框架、理解MATLAB图像处理函数意义、练习模板匹配识别流程的读者也便于在此基础上改进算法、提升系统稳定性与识别准确率。1. 为什么课程设计选车牌识别从一张停车闸口照片说起很多人第一次做数字图像处理课程设计选题列表里翻来覆去就是边缘检测、直方图均衡、傅里叶变换去噪做完把图一贴就交差老师给分也就六七十。车牌识别不一样它一条链路把灰度化、去噪、二值化、边缘提取、形态学、连通域分析、字符分割、模板或特征匹配全串起来了几乎把课本前半本的算子都用了一遍还天然带一个识别率指标能写进报告。更关键的是它足够具体——一张停车场闸口抓拍的车辆正面照光照不均、车牌有倾斜、背景是水泥墙这些真实约束逼着你把参数一个个调出来而不是在一张干净 Lena 图上跑个 sobel 就完事。这篇讲的就是用 MATLAB 从零实现这套流程代码能直接跑参数能改坑也标出来适合正在做数字图像处理大作业、课程设计或者想用 MATLAB 而非 Python 快速验证图像算法的人。2. 车牌识别的整体流程与 MATLAB 图像处理工具选型2.1 从原始彩图到候选车牌区域的处理链路车牌识别的工程实现通常拆成四大步预处理、车牌定位、字符分割、字符识别。预处理负责把 RGB 三通道压成灰度同时压掉噪声车牌定位是整条链路里最容易翻车的一步目标是在整幅图里框出那块矩形区域字符分割把车牌内部切成一到七个独立字符位字符识别对每个字符位给出具体是什么字。国内蓝底白字车牌是七个字符第一位是省份汉字第二位是字母后面五位字母数字混排新能源绿牌是八位。课程设计里绝大多数人只做蓝牌因为蓝底和车辆、路面的颜色差异最明显。用 MATLAB 做这件事的优势在于图像处理工具箱的函数命名非常贴近教科书rgb2gray、medfilt2、edge、bwareaopen、regionprops都是即插即用不像 OpenCV 要自己管 Mat 和内存。劣势也很明显没有现成的 OCR 接口字符识别得自己写模板匹配或者用简单分类器这恰恰是课程设计要考察的部分。2.2 关键函数选型与对应课本知识点对照处理阶段常用 MATLAB 函数对应知识点课程设计报告可写的指标灰度化rgb2gray加权平均法 Y0.299R0.587G0.114B不同权重对车牌对比度影响去噪medfilt2、wiener2中值滤波、维纳滤波PSNR、主观清晰度边缘检测edge(I,sobel)、canny梯度算子、非极大值抑制边缘连续性、噪声敏感度形态学strel、imclose、imopen膨胀、腐蚀、闭开运算结构元素尺寸对定位的影响连通域bwlabel、regionprops连通域标记矩形度、长宽比阈值颜色分割自定义 HSV 阈值色彩空间转换蓝色饱和度范围这张表基本就是报告里算法原理一章的骨架。选型逻辑是先用颜色信息粗定位再用形态学把碎块连成整块最后用几何特征筛掉非车牌区域。纯颜色法在强反光下会失败纯边缘法在复杂纹理背景上会误检两者结合是课程设计里性价比最高的方案。2.3 MATLAB 环境准备与读图显示的最小验证动手前先确认工具箱装全了。命令行敲ver看有没有 Image Processing Toolbox没有的话rgb2gray之后的很多函数会直接报未定义。% 环境与读图最小验证脚本 clc; clear; close all; I imread(car_plate.jpg); % 换成你自己的车辆照片 info imfinfo(car_plate.jpg); % 查看位深、色彩类型 fprintf(尺寸: %d x %d x %d, 色彩类型: %s\n, ... size(I,1), size(I,2), size(I,3), info.ColorType); % 若是 indexed 或 CMYK先转真彩 if ~strcmp(info.ColorType, truecolor) I ind2rgb(I, info.Colormap); I im2uint8(I); end figure(Name,原始图像); imshow(I); title(原始车辆图像);这段代码先读出图像尺寸和色彩类型是因为后面所有阈值都和位深有关im2bw默认阈值 0.5 只适用于 double 类型 0 到 1 范围的图像如果图是 uint8 的 0 到 255直接im2bw会报错。im2uint8统一转成 uint8 是稳妥做法。很多同学卡在这一步错误信息是Expected input number 1 to be double其实就是类型没对齐。提示把测试图放在脚本同目录用相对路径读换电脑不会因为绝对路径失效。3. 车牌定位颜色阈值、形态学与连通域筛选的实操3.1 基于 HSV 色彩空间的蓝色车牌粗定位RGB 三通道受光照影响大直接对 B 通道阈值化在阴影里会漏、在反光下会糊。HSV 空间把色调 H 单独抽出来蓝色车牌在 H 上非常集中。常见做法是转 HSV 后同时卡 H、S、V 三个区间。I imread(car_plate.jpg); hsv rgb2hsv(I); H hsv(:,:,1); S hsv(:,:,2); V hsv(:,:,3); % 蓝色车牌经验区间H 在 0.55~0.75(约 198°~270°)S 高V 中等偏上 bwBlue (H 0.54) (H 0.75) (S 0.35) (V 0.30); % 形态学闭运算填补字符间的空隙让整块车牌连成一片 se strel(rectangle, [5, 25]); % 横向长条符合车牌形状 bwClose imclose(bwBlue, se); bwOpen imopen(bwClose, strel(rectangle,[3,3])); % 去小噪点 figure; imshow(bwBlue); title(HSV 蓝色分割原始结果); figure; imshow(bwOpen); title(形态学处理后);逻辑说明rgb2hsv把每个像素映射到色调、饱和度、亮度。H 0.54大致对应 194 度往上的蓝青区间S 0.35排除灰白色的水泥墙和天空V 0.30排除纯黑的车底阴影。闭运算用横向长结构元素是因为车牌本身宽高比约 3:1横向一闭就能把蓝-蓝底之间被字符切断的部分连起来。开运算再去掉零散蓝色像素比如车灯反光。参数怎么调如果漏检先把S下限降到 0.25如果误检别的蓝车把H区间收窄到 0.56 到 0.68。3.2 regionprops 提取候选框并用长宽比过滤形态学之后通常还是会有几块候选蓝色车身、蓝色广告牌都可能留下。这时候用regionprops拿几何属性做二次筛选。stats regionprops(bwOpen, BoundingBox, Area, Extent, MajorAxisLength, MinorAxisLength); ratioMin 2.0; ratioMax 5.5; % 车牌长宽比大致范围 areaMin 1500; % 最小面积滤掉远处小碎块 candidates []; for k 1:numel(stats) bb stats(k).BoundingBox; ratio bb(3) / bb(4); % 宽/高 if ratio ratioMin ratio ratioMax stats(k).Area areaMin candidates [candidates; bb]; %#okAGROW end end fprintf(符合长宽比与面积的候选框数量: %d\n, size(candidates,1));BoundingBox返回的是[x, y, width, height]注意 MATLAB 里图像坐标是 (列, 行) 顺序和直觉的 (行, 列) 反着画框时这个坑最常见。长宽比设定 2.0 到 5.5 覆盖了蓝牌和新能源绿牌的常见比例同时把正方形广告牌排除。Extent是区域面积占外接矩形面积的比例车牌字符间隙多Extent 一般不高反而不能用太高阈值去卡。3.3 精定位与倾斜校正的补充处理粗定位出来的框往往比车牌大一圈可以用边缘投影法收紧。bestBB candidates(1,:); plateROI imcrop(I, bestBB); grayROI rgb2gray(plateROI); % 水平投影车牌区域行方向字符密集灰度跳变次数多 bwEdge edge(grayROI, sobel); rowSum sum(bwEdge, 2); [~, topIdx] max(rowSum); % 用 Hough 检测直线求倾斜角 [Hlines, T, R] hough(bwEdge); P houghpeaks(Hlines, 5, Threshold, ceil(0.3*max(Hlines(:)))); lines houghlines(bwEdge, T, R, P, FillGap, 10, MinLength, 20); if ~isempty(lines) theta mean([lines.theta]); fprintf(检测到的平均倾斜角: %.2f 度\n, theta); plateROI imrotate(plateROI, -theta, bilinear, crop); end figure; imshow(plateROI); title(校正后的车牌区域);hough把边缘点映射到参数空间houghpeaks找峰值对应的直线houghlines还原成线段。字符上下边缘基本是水平的所以lines.theta的均值就接近倾斜角。imrotate里用bilinear插值再crop避免黑边被后续二值化当成背景。如果图像本身没倾斜这步不会有害只是多花点时间。注意hough对噪声敏感先对 ROI 做medfilt2再求边缘否则检测出的直线可能落在字符笔画上。4. 字符分割与模板匹配识别的代码实现4.1 二值化与垂直投影切分单字符定位到车牌后先把 ROI 灰度化再二值化。Otsu 阈值比固定阈值稳因为不同照片车牌反光程度差别大。grayPlate rgb2gray(plateROI); grayPlate medfilt2(grayPlate, [3 3]); % 去椒盐噪声 level graythresh(grayPlate); % Otsu 自动阈值 bwPlate imbinarize(grayPlate, level); bwPlate ~bwPlate; % 白字黑底转成白底黑字 bwPlate bwareaopen(bwPlate, 20); % 去小噪点 % 垂直投影统计每列白像素数 colSum sum(bwPlate, 1); colSum(colSum 1) 0; % 找字符区间的起止列 thr max(colSum) * 0.15; inChar colSum thr; d diff([0 inChar 0]); startCol find(d 1); endCol find(d -1) - 1; fprintf(切分出 %d 个字符块\n, numel(startCol));逻辑说明graythresh用最大类间方差法算阈值对双峰直方图的图效果最好车牌正好是白字蓝底/黑底两个峰。~bwPlate取反是因为后续模板匹配习惯白底黑字。bwareaopen删掉面积小于 20 像素的连通域一般都是噪点或标点。垂直投影colSum统计每列前景像素字符列投影高、间隙列投影接近零用最大值的 15% 做软阈值切分。难点在于汉字京粤这类笔画不连的字符投影会出现多个峰常见修法是把间距小于 3 像素的段合并成一块。4.2 归一化到统一尺寸再匹配字符块大小不一必须先归一化。charSize [40, 20]; % 统一到 40 行 20 列 chars cell(1, numel(startCol)); for i 1:numel(startCol) seg bwPlate(:, startCol(i):endCol(i)); chars{i} imresize(seg, charSize); end % 保存一张拼图便于检查分割质量 montage(cat(3, chars{:}), Size, [1 numel(chars)]); title(分割后的字符序列);imresize用双线性插值把每块缩放到 40×20这样字符模板和待识别块尺寸一致做异或运算时才能逐像素对齐。montage把分割结果拼成一排显示是排查字符被切歪最快的可视化手段——如果拼图里某一块包含两个字符或者只包含半个笔画说明前一步投影阈值不对。4.3 模板匹配法识别的实现与识别率评估模板库里每个字符存一张同样 40×20 的二值图。% 假设模板存在 templates 结构体中templates.name, templates.img function [label, score] matchChar(charImg, templates) bestScore -inf; label ?; for k 1:numel(templates) t templates(k).img; same sum(~xor(charImg(:), t(:))); % 相同像素数 score same / numel(t); if score bestScore bestScore score; label templates(k).name; end end endxor逐位比较两个二值图相同位置的像素越多得分越高。这种方法的准确率高度依赖模板质量字体不一样、粗细不一样都会掉分。实践中对数字和字母能到 85% 以上汉字因为笔画复杂通常在 60% 到 75%。要提高可以给每个字符建 3 到 5 个不同字体或粗细的模板取最高分。评估指标就写识别率 正确字符数 / 总字符数在报告里列个混淆矩阵比如8 被误判为 B出现几次比只给一个百分比有说服力得多。5. 提速、抗干扰与报告演示的进阶技巧5.1 用积分与预分配减少循环开销模板匹配是双重循环字符数乘模板数模板上千时明显卡。把模板矩阵预先向量化能省不少时间。% 把所有模板展平成矩阵一次矩阵运算算完所有相似度 Tmat zeros(charSize(1)*charSize(2), numel(templates)); for k 1:numel(templates) Tmat(:,k) templates(k).img(:); end q charImg(:); scores 1 - sum(xor(repmat(q,1,size(Tmat,2)), Tmat), 1) / numel(q); [~, idx] max(scores); label templates(idx).name;repmat把待识别向量复制成和模板矩阵同宽xor一次性算出所有模板的差异max取最高分。相比逐模板循环模板数越多提速越明显。scores用 1 减去差异比例直接就是相似度便于设阈值低于 0.6 就判为无法识别不要硬猜报告中如实标注拒识比误识更专业。5.2 典型失败场景与参数回退策略失败现象大概率原因回退动作完全定位不到车牌H 区间不在本图车牌色调上打印 H 的直方图重新定区间框住车窗或广告牌长宽比阈值太松收紧 ratioMax 到 4.5字符粘连成一块投影阈值 thr 太高降到 0.08 或改用连通域分割汉字识别全错模板字体单一补 3 种字体的汉字模板倾斜车牌分割乱未做倾斜校正先跑一遍 Hough 校正这张表可以直接抄进报告实验结果分析里。调参的正确姿势是每次只动一个参数把前后图都存下来做对比而不是一次全改然后不知道为什么好了。课程设计答辩最容易被问的就是你这个阈值怎么定的能回答通过 H 分量直方图统计蓝色车牌集中在 0.58 到 0.70我取中间偏宽区间就很稳。5.3 打包成可演示脚本与报告图表输出答辩现场最忌讳现场调参数。把流程封成一个主函数用try-catch兜底一次性输出所有中间图和识别结果。function result plateRecognition(imgPath, templates) result.text ; result.plateROI []; result.ok false; try I imread(imgPath); plateROI locatePlate(I); % 第 3 章流程 if isempty(plateROI), return; end chars segmentChars(plateROI); % 第 4 章流程 for i 1:numel(chars) [lab, sc] matchChar(chars{i}, templates); if sc 0.6, lab ?; end result.text [result.text lab]; end result.plateROI plateROI; result.ok true; catch ME fprintf(识别失败: %s\n, ME.message); end endtry-catch保证任何一步崩了都不会让演示中断ok字段供上层判断。跑批时循环调用这个函数把每张图的result.text和人工标注对比自动算识别率。报告里的图建议用exportgraphics(gcf,fig1.png,Resolution,300)输出 300 dpi比直接截图清晰。选一张定位成功、一张部分失败、一张倾斜校正前后的对比图三张图就能把整个工作量和难点讲清楚。最后提醒一点模板库的字符图片不要从网上下载带水印的自己用insertText在空白图上画字体选宋体或仿宋和真实车牌接近这样识别率数字才站得住。本文还有配套的精品资源点击获取