VideoImageWarp
Steal a Video's Motion and Glue It Onto Your Own Image
- video_images
- first_frame
- influence_map
- IMAGE
VideoImageWarp is the "motion transfer" trick done the old-school way: take a reference video, take one image you generated, and warp that image frame by frame so it dances exactly like the video - without a single video model running. It's the only node in the blob8/ComfyUI_video-image-motion-transfer pack, and it does something most image-to-video tools can't: it preserves your stylized image perfectly while copying the motion of an arbitrary reference clip.
The recipe the author ships: grab a video, pull its first frame, run it through an img2img pass with a depth ControlNet so your generated subject keeps the reference's composition. Then feed your stylized frame plus the original video frames into VideoImageWarp, and out comes a warped video that moves like the source but looks like your generation. The demo uses SDXL, but the node is architecture-agnostic - it works with anything that can pull off the img2img step.
How it works
The name is a lie in the best way - there are no AI models in this node at all. It's pure classical computer vision, so it runs fast and cheap on CPU. Each step in the source is doing textbook optic-flow:
- Compute optical flow between consecutive video frames using OpenCV's DualTVL1 algorithm (that's why the pack needs
opencv-contrib-python- plainopencv-pythondoesn't ship it). - Accumulate the flow across the whole clip, with each frame's flow decaying by
stabilization. That accumulation is what makes the warp track long camera moves instead of jittering frame to frame. - Sample the accumulated flow onto a sparse grid of points (
grid_spacing), interpolate that sparse displacement into a dense field, and warp your stylized first frame onto it with bilineargrid_sample.
Because it only moves pixels, it can't invent content - the far side of a rotating object, a face turning to profile - and that's the honest limitation, which is why people who need true inpainting-on-reveal go back to Wan or LTX. For anything where the camera moves and the subject stays roughly front-facing, this is a free, deterministic alternative.
The inputs that matter
Two IMAGE inputs are the heart of it: video_images (the reference video as a batch of frames, usually straight out of a video loader) and first_frame (your stylized image). Then the few you'll actually touch:
compute_flow_resolution(default 0.15) - not a scale factor, it's megapixels. The video gets rescaled down to that for flow computation. Lower is faster and, per the author, looks just as good; don't crank it up expecting quality.stabilization(default 0.01) - how fast accumulated flow decays. The big one: distorted output means raise it toward 0.15.motion_scale(default 1) - multiplies the motion before warping. Go negative to reverse the motion. Fun, and it's a live knob.grid_spacing(default 10) - grid resolution for the warp. Lower = more detail, slower.influence_map(optional) - a mask that scales motion intensity per-region, so you can freeze the background and only let the subject move.
Everything else in the required list - tau, lambda_, theta, nscales, warps, epsilon, inner_iterations, outer_iterations - is raw DualTVL1 tuning, which the README itself calls "hard to explain and not as useful." Leave them. And yes, warp_smooting is spelled exactly like that (typo baked into the schema); it blurs the flow for smoother results. The single output is an IMAGE batch - the warped frames - ready for a save-video node or a VAE encode if you want another generation pass.
One genuinely clever detail: the node caches computed flow keyed on the video, resolution, and the DualTVL1 params. So fiddling with motion_scale, grid_spacing, stabilization, or influence_map does not recompute the flow - you iterate on the warp for free.
Installing it
Easiest is ComfyUI Manager: search for ComfyUI_video-image-motion-transfer. Otherwise:
cd ComfyUI/custom_nodes
git clone https://github.com/blob8/ComfyUI_video-image-motion-transfer
Then the gotcha: the shipped requirements.txt has a malformed line (cv2opencv-contrib-python - a mangled package name), so install the real thing yourself:
pip install opencv-contrib-python
The example workflow also needs comfyui_controlnet_aux (for the depth preprocessor, like Depth Anything v2) and KJNodes, plus the SDXL depth ControlNet weights: diffusion_pytorch_model.fp16.safetensors from diffusers/controlnet-depth-sdxl-1.0, dropped into models/controlnet.
Troubleshooting
- Distorted, melting output → raise
stabilizationto ~0.15. The accumulated flow is drifting and the decay is too weak. AttributeError: module 'cv2' has no attribute 'optflow'→ you installed plain opencv, not the contrib build:pip install opencv-contrib-python.- Warp looks blocky or smeary → lower
grid_spacing; raisewarp_smootingif it's too noisy. - You changed a parameter and nothing happened → that's the flow cache, not a bug. It recomputes only when
compute_flow_resolution, the DualTVL1 params, or the video input change.
A niche tool with a near-zero footprint online, and it deserves that - one clever idea, not a platform. But that idea (deterministic, no-model motion transfer on top of any i2i-capable checkpoint) has no real replacement in ComfyUI, and for the price of one pip install it's worth a Saturday experiment.
Inputs (16)
| Name | Type | Default | Description |
|---|---|---|---|
| video_images | IMAGE | — | |
| compute_flow_resolution | FLOAT | 0.150.1–2.5 | — |
| stabilization | FLOAT | 0.0100–1 | — |
| motion_scale | FLOAT | 1.00-999–999 | — |
| grid_spacing | INT | 10 | — |
| first_frame | IMAGE | — | |
| warp_smooting | FLOAT | 3.000–100 | — |
| tau | FLOAT | 0.250.1–0.5 | — |
| lambda_ | FLOAT | 0.150.05–0.5 | — |
| theta | FLOAT | 0.300.1–0.5 | — |
| nscales | INT | 53–8 | — |
| warps | INT | 53–10 | — |
| epsilon | FLOAT | 0.0100.001–0.01 | — |
| inner_iterations | INT | 3010–50 | — |
| outer_iterations | INT | 103–15 | — |
| influence_mapopt | IMAGE | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |