作者clang (llvm)
看板Python
标题Re: [问题] cv2.circle与记忆体位置
时间Fri May 11 12:59:51 2018
小的就个人的理解稍做解释
错了还请板上大大指正
※ 引述《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 不给吃呢 ---
我自己是没去注意过他怎麽接上 numpy 的拉
不过去对照一下 circle 这个函式的实做
#define ICV_PUT_POINT( ptr, x ) \
memcpy( ptr + (x)*pix_size, color, pix_size );
它毕竟是整个 pixel 进行拷贝,所以当值不是乾乾净净的排列好的时候他不知道从哪里抓值吧
: 因此跟 b = a[::-1].copy() 应该是一样的
: 再来,回到原始问题
: img_rgb = cv2.imread("image.jpg")[:,:,::-1]
: ^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
: 将这变数 值为cv2.imread("image.jpg")[:,:,::-1]
: 指向 只是cv2.imread载入进来是bgr顺序,所以用[:,:,::-1]变成rgb顺序而已
: cv2.circle(img_rgb, (616,44),4,[255, 0, 0], thickness=-1)
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
: 在img_rgb上某个位置加入某个大小的圆点
: 但就是错的!
: 不过在[:,:,::-1]後面加个.copy()就对了
: ---------------------------------------------------------
: debug三个多小时终於找到问题在这....
: 不过完全违背我对 iterator[index] 的认知
: 照理说 iterator[index] 就是造一份新的记忆体位置
: 但是在cv2.circle到底发生什麽事!?
: 很想知道原因QQ 谢谢解惑!
是说你觉得要用 .copy() 很怪,是可以用
cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
拉,它能转的种类也是颇多的
---
我为啥突然打了这堆东西阿...
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 140.113.73.133
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/Python/M.1526014799.A.5D1.html
1F:推 znmkhxrw: 上了一课,谢谢!然後关於你最後一段说.copy()很怪 是? 05/11 13:35
这边单纯指个人 coding 习惯
像我自己会尽量减少 copy() 的发生
不过那就要看当时要做的事情是否有办法惹
2F:→ znmkhxrw: 或者是说 我如果以後要避免到这种错误 要有什麽好习惯? 05/11 13:35
3F:→ znmkhxrw: 因为我本意只是让ndarray的RGB跟BGR互调 才用[:,:,::-1] 05/11 13:37
4F:→ znmkhxrw: 然後就出现这个错误 第一次遇到@@ 以後该怎麽注意 05/11 13:37
习惯的话,就只能说多读 doc 了
我们现在在用 python 很多时候只是以它当界面,而实际操作的工作还是由外部的函式完成
要避免这些错误的发生就是认真去搞清楚每个指令实际上对应什麽操作
下面这个问题的话...抱歉我不是很理解
5F:推 znmkhxrw: 另外问个问题 [:,:,::-1]是创立新的指标阵列 05/11 13:39
6F:→ znmkhxrw: 代表说 old_index , new_index 是两个不同指标(变数?) 05/11 13:40
7F:→ znmkhxrw: 然後指向同一个值? 05/11 13:40
8F:→ znmkhxrw: 我观念还在浅浅的 "a = b" 代表把a指向b值QQ 05/11 13:41
9F:推 laputaflutin: 上面的说法也有点问题,a与b都是name "a = b"的意思 05/11 13:54
※ 编辑: clang (140.113.73.133), 05/11/2018 14:03:13
10F:→ laputaflutin: 是指将"b"这个name对应的object同样给"a"name对应 05/11 13:57
11F:推 laputaflutin: 另外要注意copy()也只是复制name引用(reference) 05/11 14:00
12F:→ laputaflutin: 真正要达成语意上的copy要用 copy.deepcopy() 05/11 14:02
13F:推 CaptainH: 不要乱教,那也是看实作. numpy的copy就是真的复制 05/11 22:01