Skip to content

AdaptiveGrainMask

dnjulek edited this page Jul 7, 2026 · 1 revision

A port of kageru's Rust adaptivegrain plugin (adg.Mask).

Builds a grain mask from the luma plane: dark pixels get a high mask value and bright pixels a low one, so downstream grainers can add more grain to shadows and less to highlights. The strength of the falloff is shaped both by luma_scaling and by the frame's own average luma — brighter frames are masked more aggressively.

Unlike the Rust original, which reads the PlaneStatsAverage frame prop, this plugin computes the plane average internally (identical to std.PlaneStats), so no PlaneStats call is required beforehand.

Usage

vszip.AdaptiveGrainMask(vnode clip[, float luma_scaling=10.0])

Parameters

  • clip:
    Clip to process. 8-16 bit integer or 32-bit float, any planar/gray color family. Half precision float (GRAYH) is not supported. Only plane 0 (luma) is read; the output is a single-plane Gray clip with the same bit depth and sample type as the input.

  • luma_scaling: (Default: 10.0)
    Shapes the falloff curve. Larger values push the mask toward zero more quickly as luma rises (less grain overall); smaller values keep more of the frame masked. Negative values invert the emphasis (mask grows with luma).

Notes

  • Integer output is bit-exact with the Rust adg.Mask plugin; float output matches within ~1 ULP of the vectorized pow (~1e-7).
  • Integer formats use a 256-entry LUT indexed by src >> (bits − 8). For depths above 8 bit this is lossy by design — it faithfully reproduces the Rust reference, which does the same.

Example

# more grain in the shadows, less in the highlights
mask = core.vszip.AdaptiveGrainMask(src, luma_scaling=10.0)
grained = core.std.MaskedMerge(src, src.noise.Add(...), mask)

Clone this wiki locally