cv2.ft.FT12D_process
The fuzzy transform, upgraded so gradients don't come out as staircases
- matrix
- kernel
- mask
- nparray
Same shape as FT02D_process - image in, kernel, optional mask, float array out - but a different fit underneath. The F⁰ transform (FT02D_*) replaces each window with a single weighted average, which is why its output can look slightly terraced across a smooth gradient. The F¹ transform used here (FT12D_*) fits a plane to each window instead, so a ramp inside a window survives the round trip and only the noise gets averaged away.
If you're choosing between the two, that's the whole decision: F⁰ for flat regions and heavy noise, F¹ when your image has gradients that shouldn't come out banded.
How it works
The F-transform is a two-stage model fit rather than a convolution. The forward pass walks a (2r+1)² window over the image, where the window weights are the "basic function" supplied by cv2.ft.createKernel; the inverse pass reconstructs pixels from the overlapping window representations. F¹ keeps a linear term per window on top of the constant, so the reconstruction has a slope available. That extra degree of freedom is exactly why the F¹ family carries three coefficient outputs in its polynomial variant: an average, and a gradient in each direction.
process is the one-call version: forward and inverse in a single step. OpenCV's docs describe it as sufficient and optimised for the cv::Mat case, which is a polite way of saying you don't need the separate two-node version unless you want to touch the intermediate representation.
Inputs and outputs
matrix- IMAGE, MASK or NPARRAY. An IMAGE becomes a uint8 BGR frame, and only frame 0 of a batch: theftfunctions aren't frame-batch safe in this pack, so a clip gives you one frame.kernel- required, fromcv2.ft.createKernel, with a channel count that matches the image (3 for BGR, 1 for greyscale). Radius is a property of the kernel:(2r+1)square, so radius grows cost quadratically. The freshly-created kernel defaults to radius 0, which is a 1×1 no-op.mask- optional; non-zero = known, zero = excluded. Excluded pixels are reconstructed from their neighbours, which makes the masked mode a fill rather than a filter.
Output: one nparray, 32-bit float, in the same numeric range as your input. NPARRAYs don't preview, so Preview CV Array or CV Array → Image is how you look at it.
Does it beat a blur?
Sometimes. It's a weighted local fit, so it's more aggressive about preserving the local trend than a Gaussian of comparable radius, and unlike a bilateral filter it has no range term to tune and no intensity threshold to cross. What it isn't is fast: F¹ costs more than F⁰, which already costs more than a separable Gaussian. If you want edge-preserving smoothing and don't specifically want this maths, reach for a guided or bilateral filter instead and save yourself the mystery.
Where it earns its keep is in a pipeline that already speaks F-transform - feeding the same components into gradient computation, or reconstructing after you've edited the intermediate array - and in the noise-robust derivative work its sibling FT12D_polynomial does.
Install
Manager → search 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 ComfyUI. ft is a contrib module in a shared site-packages/cv2, so an ordinary opencv-python install can wipe the whole family out of your node menu; tools/repair_opencv_contrib.py --check is how you confirm that's what happened. Python ≥ 3.12, recent ComfyUI on the V3 node API, no model downloads.
Where people get burned
- Radius 0. No error, no effect, wasted afternoon.
- Mask direction. Non-zero means keep. A painted hole mask needs
cv2.bitwise_notfirst. - Channel mismatch between kernel and image. Throws inside cv2 without saying "channels".
- Treating the output as a picture. It's a float NPARRAY; the preview node will normalise it and can make a perfectly correct result look wrong.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| matrix | NPARRAY,IMAGE,MASK | Input matrix. 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. | |
| kernel | NPARRAY,IMAGE,MASK | Kernel used for processing. Function `ft::createKernel` can be used. 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. | |
| maskopt | NPARRAY,IMAGE,MASK | Mask used for unwanted area marking. This function computes $F^1$-transfrom and inverse $F^1$-transfotm in one step. It is fully sufficient and optimized for `cv::Mat`. 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. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| nparray | NPARRAY | — |