测试numpy数组是否是numpy数组列表的成员,并将其从列表中删除



测试numpy数组c是否为numpy数组列表CNTS:的成员时

import numpy as np
c = np.array([[[ 75, 763]],
[[ 57, 763]],
[[ 57, 749]],
[[ 75, 749]]])
CNTS = [np.array([[[  78, 1202]],
[[  63, 1202]],
[[  63, 1187]],
[[  78, 1187]]]),
np.array([[[ 75, 763]],
[[ 57, 763]],
[[ 57, 749]],
[[ 75, 749]]]),
np.array([[[ 72, 742]],
[[ 58, 742]],
[[ 57, 741]],
[[ 57, 727]],
[[ 58, 726]],
[[ 72, 726]]]),
np.array([[[ 66, 194]],
[[ 51, 194]],
[[ 51, 179]],
[[ 66, 179]]])]
print(c in CNTS)

我得到:

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

然而,答案相当明确:c正是CNTS[1],所以c in CNTS应该返回True!

如何正确测试numpy数组是否是numpy数组列表的成员

删除时也会出现同样的问题:

CNTS.remove(c)

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

应用程序:测试opencv轮廓(numpy数组(是否是轮廓列表的成员,请参见例如从轮廓列表中删除opencv轮廓。

由于in本质上调用了CNTS的每个元素x上的bool(c == x),因此您会得到错误。是__bool__转换引起了错误:

>>> c == CNTS[1]
array([[[ True,  True]],
[[ True,  True]],
[[ True,  True]],
[[ True,  True]]])
>>> bool(_)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

这同样适用于删除,因为它测试每个元素的相等性。

遏制

解决方案是使用np.array_equal或将all方法应用于每次比较:

any(np.array_equal(c, x) for x in CNTS)

any((c == x).all() for x in CNTS)

删除

要执行删除,您对元素的索引比对其存在更感兴趣。我能想到的最快的方法是迭代索引,使用CNTS的元素作为比较键:

index = next((i for i, x in enumerate(CNTS) if (c == x).all()), -1)

此选项可以很好地短路,并返回-1作为默认索引,而不是引发StopIteration。如果您喜欢该错误,可以删除参数-1next。如果您愿意,可以将(c == x).all()替换为np.array_equal(c, x)

现在你可以像往常一样删除:

del CNTS[index]

此解决方案适用于这种情况:

def arrayisin(array, list_of_arrays):
for a in list_of_arrays:
if np.array_equal(array, a):
return True
return False

此函数对数组列表进行迭代,并测试与其他数组的相等性。所以用法是:

>>> arrayisin(c, CNTS)
True

要从列表中删除该数组,可以获取该数组的索引,然后使用list.pop。在函数get_index中,我们枚举数组列表,这意味着我们压缩列表的索引和列表的内容。如果有匹配,我们返回匹配的索引。

def get_index(array, list_of_arrays):
for j, a in enumerate(list_of_arrays):
if np.array_equal(array, a):
return j
return None
idx = get_index(c, CNTS)  # 1
CNTS.pop(idx)

有关list.pop的文档,请参阅python数据结构教程https://docs.python.org/3/tutorial/datastructures.html

使用del删除要删除的列表的索引。

del CNTS[int(np.where(list(np.array_equal(row, c) for row in CNTS))[0])]
CNTS
[array([[[  78, 1202]],
[[  63, 1202]],
[[  63, 1187]],
[[  78, 1187]]]), array([[[ 72, 742]],
[[ 58, 742]],
[[ 57, 741]],
[[ 57, 727]],
[[ 58, 726]],
[[ 72, 726]]]), array([[[ 66, 194]],
[[ 51, 194]],
[[ 51, 179]],
[[ 66, 179]]])]

最新更新