Bild serialisieren



  • Ich würde gerne meine Klasse BildDaten mit Hilfe von boost serialisieren.

    #ifndef BildDaten_hpp
    #define BildDaten_hpp
    
    #include "../Daten.hpp"
    #include <opencv/cv.h>
    #include <opencv/highgui.h>
    #include <string>
    
    //! Dies ist die Datenklasse vom CameraModul. Damit versendet das CameraModul Bilder. Dabei wird das Bild in zwei Formaten weitergegeben. Im IplImage und im Mat Format.
    class BildDaten : public Daten
    {
      public:
        BildDaten();
        BildDaten(cv::Mat*, IplImage*);
        virtual ~BildDaten();
        cv::Mat* leseMat() const;
        IplImage* leseImg() const;
    
      private:
        friend class boost::serialization::access; 
    
        template <typename Archive>
        void save(Archive &ar, const unsigned int version)
        {
          ar << boost::serialization::base_object<Daten>(*this); 
    
          // Wir extrahieren die Bildeigenschaften.
          int height = Img->height;
          int width = Img->width;
          int nChannels = Img->nChannels;
          int depth = Img->depth;
          int size = Img->imageSize;
          char* data = Img->imageData;
    
          ar << width << height << depth << nChannels << size;
          ar << boost::serialization::binary_object(data, size);
        };
    
        template <class Archive>
        void load(Archive &ar, const unsigned int version)
        {
          int height, width, nChannels, depth, size;
          char* data;
    
          ar >> width >> height >> depth >> nChannels >> size;
    
          Img = cvCreateImage(cvSize(width,height), depth, nChannels);
    
          ar >> boost::serialization::binary_object(Img->imageData, size);
        }
    
        cv::Mat* Mat;
        IplImage* Img;
    };
    #endif
    

    Das klappt eigentlich wunderbar. Der Kode lässt sich kompilieren und ausführen. Ein binäres Archiv wird geöffnet und ein Bild darin gespeichert (denke ich, denn es ist ein Bild und 70KB groß).
    Will ich es aber wieder aus dem Archiv holen bekomme ich eine Nullpointerexception.

    BildDaten* B;
      Bildarchiv >> B;
      IplImage* Img;
      Img = B->leseImg();
      int height = Img->height;
    

    Ich vermute stark es liegt an der Zuweise zum Zeiger Img!? Die Zuweisung ist doch nur innerhalb der Methode load() gültig, oder?
    Hat mir jemand einen Tipp oder weiß woran es liegt?

    Gruß fabske



  • Was genau macht denn die Anweisung "Bildarchiv >> B;"?

    Soll der Streaming-Operator wirklich auf einem Zeiger von BildDaten arbeiten und nicht direkt auf einem Bilddaten-Objekt?

    Schau doch einfach mit dem Debugger nach, welche Variable konkret falsch gesetzt ist.



  • Anscheinend gibt es Probleme mit der Speicherverwaltung. So sieht mein Programm aus, welches das Bild ins Archiv serialisiert:

    BD ist ein Zeiger auf ein Objekt vom Typ BildDaten() und bereits vorhanden!
    
        boost::archive::binary_oarchive Bildarchiv("Bilder");
    
        // im 2. Takt schieben wir das Bild rein.
        if(Takt==2)
        {
          // vorher geben wir mal die Werte aus
          IplImage* Img;
          Img = BD->leseImg();
    
          int height = Img->height;
          int width = Img->width;
          int nChannels = Img->nChannels;
          int depth = Img->depth;
          int size = Img->imageSize;
          char* data = Img->imageData;
    
          std::stringstream ausgabe;
          ausgabe << "width: " << width << " height: " << height << " depth: "<< depth << " channels: " << nChannels << " size: " << size << std::endl;
          cout << ausgabe.str();
    
          Bildarchiv << BD;
        }
    

    Soweit so gut. Es entsteht eine Binärdatei "Bilder" mit aber nur 64 Byte! Kann das sein? Funktioniert ar << boost::serialization::binary_object(data, size); nicht?

    Nun will ich das Bild in einem anderen Programm wieder raus holen:

    BildDaten* B = new BildDaten();
    
      Bildarchiv >> B;
    
      std::stringstream ausgabe1;
      ausgabe1 << "Takt: " <<  B->leseTakt() << "  Ersteller: " << B->leseErsteller() << "  Erstellungszeit: " << B->leseErstellungszeit() << std::endl;
      HIRN::schreiben(ausgabe1.str());
    
      IplImage* Img = B->leseImg();
    
          std::cout << "AAA\n";
    
          int height = Img->height;
          int width = Img->width;
          int nChannels = Img->nChannels;
          int depth = Img->depth;
          int size = Img->imageSize;
          //char* data = Img->imageData;
    
          std::stringstream ausgabe;
          ausgabe << "width: " << width << " height: " << height << " depth: "<< depth << " channels: " << nChannels << " size: " << size << std::endl;
          std::cout << ausgabe.str();
    
          std::cout << "BBB\n";
    

    Ich erstelle eine Zeiger auf BildDaten() B und erzeuge ein Objekt, ansonsten hab ich ja keinen Speicher allokiert. Aber der Zeiger in B auf ein IplImage hat ja keinen Speicher allokiert! Ist das ein Problem?



  • Du musst vor dem deserialisieren kein Objekt anlegen. Das macht boost.serialization bei Serialisierung durch Pointer selbst. Freigeben musst Du es dann am Ende aber wieder.
    Hast Du mal geguckt, welchen Wert der size -Parameter beim Serialisieren hat? So ca. 64 vllt.?

    Lies evtl. auch mal das hier und auch die anderen Themen zur Pointerserialisierung in der Doku...



  • In der Tat! sizeof(data) hat den Wert 4! (VOR dem Serialisieren, also das ganz normale Bild) Aber warum??



  • fabske schrieb:

    In der Tat! sizeof(data) hat den Wert 4! (VOR dem Serialisieren, also das ganz normale Bild) Aber warum??

    Bekommt bei int size = Img->imageSize das imageSize seine Größe über sizeof(data) zugewiesen?
    Dann liegt es daran, dass data ein Pointer ist, und sizeof(T*) liefert Dir die Größe eines Pointers auf Deiner Plattform (also wohl 4).

    Wenn Du mit rohen Array-Objekten auf dem Heap hantierst, musst Du die Größe immer mitspeichern. Oder Du benutzt std::vector . Der macht das für Dich automatisch.



  • Eigentlich ist es so in Ordnung und wie du gesagt hast!

    int size = Img->imageSize;
          char* data = Img->imageData;
    
          std::stringstream ausgabe;
          ausgabe << "size: " << size << " sizeof: " << sizeof(Img->imageData) << std::endl;
    

    Heraus kommt: size: 1082880 sizeof: 4

    Aber warum zum Henker serialisiert er denn dann nicht??

    ar << boost::serialization::make_binary_object(data, size);

    muss doch funktionieren?


Anmelden zum Antworten