Nodes/ComfyUI CV/CV Connected Components (Split Mask)
ComfyUI Node

CV Connected Components (Split Mask)

One mask in, one mask per blob out

By bmad4ever·Created 4 months ago·Updated 15 days ago· 1
CV Connected Components (Split Mask)
  • mask
  • region_masks
  • bboxes
  • count
◄connectivity8►
◄min_area16►
◄max_regions64►
◄sortlargest first►

What this is for

A single binary mask with four objects in it is a problem the moment you want to treat those objects differently - one inpaint per region, one crop per face, one colour per blob. The detailing loop the community runs (detect a region, crop it, re-render it, paste it back) is structurally per-region, and this is the node that gets you from "one mask" to "four masks" without writing a loop.

It's the plain-CV counterpart to the Impact Pack's SEGS container: same idea - a set of regions as data - different transport.

How it works

cv2.connectedComponentsWithStats labels the blobs, then the node filters, sorts and slices them. Each surviving label becomes its own full-size mask (the whole frame is present, only that region is white), and the outputs are assembled as batches so downstream nodes iterate over them naturally.

The filters exist because raw connected components on a real mask is mostly noise: min_area drops specks below a pixel count (16 by default - raise it on a 4K frame, or you'll get hundreds of mask entries for JPEG mush), and max_regions caps the count after sorting so a pathological mask doesn't spawn 12,000 outputs.

sort decides which regions survive that cap and what order they come out in: largest first (the useful default), left to right, or top to bottom. Order is not cosmetic here - if you're pairing region i with a label, a crop, or a per-region prompt from a list, the sort order is the correspondence.

One batch subtlety: if the input mask is itself a batch, the frames are merged (bitwise OR) before splitting. You get the union, not per-frame components.

Empty is a normal outcome: no components, or all of them below min_area, yields empty batches and count = 0 instead of an exception, so a workflow that fans out over regions simply does nothing that run.

Inputs and outputs

  • mask - the mask to split; a batch is unioned first.
  • connectivity (default 8) - 8 also joins diagonal pixels, so a thin diagonal stroke is one component; 4 splits it. Anti-aliased edges tend to need 8.
  • min_area (default 16), max_regions (default 64), sort - as above.

Three outputs:

  • region_masks - a MASK batch, one full-size mask per region.
  • bboxes - core BOUNDING_BOX data: per-frame lists of {x, y, width, height} dicts, compatible with Draw BBoxes, Crop By Bounding Boxes, Image Crop and friends. This is the important one for staying inside normal ComfyUI.
  • count - how many regions came out.

The canonical next step is CV Crop by Masks, which turns the batch into per-region crops you can process individually - one inpainting pass per region, say. For visual sanity-checking, OpenCV Overlay Masks (this pack) or the core Draw BBoxes node.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
# restart ComfyUI

Manager users: ComfyUI CV (bmad4ever). Requires Python ≥ 3.12, a V3-node-API ComfyUI, and opencv-contrib-python-headless~=5.0.0.93 (installed from the pack's requirements). No models.

Common issues

  • Count is absurdly high. Speckle. Raise min_area, and consider whether connectivity 4 is fragmenting regions that are visually one blob - the two effects roughly cancel out and both look like "it found the wrong things".
  • A region went missing. max_regions (64) with largest first will drop small ones once you're past the cap. Check count against what you expected to see.
  • region_masks are all full-size and mostly black. That's by design - the frame geometry is preserved so each mask lines up with the original image and with the bboxes. If you wanted tight crops, CV Crop by Masks is the next node.
  • Contrib-backed nodes vanished pack-wide. A non-contrib OpenCV wheel clobbered the shared site-packages/cv2; python tools/repair_opencv_contrib.py --check, then --apply.
Categoryimage/CV

Inputs (5)

NameTypeDefaultDescription
maskMASKMask to split. A batch is merged (union) before splitting.
connectivityCOMBO88 also connects diagonal pixels; 4 only direct neighbors.
min_areaINT161–2147483647Regions smaller than this many pixels are dropped (removes noise specks).
max_regionsINT641–1024Keep at most this many regions (after sorting).
sortCOMBOlargest firstOrder of the output region masks/boxes: by area (largest first), left-to-right, or top-to-bottom.

Outputs (3)

NameTypeDescription
region_masksMASKOne full-size mask per region, as a MASK batch.
bboxesBOUNDING_BOXCore BOUNDING_BOX data: per-frame lists of {x, y, width, height} dicts - compatible with Draw BBoxes, Crop By Bounding Boxes, Image Crop, etc.
countINT—