首页 > 解决方案 > 将 cv::Mat 插入 std::map 后会改变吗?根本原因是什么?

问题描述

当我处理来自多相机的图像流时,我遇到了这个问题。我创建了一张地图并根据相机 ID 将所有图像放入其中,所以我有:

std::mat<uint32_t, cv::Mat> images;

addImages一旦从特定相机接收数据,我将通过调用将图像添加到该地图中:

void addImages(uint32_t camera_id, CameraData imgData)
{
  cv::Mat img = cv::Mat(imgData.height(), imgData.width(), CV_8UC3, (void *)imgData.ptr);
  images.insert(make_pair(camera_id, img));
  cv::imshow("origin image", img);
}

当我在其他地方显示该地图的图像时,会发生奇怪的事情。图像发生了变化,我可以看出它的颜色与原始颜色不同。

void showImage(uint32_t camera_id)
{
  cv::imshow("get image", images[camera_id]);
  cv::waitKey(1);
}

addImages但是当我稍微更改代码时,图像与预期的原始图像相同。

void addImages(uint32_t camera_id, CameraData imgData)
{
  cv::Mat img = cv::Mat(imgData.height(), imgData.width(), CV_8UC3, (void *)imgData.ptr);
  
  // NOTE THIS LINE!!! 
  images.insert(make_pair(camera_id, img.clone()));


  cv::imshow("origin image", img);
}

所以,我的问题是,有什么区别?有没有其他方法可以解决这个问题?

标签: c++opencv

解决方案


这条线似乎不正确。

cv::Mat img = cv::Mat(imgData.height(), imgData.width(), CV_8UC3, (void *)imgData.ptr);

这是此构造函数的第四个参数的文档中的引用

指向用户数据的指针。采用数据和步骤参数的矩阵构造函数不分配矩阵数据。相反,它们只是初始化指向指定数据的矩阵头,这意味着没有数据被复制。

换句话说,Mat对象只是存储这个指针,它不会从中复制数据。

现在,当您的addImages函数退出时,它会破坏imgData(可能)使您刚刚存储在对象中的指针无效的img对象。这会导致您看到的问题。

第二个版本创建了一个img对象的克隆,它确实复制了图像数据,因此中断了img对象和imgData对象之间的连接。

您可以imgData通过引用传递参数来解决此问题。这意味着imgData对象不会在函数结束时被销毁。但是您仍然会遇到Mat对象和CameraData对象共享图像数据的情况。所以这可能不是一个好的解决方案,但只有你可以肯定地说。


推荐阅读