Files
Titano/Titano
Alby96andClaude Opus 5 a815a91006 Sei moduli avanzati per la produzione cinematografica
Estende il motore con stabilizzazione sub-pixel, deflicker per regioni,
transizioni giorno-notte, movimento di macchina virtuale, rimappatura non
lineare del tempo e accumulo temporale. Tutto in-house, nessuna dipendenza
aggiunta: il progetto continua a non contenere un solo PackageReference.

Perche' questa forma. Il rendering non percorre piu' la sequenza sorgente ma
un piano di fotogrammi d'uscita, ognuno con posizione anche frazionaria e
durata propria. Le quattro modalita' temporali producono tutte quella stessa
forma, quindi il ciclo di rendering e' uno solo e non ha un ramo per ciascun
caso; da li' discende anche la sfocatura, perche' un fotogramma che copre v
scatti ha angolo di otturatore diviso v.

Gli spostamenti si misurano con la correlazione di fase, che ignora per
costruzione le differenze di luminosita' fra scatti - in un time-lapse ci sono
sempre - e reagisce alla sola geometria. Il picco intero non basta: la
superficie di correlazione viene ricostruita a passo fine valutando la somma
di Fourier sulle posizioni intermedie invece di interpolare con una parabola
tre campioni di una cresta che parabola non e'. L'errore misurato scende da
0,14 a 0,08 px.

I gradini di esposizione non sono rumore da mediare: l'ampiezza si legge
esatta nei metadati e viene ridistribuita su una transizione a derivata nulla
agli estremi. Il deflicker lavora poi su una serie gia' priva di gradini,
invece di trasformare lo scalino in una rampa con due spigoli.

La maschera delle regioni nasce dalla mediana temporale di un campione di
fotogrammi, che toglie di mezzo proprio le nuvole di passaggio, e la linea
d'orizzonte viene agganciata al massimo del gradiente verticale. Sulla scena
di prova il terreno passa da 0,062 a 0,026 stop di oscillazione.

Ritaglio virtuale e correzione di stabilizzazione sono entrambi affini e
vengono composti in una sola trasformazione: due ricampionamenti in fila
costerebbero il doppio di nitidezza senza dare nulla in cambio.

Sulla memoria: i moduli avanzati hanno rotto l'assunto che bastassero due
fotogrammi vivi alla volta, quindi il disco entra ora in gioco - come annotato
nel commit precedente, e' questa la porta che si apriva. La finestra attiva
resta sempre in memoria perche' la mediana ha bisogno di tutti i suoi
fotogrammi insieme; solo la lettura in anticipo viene parcheggiata su disco
oltre il tetto, e ripresa una volta sola. Non esiste un caso in cui lo stesso
fotogramma vada e torni piu' volte. Il file di parcheggio si cancella da se'.

Verifica: da 26 a 51 controlli. Nessuna soglia scelta a posteriori - il
tremolio ha un percorso noto, il gradino un'ampiezza dichiarata nei metadati e
visibile nei pixel, la nuvola attraversa il solo cielo. Il controllo
conclusivo rende una sequenza con tutti i moduli attivi insieme e tetto di
memoria volutamente stretto, poi la rilegge con il lettore di sistema.
Verificato anche sui DNG GoPro reali: 580 file, render di prova conforme.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 16:55:27 +02:00
..

Titano

Applicazione desktop per la creazione e l'ottimizzazione di time-lapse di livello professionale, sviluppata interamente in-house.

Il vincolo che definisce il progetto

Zero librerie di terze parti. Il file di progetto non contiene alcun <PackageReference>: tutto ciò che non è la libreria standard di .NET è scritto qui dentro oppure ottenuto tramite P/Invoke diretto verso componenti del sistema operativo.

