Jpg Bilder einlesen und skalieren



  • Hey Leute,

    ich habe vor Bilder zu skalieren. Das erstmal vorweg.

    Im Prinzip soll das erstmal so laufen, das ich meine .jpg datei öffne und dann nach einzelnen Hex Zeichen suchen kann. (--> http://developer.mobotix.com/docs/mxpeg_frame.html)

    Problem für mich ist irgendwie finde ich sehr wenig zu dem Thema oder ich suche mit falschen Schlagwörtern.

    Ich hab mir jetzt gedacht das ich die Datei in mit ifstream öffne und in einen Vektor schiebe damit ich leichter nach den Zeichen suchen kann. So in dieser art hier:

    ifstream img; 
    img.open("test.jpg" ios::binary); 
    img.close();
    

    Fragen:
    Frag ist komm ich da dann auch an die Hex Zeichen?
    Versteht ihr überhaupt was ich will? Braucht ihr mehr Infos?



  • Gegenfrage: Weisst du überhaupt, was du da vorhast? Deine 3 Zeilen Code sind in eienr Zeile schneller getippt, sicherer und machen genau dasselbe. Nämlich erstmal nur die Datei öffnen, mehr nicht.

    JPG ist kein simples Verfahren, und da steckt viel mehr hinter als man anfangs meinen mag (Huffman Code, RLE, Quantisierung usw...)

    Und wenn du schon danach fragst wie du an solche "Hex-Zeichen" drankommst, bezweifle ich eher, dass du es schaffst JPG zu decodieren.

    Was du anfangs machen könntest, wäre das hier:

    void load()
    {
    	std::vector<char> v;
    	v.reserve(10000); // random Wert
    
    	std::ifstream f("lol.jpg", std::ios::binary);
    
    	while ( f )
    	{
    		char c;
    		f.read(&c, sizeof(c));
    		v.push_back(c);
    	}
    }
    

    Damit hast du eigentlich schonmal das gesamte Bild in deinem Programm (und Arbeitsspeicher).



  • Enno schrieb:

    ich habe vor Bilder zu skalieren.

    Wenn du einfach nur Bilder automatisiert skalieren willst (Kommandozeile, Script usw.), nimm Imagemagick oder sonst was, das ein CLI anbietet.
    Wenn du gern selbst was in C++ machen willst, guck dir mal CImg an.
    Wenn du keine externe lib verwenden (also das Rad neu erfinden) willst, hast du noch viel zu lernen. Ist bestimmt eine gute Übung, aber könnte (wenn ich mir deine Posts so angucke), momentan noch etwas zu schwierig sein.



  • Danek erstmal für die antworten. 🙂
    Ich hätte vielleicht noch erwähnen sollen das ich diese Literatur auch noch vorliegen habe:
    http://www.amazon.de/Bilddatenkompression-Grundlagen-Codierung-Wavelets-H-264/dp/383480472X

    Skym0sh0 schrieb:

    Gegenfrage: Weisst du überhaupt, was du da vorhast? Deine 3 Zeilen Code sind in eienr Zeile schneller getippt, sicherer und machen genau dasselbe. Nämlich erstmal nur die Datei öffnen, mehr nicht.

    JPG ist kein simples Verfahren, und da steckt viel mehr hinter als man anfangs meinen mag (Huffman Code, RLE, Quantisierung usw...)

    Das ist mir bewusst aber genau das werde ich lernen wollen. Hab mich auch mit Huffman, Entropie, Quantisierung ... ein wenig beschäftige also bin dabei.

    Skym0sh0 schrieb:

    Und wenn du schon danach fragst wie du an solche "Hex-Zeichen" drankommst, bezweifle ich eher, dass du es schaffst JPG zu decodieren.

    Das hatte ich allerdings vor. 😞

    Skym0sh0 schrieb:

    Was du anfangs machen könntest, wäre das hier:

    void load()
    {
    	std::vector<char> v;
    	v.reserve(10000); // random Wert
    
    	std::ifstream f("lol.jpg", std::ios::binary);
    
    	while ( f )
    	{
    		char c;
    		f.read(&c, sizeof(c));
    		v.push_back(c);
    	}
    }
    

    Damit hast du eigentlich schonmal das gesamte Bild in deinem Programm (und Arbeitsspeicher).

    Ok danke. 🙂

    Dobi schrieb:

    Wenn du einfach nur Bilder automatisiert skalieren willst (Kommandozeile, Script usw.), nimm Imagemagick oder sonst was, das ein CLI anbietet.
    Wenn du gern selbst was in C++ machen willst, guck dir mal CImg an.
    Wenn du keine externe lib verwenden (also das Rad neu erfinden) willst, hast du noch viel zu lernen. Ist bestimmt eine gute Übung, aber könnte (wenn ich mir deine Posts so angucke), momentan noch etwas zu schwierig sein.

    Das wird wohl drauf hinaus laufen das ich das Rad neu erfinden werde. 😃 Aber danke für die Tipps. Bin auch schon auf Imagemagick und CImg gestoßen.



  • Achja, bevor etwas falsches rüberkommt: Persönlich angreifen oder niedermachen will ich dich nicht.

    Versuch dich da ruhig dran, aber es wird nicht einfach 😉

    Und wenn du Hilfe brauchst, frag ruhig...



  • Skym0sh0 schrieb:

    Achja, bevor etwas falsches rüberkommt: Persönlich angreifen oder niedermachen will ich dich nicht.

    Versuch dich da ruhig dran, aber es wird nicht einfach 😉

    Und wenn du Hilfe brauchst, frag ruhig...

    Ach als ob. 😃 Da hab ich schon anderes erlebt.^^

    Kannst du mir mal einmal sagen warum du das:

    v.reserve(10000);
    

    machst?
    Hab die reference gelesen aber noch nicht so richtig kapiert. 🙂
    http://www.cplusplus.com/reference/vector/vector/reserve/

    Ansonsten hab ich das doch nun Zeichen weise in dem Vektor drin und könnte damit weiter machen oder? Z.b. erstmal den Audio teil abschneiden, wenn vorhanden?



  • Skym0sh0 schrieb:

    Was du anfangs machen könntest, wäre das hier:

    void load()
    {
    	std::vector<char> v;
    	v.reserve(10000); // random Wert
    
    	std::ifstream f("lol.jpg", std::ios::binary);
    
    	while ( f )
    	{
    		char c;
    		f.read(&c, sizeof(c));
    		v.push_back(c);
    	}
    }
    

    Damit hast du eigentlich schonmal das gesamte Bild in deinem Programm (und Arbeitsspeicher).

    Zeichenweise einlesen ist furchtbar. Und danach hast du 1 Zeichen zu viel in "v" stehen.



  • hustbaer schrieb:

    Skym0sh0 schrieb:

    Was du anfangs machen könntest, wäre das hier:

    void load()
    {
    	std::vector<char> v;
    	v.reserve(10000); // random Wert
    
    	std::ifstream f("lol.jpg", std::ios::binary);
    
    	while ( f )
    	{
    		char c;
    		f.read(&c, sizeof(c));
    		v.push_back(c);
    	}
    }
    

    Damit hast du eigentlich schonmal das gesamte Bild in deinem Programm (und Arbeitsspeicher).

    Zeichenweise einlesen ist furchtbar. Und danach hast du 1 Zeichen zu viel in "v" stehen.

    Besseren Vorschlag? 🙂



  • Enno schrieb:

    Kannst du mir mal einmal sagen warum du das:

    v.reserve(10000);
    

    machst?

    std::vector ist intern ein zusammenhängendes Array. Wenn da der Platz ausgeht, dann muss ein neues Array angefordert werden, die alten Daten überkopiert und das alte freigegeben. Das nennt man dann "reallocation".
    Das braucht natürlich Zeit.
    Daher kann es Sinn machen vor dem Einfügen schonmal sicherzustellen dass das Array gross genug ist. Das macht man mit "reserve".

    Macht in dem Beispiel aber wenig Sinn, da danach dann Byteweise eingelesen wird, was wieder ein ziemlicher Performance-Killer ist.



  • Der Vector vergrößert sich von selbst. Wenn du schon 1000000 Elemente in dem drin hast, und dann muss er sich vergrößern, dauert das kopieren natürlich recht lange.

    Weisst du von vornerein die Größe und machst den Vector so gross, dann muss er nicht alles hin und herkopieren. Ja letztlich ist es eine Laufzeitoptimierung...

    Die 10000 waren nur ein Dummywert, aus Informatikersicht total dämlich, da er wahrscheinlich zu klein sein dürfte und dann haben wir den Salat, daher mache ichs jetzt richtig ->

    std::vector<char> load()
    {
    	std::ifstream f("lol.jpg", std::ios::binary);
    
    	auto anfang = f.tellg(); // soltle 0 sein
    	f.seekg(0, std::ios::end);
    	auto ende = f.tellg();
    
    	std::vector<char> v;
    	v.reserve(ende - anfang); // random Wert
    
    	while ( f )
    	{
    		char c;
    		f.read(&c, sizeof(c));
    		v.push_back(c);
    	}
    
    	return v;
    }
    

    Edit:[quote="hustbaer"]

    Enno schrieb:

    Macht in dem Beispiel aber wenig Sinn, da danach dann Byteweise eingelesen wird, was wieder ein ziemlicher Performance-Killer ist.

    Ja, da hast du recht...



  • hustbaer schrieb:

    Enno schrieb:

    Kannst du mir mal einmal sagen warum du das:

    v.reserve(10000);
    

    machst?

    std::vector ist intern ein zusammenhängendes Array. Wenn da der Platz ausgeht, dann muss ein neues Array angefordert werden, die alten Daten überkopiert und das alte freigegeben. Das nennt man dann "reallocation".
    Das braucht natürlich Zeit.
    Daher kann es Sinn machen vor dem Einfügen schonmal sicherzustellen dass das Array gross genug ist. Das macht man mit "reserve".

    Macht in dem Beispiel aber wenig Sinn, da danach dann Byteweise eingelesen wird, was wieder ein ziemlicher Performance-Killer ist.

    Ah ok so hab ich es nun verstanden, danke. 😃
    Allerdings brauche ich das doch Byteweise um es dann verarbeiten zu können oder?

    EDIT: Wenn ihr weitere Code Beispiele zu dem Thema habt oder hier im Forum Threads die mir helfen könnten bin ich da auch offen für. 🙂



  • Enno schrieb:

    Besseren Vorschlag? 🙂

    std::ifstream f("lol.jpg", std::ios::binary);
    
    file.seekg(0, std::ios::end);
    size_t len = file.tellg();
    file.seekg(0, ios_base::beg);
    
    v.resize(len);
    f.read(&v[0], len);
    

    @Skym0sh0
    An den Anfang zurück-seeken wäre nicht dumm. Und wenn du schon die Grösse ermittelt hast, wieso dann immer noch Zeichenweise einlesen?



  • Enno schrieb:

    Allerdings brauche ich das doch Byteweise um es dann verarbeiten zu können oder?

    Es steht nach dem Einlesen immer "Byteweise" im Speicher. Das heisst aber nicht dass man Byte für Byte einzeln einlesen muss. Man kann auch ruhig das ganze File auf einmal lesen.



  • hustbaer schrieb:

    Enno schrieb:

    Allerdings brauche ich das doch Byteweise um es dann verarbeiten zu können oder?

    Es steht nach dem Einlesen immer "Byteweise" im Speicher. Das heisst aber nicht dass man Byte für Byte einzeln einlesen muss. Man kann auch ruhig das ganze File auf einmal lesen.

    Ah ok das wusste ich auch noch nicht. 😃


  • Mod

    Enno schrieb:

    Besseren Vorschlag? 🙂

    Enno schrieb:

    Ah ok das wusste ich auch noch nicht. 😃

    Diese Fragen und Kommentare deuten darauf hin, dass du, wie auch schon von anderen vermutet, viel zu wenig Programmiererfahrung hast, um dein Problem selbstständig umzusetzen. Dir fehlen einfach die ganzen Grundmuster, die man in so gut wie jedem Programm benötigt. Eine Datei einlesen ist kleines Einmaleins. Dies und all die anderen wichtigen Grundmuster der Datenverarbeitung müssen sitzen, bevor du anfängst, komplizierte Algorithmen aus Fachbüchern umzusetzen. Du solltest ganz dringen erst einmal eine ganze Menge Übungsaufgaben aus guten(!) Lehrbüchern machen.

    Zur direkten Frage:
    Nicht ganz standardkonforme Antwort (die aber praktisch überall funktioniert): Dateigröße ermitteln (Betriebssystemfunktion fstat), Speicher reservieren, read.

    Standardkonforme Antwort, Variante a (schlecht): Wenn schon zeichenweise lesen, dann richtig. Erst lesen, dann prüfen, dann verarbeiten. Siehe obiger Absatz über Grundmuster. Alle Leseaktionen in C++ (und in C und vielen anderen Sprachen auch) müssen nach diesem Muster erfolgen. Prüfen, Lesen, Verarbeiten ist immer falsch.

    Standardkonforme Antwort, Variante b (deutlich besser): Blockweise lesen (read, ein paar tausend Byte sind ein guter Richtwert), nach dem Lesen prüfen und gelesene Datenmenge (read-Dokumentatioon lesen!) verarbeiten.



  • SeppJ schrieb:

    Diese Fragen deuten darauf hin, dass du, wie auch schon von anderen vermutet, viel zu wenig Programmiererfahrung hast, um dein Problem selbstständig umzusetzen. Dir fehlen einfach die ganzen Grundmuster, die man in so gut wie jedem Programm benötigt. Eine Datei einlesen ist kleines Einmaleins. Dies und all die anderen wichtigen Grundmuster der Datenverarbeitung müssen sitzen, bevor du anfängst, komplizierte Algorithmen aus Fachbüchern umzusetzen. Du solltest ganz dringen erst einmal eine ganze Menge Übungsaufgaben aus guten(!) Lehrbüchern machen.

    Ja ich weiß ich bin echt nicht so der King. Ist auch ok das das kritisiert wird. Habe auch das Buch Der C++-Programmierer. Will mich jetzt auch nicht raus reden warum das bei mir alles so lange dauert. 😉

    SeppJ schrieb:

    Zur direkten Frage:
    Nicht ganz standardkonforme Antwort (die aber praktisch überall funktioniert): Dateigröße ermitteln (Betriebssystemfunktion fstat), Speicher reservieren, read.

    Standardkonforme Antwort, Variante a (schlecht): Wenn schon zeichenweise lesen, dann richtig. Erst lesen, dann prüfen, dann verarbeiten. Siehe obiger Absatz über Grundmuster. Alle Leseaktionen in C++ (und in C und vielen anderen Sprachen auch) müssen nach diesem Muster erfolgen. Prüfen, Lesen, Verarbeiten ist immer falsch.

    Standardkonforme Antwort, Variante b (deutlich besser): Blockweise lesen (read, ein paar tausend Byte sind ein guter Richtwert), nach dem Lesen prüfen und gelesene Datenmenge (read-Dokumentatioon lesen!) verarbeiten.

    Ich danke für die Anregungen und werde mich jetzt mal dran machen um zu versuchen da was hin zu bekommen. 😃 Ansonsten hört ihr von mir!



  • So mal kleines Update was ich bis jetzt hab:

    #include <iostream>
    #include <vector>
    #include "mxpw.h"
    
    Huffamn{
    private:
      //Vektor für ??
      std::vector<char> veki;
      //Der virtuelle Datenstrom
      std::vector<char> datastream;
    public:
      //Constructer
      Huffman{};
      //Deconstructer
      ~Huffamn{};
      //JPEG Encoder
      void encoder();
      //JPEG Decoder
      void decoder();
      //Baum bauen
      void buildtree();
      //Knoten übersetzung bauen
      void buildbook();
      //Knoten bauen
      void buildnode();
      //Characters lesen
      void readChar();
      //Baum lesen
      void readtree();
      //Zählen und Wahrscheinlichkeiten
      void count();
    
      // Reserviert eine Datengröße
      void ReserveSize(size_t Bytes) datastream.reserve(Bytes); }
      // Löscht den Stream
      void ReleaseStream() { datastream.clear(); }
    };
    
    #include <iostream>
    #include <vector>
    #include "huffman.h"
    
    //Fügt Daten ein
    /*template<typename T> void Assign(T data)
    {
        char *tmpdata = new char[sizeof(T)];
        memcpy((void**)&tmpdata, data, sizeof(T));
        for(int i = 0; i < sizeof(T); i++)
            datastream.push_back(tmpdata[i]);
    }
    
    //Liest Daten aus dem Datenstream
    template<typename T> const bool GetData(T *val, unsigned int position) const
    {
        if(sizeof(T) + position > datastream.size()) return false;
        char *tmpdata = new char[sizeof(T)];
        for(int i = 0; i < sizeof(T); i++)
            tmpdata[i] = datastream[i+position];
        memcpy((void**)&val, tmpdata, sizeof(T));
        return true;
    }*/
    
    //Encoded das JPEG
    void Huffman::encoder(){
      readChar();
      count();
      buildtree();
      buildbook();
    }
    
    //Decoded das JPEG
    void Huffman::decoder(){
      readtree();
      buildtree();
    }
    
    //Liest den erstellten Baum
    void Huffman::readtree(){
      std::iterator it;
      for(it; veki.begin() < veki.end(); it++){
        if(it == x09){
        }
      }      
    }
    
    //Zum Knoten Baum bauen
    void Huffman::buildtree(){
    
    }
    
    //Zum Knoten übersetzung bauen
    void Huffman::buildbook(){
    
    }
    
    //Knoten bauen
    void Huffman::buildnode(){
    
    }
    
    //Lesen des erstellten Baumes
    void Huffman::readtree(){
    
    }
    
    //Characters einlesen in Datenstrom
    void Huffman::readChar(){
      read.input();
    
    }
    
    //Zählen und Wahrscheinlichkeiten
    void Huffman::count(){
    
    }
    

    Das ist jetzt erstmal so eine Übersicht wie ich mir das vorgestellt hab. Musste viel lesen und werde jetzt anfangen das alles weiter aus zubauen. Wollte nur mal wissen ob euch das so gefällt oder ob ihr jetzt schon Anregungen habt.



  • Ja, dein Interface ist schon zu gross. Das wirkt als ob du zig verschiedene Funktion anbietest. Im Prinzip ist das doch aber nur das nötige zum Einlesen?!

    Und welche Funktion du da nutzt/anbietest braucht den Nutzer ja nicht zu sehen, daher -> diese Hilfsfunktionen privatisieren:

    class JPG_Reader
    {
    public:
        // ...
        void readJPG(std::istream & is) // z.B.
        {
            readStream(is);
            buildTree();
            buildbook();
            // blabla...
        }
    
        // ... andere öffentliche Methoden
    
    private:
        void readStream(std::istream& is);
        void buildTree();
        void buildbook();
        // ... usw.
    };
    

    So kannst du von aussen sagen:

    int main()
    {
        JPG_Reader r;
        r.readPJG(std::cin);
    
        r.print(std::cout);
    }
    

    Mit deiner Methode wäre das eventuell zu sowas ausgeufert:

    int main()
    {
    	Huffman h;
    	h.decode();
    	h.buildtree();
    	h.readtree(); // Ups, readtree muss eigentlich vor buildtree ausgeführt werden
    	h.buildnode(); 
    	// ..
    }
    

    Einen Grund habe ich dran kommentiert.



  • Danke das du schon so schnell antwortest! 😃

    Ich werde mich ran machen und deine Vorschläge, die mir sehr zusagen, umsetzen. Wenn ich weiter bin werde ich hier wieder ein Update machen. 🙂



  • Nur um's mal erwähnt zu haben: http://libjpeg.sourceforge.net/



  • Wenn du mit solchen Low-Level-Algorithmen arbeitest, mache dich unbedingt mit der Funktionsweise von Zeigern, RAM und Datenstrukturen im Detail vertraut. Auch RAII musst du unbedingt anschauen. Du wirst sonst wahnsinnig viel Zeit mit Debugging verbraten, viel mehr als wenn du die Zeit in die Lektüre von C++ investiert hättest. Ich fürchte, alleine die Implementierung der Algorithmen wird schon genügend Zeit (auch für Debugging) benötigen -- wenn du dann noch Probleme mit der Programmiersprache hast, wirst du sehr schnell die Motivation verlieren 😉

    dot schrieb:

    Nur um's mal erwähnt zu haben: http://libjpeg.sourceforge.net/

    Es seien auch Boost.GIL und SFML erwähnt, wobei ich mit ersterem noch nie gearbeitet habe.


Anmelden zum Antworten