删除彼此靠近的 2d 点

Removing the 2d point that are close to each others

我想删除彼此靠近或只是重复的坐标。

例如,

x = [[9, 169], [5, 164],[340,210],[1020,102],[210,312],[12,150]]

在上面的列表中,第一个和第二个元素彼此靠近。如何在保留第一个元素的同时删除第二个元素?

以下是我试过的,

def process(input_list, thresh=(10, 10)):
    buffer = input_list.copy()
    n = 0
    prev_cx, prev_cy = 0, 0
    for i in range(len(input_list)):
        elem = input_list[i]
        cx, cy = elem
        if n == 0:
            prev_cx, prev_cy = cx, cy
        else:
            ab_cx, ab_cy = abs(prev_cx - cx), abs(prev_cy - cy)
            if ab_cx <= thresh[0] and ab_cy <= thresh[1]:
                del buffer[i]
        n += 1
    return buffer


x = [[9, 169], [5, 164], [340, 210], [1020, 102], [210, 312], [12, 150]]
processed = process(x)
print(processed)

问题在于它不会递归检查是否有任何其他重复项,因为它只检查相邻坐标。过滤坐标的有效方法是什么?

阈值 = (10,10) 的示例输入:

x = [[12,24], [5, 12],[100,1020], [20,30], [121,214], [15,12]]

示例输出:

x = [[12,24],[100,1020], [121,214]]

你的问题有点含糊,但我的意思是:

  1. 您想比较点的所有组合
  2. 如果组合包含比阈值更接近的点
  3. 然后从输入列表的开头移除点

试试这个:

import itertools

def process(input_list, threshold=(10,10)):
    combos = itertools.combinations(input_list, 2)
    points_to_remove = [point2
                        for point1, point2 in combos
                        if abs(point1[0]-point2[0])<=threshold[0] and abs(point1[1]-point2[1])<=threshold[1]]
    points_to_keep = [point for point in input_list if point not in points_to_remove]
    return points_to_keep

coords = [[12,24], [5, 12],[100,1020], [20,30], [121,214], [15,12]]
print(process(coords))
    
>>> [[12, 24], [5, 12], [100, 1020], [121, 214]]

其工作方式是使用 itertools 生成点的所有组合(保留原始顺序中的点),然后使用阈值创建要删除的点列表。然后它 returns 一个不在要删除的点列表中的点列表。

你会发现我比你多了一分。我只是简单地复制了您想要的功能(即 dy 和 dx <= thresh 用于点删除)。 但是,如果我用 AND 语句更改行以删除 point if dy OR dx <= thresh,我会得到与您的示例相同的输出。

所以我要请你重新检查你的示例输出。

顺便说一句,确认单独检查 x 和 y 邻近度是否是您真正想要的可能对您很有用。因此,作为奖励,我还提供了一个使用欧几里得距离的版本:

import itertools
import math

def process(input_list, threshold=100):
    combos = itertools.combinations(input_list, 2)
    points_to_remove = [point2 for point1, point2 in combos if math.dist(point1, point2)<=threshold]
    points_to_keep = [point for point in input_list if point not in points_to_remove]
    return points_to_keep

coords = [[12,24], [5, 12],[100,1020], [20,30], [121,214], [15,12]]
print(process(coords))

>>> [[12, 24], [100, 1020], [121, 214]]

当我使用 100 的阈值半径时,此版本适合您的原始样本。

我将其拆分得有点不同。当然,这也很棘手,因为您必须修改列表。

def remove_close_neighbors(input_list, thresh, position):
  target_item = input_list[position]
  return [item for i, item in enumerate(input_list) if i == position or not is_close(target_item, item, thresh)]

这将删除除正在考虑的项目之外的所有“重复”(或关闭)点。

(然后定义is_close检查阈值条件)

然后我们可以检查我们的项目:

def process(input_list, thresh):
  pos = 0
  while pos < len(input_list):
    input_list = remove_close_neighbors(input_list, thresh, pos)
    pos += 1

这绝不是实现此目的的最有效方法。这取决于您需要多大的可扩展性。如果我们说的是“a bajillion points”,您将需要研究巧妙的数据结构和算法。我认为 tree 结构可能会很好,可以“按扇区”对点进行分组,因为那样你就不必一直将每个点与其他点进行比较。