我想知道如何将OpenCV C ++标准cv :: Mat类型转换为Qimage。我一直在寻找,但没有运气。我找到了一些将IPlimage转换为Qimage的代码,但这不是我想要的。感谢
答案 0 :(得分:35)
Michal Kottman的答案是有效的,并给出了一些图像的预期结果,但在某些情况下它会失败。这是我发现这个问题的解决方案。
QImage imgIn= QImage((uchar*) img.data, img.cols, img.rows, img.step, QImage::Format_RGB888);
区别在于添加img.step部分。如果没有它,qt不会抱怨,但如果没有它,一些图像将无法正常显示。希望这会有所帮助。
答案 1 :(得分:29)
这是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;
}
答案 2 :(得分:23)
要从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);
比手动将像素转换为QImage
更有效,但您必须将原始cv::Mat
图像保留在内存中。它可以很容易地转换为QPixmap
并使用QLabel
:
QPixmap pixmap = QPixmap::fromImage(img);
myLabel.setPixmap(pixmap);
<强>更新强>
由于OpenCV默认使用BGR顺序,因此您应首先使用cvtColor(src, dst, CV_BGR2RGB)
来获取Qt理解的图像布局。
更新2:
如果您要显示的图像具有非标准stride(当它是非连续的,子矩阵时),图像可能会失真。在这种情况下,最好使用cv::Mat::step1()
明确指定步幅:
QImage img((uchar*)mat.data, mat.cols, mat.rows, mat.step1(), QImage::Format_RGB32);
答案 3 :(得分:3)
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);
这对我有用。我在上面修改了Michal Kottman的代码。
答案 4 :(得分:2)
cv :: Mat有一个转换运算符到IplImage,所以如果你有把IplImage转换成QImage的东西,那就用它(或者做 - 可能是次要的 - 调整直接取cv :: Mat,内存布局是一样的,它只是“只是”不同的标题。)
答案 5 :(得分:2)
我也有同样的问题,所以我开发了四个功能来减轻我的痛苦,他们是
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);
这些函数可以处理具有1,3,4个通道的图像,每个像素必须仅占用一个字节(CV_8U-&gt; Format_Indexed8,CV_8UC3-&gt; QImage :: Format_RGB888,CV_8UC4-&gt; QImage :: Format_ARGB32),我还没有处理其他类型(QImage :: Format_RGB16,QImage :: Format_RGB666等)。代码位于 在github。
**转换到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);
}
};
转化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());
}
};
如果有人可以扩展这些功能并使它们支持更多类型,那么如果有任何错误,请通知我。
答案 6 :(得分:2)
默认情况下,OpenCV将图像加载为蓝绿红(BGR)格式的Mat
,而QImage
则需要RGB。这意味着,如果将Mat
转换为QImage
,则蓝色和红色通道将被交换。要解决此问题,在构造QImage
之前,您需要使用参数Mat
通过cvtColor
方法将CV_BGR2RGB
的BRG格式更改为RGB,如下所示: / p>
Mat mat = imread("path/to/image.jpg");
cvtColor(mat, mat, CV_BGR2RGB);
QImage image(mat.data, mat.cols, mat.rows, QImage::Format_RGB888);
或者,在rgbSwapped()
上使用QImage
QImage image = QImage(mat.data, mat.cols, mat.rows, QImage::Format_RGB888).rgbSwapped());
答案 7 :(得分:1)
This post显示如何将QImage
转换为OpenCV的IplImage
,反之亦然。
之后,如果您需要帮助才能在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!
这是一个黑客,但会完成工作。
答案 8 :(得分:1)
使用静态函数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);
}
答案 9 :(得分:0)
这看起来很愚蠢,但是将图像保存到文件夹然后读入QImage对象似乎是最快捷的方式。
Mat x = imread("--.jpg");
imwrite("x.jpg", x);
QImage img("x.jpg");
答案 10 :(得分:-2)
这对我有用。它有点狡猾,表现糟糕(正如评论中所指出的那样),但是到目前为止我使用的所有颜色格式都可以使用,并且它也很简单。
程序如下:
cv::Mat image = //...some image you want to display
// 1. Save the cv::Mat to some temporary file
cv::imwrite("../Images/tmp.jpg",image);
// 2. Load the image you just saved as a QImage
QImage img;
img.load("../Images/tmp.jpg");
完成!强>
如果您想要在QLabel中显示它,请继续:
// Set QImage as content of MyImageQLabel
ui-> MyImageQLabel->setPixmap(QPixmap::fromImage(img, Qt::AutoColor));
我个人将它用于简单的图像编辑器。