尧图精选

YOLOv8无人机航拍牧羊识别:从数据集构建到部署的完整实战

🕒 发布时间:2026/10/2 3:45:31 📁 来源:尧图网络
简介本资源为基于YOLOv8的无人机航拍牧羊目标检测项目代码面向深度学习入门与进阶学习者、计算机视觉方向学生及需要落地航拍牲畜识别方案的开发者。项目围绕无人机视角下的羊群检测任务提供从环境配置到模型训练、推理部署的完整工程结构帮助读者快速复现并迁移到类似航拍目标检测场景。压缩包共468个文件约26.23MB以227个md说明文档、130个Python脚本、43个yaml与12个yml配置为主另含pt权重、cpp推理源码、sh脚本、ipynb笔记及少量图片与样式文件覆盖训练、推理、Docker部署等环节。按requirements.txt配置环境即可使用。目前已有85人学习关注适合希望掌握YOLOv8实战流程、理解航拍小目标检测难点并积累项目经验的读者参考。1. 从一段航拍视频说起YOLOv8 无人机牧羊识别到底在做什么把无人机飞到羊群上方两百米回传画面里几百个白色小点缓慢移动人眼盯十分钟就花可牧场主需要知道头羊往哪走、有没有羊掉队、边界有没有被冲散。YOLOv8 无人机航拍牧羊识别要解决的就是这件事用目标检测模型在航拍画面里把每一只羊框出来再交给上层逻辑做计数、跟踪和越界判断。它适合两类人一类是手里已经有无人机和视频流、想把 AI 接进现有巡检流程的工程团队另一类是刚学完 YOLOv8 训练自己数据集、想找一个真实场景练手的开发者。这个方向的门槛不在模型本身而在航拍数据的小目标、密集遮挡和光照剧变下面把我实际跑过一遍的路径拆开讲。2. 航拍牧羊数据集从原始视频到 YOLOv8 可训练格式2.1 为什么牧羊场景不能直接套公开数据集公开的 COCO、VOC 里虽然有 sheep 这一类但绝大多数是地面平视拍摄羊在画面里占几百像素背景是草地围栏。无人机航拍是俯视或大角度斜视单只羊在 1080p 画面里往往只有 20 到 60 像素还经常几只挤成一团边界框互相重叠。直接拿 COCO 预训练权重去推理航拍画面召回率会掉得很难看因为模型学到的纹理和尺度分布完全对不上。常见做法是自己采数据用无人机在目标牧场飞几个架次覆盖早中晚三个时段和晴天阴天两种光照每段视频抽帧后人工标注。我一般会按 8:1:1 划分训练、验证、测试并且保证同一段视频的帧不要跨集合否则相邻帧高度相似会造成验证指标虚高这是血泪经验。2.2 抽帧、去重与标注的完整命令抽帧用 ffmpeg 最省事关键是控制帧率航拍视频 30fps 相邻帧几乎一样按每秒 2 帧抽就够。下面这段脚本把视频目录批量抽帧并按视频名建子目录方便后续追溯来源。# 批量抽帧每个视频每秒抽 2 帧输出到 frames/视频名/ for f in raw_videos/*.mp4; do name$(basename $f .mp4) mkdir -p frames/$name # -vf fps2 表示每秒保留2帧避免相邻帧冗余 ffmpeg -i $f -vf fps2 -q:v 2 frames/$name/%05d.jpg done抽完帧先做去重否则大量近似帧会让模型过拟合到某几个背景。用感知哈希做粗筛汉明距离小于 5 的判为重复只保留一张。import imagehash from PIL import Image import os def dedup(folder, threshold5): seen [] kept 0 for fn in sorted(os.listdir(folder)): if not fn.lower().endswith((.jpg, .png)): continue path os.path.join(folder, fn) h imagehash.phash(Image.open(path)) # 与已保留的哈希逐一比对距离过近则丢弃 if any(h - s threshold for s in seen): os.remove(path) else: seen.append(h) kept 1 print(f保留 {kept} 张删除 {len(seen) - kept} 张)标注工具用 labelme 或 X-AnyLabeling 都行类别只设一个 sheep。标完导出成 COCO 或 VOC 格式再转 YOLO 的 txt。YOLO 格式每行是类别 中心x 中心y 宽 高全部归一化到 0 到 1。转换时最容易翻车的是坐标越界和空标注文件下面这个脚本顺手做了校验。import json, os def coco_to_yolo(coco_json, out_dir, img_dir): data json.load(open(coco_json)) # 建立 image_id 到文件名的映射 id2img {im[id]: im for im in data[images]} os.makedirs(out_dir, exist_okTrue) for ann in data[annotations]: im id2img[ann[image_id]] w, h im[width], im[height] x, y, bw, bh ann[bbox] cx, cy (x bw / 2) / w, (y bh / 2) / h nw, nh bw / w, bh / h # 越界裁剪防止归一化后超出 0~1 导致训练报错 cx, cy min(max(cx, 0), 1), min(max(cy, 0), 1) nw, nh min(nw, 1), min(nh, 1) line f0 {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}\n txt os.path.join(out_dir, os.path.splitext(im[file_name])[0] .txt) with open(txt, a) as f: f.write(line)参数上threshold控制去重强度牧羊场景背景单一可以调到 8 更激进fps2是经验值羊群移动慢可以降到 1快速奔跑的牧羊犬场景要提到 5。标注阶段建议每张图不超过 30 个框太密的目标在 640 输入下会严重粘连后面训练时再想拆开就难了。2.3 数据集目录结构与 data.yaml 写法YOLOv8 对目录结构有固定要求images 和 labels 必须平行且文件名一一对应。我一般这样组织sheep_dataset/ images/ train/ val/ test/ labels/ train/ val/ test/ data.yamldata.yaml 里写清路径和类别名注意path用绝对路径最稳相对路径在不同工作目录下启动训练时经常找不到文件。path: /data/sheep_dataset train: images/train val: images/val test: images/test nc: 1 names: [sheep]nc是类别数牧羊只检测羊就是 1。如果还想区分羊和牧羊犬改成 2 并在 names 里按索引顺序写。写完用一行命令快速验证标签有没有越界或空文件# 检查是否存在空标签文件无目标的图会被跳过但空文件要警惕 find labels -name *.txt -size 0 | head3. 用 YOLOv8 训练牧羊检测模型参数怎么设、曲线怎么看3.1 环境搭建与模型选型环境这块Ubuntu 20.04 上装 CPU 版和 GPU 版差别很大。有 NVIDIA 显卡就走 CUDA没有就用 CPU 版先跑通流程。装 ultralytics 一条命令但要注意 Python 版本别太新3.8 到 3.10 最稳。# 创建虚拟环境并安装CPU 版直接 pip 即可 python -m venv yolo_env source yolo_env/bin/activate pip install ultralytics # 验证安装与版本 yolo checks模型选型上航拍小目标优先考虑 YOLOv8s 或 YOLOv8mn 版虽然快但小目标召回明显吃亏x 版在单卡 1660Ti 上训练慢到怀疑人生。输入尺寸从默认 640 提到 960 或 1280 对小目标帮助很大代价是显存和训练时间成倍涨。我一般先用 640 跑通全流程确认数据没问题再切 960 正式训。3.2 训练命令与关键参数逐条解释训练用命令行或 Python 脚本都行我习惯写脚本方便记录参数。下面这份是牧羊场景调过的配置。from ultralytics import YOLO # 加载预训练权重迁移学习比从头训收敛快得多 model YOLO(yolov8s.pt) model.train( datasheep_dataset/data.yaml, epochs150, # 牧羊数据量通常几千张150 轮够收敛 imgsz960, # 小目标关键参数640 会丢大量羊只 batch8, # 1660Ti 6G 显存下 960 输入只能开到 8 device0, # 0 表示第一块 GPUCPU 训练写 cpu workers4, # 数据加载线程太多会抢内存 lr00.01, # 初始学习率迁移学习常用 0.01 lrf0.01, # 最终学习率 lr0 * lrf momentum0.937, weight_decay0.0005, warmup_epochs3, # 前 3 轮预热防止初期梯度爆炸 patience30, # 30 轮无提升就早停省时间 augmentTrue, # 开启内置增强 mosaic1.0, # 马赛克增强对密集小目标有效 close_mosaic10, # 最后 10 轮关闭 mosaic稳定收敛 projectruns/sheep, namev8s_960, )imgsz是牧羊场景最该动的参数从 640 提到 960 通常能把小目标 mAP 拉高 5 到 10 个点。mosaic增强把四张图拼一张能显著增加小目标出现频率但训练末期必须关掉否则框的位置会飘。patience设 30 是防止过拟合后白跑验证指标连续 30 轮不涨就停。batch要根据显存调爆显存就减半别硬撑。3.3 损失曲线和指标怎么读训练完在 runs 目录下有 results.csv 和曲线图。重点看三件事box_loss 是否稳定下降、mAP50 是否还在涨、有没有过拟合。画曲线用下面这段把训练和验证损失放一起对比。import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/sheep/v8s_960/results.csv) df.columns [c.strip() for c in df.columns] plt.plot(df[epoch], df[train/box_loss], labeltrain) plt.plot(df[epoch], df[val/box_loss], labelval) plt.xlabel(epoch); plt.ylabel(box_loss); plt.legend() plt.savefig(loss_curve.png)如果 train 损失一直降而 val 损失开始抬头就是过拟合加数据或加增强。如果两条都居高不下多半是学习率太大或标签有问题。mAP50 在牧羊场景能到 0.85 以上算不错mAP50-95 通常低不少因为小目标定位精度天然吃亏别拿它跟地面拍摄的指标比。4. 推理部署与航拍视频流接入的避坑清单4.1 从单张图推理到视频流实时检测训练完先用单张图验证再上视频。单张推理一行就够from ultralytics import YOLO model YOLO(runs/sheep/v8s_960/weights/best.pt) # conf 置信度阈值iou 是 NMS 的重叠阈值 results model.predict(test.jpg, conf0.35, iou0.5, imgsz960) results[0].save(out.jpg)视频流用 OpenCV 逐帧读注意航拍视频分辨率高直接喂原图会拖慢推理先缩放到模型输入尺寸附近再送进去。实时性要求高就上 TensorRT 或 ONNX RuntimeRK3588 这类边缘板子部署 YOLOv8 也是常见路线但模型转换和量化是另一个话题这里先把 PC 端跑通。4.2 航拍牧羊检测的五个高频翻车点现象一模型把白云、白石头当成羊。原因是背景里存在与羊颜色相近的干扰物训练集没覆盖。解决是补采含这类干扰的负样本或者在 data.yaml 里加一个 background 类专门吸收误检再重训。现象二羊群密集时框大量重叠、计数偏多。原因是 NMS 的 iou 阈值设太高重叠框没被抑制。解决是把推理时 iou 从 0.7 降到 0.5 甚至 0.45密集场景还可以换 soft-NMS但 ultralytics 默认没开需要自己改后处理。现象三早晚逆光时召回骤降。原因是训练集光照分布不均模型没见过强逆光。解决是抽帧时按时间段均衡采样训练时开 HSV 增强把 hsv_v 调大模拟明暗变化。现象四验证 mAP 很高但实际视频漏检严重。原因是训练验证集来自同一段视频分布太像指标虚高。解决是严格按视频划分集合测试集必须来自没参与训练的架次。现象五训练到一半 loss 变 NaN。原因是学习率过大或某批标签坐标异常。解决是先把 lr0 降到 0.001 重跑同时用前面的校验脚本扫一遍标签把越界和宽高为 0 的框清掉。注意航拍数据标注时被遮挡超过 70% 的羊建议标为忽略区域而不是硬标框否则模型会学到一堆不完整目标推理时反而更乱。5. 把牧羊识别做稳的一个进阶技巧分块推理加跨帧投票单帧检测在密集羊群上总会有抖动同一只羊这帧框到、下帧丢了直接拿去做计数会跳变。我后来固定用一套组合拳先把 4K 航拍图切成带重叠的 2x2 小块分别推理再把结果映射回原图做全局 NMS最后对连续 5 帧的检测框做一次简单投票只有出现 3 帧以上的框才保留。分块推理解决的是小目标在整图缩放后像素太少的问题跨帧投票解决的是单帧漏检和误检。切块时重叠比例设 0.2太小会在切缝处丢目标太大则重复框增多拖慢后处理。import cv2, numpy as np from ultralytics import YOLO model YOLO(best.pt) def tiled_infer(img, tile2, overlap0.2): h, w img.shape[:2] th, tw h // tile, w // tile boxes [] for i in range(tile): for j in range(tile): y0 max(0, int(i * th - th * overlap)) x0 max(0, int(j * tw - tw * overlap)) y1 min(h, int((i 1) * th th * overlap)) x1 min(w, int((j 1) * tw tw * overlap)) crop img[y0:y1, x0:x1] r model.predict(crop, conf0.3, imgsz960, verboseFalse)[0] for b in r.boxes.xyxy.cpu().numpy(): # 把局部坐标加回原图偏移 boxes.append([b[0] x0, b[1] y0, b[2] x0, b[3] y0]) return boxes这段只做了分块和坐标还原跨帧投票需要维护一个历史框列表用 IoU 匹配当前帧和过去帧的框命中次数达标的才输出。参数上tile2适合 4K 图1080p 用 1 就行overlap0.2是平衡速度和召回的经验值。验证这套是否有效别只看 mAP直接拿一段没训过的视频跑人工数一遍漏检和误检比任何指标都直观。我踩过的最大坑是切块后忘了加偏移框全挤在左上角排查了半天才发现是坐标没还原。做视觉这行玄学少低级错误多写完先拿一张图把框画出来看一眼能省掉大量后悔药。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →