如何通过其值缓冲栅格像素?


28

左侧的像素表示树的位置及其关联的树冠半径(即像素值范围为2-5)。我想通过它们的冠状半径值来缓冲这些栅格像素。右边的图像是我希望仅使用栅格处理方法来完成的图像

我最初会考虑在ArcGIS中使用圆形焦点总和,尽管邻域设置是一个固定值,但不会考虑可变大小的冠状半径。

用像素值“缓冲”像素的好方法是什么?

在此处输入图片说明


2
您是否尝试过将栅格转换为点,然后按字段缓冲然后转换回栅格?

2
它有助于认识到这是一个非本地操作,因为该非本地性表明对如何进行计算存在固有的限制。例如,如果仅将输入中的单个孤立像素更改为较大的值,则您的输出几乎会在所有地方发生根本变化。因此,如果您知道输入值的限制,请共享它们,因为这可能会导致改进的解决方案。例如,您所有的输入值都将始终位于集合{2,3,4}中吗?
ub

@Dan Patterson这就是我想到右边的图像的方式。但是,我试图完全避免矢量运算,并避免这些步骤。
亚伦

2
@whuber此数据集表示树冠直径可变的树木。鉴于此,树冠半径测量值实际上可以在1-10之间变化。我还应该补充一点,对于不存在冠冕,缓冲输出仅需要为0,对于存在冠冕则只需为1。
亚伦

1
好,谢谢。看起来您是通过将值3的点的3个缓冲区,值4的点的4个缓冲区和值5的点的5个缓冲区联合来创建示例输出的。(您似乎已经忘记了处理具有价值的点2。)该过程不仅可以回答您的问题,而且(我相信)这是使用Spatial Analyst中可用工具的最简单解决方案。
ub

Answers:


14

这是Python 2.7使用numpy和的纯栅格解决方案scipy

import numpy as np
from scipy import ndimage
import matplotlib.pyplot as plt

#create tree location matrix with values indicating crown radius
A = np.zeros((120,320))
A[60,40] = 1
A[60,80] = 2
A[60,120] = 3
A[60,160] = 4
A[60,200] = 5
A[60,240] = 6
A[60,280] = 7

#plot tree locations
fig = plt.figure()
plt.imshow(A, interpolation='none')
plt.colorbar()

#find unique values
unique_vals = np.unique(A)
unique_vals = unique_vals[unique_vals > 0]

# create circular kernel
def createKernel(radius):
    kernel = np.zeros((2*radius+1, 2*radius+1))
    y,x = np.ogrid[-radius:radius+1, -radius:radius+1]
    mask = x**2 + y**2 <= radius**2
    kernel[mask] = 1
    return kernel

#apply binary dilation sequentially to each unique crown radius value 
C = np.zeros(A.shape).astype(bool)   
for k, radius in enumerate(unique_vals):  
    B = ndimage.morphology.binary_dilation(A == unique_vals[k], structure=createKernel(radius))
    C = C | B #combine masks

#plot resulting mask   
fig = plt.figure()
plt.imshow(C, interpolation='none')
plt.show()

输入: 在此处输入图片说明

输出: 在此处输入图片说明


1
+1为扩张方法!它也适用于近点。
Antonio Falciano 2014年

这是一个很好的例子,说明了为什么旧的喷射色彩设计如此糟糕。翠绿看起来更清晰。
naught101

8

基于向量的方法

此任务可以通过三个步骤完成:

注意:使用缓冲区字段可避免为每个冠部半径值计算缓冲区。


基于栅格的方法

避免基于向量的解决方案,此问题建议使用一种基于最近邻的元胞自动机。假设所有黑色像素均为零,则将像素平方并且其大小等于1(或者适当缩放),采用的规则非常简单:

  1. 如果像素值(VALUE)大于1,则其值变为VALUE-1,然后考虑其周围的像素。如果它们的值是小于VALUE-1,这些像素出生成长,其价值变得VALUE-1。否则,这些像素将保留下来并保持不变。
  2. 如果为VALUE<=1,则不执行任何操作(像素已耗尽!)。

