Alpha-Composing

Luk10

Top Contributor
Grüße,

Ich habe die Aufgabe bzw. das Ziele eine Methode
Code:
int composeColors(int color1, int color2)
zu schreiben. Sie soll die beiden Farben [RGB] (int-Werte mit 8 Bits für den Alpha-Wert) "aufeinander legen", also die beiden Farben kombinieren.

Es soll dabei nicht die Klasse Color verwendet werden, sondern das wirklich neu geschrieben werden.
Meine Frage bezieht sich jetzt erstmal auf die Regeln nach welchen die einzelnen Farb-Kanäle verrechnet werden um den Resultat RGB Farbwert zu bekommen.

Beispiel:
Was passiert wenn ich einen [G = 200; Alpha = 150] und [G = 20; Alpha = 70] zusammenstellen will.

Durch ausprobieren (in PS5) konnte ich nur feststellen, dass die Reihenfolge der beiden egal ist.

Ist (noch) nicht wirklich Java-related, aber ich weiß nicht wo ich das sonst fragen sollte.

-Luk10-
 

Atze

Top Contributor
wird das nicht einfach aufeinandergerechnet? bei 8 bit hast du doch werte von 0 - 256.

G = 200; Alpha = 150 + G = 20; Alpha = 70

wären dann doch

G = 220; Alpha = 220

?

da beide die gleichen werte ergeben, ist die reihenfolge wohl egal :)
 

Luk10

Top Contributor
Danke schonmal für den Wikipedia-Link!

Ich denke der "Standard" ist B over A, wenn ich mich nicht täusche. Hab jetzt auch durch ausprobieren feststellen können, dass es einen Unterschied macht, ob ich A over B oder B over A habe.

Nach welcher Regel werden denn die Farben bei B over A berechnet? Wikipedia sagt nichts dazu?

[EDIT]Kleines Beispiel angehängt![/EDIT]

alpha-10.png


Absolut Unverständlich wie die Farben da berechnet werden ...
 
Zuletzt bearbeitet:

Luk10

Top Contributor
So die Berechnungsregeln sind jetzt einigermaßen klar. Habe aber noch eine Frage bezüglich der einzelnen Kanäle aus dem 32-Bit Integer:

So habe ich mir das vorgestellt:

Java:
int rgb = meinBeispielARGB;
	
    int alpha = (rgb >>> 24);
	int red = ((rgb << 8) >>> 24);
	int green = ((rgb << 16) >>> 24);
	int blue = ((rgb << 24) >>> 24);

Sollte mir dann den RGB-Wert zwischen 0 und 255 geben ... glaub aber, dass da was nicht so ganz funktioniert weil ich beim testen seltsame Ergebnisse (Konsolenausgabe) bekomme.

Dann mir jemand sagen was da nicht stimmt?
 

Marco13

Top Contributor
Sowas wie
int alpha = (rgb >>> 24);
int red = (rgb >>> 16) & 0xFF;
int green = (rgb >>> 8) & 0xFF;
int blue = (rgb >>> 0) & 0xFF;
sollt's tun
 

Luk10

Top Contributor
So hab jetzt beides testen können und sowohl

Java:
int rgb = meinBeispielARGB;
    
int alpha = (rgb >>> 24);
int red = ((rgb << 8) >>> 24);
int green = ((rgb << 16) >>> 24);
int blue = ((rgb << 24) >>> 24);

als auch

Java:
int rgb = meinBeispielARGB;

int alpha = (rgb >>> 24);
int red = (rgb >>> 16) & 0xFF;
int green = (rgb >>> 8) & 0xFF;
int blue = (rgb >>> 0) & 0xFF;

funktioniert.

Ich muss jetzt diese Werte auf RGBA-Werte zwischen 0 und 1 runterrechnen.
Also hätte ich
Code:
(Wert / Maximum) = (rgb / 255)
gerechnet.

Aber in PS wird ein Wert von 128 und nicht 127.5 als "50%" gewertet ... das ist irgendwie seltsam. Eigentlich hat ja ein Byte auch einen Wertebrech von 256 ... aber die 0 muss halt beachtet werden.

Was ist da jetzt richtig? Wie rechne ich das vernünftig um?

Danke,
-Luk10-
 

Luk10

Top Contributor
Naja ich weiß nicht wie das Sinn machen soll:

100% = 1.0 = 255
50% = 0.5 = (255 / 2) = 127.5 und nicht 128
0% = 0.0 = 0
 
S

Spacerat

