AP Flow Occlusion Mask
Where the flow lies — the occlusion mask that keeps warps from ghosting
- flow_data
- valid_mask
- occlusion_mask
- confidence_visualization
Here's the thing nobody tells you about optical flow: the flow field is a lie in the places where objects appear or disappear. When the camera pans and a building slides behind a tree, there is no correct motion vector for the tree's edge - the pixels there were covered up between frame A and frame B. If you blindly warp along the flow in those regions, you get stretching, ghosting, and smears. That's what occlusion is, and it's the difference between a flow workflow that looks like video and one that looks like a Photoshop liquify accident.
AP Flow Occlusion Mask finds those regions for you. It's the honesty check between computing flow and applying it, and it's the reason the pack's composite node can blend warped and original pixels without smearing.
The mechanism
It uses forward-backward consistency - the standard technique, done properly. APGetRAFTOpticalFlow computed both the forward (ab) and backward (ba) fields. The occlusion node warps the backward field forward, then checks: if you go A→B with the forward flow, then come back B→A with the backward flow, do you land where you started? Where the round trip fails - the cycle error exceeds a threshold - the flow is inconsistent, which is exactly where occlusion lives.
Two knobs control the strictness:
abs_epsilon(default 1.0) - the absolute pixel distance below which a round trip counts as consistent.rel_epsilon(default 0.05) - the relative allowance, scaled by how much motion there was. Fast motion gets more slack, which is the right behavior: big displacements have more uncertainty.
dilate_occlusion grows the occlusion regions by a kernel radius (up to 32) - use it when you want the mask to also swallow the uncertain fringe around occluded areas, which often prevents a thin ghosting halo.
Outputs and how to use them
Three outputs, and each has a job:
valid_mask- 1 where the flow round-trips consistently, 0 at occlusions. This is what you feed to a composite so warped pixels are only trusted where the flow was actually consistent.occlusion_mask- the inverse: 1 where pixels are occluded. Plug this intoAPFlowComposite'socclusion_maskinput (setinvert_occlusionthere if the polarity feels wrong) so the composite keeps the original frame instead of the warped one in covered regions.confidence_visualization- a grayscale image of flow confidence, useful for eyeballing which regions will ghost before you waste a render on finding out.
It also carries the same flow_direction, batch_mode, flow_skip/frames_skip, and optional current_frame_index plumbing as the other flow nodes, so it slots into index-aware loops cleanly.
Installing it
Pack-wide install: ComfyUI Manager (search "AP_OpticalFlow") or
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
then restart. torchvision>=0.15 is the only dependency.
The honest cost
This node needs the backward flow field to do its job properly. If you set compute_backward=false on APGetRAFTOpticalFlow, the backward field is just the negated forward field, and forward-backward consistency becomes nearly meaningless - you'll get an occlusion mask that thinks everything is either fine or everything is occluded. So if you're using this node, leave compute_backward on. That's the single most common setup mistake with the occlusion step, and it produces confusing garbage that looks like a node bug when it's actually a config error.
Also: occlusion masks don't fix fast motion or heavy blur. The README is upfront that flow quality degrades there, and no consistency check can recover information the flow never had. If your shot is a whip-pan with motion blur, expect the occlusion regions to be large and the composite to lean on the original frame a lot - which is, honestly, the right outcome.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| flow_data | AP_FLOW | — | |
| flow_direction | COMBO | ab | 2 options: ab, ba |
| batch_mode | COMBO | auto | 2 options: auto, by_index |
| flow_skip | INT | 00–2147483647 | — |
| frames_skip | INT | 00–2147483647 | — |
| abs_epsilon | FLOAT | 1.000–50 | — |
| rel_epsilon | FLOAT | 0.0500–1 | — |
| dilate_occlusion | INT | 00–32 | — |
| current_frame_indexopt | INT | 00–2147483647 | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| valid_mask | MASK | — |
| occlusion_mask | MASK | — |
| confidence_visualization | IMAGE | — |