2016-12-14 64 views
5

在numpy中,如果我正在切片超過數組的末尾,是否有一種方法可以填零填充條目,以便獲得所需切片大小的東西?零填充切片過去數組在numpy末尾

例如,

>>> x = np.ones((3,3,)) 
>>> x 
array([[ 1., 1., 1.], 
     [ 1., 1., 1.], 
     [ 1., 1., 1.]]) 
>>> x[1:4, 1:4] # would behave as x[1:3, 1:3] by default 
array([[ 1., 1., 0.], 
     [ 1., 1., 0.], 
     [ 0., 0., 0.]]) 
>>> x[-1:2, -1:2] 
array([[ 0., 0., 0.], 
     [ 0., 1., 1.], 
     [ 0., 1., 1.]]) 

在視覺上,我想的出界外地區進行零填充:

enter image description here

我處理照片,並且希望爲了表示移除我的應用程序的圖像。

我目前的計劃是在切片之前使用np.pad使整個陣列變大,但索引似乎有點棘手。有沒有一種可能更簡單的方法?

+1

我手動只怕填充是唯一的選擇,因爲修改NumPy數組上的'[]'的行爲是不可能的(因爲'numpy.ndarray'在C中實現,它禁止了動態y替換'numpy.ndarray .__ getitem__')。 –

回答

4

據我知道有這樣的問題沒有numpy的溶液(也沒有在我知道任何包)。你可以自己做,但即使你只想要基本的切片,它也會是非常複雜的。我建議你手動np.pad你的數組,並簡單地抵消你的開始/停止/步驟,然後再切實分割它。

但是如果你需要的支持是整數和片,而一步,我有一些這方面的「工作代碼」:

import numpy as np 

class FunArray(np.ndarray): 
    def __getitem__(self, item): 

     all_in_slices = [] 
     pad = [] 
     for dim in range(self.ndim): 
      # If the slice has no length then it's a single argument. 
      # If it's just an integer then we just return, this is 
      # needed for the representation to work properly 
      # If it's not then create a list containing None-slices 
      # for dim>=1 and continue down the loop 
      try: 
       len(item) 
      except TypeError: 
       if isinstance(item, int): 
        return super().__getitem__(item) 
       newitem = [slice(None)]*self.ndim 
       newitem[0] = item 
       item = newitem 
      # We're out of items, just append noop slices 
      if dim >= len(item): 
       all_in_slices.append(slice(0, self.shape[dim])) 
       pad.append((0, 0)) 
      # We're dealing with an integer (no padding even if it's 
      # out of bounds) 
      if isinstance(item[dim], int): 
       all_in_slices.append(slice(item[dim], item[dim]+1)) 
       pad.append((0, 0)) 
      # Dealing with a slice, here it get's complicated, we need 
      # to correctly deal with None start/stop as well as with 
      # out-of-bound values and correct padding 
      elif isinstance(item[dim], slice): 
       # Placeholders for values 
       start, stop = 0, self.shape[dim] 
       this_pad = [0, 0] 
       if item[dim].start is None: 
        start = 0 
       else: 
        if item[dim].start < 0: 
         this_pad[0] = -item[dim].start 
         start = 0 
        else: 
         start = item[dim].start 
       if item[dim].stop is None: 
        stop = self.shape[dim] 
       else: 
        if item[dim].stop > self.shape[dim]: 
         this_pad[1] = item[dim].stop - self.shape[dim] 
         stop = self.shape[dim] 
        else: 
         stop = item[dim].stop 
       all_in_slices.append(slice(start, stop)) 
       pad.append(tuple(this_pad)) 

     # Let numpy deal with slicing 
     ret = super().__getitem__(tuple(all_in_slices)) 
     # and padding 
     ret = np.pad(ret, tuple(pad), mode='constant', constant_values=0) 

     return ret 

這可以使用如下:

>>> x = np.arange(9).reshape(3, 3) 
>>> x = x.view(FunArray) 
>>> x[0:2] 
array([[0, 1, 2], 
     [3, 4, 5]]) 
