C++ cv::Mat 到 QImage 并返回

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17127762/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 20:56:29  来源:igfitidea点击:

cv::Mat to QImage and back

c++qtopencvqimagemat

提问by user1113159

//Sorry for my english.

//对不起我的英语不好。

Tell me please, what I am doing wrong? I have read a lot about this. And write some code, but I have a terrible result.

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

As I understand in Opencv CV_8UC3is the same as QImage::Format_RGB888, except BRG and RGB accordingly.

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

to read cv::Mat in this format I can do:

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

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

So, to convert cv::Mat to QImage I can do:

因此,要将 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;
}

I made temp mat becouse I want to have copy of data in QImage.

我制作了临时垫,因为我想在 QImage 中复制数据。

Then. To convert it back I Have to do:

然后。要将其转换回我必须执行的操作:

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

I have inserted cvtColor(res, res,CV_BGR2RGB); to make cv Mat with BGR colors. I do not exactly know what in inside this function cvtColor(res, res,CV_BGR2RGB);, But I decided that if cvtColor(res, res,CV_BGR2RGB);change places R and B, that will chage places of this colors back, because I did not found CV_BGR2RGB.

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

So, I wrote short sample 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();
}

and .pro 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 \

And I have got a BAD result!!! My bad result

我得到了一个糟糕的结果!!! 我的坏结果

Is there some? People,I need help!

有吗?人,我需要帮助!

I added some debug info to get cv::Mat.step and QImage.bytesPerLine() and it is different.

我添加了一些调试信息来获取 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 

What does it means and may be problem in it?

它是什么意思,可能有什么问题?

回答by Marek R

Code looks fine with one exception.
Memory management. cv::Matdoesn't work like QImagein this mater. Remember that QImageis using copy on write mechanism and shares memory for each copy. cv::Matalso shares memory but it doesn't do copy on write (I'm also new with open cv (2 weeks) so I can't explain yet exactly how it works but I've stumbled on some crushes because of that)!
Another thing is that when you are creating QImagefrom memory image is using this memory and doesn't take ownership of it.
Final outcome is that on Linux and Qt5 your code is crashes because of problems with memory management. On your screen shot you can see at the top of second window that something strange is going on and you see some memory trash.

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

So I've corrected your conversion functions it works perfectly:

所以我更正了你的转换功能,它完美地工作:

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

So we both have to do a reading about memory management in open-CV :).

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

OFFTOPIC:
Best way to include openCV in qt projects on Linux is to add to pro file something like:

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

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

You will be free of path problems when moving code to another machine.

将代码移动到另一台机器时,您将不会遇到路径问题。

回答by user1113159

Thanks a Lot! It is realy works! But. Why does memory whas spoiled? First. I have some memory load incv::Mat

多谢!真的很管用!但。为什么记忆会变质?第一的。我有一些内存负载 incv::Mat

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

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

then I put a copy of this cvMat to other cv:Mat

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

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

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

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

then make QImage from this data QImage dest= QImage((uchar*) temp.data, temp.cols, temp.rows, temp.step, QImage::Format_RGB888);

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

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

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

And then temp goes out of scope and delete it self? QImage does not take ownership of it so memory in temp1 and dest marked as free, and there compiler can put other data? Is I am right?

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