Recensubs HQ

Inverse Kernel Resize and you, Tutto quello che hai sempre voluto sapere ma non hai mai osato chiedere

« Older   Newer »
  Share  
Tada no Snob
view post Posted on 3/2/2013, 04:12 by: Tada no Snob     +1   -1
Avatar

Snobbery Inside

Group:
Utente abilitato
Posts:
2,197
Reputation:
+1,005
Location:
Favolandia

Status:


Premessa, se non siete encoder o non volete tutta la pappardella iniziale scrollate pure fino alle conclusioni.

Bene, detto questo è utile dare una definizione di quello che si intende con inversione del kernel, e lascio la parola all'autore di dither, uno dei plugin di cui ormai nessuno può evitare l'utilizzo (se non lo usate e/o non sapete l'inglese saltate alle conclusioni o chiudere il topic, il tutto evidentemente non fa per voi)
Inverting the kernel allows to “undo” a previous upsizing by compensating the loss in high frequencies, giving a sharper and more accurate output than classic kernels, closer to the original.

Ok, la base è quella, dovendo essere più espliciti la tecnica nasce da un problema onnipresente parlando di full hd, ovvero che il materiale non è realmente 1080p ma spesso ad una risoluzione inferiore (480, 540 o 720 di solito), questo potrebbe anche essere accettabile, il vero problema però è il modo in cui gli anime vengono quasi sempre portati a 1080p, ovvero attraverso un resize bilineare, che blurra da matti perdendo parecchia nitidezza (le altre frequenze di cui si parlava sopra).
Ridimensionare alla risoluzione originale aiuta a non rilasciare un file mastodontico e blurratissimo, ma non compensa la perdita originale.
Proprio per questo sono nate le tecniche di inversione del kernel, che sono incluse in due plugin per avisynth, dither e debilinear.

Senza troppo perderci in inutili chiacchere posto 3 immagini, ognuna ridimensionata a 1280x720 con un metodo diverso
Blackman4taps
Dither16_invks_bilinear
Debilinear

Apritele ognuna in una scheda diversa, potrete vedere da soli la differenza tra i vari metodi.
In particolare tra debilinear e blackman c'è una differenza di dettaglio veramente evidente (e anche una differenza di filesize, la maggiore nitidezza infatti incide in modo sfavorevole da questo punto di vista, e potete aspettarvi anche un aumento di bitrate richiesto del 20%).
Tra dither16 e debilinear la differenza invece è meno evidente (il secondo però dovrebbe apparirvi leggermente più nitido).
La differenza tra i due è semplice, debilinear è l'inversione perfetta di un BilinearResize di avisynth, l'invks invece usa un algoritmo diverso, che ha più parametri di controllo ma che, a conti fatti, restituisce un'immagine meno nitida ma anche meno priva di artefatti.
E debilinear, proprio per come è stato progettato, è molto più facile che li crei. Scordatevi infatti il crop e scordatevi una resa accettabile nel caso ci siano dettagli superiori a quelli della risoluzione finale.

E proprio i dettagli a risoluzione superiori rispetto a quella finale sono il vero problema del metodo, il chroma, i crediti, le scritte a schermo, i titoli, tutti queste parti possono contenere dettaglio che mal si sposa con i metodi di inversione del kernel, soprattutto debilinear.
Per il chroma non è un grosso problema, si può fare 444 o accontentarsi di un normale resize, tutto il resto fino a ieri richiedeva l'utilizzo di dither16 tappandosi il naso.
Da oggi invece non è più così perché c'è una bella funzioncina che dovrebbe aiutare a maskare i dettagli e permettere un merge salvifico.
La parola alle immagini
Blackman
DebilinearNotMasked
DebilinearMasked



Direi che si commentano da sole.
La funzione
CODICE
#masking detail v0.1a
function MaskDetail(clip clp, int final_width, int final_height, int "RGmode", int "cutoff", float "gain", int "expandN", int "inflateN", bool "blur_more", float "src_left", float "src_top", float "src_width", float "src_height")
{
RGmode = default( RGmode,  3)  # spatial filter to remove false positive (noise, compression artifact and so on) , this is its mode
cutoff = default( cutoff,  70 ) # exclude from the mask the pixel with less than this value
gain = default( gain,  0.75 ) # increase the value of the remaining pixel
expandN = default( expandN,  2 ) # how many mt_expand
inflateN = default( inflateN,  1 ) #how many mt_inflate
blur_more = default( blur_more,  false ) #additional blur after resize
src_left= default( src_left,  0 )
src_top = default( src_top,  0 )
src_width = default( src_width,  0 )
src_height = default( src_height,  0 )
CUT   = string(cutoff)
GAN = string(gain)

diff=mt_makediff(clp,clp.debilinearY(final_width,final_height).bilinearresize(clp.width(),clp.height()),u=1,v=1)
initial_mask = diff.histogram("luma").Removegrain(RGmode,-1).mt_lut("x "+CUT+" < 0 x "+GAN+" 256 x + 256 / * * ?",u=1,v=1)
expanded = initial_mask.expandMask(expandN)
inflated = expanded.inflateMask(inflateN)
final = blur_more ? inflated.BilinearResize(final_width, final_height, src_left, src_top, src_width, src_height).Removegrain(12,-1) : inflated.BilinearResize(final_width, final_height, src_left, src_top, src_width, src_height)
return final.Greyscale()
}

function expandMask(clip clp, int "expandN")
{
return expandN > 0 ? expandMask(clp.mt_expand(u=1,v=1), expandN - 1) : clp
}
function inflateMask(clip clp, int "inflateN")
{
return inflateN > 0 ? inflateMask(clp.mt_inflate(u=1,v=1), inflateN - 1) : clp
}


Per chi è a digiuno di reverse polish notation il lut fa x < cutoff ? 0 : x * gain * (256+x) / 256
Il resto si capisce anche dando una rapida lettura.
Ovviamente è una funzione da tweakare in base alle esigenze e a quanto si voglia una mask precisa (in questo caso è molto importante anche cosa si sceglie come metodo di removegrain)

Come test il tutto è stato applicato ai blu-ray di one off, che sono stati il motivo principale che mi hanno spinto a completare questa funzione, però il campo di applicazione non è affatto limitato ai blu-ray, ad esempio la funzione mi è tornata molto utile per lo scrolling text di Vividred Operation
Dither_invks_puro
Dither_invks_maskato

Decisamente meglio.

Ok, dopo questa introduzione lunghissima è arrivato il momento di qualche snippet di codice.
Con One Off ho usato
CODICE
mask = MaskDetail(last,1280,720,expandN=2,inflateN=1,RGmode=3,cutoff=70,gain=0.8,blur_more=true)
Dither_convert_8_to_16()
big=last
DebilinearY(1280,720,lsb_inout=true)
noalias=big.Dither_resize16(1280,720,kernel="blackmanminlobe", taps=5)
masked = Dither_merge16_8(noalias,last, mask.invert(), u=1,v=1)
strange(0,3138,masked)
strange(21069,21235,masked)
strange(40796,0,masked)
MergeChroma(noalias)
#segue codice per output a 10bit

(uso la maschera invertita perché così se tutto il video è da maskare posso fare u=2 e V=2 e risparmiare il mergechroma finale)

Per Vividreddo
CODICE
#mask fatto a mano prima di scrivere la funzione, quindi escluso
Dither_convert_8_to_16()
big=last
Dither_resize16(1280,720,kernel="bilinear", invks=true,y=3, u=1, v=1,src_left=2, src_width=-2)
noalias=big.Dither_resize16(1280,720,kernel="blackmanminlobe", taps=4,src_left=2, src_width=-2,y=3,u=3,v=3)
masked = Dither_merge16_8(noalias,last, mask.invert(), u=1,v=1)
strange(2949,3020,noalias)
strange(792,2949,masked)
strange(17463,18508,masked)
strange(32583,34811,masked) #in realtà dalla 3 in poi ho messo una zona a parte per il "continua", dato che è inutile maskarlo
MergeChroma(noalias)
#segue codice per output a 10bit


La differenza è data soprattutto dalla sorgente, già solo il crop renderebbe sconsigliato Debilinear per Vivid, in più parliamo di una trasmissione tv, dove blocking, scagate varie dell'mpeg2, noise ecc ecc sono all'ordine del giorno.
Invks di dither aiutare a dare più nitidezza e direi che oltre non è saggio spingersi.
E anche invks di solito lo uso con l'opzione invkstaps=4 o meno, sia per bloatare di meno sia per assicurarmi che ci siano meno artefatti (per gli screen ho preferito tornare a settaggi più spinti per illustrare meglio la differenza).

L'altra alternativa sarebbe usare Dither_resize16nr, che è un wrapper intorno a Dither_resize16 (lo si usa allo stesso modo, aggiungendo noring=true) che dovrebbe aiutare a combattere il rining.
Considerato che l'inverse kernel più che altro crea aliasing, e che l'nr non lo rimuove del tutto, direi che l'utilità non è esagerata.
Va bene per avere ancora maggiore sicurezza rispetto al dither invks classico e risparmiare un po' di filesize, ma personalmente non mi convince, ho fatto qualche encode di prova e ho notato un'immagine più piatta, con meno digital noise e quindi a maggiore rischio artefatti (ho provato con Strike Witches S2, che ha della gran fapdigital grain).

Conclusioni aka tl;dr
L'inverse kernel è un ottimo modo per ridare al video quella nitidezza che aveva in origine, ma non è né la panacea di tutti i mali né un settaggio "set and forget".
Per i blu-ray upscalati e la roba su cruncyroll presa bene mi sentirei di consigliarlo nella maggioranza dei casi, nella serie tv solo se avete la sbatta di perdere del gran tempo sul ts, perché l'inverse kernel rende più nitido il video ma molto più evidenti gli errori o le mancanze dell'encoder, insomma, soprattutto per anime d'azione su canali pietosi non è detto che il gioco valga la candela.
È una di quelle cose da valutare da persona a persona e di caso in caso (come, imho, il delogo).
Se siete saltati fin qui dalla prima riga e pensiate che possa valere la pena di tentare, ignorate il codice postato e ripartite dall'ìnizio a leggere.
Se invece questo non fa al caso vostro chiudete pure il topic e infilate la testa tra la sabbia, ma sappiate che personalmente porrei un limite di voto settato a 7 per gli encoding da blu-ray fatti senza inverse kernel.

Spero di essermi ricordato di scrivere un po' tutto. ma nel caso fatemi pure notare cosa ho scordato, o se ho scritto fesserie (i typo/errori vari da 4 di mattina li correggerò io in seguito, segnalate roba di concetto XD).
Ci sarebbero altri punti da toccare (inverse kernel + 444, inverse kernel con fap-upscale a 1080p ecc ecc), ma non ne ho tempo, voglia ed è anche giusto che pure mirkosp e Mad Hatter tirino un po' fuori la paglia dal culo postando script/immagini/opinioni.
 
Web  Top
28 replies since 3/2/2013, 04:12   5530 views
  Share