Ambito Come è risolto
Parsing EXIF / XMP Parser binario proprietario (Metadata/)
Analisi fotometrica e deflicker Algoritmi proprietari (Analysis/)
Campo vettoriale e motion blur Schema differenziale piramidale proprietario (Motion/)
Trasformata di Fourier CooleyTukey a base due, in loco (Motion/Fourier.cs)
Segmentazione e stabilizzazione Otsu, gradiente e correlazione di fase proprietarie
Interpolazione di curve Spline monotona e Bézier proprietarie (Core/Spline.cs)
Contenitore MP4 Multiplexer ISO-BMFF proprietario (Video/Mp4Muxer.cs)
Decodifica immagini WIC, componente di Windows, via COM interop scritto a mano
Codifica video Media Foundation Transform, encoder hardware di sistema
Interfaccia grafica WinForms + GDI+, ogni controllo disegnato a mano (UI/)

Non viene invocato nessun processo esterno: niente FFmpeg, niente ExifTool.

Principi architetturali

Il video è l'unico file che sopravvive. Il flusso compresso viene prodotto in streaming: ftyp e l'header mdat all'apertura, i pacchetti dell'encoder direttamente nel file, moov in chiusura. L'elaborazione può creare un solo altro file — il parcheggio temporaneo dei fotogrammi descritto più sotto — che nasce con la cancellazione automatica alla chiusura e non contiene nulla di riutilizzabile.

Impronta di memoria governata, non incidentale. I fotogrammi vivono in array float presi da un pool (Imaging/ImageBuffer.cs) e passano da una finestra scorrevole (Pipeline/FrameWindow.cs). L'occupazione dipende dall'ampiezza della finestra — che l'utente sceglie — e mai dalla lunghezza della sequenza: la verifica automatica lo misura esplicitamente.

Interfaccia reattiva. Ingestion, analisi e render girano su thread di lavoro; il thread dell'interfaccia riceve solo aggiornamenti di stato immutabili tramite IProgress<T>.

Struttura

Metadata/    parser binario TIFF/Exif, scanner XMP, riconoscimento contenitori
Core/        sequenza, cadenza, shutter angle, spline monotona e Bézier
Imaging/     buffer poolati, spazio colore lineare, decodifica WIC, stadio geometrico
Analysis/    luminanza, deflicker, segmentazione in regioni, transizioni giorno-notte
Motion/      Fourier, correlazione di fase, stabilizzazione, optical flow, blur, stacking
Video/       conversione NV12, encoder Media Foundation, multiplexer MP4
Pipeline/    piano di rendering, finestra scorrevole, orchestrazione, impostazioni
UI/          tema scuro, grafico vettoriale, editor di curve e keyframe, pannelli
Diagnostics/ sequenze sintetiche, verifica end-to-end, ispettore MP4

Il piano di rendering

Il motore non percorre la sequenza sorgente: percorre un elenco di fotogrammi d'uscita, ognuno con la propria posizione — anche frazionaria — e la propria durata. Durata costante, durata proporzionale all'intervallo, cadenza uniformata e rimappatura non lineare producono tutte quella stessa forma, quindi il ciclo di rendering è uno solo e non contiene un ramo per ciascuna modalità.

Una posizione frazionaria significa un fotogramma che non esiste e va sintetizzato dal campo vettoriale. Da qui discende anche la sfocatura: se un fotogramma d'uscita copre v scatti, l'angolo di otturatore effettivo è quello di ripresa diviso v, e la scia da sintetizzare si scala della stessa quantità. Accelerare e rallentare restano quindi coerenti con la fisica dell'esposizione invece di essere un semplice salto di indici.

Note sugli algoritmi

Deflicker. Per ogni fotogramma si esegue una regressione lineare locale pesata sulla finestra mobile. I pesi combinano una gaussiana sulla distanza temporale e, in seconda passata, un peso di robustezza di Tukey che neutralizza i fotogrammi anomali. La componente lineare segue senza ritardo le rampe reali di luce (alba, tramonto) e rimuove solo la componente ad alta frequenza dovuta alle micro-variazioni del diaframma. La misura è la media logaritmica troncata: invariante alla scala, insensibile a cieli bruciati e ombre chiuse.

