View Full Version : if..then style multiple condition filter execution help required
RedDwarf1
18th October 2008, 03:26
I am trying to work out a conditional if then style script and there are two conditions that must be met for it to be carried out. I want the current frame to between 52189 and 52238 inclusive for the filter to be applied but I am having trouble deciphering the documentation in order to construct it using AVISynth scripting.
such as
If current_frame>=52189 AND current_frame<=52238 THEN do filter
Applyrange is no use to me before someone recommends it.
So would someone who knows how to do this in AVISynth scripting point me in the right direction?
Didée
18th October 2008, 03:59
Have a look at this thread (http://forum.doom9.org/showthread.php?t=141883).
There you'll find good hints how to do it with the conditional environment. And you'll find the even better hint about "wrong thinking" - Avisynth basically doesn't work in a frame-dependent way. If you were a bit more specific about the actual problem, we could tell better. E.g., from the example you gave, ApplyRange would be *exactly* the thing you are looking for. If there are other reasons why it isn't, name them.
mikeytown2
18th October 2008, 04:02
http://avisynth.org/mediawiki/Operators
This should be close to what your looking for
result = current_frame>=52189 && current_frame<=52238 ? filter() : nop()
http://avisynth.org/mediawiki/Non-clip_functions#Control_Functions
Although for what your trying to do RemapFrames sounds like a good place to start
http://avisynth.org/stickboy/
RedDwarf1
18th October 2008, 04:34
Thanks but I am getting an error as it does not know what current_frame means. I did see that variable mentioned here (http://avisynth.org/mediawiki/Runtime_environment) and thought it would be useful for this but when previewing the script in AvsP it is not recognised. Is something else required to make that available?
RemapFrames does not sound useful in this instance as I don't want to alter the frame order, merely alter a small group of frames attributes. The if...then style would be ideal if I could get it working.
this does not work either, giving the same error.
subtitle( string(current_frame))
RedDwarf1
18th October 2008, 05:39
Have a look at this thread (http://forum.doom9.org/showthread.php?t=141883).
There you'll find good hints how to do it with the conditional environment. And you'll find the even better hint about "wrong thinking" - Avisynth basically doesn't work in a frame-dependent way. If you were a bit more specific about the actual problem, we could tell better.
I am trying to apply an overlay to a certain group of frames and didn't want to have to trim to do it.
E.g., from the example you gave, ApplyRange would be *exactly* the thing you are looking for. If there are other reasons why it isn't, name them.
Because Applyrange arguments cannot contain a clip and the filter requires 3 clips.
stickboy
18th October 2008, 07:26
Thanks but I am getting an error as it does not know what current_frame means. I did see that variable mentioned here (http://avisynth.org/mediawiki/Runtime_environment) and thought it would be useful for this but when previewing the script in AvsP it is not recognised.
Is something else required to make that available?It only works with certain functions (ScriptClip, FrameEvaluate). However, you should be wary of using ScriptClip/FrameEvaluate; they're usually not the appropriate idiom to use for AviSynth scripts, where you should be applying a more functional rather than imperative style.
RemapFrames does not sound useful in this instance as I don't want to alter the frame order, merely alter a small group of frames attributes. The if...then style would be ideal if I could get it working.RemapFrames does a lot more than that. In general, it allows you to remap frames from one clip into another clip. Altering frame order is a narrow view where both clips happen to be the same.
I am trying to apply an overlay to a certain group of frames and didn't want to have to trim to do it.Why not?
Because Applyrange arguments cannot contain a clip and the filter requires 3 clips.I don't think that's true. You're probably calling it wrong.
Even if it were true, you could either:
A. Make a wrapper function that calls the filter with the arguments you want, and then use that wrapper function with ApplyRange.
B. Use my JDL_ApplyRange function.
mikeytown2
18th October 2008, 08:23
C. Use Trim and Splice
http://avisynth.org/mediawiki/Trim
http://avisynth.org/mediawiki/Splice
post your script if you need any more help
Didée
18th October 2008, 10:07
Using trim + splice would certainly do.
OTOH, ApplyRange definetly does work with several clips. The trick is that with ApplyRange you can't use *named* parameters for the target filter. You have to provide all necessary parameters of the target filter in native order.
The following uses ApplyRange to overlay a fft3dfilter'ed version of the original over the dark parts, for frames 35000 to 35050. It does work.
base = last
to_overlay = base.fft3dfilter()
the_mask = base.levels(20,1.0,40,255,0,false)
ApplyRange(base, 35000,35050, "Overlay", to_overlay,0,0,the_mask,1.0,"Blend")
Compare to the declaration of "Overlay" given in the docs:
Overlay (clip, clip overlay, int "x", int "y", clip "mask", float "opacity", string "mode", bool "greymask", string "output", bool "ignore_conditional", bool "pc_range")
IanB
18th October 2008, 10:11
This is the "under the hood" result you need to end up with :-...Source(...)
A=Trim(0, 52188)
B=Trim(52189, 52238)
C=Trim(52239, 0)
B=B.Overlay(....)...
A + B + CApplyRange, JDL_ApplyRange, RemapFrames, etc all provide syntactic sugar for doing the above in an easier to type way in particular circumstances.
Learn to think in terms of transforming a whole clip, not the individual frames within the clip. When you need to do something to a part of a clip, think slice and dice, process then join and paste, this cost absolutely nothing in final processing speed.
The conditional environment recompiles the component script every frame! You should only ever use it as a last resort. And you need to be mindful of how long various filters take to create and initialise when using it.
An example of slow initialisation is the ShowFrameNumber() family. SubTitle uses the same text rendering code, it slowly renders the text once, then overlays the same resultant image very fast on every frame. The Show*() routines slowly renders new text every frame, then overlays the resultant image very fast on just the current frame. The ShowFrameNumber() routines effectively implements ScriptClip("SubTitle(String(CurrentFrame))"), not a shining example of how to do things.
When you finally need to use the conditional environment consider using ConditionalFilter() first. It offers per frame selection from 2 input clips without needing to recompile the possibly very complicated source for the 2 input clips. The decision code is still compiled every frame, but that hopefully is trivial in comparison.
RedDwarf1
19th October 2008, 05:01
I am trying to apply an overlay to a certain group of frames and didn't want to have to trim to do it.
Why not?
Because it is a bit messy and it is the way I have been doing things and wanted to try a different method and this seemed like the ideal place to try it as with a few additions I might make it into a function which I would want to just specify the frames and have it do it automatically.
Because Applyrange arguments cannot contain a clip and the filter requires 3 clips.
I don't think that's true. You're probably calling it wrong.
Even if it were true, you could either:
It was very late and I was tired when I read the docs and I misread them. I had tried it and did not get it working so I put the misread info and a failed attempt together by mistake. I must of written the instruction incorrectly when I tried it.
C. Use Trim and Splice
http://avisynth.org/mediawiki/Trim
http://avisynth.org/mediawiki/Splice
post your script if you need any more help
I know that will work but I did not want to do it that way as I was thinking about making a function afterwards and using Trim and splice looks a bit messy. But I will compare it to see what speed difference there is.
Using trim + splice would certainly do.
OTOH, ApplyRange definetly does work with several clips. The trick is that with ApplyRange you can't use *named* parameters for the target filter. You have to provide all necessary parameters of the target filter in native order.
That must be why my attempt at using it failed as I was using named parameters.
The following uses ApplyRange to overlay a fft3dfilter'ed version of the original over the dark parts, for frames 35000 to 35050. It does work.
base = last
to_overlay = base.fft3dfilter()
the_mask = base.levels(20,1.0,4008,255,0,false)
ApplyRange(base, 35000,35050, "Overlay", to_overlay,0,0,the_mask,1.0,"Blend")
That is useful and makes it clear how to use it. The construction of the mask might be helpful as well as I thought there must be an easier way of constructing it from the overlaid image. But I have not got it working as I want yet.
IanB
19th October 2008, 08:28
@RedDwarf1,
Also note the ApplyRange() solution does not scale well. Use it maybe 3 or 4 times, if you find the need for more than that, then start thinking about another solution.
To use ApplyRange() and Animate() with functions that have lots of named arguments or to generate more complex range targets, wrap the code in a user function like thus:-...
base = last
to_overlay = base.fft3dfilter()
the_mask = base.levels(20, 1.0, 40, 255, 0, false)
ApplyRange(base, 35000,35050, "MyOverlay", to_overlay, the_mask)
Function MyOverlay(clip B, clip O, clip M) {
return Overlay(base, overlay=O, mask=M, mode="Blend")
}Also in the mask generation, the 3rd arg, 4008, does not seem right. With these values the mask will be 255 (fully opaque) for all values less than or equal to 20 and ramp down to 240 (94% opaque) for a value of 255. Reading between the lines, I think a value of 30 to 50 might be more what you are after.
Didée
19th October 2008, 14:50
Oops! The "4008" was meant to be a "40", yes. Was trying to make a last-second edit "48" -> "40", but got twiddled fingers or something. :)
RedDwarf1
21st October 2008, 00:07
@RedDwarf1,
Also note the ApplyRange() solution does not scale well. Use it maybe 3 or 4 times, if you find the need for more than that, then start thinking about another solution.
To use ApplyRange() and Animate() with functions that have lots of named arguments or to generate more complex range targets, wrap the code in a user function like thus:-...
base = last
to_overlay = base.fft3dfilter()
the_mask = base.levels(20, 1.0, 40, 255, 0, false)
ApplyRange(base, 35000,35050, "MyOverlay", to_overlay, the_mask)
Function MyOverlay(clip B, clip O, clip M) {
return Overlay(base, overlay=O, mask=M, mode="Blend")
}Also in the mask generation, the 3rd arg, 4008, does not seem right. With these values the mask will be 255 (fully opaque) for all values less than or equal to 20 and ramp down to 240 (94% opaque) for a value of 255. Reading between the lines, I think a value of 30 to 50 might be more what you are after.
Thanks for the hints. I think I have come up with a way of doing all I need using overlay and ConditionalReader to alter the position and opacity like I wanted. I have removed the ApplyRange as ConditionalReader helps me do everything I wanted.
Thanks to everyone who contributed and helped me out on this.
IanB
21st October 2008, 03:31
So you end up with an optimal, scalable result. :D If the alternate processing path is sufficiently intensive then you might like to add a ConditionalFilter() to the script....
Base = Last
to_overlay = Base.fft3dfilter()
the_mask = Base.levels(20, 1.0, 40, 255, 0, false)
Overlay(Base, overlay=to_overlay, mask=to_overlay, mode="Blend", opacity=0.0, ignore_conditional=false)
ConditionalFilter(Last, Base, "OL_opacity_offset", "greaterthan", "0.0") # If nop then skip processing
ConditionalReader("C:\...file.txt", "OL_opacity_offset") # TYPE float\DEFAULT 0.0\R 35000 35050 1.0
RedDwarf1
24th October 2008, 05:13
So you end up with an optimal, scalable result. :D If the alternate processing path is sufficiently intensive then you might like to add a ConditionalFilter() to the script....
Base = Last
to_overlay = Base.fft3dfilter()
the_mask = Base.levels(20, 1.0, 40, 255, 0, false)
Overlay(Base, overlay=to_overlay, mask=to_overlay, mode="Blend", opacity=0.0, ignore_conditional=false)
ConditionalFilter(Last, Base, "OL_opacity_offset", "greaterthan", "0.0") # If nop then skip processing
ConditionalReader("C:\...file.txt", "OL_opacity_offset") # TYPE float\DEFAULT 0.0\R 35000 35050 1.0
Thanks, I will keep a note of that incase it comes in useful.
Is there a way of producing an animated overlay? I could not find a filter that does it except for a VirtualDub filter but I would rather avoid that if possible due to the colour conversion involved.
I have tried using a gif image in overlay but it did not work. The Animate command sounds like it might do it but I don't know what command would be needed to be used with it to make an animated overlay.
Any ideas?
Gavino
24th October 2008, 13:59
Use Animate with Overlay (or your own wrapper, eg MyOverlay) in a similar way to ApplyRange in IanB's example at post #11 above.
Or you can use ConditionalReader to vary the overlay position via the Overlay variables (http://avisynth.org/mediawiki/Overlay#Conditional_Variables) OL_x_offset and OL_y_offset in a similar way to OL_opacity offset.
RedDwarf1
24th October 2008, 23:51
After I had shut down my PC I started thinking about it ( put my brain into gear lol ) I remembered that the parameter to overlay is a clip and a clip can be any image or video so just changing the clip from a still image which was using imagereader to an animated video should do it. Then using Loop() to loop the video so it repeats while the main video is playing. I have that working but producing a mask so that the black areas are translucent is proving difficult. I have it almost working but even after making a mask of the overlay video for which I used a short TV logo animation I had and resized smaller the overlay is showing a darkened area where the overlaid border edges are rather than it being totally transparent like I believe it should be. The mask is being converted so that the black TV areas are black $000000 and the other active picture areas which are none black are white. Does anyone know why this is not working correctly and why the outline is there when that area should be transparent?
# All video is YV12
Source=dgdecode_mpeg2source("D:\Video\test.d2v")
source=LeakKernelDeint(source,order=1)
Source=bilinearresize( Source ,640,352, 4,2,-6,-2)
overlay_video=loop(avisource("D:\Video\hfyu_mini_logo_vid.avi", audio=false) )
overlay_Mask=ColorYUV(overlay_video, levels="TV->PC").greyscale().levels(0,1.0,1,0,255)
Source=overlay( Source, overlay_video, 508, 248, overlay_Mask, 1.0, "blend")
return Source
Logo_Mask=ColorYUV(Logo, levels="TV->PC").greyscale().levels(0,1.0,1,0,255) # to convert a small YV12 video clip to black and white to mask the overlay so that black areas show the video beneath the overlay clip
You can see it here. It has been cropped to show the overlay and you can see the overlay outline is darker than the surrounding area. This is with a 1.0 opacity setting but lowering that only reduces the different.
http://i34.tinypic.com/4tvtz6.png
the mask produced by the line above for this frame
http://i33.tinypic.com/24y1v0m.png
I was already using ConditionalReader to change the x & y offsets to allow movement so that is not a problem.
kemuri-_9
25th October 2008, 00:10
that's because the mask is YV12, I've found it do that with YUY2/YV12 masks.
have the mask in RGB24/32 and then apply it with overlay, shouldn't show the shadowed box then.
RedDwarf1
25th October 2008, 03:36
Thanks for pointing me in the right direction. I had been manually making RGB masks previously for stationary overlays but as you will understand, with a multi frame video overlay that is very impractical.
I have fixed it now by converting the overlay video and mask to RGB. :D
Gavino
25th October 2008, 11:47
I have fixed it now by converting the overlay video and mask to RGB. :D
There is no need to do that - Overlay works fine with YUV clips and it's faster too, since it works internally in YUV.
The real problem was your script was setting the mask wrong. For YUV, instead of
mask=ColorYUV(video, levels="TV->PC").greyscale().levels(0,1.0,1,0,255)
you need to use
mask=ColorYUV(video, levels="TV->PC").levels(0,1.0,1,0,255, coring=false)
RedDwarf1
27th October 2008, 07:01
There is no need to do that - Overlay works fine with YUV clips and it's faster too, since it works internally in YUV.
The real problem was your script was setting the mask wrong. For YUV, instead of
mask=ColorYUV(video, levels="TV->PC").greyscale().levels(0,1.0,1,0,255)
you need to use
mask=ColorYUV(video, levels="TV->PC").levels(0,1.0,1,0,255, coring=false)
Nice one. Thanks I will give that a try.
vBulletin® v3.8.5, Copyright ©2000-2012, Jelsoft Enterprises Ltd.