Ideogram Masked Palette Extractor
The Palette of Just the Subject, Not the Whole Frame
- image
- mask
- palette_json
- palette_preview
- color_count
The plain palette extractor looks at the whole image. That's a problem the moment your subject is a small part of a busy frame: a red jacket worn by a figure standing in front of a green field produces a palette that's mostly greens, and the jacket's red - the color you actually want to match - drowns. IdeogramMaskedPaletteExtractor only extracts colors from the pixels inside a mask, so you get the palette of the subject, not the scene.
This is the node that makes per-element palettes actually accurate. Ideogram 4's compositional_deconstruction schema lets each region of a generation carry its own reference palette, and a region-accurate palette is what makes that regional control read as intentional instead of random. Mask the subject → get its true colors → feed them to the element builder. The pack's showcase workflow showcase_04_masked_subject_and_global.json does exactly this: masked extraction for the per-element palette, plain extraction for the global one, two palettes in one structured prompt.
Inputs and how it works
The pipeline underneath is the same k-means + Delta-E (perceptual LAB distance) extraction as the rest of the pack, but the pixel pool is restricted to the masked region before clustering runs. Inputs:
image- the source IMAGE.mask- a MASK, from any of ComfyUI's many masking/sampling nodes.num_colors- 2 to 16, default 8.min_delta_e- 0 to 100, default 10.0. Perceptual distance floor between kept colors.mask_threshold- 0.0 to 1.0, default 0.5. Pixels with mask values above this count as "in the region."
Outputs: palette_json, palette_preview (swatch strip), color_count.
The mask_threshold input is the subtle one. Masks are grayscale, and a soft-edged mask from a blur or a SAM segmentation has no crisp boundary. The threshold decides where "in" becomes "out." Lower it and you include more of the feathered edge; raise it and you tighten toward the mask's bright core. If your palette keeps picking up background colors, your threshold is too low.
The graceful-failure behavior you'll appreciate
An empty or below-threshold mask - the classic footgun when a mask node produced nothing - doesn't crash. The node falls back to a single gray #808080 swatch and keeps the graph running. Annoying if it happens silently, but far better than a bricked workflow. If you ever see a one-color gray palette where a rich one should be, the mask is your first suspect.
Installing it
Same pack, same install. ComfyUI Manager: search "Ideogram Palette and Prompt Tools". Or:
cd ComfyUI/custom_nodes
git clone https://github.com/SurrealByDesign/ComfyUI-Ideogram-Palette-and-Prompt-Tools
Restart ComfyUI. Only extra dependency: scikit-learn (Manager installs it from requirements.txt, or pip install scikit-learn). torch/numpy/Pillow deliberately not pinned - ComfyUI already ships them, and the author won't risk a torch reinstall breaking your CUDA setup. Nodes under Ideogram/Palette, Python ≥ 3.10, tested on ComfyUI 0.24.0 / Python 3.12.
Gotchas and troubleshooting
- Mask and image must be the same resolution. A resized or padded mismatch silently changes which pixels get selected. If the palette looks wrong, check the mask dimensions first.
- Gray fallback = empty mask. Verify the mask node actually output something (PreviewImage it) before debugging the extraction itself.
- Small regions give small palettes. A tiny subject with a handful of distinct colors may return fewer than
num_colors- that's the dedup working, and for a ≤5-color element palette that's usually fine. - This is a regional tool, not a whole-frame one. If you have no mask, the plain
IdeogramPaletteExtractoris the node you want; don't reach for this one and fight with thresholding for no reason.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| mask | MASK | — | |
| num_colors | INT | 82–16 | — |
| min_delta_e | FLOAT | 10.00–100 | — |
| mask_threshold | FLOAT | 0.500–1 | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| palette_json | STRING | — |
| palette_preview | IMAGE | — |
| color_count | INT | — |