【问题标题】:How to convert QImage to opencv Mat如何将 QImage 转换为 opencv Mat
【发布时间】:2023-03-09 05:49:01
【问题描述】:

我在 Internet 上进行了搜索,但找不到将 QImage(或 QPixmap)转换为 OpenCV Mat 的方法。我该怎么做呢?

感谢任何帮助。

【问题讨论】:

  • @Thrustmaster - 不完全是一个骗局,踩踏的问题只会反过来影响

标签: c++ qt opencv


【解决方案1】:

如果 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。

【讨论】:

  • 我是否必须使用 scanLine 遍历图像中的每个指针?
  • @user1576633 不,QImage是连续存储的scanLine(),不带arg,指向图片数据的开头
  • 如果 QImage 即将消失,为什么不简单地将这个垫子克隆到另一个垫子上?
  • 另外,我找不到 scanLine() 重载了 not args。
  • 您建议的方式引发编译错误:'rows' : is not a member of 'QImage' 和 'cols' 和 'scanline' 相同。
【解决方案2】:

我在 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;
        }
    }
}

【讨论】:

    【解决方案3】:

    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)

    【讨论】:

      【解决方案4】:

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

      但在我看来,如果你同时使用 Qt 和 OpenCV,那么输入 QImage 可能只是为了显示,这种情况下你可能想要使用 @987654324 @ 因为它针对显示进行了优化。所以这就是我所做的:

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

      【讨论】:

        【解决方案5】:

        我会将图像保存到磁盘并从 cv 重新打开它;)

        @^ 我已经尝试过之前的解决方案。它似乎不适合我。虽然我得到了一些图像,但它看起来像是一些条形码信息类型的图像。我猜是参数不匹配。

        【讨论】:

          猜你喜欢
          • 2011-06-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-15
          相关资源
          最近更新 更多