我想将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
通常,cv::Mat会被重新计算,但这种情况比较特殊。如果您使用外部/借用的数据指针,您必须clone() mat,以确保它拥有自己的像素副本,否则,一旦您离开'scaleSvg()'的范围,mat 'out'持有'悬空指针'。
您尝试'new'要复制的数据,不幸的是,这并不能解决它(您只在那里添加了另一个问题)。
您还必须自己删除[]uchar *数据像素,而您没有这样做,因此您的代码目前组合了最糟糕的情况。
,试试:
out = cv::Mat(image.height(), image.width(), CV_8UC4, image.constBits(), CV_AUTOSTEP).clone();