使用原始数据将 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