Wednesday, January 1, 2020

Two different solutions for Denoising video with AVISynth

Last year, I worked on a couple of projects that involved not just deinterlacing, but denoising. Some scenes had a fine, natural noise that I preferred to keep intact. Other scenes had so much noise it was difficult to make out the faces of the actors. Figuring out how to minimize the noise without sacrificing too much detail or looking jarringly different from the surrounding shots turned out to be a real challenge.

Here are some notes from my experimenting.

Commercial tools


There are some commercial tools for denoising, each with their own strengths and weaknesses. Here's three of the most common:

I've used Neat Video in the past, and it has some real advantages in terms of denoising strength, being able to manually select what to consider noise (if there's a large enough area of just noise in frame), and parameters to tweak. In particular, it's great at dealing with blotchy chroma (color) noise. It's really easy to overdo it, however, and sometimes it takes a lot of tweaking to remove only the noise you want.

There's also Red Giant's Denoiser III, which has a much simpler interface, and is better for even noise reduction, although not as great for dealing with truly terrible noise.

Then there's the Studio version of DaVinci Resolve. I don't own this and can't get a trial version, so I don't know how well it would perform.

If you're looking to denoise HD or higher resolution footage, I'd recommend one of the above. They're all fully GPU accelerated, focus on modern camera sensor noise, and they don't have a chance of introducing gamma or color shifts.

However, for SD interlaced video, I think AVISynth has some better options.

TemporalDegrain2


Let's start with TemporalDegrain2. With low to medium grain/noise, the default settings are usually fine. It uses many of the same requirement filters as QTGMC, so if you've already got QTGMC set up, you should be able to use TemporalDegrain2 at defaults. The one setting to pay attention to is grainLevel=True. Setting this to False may give better performance on some footage, so try it both ways to check.

Here's a brightened capture of some noisy SD footage (Note that I haven't done a pixel aspect ratio correction, so the image is slightly squashed):


And here's the same footage passed through TemporalDegrain2 at grainLevel=False:


And grainLevel=True:



The difference is subtle in this case, but definitely there.

More detailed instructions are included in the .avsi script if you want to play around with things, but in my experience, the defaults do the best job at denoising without undesirable artifacts.

Oh, and one more important thing: TemporalDegrain2 has a 64-bit version for AVISynth.

SMDegrain


Next, let's look at SMDegrain. If you thought QTGMC has a lot of options...

Using the recommendations for a starting point from the documentation:

SMDegrain(tr=2,thSAD=250,contrasharp=true,refinemotion=true,lsb=true)
Gives this result:


Not very impressive in this case. Let's try the recommendation for "dark scenes", and trigger the interlaced switch so the denoising can be done prior to calling QTGMC:

 SMDegrain(tr=3,thSAD=300,contrasharp=true,str=2.0,refinemotion=true,lsb=true,interlaced=true)
Which gives us this:


Better, but still not great. Again, this is a fairly noisy clip. Depending on the type/amount of noise, the defaults might be much more effective.

Now, let's look at the option for "grainy sources". I like to call this the "kitchen sink" option:

pre=fluxsmootht(3).removegrain(11)
SMDegrain(tr=6,thSAD=500,contrasharp=30,prefilter=pre,str=1.2,refinemotion=true,lsb=true)
What's happening here is that in addition to increasing the strength of denoising, we've added a prefilter. This is designed to blur the image first when calculating what detail to preserve, so the denoise can be that much more aggressive. If you just use a number here, SMDegrain will do some variation of a simple blur for it's initial calculations. In this case, we're using more intensive solutions. Here's the end result:


