Examples

This page contains complete examples demonstrating the MIMIC Data API.

Creating a Complete Scene

This example shows how to create a scene with cameras, LiDAR, radar, and actors:

# Creating a scene with a camera and an actor
from mimic_data_api import (
    Camera,
    CameraIntrinsics,
    DistortionParameters,
    RollingShutterParameters,
    ImageData,
    Actor,
    ActorDimensions,
    Scene,
    EgoVehicle,
    Sensors,
    WorldTrajectory,
    Radar,
    RadarIntrinsics,
    RadarPointCloudData,
    Lidar,
    LidarIntrinsics,
    LidarPointCloudData,
    VerticalResolution,
)
import numpy as np
from pathlib import Path

# Define timestamps and trajectory
timestamps = np.array([0.0, 1.0, 2.0])
poses = np.array(3 * np.eye(4).tolist()).reshape(3, 4, 4)

ego_trajectory = WorldTrajectory(
    timestamps=timestamps,
    object2world=poses,
)

# Create image data entries
images = [
    ImageData(
        filepath=f"camera/{i:08d}.png",
        timestamp=float(i),
        undistorded=True,
        rolling_shutter=RollingShutterParameters()
    )
    for i in range(3)
]

# Create a camera
camera = Camera(
    id=1,
    name="Front Camera",
    camera_model="pinhole",
    intrinsics=CameraIntrinsics(
        fx=1000.0,
        fy=1000.0,
        cx=640.0,
        cy=360.0,
        skew=0.0,
        height=720.0,
        width=1280.0,
    ),
    distortion_parameters=DistortionParameters(),
    trajectory=WorldTrajectory(
        timestamps=timestamps,
        object2world=poses,
    ),
    images_data=images,
    extrinsics=np.eye(4),
)

# Create LiDAR point cloud data entries
lidar_pcds = [
    LidarPointCloudData(
        filepath=f"lidar/{i:08d}.ply",
        timestamp=float(i),
        egomotion_compensated=True,
        has_missing_points=False
    )
    for i in range(3)
]

# Create a LiDAR sensor
lidar = Lidar(
    id=1,
    name="top_lidar",
    extrinsics=np.eye(4),
    intrinsics=LidarIntrinsics(
        vertical_fov=np.pi / 4,  # 45 degrees
        horizontal_fov=2 * np.pi,  # 360 degrees
        horizontal_resolution=0.01,
        vertical_resolution=VerticalResolution(vertical_resolution=0.01),
        max_range=100.0,
        min_range=0.1,
        rotation_type="clockwise",
        lidar_type="rotating"
    ),
    trajectory=WorldTrajectory(
        timestamps=timestamps,
        object2world=poses,
    ),
    lidar_pcds_data=lidar_pcds,
    min_cut_off_range=1.5
)

# Create radar point cloud data entries
radar_pcds = [
    RadarPointCloudData(
        filepath=f"radar/{i:08d}.ply",
        timestamp=float(i)
    )
    for i in range(3)
]

# Create a radar sensor
radar = Radar(
    id=1,
    name="front_radar",
    extrinsics=np.eye(4),
    intrinsics=RadarIntrinsics(
        range=200,
        azimuth_fov=np.pi / 3,  # 60 degrees
        elevation_fov=np.pi / 6,  # 30 degrees
        azimuth_resolution=[(0.0, 0.01), (np.pi / 6, 0.02)],
        elevation_resolution=None,
        min_speed_resolution=-50.0,
        max_speed_resolution=50.0,
    ),
    trajectory=WorldTrajectory(
        timestamps=timestamps,
        object2world=poses,
    ),
    radar_pcds_data=radar_pcds,
)

# Create an actor (vehicle)
actor = Actor(
    id=1,
    name="Vehicle_001",
    dimensions=ActorDimensions(length=4.5, width=2.0, height=1.5),
    boxtype="vehicle",
    original_boxtype="sedan",
    dynamic=True,
    trajectory=WorldTrajectory(
        timestamps=timestamps,
        object2world=poses,
    ),
    description="A sedan traveling in the adjacent lane"
)

# Assemble the scene
sensors = Sensors(
    cameras=[camera],
    lidars=[lidar],
    radars=[radar]
)

scene = Scene(
    ego_vehicle=EgoVehicle(
        trajectory=ego_trajectory,
        sensors=sensors,
    ),
    actors=[actor],
)

