Nodes/ComfyUI CV/cv2.ximgproc.thinning
ComfyUI Node

cv2.ximgproc.thinning

Turn a fat blob mask into a one-pixel skeleton

By bmad4ever·Created 4 months ago·Updated 14 days ago· 1
cv2.ximgproc.thinning
  • src
  • result
◄thinningTypeTHINNING_ZHANGSUEN►

Skeletonisation is one of those operations that sounds academic and turns out to be the practical answer to a lot of questions: how thick is this stroke, how many branches does this shape have, where's the centre line of this road/lane/cable/letter, which way do these clock hands point. Thinning erodes a binary blob down to a single-pixel-wide line that runs through its middle, preserving connectivity. Everything you can then measure - length, junctions, endpoints, orientation - is trivial on a skeleton and painful on a mask.

Feeding it is the part people get wrong, so start there.

Inputs

  • src - a single-channel 8-bit binary image, foreground at 255. The tooltip is unambiguous: "the foreground is eroded to a 1-pixel-wide skeleton. Threshold first." In practice, hand it a MASK, or a binary NPARRAY from a threshold node - this is one of the wrappers that doesn't grayscale a colour IMAGE for you, and the function insists on one channel. The output echoes the input's format, so a MASK in gives you a MASK back, ready for whatever consumes masks downstream.
  • thinningType (THINNING_ZHANGSUEN) - which algorithm. Zhang–Suen is the classic fully-parallel one; Guo–Hall tends to produce fewer spurious side branches, which matters a lot when you're counting junctions or tracing a path. If your skeleton comes back hairy, switch algorithms before you blame your threshold.

What it's actually for

  • Width/profile measurement. Skeleton length plus blob area gives you an average stroke thickness; the pack's region-properties node reports skeleton length among its many columns.
  • Topology. A skeleton is where "how many loose ends does this shape have" becomes answerable - the same node exposes skeleton loose ends as a feature.
  • Path extraction. Lane markings, wires, cursive text, hand-drawn strokes: once you have a skeleton you have a curve you can sample, filter, or feed into the pack's contour machinery.
  • Shape descriptors that don't care about weight. Heavy and light versions of the same glyph thin to similar skeletons.

The pack also ships a curated CV Skeletonize node that wraps this function with a morphological fallback, and it's the better default if you don't specifically want the raw function's behaviour - you get a working skeleton even when the fast path isn't available, and a dropdown naming the algorithms.

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 models, nothing else to fetch. thinning is a contrib function, so a plain opencv-python wheel installed over the contrib one makes it disappear from the menu; tools/repair_opencv_contrib.py --check names that, --apply repairs it.

Common issues

Build errors like (-215) … CV_8UC1. Your input isn't single-channel binary - usually a colour IMAGE that went straight in. Mask → CV Array or an explicit threshold in front of it fixes it.

Skeleton is fragmented into dashes. The blob was already broken by the threshold. A closing operation (morphologyEx, MORPH_CLOSE) before thinning connects the pieces; thinning cannot invent a bridge.

Hairy skeleton with stub branches. Classic thinning artefact: small boundary bumps in the mask become short spurs. Try Guo–Hall, smooth the mask before thinning, or prune the output by removing short branches.

Nothing appears for one frame in a batch. The node takes frame 0 of an IMAGE/MASK batch when you wire one directly. For a per-frame effect, loop the frames through the pack's batch nodes (Image Batch → CV Batch, the array nodes, CV Batch → Image Batch) instead of hoping it multiplies itself.

Categoryimage/CV/low-level/ximgproc

Inputs (2)

NameTypeDefaultDescription
srcCOMFY_MATCHTYPE_V3Source 8-bit single-channel image, containing binary blobs, with blobs having 255 pixel values. 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.
thinningTypeoptCOMBOTHINNING_ZHANGSUENValue that defines which thinning algorithm should be used. See cv::ximgproc::ThinningTypes

Outputs (1)

NameTypeDescription
resultCOMFY_MATCHTYPE_V3Echoes the 'src' input's format: an IMAGE link comes back as IMAGE, MASK as MASK, NPARRAY stays NPARRAY.