【问题标题】:cv::Mat to QImage and backcv::Mat 到 QImage 并返回
【发布时间】:2013-06-12 05:46:34
【问题描述】:

//对不起我的英语。

请告诉我,我做错了什么? 我已经阅读了很多关于此的内容。并写了一些代码,但结果很糟糕。

据我了解 在 Opencv 中 CV_8UC3QImage::Format_RGB888 相同,除了相应的 BRG 和 RGB。

以这种格式读取 cv::Mat 我可以这样做:

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

所以,我可以将 cv::Mat 转换为 QImage:

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

我制作了临时垫,因为我想在 QImage 中拥有数据副本。

那么。 要将其转换回来,我必须这样做:

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

我已插入 cvtColor(res, res,CV_BGR2RGB);用 BGR 颜色制作 cv Mat。我不完全知道这个函数里面有什么cvtColor(res, res,CV_BGR2RGB);,但我决定 如果 cvtColor(res, res,CV_BGR2RGB); 改变 R 和 B 的位置,就会把这个颜色的位置改回来,因为我没有找到 CV_BGR2RGB

所以,我写了一个简短的示例程序

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

和.pro文件

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

我的结果很糟糕!!!

有吗?各位,我需要帮助!

我添加了一些调试信息来获取 cv::Mat.step 和 QImage.bytesPerLine() 并且它是不同的。

alex@lenovo /media/Files/Programming/Cpp/tests/QImagecvMat $ ./QcvMat 
cv step  942 
QImage  bytesPerLine  944 
cv step  942 
QImage  bytesPerLine  944 

这是什么意思,可能是什么问题?

【问题讨论】:

    标签: c++ qt opencv qimage mat


    【解决方案1】:

    代码看起来不错,但有一个例外。
    内存管理。 cv::Mat 在本校中不像 QImage 那样工作。请记住,QImage 正在使用写时复制机制并为每个副本共享内存。 cv::Mat 也共享内存,但它不会在写入时复制(我也是 open cv 的新手(2 周),所以我还不能准确解释它是如何工作的,但我偶然发现了一些迷恋)!
    另一件事是,当您从内存映像创建 QImage 时,它正在使用此内存并且不拥有它。
    最终结果是,在 Linux 和 Qt5 上,您的代码由于内存管理问题而崩溃。在您的屏幕截图中,您可以在第二个窗口的顶部看到发生了一些奇怪的事情,并且您会看到一些内存垃圾。

    所以我已经更正了你的转换函数,它可以完美运行:

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

    所以我们都必须阅读有关 open-CV 中的内存管理的内容:)。

    OFFTOPIC:
    在 Linux 上的 qt 项目中包含 openCV 的最佳方法是在 pro 文件中添加如下内容:

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

    将代码移动到另一台机器时不会出现路径问题。

    【讨论】:

    • 你不能只做dest.detach()并返回dest吗?此外,detach() 不在documentation 中。为什么?无论哪种方式,this solution 都使用 Qt 的 rgbSwapped(),它有效且已记录在案。
    • 不错的链接,当我写这个答案时,这个页面还不存在:)。绝对是更好的解决方案(更通用)。我在CV_8UC1 的情况下看到一个错误(内存未分离)。它没有被暴露,因为它与cvMatToQPixmap 一起使用并复制了内容。关于这个detach 我没有注意到它没有记录。所以我会解决这个问题。
    • 我现在可以拥抱你了!对我来说就像魔术一样工作,很好地解释了伙计!
    • 那么在调用函数的时候说QImage2Mat是应该传递Qimage的引用还是直接传递变量?
    【解决方案2】:

    非常感谢!真的很管用! 但。为什么记忆会被破坏? 第一的。我有一些内存负载 incv::Mat

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

    然后我把这个 cvMat 的副本放到其他 cv:Mat

    cv::Mat temp(src.cols,src.rows,src.type());
    cvtColor(src, temp,CV_BGR2RGB);
    
    mat1  -  [=========================================]
    
    temp  -  [=========================================]
    

    然后根据这些数据制作 QImage QImage dest= QImage((uchar*) temp.data, temp.cols, temp.rows, temp.step, QImage::Format_RGB888);

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

    然后 temp 超出范围并自行删除? QImage 没有它的所有权,所以 temp1 和 dest 中的内存标记为空闲,编译器可以放置其他数据吗?我是对的吗?

    【讨论】:

    • 未损坏(内存泄漏)但已损坏(悬空指针)。 IMO 问题是Mat2QImage 中的本地temp 矩阵。 QImage 指的是该矩阵的内存,它是局部变量,因此在返回表单 Mat2QImage 时释放了内存。
    猜你喜欢
    • 2012-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-28
    • 1970-01-01
    相关资源
    最近更新 更多