PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Farbe mit Alphakanal/Hintergrund mischen



Jaecko
12.09.2010, 11:44
Moin.

Bei einem Projekt lass ich von einem AVR Bitmaps auf einem Farb-LCD anzeigen. Klappt soweit auch ganz gut.

Das Format der Bitmaps ist ein eigenes relativ einfaches ARGB-Format, d.h. je ein 4-Byte-Block für Alpha, Rot, Grün, Blau.

Für "transparente" Bereiche (Hintergrund soll durchscheinen), verwend ich ein einfaches Chromakey-Verfahren, d.h. z.B. die Farbe Magenta kommt im Icon nicht vor; alle Pixel in dieser Farbe werden einfach nicht dargestellt (Hintergrund bleibt erhalten)

Nun gibts jedoch auch Icons, bei denen ein Pixel am Rand halbtransparent ist, d.h. der Hintergrund UND die jeweilige Pixelfarbe sollen gemischt werden; der Alphakanal muss also ausgewertet werden.
(Je kleiner Alpha, um so mehr transparent ist das jeweilige Pixel)

Nun die Frage: Wie mischt man hier (mathematisch) am besten, wenn die folgenden Dinge bekannt sind:
- RGB-Wert Hintergrund
- RGB-Wert darzustellendes Pixel
- Alpha-Wert darzustellendes Pixel

Ein einfacher Mittelwert wirds ja vermutlich nicht sein.
Ebenso glaub ich nicht, dass es was wie R(neu) = R(background) + (alpha/255 * R(foreground)) ist.

mfG

Felix G
12.09.2010, 12:13
Also ich denke eine gewichtete Mittelung sollte da eigentlich ein sinnvolles Ergebnis liefern...

Allerdings ist deine Variante unvollständig, da auch der Hintergrund nicht so bleiben kann wie er ist, sondern mit 255 - A multipliziert werden muss.

Also nicht R = R1 + (A * R2), sondern eher R = ((1 - A) * R1) + (A * R2)

(ich gehe hier von einem Wertebereich zwischen 0 und 1 aus, damit es übersichtlich bleibt, bei der Implementierung muss man natürlich 255-A nehmen, und durch 255 dividieren)

Jaecko
12.09.2010, 12:37
Hm, stimmt, der Hintergrund muss ja auch noch dazu.
Aber sieht sinnvoll aus, thx.

Pro Pixel 2 Divisionen, wird das Teil ganz schön ausbremsen.
Evtl. ist der Fehler bei ner Division durch 256 vernachlässigbar, dann shift ich da einfach 8 nach rechts.

Felix G
12.09.2010, 12:54
Würde ich auch so machen, vor allem weil der Compiler das noch weiter optimieren kann (der rechnet einfach direkt mit dem Register weiter das die oberen 8 Bit enthält).


Außerdem braucht man prinzipiell nur eine Division, wenn man das ganze folgendermaßen ausrechnet:

R = (((255 - A) * R1) + (A * R2)) / 256

würde man es nämlich so machen: (A / 256) * R2 müsste man ja sogar mit Floats arbeiten, da ist es doch erheblich performanter de Division erst als letzten Schritt durchzuführen (und eben zusätzlich durch einen Shift zu ersetzen)

Jaecko
12.09.2010, 14:18
Perfekt, haut wunderbar hin.
Der Code bläht sich beim Dividieren um gut 1,4kB gegenüber dem Shift auf.
Macht man eine Fallunterscheidung (da ja bei Alpha = 0 und 255 nichts gerechnet werden muss), gibts zwischen Divison und Shift keinen subjektiv erkennbaren zeitlichen Unterschied mehr.

Der Farbfehler ist ebenso nicht zu erkennen. Mir fällt da grad ein, dass die unteren Bits, die diesen Fehler verursachen würden, bei der Konversion von 24-Bit RGB ins 16-Bit 565-Format fürs LCD sowieso verloren gehen.