Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How can PointCloud Registration be run deterministically? #6225

Open
3 tasks done
dalnoguer opened this issue Jun 22, 2023 · 2 comments
Open
3 tasks done

How can PointCloud Registration be run deterministically? #6225

dalnoguer opened this issue Jun 22, 2023 · 2 comments
Labels

Comments

@dalnoguer
Copy link

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
Copy link

Also interested in this.

@JaouadROS
Copy link

From what I understand from the history is that this PR #3737 was canceled by this one #5247. So instead of having the seed as an input parameter of the function, you can have it globally in your code by calling o3d.utility.random.seed(xxx);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants