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

时间:2014-05-17 22:44:21

标签: c++ qt opencv svg

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

2 个答案:

答案 0 :(得分:2)

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

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

Baradé关于使用位的问题是有效的,但是因为你克隆了结果,Mat将从位复制数据,所以它不会成为问题。

答案 1 :(得分:0)

通常,cv :: Mat被重新计算,但这种情况很特殊。如果你使用外部/借用数据指针,你必须克隆()垫子,以确保它拥有自己的像素副本,否则,只要你离开&#39; scaleSvg的范围()&#39;,Mat&#39; out&#39;拥有一个悬垂的指针&#39;。

你尝试过新的&#39;遗憾的是,要复制的数据无法解决(你只在那里添加了另一个问题)。

你也必须自己删除[]你自己的uchar *数据像素,而你不会这样,所以你的代码目前结合了最糟糕的世界。

相反,请尝试:

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