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

AP Apply RAFT Optical Flow (Masked)

Warp only the part that moves — masked optical flow without smearing your background

By adampolczynski·Created 6 months ago·Updated 6 months ago· 1
AP Apply RAFT Optical Flow (Masked)
  • images
  • mask
  • flow_data
  • output_images
  • warped_images
  • 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

The plain APApplyRAFTOpticalFlow warps your whole frame. That's fine when the whole scene moves - a pan, a dolly, a subject that fills the frame. But most temporal work is the opposite: you've got a moving subject on a static background, and warping everything smears the background and drags ghosting across regions that should be untouched. This node is the fix. Give it a mask, and only the masked region gets warped; everything else stays put.

It's the node the author clearly intends as the workhorse. The README's recommended "professional anti-blur compositing" pipeline routes this node's warped_mask output into APFlowComposite.effect_mask, not the unmasked variant's. If you're building a temporal-consistency or video-inpaint workflow and you're using the plain apply node, you're probably making life harder than you need to.

The mechanism

It's the same grid-sample warp as the unmasked node, plus mask math. Your mask is optionally inverted (invert_mask), feathered (mask_feather, an average-pool blur of 2*feather+1 pixels), and scaled by mask_strength before it's used as the blend alpha. The image is warped fully, the mask is warped too, and then output = warped × (warped_mask × original_mask) + original × the inverse. So inside the mask you get the flow-moved pixels; outside, you get the untouched original.

That's why there are four outputs instead of two. warped_images is the raw warped frame (everything moved), output_images is the masked composite (only your region moved), and warped_mask is the mask after it's been pushed through the flow - which is genuinely useful because it tells you where the subject ended up, not where it started. valid_mask is the usual warp-validity map for the frame edges.

The inputs that matter

Everything from the unmasked node carries over (flow_direction, batch_mode, strength, invert_flow, flow_skip/frames_skip, the optional current_frame_index). The new ones, for a beginner:

  • mask - the region to warp. From a SAM segmentation, a detected subject, a hand-drawn region. The README's recommended settings are strength 0.6–1.0, mask_feather 3–8, mask_strength 0.8–1.0.
  • mask_feather - softens the mask edge so you don't get a hard seam between warped and unwarped pixels. Start at 3–8; if the mask edge is visible, raise it.
  • mask_strength - scales the mask's influence. Under 1.0 lets a bit of the original bleed through even inside the mask, which helps hide warp errors.
  • invert_mask - swap which side warps. Occasionally you have a background mask and want the inverse; this saves you an InvertMask node.

The wiring pattern that actually works

The README's recommended anti-ghosting setup, roughly:

  1. Compute flow from neighboring frames with APGetRAFTOpticalFlow.
  2. APFlowOcclusionMask from the same flow_data to find covered/revealed regions.
  3. This node to warp image + mask.
  4. APFlowComposite - feed warped_mask into its effect_mask, set alpha_mode = flow_confidence_x_mask, enable use_difference_gate with a low difference_threshold (0.005–0.02).

That last part is the difference between a clean result and a smeary one: the difference gate blocks the composite from touching pixels where the warped frame barely differs from the original - i.e. background that shouldn't have changed - so changes stay focused on actually-warped regions.

Installing it

Standard pack install: ComfyUI Manager (search "AP_OpticalFlow"), or clone it 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. Dependency is just torchvision>=0.15; RAFT weights auto-download on first flow compute.

When to reach for the masked variant

Video inpainting is the canonical case: you're masking the moving parts and repainting them per-frame, and you want the warp (and its valid mask) to stay inside that moving region so the inpaint doesn't fight the static background. Same logic applies to face-consistent video and anything where a subject moves against a fixed scene. If your region is the whole frame, save the extra wires and use the unmasked node.

CategoryAP_OpticalFlow

Inputs (15)

NameTypeDefaultDescription
imagesIMAGE
maskMASK
flow_dataAP_FLOW
flow_directionCOMBOab2 options: ab, ba
batch_modeCOMBOauto3 options: auto, by_index, repeat_image
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_imagesIMAGE
warped_imagesIMAGE
warped_maskMASK
valid_maskMASK