
本教程详细介绍了如何利用 numpy 的 `np.mgrid` 函数,在给定的 3d 边界框内以指定步长高效地采样一系列空间点,并为每个采样点自动关联其所属边界框的标签。通过直接在 `np.mgrid` 中构造标签维度,避免了额外的数据处理步骤,从而简化了代码并提升了效率。
在处理 3D 空间数据时,我们经常会遇到以边界框形式表示的对象。每个边界框通常由其最小和最大坐标定义,并且可能带有一个或多个属性,例如标签。本教程中,我们假设每个边界框由 8 个 4D 坐标点描述,格式为 (x, y, z, l),其中 (x, y, z) 是空间坐标,l 是一个整数标签。一个 boxes 数组可能包含 n 个这样的边界框,其形状可能为 (n, 8, 4)。
例如,一个边界框的数据结构可能如下所示:
boxes[0] = [
[0.0, 0.0, 0.0, 1],
[2.0, 0.0, 0.0, 1],
[2.0, 3.0, 0.0, 1],
[0.0, 3.0, 0.0, 1],
[0.0, 0.0, 1.0, 1],
[2.0, 0.0, 1.0, 1],
[2.0, 3.0, 1.0, 1],
[0.0, 3.0, 1.0, 1]
]这里,每个点的第四个维度(索引为 3)代表其所属边界框的标签。
我们的目标是在每个给定的 3D 边界框内部,以一个固定的 step_size(例如 0.01 米)生成一系列均匀分布的 (x, y, z) 坐标点,并将每个采样点与其所属边界框的标签 l 关联起来。最终输出应是一个包含所有采样点及其对应标签的列表或数组。
NumPy 库提供了 np.mgrid 函数,它是一个非常强大的工具,用于在指定范围内生成多维网格坐标。它的语法类似于 Python 的切片操作,格式为 start:stop:step。
在本教程中,我们将主要利用浮点数 step_size 的用法,并结合巧妙的维度构造来实现标签的自动关联。
为了高效地在 3D 边界框内采样点并关联标签,我们可以将 np.mgrid 的功能扩展到第四个维度,专门用于存储标签信息。
对于一个给定的边界框 box(形状为 (8, 4)),我们需要提取其 x, y, z 坐标的最小值和最大值,以及其标签。由于所有 8 个点的标签都是相同的,我们可以从任意一个点获取标签。
import numpy as np
# 假设这是一个单独的边界框数据
box = np.array([
[0.0, 0.0, 0.0, 1],
[2.0, 0.0, 0.0, 1],
[2.0, 3.0, 0.0, 1],
[0.0, 3.0, 0.0, 1],
[0.0, 0.0, 1.0, 1],
[2.0, 0.0, 1.0, 1],
[2.0, 3.0, 1.0, 1],
[0.0, 3.0, 1.0, 1]
])
step_size = 0.6 # 采样步长
# 提取x, y, z维度的最小值和最大值
min_x, max_x = np.min(box[:, 0]), np.max(box[:, 0])
min_y, max_y = np.min(box[:, 1]), np.max(box[:, 1])
min_z, max_z = np.min(box[:, 2]), np.max(box[:, 2])
# 提取边界框的标签
label = int(box[0, 3]) # 假设所有点的标签相同现在,我们将 np.mgrid 应用于四个维度:x, y, z 和 label。
points_with_labels = np.mgrid[
min_x:max_x:step_size,
min_y:max_y:step_size,
min_z:max_z:step_size,
label:label + 1 # 关键:生成一个只包含标签值的维度
]这里 label:label + 1 是一个巧妙的用法。它会生成一个从 label 开始,步长为 1,到 label + 1 结束(不包含 label + 1)的序列。这意味着这个维度将只包含 label 这一个值,从而将标签广播到所有生成的 (x, y, z) 点上。
np.mgrid 的输出是一个多维数组,其每个维度对应于输入切片。我们需要将其重塑为 (N, 4) 的二维数组,其中 N 是采样点的总数,每行代表一个 (x, y, z, label) 点。
points_final = points_with_labels.reshape(4, -1).T
reshape(4, -1) 会将数组重塑为 4 行,列数自动计算。.T 进行转置操作,将形状变为 (-1, 4),即 N 行 4 列,这正是我们期望的 (x, y, z, label) 格式。
让我们结合上述步骤,为一个示例边界框生成采样点。
import numpy as np
from itertools import product, repeat
# 示例边界框数据
# 这是一个从 (0,0,0) 到 (1,1,1) 的立方体,标签为 7
label = 7
box = np.hstack([np.array(list(product(*repeat(range(2), 3)))), np.ones((8,1)) * label])
print("原始边界框数据:\n", box)
step_size = 0.6 # 采样步长
# 提取x, y, z维度的最小值和最大值
min_x, max_x = np.min(box[:, 0]), np.max(box[:, 0])
min_y, max_y = np.min(box[:, 1]), np.max(box[:, 1])
min_z, max_z = np.min(box[:, 2]), np.max(box[:, 2])
# 使用 np.mgrid 生成点和标签
points_with_labels = np.mgrid[
min_x:max_x:step_size,
min_y:max_y:step_size,
min_z:max_z:step_size,
label:label + 1
]
# 重塑数据为 (N, 4) 格式
sampled_points = points_with_labels.reshape(4, -1).T
print("\n采样步长:", step_size)
print("生成的采样点及其标签:\n", sampled_points)输出示例:
原始边界框数据: [[0. 0. 0. 7.] [0. 0. 1. 7.] [0. 1. 0. 7.] [0. 1. 1. 7.] [1. 0. 0. 7.] [1. 0. 1. 7.] [1. 1. 0. 7.] [1. 1. 1. 7.]] 采样步长: 0.6 生成的采样点及其标签: [[0. 0. 0. 7. ] [0. 0. 0.6 7. ] [0. 0.6 0. 7. ] [0. 0.6 0.6 7. ] [0.6 0. 0. 7. ] [0.6 0. 0.6 7. ] [0.6 0.6 0. 7. ] [0.6 0.6 0.6 7. ]]
当需要处理多个边界框时,我们可以遍历 boxes 数组,对每个边界框应用上述逻辑,并将结果收集起来。
import numpy as np
# 模拟多个边界框数据
# boxes.shape = (num_boxes, 8, 4)
boxes = np.array([
[
[0.0, 0.0, 0.0, 1], [2.0, 0.0, 0.0, 1], [2.0, 3.0, 0.0, 1], [0.0, 3.0, 0.0, 1],
[0.0, 0.0, 1.0, 1], [2.0, 0.0, 1.0, 1], [2.0, 3.0, 1.0, 1], [0.0, 3.0, 1.0, 1]
],
[
[10.0, 10.0, 10.0, 2], [11.0, 10.0, 10.0, 2], [11.0, 12.0, 10.0, 2], [10.0, 12.0, 10.0, 2],
[10.0, 10.0, 11.0, 2], [11.0, 10.0, 11.0, 2], [11.0, 12.0, 11.0, 2], [10.0, 12.0, 11.0, 2]
]
])
step_size = 0.5 # 采样步长
all_sampled_points = []
for i in range(boxes.shape[0]):
current_box = boxes[i]
# 提取x, y, z维度的最小值和最大值
min_x, max_x = np.min(current_box[:, 0]), np.max(current_box[:, 0])
min_y, max_y = np.min(current_box[:, 1]), np.max(current_box[:, 1])
min_z, max_z = np.min(current_box[:, 2]), np.max(current_box[:, 2])
# 提取边界框的标签
label = int(current_box[0, 3])
# 使用 np.mgrid 生成点和标签
points_with_labels = np.mgrid[
min_x:max_x:step_size,
min_y:max_y:step_size,
min_z:max_z:step_size,
label:label + 1
]
# 重塑数据为 (N, 4) 格式
sampled_points_for_box = points_with_labels.reshape(4, -1).T
all_sampled_points.append(sampled_points_for_box)
# 将所有边界框的采样点合并为一个 NumPy 数组
final_sampled_data = np.vstack(all_sampled_points)
print("所有边界框的采样点及其标签的前10行:\n", final_sampled_data[:10])
print("\n所有边界框的采样点总数:", final_sampled_data.shape[0])端点包含性: 使用 np.mgrid 配合浮点数 step_size 时,生成的序列默认不包含 stop 值。这意味着 max_x, max_y, max_z 这些边界值本身可能不会被采样到,除非它们恰好是 start + k * step_size 的精确结果。如果需要严格包含端点,可以考虑以下方法:
浮点数精度: 在涉及浮点数计算时,尤其是在比较边界或计算步长时,可能会遇到浮点数精度问题。在实际应用中,如果对边界的精确性有极高要求,需要谨慎处理。
性能考量: 对于少量边界框,上述循环方法效率足够。但如果 boxes 数组非常大,且每个边界框的采样点数量也很多,循环可能不是最高效的方式。在这种极端情况下,可以考虑更高级的矢量化技术或并行计算,但这会使代码复杂性显著增加。对于大多数常见的 3D 场景,当前方法已提供良好的性能和可读性。
通过巧妙地利用 NumPy np.mgrid 函数的切片语法,
以上就是使用 NumPy 在 3D 边界框内高效采样点并关联标签的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号