Recensubs HQ

La vera guida a come cavolo si encoda per davvero - Episodio 6: Ultime nozioni introduttive di AVS

« Older   Newer »
  Share  
view post Posted on 19/1/2015, 16:04     +1   -1
Avatar

Bimbosp

Group:
Administrator
Posts:
9,780
Reputation:
+929
Location:
Gallarate (VA)

Status:


Salve gente! È da ottobre che non ci si vede.
Come dicevo, prima di proseguire, dovevo finire Love Lab, per cui c'è voluto un po'. Ma ormai è ora.

Dunque, facendo mente locale su cos'ho spiegato di AVS, mi pare di avervi detto come creare uno script, usare le funzioni, caricare sorgenti, usare trim e blankclip, spiegato l'overloading, introdotto tipi e variabili locali, dimostrato l'utilizzo dell'operatore ternario e creato funzioni custom.

Ciò significa che a questo giro rimane da parlare delle variabili globali, delle funzioni ricorsive (e di conseguenza dei cicli for/dei loop) e di ConditionalFilter e soci. Dopodiché direi che potremo passare finalmente ai primi passi di ivtc, ma quello sarà per un'altra volta.

Ok, un passo alla volta, cominciamo con le variabili globali.


Capitolo 1: Le variabili globali

La volta scorsa vi avevo mostrato che per assegnare un valore a una variabile, basta usare il simbolo =, per cui per assegnare il valore 2 alla variabile Due, basta fare

CODICE
Due = 2


Ma una variabile dichiarata in questo modo è disponibile solo all'interno della funzione/script attuale (se in un .avs/.avsi create più funzioni, la variabile è disponibile solo all'interno della singola funzione in cui è dichiarata), cosa che potrebbe non essere ottimale.
Per poter dichiarare una variabile globale, si utilizza la keyword global, in questo modo:

CODICE
global Due = 2


Facendo così, all'interno dello script, qualsiasi funzione chiamata avrà a disposizione quella variabile. Ciò comporta due cose:
1) È possibile creare funzioni che oltre al risultato della funzione restituiscano altri valori tramite variabili globali;
2) È importante specificare variabili globali con nomi certamente univoci per evitare incasinamenti dovuti a variabili con lo stesso nome in script diversi.

Il punto 2 è di vitale importanza ed è una buona regola in generale per la programmazione, ma in base al linguaggio può essere più comodo semplicemente scrivere su un file quello che serve anziché usare una variabile globale... ma scrivere e leggere file con avisynth è più un casino che non altro, per cui conviene evitare se non strettamente necessario.

Parlando di casi reali in cui capita di usare global, il primo esempio che mi viene in mente è l'utilizzo dei preset in YATTA. Ogni preset è in realtà una funzione a sé stante, che viene chiamata opportunamente quando serve, ma capita che all'interno di una funzione vi serva salvare un clip o una qualche variabile da riutilizzare più avanti nello script, in un altro preset o che. Capita realtivamente spesso per il delogo, in cui torna utile salvare il clip senza delogo per poter utilizzare poi logonr (che fa un confronto fra clip con e senza logo). Per ora fatevi bastare questo, entreremo nello specifico dei preset in una guida futura (per il delogo invece fate riferimento alla guida di Maddo, se volete).

Ad ogni modo, una volta dichiarata come globale, la variabile si usa come quelle locali, ovvero semplicemente come Due, quindi se volete fare un blankclip che duri quel tot di frame, basta fare

CODICE
Blankclip(length=Due)


Tutto qui. Molto semplice, infatti non c'è altro da sapere sulle variabili globali. Passiamo oltre.


Capitolo 2: Le funzioni ricorsive e i loop

Copincollando dalla pagina di Wikipedia, un algoritmo ricorsivo è "un algoritmo espresso in termini di se stesso, ovvero in cui l'esecuzione dell'algoritmo su un insieme di dati comporta la semplificazione o suddivisione dell'insieme di dati e l'applicazione dello stesso algoritmo agli insiemi di dati semplificati". Che in parole povere significa che all'interno della funzione andremo a chiamare la funzione stessa.

Di base il codice che effettua una ricorsione è come segue:

CODICE
function FunzioneRicorsiva() {
FunzioneRicorsiva()
}


