19

I have the following code, which continuously fetches all the frames from a video by using VideoCapture library in opencv in python:

import cv2

def frame_capture:
        cap = cv2.VideoCapture("video.mp4")
        while not cap.isOpened():
                cap = cv2.VideoCapture("video.mp4")
                cv2.waitKey(1000)
                print "Wait for the header"

        pos_frame = cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES)
        while True:
                flag, frame = cap.read()
                if flag:
                        # The frame is ready and already captured
                        cv2.imshow('video', frame)
                        pos_frame = cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES)
                        print str(pos_frame)+" frames"
                else:
                        # The next frame is not ready, so we try to read it again
                        cap.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, pos_frame-1)
                        print "frame is not ready"
                        # It is better to wait for a while for the next frame to be ready
                        cv2.waitKey(1000)

                if cv2.waitKey(10) == 27:
                        break
                if cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES) == cap.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT):
                        # If the number of captured frames is equal to the total number of frames,
                        # we stop
                        break

But I want to grab a specific frame in a specific timestamp in the video.

How can I achieve this?

6
  • 1
    set the position using CV_CAP_PROP_POS_MSEC , and then grab the frame Commented Nov 4, 2015 at 14:01
  • Could you give a small example? :) Commented Nov 4, 2015 at 14:04
  • 1
    not in Python, I couldn't test it :D Commented Nov 4, 2015 at 14:06
  • 1
    I would presume it would be similar to: frame = cap.get(CV_CAP_PROP_POS_MSEC(10)). Although this may be a more difficult problem than this Commented Nov 4, 2015 at 15:14
  • 2
    @GPPK it should be more like cap.set(CV_CAP_PROP_POS_MSEC, 123) frame = cap.read(). All if set works properly as you mentioned Commented Nov 4, 2015 at 15:53

2 Answers 2

41

You can use set() function of VideoCapture.

You can calculate total frames:

cap = cv2.VideoCapture("video.mp4")
total_frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)

Here 7 is the prop-Id. You can find more here http://docs.opencv.org/2.4/modules/highgui/doc/reading_and_writing_images_and_video.html

After that you can set the frame number, suppose i want to extract 100th frame

cap.set(cv2.CAP_PROP_FRAME_COUNT, 100)
ret, frame = cap.read()
cv2.imwrite("path_where_to_save_image", frame)
Sign up to request clarification or add additional context in comments.

5 Comments

Nice! I'd specify that 7 is the ordinal value of CV_CAP_PROP_FRAME_COUNT and that 1 is the ordinal value of CV_CAP_PROP_POS_FRAMES - so what you're doing here is, you're actually moving the "frame reader" to the offset of the 100th frame, and then you read the "next" one, that is the 101st frame
is there a way to set the number of frames to be extracted?
what if the frames are recieved from a web cam. Does this take effect
The magic number 7 is actually the constant cv2.CAP_PROP_FRAME_COUNT, i.e. total_frames = cap.get(cv2.CAP_PROP_FRAME_COUNT) .
Doesn't work for me. I get empty frames (NP array full of zeros) whatever video file and whatever count I use. Any idea why?
8

this is my first post so please don't rip into me if I don't follow protocol completely. I just wanted to respond to June Wang just in case she didn't figure out how to set the number of frames to be extracted, or in case anyone else stumbles upon this thread with that question:

The solution is the good ol' for loop:

    vid = cv2.VideoCapture(video_path)
    for i in range(start_frame, start_frame+how_many_frames_you_want):
        vid.set(1, i)
        ret, still = vid.read()
        cv2.imwrite(f'{video_path}_frame{i}.jpg', still)

3 Comments

Welcome to SO. Explaining how your code answers the question is always a good thing.
For me, this just print the same image for each number in range
Nice. Only that the range you were using was wrong. (range(start_frame, how_many_frames_you_want). I corrected it

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.