You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Open3D实现实心体素化并将.obj转为NumPy数组?

解决方案:基于Open3D CUDA加速的实心体素化

问题分析

你当前的代码仅生成了网格表面的空心体素,因为VoxelGrid.create_from_triangle_mesh只会标记与网格三角面相交的体素。要实现实心体素填充,需要批量判断每个体素是否处于网格内部,同时利用Open3D的CUDA加速能力避免循环操作。

前置准备

确保安装带CUDA支持的Open3D版本:

pip install open3d-cuda

完整代码实现

import open3d as o3d
import numpy as np

# 1. 加载并预处理网格(确保闭合,避免填充错误)
mesh = o3d.io.read_triangle_mesh('path/to/file.obj')
mesh.compute_vertex_normals()

# 修复网格缺陷(可选但推荐)
if not mesh.is_closed():
    mesh = mesh.remove_duplicated_vertices()
    mesh = mesh.remove_degenerate_triangles()
    mesh = mesh.fill_holes()

# 2. 定义体素参数与网格边界
voxel_size = 0.01
bbox = mesh.get_axis_aligned_bounding_box()
min_bound, max_bound = bbox.min_bound, bbox.max_bound

# 计算体素网格尺寸
grid_size = ((max_bound - min_bound) / voxel_size).astype(int) + 1

# 生成所有体素的中心坐标(批量生成,无循环)
x = np.linspace(min_bound[0] + voxel_size/2, max_bound[0] - voxel_size/2, grid_size[0])
y = np.linspace(min_bound[1] + voxel_size/2, max_bound[1] - voxel_size/2, grid_size[1])
z = np.linspace(min_bound[2] + voxel_size/2, max_bound[2] - voxel_size/2, grid_size[2])
xx, yy, zz = np.meshgrid(x, y, z, indexing='ij')
voxel_centers = np.stack([xx.ravel(), yy.ravel(), zz.ravel()], axis=1)

# 3. CUDA加速的内部点判断(射线投射法)
# 创建CUDA射线投射场景
scene = o3d.t.geometry.RaycastingScene()
mesh_tensor = o3d.t.geometry.TriangleMesh.from_legacy(mesh)
scene.add_triangles(mesh_tensor)

# 生成批量射线:体素中心为起点,沿X轴正方向发射
rays = np.concatenate([voxel_centers, np.tile([1.0, 0.0, 0.0], (voxel_centers.shape[0], 1))], axis=1)
rays_tensor = o3d.core.Tensor(rays, dtype=o3d.core.Dtype.Float32)

# 执行射线投射,统计交点数量
cast_result = scene.cast_rays(rays_tensor)
hit_counts = cast_result['primitive_ids'].shape[1] - np.sum(cast_result['primitive_ids'] == -1, axis=1)
is_inside = hit_counts % 2 == 1  # 奇偶规则判断内部点

# 4. 生成实心体素数组并保存
voxel_array = np.zeros(grid_size, dtype=np.uint16)
voxel_array[xx.ravel(), yy.ravel(), zz.ravel()] = is_inside.astype(np.uint16) * 1

# 保存为.npy
np.save('path/to/file_solid.npy', voxel_array)

# 可选:保存为nii.gz(医学CT格式)
import nibabel as nib
# 调整坐标系以匹配医学图像规范(按需修改)
voxel_nii = np.transpose(voxel_array, (2, 1, 0))
affine = np.diag([voxel_size, voxel_size, voxel_size, 1])
nib.save(nib.Nifti1Image(voxel_nii, affine), 'path/to/file_solid.nii.gz')

关键说明

  • CUDA加速核心:使用o3d.t.geometry.RaycastingScene实现批量射线投射,所有计算在GPU上完成,避免Python循环的性能瓶颈。
  • 内部点判断逻辑:利用射线与网格交点数量的奇偶性(奇数表示点在封闭网格内部),这是计算机图形学中判断点是否在多边形/网格内部的经典方法。
  • 网格预处理:修复网格的孔洞、重复顶点等缺陷,确保内部填充的准确性。

内容的提问来源于stack exchange,提问作者adamW

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 09:53:18