Gast
Ob nun 127 oder 128 als 50% interpretiert wird ist anwendungsabhängig, da gibt's afaik kein Gesetz für (ausser vllt. "ab 0.5 wird aufgerundet").
Beim Alpha-Compositig wird zunächst erstmal eine Ausgangsfarbe (Hintergrundfarbe) ohne Transparenz benötigt - irgend eine Farbe muss so ein Punkt ja bekommen. Nun darfst du aber nicht rgb durch 255 teilen, sondern musst jeweils [c]r / 255.0[/c], [c]b / 255.0[/c], [c]b / 255.0[/c] und [c]a / 255.0[/c] teilen und zwar r, g und b von Bild 1 und a von Bild 2. Nun rechnest du:
Code:
rb = r * a
gb = g * a
bb = b * a
rb, gb und bb ergeben nun die ausmultiplizierten Farbwerte welche ebenfalls zwischen 0 und 1 liegen.
EDIT hier einfügen XD
Diese Werte müssen nun wieder mit 255 multipliziert werden und in ein int gewandelt werden.
Das ist aber nur eine Art des Wandelns (Grundlage). Für's Compositing gibt's noch viel mehr - ONE_MINUS_SRC_ALPHA, ONE_MINUS_DST_ALPHA usw, das hat aber nur damit etwas zu tun, welches Bild über den jeweils anderen liegen soll.
[EDIT]Ok, vergessen... die resultierenden Werte... :oops:
Code:
rn = (rs + rd) / 2
gn = (gs + gd) / 2
bn = (bs + bd) / 2
xn = Wert Neu, xs = Wert Quelle und xd = Wert Ziel. Dann xn statt xb wandeln. Eigentlich kommen hier erst die Compositing-Methoden zum Tragen. ;)[/EDIT]
 
Zuletzt bearbeitet von einem Moderator:

Luk10

Top Contributor
Ja mir ist bewusst, dass ich nicht den rgb "int" durch 255.0 teilen darf ... hab ich wohl missverständlich geschrieben.

Also rundet man das dann einfach ... gut.
 

Luk10

Top Contributor
So, jetzt denke ich passt das hier die Methode so far:

Was jetzt noch fehlt ist das"Zusammensetzten" der einzelnen ARGB-Werte zu einem RGB-Rückgabewert ...

Dazu müsste ich irgendwie gezielt die Bits in einem Int setzten ...

-Luk10-

[EDIT]
Java:
    private int computeColor(int oldIn, int newIn) {

	// newIn over oldIn
	int result = 0;

	// {Red, Green, Blue, Alpha}
	int[] oldRgb = { (oldIn >>> 16) & 0xff, (oldIn >>> 8) & 0xff, (oldIn >>> 0) & 0xff, (oldIn >>> 24) };
	int[] newRgb = { (newIn >>> 16) & 0xff, (newIn >>> 8) & 0xff, (newIn >>> 0) & 0xff, (newIn >>> 24) };
	int[] resultRgb = { -1, -1, -1, -1 };

	// Values between 0.0 and 1.0
	double[] resultArgb = { -1, -1, -1, -1 };

	resultArgb[3] = (newRgb[3] / 255.0) + (1 - (newRgb[3] / 255.0)) * (oldRgb[3] / 255.0);
	resultRgb[3] = (int) Math.round(resultArgb[3] * 255.0);
	result = (result | resultRgb[3]) << 8;

	for (int i = 0; i < 3; i++) {

	    resultArgb[i] = (1.0 / resultArgb[3]) * ((newRgb[3] / 255.0) * (newRgb[i] / 255.0) + (1 - (newRgb[3] / 255.0)) * (oldRgb[3] / 255.0) * (oldRgb[i] / 255.0));
	    resultRgb[i] = (int) Math.round(resultArgb[i] * 255.0);

	    result = (result | resultRgb[i]);
	    if (i < 2) result = result << 8;

	}

	return result;

    }

Getest und funktioniert. Ich denke man könnte es auch ohne das int[] resultRgb machen, aber bin mir nicht sicher und ich denke das wird dann noch unübersichtlicher[/EDIT]
 
Zuletzt bearbeitet:
S

Spacerat

Gast
Irgendwo einfügen (z.B. Zeile 2):
[JAVA=2]int rc = 0, int c = 0;[/code]
ab Zeile 16 einfügen:
[JAVA=16]c = (int) (resultArgb * 255.0);
rc <<= 8;
rc |= c;[/code]
und zum Schluss:
Java:
return rc;
Und natürlich den Rückgabewert der Methode von void nach int setzen.
[EDIT]Im übrigen... kann es sein, dass du, so wie du es machst, die Alphawerte doppelt hinzumultiplizierst? Deine Berechnungen sehen ein wenig seltsam aus.[/EDIT]
 
Zuletzt bearbeitet von einem Moderator:

Ähnliche Java Themen

Neue Themen


Oben