000
11.02.2017, 02:55 Uhr
Yadgar
|
Hi(gh)!
Mittlerweile habe ich es tatsächlich geschafft, im Rahmen meines Kommandozeilen-Bildbearbeitungsprogramms "YIP" (Yadgar's Image Processor - ImageMagick für Arme...) so etwas wie Floyd-Steinberg-Rasterung zu programmieren, nach dem Artikel "Floyd-Steinberg" in der englischen Wikipedia... in Pseudocode wird der Algorithmus dort so dargestellt:
Code: |
for each y from top to bottom for each x from left to right oldpixel := pixel[x][y] newpixel := find_closest_palette_color(oldpixel) pixel[x][y] := newpixel quant_error := oldpixel - newpixel pixel[x + 1][y ] := pixel[x + 1][y ] + quant_error * 7 / 16 pixel[x - 1][y + 1] := pixel[x - 1][y + 1] + quant_error * 3 / 16 pixel[x ][y + 1] := pixel[x ][y + 1] + quant_error * 5 / 16 pixel[x + 1][y + 1] := pixel[x + 1][y + 1] + quant_error * 1 / 16
|
Bei mir in C++ sieht das so aus:
C++: |
void floydsteinberg(vector<vector<pixel> > &img, vector<rgb> &pal) { unsigned short h = img.size(); unsigned short w = img[0].size(); unsigned short r, c, i; unsigned short p = pal.size(); rgb t0, t1, t2, t3, t4, closest=pal.at(0); rgb triple, dist; float newred, newgreen, newblue; for (r=0; r<h; r++) { for (c=0; c<w; c++) { img[r].at(c).get_all(triple); t0 = triple; t1 = {-1, -1, -1}; t2 = {-1, -1, -1}; t3 = {-1, -1, -1}; t4 = {-1, -1, -1}; if (c < w-1) { img[r].at(c+1).get_all(triple); t1 = triple; } if (c > 0 && r < h-1) { img[r+1].at(c-1).get_all(triple); t2 = triple; } if (r < h-1 ) { img[r+1].at(c).get_all(triple); t3 = triple; } if (c < w-1 && r < h-1 ) { img[r+1].at(c+1).get_all(triple); t4 = triple; } 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)); } } }
cout << "Floyd-Steinberg-Rasterung wird berechnet!" << endl; }
|
"pixel" ist eine selbst entwickelte Klasse, "rgb" ein struct-Objekt für Farbtripel.
Das Programm kompiliert problemlos (bis auf ein paar Warnungen wegen nur in C++11 verfügbarer Funktionen), es gibt auch keinen Laufzeitfehler... aber wenn ich mir die gerasterte Bilddatei (von RGB nach 1-bit-Schwarzweiß) ansehe, frage ich mich, was da falsch gelaufen ist - wie Floyd-Steinberg-Schwarzweiß z. B. in GIMP sieht es nämlich nicht aus!
Hier das Original... und das hier ist die schwarzweiße gerasterte Version!
Bis bald im Khyberspace!
Yadgar -- Flagmaker - ein Programmier-Blog Dieser Post wurde am 11.02.2017 um 02:57 Uhr von Yadgar editiert. |