Motion blur. Lo shutter angle reale è 360 × posa / intervallo. La scia già incisa nel fotogramma e quella sintetica si compongono in quadratura, quindi per raggiungere l'apertura obiettivo serve una scia di √(obiettivo² reale²) volte lo spostamento: sommare linearmente produrrebbe un'immagine sistematicamente troppo morbida. Il filtro di ricostruzione è di tipo gather: un campione contribuisce al pixel centrale solo se la propria scia lo raggiunge davvero, così lo sfondo fermo non viene trascinato nei soggetti in movimento.

Optical flow. Schema differenziale piramidale: su ogni nodo di una griglia rada si risolve iterativamente il sistema normale 2×2 costruito dai gradienti spaziali e dalla differenza temporale. Un filtro mediano fra un livello e l'altro elimina i vettori spuri delle zone piatte. L'analisi avviene a risoluzione ridotta e i vettori vengono riportati in scala piena: il costo non dipende dalla dimensione dei file sorgente. Il campo si calcola solo quando serve davvero: se la posa copre già più dell'apertura obiettivo — il caso delle riprese notturne, con pose da trenta secondi su intervalli da trentaquattro — non c'è sfocatura da sintetizzare e la voce di spesa più pesante della pipeline viene saltata.

Moduli avanzati

Stabilizzazione sub-pixel. Lo spostamento fra fotogrammi adiacenti si misura con la correlazione di fase: una traslazione nello spazio è uno sfasamento lineare in frequenza, e normalizzando lo spettro incrociato al modulo unitario resta solo la fase, la cui antitrasformata è un impulso posto sullo spostamento. Il metodo ignora quindi per costruzione le differenze di luminosità fra due scatti — che in un time-lapse ci sono sempre — e reagisce alla sola geometria. Sotto il pixel la superficie di correlazione viene ricostruita a passo fine valutando direttamente la somma di Fourier sulle posizioni intermedie, invece di interpolare con una parabola tre campioni di una cresta che parabola non è: l'errore misurato scende da 0,14 a 0,08 px. Nove riquadri per coppia danno nove misure indipendenti, da cui si stima ai minimi quadrati una similitudine — traslazione, rotazione e scala — scartando i riquadri occupati da nuvole o fronde, che si muovono per conto loro. Il percorso assoluto viene infine lisciato: ciò che resta fra percorso vero e percorso liscio è il tremolio, e la sua inversa è la correzione. Una panoramica voluta sopravvive perché è già liscia.

Deflicker per regioni. Una nuvola densa che attraversa il cielo abbassa la luminanza media del fotogramma; il deflicker legge un calo di luce e schiarisce tutto, paesaggio compreso, che invece non era cambiato. Titano divide il fotogramma in due regioni e dà a ciascuna la propria curva. La maschera nasce una volta sola dalla mediana temporale di un campione di fotogrammi — la mediana toglie di mezzo proprio ciò che passa e non resta — e la linea d'orizzonte viene poi agganciata al massimo del gradiente verticale, che cade sul bordo vero e non dove capita la soglia. Sulla scena di prova il terreno passa da 0,062 a 0,026 stop di oscillazione.

Transizioni giorno-notte. Attraversando il tramonto la macchina deve cambiare tempo, ISO o diaframma, e ogni cambio è quantizzato: nel filmato si vede uno scalino netto. Il deflicker ordinario non aiuta, perché un gradino non è rumore da mediare e la finestra mobile lo trasforma in una rampa con due spigoli. Titano legge invece l'ampiezza esatta nei metadati — il valore di esposizione vale log2(N²/t) log2(ISO/100) — e la ridistribuisce su una transizione a derivata nulla agli estremi, lunga a piacere. Il deflicker lavora poi sulla serie già priva di gradini. Il bilanciamento del bianco riceve un trattamento parallelo: si liscia il rapporto fra i canali invece della loro luminanza, così sparisce il tremolio del bilanciamento automatico e resta il viaggio verso il caldo del tramonto.

Movimento di macchina virtuale. Un sensore da dodici megapixel contiene un 4K con abbondante margine di ritaglio: da lì si ricava una panoramica che in ripresa avrebbe richiesto una slitta motorizzata, decisa dopo, guardando il materiale. Fra un nodo e il successivo il tempo passa per una curva di Bézier con estremi fissi — senza, il movimento partirebbe e si fermerebbe di colpo, e a velocità di time-lapse lo scatto si vede benissimo. Ritaglio e correzione di stabilizzazione sono entrambi affini e vengono composti in una sola trasformazione: il fotogramma viene interpolato una volta sola, con una cubica di Catmull-Rom.

Rimappatura non lineare del tempo. Una curva di velocità dice quanti scatti vengono consumati per ogni fotogramma d'uscita: sopra 1 la sequenza accelera saltando scatti, sotto 1 rallenta e i mancanti vengono sintetizzati. La velocità del filmato resta fissa. La spline è monotona per costruzione (schema di FritschCarlson): una Catmull-Rom ordinaria sovraelongerebbe fra due nodi molto diversi, e una velocità negativa farebbe tornare indietro la sequenza.

Accumulo temporale. La mediana su una finestra di fotogrammi dà a ogni pixel il valore centrale della propria serie: la scena stabile resta se stessa, chi attraversa l'inquadratura una volta sola sparisce. Una media lascerebbe un fantasma tanto più visibile quanto più l'intruso era contrastato. Il massimo progressivo conserva invece il valore più alto incontrato e trasforma le stelle in archi continui; con una lunghezza di scia finita l'accumulo decade e le scie hanno una coda invece di riempire il cielo. Se la stabilizzazione è attiva i fotogrammi vengono sovrapposti dopo averli raddrizzati, altrimenti la mediana scambierebbe per intruso il tremolio stesso.

Memoria e parcheggio su disco

I moduli avanzati hanno rotto l'assunto su cui la pipeline originale era costruita: che bastassero due fotogrammi vivi alla volta. La mediana ne vuole un'intera finestra simultaneamente, la rimappatura può chiedere lo stesso scatto per molti fotogrammi d'uscita consecutivi.

La regola di residenza è una sola e non produce mai andirivieni: la finestra attiva sta sempre in memoria, perché chi la usa ha bisogno di tutti i suoi fotogrammi insieme; i fotogrammi letti in anticipo — che servono a tenere occupati tutti i processori sulla decodifica dei RAW, la parte più lenta della pipeline — finiscono su disco quando il tetto di memoria è raggiunto, e vengono ripresi una volta sola, quando entrano nella finestra. Non esiste un caso in cui lo stesso fotogramma vada e torni dal disco più volte. Il file di parcheggio nasce con l'opzione di cancellazione alla chiusura: se il programma termina male, lo rimuove il sistema.

Sorgenti RAW e limiti dei codec

I file RAW e DNG non espongono l'immagine principale nella prima directory: quella è una miniatura, e le dimensioni vere vivono in una SubIFD marcata come non ridotta. Titano sceglie la directory dell'immagine principale invece di fidarsi della prima, e legge i metadati con una finestra che si estende su richiesta: di un DNG da 15 MiB ne tocca 128 KiB.

Orientamento. Il tag Exif dice come raddrizzare l'immagine, ma non basta leggerlo: alcuni decodificatori di sistema lo applicano già per conto proprio e altri no. Applicarlo una seconda volta ribalta il fotogramma, non applicarlo mai lo lascia coricato. In modalità automatica Titano confronta le dimensioni che il decodificatore restituisce con quelle che il file dichiara di contenere e decide di conseguenza; la sezione Generale mostra cosa ha dedotto e permette di imporre una trasformazione diversa, con riscontro immediato nell'anteprima.

Qualità. Il profilo di elaborazione governa finezza della griglia del campo vettoriale, livelli della piramide, iterazioni per livello, campioni per pixel della scia e risoluzione della passata fotometrica. Il valore predefinito è "Massima": costa circa tre volte il tempo di "Standard" e si vede nei bordi dei soggetti in movimento.

La risoluzione di lavoro viene infine ricondotta ai limiti del codec. Un encoder hardware accetta volentieri un fotogramma 4000×3000 e dichiara un livello alto: il flusso è formalmente valido ma supera il Livello 5.2 di H.264, e i decodificatori comuni si rifiutano di aprirlo. Il video uscirebbe, peserebbe, e non si riprodurrebbe. Titano riduce quindi il fotogramma al massimo riproducibile conservando le proporzioni, e lo dichiara in interfaccia. Le sorgenti 16:9 fino al 4K UHD non vengono toccate.

Compilazione ed esecuzione

dotnet build -c Release
dotnet run  -c Release

Richiede .NET 10 SDK su Windows x64.

Verifica automatica

Titano.exe --selftest [cartella]

Genera sequenze sintetiche dalle proprietà note e le fa attraversare l'intera pipeline, confrontando 51 grandezze misurate con i valori attesi. Nessuna soglia è scelta a posteriori: la scena è costruita perché il valore atteso sia la conseguenza aritmetica di come è stata generata — il tremolio ha un percorso noto, il gradino di esposizione un'ampiezza dichiarata nei metadati e visibile nei pixel, la nuvola attraversa il solo cielo.

Copre campi Exif, cadenza e shutter angle; riduzione dello sfarfallio e conservazione della rampa di luce; invarianza della luminanza alla scala di decodifica; correlazione di fase sotto il pixel; misura e rimozione del tremolio con la panoramica voluta che sopravvive; copertura della maschera delle regioni; riconoscimento e ridistribuzione dei cambi di esposizione; lisciatura cromatica con la deriva del tramonto conservata; monotonia e simmetria delle curve di accelerazione; trasparenza e ritaglio dello stadio geometrico; monotonia della rimappatura temporale; rimozione dell'intruso da parte della mediana e conservazione dei passaggi da parte del massimo; allineamento delle NAL dentro ogni campione del contenitore; e — prova conclusiva — un rendering con tutti i moduli attivi insieme, con tetto di memoria volutamente stretto per esercitare il parcheggio su disco, riletto poi dal lettore di sistema.

Titano.exe --diagnose <cartella> [uscita.mp4] [fotogrammi] [larghezza] [h264|hevc]

Riporta cosa il programma riesce davvero a leggere da una cartella reale: metadati file per file, dimensione dichiarata contro dimensione decodificata, coerenza della luminanza fra risoluzioni diverse, cadenza sull'intera sequenza. Indicando un file di uscita esegue anche un render di prova e ne riverifica il contenitore. È lo strumento con cui si distingue un difetto del motore da un formato che il sistema non sa aprire.

Titano.exe --capture <file.png> [cartella-sequenza] [scheda] [avanzato]

Cattura l'interfaccia in un'immagine, per verificarne la resa in modo riproducibile. Con avanzato i moduli opzionali vengono accesi prima del caricamento, così l'immagine mostra curve di regione, marcatori dei cambi di esposizione, percorso della macchina virtuale e contorno delle regioni con dati veri invece che a riposo.

Titano.exe --make-icon <file.ico>

Ridisegna l'icona dell'applicazione — scie stellari attorno al polo celeste, l'immagine in cui il tempo diventa visibile — e ne scrive il contenitore ICO a mano. I livelli sotto i venti pixel ricevono meno archi e più spessi: alla dimensione della barra delle applicazioni sette scie sottili diventerebbero una macchia.