TypeError: Layout of the output array image is incompatible 问题解决

本周在使用findContours的过程中遇到了以下问题:

TypeError: Layout of the output array image is incompatible with cv::Mat (step[ndims-1] != elemsize or step[1] != elemsize*nchannels)

感谢这篇文章:https://www.jianshu.com/p/cc3f4baf35bb,引导我往正确的方向进行思考。

先讲结论造成以上问题的原因是:输入与输出的numpy格式不一致

我一开始的第一反应是为什么findContours函数会有“output array image”,我只关注contours。这其实是我在写代码中一个盲区,对于findContours函数我一般都是这么写:

_, contours, _ = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

 

对于第一个与第三个返回值现阶段直接就跳过,这其实恰恰是产生问题的关键原因,完整的findContours函数输出应该如下:

binary, contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

binary的输出与image完全一样,所以在使用的时候一般就忽略了这个参数,顺便提一句在findContours函数的注释中有这么一句:

@note Since opencv 3.2 source image is not modified by this function.

opencv3.2之后就不会再修改image了,但是findContours函数为什么要改原图?挺让人费解的。到了opencv4.2之后这个返回值干脆就被取消了,又造成了一系列的软件兼容问题。

返回到这个错误上来,上面说了这么多就是想说findContours函数其实是有一个image array输出的。而这个array的要求非常严格。

我在处理image是按照channel维度对它进行遍历,然后在每个channel上执行findContours函数,为了确保后续操作不会影响原图,我首先对每个channel执行了复制操作,这又是产生问题的另一个关键因素。当时是执行了copy.deepcopy()操作,这在我之前的使用过程中都是没有问题的,包括我今天做实验依然没有问题,但是那天程序却一直在报错。而后改为了numpy的copy函数才通过。

我首先把可以用于numpy的拷贝方法与其对应的flags输出列在下面:

 

第一列表示原图的flags属性,one_channel表示使用遍历方式获得的一个channel的flags属性,cv2.split表示使用split函数获得的每一个channel的flags属性,numpy.copy()表示首先使用遍历方式获得一个channel,而后调用copy函数得到的一个channel的flags属性,最后copy.deepcopy()与numpy.copy()类似先遍历获得一个channel然后复制。

引用这篇博客中的一个关键结论:输入与输出必须完全一致,不单是值上的一致性,还需要保证array结构上的一致性。通过对比上表就可以发现,其实就是两点不一样:“C_CONTIGUOUS”与“OWNDATA ”,“OWNDATA ”非常好理解,使用切片方式获取数据,自然不拥有数据,只拥有数据的引用。“C_CONTIGUOUS”表示数据是在一个单一的C风格的连续段中,由于numpy存储数据是连续存储最后一个维度,而后倒数第二个,以此类推。因此单独获得一个channel的数据也就不是连续的了。

现在也就是比较明确了,对于opencv输入也是输出的函数,必须保证array在flags层面上的一致性。

在使用过程中推荐使用split函数与numpy copy()函数,因为我在使用copy.deepcopy过程中就遇到了“output array image is incompatible”问题。

PS:还要提一句findContours函数输入可以是(n, n)维度的,不一定要(n,n, 1)维度。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章