【发布时间】:2015-12-17 13:52:58
【问题描述】:
我正在使用 numpy 处理栅格数据(从 GDAL 读取后),它表示海拔。我的目标是使用 numpy 计算数组中每个像素的水流方向,主要根据给定像素与其 8 个相邻像素之间的高程差异确定。
我已经实现了一个滚动窗口技术来生成一个包含每个像素及其邻居的多维数组,其工作原理如下:
def rolling_window(array, window_size):
itemsize = array.itemsize
shape = (array.shape[0] - window_size + 1,
array.shape[1] - window_size + 1,
window_size, window_size)
strides = (array.shape[1] * itemsize, itemsize,
array.shape[1] * itemsize, itemsize)
return np.lib.stride_tricks.as_strided(array, shape=shape, strides=strides)
array = np.arange(100)
array = array.reshape(10, 10)
w = rolling_window(array, 3)
# produces array with shape (8, 8, 3, 3) - edge cases are not currently dealt with.
因此,一系列 3 x 3 阵列,以 1,1 处的研究像素为中心,每个阵列位于栅格“行”阵列的另一个维度内,例如,从输入的一个像素开始,表示它的阵列可以如下,其中像素值为 4 是研究像素,其他值是它的直接邻居。
array([[[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]]]])
我当前处理这个多维数组的方法的简化版本是以下函数:
def flow_dir(array):
# Value to assign output based on element index.
flow_idx_dict = {0: 32,
1: 64,
2: 128,
3: 16,
5: 1,
6: 8,
7: 4,
8: 2}
# Generates the rolling window array as mentioned above.
w = rolling_window(array, 3)
# Iterate though each pixel array.
for x, i in enumerate(w, 1):
for y, j in enumerate(i, 1):
j = j.flatten()
# Centre pixel value after flattening.
centre = j[4]
# Some default values.
idx = 4
max_drop = 0
# Iterate over pixel values in array.
for count, px in enumerate(j):
# Calculate difference between centre pixel and neighbour.
drop = centre - px
# Find the maximum difference pixel index.
if count != 4:
if drop > max_drop:
max_drop = drop
idx = count
# Assign a value from a dict, matching index to flow direction category.
value = flow_idx_dict[idx]
# Update each pixel in the input array with the flow direction.
array[x, y] = value
return array
可以理解,所有这些 for 循环和 if 语句都非常慢。我知道必须有一个矢量化的 numpy 方法来做到这一点,但我正在努力寻找我需要的确切功能,或者可能不了解如何正确实现它们。我尝试过 np.apply_along_axis、np.where、np.nditer 等,但到目前为止都无济于事。我认为我需要的是:
一种将函数应用于滚动窗口生成的每个像素数组的方法,而无需使用 for 循环来访问它们。
查找最大drop index值,不使用if语句和枚举。
能够批量更新输入数组,而不是单个元素。
【问题讨论】:
-
你能分享
rolling_window函数定义吗?另外,flow_idx_dict是什么?您能否添加可用于运行flow_dir的示例输入? -
我在 rolling_window 和 flow 字典中添加了。将 np.arange(100) 重整为 (10, 10) 的示例足以作为 flow_dir 的输入,尽管实际上我的数组要大得多,并且它们的值变化更大。
-
那么,我会先使用
arr = np.arange(90),然后再使用flow_dir(arr)?我认为这会引发错误。 -
你看过numpy.gradient吗?
-
想了很多。查看 np.pad 以使您能够反映边缘值以帮助处理边缘影响。因此,我假设,您只需要找到最小差异(您的窗口 - 中间)即可将您的值从字典中提取出来,但目前尚不清楚您是单独使用基数还是考虑重复甚至相反的最大下降。
标签: python arrays numpy multidimensional-array raster