0

0

3D网格中盒子内部点的高效采样教程

碧海醫心

碧海醫心

发布时间:2025-11-24 14:10:13

|

216人浏览过

|

来源于php中文网

原创

3D网格中盒子内部点的高效采样教程

本教程详细阐述了如何在3d网格中对给定盒子进行高效的内部点采样。通过利用numpy库的`np.mgrid`函数,我们将展示一种简洁且向量化的方法,以指定步长生成包含(x, y, z)坐标及对应标签的采样点集合。这种方法显著简化了代码并提升了处理多个3d盒子的效率,适用于需要大规模空间数据采样的场景。

在处理3D空间数据时,我们经常需要对特定区域(例如由一组坐标定义的盒子)进行均匀采样。这在计算机图形学、物理模拟、机器学习特征提取等领域尤为常见。本文将深入探讨如何使用Python的NumPy库,特别是np.mgrid函数,高效地从3D盒子内部提取具有指定步长的采样点,并为每个点关联其所属盒子的标签。

1. 问题背景与数据结构

假设我们有一个包含n个3D盒子的数组,每个盒子由其8个顶点定义。每个顶点是一个4D坐标(x, y, z, l),其中(x, y, z)表示空间位置,l是一个整数标签(例如,表示物体类型)。

例如,一个盒子的数据结构可能如下所示:

boxes.shape = (n, 8, 4) # n个盒子,每个盒子8个顶点,每个顶点4个维度(x, y, z, label)

# 示例:第一个盒子的数据
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]
]

我们的目标是,给定一个step_size(例如0.01米),在每个盒子的内部以该步长均匀地采样点,并为每个采样点附上盒子的标签。最终输出应是一个包含所有采样点及其对应标签的集合。

2. 传统采样方法的局限性

一种常见的直观方法是:

  1. 计算每个盒子的x, y, z维度的最小值和最大值。
  2. 根据step_size计算每个维度上需要采样的点数。
  3. 使用np.mgrid配合复数步长(例如num_points * 1j)来生成包含端点的坐标网格。
  4. 将生成的坐标展平并堆叠,然后为每个点重复盒子的标签。
  5. 对所有盒子重复上述过程,并将结果收集到列表中。

其大致代码结构如下:

import numpy as np

# 假设 boxes 已定义
# mins = np.min(boxes[:, :, :3], axis=1) # 获取每个盒子的x,y,z最小值
# maxs = np.max(boxes[:, :, :3], axis=1) # 获取每个盒子的x,y,z最大值
# labels = boxes[:, 0, 3].astype(int) # 假设每个盒子的标签一致

# sampled_points_list = []
# sampled_labels_list = []
# step_size = 0.01

# for i in range(boxes.shape[0]):
#     # 计算每个维度上的点数
#     num_points_x = int(np.floor((maxs[i, 0] - mins[i, 0]) / step_size))
#     num_points_y = int(np.floor((maxs[i, 1] - mins[i, 1]) / step_size))
#     num_points_z = int(np.floor((maxs[i, 2] - mins[i, 2]) / step_size))

#     # 使用复数步长确保包含终点
#     x_coords, y_coords, z_coords = np.mgrid[
#         mins[i, 0]:maxs[i, 0]:(num_points_x + 1)*1j, # +1 to ensure endpoint is included if needed
#         mins[i, 1]:maxs[i, 1]:(num_points_y + 1)*1j,
#         mins[i, 2]:maxs[i, 2]:(num_points_z + 1)*1j
#     ]
#     points = np.vstack([x_coords.ravel(), y_coords.ravel(), z_coords.ravel()]).T
#     current_labels = np.repeat(labels[i], points.shape[0])

#     sampled_points_list.append(points)
#     sampled_labels_list.append(current_labels)

# # sampled_points = np.vstack(sampled_points_list)
# # sampled_labels = np.concatenate(sampled_labels_list)

这种方法虽然可行,但在计算每个维度上的点数以及处理标签重复时,代码略显繁琐。更重要的是,np.mgrid的复数步长用法需要我们预先计算点数,这增加了复杂性。

3. 基于np.mgrid的优化采样方法

NumPy的np.mgrid函数提供了一种更简洁的切片语法start:stop:step,可以直接指定步长来生成等间隔的数值序列。通过巧妙地利用这一特性,我们可以将坐标生成和标签关联集成到单个np.mgrid调用中,从而实现更高效、更简洁的采样。

Copy Leaks
Copy Leaks

AI内容检测和分级,帮助创建和保护原创内容

下载

核心思想是:将盒子的标签作为np.mgrid的第四个维度。由于标签对于盒子内部的所有采样点都是一致的,我们可以将其范围设置为label:label+1,这样np.mgrid将只在该维度生成一个值,即盒子的标签。

对于单个盒子box及其标签label,采样代码如下:

import numpy as np

# 假设 box 是一个形状为 (8, 4) 的NumPy数组,label 是该盒子的整数标签
# step_size 是采样步长

# 获取盒子的 x, y, z 坐标范围
min_x, min_y, min_z = np.min(box[:, :3], axis=0)
max_x, max_y, max_z = np.max(box[:, :3], axis=0)

