2013-06-15 21 views
14

// Przepraszamy za mój angielski.cv :: Mat do QImage iz powrotem

Powiedz mi, proszę, co robię źle? Czytałem dużo o tym. Napisz trochę kodu, ale mam straszny wynik.

Jak rozumiem w OpenCV CV_8UC3 jest taka sama jak QImage :: Format_RGB888, z wyjątkiem BRG i RGB odpowiednio.

czytać cv :: Mat w tym formacie można zrobić:

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

Tak więc, aby przekształcić cv :: Mat do QImage mogę zrobić:

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

zrobiłem matę temp becouse Chcę mieć kopię danych w QImage.

Następnie. Aby przekształcić go z powrotem muszę zrobić:

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

Wprowadziłem cvtColor (OZE, OZE, CV_BGR2RGB); zrobić cv Mat z kolorami BGR. Nie wiem dokładnie, co w tej funkcji: cvtColor (res, res, CV_BGR2RGB);, Ale zdecydowałem , że jeśli cvtColor (res, res, CV_BGR2RGB); zmień miejsca R i B, które będą ścigać miejsca z tymi kolorami, ponieważ nie znalazłem CV_BGR2RGB.

Tak, napisałem krótki program

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

próbki i .pro plik

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

I mam zły wynik !!! My bad result

Czy są jakieś? Ludzie, potrzebuję pomocy!

Dodałem trochę informacji do debugowania, aby uzyskać cv :: Mat.step i QImage.bytesPerLine() i to jest inne.

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

Co to oznacza i może być w tym problem?

Odpowiedz

31

Kod wygląda dobrze z jednym wyjątkiem.
Zarządzanie pamięcią. cv::Mat nie działa tak jak QImage w tej materii. Pamiętaj, że QImage używa mechanizmu kopiowania przy zapisie i udostępnia pamięć dla każdej kopii. cv::Mat także dzieli się pamięcią, ale nie kopiuje przy pisaniu (jestem też nowy z otwartym cv (2 tygodnie), więc nie mogę dokładnie wyjaśnić, jak to działa, ale natknąłem się na niektóre zmiażdżenia z tego powodu) !
Inną sprawą jest to, że podczas tworzenia QImage z obrazu pamięci korzysta się z tej pamięci i nie przejmuje na nią odpowiedzialności.
Ostateczny wynik jest taki, że w systemie Linux i Qt5 twój kod ulega awarii z powodu problemów z zarządzaniem pamięcią.Na zrzucie ekranu widać na górze drugiego okna, że ​​dzieje się coś dziwnego i widzisz trochę kosza pamięci.

Więc ja skorygować swoje funkcje konwersji działa idealnie:

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

więc oboje mamy zrobić czytając o zarządzaniu pamięcią w otwartym CV :).

OFFTOPIC:
Najlepszy sposób to OpenCV w Qt projektów na Linux jest dodanie do pro pliku coś takiego:

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

Będziesz wolny od problemów ścieżki podczas przenoszenia kod do innego urządzenia.

+2

Nie możesz po prostu zrobić 'dest.detach()' i zwrócić 'dest'? Ponadto 'detach()' nie znajduje się w [dokumentacji] (http://qt-project.org/doc/qt-5/qimage.html). Czemu? Tak czy inaczej, [to rozwiązanie] (http://asmaloney.com/2013/11/code/converting-between-cvmat-and-qimage- or-qpixmap/) używa Qt 'rgbSwapped()', który działa i jest udokumentowany. – takfuruya

+0

Dobry link, kiedy pisałem tę odpowiedź, ta strona jeszcze nie istniała :). Ostatecznie jest to lepsze rozwiązanie (bardziej uniwersalne). Widzę jeden błąd w przypadku "CV_8UC1" (pamięć nie jest odłączona). Nie był odsłonięty, ponieważ był używany w łańcuchu z 'cvMatToQPixmap' i kopiuje zawartość. O tym "odłączeniu" nie zauważyłem, że nie jest to udokumentowane. Więc to naprawię. –

+0

Mogę cię teraz przytulić! Pracowałam jak magia dla mnie, ładnie wyjaśniony facet! – PRIME

2

Wielkie dzięki! To naprawdę działa! Ale. Dlaczego pamięć jest zepsuta? Po pierwsze. Mam pewne incv obciążenia pamięci :: Mat

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

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

następnie umieścić kopię tej cvMat do innej odmiany: Mat

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

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

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

następnie dokonać QImage z tych danych QImage dest = QImage ((uchar *) temp.data, temp.cols, temp.rows, temp.step, QImage :: Format_RGB888);

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

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

A następnie temp wychodzi poza zakres i usunąć go samodzielnie? QImage nie bierze na siebie własności, więc pamięć w temp1 i dest jest oznaczona jako darmowa, a kompilator może umieścić inne dane? Czy mam rację?

+1

niezepsuty (wyciek memów), ale uszkodzony (zwisające wskaźniki). Problem z IMO był lokalną macierzą 'temp' w' Mat2QImage'. QImage odnosiło się do pamięci tej macierzy i jest zmienną lokalną, dzięki czemu pamięć została zwolniona po powrocie z 'Mat2QImage'. –

Powiązane problemy