基于PSPNet与DeepLabV3+的遥感图像国土分类项目实战

简介:这份资源是面向计算机相关专业学生与项目实战学习者的课程设计/期末大作业源码包,主题为基于图像分割的卫星遥感图像国土分类。项目采用Python实现,涵盖数据预处理、模型构建与训练等完整流程,涉及PSPNet、DeepLabV3、DeepLabV3+等主流分割网络,适合作为图像分割与遥感分类方向的学习范例。压缩包共12个文件,以8个py源码文件为核心,另含2个log训练日志、1个txt说明与1张png展示图,整体约2.49MB,结构紧凑、便于快速浏览与二次开发。资源已通过严格调试,下载后可直接运行,省去环境搭建与排错成本。目前已有159人学习下载,读者可从中获取完整的项目目录组织、分割模型实现代码、训练日志参考以及数据加载与预处理脚本,帮助理解遥感图像国土分类的技术路线与工程落地方式,适合用于课程设计参考、大作业复现及项目实战练习。

1. 遥感图像国土分类项目:从像素到地类的完整工程链路

拿到一份卫星遥感影像,怎么让机器自动告诉你哪片是水体、哪片是建筑、哪片是植被?这个课程设计项目干的就是这件事。它用 Python 搭了一套基于图像分割的国土分类流程,核心是把遥感影像按像素打上地类标签,而不是简单给整张图贴一个类别。项目里包含了预处理脚本、数据加载模块、PSPNet 和 DeepLabV3+ 等分割网络实现,还有训练日志和展示海报,结构上已经是一个能跑通的小型工程。适合正在做课程设计、期末大作业的计算机相关专业学生,也适合想拿一个真实遥感场景练手分割模型的开发者。遥感数据本身有保密限制,项目里放了说明文件,但代码框架和网络结构是完整的,换成自己的数据就能跑。

2. 项目结构拆解:从 preprocess 到 seg_zoo 的模块分工

2.1 目录层级与文件职责

先把压缩包解开,根目录下能看到这些关键文件:preprocess.py和preprocess_water.py负责数据预处理,data_load.py管数据读取和增强,nets/目录下放着seg_zoo.py、pspnet.py、deeplabv3.py、deeplabv3_plus.py四个网络定义文件,deecamp_train.py是训练入口,pspnet.log和deeplab_v3.log是跑过的训练日志,data/目录里有一个说明文件解释为什么没有放原始遥感数据,另外还有 26 组 poster 展示图。

这种结构在课程设计里算比较规范的,把数据、模型、训练脚本分开了。nets/seg_zoo.py像是一个模型仓库的入口,里面大概率用字典或工厂函数把不同分割网络注册进去,训练脚本通过名字就能拿到对应的模型类。我一般做类似项目也会这么干,好处是加新网络时不用改训练主逻辑,只在seg_zoo.py里注册一下就行。

2.2 预处理脚本的分工逻辑

preprocess.py和preprocess_water.py分开写,说明水体这一类可能做了特殊处理。遥感影像里水体在近红外波段反射率很低,用 NDWI 指数能比较干净地提取出来,单独写一个脚本可能是为了先做水体掩膜或者生成水体标签。常见做法是:preprocess.py做通用的大气校正、裁剪、归一化,preprocess_water.py专门算 NDWI 并生成水体二值图,后面训练时把水体作为一个独立类别或者先验信息用。

# preprocess.py 典型结构示意 import numpy as np from osgeo import gdal def read_tif(path): """读取遥感 tif,返回数组和地理变换参数""" ds = gdal.Open(path) img = ds.ReadAsArray() # 形状 (bands, H, W) geo = ds.GetGeoTransform() return img, geo def normalize(img): """按波段做 min-max 归一化,避免量纲差异""" img = img.astype(np.float32) for i in range(img.shape[0]): band = img[i] img[i] = (band - band.min()) / (band.max() - band.min() + 1e-8) return img def crop_patches(img, size=256, stride=128): """滑窗裁剪成小图块,方便送进分割网络""" patches = [] _, H, W = img.shape for y in range(0, H - size + 1, stride): for x in range(0, W - size + 1, stride): patches.append(img[:, y:y+size, x:x+size]) return np.stack(patches)

