基于深度学习的多光谱图像语义分割 —— 从原理到实践(第二节)

📅 2026/7/18 2:45:21 👁️ 阅读次数 📝 编程学习
基于深度学习的多光谱图像语义分割 —— 从原理到实践(第二节)

基于深度学习的多光谱图像语义分割 —— 从原理到实践(第二节)

上一节我们建立了语义分割和多光谱图像的基本认知,并明确了本示例的整体流程。
现在进入实战第一步:下载数据、加载到 MATLAB、理解数据结构,并进行初步可视化


2. 数据获取与预处理

2.1 下载预训练的 U‑Net 模型(可选)

如果你只是想快速体验分割效果,而不想花费数小时训练网络,可以直接使用官方提供的预训练模型。该模型已经在 Hamlin Beach 数据集上训练了 70 个 epoch,并取得了很好的精度。

我们首先指定一个存放数据的文件夹(这里使用系统临时目录下的rit18_data文件夹):

dataDir=fullfile(tempdir,"rit18_data");然后下载预训练网络的 ZIP 压缩包,并解压加载其中的 net 变量: ```matlab matlab trainedNet_url="https://ssd.mathworks.com/supportfiles/"+..."vision/data/trainedMultispectralUnetModel_v2.zip";downloadTrainedNetwork(trainedNet_url,dataDir);load(fullfile(dataDir,"trainedMultispectralUnetModel",..."trainedMultispectralUnetModel_v2.mat"));` ````

注意:downloadTrainedNetwork 是本示例自带的辅助函数,它会自动处理下载和解压。如果你的网络环境无法直接访问 MathWorks 服务器,可以手动下载该 ZIP 文件并解压到对应目录,然后执行 load 命令。

加载成功后,工作区中会出现 net 变量(一个 dlnetwork 对象),这就是训练好的 U‑Net。

2.2 下载原始数据集

接下来下载 Hamlin Beach 多光谱数据集(MAT 版本,约 3.0 GB)。同样使用辅助函数:

matlabdownloadHamlinBeachMSIData(dataDir);

该函数会将 rit18_data.mat 文件下载到 dataDir 下。下载完成后,我们将其加载到工作区:

matlabload(fullfile(dataDir,"rit18_data.mat"));

此时工作区中会新增多个变量,最重要的三个是:

train_data —— 训练集图像

val_data —— 验证集图像

test_data —— 测试集图像

用 whos 查看它们的原始尺寸:

matlab whos train_data val_data test_data

输出如下(具体数值可能因版本略有差异):

text Name Size Bytes Class Attributes test_data7x12446x76541333663576uint16 train_data7x9393x5642741934284uint16 val_data7x8833x6918855493716uint16

可以看到,数据排列为 通道数 × 高度 × 宽度,其中:

第 1 维是通道(7 个通道)

第 2 维是宽度(列数)

第 3 维是高度(行数)

但 MATLAB 中常见的多通道图像布局是 高度 × 宽度 × 通道数。为了后续处理方便,我们必须进行维度转置。

2.3 维度重排:从 CHW 到 HWC

使用 permute 函数将第 2、3 维移到前面,将通道维放到最后:

matlab train_data=permute(train_data,[231]);val_data=permute(val_data,[231]);test_data=permute(test_data,[231]);

再次用 whos 检查:

matlab whos train_data val_data test_data

现在尺寸变为:

text Name Size Bytes Class Attributes test_data12446x7654x71333663576uint16 train_data9393x5642x7741934284uint16 val_data8833x6918x7855493716uint16

这样每个变量就是一个 高度 × 宽度 × 通道 的三维数组,符合 MATLAB 图像的惯例。

为什么顺序很重要?

因为后续函数(如 histeq、imshow、blockedImage)都默认前两维是空间维度,第三维是通道。如果顺序不对,这些函数会误解数据,导致错误结果。

2.4 了解光谱波段中心波长

数据集中还提供了一个变量 band_centers,表示每个通道的中心波长(单位:纳米):

matlabdisp(band_centers)

输出:

text490550680720800900

这里只列出了 6 个值(因为第 7 通道是掩膜,没有波长信息)。对应关系为:

通道 1:490 nm(蓝色)

通道 2:550 nm(绿色)

通道 3:680 nm(红色)

通道 4:720 nm(近红外)

通道 5:800 nm(近红外)

通道 6:900 nm(近红外)

可见本数据集涵盖了可见光到近红外的广泛范围,为植被、水体等判别提供了丰富信息。

2.5 可视化多光谱数据

为了直观感受不同通道的含义,我们先显示 RGB 组合图像。已知 RGB 通道对应的是第 3(红)、2(绿)、1(蓝)通道,因此提取这三个通道并组合:

matlab rgbTrain=histeq(train_data(:,:,[321]));rgbVal=histeq(val_data(:,:,[321]));rgbTest=histeq(test_data(:,:,[321]));

这里使用了 histeq 进行直方图均衡化,目的是增强对比度,使图像在屏幕上更明亮清晰(原始数据是 16 位无符号整型,直接显示可能偏暗)。

然后我们将三张图像的 RGB 分量并排显示为蒙太奇:

matlabmontage({rgbTrain,rgbVal,rgbTest},BorderSize=10,BackgroundColor="white");title("RGB Component of Training,Validation,and TestImage(Left to Right)");

运行后会得到类似下面的效果(由于是文字描述,无法显示实际图像,你可以在 MATLAB 中亲自运行查看):

训练图像(左)覆盖了公园的主要区域,包含树木、草地、道路、建筑等。

