
简介本资源为基于YOLOv7的车牌识别算法系统面向计算机、人工智能、通信工程、自动化等专业的在校学生、教师及企业开发者可用于毕业设计、课程设计、项目立项演示或算法进阶学习。系统支持单行蓝牌、单行黄牌、新能源车牌、白色警用车牌、教练车牌、武警车牌、使馆车牌、港澳牌车、双层农用车牌、民航车牌等12种中文车牌类型覆盖常见与特殊场景的识别需求。压缩包共100个文件约24.05MB包含38个Python源码、13个YAML配置、5个Shell脚本、4个C与CUDA加速文件、2个PyTorch权重文件以及JPG/PNG示例图、说明文档和演示文稿兼顾训练、推理与部署环节。已有122人学习关注。项目代码经测试运行成功附带完整文档与权重读者可快速复现车牌检测与识别流程并在此基础上修改扩展实现自定义功能。1. 从一份车牌识别源码包说起12 种中文车牌到底怎么落地路上跑的车牌远不止蓝牌一种。单行蓝牌、单行黄牌、新能源绿牌、白色警用车牌、教练车牌、武警车牌、双层黄牌、双层武警、使馆车牌、港澳牌车、双层农用车牌、民航车牌——这 12 种类型如果只用一个通用检测模型硬扛双层车牌和单层车牌的字符排布差异会直接把识别率拉垮。这份基于 YOLOv7 的车牌识别算法系统把检测和识别拆成两段式流水线检测负责框出车牌位置并区分类型识别负责按类型走对应的字符解码逻辑源码包里detect_rec_plate.cpp、plate_rec.cpp、onnx2trt.cpp、utils.cpp、preprocess.cu这几个文件就是整条链路的骨架。它适合做毕设、课设、算法验证也适合已经跑通过 YOLO 系列、想补上「检测识别部署」完整闭环的从业者。下面按「资源是什么 → 怎么用 → 坑在哪」的顺序拆开讲。2. 两段式流水线拆解检测框与字符解码怎么分工2.1 为什么车牌识别不能只靠一个 YOLOv7YOLOv7 本身是目标检测网络输出的是边界框和类别。如果直接把 12 种车牌类型当成 12 个检测类别模型确实能告诉你「这里有个新能源车牌」但它不会告诉你车牌上的字符是什么。车牌识别的本质是「先定位、再读字」定位和读字对网络结构的要求完全不同定位需要大感受野和强特征提取读字需要序列建模能力来处理不定长字符。常见做法是检测阶段用 YOLOv7 输出车牌四角点或水平框识别阶段用 CRNN 或轻量级序列模型做字符分类。这份源码里detect_rec_plate.cpp承担的是调度角色它先调用检测模型拿到车牌区域再根据检测出的车牌类型把区域裁剪、矫正后送入plate_rec.cpp里的识别逻辑。检测和识别分离的好处是换检测模型不影响识别换识别模型也不影响检测调试时能单独定位是哪一段出了问题。另一个关键点是车牌类型决定了字符排布规则。单行蓝牌是 7 个字符一行排列双层黄牌是上下两行、每行字符数不同新能源车牌是 8 个字符且第一位是字母。如果识别模型不区分类型、统一按 7 字符解码双层车牌和新能源车牌必然出错。所以plate_rec.cpp里会先读检测阶段传过来的类型标签再选择对应的解码分支。2.2 检测阶段YOLOv7 的输入输出与类型标签YOLOv7 的输入默认是 640×640 的 RGB 图像但车牌在整图中占比很小直接缩放到 640 会丢失字符细节。工程上一般会先把原图做一次粗定位或者用较大输入尺寸如 1280来保留分辨率。这份源码的预处理逻辑在preprocess.cu里用 CUDA 做归一化和 letterbox 填充保证长宽比不变的前提下缩放到网络输入尺寸。检测输出是每个预测框的坐标、置信度和类别概率。12 种车牌类型对应 12 个类别索引源码里通过utils.cpp里的后处理函数做 NMS 和置信度过滤。这里有个容易忽略的点双层车牌的检测框高度通常是单层车牌的 1.5 到 2 倍如果 NMS 的 IoU 阈值设得过高上下两层可能被拆成两个框设得过低相邻车牌可能被合并。常见做法是 IoU 阈值取 0.45 到 0.5 之间再对宽高比异常比如高度大于宽度的框做二次判断。// utils.cpp 中 NMS 后处理的关键参数示意 float conf_thres 0.25f; // 置信度阈值低于此值的框直接丢弃 float iou_thres 0.45f; // NMS IoU 阈值控制重叠框合并程度 int max_det 100; // 单图最多保留的检测框数量 // 对双层车牌若框高宽比 1.2标记为双层类型后续走双行解码上面三个参数是检测阶段最常调的。conf_thres调低会引入误检调高会漏掉远距离小车牌iou_thres在车牌密集场景比如停车场出入口需要适当降低到 0.4 左右避免相邻车牌被误合并。max_det一般不用改除非做批量图片推理时发现漏检。2.3 识别阶段plate_rec.cpp 里的字符解码逻辑识别阶段拿到的是裁剪后的车牌小图。plate_rec.cpp里的处理流程通常是灰度化 → 尺寸归一化到固定高度如 48 或 64→ 按类型决定是否拆分成上下两行 → 送入识别网络 → CTC 解码或注意力解码 → 输出字符序列。12 种车牌类型里双层车牌的处理最特殊。双层黄牌和双层武警的字符分上下两行如果直接整图送入识别网络网络会把上下行字符当成一个序列解码结果会乱序。源码里的做法是检测阶段如果判定为双层类型识别前先用投影法或固定比例把车牌图切成上下两半分别识别后再按「上行在前、下行在后」拼接。// plate_rec.cpp 中双层车牌拆分逻辑示意 if (plate_type DOUBLE_YELLOW || plate_type DOUBLE_ARMED) { int mid plate_img.rows / 2; // 按高度中点切分 cv::Mat top plate_img.rowRange(0, mid); cv::Mat bottom plate_img.rowRange(mid, plate_img.rows); std::string top_str rec_single_line(top); // 识别上半行 std::string bottom_str rec_single_line(bottom); // 识别下半行 result top_str bottom_str; // 拼接完整车牌号 }这段逻辑的关键参数是切分位置。固定取中点对大多数双层车牌够用但如果拍摄角度倾斜上下行高度不一致固定中点会切到字符。更稳的做法是先做水平投影找到两行之间的空白谷底再切。源码里用的是固定比例实际部署时如果发现双层车牌识别率明显偏低可以优先改这里。新能源车牌是 8 位字符第一位是字母D 或 F后面是数字和字母混合。识别网络输出的字符集需要包含这些字母否则解码时会丢字符。plate_rec.cpp里的字符字典一般会覆盖数字 0-9、字母 A-Z 以及中文省份简称具体字典内容在源码的配置区能看到。2.4 onnx2trt.cpp模型转换与推理加速的衔接onnx2trt.cpp这个文件负责把训练好的 ONNX 模型转成 TensorRT 引擎。YOLOv7 的 PyTorch 权重先导出 ONNX再用这个脚本转成 TensorRT 的 plan 文件。转换时需要注意 opset 版本和动态尺寸设置如果导出 ONNX 时用了 opset 11 以上TensorRT 的解析器兼容性更好如果输入尺寸固定为 640×640转换时把动态维度关掉推理速度会更快。# 常见的 ONNX 导出与 TensorRT 转换命令示意 python export.py --weights yolov7_plate.pt --include onnx --img-size 640 640 --opset 12 ./onnx2trt yolov7_plate.onnx yolov7_plate.engine --fp16第一行把 PyTorch 权重导出为 ONNX--opset 12是较稳妥的选择。第二行调用源码编译出的onnx2trt可执行文件--fp16开启半精度推理速度通常能提升 30% 到 50%精度损失在车牌识别场景下一般可接受。如果发现转换后检测框坐标偏移优先检查导出 ONNX 时的输入尺寸和预处理是否一致。3. 从源码到可运行编译、模型准备与推理验证3.1 编译环境与依赖项确认这份源码是 C 工程依赖 OpenCV、CUDA、TensorRT 和 cuDNN。编译前先确认版本匹配CUDA 版本要和 TensorRT 版本对应OpenCV 建议用 4.x。preprocess.cu是 CUDA 核函数文件编译时需要 nvcc 支持。如果只在 CPU 上跑可以把 CUDA 相关代码注释掉但推理速度会明显下降。# 典型的编译流程示意 mkdir build cd build cmake .. -DCMAKE_BUILD_TYPERelease -DOpenCV_DIR/usr/local/opencv4 make -j$(nproc)CMAKE_BUILD_TYPERelease开启优化OpenCV_DIR指向本机 OpenCV 安装路径。如果 cmake 报找不到 TensorRT需要手动在 CMakeLists.txt 里指定 TensorRT 的 include 和 lib 路径。编译产物里会有detect_rec_plate可执行文件这就是推理入口。3.2 模型文件放置与配置文件检查源码包里通常不包含训练好的权重文件需要自己准备或从项目说明里指定的位置获取。检测模型和识别模型分别放在models/目录下配置文件中会写明模型路径、输入尺寸、字符字典路径。readme.docx里一般会说明模型文件应该放哪、配置文件怎么改。常见做法是先用项目自带的示例图片跑一遍确认整条链路能通。如果检测框位置对但识别结果乱码大概率是字符字典不匹配如果检测框都没有检查模型路径和输入尺寸是否写对。3.3 单图推理与结果验证# 单张图片推理命令示意 ./detect_rec_plate --image test_plate.jpg --config config.yaml --output result.jpg运行后会在result.jpg上画出检测框和识别出的车牌号。验证时重点看三类单行蓝牌是否 7 位全对、新能源车牌是否 8 位且首位字母正确、双层车牌上下行拼接顺序是否正确。如果某类车牌系统性出错回到plate_rec.cpp里查对应的解码分支。3.4 批量测试与指标统计单张跑通后用一批测试图做统计。把检测框和识别结果导出成文本和标注文件对比算检测 mAP 和识别准确率。车牌识别场景下识别准确率比检测 mAP 更关键因为检测框稍微偏一点不影响读字但字符错一个整个车牌号就错了。# 批量统计识别准确率的脚本示意 import os correct, total 0, 0 for line in open(predictions.txt): pred_plate, gt_plate line.strip().split(,) total 1 if pred_plate gt_plate: correct 1 print(f识别准确率: {correct/total:.4f})这个脚本假设预测结果和标注按行对应。实际使用时要注意车牌号里的字母 O 和数字 0、字母 I 和数字 1 容易混淆统计时可以先把这些易混字符统一映射后再比对否则准确率会被低估。4. 避坑与排查车牌识别落地时最容易翻车的五个点4.1 双层车牌被当成单层识别字符顺序全乱现象双层黄牌或双层武警车牌的识别结果只出现一行字符或者上下行字符交错。原因检测阶段没有正确区分单双层类型识别阶段走了单行解码分支。解决检查检测模型的类别索引是否和plate_rec.cpp里的类型判断一致确认双层类型的枚举值没有写错如果检测正确但识别仍乱检查切分位置是否落在字符上改用投影法找行间空白。4.2 新能源车牌少一位首位字母丢失现象新能源车牌识别出 7 位而不是 8 位或者首位 D/F 变成数字。原因识别网络的字符字典里没有包含新能源专用字母或者 CTC 解码时把首字符当成了空白符。解决打开字符字典文件确认 D、F 在列检查 CTC 解码的 blank 索引是否和训练时一致如果训练集里新能源样本太少需要补充样本重新训练识别模型。4.3 ONNX 转 TensorRT 后检测框整体偏移现象PyTorch 推理正常转成 TensorRT 引擎后检测框位置系统性偏移几十像素。原因导出 ONNX 时的预处理归一化均值、方差、letterbox 填充方式和 TensorRT 推理时的预处理不一致。解决把预处理参数写进配置文件确保导出和推理用同一套检查 letterbox 的填充值是否一致常见的是 114 或 128不一致会导致坐标映射错位。4.4 编译时报 preprocess.cu 相关链接错误现象make时提示 CUDA 核函数未定义引用。原因CMakeLists.txt 里没有把.cu文件加入编译源或者 nvcc 和 gcc 版本不兼容。解决确认 CMakeLists.txt 里有enable_language(CUDA)并把preprocess.cu加入add_executable如果 nvcc 报不支持当前 gcc 版本降级 gcc 或升级 CUDA 到匹配版本。4.5 远距离小车牌漏检严重现象近处车牌能检出远处或小尺寸车牌检测不到。原因YOLOv7 输入尺寸固定为 640小车牌缩放后像素太少。解决把推理输入尺寸提高到 1280或者先用一个粗定位模型裁出车牌大致区域再送入检测也可以在训练时增加小目标样本的权重。5. 进阶技巧用类型分支和置信度阈值把识别率再提一档跑通整条链路之后真正拉开识别率差距的往往不是换更大的模型而是把类型分支和阈值调细。我一般会做三件事。第一按车牌类型分别统计识别准确率。把 12 种类型拆开看你会发现双层车牌和新能源车牌的准确率通常明显低于单行蓝牌。针对低准确率类型单独调参比全局调参有效得多。比如双层车牌可以把检测置信度阈值从 0.25 降到 0.2先保证不漏检再用识别阶段的字符置信度做二次过滤。第二给识别结果加一个置信度门槛。plate_rec.cpp里 CTC 解码时会输出每个字符的概率把整串字符的最低概率作为该车牌的识别置信度。低于某个阈值比如 0.6的结果标记为「不确定」在实际业务里可以触发二次识别或人工复核。这个做法在停车场、收费站场景很实用能避免低质量结果直接进数据库。第三做类型与字符集的交叉校验。单行蓝牌第二位通常是字母新能源车牌首位只能是 D 或 F使馆车牌有固定的字符格式。识别完成后用这些规则做一次后处理校验不符合规则的直接丢弃或降权。这一步不需要重新训练模型纯逻辑判断就能过滤掉一部分明显错误。调优手段作用阶段典型参数预期收益按类型分阈值检测后处理conf_thres 0.2~0.3双层车牌召回提升字符置信度过滤识别解码min_char_prob 0.6低质量结果减少类型规则校验识别后处理正则匹配明显错误过滤从那以后我每次拿到车牌识别项目都会先把 12 种类型各跑一遍统计再决定调哪个分支而不是一上来就换模型。希望帮到你。本文还有配套的精品资源点击获取