JonaGik
JonaGik

Reputation: 1573

OpenCV - Creating an Array of Mat Objects

I would have thought this is trivial, but I'm having some trouble with it.

I want to read a video file into memory and store it in an array. I want the array to be of pointers to Mat objects.

This is the code I'm using:

cv::VideoCapture vidCap = cv::VideoCapture("file.avi");
int frames = (int)vidCap.get(CV_CAP_PROP_FRAME_COUNT);
cv::Mat** frameArray = new cv::Mat*[frames];
for (int num = 0; num < frames; num++) {
     frameArray[num] = new cv::Mat;
     vidCap >> *(frameArray[num]);
}

However, when I display an image (for example, the first image in the array), it displays the last frame. Where am I going wrong? This is the code for displaying the image:

cv::namedWindow("Movie", 1);
cv::imshow("Movie", *(frameArray[0]));
cv::waitKey(0);

I would imagine that, since it's displaying the last image, all the pointers in the array are the same and, therefore, it is modifying the same memory. However, when I printf the pointers, they are different.

Upvotes: 4

Views: 15694

Answers (2)

TheBoxyBear
TheBoxyBear

Reputation: 391

But is there actually a way of creating Mat arrays? I really don't see other options in my case but trying to access an item in the array considers the array as a single Mat and thinks I'm trying to access its data.

Edit: Found a workaround using a pointer:

Mat* array = new Mat[arraySize];

Upvotes: 1

Sam
Sam

Reputation: 20056

There are more flaws in your code. At least two of them are:

  1. vidCap.get(CV_CAP_PROP_FRAME_COUNT); does not return the correct number of frames, most of the time. That's it, ffmpeg can't do better. For some codecs it works, for some, in doesn't.

  2. Mat matrices have an interesting behaviour. They are actually pointers to the matrix data, not objects. When you say new Mat you just create a new pointer. And combined with the fact that videoCap returns all the time the same memory area, just with new data, you acutually will have a vector of pointers pointing to the last frame.

You have to capture the frame in a separate image and copy to the reserved location:

std::vector<cv::Mat> frames;
cap >> frame;
frames.push_back(frame.clone());

Please note the change from array of pointers to a vector of objects. This avoids the need for reading the number of frames beforehand, and also makes the code safer.

Upvotes: 3

Related Questions