- We release the project page of Holi-Spatial, check on here.
- We have released a subset of the Holi-Spatial dataset, featuring 2,000+ high-quality Gaussian models, each accompanied by its corresponding mesh and scene-level 3D bounding box annotations, together with HoliSpatial-QA-2M, a 2-million-scale QA dataset built upon part of these richly annotated 3D assets.
- We release all model checkpoints.
- We will release the pipeline code in July.
This repository contains the data curation pipeline used to turn ScanNet, ScanNet++, or DL3DV scenes into 3DGS geometry, mesh-guided masks, object/region 3D annotations, spatial QA, and LLaMA-Factory training data.
The pipeline follows the three stages described in the Holi-Spatial paper:
- Geometric optimization: DA3 depth/point cloud initialization, then PGSR/3DGS training.
- Image-level perception: VLM class or region discovery, then SAM3 mask generation.
- Scene-level lift and refinement: lift masks into 3D, merge/filter boxes, caption instances, and synthesize spatial QA.
Paper: https://arxiv.org/abs/2603.07660
inference_da3_scannetppv2.py,run_da3.sh: unified DA3 preprocessing for ScanNet, ScanNet++, and DL3DV.PGSR/: PGSR training, rendering, and mesh-to-mask code used by this pipeline.3dgs_train.sh: batch PGSR/3DGS training entrypoint for ScanNet, ScanNet++, and DL3DV.mesh.sh: render meshes and generate mesh-guided masks for ScanNet v2, ScanNet++, and DL3DV.classic_vllm.py,classic_region.py: VLM-based object and functional-region label discovery.sam3.py: SAM3 text-prompted mask generation.3d_bounding_instance_gs_rerun_da3.py: object 2D-to-3D lifting/refinement.3d_bounding_instance_gs_region.py: functional-region 2D-to-3D lifting/refinement.postprocess_3d_bbox_aabb.py: floor-aligned AABB-style box post-processing before QA generation.scannetppv2_new.sh,scannetppv2_region.sh,scannetv2_all.sh,scannetv2_region.sh,DL3DV_new.sh,dl3dv_new_2k.sh: dataset-specific annotation batch scripts.qa_generation/: instance captions, spatial QA generation, QA filtering, and LLaMA-Factory conversion.
Create a CUDA-enabled Python environment, then install the common dependencies:
pip install -r requirements.txt
pip install -e PGSR/submodules/diff-plane-rasterization
pip install -e PGSR/submodules/simple-knnInstall or expose the external model packages required by the pipeline:
- Depth Anything 3: provides
depth_anything_3.api.DepthAnything3. - SAM3 checkpoint/assets:
sam3.pydownloads the default checkpoint and BPE asset fromfacebook/sam3when local paths are not provided. - A VLM served through an OpenAI-compatible vLLM endpoint. All scripts default to
http://localhost:8000/v1orhttp://localhost:8000/v1/chat/completions.
ScanNet v2:
scannetv2/scans/<scene_id>/
color/
pose/
intrinsic/
ScanNet++:
scannetppv2/data/<scene_id>/
dslr/nerfstudio/transforms_undistorted.json
dslr/resized_undistorted_images/
DL3DV:
processed_dl3dv_ours/1K/<scene_id>/
dense/cam/
dense/rgb/
The QA stage also needs a covisibility root, for example scannetppv2_wai/<scene_id>/covisibility/v0/*.npy or dl3dv_wai/1K_<scene_id>/*.npy.
Process a directory of scenes:
SCENE_ROOT=scannetppv2/data bash run_da3.shProcess a single scene:
SCENE_DIR=scannetppv2/data/0a5c013435 bash run_da3.shOutputs per scene:
depth_da3/<image_stem>.npypointcloud_da3.ply
DL3DV example:
SCENE_ROOT=processed_dl3dv_ours/1K bash run_da3.shFor pre-split scene lists, such as ScanNet v2 lists:
SPLIT_DIR=scannetv2/splits NUM_GPUS=8 bash run_da3.shThe generic batch script supports ScanNet v2, ScanNet++, and DL3DV. Set roots explicitly for your dataset.
ScanNet v2 example:
SCENE_ROOT=scannetv2/scans \
OUTPUT_ROOT=pgsr_scannetv2_all \
LOG_FILE=train_pgsr_progress_scannetv2.json \
bash 3dgs_train.shScanNet++ example:
SCENE_ROOT=scannetppv2/data \
OUTPUT_ROOT=pgsr_scannetppv2_all \
LOG_FILE=train_pgsr_progress_scannetppv2.json \
bash 3dgs_train.shThe expected trained model output is:
<OUTPUT_ROOT>/<scene_id>/point_cloud/iteration_30000/point_cloud.ply
ScanNet v2 example:
DATA_ROOT=scannetv2/scans \
OUTPUT_ROOT=pgsr_scannetv2_all \
bash mesh.shScanNet++ example:
DATA_ROOT=scannetppv2/data \
OUTPUT_ROOT=pgsr_scannetppv2_all \
bash mesh.shOutputs:
<3dgs_output>/<scene_id>/mesh/tsdf_fusion_post.ply<data_root>/<scene_id>/mask/
Start an OpenAI-compatible vLLM server, then run object annotation.
ScanNet++ object instances:
DATA_ROOT=scannetppv2/data \
SCENES_DIR=pgsr_scannetppv2_all \
CLASS_JSON_DIR=Qwen3VL-32B-Scannetppv2 \
MASK_ROOT=sam3_masks_scannetppv2_new \
OUTPUT_JSON_DIR=output_scannetppv2_new \
VLLM_API_BASE=http://localhost:8000/v1 \
VLLM_CHAT_URL=http://localhost:8000/v1/chat/completions \
bash scannetppv2_new.shScanNet++ functional regions:
DATA_ROOT=scannetppv2/data \
SCENES_DIR=pgsr_scannetppv2_all \
CLASS_JSON_DIR=Qwen3VL-32B-Scannetppv2_region \
MASK_ROOT=sam3_masks_scannetppv2_region \
OUTPUT_JSON_DIR=output_scannetppv2_region_new \
VLLM_API_BASE=http://localhost:8000/v1 \
VLLM_CHAT_URL=http://localhost:8000/v1/chat/completions \
bash scannetppv2_region.shThe same pattern applies to scannetv2_all.sh, scannetv2_region.sh, DL3DV_new.sh, and dl3dv_new_2k.sh.
Annotation outputs are one JSON per scene, containing instance labels, source images, masks, 3D boxes, and metadata needed by QA generation.
Convert the raw 3D object boxes into floor-aligned AABB-style boxes before QA generation:
python postprocess_3d_bbox_aabb.py \
--input_dir output_scannetppv2_new \
--output_dir output_scannetppv2_new_aabb \
--floor_label floor \
--axis_method largest_face \
--extent_mode keepFor ScanNet v2, use the corresponding object annotation directory:
python postprocess_3d_bbox_aabb.py \
--input_dir output_scannetv2_new \
--output_dir output_scannetv2_new_aabb \
--floor_label floorThe region JSONs can be kept as generated by the region annotation step.
Generate object descriptions:
python qa_generation/generate_3d_instance_description.py \
--input_dir output_scannetppv2_new_aabb \
--output_dir output_scannetppv2_new_aabb_with_descriptions \
--dataset_root scannetppv2/data \
--vllm-api-url http://localhost:8000/v1/chat/completionsGenerate object + region spatial QA:
python qa_generation/generate_two_view_qa_region.py \
--data-root scannetppv2/data \
--wai-root scannetppv2_wai \
--marker-types language_description \
--bbox-json-folder output_scannetppv2_new_aabb_with_descriptions \
--region-bbox-json-folder output_scannetppv2_region_new \
--output output_QA_new_lang_add_regionFilter repeated/ambiguous descriptions:
python qa_generation/filter_qa_repeat_descriptions.py \
--data-root scannetppv2/data \
--bbox-json-folder output_scannetppv2_new_aabb_with_descriptions \
--output output_QA_new_lang_add_region \
--output-filter-repeat output_QA_new_add_region_filter_repeat \
--vllm-api-url http://localhost:8000/v1/chat/completionspython qa_generation/convert_qa_to_llamafactory.py \
--image-root scannetppv2/data \
--qa-json-dir output_QA_new_add_region_filter_repeat \
--output-dir output_llamafactory_QA_add_region_langThe final output contains dataset.jsonl and copied/rendered images in the format expected by LLaMA-Factory multimodal SFT.
- DA3:
depth_da3/,pointcloud_da3.ply - PGSR:
pgsr_*/<scene>/point_cloud/iteration_30000/point_cloud.ply - Mesh/masks:
mesh/tsdf_fusion_post.ply,<data_root>/<scene>/mask/ - Object boxes:
output_scannetppv2_new/<scene>.json - AABB object boxes:
output_scannetppv2_new_aabb/<scene>.json - Region boxes:
output_scannetppv2_region_new/<scene>.json - Descriptions:
output_scannetppv2_new_aabb_with_descriptions/<scene>.json - QA:
output_QA_new_add_region_filter_repeat/<scene>.json - LLaMA-Factory:
output_llamafactory_QA_add_region_lang/dataset.jsonl
- All large datasets, model checkpoints, masks, QA outputs, and 3DGS outputs are ignored by
.gitignore. - The batch scripts skip scenes whose final output JSON or trained point cloud already exists.
- For single-scene debugging, call the Python scripts directly with
--scene,--data-root,--scene-json,--mask-root, and--model-path.
This pipeline builds on and benefits from several open research works and foundation models:
We also thank the dataset providers:
We thank the authors and maintainers of these projects for making their work available to the community.
If you find this work useful, please consider citing:
@article{gao2026holi,
title={Holi-spatial: Evolving video streams into holistic 3d spatial intelligence},
author={Gao, Yuanyuan and Li, Hao and Liu, Yifei and Ji, Xinhao and Gong, Yuning and Liao, Yuanjun and Liu, Fangfu and Zhang, Manyuan and Yang, Yuchen and Xu, Dan and others},
journal={arXiv preprint arXiv:2603.07660},
year={2026}
}