Skip to main content
Upload an MCAP recording directly as a Scene, or use the Scene SDK (encord.beta.scene) to combine separate point cloud, image, camera, and frame-of-reference streams without writing raw Scene JSON. Use this guide for the workflow. Use the Scene SDK reference for method-level details.

SDK Version Requirements

The examples on this page need encord 0.1.205 or later. To update, run pip install --upgrade encord. The Scene features were added in these versions: SceneRead is a deprecated alias of SceneReader. Use SceneReader in new code.

Upload an MCAP Recording

MCAP support is in Beta. Contact your Encord support representative to enable the feature for your Organization.
For an .mcap recording on your computer, use StorageFolder.upload_scene_file. You do not need a SceneBuilder or a cloud integration to upload a local file to Encord-managed storage. upload_scene_file also uploads other single-file Scenes: .bag (ROS 1), .db3 (ROS 2), .e57, .las, .laz, .pcd, and .ply files. It detects the format from the file extension. For an .mcap recording in your cloud storage, register it through a cloud integration with StorageFolder.add_private_data_to_folder_start.
Replace the values in the # User input section with your own. Add the returned Scene item to a Dataset before creating an annotation Project. See MCAP Support for supported streams, transforms, size guidance, and examples. Use StorageItem.update(scene_layout=...) to configure an MCAP layout, and follow MCAP Scene labels for continuous MCAP Scene 3D events, segmentation, and time-series labels.

Build and Upload a Composite Scene

Build the Scene with SceneBuilder, then register it into Files & Folders with StorageFolder.upload_scene.
Build and Upload a Scene
upload_scene validates the Scene, waits for registration to finish, and returns the new Scene item’s UUID. Add that item to a Dataset before creating an annotation Project.

Add Multi-frame Sensor Streams

Create stream builders once, then append events. Use the same timestamp for events that should appear together in the editor.
Multi-frame Scene Streams
Timestamps must be whole numbers that start at 0, such as the frame indices 0, 1, 2, .... Fractional timestamps such as 0.5 fail registration, and a Scene that starts at a large value, such as a Unix epoch timestamp, does not open in the label editor. If your sensors are sampled at different rates, convert their timestamps to integer frame indices on one shared timeline that starts at 0.

Define Camera Streams Separately

Passing width, height, intrinsics, and timestamp to add_image_stream creates a camera stream named <image stream name>/camera automatically. All four arguments are required in this mode. To control the camera stream yourself, for example to give it its own name, mount pose, or a new set of camera parameters when calibration changes, create it with SceneBuilder.add_camera_stream. Then link the image stream to it using the camera argument.
Separate Camera Stream

Rotate Image Streams

If a camera is mounted sideways or upside down, set rotation on its image stream to display the images upright in the label editor. rotation is the clockwise rotation in degrees, and must be 0, 90, 180, or 270. The default is 0. You can set it with a separate camera stream, as in the example below, or with inline camera parameters. Image stream rotation requires encord 0.1.212 or later. Rotation only changes how the images are displayed. Keep the camera’s width, height, intrinsics, distortion, and pose in the original image coordinates, as the camera captured the images. Encord rotates the images and anything projected onto them together.
Rotate an Image Stream
Image streams read with SceneReader have a rotation attribute, and SceneReader.to_upload_payload keeps the rotation when you copy a Scene.

Position Sensors with Poses

Every pose places a child frame inside its parent frame. The position is the child’s origin in parent coordinates, and the rotation turns the child’s axes into the parent’s axes, so a point p in the child frame is at R @ p + t in the parent frame. For a sensor, the pose is where it is mounted on its frame of reference and which way it points: its extrinsic calibration.
  • Link a point cloud or camera stream to a frame of reference with frame_of_reference=, and set a static mount pose with pose=. You can also call set_frame_of_reference() and set_pose() on the stream after you create it.
  • When a frame moves, such as an ego vehicle, add a pose event to its frame-of-reference stream for each frame.
  • Nest frames of reference with add_for_stream(name, parent_for_id=...). A frame of reference without a parent is attached to the Scene root, "root".
  • For an image stream linked to a camera stream with camera=, set the frame of reference and pose on the camera stream.
Build poses with these helpers from encord.beta.scene:
Position Sensors with Poses

Coordinate Conventions

Set coordinate conventions in the SDK when your data uses known world and camera axes. For example, driving datasets often use a world convention such as forward, left, up and camera axes such as right, down, forward. Use SceneBuilder.set_world_convention and SceneBuilder.set_camera_convention with Direction values. The world and camera conventions must have matching handedness.

Add Time Series and Configure a Layout

