资讯动态

无人机红外小目标检测:HIT-UAV数据集与YOLOv8训练实践全指南

发布时间:2026/10/13 11:03:19 来源:尧图企业网站定制
简介HIT-UAV红外小目标数据集是一套专为无人机航拍场景下红外小目标检测任务设计的数据资源面向计算机视觉、遥感图像处理等领域的研究者与算法工程师。内容覆盖学校、停车场、道路、游乐场等多种地面场景基于43470帧原始视频提取出2898幅红外热图像并包含飞行高度60至130米、相机视角30至90度、白天与夜间不同光照等多样化条件能够支撑小目标检测、跟踪及多场景泛化研究。压缩包共包含2002个文件以XML标注文件为主共1994个另有txt文件用于训练集、验证集、测试集划分以及Python格式的标注转换脚本和说明文档整体体积约192.88MB目录结构清晰便于直接解压使用。该数据集已吸引1520人学习浏览适合需要标准化红外小目标数据来验证算法性能的科研与工程实践者获取使用。1. HIT-UAV无人机红外小目标检测入门的第一个像样数据集做过目标检测的人迟早会遇到一个尴尬模型在公开彩色航拍数据集上表现不错一换到无人机红外视角就明显失效。原因倒不是模型结构差而是红外小目标检测需要一套真实无人机航拍、带精确标注的红外基准数据这类资源在几年前还非常稀缺。HIT-UAV 就是为这个场景公开的数据集之一它来自高校研究团队采集了不同飞行高度下的无人机红外图像标注了行人、自行车、汽车等类别大量目标在画面中的面积占比极低恰好踩中小目标检测最难受的区域。这篇文章会把它的数据格式、整理方法、训练参数和常见坑一次讲清适合正在做无人机巡检、红外夜视或者小目标检测方案的工程师。2. HIT-UAV 到底是什么数据组成、标注格式与任务适配边界2.1 一张图像对应一个 txtHIT-UAV 标注格式与坐标含义HIT-UAV 的基本单位是一张红外图像文件和一份同名 txt 标注文件。图像通常是 JPEG 格式标注文件里每行描述一个目标格式遵循 YOLO 标准类别 id、归一化中心点 x、归一化中心点 y、归一化宽 w、归一化高 h。拿到压缩包后第一件事不是直接训练而是把标注格式确认清楚尤其要确认坐标是不是归一化的。不少第三方分享版本会在转换时把坐标写错直接把像素坐标塞进 txt表面看格式一样训练时框的位置却全部偏移。给你一个随手可用的检查思路先随机打开几个 txt看坐标值域。如果所有值都落在 0 到 1 之间大概率是归一化坐标如果出现大于 1 的数字说明文件里存的是绝对像素值需要在训练前统一转换。还有一种半坑状态是坐标大多数在 0-1 区间但偶尔有几个大于 1这种通常是标注工具边界处理不当造成的越界框训练时会被 YOLO 直接忽略或裁剪导致有效标注数量少于文件行数。数据集里除了图像和标签通常还附带元信息文件记录每帧的拍摄高度、采集环境、目标遮挡状态等内容。对普通训练来说这些字段不是必需的但对分析实验结果很有用。比如某一帧的 mAP 突然下降先看元信息里是不是特殊高度或特殊天气再决定要不要调整训练采样权重。很多人在这一块偷懒结果把数据分布问题误判成模型能力问题。2.2 红外小目标为何难识别目标尺度、背景干扰与伪彩色映射红外图像和可见光图像有本质差异。可见光图像里目标有丰富的颜色和纹理信息而红外图像主要靠温度差异形成轮廓目标与背景的灰度差往往很微弱加上伪彩色映射后原本就弱的纹理信息进一步被压缩。你在训练时如果把红外伪彩色图当成普通三通道真彩图处理沿用 ImageNet 的归一化统计量很多暗部细节会被直接压掉模型学到的东西也会偏离实际分布。HIT-UAV 的难度更多来自目标尺度。低空帧里一个行人可能还有几十个像素宽到了较高飞行高度行人在画面里往往只剩几个像素有些甚至只有三五个像素的灰度团块。这种目标在特征图上下采样四五次之后就基本消失了常规检测头根本拿不到有效信息。与此同时数据里跨尺度跨度非常大同一批训练数据既有大目标也有极小目标模型需要同时在浅层高分辨率特征图和小感受野上做预测这对特征金字塔的设计和标签分配策略都是直接考验。另一个容易被忽略的问题是背景复杂度。无人机视角下的地面场景包含道路、树木、屋顶、车辆阴影等大量干扰红外图像里这些背景的温度轮廓会形成无数假目标候选。小目标检测的困难不仅在于目标本身小更在于背景里像目标的碎片太多模型要在噪声中找到真正有温度差异的局部区域。2.3 哪些任务适合用 HIT-UAV与通用目标数据集的对比选择在动手训练之前先想清楚 HIT-UAV 适不适合你的任务能省下几天白折腾的时间。它的适用场景很明确无人机视角下的人车目标检测、红外夜视场景的监控识别、小目标检测算法的基准验证以及多尺度检测网络在跨高度场景的泛化测试。它的高度跨度让模型必须学会跨尺度检测这是常规可见光数据集很难提供的。不合适的场景也很清楚。如果你的应用是密集行人计数HIT-UAV 的标注密度明显不足如果目标是船只、无人机或者其他特定装备它根本没有对应类别如果只需要检测画面中央的大目标它的难度反而会干扰你的实验结论。用一张对比表可以更直观看清它的边界对比维度HIT-UAV常规可见光航拍数据普通红外地面监控数据目标尺度极小到中等跨幅大中等偏大中等到大背景复杂度高温度轮廓噪声多中等较低适合任务无人机巡检、小目标检测通用航拍检测地面固定监控数据获取难度公开但数量有限较多公开集多数不公开简单说HIT-UAV 的价值在于把小目标检测和无人机视角这两个难点叠加在一起。如果你的任务没有这个组合需求用它不一定是最优选择反过来如果你正好卡在这个组合上它就是当下少有的直接可用资源。3. 把 HIT-UAV 整理成可训练的目录下载后的三步校验3.1 数量校验图像和标签是否一一对应下载解压之后第一步永远是数量校验。不同渠道分享的 HIT-UAV 版本文件组织方式可能有差异有的直接分好了 train 和 val有的把所有文件摊在一个目录里还有的会在传输过程中丢文件。不校验就直接训练轻则缺了一部分标注重则图像与标签错位导致模型学到完全错误的信息。一个最基础的校验脚本长这样from pathlib import Path def verify_pairs(image_dir, label_dir): imgs {p.stem for p in Path(image_dir).glob(*.jpg)} labels {p.stem for p in Path(label_dir).glob(*.txt)} missing_labels imgs - labels orphan_labels labels - imgs print(f图像数量: {len(imgs)}) print(f标签数量: {len(labels)}) print(f缺少标签的图像: {sorted(missing_labels)[:10]}) print(f没有图像的标签: {sorted(orphan_labels)[:10]}) return not missing_labels and not orphan_labels verify_pairs(hit-uav/images/train, hit-uav/labels/train)这段代码分别把图像文件名和标签文件名的文件主名收集成集合再比较差异。注意这里只比较 stem 即去掉后缀的文件主体部分不能直接比较完整文件名因为 jpg 和 txt 后缀不同全名比较必然全是差异。脚本的输出会直接列出缺哪些文件的标注以及哪些标注没有对应图像。如果发现数量对不上先重新解压排除压缩包损坏的可能。如果重新解压后仍然缺失就要对照数据集原始发布说明确认是否有些帧本身就故意不配标签——这类帧通常在文档里被标记为难例或纯背景负样本需要你自己决定是删除还是保留。最忌讳的做法是自己编造标签补齐数量脏数据一旦进入训练集后续排查会非常痛苦。3.2 避免数据泄漏按视频片段分组而不是随便随机划分如果下载版本已经分好了 train 和 val先别高兴你需要验证划分方式。HIT-UAV 这类无人机数据集通常来自连续视频抽帧相邻帧之间的场景几乎一样。如果当初划分时直接按帧随机打散同一段飞行视频的前一帧可能进了训练集后一帧进了验证集验证集里全是模型已经见过的场景mAP 会虚高五到十个点等部署到真实连续视频上立刻现原形。更可靠的划分方法是按视频片段分组而不是按单帧划分。常见做法是先提取文件名里的场景编号或者采集批次号把属于同一个批次的帧聚成一簇然后以簇为单位划分数据。如果发行版本没有直接提供批次信息可以通过文件名中的连续编号特征推断比如编号前三位相同的帧属于同一段采集单元就按这个前缀分组。下面是一个按文件名前缀分组的划分脚本模式可以灵活调整import random from pathlib import Path import shutil random.seed(42) img_dir Path(hit-uav/all_images) train_dir Path(hit-uav/images/train) val_dir Path(hit-uav/images/val) label_dir_all Path(hit-uav/all_labels) # 提取每个文件所属的片段 id这里假设文件名前 6 个字符代表一个片段 groups {} for img_path in img_dir.glob(*.jpg): group_id img_path.stem[:6] groups.setdefault(group_id, []).append(img_path) # 先收集片段 id按 8:2 划分片段而不是划分帧 group_ids list(groups.keys()) random.shuffle(group_ids) split_idx int(len(group_ids) * 0.8) train_groups set(group_ids[:split_idx]) val_groups set(group_ids[split_idx:]) for img_path in img_dir.glob(*.jpg): group_id img_path.stem[:6] target_img_dir train_dir if group_id in train_groups else val_dir target_lab_dir Path(hit-uav/labels/train) if group_id in train_groups else Path(hit-uav/labels/val) target_img_dir.mkdir(parentsTrue, exist_okTrue) target_lab_dir.mkdir(parentsTrue, exist_okTrue) shutil.copy(img_path, target_img_dir / img_path.name) lab_path label_dir_all / (img_path.stem .txt) if lab_path.exists(): shutil.copy(lab_path, target_lab_dir / lab_path.name)这段代码的核心逻辑是先把所有图像按文件名前缀分组再把分组后的 id 打散并分成训练和验证两部分最后把整组文件复制过去。注意我特意在开头设置了 random.seed(42)保证每次跑结果一致方便复现实验。前缀长度 6 只是个示例值具体由数据集文件名的命名规则决定实际使用时先打印几个文件名观察规律再定。3.3 画框验证标注到底落在哪里只有可视化最直观数量校验过了、分组划分也做了还不算完。我曾经被一份格式完全正确但坐标全部偏移的标注坑过整整两天。所以第三步必须做可视化随机选几张训练图把标注框按坐标画回去肉眼检查框是否贴合目标边缘。下面这段脚本可以实现快速的画框检查import cv2 from pathlib import Path def draw_yolo_boxes(img_path, label_path, class_namesNone): img cv2.imread(str(img_path)) h, w img.shape[:2] for line in Path(label_path).read_text().strip().splitlines(): parts line.split() cls int(parts[0]) x_c, y_c, bw, bh map(float, parts[1:5]) x1 int((x_c - bw / 2) * w) y1 int((y_c - bh / 2) * h) x2 int((x_c bw / 2) * w) y2 int((y_c bh / 2) * h) color (0, 255, 0) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) if class_names: cv2.putText(img, class_names[cls], (x1, max(0, y1 - 5)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1) return img sample draw_yolo_boxes( hit-uav/images/val/000123.jpg, hit-uav/labels/val/000123.txt, class_names[person, bicycle, car, other vehicle] ) cv2.imwrite(hit_uav_check.jpg, sample)脚本的原理是用图像实际宽高把归一化坐标还原成像素坐标再在图像上画矩形框。需要留意的细节是画框用的颜色通道顺序OpenCV 读取的是 BGR 顺序和日常看到的 RGB 习惯相反如果输出图像红蓝反了不要惊讶那是通道顺序问题。真正需要警惕的是框是否明显偏离目标或者框的大小与目标实际尺寸严重不符。如果框大致在目标附近但边缘飘忽很可能是归一化和反归一化之间多乘了一次宽高如果框完全乱飞优先检查 txt 里是否混入了负样本或者越界坐标YOLO 对越界框的处理策略是裁剪到边界这会让可视化结果看起来像是框偏了。4. 在 YOLOv8 上训练 HIT-UAV配置、命令和参数调试4.1 数据配置与第一个能跑起来的训练命令当目录结构整理好后数据配置是下一步的关键。用一个 data.yaml 文件描述数据集路径、训练集位置、验证集位置和类别名称就能直接接入 YOLO 训练流程。path: /data/hit-uav train: images/train val: images/val names: 0: person 1: bicycle 2: car 3: other vehicle这里的path是数据集根目录的绝对路径train和val是相对路径不要写成/data/hit-uav/images/train这种带根目录的完整路径YOLO 会自动拼接。names的排列顺序必须和标签文件里的类别 id 完全一致顺序错一位意味着所有标签整体错位训练出来的模型类别全乱。配置没问题后先跑一个最小验证命令yolo train datahit_uav.yaml modelyolov8n.pt epochs50 imgsz640 batch8 device0modelyolov8n.pt选的是最小模型先跑通流程再换大模型可以省下不少试错时间。imgsz640是默认分辨率batch8在 12GB 显存上是安全值如果显存只有 8GB把 batch 降到 4。device0指定使用第一张显卡没有 GPU 可以改成devicecpu但训练时间会成倍拉长。第一次运行会自动下载预训练权重如果网络较慢建议提前把权重文件手动下载放入本机缓存目录离线环境也可以用yolo export生成相应权重再复用。4.2 影响小目标 mAP 的关键参数分辨率、增强与类别权重HIT-UAV 这类小目标数据集参数设置和常规目标检测有明显差异。第一个要改的就是输入分辨率。红外小目标在 640 分辨率下往往只有十几个像素经过特征图多次下采样后信息接近丢失把 imgsz 提高到 960 或 1280 是提升小目标召回率最直接的手段。但分辨率提上去显存占用也会跟着涨训练速度变慢需要根据显卡实际容量做取舍。第二个比较隐蔽的是 mosaic 增强。YOLOv8 默认开启 mosaic 数据增强把四张图缩略后拼成一张这对常规目标能提升泛化能力但对小目标反而是反效果四张图缩小后目标变得更小模型更难学到有效特征。我的常见做法是保留 mosaic 但把概率降到 0.5 左右如果训练中后期 mAP 持续抖动就索性设为 0.0让模型专注学习原始尺度的目标。第三个是类别不平衡问题。HIT-UAV 里不同类别数量差异较大直接训练时数量占优的类别会主导 loss小类别目标学不到足够特征。处理方式有两种一是对少数类别做重复采样在 DataLoader 里给少数类样本更高的采样概率二是调整 loss 中的类别权重参数让少数类在计算损失时占比更大。实际经验是重复采样的效果通常更好因为它不只是放大损失还给模型提供了更多真实样本。第四个是置信度阈值评估。小目标检测模型在低置信度区域往往藏着大量正确预测如果评估时用默认的置信度阈值会把这些正确结果当噪声滤掉。调参数时可以把验证阶段的conf_thres降到 0.01单独看模型的极限召回能力再根据实际部署需求选择合适的截断线。这样就不会被默认阈值下的 mAP 误导避免误判模型能力。4.3 训练日志怎么看loss 曲线、过拟合判断与显存预算训练跑起来之后不要把终端关掉就不管了。YOLO 训练日志里输出包含 box_loss、cls_loss、dfl_loss 以及每轮验证后的 mAP需要重点关注的是 loss 曲线的走势而不是某一个数值。正常训练的标志是训练 loss 持续下降并趋于平稳验证 mAP 同步上升后进入平台期。如果训练 loss 下降但验证 mAP 不升反降先怀疑数据划分是否有问题再怀疑是否过拟合。显存预算是另一个实操问题。把输入从 640 提到 1280特征图面积变成原来的四倍激活值显存占用也近似四倍。以中小规模模型为例640 分辨率下 batch16 大约需要 10GB 显存1280 分辨率要维持同样 batch显存需求会接近 40GB。没有大显存时推荐折中方案imgsz960、batch8这个组合在小目标召回率和训练成本之间相对平衡。需要提醒的是提升 imgsz 并不等于把目标变大。YOLO 训练时会做 letterbox 等比缩放如果原图是 1080×540设成 1280 后图像会被等比放大加边实际目标尺寸增量有限但计算量暴涨。更好的做法是先看数据集原图的分辨率选择一个接近原始宽高的值比如 960 或 832让网络直接看到原始像素信息而不是靠加边填充的方式硬撑分辨率。5. HIT-UAV 使用避坑指南五个典型问题和排查思路5.1 训练很久 mAP 却始终在 30% 附近徘徊这是命中率最高的一个现象。训练流程正常、loss 正常下降但验证 mAP 就是上不去。原因通常是标签坐标系没搞对。HIT-UAV 的 txt 本来是归一化坐标但某些第三方转换脚本会把坐标按像素值直接写入导致框的位置整体偏移。排查顺序是先做可视化检查确认框的分布是否合理如果框大致对但 mAP 仍低再看输入分辨率是否过小最后检查数据增强里是否同时开了多个对目标尺度不友好的策略比如强缩放配合强裁剪会把小目标破坏得面目全非。5.2 图像和标签数量对不上训练时不断警告缺标签YOLO 在训练时如果发现某张图没有对应标签会跳过该图并打印警告。这种现象在数据集刚下载时尤其常见。原因大概率出在解压或传输环节少数文件损坏或丢失。解决方法是重新下载原包对比文件完整清单不要手工伪造标签。另一种情况是发行版本中部分帧根本没有目标实例这些帧被当作纯背景负样本使用区分方式是查看发布说明中是否明确列出这部分文件的用途。5.3 训练过程正常但预测结果全部集中在某一个类别现象是精确率高、召回率极低模型输出几乎全是单一类别。这种问题九成出在 names 顺序上。如果 HIT-UAV 的原始标签里类别 0 是 person而你的 yaml 里类别 0 写成了其他类别所有标注都会错位模型学到的类别语义完全错误。解决办法是统计整个数据集每个类别 id 出现的框数量再和官方说明做对比偏差大的几乎可以确定是顺序问题。还有一种情况是标签文件里出现了超出 names 数量的类别 id这类行会被训练框架静默忽略导致该类别目标相当于没有参与训练。5.4 用 ImageNet 归一化统计量处理红外伪彩色图暗部细节被压低很多训练代码直接使用 ImageNet 预训练模型的归一化参数这些参数的来源是千万张自然图像而 HIT-UAV 是红外伪彩色图通道统计特征完全不同。硬套这组参数会把红外图像中温度细节差异压缩目标与背景的对比度进一步降低。我的习惯是统计数据集自身的均值和方差写入归一化层参数或者直接关闭归一化让网络学习原始像素分布。前者收敛快后者最终漏检率低建议在训练前做两次小规模实验对比再决定正式方案。5.5 验证集 mAP 虚高但在真实连拍视频上大量漏检这是最隐蔽也最致命的问题。原因几乎都是数据泄漏。如果训练集和验证集来自同一段视频的相邻帧模型在验证时等于看到了同一个场景的近似画面指标自然好看。解决思路是回到 3.2 的片段分组方法确保验证集里的场景从未出现在训练集中。判断当前数据是否泄漏有一个简单的实验方法单独拿一段完全不在数据集里的无人机红外视频做推理对比验证集上的表现如果差距过大说明大概率存在泄漏。6. 走出数据集用小目标分段指标和负样本测试判断真实可靠性把 HIT-UAV 训练完距离真正可用还差最后一步评估。我习惯先导出 ONNX 模型跑一次完整验证集推理把预测框和真值框同时可视化按目视检查小目标聚集区域和边缘遮挡位置而不是只看 mAP 曲线。接下来一定要做的是按目标尺寸拆开统计。把验证集中所有目标按像素面积分段比如小于 32×32 的算极小目标32×32 到 96×96 的算中等目标大于 96×96 的算较大目标分别计算召回率。HIT-UAV 这类跨高度数据集如果不做分段统计小目标检测能力很容易被大目标拉高的整体指标掩饰。你会发现模型可能在中等目标上表现不错但极小目标召回率还不到一半这种差距只有分段统计才能暴露。按飞行高度分组也有价值低空和高空数据分开评估能看出模型的尺度泛化能力到底在哪一层失效。如果部署场景是真实无人机巡检加一轮负样本测试也很有必要。找一段完全没有目标的地面红外视频喂给模型统计误报数量。小目标检测模型在纯背景上的误报往往远超预期——那些看起来像人的温度团块可能是地面发热点、汽车引擎盖或者路灯灯罩模型都会给出高置信度的假预测。这一步能直接指导部署时的置信度阈值设计也能帮你判断模型是否过度拟合了训练集的背景纹理。我的个人习惯是每次训练完都把这组评估结果存档分段 AP、高度组召回率、负样本误报数量存档后和上一版对比。只有这三项指标同时好看模型才敢拿去现场测试光看单个 mAP 曲线决定上不上线迟早要出问题。希望这套验证思路能帮到你少走一些我当年走过的弯路。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