OpenCV fastNlMeansDenoising_0
FastNlMeansDenoising_0
- src
- dst
- nparray
You generated something and it came out noisy - sensor-looking grain, JPEG blocks, the faint shimmer you get from a too-aggressive upscale. Your first instinct might be to stick it back through the model. Don't. A plain blur will smooth the noise but turn every edge to mush, and a diffusion re-pass is a lottery. This is the middle path: non-local means denoising, one of the genuinely clever deterministic filters OpenCV has had for years.
fastNlMeansDenoising_0 wraps cv2.fastNlMeansDenoising, and the idea behind it is what makes it worth knowing. A normal blur averages each pixel with its neighbors - that's why edges smear. Non-local means instead averages each pixel with pixels that look like it, anywhere in the image. A patch of skin in the corner is denoised by averaging with similar skin patches elsewhere, not by dragging in the edge that's right next to it. Edges survive, noise doesn't. It's slower than a blur - it's searching the image - but it's the right tool when "denoise" needs to mean "keep the structure."
The inputs that matter
src(NPARRAY) - the image. Grayscale only. This overload works on a single-channel 8-bit array; feed it a BGR image and you'll get the classicimg.type() == CV_8UC1assertion error the README warns about. Convert first withcvtColorusing code6(BGR2GRAY).h(FLOAT) - filter strength. Higher = smoother, blobbier. OpenCV's rule of thumb is ~3 for grayscale.templateWindowSize(INT) - the patch size being compared, an odd number like 3–7. Bigger patches = softer result, more compute.searchWindowSize(INT) - how far the algorithm looks for similar patches, default 21. This is the cost knob; bumping it up is where the minutes go.dst(NPARRAY, optional) - an out-parameter. Leave it unplugged; the README tells you to avoid optionaldstinputs on principle.
Output is a single nparray - the denoised image, same size and type as the input. Wire it into Nparrays2Image to get back a Comfy IMAGE.
Installing it
One of ~600 nodes in geroldmeisinger/opencv-comfyui - install the pack once. In ComfyUI Manager search opencv-comfyui, or:
cd ComfyUI/custom_nodes
git clone https://github.com/geroldmeisinger/opencv-comfyui
then restart. Requirements are opencv-contrib-python, numpy, torch. If ComfyUI fails to start with Cannot import name 'guidedFilter' from 'cv2.ximgproc', conflicting OpenCV installs are fighting - one consistent opencv-contrib-python fixes it.
Two gotchas before you wire it up. Everything in this pack runs on nparrays in BGR, 0–255 - bring your image in via Image2Nparray, take the result out via Nparrays2Image. And batch size must be 1; if you get the "batch_size==1" error, put ImageFromBatch (length 1) in front.
When to reach for it
Grayscale inputs are a real constraint for photo work, so for color images you'll more often want fastNlMeansDenoisingColored_0 instead. But if your pipeline is already grayscale - depth maps, masks, line art, upscaled alpha - this is the cleanest edge-preserving denoise in the pack, and it's deterministic and free, the exact kind of cheap primitive the post-processing layer exists to push. Don't pay a diffusion pass for work a filter does in milliseconds.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| src | NPARRAY | — | |
| h | FLOAT | — | |
| templateWindowSize | INT | — | |
| searchWindowSize | INT | — | |
| dstopt | NPARRAY | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| nparray | NPARRAY | — |