.hpp文件_4 OpenCV读取和显示视频文件

使用OpenCV播放视频几乎与显示单张图片一样简单。唯一需要改变的是需要某种循环来依次读取每一帧。

例3. OpenCV显示视频文件

#include "opencv2/highgui/highgui.hpp"#include "opencv2/imgproc/imgproc.hpp"using namespace cv;int main(int argc, char** argv){namedWindow("例子3", 0);VideoCapture cap;cap.open("E:/ 1.mp4");Mat frame;  for (;;){cap >> frame;if (frame.empty()) break;imshow("例子3", frame);if (waitKey(33) >= 0)break;}return 0;}

首先创建一个显示窗口 ("例子3")。 然后实例化视频捕获对象VideoCapture。 该对象可以打开和关闭ffmpeg支持的许多类型的视频文件。

cap.open(); 可以传入视频文件名称。

Mat frame;这条语句定义一个Mat对象,用于显示每一帧视频。

capture对象被赋予一个包含要打开的视频的路径和文件名的字符串。 一旦打开,将包含有关正在读取的视频文件的所有信息,VideoCapture对象被初始化为视频的开头。在该程序中。

cap >> frame; 利用循环一次读取每一帧到图像矩阵变量Mat中。

if( frame.empty() ) 检查是否为空

break;

一旦进入循环,将从捕获对象流中逐帧读取视频文件。如果视频帧已成功读入,则通过imshow()显示。

if( cv::waitKey(33) >= 0 ) break;

一旦显示了帧图像,就等待33 ms。如果用户在这段时间内点击某个键,将退出读取循环。 否则,33毫秒会通过,将再次执行循环。 退出时,所有分配的数据在超出范围时自动释放。

c56cd42b63cf013189f129b8360d0496.png

例3运行结果示意图

例3中的视频播放器用户无法在视频中快速移动的。 下面我们添加一个滑动条,还可以允许用户通过按S键对视频进行单步操作,并通过按R键进入运行模式,并且只要用户通过滑动条跳转到视频中的新位置,我们会在单步模式下暂停。

HighGUI工具包提供了许多用于处理图像和视频的简单工具,超出了刚刚演示的简单功能。一个特别有用的是滑动条,它使用户能够轻松地从视频的一部分跳到另一部分视频。 要创建一个滑动条,需要调用createTrackbar()并指出希望滑动条出现在哪个窗口中。为了获得所需的功能,需要一个将执行重定位的回调。 例4是具体的实现方法。

例4。 在窗口中添加一个滑动条,以便在视频文件中移动,通过点击"S"进行单步操作,通过点击"R"连续播放

#include "opencv2/highgui/highgui.hpp"#include "opencv2/imgproc/imgproc.hpp"using namespace std;using namespace cv;int g_slider_position = 0;int g_run = 1, g_dontset = 0;VideoCapture g_cap;void onTrackbarSlide(int pos, void *){g_cap.set(CAP_PROP_POS_FRAMES, pos);if (!g_dontset)g_run = 1;g_dontset = 0;}int main(int argc, char** argv){namedWindow("例4", 0);g_cap.open("E:/1.mp4");int frames = (int)g_cap.get(CAP_PROP_FRAME_COUNT);int width = (int)g_cap.get(CAP_PROP_FRAME_WIDTH);int height = (int)g_cap.get(CAP_PROP_FRAME_HEIGHT);createTrackbar("Position", "例4", &g_slider_position, frames, onTrackbarSlide);Mat frame;for (;;){if (g_run != 0){g_cap >> frame;if (frame.empty()) break;int current_pos = (int)g_cap.get(CAP_PROP_POS_FRAMES);g_dontset = 1;setTrackbarPos("Position", "例4", current_pos);imshow("例4", frame);g_run -= 1;}char c = (char)waitKey(10);if (c == 's') // 单步{g_run = 1;}if (c == 'r') // 连续{g_run = -1;}if (c == 27)break;}return(0);}

上面是添加一个全局变量来表示滑动条的位置,然后添加一个回调来更新此变量并重新定位视频中的读取位置。看看具体的细节。

int g_slider_position = 0;

int g_run = 1;

int g_dontset = 0;

VideoCapture g_cap;

首先定义一个全局变量g_slider_position,表示滑动条的位置状态。 回调将需要访问捕获对象g_cap,所以也将其定义为全局变量。将全局变量前面加g_是一个习惯。另一个全局变量g_run显示新的帧。 正数表示停止前显示的帧数; 负数表示系统以连续视频模式运行。

为了避免混淆,当用户点击滑动条跳转到视频中的新位置时,通过设置g_run = 1将视频暂停在单步状态。但是,有一个问题,随着视频的播放,希望滑块轨迹条在显示窗口中的位置根据视频中的位置前进。这可以通过让主程序在每次获得新帧时调用trackbar回调函数来更新滑动条的位置。 但是,又不希望通过调用trackbar回调来进入单步模式。 为了避免这种情况,引入了最终的全局变量g_dontset,以允许在不触发单步模式的情况下更新滑动条的位置。

这里定义一个回调,供用户拖动滑动条时使用。 这个回调传递一个32位整数pos,得到新的trackbar位置。 在此回调中,使用g_cap.set()中的新位置将视频播放切换到新位置。 if()语句将程序设置为在下一次进入后进入单步模式,但前提是该回调是由用户单击触发的,而不是从主函数中调用。

g_cap.set()和g_cap.get()在视频操作中经常会看到的。 这允许我们配置VideoCapture对象的各种属性。 在这种情况下,传递参数: CAP_PROP_POS_FRAMES,这表示希望以帧为单位设置读取位置。

int frames = (int) g_cap.get(CAP_PROP_FRAME_COUNT);

int width = (int) g_cap.get(CAP_PROP_FRAME_WIDTH);

int height = (int) g_cap.get(cvCAP_PROP_FRAME_HEIGHT);

例4与例3的核心内容相同。区别是添加了滑动条来控制视频的播放。createTrackbar("Position", "例4", &g_slider_position, frames, onTrackbarSlide);

函数createTrackbar()还允许给滑动条一个标签并指定放置位置的窗口,提供一个绑定到滑动条的变量,滑动条的最大值(视频中的帧数)和一个回调函数(如果不需要,则返回NULL)。

在循环中,除了读取和显示视频帧外,还获取视频中的当前位置,设置g_dontset,以便下一次回调不会进入单步模式,然后调用回调更新显示给用户的滑动条的位置。 全局g_run递减,其效果是让其保持单步模式,或者让视频依赖于用户按键设置的状态运行。

在循环的底部,判断用户的键盘输入。 如果"S"被按下,进入单步模式(g_run被设置为1,这允许读取单个帧)。 如果按下"R",会进入连续模式(g_run设置为-1)。 最后,如果Esc被按下,程序将终止。如果你刚好有一些视频文件,可以按照上面的例子试运行一下,看是否达到了上面提到的效果。

58a79f1d7fefb7be746e3c33c63a3b1f.png

例4运行结果示意图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值