cv2.detailEnhance
Local contrast pop from two sliders, no model
- src
- result
cv2.detailEnhance is the deterministic, model-free answer to "this image looks flat, can you make the detail read". It's one of OpenCV's photo-module NPR filters - the same family as edgePreservingFilter, pencilSketch and stylization, all built on edge-preserving smoothing - and it does what it says: it boosts local structure while leaving the overall tonality roughly where it was. No diffusion pass, no VRAM, instant.
How it differs from sharpening
The KB's post-processing notes make the point that "sharpening is unsharp masking, and the name is literally the recipe" - blur a copy, subtract, add the difference back scaled. That's a high-pass operation and it's why cranking it produces halos: you're amplifying noise and edge overshoot together. detailEnhance is the same idea (make local detail stronger) built on an edge-aware decomposition instead: flat regions get smoothed and left alone, structure gets its contrast lifted. It's closer in spirit to a local-contrast or "clarity" slider in a RAW editor than to a sharpen radius/amount pair.
That also means it's not interchangeable with a sharpen node in this pack (cv2.unsharpMask-style nodes elsewhere), and it's not a substitute for a proper upscale. What it's good at is texture and mid-frequency structure: skin, fabric, foliage, stone - the stuff that makes an image look rendered when it's too smooth.
The inputs
src must be an 8-bit, three-channel image, and it accepts an IMAGE link directly. The output echoes that format - an IMAGE in gives an IMAGE out - so you can preview it immediately rather than doing the CV Array → Image dance. It's one of the type-preserving wrappers in this pack.
The two knobs are the whole filter, and the pack's own tooltips describe them better than OpenCV's docs do:
sigma_s(FLOAT, default 10, range 0–200) - the spatial scale, "how far the filter reaches. Bigger = stronger flattening". In practice this is the size of the features it treats as detail: small values lift fine texture, big values lift broader shapes and can start to look like a bad HDR.sigma_r(FLOAT, default 0.15, range 0–1) - the range threshold, "colour differences below it are smoothed away, above it are kept as edges. Bigger = fewer surviving edges". Lower it and the filter sees more of your image as edges; push it too far down and you amplify noise along with the structure.
Defaults are sensible. Change one at a time.
Where it fits in a workflow
A cheap final-pass punch on a finished render before you export, especially on images that came out of a high-denoise or heavy-upscale pipeline where micro-detail got smoothed away. Or the opposite move: run it as a reference while comparing two upscale paths, since it makes the difference in retained detail obvious. And because it's deterministic and instantaneous, you can use it in a batch loop without worrying about what sampling does to the look.
The honest limit: it can't invent detail that isn't there, and past a point it starts to produce the flattened, over-processed look that every clarity slider is notorious for. If your problem is that a 512px generation doesn't hold up at 4K, this is not the fix - that's upscaling territory, and this pack's cv2.detail.* and photo wrappers won't help. What it's for is the last 5%, not the first 50%.
Install
Manager → Install Custom Nodes → ComfyUI CV (publisher bmad4ever), 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; the contrib headless OpenCV wheel is the only dependency and no models are downloaded. This function is core OpenCV, but the pack as a whole wants the contrib build: all four OpenCV wheels share one site-packages/cv2, so installing plain opencv-python over it empties the contrib submodules and those nodes disappear (python tools/repair_opencv_contrib.py --check, then --apply). The pack is GPL-3.0, forked from geroldmeisinger/opencv-comfyui, largely LLM-written, and the author's disclaimer is explicit that it isn't production-ready.
Common issues
- Type assertion on execution. Colour images only, 8-bit. A MASK or a 4-channel image will raise; convert first.
- The image looks flattened and plasticky.
sigma_stoo high. Come back toward 5–15 for a photoreal pass. - Noise and grain got louder.
sigma_rtoo low - you've moved the edge threshold below your sensor/compression noise. Raise it toward 0.15–0.25. - Nothing happens. At small image sizes there's little mid-frequency structure to lift; the effect is strongest on large images with real detail in them.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| src | COMFY_MATCHTYPE_V3 | Input 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. | |
| sigma_sopt | FLOAT | 10.0000-1e+38–1e+38 | %Range between 0 to 200. Preset to the OpenCV default (10.0). |
| sigma_ropt | FLOAT | 0.1500-1e+38–1e+38 | %Range between 0 to 1. Preset to the OpenCV default (0.15). |
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. |