一、代码
Python
import open3d as o3d
import numpy as npdef extract_points(point_cloud, salient_radius=5, non_max_radius=5, gamma_21=0.95, gamma_32=0.95, min_neighbors=6):keypoints = o3d.geometry.keypoint.compute_iss_keypoints(point_cloud,salient_radius=salient_radius,non_max_radius=non_max_radius,gamma_21=gamma_21,gamma_32=gamma_32,min_neighbors=min_neighbors)return keypointsdef view_show(point1, point2):# 关键点绿色point1.paint_uniform_color([0, 1, 0])# 点云红色point2.paint_uniform_color([1, 0, 0])# 可视化方法1# 可视化关键点和原始点云# o3d.visualization.draw_geometries([point1, point2],# window_name="ISS",# point_show_normal=True,# mesh_show_back_face=True)# 可视化方法2vis = o3d.visualization.Visualizer()vis.create_window(window_name="FPFH", width=1200, height=1200)# 设置背景颜色vis.get_render_option().background_color = [0, 0, 0] # 白色背景# 添加点云到Visualizervis.add_geometry(point1)vis.add_geometry(point2)# 运行可视化循环vis.run()vis.destroy_window()if __name__ == "__main__":# 读取点云scene = o3d.io.read_point_cloud("data/pig_view1.pcd")target = o3d.io.read_point_cloud("data/pig_view2.pcd")view_show(scene, target)# 法线scene.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.5, max_nn=100))target.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.5, max_nn=100))# 使用ISS关键点检测算法keypoints_scene = extract_points(scene)keypoints_target = extract_points(target)# 打印关键点个数print(f"scene点的个数:{len(scene.points)}")print(f"keypoints_scene点的个数:{len(keypoints_scene.points)}")print(f"target点的个数:{len(target.points)}")print(f"keypoints_target点的个数:{len(keypoints_target.points)}")source_fpfh = o3d.pipelines.registration.compute_fpfh_feature(keypoints_scene,o3d.geometry.KDTreeSearchParamHybrid(radius=0.5, max_nn=100))target_fpfh = o3d.pipelines.registration.compute_fpfh_feature(keypoints_target,o3d.geometry.KDTreeSearchParamHybrid(radius=0.5, max_nn=100))reg_p = o3d.pipelines.registration.registration_ransac_based_on_feature_matching(source=keypoints_scene,target=keypoints_target,source_feature=source_fpfh,target_feature=target_fpfh,mutual_filter=False, # 确保双向过滤以提高匹配质量max_correspondence_distance=40, # 确保这个阈值是合理的,根据你的点云的尺度来调整estimation_method=o3d.pipelines.registration.TransformationEstimationPointToPoint(False),ransac_n=3, # 使用默认值即可checkers=[ # 根据需要调整对应检查器# o3d.pipelines.registration.CorrespondenceCheckerBasedOnEdgeLength(0.8),o3d.pipelines.registration.CorrespondenceCheckerBasedOnDistance(90)],criteria=o3d.pipelines.registration.RANSACConvergenceCriteria(9000000, 0.999))print(reg_p.transformation)keypoints_scene.transform(reg_p.transformation)# 可视化配准结果view_show(keypoints_scene, keypoints_target)
关键代码解析:
scene.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.5, max_nn=100))target.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.5, max_nn=100))
-
radius
(半径):定义在估算法向量时用于搜索邻近点的半径。对于每个点,算法将在以该点为中心、半径为radius
的球体内搜索其他点。如果点云的密度较大,你可能需要选择较小的半径,以确保只考虑附近的点。如果点云的密度较小,你可能需要选择较大的半径,以确保找到足够的邻近点用于法向量估计。 -
max_nn
(最大邻近点数):定义在搜索中考虑的最大邻近点数量。对于每个点,算法将找到最多max_nn
个邻近点,并使用它们来估计法向量。选择适当的邻近点数量取决于点云的性质和应用场景。如果点云比较密集,你可能需要较大的值,而在点云比较稀疏的情况下,可以选择较小的值。
source_fpfh = o3d.pipelines.registration.compute_fpfh_feature(keypoints_scene,o3d.geometry.KDTreeSearchParamHybrid(radius=0.05, max_nn=100))target_fpfh = o3d.pipelines.registration.compute_fpfh_feature(keypoints_target,o3d.geometry.KDTreeSearchParamHybrid(radius=0.05, max_nn=100))
-
keypoints_scene
和keypoints_target
:这是两个输入点云中提取的关键点的集合。通常,在计算点云特征时,为了降低计算复杂度,会选择提取一些具有代表性的点作为关键点。这些关键点通常是点云中的显著特征点。 -
o3d.geometry.KDTreeSearchParamHybrid
:这是用于构建KD树以进行最近邻搜索的参数对象。这里的radius
和max_nn
参数影响了在计算FPFH特征时考虑的邻域范围和最大邻近点数。-
radius
(半径):定义了在计算FPFH特征时用于搜索邻域点的半径。只有距离小于半径的点才会被考虑在内。选择适当的半径与你的数据集和任务有关。较小的半径可以更细致地捕捉局部几何结构,但也可能更敏感于噪声;较大的半径可以平滑局部结构,但可能忽略小尺度的特征。 -
max_nn
(最大邻近点数):定义在搜索中考虑的最大邻近点数量。选择适当的最大邻近点数取决于点云的密度和特征的复杂性。较大的值可以捕获更丰富的局部信息,但也增加了计算成本。
-
reg_p = o3d.pipelines.registration.registration_ransac_based_on_feature_matching(source=keypoints_scene,target=keypoints_target,source_feature=source_fpfh,target_feature=target_fpfh,mutual_filter=False, # 确保双向过滤以提高匹配质量max_correspondence_distance=40, # 确保这个阈值是合理的,根据你的点云的尺度来调整estimation_method=o3d.pipelines.registration.TransformationEstimationPointToPoint(False),ransac_n=3, # 使用默认值即可checkers=[ # 根据需要调整对应检查器# o3d.pipelines.registration.CorrespondenceCheckerBasedOnEdgeLength(0.8),o3d.pipelines.registration.CorrespondenceCheckerBasedOnDistance(90)],criteria=o3d.pipelines.registration.RANSACConvergenceCriteria(9000000, 0.999))
-
source
和target
:分别是源点云和目标点云,用于进行配准的两个点云。 -
source_feature
和target_feature
:分别是源点云和目标点云的特征,通常是通过FPFH等方法计算得到的局部特征描述子。 -
mutual_filter
:一个布尔值,指定是否进行双向过滤以提高匹配质量。如果设置为True,将考虑源点云到目标点云和目标点云到源点云的匹配,以减少错误匹配。 -
max_correspondence_distance
:最大对应距离,用于过滤不合格的匹配对。只有距离小于该阈值的匹配才会被认为是有效的。该值的设置应根据点云的尺度来调整,确保它适当地覆盖了预期的点云之间的距离。 -
estimation_method
:指定了用于估计变换的方法。在这里,TransformationEstimationPointToPoint(False)
表示使用点到点的变换估计方法。该参数影响了配准的精度和速度。 -
ransac_n
:RANSAC算法中随机抽样的次数。在大多数情况下,使用默认值即可。 -
checkers
:一个列表,包含用于过滤匹配对的检查器。在这里,CorrespondenceCheckerBasedOnDistance(90)
指定了一个基于距离的检查器,它将过滤掉距离大于90的匹配对。你可以根据需要添加其他检查器或调整参数。 -
criteria
:RANSAC算法的收敛标准。RANSACConvergenceCriteria
指定了RANSAC迭代的最大迭代次数和收敛阈值。在这里,它设置为最大迭代次数为9000000,收敛阈值为0.999。这些值可能需要根据你的数据集和配准的要求进行调整。
结果:
配准前
配准后,改了很多次参数,感觉效果依然很差