基于深度学习的多光谱图像语义分割 —— 从原理到实践(第三节)
基于深度学习的多光谱图像语义分割 —— 从原理到实践(第三节)
上一节我们完成了数据加载、维度转换、多通道可视化和标签二分类。
然而,这些图像尺寸高达9000×5000 像素以上,如果直接送入深度学习网络,单张图像就会撑爆 GPU 显存(甚至 CPU 内存也吃力)。
本节我们将学习 MATLAB 提供的分块图像(Blocked Image)框架,轻松应对超大尺寸图像的处理与训练。
3. 分块图像与数据存储——让大图像训练不再困难
3.1 为什么要分块?
深度学习的训练过程通常需要将图像划分为小批量(mini‑batch),每批包含若干张固定尺寸的图像(例如 256×256)。对于普通大小的图像(如 224×224、512×512),这很简单。但对于遥感或医学影像这样的超高分辨率图像,直接整张送入网络会遇到两个问题:
- 内存/显存不足:一张 9393×5642×6 的图像(假设每个像素 float32)占用约 9393×5642×6×4 ≈ 1.27 GB,远超 GPU 显存。
- 计算量爆炸:卷积操作在大尺寸特征图上计算量极大,训练速度极慢。
因此,标准做法是将大图像切成若干小补片(Patch),每次只训练一个补片。这与卷积神经网络本身的滑动窗口思想一脉相承。通过随机采样补片,我们既降低了资源需求,又增加了训练样本的多样性(一张大图可产生成千上万个补片)。
3.2 MATLAB 的分块图像体系
MATLAB 从 R2019b 开始引入了blockedImage对象,专门用于处理无法一次性装入内存的大图像。它并不将整个图像数据加载到内存,而是只记录图像的尺寸、数据类型和文件位置,并按需从磁盘读取特定区域的数据块。配合blockedImageDatastore,可以方便地迭代读取这些块,非常适合训练。
核心概念:
- 分块(Block):将大图像划分为规整的矩形小块(如 256×256 像素)。
- 块位置集合(BlockLocationSet):记录所有有效块的行列索引,我们可以筛选出符合条件的块(例如避开纯背景区域)。
- 数据存储(Datastore):MATLAB 的数据流接口,支持循环迭代、随机打乱、批量读取等。
3.3 将训练图像、标签、掩膜转换为分块图像
我们只使用前 6 个光谱通道作为网络输入(第 7 通道是掩膜,不作为特征输入),同时将训练标签和掩膜也转为分块图像。
设定补片尺寸为256×256(这个大小可权衡精度和速度,通常 128~512 之间):
```matlab inputTileSize=[256256];bim=blockedImage(train_data(:,:,1:6),BlockSize=inputTileSize);bLabels=blockedImage(labelsTrain,BlockSize=inputTileSize);bmask=blockedImage(maskTrain,BlockSize=inputTileSize);此时 bim、bLabels、bmask 并没有真正读取数据,只是记录了图像的元信息和块划分方式。你可以通过 disp(bim) 查看其属性,例如 Size、BlockSize、NumBlocks 等。
3.4 选择有效的块——利用掩膜过滤
并不是所有块都值得训练。图像边界或飞行器边缘的无效区域(掩膜为 0)占比很高,如果这些块也被送入网络,会浪费计算资源并引入噪声。因此我们只选择那些有效像素占比大于 95% 的块。
为了实现这一点,我们需要生成一个“块位置集合”,即所有满足条件的块的行列索引。这里引入两个参数:
块偏移(BlockOffsets):相邻块之间的重叠像素数。适当重叠可以增加样本量,并让模型学习到边界附近的上下文信息(因为补片间有重叠,同一像素可能在多个补片中出现,相当于数据增强)。
重叠比例(overlapPct):这里设为 0.185,即 256×0.185 ≈ 47 像素的重叠。
matlab overlapPct=0.185;blockOffsets=round(inputTileSize.*overlapPct);bls=selectBlockLocations(bLabels,...BlockSize=inputTileSize,BlockOffsets=blockOffsets,...Masks=bmask,InclusionThreshold=0.95);selectBlockLocations 会遍历所有可能的块位置(考虑偏移),并检查每个块中掩膜的有效像素比例,若 ≥ 0.95 则保留该位置。返回的 bls 是一个包含 BlockLocationSet 信息的结构体。
3.5 One‑Hot 编码标签
深度学习中,多分类问题的标签通常采用 one‑hot 编码(对于二分类也一样)。例如,类别 1 编码为 [1, 0],类别 2 编码为 [0, 1]。这样做是为了配合交叉熵损失函数,因为交叉熵期望预测输出是一个概率分布向量。
我们对整个标签图进行 one‑hot 编码,并将无效区域(掩膜外)设置为 NaN,这样在自定义损失函数中可以用 isnan 忽略这些位置。
matlab labelsTrain1hot=onehotencode(labelsTrain,3,ClassNames=1:2);labelsTrain1hot(isnan(labelsTrain1hot))=0;% 将 NaN 转为 0(但后续会用掩膜屏蔽)bLabels=blockedImage(labelsTrain1hot,BlockSize=inputTileSize);这里 onehotencode 的第 3 个维度是通道维,编码后每个像素变为长度为 2 的向量。
3.6 创建分块图像数据存储
现在我们需要将图像块和标签块配对,组成一个可迭代的数据源。blockedImageDatastore 可以从分块图像中按指定块位置集合读取数据,每次返回一个块(或者一批块)。
matlab bimds=blockedImageDatastore(bim,BlockLocationSet=bls,PadMethod=0);bimdsLabels=blockedImageDatastore(bLabels,BlockLocationSet=bls,PadMethod=0);PadMethod=0 表示如果块不够大(例如边缘),不填充,但这些位置我们已通过掩膜筛选,所以不会出现无效块。
然后使用 combine 将两个数据存储合并成一个,训练时每次迭代会同时返回图像块和对应的标签块:
matlab dsTrain=combine(bimds,bimdsLabels);预览一个样本,验证数据形状:
matlabpreview(dsTrain)输出类似:
text ans=1×2cell array256×256×6uint16256×256×2double这表明第一个元素是 256×256×6 的图像块(uint16 类型),第二个元素是同尺寸的标签块(double 类型,one‑hot 编码)。
数据存储的优势:
支持随机打乱(shuffle 方法),每轮训练可重新排列顺序。
支持 mini‑batch 批量读取(通过 read 或 readall)。
与 trainnet 无缝对接,可直接作为训练数据源。
3.7 本节小结
在本节中,我们解决了大图像训练的核心难题——分块化。通过 MATLAB 的 blockedImage 框架,我们:
将大图像划分为 256×256 的小补片;
利用掩膜筛选出有效补片,避免无效区域干扰训练;
将标签进行 one‑hot 编码;
创建了可迭代的 CombinedDatastore,为后续网络训练做好了数据准备。
下一节,我们将正式构建 U‑Net 网络,并定义自定义损失函数和训练选项,然后启动训练(或直接加载预训练模型进行推理)。敬请期待第四节《U‑Net 构建与模型训练》。