ConditionalFilter
(clip testclip, clip source1, clip source2,
string expression1, string operator, string expression2, bool "show")
ConditionalFilter
gibt source1 zurück,
wenn die Bedingung, die aus "expression1+operator+expression2"
geformt wird, für das aktuelle Frame erfüllt ist. Andernfalls wird source2 zurück gegeben. Wenn irgendeine Funktion in
expression1 oder expression2 nicht explizit auf einen bestimmten Clip angewendet wird, so wird sie auf einen testclip angewendet. Der Ton wird
source1entnommen.
Ein Beispiel. Es wählt Frames aus vid_blur wenn der durchschnittliche Helligkeitswert eines Frames unter 20 liegt. Andernfalls werden Frames aus vid zurück gegeben.
vid = AviSource("file")
vid_blur = vid.Blur(1.5)
ConditionalFilter(vid, vid_blur, vid, "AverageLuma()", "lessthan", "20")
Wenn man am Ende show="true" hinzufügt, wird der aktuelle Wert auch angezeigt.
Die Strings expression1 und expression2 können
beliebige numerische oder Boolsche Ausdrücke sein. Sie können auch
interne Funktionen oder User functions enthalten, und ebenso einige
zusätzliche bereits vordefinierte Funktionen (die Laufzeitfunktionen)
und die spezielle Laufzeitvariable current_frame (die Bildnummer des gerade abgefragten Frames).
Der String operator kann sein "equals", "greaterthan" oder "lessthan" beziehungsweise in Symbolform "=", ">" oder "<".
ScriptClip
(clip, string filter, bool "show", bool
"after_frame")
ScriptClip
gibt den Clip zurück, der durch das filter für jedes Frame (oft unterschiedlich) bearbeitet wurde. Der String filter
kann jeder Ausdruck sein, der einen Clip zurück gibt, einschließlich
interner Funktionen oder User clip Funktionen, und er kann auch
Zeilenumbrüche enthalten (das ermöglicht, dass eine ganze Kette von
Statements ausgewertet wird). Im filter Ausdruck können auch vordefinierte Funktionen (die Laufzeitfunktionen)
und die spezielle Laufzeitvariable current_frame
(die Bildnummer des gerade abgefragten Frames) verwendet werden. Wenn man show="true" hinzufügt, werden die aktuellen Werte auf dem Schirm angezeigt.
# Dies zeigt den Unterschied gegenüber dem vorherigen Frame im aktuellen Frame an:
clip = AviSource("c:\file.avi")
ScriptClip(clip, "Subtitle(String(YDifferenceFromPrevious))")
# Hier wird Blur auf jeden Frame angewendet entsprechend dem Unterschied zum vorherigen Frame.
# Außerdem zeigt es, wie Fehler angezeigt werden bei manchen Frames :)
clip = AviSource("c:\file.avi")
ScriptClip(clip, "Blur(YDifferenceFromPrevious/20.0)")
# Dies verwendet TemporalSoften in sehr ruhigen Szenen und einen variablen Blur in bewegten Szenen.
# Blur is now capped properly.
# Wir weisen auch eine Variable zu, weshalb es einen Zeilenumbruch gibt:
function fmin(float f1, float f2) {
return (f1<f2) ? f1 : f2
}
clip = AviSource("c:\file.avi")
T = clip.TemporalSoften(2, 7, 7, 3, 2)
ScriptClip(clip, "diff = YDifferenceToNext()"+chr(13)+"diff>2.5 ? Blur(fmin(diff/20, 1.5)) : T")
# Zeigt die aktuelle Bildnummer in einem Clip:
ScriptClip("subtitle(string(current_frame))")
# Zeigt "frame = " und die Bildnummer in einem Clip:
ScriptClip("""subtitle("frame = " + string(current_frame))""")
In Version v2.55 wurde eine Option after_frame=true/false hinzugefügt. Sie bestimmt, ob das Skript abgearbeitet wird, bevor (default) oder nachdem das Bild vom Filter davor geholt wurde.
Beschränkungen: Das Ergebnis des Skriptes MUSS exakt die gleichen
Eigenschaften (Farbraum, Breite und Höhe) haben wie der Clip, den ScriptClip
bekommen hat. Das Ergebnis kann eine andere Länge haben, aber
mindestens die des Quellclips. Der Ton von "Clip" wird unverändert
durchgeschleift. Bei zwei unterschiedlichen Quellen (z.B. Mpeg2Dec3 und
AviSource) kann es zu Problemen mit dem Farbräumen kommen - ein
beliebter Fehler.
FrameEvaluate
(clip clip, script filter, bool "after_frame")
Ähnlich wie ScriptClip
, außer dass das Ergebnis des Filters filter
ignoriert wird.
Dies kann dazu genutzt werden, um Variablen usw. zuzuweisen. Die Frames
werden direkt von dem mitgegebenen Script durchgeschleift.
In Version v2.53 wurde die Option after_frame=true/false
hinzugefügt. Sie bestimmt, ob das Skript abgearbeitet wird, bevor
(default) oder nachdem das Bild vom Filter davor geholt wurde.
Dieses Filter erlaubt, beliebige Informationen frameweise in eine wählbare Variable zu importieren.
Siehe ConditionalReader Seite.
Dies sind die internen Fuktionen, die in jedem Frame ausgewertet werden.
Diese Funktionen geben den durchschnittlichen Wert des Pixels einer Ebene (Kanal) zurück. (Erfordert YV12 und ISSE):
AverageLuma
(clip)
AverageChromaU
(clip)
AverageChromaV
(clip)
Diese Funktionen geben als Dezimalzahl zwischen 0 und 255 die
absolute Differenz zweier Ebenen (Kanäle) zurück. (Erfordert YV12,
ISSE):
RGBDifference
(clip1, clip2)
LumaDifference
(clip1, clip2)
ChromaUDifference
(clip1, clip2)
ChromaVDifference
(clip1, clip2)
Wenn man diese Funktionen verwendet, beziehen sich immer auf
einen impliziten "last" Clip (der erste Parameter muss nicht
spezifiziert werden), folglich wird der erste Parameter durch den
Testclip ersetzt.
Diese Funktionen sind ganz praktisch, wenn man Szenenwechsel erkennen will:
RGBDifferenceFromPrevious
(clip)
YDifferenceFromPrevious
(clip)
UDifferenceFromPrevious
(clip)
VDifferenceFromPrevious
(clip)
RGBDifferenceToNext
(clip)
YDifferenceToNext
(clip)
UDifferenceToNext
(clip)
VDifferenceToNext
(clip)
# Es wird der letzte Frame vor einem Szenenwechsel
# durch den ersten Frame nach dem Szenenwechsel ersetzt:
ConditionalFilter(last, last, last.trim(1,0), "YDifferenceToNext()", ">", "10", true)
YPlaneMax
(clip, float threshold)
UPlaneMax
(clip, float threshold)
VPlaneMax
(clip, float threshold)
YPlaneMin
(clip, float threshold)
UPlaneMin
(clip, float threshold)
VPlaneMin
(clip, float threshold)
YPlaneMedian
(clip)
UPlaneMedian
(clip)
VPlaneMedian
(clip)
YPlaneMinMaxDifference
(clip, float threshold)
UPlaneMinMaxDifference
(clip, float threshold)
VPlaneMinMaxDifference
(clip, float threshold)
Threshold ist das Verhältnis, wieviel Prozent an Pixeln über oder unter dem Minimum erlaubt sind. Der Schwellenwert ist optional und standardmäßig 0.
Wenn du den Stoff oben verstanden hast, kannst du mit "Erweiterter bedingte Filterung" fortfahren, wo wir ein wenig mehr über bedingte Filterung erläutern.
Du musst ein paar Dinge über die Funktionalität von AviSynth wissen, um diesen Abschnitt zu verstehen:
Scripts werden von oben nach unten durchlaufen, aber wenn ein Frame
angefragt wird, wird tatsächlich zuerst das letzte Filter zuerst
aufgerufen, welches seinerseits die Zulieferung des Frames in der
Filterkette von oben anfordert.
Zum Beispiel:
AviSource("meinedatei.avi")Wenn man das Skript in Vdub öffnet, passiert Folgendes
ColorYUV(analyze=true)
Histogram()
Folglich arbeitet die Filterkette im Prinzip rückwärts (der Ausgang
wird von unten "gezogen" statt von oben "gedrängt" zu werden). Das gibt
jedem Filter die Möglichkeit, mehrere Bilder von der Quelle oberhalb
abzufragen.
Bedingte Filter müssen jedoch Skripte auswerten, bevor sie Frames aus
dem Filter darüber verlangen, weil sie wissen müssen, welcher Filter
abzufragen ist. Ein weiterer wichtiger Punkt ist, dass nur globale
Variablen gleichzeitig innerhalb des bedingten Filters und außerhalb
eingesetzt werden können (und umgekehrt).
Werfe einen Blick auf das
folgende Skript
v = AviSource("E:\Temp\Test3\atomic_kitten.avi").ConvertToYV12Dieses Filter arbeitet wie folgt:
function g(clip c)
{
global w = c
c2 = ScriptClip(c, "subtitle(t)")
c3 = FrameEvaluate(c2, "t = String(text)")
c4 = FrameEvaluate(c3, "text = YDifferenceFromPrevious(w)")
return c4
}
g(v)
v = AviSource("E:\Temp\Test3\atomic_kitten.avi").ConvertToYV12Dies ist nur ein Beispiel für die Möglichkeiten. In dem Skript oben ist vieles redundant, und kann entfernt werden.
function g(clip c)
{
global w = c
c2 = ScriptClip(c, "subtitle(t)")
c3 = FrameEvaluate(c2, "me()")
c4 = FrameEvaluate(c3, "global text = YDifferenceFromPrevious(w)")
return c4
}
function me()
{
global t = String(text)
}
g(v)
v = AviSource("c:\clip.avi")
# ScriptClip akzeptiert mehrzeilige Skripte:
Scriptclip(v,"
text = YDifferenceFromPrevious()
t = string(text)
subtitle(t)
")
v = AviSource("c:\clip.avi")Im folgenden Abschnitt werden bildabhängige Informationen in eine Textdatei geschrieben.
ScriptClip(v, "Subtitle(String(YDifferenceFromPrevious))")
Im folgenden Beispiel werden bildabhängige Informationen in eine Textdatei geschrieben.
Die erste Variable "a" beschreibt, ob das Frame Kammeffekte
(interlacing) hat (oberhalb eines bestimmten Schwellwertes). Beachte,
IsCombed ist ein Filter aus dem Decomb
Plugin. Die zweite Variable "b" beschreibt, ob es in diesem Frame
"viel" Bewegung gibt.
global sep="."
global combedthreshold=25
function IsMoving()
{
global b = (diff < 1.0) ? false : true
}
function CombingInfo(clip c)
{
datei = "F:\interlace.log"
global clip = c
c = WriteFile(c, datei, "a", "sep", "b")
c = FrameEvaluate(c, "global a = IsCombed(clip, combedthreshold)")
c = FrameEvaluate(c, "IsMoving")
c = FrameEvaluate(c, "global diff = 0.50*YDifferenceFromPrevious(clip) + 0.25*UDifferenceFromPrevious(clip) + 0.25*VDifferenceFromPrevious(clip)")
return c
}
v = mpeg2source("F:\From_hell\from_hell.d2v").trim(100,124)
CombingInfo(v)
Wir können die zwei Funktionen etwas aufräumen und globale Variablen entfernen, indem wir es wie folgt schreiben:
function IsMoving(float diff)
{
return (diff >= 1.0)
}
function CombingInfo(clip c)
{
datei = "F:\interlace.log"
c = WriteFile(c, datei, "a", "sep", "b")
c = FrameEvaluate(c,"
diff = 0.50*YDifferenceFromPrevious() + 0.25*UDifferenceFromPrevious() + 0.25*VDifferenceFromPrevious()
b = IsMoving(diff)
a = IsCombed(combedthreshold)
")
return c
}
Im folgenden Abschnitt wird ein Beispiel betrachtet für ein "adaptives Bewegungs/Resizing Filter".
Einige adaptive Bewegungs/Resizing Filter sind im Forum beschrieben
worden. Solche Filter
unterscheiden zwischen geringer, mittlerer und starker Bewegung in
einem Clip (auf einer Bild für Bild Basis). Indem man das tut, können
verschiedene Filter für verschieden starke Bewegungen in dem Clip
angewendet werden. Allgemein würde man Temporal smoothing bei gering
bewegten Szenen anwenden, räumliches smoothing in stark bewegten Szenen
und spatio-temporal
smoothing bei mittlerer Bewegung.
Hier folgt eine vereinfachte Version des QUANTIFIED MOTION FILTER v1.5 b1 (10/07/2003)
von HomiE FR:
----------------------------------------------------Dieses Filter arbeitet so:
# QUANTIFIED MOTION FILTER v1.3
# LOADING AVISYNTH PLUGINS
LoadPlugin("C:\PROGRA~1\GORDIA~1\mpeg2dec3.dll")
LoadPlugin("C:\PROGRA~1\GORDIA~1\TemporalCleaner.dll")
LoadPlugin("C:\PROGRA~1\GORDIA~1\FluxSmooth.dll")
LoadPlugin("C:\PROGRA~1\GORDIA~1\UnFilter.dll")
# LOADING QUANTIFIED MOTION FILTER SCRIPT
Import("E:\temp\QMF\qmf.avs")
# FILTER FÜR GERINGE BEWEGUNG
# -> SHARP RESIZING + TEMPORAL ONLY
function Low_Motion_Filter(clip c)
{
c = TemporalCleaner(c, 5, 10)
c = LanczosResize(c, 512, 272)
return c
}
# FILTER FÜR MITTLERE BEWEGUNG
# -> NEUTRAL BICUBIC RESIZING + TEMPORAL & SPATIAL
function Medium_Motion_Filter(clip c)
{
c = FluxSmooth(c, 7, 7)
c = BicubicResize(c, 512, 272, 0.00, 0.50)
return c
}
# FILTER FÜR STARKE BEWEGUNG
# -> SOFT RESIZING + SPATIAL ONLY
function High_Motion_Filter(clip c)
{
c = FluxSmooth(c, -1, 14)
c = UnFilter(c, -30, -30)
c = BilinearResize(c, 512, 272)
return c
}
# VIDEOQUELLE ÖFFNEN
AviSource("E:\temp\QMF\britney-I_love_rock_'n_roll.avi")
ConvertToYV12(interlaced=true)
Telecide(0)
# ADAPTIVES RESIZING FILTER ANWENDEN (USING QMF)
QMF()
----------------------------------------------------
# QUANTIFIED MOTION FILTER (17/08/2003) by HomiE FR (homie.fr@wanadoo.fr)
# BEWEGUNGSABSCHÄTZUNGS FUNKTION
function ME()
{
# BEWEGUNGSLEVEL SETZEN NACH DER DURCHSCHNITTSDIFFERENZ [1]
global motion_level = (diff < threshold_lm) ? 0 : motion_level
global motion_level = (diff >= threshold_lm && diff <= threshold_hm) ? 1 : motion_level
global motion_level = (diff > threshold_hm) ? 2 : motion_level
}
# QUANTIFIED MOTION FILTER FUNKTION
function QMF(clip c, float "threshold_lm", float "threshold_hm", bool "debug")
{
# SCHWELLWERTE FÜR BEWEGUNGSLEVEL SETZEN [2]
threshold_lm = default(threshold_lm, 4.0)
threshold_hm = default(threshold_hm, 12.0)
global threshold_lm = threshold_lm
global threshold_hm = threshold_hm
# DEBUG INFORMATION ANSCHALTEN/ABSCHALTEN [3]
debug = default(debug, false)
# BEWEGUNGSLEVEL INITIALISIEREN
global motion_level = 0
# SETTING PRESENT CLIP [4]
global clip = c
# GETTING OUTPUT RESOLUTION [5]
width = Width(Low_Motion_Filter(c))
height = Height(Low_Motion_Filter(c))
global c_resized = PointResize(c, width, height)
# BEWEGUNGSFILTER ANWENDEN JE NACH BEWEGUNGSLEVEL [6]
c = ConditionalFilter(c, Low_Motion_Filter(c), c_resized, "motion_level", "=", "0") # [6a]
c = ConditionalFilter(c, Medium_Motion_Filter(c), c, "motion_level", "=", "1") # [6b]
c = ConditionalFilter(c, High_Motion_Filter(c), c, "motion_level", "=", "2") # [6c]
# DEBUG INFORMATION AUSGEBEN [7]
c = (debug == true) ? ScriptClip(c, "Debug()") : c
# BEWEGUNSLEVEL ERHALTEN DURCH BEWEGUNGSABSCHÄTZUNG [8]
c = FrameEvaluate(c, "ME()")
# UNTERSCHIEDE ZWISCHEN VERGANGENEN UND AKTUELLEN FRAMES ERHALTEN [9]
c = FrameEvaluate(c, "global diff = 0.50*YDifferenceFromPrevious(clip) + 0.25*UDifferenceFromPrevious(clip) + 0.25*VDifferenceFromPrevious(clip)")
return c
}
# DEBUG INFORMATION FUNKTION
function Debug(clip c)
{
# PRINTING VERSION INFORMATION [10]
c = Subtitle(c, "Quantified Motion Filter", x=20, y=30, font="lucida console", size=18, text_color=$FFFFFF)
c = Subtitle(c, "by HomiE FR (homie.fr@wanadoo.fr)", x=20, y=45, font="lucida console", size=14, text_color=$FFFFFF)
# PRINTING MOTION ESTIMATION INFORMATION [11]
c = Subtitle(c, "motion estimation", x=20, y=85, font="lucida console", size=18, text_color=$FFFFFF)
c = Subtitle(c, "diff = "+string(diff), x=20,y=110, font="lucida console", size=16, text_color=$FFCCCC)
# PRINTING QUANTIFIED MOTION FILTER INFORMATION [12]
c = Subtitle(c, "quantified motion filter", x=20, y=135, font="lucida console", size=18, text_color=$FFFFFF)
c = (motion_level == 0) ? Subtitle(c, "scene type = low motion", x=20, y=160, font="lucida console", size=16, text_color=$66FF66) : c
c = (motion_level == 1) ? Subtitle(c, "scene type = medium motion", x=20, y=160, font="lucida console", size=16, text_color=$66FF66) : c
c = (motion_level == 2) ? Subtitle(c, "scene type = high motion", x=20, y=160, font="lucida console", size=16, text_color=$66FF66) : c
return c
}
----------------------------------------------------
Ein paar Details wurden weggelassen, aber im Prinzip funktioniert das Skript auf diese Art.
$Date: 2008/12/21 09:23:02 $