如何将opencv cv :: Mat转换为qimage
我想知道如何将OpenCV C ++标准cv :: Mattypes转换为Qimage。 我一直在四处寻找,但没有运气。 我发现一些代码将IPlimage转换为Qimage,但这不是我想要的。 谢谢
这里是24位RGB和灰度浮点的代码。 其他types的容易调整。 它是一样高效的。
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; }
Michal Kottman的答案是有效的,并给出了一些图像的预期结果,但在某些情况下会失败。 这是我发现这个问题的解决scheme。
QImage imgIn= QImage((uchar*) img.data, img.cols, img.rows, img.step, QImage::Format_RGB888);
区别在于添加img.step部分。 QT不会抱怨没有它,但一些图像不会没有它正确显示。 希望这会有所帮助。
要从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:
如果您试图显示的图像具有非标准步幅 (当图像不连续时,子图片),图像可能会失真。 在这种情况下,最好使用cv::Mat::step1()
来显式指定步幅:
QImage img((uchar*)mat.data, mat.cols, mat.rows, mat.step1(), QImage::Format_RGB32);
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的代码。
cv :: Mat有一个到IplImage的转换运算符,所以如果你有一些将IplImage转换成QImage的东西,就使用它(或者直接使用cv :: Mat进行 – 可能是小调整),内存布局是同样,这只是“不同”的标题。)
这篇文章演示了如何将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!
这是一个黑客,但将完成工作。
使用静态函数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); }
我也有和你一样的问题,所以我开发了四个function来减轻我的痛苦,他们是
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-> Format_Indexed8,CV_8UC3-> QImage :: Format_RGB888,CV_8UC4-> QImage :: Format_ARGB32),我不处理其他types(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()); } };
如果有人可以扩展这些function并支持更多的types,那么请告诉我是否有任何错误。
这可能看起来很愚蠢,但将图像保存到一个文件夹,然后读入QImage对象似乎是最快的方法。
Mat x = imread("--.jpg"); imwrite("x.jpg", x); QImage img("x.jpg");
这为我做了诡计。 这是一个有点狡猾,有可怕的performance(正如在评论中指出的那样),但是到目前为止所有的颜色格式都可以使用,而且它也很简单。
程序如下:
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));
我个人使用这个简单的图像编辑器。