3D超点(3D Superpoint)概念解释与代码实现
超点概念解释:
3D Superpoint起源于Large-scale Point Cloud Semantic Segmentation with Superpoint Graphs(2017年)这篇论文。
论文中对Superpoint的定义为:geometrically simple yet meaningful shapes。Superpoint的划分是默认Superpoint内的点都是属于同一个物体类别的
3D Superpoint的核心思想就是把初始的数量非常多的点云根据其邻近的几何信息给划分成更大的point patch,每个大的point patch就叫做一个超点(3D Superpoint)
超点的划分基于局部的linearity,planarity,scattering,verticality,elevation的信息:
得到点云的超点的代码实现:
一般使用segmentator库来实现3D点云的超点划分,输入需要xyz和mesh的信息,如果不包含mesh信息,则需要先生成mesh信息,再用segmentator得到超点
segmentator库安装:
segmentator库地址:
https://github.com/Karbo123/segmentator?tab=readme-ov-filehttps://github.com/Karbo123/segmentator?tab=readme-ov-file创建环境:
conda create --name segmentator -y python=3.8
在cmake的下面插入这两行来避免compile时nvcc版本的问题:
-DCMAKE_CUDA_COMPILER=/usr/local/cuda-12.1/bin/nvcc \
-DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-12.1 \
cd csrc && mkdir build && cd buildcmake .. \
-DCMAKE_CUDA_COMPILER=/usr/local/cuda-12.1/bin/nvcc \
-DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-12.1 \
-DCMAKE_PREFIX_PATH=`python -c 'import torch;print(torch.utils.cmake_prefix_path)'` \
-DPYTHON_INCLUDE_DIR=$(python -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())") \
-DPYTHON_LIBRARY=$(python -c "import distutils.sysconfig as sysconfig; print(sysconfig.get_config_var('LIBDIR'))") \
-DCMAKE_INSTALL_PREFIX=`python -c 'from distutils.sysconfig import get_python_lib; print(get_python_lib())'` \
-DCMAKE_PREFIX_PATH=`python -c 'import torch;print(torch.utils.cmake_prefix_path)'` \
-DPYTHON_INCLUDE_DIR=$(python -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())") \
-DPYTHON_LIBRARY=$(python -c "import distutils.sysconfig as sysconfig; print(sysconfig.get_config_var('LIBDIR'))") \
-DCMAKE_INSTALL_PREFIX=`python -c 'from distutils.sysconfig import get_python_lib; print(get_python_lib())'` \
-DCMAKE_CXX_STANDARD=17 \
-DCMAKE_CXX_STANDARD_REQUIRED=ON \
-DCMAKE_CXX_EXTENSIONS=OFF \
-DCMAKE_CUDA_STANDARD=17 \
-DCMAKE_CUDA_STANDARD_REQUIRED=ON \
-DCMAKE_CUDA_EXTENSIONS=OFFmake && make install # after install, please do not delete this folder (as we only create a symbolic link)
如果碰到报错:#error You need C++17 to compile PyTorch,用以下方式解决:
1️⃣ 在 CMakeLists.txt
中全局设置 C++17:
在项目根目录 CMakeLists.txt
顶部加:
# 强制主 C++ 编译器使用 C++17
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)# 强制 CUDA 编译器使用 C++17
set(CMAKE_CUDA_STANDARD 17)
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
set(CMAKE_CUDA_EXTENSIONS OFF)
再运行即可成功安装
由3D点云生成mesh:
对于没有mesh的点云,需要额外先生成mesh
运行以下代码即可:
import open3d as o3d
import trimesh
import numpy as np# -----------------------------
# 参数
# -----------------------------
PLY_PATH = "/data/xxx/projects/colmap/mycolmap_project/dense/fused.ply"
MESH_OUTPUT_PATH = "/data/xxx/projects/colmap/mycolmap_project/dense/fused_mesh.ply" # 生成网格文件# -----------------------------
# 1. 读取点云
# -----------------------------
pcd = o3d.io.read_point_cloud(PLY_PATH)# 如果点云没有法线,估计法线
if not pcd.has_normals():print("Estimating normals...")pcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamKNN(knn=30))# -----------------------------
# 2. Poisson 网格重建
# -----------------------------
print("Performing Poisson surface reconstruction...")
mesh_o3d, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pcd, depth=9
)# 可选:去掉低密度三角形(噪声)
densities = np.asarray(densities)
faces_to_keep = densities > np.percentile(densities, 5)
mesh_o3d = mesh_o3d.select_by_index(np.where(faces_to_keep)[0], cleanup=True)# -----------------------------
# 3. 保存网格文件
# -----------------------------
o3d.io.write_triangle_mesh(MESH_OUTPUT_PATH, mesh_o3d)
print(f"Mesh saved to: {MESH_OUTPUT_PATH}")# -----------------------------
# 4. 测试 trimesh 读取
# -----------------------------
mesh_trimesh = trimesh.load_mesh(MESH_OUTPUT_PATH)
print(f"Mesh loaded: vertices={len(mesh_trimesh.vertices)}, faces={len(mesh_trimesh.faces)}")
生成mesh的速度还是比较慢的
生成的ply文件:
打印出顶点和面的信息:
顶点和面的文件格式解释如下:
mesh可视化:
细节展示:
生成superpoint:
生成superpoint的代码
使用以下python代码:segmentator/get_superpoint.py
import trimesh
import numpy as np
from segmentator import segment_mesh, segment_point, compute_vn
import trimesh
import torch
import matplotlib.pyplot as pltMESH_PATH = "/data/xxx/projects/colmap/mycolmap_project/dense/fused_mesh.ply" # here is the path to your triangle mesh
mesh = trimesh.load_mesh(MESH_PATH)# segment on mesh
vertices = torch.from_numpy(mesh.vertices.astype(np.float32))
faces = torch.from_numpy(mesh.faces.astype(np.int64))
ind = segment_mesh(vertices, faces)
color_table = torch.randint(0, 256, size=(1 + ind.max(), 3))
np.savetxt("result_pc_mesh.txt", torch.cat([vertices, color_table[ind]], dim=1).numpy())# segment on pointcloud
normals = torch.from_numpy(compute_vn(mesh).astype(np.float32))
edges = torch.from_numpy(mesh.edges.astype(np.int64)) # NOTE the edges can actually be obtained from knn graph or radius graph
ind = segment_point(vertices, normals, edges)
# 最终生成的是点xyz和对应的rgb颜色n_classes = int(ind.max()) + 1
colors = (plt.cm.tab20(np.linspace(0, 1, n_classes))[:, :3] * 255).astype(np.uint8)
color_table = torch.tensor(colors)print("point number:", vertices.shape[0])
print("superpoint number:", len(ind.unique()))
np.savetxt("result_pc_point.txt", torch.cat([vertices, color_table[ind]], dim=1).numpy())
得到的数值结果:
point number: 45867
superpoint number: 344
superpoint划分的效果可视化:
使用代码:segmentator/viser_superpoint.py