Source: tests/test_real_adapters.py · Plain text

tests/test_real_adapters.py

import json
from pathlib import Path

import numpy as np
import pytest
from PIL import Image

from mcss.data.hypersim import convert_hypersim_pose
from mcss.data.manifest import ManifestFrame, SceneManifest, load_manifest, save_manifest
from mcss.data.replica import _resize_scalar, prepare_replica


def test_manifest_rejects_paths_outside_scene_root(tmp_path: Path) -> None:
    data = {
        "schema_version": 1,
        "scene_id": "scene",
        "coordinate_convention": "opencv_c2w",
        "image_size": [4, 4],
        "bounds": [[-1, -1, -1], [1, 1, 1]],
        "frames": [
            {
                "frame_id": 0,
                "rgb": "../escape.png",
                "intrinsics": np.eye(3).tolist(),
                "c2w": np.eye(4).tolist(),
            }
        ],
    }
    with pytest.raises(ValueError, match="relative"):
        SceneManifest.from_dict(data, tmp_path)


def test_manifest_roundtrip_preserves_frame_contract(tmp_path: Path) -> None:
    frame = ManifestFrame(
        frame_id=0,
        rgb="rgb/000000.png",
        intrinsics=np.eye(3).tolist(),
        c2w=np.eye(4).tolist(),
        depth="depth/000000.npy",
    )
    manifest = SceneManifest(
        scene_id="scene",
        image_size=(4, 4),
        bounds=((-1.0, -1.0, -1.0), (1.0, 1.0, 1.0)),
        frames=(frame,),
        root=tmp_path,
    )
    path = save_manifest(manifest, tmp_path / "manifest.json")

    restored = load_manifest(path)

    assert restored.scene_id == "scene"
    assert restored.frames[0].depth == "depth/000000.npy"


def test_replica_preparation_converts_a_small_rendered_fixture(tmp_path: Path) -> None:
    raw = tmp_path / "raw"
    (raw / "rgb").mkdir(parents=True)
    (raw / "depth").mkdir()
    Image.new("RGB", (4, 4), (120, 80, 40)).save(raw / "rgb" / "frame000000.jpg")
    Image.fromarray(np.full((4, 4), 2000, dtype=np.uint16)).save(raw / "depth" / "depth000000.png")
    np.savetxt(raw / "traj.txt", np.eye(4).reshape(1, 16))
    (raw / "cam_params.json").write_text(
        json.dumps({"fx": 4.0, "fy": 4.0, "cx": 1.5, "cy": 1.5, "depth_scale": 1000.0}),
        encoding="utf-8",
    )

    manifest_path = prepare_replica(raw, tmp_path / "prepared", frame_limit=1)
    manifest = load_manifest(manifest_path)

    assert manifest.frames[0].depth is not None
    assert (manifest_path.parent / manifest.frames[0].depth).is_file()
    depth = np.load(manifest_path.parent / manifest.frames[0].depth)
    assert depth[0, 0] == 2.0


def test_hypersim_pose_converts_opengl_camera_axes_to_opencv() -> None:
    orientation = np.eye(3, dtype=np.float32)
    position = np.array([1.0, 2.0, 3.0], dtype=np.float32)

    pose = convert_hypersim_pose(orientation, position, meters_per_asset_unit=2.0)

    np.testing.assert_allclose(pose[:3, :3], np.diag([1.0, -1.0, -1.0]))
    np.testing.assert_allclose(pose[:3, 3], position * 2.0)


def test_resized_metric_array_remains_writable() -> None:
    value = _resize_scalar(np.ones((4, 4), dtype=np.float32), (2, 2))
    value[0, 0] = 0.0

    assert value[0, 0] == 0.0