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.

SecretAgentMan
  • 2,856
  • 7
  • 21
  • 41
JonaGik
  • 1,533
  • 5
  • 24
  • 35
  • You might be having an issue discussed in the following thread. http://stackoverflow.com/questions/1356543/cvgetcaptureproperty-always-return-0-for-cv-cap-prop-frame-count – Dmitri Bouianov Feb 04 '12 at 06:25

2 Answers2

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.

Sam
  • 19,708
  • 4
  • 59
  • 82
  • 1
    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. – JonaGik Feb 04 '12 at 10:18
  • 2
    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 – Sam Feb 04 '12 at 15:55
  • Regarding your first point, is there a way to get around this? How might I find the number of frames in a video? – JonaGik Feb 07 '12 at 01:21
  • 1
    Nothing worth the effort. But you can use a dynamic array to keep your frames in. A vector is as good as a Mat**. – Sam Feb 07 '12 at 16:22
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];
TheBoxyBear
  • 371
  • 2
  • 15
  • 1
    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? – Yunnosch Nov 03 '20 at 17:58
  • Even if I am wrong, please take the [tour] and read [answer]. – Yunnosch Nov 03 '20 at 17:58
  • 1
    This does not provide an answer to the question. You can [search for similar questions](/search), 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](/questions/ask), and include a link to this one to help provide context. See: [Ask questions, get answers, no distractions](/tour) – Yunnosch Nov 03 '20 at 18:12