★★★ 本文源自AlStudio社区精品项目,【点击此处】查看更多精品内容 >>>

1. 项目背景

  • 光学遥感影像以其高分辨率和稳定的几何特性被广泛应用于国防安全、环境科学、天气监测等领域。然而,人造卫星携带的遥感传感器在获取陆地信息时,不可避免地会受到气候,尤其是云层的影响。因此,去除高分辨率遥感图像中的云是分析前必不可少的预处理步骤

  • 遥感影像中需要去除的云具体分为薄云、厚云和云影三类,如下图所示。被薄云覆盖的区域仍然保留了遥感传感器捕捉到的部分地物,并且可以从单张影像中恢复原先的细节。而被厚云、云影覆盖的信息会完全丢失,这使得从单幅图像中去除厚云成为一个条件受限的问题。因此,解决这一问题往往需要多时相数据

  • 本项目通过PaddleRS集成的NAFNet模型来进行单幅遥感影像的薄云去除,效果如下图所示:

薄云遮挡图像去云结果
  • 此外,本项目还与数据集论文以及SpAGAN去云模型论文做了定量评价,结果在第五部分

2. 数据集介绍

  • 本项目所用的数据集为遥感影像去云数据集RICE,具体介绍可以查看论文A Remote Sensing Image Dataset for Cloud Removal

  • 该数据集主要包含两个子数据集RICE1RICE2:

    • RICE1: RICE1包含500对图像,如下图所示,每对图像有云和无云图像大小为512*512

    • RICE2: RICE2包含736组图像,如下图所示,每组包含3张512*512大小的图像。,分别为参考图片无云、图片有云和掩模有云,但本项目只使用有云和无云的图片,没有使用掩模图

3. 数据处理

  • 将数据解压,得到RICE1与RICE2两个数据集,按照SpA GAN作者的做法,将RICE1与RICE2按照0.8与0.2的比例划分训练集与测试集。由于划分具有随机性,所以想复现本项目的结果,请到百度网盘下载划分好的数据集,提取码:xo7v
  • :由于RICE1与RICE2影像分辨率不同,所以进行分开训练
# 解压数据集
!unzip -qo data/data195014/RICE_DATASET.zip -d work/RICE_DATASET/
# 解压PaddleRS,因为这部分代码暂未合入,所以使用压缩包的形式使用
!unzip -qo PaddleRS.zip -d .
%cd PaddleRS/
/home/aistudio/PaddleRS
# 配置环境
!pip install -r requirements.txt
!pip install -v -e .
# 划分数据集
!mkdir -p ./data/
!python tools/prepare_dataset/prepare_rice.py --ratios 0.8 0.2 \
        --in_dataset_dir ../work/RICE_DATASET/RICE1 \
        --out_dataset_dir ./data/RICE1/ 
!python tools/prepare_dataset/prepare_rice.py --ratios 0.8 0.2 \
        --in_dataset_dir ../work/RICE_DATASET/RICE2 \
        --out_dataset_dir ./data/RICE2/ 
Write file list to ./data/RICE2/train.txt.
Write file list to ./data/RICE2/val.txt.

4. 模型训练、测试与预测

4.1 模型训练

  • 为了提高模型的收敛效率和表现,本项目使用在SIDD模型上训练得到的NAFNet-width-32.pdparams作为预训练权重进行训练
  • 训练所用的初始学习率为0.0004,batch size为20,epoch数量为200,在V100 32G的环境下训练时间为1.5小时以内。若使用V100 16G的环境,可以将学习率与batch size下调
import paddle

import paddlers as pdrs
from paddlers import transforms as T
  • 定义数据集的路径,本项目训练流程的示例以RICE1为例,若要训练RICE2则修改数据集的相关路径即可
# 数据集存放目录
DATA_DIR = './data/RICE1'
# 训练集`file_list`文件路径
TRAIN_FILE_LIST_PATH = './data/RICE1/train.txt'
# 验证集`file_list`文件路径
EVAL_FILE_LIST_PATH = './data/RICE1/val.txt'
# 实验目录,保存输出的模型权重和结果
EXP_DIR = './output/nafnet/'
# 定义训练和验证时使用的数据变换(数据增强、预处理等)
# 使用Compose组合多种变换方式。Compose中包含的变换将按顺序串行执行
# API说明:https://github.com/PaddlePaddle/PaddleRS/blob/develop/docs/apis/data.md
train_transforms = [
    # 从输入影像中裁剪256×256大小的影像块
    T.RandomCrop(crop_size=256),
    # 以50%的概率实施随机水平翻转
    T.RandomHorizontalFlip(prob=0.5),
    # 以50%的概率实施随机垂直翻转
    T.RandomVerticalFlip(prob=0.5),
    # 以默认设置实施随机的翻转或旋转
    T.RandomFlipOrRotate(),
    # 将数据归一化到[0,1]
    T.Normalize(
        mean=[0.0, 0.0, 0.0], std=[1.0, 1.0, 1.0])
]

