有人可以根据实际的分析经验告诉我,这两种凹陷填充算法之间是否存在差异,除了它们处理和填充DEM中凹陷(沉)的速度之外?
奥利维尔·普兰琼(Olivier Planchon),弗雷德里克·达布(Frederic Darboux)
和
在数字高程模型中识别和填充表面凹陷的有效方法,以进行水文分析和建模
王刘
谢谢。
有人可以根据实际的分析经验告诉我,这两种凹陷填充算法之间是否存在差异,除了它们处理和填充DEM中凹陷(沉)的速度之外?
奥利维尔·普兰琼(Olivier Planchon),弗雷德里克·达布(Frederic Darboux)
和
在数字高程模型中识别和填充表面凹陷的有效方法,以进行水文分析和建模
王刘
谢谢。
Answers:
从理论上讲,凹陷填充只有一个解决方案,尽管可以有很多方法来解决该问题,这就是为什么有这么多不同的凹陷填充算法的原因。因此,从理论上讲,用Planchon和Darboux或Wang和Liu填充的DEM,或任何其他凹陷填充算法,之后应该看起来相同。但是,他们可能不会这样做,并且有一些原因。首先,虽然只有一种解决方案可以填充凹陷,但是有很多不同的解决方案可以在已填充凹陷的平坦表面上应用渐变。也就是说,通常我们不仅要填充凹陷,而且还希望迫使流过填充凹陷的表面。这通常涉及添加非常小的渐变,并且1)有很多不同的策略可以做到这一点(其中很多直接内置于各种凹陷填充算法中),并且2)处理如此小的数值通常会导致较小的舍入误差,从而可能在填充的DEM之间存在差异。看一下这张图片:
它显示了两个DEM之间的“差异DEM”,它们都是从源DEM生成的,但一个使用Planchon和Darboux算法填充了凹陷,另一个使用Wang和Liu算法填充了凹陷。我应该说,抑郁症填充算法都是Whitebox GAT中的工具,因此与上述答案中所描述的不同,它们是算法的不同实现。请注意,DEM的差异均小于0.008 m,并且它们完全包含在地形凹陷区域内(即,不在凹陷内的网格单元的高度与输入DEM完全相同)。8 mm的较小值反映了用于在填充操作留下的平面上强制流动的微小值,并且当用浮点值表示这么小的数字时,舍入误差的范围也可能会在一定程度上影响该值。您看不到上图中显示的两个填充的DEM,但是您可以从它们的图例条目中得知它们也具有与期望值完全相同的高程值范围。
那么,为什么要在上面的答案中观察到沿DEM的峰和其他非低压区的高程差异?我认为这实际上只能归结为算法的特定实现。该工具内部可能正在发生某种情况,以解决这些差异,并且与实际算法无关。考虑到学术论文中算法的描述与其实际实现之间的差距,再加上在GIS内部如何处理数据的复杂性,这对我来说并不奇怪。无论如何,感谢您提出这个非常有趣的问题。
干杯,
约翰
我将尝试回答我自己的问题-dun dun dun。
我使用SAGA GIS使用基于Planchon和Darboux(PD)的填充工具(以及基于Wang和Liu(WL)的填充工具针对6个不同的流域)检查了填充流域的差异。(在此,我仅展示两组结果-在所有6个分水岭上它们都是相似的)(我说“基于”),因为始终存在关于差异是由于算法还是算法的特定实现而产生的问题。
分水岭DEM是通过使用USGS提供的分水岭shapefile剪切镶嵌的NED 30 m数据而生成的。对于每个基本DEM,运行两个工具。每个工具只有一个选项,即最小强制斜率,这在两个工具中均设置为0.01。
分水岭填满后,我使用栅格计算器来确定结果网格中的差异-这些差异仅应归因于两种算法的行为不同。
下方显示代表差异或不存在差异的图像(基本上是计算得出的差异栅格)。用于计算差异的公式为:((((PD_Filled-WL_Filled)/ PD_Filled)* 100)-给出每个单元格之间的差异百分比。灰色的单元格现在显示出差异,单元格的颜色变红表明所产生的PD升高更大,而绿色的单元格则表明所导致的WL升高更大。
第一分水岭:怀俄明州分水岭
这是这些图片的图例:
差异仅在-0.0915%到+ 0.0910%之间。差异似乎集中在峰和窄流通道周围,其中WL算法在通道中略高,局部区域周围的PD略高。
清除分水岭,怀俄明州,缩放1
清除分水岭,怀俄明州,放大2
第二分水岭:新罕布什尔州温尼伯索基河
这是这些图片的图例:
温尼伯索基河,新罕布什尔州,放大1
差异仅在-0.323%到+ 0.315%之间。差异似乎集中在峰和窄流通道周围,(如前所述)WL算法在通道中略高,局部区域周围的PD略高。
太好了,有什么想法吗?在我看来,这些差异似乎微不足道,不太可能影响进一步的计算。有人同意吗?我正在通过完成这六个分水岭的工作流程进行检查。
编辑: 更多信息。似乎WL算法会导致较宽的不太明显的通道,从而导致较高的地形指数值(我的最终导数数据集)。下面左图是PD算法,右图是WL算法。
这些图像显示了相同位置的地形指数差异-右侧WL图片中较宽的湿润区域(更多通道-更红,TI更高);左侧的PD图片中的通道较窄(湿区较少-红色较少,红色区域较窄,TI较低)。
另外,这里是PD如何处理(左)凹陷,而WL如何处理(右)-注意在WL填充的输出中,凸起的橙色(较低的地形指数)线段/线穿过凹陷吗?
因此,差异尽管很小,但似乎确实会影响其他分析。
如果有人感兴趣,这是我的Python脚本:
#! /usr/bin/env python
# ----------------------------------------------------------------------
# Create Fill Algorithm Comparison
# Author: T. Taggart
# ----------------------------------------------------------------------
import os, sys, subprocess, time
# function definitions
def runCommand_logged (cmd, logstd, logerr):
p = subprocess.call(cmd, stdout=logstd, stderr=logerr)
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# environmental variables/paths
if (os.name == "posix"):
os.environ["PATH"] += os.pathsep + "/usr/local/bin"
else:
os.environ["PATH"] += os.pathsep + "C:\program files (x86)\SAGA-GIS"
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# global variables
WORKDIR = "D:\TomTaggart\DepressionFillingTest\Ran_DEMs"
# This directory is the toplevel directoru (i.e. DEM_8)
INPUTDIR = "D:\TomTaggart\DepressionFillingTest\Ran_DEMs"
STDLOG = WORKDIR + os.sep + "processing.log"
ERRLOG = WORKDIR + os.sep + "processing.error.log"
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# open logfiles (append in case files are already existing)
logstd = open(STDLOG, "a")
logerr = open(ERRLOG, "a")
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# initialize
t0 = time.time()
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# loop over files, import them and calculate TWI
# this for loops walks through and identifies all the folder, sub folders, and so on.....and all the files, in the directory
# location that is passed to it - in this case the INPUTDIR
for dirname, dirnames, filenames in os.walk(INPUTDIR):
# print path to all subdirectories first.
#for subdirname in dirnames:
#print os.path.join(dirname, subdirname)
# print path to all filenames.
for filename in filenames:
#print os.path.join(dirname, filename)
filename_front, fileext = os.path.splitext(filename)
#print filename
if filename_front == "w001001":
#if fileext == ".adf":
# Resetting the working directory to the current directory
os.chdir(dirname)
# Outputting the working directory
print "\n\nCurrently in Directory: " + os.getcwd()
# Creating new Outputs directory
os.mkdir("Outputs")
# Checks
#print dirname + os.sep + filename_front
#print dirname + os.sep + "Outputs" + os.sep + ".sgrd"
# IMPORTING Files
# --------------------------------------------------------------
cmd = ['saga_cmd', '-f=q', 'io_gdal', 'GDAL: Import Raster',
'-FILES', filename,
'-GRIDS', dirname + os.sep + "Outputs" + os.sep + filename_front + ".sgrd",
#'-SELECT', '1',
'-TRANSFORM',
'-INTERPOL', '1'
]
print "Beginning to Import Files"
try:
runCommand_logged(cmd, logstd, logerr)
except Exception, e:
logerr.write("Exception thrown while processing file: " + filename + "\n")
logerr.write("ERROR: %s\n" % e)
print "Finished importing Files"
# --------------------------------------------------------------
# Resetting the working directory to the ouputs directory
os.chdir(dirname + os.sep + "Outputs")
# Depression Filling - Wang & Liu
# --------------------------------------------------------------
cmd = ['saga_cmd', '-f=q', 'ta_preprocessor', 'Fill Sinks (Wang & Liu)',
'-ELEV', filename_front + ".sgrd",
'-FILLED', filename_front + "_WL_filled.sgrd", # output - NOT optional grid
'-FDIR', filename_front + "_WL_filled_Dir.sgrd", # output - NOT optional grid
'-WSHED', filename_front + "_WL_filled_Wshed.sgrd", # output - NOT optional grid
'-MINSLOPE', '0.0100000',
]
print "Beginning Depression Filling - Wang & Liu"
try:
runCommand_logged(cmd, logstd, logerr)
except Exception, e:
logerr.write("Exception thrown while processing file: " + filename + "\n")
logerr.write("ERROR: %s\n" % e)
print "Done Depression Filling - Wang & Liu"
# Depression Filling - Planchon & Darboux
# --------------------------------------------------------------
cmd = ['saga_cmd', '-f=q', 'ta_preprocessor', 'Fill Sinks (Planchon/Darboux, 2001)',
'-DEM', filename_front + ".sgrd",
'-RESULT', filename_front + "_PD_filled.sgrd", # output - NOT optional grid
'-MINSLOPE', '0.0100000',
]
print "Beginning Depression Filling - Planchon & Darboux"
try:
runCommand_logged(cmd, logstd, logerr)
except Exception, e:
logerr.write("Exception thrown while processing file: " + filename + "\n")
logerr.write("ERROR: %s\n" % e)
print "Done Depression Filling - Planchon & Darboux"
# Raster Calculator - DIff between Planchon & Darboux and Wang & Liu
# --------------------------------------------------------------
cmd = ['saga_cmd', '-f=q', 'grid_calculus', 'Grid Calculator',
'-GRIDS', filename_front + "_PD_filled.sgrd",
'-XGRIDS', filename_front + "_WL_filled.sgrd",
'-RESULT', filename_front + "_DepFillDiff.sgrd", # output - NOT optional grid
'-FORMULA', "(((g1-h1)/g1)*100)",
'-NAME', 'Calculation',
'-FNAME',
'-TYPE', '8',
]
print "Depression Filling - Diff Calc"
try:
runCommand_logged(cmd, logstd, logerr)
except Exception, e:
logerr.write("Exception thrown while processing file: " + filename + "\n")
logerr.write("ERROR: %s\n" % e)
print "Done Depression Filling - Diff Calc"
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# finalize
logstd.write("\n\nProcessing finished in " + str(int(time.time() - t0)) + " seconds.\n")
logstd.close
logerr.close
# ----------------------------------------------------------------------
在算法级别,这两种算法将产生相同的结果。
为什么您会变得与众不同?
数据表示
如果您的一种算法使用float
(32位),另一种使用double
(64位),则不应期望它们产生相同的结果。同样,某些实现表示浮点值使用整数数据类型,这也可能导致差异。
排水执法
但是,如果使用局部方法确定流向,则两种算法都将产生平坦区域,该平坦区域不会流失。
Planchon和Darboux通过在平坦区域的高度上增加一小部分来加强排水来解决此问题。如Barnes等人所述。(2014)的论文“在栅格数字高程模型中有效分配排水平面上的排水方向”,如果该增量太大,则增加此增量实际上会导致不自然地重新路由平坦区域之外的排水。一种解决方案是使用例如nextafter
功能。
其他想法
Wang和Liu(2006)是Priority-Flood算法的一种变体,正如我在论文“ Priority-flood:一种用于数字高程模型的最佳凹陷填充和分水岭标记算法”中所讨论的。
Priority-Flood对于整数和浮点数据都具有时间复杂性。在我的论文中,我指出避免在优先级队列中放置单元格是提高算法性能的好方法。其他作者,如Zhou等。(2016)和Wei等。(2018)使用这个想法进一步提高了算法的效率。所有这些算法的源代码都在这里。
考虑到这一点,Planchon and Darboux(2001)算法是一个科学失败的地方的故事。Priority-Flood 在整数数据上以O(N)时间工作,在浮点数据上以O(N log N)时间工作,而P&D在O(N 1.5)时间工作。这转化为巨大的性能差异,该差异随DEM的大小呈指数增长:
到2001年,Ehlschlaeger,Vincent,Soille,Beucher,Meyer和Gratin共同发表了五篇论文,详细介绍了Priority-Flood算法。Planchon和Darboux以及他们的审稿人都错过了所有这些信息,并发明了一个速度要慢几个数量级的算法。现在到了2018年,我们仍在构建更好的算法,但仍在使用P&D。我认为这很不幸。