【问题标题】:converting QImage to cv::Mat by using raw data使用原始数据将 QImage 转换为 cv::Mat
【发布时间】:2026-01-07 06:00:01
【问题描述】:

我想将 SVG 图形转换为 OpenCV Mat 对象。因此,SVG 图形被加载到一个 QSvgRenderer 对象中,然后转换为一个 QImage 对象,我使用它的原始数据创建我的最终 Mat 对象:

 void scaleSvg(const cv::Mat &in, QSvgRenderer &svg, cv::Mat &out)
 {
     if (!svg.isValid())
     {
          return;
     }

     QImage image(in.cols, in.rows, QImage::Format_ARGB32);

     // Get QPainter that paints to the image
     QPainter painter(&image);
     svg.render(&painter);

     std::cout << "Image byte count: " << image.byteCount() << std::endl;
     std::cout << "Image bits: " << (int*)image.constBits() << std::endl;
     std::cout << "Image depth: " << image.depth() << std::endl;

     uchar *data = new uchar[image.byteCount()];
     memcpy(data, image.constBits(), image.byteCount());

     out = cv::Mat(image.height(), image.width(), CV_8UC4, data, CV_AUTOSTEP);
     std::cout << "New byte count: " <<  out.size() << std::endl;
     std::cout << "New depth: " << out.depth() << std::endl;
     std::cout << "First bit: " << out.data[0] << std::endl;
 }

不幸的是,将生成的对象写入文件时出现“内存访问冲突”错误:

 std::cout << (int*)out.data << std::endl; // pointer can still be accessed without errors
 cv::imwrite("scaled.png", out); // memory access error

正在写入的文件大小不超过 33 个字节(仅标题数据??)。 在互联网上有一些关于 cv::Mat 指针所有权的解释,我认为它会在最后一次引用它之后被释放,因为“out”是一个引用,所以不应该是这种情况。顺便提一句。将 SVG 转换为 cv::Mat 的另一种方法总是受欢迎的。由于 OpenCV 似乎不支持 SVG,这看起来是一种简单的方法来完成它。

【问题讨论】:

    标签: c++ qt opencv svg


    【解决方案1】:

    由于 constBits 确实不起作用,并且假设每行的字节数相同并不总是安全的(它会导致我的段错误)。我在StereoMatching's anwser找到了以下建议:

    cv::Mat(img.height(), img.width(), CV_8UC4, img.bits(), img.bytesPerLine()).clone()
    

    Baradé 对使用位的担忧是有道理的,但是因为您克隆了结果,所以 Mat 会从位复制数据,所以这不是问题。

    【讨论】:

      【解决方案2】:

      通常, cv::Mat 被引用,但这种情况是特殊的。如果您使用外部/借用数据指针,则必须克隆()垫子,以确保它拥有自己的像素副本,否则,一旦您离开“scaleSvg()”的范围, Mat 'out' 包含一个 '悬空指针'。

      您尝试“新建”要复制的数据,不幸的是,这并没有解决它(您只是在那里添加了另一个问题)。

      您还必须自己删除[] uchar *data 像素,而您不需要,因此您的代码目前结合了最糟糕的情况。

      相反,尝试:

      out = cv::Mat(image.height(), image.width(), CV_8UC4, image.constBits(), CV_AUTOSTEP).clone();
      

      【讨论】:

      • 感谢您的回答,但这种方式不起作用。 constBits() 不能使用,因为它返回一个 const 指针。当我使用 bits() 这似乎是错误的,因为 cv::Mat 的破坏可能会释放 bits() 如果它使用引用计数机制(也许我在这里错了)即使在您发布的语句中也会发生内存映射错误和之后不会。