[Python] Move camera through x, y, z and it's rotation matrix, and be able to generate camera...

Discussão em 'Python' iniciado por Stack, Setembro 26, 2024.

  1. Stack

    Stack Membro Participativo

    I have had written a code to find the projection of the object seen from different different camera perspectives.

    import numpy as np
    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d.art3d import Poly3DCollection
    from mpl_toolkits.mplot3d import Axes3D

    def load_obj(filename):
    vertices = []
    faces = []
    with open(filename, 'r') as file:
    for line in file:
    if line.startswith('v '):
    vertices.append(list(map(float, line.strip().split()[1:])))
    elif line.startswith('f '):
    faces.append([int(face.split('/')[0]) - 1 for face in line.strip().split()[1:]])
    return np.array(vertices), faces

    def plot_camera_frustum(ax, camera_pos, camera_dir, up_vector, fov_h, fov_v, near_dist, far_dist, color='r'):
    # Calculate camera axes
    camera_right = np.cross(camera_dir, up_vector)
    if np.allclose(camera_right, 0):
    camera_right = np.array([1, 0, 0])
    camera_up = np.cross(camera_right, camera_dir)

    # Normalize vectors
    camera_dir = camera_dir / (np.linalg.norm(camera_dir) + 1e-10)
    camera_right = camera_right / (np.linalg.norm(camera_right) + 1e-10)
    camera_up = camera_up / (np.linalg.norm(camera_up) + 1e-10)

    # Calculate frustum corners
    near_height = 2 * np.tan(np.radians(fov_v / 2)) * near_dist
    near_width = 2 * np.tan(np.radians(fov_h / 2)) * near_dist
    far_height = 2 * np.tan(np.radians(fov_v / 2)) * far_dist
    far_width = 2 * np.tan(np.radians(fov_h / 2)) * far_dist

    # Near plane corners
    near_center = camera_pos + near_dist * camera_dir
    near_top_left = near_center + (near_height / 2) * camera_up - (near_width / 2) * camera_right
    near_top_right = near_center + (near_height / 2) * camera_up + (near_width / 2) * camera_right
    near_bottom_left = near_center - (near_height / 2) * camera_up - (near_width / 2) * camera_right
    near_bottom_right = near_center - (near_height / 2) * camera_up + (near_width / 2) * camera_right

    # Far plane corners
    far_center = camera_pos + far_dist * camera_dir
    far_top_left = far_center + (far_height / 2) * camera_up - (far_width / 2) * camera_right
    far_top_right = far_center + (far_height / 2) * camera_up + (far_width / 2) * camera_right
    far_bottom_left = far_center - (far_height / 2) * camera_up - (far_width / 2) * camera_right
    far_bottom_right = far_center - (far_height / 2) * camera_up + (far_width / 2) * camera_right

    # Plot frustum
    frustum_points = [near_top_left, near_top_right, near_bottom_right, near_bottom_left,
    far_top_left, far_top_right, far_bottom_right, far_bottom_left]
    frustum_faces = [[0, 1, 2, 3], [4, 5, 6, 7], [0, 4, 7, 3],
    [1, 5, 6, 2], [0, 1, 5, 4], [3, 2, 6, 7]]

    frustum_collection = Poly3DCollection(np.array(frustum_points)[frustum_faces], alpha=0.2, facecolor=color)
    ax.add_collection3d(frustum_collection)

    def plot_obj_with_camera(filename, translation, camera_pos, camera_target, fov_h, fov_v):
    vertices, faces = load_obj(filename)

    # Apply translation to vertices
    vertices += translation

    fig = plt.figure(figsize=(15, 6))

    # 3D view subplot
    ax1 = fig.add_subplot(121, projection='3d')

    mesh = Poly3DCollection(vertices[faces], alpha=0.3)
    face_color = [0, 1, 1] # Cyan color (RGB: 0, 1, 1)
    mesh.set_facecolor(face_color)
    ax1.add_collection3d(mesh)

    # Set plot limits
    ax1.set_xlim(0, 0.1)
    ax1.set_ylim(0, 0.1)
    ax1.set_zlim(0, 0.1)

    # Calculate camera direction
    camera_dir = camera_target - camera_pos
    camera_dir = camera_dir / np.linalg.norm(camera_dir)

    # Define up vector (assuming Z is up)
    up_vector = np.array([0, 0, 1])

    # Plot camera point
    ax1.scatter(*camera_pos, color='r', s=100, label='Camera')

    # Plot camera frustum
    near_dist = 0.01
    far_dist = 0.05
    plot_camera_frustum(ax1, camera_pos, camera_dir, up_vector, fov_h, fov_v, near_dist, far_dist)

    ax1.set_xlabel('X')
    ax1.set_ylabel('Y')
    ax1.set_zlabel('Z')
    ax1.legend()
    ax1.set_title('3D Object with Camera and View Frustum')

    # Camera view subplot
    ax2 = fig.add_subplot(122)

    # Project vertices onto camera plane
    camera_right = np.cross(camera_dir, up_vector)
    if np.allclose(camera_right, 0):
    # If camera_right is zero, choose a different up_vector
    up_vector = np.array([0, 1, 0])
    camera_right = np.cross(camera_dir, up_vector)

    camera_up = np.cross(camera_right, camera_dir)

    camera_right = camera_right / (np.linalg.norm(camera_right) + 1e-10)
    camera_up = camera_up / (np.linalg.norm(camera_up) + 1e-10)

    # Create camera transformation matrix
    camera_matrix = np.column_stack((camera_right, camera_up, -camera_dir))
    camera_translation = -camera_pos

    # Transform vertices to camera space
    vertices_camera = np.dot(vertices + camera_translation, camera_matrix.T)

    # Project vertices onto 2D plane
    vertices_2d = vertices_camera[:, :2] / (vertices_camera[:, 2, np.newaxis] + 1e-10)

    # Print debug information
    print("Vertices 2D shape:", vertices_2d.shape)
    print("Vertices 2D min/max:", np.min(vertices_2d), np.max(vertices_2d))

    # Plot 2D projection
    for face in faces:
    ax2.fill(vertices_2d[face, 0], vertices_2d[face, 1], alpha=0.3, color = 'cyan')

    ax2.set_xlim(-2, 2) # Adjusted limits
    ax2.set_ylim(-2, 2) # Adjusted limits
    ax2.set_aspect('equal')
    ax2.set_title("Camera View")
    ax2.set_xlabel("X")
    ax2.set_ylabel("Y")

    plt.tight_layout()
    plt.show()

    # Usage
    obj_filename = 'T_Joint_2a0e9f91/mesh/T_Joint_2a0e9f91.obj'
    translation = np.array([0.01, 0.01, 0.0]) # Translation vector
    camera_pos = np.array([0.03, 0.015, 0.03]) # Camera directly above the object
    camera_target = np.array([0.04, 0.025, 0]) # Looking directly at the center of the object
    fov_h = 42.62 # Horizontal field of view in degrees
    fov_v = 56.31 # Vertical field of view in degrees

    plot_obj_with_camera(obj_filename, translation, camera_pos, camera_target, fov_h, fov_v)


    See in the given image you can see that my object in figure 1 is not entirely in the field of view of the camera but still when I am plotting the projection of the object I can see the entire object as shown in figure 2. Why? Please can anyone tell me my mistake and tell me a solution to improve my code.

    [​IMG]

    For simplicity you can try same thing for a cube instead of object from obj file.

    Thank You in advance!!

    Continue reading...

Compartilhe esta Página