2017-07-14 87 views
1

给定一个数组image它可能是一个2D,3D或4D,但是更可取的nD数组,我想用一个列表来提取数组的一个连续部分,列表表示我如何如果扩展名不在图像中,则沿着所有轴延伸并填充pad_value用填充切片numpy ayarray独立于数组维度

我想出了这一点:

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

+1

'numpy'函数可以处理可变数量的维度。他们将维度扩展到某个期望的数字(查看'atleast_3d'的代码)。他们交换坐标轴,以便工作坐标系(与坐骑相反)按照已知的顺序(在开始或结束时)。他们创建索引元组。 – hpaulj

回答

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]]]) 
         ^
+0

谢谢!这确实是一个有效的解决方案:但它不会复制原始图像的内存吗?我承认在我的例子中也发生了这种情况,但是我可以检查切片是否超出范围,如果不立即返回切片。 –

+0

@JonasTeuwen是的,它涉及复制。关于填充的整个想法是为了避免那些用于出界的检查来缓解处理泛型暗淡的代码。 – Divakar

1

下面是一个简单的工作示例,演示了如何反复“wittle下来”你的输入矩阵,以获得在为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) 

这个例子没有考虑到切片超越现有尺寸,但这个异常可以很容易地在循环中捕获。