SphereSfM Add Camera Path
Grow a splat dataset instead of rebuilding it — add a camera path to what you've got
- pano_frames_1
- pano_frames_2
- pano_frames_3
- pano_frames_4
- model_dir
- num_images
- num_points
- num_added_frames
You built a scene with SphereSfM Dataset, trained it, and now you want to fly through a room the original camera path never touched. The obvious move - re-run the whole pipeline from scratch - is also the wasteful one: feature extraction, matching, and spherical bundle adjustment are all expensive, and you'd redo every frame you already solved. SphereSfM Add Camera Path exists so you don't. It takes one more WAN pano trajectory (a single Camera Plot + WAN group) and registers it into the dataset you already built, growing images/ and the sparse reconstruction instead of starting over.
This is incremental SfM, and it's genuinely handy - you can keep flying the camera through new corners of a scene and each run folds the new views into the same reconstruction. It's also chainable: every successful add is promoted to the base model, so you can add a second, third, fourth path by running this node again against the same dataset.
How it works
The base build leaves behind _spheresfm_work/ - the equirect frames, the feature database.db, and the SPHERE model. This node reuses all of it, so the new frames are solved in the same world as the originals:
- New equirect frames are appended to
_spheresfm_work/equirect(numbering continues). feature_extractorruns on the new frames only (their own SPHERE camera, same database).- A matcher runs -
exhaustiveby default, because the new clip is a separate trajectory and has to be matched against the existing frames, not just its own neighbors. image_registratorpins the new images against the existing 3D points,point_triangulatoradds new points, andsphere_cubic_reprojecerwrites the new cube faces intoimages/, replacingsparse/0with the extended model.
Inputs that matter
dataset_dir(required) - the existing dataset. Wire the Dataset Project node'sdataset_dirhere, or type the folder. It must contain_spheresfm_work/from amode=colmap_nowbuild;panorama_onlydatasets can't be extended.pano_frames_1- the new WAN equirect video. "Optional" in the schema, required in practice.pano_frames_2/3/4concatenate more trajectories.adjust_existing_cameras- off (default) keeps existing poses bit-stable; purely additive, only new faces are written. On lets a global solve nudge the old poses to fit the new data - and re-renders every cube face, so only flip it if the new path reveals the base was slightly off.matcher_type- keepexhaustiveunless the new clip is a direct temporal continuation of the last one.retriangulate(default on) - run the triangulator so new images contribute 3D points; off is faster and sparser.abs_pose_min_num_inliers- min verified inliers to register a new image (default 30). Lower it if new frames won't register; raise it to be stricter.face_size- set the same value the base dataset used so the new faces match the existing ones (0= auto).
Outputs: model_dir, num_images, num_points, and num_added_frames so you can confirm the add actually registered something.
Install
Same pack-wide install as the base node:
cd ComfyUI/custom_nodes
git clone https://github.com/mickmumpitz/ComfyUI-SplatKit
python_embeded\python.exe -m pip install -r ComfyUI-SplatKit/requirements.txt
Restart ComfyUI. The colmap_sphere.exe binary auto-downloads on first SfM run (SHA-256 verified, NVIDIA Turing+ for GPU matching, CPU fallback otherwise). Ready-made graph: workflows/1b_camera_plot_add_to_dataset.json.
Common issues
- "dataset folder does not exist" - you built it with
mode=panorama_only, or pointed at the wrong folder. It needs acolmap_nowbuild with_spheresfm_work/. - New frames won't register - the new path must share view with the existing scene (start it near where earlier paths looked) so SfM can match features across them, and it still needs real movement/parallax. Lower
abs_pose_min_num_inliers, double-checkmatcher_typeisexhaustive, and make sure the new clip actually overlaps the old views. - Run it before upscaling the dataset, and keep
adjust_existing_camerasoff unless you have a reason - the purely additive default is what keeps your already-working reconstruction untouched.
One more thing: running this node deletes the base run's solve fingerprint, so a later reuse_solve on the base node re-solves rather than inheriting the extended model. That's intentional - the solve on disk is no longer the base run's.
Inputs (17)
| Name | Type | Default | Description |
|---|---|---|---|
| dataset_dir | STRING | The EXISTING SphereSfM dataset to add to -- wire the Dataset Project node's dataset_dir here (the same value the base SphereSfM node used as output_name), or type the dataset folder name/path. Must contain _spheresfm_work/ from a mode=colmap_now build. | |
| pano_frames_1opt | IMAGE | The new WAN equirect pano video (one Camera Plot + WAN group) to add to the dataset. Required in practice. | |
| pano_frames_2opt | IMAGE | Optional extra new trajectory; concatenated after pano_frames_1. | |
| pano_frames_3opt | IMAGE | Optional third new trajectory. | |
| pano_frames_4opt | IMAGE | Optional fourth new trajectory. | |
| frame_strideopt | INT | 11–100 | Use every Nth new frame. Thin long clips but keep matching overlap. |
| max_framesopt | INT | 00–1000 | Cap NEW frames after stride (0 = no cap). |
| matcher_typeopt | COMBO | exhaustive | How to match the new frames. exhaustive (default) matches them against the EXISTING frames too, which is what lets a separate path link into the reconstruction -- keep this unless the new clip is a direct temporal continuation of the last one. |
| adjust_existing_camerasopt | BOOLEAN | false | OFF (default): keep the existing cameras/poses FIXED -- purely additive, original views stay bit-stable, only new faces written. ON: let a global solve refine existing poses to fit the new data (re-renders EVERY cube face; use only if the new path reveals the base was slightly off). |
| retriangulateopt | BOOLEAN | true | Run point_triangulator after registration so the newly added images contribute 3D points (denser cloud in the added region). Off = register poses only (faster, sparser). |
| face_sizeopt | INT | 00–2048 | Cube-face resolution (px). 0 = auto (~equirect_w/4). Set the SAME value the base dataset used so new faces match the existing ones. |
| max_num_featuresopt | INT | 81921024–32768 | — |
| peak_thresholdopt | FLOAT | 0.00660–0.1 | — |
| edge_thresholdopt | FLOAT | 101–50 | — |
| max_num_matchesopt | INT | 327684096–131072 | — |
| abs_pose_min_num_inliersopt | INT | 3010–200 | Min verified inliers to register a new image against the existing 3D points. Lower if new frames won't register; raise for stricter. |
| image_orderopt | COMBO | camera_major | Order recorded in the dataset marker for upscaling (COLMAP files untouched). camera_major groups each cube face into a coherent per-view sub-video across ALL trajectories; frame_major keeps plain lexical order. |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| model_dir | STRING | — |
| num_images | INT | — |
| num_points | INT | — |
| num_added_frames | INT | — |