Add a CSV time series stream with SceneBuilder.add_time_series_stream(name, uri=...). A time series stream is a single file and has no events. See Time Series Column Structure for the CSV format. Set SceneBuilder.layout to a SceneLayout to choose the tiles the label editor shows and how they are arranged:
  • tiles maps tile IDs to Scene3DViewerTile, SceneImageTile, or SceneTimeSeriesTile objects. Image and time series tiles reference streams by stream name.
  • layout arranges the tiles with nested SceneTileLayout splits. SceneTileLayoutDirection.ROW places the two panes side by side, and SceneTileLayoutDirection.COLUMN stacks them. split_percentage sets the first pane’s share of the space, from 5 to 95.
  • timeline lists the time series tile IDs to show in the timeline.
Every tile must be used in layout or timeline, and a layout can contain at most one 3D viewer tile. To change the layout of a registered Scene, call StorageItem.update(scene_layout=...). Pass scene_layout=None to remove the layout. For MCAP recordings, see Configure an MCAP layout.
Time Series Stream and Scene Layout

Scene View Settings

SceneViewSettings holds per-Scene rendering settings that the label editor applies when the Scene is opened from the Editor or Explorer view. Unset fields fall through to the annotator’s own preferences.
  • point_cloud_colouring — one of SceneHeightColouring, SceneProvidedColouring, SceneSolidColouring, SceneImageColouring, or SceneSensorColouring. SceneHeightColouring takes color_height_bounds, the minimum and maximum heights used for the color gradient.
  • point_radius — radius used to render point cloud points, from 0 to 100.
  • render_image_outside_base_range — Render the full image captured by the camera. Useful for wide-angle and fisheye lenses.
  • radius_indicators — a list of SceneRadiusIndicator, each with the frame_of_reference_id at its center, a radius in scene units, and a hex color.
  • radius_filter_enabled — whether point clouds are filtered to the configured radius indicators.
Assign the settings to SceneBuilder.settings before upload, patch a registered Scene with StorageItem.update(scene_view_settings=...), or read them from SceneReader.view_settings. Pass scene_view_settings=None to restore the defaults:
Configure Scene View Settings
frame_of_reference_id must be "root" for the world frame, or the name of a frame-of-reference stream in the same Scene.

Read and Copy Registered Scenes

SceneReader fetches a registered Scene and returns signed URLs for its constituent files. It can also convert a registered Scene back into a DataUploadScene for migration or copying. SceneReader.read() supports composite Scenes only. It raises a ValueError for single-file Scenes, such as MCAP recordings. SceneReader.to_upload_payload() works for both composite and single-file Scenes.
Read and Copy a Scene
Use find_stream and find_event when a missing stream or timestamp is acceptable: they return None. Use get_stream and get_event when missing data should fail fast: they raise KeyError. find_event and get_event only match an event whose timestamp is exactly the one you pass.
  • SceneReader fetches the Scene the first time you read it and caches it. Create a new SceneReader to see changes made after that.
  • A time series stream has no events. find_stream(name, kind="time_series") returns its CSV url and signed_url.
  • to_upload_payload(uri_mapper=...) takes a function or a dict of {old URI: new URI}. URIs that are not in the dict are kept unchanged. The payload keeps the Scene’s view settings and layout.
  • add_private_data_to_folder_start returns an upload job ID. Pass it to add_private_data_to_folder_get_result to wait for the copy and get the new Scene item’s UUID.

Read Frame of Reference Streams

A Scene’s coordinate frames are exposed as frame-of-reference streams. Read them with get_stream(..., kind="frame_of_reference") (or find_stream) to inspect each frame’s pose over time. Every point-cloud and image stream also reports the frame it is expressed in through its frame_of_reference_id.
Read a Frame of Reference Stream
Each FrameOfReferenceEvent gives the frame’s position (translation to its parent frame) and rotation (a 3x3 column-major matrix as a 9-tuple) at a timestamp, along with its frame_id and parent_frame_id.

Camera Distortion Models

The supported distortion models are defined in encord.beta.scene.intrinsics.
Camera Distortion Models
For most workflows, use intrinsics_pinhole or a dedicated distortion constructor. Use intrinsics_advanced only when you already have full calibration matrices and need to supply them directly.

Validation Checklist

Before handing Scenes to annotators:
  • Confirm every point cloud and image URI is accessible by the integration used for registration.
  • Keep stream names stable and descriptive, such as lidar, front, rear, or ego.
  • Use whole-number timestamps that start at 0. Fractional timestamps fail registration, and epoch timestamps stop the Scene opening in the editor.
  • Confirm every SceneRadiusIndicator names "root" or a frame-of-reference stream the Scene defines. Upload fails otherwise.
  • Check that quaternions are in (qx, qy, qz, qw) order and Euler angles are in radians.
  • Confirm every layout tile references an existing stream and is used in layout or timeline.
  • Open at least one registered Scene in the editor to verify orientation, calibration, and frame navigation.

Create and Register Scenes

Learn the Scene data model and registration choices.