📐 S42 CutFlow Stabilize
De-shaking AI jitter and handheld wobble with OpenCV optical flow
- clip
- clip
- frame_count
- info
AI-generated video has a tell: the camera "vibrates." Small frame-to-frame position shifts that look like the whole image is trembling - the model never quite commits to a stable camera. S42CF_Stabilize is the fix. It's a real, honest-to-goodness software stabilizer: it tracks feature points through your clip with OpenCV's optical flow, works out how the camera moved, smooths that motion path, and re-renders the clip along the smoothed path. Same family of technique as the "video stabilization" in any phone or NLE, running inside your node graph.
The inputs
- clip - the shaky footage.
- smoothing (int, 3–60, default 15) - the smoothing window radius in frames. Bigger = smoother, locked-off feel, but also more cropping (the correction moves more, and the cropped area grows). 15 is the moderate default; 30+ gives that tripod-locked look.
- crop_mode - what to do with the black edges stabilization creates.
auto_crop(default, recommended) zooms in to hide the borders;fill_borderstretches edge pixels to fill them;noneleaves the black borders visible so you can see exactly how much was corrected. Start withauto_cropand switch tononeif you're debugging why the frame looks cropped. - max_shift (float, 0.01–0.3, default 0.1) - the ceiling on correction, as a fraction of the frame. 0.1 = up to 10% movement correction. This is the anti-over-correction guard - real footage with intentional camera moves won't get chased into a smear.
How it works
The pipeline is textbook OpenCV: goodFeaturesToTrack finds up to 200 corners, calcOpticalFlowPyrLK tracks them between frames, estimateAffinePartial2D fits a translation+rotation transform to the tracked points, and the per-frame deltas get cumulatively summed into a camera path. A moving-average kernel (width = 2×smoothing+1) smooths that path, and the difference between raw and smoothed path is what gets applied to each frame via warpAffine. If OpenCV can't find enough features - a blank or textureless clip - it falls back to no correction rather than inventing movement.
Outputs: clip, frame_count, and info (which reports the max border correction in pixels - useful for understanding how much crop you're eating).
Installing it
This is the one S42 CutFlow node with a real dependency attached: it needs OpenCV, and the pack's requirements.txt installs it (opencv-python-headless). If you skipped the requirements step, you'll get a passthrough clip with an ERROR: opencv-python not installed info string rather than a crash - install it and re-run:
cd ComfyUI/custom_nodes/
git clone https://github.com/GeekyGhost/S42-CutFlow.git
pip install -r S42-CutFlow/requirements.txt # Windows portable: python_embeded\python.exe -m pip
Or ComfyUI Manager, search S42 CutFlow, install, restart. It's under S42 CutFlow/Composition.
Gotchas
The honest limits. This is 2D translation/rotation stabilization, not full rolling-shutter or warp stabilization - it won't fix dramatic camera whip-pans or perspective wobble, and it can't smooth genuine parallax. Second, textureless footage defeats it: a blank wall or a clear sky gives the tracker nothing to hold onto, and you get no correction. Third, auto_crop does zoom in - expect a mild resolution hit; that's the price of hidden borders, and it's why big smoothing values cost you more frame. And one ordering note: stabilize before you add grain or sharpening, so those passes operate on the already-steady footage rather than amplifying the jitter's edges. For AI clips specifically, this is the "no more vibrating" button - run it right after your VAE decode and the difference is often dramatic.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| clip | IMAGE | Shaky video clip to stabilize. | |
| smoothing | INT | 153–60 | Smoothing window radius in frames. Larger = smoother but more cropping. 15 = moderate stabilization. |
| crop_mode | COMBO | auto_crop | 'auto_crop' = zoom in to hide black borders (recommended). 'fill_border' = fill borders by extending edge pixels. 'none' = leave black borders visible. |
| max_shift | FLOAT | 0.100.01–0.3 | Maximum allowed shift as fraction of frame. 0.1 = up to 10% movement correction. Prevents over-correction. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| clip | IMAGE | — |
| frame_count | INT | — |
| info | STRING | — |