ComfyUI Node

πŸ”„ Temporal Smoother

Real frame-to-frame smoothing with motion compensation, but mind the buffer

By kanibusΒ·Created about a year agoΒ·Updated about a year agoΒ· 5
πŸ”„ Temporal Smoother
  • current_frame
  • previous_frames
  • smoothed_frame
  • motion_visualization
  • motion_amount
  • smoothing_applied
β—„smoothing_strength0.70β–Ί
β—„buffer_size5β–Ί
β—„frame_weightsexponentialβ–Ί
β—„motion_compensationtrueβ–Ί
β—„adaptive_smoothingtrueβ–Ί
β—„cache_resultstrueβ–Ί
β—„wan_versionautoβ–Ί
β—„temporal_consistency_modeenhancedβ–Ί

One of the genuinely working nodes in the kanibus/kanibus pack (a Claude-generated repo, last commit Aug 2025), TemporalSmoother smooths a video frame against its recent history - the classic trick for killing flicker and jitter in tracking-derived output. It's real: actual weighted averaging across a frame buffer, real phase-correlation motion compensation, and a motion visualization you can eyeball. It's also stateful, and that's the thing that will bite you.

How it works

The node keeps a rolling buffer of recent frames (max length 20) on the node instance. Each call:

  1. Appends current_frame to the buffer.
  2. Computes motion between the previous and current frame (mean absolute difference in grayscale).
  3. With adaptive_smoothing on, reduces smoothing strength when motion is high - so fast action stays crisp while static shots get heavy smoothing. Off, it uses your strength flat.
  4. Weighted-averages the last buffer_size frames using your frame_weights profile - linear, exponential (recent frames weighted more) or gaussian.
  5. If motion_compensation is on, aligns each buffered frame to the current frame first, via cv2.phaseCorrelate shift detection, so moving objects don't smear. Shift is only applied if it's small (<10px), which is a sensible guard.

Outputs: smoothed_frame (IMAGE), motion_visualization (IMAGE - a difference map of the last two frames), motion_amount (FLOAT), and smoothing_applied (FLOAT - the adaptive strength actually used).

Inputs you'll set

  • smoothing_strength (0–1, default 0.7) - the master dial. Higher = smoother but blurrier fast motion.
  • buffer_size (1–20, default 5) - how many frames get averaged. More frames = stronger smoothing and more latency.
  • frame_weights - exponential is the sensible default; linear for uniform, gaussian for a centered-weighted feel.
  • motion_compensation (on) and adaptive_smoothing (on) - keep both on unless you're chasing speed.

previous_frames (an optional IMAGE input) exists in the schema but the shipped code manages its own buffer and doesn't consume it - don't bother wiring it.

Installing

cd ComfyUI/custom_nodes
git clone https://github.com/kanibus/kanibus
cd kanibus    # lowercase - README's "cd Kanibus" fails on case-sensitive systems
pip install -r requirements.txt   # or requirements_minimal.txt if it clashes
python install.py

Restart ComfyUI, find it under Kanibus/Processing. Pure OpenCV - no model downloads. The README's "5.6GB of required ControlNet models" line doesn't apply here.

The gotcha: it's stateful

The frame buffer lives on the node instance, not in the graph. Feed it frames in the wrong order - or reuse the node across two different jobs without restarting - and it averages frames from the previous run. This is the #1 source of "why does my output look blended with something else?" confusion with this node. If your workflow runs once and finishes, you're fine; if you're testing iteratively on single frames, expect stale buffer contents. The smoothing_applied output tells you how much it actually blended on a given call, which is your best debugging signal.

Where it fits

In a tracking pipeline (feed it NeuralPupilTracker's annotated frames or masks), it genuinely reduces per-frame jitter. motion_amount can even drive downstream logic - e.g., gating re-tracking on high motion. For a placeholder-free alternative, most video-frame chains already include a temporal filter; but if you're in the pack anyway, this one is competent and worth using.

Just remember: it's a smoothing node with a memory, and its memory doesn't know when your job ended.

CategoryKanibus/Processing

Inputs (10)

NameTypeDefaultDescription
current_frameIMAGEβ€”
smoothing_strengthFLOAT0.700–1β€”
buffer_sizeINT51–20β€”
previous_framesoptIMAGEβ€”
frame_weightsoptCOMBOexponential3 options: linear, exponential, gaussian
motion_compensationoptBOOLEANtrueβ€”
adaptive_smoothingoptBOOLEANtrueβ€”
cache_resultsoptBOOLEANtrueβ€”
wan_versionoptCOMBOauto3 options: auto, wan_2.1, wan_2.2
temporal_consistency_modeoptCOMBOenhanced3 options: standard, enhanced, ultra

Outputs (4)

NameTypeDescription
smoothed_frameIMAGEβ€”
motion_visualizationIMAGEβ€”
motion_amountFLOATβ€”
smoothing_appliedFLOATβ€”