user6709725
user6709725

Reputation:

cv::Mat will be changed after inserting it into a std::map? What is the underlying reason?

I meet this problem when I deal with image streams from multi-cameras. I create a map and put all images into it based on the camera id, so I have:

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

I will add image into that map by calling addImages as soon as receiving data from a specific camera:

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);
}

When I show images from that map somewhere else, strange thing happens. The image changes and I can tell that its color differs from the original one.

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

But when I change addImages codes a little bit, images are same as original ones which is expected.

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);
}

So, my question is, what is the difference? Is there any other way to solve this problem?

Upvotes: 0

Views: 313

Answers (1)

john
john

Reputation: 87959

This line seems incorrect.

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

Here's a quote from the documentation on the fourth parameter to this constructor

Pointer to the user data. Matrix constructors that take data and step parameters do not allocate matrix data. Instead, they just initialize the matrix header that points to the specified data, which means that no data is copied.

In other words the Mat object just stores this pointer, it doesn't copy the data from it.

Now when your addImages function exits it destroys the imgData object which (presumably) invalidates the pointer you have just stored in the img object. That results in the problem you see.

The second version creates a clone of the img object which does copy the image data and so breaks the connection between the img object and the imgData object.

You might be able to fix this problem by passing the imgData parameter by reference. This means the imgData object would not be destroyed at the end of the function. But you would still have a situation where the Mat object and the CameraData object are sharing image data. So that might not be a good solution, but only you could say that for sure.

Upvotes: 2

Related Questions