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

zin*_*non 34 python opencv python-2.7

有没有办法使用VideoCapture()方法获取特定的框架?

我目前的代码是:

import numpy as np
import cv2

cap = cv2.VideoCapture('video.avi')
Run Code Online (Sandbox Code Playgroud)

是我的参考教程.

zin*_*non 32

谢谢GPPK.

视频参数应以整数形式给出.每个标志都有自己的值.请参阅此处查看代码.

正确的解决方案是:

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()
Run Code Online (Sandbox Code Playgroud)

  • 在cap.set()中,第一个参数应该是'cv2.cv.CV_CAP_PROP_POS_FRAMES'而没有任何魔法'1'或'2'.第二个是范围0中的帧号 - cv2.cv.CV_CAP_PROP_FRAME_COUNT - 它是一个整数,而不是浮点数0.0 - 1.0! (10认同)
  • 在使用 `cap.set()` 的 `python 3.5` 中,第一个参数定义了 0.0-1.0 范围内的帧号。所以它是`cap.set(1,frame_no)`。 (5认同)

Ale*_*nko 26

是的,它很直接:

import cv2
cap = cv2.VideoCapture(videopath)
cap.set(cv2.CV_CAP_PROP_POS_FRAMES, frame_number-1)
res, frame = cap.read()
Run Code Online (Sandbox Code Playgroud)

'frame_number'是0 ... amount_of_frames范围内的整数.注意:你应该设置'frame_number-1'来强制读取帧'frame_number'.它没有很好地记录,但测试显示了VideoCapture模块的行为.

'res'是操作的布尔结果,可以使用它来检查帧是否被成功读取.可以通过以下方式获得帧数:

amount_of_frames = cap.get(cv2.CV_CAP_PROP_FRAME_COUNT)
Run Code Online (Sandbox Code Playgroud)

  • `cv2.cv.CV_CAP_PROP_FRAME_COUNT`不适用于我.我找到了'cv2.CAP_PROP_FRAME_COUNT` (7认同)
  • 我猜你使用的是cv 3.x. Opencv 3.x在cv2模块中定义了这些常量,没有CV_前缀.Opencv 2.x在cv2.cv模块和CV_前缀中定义它们. (7认同)
  • 对于 cap.set,您需要使用frame_number 作为 [0;amount_of_frames-1] 的索引。根据您的建议,对于第一帧,我们应该设置 0-1=-1,对吧?这是没有意义的,因为 cap.set 在该操作之后返回 0。然而,在一些 mp4 视频上,我可以设置 0 帧和 num_of_frames 帧并成功读取它们(因此,总共读取 n+1 帧),这显然是一些舍入错误。 (2认同)

JPa*_*h88 19

如果您想要一个精确的帧,您可以将VideoCapture会话设置为该帧.自动调用该帧更加直观."正确"的解决方案要求您输入已知数据:如fps,length和诸如此类的东西.您需要知道的以下代码是您要调用的帧.

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
Run Code Online (Sandbox Code Playgroud)

如果要按住窗口,直到按退出:

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

  • `cap.set(1,frame_no)`中的1是什么? (2认同)

小智 12

设置特定帧

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

frame = 30
cap.set(cv2.CAP_PROP_POS_FRAMES, frame)
Run Code Online (Sandbox Code Playgroud)

请注意,您不必传递给该函数,frame - 1因为正如文档所说,该标志CAP_PROP_POS_FRAMES表示“接下来要解码/捕获的帧的基于 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()
Run Code Online (Sandbox Code Playgroud)

设置特定时间

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

milliseconds = 1000
cap.set(cv2.CAP_PROP_POS_MSEC, milliseconds)
Run Code Online (Sandbox Code Playgroud)

就像之前一个完整的例子一样,每秒读取一个帧可以通过这种方式实现:

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()
Run Code Online (Sandbox Code Playgroud)


小智 6

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

frame = 15
cap.set(cv2.CAP_PROP_POS_FRAMES, frame-1)
Run Code Online (Sandbox Code Playgroud)