【问题标题】:Error: operands could not be broadcast together with shapes (1776,1,2) (3896,1,2)错误:操作数无法与形状一起广播 (1776,1,2) (3896,1,2)
【发布时间】:2017-07-02 23:22:51
【问题描述】:

我是 python 新手,我正在尝试编写一个代码,从图像中提取轮廓并按照轮廓列表中元素长度的升序对它们进行排序。当我使用 sort() 或 list.sort() 时,出现错误:操作数无法与形状一起广播 (1776,1,2) (3896,1,2) 我该如何解决这个问题? 这是我正在使用的image

我得到的错误信息是:

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()

【问题讨论】:

  • 让错误消失很容易,但要确保结果是您想要的结果却不太容易。您是否了解错误中的这些维度,以及您的预期结果应该是什么大小?
  • 我相信它们是列表中第一个和第二个元素的尺寸
  • 对不起,如果这是一个愚蠢的问题。我以前没有使用 python 的经验,我一直在尝试解决这个问题。
  • 是的,但他们的目的是什么?我的观点是,我可以告诉你如何制作尺寸以使其广播,例如,结果可能具有(1776,3896,1,2) 的形状。但这是否有意义是另一回事,您应该了解正在发生的事情以及您到底想做什么。
  • 我刚刚添加了错误信息。我真的很感谢你告诉我这件事。谢谢!

标签: python python-2.7 image-processing


【解决方案1】:

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

无论如何,您的问题的核心可以很容易地回答。从cv2.findContours 返回的contours 看起来像这样:

>>> 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]

【讨论】:

  • 非常感谢!现在这很有意义。我想我无法理解错误是由于我不熟悉 python 以及各自的代码行在做什么,但感谢您帮助我更好地理解它:)
  • @Alizay 很高兴我能提供帮助。如果你有时间,如果你想使用构建在上面的框架,学习原生 python 本身会有很大帮助。无论如何,如果以上确实解决了您的问题,请考虑marking my answer as accepted
猜你喜欢
  • 2019-09-01
  • 2022-09-24
  • 2015-05-18
  • 2018-02-28
  • 1970-01-01
  • 2017-09-09
  • 2020-09-06
  • 2012-10-31
  • 2013-04-07
相关资源
最近更新 更多