Log in

View Full Version : Request for help to convert some Avisynth functions


Boulder
13th September 2015, 18:09
I'm trying to make the switch from Avisynth 2.6 to Vapoursynth as Avisynth has become very unstable ever since I got an i7. I'm currently trying to get the hang of the syntax and convert the stuff I always use to process videos.

I'm having some difficulties in converting the predenoiser helper functions that I use. Could someone please take a look at them and show some magic? There could be some native alternatives in Vapoursynth that I don't know of so feel free to customize if needed :)

function Prefilter (clip c, int "th", bool "chromamotion")
{
chromamotion = default(chromamotion, true)
output = Flux5framesT(c,th=th,chromamotion=chromamotion)
return output
}

function Flux5framesT(clip c, int "th", int "thC", bool "chromamotion")
{
chromamotion = default(chromamotion, true)
th = default(th, 2)
thC = default(thC, chromamotion ? th : 0)
med = chromamotion ? ytouv(c.utoy8().median5t(), c.vtoy8().median5t(), c.median5t()) : c.median5t().mergechroma(c)
avg = c.temporalsoften(2, th, thC, 24, 2)
output = interleave(c, med, avg).clense(grey=!chromamotion).selectevery(3,1)
return output
}

function median5t(clip src)
{
function min(clip a, clip b) {return mt_logic(a, b, mode="min")}
function max(clip a, clip b) {return mt_logic(a, b, mode="max")}
src
last + trim(framecount()-1,-1).loop(5)
bcmin = min(SelectEvery(2, -1), SelectEvery(2, 0))
bcmax = max(SelectEvery(2, -1), SelectEvery(2, 0))
demin = bcmin.SelectEvery(1, 1)
demax = bcmax.SelectEvery(1, 1)
x = max(bcmin, demin)
y = min(bcmax, demax)
a = SelectEvery(2, -2)
f = SelectEvery(2, 3)
Interleave(a, x, y, f).Clense(grey=true).SelectEvery(4, 1, 2)
trim(0,length=src.framecount())
}

Are_
13th September 2015, 22:59
I guess it can be greatly improved, because it is a pretty straight conversion without much thinking. And not really tested, I leave that to you. :P

import vapoursynth as vs


def prefilter(clip, thr=2, chromamotion=True):
core = vs.get_core()
return flux5framest(clip, thr=thr, chromamotion=chromamotion)


def flux5framest(clip, thr=2, thrc=None, chromamotion=True):
core = vs.get_core()

if chromamotion is True:
thrc = thr if thrc is None else thrc
else:
thrc = 0

if chromamotion is True:
y = core.std.ShufflePlanes(clip, planes=0, colorfamily=vs.GRAY)
u = core.std.ShufflePlanes(clip, planes=1, colorfamily=vs.GRAY)
v = core.std.ShufflePlanes(clip, planes=2, colorfamily=vs.GRAY)
med = core.std.ShufflePlanes([median5t(y), median5t(u), median5t(v)], planes=[0, 0, 0], colorfamily=vs.YUV)
else:
y = core.std.ShufflePlanes(clip, planes=0, colorfamily=vs.GRAY)
med = core.std.ShufflePlanes([median5t(y), clip, clip], planes=[0, 1, 2], colorfamily=vs.YUV)

avg = core.focus.TemporalSoften(clip, radius=2, luma_threshold=thr, chroma_threshold=thrc, scenechange=24, mode=2)
res = core.std.Interleave([clip, med, avg]).rgvs.Clense(planes=[0, 1, 2] if chromamotion is True else 0).std.SelectEvery(cycle=3, offsets=1)

return res

def median5t(clip):
core = vs.get_core()

def logic_max(c1, c2):
return core.std.Expr([c1, c2], expr=['x y max'])

def logic_min(c1, c2):
return core.std.Expr([c1, c2], expr=['x y min'])

last = core.std.DuplicateFrames(clip, frames=[clip.num_frames-1] * 5)
bcmin = logic_min(core.std.DuplicateFrames(last, frames=[0]).std.SelectEvery(cycle=2, offsets=1), core.std.SelectEvery(last, cycle=2, offsets=0))
bcmax = logic_max(core.std.DuplicateFrames(last, frames=[0]).std.SelectEvery(cycle=2, offsets=1), core.std.SelectEvery(last, cycle=2, offsets=0))
demin = core.std.DeleteFrames(bcmin, frames=0)
demax = core.std.DeleteFrames(bcmax, frames=0)
x = logic_max(bcmin, demin)
y = logic_min(bcmax, demax)
a = core.std.DuplicateFrames(last, frames=[0]).std.SelectEvery(cycle=2, offsets=0)
f = core.std.DeleteFrames(last, frames=0).std.SelectEvery(cycle=2, offsets=1)
last = core.std.Interleave([a, x, y, f]).rgvs.Clense(planes=0).std.SelectEvery(cycle=4, offsets=[1, 2])
return core.std.Trim(last, length=clip.num_frames)

Boulder
14th September 2015, 03:53
Thanks a lot, looks like you deciphered the negative offset in SelectEvery :) I'll try to test it today so that I can continue building the rest of the denoising process..

Boulder
14th September 2015, 16:23
I did some very quick testing and at least the effects seem the same as with the Avisynth equivalent. Will need to test it a bit more though to make sure :)

I'm using DGDecodeNV to decode my sources. I found out that the Vapoursynth prefilter function has an issue with some sources. The source filter reports some videos as "FPS: 120000/5005" and some as 24000/1001. Naturally, both return the same result but Interleave chokes with the first case with "vapoursynth.Error: Interleave: clip property mismatch". Using AssumeFPS helps there.

hydra3333
26th September 2015, 04:58
I'm using DGDecodeNV to decode my sources.
So do I. And the vanilla dgdecode.