这段代码里read_tif用 GDAL 读多波段遥感图,normalize按波段归一化,crop_patches做滑窗裁剪。参数size=256是送入网络的图块大小,stride=128控制重叠度,重叠一半能减少边缘拼接的割裂感。如果显存够,可以把size提到 512,但 batch size 要相应降下来。

2.3 数据加载与增强

data_load.py一般会继承 PyTorch 的Dataset类,实现__getitem__和__len__。遥感数据增强和自然图像不太一样,翻转、旋转可以用,但颜色抖动要谨慎,因为波段反射率是有物理意义的。常见做法是只做几何增强,加上随机裁剪和归一化。

# data_load.py 核心逻辑示意 import torch from torch.utils.data import Dataset import numpy as np class SegDataset(Dataset): def __init__(self, img_list, label_list, transform=None): self.img_list = img_list self.label_list = label_list self.transform = transform def __getitem__(self, idx): img = np.load(self.img_list[idx]) # (C, H, W) label = np.load(self.label_list[idx]) # (H, W) if self.transform: img, label = self.transform(img, label) return torch.from_numpy(img).float(), torch.from_numpy(label).long() def __len__(self): return len(self.img_list)

这里img是浮点型,label转成long是因为交叉熵损失要求标签是整数类别。transform如果要做同步几何变换,得自己写一个同时处理 img 和 label 的函数,不能直接用 torchvision 的单图变换,否则图像和标签会对不上,这是分割任务里很容易翻车的地方。

3. 分割网络选型:PSPNet 与 DeepLabV3+ 的实现差异

3.1 PSPNet 的金字塔池化模块

pspnet.py里的核心是金字塔池化模块(PPM)。遥感影像里地物尺度差异大,一片水体可能占半张图,一栋建筑只有几十个像素,PPM 用不同大小的池化核去抓多尺度上下文,正好对路。典型实现是四个分支,池化核大小分别对应 1x1、2x2、3x3、6x6 的全局平均池化,然后上采样拼回特征图。

# pspnet.py 中 PPM 模块示意 import torch import torch.nn as nn import torch.nn.functional as F class PPM(nn.Module): def __init__(self, in_dim, reduction_dim, bins): super(PPM, self).__init__() self.features = [] for bin_size in bins: self.features.append(nn.Sequential( nn.AdaptiveAvgPool2d(bin_size), nn.Conv2d(in_dim, reduction_dim, 1), nn.BatchNorm2d(reduction_dim), nn.ReLU(inplace=True) )) self.features = nn.ModuleList(self.features) def forward(self, x): x_size = x.size() out = [x] for f in self.features: out.append(F.interpolate(f(x), x_size[2:], mode='bilinear', align_corners=True)) return torch.cat(out, 1)

bins通常设成[1, 2, 3, 6],reduction_dim是每个分支降到的通道数,一般是in_dim // 4。F.interpolate把池化后的小特征图拉回原尺寸再拼接。这里align_corners=True在 PyTorch 里会影响上采样对齐,分割任务里建议统一设成 True,不然拼接时会有半个像素的偏移,小目标边缘容易糊。

3.2 DeepLabV3+ 的空洞卷积与解码器

deeplabv3_plus.py比 PSPNet 多了一个解码器分支。编码器用空洞卷积(Atrous Convolution)扩大感受野,不丢分辨率;解码器把浅层特征和深层特征融合,恢复边界细节。遥感地物边界往往比较规则,比如农田的田埂、水体的岸线,解码器对这类边界提升明显。

# deeplabv3_plus.py 中 ASPP 与解码器融合示意 class ASPP(nn.Module): def __init__(self, in_dim, out_dim, rates): super(ASPP, self).__init__() self.branches = nn.ModuleList() for r in rates: self.branches.append(nn.Sequential( nn.Conv2d(in_dim, out_dim, 3, padding=r, dilation=r), nn.BatchNorm2d(out_dim), nn.ReLU(inplace=True) )) def forward(self, x): return torch.cat([b(x) for b in self.branches], dim=1) class Decoder(nn.Module): def __init__(self, low_dim, high_dim, num_classes): super(Decoder, self).__init__() self.low_proj = nn.Conv2d(low_dim, 48, 1) self.fuse = nn.Sequential( nn.Conv2d(48 + high_dim, 256, 3, padding=1), nn.BatchNorm2d(256), nn.ReLU(inplace=True), nn.Conv2d(256, num_classes, 1) ) def forward(self, low, high): low = self.low_proj(low) high = F.interpolate(high, low.shape[2:], mode='bilinear', align_corners=True) return self.fuse(torch.cat([low, high], dim=1))

