Nodes/ComfyUI-CustomNodePacks/Grain Match (MEC)
ComfyUI Node

Grain Match (MEC)

Grain Match (MEC)

By Code2Collapse·Created 6 months ago·Updated a day ago· 52
Grain Match (MEC)
  • reference
  • target
  • image
  • info_json
intensity1.00
denoise_kernel5
seed0

Grain Match (MEC) is the anti-"AI look" node. Diffusion output reads as generated partly because it's too clean - real cameras and film carry noise, AI output doesn't, and adding a little back is the single cheapest move for making an image or video read as captured rather than synthetic. But slapping a random noise overlay on looks worse than nothing. The whole point of this node is that it extracts the actual grain from a reference plate and re-applies it to your target, so the grain matches the footage's character instead of fighting it.

It's part of the Plate Tools in ComfyUI-CustomNodePacks, the ~72-node umbrella pack from Code2Collapse (Likhith-24, active on r/comfyui). If you're compositing AI elements into real footage, "plate" is exactly what that reference background is called - and matching the grain of your synthetic addition to the plate is how the composite stops looking pasted on.

How it works

The mechanism is simple and honest, straight from the source code:

  1. Estimate grain = reference − denoise(reference). It box-filters the reference with denoise_kernel (default 5), subtracts the smooth result from the original, and what's left is the grain signature.
  2. Rescale and add. The extracted grain is scaled by intensity and added to your target, clamped back to 0-1.
  3. Per-frame variety. If the reference has multiple frames, it samples a random reference frame for each target frame (seeded by seed), so the result is temporally non-static - a static noise pattern on video is how you spot the fake.

Three optional knobs: intensity (0 to 4, default 1 - 1.0 means "apply the reference's grain at full strength"), denoise_kernel (3-15, the smoothing radius that sets how much detail counts as grain), and seed (controls which reference frames get sampled). Outputs are the grained image plus an info_json with the measured grain std and what you applied - handy for reproducing the exact look later.

The inputs and outputs that matter

  • reference (IMAGE) - the footage whose grain you want. Use a real shot, ideally a flat-ish region without too much fine detail, or the "grain" you extract will include texture.
  • target (IMAGE) - what gets the grain.
  • intensity - start at 1.0, drop to 0.3-0.5 if the result looks noisy.
  • image out - your grained target, ready for the comp.
  • info_json - grain_std and settings, so you can reproduce a match.

Installing it

Ships inside ComfyUI-CustomNodePacks. Manager → search "CustomNodePacks", or:

cd ComfyUI/custom_nodes
git clone https://github.com/Code2Collapse/ComfyUI-CustomNodePacks.git

The grain path itself needs only torch (its box denoiser is a conv2d). The pack still wants opencv-python>=4.7.0 and scipy>=1.10.0 for its other nodes - install what's missing rather than the whole requirements.txt (the README warns it can overwrite ComfyUI's torch). Restart ComfyUI.

Common issues

  • Grain looks like static, not film - reference is probably too detailed or you've set denoise_kernel too small, so texture leaks into the "grain". Raise the kernel a bit and use a clean reference region.
  • Target comes out too noisy - intensity 1.0 is full-strength plate grain; for AI output against modern footage, 0.4-0.7 is usually the sweet spot. Start low and nudge up.
  • Result looks flat in video - the node handles per-frame randomness, but if you want motion in the grain (which real grain has), that's beyond this node's scope; it's static-pattern-per-frame by design.

One honest note from the KB's decision tree: grain is the cheap deterministic fix for the "too clean" look - do it after you've finished color work, not before, or your grade will bury it.

CategoryMaskEditControl/PlateTools

Inputs (5)

NameTypeDefaultDescription
referenceIMAGE
targetIMAGE
intensityoptFLOAT1.000–4
denoise_kerneloptINT53–15
seedoptINT00–2147483647

Outputs (2)

NameTypeDescription
imageIMAGE
info_jsonSTRING