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

Posted

技术标签:

【中文标题】使用原始数据将 QImage 转换为 cv::Mat【英文标题】:converting QImage to cv::Mat by using raw data 【发布时间】:2014-05-17 22:44:21 【问题描述】:

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

【问题讨论】:

【参考方案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() 如果它使用引用计数机制(也许我在这里错了)即使在您发布的语句中也会发生内存映射错误和之后不会。

以上是关于使用原始数据将 QImage 转换为 cv::Mat的主要内容,如果未能解决你的问题,请参考以下文章

使用 QImage::loadFromData 将 cv::mat 转换为 QImage

将 QImage* 转换为 void* ,反之亦然

将 cv::mat 转换为 QImage

使用 PySide 将 QImage 转换为 Numpy 数组

Qt5 将 QImage 转换为 OpenGL 格式

可以将 QImage 文件内容加载到 QString 吗?