ComfyUI Node

ColorshiftColor

Turn any image into a numbered color palette you can actually recolor

By 852wa·Created 2 years ago·Updated 2 years ago· 53
ColorshiftColor
  • images
  • lock_masks
  • palette_override
  • images
  • palette
  • index_maps
  • palette_preview
color_count8
font_size20
sampling_rate0.25
n_init3

ColorshiftColor is a KMeans color-quantization node: it crushes an image down to a fixed number of flat colors, then hands you the palette, a per-pixel index map, and a numbered preview so the rest of the pack can recolor by swatch number. It's the entry point of the ComfyUI-ColorshiftColor pack (alongside CsCPaletteEditor and CsCFill), and it's built for one specific job: flat-color cel/anime art that you want to re-theme or batch-recolor without repainting a single region.

If your images are photographs, this is the wrong tool - KMeans on a photo just gives you posterized mush. Feed it clean flat art and it's the difference between "recolor by hand in Krita" and "type a number, hit run."

How it works

The node clusters pixels in RGB space with scikit-learn's KMeans, then assigns every pixel to its nearest cluster center. Two details keep it fast and predictable:

  • It downsamples the image 0.5x and clusters only a sampling_rate slice (default 0.25) of those pixels, so it's cheap even on full video frame batches. That's the whole point of the sampling_rate slider - lower it on big images for speed, nudge it up if the palette comes out wrong.
  • After clustering it re-sorts the palette by screen area, so the biggest color region is index 0, then 1, 2... That ordering matters: every other node in the pack references swatches by number.

KMeans itself uses a fixed random state, so palette geometry is reproducible for a given image; the pixel sampling isn't seeded, so expect tiny run-to-run wobble. Irrelevant for recolor work.

The inputs that matter

Two dials you'll actually touch, and a pile of options:

  • images - any IMAGE, stills or a batch of video frames.
  • color_count (2–64, default 8) - how many flat colors to reduce to. This is the parameter. Too few and adjacent colors merge; too many and it stops being "flat."

The rest are set-and-forget: sampling_rate (speed/accuracy), n_init (KMeans restarts, leave at 3), font_size (size of the numbers on the preview). palette_override lets you force your own palette instead of computing one - the node just matches every pixel to the nearest color in yours. lock_masks keeps the regions you mask out of the quantization untouched.

What comes out

  • images - the quantized, flat-color image.
  • palette - the N colors as a PALETTE tensor.
  • index_maps - the sneaky one. It's typed MASK, but it does not carry 0–1 alpha values: it's an integer label per pixel (0 to color_count−1) saying which swatch that pixel belongs to. Don't feed it into normal mask math expecting floats.
  • palette_preview - the numbered swatch grid, ready to eyeball or save. Those numbers are what lock_color_num and the operations strings in the sibling nodes reference.

Install

No model files, no API keys, nothing to download - just one Python dependency, which the README flags in its very first line:

cd ComfyUI/custom_nodes
git clone https://github.com/852wa/ComfyUI-ColorshiftColor
pip install scikit-learn

Or skip the shell: search "ComfyUI-ColorshiftColor" in ComfyUI Manager and hit install. Restart ComfyUI after. scikit-learn is the only non-trivial dependency (it's the KMeans engine) and it's pure CPU, so it installs in seconds.

Issues worth knowing

  • The README is Japanese. The gist that matters: for single-color-background video, don't render with Video Combine - the README says the encoder adds noise, and recommends saving numbered PNGs with SaveImage instead. The example workflows use VideoHelperSuite to load video and feed frames through this node in a batch.
  • It will happily quantize a photo, and the result will look like a 1998 web-safe color scheme. Match the tool to the flat art, and it's genuinely great.
CategoryImage/Color

Inputs (7)

NameTypeDefaultDescription
imagesIMAGE
color_countINT82–64
lock_masksoptMASK
palette_overrideoptPALETTE
font_sizeoptINT2010–50
sampling_rateoptFLOAT0.250.01–0.5
n_initoptINT31–10

Outputs (4)

NameTypeDescription
imagesIMAGE
palettePALETTE
index_mapsMASK
palette_previewIMAGE