## ConditionalFilter

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

`ConditionalFilter` renvoie source1 quand la condition formée par ''filter+operator+value'' (filtre+opérateur+valeur) est remplie. Sinon, il renvoie source2. Si filter n'est pas explicitement appliqué à un clip, il sera appliqué sur testclip. Le flux audio est pris dans source1.

Voici un exemple. Il choisit une image de la vidéo vid_blur quand la valeur moyenne de la luminance de cette image est inférieure à 20. Sinon, une image de vid est renvoyée.

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

En ajoutant show="true" (vrai), cela affiche les valeurs calculées sur l'image.

La chaîne filter peut être n'importe quel filtre interne, mais également certains filtres prédéfinis (les fonctions d'exécution).
La chaîne operator peut être "equals" (égal à), "greaterthan" (supérieur à) ou "lessthan" (inférieur à). Ou bien "=", ">" or "<" respectivement.

## ScriptClip

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

`ScriptClip` renvoie le clip renvoyé par function évalué pour chaque image. La chaîne filter peut être n'importe quel filtre interne mais également certains filtres prédéfinis (les fonctions d'exécution). En ajoutant show="true" (vrai), cela affiche les valeurs calculées sur l'image.

Quelques exemples:

    # Cela affiche la différence de luminance avec l'image précédente sur l'image actuelle:
    clip = AviSource("c:\file.avi")
    ScriptClip(clip, "Subtitle(String(YDifferenceFromPrevious))")

    # Cela applique un flou (blur) dont la force est basée sur la différence de luminance avec l'image précédente.
    # Cela montre également comment les erreurs sont renvoyées sur certaines images :)
    clip = AviSource("c:\file.avi")
    ScriptClip(clip, "Blur(YDifferenceFromPrevious/20.0)")

    # Cela applique le filtre temporalsoften sur les scènes très statiques, et applique un flou variable sur les scènes avec du mouvement.
    # Le filtre blur (flou) est maintenant écrit de manière correcte. Nous assignons également une variable
    # et c'est la raison pour laquelle nous avons un retour à la ligne:
    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)")

    # Affiche le numéro de l'image d'un clip:
    ScriptClip("subtitle(string(current_frame))")

    # Affiche 'frame = le numéro d'image' sur un clip:
    ScriptClip("""subtitle("frame = " + string(current_frame))""")

Dans v2.55 une option after_frame=true/false (vrai/faux) a été ajoutée. Elle indique si le script doit être évalué avant (par défaut) ou après que les filtres soient appliqués à l'image.

"Restrictions": la sortie du script DOIT être exactement similaire au clip fourni à `ScriptClip` (même espace de couleurs, largeur et hauteur). Le clip renvoyé peut avoir une longueur différente - mais la longueur de "clip" est toujours utilisée. L'audio de "clip" est transmis sans modifications. Pour deux sources assez différentes (MPEG2DEC3 et AviSource par exemple) - vous pouvez rencontrer des erreurs de correspondance d'espace de couleur. C'est un caprice connu.

## FrameEvaluate

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

Similaire à `ScriptClip`, sauf que la sortie du filtre est ignorée. Cela peut être utile pour assigner des variables, etc... Les images sont directement transmises à partir du clip source.
Dans v2.53 l'option after_frame=`true/false` (vrai/faux) a été ajoutée. Cela indique si le script doit être évalué avant (par défaut) ou après que les filtres soient appliqués à l'image.

## ConditionalReader

Cela permet d'importer une information dans une variable donnée.

Voir la page dédiée à ConditionalReader.

## Fonctions d'exécution

Voici les fonctions internes qui sont évaluées pour chaque image.

Cela renvoie la valeur moyenne de la valeur des pixels suivant un canal donné (nécessite YV12, ISSE):
`AverageLuma` (clip)
`AverageChromaU` (clip)
`AverageChromaV` (clip)

Cela renvoie un flottant compris entre 0 et 255 qui correspond à la valeur absolue de la différence entre deux canaux (nécessite YV12, ISSE):
`RGBDifference` (clip1, clip2)
`LumaDifference` (clip1, clip2)
`ChromaUDifference` (clip1, clip2)
`ChromaVDifference` (clip1, clip2)

Quand vous utilisez ces fonctions, il y a implicitement un clip défini comme le premier argument de la fonction (le premier argument n'a pas besoin d'être spécifié).

Les fonctions suivantes peuvent être bien utiles pour détecter des changements de scènes:
`RGBDifferenceFromPrevious` (clip)
`YDifferenceFromPrevious` (clip)
`UDifferenceFromPrevious` (clip)
`VDifferenceFromPrevious` (clip)
`RGBDifferenceToNext` (clip)
`YDifferenceToNext` (clip)
`UDifferenceToNext` (clip)
`VDifferenceToNext` (clip)

    # Cela remplace la dernière image avant un changement de scène
    # par la première image après le changement de scène:
    ConditionalFilter(last, last, last.trim(1,0), "YDifferenceToNext()", ">", "10", true)

