Python 将函数应用于无循环的多维numpy数组
我正在使用numpy处理光栅数据(从GDAL读取后),它表示高程。我的目标是使用numpy计算阵列中每个像素的水流方向,这主要是由给定像素与其8个相邻像素之间的高程差确定的Python 将函数应用于无循环的多维numpy数组,python,arrays,numpy,multidimensional-array,raster,Python,Arrays,Numpy,Multidimensional Array,Raster,我正在使用numpy处理光栅数据(从GDAL读取后),它表示高程。我的目标是使用numpy计算阵列中每个像素的水流方向,这主要是由给定像素与其8个相邻像素之间的高程差确定的 array([[[[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8]]]]) 我已经实现了滚动窗口技术,用每个像素及其邻域生成多维数组,其工作原理如下: def rolling_window(array, window_size): itemsize
array([[[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 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_沿_轴、np.where、np.nditer和其他方法,但到目前为止没有任何效果。我想我需要的是:
我认为这里可以避免滚动窗口;与NX3X3相比,在NxN阵列上进行矢量化更容易、可读性更强 考虑以下数据:
array = np.array([[78, 72, 69, 71, 58, 49],
[74, 67, 56, 49, 46, 50],
[69, 53, 44, 37, 38, 48],
[64, 58, 55, 22, 33, 24],
[68, 61, 47, 21, 16, 19],
[74, 53, 34, 12, 11, 12]])
N=6
首先,以这种方式计算8个渐变和代码:
gradient = np.empty((8,N-2,N-2),dtype=np.float)
code = np.empty(8,dtype=np.int)
for k in range(8):
theta = -k*np.pi/4
code[k] = 2**k
j, i = np.int(1.5*np.cos(theta)),-np.int(1.5*np.sin(theta))
d = np.linalg.norm([i,j])
gradient[k] = (array[1+i: N-1+i,1+j: N-1+j]-array[1: N-1,1: N-1])/d
它很快,因为几乎没有外部环路(8)。
(-gradient).argmax(轴=0)
给出每个像素的流动方向
最后,获取
代码:
direction = (-gradient).argmax(axis=0)
result = code.take(direction)
结果:
array([[ 2, 2, 4, 4],
[ 1, 2, 4, 8],
[128, 1, 2, 4],
[ 2, 1, 4, 4]])
您能否共享
滚动窗口函数定义?另外,什么是flow\u idx\u dict
?你能添加可用于运行flow_dir
的示例输入吗?我已经在滚动窗口和flow dict中添加了。np.arange(100)的示例被重塑为(10,10)就足够作为flow_dir的输入了,尽管实际上我的数组要大得多,并且它们的值更可变。因此,我将使用arr=np.arange(90)
然后流动方向(arr)
?我想这会造成错误。你看过了吗?估计也一样。查看np.pad,使您能够反映边缘值,以帮助处理边缘影响。所以我假设,你只需要找到最小的差异(你的窗口-中间)就可以从字典中提取你的值,但不清楚你是单独使用基数,还是考虑重复,或者相反的最大下降。当然,你会很高兴避免滚动窗口,我的大脑是如何在空间分析背景下工作的,而不是数学或计算机科学。我认为这非常接近我所需要的,只是编码不像预期的那样,例如,给定一个[3,2,0]、[1,6,9]、[4,4,4]的窗口,中心像素(6)的输出是4(即南),但应该是128(NE),就像这里的方向编码一样。可能是因为渐变数组的一半数据被设置为零。我需要做一些编辑才能运行,但它仍然不在那里-对角线的渐变差仍然为零。对于那些,j,i是0,0,而不是-1,-1等等。我还发现argmax实际上是正确的函数,因为它是所追求的最大压降。忽略对角线,现在可以正常工作了,所以我认为需要进一步工作的只是分配I&j的行。问题是3/2,在我的Python2.7安装中返回1。将此更改为3/2.0解决了此问题。是的,我相信是这样,谢谢您抽出时间。使用1000 x 1000个单元的测试阵列,您的代码比迭代滚动窗口方法快大约100倍,完全满足我的要求。现在,我需要看看边缘盒和水槽。。。