TypeError: Layout of the output array img is incompatible with cv::Mat (step[ndims-1] != elemsize or step[1] != elemsize*nchannels)
错误如上,代码如下,stackoverflow我也看到几篇,说的很随意,没有解决我的问题,自己研究了很久,或许有人代码不太一样的也有这个错误,但是可能使用了别的opencv函数触发了这个错误,我下面详细解释一下
#-*- coding:utf-8 -*-
import cv2
import numpy as np
if __name__=="__main__":
#读入图片并将通道数翻转
img = cv2.imread('./test.png')[:,:,::-1]
#拷贝img至img_copy
img_copy = img.copy()
#输入要画的框
box = np.array([0, 12, 13, 18, 2, 20, 3, 40])
#画框
cv2.polylines(img_copy[:, :, ::-1], box.astype(np.int32).reshape(-1,1,2),
isClosed=True, color=(255,255,0), thickness=2)
上述代码很简单,也有相应的解释,但是这样使用polylines函数会报错 (TypeError: Layout of the output array img is incompatible with cv::Mat (step[ndims-1] != elemsize or step[1] != elemsizenchannels)) ,或许有人和我一样怀疑是拷贝函数哪出问题的了导致数据通道数发生改变,或者导致数据类型发现变化,测试如下:
#-*- coding:utf-8 -*-
import cv2
import numpy as np
if __name__=="__main__":
img = cv2.imread('./test.png')[:,:,::-1]
img_copy = img.copy()
print("img.dtype == img_copy.dtype:{}".format(img.dtype == img_copy.dtype))
print("np.all(np.equal(img,img_copy)):{}".format(np.all(np.equal(img,img_copy))))
上面代码输出
img.dtype == img_copy.dtype:True
np.all(np.equal(img,img_copy)):True
说明数据完全一样,数据类型也一样,那问题出在哪了?
这个问题出在几个点,解释之前要明确几个点:
1.python中切片操作,如[:,:,::-1],是浅拷贝(会创建新的对象,但是数据完全来自于切片前的对象)
2.cv2.polylines()函数的输入也是输出
3.在numpy里面,数据有个flags的属性查看
看如下代码:
#-*- coding:utf-8 -*-
import cv2
import numpy as np
if __name__=="__main__":
#读入图片并将通道数翻转
img = cv2.imread('./test.png')[:,:,::-1]
#拷贝img至im
img_copy = img.copy()
print("img.flags:\n{}".format(img.flags))
print("img_copy.flags:\n{}".format(img_copy.flags))
上述代码输出:
img.flags:
C_CONTIGUOUS : False
F_CONTIGUOUS : False
OWNDATA : False
WRITEABLE : True
ALIGNED : True
WRITEBACKIFCOPY : False
UPDATEIFCOPY : False
img_copy.flags:
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
WRITEABLE : True
ALIGNED : True
WRITEBACKIFCOPY : False
UPDATEIFCOPY : False
关于numpy中flags的说明如下(来自官网):
属性 | 描述 |
---|---|
C_CONTIGUOUS | 数据是在一个单一的C风格的连续段中 |
F_CONTIGUOUS | 数据是在一个单一的Fortran风格的连续段中 |
OWNDATA | 数组拥有它所使用的内存或从另一个对象中借用它 |
WRITEABLE | 数据区域可以被写入,将该值设置为 False,则数据为只读 |
ALIGNED | 数据和所有元素都适当地对齐到硬件上 |
WRITEBACKIFCOPY | 这个数组是另一数组的副本,当C-API函数PyArray_ResolveWritebackIfCopy调用时,源数组会由这个数组中的元素更新 |
UPDATEIFCOPY | 这个数组是其它数组的一个副本,当这个数组被释放时,原数组的内容将被更新 |
上面输出可以看出img在内存中是c风格不连续的,且是个浅拷贝,而img_copy是c风格连续的,且是深拷贝(自己拥有内存,数据自己管理)。通过这个可以知道,两个内存虽然数据是一样的,但是存储方式是不一样的,当调用方式如下时
cv2.polylines(img_copy[:, :, ::-1], box.astype(np.int32).reshape(-1,1,2),
isClosed=True, color=(255,255,0), thickness=2)
#或者是下面这种调用方式
#img_copy_t = img_copy[:, :, ::-1]
#cv2.polylines(img_copy_t, box.astype(np.int32).reshape(-1,1,2),
#isClosed=True, color=(255,255,0), thickness=2)
调用时都会报错,因为使用[:,:,::-1]后传给函数的是个浅拷贝c风格不连续的内存数据,但是输出的内存是连续的由image_copy管理的,导致输入输出不一致报错,下面几种方式都不会导致报错,因为保证的输入输出一致性
1.
#-*- coding:utf-8 -*-
import cv2
import numpy as np
if __name__=="__main__":
#读入图片并将通道数翻转
img = cv2.imread('./test.png')
#拷贝img至img_copy
img_copy = img.copy()
#输入要画的框
box = np.array([0, 12, 13, 18, 2, 20, 3, 40])
#画框
cv2.polylines(img_copy, box.astype(np.int32).reshape(-1,1,2),
isClosed=True, color=(255,255,0), thickness=2)
#-*- coding:utf-8 -*-
import cv2
import numpy as np
if __name__=="__main__":
#读入图片并将通道数翻转
img = cv2.imread('./test.png')[:,:,::-1]
#拷贝img至img_copy
img_copy = img.copy()
#输入要画的框
box = np.array([0, 12, 13, 18, 2, 20, 3, 40])
#画框
cv2.polylines(img[:,:,::-1], box.astype(np.int32).reshape(-1,1,2),
isClosed=True, color=(255,255,0), thickness=2)
#-*- coding:utf-8 -*-
import cv2
import numpy as np
if __name__=="__main__":
#读入图片并将通道数翻转
img = cv2.imread('./test.png')
#拷贝img至img_copy
img_copy = img.copy()
#输入要画的框
box = np.array([0, 12, 13, 18, 2, 20, 3, 40])
#画框
img_copy_t = img_copy[:,:,::-1]
cv2.polylines(img_copy_t[:,:,::-1], box.astype(np.int32).reshape(-1,1,2),
isClosed=True, color=(255,255,0), thickness=2)
猜测opencv输入也是输出的函数都会有类似问题,尝试cv2.lines()也有相同问题
如有不对的地方,欢迎指正