Load Dataset Images (Ordered)
Feed a temporal upscaler one coherent view at a time
- meta_batch
- images
- order_names
- canonical_dir
- group_sizes
- batch_size
- passthrough_json
- job
A SphereSfM dataset's images are six cube faces per frame (front, back, left, right, up, down). If you load them in plain lexical order and hand them to a temporal upscaler like SeedVR2, the view direction flips six times per frame - the model sees a coherent bit of front wall, then sky, then floor, and its temporal context is worthless. Load Dataset Images (Ordered) fixes that by reading the dataset's p2s_dataset.json marker and loading each cube face as its own coherent per-view sub-video (camera-major order), so SeedVR2 gets a fixed view per sequence. This is the difference between upscaled frames that look like they came from the same camera and frames that look like six different videos stitched together.
It's also where you set the upscale's VRAM strategy. The generic loader + Meta Batch Manager pattern streams frames in chunks; this node's meta_batch input takes a VHS Batch Manager and streams frames_per_batch frames at a time instead of loading the whole dataset into RAM - the stated fix for "the upscaled result does not fit in RAM." Set frames_per_batch to a divisor of the per-view length (81 → 81, 27, 9, 3, 1) so no chunk straddles a view boundary.
Inputs that matter
dataset_name/dataset_path- the SphereSfM dataset, same as the other upscale nodes.camera_index--1loads all cameras;0..N-1loads one view/trajectory's sub-video. The console lists available cameras each run.select_every_nth/drop_partial_stride- thin the sequence inside each view group (never across the flat list), so the loop still sees coherent sub-videos. The warning in the tooltip is real: skipped frames are not written by the saver whilesparse/0/images.binstill registers them - reconcile withtools/stride_dataset.py(--mode pruneor--mode keep-lowres) before training.on_size_mismatch- defaulterror(a batch needs one size).resize_and_passthroughresizes the odd images down and lists them onpassthrough_json- frame 00000 is usually the original panorama, a separate larger COLMAP camera, and gets passed through untouched.prepare_in_place- does the originals-preserving swap (images → images_lowres) here before the first read, if you want an in-place COLMAP upscale without a separate Prepare node.
Outputs
images (camera-major batch of pristine originals), order_names (JSON list of filenames in exact loaded order - wire into the Save node so each upscaled frame maps back to its filename), canonical_dir (the COLMAP images folder), group_sizes (per-view lengths), batch_size, passthrough_json, and job - which bundles everything the streaming saver needs down one link.
Install & gotchas
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; the pack's requirements (opencv, trimesh, etc.) are light and this node needs nothing else - your upscaler does. The one footgun: don't wire the loader's batch_size output into the Batch Manager that drives it - that's a dependency cycle ComfyUI refuses, which is exactly why the separate DatasetUpscalePlan node exists.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| dataset_name | STRING | my_scene | Name of the SphereSfM dataset folder under ComfyUI/output. |
| dataset_pathopt | STRING | Optional explicit path to the dataset root or images folder. Overrides dataset_name. | |
| lowres_suffixopt | STRING | _lowres | Originals-folder suffix; must match the Save node's suffix. |
| camera_indexopt | INT | -1-1–4096 | -1 = load all cameras. 0..N-1 = load only that camera's sub-video (one coherent view/trajectory). The console lists the available cameras on each run. |
| meta_batchopt | VHS_BatchManager | Optional VHS Meta Batch Manager. When wired, the camera-major sequence is STREAMED frames_per_batch frames at a time instead of loaded whole -- the fix for 'the upscaled result does not fit in RAM'. Set frames_per_batch to a divisor of the per-view length (81 -> 81, 27, 9, 3, 1) so no chunk straddles a view boundary. The order_names / canonical_dir outputs stay whole-dataset. | |
| on_size_mismatchopt | COMBO | error | What to do when the folder holds more than one image size. error: refuse (a batch needs one size). resize_and_passthrough: resize the odd images DOWN to the majority size so they still give the temporal model its context, and list them on the passthrough_json output. Frame 00000 is normally the ORIGINAL panorama (a separate, larger COLMAP camera) -- wire passthrough_json into Save Upscaled Frames (Streaming) and its untouched original is copied to the output instead of the generated upscale. |
| prepare_in_placeopt | BOOLEAN | false | Do the originals-preserving swap here, before the first read: images/ -> images_lowres/ (once, atomically) and a fresh empty images/ for the saver to fill. Idempotent, so a re-run renames nothing. Turn this ON for an in-place COLMAP dataset upscale and you do not need a separate Prepare node. |
| select_every_nthopt | INT | 11–1000 | Thin the sequence: keep every Nth frame. Applied INSIDE each view group, never across the flat list -- 24 views of 81 at N=3 become 24 views of 27, so no chunk ever straddles a view boundary and the loop still sees coherent sub-videos. Counting starts at each view's first frame, so frame 00000 (the real panorama) is always kept. group_sizes and suggested_batch_size are recomputed for you. WARNING: the skipped frames are then NOT written by the saver, while sparse/0/images.bin still registers them. Reconcile the dataset afterwards with tools/stride_dataset.py (--mode prune or --mode keep-lowres) before training on it. |
| drop_partial_strideopt | BOOLEAN | false | What to do with the frame that falls out of the stride. 81 frames at N=5 is 16 complete 5-frame windows plus 1 leftover: off keeps it (17 per view), on omits it (16 per view). CAUTION: 17 is 4n+1 so it can be one clean SeedVR2 batch, while 16's only 4n+1 divisor is 1 -- turning this on can collapse suggested_batch_size to 1 and cost you all temporal context. Check the printed suggested_batch_size after changing it, and match tools/stride_dataset.py --drop-partial. |
Outputs (7)
| Name | Type | Description |
|---|---|---|
| images | IMAGE | — |
| order_names | STRING | — |
| canonical_dir | STRING | — |
| group_sizes | STRING | — |
| batch_size | INT | — |
| passthrough_json | STRING | — |
| job | STRING | — |