[SOLVED] save QVector<QImage> to QDataStream and read back



  • I'm trying to save and load QVector<QImage> to a file with QDataStream using this code :

    for saving
    @
    QFile file("students_dataset.dat");
    file.open(QIODevice::WriteOnly);
    QDataStream out(&file);
    out << qimgvect ;
    file.flush();
    file.close();
    @

    for loading

    @
    QFile file("students_dataset.dat");
    file.open(QIODevice::ReadOnly);
    QDataStream in(&file);
    QVector<QImage> qimgvect;
    in >> qimgvect;
    file.close();
    @

    but i get a weird result :
    !http://i.stack.imgur.com/9lJb1.png(saveed)! saved
    !http://i.stack.imgur.com/sMsnL.png(loaded)! loaded

    what is wrong with this code?
    is there a better way to do it ?



  • I use the same code with more complicated "structure" with images B&W and for me it's work. However I limited with 53 images in my datastream but i think it's size of my images which are too big (10800*480) ...



  • Some idea:
    I pass the size of my vector in my stream at wirte. And after the contents:
    @
    QFile file("students_dataset.dat");
    file.open(QIODevice::ReadOnly);
    QDataStream in(&file);
    int nbImages =-1;
    in >> nbImages;
    QVector<QImage> qimgvect;
    for(int i=0; i<nbImages ;i++)
    {
    QImage img;
    in >> img;
    qimgvect.append(img);
    }
    file.close();
    @

    Try this...



  • thank you for replay , but do you mean that the problem is in the
    @ QDataStream << Qvector<T> @

    not in QImage

    the image size is only 70x70 and i was testing with few images



  • No no I didn't say that the problem is in QVector but for a my progress dialog I use this code.
    Try it and say me something.



  • thanks for help, I have tried as you suggested but i got the same results
    here is the saving part :
    @
    QFile file("students_dataset.dat");
    file.open(QIODevice::WriteOnly);
    QDataStream out(&file);
    qimgvect.clear();
    int nbImages = qimgvect.size();
    out << nbImages;
    for(int i=0; i<nbImages ;i++)
    {
    QImage img = qimgvect.value(i);
    out << img;
    }
    file.flush();
    file.close();
    @

    I think the problem is in the image format ( indexed8) but I'm not that good to figure it out



  • Oh ! of course ! By default the format is RGB32bit
    try this:

    @
    QVector<QRgb> grayscale;
    for (int i = 0; i < 256; ++i)
    grayscale.append(qRgb(i, i, i));

    QFile file("students_dataset.dat");
    file.open(QIODevice::ReadOnly);
    QDataStream in(&file);
    int nbImages =-1;
    in >> nbImages;
    QVector<QImage> qimgvect;
    for(int i=0; i<nbImages ;i++)
    {
    QImage img;
    in >> img;
    img = img.conconvertToFormat(QImage::Format_Indexed8,grayscale);
    qimgvect.append(img);
    }
    file.close();
    @



  • thanks that was a great step ahead , do I need to change the format also before saving because the result is :
    !http://i.stack.imgur.com/Y8LLI.png(result)!



  • If you want use QImage with B&W You must fill image with grayscale !!!

    When you write your image :
    @QVector<QRgb> grayscale;
    for (int i = 0; i < 256; ++i)
    grayscale.append(qRgb(i, i, i));

    QImage img;
    img.fill(grayscale);
    // And now your can write in your image with img.setPixel(x,y,0..255);
    @



  • sorry for taking long , the original image is already in (indexed8) format and it's filled before so i'm asking if i should convert it to RGB32 before saving , any suggestion would be appreciated, thanks



  • No you don't have to convert before saving can you send me your code ?



  • do i post it here or send it in another way ?



  • you can send me francknos[at]gmail.com



  • @
    void savedata(const std::vectorcv::Mat* MatVect,const std::vector<int>* intVect){
    QFile file("students_dataset.dat");
    file.open(QIODevice::WriteOnly);
    QDataStream out(&file);
    qimgvect.clear();
    for (size_t i = 0; i < MatVect->size(); ++i) {
    cv::Mat matt = MatVect->at(i);
    QImage img= Mat2QImage(matt);
    qimgvect.push_back(img);
    }
    QVector<int> qintvect = QVector<int>::fromStdVector(*intVect);

        int nbImages = qimgvect.size();
        out << nbImages;
        for(int i=0; i<nbImages ;i++)
        {
            QImage img = qimgvect.value(i);
            out << img;
        }
        out  << qintvect;
        file.flush();
        file.close();
        return;
    

    }

    void loadData(std::vectorcv::Mat* MatVect,std::vector<int>* intVect){
    QFile file("students_dataset.dat");
    file.open(QIODevice::ReadOnly);
    QDataStream in(&file);
    qimgvect.clear();
    MatVect->clear();
    QVector<int> qintvect ;
    int nbImages =-1;
    QVector<QRgb> grayscale;
    for (int i = 0; i < 256; ++i) grayscale.append(qRgb(i, i, i));

    in >> nbImages;
    for(int i=0; i<nbImages ;i++)
    {
         QImage img;
         in >> img;
         img = img.convertToFormat(QImage::Format_Indexed8,grayscale);
         qimgvect.push_back(img);
    }
    in >> qintvect;
    
    for (size_t i = 0; i < qimgvect.size(); ++i) {
        QImage img = qimgvect.value(i);
        cv::Mat matt = QImage2Mat(img);
        MatVect->push_back(matt);
    }
    *intVect  = qintvect.toStdVector();
    file.close();
    return;
    

    }
    @



  • Are you sure that
    @QImage img= Mat2QImage(matt);@
    construct a Image Index_8 ?
    try qDebug on each pixel of img and look if all pixel are between 0 and 255.
    Or try to convert in written:
    @
    for (size_t i = 0; i < MatVect->size(); ++i)
    {
    cv::Mat matt = MatVect->at(i);
    QImage img= Mat2QImage(matt).convertToFormat(QImage::Format_Indexed8,grayscale);
    qimgvect.push_back(img);
    }
    @



  • Here is the the function :
    @
    QImage Mat2QImage(cv::Mat const& src)
    {
    cv::Mat temp; // make the same cv::Mat
    src.copyTo(temp);
    QImage dest((const uchar *) temp.data, temp.cols, temp.rows, temp.step, QImage::Format_Indexed8);
    dest.bits(); // enforce deep copy
    return dest;
    }
    @
    I've converted them as you suggested also I've checked using
    @qDebug() << QString::number(img.isGrayscale());@

    the result was always 1
    all the image have the same effect : image repeated 4 times horizontally inside itself like shown :
    !http://i.stack.imgur.com/Y8LLI.png(img)!
    thanks again for your help



  • try this function :
    @
    /* OpenCV ===========================================================================/
    QImage cvtCvMat2QImage(const cv::Mat & image, bool isBgr)
    {
    QImage qtemp;
    if(!image.empty() && image.depth() == CV_8U)
    {
    if(image.channels()==3)
    {
    const unsigned char * data = image.data;
    if(image.channels() == 3)
    {
    qtemp = QImage(image.cols, image.rows, QImage::Format_RGB32);
    for(int y = 0; y < image.rows; ++y, data += image.cols
    image.elemSize())
    {
    for(int x = 0; x < image.cols; ++x)
    {
    QRgb * p = ((QRgb*)qtemp.scanLine (y)) + x;
    if(isBgr)
    {
    *p = qRgb(data[x * image.channels()+2], data[x * image.channels()+1], data[x * image.channels()]);
    }
    else
    {
    *p = qRgb(data[x * image.channels()], data[x * image.channels()+1], data[x * image.channels()+2]);
    }
    }
    }
    }
    }
    else if(image.channels() == 1)
    {
    // mono grayscale
    qtemp = QImage(image.data, image.cols, image.rows, image.cols, QImage::Format_Indexed8).copy();
    QVector<QRgb> my_table;
    for(int i = 0; i < 256; i++) my_table.push_back(qRgb(i,i,i));
    qtemp.setColorTable(my_table);
    }
    else
    {
    printf("Wrong image format, must have 1 or 3 channels\n");
    }
    }
    return qtemp;
    }

    cv::Mat cvtQImage2CvMat(const QImage & image)
    {
    cv::Mat cvImage;
    if(!image.isNull() && image.depth() == 32 && image.format() == QImage::Format_RGB32)
    {
    // assume RGB (3 channels)
    int channels = 3;
    cvImage = cv::Mat(image.height(), image.width(), CV_8UC3);
    unsigned char * data = cvImage.data;
    for(int y = 0; y < image.height(); ++y, data+=cvImage.cols*cvImage.elemSize())
    {
    for(int x = 0; x < image.width(); ++x)
    {
    QRgb rgb = image.pixel(x, y);
    data[x * channels+2] = qRed(rgb); //r
    data[x * channels+1] = qGreen(rgb); //g
    data[x * channels] = qBlue(rgb); //b
    }
    }
    }
    else
    {
    printf("Failed to convert image : depth=%d(!=32) format=%d(!=%d)\n", image.depth(), image.format(), QImage::Format_RGB32);
    }
    return cvImage;
    }

    QImage cvtIplImage2QImage(const IplImage * image)
    {
    QImage qtemp;
    if (image && image->depth == IPL_DEPTH_8U && cvGetSize(image).width>0)
    {
    const char * data = image->imageData;
    qtemp= QImage(image->width, image->height,QImage::Format_RGB32);

        for(int y = 0; y < image->height; ++y, data +=image->widthStep )
        {
            for(int x = 0; x < image->width; ++x)
            {
                uint *p = (uint*)qtemp.scanLine (y) + x;
                *p = qRgb(data[x * image->nChannels+2], data[x * image->nChannels+1],data[x * image->nChannels]);
            }
        }
    }
    else if(image && image->depth != IPL_DEPTH_8U)
    {
        printf("Wrong iplImage format, must be 8_bits\n");
    }
    return qtemp;
    

    }

    // Returned image must be released explicitly (using cvReleaseImage()).
    IplImage * cvtQImage2IplImage(const QImage & image)
    {
    IplImage * iplTmp = 0;
    if(!image.isNull() && image.depth() == 32 && image.format() == QImage::Format_RGB32)
    {
    // assume RGB (3 channels)
    int channels = 3;
    iplTmp = cvCreateImage(cvSize(image.width(), image.height()), IPL_DEPTH_8U, channels);
    char * data = iplTmp->imageData;
    for(int y = 0; y < image.height(); ++y, data+=iplTmp->widthStep)
    {
    for(int x = 0; x < image.width(); ++x)
    {
    QRgb rgb = image.pixel(x, y);
    data[x * channels+2] = qRed(rgb); //r
    data[x * channels+1] = qGreen(rgb); //g
    data[x * channels] = qBlue(rgb); //b
    }
    }
    }
    else
    {
    printf("Failed to convert image : depth=%d(!=32) format=%d(!=%d)\n", image.depth(), image.format(), QImage::Format_RGB32);
    }
    return iplTmp;
    }
    @



  • thank you Francknos for keeping up with me, I have tried converting the image before saving and it did solve the problem
    @ img = img.convertToFormat(QImage::Format_ARGB32); @

    Here is the saving part now :
    @
    QFile file("students_dataset.dat");
    file.open(QIODevice::WriteOnly);
    QDataStream out(&file);
    qimgvect.clear();
    int nbImages = qimgvect.size();
    out << nbImages;
    for(int i=0; i<nbImages ;i++)
    {
    QImage img = qimgvect.value(i);
    img = img.convertToFormat(QImage::Format_ARGB32);
    out << img;
    }
    file.flush();
    file.close();
    @
    Format_ARGB32 is the reason for the effect in the result ( 4 channels )
    I'll try to elemenate the for loop and post back .
    thank you !



  • Glad it's works !!



  • SO Here is the final solution :
    for saving grayscale Qimage through *QDataStream * convert it to Format_ARGB32 then save it, for loading convert it back to Format_Indexed8 :
    saving code
    @
    QFile file("students_dataset.dat");
    file.open(QIODevice::WriteOnly);
    QDataStream out(&file);
    //converting to ARGB32
    foreach (QImage img, qimgvect) {
    img = img.convertToFormat(QImage::Format_ARGB32);
    }
    // saving to QDataStream
    out << qimgvect ;
    file.flush();
    file.close();
    @
    for loading
    @
    QFile file("students_dataset.dat");
    file.open(QIODevice::ReadOnly);
    QDataStream in(&file);
    QVector<QImage> qimgvect;
    // loading images vector from QDatastream
    in >> qimgvect;
    // converting to grayscale
    QVector<QRgb> grayscale;
    for (int i = 0; i < 256; ++i) grayscale.append(qRgb(i, i, i));
    for (int i, i < qimgvect.size(),i++) {
    QImage img = qimgvect.at(i).convertToFormat(QImage::Format_Indexed8,grayscale);
    qimgvect.push_back(img);
    }
    file.close();
    @

    I think even QImage with other Formats will face the same problem since it is assumed that the default format is Format_ARGB32


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.