logo Sign In

Post #674847

Author
althor1138
Parent topic
LDnoise : A Laserdisc denoiser for Avisynth.
Link to post in topic
https://originaltrilogy.com/post/id/674847/action/topic#674847
Date created
29-Nov-2013, 2:10 PM

I came up with this idea a couple of weeks ago and it worked a lot better than I thought it would so I'm posting it here to hopefully get some feedback and so others can use it if they want.

There are a few requirements for this function to work properly:

1.) Clip needs a resolution of 720x480.

2.) Must be in YUY2 colorspace.

3.) Must be widescreen format. (This denoiser samples the black bars for noise and uses this information to denoise the film area.)

4.) Requires MVTOOLS2 and DFTTEST along with knowledge of avisynth.

function LDnoise(clip input, float "strength", int "mc", int "temporalframes",\

int "blksize", int "search", int "searchparam", int "overlap", int "dct")

{

 

# Set default options. 

 

strength=default(strength,1)

temporalframes=default(temporalframes,1)

mc = default(mc, 0)

 

# Prepare supersampled clip.

 

super = input.MSuper(levels=6,chroma=true)

 

# Motion vector search.

 

b5vec = MAnalyse(super, delta=5, isb=true,chroma=true, search=search, searchparam=searchparam, overlap=overlap, dct=dct)

b4vec = MAnalyse(super, delta=4, isb=true,chroma=true, search=search, searchparam=searchparam, overlap=overlap, blksize=blksize, dct=dct)

b3vec = MAnalyse(super, delta=3, isb=true,chroma=true, search=search, searchparam=searchparam, overlap=overlap, blksize=blksize, dct=dct)

b2vec = MAnalyse(super, delta=2, isb=true,chroma=true, search=search, searchparam=searchparam, overlap=overlap, blksize=blksize, dct=dct)

b1vec = MAnalyse(super, delta=1, isb=true,chroma=true, search=search, searchparam=searchparam, overlap=overlap, blksize=blksize, dct=dct)

f1vec = MAnalyse(super, delta=1, chroma=true, search=search, searchparam=searchparam, overlap=overlap, blksize=blksize, dct=dct)

f2vec = MAnalyse(super, delta=2, chroma=true, search=search, searchparam=searchparam, overlap=overlap, blksize=blksize, dct=dct)

f3vec = MAnalyse(super, delta=3, chroma=true, search=search, searchparam=searchparam, overlap=overlap, blksize=blksize, dct=dct)

f4vec = MAnalyse(super, delta=4, chroma=true, search=search, searchparam=searchparam, overlap=overlap, blksize=blksize, dct=dct)

f5vec = MAnalyse(super, delta=5, chroma=true, search=search, searchparam=searchparam, overlap=overlap, blksize=blksize, dct=dct)

 

# Motion Compensation.

 

b5clip = MCompensate(input,super, b5vec)

b4clip = MCompensate(input,super, b4vec)

b3clip = MCompensate(input,super, b3vec)

b2clip = MCompensate(input,super, b2vec)

b1clip = MCompensate(input,super, b1vec)

f1clip = MCompensate(input,super, f1vec)

f2clip = MCompensate(input,super, f2vec)

f3clip = MCompensate(input,super, f3vec)

f4clip = MCompensate(input,super, f4vec)

f5clip = MCompensate(input,super, f5vec)

 

# Create compensated clip.

 

interleaved = mc >= 5 ? Interleave(f5clip, f4clip, f3clip, f2clip, f1clip, input, b1clip, b2clip, b3clip, b4clip, b5clip) :

\ mc == 4 ? Interleave(f4clip, f3clip, f2clip, f1clip, input, b1clip, b2clip, b3clip, b4clip) :

\ mc == 3 ? Interleave(f3clip, f2clip, f1clip, input, b1clip, b2clip, b3clip) :

\ mc == 2 ? Interleave(f2clip, f1clip, input, b1clip, b2clip) :

\ mc == 1 ? Interleave(f1clip, input, b1clip):

\ input

 

#Perform DFTTEST

 

params="""dfttest(y=true,u=true,v=true,f0beta=0.5,sigma=0,dither=0,sbsize=25,sosize=20,tbsize="""+string(temporalframes)+""",tosize="""+string(temporalframes)+"""/3,nstring=\

    "a:"""+string(strength)+""" \

    "+string(current_frame)+",0,440,10 \

    "+string(current_frame)+",0,10,10 \

    "+string(current_frame)+",0,10,340 \

    "+string(current_frame)+",0,10,680 \

    "+string(current_frame)+",0,440,680 \

    "+string(current_frame)+",1,440/2,3 \

    "+string(current_frame)+",1,3,3 \

    "+string(current_frame)+",1,3,340/2 \

    "+string(current_frame)+",1,3,680/2 \

    "+string(current_frame)+",1,440/2,350 \

    "+string(current_frame)+",2,120,3 \

    "+string(current_frame)+",2,3,3 \

    "+string(current_frame)+",2,3,340/2 \

    "+string(current_frame)+",2,3,680/2 \

    "+string(current_frame)+",2,440/2,680/2")

    """

filter=eval("scriptclip(interleaved,params)")

return SelectEvery(filter, mc * 2 + 1,mc)

 

}

 

There are only 3 parameters that you need to adjust really.  They are:

 

Strength: It defaults to 1.  Valid range is .01 and up.  1-10 is a good area to stay within. Every source needs tweaked however, so numbers can vary wildly.  There is no set and forget.

Temporalframes: Defaults to 1. 1 enables spatial only filtering.  Must be an odd number. Numbers above 9 are overkill and will probably cause a crash. I recommend 1 or 3.

MC: Defaults to 0. Valid range is 0-5. Defines the number of motion compensated frames. I recommend setting this to 5 if you have enabled temporal filtering with the temporalframes parameter.

 

This is basically a motion compensated dfttest wrapped into a function.  It's different from just running dfttest and letting the denoiser blindly search for noise though.  It samples noise from 5 separate blocks in the widescreen bars, for the frame that it is processing, in the luma and chroma planes and applies this information when denoising. If you enable temporal frames it starts comparing noise from the previous and future frames as well.  The motion compensation prevents stuff like laser bolts from getting erased when temporal filtering is enabled, etc.  It has the same problems as most denoisers and if you crank it up everything will turn to plastic.  It's strong point is that it is much better at keeping detail with less artifacting. It can cause banding with higher values, especially in the black bar areas.

This won't work on the GOUT,for example, because there isn't any analog noise in the black bar areas as far as I know. BTW, this will work with the JSC captures because I've set the coordinates for the noise sampling blocks outside of any areas that would contain subtitling.