ConditionalFilter

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

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.

Einige Beispiele:
# 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

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.

ConditionalReader

Dieses Filter erlaubt, beliebige Informationen frameweise in eine wählbare Variable zu importieren.

Siehe ConditionalReader Seite.

Runtime Functions (Laufzeitfunktionen)

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)

Andere interne Funktionen:

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.

Erweiterte bedingte Filterung: Teil I

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")
ColorYUV(analyze=true)
Histogram()
Wenn man das Skript in Vdub öffnet, passiert Folgendes

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").ConvertToYV12

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)
Dieses Filter arbeitet wie folgt: Wie man sehen kann, ist w als globale Variable definiert. Auf diese Art können wir es später im Skript in der bedingten Abfrageumgebung verwenden. Wenn wir die Variablen t und text in einer anderen Fuktion nutzen wollen (innerhalb oder außerhalb der bedingten Abfrage), müssen sie ebenfalls als globale Variablen definiert werden.

Folglich zum Beispiel:
v = AviSource("E:\Temp\Test3\atomic_kitten.avi").ConvertToYV12

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)
Dies ist nur ein Beispiel für die Möglichkeiten. In dem Skript oben ist vieles redundant, und kann entfernt werden.
Die folgenden zwei Skripte ergeben den selben Output
v = AviSource("c:\clip.avi")
# ScriptClip akzeptiert mehrzeilige Skripte:
Scriptclip(v,"
text = YDifferenceFromPrevious()
t = string(text)
subtitle(t)
")
v = AviSource("c:\clip.avi")
ScriptClip(v, "Subtitle(String(YDifferenceFromPrevious))")
Im folgenden Abschnitt werden bildabhängige Informationen in eine Textdatei geschrieben.

Erweiterte bedingte Filterung: Teil II

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".

Erweiterte bedingte Filterung: Teil III

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:

---------------------------------------------------- 
# 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
}
----------------------------------------------------
Dieses Filter arbeitet so:

Ein paar Details wurden weggelassen, aber im Prinzip funktioniert das Skript auf diese Art.

$Date: 2008/12/21 09:23:02 $