OpenCV adaptiveThreshold_0
OpenCV adaptiveThreshold_0
- src
- dst
- nparray
adaptiveThreshold_0 is one of the handful of nodes in this pack you'll actually reach for in a ComfyUI image workflow. It wraps cv2.adaptiveThreshold and turns a grayscale image into a binary black-and-white one - but with a local threshold instead of a single global value. For every pixel it compares against the average of its neighborhood (a blockSize-sized window), plus a constant. Where the pixel is brighter than that local bar, it goes one way; darker, the other.
That "local" bit is what makes it special. A global threshold dies on uneven lighting - shadows flip entire regions to the wrong side. The adaptive version ignores slow lighting gradients and still catches real edges, which is why it's the go-to for extracting clean line art, ink outlines, or "binarized mask" versions of a gray depth map. If your goal is ControlNet-style lineart or a sharp mask from a soft gray input, this is a serious candidate.
How it works
The signature is cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C[, dst]). Two knobs define the method:
- adaptiveMethod -
0is MEAN_C (compare against the local mean),1is GAUSSIAN_C (a Gaussian-weighted mean). GAUSSIAN_C tends to follow edges a bit better; both work. - thresholdType -
0is THRESH_BINARY,1is THRESH_BINARY_INV. Pick1if you want the lines themselves white on black (lineart style).
The other three are the feel of the result: maxValue (usually 255 - the value pixels get when they clear the bar), blockSize (the neighborhood window; must be odd - 11–21 is a sane start), and C (a constant subtracted from the local average - larger C means only stronger edges survive).
The non-negotiable input detail
adaptiveThreshold only works on single-channel grayscale. Feed it a BGR image and OpenCV asserts with img.type() == CV_8UC1. So the chain is: Image2Nparray → the pack's cvtColor with code=6 (BGR2GRAY) → adaptiveThreshold_0 → Nparrays2Image. Grayscale comes back through Nparrays2Image's gray→RGB conversion, so the output displays fine. This is exactly the workflow the README walks you through, and skipping the cvtColor step is the #1 way people hit the assertion.
The inputs that matter
- src (NPARRAY) - must be grayscale.
- maxValue (FLOAT) - typically 255.
- adaptiveMethod (INT) - 0 = mean, 1 = Gaussian.
- thresholdType (INT) - 0 = binary, 1 = inverted.
- blockSize (INT) - odd window size.
- C (FLOAT) - subtracted constant; larger = pickier.
- dst (NPARRAY, optional) - skip it; read the return value.
Output: one nparray - the binary image.
Installing opencv-comfyui
ComfyUI Manager → search "opencv-comfyui", or:
cd ComfyUI/custom_nodes
git clone https://github.com/geroldmeisinger/opencv-comfyui
Restart. Dependency:
pip install opencv-contrib-python
Gotchas
img.type() == CV_8UC1assertion - your input is BGR or RGBA, not grayscale. cvtColor (code=6) first.- Even blockSize - must be odd, or cv2 throws.
- Batch_size == 1 - conversion nodes refuse batches; use
ImageFromBatch.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| src | NPARRAY | — | |
| maxValue | FLOAT | — | |
| adaptiveMethod | INT | — | |
| thresholdType | INT | — | |
| blockSize | INT | — | |
| C | FLOAT | — | |
| dstopt | NPARRAY | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| nparray | NPARRAY | — |