Come utilizzare la premoltiplicazione durante la convoluzione dell'immagine per risolvere il problema dell'alpha bleed?

StackOverflow https://stackoverflow.com/questions/4854839

Domanda

sto cercando di applicare una sfocatura a riquadro a un'immagine trasparente e ottengo un "alone scuro" attorno ai bordi.

Jerry Huxtable ha una breve menzione del problema, e un'ottima dimostrazione che mostra il problema:

enter image description here

Ma io, per quanto mi riguarda, non riesco a capire come"alfa premoltiplicato"può risolvere il problema.Ora facciamo un esempio molto semplice.ho un'immagine 3x3, contenente un pixel rosso e uno verde:

enter image description here

In realtà i restanti pixel sono trasparenti:

enter image description here

Ora applicheremo una sfocatura box 3x3 all'immagine.Per semplicità, calcoleremo solo il nuovo valore del pixel centrale.Il modo in cui funziona una sfocatura del riquadro è che, poiché abbiamo un quadrato di 9 posizioni (3x3, chiamato kernel), prendiamo 1/9 di ciascun pixel nel kernel e lo sommiamo:

enter image description here

COSÌ

finalRed =   1/9 * red1 + 1/9 * red2 + 1/9 * red3+ ... + 1/9 * red9
finalGreen = 1/9*green1 + 1/9*green2 + 1/9*green3+ ... + 1/9*green9
finalBlue =  1/9* blue1 + 1/9* blue2 + 1/9* blue3+ ... + 1/9* blue9
finalAlpha = 1/9*alpha1 + 1/9*alpha2 + 1/9*alpha3+ ... + 1/9*alpha9

In questo esempio molto semplificato, i calcoli diventano molto semplici:

finalRed =   1/9 * 255
finalGreen = 1/9 * 255
finalBlue =  0
finalAlpha = 1/9*255 + 1/9*255

Questo mi dà un valore di colore finale di:

finalRed =   28
finalGreen = 28
finalBlue =  0
finalAlpha = 56 (22.2%)

enter image description here

Questo colore è troppo scuro.Quando eseguo una sfocatura Box 3px sulla stessa immagine 3x3 pixel in Photoshop, ottengo ciò che mi aspetto:

enter image description here

Che è più chiaro se visualizzato su bianco:

enter image description here


In realtà sto eseguendo una sfocatura del riquadro su una bitmap contenente testo trasparente e il testo ottiene l'oscurità rivelatrice attorno ai margini:

enter image description here

sto iniziando con una bitmap GDI+ in PixelFormat32bppARGB formato


Come posso utilizzare "alfa premoltiplicato" quando applico il kernel di convoluzione 3x3?

Qualsiasi risposta dovrà includere nuovi forumla, poiché:

final = 1/9*(pixel1+pixel2+pixel3...+pixel9)

Mi sta dando la risposta sbagliata.


Modificare: Un esempio più semplice è:

Eseguirò questi calcoli con valori di colore e alfa nell'intervallo 0..1:

enter image description here

applicherò il filtro di convoluzione della sfocatura del riquadro al pixel centrale:

ARGB'
      = 1/9 * (0,1,0,1) + 1/9 * (0,0,0,0) + 1/9 * (0,0,0,0) + 
        1/9 * (0,1,0,1) + 1/9 * (0,0,0,0) + 1/9 * (0,0,0,0) + 
        1/9 * (0,1,0,1) + 1/9 * (0,0,0,0) + 1/9 * (0,0,0,0);

      = (0, 0.11, 0, 0.11) + (0,0,0,0) + (0,0,0,0) +
        (0, 0.11, 0, 0.11) + (0,0,0,0) + (0,0,0,0) +
        (0, 0.11, 0, 0.11) + (0,0,0,0) + (0,0,0,0)

      = (0, 0.33, 0, 0.33)

Che dà un verde scuro abbastanza trasparente.

enter image description here

Il che non è quello che mi aspetto di vedere.E per fare un confronto, Box Blur di Photoshop è:

enter image description here

Se presumo (0, 0.33, 0, 0.33) è alfa premoltiplicato e demoltiplicandolo, ottengo:

(0, 1, 0, 0.33)

enter image description here

Il che sembra giusto per il mio esempio completamente opaco;ma non so cosa fare quando inizio a coinvolgere pixel parzialmente trasparenti.

Guarda anche

È stato utile?

Soluzione

tkerwin ha ha già fornito la risposta corretta, ma sembra che necessitino ulteriori spiegazioni.

I calcoli che hai mostrato nella tua domanda sono assolutamente corretti, fino alla fine.È lì che ti manca un passaggio: i risultati sono ancora in modalità alfa premoltiplicata e devono essere "non moltiplicati" nel formato PixelFormat32bppARGB.L'opposto di una moltiplicazione è una divisione, quindi:

finalRed = finalRed * 255 / finalAlpha;
finalGreen = finalGreen * 255 / finalAlpha;
finalBlue = finalBlue * 255 / finalAlpha;

Hai espresso la preoccupazione che il divario possa creare un risultato decisamente fuori portata, ma ciò non accadrà.Se segui i calcoli, noterai che i valori rosso, verde e blu non possono essere maggiori del valore alfa, a causa del passaggio di premoltiplicazione.Se stessi utilizzando un filtro più complicato di un semplice riquadro di sfocatura potrebbe essere una possibilità, ma sarebbe così anche se non stessi utilizzando alpha!La risposta corretta è bloccare il risultato, trasformando i numeri negativi in ​​0 e qualsiasi cosa maggiore di 255 in 255.

Altri suggerimenti

Seguendo i consigli nel tuo link, pre-multiplici prima di sfocarsi e non-multiplica dopo la sfocatura. Nel tuo esempio, il pre-multiplico in realtà non fa nulla, poiché non ci sono pixel semitrasparenti. Hai fatto la sfocatura, quindi hai bisogno di non pre-multiplica facendo (supponendo valori di colore normalizzati da 0 a 1):

RGB' = RGB/A  (if A is > 0)
A' = A

Questo ti darà un'immagine finale sfocata non multiplica.

Entrambe le risposte sembrano sbagliate qui.

Usa la modalità di fusione corretta, che secondo Porter Duff è:

FG.RGB + (1.0 - FG.Alpha)*BG.RGB

Non sono sicuro da dove provengano il resto delle risposte, ma wow.

La codifica alfa determina l'operazione eccessiva.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top