isl-org / Open3D

Open3D: A Modern Library for 3D Data Processing
http://www.open3d.org
Other
11.17k stars 2.27k forks source link

How can PointCloud Registration be run deterministically? #6225

Open dalnoguer opened 1 year ago

dalnoguer commented 1 year ago

Checklist

My Question

Hello,

I am running pointcloud registration in two steps. First I get an initial estimate using ransac:

        distance_threshold = self.voxel_size * 1.5
        self.logger.info(":: RANSAC registration on downsampled point clouds.")
        self.logger.info(f"Since the downsampling voxel size is {self.voxel_size},")
        self.logger.info(f"we use a liberal distance threshold {distance_threshold}.")

        source_down, source_fpfh = self.extract_FPFH(source_pcd)
        target_down, target_fpfh = self.extract_FPFH(target_pcd)

        result = o3d.pipelines.registration.registration_ransac_based_on_feature_matching(
            source_down, target_down, source_fpfh, target_fpfh, True,
            distance_threshold,
            o3d.pipelines.registration.TransformationEstimationPointToPoint(False),
            3, [
                o3d.pipelines.registration.CorrespondenceCheckerBasedOnEdgeLength(
                    0.9),
                o3d.pipelines.registration.CorrespondenceCheckerBasedOnDistance(
                    distance_threshold)
            ], o3d.pipelines.registration.RANSACConvergenceCriteria(
                self.ransac_iter, self.conf_prob),
            seed=0,
        )

Then, I refine the estimate using ICP:

        initial_guess = result.transformation
        distance_threshold = self.voxel_size * 0.4
        radius_normal = self.voxel_size * 2

        # Convergence-Criteria for Vanilla ICP
        criteria = o3d.pipelines.registration.ICPConvergenceCriteria(
            relative_fitness=0.000001,
            relative_rmse=0.000001,
            max_iteration=self.icp_iter
        )

        self.logger.info(":: ICP registration is applied on original point")
        self.logger.info("   clouds to refine the alignment. This time we use a strict")
        self.logger.info(f"   distance threshold {distance_threshold}.")
        if self.method == "p2p":
            self.logger.info(":: Running ICP with p2p")
            reg_p2p = o3d.pipelines.registration.registration_icp(
                source_pcd,
                target_pcd,
                distance_threshold,
                initial_guess,
                o3d.pipelines.registration.TransformationEstimationPointToPoint(),
                o3d.pipelines.registration.ICPConvergenceCriteria(max_iteration=self.icp_iter),
            )
        elif self.method == "p2plane":
            self.logger.info(":: Running ICP with p2plane")
            source_pcd.estimate_normals(
                o3d.geometry.KDTreeSearchParamHybrid(radius=radius_normal, max_nn=30))
            target_pcd.estimate_normals(
                o3d.geometry.KDTreeSearchParamHybrid(radius=radius_normal, max_nn=30))
            reg_p2p = o3d.pipelines.registration.registration_icp(
                source_pcd, target_pcd, distance_threshold,
                initial_guess,
                o3d.pipelines.registration.TransformationEstimationPointToPlane(),
                criteria)
        else:
            raise ValueError(f"Registration method {self.method} not implemented.")

I have seen that in this #3737 the seed should have been added to the method, but it is not the case.

What do you propose? I would need a deterministic method to align pointclouds.

Thanks!

eriksandstroem commented 10 months ago

Also interested in this.