000
23.01.2018, 21:26 Uhr
Yadgar
|
Hi(gh)!
Seit Monaten rechne ich meine selbst gerenderten oder per Digitalkamera gefilmten Videos in Atari ST-Monochrome-Modus (zunächst einmal nur in visueller Hinsicht, die Konvertierung in ein vom Atari ST lesbares Datenformat erfolgt später) um, und zwar ohne und mit Floyd-Steinberg-Rasterung. Die Routine für diese Rasterung habe ich gemäß der englischsprachigen Wikipedia-Seite zum Stichwort "Floyd-Steinberg dithering" implementiert, hier der Funktions-Code:
C++: |
void floydsteinberg(vector<vector<pixel> > &img, vector<rgb> &pal) // Funktion bekommt Referenzen auf gesamtes Bild und verwendete Farbpalette übergeben { unsigned short h = img.size(); // Bildhöhe unsigned short w = img[0].size(); // Bildbreite unsigned short r, c, i; // Bildzeile, Bildspalte, Zähler unsigned short p = pal.size(); // Anzahl der Farben in der verwendeten Palette rgb t0, t1, t2, t3, t4, closest=pal.at(0); // Aktuelles Pixel und rechts, links unten, unten und rechts unten angrenzende Pixel rgb triple, dist; // Puffer-Objekt für Pixel, Farbabstands-Tripel (im RGB-Farbraum) float newred, newgreen, newblue; // neue Farbwerte nach Fehlerdiffusion for (r=0; r<h; r++) { for (c=0; c<w; c++) { t0 = {-1, -1, -1}; // = triple t1 = {-1, -1, -1}; t2 = {-1, -1, -1}; t3 = {-1, -1, -1}; t4 = {-1, -1, -1}; t0.red = img[r].at(c).get_red(); t0.green = img[r].at(c).get_green(); t0.blue = img[r].at(c).get_blue(); if (c < w-1) // falls Zeilenende noch nicht erreicht { t1.red = img[r].at(c+1).get_red(); t1.green = img[r].at(c+1).get_green(); t1.blue = img[r].at(c+1).get_blue(); } if (c > 0 && r < h-1) // falls Pixel weder am linken noch am unteren Bildrand { t2.red = img[r+1].at(c-1).get_red(); t2.green = img[r+1].at(c-1).get_green(); t2.blue = img[r+1].at(c-1).get_blue(); } if (r < h-1 ) // falls Pixel nicht am unteren Bildrand { t3.red = img[r+1].at(c).get_red(); t3.green = img[r+1].at(c).get_green(); t3.blue = img[r+1].at(c).get_blue(); } if (c < w-1 && r < h-1 ) // falls Pixel weder am rechten noch am unteren Bildrand { t4.red = img[r+1].at(c+1).get_red(); t4.green = img[r+1].at(c+1).get_green(); t4.blue = img[r+1].at(c+1).get_blue(); } for (i=0; i<p; i++) { if (coldist(t0, pal.at(i)) < coldist(t0, closest)) closest = pal.at(i); } img[r].at(c).set_all(closest.red, closest.green, closest.blue); dist.red = t0.red - closest.red; dist.green = t0.green - closest.green; dist.blue = t0.blue - closest.blue; if (t1.red > -1) { img[r].at(c+1).get_all(triple); newred = triple.red + dist.red*0.4375; newgreen = triple.green + dist.green*0.4375; newblue = triple.blue + dist.blue*0.4375; img[r].at(c+1).set_all(mround(newred), mround(newgreen), mround(newblue)); } if (t2.red > -1) { img[r+1].at(c-1).get_all(triple); newred = triple.red + dist.red*0.1875; newgreen = triple.green + dist.green*0.1875; newblue = triple.blue + dist.blue*0.1875; img[r+1].at(c-1).set_all(mround(newred), mround(newgreen), mround(newblue)); } if (t3.red > -1) { img[r+1].at(c).get_all(triple); newred = triple.red + dist.red*0.3125; newgreen = triple.green + dist.green*0.3125; newblue = triple.blue + dist.blue*0.3125; img[r+1].at(c).set_all(mround(newred), mround(newgreen), mround(newblue)); } if (t4.red > -1) { img[r+1].at(c+1).get_all(triple); newred = triple.red + dist.red*0.0625; newgreen = triple.green + dist.green*0.0625; newblue = triple.blue + dist.blue*0.0625; img[r+1].at(c+1).set_all(mround(newred), mround(newgreen), mround(newblue)); } } } }
|
Zur Sicherheit auch noch die Rundungs-Routine mround():
C++: |
int mround(double cv) { int c; if (cv-floor(cv) < 0.5) c = floor(cv); else c = ceil(cv); return c; }
|
Konkret kam es beim Umrechnen dieses Videos in Monochrom-Floyd-Steinberg und Atari ST-Auflösung (hier 533 x 400 Pixel) immer beim Überfliegen von Meeren oder größeren Binnenseen (normalerweise dunkelblau) zu vom Horizont "herunterlappenden" heller gerasterten Bereichen, die es dort den Originalfarben nach nicht geben dürfte:
Das Originalbild als PNG (mein in der Entwicklung befindliches Konsolen-Bildbearbeitungsprogramm "yip" kann nur unkomprimierte TGAs verarbeiten, daher hier noch der Link auf die TGA-Version)
Ist die Dokumentation des Floyd-Steinberg-Algorithmus in der Wikipedia unvollständig - oder habe ich beim Programmieren etwas übersehen?
Bis bald im Khyberspace!
Yadgar -- Flagmaker - ein Programmier-Blog Dieser Post wurde am 23.01.2018 um 22:17 Uhr von Yadgar editiert. |