使用python-opencv的一个坑

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()也有相同问题

如有不对的地方,欢迎指正

猜你喜欢

转载自blog.csdn.net/liuxiaoheng1992/article/details/83629021