Remove the outlier points in the point cloud. Currently, it removes points that have few neighbors in a given sphere around them. Args: radius: the radius of the sphere min_num_points_in_radius: minimum number of point
(
self,
radius: float,
min_num_points_in_radius: int,
printout: bool = False,
)
| 588 | return point_cloud |
| 589 | |
| 590 | def remove_outlier( |
| 591 | self, |
| 592 | radius: float, |
| 593 | min_num_points_in_radius: int, |
| 594 | printout: bool = False, |
| 595 | ) -> 'PointCloud': |
| 596 | """ |
| 597 | Remove the outlier points in the point cloud. |
| 598 | Currently, it removes points that have few neighbors in a given sphere around them. |
| 599 | |
| 600 | Args: |
| 601 | radius: |
| 602 | the radius of the sphere |
| 603 | min_num_points_in_radius: |
| 604 | minimum number of points within the sphere to consider a point as inlier |
| 605 | |
| 606 | Returns: |
| 607 | self, with the valid_mask modified |
| 608 | """ |
| 609 | if radius is None or radius < 0 or min_num_points_in_radius is None or min_num_points_in_radius < 0: |
| 610 | return self |
| 611 | |
| 612 | # make sure valid mask is not None |
| 613 | self.realize_valid_mask() |
| 614 | |
| 615 | if printout: |
| 616 | print('Removing outlier points:', flush=True) |
| 617 | # we use the raw xyz_w instead of the o3d_pcd, so the index mapping is easy |
| 618 | for ib in range(self.xyz_w.size(0)): |
| 619 | xyz_w = self.xyz_w[ib] # (n, 3) |
| 620 | if self.included_point_at_inf: |
| 621 | xyz_w = xyz_w[1:] # (n, 3) |
| 622 | idx_offset = 1 |
| 623 | else: |
| 624 | idx_offset = 0 |
| 625 | |
| 626 | xyz_w = xyz_w.detach().cpu().numpy() |
| 627 | o3d_pcd = o3d.geometry.PointCloud() |
| 628 | o3d_pcd.points = o3d.utility.Vector3dVector(xyz_w) # (n, 3) |
| 629 | |
| 630 | cleaned_o3d_pcd, valid_idxs = o3d_pcd.remove_radius_outlier( |
| 631 | nb_points=min_num_points_in_radius, |
| 632 | radius=radius |
| 633 | ) # valid_idxs contains the list of valid index in o3d_pcd |
| 634 | |
| 635 | invalid_mask = torch.ones(self.xyz_w.size(1), dtype=torch.bool) |
| 636 | for idx in valid_idxs: |
| 637 | invalid_mask[idx + idx_offset] = 0 |
| 638 | invalid_mask = invalid_mask.to(device=self.valid_mask.device) |
| 639 | |
| 640 | # mark the valid_mask |
| 641 | self.valid_mask[ib, invalid_mask, :] = 0 |
| 642 | |
| 643 | if printout: |
| 644 | print( |
| 645 | f' ({ib}): removed {xyz_w.shape[0] - len(valid_idxs)} / {xyz_w.shape[0]}' |
| 646 | f' = {(xyz_w.shape[0] - len(valid_idxs)) / xyz_w.shape[0] * 100.:.2f}% points', |
| 647 | flush=True, |
no test coverage detected