Log in

View Full Version : MVDenoise vs MVDegrain1/2


Morte66
18th February 2007, 16:25
Lately I've been trying out MVTools, mostly for denoising. And one thing is puzzling me: what's the difference in intent between MVDegrain1/2 and MVDenoise? Obviously they have slightly different parameters, and MVDenoise goes faster whilst AFAICT MVDegrain generally does more. But other than that, are they meant for different applications? Or is MVDegrain just a more sophisticated solution to the same problem?

Do they tackle different issues, e.g. one for pixel-sized random noise and the other for patterened film grain or something like that?

How would you decide which to use, apart from trial and error?

Would it ever make sense to use both?

This might have an answer so simple that nobody felt they needed to put it in the docs (http://avisynth.org.ru/mvtools/mvtools.html), but indulge me...

Terranigma
18th February 2007, 16:42
Mvdegrain removes both grain and noise.
using mvdenoise from my experiences, seemed to have introduced blocks in certain frames. I've never gotten that using mvdegrain, so I'd prefer mvdegrain2 over mvdenoise any day. :)

*.mp4 guy
18th February 2007, 17:30
It roughly breaks down to mvdegrain2>mvdegrain1>mvdenoise both in quality/effectiveness and speed. Otherwise they all do more or less the same thing, infact the only difference between mvdegrain 1 and 2 is the amount of motion compensation used (2 uses more). mvdegrain1/2 doesn't ever introduce blocking (in my experience) while mvdenoise can.

Didée
18th February 2007, 17:55
The lesser blocking of MVDegrain is most probably due to the fact that MVDegrain can work with overlapped blocks. MVDenoise can not. (MVDenoise was there long time before overlapped-blocks operations were introduced by Fizick.)

Methodology of operation:

- MVDenoise does a plain temporal averaging of the compensated frames.

- MVDegrain: We don't know what it's doing exactly, Fizick never told us. *cough*. (In the sources, the interesting parts are assembler code.)
Some kind of temporal median filtering is supposed to be involved, that's all that can be said. Until Fizick reveals the "secret", that is.

(You may call me an oddball, but that's the main reason I don't use MVDegrain. It's a black box, and about black boxes I've ranted in the past already ...)

Morte66
18th February 2007, 19:16
The lesser blocking of MVDegrain is most probably due to the fact that MVDegrain can work with overlapped blocks. MVDenoise can not.

That's what I've found. My interest in MVTools started with a degrain/deblock routine M4G gave me for a really bad DVD:
source = last
backward_vec2 = source.MVAnalyse(isb = true, delta = 2, pel = 2, overlap=4, sharp=2, idx = 1, truemotion=true)
backward_vec1 = source.MVAnalyse(isb = true, delta = 1, pel = 2, overlap=4, sharp=2, idx = 1, truemotion=true)
forward_vec1 = source.MVAnalyse(isb = false, delta = 1, pel = 2, overlap=4, sharp=2, idx = 1, truemotion=true)
forward_vec2 = source.MVAnalyse(isb = false, delta = 2, pel = 2, overlap=4, sharp=2, idx = 1, truemotion=true)
mask = mvmask(kind=1, vectors=forward_vec1).UtoY().spline36resize(720,576)#its very important that this line matches the resolution you are feeding the script with
smooth = source.degrainmedian(mode=3).fft3dfilter(bt=3, sigma=4, plane=0)
source2 = maskedmerge(source, smooth, mask)
source2.MVDegrain2(backward_vec1,forward_vec1,backward_vec2,forward_vec2,thSAD=400,idx=1)
That's great but very slow, about 1.75fps for 720x576 on my A64 X2 3800+. So I started looking at Deblock_QED with MVDenoise, MVDegrain1/2 or fft3dgpu, hoping it would work out for normal quality DVDs where the blocking is not due to motion in the content.

I got Deblock_QED and non-overlapped MVDegrain1 working pretty nicely at about 5-6fps, and at first I thought I had 80% of the results for 30% of the CPU. But it turns out that it breaks up into clusters of blocks on certain patterns and motion (check clothing is a particular culprit). The same material has no blocking with ffd3dgpu, but it doesn't look so pleasing to me. I'm going to try MVDegrain with overlapping next.

