Nodes/ComfyUI-HiddenImages/NanoBanana Pattern Preprocessor
ComfyUI Node

NanoBanana Pattern Preprocessor

The node that decides whether your QR actually scans

By GeekatplayStudio·Created 5 months ago·Updated 24 days ago· 0
NanoBanana Pattern Preprocessor
  • image
  • image
  • mask
blur_radius6.0
contrast1.60
brightness1.00
threshold0.50
invertfalse

The whole trick of a hidden-image workflow is smuggling a machine-readable pattern - a QR code, a logo, a strip of text - into a picture that doesn't look like a pattern at all. The pattern preprocessor is where you win or lose that bet. Feed it the raw QR PNG you made in an online generator and it hands back the clean, high-contrast condition that a brightness/pattern ControlNet actually wants. Skip it, or run it badly, and you get an image that looks like it has a QR in it and fails to scan on a phone. That's the failure mode every hidden-image beginner hits.

What it actually does

It's a small PIL pipeline, and the source is short enough to read in a minute. Each input frame gets converted to grayscale, optionally blurred with a Gaussian, pushed through contrast and brightness enhancements, and then thresholded: every pixel above threshold * 255 becomes white, everything below becomes black. You get a clean binary map instead of the jittery gray mess a camera photo or a rendered logo starts as.

That final threshold is the important part. Hidden-image ControlNets (the SD 1.5 QR Code Monster line, the SDXL optical-pattern models) are trained on crisp black-and-white input. Soft grays confuse them and the generated QR ends up not scannable.

Inputs that matter

  • threshold (default 0.5) - the cutoff for black vs white. This is the one you'll actually touch.
  • contrast (default 1.6) - push it up when your source art is gray and washed out.
  • blur_radius (default 6) - smooths jaggies, but too much melts fine QR modules. For QR art, keep it small.
  • brightness (default 1.0) and invert - use invert when your source is white-on-dark and the ControlNet wants black-on-white (or vice versa).

The outputs are named image and mask: image is the processed grayscale, mask is the same content thresholded. Wire image into your ControlNet's image input - that's the common mistake, people grab the mask and wonder why the control is wrong.

Installing it

This is part of the ComfyUI-HiddenImages pack, so you get all four NanoBanana nodes at once. Easiest path is ComfyUI Manager: search "ComfyUI-HiddenImages" and install. Or by hand:

cd /path/to/ComfyUI/custom_nodes
git clone https://github.com/GeekatplayStudio/ComfyUI-HiddenImages.git
cd ComfyUI-HiddenImages
./install.sh

The nodes themselves only need Pillow and numpy - no CUDA weight. But the installer is where the real work happens: it downloads the ControlNet weights, and clones ComfyUI-Manager, ComfyUI_IPAdapter_plus, and comfyui_controlnet_aux if you don't have them. The qr preset grabs the SD 1.5 QR Code Monster v2 mirror and the SDXL optical-pattern model. One honest caveat: QR Monster never got a port past SDXL, so your scannable-QR work lives on SD 1.5/SDXL. The FLUX side of this pack is the ghost workflow, which uses Canny instead.

Troubleshooting

Your output won't scan - the checklist, roughly in order: raise contrast, check that threshold isn't sitting on the gray values your source is full of, and confirm you haven't inverted the polarity away from what the ControlNet expects. If the pattern is there but mushy, lower the blur and turn the ControlNet strength up (that's what the pack's Magic Scheduler is for). And remember the ControlNet eats the image output, not the mask.

It's a tiny node, honestly - a few PIL calls. But it encodes the fiddliest part of a QR workflow, and once you've fought an unscannable "artistic QR" for an afternoon you'll appreciate having the polarity and threshold logic already done.

CategoryNanoBanana/Illusion

Inputs (6)

NameTypeDefaultDescription
imageIMAGE
blur_radiusFLOAT6.00–64
contrastFLOAT1.600.1–4
brightnessFLOAT1.000.1–3
thresholdFLOAT0.500–1
invertBOOLEANfalse

Outputs (2)

NameTypeDescription
imageIMAGE
maskMASK