rates一般设[6, 12, 18],对应不同空洞率。low_dim是骨干网络浅层输出通道数,high_dim是 ASPP 输出通道数。解码器先把浅层特征降到 48 通道,再和上采样后的深层特征拼接,最后过两层卷积出类别预测。这里 48 是个经验值,来自原论文,显存紧张时可以降到 32。

3.3 模型注册与切换

seg_zoo.py把上面这些网络统一管理起来,训练脚本通过字符串名字就能切换模型。这种设计在课程设计里很实用,因为要对比不同网络的效果,改一个参数就能换模型,不用动训练代码。

# seg_zoo.py 模型注册示意 from nets.pspnet import PSPNet from nets.deeplabv3 import DeepLabV3 from nets.deeplabv3_plus import DeepLabV3Plus MODEL_ZOO = { 'pspnet': PSPNet, 'deeplabv3': DeepLabV3, 'deeplabv3_plus': DeepLabV3Plus, } def build_model(name, num_classes, **kwargs): if name not in MODEL_ZOO: raise ValueError(f'未知模型: {name}') return MODEL_ZOO[name](num_classes=num_classes, **kwargs)

num_classes是国土分类的类别数,比如水体、建筑、植被、裸地、道路五类就传 5。kwargs可以透传骨干网络类型、是否用预训练权重等参数。训练脚本里写model = build_model('pspnet', num_classes=5)就能拿到模型实例。

4. 训练与推理:deecamp_train.py 的完整流程

4.1 训练入口的参数组织

deecamp_train.py是主训练脚本,从日志文件pspnet.log和deeplab_v3.log能看出至少跑过 PSPNet 和 DeepLabV3 两组实验。训练脚本一般用 argparse 组织参数,包括数据路径、模型名、学习率、batch size、epoch 数、是否用预训练权重等。

# 典型训练命令 python deecamp_train.py \ --model pspnet \ --data_root ./data \ --num_classes 5 \ --batch_size 8 \ --lr 0.001 \ --epochs 50 \ --crop_size 256 \ --pretrained

--crop_size 256要和预处理时的裁剪大小一致,--pretrained表示加载 ImageNet 预训练骨干权重。遥感数据量通常不大,从预训练权重起步能明显加快收敛,这是血泪经验,从零训很容易卡在低精度。

4.2 损失函数与评估指标

国土分类里类别不平衡很常见,水体可能占 60%,建筑只占 5%。直接用交叉熵会让模型偏向多数类。常见做法是加类别权重,或者用 Dice Loss 和交叉熵组合。

# 损失函数组合示意 import torch.nn as nn class CombinedLoss(nn.Module): def __init__(self, class_weights=None): super(CombinedLoss, self).__init__() self.ce = nn.CrossEntropyLoss(weight=class_weights) def forward(self, pred, target): ce_loss = self.ce(pred, target) # Dice Loss 计算 pred_soft = torch.softmax(pred, dim=1) target_onehot = torch.nn.functional.one_hot(target, pred.shape[1]).permute(0, 3, 1, 2).float() intersection = (pred_soft * target_onehot).sum(dim=(2, 3)) union = pred_soft.sum(dim=(2, 3)) + target_onehot.sum(dim=(2, 3)) dice_loss = 1 - (2 * intersection + 1e-6) / (union + 1e-6) return ce_loss + dice_loss.mean()

class_weights可以按类别频率的倒数来设,频率低的类权重高。Dice Loss 直接优化重叠度,对小目标更友好。评估指标一般看 mIoU 和各类 IoU,训练日志里应该记录了这些值。

4.3 推理与结果拼接

推理时把大图裁成小块送进网络,再把预测结果拼回原尺寸。重叠区域可以取平均或者投票,减少拼接缝。

# 滑窗推理拼接示意 def sliding_inference(model, img, size=256, stride=128, num_classes=5): model.eval() _, C, H, W = img.shape prob_map = torch.zeros((num_classes, H, W), device=img.device) count_map = torch.zeros((1, H, W), device=img.device) for y in range(0, H - size + 1, stride): for x in range(0, W - size + 1, stride): patch = img[:, :, y:y+size, x:x+size] with torch.no_grad(): out = torch.softmax(model(patch), dim=1) prob_map[:, y:y+size, x:x+size] += out[0] count_map[:, y:y+size, x:x+size] += 1 prob_map /= count_map.clamp(min=1) return prob_map.argmax(dim=0)

