2012-06-23 141 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;}