在2d NumPy数组中迭代子矩阵

2izufjch  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(90)

在图像的浮点高度图上,我迭代数组中的每个2x2正方形子矩阵,执行计算,对结果求和。这是缓慢的,因为海拔Map很大(16K x 16K),并且循环比NumPy或SciPy慢。如何遍历多维NumPy数组块?
这个3x3 NumPy数组可以是NxM:

[[0.0, 1.0, 2.0],
 [3.0, 4.0, 5.0],
 [6.0, 7.0, 8.0]]

我想要一个快速迭代器,它产生:

> [0.0, 1.0, 3.0, 4.0]
> [1.0, 2.0, 4.0, 5.0]
> [3.0, 4.0, 6.0, 7.0]
> [4.0, 5.0, 7.0, 8.0]

子矩阵中的值的顺序并不重要,只要它们是一致的(逆时针、顺时针、Z字形等)。我的代码不使用NumPy:

shape_dem_data = shape_dem.getdata() # shape_dem is a PIL image

for x in range(width - 1):
    for y in range(height - 1):
        i = y * width + x
        z1 = shape_dem_data[i]
        z2 = shape_dem_data[i + 1]
        z3 = shape_dem_data[i + width + 1]
        z4 = shape_dem_data[i + width]
        # Create a bit-mask indicating the available elevation data
        mask = (z1 != NULL_HEIGHT) << 3 |\
               (z2 != NULL_HEIGHT) << 2 |\
               (z3 != NULL_HEIGHT) << 1 |\
               (z4 != NULL_HEIGHT) << 0
        if mask == 0b1111:
            # All data available.
            surface_area += area_of_triangle(((0, 0, z1), (gsd, 0, z2), (gsd, gsd, z3)))
            surface_area += area_of_triangle(((0, 0, z1), (gsd, gsd, z3), (0, gsd, z4)))
            pass
        elif mask == 0b1101:
            # Top left triangle
            surface_area += area_of_triangle(((0, 0, z1), (gsd, 0, z2), (0, gsd, z4)))
        elif mask == 0b0111:
            # Bottom right triangle
            surface_area += area_of_triangle(((gsd, 0, z2), (gsd, gsd, z3), (0, gsd, z4)))
        elif mask == 0b1011:
            # Bottom left triangle
            surface_area += area_of_triangle(((0, 0, z1), (gsd, gsd, z3), (0, gsd, z4)))
        elif mask == 0b1110:
            # Top right triangle
            surface_area += area_of_triangle(((0, 0, z1), (gsd, 0, z2), (gsd, gsd, z3)))
return surface_area

目的是计算高度数组的表面积(给定像素之间的固定采样距离)。位屏蔽检查哪些像素组合不是“空”高度(并相应地调整计算)。

x0fgdtte

x0fgdtte1#

使用scikit-image的view_as_windows是一种可能的方法:

In [55]: import numpy as np

In [56]: from skimage.util import view_as_windows

In [57]: wrows, wcols = 2, 2

In [58]: img = np.arange(9).reshape(3, 3).astype(np.float64)

In [59]: img
Out[59]: 
array([[0., 1., 2.],
       [3., 4., 5.],
       [6., 7., 8.]])

In [60]: view_as_windows(img, window_shape=(wrows, wcols), step=1).reshape(-1, wrows*wcols)
Out[60]: 
array([[0., 1., 3., 4.],
       [1., 2., 4., 5.],
       [3., 4., 6., 7.],
       [4., 5., 7., 8.]])

编辑

如果上面的方法对你无效,scipy.ndimage.generic_filter可以做到这一点:

In [77]: from scipy.ndimage import generic_filter

In [78]: def surface_area(block):
    ...:     z1, z2, z3, z4 = block
    ...:     # YOUR CODE HERE
    ...:     return z1
    ...: 
    ...: 

In [79]: generic_filter(img, function=surface_area, 
    ...:                size=(wrows, wcols), mode='constant', cval=np.nan)
    ...: 
Out[79]: 
array([[nan, nan, nan],
       [nan,  0.,  1.],
       [nan,  3.,  4.]])

请注意,您必须更改函数surface_area,以便它正确执行计算(在我的玩具示例中,它只是返回每个2×2窗口的左上角值)。

相关问题