Nodes/TKNodes/Video Transition Detector
ComfyUI Node

Video Transition Detector

Finding real scene boundaries in your video

By trashkollector·Created about a year ago·Updated a day ago· 1
Video Transition Detector
  • images
  • boundaries_json
  • boundary_count
  • report
  • boundary_frames
  • debug_csv
fps25.00
max_segment_seconds10.0
cut_z_thresh3.0
dissolve_dip_ratio0.70
dissolve_min_len5
analysis_width160
debug_modefalse

If you've ever tried to re-render a long video by chunking it into LTX or Wan-sized pieces, you know the pain of picking where the chunks go. Chop mid-action and you get a mushy crossfade where a punch used to be. The whole point of TKTransitionDetector is to answer "where do I cut?" for you, and it's smarter than a naive "every N frames" splitter: it finds real cuts, catches crossfades, and only falls back to forced boundaries when the video gives it nothing to work with.

This is the TKNodes pack's answer to the scene-change detection you get in a real NLE - the README even says "similar to how Davinci works." Calm down before you expect broadcast-grade accuracy, though. The source's own docstring calls it a prep tool, "mostly correct, fast, no manual threshold babysitting." For feeding a video-to-video chunking pipeline that's exactly the right trade.

How it works

The node downscales your frame batch to a small grayscale strip (analysis_width, default 160 - detection doesn't need full resolution) and runs two signals in parallel:

  • Hard cuts show up as an isolated spike in histogram distance between consecutive frames. It uses a rolling z-score over that distance, so a jump is only a cut if it's a lone spike - not part of a sustained run (that's a dissolve, not a cut). cut_z_thresh (default 3) is your sensitivity knob: raise it to see fewer cuts.
  • Dissolves and crossfades don't spike; they smear. Canny edge density dips while the image blurs between shots, and the detector compares each frame against a backward-looking baseline that deliberately ignores recent frames - so the dip stays visible even while it's happening. A dip lasting at least dissolve_min_len frames (default 5) marks where the dissolve finishes.

Boundaries that land within three frames of each other get deduped, and then the guardrail kicks in: any gap longer than max_segment_seconds (default 10) gets a "forced" boundary inserted so downstream rendering never gets asked for more than it can chew. Video-generation models have hard frame-count ceilings - LTX wants 8n+1 frames, Wan wants 4n+1 - and forcing a 10-second cap is the chunker's job security.

The inputs that matter

You mostly touch three knobs. fps needs to match your source (feed it the same FPS the video was loaded at, or every time label will be wrong). max_segment_seconds caps chunk length. And when detection feels wrong, cut_z_thresh is where you start: too many phantom cuts, raise it; real cuts being ignored, lower it. debug_mode is worth one run - it fills the debug_csv output with per-frame z-scores, edge density, and baselines so you can see exactly why a frame got flagged instead of guessing.

Outputs

Five of them, but the two that matter: boundaries_json gives you each boundary with its frame number, time, and type (cut, dissolve_end, forced, end), and boundary_frames hands you a clean list of frame indices you can wire into the pack's chunkers or a loop. report is a human-readable summary you can drop on a Text node to check your work, and boundary_count is just the integer count for bookkeeping.

Install

It ships in the TKNodes pack, so one install gets you all of this. ComfyUI Manager, search "Handy Nodes", install, restart. Or the manual way:

cd ComfyUI/custom_nodes
git clone https://github.com/trashkollector/TKNodes

Then restart ComfyUI. The pack pulls in numpy, opencv (used here), pydub, torchaudio and more via requirements.txt, and needs FFmpeg on your system PATH for anything touching audio files. The detector itself is lightweight - no model downloads, it's pure image math on your existing tensor.

Where people get burned: forget to match fps to the source and every timestamp is off by the ratio; crank analysis_width up to 640 thinking you'll get more accuracy and mostly you'll get slower runs for the same answer. Leave it low. The detector is a chopping guide, not a precision instrument - let the chunker handle the boundary snapping, that's its job.

CategoryTKNodes/video

Inputs (8)

NameTypeDefaultDescription
imagesIMAGE
fpsFLOAT25.001–240
max_segment_secondsFLOAT10.01–120
cut_z_threshFLOAT3.01–10
dissolve_dip_ratioFLOAT0.700.1–0.95
dissolve_min_lenINT52–60
analysis_widthINT16064–640
debug_modeBOOLEANfalse

Outputs (5)

NameTypeDescription
boundaries_jsonSTRING
boundary_countINT
reportSTRING
boundary_framesINT
debug_csvSTRING