Nodes/comfyui_bmad_nodes/AdaptiveThresholding
ComfyUI Node Runs on cloud

AdaptiveThresholding

The threshold that survives shadows and uneven light

By bmad4ever·Created 3 years ago·Updated 9 months ago· 70
AdaptiveThresholding
  • src
  • IMAGE
max_value255
adaptive_methodADAPTIVE_THRESH_GAUSSIAN_C
threshold_typeBINARY
block_size4
c2

The difference between "threshold" and "adaptive threshold" is whether a shadow wrecks your mask. A plain threshold picks one cutoff for the entire image, so a photograph with a gradient of light turns into a mess - one half goes white, the other half goes black, and your nice binary mask looks like a split screen. Adaptive thresholding computes the cutoff locally, per neighborhood, which means it can follow the lighting. That's why it's the go-to first step for binarizing photos of documents, receipts, or anything shot under real-world light.

This node is a clean wrapper around OpenCV's cv.adaptiveThreshold, sitting in Bmad/CV/Thresholding alongside the pack's CLAHE and OtsuThreshold nodes. If you're working with uneven lighting, the standard chain is CLAHE → AdaptiveThresholding: equalize local contrast first, then threshold adaptively.

The inputs that matter

  • src - your image (grayscale internally; the node converts).
  • adaptive_method - ADAPTIVE_THRESH_MEAN_C (average of the neighborhood) or ADAPTIVE_THRESH_GAUSSIAN_C (weighted average, sharper on edges). Gaussian is the usual pick.
  • threshold_type - the standard OpenCV five: BINARY, BINARY_INV (inverted), TRUNC, TOZERO, TOZERO_INV. You'll almost always use BINARY or BINARY_INV.
  • block_size (default 4, min 2, step 2) - the size of the neighborhood used to compute each pixel's cutoff. Bigger = more global behavior; smaller = more local, and noisier.
  • c (default 2, range down to −999) - a constant subtracted from each computed threshold. Raise it to suppress noise, lower it to keep faint strokes.
  • max_value (default 255) - the value assigned to pixels that pass the threshold.

One subtlety the author handled for you: OpenCV requires an odd block_size, but the widget takes even numbers and the node adds 1 internally. So block_size: 4 really means a 5×5 neighborhood. Don't fight it - just know the widget value and the actual kernel differ by one.

Output is a single IMAGE, returned as grayscale copied into RGB (the pack's standard convention), ready for the next masking node.

Install

Ships in bmad4ever/comfyui_bmad_nodes. ComfyUI Manager → search comfyui_bmad_nodes, or:

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_bmad_nodes
cd comfyui_bmad_nodes
pip install -r requirements.txt

Restart. It's pure OpenCV (opencv-python~=4.8.1.78 pinned in the pack's requirements.txt); no models.

Gotchas

The two knobs to tune are block_size and c, and they interact. Too-small block + too-low c and your binary image is static. Too-large block and you're back to a global threshold with all the shadow problems. Also remember src is treated as grayscale - if your input is already a soft-edged mask, run it through a threshold first to get clean 0/255 values, or the "adaptive" part will react to mid-gray gradients you didn't intend.

CategoryBmad/CV/Thresholding

Inputs (6)

NameTypeDefaultDescription
srcIMAGE
max_valueINT2550–255
adaptive_methodCOMBOADAPTIVE_THRESH_GAUSSIAN_C2 options: ADAPTIVE_THRESH_MEAN_C, ADAPTIVE_THRESH_GAUSSIAN_C
threshold_typeCOMBOBINARY5 options: BINARY, BINARY_INV, TRUNC, TOZERO, TOZERO_INV
block_sizeINT4
cINT2

Outputs (1)

NameTypeDescription
IMAGEIMAGE