# 使用 np.mgrid 直接生成包含标签的采样点
# 注意:np.mgrid 的 start:stop:step 语法不包含 stop 值
sampled_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 # 标签维度,生成一个值
].reshape(4, -1).T

代码解析:

  1. np.min(box[:, :3], axis=0) 和 np.max(box[:, :3], axis=0):这行代码从盒子的所有顶点中提取x, y, z坐标,并计算每个维度上的最小值和最大值,从而定义了盒子的边界。
  2. np.mgrid[min_x:max_x:step_size, ... , label:label + 1]:
    • min_x:max_x:step_size:为X轴生成从min_x开始,以step_size为步长,直到但不包括max_x的等间隔序列。Y轴和Z轴同理。
    • label:label + 1:为第四个维度(标签)生成一个从label开始,以1为步长,直到但不包括label + 1的序列。这意味着它只会生成一个值,即label本身。
    • np.mgrid会返回一个多维数组,其维度顺序是[x_dim, y_dim, z_dim, label_dim]。
  3. .reshape(4, -1).T:
    • reshape(4, -1):将生成的网格展平为一个2D数组,其中第一维是4(对应x, y, z, label),第二维是所有采样点的总数。
    • .T:进行转置操作,将数组形状从(4, N)变为(N, 4),使得每一行代表一个采样点(x, y, z, label),这更符合通常的数据表示习惯。

这种方法极大地简化了代码,并充分利用了NumPy的向量化能力,对于大规模数据处理具有显著的性能优势。

4. 完整示例与应用

现在,我们将上述优化方法应用于处理多个3D盒子。

import numpy as np

# 示例输入数据:包含两个盒子
boxes = np.array([
    [ # 第一个盒子,标签为1
        [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]
    ],
    [ # 第二个盒子,标签为2
        [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_coords = boxes[i, :, :3] # 提取当前盒子的x,y,z坐标
    # 假设盒子的标签在所有顶点中都是一致的,取第一个顶点的标签即可
    current_box_label = int(boxes[i, 0, 3])

    # 计算当前盒子的x,y,z坐标范围
    min_x, min_y, min_z = np.min(current_box_coords, axis=0)
    max_x, max_y, max_z = np.max(current_box_coords, axis=0)

    # 使用优化方法生成采样点,包含标签作为第四维
    sampled_box_points = np.mgrid[
        min_x:max_x:step_size,
        min_y:max_y:step_size,
        min_z:max_z:step_size,
        current_box_label:current_box_label + 1 # 标签维度
    ].reshape(4, -1).T

    all_sampled_points.append(sampled_box_points)

# 合并所有盒子的采样点到一个NumPy数组中
final_sampled_data = np.vstack(all_sampled_points)

print("最终采样数据形状:", final_sampled_data.shape)
print("\n前5个采样点:\n", final_sampled_data[:5])
print("\n后5个采样点:\n", final_sampled_data[-5:])

# 验证采样点的标签
print("\n采样点中包含的标签:", np.unique(final_sampled_data[:, 3]))

示例输出(部分):

最终采样数据形状: (108, 4)

前5个采样点:
 [[0.  0.  0.  1. ]
 [0.  0.  0.5 1. ]
 [0.  0.  1.  1. ]
 [0.  0.5 0.  1. ]
 [0.  0.5 0.5 1. ]]

后5个采样点:
 [[10.5 11.5 10.5 2. ]
 [10.5 11.5 11.  2. ]
 [10.5 12.  10.  2. ]
 [10.5 12.  10.5 2. ]
 [10.5 12.  11.  2. ]]

采样点中包含的标签: [1. 2.]

5. 注意事项与最佳实践

  1. np.mgrid的步长行为: start:stop:step 语法生成的序列不包含 stop 值。这意味着如果你的盒子边界正好是max_x,那么max_x本身不会被采样到。如果需要包含max_x,可以考虑将max_x稍微增大一个极小值(例如max_x + epsilon),或者使用np.linspace来精确控制点数并包含端点。但在大多数均匀采样场景中,不包含终点是可接受的。
  2. 浮点数精度: 由于step_size是浮点数,浮点运算可能导致精度问题。在某些情况下,这可能会导致边界点采样行为的微小差异。
  3. 标签一致性: 本教程假设每个盒子的所有顶点都具有相同的标签。在实际应用中,请确保你的数据结构符合这一假设,或者相应地调整标签提取逻辑。
  4. 内存消耗: 对于非常大或非常小的step_size,

相关专题

更多
python开发工具
python开发工具

php中文网为大家提供各种python开发工具,好的开发工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。php中文网还为大家带来python相关课程以及相关文章等内容,供大家免费下载使用。

760

2023.06.15

python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

639

2023.07.20

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

762

2023.07.25

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

619

2023.07.31

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

1285

2023.08.03

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

549

2023.08.04

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

579

2023.08.04

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

709

2023.08.11

微信聊天记录删除恢复导出教程汇总
微信聊天记录删除恢复导出教程汇总

本专题整合了微信聊天记录相关教程大全,阅读专题下面的文章了解更多详细内容。

36

2026.01.18

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 4.7万人学习

Django 教程
Django 教程

共28课时 | 3.2万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号