Apply Noise Pattern (Alpha-safe)
Your cutout still looks pasted in — this is the grain node that fixes it
- image
- noise_pattern
- mask
- base_image
- result
- info
You've composited an AI-generated person onto a real photo, and something's off. The composite subject has that sterile, denoised-looking surface while the background around it has actual sensor grain. That mismatch is one of the biggest "this is AI" tells there is - the community has been calling out too-clean surfaces since 2023, and it's survived every model generation since. ApplyNoisePattern is the last step of the fix: it stamps a real photo's grain back onto your cutout so foreground and background finally live in the same world.
It's the "apply" half of the fuselayer noise-match pack. Feed it a noise_pattern (extracted from a real photo by the pack's RealNoiseExtractor), and it tiles that pattern over your image and blends it in - with alpha and mask handling that doesn't wreck your cutout.
How it works
The noise pattern is a small image whose pixels average to 0.5 (50% gray) - gray encodes "no change," and deviations from gray are the grain. The node tiles that pattern across your image (optionally phase-shifted), then blends.
The default blend_mode is linear_light, which is the classic frequency-separation move: Photoshop retouchers have re-applied high-frequency layers with Linear Light at ~50% opacity for years, and this is the same math. (blend − 0.5) × 2 × strength gets added to the base. That's why the strength default of 0.5 is where you should start - 1.0 is loud, and the tooltip is right that ~0.5 is typical. overlay and soft_light are gentler if linear light feels too crunchy, and add is basically for testing whether your pattern is even doing anything.
The alpha stuff is the actual selling point
The node is alpha-safe, which is where a lot of naive grain-overlay approaches fall apart. With respect_alpha on (default), your image's own alpha channel becomes the mask - so the grain only lands on the cutout, not on the background it's pasted over. An external mask input unions with that. Three inputs beginners should know:
mask_feather_px- softens the mask edge so you don't get a crisp grain boundary line around the cutout. The default 1px is subtle; bump it if you see an edge.treat_input_as_premultiplied- for premultiplied PNGs. If your cutout has dark fringing around the edges, try this on; it unpremultiplies before blending and re-premultiplies after.base_image- lets you composite straight over a background inside this one node, which is what the author calls the "2-image workflow." If your image is an RGBA cutout and a background is available, wire it here and the node handles the composite.
offset_x / offset_y shift the pattern's phase, and randomize_phase + seed gives you per-run variation - handy for batches.
Outputs
result- the composited IMAGE. Preview it, save it, done.info- a STRING debug dump: which mask sources were used (alpha, external, none→full), mask coverage %, feather width, whether premultiplication ran, whether the base image was composited, and the output channel count. Paste this when asking for help; it answers the questions people would otherwise make you screenshot.
Install
It ships in the fuselayer/comfyui-noise-match pack, so you get all four nodes at once. ComfyUI Manager can find it (it's registered with the Comfy Registry as "comfyui-noise-match"), or:
cd ComfyUI/custom_nodes
git clone https://github.com/fuselayer/comfyui-noise-match
Then restart ComfyUI. The nodes land under image/noise. The real requirements.txt pulls numpy, scipy, and opencv-python - the code degrades gracefully if OpenCV is missing (falls back to scipy), but let the installer grab it. No model downloads; this is pure image math, runs on CPU fine.
Common issues
- Result looks washed out or nothing changes: your pattern isn't centered at 0.5. Run it through the pack's
NoisePatternVisualizer- it flags exactly this. A pattern with the wrong mean shifts brightness globally instead of adding grain. - Grain visible on the background, not just the cutout: your mask coverage is wrong. Check the
infostring - it tells you coverage % and which mask sources fired. - Hard grain line at the cutout edge: crank
mask_feather_pxup a few pixels. - The bundled example workflow won't load: it also uses rgthree's
Display Any/Image Comparerand an AILab mask-preview node - separate packs. Install those or ignore the example; the four noise nodes themselves are self-contained.
One honest caveat: this adds noise, not a pixel-perfect copy of the sensor's statistics - but for killing that "clean AI object on a noisy photo" tell, it's the closest thing to a one-click fix in ComfyUI.
Inputs (13)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| noise_pattern | IMAGE | — | |
| strength | FLOAT | 0.500–2 | Noise intensity. ~0.5 typical for Linear Light |
| blend_mode | COMBO | linear_light | Blending algorithm |
| maskopt | MASK | — | |
| base_imageopt | IMAGE | — | |
| respect_alphaopt | BOOLEAN | true | Use image alpha as mask if present |
| mask_feather_pxopt | FLOAT | 1.00–10 | Feather the effective mask (in pixels) to soften edges |
| treat_input_as_premultipliedopt | BOOLEAN | false | Unpremultiply RGB by alpha before blending; re-premultiply after |
| offset_xopt | INT | 00–4096 | — |
| offset_yopt | INT | 00–4096 | — |
| randomize_phaseopt | BOOLEAN | false | — |
| seedopt | INT | 00–2147483647 | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| result | IMAGE | — |
| info | STRING | — |