Hallo Besucher, der Thread wurde 7,5k mal aufgerufen und enthält 35 Antworten

letzter Beitrag von Yadgar am

C++: Problem mit Umrechnung von RGB-Bildern in C 64-Multicolor

  • Hi(gh)!


    Habe mittlerweile meine alten C-Lehrbücher ausgegraben... und ich glaube wirklich, dass ich c64multicolor_correct() besser überwiegend in C schreibe... da C 64-Bilder (GEOS mal außen vor gelassen) sowieso immer 160 x 200 Pixel groß sind, sind Vektoren mit ihrer dynamischen Speicherverwaltung in diesem Fall reiner Overkill, also täte es auch ein eindimensionales Pixel-Array, wo man die Pixelpositionen im Bild mit Integer- und Modulo-Divisionen errechnet...


    Bis bald im Khyberspace!


    Yadgar

  • Einfacher ist immer besser :thumbup: . Lieber erst mal einfach und geht, erweitern kann man später immer noch.

  • Wäre es für den Einstieg nicht besser, gleich mal was "Geeigneteres" zu nehmen wie Python, wo man weniger gegen die Lernkurve der Sprache kämpfen muss, sondern sich mehr auf die Aufgabenstellung konzentrieren kann?

  • Zitat von Claus

    Ich würde einfach die C64-Farbe mit dem geringsten euklidischen Abstand zur Originalfarbe nehmen, also die Summe der quadrierten Differenzen für R, G und B minimieren.

    So macht es auch GoDot.


    Arndt


    Edit: Ein bisschen Genaueres hier und hier.

  • Keine gute Idee - ich kann überhaupt kein Python!

    Sorry hatte das hier

    Je länger ich mich mit diesem ganzen Kram herumquäle, desto mehr sehe ich ein: ich tauge nicht zum Programmierer! Ich kann das einfach nicht, ich bin zu dumm dazu! Daher vergesst auch alles, was Ihr im Februar über meine größenwahnsinnigen Phantasien zu einer Retrocomputing-Datenbank gelesen habt, die wird es auch niemals geben...

    so interpretiert, dass Du die Sprache auch erst lernst.

  • [...] besser überwiegend in C schreibe [...]

    Aber doch nicht der Vektoren wegen ;)
    Würde zwar zustimmen, dass die da zumindest für dein Targetimage überflüssig sind, aber dazu gibts ja mittlerweile das std::array,
    das sich genauso verhält wie die klassischen C-arrays (die dir in C++ ja auch zur verfügung stehen), nur halt noch kompatibilität mit der ganzen STL obendrauf legen.
    Statt

    C
    1. std::vector<std::vector<pixel>> c64_4x8area;
    2. c64_4x8area.resize(8);
    3. for(auto& vec: c64_4x8area){
    4. vec.resize(4);
    5. }


    dann z.b. einfach

    C
    1. std::array<std::array<pixel, 8>, 4> c64_4x8area;


    Leider grad selber in Windows, drum krieg ich deine Päckchen nicht geöffnet (daraus schließe ich mal dass du zumindest nen vernünftigen Compiler benutzt ;) ).
    Aber mal noch generelle Tips zu dem was du direkt in den Thread gepackt hast:


    Irgendjemand schrob ja schon dass das nach uninitialisierten Variablen riecht.
    Du machst recht viel Zeug manuell, z.b.:


    Code
    1. pixel p;
    2. rgb c;
    3. vector<vector<pixel>> vec;
    4. p.set_blue(vec[i].at(j).get_blue();
    5. c.blue = p.get_blue()
    6. if(c.red == areacols[m].red){}

    Hat dein pixel keinen assignment-operator? wenn der keine pointer oder references als member hat sollte der dir sogar automatisch generiert werden.
    Genauso könntest du einfach eine funktion rgb pixel::to_rgb() einführen, bzw bool rgb::operator==(const rgb&),
    einfach um die vielen manuellen dinge die sich wiederholen zu reduzieren. Weniger Code, weniger Fehler :)


    Wozu denn eigentlich die doppelten casts?
    width = (unsigned short)(unsigned char)ch;
    Da würde doch
    width = static_cast<unsigned short>(ch);
    reichen, oder?


    Was Python betrifft, ist natürlich eine supergeile Sprache und ne ernsthafte Alternative,
    aber wenn du versuchst, mehr idiomatisches C++ zu schreiben ist C++ näher an Python als C ;)
    Alles neuschreiben ist vielleicht auch nicht das beste.
    So schlecht schauts ja alles gar nicht aus, werd unter Linux später mal nachsehen was deine Schleifen eigtl. so alles treiben.

  • Was Python betrifft, ist natürlich eine supergeile Sprache und ne ernsthafte Alternative,
    aber wenn du versuchst, mehr idiomatisches C++ zu schreiben ist C++ näher an Python als C ;)
    Alles neuschreiben ist vielleicht auch nicht das beste.
    So schlecht schauts ja alles gar nicht aus, werd unter Linux später mal nachsehen was deine Schleifen eigtl. so alles treiben.

    Ist Python als Interpretersprache nicht wesentlich langsamer als C++? Da yip hauptsächlich dazu dient, in Einzelbildsequenzen umgewandelte Videos zu bearbeiten, wäre das nicht so günstig...


    Unabhängig davon habe ich ja im Moment den Vektor für den jeweils aktuellen 4 x 8-Pixel-Bereich im Verdacht - den übergebe ich aus dem Hauptprogramm als Referenz, obwohl er nur in c64multicolor_correct() und sonst nirgendwo benötigt wird! Da könnte ich ihn doch auch in der Funktion selbst erzeugen...


    Parallel habe ich angefangen, das Ganze (also c64multicolor_correct(), nicht yip) als eigenständiges Programm mehr C-orientiert neu zu schreiben:
    einfache struct rgb für die Pixel bzw. Farben, statt zweidimensionalem Vektor ein eindimensionales C-Array vom Typ rgb - die Größe eines C 64-BIldes im Multicolor-Modus (ohne GEOS) steht ja ohnehin von vornherein fest, also kann ich auch einfach


    Code
    1. rgb c64image[32000];

    schreiben... die Pixelpositionen würde man mit Integer- und Modulo-Divisionen ermitteln. Lediglich beim Array mit den im jeweils aktuellen 4 x 8-Bereich gefundenen Farben müsste ich einen Vektor (oder dynamische Speicherverwaltung im C-Stil) verwenden...

  • Neu schreiben kann aber manchmal besser sein, gerade wenn es ein langer unstrukturierter Code ist. Wenn der Algorithmus schon steht, braucht man da nicht mehr drüber nachdenken, sondern kann sich auf übersichtlichen Code konzentrieren. Später wird man sich selbst dankbar sein, weil das einfach wartbarer ist.


    Und es scheint doch ein privates Hobby zu sein? Man hat keinen Zeitdruck, sondern kann erst mal andere Fingerübungen machen, bis man es raus hat. Dann kann man ja nochmal starten und vielleicht geht es plötzlich ganz flott von der Hand.

  • Ist Python als Interpretersprache nicht wesentlich langsamer als C++? Da yip hauptsächlich dazu dient, in Einzelbildsequenzen umgewandelte Videos zu bearbeiten, wäre das nicht so günstig...

    Da kenn ich mich zwar nicht aus, aber das Phyton stark im Mathematik-Bereich vertreten ist, wird seinen Grund haben.

  • Neu schreiben kann aber manchmal besser sein, gerade wenn es ein langer unstrukturierter Code ist. Wenn der Algorithmus schon steht, braucht man da nicht mehr drüber nachdenken, sondern kann sich auf übersichtlichen Code konzentrieren. Später wird man sich selbst dankbar sein, weil das einfach wartbarer ist.


    Und es scheint doch ein privates Hobby zu sein? Man hat keinen Zeitdruck, sondern kann erst mal andere Fingerübungen machen, bis man es raus hat. Dann kann man ja nochmal starten und vielleicht geht es plötzlich ganz flott von der Hand.

    Ja, es ist ein privates Hobby... aber meine Lebenszeit ist auch endlich (mehr als die Hälfte ist schon rum!), und dann gibt es da im US-Staat New York nahe der Grenze zu Vermont eine Menschin, die mir erlaubt hat, die zahlreichen YouTube-Videos von ihrem zahmen Kanadaluchs Maxwell zu vervierundsechzigern und atarifizieren... und da möchte ich in überschaubarer Zeit endlich mal liefern! Bis jetzt geht mit yip leider nur Atari ST monochrom (aber immerhin mit Floyd-Steinberg-Rasterung) und C 64-Blockmodus (40 x 25 Pixel)...

  • das Phyton stark im Mathematik-Bereich vertreten ist, wird seinen Grund haben.

    Sicher nicht die Geschwindigkeit ;) . Ob der Unterschied für diesen Zweck aber so kritisch ist, sein mal dahingestellt. In jedem Fall: weitermachen!

  • Sodala, habs mir gerade mal angekuckt.
    Wenn man den resize(8) in main wieder reinkommentiert läuft das bei mir :)
    Hast du vllt noch eben ein entsprechendes Bild?


    Genereller Tip:
    Nimm für den Anfang durchweg .at() um auf STL-container zuzugreifen.
    Das wirft im Gegensatz zu operator[] immer ne Exception, egal welchen container du nimmst,
    wenn der Algorithmus noch nicht klar ist hilft das ungemein :)

  • die Größe eines C 64-BIldes im Multicolor-Modus (ohne GEOS) steht ja ohnehin von vornherein fest, also kann ich auch einfach rgb c64image[32000]; schreiben... die Pixelpositionen würde man mit Integer- und Modulo-Divisionen ermitteln. Lediglich beim Array mit den im jeweils aktuellen 4 x 8-Bereich gefundenen Farben müsste ich einen Vektor (oder dynamische Speicherverwaltung im C-Stil) verwenden...

    wie wärs denn mit


    Code
    1. std::array<std::array<rgb, 160>, 200> image;

    damit kannste dir dein index-rumgerechne sparen, das hat auch keinerlei laufzeit-overhead.
    Um die aktuellen Farben zu sammeln würde ich dir dagegen fast mal ein std::set<rgb> vorschlagen.
    Da kannste einfach alle Pixel (oder rgb werte) reinstecken, das kümmert sich selbst drum doppelte Werte auszusortieren.
    Generell frag ich mich wozu du Pixel und RGB unterscheidest? Sehe da aus deinem header keine Notwendigkeit für.
    Den Zugriff auf die Werte musste nicht maskieren, dadurch dass du private-member hast wird die klasse nur viel komplizierter und du musst dich um konstruktoren etc. kümmern.
    Bei deinem RGB kümmert sich der Compiler drum.
    Bau dir da noch einen bool operator==(const rgb& l, const rgb& r); dazu, und schieb die member-funktionen deines pixels da rein und du sparst dir viel kopfzerbrechen :)

  • Hi(gh)!


    Was ist denn jetzt kaputt? Mit einem Mal kompiliert yip.cc nicht mehr, ich bekomme eine Abbruchmeldung:


    yip.cc:5:21: fatal error: iostream.h: Datei oder Verzeichnis nicht gefunden
    #include<iostream.h>


    Aber da steht nirgendwo #include<iostream.h>, sondern nur #include<iostream>! Und auch nicht in Zeile 5, Spalte 21, sondern in Zeile 13, Spalte 1!


    Was soll das? Warum sind Computer so unberechenbar?!?


    (einige Minuten später)


    Alles klar, ich war im falschen Verzeichnis - und habe das falsche yip.cc zu kompilieren versucht!