C++ / cv::Mat相当于使用memcpy创建IplImage

4

我得到了一些代码,其中使用memcpy创建了一个IplImage,然后转换为cv :: Mat:

IplImage* iplImage = cvCreateImage(cv::Size(imageWidth, imageHeight), IPL_DEPTH_8U, bytesPerPixel);
memcpy(iplImage->imageData, memory, imageWidth * imageHeight * bytesPerPixel);
cv::Mat image = cv::cvarrToMat(iplImage, true, true, 0);
cvReleaseImage(&iplImage);

内存是指向内存块开头的空指针。

我希望将这段代码移植到仅使用OpenCV C++ Api。这是我首先尝试的方法:

cv::Mat image(cv::Size(imageWidth, imageHeight), CV_MAKETYPE(CV_8U, bytesPerPixel), memory);

但是图片是空的。
然后我尝试了这个:
cv::Mat image(cv::Size(imageWidth, imageHeight), CV_MAKETYPE(CV_8U, bytesPerPixel));
memcpy(image.data, memory, imageWidth * imageHeight * bytesPerPixel);

这种方法可以使用,但是它会占用更多的RAM(约100mb),因此我想可能存在一些不必要的复制。

正确的方法应该是什么?

编辑:内存实际上在一个包装类中。它会自动释放。我为了简单起见将其改为了“memory”。

编辑2:这是完整的代码,包括内存来源的对象:

cv::Mat RecordingPlayer::next() {
    if (currentContainer.getDataType() == odcore::data::image::SharedImage::ID()) {
        odcore::data::image::SharedImage sharedImage = currentContainer.getData<odcore::data::image::SharedImage>();
        std::shared_ptr<odcore::wrapper::SharedMemory> memory = odcore::wrapper::SharedMemoryFactory::attachToSharedMemory(sharedImage.getName());
        IplImage* iplImage = cvCreateImage(imageSize(), IPL_DEPTH_8U, bytesPerPixel);
        memcpy(iplImage->imageData, memory->getSharedMemory(), imageWidth * imageHeight * bytesPerPixel);
        cv::Mat image = cv::cvarrToMat(iplImage, true, true, 0);
        cvReleaseImage(&iplImage);
        return image;
    } else {
        return cv::Mat();
    }
}

在你第一次尝试后,你是否释放了内存? - Miki
没有. 内存被封装在一个奇怪的SharedMemory对象中,该对象又被封装在一个std::shared_ptr中。 - Sebastian.M
你能否使用一些虚拟数据在内存中构建一个 [mcve],这样会更容易找到问题所在。你的第一次尝试是正确的方法,问题似乎出现在你的共享对象中。 - Miki
1
所以,只是为了确保,当您的图像仍然有效时,“memory”会自动释放?很可能是的。 - Miki
我同意。然而问题在于数据来自我没有太多文档的另一个库。我不知道数据长什么样子,就我所见,也没有可能只是用虚拟数据创建这样的对象。 - Sebastian.M
1个回答

4
问题在于在矩阵仍然有效的情况下,memory->getSharedMemory()中的数据被释放了。OpenCV在底层数据上创建了一个矩阵头,但无法对其进行控制。因此,您需要对这些底层数据进行深层复制。最简单的方法是使用clone()
cv::Mat image = Mat(cv::Size(imageWidth, imageHeight), CV_MAKETYPE(CV_8U, bytesPerPixel), memory->getSharedMemory()).clone(); 

1
可以了,非常感谢!而且它不使用版本2中的额外内存。但我必须承认,我不明白为什么。我本以为memcpy和克隆Mat会做更多或更少相同的事情。 - Sebastian.M
我不能为你详细解释这个(我应该运行一些测试并检查源代码...),但总的来说,OpenCV在内存管理和优化方面非常聪明,因此使用OpenCV函数通常比朴素的实现更好。你可以问一个关于此的新问题(删除所有与您的情况特定相关的内容)。那将很有趣。 - Miki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接