Preprocessing turns a raw Project Aria recording (sample.vrs + MPS SLAM & hand
tracking) into a structured, per-frame dataset with 3D hand/object tracking, ready to
train HumanEgo policies. This doc covers (1) how to download a sample and run the
pipeline, (2) the pipeline architecture, and (3) every file it produces and what it means.
The data lives on the public HuggingFace dataset
Leo-TX/HumanEgo — no token required.
pip install huggingface_hub # for downloading
# and follow the repo README to install the full preprocessing environmentDownload data (scripts/download_data.py) — pick a task and how many recordings:
# 1 serve_bread recording (default), WITH precomputed output (~2 GB); all_data.tar auto-extracted
python scripts/download_data.py
# the first 20 serve_bread recordings, with precomputed output
python scripts/download_data.py --task serve_bread --num 20
# INPUT ONLY (~0.6 GB/recording) — to run the pipeline yourself
python scripts/download_data.py --task serve_bread --num 1 --input-only| flag | meaning |
|---|---|
--task |
serve_bread | water_flowers | all (default serve_bread) |
--num |
how many recordings — first N, or all (default 1) |
--input-only |
inputs only; skip the precomputed preprocess/ output |
--out |
download location (default ./data) |
Run the pipeline:
python -m preprocess.Preprocess \
--mps_path ./data/serve_bread/aria/mps_serve_bread_000_vrs --task serve_breadEverything is written to …/mps_serve_bread_000_vrs/preprocess/. On an RTX 4090 a
~33 s / 1000-frame recording takes ~20 min end-to-end.
Plain huggingface_hub (no helper script)
from huggingface_hub import snapshot_download
# input only
snapshot_download(
repo_id="Leo-TX/HumanEgo", repo_type="dataset", local_dir="./data",
allow_patterns=["serve_bread/aria/mps_serve_bread_000_vrs/*"],
ignore_patterns=["serve_bread/aria/mps_serve_bread_000_vrs/preprocess/*"],
)Drop ignore_patterns to also fetch the precomputed output, then unpack the per-frame
archive: tar -xf …/preprocess/all_data.tar -C …/preprocess.
mps_serve_bread_000_vrs/
├── sample.vrs # raw Aria recording ┐
├── slam/ # MPS SLAM (trajectory + semidense points)│ INPUT
├── hand_tracking/ # MPS hand tracking (hand_tracking_results.csv)
├── else/ # VRS metadata / health checks ┘
└── preprocess/ # ← everything below is GENERATED by the pipeline
├── <top-level files> # per-stage results + diagnostic plots
├── vis/ # visualization clips (mp4 + gif)
├── cfg/ # snapshot of the configs used (auto-regenerated)
└── all_data/<idx>/ # per-frame data (rgb, masks, poses, training_data.json)
preprocess.Preprocess runs these stages in order (entry point: preprocess/Preprocess.py):
| # | Stage | What it does | Models |
|---|---|---|---|
| 1 | aria | Extract RGB frames + camera config (AriaCam), MPS hand keypoints (AriaHands), SLAM device poses (AriaSlam), and segment the sequence into Navigation / Transition / Manipulation phases (AriaPhases). |
projectaria_tools (MPS) |
| 2 | indices | Isolate the object-centric window (the manipulation segment) used by all downstream 3D stages. | — |
| 3 | dinosam | Detect + segment the prompted objects (obj1, obj2) and the arm/hands, per frame → object & arm masks. |
Grounding DINO + SAM 2 |
| 4 | kptsselector | Pick trackable keypoints on each object. | — |
| 5 | cotracker | Track the 2D keypoints across the object-centric frames. | CoTracker3 |
| 6 | camtriangulator | Lift the 2D tracks to 3D object poses using the SLAM camera poses. | — (geometry) |
| 7 | lama | Inpaint the arm/hand out of the RGB frames (arm-free frames). | LaMa |
| 8 | visualkpts | Render arm + object keypoints onto the RGB and arm-inpainted RGB. | — |
| 9 | datasetgen | Consolidate everything into per-frame training_data.json — 4×4 SE(3) poses for cameras / hands / objects in an object-centric world frame, using a grasp "latch & propagate" state machine to keep object pose stable under occlusion. Also renders the object-centric 3D scene. |
— |
The released default runs hand tracking via aria_mps only — that is all the Quick Start needs. The mediapipe / wilor / hamer methods are an ablation, off by default. Reproducing it takes three steps: install the extra packages (
SKIP_HAND=0 bash setup.sh), list the methods incfg/preprocess/base/Preprocess.yaml→hand_tracking_methods, and un-commentself.preprocess_hands()inpreprocess/Preprocess.py(it is commented out by default).
| File | Stage | Meaning |
|---|---|---|
aria_cam_rgb_config.json |
aria | RGB camera calibration/config (intrinsics, resolution, fps). |
aria_phases_results.json |
aria | Phase segmentation: frame ranges for Navigation/Transition/Manipulation + the object-centric window. |
aria_phases_analysis.png |
aria | Plot of the phase segmentation over time. |
aria_slam_analysis.png |
aria | Plot of the SLAM trajectory / pose analysis. |
aria_hands_analysis_l.png / _r.png |
aria | Left / right hand tracking analysis plots. |
dinosam_mask_obj1.png / obj2.png |
dinosam | DINO+SAM2 segmentation preview for object 1 / object 2. |
kptsselector_results.json |
kptsselector | The keypoints selected on each object for tracking. |
kptsselector_vis_obj1.png / obj2.png |
kptsselector | Visualization of the selected keypoints. |
cotracker_results.json |
cotracker | 2D CoTracker tracks of the keypoints across the object-centric frames. |
camtriangulator_results.json |
camtriangulator | Triangulated 3D object keypoints/poses per frame. |
camtriangulator_vis.ply |
camtriangulator | 3D point cloud of the triangulated keypoints. |
camtriangulator_vis.png |
camtriangulator | 2D diagnostic render of the triangulation. |
object_centric.ply |
datasetgen | Final object-centric 3D scene (multi-object point cloud + trajectories). |
object_centric.png |
datasetgen | 2D diagnostic plot of the object-centric scene. |
| File | Meaning |
|---|---|
aria_cam_rgb.* |
The raw extracted RGB stream. |
aria_vis.* |
RGB + MPS hand keypoints + phase labels over the sequence. |
aria_vis_full_hands.* |
RGB with full hand skeletons. |
visualkpts_vis.* |
Tracked arm + object keypoints on (arm-inpainted) RGB. |
<idx> is the zero-padded frame index. Image-name convention: W=with, Wo=without,
Arm/Obj=arm/object, Kpts=keypoints overlaid.
| File | Meaning |
|---|---|
rgb.png |
Extracted RGB frame. |
rgb_WoArm.png |
RGB with the arm inpainted out (LaMa). |
rgb_WArmObjKpts.png |
RGB with arm + object keypoints overlaid. |
rgb_WoArm_WArmObjKpts.png |
Arm-inpainted RGB with arm + object keypoints overlaid. |
mask_obj1.png / mask_obj2.png |
Per-frame object segmentation masks. |
mask_arm.png |
Per-frame arm/hand segmentation mask. |
mask_arm_and_obj.png |
Combined arm + object mask. |
aria_cam_rgb.json |
Per-frame camera pose (c2w) + intrinsics. |
aria_hands.json |
Per-frame MPS hand keypoints / pose. |
aria_slam.json |
Per-frame SLAM device pose. |
aria_phases.json |
Per-frame phase label. |
training_data.json |
The per-frame training target (schema below). Written for the manipulation-phase frames. |
The final per-frame dataloader target produced by DatasetGen:
A snapshot of the merged YAML configs used for this run, one file per module
(AriaCam.yaml, DINOSAM.yaml, …). Auto-generated every run and fully regenerable —
it documents exactly which settings produced the outputs.
Configs live under cfg/preprocess/ and are compiled per run (load_cfg_dynamic_task):
cfg/preprocess/base/Preprocess.yaml— the master config. It points to each module's YAML (AriaCam_path,DINOSAM_path, …) and setshand_tracking_methods.cfg/preprocess/base/<Module>.yaml— per-module defaults, one file per pipeline stage (AriaCam,AriaHands,AriaSlam,AriaPhases,DINOSAM,KptsSelector,CoTracker,CamTriangulator,Lama,VisualKpts,DatasetGen). Every field is documented inline in these files — read them for the full set of knobs and their defaults.cfg/preprocess/tasks/<task>.yaml— a small per-task override selected by--task <task>, deep-merged over the base so you only specify what differs for your task.
python -m preprocess.Preprocess --mps_path <recording_dir> --task <task> \
[--cfg_path cfg/preprocess/base/Preprocess.yaml] [--no-video] [--no-gif]If
cfg/preprocess/tasks/<task>.yamlis missing, preprocessing still runs but uses the base defaults — whosedinosam_promptis a placeholder ("a pretty cat ."), so it won't detect your objects. A task file is therefore effectively required.
Each top-level key targets the module of the same name; the values are deep-merged onto that module's base YAML. The fields that typically vary per task:
| Key | Stage | Meaning |
|---|---|---|
DINOSAM.dinosam_prompt.{obj1,obj2,…} |
dinosam | Required. Open-vocabulary Grounding DINO text prompt for each manipulated object — end each phrase with a space + period, e.g. "a plate .". The keys obj1, obj2, … become the object ids used everywhere downstream. |
DINOSAM.dinosam_prompt.arm |
dinosam | Prompt for the hand/arm that gets segmented and inpainted (usually "human arms . human hands ."). |
AriaHands.hand_selection |
aria | Which hand to keep: "right", "left", "auto" (highest confidence), or "none" (both). |
AriaHands.grasp_threshold |
aria | Fingertip distance (m) below which a grasp is detected — tune to your object size. |
AriaPhases.{v_stop_thresh,finished_frames,manip_clean_manual_offset} |
aria | Phase-segmentation tuning: stop-speed threshold (m/s), how many trailing frames to mark finished, and how much to trim around the manipulation boundary. |
CamTriangulator.pose_method.{obj1,…,default} |
camtriangulator | Per-object 3D orientation method: "vlm" (Orient-Anything, semantic), "pca1" (star-shaped geometric), or "pca2" (object-centric; handles upright/fallen objects). |
DatasetGen.disable_kinematic_latching_{left,right} |
datasetgen | Set true to keep an object fixed at its initial pose instead of latching it to the hand on grasp. |
For every other tunable field and its default, see the matching
cfg/preprocess/base/<Module>.yaml.
- Create
cfg/preprocess/tasks/<your_task>.yaml. - Set
DINOSAM.dinosam_promptfor each object you manipulate (obj1,obj2, …) plus thearmprompt. - Set
AriaHands.hand_selection(andgrasp_thresholdif needed), and pick aCamTriangulator.pose_methodper object. - Run
python -m preprocess.Preprocess --mps_path <recording_dir> --task <your_task>. - Verify: check
…/preprocess/dinosam_mask_obj*.pngto confirm the prompts segment the right objects, and the…/preprocess/cfg/snapshot to confirm your overrides were applied; iterate on the prompts/thresholds as needed.
Example — cfg/preprocess/tasks/serve_bread.yaml:
AriaHands:
hand_selection: "right" # serve_bread is one-handed (right)
DINOSAM:
dinosam_prompt:
obj1: "piece of bread ."
obj2: "a plate ."
arm: "human arms . human hands ."
CamTriangulator:
pose_method:
obj1: "pca1"
obj2: "pca1"
default: "pca1"# an entire task (all serve_bread recordings), with precomputed output
python scripts/download_data.py --task serve_bread --num all
# the whole dataset (serve_bread + water_flowers) — large
python scripts/download_data.py --task all --num all
# inputs only, to reprocess everything yourself
python scripts/download_data.py --task all --num all --input-onlyall_data.tar is just the per-frame files packed into one archive (so the dataset stays at a
few dozen files per recording instead of hundreds of thousands). It is auto-extracted on
download and is fully regenerable by running preprocessing, so you only need it to get the
precomputed per-frame results without running the pipeline.
{ "metadata": { "idx", "ts", // frame index, timestamp "w", "h", "fps", // image size, frame rate "k": [3×3 intrinsics], "c2w": [4×4 camera-to-world], "anchor_key": "obj1", // object designated as the world origin (object-centric frame) "is_finished": <float>, // 1.0 on the final frames of the demonstration "world_transforms": { ... } // reference-frame transforms (cam0, virtual_static_anchor) }, "obs": { // image / mask paths for this frame "rgb_path", "mask_arm_path", "mask_obj_path", // the COMBINED arm+object mask; per-object masks are mask_obj1.png / mask_obj2.png "rgb_WoArm_path", "rgb_WArmObjKpts_path", "rgb_WoArm_WArmObjKpts_path", ... }, "entities": { "hands": { "right": { "T_hand_to_world": [4×4 SE(3)], "grasp": <float> } }, "objects": { "obj1": { "T_obj_to_world": [4×4], "is_dynamic": <bool> }, "obj2": { ... } }, // ablation only (empty unless mediapipe/wilor/hamer were enabled): "hands_mediapipe": {...}, "hands_wilor": {...}, "hands_hamer": {...} } }