View Full Version : Building a function - newbie question
Gargalash
31st August 2009, 15:59
Hello,
I have scripts in which I often use the following lines:
source=last
backward_vec2 = source.MVAnalyse(isb = true, delta = 2, pel = 2, overlap=4, sharp=1, idx = 1)
backward_vec1 = source.MVAnalyse(isb = true, delta = 1, pel = 2, overlap=4, sharp=1, idx = 1)
forward_vec1 = source.MVAnalyse(isb = false, delta = 1, pel = 2, overlap=4, sharp=1, idx = 1)
forward_vec2 = source.MVAnalyse(isb = false, delta = 2, pel = 2, overlap=4, sharp=1, idx = 1)
source.MVDegrain2(backward_vec1,forward_vec1,backward_vec2,forward_vec2,thSAD=200,idx=1)
clip=last
last
}
I told myself it would be more practical to include all those lines in one function called "Mydegrainer()" so I made the following and saved it in a file named "Mydegrainer.avs" and I am importing it in my script:
function Mydegrainer(){
source=last
backward_vec2 = source.MVAnalyse(isb = true, delta = 2, pel = 2, overlap=4, sharp=1, idx = 1)
backward_vec1 = source.MVAnalyse(isb = true, delta = 1, pel = 2, overlap=4, sharp=1, idx = 1)
forward_vec1 = source.MVAnalyse(isb = false, delta = 1, pel = 2, overlap=4, sharp=1, idx = 1)
forward_vec2 = source.MVAnalyse(isb = false, delta = 2, pel = 2, overlap=4, sharp=1, idx = 1)
source.MVDegrain2(backward_vec1,forward_vec1,backward_vec2,forward_vec2,thSAD=200,idx=1)
clip=last
last
}
Then I simply call it with:
Mydegrainer()
This is where I have trouble. I get this error:
Invalid arguments to function "MVAnalyse"
(C:\Program Files\AviSynth 2.57\plugins\Mydegrainer.avs, line 3)
I supposed I have a lack of understanding of basic AVISynth.
Thanks for helping!
MatLz
31st August 2009, 18:06
function Mydegrainer(clip source)
{
backward_vec2 = source.MVAnalyse(isb = true, delta = 2, pel = 2, overlap=4, sharp=1, idx = 1)
backward_vec1 = source.MVAnalyse(isb = true, delta = 1, pel = 2, overlap=4, sharp=1, idx = 1)
forward_vec1 = source.MVAnalyse(isb = false, delta = 1, pel = 2, overlap=4, sharp=1, idx = 1)
forward_vec2 = source.MVAnalyse(isb = false, delta = 2, pel = 2, overlap=4, sharp=1, idx = 1)
source.MVDegrain2(backward_vec1,forward_vec1,backward_vec2,forward_vec2,thSAD=200,idx=1)
}
Gargalash
31st August 2009, 18:50
MatLz, thanks for your help, as you probably know, it works.
I have another question regarding this. I would like to add a parameter to my function call to control the strength of the denoising by changing the "thSAD" parameter of MVDegrain2
I did this in Mydegrainer.avs:
function Mydegrainer(clip source, int "strength" )
{
STR= strength
backward_vec2 = source.MVAnalyse(isb = true, delta = 2, pel = 2, overlap=4, sharp=1, idx = 1)
backward_vec1 = source.MVAnalyse(isb = true, delta = 1, pel = 2, overlap=4, sharp=1, idx = 1)
forward_vec1 = source.MVAnalyse(isb = false, delta = 1, pel = 2, overlap=4, sharp=1, idx = 1)
forward_vec2 = source.MVAnalyse(isb = false, delta = 2, pel = 2, overlap=4, sharp=1, idx = 1)
source.MVDegrain2(backward_vec1,forward_vec1,backward_vec2,forward_vec2,thSAD=STR,idx=1)
}
And I call the function like this:
Mydegrainer(strength = 400)
The filter strength does vary when I change de value, but: Is this the right way to do it?
Gavino
31st August 2009, 19:04
Yes, you've basically got the idea.
You don't need to say STR=strength, you can just use 'strength' itself like MVDegrain2( ... ,thSAD=strength, ...).
By putting the name in quotes in the function header, you are defining strength as an optional argument. So you should give it a default value, eg
strength = Default(strength, 400)
Then you can just call it as MVDegrainer() and it will use 400.
See http://avisynth.org/mediawiki/User_defined_script_functions.
Gargalash
31st August 2009, 20:11
Thanks for the explanation and the reference Gavino!
MatLz
31st August 2009, 21:01
I think MVDegrain2 is very usefull for big noise removing, but it is incredibly slow!
For little noise removing, I think MVDegrain1 is enough and is 3x faster than MVDegrain2.
So I made you a simple function:
mydegrainer(mode,strength)
"mode" is for use MVDegrain1 or MVDegrain2 (MVDegrain1 always in use except with "mode=2")
"strength" is for change value of thsad (default is 200)
Gargalash
2nd September 2009, 14:26
MatLz,
Thanks for this, I will look at it when it gets approved! Indeed MVDegrain2 is slow, I never made tests to consider this. But at the same time, I do need the strong denoising some times.
Would you say MVDegrain1 is a good pick to improve compressibility?
thewebchat
2nd September 2009, 15:17
Rather than MVDeGrain, have you considered using MDeGrain (mvtools2)? If you need fast denoising, you could try FFT3DFilter (17fps on 480p and Core 2) or FFT3DGPU. Unlike MVDeGrain, FFT3DFilter can actually remove grain, which should be significantly better for compressibility
Gargalash
2nd September 2009, 15:24
Fast is not necessary at all. The more compressibility gained, the better. With this new information, would you recommend another degrainer? I will check that page where a comparison of the various degrainer was made...
Thanks!
thewebchat
2nd September 2009, 15:50
Well, the question is if you want the result to look good or if you want it compressible. MDeGrain1/2 will probably not remove all your temporal noise and it will definitely not remove any spatial noise. MDeGrain3 will probably remove all temporal noise. If you want more compressibility, you need to add a spatial denoiser. TNLMeans is usually better than dfttest is usually better than FFT3DFilter, but only FFT3DFilter is fast enough to be usable. Spatial denoising will eat details very quickly.
Gavino
2nd September 2009, 15:50
OTD = ((mode==2)==true) ? ...
Surely it's clearer and simpler just to write
OTD = (mode==2) ? ...
MatLz
2nd September 2009, 17:35
Surely it's clearer and simpler just to write
OTD = (mode==2) ? ...
Hum hum... It happens with the newbies! It works but needs to be cleaned, you're totally right.
Thanks Gavino.
MatLz
2nd September 2009, 18:26
function chain(clip INP,int "mode",int "dn",int "sh")
{
mode=default(mode,0)
dn=default(dn,mode)
sh=default(sh,mode)
dnv=(dn==1) ? 5 : 0
dnv=(dn==2) ? 7 : dnv
dnv=(dn==3) ? 10 : dnv
OD=(dn==0) ? INP : denoise(OTD,dnv)
shv=(sh==1) ? 0.2 : 0
shv=(sh==2) ? 0.35 : shv
shv=(sh==3) ? 0.5 : shv
OUT=(sh==0) ? OD : sharpen(OD,shv)
return OUT
}
I want to chain some filters like that, with presets. It seems to work but I'm not sure about the conditionally order and the "else" values.
Gavino
2nd September 2009, 19:34
dnv=(dn==1) ? 5 : 0
dnv=(dn==2) ? 7 : dnv
dnv=(dn==3) ? 10 : dnv
OD=(dn==0) ? INP : denoise(OTD,dnv)
OTD isn't defined - you probably meant INP here.
For conditional setting of one value based on another, I prefer to use the (often-forgotten) Select (http://avisynth.org/mediawiki/Internal_functions/Control_functions) function.
It's also a good idea to have a validation check for arguments.
Assert(dn >= 0 && dn <= 3, "dn must be in range 0-3")
dnv = Select(dn, 0, 5, 7, 10)
MatLz
2nd September 2009, 20:03
OTD isn't defined - you probably meant INP here.
Yes, I've cut 6 filters chain and forgot to change.
Deblock, temporaldenoising, spatialdenoising, debanding, edges deringing and sharpening.
I will try your suggestion after eating. It seems to be a nice alternative.
Thanks Gavino.
A+
MatLz
3rd September 2009, 01:31
Well, it does work perfectly as expected, for attribuating values and bypass.
But I've notice a really strange thing:
If I use edeen when warpsharp is in the plugins directory, it causes parasites or a crash!..annoying, I use these two filters in my function...
Any idea?
thewebchat
3rd September 2009, 01:36
You could, uh, not use WarpSharp and eDeen. If that doesn't work for you, try loading them manually or using an alternative warp sharpener (e.g. awarpsharp, awarpsharp2, masktools).
Scintilla
4th September 2009, 18:26
If I use edeen when warpsharp is in the plugins directory, it causes parasites or a crash!..annoying, I use these two filters in my function...
Personally, I can't get VirtualDub(/Mod) to open any scripts at all if I have WarpSharp in the plugins directory. It's known to break autoloading; just move it somewhere else and load it manually.
MatLz
29th September 2009, 14:53
OUT = (a >= 1) ? filtering(INP) : INP
OUT = (a >= 2) ? filtering(OUT) : OUT
OUT = (a >= 3) ? filtering(OUT) : OUT
OUT = (a >= 4) ? filtering(OUT) : OUT
OUT = (a >= 5) ? filtering(OUT) : OUT
(...)
OUT = (a >= n) ? filtering(OUT) : OUT
In Avisynth, is there an other simply way to apply a filtering n times?
Well..."OUT=filtering(INP)^n" doesn't work of course!(just to illustrate)...but, can a command like that will be added in a new Avisynth version?
kemuri-_9
29th September 2009, 15:18
use gscript's while capability or use a recursive function:
function MultiApply(clip clip, string func, int times)
{
clip
(times > 0) ? Eval(func) : last
return( (times > 1) ? MultiApply(last,func,times-1) : last )
}
ColorBars().trim(0,499)
MultiApply("Blur(1.0)",20)
will apply blur(1.0) 20 times to the clip
MatLz
29th September 2009, 15:42
It works!
I've call this function k9ma.
Very usefull for masktools filters.
Thank you Kemuri-_9!
Gavino
29th September 2009, 19:23
use gscript's while capability or use a recursive function
GScript also has a 'for' loop which works well for this:
GScript("""
for (i = 1, 20) { Blur(1.0) }
""")
MatLz
30th September 2009, 07:40
Thanks Gavino, it works but there is a little problem with setting n time to 0.
With the recursive function, set n to 0 mean a complete bypass of traitment...but with Gscript it doesn't work. I know it's a particular case, but in a chain of filtering this can happen if need is.
Gavino
30th September 2009, 09:42
With the recursive function, set n to 0 mean a complete bypass of traitment...but with Gscript it doesn't work.
It should work...
GScript(" for (i = 1, n) { Blur(1.0) } ")
will do nothing if n=0, and leave 'last' unchanged.
However, if this is the last statement in a function (or a script), you will need to add 'return last', since in the n=0 case GScript itself will return an 'empty' value.
MatLz
15th October 2009, 14:46
Indeed and of course, it does work. I forgot the return to the last...newbie error...
Sorry for late answer too.
Well, I have a new stupid question about expressions we can have in, for example, masktools filter:
"x 128 / 0.67 ^ 255 *"
...is possible to change a value in a variable? Like that:
"x 128 / 0.67 ^ V *"
Didée
15th October 2009, 16:27
function Foo( clip c, int "scale" )
{
scale = default( scale, 255 )
[...]
... "x 128 / 0.67 ^ "+string(scale)+" *" ...
[...]
}
MatLz
15th October 2009, 16:42
It does work perfectly.
Thank you very much Didée.
MatLz
20th November 2009, 22:59
Hi! I'm again in trouble...
AVSIfunction k9ma(clip K9MAIN,string f,int t)
{
K9MAIN
(t>0) ? Eval(f) : last
return((t>1) ? k9ma(last, f, t-1) : last)
}SCRIPT...
k9ma("""deleteframe(startframe)""",numberofframestodelete)
With small numberofframestodelete's value it works, with high values all my previews crashe without any error messages!
Is there a limitation of the consecutive frames we can delete with deleteframe?or am I doing something else wrong?
Gavino
20th November 2009, 23:30
With small numberofframestodelete's value it works, with high values all my previews crashe without any error messages!
How high are the values you are talking about?
You are probably getting a stack overflow because of too many recursive calls, although my experience is you can usually get away with several hundred, at least.
You could rewrite your function as a loop using GScript instead of recursion. But of course there are better ways of deleting many frames, eg Trim. ;)
MatLz
20th November 2009, 23:42
I did test with high values...1500frames approximately.
Yes I know trim, I'm not really a newbie ;), but in the case we have a lot of sources and a lot of trim(sources), it calls too much times the input source plugin so eats a lot of ram!
I will try with Gscript.
Gavino
20th November 2009, 23:53
Trim is virtually a cost-free operation, in both time and memory, so I don't understand your remark. DeleteFrame is also cheap, but 1500 DeleteFrame instances will use much more resources than the equivalent single Trim+Splice.
And how does the source come into it?
Guest
21st November 2009, 04:47
He means he does this:
part1=AVISource().Trim()
part2=AVISource().Trim()
part3=AVISource().Trim()
Instead of the correct way:
vid=AVISource()
part1=vid.Trim()
part2=vid.Trim()
part3=vid.Trim()
MatLz
21st November 2009, 11:09
@You two
You're absolutely right, I was mistaken.
Call too much sources in the incorrect way increase memory usage...it's not trim. And 'deleteframe' eats more ram than trim for the same editing.
MatLz
21st November 2009, 11:13
But I'm a rebel:devil:, I want the word "del" in my useless function!function del(clip IN ,int "a",int "b",int "c",int "d",int "e",int "f"...)
{
trim(IN,0,a-1)+trim(IN,b+1,0)
trim(last,0,c-1)+trim(last,d+1,0)
trim(last,0,e-1)+trim(last,f+1,0)
...
}This works if we start by the end and go to the begining. But is possible in Avisynth to sort values by "decreased values"?
With that, it will be possible to set the couples of values (a/b,c/d,e/f...) in disorder...rebel:devil:
Gavino
21st November 2009, 11:29
Sorting is difficult (perhaps impossible?) since the script language doesn't have arrays.
Your function is incomplete too - it won't work if a (c, e, etc) is 0 or 1, or if b (d, f, etc) is the last frame.
The simplest way to delete a range of frames a to b is Loop(0, a, b).
MatLz
21st November 2009, 11:45
Of course it is incomplete! I can't write more than 500bytes of caracters in my posts...:(
For sorting there are the operators '>' but it's a real hassle with high number of variable...
Thanks for the loop idea, I didn't see this function in the doc!!
Gavino
21st November 2009, 11:55
By 'incomplete', I meant it does not work for certain values of the arguments, because of the special meaning of 0 and -1 in Trim.
Trim(0,a-1) doesn't do what you want when a is 0 or 1.
Trim(b+1,0) will repeat the last frame if b is framecount-1.
You will avoid these issues by using Loop.
MatLz
21st November 2009, 12:16
But I don't want set 0 or 1 to the arguments! Why do that?
It was just to simplify the usage, for example instead of
trim(0,10)+trim(20,0)
-> del(11,19)
Is it not more easy if there are lot of trim?
Gavino
21st November 2009, 12:33
But I don't want set 0 or 1 to the arguments! Why do that?
What if you want to delete frames 1 to 10, say.
del(1,10) doesn't work as written with the Trim approach.
You might say you'll never want to do that, but the point of a function (especially one that you want to reuse in any script) is to 'cover all the bases'. If some combination of arguments doesn't work, the function is less useful than it could be.
MatLz
21st November 2009, 13:03
ARRGGGH, I'm lost now...:confused:
Does this fix the 1 issue?
function del(clip IN ,int "a",int "b")
{
INA=(a==1) ? deleteframe(IN,1) : IN
a=(a==1) ? 2 : a
trim(INA,0,a-1)+trim(IN,b+1,0)
}:confused:
Gavino
21st November 2009, 14:55
Does this fix the 1 issue?
No, del(1,10) would incorrectly retain frame 2. Try it and see!
Tip: add ShowFrameNumber() when testing functions like this.
function del(clip IN, int a, int b) {
IN.Trim(0, -a) + IN.Trim(b+1, 0)
}
works, but still leaves the problem if a=0 or b=framecount-1.
You avoid these problems by writing it as
function del(clip IN, int a, int b) {
IN.Loop(0, a, b)
}
Also, remove the quotes from "a" and "b" because these are not optional arguments.
See this thread for stickboy's classic description of the Trim problem, and here (http://avisynth.org/stickboy/jdl-util.avsi) for his Trim2 and Trim3 solution.
MatLz
22nd November 2009, 00:54
Well well well...if I'm right, I claim copyright!...I think I did it.
Three zones by sorting 6 variables...as expected it was a real hassle.....for my tiny brain...;)
MatLz
22nd November 2009, 01:01
So for example that means:
Del(100,200,300,400,500,600) = Del(500,600,100,200,300,400) = Del(300,400,500,600,100,200).....
Maybe useless but...done...
Gavino
22nd November 2009, 12:20
Well done.
For up to 3 pairs, you can just run through the 6 possible orders as you have done.
Extending this to 4 or more pairs would be very tedious.
I have a feeling the logic could be expressed more simply using GScript's block 'if'.
Have you considered using that? It would make an interesting comparison.
Possible refinement: detect and reject invalid ranges (b<a) or overlapping ones (messy).
A small improvement:
aa = defined(c)&&a>c ? a : a
aa = defined(c)&&c>a ? c : aa
can be replaced by
aa = defined(c)&&c>a ? c : a
and
cc = defined(c)&&a>c ? c : c
cc = defined(c)&&c>a ? a : cc
by
cc = defined(c)&&c>a ? a : c
I learned something from this too - I didn't realise you could just write a>c>e instead of a>c && c>e.
Though this reveals a language pitfall (not in your code) which could catch people out: a>b == false is interpreted as a>b && b==false, meaning that if a is not > b, it returns false instead of the expected true (if a>b, it gives an error).
MatLz
22nd November 2009, 17:07
Yes some parts need to be cleaned, it was just to develop the basis of a logical chain order in my mind, I will correct that, thanks.
You're also right:
4zones/8variables with that method would be tedious...maybe more than 200 supplemantary lines no?
I will also add 'assert' functions for invalid ranges.
I will take a look with Gscript scripting for more zones....but only if people are interested by this a little useless function!
Gavino
22nd November 2009, 18:37
As I thought, it comes out more simply (IMHO) using GScript.
Here's the GScript version of your 3-range function:
GScript("""
function del(clip IN,int a,int b,int "c",int "d",int "e",int "f")
{
if (!defined(c)) { # single range
aa=a bb=b
}
else if (!defined(e)) { # 2 ranges
if (a > c) { aa=a bb=b cc=c dd=d }
else { aa=c bb=d cc=a dd=b }
}
else { # 3 ranges
if (a > c > e) { aa=a bb=b cc=c dd=d ee=e ff=f }
else if (a > e > c) { aa=a bb=b cc=e dd=f ee=c ff=d }
else if (c > a > e) { aa=c bb=d cc=a dd=b ee=e ff=f }
else if (c > e > a) { aa=c bb=d cc=e dd=f ee=a ff=b }
else if (e > a > c) { aa=e bb=f cc=a dd=b ee=c ff=d }
else if (e > c > a) { aa=e bb=f cc=c dd=d ee=a ff=b }
# else error (2 or more are equal)
}
loop(IN,0,aa,bb)
if (defined(c)) { loop(0,cc,dd) }
if (defined(e)) { loop(0,ee,ff) }
return last
}
""")
Extending it in a similar way to 4 ranges would need around another 24 (=factorial 4) lines (and 120 lines for 5 ranges!).
MatLz
23rd November 2009, 03:28
Ok, it's done for 4 ranges....but it seems we can't use assert function with GScript! Crashes without any error messages...
Gavino
23rd November 2009, 10:44
I can't reproduce the GScript/Assert problem. Please post your script. If you can reduce it to a small example, so much the better.
MatLz
23rd November 2009, 11:47
scriptdel(13,20)avsiGScript("""
function del(clip IN,int a,int b)
{
Assert(a!=13, "NO NO NO 13 IS NOT ALLOWED!!!")
loop(IN,0,a,b)
}
""")I can't do more small...
With others values than the assertion it doesn't crashe. Simple del function does work, error message appears.
Strange...
Well, in all cases, GScript allowed to me to make the 4 ranges in 2x less time than the 3 ranges with the "regular method"! Really nice!
Gavino
23rd November 2009, 13:09
Thanks - I will investigate.
In the meantime, try moving the GScript call inside the function:
function del(clip IN,int a,int b)
{
GScript("""
Assert(a!=13, "NO NO NO 13 IS NOT ALLOWED!!!")
loop(IN,0,a,b)
""")
}
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.