简体   繁体   English

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

[英]Test if a numpy array is a member of a list of numpy arrays, and remove it from the list

When testing if a numpy array c is member of a list of numpy arrays CNTS :在测试 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)

I get:我得到:

ValueError: The truth value of an array with more than one element is ambiguous. ValueError:包含多个元素的数组的真值不明确。 Use a.any() or a.all()使用 a.any() 或 a.all()

However, the answer is rather clear: c is exactly CNTS[1] , so c in CNTS should return True!然而,答案很明确: c正是CNTS[1] ,所以c in CNTS应该返回 True!

How to correctly test if a numpy array is member of a list of numpy arrays?如何正确测试 numpy 数组是否是 numpy 数组列表的成员?

The same problem happens when removing :删除时会发生同样的问题:

CNTS.remove(c)

ValueError: The truth value of an array with more than one element is ambiguous. ValueError:包含多个元素的数组的真值不明确。 Use a.any() or a.all()使用 a.any() 或 a.all()

Application: test if an opencv contour (numpy array) is member of a list of contours, see for example Remove an opencv contour from a list of contours .应用程序:测试opencv轮廓(numpy 数组)是否是轮廓列表的成员,例如参见Remove an opencv contour from a list of contours

You are getting the error because in essentially invokes bool(c == x) on every element x of CNTS .您收到错误是因为in基本上对CNTS每个元素x调用bool(c == x) It's the __bool__ conversion that is raising the error:这是引发错误的__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()

The same applies for removal, since it tests for equality with each element.这同样适用于删除,因为它测试每个元素的相等性。

Containment遏制

The solution is to use np.array_equal or apply the all method to each comparison:解决方案是使用np.array_equal或将all方法应用于每个比较:

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

OR或者

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

Removal移动

To perform the removal, you are more interested in the index of the element than its existence.要执行删除,您对元素的索引比它的存在更感兴趣。 The fastest way I can think of is to iterate over the indices, using the elements of CNTS as comparison keys:我能想到的最快方法是迭代索引,使用CNTS的元素作为比较键:

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

This option short circuits quite nicely, and returns -1 as the default index rather than raising a StopIteration .这个选项可以很好地短路,并返回-1作为默认索引而不是引发StopIteration You can remove the argument -1 to next if you prefer the error.如果您更喜欢错误,可以将参数-1删除到next If you prefer, you can replace (c == x).all() with np.array_equal(c, x) .如果您愿意,可以将(c == x).all() np.array_equal(c, x) (c == x).all()替换为np.array_equal(c, x)

Now you can remove as usual:现在您可以像往常一样删除:

del CNTS[index]

This solution could work for this case:此解决方案适用于这种情况:

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

This function iterates over a list of arrays and tests the equality against some other array.此函数迭代数组列表并测试其他数组的相等性。 So the usage would be:所以用法是:

>>> arrayisin(c, CNTS)
True

To remove the array from the list, you can get the index of the array and then use list.pop .要从列表中删除数组,您可以获取数组的索引,然后使用list.pop In the function get_index , we enumerate the list of arrays, meaning we zip the indices of the list and the contents of the list.在函数get_index ,我们枚举数组列表,这意味着我们压缩列表的索引和列表的内容。 If there is a match, we return the index of the match.如果有匹配项,我们返回匹配项的索引。

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)

Please see the python data structures tutorial for the documentation of list.pop https://docs.python.org/3/tutorial/datastructures.html list.pop的文档请参见python数据结构教程https://docs.python.org/3/tutorial/datastructures.html

Use del to delete the index of the list you want to remove.使用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]]])]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM