繁体   English   中英

Opencv VideoCapture 设置 CV_CAP_PROP_POS_FRAMES 不起作用

[英]Opencv VideoCapture set CV_CAP_PROP_POS_FRAMES not working

我正在使用 opencv 使用 mpeg 压缩从 Vivotek 相机的视频输出中读取帧。 我正在尝试使用该功能从特定位置开始播放视频,如下所示,其中 start 是我要跳过的帧数。

inputVideo.set(CV_CAP_PROP_POS_FRAMES, start); 

但是我遇到了这个问题,因为正在捕获不正确的帧,这发生在开始时的帧之前。

我正在使用 opencv 版本 2.4.2

有人可以帮忙解决这个问题吗?

有点晚了,但搜索相同的主题(不是特定于 Vivotek 相机,而是更多关于 openCV 的 mpeg 问题):

  • 视频已编码
  • OpenCV 使用 FFMPEG
  • 编码使用关键帧
  • 跳过某些帧时,编码无法为您提供所需的确切帧

看到类似的问题:

  • 在 cvSetCaptureProperty 中使用 CV_CAP_PROP_POS_FRAMES 获取单个帧

  • 如何从视频文件中获取一帧?

  • CV_CAP_PROP_POS_FRAMES 设置下一帧编号的问题

    desired position key frame (this is where the cursor will stop) | | | | | > | | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

    使用带有轨迹栏的 openCV 2.4.8 / VS2013 的示例代码:

  • 使用 AVI 格式 [MPEG4 Video (H264)] 测试:设置帧位置工作正常
  • 使用 MPG 格式 [MPEG1/MPEG2] 测试:设置帧位置工作正常

    double currentPos = capture.get(CV_CAP_PROP_POS_FRAMES); std::cout << "CV_CAP_PROP_POS_FRAMES = " << currentPos << std::endl; // position_slider 0 - 100 double noFrame = position_slider*nbFrames / 100; // solution 1 bool success = capture.set(CV_CAP_PROP_POS_FRAMES, noFrame); // solution 2 double frameRate = capture.get(CV_CAP_PROP_FPS); double frameTime = 1000.0 * noFrame / frameRate; bool success = capture.set(CV_CAP_PROP_POS_MSEC, frameTime); if (!success) { std::cout << "Cannot set frame position from video file at " << noFrame << std::endl; return; } currentPos = capture.get(CV_CAP_PROP_POS_FRAMES); if (currentPos != noFrame) { std::cout << "Requesting frame " << noFrame << " but current position == " << currentPos << std::endl; } success = capture.read(frame_aux); if (!success) { std::cout << "Cannot get frame from video file " << std::endl; return; } imshow("test", frame_aux);

正如 BlouBlou 所说,当你用 FFMPEG 读取一些高压缩视频格式时,它使用了“关键帧”技术来解码视频。 因此,设置CV_CAP_PROP_POS_FRAMES属性将无法正常工作。

我测试了 5 个 mpeg 视频以从中读取所有帧。 使用long totalFrameNumber = capture.get(CV_CAP_PROP_FRAME_COUNT);获取总帧数long totalFrameNumber = capture.get(CV_CAP_PROP_FRAME_COUNT);

然后我将每个视频读了两次,第一次没有将CV_CAP_PROP_POS_FRAMES设置为 0,第二次设置它。

当您将CV_CAP_PROP_POS_FRAMES设置为 0 时,它确实CV_CAP_PROP_POS_FRAMES了一些帧,每个视频大约 10 帧。 我猜是因为关键帧不在视频的第一帧,所以FFMPEG会跳过一些帧到第一个关键帧。 但有些视频格式如.avi 不会出现这样的问题。 我希望我的真实经历可以为其他人节省很多时间(我花了很长时间才找到这个页面,但已经足够了)。

无论如何,强烈建议不要在面对 mpeg 格式的视频时使用CV_CAP_PROP_POS_FRAMES来获取特定帧。 设置CV_CAP_PROP_POS_MSEC是一个明智的选择:)

如果您愿意升级到 OpenCV 3.0,以下 2 个用例可能对您有所帮助。 这可能适用于早期版本,但我还没有尝试过。 如果您希望它捕获帧 a 和帧 b 之间的所有帧,请参阅第二个用例并将“desired_frames”替换为:

desired_frames = range(a,b)

首先导入一些包

import cv2
import math
import numpy as np

每 n 秒捕获一次(这里,n = 5)

#################### Setting up the file ################
videoFile = "Jumanji.mp4"
vidcap = cv2.VideoCapture(videoFile)
success,image = vidcap.read()

#################### Setting up parameters ################

seconds = 5
fps = vidcap.get(cv2.CAP_PROP_FPS) # Gets the frames per second
multiplier = fps * seconds

#################### Initiate Process ################

while success:
    frameId = int(round(vidcap.get(1))) #current frame number, rounded b/c sometimes you get frame intervals which aren't integers...this adds a little imprecision but is likely good enough
    success, image = vidcap.read()

    if frameId % multiplier == 0:
        cv2.imwrite("FolderSeconds/frame%d.jpg" % frameId, image)

vidcap.release()
print "Complete"

或者,每 n 帧捕获一次(此处,n = 10)

#################### Setting up the file ################
videoFile = "Jumanji.mp4"
vidcap = cv2.VideoCapture(videoFile)
success,image = vidcap.read()

#################### Setting up parameters ################

#OpenCV is notorious for not being able to good to 
# predict how many frames are in a video. The point here is just to 
# populate the "desired_frames" list for all the individual frames
# you'd like to capture. 

fps = vidcap.get(cv2.CAP_PROP_FPS)
est_video_length_minutes = 3         # Round up if not sure.
est_tot_frames = est_video_length_minutes * 60 * fps  # Sets an upper bound # of frames in video clip

n = 5                             # Desired interval of frames to include
desired_frames = n * np.arange(est_tot_frames) 


#################### Initiate Process ################

for i in desired_frames:
    vidcap.set(1,i-1)                      
    success,image = vidcap.read(1)         # image is an array of array of [R,G,B] values
    frameId = vidcap.get(1)                # The 0th frame is often a throw-away
    cv2.imwrite("FolderFrames/frame%d.jpg" % frameId, image)

vidcap.release()
print "Complete"

差不多就是这样。


一些不幸的警告...取决于您的 opencv 版本(这是为 opencv V3 构建的),您可能需要以不同的方式设置 fps 变量。 有关详细信息,请参见此处 要找出您的版本,您可以执行以下操作:

 (major_ver, minor_ver, subminor_ver) = (cv2.__version__).split('.') major_ver

对我来说奇怪的是,我在前面有一个assert

inputVideo.set(CV_CAP_PROP_POS_FRAMES, start); 

并删除该assert解决了问题

暂无
暂无

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

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