☰
多模态图像数据集实战:红外、可见光、高光谱与SAR拆包配对与训练
2026/10/16 9:40:08 网站建设 项目流程

简介:这份图像合集面向遥感图像处理的学习者与研究者,整合了红外、可见光、高光谱与SAR四类典型数据,可用于图像融合、地物分类与目标识别等实验场景。压缩包共56个文件,约68.12MB,以jpg、bmp、tif等图像格式为主,另含mat数据文件、m脚本、hdr与dat等配套元数据,以及txt说明和docx文档,覆盖从原始影像到处理代码的完整链路。其中高光谱部分包含Indian Pines与PaviaU实验样本、地面验证数据及MATLAB读取程序,红外与可见光部分提供已配准的融合数据集,SAR部分为高分三号影像,便于直接开展算法验证。目前已有3795人学习下载,适合作为教学演示、课程设计或科研预研的素材,帮助读者快速理解多源遥感数据的组织方式与处理流程。

1. 一个压缩包里的四种“眼睛”:红外、可见光、高光谱、SAR 图像合集到底怎么用

拿到一个名为“图像合集(红外、可见光、高光谱、sar图像).zip”的压缩包,第一反应往往不是兴奋,而是发懵:四种模态混在一起,分辨率不一样、通道数不一样、标注格式可能也不一样,直接解压丢进训练脚本,大概率在第一个 batch 就报错。这个合集真正解决的不是“有没有数据”,而是“能不能把不同物理成像机制的数据对齐到同一个任务里”。红外看热辐射,可见光看反射,高光谱看连续波段,SAR 看微波后向散射,它们对同一场景的描述是互补的,但互补的前提是你得先把它们拆开、配对、归一化。适合谁?做多模态融合检测、遥感地物分类、夜间或恶劣天气感知的从业者,以及想验证自己模型跨模态鲁棒性的算法工程师。这一章先把四种模态的物理含义和工程差异讲清楚,后面再动手拆包和配对。

2. 拆包前先认清四种模态:物理差异决定预处理路线

2.1 红外与可见光:像素对齐容易,辐射含义完全不同

红外图像记录的是目标自身的热辐射,常见的是长波红外 8~14 微米,输出通常是单通道灰度,像素值反映温度差异。可见光图像记录的是反射光,通常是三通道 RGB,像素值反映颜色和亮度。两者在空间上可以对齐,但同一位置的像素值没有任何数值可比性。我一般会先把红外图归一化到 0~1,再复制成三通道,或者用一层卷积把单通道映射到三通道,而不是直接把红外当灰度图塞进 RGB 网络。常见做法是:红外分支单独走一个 backbone,可见光分支走另一个,在中间层做特征融合,而不是在输入层拼接。

2.2 高光谱:通道数是双刃剑,降维和波段选择是必修课

高光谱图像通常有几十到几百个连续波段,每个像素是一条光谱曲线。它的优势是能区分“看起来一样但材质不同”的地物,代价是数据量大、波段间冗余高、标注成本极高。直接拿高光谱全波段去训练,显存和过拟合会同时找上门。我一般会先做两件事:一是按任务选波段,比如植被分类关注红边和近红外,水体关注可见光到近红外;二是用 PCA 或波段指数做降维,把几百个通道压到十几个再送进网络。注意,高光谱的波段顺序和中心波长必须记录清楚,否则后面复现时对不上。

2.3 SAR:相干成像带来的斑点噪声,不能用普通去噪思路

SAR 是主动微波成像,记录的是后向散射强度,相位信息也很重要。它的典型问题是相干斑噪声,表现为颗粒状纹理,不是高斯噪声,所以用普通均值滤波或高斯滤波去噪效果很差。常见做法是先用 Lee 滤波、Frost 滤波或非局部均值做斑点抑制,再做地理编码和辐射定标。SAR 图像通常是单通道,动态范围大,直接归一化到 0~1 会丢失弱散射目标,我一般会先做对数变换或分位数拉伸。另外,SAR 的几何畸变(叠掩、透视收缩)比光学图像严重,做像素级配对时要特别小心。

