2013-06-15 18 views
14

// Mi scuso per il mio inglese.cv :: Mat to QImage and back

Dimmi, per favore, cosa sto facendo male? Ho letto molto su questo. E scrivi del codice, ma ho un risultato terribile.

Se ho ben capito in Opencv CV_8UC3 è lo stesso di QImage :: Format_RGB888, tranne BRG e RGB di conseguenza.

leggere cv :: Mat in questo formato che posso fare:

cv::Mat mat1 = cv::imread("bugero.jpg",3); 

Così, per convertire cv :: Mat a QImage che posso fare:

QImage Mat2QImage(cv::Mat const& src) 
{ 
    cv::Mat temp(src.cols,src.rows,src.type()); 
    cvtColor(src, temp,CV_BGR2RGB); 
    QImage dest= QImage((uchar*) temp.data, temp.cols, temp.rows, temp.step, QImage::Format_RGB888); 
    return dest; 
} 

ho fatto mat Temp siccome Voglio avere una copia dei dati in QImage.

Quindi. Per riconvertirlo che devo fare:

cv::Mat QImage2Mat(QImage const& src) 
{ 
    QImage temp = src.copy(); 
    cv::Mat res(temp.height(),temp.width(),CV_8UC3,(uchar*)temp.bits(),temp.bytesPerLine()); 
    cvtColor(res, res,CV_BGR2RGB); 
    return res; 
} 

ho inserito cvtColor (res, res, CV_BGR2RGB); per fare cv Mat con i colori BGR. Non so esattamente cosa all'interno di questa funzione cvtColor (res, res, CV_BGR2RGB);, ma ho deciso che se cvtColor (res, res, CV_BGR2RGB); cambia i posti R e B, che rilasceranno i posti di questi colori, perché non ho trovato CV_BGR2RGB.

Così, ho scritto programma di esempio breve

#include <QApplication> 
#include <QtGui> 
#include <cv.h> 
#include "opencv2/highgui/highgui.hpp" 

QImage Mat2QImage(cv::Mat const& src) 
{ 
    cv::Mat temp(src.cols,src.rows,src.type()); // make the same cv::Mat 
    cvtColor(src, temp,CV_BGR2RGB); // cvtColor Makes a copt, that what i need 
    QImage dest= QImage((uchar*) temp.data, temp.cols, temp.rows, temp.step, QImage::Format_RGB888); 
    return dest; 
} 

cv::Mat QImage2Mat(QImage const& src) 
{ 
    QImage temp = src.copy(); 
    cv::Mat res(temp.height(),temp.width(),CV_8UC3,(uchar*)temp.bits(),temp.bytesPerLine()); 
    cvtColor(res, res,CV_BGR2RGB); // make convert colort to BGR ! 
    return res; 
} 


int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    QWidget W1; 
    QWidget W2; 
    QLabel imlab1(&W1); 
    QLabel imlab2(&W2); 
    W1.setWindowTitle("Convert cv::Mat to QImage First time"); 
    W2.setWindowTitle("Convert cv::Mat to QImage Second time");  




    cv::Mat mat1 = cv::imread("bugero.jpg",3); 

    QImage qim1 = Mat2QImage(mat1); 

    cv::Mat mat2 = QImage2Mat(qim1); 

    QImage qim2 = Mat2QImage(mat2); 

    cv::Mat mat3 = QImage2Mat(qim2); 



    cv::imshow("First Mat",mat1); 
    imlab1.setPixmap(QPixmap::fromImage(qim1)); 
    W1.setFixedSize(qim1.size()); 
    cv::imshow("Convert QImage to cv::Mat firstly",mat2); 
    imlab2.setPixmap(QPixmap::fromImage(qim2)); 
    W2.setFixedSize(qim2.size()); 
    cv::imshow("Convert QImage to cv::Mat secondly",mat2); 
    W1.show(); 
    W2.show(); 

    return a.exec(); 
} 

e il file .pro

INCLUDEPATH += /usr/local/include/opencv /usr/local/include/opencv2 
LIBS += -lopencv_core -lopencv_imgproc\ 
             -lopencv_highgui 
QT  += gui 
QT  += core 
SOURCES += \ 
    QcvMat.cpp \ 

E ho ottenuto un risultato MALE !!! My bad result

C'è qualche? Gente, ho bisogno di aiuto!

Ho aggiunto alcune informazioni di debug per ottenere cv :: Mat.step e QImage.bytesPerLine() ed è diverso.

[email protected] /media/Files/Programming/Cpp/tests/QImagecvMat $ ./QcvMat 
cv step 942 
QImage bytesPerLine 944 
cv step 942 
QImage bytesPerLine 944 

