簡體   English   中英

numpy 是否有可能在不更改 memory 順序和迭代器的情況下交換矩陣的 x,y?

[英]Is there possibilty in numpy to swap x,y of matrix without changing memory order and iterators?

我正在嘗試從fortranc++ 的世界切換到 numpy 主要是我正在處理巨大的圖像,其中坐標方向是x:從左到右,y:自上而下,像素存儲在行中,常見於圖像格式。

Numpy 說它還按行存儲矩陣。 就好的而言,它與 fortran/c++ 保存圖像相同。 但是,請參閱以下示例,從黑色到白色的灰色行。 讓我們創建圖像 3x3,其中第一行是 123 等

黑白圖像符合預期,帶有 matplotlib imshow(mat)

mat = np.array([1,2,3,4,5,6,7,8,9], 'i1').reshape(3,3)

接下來我使用以下代碼獲取有關矩陣的信息。 例行打印: position x=1, y=0 , position 中的值在 memory 中查看是否復制了數組、步幅和迭代器。

def pr(a):
    x=1; y=0;
    print(a[x,y])
    print(a.ctypes.data, a.strides, a.ravel(order='K'), [x for x in a.flat], a.flatten(order='K'))
    print(a.flags)

對於C 順序的矩陣mat ,我有

4
94598176807408 (3, 1) [1 2 3 4 5 6 7 8 9] [1, 2, 3, 4, 5, 6, 7, 8, 9] [1 2 3 4 5 6 7 8 9]
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False

所以很明顯x,y被交換了,因為對於x=1y=0像素值是 2 而不是 4,所以我已更改為 F 順序。

# mat = mat.ravel(order='K').reshape(3,3, order='F')
mat.strides = (1,3)
# mat = np.swapaxes(mat, 0, 1)

以上是獲得具有相同結果的F 階的三種可能性。

2
94598176807408 (1, 3) [1 2 3 4 5 6 7 8 9] [1, 4, 7, 2, 5, 8, 3, 6, 9] [1 2 3 4 5 6 7 8 9]
  C_CONTIGUOUS : False
  F_CONTIGUOUS : True

現在,當使用具有相同 memory 布局的 F 訂單時,圖像被交換

如您所見, x=1 y=2的值 2 是正確的,使用mat[x,y]是正確的,memory 順序是正確的,但迭代器是錯誤的1 4 7... 結果是保存或顯示圖像不好,全部被交換。 不在 memory 訂單中的迭代器有很大的性能損失。

問題是:如何在沒有圖像副本的情況下設置 numpy 矩陣,交換 x,y 並且所有其他屬性都與 C 順序相同。 我嘗試設置 C_CONTIGUOUS=True,但這是不可能的。?

一種方法是使用 C 順序,但在所有此類矩陣上都必須使用反向索引 [y,x],問題是它非常混亂,所有向量都是正常的(x,y,z)並且一些對象使用交換索引順序.? 軸的正確命名順序有助於圖像的進一步空間操作。

也許有可能擴展numpy ,使用其他索引方法,如mat.swap2[x,y]只返回mat[y,x]或例如。 mat[*reversed((x,y))] 但是有更好的解決方案嗎?

接下來是fortranc++中的兩個示例,例如。 犰狳矩陣庫(因為 c/c++ 似乎沒有定義自己的通用矩陣對象)。 兩個示例都使用 F 順序,索引正確mat[x,y] ,memory 布局與輸入圖像的二進制布局相同,逐行,迭代器在 memory 布局中。 在我看來,F 順序中的 numpy 不支持相同的行為似乎很奇怪。 或者只是我不明白 numpy 的哲學。

fortran中的示例,保存和迭代此類矩陣按 memory 順序(此處未顯示)。

...
    integer(1) :: mat(0:2,0:2)      ! matrix 3x3 indexing 0,1,2
    data mat /1,2,3,4,5,6,7,8,9/    ! memory order
    print*, mat(1,0)                ! value for x=1 y=0 is 2 ok
...

C++中的示例與犰狳,保存並再次迭代是按 memory 順序(此處未顯示)。

#define ARMA_U8_TYPE   uint8_t
#define ARMA_S8_TYPE    int8_t        // define support for int8 instead of char
#include <armadillo>
...
    using namespace arma;
    int8_t amem[] = {1,2,3,4,5,6,7,8,9};        // memory order
    Mat<int8_t> mat(amem, 3,3,  false,true);    // matrix 3x3
    cout << (int)mat(1,0) << "\n";              // value for x=1 y=0 is 2 ok
...

首先 numpy 對列主模式有混淆的術語, F_CONTIGUOUS在 memory 中對於 2D 等從不連續。 就像按設計查看一樣, memory 布局始終為C 出於性能原因和您指定的軸分配,使用列主順序更自然,但在 numpy 中並不容易。

此外,內置/擴展不允許僅使用setattr()直接擴展 numpy 類,但您可以派生自己的。

為了簡單起見, numpy 始終使用默認的C順序(行主要順序)並將軸交換為mat[z,y,x] 在我看來,這似乎是最不容易混淆的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM