【深度学习遥感地学应用】围绕 识别—监测—评估—预警 这一整条链条展开深度学习在“溜砂坡(scree/talus slope)”相关问题里的应用(附代码)(一)
【深度学习遥感地学应用】围绕 识别—监测—评估—预警 这一整条链条展开深度学习在“溜砂坡(scree/talus slope)”相关问题里的应用(附代码)(一)
文章目录
- 【深度学习遥感地学应用】围绕 识别—监测—评估—预警 这一整条链条展开深度学习在“溜砂坡(scree/talus slope)”相关问题里的应用(附代码)(一)
-
- 一、应用 1:溜砂坡自动识别与制图(Mapping / Segmentation)
-
- 1.1 典型任务
- 1.2 可以用的模型
- 1.3 代码示例:多通道 U-Net 做溜砂坡分割(可直接改数据)
-
- (1) 计算 DEM 地形因子(坡度 + 曲率)作为额外通道
- (2) PyTorch Dataset:读取影像 + 地形因子 + mask
- (3) 最小 U-Net + 训练(BCEWithLogits + Dice)
- 二、应用 2:落石/崩塌事件识别(Rockfall event detection)
-
- 代码思路(常见做法)
-
- 示例:差分栅格 patch 分类(简化版 CNN)
欢迎家人们点赞、关注、收藏! 祝大家逢考必过!逢投必中!上岸上岸上岸!upupup
大多数高校硕博生毕业要求需要参加学术会议,发表EI或者SCI检索的学术论文会议论文。详细信息可扫描博文下方二维码 “学术会议小灵通”或参考学术信息专栏:https://ais.cn/u/mmmiUz 详细免费的AI课程可在这里获取→www.lab4ai.cn
一、应用 1:溜砂坡自动识别与制图(Mapping / Segmentation)
1.1 典型任务
- 输入:卫星/航片正射影像(RGB/NIR)、DEM 派生地形因子(坡度、曲率、粗糙度)、或多源融合
- 输出:溜砂坡范围(像素级语义分割)或面状矢量
- 意义:快速编制溜砂坡分布图,为灾害清单、道路选线、泥石流物源评估提供底图
有研究已直接做“talus mapping with deep learning + high-resolution data”。
1.2 可以用的模型
- U-Net / DeepLabV3+ / SegFormer(2D 语义分割)
- 输入通道可做成:[RGB, slope, curvature, roughness] 多通道
1.3 代码示例:多通道 U-Net 做溜砂坡分割(可直接改数据)
下面是最小可跑的 U-Net(你把数据换成自己的影像 patch 即可)。
(1) 计算 DEM 地形因子(坡度 + 曲率)作为额外通道
import numpy as np
import rasterio
def terrain_features_from_dem(dem_path: str):
"""
返回 slope(0~1归一化前) 与 curvature(简单二阶差分近似)
"""
with rasterio.open(dem_path) as ds:
dem = ds.read(1).astype(np.float32)
transform = ds.transform
dx = transform.a
dy = –transform.e
# 一阶梯度
gy, gx = np.gradient(dem, dy, dx)
slope = np.sqrt(gx**2 + gy**2) # 近似坡度(梯度幅值)
# 二阶:曲率(非常简化,工程上可换更严谨的 profile/plan curvature)
gyy, gyx = np.gradient(gy, dy, dx)
gxy, gxx = np.gradient(gx, dy, dx)
curvature = gxx + gyy # Laplacian 近似
return slope, curvature
(2) PyTorch Dataset:读取影像 + 地形因子 + mask
假设你已经把训练数据切成 patch:
- img/*.tif(比如 4 通道:RGBN 或 RGB)
- dem/*.tif
- mask/*.tif(0/1:非溜砂坡/溜砂坡)
import os, glob
import torch
from torch.utils.data import Dataset
import rasterio
import numpy as np
class TalusSegDataset(Dataset):
def __init__(self, img_dir, dem_dir, mask_dir):
self.imgs = sorted(glob.glob(os.path.join(img_dir, "*.tif")))
self.dem_dir = dem_dir
self.mask_dir = mask_dir
def __len__(self):
return len(self.imgs)
def __getitem__(self, idx):
img_path = self.imgs[idx]
name = os.path.splitext(os.path.basename(img_path))[0]
dem_path = os.path.join(self.dem_dir, f"{name}.tif")
mask_path = os.path.join(self.mask_dir, f"{name}.tif")
with rasterio.open(img_path) as ds:
img = ds.read().astype(np.float32) # (C,H,W)
slope, curv = terrain_features_from_dem(dem_path)
with rasterio.open(mask_path) as ds:
mask = ds.read(1).astype(np.float32) # (H,W)
# 归一化(示意:你可换成训练集 mean/std)
img = img / (img.max() + 1e-6)
slope = slope / (np.percentile(slope, 99) + 1e-6)
curv = curv / (np.percentile(np.abs(curv), 99) + 1e-6)
x = np.concatenate([img, slope[None, ...], curv[None, ...]], axis=0) # (C+2,H,W)
x = torch.from_numpy(x)
y = torch.from_numpy(mask[None, ...]) # (1,H,W)
return x, y
(3) 最小 U-Net + 训练(BCEWithLogits + Dice)
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import DataLoader
class ConvBlock(nn.Module):
def __init__(self, in_ch, out_ch):
super().__init__()
self.net = nn.Sequential(
nn.Conv2d(in_ch, out_ch, 3, padding=1),
nn.BatchNorm2d(out_ch),
nn.ReLU(inplace=True),
nn.Conv2d(out_ch, out_ch, 3, padding=1),
nn.BatchNorm2d(out_ch),
nn.ReLU(inplace=True),
)
def forward(self, x): return self.net(x)
class UNetSmall(nn.Module):
def __init__(self, in_ch, base=32):
super().__init__()
self.enc1 = ConvBlock(in_ch, base)
self.pool1 = nn.MaxPool2d(2)
self.enc2 = ConvBlock(base, base*2)
self.pool2 = nn.MaxPool2d(2)
self.bott = ConvBlock(base*2, base*4)
self.up2 = nn.ConvTranspose2d(base*4, base*2, 2, stride=2)
self.dec2 = ConvBlock(base*4, base*2)
self.up1 = nn.ConvTranspose2d(base*2, base, 2, stride=2)
self.dec1 = ConvBlock(base*2, base)
self.out = nn.Conv2d(base, 1, 1)
def forward(self, x):
e1 = self.enc1(x)
e2 = self.enc2(self.pool1(e1))
b = self.bott(self.pool2(e2))
d2 = self.up2(b)
d2 = self.dec2(torch.cat([d2, e2], dim=1))
d1 = self.up1(d2)
d1 = self.dec1(torch.cat([d1, e1], dim=1))
return self.out(d1) # logits
def dice_loss_with_logits(logits, targets, eps=1e-6):
probs = torch.sigmoid(logits)
num = 2 * (probs * targets).sum(dim=(2,3))
den = (probs + targets).sum(dim=(2,3)) + eps
return 1 – (num / den).mean()
def train_seg():
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
ds = TalusSegDataset("img", "dem", "mask")
dl = DataLoader(ds, batch_size=4, shuffle=True, num_workers=2, pin_memory=True)
sample_x, _ = ds[0]
model = UNetSmall(in_ch=sample_x.shape[0]).to(device)
opt = torch.optim.AdamW(model.parameters(), lr=2e-4, weight_decay=1e-2)
for epoch in range(30):
model.train()
total = 0.0
for x, y in dl:
x, y = x.to(device), y.to(device)
logits = model(x)
loss = F.binary_cross_entropy_with_logits(logits, y) + 0.5 * dice_loss_with_logits(logits, y)
opt.zero_grad()
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
opt.step()
total += loss.item()
print(f"epoch {epoch+1:02d}, loss={total/len(dl):.4f}")
# train_seg()
二、应用 2:落石/崩塌事件识别(Rockfall event detection)
溜砂坡常处于“落石补给—再分配”的动力系统里,深度学习常用于:
- 从 LiDAR 差分/点云变化 中自动识别落石事件,减少人工判读 已有工作把深度学习用于“rockfall database population / event classification”
代码思路(常见做法)
示例:差分栅格 patch 分类(简化版 CNN)
import torch
import torch.nn as nn
import torch.nn.functional as F
class PatchCNN(nn.Module):
def __init__(self, in_ch=1, num_classes=3):
super().__init__()
self.net = nn.Sequential(
nn.Conv2d(in_ch, 16, 3, padding=1), nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(16, 32, 3, padding=1), nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(),
nn.AdaptiveAvgPool2d(1),
)
self.fc = nn.Linear(64, num_classes)
def forward(self, x):
h = self.net(x).flatten(1)
return self.fc(h) # logits
# 输入 x: (B,1,H,W) 例如差分高程、或点云距离栅格
- 你真正落地时,关键在于:训练样本怎么标注(事件 vs 噪声)。通常先用阈值 + 形态学提候选,再人工快速确认少量样本。


