恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

基于YOLOv5与CRNN的中文车牌识别系统:从检测到界面全流程解析

  • 首页
  • 资讯中心
  • /
  • 基于YOLOv5与CRNN的中文车牌识别系统:从检测到界面全流程解析

相关资讯

3 个阶段跑通 Open Notebook 全流程文献管理工作流 2026/9/1 21:01:47
51单片机8音键电子琴实战:定时器中断与频率换算精度控制 2026/9/1 21:01:47
低配电脑怎么跑 Switch 游戏:yuzu 模拟器完整使用手册 2026/9/1 21:01:47

最新资讯

AI编程协同工具Buzz AI:整合Claude Code与Codex实现高效开发
从酷家乐B卷看测试开发笔试:题型解析与避坑指南
测试开发校招笔试核心考点与备考路线全解析
第1章:Celery 术语全景与分布式任务架构原理
LVGL圆屏音频播放器开发实战:从裁剪到多任务通信
基于Hadoop MapReduce的电影用户性别预测:从数据清洗到朴素贝叶斯实战

今日推荐

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

本周热门

备战数据库管理工程师校招:索引、事务、备份恢复核心考点解析
数字电路时序基石:深入理解建立时间与保持时间
蓝桥杯国赛超声波测距机:从单片机原理到嵌入式系统实战

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

基于YOLOv5与CRNN的中文车牌识别系统:从检测到界面全流程解析

