C++ 如何将 OpenCV cv::Mat 转换为 QImage
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5026965/
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
How to convert an OpenCV cv::Mat to QImage
提问by Hien
I am wondering how would I convert the OpenCV C++ standard cv::Mat type to QImage. I have been searching around, but have no luck. I have found some code that converts the IPlimage to QImage, but that is not what I want. Thanks.
我想知道如何将 OpenCV C++ 标准 cv::Mat 类型转换为 QImage。我一直在四处寻找,但没有运气。我发现了一些将 IPlimage 转换为 QImage 的代码,但这不是我想要的。谢谢。
回答by chAmi
Michal Kottman's answer is valid and give expected result for some images but it'll fail on some cases. Here is a solution i found to that problem.
Michal Kottman 的回答是有效的,并为某些图像提供了预期的结果,但在某些情况下会失败。这是我找到的解决该问题的方法。
QImage imgIn= QImage((uchar*) img.data, img.cols, img.rows, img.step, QImage::Format_RGB888);
Difference is adding img.step part. qt won't complain without it but some images won't show properly without it. Hope this will help.
不同之处在于添加了 img.step 部分。没有它,qt 不会抱怨,但如果没有它,某些图像将无法正常显示。希望这会有所帮助。
回答by ypnos
Here is code for 24bit RGB and grayscale floating point. Easily adjustable for other types. It is as efficient as it gets.
这是 24 位 RGB 和灰度浮点的代码。其他类型可轻松调节。它是最有效的。
QImage Mat2QImage(const cv::Mat3b &src) {
QImage dest(src.cols, src.rows, QImage::Format_ARGB32);
for (int y = 0; y < src.rows; ++y) {
const cv::Vec3b *srcrow = src[y];
QRgb *destrow = (QRgb*)dest.scanLine(y);
for (int x = 0; x < src.cols; ++x) {
destrow[x] = qRgba(srcrow[x][2], srcrow[x][1], srcrow[x][0], 255);
}
}
return dest;
}
QImage Mat2QImage(const cv::Mat_<double> &src)
{
double scale = 255.0;
QImage dest(src.cols, src.rows, QImage::Format_ARGB32);
for (int y = 0; y < src.rows; ++y) {
const double *srcrow = src[y];
QRgb *destrow = (QRgb*)dest.scanLine(y);
for (int x = 0; x < src.cols; ++x) {
unsigned int color = srcrow[x] * scale;
destrow[x] = qRgba(color, color, color, 255);
}
}
return dest;
}
回答by Michal Kottman
To convert from cv::Mat
to QImage
, you could try to use the QImage(uchar * data, int width, int height, Format format)
constructor as follows (mat
is a cv::Mat
) :
要转换cv::Mat
到QImage
,你可以尝试使用QImage(uchar * data, int width, int height, Format format)
构造如下(mat
是cv::Mat
):
QImage img((uchar*)mat.data, mat.cols, mat.rows, QImage::Format_RGB32);
It is more efficient than manually converting the pixels to the QImage
, but you have to keep the original cv::Mat
image in memory. It can be easily converted to a QPixmap
and displayed using a QLabel
:
它比手动将像素转换为 更有效QImage
,但您必须将原始cv::Mat
图像保留在内存中。它可以很容易地转换为 aQPixmap
并使用 a 显示QLabel
:
QPixmap pixmap = QPixmap::fromImage(img);
myLabel.setPixmap(pixmap);
Update
更新
Because OpenCV uses BGR order by default, you should first use cvtColor(src, dst, CV_BGR2RGB)
to get an image layout that Qt understands.
因为 OpenCV 默认使用 BGR 顺序,所以你应该首先使用它cvtColor(src, dst, CV_BGR2RGB)
来获取 Qt 理解的图像布局。
Update 2:
更新 2:
If the image you are trying to show has nonstandard stride(when it is non-continuous, submatrix), the image may appeard distorted. In this case, it is better to explicitly specify the stride using cv::Mat::step1()
:
如果您尝试显示的图像具有非标准步幅(当它是非连续的子矩阵时),则图像可能会失真。在这种情况下,最好使用cv::Mat::step1()
以下方法明确指定步幅:
QImage img((uchar*)mat.data, mat.cols, mat.rows, mat.step1(), QImage::Format_RGB32);
回答by Gunnar Karlsson
OpenCV loads images into a Mat
in Blue-Green-Red (BGR) format by default, while QImage
expects RGB. This means that if you convert a Mat
to QImage
, the blue and red channels will be swapped. To fix this, before constructing the QImage
, you need to change the BRG format of your Mat
to RGB, via the cvtColor
method using argument CV_BGR2RGB
, like so:
Mat
默认情况下,OpenCV 将图像加载为蓝绿红 (BGR) 格式,而QImage
期望使用 RGB。这意味着如果您将 a 转换Mat
为QImage
,则蓝色和红色通道将交换。要解决此问题,在构建 之前QImage
,您需要Mat
通过cvtColor
使用参数的方法将 BRG 格式更改为 RGB CV_BGR2RGB
,如下所示:
Mat mat = imread("path/to/image.jpg");
cvtColor(mat, mat, CV_BGR2RGB);
QImage image(mat.data, mat.cols, mat.rows, QImage::Format_RGB888);
Alternatively, use rgbSwapped()
on the QImage
或者,rgbSwapped()
在QImage
QImage image = QImage(mat.data, mat.cols, mat.rows, QImage::Format_RGB888).rgbSwapped());
回答by Mathai
Mat opencv_image = imread("fruits.jpg", CV_LOAD_IMAGE_COLOR);
Mat dest;
cvtColor(opencv_image, dest,CV_BGR2RGB);
QImage image((uchar*)dest.data, dest.cols, dest.rows,QImage::Format_RGB888);
This is what worked for me. I modified Michal Kottman's code above.
这对我有用。我修改了上面 Michal Kottman 的代码。
回答by karlphillip
This postshows how to convert a QImage
to OpenCV's IplImage
and vise-versa.
这篇文章展示了如何将 a 转换QImage
为 OpenCV IplImage
,反之亦然。
After that, if you need help to convert between IplImage*
to cv::Mat
:
之后,如果您需要帮助在 和 之间IplImage*
进行转换cv::Mat
:
// Assume data is stored by:
// IplImage* image;
cv::Mat mat(image, true); // Copies the data from image
cv::Mat mat(image, false); // Doesn't copy the data!
It's a hack, but will get the job done.
这是一个黑客,但会完成工作。
回答by etarion
cv::Mat has a conversion operator to IplImage, so if you have something that converts the IplImage to a QImage, just use that (or make the - probably minor - adjustments to take the cv::Mat directly, the memory layout is the same, it's "just" the header that is different.)
cv::Mat 有一个到 IplImage 的转换运算符,所以如果你有将 IplImage 转换为 QImage 的东西,只需使用它(或进行 - 可能是次要的 - 调整以直接获取 cv::Mat,内存布局是相同,它“只是”不同的标题。)
回答by StereoMatching
I have the same problem as you too, so I develop four functions to alleviate my pain, they are
我也有和你一样的问题,所以我开发了四个功能来减轻我的痛苦,它们是
QImage mat_to_qimage_cpy(cv::Mat const &mat, bool swap = true);
QImage mat_to_qimage_ref(cv::Mat &mat, bool swap = true);
cv::Mat qimage_to_mat_cpy(QImage const &img, bool swap = true);
cv::Mat qimage_to_mat_ref(QImage &img, bool swap = true);
These functions can handle the images with 1, 3, 4 channels, every pixelmust occupy one byte only(CV_8U->Format_Indexed8, CV_8UC3->QImage::Format_RGB888, CV_8UC4->QImage::Format_ARGB32), I do not deal with other types yet(QImage::Format_RGB16, QImage::Format_RGB666 and so on). The codes are located at github.
这些函数可以处理1、3、4通道的图像,每个像素必须只占一个字节(CV_8U->Format_Indexed8、CV_8UC3->QImage::Format_RGB888、CV_8UC4->QImage::Format_ARGB32),其他的我不处理类型(QImage::Format_RGB16、QImage::Format_RGB666 等等)。代码位于github。
The key conceptsof **transform mat to Qimage ** are
**transform mat to Qimage **的关键概念是
/**
* @brief copy QImage into cv::Mat
*/
struct mat_to_qimage_cpy_policy
{
static QImage start(cv::Mat const &mat, QImage::Format format)
{
//The fourth parameters--mat.step is crucial, because
//opencv may do padding on every row, you need to tell
//the qimage how many bytes per row
//The last thing is if you want to copy the buffer of cv::Mat
//to the qimage, you need to call copy(), else the qimage
//will share the buffer of cv::Mat
return QImage(mat.data, mat.cols, mat.rows, mat.step, format).copy();
}
};
struct mat_to_qimage_ref_policy
{
static QImage start(cv::Mat &mat, QImage::Format format)
{
//every thing are same as copy policy, but this one share
//the buffer of cv::Mat but not copy
return QImage(mat.data, mat.cols, mat.rows, mat.step, format);
}
};
The key conceptsof transform cv::Mat to Qimage
are
变换的关键概念cv::Mat to Qimage
是
/**
* @brief copy QImage into cv::Mat
*/
struct qimage_to_mat_cpy_policy
{
static cv::Mat start(QImage const &img, int format)
{
//same as convert mat to qimage, the fifth parameter bytesPerLine()
//indicate how many bytes per row
//If you want to copy the data you need to call clone(), else QImage
//cv::Mat will share the buffer
return cv::Mat(img.height(), img.width(), format,
const_cast<uchar*>(img.bits()), img.bytesPerLine()).clone();
}
};
/**
* @brief make Qimage and cv::Mat share the same buffer, the resource
* of the cv::Mat must not deleted before the QImage finish
* the jobs.
*/
struct qimage_to_mat_ref_policy
{
static cv::Mat start(QImage &img, int format)
{
//same as copy policy, but this one will share the buffer
return cv::Mat(img.height(), img.width(), format,
img.bits(), img.bytesPerLine());
}
};
If would be good if some one can extend these functions and make them support more types, please inform me if there are any bugs.
如果有人可以扩展这些功能并使它们支持更多类型会很好,如果有任何错误,请通知我。
回答by D. Sangue
Use the static function convert16uc1 for the depth image:
对深度图像使用静态函数 convert16uc1:
QPixmap Viewer::convert16uc1(const cv::Mat& source)
{
quint16* pSource = (quint16*) source.data;
int pixelCounts = source.cols * source.rows;
QImage dest(source.cols, source.rows, QImage::Format_RGB32);
char* pDest = (char*) dest.bits();
for (int i = 0; i < pixelCounts; i++)
{
quint8 value = (quint8) ((*(pSource)) >> 8);
*(pDest++) = value; // B
*(pDest++) = value; // G
*(pDest++) = value; // R
*(pDest++) = 0; // Alpha
pSource++;
}
return QPixmap::fromImage(dest);
}
QPixmap Viewer::convert8uc3(const cv::Mat& source)
{
quint8* pSource = source.data;
int pixelCounts = source.cols * source.rows;
QImage dest(source.cols, source.rows, QImage::Format_RGB32);
char* pDest = (char*) dest.bits();
for (int i = 0; i < pixelCounts; i++)
{
*(pDest++) = *(pSource+2); // B
*(pDest++) = *(pSource+1); // G
*(pDest++) = *(pSource+0); // R
*(pDest++) = 0; // Alpha
pSource+=3;
}
return QPixmap::fromImage(dest);
}
QPixmap Viewer::convert16uc3(const cv::Mat& source)
{
quint16* pSource = (quint16*) source.data;
int pixelCounts = source.cols * source.rows;
QImage dest(source.cols, source.rows, QImage::Format_RGB32);
char* pDest = (char*) dest.bits();
for (int i = 0; i < pixelCounts; i++)
{
*(pDest++) = *(pSource+2); // B
*(pDest++) = *(pSource+1); // G
*(pDest++) = *(pSource+0); // R
*(pDest++) = 0; // Alpha
pSource+=3;
}
return QPixmap::fromImage(dest);
}
回答by Burak Mete
It might seem silly, but saving the image to a folder and then reading into a QImage object seemed to me the quickest way.
这可能看起来很傻,但是将图像保存到文件夹然后读入 QImage 对象对我来说似乎是最快的方法。
Mat x = imread("--.jpg");
imwrite("x.jpg", x);
QImage img("x.jpg");