0

I'm working on face recognition in Qt & openCV using the FisherFaces recognizer which doesn't support updating so i have to save the faces database to retrain the recognizer after any changes.
Here is my code for saving :

save(const std::vector* MatVect){
       QFile file("students_dataset.dat");
       file.open(QIODevice::WriteOnly);
       QDataStream out(&file);
       QVector qimgvect;
       for (size_t i = 0; i < MatVect->size(); ++i) 
       {
                cv::Mat matt = MatVect->at(i);
                QImage img((uchar*)matt.data, matt.cols, matt.rows, matt.step, QImage::Format_Indexed8);
                qimgvect.push_back(img);
        }
       out << qimgvect ;
       file.flush();
       file.close();
    } 

and this is for loading :

load(std::vector* MatVect)
    {
    QFile file("students_dataset.dat");
    file.open(QIODevice::ReadOnly);
    QDataStream in(&file);
    QVector qimgvect;
    in >> qimgvect;
    for (size_t i = 0; i < qimgvect.size(); ++i) 
      {
        QImage img = qimgvect.at(i);
        cv::Mat matt = cv::Mat(70, 70, CV_8U, img.bits(), img.bytesPerLine());
        MatVect->push_back(matt);
      }
    file.close();
    return;
    } 
the problem is that what I read back from the file is not what i saved
saved loaded

so what's exactly wrong in this code (hope not all of it ) ?
is there a better/easier way of saving the vector ?
EDIT :
thanks to Marek_R the conversion part is fixed, but saving and loading with QDataStream is the problem now :
saved loaded
so what's causing those lines ?
EDIT :
I have tried this :
made QimgVect public and elemenated QDataStream part : MatVect-> QimgVect than QimgVect->MatVect and it did work fine, but after adding QDataStream : MatVect-> QimgVect->QDataStream and QDataStream->QimgVect->MatVect i get get the result shown above( vertical white lines ).
EDIT
converting the image from RGB32 to Indexed8 after reading from qdatastream gives the following result :
enter image description here

Chebhou
  • 148
  • 1
  • 16
  • image on the left is larger than image on the right, i guess, 70x70 is wrong – berak Sep 27 '14 at 11:40
  • i tried `img.width(), img.height()` before but i got the same result ,so i used 70x70 because all the images are 70x70 as a result of some processioning. – Chebhou Sep 27 '14 at 12:50

2 Answers2

1

this is memory management issue. When you create matrix from piece of memory copy of this memory is not created. At the same time this memory is disposed when QImage goes out of the scope.

Check answer about converting between QImage and cv:Mat (there is a better link in comment but for some reason page is not working so I didn't provided this link here).

When you are coping cv::Mat only a shallow copy is created. Actual Matrix contents is not copied. See cv::Mat constructor documentation:

m – Array that (as a whole or partly) is assigned to the constructed matrix. No data is copied by these constructors. Instead, the header pointing to m data or its sub-array is constructed and associated with it. The reference counter, if any, is incremented. So, when you modify the matrix formed using such a constructor, you also modify the corresponding elements of m . If you want to have an independent copy of the sub-array, use Mat::clone()

Community
  • 1
  • 1
Marek R
  • 32,568
  • 6
  • 55
  • 140
  • `qimgvect.push_back(img)` is taking a copy of the `img` before it goes out of scope – Chebhou Sep 28 '14 at 10:40
  • thank you that was the problem, here is what made me think it's copied [Q_about vector](http://stackoverflow.com/questions/2422273/one-question-about-vector-push-back), but now i have a new problem in `QDataStream` because i tested the code without it and it was working fine ,please see the edit – Chebhou Sep 28 '14 at 21:32
0

SO Here is a 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

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Chebhou
  • 148
  • 1
  • 16