尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

yolov8无人机交通监控实战:从数据集标注到模型训练部署全流程

yolov8无人机交通监控实战:从数据集标注到模型训练部署全流程 简介基于YOLOv8的无人机交通监控设计项目代码主要面向深度学习与图像识别方向的毕业设计、课程设计及期末大作业。项目能够实时识别与跟踪道路上的车辆和行人并集成车牌检测、速度估计、字符分割等功能模块。压缩包共27个文件以十二个Python代码文件为主体同时包含九个编译缓存文件、配置文件、使用说明以及少量示例图片整体大小仅94KB结构按主程序、配置、工具和资源目录划分简洁紧凑且便于二次开发。已有46人浏览学习适合作为同类智能交通监控项目的参考资料。从项目内部结构看车辆检测、车牌识别、速度估算等脚本协同工作配合依赖列表与使用文档可帮助快速搭建环境并理解整条算法流程对课程设计或毕业设计的方案实现具有很好的借鉴价值。1. 无人机交通监控这块硬骨头yolov8 为什么能啃下来一辆车在无人机俯视画面里往往只有几十个像素树影一挡就可能让目标消失两三帧。无人机交通监控的难点从来不在“能不能看见路”而在怎么从一片密密麻麻的俯视画面里把小车、货车、行人稳定捞出来。yolov8 是这两年做这件事性价比最高的检测器之一精度和速度的平衡在 GTX1660Ti 这类中等显卡上就能跑起来也适合在 RK3588 这类边缘设备上做部署。这份资源把 yolov8 跑通无人机交通监控的完整链条——环境搭建、数据集标注、模型训练、调参、常见坑、部署导出——整理成了一套可以直接照着跟做的流程。想拿它做毕业设计、课程设计或期末大作业的人照着一路做完就能交出一份完整可演示的结果。2. 把地基打牢yolov8 选型逻辑与 Ubuntu/Windows 环境搭建2.1 为什么是 yolov8先看懂网络结构和五个尺寸开始之前我习惯先交代一句选型逻辑因为很多人在环境上翻车本质是没搞懂自己手里的显卡和数据量到底适合哪个模型。yolov8 相比前代最核心的变化是三点。第一主干网络用了 C2f 结构相当于把不同层级的特征反复融合对小车、行人这种小目标更友好第二检测头改成了 Anchor-Free 解耦结构也就是不再预设一堆先验框去“猜”而是直接回归目标中心点和宽高收敛更稳第三训练阶段自带 Mosaic 等数据增强数据量不够的时候能硬凑出一些多样性。这三个特性叠加起来恰好命中无人机交通监控的两个痛点目标小、样本变化大。然后是模型尺寸怎么选。yolov8 官方给了 n、s、m、l、x 五个档位很多课设新手一上来就选 x结果显存直接爆炸。我按自己的经验给个选型参照模型体积/显存场景匹配yolov8n最小CPU 能跑快速验证流程、边缘设备部署yolov8s6G 显存可用课设/毕设主力档位yolov8m中高显存追求精度且有独显yolov8l / x高显存数据量大、对 mAP 有硬指标这套项目资源里默认按 yolov8s 来组织训练流程因为这个档位在 1660Ti、3060 这类学生最常见的显卡上能在 batch16 下稳定训练速度也不会把人拖崩溃。你要是机器比较老先换成 yolov8n 跑通再回头换 s 收精度。2.2 环境搭建Ubuntu 20.04 与 Windows 双方案先说结论Ubuntu 20.04 是 yolov8 最舒服的跑法但不是唯一选择。Windows 下用 conda 也一样能跑通只是个别依赖善于折腾人。我一般建议新手直接上 conda因为虚拟环境隔离能救回来一半以上的依赖冲突。conda create -n yolo python3.9 -y conda activate yolo pip install ultralytics -i https://pypi.tuna.tsinghua.edu.cn/simple这一段逻辑很直接创建一个干净的 Python 3.9 环境然后安装 ultralytics 这个包。python3.9 是一个比较稳的选择3.10 以上在某些旧版 torch 下有兼容问题3.8 又偏老ultralytics 包会把 yolo 的命令行工具和后端推理一起装进来。后面那个-i参数是指定 PyPI 镜像源国内网络环境下载速度会快很多注意如果你在公司内网或有自己的 pip 源可以替换掉这段。如果你有 NVIDIA 显卡还要让 PyTorch 用上 GPU这一步往往才是真正卡人的地方pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118这里cu118是 CUDA 11.8 对应的预编译 wheel。需要先确认你的显卡驱动支持哪个 CUDA 版本用nvidia-smi看一下右上角。驱动支持的版本号大于等于 11.8 就行不用强制让 PyTorch 和驱动完全一致。没有独立显卡的话直接把 ultralytics 装完yolov8n 在 CPU 上也能跑推理只是训练要慢很多这个在 2.3 会说兜底方案。2.3 验证环境跑通官方预训练 demo环境装完别急着训先拿一张带车的俯视图跑一次预训练权重确认整条链路是通的。这一步能帮你把“环境问题”和“模型问题”切分开后面训练报错你就知道排查方向。yolo detect predict modelyolov8s.pt sourcetest.jpg conf0.25这条命令的意思是用 yolov8s 的官方预训练权重对 test.jpg 做目标检测conf0.25表示只保留置信度高于 25% 的框。第一次跑会自动下载权重到当前目录如果下载慢可以从 ultralytics 的 release 页面手动下好丢进目录里。跑完会在 runs/detect/predict 里生成带框的图。用 Python API 也是一样我习惯写成这样方便后面接摄像头和视频from ultralytics import YOLO model YOLO(yolov8s.pt) results model.predict(sourcetest.jpg, conf0.25, saveTrue) boxes results[0].boxes print(boxes.xyxy, boxes.cls, boxes.conf)逻辑说明YOLO 对象加载一次权重predict 方法返回一个结果列表每个元素对应一张图.boxes.xyxy是每个检测框的四角坐标.cls是类别 id.conf是置信度。你只需要从那之后把所有关心的问题都挂在 results 对象上查。如果你的机器是 GTX1660Ti这个 demo 跑起来毫无压力显存占用不到 2G。如果你手里只有 CPU把 model 换成yolov8n.pt再跑一次能出结果就说明基础链路没问题。CPU 也能凑合做毕设就是把预期管理好n 档训练 100 epochs用几百张图时间可能以天计想快就得砍 imgsz、降 epochs具体在第四章参数部分展开讲。3. 数据是这行的大半条命标注、清洗与数据集划分实战3.1 航拍数据从哪来公开数据集与自采无人机交通监控和普通路测画面的最大区别在于视角。普通数据集里车是从侧面拍的特征是“车头车尾”无人机画像是从上往下看的特征是“车顶车影”。所以拿自动驾驶路测数据集硬训放到航拍视角上效果会打骨折。数据集来源我一般走三条路。第一条是公开航拍数据集比如 VisDrone本身就是无人机视角类别里有 car、bus、truck、pedestrian正好对口交通监控缺点是标注质量参差有些标签你需要自己筛。第二条是自采用大疆入门款在路口飞一圈录 1080p 视频再按帧抽图这样做出来的数据跟你最终的运行场景最贴近。第三条是针对毕设场景的取巧方案如果学校有开放的无人机巡检项目素材或者网上有公开的车辆航拍视频抽帧之后自己标注也能凑到几百张可用数据。无论哪条路我建议起步至少 800 到 1500 张图每张图里目标数量不要太少。航拍图中背景占比高如果每张只有一辆车模型很容易学成“找马路”而不是“找车”这是个很常见的隐蔽问题。3.2 labelme 标注实操从打框到 yolov8 能吃的 txt标注工具我推 labelme理由就一个JSON 格式自带坐标和图片尺寸不会被编码方式坑到。yolov8 要的标注格式是纯文本每行一个目标格式是类别id 中心点x 中心点y 宽度 高度所有值都归一化到 0~1。labelme 生成的 JSON 必须自己写脚本转换。import json import os # labelme 导出的 json 所在目录 src_dir labelme_jsons # yolov8 数据集 labels 输出目录 dst_dir dataset/labels/train # 类别必须和 data.yaml 里的 names 顺序完全一致 class_map {car: 0, bus: 1, truck: 2, person: 3} os.makedirs(dst_dir, exist_okTrue) for fname in os.listdir(src_dir): if not fname.endswith(.json): continue with open(os.path.join(src_dir, fname), encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] out_lines [] for shape in data[shapes]: label shape[label] if label not in class_map: continue points shape[points] x1, y1 points[0] x2, y2 points[1] x_c (x1 x2) / 2 / img_w y_c (y1 y2) / 2 / img_h w abs(x2 - x1) / img_w h abs(y2 - y1) / img_h out_lines.append(f{class_map[label]} {x_c:.6f} {y_c:.6f} {w:.6f} {h:.6f}) out_name os.path.splitext(fname)[0] .txt with open(os.path.join(dst_dir, out_name), w, encodingutf-8) as f: f.write(\n.join(out_lines))逻辑说明labelme 用矩形框标注时points里存的是矩形对角线的两个端点所以我用两个点的坐标取平均算中心点再取绝对差算宽高最后全部除以图片宽高做归一化。这样转换出的 txt 文件不会跟具体的输入尺寸绑死训练时不管 imgsz 设成多少都不会出坐标错位的问题。参数说明class_map是你自己定的类别表这里把 car、bus、truck、person 映射成 0、1、2、3这个映射必须和后面 data.yaml 里的names顺序完全一致否则类别全乱。abs()不能省因为标注时对角点可能从右下往左上拖不信你可以测试一次。3.3 数据划分与清洗别让模型“偏科”标注完之后的划分看起来是小事实际上很多人在这里翻车。最常见的错误是把同一段视频相邻帧同时放进 train 和 val结果验证集和训练集高度相似mAP 虚高换到真实场景立刻现原形。我习惯用下面这个方式做随机划分并固定随机种子保证可复现import os import random image_dir dataset/images label_dir dataset/labels train_ratio 0.8 val_ratio 0.1 imgs [f for f in os.listdir(image_dir) if f.endswith(.jpg)] random.seed(42) random.shuffle(imgs) train_n int(len(imgs) * train_ratio) val_n int(len(imgs) * val_ratio) sets { train: imgs[:train_n], val: imgs[train_n:train_n val_n], test: imgs[train_n val_n:] } for split, files in sets.items(): os.makedirs(fdataset/{split}/images, exist_okTrue) os.makedirs(fdataset/{split}/labels, exist_okTrue) for img in files: os.system(fcp {image_dir}/{img} dataset/{split}/images/) label_file img.replace(.jpg, .txt) if os.path.exists(os.path.join(label_dir, label_file)): os.system(fcp {label_dir}/{label_file} dataset/{split}/labels/)逻辑说明先读全部图片shuffle 打乱顺序按 8:1:1 切出 train、val、test然后把图片和对应的 txt 标注同步拷贝到新目录。这里用随机划分而不是按时间戳划分对课设级数据量更实用。划分之后一定要做一次清洗我每次都检查三件事第一有没有空标注文件训练时读到空 txt 会直接报错或产生 NaN第二有没有坐标越界的框比如 w 或 h 算出来大于 1说明标注或转换有问题第三每类目标数量是否均衡如果 car 有 2000 个、truck 只有 30 个truck 基本学不出来要么补标注要么把 truck 并回 car 类。4. 把模型训出来训练参数逐项拆解与损失曲线判读4.1 data.yaml 与训练命令训练参数到底是什么意思训练前先要准备一个 data.yaml它的作用是把数据目录和类别定义一次性告诉训练器。项目资源里已经把这个文件帮你放好了你只需要按自己的目录改三处路径。path: dataset train: train/images val: val/images test: test/images nc: 4 names: [car, bus, truck, person]注意这里nc和names必须与 3.2 里的 class_map 完全吻合。很多人的 mAP 是 0问题的根源就是这里顺序对不上。然后看训练命令。以下是我在资源里给的标准训练配置逐项说明含义yolo train \ modelyolov8s.pt \ datatraffic.yaml \ epochs100 \ imgsz640 \ batch16 \ device0 \ patience20 \ optimizerAdamW \ projectruns/train \ nameuav_traffic参数逐个说modelyolov8s.pt加载官方预训练权重做迁移学习这比从头训收敛快非常多一定要用data指向刚刚的 yamlepochs100对几百张图来说够了课设跑 100 epochs 大约几小时imgsz640是训练输入分辨率航拍小目标多有条件优先试 832但显存不够时就退回 640batch16是每轮塞进去 16 张图GTX1660Ti 6G 显存配 imgsz640 稳定跑再往上就危险patience20是早停机制验证集连续 20 轮不提升就自动停能省时间optimizerAdamW是 yolov8 默认推荐比 SGD 收敛稳小数据量下表现更友好device0指定用第一块 GPUCPU 环境改成devicecpu。还有个容易被忽略的点是project 和 name。这两个参数决定训练结果输出到哪个目录不写的话默认放到 runs/train/exp 这种文件夹里多跑几次会出现 exp1、exp2 层层叠叠找 weight 的时候很乱。写成runs/train/uav_traffic权重就在runs/train/uav_traffic/weights/best.pt清晰。4.2 损失曲线怎么看early stop 和过拟合的判断训练过程会生成 results.png 和 results.csv很多人只看最后一个 mAP 数字其实中间过程里藏着大量信息。yolov8 的 results.png 里主要有 box_loss、cls_loss、dfl_loss 三种损失以及 precision、recall、mAP50、mAP50-95 四条指标。我判断一个模型学没学歪关键看三点。第一train 的 box_loss 和 val 的 box_loss 同时下降说明模型在正常收敛如果 train 一直在降、val 曲线在某个点掉头向上这是典型的过拟合信号加大数据增强或者砍 epochs。第二mAP50 和 mAP50-95 之间的差距。mAP50 高但 50-95 上不去说明模型只学到了“大概能框住”的水平框的定位精度不够这对航拍小目标很致命可以靠提高 imgsz 或加小目标检测层缓解。第三观察 early stop。如果 100 epoch 在 30 多轮就被 patience 掐断不要慌这通常代表模型已经收敛真正该注意的是“被掐断时 val loss 还在持续下降”这说明 patience 给太小了改成 30 再训。损失曲线这种东西很多第一次跑的人看半天也感受不到区别我第一天也被折磨得够呛。我的经验是只看一排文件——results.png里右下角的 mAP50 曲线只要它是整体向上、尾部平滑基本就能用了。非要较真就把 resources 里给的runs/train/uav_traffic/results.png当参照跟你自己训的图对比。4.3 航拍小目标改进方向协调注意力与 P2 检测头如果你的验证集 mAP50 已经到 60 以上但实测俯视画面里小车还是漏那就是典型的小目标问题。yolov8 默认的检测头对 32 倍下采样的特征图更敏感一辆车只有 20×20 像素的时候特征图早就把它抹没了。资源里给了两个改进思路我建议不要一上来就全上一个一个试。第一个是加 P2 小目标检测层让模型在更高分辨率的特征图上做检测代价是显存压力变大、训练变慢第二个是嵌入注意力机制常见做法是把协调注意力CoordAtt加进 C2f 模块里让模型更关注小目标的空间位置。这两个改动都要动网络结构代码对课设来说属于加分项。我通常在 baseline 完全跑通、各项指标都看过之后才会考虑动这一层。这里必须劝一句改进有风险改动越深出问题的概率越大。毕设答辩看的是完整闭环不是单纯 mAP 数字。先把标准流程做到 90 分再去碰改进是性价比最高的策略。5. 常见问题与避坑记录环境、显存与训练的翻车实录5.1 环境与显存三件高频事故现象一训练刚启动就报CUDA error: no kernel image is available for execution on the device前面import torch都正常但一上 GPU 就死。原因PyTorch 编译时的 CUDA 算力和你显卡的算力不匹配。比如装了 cu118 版本的 torch在旧架构显卡上就可能找不到可执行内核。这个报错最迷惑人的地方在于PyTorch 本身能 import类型检查也能过直到真正跑张量运算才炸出来。解决把 torch 换成和你显卡算力匹配的版本。先跑nvidia-smi看驱动支持的最高 CUDA 版本再用 Pytorch 官方 wheel 的cu121或cu118重装。注意重装前后必须pip uninstall torch torchvision再装直接覆盖装经常会残留旧包。Conda 用户更省心的做法是用conda install pytorch pytorch-cuda11.8 -c pytorch让 conda 替你做算力匹配。现象二训练到一半爆RuntimeError: CUDA out of memory进程直接挂掉。原因不是显存不够就是你 batch 或 imgsz 开大了。很多人看到网上教程写 batch32、imgsz640没想过那是 24G 显存的配置1690Ti 直接当场去世。另外 Mosaic 增强会让训练时单张图的显存消耗变大这个也是隐形的显存杀手。解决把 batch 降到 8 或 4imgsz 降到 640 以下能解决 80% 的情况。还有一种办法是用梯度累积替代大 batch把 batch16 拆成 batch4、积累 4 步再更新一次权重效果近似但显存压力小很多。如果这两个都试了还是 OOM检查是不是开了太多并行程序关掉浏览器和桌面环境有时候能救回来。现象三训练时 GPU 利用率忽高忽低任务管理器看到 CPU 被拉满一个 epoch 跑到天荒地老。原因数据加载瓶颈。yolov8 默认 dataloader 的num_workers在部分环境下可能是 0图片解码全压在主进程上GPU 只能干等着。解决训练命令里加workers8Windows 下建议 4再加大一点prefetch_factor。如果跑在机械硬盘上把数据集挪到 SSD。这一步是“看起来无关紧要但实际效果巨大”的优化有时能把 epoch 时间砍掉一半。血泪经验我第二次跑项目时因为这个多耗了一整晚。5.2 数据与训练四个最阴间的错误现象一训练全程收敛正常loss 在降但 val 的 mAP50 一直是 0。原因十有八九是类别 id 错位。标注 txt 里第一列是 0、1、2、3但 data.yaml 的names顺序和训练时读到的 class_map 对不上模型学的类别和验证算的类别压根不是一回事。还有一种可能是你把nc写成 5但标注里只有 0~3某些类别完全没有样本mAP 就会按 0 算。解决训练前写一个脚本统计 train 和 val 两个目录下所有 txt 的类别分布确认每个类 id 都在nc范围内并且每类样本数大于 30。这个检查是玄学重灾区跑一次只要三秒但它能救命。现象二loss 正常下降但画出来的预测框全是歪的宽度高度乱飞。原因json 转 txt 时没有按图片尺寸归一化或者是读取imageWidth时拿错字段labelme 有的旧版本存的是imageData加分离的宽高字段。如果有个别图片的标注 txt 里 w 大于 1 或 h 大于 1这一张图就会把整个训练过程带偏。解决转换脚本里统一读data[imageWidth]不要从 fileName 猜转换完成后扫一遍 txt把 w 或 h 大于 1.0 的过滤出来人工复查。我现在的习惯是标注完先跑扫描脚本再训等于给数据加一道安检。现象三训练到一半 loss 出现 NaN或者直接崩掉。原因最常见是学习率太大。特别是用 SGD 而非 AdamW 时数据量小、lr 默认值偏高就容易炸。其次是有空标注 txt一张图没有目标但 dataloader 还是会读它导致 loss 计算出现除零或空值。解决先检查空 txt把空文件删掉或补标注然后把 optimizer 切回 AdamW或者在yolo train加lr00.001显式压低初始学习率。顺序一定要是“先查数据再调参”多数时候问题根本不在超参。现象四CPU 环境下训练慢得让人怀疑人生100 epochs 完全跑不动最后用 10 epochs 交差模型效果自然差。原因CPU 跑 yolov8s 本身就是超高难度动作资源默认是给 GPU 设计的。很多人拿到后直接照抄命令没用小的模型档位也没有降分辨率时间上完全不可行。解决CPU 兜底方案我反复验证过把命令改成yolov8n.pt imgsz416 batch8 epochs30时间能压缩到几小时量级。虽然精度和 s 档有差距但至少能交一个流程完整的毕设答辩时把“硬件受限”如实讲出来老师是认这个逻辑的。6. 部署与进阶验证导出 ONNX、移植边缘设备与推理核验训练完的.pt权重只能在你本地 Python 环境里跑真要让无人机地面站或边缘盒子用起来第一步是导出成 ONNX 通用格式。这个资源里也在部署环节给了对应脚本和配置说明导出命令很直接yolo export modelruns/train/uav_traffic/weights/best.pt formatonnx opset12导出完成后会生成best.onnx建议顺手用 onnxruntime 跑一遍和 PyTorch 的输出对比确认数值误差在可接受范围内。opset参数注意别拉太高12 到 15 之间是兼容性最稳的区间尤其是后面还要接 RK3588 这类边缘设备时opset 过高会让模型转换工具直接拒绝导入。边缘设备移植这块常见做法是分两条线RK3588 用 rknn-toolkit2 把 onnx 转成 rknn 格式Orin 这类 NVIDIA 平台直接用 TensorRT 加速。无论哪条线转换后都要重新校验一次精度不能认为 onnx 上准就代表边缘端也准。推理侧我一般会做一次抽帧视频验证拿一段无人机航拍视频按 5 帧抽一张统计每类的漏检和误检把 conf 阈值从 0.25 调到 0.35 看漏检率变化。这个动作成本很低但能让你在答辩时说得清“我这个模型到底在真实画面上表现如何”而不是只报一个训练集上的 mAP。从那以后我每次拿到一批标注数据都会强制走一遍完整检查流程先统计类别分布再扫坐标越界最后空 txt 过滤全部通过才允许进训练。这个习惯帮我少熬了无数个半夜。希望帮到你。本文还有配套的精品资源点击获取
返回列表