Nodes/ComfyUI CV/cv2.kmeans
ComfyUI Node

cv2.kmeans

Palette, clusters and grouping — the workhorse the pack builds three subgraphs around

By bmad4ever·Created 4 months ago·Updated 14 days ago· 1
cv2.kmeans
  • data
  • bestLabels
  • retval
  • bestLabels
  • centers
◄K0►
◄criteria_typemax count or epsilon (whichever first)►
◄criteria_max_count30►
◄criteria_epsilon0.00►
◄attempts0►
◄flagsKMEANS_PP_CENTERS►

K-means is the algorithm you reach for when you want N groups and nobody's told you where the boundaries are: eight colours for a palette, five sizes of blob, three kinds of texture. cv2.kmeans is OpenCV's implementation - Lloyd's algorithm with k-means++ seeding - and it's the single most reused node in bmad4ever/comfyui_cv, which ships three subgraph blueprints built on it (CV K-Means Colors, CV K-Means Mask Clusters, CV K-Means Points) plus a workflow playground.

Its input is points, not pixels. That's the thing to get straight before anything else.

Inputs that matter

  • data - an N × D array of float coordinates, and float32 specifically: the tooltip says so, and the pack's own blueprint notes that cv2 asserts on it, "so the blueprint casts". CV Cast Array to float32 is the step you'll forget. Pixels need reshaping into a point list first - an image is H × W × C, and k-means wants rows of numbers. The pack's CV Reshape Array and the blueprint's flattening are how that happens.
  • K - the number of clusters. Must be ≥ 1 and no greater than your sample count. Here's the trap the pack documents: cv2.kmeans asserts when you ask for more clusters than samples, so the Detect Spectral Peaks (K-Means) blueprint pads its feature table with dummy rows and drops them afterwards because "zero peaks is valid".
  • criteria_type / criteria_max_count / criteria_epsilon - the stop condition, split into a real dropdown plus two numbers (30 iterations, 0.001 epsilon by default) instead of cv2's opaque (type, max, eps) tuple. You stop after a max count, when the movement drops below epsilon, or whichever comes first.
  • attempts - how many times to run the whole thing from different initial labels, keeping the best result. Higher is more stable and linearly slower.
  • flags - KMEANS_PP_CENTERS (the default, and the one you want), KMEANS_RANDOM_CENTERS, or KMEANS_USE_INITIAL_LABELS if you're supplying a starting labelling.
  • bestLabels - an optional NPARRAY, for warm-starting.

Outputs: retval (the compactness - the sum of squared distances from each point to its centre, i.e. lower is a tighter fit), bestLabels (int32, one cluster index per sample), and centers (float32, one row per cluster - your palette, or your cluster centroids).

The part people miss: it's random

K-means draws from OpenCV's global RNG, so the same graph can give you different clusters on different runs. The pack's blueprint handles this by setting the seed internally, and the pack ships CV Random Seed (cv2.setRNGSeed with a passthrough) precisely for "repeatable kmeans/randu/RANSAC". If you're tuning K and want to compare like with like, seed it.

What each shape is good for

Colour quantization. Flatten the pixels, cluster in 3D RGB (or Lab), then use the labels to map each pixel to its centre - that's a palette-limited image, and it's the honest way to make a small-colour-space look rather than asking a diffusion model to fake pixel art. CV K-Means Colors is that pipeline, plus a coverage-sorted palette strip.

Grouping regions by measured properties. CV Region Properties gives you a feature matrix (area, circularity, orientation, colour), and k-means groups the blobs by it. "No position | area" clusters by size, ignore position and you get shape families. The blueprint clamps k to the region count, so asking for more clusters than blobs doesn't explode.

Clustering a point set - keypoints, detections, 3D points - for a spatially grouped summary.

Labels are indices, so the consumers downstream are CV Take By Index, CV Reduce Array By Label (one row per cluster: mean/sum/count) and the pack's label-to-mask nodes.

Installing the pack

Manager → search comfyui_cv, or:

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"

Python ≥ 3.12 and a recent ComfyUI (V3 node API), OpenCV curated at 5.0.0.93. Core function - no contrib needed for this node - and no model downloads. The three K-Means blueprints live in the repo's subgraphs/ folder and are one-node workflows you can open and build around.

Where people get burned

Not float32. cv2 asserts, and it's the single most common failure.

Passing an image instead of points. data is typed NPARRAY-only because it's data; reshape to N × D first.

More clusters than samples. Assert, not a warning. Pad or clamp.

Comparing runs without seeding. Different labels for the same data, and you conclude something's wrong with K when nothing is.

Expecting cluster indices to be stable across runs. They aren't - cluster 0 in one run can be cluster 3 in the next, even with the same centres, because the numbering follows discovery order. Sort by centre value (or by coverage) before you compare or colour anything.

As always with this pack: the README states it's a personal, heavily LLM-assisted project, with a warning against production use without your own review. K-means is a good one to sanity check on your own data - a palette of eight colours either looks like eight colours or it doesn't.

Categoryimage/CV/low-level/cv2 K

Inputs (8)

NameTypeDefaultDescription
dataNPARRAYData for clustering. An array of N-Dimensional points with float coordinates is needed. Examples of this array can be: - Mat points(count, 2, CV_32F); - Mat points(count, 1, CV_32FC2); - Mat points(1, count, CV_32FC2); - std::vector\ points(sampleCount); A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here.
KINT0-2147483648–2147483647Number of clusters to split the set by.
criteria_typeCOMBOmax count or epsilon (whichever first)When to stop iterating: after max_count iterations, when the change drops below epsilon, or whichever comes first.
criteria_max_countINT301–2147483647Maximum iterations (ignored when 'epsilon only').
criteria_epsilonFLOAT0.000–1e+38Target accuracy / smallest change worth continuing for (ignored when 'max count only').
attemptsINT0-2147483648–2147483647Flag to specify the number of times the algorithm is executed using different initial labellings. The algorithm returns the labels that yield the best compactness (see the last function parameter).
flagsCOMBOKMEANS_PP_CENTERSFlag that can take values of cv::KmeansFlags
bestLabelsoptNPARRAYInput/output integer array that stores the cluster indices for every sample. Optional - leave unconnected for the OpenCV default (None). A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here.

Outputs (3)

NameTypeDescription
retvalFLOAT—
bestLabelsNPARRAY—
centersNPARRAY—