Recensubs HQ

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

« Older   Newer »
  Share  
view post Posted on 6/2/2013, 12:09     +1   -1
Avatar

Distruttore di mercati

Group:
Utente abilitato
Posts:
682
Reputation:
+163
Location:
Aiur

Status:


Si lo avevo notato, sul mio post precedente ho preso in considerazione solo il caso orizzontale visto che il perché ci sia lo shift di 0.5 in verticale mi è chiaro, non mi è ben chiaro il perché di quello orizzontale.
 
Top
view post Posted on 6/2/2013, 12:25     +1   -1
Avatar

Snobbery Inside

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

Status:


CITAZIONE (mirkosp @ 6/2/2013, 11:15) 
Non serve, perché facendo direttamente src_width=width, src_height=height, va a prendere i valori del last, che in quel punto coincide ancora con big (e poi big non viene più usato).

Eh, l'idea è di riscriverlo meglio e più chiaro in seguito, e quindi, tra le altre cose, mandare a capo dopo Dither_convert_8_to_16().
E in quel caso avrei un'altezza doppia, quindi preferisco salvarmi una clip a 8 bit per le proprietà (in realtà sarebbe meglio salvarsi o, ancora meglio, calcolarsi, i valori direttamente, ma quella è una cosa che pensavo di fare insieme al post crop).

@Liquid Dr4k3: ma infatti per il turnright->nnedi->turnleft lo shift orizzontale è 0 (e -0.5 quello verticale).
Poi però c'è un nnedi senza turnright o turnleft, e lì lo shift orizzontale è -0.5 (e 0 quello verticale).
Totale -0.5 e -0.5.
 
Web  Top
view post Posted on 6/2/2013, 12:33     +1   -1
Avatar

Distruttore di mercati

Group:
Utente abilitato
Posts:
682
Reputation:
+163
Location:
Aiur

Status:


Perfetto, adesso mi è chiaro... non stavo pensando che dopo il turnright->nnedi->turnleft si introduceva uno shift verticale.
Pensavo che dopo turnright->nnedi->turnleft lo shift fosse zero per entrambi, grazie ^^

Edited by Liquid Dr4k3 - 6/2/2013, 13:08
 
Top
LastSlice
view post Posted on 30/7/2013, 15:21     +1   -1




Innanzitutto grazie per le informazioni. Poi, precisando che:

•non sono un encoder;
•ho preso la prima cosa 1080p che ho trovato per fare una prova;
•nello script avs ho solo FFVideoSource e sotto il primo degli esempi (quello per i BD di One Off).

Aprendo il video con Virtualdub mi esce 'sta roba
http:// i.imgur.com/XqupIlQ.jpg

A intuito potrei pensare che è perché non ho messo tale "segue codice per output a 10bit", però non so nemmeno cosa scrivere. :v
C'è qualcuno che potrebbe gentilmente aiutarmi?
 
Top
view post Posted on 30/7/2013, 16:09     +1   -1
Avatar

Distruttore di mercati

Group:
Utente abilitato
Posts:
682
Reputation:
+163
Location:
Aiur

Status:


Quello è lo stack MSB LSB, infatti quelli che vedi sopra sono gli 8bit più significativi e quelli sotto sono gli 8bit meno significativi. Tada alla fine dello script aveva messo #segue codice per output a 10bit, visto che l'output dello script stesso è a 16bit. Se vuoi darlo in input ad x264 a 10bit aggiungi:
CODICE
Dither_quantize(10,reducerange=true,mode=8).Dither_out()

alla fine, se invece vuoi tornare ad 8bit:
CODICE
DitherPost()


Btw, hai preso un pessimo esempio visto che Shingeki no Kyojin non è 720p, ma a quanto pare ha un dettaglio effettivo che varia da scena a scena... quindi fare kernel inversion blind a 720p su quel video non è la cosa migliore visto che ti andresti a mangiare dettaglio.
 
Top
view post Posted on 30/7/2013, 16:24     +1   -1
Avatar

Snobbery Inside

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

Status:


Più che altro andresti a creare haloing.
La perdita di dettaglio è il meno.

