isl-org / Open3D

Open3D: A Modern Library for 3D Data Processing
http://www.open3d.org
Other
11.46k stars 2.31k forks source link

How can I apply a transformation only once in open3D #6894

Open JaouadROS opened 3 months ago

JaouadROS commented 3 months ago

Checklist

My Question

I want to apply a simple rotation to my 3D model, say 10° pitch, with respect to the recent rotation only once but the model keeps rotating indefinitely. I tried using rotation matrix in a transformation but I get the same issue.

Later I want to be able to generate a pose (rotation+translation) from the video processing and apply it the 3D model.

Here is an example code:

from colorama import init
import numpy as np
import open3d as o3d
import cv2

# Paths to the 3D object and video file
obj_path = "Compressor HD.obj"

# Callback function to update the texture of the plane with video frames
def update(vis):
    global obj_mesh, initial_rotation

    obj_mesh.rotate(o3d.geometry.get_rotation_matrix_from_xyz(np.radians([10, 0, 0])), center=[0, 0, 0])

    vis.update_geometry(obj_mesh)
    vis.poll_events()
    vis.update_renderer()
    return False

if __name__ == "__main__":

    vis = o3d.visualization.VisualizerWithKeyCallback()
    vis.create_window()

    # Load and add the 3D object to the scene
    obj_mesh = o3d.io.read_triangle_mesh(obj_path)
    obj_mesh.compute_vertex_normals()
    vis.add_geometry(obj_mesh)

    initial_rotation = obj_mesh.get_rotation_matrix_from_xyz([0, 0, 0])

    # Create and add coordinate frame
    axis_length = 200 
    coordinate_frame = o3d.geometry.TriangleMesh.create_coordinate_frame(size=axis_length, origin=[0, 0, 0])
    vis.add_geometry(coordinate_frame)

    # Register callback to update video frame texture
    vis.register_animation_callback(update)

    vis.run()
    vis.destroy_window()
    cv2.destroyAllWindows()
timohl commented 3 months ago

First of, I don't think you have to call vis.poll_events(), vis.update_renderer() and vis.update_geometry(obj_mesh) in the callback function. Calling vis.run() already does this for you: https://github.com/isl-org/Open3D/blob/f02e7d24ea115e716445a7fae5093bce60a37d20/cpp/open3d/visualization/visualizer/Visualizer.cpp#L274-L288 But you should return True or False to signal if UpdateGeometry() needs to be called.

I think if you just want to rotate once, you could just add an if in the callback:


target_rotation = 10
applied_rotation = 0

def update(vis):
    global obj_mesh, target_rotation, applied_rotation
    if applied_rotation < target_rotation:
        applied_rotation += 10
        obj_mesh.rotate(o3d.geometry.get_rotation_matrix_from_xyz(np.radians([10, 0, 0])), center=[0, 0, 0])
        return True
    return False

This is just a quick and dirty way to make it rotate just once.

You might want to extend on this by having a list of poses and a current index, and then in each update-call apply the pose at the current index and increment the index. That way you could apply a list of movements.

Also, you might want to use the current time and update only every x msecs to control the speed of animation. Interpolation between poses might also be of interest for smooth transitions.

Note that I never used the animation callback, but this is just some ideas how I would try to do it. Hope my ideas help you with this. :)

JaouadROS commented 3 months ago

Thank you for your time.

I don't have a list of poses because I do generate poses inside update function and they are changing at every frame of the animation. What I found as a solution is to re apply the initial vertices at the beginning of the update function:

# Initialize the initial vertices
initial_obj_mesh_vertices = np.asarray(obj_mesh.vertices).copy()

# and reply them in the update
obj_mesh.vertices = o3d.utility.Vector3dVector(initial_obj_mesh_vertices)
obj_mesh.compute_vertex_normals()

But I'm still looking for a different way to do it. Ideally, I want to be able to apply the transformation with respect to a fixed reference frame. So that way no matter how many times I apply the transformation, it will be the same and it won't be an accumulated one.