""" ICP algorithm for point cloud registration. """ import copy import os import sys import time import open3d as o3d import numpy as np BASE_DIR = os.path.dirname(os.path.abspath(__file__)) sys.path.append(BASE_DIR) sys.path.append(os.path.join(BASE_DIR, '../lib')) from configs import FLAGS def preprocess_point_cloud(pcd, voxel_size): print(":: Downsample with a voxel size %.3f." % voxel_size) pcd_down = pcd.voxel_down_sample(voxel_size) radius_normal = voxel_size * 2 print(":: Estimate normal with search radius %.3f." % radius_normal) pcd_down.estimate_normals( o3d.geometry.KDTreeSearchParamHybrid(radius=radius_normal, max_nn=30)) radius_feature = voxel_size * 5 print(":: Compute FPFH feature with search radius %.3f." % radius_feature) pcd_fpfh = o3d.pipelines.registration.compute_fpfh_feature( pcd_down, o3d.geometry.KDTreeSearchParamHybrid(radius=radius_feature, max_nn=100)) return pcd_down, pcd_fpfh def prepare_dataset(s, t, voxel_size): print(":: Load two point clouds and disturb initial pose.") source = o3d.io.read_point_cloud(s) target = o3d.io.read_point_cloud(t) trans_init = np.asarray([[0.0, 0.0, 1.0, 0.0], [1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 0.0, 1.0]]) source.transform(trans_init) # draw_registration_result(source, target, np.identity(4)) source_down, source_fpfh = preprocess_point_cloud(source, voxel_size) target_down, target_fpfh = preprocess_point_cloud(target, voxel_size) return source, target, source_down, target_down, source_fpfh, target_fpfh def execute_fast_global_registration(source_down, target_down, source_fpfh, target_fpfh, voxel_size): distance_threshold = voxel_size * 0.5 print(":: Apply fast global registration with distance threshold %.3f" \ % distance_threshold) result = o3d.pipelines.registration.registration_fast_based_on_feature_matching( source_down, target_down, source_fpfh, target_fpfh, o3d.pipelines.registration.FastGlobalRegistrationOption( maximum_correspondence_distance=distance_threshold)) return result def icp(s_file, t_file): """ icp algorithm More point cloud registration algorithm: GICP: https://github.com/avsegal/gicp NICP: http://jacoposerafin.com/nicp/ :param s_file: source point cloud file :param t_file: target point cloud file :return: """ threshold = 0.02 # fast global registration print("Apply Fast global registration") voxel_size = 0.05 # means 5cm for this dataset source, target, source_down, target_down, source_fpfh, target_fpfh = prepare_dataset(s_file, t_file, voxel_size) start = time.time() result_fast = execute_fast_global_registration(source_down, target_down, source_fpfh, target_fpfh, voxel_size) print("Fast global registration took %.3f sec." % (time.time() - start)) print("trans_init: ") trans_init = result_fast.transformation print(trans_init) # point-to-point ICP print("Apply point-to-point ICP") reg_p2p = o3d.pipelines.registration.registration_icp( source, target, threshold, trans_init, o3d.pipelines.registration.TransformationEstimationPointToPoint(), o3d.pipelines.registration.ICPConvergenceCriteria(max_iteration=2000)) print(reg_p2p) print("Transformation is:") print(reg_p2p.transformation) if __name__ == "__main__": print("**********ICP**********") print("source file: ", FLAGS.s_file) print("target file: ", FLAGS.t_file) icp(FLAGS.s_file, FLAGS.t_file) print("***********************")