OpenCV/Python: read specific frame using VideoCapture

PythonPython 2.7Opencv

Python Problem Overview


Is there a way to get a specific frame using VideoCapture() method?

My current code is:

import numpy as np
import cv2

cap = cv2.VideoCapture('video.avi')

This is my reference tutorial.

Python Solutions


Solution 1 - Python

Thank you GPPK.

The video parameters should be given as integers. Each flag has its own value. See here for the codes.

The correct solution is:

import numpy as np
import cv2

#Get video name from user
#Ginen video name must be in quotes, e.g. "pirkagia.avi" or "plaque.avi"
video_name = input("Please give the video name including its extension. E.g. \"pirkagia.avi\":\n")

#Open the video file
cap = cv2.VideoCapture(video_name)

#Set frame_no in range 0.0-1.0
#In this example we have a video of 30 seconds having 25 frames per seconds, thus we have 750 frames.
#The examined frame must get a value from 0 to 749.
#For more info about the video flags see here: https://stackoverflow.com/questions/11420748/setting-camera-parameters-in-opencv-python
#Here we select the last frame as frame sequence=749. In case you want to select other frame change value 749.
#BE CAREFUL! Each video has different time length and frame rate. 
#So make sure that you have the right parameters for the right video!
time_length = 30.0
fps=25
frame_seq = 749
frame_no = (frame_seq /(time_length*fps))

#The first argument of cap.set(), number 2 defines that parameter for setting the frame selection.
#Number 2 defines flag CV_CAP_PROP_POS_FRAMES which is a 0-based index of the frame to be decoded/captured next.
#The second argument defines the frame number in range 0.0-1.0
cap.set(2,frame_no);

#Read the next frame from the video. If you set frame 749 above then the code will return the last frame.
ret, frame = cap.read()

#Set grayscale colorspace for the frame. 
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

#Cut the video extension to have the name of the video
my_video_name = video_name.split(".")[0]

#Display the resulting frame
cv2.imshow(my_video_name+' frame '+ str(frame_seq),gray)

#Set waitKey 
cv2.waitKey()

#Store this frame to an image
cv2.imwrite(my_video_name+'_frame_'+str(frame_seq)+'.jpg',gray)

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

Solution 2 - Python

Yes, it's very straight forward:

import cv2
cap = cv2.VideoCapture(videopath)
cap.set(cv2.CV_CAP_PROP_POS_FRAMES, frame_number-1)
res, frame = cap.read()

'frame_number' is an integer in range 0...amount_of_frames. Notice: you should set 'frame_number-1' to force reading frame 'frame_number'. It's not documented well but test shows that behavior of VideoCapture module.

'res' is boolean result of operation, one may use it to check if frame was successfully read. One may obtain amount of frames by:

amount_of_frames = cap.get(cv2.CV_CAP_PROP_FRAME_COUNT)

Solution 3 - Python

If you want an exact frame, you could just set the VideoCapture session to that frame. It's much more intuitive to automatically call on that frame. The "correct" solution requires you to input known data: like fps, length, and whatnot. All you need to know with the code below is the frame you want to call.

import numpy as np
import cv2
cap = cv2.VideoCapture(video_name) #video_name is the video being called
cap.set(1,frame_no); # Where frame_no is the frame you want
ret, frame = cap.read() # Read the frame
cv2.imshow('window_name', frame) # show frame on window

If you want to hold the window, until you press exit:

while True:
    ch = 0xFF & cv2.waitKey(1) # Wait for a second
    if ch == 27:
		break

Solution 4 - Python

Set a specific frame

From the documentation of the VideoCaptureProperties (docs) is possible to see that the way to set the frame in the VideoCapture is:

frame = 30
cap.set(cv2.CAP_PROP_POS_FRAMES, frame)

Notice that you don't have to pass to the function frame - 1 because, as the documentation says, the flag CAP_PROP_POS_FRAMES rapresent the "0-based index of the frame to be decoded/captured next".

Concluding a full example where i want to read a frame at each second is:

import cv2

cap = cv2.VideoCapture('video.avi')

# Get the frames per second
fps = cap.get(cv2.CAP_PROP_FPS) 

# Get the total numer of frames in the video.
frame_count = cap.get(cv2.CAP_PROP_FRAME_COUNT)

frame_number = 0
cap.set(cv2.CAP_PROP_POS_FRAMES, frame_number) # optional
success, image = cap.read()

while success and frame_number <= frame_count:

    # do stuff

    frame_number += fps
    cap.set(cv2.CAP_PROP_POS_FRAMES, frame_number)
    success, image = cap.read()

Set a specific time

In the documentation linked above is possible to see that the way to set a specific time in the VideoCapture is:

milliseconds = 1000
cap.set(cv2.CAP_PROP_POS_MSEC, milliseconds)

And like before a full example that read a frame each second che be achieved in this way:

import cv2

cap = cv2.VideoCapture('video.avi')

# Get the frames per second
fps = cap.get(cv2.CAP_PROP_FPS) 

# Get the total numer of frames in the video.
frame_count = cap.get(cv2.CAP_PROP_FRAME_COUNT)

# Calculate the duration of the video in seconds
duration = frame_count / fps

second = 0
cap.set(cv2.CAP_PROP_POS_MSEC, second * 1000) # optional
success, image = cap.read()

while success and second <= duration:

    # do stuff

    second += 1
    cap.set(cv2.CAP_PROP_POS_MSEC, second * 1000)
    success, image = cap.read()

Solution 5 - Python

For example, to start reading 15th frame of the video you can use:

frame = 15
cap.set(cv2.CAP_PROP_POS_FRAMES, frame-1)

Solution 6 - Python

In addition, I want to say, that using of CAP_PROP_POS_FRAMES property does not always give you the correct result. Especially when you deal with compressed files like mp4 (H.264).

In my case when I call cap.set(cv2.CAP_PROP_POS_FRAMES, frame_number) for .mp4 file, it returns False, but when I call it for .avi file, it returns True. Take into consideration when decide using this 'feature'.

very-hit recommends using CV_CAP_PROP_POS_MSEC property.

Read this thread for additional info.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionzinonView Question on Stackoverflow
Solution 1 - PythonzinonView Answer on Stackoverflow
Solution 2 - PythonAlexey AntonenkoView Answer on Stackoverflow
Solution 3 - PythonJParrish88View Answer on Stackoverflow
Solution 4 - PythonVittorioView Answer on Stackoverflow
Solution 5 - PythonDawid PustówkaView Answer on Stackoverflow
Solution 6 - PythonVolkov MaximView Answer on Stackoverflow