24bit -> 8bit Grafik

HolgerX

Mitglied
Wie kann ich in (Visual) c++ aus einer 24bit Bitmap eine 8bit Bitmap kreiieren?

D.h. ich lade eine 24bit Bitmap aus einer Datei, will sie dann aber nur mit 256 Farben anzeigen, bzw. als 8bit Bitmap weiterverarbeiten.
 
Da wird es knifflig.

Das grosse Problem ist die 256 Farben festzulegen, auf die die Bitmap gemappt werden soll.

1) Wenn du eine vorgefertigte Palette hast, ist das einfach: Für jedes Pixel den Eintrag suchen, der am nächsten liegt.

2) Die andere Methode ist die Palette selbst aus den benutzten Farben zusammenrechnen. Die logischste Methode braucht eine FETTE Tabelle (256x256x256 = 16 MB), fällt also vernunftbedingt flach. Hier wird oft zu einer Methode gegriffen, die wie eine std::map mit drei Indizes funktioniert; also nur benötigte Indizes werden tatsächlich angelegt. In diesen Farb-Kubus (Rot x Grün x Blau) werden alle Pixel eingesetzt (mit Zähler). Aus allen eingetragenen Farben nimmt man die 256 gewichtsstärksten Einträge, die den grössten Abstand voneinander haben, damit man alle möglichen Farbabstufungen abdeckt. Jetzt ist die Palette fertig, weiter geht's bei Punkt 1.

Ich habe mich wahrscheinlich bei der Erklärung des Farbkubus böse verdackelt, aber so ähnlich läuft das, google nach "Quantization Cube". Alles in allem eine happige, prozessorintensive Angelegenheit.
 
Also das geht sicher auch mit viel geringerem Speicheraufwand:
256 Farben stehen für die Farbtabelle zur Verfügung, dann braucht man nur jedem Index die 3 bytes zuordnen, die es benötigt eine Farbe vollständig zu beschreiben, das sind imho nicht mal ein kilobyte (768bytes). Die Tabelle erstellt man anhand der Häufigkeit der Farben (also einfach sortiert), wie man sie im Bildchen findet und nähert die Farben, die nicht genau passen und für die kein Platz mehr ist an.
(Oder hast du das in deiner anderen Erklärung gemeint Endurion? Dann sorry... :))
 
Jaaaaa...., aber welche 256 Farben bekommen den Vorrang?

Man berücksichtige einen 255-farbigen Rot-Verlauf und ein Weiss. Das Weiss darf da nicht unter den Tisch fallen, nur weil Rot vorherrscht.

Dieses Farben richtig sortieren ist das grosse Problem. Man bekommt recht schnell was hin, was mit 60% der Bilder funktioniert (hatte ich früher auch schon gemacht), aber bei den anderen Bildern werden Farben grau oder ganz durch eine andere ersetzt. Sobald man die Ziel-Palette beisammen hat, ist es ja nur stures Vergleichen-Ersetzen.
 
Meine Idee: Zuerst ermittele ich die häufigsten Farben (also komplett RGB), die finden schon ihren Weg in die Tabelle. Dann ordne ich Gruppen bestimmter Größe und ähnlicher Farbwerte und ein gemeinsames RGB-Schema zu, so treffen sich die Pixel sozusagen in der Mitte. Als Hilfe könnte man eine einfach Bitmap anlegen (ich meine Bit-Map wörtlich :)), in der festgehalten wird, welche Pixel bereits zugeordnet sind. Man kann auch gut ausrechnen, wie groß die Pixelgruppen sein müssen (hat ja die Ausmaße des Bildes und die 256 Farbenvorgabe). Ist nur ne Idee, hab's selbst noch nie gemacht.
 
Die logischste Methode braucht eine FETTE Tabelle (256x256x256 = 16 MB), fällt also vernunftbedingt flach.
Ich widerspreche da mal einfach. Unter gewissen Umständen ist es sicherlich sehr vernünftig, diese 16 MB Speicher ganz einfach zur Verfügung zu stellen. Bei heutigen Rechnern sollte das nicht allzu schmerzhaft sein, und in einer Umgebung wie z.B. Photoshop, wo Dokumente ohnehin innerhalb des Speichers häufig 10 bis 100 MB gross sind, ist das nicht einmal grössenwahnsinnig. Wenn es die Implementierung vereinfacht und funktioniert , sollte man es tun und später nach Bedarf optimieren. Geschickterweise baut man es so ein, dass der Wechsel zu einer optimierten Methode nicht Umbau der gesamten Anwendung erfordert.

Endurion, meintest du bei deiner Erwähnung der std::map eventuell Sparse Arrays? Das ist durchaus möglich, bringt aber hier wegen der drei Dimensionen einige Probleme, wenn man nachher versucht, die Nachbarschaftsbeziehungen zu analysieren (um zum Beispiel die geeignetste, nächste Farbe zu finden). Günstiger ist da der Ansatz, entweder tatsächlich den Speicher zur Verfügung zu stellen (s.o.), oder zwei Strategien zu koppeln, beispielsweise einen 8x8x8-Würfel, der den gesamten Farbraum umfasst, und darin nach Bedarf genauer zu unterscheiden. Octrees wären sicher auch eine sehr gute Idee, aber damit habe ich mich praktisch leider noch nicht beschäftigt.
 
Nuja, es kommt auf die Anwendung drauf an. Bei einem Spiel, das mal eben so 16 MB für eine poplige Grafikumwandlung verputzt, ist das nicht wirklich tragbar.

Bei einem Zeichenprogramm oder sowas geht das ja eigentlich.

Ich habe mich vor langer langer Zeit mal für ein eigenes Zeichenprogramm damit beschäftigt und bin auf einen Quantisierungs-Cube gestossen. Der beinhaltet so eine Art "Sparse Array" (ja, das habe ich gemeint) und reduziert dann die Einträge, bis die gewünschte Anzahl übrig bleibt. Klappt auch einwandfrei.
 
Zurück