PDA

View Full Version : "Sticking" overlay


vova254
28th October 2009, 21:41
Hi, all!
I will greatly appreciate if anyone help me to write the following script.
I need to overlay one "small" clip on another "big" (image sequense) with changing left edge position. For this purpose i use ConditionalReader filter and left x coordinate from a text file as follows:

global in = DirectshowSource("test.mkv", fps=25)
CoronaSequence("bio%06d.jpg", 0, 99, gapless = true).AssumeFPS(1.00*25/20).ChangeFPS(in)
ScriptClip("""Layer(last,in,"add",256,left,14)""")
ConditionalReader("left1.txt", "left")

But also i need to leave each frame of overlayed clip on the background and put every following frame on combination of "big" clip and previous frame of "small" clip. Unfortunally, i don't have enough experience in runtime filters to find a proper script.

Thanks in advance

Gavino
28th October 2009, 22:44
Replace the ScriptClip line with:
out = last
ScriptClip("""
out = Layer(out,in,"add",256,left,14)
return out
""")

Incidentally, there is no need for 'in' to be global.

vova254
30th October 2009, 19:32
Gavino, thanks a lot for your reply, but this is not what I need. As i see in result, this script duplicates the entire clip to all coordinate positions read from file, but i need to "stick" or "freeze" only one current frame to place where it appeared and overlay the further part of clip on the result, and so on for each frame. It will look like a "trace" of clip. I think, it should be some combination of Layer() and FreezeFrame() in runtime script working like a pipe, but i can't find a proper. Does the facilities of Avisynth allow to make these operations?

Gavino
30th October 2009, 20:13
As i see in result, this script duplicates the entire clip to all coordinate positions read from file, but i need to "stick" or "freeze" only one current frame to place where it appeared and overlay the further part of clip on the result, and so on for each frame. It will look like a "trace" of clip.
That's what I was attempting to do.
I must confess I didn't test it before posting, but I've just tried it now and you're right - it doesn't work correctly.
Sorry about that. You need to replace the out= ... with
out = Layer(out,in.FreezeFrame(0,in.Framecount()-1,current_frame),"add",256,left,14)

vova254
30th October 2009, 21:21
Great! Thanks a lot! I am very much obliged to you for your help.
Could you explain a little bit detailed how does your script work?
As i see again as in previous case, this script overlays several "freezed" (in terms of FreezeFrame() filter) videoclips on background. But the quantity of these 25-fps streams at the each moment is equal to current_frame number, and they are played simultaneously! It reduces to extremely slow operation of this script. Encoding speed drops almost to zero after several tens of frames. Is there any way to avoid this problem?
Using Trim(current_frame,-1) instead of FreezeFrame doesn't improve the situation.

Gavino
31st October 2009, 02:08
Could you explain a little bit detailed how does your script work?
The way it works essentially follows your description of the problem.
And the key to understanding it lies in understanding what ScriptClip actually does for each frame requested:
1) The variable current_frame is set and the run-time script is evaluated (equivalent to calling Eval on the string in triple-quotes). The result of this is (or should be) a clip.
2) The frame numbered by current_frame is fetched from that clip and delivered as the result of ScriptClip (for that frame).

The trick here is that the variable 'out' is used to remember the result of each evaluation so that it can be used in the next one. So the clip 'out' is built up on each frame by Layer'ing the corresponding frame of 'in' onto the clip created in the previous frame. And at each frame, the result 'so far' is delivered by ScriptClip.
As i see again as in previous case, this script overlays several "freezed" (in terms of FreezeFrame() filter) videoclips on background. But the quantity of these 25-fps streams at the each moment is equal to current_frame number, and they are played simultaneously! It reduces to extremely slow operation of this script. Encoding speed drops almost to zero after several tens of frames. Is there any way to avoid this problem?
Using Trim(current_frame,-1) instead of FreezeFrame doesn't improve the situation.
As you say, frame n consists of n+1 Layer operations, which will get increasingly slower with each additional frame. (FreezeFrame or Trim take negligible time compared to Layer.) At first sight, this appears to be inevitable, since each frame has a different background.

However, a possible way to improve this is to build up the layers on a transparent static background which can then be layered onto the original background clip. The advantage here is that each frame can be re-used in creating the next one, so each frame adds only one Layer operation.

Try this:
in = DirectshowSource("test.mkv", fps=25)
bg = CoronaSequence("bio%06d.jpg", 0, 99, gapless = true).AssumeFPS(1.00*25/20).ChangeFPS(in)
out = BlankClip(bg)
ScriptClip(bg, """
out = Layer(out.Loop(2,0,0),in.Trim(current_frame,-1),"add",256,left,14)
return out
""")
ConditionalReader("left1.txt", "left")
Layer(bg, last)
The extra trick here is that on each iteration, the Loop function is used to get the previous frame, which hopefully should be in the Avisynth cache, avoiding repeating the Layer operation for frames already created.

EDIT: I'm assuming your clips are RGB32. If not, you will need to add ConvertToRGB32 to in and bg.

vova254
31st October 2009, 11:54
You are a God!:) It works!

I'm assuming your clips are RGB32. If not, you will need to add ConvertToRGB32 to in and bg.

Yes, I perform this conversion, indeed. Simply, I didn't want to pay attention on inessential details. Finally, the script has the following code:

global divisor = 20
in = DirectshowSource("test.mkv", fps=25).ConvertToRGB32
bg = CoronaSequence("bio%06d.jpg", 0, 99, gapless = true).AssumeFPS(1.0000*25/divisor).ChangeFPS(in)
out = BlankClip(bg)
ScriptClip(bg, """
out = (current_frame%divisor==0)?Layer(BlankClip(bg),in.Trim(current_frame,-1),"add",256,left,14)_
_:Layer(out.Loop(2,0,0),in.Trim(current_frame,-1),"add",256,left,14)
return out
""")
ConditionalReader("left1.txt", "left")
Layer(bg,last).ConvertToYV12

I have slightly modified this script in comparison with your last variant, because I need to refresh the entire frame by every (divisor) screenshot (otherwise it will rub away with the trace of "small" clip). How does it seem for you, is there any pitfalls in this variant, which could influence on execution speed of the script?

Gavino
31st October 2009, 12:50
is there any pitfalls in this variant, which could influence on execution speed of the script?
A minor speed-up could perhaps be achieved by setting blank=BlankClip(bg) before ScriptClip and rewriting the run-time script as
out = (current_frame%divisor==0) ? blank : out.Loop(2,0,0)
out = Layer(out,in.Trim(current_frame,-1),"add",256,left,14)
return out
which reduces the overhead incurred on every frame.
BTW divisor doesn't need to be global, a run-time script runs at the same scope level as a main script.

I'm glad it worked, it was an interesting problem to solve. :D