Boulder
18th February 2007, 19:27
- MVDegrain: We don't know what it's doing exactly, Fizick never told us. *cough*. (In the sources, the interesting parts are assembler code.)
Some kind of temporal median filtering is supposed to be involved, that's all that can be said. Until Fizick reveals the "secret", that is.I've always thought that MVDegrain is DeGrainmedian on steroids..just better motion compensation perhaps?

Fizick
18th February 2007, 22:11
Well,
I complitely with you, Didee! I do not use any of your scripts, because I do not understand them. ;)

Do you really try read C source code?
Interesting part of code does not contain any assembler. :)
Here is simple description:

MVdenoise uses hard thresholding. If SAD is above thSAD threshold, or motion vector length is above some thMV threshold, this compensated block is not used. If no, source block is used instead (in averaging). Result pixel is average of all compensated pixels of good blocks with difference from source pixel below third Temporal threshold (and source included).

MVDegrain uses soft thresholding. If SAD is above threshold, this block is not used. If SAD is below threshold, its weight is equal to (Threshold-SAD). Result is (normalized) weighted sum of blocks (several frames and source).
Second difference is overlapping in MVDegrain.

Didée
19th February 2007, 00:43
Well,
I complitely with you, Didee! I do not use any of your scripts, because I do not understand them. ;)
Fair enough! (For the joke.) :D

However, it is not quite the same:
A user of Avisynth is supposed to understand its script language. (hence figuring a script's workflow can be expected.)
However, an avisynth user is not necessarily supposed to understand C language! (and being unsure about some small syntactical things can be enough to drive you into confusion & not-understanding.)

Therefore, I dare to say that my reasoning is more traceable than yours. :p

Joking apart: Thanks for the short summation. So, MVDegrain basically is doing just weighted averaging? Interesting.The weighting and overlapping stuff was clear, that was mentioned in the past. But not the averaging thingy ... the "degrain" in the filter name made me think that some median-like clipping would be used. My wrong.
Now I see that MVDegrain is more primitive than I thought it would be. :)

Well, if so, then Boulder's assumption of
I've always thought that MVDegrain is DeGrainmedian on steroids..just better motion compensation perhaps?
can be answered with "no". Clipping and averaging are two different pairs of shoes.


@ Morte66:

Assuming that idx handling of MVDegrain is working as expected, your script is wrong.

First, you're doing halfpel vector search on 'source', with "idx=1". (Now, idx=1 is "tied" to the clip 'source'.)

Then, you produce 'source2'. The result is a clip that's different from 'source'.

Lastly, you call MVDegrain on 'source2' ... BUT with idx=1. And that's where the error lies: You want MVDegrain to work on 'source2', but by specifying idx=1 you tell MVDegrain to use the halfpel interpolation of 'source'. So, effectively MVDegrain is processing 'source' instead of 'source2'.
--> You need to use "idx=2" in the MVDegrain line.
(Or any other value that's a) different from the idx in the MVAnalyze lines and, just in case, that's b) not used anywhere else in the script.)


Hmmh ... somehow, somewhere, a more sticking-out explanation of the idx "problem" should be made. It's not difficult to use idx correctly, really. But somehow, it gets used wrong regularly ...

Fizick
19th February 2007, 06:20
Yes, MVDegrain is very primitive (as all genious things) :)
about name: is is not MVDegrainMedian.
idx is hell, i know, but it is useful.


(I corrected MVDenoise description a bit above).

Morte66
19th February 2007, 12:41
@ Morte66:

Assuming that idx handling of MVDegrain is working as expected, your script is wrong.

First, you're doing halfpel vector search on 'source', with "idx=1". (Now, idx=1 is "tied" to the clip 'source'.)

Then, you produce 'source2'. The result is a clip that's different from 'source'.

Lastly, you call MVDegrain on 'source2' ... BUT with idx=1. And that's where the error lies: You want MVDegrain to work on 'source2', but by specifying idx=1 you tell MVDegrain to use the halfpel interpolation of 'source'. So, effectively MVDegrain is processing 'source' instead of 'source2'.

Well, the script is a "black box" ;) I just paste it in on certain encodes, I didn't even start to understand it until this weekend.

