Qimage to cv :: Mat convertion weird behavior

I am trying to create an application in which I am trying to integrate opencv and qt.

I was able to successfully convert cv :: Mat to QImage using the following code:

void MainWindow::loadFile(const QString &fileName) { cv::Mat tmpImage = cv::imread(fileName.toAscii().data()); cv::Mat image; if(!tmpImage.data || tmpImage.empty()) { QMessageBox::warning(this, tr("Error Occured"), tr("Problem loading file"), QMessageBox::Ok); return; } /* Mat to Qimage */ cv::cvtColor(tmpImage, image, CV_BGR2RGB); img = QImage((const unsigned char*)(image.data), image.cols, image.rows, QImage::Format_RGB888); imgLabel->setPixmap(QPixmap::fromImage(img)); imgLabel->resize(imgLabel->pixmap()->size()); saveAsAct->setEnabled(true); } 

However, when I try to convert QImage to cv :: Mat using the following code:

 bool MainWindow::saveAs() { if(fileName.isEmpty()) { QMessageBox::warning(this, tr("Error Occured"), tr("Problem loading file"), QMessageBox::Close); return EXIT_FAILURE; }else{ outputFileName = QFileDialog::getSaveFileName(this, tr("Save As"), fileName.toAscii().data(), tr("Image Files (*.png *.jpg *.jpeg *.bmp)\n *.png\n *.jpg\n *.jpeg\n *.bmp")); /* Qimage to Mat */ cv::Mat mat = cv::Mat(img.height(), img.width(), CV_8UC4, (uchar*)img.bits(), img.bytesPerLine()); cv::Mat mat2 = cv::Mat(mat.rows, mat.cols, CV_8UC3 ); int from_to[] = {0,0, 1,1, 2,2}; cv::mixChannels(&mat, 1, &mat2, 1, from_to, 3); cv::imwrite(outputFileName.toAscii().data(), mat); } saveAct->setEnabled(true); return EXIT_SUCCESS; } 

I have no success, and the result is completely erratic. On the network I was looking for, I saw that people use this method without mentioning any specific problems. Does anyone have any ideas what could be causing the problem? Thanks in advance.

Theoodore

PS I am using opencv 2.4 and Qt 4.8 on an Arch Linux system with gnome-3.4

+4
source share
7 answers

Just find the “right” solution to copy (not link) QImage to cv :: Mat

Martin Beckett's answer is almost right.

 for (int i=0;i<image.height();i++) { memcpy(mat.ptr(i),image.scanline(i),image.bytesperline()); } 

I don’t see the full codes, but I think you can use it that way

 cv::Mat mat(image.height(), image.width(), CV_8UC3); for (int i=0;i<image.height();i++) { memcpy(mat.ptr(i),image.scanline(i),image.bytesperline()); } 

But this code exists, the memory allocated by cv :: Mat may not have , have the same "byte string" as QImage

The solution I found first takes a QImage link, then clones it

 return cv::Mat(img.height(), img.width(), format, img.bits(), img.bytesPerLine()).clone(); 

Martin Beckett's decision could lead to the correct result in most of the time I did not notice that there was an error until I hit it.

Be that as it may, I hope this is the “right” decision. If you find any errors, please everyone knows that we may have a change to improve the codes.

+2
source

opencv images are stepwise, so each line starts with a multiple of 32 bits, which speeds up memory access. If you use a format of 3 bytes / pixels, then if you do not have a width of 1/3 of a multiple of 4, you will have a “spare” memory at the end of each line

A safe way is to copy image data line by line at a time. Opencv mat.ptr (string) returns a pointer to the beginning of each line, and the QImage.scanline (row) member does the same

See How to output this 24-bit image in Qt

edit: Something like

 for (int i=0;i<image.height();i++) { memcpy(mat.ptr(i),image.scanline(i),image.bytesperline()); } 
0
source

I think you may find this helpful. http://www.jdxyw.com/?p=1480

