通过使用原始数据将QImage转换为cv::Mat

converting QImage to cv::Mat by using raw data

本文关键字:转换 cv QImage Mat 原始数据      更新时间:2023-10-16

我想将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,这看起来是一个简单的方法来完成它。

因为constBits确实不起作用,并且假设每行的字节数是相同的并不总是安全的(这对我来说会导致段错误)。我在StereoMatching的回答中发现了以下建议:

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

barad关于使用位的担忧是有效的,但由于您克隆了结果,Mat将从位复制数据,因此这将不是一个问题。

通常,cv::Mat会被重新计算,但这种情况比较特殊。如果您使用外部/借用的数据指针,您必须clone() mat,以确保它拥有自己的像素副本,否则,一旦您离开'scaleSvg()'的范围,mat 'out'持有'悬空指针'。

您尝试'new'要复制的数据,不幸的是,这并不能解决它(您只在那里添加了另一个问题)。

您还必须自己删除[]uchar *数据像素,而您没有这样做,因此您的代码目前组合了最糟糕的情况。

,试试:

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