def add_camera_animation(
    cameras,
    parent_collection,
    animation_frame_source="ORIGINAL",
    add_background_images=False,
    reorganize_undistorted_images=False,
    number_interpolation_frames=0,
    interpolation_type="LINEAR",
    remove_rotation_discontinuities=True,
    consider_missing_cameras_during_animation=False,
    image_dp=None,
    image_fp_type=None,
    op=None,
):
    """Add an animated camera from a set of reconstructed cameras."""
    log_report("INFO", "Adding Camera Animation: ...", op)

    if len(cameras) == 0:
        return

    if animation_frame_source == "ORIGINAL":
        number_interpolation_frames = 0
    elif animation_frame_source == "ADJUSTED":
        add_background_images = False
    else:
        assert False

    if consider_missing_cameras_during_animation:
        assert image_dp is not None and image_fp_type is not None
        cameras = _enhance_cameras_with_non_reconstructed_cameras(
            cameras, image_dp, image_fp_type, op
        )

    # Using the first reconstructed camera as template for the animated camera.
    # The values are adjusted with _add_transformation_animation() and
    # add_camera_intrinsics_animation().
    some_cam = cameras[0]
    cam_obj = add_camera_object(
        some_cam, "Animated Camera", parent_collection, copy_matrix_world=False
    )

    cameras_sorted = sorted(
        cameras,
        key=lambda camera: int(
            "".join(filter(str.isdigit, camera.get_relative_fp()))
        ),
    )

    transformations_sorted = []
    camera_intrinsics_sorted = []
    for camera in cameras_sorted:
        if isinstance(camera, _NonReconstructedCamera):
            matrix_world = None
            camera_intrinsics = None
        else:
            matrix_world = compute_camera_matrix_world(camera)
            shift_x, shift_y = compute_principal_point_shift(
                camera, relativ_to_largest_extend=True
            )
            camera_intrinsics = _CameraIntrinsics(
                camera.get_field_of_view(), shift_x, shift_y
            )

        transformations_sorted.append(matrix_world)
        camera_intrinsics_sorted.append(camera_intrinsics)

    _add_transformation_animation(
        animated_obj_name=cam_obj.name,
        transformations_sorted=transformations_sorted,
        number_interpolation_frames=number_interpolation_frames,
        interpolation_type=interpolation_type,
        remove_rotation_discontinuities=remove_rotation_discontinuities,
        op=op,
    )

    _add_camera_intrinsics_animation(
        animated_obj_name=cam_obj.name,
        intrinsics_sorted=camera_intrinsics_sorted,
        number_interpolation_frames=number_interpolation_frames,
        op=op,
    )

    if add_background_images:
        _add_background_image_sequence(
            cam_obj, cameras_sorted, reorganize_undistorted_images, op
        )

    log_report("INFO", "Adding Camera Animation: Done", op)
    return cam_obj
Add an animated camera from a set of reconstructed cameras.
photogrammetry_importer/importers/camera_animation_utility.py