Che in pratica, quando chiamerete FunzioneRicorsiva(), continuerà a chiamare sé stessa per l'eternità, o fino a quando voi non terminerete forzatamente l'esecuzione dello script.
Già.
La prima regola delle funzioni ricorsive è di fare attenzione a non creare un ciclo infinito, infatti. A questo scopo torna utile impiegare parametri e controlli con l'operatore ternario in modo tale da capire quando uscire. Ovviamente è anche molto importante assicurarsi che i parametri passati in input siano corretti, per evitare situazioni spiacevoli.

Facciamo un esempio semplice.

Vogliamo creare una funzione che applichi X volte un filtro passato come parametro.

Data la premessa, sappiamo che, oltre al clip in input, diventa necessario avere un parametro per capire quanti giri fare e un parametro per il filtro da usare.
Tuttavia, visto che il filtro va applicato più volte, non possiamo semplicemente passare un clip col filtro già applicato, ma bisogna passare il filtro stesso. Per fare questo ci torna utile impiegare Eval e passare il filtro come blocco di testo.
Partiamo subito col codice e analizziamo:

CODICE
function FiltroRicorsivo( clip c, int i, string "s") {
Assert(i > 0, "È necessario specificare un valore maggiore di 0")
Eval("c."+s)
i = i - 1
i == 0 ? last : FiltroRicorsivo(last, i, s)
}


Anzitutto la variabile i è quella che utilizziamo per controllare le iterazioni. Inizialmente il valore è dato dall'utente, e a ogni giro decrementiamo di uno la variabile: ciò significa che quando raggiunge lo zero avremo fatto il numero di giri specificati dall'utente all'inizio. Sfruttando il . ed eval, possiamo concatenare la stringa che contiene il filtro da usare al nostro clip, e quindi una volta applicato il filtro sappiamo che quel che doveva fare questo ciclo è stato fatto, per cui possiamo decrementare la variabile. Con il controllo decidiamo come procedere: se ha già raggiunto lo zero possiamo uscire dal ciclo restituendo il clip definitivo, se ancora non abbiamo finito richiamiamo il filtro stesso, passando le nuove variabili modificate.
Nota finale, ma non per importanza: l'assert serve per assicurarci che l'utente non abbia specificato un valore di i che ci porterebbe ad avere un ciclo infinito; specificando un valore pari o inferiore a 0, e continuando a decrementarlo, non arriveremo mai a 0 per cui non usciremmo mai.

Con un esempio pratico...

CODICE
Blankclip()


È un clip nero.

CODICE
Blankclip()
FiltroRicorsivo(1,"invert()")


Il clip nero entra nel ciclo, tramite eval viene applicato invert e diventa bianco. L'i viene decrementato da 1 a 0, l'operatore ternario controlla che i sia uguale a 0, che risulta vero, per cui come comando si ritrova last, che attualmente è un clip bianco. Usciamo dal ciclo e ci viene fornito un clip bianco.

CODICE
Blankclip()
FiltroRicorsivo(2,"invert()")


Il clip nero entra nel ciclo, tramite eval viene applicato invert e diventa bianco. L'i viene decrementato da 2 a 1, l'operatore ternario controlla che i sia uguale a 0, ma risulta falso, per cui come comando si ritrova FiltroRicorsivo(last, i,"invert()"). Attualmente last è un clip bianco e i è 1. Entriamo nuovamente in Filtro ricorsivo con questi nuovi valori. Siccome i è valido, viene applicato Eval, che porta il clip da bianco a nero, poi i viene decrementato da 1 a 0. L'operatore ternario verifica la condizione, che risulta essere vera, per cui si limita a prosegure con un last. Il ciclo è concluso e noi abbiamo un clip nero.

In questo caso è come aver usato un ciclo for, ma ovviamente la condizione può essere qualsiasi cosa, per cui sta a voi decidere come può tornarvi utile e farne un uso ragionato e sensato. Del resto dovete tenere presente che la ricorsione non è particolarmente ottimizzata in avisynth, per cui ne risulta che gli script che ne fanno uso vengono rallentati anche di parecchio: è bene pensare a soluzioni alternative per quanto possibile e farne uso solo quando necessario, ma se vi serve davvero può comunque essere molto utile.

Ok, con questo rimane un'ultima cosa e poi direi che per oggi può bastare.


Capitolo 3: ConditionalFilter, ConditionalSelect, ScriptClip, FrameEvaluate e ConditionalReader.