eval_transforms = [
    # 验证阶段与训练阶段的数据归一化方式必须相同
    T.Normalize(
        mean=[0.0, 0.0, 0.0], std=[1.0, 1.0, 1.0])
]
# 分别构建训练和验证所用的数据集
train_dataset = pdrs.datasets.ResDataset(
    data_dir=DATA_DIR,
    file_list=TRAIN_FILE_LIST_PATH,
    transforms=train_transforms,
    num_workers=0,
    shuffle=True,
    sr_factor=1)

eval_dataset = pdrs.datasets.ResDataset(
    data_dir=DATA_DIR,
    file_list=EVAL_FILE_LIST_PATH,
    transforms=eval_transforms,
    num_workers=0,
    shuffle=False,
    sr_factor=1)
2023-04-15 21:36:37 [INFO]	400 samples in file ./data/RICE1/train.txt
2023-04-15 21:36:37 [INFO]	100 samples in file ./data/RICE1/val.txt
in_channels=3
width=32
middle_blk_num=12
enc_blk_nums=[2, 2, 4, 8]
dec_blk_nums=[2, 2, 2, 2]
# 目前已支持的模型请参考:https://github.com/PaddlePaddle/PaddleRS/blob/develop/docs/intro/model_zoo.md
# 模型输入参数请参考:https://github.com/PaddlePaddle/PaddleRS/blob/develop/paddlers/tasks/restorer.py

model = pdrs.tasks.res.NAFNet(in_channels=in_channels, 
                              width=width,
                              middle_blk_num=middle_blk_num,
                              enc_blk_nums=enc_blk_nums,
                              dec_blk_nums=dec_blk_nums)
W0416 11:35:14.167667   286 gpu_resources.cc:61] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 11.2, Runtime API Version: 11.2
W0416 11:35:14.171555   286 gpu_resources.cc:91] device: 0, cuDNN Version: 8.2.
# 制定定步长学习率衰减策略
lr_scheduler = paddle.optimizer.lr.CosineAnnealingDecay(
    0.0004,
    T_max=4000,
    # 学习率衰减系数,这里指定每次减半
    eta_min=8e-7
)

# 构造AdamW优化器
optimizer = paddle.optimizer.AdamW(
    learning_rate=lr_scheduler,
    parameters=model.net.parameters(),
    weight_decay=0.0,
    beta1=0.9,
    beta2=0.9,
    epsilon=1e-8
)
# 执行模型训练
model.train(
    num_epochs=200,
    train_dataset=train_dataset,
    train_batch_size=20,
    eval_dataset=eval_dataset,
    optimizer=optimizer,
    save_interval_epochs=10,
    # 每多少次迭代记录一次日志
    log_interval_steps=10,
    save_dir=EXP_DIR,
    # 指定预训练权重路径
    pretrain_weights=r"../work/pertrain/NAFNet-SIDD-32.pdparams", 
    # 是否使用early stopping策略,当精度不再改善时提前终止训练
    early_stop=False,
    # 是否启用VisualDL日志功能
    use_vdl=True,
    # 指定从某个检查点继续训练
    resume_checkpoint=None)

4.2 模型测试

  • 训练完毕后,可以在测试集上测试权重效果。本项目没单独设置测试集,这部分使用验证集
  • 对于遥感影像薄雾去除任务,评估的指标为PSNR(Peak Signal-to-Noise Ratio)SSIM(Structure Similarity Index Measure),具体如何定义可以参考图像质量评价指标之 PSNR 和 SSIM,这里不做赘述,两者都是值越大,代表效果越好
from paddlers.tasks import load_model

# 构建测试集
test_dataset = pdrs.datasets.ResDataset(
    data_dir=DATA_DIR,
    file_list=EVAL_FILE_LIST_PATH,
    transforms=eval_transforms,
    num_workers=0,
    shuffle=False,
    sr_factor=1)

# 加载RICE1验证集上最佳模型
model = load_model("../work/NAFNet_RICE1/best_model")

# 验证模型在测试集上效果
res = model.evaluate(test_dataset)

# 打印评价指标
print(f"\nPSNR={res['psnr']:.2f}, SSIM={res['ssim']:.4f}")
2023-04-15 00:08:45 [INFO]	100 samples in file ./data/RICE1/val.txt
2023-04-15 00:08:46 [INFO]	Model[NAFNet] loaded.
2023-04-15 00:08:46 [INFO]	Start to evaluate(total_samples=100, total_steps=100)...

PSNR=38.45, SSIM=0.9686

4.3 模型预测

  • 预测RICE1上的结果
from paddlers.tasks import load_model
from PIL import Image
import matplotlib.pyplot as plt
%matplotlib inline

# 加载RICE1验证集上最佳模型
model = load_model("../work/NAFNet_RICE1/best_model")
image_file = r"../work/RICE_DATASET/RICE1/cloud/0.png"
label_file = r"../work/RICE_DATASET/RICE1/label/0.png"

