ComfyUI Node

Spectral Histogram Match

Make an AI image's spectrum statistically indistinguishable from a photo

By EdoardoGuerriero·Created 2 months ago·Updated 2 months ago· 0
Spectral Histogram Match
  • image_source
  • image_target
  • image
strength0.75
tile_size0
tile_overlap64

Histogram matching in pixel space is an old, reliable trick: remap one image's brightness distribution to match another's. SpectralHistogramMatch does the frequency-domain version - it remaps the FFT coefficient magnitudes of your source image so their statistical distribution matches a target image's. Unlike pixel-space matching, this never touches colour or spatial structure; it only changes the distribution of spectral energy. Phase is always preserved, so edges, object positions, and generated content survive intact.

The pitch in the pack's README is clean and worth taking seriously: use it pre-processing to make a synthetic or AI-generated image spectrally indistinguishable from a natural photograph before VAE encoding, or post-processing to give a generated image the same grain and texture character as a reference without altering its colours or content. If you've ever stared at an img2img output that "still looks AI" no matter the denoise, this is aimed at the mechanism behind that feeling.

It's the global, simpler sibling of RadialStratifiedHistogramMatch (which matches per radial band). This node does one CDF match across the whole spectrum - fewer knobs, faster, and right when you just want the overall character to converge. The README's demo shows the pair side by side: after matching, the source's FFT spectrum visibly converges toward the target's.

The inputs that matter

  • image_source - the image whose spectral magnitude distribution gets remapped (your AI output or img2img input).
  • image_target - the reference; its magnitude distribution is the target (feed it a clean natural photo).
  • strength (default 0.75) - 0 = no change, 1 = fully matched. The tooltip's starting range is 0.5–0.8.

Plus the pack-standard tile_size/tile_overlap for large images (0 = whole image, fine for most cases). One image output.

Installing it

Ships in ComfyUI-Spectral-Preprocessing-Nodes - one install, all sixteen nodes under Spectral Preprocessing. ComfyUI Manager (search "ComfyUI-Spectral-Preprocessing-Nodes"), or:

cd ComfyUI/custom_nodes
git clone https://github.com/EdoardoGuerriero/ComfyUI-Spectral-Preprocessing-Nodes

Restart. Only numpy and scipy (both bundled); nothing to download.

Where people get burned

The two-input setup trips up the first-timer more than anything else: nothing happens (or the wrong thing happens) because the target isn't wired in or is the same as the source. You need a different reference image - for the pre-processing use case, a natural photograph, not another AI image. Second, don't expect a visible pixel change at low strength; like most of this pack, the meaningful change is in the spectrum and how the VAE responds to it. Verify with the FFT Spectrum Visualizer's log-magnitude panel - the point is that the source's spectrum starts resembling the target's, not that the image looks different. And remember the strength dial: 0.75 default means you're keeping a quarter of the source's original spectral character, which is usually the right compromise between "natural enough for the encoder" and "still recognizably your image."

CategorySpectral Preprocessing

Inputs (5)

NameTypeDefaultDescription
image_sourceIMAGEImage whose spectral magnitude distribution will be remapped.
image_targetIMAGEReference image — its magnitude distribution is the target.
strengthFLOAT0.750–10 = no change to source. 1 = fully match target magnitude distribution. 0.5–0.8 is a good starting range.
tile_sizeINT00–2048Tile size for large images. 0 = whole image.
tile_overlapINT640–512Tile overlap in pixels (used only when tile_size > 0).

Outputs (1)

NameTypeDescription
imageIMAGE