本文档介绍如何使用PPF (Point Pair Feature) 表面匹配库的Python接口进行3D物体识别和姿态估计。
This document describes how to use the Python interface of the PPF (Point Pair Feature) surface matching library for 3D object recognition and pose estimation.
cd python
./install.shcd python
pip install -e .cd python
pip install -r requirements.txt
mkdir build && cd build
cmake .. -DPYTHON_EXECUTABLE=$(which python)
make -j$(nproc)
cd ..
cp build/ppf.so .from ppf_wrapper import PPFMatcher, PointCloud
# 加载模型和场景
# Load model and scene
model = PointCloud.from_file("model.ply")
scene = PointCloud.from_file("scene.ply")
# 创建匹配器并训练模型
# Create matcher and train model
matcher = PPFMatcher()
matcher.train_model(model, sampling_distance_rel=0.025)
# 执行匹配
# Execute matching
matches = matcher.match_scene(
scene,
sampling_distance_rel=0.025,
key_point_fraction=0.1,
min_score=0.1,
num_matches=5
)
# 处理结果
# Process results
for i, (pose, score) in enumerate(matches):
print(f"匹配 {i+1}: 分数 = {score:.4f}")
print("姿态矩阵:")
print(pose)用于表示3D点云数据。 Used to represent 3D point cloud data.
# 从PLY文件加载
# Load from PLY file
pc = PointCloud.from_file("model.ply")
# 从NumPy数组创建
# Create from NumPy array
import numpy as np
points = np.random.rand(1000, 3).astype(np.float32) # Nx3点坐标 / point coordinates
normals = np.random.rand(1000, 3).astype(np.float32) # Nx3法向量(可选) / normals (optional)
pc = PointCloud.from_numpy(points, normals)# 基本属性
# Basic properties
print(f"点数: {pc.num_points}")
print(f"是否有法向量: {pc.has_normals}")
# 设置视点(用于法向量计算)
# Set viewpoint (for normal computation)
pc.set_view_point(x, y, z)
# 保存到文件
# Save to file
pc.save("output.ply")
# 转换为NumPy数组
# Convert to NumPy array
points, normals = pc.to_numpy()主要的匹配器类,用于训练模型和执行匹配。 The main matcher class for training models and performing matching.
matcher = PPFMatcher()
# 基本训练
# Basic training
matcher.train_model(model, sampling_distance_rel=0.025)
# 自定义训练参数
# Custom training parameters
matcher.train_model(
model,
sampling_distance_rel=0.025, # 采样距离(相对于物体直径) / Sampling distance (relative to object diameter)
feat_distance_step_rel=0.04, # 特征距离步长 / Feature distance step
feat_angle_resolution=30, # 特征角度分辨率 / Feature angle resolution
pose_ref_rel_sampling_distance=0.01, # 姿态精化采样距离 / Pose refinement sampling distance
knn_normal=10, # 法向量估计的最近邻数 / KNN for normal estimation
smooth_normal=True # 是否平滑法向量 / Whether to smooth normals
)# 基本匹配
# Basic matching
matches = matcher.match_scene(scene)
# 自定义匹配参数
# Custom matching parameters
matches = matcher.match_scene(
scene,
sampling_distance_rel=0.025, # 场景采样距离 / Scene sampling distance
key_point_fraction=0.1, # 关键点比例 / Key point fraction
min_score=0.1, # 最小分数 / Minimum score
num_matches=5, # 最大匹配数 / Maximum number of matches
knn_normal=10, # 法向量估计的最近邻数 / KNN for normal estimation
smooth_normal=True, # 是否平滑法向量 / Whether to smooth normals
invert_normal=False, # 是否反转法向量 / Whether to invert normals
max_overlap_dist_rel=0.5, # 最大重叠距离 / Maximum overlap distance
sparse_pose_refinement=True, # 稀疏姿态精化 / Sparse pose refinement
dense_pose_refinement=True, # 密集姿态精化 / Dense pose refinement
pose_ref_num_steps=5, # 姿态精化步数 / Pose refinement steps
pose_ref_dist_threshold_rel=0.1, # 姿态精化距离阈值 / Pose refinement distance threshold
pose_ref_scoring_dist_rel=0.01 # 评分距离阈值 / Scoring distance threshold
)# 保存训练好的模型
# Save trained model
matcher.save_model("trained_model.ppf")
# 加载预训练模型
# Load pre-trained model
new_matcher = PPFMatcher()
new_matcher.load_model("trained_model.ppf")from ppf_wrapper import transform_pointcloud, sample_mesh, compute_bounding_box
# 变换点云
# Transform point cloud
transformed = transform_pointcloud(pc, pose_matrix, use_normal=True)
# 采样网格
# Sample mesh
sampled = sample_mesh(pc, radius=0.01)
# 计算边界框
# Compute bounding box
min_point, max_point = compute_bounding_box(pc)#!/usr/bin/env python3
import numpy as np
from ppf_wrapper import PPFMatcher, PointCloud, transform_pointcloud
def main():
# 加载数据
# Load data
model = PointCloud.from_file("gear.ply")
scene = PointCloud.from_file("gear_n35.ply")
# 设置视点
# Set viewpoint
model.set_view_point(620, 100, 500)
scene.set_view_point(-200, -50, -500)
# 训练和匹配
# Train and match
matcher = PPFMatcher()
matcher.train_model(model, sampling_distance_rel=0.025)
matches = matcher.match_scene(
scene,
sampling_distance_rel=0.025,
key_point_fraction=0.1,
min_score=0.1,
num_matches=5
)
print(f"找到 {len(matches)} 个匹配:")
for i, (pose, score) in enumerate(matches):
print(f"匹配 {i+1}: 分数 = {score:.4f}")
# 保存变换后的模型
# Save transformed model
transformed = transform_pointcloud(model, pose)
transformed.save(f"result_{i+1}.ply")
if __name__ == "__main__":
main()- 值范围 / Value Range: 0.01 - 0.1
- 默认值 / Default: 0.04
- 说明 / Description: 相对于物体直径的采样距离 / Sampling distance relative to object diameter
- 建议 / Recommendations:
- 小物体使用较小值 (0.02-0.03) / Use smaller values for small objects
- 大物体使用较大值 (0.05-0.08) / Use larger values for large objects
- 噪声大的数据使用较大值 / Use larger values for noisy data
- 值范围 / Value Range: 0.05 - 0.5
- 默认值 / Default: 0.2
- 说明 / Description: 场景中用作关键点的点比例 / Fraction of points used as key points in the scene
- 建议 / Recommendations:
- 快速匹配使用较小值 (0.05-0.1) / Use smaller values for fast matching
- 精确匹配使用较大值 (0.2-0.3) / Use larger values for accurate matching
- 值范围 / Value Range: 0.0 - 1.0
- 默认值 / Default: 0.2
- 说明 / Description: 返回姿态的最小分数阈值 / Minimum score threshold for returned poses
- 建议 / Recommendations:
- 噪声大的数据降低阈值 (0.1-0.15) / Lower threshold for noisy data
- 清洁数据可以提高阈值 (0.3-0.4) / Higher threshold for clean data
# 对大点云进行采样
# Sample large point clouds
sampled_model = sample_mesh(model, radius=0.01)
sampled_scene = sample_mesh(scene, radius=0.01)
# 使用采样后的数据进行匹配
# Use sampled data for matching
matcher.train_model(sampled_model)
matches = matcher.match_scene(sampled_scene)# 训练并保存模型
# Train and save model
matcher = PPFMatcher()
matcher.train_model(model)
matcher.save_model("cached_model.ppf")
# 后续使用时直接加载
# Load directly for subsequent use
matcher = PPFMatcher()
matcher.load_model("cached_model.ppf")PPF库自动使用OpenMP进行并行处理,无需额外配置。 The PPF library automatically uses OpenMP for parallel processing, no additional configuration needed.
# 如果点云没有法向量,可以手动计算
# If point cloud has no normals, compute manually
if not model.has_normals:
# 设置合适的视点
# Set appropriate viewpoint
model.set_view_point(620, 100, 500)
# 库会自动计算法向量
# Library will automatically compute normals-
导入错误 Import Error
ImportError: No module named 'ppf'解决 / Solution: 确保已正确构建并复制了ppf.so文件 / Ensure ppf.so is properly built and copied
-
文件未找到 File Not Found
FileNotFoundError: Failed to load PLY file解决 / Solution: 检查文件路径是否正确,确保文件存在 / Check file path and ensure file exists
-
内存不足 Insufficient Memory
MemoryError解决 / Solution: 增加采样距离或使用采样函数减少点数 / Increase sampling distance or use sampling function to reduce points
-
匹配结果为空 Empty Matching Results
Found 0 matches解决 / Solution:
- 降低min_score阈值 / Lower min_score threshold
- 增加key_point_fraction / Increase key_point_fraction
- 检查数据质量和法向量 / Check data quality and normals
本项目遵循与原始Surface Match库相同的许可证。 This project follows the same license as the original Surface Match.
感谢SurfaceMan的开源! 欢迎提交问题和优化改进!