But now I look at it... It seems to me that I'm doing MVAnalyse on source and leaving notes in idx1. Then I'm using part of the analysis to create the deblocked source2 with MaskTools (which I don't understand at all, that's for next weekend). Then I do MVDegrain on source2 using the notes from source that was stored in idx1. If source2 has the same motion as source (it's a deblocked version), would this be OK?

Morte66
19th February 2007, 13:00
Yes, MVDegrain is very primitive (as all genious things) :)
about name: is is not MVDegrainMedian.

So this is why the docs include an example of motion compensation for external denoisers...
source=last
backward_vectors = source.MVAnalyse(isb = true, truemotion=true, delta = 1, idx = 1)
# we use explicit idx for more fast processing
forward_vectors = source.MVAnalyse(isb = false, truemotion=true, delta = 1, idx = 1)
forward_compensation = source.MVFlow(forward_vectors, idx=1, thSCD1=500) # or use MVCompensate
backward_compensation = source.MVFlow(backward_vectors, idx=1, thSCD1=500) # or use MVCompensate
# create interleaved 3 frames sequences
interleave(forward_compensation, source, backward_compensation)
DeGrainMedian() # place your preferred temporal (spatial-temporal) denoiser here
return selectevery(3,1) # return filtered central (not-compensated) frames only

Didée
19th February 2007, 13:33
But now I look at it... It seems to me that I'm doing MVAnalyse on source and leaving notes in idx1. Then I'm using part of the analysis to create the deblocked source2 with MaskTools (which I don't understand at all, that's for next weekend). Then I do MVDegrain on source2 using the notes from source that was stored in idx1. If source2 has the same motion as source (it's a deblocked version), would this be OK?

Practical answer: Try this:

source = last
source2 = source.flipvertical()

backward_vec2 = source.MVAnalyse(isb = true, delta = 2, pel = 2, overlap=4, sharp=1, idx = 1)
backward_vec1 = source.MVAnalyse(isb = true, delta = 1, pel = 2, overlap=4, sharp=1, idx = 1)
forward_vec1 = source.MVAnalyse(isb = false, delta = 1, pel = 2, overlap=4, sharp=1, idx = 1)
forward_vec2 = source.MVAnalyse(isb = false, delta = 2, pel = 2, overlap=4, sharp=1, idx = 1)

source2.MVDegrain2(backward_vec1,forward_vec1,backward_vec2,forward_vec2,thSAD=400,idx=1)

This should convince you that something is fishy when not using idx as I told. ;)

*.mp4 guy
19th February 2007, 13:35
Didée, I made that script, so It should be me you blame, not Morte66. Secondly you are right about idx, I know what it does, but it must have slipped past me =/. Which means that the processed source isn't doing anything in particular, which would go against the test results I got, I'll have to see whats going on.

Morte66
19th February 2007, 13:40
Practical answer: Try this:

source = last
source2 = source.flipvertical()

backward_vec2 = source.MVAnalyse(isb = true, delta = 2, pel = 2, overlap=4, sharp=1, idx = 1)
backward_vec1 = source.MVAnalyse(isb = true, delta = 1, pel = 2, overlap=4, sharp=1, idx = 1)
forward_vec1 = source.MVAnalyse(isb = false, delta = 1, pel = 2, overlap=4, sharp=1, idx = 1)
forward_vec2 = source.MVAnalyse(isb = false, delta = 2, pel = 2, overlap=4, sharp=1, idx = 1)

source2.MVDegrain2(backward_vec1,forward_vec1,backward_vec2,forward_vec2,thSAD=400,idx=1)

This should convince you that something is fishy when not using idx as I told. ;)

Now I would expect that to fail, because you've done a FlipVertical rather than a deblocking. Of course source2 would have different motion from source in that case, and using the same motion vector analysis would be a disaster.

Whereas it seems that it might work if source2 is a deblocked version of source, with the same content motion.

