OpenCV/Python:使用 VideoCapture 读取特定帧
Posted
技术标签:
【中文标题】OpenCV/Python:使用 VideoCapture 读取特定帧【英文标题】:OpenCV/Python: read specific frame using VideoCapture 【发布时间】:2016-02-12 13:39:35 【问题描述】:有没有办法使用VideoCapture()
方法获取特定帧?
我当前的代码是:
import numpy as np
import cv2
cap = cv2.VideoCapture('video.avi')
This是我的参考教程。
【问题讨论】:
【参考方案1】:感谢 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://***.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()
【讨论】:
在python 3.5
使用cap.set()
中,第一个参数定义范围为0.0-1.0 的帧号。所以它是cap.set(1,frame_no)
。
在 cap.set() 中,第一个参数应该是 'cv2.cv.CV_CAP_PROP_POS_FRAMES',没有任何魔法 '1' 或 '2'。第二个是 0 - cv2.cv.CV_CAP_PROP_FRAME_COUNT 范围内的帧号 - 它是一个整数,而不是浮点数 0.0 - 1.0!
@AlexeyAntonenko 重要的是要注意转换为“索引”并不总是完美的。它不一定给你准确的“索引”框架,我猜开发人员只是包装了旧的 [0-1] 代码并且存在舍入错误。我在 OpenCV 页面上发布了一个问题/错误报告,因为他们主页上的实际错误报告链接已损坏。 answers.opencv.org/question/200232/…
使用 opencv-python-4.1.1.26,找不到 cv2.cv.CV_CAP_PROP_POS_FRAMES。也许枚举已关闭,但我不得不使用 vid.set(1, myEndFrame)。【参考方案2】:
如果您想要一个精确的帧,您可以将 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
【讨论】:
cap.set(1,frame_no)
中的 1 是什么?
看看下面我的回答。【参考方案3】:
是的,很简单:
import cv2
cap = cv2.VideoCapture(videopath)
cap.set(cv2.CV_CAP_PROP_POS_FRAMES, frame_number-1)
res, frame = cap.read()
'frame_number' 是 0...amount_of_frames 范围内的整数。注意:你应该设置'frame_number-1'来强制阅读框架'frame_number'。它没有很好地记录,但测试表明 VideoCapture 模块的行为。
'res' 是布尔运算结果,可以用它来检查帧是否被成功读取。 可以通过以下方式获得帧数:
amount_of_frames = cap.get(cv2.CV_CAP_PROP_FRAME_COUNT)
【讨论】:
cv2.cv.CV_CAP_PROP_FRAME_COUNT
对我不可用。我确实找到了cv2.CAP_PROP_FRAME_COUNT
我猜你使用的是 cv 3.x。 Opencv 3.x 在 cv2 模块中定义了这些常量,并且没有 CV_ 前缀。 Opencv 2.x 在 cv2.cv 模块中定义它们,并带有 CV_ 前缀。
对于 cap.set,您需要使用 frame_number 作为 [0;amount_of_frames-1] 的索引。按照您的建议,对于第一帧,我们应该设置 0-1=-1,对吗?这是没有意义的,因为 cap.set 在该操作之后返回 0。但是,在某些 mp4 视频上,我可以设置 0 帧和 num_of_frames 帧并成功读取它们(因此,总共读取 n+1 帧),这显然是一些舍入错误。
该属性现在被命名为cv2.cv2.CAP_PROP_POS_FRAMES
或者只是cv2.CAP_PROP_POS_FRAMES
【参考方案4】:
例如,要开始阅读视频的第 15 帧,您可以使用:
frame = 15
cap.set(cv2.CAP_PROP_POS_FRAMES, frame-1)
【讨论】:
【参考方案5】:设置特定框架
从VideoCaptureProperties(docs)的文档中可以看出在VideoCapture中设置帧的方式是:
frame = 30
cap.set(cv2.CAP_PROP_POS_FRAMES, frame)
请注意,您不必传递给函数 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()
设置具体时间
在上面链接的文档中可以看到,在 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()
【讨论】:
这是最新的答案。【参考方案6】:另外,我想说的是,使用CAP_PROP_POS_FRAMES
属性并不总是给你正确的结果。尤其是在处理 mp4 (H.264) 等压缩文件时。
在我的情况下,当我为 .mp4 文件调用 cap.set(cv2.CAP_PROP_POS_FRAMES, frame_number)
时,它返回 False
,但当我为 .avi 文件调用它时,它返回 True
。
决定使用此“功能”时要考虑到。
very-hit 建议使用CV_CAP_PROP_POS_MSEC
属性。
阅读this thread了解更多信息。
【讨论】:
以上是关于OpenCV/Python:使用 VideoCapture 读取特定帧的主要内容,如果未能解决你的问题,请参考以下文章
使用 imshow + waitKey 显示图像 opencv+python 时出现问题
使用 OpenCV+Python-2.7 进行全身检测和跟踪