2013-06-15 26 views
14

// Xin lỗi vì tiếng anh của tôi.cv :: Mat to QImage và quay lại

Hãy cho tôi biết, tôi đang làm gì sai? Tôi đã đọc rất nhiều về điều này. Và viết một số mã, nhưng tôi có một kết quả khủng khiếp.

Theo tôi được biết trong OpenCV CV_8UC3 cũng giống như QImage :: Format_RGB888, trừ BRG và RGB cho phù hợp.

để đọc cv :: Mat ở định dạng này, tôi có thể làm:

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

Vì vậy, để chuyển đổi cv :: Mat để QImage tôi có thể làm:

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

tôi đã tạm mat becouse Tôi muốn có bản sao dữ liệu trong QImage.

Sau đó. Để chuyển đổi nó trở lại tôi phải làm:

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

Tôi đã chèn cvtColor (res, res, CV_BGR2RGB); để làm cho cv Mat với màu BGR. Tôi không chính xác biết những gì bên trong chức năng này cvtColor (res, res, CV_BGR2RGB) ;, Nhưng tôi quyết định rằng nếu cvtColor (res, res, CV_BGR2RGB); thay đổi các địa điểm R và B, điều này sẽ chage các vị trí của màu này trở lại, bởi vì tôi không tìm thấy CV_BGR2RGB.

Vì vậy, tôi đã viết chương trình mẫu ngắn

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

và 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 \ 

Và tôi đã có một kết quả BAD !!! My bad result

Có một số không? Mọi người, tôi cần giúp đỡ!

Tôi đã thêm một số thông tin gỡ lỗi để nhận cv :: Mat.step và QImage.bytesPerLine() và nó khác.

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

Điều đó có nghĩa là gì và có thể có vấn đề gì?

Trả lời

31

Mã có vẻ tốt với một ngoại lệ.
Quản lý bộ nhớ. cv::Mat không hoạt động như QImage trong tài liệu này. Hãy nhớ rằng QImage đang sử dụng bản sao trên cơ chế ghi và chia sẻ bộ nhớ cho mỗi bản sao. cv::Mat cũng chia sẻ bộ nhớ nhưng không sao chép trên ghi (Tôi cũng mới với cv mở (2 tuần) vì vậy tôi không thể giải thích chính xác cách thức hoạt động nhưng tôi đã vấp phải một số nghiền vì điều đó) !
Một điều nữa là khi bạn đang tạo QImage từ hình ảnh bộ nhớ đang sử dụng bộ nhớ này và không sở hữu nó.
Kết quả cuối cùng là trên Linux và Qt5, mã của bạn bị treo do các vấn đề về quản lý bộ nhớ.Trên ảnh chụp màn hình của bạn, bạn có thể nhìn thấy ở trên cùng của cửa sổ thứ hai mà một cái gì đó kỳ lạ đang xảy ra và bạn thấy một số thùng rác bộ nhớ.

Vì vậy, tôi đã sửa các chức năng chuyển đổi của bạn nó hoạt động hoàn hảo:

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

Vì vậy, cả hai chúng tôi phải làm một đọc về quản lý bộ nhớ trong mở CV :).

Offtopic:
Cách tốt nhất để bao gồm OpenCV trong các dự án qt trên Linux là để thêm vào pro tập tin gì đó như:

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

Bạn sẽ được miễn phí các vấn đề về đường khi di chuyển mã để máy khác.

+2

Bạn không thể làm 'dest.detach()' và trả về 'dest'? Ngoài ra, 'detach()' không có trong [documentation] (http://qt-project.org/doc/qt-5/qimage.html). Tại sao? Dù bằng cách nào, [giải pháp này] (http://asmaloney.com/2013/11/code/converting-between-cvmat-and-qimage-or-qpixmap/) sử dụng 'rgbSwapped()' của Qt hoạt động và được ghi lại. – takfuruya

+0

Liên kết đẹp, khi tôi viết câu trả lời này, trang này chưa tồn tại :). Rõ ràng nó là giải pháp tốt hơn (phổ quát hơn). Tôi thấy một lỗi ở đó cho trường hợp 'CV_8UC1' (bộ nhớ không bị tách rời). Nó không được hiển thị vì nó được sử dụng trong chuỗi với 'cvMatToQPixmap' và bản sao nội dung này. Về việc này, tôi không nhận ra rằng nó không được ghi chép lại. Vì vậy, tôi sẽ sửa lỗi này. –

+0

Tôi chỉ có thể ôm bạn ngay bây giờ! Làm việc như một phép thuật cho tôi, fella giải thích độc đáo! – PRIME

2

Cảm ơn rất nhiều! Nó thực sự là công trình! Nhưng. Tại sao bộ nhớ bị hư hỏng? Đầu tiên. Tôi có một số incv tải bộ nhớ :: Mat

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

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

sau đó tôi đặt một bản sao của CvMat này để cv khác: Mat

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

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

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

sau đó hãy chắc QImage từ dữ liệu này QImage dest = QImage ((uchar *) temp.data, temp.cols, temp.rows, temp.step, QImage :: Format_RGB888);

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

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

Và sau đó tạm thời tự tắt và tự xóa nó? QImage không có quyền sở hữu của nó để bộ nhớ trong temp1 và dest đánh dấu là miễn phí, và có trình biên dịch có thể đặt dữ liệu khác? Tôi có đúng không?

+1

không hư hỏng (mem leak) nhưng bị hỏng (con trỏ lơ lửng). Vấn đề IMO là ma trận 'temp' cục bộ trong' Mat2QImage'. QImage đã đề cập đến bộ nhớ của ma trận đó và nó là biến cục bộ để bộ nhớ được giải phóng trên biểu mẫu trả về 'Mat2QImage'. –