Now we're talking. However, you should know some things about the Kitchen Sink method:
  • If you use the interlaced option it'll distort, so don't do that. You could use SeparateFields() first and AssumeFieldBased() plus Weave() after to try to preserve the interlacing while reducing the amount of time it takes to denoise, but in my experience, that makes the processing look crappier/lower resolution. Either use it after QTGMC, or use it before and accept that the motion may not always look quite right.
  • You can do multiple passes, but since SMDegrain is 32-bit only, you're realistically limited to 2 passes without render freezes/crashes due to memory issues.
  • Yes, SMDegrain is available in 64-bit for VapourSynth (via havsfunc, which also contains a port of QTGMC). There, you're more likely to be able to squeeze in 3 passes, but it'll be excruciatingly slow if you do that, and can end up overprocessing the image. Also, you'll need to pay attention to the documentation for the various options, as they sometimes use different capitalization than on AVISynth. Why? Basically, VapourSynth scripts use Python, and Python is case-sensitive. Also, you have to re-write the fluxsmootht and removegrain entries in a different way, and remove the lsb=true option (because VapourSynth doesn't need it).
  • In footage with significant motion, you may notice more of a smearing effect, similar to the old-school electronic denoising on the laserdisk versions of the original Star Wars trilogy.
  • If you use multiple passes, you can end up with a dithering effect that's very noticeable on dark footage.
Basically, there are some drawbacks. The good news is that you can get very close to the same results with a line like this:

SMDegrain(tr=6,thSAD=500,contrasharp=0,str=1.2,refinemotion=true,lsb=true,interlaced=true)
Which gives this:


This is easier to run, has less of a smearing effect, works better with interlaced footage, and I've removed the built-in sharpening (Contrasharp) so I can use LimitedSharpenFaster later instead.

For those interested, here's a condensed (AVISynth+) version of my .avs script using the above options:

SetFilterMTMode("QTGMC", 2)
SetFilterMTMode("f3kdb", 2)
AVISource("DV Noise Test intro.avi", audio=true)
ConvertToYV12()

SMDegrain(tr=6,thSAD=500,contrasharp=0,str=1.2,refinemotion=true,lsb=true,interlaced=True,Globals=2) 
QTGMC( Preset="Slower", EdiThreads=3 ) 
#--------------(Optional) Reduce chroma noise----------------------
#f3kdb(grainY=0, grainC=0, sample_mode=1)  
Prefetch(10) 
Since the original clip is DV video, I've done a colorspace conversion to YV12. If you're using a Digibeta file or ProRes capture, you might be able to get away without it, or you could convert to YUY2 instead.


Some other info that might be worth knowing:

SMDegrain has a variable called "globals" that allows you to change the way motion vectors are used. Basically, the globals are motion vector calculations, which can be either generated each time SMDegrain is called (default), passed through, or used from previous passes. In other words, if you want the same patterns of noise to be denoised in subsequent passes, you can use:

SMDegrain(tr=6,thSAD=500,contrasharp=0,str=1.2,refinemotion=true,lsb=true,interlaced=true,Globals=2)

for the first pass and:

SMDegrain(tr=6,thSAD=500,contrasharp=0,str=1.2,refinemotion=true,lsb=true,interlaced=true,Globals=1)

for the second. While doing so can reduce processor load a bit, it's still generally not a good idea to do three or more passes, even with globals=1.

