如何将QImage转换为OpenCV Mat

12

我在互联网上搜索了一下,但是找不到将QImage(或QPixmap)转换为OpenCV Mat的方法。我该如何实现?

非常感谢任何帮助。


这里可能有一个重复的链接:(https://dev59.com/K2XWa4cB1Zd3GeqPL1MS) - UltraInstinct
@Thrustmaster - 不完全是重复的问题,只有在向另一方向进行步进时才会出现问题。 - Martin Beckett
5个回答

13
如果QImage仍然存在,并且您只需要对其执行快速操作,则可以使用QImage内存构建cv :: Mat:
cv :: Mat mat(image.height(),image.width(),CV_8UC3,(cv :: Scalar *)image.scanLine(0));
这假设QImage是3通道,即RGB888。
如果QImage将消失,则需要复制数据,请参见Qimage to cv :: Mat convertion strange behaviour
如果QImage是Format_ARGB32_Premultiplied(首选格式),则需要将每个像素转换为OpenCV的BGR布局。 cv :: cvtcolor()函数可以在最新版本中将ARGB转换为RGB。 或者您可以使用QImage :: convertToFormat()将其转换为RGB,然后再复制数据。

1
我需要使用scanLine循环遍历图像中的每个指针吗? - user1576633
@user1576633 不,QImage 是连续存储的 scanLine(),没有参数时,指向图像数据的起始位置。 - Martin Beckett
为什么不直接将这个 mat 克隆到另一个 mat 上,如果 QImage 要消失了呢? - mehfoos yacoob
3
我找不到没有参数重载的scanLine()函数。 - mehfoos yacoob
3
你提出的方法会导致编译错误,错误信息为:*'rows' : is not a member of 'QImage'*,同样的错误也会出现在'cols'和'scanline'上。 - Angie Quijano
这个答案有点过时了,将其更改为cv::MatMat mat(img.height(), img.width(), CV_8UC4, (cv::Scalar*)img.scanLine(0));适用于RGBA8888。 - Kaaf

11

在您发布这个问题的一年后,互联网上已经有了很好的答案:

但我认为,如果您同时使用Qt和OpenCV,则类型 QImage 可能只是用于显示,因此您可能希望使用 QPixmap ,因为它针对显示进行了优化。所以这就是我做的事情:

  1. 将图像加载为 cv :: Mat ,如果要显示图像,请使用第二篇文章中介绍的非复制方法转换为 QPixmap
  2. cv :: Mat 中进行图像处理。
  3. 在工作流程中的任何时间,您都可以调用类似于 Mat2QPixmap()的函数来获取实时结果。
  4. 永远不要将 QPixmap 转换为 cv :: Mat ,考虑到每种类型的目的,这样做没有意义。

6
使用Qt 5.11(以及可能的早期版本)的答案是:
    cv::Mat mat(image.height(), image.width(),CV_8UC3, image.bits());  
    // image.scanline() does not exist, 
    //and height/width is interchanged for a matrix

再次强调,假设QImage是RGB888格式(即QImage::Format_RGB888)


3

我尝试使用OpenCV 3.1+风格的代码:

void qimage_to_mat(const QImage& image, cv::OutputArray out) {

    switch(image.format()) {
        case QImage::Format_Invalid:
        {
            cv::Mat empty;
            empty.copyTo(out);
            break;
        }
        case QImage::Format_RGB32:
        {
            cv::Mat view(image.height(),image.width(),CV_8UC4,(void *)image.constBits(),image.bytesPerLine());
            view.copyTo(out);
            break;
        }
        case QImage::Format_RGB888:
        {
            cv::Mat view(image.height(),image.width(),CV_8UC3,(void *)image.constBits(),image.bytesPerLine());
            cvtColor(view, out, cv::COLOR_RGB2BGR);
            break;
        }
        default:
        {
            QImage conv = image.convertToFormat(QImage::Format_ARGB32);
            cv::Mat view(conv.height(),conv.width(),CV_8UC4,(void *)conv.constBits(),conv.bytesPerLine());
            view.copyTo(out);
            break;
        }
    }
}

void mat_to_qimage(cv::InputArray image, QImage& out)
{
    switch(image.type())
    {
        case CV_8UC4:
        {
            cv::Mat view(image.getMat());
            QImage view2(view.data, view.cols, view.rows, view.step[0], QImage::Format_ARGB32);
            out = view2.copy();
            break;
        }
        case CV_8UC3:
        {
            cv::Mat mat;
            cvtColor(image, mat, cv::COLOR_BGR2BGRA); //COLOR_BGR2RGB doesn't behave so use RGBA
            QImage view(mat.data, mat.cols, mat.rows, mat.step[0], QImage::Format_ARGB32);
            out = view.copy();
            break;
        }
        case CV_8UC1:
        {
            cv::Mat mat;
            cvtColor(image, mat, cv::COLOR_GRAY2BGRA);
            QImage view(mat.data, mat.cols, mat.rows, mat.step[0], QImage::Format_ARGB32);
            out = view.copy();
            break;
        }
        default:
        {
            throw invalid_argument("Image format not supported");
            break;
        }
    }
}

0
cv::Mat to_cvmat(QImage img)
{
    img = img.convertToFormat(QImage::Format_RGB888, Qt::ColorOnly).rgbSwapped();
    return cv::Mat(img.height(), img.width(), CV_8UC3, img.bits(), img.bytesPerLine()).clone();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接