20

I need to access frames from video by the frame index. So far I used code like this:

video = cv2.VideoCapture(video_path)
status, frame = video.read()

The code reads the first frame. If I use the code repeatedly I will get next frames. But how I can access directly any frame by its index?

In other words, if I want second frame, how can I access directly the second frame without calling read() two times?

1

2 Answers 2

33

Use VideoCapture::set() with CAP_PROP_POS_FRAMES property id to set the position of the frame to be read.

myFrameNumber = 50
cap = cv2.VideoCapture("video.mp4")

# get total number of frames
totalFrames = cap.get(cv2.CAP_PROP_FRAME_COUNT)

# check for valid frame number
if myFrameNumber >= 0 & myFrameNumber <= totalFrames:
    # set frame position
    cap.set(cv2.CAP_PROP_POS_FRAMES,myFrameNumber)

while True:
    ret, frame = cap.read()
    cv2.imshow("Video", frame)
    if cv2.waitKey(20) & 0xFF == ord('q'):
        break

cv2.destroyAllWindows()
Sign up to request clarification or add additional context in comments.

6 Comments

cap.set(1, myFrameNumber) is required for python 3
Thanks, @zindarod for the help! It's also recommended to add cap.release() before cv2.destroyAllWindows()
This method can lead to incorrect results - see github.com/opencv/opencv/issues/9053 . Basically opencv can't do reliable random access
@Peter Thank you for pointing this out. Do you know if subsequent frames produced by calls to read() will be consecutive?
Yes, I believe so - though I have had the experience of getting None returned partway through a video, only to get a frame on the next call to read() ... So I'm not sure what that means. All solutions are bad though as far as I know. pyav works but is slow decord is fast but eats way to much memory on long videos.
|
2
import os
folder= 'frames'
os.mkdir(folder)
import cv2
vidcap = cv2.VideoCapture('four.mp4')
def getFrame(sec):
    vidcap.set(cv2.CAP_PROP_POS_MSEC,sec*1000)
    hasFrames,image = vidcap.read()
    if hasFrames:
        cv2.imwrite("image"+str(count)+".jpg", image)     # save frame as JPG file
    return hasFrames
sec = 0
frameRate = 0.5 #//it will capture image in each 0.5 second
count=1
success = getFrame(sec)
while success:
    count = count + 1
    sec = sec + frameRate
    sec = round(sec, 2)
    success = getFrame(sec)

Comments

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.