Skip to content

Latest commit

 

History

History
287 lines (228 loc) · 14 KB

README.md

File metadata and controls

287 lines (228 loc) · 14 KB

HumanEgo — Preprocessing

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.


1. Quick start

pip install huggingface_hub        # for downloading
# and follow the repo README to install the full preprocessing environment

Download 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_bread

Everything 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.


2. Data layout

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)

3. Pipeline architecture

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 in cfg/preprocess/base/Preprocess.yaml → hand_tracking_methods, and un-comment self.preprocess_hands() in preprocess/Preprocess.py (it is commented out by default).


4. Output reference — every file

4.1 Top-level preprocess/ files

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.

4.2 preprocess/vis/ — visualization clips (.mp4 + .gif)

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.

4.3 preprocess/all_data/<idx>/ — per-frame data

<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.

4.4 training_data.json schema

The final per-frame dataloader target produced by DatasetGen:

{
  "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": {...}
  }
}

4.5 preprocess/cfg/

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.


5. Configuration

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 sets hand_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>.yaml is missing, preprocessing still runs but uses the base defaults — whose dinosam_prompt is a placeholder ("a pretty cat ."), so it won't detect your objects. A task file is therefore effectively required.

5.1 Task-config fields

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.

5.2 Adding a new task

  1. Create cfg/preprocess/tasks/<your_task>.yaml.
  2. Set DINOSAM.dinosam_prompt for each object you manipulate (obj1, obj2, …) plus the arm prompt.
  3. Set AriaHands.hand_selection (and grasp_threshold if needed), and pick a CamTriangulator.pose_method per object.
  4. Run python -m preprocess.Preprocess --mps_path <recording_dir> --task <your_task>.
  5. Verify: check …/preprocess/dinosam_mask_obj*.png to 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"

6. Downloading more data

# 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-only

all_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.