View Full Version : Need help for a recursive AVS function.
scharfis_brain
20th March 2008, 20:58
Hello everyone.
I am searching for an AVS-Function that takes an
input image and crops it into a given number of tiles and returns an interleaved clip of these tiles.
eg:
function tile(clip i, int count)
{
}
if the source image is 500x500 pixels
the function tile(last, 5) call shall put out 5 frames of 500x100 pixels.
I tried it, but it does not work :(
function serialcrop(clip i, clip j, int count, int all)
{
return (count > 0) ? interleave(i.subtitle(string(count)).crop(0,0,0,j.height/all), serialcrop(j.crop(0,(j.height/all)*(count-1),0,(j.height/all)*count),j,count-1,all)) : i.subtitle("x") #stackvertical(i, j.crop(0,0,0,j.height/all) )
}
i -> frames to be returned (changes during the iterations)
j -> input clip (stays static during the iterations)
count -> number of tiles (decreases during the iterations)
all -> number of tiles (stays static during the iterations)
it works somehow, but it spits out the tiles in a werid order :(
Wilbert
20th March 2008, 22:50
Try something like:
function serialcrop(clip j, int count, int ratio)
{
return (count > 1) ? interleave(j.crop(0,0,0,-(count-1)*ratio).subtitle(string(count)),
\ serialcrop(j.crop(0,ratio,0,0),count-1,ratio)) :
\ j.subtitle(string(ratio))
}
clip = ...
ratio = clip.height/count # type: int, and always the same here
serialcrop(clip, count, ratio)
I didn't test it, so probably doesn't work as it is.
stickboy
20th March 2008, 22:54
Hello everyone.
it works somehow, but it spits out the tiles in a werid orderIt's because you are recursively calling Interleave with two arguments each time; on each recursive call, you alternate frames from the two argument clips. You need to call Interleave with "count" argument clips.
Let me think. You probably could do it by recursively building up a string of arguments to supply to Interleave and then using Eval. There are probably better ways (my InterleaveEvery function might work too).
gzarkadas
21st March 2008, 16:26
Try the following code (it requires installation of latest AVSLib version). It basically follows the suggestion by stickboy, using the array functions to build the argument string to Interleave.
LoadPackage("avslib", "array")
# NO checks of arguments are made; add it as needed
# Assumes c.Height is divisible by cnt and valid for c's colorspace
#
function Tile(clip c, int cnt) {
global __tile_c = c
cut_y = Round(c.Height / cnt)
crop_left = ArrayFill(0, cnt)
crop_top = ArrayRange(0, cnt - 1).ArrayOpValue(cut_y, "*")
crops = ArrayOpArrayFunc(crop_left, crop_top, "__tile_c.Crop", String(c.Width) + "," + String(cut_y))
return Eval("Interleave(" + crops + ")")
}
To be complete the function should make basic argument checks but I have left them out for easier inspection of the core ideas behind.
Gavino
24th March 2008, 17:03
Here is an alternative version (again based on stickboy's idea) that uses only core Avisynth functions.
function Slice(clip c, int n, int count) {
# produce the nth of 'count' horizontal slices of input clip
# (assumes height and colorspace valid for this operation)
h = c.height/count
Crop(c, 0, (n-1)*h, c.width, h)
}
function BuildArgs(string clipName, int n, int count) {
# construct arguments 'n' to 'count' (inclusive) for Interleave, as a string
argn = "Slice(" + clipName + "," + string(n) + "," + string(count) + ")"
(n == count ? argn : argn + "," + BuildArgs(clipName, n+1, count))
}
function Tile(clip c, int count) {
# the user-level function requested by scharfis_brain
Eval("Interleave(" + BuildArgs("c", 1, count) + ")")
}
It is quite instructive to realize that the recursion incurs no 'run-time' overhead and is used only to construct the required filter chain. (Indeed, this is probably true of almost all realistic examples of recursion in Avisynth.)
scharfis_brain
24th March 2008, 18:28
thank you!
this helped me a lot!
I needed it for this purpose:
http://www.dvdboard.de/forum/showthread.php?t=125764&highlight=mostile
Terka
6th April 2008, 11:55
how could the slice function be used in a loop
to cut the input clip to tiles clips and filter them separately?
gzarkadas
6th April 2008, 18:45
It depends on the number of tiles and the filtering you intend to do and how you plan to merge the filtered tiles later.
-- For few tiles and/or one-shot projects it is better to assign the result of Slice directly to variables and proceed as normal (ie hard-code Slice calls).
-- For a generic solution you need to provide a generic placeholder for the generated variables, so that the rest of the script can access them. Alternatively, you need a way to selectively run a filter chain, based on current value of n, on the result of Slice and at the same time merge the filtered tiles in the output clip.
If you opt for the later case, you can make your life easier by using a ready-made library, as in the example below.
1. Create the tiles as separate clips (assumes that already "Slice" has been defined, the input clip has been assigned to variable "c" and the total number of tiles has been assigned to variable "count"):
LoadPackage("avslib", "array")
src = ArrayFill(c, count)
ids = ArrayRange(1, count)
tiles = ArrayOpArrayFunc(src, ids, "Slice", String(count))
2. Filter the tiles at your taste:
function my_tile_filter(clip c, int tile_id) { ... }
filtered = ArrayOpArrayFunc(tiles, ids, "my_tile_filter")
3. For merging of the filtered tiles there are plenty of options, say:
# reconstruct source clip, filtered in zones
final = filtered.ArraySum(sum_func="StackVertical")
...
# interleave tiles
final = Eval("Interleave(" + filtered + ")")
...
# join (with +) tile-clips one after the other
final = filtered.ArraySum()
...
Terka
7th April 2008, 13:00
thank you for reply, ill try it.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.