stride小于size就有重叠,count_map记录每个像素被预测了几次,最后取平均。这样比不重叠裁剪的边缘效果好很多,代价是推理时间增加。

5. 避坑与排查:遥感分割项目里最容易翻车的几件事

5.1 图像和标签对不上

现象:训练 loss 一直不降,或者预测结果全是某一类。原因:数据增强时图像和标签用了不同的随机变换,或者裁剪时坐标没同步。解决:写一个同时接收 img 和 label 的 transform 函数,所有几何变换用同一组随机参数。我一般会在 Dataset 里先固定随机种子,再对 img 和 label 做同样的翻转和裁剪。

5.2 波段顺序和归一化搞错

现象:模型在验证集上表现正常,换一批数据就崩。原因:不同来源的遥感影像波段顺序可能不一样,有的按 RGB 排,有的按波长排;归一化方式不统一也会导致分布偏移。解决:在preprocess.py里明确记录波段顺序,归一化参数(均值、标准差)保存成配置文件,推理时加载同一份配置。别偷懒用img / 255,遥感影像的数值范围不一定是 0 到 255。

5.3 显存不够导致 batch size 只能设 1

现象:训练时 OOM,只能把 batch size 降到 1,训练极不稳定。原因:遥感图块尺寸大,PSPNet 和 DeepLabV3+ 的 PPM/ASPP 模块又吃显存。解决:先用小 crop size 跑通,比如 128;或者用梯度累积模拟大 batch;还可以把骨干网络从 ResNet101 换成 ResNet50。如果显存实在紧张,混合精度训练能省不少。

5.4 类别不平衡导致小类被忽略

现象:mIoU 看着还行,但建筑、道路这些小类的 IoU 接近 0。原因:交叉熵被多数类主导。解决:加类别权重,或者用 Focal Loss、Dice Loss。另外评估时别只看总体精度,要打印每一类的 IoU,不然小类全预测错也发现不了。

5.5 推理拼接出现网格状伪影

现象:大图推理结果有明显的方块边界。原因:滑窗裁剪时没有重叠,或者重叠区域直接覆盖而不是平均。解决:设置stride小于size,重叠区域用概率平均或投票。如果还有伪影,检查上采样时align_corners是否一致,训练和推理要统一。

6. 二次开发:换数据、换网络、加类别的实操思路

拿到这个项目后,最直接的改造是换成自己的遥感数据。把data/目录里的说明文件替换成你的影像和标签,标签要是单通道的类别索引图,像素值 0 到 N-1 对应不同地类。然后改preprocess.py里的波段读取和归一化参数,跑一遍预处理生成图块。如果类别数变了,训练命令里的--num_classes要同步改,损失函数的class_weights也要重新算。

换网络更简单,seg_zoo.py里已经注册了三个模型,训练时改--model参数就行。想加新网络,比如 UNet 或者 SegFormer,在nets/下新建文件,然后在seg_zoo.py的MODEL_ZOO字典里加一行注册。注意新网络的输入输出接口要和现有训练脚本对齐,输入是(B, C, H, W),输出是(B, num_classes, H, W)。

加类别的话,除了改num_classes,还要检查标签生成脚本。如果原来只分了五类,现在要加一类“园地”,得在标签图里把对应像素值改成新的索引,并确保预处理时没有把这类过滤掉。类别权重也要重新统计,不然新类可能因为样本少被忽略。

验证改造是否成功,我一般会先跑一个极小的子集,比如 20 张图,看 loss 能不能降下去,再跑全量。训练日志里重点看每一类的 IoU,如果某一类一直是 0,大概率是标签映射错了。推理时拿几张训练集里的图先过一遍,确认预测结果和标签大致对得上,再上验证集。

从那以后我每次换数据集,都强制先跑一遍可视化检查:随机抽几张图,把原图、标签、预测结果并排画出来看。这一步能省掉后面很多排查时间。希望帮到你。

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

相关新闻

随机森林预测电池RUL:不依赖电化学方程的稳定建模方法

随机森林预测电池RUL:不依赖电化学方程的稳定建模方法

