cv2.ximgproc.amFilter
The guided smoother that uses a second image as its opinion
- joint
- src
- result
Most denoising filters look only at the picture in front of them and have to guess which high-frequency detail is texture and which is noise. A guided filter gets told: you hand it a second image, and it keeps the structure of that one while smoothing the first. The textbook use is the flash/no-flash pair - a noisy available-light frame plus a clean flash frame of the same scene - but the trick generalises to anything where you have a cleaner or structural reference: a matte plate against a noisy plate, a depth map as a guide for a colour image, a low-noise render as the guide for a noisy one.
amFilter is the "adaptive manifold" version of that idea from cv2.ximgproc. It's a fast approximation of the bilateral-family behaviour - instead of comparing every pixel to every pixel in the neighbourhood, it builds a low-dimensional manifold of the joint image's colours and filters in that space, which is why it scales to larger sigma_s than a naive bilateral.
Inputs and outputs
joint- the guide image (the tooltips call it "joint (also called as guided)"), with any number of channels. This is a match-type socket:IMAGE/MASK/NPARRAYin, same format out.src- the image actually being filtered.sigma_s- spatial standard deviation, in pixels. How far influence spreads. Bigger = smoother, slower.sigma_r- colour-space standard deviation. This one is in the units of your pixel values, not normalised 0–1 - a ComfyUIIMAGEreaches cv2 as 8-bit 0–255, so values in the tens are the range that visibly smooths, and a value like 0.2 is a very tight colour threshold that keeps almost everything. If the node appears to do nothing, this is why. Check which scale your array is in (Inspect CV Data, orImage → CV Arrayto control the dtype yourself) before you conclude the filter is broken.adjust_outliers- the optional boolean from the paper's Eq. 9. Off by default, and off is fine unless you're seeing outliers survive the smoothing.
One output, echoing the guide's format.
Wiring it
The default setup is the boring one and it works: same image into joint and src. That's just self-guided edge-preserving smoothing. The interesting setup is two images - for a flash/no-flash pair, guide with the flash frame and filter the no-flash one; for matte work, guide with the aligned clean plate and filter the noisy one.
If you want to know whether it actually helped, don't squint - the pack has CV Quality Compare, which scores two images with SSIM (and hands back a per-pixel quality map showing where they disagree). Comparing filter settings by number is a small habit that saves a lot of eyeballing, and 10_ximgproc_edge_aware_filters in the pack's examples is built entirely around doing that.
Where it sits among the smoothers
The pack's own filter sheet puts six edge-aware filters side by side, and the differences are real, not cosmetic:
guidedFilter- local linear fit to the guide, fast, no gradient reversal. The default choice for guided work.amFilter- this one; the manifold approximation, good at large spatial sigma.dtFilter- domain transform; cheapest per iteration, sharp edges.bilateralTextureFilter- separates texture from structure rather than just comparing colours.l0Smooth- flat cartoon regions with hard steps.rollingGuidanceFilter/fastGlobalSmootherFilter/weightedMedianFilter- scale-space, global, and specular-noise flavours.
If you just need "smooth the noise, keep the edges" on one photo, start with guidedFilter or dtFilter; reach for amFilter when you have a joint image doing real work.
Installing it
Contrib module, so it needs an OpenCV build with contrib - which is what the pack declares. 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
Python ≥3.12, recent V3-API ComfyUI. If your ximgproc nodes vanish, you've installed a non-contrib opencv-python* wheel over the contrib one - they share a single site-packages/cv2 and the last install wins. tools/repair_opencv_contrib.py --check in the pack repo tells you.
What goes wrong
- Nothing visible happened. Almost always
sigma_ron the wrong scale (above). - Smeared into mush.
sigma_stoo large orsigma_rtoo large - you've told it to treat colour differences as noise. - Guide and source don't match. They must be the same size. If you're using two captures, align them first; the filter trusts the guide's edges completely.
- It blocks the queue. This is an iterative filter running in-process; on a big frame it will hold the run. Test at preview resolution first.
- Wrong wheel, empty module.
ximgprocfunctions exist as empty stub packages when the contrib binary is missing, so you get import success and zero attributes rather than a clean error.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| joint | COMFY_MATCHTYPE_V3 | joint (also called as guided) image or array of images with any numbers of channels. 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. | |
| src | NPARRAY,IMAGE,MASK | filtering image with any numbers of channels. 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. | |
| sigma_s | FLOAT | 0.0000-1e+38–1e+38 | spatial standard deviation. |
| sigma_r | FLOAT | 0.0000-1e+38–1e+38 | color space standard deviation, it is similar to the sigma in the color space into bilateralFilter. |
| adjust_outliersopt | BOOLEAN | false | optional, specify perform outliers adjust operation or not, (Eq. 9) in the original paper. Preset to the OpenCV default (False). |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| result | COMFY_MATCHTYPE_V3 | Echoes the 'joint' input's format: an IMAGE link comes back as IMAGE, MASK as MASK, NPARRAY stays NPARRAY. |