From the documentation, here's how each number option works:
  • 0: Ignore globals, just process
  • 1: Read globals and Process
  • 2: Process and output globals
  • 3: Output globals only, don't process 

  • Doing a globals=2 pass and then a globals=1 pass results in the following:



    Which is pretty darn clean. You may still notice some artifacts on fast-moving objects:



    but that's true of any SMDegrain setting that I've tried. TemporalDegrain2 does better with these artifacts, but not so well with overall noise in noisy footage, at least at defaults:



    Oh, and if you still have chroma noise after this, you might want to try messing with something like f3kdb.

    Other notes


    For comparison's sake, here's the best results I could get using Magic Bullet Denoiser III and Neat Video 5, applied to a version of the video already deinterlaced with QTGMC. Yes, both have ugly watermarks due to them being trial versions.



    I could probably get Neat Video looking a bit better with some more tweaking, but this is what I would consider an acceptable denoise from it. If you look closely, you'll notice that Denoiser III retains some noise in this case, while Neat Video removes more, but has a slightly plastic look. This is the tradeoff in denoising - removing *all* grain often removes surface details you might want to keep. For an extreme example of this, check out the Predator Ultimate Edition Blu-Ray.



    I may update this post later, but I think that's it for now. Post a comment if you have a question or correction.

    32 comments:

    XerxesZ said...

    HI Andrew,
    Have enjoyed you AviSynth restoration videos and others (Lamy, NM), a fan and subscriber.

    I have purchased and use Neat Video on older SD interlaced AVI files (BTW: great support). The company suggests it be used first, prior to any other filters, such as deinterlacing.

    Have experimented, but have used it as prescribed, and the saved files as ProRes, followed by the deinterlacing process as you describe through AviSynth or within After Effects using Field Kits plug in demo. Unfortunately Fields Kits program can not create 60 frames per second within Premiere pro, but will do it within After Effects.

    The order is important. In future video you might test this out.
    Thanks for all your help. You are a A great teacher.

    RDN

    Andrew Swan said...

    I might do that, RDN. Thanks.

    Dogway said...

    Hello good rundown of SMDegrain. For heavy grain sources I would first evaluate a good spatial (or soft temporal-spatial) denoiser that looks rather clean in as a still frame (prefilter=4 maybe), and then feed that as a prefilter to let SMDegrain bring coherence in the temporal domain. With low contrast sources like this I think lowering thSAD and tr a bit can be helpful.

    Andrew Swan said...

    Dogway: I messed with prefiltering a bit, and it's debatable whether it's better or not for the sample clip I used in this post. However, the "kitchen sink" method works great on other SD footage I've processed, and it uses extensive prefiltering, so I guess it's something to try on a case-by-case basis.

    You were definitely right about changing thSAD, though. Bumping it up helped my sample clip a lot. I'll do some more testing, and update the post.

    Mary said...

    Hello Andrew I'm having a problem with missing Dither_lut8 called by SMDgrain. I have a dither.dll shown by AVIsynth tool. Where can I find it? Libfftw3f-3.dll seems to be having problem too. It's in both Sys32 and Wow64 but AVIsynth tool says it's needed by MVTools.dll and I should put it in. Can't figure out either one. Thank you for your time. Steep learning curve.

    Andrew Swan said...

    Mary,

    The trick with libfftw is that you need to use the 32-bit version in SysWOW64 on a 64-bit OS *or* the 64-bit version in System32 on a 32-bit OS. Don't ask me why. Also, make sure you have both libfftw3f-3.dll and a copy of it named "FFTW3.dll" in whatever system directory you use.

    As to issues with Dither, if you don't already have QTGMC set up, you may not have all the prerequisite filters installed for Dither to work. Check here:

    http://avisynth.nl/index.php/Dither

    and use the results of AVSInfotool to see what you're missing.

    I agree that setting up this stuff is a royal PITA. If I could find a free, open source alternative, I would heartily recommend it.

    Mary said...

    Got the problems fixed Thank you but when I ran the script it didn't do anything to the video. I adjusted the setting to max for a second try and still nothing. I took the same frame from each video and they were all exactly the same. Had some trouble getting the batch file to run but I finally got it right. When using AVSPMOD I can watch the video great until I add the QTGMC then it becomes basically unusable. Windows reports "not responding" but it is still working but extremely slowly. Do you have any insight into this problem? Could you possibly send a screen shot of your Avisynth tool for both the 32 and 64? I would like to see what I am probably missing or what I don't need. Thanks again.

    Andrew Swan said...

    Mary,

    I have a bunch of filters installed, so I'm not sure how helpful my avstool dump would be.

    You shouldn't try to *play back* video with QTGMC or other hefty filters applied inside AVSPMod - they're incredibly demanding, and not designed for real-time playback. It's better to just go to a frame and use the F5 key to update that frame when you change settings, then maybe move a couple of frames forward using the arrow keys.

    Could you do me a favor and post your .avs script? It might help me narrow down the issues you're having.

    Mary said...

    This is what I pulled off your blog and only changed the input file and some settings using the AVSPMOD.

    SetFilterMTMode("QTGMC", 2)
    SetFilterMTMode("f3kdb", 2)
    FFMPEGSource2("Reel1noedit.mp4")
    ConvertToYV12()

    SMDegrain(tr=6,thSAD=1000,contrasharp=0,str=8.0,refinemotion=true,lsb=true,interlaced=false,Globals=2)

    QTGMC( Preset="Very Slow", EdiThreads=2 )

    #--------------(Optional) Reduce chroma noise----------------------
    #f3kdb(grainY=0, grainC=0, sample_mode=1)

    Prefetch(4)

    Ok I will try not to play the file. I will just try to select one frame.

    Andrew Swan said...

    Cool. Some other notes:

    - If you aren't using f3kdb, then you can remove the SetFilterMTMode line with it at the the top and the commented-out line towards the bottom.

    - If you plan on denoising before QTGMC, make sure to set the interlaced option to true.

    - If you have a quad-core processor without hyperthreading (or dual-core with hyperthreading), then your PreFetch and EdiThreads look fine. If you have a quad-core with hyperthreading, you could double the numbers for each.

    Mary said...

    I didn't use the F3kdb because it wasn't installed. I installed it and used the following script.

    SetFilterMTMode("QTGMC", 2)
    SetFilterMTMode("f3kdb", 2)
    FFMPEGSource2("Reel1noedit.mp4")
    ConvertToYV12()

    SMDegrain(tr=6,thSAD=1000,contrasharp=0,str=8.0,refinemotion=true,lsb=true,interlaced=true,Globals=2)

    QTGMC( Preset="Very Slow", EdiThreads=4)

    #--------------(Optional) Reduce chroma noise----------------------
    f3kdb(grainY=1, grainC=1, sample_mode=1)

    Prefetch(7)



    Didn't change much but put some numbers in the F3kdb filter. I haven't read up on it to see what the parameters are yet. AVSPmod would not even go past the spinning wait wheel of wait. hit the batch file and output started OK. Same results no change in a frame at all. I tried to paste the frames but no dice. Sooooooo what do you think is happening here. I was hoping for a little change at least.


    Mary said...

    tried this too. It's like the video just goes in and back out without a single change.

    SetFilterMTMode("QTGMC", 2)
    SetFilterMTMode("f3kdb", 2)
    FFMPEGSource2("Reel1noedit.mp4")
    ConvertToYV12()

    SMDegrain(tr=6,thSAD=1000,contrasharp=0,str=8.0,refinemotion=true,lsb=true,interlaced=true,Globals=2)

    QTGMC( Preset="Very Slow", EdiThreads=4)

    #--------------(Optional) Reduce chroma noise----------------------
    f3kdb(grainY=100, grainC=100, sample_mode=1)

    Prefetch(7)

    Mary said...

    this is .bat script

    ffmpeg -i Reel1noedit.mp4 -c:v libx264 -preset slow -crf 22 -c:a copy outputReel1noedit5.mp4

    I've tried resizing and cropping Nothing changes.

    Andrew Swan said...

    Your .bat script points to the original video file as the input rather than the .avs script. Try changing that, then see what you get.

    Also, you can switch to "Slower" rather than "Very Slow" for the QTGMC preset. The quality difference isn't really noticeable.

    Mary said...

    I knew it was something dumb like that. I remember when I was first doing the .bat the CMD would just flash up and go off. I looked around on the web and got something to use the video file name. Must have been for some other process. so basically I was just encoding the file back to exactly what I started with.:( I was using .avsi when I changed it to .avs wonders of wonders it worked. :) Thank you so much. Now I can start to see what the different parameters do to make my video better. Thanks again.

    Mary said...

    It's going but barely. .6 frames per second. I have a Intel Core i7-2600 CPU @ 3.4GHZ 4 core 8 threads. Is this to weak a processor? I'm only doing a 6000 frame clip to check my processes but this will take forever. It will be even worse when I do the full video files. CMD is taking about 80% of the processor but I did lower down the prefetch because it didn't even appear to be starting in CMD. this is what I'm running.

    SetFilterMTMode("QTGMC", 2)

    FFMPEGSource2("Reel1noedit.mp4")
    ConvertToYV12()

    SMDegrain(tr=6,thSAD=500,contrasharp=0,str=1.2,refinemotion=true,lsb=true,interlaced=true,Globals=2)

    QTGMC( Preset="Slower", EdiThreads=2 )

    #--------------(Optional) Reduce chroma noise----------------------
    #f3kdb(grainY=0, grainC=0, sample_mode=1)

    Prefetch(4)

    Andrew Swan said...

    What version of AVISynth are you running?

    You *should* also be able to raise PreFetch to 8 without a problem, but if it still freezes then maybe compromise and do 6? It's usually EdiThreads that can jam up the encoding if it's set too high, and your setting of 2 should be fine.

    Also, if you want to benchmark your script for resource usage using different settings, you can try downloading and running avsmeter (with something like "avsmeter youscript.avs") in the same directory as your script.

    Mary said...

    I pretty sure its this one. But Ive installed so much I don't remember.
    AviSynthPlus-MT-r2772-with-vc_redist.exe
    I'll try the meter thank you. Oh and it worked, I can see the difference now:)

    Mary said...

    Where can I get the F3kdb? Is this a .dll or a .avs? I redid my compuetr and am retrying the scripts. This is a royal pain.

    Andrew Swan said...
    This comment has been removed by the author.
    Andrew Swan said...

    Mary,

    Try this link:

    http://forum.doom9.org/showthread.php?t=161411

    It's more direct. Scroll down to where it says "Binary" and choose the x86 version.

    Mary said...

    I'd say the web page has a problem.

    Fatal Error: ezSQL_mysql requires mySQL Lib to be compiled and or linked in to the PHP engine

    I'll look around tomorrow. I tried today but didn't have any luck. I see you deleted your first post. Was it all @%$&#*%$@&%*#@$

    Andrew Swan said...

    Yeah, I posted the link to the F3kdb GitHub page in the deleted comment, but that just has the source code. Not sure why you got the SQL error on the doom9 post - it comes up fine for me. You could try going through the plugin page on the AVISynth wiki:

    http://avisynth.nl/index.php/External_filters#Debanding

    There’s some other alternatives there as well for debanding.

    enable said...
    This comment has been removed by a blog administrator.
    enable said...

    Hi Andrew Swan

    can you tell me whats different
    EdiThreads=2 and EdiThreads=50 ?

    i used both of them. my cpu usage for both %60 and time spent for encoding are are same.

    i have a laptop with (intel core 17-3610QM) cpu. HyperThreading = disable

    i read this WIKI:
    http://avisynth.nl/index.php/QTGMC#Multi-Threaded_Usage

    can you give a example SetMTMode X

    or can you give me a sample script for QTGMC with most usage cpu power? i need encode some video with QTGMC filter

    thanks.

    Andrew Swan said...

    If you've disabled Hyperthreading, you won't get full performance out of the multithreaded filters.

    Most modern multithreaded filters are detected automatically by AVISynth+, but if you want to enable it manually, you can do a SetFilterMTMode("f3kdb", 2) command.

    As to EditThreads, set it to half your total number of logical cores (you can find that in task manager). there's no benefit to going above that.

    Mark Hevingham said...

    Hi Andrew, I am a bit late to the party. Having experimented with various options I am using your YouTube method from OUTDATED - Deinterlacing SD video with AVISynth+, QTGMC, and FFMPEG Tutorial - Revisited Oct 8, 2018. I am running an i7, GTX1080 and 64GB RAM on W10. For some unexplained reason the newest method results in stuttering footage out of Virtual Dub so I am using the .bat method.

    Currently I am deinterlacing old PAL recordings and Spline64 upsizing to 1440 x 1080 with fantastic results so firstly THANK You for the fabulous tutorial.

    Some of the clips I am converting are "telerecordings" as we say in the UK or "Kinescopes" as I believe you would know them. 25i to 50p HD looks great bar one issue. When transferred to 16mm film, the recordings have become very noisy in places. As you can imagine there is a lot more grain on a kinescope due to being on film than if the program was on BW VT. I was wondering which plugin you would recommend and where to place it in my simple script taken from your 64 tutorial as I have tried adding a few and it says I can't run 32 bit in the program?

    SetFilterMTMode ("QTGMC", 2)
    FFmpegSource2("title_t05.mkv", atrack=1)
    ConvertToYV12()
    AssumeTFF()
    QTGMC(preset="Slow", EdiThreads=1)
    Spline64Resize(1440,1080)
    Prefetch(1)

    Kind regards and thanks from the UK

    Mark

    Andrew Swan said...

    @ Mark Hevingham

    I'm not an expert in denoising using AVISynth, but I've seen decent results from TemporalDegrain2. Here's a blog post I did looking at a few different options that might be helpful:

    https://macilatthefront.blogspot.com/2020/01/two-different-solutions-for-denoising.html

    Mark Hevingham said...

    Thank you Andrew. Very kind of you to reply so quickly

    Unknown said...

    Hello and thank you for your time to test all of theses variants. As I can see, you always use the denoiser before using QTGMC in the default-setting.

    But does QTGMC in default not also remove some noise? And why do not use the denoise options that are included in QTGMC (or even QTGMC+ https://github.com/Dogway/Avisynth-Scripts/blob/master/MIX%20mods/QTGMC%2B.avsi)?

    Andrew Swan said...

    Whether or not I use just QTGMC depends on both the amount and size of the noise in the image. If it’s just a bit of noise, then it works fine. However, for heavy noise, I find that either TemporalDegrain2 or a commercial solution like Neat Video are much more effective. I haven’t heard of/used QTGMC+, so I’ll have to check that out at some point.

    Unknown said...

    Hm, maybe it's because QTGMC+ is just so much better than the QTGMC version you used, or the parameters need just so much tuning an luck. I gave it a very quick shot at some MiniDV footage that has similar if not even more noise than your example. The results are stunning, there is nearly no more noise but sill fine details remain very clearly. As I said, it was a quick shot that might additional tuning, because the result now looks almost as plastic.

    I uploaded you some stuff in my Google drive, feel free to use: https://drive.google.com/drive/folders/1a9AddbrHcpL5QRCFK3Bzs-t4mmLNm2hq

    My QTGMC+ call with noise reduction is like that (I do not care about the slow processing time):

    QTGMCp(clip1, Preset="Placebo", SourceMatch=3, MatchPreset="placebo", MatchPreset2="Placebo", Sharpness=0.25, SLMode=4, SOvs=2, SVThin=0.5, TR0=2, TR1=2, TR2=2, Rep0=1, Rep1=0, Rep2=4, RepChroma=True, Lossless=2, EdiMode="NNEDI3", NNSize=3, NNeurons=4, EdiQual=2, EdiMaxD=3, NoiseProcess=1, ChromaNoise=true, Denoiser="dfttest", DenoiseMC=true, NoiseTR=2, Sigma=1.8, GrainRestore=0.0, NoiseRestore=0.0, NoiseDeint="Generate", StabilizeNoise=true, Precise=true, ShowNoise=0)

    Which deinterlacing algorithm is the best? Part 1 - HD interlaced footage

    Before I began, I'd like to give a special thanks to Aleksander Kozak for his help in testing and providing the HD footage used in this ...