2016-10-24 67 views
2

我有一個較大的圖像A和一個較小的圖像B,都表示爲2-D numpy陣列。我想使用A作爲畫布,並在其上面編寫B的譯文,並以六角形排列。我無法理解的部分是如何處理圖像,以便圖像在垂直和水平方向上都包裹 - 基本上我想要的是將(填充的,必要時)子圖像定期鑲嵌到圓環上。分配給一個numpy陣列的包裝切片

我見過的numpy.takenumpy.roll討論在 wrapping around slices in Python/numpy和展示我如何訪問和返回副本陣列的包裹片的,但我想分配給該-即對於任意整數rowOffsetcolumnOffset我想做的相當於:

A = numpy.zeros((5,11), int) 
    B = numpy.array([[1,2,3,4,5,6,7]]) * numpy.array([[10,100,1000]]).T 
    # OK, we wouldn't be able to fit more than one or two copies of B into A, but they demonstrate the wrapped placement problem 

    wrappedRowIndices = (numpy.arange(B.shape[0]) + rowOffset) % A.shape[0] 
    wrappedColumnIndices = (numpy.arange(B.shape[1]) + columnOffset) % A.shape[1] 
    A[ wrappedRowIndices, : ][ :, wrappedColumnIndices ] = B 

我從評論on the question, 和片刻的思考方式看numpy陣列被表示,以這種需求的方式,包裝的切片無法以view的形式返回。

是否有(Y)以這種方式指定給數組的包裝切片的方法,或(X)用於執行我想要實現的鑲嵌類型的現有實用程序?

+0

怎麼會是六邊形的?不是'B'一個正方形嗎? – maxymoo

+0

我的意思是'B'副本的中心將在包裝好的六邊形的角落分佈在'A'上,而不是'B'本身是六角形的。我猜最容易處理的變體是'B'的尺寸小於六邊形的尺寸,因此副本之間沒有重疊。 – jez

+0

我想如果你必須使用'strides'中的視圖,你可以將cols和rows添加到'A'中,然後索引它,當然內存允許。創建填充版本:'A1 = np.column_stack((A,A [:,:.shape [1] -1]))','A2 = np.row_stack((A1,A1 [:B.shape [0] -1]))'。 – Divakar

回答

1

您當前的代碼分解爲__getitem____setitem__。如您所注意的,__getitem__不會返回視圖,因此__setitem__只是最終修改副本。

你需要做的全部事情在一個__setitem__(即一組括號):

A[wrappedRowIndices[:,np.newaxis], wrappedColumnIndices] = B 

由於廣播,這相當於:

A[wrappedRowIndices[:,np.newaxis], wrappedColumnIndices[np.newaxis,:]] = B 

當超過索引一個陣列,其規則是:

# ... here is NOT the python Ellipsis! 
y = x[a, b, c, ...] 
y[i, j, ..] = x[a[i,j,...], b[i,j,...], ...] 

實際上,有這個一個內建,np.ix_()

A[np.ix_(wrappedRowIndices, wrappedColumnIndices)] = B 

推廣到ND,您可以:

def place_wrapped(canvas, brush, position): 
    assert canvas.ndim == brush.ndim == len(position) 
    ind = np.ix_(*(
     (np.arange(b_dim) + shift) % c_dim 
     for b_dim, c_dim, shift in zip(brush.shape, canvas.shape, position) 
    )) 
    canvas[ind] = brush 

+0

這個答案告訴我一件有價值的事情,即你**可以**只用一對方括號把數組的矩形塊 - 但是你建議的分配失敗與'ValueError:數組不能廣播以正確的形狀' – jez

+0

如果元素的數量是正確的,你可以用一個或者兩個平坦的東西來修復。 – hpaulj

+0

我原以爲你所說的規則要求'[np.newaxis,:]'而不是'[:,np.newaxis]'爲第二個索引數組。但是這兩種變體都可以工作(用於*獲取塊的副本),並且兩者都失敗,並且具有相同的「ValueError」(用於設置塊內容)。給RHS添加一個'.flat'沒有什麼區別。給LHS添加一個'.flat'可以消除這個異常,但是現在看來我們正在重新編寫'__getitem__'副本:'A'保持不變。 – jez

3

np.put是一維相當於np.take

In [1270]: A=np.arange(10) 
In [1271]: np.take(A,[8,9,10,11],mode='wrapped') 
Out[1271]: array([8, 9, 0, 1]) 
In [1272]: np.put(A,[8,9,10,11],[10,11,12,13],mode='wrapped') 
In [1273]: A 
Out[1273]: array([12, 13, 2, 3, 4, 5, 6, 7, 10, 11]) 
In [1274]: np.take(A,[8,9,10,11],mode='wrapped') 
Out[1274]: array([10, 11, 12, 13]) 

其文檔建議np.placenp.putmask(和np.copyto)。我沒有用過那麼多,但是可能會構建一個掩碼,並重新排列B這個副本。

=================

下面是與place一個實驗:

In [1313]: A=np.arange(24).reshape(4,6) 
In [1314]: mask=np.zeros(A.shape,bool) 
In [1315]: mask[:3,:4]=True 
In [1316]: B=-np.arange(12).reshape(3,4) 

所以我有mask大小相同A,用'洞'的大小爲B

我可以以wrapped方式在A滾動兩者maskB,和place的值。

In [1317]: np.place(A, np.roll(mask,-2,0), np.roll(B,1,0).flat) 
In [1318]: A 
Out[1318]: 
array([[ -8, -9, -10, -11, 4, 5], 
     [ 6, 7, 8, 9, 10, 11], 
     [ 0, -1, -2, -3, 16, 17], 
     [ -4, -5, -6, -7, 22, 23]]) 

而且與2D卷

In [1332]: m=np.roll(np.roll(mask,-2,0),-1,1) 
In [1333]: m 
Out[1333]: 
array([[ True, True, True, False, False, True], 
     [False, False, False, False, False, False], 
     [ True, True, True, False, False, True], 
     [ True, True, True, False, False, True]], dtype=bool) 
In [1334]: b=np.roll(np.roll(B,1,0),-1,1) 
In [1335]: b 
Out[1335]: 
array([[ -9, -10, -11, -8], 
     [ -1, -2, -3, 0], 
     [ -5, -6, -7, -4]]) 
In [1336]: A=np.zeros((4,6),int) 
In [1337]: np.place(A, m, b.flat) 
In [1338]: A 
Out[1338]: 
array([[ -9, -10, -11, 0, 0, -8], 
     [ 0, 0, 0, 0, 0, 0], 
     [ -1, -2, -3, 0, 0, 0], 
     [ -5, -6, -7, 0, 0, -4]]) 
+0

不是'np.place(arr,mask,vals)'只是'arr [mask] = vals'? – Eric

+0

我們不得不看看編譯後的_insert函數的作用。 'A [m] = b.flat'也是一樣的。 – hpaulj

+0

謝謝 - 這使我走上了一條通用的解決方案(請參閱我發佈的答案)。 – jez

1

這裏有一個工作的基礎上hpaulj的回答解決我的問題Ÿ一個函數。然而,這可能不是解決X的最有效方式,因爲在numpy.roll中完成了所有繁重的工作。

import numpy 

def place_wrapped(canvas, brush, position): 
    mask = numpy.zeros(canvas.shape, bool) 
    mask[[slice(extent) for extent in brush.shape]] = True 
    for axis, shift in enumerate(position): 
     canvas_extent = canvas.shape[axis] 
     brush_extent = brush.shape[axis] 
     shift %= canvas_extent 
     if shift: 
      mask = numpy.roll(mask, shift, axis=axis) 
      nwrapped = shift + brush_extent - canvas_extent 
      if nwrapped > 0: brush = numpy.roll(brush, nwrapped, axis=axis) 
    numpy.place(canvas, mask, brush.flat) 


A = numpy.zeros((5,11), int) 
B = numpy.array([[1,2,3,4,5,6,7]]) * numpy.array([[10,100,1000]]).T 
print(B) 

rowOffset = 3 
columnOffset = 7 
place_wrapped(A, B, (rowOffset, columnOffset)) 
print(A) 

Eric的矯正方法也工作過,和我想象它必須是更有效,因爲它沒有做任何的數據副本:

def place_wrapped2(canvas, brush, position): 
    ind = [ 
     ((numpy.arange(brush.shape[axis]) + shift) % canvas.shape[axis]).reshape([ 
      extent if i == axis else 1 
      for i, extent in enumerate(brush.shape) 
     ]) 
     for axis, shift in enumerate(position) 
    ] 
    canvas[ind] = brush 

A *= 0 # reset 
place_wrapped2(A, B, (rowOffset, columnOffset)) 
print(A) 
+0

看到我更正的答案 - 不幸的是,您的任何嘗試都沒有解決問題 – Eric