Search code examples
python-3.9open3d

Copy camera viewpoint using open3d gui


Open3d's easy draw_geometries utility makes it possible to copy & paste camera parameters to restore a certain view point after it has been changed. It seems like this functionality would also be available when using the SceneWidget and its Open3DScene high level scene. However I have not figured out a way to mimic this behavior.

Copying and pasting a viewpoint from draw_geometries onto notepad reveals this information:

boundingbox_max, boundingbox_min, field_of_view, front, lookat, up, zoom

In order for it to have the same effect using the SceneWidget I would have to somehow obtain this information from the scene's camera, create a copy, and then load it later when it is needed. Nevertheless, I cannot access the above properties explicitly through the camera object, nor have I found a way to set them (assuming I already have them).

The next "obvious" solution would be the camera class's copy_from method, which sounds great, except I am unable to instantiate the Camera class in order to use it.

How can I achieve this save & restore viewpoint effect?

Thanks in advance


Solution

  • In the end I was able to figure out two solutions. I could not figure out a way to instantiate the Camera class in order to use the copy_from method. A neat way around this problem is to create a second SceneWidget that will not be shown and simply act as a buffer. Using the SceneWidget.Open3DScene's camera property it is possible to copy to and from the main scene's camera. In summation, bind a key that saves the main camera to the buffer scene's camera, and another key to restore it.

    This solution however only allows copying and pasting viewpoints for a single runtime of the application, so we need to save the camera parameters to a file. Using the default camera movement pattern, it appears that only the camera itself moves and rotates around the object. Through the camera's get_model_matrix() method, we get a 4x4 matrix. The last column corresponds to the camera position and the first 3x3 matrix represents a composite rotation. We extract and save the following information

    m = camera.get_model_matrix()
    rot = model[:3, :3]
    pos = model[:3, 3]
    

    An then, in order to restore the viewpoint we use the SceneWidget's look_at(point, camera_position, camera_up), as follows:

    camera_dir = np.dot(rot, np.array([[0],[0],[-1]])).squeeze()
    scene.look_at(pos + camera_dir, pos, np.array([0,1,0]))
    

    Since by default the camera looks towards the screen (-z) we multiply the direction vector by the rotation matrix we save earlier, and obtain a point on the direction vector as pos + camera_dir.

    Warning! This does not account for the direction of the up vector. If the viewpoint you want to save is upside down, the up vector should be (0,-1,0).