>>> x[-3:2] 
array([[0, 0, 0], 
     [0, 0, 0], 
     [0, 0, 0], 
     [0, 1, 2], 
     [3, 4, 5]]) 
>>> x[-3:2, 2] 
array([[0], 
     [0], 
     [0], 
     [2], 
     [5]]) 
>>> x[-1:4, -1:4] 
array([[0, 0, 0, 0, 0], 
     [0, 0, 1, 2, 0], 
     [0, 3, 4, 5, 0], 
     [0, 6, 7, 8, 0], 
     [0, 0, 0, 0, 0]]) 

注意這可能包含錯誤和「不乾淨編碼」的部分,我從來沒有使用過,除非在微不足道的情況下。

4

本課程可以處理您的第一個測試(x[1:4, 1:4]),並且可以進行修改以處理您的其他測試(即,如果您願意,可以將零附加到開頭)。

class CustomArray(): 

    def __init__(self, numpy_array): 
     self._array = numpy_array 

    def __getitem__(self, val): 

     # Get the shape you wish to return 
     required_shape = [] 
     for i in range(2): 
      start = val[i].start 
      if not start: 
       start = 0 
      required_shape.append(val[i].stop - start) 

     get = self._array[val] 

     # Check first dimension 
     while get.shape[0] < required_shape[0]: 
      get = np.concatenate((get, np.zeros((1, get.shape[1])))) 

     # Check second dimension 
     get = get.T 
     while get.shape[0] < required_shape[1]: 
      get = np.concatenate((get, np.zeros((1, get.shape[1])))) 
     get = get.T 

     return get 

下面是一個例子的它的用法:

a = CustomArray(np.ones((3, 3))) 

print(a[:2, :2]) 
[[ 1. 1.] 
[ 1. 1.]] 

print(a[:4, 1:6]) 
[[ 1. 1. 0. 0. 0.] 
[ 1. 1. 0. 0. 0.] 
[ 1. 1. 0. 0. 0.] 
[ 0. 0. 0. 0. 0.]] 

# The actual numpy array is stored in the _array attribute 
actual_numpy_array = a._array 
0

在一維數組我這樣做的情況下,可能是有用的,如果有人掉下這裏...

def getPaddedSlice(npArray, pos, lenSegment, center = False): 
    lenNpArray = len(npArray) 
    if center: 
     if lenSegment % 2 == 0: 
      startIndex = int(pos - math.floor(lenSegment/2.0)) + 1 
      lastIndex = int(pos + math.ceil(lenSegment/2.0)) + 1 

     else : 
      startIndex = int(pos - math.floor(lenSegment/2.0)) 
      lastIndex = int(pos + math.ceil(lenSegment/2.0)) + 1 
    else: 
     startIndex = pos 
     lastIndex = startIndex + lenSegment 

    if startIndex < 0: 
     padded_slice = npArray[0: lastIndex] 
     padded_slice = np.concatenate((np.zeros(abs(startIndex)), padded_slice)) 
    else: 
     if center : 
      padded_slice = npArray[startIndex: lastIndex] 
     else: 
      padded_slice = npArray[pos: lastIndex] 

    if lastIndex > len(npArray): 
     if center : 
      padded_slice = npArray[startIndex: pos + lenSegment] 
      padded_slice = np.concatenate((padded_slice, np.zeros(lastIndex - len(a)))) 
     else : 
      padded_slice = npArray[pos: pos + lenSegment] 
      padded_slice = np.concatenate((padded_slice, np.zeros(lastIndex - len(a)))) 

    return padded_slice 

使用

a = np.asarray([2,2,3,1,7,6,5,4]) 

for i in range(len(a)): 
    b = getPaddedSlice(a, i, lenSegment, True) 
    print b 

顯示

[0 2 2 3] 
[2 2 3 1] 
[2 3 1 7] 
[3 1 7 6] 
[1 7 6 5] 
[7 6 5 4] 
[6 5 4 0] 
[5 4 0 0]