Opencv VideoCapture设置CV_CAP_PROP_POS_FRAMES不起作用

时间:2013-10-16 13:05:03

标签: opencv

我正在使用opencv使用mpeg压缩从Vivotek相机的视频输出中读取帧。我正在尝试使用该函数从特定位置启动视频。如下所示,start是我想要跳过的帧数。

inputVideo.set(CV_CAP_PROP_POS_FRAMES, start); 

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

我正在使用opencv版本2.4.2

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

4 个答案:

答案 0 :(得分:13)

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

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

看到类似的问题:

  • Getting individual frames using CV_CAP_PROP_POS_FRAMES in cvSetCaptureProperty

  • How can I get one single frame from a video file?

  • Problem with CV_CAP_PROP_POS_FRAMES setting next frame number

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

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

  • 使用AVI格式测试[MPEG4视频(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);
    

答案 1 :(得分:2)

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

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

获取总帧数

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

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

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

是一个明智的选择

答案 2 :(得分:1)

如果您愿意升级到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变量。有关详细信息,请参阅here。要查找您的版本,您可以执行以下操作:

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

答案 3 :(得分:0)

奇怪的是,我在{p> 1前面有一个assert

inputVideo.set(CV_CAP_PROP_POS_FRAMES, start); 

并删除assert可解决问题