expertenaustausch > comp.lang.* > comp.lang.iso-c++

Jörg Yadgar Bleimann (03.07.2018, 00:07)
Hi(gh)!

Zum besseren Verständnis vorweg: yip (Yadgar's Image Processor) ist ein
konsolenbasiertes (für Linux und Windows) Bildbearbeitungsprogramm, an
dem ich seit einigen Jahren programmiere... voriges Jahr hatte ich mich
schon einmal in diesem Zusammenhang an d.c.l.i-c++ gewandt.

Mein aktuelles Problem bezieht sich auf die neu implementierte
"-c64"-Funktionalität, ein Kommando, das eingelesene True-Color-Bilder
in die 16farbige Palette des Commodore 64 umrechnet und, falls die
Bilddateien nicht bildfüllend sind (40 x 25 Pixel im Blockgrafik- und
160 x 200 Pixel im Multicolor-Modus) die fehlenden Zeilen oder Spalten
mit einer aus diesen 16 Farben wählbaren Füllfarbe auffüllt. Diese
beiden Funktionen arbeiten einwandfrei; beim Multicolor-Modus kommt
jedoch eine dritte Funktion hinzu, in deren Code ein für mich nicht
nachvollziehbarer Fehler steckt.

Entsprechend der hardwareseitig vorgegebenen Beschränkung der freien
Farbwahl im Multicolor-Modus des C 64 teilt diese dritte Funktion,
c64multicolor_correct() das Bild in Abschnitte zu jeweils 4 x 8 Pixel,
zählt in jedem dieser Abschnitte die vorkommenden Farben; falls die
Anzahl der Farben größer ist als 4 ist, werden die Häufigkeiten der
Farben ermittelt, die Farben absteigend nach ihrer Häufigkeit sortiert
und alle Farben ab der fünften Farbe durch die im RGB-Farbraum nächste
unter den ersten vier Farben ersetzt.

Soweit die Theorie... hier der Code:

void c64multicolor_correct(vector<vector<pixel> >& c64img,
vector<vector<pixel> >& c64_area)
{
short a, b, i, j, k, l, m, n, colnum_area, freq;
pixel p;
rgb c;
vector<rgb> areacols;
vector<short> colfreqs;
bool match;

for (a=24; a<32; a+=8) // zu Testzwecken wird nur ein einzelner 4 x
8-Bereich eingelesen! Bitte anschließend korrigieren!
{
for (b=56; b<60; b+=4)
{
c64_area.resize(8);
for (i=a; i<a+8; i++) // pixels from image are copied into
temporary 4 by 8 pixel vector
{
for (j=b; j<b+4; j++)
{
p.set_red((unsigned char)c64img[i].at(j).get_red());
p.set_green((unsigned char)c64img[i].at(j).get_green());
p.set_blue((unsigned char)c64img[i].at(j).get_blue());

//cout << "Pixel (" << b+j << "/" << a+i << "): rgb <" <<
p.get_red() << "," << p.get_green() << "," << p.get_blue() << ">" << endl;

c64_area[i-a].push_back(p);
}
}
areacols.resize(0);
for (k=0; k<8; k++) // vector containing different colors in
temporay 4 by 8 pixel vector is created
{
for (l=0; l<4; l++)
{
c.red = c64_area[k].at(l).get_red();
c.green = c64_area[k].at(l).get_green();
c.blue = c64_area[k].at(l).get_blue();
match=false;
if (k==0 && l==0)
{
areacols.push_back(c);
}
else
{
for (m=0; m<areacols.size(); m++)
{
if (c.red == areacols[m].red && c.green ==
areacols[m].green && c.blue == areacols[m].blue)
{
match=true;
}
}
if (match == false) // new color found
{
areacols.push_back(c);
}
}

}
}
colnum_area = areacols.size();
//cout << "Number of different colors in 4 by 8 pixel area (" <<
b << "/" << a << " to " << b+3 << "/" << a+7 << "): " << colnum_area <<
endl;
if (colnum_area > 4)
{
colfreqs.resize(colnum_area);
for (m=0; m<colfreqs.size(); m++)
colfreqs[m] = 0;
m=0;
for (k=0; k<8; k++)
{
for (l=0; l<4; l++)
{
if ( k == 0 && l == 0)
{
colfreqs[m]++;
}
else
{
c.red = c64_area[k].at(l).get_red();
c.green = c64_area[k].at(l).get_green();
c.blue = c64_area[k].at(l).get_blue();
while (!(c.red == areacols[m].red && c.green ==
areacols[m].green && c.blue == areacols[m].blue))
m++;
colfreqs[m]++;
m = 0;
}
}
}
for (m = 0; m < colnum_area; m++)
cout << "Farbe #" << m << ": rgb <" << areacols[m].red << "," <<
areacols[m].green << "," << areacols[m].blue << "> - " << colfreqs[m] <<
" Pixel" << endl;
qsrt(colfreqs, areacols, 0, colfreqs.size()-1);
for (m = 0; m < colnum_area; m++)
cout << colfreqs[m] << " Pixel: rgb <" << areacols[m].red << "," <<
areacols[m].green << "," << areacols[m].blue << ">" << endl;

vector<rgb> fourcolors;
for (m = 0; m < 4; m++)
fourcolors.push_back(areacols[m]);
vector<rgb> excesscolors;
for (m = 4; m < colnum_area; m++)
excesscolors.push_back(areacols[m]);

rgb closest = fourcolors[0];
for (m = 4; m < colnum_area; m++)
{
for (n = 0; n < 4; n++)
{
if (coldist(areacols[m], fourcolors[n]) < coldist(areacols[m],
closest))
{
closest = fourcolors[n];
cout << "rgb <" << areacols[m].red << "," << areacols[m].green <<
"," << areacols[m].blue << "> wird ersetzt durch <"<< fourcolors[n].red
<< "," << fourcolors[n].green << "," << fourcolors[n].blue << ">" << endl;
}
}
}

cout << Uuml << "bersch" << uuml << "ssige Farben:" << endl;
for (m = 0; m < colnum_area-4; m++)
cout << "rgb <" << excesscolors[m].red << "," <<
excesscolors[m].green << "," << excesscolors[m].blue << ">" << endl;

for (k=0; k<8; k++)
{
for (l=0; l<4; l++)
{
match = false;
m = 0;
c.red = c64_area[k].at(l).get_red();
c.green = c64_area[k].at(l).get_green();
c.blue = c64_area[k].at(l).get_blue();
while (match == false && m < colnum_area-4)
{
cout << c.red << " " << c.green << " " << c.blue << " | " <<
excesscolors[m].red << " " << excesscolors[m].green << " " <<
excesscolors[m].blue << endl;
if ((c.red == excesscolors[m].red) && (c.green ==
excesscolors[m].green) && (c.blue == excesscolors[m].blue))
match == true;
m++;
}
cout << match << endl;
if (match == true)
{
rgb closest = fourcolors[0];
for (n=0; n<4; n++)
{
if (coldist(c, fourcolors[n]) < coldist(c, closest))
closest = fourcolors[n];
}
cout << a+k << endl;
cout << b+l << endl;
c64img[a+k].at(b+l).set_all(closest.red, closest.green,
closest.blue);
}
}
}
}
}
}
}

Die Funktion bekommt zwei Referenzen auf Vektoren vom Typ pixel
übergeben. Die Klasse pixel ist wie folgt definiert:

class pixel
{
public:
pixel(); // Standard-Konstruktor
pixel (short, short, short); // Allgemeiner Konstruktor
~pixel(); // Destruktor
void set_all(short, short, short);
void set_red(short);
void set_green(short);
void set_blue(short);
void get_all(rgb&);
short get_red();
short get_green();
short get_blue();
void invert();
void rgb2grey();
void rgb2grey(float, float, float);
float getvalue();
private:
short r;
short g;
short b;
short round(float);
};

pixel::pixel()
{}

pixel::pixel(short red, short green, short blue)
{
r = red;
g = green;
b = blue;
}

pixel::~pixel()
{}

void pixel::set_all(short red, short green, short blue)
{
r = red;
g = green;
b = blue;
}

void pixel::set_red(short red)
{
r = red;
}

void pixel::set_green(short green)
{
g = green;
}

void pixel::set_blue(short blue)
{
b = blue;
}

void pixel::get_all(rgb &tr)
{
tr.red = r;
tr.green = g;
tr.blue = b;
}

short pixel::get_red()
{
return r;
}

short pixel::get_green()
{
return g;
}

short pixel::get_blue()
{
return b;
}

void pixel::invert()
{
r = 255-r;
g = 255-g;
b = 255-b;
}

void pixel::rgb2grey()
{
float red = r*0.299;
float green = g*0.587;
float blue = b*0.114;
float sum = red+green+blue;
r = g = b = round(sum);
}

void pixel::rgb2grey(float redw, float greenw, float bluew)
{
float sumw = redw+greenw+bluew;
float red = r*(redw/sumw);
float green = g*(greenw/sumw);
float blue = b*(bluew/sumw);
float sum = red+green+blue;
r = g = b = round(sum);
}
short pixel::round(float total)
{
short grey;
if (total-floor(total) < 0.5)
grey = floor(total);
else
grey = ceil(total);

return grey;
}
for (k=0; k<8; k++)
{
for (l=0; l<4; l++)
{
match = false;
m = 0;
c.red = c64_area[k].at(l).get_red();
c.green = c64_area[k].at(l).get_green();
c.blue = c64_area[k].at(l).get_blue();
while (match == false && m < colnum_area-4)
{
cout << c.red << " " << c.green << " " << c.blue << " | " <<
excesscolors[m].red << " " << excesscolors[m].green << " " <<
excesscolors[m].blue << endl;
if ((c.red == excesscolors[m].red) && (c.green ==
excesscolors[m].green) && (c.blue == excesscolors[m].blue))
match == true;
m++;
}
cout << match << endl;
if (match == true)
{
float pixel::getvalue()
{
float value;
value = r*0.299+g*0.587+b*0.114;
return value;
}

Nach diversen Testausgaben (der gefundenen Farben und deren Sortierung)
erfolgt ein erneutes Durchgehen aller 32 Pixel des 4 x 8-Abschnittes;
für jedes Pixel wird geprüft, ob seine Farbe mit einer der (in diesem
Fall drei) überzähligen Farben identisch ist:

for (k=0; k<8; k++)
{
for (l=0; l<4; l++)
{
match = false;
m = 0;
c.red = c64_area[k].at(l).get_red();
c.green = c64_area[k].at(l).get_green();
c.blue = c64_area[k].at(l).get_blue();
while (match == false && m < colnum_area-4)
{
cout << c.red << " " << c.green << " " << c.blue << " | " <<
excesscolors[m].red << " " << excesscolors[m].green << " " <<
excesscolors[m].blue << endl;
if ((c.red == excesscolors[m].red) && (c.green ==
excesscolors[m].green) && (c.blue == excesscolors[m].blue))
match == true;
m++;
}
cout << match << endl;
if (match == true)
{
[...]

Obwohl laut Ausgabe bereits beim ersten Pixel die Gleichheit mit einer
der überzähligen Farben erreicht ist, wird

((c.red == excesscolors[m].red) && (c.green == excesscolors[m].green) &&
(c.blue == excesscolors[m].blue))

niemals wahr! Wieso?

Die Objekte c und der Vektor excesscolors[] sind vom Typ rgb, im
Gegensatz zu pixel keine Klasse, sondern eine einfache Struktur:

struct rgb // global!
{
short red;
short green;
short blue;
};

Hier die vorhin angekündigte Ausgabe des Programms:

Farbe #0: rgb <112,116,111> - 1 Pixel
Farbe #1: rgb <253,254,252> - 12 Pixel
Farbe #2: rgb <48,230,198> - 3 Pixel
Farbe #3: rgb <66,69,64> - 6 Pixel
Farbe #4: rgb <164,167,162> - 8 Pixel
Farbe #5: rgb <0,0,0> - 1 Pixel
Farbe #6: rgb <95,83,254> - 1 Pixel
12 Pixel: rgb <253,254,252>
8 Pixel: rgb <164,167,162>
6 Pixel: rgb <66,69,64>
3 Pixel: rgb <48,230,198>
1 Pixel: rgb <0,0,0>
1 Pixel: rgb <95,83,254>
1 Pixel: rgb <112,116,111>

Überschüssige Farben:
rgb <0,0,0>
rgb <95,83,254>
rgb <112,116,111>
112 116 111 | 0 0 0
112 116 111 | 95 83 254
112 116 111 | 112 116 111
0
253 254 252 | 0 0 0
253 254 252 | 95 83 254
253 254 252 | 112 116 111
0
48 230 198 | 0 0 0
48 230 198 | 95 83 254
48 230 198 | 112 116 111
0
253 254 252 | 0 0 0
253 254 252 | 95 83 254
253 254 252 | 112 116 111
0
66 69 64 | 0 0 0
66 69 64 | 95 83 254
66 69 64 | 112 116 111
0
253 254 252 | 0 0 0
253 254 252 | 95 83 254
253 254 252 | 112 116 111
0
164 167 162 | 0 0 0
164 167 162 | 95 83 254
164 167 162 | 112 116 111
0
253 254 252 | 0 0 0
253 254 252 | 95 83 254
253 254 252 | 112 116 111
0
0 0 0 | 0 0 0
0 0 0 | 95 83 254
0 0 0 | 112 116 111
0
253 254 252 | 0 0 0
253 254 252 | 95 83 254
253 254 252 | 112 116 111
0
253 254 252 | 0 0 0
253 254 252 | 95 83 254
253 254 252 | 112 116 111
0
48 230 198 | 0 0 0
48 230 198 | 95 83 254
48 230 198 | 112 116 111
0
66 69 64 | 0 0 0
66 69 64 | 95 83 254
66 69 64 | 112 116 111
0
253 254 252 | 0 0 0
253 254 252 | 95 83 254
253 254 252 | 112 116 111
0
164 167 162 | 0 0 0
164 167 162 | 95 83 254
164 167 162 | 112 116 111
0
253 254 252 | 0 0 0
253 254 252 | 95 83 254
253 254 252 | 112 116 111
0
66 69 64 | 0 0 0
66 69 64 | 95 83 254
66 69 64 | 112 116 111
0
48 230 198 | 0 0 0
48 230 198 | 95 83 254
48 230 198 | 112 116 111
0
253 254 252 | 0 0 0
253 254 252 | 95 83 254
253 254 252 | 112 116 111
0
164 167 162 | 0 0 0
164 167 162 | 95 83 254
164 167 162 | 112 116 111
0
66 69 64 | 0 0 0
66 69 64 | 95 83 254
66 69 64 | 112 116 111
0
164 167 162 | 0 0 0
164 167 162 | 95 83 254
164 167 162 | 112 116 111
0
253 254 252 | 0 0 0
253 254 252 | 95 83 254
253 254 252 | 112 116 111
0
164 167 162 | 0 0 0
164 167 162 | 95 83 254
164 167 162 | 112 116 111
0
66 69 64 | 0 0 0
66 69 64 | 95 83 254
66 69 64 | 112 116 111
0
164 167 162 | 0 0 0
164 167 162 | 95 83 254
164 167 162 | 112 116 111
0
164 167 162 | 0 0 0
164 167 162 | 95 83 254
164 167 162 | 112 116 111
0
253 254 252 | 0 0 0
253 254 252 | 95 83 254
253 254 252 | 112 116 111
0
66 69 64 | 0 0 0
66 69 64 | 95 83 254
66 69 64 | 112 116 111
0
95 83 254 | 0 0 0
95 83 254 | 95 83 254
95 83 254 | 112 116 111
0
253 254 252 | 0 0 0
253 254 252 | 95 83 254
253 254 252 | 112 116 111
0
164 167 162 | 0 0 0
164 167 162 | 95 83 254
164 167 162 | 112 116 111
0

Bis bald im Khyberspace!

Yadgar
Alfred Peters (05.07.2018, 01:58)
Es schrieb einmal Jörg "Yadgar" Bleimann:
>               if ((c.red == excesscolors[m].red) && (c.green ==
> excesscolors[m].green) && (c.blue == excesscolors[m].blue))
>                 match == true;


"Da ist ein = doppelt. Das müssen wir abziehen." ;-)

Alfred
Jörg Yadgar Bleimann (07.07.2018, 00:48)
Hi(gh)!

On 05.07.2018 01:58, Alfred Peters wrote:
> Es schrieb einmal Jörg "Yadgar" Bleimann:
>>               if ((c.red == excesscolors[m].red) && (c.green ==
>> excesscolors[m].green) && (c.blue == excesscolors[m].blue))
>>                 match == true;

> "Da ist ein = doppelt. Das müssen wir abziehen." ;-)
> Alfred


Ja, das habe ich zwischenzeitlich dann auch gesehen bzw. bin darauf
hingewiesen worden... mittlerweile bin ich, siehe Betreff, ein ganzes
Stück weiter in der Programmierung (oder besser im manuellen Debugging),
aber die Funktion c64multicolor_correct() macht immer noch nicht, was
sie soll.

Zur besseren Verdeutlichung hier erst mal ein Link auf das komplette
Paket mit Quelltexten, Log und einem Beispielbild:

Das Bild muss mit folgendem yip-Kommando bearbeitet werden:
yip -c64 koeln_160x200.tga multicolor 0 1

Konkret passiert gegenwärtig Folgendes: wenn ich eine Reihe von 4 x
8-Pixelbereichen auf überzählige Farben (zur Erinnerung: das Programm
soll RGB-Bilder so umrechnen, als würden sie auf einem C 64 im
Multicolor-Modus dargestellt werden, also pro 4 x 8-Pixel-Bereich nur 4
aus 16 Farben), dann stimmen die Pixelanzahlen für die gefundenen
Farben, teilweise sogar die gefundenen Farben selbst nicht mit dem
(vorläufig ohne diese Korrektur) abgespeicherten Bild überein.

Zwei Beispiele:

Im 4 x 8-Bereich 8/128 bis 12/136 sollten laut gespeichertem "C
64-Rohbild" gefunden werden:
1 x türkisgrün - rgb <48,230,198>
4 x "weiß" - rgb <253,254,252>
12 x hellgrau - rgb <164,167,162>
10 x mittelgrau - rgb <112,116,111>
4 x schwarz - rgb <0, 0, 0>
1 x dunkelblau - rgb <33,27,174>

Tatsächlich findet c64multicolor_correct():
1 x türkisgrün - rgb <48,230,198>
4 x "weiß" - rgb <253,254,252>
12 x hellgrau - rgb <164,167,162>
10 x mittelgrau - rgb <112,116,111>
4 x dunkelgrau - rgb <66,69,64> // Abweichung!
1 x dunkelblau - rgb <33,27,174>

Ein anderes Beispiel, 4 x 8-Bereich 16/128 bis 20/136:
Sollwerte laut gespeichertem Bild:
14 x mittelgrau - rgb <112,116,111>
8 x schwarz - rgb <0, 0, 0>
7 x dunkelgrau - rgb <66,69,64>
2 x hellrot - rgb <254, 74, 87>
1 x orange - rgb <184, 65, 4>

Tatsächlich gefunden:
14 x mittelgrau - rgb <112,116,111>
4 x schwarz - rgb <0,0,0> // Abweichung!
7 x dunkelgrau - rgb <66,69,64>
4 x hellgrau - rgb <164,167,162> // Abweichung!
2 x hellrot - rgb <254,74,87>
1 x orange - rgb <184,65,4>

Hier stimmt nicht einmal die Anzahl der Farben überein!

Bis bald im Khyberspace!

Yadgar
Jörg Yadgar Bleimann (11.07.2018, 16:27)
Hi(gh)!

On 05.07.2018 14:49, Bonita Montero wrote:

> Die Wahrscheinlichkeit, dass dein Programm jemand heutzutage für
> diesen Zweck einsetzt dürfte bei der eines 6ers im Lotto liegen.


Hurra, Jackpot!!! Ich werde dieses Programm auf jeden Fall für diesen
Zweck einsetzen - sonst würde ich es ja nicht programmieren, oder?

Bis bald im Khyberspace!

Yadgar
Ähnliche Themen