I think what I need to do is compare is the original script against something like this...
#deblock
mask_source = last
mask_forward_vec1 = mask_source.MVAnalyse(isb = false, delta = 1, pel = 2, overlap=4, sharp=2, idx = 1, truemotion=true)
mask = mvmask(kind=1, vectors=mask_forward_vec1).UtoY().spline36resize(720,576)
mask_smooth = mask_source.degrainmedian(mode=3).fft3dfilter(bt=3, sigma=4, plane=0)
maskedmerge(mask_source, mask_smooth, mask)

#completely separate degrain
source = last
backward_vec2 = source.MVAnalyse(isb = true, delta = 2, pel = 2, overlap=4, sharp=2, idx = 2, truemotion=true)
backward_vec1 = source.MVAnalyse(isb = true, delta = 1, pel = 2, overlap=4, sharp=2, idx = 2, truemotion=true)
forward_vec1 = source.MVAnalyse(isb = false, delta = 1, pel = 2, overlap=4, sharp=2, idx = 2, truemotion=true)
forward_vec2 = source.MVAnalyse(isb = false, delta = 2, pel = 2, overlap=4, sharp=2, idx = 2, truemotion=true)
source.MVDegrain2(backward_vec1,forward_vec1,backward_vec2,forward_vec2,thSAD=400,idx=2)

Didée
19th February 2007, 13:50
I just wanted to make clear that with wrong idx usage like

green = something
red = green.process(make_reddish)

vectors1/2/3/4 = green.MVanalyze(...,pel=2,idx=1)

result = red.MVDegrain2(vectors1/2/3/4, idx=1) # idx=1 is incorrect

you end up with a mix of (1*green + 4*red)/5

In your case, you would've created a deblocked clip, and get a mix of 20% deblocked and 80% not-deblocked.

It might not look obviously borked, but it *is* wrong. My radical example shows what's *really* happening then.

Morte66
19th February 2007, 15:40
I just wanted to make clear that with wrong idx usage like

green = something
red = green.process(make_reddish)

vectors1/2/3/4 = green.MVanalyze(...,pel=2,idx=1)

result = red.MVDegrain2(vectors1/2/3/4, idx=1) # idx=1 is incorrect

you end up with a mix of (1*green + 4*red)/5

In your case, you would've created a deblocked clip, and get a mix of 20% deblocked and 80% not-deblocked.

It might not look obviously borked, but it *is* wrong. My radical example shows what's *really* happening then.

Ha, got it. I need a smiley for "lightbulb over head". This one will have to do...

:thanks:

Morte66
19th February 2007, 19:07
After a few more comparisons, I think that the thing I like best about MVDegrain2 us the way it reduces block/macroblick-sized flickery stuff in mpeg2.[1] It has worked wonders for my "Northern Exposure" DVDs.

I wondered whether this is becaue it has a longer timebase (five frames) than most denoisers I use (fft3d, DegrainMedian, FrFun). So I tried an experiment, using MVAnalyse/MVFlow to wrap fft3dgpu, which can be used at 2/3/4 frame durations. Example:
source=last
forward_vectors = source.MVAnalyse(isb = false, truemotion=true, overlap=4, delta = 1, idx = 3)
backward_vectors = source.MVAnalyse(isb = true, truemotion=true, overlap=4, delta = 1, idx = 3)
backward_vectors2 = source.MVAnalyse(isb = true, truemotion=true, overlap=4, delta = 2, idx = 3)
forward_compensation = source.MVFlow(forward_vectors, idx=3, thSCD1=500) # or use MVCompensate
backward_compensation = source.MVFlow(backward_vectors, idx=3, thSCD1=500) # or use MVCompensate
backward_compensation2 = source.MVFlow(backward_vectors2, idx=3, thSCD1=500) # or use MVCompensate
interleave(forward_compensation, source, backward_compensation,backward_compensation2)
fft3dgpu(bw=16, bh=16, bt=4, sigma=1, plane=4, precision=1)
selectevery(4,1) # return filtered original (not-compensated) frames only
As the timebase gets longer, I see a small reduction in the random-looking noise (the short filter pretty much killed it), plus a progressive reduction in flicker. It also seems that DegrainMedian and fft3d are less prone to occasional blocking than MVDegrain1/2 if you don't use Overlap, which keeps the speed up.

Since flickery stuff really gets on my nerves, this is great news.

