Qimage cv :: Mat转换奇怪的行为

我正在尝试创build一个应用程序,我试图整合opencvqt

我成功地通过使用下面的代码成功地将cv :: Mat转换为QImage:

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); } 

但是,当我试图通过使用以下代码将QImage转换为cv :: Mat:

 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; } 

我没有成功,结果是完全混乱的形象。 在我search的networking中,我看到人们用这种方式没有提到任何具体的问题。 有人有任何想法,关于什么可能是造成这个问题? 提前致谢。

Theoodore

PS我正在使用GNOME 3.4下的Arch Linux系统下使用opencv 2.4和Qt 4.8

只要找出复制 (不参考)的QImage到cv :: Mat的“正确”的解决方案

马丁·贝克特的回答几乎是正确的

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

我没有看到完整的代码,但我想你可能想要像这样使用它

 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()); } 

但是这个代码存在一个问题,由cv :: Mat分配的内存可能不像 QImage 那样具有相同的“bytesperline”

我找到的解决方案是先参考QImage,然后克隆它

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

Martin Beckett提出的解决方案在大多数情况下都能产生正确的结果,我没有注意到有一个错误,直到我点击它。

无论如何,我希望这是一个“正确”的解决方案。 如果您发现任何错误,请让每个人都知道,以便我们可以改变代码。

我想你可能会觉得这很有用。 http://www.jdxyw.com/?p=1480

它使用IplImage获取数据,但可以使用cv :: Mat和Mat.data来获取指向原始矩阵的指针。 我希望你会觉得这很有用。

opencv图像是逐步的,以便每行开始在32位的倍数,这使得内存访问速度更快。 如果您使用的是3byte / pixel格式,那么除非您的宽度是4的倍数的1/3,否则您将在每行的末尾有“备用”内存

安全的方法是一次复制一行图像数据。 opencv mat.ptr(row)返回一个指向每一行开始的指针,而QImage .scanline(row)成员也是一样的

请参阅如何在Qt中输出此24位图像

编辑:类似的东西

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

确定按照你的指示现在我的loadFile()函数是这样的:

 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); } 

但是这又似乎不起作用…:(我在QLabel中获得的图像是完全不好的…

从这个源代码

 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() 

这是我从这里得到的, 由于jose。 它帮助我克服这一点。

要在Qt(QImage)中可视化OpenCV图像(cv :: Mat),您必须执行以下步骤:

  1. 反转颜色顺序: cv::cvtColor(imageBGR, imageRGB, CV_BGR2RGB);
  2. 更改格式OpenCV为Qt: QImage qImage((uchar*) imageRGB.data, imageRGB.cols, imageRGB.rows, imageRGB.step, QImage::Format_RGB888);
  3. 使用QPainter来渲染图像。

请注意使用QImage :: Format。 在这个问题上阅读Qt。

如果你仍然在寻找解决方案。 这里是一个:

Cv :: Mat到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; } 

对于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;}