2.4 四种模态的工程参数对比

模态典型通道数像素含义主要噪声预处理重点
可见光3反射亮度/颜色传感器噪声、光照变化白平衡、去噪、几何校正
红外1热辐射强度非均匀性、固定图案噪声非均匀性校正、温度定标
高光谱几十到几百连续光谱反射率条带噪声、坏波段波段选择、降维、辐射定标
SAR1(+相位)后向散射强度相干斑噪声斑点滤波、地理编码、对数拉伸

这张表不是让你背,而是让你在写 dataloader 时知道每个分支该做什么。比如红外分支的归一化参数和可见光分支必须分开算,不能共用一个 mean/std。

3. 把压缩包拆成可训练的配对数据集:目录结构与转换脚本

3.1 先看目录,再决定配对策略

拿到压缩包后不要急着解压到桌面,先列目录。常见结构有两种:一种是按模态分文件夹,每个文件夹里是同一场景的切片,文件名里带场景 ID 和坐标;另一种是按场景分文件夹,每个场景里放四种模态的子图。前者需要你按文件名做配对,后者直接按场景读。我一般会先跑一段脚本统计文件数量和命名规律,再决定用哪种配对方式。

import os import zipfile from collections import defaultdict zip_path = "图像合集(红外、可见光、高光谱、sar图像).zip" extract_root = "./dataset_raw" # 只解压一次,避免重复操作 if not os.path.exists(extract_root): with zipfile.ZipFile(zip_path, "r") as z: z.extractall(extract_root) # 统计各模态文件数量和命名前缀 modal_dirs = ["visible", "infrared", "hyperspectral", "sar"] stats = {} for modal in modal_dirs: modal_path = os.path.join(extract_root, modal) if not os.path.isdir(modal_path): continue files = [f for f in os.listdir(modal_path) if f.lower().endswith((".png", ".jpg", ".tif", ".tiff"))] prefixes = defaultdict(int) for f in files: # 假设文件名格式为 场景ID_坐标.扩展名,取第一个下划线前的内容 prefix = f.split("_")[0] prefixes[prefix] += 1 stats[modal] = {"total": len(files), "prefix_count": len(prefixes)} print(f"{modal}: 总文件数 {len(files)},场景前缀数 {len(prefixes)}") # 找出四种模态共有的场景前缀 common_prefixes = None for modal in modal_dirs: modal_path = os.path.join(extract_root, modal) if not os.path.isdir(modal_path): continue files = [f for f in os.listdir(modal_path) if f.lower().endswith((".png", ".jpg", ".tif", ".tiff"))] prefixes = set(f.split("_")[0] for f in files) if common_prefixes is None: common_prefixes = prefixes else: common_prefixes &= prefixes print(f"四种模态共有的场景前缀数量: {len(common_prefixes) if common_prefixes else 0}")

这段脚本做了三件事:解压、统计各模态文件数和场景前缀数、求四种模态共有的场景前缀。参数说明:extract_root是解压目标目录,建议放在数据盘而不是系统盘;modal_dirs里的文件夹名要根据实际压缩包内容调整,如果压缩包用的是中文文件夹名,改成对应中文即可。逻辑说明:先按文件名前缀做粗配对,如果共有前缀数量为 0,说明命名规则不是“场景ID_坐标”,需要进一步看文件名或读 README。

3.2 配对与切片:把大图裁成模型能吃的尺寸

遥感图像往往很大,比如 10000×10000 像素,直接送进网络不现实。常见做法是滑窗裁剪成 256×256 或 512×512 的切片,并保证四种模态在同一位置裁同样的窗口。这里的关键是:红外、可见光、高光谱、SAR 的空间分辨率可能不同,如果分辨率不一致,要先重采样到同一地面采样距离,再裁窗口。我一般会以可见光或 SAR 的分辨率为基准,把其他模态重采样过去。

