cv2.ft.inpaint
The third inpainter, and the one with the backwards mask
- image
- mask
- result
This is cv2.ft.inpaint, the fuzzy-transform inpainter from OpenCV's contrib ft module. In ComfyUI terms it's not a generative inpaint - it doesn't touch your diffusion model, has no prompt, and won't invent plausible eyelashes. It reconstructs missing pixels from the surrounding ones using a weighted local fit, and it does it in milliseconds on the CPU.
So why open it? Because sometimes that's exactly right: dust, a scratched overlay, a scan line, a small over-painted blob, a watermark-ish defect on a flat background. Instruction-editing models took most of the "fix what's wrong" job a while ago, and the thing masked inpainting still owns is not disturbing everything else. A deterministic fill is the extreme version of that: it changes the hole and nothing else, ever, with no seed lottery.
The mask is inverted, and that's the whole article
Three inpainters live in this pack and they share one parameter name with two opposite meanings:
| Function | Non-zero in the mask means |
| --- | --- |
| cv2.inpaint (photo module) | the HOLE - repair these pixels |
| cv2.xphoto.inpaint (contrib) | KNOWN - trust these pixels |
| cv2.ft.inpaint (this node) | KNOWN - trust these pixels |
You paint a hole in ComfyUI's mask editor, so you have a hole mask. Handed to this node, non-zero means "known" - meaning it will faithfully keep your carefully painted blob and rebuild everything around it. The pack's own tooltip says it, the demo workflow says it, and everyone still does it once. Put a cv2.bitwise_not between your mask and this node:
MASK (hole = 1) -> cv2.bitwise_not -> mask (hole = 0 = missing)
IMAGE ----------------------------------> image
The inputs
image is the polymorphic socket and the one that decides the output format - IMAGE in, IMAGE out, MASK in, MASK out. mask takes the same types. radius is the radius of the fuzzy basic function, and it's roughly the widest gap the algorithm can bridge: a hairline needs 2–5, a hole that's 30 px across needs a radius in that neighbourhood, and the cost goes up with it.
function is the shape of the basic function, and it only offers LINEAR here. That's not the pack being lazy: the SINUS kernel raises on every call in the pinned OpenCV 5.0 build, so offering it would just be a broken dropdown.
algorithm is the interesting one:
MULTI_STEP- the default. Refines outward with several radii, automatically.ITERATIVE- repeats the partial computation until it settles. Slowest, smoothest.ONE_STEP- and here's the trap: it's broken on this OpenCV build. It returns NaN at every pixel where the mask is zero, regardless of radius or mask convention. The node's default isMULTI_STEPprecisely because of that, andONE_STEPstays selectable only so old saved workflows still load. Don't pick it because it sounds cheapest.
The output result echoes the input format, and the wrapper quietly re-casts depth for you - the ft module hardcodes 32-bit float output, so a uint8 IMAGE comes back as uint8 rather than as a float array you then have to normalise.
Install
Manager → ComfyUI CV, or:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"
Restart. ft is a contrib module, so if this node is missing from your menu or throws module 'cv2' has no attribute 'ft', you've got a non-contrib wheel overwriting the contrib one in the shared site-packages/cv2. tools/repair_opencv_contrib.py --check diagnoses it; --apply fixes it. No models to download - this one is pure maths.
Where people get burned
- Non-zero = known. Not the other way round.
cv2.bitwise_notfirst. ONE_STEPgives you a NaN-speckled image on the pinned build. It looks like a bug in your pipeline; it isn't.- Radius is a reach limit. If your hole is wider than the radius can span, you get a plausible-looking smudge rather than an error - so preview the result instead of trusting the run.
- If you actually want texture back (bricks, grass, fabric), this is the wrong tool. Frequency-selective extrapolation (
cv2.xphoto.inpaint,FSR_BEST) reconstructs texture; the fuzzy transform reconstructs smoothness. Workflow18_inpainting_playground.jsonin the pack wires all three side by side so you can watch the difference.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| image | COMFY_MATCHTYPE_V3 | Input image. The image output(s) echo this input's format. Accepts a ComfyUI IMAGE/MASK directly (frame 0 of a batch) or an NPARRAY. Arithmetic ops (add, multiply, etc.) process the full IMAGE batch when both inputs have the same batch size. | |
| mask | NPARRAY,IMAGE,MASK | Mask used for unwanted area marking. Accepts a ComfyUI IMAGE/MASK directly (frame 0 of a batch) or an NPARRAY. Arithmetic ops (add, multiply, etc.) process the full IMAGE batch when both inputs have the same batch size. | |
| radius | INT | 0-2147483648–2147483647 | Radius of the basic function. |
| function | COMBO | LINEAR | Function type could be one of the following: - `ft::LINEAR` Linear basic function. |
| algorithm | COMBO | MULTI_STEP | Algorithm could be one of the following: - `ft::ONE_STEP` One step algorithm. - `ft::MULTI_STEP` This algorithm automaticaly increases radius of the basic function. - `ft::ITERATIVE` Iterative algorithm running in more steps using partial computations. This function provides inpainting technique based on the fuzzy mathematic. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| result | COMFY_MATCHTYPE_V3 | Echoes the 'image' input's format: an IMAGE link comes back as IMAGE, MASK as MASK, NPARRAY stays NPARRAY. |