View Full Version : Averaging two analog captures for noise reduction
I've long thought the best way to clean up analog captures is to capture the source multiple times and then average them together. Good ol' statistics will beat fancy threshold- using algorithms every time. But, I always dismissed the idea as being impractical. First, I thought you need a statistically valid sample - an average of two caps would probably not improve things much. Second, getting even just two captures would be difficult, much less more. Recently I started capturing music videos overnight though, and if you ever watch vh1 or mtv you know that they play 95% of the same videos *every* day. Plus when your source is only 3:30 minutes long, you can afford to play around to get the best results.
So, I captured a video, Jimmy Eat World - In the Middle, twice, combined them in avisnyth with StackHorizontal(), then wrote up a quick vdub filter to do the averaging - unfortunately I don't know avisynth well enough to write a plugin for it.
For a first comparison, I encoded the averaged result back to huffyuv to compare size with the original capture.
Capture 1: 661,810 kb
Averaged: 593,810 kb
Subjectively comparing the two, the amount of noise is very visibly reduced. There is still noise in the averaged file, but it's hard to tell how much just stepping through at 1:1, and huffyuv isn't exactly meant for fullscreen playback.
So, I then encoded both to divx 5, 1 pass CQ Quant=4 with b-frames. I put the raw capture file through my normal noise filtering, 2D cleaner (default settings)+ Smart Smoother HQ (Average mode, r=5, threshold=12). These settings give consistently good results for the station I capped from. The averaged file got no further processing.
Raw + noise filters: 31,262 kb
Averaged: 30,312 kb
Sometimes the simple ways are better. Subjectively, it's difficult to tell them apart. The experienced eye can tell that filters have been used on the filtered file, while the averaged file looks like it just came from a very clean analog source. There are none of the artifacts temporal filters can leave or loss of sharpness from spatial filters, and it works equally well on motion areas and motionless ones. Plus, I can always follow up the averaging with noise filters, but use more conservative settings.
And now the reason for my post, as I said I don't know avisynth well enough (yet) to write the entire thing as one function. Using stackhorizontal() then a vdub filter is cumbersome and less efficient. But for someone who does know it should be trivial to write, the vdub version (http://members.verizon.net/~vze3kkvm/TemporalMixer/TemporalMixer.zip) took me all of 10 minutes. So, I was hoping some kind soul could help me out with this. You can assume that the two clips have already been aligned and made the same length with trim()
-Leuf
Richard Berg
3rd July 2002, 01:45
You're (http://forum.doom9.org/showthread.php?s=&threadid=28250) in luck (http://arstechnica.infopop.net/OpenTopic/page?a=tpc&s=50009562&f=67909965&m=4020952194) :) It does seem to be a very good technique, though I haven't tried it myself.
Hmm, well it seems my luck only goes so far. Layer requires RGB32, Telecide requires YUY2. So, either I have to telecide each clip separately first, converttoRGB32, layer.. or converttoRGB32 both first, layer, converttoyyuy2, telecide. I chose the latter, and it's just barely faster than my stackhorizontal+vdub filter. But here's the odd thing:
Test clip (first 500 frames of the same video as before):
mine 96,356 kb
layer 104,120 kb
Which is pretty odd, and I can't explain it yet. I used 128 for "amount" as in your second link, I'm assuming it's on a 255 scale.
poptones
3rd July 2002, 06:13
Layer used to work wiht yuy2, and it wil be made to again. If no one else does it first I'll get my code repaired and share it asap. This feature was removed because... well, long story. I'm sure you heard it.
The difference might be because of a difference in averaging. Since the veedub combine is intended to combine to adjacent fields which may or may not align it is probably blurring the image somewhat. Layer doesn't do this - it just adds'em up and divides by two on each pixel.
Man, I suck as a typist.
trbarry
3rd July 2002, 07:17
I always wondered if this would work. I never got around to it (and won't) but thought it might be useful to capture from VHS multiple times, maybe even from different tapes and VCRs, and then average them.
But I was never sure I'd be able to keep them lined up properly and was too lazy to write a program that would do it right, even if I knew how.
But the way I was thinking, I'd capture 4 times and then use a median filter, taking the average of the center two samples of each frame and tossing out the outliers.
- Tom
Originally posted by poptones
Layer used to work wiht yuy2, and it wil be made to again. If no one else does it first I'll get my code repaired and share it asap. This feature was removed because... well, long story. I'm sure you heard it.
No rush :)
The difference might be because of a difference in averaging. Since the veedub combine is intended to combine to adjacent fields which may or may not align it is probably blurring the image somewhat. Layer doesn't do this - it just adds'em up and divides by two on each pixel.
The vdub filter is working the same way, just that instead of two source files it has two pointers to the same file, one offset half the width to the right. They are both aligned the same with Trim beforehand. The only difference I can see is that with mine Telecide is run before the averaging, with layer it's run after. So mine is working on progressive frames, layer is working on interlaced. So, they shouldn't produce exactly the same results, but for the most part it ought to come out in the wash. I have a hard time accepting that explanation for a ~10% difference. I had to delete the source files to make room for a cap last night, or else I would try running telecide on the two clips first then layer.. but that again has it's own set of problems, as even though both are aligned to start with Telecide may produce different output for each.
-Leuf
sh0dan
3rd July 2002, 17:38
You could use Luma / Chroma Merger (http://cultact-server.novi.dk/kpo/avisynth/merge_as.html) to merge two sources in Avisynth. So a script like this:
(import stuff)
avisource("file 1")
avi2=avisource("file 2")
mergeluma(avi2,0.5)
mergechroma(avi2,0.5)
That should give you an exact average of the two sources (and be much easier and faster than using vdub). Be aware of your colors - there may be a bug in mergechroma in weighed mode - but it may also be related to a specific testcase - if so, please mail me, or post here.
Milkman Dan
7th July 2002, 06:44
How did you deal with dropped frames?
This sounds like a very interesting method indeed.
poptones
7th July 2002, 12:27
On the examples I posted with the garbage video, it was a direct stream rip from a satellite; there were no dropped frames. For other stuff I've found it's not terribly difficult if you have a decent capture. If there are more than a very few, I just run it over. For a few, it's pretty easy to find the frame that loses sync, duplicate it (or trim the other clip) and go on to the next. It's confusing the first time or two, but it's something quickly learned.
Didée
7th July 2002, 19:16
A direct stream rip from satellite ... do I get you right: Satellite´s MPEG-2 data directly to HD?
If so, could you share some more of your skills? (although you already share very much!)
poptones
7th July 2002, 20:32
My secret: connections in germany.
I didn't do the rip. Apparently there is a very big underground in europe of people who have created linux PC add-ons to certain models of satellite receivers. I can't recall the brand but I'm certain it's a very well known euro brand and - get this - it has a SCSI port on the back! People have created all sorts of useful tools based around this. Rather than ripping DVDs, they can just as easily rip right from the satellite in "perfect" (ahem) digital quality.
Through indirect connections with mutual garbage fans a couple of us here in the states managed to get "an evening with garbage" - WDR broadcast three back to back episodes of the german rock concert type show "Rockpalast" (very cool, just go to wdr.de or whatever it is).
The supremely cool part was they rebroadcast two of the shows (the best ones) immediately after! So I have about a dozen discs here (something around 11GB) which I have been hoping to "remaster" and commit to a pristinely beautiful DVD collection (all 3 shows, or at least the best two).
It's what got me "serious" about working on avisynth, in fact, cuz I was just frustrated to death futzing around in Adobe's stuff (not to mention I just kinda despise them in general) and I really really want to make this look good. So, in a way, just getting this already broadcast show to DVD has been the source of about a year of on and off creation for me.
Yeah, I could just "rip" it. But there's no fun (to me) in that. I wanna "art it all up" and to do that I need good tools. Basically this is the same thing I ended up doing when I took scientific visualization in college. Soon as I learned the file formats in Wavefront, I spent the rest of the semester writing cool tools to morph models rather than actually trying to make a demo reel.
Too much info?
Anyway, with the loop() filter dividee recently added I think it just got a LOT easier to fix misalingments between analog captures.
Leuf
10th July 2002, 19:17
Originally posted by sh0dan
That should give you an exact average of the two sources (and be much easier and faster than using vdub). Be aware of your colors - there may be a bug in mergechroma in weighed mode - but it may also be related to a specific testcase - if so, please mail me, or post here.
Well, I've had the chance this week to capture Witchblade twice, since TNT are nice enough to repeat it the following day. I've been anxious to try it out on this, as my TNT source is among my worst channels for noise and so far I haven't come up with a filter chain for it that I'm happy with the results from.
So, I tried again this time using all 3 methods we've discussed in this thread, my vdub filter, layer, and merge.
First I did up to the opening credits back to huffyuv to compare file sizes again.
vdub: 1,377,366
merge: 1,349,376
layer: 1,472,616
So, again it seems like layer is high for some reason. I tried again on just the first 500 frames, and didn't use decomb this time so I could compare to the original frames.
vdub: 111,456
merge: 109,722
layer: 119,562
I then picked a frame at random and looked at the 2 sources and outputs closeup in photoshop. What I've concluded is that layer doesn't seem to be producing an average of the two, it's weighed more to the first clip. I've been using amount = 128. For example, given source 1 (179,180,177) source 2 (181,184,177) layer produced (180,181, 178) Though there are some colorspace conversions going on that account for some error. This is the only explanation I can come up with to account for the different filesizes.
With Merge there *does* seem to be something fishy going on with the color, though it's difficult to pin down exactly. There isn't a huge difference between the two sources + colorspace conversions, it's hard to tell. But my first reaction when I loaded it was there was more green. In looking at the values it seems more like the green is right, but R+B are too low, sometimes lower than were in either source pixel. Example: source 1 (19,15,16) source 2 (20,18,19) merge produced (18,16,14)
-Leuf
poptones
10th July 2002, 19:42
There are a couple of sources of error. One is simply the math is based on 255 (8 bits) but then it is divided by 256 (shift 8). So right there you have a tiny bit of error. And because of the weightings applied to colorspace, it's going to effect blue the least, and green the most. No getting around it.
One could use "c math" to do it all, but then it's significantly slower. The tradeoff is a tiny bit of error in exchange for much faster execution.
This is the place where I started thinking about going to 16 bits before. If all calculations were done in 16 bits there'd be far less error (which is a good reason the "high end" applications have gone there, considering the much smaller speed tradeoffs) but it would be a LOT of work to port all these filters to supporting 16 bit planes.
For merging there's going to be far mroe error. Especially when you're just "merging." Color is determined by luminance and chroma, so just blindly overwriting one with the other is going to have indeterminate results.
const int scaled_y = (y1+y2 - 32) * int(255.0/219.0*32768+0.5);
const int b_y = ((rgb[0]+rgb_next[0]) << 15) - scaled_y;
yuv[1] = ScaledPixelClip((b_y >> 10) * int(1/2.018*1024+0.5) + 0x800000); // u
const int r_y = ((rgb[2]+rgb_next[2]) << 15) - scaled_y;
yuv[3] = ScaledPixelClip((r_y >> 10) * int(1/1.596*1024+0.5) + 0x800000); // v
The most "perfect" solution would be to go to 16 bits. this would also put avisynth on par (in this respect) with stuff like premeire and vegas. I think I could even handle most of the filters, but I have no idea what's going on deeper where frames get created and passed around.
waka
10th July 2002, 22:13
I played around with averaging clips together not too long ago and it works quite well. With my source, so-so cable, the benefit became pretty minor after 4 or 5 blends. Almost indistinguishable in individual frames. File sizes do give a rough idea of the improvement you can expect. The following is from a 100 frame, huffyuv sample.
1 source: 23.9 megs
2 sources: 22.0
3 sources: 21.5
4 sources: 20.8
5 sources: 20.5
I didn't bother going any further as the difference was very minor at that point. I imagine dirtier samples would still show improvement at 5+ sources. The first blend was done using a method I put together in vdub, subsequent blends were done with layer in an earlier avisynth build by poptones.
I am currently trying out avisynth 2.0.1.1 and layer isn't working like I expect it to.
I expect clip1.layer(clip2,"add",128,0,0,use_chroma=true) to average the 2 clips. More often than not, it seems to just spit out clip1 and not a blend. Have there been issues worked out in the layer code since 2.0.1.1, or am I misunderstanding layer? Any help would be greatly appreciated as this is driving me insane.
Thanks
dividee
10th July 2002, 22:51
In RGB32, you should make sure the second clip has an opaque mask in the alpha channel before calling Layer:
clip2.Mask(clip2.BlankClip(color=$FFFFFF))
waka
10th July 2002, 23:08
That did it.
Thanks again.
Leuf
10th July 2002, 23:43
Hmmm, well I tried just doing mergeluma, leaving the chroma alone, ended up with a size of 1,360,944. Which is pretty much square in the middle between what the RGB and luma/chroma averages gave. No color problems, and it's the fastest method. For say a vhs source I wouldn't want to leave out the chroma, but it seems to be okay for this cable source.. and still more compressible than the RGB average.. which is pretty interesting. I guess since the codec ultimately has to store it as YUY2 that makes sense.
Time to try a full encode..
-Leuf
Richard Berg
11th July 2002, 04:05
If I had a P4 I'd push for 16-bit in a second -- they can twiddle 4x16 integers exactly the way MMX procs can do 4x8 so there'd be no loss of speed at all.
poptones
11th July 2002, 05:48
but most of the core stuff isn't yet mmx'd. I mean a lot is, but not so much as to be daunting. A good bit of it would be changing BYTEs to WORDS and such. The c code math is (mostly) ints anyway, right? A lot of that would just be adjusting shifts and coefficients.
compare "layer."
:loopstart
movd mm6, [esi + ecx*4] ;src2
//change to movq
movq mm2,mm6
//no change
psrlq mm2,24 ;mm2= 0000|0000|0000|00aa
//change to psrlq mm2,48 - big deal
pmullw mm2,mm1 ;mm2= pixel alpha * script alpha
//changes to pmadd mm2,mm1 - easy cuz it's mostly zeroes ;)
//BTW we use 15 bit coefficient here and now we have "almost perfect" math
movd mm7, [edi + ecx*4] ;src1/dest
//another movq
psrlw mm2,8 ;mm2= 0000|0000|0000|00aa*
// scale change - big deal again
punpcklwd mm2,mm2 ;mm2= 0000|0000|00aa*|00aa*
punpckldq mm2, mm2 ;mm2=00aa*|00aa*|00aa*|00aa*
//no change
movd mm3, rgb2lum
//one more movq
//----- alpha mask now in all four channels of mm3
punpcklbw mm7,mm0 ;mm7= 00aa|00bb|00gg|00rr
punpcklbw mm6,mm0 ;mm6= 00aa|00bb|00gg|00rr
//these two actually go away!
pandn mm6, mm4
//for subtract only - no change
//----- begin the fun stuff
//----- start rgb -> monochrome
pmaddwd mm6,mm3
punpckldq mm3,mm6
paddd mm6, mm3 ;32 bit result
psrld mm6, 47 ;8 bit result
punpcklwd mm6, mm6 ;propogate words
punpckldq mm6, mm6
//----- end rgb -> monochrome
//with 15 bit coefficients, this is essentially unchanged!
psubsw mm6, mm7
//no change
pmullw mm6, mm2 ;mm6=scaled difference*255
//this part actually adds a few ops - perhaps as many as five
//for pmov mm1,mm6/pmullw mm1,mm2/pmullhw mm6,mm2 and then recombining
//- but I don't feel like figgering it out right now ;)
psrlw mm6, 8 ;scale result
//scale changes - big deal
paddb mm6, mm7 ;add src1
//becomes paddw
//----- end the fun stuff...
packuswb mm6,mm0
//more history
movd [edi + ecx*4],mm6
//becomes another movq
inc ecx
cmp ecx, edx
jnz loopstart
Granted it's only one routine, but it does quite a bit - one conversion RGB to monochrome (which costs nothing extra at all!) and the "math" part is only negligibly longer, part of which is offset by the fewer pack/unpack instructions - which occupy most of the time in this, BTW, and which cannot be paralleled. So the entire routine could end up executing almost the exact same speed, but with greater accuracy!
I wouldn't mind tackling the colorspace conversions with this, and I'd definitely tackle the c-code filters, but I don't know how much of the core relies on the assumption of 8 but planes.
Sure would be nice. One could even leave the "old" routines alone and just add new support for 16 bit formats.
Hmmm... How hard would that part be?
Richard Berg
11th July 2002, 05:57
I'd just have to double-check every filter to make sure they don't implicitly assume "if it's not RGB24 or RGB32 it must be YUY2" or similar. Way easier than the planar formats someone proposed in another thread, in any case.
UGAthecat
11th July 2002, 07:31
ok, I know that the layer and merge filters have a lot of great uses, but aren't they overkill for just averaging frames together to make a new, hopefully less noisy, frame?
thinking along the lines of KISS, why not just make a filter that takes the 2 frames, adds them together, and then divides the result by 2. Or to get simpler to optimize (but slightly less acurate) divide each frame by 2, and then add them together. doing the division first you can keep all the values 8bit and fully mmx optimizeable.
I know this wont give you the option to do all of the cool stuff listed by poptones on the article linked from ars, but it would be insanely fast and good enough for use with sources that aren't incredibly noisy.
poptones
11th July 2002, 09:01
It would save about two ops by getting rid of the alpha channel support.
Seriously. Go look at the code.
If you're using a prefab build from sourceforge you may not have the latest version. The MMX optimized YUY laering is just about as fast as it can be. I'm working on some op reordering, but it's already pretty damn fast.
Dividing first and then adding would increase the potential for error pretty badly. There's already subtle color shift (try YUY layering wiht transparency at 128 over about ten layers) and truncating one lsb from each op would only make it worse. I'm trying to get more accuracy, not less!
poptones
11th July 2002, 11:04
OK, on second thought I figured it's two easy to avoid. Sorry for shooting you down so quickly.
So I went in and stripped everything out. I added a mode called FAST. If you use layer() like this:
clip.layer(otherclip,"fast")
It does exactly what you describe: it loads in a quad, shifts everything right one bit, masks out the MSB (there are few packed byte instructions - masking is the only way to do this), adds'em, and spits'em back into memory. There is a slight perceptible difference, but it didn't look too noticeable on my casual inspection.
Yes, it's faster. It does two pixels at a time in RGB and four at a time in YUY2, and the inner loop is half the size (11 instructions, perhaps 6-10 clocks) of the other (add, subtract, etc) operations.
I'll get the changes up to the server soon as I figure out why tortoise won't connect. Would you like me to post a dll? I'm reluctant to do so (and screw up revisioning), but will if you really really can't wait.
dividee
11th July 2002, 11:59
Isn't it be a perfect case to use PAVGB instead ? ;)
poptones
11th July 2002, 12:28
It would if I had something newer than a PII to test it.
I added three instructions that makes it "almost perfect." Simple mask/store/add restores the LSB from one of the sources. So for averaging two sources it's +- 1/2lsb, which is pretty good. And with AMDs it should (I think) execute the inner loop in about 9-10 clocks, intels would be 13 (doesn't the AMD have two shifter paths? I thought so anyway.)
I'd like to play with the fancier stuff, but I ain't got a PIII.
BTW can you help me with tortoise? I can't get it to connect and I'm wondering if there's some magic involved. I installed it, but the usage directions are pretty poor.
dividee
11th July 2002, 13:19
I forgot you only have a PII.
For Tortoise, it wasn't hard to configure. I didn't had any success with the old "stable" 0.44, but the "unstable" 0.54 version works well.
Choose Secure shell ( :ext: ) as Protocol, cvs.avisynth2.sourceforget.net as Server, /cvsroot/avisynth2 as repository directory and your sourceforge username. No quirks.
Wilbert
11th July 2002, 14:06
I'll get the changes up to the server soon as I figure out why tortoise won't connect. Would you like me to post a dll? I'm reluctant to do so (and screw up revisioning), but will if you really really can't wait.
Please do, cause I want to make a comparison tonight. Waka also posted a nice method somewhere in the ars-forum a while ago.
btw) What do you mean by tortoise?
UGAthecat
11th July 2002, 19:26
@poptones
I'm in no hurry, I just figured it would be fairly quick (processing wise) and not incredibly inacurate (maybe results will be off by 1, which for 0-255 isn't all that bad) but I guess there is demand from others.
Also, I take no offense at being shot down. I know that something that may seem easy to me could be quite a bit more difficult to implement, as I don't really know much about the innards of avisynth, or the difficulties in dealing with different colorspaces, etc.
In any event... thanks for the intrest, and incredibly quick response!
Wilbert
12th July 2002, 09:53
Ok, I made a little test. I used two methods, the first one is described in this thread Wakas method (http://arstechnica.infopop.net/OpenTopic/page?a=tpc&s=50009562&f=67909965&m=6050925074) and the method mentioned in this thread:
method 1)
Using AviSynth 2.0.1. The script is given by:
Import("C:\install\avisynth\vdub_filters.avs")
interleave(AviSource("F:\clip1.avi"),AviSource("F:\clip2.avi"))
# Gives a clip of 814 frames. Frame 001 is the first frame of clip1, frame 002 is the first frame of clip2,
# frame 003 is the second frame of clip1, etc.
AssumeFieldBased()
# The clip is assumed to have 814 fields.
Weave()
# The fields are weaved together. Thus frame 1 = field 1 (frame 001) and field 2 (frame 002), frame 2 = field3
# (frame 003), etc. Thus the odd lines of frame 1 correspond to frame 001 and the even lines of frame 1
# correspond to frame 002, etc. Resolution is 704x1152.
ConvertToRGB32()
VD_GeneralConvolution3D("input","000","000","000","000","000",
\ "000","000","080","000","000",
\ "000","000","080","000","000",
\ "000","000","000","000","000",
\ "000","000","000","000","000")
# line x and line x+1 are blended by the same amount (080 hexadecimal = 128 decimal)
SeparateFields()
SelectOdd()
# The even lines (which correspond to the second clip are thrown away).
Levels(3,1.03,255,8,240)
# Adjust the colors.
time: 2:35, pictures: picture3(interleave).jpg and picture4(interleave).jpg
method 2)
Using AviSynth 2.0.1 and layer/mask. The script is given by:
clip_1=ConvertToRGB32(AVISource("F:\clip1.avi"))
clip_2=ConvertToRGB32(AVISource("F:\clip2.avi"))
clip_3=Mask(clip_2,BlankClip(clip_2,color=$FFFFFF))
clip_4=Layer(clip_1,clip_3,"add",128,0,0,use_chroma=true)
Levels(clip_4,3,1.03,255,8,240)
time: 1:18, pictures: picture5(layer_mask).jpg and picture6(layer_mask).jpg
With both method the noise is nicely reduced while keeping detail. For some reason the deinterlacing effects disappeared using the first method (maybe because of the smoothing). While it is still present using the second method. Besides that I don't see a difference between the two methods except that the first method is much slower.
I also included two pictures picture7(2dcleaner_1_255).jpg and picture8(2dcleaner_1_255).jpg where I used 2d_cleaner with radius 1 and threshold 255 on just one of the clips. Note that it is less detailed and still more noisy as the in the above two methods.
I attached a file with all pictures (including the original) and avs-scripts. I hope the mod. approves it since I don't have a homepage.
Wilbert
12th July 2002, 10:07
Forgot to attach the file ...
waka
12th July 2002, 16:43
The 3x3 general convolution built into vdub is significantly faster than that in avisynth, at least as of 2.0.1. It still is a little bit slower then the layer method though. Also if you try selecteven, or discard field 2 in vdub, I think you will find that all interlacing remains. Selectodd would be like a blend deinterlace. That is all probably a moot point as layer seems to the better method given that it is faster, more powerful, and the end results are pratically identical. Either way, nice writeup.
Wilbert
12th July 2002, 17:13
.The 3x3 general convolution built into vdub is significantly faster than that in avisynth, at least as of 2.0.1.
That's the one I was using.
Also if you try selecteven, or discard field 2 in vdub, I think you will find that all interlacing remains. Selectodd would be like a blend deinterlace.
First point. I don't understand what you are saying here. Why does it matter whether you discard field 1 or 2?
Second point. Discarding field 2 in VDub is the same as "clip.SeparateFields.SelectOdd" in AviSynth, no? Whereas as discarding field 1 is similar to "clip.SeparateFields.SelectEven" in AviSynth. I haven't checked it but I don't think it matters whether you discard field 1 or field 2 (I will do that in the weekend).
As can be seen in the pictures, in the layer method interlacing effects remain.
I will try again to attach the file, otherwise you have to wait until monday. For some reason I can't attach the file ...
waka
12th July 2002, 19:19
Hmm, what I meant was to write an avs for the first half of the process(interleave, weave) and use virtualdub to do the second half(convolution, drop a field). The 3x3 convolution internal to virtualdub is faster than the 5x5 convolution 3d written by Gunnar. I was under the impression that the 5x5 is the one in avisynth and thus what you were using. Anyhow it doesn't particularly matter, my apologies if I am misunderstanding you.
As for the field thing, I can't explain it clearly so try this instead.
black=blankclip(height=240)
white=blankclip(height=240,color=$ffffff)
clip=interleave(black,white).assumefieldbased.weave
#pretend this black and white frame is our original capture
interleave(clip,clip).assumefieldbased.weave
generalconvolution(0,"0 128 0 0 128 0 0 0 0")
separatefields.selecteven
The output is alternating black and white like it should be, however if we use selectodd instead of selecteven we get all grey instead of black and white.
poptones
12th July 2002, 21:30
I hope people don't get to used to using the mask() command for "blank" clips. It's not needed except on the versions where the old convertToRGB32() snuck out. If you convert to RGB32, the mask is set by default - no need for a mask that just slows things down.
And I still haven't managed to get tortoise to connect with sourceforge. I really don't get it; if I click "get tortoise CVS" it works fine, hooking up to the server and grabbing the modules. It also works for the other "preset." But I can't seem to get into this project at sourceforge even 'tho I have triple checked the settings for server, path, etc.
Anyway, you might like to try this DLL. It is a build of the very latest source including my most recent tweaks to the layer and mask filters AND a convertToRGB32() that returns the mask in the proper state (although it won't be needed in this example anyway, because "fast" mode ignores the mask info).
http://personal.ayrix.net/~poptones/avisynth.zip
For your test all you really need is this:
layer(clip1,clip2,"fast")
levels(whatever)
That's it. Let us know how it compares.
Richard Berg
13th July 2002, 03:04
If you can grab put not commit, chances are it's an authentication thing since the server is read-only if it thinks you're anonymous. What are you using for SSH, or does tortoise have that built-in?
poptones
13th July 2002, 03:57
Allegedly it's built in. I just don't get it. I can't even "get" much less "commit." I made the .ssh directory, set the system HOME variable, but when I try to connect using ext it just sits there. At least the other methods give me error messages.
Finally! A bit of success. At least it's pulling down the modules. Perhaps I can get this update sent in tonight.
dividee
13th July 2002, 23:19
Just another way to average captures, when you have an odd number of them:
Interleave(clip1,clip2,clip3)
TemporalSoften(1,255,255)
SelectEvery(3,1)
It makes me think to put my MMX version of TemporalSoften in the CVS.
Poptones, I saw you finally defeated the tortoise :D
poptones
14th July 2002, 00:10
Ayup, I finally whipped the turtle. Only took a few days... ;)
I just sent another revision. This one has multiply for both RGB32 and YUY2. This means it now supports, in both modes, Add, Subtract, Mul, and Fast. It also now supports Lighten and Darken (with thresholds) in RGB32. Ironically, the YUY version is proving harder to get than the RGB version where everything has to be converted into luminance before any ops can be done!
Here's my latest tip. I'm trying to put together a collection of them for a good how-to on video FX processing in avisynth.
Multiply is really good for making masks. One thing you can do pretty readily is make a filter that blends only the stationary objects across an arbritrary number of frames. Other, optimized methods exist, but this is a good example to illustrate the effective application of math beyond simple "add" and "subtract."
#This is a sobel edge detection along both axis...
hor=filt.generalconvolution(0,"-1 0 1 -2 0 2 -1 0 1")
vert=filt.generalconvolution(0,"-1 -2 -1 0 0 0 1 2 1")
edgemask=hor.layer(vert,"lighten",255,0,0)
#This "burns" the light patches by effectively squaring every value.
#Try this next line alone with a clip and see how it works
edgemask=edgemask.layer(edgemask,"mul",255,0,0)
#blur around edges to help reduce "flickering" - set radius as desired
edgemask=edgemask.generalconvolution(0,
"10 10 10 10 10
10 10 10 10 10
10 10 16 10 10
10 10 10 10 10
10 10 10 10 10")
#this sets sensitivity. Play with input and output thresholds
#and gamma to see for yourself how it works
edgemask=edgemask.Levels(0,.95,128,0,255)
#and the cool part; zero times any number is what?
#Ayup, anything not present across both frames gets removed.
#Extend precision as long as you like by adding more layers...
motionmask=edgemask.layer(edgemask.trim(1,0),"mul",255,0,0)
#Why set levels twice? This one sets the "amount" of function.
#the one above controls the sensitivity to motion across frames
motionmask=motionmask.Levels(0,.5,64,0,255)
#Now apply the mask to a copy of the clip
motion=clip.mask(edgemask)
#and sum the temporally shifted copy with the original.
clip=clip.layer(motion.trim(1,0),"add",128,0,0)
Note again that FAST mode ignores ALL alpha info. You gotta sum, multiply, subtract, lighten or darken for this to work.
There are more optimized special purpose filters that do most of this, but knowing how to use layers and masks will give you the chance to quickly and easily create just about any nonlinear function you care to try. Save them as functions and you can create a whole library of custom filters using nothing more than notepad.
dividee
14th July 2002, 05:28
I assume clip=filt ;)
AFAIK, your filter won't blend (denoize) the stationary objects as a whole but only the edge of them.
Also I found a little mask synchro problem; the end of the script should be
#Now apply the mask to a copy of the clip
motion=clip.trim(1,0).mask(edgemask)
#and sum the temporally shifted copy with the original.
clip=clip.layer(motion,"add",128,0,0)
And with the avisynth version currently in the CVS, I still had to use Mask after AVISource.
One thing you can do pretty readily [...]
You may do such things "readily", but it's not my case. I think it took me longer to understand it than you to write it ;)
poptones
14th July 2002, 07:10
Ah, bu tyou are thinking backwards! Or, perhaps you are thinking too "clearly.
You START with a blurred "base." Blur it as much as you like. Call it "blur" (har). Then on TOP of that "blur" you add the lines - like painting a watercolor and then inking in the lines...
BTW, yes I know the zip at cvs has not been rebuilt yet. I'm leaving it up to someone else to decide when the time is right to step to the next revision. And truthfully I'm not yet ready to say the layer module evne should be committed to another "official rev." I'd like to squash a bug or two, and I honestly feel I'm just a weekend away from having the new operations working in yuy2 as well.
But if you can compile it yourself then all this should be working. Even the mask. I checked the source for that module and it looked like it had been revised.
dividee
14th July 2002, 09:43
hehe got it now. I just assumed clip=filt and didn't give it a second tought.
:stupid:
But I was talking about the source in the CVS, not the zip! I just did a Rebuild All to be sure, and the mask is incorrect just after AVISource. And the source.cpp hasn't been updated for 8 days. Maybe the behaviour depends on the decompressor of the AVI file ?
Kaizen
14th July 2002, 14:29
Attaching for Wilburt.
I wonder what the problem was.
poptones
14th July 2002, 17:59
And with the avisynth version currently in the CVS, I still had to use Mask after AVISource.
Doh! Got it now. I fixed the part in convertToRGB32() but never went after the source.
Mkay, so it works after conversion, but not if you just "open" an RGB32 file. I'll look into that one.
Wilbert
15th July 2002, 09:20
@kaizen,
Thanks for attaching the file. Maybe it is because the filename which had the form "filename..zip". I didn't see that until Chris told me so.
@Poptones and the other sourceforge people:
I hope people don't get to used to using the mask() command for "blank" clips. It's not needed except on the versions
where the old convertToRGB32() snuck out. If you convert to RGB32, the mask is set by default - no need for a mask that
just slows things down.
This is really weird (bug in ConvertToRGB32 ?):
# showed only shakira:
clip1=ConvertToRGB32(AVISource("F:\shakira-underneath_your_clothes.avi")) # uncompressed
clip2=ConvertToRGB32(AVISource("G:\atomic_kitten.avi")) # compressed with ASUS video codec
clip3=trim(clip2,100,506)
Layer(clip1,clip3,"add",128,0,0,use_chroma=true)
# showed shakira and atomic kitten:
clip1=ConvertToRGB32(AVISource("F:\shakira-underneath_your_clothes.avi"))
clip2=ConvertToRGB32(AVISource("G:\atomic_kitten.avi"))
clip3=trim(clip2,100,506)
Layer(clip3,clip1,"add",128,0,0,use_chroma=true)
# showed shakira and atomic kitten:
clip1=ConvertToRGB32(AVISource("F:\shakira-underneath_your_clothes.avi")) # uncompressed
clip2=ConvertToRGB32(AVISource("G:\atomic_kitten.avi")) # compressed with Huffyuv codec
clip3=trim(clip2,100,506)
Layer(clip1,clip3,"add",128,0,0,use_chroma=true)
# showed shakira and atomic kitten:
clip1=ConvertToRGB32(AVISource("F:\shakira-underneath_your_clothes.avi")) # uncompressed
clip2=ConvertToRGB32(AVISource("G:\atomic_kitten.avi")) # compressed with ASUS video codec
clip3=trim(clip2,100,506)
clip3=Mask(clip3,BlankClip(clip3,color=$FFFFFF))
Layer(clip1,clip3,"add",128,0,0,use_chroma=true)
Haven't tried any other codecs.
@all:
Why does the following result in a red clip, and not in a white clip?
white = blankclip(width=352,height=288,color=$ffffff)
red = blankclip(width=352,height=288,color=$ff0000)
interleave(white,red).assumefieldbased.weave # result: line1 red, line2 white, etc. (why?), with resolution 352x576
separatefields.selectodd() # red clip
@Waka:
Hmm, what I meant was to write an avs for the first half of the process(interleave, weave) and use virtualdub to do the
second half(convolution, drop a field). The 3x3 convolution internal to virtualdub is faster than the 5x5 convolution 3d
written by Gunnar. I was under the impression that the 5x5 is the one in avisynth and thus what you were using. Anyhow
it doesn't particularly matter, my apologies if I am misunderstanding you.
You are right that differs a lot. The encoding time was 1:15 instead of 2:28!
As for the field thing, I can't explain it clearly so try this instead.
black=blankclip(height=240)
white=blankclip(height=240,color=$ffffff)
clip=interleave(black,white).assumefieldbased.weave
# pretend this black and white frame is our original capture
interleave(clip,clip).assumefieldbased.weave
generalconvolution(0,"0 128 0 0 128 0 0 0 0")
separatefields.selecteven
The output is alternating black and white like it should be, however if we use selectodd instead of selecteven we get all
grey instead of black and white.
Ok, I understand. Back to my test-scripts:
Ending on "selecteven" results in frames with:
line1 = (line1_clip1+line1_clip2)/2
line2 = (line2_clip1+line2_clip2)/2
and the deinterlacing effects remain.
Ending on "selectodd" results in frames with:
line1 = line1_clip1
line2 = (line1_clip2+line2_clip1)/2
line3 = (line2_clip2+line3_clip1)/2
and the deinterlacing effects are smoothed out.
What do you think of the last method, as a method of filtering noise
and cleaning up the remaining deinterlacing effects (= method 1)?
I also use a deinterlacer (smart deinterlace gave good result, wasn't satisfied with area based deinterlace) to clean up the deinterlacing effects on the
method 2) output clip --> time: 2:54
method 3) input clips --> time: 3:09
Although the result are a bit better than method 1. If you take the encoding time into account, 1:15, the first method is also nice. What do you about that?
@Poptones and others:
Anyway, you might like to try this DLL. It is a build of the very latest source including my most recent tweaks to the layer
and mask filters AND a convertToRGB32() that returns the mask in the proper state (although it won't be needed in this
example anyway, because "fast" mode ignores the mask info).
http://personal.ayrix.net/~poptones/avisynth.zip
For your test all you really need is this:
layer(clip1,clip2,"fast")
levels(whatever)
That's it. Let us know how it compares.
Clips are both 407 frames:
clip1=ConvertToRGB32(AVISource("F:\shakira-underneath_your_clothes.avi"))
clip2=ConvertToRGB32(AVISource("F:\shakira-underneath_your_clothes2.avi"))
clip3=Layer(clip1,clip2,"add",128,0,0,use_chroma=true)
Levels(clip3,3,1.03,255,8,240)
# time 1:18 (without cleaning up deinterlacing effects)
clip1=ConvertToRGB32(AVISource("F:\shakira-underneath_your_clothes.avi"))
clip2=ConvertToRGB32(AVISource("F:\shakira-underneath_your_clothes2.avi"))
clip3=Layer(clip1,clip2,"fast")
Levels(clip3,3,1.03,255,8,240)
# time 1:19 (without cleaning up deinterlacing effects)
Sorry, the reduces version appears to be slower ...
dividee
15th July 2002, 21:09
This is really weird (bug in ConvertToRGB32 ?):
# showed only shakira:
clip1=ConvertToRGB32(AVISource("F:\shakira-underneath_your_clothes.avi")) # uncompressed
clip2=ConvertToRGB32(AVISource("G:\atomic_kitten.avi")) # compressed with ASUS video codec
clip3=trim(clip2,100,506)
Layer(clip1,clip3,"add",128,0,0,use_chroma=true)
[...]
The ASUS codec is probably outputting RGB32 data, so ConvertToRGB32 is bypassed and the mask isn't applied. Should work if you change it to ConvertToRGB32(ConvertToRGB24(AVISource("...")), but it's probably faster to use the Mask filter, then.
Why does the following result in a red clip, and not in a white clip?
white = blankclip(width=352,height=288,color=$ffffff)
red = blankclip(width=352,height=288,color=$ff0000)
interleave(white,red).assumefieldbased.weave # result: line1 red, line2 white, etc. (why?), with resolution 352x576
separatefields.selectodd() # red clip
Sometimes this parity thing is more confusing than helpful.
Both Weave and SeparateFields uses parity to combine or separate the fields. If you didn't look at the intermediate result you wouldn't have been surprised by the final result. If the top line of the intermediate result was red, it means that parity was bottom field first in the clip. If you add ComplementParity just before Weave, you'll have the top line white, but the final result should still be the red clip. If you add ComplementParity before SeparateFields you'll obtain the white clip.
poptones
15th July 2002, 22:46
The problems are multifold. Some software returns RGB and RGBA as the same thing - RGBA - except RGB has an inderterminate alpha channel. And convertToRGB32 will ignore it if it sees it's already RGBA, so the "indeterminate" mask doesn't get cleaned up. And there's nothing much that can be done about this problem unless you're willing to live with never being able to import RGBA video! (Which, quite frankly, might not be too big an issue... see below.) In these cases, all you can do is set a white mask yourself. Perhaps this could be better done with a special, optimized "mask" switch - I'll look into that.
Wilbert, I have a question about this, 'tho...
clip1=ConvertToRGB32(AVISource("F:\shakira-underneath_your_clothes.avi"))
clip2=ConvertToRGB32(AVISource("F:\shakira-underneath_your_clothes2.avi"))
clip3=Layer(clip1,clip2,"add",128,0,0,use_chroma=true)
Levels(clip3,3,1.03,255,8,240)
Why are you converting this to RGB twice? Or why at all? Layer works just fine with YUY2. In fact, it's twice as fast. So unless you're I/O bound on this, getting rid of the redundant RGB conversions and using the FAST mode as I suggested will cut these times dramatically. Since there's only one LAYER in there, this really isn't much of a benchmark, except as as measure of total system throughput.
clip1=AVISource("F:\shakira-underneath_your_clothes.avi")
clip3=Layer(clip1,clip1,"fast")
convertToRGB32().Levels(clip3,3,1.03,255,8,240)
Give that a shot and see whatcha get. I just (last night, before I committed the latest revision) went through all these modes on my PII/450 using this:
clip=avisource("garbage-test.avi")
clip=clip.layer(clip,"lighten",128,0,0).layer(clip,"lighten",128,0,0).layer(clip,"lighten",128,0,0).layer(clip,"lighten",128,0,0).layer(clip,"lighten",128,0,0)
return clip.trim(0,99)
I made two different source clips, one in RGBA and one in YUY2, by changing the conversion on the first line above and saving the file using direct stream copy. So no conversions in avisynth were done for the first round, and I threw away the first run because it was always about 50% slower. What I ended up with was approximately:
YUY2(ADD) - 12 sec
YUY2(LIGHTEN) - 12-13 sec
YUY2(FAST) - 9 sec
RGBA(ADD) - 43 sec
RGBA(LIGHTEN) - 48 sec
RGBA(FAST) - 40 sec
Then I used the YUY source for the RGBA tests, this time doing the conversion internally (on the first line, above). The results were pretty revealing:
RGBA(ADD) - 20 sec
RGBA(LIGHTEN) - 24 sec
RGBA(FAST) - 16 sec
So even 'tho I used an RGBA "source" it was much, much slower. Was it just because the YUY source file could fit in memory and the RGBA couldn't? I doubt it as I have only 256MB memory to begin. Was it the file handler? I don't know how I would test that; the files were both saved uncompressed using the standard windows file handler via veedub.
On my system, at least, 100 uncompressed frames (640x480) are more I/O bound than processing. And by extrapolating the above, it would seem I could run this test on 500 frames (still) in under a minute.
And my test was with a whole chain of'em. I really doubt you're going to see much difference in a benchmark of these filters unless you stack'em. My system will barely direct stream copy straight through avisynth at more than ten fps, and using the above benchmark it was often maxxing out (on the YUY2) at more than six fps.
I'd love to know what others get with higher end systems. If you'd care to try the above, just use a YUY2 source at 640x480. The content is irrelevant as all commands use the exact same operations for every pixel in the frame (even the booleans). All that matters is the 640x480 YUY2 source - and run it more than once.
Should I post the DLL? I hate to keep introducing new versions. These latest additions are, to me, "stable" so if mr berg want to put together a new rev on sourceforge that'd be rockin'...
waka
16th July 2002, 04:56
I did some preliminary runs using the dll from a couple posts back. This is on an xp@1710(190x9), epox 8k3a+, 512MB ram. Times for first run thrown out.
100 frames
yuy2(add) - 2 sec
rgba(add) - 4 sec
yuy2>rgba(add) - 4 sec
fast was the same
500 frames
yuy2(add) - 11 sec
rgba(add) - 49 sec
yuy2>rgba(add) - 22 sec
fast was the same
If you are interested I can do something more comprehensive, different fsb speeds, reading/writing to drives on separate ide channels, etc.
For Wilbert,
I haven't done much with interlaced stuff recently, but when I did I was never very happy with the smart deinterlacers and usually ended up blending the fields. In which case using convolution would seem to kill two birds with one stone. That said, I'm sure the deinterlacers have improved since then so I really couldn't say which way I would prefer. As for quality vs. time, I always try to go for the best quality, within reason. Of course what is reasonable for one person isn't for another. I prefer to ivtc by hand, most people would probably think that a waste. If you have the time and patience I say go with what looks best.
Edit: Now that I actually think about it, doing the selectodd wouldn't be any better than a blend deinterlace on one source, oops.
Wilbert
16th July 2002, 10:19
@poptones,
I'm a bit confused, a couple of posts back you said:
I hope people don't get to used to using the mask() command for "blank" clips. It's not needed except on the versions where the old convertToRGB32() snuck out. If you convert to RGB32, the mask is set by default - no need for a mask that just slows things down.
IOW, ConvertToRGB32 => no mask needed
Does that mean that if your input is YUY2 that you have to you mask?
But above you asked:
Wilbert, I have a question about this, 'tho...
clip1=ConvertToRGB32(AVISource("F:\shakira underneath_your_clothes.avi"))
clip2=ConvertToRGB32(AVISource("F:\shakira-underneath_your_clothes2.avi"))
clip3=Layer(clip1,clip2,"add",128,0,0,use_chroma=true)
Levels(clip3,3,1.03,255,8,240)
Why are you converting this to RGB twice? Or why at all? Layer works just fine with YUY2.
First the two clips are two different (that was the whole point: use two different clips for removing noise, they are RGB_something) and second because the mask is than set by default (like you said above).
I will do your proposed checks tonight.
@dividee
The ASUS codec is probably outputting RGB32 data, so ConvertToRGB32 is bypassed and the mask isn't applied. Should work if you change it to ConvertToRGB32(ConvertToRGB24(AVISource("...")), but it's probably faster to use the Mask filter, then.
I will check that ... About this red-white clip:
If you didn't look at the intermediate result you wouldn't have been surprised by the final result.
The problem is, that I was surprised looking only at the final result. Let's look more closely at the following two scripts
interleave(white,red)
Result: frame1=white, frame2=red, frame3=white, right?
interleave(white,red).assumefieldbased
Result: frame1_topfield = frame1 = white, frame1_bottomfield = frame2 = red, why is this false or is true? Why is the parity: bottom field first?
Sorry for asking those basic questions :confused:
@waka
As for quality vs. time, I always try to go for the best quality, within reason. Of course what is reasonable for one person isn't for another. I prefer to ivtc by hand, most people would probably think that a waste. If you have the time and patience I say go with what looks best.
The problem is that I can't go for ivtc, I live in a pal-country.
poptones
17th July 2002, 01:05
But if you don't need the mask features (and you don't for simple layering for noise reduction) then you don't need to run the conversions unless your source is RGB (24 bit, not 32 bit). If the source is YUY or RGBA, all you need to do is layer them:
source1.layer(source2,"Fast")
No need to set masks or convert, because "fast" ignores the masks. It just adds'em up and divides by 2 - that's it.
The other part - I dunno. I've not looked into it too deeply, as the only thing I use separatefields for is to perform fieldwise processing.
WarpEnterprises
17th July 2002, 08:47
Wouldn't it be good to combine
MergeLuma, MergeChroma, Layer
into one function?
It seems that all 3 do alike things, only the user gets confused.
Or is it not true that MergeChroma(MergeLuma, 0.5) , 0.5) = Layer("fast")?
Wilbert
17th July 2002, 09:25
@dividee
The ASUS codec is probably outputting RGB32 data, so ConvertToRGB32 is bypassed and the mask isn't applied. Should work if you change it to ConvertToRGB32(ConvertToRGB24(AVISource("...")), but it's probably faster to use the Mask filter, then.
Well, that worked. I looked into some docs but I can nowhere find that the asus codec is outputting RGB32 data. Is there a simple way to see that? (Maybe I can find it on their homepage ...)
@poptones
But if you don't need the mask features (and you don't for simple layering for noise reduction) then you don't need to run the conversions unless your source is RGB (24 bit, not 32 bit). If the source is YUY or RGBA, all you need to do is layer them:
Ok, understood. I did the tests:
I did some preliminary runs using the dll from a couple posts back.
This is on an Athlon@1200(133x9), ASUS A7M266, 384MB DDR SDRAM
500 frames [no audio]:
yuy2(add) - [44 sec]
yuy2(lighten) - [37 sec]
yuy2(fast) - [44 sec]
rgba(add) - [78 sec]
rgba(lighten) - [49 sec]
rgba(fast) - [56 sec]
rgba -> yuy2(add) - [51 sec]
rgba -> yuy2(lighten) - [46 sec]
rgba -> yuy2(fast) - [47 sec]
dividee
17th July 2002, 09:27
@Wilbert:
interleave(white,red).assumefieldbased
Result: frame1_topfield = frame1 = white, frame1_bottomfield = frame2 = red, why is this false or is true? Why is the parity: bottom field first?
It depends. Honestly I don't know when avisynth consider something to have top or bottom field dominance. What makes things worse, in the code a bool is used for parity and I can never remember whether true=top or bottom dominance. Usually I don't care and just add ComplementParity when it does it wrong, but I admit it could be useful to have a pair of filter such as AssumeBFF and AssumeTFF.
Wilbert
17th July 2002, 09:33
That would be nice, if it isn't too much work :)
dividee
17th July 2002, 09:43
Well, that worked. I looked into some docs but I can nowhere find that the asus codec is outputting RGB32 data. Is there a simple way to see that? (Maybe I can find it on their homepage ...)
If I'm not mistaken, avisynth first asks the codec if it can decompress to YUY2, if it answers no, it fallback to RGB32, then RGB24. So it doesn't mean that the codec can only decompress to RGB32, just that it can't decompress to YUY2.
That would be nice, if it isn't too much work :)
No that should be the easiest filter I'll ever do, once I figure if true=TFF or BFF :)
[EDIT:] I have written the filter. Note that you should use it after AssumeFieldBased or AssumeFrameBased, since they both reset the parity to BFF (which make sense, if you think about it). BFF seems to be the default in avisynth. Will be in my next commit on the CVS.
poptones
17th July 2002, 18:06
Wilbert, thanks for the feedback. Now, that's really odd. I mean, I did a good bit of instruction reordering because the lighten and darken ops are more complicated, but I didn't think I had actually made them MORE efficient than the add and mul and sub!
Would you mind running this below for all three types, replacing the "lighten" with "add" and "fast?" If you and a couple others could do it and report back it would help me a lot. I honestly cannot understand how lighten could be FASTER than a simple add, but if this is common on many machines it seems obvious I need to look again at my mmx instruction sequences. I know on my "old fashion" PII it acts as I expect and your results, while pleasing, are also kinda puzzling.
clip=avisource("garbage-test.avi")
clip=clip.layer(clip,"lighten",128,0,0).layer(clip,"lighten",128,0,0).layer(clip,"lighten",128,0,0).layer(clip,"lighten",128,0,0).layer(clip,"lighten",128,0,0)
return clip.trim(0,499)
edit: never mind, I think. Are you using the latest version off sourceforge? If you are using one with c-code I can understand, as it's probably just doing a bunch of null ops and returning. To get valid lighten and darken functions you need to make a build from the cvs, as I don't believe there's a fresher build just yet.
Wilbert
18th July 2002, 12:13
@poptones,
Would you mind running this below for all three types, replacing the "lighten" with "add" and "fast?" (..)
I guess I'm misunderstanding you, but that's what I (and Waka) did (with a clip of 500 frames). I used the version you attached a couple of posts back. Let us know if/when you want us to do some more tests.
Wilbert
27th July 2002, 18:09
@dividee,
No that should be the easiest filter I'll ever do, once I figure if true=TFF or BFF. [EDIT:] I have written the filter. Note that you should use it after AssumeFieldBased or AssumeFrameBased, since they both reset the parity to BFF (which make sense, if you think about it). BFF seems to be the default in avisynth. Will be in my next commit on the CVS.
I downloaded v2.02, but it doesn't know AssumeTFF or AssumeBFF. All I can find in field.h is a function named AssumeParity, but I can't get that to work either.
dividee
27th July 2002, 18:21
Yeah, that's the one. Internally it's only one function but it maps to two script filters. But I'm sorry, I commited the filter after Richard released 2.02. I'll compile a version and send it to you.
goemon
28th December 2002, 07:42
so whats the "final conclusion" on averaging clips?
eg whats 'the script' to average 2 clips?
wotef
28th December 2002, 11:26
gee, big old bump
conclusion - it works bloody well! successfully reduces noise and saves me on average about 100mb on my 1 cd caps
simplest script would be:
clip0=avisource("capture.avi")
clip1=avisource("capture1.avi")
union=clip0.layer(clip1,"fast")
return union
goemon
28th December 2002, 12:27
so layer is the way to go then?
the result looks pretty good to me...
sh0dan
28th December 2002, 17:18
For AviSynth 2.5 you should be able to use:
clip0=avisource("capture.avi")
clip1=avisource("capture1.avi")
mergeluma(clip0,clip1,0.5)
mergechroma(clip1,0.5)
Richard Berg
29th December 2002, 11:05
Layer is still easier and faster, no?
(Disregard me if the YV12 version hasn't been compiled into a downloadable binary, or isn't working right yet, or similar. Speaking of which, has anyone tested Tweak-YV12? Worked for me, but that's never a good indication of anything ;))
goemon
29th December 2002, 11:07
so which is better? layer or merge?
what about averaging 3 sources?
wotef
29th December 2002, 14:15
layer works great in 2.5, thanks to marc fd ^__^
tweak works for me, too :)
goemon - obviously, the more inputs you have the more the random noise should be averaged out; i recall waka said the time/denoising benefits seemed to give diminishing returns after 4 inputs or so
i use two and it does well
if you're interested, have a read of this:
http://utam.geophys.utah.edu/ebooks/gg527/impro/hmwk1.html#s8
otherwise, just suck it and see
goemon
29th December 2002, 14:32
what's tweak?
anyone have a script to average 3 sources?
dividee
29th December 2002, 21:10
Originally posted by goemon
anyone have a script to average 3 sources? Just read the whole thread ;)
WarpEnterprises
29th December 2002, 22:28
3 sources can't be added completely symmetric.
You have to do something like
Layer(Layer(Clip1, clip2) , Clip3)
with the outer Layer having a smaller weight on Clip3.
sh0dan
29th December 2002, 23:57
This should be closer to average :
clip0=avisource("capture.avi")
clip1=avisource("capture1.avi")
clip2=avisource("capture2.avi")
luma1 = mergeluma(clip0,clip1,0.33)
luma2 = mergeluma(clip2,clip1,0.33)
mergeluma(luma1,luma2,0.5)
c1 = mergechroma(clip0,clip1,0.33)
c2 = mergechroma(clip2,clip1,0.33)
mergechroma(c1,c2,0.5)
Regarding merge vs. layer - the speed is probably very, very close (both are MMX optimized, and depend more on memory timing). Quality should be the same.
dividee
30th December 2002, 00:18
Since nobody bothered to re-read the whole thread, here was my solution:Interleave(clip1,clip2,clip3)
TemporalSoften(1,255,255)
SelectEvery(3,1) Should be as fast as other methods, maybe faster and theorically better quality, since only one averaging operation is done per pixel instead of two.
sh0dan
30th December 2002, 00:26
@dividee: Had forgotten that one - brilliant! It'll be exact average, and also quite fast.
WarpEnterprises
30th December 2002, 21:11
@dividee: Now I know for sure why I had the feeling somebody was missing the last time - great you are active again... :)
waka
31st December 2002, 06:30
I have a couple pics that show 1 source, 2 sources, and 4 sources for those interested.
http://mywebpages.comcast.net/jczimmerman/d1.jpg
http://mywebpages.comcast.net/jczimmerman/d2.jpg
http://mywebpages.comcast.net/jczimmerman/dc.jpg
Those were fairly clean to begin with so the jump to 4 sources wasn't astounding or anything. If you are dealing with dirty off the air type stuff, I imagine 4+ would still be beneficial. If I have more than 2 to combine, I just tack on another layer and adjust the weight accordingly. Not perfect, but close enough.
clip1.layer(clip2,"add",128).layer(clip3,"add",85)....layer(clipN,"add",256/N)
With an odd number of sources, temporalsoften should be better.
Make sure the clips are identical, except for noise of course. I have come across a movie that was shifted horizontally a couple pixels from a previous capture. Usually not a problem, but something to be aware of.
Also, if there is any non-random noise you'll end up emphasizing that as well. Some channels give me vertical bands of faint diagonal lines, typically it's hidden amongst all the other noise and not a problem. After a couple layers those lines become apparent as a vertical band that is slightly darker(or lighter, I forget) than the rest of the picture.
Didée
31st December 2002, 13:20
@ waka
And here an old topic comes up again:
Notice that you have changed colors in your layered results:
the faces as well as the beige jacket in the foreground have a greenish color cast, compared to the first picture.
Since you were actually using layer, try temporalsoften instead. In case it's still the same, try C3D instead of temporalsoften.
Time ago, the color-shifting problem was discussed in several places around here. Participiants were TemporalSmoother, Convolution3D, SmartSmootherHiQ, and maybe some more I forgot. Perhaps also TemporalSoften, but I can't recall.
It turned out that the problem was simply caused by internal rounding errors of the filters, e.g. MMX stuff, 8bit an 16bit arithmetics ... ah, such kind of stuff, what do I know. :(
I haven't personally seen such color shifting for quite some time now, but looking at your pictures, it reminded me immediately of that topic.
waka
31st December 2002, 15:02
Interesting.
I had noticed the color shift. At the time I had adjusted the capture brightness/contrast slightly to alleviate some clipping and I attributed the color change largely to that. Yeah I know, poor practice for making test samples. I just happened to have those already available on the web.
But now that you mention it, I have been somewhat irked by some things having a greenish tint. Issues with layer would go a long ways in explaining that. Examining the color instead of the noise, the change is rather obvious. I'm under the impression that marc redid a fair amount of the code for 2.5, so perhaps any problems might have been fixed. Definately requires some testing.
Thanks for bringing it to my attention.
scmccarthy
31st December 2002, 16:52
Perhaps filter the luma separately and merging the chroma back in would help as a temporary fix?
Stephen
dividee
31st December 2002, 22:28
Proper rounding is easy to forget and often cause a (very light) slowdown. Furthermore, when writing the filter, you won't think that such a small error will be visible... The error is probably present in the luma channel too, but not visible.
You might try something like: ColorYUV(off_y=2,off_u=2,off_v=2).
Since it's a rounding error, it's never superior to 1 per application of the filter. So the max value to offset should be the number of time the filter is used, and my best guess would be half of that.
WarpEnterprises
1st January 2003, 20:55
small remark on clip count:
the effect of noise reduction goes with the square root of the clip number, so 4 clips is (only) twice the noise reduction of 2 clips (assuming normal distribution of noise, which as is written not always the case).
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.