2012-06-23 95 views
4

我想创建一个应用程序,我试图整合opencv和qt。Qimage 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 ::垫:

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

我没有成功,结果是完全无序的图像。在我搜索的网络中,我看到人们使用这种方式而没有提到任何具体问题。有人有任何想法,关于可能导致问题的原因?提前致谢。

Theoodore

P.S.我使用的OpenCV 2.4和Qt 4.8,一个Arch Linux的系统下使用gnome-3.4

回答

0

OpenCV的图像呈阶梯状,使每一行上32位的倍数开始,这使得内存访问速度更快。如果您使用的是3byte /像素格式,那么除非您的宽度是4的倍数的1/3,否则每行末尾都会有'备用'内存

安全的方法是复制图像数据一次一行。 OpenCV的mat.ptr(行)返回一个指针,每行的开始和QImage的.scanline(行)成员不相同

How to output this 24 bit image in Qt

编辑:喜欢的东西

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

我改变了代码 “CV ::垫QImage的” 到 CV :: cvtColor(tmpImage,图像,CV_BGR2RGB); uchar * buffer = image.ptr(); img = QImage(buffer,image.cols,image.rows,image.step,QImage :: Format_RGB888); imgLabel-> setPixmap(QPixmap :: fromImage(img)); imgLabel-> resize(imgLabel-> pixmap() - > size()); 但它似乎没有任何影响。我认为的问题是如何正确地将“QImage”转换为cv :: Mat。 – ThT

+0

不,你必须循环遍历所有行,一次复制一个,因为它们不一定是连续的格式之一,请参阅链接中的代码 –

0

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

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

0

确定现在按照你的指示我的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我得到的图像极坏......

+0

好吧,我在memcpy()行中有一个错误,我不得不在image.ptr(i)和img.scanLine(i)之间切换。现在可以,Qimage拥有cv :: Mat的所有信息。但是现在我怎么从Qimage去cv :: Mat,我必须做同样的事情,但是相反的顺序呢? – ThT

+0

的确按照相反的顺序进行操作: - )...感谢@Martin Beckett p.s.当然你仍然需要改变你的最终矩阵的rgb到bgr的频道顺序 – ThT

0

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

OP想要QImage到Mat –

0

这是我从here thanks to jose.它帮助我渡过这个了。

形象化OpenCV的图像(CV :: MAT)在QT(QImage的),你必须遵循以下步骤:

  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 ::格式。在这个问题上阅读Qt。

+0

OP要QImage到cv :: Mat –

2

只要找到了复制(不参考)的QImage到CV的“正确”的解决方案::垫

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

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 ocated ::垫可能不具有相同的“bytesperline”为QImage的

我找到的解决方案是采取的QImage的参考,然后再复制它

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

马丁的解决方案贝克特建议可以在大多数时间产生正确的结果,我没有注意到有一个错误,直到我打它。

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

0

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

了Cv ::垫的QImage:

QImage的Mat2QImage(CV ::垫&图) {

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 ::垫QImage2Mat(QImage的&图像){

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