ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

360张热红外无人机图,玩转YOLO目标检测训练

360张热红外无人机图,玩转YOLO目标检测训练 简介面向目标检测开发者和无人机视觉研究者这份热红外无人机数据集包含360张带标签图像专为YOLO系列算法设计已按比例划分好附带的data.yaml可直接被YOLOv5至YOLO11等版本读取非常适合快速验证算法或入门练习。包体共1081个文件含360张JPG原图、360个YOLO格式TXT标签、360个VOC格式XML标签及1个YAML配置TXT标签为class x_center y_center width height归一化坐标XML兼容VOC工具链两种格式分文件夹存放便于按需选用。整个压缩包仅6.72MB现已有81人学习浏览轻量且下载方便拿到后即可直接训练和验证免去手动标注与格式转换聚焦模型调参和精度优化也适合做YOLO系列不同版本的效果对比或教学演示。1. 三百六十张热红外图凭什么敢直接上YOLO做无人机的都知道热红外相机跟可见光完全是两套逻辑夜里能看见人白天却分不清车和路。手里只有360张带标签的热红外无人机图像第一反应往往是“这也太少了吧怎么训”。但这类数据集在航拍工地、夜间搜救、电力巡检、安防巡逻里恰恰是常态——客户不会等你去攒一万张他们要的是今天拿到数据下周能出第一版检测模型。YOLO系列对数据量不挑剔的底子在这里反而成了优点360张图做单类别或二类别检测配合预训练权重和合理的数据增强完全能跑出一个能落地的初版模型。这篇文章就是冲着这一件事来的教你把“yolo算法-热红外无人机数据集-360张图像带标签.zip”从解压开始一路走到训练、验证、部署并把最容易被小数据集坑死的几个参数和习惯一次说透。适合正在做无人机视觉感知、夜视巡检或热成像目标检测的工程师。2. 热红外图像为什么让YOLO“水土不服”先把模态差异讲透2.1 灰度单通道、高温亮斑与低对比度热红外图的三个本质热红外相机输出的图像本质上是辐射温度场的量化映射大多数机载热成像模组返回的是单通道灰度或伪彩色图像。这意味着YOLO默认要求的RGB三通道输入需要先做通道复制或灰度归一化——常见做法是直接把单通道复制成三通道yolov8的ultralytics代码里对灰度图会自动做repeat处理所以即使你给的数据是灰度图也不会有通道报错。但真正影响检测的并不是通道数而是热红外的三个图像特性第一物体与背景的亮度差来自温差而不是反射率白天阳光下同一辆车可能和路面温度接近目标跑到背景里去了第二高温目标发动机、人体、烟囱在图上呈现亮斑状边缘是渐变的温度过渡带没有可见光图像那种清晰的纹理边缘第三夜间或冬季场景下整体动态范围窄直方图挤在一段低值区间里人眼看着黑漆漆一片模型同样容易把低对比度区域误判为背景。理解了这三点再去调数据增强和标注策略就有方向了。可别指望把可见光的SSD、Faster R-CNN那套经验原封不动搬过来——在热红外无人机图上翻车的第一个坑往往是相机位姿和温差方向一起变导致同一类目标的表观特征在训练集和验证集里差异极大。比如白天拍的人头是亮的到了傍晚变成暗的模型若只见过“亮人头”晚上必然漏检。2.2 模型选型在YOLOv5与YOLOv8之间怎么选360张图这个规模决定了你不能贪大。YOLOv8n和YOLOv5s是两类常用起点。YOLOv8n参数最少推理最快适合先跑通流程YOLOv5s的C3结构在低数据量下不容易过拟合而且yolov5的锚框策略对中低分辨率目标更友好。我个人习惯在热红外小数据集上先用YOLOv5s跑一轮基线再用YOLOv8n复现一次对比两者在val集上的mAP50和漏检率而不是一开始就押宝某个版本。选型还涉及另一个容易被忽略的点机载设备部署环境。如果你最终要跑在Jetson Nano或Orin Nano上yolov5导出TensorRT的生态更成熟int8量化踩坑资料多如果跑在树莓派这类ARM设备上yolov8通过onnxruntimeNCNN转换更省心。回到标题里的“yolo算法”它并不限定某个具体版本但版本选择的边界条件——显存、推理帧率、算子兼容性——是你在解压数据集之前就应该想清楚的事。2.3 红外特有的数据增强不要照搬可见光增强可见光数据集里用得风生水起的随机色斑、RGB通道偏移、饱和度抖动在热红外图上基本没有意义。灰度图没有颜色信息这些增强只会引入伪纹理。热红外图该用的增强是另一套组合拳直方图均衡模拟不同温标映射、亮度反相让冷目标变亮、高斯噪声模拟传感器热噪声、随机裁剪缩放模拟无人机高度变化。yolov5/v8的增强管线里hsv_h/hsv_s/hsv_v这三个参数对灰度图的影响集中在v亮度上建议把h和s直接关掉只保留v的小幅扰动否则模型容易把可见光经验带偏训练出来的权重在纯红外图上表现飘忽。除了这些内置参数还有一个增强方向值得尝试在离线阶段对原始图做CLAHE限制对比度自适应直方图均衡再训练。CLHE能拉伸局部对比度让低动态范围区域的边缘细节显出来。但注意增强是一把双刃剑——过度均衡会把原本均匀的温差过渡带变成“台阶状”伪边缘模型学到的是处理过的纹理而不是真实热分布真机上一部署就露馅。3. 解包数据集目录结构、标签检查与类别分布核对3.1 标准YOLO格式目录images/labels/train-val拆分的共识拿到这个zip后解压第一件事不是急着训练而是先确认目录结构。业界对YOLO格式数据集的通行约定是images/和labels/两个顶层目录各自再按train/val少数有test/划分子目录标签文件每行是“class x_center y_center width height”坐标都归一化到[0,1]。你手里这个数据集虽然叫“带标签”但不一定严格按这个结构打包常见做法是先写一段脚本把所有JPEG/PNG图片路径和对应TXT标签路径配对检查一遍。# 检查每个标签文件是否可读、是否为空、是否越界 #!/bin/bash ZIP_NAMEyolo算法-热红外无人机数据集-360张图像带标签.zip unzip -q $ZIP_NAME -d thermal_uav cd thermal_uav for label in $(find . -name *.txt | grep -v classes.txt); do if [ ! -s $label ]; then echo EMPTY: $label fi done echo Total labels: $(find . -name *.txt | grep -v classes.txt | wc -l)这段脚本做的事情有两个其一遍历所有TXT标签文件把大小为0的空文件列出来——空标签文件在后续训练里会参与loss计算产生一个没有目标的梯度容易把anchor往背景方向拉偏其二统计标签文件总数和图片数做对照。360张图对应360个TXT是理想情况如果两者不等说明有图片未被标注或者部分标签没有对应图片这两种情况都需要在训练前处理掉。3.2 用脚本核对标签类别编号、越界框与空标注目录结构没问题后下一步是检查标签内容本身。YOLO格式的标签文件里类别编号必须从0开始连续。比如一张图里标了“person”和“car”classes.txt里第一行person、第二行car标签文件里对应0和1。如果某个标签文件里写了class id5而数据集总共只有2个类别这个框在训练时会直接越界报错或静默丢弃。# 扫描所有txt标签报告越界框、非法class id、坐标非有限值 import os import numpy as np label_dir labels/train bad_files [] class_ids set() for root, dirs, files in os.walk(label_dir): for f in files: if not f.endswith(.txt): continue path os.path.join(root, f) with open(path, r) as fp: lines fp.readlines() if len(lines) 0: bad_files.append((path, empty)) continue for ln in lines: parts ln.strip().split() if len(parts) ! 5: bad_files.append((path, fbad_format: {ln})) continue cid, cx, cy, w, h int(parts[0]), *map(float, parts[1:]) class_ids.add(cid) if not (0 cx 1 and 0 cy 1): bad_files.append((path, fcenter_out: {cx},{cy})) if w 0 or h 0 or w 1 or h 1: bad_files.append((path, fwh_out: {w},{h})) print(class_ids:, sorted(class_ids)) for item in bad_files[:50]: print(item)越界框是无人机数据的常见毛病标注工具默认输出像素坐标转YOLO格式时忘记除以图像宽高就会出现cx0.5但w1200这样的非法值。这类框如果不清理训练时BGR损失直接崩成NaN而且极难定位到是哪个文件的问题——训练日志只报“image 142 loss is nan”不会告诉你第142张图是狗是猫。上面这段脚本会把问题文件具体路径列出来对到文件名就能快速修。3.3 小数据集热身先用train/val跑一轮别急着划分test360张图怎么划分常见误区是上来就按7:2:1切train/val/test最后一算train只有252张val 72张test 36张。36张的test集合本身就接近噪声统计出来的mAP置信区间宽得没法用。我的建议是先把360张按8:2切成train和valtest阶段先不用留。等模型收敛了再从验证集里抽一部分做最终盲测。还有一个比划分更前置的问题检查类别样本的平衡性。假设这个数据集的目标是“行人”和“车辆”可能车辆占了300个框行人只有80个框。这种情况下YOLO默认的BCE loss会让模型偏向多数类训练后期车辆mAP一路涨行人mAP卡在0.1不动。处理办法是给少数类加权——yolov8支持在data.yaml里用“class_weights”字段或者更简单的方式在训练时给少数类的图片重复采样。但重复采样要控制倍数2倍以内是安全区翻太多反而让模型对同一批图死记硬背。4. 用YOLOv8在本地跑通热红外无人机检测最小训练配置与六个参数4.1 写一个只属于这个数据集的data.yaml目录结构清理完后第一个该动手写的是data.yaml。不要复制别人仓库里的通用配置这份文件里的“names”必须和你实际标注的类别一一对应。假设数据集里有两类person和car那么names写成“[person, car]”注意顺序必须和标签文件里的class id一致顺序错了模型不会报错只是预测输出张量的索引对不上后处理时0变成车、1变成人。# thermal_uav.yaml path: ./datasets/thermal_uav # 数据集根目录请改成你的实际路径 train: images/train val: images/val names: 0: person 1: cartrain和val字段在yolov8里支持相对路径和绝对路径两种写法。相对路径严谨依赖“path”字段绝对路径写法直白但不可移植——你换台机器就得改YAML稍不留神就变成“在我电脑上能跑”的僵尸配置。我一般写成上面这种相对结构并在训练命令里用“cd”到数据集根目录的上一级再启动。这是个小习惯但能省很多跨机器复现的麻烦。4.2 训练命令从迁移学习权重起步360张图从头训练等于自杀必须做迁移学习。yolov8默认下载yolov8n.pt做预训练这个权重是在COCO上训出来的虽然COCO没有热红外模态但底层特征提取器里的边缘、纹理、形状基元仍然可用。启动命令如下cd ~/thermal_uav_project yolo detect train \ modelyolov8n.pt \ datathermal_uav.yaml \ imgsz640 \ epochs200 \ batch16 \ patience30 \ project./runs \ namethermal_exp01这段命令的意思是用COCO预训练的yolov8n.pt作为起点在thermal_uav.yaml定义的数据集上按640×640分辨率训练200轮batch size为16如果连续30轮val精度没有任何提升就早停所有结果记录在runs/thermal_exp01目录下。对实验记录不敏感的读者可能会忽略“project/name”这两个参数但它们在对比实验时极其重要——每次跑新的参数组合换一个name值原始结果就不会被覆盖后面对比曲线有大用。4.3 六个值得手动调的参数imgsz、epochs、batch、mosaic、patience与lr六个参数里有四个我建议按下面这个原则调imgsz热红外无人机图分辨率往往在640×512或384×288本来就不高强行resize到1280只会让模型看到一堆插值假纹还把显存吃干净。640是一个均衡值但如果你的目标框普遍很小比如一张图上人只占30×30像素建议试一次imgsz896或960小目标检测的提升往往在分辨率增大的一瞬间就能看到。epochs360张图配200个epochs是合理范围但要注意配合早停。如果数据增强强、目标小训练到150轮还在缓慢上涨是正常的如果50轮就收敛不动了不是好事就是坏事——好事证明任务简单坏事证明模型死记硬背了训练集。看train/loss和val/loss的曲线走向再判断。batchbatch大小直接决定BN层的统计质量。小数据集上batch16是底线再小比如batch4BN跑在噪声很大的统计量上模型会抖得很厉害。如果你的GPU只有6GB显存把batch降到8同时把imgsz降到480效果往往比硬撑640×640batch4更好。mosaicyolov8的mosaic增强对通用目标检测很有效但在小目标和极小数据集上可能适得其反——四张图拼一起物体被缩放得更小标注框错位概率升高模型学到的上下文是割裂的。对360张图这样的规模我倾向把mosaic关闭在ultralytics里设置mosaic0.0或者只在训练后半段通过close_mosaic参数关闭。这个细节在5.4节会展开讲。patience小数据集上的过拟合来得很快patience50有风险模型可能早在100轮时就已经把训练集背下来了后面50轮全靠早停机制往回拉。设30比较谨慎20也算合理。lryolov8默认lr00.01配合cosine衰减在多数场景可用。但小数据集有一个常见情况——预训练权重在源域COCO和目标域热红外之间的feature分布差异大默认学习率容易让模型一开始就大步走在错误的梯度方向上。建议设为0.005以下效果不理想再往上调。4.4 验证输出从val_batch预测图看什么训练结束后进入runs/thermal_exp01目录会产生一组val_batch*.jpg。这些图是模型在验证集上的预测可视化红框是预测结果绿色框是真实标注重叠部分。不要只看mAP数字直接盯这几张图里的三类现象第一有没有框到背景高亮区——热红外图里轮胎、地面反光常常被误检成“人”这类误检mAP50算不出来但在实际部署中是致命伤第二小目标有没有漏框——看图像上方的远距离目标如果预测框零零星星说明小目标那一栏的AP很低第三相邻目标有没有被合并成一个框——无人机俯拍时两个人的热辐射重叠模型常常只画一个框。把这三个观察记下来再决定要不要调anchor或增强比起单看一个mAP值靠谱得多。5. 360张红外图的五个坑从漏检到过拟合的翻车实录5.1 红外行人成了“半个人”环境温度造成的标注边界分歧现象训练集里清晰完整的人形目标在验证集里被标成了半个框模型完全学不到完整轮廓。原因热红外图像里人的边界取决于人与背景的温差。夏天中午人比地面凉呈现为暗色人形边缘清晰到了傍晚地面散热快人反而比地面热亮度反转边缘过渡带变宽。不同时间采集的图像上“同一个人的边界”在像素级上根本不一致。如果标注员按可见光的习惯把整个轮廓包进去落在温差过渡带里的像素其实是环境温度模型学到的是“带环境晕圈的人”。解决约定标注规则时只框核心高温区躯干头部不要包含过渡带。如果标签已经打好了可以做一次形态学腐蚀把每个框向内缩3~5个像素再训练。这个做法牺牲了一点点定位精度但换来的是边界一致性实测mAP通常能涨2~3个点。5.2 无人机视角的图幅差异分辨率不统一引发的锚框匹配震荡现象训练loss在100轮以后仍然锯齿状抖动val mAP一直在0.2~0.3之间波动上不去。原因无人机飞行高度不固定导致同一目标在图中的尺寸跨度极大——20米高度行人占200×80像素100米高度只占30×15像素。YOLO的锚框是在数据分布上统计出来的如果训练集里大目标多一些锚框整体偏大小目标匹配不到合适的anchor损失函数在小目标上每次回传的梯度方向和大小都不稳定loss自然抖。解决先跑一段统计脚本打印所有GT框的宽高分布。如果发现宽度在[0.05, 0.5]之间分布极不均匀建议在data.yaml里用“anchors”字段手动指定3组小尺度锚框比如针对640分辨率设[4,4,8,8,12,12]或者在训练命令里加anchor_mse0关闭自动锚框计算。改完以后loss曲线通常会明显变滑。5.3 夜间场景几乎全黑注释亮度区间或做直方图均衡现象训练集里混入夜间图像后loss正常但检测结果全空白验证集mAP0。原因夜间热红外图动态范围极窄比如整张图的像素值集中在30~808bit灰度YOLO的大卷积核在这样低对比度的输入上提取不到有效梯度等于在喂噪声。解决分两步走——第一步先画灰度直方图确认图像分布区间第二步离线对所有夜间图做CLAHE或线性拉伸把[30,80]映射到[0,255]。还有一个更通用的做法是在数据增强里把RandomBrightnessContrast的contrast_limit提高如[0.3, 0.5]但注意训练和推理时的预处理要一致比如都在模型输入前做同样的拉伸否则模型权重学到的映射关系在部署时对不上。这里没有玄学就是输入分布对齐的问题。5.4 目标小、图又多mosaic增强在小物体上的反效果现象开启默认mosaic时训练到80轮val mAP50从0.5掉到0.4关了mosaic恢复。原因mosaic把四张图缩放后拼在一起小目标如30×15像素的行人拼完之后可能只剩15×7像素标注框和真实目标间的IoU计算噪声急剧增大模型学到的基本是噪音同时热红外图拼图后相邻图的温差区域互相污染产生大量虚拟的热斑伪目标。解决关掉mosaic或设置close_mosaic10最后10轮关闭是稳妥做法。你可以在训练命令中直接加上“mosaic0.0 close_mosaic0”来彻底关闭。替代方案是新增Scale和RandomAffine增强模拟无人机高度变化会比mosaic更适合小物体场景。5.5 验证集卡在0.3 mAP50还能不能继续用先查类别分布再下结论现象训练完验证集mAP50只有0.32但看val_batch预测图又觉得模型检测得还行不知道该不该调参重训。原因小数据集的mAP对验证集划分极其敏感。360张图按8:2划分后72张验证图里类别分布可能跟训练集差异很大——比如验证集里“car”多、“person”少而模型对car学得本来就不够mAP自然被拉低。解决先算出每张验证图的GT框数量和类别分布如果发现person只有几十个框mAP50在0.3这个水位其实已经算正常。这时候不要盲目加epochs而应该去扩充person类别的样本或调整类别权重。我自己在这个阶段常常做一件事统计mAP走查每个类别的AP值若person AP0.5而car AP0.15那问题集中在car而不在整体——直接针对car补充数据或调损失权重。6. 落地不只是跑通模型导出、部署验证与数据扩展策略6.1 导成ONNX/TensorRT把训练权重变成能在机载设备跑的格式训练完的.pt权重不能直接上无人机机载设备ultralytics提供了标准导出链路yolo export modelruns/thermal_exp01/weights/best.pt formatonnx opset12 yolo export modelruns/thermal_exp01/weights/best.pt formatengine device0第一次导出engine会做逐层校准耗时取决于GPU导出后验证一下engine输出和onnx输出是否一致常见做法是在同一个验证集上跑一遍推理对比检测框坐标偏差超过1%就得检查量化精度损失。对Jetson这类设备TensorRT的fp16通常能在不损失精度的情况下把推理速度拉到接近实时int8要慎用热红外图的动态范围窄int8量化后背景和目标的灰度差进一步压缩漏检率会明显上升。6.2 用视频序列验证时序稳定性漏检率比mAP更真实拿到engine模型后不要只测单张图片接一个无人机视频序列连续推理300帧重点看两个指标单帧漏检率和跨帧框抖动。热红外图像噪声大同一个目标在相邻帧里可能一帧检出、一帧丢失形成“闪烁”现象——这在单帧mAP上完全看不出来但对实际巡检/搜救任务是不可接受的。解决办法是给后处理加一个简单的时序滤波目标在当前帧丢失时用上一帧位置做线性外推补一帧连续丢失超过5帧才判定目标真正消失。实现上可以维护一个目标轨迹列表用IoU匹配相邻帧检测框这个逻辑用几十行Python就能写完但部署价值远高于在测试集上多抠那0.05的mAP。6.3 给这批360张图“续命”伪标签挖掘与可见光-红外联合自步方法360张图训出来的模型边界上限摆在那里。想再往上走两条路最实在一是把这批模型拿去对同一场景的未标注热红外视频做推理把置信度高于0.9的检测框保存为伪标签人工抽检修正后并入训练集——这叫伪标签挖掘热红外无人机场景里背景相对固定伪标签的准确率通常比想象中高二是如果同一架无人机还挂了可见光相机可以先用成熟的可见光检测模型拿到框再把可见光图像与红外图像做配准把框迁移到红外图上省去大量人工标注。这两条路都能让360张图的初始数据集在两周内膨胀到2000张以上而模型的泛化能力也随之稳定。我现在的习惯是拿到任何小规模红外数据集第一件事先把“能否复制标注到相邻帧/相邻模态”想清楚而不是闷头调参。数据集本身的规模是死的但利用效率是活的。最后也算一句过来人的教训小数据集训练时改一次参数就换一个name目录跑训练完先开val_batch看图再决定下一步别让自动调参脚本替你盲目跑几十个组合那是对硬件和时间的双重浪费。希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进