TS Video Depth
Steady depth maps for whole clips — not 24 flickering stills
- images
- image
Run a still-image depth model on a video frame by frame and you get a depth map that swims - edges wobble, distances pop between frames, and the result is unusable for anything temporal. TS Video Depth is the fix: it runs Video Depth Anything over a sliding window of frames, so each frame's depth is informed by its neighbors and the result stays steady from frame to frame. The temporal consistency is the entire reason this node exists.
Depth maps earn their keep in a few places, and the steady kind is what makes them usable: driving a depth ControlNet on a clip, building a parallax or 2.5D move, masking by distance over time. If you only have a still - or a batch of unrelated pictures - the pack's TS Image Depth is the better tool; it runs the still-trained Depth Anything V2, which is both quicker and sharper on a single frame.
How it works
The model sees the clip through a sliding window. window_length (default 32) is both the default and the ceiling: the temporal module carries an absolute positional embedding with exactly 32 slots, so you can't build a longer window from these weights at all. window_overlap (default 10) is how many frames consecutive windows share - more overlap means smoother joins and proportionally more compute. At the defaults the model already runs about 1.45 frames for every frame of output.
Two details tell you this was built by someone who actually ran it:
- Temporal median, not average.
flicker_suppression(0–1, default 0) blends in a temporal median of the depth, which drops single-frame pops without smearing real movement the way an average would. Crank it to 1 on a locked-off camera and get a rock-solid map; keep it around 0.3–0.5 to take the twitch out of static shots. - Edge-aware upscale. The model works at low resolution;
edge_aware_upscale(default on) uses the full-res RGB as a guide when scaling back up, so silhouettes stay sharp. If you're feeding 4K and want the sharpest edges, leavemax_resat -1 (no cap) so the RGB guide keeps full resolution.
The inputs that matter
images- the frame batch,(N, H, W, 3)in 0..1. Any aspect ratio; 16:9 is the model's sweet spot.model_filename-vitlfp16 (~0.75 GB, default, best quality) orvitsfp16 (~55 MB, fast, less stable on fine detail). Weights are fp16 safetensors, downloaded on first use toComfyUI/models/videodepthanything; an old.pthname still loads if a saved workflow references it.input_size- the internal resolution the transformer sees, default 518 (the model's native training size). 644 gives ~54% more depth detail for ~54% more VRAM/time; anything at or above 770 is out-of-distribution for DINOv2 and quality can regress. If you OOM, the node auto-retries down through 518 → 392 → 280 → 168.precision- fp16 default (required for vitl at 4K on a 16 GB card); fp32 doubles VRAM and is mostly for small inputs.colormap-gray(default) is the raw normalized depth, the one to feed downstream nodes like ControlNet. The inferno/viridis/plasma/magma/cividis options are for visualization only.
The single output, image, is a depth map at the same resolution as your input RGB - a regular IMAGE you can feed straight into a ControlNet, a saver, or a 3D node.
Installing it
Part of comfyui-timesaver: ComfyUI Manager → search Timesaver, or
cd ComfyUI/custom_nodes
git clone https://github.com/AlexYez/comfyui-timesaver
cd comfyui-timesaver
python -m pip install -r requirements.txt
then restart ComfyUI. The model downloads itself on first run.
Gotchas
If the map flickers, raise flicker_suppression before touching anything else - that's the dedicated knob for it. If it's soft, check whether max_res is capping your input before the edge-aware upscale. And the one trap that costs people an afternoon: reaching for this on a still. For a single picture, use TS Image Depth; feeding one frame into a video model means 32 duplicated frames, and the depth range flattens - measured, a portrait's face and hair blow out to flat white.
Inputs (17)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | Video frames as an IMAGE batch (N, H, W, 3) in 0..1. Any aspect ratio; 16:9 is the model's sweet spot. | |
| model_filename | COMBO | video_depth_anything_vitl_fp16.safetensors | Video Depth Anything checkpoint. Downloaded on first use to ComfyUI/models/videodepthanything. • vitl fp16 (~0.75 GB, default) — best quality. Recommended for production. • vits fp16 (~55 MB) — fast, less stable on fine detail. Only safetensors are offered: half the download and an order of magnitude quicker to read (0.01 s against 0.66 s, measured). A graph that still names an old .pth keeps working — the file is simply no longer suggested. |
| input_size | INT | 51864–4096 | Internal resolution the transformer sees (DINOv2 patch size 14, snapped automatically). Higher = more depth detail, more VRAM / time. For 16:9 source (after max_res cap): • 518 (default, native) — model trained at this size; ~480 K depth pixels. • 644 — ~740 K depth pixels (+54% detail, +54% VRAM/time). Safe on ≥24 GB. • 700 — ~872 K depth pixels (+82% detail, +82% VRAM). OOM risk on 16 GB. • ≥770 — out-of-distribution for DINOv2 (quality can REGRESS). If OOM, the node auto-retries on 518 → 392 → 280 → 168. |
| max_res | INT | 1280-1–8192 | Cap on the longer side of input frames before model preprocessing. • Does NOT change depth detail — the model always resamples to input_size. • -1 — no cap. Keeps full-resolution RGB as the guide for edge_aware_upscale, giving the sharpest silhouettes on the output. • 1280 (default) — downscales 4K to HD first; saves preprocess RAM and speeds up resize, at the cost of a slightly softer edge-aware upscale. Recommendation: -1 for 4K when edge_aware_upscale=True, 1280 otherwise. |
| precision | COMBO | fp16 | Inference dtype. • fp16 (default) — 2× faster, ~50% less VRAM. Required for vitl @ 4K on a 16 GB card. • fp32 — marginally cleaner gradients on smooth surfaces; doubles VRAM, almost always triggers OOM on 4K. Use only on small inputs or ≥24 GB cards. |
| colormap | COMBO | gray | Output color mapping. • gray (default) — raw normalized depth in all 3 channels. Use this if the depth map feeds downstream nodes (ControlNet, 3D, etc). • inferno / viridis / plasma / magma / cividis — perceptually uniform matplotlib colormaps for visualization only. Bilinear LUT interpolation removes 8-bit banding. |
| dithering_strength | FLOAT | 0.00500–0.016 | Sub-LSB noise added to the normalized depth before colormap, to break up 8-bit banding when the result is saved as PNG/JPEG. • 0 — no dither. • 0.005 (default) — light, OK with bayer pattern + bilinear LUT. • 0.016 (max) — aggressive, guaranteed banding-free on gray output. If you still see bands, raise toward 0.016 and prefer dither_pattern=bayer. |
| apply_median_blur | BOOLEAN | true | Legacy denoise toggle (kept for workflow compatibility). Used only when denoise_method=auto: True → 3×3 median, False → none. When denoise_method is set explicitly (bilateral / median / none), this toggle is ignored. |
| upscale_algorithm | COMBO | Lanczos4 | Resampling kernel for upscaling the depth map back to the original frame size. Used only when edge_aware_upscale=False. • Lanczos4 (default) — bicubic with antialias, the sharpest of the two. • Cubic — the SAME kernel as Lanczos4. PyTorch has no Lanczos, and both labels map to bicubic+antialias, so the two options are pixel-for-pixel identical (verified). Kept because saved workflows carry the value. • Linear — bilinear, softer and cheaper. The only genuinely different choice here. |
| normalization_modeopt | COMBO | percentile | How to map raw depth onto [0..1]. image is always normalized minmax. • minmax — uses global min/max across the whole video. Simple, but one outlier frame (object very close or far) can squash the contrast of every other frame. • percentile (default, quality) — robust 1%..99% range. Better contrast and temporal stability on long clips. Slightly more memory (samples a subset of pixels for quantile). |
| denoise_methodopt | COMBO | bilateral | Spatial denoise applied at low-res depth (before upscale). • auto — follow legacy apply_median_blur toggle. • none — no denoise, maximum detail; may show grain on fine textures. • median — 3×3 median, removes impulse noise, slightly blurs thin geometry. • bilateral (default, quality) — edge-preserving 5×5; smooths surface noise while keeping object silhouettes sharp. |
| dither_patternopt | COMBO | bayer | Dither distribution used by dithering_strength. • white — TPDF (triangular) random noise, full antibanding standard, but adds visible grain on flat surfaces. • bayer (default, quality) — deterministic 8×8 ordered pattern. Banding-free, no temporal flicker, no grain. Best paired with bilinear colormap LUT (already enabled). |
| edge_aware_upscaleopt | BOOLEAN | true | Final upscale strategy. • False — plain resampling via upscale_algorithm (Lanczos4 etc). Fastest. • True (default, quality) — Fast Guided Filter using the input RGB as edge guide. Silhouettes snap to real object boundaries; thin geometry is preserved. Costs ~5-10% extra postprocess time. Combine with max_res=-1 to keep the guide at full 4K for the sharpest result. |
| flicker_suppressionopt | FLOAT | 0.000–1 | Blends in a temporal MEDIAN of the depth to kill single-frame pops. • 0 (default) — off, output unchanged. • 0.3-0.5 — takes the twitch out of static shots. • 1 — pure median; safe on a locked-off camera, can lag fast motion. A median is used rather than an average on purpose: it drops outliers without smearing real movement. |
| flicker_radiusopt | INT | 11–8 | Half-width of the temporal median window, in frames (1 = look at 3 frames, 2 = 5, and so on). Bigger is steadier and slower to react. Ignored when flicker_suppression is 0. |
| window_lengthopt | INT | 328–32 | Frames the model sees at once. 32 is both the default and the ceiling: the temporal module carries an absolute positional embedding with exactly 32 slots, so a longer window cannot be built from these weights at all. Lower it only to fit VRAM — shorter windows mean less context and less consistency. |
| window_overlapopt | INT | 102–24 | How many frames consecutive windows share. More overlap means smoother joins and proportionally more compute: at the default the model already runs ~1.45 frames for every frame of output. Must stay below window_length. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | Depth map as IMAGE (N, H, W, 3) float in 0..1 at the original RGB resolution. Same as a regular IMAGE — feed directly into ControlNet, save nodes, etc. |