View Full Version : New filter - DeGrainMedian for grain removal
Fizick
13th August 2004, 16:45
Almost all filter-writers had wrote at least one denoiser.
Now i also did it.
DeGrainMedian - Spatio-Temporal Limited Median filter for grain removal
Plugin for Avisynth 2.5
Version 0.1 - August 13, 2004
DeGrainMedian plugin is mainly for film grain removal, but may be used for general denoising.
It uses some spatio-temporal limited median method.
The plugin is mostly based on two ideas, used at two stages of processing.
The first idea is from STMedianFilter plugin by Tom Barry -
I also use part of its great optimized code.
Shortly it is 3D cube, and 13 opposite pairs.(see doc)
STMedianFilter at second stage don't filter pixel if it would change it more than some threshold.
(More correctly, it firstly makes temporal detecting and thresholding,
with following spatial detecting and thresholding)
The most denoisers also do not filter pixels with big noise (big luma differences).
But both such single pixels are very visible on flat smoothed regions,
and group of them forms very annoying edge artifacts.
Moreover, pure temporal denoisers often produce ghosting even for not very big thresholds.
DeGrainMedian at this second stage uses other (different) method of pixel processing.
Here I use second idea, borrowed from Dust plugin by Steady. See part of Dust doc here:
"Limit=5
Sets the strength of the temporal filtering. (How much it can change the
original pixel)." (The end of Steady citation).
So, if filtered pixel would be changed more than some threshold (limit), it will NOT be restored to original in DeGrainMedian,
but will be changed by LIMITED value.
(separately for Luma and Chroma)
DeGrainMedian plugin filters ALL pixels, but with limited strength.
Therefore, all grain and strikes are (fully or partially) smoothed.
Filter almost don't produce edge artifacts.
Ghosting is also minimal, since it is automatically switched to spatial smoothing as more nearest pair by values.
So, DeGrainMedian have a speed of STMedianFilter (true) and strength of Dust (true by limit value :)!
It is almost not joke :devil:
What is bad, really?
1. Some blurring (you want denoising without it ? :) .
2. It can not produce flat fully smooth picture, some noise always remains (you like oversmoothed and blocked clips ?) .
3. Motion compensation is limited to 1 pixel value (of course, it is NOT Dust, but what about external motion compensation ?).
Seriously, it is not super filter and still experimental, but for my noisy grainy films it makes quite good results.
Firstly I developed it as prefilter (to Vaguedenoiser etc), but it seems now, that sometimes it can be used alone...
Probably, it can help somebody else. That is why I release it.
http://bag.hotmail.ru
Didée
14th August 2004, 15:45
Well, I haven't tested it yet, but after reading the docs I can say that I like the concept. :)
Some additional scenechange protection would be nice. Although there won't occur major blending artefacts on changes, thanks to the limited temporal processing, some noticeable artefacting may come up when relatively big thresholds are used.
Thanks for sharing this, Fizick.
- Didée
Fizick
14th August 2004, 18:15
Some additional scenechange protection would be nice
and may be added later if "concept" will well not only in docs, but in real tests. :)
I wait its, welcome.
krieger2005
18th August 2004, 10:37
Hi,
i've done some tests on a VHS-Capture with dot-crawls. While your filter makes with high thresholds the picture little smooth i used a mask only to use it for edges. The result was the removing of dot-crawls (wibbling edges). I don't look enoght at different results at the moment, i mean what does the filter done when there was motion or in still images... As long as i remember the picture get smooth in motion...
A second try was on a use on a DVD-source, which was compressed littlebit to hard, so the deinterlacing produce some artifacts (with KerneDeInt, still with high thresholds). Here i used low thresholds of your filter and deinterlace then. The Result was a clean image.
So for now i think, this is right good and should be developed... for example to get a "interlaced"-flag ;). I will try it even more..
Thanks for your work
Fizick
18th August 2004, 18:13
Krieger2005,
Thanks for test report.
I think about "interlaced" flag.
But seems it works without it somehow :confused:
But firstly I must fix one bug.
For spatial part of YV12 mode smoothing, the neibours distance form central pixel was 2 pixels instead of 1.
New version 0.1.1 is released.
numlock
19th August 2004, 00:20
Will this filter work with interlaced sources also ? Or is this only for progressive ?
krieger2005
19th August 2004, 07:47
Will this filter work with interlaced sources also ? Or is this only for progressive
So for now i think, this is right good and should be developed... for example to get a "interlaced"-flag .
So for now it has no interlaced flag and should used with
mpeg2source(...)
SeparateFields
Interleave(SelectEven.DeGrainMedian, SelectOdd.DeGrainMedian)
Weave
Serg Belyansky
20th August 2004, 08:58
I should say that judging on fine-but-contrasty grain removal this filter is the best of all I tried. Its effect reminds me he effect of high-end DVNR devices I've seen at TV-stations recently.
Also I can't see any need for scene change detection: with parameters set at (7, 10) there are positively _no_ scene change artifacts.
(BTW, thank you for DeSpot filter. Too bad E-Gold still refuses my payments :angry: )
Yuri
20th August 2004, 21:32
Fully agree with Serg Belyansky.
With my DVD content it worked a miracle. Blurring is not as strong as Dust's. With film content it was teamed with removedirt and that time both of them worked a miracle! Thanks for great filters.
Fizick
20th August 2004, 22:12
Serg Belyansky,
Yes, scenechange detection is not very needed, since the filter is adaptively switched to spatial part.
Yes, most other filters do no remove contrast grain.
Yuri,
Thanks for test report and warm words!
But somebody (i4004) notes some oversmoothing.
I too. Anybody else? :)
Probably I can add more safe (but not so effective) mode in new version soon.
Fizick
21st August 2004, 20:52
New version 0.2 released.
Since version 0.2, I add to DeGrainMedian also some other more safe operation modes 1-4 (code borrowed from RemoveGrain plugin by Kassandro).
We consider the same 3x3x3 cube.
New pixel candidate value (newp) is clipped by values of neighbor pixels from pair (bound1 and bound2).
But mode1-mode4 use more safe criterion (weight) of optimal pixel pair,
We take into account also the difference of new value from central pixel old value (oldp) .
Mode=0 of DeGrainMedian (similar to mode=9 of RemoveGrain) uses weight=|bound1 -bound2|, it is strongest (used in v.0.1).
Mode=1 of DeGrainMedian (similar to mode=8 of RemoveGrain) uses weight=|oldp - newp|+2* |bound1 - bound2|
Mode=2 of DeGrainMedian (similar to mode=7 of RemoveGrain) uses weight=|oldp - newp|+ |bound1 - bound2|
Mode=3 of DeGrainMedian (similar to mode=6 of RemoveGrain) uses weight=2*|oldp - newp|+ |bound1 - bound2|
Mode=4 of DeGrainMedian (similar to mode=5 of RemoveGrain) uses weight=|oldp - newp|, it is weakest.
Set mode parameter to bigger value if you found picture as oversmoothed (try!).
The more mode number, the bigger limit values is safe.
It seems, that mode=1 (now default) is good compromise, but it is dependent from source.
With mode=4, the result changes are invisible, but some of "hot" pixels are removed.
Try, and please post test reports.
Serg Belyansky
26th August 2004, 12:14
Mode=1 is the best default indeed. Though I think that i will use Mode=0 from time to time, since it removes very-high-contrast grain somewhat better.
Mug Funky
27th August 2004, 16:44
fizick: bravo, man. this denoiser is very cool indeed.
i always liked removedirt, but am prevented from using it for real-world situations, because of a nasty problem it has with "earthquake" style shaking, like you find in almost all anime at some point.
degrainmedian gives similar results but doesn't "remove" large sections of the frame in juddering motion. :)
i've only used it at default settings, so i'll see what i think of it after some experimentation (i'm working on converting Eva platinum edition to PAL. i never got a good look at the old eva, but considering that the "renewal" edition was seen as a dramatic improvement, the originals must have been complete crap, because the new ones are pretty awful too.)
Fizick
27th August 2004, 22:06
Yes, it is "cool" - it removes "hot" pixels :)
BTW, for numlock et al, I release "interlaced" version 0.3 today.
Soulhunter
28th August 2004, 00:46
Finally I found some time to do a quick test with this filter !!!
First conclusion...
Its very fast (14fps -> 12fps) !!!
It drops the filesize 5-10 % (regular movie) without blurring too much... :)
Bye
Yuri
28th August 2004, 10:58
Fizick,
great filter!
Are you planning to incorporate despot/descratch features into degrain? That would be splendid if you did!
Thanks and regards.
Fizick
28th August 2004, 19:48
incorporate despot/descratch features into degrain? :confused:
Yuri
28th August 2004, 20:26
To simplify the script chain: despot-descratch-degrain ...
Fizick
29th August 2004, 20:43
No.
Fizick
12th September 2004, 20:29
I release version 0.4, September 10, 2004 - Fixed possible bug with different frame pitches (prev, current, next).
Quite exotic, but possible case.
I forget to note this limitation of previous versions.
kassandro
12th September 2004, 22:21
Fizick,
I just made a look at your solution of the non-constant pitch problem. It is fairly optimal, i.e. bitblts are minimised, but instead of malloc you should use alloca. Executing malloc 100000 times you risk that heap fragmentation may exhaust memory. Use alloca instead. alloca simply allocates the memory on the stack and automaticly releases it, when you leave the stack frame of the function, where it was allocated.
Fizick
13th September 2004, 18:23
Kassandro,
I think my solution is better.
1. The stack size is limited.
2. Why do you think that all 100000 frames have different pitches?
kassandro
13th September 2004, 20:55
Originally posted by Fizick
Kassandro,
I think my solution is better.
1. The stack size is limited.
2. Why do you think that all 100000 frames have different pitches?
Fizick,
take a 720x576 with 100000 frames and execute the following somewhat bizarre script:
MPEG2Source("input.d2v")
cropped=crop(128,0,0,0) # the luma pitch is 720
even=selecteven(cropped).undot() # the resulting pitch is 720 - 128
odd=selectodd(cropped)
interleave(even, odd) # the pitch alternates between 592 and 720
if you do so, the pitch will alternate all the time and all in all malloc/free will be called 200000 times by your most recent DeGrainMedian. That should not happen in a good program. Now the malloc chunks alternate between two sizes. When I tried the above script it did execute correctly without heap fragmentation. But if the situation gets more complicated it may happen.
Now alloca - unlike malloc - is fast and simple. Essentially only the size of the memory chunk is subtracted from the stack register, which is restored to its value before the function call, when you leave the function. The problem is that the stack is very limited, though 800 kb should not be a problem at all. I really don't understand why the stack is limited. If the stack is exceeded and a page fault happens the system system should simply supply new real memory to enlarge the stack.
Fizick
13th September 2004, 21:00
But it is limited.
And why you do not consider resizing to 4096x4096 ? ;)
kassandro
13th September 2004, 21:14
Originally posted by Fizick
But it is limited.
And why you do not consider resizing to 4096x4096 ? ;)
One should try it, to see what happens.
The heap after all is also limited by virtual memory.
Leak
13th September 2004, 22:36
Originally posted by kassandro
if you do so, the pitch will alternate all the time and all in all malloc/free will be called 200000 times by your most recent DeGrainMedian.
Why not just keep the last used buffer around instead of freeing it and only replace it if it's too small? Or free it only after it hasn't been used for a number of frames...
np: Funki Porcini - King Ashabanapal (Parts In The Post (Disc 2))
kassandro
14th September 2004, 05:40
Originally posted by Leak
Why not just keep the last used buffer around instead of freeing it and only replace it if it's too small? Or free it only after it hasn't been used for a number of frames...
The problem with this solution is, that the size of the buffer depends on the pitch of the frame in the middle and in theory this pitch may change from frame to frame. If it gets bigger, the old buffer is simply too small and you have to reallocate. On the other hand, you don't want to spend too much time with this kind of problem, because in practice it virtually never happens.
Leak
14th September 2004, 09:41
Originally posted by kassandro
The problem with this solution is, that the size of the buffer depends on the pitch of the frame in the middle and in theory this pitch may change from frame to frame. If it gets bigger, the old buffer is simply too small and you have to reallocate. On the other hand, you don't want to spend too much time with this kind of problem, because in practice it virtually never happens.
That was what I meant, just keep the buffer around and only re-allocate it when it's too small - unless you have a video where the pitch grows with every frame (which seems rather unlikely to me) you'll just re-allocate a few times throughout the video and not on every frame as in the worst-case scenario you mentioned before...
np: Lali Puna - Middle Curse (Scary World Theory)
SpikeSpiegel
14th September 2004, 12:54
Great work, Fizick!
Anyway I wanna make a few considerations:
-Usually, the only way to clean correctly (with no artifacts risk) low-motion areas is to use a spatial smoother (or a spatio-temporal denoiser in this case), but, this way, blurring is inevitable.
-Temporal filters can easily erase (almost) all noise in static areas with no definition lost, but they behave randomly with motion ones (especially when the chroma difference between details is really low).
I noticed that, using DeGrainMedian, "mode2" is the best compromise between blurring and definition (IMHO, mode1 is too aggressive), but, this way, the filter can't remove enough noise in static areas, omnipresent in DVD stuff.
That's why I'd like to suggest this combination:
DeGrainMedian with mode2/3
+
RemoveDirt with low mthreshold (<40 should be fine), to let it work only on static areas
I did a few tests and results seem very good!
Fizick
14th September 2004, 17:06
SpikeSpiegel,
You of course must select the most appropriate filters and parameters combination for your source.
BTW, you also may try to use several DeGrainMedians with sililar of different parameters:
DeGrainMedian(4).DeGrainMedian(3)
:)
or
DeGrainMedian().DeGrainMedian().DeGrainMedian().DeGrainMedian()
:D
SpikeSpiegel
14th September 2004, 18:37
Originally posted by Fizick
SpikeSpiegel,
You of course must select the most appropriate filters and parameters combination for your source.
BTW, you also may try to use several DeGrainMedians with sililar of different parameters:
Sure, anyway I'm not saying that this is an universal solution, but, in this case (I forgot to write that it should be used with hi/medium-quality-DVD-source, xcuse me), considering how the two filters work, it could be the best way to get a good cleaning (and a better compressibility) without compromising too much definition.
This is because I think that it's (almost) impossible to get total adaptiveness (for each "variable", like motion and color characteristics, in the same frame) with only one filter&setting (even if DeGrainMedian's pretty close :) ), so the better way should be to use different filters only in the "situation" (frames and part of frame) where they work better.
Anyway, it seems that for every other purpose (4example cartoons), there's no need of anything else! ;)
Fizick
14th September 2004, 20:33
SpikeSpiegel,
You also may try TTempSmooth temporal filter by Tritical.
It is qute good (for classical pure temporal), since it can uses 5-7 frames.
SpikeSpiegel
16th September 2004, 13:29
Originally posted by Fizick
SpikeSpiegel,
You also may try TTempSmooth temporal filter by Tritical.
It is qute good (for classical pure temporal), since it can uses 5-7 frames.
Thanks for the tip!
I was searching for a precise temp. filter with no mod8-resolution limitation (unlike RemoveDirt), so it may be really useful!
Fizick
10th October 2004, 14:50
BTW, I realy have got good result for VHS with this double without other denoisers:
degrainmedian(mode=1,limity=8,limituv=8,interlaced=true)
degrainmedian(mode=0,limity=4,limituv=4,interlaced=true)
HighInBC
16th October 2004, 17:32
This is a great filter, but would it be possible to have a variable radius on the median blur? so that I can have a far more pronounced effect. This of course would make a video look very blurred, but it would be perfect for alpha masks
Fizick
16th October 2004, 20:36
Do you understand, that DegrainMedian is not spatial, but spatial-temporal denoiser? ;)
HighInBC
16th October 2004, 21:36
Oh, well I would give my left eyebrow for a purely spacial, variable radius median filter
Fizick
23rd March 2005, 20:34
New Version 0.5, March 23, 2005 - Use more correct cache settings. Thank to Turyst04 for stablity problem report.
There was some problem of v.0.4 with my GetDups plugin.
Setmemorymax(128) help a little, but...
I did not use cache settings.
Now I use CACHE_RANGE=2.
I really wonder, in what case we must use CACHE_RANGE=1 ?
kassandro
24th March 2005, 21:15
Originally posted by HighInBC
Oh, well I would give my left eyebrow for a purely spacial, variable radius median filter
My RemoveGrain filter is purely spatial, has many more modes and is a lot faster, especially if you have a SSE3 capable CPU. However, as DeGrainMedian it is radius 1 only anf there are very good reason for it. The execution would explode quadraticly with the radius and there are other implementation specific issues. It is faster (execution time increases only linearlily) to iterate these filters and the effect is very similar. For instance radius=4 is similar to a fourfold iteration of these filters.
Originally posted by Fizick
Now I use CACHE_RANGE=2.
I really wonder, in what case we must use CACHE_RANGE=1 ?
CACHE_RANGE=1 is always bad, because you use the previous and the subsequent frame and there difference is simply 2 and not 1. If you would use CACHE_RANGE=1, then each input frame is processed twice. If you would use CACHE_RANGE=0, then each input frame would be processed processed even three times. CACHE_RANGE=1 would be sufficient if you use only the previous or the subsequent frame but not both. Of course, the speed gain, which you will achieve with CACHE_RANGE=2 heavily depends on the speed of the filter immediately before DeGrainMedian.
tsp
24th March 2005, 21:27
My RemoveGrain filter is purely spatial, has many more modes and is a lot faster, especially if you have a SSE3 capable CPU. However, as DeGrainMedian it is radius 1 only anf there are very good reason for it. The execution would explode quadraticly with the radius and there are other implementation specific issues. It is faster (execution time increases only linearlily) to iterate these filters and the effect is very similar. For instance radius=4 is similar to a fourfold iteration of these filters.
http://forum.doom9.org/showthread.php?s=&threadid=84636
Although this filter was first created a couple of weeks after HighInBC requested it and it's not that slow because the speed only decreases linearly with radius (using the same principle as bucket sort). This algorithm doesn't work with MMX so for the small radius a batcher sort is used (with increases n*(log2(n))^2).
Fizick
24th March 2005, 22:27
Is CACHE_RANGE directional (forward, backward)?
or it is a radius from current frame?
or it is a simply counter (limit) of cached frames?
kassandro
25th March 2005, 00:11
Originally posted by Fizick
Is CACHE_RANGE directional (forward, backward)?
or it is a radius from current frame?
or it is a simply counter (limit) of cached frames?
Last time, when I studied the Avisynth source code, it was a radius from the last processed (not necessarily the current, i.e. last requested) frame. Meanwhile the Avisynth cache seems to have undergone substantial changes. As this subject is quite important for filter writers to achieve maximal performance without wasting memory, it should be better documented.
Fizick
25th March 2005, 05:28
kassandro,
thanks for respond.
Yes, it would be nice. Now i try change radius and look to memory usage, speed, faults, etc.
AVIL
1st April 2005, 21:56
Hi:
By suggestion of Ficik i continue here the trhead :
http://forum.doom9.org/showthread.php?s=&threadid=92327
AVIL
1st April 2005, 22:05
Hi:
Sorry for my inexperience, i can't post the attachement. I pick the file ( extension jpg, size 103 kb ) whith the button "Examinar" (in spanish). The name of the file appears in the window but, alas, no attachement is made. Surely i'm doing anything erroneus.
Help please.
Soulhunter
1st April 2005, 22:08
Originally posted by AVIL
Sorry for my inexperience, i can't post the attachement. I pick the file ( extension jpg, size 103 kb ) whith the button "Examinar" (in spanish). The name of the file appears in the window but, alas, no attachement is made. Surely i'm doing anything erroneus.
Help please.
Just upload ya pic here... (http://imageshack.us/) ;)
Bye
AVIL
1st April 2005, 22:21
Tanks Soulhunter, you have saved one soul (the mine).
This is the image (click to enlarge):
http://img93.exs.cx/img93/4748/degrainmedian9xs.th.jpg (http://img93.exs.cx/my.php?loc=img93&image=degrainmedian9xs.jpg)
The first part is the image as is, the second part is the difference ( luma only ) after apply degrainmedian(mode=1,limituv=0) in YUY2 and done posterior conversion to YV12. The third part is the difference after degrainmedian(mode=1,limituv=0) directly in YV12. I have expected the same luma difference ( or very approximate ).
Ouch, post a problem is near as difficult as doing complex scripts.
Fizick
2nd April 2005, 18:27
New Version 0.6, April 2, 2005 - fixed some bugs with YUY2. Thanks to AVIL for report.
But I am stil can not get STRICTLY same output foe YUY2 as YV12.:confused:
Ouch, fix bugs problem is near as difficult as doing complex scripts.
Guest
3rd April 2005, 20:11
Re: Attachments.
There is a delay because the mod has to approve them and we don't check every 10 minutes for pending ones. :)
So my personal policy is that I welcome a PM from you when making an attachment to notify me that it is pending.
Thank you for your interesting contributions to the forum.
JuanC
16th April 2005, 07:45
@Fizick: I've been using this filter lately, I like it a lot, but I have just noticed that my interlaced clips are getting encoded with the field dominance reversed: They are originaly TFF, but just after using DeGrainMedian (interlaced=true) they become BFF :confused: Is there anything I am missing ?
My clips are originally mpeg2 video clips (using dgdecode) either 352x480 or 720x480 (NTSC, 29.97 fps). My scripts are very simple, something like the following will be enough to reproduce the situation I am describing:DGdecode_mpeg2source("Paulita-mpeg2-corta.d2v")
#Return AssumeTFF().SeparateFields()
Return DeGrainMedian(interlaced=true,mode=2).AssumeTFF().SeparateFields() Then I encode them to mpeg2 interlaced.
Thanks for your comments (and the filters ;) )
Boulder
16th April 2005, 11:09
The filter could use AssumeFieldBased or similar internally. Avisynth defaults to BFF so that might be the cause.
JuanC
18th April 2005, 03:17
Thanks for your comment Boulder, more info: Avisynth correctly identifies the original video clip as Not FieldBased (Not Separated), TFF. After the filter is applied, Avisynth still believes the video clip is TFF, when in fact it's now BFF. Meanwhile, I am using this filter like this: limpiar=AssumeTFF().SeparateFields()
E=selectEven(limpiar).DeGrainMedian(interlaced=false,mode=2)
O= selectOdd(limpiar).DeGrainMedian(interlaced=false,mode=2)
Interleave(E,O) .Weave() Now I still get the video clip TFF after applying the filter.
Turyst04
18th April 2005, 17:00
JuanC
Meanwhile, I am using this filter like this: limpiar=AssumeTFF().SeparateFields()
E=selectEven(limpiar).DeGrainMedian(interlaced=false,mode=2)
O= selectOdd(limpiar).DeGrainMedian(interlaced=false,mode=2)
Interleave(E,O) .Weave() Now I still get the video clip TFF after applying the filter.
I now try use doom9 forum only (and my english is bad - sorry).
Anyway: JuanC, your avs is correct.
May be next script is suitable (if use more then 1 filters):
function ApplyInterlacedFilter(clip v1, string filter) {
v2 = separatefields(v1)
selecteven(v2)
even = Eval(filter)
selectodd(v2)
odd = Eval(filter)
interleave(even,odd)
return weave()
}
i=last
mdata=Depanestimate(i)
depaninterleave(i,data=mdata, prev=1, next=1, matchfields=true)
applyinterlacedfilter(last, "DeGrainMedian(interlaced=false,mode=2)")
applyinterlacedfilter(last, "fft3dfilter(sigma=3,bt=3)")
selectevery(3,1)
(depaninterleave using is recommended by Fizick and result is better)
Fizick
19th April 2005, 21:52
JuanC,
after SeparateFields interlaced clip become progressive.
So, you must use (interlaced=false).
But why do you not use the simplest script ?:
DGdecode_mpeg2source("Paulita-mpeg2-corta.d2v")
AssumeTFF()
DeGrainMedian(interlaced=true,mode=2)
Does this script reverse the fields dominance ? :confused:
JuanC
20th April 2005, 06:02
Originally posted by Fizick
Does this script reverse the fields dominance ? :confused: Yes it does.
Fizick
20th April 2005, 22:04
JuanC,
I found a bug for mode=2 YV12 interlaced,
and release new version 0.7 today.
Personally I prefer mode=0,1. and never used mode=2.
I can not reproduce the reverse of fields dominance.
What about other modes and colorspace YUY2?
How you detect it?
JuanC
21st April 2005, 06:43
Originally posted by Fizick
I found a bug for mode=2 YV12 interlaced,
and release new version 0.7 today. Thanks!, I'll try this.Originally posted by Fizick
I can not reproduce the reverse of fields dominance.
How you detect it? To detect it I use the technique described by D.Graft and included in the Decomb_Tutorial.html file in the Step 1 of Telecide Section: "Determine and Set the Field Order": Use this in your script: Return AssumeTFF().SeparateFields() And by playing it (Vdub) review if the movement is always fluid, then it is TFF, if the movement is back&forth... Then it is not TFF, you could then use AssumeBFF and verify the same way. Also, if you don't IVTC neither Deinterlace, you encode your video interlaced, you'll see using any player very strange artifacts (back&forth!!!)Originally posted by Fizick
What about other modes and colorspace YUY2? I haven't tried that yet. But I would next weekend.
LordIntruder
20th May 2005, 05:47
Hi,
Can someone enlighten me about the 'mode' option? I mean is mode=0 will clean less grain or not than mode=4 ? In the doc it is said:
"mode (0 to 4, default=1) - operation mode (the more, the weaker)"
The more (4 per exemple) the weaker. The weaker what? The image quality is cleaned more but also looks worse?
And a important thing: I have an interlaced PAL source. In my AVS I deinterlaced it with decomb. Must I integrate the option 'interlaced'?
FieldDeinterlace()
DeGrainMedian(interlaced=true, mode=0)
??
I think not because before I deinterlace my source so I guess this option is not needed but an advice won't be too much. ;)
Thanks. :)
Fizick
20th May 2005, 20:30
LordIntruder,
1. The more mode number, the weaker the degree of denoising.
If someboby can say this in good English, please post.
2. Yes, use:
interlaced=false
3. Use your own eyes to test :rolleyes:
LordIntruder
21st May 2005, 03:33
Fizick: thanks.
I'll try mode=0 and mode=4 to see the differences. I asked because I've just tried your filter last night for the first time and was a bit lost with technical explanations. Now I have to modify parameters and see what changes in the video.
And thanks to confirm for 'interlaced' option. :)
LordIntruder
21st May 2005, 23:31
Ok so to confirm after some tests
mode=0 --> removes a lot of grain
mode=4 --> removes only a little grain
Even in mode=0, the more aggressive, details are still well preserved.
Thanks for your work on all those filters. :)
Poutnik
31st May 2005, 15:34
DegrainMedian and STMedianFilter relation - I am little confused:
AFA I understand, the main result difference is limiting - not disabling - change, if pixel is to be changed too much.
Both ones have limits/thresholds for Y and UV change - treated differently.
But STMF has spatial edge threshold and temporal scene change one.
Should I consider DGM as "more clever", having those detections
build in ?
Or maybe these are controlled indirectly by other approach
- by choosing mode number ( I understand mode differences ) ?
Beave
13th July 2005, 00:34
I just stumbled across this filter. I must say I'm really impressed by the results. I used mode=0 on very noisy HDTV source and it was almost as good in removing the grain as Pixiedust, but much faster.
Compressebility:
Original: 34% / 8:23
DeGrainMedian(mode=0):50% / 9:44
Pixiedust(): 53% / 16:44
Pixiedust(8): 56% / 16:58
Visually both the filters are very close I must say. DeGrainMedian leaves the pictiure very sharp and removes a good portion of the grain. Pixiedust produces wierd black or white lines in some parts of the image. I will definatly rather use DeGrainMedian in the future.
I still can't decide how to pair this filter. RemoveGrain(mode=2) is not bad, but removes more fine details. On the website it is mentioned that one should try to put a motion compensation filter after this one. Which filter of MVTools should I try here? Does DePan work better in combination?
Chainmax
13th July 2005, 03:45
First, try mode=5 instead of mode=2. According to Boulder, mode=5 removes almost as much noise as mode=2 whithout softening the picture that much.
I remember that some time ago, scharfis_brain recommended to use depaninterleave (from the DePan package) for improved results on heavy denoising. I bet you have to use the DepanInterleave commands before the denoising steps.
I would recommend you to try LRemoveDust_YV12(17,x) with x being the denoising strength (I suggest you start by "2"), then follow that with BlindPP(quant=0,cpu=0,cpu2="ooooxx") (from DGDecode) or a very slight denoiser.
Beave
13th July 2005, 11:41
I forgot to tell that the above tests had Removegrain(mode=2) in the end of the script.
Compressebility with Removegrain(mode=2):
Original: 34% / 8:23
DeGrainMedian(mode=0):50% / 9:44
Pixiedust(): 53% / 16:44
Pixiedust(8): 56% / 16:58
Compressebility without Removegrain(mode=2):
Original: 26% / 8:23
DeGrainMedian(mode=0):40% / 9:42
DeGrainMedian(mode=0) + RemoveGrain(mode=5):45% / 10:32
All the tests have cpu=4 in mpeg2source and I'm really ok with it, cause it seems only to remove blocks, but not softening the rest of the picture. Is there a reason why you would rather use BlindPP?
RemoveGrain(mode=5) is definatly much better then mode=2. There is almost no visual difference, but I gain 5% (well actually 11%). mode=2 improves the %age even more, but takes away those little light spots in the eyes, which makes the picture less appealing to me.
LRemoveDust(17,2) is even worse IMHO. The picture is even smoother and has less details left.
Doesn't mode=5 have a thin line problem? Or maybe I'm confusing it with some other mode.
I can't get DepanInterleave to work properly. I have not studied the entire docs, but the framerate seems to be different. I used:
mdata = DePanEstimate(r)
r=DePanInterleave(r, data=mdata)
Beave
13th July 2005, 15:54
I just made another testrun with an additional FFT3DFilter. This seems to be a very good combination. The picture still appeares to be sharp and the compressibililty enhances to 56%. It is a much better choice in my case then RemoveGrain(mode=2). It is sharper and still improves from 50% to 56%. Another RemoveGrain(mode=5) after this one and I even get 59% without seeing any difference. Not bad at all compared to the original 26%.
Is there an avisynth function where I can put one frame from movie1 and then the same frame from movie two after another? Like 11223344 ...
It might be easier to spot the differences when the same frame can be switched instead of putting them beside each other to compare. Or is there an even better method to compare different filter settings?
krieger2005
13th July 2005, 15:58
interleave
Fizick
13th July 2005, 17:47
When i have not a time, i often use for analog TV capture two degrainmedian (fast) script similar to:
AVISource("H:\capture\n-c6.avi")
degrainmedian(limity=2,limituv=4,interlaced=true)
degrainmedian(limity=2,limituv=4,interlaced=true)
leonid_makarovsky
26th September 2005, 16:27
I am now playing with DeGrainMedian to remove grain from LaserDisc. It does an amazing job. However, LDs are not only grainy, they are a bit noisy like VHS but to a less degree. I remove grain, but the noise is still left. I was thinking applying PixieDust to remove the analog noise. The question is, should I use PixieDust before DeGrainMedian or after? Thanks.
--Leonid
leonid_makarovsky
27th September 2005, 14:41
I chose the optimal parameters for LaserDisc grain removal:
DeGrainMedian(limitY = 5, limitUV = 10, mode = 0, interlaced = true)
However, I am using this in combination with other filters that work only in progressive mode. So I'd like to change it to:
SeparateFields()
DeGrainMedian(limitY = ???, limitUV = ??, mode = ???, interlaced = false)
Weave()
I have a hard time choosing equivalent arguments that give the same effect as interlaced version. Nothing seem to work. Can anyone give me a clue which arguments would give the same effect for the SeparateFields/Weave as this one:
DeGrainMedian(limitY = 5, limitUV = 10, mode = 0, interlaced = true)
Thanks.
--Leonid
Fizick
27th September 2005, 16:25
http://www.avisynth.org/InterlacedSmoothing
foxyshadis
29th September 2005, 09:17
I just made another testrun with an additional FFT3DFilter. This seems to be a very good combination. The picture still appeares to be sharp and the compressibililty enhances to 56%. It is a much better choice in my case then RemoveGrain(mode=2). It is sharper and still improves from 50% to 56%. Another RemoveGrain(mode=5) after this one and I even get 59% without seeing any difference. Not bad at all compared to the original 26%.
Although removegrain mode 5 is much safer, if you're going to compare to temporal smoothers you really should be comparing to removetemporalgrain. (It's in the docs, for reference it's this: )
function RemoveTemporalGrain(clip input, int _mode) {
rg = RemoveGrain(input, mode=_mode)
return TemporalRepair(rg, input)
}
I've found it to be much safer at higher smoothing levels than removegrain, while still being effective. I generally use mode 2 or 3 with it, as 4/17 tends to cause the minor dulling you noticed earlier. It's also nearly as fast as removegrain alone.
That said, I'm going to run my own tests with degrainmedian, fft3d, and a few others when I start my next round of work next week sometime.
Fizick
10th October 2005, 18:21
Version 0.8 October 9, 2005 - changed frame cache range to 3;
- added option norow to disable using same row (horizontal) spatial pair;
- fixed documentation error about mode=1;
- renamed old mode 4 to 5, 3 to 4, 2 to 3, added new mode 2.
KillNoise
19th October 2005, 18:15
Is DeGrainMedian() operating in recursive manner ?
i.e. with
c = current input frame
p = previous input frame
f = forthcoming input frame
o = current output frame
l = last (previous) output frame (for sequential access; otherwise l = o)
is it
o = function(p,c,f) # non-recursive
or
o = function(l,c,f) # recursive (sequential access provided; otherwise use non-recursive p)
?
(Using l gives some better estimation than p, because l has been already cleaned before.)
PS: Any recommendations when to use new DeGrainMedian() parameter "norow" ?
Fizick
19th October 2005, 20:04
1. non-recursive, as almost all Avisynth filters
2. use norow, when you have thin horizontal noise lines and you have not horizontal wires :)
KillNoise
23rd October 2005, 22:11
non-recursive, as almost all Avisynth filters
I have been discussing this recently with Kassandro concerning his Clense(): He has changed it to recursive operation on sequential access for better
temporal smoothing (introducing a bool option parameter to switch back to former non-recursive method). We also discussed making the chain "Clense(source).Repair(source, mode=16)" into a monolytic compound function to use the last repaired frame as recursive input for the clense-operation. (This lead to a general recursion scheme implemented in Kassandros new AssignRecursionClip() & Recusrsion.dll)
I think recursive operation will be benefit for DeGrainMedian() as well. Do you think it will be much effort to give it a try ? (Might perhaps use negative mode numbers to activate recursion.)
Fizick
26th October 2005, 16:34
Sorry for silence,
but i am still not sure, that recursion will be better for this median algo.
Poutnik
29th October 2005, 17:11
Two questionable ideas:
Would it make sense to give ( in general ) different weights to temporal and spatial pairs ?
One can see 3x3x3 cube as a cube in real 3D space. More precisly 2D x time.
Object presence in 2D frame is like 2D slice/cut of mystery 3D object.
The question is, if these dimensions are comparable in scale.
Almost everyone would consider spatial neighbors as similar/related with high probability. But in time scale it is not such case, even without scene change.
Looks for me like a temporal unit is significantly larger than spatial one so 3x3x3 is more a block than a cube.
Spatial scale units (pixel size) are quite fine small, but temporal space units
are quite large, so at one time the object is there, in next time unit it is not there. Ghosting of temporal smoothers can be related to that.
If there is 1000 fps temporal smoothers would have life much easier.
From that was born an idea to give pure spatial pairs other weights then to temporal-spatial pairs.
another question what about adaptive weights.... But it could slow down this
pretty, simple and fast filter.
-------------------
Would it make sense to implement in 3D any other methods from RemoveGrain ?
livetoride2112
29th October 2005, 20:42
Hey,
Thanks to everyone for your input on my thread.
KillNoise
29th October 2005, 22:16
I don't know how to prove recursive operation advantages without practical testing an implementation, but there is some evidence: Median operation is not good in damping of flickering oszillations. Easy to see for Clense() operation, which performs temporal min-max-clipping pixel values of input[t,x,y] within interval
min(input[t-1,x,y], input[t+1,x,y]) to max(input[t-1,x,y], input[t+1,x,y])
Recursive operation would use interval
min(output[t-1,x,y], input[t+1,x,y]) to max(output[t-1,x,y], input[t+1,x,y])
Example for temporal sequence at some single pixel:
Input(t): 5,4,6,5,6,4,6,5,4,6,4,6,4,5,... # oscillating noise over constant value 5
Clensed(t) non-recursive: 5,5,5,6,5,6,5,5,5,4,6,4,5,x,... # non-recursive pass through some oscillations
Clensed(t) recursive: 5,5,5,5,5,5,5,5,5,5,5,5,5,x,... # better smoothing with recursive Clense
Other examples may be constructed, but i'm sure you will not find any for which recursive operation will perform inferior. Note that this applies not only for small noise amplitudes: Even very high oscillation amplitudes may pass through. Effect is worst for "resonant" flickering frequency of half frame rate - likely after deinterlace.
I think recursive operation is superior because it makes use of the available signal/noise enhancement performed on previous frame. Further, using the previous output as reference helps to reduce temporal flutuations, thus improving compression.
Considering DeGrainMedian() is little more complicated, but i think recursion can help in both of two stages:
In first stage DeGrainMedian() tries to find the spatial/temporal texture-direction by selecting the axis of minimal change among the 13 line-pairs. Replacing the previous input frame by the previously degrained output provides the best estimate of previous image available at this point, making the direction decision more reliable.
Second stage applies the median filter along the determined texture-direction axis. If this is one of the 9 temporal directions (most likely for all static areas), then recursion will enhance denoising as shown for Clense().
Besides, i like the slight motion compensation capability of DeGrainMedian() which might reduce small image jitter, sometimes caused by bad film transport mechanics, as well as possibly from fidgety motion compensation disturbed by noise. This jitter stabilizing feature will surely improve with using previous output frame as reference.
I expect DeGrainMedian() recursive operation will be nearly as effective as double-cascading DeGrainMedian(), but faster and with lower artefacts risk (e.g. not degrading spot-details by limit-value twice).
What do you think ? Isn't it worth trying an option for DeGrainMedian() recursive operation ?
Then you can experimentally evaluate performance comparison between simple, recursive and double-cascaded DeGrainMedian().
KillNoise
29th October 2005, 22:17
Using DeGrainMedian() "norow" option
I think "norow" adresses two important issues with analog video signal transmission:
Primary application is removing line offset error caused by faulty black level clamping, which sometimes occurs with analog video signal, mostly for video tape recordings.
Further, denoising (generally based on stochastic estimation techniques) mostly assumes noise to be uncorrelated for each pixel indepently, which is correct only with one exception: if analog video signal transmission was involved somewhere in signal chain, it introduces some lowpass filtering which correlates noise for horizontal neighbour pixels, so that it is likely mistaken as horizontal line segment detail to be preserved.
For this reason i like using initial filtering with RemoveGrain(2), whose "line end eating" property is able to reduce horizontaly correlated noise considerably (though it works equally in every other direction too). DeGrainMedian(norow=true) might be a more specific alternative.
KillNoise
29th October 2005, 22:18
Using DeGrainMedian() for extremely grained movies
When looking carefully at heavily grained movies, i often see extreme fluctuation amplitudes, exceeding image details level by far. I think only the human eyes temporal low pass filtering capeability makes such image appear acceptable. Of course these fluctuations are disastrous for compression efficency.
Effectively suppressing those high fluctuation amplitudes requires DeGrainMedian() to be used with equivalent high change limit values, thus increasinging artefacts risk as well. I think there is a fundamental difference regarding any filters performance depending on whether noise exceeds image details level or is only a small, harmless amplitude (the former renders most threshold based concepts useless !).
I wonder how much recursive operation can improve performance in case of such excessive fluctuations ...
Using DeGrainMedian(limitY=255, limitUV=255, mode=4) - recursive or not - might be another alternative: DeGrainMedian mode 4, similar to RemoveGrain mode 6, should preserve line end points as well as small spots, so i think can be well used without any change limits. Because of including temporal filtering, it should be more effective than RemoveGrain(mode=6). Might it also do more harm then ? Any suggestions ?
Though quite simple in concept, DeGrainMedian() seems to be a most powerfull filter. (Suppose it implements a simple form of signal-adaptive filtering.)
"Fascinating !", as Mr. Spook would say.
I wonder whether this concept can be further enhanced by more sophisticated texture detection in first stage or an improved filter-algo in second stage ? Perhaps by iteratively reusing direction information or filtered results from spatial neighbours (similar idea as with temporal recursion for previous frame). It would be easy at least for the 4 spatial neigbours which have already just been processed (though i don't realy like this kind of anisotropic recursion).
Fizick
29th October 2005, 23:39
Poutnik,
IMHO, if we give small weight to temporal pair, the filter will be too weak to grain, like RemoveGrain ;)
But you may try modify the code and experiment what you want.
The code is opensource.
There are many ways to add and subtract even 3 pixels :)
But you must understand, what do you want to do. :)
I think, for true denoising improving, we must use more pixels, and probably compare not single pixels , but small spatial blocks (2x2 ?).
It seems, Tom Barry used similar aporoach in his great TomsMoComp plugin.
But it will be not DGM filter.
The larger block is fine too, but we then re-invent Dust and MVtools. :)
Poutnik
30th October 2005, 06:52
Spasibo za otvet, Sasa. (Thank you for the answer).
I may try to modify a filter, but it would not Avisynth filter anymore. :p I am just going to learn VC++. I did not programming for many many years. I know well Z80, much more then SSE :(
Not brave enough to try xxxxDust on my Celeron600(SSE). :p
XXXXTools are still blackbox for me.
I had to ask even I could imagine You asked this question yourself before.
Thank you for all your effort developing those nice filters, in spite of that my CPU some of them does not like ( is lazy ) :p
KillNoise
1st November 2005, 20:12
Different handling for temporal and spatial pairs
Would it make sense to give (in general) different weights to temporal and spatial pairs ? ...
The question is, if these dimensions are comparable in scale. Almost everyone would consider spatial neighbors as similar/related with high probability. But in time scale it is not such case, even without scene change. Looks for me like a temporal unit is significantly larger than spatial one so 3x3x3 is more a block than a cube. Spatial scale units (pixel size) are quite fine small, but temporal space units are quite large, so at one time the object is there, in next time unit it is not there. ...
From that was born an idea to give pure spatial pairs other weights then to temporal-spatial pairs.
Very, very true note, Poutnik !
The question is: Does temporal filtering make sense at all for motion areas ?
Generally: No! - There is no useful correlated information in temporal axis, so any temporal filtering can do nothing but harm (except with motion compensation establishing temporal correlation). An exception is for uniform colored moving areas overlapping from frame to frame, but for these we should not recognize motion.
==> For DeGrainMedian: if motion > 1 pixel would be detected, none of the temporal pairs should be regarded at all.
In my oppinion the ideal ST-filtering scheme (without using motion compensation) should be:
1) moderate spatial filter (YUV; nonlinear to remove large grain and noise peaks, e.g. RemoveGrain mode 2)
# can be applied overall, will make motion detection and subsequent filtering more reliable
2) determine binary motion mask by frame-to-frame change analysis
# preferably using a low pass filtered clip version to supress jitter & HF noise disturbance
# change analysis preferably based on small clusters rather than single pixels (e.g. 2x2 or 4x4 blocks)
# the motion mask might be reduced to 2x2 or 4x4 "macropixel"-resolution for processing performance
3a) apply temporal filter for static areas (YUV)
# with breaking temporal filter extent on frames indicating motion (recursive method prefered)
3b) apply stronger spatial filter for motion areas (YUV)
# spending less bits on encoding where the eye is less sensitive for deterioration
4) downsize target resolution with appropriate lowpass for anti-aliasing (e.g. RemoveGrain mode 12)
# making an adequate tradeoff for spatial resolution versus signal/noise dynamic resolution
5) aplly structure adaptive (signal-adaptive) spatial filter (YUV) (e.g. RemoveGrain mode 6)
# "intelligent" spatial filter can use denoised input to further enhance image structures
# (spatio-temporal DeGrainMedian(mode=4) could be used as well)
6) optionally use some change limited sharpening on luma to compensate loss of "crispness"
I'm not sure whether step 5 and 6 should be reversed. However, step 6 might also be done after decoding.
On the other hand, my experience: Encoding with limited sharpness "preemphasis" and stronger quantizer at same bitrate often yields nicer, more detailed result (sufficient denoising provided; only for "naturally" textured image, not for cartoon-anime)
Well, the power of simplicity with DeGrainMedian is its implicit (though far from perfect) ability to automaticly switch from temporal to spatial filtering on motion areas, so that it incorporates steps 2 and 3 in one. This is simmilar to Kasandros approach of using Clense with Repair-Bypass, which could also be implemented as monolithic compound function to operate on 3x3x3 cube like DeGrainMedian (one example of ST-anisotropic handling asked for).
I see most artefact risk for any small objects transient passing constant background during one frame: Temporal 2-frame step difference would be near zero for this case, so DeGrainMedian mode 0 is likley to erase the object (only change limits would help, but these also obstruct grain filter performance as i stated earlier here). At least there is high risk for compression-hampering unsteadiness caused by wavering between temporal and spatial axis, thus switching between object and backgroung colour.
My consequence: If mode 0 is used, spatial directions need some higher priority than temporal ones.
Suggest modification to select only among the 9 temporal axes with using DeGrainMedian mode 0 first, then correct the resulting center pixel by spatial filtering rules like Kassandros Repair mode 9 or 16. This is quite similar to Clense-Repair pattern, except for the Clense-operation based on a divergent bundle of 9 axes rather than only one central. Recursion would then comprise the entire operation rather than clense alone, reusing an even more reliable output for previous of next frame.
Further improvement specially with recursive operation: Instead of using 9 temporal axis with central pixel of current frame as pivot, we could use 9 axes with their pivot on center pixel of last frame, i.e. simply find the one pixel among the 3x3 in forthcomming frame whose value is next to last center pixel (probably even faster). Then use this pair for clipping (again with subsequent spatial Repair within current frame).
Why better ? If we consider the last filtered output frame as most reliable reference available, it is only consequent to make it the pivot for DeGrainMedian "motion compensation" for best jitter suppression on output.
I wonder, whether someone could find a set of rules to make up stochastic optimal ST-filtering decisions based on a 3x3x3 cube (not bothering about effort and speed performance for a first theoretical evaluation) ?
KillNoise
1st November 2005, 20:20
DeGrainMedian Based on Motion Detection
Here is another idea: The 3x3 cluster can be used for motion detection by frame-to-frame change analysis, enabling explicit decision whether to use temporal or spatial filtering. Might work as follows:
Calculate 2x2 averages (or simply sums) for each of the four quadrants at the corners within 3x3 block (partially overlapping):
Q0 = (c + n0 + n1 + n2)
Q1 = (c + n2 + n3 + n4)
Q2 = (c + n4 + n5 + n6)
Q3 = (c + n6 + n7 + n0)
for 3x3 array
[n7] [n0] [n1]
[n6] [c] [n2]
[n5] [n4] [n3]
This is convenient for data reduction and supressing noise & jitter by low-pass filter.
Motion detection compares these 4 quadrant averages from current frame with those of last frame, assuming motion if more than one of the four difference values exceeds a threshold parameter.
Depending on this motion decision apply prefered pure temporal or pure spatial filtering (e.g. RemoveGrain mode 22 for moderate or mode 17 for strong filtering might be a good choice)
An even more efficent modification might be using a 4x4 luma pixels block instead, with the four 2x2 cluster averages not overlapping and then use the motion decission commonly for each of the 2x2 core pixels as well as for the U and V chroma pixel in YU12 simultaneously. This performs faster motion detection on half resolution grid only and we could also apply very efficient temporal filtering methods for the 2x2 luma cluster.
Well, this might go beyond scope of DeGrainMedian, but maybe some talented programmer would like to adopt and implement this idea. If there is interest, i could tell some more about efficent temporal filtering on clusters. (Maybe continue this on a new thread)
Fizick
1st November 2005, 21:20
KillNoise,
Thank you very much for your suggestions!
I read it , but i am busy with other project now.
The one comment first:
You wrote:
For DeGrainMedian: if motion > 1 pixel would be detected, none of the temporal pairs should be regarded at all.
IMHO, it is not true:
1. Often we have large areas with similar colors.Even if this object moves, we can yse strong temporal filter.
2. There are no good way to reliably detect motion and distinguish it from big grain.
(you wrote it above).
3. Using different filters and its strength on different regions give anoying transient regions (edges).
So, DegrainMedian is still the best now :)
Will waiting some talanted programmer. :)
Fizick
2nd November 2005, 05:58
Three more comments:
4. Threre are many good denoisers, but threre are no good de-grainers.
DeGrainMedian is best (IMHO :) ) but it is not good.
5. Instead of explicit clustering, we can use multilevel processing.
6. Some time ago i also waited when somebody will wrote filter with advanced algo.
Killnoise, take C complirer, and become the talanted prorgammer !
KillNoise
5th December 2005, 23:10
Thank you very much for your suggestions!
I read it , but i am busy with other project now.
Well I know; noone having no time no more seems to be THE affliction of our time ...
Me, i took until now even to watch your replies.
Can you imagine yet to find opportunity to provide an enhanced version at least with recursive option ?
Suppose this might not be very great effort for you, knowing all the code structure and caveats
(realy no chance of doing it myself - i am so far from talented in coding)
I'm sure, not only me would appreceate you very much for doing so, making this best filter even better.
1. Often we have large areas with similar colors. Even if this object moves, we can use strong temporal filter.
Absolutely true. When talking of simple Motion Detection, i assume uniform areas should adequately not be detected as moving (may be different for using Motion Compensation)
2. There are no good way to reliably detect motion and distinguish it from big grain.
...
4. Threre are many good denoisers, but threre are no good de-grainers.
Seems like a logical consequence, maybe a fundamental law: Rather easy to get rid of uncorrelated white noise; however, grain is spatially correlated noise, ranging into the frequency scale of image details to be preserved. So only temporal filtering can help to separate grain from image detail. Using motion compensation would clearly be the way to do it perfectly. (For encoding efficiency, it would be consequent to fight grain within the encoders motion estimation & residual encoding process, rather than aiming exact reproduction of bad input !)
However, even without motion compensation efforts we should already be able to "squeeze" away most part of the bits commonly wasted on noise and grain, leaving some residual noise for the benefit of dithering effects.
Concerning motion detection/compensation beeing fooled by grain & noise, i think its allways a good idea to provide a separate, heavily filtered parallel stream/clip to be used merely for motion analysis. In case of DeGrainMedian() you might use this to determine selection of the axis direction to be used for filtering the pixels from original clip then.
5. Instead of explicit clustering, we can use multilevel processing.
Not sure i got you right: Do you mean multi-scale decomposition ? How would you apply it here ?
DeGrainMedian is best (IMHO) but it is not good.
It IS good, because it is one of the best we have today.
Good reason however to develop it further to make it even better, if you can.
Recursion seems to be a most promising approach. Looking forward to see it playing soon ...
Fizick
6th December 2005, 23:00
mulilevel approach I tried implement in degrainpiramid script somewhere here.
other comments later.
Poutnik
7th December 2005, 16:24
There is Didée's comment and modification of DegrainPiramid
at Kassandros forum...
He suggested to replace pointresize by bicubicresize.
http://videoprocessing.11.forumer.com/viewtopic.php?t=44&postdays=0&postorder=asc&highlight=degrainpiramid&start=30
Axed
11th December 2005, 00:05
I think i have a problem here. I was playing with degrainmedian because everyone said it was quite fast, my problem is that its sooo slow. I get 0.3 - 0.5 speeds in CCE on my P4 2.4 with only dgdecode and degrainmedian in the filter chain. I tried degrainmedian() with a movie that is progressive.
All my other filters (in other avs files) seem to be fast and working properly, but if you need more information please say so.
Fizick
11th December 2005, 00:10
:script:
system config? Avisynth version? DegrainMedian version?
It is trivial questions. We are not telepathic.
Axed
11th December 2005, 00:28
Sorry, never had to report a problem before.
Avisynth 2.5.6, newest degrainmedian. P4 2.4, 768 meg ram running Windows XP SP2.
loadplugin("c:\stuff\dgindex\dgdecode.dll")
loadplugin("c:\stuff\filters\degrainmedian.dll")
mpeg2source("rush hour.d2v")
degrainmedian()
Nothing special there as you can see, and i know every single other filter is running at full speed?
Just remembered something too, when i ran degrainmedian on a shorter clip (i believe it was 10,000 frames) it ran at above realtime speeds using the same style script.
Fizick
11th December 2005, 00:56
Strange.
1.What is "newest" degrainmedian version?
2. you do not use convertto...?
Axed
11th December 2005, 01:13
I use 0.8, i knew it was the newest because i only downloaded it a week ago and i keep an eye on your homepage.
The reason i didnt have converttoyuy2() in that script is that i was testing the script in xvid to doublecheck it wasnt a CCE fault.
Im a newbie at programming, but is there any special libraries that degrainmedian uses? Its entirely possible one of them on my computer could be corrupted or something.
Also i ment to say, i have no plugins in my "avisynth 2.5\plugins" directory barring the default avisynth ones.
Boulder
11th December 2005, 06:34
Try
loadplugin("c:\stuff\dgindex\dgdecode.dll")
loadplugin("c:\stuff\filters\degrainmedian.dll")
mpeg2source("rush hour.d2v")
Crop(0,0,-0,-0,true)
degrainmedian()
KillNoise
13th December 2005, 23:34
other comments later.
Well ... ?
How do you think about you can make a recursive DeGrainMedian ?
BTW:
Thinking thoroughly about it , i can't understand the idea behind using 9 temporal axis rather than simply one straight:
You mentioned "motion compensation", but this can not happen but for veeery slooow < 2 px/frame; but see practically almost every movements much faster than that (i.e. temporally discontinous).
There may be small jittering fluctuatuions (e.g. irregularities from film-scanner transport mechanism or from TV horizontal line sync) which might lead to some blurr (at least on "stupid" temporal filtering). However, these seem mostly fast jittering or oszillating forth an back, so they misfit the 3-frame linear motion model assumed by DeGrainMedian, rendering it useless.
So i ask you, how to justify computational effort for extra 8 temporal diagonal axis (beyond only 1 straight temporal + 4 spatial) ?
Axed
14th December 2005, 03:04
Try
<snip>
Didnt help.
Fizick
14th December 2005, 21:42
KillNoise,
1. "Later": is still not occures. Sorry. :(
I am still do not want implement recursion (not generally, but in DegrainMedian specifically - it would not be median).
2. By the way, some time ago I considered to add more temporal pairs. :)
(for 2 pixel compensation).
But I am still do not want broke my filter.
It will be better to design a new, for example "KillNoise" :)
Who will wrote it? ;)
But my thougths are about MVDeGrain.
Fizick
14th December 2005, 21:48
Axed,
I do not get it.
DGMedian do not use nothing special.
What is your clip size?
Can you try it with other source, or without mpegsource?
Use Avisource or Blankclip.
KillNoise
30th December 2005, 12:51
I am still do not want implement recursion (not generally, but in DegrainMedian specifically - it would not be median).
Can you explain why do you think recursion with DeGrainMedian would no more improve denoise performance?
By the way, some time ago I considered to add more temporal pairs. (for 2 pixel compensation).
But I am still do not want broke my filter.
Sure you are right - not worth the effort: More temporal pairs would make it slower without improving much.
Denoise moving details will clearly require true motion compensation. Without that we should talk of simple motion detection - which however performs equally well on still and uniform moving areas. Those contribute by far greatest part of total noise ammount - for most movies: My personal estimate is generaly about 80% of possible denoise compression enhancement can be achieved "cheaply" with only motion detection alone (unless you have one of those action movie scenes e.g. with rocking hand-held camera)
I think fundamental filter rule for most efficient compression enhancement is:
"make as most pixels kept constant from frame to frame, if you may reasonably assume their changes were caused by noise/grain rather than image detail"
There are several indications to base this decision on. However, keeping pixels constant on output frames generally establishes a recursive rule (same as subsequent progressive video encoding is recursive by nature)!
But my thougths are about MVDeGrain.
I also thought about that. The fundamental filter rule above need to be modified then, to keep pixels constant with respect to the prediction derived from last output frame. So you have to recursively apply motion compensation on last output frame to predict current frame - imitating same as the video codec will do within its own prediction loop. (Reverse motion compensation from next frame is to be performed as usual.) Then apply pixel-value keeping 3D filter rules as above.
Consequently the video encoders motion estimation will then mostly follow your preceding one, yielding a minimum of residual DCT coefficients to encode. Important: your own motion compensation should perform equally intelligent - or better than the one within the encoder. To prevent it from beeing fooled by grain & noise, motion estimation should be fed by a separate, heavily prefiltered parallel input clip and use some bias to favour uniform pan motion (or still) over hectically wavering in attempt to follow noise & grains pseudo-movements (simple SAD minimisation might be more stable here than squared differences !) Further it should provide options to apply in-loop deblocking and to select motion compensation based on 8x8 or 4x4 blocks (matched for hierarchical motion estimation of x264 AVC).
==> Squeezing out those remaining estimated ca. 20% of denoise compression enhancement does not come cheap !
Of course it would be much more efficient when doing it all within the encoder (anyone here involved with XviD/x264 developments to take these considerations there ?).
On the other hand, an external prefilter with superior motion compensation might be used as versatile front-end for any stupid codec, enhancing its compression as well as resulting image quality.
It will be better to design a new, for example "KillNoise"
Who will wrote it?
Might rename plugin something like "DeGrainR" (could preferably compile from same source code using compile switches on few branches rather than forking all your project.)
I can see no one but you who could make this work with reasonable effort - at least not me: My background is signal processing algorithm theory, not much practical programming skills.
So please think about if you can take the time to make the good even better: Let us experience further enhancement of your popular DeGrainMedian filter... I am sure you will make many users very happy !
Axed
30th December 2005, 13:42
Axed,
I do not get it.
DGMedian do not use nothing special.
What is your clip size?
Can you try it with other source, or without mpegsource?
Use Avisource or Blankclip.
I believe its a problem with my computer. Im going to reinstall XP for the new year and try again then. I bet that will fix all these weird problems im having with certian filters and other programs.
Sorry for the slow reply also, Christmas has been so busy this year for me.
Thanks for the attempts to help tho Fizick & Boulder.
Serbianboss
18th April 2006, 23:26
I have just 2 questions:
1. I always work with DV avi (bottom field first) interlaced materials. So, does is better to use Script 1 or Script 2 for interlaced sources?
Script 1
avisource("D:\CAPTURE\bmw.avi")
LoadPlugin("DeGrainMedian.dll")
ConvertToYuY2(interlaced=true)
DeGrainMedian(limitY=5,limitUV=7,mode=0)
Script 2
LoadPlugin("DeGrainMedian.dll")
avisource("D:\CAPTURE\bmw.avi")
ConvertToYuY2(interlaced=true)
SeparateFields()
odd=SelectOdd.DeGrainMedian (limitY=5,limitUV=7,mode=0)
evn=SelectEven.DeGrainMedian (limitY=5,limitUV=7,mode=0)
Interleave(evn,odd)
Weave()
2. When using script 2, does i duplicate DeGrainMedian parametars? Because i two times use (limitY=5,limitUV=7,mode=0)
Fizick, excellent filter.
best regard
Fizick
19th April 2006, 00:27
1. both script are equivalent by results.
speed may be a little different.
2. yes, you must set all params.
Serbianboss
19th April 2006, 00:47
1. So its no matter which i script using(1 or 2) OK. Which you prefer for interlaced video?
Script 1 is little faster.
2. Can i just set parametar for one, so that line evn=SelectEven.DeGrainMedian dont have any parametars?
LoadPlugin("DeGrainMedian.dll")
avisource("D:\CAPTURE\bmw.avi")
ConvertToYuY2(interlaced=true)
SeparateFields()
odd=SelectOdd.DeGrainMedian (limitY=5,limitUV=7,mode=0)
evn=SelectEven.DeGrainMedian
Interleave(evn,odd)
Weave()
best regard
Serbianboss
You are not programmer ;)
in line
evn=SelectEven.DeGrainMedian
DeGrainMedian run with defaults parametrs!
(defaults - see in manual)
PS Excuse me my English...
Serbianboss
19th April 2006, 09:15
So, if i leave line evn=SelectEven.DeGrainMedian empty my parametars would be:
odd=SelectOdd.DeGrainMedian (limitY=5,limitUV=7,mode=0)
evn=SelectEven.DeGrainMedian (limitY=4,limitUV=6,mode=1)(because this is default parametars right?)
foxyshadis
19th April 2006, 12:27
If you use 2.5.6 use parentheses, if you use 2.5.7 alpha it doesn't matter. 2.5.6 and below and below has a bug that slows down encoding something fierce. I can't stress enough how much of a difference it can sometimes make.
Otherwise, for degrainmedian, it is probably better to run it with separatefields (can cause weird artifacts in the other fiels otherwise) but it would be better still to mask it off to apply to only its own field in motion and both in more static areas. I leave that as a future exercise though. (I think mvbob has a function for it.)
Fizick
21st April 2006, 22:28
Serbianboss,
Sorry, I do not look your "script 1" carefull.
For correct processing of interlaced sources without separation fields, it must be
...
DeGrainMedian(limitY=5,limitUV=7,mode=0, interlaced=true)
(But mode=0 can kill some details)
Serbianboss
23rd April 2006, 22:49
i found that this parametars are very good for noisy interlced sources:
LoadPlugin("DeGrainMedian.dll")
avisource("C:\Documents and Settings\Nenad\My Documents\Video 1.avi")
Trim(157803,159318)
ConvertToYuY2(interlaced=true)
degrainmedian(mode=1,limity=6,limituv=7,interlaced=true)
degrainmedian(mode=1,limity=6,limituv=7,interlaced=true)
crop(8,4,-8,-12)
AddBorders(8,8,8,8)
Boulder
4th July 2006, 08:48
Which frames does DegrainMedian use for doing its magic? Is it previous-current-next or previous-current (or possibly something else)? The reason why I'm asking is that I use it for motion compensated denoising and would like to know how many frames (and which ones) should be created by compensating.
Didée
4th July 2006, 09:56
It's previous-current-next. Therefore, for each single input pixel, the spatio-temporal 3*3*3 neighborhood is considered.
It's somewhat "between the lines" of DeGrainMedian's documentation ...
See also the example section of MVTools' documentation. The vanilla method for using DeGrainMedian together with motion compensation is given there. Didn't you see? ;)
(From MVTools documentation: )
To denoise with some external denoiser filter (which uses 3 frames: prev, cur, next):
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) # or use MVCompensate function
backward_compensation = source.MVFlow(backward_vectors, idx=1) # or use MVCompensate function
# 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
Boulder
4th July 2006, 10:02
Uh, MVTools' documentation is the place where I stole my code from originally..I browsed through it quickly before posting here but somehow missed that DGM is used there :o
squid_80
28th July 2006, 10:20
Fizick: You're probably gonna hate me, but I think I found a bug in the YV12 interlaced modes.
LoopQ:
// Search between prev and next frame - Temporal
movq mm0, qword ptr[ebx+2*ecx] // load our curr pixels vals
// diagweight8(oldp, newp, weight, bound1, bound2, reg1, reg2)
// oldp is clipped with min(bound1, bound2) and max(bound1, bound2)
// finally weight = |oldp - newp| + 2*|bound1 - bound2|
// Search Spatial
diagweight8(mm0, mm1, mm2, [ebx - 1], [ebx + 4*ecx + 1], mm6, mm7) // up left, down right
diagweight8(mm0, mm3, mm4, [ebx + 4*ecx -1], [ebx + 1], mm6, mm7)// up right, down left
// mergeweighted(value1, weight1, value2, weight2)
// if( weight2[i] <= weight1[i] ) { value1[i] = value2[i]; weight1[i] = weight2[i]; }
// value2 remains unchanged
mergeweighted(mm1, mm2, mm3, mm4)
diagweight8(mm0, mm3, mm4, [ebx + 4*ecx ], [ebx], mm6, mm7)// up, down
mergeweighted(mm1, mm2, mm3, mm4)
diagweight8(mm0, mm3, mm4, [ebx + ecx + 1], [ebx + ecx - 1], mm6, mm7)// left, right
mergeweighted(mm1, mm2, mm3, mm4)
Shouldn't the last call to diagweight8 be:
diagweight8(mm0, mm3, mm4, [ebx +2*ecx +1], [ebx + 2*ecx -1], mm6, mm7) ?
The same code is used for all YV12 interlaced modes > 0 except if norow is true.
Fizick
28th July 2006, 15:44
Yes, it is a bug.
Thanks for point to it! Will fix it soon.
Is DGM source really interesting reading? :)
squid_80
28th July 2006, 16:13
Someone requested a 64-bit port, so I had to rewrite the assembly... Then I wondered why the new version was producing different results to the old one.
Lots of copy-pasting in the source code. :)
Fizick
28th July 2006, 16:16
Will you release your version?
squid_80
28th July 2006, 16:25
Already have: http://okejl.dk/dunstan/DeGrainMedian64.zip
and http://okejl.dk/dunstan/degrainmediansrc.zip
Contains a vs2005 project, can be used to compile for x86 or x64. (I had to add push ebx, pop ebx to all those __asm blocks. Very annoying.)
There's one small difference: I changed to using SSE2 instead of MMX. So instead of 8 pixels at the start and end of each row only being processed vertically, there's now 16.
Fizick
28th July 2006, 16:40
O.K., I released new version 0.8.1 about 5 minutes ago :)
Try compare the results.
squid_80
28th July 2006, 17:46
Results are identical now, except for the first and last 32 pixels of each row for YV12 and first and last 8 pixels for YUY2 (for the reason explained above).
Also the original seems to cause an access violation if the input width is <= 32(YV12) or 8(YUY2). Haven't looked to see exactly why, probably not worth investigating.
Edit: I just did some speed tests and this is pretty amazing. Input script:
mpeg2source("test.d2v")
degrainmedian()
trim(0, -1000)
Time to process using 32-bit: 18875ms.
Time to process using 64-bit: 12515ms.
If only all 64-bit stuff gave me this much of a speed up!
Fizick
28th July 2006, 18:39
Probably it due to SSE2.
It may be implemented for 32-bit version too, of cource,
but is not supported by all 32 bit CPU.
squid_80
29th July 2006, 05:28
I used intrinsics so it's simple to recompile for x86. Results for a 4000 frame test:
Old (MMX) version: 74718ms.
New (SSE2) version: 66421ms.
So it's a little quicker which isn't what I expected (many unaligned loads) but the AMD64 version is still a lot quicker by comparison, probably because of the extra XMM registers.
foxyshadis
29th July 2006, 08:36
That's pretty cool. =o
I'm not criticising, but would it be better to just apply the transform to the entire image (including off-image garbage) and apply a 1-pixel fixup at the borders after to deal with introduced off-edge garbage? Or do vertical-only columns just not make that much difference, compared to the extra time to do the fixups?
squid_80
29th July 2006, 13:32
It's not my filter, I just ported it :)
It wouldn't be too hard to extend the edge pixels similar to how avisynth's internal blur/sharpen works. But I really don't think it's worth the effort - I haven't seen anyone complaining because their 8 edge pixels aren't cleaned as much as the rest of the picture. Top and bottom lines aren't filtered at all!
Fizick
29th July 2006, 17:24
It's not quite my filter, I just a little re-designed STMedian by trbarry. :)
J-Wo
19th August 2006, 19:46
Hi! I think this is a great filter, I always use it when processing DVDs using DVD-RB. I use the parameters given in the readme for light grain removal, but I have question about interlaced material. Some of my DVDs have mixed interlaced and progressive material, even within the same VTS. For example, a typical Six Feet Under episode is interlaced only for the title sequence, but the rest of the episode is progressive. Will it hurt my encodes to always have interlaced=true, even if some of the material is progressive? Here is the line I use:
DeGrainMedian(limitY=5,limitUV=5,mode=3,interlaced=true)
P.S. an early post you mentioned "The more mode number, the weaker the degree of denoising. If someboby can say this in good English, please post." I would suggest changing your documentation to read "The lower the mode setting, the stronger the denoising". I think that makes things much more clear.
Fizick
20th August 2006, 17:30
J-Wo,
Probably it is quite safe (for so low settings). But if you want better quality, you must use approriate setting for different parts of your clip.
trim(0,12340).degrainmedian(mode=3,interlaced=true) ++ trim (12341,0).degrainmedian(mode=3, interlaced=false)
And thanks for suggestion.
Chainmax
7th September 2006, 21:35
I am trying to cleanup some dotcrawl on a clip where DeDot isn't enough. Since I recall Mug Funky saying a long time ago that DeGrainMedian() could help in that regard, I tried it. It did work, but there's still a tiny bit of dotcrawl left. So, short of using GuavaComb, I have to raise DeGrainMedian's strenght. Here's the question then, which of these two:
DeGrainMedian() ---> DeGrainMedian(limitY=5,limitUV=7)
DeGrainMedian() ---> DeGrainMedian(mode=0)
implies a bigger jump in denoising strength?
akapuma
7th October 2006, 17:57
Hello,
I've a problem. If I use DeGrainMedian 0.8.1 with the following .avs-script, I get a small green stripe at the right site (example (http://akapuma.info/test/dgm.jpg)):
mpeg2source("D:\Rekorder\akaenc\aka.d2v")
crop(24,10,514,564)
DeGrainMedian(limitY=5,limitUV=7,mode=2)
BicubicResize(512,560,0,0.5)
Without DeGrainMedian, there is no green stripe. I testet this with different movies with the script above (only changed the .d2v).
What's the cause?
Best regards
akapuma
Fizick
7th October 2006, 23:00
Generally, width must be mod-8 for DegrainMedian (it uses iSSE optimization).
But it may be considered as a bug.
Anyway, I released new version 0.8.2 today.
I added new parameter "color" and now you can set any color of this stripe instead of green! :D
foxyshadis
7th October 2006, 23:02
Haha. ;) Oh, does this have squid_80's SSE2 version incorporated?
Fizick
7th October 2006, 23:14
I never tried his version (my old Athlon does not support SSE2).
Generally say, borders are devil's invention.
Most code is aroung border processing. :(
It is a joke, of course (not about borders, but about color) ;)
akapuma
8th October 2006, 07:50
Thank you for the 0.8.2. Works fine!
Best regards
akapuma
Fizick,
DeGrainMedian has nice results at really good speed.
Would it be possible to add following mode (for remove bob flicker):
now: 13 ways you could draw a line through center of the Rubics cube and a pair of two nearest neighbors.
new: add all temporal ways: 9x9+4=85
no reply?
Terka
16th May 2010, 18:24
please, could someone add the above to the DeGrainMedian code?
tormento
2nd September 2010, 06:41
Could you gladly (or somebody else, I'm not so egoist) provide a x64 compile to test?
Thanks ;)
Edit: just found on squid_80 page. Sorry...
kedautinh12
15th April 2021, 04:17
New filter DeGrainMedian back port from vapoursynth support HBD
https://github.com/Asd-g/AviSynth-vsDeGrainMedian
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.