'How to crop a point cloud in Open3D by using a polygon volume?

at first i have to say that I'm very new to programming, especially in Open3D. I'm trying to crop a point cloud, but not as shown in the Open3D tutorial with a *.json file, but rather with a polygon volume which i created by using 4 coordinates (corner points of the 2D bounding box). My code is shown below.

model = "point_cloud.ply"
pcd = o3d.io.read_point_cloud(model)
downpcd = pcd.voxel_down_sample(voxel_size = 0.015)

corners = np.array([
        [ -0.091687413867212741, -0.14071210477866827, 0.0 ],
        [ 0.030980770065893004, -0.14071210477866827, 0.0 ],
        [ 0.030980770065893004, -0.044064443478879611, 0.0 ],
        [ -0.091687413867212741, -0.044064443478879611, 0.0 ]
    ])

bounding_polygon = corners.astype("float64")

vol = o3d.visualization.SelectionPolygonVolume()
vol.orthogonal_axis = "Z"
vol.axis_max = 0.81700000000000017
vol.axis_min = -2.8580000000000001
vol.bounding_polygon = o3d.utility.Vector3dVector(bounding_polygon)

Up to this line everything seems to work fine, but when I'm trying to use this polygon volume to crop my loaded point cloud with this function I always recieve an error.

cropped_pcd = vol.crop_point_cloud([downpcd])

This is the error i get:

Traceback (most recent call last):
  File "c:\Users\Privat\Desktop\User\PCD\CropPCDByCoordinates.py", line 42, in <module>
    cropped_pcd = vol.crop_point_cloud([downpcd])
TypeError: crop_point_cloud(): incompatible function arguments. The following argument types are supported:
    1. (self: open3d.cpu.pybind.visualization.SelectionPolygonVolume, input: open3d.cpu.pybind.geometry.PointCloud) -> open3d.cpu.pybind.geometry.PointCloud

Invoked with: SelectionPolygonVolume, access its members:
orthogonal_axis, bounding_polygon, axis_min, axis_max, [PointCloud with 364980 points.]

When I'm using a *.json file with the same information everything works fine, but I would like to crop it without loading a *.json file.

This is the *.json file where i got my information from:

{
    "axis_max" : 0.81700000000000017,
    "axis_min" : -2.8580000000000001,
    "bounding_polygon" : 
    [
        [ -0.091687413867212741, -0.14071210477866827, 0.0 ],
        [ 0.030980770065893004, -0.14071210477866827, 0.0 ],
        [ 0.030980770065893004, -0.044064443478879611, 0.0 ],
        [ -0.091687413867212741, -0.044064443478879611, 0.0 ]
    ],
    "class_name" : "SelectionPolygonVolume",
    "orthogonal_axis" : "Z",
    "version_major" : 1,
    "version_minor" : 0

} 

Any advice and/or explanation how to avoid this error would be appreciated. Thanks.

I'm using Python 3.9 in MS Visual Studio Code on Windows 10.



Solution 1:[1]

Another method to crop pointcloud in open3d is using object of class bounding box (So this handles only rectangles and not a higher polygon).

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 SFA