验证图像(中)和测试图像(右)是不同航拍区域,场景略有差异。

2.6 显示近红外通道

接下来单独显示第 4、5、6 通道(均为近红外),同样做直方图均衡化以便观察:

matlab ir4Train=histeq(train_data(:,:,4));ir5Train=histeq(train_data(:,:,5));ir6Train=histeq(train_data(:,:,6));montage({ir4Train,ir5Train,ir6Train},BorderSize=10,BackgroundColor="white");title("Infrared Channels4,5,and6(Left to Right)of Training Image");

你会看到:

第 4 通道(720 nm)中树木显得较暗,而草地相对亮一些。

第 5、6 通道(800、900 nm)中树木的亮度逐渐变化,这反映了不同植被在近红外不同子波段的反射特性差异。

这些额外的光谱信息正是多光谱图像相对于普通 RGB 的优势所在——它们能够“看到”人眼不可见的细节,从而让深度学习模型更好地分离不同地物。

2.7 查看掩膜通道
第 7 通道是一个二值掩膜(Mask),值为 1 表示该像素属于有效分析区域(即图像内部有意义的部分),值为 0 表示图像边界或无效区域(例如飞行器拍摄时边缘的暗角)。我们提取三个数据集的掩膜:

matlab maskTrain=train_data(:,:,7);maskVal=val_data(:,:,7);maskTest=test_data(:,:,7);montage({maskTrain,maskVal,maskTest},BorderSize=10,BackgroundColor="white");title("Mask of Training,Validation,and TestImage(Left to Right)");

掩膜图像为黑白二值图,白色区域代表有效像素。在后续的训练和评估中,我们只关心掩膜内的像素,忽略背景区域,这样可以避免无效数据干扰模型学习。


2.8 理解原始标签类别

数据集中除了图像数据,还包含对应的标签图:train_labels、val_labels、test_labels。这些标签图与图像空间尺寸相同,每个像素值是一个整数(0~18),表示该像素的类别 ID。

我们可以查看所有类别的名称:

matlabdisp(classes)

输出为:

text0.Other Class/Image Border1.Road Markings2.Tree3.Building4.Vehicle(Car,Truck,or Bus)5.Person6.Lifeguard Chair7.Picnic Table8.Black Wood Panel9.White Wood Panel10.Orange Landing Pad11.Water Buoy12.Rocks13.Other Vegetation14.Grass15.Sand16.Water(Lake)17.Water(Pond)18.Asphalt(Parking Lot/Walkway)

共有 18 个类别,其中 ID 0 是背景/图像边界,不计入分析。本例为了简化问题,只区分 植被(Vegetation) 和 非植被(NotVegetation),因此需要将原始标签合并为二类。

2.9 将标签转换为二分类

我们定义目标类别集合:

matlab classNames=["NotVegetation","Vegetation"];

根据语义,植被包括类别 ID 为 2 (Tree)、13 (Other Vegetation) 和 14 (Grass)。其余所有非背景类(以及背景)都属于非植被。我们创建新的标签数组,其中:

值为 1 表示非植被

值为 2 表示植被

具体代码如下:

matlab vegetationClassIDs=[21314];nonvegetationClassIDs=setdiff(1:length(classes),vegetationClassIDs);labelsTrain=zeros(size(train_labels),"uint8");labelsTrain(ismember(train_labels,nonvegetationClassIDs))=1;labelsTrain(ismember(train_labels,vegetationClassIDs))=2;labelsVal=zeros(size(val_labels),"uint8");labelsVal(ismember(val_labels,nonvegetationClassIDs))=1;labelsVal(ismember(val_labels,vegetationClassIDs))=2;

这里使用 ismember 快速判断每个像素的原始类别是否属于目标集合,然后赋值。注意我们将背景(ID 0)也归为非植被,因为 nonvegetationClassIDs 包含所有非植被类别(包括 ID 0)。

接着,我们将验证集的真实标签保存为 PNG 文件,以便后续评估时使用:

matlabimwrite(labelsVal,"gtruth.png");

2.10 可视化训练标签

为了确认标签转换是否正确,我们将训练集的 RGB 图像与新的二值标签叠加显示:

matlab cmap=[101;010];% 第一行:品红(非植被),第二行:绿色(植被)B=labeloverlay(rgbTrain,labelsTrain,Transparency=0.8,Colormap=cmap);imshow(B,cmap);title("TrainingLabels(Magenta=NotVegetation,Green=Vegetation)");numClasses=numel(classNames);ticks=1/(numClasses*2):1/numClasses:1;colorbar(TickLabels=cellstr(classNames),Ticks=ticks,TickLength=0,TickLabelInterpreter="none");

运行后你会看到一幅彩色叠加图,其中品红色区域代表非植被(道路、建筑、水体等),绿色区域代表植被(树木、草地、灌木等)。这样可以直观地判断标签质量以及分类的合理性。

2.11 本节小结

至此,我们已经完成了:

下载预训练模型和原始数据集;

将数据从 CHW 格式转为 HWC 格式;

可视化 RGB、红外通道和掩膜,理解多光谱数据的组成;

将原始 18 类标签合并为二分类;

保存验证集真实标签并可视化训练标签。

下一节,我们将面对一个现实挑战:图像尺寸巨大,无法一次性送入 GPU。届时我们将引入 分块处理(Patch‑based Processing) 技术,利用 MATLAB 的 blockedImage 和 blockedImageDatastore 高效管理大图像数据。

敬请期待第三节《分块图像与数据存储——让大图像训练不再困难》。