Nodes/ComfyUI CV/cv2.fastNlMeansDenoisingColored
ComfyUI Node

cv2.fastNlMeansDenoisingColored

Denoise in LAB so the colour doesn't drift

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
cv2.fastNlMeansDenoisingColored
  • src
  • result
◄h3.0000►
◄hColor3.0000►
◄templateWindowSize7►
◄searchWindowSize21►

If your source is a colour photograph and it's noisy, this is the fastNlMeans variant you want - not the grayscale one with a colour image fed into it. The difference is not cosmetic: this version converts to CIELAB and denoises the luminance and the colour components separately, with two different strengths. That separation is the whole point, because luminance noise and chroma noise are different problems and want different treatment.

The mechanism

Non-local means averages each pixel with pixels from anywhere in a search window whose surrounding patch looks similar, weighted by that similarity - so flat areas clean up while edges survive. The colour version runs that over the L channel of CIELAB, and then over the A and B channels separately, with the split letting you say "grain is a luminance problem, my chroma is fine". It's the same algorithm as its grayscale sibling, wearing a colour-space harness; the cost profile is identical, which is why this call also lives in the pack's always-offload set and gets its own interruptible subprocess. Long call, but Cancel works.

The inputs

src takes an IMAGE, MASK or NPARRAY and the output result echoes the input's format - IMAGE in, IMAGE out. The tooltip does say the underlying function expects an 8-bit 3-channel image, so this is a colour-semantics node: feeding it a MASK is technically accepted, but you've picked the wrong node for a single channel.

Four knobs, and the split matters:

  • h (default 3.0) - the luminance strength. This is "how much grain do I remove", and it's the one that trades detail for cleanliness.
  • hColor (default 3.0) - the chroma strength, for the A and B channels. The tooltip's guidance is unusually concrete: 10 is enough for most images to clear colour speckle without distorting the hues. That's the practical setup - a low h, hColor around 10 - because coloured splotches are ugly and easily removed, while pushing h hard is how you get waxy skin.
  • templateWindowSize (7) and searchWindowSize (21) - patch size and search radius, both odd, both recommended at their defaults. Lowering searchWindowSize to ~11–15 is the standard speed/quality trade when a 4K frame is taking minutes; the tooltip warns plainly that cost scales linearly with it.

Where it fits

Cleaning inputs, the same as the grayscale version, but for the photographs that actually have chroma noise: high-ISO captures, older compact-camera JPEGs, frames pulled from compressed video. A noisy reference image handed to img2img or a controlnet pass contaminates the generation, and spending a minute of deterministic denoising before the expensive generative step is nearly always the better trade.

It's also the right tool when a mask isn't the problem but a score map is - no, scratch that, keep it for pictures. Where it's the wrong tool is the popular one: this will not fix AI grain, and it will not give you the film look. photorealism.md and post-processing.md both land on the same conclusion from different directions - grain is a feature people add deliberately, and smooth, noise-free AI output is a tell. Denoise the source, don't launder the output.

Comparing to the neighbours

Against the grayscale cv2.fastNlMeansDenoising: use this one for colour. Against a bilateral or guided filter: those are edge-preserving and much faster, and for skin they're usually the better choice; NLM's patch-similarity model handles repeated texture (brick, fabric, foliage) better. Against a generative cleanup pass: always prefer the deterministic one first - the entire argument of the post-processing layer is that a millisecond operation which does the job exactly beats a diffusion pass that rerolls the face.

Installing it

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"

Or install comfyui_cv from ComfyUI Manager and restart. Python ≥ 3.12, V3-API ComfyUI. Node path: image/CV/low-level/cv2 F.

Traps

Frame 0. This is a single-image node in practice - an IMAGE batch gets handled as its first frame, so process a sequence frame by frame (or split the batch) rather than assuming all eight frames came back denoised. Watch the hColor 10 rule of thumb: pushing it to 20+ starts flattening genuinely saturated colours into grey. And set expectations on time with a stopwatch, not with the algorithm's name.

Categoryimage/CV/low-level/cv2 F

Inputs (5)

NameTypeDefaultDescription
srcCOMFY_MATCHTYPE_V3Input 8-bit 3-channel 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.
hoptFLOAT3.0000-1e+38–1e+38Parameter regulating filter strength for luminance component. Bigger h value perfectly removes noise but also removes image details, smaller h value preserves details but also preserves some noise Preset to the OpenCV default (3.0).
hColoroptFLOAT3.0000-1e+38–1e+38The same as h but for color components. For most images value equals 10 will be enough to remove colored noise and do not distort colors The function converts image to CIELAB colorspace and then separately denoise L and AB components with given h parameters using fastNlMeansDenoising function. Preset to the OpenCV default (3.0).
templateWindowSizeoptINT7-2147483648–2147483647Size in pixels of the template patch that is used to compute weights. Should be odd. Recommended value 7 pixels Preset to the OpenCV default (7).
searchWindowSizeoptINT21-2147483648–2147483647Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time. Recommended value 21 pixels Preset to the OpenCV default (21).

Outputs (1)

NameTypeDescription
resultCOMFY_MATCHTYPE_V3Echoes the 'src' input's format: an IMAGE link comes back as IMAGE, MASK as MASK, NPARRAY stays NPARRAY.