错误:操作数无法与形状一起广播(1776,1,2)(3896,1,2)

时间:2017-07-02 23:22:51

标签: python python-2.7 image-processing

我是python的新手,我试图编写一个从图像中提取轮廓的代码,并按照轮廓列表中元素长度的升序排序。当我使用sort()或list.sort()时,我得到一个错误:操作数无法与形状一起广播(1776,1,2)(3896,1,2) 我怎么能解决这个问题? 这是我正在使用的deployment instructions for GitHub Pages

我得到的错误信息是:

Traceback (most recent call last):

File "/home/dehaoliu/opencv_test/Engineering drawings/example.py", line 19, in <module>
    contours.sort()
ValueError: operands could not be broadcast together with shapes (1776,1,2) (3896,1,2) 

以下是产生错误的缩短代码:

import cv2
    import numpy as np
    from math import sqrt

name='20_right_5-1'
img = cv2.imread(name+'.JPG')
im = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.imwrite(name+"_dilation.jpg", closing)
im = cv2.imread(name+'_dilation.jpg')
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
#ret,thresh = cv2.threshold(imgray,127,255,cv2.THRESH_BINARY_INV)
blur = cv2.GaussianBlur(imgray,(5,5),0)
ret,thresh = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
im2, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cv2.drawContours(im, contours, -1, (0,255,0), 3)

cv2.namedWindow("Contours")
cv2.imshow("Contours", im)

cv2.waitKey(0)
cv2.destroyAllWindows()

cv2.imwrite(name+"_contour.jpg", im)
print "this is contours"
print contours
print type(contours)
contours.sort()

1 个答案:

答案 0 :(得分:0)

请注意,原始问题和缩短版本都包含一些错误,这些错误会使重现问题变得有点困难。此外,您似乎做了很多不必要的事情(例如导入数学,图像,matplotlib,scipy等而不使用它们,或仅保存图像以便以另一个名称再次读取它们)。

无论如何,你的问题的核心可以轻松回答。从contours返回的cv2.findContours看起来像这样:

>>> type(contours)
list
>>> len(contours)
15
>>> type(contours[0])
numpy.ndarray
>>> print(contours[0].shape)
(3888, 1, 2)

即。您的15个轮廓中的每一个都是一个形状为(N,1,2)的3d numpy数组。除了单例维度之外,您基本上在矩阵中有N*2个点:N个整数对,即Nx,y个图像坐标对,用于跟踪图像上的给定轮廓

现在,当你尝试对这个数组列表进行排序时,python会尝试比较两个元素,例如

contours[0] < contours[1]

但是numpy数组被比较 elementwise ,当数组在某些地方具有单个维度时使用所谓的广播。这意味着以下行为:

>>> np.random.rand(2,3) < np.random.rand(1,3)
array([[ True,  True, False],
       [False,  True, False]], dtype=bool)
>>> np.random.rand(2,3) < np.random.rand(4,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: operands could not be broadcast together with shapes (2,3) (4,3) 

也就是说,兼容形状的数组(例如(2,3)(1,3))沿单例维度有效扩展,并且逐个元素地进行比较。如果两个形状不匹配(例如(1776,1,2)(3896,1,2)),则会出现错误。但这不是你想要做的第一个!

您想要做的事情在您的问题中清楚地表达出来:按照长度按升序排列轮廓。大!我们仍然可以使用contours.sort(或sorted()如果我们想要副本),但我们需要告诉sort 要按什么排序。在我们的例子中,它需要按轮廓的长度排序。轮廓的长度是多少?对于每个轮廓contour,它是第一个维度的大小,即contour.shape[0]

最重要的是你需要将一个键函数传递给.sort,它允许你按轮廓长度排序,从而导致比较整数(而不是数组):

>>> [contour.shape[0] for contour in contours]
[3888, 1775, 1044, 1508, 255, 95, 233, 330, 310, 177, 155, 592, 506, 1044, 663]
>>> contours.sort(key=lambda contour: contour.shape[0])
>>> [contour.shape[0] for contour in contours]
[95, 155, 177, 233, 255, 310, 330, 506, 592, 663, 1044, 1044, 1508, 1775, 3888]