Comunque le priorità per la storia dell'inverse kernel sarebbero:
- far uscire la nuova versione di maskdetails con il prefilter, che è quella che uso ormai da mesi (banale, ma non ho voglia di farlo)
- rendere Mighty Upscale funzionante in tutti i casi e non a culo se la source è 720p (forse fattibile, ma è una rottura di palle)
- finalizzare un antialiasing serio che non crei haloing (hardmode)

In generale la grossa inculata è che su avisynth non esiste un vero e proprio passabasso (cioè, credo si possa fare, ma non ho idea di come farlo funzionare per bene).
 
Web  Top
view post Posted on 30/7/2013, 16:36     +1   -1
Avatar

Distruttore di mercati

Group:
Utente abilitato
Posts:
682
Reputation:
+163
Location:
Aiur

Status:


Stranamente facendo dbl a 720p non si crea tanto haloing in questo caso (provato sia su bd che ts che crunchy). Invece da BD facendo dbl->nnedi->invks mi crea ringing, infatti non ho adottato quella soluzione proprio per questo motivo. Il vero problema è che non si riesce a capire esattamente quale sia la risoluzione per ogni sequenza (da lì il ringing con dbl->nnedi->invks), infatti se si riuscisse a far funzionare mighty upscale anche in questi casi sarebbe una benedizione.
 
Top
LastSlice
view post Posted on 30/7/2013, 19:50     +1   -1




CITAZIONE (Liquid Dr4k3 @ 30/7/2013, 17:09) 
Quello è lo stack MSB LSB, infatti quelli che vedi sopra sono gli 8bit più significativi e quelli sotto sono gli 8bit meno significativi. Tada alla fine dello script aveva messo #segue codice per output a 10bit, visto che l'output dello script stesso è a 16bit. Se vuoi darlo in input ad x264 a 10bit aggiungi:
CODICE
Dither_quantize(10,reducerange=true,mode=8).Dither_out()

alla fine, se invece vuoi tornare ad 8bit:
CODICE
DitherPost()

Ho usato DitherPost(), visto che mi interessava fare una lossless prima di passare da x264.exe. Grazie, funziona.

Avrei però ancora due domande, se non è un problema.

CITAZIONE
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)


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

1) Come diventa il codice per applicarlo a tutto il video?

2) Non c'entra niente con questo, però volevo sapere qualcosa a riguardo di AddGrain. O meglio, come esempio nella pagina di Avisynth c'è AddGrain(20, 0, 0), ma più o meno qual è il limite da non superare?
 
Top
view post Posted on 30/7/2013, 20:53     +1   -1
Avatar

Snobbery Inside

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

Status:


CITAZIONE (LastSlice @ 30/7/2013, 20:50) 
1) Come diventa il codice per applicarlo a tutto il video?

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)
Dither_merge16_8(noalias,last, mask.invert(), u=1,v=1)
MergeChroma(noalias)


o meglio

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)
Dither_merge16_8(noalias,last, mask.invert(), u=2,v=2)


(non l'ho testato ma sono ragionevolmente sicuro che sia ok)


Comunque è meglio impararsi un po' il linguaggio di avisynth e cosa fanno i filtri, prima di provare a smanettare su filtri complessi/non propriamente adatti a neofiti.

CITAZIONE (LastSlice @ 30/7/2013, 20:50) 
2) Non c'entra niente con questo, però volevo sapere qualcosa a riguardo di AddGrain. O meglio, come esempio nella pagina di Avisynth c'è AddGrain(20, 0, 0), ma più o meno qual è il limite da non superare?

Dipende molto dall'anime in realtà.
Comunque a occhio e croce io non salirei oltre i 5 (20 è davvero assurdo come valore), poi diventa troppo vistoso.
E comunque devi considerare che successivamente lo vai a comprimere, e rischi che tutto quel bel grain aggiunto se ne vada via/rimanga impastato.
Come spesso accade nell'encoding devi andare a occhio.
 
Web  Top
LastSlice
view post Posted on 30/7/2013, 21:37     +1   -1




Darò sicuramente un'occhiata alla wiki di Avisynth, grazie per le risposte.
 
Top
view post Posted on 3/10/2014, 17:14     +1   +1   -1
Avatar

Distruttore di mercati

Group:
Utente abilitato
Posts:
682
Reputation:
+163
Location:
Aiur

Status:


Magari a qualcuno può servire quindi la butto qua. In un paio di occasioni mi è servito di maskare dei credit, ma per vari motivi usando il mask proposto da chibi mi si andava ad aggiungere alla mask roba che non volevo. Questo non per colpa della mask chiaramente, ma magari perché stavo andando ad usare dbl a 720p su un qualcosa che 720p non era (senza che dbl facesse troppi danni), come mi è capitato di recente con una .ts di ZnT. Per evitare questo sono andato a modificare leggermente la funzione proposta da chibi aggiungendo un'ulteriore modalità, la quale va a creare la mask su un principio completamente diverso dal fare la differenza tra la clip di partenza e la clip downscalata con dbl e riupscalata con bilinear. Per la precisione questa modalità sfrutta il fatto che, solitamente, i credit sono aggiunti in pc-range, mentre tutto il resto DOVREBBE essere in tv-range. Quindi, andando a fare la mask su tutto quello che ha il luma in pc-range, si dovrebbe ottenere qualcosa di più o meno accurato. Veramente, l'ho modificata al volo e usata un paio di volte a dir tanto, quindi se notate qualcosa che non va fatemi sapere. Più che altro vuole essere uno spunto.

CODICE
function MaskDetailMod(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", int "Mode", int "thr")
{
Mode = default( Mode,  1 ) # =1 -> mt_makediff   !=1 -> PC-Range Mask
thr = default( thr,  233 )
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,  Mode==1 ? 2 : 4 ) # how many mt_expand
inflateN = default( inflateN,  Mode==1 ? 2 : 4 ) #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)
TH = string(thr)

initial_mask= Mode==1 ?
\ mt_makediff(clp,clp.debilinearY(final_width,final_height).bilinearresize(clp.width(),clp.height()),u=1,v=1).Removegrain(RGmode,-1) :
\ mt_lut(clp, "x "+TH+" > x 0 ?",u=1,v=1).Removegrain(RGmode,-1)

mask = initial_mask.histogram("luma").mt_lut("x "+CUT+" < 0 x "+GAN+" 256 x + 256 / * * ?",u=1,v=1)
expanded = 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
}


È uguale a quella nel primo post, semplicemente ho aggiunto mode e thr. Mettendo Mode a 2 (o qualunque cosa diversa da 1 che è il valore di default) si va a creare la mask considerando il pc-range. Invece thr determina il valore di soglia oltre il quale si va a maskare. In teoria thr dovrebbe essere 235, ma ho notato che spesso conviene metterla un poco più bassa per prendere meglio quello che ci interessa, tanto se viene preso qualcos'altro spesso questo viene filtrato da degrain e lut successivi. Quindi di default l'ho messa a 233, ma se si vuole si può modificare mentre si fa un riscontro visivo su quello che stiamo maskando. Inoltre ho notato che maskando sulla base del pc-range spesso conviene dare qualche ciclo in più di inflateMask e expandMask, visto che con 2 cicli solitamente ci si perde qualcosa. Di conseguenza, se si utilizza un Mode != 1, i cicli di inflateMask e expandMask di default saranno 4 invece che 2.
 
Top
MonoS94
view post Posted on 28/12/2014, 22:24     +1   -1




Ho portato la funzione MaskDetail su vapoursynth, e visto che c'ero le ho anche aggiunto il supporto a 16bit [mask a 16bit, is science gone so far??].

L'unica differenza è l'utilizzo di invks invece che di debilinear/bicubic, ma se qualcuno lo ritiene necessario aggiungerò anche questa modalità.

La mia versione include anche la modalità di Liquid e un'altra sperimentale di Chibi [nonché l'unione delle due]

Tutte le info sono qui forum.doom9.org/showthread.php?t=171546

Edited by mirkosp - 29/12/2014, 18:14
 
Top
view post Posted on 19/1/2021, 20:57     +1   -1
Avatar

Bimbosp

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

Status:


Necropost di più di 6 anni, oh yeah baby!

Vi sono mancato? Ovviamente no, ma fa niente.

Ad ogni modo, maskdetail continuava a starmi stretto, nel senso che le maschere che tirava fuori non mi convincevano mai pienamente ed ero certo che ci fosse qualcosa nel procedimento stesso da dover rivedere.
Principalmente, l'approccio a colpi di expand e inflate per cercare di costruire la maschera porta a un risultato molto artificiale e "quadrettoso" che poco combacia con l'area che realmente si voleva mascherare idealmente.
Quel che ne è risultato dopo una sessione di brainstorming e testing di non so quantificare quanto tempo è quel che segue:

CODICE
#edmask v1.0 by mirkosp
#yet another detail mask function for high res elements overlayed on upscaled content
#in other words, masking those 1080 things on non-1080 chinese cartoons.
#first we do the usual: a difference and a removegrain for a first false positive cleanup step
#then we use eedi: actual detail is more likely to be close together and connected, not separated
#however, the first step often runs into false negatives and a straight line at 1080 will often have a few missing bits here and there
#by running eedi, we make sure that things that should be together (text lines and so on) actually get connected
#obviously, since our final result is a mask, we can pick speed over quality settings with little repercussions
#next, we try to clean up false negatives: by running a preliminary lut we cut away a few things, and leave at a 50:50 limbo things which might be details or not
#once we've done that, as actual 1080 details are more likely to be things visible at a distance and not a random dot in the middle of the screen, we do a massive downscale
#by doing this with another removegrain, we improve our odds of removing random false positive noise around the screen
#with a final blur before going back to the final res we ensure the mask is soft so the reversed upscale and the normal resize blend together well enough

function edmask (clip c, int width, int height, int "thrmax", int "thrmin", int "cut") {
thrmax=default(thrmax,128)
thrmin=default(thrmin,50)
cut=default(cut,40)
c
edmask=diffmask(last,debicubicy(width,height).bicubicresize(c.width,c.height)).removegrain(11)
edmask=overlay(edmask.eedi3(0,alpha=0.8,beta=0.1,gamma=100,u=false,v=false,ucubic=false,cost3=false,vcheck=0,mdis=5,nrad=1),edmask.eedi3(1,alpha=0.8,beta=0.1,gamma=100,u=false,v=false,ucubic=false,cost3=false,vcheck=0,mdis=5,nrad=1)).turnleft()
edmask=overlay(edmask.eedi3(0,alpha=0.8,beta=0.1,gamma=100,u=false,v=false,ucubic=false,cost3=false,vcheck=0,mdis=5,nrad=1),edmask.eedi3(1,alpha=0.8,beta=0.1,gamma=100,u=false,v=false,ucubic=false,cost3=false,vcheck=0,mdis=5,nrad=1)).turnright()
edmask.mt_lut("x "+string(thrmax)+" > 255 x "+string(thrmin)+" > 128 0 ? ?").bicubicresize(320,muldiv(320,c.height,c.width)).removegrain(11).mt_lut("x "+string(cut)+" > 255 0 ? ?").blur(1).bicubicresize(width,height)
}


Ovviamente, in mia piena tradizione, non è esattamente la cosa più veloce e "stabile" (a livello di cpu) che ci sia, ma rispetto a roba che ho tirato fuori in passato ho fatto dei passi da gigante!
Il risultato comunque, per quanto possa probabilmente avere ulteriori migliore, mi convince e soddisfa a sufficienza.
Sotto spoiler un'immagine di riferimento e il confronto tra maskdetail con settaggi di default ed edmask con settaggi di default:


Sicuramente potrete lamentarvi che usare maskdetail con settaggi default sia una mezza bastardata, per cui vi lascio di seguito un altro riferimento di alcuni settaggi a cui ero arrivato con scarsa soddisfazione tentando di farci qualcosa (forse a causa di incompetenza mia nell'adoperare maskdetail, anche, eh, non lo escluderei):
CODICE
maskdetail(1440,810,cutoff=40,gain=2.5,expandN=3)


Come vedete, siamo a livelli simili, ma leggermente inferiori, di affidabilità della maschera in quanto a dettagli rintracciati, ma con nettamente più falsi positivi e un look inevitabilmente "quadrettoso", come lo chiamavo più sopra.
L'unico contraltare di edmask è che, quando i falsi positivi riescono a sopravvivere a tutti i passaggi, si potrebbero portare appresso un'area potenzialmente più grossa nella maschera finale rispetto a maskdetail, ma soppesando pro e contro mi accontento così.

Spero che vi torni utile, ma siamo nel 2021 e il fansub è morto l'encoding nel fansub ha lasciato spazio al remux, quindi vabbè.
 
Web  Top
view post Posted on 19/1/2021, 21:12     +1   -1
Avatar

Bimbosp

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

Status:


Colpo di scena abbiamo già una v1.1!

Confrontandomi su Telegram col nostro Snobbino di quartiere, abbiamo convenuto che a conti fatti l'apporto di eedi per certi versi rasenta il placebo (ma bisognerebbe confrontare su più contenuti per verificare per bene).
Il grosso viene fatto comunque dal passaggio alla risoluzione bassa, che però qualcuno potrebbe voler customizzare.

Per non togliere del tutto la possibilità di avere eedi, per chi lo volesse usare comunque, e per aggiungere la possibilità di specificare la res bassa di riferimento, ecco una v1.1:
CODICE
#edmask v1.1 by mirkosp
#yet another detail mask function for high res elements overlayed on upscaled content
#in other words, masking those 1080 things on non-1080 chinese cartoons.
#first we do the usual: a difference and a removegrain for a first false positive cleanup step
#then we use eedi: actual detail is more likely to be close together and connected, not separated
#however, the first step often runs into false negatives and a straight line at 1080 will often have a few missing bits here and there
#by running eedi, we make sure that things that should be together (text lines and so on) actually get connected
#obviously, since our final result is a mask, we can pick speed over quality settings with little repercussions
#next, we try to clean up false negatives: by running a preliminary lut we cut away a few things, and leave at a 50:50 limbo things which might be details or not
#once we've done that, as actual 1080 details are more likely to be things visible at a distance and not a random dot in the middle of the screen, we do a massive downscale
#by doing this with another removegrain, we improve our odds of removing random false positive noise around the screen
#with a final blur before going back to the final res we ensure the mask is soft so the reversed upscale and the normal resize blend together well enough

function edmask (clip c, int width, int height, int "thrmax", int "thrmin", int "cut", int "wlow", bool "eedimode") {
thrmax=default(thrmax,128)
thrmin=default(thrmin,50)
cut=default(cut,40)
wlow=default(wlow,320)
eedimode=default(eedimode,false)
c
edmask=diffmask(last,debicubicy(width,height).bicubicresize(c.width,c.height)).removegrain(11)
qmask=edmask
edmask=overlay(edmask.eedi3(0,alpha=0.8,beta=0.1,gamma=100,u=false,v=false,ucubic=false,cost3=false,vcheck=0,mdis=5,nrad=1),edmask.eedi3(1,alpha=0.8,beta=0.1,gamma=100,u=false,v=false,ucubic=false,cost3=false,vcheck=0,mdis=5,nrad=1)).turnleft()
edmask=overlay(edmask.eedi3(0,alpha=0.8,beta=0.1,gamma=100,u=false,v=false,ucubic=false,cost3=false,vcheck=0,mdis=5,nrad=1),edmask.eedi3(1,alpha=0.8,beta=0.1,gamma=100,u=false,v=false,ucubic=false,cost3=false,vcheck=0,mdis=5,nrad=1)).turnright()
return eedimode ? edmask.mt_lut("x "+string(thrmax)+" > 255 x "+string(thrmin)+" > 128 0 ? ?").bicubicresize(wlow,muldiv(wlow,c.height,c.width)).removegrain(11).mt_lut("x "+string(cut)+" > 255 0 ? ?").blur(1).bicubicresize(width,height) : qmask.mt_lut("x "+string(thrmax)+" > 255 x "+string(thrmin)+" > 128 0 ? ?").bicubicresize(wlow,muldiv(wlow,c.height,c.width)).removegrain(11).mt_lut("x "+string(cut)+" > 255 0 ? ?").blur(1).bicubicresize(width,height)
}


Visto che eedi sembra essere quasi placebo, ho deciso di lasciarlo disattivato di default.
 
Web  Top
28 replies since 3/2/2013, 04:12   5530 views
  Share