# Export to JSON
with open("scene.json", "w") as f:
    f.write(scene.model_dump_json(indent=2))

print("Scene created and saved to scene.json")

Loading and Inspecting a Scene

Load an existing scene and inspect its contents:

from mimic_data_api import Scene
from pathlib import Path

# Load scene from JSON
scene_json = Path("scene.json").read_text()
scene = Scene.model_validate_json(scene_json)

# Inspect ego vehicle
ego = scene.ego_vehicle
print(f"Ego trajectory: {len(ego.trajectory.timestamps)} frames")
print(f"Duration: {ego.trajectory.timestamps[-1] - ego.trajectory.timestamps[0]:.1f} seconds")

# List sensors
print(f"\nCameras: {len(ego.sensors.cameras)}")
for cam in ego.sensors.cameras:
    print(f"  - {cam.name}: {cam.camera_model}, {cam.intrinsics.width}x{cam.intrinsics.height}")

if ego.sensors.lidars:
    print(f"\nLiDARs: {len(ego.sensors.lidars)}")
    for lidar in ego.sensors.lidars:
        print(f"  - {lidar.name}: {lidar.intrinsics.lidar_type}, range={lidar.intrinsics.max_range}m")

if ego.sensors.radars:
    print(f"\nRadars: {len(ego.sensors.radars)}")
    for radar in ego.sensors.radars:
        print(f"  - {radar.name}: range={radar.intrinsics.range}m")

# List actors
print(f"\nActors: {len(scene.actors)}")
for actor in scene.actors:
    status = "dynamic" if actor.dynamic else "static"
    print(f"  - [{actor.id}] {actor.name}: {actor.boxtype} ({status})")
    print(f"    Dimensions: {actor.dimensions.length}m x {actor.dimensions.width}m x {actor.dimensions.height}m")

Working with Camera Intrinsics

Project 3D points to image coordinates:

import numpy as np
from mimic_data_api import Camera, CameraIntrinsics

# Get intrinsic matrix
intrinsics = CameraIntrinsics(
    fx=1000, fy=1000,
    cx=640, cy=360,
    skew=0,
    width=1280, height=720
)
K = intrinsics.as_K()

# 3D point in camera coordinates
point_3d = np.array([1.0, 0.5, 5.0])  # x=1m right, y=0.5m down, z=5m forward

# Project to 2D (homogeneous coordinates)
point_2d_h = K @ point_3d
point_2d = point_2d_h[:2] / point_2d_h[2]

print(f"3D point: {point_3d}")
print(f"2D projection: ({point_2d[0]:.1f}, {point_2d[1]:.1f}) pixels")

Transforming Points Between Frames

Transform points between sensor, vehicle, and world frames:

import numpy as np

# Example: Point in LiDAR sensor frame
point_sensor = np.array([10.0, 2.0, 0.5, 1.0])  # Homogeneous coordinates

# Sensor to vehicle transform (extrinsics)
# Example: LiDAR mounted 1.5m above vehicle origin
T_sensor_to_vehicle = np.array([
    [1, 0, 0, 0],
    [0, 1, 0, 0],
    [0, 0, 1, 1.5],
    [0, 0, 0, 1]
], dtype=np.float64)

# Vehicle to world transform (from trajectory)
# Example: Vehicle at position (100, 50, 0) with 45° yaw
angle = np.pi / 4
T_vehicle_to_world = np.array([
    [np.cos(angle), -np.sin(angle), 0, 100],
    [np.sin(angle), np.cos(angle), 0, 50],
    [0, 0, 1, 0],
    [0, 0, 0, 1]
], dtype=np.float64)

# Transform point to vehicle frame
point_vehicle = T_sensor_to_vehicle @ point_sensor
print(f"Point in vehicle frame: {point_vehicle[:3]}")

# Transform point to world frame
point_world = T_vehicle_to_world @ point_vehicle
print(f"Point in world frame: {point_world[:3]}")

# Or compose transforms first
T_sensor_to_world = T_vehicle_to_world @ T_sensor_to_vehicle
point_world_direct = T_sensor_to_world @ point_sensor
print(f"Point in world frame (direct): {point_world_direct[:3]}")

Filtering Dynamic Actors

Find and analyze dynamic actors:

from mimic_data_api import Scene
import numpy as np

# Load scene
scene = Scene.model_validate_json(open("scene.json").read())

# Get only dynamic actors
dynamic_actors = [a for a in scene.actors if a.dynamic]

print(f"Found {len(dynamic_actors)} dynamic actors")

for actor in dynamic_actors:
    # Calculate approximate speed from trajectory
    positions = actor.trajectory.object2world[:, :3, 3]  # Extract translations
    timestamps = actor.trajectory.timestamps

    if len(timestamps) > 1:
        distances = np.linalg.norm(np.diff(positions, axis=0), axis=1)
        dt = np.diff(timestamps)
        speeds = distances / dt
        avg_speed = np.mean(speeds)

        print(f"\n{actor.name} ({actor.boxtype}):")
        print(f"  Average speed: {avg_speed:.1f} m/s ({avg_speed * 3.6:.1f} km/h)")
        print(f"  Track length: {np.sum(distances):.1f} m")

Multi-Camera Setup

Create a surround-view camera configuration:

import numpy as np
from mimic_data_api import (
    Camera, CameraIntrinsics, DistortionParameters,
    ImageData, WorldTrajectory, Sensors, EgoVehicle, Scene
)

def create_camera(name: str, yaw_deg: float, trajectory: WorldTrajectory) -> Camera:
    """Create a camera with given orientation."""
    yaw = np.radians(yaw_deg)

    # Rotation matrix (yaw only)
    R = np.array([
        [np.cos(yaw), -np.sin(yaw), 0],
        [np.sin(yaw), np.cos(yaw), 0],
        [0, 0, 1]
    ])

    # Extrinsics: camera mounted at vehicle center, different orientations
    extrinsics = np.eye(4)
    extrinsics[:3, :3] = R

    # Create image data for each timestamp
    images = [
        ImageData(
            filepath=f"{name.lower()}/{i:08d}.png",
            timestamp=t,
            undistorded=True
        )
        for i, t in enumerate(trajectory.timestamps)
    ]

    return Camera(
        id=hash(name) % 1000,
        name=name,
        camera_model="pinhole",
        intrinsics=CameraIntrinsics(
            fx=800, fy=800, cx=640, cy=360,
            skew=0, width=1280, height=720
        ),
        distortion_parameters=DistortionParameters(),
        extrinsics=extrinsics,
        trajectory=trajectory,
        images_data=images
    )

# Create trajectory
n_frames = 100
trajectory = WorldTrajectory(
    timestamps=np.linspace(0, 10, n_frames),
    object2world=np.stack([np.eye(4)] * n_frames)
)

# Create surround-view cameras
cameras = [
    create_camera("FRONT", 0, trajectory),
    create_camera("FRONT_LEFT", 45, trajectory),
    create_camera("FRONT_RIGHT", -45, trajectory),
    create_camera("REAR", 180, trajectory),
    create_camera("REAR_LEFT", 135, trajectory),
    create_camera("REAR_RIGHT", -135, trajectory),
]

# Create scene
scene = Scene(
    ego_vehicle=EgoVehicle(
        trajectory=trajectory,
        sensors=Sensors(cameras=cameras)
    ),
    actors=[]
)

print(f"Created scene with {len(cameras)} cameras:")
for cam in cameras:
    print(f"  - {cam.name}")

Round-Trip Validation

Verify that serialization preserves data:

from copy import deepcopy
from mimic_data_api import Scene, Camera

# Load or create scene
scene = Scene.model_validate_json(open("scene.json").read())

# Make a deep copy
scene_copy = deepcopy(scene)

# Serialize and deserialize
json_str = scene.model_dump_json(indent=2)
scene_roundtrip = Scene.model_validate_json(json_str)

# Verify cameras match
for orig_cam, rt_cam in zip(
    scene.ego_vehicle.sensors.cameras,
    scene_roundtrip.ego_vehicle.sensors.cameras
):
    assert orig_cam == rt_cam, f"Camera {orig_cam.name} mismatch!"

# Verify actors match
for orig_actor, rt_actor in zip(scene.actors, scene_roundtrip.actors):
    assert orig_actor.id == rt_actor.id
    assert orig_actor.boxtype == rt_actor.boxtype

print("Round-trip validation successful!")

Note

For more detailed API documentation, see the Scene Module reference pages.