在Open3D中查找与体素相交且距体素中心最近的三角形
解决Open3D中查找体素中心最近三角形的问题
你的核心问题是误用了基于顶点的KD树——KDTreeFlann(mesh)默认用网格的顶点构建索引,所以返回的是最近顶点的ID,而非三角形ID。以下是两种可行的解决方案:
方案一:直接使用compute_closest_point_on_mesh(推荐)
Open3D的TriangleMesh内置了compute_closest_point_on_mesh方法,直接返回查询点到网格表面最近点的距离,以及该点所在的三角形索引,完全匹配你的需求。修改后的代码如下:
import open3d as o3d import numpy as np vertices = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]]) triangles = np.array([[0, 1, 2]]) mesh = o3d.geometry.TriangleMesh() mesh.vertices = o3d.utility.Vector3dVector(vertices) mesh.triangles = o3d.utility.Vector3iVector(triangles) # 体素中心示例 voxel_centers = np.array([[0.1, 0.1, 0.1], [0.5, 0.5, 0.5], [0.9, 0.9, 0.9]]) closest_triangles = [] for center in voxel_centers: # 直接获取最近点所在的三角形ID _, triangle_id = mesh.compute_closest_point_on_mesh(center) closest_triangles.append(triangle_id) closest_triangles = np.array(closest_triangles) print("Closest triangles") print(closest_triangles)
运行后输出为[0 0 0],符合你只有一个三角形的实际情况。
方案二:基于顶点KD树关联三角形索引(不推荐,仅作原理说明)
如果坚持要用KDTree,需要先建立顶点到所属三角形的映射,再对查询到的最近顶点,筛选其所属三角形并计算距离,最终选最近的那个。步骤如下:
import open3d as o3d import numpy as np from collections import defaultdict vertices = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]]) triangles = np.array([[0, 1, 2]]) mesh = o3d.geometry.TriangleMesh() mesh.vertices = o3d.utility.Vector3dVector(vertices) mesh.triangles = o3d.utility.Vector3iVector(triangles) # 构建顶点到三角形的映射字典 vertex_to_triangles = defaultdict(list) for tri_idx, tri in enumerate(mesh.triangles): for v_idx in tri: vertex_to_triangles[v_idx].append(tri_idx) voxel_centers = np.array([[0.1, 0.1, 0.1], [0.5, 0.5, 0.5], [0.9, 0.9, 0.9]]) kdtree = o3d.geometry.KDTreeFlann(mesh) closest_triangles = [] for center in voxel_centers: _, vertex_ids, _ = kdtree.search_knn_vector_3d(center, 1) v_idx = vertex_ids[0] # 获取该顶点所属的所有三角形 candidate_tris = vertex_to_triangles[v_idx] # 计算每个候选三角形到查询点的距离(用三角形重心距离) min_dist = float('inf') best_tri = -1 for tri_idx in candidate_tris: tri_verts = np.asarray(mesh.vertices)[np.asarray(mesh.triangles)[tri_idx]] centroid = np.mean(tri_verts, axis=0) dist = np.linalg.norm(centroid - center) if dist < min_dist: min_dist = dist best_tri = tri_idx closest_triangles.append(best_tri) closest_triangles = np.array(closest_triangles) print("Closest triangles") print(closest_triangles)
这种方法效率较低、逻辑复杂,仅在特殊场景下使用。
额外:筛选与体素相交的三角形
你的需求是“找到与给定体素相交且距离体素中心最近的三角形”,可以在获取最近三角形后,验证其是否与体素相交:
def triangle_intersects_voxel(tri_verts, voxel_aabb): # 获取三角形的AABB tri_aabb = o3d.geometry.AxisAlignedBoundingBox.create_from_points(o3d.utility.Vector3dVector(tri_verts)) # 判断两个AABB是否相交 return tri_aabb.intersects(voxel_aabb) # 假设体素边长为0.2,创建体素的AABB voxel_size = 0.2 valid_triangles = [] for idx, center in enumerate(voxel_centers): voxel_min = center - voxel_size/2 voxel_max = center + voxel_size/2 voxel_aabb = o3d.geometry.AxisAlignedBoundingBox(voxel_min, voxel_max) # 获取最近三角形的顶点 tri_idx = closest_triangles[idx] tri_verts = np.asarray(mesh.vertices)[np.asarray(mesh.triangles)[tri_idx]] if triangle_intersects_voxel(tri_verts, voxel_aabb): valid_triangles.append(tri_idx) else: # 若最近三角形不相交,可扩大搜索范围找其他相交三角形 pass
内容的提问来源于stack exchange,提问作者roymustang
相关产品推荐
相关产品推荐

