Simple MDegrain Mod — SMDegrain()

 

Abstract

Author: Dogway
Version: v4.6.0d
Download: https://github.com/Dogway/Avisynth-Scripts/SMDegrain
Discussion: https://forum.doom9.org/showthread.php?t=182881
Category: Temporal Denoiser
Date: 30-March-2024

 

Table of contents

 

Dependencies     

Required
Optional

 

Aknowledgements     

Original SMDegrain() by Caroliano

This function uses code from Didée, and cretindesalpes' creations, and has parts inspired by LaTo's functions (Show panel, etc) and Jawed's Killer() function, as well as relying on third-party tools for certain features.

Special thanks go to: cretindesalpes, Didée, Gavino, Sagekilla, and MVtools developers.

 

Introduction     

SMDegrain is a simple wrapper for MVTools and client functions for general purpose temporal denoising. Unlike other MVTools based denoising filters, here and specially at default values the output will be source agnostic and similar to a plain MVTools code block.
The changes are mainly for useability and convenience, so you can think of it like an interface for MVTools or an extension of it so to speak. For example it will work out of the box with YUY2, interlaced inputs, HBD clips or a combination of them.
Internally default values have been optimized with pareto statistics via Zopti, so except for tr (radius) and thSAD there isn't a need to tweak much further.
What SMDegrain brings though is an interface to apply prefilters, either via the internal presets or external custom ones, motion filters, different degrain modes, lowpassing to recover smearing, etc. Following a list of the main features:

Frame properties support: Reads frame properties for details on luma/chroma range, bitdepth, source matrix or interlacing.
High bitdepth denoising: Supports AviSynth+ native HBD formats, from 8-bit up to 16-bit.
Contrasharpening: The pretty much standarized sharpening method created by Didée is blended into the function, so you can easily use it in HBD pipelines. An strength biased method is also possible via an internal LSFplus call. A CClip parameter is also supplied so you can choose another source to sharpen from, other than the default SMDegrain() input.
Interlaced support: It supports interlaced sources, for YUY2 color spaces and most parameters as well.
UHD optimized: UHD denoising can be optimized via motion vector scaling providing much higher performance. Enabled by default with UHDhalf argument.
Extended Subpixel Accuracy: nnedi3 is added as the 4th option for subpixel. Not strictly necessary in most cases.
Better Motion Vectors: An internal conversion from TV levels (16-235) to PC levels (0-255) and a dark zone luma expansion is done to the clip where the motion analysis will be performed on, so you can get much better motion vectors
Prefilters: An easy parameter to load predefined prefilters that perform well in most situations. It also accepts loading your personal prefiltered clips.
Degrain modes: As a bonus you can try other temporal denoisers (mainly from the ex_median() function) with mode so you can test temporal medians from a simple medianT to a ML3Dex algorithm in a motion compensated fashion.
Smear protection: Smearing of low contrast shading is a known side-effect of MDegrain, as a solution the LFR argument was added to recover low frequency details along DCTFlicker to temporally calm down the recovered frequencies.
Motion Filters: It will allow you to filter those parts where SMDegrain() couldn't find a matching block, or in other words motion areas where SMDegrain() couldn't denoise. One use for it would be spatial denoisers or deblockers since motion areas are prone to heavy blocking and artifacts.
Motion Vectors Globals Input/Output: Reuse motion vectors globals for faster processing, or just use SMDegrain() as a shortcut for creating nice quality motion vectors.
RefineMotion Option (MRecalculate): Performs finer block matching refinement, unless you are very performance deprived you should use this as default for a quality boost.
Show Panel: Everything is off by default, but a few settings change in context (i.e. when in HD). Check what is happening behind the scenes and have a fast look at all your settings.
Robust: Everything listed above works together with each other indistinctly with interoperability, reliability and optimization in mind. The general idea is to serve as an user friendly front end for vanilla mvtools2+mdegrain or as the original script creator entitled "To make your scripts shorter and less geeky". Most parameters are turned off or defaulted to MVTools2 defaults or close. Features are based on popular general conceived good practices and time tried-and-tested procedures.

Parameters are arranged in 2 blocks.

Basic: For people who just need the most basic parameters because either they don't have the time, knowledge or interest into looking for complex settings. Or they are content with defaults (pretty much mvtools defaults)
Advanced: If you run into some problems, are nitpicking or just want to fine tune your settings according to the source, have a look at this block, it contains the rest and bulk of the function parameters.

