多光谱目标检测实战:YOLO可用的可见光与红外融合数据集精讲

张开发
2026/4/16 12:53:53 15 分钟阅读

分享文章

多光谱目标检测实战:YOLO可用的可见光与红外融合数据集精讲
1. 多光谱目标检测的核心价值与应用场景当你需要在夜间监控安防、自动驾驶或军事侦察等场景中实现精准目标检测时仅靠可见光摄像头往往会遇到致命短板。这时候可见光红外的多光谱方案就展现出独特优势——红外成像能穿透烟雾、无视光照条件而可见光提供丰富的色彩纹理信息。我在去年参与的智慧园区项目中就深有体会单纯RGB摄像头在夜间漏检率高达40%引入红外数据后直接降到8%以下。目前主流的多光谱数据集主要分为两类同步采集型如LLVIP数据集每张可见光图片都有严格配准的红外版本异步关联型像KAIST数据集可见光和红外图像来自不同传感器需要后期对齐这些数据集要适配YOLO训练需要解决三个关键问题标注格式转换VOC/COCO→YOLO txt多光谱数据对齐特别是异步采集的数据样本均衡处理解决昼夜数据量不平衡2. KAIST数据集深度解析与实战处理2.1 原始数据解剖与痛点分析KAIST作为最早开源的可见光-红外行人数据集包含95328张图像50187训练45141测试但直接使用会遇到几个典型问题数据冗余严重相邻帧差异极小视频抽帧导致标注质量参差存在person?等模糊标签昼夜分布不均夜间数据占比仅36%这是我整理的原始数据分布表子集时段场景数据量标注数set00白天校园17,49811,016set03夜间校园6,6687,418set04夜间公路7,20017,5792.2 数据清洗实战代码基于学术界主流做法我推荐这样的处理流程import os from PIL import Image def kaist_clean(raw_dir, output_dir, sample_interval2): 清洗KAIST原始数据 Args: raw_dir: 原始数据集路径 output_dir: 输出路径 sample_interval: 采样间隔 for subset in os.listdir(raw_dir): rgb_path os.path.join(raw_dir, subset, visible) ir_path os.path.join(raw_dir, subset, lwir) # 创建输出目录 os.makedirs(f{output_dir}/images/train, exist_okTrue) os.makedirs(f{output_dir}/labels/train, exist_okTrue) # 遍历并采样 for i, img_name in enumerate(os.listdir(rgb_path)): if i % sample_interval ! 0: continue # 过滤无目标图像 label_path f{raw_dir}/annotations/{img_name.replace(.jpg,.txt)} if not os.path.exists(label_path): continue # 复制有效数据 shutil.copy(f{rgb_path}/{img_name}, f{output_dir}/images/train/rgb_{img_name}) shutil.copy(f{ir_path}/{img_name}, f{output_dir}/images/train/ir_{img_name}) process_labels(label_path, f{output_dir}/labels/train/{img_name})关键处理步骤说明采样降频每2帧取1帧减少冗余负样本过滤删除无目标的空白图像标签统一将people/cyclist合并为person类3. LLVIP数据集YOLO格式转换3.1 数据集特性对比LLVIP相比KAIST有几个显著优势严格配准可见光与红外像素级对齐标注精确仅含person单类别规模适中30,976张图像适合快速实验def voc2yolo(voc_ann_path, output_dir): VOC转YOLO格式核心代码 tree ET.parse(voc_ann_path) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) with open(f{output_dir}/{os.path.basename(voc_ann_path).replace(.xml,.txt)}, w) as f: for obj in root.iter(object): cls obj.find(name).text if cls ! person: continue xmlbox obj.find(bndbox) b (float(xmlbox.find(xmin).text), float(xmlbox.find(xmax).text), float(xmlbox.find(ymin).text), float(xmlbox.find(ymax).text)) # 转换到YOLO格式 x_center ((b[0] b[1]) / 2) / w y_center ((b[2] b[3]) / 2) / h width (b[1] - b[0]) / w height (b[3] - b[2]) / h f.write(f0 {x_center} {y_center} {width} {height}\n)3.2 多光谱数据加载技巧在YOLOv5中加载双模态数据需要自定义Datasetclass MultispectralDataset(Dataset): def __init__(self, rgb_dir, ir_dir, label_dir): self.rgb_files sorted(glob(f{rgb_dir}/*.jpg)) self.ir_files sorted(glob(f{ir_dir}/*.jpg)) self.label_files sorted(glob(f{label_dir}/*.txt)) def __getitem__(self, index): # 加载双模态图像 rgb_img cv2.imread(self.rgb_files[index]) ir_img cv2.imread(self.ir_files[index]) # 通道拼接 [H,W,6] fused np.concatenate((rgb_img, ir_img), axis2) # 处理标签 labels [] with open(self.label_files[index]) as f: for line in f.readlines(): class_id, *coords line.strip().split() labels.append([int(class_id)] [float(x) for x in coords]) return fused, np.array(labels)4. 数据增强与模型训练策略4.1 多光谱专属增强方案针对红外数据的特性需要调整传统增强策略禁用色彩扰动红外图像不应做HSV增强同步空间变换对可见光和红外图像应用相同的翻转/旋转通道独立归一化# 在albumentations中的实现示例 transform A.Compose([ A.HorizontalFlip(p0.5), A.RandomBrightnessContrast(p0.2), # 仅对RGB通道 A.OneOf([ A.MotionBlur(p0.2), A.GaussNoise(p0.1), ]), ], additional_targets{image1: image}) # 对双模态同步处理4.2 YOLOv5/v8训练关键参数在data.yaml中需要特殊配置# 多光谱数据配置示例 nc: 1 # person类 channels: 6 # RGBIR三通道 names: [person] train: ../train/images val: ../val/images # 特殊参数 hsv_h: 0.0 # 禁用色相增强 hsv_s: 0.0 # 禁用饱和度增强 fliplr: 0.5 # 水平翻转概率启动训练时建议的指令python train.py --data multispectral.yaml --cfg yolov5s6.yaml --img 640 --batch 16 --epochs 100 --weights yolov5s.pt --hyp hyp.no-augmentation.yaml我在实际项目中发现当使用预训练权重时需要修改模型第一层卷积# 修改models/yolo.py中的Conv模块 if pretrained: # 原始RGB三通道权重 old_weights model.conv1.weight.data # 新权重初始化对红外通道取均值 new_weights torch.cat([old_weights, old_weights.mean(dim1,keepdimTrue).repeat(1,3,1,1)], dim1) model.conv1 nn.Conv2d(6, model.conv1.out_channels, kernel_sizemodel.conv1.kernel_size, stridemodel.conv1.stride) model.conv1.weight.data new_weights

更多文章