我是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()
答案 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
个整数对,即N
个x,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]