result = model.predict(image_file, T.Compose(eval_transforms))['res_map']
cloud = Image.open(image_file)
label = Image.open(label_file)

plt.figure(figsize=(12, 6))
plt.subplot(1,3,1), plt.title('Input')
plt.imshow(cloud), plt.axis('off')
plt.subplot(1,3,2), plt.title('Output')
plt.imshow(result), plt.axis('off') 
plt.subplot(1,3,3), plt.title('GT')
plt.imshow(label), plt.axis('off') 
plt.show()
2023-04-16 11:40:46 [INFO]	Model[NAFNet] loaded.

在这里插入图片描述

  • 预测RICE2的结果
# 加载RICE2验证集上最佳模型
model = load_model("../work/NAFNet_RICE2/best_model")
image_file = r"../work/RICE_DATASET/RICE2/cloud/90.png"
label_file = r"../work/RICE_DATASET/RICE2/label/90.png"

result = model.predict(image_file, T.Compose(eval_transforms))['res_map']
cloud = Image.open(image_file)
label = Image.open(label_file)

plt.figure(figsize=(12, 6))
plt.subplot(1,3,1), plt.title('Input')
plt.imshow(cloud), plt.axis('off')
plt.subplot(1,3,2), plt.title('Output')
plt.imshow(result), plt.axis('off') 
plt.subplot(1,3,3), plt.title('GT')
plt.imshow(label), plt.axis('off') 
plt.show()
2023-04-16 11:35:49 [INFO]	Model[NAFNet] loaded.

在这里插入图片描述

  • 为在项目背景部分展示效果,将RICE2的验证集全部预测并保存结果至work/RICE2_VAL文件夹下
import os
import tqdm

data_dir = r"./data/RICE2"
save_root = r"../work/RICE2_VAL"

if not os.path.isdir(save_root):
    os.mkdir(save_root)
save_cloud = os.path.join(save_root, 'cloud')
if not os.path.isdir(save_cloud):
    os.mkdir(save_cloud)
save_dir = os.path.join(save_root, 'output')
if not os.path.isdir(save_dir):
    os.mkdir(save_dir)

with open(r"./data/RICE2/val.txt", "r") as f:
    lines = f.readlines()

for item in tqdm.tqdm(lines):
    item = item.strip()
    item = item.split(' ')
    cloud_name = item[0]
    cloud_file = os.path.join(data_dir, cloud_name)

    result = model.predict(cloud_file, T.Compose(eval_transforms))['res_map']
    result = Image.fromarray(result).convert("RGB")
    result.save(os.path.join(save_dir, os.path.basename(cloud_file)))

    cloud = Image.open(cloud_file)
    cloud.save(os.path.join(save_cloud, os.path.basename(cloud_file)))
100%|██████████| 100/100 [00:30<00:00,  3.33it/s]

00, 3.33it/s]

5. 结果分析与展望

5.1 结果分析

  • RICE_DATASET作者所用的pix2pix模型和SpAGAN模型进行去云对比,对比结果如下表所示,本项目实现的指标优于前两者:

    • RICE1数据集上对比结果:
    ModelPSNRSSIM
    pix2pix31.030.91
    SpAGAN30.230.95
    Ours38.450.97
    • RCIE2数据集上对比结果:
    ModelPSNRSSIM
    pix2pix30.040.80
    SpAGAN28.370.91
    Ours39.290.97
  • 因为前两者均是用GAN作为生成模型,生成的图片会更符合人眼视觉效果,但定性评价的指标就不会太高。本项目使用NAFNet进行去云,指标比较高,但也容易造成太平滑的结果

5.2 展望

  • 遥感图像去云本质上还是图像复原的问题,可以结合现在图像复原领域的SOTA以及遥感图像的一些特性进一步优化去云的效果
  • 但是我个人认为最直接有效的手段还是获取多时相的数据

参考文献

@article{Pan2020,
  title   = {Cloud Removal for Remote Sensing Imagery via Spatial Attention Generative Adversarial Network},
  author  = {Heng Pan},
  journal = {arXiv preprint arXiv:2009.13015},
  year    = {2020}
}
@unknown{unknown,
author = {Lin, Daoyu and Xu, Guangluan and Wang, Xiaoke and Wang, Yang and Sun, Xian and Fu, Kun},
year = {2019},
month = {01},
pages = {},
title = {A Remote Sensing Image Dataset for Cloud Removal}
}
@article{chen2022simple,
  title={Simple Baselines for Image Restoration},
  author={Chen, Liangyu and Chu, Xiaojie and Zhang, Xiangyu and Sun, Jian},
  journal={arXiv preprint arXiv:2204.04676},
  year={2022}
}

此文章为搬运
原项目链接

Logo

学大模型,用大模型上飞桨星河社区!每天8点V100G算力免费领!免费领取ERNIE 4.0 100w Token >>>

更多推荐