作者:
clang (llvm)
2018-05-11 12:59:51小的就個人的理解稍做解釋
錯了還請板上大大指正
※ 引述《znmkhxrw (QQ)》之銘言:
: 想請問一下,為什麼以下程式碼會錯誤:
: import cv2
: img_rgb = cv2.imread("image.jpg")[:,:,::-1]
: cv2.circle(img_rgb, (616,44),4,[255, 0, 0], thickness=-1)
: TypeError: Layout of the output array img is incompatible with cv::Mat
: (step[ndims-1] != elemsize or step[1] != elemsize*nchannels)
: 但是!我只要加入.copy()就對了 即 ....[:,:,::-1].copy()
: 來龍去脈如下
: ==========================================================
: 首先舉個例子釐清一件事情:
: a = [1,2]
: b = a[::-1]
: 則 b 就是 [2,1],而且記憶體位置不同! id(a) != id(b)
: 邏輯就是把 b 指向某個不同於a的記憶體位置,值為a = [1,2][::-1]
不管是 list 還是 numpy,值本身不是直接存在 array 中,這個 array/list 本身是個指標陣列,會指向值真正在的地方
從你舉的範例可以對照一下
In []: a = [1, 2]
In []: b = a[::-1]
In []: id(a) == id(b)
Out[]: False
b 確實會相異於 a,但它只是建立了新的指標陣列,值沒有被複製
In []: id(a[0]) == id(b[1])
Out[]: True
同樣的行為適用在numpy上
In []: a = numpy.zeros((3, 5))
...: b = a[:, ::-1]
...: a[0, 0] = 1
...: print(b)
...:
[[0. 0. 0. 0. 1.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
明明改的是 a 的值,但 b 也被修改了
這邊參考 numpy doc 的 indexing 說明
"All arrays generated by basic slicing are always views of the original array."
- https://docs.scipy.org/doc/numpy-1.13.0/reference/arrays.indexing.html
這個函式庫預設的規則就是回傳 view 而不是拷貝,意即只是換換"看這個array的方式"而已
而 numpy 存陣列的方式是將資料存在連續的一維陣列中
然後用stride去紀錄當我想取某個值的時候怎麼去跳到正確的位子
以上圖的 a/b 來說
In []: a.strides
Out[]: (40, 8)
In []: b.strides
Out[]: (40, -8)
你覺得值被反轉了,但他只轉了讀data的順序
直到你下了 .copy() 它才真正的複製了值,並且將值排好
In []: b = a[::-1].copy()
In []: b.strides
Out[]: (40, 8)
而為什麼 cv2 不給吃呢
上了一課,謝謝!然後關於你最後一段說.copy()很怪 是?或者是說 我如果以後要避免到這種錯誤 要有什麼好習慣?因為我本意只是讓ndarray的RGB跟BGR互調 才用[:,:,::-1]然後就出現這個錯誤 第一次遇到@@ 以後該怎麼注意另外問個問題 [:,:,::-1]是創立新的指標陣列代表說 old_index , new_index 是兩個不同指標(變數?)然後指向同一個值?我觀念還在淺淺的 "a = b" 代表把a指向b值QQ