有哪些可用的栅格平滑/一般化工具?


46

我有一个DEM,我想对其进行平滑或概括以消除地形的极端情况(切掉峰和填谷)。理想情况下,我还希望控制“模糊性”的半径或水平。最后,我将需要一组从稍微模糊到真正模糊的栅格。(理论上,最模糊的是所有值的算术平均值的恒定栅格)。

我可以使用任何工具或方法(基于Esri,GDAL,GRASS)吗?我需要在家烘烤自己的高斯模糊例程吗?我可以使用低通滤波器(例如ArcGIS的filter),如果是这样,我是否需要运行多次以获取大半径的效果?


仅将栅格导出到更大的像元大小该怎么办?这还会导致极端的静音吗?

1
是的,这也将减少极端情况(假设隐式重采样涉及某种形式的平均),但这是平滑 DEM 的一种糟糕方法:您将创建少量大块。顺便说一句,通常不需要导出栅格来执行此操作。聚合以及重新采样到不同的像元大小是通常在基于光栅的软件中发现的基本操作。
whuber

Answers:


29

高斯模糊只是加权焦距平均值。您可以使用一系列短距离圆形邻域(未加权)来高精度地重新创建它:这是Central Limit定理的一个应用。

您有很多选择。“过滤器”太有限-仅适用于3 x 3邻域-因此请不要打扰。大型DEM的最佳选择是将计算在ArcGIS之外带入使用快速傅立叶变换的环境中:它们进行相同的焦点计算,但是(相比之下)它们执行起来非常快。(GRASS具有FFT模块。该模块用于图像处理,但如果可以将其以合理的精度重新缩放到0..255范围内,则可以将其投入DEM的使用。)除非至少有两个解决方案,值得考虑:

  1. 创建一组邻域权重,以近似于一个较大邻域的高斯模糊。使用此模糊的连续遍历来创建更平滑的DEM序列。

    (权重计算为exp(-d ^ 2 /(2r)),其中d是距离(如果愿意,可以在单元格中),r是有效半径(也可以在单元格中)。必须在延伸的圆内计算至少达到3r。这样做之后,将每个权重除以它们的总和,这样最后它们就等于1。)

  2. 或者,忘记加权;只需反复执行循环焦点均值。我正是为了研究派生网格(如坡度和坡向)如何随DEM的分辨率变化而做的。

两种方法都将很好地工作,并且在经过前几遍之后,几乎没有什么选择,但是收益递减:n个连续聚焦装置(均使用相同的邻域大小)的有效半径仅为(大约)n乘以焦点均值半径的平方根。因此,对于大量的模糊,您将要从大半径的邻域重新开始。如果使用未加权的均值,则在DEM上运行5-6次。如果您使用的权重接近高斯,则只需要通过一遍:但是您必须创建权重矩阵。

这种方法确实具有DEM的算术平均值作为极限值。


1
如果您的数据出现峰值,您可以先尝试使用中值过滤器(en.wikipedia.org/wiki/Median_filter),然后再根据Whuber的建议应用更一般的模糊处理。
MerseyViking

@Mersey这是一个很好的建议。我从未见过带有局部异常值的DEM,但是我再也不必处理原始DEM(例如原始LIDAR结果)。您无法使用FFT进行中值滤波,但是(通常)您仅需要3 x 3的邻域,因此无论如何这都是一种快速的操作。
ub

谢谢胡伯。我必须承认,我只使用过预处理的LiDAR数据,但是SRTM数据中存在一些明显的峰值,这将受益于中值滤波器。不过,它们的确倾向于2或3个样本宽,因此需要一个更大的中值滤波器。
MerseyViking,

@Mersey您仍然可以使用更大的5 x 5或7 x 7的中值滤镜。但是,如果您打算(例如)使用101 x 101滤镜,请准备好等待!您还提出了一个值得阐述的重要观点:在做任何事情之前,对DEM进行探索性分析是一个很好的主意。这将包括识别峰值(局部异常值)并表征其大小和范围。在使用过滤器清除它们之前,您需要确保它们确实是伪像(而不是某些实际现象)!

1
+1用于高程数据的FFT。实际上,我已经在32位NED数据草中进行了这项工作,以消除双向条带化。最后,这也是有问题的,因为它重新引入了困扰许多其他轮廓衍生DEM的梯田效果。
杰·瓜纳里

