KMeansColor
Posterize an image down to N dominant colors — KMeansColor
- image
- IMAGE
KMeansColor reduces an image to a fixed number of flat colors using k-means clustering, and outputs the quantized result. If "reduce to N colors" sounds like posterization, that's because it basically is - but the "N colors" here are computed from your image's actual dominant palette, not chosen by you. Give it number_of_colors = 5 and you get back the same picture rendered in its 5 most representative colors, every pixel snapped to the nearest one.
The interesting word in that sentence is "dominant." K-means doesn't just down-sample the palette; it finds the clusters in pixel-color space, so the output colors genuinely summarize what's in the image - the sky's blue, the skin tone, the grass. That makes it useful in a few ComfyUI spots: flat-color stylization, simplifying an image before color-based masking, or preprocessing for further color work. The pack groups it under "Color A." (color analysis), alongside FindComplementaryColor and SampleColorHSV, so think of it as part of the color-toolkit, not a filter you'd throw on a finished render.
How it works
Under the hood it's OpenCV's kmeans on the flattened pixel array. The pixels become 3D points in RGB space, and k-means finds number_of_colors cluster centers:
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, max_iterations, eps)
_, labels, centers = cv.kmeans(pixels, number_of_colors, None, criteria, 10, cv.KMEANS_RANDOM_CENTERS)
Then every pixel is replaced with its cluster center's color. The 10 is the number of attempts - k-means is randomized, so it runs 10 times and keeps the best. max_iterations and eps control when the clustering stops converging; for most images the defaults (100 iterations, eps 0.2) are fine, and you only touch them if you want a tighter or looser fit.
Inputs and outputs
image- the IMAGE to quantize.number_of_colors- INT, default2, minimum1. This is the one you'll actually tune: 2-4 gives bold flat shapes, 8-12 keeps more of the original look.max_iterations- INT, default100. Cap on clustering iterations.eps- FLOAT, default0.2, step0.05. Convergence threshold; smaller = stricter, more iterations.- Output: one IMAGE, the same size with colors reduced to the cluster centers.
Install
Ships in bmad4ever/comfyui_bmad_nodes. Via ComfyUI Manager, search "comfyui_bmad_nodes" ("Bmad Nodes"), install, restart. Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_bmad_nodes
cd comfyui_bmad_nodes
pip install -r requirements.txt
Restart ComfyUI after. Needs opencv-python and numpy (numpy ships with the ComfyUI environment); no model files.
Common issues
Two things to know. First, k-means is randomized - the exact clusters can shift slightly between runs because of the random center init, so don't expect pixel-identical output on reruns; bump up the attempts in code if determinism ever matters. Second, this node outputs the image, not the list of palette colors. If your actual goal is "give me the 5 dominant hex values," you want a different node (FindComplementaryColor or SampleColorHSV fit that bill better); KMeansColor is for when you want the quantized picture. And don't forget number_of_colors is what drives everything - leave it at 2 and you'll wonder why your image turned into a two-tone silhouette.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| number_of_colors | INT | 2 | — |
| max_iterations | INT | 100 | — |
| eps | FLOAT | 0.20 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |