【发布时间】:2012-06-29 10:20:37
【问题描述】:
是否可以在 OpenCV 中向后播放视频? 通过 API 调用或缓冲视频帧并将顺序反转为 一个新的视频文件。
谢谢
【问题讨论】:
是否可以在 OpenCV 中向后播放视频? 通过 API 调用或缓冲视频帧并将顺序反转为 一个新的视频文件。
谢谢
【问题讨论】:
唯一可行的方法是手动提取帧,缓冲它们(在内存或文件上),然后以相反的顺序重新加载它们。
问题在于视频压缩器都在利用时间冗余——事实上,两个连续的帧大部分时间都非常相似。因此,它们不时编码一个完整的帧(通常每几百帧),然后只发送前一个和当前之间的差异。
现在,要使解码工作,必须按相同的顺序完成 - 解码一个关键帧(一个完整的),然后为每个新帧添加差异以获得当前图像。
这种策略使得在视频中反向播放变得非常困难。有几种技术,但都涉及缓冲。
现在,您可能已经看到了 Astor 描述的 CV_CAP_PROP_POS_FRAMES 参数。看起来没问题,但由于上述问题,OpenCV 无法正确跳转到特定帧(在这些问题上存在多个错误)。他们(OpenCV 开发人员)正在研究一些解决方案,但即使这些解决方案也会非常慢(它们涉及返回到前一个关键帧,然后解码回选定的关键帧)。如果使用这种技术,每帧必须平均解码数百次,因此速度非常慢。然而,它不起作用。
编辑 如果您追求缓冲方式来反转它,请记住,解码后的视频将很快耗尽普通计算机的内存资源。一个普通的 720p 视频一分钟在解压缩时需要 4.7GB 内存!将帧作为单个文件存储在磁盘上是解决此问题的实用方法。
【讨论】:
另一种解决方案,类似于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;
}
}
【讨论】:
是的,这是可能的。使用 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 文章。
【讨论】: