4

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.

1

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for your answer! I found that "cap >> frame" populated each Mat object's parameters but didn't copy the data. To get around it, I got some memory from the heap, copied the data to that memory, then set "frame.data = myMemoryPtr" where myMemoryPtr is the pointer to the allocated memory.
that's the same as frame.copyTo(). I prefer my version, since it's clean, and OpenCV automatically frees the memory when it's not used anymore
Regarding your first point, is there a way to get around this? How might I find the number of frames in a video?
Nothing worth the effort. But you can use a dynamic array to keep your frames in. A vector<Mat> is as good as a Mat**.
1

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];

3 Comments

Do I understand correctly that you created this post to ask a different question than the one at the top of this page and then have edited it, to answer your own question which does not answer the question at the top of this page?
Even if I am wrong, please take the tour and read How to Answer.
This does not provide an answer to the question. You can search for similar questions, or refer to the related and linked questions on the right-hand side of the page to find an answer. If you have a related but different question, ask a new question, and include a link to this one to help provide context. See: Ask questions, get answers, no distractions

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.