View Full Version : Using per frame conditional filtering
sh0dan
1st April 2003, 22:55
A new filter has been put into the latest AviSynth core, and it features "conditional filtering" for the first time. Note that this is a completely new feature and most likely still contain bugs!
Basic usage is:
ConditionalFilter(Clip testclip, Clip source1, Clip source2, String condition1, String operator, String condition2,[bool "show"])
What is does is like this: It chooses between source1 and source2 based on how the testclip looks. The best way to illustrate is through an example:
vid = avisource("file")
vid_blur = vid.blur(1.5)
Conditionalfilter(vid, vid_blur, vid, "AverageLuma()", "lessthan","20")
This will choose frames from vid_blur when the average luma value of a frame is less than 20. Otherwise frames from vid will be returned. Adding "true" at the end will display the actual values on the screen.
The operator can be "equals", "morethan" or "lessthan". Or "=", ">" or "<" respectively.
Both conditions can be general expressions. That means you can use all internal functions, like sin(), cos(), variables, etc. Furthermore a few very basic functions has been put in (like AverageLuma). It is possible for filters to extend these functionalities, and adding more conditional functions.
For each frame, the variable "frame_number" is updated. You can even use this in your script. For instance:
ConditionalFilter(last,last.subtitle("S1"),last.subtitle("S2"),"current_frame%4","=","0")
Be aware, that when you reference a video clip or any other variable, it will be represented by the value it has at the end of the script.
The internal functions (so far) are:
AverageLuma(clip),
AverageChromaU(clip),
AverageChromaV(clip)
This will return the average pixel value of a plane. (Requires YV12, ISSE).
LumaDifference(clip,clip),
ChromaUDifference(clip,clip),
ChromaUDifference(clip,clip)
These return a float value between 0 and 255 of the absolute difference between two planes.(Requires YV12, ISSE)
When using these functions there are "implicit last" (first parameter doesn't have to be specified), so the first parameter is replaced by the testclip.
A further example:
vo=last
vi2=vo.trim(1,0)
vi=greyscale()
conditionalfilter(vo,vo,vi,"lumadifference(vi2)","<","5",true)
This will make frames on scene changes (or heavy movement) to become grey.
Suggestions for conditional filters are very welcome - even though I might not have time to implement them all.
You need the very latest binary to test this!
IanB
2nd April 2003, 00:53
@Sh0dan : Very cool!:cool:
How about the following set:-
MinLuma() blackest pixel
MaxLuma() whitest pixel
Probably not quite so useful (signed values)
. MinChromaU()
. MaxChromaU()
. MinChromaV()
. MaxChromaV()
Maybe more useful as absolutes
. MinAbsChromaU()
. MaxAbsChromaU()
. MinAbsChromaV()
. MaxAbsChromaV()
More likely just to want the saturation (sqrt(U'^2+V'^2)) values
. MinChromaUV() or MinSaturation()
. MaxChromaUV() or MaxSaturation()
. AverageChromaUV() or AverageSaturation()
Possibly other statistical measures like Median value or upper and lower quartiles could
be good as well.
Also nothing in AviSynth says a plugin/filter has to return a Clip (they just all seem to). There are already functions like FrameRate() that return non-clip values ;) so you probably don't need to build the world into this Filter.
IanB
mustardman
2nd April 2003, 04:30
This is truly good news!
I did a similar post to the VirtualDub forum, as yet no replies (suspect all are asleep). The gist of my post is to correct random frame jumps ... from my VD post ...
"Say for example, I have really bad sync, or a film converted to video with random bad frame alignment... I look for the black frame band in the picture (x1,y1,x2,y2), and then shift the picture back to where it should be. Hence correcting random occurances,..."
I have very little idea on programming, so unfortunately I can't help out on that front.
But now one exists, how to actually use the filter to base the decision on a small area of the frame, x1y1x2y2, do I specify the 1st parameter as clipped video, or in the "AverageLuma" function??
vid = # original source video
shift_vid = vid.crop(0,y,width,height).addborders(0,0,0,y) # video moved up by y, bit more complex for a wrapping around function!
Conditionalfilter(vid.crop(x1,y1,x2,y2), vid, shift_vid, "AverageLuma()", "lessthan","20")
Conditionalfilter(vid, vid, shift_vid, "AverageLuma(x1,y1,x2,y2)", "lessthan","20")
Thanks for the work people! :) :)
mustardman
2nd April 2003, 05:04
Hmmm. Went to get the latest binary as suggested by sh0dan, but the sourceforge page only contains the 2.5.1beta dated 12th March. As you posted today/yesterday, I assume this is not the binary you are referring to!
Where can I get the very latest?
Thanks.
PS: Sorry, my last post should read for the second script line...
Conditionalfilter(vid, vid, shift_vid, "AverageLuma(crop(x1,y1,x2,y2))", "lessthan","20")
sh0dan
2nd April 2003, 08:30
@MustardMan: Follow the second link in my signature.
Actually both your scripts are correct. :)
If you don't specify a clip, the "testclip" is used as "implicit last".
@IanB: Yes - further single image statistical functions are in the works, and more compare functions should also be done.
hakko504
2nd April 2003, 09:10
How bout something that can choose the frame with the least interlacing? I'm thinking of clips that are hard to IVTC then you could feed it both the IVTC2 and the Decombed version and get the best in return.
WarpEnterprises
2nd April 2003, 09:56
1) You are right, "n" as frame number may be a little short.
But is it now
frame_number
or
current_frame
(I would prefer frame_number or maybe only frame)
2) I still don't understand why you use three parameters instead of one string evaluating to a bool. It would be much clearer to script writers.
4) what does that mean:
when you reference a video clip ... it will be represented by the value it has at the end of the script?
Putting a clip in the condition function feeds not the current value but the last in the script? That means it is strongly suggested to only use implicit last as this is how you feed the testclip?
5) I suppose the two choice clips must have the same video properties
6-9) very great - now using AviSynth gets really funny :)
sh0dan
2nd April 2003, 14:50
Thread split - post usage here, and development issues to the new thread (http://forum.doom9.org/showthread.php?s=&threadid=50104).
Usage related reply to WE:
Originally posted by WarpEnterprises
2) I still don't understand why you use three parameters instead of one string evaluating to a bool. It would be much clearer to script writers.
Adding a second version that only takes one string later is not a big deal. Right now this was the easiest way to control it.
4) what does that mean:
when you reference a video clip ... it will be represented by the value it has at the end of the script?
Putting a clip in the condition function feeds not the current value but the last in the script? That means it is strongly suggested to only use implicit last as this is how you feed the testclip?
That means, if you use variables in the condition tests, you may not redefine any of them later in the script.
The condition checks are run after the entire script has been parsed, and the graph has been created. Therefore any variables that has changed since the condition filter will contain their new values. An example:
vid=last.blur(1.5)
Conditionalfilter(last,last,last,"LumaDifference(vid)","=","0")
vid = avisource("hest.avi")
The lumaDifference will be calculated to the AVISource vid clip.
Unfortunately I cannot see any way to avoid this.
ad. 5). Yes - it is checked, just as colorspace, etc. (I may have missed a few in the exitement though). ;)
ad. 6-9) Yes - User defined Filtering based on image properties opens up many possibilities.
sh0dan
2nd April 2003, 16:41
Added the following conditional functions:
YDifferenceFromPrevious()
UDifferenceFromPrevious()
VDifferenceFromPrevious()
and
YDifferenceToNext()
UDifferenceToNext()
VDifferenceToNext()
These should be quite handy for detecting scene change transitions:
Example:
conditionalfilter(last,last,last.trim(1,0),"YDifferenceToNext()",">","10", show=true)
This will replace the last frame before a scenechange with the first frame after the scenechange. (Inspired by another thread).
This made me think of: Audio is always passed untouched through, from the testclip for now.
The CVS Binary is dated April 3rd.
bilu
2nd April 2003, 19:06
@sh0dan
I've just realized this is the first frame-by-frame evaluation and conditional filtering ever done in Avisynth! :D Way to go, sh0dan!
Haven't tried it yet, it seems we can use any variables, right?
Now if we could have an "exists filename" condition and variable import... ;)
I've got to show this to Ddogg :D
Bilu
sh0dan
2nd April 2003, 23:29
Yes - you can use any variables - and in principle execute as many functions as you like, as long as it returns either bool, int or float.
bilu
2nd April 2003, 23:40
And could I use Import() in one of the sources? ;)
Bilu
sh0dan
2nd April 2003, 23:57
Sources are static - only the two conditions are evaluated, so no.
mustardman
4th April 2003, 02:30
(@sh0dan).
Trying to use the new ConditionalFilter, I cannot get it to work. The conditional statement always returns an access violation error, except if I deliberately put in bad parameters (for example: try to use AverageLuma for RGB space).
Here is my script, 'TestArea' and 'Video' are returned as expected, 'FixVid' has the error reported as I have shown below.
Video = AVISource("e:\VD capture\CAM01 Comp VCRstab.avi")
Video = FlipVertical(Video) # Flip the video upside down to correct for MJPEG decoder
Video = AddBorders(Video,0,1,0,0) # Add one black line at the top of the frame
TestArea = ConvertToYV12(Crop(Video,0,0,260,200)) # AverageLuma function can only deal with YV12
FixVid = ConditionalFilter(TestArea,Subtitle(Video,"1ST CLIP"),Subtitle(Video,"2ND CLIP"),"AverageLuma()","LessThan","10")
#Return(TestArea)
#Return(Video)
Return(FixVid)
# Avisynth: caught an access violation at 0x025ea268 attempting to write 0x03471210
I know this is very new stuff, but I thought you should know.
The return size of the error video is the same size as the 'TestArea' clip, not the size of the 'Video' clip, which I found a bit strange.
Thanks :)
OK... some more info has come to light (ie: I am playing with it).
I tried your sample script for selecting a frame number, and it worked fine. So I dug.
It seems as though the test clip and the two source clips have to be the same size. Obviously for the two sources, but the test???? Also, it appears all 3 clips have to be in the same colour space or it will not work.
Anyway, my kludge to fix my current problem was to use StackVertical & StackHorizontal to return my small test area to full size, convert all clips to YV12, and back to RGB at the end, and it works great!!
This is going to save me weeks!!! (actually, without it, I probably would not even have tried!)
Much appreciated :)
sh0dan
4th April 2003, 09:56
Yes - the two source clips must be exactly alike - however previously the testclip also had to be the same as the two sources. This is now fixed in a new binary.
There is also proper error handling now. Sorry for the inconvinience.
mustardman
6th April 2003, 03:30
Thanks for the update to fix the size of the test clip. Still a bug though, the output clip size is that of the test clip, not the size of the two source clips!
Also, there appears to be a bug in the code (both this last build and the previous one I got containing the ConditionalFilter, maybe others as well) that brings up an "Unrecognised Exception" whenever I try to do any type of resize. An earlier version I have (v2.07) does resize OK.
Thanks for your efforts :) I am finding ConditionalFilter exceptional.
mustardman
14th April 2003, 13:22
This subject has been quiet for a couple of weeks, and I have got no feedback on my posts to the other threads on conditional filtering.
One was a bug that was introduced somewhere, probably not to do with conditional, but was in the CVS that had the conditional filter in it. "resize" does not work with any settings.
The other is a comment on ConditionalFilter, and perhaps someone in the know would like to address it while it is still experimental and can be changed...
I can do effectively the same thing with
1) ConditionalFilter(testclip,sourceA,sourceB,"AverageLuma()","<","128")
2) ConditionalFilter(anyclip,sourceA,sourceB,"AverageLuma(testclip)","<","128")
The only difference is that *if* "testclip" (or "anyclip") is a different size to "sourceA" ("sourceA" same size as "sourceB") the output of the filter is the size of "testclip".
Since syntax "2" is possible, why not have the general syntax for conditional filter to be...
ConditionalFilter(sourceA,sourceB,<test_expression1>,<condition>,<test_expression2>[,true|false])
...as I have noticed that AverageLuma (and other functions) are quite valid in place of <test_expression2>, as well as the first expression.
This would remove the requirement that the first clip ("testclip" above) has to be the same size as the desired output. This would mean the "last" image would always be used as "sourceA" unless specified.
Comments please!
PS: The ability to view the results of the two expressions is excellent! (using true/false)
sh0dan
14th April 2003, 17:45
(Merged with previous thread for reference)
"testclip" should not have anything to do with the output size. I may have an older CVS build up than I remember, but that was fixed some time ago.
When you are referencing to "size" - is it actually the length you are refering to??
For now it determined by the length of the testclip, correctly.
Anyway, how should it best be defined:
a) The longest of source1 and source2?
b) The shortest of source1 and 2?
c) The length of testclip? (as it is now)
d) source1 and source2 should be the same length?
Similar for sound - should it come from:
z) Testclip always (as it is now)
y) Source1 always.
x) Source2 always.
w) The one selected as input source (NOT a good idea!)
My personal opinion is b) z).
Testclip is delivered as "conditional last", which gives much easier syntax in the conditional filters.
sh0dan
14th April 2003, 20:25
A new function "ScriptClip" is introduced:
Syntax: ScriptClip([clip], "Script"[, show=true/false]).
This function further extends the possibilities of conditional filtering. A simple example:
AviSource("file.avi")
ScriptClip("Subtitle(String(YDifferenceFromPrevious()))")
This will print the difference from the previous frame onto the current one. A more advanced example:
AviSource("file.avi")
ScriptClip("Blur(YDifferenceFromPrevious()/20.0)")
This will apply blur on each frame based on the difference from the previous. This will also show how errors are reported on some frames :)
An advanced example:
function fmin(float f1, float f2) {
return (f1<f2) ? f1 : f2
}
AviSource("file.avi")
ScriptClip("diff = YDifferenceToNext()"+chr(13)+"diff > 2.5 ? Blur(fmin(diff/20,1.5)) : TemporalSoften(2,7,7,3,2)")
This will apply temporalsoften to very static scenes, and apply a _variable_ blur on moving scenes. Blur is now capped properly. We also assign a variable - and this is why a line break is inserted.
Get the new binary at the second link in my sig.
"Restrictions" - the output of the script MUST be exactly like the clip deliviered to ScriptClip (Same Colorspace, Width and Height). Your returned clip is allowed to have different length - but the length from "clip" is always used. Audio from "clip" is passed through untouched.
For two very different sources (MPEG2DEC3 and AviSource) - you might run into colorspace mismatches. This is known quirk.
WarpEnterprises
14th April 2003, 22:34
1) ad "selection of properties": Why should the sound come from the testclip? Most of the current multi-clip-filters use Source1 as "default".
2) Is there a reference to the framenumber in ScriptClip?
3) So ScriptClip is some kind of generalisation of ConditionalFilter or what else are the pros/cons?
mustardman
15th April 2003, 07:50
Mmmm, had not even considered the lengths of clips! I should have been a bit more specific, the size I was referring to is the width/height of each clip.
I agree with you, option (b) would be good. Repeating the last frame for different source1 & source2 lengths would not be the best.
But I did think (y) audio from source1 would be preferable.
In all honesty, although I know it could do it, I had not thought of the complications of different length clips. The way I was using it personally was that all 3 clips came from the same base clip.
testclip = original clip enhanced/resized/filtered to give me testable results.
sourceA = original clip with filter sequence 1 applied.
sourceB = original clip with filter sequence 2 applied.
Hence, all were same length and have the same audio. The 'size' (w,h) of "testclip" could vary though, as I wanted to apply a "crop" to it.
Also, is there any plans to make this filter RGB compatible? I am dealing with interlaced material, and have _great_ difficulty dealing with single line shifts & crops with YV12 (which is 2 line based).
I had a look through the added "ScriptClip" but the use of such a beast seems fairly complex. It _really_ does need your examples to show how to use it!!!!
Great work!!
sh0dan
15th April 2003, 12:10
I have just updated (no binary yet):
- Added FrameEvaluate(clip, script) - Similar to ScriptClip, except the output of the filter is ignored. This can be used for assigning variables, etc. Frames are passed directly through from the supplied clip.
- ConditionalFilter now takes audio from \"Source1\" instead of the testclip.
- Minor adjustments to onscreen error reporting (CFilter and ScriptClip).
- Fixed problems with implicit last giving problem with multiple filter instances of ScriptClip/Cfilter.
- Added conditional RGBDifference(clip1,clip2)
- Added conditional RGBDifferenceFromPrevious(clip)
- Added conditional RGBDifferenceToNext(clip)
b) is the current behaviour, and the shorter source has the last frame duplicated (this allows for 1 frame sources).
Sound will be y) behaviour in the next binary.
(You cannot blame me for not listeling ;) )
mustardman
16th April 2003, 12:30
You sure are putting some effort into this whole conditional thing!
One frame sources... yes, it makes good sense to repeat the last frame of the shorter clip. It's pretty obvious you have been doing this for a while, always thinking ahead!
Good work sh0dan, it is appreciated.
Bidoche
16th April 2003, 13:08
I think to add functions as a type usable in script.
That way you will just have to pass a int to bool function to your filter and it will works fine, thus delegating all the work to the parser (which is here for that anyway).
Of course, it will require some syntax in order to bind arguments correctly (you want parametrised functions).
VideoFrame will have to be promoted to a type too, but with access limited to functions definitions, so it won't be possible to get huge graphs eating memory with them.
Blankman
16th April 2003, 18:50
Yahoo! Great! Now all I have to do is figure out an expression for detecting film edits on the top and bottom border. Then instead of cropping the grabage out, I can automate frame subsitution. Example:
a = dup(...)
b = reverse().dup(...).reverse()
conditionalfilter(last,b,a,...)
Didée
21st April 2003, 11:15
[edit] false alarm, sorry. Struggling with the syntax ...
HomiE FR
29th April 2003, 07:53
Hi all,
First of all, thanks sh0dan for this very useful new feature ! I'm trying to do a sort of scene change cleaner for PAL anime DVD source. You gave me a script on the Decomb topic, and I'd like to tweak it a bit if possible.
My problem is that I would need to know how to make "current_frame" work : indeed, when I try to put current_frame inside of ConditionalFilter, Avisynth keeps telling me that it doesn't know what "current_frame" means (that's the same with "frame_number").
I've tried to read everything over this topic, but it's kind of hard for me, so if someone can tell me where such a script is wrong, it would really help me. I just put the part where ConditionalFilter is involved, because I think the rest is pretty "conventional".
Total is a clip which has been defined before in the script and work properly.
I don't know if my function is right, but I need the number of the frame to do what I want to do.
So I use current_frame in ConditionalFilter, which I think would give the frame number (as an integer) to my SCCleaner function. I really don't know how to get this to work.
function SCCleaner(clip c, int frame)
{
c = c.DeleteFrame(frame+1).DeleteFrame(frame).DeleteFrame(frame-1).DuplicateFrame(frame-1).DuplicateFrame(frame-1).DuplicateFrame(frame-2)
return c
}
Clip = Total
TestClip = Clip.Trim(1,0)
New = ConditionalFilter(TestClip,SCCleaner(Clip,current_frame),Clip,"YDifferenceFromPrevious()",">","10",true)
Return New
The problem is that Avisynth tells it doesn't know what "current_frame" means... Sorry if I miss anything obvious, but if I can get help on this topic it surely is here.
Thanks !
HomiE FR
sh0dan
29th April 2003, 09:16
No problem - Conditional filtering is not very easy, so I don't mind helping out! :)
function SCCleaner(clip c, int frame)
{
c = c.DeleteFrame(frame+1).DeleteFrame(frame).DeleteFrame(frame-1).DuplicateFrame(frame-1).DuplicateFrame(frame-1).DuplicateFrame(frame-2)
return c
}
Clip = last
CleanedClip = SCriptClip("SCCleaner(Clip,current_frame)")
TestClip = Clip.Trim(1,0)
New = ConditionalFilter(TestClip,CleanedClip,Clip,"YDifferenceFromPrevious()",">","10",true)
return new
This appears to be what you want to do.
HomiE FR
29th April 2003, 10:31
Many thanks sh0dan :) , I'm going one step further towards a working script... But I've found out that the way I designed it was completely useless, since I created CleanedClip as if ConditionalFilter would do the job 3 frames at a time (and even in that case I'm not sure it's OK).
Whatever, this feature in Avisynth is really interesting and I'm trying to improve my script.
But I have a new problem (which is totally unlinked with ConditionalFilter, but if you don't mind I'll ask my question anyway) :
EDIT : I succeeded eventually ! :)
Thanks !
sh0dan
29th April 2003, 10:52
is it possible to do var = var + 1 to increment it ??
No problem.
All variables are in principle global, IIRC variables are not scoped in any way.
There is the "FrameEvaluate(clip, script)" that allows you to execute scripts every time there is requested frames from the filter.
So basicly what you want to do is to repeat the same frame three frames after a scenechange?
HomiE FR
29th April 2003, 11:03
You're fast !! :eek:
I've succeeded in using the variables I wanted to. Now I think I can really finish the job ! :) Thanks for the details, I'll go try FrameEvaluate (so much toys to play with, I didn't know they existed 24 hours ago).
About the scene change, I'd like to :
1. point out the first frame (which has the number n) to turn the expression into true
2. delete the frames n° n+1, n and n-1 (because of these crappy anime DVDs, sometimes even the frames before and after are blended so it looks really bad and I want to cut them off too)
3. put instead (in this order) the frames which have after the deletion the numbers n-2, n-1 and n-1 because these frames won't have scene change ghosting and it's no problem to have 2 or 3 duplicates in a row during a scene change I think.
I hope this does make sense ! :)
sh0dan
29th April 2003, 11:37
ok - did something that duplicates frames 3 after the scenechange:
You need to be sure the threshold is ok, since it will look very crappy if false scenechanges are detected.
The last two lines just ensure that you request frames sequencially.
function SCCleaner(clip c, int frame, int frame_offset)
{
c = FreezeFrame(c, frame-3, frame+3, frame+frame_offset)
return c
}
showframenumber()
frame_offset=0
last_frame = 0
Testclip = last
CleanedClip = ScriptClip("SCCleaner(testclip,current_frame, frame_offset)")
Conditionalfilter(testclip, cleanedclip, testclip, "frame_offset", ">", "-1" , show = false)
FrameEvaluate("frame_offset = (YDifferenceFromPrevious(testclip) > 15) ? 3 : frame_offset")
FrameEvaluate("frame_offset = frame_offset - 1")
FrameEvaluate("last_frame = current_frame")
FrameEvaluate("frame_offset = (last_frame == current_frame-1) ? frame_offset : 0")
HomiE FR
29th April 2003, 17:36
Well sh0dan, I don't know how to thank you for your highly appreciated help ! (I mean it)
About your last script, I'm trying hard to understand how it works but I still have some problems : I will look into that matter, because I think that all the new conditional features you have implemented into Avisynth are very powerful (for instance, it's possible to write a Dup "pseudo" clone in a few lines).
I also succeeded with my script, which seems to work like a charm on the sample I gave it : I'm very proud, even though most of the lines are from you. :p
I post the code (in case you'd like to see it, since I bothered you all day long to get this script to work properly) :
global sc = 0
function SCCleaner(clip c, int frame)
{
c = (sc == 0) ? c.FreezeFrame(frame-10,frame+10,frame-1).Subtitle("clean = 0") : c
c = (sc == 1) ? c.FreezeFrame(frame-10,frame+10,frame+2).Subtitle("clean = 1") : c
c = (sc == 2) ? c.FreezeFrame(frame-10,frame+10,frame+1).Subtitle("clean = 2") : c
global sc = sc + 1
global sc = (sc == 3) ? 0 : sc
return c
}
function SCCond(clip c, int frame)
{
c = (sc == 0) ? c.Subtitle("cond = 0") : c
c = (sc == 1) ? c.FreezeFrame(frame-10,frame+10,frame+2).Subtitle("cond = 1") : c
c = (sc == 2) ? c.FreezeFrame(frame-10,frame+10,frame+1).Subtitle("cond = 2") : c
global sc = (sc == 0) ? 0 : sc + 1
global sc = (sc == 3) ? 0 : sc
return c
}
Clip = Total
Clip1 = ScriptClip(Clip,"SCCleaner(current_frame)")
Clip2 = ScriptClip(Clip,"SCCond(current_frame)")
TestClip = Clip.Trim(1,0)
New = ConditionalFilter(TestClip,Clip1,Clip2,"YDifferenceFromPrevious()",">","20",false)
return New
And again, it's great to see developers who help anonymous users (like me) that much !
HomiE FR
HomiE FR
30th April 2003, 19:41
Hi sh0dan (and others too),
I'm done with the script which detects (not perfectly, but I want to improve that) scene changes and applies a little operation to make thm not blended.
The problem I have is that since there are ghosts all over my source, it's pretty hard to find a threshold which would only detects scenes changes and not frames with high motion too... Sometimes the YDiff evaluated for a frame with high motion is higher that the one for a scene change (because of the ghosts).
That's why I'm thinking of adding a new feature to the script : I'd like to store the average diff from the last 10 frames : (YDiff(frame1)+...+YDiff(frame10))/10, which would be updated at each frame, obviously. Then, if the result is above some threshold (a low threshold I guess), it is that we're in a high motion scene and we could make the threshold for scene change detection higher to prevent wrong detections. Then, when the high motion scene is over, the average gets below the "high motion" threshold and we can lower the threshold for scene change detection.
I hope the idea sounds right (maybe a bit useless, but I find it fun to write AVS scripts, so...), but I'm not sure it would be possible with all your new conditional filtering. That's why I'd like to ask you if you believe that this is possible ?
Thanks in advance !
HomiE FR
Edit : Sorry, but I'm trying hard to understand how the last script you posted works, but I can't... :( I can't understand how ConditionalFilter and FrameEvaluate are linked, and if ConditionalFilter is totally done when FrameEvaluate starts, or if there is some "recursive matter" here, or how the variables work. I guess I don't understand a single line.
I feel there is everything in this script you wrote that would make m able to do what I want, but I can't understand.
sh0dan
1st May 2003, 11:16
You might have noticed:
YPlaneMax(clip, float threshold),
YPlaneMin(clip, float threshold),
YPlaneMedian(clip),
YPlaneMinMaxDifference(clip, float threshold)
- Threshold is a percentage, on how many percent of the pixels are allowed above or below minimum. The threshold is optional and defaults to 0.
- There are similar funtions for U and V.
A little more for you to play with.
Simple example:scriptclip("Subtitle(string(YPlaneMinMaxDifference()))")
@sh0dan
I'm very lazy today so I dare to ask a little help.
I want to add to this example you gave us; the new YPlaneMax(clip, float threshold),where threshold=25%.
How should we write it for both conditions?.Is it possible?
example:
vid=mpeg2source("D:\mysource.d2v")
vid_blur = vid.blur(1.5)
Conditionalfilter(vid, vid_blur, vid,"AverageLuma()", "lessthan","20")
Thanks in advance Arda
sh0dan
2nd May 2003, 08:45
@ARDA: What exactly would you like it to do?
@sh0dan
apply blur(1.5) when AverageLuma() is lessthan 20 and no luma is over
25 (20+25%).Of course it is just an example.Once more my english!
I hope now you can understand.
Thanks again Arda
JasonFly
10th May 2003, 00:01
I am currently testing conditional filtering and I have tested the two foillowing scripts:
First:
threshold_hm = 20
function Detect_Motion(clip Source, float threshold_hm)
{
Slow_Fr = Source.trim(1,0)
Hight_Fr = Source.Greyscale().trim(1,0)
Video = Conditionalfilter( Source.trim(1,0), Slow_Fr, Hight_Fr, " YDifferenceFromPrevious() + UDifferenceFromPrevious() + VDifferenceFromPrevious() ", "<", "threshold_hm", True)
return Video
}
Video = Detect_Motion(Source, threshold_hm)
Return Video
Second: The same but with ToNext instead of FromPrevious
threshold_hm = 20
function Detect_Motion(clip Source, float threshold_hm)
{
Slow_Fr = Source.trim(1,0)
Hight_Fr = Source.Greyscale().trim(1,0)
Video = Conditionalfilter( Source.trim(1,0), Slow_Fr, Hight_Fr, " YDifferenceToNext() + UDifferenceToNext() + VDifferenceToNext() ", "<", "threshold_hm", True)
return Video
}
Video = Detect_Motion(Source, threshold_hm)
Return Video
The problem is that these two scripts send me exactly the same results in the result output of conditional filter. Is it all ok whith these functions or am I doing something wrong(maybe I havn't understand the real meaning of these functions?)
BTW, Thanks to all avisynth developers for this cool new feature.;)
EDIT:
I cannot find the sources of the latest builds of avisynth(since 13 march 2003)
Is this normal?
sh0dan
10th May 2003, 00:17
You are right! Difference to next is actually returning difference to previous. If all is right, I'll be able to post a fixed binary tomorrow.
The latest source is always available through Sourceforge CVS (http://sourceforge.net/cvs/?group_id=57023), where you can also browse the source.
HomiE FR
15th May 2003, 19:43
@sh0dan :
Hi, I have some problems here with some avisynth plugins when they are used within a conditional function, such as scriptclip. When I put Deen or FluxSmooth (asharp or edeen or awarpsharp have no problems) in ScriptClip, I can see during encoding only a few hundreds frames after the beginning that memory usage is growing abnormally fast, without stopping. It can reach over 1 GB !
I don't know if this is because these two filters have some temporal features, so they need previous and next frames in ordre to operate, but I believe this is not normal.
I have read in another thread that avisynth (with setmemorymax) can't stop filters such as deen to allocate memory, but isn't there another way to prevent them for eating up all the memory found ?
If you think I'm not precise enough, I'll post an example where I have a problem (but the script is rather complex, so I guess it would be painful to read).
Thanks.
sh0dan
15th May 2003, 21:22
They most likely have a memoryleak - since a filter instance is being created on each frame in scriptclip, even small leaks will accumulate - there is no other solution than to give notice to the authors. ;)
You are right about setmemorymax - it doesn't control the memoryallocation by filters.
HomiE FR
15th May 2003, 21:41
thank you sh0dan, if the problem is spotted I guess it's possible to find a solution.
i will mail marcfd (even if he stopped coding i think) about that.
i've noticed that the memory leak seems to be even stronger in fluxsmooth. your conditional filters really push avisynth plugins to their "borders". :)
but just a small question (since i'm no pro-coder) : is a memory leak just a place in the code where the function to free memory hasn't been called after leaving something behind ? is it hard to spot and to remove ?
sh0dan
15th May 2003, 21:52
is a memory leak just a place in the code where the function to free memory hasn't been called after leaving something behind ? is it hard to spot and to remove ?
Yes - it is exactly as you describe it.
Leaks are easy to overlook, because they only become visible in "extreme" situations. Allocating 256 bytes in a filter, that are not freed does not pose any problems - however, when you do it every frame in a 150000 frame movie, you've got about 36 megabytes.
The main problem in finding leaks is that they can be complex to find. The reason is, that you might not want to deallocate them the same place you allocate them. mpeg2dec(3) is an example of this - memory allocations are scattered all over and the allocated memory is being passed all around the code, so keeping track of it is not easy at all.
HomiE FR
16th May 2003, 06:56
thanks for the explanation.
I understand that they can be hard to remove, and it's sad to say that Avisynth can't do anything to prevent this from happening (since this is the filter itself which "plays" with the memory, without control from Avisynth).
But I'll try to contact the authors of these filters in order to ask for help if possible.
Defiler
27th May 2003, 18:32
OK. Obviously I'm doing something wrong here. Can you give me a pointer?
I'm trying to make a script that will stomp on DivX3.11a "sh*tblocks" by looking for instances where the luma difference between a frame and the one immediately preceding it is almost zero.
In pseudo-code:
If YDifferenceFromPrevious < 1
Then FreezeFrame(current_frame, current_frame, current_frame-1)
Else Do_Nothing
I've written 5 or 6 scripts, but none of them seem to actually perform the task specified in the conditional. The latest one uses huge thresholds, and has a GreyScale() statement in it, just to make it VERY obvious when the conditional is kicking in. Even though the output from "show=true" seems correct, it never seems to act upon that decision.
function DIVX3SUX(clip z, int frame)
{
z = FreezeFrame(z, frame, frame, frame-1)
GreyScale(z)
return z
}
Evaluate=last
Unaltered=Evaluate
Fixed=ScriptClip(Unaltered,"DIVX3SUX(Unaltered,current_frame)",show=false)
ConditionalFilter(Evaluate,Fixed,Unaltered,"YDifferenceFromPrevious()",">","100",show=true)
My previous attempts were fancier.. I'm trying to pare things down to the bare minimum that will actually execute the conditional.
By the way.. My intent is to use this inside the new ffdshow Avisynth feature. That's why I can't use any of the "Next" comparisons. There is no "next" frame yet, in ffdshow. Heh.
Thanks for taking the time to assist us, sh0dan.
sh0dan
27th May 2003, 19:49
I'm not 100% sure it is possible what you propose, but to see that conditional filtering works, try:
function DIVX3SUX(clip z, int frame)
{
z = FreezeFrame(z, frame, frame, frame-1)
z = GreyScale(z)
return z
}
Spot the difference :)
Defiler
27th May 2003, 20:25
Thanks. That fixed that particular problem. However, I still haven't found a combination of commands that will successfully replace the current frame in "z" with the previous frame in "Unaltered"
Here's what I have now..
AVISource("blahblah.avi")
function DIVX3SUX(clip z, int frame)
{
z = DuplicateFrame(z, frame-1)
z = GreyScale(z)
return z
}
Evaluate=last
Unaltered=Evaluate
Fixed=ScriptClip(Unaltered,"DIVX3SUX(Unaltered,current_frame)",show=false)
ConditionalFilter(Evaluate,Fixed,Unaltered,"YDifferenceFromPrevious()","<","100",show=false)
This script successfully makes every frame with a Y-difference less than 100 greyscale. However, it doesn't duplicate any frames.
It seems to me that I'd really like to be saying "z = DuplicateFrame(Unaltered, frame-1)", however, that doesn't seem to work, no matter where I place the clip statements. I presume also that the fact that every "clip" passed from ScriptClip is actually only one frame long doesn't help this situation. Heh.
Just to be sure, I tried a much simpler script:
AVISource("Input File.avi",false)
ScriptClip(last,"DuplicateFrame(last,current_frame)")
In my thinking, this script should endlessly repeat the first frame of the video. Am I wrong? Instead, it seems to do nothing at all. I'm probably missing the entire point here. It wouldn't surprise me. Heh.
By the way.. Thank you for your extremely prompt response.
sh0dan
27th May 2003, 20:39
>In my thinking, this script should endlessly repeat the first frame of the video.
No - current_frame is updated each time Scriptclip is called, so the only thing you accomplish to duplicating the current frame (which has no effect, as it is the next frame being duplicated when the next frame is requested).
Defiler
27th May 2003, 20:43
Aah, that would explain a variety of different things.
Do you think what I am trying to achieve with the last (two-line) script can be accomplished, without knowing actual frame numbers ahead of time?
Cross
8th June 2003, 11:09
Hi, didn't know if posting this here. BTW i searched and tested a lot but didn't find any explanation.
I ever assume i'm missing something or i don't understand well (one hundred times! :) ) before posting.
Well, i have this SIMPLE script
vid=MPEG2Source("..\file.d2v").trim(7650,7720)
vidg=greyscale(vid)
cond=ConditionalFilter(vid, vidg, vid, "YDifferenceFromPrevious()", "lessthan", "1",True)
return cond
Just a test to understand how conditionalfilter() works.
Now, the strange behaviour is that it gives 0 (zero) as result of the comparison on the second frame!
And gives a value on the first frame based on something i missed in the docs or in the forums, if so i apologize.
I tried the clip without the trim and it does not give any strange value on the first and second frames, but there is a lot of blackness at the start of the clip.
I didn't check with a clip starting with a non black frame and without trimming because i'm fairly sure it should go ok and BTW this is enough to start having a bit of headache. ;)
Thanks in advance and i'm learning so much in these weeks I spent on your forum that i almost cannot manage all the informations. You are great guys.
Cross
Cross
8th June 2003, 18:37
@sh0dan
(are you a system shock fan?)
i have this kind of script:
...
...
vid=MPEG2Source("...file.d2v").trim(startframe,-cliplen).telecide(guide=2,post=false)
...
...
cond=ConditionalFilter(vid, blend, vid, "status", "equals", "0",True)
cond=scriptclip(cond,"i=i+1"+chr(13)+
...
...
\ "Subtitle(String(lumadifference(vid,vid1)))"+chr(13)+
\ "Subtitle(String(j),10,60)")
return cond
well, sorry for the missing lines, just wanted to be brief.
The point is that if i call lumadifference() from within a scriptclip or a frameevaluate() (i'm no English, but shouldn't it be frameevalutate?) it's ok.
But if i call a function like this:
function vvv(clip test)
{
lumadifference(test,test.trim(100,-1))
}
from within a scriptclip or frameevaluate it outputs an error (invalid input for lumadifference).
The question is: I am doing something wrong, is it possible to do such a thing? Or is it just not implemented in the use of that functions?
Cross
Defiler
9th June 2003, 16:46
Originally posted by Cross
[B(i'm no English, but shouldn't it be frameevalutate?) it's ok.[/B]Nope. "Evaluate" is correct. Thus, so is FrameEvaluate. The English word comes from the French word "évaluation."
Cross
10th June 2003, 01:22
ooops! I was sure the English word was Evalutation. There is something to learn behind every corner. :)
Regarding my problem, from what i understand, every time e frame is requested, avisynth parses and executes the conditionalfilter() scriptclip() and frameevaluate(). Right? I think, since i didn't read anything else that the execution is in order of appaerance in the script. Now, since the "environment" created by these functions is more that of a conventional programming language than the pure scripting language that avisynth is, and that i miss some form of flow-control structures,i was asking myself if there was some way to take the functions used in this frame-by-frame environment and put them in some user functions (to be used only in those conditional frame functions. That's obvious). That's it.
Thanks and sorry for my not perfect english.
Cross
Defiler
10th June 2003, 03:26
That's "imperfect English".. Hehe. But seriously, yours is much better than my Italian.
The problem you are having is much the same as what I experienced earlier in the thread. Conditional filtering operates on a single frame at a time. You essentially can't use "Trim()" with it.
I assume sh0dan will correct me if I am wrong about this.
Cross
10th June 2003, 12:18
Originally posted by Defiler
Conditional filtering operates on a single frame at a time. You essentially can't use "Trim()" with it.
I assume sh0dan will correct me if I am wrong about this.
No, at least I think (based on my little experience) that avisynth has complete random access at the source clips, so you can ask for single frames at your will.
example:
vid=MPEG2Source(FILENAME)
ct=0
sum=0
sumstring="Sum "
averagestring="Avg "
cond=scriptclip(vid,
\"sum=0"+chr(13)+
\"ct=current_frame"+chr(13)+
\"sum=sum+lumadifference(vid.trim(ct,1),vid.trim(ct+1,1))"+chr(13)+
\"ct=ct+1"+chr(13)+
\"sum=sum+lumadifference(vid.trim(ct,1),vid.trim(ct+1,1))"+chr(13)+
\"ct=ct+1"+chr(13)+
\"sum=sum+lumadifference(vid.trim(ct,1),vid.trim(ct+1,1))"+chr(13)+
\"ct=ct+1"+chr(13)+
\"sum=sum+lumadifference(vid.trim(ct,1),vid.trim(ct+1,1))"+chr(13)+
\"ct=ct+1"+chr(13)+
\"sum=sum+lumadifference(vid.trim(ct,1),vid.trim(ct+1,1))"+chr(13)+
\"ct=ct+1"+chr(13)+
\"sum=sum+lumadifference(vid.trim(ct,1),vid.trim(ct+1,1))"+chr(13)+
\"ct=ct+1"+chr(13)+
\"sum=sum+lumadifference(vid.trim(ct,1),vid.trim(ct+1,1))"+chr(13)+
\"ct=ct+1"+chr(13)+
\"sum=sum+lumadifference(vid.trim(ct,1),vid.trim(ct+1,1))"+chr(13)+
\"ct=ct+1"+chr(13)+
\"sum=sum+lumadifference(vid.trim(ct,1),vid.trim(ct+1,1))"+chr(13)+
\"ct=ct+1"+chr(13)+
\"sum=sum+lumadifference(vid.trim(ct,1),vid.trim(ct+1,1))"+chr(13)+
\"ct=ct+1"+chr(13)+
\"trim(current_frame+100,1)"+chr(13)+
\"subtitle(sumstring+String(sum))"+chr(13)+
\"subtitle(averagestring+String(sum/(ct-current_frame)),10,50)"+chr(13)+
\"subtitle(String(ct-current_frame),10,80)")
return cond
You could navigate the whole clip in every single-frame evalutation process. The problem, at least IMHO is that you have not much control over the flow of the code. And avisynth is wonderful and useful and free and I could never ever dare to whine about something.
But now that I have all this power on my fingertips I cannot make a loop or include those special features in recursive user functions. :(
Cross
sh0dan
10th June 2003, 14:00
@All: I'm sorry - I just don't have the time to get into this ATM.
However - functions for conditional filtering is in no way limited to internal functions.
It is perfectly possible to add more functionality in plugins. For now I have no other plans to conditional filtering than bugfixes (if any should arise).
So - the internal functions should (as always) be considered "basic" filters - so for more advanced functions plugins should be written.
@Cross: Yes - loved the Shock1 in 1994 - just blew my mind. The most perfect "hacker" game ever made, with a very solid plot.
Defiler
10th June 2003, 14:51
Avisynth certainly allows random access (at least, with the Source functions that support it), but the conditional filtering itself operates on single frames. I have not been able to make the type of script you are describing work. I thought it was because the ConditionalFilter metaphor just didn't allow it, but it is possible that I am doing something wrong.
Cross
10th June 2003, 16:09
@sh0dan: as i posted a few days ago, i think there is something wrong with these functions and a trimmed clip.
Again... (sorry to post this again) but i did some more checking.
vid=MPEG2Source("file.d2v").trim(7650,7720)
vidg=greyscale(vid)
cond=ConditionalFilter(vid, vidg, vid, "YDifferencefromprevious()", "lessthan", "1",True)
return cond
Now, the first frame gives in reality the value returned by YDifferencetonext in the first frame (and maybe is the correct behaviour, but I would have bet on 0), but gives 0 on the second frame, and this IMO is strange.
If there is an explanation, i don't get it.
As for the control structures, I took a look at another thread regarding developement of 3.0 and WHILE like structures. Got a lot of informations. Maybe I'll go to AviSynth Filter SDK directly.
@defiler: if I got it right, the special conditional functions get parsed every frame, and all frames of all clips involved are requested and given to the functions or filters requesting them. So it is sure very slow, but from what i experienced you could analyze the whole world in every iteration of the script.
Cross
stickboy
6th September 2003, 07:36
Originally posted by sh0dan is it possible to do var = var + 1 to increment it ??All variables are in principle global, IIRC variables are not scoped in any way.Is this still true? I tried the following in AviSynth 2.5.2 (Sep 3, 2003 build):c = ColorBars(640, 480).Trim(0, 99) # 100 frames
n = 0
c.FrameEvaluate("n = n + 1")
MessageClip(String(n))The resulting clip displays the number 0, but I would expect the resulting clip to display 100 (or at least something non-zero). Am I misusing FrameEvaluate, or does FrameEvaluate indeed evaluate its thunk in a different scope?
Also, FWIW:
Instead of sprinkling Chr(13) everywhere, actual line-breaks seem to work fine and make everything more readable. For example:
ScriptClip("diff = YDifferenceToNext()
diff > 2.5 ? Blur(fmin(diff/20,1.5)) : TemporalSoften(2,7,7,3,2)")
Wilbert
6th September 2003, 16:08
Is this still true? I tried the following in AviSynth 2.5.2 (Sep 3, 2003 build):
code:
c = ColorBars(640, 480).Trim(0, 99) # 100 frames
n = 0
c.FrameEvaluate("n = n + 1")
MessageClip(String(n))
The resulting clip displays the number 0, but I would expect the resulting clip to display 100 (or at least something non-zero). Am I misusing FrameEvaluate, or does FrameEvaluate indeed evaluate its thunk in a different scope?
I think the problem is the following: The first frame is requested from AviSynth, hence from MessageClip (with n=0). FrameEvaluate makes it n=0+1=1. The frame is requested from Colorbars, and Colorbars gives the first frame. Then n is set back to 0. Frame is given to FrameEvaluate, where nothing happens. Frame is given to Messageclip. Since n is set back to 0, it returns MessageClip(String(0)). This happens for every frame (and n is everytime set back: 0->1->0).
Compare it with the following:
c = ColorBars(640, 480).Trim(0, 99) # 100 frames
global n = 0
c1 = c.ScriptClip("subtitle(string(n))")
c2 = c1.FrameEvaluate("n = n + 1")
return c2
edit: I put up some more documentation on avisynth.org about this. I hope it's useful to anyone :)
stickboy
6th September 2003, 20:21
Hmm... this is really confusing.
Why does n get reset back to 0 each time? And in the following code, n is incremented as expected within ScriptClip, but outside of ScriptClip it's 0. Is that behavior consistent with what you're saying?n = 0
c = ColorBars(640, 480).Trim(0, 99) # 100 frames
c = c.ScriptClip("n = n + 1
Subtitle(String(n))")
c.BlankClip().Trim(0, -1).Subtitle(String(n)) + c
WarpEnterprises
6th September 2003, 23:19
You mix up the script functions (which are executed once on script load) and the script which is executed by ScriptClip every frame (which has indeed it's own scope).
There is no way to make a script frame-variable, only special functions (all those cond. functions) can do that for their arguments.
Wilbert
6th September 2003, 23:27
And in the following code, n is incremented as expected within ScriptClip, but outside of ScriptClip it's 0. Is that behavior consistent with what you're saying?
No, it isn't. But I think your explanation is correct here :)
stickboy
7th September 2003, 00:18
Originally posted by WarpEnterprises
You mix up the script functions (which are executed once on script load) and the script which is executed by ScriptClip every frame (which has indeed it's own scope).
There is no way to make a script frame-variable, only special functions (all those cond. functions) can do that for their arguments.Ah... It makes much more sense to me now. Thanks.
WarpEnterprises
7th September 2003, 00:39
I hope I get this all correct, it's quite tricky internally, so please don't belive it completely until you tried it out. ;)
In addition, what is possible and again confuses is to pass variables from the normal script to the "inside script", but only the value at the end of the normal script, which is not necessary the value at the position of the "inside script".
mustardman
19th September 2003, 12:12
Interesting...
I want to do some funky maths on the value of "AverageLuma" returned from a single frame (that changes thoughout the script). No matter what I try, I can't get the value 'outside', where I can then apply some of the nice float functions to it.
If I gather correctly, this is because it cannot be done?
ie: A value (say x) in an outside script cannot be based on a value from inside a script function (even when it is made global... using EvaluateFrame as the function). eg: c3 = FrameEvaluate(c21, "global x = AverageLuma(c1)")
It would be really nice if you could do "x = AverageLuma(clip)" in the basic script :)
MustardMan.
WarpEnterprises
19th September 2003, 22:29
You are right, that is not possible.
First the "outside script" is evaluated once on script loading
Second all filters in the chain are initiated FROM END TO START.
Third every requested frame is calculated.
So you see that only variables that are generated BEFORE or AT THE SAME TIME can be used together.
The "global" thing is only the "script range" where the variable is seen, not the "time range".
You see, very tricky, very powerful, but, hey, that's the fun of AviSynth.
mustardman
22nd September 2003, 10:49
Thanks for the confirmation... no wonder I could not get it to work. I had previously done some digging in regard to how "conditionalFilter" and its' brothers worked (and in fact all video processing in AVIsynth). It was interesting to note that they work backwards - as the main script (if it could be separated) works forward.
The examples given in the online help/manual are easy examples, but conceptually quite challenging.
Yes, AVIsynth is very powerful, and extremely easy to use once you get the hang of scripts... ahh, the joy of writing programs again!
:)
vBulletin® v3.8.5, Copyright ©2000-2012, Jelsoft Enterprises Ltd.