简体   繁体   English

OpenCV/Python:使用 VideoCapture 读取特定帧

[英]OpenCV/Python: read specific frame using VideoCapture

Is there a way to get a specific frame using VideoCapture() method?有没有办法使用VideoCapture()方法获取特定帧?

My current code is:我目前的代码是:

import numpy as np
import cv2

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

This is my reference tutorial. 是我的参考教程。

Thank you GPPK.谢谢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()

The following code can accomplish that:下面的代码可以做到这一点:

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

frame_number is an integer in the range 0 to the number of frmaes in the video. frame_number是一个整数,范围为 0 到视频中的帧数。
Notice: you should set frame_number-1 to force reading frame frame_number .注意:你应该设置frame_number-1来强制阅读frame_number It's not documented well but that is how the VideoCapture module behaves.它没有很好地记录,但这就是 VideoCapture 模块的行为方式。

One may obtain amount of frames by:可以通过以下方式获得帧数:

amount_of_frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)

If you want an exact frame, you could just set the VideoCapture session to that frame.如果您想要一个精确的帧,您可以将 VideoCapture 会话设置为该帧。 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. “正确”的解决方案要求您输入已知数据:如 fps、长度等。 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

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:从 VideoCaptureProperties ( docs ) 的文档中可以看出,在 VideoCapture 中设置帧的方法是:

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" .请注意,您不必传递给函数frame - 1因为,正如文档所述,标志CAP_PROP_POS_FRAMES表示“接下来要解码/捕获的帧的基于 0 的索引”

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:在上面链接的文档中可以看到在 VideoCapture 中设置特定时间的方法是:

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()

For example, to start reading 15th frame of the video you can use:例如,要开始阅读视频的第 15 帧,您可以使用:

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

In addition, I want to say, that using of CAP_PROP_POS_FRAMES property does not always give you the correct result.另外,我想说的是,使用CAP_PROP_POS_FRAMES属性并不总是会给你正确的结果。 Especially when you deal with compressed files like mp4 (H.264).尤其是在处理 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 .就我而言,当我为 .mp4 文件调用cap.set(cv2.CAP_PROP_POS_FRAMES, frame_number)时,它返回False ,但是当我为 .avi 文件调用它时,它返回True Take into consideration when decide using this 'feature'.在决定使用此“功能”时考虑。

very-hit recommends using CV_CAP_PROP_POS_MSEC property. very-hit建议使用CV_CAP_PROP_POS_MSEC属性。

Read this thread for additional info.阅读此线程以获取更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM