View Full Version : [solved] interleave in a loop (open n numbered clips and interleave)
jmac698
4th August 2012, 11:35
Hi,
I'm stuck with how to script this.
Normally if I have a set of clips, v1, v2, v3...
I can do
interleave(v1, v2, v3...)
My problem is, I want to do this in a loop, for an arbitrary number of clips.
The first problem is that there's no arrays of videos, but that's ok, I really just wanted to load a set of files anyhow.
I can easily load a set of numbered clips with
v=avisource(dir+fn+String(n, "%02.0f")+".avi")
n=n+1
Except that I wouldn't really write it that way of course, I'd put it in a loop, with recursion or GScript.
In order to store those clips into one (a type of array workaround), I want to interleave them together as I open them.
Doing something like:
#inner loop
vcurrent=avisource(...)
interleave(v,vcurrent)
Isn't going to work. Thinks like stacking videos or joining clips can be done in such loops, but interleaving has to be done "all at once". There must be some approach to this, maybe with selectevery, joining clips, and so on.
Note: the clips are different lengths, and I'm using a temporal filter after this step, which requires the videos to be interleaved. The videos are actually the same captures for using the median technique. The order isn't really important, and the result can be trimmed to the smallest size detected while loading.
Thanks
StainlessS
4th August 2012, 12:25
Perhaps Stickboys InterleaveEvery could be persuaded to assist.
http://forum.doom9.org/showthread.php?p=467878#post467878
EDIT: Maybe something like (have not played with it):
clip1=Avisource(...)
clip2=Avisource(...)
clip3=Avisource(...)
clip4=Avisource(...)
clip5=Avisource(...)
etc
clip1=clip1.InterleaveEvery(clip2,2,1)
clip1=clip1.InterleaveEvery(clip3,3,2)
clip1=clip1.InterleaveEvery(clip4,4,3)
clip1=clip1.InterleaveEvery(clip5,5,4)
But in a loop (assuming all same length).
EDIT: Trim(0, nclips*minlen-1)
jmac698
4th August 2012, 12:48
That does look promising! The actual download: http://forum.doom9.org/showthread.php?p=461878#post461878
Apparently there's a script version, but it would crash eventually.
StainlessS
4th August 2012, 12:51
See Edit.
jmac698
4th August 2012, 13:37
Yep, that looks good.
I think the ideal function I want is
InterleaveClips(string basename, int n, int trim1, int trim2...)
Where basename is like "capture" to which string(n) is added, and there's optional trims for each clip off the beginning (this part is obviously not unlimited).
Then I can just do depulse, medianblurt(n) etc.
An even fancier version would allow you to supply the format string (for filename generation), to add a common processing step to each clip (needed for temporal processing of each clip), and really ideally, to take as much length as possible, let's say only 3 clips of 5 had frames at the end, to fill up the "empty" frames with copies of some of the others, this would let median always work with what's available.
IanB
4th August 2012, 23:16
Build a string with the argument list then Eval() it.Foo="Interleave("
...
Foo=Foo+"Clip"+String(N)+", "
...
Foo=Left(Foo, StrLen(Foo)-2)+")" # Fix last ", "
Eval(Foo) # Interleave(Clip1, Clip2, Clip3, ...)
ajp_anton
6th August 2012, 10:29
Another approach could be to join them end to end and then use selectevery(1,0,L,2*L,3*L,...) where L is the length of each clip. Assuming they are all the same length of course.
jmac698
6th August 2012, 10:48
Thanks! I like that idea the best. I can search for the minimum clip framelength as I load them.
StainlessS
6th August 2012, 11:26
for an arbitrary number of clips
Not sure, I think number of plugin args is limited to 64 (or thereabouts), have asked that question
before (without answer) and about limit on size of eg array of clips as a single arg (as used in
ClipClop and Prune which support up to 256 clips but dont know if Avisynth does).
EDIT: Anybody know what the limits on plug args are, in particular the max number
of "1 or more args of a type" supplied to plug as an AVSValue array?
ajp_anton
6th August 2012, 13:47
Thanks! I like that idea the best. I can search for the minimum clip framelength as I load them.Or the maximum length? I think interleave just repeats the last frame of the shorter clips to match the length of the longest, so you may have to do that manually here (or whatever method you use to match the lengths).
Also you may have to trim the end result to where selectevery has gone through the first clip.
It should also be possible to write another interleave function that interleaves two clips, but fits in an arbitrary number of frames from each clip instead of one at a time.
edit:
Hope this works. Some people don't seem to like scriptclip, but it's easier to write. Feel free to port it into something more efficient, and/or fix any bugs (I can't test this at the moment).
function interleave_group(clip v,clip u,int a,int "b")
{
# Interleaves frames from clips v,u in groups of a,b frames respectively.
# The resulting clip ends whenever one of the source clips end.
b = default(b,1)
interleave(v,u)
scriptclip("""
frame = current_frame
n = frame/(a+b)
m = frame%(a+b)
f = m<a ? a : b
c = m<a ? 0 : 1
m = m<a ? m : m-a
trim(2*(n*f+m)+c,-1)
""",args="a,b")
trim(0,-floor(min(v.framecount/a,u.framecount/b)*(a+b)))
}
StainlessS
6th August 2012, 18:23
@Wilbert,
Concerning above post
args="a,b"
In ScriptClip, does not seem to be in current 2.6 docs neither built in nor in wiki, have seen
it used before like that but on accessing docs, no mention found, perhaps hidden in some
advanced section of the docs.
EDIT: Above args="a,b" turns out to be part of Grunt plugin: http://forum.doom9.org/showthread.php?t=139337
EDIT: From builtin docs
ScriptClip (clip, string filter, bool "show", bool "after_frame")
jmac698
6th August 2012, 18:33
It's from GScriptClip
StainlessS
6th August 2012, 18:42
Thanks Jmac, turns out to be Grunt:
http://forum.doom9.org/showthread.php?t=139337
jmac698
6th August 2012, 20:05
What I meant :)
StainlessS
6th August 2012, 20:22
Tis an accolade to Grunt that it can so seamlessly slip into scriptclip, to the point where
you forget where extensions originate, it does also however mean that its very easy to forget
the reliance on Grunt and cause problems in published scripts. Perhaps I should
remove this great plugin from my plugins directory, and only load on known demand.
If any plugins should be integrated into Avisynth, then GScript and Grunt have to be top
of the list.
EDIT: With an additional 'Until' to match the 'While' in GScript.
jmac698
8th August 2012, 20:12
Well, enough talk, let's make some scripts.
Update:
The following correctly opens n clips in order, then joins, and interleaves them:
#Improved median script
dir="C:\project004\median\"
fn_prefix="sample"
#Open and interleave the files
n=3
OpenClips(dir, fn_prefix, n, true)
Function OpenClips(string dir, string fn, int n, bool label) {
#Open a set of numbered clips, interleave and return as one
#dir - directory of the clips
#fn - filename prefix
#n - number of clips to open. This number is added to the filename.
#label - if true, label each clip with the filename
#call the recursive version
_OpenClips(dir, fn, n, n, label)
l=last.framecount/n#** assuming same size!
interleave_group(last,l,n,true)
}
Function _OpenClips(string dir, string fn, int n, int i, bool label) {
#recursive version, containing current loop index i
#Note that this joins all the videos; to do is interleave them.
i<2 ? _Open(dir, fn, i, label) : _OpenClips(dir, fn, n, i-1, label) + _Open(dir, fn, i, label)
}
function _Open(string dir, string fn, int i, bool label) {
#function to open a numbered clip; just to shorten it's use elsewhere
avisource(dir+fn+String(i, "%1.0f")+".avi")
label ? subtitle(fn+String(i, "%1.0f")+".avi") : last
}
function interleave_group(clip v, int l, int n, bool debug) {
#rearrange the frames from 0..l-1, l..2*l-1..., n*l..(n+1)*l-1... to 0,l,1,l+1,...l-1,n*l
#this function has to avoid using anything with a long list of arguments, as that is a limiatation
v
GScriptClip("""
i=current_frame
clip=i%n
clips_frame=floor(i/n)
f=clip*l+clips_frame
trim(f,-1)
debug ? subtitle("current_frame="+string(i)+", converted to: "+string(f) \
+" which is clip="+string(clip)+", frame="+string(clips_frame),y=32) : last
""",args="l,n,debug")
}
jmac698
8th August 2012, 22:41
And here's the generalized median of n clips:
#Generalized Median
#0.1 by jmac
#A script to open n video clips and perform a median between them
#Requirements:
#MedianBlur (http://avisynth.org/warpenterprises/#MedianBlur) by tsp
#GRunt (http://forum.doom9.org/showthread.php?t=139337) by Gavino
#Usage:
#This script is meant to be used in a denoising technique which takes n captures of
# the same video from videotape, then performs a median on them, to reduce noise and dropouts/comets
#It requires the n clips to be prepared to the same length, same starting point, and no dropped frames between them
#Therefore, the script could use some practical improvements, like matching start points or accounting for dropped/duped frames,
# or different clip lengths.
#It's also very slow for many clips.
#set the dir to your clip directory
#set the filename to the common part of your filename
#set n to the number of clips. The files must be named like clip1.avi, clip2,avi, ... clipn.avi
dir="C:\project004\median\"
fn_prefix="sample"
#Open and interleave the files
n=3
OpenClips(dir, fn_prefix, n, false)
TemporalMedian(n)
Function OpenClips(string dir, string fn, int n, bool label) {
#Open a set of numbered clips, interleave and return as one
#dir - directory of the clips
#fn - filename prefix
#n - number of clips to open. This number is added to the filename.
#label - if true, label each clip with the filename
#call the recursive version
_OpenClips(dir, fn, n, n, label)
l=last.framecount/n#** assuming same size!
interleave_group(last,l,n,false)
}
Function _OpenClips(string dir, string fn, int n, int i, bool label) {
#recursive version, containing current loop index i
#Note that this joins all the videos; to do is interleave them.
i<2 ? _Open(dir, fn, i, label) : _OpenClips(dir, fn, n, i-1, label) + _Open(dir, fn, i, label)
}
function _Open(string dir, string fn, int i, bool label) {
#function to open a numbered clip; just to shorten it's use elsewhere
avisource(dir+fn+String(i, "%1.0f")+".avi")
label ? subtitle(fn+String(i, "%1.0f")+".avi") : last
}
function interleave_group(clip v, int l, int n, bool debug) {
#rearrange the frames from 0..l-1, l..2*l-1..., n*l..(n+1)*l-1... to 0,l,1,l+1,...l-1,n*l
#this function has to avoid using anything with a long list of arguments, as that is a limiatation
v
GScriptClip("""
i=current_frame
clip=i%n
clips_frame=floor(i/n)
f=clip*l+clips_frame
trim(f,-1)
debug ? subtitle("current_frame="+string(i)+", converted to: "+string(f) \
+" which is clip="+string(clip)+", frame="+string(clips_frame),y=32) : last
""",args="l,n,debug")
}
function TemporalMedian(clip a, int n) {
#Perform a temporal median of n clips. n must be odd.
#The clips must be prepared with this command: interleave(clip1, clip2, ... clipn)
a.MedianBlurT(0,0,0,(n-1)/2)#From MedianBlur dll
SelectEvery(n,(n-1)/2)
}
Any ideas on how I could extend this to duplicate parts of clips that are not the same length? Hmm.. maybe I need a function to return a frame from the longest clip if it exceeds the framecount of the specified clip. I also want to trim the starts with a text file.
vBulletin® v3.8.11, Copyright ©2000-2025, vBulletin Solutions Inc.