VideoMilk78
20th September 2025, 02:20
I've been toying around with mRD_RestoreGrain for quite some time after finding it in this thread (https://forum.doom9.org/showthread.php?t=182831) however the issue was that after restoring grain there would be discoloration and artifacts around where the dirt had been. I came up with this script that expands the area around the spot slightly and puts the clean version where dirt was leaving the rest of the grain structure completely original.
/*
KeepGrain — a modification and improvement of mRD_RestoreGrain, developed by VideoMilk78.
Requirements:
Avisynth+ 3.7.4
masktools2.dll
OverlayPlus.avsi
ExpandMask (included)
mRD_RestoreGrain (included)
Usage:
KeepGrain(Clip "source",Clip "clean",Int "expand",int "blur")
Parameters:
Source, unfiltered film source
Clean, source cleaned with a dirt removal filter of choice
Expand, expands the restore mask
Blur, softens the edges of restore mask
*/
Function KeepGrain(Clip "source",Clip "clean",Int "expand",int "blur") { #https://forum.doom9.org/showthread.php?p=2022883#post2022883
Expand=default(expand,4)
Blur=default(Blur,expand/4)
Grain=clean.mRD_RestoreGrain(source,40,40)
mask=mt_lutxy(source, grain, expr="x y - abs 0 > 255 0 ?", u=1, v=1).ExpandMask(expand,blur)
OverlayPlus(source,clean,mask=mask,chroma=true)
}
Function mRD_RestoreGrain(clip rd, clip o, float "str1", float "str2") { #https://forum.doom9.org/showthread.php?p=1943371#post1943371
sisavs26 = !(VersionNumber() < 2.60)
str1 = string(default(str1, 10.0))
str2 = string(default(str2, 20.0))
expr = sisavs26 ? " x range_half - abs "+str1+" scalef min "+str2+" scalef x range_half - abs - min 0 max x range_half - x range_half - abs 1 max / * range_half + " : " x 128 - abs "+str1+" min "+str2+" x 128 - abs - min 0 max x 128 - x 128 - abs 1 max / * 128 + "
Return sisavs26 ? mt_makediff(o, rd).mt_lut(expr, use_expr=2).mt_adddiff(rd, chroma="copy second") : mt_makediff(o, rd).mt_lut(expr).mt_adddiff(rd, chroma="copy second")
}
function ExpandMask(clip mask, int amount, float "blur") {
blur = Default(blur, 0)
for (i = 1, amount) {
mask = mask.mt_expand(chroma="-128")
}
if (blur > 0) {
mask = mask.mt_inflate()
}
return mask
}
/*
KeepGrain — a modification and improvement of mRD_RestoreGrain, developed by VideoMilk78.
Requirements:
Avisynth+ 3.7.4
masktools2.dll
OverlayPlus.avsi
ExpandMask (included)
mRD_RestoreGrain (included)
Usage:
KeepGrain(Clip "source",Clip "clean",Int "expand",int "blur")
Parameters:
Source, unfiltered film source
Clean, source cleaned with a dirt removal filter of choice
Expand, expands the restore mask
Blur, softens the edges of restore mask
*/
Function KeepGrain(Clip "source",Clip "clean",Int "expand",int "blur") { #https://forum.doom9.org/showthread.php?p=2022883#post2022883
Expand=default(expand,4)
Blur=default(Blur,expand/4)
Grain=clean.mRD_RestoreGrain(source,40,40)
mask=mt_lutxy(source, grain, expr="x y - abs 0 > 255 0 ?", u=1, v=1).ExpandMask(expand,blur)
OverlayPlus(source,clean,mask=mask,chroma=true)
}
Function mRD_RestoreGrain(clip rd, clip o, float "str1", float "str2") { #https://forum.doom9.org/showthread.php?p=1943371#post1943371
sisavs26 = !(VersionNumber() < 2.60)
str1 = string(default(str1, 10.0))
str2 = string(default(str2, 20.0))
expr = sisavs26 ? " x range_half - abs "+str1+" scalef min "+str2+" scalef x range_half - abs - min 0 max x range_half - x range_half - abs 1 max / * range_half + " : " x 128 - abs "+str1+" min "+str2+" x 128 - abs - min 0 max x 128 - x 128 - abs 1 max / * 128 + "
Return sisavs26 ? mt_makediff(o, rd).mt_lut(expr, use_expr=2).mt_adddiff(rd, chroma="copy second") : mt_makediff(o, rd).mt_lut(expr).mt_adddiff(rd, chroma="copy second")
}
function ExpandMask(clip mask, int amount, float "blur") {
blur = Default(blur, 0)
for (i = 1, amount) {
mask = mask.mt_expand(chroma="-128")
}
if (blur > 0) {
mask = mask.mt_inflate()
}
return mask
}