47

我想知道如何将 OpenCV C++ 标准 cv::Mat 类型转换为 QImage。我一直在四处寻找,但没有运气。我找到了一些将 IPlimage 转换为 QImage 的代码,但这不是我想要的。谢谢。

4

10 回答 10

45

Michal Kottman 的回答是有效的,并且对某些图像给出了预期的结果,但在某些情况下会失败。这是我找到的解决该问题的方法。

QImage imgIn= QImage((uchar*) img.data, img.cols, img.rows, img.step, QImage::Format_RGB888);

不同之处在于添加了 img.step 部分。没有它,qt 不会抱怨,但没有它,有些图像将无法正确显示。希望这会有所帮助。

于 2012-09-07T05:40:36.090 回答
29

要从 to 转换cv::MatQImage您可以尝试使用QImage(uchar * data, int width, int height, Format format)如下构造函数(matis a cv::Mat):

QImage img((uchar*)mat.data, mat.cols, mat.rows, QImage::Format_RGB32);

它比手动将像素转换为 更有效QImage,但您必须将原始cv::Mat图像保存在内存中。它可以很容易地转换为 aQPixmap并使用 a 显示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);
于 2011-02-17T23:46:10.933 回答
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;
}
于 2012-01-15T01:56:28.963 回答
8

默认情况下, OpenCV 将图像加载为Mat蓝绿红 (BGR) 格式,而QImage需要 RGB。这意味着如果您将 a 转换MatQImage,蓝色和红色通道将被交换。要解决此问题,在构造 之前,您需要通过使用参数的方法将QImage您的 BRG 格式更改Mat为 RGB,如下所示:cvtColorCV_BGR2RGB

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());
于 2018-11-11T02:05:12.320 回答
4
    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 的代码。

于 2012-02-05T19:34:08.363 回答
3

我也有和你一样的问题,所以我开发了四个功能来减轻我的痛苦,它们是

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),其他的我不处理类型尚未(QImage::Format_RGB16、QImage::Format_RGB666 等)。代码位于github

**将 mat 转换为 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());
    }
};

如果有人可以扩展这些功能并使其支持更多类型会很好,如果有任何错误,请告诉我。

于 2015-07-27T20:43:55.787 回答
2

cv::Mat 有一个转换为 IplImage 的操作符,所以如果你有将 IplImage 转换为 QImage 的东西,只需使用它(或进行 - 可能是微小的 - 调整以直接获取 cv::Mat,内存布局就是同样,它“只是”不同的标题。)

于 2011-02-17T10:24:22.683 回答
2

这篇文章展示了如何将 a 转换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!

这是一个黑客,但会完成工作。

于 2011-12-08T19:28:50.107 回答
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);
}
于 2013-06-10T13:42:30.810 回答
-4

这对我有用。它有点狡猾,性能很差(正如评论中指出的那样),但适用于我迄今为止所使用的所有颜色格式,而且操作起来也很简单。

程序如下:

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

我个人将其用于简单的图像编辑器。

于 2013-10-04T10:01:59.670 回答