'Select remaining points after cropping a point cloud

I am currently facing a problem regarding point cloud cropping. More specifically, I already know how to crop a point cloud based on Open3D, a package for point cloud processing. There are several ways to do it, for example:

newCamView = np.hstack((camView, np.zeros(shape=camView.shape[0]).reshape(3,1)))
vol = o3d.visualization.SelectionPolygonVolume()
vol.bounding_polygon = o3d.utility.Vector3dVector(newCamView)
vol.orthogonal_axis = "Z"
vol.axis_max = 10 
vol.axis_min = -10 

pcd_cropped = vol.crop_point_cloud(pcd_raw)
pcd_final = np.asarray(np.hstack((pcd_cropped.points,pcd_cropped.colors)))

But in the context of my problem, I also need to extract the points outside the volume of interest. And even after studying the Open3D documentation and searching on the internet I can't find an answer.

I would be interested in some help to either find out how to invert the selection based on a cropping method or a way to extract the specific indexes of the points that lie within the bounding volume so that I can use the function select_by_index from o3d.geometry.PointCloud to get both inliers and outliers.



Solution 1:[1]

You can use the Point Cloud Distance for this task. The following code should give you the points outside the crop:

dists = np.asarray(pcd_raw.compute_point_cloud_distance(pcd_cropped))
indices = np.where(dists > 0.00001)[0]
pcd_cropped_inv = pcd_raw.select_by_index(indices)

Solution 2:[2]

Another method to crop pointcloud in open3d is using object of class bounding box. (So this method is only for rectangular shape and not for a polygon based cropping.)

Lets create an arbitrary bounding box with center at origin, a value below 1 as edge length, and rotation R.

R = np.identity(3)  
extent = np.ones(3)/1.5 # trying to create a bounding box below 1 unit
center = np.zeros(3) 
obb = o3d.geometry.OrientedBoundingBox(center,R,extent) # or you can use axis aligned bounding box class

Now you can crop your point cloud (pcd) by:

cropped = pcd.crop(obb)

o3d.visualization.draw_geometries([cropped]) #press ESC to close

To get indices of points inside this bounding box:

inliers_indices = obb.get_point_indices_within_bounding_box(pcd.points)
        
inliers_pcd = pcd.select_by_index(inliers_indices, invert=False) # select inside points = cropped 
outliers_pcd = pcd.select_by_index(inliers_indices, invert=True) #select outside points
    
o3d.visualization.draw_geometries([outliers_pcd])

If you already know the boundaries that you want to crop, you can create a bounding box like above and crop. Or if you want to crop w.r.t. the bounding box of another pointcloud/object (if you know pose, you can transform it and then compute bounding box of it) and use this bounding box to crop the larger point cloud. To get bounding box of point cloud:

obb = pcd.get_oriented_bounding_box(robust=False) #set robust =True for more robust computation.
aabb = pcd.get_axis_aligned_bounding_box()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 snwflk
Solution 2