I have spent some time tweaking the FixRipsP2 script (based on Didée's script initially ) and i believe i've nailed it. It now remove effectively grains/noise and keeps lots of details without weird artifacts (like warping).
I have tweaked: the motion vectors parameters to my liking (probably the hardest part), removed Tmedian2 (which cause warping) replaced with a tweaked version of Spotless.
This script is very useful for vhs with: grains, noise, dropouts
Feel free to try it with your video and report how good (or bad) it is for further tweaks.
#### TWEAKED VERSION OF FIXRIPSP2 , BY THEMASTER1, June 2022
# TO REMOVE GRAINS, DROPOUTS (Only light ones, not multi frames ones)
# http://www.digitalfaq.com/forum/video-restore/12806-fixrips-grainnoisedropouts-script.html
# The original script comes from Didée, see more here: http://forum.doom9.org/showpost.php?p=1483709&postcount=10
# + svp from https://forum.doom9.org/showthread.php?p=1574161, note that blocksize is only 8 not for as when using mvtools
#########
function FixRipsP2(clip a, bool "svp")
{
svp=default(svp,false)
a
clense(reduceflicker=false).merge(last,0.5).clense(reduceflicker=false)
mot=removegrain(8,0).DepanEstimate(range=2)
take2=a.depaninterleave(mot,prev=2,next=2,subpixel=2)
clean1=take2.selectevery(5,2)
clean1=clean1.mt_lutxy(clean1,"x 1 + y < x 2 + x 1 - y > x 2 - y ? ?",U=2,V=2)
svp ? { # using svp
sup1 = clean1 .SVSuper("pel:2, scale:{up:0}")
search_params="block:{w:4,overlap:2}" # can't use blocksize 4, w:4 <> blocksize 8
v21=sup1.SVAnalyse("{"+search_params+"}")
v22=sup1.SVAnalyse("{"+search_params+",special:{delta:2}}")
bv22=v22.SVConvert(isb=true)
bv21=v21.SVConvert(isb=true)
fv21=v21.SVConvert(isb=false)
fv22=v22.SVConvert(isb=false)
sup2 = a.msuper(pel=2,levels=1,sharp=2)
interleave(a.mcompensate(sup2,fv22),a.mcompensate(sup2,fv21),a,a.mcompensate(sup2,bv21),a.mcompensate(sup2,bv22))
selectevery(5,2)
sup3 = last.msuper(pel=2,sharp=2,hpad=0,vpad=0)
# SVAnalyse accepts MSuper with zero padding!
v31=sup3.SVAnalyse("{"+search_params+"}")
v32=sup3.SVAnalyse("{"+search_params+",special:{delta:2}}")
v33=sup3.SVAnalyse("{"+search_params+",special:{delta:3}}")
bv33=v33.SVConvert(isb=true)
bv32=v32.SVConvert(isb=true)
bv31=v31.SVConvert(isb=true)
fv31=v31.SVConvert(isb=false)
fv32=v32.SVConvert(isb=false)
fv33=v33.SVConvert(isb=false)
} : { # using mvtools
sup1 = clean1.msuper(pel=2,sharp=0)
sup2 = a.msuper(pel=2,levels=1,sharp=2)
bv21=sup1.manalyse(isb=true, truemotion=true,global=true,delta=1,blksize=4,overlap=2,search=3,searchparam=5,DCT=2)
bv22=sup1.manalyse(isb=true, truemotion=true,global=true,delta=2,blksize=4,overlap=2,search=3,searchparam=5,DCT=2)
fv21=sup1.manalyse(isb=false,truemotion=true,global=true,delta=1,blksize=4,overlap=2,search=3,searchparam=5,DCT=2)
fv22=sup1.manalyse(isb=false,truemotion=true,global=true,delta=2,blksize=4,overlap=2,search=3,searchparam=5,DCT=2)
interleave(a.mcompensate(sup2,fv22),a.mcompensate(sup2,fv21),a,a.mcompensate(sup2,bv21),a.mcompensate(sup2,bv22))
#SpotLess(RadT=5,ThSAD=1000000,ThSAD2=1000000,pel=2,chroma=false,BlkSz=8,Olap=4,tm=false,glob=false,bBlur=0.0).selectevery(5,2) # proposed by The Filter Developper
SpotLess(RadT=2,ThSAD=500000,ThSAD2=499000,pel=2,chroma=true,BlkSz=4,Olap=2,tm=false,glob=false,bBlur=0.0).selectevery(5,2) # to remove less fine details BlkSz=4,Olap=2 et RADT=1 (If higher it creates artifacts)
sup3 = last.msuper(pel=2,sharp=2)
bv31=sup3.manalyse(isb=true, truemotion=true,global=true,delta=1,blksize=4,overlap=2,search=3,searchparam=5,DCT=2)
bv32=sup3.manalyse(isb=true, truemotion=true,global=true,delta=2,blksize=4,overlap=2,search=3,searchparam=5,DCT=2)
bv33=sup3.manalyse(isb=true, truemotion=true,global=true,delta=3,blksize=4,overlap=2,search=3,searchparam=5,DCT=2)
fv31=sup3.manalyse(isb=false,truemotion=true,global=true,delta=1,blksize=4,overlap=2,search=3,searchparam=5,DCT=2)
fv32=sup3.manalyse(isb=false,truemotion=true,global=true,delta=2,blksize=4,overlap=2,search=3,searchparam=5,DCT=2)
fv33=sup3.manalyse(isb=false,truemotion=true,global=true,delta=3,blksize=4,overlap=2,search=3,searchparam=5,DCT=2)
}
#last.mdegrain1(sup3,bv31,fv31,bv32,fv32,bv33,fv33,thSAD=499)
last.mdegrain1(sup3,bv31,fv31,thSAD=499)
#last.mdegrain1(sup3,bv31,fv31,thSAD=499)
interleave()
return last
}
######################
################
function MinBlur(clip clp, int r, int "uv")
{
uv = default(uv,3)
uv2 = (uv==2) ? 1 : uv
rg4 = (uv==3) ? 4 : -1
rg11 = (uv==3) ? 11 : -1
rg20 = (uv==3) ? 20 : -1
medf = (uv==3) ? 1 : -200
RG11D = (r==0) ? mt_makediff(clp,clp.sbr(),U=uv2,V=uv2)
\ : (r==1) ? mt_makediff(clp,clp.removegrain(11,rg11),U=uv2,V=uv2)
\ : (r==2) ? mt_makediff(clp,clp.removegrain(11,rg11).removegrain(20,rg20),U=uv2,V=uv2)
\ : mt_makediff(clp,clp.removegrain(11,rg11).removegrain(20,rg20).removegrain(20,rg20),U=uv2,V=uv2)
RG4D = (r<=1) ? mt_makediff(clp,clp.removegrain(4,rg4),U=uv2,V=uv2)
\ : (r==2) ? mt_makediff(clp,clp.medianblur(2,2*medf,2*medf),U=uv2,V=uv2)
\ : mt_makediff(clp,clp.medianblur(3,3*medf,3*medf),U=uv2,V=uv2)
DD = mt_lutxy(RG11D,RG4D,"x 128 - y 128 - * 0 < 128 x 128 - abs y 128 - abs < x y ? ?",U=uv2,V=uv2)
clp.mt_makediff(DD,U=uv,V=uv)
return(last)
}
function SpotLess(clip c,int "RadT",int "ThSAD",int "ThSAD2",int "pel",bool "chroma", int "BlkSz",Int "Olap",bool "tm",Bool "glob",Float "bBlur") {
RadT = Default(RadT,1) # Temporal radius. (MCompensate arg)
ThSAD = Default(ThSAD,10000) # SAD threshold at radius 1 (Default Nearly OFF).
ThSAD2 = Default(ThSAD2,ThSAD) # SAD threshold at radius RadT.
Pel = Default(pel,2) # Default 2. 1, 2, or 4. Maybe set 1 for HD+. (1=precision to pixel, 2=precision to half pixel, 4=quarter pixel)
Chroma = Default(chroma,True) # MAnalyse chroma arg. If set to true, use chroma in block matching.
BlkSz = Default(BlkSz,8) # Default 8. MAnalyse BlkSize. Bigger blksz quicker and perhaps better, esp for HD clips. Maybe also better where BIG noise.
OLap = Default(OLap, BlkSz/2) # Default half of BlkSz.
Tm = Default(tm,True) # TrueMotion, Some folk swear MAnalyse(truemotion=false) is better.
Glob = Default(glob,Tm) # Default Tm, Allow set MAnalyse(global) independently of TrueMotion.
Bblur = Default(bblur,0.0) # Default OFF
Assert(1 <= RadT,"SpotLess: 1 <= RadT")
pad = max(BlkSz,8)
sup = (bBlur<=0.0 ? c : c.blur(bblur)).MSuper(hpad=pad,vpad=pad,pel=pel,sharp=2)
sup_rend = (bBlur<=0.0) ? sup : c.MSuper(hpad=pad,vpad=pad,pel=pel,sharp=2,levels=1) # Only 1 Level required where not MAnalyse-ing.
MultiVec = sup.MAnalyse(multi=true, delta=RadT,blksize=BlkSz,overlap=OLap,search=4,chroma=Chroma,truemotion=Tm,global=Glob)
c.MCompensate(sup_rend,MultiVec,tr=RadT,thSad=ThSAD,thSad2=ThSAD2)
MedianBlurTemporal(radiusY=0,radiusU=0,radiusV=0,temporalradius=RadT) # Temporal median blur only [not spatial]
SelectEvery(RadT*2+1,RadT) # Return middle frame
}
Problem is the syntax of the ?-operator seems to be wrong.
I thought I correctly looked it up over at http://avisynth.nl/index.php/Block_statements, but that does not seem to be the case.
Do you see the what I did wrong?
Jeez.. i wish, I'm not a coder by any means, just a sub-par tweaker lol. I'm sure they'll help you out on doom9, brilliants minds over there. I support this SVP tweak though (MV's calculated by GPU) , anything to speed up the processing of this script is welcome.
function FixRipsP2(clip a)
{
a
clense(reduceflicker=false).merge(last,0.5).clense(reduceflicker=false)
mot=removegrain(8,0).DepanEstimate(range=2)
take2=a.depaninterleave(mot,prev=2,next=2,subpixel=2)
clean1=take2.selectevery(5,2)
sup1 = clean1
\ .mt_lutxy(clean1,"x 1 + y < x 2 + x 1 - y > x 2 - y ? ?",U=2,V=2)
\ .msuper(pel=2,sharp=0)
sup2 = a.msuper(pel=2,levels=1,sharp=2)
bv21=sup1.manalyse(isb=true, truemotion=true,global=true,delta=1,blksize=4,overlap=2,search=3,searchparam=5,DCT=2)
bv22=sup1.manalyse(isb=true, truemotion=true,global=true,delta=2,blksize=4,overlap=2,search=3,searchparam=5,DCT=2)
fv21=sup1.manalyse(isb=false,truemotion=true,global=true,delta=1,blksize=4,overlap=2,search=3,searchparam=5,DCT=2)
fv22=sup1.manalyse(isb=false,truemotion=true,global=true,delta=2,blksize=4,overlap=2,search=3,searchparam=5,DCT=2)
interleave(a.mcompensate(sup2,fv22),a.mcompensate(sup2,fv21),a,a.mcompensate(sup2,bv21),a.mcompensate(sup2,bv22))
#SpotLess(RadT=5,ThSAD=1000000,ThSAD2=1000000,pel=2,chroma=false,BlkSz=8,Olap=4,tm=false,glob=false,bBlur=0.0).selectevery(5,2) # proposed by The Filter Developper
SpotLess(RadT=2,ThSAD=500000,ThSAD2=499000,pel=2,chroma=true,BlkSz=4,Olap=2,tm=false,glob=false,bBlur=0.0).selectevery(5,2) # to remove less fine details BlkSz=4,Olap=2 et RADT=1 (If higher it creates artifacts)
sup3 = last.msuper(pel=2,sharp=2)
bv31=sup3.manalyse(isb=true, truemotion=true,global=true,delta=1,blksize=4,overlap=2,search=3,searchparam=5,DCT=2)
fv31=sup3.manalyse(isb=false,truemotion=true,global=true,delta=1,blksize=4,overlap=2,search=3,searchparam=5,DCT=2)
last.mdegrain1(sup3,bv31,fv31,thSAD=499)
interleave()
return last
}
removed Tmedian2 (which cause warping) replaced with a tweaked version of Spotless.
What seems strange is that you only replaced TMeadian2 with Spotless in one occurance and simpls dropped the other.
You only use it for sup3, but Didée used it for all sups. This seems strange.
Hey well done, could be useful for animes perhaps (not my area).
Though, Svp is not exactly "motion safe" i've noticed it before when messing with motion interpolation
Happy if someone has any usage for it. I'm usually not really using AviSynth so I won't use it.
I gues the motion problem is related to the bloack size ony be 8.