CV Superpixels
Stop Editing Pixels, Start Editing Regions
- image
- labels
- contours
- count
A pixel grid is a terrible unit for image editing. Colour one and you've coloured 1/2,000,000th of a picture; mask a face and you get a jagged outline that ignores where the face actually ends. Superpixels fix that: they group pixels into small regions that are uniform in colour and respect edges, so every region is already a coherent chunk of something.
That makes them the right unit for region-wise recolouring, palette work, cartoon flattening, and masks that snap to real boundaries instead of a hand-drawn polygon. The pack's CV Snap Mask To Labels blueprint exists for exactly that last job - round a rough mask onto superpixel edges so the outline follows the subject.
How it works
This wraps cv2.ximgproc's superpixel implementations. algorithm is the real choice:
- SLIC needs an explicit
compactness, so you control the shape/edge tradeoff by hand. - SLICO (the default) tunes compactness per region. It's the one to leave on unless you have a reason.
- MSLIC adds manifold-aware sizing on top.
- LSC preserves fine structure best - and note that its
compactnesswidget is actually the LSC ratio (0–1), so the node divides the shared 0–100 slider by 100 before passing it. - SEEDS and ScanSegment are the fast ones, and they take a target count instead of a region size.
That last point is the input that confuses people. region_size (default 20) drives the SLIC family: it's the average superpixel width in pixels, so the number of regions follows from your image size. num_superpixels (default 200) drives SEEDS and ScanSegment, and is ignored by the others. Which one is live depends on algorithm - the node feeds each implementation the parameter it actually uses.
iterations (default 10) is refinement passes: more gives better-fitting boundaries, linearly slower. 4–10 is usually enough.
compactness (default 10) is how hard regions are pulled towards a tidy compact shape. High gives neat square-ish blobs that happily cut across edges; low gives ragged regions that hug them. SLICO ignores it, LSC reinterprets it as described above.
enforce_connectivity (default on) merges stray disconnected fragments into their neighbours, so every label is one connected region rather than a scattering of islands. Turn it off only if you want raw clustering.
Outputs
labels - an int32 (H,W) map where each pixel holds its region index, 0..count-1. contours - a uint8 (H,W) mask with 255 on region boundaries, which is the cheapest way to see what the segmentation did; overlay it and you'll know in two seconds whether your region_size is sane. count - how many superpixels you actually got, which can differ from what you asked for.
Preview labels with Preview CV Array in normalize mode. The classic chain is labels → CV Reduce Array By Label (mean) to get one colour per region → CV Take By Index to paint them back - that's the CV Superpixel Paint blueprint in docs/subgraphs.md, and 25_saliency_superpixels.json shows the mask-snapping version.
Install
ComfyUI Manager → search ComfyUI CV (publisher bmad4ever), or:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"
Restart after. Python ≥ 3.12 and a recent ComfyUI on the V3 node API.
This is a contrib node in the strict sense - ximgproc is contrib-only, so the contrib wheel isn't optional here. Install a plain opencv-python alongside and the two share site-packages/cv2; the contrib submodules go empty and this node stops working while the plain cv2 nodes keep going, which is a confusing way to find out. tools/repair_opencv_contrib.py --check diagnoses, --apply repairs.
Sample images come via workflows/01_install_example_inputs.json - run it once, then reload the page so the dropdowns see the files.
Where it bites
count is the number you should read, not the one you set. Very small regions on a busy image can end up with a few stray pixels, and if you're feeding labels into per-region statistics those tiny regions skew the numbers - bump region_size or leave enforce_connectivity alone.
The usual pack caveat, in the author's own words: personal project, heavy LLM assistance, curated against one OpenCV build, no support planned, workflows not production-grade. The wrapper itself is faithful - this is a straight ximgproc call with well-chosen defaults - so the caveat is about trusting the presets, not the plumbing.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| image | NPARRAY,IMAGE | Image to segment (3-channel). Frame 0 of a batch. 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. | |
| algorithm | COMBO | SLICO | SLIC needs an explicit compactness; SLICO (the default) tunes it per region; MSLIC adds manifold-aware sizing. LSC preserves fine structure best. SEEDS and ScanSegment take a TARGET COUNT instead of a region size and are the fastest. |
| region_size | INT | 204–512 | SLIC/SLICO/MSLIC/LSC: average superpixel width in pixels - the region COUNT follows from the image size. Ignored by SEEDS/ScanSegment, which use num_superpixels instead. |
| num_superpixels | INT | 2002–10000 | SEEDS/ScanSegment: how many regions to aim for (approximate). Ignored by the others. |
| iterations | INT | 101–100 | Refinement passes. More = better-fitting boundaries, linearly slower; 4-10 is usually enough. |
| compactnessopt | FLOAT | 10.00.1–100 | SLIC/MSLIC: how strongly regions are pulled towards a compact shape. High = tidy squarish blobs that cut across edges; low = ragged regions that hug edges. For LSC this is the 'ratio' (0-1); SLICO ignores it entirely. |
| enforce_connectivityopt | BOOLEAN | true | Merge stray disconnected fragments into their neighbours so every label is one connected region. Turn off only if you want the raw clustering. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| labels | NPARRAY | int32 (H,W) map: the region index each pixel belongs to, from 0 to count-1. |
| contours | NPARRAY | uint8 (H,W) mask, 255 on region boundaries - overlay it to see the segmentation. |
| count | INT | Number of superpixels actually produced (may differ from the requested count). |