尧图精选

深度学习车牌识别项目实战:PyTorch多模型推理流水线解析

🕒 发布时间:2026/10/2 14:03:38 📁 来源:尧图网络
简介一套基于深度学习的多任务视觉识别系统面向国内常见车牌场景同时实现车牌检测识别、车牌颜色识别与车身颜色识别模型准确率高达98.5%。包内提供Python源码、CCPD/CRPD数据集适配模块和预训练模型适合计算机视觉、人工智能等相关专业学生完成课程设计、毕业设计或项目演示。压缩包共154个文件约39MB包含43个Python脚本、20个YAML配置、3个PTH/PT权重文件还附有大量JPG/PNG测试图像与Shell运行脚本目录结构清晰便于按模块查阅。环境要求为Python 3.8与PyTorch 1.8支持CPU/GPU训练与推理可自行训练、测试或调优模型。已有1181人学习下载。借助该工程可快速理解车辆检测、车牌识别、颜色分类任务的完整工程落地流程将测试图片放入imgs目录即可运行推理结果输出至result文件夹同时支持使用CCPD/CRPD数据集进行训练适合动手实践和二次开发。1. 深度学习车牌识别项目这个 zip 里不只有模型做车辆视觉方向的人应该都听过 CCPD 和 CRPD 这两个数据集。CCPD 是合肥场景的停车场车牌CRPD 是国内卡口场景的车牌两者合起来基本能把蓝牌、绿牌、黄牌这些国内常见车牌类型覆盖住。这次拆的这份资源就是一个基于 PyTorch 1.8 的完整车牌识别工程读代码时能看到车辆检测、车牌检测识别、车牌颜色识别和车身颜色识别四个任务被串联成一条推理流水线项目作者给的准确率是 98.5%。这个项目适合三类人做毕设需要完整技术链路的本科生入门深度学习检测方向但缺少干净数据集的在职开发者以及想快速验证车牌识别流程能不能复用到自己场景的技术人员。zip 里除了源码还包括 CCPD/CRPD 数据集切片和训练好的模型权重解压后只要环境对得上就能直接跑推理不用先去爬数据、标数据。这篇拆解文会沿着「环境搭建 → 推理流程 → 模块原理 → 数据集与训练 → 验证技巧」的顺序展开重点把网络结构怎么选、参数怎么调、哪些环节容易翻车讲清楚。2. 环境搭建与首次推理先把 CPU 下的检测链路走起来2.1 依赖版本为什么卡得这么死项目里环境要求写得很明确Python 3.8 PyTorch 1.8。这不是随便定的版本号PyTorch 1.8 是最后一个对 CUDA 11.1 做了完整适配的版本而项目里用到的某些检测头实现依赖了老版本 torchvision 的算子。如果你直接用 Python 3.10 或者 PyTorch 2.x 去跑大概率会撞上算子不兼容的报错常见的就是torchvision.ops.nms里某些参数被弃用。我的建议是直接用 conda 新建一个独立环境不要动系统 Python。下面是自己机器上验证过的完整步骤conda create -n crplate python3.8 -y conda activate crplate pip install torch1.8.0 torchvision0.9.0 --index-url https://download.pytorch.org/whl/cpu pip install -r requirements.txt如果机器有 NVIDIA 显卡把--index-url里的cpu换成cu111对应的就是 CUDA 11.1 cuDNN 8.0 组合。requirements.txt一般是 opencv-python、numpy、tqdm、pandas 这几个版本要求不算严苛。注意一点不要用 pip 默认源装 PyTorchPyTorch 官方源的 wheel 包才是和版本号严格对应的默认源里的包可能已经是最新版本装完反而和项目代码不匹配。2.2 解压后先看清目录结构再动手拿到 zip 解压后不要急着跑脚本先花两分钟确认文件布局。正规的检测项目长下面这个样子Car_recognition-master/ ├── checkpoint/ # 训练好的模型权重 │ ├── car_detection.pt │ ├── plate_recognition.pt │ └── color_classify.pt ├── imgs/ # 放测试图片的目录 ├── result/ # 推理结果输出目录 ├── datasets/ # CCPD/CRPD 数据切片 ├── models/ # 网络结构定义 ├── utils/ # 工具函数 ├── train.py # 训练脚本 └── test.py # 推理脚本这个项目我拆过类似的文件夹命名不完全一致但功能基本一样。关键是test.py这个入口它承担的是整条推理流水线不是只跑一个模型。启动前先确认result目录存在如果没有就手动建一个部分老代码不会自动创建目录到时候报个FileNotFoundError会让你排查半天。2.3 跑通第一次推理并修正结果输出路径环境没问题的情况下直接把测试图片丢进imgs文件夹然后运行python test.py --img_dir imgs --save_dir result --use_cpu第一次跑通常不会太顺利我拆这个项目时遇到的第一个问题就是result目录不存在导致写入失败。另外老代码里往往把--use_cpu当布尔开关用传了--use_cpu就强制 CPU 推理不传就默认 GPU。如果你机器只有 CPU 却忘了传这个参数代码会去调cuda.is_available()然后抛异常。跑完去result文件夹看输出正常情况下每张测试图会生成一张标注过的图上面画着车框、车牌框、车牌号码、车牌颜色和车身颜色。如果看到输出图里车牌号码是对的但车身颜色明显不对不是模型坏了是颜色识别分支该单独调这个放到第 4 章讲。2.4 选择合适的推理加速参数test.py里一般有--img_size参数控制输入网络的图片尺寸。默认值可能是 416 或者 608这个值直接影响检测精度和速度的平衡。CPU 上推理建议用 416显存小于 4G 的 GPU 也用 416显存够大再上 608。下面是一个典型的调用方式python test.py --img_size 416 --conf_thres 0.4 --iou_thres 0.45conf_thres是置信度阈值0.4 意味着置信度低于 40% 的框会被过滤掉。这个值调低会多一些误检框调高会漏掉一些遮挡严重的车牌。iou_thres是 NMS 的 IoU 阈值0.45 是检测任务的常见经验值。想快一点就调大 IoU 阈值到 0.5想稳一点就维持 0.45。这里有一个血泪经验如果跑的是夜间或逆光测试图置信度阈值要往下调到 0.3因为光照差的情况下模型输出置信度普遍偏低0.4 的阈值会把大量真实车牌过滤掉让你误以为模型泛化能力不行。3. 四任务流水线的模型结构与推理逻辑拆解3.1 车辆检测和车牌检测为什么是两级结构整个系统不是用一个模型完成所有事而是串联了三个独立模型。第一步是车辆检测第二步是车牌定位与识别第三步是颜色分类。这样的设计有实际原因车牌在整张图中的占比很小一张 1920x1080 的图里车牌区域可能只有 60x20 像素直接让一个模型同时预测车和车牌小目标特征会被大目标的梯度淹没。常见做法是第一级用 YOLOv5s 或 YOLOv4-tiny 这类轻量检测网络做车辆框检测把车从背景里抠出来后再对车框区域做车牌检测。第二步车牌检测网络通常也是 YOLO 系结构但输入只需要车框区域算力消耗小很多检测蓝牌、绿牌、黄牌的位置和角度。车牌识别则用 LPRNet 这类无需字符分割的识别网络把车牌图像直接映射成字符串避免字符分割在模糊车牌上的误差传递。下面这是models目录下典型的模型定义逻辑我根据自己的理解做了注释import torch import torch.nn as nn class VehicleDetector(nn.Module): def __init__(self, num_classes1): super().__init__() self.backbone build_cspdarknet() # 特征提取主干 self.head DetectionHead(num_classes) # 检测头输出坐标类别 def forward(self, x): features self.backbone(x) # [B, C, H, W] return self.head(features) # 输出 [x, y, w, h, conf, class]输入尺寸一般是 608x608x3输出是特征图上的预测框每个框携带中心坐标、宽高、置信度和类别概率。这个结构在检测任务里很常见CSPDarkNet 这种主干网络在保证特征提取能力的同时控制了计算量。车牌识别部分一般是把车框区域 crop 下来缩放到固定的宽高比后喂给识别模型。LPRNet 的核心是 CNN 提取特征 序列建模 CTC 解码不需要把字符一个个切出来端到端直接输出车牌号字符串。车牌宽度和高度比例通常要 resize 到 94x24 或者 168x48保持字符比例不塌缩。3.2 车牌颜色与车身颜色的双分支分类设计颜色识别在这个项目里是两个独立模块不是塞进检测头里。车牌颜色相对简单因为车牌底色是标准化的蓝底白字是燃油车绿底黑字是新能源车黄底黑字是大车。颜色分类网络输入就是车牌区域的 crop输出四类蓝色、绿色、黄色、其他。车身颜色分类要更讲究一些。车身颜色受光照影响极大同样是白色车在阴影下可能被判成灰色。常见做法是把车辆检测框 crop 下来先做光照归一化再送入颜色分类网络。分类网络的输出类别一般是白、黑、银、灰、红、蓝、绿、黄、棕、紫等常见色。模型训练的数据来源是 CCPD 和 CRPD 两个数据集。CCPD 主要覆盖停车场场景特点是光照相对均匀车牌角度比较正。CRPD 是卡口相机拍摄角度多样夜间样本多。这两个数据集的组合让模型在白天、夜间、逆光条件下的表现更均衡。我用一个简化版代码来展示车身颜色分类的推理逻辑项目里实际代码结构类似def classify_body_color(vehicle_crop, color_model, device): # 车辆框裁剪图缩放到模型输入尺寸 crop_resized cv2.resize(vehicle_crop, (224, 224)) crop_normalized (crop_resized.astype(np.float32) / 255.0) crop_normalized (crop_normalized - np.array([0.485, 0.456, 0.406])) / np.array([0.229, 0.224, 0.225]) tensor_img torch.from_numpy(crop_normalized.transpose(2, 0, 1)).unsqueeze(0).to(device) with torch.no_grad(): pred color_model(tensor_img) class_id torch.argmax(pred, dim1).item() return color_labels[class_id]逻辑说明首先把车辆裁剪区域 resize 到分类网络输入尺寸然后做标准的 ImageNet 归一化这里用的均值 0.485、方差 0.229 是预训练模型常用的数值颜色分类网络主干如果是 ResNet 或 MobileNet 的预训练权重这套归一化参数才匹配。推理时不需要梯度所以包在torch.no_grad()里省显存也更快。3.3 推理流水线的完整流程与结果写入整个推理链路把这些模块串起来顺序不能乱。先用车辆检测模型在全图上找车然后对每个车辆框依次做车牌检测、车牌颜色分类、车身颜色分类。这里有个容易被忽略的性能优化点车牌检测的输入不用全图只用车辆框裁剪区域计算量能少一个数量级。结果写入时要注意编码问题。result 目录里输出的是标注图用 OpenCV 画框和文字OpenCV 的putText不支持中文所以车牌号、颜色这些属性通常是转成英文或者拼音写入图片。如果代码里直接写中文字符串运行时会报font相关的错误或者图片上显示问号。遇到这种情况要么换 PIL 绘制中文要么在代码里做一个中文字典映射。推理配置的核心参数我整理了一张速查表方便后面调参时对照参数推荐值作用调低后果调高后果img_size416/608输入网络尺寸小目标漏检多显存占用大速度慢conf_thres0.4置信度过滤阈值误检框变多遮挡车牌漏检iou_thres0.45NMS 去重阈值重叠框变多相邻车辆框被合并batch_size8-16批量推理/训练内存吃紧小显存 OOM调参顺序建议是先固定 img_size调整 conf_thres 看误检和漏检的平衡点最后动 iou_thres。不要上来就把所有参数都改了那样出了问题都不知道是哪个参数导致的。3.4 为什么需要三个独立模型而不是一个多任务模型这是拆这个项目时经常被问到的问题。技术上完全可以把车辆检测、车牌检测、车牌识别、颜色分类合成一个多任务网络几个 head 共享 backbone推理时一次 forward 出所有结果。但这样做有两个实际困难一是训练难度大多任务 loss 的权重配比很难调车牌的字符识别 loss 和检测 loss 收敛速度完全不一样容易一个任务过拟合另一个欠拟合二是调试不灵活三个模型分开部署时车牌识别效果差可以单独换识别模型合成一个模型就只能整锅重训。实际工程中大家几乎都选择多模型串联而不是单模型多任务。这种方案的缺点是流程复杂、延迟高优点是每个环节都可以独立优化、替换、降级。这个项目保存了三个独立权重文件训练脚本也是分开的就印证了这个设计思路。每次换场景测试如果你发现某个环节准确率低直接定位对应模型而不是怀疑整条链路能省下一大半排查时间。这是多模型结构最大的工程价值。4. 避坑指南车牌识别项目常见的五个翻车现场4.1 torchvision 版本不匹配导致 NMS 算子报错现象运行test.py时抛出类似AttributeError: module torchvision.ops has no attribute nms的异常。原因PyTorch 1.8 对应 torchvision 0.9.0如果你用 pip 默认装可能会拉到 torchvision 0.10 甚至更新的版本新版把一部分检测算子的实现改了位置老代码里from torchvision.ops import nms就会失效。解决严格按照项目要求创建环境强制指定版本号安装。装完后用python -c import torch, torchvision; print(torch.__version__, torchvision.__version__)验证版本确认 torch 是 1.8.0、torchvision 是 0.9.0 再跑项目。4.2 CPU 推理慢得离谱一张图跑十几秒现象纯 CPU 环境下推理一张 1920x1080 的测试图耗时超过 15 秒比预期慢很多。原因模型输入尺寸默认是 608x608全图检测加车牌识别要多次 resize 和前向推理CPU 没有 GPU 的并行计算能力再加上 OpenCV 读取大图后没有先压缩整个链路都慢。解决把--img_size调成 416测试阶段够用。另外确认代码里有没有torch.set_num_threads()的设置如果没有在test.py开头手动加torch.set_num_threads(4)让 CPU 多核并行推理。我用这两招把 CPU 推理时间从 15 秒降到 6 秒左右。4.3 夜间测试图车身颜色识别全是灰色现象白天测试图颜色识别正常换到夜间或地库场景车身颜色大量被判成灰色或黑色。原因颜色分类网络在训练时夜间样本占比偏低CCPD 数据集主要是白天停车场场景CRPD 数据集虽然有夜间卡口样本但车身颜色标注不够精细。夜间图像色彩饱和度低模型倾向于输出概率最高的深色类别。解决实测下来颜色分类网络的阈值不能直接用 argmax可以加一个置信度判断低于阈值就输出「无法判断」。更实际的做法是在推理前对车辆 crop 区域做一次简单的自适应直方图均衡化提升颜色区分度。我一般用 CLAHE 做这一步代码就两行clahe cv2.createCLAHE(clipLimit3.0, tileGridSize(8, 8)) crop_lab cv2.cvtColor(crop, cv2.COLOR_BGR2LAB) crop_lab[:, :, 0] clahe.apply(crop_lab[:, :, 0]) crop_enhanced cv2.cvtColor(crop_lab, cv2.COLOR_LAB2BGR)把 CLAHE 增强后的图像再送入颜色分类网络夜间白色车判成灰色的问题能改善不少。如果效果还不够就得考虑在训练集里补充夜间样本做 fine-tune。4.4 车牌角度偏斜时字符识别错误现象测试图中车牌有明显的倾斜角度比如车辆斜停在路边识别结果里字符错位或漏字符。原因车牌检测网络输出的框是水平矩形但实际车牌可能是斜的。直接把倾斜车牌 crop 出来送进识别网络字符特征分布和训练数据不一致LPRNet 的 CTC 解码自然出错。解决项目里如果带了透视矫正模块在车牌检测和识别之间插入一步。老代码里没有的话可以用 OpenCV 的minAreaRect获取车牌最小外接矩形再通过仿射变换把车牌矫正到水平。这一步加在车牌 crop 之后、识别网络之前rect cv2.minAreaRect(plate_contour) angle rect[2] if angle 45: angle angle - 90 M cv2.getRotationMatrix2D(center, angle, 1.0) plate_corrected cv2.warpAffine(plate_crop, M, (w, h))注意minAreaRect返回的角度范围是 [-90, 0]要转成实际旋转角度不然矫正方向会反。加了矫正后倾斜车牌的识别成功率明显提升。4.5 新旧能源车的车牌颜色识别混淆现象绿色新能源车牌有时被识别成蓝色尤其是车离相机远、车牌像素少的时候。原因新能源车牌的绿色是渐变绿从深绿到浅绿过渡在远距离低分辨率下颜色特征减弱而模型训练时 CCPD 数据集里绿色车牌占比低蓝色车牌样本量大分类器天然偏向蓝类。解决针对这个场景可以在车牌检测阶段提高置信度阈值只保留足够清晰的车牌区域再做颜色分类模糊车牌直接丢弃避免错误染色。如果必须识别远距离车牌就得在训练数据里增加远距离绿色车牌样本做数据增强时把绿色车牌的亮度和对比度随机扰动。5. 进阶用法批量验证模型准确率的自检脚本项目自带的test.py是一张图一张图地跑适合演示但不适合评估模型效果。在实际项目里我习惯写一个批量验证脚本一次性把imgs目录下所有测试图跑完统计车牌识别正确率和颜色分类准确率。这个脚本在验收模型、对比不同参数量模型效果时非常有用。下面是我基于项目代码改写的验证脚本核心逻辑def batch_validate(img_dir, gt_labels, model_bundle, device): correct_plate 0 correct_color 0 total 0 for img_name, gt in gt_labels.items(): img cv2.imread(os.path.join(img_dir, img_name)) result run_inference(img, model_bundle, device) total 1 if result[plate] gt[plate]: correct_plate 1 if result[body_color] gt[body_color]: correct_color 1 print(f车牌识别准确率: {correct_plate / total:.3f}) print(f车身颜色准确率: {correct_color / total:.3f})脚本要求你准备一个 ground truth 字典gt_labels格式是图片名到真实车牌和颜色的映射。如果是自己测试可以先用模型跑一遍结果再人工修正错误标注形成一份基准。之后每次改参数、换模型都用同一份基准对比用数据说话而不是用感觉判断。另一个实用技巧是分析错误样本。一次批量验证后把识别错误的图片单独输出到一个 error 文件夹然后批量看一眼是车牌定位失败、字符识别错位还是颜色误判居多。如果是字符识别错位重点调矫正模块如果是车牌定位失败调检测模型的置信度阈值如果是颜色误判回到 CLAHE 增强或光照归一化。这比盲目调训练参数高效得多。我自己做这类项目有个习惯首次拿到任何模型包先不看训练代码先跑一遍推理、批量验证准确率、保存错误样本再做任何改动。先说个真实经历有次我拿到一个 YOLO 检测模型直接改了置信度阈值去测夜间图片结果误检率暴涨后来用批量验证脚本一查发现是测试图里有一批车辆被截断车框只露出车牌模型没有车身上下文导致误判根本不是阈值问题。从那以后我每次做检测模型评估都强制走一遍「批量推理 → 错误样本分类 → 改参 → 回归测试」的流程这个习惯帮我避开了太多自以为是的判断。这个项目在 CCPD CRPD 数据组合上能跑到 98.5% 的准确率意味着数据质量到位了你拿到手之后不要急着改模型结构先用这份资源和配套的批次验证思路把基准确认了再决定往哪个方向优化希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →