Generalmente il rilevamento dei bordi si riduce per rilevare aree dell'immagine con un valore di gradiente elevato.
Nel nostro caso possiamo vedere grossolanamente il gradiente come la derivata della funzione immagine, quindi l'ampiezza del gradiente ti dà informazioni su quanto la tua immagine cambia localmente (rispetto ai pixel / texel vicini).
Ora, come dici tu, un vantaggio è un'indicazione di discontinuità, quindi ora che abbiamo definito il gradiente è chiaro che questa informazione è tutto ciò di cui abbiamo bisogno. Una volta trovato il gradiente di un'immagine, è solo una questione di applicare una soglia per ottenere un valore binario edge / non-edge.
Come trovi questo gradiente è davvero quello che stai chiedendo e devo ancora rispondere :)
Molti modi! Qui un paio :)
Funzioni shader integrate
Sia hlsl che glsl offrono funzioni derivate. In GLSL hai dFdx e dFdy che ti danno rispettivamente informazioni sul gradiente in direzione xey. In genere queste funzioni vengono valutate in un blocco di frammenti 2x2.
A meno che tu non sia interessato in una sola direzione, un buon modo per ottenere un risultato compatto che indica quanto è forte il gradiente nella regione è la larghezza che non ti dà nient'altro che la somma del valore assoluto di dFdy e dFdy.
È probabile che tu sia interessato a un bordo dell'immagine complessiva piuttosto che a un canale specifico, quindi potresti voler trasformare la tua funzione immagine in luminanza. Con questo in mente, quando si tratta di rilevamento dei bordi il tuo shader potrebbe includere qualcosa di simile a:
float luminance = dot(yourFinalColour,vec3(0.2126, 0.7152, 0.0722));
float gradient = fwidth(luminance );
float isEdge = gradient > threshold;
Con una soglia alta troverai bordi più grossolani e potresti perdere alcuni, al contrario, con una soglia bassa potresti rilevare bordi falsi. Devi sperimentare per trovare la soglia più adatta alle tue esigenze.
Vale la pena menzionare il motivo per cui queste funzioni funzionano, ma non ho tempo per farlo ora, probabilmente aggiornerò questa risposta in seguito :)
Post-elaborazione dello spazio dello schermo
Potresti diventare più fantasioso di così, ora il campo del rilevamento dei bordi nell'elaborazione delle immagini è immenso. Potrei citarti decine di buoni modi per rilevare il rilevamento dei bordi in base alle tue esigenze, ma manteniamolo semplice per ora, se sei interessato posso citarti più opzioni!
Quindi l'idea sarebbe simile a quella sopra, con la differenza che potresti guardare in un quartiere più ampio e usare una serie di pesi su campioni circostanti se vuoi. In genere, esegui una convoluzione sull'immagine con un kernel che ti dà come risultato una buona informazione sul gradiente.
Una scelta molto comune è il kernel Sobel
Che ti danno rispettivamente gradienti nelle direzioni xey:
G r a dIo E n t Mun' gn i t u de = ( G r a dIo E n tX)2+ ( G r a dIo E n ty)2-----------------------√
Quindi puoi eseguire la soglia come ho menzionato sopra.
Questo kernel, come puoi vedere, dà più peso al pixel centrale, in modo efficace sta calcolando il gradiente + un po 'di levigatura che aiuta tradizionalmente (spesso l'immagine è sfocata gaussiana per eliminare i piccoli bordi).
Quanto sopra funziona abbastanza bene, ma se non ti piace il livellamento puoi usare i kernel Prewitt:
(Nota che sono di fretta, scriverò presto il testo formattato corretto invece delle immagini!)
In realtà ci sono molti più kernel e tecniche per trovare il rilevamento dei bordi in un modo di elaborazione delle immagini piuttosto che in grafica in tempo reale, quindi ho escluso metodi più contorti (gioco di parole non inteso) come probabilmente staresti bene con le funzioni dFdx / y .