bounding-boxopen3d

How to rotate oriented bounding box in Open3D


i'm trying to crop a PointCloud using an OrientedBoundingBox with the Open3D built-in method, the pcl is not orthogonal with the axis and I need to get a bounding parallel to the pcl, I tried to set the rotation matrix R of the bounding box but it is always created parallel to XY plane and orthogonal to Z axis, where am I wrong? this is my code

mesh_coord_frame = o3d.geometry.TriangleMesh.create_coordinate_frame(size=0.3, origin=[0, 0, 0.45])

##CREATE BOUNDING BOX FROM CENTER, EXTENSION AND ROTATION
oriented_bounding_box = o3d.geometry.OrientedBoundingBox(center=[0.0, 0.0, 0.65], extent=[0.10, 0.10, 0.02],
            R=[[np.cos(np.pi/4), 0, 0], [0, np.sin(np.pi/4), 0], [0, 0, 1]])
    
##CROP THE VOLUME IN THE BOUNDING BOX
point_cloud_crop = pcd.crop(oriented_bounding_box)

# View original point cloud with the cuboid, all 5 points present
o3d.visualization.draw_geometries([mesh_coord_frame, pcd, oriented_bounding_box])

# View cropped point cloud with the cuboid, only 3 points present
o3d.visualization.draw_geometries([mesh_coord_frame, point_cloud_crop, oriented_bounding_box])

Screenshot


Solution

  • Check how the rotation matrix looks like when doing rotation along 3 axes on the wikipedia.

    What you are using as rotation matrix is

    [
     [np.cos(np.pi/4), 0, 0], 
     [0, np.sin(np.pi/4), 0], 
     [0, 0, 1]
    ]   
    

    This when multiplied with any vector (x,y,z), will only scale down x value by np.cos(np.pi/4), y value by np.sin(np.pi/4) and keep z unchanged (multiplied by 1). This matrix is not a rotation matrix.

    Now, for rotation, you can generate rotation matrix as:-

    R = o3d.geometry.get_rotation_matrix_from_xyz((0, np.pi/4, np.pi/4))
    oriented_bounding_box = o3d.geometry.OrientedBoundingBox(
        center=[0.0, 0.0, 0.65],
        extent=[0.10, 0.10, 0.02],
        R=R
    )
    

    Another method useful for you will be finding oriented bounding box for your pointcloud.

    # Create an example pointcloud
    pcl:o3d.geometry.PointCloud = o3d.io.read_point_cloud(o3d.data.PLYPointCloud().path)
    # Compute an OBB which covers pcl tightly. Robust = True helps in degenerative cases, it adds a little noise to prevent any computational error.
    oriented_bounding_box = pcl.get_oriented_bounding_box(robust=True)
    
    # Set color since OBB will have white color which is difficult to see with white background of visualizer.
    oriented_bounding_box.color = [1.0, 0, 0]