This document outlines the steps for processing VLM 3R data, focusing on datasets with ground truth annotations.
- Quick Start: ScanNet Preprocessing Workflow
- 1. Datasets with Ground Truth Annotations
- 2. Data Preprocessing Details
- 3. Downstream Task Generation (QA)
We provide a complete, end-to-end workflow for processing the ScanNet dataset, from raw data to the final QA pairs. This includes detailed steps and command-line examples for each stage of the process. For the full guide, please refer to the documentation at src/metadata_generation/ScanNet/scannet.md.
Follow the instructions from the respective repositories to download the raw data:
- ScanNet: Download data to
data/raw_data/scannet. Follow instructions at https://github.com/ScanNet/ScanNet. - ScanNet++: Download data to
data/raw_data/scannetpp. Follow instructions at https://github.com/scannetpp/scannetpp. - ARKitScenes: Download data to
data/raw_data/arkitscenes. Follow instructions at https://github.com/apple/ARKitScenes.
This section outlines the general pipeline for preprocessing 3D scene data for tasks. The goal is to extract structured scene-level and frame-level metadata from raw inputs, which can then be used to generate diverse question-answering (QA) datasets.
The preprocessing pipeline requires the following types of data for each scene:
- Point Cloud (PCD): A 3D point cloud representation of the scene (e.g., from
.plyor.pcdfiles). Each point should ideally be associated with:- Semantic label ID (indicating the object category).
- Instance label ID (distinguishing individual objects of the same category).
- Coordinates (x, y, z).
- Color (R, G, B).
- Video: A video recording capturing a traversal through the scene (e.g.,
.mp4format). - Sampled Frame Data: A collection of frames sampled from the video or reconstruction sequence, including:
- Color Images: RGB images corresponding to sampled viewpoints.
- Depth Maps: Per-pixel depth information for each sampled frame.
- Instance Masks: Segmentation masks identifying object instances within each frame.
- Camera Poses: The 6DoF camera pose (rotation and translation, typically as a 4x4 matrix) for each sampled frame, defining its position and orientation in the world coordinate system (often aligned with the point cloud).
- Camera Intrinsics: The intrinsic parameters of the camera used to capture the video/frames (focal length
fx,fy; principal pointcx,cy).
(Note: Specific scripts or tools might be needed to generate the Sampled Frame Data from the raw Video and Point Cloud if not already available.)
The core preprocessing involves generating two types of metadata files:
-
Scene Metadata Generation:
- Processes the input Point Cloud.
- Extracts scene-wide information such as:
- Overall scene dimensions (e.g., room area).
- Scene center coordinates.
- Counts of different object categories present.
- 3D bounding boxes (including center, size, and orientation) for each object instance.
- Typically saves this information in a structured format like JSON (e.g.,
scene_metadata.json).
-
Frame Metadata Generation:
- Processes the Sampled Frame Data (Color, Depth, Masks, Poses) and Camera Intrinsics.
- Extracts frame-specific information such as:
- Camera pose for each frame.
- 2D bounding boxes for object instances visible in each frame.
- Typically saves this information, grouped by scene, in a structured format like JSON (e.g.,
frame_metadata.json).
The specific structure of the output metadata JSON files, based on the current implementation (e.g., scannet_metadata.py, scannet_frame_metadata.py), is as follows:
-
Scene Metadata (
scannet_metadata.json): A JSON file containing a dictionary where keys are scene IDs (e.g., "scene0000_00"). Each scene ID maps to a dictionary with the following structure:{ "scene_id": { // e.g., "scene0000_00" "video_path": "relative/or/absolute/path/to/scene_id.mp4", "dataset": "scannet", // Or other dataset identifier "room_size": 123.45, // Area in square units (calculated from point cloud) "room_center": [x, y, z], // List of floats for center coordinates "object_counts": { "category_name": count, // ... }, "object_bboxes": { "category_name": [ { "centroid": [cx, cy, cz], // Center coordinates "axesLengths": [lx, ly, lz], // Length of axes "normalizedAxes": [ // 3x3 rotation matrix as flattened list or list of lists r11, r12, r13, r21, r22, r23, r31, r32, r33 ], "min": [min_x, min_y, min_z], // Minimum corner of the axis-aligned bounding box "max": [max_x, max_y, max_z], // Maximum corner of the axis-aligned bounding box "instance_id": N // Instance ID from the dataset }, // ... other instances of this category ], // ... other categories } }, // ... other scene IDs } -
Frame Metadata (
scannet_frame_metadata.json): A JSON file containing a dictionary where keys are scene IDs. Each scene ID maps to a dictionary with frame-level information:{ "scene_id": { // e.g., "scene0000_00" "camera_intrinsics": { "fx": float, "fy": float, "cx": float, "cy": float }, "img_width": 640, // Image width used during processing "img_height": 480, // Image height used during processing "frames": [ { "frame_id": 0, // Integer frame index/number from sampled data "file_path_color": "color/scene_id/000000.jpg", // Relative path to color image within processed dir "file_path_depth": "depth/scene_id/000000.png", // Relative path to depth map within processed dir "camera_pose_camera_to_world": [ // 4x4 matrix as list of lists [r11, r12, r13, tx], [r21, r22, r23, ty], [r31, r32, r33, tz], [0.0, 0.0, 0.0, 1.0] ], "bboxes_2d": [ { "instance_id": 0, // Instance ID from the dataset "bbox_2d": [xmin, ymin, xmax, ymax] // Integer pixel coordinates }, // ... other detected instances in this frame ] }, // ... other frames in this scene ] }, // ... other scene IDs }
This section details the Question-Answering (QA) tasks. We first introduce VSI-Bench, a benchmark from a published paper, and then describe our implemented VSTIbench tasks.
This section details the QA tasks in the VSI-Bench benchmark from "Thinking in Space: How Multimodal Large Language Models See, Remember, and Recall Spaces". The benchmark has over 5,000 QA pairs from 288 real-world indoor videos, categorized into Configurational, Measurement Estimation, and Spatiotemporal tasks. We extend our gratitude to the VSI-Bench team for providing the original data generation scripts, which served as a significant reference for our work.
Task Summary Table (VSI-Bench)
| Task Name | Task Category | Answer Type |
|---|---|---|
| Object Count | Configurational | Numerical |
| Relative Distance | Configurational | Multiple Choice |
| Relative Direction | Configurational | Multiple Choice |
| Route Plan | Configurational | Multiple Choice |
| Object Size | Measurement | Numerical |
| Absolute Distance | Measurement | Numerical |
| Room Size | Measurement | Numerical |
| Appearance Order | Spatiotemporal | Multiple Choice |
The generated scene and frame metadata serve as input for generating these QA pairs.
These tasks test a model's understanding of the spatial layout and relationships.
- Object Count: Asks for the total number of instances of a specific object category (e.g., "How many chairs are there?").
- QA Generation (
get_obj_count_qa.py): This task generates multiple-choice questions based onscene_metadata.json. It iterates through theobject_countsfor each object type in the scene. For categories with more than one instance, it formulates a question. The correct answer is the actual count from the metadata. The other three distractor options are generated by adding small, random offsets to the correct answer, creating a four-choice question.
- QA Generation (
- Relative Distance: Asks which of four candidate objects is closest to a target object (e.g., "...which of these objects...is the closest to the printer?").
- QA Generation (
get_obj_rel_distance_v1_qa.py,...v2_qa.py,...v3_qa.py): This task generates multiple-choice questions asking which of several candidate objects is closest to a "primary" object.- Object Selection: The "primary" object (the reference for distance) is chosen from unique object categories (with only one instance in the scene) to ensure clarity. Candidate objects are selected from the remaining objects. V1 provides 4 choices, V2 provides 3, and V3 provides 2.
- Distance Calculation: The script calculates the minimum Euclidean distance between the 3D bounding boxes of the primary object and each candidate object.
- Ambiguity Filtering: To create clear questions, the script filters out cases where: 1) The distances from any two candidate objects to the primary object are too close to each other (e.g., within 15-30 cm, depending on room size), making them hard to distinguish. 2) The closest candidate is already touching or extremely close to the primary object (less than 15 cm).
- Answer: The category of the candidate object closest to the primary object is the correct answer.
- QA Generation (
- Relative Direction: Asks for the direction of a 'querying object' relative to an observer's position and orientation (e.g., "If I am standing by the refrigerator and facing the sofa, is the kettle to my left, right, or back?").
- QA Generation (
get_obj_rel_direction_v1_qa.py,...v2_qa.py,...v3_qa.py): This task generates multiple-choice questions of the form, "If I am standing at object A and facing object B, in which direction is object C?"- Object Selection: The script selects three distinct and unique (instance count of 1) objects from the scene to serve as the observer's position (A), the orientation reference (B), and the queried target (C).
- Direction Calculation: The script performs calculations on a 2D plane. It sets object A as the origin and defines the vector from A to B as "forward". It then calculates the angle between this "forward" vector and the vector from A to C.
- Answer Options: Based on the angle, the script categorizes object C into different directions. There are several versions:
- V1: Four diagonal categories (front-left, front-right, back-left, back-right).
- V2: Three main directions (left, right, back).
- V3: Two relative directions (left, right).
- Ambiguity Filtering: To ensure clarity, the script excludes cases where the objects are inappropriately spaced (too close or too far) or where the target object C lies on the boundary between two direction categories (e.g., exactly to the left).
- QA Generation (
- Route Plan: Asks the model to fill in missing turn commands in a navigation sequence (e.g., "...Fill in this route: 1. Go forward until the washing machine 2. [?]...").
- QA Generation: (Implementation in progress)
These tasks require estimating quantitative spatial properties.
- Object Size: Asks for the length of the longest dimension of an object in centimeters (e.g., "What is the length of the longest dimension...of the refrigerator in centimeters?").
- QA Generation (
get_obj_size_qa.py): This task generates multiple-choice questions about the size of unique objects (instance count of 1) in the scene.- Answer Calculation: The script reads the three
axesLengthsof the object's 3D bounding box from the metadata, finds the maximum value, and converts it from meters to centimeters to serve as the correct answer. - Option Generation: The other three distractor options are created by generating random numbers within a certain percentage range (e.g., 40% to 180%) of the correct answer, forming a four-choice question.
- Answer Calculation: The script reads the three
- QA Generation (
- Absolute Distance: Asks for the Euclidean distance between two objects in meters (e.g., "...what is the distance between the bed and the sofa in meters?").
- QA Generation (
get_obj_abs_distance_qa.py): This task generates multiple-choice questions about the absolute distance between pairs of unique objects (instance count of 1) in the scene.- Object Selection & Distance Calculation: The script iterates through all unique objects in the scene and calculates the minimum Euclidean distance between the 3D bounding boxes for each pair. It skips pairs that are closer than 0.2 meters.
- Answer & Options: The calculated distance (in meters, rounded to one decimal place) is the correct answer. The other three distractor options are created by generating random numbers near the correct answer.
- QA Generation (
- Room Size: Asks for the estimated area of the room in square meters (e.g., "What is the size of this room (in square meters)?").
- QA Generation (
get_room_size_qa.py): This task generates one multiple-choice question per scene about its total area.- Answer Calculation: The script directly reads the
room_sizevalue fromscene_metadata.jsonand rounds it to one decimal place to use as the correct answer. - Option Generation: The other three distractor options are created by generating random numbers near the correct answer.
- Answer Calculation: The script directly reads the
- QA Generation (
This task tests processing spatial information over time.
- Appearance Order: Asks for the order in which four object categories first appear in the video (e.g., "What will be the first-time appearance order of the following categories...: basket, printer, refrigerator, kettle?").
- QA Generation (
get_spatial_temporal_appearance_order_qa.py): This task generates multiple-choice questions about the first-appearance order of four object categories in the video.- First Appearance Time Calculation: The script first iterates through the time-sorted
frame_metadata.jsonto find the first frame number where each object instance appears. It then maps the instance ID to its category usingscene_metadata.jsonto determine the first appearance frame number (and converts it to seconds) for each category. - Object Selection & Ambiguity Filtering: The script randomly selects four categories from all that appear in the scene. To ensure a clear answer, it filters out combinations where the first appearance times are too close (e.g., less than 1 second apart).
- Answer & Option Generation:
- The correct answer is the list of the four categories sorted in ascending order of their first appearance time.
- The four categories are mentioned in a random order in the question to avoid giving clues.
- Distractor options are generated by creating other random permutations of the four categories.
- First Appearance Time Calculation: The script first iterates through the time-sorted
- QA Generation (
The generated scene_metadata.json and frame_metadata.json files serve as the primary input for the various task-specific QA generation scripts located in the src/tasks directory. Each script reads the metadata and formulates questions and answers related to its specific focus.
Task Summary Table (VSTIbench)
| Task Name | Task Level | Answer Type |
|---|---|---|
| Camera-Object Absolute Distance QA | Frame-Level | Numerical |
| Camera-Object Relative Distance QA (V1, V2, V3) | Frame-Level | Multiple Choice |
| Object-Object Relative Position QA (Near/Far, Left/Right, Up/Down) | Frame-Level | Multiple Choice |
| Camera Displacement QA | Sequence-Level | Numerical |
| Camera Movement Direction QA (V1, V2, V3) | Sequence-Level | Multiple Choice |
These tasks generate questions based on the information available within a single frame or the scene's point cloud.
- Camera-Object Absolute Distance QA (
get_cam_obj_abs_dist_qa.py): Generates frame-level questions asking for the approximate Euclidean distance (in meters) between the camera's position in a specific frame and the closest point on the 3D bounding box of a target unique object instance, expecting a numerical answer.- Method: Calculates the 3D Euclidean distance between the camera's world coordinates (from frame pose) and the closest point on the 3D bounding box of the object (derived from scene metadata).
- Example Question (Template:
VSTI_CAMERA_OBJ_DIST_TEMPLATE): "What is the approximate distance (in meters) between the camera (or the person filming) and the nearest point of the nightstand in frame 2 of 32?"
- Camera-Object Relative Distance QA (V1, V2, V3): Generates frame-level multiple-choice questions asking which of several candidate object instances is closest to the camera in a specific frame, measuring from the closest point of each object. This task comes in three variations, differing by the number of choices provided:
- V1 (
get_cam_obj_rel_dist_qa_v1.py): 4 multiple-choice options. (Template:VSTI_CAMERA_OBJ_REL_DIST_TEMPLATE_V1) - V2 (
get_cam_obj_rel_dist_qa_v2.py): 3 multiple-choice options. (Template:VSTI_CAMERA_OBJ_REL_DIST_TEMPLATE_V2) - V3 (
get_cam_obj_rel_dist_qa_v3.py): 2 multiple-choice options. (Template:VSTI_CAMERA_OBJ_REL_DIST_TEMPLATE_V3) - Method: Calculates the 3D Euclidean distance between the camera's position (from frame pose) and the closest point on the 3D bounding box of each candidate object instance (derived from scene metadata). The candidate object with the minimum distance to the camera is the correct answer.
- Example Question (V2, 3 options): "Measuring from the closest point of each object, which of these objects (chair, sofa, lamp) is the closest to the camera in frame 10 of 32?"
- Example Options: A. chair, B. sofa, C. lamp
- Example Answer: A (if the chair is the closest to the camera among the options)
- V1 (
- Object-Object Relative Position QA (Near/Far, Left/Right, Up/Down): Generates frame-level, 2-choice multiple-choice questions asking for the spatial relationship between two unique object instances within a frame. This task is split into three separate QA generation scripts, one for each spatial dimension:
- Near/Far (
get_obj_obj_rel_pos_nf_qa.py): Asks if object A is nearer or farther than object B, relative to the camera. (Template:VSTI_OBJ_OBJ_REL_POS_NF_TEMPLATE) - Left/Right (
get_obj_obj_rel_pos_lr_qa.py): Asks if object A is to the left or right of object B. (Template:VSTI_OBJ_OBJ_REL_POS_LR_TEMPLATE) - Up/Down (
get_obj_obj_rel_pos_ud_qa.py): Asks if object A is up or down relative to object B. (Template:VSTI_OBJ_OBJ_REL_POS_UD_TEMPLATE) - Method: Transforms the 3D bounding box vertices of both unique objects into the camera's coordinate system for the given frame.
- For Near/Far: Compares the Z-coordinates (depth). If object A's maximum Z is less than object B's minimum Z (by a threshold), A is 'Near'. If object A's minimum Z is greater than object B's maximum Z (by a threshold), A is 'Far'.
- For Left/Right: Compares the X-coordinates. If object A's maximum X is less than object B's minimum X (by a threshold), A is 'Left'. If object A's minimum X is greater than object B's maximum X (by a threshold), A is 'Right'.
- For Up/Down: Compares the Y-coordinates (+Y is typically Down). If object A's maximum Y is less than object B's minimum Y (by a threshold), A is 'Up' (less Y). If object A's minimum Y is greater than object B's maximum Y (by a threshold), A is 'Down' (more Y).
- Uses only pairs where one object is entirely nearer/farther, left/right, or up/down than the other.
- Example Questions:
- (Near/Far): "In frame 5 of 32, relative to the camera, is the chair Near or Far compared to the table?"
- (Left/Right): "In frame 12 of 32, relative to the sofa, is the lamp to the Left or Right?"
- (Up/Down): "In frame 20 of 32, relative to the desk, is the monitor Up or Down?"
- Example Options (for one question type, e.g., Near/Far): A. Near, B. Far
- Example Answer (for the Near/Far example): A (if the chair was entirely closer to the camera than the table)
- Near/Far (
These tasks generate questions based on information aggregated across a sequence of frames.
- Camera Displacement QA (
get_camera_displacement_qa.py): Generates sequence-level questions asking for the approximate Euclidean distance the camera traveled between two specified frames, expecting a numerical answer.- Method: Calculates the Euclidean distance between the camera's world positions (translation components) at the start and end frames of the specified sequence using their camera_pose_camera_to_world metadata.
- Example Question: "Approximately how far (in meters) did the camera move between frame 10 and frame 30 of 32?"
- Example Answer: 1.8 (if the calculated distance between camera positions was 1.8 meters)
- Camera Movement Direction QA (V1, V2, V3): Generates sequence-level multiple-choice questions asking about the primary direction of the camera's translation (movement) during a specified sequence, relative to its starting orientation. This task is split into three variations based on the number of choices:
- V1 (
get_camera_movement_direction_qa_v1.py): 4 multiple-choice options (Forward, Backward, Left, Right). (Template:VSTI_CAMERA_MOVEMENT_DIRECTION_TEMPLATE_V1) - V2 (
get_camera_movement_direction_qa_v2.py): 3 multiple-choice options. (Template:VSTI_CAMERA_MOVEMENT_DIRECTION_TEMPLATE_V2) - V3 (
get_camera_movement_direction_qa_v3.py): 2 multiple-choice options. (Template:VSTI_CAMERA_MOVEMENT_DIRECTION_TEMPLATE_V3) - Method: Compares the camera poses (
camera_pose_camera_to_world) of the start and end frames for a given sequence. It calculates the displacement vector between these two points, transforms this vector into the starting frame's local coordinate system, and then determines the primary direction of movement (e.g., Forward, Backward, Left, Right). Note that this method considers only the net displacement, not the full path taken between the frames. - Example Question (V2, 3 options): "During the sequence from frame 5 to frame 20 of 32, what was the primary direction of the camera's movement?"
- Example Options: A. Forward, B. Left, C. Right
- Example Answer: A (if the camera primarily moved forward)
- V1 (