简介:面向使用YOLO系列算法进行红外图像目标检测的研究者与开发者,这份数据集涵盖2679张红外鸟类图像及对应标注,已按训练/验证/测试集划分好,并内置data.yaml配置文件,可直接用于YOLOv5、v7、v8、v9、v10、v11等模型训练与验证测试。资源共2000个文件,以XML标签为主,同时提供YOLO格式TXT标注,两种标签分别存放,方便按需切换;标注信息包含目标类别索引、归一化中心坐标与宽高,适用于常见检测框架。压缩包整体约49.14MB,数据规模适中,便于快速下载与迭代实验。已有170人学习使用,适合刚入门目标检测或需要特定红外鸟类数据做算法对比的读者,省去自行采集与标注的耗时流程。
1. 红外场景下的鸟类检测,数据集本身才是瓶颈
在可见光数据上跑通的 YOLO 模型,一到红外场景就出现漏检率飙升、定位框偏移、置信度普遍低于 0.3 的现象,这不是网络结构的问题,而是训练分布和推理分布不一致。红外图像没有颜色纹理,只有热辐射梯度,鸟类在天空背景下的轮廓往往和树枝、云层边缘混淆,加上飞行姿态多变、目标尺寸小,常规的 COCO 预训练权重几乎无法直接迁移。这个数据集提供了 2679 张已标注的红外鸟类图像,同时给出 YOLO txt 和 VOC xml 两种标签格式,并划分好了训练集、验证集与测试集,还内置了data.yaml。适合做三件事:一是直接训练 YOLOv5/v8/v9/v7/v10/YOLO11 系列检测模型,二是验证不同 Backbone 在红外小目标上的表现差异,三是作为红外目标检测算法改进的基准数据。如果你正在做无人机巡检、机场驱鸟或生态监测项目,这份数据可以省掉最耗时的采集标注环节。
2. 目录结构与双标签格式:txt 和 xml 是如何对应同一张图的
2.1 解压后的目录组织
拿到压缩包后先看整体布局。常见做法是数据已经按 YOLO 惯例分成images和labels两个顶层目录,其中labels下又有yolo_format和voc_format两个子目录。训练集、验证集、测试集通常通过三个文本文件(train.txt、val.txt、test.txt)或直接在目录下拆分train/、val/、test/子文件夹来体现。该数据集的划分已经完成并且配置好了data.yaml,因此不需要自己再写random_split脚本。
以典型结构为例:
bird_infrared_dataset/ ├── data.yaml ├── images/ │ ├── train/ │ │ ├── img_0975_697.jpg │ │ ├── img_0975_695.jpg │ │ └── ... │ ├── val/ │ └── test/ ├── labels/ │ ├── yolo_format/ │ │ ├── train/ │ │ │ ├── img_0975_697.txt │ │ │ └── ... │ ├── voc_format/ │ │ ├── train/ │ │ │ ├── img_0975_697.xml │ │ │ └── ...data.yaml内容一般长这样:
train: ./images/train val: ./images/val test: ./images/test nc: 1 names: ['bird']如果你的数据集中鸟类类别不止一种,names列表会对应实际标注的类别名。该数据集文件名末尾出现的正是类别名称,例如img_0975_697.xml中的697并不是类别,而是图像编号,真正的类别需要打开标签文件确认。
2.2 YOLO txt 标签的坐标体系
YOLO 格式每一行代表一个目标框,五个数值分别是class_index, x_center, y_center, width, height。这里的四个坐标值全部是归一化比例,范围 0~1,不是像素坐标。计算方式是把像素坐标除以图像宽高:
x_center = (x_min + x_max) / 2 / img_width y_center = (y_min + y_max) / 2 / img_height width = (x_max - x_min) / img_width height = (y_max - y_min) / img_height例如一行标签:
0 0.684375 0.421528 0.091667 0.064815含义是类别索引 0(即 bird),检测框中心位于图像横向 68.44%、纵向 42.15% 的位置,框宽占图像宽度 9.17%,框高占图像高度 6.48%。这种比例式存储的好处是不受图像分辨率影响,不管原图是 640×512 还是 1280×1024,标签文件不需要改变;坏处是一旦图像被裁剪或缩放,旧标签就失效了。
使用 opencv 读取图像时要注意:cv2.imread得到的是H × W × C的 numpy 数组,所以像素宽对应img.shape[1],像素高对应img.shape[0]。我之前见过有人把二者写反,导致所有框的长宽比错误,训练时 loss 能下降但 mAP 始终上不去。
2.3 VOC xml 标签的结构与读取
VOC 格式保留了人类可读的像素坐标,每个 xml 文件里包含<object>节点,里面有<name>、<bndbox>以及xmin/ymin/xmax/ymax四个像素整数值。示例:
<annotation> <filename>img_0975_697.jpg</filename> <size> <width>1280</width> <height>720</height> <depth>3</depth> </size> <object> <name>bird</name> <bndbox> <xmin>638</xmin> <ymin>210</ymin> <xmax>755</xmax> <ymax>257</ymax> </bndbox> </object> </annotation>VOC 格式适合人来复查、用 LabelImg 二次编辑,也方便转成 COCO 格式。而 YOLO 格式是训练时的直接输入。需要说明的是,该数据集为了让两种格式互相验证,特意把同一张图的标注分别保存为.txt和.xml,因此你不应该出现「同一张图在两个格式中框的数量或位置不同」的情况。如果发现不一致,优先以 xml 的像素坐标为准重新计算 yolo 标签。
2.4 如何验证两种格式是否对齐
写一个快速脚本检查每个 xml 对应的 txt 是否存在,并抽查坐标转换误差:
import os import cv2 import xml.etree.ElementTree as ET xml_dir = 'labels/voc_format/train' txt_dir = 'labels/yolo_format/train' img_dir = 'images/train' for xml_file in sorted(os.listdir(xml_dir)): base = os.path.splitext(xml_file)[0] txt_file = os.path.join(txt_dir, base + '.txt') if not os.path.exists(txt_file): print(f'缺少txt: {base}') continue tree = ET.parse(os.path.join(xml_dir, xml_file)) root = tree.getroot() img = cv2.imread(os.path.join(img_dir, base + '.jpg')) h, w = img.shape[:2] with open(txt_file, 'r') as f: for line in f: cls, xc, yc, bw, bh = map(float, line.split()) # 反算回像素坐标 px_cx, px_cy = xc * w, yc * h px_w, px_h = bw * w, bh * h # 从 xml 取出第一个目标做比较(这里仅演示) obj = root.find('object') bnd = obj.find('bndbox') xmin = float(bnd.find('xmin').text) ymin = float(bnd.find('ymin').text) xmax = float(bnd.find('xmax').text) ymax = float(bnd.find('ymax').text) xml_cx = (xmin + xmax) / 2 xml_cy = (ymin + ymax) / 2 if abs(xml_cx - px_cx) > 1 or abs(xml_cy - px_cy) > 1: print(f'坐标偏差: {base}')参数说明:w和h是从图像读取到的实际宽高,用来把 yolo 归一化坐标还原成像素坐标,再和 xml 中的 ground truth 比对。允许 1 像素误差是因为某些标注工具会产生浮点截断。如果大面积出现偏差,说明数据集在导出时可能做了图像缩放,需要重新生成标签。
3. 用 YOLOv8/YOLO11 训练红外鸟类检测模型
3.1 选择哪个 YOLO 版本
该数据集在描述中声称同时适配 yolov5、yolov7、yolov8、yolov9、yolov10、yolo11。对于红外鸟类的典型应用场景(目标小、背景杂、实时性要求高),我的建议是优先尝试 YOLOv8n 或 YOLO11n。原因在于:
- YOLOv8 的 C2f 结构在保持轻量化的同时提升了梯度流,对中小目标比 v5 的 C3 更友好;
- YOLO11 进一步优化了 C3k2 模块,在相同参数量的情况下推理速度略快;
- YOLOv10 去掉 NMS 的设计在实际部署时比较方便,但它的训练稳定性和生态兼容性目前仍不如 v8;
- YOLOv9 的可逆分支在复杂背景下有优势,但显存占用高,不适合 8GB 以下显卡。
如果追求速度,用 n 版本;如果精度优先,换成 s 或 m 版本。该数据集 2679 张图属于小规模数据,不建议直接上 x 版本,很容易过拟合。
3.2 修改 data.yaml 并检查路径
训练前需要确认data.yaml中train、val的路径。如果你的文件放在服务器/data/bird下,建议改成绝对路径,避免当前工作目录变化导致FileNotFoundError:
train: /data/bird/images/train val: /data/bird/images/val test: /data/bird/images/test nc: 1 names: ['bird']注意:YOLO 训练时会根据data.yaml中的train/val路径去读取对应的图像和标签。标签路径不是由 yaml 直接指定,而是自动将images替换为labels下的相应格式目录。该数据集由于把 txt 放在labels/yolo_format下,和默认的labels目录结构不同,需要额外处理。
3.3 处理标签子目录结构
如果labels/yolo_format/train里存放的是 txt,而images/train里是 jpg,YOLO 默认查找的是images同级的labels目录。解决办法有两个:
方法一:建立软链接(Linux 推荐):
ln -s /path/to/dataset/labels/yolo_format /path/to/dataset/labels方法二:写一个脚本把 txt 复制到标准布局:
mkdir -p labels/train labels/val labels/test cp labels/yolo_format/train/*.txt labels/train/ cp labels/yolo_format/val/*.txt labels/val/ cp labels/yolo_format/test/*.txt labels/test/我一般用方法二,因为软链接在打包迁移时容易断链,复制最稳妥。注意 class 索引要一致,该数据集类别从 0 开始,如果你的names列表顺序和 txt 中的索引不一致,训练时只会报错或产生错误的类别映射。
3.4 执行训练命令
以 YOLOv8 为例,运行命令:
yolo detect train \ model=yolov8n.pt \ data=/data/bird/dataset.yaml \ epochs=100 \ imgsz=640 \ batch=16 \ lr0=0.01 \ lrf=0.1 \ patience=20 \ project=/output/bird_yolov8 \ name=exp1 \ cache=True参数说明:
model=yolov8n.pt:加载 COCO 预训练权重,可以加快收敛。对于红外图像,预训练特征不完全适用,但前几层的边缘和纹理提取仍然有用;epochs=100:2679 张图的数据量,100 epoch 足以收敛,再多容易过拟合;imgsz=640:输入尺寸。红外图像中鸟类目标较小,可以尝试imgsz=960或1280提升小目标召回率,代价是显存和训练时间增加;batch=16:根据显存调整,8GB 显卡建议 8~16;lr0=0.01:初始学习率。如果发现 loss 震荡,降到 0.005;patience=20:20 个 epoch 内 mAP 没有提升就早停,避免无效训练。
如果你是 YOLO11 用户,只需把model=yolov8n.pt换成model=yolo11n.pt,其他命令兼容:
yolo detect train \ model=yolo11n.pt \ data=/data/bird/dataset.yaml \ epochs=100 \ imgsz=640 \ batch=16 \ project=/output/bird_yolo113.5 训练过程中的关键指标观察
训练日志里重点看box_loss、cls_loss、dfl_loss以及验证集的mAP50和mAP50-95。红外数据集的背景温度分布和可见光不同,初期cls_loss可能会偏高,这属于正常现象,因为网络在重新适应红外纹理。
提示:如果训练时出现
WARNING: incorrect labels或Dataset not found,先检查标签文件是否为空、类别索引是否越界、路径是否存在。不要盲目调网络参数,90% 的问题出在数据格式上。
3.6 测试集上的验证
训练完成后,用训练时划分的 test 集做最终评估:
yolo detect val \ model=/output/bird_yolov8/exp1/weights/best.pt \ data=/data/bird/dataset.yaml \ split=test \ imgsz=640注意 YOLO 默认只验证 val 集,split=test可以指定测试集。如果data.yaml中没有定义test字段,需要手动加上,否则验证脚本会报错。
4. VOC 格式与 YOLO 格式的转换与数据清洗
4.1 批量 VOC 转 YOLO 的脚本逻辑
虽然该数据集已经同时提供了两种格式,但当你需要增加新标注图片,或者从其他公开数据集迁移数据时,仍然需要自己实现转换。标准的转换脚本如下:
import os import xml.etree.ElementTree as ET from glob import glob classes = ['bird'] # 需与 data.yaml 中 names 顺序一致 def convert_annotation(xml_path, out_txt_path, img_w, img_h): tree = ET.parse(xml_path) root = tree.getroot() with open(out_txt_path, 'w') as f: for obj in root.iter('object'): name = obj.find('name').text if name not in classes: continue cls_idx = classes.index(name) bnd = obj.find('bndbox') xmin = float(bnd.find('xmin').text) ymin = float(bnd.find('ymin').text) xmax = float(bnd.find('xmax').text) ymax = float(bnd.find('ymax').text) # 防止边界越界 xmin = max(0, min(xmin, img_w - 1)) ymin = max(0, min(ymin, img_h - 1)) xmax = max(0, min(xmax, img_w - 1)) ymax = max(0, min(ymax, img_h - 1)) if xmax <= xmin or ymax <= ymin: continue x_center = (xmin + xmax) / 2 / img_w y_center = (ymin + ymax) / 2 / img_h width = (xmax - xmin) / img_w height = (ymax - ymin) / img_h f.write(f'{cls_idx} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n')代码说明:读取 xml 时先判断类别是否在预设列表里,不在就跳过;对坐标做了边界裁剪,防止标注超出图像尺寸;过滤掉宽或高小于等于 0 的空框。img_w和img_h需要从对应图像读取,不能依赖 xml 里<size>字段的值,因为有些标注工具写入的 size 与真实图像不一致。
4.2 数据清洗:找出 0 尺寸框和越界框
红外数据集里常见的问题是劣质标注,比如目标被树枝遮挡后只标注了可见部分,或者边缘目标只有半个框。训练前用脚本清洗:
python check_labels.py --label_dir labels/yolo_format/train --img_dir images/train检查脚本要点:
- 每一行解析后,
x_center、y_center是否在 0~1 之间; width、height是否大于 0 且小于 1;- 目标框面积是否小于整图的 0.01%(太小可能是误标);
- 用 opencv 在图上画出所有框,输出为拼接长图,肉眼快速扫一遍。
对于面积占比小于 0.0001 的极端小目标,可以将其过滤或保留,取决于你的检测需求。鸟类的飞行姿态在红外图像中可能只有 4~5 个像素宽,这种情况下即使标注正确,模型也很难学出有效特征,建议用切片策略(后面介绍)。
4.3 类别不均衡与样本数统计
虽然该数据集只有「bird」一个类别,但如果是多类别红外鸟类数据集,需要统计每类的目标数量:
cat labels/yolo_format/train/*.txt | awk '{print $1}' | sort | uniq -c输出结果每行是一个类别索引及目标数量。如果某个类别的实例数远小于其他类,就要考虑样本复制或使用cls_loss的 class weight。单类别情况下,重点关注的是目标尺寸分布。可以写个小程序收集所有 gt 框的宽度、高度,按区间绘制直方图,辅助决定训练时的imgsz。
4.4 验证集和测试集不要被污染
该数据集已经划分好 train/val/test,但如果你要重新划分,必须按照图像名而不是按文件顺序简单切分。因为红外序列帧中相邻帧高度相似,如果同一段连续帧同时出现在训练集和测试集中,测得的 mAP 会虚高。建议划分时先对图像名做时间戳或场景分组,再按组划分。该数据集的图像名如img_0975_697,其中0975可能是场景编号,697是帧编号,合理划分应该让同一个0975场景的图片尽量落在同一个集合内。
5. 红外小目标场景下的调参与推理加速技巧
5.1 增大输入分辨率并开启 TTA 验证
红外鸟类在 640×512 原图中往往只占几十个像素,直接在 640 输入下训练容易导致目标特征被下采样丢失。推荐做法是训练时用 640 起步,收敛后加载 best.pt 再以 960 或 1280 微调 20~30 个 epoch:
yolo detect train \ model=/output/bird_yolov8/exp1/weights/best.pt \ data=/data/bird/dataset.yaml \ epochs=30 \ imgsz=1280 \ lr0=0.002 \ freeze=10freeze=10表示冻结前 10 层网络,只微调高层特征,避免因输入尺寸突变导致底层特征崩塌。验证时可以临时开启测试时增强来估计上限:
yolo detect val \ model=best.pt \ data=dataset.yaml \ imgsz=1280 \ augment=True5.2 对小目标用 SAHI 切片推理
如果目标平均边长小于 16 像素,直接检测很难提升。常见做法是使用 SAHI(Slicing Aided Hyper Inference),把原图切成若干重叠切片,分别检测后再合并结果。以 YOLOv8 为例:
from sahi.model import Yolov8DetectionModel from sahi.predict import get_sliced_prediction model = Yolov8DetectionModel( model_path='best.pt', confidence_threshold=0.3, image_size=640, device='cuda:0' ) result = get_sliced_prediction( 'test.jpg', model, slice_height=320, slice_width=320, overlap_height_ratio=0.2, overlap_width_ratio=0.2 ) result.export_visuals(export_dir='sahi_output/')参数说明:slice_height/width是对原图切片的尺寸,取 320 表示把 1280×1024 的红外图切成 4×4 共 16 块;overlap_height_ratio=0.2是切片间重叠比例,避免目标正好被切到两块边缘导丢失。切片推理速度会下降数倍,适合对单帧或离线视频流做后处理,不适合实时部署。
5.3 使用 TensorRT 加速推理
如果模型要部署到 Jetson 或边缘设备,官方yolo export可以直接转 TensorRT:
yolo export model=best.pt format=engine device=0 half=True imgsz=640half=True启用 FP16 精度,在大多数显卡上推理速度能提升 1.5~2 倍,mAP 损失通常在 0.5% 以内。红外数据本身对比度低,如果模型对噪声敏感,可以先用 Opencv 做一次 CLAHE 增强再送入网络:
import cv2 img = cv2.imread('input.jpg', cv2.IMREAD_GRAYSCALE) clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) enhanced = clahe.apply(img) enhanced_bgr = cv2.cvtColor(enhanced, cv2.COLOR_GRAY2BGR)注意红外图像如果是单通道数据,需要先转成 3 通道,因为 YOLO 训练时的输入是 BGR 三通道。clipLimit太大会放大热噪声,建议 1.5~2.0 之间,tileGridSize决定了局部对比度增强的粒度,8×8 对 640 分辨率来说比较稳妥。经过 CLAHE 后再推理,往往能找回 5%~10% 的漏检框,尤其是低照度环境下体温与背景温差较小的鸟类。
5.4 针对该数据集的快速验证路径
你可以直接拿验证集里几张典型红外图像,分别用原始图和 CLAHE 增强图跑一次推理,比较漏检目标的重叠情况:
yolo predict model=best.pt source=val_sample/ save=True conf=0.25conf=0.25是置信度阈值,红外小目标置信度普遍偏低,如果实测大量目标被滤掉,可以下调到 0.15,同时用 NMS 的iou=0.4减小重叠框保留。调整阈值前先确认 val 集上的 mAP50 不低于 0.8,否则调阈值没有意义,问题仍在模型本身或训练数据。
本文还有配套的精品资源,点击获取