Nodes/AP Optical Flow + Loop + Inpaint Crop/Stitch/AP Apply RAFT Optical Flow (Latent, Masked)
ComfyUI Node

AP Apply RAFT Optical Flow (Latent, Masked)

Region-limited latent warping — flow inside a mask, no pixel detour, no background drift

By adampolczynski·Created 6 months ago·Updated 6 months ago· 1
AP Apply RAFT Optical Flow (Latent, Masked)
  • latent
  • mask
  • flow_data
  • output_latent
  • warped_latent
  • warped_mask
  • valid_mask
flow_directionab
batch_modeauto
flow_skip0
frames_skip0
strength1.00
invert_flowfalse
invert_maskfalse
mask_strength1.00
mask_feather0
interpolationbilinear
padding_modeborder
current_frame_index0

This is the node you get when you take the "warp in latent space" idea from APApplyRAFTOpticalFlowLatent and add the "warp only where I say" idea from APApplyRAFTOpticalFlowMasked, and it's the one that unlocks genuinely practical video-inpaint-in-latent pipelines.

The use case is specific and worth naming precisely. You're doing temporal inpainting on video: a moving subject needs to be repainted every frame, but the background is static and must not drift. The classic approach decodes to pixels, warps the masked region, encodes back, inpaints, and repeats - and every one of those encode/decode round trips is wasted time and a source of latent drift. This node lets you do the warping step entirely in latent space, limited to the masked region, so the loop body stays latent from start to finish. The pack's loop system (APLoopOpen (Latent)/APLoopClose (Latent)) is built around exactly this shape.

The mechanism

Same as the masked image variant, transplanted into latent space. The flow field is resized down to the latent's resolution. Your mask is optionally inverted (invert_mask), feathered (mask_feather), and scaled (mask_strength), then the latent samples are warped by the flow and the mask is warped too. Output = warped × (warped_mask × original_mask) + original × inverse. Outside the mask, the latent is untouched - which is precisely what keeps your static background from drifting frame over frame.

It also carries the latent dict's metadata through, and it's careful about dtype - if you're running on CPU with float16 latent samples it promotes to float32 for the warp math and casts back, which is a small quality-of-life detail that tells you this pack has seen real iteration loops.

The inputs that matter

Everything from the latent apply node is here (latent, flow_data, flow_direction, batch_mode with repeat_latent, flow_skip/frames_skip, strength, invert_flow, interpolation, padding_mode, optional current_frame_index), plus the mask controls. The ones you actually set:

  • mask - the region to warp, at latent or pixel resolution (it gets resized to match the latent). The README's settings for masked warping apply: strength 0.6–1.0, mask_feather 3–8, mask_strength 0.8–1.0.
  • mask_feather - soften the mask edge so the warped/unwarped boundary doesn't show up as a hard seam in the final video.
  • mask_strength - scale the mask's influence; under 1.0 lets a little original through inside the mask to hide warp errors.
  • invert_mask - flip which side warps, saving you an invert node.

Outputs and where they go

Four outputs, same shape as the masked image node: output_latent (the masked composite - your warp result, background preserved), warped_latent (the fully-warped latent), warped_mask (the mask after flow, at latent resolution - tells you where the region landed), and valid_mask (warp validity). The pair you'll usually care about: feed output_latent to your sampler, and if you're building a manual composite keep warped_mask around for the alpha.

Installing it

ComfyUI Manager (search "AP_OpticalFlow"), or manually:

cd ComfyUI/custom_nodes
git clone https://github.com/adampolczynski/ComfyUI_AP_OpticalFlow
python -m pip install -r custom_nodes/ComfyUI_AP_OpticalFlow/requirements.txt

Restart ComfyUI. One dependency (torchvision>=0.15), RAFT weights auto-download on first flow compute.

Where it sits in a workflow

The README's latent pipeline section puts it plainly: build flow with APGetRAFTOpticalFlow, warp latents directly with the plain latent node for whole-frame work, and use this node for region-limited latent warping with your mask. If your workflow never touches the VAE until the very end, this is the warp node you want. If your mask covers the whole frame, drop the mask input and use the unmasked latent variant - the extra mask math buys you nothing there.

CategoryAP_OpticalFlow

Inputs (15)

NameTypeDefaultDescription
latentLATENT
maskMASK
flow_dataAP_FLOW
flow_directionCOMBOab2 options: ab, ba
batch_modeCOMBOauto3 options: auto, by_index, repeat_latent
flow_skipINT00–2147483647
frames_skipINT00–2147483647
strengthFLOAT1.00-4–4
invert_flowBOOLEANfalse
invert_maskBOOLEANfalse
mask_strengthFLOAT1.000–2
mask_featherINT00–64
interpolationCOMBObilinear3 options: bilinear, nearest, bicubic
padding_modeCOMBOborder3 options: border, zeros, reflection
current_frame_indexoptINT00–2147483647

Outputs (4)

NameTypeDescription
output_latentLATENT
warped_latentLATENT
warped_maskMASK
valid_maskMASK