简体   繁体   English

使用 numpy logical_and 或在哪里定位 3D 边界框内的点索引?

[英]Locating indices of points within 3D bounding box using numpy logical_and or where?

I have a large list of points (x, y, z) .我有很多点(x, y, z)

points = np.random.rand(999).reshape(333, 3)

I also have two points representing the minimum and maximum corners of a 3D bounding box representing points of interest我还有两个点代表 3D 边界框的最小和最大角,代表兴趣点

min_point = np.random.rand(3)
min_x, min_y, min_z = min_point[0], min_point[1], min_point[2]

max_point = np.random.rand(3)
max_x, max_y, max_z = max_point[0], max_point[1], max_point[2]

I am trying to select indices in points which lie within this bounding box but am having issues.我正在尝试 select 索引位于此边界框内但有问题的points I originally attempted using np.where我最初尝试使用np.where

poi_inds = np.where(
    points[:, 0] > min_x and points[:, 0] < max_x and
    points[:, 1] > min_y and points[:, 1] < max_y and
    points[:, 2] > min_z and points[:, 2] < max_z
)

Though this results in虽然这会导致

ValueError: The truth value of an array with more than one element is ambiguous.

because and 'ing the results of each comparison is ambiguous (from my understand numpy can't decide to do element-wise or entire array and ).因为and 'ing 每次比较的结果都是模棱两可的(据我了解numpy不能决定逐元素或整个数组and )。

I found an SO answer which provides a solution in the 2D case and I've attempted to expand it to the 3D case我找到了一个 SO answer,它在 2D 案例中提供了一个解决方案,我试图将其扩展到 3D 案例

poi_inds = np.all(np.logical_and.reduce((
    points[:, 0] > min_x, points[:, 0] < max_x,
    points[:, 1] > min_y, points[:, 1] < max_y,
    points[:, 2] > min_z, points[:, 2] < max_z)))

Though this seems to always result in no points being selected ( poid_inds = (False) , if I remove the np.all I find all indices are False ) even after running the SSCCE below multiple times.尽管这似乎总是导致没有选择任何点( poid_inds = (False) ,如果我删除np.all我发现所有索引都是False )即使在多次运行以下 SSCCE 之后也是如此。

import numpy as np

points = np.random.rand(999).reshape(333, 3)

rand_pt0 = np.random.rand(3)
rand_pt1 = np.random.rand(3)
# Ensure the minimum point is always less than the maximum
min_point = np.array([
    rand_pt0[0] if rand_pt0[0] < rand_pt1[0] else rand_pt1[0],
    rand_pt0[1] if rand_pt0[1] < rand_pt1[1] else rand_pt1[1],
    rand_pt0[2] if rand_pt0[2] < rand_pt1[2] else rand_pt1[2],
])
max_point = np.array([
    rand_pt1[0] if rand_pt0[0] < rand_pt1[0] else rand_pt0[0],
    rand_pt1[1] if rand_pt0[1] < rand_pt1[1] else rand_pt0[1],
    rand_pt1[2] if rand_pt0[2] < rand_pt1[2] else rand_pt0[2],
])

min_x, min_y, min_z = min_point[0], min_point[1], min_point[2]
max_x, max_y, max_z = max_point[0], max_point[1], max_point[2]

# poi_inds = np.where(
#     points[:, 0] > min_x and points[:, 0] < max_x and
#     points[:, 1] > min_y and points[:, 1] < max_y and
#     points[:, 2] > min_z and points[:, 2] < max_z
# )

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

What is the proper use of np.where or np.logical_and in this case to locate the points within the described bounding box?在这种情况下,正确使用np.wherenp.logical_and来定位所描述的边界框中的点是什么?

I have found a compact solution which utilizes np.where , functools.reduce , and np.intersect1d我找到了一个紧凑的解决方案,它利用np.wherefunctools.reducenp.intersect1d

from functools import reduce

poi_inds = reduce(np.intersect1d, (
    np.where(points[:, 0] > min_x),
    np.where(points[:, 0] < max_x),
    np.where(points[:, 1] > min_y),
    np.where(points[:, 1] < max_y),
    np.where(points[:, 2] > min_z),
    np.where(points[:, 2] < max_z)
))

On large lists >100M points this is many times faster than iterating through the points "manually".在大于 100M 点的大型列表中,这比“手动”遍历这些点要快很多倍。

poi_inds = []
for ind, pt in enumerate(points):
    if min_x < pt[0] < max_x and min_y < pt[1] < max_y and min_z < pt[2] < max_z:
        poi_inds.append(ind)

If points is a Numpy array you can use & instead of np.logical_and to write this as:如果points是 Numpy 数组,则可以使用&而不是np.logical_and将其写为:

  mask_x = (points[:, 0] >= min_x) & (points[:, 0] <= max_x)
  mask_y = (points[:, 1] >= min_y) & (points[:, 1] <= max_y)
  mask_z = (points[:, 2] >= min_z) & (points[:, 2] <= max_z)
  mask = mask_x & mask_y & mask_z
  indices = np.where(mask)

Which, from a quick test, seems to be faster than the solution by KDecker.从快速测试来看,这似乎比 KDecker 的解决方案更快。

The problem is that you are comparing an array with an element.问题是您正在将数组与元素进行比较。

points[:, 0] > min_x

An array cannot be compared with a single element.数组不能与单个元素进行比较。
Instead, you need to use a loop.相反,您需要使用循环。

for i in range(333):
    points[i:0] > min_x

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

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