import numpy as np from PIL import Image import os def load_and_resize(path, target_size=(512, 512)): """读取图像并重采样到目标尺寸,高光谱保留通道维""" img = Image.open(path) img = img.resize(target_size, Image.BILINEAR) return np.array(img) def crop_pairs(prefix, modal_paths, crop_size=256, stride=128): """对同一场景前缀的四种模态做同步滑窗裁剪""" arrays = {} for modal, path in modal_paths.items(): arr = load_and_resize(path, target_size=(1024, 1024)) arrays[modal] = arr h, w = 1024, 1024 patches = [] for y in range(0, h - crop_size + 1, stride): for x in range(0, w - crop_size + 1, stride): patch = {} for modal, arr in arrays.items(): if arr.ndim == 2: patch[modal] = arr[y:y+crop_size, x:x+crop_size] else: patch[modal] = arr[y:y+crop_size, x:x+crop_size, :] patches.append(patch) return patches # 示例:假设已经找到共有前缀 "scene001" modal_paths = { "visible": "./dataset_raw/visible/scene001_0.png", "infrared": "./dataset_raw/infrared/scene001_0.png", "hyperspectral": "./dataset_raw/hyperspectral/scene001_0.tif", "sar": "./dataset_raw/sar/scene001_0.tif", } patches = crop_pairs("scene001", modal_paths, crop_size=256, stride=128) print(f"scene001 裁出 {len(patches)} 个配对切片")

参数说明:crop_size是切片尺寸,stride是滑窗步长,步长小于切片尺寸可以增加样本量,但会引入重叠。逻辑说明:先把四种模态统一重采样到 1024×1024,再同步裁剪,保证每个切片里四种模态的空间位置一致。注意,高光谱如果通道数很多,重采样时不要用双线性插值去改变通道数,只改变空间尺寸。

3.3 保存为训练友好的格式:HDF5 或 NumPy 分片

配对好的切片如果直接存成图片,高光谱的通道信息会丢失,SAR 的浮点精度也会被压缩。我一般会存成 HDF5 或 NumPy 的 .npz 分片,每个分片包含一个 batch 的四种模态数组和标签。这样 dataloader 读起来快,也不容易在格式转换上翻车。

import h5py def save_patches_to_hdf5(patches, output_path): """把配对切片保存为 HDF5,每个切片一个 group""" with h5py.File(output_path, "w") as f: for i, patch in enumerate(patches): grp = f.create_group(f"patch_{i:06d}") for modal, arr in patch.items(): # 高光谱和 SAR 用 float32,可见光和红外用 uint8 即可 if modal in ("hyperspectral", "sar"): grp.create_dataset(modal, data=arr.astype(np.float32), compression="gzip") else: grp.create_dataset(modal, data=arr.astype(np.uint8), compression="gzip") print(f"已保存 {len(patches)} 个切片到 {output_path}") save_patches_to_hdf5(patches, "./dataset_paired/scene001.h5")

参数说明:compression="gzip"可以显著减小高光谱和 SAR 的存储体积,但读取时会多一点 CPU 开销。逻辑说明:每个切片一个 group,group 名用序号,方便后续按索引读取。如果切片数量很大,建议按场景分多个 HDF5 文件,不要全塞一个文件里。

4. 多模态数据加载与增强:别让一个分支拖垮整个 batch

4.1 自定义 Dataset:四种模态分别归一化

PyTorch 的 Dataset 里,最容易犯的错是四种模态共用一个 Normalize。可见光的 mean/std 是 ImageNet 的,红外是单通道,高光谱是几百个通道,SAR 是浮点且动态范围大,必须分开处理。我一般会在__getitem__里对每个模态单独做归一化,再返回一个字典。

import torch from torch.utils.data import Dataset import h5py import numpy as np class MultiModalDataset(Dataset): def __init__(self, h5_path, transform=None): self.h5_path = h5_path self.transform = transform with h5py.File(h5_path, "r") as f: self.keys = list(f.keys()) def __len__(self): return len(self.keys) def __getitem__(self, idx): with h5py.File(self.h5_path, "r") as f: grp = f[self.keys[idx]] visible = grp["visible"][:].astype(np.float32) / 255.0 infrared = grp["infrared"][:].astype(np.float32) / 255.0 hsi = grp["hyperspectral"][:].astype(np.float32) sar = grp["sar"][:].astype(np.float32) # 红外复制成三通道,方便复用可见光 backbone if infrared.ndim == 2: infrared = np.stack([infrared] * 3, axis=-1) # 高光谱按波段做标准化,这里用简单的 min-max hsi = (hsi - hsi.min()) / (hsi.max() - hsi.min() + 1e-8) # SAR 做对数拉伸,压缩动态范围 sar = np.log1p(np.abs(sar)) sar = (sar - sar.min()) / (sar.max() - sar.min() + 1e-8) if sar.ndim == 2: sar = np.stack([sar] * 3, axis=-1) sample = { "visible": torch.from_numpy(visible).permute(2, 0, 1), "infrared": torch.from_numpy(infrared).permute(2, 0, 1), "hyperspectral": torch.from_numpy(hsi).permute(2, 0, 1), "sar": torch.from_numpy(sar).permute(2, 0, 1), } if self.transform: sample = self.transform(sample) return sample

参数说明:h5_path是上一步保存的 HDF5 文件路径;transform可以传入自定义的增强函数,但要注意几何增强必须同步应用到四种模态。逻辑说明:可见光和红外除以 255 归一化,高光谱做 min-max,SAR 先取对数再归一化。红外和 SAR 复制成三通道是为了复用常见的 RGB backbone,如果自己设计网络,可以保持单通道。

4.2 同步增强:几何变换必须四路一致

随机裁剪、翻转、旋转这些几何增强,如果只对可见光做,其他三种模态就对不上了。我一般会自己写一个同步增强类,或者用支持多输入的增强库。下面是一个简单的同步翻转和旋转示例。

import random import torchvision.transforms.functional as TF class SyncAugment: def __init__(self, p=0.5): self.p = p def __call__(self, sample): # 同步水平翻转 if random.random() < self.p: for k in sample: sample[k] = torch.flip(sample[k], dims=[2]) # 同步垂直翻转 if random.random() < self.p: for k in sample: sample[k] = torch.flip(sample[k], dims=[1]) # 同步旋转 90 度的整数倍 if random.random() < self.p: k_rot = random.choice([1, 2, 3]) for k in sample: sample[k] = torch.rot90(sample[k], k=k_rot, dims=[1, 2]) return sample

参数说明:p是每种增强的执行概率,可以按需调整。逻辑说明:所有几何变换都在同一个随机决策下应用到四个模态,保证空间对齐不被破坏。注意,高光谱的通道维在 dim=0,所以翻转和旋转时只操作空间维 dim=1 和 dim=2。

4.3 模态缺失与不对齐:训练时的容错设计

实际数据里经常出现某个模态缺失或配准不准的情况。如果 Dataset 直接报错,整个训练就断了。我一般会在__getitem__里做容错:如果某个模态文件不存在,就用全零数组代替,并返回一个 mask 标记哪些模态可用。训练时根据 mask 决定是否跳过该分支的损失。

def safe_load(grp, modal, shape): """安全读取模态,缺失时返回全零和 mask""" if modal in grp: arr = grp[modal][:] mask = 1.0 else: arr = np.zeros(shape, dtype=np.float32) mask = 0.0 return arr, mask

参数说明:shape是该模态的预期形状,需要提前知道。逻辑说明:mask 为 0 时,后续融合模块可以忽略该模态的特征。这个设计在多模态数据里很实用,能避免因为个别样本缺失导致训练中断。

5. 避坑与排查:四种模态混用时的血泪经验

5.1 现象:训练 loss 不下降,验证集准确率随机波动

原因:四种模态的归一化参数不统一,或者某个模态的数值范围远大于其他模态,导致梯度被某一个分支主导。比如 SAR 原始值可能是 0~10000,可见光是 0~255,如果不做对数拉伸和归一化,SAR 分支的梯度会爆炸。

解决:逐模态检查数值范围,打印每个模态的 min/max/mean/std。SAR 必须做对数变换或分位数拉伸,高光谱必须做波段标准化。我一般会在 Dataset 里加一行断言,确保每个模态归一化后的值在 0~1 或 -1~1 之间。

5.2 现象:高光谱通道数对不上,报错 “expected input to have X channels”

原因:高光谱图像在保存或重采样时通道维被改变,比如用 PIL 读取多波段 TIFF 时只返回了前三个波段,或者 HDF5 里存的形状和网络预期不一致。

解决:用gdal或rasterio读取高光谱,不要用 PIL。保存 HDF5 时打印形状,加载时再打印一次,确保通道数一致。如果网络第一层是Conv2d(in_channels=200),那 HDF5 里高光谱的通道数必须是 200,不能多也不能少。

5.3 现象:SAR 图像全黑或全白,看不出纹理

原因:SAR 是浮点数据,动态范围大,直接按 0~255 显示或保存成 uint8 会丢失信息。如果归一化时用了全局 min/max,而图像里有一个极亮的目标,其他区域就会被压成黑色。

解决:先做对数变换log1p(abs(sar)),再用 2%~98% 分位数拉伸,而不是用全局 min/max。显示时用matplotlib的imshow并指定vmin和vmax为分位数。保存成图片时用 16 位 PNG 或直接存浮点 HDF5。

5.4 现象:四种模态配准不上,融合后目标位置偏移

原因:不同模态的成像几何不同,SAR 有叠掩和透视收缩,高光谱可能有条带噪声导致的几何畸变,红外和可见光也可能因为镜头视场不同而有偏移。

解决:先做几何校正和重采样,再检查配准精度。我一般会选几个明显的地物角点,手动量一下偏移量,如果偏移超过 2~3 个像素,就要重新配准。不要指望网络自己学会对齐,除非你有专门的配准模块。

5.5 现象:训练时显存爆掉,batch size 降到 1 还是不够

原因:高光谱的通道数太多,或者 SAR 和可见光的分辨率太高,四个分支同时前向传播时显存叠加。

解决:先降维高光谱,用 PCA 或波段选择把通道数压到 20 以内;再降低切片尺寸,从 512 降到 256;如果还不够,用梯度累积模拟大 batch,或者把四个分支改成串行前向,用完一个分支就释放中间变量。

6. 从能跑到好用:多模态合集的进阶用法与验证习惯

把数据跑通只是第一步,真正决定这个方向值不值得投入的,是你能不能用这套合集验证出“多模态确实比单模态好”。我一般会做三组对照:单模态基线、早期融合、中期融合。单模态基线选可见光或 SAR,早期融合在输入层拼接,中期融合在 backbone 中间层做注意力融合。如果中期融合比单模态高 2~3 个点,说明多模态有增益;如果只高 0.5 个点,就要检查是不是某个模态在拖后腿。

验证时不要只看总体准确率,要按模态可用性分层看。比如把测试集分成“四模态齐全”“缺高光谱”“缺 SAR”三组,分别看准确率。如果缺高光谱时准确率掉得特别厉害,说明模型过度依赖高光谱,实际部署时一旦高光谱不可用就会翻车。我一般会强制模型在训练时随机丢弃某个模态,让每个分支都学到有用的特征,而不是只靠一个模态撑场面。

还有一个习惯:每次换数据集或改预处理,先跑一个 100 样本的小实验,打印每个模态的数值范围、配准误差和单模态基线准确率。这个“体检”流程能帮你提前发现 80% 的坑,比直接上大模型训练省时间。多模态数据合集的价值不在于数据量大,而在于你能不能用它讲清楚“哪种模态在什么条件下补了什么信息”。如果只是把四种模态堆在一起训一个模型,那和单模态调参没有本质区别。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询