Considerando che stiamo parlando di 5 funzioni, uno si aspetta che questa sezione non finisca più.
In realtà, tutti questi filtri sono basati sullo stesso assunto, ovvero che può servire filtrare un video diversamente per ogni frame. Per questo, i vari filtri fanno cose diverse, ma che servono tutti ad agire sui singoli frame.

La pagina della wiki di avisynth è abbastanza chiara sull'utilizzo dei filtri, ma vorrei comunque spiegare in breve cosa serve a cosa e faree un esempio di utilizzo, che dovrebbe bastare a farvi capire come potreste sfruttarli.

ConditionalFilter verifica una condizione che può essere vera o falsa e decide quale clip prendere per il determinato frame in base a questa condizione.

ConditionalSelect verifica una condizione che restituisce un valore intero e decide quale video prendere in base al valore corrispondente. I valori partono da 0, quindi il primo clip di risultato verrà preso se la condizione restituisce 0 come valore, il secondo clip se restituisce 1 e così via. Sta a voi scrivere la condizione adeguatamente, ma torna utile quando si hanno più di due clip tra cui scegliere, per evitare di concatenare una sfilza di ConditionalFilter.

ScriptClip vi consente di effettuare un filtraggio mettendovi a disposizione delle parole chiave che all'interno di scriptclip si tramutano in valori diversi per ogni frame. In particolare, avete a disposizione le funzioni di runtime più una variabile denominata current_frame, che viene appunto convertita nel valore del frame che sta attualmente valutando.

FrameEvaluate è fondamentalmente identico a ScriptClip, ma l'output che viene generato dalla filterchain impiegata è ignorato. Ammetto la mia ignoranza ma non sono mai riuscito a fare un grande uso di questo filtro. In teoria dovrebbe servire per assegnare variabili, ma nella pratica non mi sono mai trovato in una situazione in cui mi servisse usarlo, per cui non saprei che dirvi.

ConditionalReader sfrutta un file di testo esterno per decidere come comportarsi in base al frame. Ha un suo formato particolare che viene dettagliato in una pagina a sé stante. Può tornare utile in caso di filtraggio molto avanzato, ma data la complessità di utilizzo non mi sono mai trovato a farne uso, preferendo sfruttare altri metodi per raggiungere gli stessi risultati.


In linea generale, di questi, utilizzo più spesso ScriptClip e di tanto in tanto mi capita di usare ConditionalFilter o ConditionalSelect.

ScriptClip in particolare torna utile in YATTA perché consente di creare preset generici che si adattano in base al frame e quindi si può tagliare il numero di custom list/preset impiegati sfruttando questo fatto.

Un esempio un po' più concreto è il seguente:

Si vuole applicare il filtro invert soltanto ad alcuni frame per cui è stato creato un mask che specifica su quale parte del frame serve applicare il filtro.

Senza ScriptClip, dovremmo manualmente caricare ogni singolo mask e usarlo su ogni frame corrispondente. Con ScriptClip possiamo tagliare il numero di righe dello script, rendendolo più leggibile, e automatizzare gran parte del processo, semplificandoci la vita.

Ne consegue che, se l'immagine che si chiama come il tal frame esiste, allora quel frame va filtrato in invert usando il mask stesso.

Ciò può essere eseguito con:

CODICE
percorso = "C:\percorso\delle\immagini\mask\"
estensione = ".png"
ScriptClip("""Exist(percorso+string(current_frame)+estensione) ? mt_merge(last,invert,imagesource(percorso+string(current_frame)+estensione,start=0,end=last.framecount-1).converttoyv12(matrix="PC.709"),true,u=3,v=3) : last""")


Non è necessario specificare percorso ed estensione come variabili, ma facendo così bisogna modificare solo in quel punto qualora si dovesse cambiare percorso/estensione specificati per riciclare il codice, per cui è più comodo per riciclare il codice.


Ok, direi che come introduzione ad AviSynth è stata esaustiva. Ora dovreste avere tutti gli strumenti per fare filtraggio anche molto avanzato. Dalla prossima lezione cominciamo a divertirci con l'ivtc.
 
Web  Top
Cadis Estrama Di Raizel
view post Posted on 2/2/2015, 20:10     +1   -1




CITAZIONE (mirkosp @ 19/1/2015, 16:04) 
[...] Ok, direi che come introduzione ad AviSynth è stata esaustiva. [...]

Alla faccia! Grazie mille comunque.
 
Top
1 replies since 19/1/2015, 16:04   566 views
  Share