Che cosa significa e può essere un problema?

risposta

31

Codice con una eccezione.
Gestione della memoria. cv::Mat non funziona come QImage in questo mater. Ricordare che QImage utilizza il meccanismo di copia su scrittura e condivide la memoria per ogni copia. cv::Mat condivide anche la memoria, ma non copia su scrittura (sono anche nuovo con cv aperto (2 settimane), quindi non posso spiegare esattamente come funziona, ma sono inciampato in qualche cotta per colpa di questo) !
Un'altra cosa è che quando si crea QImage dall'immagine di memoria si sta utilizzando questa memoria e non ne diventa proprietario.
Il risultato finale è che su Linux e Qt5 il tuo codice si blocca a causa di problemi con la gestione della memoria.Nella tua schermata puoi vedere nella parte superiore della seconda finestra che qualcosa di strano sta succedendo e vedi qualche cestino della memoria.

così ho corretto le funzioni di conversione funziona perfettamente:

QImage Mat2QImage(cv::Mat const& src) 
{ 
    cv::Mat temp; // make the same cv::Mat 
    cvtColor(src, temp,CV_BGR2RGB); // cvtColor Makes a copt, that what i need 
    QImage dest((const uchar *) temp.data, temp.cols, temp.rows, temp.step, QImage::Format_RGB888); 
    dest.bits(); // enforce deep copy, see documentation 
    // of QImage::QImage (const uchar * data, int width, int height, Format format) 
    return dest; 
} 

cv::Mat QImage2Mat(QImage const& src) 
{ 
    cv::Mat tmp(src.height(),src.width(),CV_8UC3,(uchar*)src.bits(),src.bytesPerLine()); 
    cv::Mat result; // deep copy just in case (my lack of knowledge with open cv) 
    cvtColor(tmp, result,CV_BGR2RGB); 
    return result; 
} 

Così abbiamo entrambi hanno a che fare una lettura sulla gestione della memoria in open-CV :).

offtopic:
modo migliore per includere OpenCV in progetti qt su Linux è quello di aggiungere pro lima qualcosa come:

# add open CV 
unix { 
    CONFIG += link_pkgconfig 
    PKGCONFIG += opencv 
} 

Sarete liberi di problemi di percorso quando si sposta il codice a un altro computer.

+2

Non puoi semplicemente eseguire 'dest.detach()' e restituire 'dest'? Inoltre, 'detach()' non è nella [documentazione] (http://qt-project.org/doc/qt-5/qimage.html). Perché? Ad ogni modo, [questa soluzione] (http://asmaloney.com/2013/11/code/converting-between-cvmat-and-qimage-or-qpixmap/) usa Qt's 'rgbSwapped()' che funziona ed è documentato. – takfuruya

+0

Nice link, quando stavo scrivendo questa risposta questa pagina non esisteva ancora :). Definitivamente è la soluzione migliore (più universale). Vedo un errore lì per caso 'CV_8UC1' (memoria non staccata). Non è stato esposto poiché è stato usato in catena con 'cvMatToQPixmap' e questo copia il contenuto. A proposito di questo 'distacco 'non ho notato che non è documentato. Quindi sistemerò questo. –

+0

Posso abbracciarti proprio adesso! Ha funzionato come una magia per me, gentilmente spiegato fella! – PRIME

2

Grazie mille! Funziona davvero! Ma. Perché la memoria ha rovinato? Primo. Ho qualche carico di memoria incv :: Mat

cv::Mat mat1 = cv::imread("bugero.jpg",3); 

mat1 - [=====================================] 

poi ho messo una copia di questa cvMat ad altri cv: Mat

cv::Mat temp(src.cols,src.rows,src.type()); 
cvtColor(src, temp,CV_BGR2RGB); 

mat1 - [=========================================] 

temp - [=========================================] 

poi fare QImage da questi dati QImage dest = QImage ((uchar *) temp.data, temp.cols, temp.rows, temp.step, QImage :: Format_RGB888);

mat1 - [============================================] 

temp - > [============================================] 
     /
dest --/ 

E quindi la temp esce dal campo di applicazione e si elimina automaticamente? QImage non ne ha la proprietà, quindi la memoria in temp1 e dest sono contrassegnati come liberi e il compilatore può inserire altri dati? Ho ragione?

+1

non rovinato (perdita di memoria) ma danneggiato (puntatori penzolanti). Il problema IMO era la matrice 'temp' locale in' Mat2QImage'. QImage si riferiva alla memoria di quella matrice ed è una variabile locale quindi la memoria è stata liberata sul modulo di ritorno 'Mat2QImage'. –