2012-04-02 85 views
1

我希望能夠以某種方式對numpy數組重新排序以便高效處理tile。有效地將Numpy數組重新排列/重新排列爲正確排序的Tile(圖像)

我得到了什麼:

>>> A = np.array([[1,2],[3,4]]).repeat(2,0).repeat(2,1) 
>>> A # image like array 
array([[[1, 1, 2, 2], 
     [1, 1, 2, 2]], 

     [[3, 3, 4, 4], 
     [3, 3, 4, 4]]]) 

>>> A.reshape(2,2,4) 
array([[[1, 1, 2, 2], 
     [1, 1, 2, 2]], 

     [[3, 3, 4, 4], 
     [3, 3, 4, 4]]]) 

我想要什麼:如何獲得X:

>>> X 
array([[[1, 1, 1, 1], 
     [2, 2, 2, 2]], 

     [[3, 3, 3, 3], 
     [4, 4, 4, 4]]]) 

這是可能沒有一個緩慢的蟒蛇循環?

獎勵:轉換從X到後面有一個

巴戈指出了一個類似的問題,我已經錯過了:Creating a 4D view on 2D array to divide it into cells of fixed size


爲什麼所有的麻煩呢?爲了能夠做這樣的事情:

>>> X[X.sum(2)>12] -= 1 
>>> X 
array([[[1, 1, 1, 1], 
     [2, 2, 2, 2]], 

     [[3, 3, 3, 3], 
     [3, 3, 3, 3]]]) 

編輯:解:

# MIT - License 

import numpy as np 

def tile_reorder(A, t): 
    """reshape and transpose quadratic array for easy access to quadratic tiles of size t""" 
    l = A.shape[0]/t 
    X = A.reshape((l, t, l, t)) 
    X = X.transpose([0, 2, 1, 3]) 
    return X 

def tile_reorder_reverse(X): 
    l = X.shape[0] * X.shape[2] 
    A = X.transpose([0, 2, 1, 3]) 
    A = A.reshape((l, l)) 
    return A 

if __name__ == "__main__": 
    A = np.array([[1,2,3],[3,4,5],[6,7,8]]).repeat(4,0).repeat(4,1) 

    print "A:\n", A, "\n\n" 

    print "A_tiled:\n", tile_reorder(A,4), "\n\n" 

    print "A_tiled_reversed:\n", tile_reorder_reverse(tile_reorder(A,4)), "\n\n" 

    X = tile_reorder(A,4) 
    X[X.sum((2)).sum(2)>63,:,:] += 10 
    B = tile_reorder_reverse(X) 

    print "B_processed:\n", B, "\n\n" 
+2

目前尚不清楚你的問題是什麼。您列出的代碼中哪一步不適合您。 NumPy確實有邏輯類型索引,有些像'X [X.sum(2)> 12]'應該有效。問題是你需要弄清楚你想要索引的數組的哪個維度。看起來你想說'X [:,:,X.sum(2)> 12] - = 1',因爲你想要混淆的索引只有那些有第三個索引,總和超過12 ,第一和第二個索引可以是任何東西。 – ely 2012-04-02 16:12:10

+1

如果我明白你想要做什麼,轉換回是不可能的。您正在丟失信息,您正在將原始設置映射到較小的子集。 – Hooked 2012-04-02 16:12:44

+0

希望我做得更清楚一點。索引不是造成皮塔的原因。 – Gonzo 2012-04-02 16:27:16

回答

3

你想要的東西,如:

>>> X = A.reshape(2,2,2,2) 
>>> X = X.transpose([0,2,1,3]) 
>>> X = X.reshape((2,2,-1)) 
>>> X 
array([[[1, 1, 1, 1], 
     [2, 2, 2, 2]], 

     [[3, 3, 3, 3], 
     [4, 4, 4, 4]]]) 
>>> B = X.reshape((2,2,2,2)) 
>>> B = B.transpose([0,2,1,3]) 
>>> B = B.reshape((2,2,-1)) 
>>> B 
array([[[1, 1, 2, 2], 
     [1, 1, 2, 2]], 

     [[3, 3, 4, 4], 
     [3, 3, 4, 4]]]) 
+0

這有一個問題,它不會推廣到瓷磚尺寸應該仍然是2x2的'MxN'瓷磚,但瓷磚的較大圖案大於2x2。能夠看到這個簡潔的代碼被修改以處理任意的'KxP'代碼,每個代碼都是'MxN',真是太棒了。 – ely 2012-04-02 17:24:18

+0

沒有理由不推廣,請參閱http://stackoverflow.com/questions/9006232/creating-a-4d-view-on-2d-array-to-divide-it-into-cells-of-固定大小 – 2012-04-02 18:34:57

+0

嘗試在我附加到我的答案結尾的示例上運行您的代碼。你的代碼給出了一個錯誤;我嘗試過這個。如果它通過改變呼叫中的數字來改變形狀和移位,那麼我上面的評論仍然適用 - 我認爲你的方法只有在演示如何將tile參數提供給重塑和轉置代碼並獲取它時纔是有價值的工作在一般形狀的瓷磚陣列上,瓷磚的形狀也是一般的。 – ely 2012-04-02 18:45:01

1

我覺得你只是看你的陣列的錯片。以下應該做你想要的。

>>> X[(X.sum(2)>12),:] -= 1 
>>> X 
array([[[1, 1, 1, 1], 
     [2, 2, 2, 2]], 

     [[3, 3, 3, 3], 
     [3, 3, 3, 3]]]) 

回到原來的順序有點複雜。我相信你可以將下面的代碼修改成一個名爲get_back()的函數或者其他東西,所以你不必一直重複使用它。

import numpy as np 
X = np.asarray([[[1,1,1,1],[2,2,2,2]],[[3,3,3,3],[4,4,4,4]]]) 
print X 

# Make the change to the array 
# Note that I make the change to +=1 so we can indeed see that 
# the reshaping worked by looking for the 5's. 
X[(X.sum(2)>12),:] += 1 

(M,N,P) = X.shape;  # Number of tiles is MxN 
orig_i = 2; orig_j = 2; # (Original rows/cols in a tile). 
orig = (orig_i, orig_j) # Define as a tuple for convenience. 
hstacks = [] 
for ii in range(M): 
    hstacks.append(X[ii,0,:].reshape(orig)) 
    for jj in range(1,N): 
     hstacks[-1] = np.hstack((hstacks[-1], X[ii,jj,:].reshape(orig))) 

orig_array = hstacks[0] 
for kk in range(1,len(hstacks)): 
    orig_array = np.vstack((orig_array, hstacks[kk])) 

# Print to confirm that it worked. 
print orig_array 

我得到如下:

>>> [[[1 1 1 1] 
     [2 2 2 2]] 

    [[3 3 3 3] 
     [4 4 4 4]]] 

>>> [[1 1 2 2] 
    [1 1 2 2] 
    [3 3 5 5] 
    [3 3 5 5]] 

,並測試,我與瓷磚的大格局嘗試它,以及它給出正確的結果。請注意,我使用函數get_back()來封裝上面的代碼,並且我只是在平鋪尺寸參數中對函數進行了硬編碼。真的,他們應該是輸入參數。

>>> X = np.asarray([[[1,1,1,1],[2,2,2,2],[3,3,3,3]], 
        [[4,4,4,4],[5,5,5,5],[6,6,6,6]]]) 
>>> X 
array([[[1, 1, 1, 1], 
     [2, 2, 2, 2], 
     [3, 3, 3, 3]], 

     [[4, 4, 4, 4], 
     [5, 5, 5, 5], 
     [6, 6, 6, 6]]]) 

>>> get_back(X) 
array([[1 1 2 2 3 3] 
     [1 1 2 2 3 3] 
     [4 4 5 5 6 6] 
     [4 4 5 5 6 6]]) 
+0

這種方式也可以,但是bago的解決方案雖然尚未推廣,但更優雅應該更快。 – Gonzo 2012-04-03 08:05:40