当我转换它们时,我一直遇到一些使用cv显示numpy矩阵图像的问题。
请考虑以下代码。
import cv2, numpy as np
...
ones = np.ones((100,100))
onesT = np.copy(ones.T)
onesCT = np.copy(ones.T, order='C')
cv2.circle(ones, (50,50), 3, (0), thickness=-1)
cv2.circle(onesCT, (50,50), 3, (0), thickness=-1)
cv2.circle(onesT, (50,50), 3, (0), thickness=-1)
前两个“cv2.circle”调用有效,但第三个调用给出了以下错误:
102 cv2.circle(ones, (50,50), 3, (0), thickness=-1)
103 cv2.circle(onesCT, (50,50), 3, (0), thickness=-1)
--> 104 cv2.circle(onesT, (50,50), 3, (0), thickness=-1)
TypeError: Layout of the output array img is incompatible with cv::Mat (step[ndims-1] != elemsize or step[1] != elemsize*nchannels)
为什么在转置矩阵时会发生这种情况,但如果我更改内存复制的顺序则不会发生这种情况?对我来说,所有这些矩阵都是完全相同的。
答案 0 :(得分:1)
在一个抽象层次上,所有这些矩阵都是相同的。但是在较低级别,其中两个使用C约定(row-major order)存储数据,而另一个(onesT
)使用Fortran约定(列主要顺序)。显然cv2.circle
需要一个C连续的数组。
您可以使用flags
属性检查订单。请注意F_CONTIGUOUS
的{{1}}标志为True:
onesT
检查订单信息的简明方法是np.isfortran
:
In [24]: ones.flags
Out[24]:
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
WRITEABLE : True
ALIGNED : True
UPDATEIFCOPY : False
In [25]: onesT.flags
Out[25]:
C_CONTIGUOUS : False
F_CONTIGUOUS : True
OWNDATA : True
WRITEABLE : True
ALIGNED : True
UPDATEIFCOPY : False
In [26]: onesCT.flags
Out[26]:
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
WRITEABLE : True
ALIGNED : True
UPDATEIFCOPY : False
In [27]: np.isfortran(onesT)
Out[27]: True
使用Fortran命令,因为2-d数组的转置是通过简单地交换每个维度的“strides”而实现的,而不是实际复制内存中的值数组。
例如,
onesT
(这使转置操作非常有效。)
您复制了转置数组以创建In [28]: x = np.array([[1, 2, 3], [4, 5, 6]])
In [29]: np.isfortran(x)
Out[29]: False
In [30]: np.isfortran(x.T)
Out[30]: True
,但如果您查看np.copy
的文档字符串,您会看到onesT
参数的默认值为{{1 },这意味着“尽可能地匹配a的布局。”特别是,在这种情况下,它保留了Fortran订单。另一方面,order
是一个C连续数组,因为您明确告诉'K'
使用C约定对副本进行排序。