#### Autres fonctions internes:

`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 est un pourcentage. Il représente le pourcentage de pixels permis en dessous du minimum. Le threshold est optionnel et par défaut à 0.

Si vous avez bien compris ce qui précède, vous pouvez continuer avec la partie "filtrage conditionnel avancé", qui vous en dira plus au sujet du filtrage conditionnel.

## Filtrage conditionnel avancé: partie I

Vous devez en savoir un peu plus sur le fonctionnement d'AviSynth pour bien comprendre cette partie:
Les scripts sont analysés du haut vers le bas, mais quand une image est demandée, le dernier filtre est invoqué en premier, en demandant des images précédente dans la chaîne de filtres. Par exemple:

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

Quand vous ouvrez ce script dans VirtualDub, voici ce qui se passe:

- Quand VirtualDub demande une image, Avisynth demande cette image au filtre Histogram.
- Histogram demande cette image à ColorYUV,
- ColorYUV demande l'image à AviSource, qui crée l'image, et la renvoie à ColorYUV.
- ColorYUV travail sur l'image et la renvoie à Histogram, qui la renvoie ensuite à VirtualDub.

La chaîne des filtres travaille donc vers l'arrière, cela donne la possibilité de demander plusieurs images de la source précédente.

Cependant, Conditional filters doit évaluer les scripts avant qu'ils ne demandent des images au filtre précédent, parce qu'ils ont besoin de savoir quel filtre invoquer. Une conséquence importante de ceci est que seules des variables `globales` dans l'environnement conditional filter peuvent être utilisées en dehors (et vice versa). Jetez un oeil au script suivant:

    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)

Cette chaîne de filtres fonctionne de la façon suivante:

- Quand VirtualDub demande une image, AviSynth demande une image à g().
- g() demande une image à AviSource():

- AviSynth demande une image au deuxième FrameEvaluate.
- Le deuxième FrameEvaluate évalue YDifferenceFromPrevious(w) et renvoie son résultat à la variable text, après avoir demandé une image d'AviSource. Après cela, une image est demandée au premier FrameEvaluate.
- Le premier FrameEvaluate demande une image à ScriptClip après avoir évalué String(text) et envoyé le résultat à la variable t.
- ScriptClip demande une image à ConvertToYV12(), en évaluant Subtitle(t) sur cette image.
- ConvertToYV12() demande une image à AviSource().

- AviSource() crée l'image et l'envoie à g(), qui renvoie le résultat à VirtualDub.

Comme on peut le voir, w est définie comme une variable globale. De cette manière, nous pourrons l'utiliser plus tard dans le script dans l'environnement conditionnel. Si nous souhaitons utiliser les variables t et text dans une fonction différente (à l'intérieur ou à l'extérieur de l'environnement conditionnel), elles doivent également être définies comme variables globales. Voici un exemple:

    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)

Une grande partie du script précédent est redondante et peut être supprimée. Le script suivant est équivalent.

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

Dans la partie suivante, des informations dépendants des images vont être écrites dans un fichier texte.

## Filtrage conditionnel avancé: partie II

Dans l'exemple suivant, des informations dépendants des images vont être écrites dans un fichier texte. La première variable "a" indique si l'image subit un effet de peigne (lié à l'entrelacement ou au processus Telecine). Notez que le filtre IsCombed fait partie du plugin Decomb. La seconde variable "b" indique s'il y a beaucoup de mouvement dans l'image.

    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)

Dans la partie suivante, nous allons étudier un filtre de redimenssionement adaptatif en fonction du mouvement.

## Filtrage conditionnel avancé: partie III

On a vu apparaître sur les forums quelques filtres de redimenssionement adaptatifs en fonction du mouvement. Ces filtres font une différence entre les mouvements lents, moyens et rapides (à l'échelle de l'image). En faisant cela, des filtres différents peuvent être utilisés pour chaque type de mouvement dans le clip. En général, on utilise un lissage temporel dans les scènes lentes, un lissage spatial dans les scènes rapides et un lissage spatio/temporel dans les scènes intermédiaires.
Ci dessous , une version simplifiée de QUANTIFIED MOTION FILTER v1.5 b1 (10/07/2003) de HomiE FR:

    ----------------------------------------------------
    # QUANTIFIED MOTION FILTER v1.3
    # CHARGEMENT DES PLUGINS AVISYNTH
    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")

    # CHARGEMENT DU SCRIPT QUANTIFIED MOTION FILTER

    Import("E:\temp\QMF\qmf.avs")

    # LOW MOTION FILTER FUNCTION (FONCTION POUR FILTRE DE MOUVEMENT FAIBLE)
    # -> REDIMENSSIONEMENT PRECIS + FILTRAGE TEMPOREL SEULEMENT
    function Low_Motion_Filter(clip c)
    {
      c = TemporalCleaner(c, 5, 10)
      c = LanczosResize(c, 512, 272)
      return c
    }

    # MEDIUM MOTION FILTER FUNCTION (FONCTION POUR FILTRE DE MOUVEMENT INTERMEDIAIRE)
    # -> REDIMENSSIONEMENT DE TYPE 'NEUTRAL BICUBIC' + FILTRAGE TEMPOREL & 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 (FONCTION POUR FILTRE DE MOUVEMENT RAPIDE)
    # -> REDIMENSSIONEMENT DOUX + FILTRAGE SPATIAL SEULEMENT
    function High_Motion_Filter(clip c)
    {
      c = FluxSmooth(c, -1, 14)
      c = UnFilter(c, -30, -30)
      c = BilinearResize(c, 512, 272)
      return c
    }

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

    # UTILISATION DU FILTRE ADAPTATIF DE REDIMENSSIONEMENT (UTILISATION DE QMF)
    QMF()
    ----------------------------------------------------

    # QUANTIFIED MOTION FILTER (17/08/2003) by HomiE FR (homie.fr@wanadoo.fr)
    # FONCTION D'ESTIMATION DE MOUVEMENT
    function ME()
    {
      # PARAMETRAGE DES NIVEAUX DE MOUVEMENT EN FONCTION DE LA DIFFERENCE MOYENNE [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
    }

    # FONCTION QUANTIFIED MOTION FILTER (FILTRE DE MOUVEMENT QUANTIFIE)
    function QMF(clip c, float "threshold_lm", float "threshold_hm", bool "debug")
    {
      # PARAMETRAGE DES LIMITES DES NIVEAUX DE MOUVEMENT [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

      # ACTIVATION/DESACTIVATION DES INFORMATIONS DE DEBUGAGE [3]
      debug = default(debug, false)

      # INITIALISATION DU NIVEAU DE MOUVEMENT
      global motion_level = 0

      # PARAMETRAGE DU CLIP ACTUEL [4]
      global clip = c

      # OBTENTION DE LA RESOLUTION DE SORTIE [5]
      width = Width(Low_Motion_Filter(c))
      height = Height(Low_Motion_Filter(c))
      global c_resized = PointResize(c, width, height)

      # UTILISATION DU FILTRE DE MOUVEMENT EN FONCTION DU NIVEAU DE MOUVEMENT [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]

      # AFFICHAGE DES INFORMATIONS DE DEBUG [7]
      c = (debug == true) ? ScriptClip(c, "Debug()") : c

      # OBTENTION DU NIVEAU DE MOUVEMENT A TRAVERS L'ESTIMATION DE MOUVEMENT [8]
      c = FrameEvaluate(c, "ME()")

      # OBTENTION DE LA DIFFERENCE ENTRE LES IMAGES PRECEDENTES/ACTUELLES [9]
      c = FrameEvaluate(c, "global diff = 0.50*YDifferenceFromPrevious(clip) + 0.25*UDifferenceFromPrevious(clip) + 0.25*VDifferenceFromPrevious(clip)")
      return c
    }

    # FONCTION D'INFORMATION DE DEBUGAGE
    function Debug(clip c)
    {
      # AFFICHAGE DE L'INFORMATION DE VERISON [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)

      # AFFICHAGE DE L'INFORMATION D'ESTIMATION DE MOUVEMENT[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)

      # AFFICHAGE DE L'INFORMATION DU FILTRE DE MOUVEMENT QUANTIFIE [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
    }
    ----------------------------------------------------

Cette chaîne de filtre fonctionne de la manière suivante:

- Quand VirtualDub demande une image, AviSynth demande une image à QMF.

- QMF demande une image à FrameEvaluate [9].
- Après cela le script [9] est évalué, et la variable globale diffest enregistrée après avoir demandé une image à AviSource. FrameEvaluate [9] demande une image à FrameEvaluate [8].
- Une nouvelle fois, le script [8] est évalué:

- en évaluant me(), la variable globale motion_level est enregistrée pour cette image [1]

- Si debug=true (vrai), une image est demandée à ScriptClip [7], et donc à Debug().
- Après cela (également quand debug est assigné à la valeur false (faux)), une image est demandée au dernier ConditionalFilter [6c], qui demande une image à [6b], qui lui même demande une image à [6a].

- Notez qu'à la fin, une image de High_Motion_filter, de Medium_Motion_filter, ou de Low_Motion_filter est demandée en fonction de la valeur de motion_level.

- QMF demande une image à Telecide, Telecide en demande une à ConvertToYV12 et à la fin, ConvertToYV12 en demande une à AviSource.
- AviSource crée l'image et l'envoie à ConvertToYV12, etc...

Certains détails ont été supprimés mais c'est globalement la manière dont ce filtre fonctionne.

`$English date: 2005/01/26 22:08:35 $
French translation date: 2005/11/01 JasonFly macpaille@users.sourceforge.net`