【问题标题】:Opencv: ValueErrorOpencv:值错误
【发布时间】:2016-06-02 06:30:00
【问题描述】:

我已经检测到轮廓并将它们存储在 cnts 中,并且我正在逐一访问它们,c_list 是我感兴趣的轮廓列表。 我想使用以下代码检查我现在访问的轮廓是否已经被访问过:

if not (np.all(cnts[c] in c_list)):
      while hierarchy[0][k][2] != -1:
        k = hierarchy[0][k][2]
        c_list.append(cnts[k])
        s = s+1

还是报错

ValueError:具有多个元素的数组的真值不明确。使用 a.any() 或 a.all()

有人可以纠正我做错了什么吗?

【问题讨论】:

  • 你能发布cntsc_list的样本数据吗?
  • 是的,但它确实是一个非常非常大的列表,因此我已将其上传到谷歌驱动器link
  • 几个元素就足以看到它们的结构。
  • 完整的轮廓和包含感兴趣计数的 c_list 是here
  • edit你的问题,不要在cmets中添加代码。

标签: python python-2.7 opencv numpy opencv-contour


【解决方案1】:

您的问题与 OpenCV 无关,它来自 numpy。

考虑以下示例:

>>> import numpy as np
>>> [1,3] in [[1,3],[4,5]]
True

>>> np.array([1,3]) in [[1,3],[4,5]]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

在您指定的 cmets 中(我们可以从 OpenCV 本身断言,但此信息应该在您的问题中开始)您正在比较的对象可能类似于

c_list = [[[[291, 267]], [[288, 268]], [[289, 267]]]]
cnts = np.array([[[291, 267]], [[288, 268]], [[289, 267]]])
# test for cnts[0] in c_list

问题是numpy.ndarray 的索引元素仍然是numpy.ndarray,但正如您在我的第一个示例中看到的那样,当您尝试对它们使用通常的逻辑操作时,numpy 数组的行为会有所不同本机列表。这是有道理的,因为在原生 python 处理in 具有列表值操作数的唯一明显方法 是测试第二个列表是否具有等于第一个列表的列表值元素。使用 numpy,您通常希望对数组进行元素测试,这就是为什么相同的表达式会导致错误。

现在,解决您的问题比预期的要复杂。目前尚不完全清楚您要实现的目标,并且可能有一种更合乎逻辑的方法来做到这一点。无论如何,请考虑这些修改后的示例:

>>> [1,3] in [[1,3],[4,5]]
True
>>> [1,3] in [[1,2],[4,5]]
False
>>> np.array([1,3]) in np.array([[1,3],[4,5]])
True
>>> np.array([1,3]) in np.array([[1,2],[4,5]])
True
>>> np.array([1,3]) in np.array([[0,2],[4,5]])
False

虽然在 两个 ndarrays 之间使用 in 不会产生错误,但它的行为方式令人惊讶:如果有 any 个公共元素,它会返回 True在两个数组之间!这显然不是你想做的。

在我看来,您有两个选择。您可以将所有 ndarray 转换为列表。我的意思:

>>> np.array([1,3]).tolist() in np.array([[1,3],[4,5]]).tolist()
True
>>> np.array([1,3]).tolist() in np.array([[1,2],[4,5]]).tolist()
False

这需要您调用c_list.append(cnts[k].tolist()) 并测试if not (cnts[c].tolist() in c_list):,但将numpy 数组转换为本机python 列表通常不是一个好主意,主要是出于内存考虑。如果你的轮廓有很多元素(这取决于你是否将cv2.CHAIN_APPROX_SIMPLE 传递给findContours()),这可能是一个强约束。

另一种选择是完全使用 numpy。如果我正确理解您想要检查数组np.array([[a,b]]) 是否在数组列表[np.array([[c,d]]), np.array([[f,g]]),...] 中,那么您可以使用elementwise 相等性测试,利用数组广播,并使用np.all()np.any() 以减少结果。示例:

>>> to_find = np.array([[1,3]])
>>> in_which = [np.array([[2,4]]),np.array([[1,3]]),np.array([[5,6]])]
>>> to_find in in_which
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> np.all(to_find==in_which,axis=-1).any()
True

包含您的模板的列表相同:

>>> to_find = np.array([[1,3]])
>>> in_which = [np.array([[2,4]]),np.array([[1,2]]),np.array([[5,6]])]
>>> np.all(to_find==in_which,axis=-1).any()
False

【讨论】:

  • 非常感谢您的评论,这正是我想要在感兴趣的轮廓列表中找到我的轮廓。 :+1: 实际上 cnt_list 是所有层次结构的轮廓,因为我只需要这些轮廓,而 cnts[c] 是检查他的父母是否已经检查过然后跳过这个只是为了改进算法。
  • 但我无法将 python 列表中的数组与单个 np 数组进行精确比较,请您告诉我该怎么做,因为将 if 条件更改为python if not (np.all(cnts[c] in c_list)).any(): 仍然会抛出相同的错误,所以如何将 cnt_list 更改为 numpy 数组?
  • @warl0ck 做我在回答中写的怎么样?查看最后一个代码块并尝试看看它是否可以应用于您的问题。
  • 问题是 in_which 您正在指定 numpy 数组的变量,但我已经将它们放在列表中,并且它没有签入列表并引发相同的错误。
  • 它是否与使用相同或有任何更有效的方法` any(cnts[c] is c for c in cnt_list)` 我在一个解决方案中找到了这个在堆栈本身上
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-14
  • 2018-05-08
  • 2021-10-14
  • 1970-01-01
  • 2012-12-27
  • 2011-10-11
  • 2012-03-16
相关资源
最近更新 更多