2015-11-25 13 views
6

voglio leggere un'immagine da un QRC utilizzando imread() di OpenCV in questo modo:Leggi un'immagine da un QRC utilizzando imread() di OpenCV

Mat img = imread(":/TempIcons/logo.png"); 

ma la img dimensione finale è [0x0] . Ho anche provato:

Mat img = imread("qrc://TempIcons/logo.png"); 

ma la dimensione che ottengo è la stessa. Non voglio caricare l'immagine in un QImage per trasformarlo in un cv::Mat. C'è un modo per farlo in un modo semplice? Se lo è, come posso farlo?

Grazie

+0

Ciao, grazie per il suggerimento, ma ho già provato, ma che ottengo da 'QFileInfo (" QRC ... . ") .filePath()' è sempre lo stesso percorso: ": /TempIcons/logo.png" –

risposta

7

Come @TheDarkKnight ha sottolineato, imread non è a conoscenza delle risorse Qt. È comunque possibile scrivere il proprio loader, che utilizza QFile per recuperare i dati binari dalla risorsa, e utilizza imdecode (come fatto internamente da imread) per leggere l'immagine:

Mat loadFromQrc(QString qrc, int flag = IMREAD_COLOR) 
{ 
    //double tic = double(getTickCount()); 

    QFile file(qrc); 
    Mat m; 
    if(file.open(QIODevice::ReadOnly)) 
    { 
     qint64 sz = file.size(); 
     std::vector<uchar> buf(sz); 
     file.read((char*)buf.data(), sz); 
     m = imdecode(buf, flag); 
    } 

    //double toc = (double(getTickCount()) - tic) * 1000.0/getTickFrequency(); 
    //qDebug() << "OpenCV loading time: " << toc; 

    return m; 
} 

si può chiamare come:

Mat m = loadFromQrc("qrc_path"); 

o specificando una bandiera:

Mat m = loadFromQrc("qrc_path", IMREAD_GRAYSCALE); 

Rappresentazione

Ho provato caricamento dell'immagine con loadFromQrc, e caricando il QImage e conversione in Mat utilizzando this codice, con e senza la clonazione. I risultati di loadFromQrc sono 10 volte più veloci, quindi il caricamento di QImage e la conversione in Mat.

Risultati in ms:

Load Mat    : 4.85965 
QImage to Mat (no clone): 49.3999 
QImage to Mat (clone) : 49.8497 

codice di prova:

#include <vector> 
#include <iostream> 
#include <QDebug> 
#include <QtWidgets> 

#include <opencv2/opencv.hpp> 
using namespace cv; 

Mat loadFromQrc(QString qrc, int flag = IMREAD_COLOR) 
{ 
    QFile file(qrc); 
    Mat m; 
    if(file.open(QIODevice::ReadOnly)) 
    { 
     qint64 sz = file.size(); 

     std::vector<uchar> buf(sz); 
     file.read((char*)buf.data(), sz); 
     m = imdecode(buf, flag); 
    } 
    return m; 
} 

cv::Mat QImageToCvMat(const QImage &inImage, bool inCloneImageData = true) 
{ 
    switch (inImage.format()) 
    { 
    // 8-bit, 4 channel 
    case QImage::Format_RGB32: 
    { 
     cv::Mat mat(inImage.height(), inImage.width(), CV_8UC4, const_cast<uchar*>(inImage.bits()), inImage.bytesPerLine()); 

     return (inCloneImageData ? mat.clone() : mat); 
    } 

     // 8-bit, 3 channel 
    case QImage::Format_RGB888: 
    { 
     if (!inCloneImageData) 
      qWarning() << "ASM::QImageToCvMat() - Conversion requires cloning since we use a temporary QImage"; 

     QImage swapped = inImage.rgbSwapped(); 

     return cv::Mat(swapped.height(), swapped.width(), CV_8UC3, const_cast<uchar*>(swapped.bits()), swapped.bytesPerLine()).clone(); 
    } 

     // 8-bit, 1 channel 
    case QImage::Format_Indexed8: 
    { 
     cv::Mat mat(inImage.height(), inImage.width(), CV_8UC1, const_cast<uchar*>(inImage.bits()), inImage.bytesPerLine()); 

     return (inCloneImageData ? mat.clone() : mat); 
    } 

    default: 
     qWarning() << "ASM::QImageToCvMat() - QImage format not handled in switch:" << inImage.format(); 
     break; 
    } 

    return cv::Mat(); 
} 

int main(int argc, char *argv[]) 
{ 
    QString url = "..."; 

    { 
     double tic = double(getTickCount()); 

     Mat m1 = loadFromQrc(url); 

     double toc = (double(getTickCount()) - tic) * 1000.0/getTickFrequency(); 
     qDebug() << "Load Mat: " << toc; 

     if(m1.data != NULL) 
     { 
      imshow("m1", m1); 
      waitKey(1); 
     } 
    } 


// { 
//  double tic = double(getTickCount()); 

//  QImage img; 
//  img.load(url); 
//  Mat m2 = QImageToCvMat(img, false); 

//  double toc = (double(getTickCount()) - tic) * 1000.0/getTickFrequency(); 
//  qDebug() << "QImage to Mat (no clone): " << toc; 

//  if(m2.data != NULL) 
//  { 
//   imshow("m2", m2); 
//   waitKey(1); 
//  } 
// } 


// { 
//  double tic = double(getTickCount()); 

//  QImage img; 
//  img.load(url); 
//  Mat m3 = QImageToCvMat(img, true); 

//  double toc = (double(getTickCount()) - tic) * 1000.0/getTickFrequency(); 
//  qDebug() << "QImage to Mat (clone): " << toc; 

//  if(m3.data != NULL) 
//  { 
//   imshow("m3", m3); 
//   waitKey(1); 
//  } 
// } 

    waitKey(); 
    return 0; 
} 
+0

Ciao @Miki. Il codice che fornisci è molto utile. Ho testato tempi e risultati che convertono da 'QImage' a' Mat'takes quasi allo stesso tempo in cui si utilizza il codice. –

+0

@AngieQuijano ha aiutato! Considerare nel test QImage to Mat anche il tempo impiegato da QImage per caricare l'immagine. Lo sto verificando proprio ora, quindi posso aggiornare la risposta con maggiori dettagli. – Miki

+2

@AngieQuijano, eseguo alcuni test.Il caricamento di un 'QImage' e la conversione in' Mat' è 10 volte più lento rispetto all'utilizzo di questa funzione. Aggiornato la risposta con i risultati e il codice di prova. – Miki

2

Il problema qui è che imread() carica un'immagine da un file.

Al contrario, il sistema di risorse di Qt compila i dati dalle immagini directly into the program's executable. Le operazioni di Qt su QFile sanno che quando viene fornito un percorso che inizia con ": /", fa riferimento alle risorse incorporate, piuttosto che al disco.

Pertanto, non penso che sarà possibile utilizzare imread() per accedere direttamente a un file che è stato inserito nelle risorse di Qt.

Problemi correlati