I'd like to try motion compensating a longer (spatial-)temporal denoiser. The only one I'm familiar with is FluxSmooth(S)T. Does anybody have any other favourites I ought to try?

{edit p.s. mocomped fft3dgpu is gorgeous, and slow but not impossibly slow}

--
[1] Not the same as purely oscillatory noise from analogue video tape, e.g. "Roseanne", which I think is better tackled with ReduceFlicker(Strength=1).

*.mp4 guy
19th February 2007, 19:53
try ttempsmooth(maxr=7), its pure temporal, but it takes 15 frames into account(maxr=7==max temporal radius of 7). Its very good at avoiding averaging in moving areas, so it should be artifact resistent.

Pookie
20th February 2007, 02:23
Morte66 - my eyes are sensitive to certain types of flicker as well. Kasandro's Reducefluctuations(limit=2) from his ReduceFlicker plugin is pretty good. Just don't go beyond limit=2 otherwise it can create artifacts.

fluxsmooth seems to calm things down as well, especially on deinterlaced video.

*.mp4 guy - thanks for the info. I'll try that out soon :)

grannyGeek
20th February 2007, 05:45
I would love to try out ReduceFlicker, but the links I found from searching seem to be broken

http://www.reduceflicker.de.tf/
http://home.arcor.de/kassandro/ReduceFlicker/ReduceFlicker.htm


Maybe they are obsolete.

Does anyone have a working link, or can upload a copy somewhere?

Thanks for any help.

BigDid
20th February 2007, 06:05
I would love to try out ReduceFlicker, but the links I found from searching seem to be broken

http://www.reduceflicker.de.tf/
http://home.arcor.de/kassandro/ReduceFlicker/ReduceFlicker.htm

...
Hi,

Both links are working, I downloaded from: http://home.arcor.de/kassandro/ReduceFlicker/ReduceFlicker.zip

Did

grannyGeek
20th February 2007, 06:18
well, crummy buttons!

I just get "operation timed out" after numerous attempts.

Maybe our server / firewall has me blocked from that site.

Pookie
20th February 2007, 07:40
Mirror http://www.bestsharing.com/files/kp0mSq228693/ReduceFlicker.zip.html

grannyGeek
20th February 2007, 08:37
THANK YOU POOKIE !

Blessings on you.

Morte66
20th February 2007, 17:36
try ttempsmooth(maxr=7), its pure temporal, but it takes 15 frames into account(maxr=7==max temporal radius of 7). Its very good at avoiding averaging in moving areas, so it should be artifact resistent.

That looks very stable at maxr 5-7, and it's certainly artifact resistant (no problems mo-comping it without overlap). But unfortunately it's a bit too slow for bulk DVD backup. I'm aiming for 5fps and it runs about 1.5 to 3fps at those lengths.

It does look quite useful for special cases.

[Mocomped fft3d at 4 frames is nailing enough flicker to stop it bothering me most of the time, at about 3.5fps.]

Morte66
20th February 2007, 17:40
Morte66 - my eyes are sensitive to certain types of flicker as well. Kasandro's Reducefluctuations(limit=2) from his ReduceFlicker plugin is pretty good. Just don't go beyond limit=2 otherwise it can create artifacts.

That seems to be somewhat redundant with fft3d, at least for controlling the sort of flicker that bothers me. I'll keep it in mind, though, and thanks for the hint.

BigDid
20th February 2007, 18:05
That seems to be somewhat redundant with fft3d, at least for controlling the sort of flicker that bothers me. I'll keep it in mind, though, and thanks for the hint.
Hi,

Actually trying on Blade runner with:
Reducefluctuations(limit=2).fft3dfilter(sigma=1.3, plane=4).limitedsharpenfaster(Smode=3, strength=60, soft=-1)
Seems better before fft3d, great job

Also tried after frfun for comparison: mt("frfun7(1,2.6,1)").mt("Reducefluctuations(limit=2)").mt("limitedsharpenfaster(Smode=3, strength=60, soft=-1)")
Seems better after, even better for frfun :)
But with so high settings, frfun is no match for fft3d.

I still have a major challenge: Point break but I'm afraid I'll have to do it with the script Removehighnoisemc() mixed with fft3d with applyrange (which I never used and I don't master :o )

Did