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

628mspwn  于 2022-12-28  发布在  Python
关注(0)|答案(6)|浏览(241)

有没有办法用VideoCapture()方法得到一个特定的帧?
我的当前代码是:

import numpy as np
import cv2

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

This是我的参考教程。

b09cbbtk

b09cbbtk1#

下面的代码可以实现这一点:

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

frame_number是范围0到视频中帧的数目的整数。
注意:您应该设置frame_number-1以强制阅读帧frame_number。虽然没有详细说明,但这就是VideoCapture模块的行为方式。
可以通过以下方式获得帧数:

amount_of_frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)
yfwxisqw

yfwxisqw2#

谢谢GPPK。
视频参数应该是整数。每个标志都有自己的值。代码见here
正确的解决方案是:

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

rur96b6h3#

如果您想要一个精确的帧,您可以将VideoCapture会话设置为该帧。自动调用该帧要直观得多。“正确”的解决方案需要您输入已知数据:比如fps,长度,等等。使用下面的代码,你只需要知道你想要调用的帧。

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

如果您想保留窗口,直到按退出:

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

5jvtdoz24#

设置特定帧

从VideoCaptureProperties(docs)的文档中可以看出,在VideoCapture中设置帧的方法是:

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

请注意,您不必传递给函数frame - 1,因为正如文档所述,标志CAP_PROP_POS_FRAMES ra表示 “下一个要解码/捕获的帧的从0开始的索引”
结束一个完整的例子,我想在每一秒读一帧是:

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

设置特定时间

在以上链接的文档中,可以看到在VideoCapture中设置特定时间的方法是:

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

和前面一样,每秒读取一帧的完整示例将以这种方式实现:

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

8wtpewkr5#

例如,要开始阅读视频的第15帧,您可以用途:

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

v9tzhpje6#

另外,我想说的是,使用CAP_PROP_POS_FRAMES属性并不总是给予你正确的结果,特别是当你处理像mp4(H.264)这样的压缩文件时。
在我的情况下,当我调用cap.set(cv2.CAP_PROP_POS_FRAMES, frame_number)为.mp4文件,它返回False,但当我调用它为.avi文件,它返回True .考虑当决定使用这个'功能'.
very-hit建议使用CV_CAP_PROP_POS_MSEC属性。
阅读this thread以了解更多信息。

相关问题