ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

YOLOv5s6+CRNN车牌识别工业级流水线实现

YOLOv5s6+CRNN车牌识别工业级流水线实现 简介这是一套面向计算机专业本科生与初阶AI开发者的高分毕业设计级中文车牌识别系统融合YOLOv5目标检测与CRNN端到端OCR识别技术完整实现车牌定位、颜色判别与字符识别全流程并配备可交互的PyQt GUI界面适用于课程设计、大作业及毕设实战。资源包共91个文件含53个Python核心脚本覆盖数据预处理、模型训练/测试、GUI构建、ONNX/OpenVINO导出等、15个YAML配置文件含YOLOv5多尺度模型定义与超参设置、9张效果演示图及7张测试样图另有2个预训练.pth权重文件和1个.pt模型整体压缩包仅7.65MB轻量易部署。已有238人学习下载资源经严格调试可直接运行包含清晰的模块划分如plateNet/LPRNet/colorNet三大子网络、双阶段训练脚本train_yolo.py train_ocr.py、GUI主程序main_GUI.py及配套README说明显著降低复现门槛。1. 这不是“YOLOv5CRNN”拼凑的玩具项目而是能跑通完整车牌识别流水线的毕设级工程你可能见过 dozens 个标着“YOLOv5车牌检测”的 GitHub 仓库——它们大多只到 bbox 输出就戛然而止OCR 部分要么用 pytesseract 硬凑要么直接 return 京A12345 做 mock。但这个项目不同它把车牌识别拆成可验证、可调试、可替换的三段式工业级流程——YOLOv5 负责精准定位含双层车牌、倾斜车牌、低照度车牌CRNN 主干网络 自研 colorNet 分支完成字符级 OCR 车牌颜色分类最后通过 GUI 实时渲染检测框、识别结果、置信度热力图并支持图片/视频/摄像头三种输入源。评审分 97 的核心不在炫技而在每个模块都留有 debug 接口detect_plate.py中--save-crop可导出裁剪图验证定位质量plate_ocr_test.py支持单图逐帧 OCR 可视化train_color.py单独训练颜色分类器避免 OCR 混淆蓝牌/黄牌/新能源绿牌。它面向的是需要交源码、跑演示、答评委问题的计算机专业学生也适合想快速搭建车牌识别 baseline 的算法工程师——所有依赖项版本锁定在requirements.txtCUDA 11.3 PyTorch 1.10 环境下实测通过连cv_puttext.py都重写了中文 Unicode 渲染逻辑避免 OpenCV 默认字体显示方块。2. YOLOv5s6 与 CRNN-LPRNet 双模型协同机制解析2.1 为什么选 YOLOv5s6 而非 yolov5s 或 yolov5m该项目未采用通用 COCO 预训练权重而是基于yolov5s6.yaml6 个检测头构建车牌专用检测器。关键改动在于 neck 层新增RepConv结构替代原BottleneckCSP提升小目标车牌宽高比约 3:1像素尺寸常低于 120×40的特征提取能力。对比实验显示在自建的 2000 张夜间模糊车牌数据集上yolov5s6的 mAP0.5 达 92.7%比标准yolov5s高 4.3%。其配置文件中anchors已重设为[[10,13, 16,30, 33,23], [30,61, 62,45, 59,119], [116,90, 156,198, 373,326]]专为车牌长条形目标优化。训练超参也非默认值hyp.finetune.yaml中lr0: 0.01学习率、momentum: 0.937动量、weight_decay: 0.0005权重衰减均经网格搜索确定且启用cosine学习率调度而非linear。提示yolov5s6.yaml位于models/目录其backbone部分第 5 层[-1, 1, Conv, [512, 3, 2]]后插入[-1, 1, RepConv, [512, 3, 1]]这是提升小目标召回的关键修改点。2.2 CRNN 与 LPRNet 的混合架构设计OCR 模块并非纯 CRNN而是CRNN 主干 LPRNet 字符注意力分支 colorNet 颜色分类头的三路输出结构。plateNet.py定义主干CNN 提取特征后接双向 LSTMnn.LSTM(256, 256, bidirectionalTrue)再经nn.Linear(512, len(alphabet)1)输出字符概率。但关键创新在LPRNet.py它引入STN空间变换网络对 CNN 特征图做仿射校正解决车牌倾斜导致的字符错位问题colorNet.py则从同一 CNN 特征图分支出 3D 全连接层输出蓝牌/黄牌/绿牌三分类概率。三路输出通过加权融合权重由config/plate_rec.yaml中ocr_weight: 0.7,color_weight: 0.3控制生成最终结果。2.2.1 字符集与 alphabet.py 的定制逻辑alphabets.py不是简单罗列汉字而是按字符频次易混淆性分组第 0 组高频数字0123456789第 1 组高频汉字京沪粤浙苏鲁省级简称第 2 组易混淆字符O0I1l单独建模训练时强制增强对比 loss第 3 组新能源字符D纯电动、F插电混动该分组直接影响plate_rec.py中CTCLabelConverter的解码策略——解码时优先保留组内高置信度字符跨组跳跃需满足p 0.85阈值大幅降低0误识为O的概率。2.3 检测-识别流水线的耦合与解耦设计detect_plate.py是整个 pipeline 的调度中枢其核心逻辑如下# detect_plate.py 关键片段 def run_inference(img_path, model_yolo, model_ocr, model_color): # Step 1: YOLOv5 检测 results model_yolo(img_path) # 返回 xyxy 格式 bbox plates [] for *xyxy, conf, cls in results.xyxy[0]: # 遍历每个检测框 if conf 0.5: continue # 置信度过滤 crop_img crop_by_bbox(img_path, xyxy) # 裁剪车牌区域 # Step 2: CRNNLPRNet OCR ocr_result model_ocr(crop_img) # 返回字符序列及各字符概率 color_prob model_color(crop_img) # 返回蓝/黄/绿概率分布 # Step 3: 融合决策 final_plate fuse_ocr_color(ocr_result, color_prob) plates.append({ bbox: xyxy, text: final_plate, conf: conf.item(), color: torch.argmax(color_prob).item() }) return plates此设计实现解耦调试若 OCR 准确率低可单独运行plate_ocr_test.py --img-path ./imgs_test/1.jpg验证若检测漏检可--save-crop导出所有裁剪图人工检查若颜色分类错误plate_color_test.py提供混淆矩阵可视化。3. GUI 界面开发与多源输入适配实战3.1 V_GUI.py 中 Qt5 与 OpenCV 的零拷贝图像传输GUI 并非简单调用cv2.imshow()而是基于 PyQt5 构建响应式界面核心挑战在于避免 numpy array → QImage 的内存拷贝。V_GUI.py中VideoProcessor类采用QImage的__init__构造函数直接绑定 numpy 数据内存# V_GUI.py 关键代码 class VideoProcessor(QObject): frame_ready pyqtSignal(QImage) def __init__(self, cap): super().__init__() self.cap cap self.running False def process_frame(self): ret, frame self.cap.read() if not ret: return # BGR → RGB 转换但不创建新数组 rgb_frame cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 直接使用 rgb_frame.data 创建 QImage共享内存 h, w, ch rgb_frame.shape bytes_per_line ch * w qt_image QImage(rgb_frame.data, w, h, bytes_per_line, QImage.Format_RGB888) self.frame_ready.emit(qt_image) # 发送至 GUI 线程此写法使 1080p 视频处理延迟稳定在 32ms 内RTX 3060 测试远低于QPixmap.fromImage()的 80ms。3.2 三种输入源的统一接口封装GUI 支持图片/视频/摄像头切换其底层由main_GUI.py的InputSource类统一管理输入类型初始化方式关键参数注意事项图片文件InputSource(image, path./imgs_test/1.jpg)path必填自动缩放至 1280×720 保持宽高比视频文件InputSource(video, path./test.mp4)path,skip_frames2skip_frames控制抽帧率避免 CPU 过载摄像头InputSource(camera, device_id0)device_id,fps15fps限制采集帧率防止 GPU 显存溢出InputSource的read()方法返回(frame, is_valid)元组屏蔽底层差异。例如摄像头模式下若cap.read()失败则自动重连视频模式下到达末尾自动循环播放。3.3 实时检测结果的 GUI 渲染逻辑GUI.py中draw_results()函数负责叠加渲染其核心是动态调整字体大小与边框粗细以适配不同分辨率# GUI.py 关键渲染逻辑 def draw_results(frame, results): h, w frame.shape[:2] # 根据图像宽度动态计算字号和线宽 font_scale max(0.6, min(1.2, w / 1280)) # 宽度 1280 时为 1.0 line_thickness max(2, int(w / 640)) # 宽度 640 时为 2 for res in results: x1, y1, x2, y2 map(int, res[bbox]) # 绘制带阴影的文本提升可读性 cv2.putText(frame, res[text], (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (0,0,0), line_thickness2) cv2.putText(frame, res[text], (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (255,255,255), line_thickness) # 根据车牌颜色绘制不同边框 color_map {0: (255,0,0), 1: (0,255,255), 2: (0,255,0)} # 蓝/黄/绿 cv2.rectangle(frame, (x1,y1), (x2,y2), color_map[res[color]], line_thickness)此逻辑确保在 4K 显示器上文字清晰在手机投屏时边框不显过粗。4. 模型训练与部署全流程实操指南4.1 训练 YOLOv5s6 检测器的完整命令链训练需严格遵循train_yolo.py的参数约定以下为生产环境推荐命令# 在项目根目录执行 python train_yolo.py \ --data data/plate.yaml \ --cfg models/yolov5s6.yaml \ --weights weights/yolov5s.pt \ # 使用 COCO 预训练权重 --batch-size 16 \ --epochs 300 \ --name plate_yolov5s6_finetune \ --hyp config/hyp.finetune.yaml \ --cache-images \ --workers 4 \ --project runs/train--cache-images启用内存缓存加速数据加载需 32GB RAM--workers 4设置 DataLoader 进程数避免 I/O 瓶颈--name指定输出子目录便于多实验对比训练完成后最佳权重位于runs/train/plate_yolov5s6_finetune/weights/best.pt该文件已包含model.half()优化可直接用于推理。4.2 CRNN-LPRNet 联合训练的参数配置要点OCR 训练由train_ocr.py执行关键参数需匹配config/plate_rec.yaml# config/plate_rec.yaml 关键配置 dataset: train_root: ./dataset/train val_root: ./dataset/val img_height: 64 img_width: 256 batch_size: 64 num_workers: 4 model: backbone: crnn # 可选 crnn 或 lprnet use_stn: True # 是否启用空间变换网络 color_branch: True # 是否启用颜色分类分支 optimizer: type: adam lr: 0.001 weight_decay: 1e-4执行训练命令python train_ocr.py \ --config config/plate_rec.yaml \ --output_dir runs/ocr_crnn_stn \ --resume # 若从中断恢复填入 last.pth 路径注意dataset/目录需按train/imgs/xxx.jpgtrain/labels/xxx.txt结构组织xxx.txt内容为单行车牌字符串如京A12345无空格无标点。4.3 模型导出与跨平台部署方案项目提供三种部署格式适配不同场景格式生成命令适用场景加载方式PyTorch.ptpython export_pt.py --weights weights/plate_rec.pt开发调试、GPU 服务器torch.load()ONNXpython onnx/export_pth.py --weights weights/plate_rec.ptWebAssembly、TensorRT 部署onnxruntime.InferenceSession()TensorRTpython trt_model.py --onnx weights/plate_rec.onnxJetson 边缘设备trt.Runtime().deserialize_cuda_engine()其中 TensorRT 引擎生成需指定精度# 生成 FP16 引擎平衡速度与精度 python trt_model.py --onnx weights/plate_rec.onnx --fp16 # 生成 INT8 引擎需校准数据集 python trt_model.py --onnx weights/plate_rec.onnx --int8 --calib-dataset ./dataset/calib/5. 常见故障排查与性能调优技巧5.1 检测框漂移与 OCR 错误的根因定位法当出现“检测框偏移但 OCR 结果正确”或“OCR 识别错误但检测框精准”时按以下顺序排查验证检测框坐标系一致性detect_plate.py中crop_by_bbox()函数必须使用xyxy格式非xywh且 OpenCV 裁剪索引为[y1:y2, x1:x2]。常见错误是将x1,x2与y1,y2顺序颠倒。检查 OCR 输入图像预处理plate_rec.py的resize_normalize()函数要求输入为H×W×C但 OpenCV 读取为BGR需先cv2.cvtColor(img, cv2.COLOR_BGR2RGB)。遗漏此步会导致 CRNN 将蓝色误判为红色。分析 CTC 解码失败案例运行plate_ocr_test.py --debug --img-path ./imgs_test/1.jpg查看log/ctc_debug.txt中每帧的logits输出。若某字符位置logits[:, idx]全为负值说明该位置无有效特征需检查 STN 校正是否失效。5.2 GUI 卡顿与内存泄漏的针对性修复若 GUI 运行 10 分钟后明显卡顿大概率是QImage内存未释放。V_GUI.py中需确保frame_ready信号接收端及时清理# main_GUI.py 中的槽函数修正写法 def update_frame(self, qt_image): # 旧写法直接 self.label.setPixmap(QPixmap.fromImage(qt_image)) # 新写法显式删除旧 pixmap 避免内存累积 if hasattr(self, _current_pixmap) and self._current_pixmap: self._current_pixmap None # 触发垃圾回收 self._current_pixmap QPixmap.fromImage(qt_image) self.label.setPixmap(self._current_pixmap)同时在VideoProcessor的stop()方法中添加def stop(self): self.running False if hasattr(self, cap) and self.cap.isOpened(): self.cap.release() # 强制清空 QImage 缓存 self.frame_ready.disconnect() # 断开信号连接5.3 中文字符渲染异常的终极解决方案若 GUI 中中文显示为方块根源在于cv2.putText()不支持 Unicode。项目已提供cv_puttext.py替代方案但需确认字体路径# cv_puttext.py 中 font_path 必须指向系统中文字体 font_path /System/Library/Fonts/PingFang.ttc # macOS # font_path C:/Windows/Fonts/msyh.ttc # Windows # font_path /usr/share/fonts/truetype/wqy/wqy-microhei.ttc # Ubuntu验证方法运行python utils/cv_puttext.py若弹出窗口显示“京A12345”即成功。若失败用fc-list :langzhLinux/macOS或dir C:\Windows\Fonts\*.ttcWindows查找可用中文字体路径并更新font_path。提示cv_puttext.py的put_text_cn()函数内部使用PIL.ImageDraw绘制再转回 OpenCV 格式虽比原生cv2.putText()慢 3 倍但保证中文正确渲染——这是毕设演示不可妥协的底线。本文还有配套的精品资源点击获取
返回列表