๐๏ธ Match Grain To Reference
Match a real clip's film grain instead of guessing at it
- images
- reference_image
- IMAGE
If you've ever added grain to a generated clip, you know the failure mode: a generic "grain" slider dumps the same noise on every shot, and it looks either spotless-clean or like a 1998 webcam. Match Grain To Reference is the fix for the specific case where you have a reference with grain you want to feel like yours - a real filmed plate you're cutting against, a stock clip, the previous scene in a music video. It measures the reference's grain texture and applies the same strength and colorfulness to your frames, without copying the reference's actual content.
It's part of VRGameDevGirl's pack (comfyui-vrgamedevgirl), the same collection that ships the AI Video Builder and the LTX/MiniMax enhancement workflows. The pack's post-processing folder has a whole family of these one-job finishing nodes - grain, color match, sharpen, LUT work. This one sits in the "make the AI read as captured footage" corner, which as any compositor will tell you is where realism is actually won. It's the cheapest anti-AI-look move there is.
How it works
The math is the interesting part and it's grounded, not hand-wavy. The node blurs the reference image with an averaging pool, subtracts the blur to isolate the high-frequency detail - that residual is what grain actually is - then measures its statistics per channel and as a monochrome signal.
Then it stops borrowing pixels entirely. It generates fresh Gaussian noise at your target resolution, scales it if you asked for coarse grain, and renormalizes that noise so its standard deviation matches the reference's measured grain. Your frames get target + strength * noise. Result: the texture of the reference's grain, not its content - which is why the description stresses it never copies the reference image itself.
chroma_amount is the knob that interpolates between two measurements: at 0 you get neutral monochrome grain (the classic film look), at 1.0 full per-channel color variation from the reference (real film stock has colored dye noise; digital sensors have their own color signature). 0.5 is a sane default for most footage.
Inputs that matter
You mostly touch four things:
reference_image- the frame or clip whose grain you're matching. Feed a single clean frame from the reference footage.strength(0โ2, default 1) - 0 disables the effect, 1 is the normal match, above 1 exaggerates. Rarely needed above 1.grain_size(1โ8, default 1) - 1 is fine film grain; larger values upsample the noise into softer, coarser chunks. Try 2โ3 when the output should match 35mm-ish texture rather than fine digital.chroma_amount, described above.
seed controls the pattern - fix it for repeatable output across runs, randomize per run if you don't want temporal banding to matter. batch_size (default 8) just chunks the work so you can keep VRAM in check on long videos.
Wiring it
Output is a single IMAGE, the same frames you fed in with grain added. It drops between your video source and your Save Video node, or before an encode step. The author's VRGDG_MatchGrainToRefrence.json workflow (in Workflows/post process/) wires it alongside the other post-process nodes, so if you're building a finishing pass, that's the reference layout.
Installing the pack
Grab the whole pack once - this node shares it with everything else:
cd ComfyUI/custom_nodes
git clone https://github.com/vrgamegirl19/comfyui-vrgamedevgirl.git
Or use ComfyUI Manager and search for the pack title ("VRGameDevGirl"). Restart ComfyUI and hard-refresh the browser page (Ctrl+Shift+R). One honest warning: the pack's requirements.txt is heavy - kornia, librosa, demucs, transformers, voxcpm, llama-cpp-python and friends - because it's a video-production suite, not just grain. The README's manual install path (install Cython scikit-build-core first, then -r requirements.txt) exists because voxcpm and llama-cpp-python need build tooling on Windows. If you only want this one node, you're still installing the whole dependency tree; that's the cost of a kitchen-sink pack. Python 3.12 is the safer bet on older Windows portable installs.
Common gotchas
- It's not a denoiser or a texture transfer. If the reference and your shot are wildly different resolutions, the statistics still match but the perceptual result can look off - match resolution first.
- Reference grain that's been compressed to mush (heavily compressed MP4) has almost no high-frequency residual, so the node will under-grain. Feed it a clean frame.
- Fix your seed if you're rendering a long clip in segments; otherwise each batch rolls its own grain pattern and you'll see the seams.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | โ | |
| reference_image | IMAGE | โ | |
| strength | FLOAT | 1.000โ2 | How strongly to apply the reference grain. 0 disables the effect; 1 is the normal match; higher values exaggerate it. |
| grain_size | INT | 11โ8 | Grain scale in pixels. 1 is fine film grain; larger values create softer, coarser grain. |
| chroma_amount | FLOAT | 0.500โ1 | Amount of colored grain. 0 uses neutral monochrome grain; 1 allows full per-channel color variation from the reference. |
| seed | INT | 486640900โ2147483647 | Random seed for the generated grain pattern. Randomize for a new pattern on each run, or fix it for repeatable output. |
| batch_size | INT | 81โ64 | Number of video frames processed at once. Lower values use less VRAM; higher values can be faster. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | โ |