Source code for miop.matrices_metadata

# Copyright (c) 2025, Maxime Paschoud.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.
#
# (http://opensource.org/licenses/BSD-3-Clause)
#
# __author__ = "Maxime Paschoud, ETHZ: CMBM"
#

import numpy as np
from pipeline import DAGNode

[docs] class CameraMvmtFromMetadata(DAGNode): """ Computes camera intrinsics and extrinsics (rotation matrices) from metadata. Attributes ---------- rotation_matrices : list of list of np.ndarray Rotation matrices for each image in each face. camera_position : list of dict List of dictionaries for each face containing: - 'rotations': array of 3x3 rotation matrices (extrinsics) - 'intrinsics': placeholder list for intrinsics (scaling and shear [ones, [1., 0.]]) """ def __init__(self): """ Initializes the camera movement estimation object with empty attributes. """ super().__init__() self.rotation_matrices = None self.camera_position = None
[docs] def eval(self, img_collection): """ Computes camera extrinsics (rotation matrices) for each image in the image collection using the tilt angle and inferred tilt axis from metadata. Parameters ---------- img_collection : ImageCollection The collection of images with metadata from which to compute rotations. Returns ------- list of dict One dictionary per face, containing: - 'rotations': np.ndarray of shape (N, 3, 3), rotation matrices for N images - 'intrinsics': placeholder value ([ones, [1., 0.]]) """ rot_mat = [] camera_pos = [] for face in img_collection.faces: img = face[0][0] axis = self.choose_axis(img.rotation_z) rot_mat.append([self.get_rotation_matrix(img.tilt, axis)]) for pair in face: img = pair[1] m = self.get_rotation_matrix(img.tilt, axis) rot_mat[-1].append(m) camera_pos.append({'rotations': np.asarray(rot_mat[-1]), 'intrinsics': [np.ones(len(face) + 1), [1.,0]]}) self.rotation_matrices = rot_mat self.camera_position = camera_pos return [camera_pos]
[docs] def choose_axis(self, rot_z): """ Determines the tilt axis based on rotation in the (x, y) plane. Parameters ---------- rot_z : float Rotation angle in the (x, y) plane in radians. Returns ------- list of float A 3D unit vector representing the axis of rotation, one of: - [1., 0., 0.] (default: horizontal) - [-1., 0., 0.] (rot_z ≈ 180°) - [0., 1., 0.] (rot_z ≈ -90°) - [0., -1., 0.] (rot_z ≈ 90°) """ if np.isclose(rot_z, 90 * np.pi/180): axis = [0., -1., 0.] elif np.isclose(rot_z, 180 * np.pi/180): axis = [-1., 0., 0.] elif np.isclose(rot_z, -90 * np.pi/180): axis = [0., 1., 0.] else: axis = [1., 0., 0.] return axis
[docs] def get_rotation_matrix(self, angle, axis): """ Computes a 3x3 rotation matrix given an angle and rotation axis using Rodrigues' formula. Parameters ---------- angle : float Rotation angle in radians. axis : list of float 3D axis of rotation (e.g., [1., 0., 0.] for X-axis). Returns ------- np.ndarray A 3x3 rotation matrix representing the rotation about the given axis. """ axis = np.asarray(axis) axis = axis / np.linalg.norm(axis) K = np.array([[0, -axis[2], axis[1]], [axis[2], 0, -axis[0]], [-axis[1], axis[0], 0]]) # Rotation matrix calculation using Rodrigues' formula I = np.eye(3) rotation_matrix = I + np.sin(angle) * K + (1 - np.cos(angle)) * np.dot(K, K) return rotation_matrix