使用padding切片numpy ayarray,与数组维

时间:2017-07-14 17:29:26

标签: python numpy multidimensional-array

给定一个数组image,它可能是2D,3D或4D,但是更好的nD数组,我想在一个点周围提取数组的连续部分,其中列表表示我如何沿所有轴延伸如果扩展名不在图像中,则使用pad_value填充数组。

我想出了这个:

def extract_patch_around_point(image, loc, extend, pad_value=0):
    offsets_low = []
    offsets_high = []
    for i, x in enumerate(loc):
        offset_low = -np.min([x - extend[i], 0])
        offsets_low.append(offset_low)
        offset_high = np.max([x + extend[i] - image.shape[1] + 1, 0])
        offsets_high.append(offset_high)

    upper_patch_offsets = []
    lower_image_offsets = []
    upper_image_offsets = []
    for i in range(image.ndim):
        upper_patch_offset = 2*extend[i] + 1 - offsets_high[i]
        upper_patch_offsets.append(upper_patch_offset)

        image_offset_low = loc[i] - extend[i] + offsets_low[i]
        image_offset_high = np.min([loc[i] + extend[i] + 1, image.shape[i]])

        lower_image_offsets.append(image_offset_low)
        upper_image_offsets.append(image_offset_high)

    patch = pad_value*np.ones(2*np.array(extend) + 1)

    # This is ugly
    A = np.ix_(range(offsets_low[0], upper_patch_offsets[0]),
               range(offsets_low[1], upper_patch_offsets[1]))
    B = np.ix_(range(lower_image_offsets[0], upper_image_offsets[0]),
               range(lower_image_offsets[1], upper_image_offsets[1]))
    patch[A] = image[B]

    return patch

目前它仅适用于2D,因为使用A,B等索引技巧。我不想检查维度的数量并使用不同的索引方案。如何在image.ndim上独立完成?

2 个答案:

答案 0 :(得分:1)

这是一个简单的工作示例,演示了如何迭代地“缩小”输入矩阵以获取nDims中某个点周围的补丁:

    import numpy as np

    # Givens. Matrix to be sliced, point around which to slice,
    # and the padding around the given point
    matrix = np.random.normal(size=[5,5,5])
    loc = (3,3,3)
    padding = 2

    # If one knows the dimensionality, the slice can be obtained easily
    ans1 = matrix[loc[0] - padding:loc[0] + 1,
                  loc[1] - padding:loc[1] + 1,
                  loc[2] - padding:loc[2] + 1]

    # If one does not know the dimensionality, the slice can be
    # obtained iteratively
    ans2 = matrix
    for i in range(matrix.ndim):
        # Compute slice for the particular axis
        s = slice(loc[i] - padding, loc[i] + 1, 1)
        # Move particular axis to front, slice it, then move it back
        ans2 = np.moveaxis(np.moveaxis(ans2, i, 0)[s], 0, i)

    # Assert the two answers are equal
    np.testing.assert_array_equal(ans1, ans2)

此示例未考虑现有维度之外的切片,但该异常可以很容易地在循环中捕获。

答案 1 :(得分:1)

根据我对要求的理解,我建议使用零填充版本,然后使用slice表示法使其在维数上保持通用,如此 -

def extract_patch_around_point(image, loc, extend, pad_value=0):
    extend = np.asarray(extend)
    image_ext_shp = image.shape + 2*np.array(extend)
    image_ext = np.full(image_ext_shp, pad_value)
    insert_idx =  [slice(i,-i) for i in extend]
    image_ext[insert_idx] = image

    region_idx = [slice(i,j) for i,j in zip(loc,extend*2+1+loc)]
    return image_ext[region_idx]

样品运行 -

2D案例:

In [229]: np.random.seed(1234)
     ...: image = np.random.randint(11,99,(13,8))
     ...: loc = (5,3)
     ...: extend = np.array([2,4])
     ...: 

In [230]: image
Out[230]: 
array([[58, 94, 49, 64, 87, 35, 26, 60],
       [34, 37, 41, 54, 41, 37, 69, 80],
       [91, 84, 58, 61, 87, 48, 45, 49],
       [78, 22, 11, 86, 91, 14, 13, 30],
       [23, 76, 86, 92, 25, 82, 71, 57],
       [39, 92, 98, 24, 23, 80, 42, 95],
       [56, 27, 52, 83, 67, 81, 67, 97],
       [55, 94, 58, 60, 29, 96, 57, 48],
       [49, 18, 78, 16, 58, 58, 26, 45],
       [21, 39, 15, 93, 66, 89, 34, 61],
       [73, 66, 95, 11, 44, 32, 82, 79],
       [92, 63, 75, 96, 52, 12, 25, 14],
       [41, 23, 84, 30, 37, 79, 75, 33]])

In [231]: image[loc]
Out[231]: 24

In [232]: out = extract_patch_around_point(image, loc, extend, pad_value=0)

In [233]: out
Out[233]: 
array([[ 0, 78, 22, 11, 86, 91, 14, 13, 30],
       [ 0, 23, 76, 86, 92, 25, 82, 71, 57],
       [ 0, 39, 92, 98, 24, 23, 80, 42, 95], <-- At middle
       [ 0, 56, 27, 52, 83, 67, 81, 67, 97],
       [ 0, 55, 94, 58, 60, 29, 96, 57, 48]])
                         ^

3D案例:

In [234]: np.random.seed(1234)
     ...: image = np.random.randint(11,99,(13,5,8))
     ...: loc = (5,2,3)
     ...: extend = np.array([1,2,4])
     ...: 

In [235]: image[loc]
Out[235]: 82

In [236]: out = extract_patch_around_point(image, loc, extend, pad_value=0)

In [237]: out.shape
Out[237]: (3, 5, 9)

In [238]: out
Out[238]: 
array([[[ 0, 23, 87, 19, 58, 98, 36, 32, 33],
        [ 0, 56, 30, 52, 58, 47, 50, 28, 50],
        [ 0, 70, 93, 48, 98, 49, 19, 65, 28],
        [ 0, 52, 58, 30, 54, 55, 46, 53, 31],
        [ 0, 37, 34, 13, 76, 38, 89, 79, 71]],

       [[ 0, 14, 92, 58, 72, 74, 43, 24, 67],
        [ 0, 59, 69, 46, 68, 71, 94, 20, 71],
        [ 0, 61, 62, 60, 82, 92, 15, 14, 57], <-- At middle
        [ 0, 58, 74, 95, 16, 94, 83, 83, 74],
        [ 0, 67, 25, 92, 71, 19, 52, 44, 80]],

       [[ 0, 74, 28, 12, 12, 13, 62, 88, 63],
        [ 0, 25, 58, 86, 76, 40, 20, 91, 61],
        [ 0, 28, 42, 85, 22, 45, 64, 35, 66],
        [ 0, 64, 34, 69, 27, 17, 92, 89, 68],
        [ 0, 15, 57, 86, 17, 98, 29, 59, 50]]])
                          ^