18

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?

yusuf
  • 3,591
  • 8
  • 45
  • 86
  • 1
    set the position using `CV_CAP_PROP_POS_MSEC `, and then grab the frame – Miki Nov 04 '15 at 14:01
  • Could you give a small example? :) – yusuf Nov 04 '15 at 14:04
  • 1
    not in Python, I couldn't test it :D – Miki Nov 04 '15 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](http://stackoverflow.com/questions/19404245/opencv-videocapture-set-cv-cap-prop-pos-frames-not-working) – GPPK Nov 04 '15 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 – Miki Nov 04 '15 at 15:53
  • Miki, how can I convert directly this kind of image to jpg, without saving? – yusuf Nov 04 '15 at 15:56

2 Answers2

39

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)
DomTomCat
  • 8,189
  • 1
  • 49
  • 64
Abhishek Sachan
  • 934
  • 3
  • 13
  • 26
  • 13
    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 – SomethingSomething Mar 27 '18 at 14:13
  • 3
    is there a way to set the number of frames to be extracted? – June Wang Aug 12 '19 at 17:24
  • what if the frames are recieved from a web cam. Does this take effect – Jacob Lawrence Feb 20 '21 at 09:43
  • The magic number 7 is actually the constant `cv2.CAP_PROP_FRAME_COUNT`, i.e. `total_frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)` . – Jabba Nov 07 '22 at 13:00
7

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, how_many_frames_you_want):
        vid.set(1, i)
        ret, still = vid.read()
        cv2.imwrite(f'{video_path}_frame{i}.jpg', still)
Eric De Luna
  • 71
  • 1
  • 2