项目参考AAAI Association for the Advancement of Artificial Intelligence
研究背景与意义
遥感图像变化差异可视化是遥感图像处理和分析的重要研究领域之一。随着遥感技术的快速发展和遥感数据的广泛应用,遥感图像的获取和处理变得越来越容易。然而,遥感图像通常具有大规模、高维度和复杂的特征,对于人类来说很难直观地理解和分析。因此,开发一种基于深度学习的遥感图像变化差异可视化系统具有重要的理论和实际意义。
首先,遥感图像变化差异可视化系统可以帮助人们更好地理解和分析遥感图像的变化情况。遥感图像的变化通常包括地表覆盖变化、建筑物变化、植被变化等。通过可视化系统,用户可以直观地观察到图像之间的差异,进而深入分析变化的原因和影响。这对于城市规划、环境监测、农业管理等领域具有重要的应用价值。
其次,基于深度学习的遥感图像变化差异可视化系统可以提高遥感图像处理和分析的效率和准确性。传统的遥感图像处理方法通常需要人工提取特征和进行分类,这个过程费时费力且容易出错。而深度学习技术可以自动学习图像的特征表示和分类模型,大大减少了人工干预的需求。通过将深度学习应用于遥感图像变化差异可视化系统中,可以实现自动化的图像处理和分析,提高工作效率和准确性。
此外,基于深度学习的遥感图像变化差异可视化系统还可以促进遥感技术与其他学科的交叉应用。深度学习技术在计算机视觉、模式识别、人工智能等领域取得了巨大的成功,而遥感技术在地理信息系统、环境科学、农业科学等领域也有广泛的应用。将深度学习与遥感图像变化差异可视化相结合,可以为这些领域提供更强大的工具和方法,推动相关学科的发展。
综上所述,基于深度学习的遥感图像变化差异可视化系统具有重要的研究背景和意义。它可以帮助人们更好地理解和分析遥感图像的变化情况,提高遥感图像处理和分析的效率和准确性,促进遥感技术与其他学科的交叉应用。随着深度学习技术的不断发展和遥感数据的不断增加,基于深度学习的遥感图像变化差异可视化系统将在未来得到更广泛的应用和研究。
基于深度学习的遥感图像变化差异可视化系统_哔哩哔哩_bilibili
UNet 简介
UNet 属于 FCN 的一种变体,它可以说是最常用、最简单的一种分割模型,它简单、高效、易懂、容易构建,且可以从小数据集中训练。2015 年,UNet 在论文 U-Net: Convolutional Networks for Biomedical Image Segmentation 中被提出 。UNet 的初衷是为了解决医学图像分割的问题,在解决细胞层面的分割的任务方面,其在 2015 年的 ISBI cell tracking 比赛中获得了多个第一。之后,UNet 凭借其突出的分割效果而被广泛应用在语义分割的各个方向(如卫星图像分割,工业瑕疵检测等)。
UNet 网络结构如上图所示,其网络结构是对称的,形似英文字母 U,故而被称为 UNet 。就整体而言,UNet 是一个Encoder-Decoder的结构(与 FCN 相同),前半部分是特征提取,后半部分是上采样。
Encoder:左半部分,由两个 3x3 的卷积层(ReLU)+ 一个 2x2 的 maxpooling 层组成一个下采样模块;
Decoder:右半部分,由一个上采样的卷积层 + 特征拼接 concat + 两个 3x3 的卷积层(ReLU)构成一个上采样模块。
Encoder 由卷积操作和下采样操作组成,所用卷积结构统一为 3x3 的卷积核,padding=0 ,striding=1。没有 padding 所以每次卷积之后特征图的 H 和 W 变小了,在跳层连接(Skip connection)时需注意特征图的维度。
Decoder 用以恢复特征图的原始分辨率,除了卷积以外,该过程的关键步骤就是上采样与跳层连接。上采样常用转置卷积和插值两种方式实现。在插值实现方式中,双线性插值(bilinear)的综合表现较好也较为常见 。要想网络获得好的效果,跳层连接基本必不可少。UNet 中的跳层连接通过拼接将底层的位置信息与深层的语义信息相融合。
import torch
from torch import nn
class double_conv(nn.Module):
def __init__(self, in_ch, out_ch):
super(double_conv, self).__init__()
self.conv = 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):
x = self.conv(x)
return x
class up(nn.Module):
def __init__(self, in_ch, out_ch, bilinear=True):
super(up, self).__init__()
self.conv = double_conv(in_ch, out_ch)
def forward(self, x1, x2):
x1 = nn.functional.interpolate(x1, scale_factor=2)
x = torch.cat([x2, x1], dim=1)
x = self.conv(x)
return x
class UNet(nn.Module):
def __init__(self, n_channels, n_classes):
super(UNet, self).__init__()
self.inc = double_conv(n_channels, 64)
self.down1 = nn.Sequential(nn.MaxPool2d(2), double_conv(64, 128))
self.down2 = nn.Sequential(nn.MaxPool2d(2), double_conv(128, 256))
self.down3 = nn.Sequential(nn.MaxPool2d(2), double_conv(256, 512))
self.down4 = nn.Sequential(nn.MaxPool2d(2), double_conv(512, 512))
self.up1 = up(1024, 256)
self.up2 = up(512, 128)
self.up3 = up(256, 64)
self.up4 = up(128, 64)
self.outc = nn.Conv2d(64, n_classes, 1)
def forward(self, x1, x2):
x = torch.cat([x1, x2], dim=1)
x1 = self.inc(x)
x2 = self.down1(x1)
x3 = self.down2(x2)
x4 = self.down3(x3)
x5 = self.down4(x4)
x = self.up1(x5, x4)
x = self.up2(x, x3)
x = self.up3(x, x2)
x = self.up4(x, x1)
x = self.outc(x)
return x
import itertools
import glob
from libtiff import TIFF
import numpy as np
from torch.utils.data import Dataset
from skimage.transform import match_histograms
import torch
class SctDataset(Dataset):
def __init__(self, root, size=512, slide=256):
image_path_list_2018 = glob.glob(root + '/img_2018' + '/*.tif')
image_path_list_2018.sort()
image_path_list_2017 = glob.glob(root + '/img_2017' + '/*.tif')
image_path_list_2017.sort()
image_path_list_mask = glob.glob(root + '/mask' + '/*.tif')
image_path_list_mask.sort()
self.image_path_list_2018 = image_path_list_2018
self.image_path_list_2017 = image_path_list_2017
self.image_path_list_mask = image_path_list_mask
def __getitem__(self, idx):
image1 = TIFF.open(self.image_path_list_2017[idx], mode='r').read_image()[:, :, [2, 1, 0]].transpose((2, 0, 1))
image2 = TIFF.open(self.image_path_list_2018[idx], mode='r').read_image()[:, :, [2, 1, 0]].transpose((2, 0, 1))
image2 = match_histograms(image2, image1, multichannel=True)
label = TIFF.open(self.image_path_list_mask[idx], mode='r').read_image()
label = (label / 255).astype(np.uint8)
return torch.from_numpy(image1.astype(np.float32)), torch.from_numpy(image2.astype(np.float32)), torch.from_numpy(label).long()
def __len__(self):
return len(self.image_path_list_2018)
import torch
import torch.nn as nn
import torch.nn.functional as F
class TverskyLoss(nn.Module):
def __init__(self, alpha=0.5, beta=0.5, eps=1e-7, size_average=True):
super(TverskyLoss, self).__init__()
self.alpha = alpha
self.beta = beta
self.size_average = size_average
self.eps = eps
def forward(self, logits, true):
"""Computes the Tversky loss [1].
Args:
true: a tensor of shape [B, H, W] or [B, 1, H, W].
logits: a tensor of shape [B, C, H, W]. Corresponds to
the raw output or logits of the model.
alpha: controls the penalty for false positives.
beta: controls the penalty for false negatives.
eps: added to the denominator for numerical stability.
Returns:
tversky_loss: the Tversky loss.
Notes:
alpha = beta = 0.5 => dice coeff
alpha = beta = 1 => tanimoto coeff
alpha + beta = 1 => F beta coeff
References:
[1]: https://arxiv.org/abs/1706.05721
"""
num_classes = logits.shape[1]
if num_classes == 1:
true_1_hot = torch.eye(num_classes + 1)[true.squeeze(1)]
true_1_hot = true_1_hot.permute(0, 3, 1, 2).float()
true_1_hot_f = true_1_hot[:, 0:1, :, :]
true_1_hot_s = true_1_hot[:, 1:2, :, :]
true_1_hot = torch.cat([true_1_hot_s, true_1_hot_f], dim=1)
pos_prob = torch.sigmoid(logits)
neg_prob = 1 - pos_prob
probas = torch.cat([pos_prob, neg_prob], dim=1)
else:
true_1_hot = torch.eye(num_classes)[true.squeeze(1)]
true_1_hot = true_1_hot.permute(0, 3, 1, 2).float()
probas = F.softmax(logits, dim=1)
true_1_hot = true_1_hot.type(logits.type())
dims = (0,) + tuple(range(2, true.ndimension()))
intersection = torch.sum(probas * true_1_hot, dims)
fps = torch.sum(probas * (1 - true_1_hot), dims)
fns = torch.sum((1 - probas) * true_1_hot, dims)
num = intersection
这个程序文件主要分为以下几个部分:
整体功能和构架概述:
该程序是一个基于深度学习的遥感图像变化差异可视化系统。它使用U-Net模型对2018年和2019年的遥感图像进行对比,以检测和可视化图像之间的变化差异。
以下是每个文件的功能整理:
文件名 | 功能 |
---|---|
change-detection-quick-start.py | 主程序文件,包含了整个系统的主要逻辑和流程 |
normalize.py | 定义了一个normalize函数,用于将图像进行归一化处理 |
UNet.py | 定义了一个UNet类,表示一个U-Net模型,包括双卷积层、上采样层和输出层 |
dataset.py | 定义了一个SctDataset类,表示数据集,包括获取图像和标签的方法 |
loss.py | 定义了一个TverskyLoss类,表示Tversky损失函数,用于计算模型的损失 |
utils.py | 包含一些辅助函数,如读取图像文件、显示图像等 |
上述代码均合并为ipynb | 以ipynb代码为准 |
以上文件共同构成了该系统的功能和架构。主程序文件change-detection-quick-start.py负责整个系统的流程控制,调用其他文件中定义的函数和类来完成图像处理、模型训练和可视化等任务。其他文件中定义的函数和类则提供了具体的功能实现,如图像归一化、模型定义、数据集加载和损失计算等。
为提高图像分析精度,需要在实际变化检测之前,对两个时期的卫星遥感影像进行预处理,主要目的是纠正遥感影像中的几何及辐射变形,包括去薄雾、图像精配准、裁剪和辐射归一化等。
(1)几何纠正
分别对两期全色卫星遥感影像采用基于地面控制点的多项式方法进行几何纠正,灰度重采样方法为双线性内插。对单景多光谐卫星遥感影像采用多项式方法,并与几何纠正后的全色卫星遥感影像进行配准纠正。
(2)几何配准
研究结果表明,对于变化检测来说,两期影像之间的配准误差(平均均方误差)应小于半个像元[1]。对于未达到配准精度的两期卫星遥感影像可以采用最小二乘法实现影像精配准,达到要求的配准精度。
(3)去薄雾
对于较模糊的影像,应用遥感处理软件如ER-DAS实现去薄雾处理。处理后,图像目视效果良好,纹理清晰。
(4)裁剪
对两时相影像按同区域范围裁切,使得两时相影像区域大小完全一致,便于变化检测。
(5)辐射归一化
采用线性回归法进行辐射纠正,该方法假设两时相影像中相同位置采集的无变化地物的灰度值呈线性相关。
变化向量是描述从时相1到时相⒉变化的方向和大小的光谱变化向量,如图(a)。
设时相t1,t2图像的灰度矢量分别为G=(gl. g2… , g>和H =(h1,h2,… . ,h)T,则变化向量为:
按照变化强度AG 的定义,不难发现△G |l越大,表明图像的差异越大,变化发生的可能性越大。因此,检测变化和非变化像元,可根据变化强度△G的大小,设定阈值来实现。即像元△G l超过某一阈值时,即可判定为发生变化的像元。变化的类型可由△G的指向确定,如图1(b)说明变化没有发生或不能被探测到,因为变化强度没有超过阈值;而图1©.(d)则说明不同类型的变化已经发生。
变化向量分析方法的技术流程见图2。
图像的主成分变换(PCA)是在统计特征基础上进行的一种多波段正交变换,进行的线性变换如公式(3),将原始分布在各个波段上的信息集中到少数几个互补相关的变化结果分量中,从而达到冗余压缩和信息集中的目的。差值主成分分析法实质是基于主分量变换的变化检测方法,先求两时相影像间的差值,再对多元差值影像做主成分变换,在得到的差值主成分图像上进行阈值提取,提取变化信息。
是原始图像,¥是变化后的图像,T为正交变化矩阵,由原图像协方差矩阵或者相关矩阵的特征向量组成。
差值主成分分析法的变化检测能分离变化信息,将信息量集中到少数几个主分量中。较之直接差值法,减少了波段数量,并且更能突出变化信息。差值主成分分析法的技术流程见图3。
全色影像差值法直接利用像元亮度值来进行变化检测,对经过预处理后的两时相全色影像做差值,后一时相影像减去前一时相影像,得到差值图像,在此差值图像的基础上选取适当的阈值提取变化信息。
全色影像差值法的技术流程见图4。
ERDAS的 DELTCUE自动检测是一套封装完整的变化检测模块,利用该模块进行变化检测简单方便快速。在对两期影像进行配准等预处理后,首先利用该模块对两期影像根据需要进行裁切、归一化预处理,然后选择合适的变化检测策略进行检测并生成掩膜,选择合适的过滤法则进行伪变化的剔除,最后获取变化信息,并可以根据需要选择输出的格式。
ERDAS的 DELTCUE检测其技术流程见图5。
该方法的优点是可以利用全部的波段来探测变化像元,从而避免了单一波段比较带来的信息不完整,而且可以通过变化向量的方向提供变化类型的信息。此方法对于新增建筑物、新增道路以及水系变其他的变化非常敏感,对于其他变水系的变化遗漏较多,存在以下难点:
①阈值的选取。通过选取典型变化区域的训练样本,应用变步长阈值搜索的方法来确定阈值。阈值选取的关键在于典型变化区域的选取以及步长的确定。阈值的确定需要经过多次搜索。
②变化类型的准确确定。符号编码对应的变化类型难以判断,存在“一对多”(一个编码对应多个类型)或“多对一”(一个类型对应多个编码)的情况,使得提取的变化类型遗漏或者包含其他类型信息。
③伪变化信息难于有效去除。该方法获得的道路变化检测存在的伪变化信息较多,主要原因为前后期影像上道路表面覆盖物发生变化,使得前后期影像波谱变化较大。由于云层的存在造成的伪变化未能有效去除。
④漏检率高。由于该方案在全图范围使用的是单个阈值,在进行变化检测时发生漏检的情况较多,主要是因为有些地物变化前后光谱变化未在该阈值范围之内造成。
图7差值主成分分析变化信息提取效果图
利用该方法能够检测出ALOS卫星遥感影像大部分的变化信息。对于变化类型的确定存在困难,需要进行人工干预,存在以下难点:
①变化类型难以自动区分。4种变化信息基本能提取出来,但提取后变化类型的自动确定困难,需进行人工干预。
②阈值的选取。阈值选取通过人工选取变化区域样本,进行统计分析,确定阈值。阈值的选择依据个人经验。
③漏检率高。该方法漏检率高,主要原因是对水系的变化不太敏感。
ALOS全色影像对于建筑物以及道路的变化信息非常敏感,提取出的此两类变化信息的精度非常高。但存在以下难点:
①建筑物与道路的变化类型难以区分。两种变化类型的灰度特性类似,提取的变化类型图中混淆严重。
②阈值需人工选取,受个人经验影响。
③城市场景中复杂的生态环境和各种人造目标的复杂性,使得该方法很难有效地描述和比较这些复杂的对象。
④各种原因(遮挡和阴影造成信息损失以及地物表面覆盖物变化等)引起的伪变化,降低变化检测精度。
ERDAS的 DELTCUE变化检测法的变化信息提取效果见图9。
下图完整源码&数据集&环境部署视频教程&自定义UI界面
参考博客《基于深度学习的遥感图像变化差异可视化系统》
[1]钟凯文,孙彩歌,解靓.基于GIS的广州市土地利用遥感动态监测与变化分析[J].地球信息科学学报.2009,(1).DOI:10.3969/j.issn.1560-8999.2009.01.017 .
[2]李淼,张永红,张继贤.绿地信息提取研究[J].测绘科学.2007,(2).DOI:10.3771/j.issn.1009-2307.2007.02.047 .
[3]朱运海,张百平,曹银璇,等.土地利用/覆被变化遥感检测方法与应用分析[J].地球信息科学.2007,(3).DOI:10.3969/j.issn.1560-8999.2007.03.022 .
[4]韩振镖,胡珂,李成名.基于IKONOS影像监测城市变化方法研究[J].测绘通报.2007,(5).DOI:10.3969/j.issn.0494-0911.2007.05.016 .
[5]刘玉芳,刘定生.利用纹理特征提取城市用地信息方法探索[J].测绘科学.2005,(4).46-47,56.
[6]唐德可,付琨,王宏琦.基于光谱和空域信息的城区变化检测方法研究[J].测绘科学.2005,(6).DOI:10.3771/j.issn.1009-2307.2005.06.012 .
[7]孙晓霞,张继贤.土地利用动态遥感监测的误差分析[J].测绘科学.2003,(4).DOI:10.3771/j.issn.1009-2307.2003.04.015 .
[8]陈晋,何春阳,史培军,等.基于变化向量分析的土地利用/覆盖变化动态监测(Ⅰ)–变化阈值的确定方法[J].遥感学报.2001,(4).DOI:10.3321/j.issn:1007-4619.2001.04.004 .
[9]张路.基于多元统计分析的遥感影像变化检测方法研究[J].武汉大学.2004.
[10]赵英时等编著. 遥感应用分析原理与方法 [M].科学出版社,