简介:本资源是一套基于Python随机森林算法的锂离子电池剩余寿命(RUL)预测完整实践方案,面向机器学习入门者与电池健康状态研究初学者,适用于课程设计、毕设选题及工程实训等场景。资源包共117个文件,含106个…

2026/10/19 17:55:06 阅读更多 →
MATLAB水文预报模型实战:日模型与次洪模型代码解析与避坑指南

MATLAB水文预报模型实战:日模型与次洪模型代码解析与避坑指南

简介:这份MATLAB水文预报代码包面向水文水资源、水利工程方向的研究生与工程师,用于流域产流量计算与洪水过程线预测。包内共21个文件,以17个csv降雨与径流数据文件、3个m脚本和1个xls表格为主,压缩包约93KB,数据年份覆…

2026/10/19 17:55:06 阅读更多 →
STM32智能电表制作全攻略:从硬件电路到电能计量算法

STM32智能电表制作全攻略:从硬件电路到电能计量算法

简介:基于STM32的简易智能电表项目资源,面向嵌入式学习者和电力监测开发人员,演示如何用STM32实时采集电流电压,计算功率、功率因数,并累计用电量。资源包共440个文件、约199.59MB,主要包含C源码&#xff0…

2026/10/19 17:54:05 阅读更多 →

最新新闻

DeskcommCRM实战:轻量级客户管理与销售跟进全流程落地指南

DeskcommCRM实战:轻量级客户管理与销售跟进全流程落地指南

1. 项目概述:DeskcommCRM 到底是什么,以及为什么值得关注这两年市面上叫 CRM 的产品多得数不过来,但绝大多数都陷入了一个怪圈:功能越做越重,权限越加越细,你要是只为了管好手头几百个客户,得先…

2026/10/19 23:47:06 阅读更多 →
以沟通为核心的轻量级CRM系统设计与实践

以沟通为核心的轻量级CRM系统设计与实践

一个叫 DeskcommCRM 的项目,听起来有点像某个内部系统的代号,但实际上它代表了一类特别值得聊的东西:以“沟通”为核心的客户关系管理工具。我一开始接触这个项目名的时候,第一反应是“Deskcomm”可能是 Desk Communication 的缩写…

2026/10/19 23:47:06 阅读更多 →
从线程池失控到全局限流:高并发系统稳定性实战指南

从线程池失控到全局限流:高并发系统稳定性实战指南

1. 并发失控的第一现场:线程池是怎么被击穿的先说一个我实际排查过的案例场景。某公司核心交易链路的订单服务,平时性能表现很稳定,高峰期单机支撑上千QPS没有任何压力。但一次大促活动中,下游的库存服务因为数据库连接池被打满&a…

2026/10/19 23:39:50 阅读更多 →
STC单片机范例程序实战指南:从点灯到多外设工程搭建

STC单片机范例程序实战指南:从点灯到多外设工程搭建

简介:这是一份面向嵌入式初学者与单片机开发者的STC单片机C语言范例程序合集,围绕ADC采样、串口通信、EEPROM读写、ISP在系统编程、时钟中断、端口测试及优化编程思想等核心功能展开,适合用于课程实验、自学练手与项目参考。资源包共612个文件…

2026/10/19 23:39:50 阅读更多 →
Kafka全链路性能调优:吞吐量与延迟的实战权衡

Kafka全链路性能调优:吞吐量与延迟的实战权衡

前阵子业务告警群里又炸了——消费延迟从平时的几百毫秒一路飙到分钟级,P99 延迟曲线在监控面板上直接拉成一条陡坡。接手这套 Kafka 系统两年,类似的戏码每隔一阵就重演一次。与其每次都临时救火,不如把全链路参数优化这件事系统捋一遍。这篇…

2026/10/19 23:37:47 阅读更多 →
ZXing.Net 0.16.8.0 条码识别实战:从解码链路到性能调优

ZXing.Net 0.16.8.0 条码识别实战:从解码链路到性能调优

简介:ZXing.Net.0.16.8.0 是面向 C# 与 Unity 开发者的开源条码处理库,基于 Zebra Crossing 项目,可在 .NET 框架与 Unity 引擎中实现 QR 码、Aztec、Code 128、EAN 等多种条码的读取与生成。开发者只需调用少量 API 即可为桌面应用、移动端或…

2026/10/19 23:37:47 阅读更多 →

日新闻

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →