Nodes/opencv-comfyui/OpenCV kmeans_0
ComfyUI Node

OpenCV kmeans_0

Clustering and color quantization, the raw way

By geroldmeisinger·Created about a year ago·Updated about a year ago· 35
OpenCV kmeans_0
  • data
  • bestLabels
  • centers
  • float
  • nparray_1
  • nparray_2
K
criteria
attempts
flags

OpenCV kmeans_0 wraps cv2.kmeans, the classic unsupervised clustering algorithm - and it's one of the genuinely interesting nodes in this pack, because it's the engine behind a trick a lot of people want: color quantization. K-means finds K representative colors for your data, and for an image that means "these K colors best summarize the palette." The KB's post-processing essay calls this out explicitly - palette reduction for pixel art and limited-palette looks is k-means applied to an image's pixels.

So the alluring use case is real. The catch is that this pack exposes cv2.kmeans raw: data has to be a 2D float array of shape (samples, dimensions), and your (H, W, 3) image is neither flat nor float. To quantize an image you'd reshape pixels to an N×3 float32 array first - which needs a scripting/reshape node, because this pack has no reshape node. If you can provide the right-shaped array, you get a proper clustering node in your graph. If not, you'll spend an afternoon fighting shapes for a result simpler palette tools give you directly.

How it works

cv2.kmeans(data, K, bestLabels, criteria, attempts, flags, centers) runs Lloyd's algorithm: pick K initial centroids, assign every sample to the nearest one, move each centroid to the mean of its cluster, repeat until criteria is met. It returns three things: the compactness (sum of squared distances of samples to their centroids - lower is tighter), the per-sample cluster index array, and the final centroids. Because the initial centroids are random, attempts runs the whole thing multiple times and keeps the best result.

Inputs and outputs

  • data - NPARRAY, (N, dims) float32 samples. For color quantization that's pixels as (N, 3).
  • K - INT, number of clusters (the palette size).
  • bestLabels - NPARRAY, required input even though it's an output - a quirk of this auto-generator: the stub didn't type it | None, so you must connect something (any array of the right shape) and it gets overwritten.
  • criteria - STRING, a Python literal parsed with ast.literal_eval. It's a TermCriteria tuple (type, maxCount, epsilon), e.g. (3, 10, 1.0) - type 3 = EPS+MAX_ITER, stop after 10 iterations or when movement < 1.0.
  • attempts - INT, restarts with different random seeds.
  • flags - INT: 0 KMEANS_RANDOM_CENTERS, 1 KMEANS_USE_INITIAL_LABELS, 2 KMEANS_PP_CENTERS (k-means++ initialization - better quality, costs a bit more).
  • centers - optional NPARRAY out-parameter; returned anyway.
  • Outputs: float (compactness), nparray_1 (labels, one per sample), nparray_2 (centroids, K × dims).

Installing

From opencv-comfyui:

cd ComfyUI/custom_nodes
git clone https://github.com/geroldmeisinger/opencv-comfyui
cd opencv-comfyui
pip install -r requirements.txt

or ComfyUI Manager → "opencv-comfyui". No models; deps are opencv-contrib-python, numpy, torch.

Gotchas

Three things will bite you, in order. (1) The criteria string must be valid Python literal syntax or you get the pack's signature invalid syntax (<unknown>, line 0) - the README's convention is parentheses, so write it like (3, 10, 1.0), a tuple of (type, maxCount, epsilon). (2) data must be float32 and 2D; feeding an image-shaped array throws. (3) bestLabels is required even though you never set it meaningfully - connect a placeholder nparray and read the real result off nparray_1. Set flags=2 (k-means++) for the best palette quality, and kmeans_0 vs kmeans_1 are identical overload duplicates as always.

Categoryimage/OpenCV

Inputs (7)

NameTypeDefaultDescription
dataNPARRAY
KINT
bestLabelsNPARRAY
criteriaSTRING
attemptsINT
flagsINT
centersoptNPARRAY

Outputs (3)

NameTypeDescription
floatFLOAT
nparray_1NPARRAY
nparray_2NPARRAY