发布时间:2026/9/1 21:01:47
基于YOLOv5与CRNN的中文车牌识别系统:从检测到界面全流程解析 简介这是一套面向计算机专业本科生及初阶AI从业者的中文车牌识别毕业设计实践资源聚焦智能交通场景下的端到端车牌检测与识别任务。项目融合YOLOv5实现车牌区域精准定位结合CRNN完成中文字符序列识别并集成PyQt5构建交互式图形界面支持图片上传、实时识别与结果可视化适用于课程设计、大作业及毕业设计等实践环节。压缩包共109个文件含53个Python源码涵盖模型加载、推理、GUI逻辑、15个YAML配置文件定义网络结构与训练参数、2个预训练权重.pth/.pt、9张PNG/JPG测试图像及README说明文档整体大小7.66MB结构清晰、注释完整便于调试与二次开发。已有85人学习下载提供可直接运行的完整工程包含数据预处理脚本、模型推理封装模块及界面事件响应逻辑显著降低深度学习落地门槛。 做毕设时挑来选去最终敲定了“基于YOLOv5与CRNN的中文车牌识别系统”。这套系统从功能上拆其实就两块先用目标检测模型把“车牌在哪”找出来再用序列识别模型把“车牌是什么”读出来最后用PyQt5把整个流程封装成带图形界面的程序既能处理图片、视频也能连摄像头实时识别。今天我把这套系统的设计思路、环境搭建、模型训练、GUI整合和踩坑记录完整梳理一遍希望给正在选毕设题目、或者想快速搭建一套中文车牌识别落地项目的同学一个可直接复现的参考模板。1. 系统整体设计与技术选型1.1 为什么选“YOLOv5 CRNN”这套组合很多人在做车牌识别时第一反应是找一个端到端的模型比如开源的LPRNet或者HyperLPR。这类方案确实把“检测识别”合并成一条链路部署起来简单。但真到了毕设场景我建议还是把检测和识别拆成两个独立模块理由很实际模块独立出了问题好排查。检测框不准就调YOLOv5识别文字不准就调CRNN两者互不干扰。数据标注更灵活。检测只需要标注车牌框这一个类别识别只需要准备车牌字符图片分别训练数据集可以各自优化。答辩时好讲。老师问“系统怎么设计”时你可以清晰地说出数据流输入图像 - YOLOv5检测出车牌区域 - 裁剪出车牌 - CRNN识别出文本 - 界面展示结果逻辑链路非常完整这也正是“优秀毕业设计”评委最想看到的东西。检测端选YOLOv5的原因更直白生态成熟。YOLOv5的仓库维护好、文档多、预训练权重齐全而且yolov5s这个版本的模型文件只有14MB左右CPU也能跑训练难度适中非常适合学生机。替换成别的检测模型比如Faster R-CNN精度不一定更高但训练时间和部署复杂度都会明显上升。识别端用CRNN而不是简单的模板匹配则是因为中文车牌的不定长特性。车牌有蓝牌、绿牌新能源、黄牌、白牌警车字符数不是固定的普通分类网络处理不了这种长度变化的输出。CRNN的核心是“CNN提取特征 BiLSTM建模序列 CTC损失对齐”天然支持不定长序列识别。市面上很多车牌识别项目也是这个思路可靠性有保障。另外把检测和识别分开还有一个隐藏好处你可以分别对两个模块做效果评估。检测用mAP评估识别用字符准确率评估最后再算整体端到端准确率这样论文里的实验数据非常漂亮。1.2 图形界面选型PyQt5 而不是 Tkinter毕设要有界面一开始我犹豫过是用Python自带的Tkinter还是PyQt5。对比下来差距还是很明显的维度TkinterPyQt5控件丰富度基础控件美观度一般控件多支持QSS样式表定制多线程支持需要自己封装容易踩线程坑提供QThread、信号槽机制用起来顺手视频/图像显示需要配合PIL转换效率一般QLabel QPixmap就能高效显示打包发布pyinstaller兼容性好pyinstaller也能打包需要额外注意资源文件上手难度简单相对复杂但资料很多如果你只想跑通一个演示DEMO用Tkinter确实省事。但毕设要展示、要验收、要录演示视频界面观感和交互流畅度直接影响评分。PyQt5通过QSS可以做出接近软件产品的界面效果所以我最终选了PyQt5。实际用下来还有一点很重要PyQt5的QThread配合信号槽处理摄像头实时画面时非常好用。后面我会专门讲多线程设计这里先记住一个结论——识别算法不能写在界面主线程里否则画面会卡成PPT这是新手最容易犯的错误。1.3 系统整体流程设计系统整体流程可以这么理解输入来源单张图片、视频文件、摄像头实时画面。车牌检测YOLOv5检测出图像中所有目标为“plate”的边界框返回每个框的坐标和置信度。车牌裁剪与校正根据检测框裁出车牌区域如果车牌有倾斜可以用仿射变换做角度校正蓝牌和新能源绿牌底部有固定形状也可以用轮廓检测辅助校正。车牌识别将调整到固定尺寸的车牌图输入CRNN输出字符序列。结果展示在GUI中画检测框、显示识别文本、记录识别日志。这里第3步的倾斜校正是个加分项。实际场景中拍照角度千奇百怪车牌往往不是正正的矩形。YOLOv5输出的只是最小外接矩形如果车牌倾斜角度大直接用矩形图去识别会导致字符歪斜、准确率下降。我当时的做法是拿到检测框后先尝试在框内做边缘检测用cv2.minAreaRect找到车牌的四个角点再通过仿射变换转成正视角度的图。这个步骤对识别率的提升非常明显也能作为毕设中的创新点之一写进论文。2. 环境搭建与依赖准备2.1 开发环境说明先说我最终使用的环境组合已经在多台电脑上验证过稳定兼容操作系统Windows 10/11、Ubuntu 20.04 均可Python版本3.8不要用3.10以上PyTorch和部分依赖兼容性会出问题CUDA11.3NVIDIA显卡训练用没有显卡CPU也能跑只是速度慢PyTorch1.10.0其他依赖opencv-python、numpy、pandas、matplotlib、PyQt5、pytz等推荐使用Anaconda创建独立环境避免把系统Python弄乱。命令如下conda create -n plate python3.8 conda activate plate安装PyTorch时有NVIDIA显卡的建议使用CUDA版本pip install torch1.10.0 torchvision0.11.0 --index-url https://download.pytorch.org/whl/cu113没有显卡的同学可以安装CPU版本pip install torch1.10.0 torchvision0.11.0 --index-url https://download.pytorch.org/whl/cpu需要注意的是在Windows上安装PyTorch时尽量不要用默认的清华镜像源安装GPU版因为镜像是从PyPI同步的默认不带CUDA相关依赖。直接用PyTorch官方源更保险。装完之后可以跑一条命令验证python -c import torch; print(torch.__version__, torch.cuda.is_available())如果torch.cuda.is_available()返回True说明CUDA环境OK。2.2 YOLOv5与CRNN依赖安装YOLOv5的仓库克隆下来后官方提供了requirements.txt直接安装即可git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt使用国内网络环境如果直接安装速度慢可以给pip加国内镜像pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simpleCRNN这边需要的依赖其实很少主要就是PyTorch和OpenCV。我习惯把CRNN代码单独放一个目录比如crnn_plate/里面包含网络定义、数据集加载、训练脚本、推理脚本。整个项目结构大概是这样的plate_recognition_system/ ├── yolov5/ # YOLOv5检测端官方仓库 │ ├── weights/ │ └── runs/ ├── crnn_plate/ # CRNN识别端 │ ├── models/ │ ├── data/ │ ├── train.py │ └── predict.py ├── gui/ │ ├── main_window.py │ └── assets/ └── main.py # 程序入口这种“检测端用官方仓库、识别端独立实现”的结构最大好处是YOLOv5训练、推理都可以复用官方的最佳实践自己只需要专注在数据准备、模型调整和界面整合上开发速度会快很多。2.3 中文车牌数据集准备中文车牌数据集最常用的是CCPDChinese City Parking Dataset一共20万张左右带了详细的车型标注和车牌区域信息。但CCPD原始标注是JSON格式坐标系是“左上角点和右下角点”或“四角点”不是YOLO需要的“中心点宽高”格式所以需要做一次数据转换。YOLO格式的标签示例class x_center y_center width height其中坐标都是归一化到0~1之间的。一个简单的转换脚本逻辑如下import json import cv2 import numpy as np def ccpd_to_yolo_txt(json_path, img_path, txt_path): with open(json_path, r, encodingutf-8) as f: data json.load(f) # 假设data中有车牌四角点信息取最小外接矩形的中心点和宽高 pts np.array(data[points], dtypenp.float32) x_min, y_min pts.min(axis0) x_max, y_max pts.max(axis0) img cv2.imread(img_path) h, w img.shape[:2] x_center (x_min x_max) / 2.0 / w y_center (y_min y_max) / 2.0 / h box_w (x_max - x_min) / w box_h (y_max - y_min) / h with open(txt_path, w) as f: f.write(f0 {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}\n)如果只有少量数据需要标注也可以用labelImg手动标注导出YOLO格式这一步并不难。车牌检测只有一个类别所以class是固定的0。关于CRNN识别的训练数据我单独说一句公开的中文车牌识别数据集其实比较分散很多项目是直接自己从CCPD裁剪车牌图再配合字符级标注来训练CRNN。如果你时间紧也可以考虑先下载一些GitHub上已整理好的车牌识别数据集比如某些开源项目自带的车牌图片和label文件先跑通流程再自己扩充。3. YOLOv5车牌检测模块实现3.1 标注与预处理细节车牌的检测框有一个特点长宽比很固定。普通蓝牌是440mm×140mm长宽比大约3.14:1新能源绿牌更长一些是480mm×140mm比例大约3.4:1。这个先验知识可以用来做两点优化在检测后处理中用长宽比过滤掉明显不是车牌的误检框。在数据增强时不要做极端的“擦除”或“旋转”因为车牌是规则的矩形目标过度增强反而会让模型学到错误的形状特征。YOLOv5自带了Mosaic增强、随机仿射变换、HSV色域增强等策略默认配置已经很强了我基本没有额外加太多数据增强。唯一的建议是适当提高hsv_h、hsv_s、hsv_v的随机范围因为实际场景中车牌的亮度、颜色会受光照影响很大尤其蓝牌的亮度在不同光线下差别很大增强之后模型鲁棒性会好一些。训练集和验证集划分建议按9:1并保证验证集里包含不同天气、不同角度的样本这样评估结果才真实。目录结构如下dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── plate.yaml3.2 训练配置在YOLOv5目录下创建plate.yaml内容如下# plate.yaml train: dataset/images/train val: dataset/images/val nc: 1 names: [plate]然后启动训练python train.py --img 640 --batch 16 --epochs 120 --data plate.yaml --weights yolov5s.pt --device 0参数解释一下img 640训练输入尺寸。即使原始图片很大YOLOv5也会统一缩放到640×640检测效果和速度是比较平衡的。batch 16显存8GB的显卡用16比较稳如果是12GB可以调到32。epochs 120车牌检测属于简单任务120轮已经完全够用再多容易过拟合。weights yolov5s.pt使用官方COCO预训练权重做迁移学习收敛速度会快很多不要从零开始训练。训练过程中重点观察两个曲线一是train/box_loss有没有平稳下降二是metrics/mAP_0.5是否趋近于1。正常训练到60轮以后车牌检测的mAP_0.5基本可以达到0.98以上因为车牌目标特征明显检测难度不高。如果mAP一直上不去大概率是标注框坐标错误或者数据集划分有问题。3.3 模型导出与推理封装训练完成后在runs/train/exp/weights/目录下会生成best.pt和last.pt。做界面整合时我建议额外导出成TorchScript或者ONNX格式这样部署时不用依赖YOLOv5完整的训练代码加载速度也更快python export.py --weights runs/train/exp/weights/best.pt --include torchscript onnx导出后写一个检测工具类把YOLOv5的推理过程封装成一个简洁的函数import torch import cv2 class PlateDetector: def __init__(self, weightsruns/train/exp/weights/best.pt, conf_thres0.45): self.model torch.hub.load(ultralytics/yolov5, custom, pathweights) self.model.conf conf_thres # 置信度阈值 self.model.iou 0.5 # NMS IoU阈值 def detect(self, img_bgr): results self.model(img_bgr) # 返回所有检测框的坐标和置信度 boxes results.xyxy[0].cpu().numpy() return boxes注意torch.hub.load会从GitHub加载YOLOv5仓库如果网络环境下拉取失败可以直接把YOLOv5仓库放在本地改成self.model torch.hub.load(local/path/to/yolov5, custom, pathweights, sourcelocal)这也是我实际项目里使用的方式离线部署更稳定。4. CRNN中文车牌识别模块实现4.1 车牌字符集与标签编码CRNN之前先把中文车牌字符集确定下来。中国大陆车牌的一句话规则是第一个字符是省份汉字简称第二个字符是发牌机关字母后面是5或6位数字/字母组合。新能源绿牌是8位。所以字符集至少要包含这些内容汉字省份简称京、津、冀、晋、蒙、辽、吉、黑、沪、苏、浙、皖、闽、赣、鲁、豫、鄂、湘、粤、桂、琼、渝、川、贵、云、藏、陕、甘、青、宁、新加上警、学、挂、港、澳、台等特殊字。大写字母去掉I和O因为容易和数字1、0混淆实际车牌也不使用。数字0-9。在代码里维护一个字符列表CHARS [ 京, 津, 冀, 晋, 蒙, 辽, 吉, 黑, 沪, 苏, 浙, 皖, 闽, 赣, 鲁, 豫, 鄂, 湘, 粤, 桂, 琼, 渝, 川, 贵, 云, 藏, 陕, 甘, 青, 宁, 新, 警, 学, 挂, A, B, C, D, E, F, G, H, J, K, L, M, N, P, Q, R, S, T, U, V, W, X, Y, Z, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ] CHAR2IDX {c: i for i, c in enumerate(CHARS)} IDX2CHAR {i: c for i, c in enumerate(CHARS)}标签编码时把车牌字符串逐个字符映射为索引序列比如“京A12345”变成 [0, 31, 43, 44, 45, 46, 47]。训练时每个batch内的标签长度可能不同需要做padding并且保存每张样本的真实长度信息方便CTC计算loss。4.2 CRNN网络结构与CTC原理CRNN的结构可以概括为三个部分卷积层、循环层、转录层。卷积层用CNN backbone提取图像特征。输入通常是H32的灰度图或三通道图经过若干卷积和池化后输出的特征图是“宽 W、高 1、通道数 C”的序列相当于把图像按列切片每一列作为一个时间步的特征向量。循环层用双向LSTMBiLSTM对特征序列建模。因为车牌字符之间存在顺序关系BiLSTM可以同时利用前后文信息比单纯的CNN更有利于字符序列识别。转录层将BiLSTM输出的每个时间步映射成字符分布再用CTC loss训练推理时通过CTC解码贪心搜索或束搜索得到最终文本。我给的网络定义是去掉权值共享细节的简化版方便看懂结构import torch.nn as nn class CRNN(nn.Module): def __init__(self, num_classes, hidden_size256): super(CRNN, self).__init__() # CNN特征提取层输入 1x32xW self.cnn nn.Sequential( nn.Conv2d(1, 64, 3, padding1), nn.ReLU(), nn.MaxPool2d(2, 2), nn.Conv2d(64, 128, 3, padding1), nn.ReLU(), nn.MaxPool2d(2, 2), nn.Conv2d(128, 256, 3, padding1), nn.ReLU(), nn.BatchNorm2d(256), nn.Conv2d(256, 256, 3, padding1), nn.ReLU(), nn.MaxPool2d((2, 1)), # 高度方向压成1宽度尽量保留 nn.Conv2d(256, 512, 3, padding1), nn.ReLU(), nn.BatchNorm2d(512), ) # 进入BiLSTM前做维度转换W 输入宽度/4左右 self.lstm nn.LSTM(512, hidden_size, num_layers2, bidirectionalTrue) self.fc nn.Linear(hidden_size * 2, num_classes) def forward(self, x): x self.cnn(x) # (N, 512, 1, W) x x.squeeze(2) # (N, 512, W) x x.permute(2, 0, 1) # (W, N, 512) 变成序列 out, _ self.lstm(x) # (W, N, 2*hidden_size) seq_len, batch_size, _ out.size() out self.fc(out.reshape(-1, out.size(2))) out out.view(seq_len, batch_size, -1) return out # 每个时间步输出各类别概率CTC的核心思想是解决“预测序列长度和真实标签长度不一致”的对齐问题。通俗解释模型输出序列里可以有很多空白符blank和重复字符CTC允许这些冗余存在最终在解码时把重复和blank去掉得到真正的车牌文本。比如模型输出“京A1112345”CTC解码后会先合并相同字符变成“京A12345”最后剔除blank得到“京A12345”。这也是为什么CRNN不需要预对齐标签的原因。CTC的loss在PyTorch里直接用torch.nn.CTCLoss不过要注意它的参数坑input是(T, N, C)target是(N, S)input_lengths和target_lengths要各自指定。新手最常见的问题就是维度顺序搞反导致loss直接报错。4.3 训练CRNN的关键参数训练CRNN时我把车牌图统一resize到32 x 160高32宽160并转为灰度图。高度取32是因为CRNN的CNN下采样倍数正好可以把高度压到1宽度160是经验值能覆盖大多数车牌的长度比例。如果车牌比较长宽可以到200甚至240但受限于BiLSTM时间步数不能随意乱改。训练脚本里的关键超参python train.py --batch_size 64 --lr 0.001 --epochs 60 --cuda优化器用Adam初始学习率0.001配合StepLR每20轮乘0.1。CTC loss正常的话会在前几轮快速下降从几十降到个位数后面缓慢降低到2以内。如果loss一直不降优先检查字符集、标签索引是否对得上再检查原始图片方向是否统一。推理解码我用的是最简单的贪心解码import torch def decode_greedy(output): # output: (T, N, C) 或 (T, C) pred output.argmax(dim-1).cpu().numpy() result [] prev -1 for p in pred: if p ! prev and p ! 0: # 假设0是blank result.append(IDX2CHAR[p - 1]) # 索引从1开始映射字符 prev p return .join(result)有一点要注意空白符blank在字符集中的索引位置要提前约定好比如我设定字符集前面加一个第0位是blank这样映射才稳定。之前有同学把blank放在字符集最后面结果CTC的blank0参数没改解码结果全乱了。4.4 车牌识别后处理CRNN输出后还需要做后处理不能直接相信解码结果。原因很简单模型可能在字符边界处出错比如把数字“0”识别成字母“O”或“D”。因此我在后处理里加了一道规则校验字符串长度必须是7位蓝牌或8位新能源绿牌长度不对直接标记为“识别失败”或者用置信度自动选择模型二次识别。第1位必须是汉字字符第2位必须是字母后面必须是字母/数字组合。如果某个字符在字符集中高频出现冲突比如“B”和“8”、“S”和“5”可以在置信度不高时做人工纠错。代码大致是def post_process(plate_str): plate_str plate_str.strip().replace( , ) if len(plate_str) not in (7, 8): return None if plate_str[0] not in PROVINCE_CHARS: return None if plate_str[1] not in ALPHABETS: return None if not plate_str[2:].isalnum(): return None return plate_str这一步看起来不起眼但实际能把整体识别准确率提高不少。因为CRNN是序列模型偶尔会多输出一个字符或漏掉一个字符规则校验能兜底。5. 图形界面整合实战5.1 GUI整体布局设计主界面我用PyQt5实现整体分三个区域左侧大区域视频/图片显示区占界面三分之二用于显示原图和检测框。右侧区域识别结果列表显示每一帧识别出的车牌文本、置信度、时间。顶部工具栏包括打开图片、打开视频、打开摄像头、模型配置、阈值设置等按钮。底部状态栏显示当前帧率、系统运行状态、GPU使用情况等。布局参考代码from PyQt5.QtWidgets import QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle(基于YOLOv5与CRNN的中文车牌识别系统) self.setMinimumSize(1000, 600) central QWidget() self.setCentralWidget(central) layout QHBoxLayout(central) # 左侧显示区 self.video_label QLabel(视频显示区) self.video_label.setStyleSheet(background-color: #222; color: white;) layout.addWidget(self.video_label, 2) # 右侧结果区 right_panel QVBoxLayout() self.result_label QLabel(识别结果) right_panel.addWidget(self.result_label) # ...按钮与控制项 layout.addLayout(right_panel, 1)画检测框时我用的是OpenCV在每一帧上绘制矩形和文字然后转成QImage再显示到QLabel上def cv2_to_qimage(self, img_bgr): rgb cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) h, w, ch rgb.shape bytes_per_line ch * w qimg QImage(rgb.data, w, h, bytes_per_line, QImage.Format_RGB888) return qimg.scaled(self.video_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)5.2 多线程设计与视频流处理这是整个GUI工程最容易踩坑的地方。如果直接在PyQt5的主线程里写cap.read()和模型推理视频会一帧一帧地卡界面也无法响应按钮点击。因为推理本身是耗时操作必须放到子线程。我的方案是三个线程协作采集线程循环读取图片/视频/摄像头把原始帧放进队列frame_queue。识别线程从队列取帧调用检测和识别模型把带标注的结果放进结果队列。主界面线程只负责定时从结果队列取最新帧并刷新显示。实现上可以用PyQt5的QThread或者更简单的threading.Thread加queue.Queue我倾向于后者逻辑更清晰。核心代码如下import threading import queue import time class CameraThread(threading.Thread): def __init__(self, source0): super().__init__() self.cap cv2.VideoCapture(source) self.frame_queue queue.Queue(maxsize2) self.running True def run(self): while self.running: ret, frame self.cap.read() if not ret: break if self.frame_queue.full(): try: self.frame_queue.get_nowait() except queue.Empty: pass self.frame_queue.put(frame) time.sleep(0.03)这里用maxsize2加“丢老帧”的策略是为了避免识别速度跟不上采集速度时队列堆积导致画面延迟越来越大。实测下来摄像头画面延迟基本能控制在200ms以内。识别线程的逻辑类似从帧队列取帧调用detect()和recognize()再把结果通过信号发到主界面。这里有个细节如果帧率太高识别线程CPU占用会很高可以加一个简单的限速逻辑比如每帧之间sleep 0.02秒或者只在画面变化明显时才识别。5.3 核心识别流程串联界面整合时我写了两个工具类分别封装检测和识别模型main_window.py里只需要调用它们class RecognitionSystem: def __init__(self, detector_weights, recog_weights): self.detector PlateDetector(detector_weights) self.recognizer PlateRecognizer(recog_weights) def process_frame(self, frame): dets self.detector.detect(frame) plates [] for d in dets: x1, y1, x2, y2, conf, cls d[:6] if conf 0.5: continue crop frame[int(y1):int(y2), int(x1):int(x2)] text self.recognizer.recognize(crop) if text: plates.append((text, float(conf), (int(x1), int(y1), int(x2), int(y2)))) return platesPlateRecognizer的recognize方法里做的事就是读取车牌图 - 灰度化 - resize到32x160- 归一化 - 喂给CRNN - 解码 - 后处理。识别速度在GPU上大概每张10ms在CPU上约50ms整体流程可以接受。按钮事件这里就不全部贴代码了核心就一句def on_open_video(self): path, _ QFileDialog.getOpenFileName(self, 选择视频, , MP4 Files (*.mp4);;AVI Files (*.avi)) if path: self.camera_thread CameraThread(path) self.camera_thread.start()关闭窗口时记得释放摄像头线程否则程序关不掉def closeEvent(self, event): if hasattr(self, camera_thread): self.camera_thread.running False self.camera_thread.cap.release() event.accept()6. 常见问题与排查技巧6.1 常见问题速查表现象可能原因解决办法检测框有多个重叠框NMS的IoU阈值设置偏低或置信度阈值偏低把iou调到0.45~0.5conf调到0.4以上检测不到车牌训练数据集太单一、目标太小调整img到640以上增加远程/小目标样本显存不够batch太大或图片分辨率太高减小batch开启--amp混合精度CRNN loss不下降标签索引错位、blank位置不一致检查字符集映射、检查CTCLoss参数识别结果多字/少字车牌倾斜过大、图片宽高比失真增加仿射校正调整resize宽度到200界面卡顿推理跑在主线程、队列堆积用QThread/threading子线程处理丢老帧初始化时torch.cuda不可用PyTorch CUDA版本与显卡驱动不匹配使用PyTorch官方cu113/cu118对应版本YOLOv5加载时访问GitHub失败网络受限使用本地仓库路径sourcelocal6.2 几条独家避坑经验第一不要一开始就追求高精度。第一版系统先把整条链路跑通再用小数据集训练哪怕识别准确率只有70%也能在答辩演示时展示完整的流程。之后逐步增加训练数据、调整参数效果会稳步提升。很多同学一开始就想着把所有公开数据集都下载下来训练结果数据准备就花了两周本末倒置。第二车牌检测和识别两套模型的训练数据最好保持一致来源。检测模型训练数据集里的车牌照片可以直接裁剪下来作为CRNN的训练数据。这样可以保证识别模型看到的图像风格和检测模型输出的裁剪图基本一致端到端准确率会高很多。如果数据来源差异大比如检测模型在停车场数据上训练、识别模型在新闻图片上训练实际使用时识别效果会明显下降。第三关于GPU显存不足的情况。我用的中低端显卡8GB显存训练YOLOv5时batch调到32会爆显存但20稳得很。如果实在没显卡CPU训练也不是不行只是YOLOv5训练120轮可能要一天以上。建议用官方预训练权重加迁移学习大幅缩短训练时间。第四CCPD数据集本身的图片有很多是带有晃动的、倾斜大的车型场景直接用来训练CRNN会有一定挑战。可以考虑用一个开源的“车牌识别图像增强”策略随机加一点透视变换和高斯模糊模拟真实场景的退化模型会更健壮。写在最后的一点心得复盘这个项目我最想强调的就是“模块化”这三个字。YOLOv5检测车牌、CRNN识别车牌、PyQt5做界面三个模块可以并行推进也可以各自独立测试。等你真正把检测模型改成新的数据集、或者把CRNN换成语音模型时会发现这种“三段式”解耦设计带来的便利远超预期。如果你也打算拿这个题目做毕设我的建议是先按下面的顺序排优先级先把YOLOv5检测跑通、能框出车牌然后拿固定裁剪的车牌图片把CRNN识别跑通、能输出文本最后再缝上PyQt5界面。每一步都可以用现成的模型快速验证避免“一锅乱炖”导致哪里出了问题都不知道好在哪。等整个链路通了以后再回头优化数据、调超参、加倾斜校正分数自然就上来了。这套系统后续还可以往ONNX部署、TensorRT加速、嵌入式设备落地这几个方向扩展这就是另一个话题了。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号