【问题标题】:Reverse video playback in OpenCV在 OpenCV 中反向播放视频
【发布时间】:2012-06-29 10:20:37
【问题描述】:

是否可以在 OpenCV 中向后播放视频? 通过 API 调用或缓冲视频帧并将顺序反转为 一个新的视频文件。

谢谢

【问题讨论】:

    标签: video opencv reverse


    【解决方案1】:

    唯一可行的方法是手动提取帧,缓冲它们(在内存或文件上),然后以相反的顺序重新加载它们。

    问题在于视频压缩器都在利用时间冗余——事实上,两个连续的帧大部分时间都非常相似。因此,它们不时编码一个完整的帧(通常每几百帧),然后只发送前一个和当前之间的差异。

    现在,要使解码工作,必须按相同的顺序完成 - 解码一个关键帧(一个完整的),然后为每个新帧添加差异以获得当前图像。

    这种策略使得在视频中反向播放变得非常困难。有几种技术,但都涉及缓冲。

    现在,您可能已经看到了 Astor 描述的 CV_CAP_PROP_POS_FRAMES 参数。看起来没问题,但由于上述问题,OpenCV 无法正确跳转到特定帧(在这些问题上存在多个错误)。他们(OpenCV 开发人员)正在研究一些解决方案,但即使这些解决方案也会非常慢(它们涉及返回到前一个关键帧,然后解码回选定的关键帧)。如果使用这种技术,每帧必须平均解码数百次,因此速度非常慢。然而,它不起作用。

    编辑 如果您追求缓冲方式来反转它,请记住,解码后的视频将很快耗尽普通计算机的内存资源。一个普通的 720p 视频一分钟在解压缩时需要 4.7GB 内存!将帧作为单个文件存储在磁盘上是解决此问题的实用方法。

    【讨论】:

    • :) 不是,虽然我正在考虑一些补丁。但是我在 VideoCapture 同步方面遇到了一些问题,我发现了它的一些缺陷。
    【解决方案2】:

    另一种解决方案,类似于ArtemStorozhuk's answer 是使用 FPS 从帧域移动到时域,然后使用 CV_CAP_PROP_POS_MSEC 向后搜索(不会像 CV_CAP_PROP_POS_FRAMES 那样锤击 CPU)。这是我的示例代码,它在 .mpg 上完美运行,仅使用大约 50% 的 CPU。

    #include <opencv2/opencv.hpp>
    
    int main (int argc, char* argv[])
    {
      cv::VideoCapture cap(argv[1]);
    
      double frame_rate = cap.get(CV_CAP_PROP_FPS);
    
      // Calculate number of msec per frame.
      // (msec/sec / frames/sec = msec/frame)
      double frame_msec = 1000 / frame_rate;
    
      // Seek to the end of the video.
      cap.set(CV_CAP_PROP_POS_AVI_RATIO, 1);
    
      // Get video length (because we're at the end).
      double video_time = cap.get(CV_CAP_PROP_POS_MSEC);
    
      cv::Mat frame;
      cv::namedWindow("window");
    
      while (video_time > 0)
      {
        // Decrease video time by number of msec in one frame
        // and seek to the new time.
        video_time -= frame_msec;
        cap.set(CV_CAP_PROP_POS_MSEC, video_time);
    
        // Grab the frame and display it.
        cap >> frame;
        cv::imshow("window", frame);
    
        // Necessary for opencv's event loop to work.
        // Wait for the length of one frame before
        // continuing the loop. Exit if the user presses
        // any key. If you want the video to play faster
        // or slower, adjust the parameter accordingly.    
        if (cv::waitKey(frame_msec) >= 0)
          break;
      }
    }
    

    【讨论】:

    • so.. 按毫​​秒搜索比按帧搜索消耗的 CPU 更少?为什么?因为压缩?
    • 我认为这与视频的编码方式有关......每个数据包中都有一个时间戳,表示自视频开始以来的时间,因此在视频中寻找特定时间是一个简单的二分查找操作。但我不是视频编码方面的专家,所以请对这条评论持保留态度。
    【解决方案3】:

    是的,这是可能的。使用 cmets 查看代码:

    //create videocapture
    VideoCapture cap("video.avi");
    
    //seek to the end of file
    cap.set(CV_CAP_PROP_POS_AVI_RATIO, 1);
    
    //count frames
    int number_of_frames = cap.get(CV_CAP_PROP_POS_FRAMES);
    
    //create Mat frame and window to display
    Mat frame;
    namedWindow("window");
    
    //main loop
    while (number_of_frames > 0)
    {
        //decrease frames and move to needed frame in file
        number_of_frames--;
        cap.set(CV_CAP_PROP_POS_FRAMES, number_of_frames);
    
        //grab frame and display it
        cap >> frame;
        imshow("window", frame);
    
        //wait for displaying
        if (waitKey(30) >= 0)
        {
            break;
        }
    }
    

    另请阅读this 文章。

    【讨论】:

    • cap.set(CV_CAP_PROP_POS_FRAMES, number_of_frames);真的锤CPU,但工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-20
    • 2013-08-05
    • 2018-10-10
    • 1970-01-01
    • 2021-06-05
    相关资源
    最近更新 更多