To picture what the function does, a simple SMDegrain() call matches the next code (for SD resolutions):

super_search = ex_Luma_Rebuild(S0=5.0,c=0.0312, bits=8).MSuper(rfilter=3,sharp=2)

bv2 = super_search.MAnalyse(isb = true,  delta = 2, overlap = 4, search = 2)
bv1 = super_search.MAnalyse(isb = true,  delta = 1, overlap = 4, search = 2)
fv1 = super_search.MAnalyse(isb = false, delta = 1, overlap = 4, search = 2)
fv2 = super_search.MAnalyse(isb = false, delta = 2, overlap = 4, search = 2)

MDegrain2(MSuper(levels=1), bv1, fv1, bv2, fv2, thSAD=300, thSADC=57, thSCD1=365, thSCD2=130)

As you see nothing drastic. The only changes made are the TV->PC luma expansion (ex_Luma_Rebuild() call) so you have more range to detect motion vectors, and some Zopti optimized values; rfilter to 3 for a bit more quality super search, the changed default of overlap from 0 to 4, search from 0 to 2 which has a higher performance/quality ratio, and thSAD and thSADC from 400 to 300 and 57 respectively for safer results.

This setup optimized internally along with RefineMotion might be all you need for most sources, but eventually you might encounter very grainy clips or simply noise and/or blocking. For these cases you can make use of the internal prefilter presets, but if those don't help even more creative approaches are required (see prefilter notes). The basis for good temporal denoising with SMDegrain is a good, source centric prefiltering, which in itself is a form of art.

 

Parameters     


SMDegrain (clip input, int "tr", int "thSAD", int "thSADC", bool "RefineMotion", val "contrasharp", clip "CClip", string "mode", bool "interlaced", int "plane", int "Globals", bool "tv_range",                     \
                                 int "pel", int "subpixel", val "prefilter", clip "mfilter", int "blksize", int "overlap", int "limit", float "limitC", bool "limitS", val "LFR", bool "DCTFlicker", int "thSCD1", int "thSCD2",   \
                                 bool "luma", bool "chroma", int "hpad", int "vpad", val "Show", float "Str", float "Amp", int "DCT", int "searchparam", int "pelsearch", int "search", bool "truemotion", int "gpuid", int "rfilter", bool "UHDhalf")




Basic     


tr

[int: 1, "2", 3, 4, 5, 6, ...]

Temporal radius. Select between MDegrain 1, 2, 3, 4, 5, 6 or higher. The higher generally the better, but also much slower and improvements get less drastic (diminished returns) to circumvent smearing or ghosting.
Also with larger 'tr' all the truemotion and vector penalty settings lose their meaning and turn basically to no-op.
This can be considered the strength of the denoising. Supports up to tr=128, 64 for interlaced.

thSAD, thSADC

[int:"300"], [int:"226"] (for HD)

"Sum of Absolute Differences" threshold. This is the spatial difference threshold where the motion search will consider whether to denoise given the next formula: Denoise_Weight = max( 0, 1 - 2*blockSAD² / (thSAD² + blockSAD²) )
This spatial difference will be compared in blocks (blksize). If your noise is not getting into consideration for the denoising try raising this value, or reduce its SAD with previous prefiltering.
You can alternatively raise the block size (blksize), which will likely even blocks SAD. Low values can result in staggered/blotchy denoising, large values can result in ghosting and artifacts. Values in the range 200~600 are usual.
thSADC is the same logic applied to chroma planes, since there are less differences on the chroma planes it uses by default ~thSAD/5 for safer chroma results (internally uses a function fit).

Contrasharp

[bool: true, "false"] or [int: 0 ~ 100 ]

Contrasharpening is a technique that compares the differences between the clip before blurring (original) and after blurring (filtered), and compensates (sharpens) locally with consequent strength.
By default the before "sharp" clip is the one used as input for SMDegrain(), the "after" clip is the denoised clip. Independently a "before" clip can be specified with the CClip parameter (See below)