这些规则必须被应用,直到所有像素都死了,即它们的值等于0或1,那么N-1次,其中N是您在输入栅格成为最高值。使用一些Python和numpy可以很容易地实现这种方法。


1
感谢您的回复afalciano。这种方法就是我在右侧创建图像并使用矢量方法的方法-我正在尝试避免这种方法。
亚伦

1
好的,亚伦,这是一种基于栅格的方法。希望这可以帮助。
Antonio Falciano 2014年

7

另一种选择是为每个像素值创建一个有条件的单独栅格,在这种情况下为4个栅格。然后将栅格扩展对应于栅格值的像素数(可能会遍历值列表)。最后,加入栅格(代数或空间栅格),以为树冠创建一个二进制栅格。


1
这个想法是正确的。细节可以改进:(1)选择为给定树冠半径的树创建二进制(0,1)指示器。(2)使用FFT可以快速计算出该选择的焦点和-使用给定半径的圆形邻域。(3)将焦点和(逐点)相加并将其与0进行比较,即可得出所需的缓冲区。
ub

7

在栅格中执行此操作是一个具有挑战性的问题,因为您没有机会使用像素值来定义缓冲区的大小。因此,正如您已经说过的,您将需要对每个值进行焦点过滤。

这是仅使用3个过滤器(我找不到的过滤器)来实现的可能答案,但并不完全如Whuber所言:当树木彼此靠近时,您的缓冲区将被截断。

1)编辑:欧几里得分配(这不能完全解决问题,因为它在较小的树附近削减了缓冲区,但比我的第一个解决方案要好得多)。

2)每个像素周围的欧几里得距离

3)带有条件语句的栅格计算器(地图代数)

Con("allocation_result" > ("distance_result" / pixel_size) , 1 , 0)

请注意,您可以根据需要调整半径(带或不带中心像素)的条件


+1这是一种创造性的方法。我将进行测试,看看使用这种方法进行扩展是否可行。
亚伦

2
欧几里得距离方法不起作用,因为它仅计算到最近的树的距离,这不一定是到树冠覆盖该点的树的距离。
ub

2

想知道为什么不使用ArcGIS的扩展工具?

import arcpy
from arcpy.sa import *

raster_in  = r'c:\test.tif'
raster_out = r'c:\test_out.tif'

outExpand1 = Expand(raster_in, 2, 2)
outExpand2 = Expand(outExpand1, 3, 3)
outExpand3 = Expand(outExpand3, 4, 4)
outExpand4 = Expand(outExpand4, 5, 5)

outExpand4.save(raster_out)

如果有重叠:最新的expand命令将覆盖先前的命令。


2

如果您有像素位置,则可以使用半径和中点圆算法(Bresenham Alg。的一种)来提供线索。IMO很容易通过这种方法创建多边形,而我认为在Python中实现这一点很容易。这一组多边形的并集为您提供覆盖区域。


我知道这不是问题,但是,您是否想进一步了解图形基元和扫描线多边形填充?对于圆来说,这非常容易。凸组合是一个时髦的口号等等....
huckfinn

如何使用基本栅格操作来应用?
ub

如果尝试在栅格空间中处理该点,请确定圆点,将它们按y或x排序,然后用直线(扫描线)填充该空间以填充圆。在三角形方法中,如果您通过近似于三角形的扇形来构建圆并尝试填充三角形,则需要测试该点是在内部还是外部(凸组合),否则进行测试。在“ GIS”方法中,构建多边形(按顺时针方向排列的多边形)并使其成为联合体是第三种方法(IMO是计算最昂贵的方法)。
huckfinn 2014年

需要明确的是:在“ GIS”方法中……进行诸如联合,交叉,接触之类的代数运算。……这是第三个IMO,计算上最昂贵的一个。
huckfinn 2014年
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.