cv2.ximgproc.anisotropicDiffusion
The one node in this pack the author tells you not to use
- src
- result
Perona–Malik anisotropic diffusion is one of the prettiest ideas in image processing: diffuse the image like heat, but let the diffusion slow down where the gradient is steep, so noise smooths while edges stay put. In practice, in this pack, it's a cautionary tale - and the caution comes from the author, in a note baked into the pack's own example workflow:
"It is exposed as a node, but measurement says its K (the Perona-Malik edge threshold) is inert in this OpenCV build: sweeping K from 1 to 5000 moves the edge slope by a few percent, and steps of every height are smoothed alike, so it behaves as a plain isotropic blur. It also treats everything outside the image as BLACK, so a dark rim creeps inward about a pixel per three iterations, and alpha >= 0.2 makes it DIVERGE into 0/255 ringing."
That's three separate defects in one node, all measured rather than assumed. Which makes it a genuinely useful thing to know: this is the single most over-promised classical filter in computer vision, and here's what happens when you actually measure it.
What the parameters are supposed to do
src- a 3-channel source image.alpha- "the amount to step forward by on each iteration (normally between 0 and 1)". In theory this is your numerical stability knob; in practice, per the note above, above roughly 0.2 it stops converging and starts oscillating against the uint8 clamp, which is the 0/255 ringing.K- "sensitivity to the edges", the Perona–Malik threshold. The entire point of the algorithm. Inert here.niters- iteration count. Higher means smoother, and it also means the black-border rim creeps in one more time.
Output is one type-matched value. No optional inputs - src, alpha, K and niters all four, and none of them has an OpenCV default the wrapper can fall back on, so blank-the-field-to-get-the-default doesn't apply here.
What to do instead
Reach for one of the edge-aware filters that do work, all in the same module:
cv2.ximgproc.guidedFilter- local linear fit; the general-purpose choice. Watch itseps: it's a variance, i.e. squared units of your pixel scale, so on 8-bit data anything under ~1 is a no-op and useful values sit in the hundreds.cv2.ximgproc.dtFilter- domain transform, the cheapest per iteration.cv2.ximgproc.l0Smooth- flat regions, hard steps; great for structure/detail separation.cv2.ximgproc.bilateralTextureFilter- if what you're really after is "smooth the texture, keep the shapes".cv2.ximgproc.rollingGuidanceFilter/fastGlobalSmootherFilter/weightedMedianFilter- the rest of the shelf.
And if you keep reaching for a diffusion-flavoured result, cv2.edgePreservingFilter (the photo-module one, flags RECURS_FILTER/NORMCONV_FILTER) gives you an actual edge-aware smoothing with a sane result.
Does it ever make sense?
If you want the look of isotropic diffusion - soft, posterised, slightly rimmed - then sure, use it for the effect, with alpha down around 0.1–0.15 and a small iteration count. One of the pack's older example sheets ships alpha=0.9, K=0.4, niters=1, which by the author's own measurement is the diverging configuration: a live example of exactly the failure mode, preserved because the sheet is a demonstration of the algorithm rather than a recipe. If you were about to copy those numbers, don't.
Note also that with K inert you cannot get the behaviour the algorithm is named for. An edge-preserving filter that smooths every step height alike is, functionally, a blur with a border artefact.
Installing it
Part of ComfyUI CV, contrib module required. 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 and a recent V3-API ComfyUI. If the whole ximgproc group is missing from your menu, a non-contrib opencv-python* wheel has overwritten the contrib binary - all four distributions share one site-packages/cv2. The pack ships tools/repair_opencv_contrib.py --check / --apply for that.
Two final warnings
The black-border behaviour is the one that ruins real work quietly: content near the frame edge darkens over iterations, so don't run it on a tile of a larger image unless you've padded first. And measure your results instead of trusting the name - CV Quality Compare scores two images with SSIM, so you can see per pixel whether the "edge-preserving" pass preserved anything.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| src | COMFY_MATCHTYPE_V3 | Source image with 3 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. | |
| alpha | FLOAT | 0.0000-1e+38–1e+38 | The amount of time to step forward by on each iteration (normally, it's between 0 and 1). |
| K | FLOAT | 0.0000-1e+38–1e+38 | sensitivity to the edges |
| niters | INT | 0-2147483648–2147483647 | The number of iterations |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| result | COMFY_MATCHTYPE_V3 | Echoes the 'src' input's format: an IMAGE link comes back as IMAGE, MASK as MASK, NPARRAY stays NPARRAY. |