CV Flow Map
Warp an image along its own motion (the honest way to interpolate)
- map_x
- map_y
- flow
- map_x
- map_y
A cross-fade between two video frames gives you two ghosted objects at half opacity. Warping frames along their optical flow gives you one sharp object in the middle, which is what motion actually looks like. This node is the piece that does the warping: it takes a dense displacement field and adds it to the source-coordinate maps that cv2.remap samples from.
It's from bmad4ever's ComfyUI CV (bmad4ever/comfyui_cv, a fork of Gerold Meisinger's opencv-comfyui), and it's one of eleven remap-map generators in that pack. The design idea behind all of them: a map is just an array, so lens distortion, a wave, a homography and a flow field all compose in array space and collapse into one resampling pass. Stack five of these and your image is still only interpolated once.
Inputs
map_x and map_y - the incoming coordinate maps, from CV Identity Map at the start of a chain, or from whatever remap node sits before this one. flow - an HxWx2 float field of (dx, dy) per pixel, straight off CV Optical Flow (Farneback). It gets resized to the map if the shapes differ. scale - the multiplier.
The arithmetic is literally map_x += scale * dx and map_y += scale * dy. Which doesn't sound like much until you work out what the sign means.
The sign convention, which is the whole trick
remap samples backwards: for each output pixel it asks "where in the source should I read from?" So if you want to move content a fraction t of the way along its forward motion, you pull the sample back along that motion by the same amount.
scale = 0- identity.scale = 1- apply the full motion, i.e. warp frame A to where things went in frame B.scale = -t, for t between 0 and 1 - sampletof the way back along A's motion, which lands the moving content at the in-between position.- Values beyond 1 or below 0 extrapolate, which is how you'd push past the endpoints (usually badly).
The pack's shipped interpolation workflow does it symmetrically and reads like a worked example: warp frame A with scale -t, warp frame B with scale t-1 (i.e. backward along B's own flow), then blend the two with weights 1-t and t via cv2_addWeighted, with t driven by a float primitive. Two warps, one blend, one in-between frame at exactly the time you asked for. Feed the result into a loop over the frame list and you've built slow-motion from an 18 fps clip.
Outputs
map_x and map_y - the displaced maps, ready for cv2_remap. That's it; this node never touches pixels, which is why it's cheap and why it composes.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"
Or find ComfyUI CV in ComfyUI Manager. Python ≥ 3.12 plus a ComfyUI on the V3 node API. The interpolation examples use a clip from example_inputs/ - run workflows/01_install_example_inputs.json once, reload the page, then open workflows/exercise_optical_flow_interpolation_video.json.
Two honest notes
If you just want frame interpolation, use core. ComfyUI ships Run Frame Interpolation Model (FrameInterpolate) with the RIFE and FILM loaders: native PyTorch, GPU, fp16, model offloading, and a 2–16× multiplier across a whole batch. The pack's README is unusually direct about this - the RIFE example here is the by-hand route, ONNX through cv2.dnn, on the CPU, one frame pair per execution. Read it to understand how the pieces fit, or when you need to reach a model core doesn't support. Use the core node to actually interpolate your video.
Farneback is not a modern flow estimator. It's classic, fast, CPU, and it lives in a valley between "fine for a couple of frames" and "visible tearing in motion". You'll spend real time on the flow quality, the occlusion handling (nothing here invents pixels that were hidden in both frames) and the blur on whatever the flow got wrong. That's the trade for a deterministic, model-free, offline path.
Common issues
Everything smears. Flow too coarse, or scale larger than the motion supports. Try a smaller scale and check the field visually first with CV Flow To Color.
Map shape mismatch. map_x and map_y must come from the same chain and share a shape; a second CV Identity Map sized to the other frame is not a substitute.
The remap result is soft. You're resampling once per warp, and a two-warp interpolation resamples twice plus a blend. That's inherent. Interpolating at reduced resolution and upscaling afterwards looks worse, not better.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| map_x | NPARRAY | Incoming source-x coordinate map to displace. Start the chain with 'CV Identity Map'; further remap nodes compose onto it. | |
| map_y | NPARRAY | Incoming source-y coordinate map (must share map_x's shape - both come from the same chain). | |
| flow | NPARRAY | HxWx2 float (dx, dy) displacement per pixel, e.g. the 'flow' output of 'CV Optical Flow (Farneback)'. Resized to the map if the sizes differ. | |
| scale | FLOAT | 1.00-100–100 | Multiplies the flow before adding it. 1 = full motion, 0 = identity, -t = sample a fraction t of the way back along the motion (frame interpolation at time t), negative = reverse the motion. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| map_x | NPARRAY | — |
| map_y | NPARRAY | — |