Mittelwert verschiedener Uint32 Variablen bilden
-
Da SDL_gfx momentan noch nicht bei mir läuft und auch einfach so zum basteln habe ich ein AntiAliasing in SDL programmiert. Meine Frage hat aber nichts mit SDL zu tun.
Funktionsweise:
Ich lese die RGBA Daten von vier aneinander liegenden Pixeln aus. z.B. Pixel 1 = 0xFF00FF00. Immer zwei Zeichen stehen für eine Information, also FF = Rotanteil, ... bis 00 = Alphawert.
Nun will ich diese vier Pixel auf einen Pixel legen und muss dazu ja diese vier Uint32 "mischen", also ihren Mittelwert bilden.Das habe ich folgendermaßen versucht (wahrscheinlich greift ihr euch jetzt an den Kopf, aber ich weiß es nicht besser):
farbeDesNeuenPixels = (farbe1 + farbe2 + farbe3 + farbe4) / 4;Das funktioniert nicht
. Aus 4 Weißen Pixeln wurde ein türkiser Pixel.Dann habe ich hier im Forum eine Möglichkeit gefunden, die lange Uint32 in 4 Uint8 mit den einzelnen Daten zu zerlegen:
rot1 = farbe1 & 0xff; gruen1 = (farbe1 >> 8) & 0xff; blau1 = (farbe1 >> 16) & 0xff; alpha1 = (farbe1 >> 24) & 0xff;Was exakt das 0xff darin bewirkt, weiß ich nicht, es sorgt irgendwie dafür, dass egal auf welchem Computer die Uint32 immer von vorne gelesen wird. Ka, wie.
Dann habe ich versucht, die Farben folgendermaßen zu mischen (hier nur ein Ausschnitt):
Zwischenfarbe1 = SDL_MapRGB(arbeitsflaeche->format, (rot1+rot2)/2, (gruen1+gruen2)/2, (blau1+blau2)/2);
Aber dann erscheint gar nichts, oder eventuell schwarze oder transparente Pixel auf dem Bildschirm. Im Grunde mache ich ja auch den selben Fehler wie am Anfang, dass ich die Integer addiere und durch ihre Anzahl teile. Aber wie stelle ich denn den Mittelwert zweier Uint32 oder 8 fest?
So solls eigentlich sein:
Uint32 Farbe1 = 0xFFCC66FF; Uint32 Farbe2 = 0xDDEE88BB; //Irgendwas Uint32 Mischfarbe = 0xEEDD77DD;Ich denke, für die Leute, die C++ richtig können, ist das wahrscheinlich eine leichte Aufgabe. Aber für mich ist das echt schwer, weil ich einfach nicht weiß, wie das gehen soll. Genauso wenig, wie ich weiß, wie ich die Uint8 wieder zu einer Uint32 zusammenhänge. Ich hoffe jemand kann mir das erklären.
-
Wenn du mehrere Integers addierst, kann es sein, dass du einen Überlauf kriegst. Deshalb solltest du mindestens einen Operanden vorher in einen grösseren Typen casten. Oder du führst zuerst die Division und dann die Addition durch.
-
Fällt mir gerade so ein: Bei zwei Zahlen kann man auch
Mittelwert(A,B) = (A+B)/2 = A - (A - B)/2benutzen. Das ist zwar eine Adddition mehr, aber dafür spart man sich die eventuell Zeitraubende Verwendung eines größeren Types.
edit: Das kann man bestimmt auch verallgemeinern, aber ich habe gerade keine Lust zu rechnen, das Wetter ist so schlecht.
-
SeppJ, deine Idee ist an sich nicht schlecht, nur musst du bedenken, dass
A - Bunter Umständen zu einem Unterlauf führt. Nicht viel besser als ein Überlauf.
Von daher würde ich eher zu einem Cast raten (
intstattcharsollte für die temporäre Aktion wohl drinliegen, ist wahrscheinlich auch am schnellsten). Mir fällt gerade ein, zuerst dividieren ist auch nicht gut, da man dadurch Informationen verliert.
-
Meinst du so etwas:
Uint32 Farbe1; Uint32 Farbe2; int Zwischenspeicher = Farbe1; Uint32 Mischfarbe = (Zwischenspeicher + Farbe2)/2;Funktioniert das?
-
Uint32 entspricht doch normalerweise einem unsigned int. So gesehen macht das hier keinen Sinn int als Zwischenvariable zu nehmen.
Hier ist es wirklich sinnvoll vorher zu dividieren. Etwa so:Uint32 Farbe1; Uint32 Farbe2; Uint32 Mischfarbe = Farbe1 / 2.0 + Farbe2 / 2.0;
-
Du willst doch den Durchschnitt der 8-Bit-Einzelfarben, und nicht des 32-Bit-Farbtyps, oder? Wieso dann nicht
Uint8 r1,g1,b1,a1; // deine 8-Bit-Werte der ersten Farbe Uint8 r2,g2,b2,a2; // die der zweiten Farbe // Misch-Einzelfarben in grösseren Typen (16 Bit reicht für Addition) Uint16 rm = (r1 + r2) / 2; Uint16 gm = (g1 + g2) / 2; // analog b, aDu musst ja nicht so viele Variablen anlegen, ich hab das hier der Einfachheit halber gemacht. Statt des
Uint16könntest du einfach in einem Ausdruck casten, das hier war nur zur Verdeutlichung. Du kannst das auch auf 4 Farben ausdehnen.
-
Aber wie bekomme ich die Uint16 dann wieder in eine Uint8 und die 4 RGBA Uint8 zu einer Uint32?
-
Little Programmer schrieb:
Aber wie bekomme ich die Uint16 dann wieder in eine Uint8
Durch einen ganz normalen Cast. Der zusätzliche Platz wird ja nur temporär gebraucht.
Little Programmer schrieb:
und die 4 RGBA Uint8 zu einer Uint32?
Zum Beispiel durch Bitshifts.
-
Nexus schrieb:
SeppJ, deine Idee ist an sich nicht schlecht, nur musst du bedenken, dass
A - Bunter Umständen zu einem Unterlauf führt. Nicht viel besser als ein Überlauf.
einfach die groessere zahl als 'A' nehmen:
if(A > B) return A - (A-B)/2; else return B - (B-A)/2;mit mehr als zwei Zahlen ist diese Methode allerdings nicht mehr so gut, wegen zu grossem overhead.
-
Und vor allem, da es hier um Pixel geht. Ich suche nach einer allgeminen Lösung für das Problem, aber z.B. schon das erste Programm, indem ich es anwenden will, zeichnet nur weiße Pixel auf schwarzen Hintergrund. Das bedeutet, alle schwarzen und alle weißen Pixel haben exakt die selben Werte. Auch bei anderen Programmen ist es mehr als wahrscheinlich, dass sich zwei nebeneinander liegende Pixel einen Farbwert teilen. Dann bräcuhe ich zwei ineinander verschachtelte If-Abfragen. Das ganze ist jetzt schon viel zu langsam, da es ja pixelweise den ganzen Bildschirm abtastet. Ich glaube mit den If-Abfragen reduziert sich das ganze dann auf ein neues Gesamtbild alle paar Sekunden.
Mit Bitshifts kenne ich mich zwar nciht aus, aber ich werd mich mal darüber schlau machen. Ich glaub' dieses Variablenumformungen sind die beste Idee.
Danke euch allen.