
简介这是一套基于Python的遥感影像滑坡场景分类任务代码与项目文档适合毕业设计、课程设计及项目开发参考尤其面向具备一定机器学习基础的学生与开发者。项目采用SVM分类器完成滑坡场景识别核心流程涵盖从影像中提取光谱特征平均值、标准差与GLCM纹理特征利用K-Means将特征向量聚类为视觉单词再通过LDA模型进行主题分析得到高级特征并保存为libsvm训练样本格式最终使用Libsvm工具包完成分类。资源共21个文件压缩包1.86MB主要包含4个Python脚本、4个pkl模型文件、4个txt数据文件以及md说明文档、visual_lda.model模型和visual_dict视觉词典等代码与模型文件分层存放便于按流程查阅。已有56人学习下载。源码经过严格测试文档中详细说明了从特征工程到分类评估的完整链路并提供了可直接运行的训练与测试脚本方便读者在此基础上延申使用或快速完成课程设计。1. 遥感影像滑坡场景分类到底在做什么一个毕设题的三种打开方式滑坡场景分类不是让你去数山坡上有几块石头而是给定一张遥感影像让程序判断某个区域有没有滑坡、滑坡在哪儿、面积大致多大。这个任务在灾害应急、公路选线、地质灾害普查里都有实际需求而作为毕业设计或课程设计它的优势在于输入输出都很直观评估标准清晰且从数据、模型到文档能形成一条完整的项目闭环。这个标题背后其实是一套可交付的方案包——Python 代码 项目文档 数据集处理流程目标对象是做毕设或课设的学生以及想快速上手遥感影像深度学习任务的开发者。常见做法是走两条路线一条是用遥感影像语义分割模型比如 U-Net、DeepLabV3把滑坡区域逐像素抠出来另一条是把影像切成块提取颜色、纹理、地形特征后喂给机器学习模型比如 XGBoost做有滑坡/无滑坡的场景二分类。前者精细但吃显存后者轻量且容易在普通笔记本上跑通。我见过太多人一上来就陷入我要训练一个大模型的执念结果数据集才几百张图模型又深又大训完过拟合得一塌糊涂。这个项目的正确打开方式是先想清楚你要回答哪个问题是哪里有滑坡还是这一块有没有滑坡。想清楚这一点你的模型选型、数据标注方式和评估指标就完全不一样。接下来我会把数据、建模、训练、避坑一条线讲完让你照着能做出来而不是读完还是一头雾水。2. 数据先行滑坡影像从哪里来、怎么切块、标签怎么打2.1 公开数据源与自建样本的取舍很多人做遥感影像任务的第一步不是找数据而是打开浏览器搜滑坡数据集下载然后陷入找半天找不到、找到了又要注册审批的困境。实事求地说真正公开带滑坡标注的遥感数据集并不多比较常见的来源有两类一类是学术机构发布的滑坡分割数据通常伴随论文发布另一类是自己从公开卫星影像源采集正负样本再用标注工具逐张画标签。对毕设来说我一般建议先用自己的样本把流程跑通再引入公开数据扩充。自建样本的流程是从 Google Earth、天地图或一些开放影像服务上截取滑坡多发区域比如四川、云南、贵州的山区的影像时间最好跨雨季前后因为滑坡往往发生在强降雨之后。采集时注意一个原则正样本有滑坡和负样本无滑坡的比例控制在 1:1 到 1:2 之间。滑坡场景里负样本天然多如果不做控制模型学到的就是不动声色地全预测成无滑坡准确率还有 80%看着光鲜实际毫无用处。公开数据源方面毕设里最常用的是 Building 类分割数据集做预训练之外的补充以及 Landslide4Sense 这类专门面向滑坡遥感的研究数据。注意一点很多公开数据的影像来源和分辨率跟你的应用场景不一致直接拿过来训练很容易出现训练集是光学影像、测试集是地形阴影这种模型看不懂的情况。正确的做法是先把你手上的数据统一坐标系和分辨率再谈训练。2.2 切块策略影像太大模型吃不下遥感影像的分辨率动不动就是几万乘几万像素任何深度学习模型都不可能整张图直接喂进去。所以第一步一定是切块。常见做法是按 256×256 或 512×512 的窗口滑动切块滑动的步长决定了相邻块之间有没有重叠。import cv2 import numpy as np from glob import glob def crop_image(image, label, patch_size512, stride256): 把大幅遥感影像和对应的标签图切成小块 Args: image: HxWx3 的遥感影像 (BGR 顺序) label: HxW 的标注图滑坡区域为 255背景为 0 patch_size: 切块尺寸常用 256 或 512 stride: 滑动步长一般取 patch_size 的一半保证重叠 Returns: patches: list of (patch_image, patch_label) h, w image.shape[:2] patches [] for y in range(0, h - patch_size 1, stride): for x in range(0, w - patch_size 1, stride): img_patch image[y:y patch_size, x:x patch_size] lab_patch label[y:y patch_size, x:x patch_size] # 丢掉超过 70% 都是空背景的块减少无效训练 if np.mean(lab_patch 0) 0.3: continue patches.append((img_patch, lab_patch)) return patches # 读取影像和标签 img cv2.imread(landslide_area.tif) # 注意遥感图可能不是 8bit label cv2.imread(landslide_label.png, cv2.IMREAD_GRAYSCALE) patches crop_image(img, label, patch_size512, stride256)这里有两个容易翻车的点。第一cv2.imread读进来的是 BGR 顺序而很多模型预训练时用的是 RGB你如果忘了转换训练时模型会学到一个颜色全反了的特征表达指标还不见得低但换到新数据上就崩。第二遥感影像很多是 16bit 的 TIFF 格式直接用cv2.imread会丢失位深信息。我一般会用rasterio或tifffile先读成 float32再按百分位截断转成 8bit否则阴影和高光区域的对比度完全出不来。切块时丢掉超过 70% 是纯背景的块这也是经验值——如果背景占比太高模型会把这个任务学成我在猜哪里有山而不是哪里有滑坡。2.3 数据增强的实用配置别把山脉当样本学滑坡影像的数据增强和平常做分类不太一样。经典的水平翻转、随机裁剪当然可以用但要额外注意两点遥感影像是俯视角旋转 90 度、180 度、270 度都是合法的新样本这和自然图像里汽车倒过来不合理不一样但随机颜色抖动要慎用因为滑块区域的色调特征裸露土壤、岩石的灰褐色调是核心判别依据你把色调调变等于把答案擦掉了一半。import albumentations as A train_transform A.Compose([ A.RandomCrop(256, 256), # 随机裁剪兼顾切块与空间不变性 A.HorizontalFlip(p0.5), # 水平翻转 A.VerticalFlip(p0.5), # 垂直翻转 A.RandomRotate90(p0.5), # 遥感影像特有的 90 度旋转 A.RandomBrightnessContrast(p0.2, brightness_limit0.2, contrast_limit0.2), A.Normalize(mean(0.485, 0.456, 0.406), std(0.229, 0.224, 0.225)), # ImageNet 归一化 ]) val_transform A.Compose([ A.Normalize(mean(0.485, 0.456, 0.406), std(0.229, 0.224, 0.225)), ])RandomRotate90是遥感语义分割里性价比最高的增强没有之一。遥感图像不存在上下颠倒的语义问题所以旋转不会制造错误标签。亮度对比度的扰动幅度我控得比较小因为滑坡检测对色彩分布是敏感的抖动过猛会让验证集精度忽高忽低像换了个数据集一样。归一化参数直接用 ImageNet 的均值方差是常见做法因为主干网络用的是 ImageNet 预训练权重输入分布需要对齐如果你自己从零训练可以不归一化但收敛速度会慢很多。需注意如果你的影像不是 RGB 三波段而是多光谱归一化的通道数要跟着改不能直接套三通道参数。数据这块的产出不仅是训练素材还是你项目文档里最好写的一章。我建议你保留一张原始影像 → 切块 → 增强后样本的三段式图答辩时往大屏一放比说五分钟原理都有说服力。3. 两条建模路线像素级分割与场景级分类3.1 路线AU-Net MobileNetV2 做遥感影像语义分割滑坡场景分类最主流的建模方案是语义分割给每个像素打上滑坡/非滑坡的标签输出是一张和输入同尺寸的掩膜。U-Net 是这类任务里最稳的骨架编码器部分我建议直接用 MobileNetV2 做主干而不是从零搭卷积层。原因非常实际MobileNetV2 有 ImageNet 预训练权重几十 MB 的参数量在 CPU 上也能跑推理而 VGG16 那种主干光权重就五百多 MB训练速度和显存消耗在普通学生机上都很吃力。下面是一个典型的 U-Net MobileNetV2 分割模型的 PyTorch 实现骨架import torch import torch.nn as nn import segmentation_models_pytorch as smp def build_landslide_model(encoder_namemobilenet_v2, num_classes1): 构建用于滑坡分割的 U-Net 模型 Args: encoder_name: 主干网络常用 mobilenet_v2、resnet34 num_classes: 分割类别数二分类滑坡任务为 1前景 model smp.Unet( encoder_nameencoder_name, encoder_weightsimagenet, # 加载预训练权重迁移学习必备 in_channels3, # RGB 三通道 num_classesnum_classes, activationsigmoid, # 二分类分割用 sigmoid decoder_attention_typescse, # 加入注意力对小目标滑坡更友好 ) return model我这里用segmentation_models_pytorch这个库封装好了现成的 U-Net、DeepLabV3 等结构省去手写跳连和上采样的工作。需要解释清楚的是encoder_weightsimagenet是迁移学习的关键开关加载预训练权重能让模型在训练初期就具备基础的颜色和纹理特征提取能力滑坡区域的灰褐色裸土特征很容易被早期卷积层捕获。activationsigmoid是因为我们做的是单类别前景分割输出的每个像素点代表属于滑坡的概率。如果你要区分浅层滑坡和深层滑坡等多个类别num_classes要改成类别数激活函数换成softmax。训练这样一个模型的显存开销大约在 4-6GB输入 512×512batch size 8如果你是用校园网环境或者笔记本 GTX 1650 这种 4GB 显存的卡建议把输入分辨率降到 256×256batch size 降到 4。别小看这个参数滑坡这种目标在遥感影像里占比通常很小大 patch 虽然能提供更多上下文但梯度更新时正样本像素占比过低模型容易不收敛。3.2 路线B手工特征 XGBoost 的场景级分类语义分割的缺点是标注成本高、训练门槛大。如果你的毕设题目是滑坡易发性评价或者区域滑坡灾害风险区划其实不需要像素级输出只需要判断某个区域单元是否发生了滑坡。这时候走 XGBoost 的经典机器学习路线更稳妥运行速度快文档里还能写特征工程这一大章。import numpy as np import xgboost as xgb from sklearn.model_selection import train_test_split def extract_features(img_patch): 从影像块提取手工特征用于场景级滑坡分类 Args: img_patch: HxWx3 的 RGB 影像块 Returns: feature_vector: 长度 12 的特征向量 hsv cv2.cvtColor(img_patch, cv2.COLOR_RGB2HSV) gray cv2.cvtColor(img_patch, cv2.COLOR_RGB2GRAY) features [] # 颜色统计特征RGB 三通道的均值与标准差 for c in range(3): features.append(np.mean(img_patch[:, :, c])) features.append(np.std(img_patch[:, :, c])) # HSV 的色调均值裸土与植被在色调上区别明显 features.append(np.mean(hsv[:, :, 0])) # 纹理特征灰度图的方差与梯度幅度均值 features.append(np.var(gray)) gx cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize3) gy cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize3) features.append(np.mean(np.sqrt(gx ** 2 gy ** 2))) features.append(np.mean(gray)) return np.array(features) # 假设 X 是 (N, 12) 的特征矩阵y 是 0/1 标签 X_train, X_val, y_train, y_val train_test_split(X, y, test_size0.2, random_state42) model xgb.XGBClassifier( n_estimators300, max_depth6, learning_rate0.05, subsample0.8, colsample_bytree0.8, eval_metriclogloss, ) model.fit(X_train, y_train, eval_set[(X_val, y_val)], verboseFalse)这条路线的核心逻辑是滑坡发生后原本的植被覆盖被破坏裸露土壤和岩石在 RGB 和 HSV 空间里呈现特定的色调分布通常是灰褐、棕黄色同时纹理变得比植被破碎——所以Sobel梯度均值能反映这种表面被撕开的程度。subsample0.8和colsample_bytree0.8是 XGBoost 常用的防过拟合参数对中小规模数据集特别有效。特征向量只有 12 维几百个样本就能跑出不错的效果这是经典机器学习在工程上的优势。不过要提醒你一点XGBoost 路线很难输出滑坡在哪里只能输出整个影像块是否有滑坡。如果你的文档里需要画滑坡边界图这条路走不通得用路线 A。3.3 两条路线怎么选先看你的数据量和标注形态关于建模路线我的建议是做一个简单的判断矩阵。如果你的标注是像素级掩膜每个滑坡体有精细边界而且显存够用直接走 U-Net 语义分割如果你的标注是地块级某个区域有滑坡/没有滑坡或者你没有精力画像素级标签走特征 XGBoost 的场景分类。还有一条中间路线先用 U-Net 做分割得到滑坡概率图再按地块汇总概率判断有无滑坡。这个方案适合既有像素掩膜又要区域判断的题目但工作量会翻倍。另外提一下 MobileNetV2 相关的一个细节如果你在语义分割里把主干从 ResNet 换成 MobileNetV2验证集 IoU 可能会低 3~5 个百分点但推理速度会快一个量级。对于要做成 Web 演示系统或者实时处理流程的毕设这个取舍是完全值得的。反过来如果你的实验节点很充足、不焦虑显存也可以用 ResNet34 做主干精度收益是实打实的。# 模型选型的快速对比实验 for encoder in [mobilenet_v2, resnet34, efficientnet-b0]: model build_landslide_model(encoder_nameencoder) print(f{encoder}: {sum(p.numel() for p in model.parameters()) / 1e6:.1f}M params)在开始正式训练之前把三个候选主干的参数量打印出来再结合你的显存大小做选择这是一个能在文档里亮出来的工程决策过程。4. 训练循环与评估指标给论文能用的数字4.1 损失函数为什么交叉熵在滑坡分割上不够用绝大多数做图像分类的人第一个想到的损失函数是交叉熵但滑坡语义分割里正负像素严重不平衡——一张 512×512 的图里滑坡像素可能只占 1%~5%。这时用普通交叉熵模型很快学会全预测背景损失值很好看但灾害区域一个都没找到。常见做法是用 Dice Loss 或其与交叉熵的组合。import torch import torch.nn as nn import torch.nn.functional as F class DiceLoss(nn.Module): def __init__(self, smooth1.0): super().__init__() self.smooth smooth def forward(self, pred, target): pred torch.sigmoid(pred) # (B, 1, H, W) target target.float() intersection (pred * target).sum(dim(2, 3)) dice (2.0 * intersection self.smooth) / ( pred.sum(dim(2, 3)) target.sum(dim(2, 3)) self.smooth ) return 1.0 - dice.mean() class CombinedLoss(nn.Module): def __init__(self, dice_weight0.8, bce_weight0.2): super().__init__() self.dice DiceLoss() self.bce nn.BCEWithLogitsLoss() self.dice_weight dice_weight self.bce_weight bce_weight def forward(self, pred, target): return self.dice_weight * self.dice(pred, target) self.bce_weight * self.bce(pred, target)Dice 损失的原理是把预测区域和真实区域的重合度直接作为优化目标对正负样本不平衡不敏感。混合损失里我给了 Dice 0.8 的权重、BCE 0.2 的权重这是经验值——Dice 保证模型能学到滑坡在哪BCE 保证像素级的概率校准不至于跑偏。你可以把smooth参数理解为一个防除零的平滑项设置为 1.0 在大多数任务上都够用。评估指标方面毕设文档里必须出现的三个数字是IoU交并比、Dice 系数跟损失函数里的 dice 是同一个公式、以及查准率/查全率。注意滑坡灾害场景里查全率Recall的优先级高于查准率Precision——漏掉一个滑坡比误报一个滑坡的代价大得多。所以最终选择哪个 checkpoint我一般不看最优 IoU而是看查全率在 0.8 以上的 checkpoint 里选 IoU 最高的那个。4.2 训练脚本的核心逻辑optimizer、scheduler 与 checkpoint 管理训练循环本身不复杂但有几个细节直接影响你能不能跑出一个可用的模型。第一是优化器我常用 AdamW 而不是 Adam因为权重衰减的处理方式更规范第二是学习率策略滑坡分割通常用小学习率加余弦退火起步 3e-4随着训练逐步衰减到 1e-5 左右第三是 checkpoint 必须同时保存模型结构和最优权重不能只存一个。import os import torch from torch.utils.data import DataLoader from tqdm import tqdm def train_one_epoch(model, loader, optimizer, criterion, device): model.train() total_loss, total_batch 0.0, 0 for images, masks in tqdm(loader, desctraining): images images.to(device) masks masks.to(device).unsqueeze(1) # (B, C, H, W) preds model(images) loss criterion(preds, masks) optimizer.zero_grad() loss.backward() optimizer.step() total_loss loss.item() total_batch 1 return total_loss / total_batch def validate(model, loader, criterion, device): model.eval() total_dice, total_iou, total_batch 0.0, 0.0, 0 with torch.no_grad(): for images, masks in tqdm(loader, descvalidating): images images.to(device) masks masks.to(device).unsqueeze(1) preds torch.sigmoid(model(images)) 0.5 preds preds.float() intersection (preds * masks).sum(dim(2, 3)) union (preds masks - preds * masks).sum(dim(2, 3)) dice (2.0 * intersection 1.0) / (preds.sum(dim(2,3)) masks.sum(dim(2,3)) 1.0) total_dice dice.mean().item() total_iou (intersection / (union 1e-6)).mean().item() total_batch 1 return total_dice / total_batch, total_iou / total_batch验证集注意两点一是torch.sigmoid(model(images)) 0.5这个阈值只是一个起点完整项目做完建议在验证集上搜一遍最优阈值常见做法是遍历 0.3 到 0.7选查全率最高者二是保存 checkpoint 时同时写一个best_model.pth和last_model.pth前者用于报告指标后者用于回滚。我经历过太多训练到 40 个 epoch 模型崩了的情况如果没有best_model.pth整个项目等于白跑。4.3 可视化预测结果和标签叠图才是毕设亮点模型训练完最后一步是可视化。滑坡检测这种任务光看 IoU 数字没法判断模型是不是真的学到了滑坡的形态特征。我一般会抽样 6-10 张验证集影像把原图、真实掩膜、预测掩膜三张拼在一起保存同时计算每张图的像素 IoU。import matplotlib.pyplot as plt def visualize_result(image, mask_true, mask_pred, save_path): 将原图、真实标签、预测结果拼接保存 Args: image: (H, W, 3) float32, 0~1 mask_true: (H, W) 0/1 mask_pred: (H, W) 0/1 fig, axes plt.subplots(1, 3, figsize(15, 5)) axes[0].imshow(image) axes[0].set_title(Original Image) axes[1].imshow(mask_true, cmapgray) axes[1].set_title(Ground Truth) axes[2].imshow(mask_pred, cmapjet, alpha0.7) axes[2].set_title(Prediction) plt.tight_layout() plt.savefig(save_path, dpi150) plt.close()这段代码里的cmapjet用彩色渐变显示预测概率分布比黑白的直观。叠图时注意把原图先归一化到 0-1 再imshow否则可能出现全黑或全白。把这种图输出到outputs/目录下同时把每轮的 loss 和 IoU 变化用折线图画出来你的项目文档核心素材就齐了。5. 避坑排查滑坡影像分类最常见的 5 个翻车现场5.1 现象训练损失正常下降但验证 IoU 始终为 0原因标签图和影像图没有对齐典型原因是读取 16bit TIFF 时用了cv2.imread丢失了位深或者滑动切块时对影像和标签用了不同的步长。另外一个隐蔽原因是投影坐标系不同影像来自 Web 地图服务而标签是从 GIS 软件导出的存在平移偏差。解决写一个简单的对齐检查脚本随机抽 5 块 patch把影像和标签叠在一起输出为 PNG 肉眼检查。重点看滑坡边界是否贴着地形变化走偏差超过 10 个像素就要回头检查读取和切块逻辑。统一用rasterio读取影像用同样的仿射变换参数切块能规避大部分对齐问题。5.2 现象程序一启动报ModuleNotFoundError或者提示缺少 MSVCP140.dll原因环境没配好。常见的是把opencv-python和opencv-contrib-python混着装两个包互相覆盖动态库导致崩溃。还有的是 Python 3.12 下部分旧版本库没有预编译轮子pip 临时编译源码失败。MSVCP140.dll 缺失则是 Windows 下缺少 Visual C 运行库。解决在干净的虚拟环境里统一安装pip install opencv-python和pip install opencv-contrib-python只保留一个Python 版本建议 3.9 或 3.10生态兼容性最好。缺 DLL 就装微软官方的 Visual C Redistributable一劳永逸。项目文档里把你的环境锁成requirements.txt包含segmentation-models-pytorch0.3.3、torch2.1.2这类精确版本号否则换台机器就翻车。5.3 现象滑坡区域永远被漏检模型只输出零星几个点原因正样本太少且切块策略把大面积滑坡切碎了导致模型看到的都是半个滑坡特征不完整。还有一个原因是预测概率阈值设得太机械0.5 对滑坡这种小目标太苛刻。解决训练集里把包含滑坡的 patch 做重复采样常见做法是在Dataset里让含正样本的 patch 权重翻倍。切块时建议 stride 取 patch 的一半让同一个滑坡出现在多个 patch 里相当于三倍的数据增广量。推理时把阈值降到 0.4然后再做一个后处理用开运算去掉面积小于 50 像素的噪声块。这个小噪点 大滑坡的形态学区分比单纯调阈值靠谱很多。5.4 现象验证集 IoU 很高但换了一幅影像完全不能看原因典型的过拟合到特定卫星源。很多公开数据集的影像来自同一卫星同一时期颜色分布和纹理风格高度一致模型学到的是这一批影像的风格而不是抽象的滑坡特征。解决训练集里混入不同来源的影像做色彩归一化将影像均值方差对齐到同一个目标分布并关闭掉过分强烈的颜色增强。验证时不要只用同源的随机切块留出两个完全不同区域的影像块做跨区验证这才是真实泛化能力的参考。毕设答辩时把同源验证 0.85 IoU、跨区验证 0.6 IoU这个对比放出来不仅不减分反而是加分项说明你理解泛化问题的本质。5.5 现象训练时显存不够batch size 调小后精度大幅下降原因batch size 太小BN 层的统计量不稳定训练震荡。滑坡分割本身正样本就稀少batch 再小的话很多 batch 里可能一个滑坡像素都没有梯度方向就是噪声。解决显存小优先降低输入分辨率而不是 batch size——256×256 输入配 batch size 8比 512×512 配 batch size 2 的训练效果通常更稳。还可以用梯度累积模拟大 batch每 4 个 batch 做一次参数更新等效于 batch size 乘以 4BN 层的统计量不变差的前提下把优化步数稳住。6. 从代码到毕设交付验证方法与两个值得做的进阶扩展6.1 最小验证流程要确认整个项目包能正常交付我按以下顺序跑一遍第一步在一台干净的机器上按requirements.txt重建环境运行python preprocess.py --input data/raw --output data/patches确认数据流水线没有依赖本机绝对路径。第二步用 20 张样本跑 1 个 epoch确认 loss 能下降且不低于某个下限这个能快速暴露数据读取和标签对齐的问题。第三步跑完整训练保存 checkpoint然后运行python inference.py --model best_model.pth --image test.tif输出预测掩膜与叠加可视化。最后打开项目文档按照文档里的步骤从零到一复现一遍——我发现绝大多数项目包的文档写不明白问题都在漏了环境变量配置或路径大小写不一致上。这些坑写文档的人自己早就绕过去了。6.2 进阶扩展一给项目加一个 Streamlit 交互界面很多优秀的毕设不只是跑完指标就结束而是带一个演示界面。Streamlit 是当前文科生都能上手的轻量方案你只需要把推理函数封装好再加一个文件上传组件import streamlit as st import cv2 import numpy as np from model import build_landslide_model st.set_page_config(page_title遥感影像滑坡场景分类系统, layoutwide) st.title(基于深度学习的滑坡场景分类演示) uploaded st.file_uploader(上传遥感影像支持 TIF/JPG/PNG, type[tif, png, jpg]) if uploaded is not None: img cv2.imdecode(np.frombuffer(uploaded.read(), np.uint8), cv2.IMREAD_UNCHANGED) # 统一转 8bit 并调整尺寸 if img.dtype ! np.uint8: img cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8) img_resized cv2.resize(img, (512, 512), interpolationcv2.INTER_LINEAR) pred_mask predict(model, img_resized) col1, col2 st.columns(2) col1.image(img_resized, caption原始影像, use_container_widthTrue) col2.image(pred_mask, caption滑坡预测结果, use_container_widthTrue)这里值得解释的一个工程细节是cv2.imdecode读上传文件时没有位深信息如果原始影像是 16bit直接显示会全黑所以用cv2.normalize先做百分位拉伸——这一步对遥感影像的在线读取几乎是必须的。把这个界面跑起来毕设答辩现场直接让评委上传一张图看预测效果比任何 PPT 都直观。6.3 进阶扩展二后处理与矢量导出如果你的项目文档里能多一个从栅格到矢量的步骤档次就不一样了。滑坡体在实际应用中最终要落到 GIS 里算面积所以把预测掩膜转成 GeoJSON 或 Shapefile 是一个很实际的加分扩展示例。常见做法是先用skimage.measure.find_contours提取滑坡边界轮廓再叠加影像的仿射变换参数把像素坐标换算成地理坐标。这个扩展不复杂但能说明你理解了从数据到决策的完整链条。工具上还可以利用cv2.connectedComponentsWithStats把离散的预测像素连通成一个个独立的滑坡体然后过滤掉像素面积小于阈值的噪声区域输出每个滑坡体的中心点坐标和面积。对靠模板凑毕设的学生来说这些后处理代码在答辩时能撑起至少五分钟的问答时间。说回我自己的经验早期做滑坡分割我迷信过更复杂的模型结构总觉得 IoU 上不去是网络不够深后来发现把精力花在数据对齐和阈值搜索上换来的收益远比换模型骨架明显。做这类项目80% 的时间要花在数据上20% 才是调模型这也是遥感影像任务跟普通 CV 任务最大的差异。这个方案值不值得做我的判断是值得但前提是你愿意在数据上花功夫。一个跑通流程的简化版项目比一个堆了十几个模块但训练崩了的完美计划更有价值。希望这一套从数据到交付的路径能帮你少踩几个坑。本文还有配套的精品资源点击获取