cv2.ximgproc.rollingGuidanceFilter
Smoothing that knows what size of detail it's removing
- src
- result
Most edge-preserving filters have an ambiguity problem: run them hard enough to erase texture and they also start eroding the real edges, because "detail" and "structure" look the same to a single pass with a single window. The rolling guidance filter sidesteps that by iterating. Each pass filters the image, then uses its own previous output as the guide for the next pass - small structures get removed and stay removed, while large edges get re-established by the guide. The pack's own note describes the effect neatly: it "progressively removes small-scale structure while restoring large edges."
If you've ever wanted a texture slider where texture and structure are separately controllable, that's this. It's the scale-space member of the family - the pack's edge-aware filter playground puts it next to guidedFilter, l0Smooth and the weighted median filter for exactly that comparison.
Inputs that matter
- src - the image. 8-bit or float, one or three channels. The
resultoutput echoes this input's format, so an IMAGE link comes back as an IMAGE you can preview without bridges. - sigmaSpace (3.0) - this is the one to think about. It sets the spatial reach of each pass, i.e. the scale of detail that gets removed. Turn this up to remove bigger texture, not
numOfIter. - sigmaColor (25.0) - the colour difference (in 0–255 units) below which pixels get averaged together. Too high and it bleeds across genuine edges.
- numOfIter (4) - the rolling passes. More iterations strengthen the "small stuff stays gone" effect without changing which scale you're targeting; the default 4 is a good place to stop unless you're chasing maximal flattening.
- d (-1) - the neighbourhood diameter. Non-positive means "derive it from sigmaSpace", which is the sane default here.
- borderType (
BORDER_DEFAULT) - how the pixels outside the frame are synthesised. Leave it unless you're matching another pass.
Defaults are OpenCV's own (25 / 3 / 4), so a fresh node is already in a usable place - the pack only replaces a default when the value isn't actually sensible, and here it is.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
Restart ComfyUI, or install ComfyUI CV from ComfyUI Manager. Python ≥3.12, a recent ComfyUI on the V3 node API, opencv-contrib-python-headless~=5.0.0.93 - no model downloads, no extra dependencies; that one wheel is the entire install. It's a contrib function, so a non-contrib OpenCV install on the same site-packages/cv2 silently removes the node from the menu: tools/repair_opencv_contrib.py --check diagnoses, --apply repairs.
Common issues
The pause before output. This node is on the pack's always-offload list - the cv2 call runs in an interruptible subprocess, so you can cancel a slow run instead of killing ComfyUI, at the cost of about a second of startup per call. Expected, not stuck.
You raised numOfIter and nothing changed much. Right: iterations reinforce the scale you've already set. Change sigmaSpace.
Over-flattening. You've set sigmaSpace above the size of the structure you care about. That's the whole parameter semantics; there's no edge-threshold rescue knob.
Disparity/depth maps. As with every filter in this module, invalid-pixel markers are just values - the −1 in a stereo map gets averaged into its neighbours. The curated disparity nodes in this pack handle validity; the generic smoothers don't.
Cost scales with frame size and iterations. Unlike l0Smooth, this one is at least cancellable - but it's still an iterative filter on the whole frame. Tune at preview resolution.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| src | COMFY_MATCHTYPE_V3 | Source 8-bit or floating-point, 1-channel or 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. | |
| dopt | INT | -1-2147483648–2147483647 | Diameter of each pixel neighborhood that is used during filtering. If it is non-positive, it is computed from sigmaSpace . Preset to the OpenCV default (-1). |
| sigmaColoropt | FLOAT | 25.0000-1e+38–1e+38 | Filter sigma in the color space. A larger value of the parameter means that farther colors within the pixel neighborhood (see sigmaSpace ) will be mixed together, resulting in larger areas of semi-equal color. Preset to the OpenCV default (25.0). |
| sigmaSpaceopt | FLOAT | 3.0000-1e+38–1e+38 | Filter sigma in the coordinate space. A larger value of the parameter means that farther pixels will influence each other as long as their colors are close enough (see sigmaColor ). When d>0 , it specifies the neighborhood size regardless of sigmaSpace . Otherwise, d is proportional to sigmaSpace . Preset to the OpenCV default (3.0). |
| numOfIteropt | INT | 4-2147483648–2147483647 | Number of iterations of joint edge-preserving filtering applied on the source image. Preset to the OpenCV default (4). |
| borderTypeopt | COMBO | BORDER_DEFAULT | - - - |
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. |