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

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

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值