
简介这份无人机飞鸟检测数据集面向目标检测算法研究与无人机、飞鸟识别等视觉场景适合需要标准VOC/YOLO双格式数据开展模型训练或算法对比的开发者。资源包含6647张jpg图片每张图片均配套提供Pascal VOC格式的xml标注文件和YOLO格式的txt标注文件图像与标注一一对应类别共两类Bird与Drone。全部标注由LabelImg工具按统一的矩形框规则绘制总框数7857个其中Bird有3567框、Drone有4290框xml文件保存边界框的详细坐标txt文件保存归一化后的类别与位置信息数据组织清晰每个类别均有独立框数统计便于按类别做样本均衡或加权训练可直接接入YOLO、Faster R-CNN等主流检测框架。压缩包约194.31MB文件总数约2000个以xml标注文件为主并包含使用说明txt下载解压后能快速了解目录结构、标注规则及文件组织方式。目前已有596人学习下载该数据集只保证标注准确且合理不承诺模型或权重文件的精度适合需要干净、规范标注样本做检测模型训练、算法验证或教学演示的开发者直接使用。1. 无人机飞鸟检测数据集6647张图、2类目标VOC和YOLO标注一次给全做无人机反制、机场驱鸟或者生态监测项目的人大概率都遇到过同一个尴尬算法模型不缺显卡不缺缺的是能直接扔进YOLO训练脚本的数据。网上公开的飞鸟数据集要么是相机贴脸拍的要么标注格式还得自己写脚本转一圈折腾两天数据还没喂进模型。这套「无人机飞鸟检测数据集」解决的正是这个痛点——6647张无人机俯拍视角图片鸟和鸟群两个类别VOC和YOLO两种标注格式都给你备齐了解压出来整理一下目录就能直接开训。适合正在做目标检测入门、毕设或者小型监测系统验证的从业者尤其适合手里有YOLOv5/v8训练经验但缺一份干净数据的人。2. 数据集底层结构VOC与YOLO标注格式的对应关系2.1 两种格式到底存了什么拿到压缩包先别急着解压训练先搞清楚VOC和YOLO这两种标注格式的内在区别。VOC格式本质上是把标注信息存在XML文件里每个目标用一个object节点描述里面记录的是目标框的绝对坐标xmin、ymin、xmax、ymax单位是像素坐标原点在图片左上角。这种格式的好处是直观、可读性强坏处是训练之前必须自己写解析脚本把XML转成模型能吃的格式。YOLO格式则直接走归一化路线每个目标对应txt文件里的一行四个数字分别代表中心点x、中心点y、目标框宽度、目标框高度全是相对于图片宽高的比例值。好处是YOLO系列训练脚本开箱即用坏处是人眼没法直接看。这套数据集两个格式都给了意味着你既可以拿VOC格式做数据可视化排查也可以用YOLO格式直接喂给训练脚本不必在格式转换上耗时间。2.2 路径分布与文件组织逻辑解压后先看目录层级。常见做法是Annotations存放VOC的XML文件images存放所有jpg图片labels存放YOLO的txt标注文件。这三个目录加起来就是完整数据集本体。顺手留意一下classes.txt或者obj.names这类文件里面按行写着类别名第一行是鸟第二行是鸟群类别索引从0开始跟每个txt文件里每行开头的数字严格对应。检查数据一致性有个笨办法但很管用统计三个目录下的文件数必须一一对应任何一边多一个少一个都说明标注或者拷贝过程出了问题。我一般会在Linux下直接跑一段脚本核对Windows用户用PowerShell或者Python都行。#!/bin/bash # 核对三个目录的文件数量是否一致 echo 图片数量: $(ls images/*.jpg | wc -l) echo VOC标注数量: $(ls Annotations/*.xml | wc -l) echo YOLO标注数量: $(ls labels/*.txt | wc -l)这段脚本做的事情很简单把images、Annotations、labels三个目录下的对应文件数量逐一统计出来。如果数字不一致优先排查是不是拷贝过程中漏了文件或者某个标注文件被误删。正常情况下6647张图应该对应6647个XML和6647个txt数量对不上后面训练必然报错。2.3 标注内容抽查图片与标注的对应验证文件数量对上了还不够还要抽查图片和标注内容是否真的匹配。写一个小脚本随机抽几张图把YOLO格式的txt标注还原成像素坐标画回图上人眼确认一下框的位置和类别是否合理。import cv2 import random import glob import os # 读取类别名文件 with open(classes.txt, r) as f: classes [line.strip() for line in f.readlines()] # 随机抽一张图做验证 img_path random.choice(glob.glob(images/*.jpg)) img cv2.imread(img_path) h, w img.shape[:2] # 解析对应的txt标注 txt_path img_path.replace(images, labels).replace(.jpg, .txt) with open(txt_path, r) as f: lines f.readlines() for line in lines: parts line.strip().split() cls_id, x_center, y_center, box_w, box_h map(float, parts[:5]) # 还原像素坐标 x1 int((x_center - box_w / 2) * w) y1 int((y_center - box_h / 2) * h) x2 int((x_center box_w / 2) * w) y2 int((y_center box_h / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, classes[int(cls_id)], (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) cv2.imwrite(check_result.jpg, img) print(已生成抽查结果: check_result.jpg)这里要注意YOLO格式的坐标值全部是归一化小数必须乘以图片的实际宽高才能得到像素位置很多新手直接把小数当像素坐标画框画出来的框全是歪的。代码里x_center到x2的换算过程就是把归一化坐标还原成像素坐标的核心逻辑。看到绿框和红字都符合预期说明这份数据的标注质量可用。3. 直接上手训练目录整理与YOLOv8训练配置3.1 数据集目录标准布局拿到手的数据集目录结构不一定跟YOLOv8的预期完全对齐所以第一步是把数据整理成YOLOv8的images和labels双层结构。标准布局是datasets/bird/下分images/train、images/val、labels/train、labels/val四个子目录。train和val的比例我一般按9比1切6647张图差不多能分到5980张训练、660张验证。数据划分这件事不建议手动拖拽写脚本按比例随机划分更靠谱。下面这段Python脚本做的事情就是遍历所有图片随机打乱后按比例分配同时把对应的txt标注文件同步移动到相同结构的目录下。import os import random import shutil random.seed(42) # 固定随机种子保证可复现 src_images images src_labels labels dst_root datasets/bird train_ratio 0.9 os.makedirs(f{dst_root}/images/train, exist_okTrue) os.makedirs(f{dst_root}/images/val, exist_okTrue) os.makedirs(f{dst_root}/labels/train, exist_okTrue) os.makedirs(f{dst_root}/labels/val, exist_okTrue) img_files [f for f in os.listdir(src_images) if f.endswith(.jpg)] random.shuffle(img_files) split_idx int(len(img_files) * train_ratio) for i, img_name in enumerate(img_files): label_name img_name.replace(.jpg, .txt) src_img os.path.join(src_images, img_name) src_lbl os.path.join(src_labels, label_name) if i split_idx: shutil.copy(src_img, f{dst_root}/images/train/{img_name}) shutil.copy(src_lbl, f{dst_root}/labels/train/{label_name}) else: shutil.copy(src_img, f{dst_root}/images/val/{img_name}) shutil.copy(src_lbl, f{dst_root}/labels/val/{label_name}) print(f训练集: {split_idx} 张, 验证集: {len(img_files) - split_idx} 张)代码里random.seed(42)这一行容易被忽略但很关键不固定随机种子的话每次运行划分结果都不一样后面做对比实验时训练集和验证集会变来变去模型性能的波动就说不清是数据划分还是模型本身的问题了。train_ratio参数按需调整数据量大的场景可以适当调高训练比例。3.2 编写data.yaml配置文件YOLOv8训练需要一份YAML配置文件来告诉模型数据在哪里、有哪几个类别。这里直接手动创建datasets/bird/data.yaml内容如下# 训练数据配置文件 path: ./datasets/bird train: images/train val: images/val nc: 2 names: [bird, bird_group]这份配置文件里path指定数据集根目录train和val是相对路径nc是类别数量names列表的顺序必须跟txt标注里的类别索引一一对应。注意names不能用中文YOLOv8读取类别名时如果碰到非ASCII字符部分版本的绘图和日志功能会报编码错误我遇到过好几次老老实实全用英文最省事。3.3 启动YOLOv8训练配置就绪后直接拉起训练。用YOLOv8命令行是最快的方式显存够的话nms和batch参数可以参考下面的写法。# YOLOv8n 轻量模型训练batch 16 需要约12G显存 yolo train datadatasets/bird/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ device0 \ patience20 \ project./runs/bird \ nameexp1这里几个参数值得细说。modelyolov8n.pt会先加载COCO预训练权重在预训练基础上做迁移学习比从零训练收敛快得多。imgsz640是输入分辨率飞鸟在无人机视角下往往是小目标如果硬件允许可以试试imgsz1280但训练时间会明显变长。patience20表示连续20个epoch验证集指标没有提升就提前停止训练省时间用的。4. 训练结果验证mAP与损失曲线怎么看4.1 训练输出指标解读训练完看runs/bird/exp1/目录下的结果。results.png里画了四条曲线值得关注box_loss、cls_loss、mAP50和mAP50-95。box_loss持续下降说明模型在学框的位置和大小cls_loss下降说明类别判别能力增强。mAP50在验证集上如果稳定在0.75以上这个模型基本能用于简单场景的飞鸟检测。注意一个常见的认识偏差mAP50高不代表实际效果一定好。由于无人机视角下的飞鸟目标偏小模型可能在验证集上表现不错跑到真实场景里却漏检严重。所以一定要用密集小目标场景的图片做额外测试别只看指标数字。4.2 混淆矩阵里的信号训练完会生成confusion_matrix.pngYOLOv8的混淆矩阵里每个格子代表真实目标和预测类别的对应关系。总合不唯一这个现象很多人遇到过原因在于矩阵中的数值是归一化后的比例值对角线加起来不等于100%背景类也参与计数。看这张图要盯两个位置鸟bird那一行有多少样本被误判成了背景background以及鸟群bird_group和鸟之间是否大量互相混淆。如果鸟和鸟群之间互相误判的比例偏高处理方案通常有两个。一是检查标注中这两类的边界框是否切分合理比如一群鸟聚集时被标成了多个单独的鸟或者距离很近的两只鸟被框进了一个鸟群标注。二是干脆在业务允许的前提下合并这两个类别很多时候检测应用根本不需要区分单只鸟和鸟群统一识别为“飞鸟目标”反而让模型更好学了。4.3 验证集可视化预测跑一遍验证集推理把预测结果画出来人眼检查这一步不能省。# 对验证集做批量预测并保存结果图 yolo predict modelruns/bird/exp1/weights/best.pt \ sourcedatasets/bird/images/val \ saveTrue \ conf0.25 \ imgsz640预测结果默认保存到runs/detect/predict/下。重点看三类图光线较暗或逆光条件下的图看模型是否漏检背景纹理复杂的图看是否把树叶、电线杆误检成鸟多目标聚集的图看框与框的重叠是否合理。conf0.25是置信度阈值低于这个值的预测会被过滤掉。实际部署时如果发现漏检多就调低阈值误检多就调高这个参数就是调平衡用的。5. 实战避坑从解压报错到BN崩溃的常见问题5.1 7z压缩包解压报错现象解压过程中提示CRC Failed或者Unexpected end of archive解压出来的文件数量不全。原因7z压缩包在传输或下载过程中出现了数据损坏。如果提示密码错误但密码明明是正确的基本也是压缩包文件不完整导致解压程序读到了错误的数据段。解决先校验压缩包的哈希值跟发布方给出的SHA256比对。一致的话用7-Zip自带的修复功能尝试修复不一致就直接重新下载不要抱侥幸心理。另外建议用7-Zip而不是Windows自带的解压工具处理7z格式系统自带工具对分卷和加密头的兼容性不太好。5.2 训练时显存溢出现象训练刚开始就报CUDA out of memory程序直接退出。原因batch参数设置过大或者输入分辨率imgsz设得过高单算力吃不下。解决把batch从16降到8甚至4同时imgsz从640降到512。如果换到V100这类大显存显卡上可以直接把batch拉到32训练速度会有明显提升。另外检查一下是不是有其他进程占用了显存用nvidia-smi看一眼很多人训练时还开着浏览器看视频显存被吃掉了大半。5.3 训练中BN崩溃或损失变成NaN现象训练中途loss突然变成nan或者日志里报出BN相关的错误模型参数不再更新。原因学习率过高、数据集里有异常的标注值比如框坐标大于1或者为负数、batch太小导致BatchNorm统计量不稳定。解决先查标注数据把所有txt文件过滤一遍找出坐标值不在[0,1]区间内的异常行直接删除对应图片和标注。然后降低初始学习率YOLOv8默认是0.01如果崩了就改成0.001再训。排查噪点图也是一个方向某些模糊到人眼都辨识不了的图片留在训练集里只会拖累模型。5.4 预测时检测不到远处的小鸟现象训练指标还不错但实际跑的时候远处的飞鸟完全没框出来近处的目标一切正常。原因无人机视角下鸟的目标尺寸普遍偏小模型没有学到足够的小目标特征。imgsz640时一只鸟可能只有十几个像素特征提取非常困难。解决一个方向是训练时用imgsz1280让小目标在输入图像中占据更多像素。另一个方向是额外做滑窗切图推理把大图切块后分别喂给模型检测再合并结果。两种方式都会增加算力开销只能根据实际部署硬件做取舍。5.5 类别索引错位导致训练指标异常现象训练能跑通但验证时发现预测类别跟真实类别完全对不上比如把鸟全预测成鸟群。原因data.yaml的names列表顺序和标注文件里的类别索引不一致。比如names: [bird_group, bird]但txt里0代表鸟、1代表鸟群整个模型的类别语义就错位了。解决写脚本扫描txt文件中的类别数字分布跟data.yaml里的names逐一对应确认。这是个低级的坑但每个项目都有人踩。6. 进阶玩法切片推理与结果可视化验证模型训出baseline之后不要急着部署花一点时间做验证和调优能省下后面大量返工的时间。这里介绍一下我常用的两件事切片推理和可视化代码。切片推理的逻辑很简单把一张高分辨率大图切分成多个带重叠区域的patch依次推理再把结果映射回原图坐标合并。这样做的好处是让原本只有十几个像素宽的目标被放大到模型更容易识别的尺度。切片的尺寸我用1024x1024重叠区域128像素推理时取的置信度阈值比整图推理略低一点因为切图后边缘目标可能被截断置信度天然偏低。可视化验证用下面这段脚本把两张图片拼接起来做对比验证左边是真实标签标出的目标右边是模型推理结果画出的框。这样做比单独看两张图直观得多。import cv2 from ultralytics import YOLO model YOLO(runs/bird/exp1/weights/best.pt) img cv2.imread(test/example.jpg) h, w img.shape[:2] # 读取真实标签并画框 with open(test/example.txt, r) as f: lines f.readlines() for line in lines: cls_id, x_center, y_center, box_w, box_h map(float, line.strip().split()) x1 int((x_center - box_w / 2) * w) y1 int((y_center - box_h / 2) * h) x2 int((x_center box_w / 2) * w) y2 int((y_center box_h / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, fgt_{int(cls_id)}, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) # 模型推理并画框 results model.predict(img, conf0.3) for r in results[0].boxes: x1, y1, x2, y2 map(int, r.xyxy[0]) cls_id int(r.cls[0]) conf float(r.conf[0]) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(img, fpred_{cls_id}_{conf:.2f}, (x1, y1 - 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) cv2.imwrite(compare_result.jpg, img)这段代码的关键在于把真实框画成绿色、预测框画成红色框上的文本同时标出类别和置信度一眼就能看出模型在哪些目标上漏检了哪些目标被误检了。对比图片如果发现某些特定角度或光照条件下的目标总是漏检把这些图片单独归到一小块验证集里后面每次调参都看这群图片的表现比整体mAP指标更能反映模型的短板。从那以后我每次拿到检测数据集都会先做一遍完整的格式检查、数据抽查、baseline训练、对比可视化这套流程才敢改模型结构。如果你不想在数据格式和坑里耗费时间这份整理好的无人机飞鸟检测数据集可以直接帮你省掉最枯燥的准备工作。希望帮到你。本文还有配套的精品资源点击获取