Nodes/opencv-comfyui/OpenCV adaptiveThreshold_0
ComfyUI Node

OpenCV adaptiveThreshold_0

OpenCV adaptiveThreshold_0

By geroldmeisinger·Created about a year ago·Updated about a year ago· 35
OpenCV adaptiveThreshold_0
  • src
  • dst
  • nparray
maxValue
adaptiveMethod
thresholdType
blockSize
C

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 - 0 is MEAN_C (compare against the local mean), 1 is GAUSSIAN_C (a Gaussian-weighted mean). GAUSSIAN_C tends to follow edges a bit better; both work.
  • thresholdType - 0 is THRESH_BINARY, 1 is THRESH_BINARY_INV. Pick 1 if 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 - 1121 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_8UC1 assertion - 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.
Categoryimage/OpenCV

Inputs (7)

NameTypeDefaultDescription
srcNPARRAY
maxValueFLOAT
adaptiveMethodINT
thresholdTypeINT
blockSizeINT
CFLOAT
dstoptNPARRAY

Outputs (1)

NameTypeDescription
nparrayNPARRAY