## ConditionalFilter

`ConditionalFilter` (clip testclip, clip source1, clip source2, string filter, string operator, string value, bool ''show'')

`ConditionalFilter` restituisce il clip source1 quando si verifica la condizione costituita da ''filter+operator+value'' , in caso contrario restituisce source2. Se filter non è esplicitamente applicato ad un clip, esso sarà applicato a testclip. L' audio è preso da source1.

Un esempio. Scegliere frames da vid_blur quando il valore medio del luma di un frame è < 20. In caso contrario i frames saranno presi da vid . Aggiungendo alla fine "true" si evidenzieranno sullo schermo i valori effettivi:

    vid = AviSource("file")
    vid_blur = vid.Blur(1.5)
    ConditionalFilter(vid, vid_blur, vid, "AverageLuma()", "lessthan", "20")

La stringa filter può essere un qualsiasi filtro interno, ma anche alcuni filtri predefiniti (vedere sotto).
La stringa operator può essere "equals", "greaterthan" o "lessthan". O rispettivamente "=", ">" o"<" .

## ScriptClip

`ScriptClip` (clip, string function, bool ''show', bool "after_frame")

`ScriptClip` restituisce il clip elaborato dalla function applicata ad ogni frame.

Alcuni esempi :

    # Questo mostra le differenze tra il frame precedente ed il corrente:
    clip = AviSource("c:\file.avi")
    ScriptClip(clip, "Subtitle(String(YDifferenceFromPrevious))")

    # Questo applica ad ogni frame un blur  basato sulle differenze rispetto al precedente.
    # E in più mostra come vengono comunicati gli errori rilevati su alcuni frames :)
    clip = AviSource("c:\file.avi")
    ScriptClip(clip, "Blur(YDifferenceFromPrevious/20.0)")

    # Questo applica temporalsoften alle scene statiche ed un blur _variabile_ alle scene movimentate.
    # Blur è ora completato correttamente. In più viene assegnata una variabile - e questo giustifica il line break
    che è stato inserito:
    function fmin(float f1, float f2) {
      return (f1<f2) ? f1 : f2
    }
    clip = AviSource("c:\file.avi")
    ScriptClip(clip, "diff = YDifferenceToNext()"+chr(13)+"diff > 2.5 ? Blur(fmin(diff/20,1.5)) : TemporalSoften(2,7,7,3,2)")

    #Mostra il frame-number in un clip:
    ScriptClip("subtitle(string(current_frame))")

    #Mostra 'frame = frame-number' in un clip:
    ScriptClip("""subtitle("frame = " + string(current_frame))""")

Nella v2.55 è stata aggiunta un'opzione after_frame=true/false . Questa stabilisce se lo script debba essere elaborato prima (default) o dopo che il frame sia stato preso dai filtri precedenti.

"Limitazioni": l' output dello script DEVE essere esattamente simile al clip trasferito a `ScriptClip` (stesso colorspace, larghezza ed altezza). Il clip restituito può avere lunghezza diversa - ma quella che vuiene usata è sempre la lunghezza di "clip" . L'Audio di "clip" rimane inalterato. Usando sorgenti molto diverse (MPEG2DEC3 e AviSource) - è possibile incorrere in errori di colorspace . Questo è un problema conosciuto.

## FrameEvaluate

`FrameEvaluate` (clip clip, script function, bool "after_frame")

Simile a `ScriptClip`, eccetto che l'output del filter è ignorato. Questo è utile per assegnare variabili, etc. I frames sono passati direttamente partendo dal clip fornito.
Nella v2.53 è stata aggiunta un'opzione after_frame=true/false . Questa stabilisce se lo script debba essere elaborato prima (default) o dopo che il frame sia stato preso dai filtri precedenti.

## ConditionalReader

Questo filtro consente di importare qualsiasi informazione dentro una variabile selezionabile.

Vedere la pagina dedicata a ConditionalReader .

## Runtime Functions

Queste sono funzioni interne che sono calcolate ad ogni frame.

Queste restituiscono il valor medio dei pixel di un plane (richiedono YV12, ISSE):
`AverageLuma` (clip)
`AverageChromaU` (clip)
`AverageChromaV` (clip)

Queste restituiscono un valore float compreso tra 0 e 255 del valore assoluto delle differenze tra 2 planes (richiedono YV12, ISSE):
`RGBDifference` (clip1, clip2)
`LumaDifference` (clip1, clip2)
`ChromaUDifference` (clip1, clip2)
`ChromaVDifference` (clip1, clip2)

Usando queste funzioni viene definito un clip "implicit last" (il primo parametro può non essere specificato), sicchè il primo parametro è sostituito dal testclip.

Questo dovrebbe essere veramente funzionale per determinare i cambi di scena:
`RGBDifferenceFromPrevious` (clip)
`YDifferenceFromPrevious` (clip)
`UDifferenceFromPrevious` (clip)
`VDifferenceFromPrevious` (clip)
`RGBDifferenceToNext` (clip)
`YDifferenceToNext` (clip)
`UDifferenceToNext` (clip)
`VDifferenceToNext` (clip)

    # Questo sostituisce l'ultimo frame prima di un cambio di scena
    # col primo frame dopo il cambio di scena:
    ConditionalFilter(last, last, last.trim(1,0), "YDifferenceToNext()", ">", "10", true)

#### Altre funzioni interne:

`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 è una percentuale che stabilisce quanti pixels sono consentiti sopra o sotto il minimo. Questa soglia è opzionale e vale 0 di default.

Se avete capito quanto esposto sopra, potete procedere con "advanced conditional filtering", che vi svelerà qualcosa in più sul conditional filtering.

## Advanced conditional filtering: part I

Per capire questa sezione è necessario conoscere alcune cose sulle funzionalità di AviSynth :
Gli scripts sono esaminati dall'alto al basso, ma quando viene richiesto un frame, viene chiamato per primo l'ultimo filtro ed il frame procede all'insù nella catena dei filtri . Ad esempio:

    AviSource("myfile.avi")
    ColorYUV(analyze=true)
    Histogram()

Aprendo lo script in Vdub ecco quello che succede

- Quando Vdub richiede un frame, AviSynth richiede il frame ad Histogram.
- Histogram richiede un frame a ColorYUV,
- ColorYUV ad AviSource, che produce il frame e lo consegna a ColorYUV.
- ColorYUV elabora l'immagine e la manda ad Histogram, che la restituisce a Vdub.

In questo modo la catena di filtri lavora all'indietro cosa che consente ai filtri di richiedere alla sorgente più di un frame contemporaneamente.

I Conditional filters tuttavia, hanno bisogno di elaborare gli scripts prima di richiedere frames ai filtri che stanno prima, perchè necessitano conoscere quale filtro chiamare. Altro importante problema è che solo le variabili definite `global` nel conditional filter 'environment' possono essere usate all'esterno (e vice versa). Date un'occhiata al seguente script

    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)

Questa catena di filtri lavora in questo modo:

- Quando Vdub richiede un frame, AviSynth lo richiede a g().
- g() richiede un frame ad AviSource():

- AviSynth richiede un frame al secondo FrameEvaluate.
- Questo secondo FrameEvaluate calcola YDifferenceFromPrevious(w) ed assegna questo valore alla variabile text, dopo aver richiesto un frame di AviSource. Dopo di ciò viene richiesto un frame al primo FrameEvaluate.
- Questo FrameEvaluate richiede un frame a ScriptClip dopo 'aver calcolato String(text) ed assignato questo valore alla variabile t'.
- ScriptClip richiede un frame a ConvertToYV12() e calcola Subtitle(t) di quel frame.
- ConvertToYV12() richiede un frame ad AviSource().

- AviSource() produce il frame e lo manda a g(), che lo restituisce a Vdub.

Come si può vedere , w è definita come "variabile globale". In questo modo la si può usare successivamente nello script nel conditional environment. Se si volessero usare le variabili t e text in una diversa function (dentro o fuori il conditional environment),anch'esse devono essere definite come global variables. Allora ad esempio:

    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)

Buona parte dello script precedente è ridondante e può essere eliminato. Lo script seguente produce lo stesso output

    v = AviSource("c:\clip.avi")
    ScriptClip(v, "Subtitle(String(YDifferenceFromPrevious))")

In the following section some frame dependent info will be written to a text-file.

## Advanced conditional filtering: part II

Nel seguente esempio alcune informazioni che dipendono dal frame saranno scritte in un text-file. La prima variabile "a" indica se il frame è combed (per una certa soglia "threshold"). Notare che IsCombed è un filtro del plugin Decomb . La seconda variabile "b" indica se nel frame c'è "molto" movimento.

    global sep="."
    global combedthreshold=25

    function IsMoving()
    {
    global b = (diff < 1.0) ? false : true
    }

    function CombingInfo(clip c)
    {
    file = "F:\interlace.log"
    global clip = c
    c = WriteFile(c, file, "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)

Nella sezione seguente considereremo un esempio di "adaptive motion/resizing filter".

## Advanced conditional filtering: part III

Eccovi alcuni filtri "adaptive motion/resizing" apparsi nei forums. Questi filtri discriminano tra low, medium ed high motion presente in un clip (sulla base dei frames). Per fare ciò, si possono usare filtri diversi per diversi tipi di movimento presenti nel clip. In generale, si dovrebbe usare temporal smoothing nelle scene a basso movimento, spatial smoothing nelle scene ad alto movimento e spatio-temporal smoothing nelle scena a movimento medio.
Di seguito, una versione semplificata del QUANTIFIED MOTION FILTER v1.5 b1 (10/07/2003) di 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")

    # LOW MOTION FILTER FUNCTION
    # -> SHARP RESIZING + TEMPORAL ONLY
    function Low_Motion_Filter(clip c)
    {
      c = TemporalCleaner(c, 5, 10)
      c = LanczosResize(c, 512, 272)
      return c
    }

    # MEDIUM MOTION FILTER FUNCTION
    # -> 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
    }

    # HIGH MOTION FILTER FUNCTION
    # -> 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
    }

    # OPENING VIDEO SOURCE
    AviSource("E:\temp\QMF\britney-I_love_rock_'n_roll.avi")
    ConvertToYV12(interlaced=true)
    Telecide(0)

    # APPLYING ADAPTATIVE RESIZING FILTER (USING QMF)
    QMF()
    ----------------------------------------------------

    # QUANTIFIED MOTION FILTER (17/08/2003) by HomiE FR (homie.fr@wanadoo.fr)
    # MOTION ESTIMATION FUNCTION
    function ME()
    {
      # SETTING MOTION LEVEL ACCORDING TO AVERAGE DIFFERENCE [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 FUNCTION
    function QMF(clip c, float "threshold_lm", float "threshold_hm", bool "debug")
    {
      # SETTING MOTION LEVELS THRESHOLDS [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

      # ENABLING/DISABLING DEBUG INFORMATION [3]
      debug = default(debug, false)

      # INITIALIZING MOTION LEVEL
      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)

      # APPLYING MOTION FILTER ACCORDING TO MOTION LEVEL [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]

      # PRINTING DEBUG INFORMATION [7]
      c = (debug == true) ? ScriptClip(c, "Debug()") : c

      # GETTING MOTION LEVEL THROUGH MOTION ESTIMATION [8]
      c = FrameEvaluate(c, "ME()")

      # GETTING DIFFERENCES BETWEEN PAST/PRESENT FRAMES [9]
      c = FrameEvaluate(c, "global diff = 0.50*YDifferenceFromPrevious(clip) + 0.25*UDifferenceFromPrevious(clip) + 0.25*VDifferenceFromPrevious(clip)")
      return c
    }

    # DEBUG INFORMATION FUNCTION
    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
    }
    ----------------------------------------------------

La catena di filtri lavora così:

- Quando Vdub richiede un frame, AviSynth lo richiede a QMF.

- QMF richiede un frame a FrameEvaluate [9].
- Fatto ciò viene elaborato lo script [9] , e la global variable diff è assegnata dopo aver richiesto un frame ad AviSource. FrameEvaluate [9] richiede un frame a FrameEvaluate [8].
- Ancor una volta viene calcolato lo script [8]:

- mentre si calcola me(), la global variable motion_level è assegnata al frame [1]

- Se debug=true, un frame è richiesto a ScriptClip [7], e in questo modo a Debug().
- Dopo di ciò (e anche quando debug è impostato a false) un frame è richiesto all'ultimo ConditionalFilter [6c], che richiede un frame a [6b], che a sua volta richiede un frame a [6a].

- Si noti che alla fine viene richiesto un frame a High_Motion_filter, Medium_Motion_filter, o Low_Motion_filter in funzione del valore di motion_level.

- QMF richiede un frame a Telecide, Telecide a ConvertToYV12 ed infine ConvertToYV12 ad AviSource.
- AviSource produce il frame e lo manda a ConvertToYV12, etc.

Alcuni dettagli sono stati omessi, ma lo script in definitiva lavora in questo modo.

`$Date: 2004/09/26 19:49:40 $`