It uses IplImage to get the data, but you can use cv :: Mat and Mat.data to get a pointer to the source matrix. Hope you find this helpful.

0
source

ok, following your instructions, now my loadFile () function looks like this:

 void MainWindow::loadFile(const QString &fileName) { cv::Mat image = cv::imread(fileName.toAscii().data()); if(!image.data || image.empty()) { QMessageBox::warning(this, tr("Error Occured"), tr("Problem loading file"), QMessageBox::Ok); return; } cv::cvtColor(image, image, CV_BGR2RGB); img = QImage(image.cols, image.rows, QImage::Format_RGB888); for (int i = 0; i < img.height(); i++) { // scanLine returns a ptr to the start of the data for that row // memcpy(image.ptr(i), img.scanLine(i), img.bytesPerLine());//wrong memcpy(img.scanLine(i), image.ptr(i), img.bytesPerLine()); //correct } imgLabel->setPixmap(QPixmap::fromImage(img)); imgLabel->resize(imgLabel->pixmap()->size()); saveAsAct->setEnabled(true); } 

but this again does not work ... :-( the image I get in QLabel is absolutely bad ...

0
source

From this source code

 QImage MatToQImage(const Mat& mat) { // 8-bits unsigned, NO. OF CHANNELS=1 if(mat.type()==CV_8UC1) { // Set the color table (used to translate colour indexes to qRgb values) QVector<QRgb> colorTable; for (int i=0; i<256; i++) colorTable.push_back(qRgb(i,i,i)); // Copy input Mat const uchar *qImageBuffer = (const uchar*)mat.data; // Create QImage with same dimensions as input Mat QImage img(qImageBuffer, mat.cols, mat.rows, mat.step, QImage::Format_Indexed8); img.setColorTable(colorTable); return img; } // 8-bits unsigned, NO. OF CHANNELS=3 if(mat.type()==CV_8UC3) { // Copy input Mat const uchar *qImageBuffer = (const uchar*)mat.data; // Create QImage with same dimensions as input Mat QImage img(qImageBuffer, mat.cols, mat.rows, mat.step, QImage::Format_RGB888); return img.rgbSwapped(); } else { qDebug() << "ERROR: Mat could not be converted to QImage."; return QImage(); } } // MatToQImage() 
0
source

Here is what I got from here thanks to jose. It helps me overcome this.

To render an OpenCV image (cv :: Mat) in Qt (QImage), you must follow these steps:

  • Invert the color sequence: cv::cvtColor(imageBGR, imageRGB, CV_BGR2RGB);
  • Change OpenCV format to Qt: QImage qImage((uchar*) imageRGB.data, imageRGB.cols, imageRGB.rows, imageRGB.step, QImage::Format_RGB888);
  • Use QPainter to render the image.

Note the use of QImage :: Format. Read Qt on this issue.

0
source

if you are still looking for a solution. here is one:

Cv :: Mat to QImage:

QImage Mat2QImage (cv :: Mat & image) {

 QImage qtImg; if( !image.empty() && image.depth() == CV_8U ){ if(image.channels() == 1){ qtImg = QImage( (const unsigned char *)(image.data), image.cols, image.rows, QImage::Format_Indexed8 ); } else{ cvtColor( image, image, CV_BGR2RGB ); qtImg = QImage( (const unsigned char *)(image.data), image.cols, image.rows, QImage::Format_RGB888 ); } } return qtImg; } 

For QImage cv :: Mat.

cv :: Mat QImage2Mat (QImage & image) {

 cv::Mat cvImage; switch (image.format()){ case QImage::Format_RGB888:{ cvImage = cv::Mat(image.height(), image.width(), CV_8UC3, image.bits(), image.bytesPerLine()); cv::cvtColor(cvImage, cvImage, CV_RGB2BGR); return cvImage; } case QImage::Format_Indexed8:{ cvImage = cv::Mat(image.height(), image.width(), CV_8U, image.bits(), image.bytesPerLine()); return cvImage; } default: break; } return cvImage;} 
0
source

All Articles