Thanks for the examples above, that helps.

I'm not quite sure of the end-user advantages vapoursynth brings though.

As a non-python person, I am still considering trying out vapoursynth but have a few silly beginner queries since do not know where to start.

Is there a step by step beginners thread somewhere ?

Is there a portable non-installer version ?

Is there a consolidated sample script collection somewhere ? eg using qtgmc, mvtools, debglock_qed, lsfmod, mdegrain 1/2/3 (and their interlaced equivalent), re-interlacing pal progressive->TFF, fft3dfilter, interframe, and whatnot.

With the example functions above there are lots of core = vs.get_core()" ... is that because it's in a function (?terminology?) and only one is necessary for the main body ?

Any links or advice would be most welcome.

Are_
26th September 2015, 11:26
I'm not quite sure of the end-user advantages vapoursynth brings though.
Multi-threading, 64bit, active development.
As a non-python person, I am still considering trying out vapoursynth but have a few silly beginner queries since do not know where to start.

Is there a step by step beginners thread somewhere ?
Not really, maybe the main docs from vapoursynth (http://www.vapoursynth.com/doc/)?
Is there a portable non-installer version ?
No, there are no portable versions of python, so there can't be one for vapoursynth (as far as I know).
Is there a consolidated sample script collection somewhere ? eg using qtgmc, mvtools, debglock_qed, lsfmod, mdegrain 1/2/3 (and their interlaced equivalent), re-interlacing pal progressive->TFF, fft3dfilter, interframe, and whatnot.
I don't quite follow what are you trying to say there, havsfunc (http://forum.doom9.org/showthread.php?t=166582)? Plugin/function list form the main docs (http://www.vapoursynth.com/doc/pluginlist.html)?
With the example functions above there are lots of core = vs.get_core()" ... is that because it's in a function (?terminology?) and only one is necessary for the main body ?
This is because that's not a vapoursynth script itself, but a loadable module to load that specific functions, so that's specific to modules. Every module has to load the core inside every function it has to prevent bad stuff from happening.
For a main script it only needs it at the top of it, even in a main script there were to be many functions non of them will need to create a core instance inside of them.



Any links or advice would be most welcome.
Main vapoursynth docs (http://www.vapoursynth.com/doc/index.html) are very good. :P

hydra3333
26th September 2015, 15:34
Thank you.
I don't quite follow what are you trying to say there, havsfunc (http://forum.doom9.org/showthread.php?t=166582)? Plugin/function list form the main docs (http://www.vapoursynth.com/doc/pluginlist.html)
I have had a look at those pages and will give it a try.

I was looking for a set of example scripts with each of those functions being called with various settings. I gather sometimes there's overlap in parameter naming with ?reserved words? and you need to pass the parameter name with a preceding underscore ?

Not being sure of anything, the syntax mostly, I was looking for some smarter-than-me's actual working scripts to pinch and recycle for my own purposes. Particularly around qtgmc at fast, medium , and high settings similar to
QTGMC(Preset="Fast",EdiThreads=8,Sharpness=1.2,SLMode=1)
QTGMC(Preset="Slow",EdiThreads=8,Sharpness=1.2,SLMode=1)
QTGMC(Preset="Very Slow",EdiThreads=8,Sharpness=1.2,SLMode=2,EZKeepGrain=1.2,NoiseProcess=2)


I did find what looks to be a portable python in https://www.python.org/downloads/windows/ , but it appears as if vapoursynth only comes an an installer.

Can vapoursynth be installed and run alongside avisynth without them interfering with each other ?

Mystery Keeper
26th September 2015, 15:51
VapourSynth consists of two parts:
1) The core and the API it exposes. It can be used by any application and is unaware of any scripting at all.
2) vsscript - a Python module which is installed into Python distribution and is loaded BY Python when the script is evaluated.
So, VapourSynth installer needs to know where Python is installed. And vsscript needs to know where the core is installed. Thus, no portable version.

Myrsloik
26th September 2015, 15:58
I think it's theoretically possible to make a portable version but I'm too lazy to identify all the problems. Loading a pile of dlls that can be located anywhere is very annoying though. I do however plan on supporting per user installs some day though. That's usually good enough.

Mystery Keeper
27th September 2015, 02:22
In my opinion, the best solution would be a small and portable scripting library that doesn't depend on anything else.

Are_
27th September 2015, 11:41
@hydra3333

At your questions on how a basic vapoursynth script should look:


import vapoursynth as vs
# This above is mandatory in every file, it loads vapoursynth in python.

import havsfunc as haf
import finesharp
# These are optional imports, you can import it directly or make an alias like we did with vapoursynth

core = vs.get_core()
# This is mandatory too

def a_random_function(clip, cool_setting=0):
clip = core.do.something(clip, a_setting=cool_setting)
return clip
# This is how you define your functions, no need to create another core because it is already created outside of it.

clip = core.lsmas.LWLibavSource(r'/path/to/my/video.m2ts')
# In avisynth wen we don't define were the output of a plug-in goes, it automatically goes to a hidden variable "last", not in vapoursynth.
# Here we need to explicitly send it somewhere, "clip" in this example.

clip = haf.QTGMC(clip, Preset="Very Slow", Sharpness=1.2, SLMode=2, EZKeepGrain=1.2, NoiseProcess=2)
# No EdiThreads because vapoursynth manages all of this internally.

clip = finesharp.sharpen(clip)
clip = a_random_function(clip, 2)

clip.set_output()
# This is also needed, without it the script will not return a video

hydra3333
27th September 2015, 14:56
Thank you for your response, it's a good start for me.

hydra3333
28th September 2015, 05:19
Just a link-to for posterity

"Check if porting is proper" http://forum.doom9.org/showthread.php?t=172673