
简介面向使用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。这里的四个坐标值全部是归一化比例范围 01不是像素坐标。计算方式是把像素坐标除以图像宽高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 filenameimg_0975_697.jpg/filename size width1280/width height720/height depth3/depth /size object namebird/name bndbox xmin638/xmin ymin210/ymin xmax755/xmax ymax257/ymax /bndbox /object /annotationVOC 格式适合人来复查、用 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 的设计在实际部署时比较方便但它的训练稳定性和生态兼容性目前仍不如 v8YOLOv9 的可逆分支在复杂背景下有优势但显存占用高不适合 8GB 以下显卡。如果追求速度用 n 版本如果精度优先换成 s 或 m 版本。该数据集 2679 张图属于小规模数据不建议直接上 x 版本很容易过拟合。3.2 修改 data.yaml 并检查路径训练前需要确认data.yaml中train、val的路径。如果你的文件放在服务器/data/bird下建议改成绝对路径避免当前工作目录变化导致FileNotFoundErrortrain: /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里是 jpgYOLO 默认查找的是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 \ modelyolov8n.pt \ data/data/bird/dataset.yaml \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.1 \ patience20 \ project/output/bird_yolov8 \ nameexp1 \ cacheTrue参数说明modelyolov8n.pt加载 COCO 预训练权重可以加快收敛。对于红外图像预训练特征不完全适用但前几层的边缘和纹理提取仍然有用epochs1002679 张图的数据量100 epoch 足以收敛再多容易过拟合imgsz640输入尺寸。红外图像中鸟类目标较小可以尝试imgsz960或1280提升小目标召回率代价是显存和训练时间增加batch16根据显存调整8GB 显卡建议 816lr00.01初始学习率。如果发现 loss 震荡降到 0.005patience2020 个 epoch 内 mAP 没有提升就早停避免无效训练。如果你是 YOLO11 用户只需把modelyolov8n.pt换成modelyolo11n.pt其他命令兼容yolo detect train \ modelyolo11n.pt \ data/data/bird/dataset.yaml \ epochs100 \ imgsz640 \ batch16 \ 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 \ splittest \ imgsz640注意 YOLO 默认只验证 val 集splittest可以指定测试集。如果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是否在 01 之间width、height是否大于 0 且小于 1目标框面积是否小于整图的 0.01%太小可能是误标用 opencv 在图上画出所有框输出为拼接长图肉眼快速扫一遍。对于面积占比小于 0.0001 的极端小目标可以将其过滤或保留取决于你的检测需求。鸟类的飞行姿态在红外图像中可能只有 45 个像素宽这种情况下即使标注正确模型也很难学出有效特征建议用切片策略后面介绍。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 微调 2030 个 epochyolo detect train \ model/output/bird_yolov8/exp1/weights/best.pt \ data/data/bird/dataset.yaml \ epochs30 \ imgsz1280 \ lr00.002 \ freeze10freeze10表示冻结前 10 层网络只微调高层特征避免因输入尺寸突变导致底层特征崩塌。验证时可以临时开启测试时增强来估计上限yolo detect val \ modelbest.pt \ datadataset.yaml \ imgsz1280 \ augmentTrue5.2 对小目标用 SAHI 切片推理如果目标平均边长小于 16 像素直接检测很难提升。常见做法是使用 SAHISlicing Aided Hyper Inference把原图切成若干重叠切片分别检测后再合并结果。以 YOLOv8 为例from sahi.model import Yolov8DetectionModel from sahi.predict import get_sliced_prediction model Yolov8DetectionModel( model_pathbest.pt, confidence_threshold0.3, image_size640, devicecuda:0 ) result get_sliced_prediction( test.jpg, model, slice_height320, slice_width320, overlap_height_ratio0.2, overlap_width_ratio0.2 ) result.export_visuals(export_dirsahi_output/)参数说明slice_height/width是对原图切片的尺寸取 320 表示把 1280×1024 的红外图切成 4×4 共 16 块overlap_height_ratio0.2是切片间重叠比例避免目标正好被切到两块边缘导丢失。切片推理速度会下降数倍适合对单帧或离线视频流做后处理不适合实时部署。5.3 使用 TensorRT 加速推理如果模型要部署到 Jetson 或边缘设备官方yolo export可以直接转 TensorRTyolo export modelbest.pt formatengine device0 halfTrue imgsz640halfTrue启用 FP16 精度在大多数显卡上推理速度能提升 1.52 倍mAP 损失通常在 0.5% 以内。红外数据本身对比度低如果模型对噪声敏感可以先用 Opencv 做一次 CLAHE 增强再送入网络import cv2 img cv2.imread(input.jpg, cv2.IMREAD_GRAYSCALE) clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8, 8)) enhanced clahe.apply(img) enhanced_bgr cv2.cvtColor(enhanced, cv2.COLOR_GRAY2BGR)注意红外图像如果是单通道数据需要先转成 3 通道因为 YOLO 训练时的输入是 BGR 三通道。clipLimit太大会放大热噪声建议 1.52.0 之间tileGridSize决定了局部对比度增强的粒度8×8 对 640 分辨率来说比较稳妥。经过 CLAHE 后再推理往往能找回 5%10% 的漏检框尤其是低照度环境下体温与背景温差较小的鸟类。5.4 针对该数据集的快速验证路径你可以直接拿验证集里几张典型红外图像分别用原始图和 CLAHE 增强图跑一次推理比较漏检目标的重叠情况yolo predict modelbest.pt sourceval_sample/ saveTrue conf0.25conf0.25是置信度阈值红外小目标置信度普遍偏低如果实测大量目标被滤掉可以下调到 0.15同时用 NMS 的iou0.4减小重叠框保留。调整阈值前先确认 val 集上的 mAP50 不低于 0.8否则调阈值没有意义问题仍在模型本身或训练数据。本文还有配套的精品资源点击获取