Contrasharp when set to "true", will use ex_ContraSharpening() (an ExTools mod to Didée's Contrasharpening()) which:
"Sharpens the denoised clip, but doesn't add more to any pixel than what was removed previously"
In the practice you will get a slightly sharper result than the source, which is welcome.
In the other hand if your parameter input is an integer, LSFplus() (an optimized LSFmod mod) will be used instead. It will be slower, but maybe better for certain sources.
Its value will serve as a contrasharpening multiplier, use one around 50 for similar strength as ex_ContraSharpening().

RefineMotion

[bool: true, "false"]

Refines and recalculates motion data of previously estimated (by MAnalyse) motion vectors.
Turn it on for better motion vectors, specially when dealing with ghosting issues, small details or lineart fading and whatnot.
  *Beware: It won't enhance much if you use a prefilter (in case you use it) so strong that blurs too much or kills all the details you are aiming to "refine" in first place.

Interlaced

[bool: true, "false"]

By default not needed since it will be read from frame properties, but if you are getting issues or just want to play it safe set this parameter to true. Output will also be interlaced.
Note that must feed directly interlaced clips into CClip, prefilter, or mfilter, without the need to separate fields. Check examples on the bottom section.
Given the packing sub-format for interlaced clips, the minimum 'tr' allowed is of 2 even if tr=1 is set, and jumps in 2 so for tr=3 -> 4, tr=4 -> 4, and so on.

plane

[int: 0, 1, 2, 3, "4"]

Select the planes you wish to process:
  *Keep in mind that plane=4 (2 and 3 as well) can sometimes create chroma smearing. In such case I recommend denoising chroma planes separately in the spatial domain.

prefilter

[int: "-1", 0, 1, 2, 3, 4, 5, 6, 7, 8] or [clip: - ] or [string: "", "SBR", "MinBlur", "MinBlur2", "MinBlur3", "IQMST", "DFTTest", "KNLMeans", "DGDenoise", "BM3D"]

See below for a review of prefilter presets.



Advanced     


mode

[string: "MDegrain", MedianT, MedianST, MedianSTS, TemporalSoften, TemporalSmooth, TemporalGauss, FluxSmoothT, DFTTest, ML3DEx, Hybrid, TL3D, STWM, IQMT, GaussST5]

Defines the filter for the temporal degrain. Normally should be left at default MDegrain which works best, but using other modes can provide Motion Compensation filtering
to filters that aren't motion protected like ML3DEx, IQMT, etc. probably for prefiltering or other uses. Most of these modes are explained in ExTools ex_median() entry (link).
If you append 'r' to the mode string (ie. rMedianT) it tells the filter to run twice for recursion, as a cheap way of Degrain Refinement.
TemporalSoften and TemporalSmooth are not supported in recursion mode to prevent ghosting, caution with TemporalGauss as well.

pel

[int: "1", 2, 4]

Accuracy of the motion estimation.

subpixel

[int: 0, 1, 2, "3", 4]

Subpixel accuracy. It chooses an interpolation method for pel=2 or 4. This is the 'sharp' parameter in msuper() extended with modes 3 and 4.
Unrelated to output sharpness but accuracy for the motion estimation.
For subpixel=4 you will need nnedi3 (gpuid=-1) or NNEDI3CL (gpuid=0) plugin. Very useful when used along pel=4 on very small sources, although overkill and unnecesary in most cases.

rfilter

[int: 0, 1, 2, "3"]
Hierarchical levels smoothing and reducing (halving) filter.
Set and forget setting. Mode 3 gives the most accuracy for downscaling.

prefilter

[int: "-1", 0, 1, 2, 3, 4, 5, 6, 7, 8] or [clip: - ] or [string: "", "SBR", "MinBlur", "MinBlur2", "MinBlur3", "IQMST", "DFTTest", "KNLMeans", "DGDenoise", "BM3D"]


Despite being one of the most advanced filters for AviSynth, MVTools is lacking important motion predictors like rotate/scale-zoom/skew...
Currently only translation transforms are being predicted and therefore we need to help MAnalyse client function as much as possible to create accurate motion vectors.

For this reason precisely one of the most important aspects for a satisfactory denoising in SMDegrain is to provide clean reference frames for MAnalyse,
specially when the source is grainy, technically speaking by lowering the SAD (Sum of Absolute Differences) where it matters most.

If you didn't realize already, most of the settings in MVTools and SMDegrain revolve around conditioning this prefiltered clip.
From pel, going through subpixel, to luma expansion (Str and Amp) and obviously prefilters.

In general terms spatial prefiltering is enough (presets from 0 to 3 and 5 and 7) while very grainy sources might require spatio-temporal filters (presets 4, 6 and 8).
The goal here is not to provide a fully perfectly denoised clip but a slightly soft or out-of-focus version of an ideal clean clip, that is, soft edges (but not blurry) and clean flat areas.
For example cartoons may display many flat areas that work great with median filters (1 to 3) or even non-local means (6 and 7). While live action, depending on
the nature of the grain, can use the spatial prefilters which are faster or BM3D (preset 8). Custom external prefilters will also be explained below.

To put denoising filters in comparison back to back, we can broadly order them in the following sequence of quality:
BM3D (Block Matching 3D) > NLMeans > SAD Block Matching (MVTools) > Frequency Filters (FFT/DFT..) > Bilateral > Median > simple linear filters (Gaussian Filter, Wiener Filter...)


Another useful way to think about prefilters for example when building custom prefiltered clips is to treat the clip as if you were filtering as usual without SMDegrain, that is,
using Deblockers if blocking is present, Decrawlers, cleaning Gibbs noise, some spatial denoiser, etc. Then this clip is only fed to prefilter while the original is used as input for SMDegrain.
By doing this all those issues will be cleaned temporally more effectively while retaining more details. Now, yes, areas where block matching failed (motion areas) will passthrough
the original clip with all its artifacts, so the trick is to feed the same clip to mfilter, so motion areas will apply the prefilter clip spatially while stable areas will only treat them temporally.
pre=my_custom_prefiltering().ex_sbr() # sbr to soften edges
SMDegrain(last,prefilter=pre,mfilter=pre)


Now you might think, if SMDegrain is so good, why not use it also for prefiltering?
Good question, and yes, that's actually one of the recommendations for fizz grain or simply very grainy sources (films like "300", "21 grams", etc).
Just keep in mind that running MVTools2 twice in the same script may lower performance greatly, but using a low radius (tr) can help towards that.

For example, we have a very grainy 1080p source so we are going to apply quite extreme settings.
pre=SMDegrain(tr=1,mode="TemporalSoften",blksize=32,prefilter=8  ,thSAD=700,LFR=400,DCTFlicker=false,contrasharp=false,refinemotion=true)
    SMDegrain(tr=2,mode="MDegrain"      ,blksize=32,prefilter=pre,thSAD=400,LFR=200,DCTFlicker=true ,contrasharp=true ,refinemotion=true)

TemporalSoften and TemporalGauss are two degraining modes that switch a few internal settings to make it more temporally stable. It's quite an extreme approach
also with blksize=32 and thSAD=700, therefore we should recover some low frequency smearing with LFR=400 and LFR=200, DCTFlicker=true in the second call.
Following we feed this prefilter clip to the next SMDegrain call with saner settings of 'MDegrain' and thSAD=400.
*For these two degraining modes you might want to manually tweak the thSCD1 value, specially in the thSAD 400 to 800 range.
Higher than that it's automatically parametrized to give the lowest thSCD1 value (prevents filtering across scene changes) with reasonable filtering.


The above is for mild to strong sources, for very strong ones like "21 grams" I found myself using a double call:
SMDegrain(tr=3,mode="TemporalSoften",blksize=32,thSAD=1200,LFR=300,DCTFlicker=true,contrasharp=false,refinemotion=true)
SMDegrain(tr=1,mode="MDegrain"      ,blksize=32,thSAD=300 ,LFR=false              ,contrasharp=true ,refinemotion=true)

Another option:
SMDegrain(tr=3,mode="TemporalGauss" ,blksize=32,thSAD=1300,LFR=300  ,contrasharp=false,refinemotion=true)
SMDegrain(tr=2,mode="TemporalSoften",blksize=32,thSAD= 600,LFR=false,contrasharp=true ,refinemotion=true)

Another one this time with prefilter:
pre=ex_bm3d(60,3,preset="noisy")
SMDegrain(tr=2,mode="TemporalSoften",blksize=32,thSAD=600,prefilter=pre,refinemotion=true)
ex_unsharp(0.2,Fc=width()/2) # Remove the dreamy/softness look

And another one with prefilter (the possibilities are endless so choose your poison):
SMDegrain(tr=3,mode="TemporalSoften",thSAD=600,LFR=300,DCTFlicker=true,prefilter="IQMST",refinemotion=true)

The double call method is called Degrain refinement, while the ones using prefilter are called Motion Vector refinement, and both are considered
pyramidal refinements as you lower the strength of the prefilter/denoising the lower the stack. You can also mix both methods and experiment.
Double calls are effective in the sense that it naturally applies a binomial weighting to the pixels, the furthest frames having less weight,
just like two stacked mean/box blurs approximate a binomial blur in the spatial domain.

Needless to say you can get prefiltering as complex as you wish, by using masking and other filters like ex_retinex(), ex_autolevels(), etc.
Creating these discerning masks and prefiltering chains is a research task on the end user side.
Might sound obvious but note that when feeding a clip to prefilter the clip format (dimensions, pixel type, etc) should match SMDegrain() input format.


Some (very) old examples of custom prefiltering, for history:

This last example is a function called Calm(), wrapped by Terka but it's basically QTGMC's default prefiltering from line 467 to 499 using TR0=2 and SrchClipPP=3.
It's basically a TemporalGauss, with some limiting and a gaussian blur. What he missed was adding KeepOnlyBobShimmerFixes() which removes "most" TemporalSoften frame blending artifacts.
My improved alternative was already given above, but adding ex_sbr() instead of a gaussian blur:
pre=SMDegrain(2,thSAD=1600,mode="TemporalGauss",pel=1,rfilter=0,str=0,tv_range=false,plane=0,truemotion=true) # Tuned for speed or "dumb" MV
pre=pre.ex_sbr(3,UV=3)
*You can read more about this and a stronger alternative more similar to Calm() for (film) de-wobble purposes on this post and following pages.

Notes: To sum it up; generally in denoising, temporal filters are always preferred due to its natural look (versus spatial filters).
But more often than not for good results prefiltering plays a key role on the output quality, and setting it up nicely can be looked as an art by itself.

mfilter

[clip: - ]

As with prefilter, in mfilter (Motion Filter) you can add a clip variable. This clip will be passed through those areas where SMDegrain() couldn't find a matching block, normally high motion areas.
One use for it would be to use spatial filters, like deblockers or blurring filters that mimic motion blur.
Clip should match input format.

Str

[float: 0.0 ~ 8.0] Default: 5.0

Based on the original function by cretindesalpes', with this parameter you control the strength of the brightening of the prefilter clip.
Unless you are filtering sports or TV shows aimed at daytime you most likely want this turned on at default value.
MVTools2 has issues on low frequency areas like shadows and shade details where the human eye excels at, so enhancing
the dynamic range of this area makes it easier for MAnalyse to create better motion vectors and avoid smearing.
This luma expansion is performed in the same stage as the TV->PC range conversion thus more memory friendly and less quantization artifacts.
From 0.0 to 1.0 (1.0 being no-op) uses ex_retinex(), the value will serve as the normalization factor (ie. 0.40 to normalize black to pixel value of 40 -in 8-bit scale-).
Use show to review the brightening curve for >1.0 values.

Amp

[float: 0.0 ~ 1.0] Default: 0.0312

Use this together with Str. This defines the amplitude of the brightening in the luma range, for example by using 1.0 all the
luma range will be used and the brightening will find its peak at luma value 128 in the original. Default is 0.0625 (1.0/16) which just sits over luma value 16 (256/16)

LFR

[bool: true, "false"] or [int: 50 ~ Resolution]

Cutoff frequency for Low Frequency Restore -LFR-. 'true' enables a lowpass equal to 300 for a 1080p clip.
Useful in the presence of smearing when using too extreme settings (high tr, thSAD, prefiltering, etc).
The value represents a cutoff in resolution units of the maximum dimension, so for example 300 would lowpass all details above 1920/300 = 6.4 pixels wide.

DCTFlicker

[bool: true, "false"]

Only works when LFR is activated. It tries to stabilize low frequency flicker produced by grain propagated to low frequencies by the DCT compression algorithm.
When enabled it will only pass low frequencies to motion areas and filtered through a custom temporal denoiser to calm the flicker. Only enable this when your source is very grainy.

blksize

[int: 4, 8, "16", 32, 48, 64]

Size of a block (horizontal). (Default 16 for HD material)
Larger blocks are less sensitive to noise, are faster, but also less accurate.

overlap

[int: "blksize/2"]

Must be *even* and *less* than block size. Common overlap values: blksize/4 or blksize/2.
The greater overlap, the more block count, and the lesser more processing speed.

Search

[int: 0, 1, "2", 3, 4, 5, 6, 7]

By default 2, but switched to 4 when RefineMotion is enabled.
See details at MVTools2 documentation.

DCT, searchparam, pelsearch

[-]

See details at MVTools2 documentation.

Truemotion

[bool: true, "false"] * "true" for SD

Truemotion is a preset of some parameters values. It allows easy to switch default values of all "true motion" parameters at once.
Set it 'true' for true motion search (high vector coherence), set it 'false' to search motion vectors with best SAD.
Default is 'true' (as in MVtools2 default, and contrary to MCTemporalDenoise()). By turning it off it could protect better low frequency
details (shading) when in motion (i.e. walls, grounds, clouds texture, motion blur, etc), and also protect from tiny details loss but it could leave more noise unfiltered.

Default is 'true' for SD for smoother/cleaner (more temporal coherence) high frequency details or lineart. For HD sources where the main problems are just excessive grain,
I have defaulted it to false, this is not only faster but honors detail accuracy (the main existing point for HD sources) and overall object shading.

Chroma

[bool: "true", false]

Takes chroma planes into consideration for calculating the motion vectors.
Turn it off for more speed with little cost in quality, or when your chroma is not reliable enough for motion estimation.
  *Whatch out if you turn this off when processing chroma planes (aka luma vectors when chroma denoising), it has shown problems in previous tests.

Luma

[bool: "true", false]

Takes luma plane into consideration for calculating the motion vectors.
For example if you were to denoise only Chroma planes (plane=1, 2 or 3), you might or might not want to use vectors from the Luma plane.
Actually MVTools2 doesn't have an option for this, so what this does is concerned to prefilters and finally a luma weighting that is half of the chroma on the MVTools2 side.

Hpad, Vpad

[int: "blksize"]

It is horizontal/vertical padding added internally to source frame (both left and right, and top and bottom).
Small padding is added for more correct motion estimation near frame borders.
Try to have clean borders in your source (no NAB*/black borders) to start with before tweaking this setting.
If necessary, crop beforehand ideally in multiples of 16. Turn it to 0 if you are running out of resources in your system.
*Nominal Analog Blanking

thSCD1

[int: "365"]

Threshold which decides whether a block has changed between the previous frame and the current one. So it is one of the thresholds used to tweak the scene changes detection engine.
Raising it will lower the number of blocks detected as changed. It may be useful for noisy or flickered video. To fix blending on scene changes on dark scenes, try first the Str and Amp parameters.

thSCD2

[int: 0~"130"~255]

Threshold which sets how many blocks have to change for the frame to be considered as a scene change.

limit,limitC

[int: 1 ~ "255"]

Maximal change of pixel luma/chroma (post-process like DeGrainMedian plugin
and LimitChange function of SSETools plugin, to prevent some artifacts)

limitS

[bool: "true", false]

Limit type for the contrasharpening: True: Spatial, False: Temporal (ignores CClip).
False (temporal) might give a more natural look albeit softer, so you might want to raise the contrasharpening a bit.

CClip

[clip: - ]

Define here a variable name referencing an earlier stage of your processing chain as the sharp version for the contrasharpening to compare against.
If contrasharp is not declared, by default it will use the ex_ContraSharpening() function, add contrasharp='an integer' to force LSFplus() instead.
Clip should match input format.

gpuid

[int: -1, "0", 1... ]

Enables GPU processing for the filters that support them. -1 is CPU mode, 0 is default GPU and >0 is device ID if you have more than one GPU.
-1 (CPU mode) is only for NNEDI3 (for subpixel=4) and BM3D (prefilter=8) as prefilter with KNLMeansCL is currently GPU only.

UHDhalf

[bool: "true", false]

For performance reasons computes motion vectors from a halved version of an UHD clip. Then the motion vectors are upscaled back to UHD resolution for denoising.
Keep aware that quality while good won't be on par with plain UHD denoising (UHDHalf=false), specially on low SAD areas where some slight blurring
or detail warping can happen. For this reason you might want to limit denoising to a value of 2 or 1 to minimize the effect (test with limit=2).

Globals

[int: "0", 1, 2, 3 ]

With this parameter you can, among other things, load pre-processed motion vectors (Globals=1), so you save doing this step again.

The integers define what to do with the global variables. Default is 0.


Some parameters MUST MATCH those from the processed vectors stage (e.g. Globals=2 or 3) and the read vectors stage (e.g. Globals=1). pel=, subpixel=, chroma= and vpad/hpad.
Other than that the only settings that work when reading (Globals=1) are: tr=, thSAD=, plane, limit, limitc, contrasharp, CClip and the interlaced parameters. Others are ignored.
Global names that can be reused are: srchSuper, bVec1, fVec1, bVec2, fVec2, bVec3, fVec3, bVec4, fVec4, bVec5, fVec5, bVec6, fVec6, vmulti.

e.g.:
                         SMDegrain(tr=3,thSAD=400,globals=3)    # Outputs vectors

                         SMDegrain(tr=2,thSAD=200,globals=1)    # You can use a same or lower "tr" or "thSAD" if you want
or

                         SMDegrain(tr=3,thSAD=400,globals=3)    # Outputs vectors

                         Super = MSuper(levels=1)               # Add this line just before if you have some processing between Globals Output and Input.
                         MDegrain3(Super, bVec1, fVec1, bVec2, fVec2, bVec3, fVec3, thSAD=400)

Show

[bool: true, "false" ] or [string: "Speed", "Memory", "Quality" ]

This will show the brightening curve graph over the prefiltered clip to be used for the motion search to the left(<--), and the used parameters list to the right (-->)

If you set Show to a string as indicated above, related parameters will be highlighted to guide you on correctly tweaking the function.
This is loosely based, so it doesn't exclude you from reading carefully every parameter explanation.

Even when you are not using any prefiltering, the clip to be used for the motion search where you obtain the motion vectors,
will be converted from TV levels to PC levels, the only exception being when using Globals=1 (Read) in which case the "prefiltered" clip
will be exactly the same as input clip (that is no luma conversion, although constrained to 8 bit). Additionally you can tweak the dark expansion with
Str and Amp parameters and check the effects in the left panel, but be aware to change your viewing conditions as it is in PC levels.

If you are not processing chroma for motion analysis (chroma=false) the prefiltered clip will be green, don't panic, this is correct, this happens when the
U and V planes are set to a value of 0 which is a dummy value meaning nothing or "discard". In this regard for previewing tasks simply set chroma to true temporarily.

 

Example Scripts     


A basic yet very functional call for light grain.
SMDegrain(tr=1,thSAD=300,contrasharp=true)

A personal preference. Turned all chroma off for safeness (on SD, chroma is rarely temporal-reliable enough) and speed.
SMDegrain(tr=2,thSAD=300,contrasharp=true,refinemotion=true,chroma=false,plane=0)

This is a good example to show that interlaced YUY2 sources can be processed seamlessly.
# Interlaced YUY2 source
SMDegrain(tr=1,thSAD=250,interlaced=true,contrasharp=true)

Denoising interlaced with a custom prefilter.
pre=SMD_UnfoldFieldsVertical().STTWM().SMD_FoldFieldsVertical() # Tailored SeparateFields then Interleaving back
SMDegrain(tr=1,thSAD=250,interlaced=true,prefilter=pre,contrasharp=true)

HD sources are detected automatically, and as so settings are optimized for speed; pel=1, blksize=16, overlap=8, truemotion=false
# HD source (from 1100px wide or 600px high up)
SMDegrain(tr=2,thSAD=180,prefilter=2,contrasharp=30,refinemotion=true,chroma=false,plane=0)

Tackling a grainy source pragmatically.
SMDegrain(tr=3,thSAD=500,contrasharp=40,prefilter=8,refinemotion=true)

How to reference a prior state of the script for the contrasharpening process.
sharp_ref=last
Deblock_QED(quant1=30, quant2=40)

SMDegrain(tr=3,thSAD=300,CClip=sharp_ref)

Leverage prefilter and mfilter for a spatio-temporal deblock on an mpeg file.
Also set contrasharpening to temporal limited (limitS)
pre=Deblock_QED(quant1=30, quant2=40)
SMDegrain(2, 200, prefilter=pre, mfilter=pre, refinemotion=true, contrasharp=60, limitS=false, chroma=false)

How to degrain an PQ encoded HDR clip. Note that prefilter clips also pass through ex_Luma_Rebuild() internally.
pre=DGHDRtoSDR(YUV420P16_Lim, mode="pq", gamma=1/2.4, tm=1.0, white=1500) # Check different white levels (60, 100, 203 or default 400) depending on source metadata
SMDegrain(tr=3,thSAD=300,prefilter=pre,UHDHalf=true)                      # 'UHDHalf' enabled (Default) for a performance boost

(Re)using motion vectors globals.
SMDegrain(tr=1,thSAD=400,prefilter=3,str=1.4,globals=3) # Output vectors only
MFlowFps(Super, bVec1, fVec1, num=60,den=1)

 

Final Notes     

If there is an important parameter not implemented,
you have any issue or found a bug, please don't hesitate
and ask in the main Doom9 thread:

(https://forum.doom9.org/showthread.php?t=182881)

What to expect for the future?
As DLSS3 enabled RTX GPUs lower the prices and AMD plays the catch up game
we might see more GPU based motion estimation APIs that open up advanced options
for very high quality motion vectors at reasonable or even good speeds.
Machine learning is also getting its way into AviSynth+ thanks
to the work of Asd-g and other active members, so the future is bright.

 

Changelog     

v4.6.0d (30-03-2024)

v4.5.0d (12-07-2023)

v4.4.0d (16-05-2023)

v4.3.0d (01-04-2023)

v4.2.0d (27-03-2023)

v4.1.0d (09-03-2023)

v4.0.0d (02-03-2023)

v3.6.0d (06-02-2023)

v3.5.9d (18-01-2023)

v3.5.8d (16-01-2023)

v3.5.7d (02-12-2022)

v3.5.6d (30-11-2022)

v3.5.5d (20-09-2022)

v3.5.4d (02-08-2022)

v3.5.3d (08-07-2022)

v3.5.2d (28-06-2022)

v3.5.1d (01-06-2022)

v3.5.0d (17-04-2022)

v3.4.9d (01-04-2022)

v3.4.8d (09-03-2022)

v3.4.7d (15-02-2022)

v3.4.6d (08-02-2022)

v3.4.5d (08-02-2022)

v3.4.4d (28-01-2022)

v3.4.3d (23-01-2022)

v3.4.2d (10-01-2022)

v3.4.1d (08-01-2022)

v3.4.0d (14-12-2021)

v3.3.9d (03-12-2021)

v3.3.8d (14-11-2021)

v3.3.7d (13-11-2021)

v3.3.6d (12-11-2021)

v3.3.5d (05-11-2021)

v3.3.4d (10-10-2021)

v3.3.3d (08-10-2021)

v3.3.2d (23-09-2021)

v3.3.1d (22-09-2021)

v3.3.0d (15-09-2021)

v3.2.9d (09-09-2021)

v3.2.8d (07-09-2021)

v3.2.7d (01-09-2021)

v3.2.6d (27-08-2021)

v3.2.5d (25-08-2021)

v3.2.4d (12-08-2021)

v3.2.3d (04-08-2021)

v3.2.2d (22-06-2021)

v3.2.1d (18-06-2021)

v3.2.0d (11-06-2021)

v3.1.2d (21-07-2015)

v3.1.1d (16-07-2015)

v3.1d (14-07-2015)

v3.0d (27-03-2015)

v2.2d (05-03-2013)

v2.1d (09-09-2012)

v2.0d (07-06-2012)

v1.9d (23-03-2012)

v1.8d (18-01-2012)

v1.7d (11-01-2012)

v1.6d (24-12-2011) (first open release)

v1.5d (14-10-2011)

v1.4d (16-09-2011)

v1.3d (14-09-2011)

v1.2d (13-09-2011)

v1.1d (12-09-2011)

v1.0d (09-09-2011)

v0.9d (09-09-2011)

v0.8d (05-09-2011)

v0.7d (05-09-2011)

v0.6d (04-09-2011)

v0.5d (19-07-2011)

v0.4d (03-06-2011)

v0.3d (04-03-2011)

v0.2 (24-01-2010)

v0.1