Nodes/ComfyUI CV/Colorize Superpixels (FLANN)
ComfyUI Node

Colorize Superpixels (FLANN)

Steal the palette from a reference image

By bmad4ever·Created 4 months ago·Updated 15 days ago· 1
Colorize Superpixels (FLANN)
  • target
  • reference
  • image
  • success
◄n_seg300►
◄k8►
◄flann_checks16►
◄flann_trees5►
◄guided_r12►
◄guided_eps0.04►

What this is for

A different flavour of colorization from the learned kind: you supply a reference image, and the node transfers its colour onto your grayscale target while keeping the target's own luminance structure. Point it at a summer photo of a garden and a grey scan of a garden, and the grey scan comes back summer-ish. It's the classic "colour transfer" problem, and this implementation does it through superpixel statistics + a FLANN index - the sort of pipeline you'd otherwise write in a notebook outside ComfyUI entirely.

Practical uses: tinting a depth or mask-derived render with a palette from a real photo, matching the grade of a reference when nothing generative is appropriate, and resurrecting a monochrome scan when "plausible" is enough and no prompt exists to guide a diffusion pass.

How it works

The pipeline is genuinely hand-rolled (this is one of the pack's NC nodes, meaning the algorithm is theirs and cv2 supplies primitives, not that it's a wrapper):

  1. Both images are reduced to stride-2 grids of 5×5 luminance patches.
  2. A PCA feature space is fitted on the reference, and both images are projected into it, giving each patch a compact descriptor.
  3. Both images are segmented into SLIC superpixels - roughly n_seg of them each.
  4. Per-superpixel mean descriptors are computed on both sides, and the colour side's mean Lab a/b is averaged per segment.
  5. A FLANN KD-tree is built over the reference's superpixel descriptors, and each gray superpixel runs a kNN query against it.
  6. Chrominance is transferred by distance-weighted kernel regression over those neighbours - close matches dominate, distant ones contribute a little smoothing.
  7. The a/b maps are upsampled to full resolution and, if you asked for it, run through a guided filter with the luminance as guide, so colour stops wandering across edges.

Then L + transferred ab is converted back to BGR. Note the whole thing is NPARRAY-native with its own helpers - it does not lean on cv2.ximgproc superpixels, so it works on a build where those are missing.

Inputs and outputs

Required:

  • target - the grayscale image to colour. A colour image works too; it's converted internally, and you'd still expect the output to take the reference's palette rather than the target's own chroma.
  • reference - whose a/b palette gets transferred. Chrominance only: the reference's luminance is ignored, which is why a bright reference doesn't wash out a dark target.
  • n_seg (default 300, 10–5000) - superpixels. More = finer colour detail, slower.
  • k (default 8) - kNN neighbours. Higher blends more and is smoother; lower is more literal and more prone to patchy matches.

Advanced: flann_checks (search effort), flann_trees (more trees = faster queries, more memory), guided_r (0 disables the guided filter) and guided_eps (higher = smoother, less edge-aware). If you're getting colour bleeding across an obvious edge, the guided filter is the knob; if the result looks flat and dead, guided_r=0 will show you what the raw transfer did.

Two outputs: image and success. success goes false when the pipeline can't produce a result (empty input, no valid segments, FLANN found no matches) - and the node returns a black placeholder image rather than raising, so a failed colorization doesn't halt a long workflow. Branch on it if you care.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
# restart ComfyUI

Or ComfyUI CV in ComfyUI Manager (bmad4ever). Needs Python ≥ 3.12, a V3-node-API ComfyUI and opencv-contrib-python-headless~=5.0.0.93. No models - the "reference" is just an image you already have. Runtime is CPU-bound numpy/cv2 work, so expect a second or three per frame at 300 segments rather than a GPU-speed operation.

Common issues

  • Black output. success is false. Usual causes: empty target, or a target/reference so flat that no superpixels survive. Check the boolean before blaming the palette.
  • Colour bleeds into everything. Raise n_seg (finer segments), lower k, and make sure guided_r isn't 0.
  • Barely any colour at all. The reference and target just don't have matching structure at the patch level - the kernel regression is averaging distant matches into grey. A reference that resembles the target's composition works far better than a reference that merely has nice colours.
  • Contrib-backed nodes from this pack missing. A non-contrib OpenCV wheel overwrote the shared site-packages/cv2; tools/repair_opencv_contrib.py --check / --apply.
Categoryimage/CV/colorize

Inputs (8)

NameTypeDefaultDescription
targetIMAGEGrayscale image to colorize (converted to grayscale internally, so a color image also works).
referenceIMAGEColor reference whose a/b palette is transferred. The target's own luminance structure is preserved.
n_segINT30010–5000Number of SLIC superpixels. More segments = finer color detail but slower.
kINT81–128kNN neighbors. Higher = smoother, more blending.
flann_checksoptINT161–1024FLANN KDTree search checks. Higher = more accurate, slower.
flann_treesoptINT51–50FLANN KDTree tree count. More trees = faster queries, more memory.
guided_roptINT120–100Guided filter radius (0 = disabled). Smooths chrominance while respecting luminance edges.
guided_epsoptFLOAT0.040–10Guided filter epsilon squared. Higher = smoother, less edge-aware.

Outputs (2)

NameTypeDescription
imageIMAGEColorized result: target luminance + reference chrominance transferred via FLANN superpixel matching.
successBOOLEANFalse when the pipeline could not produce a result (empty input, no valid segments, FLANN found no matches).