43

我一直在探索SciPy的signal.convolve方法(基于本菜谱),并通过以下代码片段取得了非常不错的成功:

import numpy as np
from scipy.signal import fftconvolve

def gaussian_blur(in_array, size):
    # expand in_array to fit edge of kernel
    padded_array = np.pad(in_array, size, 'symmetric')
    # build kernel
    x, y = np.mgrid[-size:size + 1, -size:size + 1]
    g = np.exp(-(x**2 / float(size) + y**2 / float(size)))
    g = (g / g.sum()).astype(in_array.dtype)
    # do the Gaussian blur
    return fftconvolve(padded_array, g, mode='valid')

我在另一个通过GDAL读取/写入float32 GeoTIFF的函数中使用了此函数(无需重新缩放为0-255字节进行图像处理),并且我一直在尝试尝试像素大小(例如2、5、20),并且非常好的输出(在ArcGIS中以1:1像素和恒定的最小/最大范围可视化):

高斯DTM

注意:此答案已更新为使用更快的基于FFT的signal.fft卷积处理功能。


1
+1不错的解决方案!我不确定,但是signal.convolve使用FFT是一个很好的选择。
ub

我一直在寻找一些我正在编写的自动缝合工具的模糊代码,偶然发现了这一点。干得好@MikeToews!
Ragi Yaser Burhum

@RagiYaserBurhum想知道更多关于您的工具的信息。MikeToews很棒的答案和非常感谢的代码片段。
杰伊·劳拉

@JayLaura没什么特别的,只需要编写一个工具即可自动缝制我和一些朋友拿着气球拍摄的图像。使用Orfeo工具箱类 orfeo-toolbox.org/SoftwareGuide/…–
Ragi Yaser Burhum 2013年

2
@whuber在修改此例程后,并未使用FFT,但现在使用FFT,并且速度更快。
Mike T

4

如果时间不长且过于复杂,则可能是对MikeT出色答案的评论。我已经玩了很多,并根据他的功能制作了一个名为FFT卷积滤波器(尚未进入“实验”阶段)的QGIS插件。除了平滑外,该插件还可以通过从原始像素中减去平滑后的栅格来锐化边缘。

在此过程中,我对Mike的功能进行了一些升级:

def __gaussian_blur1d(self, in_array, size):
        #check validity
        try:
            if 0 in in_array.shape:
                raise Exception("Null array can't be processed!")
        except TypeError:
            raise Exception("Null array can't be processed!")
        # expand in_array to fit edge of kernel
        padded_array = np.pad(in_array, size, 'symmetric').astype(float)
        # build kernel
        x, y = np.mgrid[-size:size + 1, -size:size + 1]
        g = np.exp(-(x**2 / float(size) + y**2 / float(size)))
        g = (g / g.sum()).astype(float)
        # do the Gaussian blur
        out_array = fftconvolve(padded_array, g, mode='valid')
        return out_array.astype(in_array.dtype)

有效性检查是不言而喻的,但重要的是强制转换为浮动并返回。在此之前,由于将值除以(g / g.sum()),该函数使整数数组变为黑色(仅零)。


3

在QGIS中,使用Orfeo Toolbox图像过滤可以轻松获得良好的结果。这是合理的快速,批处理模式可以正常工作。可以使用高斯,均值或各向异性扩散。

请注意,Radius是指像元数,而不是距离。

这是使用Smoothing(gaussian)的示例:

  • 生的:

    没有过滤器

  • 已过滤:

    过滤


1

高斯模糊和炫酷动画的不错解决方案。关于上述Esri过滤器工具,基本上就是硬编码为3x3大小的Esri“焦点统计”工具。焦点统计工具为您提供了更多有关移动滤镜的形状,大小和要运行的统计信息的选项。 http://desktop.arcgis.com/en/arcmap/latest/tools/spatial-analyst-toolbox/focal-statistics.htm

您还可以制作一个“不规则”过滤器,在其中传递带有权重的自己的文本文件,以用于每个单元格。文本文件在过滤器区域中具有所需的行数,并且各列用空格分隔。我猜您应该始终使用奇数行和列,因此目标单元格位于中间。

我创建了一个Excel电子表格来播放不同的权重,然后将其复制/粘贴到此文件中。如果您调整公式,它应该达到与上面相同的结果。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.