Поиск точек в ограничивающей рамке с помощью numpy

У меня есть миллионы xyz-координат из нескольких файлов облака точек, которые я храню внутри двумерного массива numpy: [[x1, y1, z1], [x2, y2, z2],..., [xn, yn, zn]].

Я хочу отфильтровать все точки, которые находятся внутри определенного ограничивающего прямоугольника, описанного 4 координатами [[x1, y1], [x2, y2]], то есть нижними левыми и верхними правыми координатами прямоугольника.

Я уже нашел следующий фрагмент кода для фильтрации координат с помощью numpy, и это почти то, что мне нужно. Единственная разница (если я правильно понял) в том, что мой двумерный массив также имеет z-координаты.

import random
import numpy as np

points = [(random.random(), random.random()) for i in range(100)]

bx1, bx2 = sorted([random.random(), random.random()])
by1, by2 = sorted([random.random(), random.random()])

pts = np.array(points)
ll = np.array([bx1, by1])  # lower-left
ur = np.array([bx2, by2])  # upper-right

inidx = np.all(np.logical_and(ll <= pts, pts <= ur), axis=1)
inbox = pts[inidx]
outbox = pts[np.logical_not(inidx)]

Как мне изменить приведенный выше код, чтобы он работал с xyz-координатами для фильтрации с помощью ограничивающего прямоугольника, описанного двумя xy-координатами?


person conste    schedule 20.02.2017    source источник


Ответы (2)


Выберите координаты X и Y ваших точек:

xy_pts = pts[:,[0,1]]

Теперь просто используйте xy_pts вместо pts в сравнениях:

inidx = np.all((ll <= xy_pts) & (xy_pts <= ur), axis=1)
person DYZ    schedule 20.02.2017
comment
Но вот так я бы потерял z-информацию или нет? Мне определенно нужно сохранить их для дальнейших расчетов. - person conste; 20.02.2017
comment
@conste Вы будете использовать исходный 3D pts, чтобы построить inbox. - person DYZ; 20.02.2017

Я пишу библиотеку Python для работы с облаками точек, и у меня есть эта функция, которая, как мне кажется, должна работать для вас:

def bounding_box(points, min_x=-np.inf, max_x=np.inf, min_y=-np.inf,
                        max_y=np.inf, min_z=-np.inf, max_z=np.inf):
    """ Compute a bounding_box filter on the given points

    Parameters
    ----------                        
    points: (n,3) array
        The array containing all the points's coordinates. Expected format:
            array([
                [x1,y1,z1],
                ...,
                [xn,yn,zn]])

    min_i, max_i: float
        The bounding box limits for each coordinate. If some limits are missing,
        the default values are -infinite for the min_i and infinite for the max_i.

    Returns
    -------
    bb_filter : boolean array
        The boolean mask indicating wherever a point should be keeped or not.
        The size of the boolean mask will be the same as the number of given points.

    """

    bound_x = np.logical_and(points[:, 0] > min_x, points[:, 0] < max_x)
    bound_y = np.logical_and(points[:, 1] > min_y, points[:, 1] < max_y)
    bound_z = np.logical_and(points[:, 2] > min_z, points[:, 2] < max_z)

    bb_filter = np.logical_and(np.logical_and(bound_x, bound_y), bound_z)

    return bb_filter

Вот пример того, что вы спрашиваете:

10 миллионов баллов:

points = np.random.rand(10000000, 3)

Прямоугольник в указанном вами формате:

rectangle = np.array([[0.2, 0.2],
                     [0.4, 0.4]])

Распаковать прямоугольник:

min_x = rectangle[:,0].min()
max_x = rectangle[:,0].max()
min_y = rectangle[:,1].min()
max_y = rectangle[:,1].max()

Получите точки маркировки логического массива внутри поля:

%%timeit
inside_box = bounding_box(points, min_x=min_x, max_x=max_x, min_y=min_y, max_y=max_y)
1 loop, best of 3: 247 ms per loop

Таким образом, вы можете использовать массив следующим образом:

points_inside_box = points[inside_box]
points_outside_box = points[~inside_box]
person David de la Iglesia    schedule 21.02.2017
comment
В настоящее время я работаю над аналогичной проблемой, и мне нравится ваш ответ. Однако кажется, что ваш код действительно предоставляет ограничивающую рамку с параллельностью осям. У вас есть какие-нибудь подсказки или решения о том, как получить минимальную ограничивающую рамку? - person dnks23; 08.08.2019
comment
Трехмерные ограничивающие рамки обычно имеют 8 координат. - person Haozhe Xie; 07.01.2020