博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
opencv学习笔记(二)——播放AVI视频(下)
阅读量:2255 次
发布时间:2019-05-09

本文共 2715 字,大约阅读时间需要 9 分钟。

从上一篇可以看出opencv播放视频很是简单,我的环境是VS2010+opencv2.49.这篇文章中我们就一起学习了如何在OpenCV中用createTrackbar函数创建和使用轨迹条,以视频进度的调整。废话少说,先上代码和结果截图再说。

#include
#include
#include
#include
using namespace std;using namespace cv;//进度条控制void onTrackbarSlide(int pos,void* capture){ (*((VideoCapture*)capture)).set(CV_CAP_PROP_POS_FRAMES,pos);}int main(void){ //打开视频文件 VideoCapture capture("海贼王.avi"); //isOpen判断视频是否打开成功 if(!capture.isOpened()) { cout<<"Movie open Error"<

运行结果如下:

这里写图片描述

这个结果界面比原来增加一个进度条。通过进度条我们可以调节播放的的进度。和上一篇的代码相比,这次在代码里面我们就添加了几行代码。来吧,我们先来看看进度条的创建与使用。

我是焦点 || 创建轨迹条——createTrackbar

我们先来看看这个函数的原型:

C++: int createTrackbar(conststring& trackbarname, conststring& winname,   int* value, int count, TrackbarCallback onChange=0,void* userdata=0);
  • 第一个参数,const string&类型的trackbarname,表示进度条的名字,用来代表我们创建的轨迹条
  • 第二个参数,const string&类型的winname,填窗口的名字,表示这个进度条会依附到哪个窗口上,即对应namedWindow()创建窗口时填的某一个窗口名,滑动条不会遮挡图像。
  • 第三个参数,int* 类型的value,一个指向整型的指针,表示滑块的位置。并且在创建时,滑块的初始位置就是该变量当前的值,当滑动条被拖到时,OpenCV会自动将进度条当前位置所代表的值传给指针指向的整数。
  • 第四个参数,int类型的count,表示滑块可以达到的最大位置的值。注意:滑块最小的位置的值始终为0
  • 第五个参数,TrackbarCallback类型的onChange,首先注意他有默认值0。这是一个指向回调函数的指针,每次滑块位置改变时,这个函数都会进行回调。并且这个函数的原型必须为void XXXX(int,void*);其中第一个参数是轨迹条的位置,第二个参数是用户数据(看下面的第六个参数)。如果回调是NULL指针,表示没有回调函数的调用,仅第三个参数value有变化。
  • 第六个参数,void*类型的userdata,他也有默认值0。这个参数是用户传给回调函数的数据,用来处理进度条事件。在上述代码我就是使用该参数传递一个VideoCapture变量,以至于进度条能控制视频帧。

这个createTrackbar函数,为我们创建一个具有特定名称和范围的进度条,并且指定一个和进度条位置同步的变量。而且要指定回调函数onChange(第五个参数),在轨迹条位置改变的时候来调用这个回调函数。可能有些朋友看完上述解释还是有点模糊,还是搞不懂进度条怎么和视频联系到一块呢?首先是进度条通过窗口的名字(第二个参数)绑定到了指定的窗口上,再通过一个整形变量(第三个参数)记录进度条所滑动到达的位置。当进度条滑动时候,会触发回调掉函数(第五个参数),而第六个参数是正是回调函数的一个参数。

下面我们看到自己写的一个回调函数onTrackbarSlide(int pos,void* capture),他的作用就是当进度条被触发时候,设置读取视频帧的位置。里面的set函数上篇博客已经有所介绍,这里就不多说啦。

注意

但是当我们在播放时候,我们移动进度条,该进度条总是定位不准,比如说我们想滑动进度条到500帧,结果是很难滑到该帧处的,会出现跳跃的现象。因为我的是opencv2.0版本,同样的代码在opencv1.0里面可能完全没错。可是这是为什么?在网上搜了一些资料,把他贴到这里供大家参考()。

原因在于opencv2.0以后,采用ffmpeg采集视频,而在opencv1.0采用vfw采集视频。而opencv在定位时候,调用的ffmpeg的av_seek_frame()函数,此函数原型为:

int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags);

其中,最后一个参数有

AVSEEK_FLAG_BACKWARD = 1; ///< seek backward

AVSEEK_FLAG_BYTE = 2; ///< seeking based on position >in bytes
AVSEEK_FLAG_ANY = 4; ///< seek to any frame, even non >key-frames

ffmpeg默认的是选取关键帧(这个概念需要具体定义)。opencv里面这个函数的参数flag是0,

int ret = av_seek_frame(ic, video_stream, timestamp, 0);

也就是按照默认的读取关键帧。因此,视频跳跃就出现了。

解决这个问题需要将0改为 AVSEEK_FLAG_ANY ,即:

int ret = av_seek_frame(ic, video_stream, timestamp, AVSEEK_FLAG_ANY );

之后重新编译opencv库,就可以了。

视频播放的例程就讲解到这里,在关于进度条的只是还有几个函数也是经常用到的如获取当前进度条的位置——getTrackbarPos函数,以及设置当前进度条的位置函数setTrackbarPos()等等,这些函数都定义在opencv2/highgui/highgui.hpp路径的highgui.hpp里面,有需要的可以去里面查看。这些函数也是很容易理解的。

你可能感兴趣的文章
数据结构——单链表(C语言实现)
查看>>
Unix C (十一)
查看>>
射频识别技术——数据编码
查看>>
如何将多个bin文件合成一个bin文件?(一)
查看>>
如何将多个bin文件合成一个bin文件?(二)
查看>>
ISO14443 Type A类型卡的防碰撞过程以及命令解析
查看>>
ISO14443 Type B类型卡的防碰撞过程以及命令解析
查看>>
双向链表实现的消息队列
查看>>
数据结构——双向链表(C语言实现)
查看>>
ISO15693类型的命令解析以及防碰撞过程
查看>>
void在C语言中特殊使用
查看>>
防止头文件被重复包含的两种方式#pragma once 与 #ifdef 的区别
查看>>
推挽输出、开漏输出、复用开漏输出、复用推挽输出以及上拉输入、下拉输入、浮空输入、模拟输入区别
查看>>
Log打印技巧(C语言实现)
查看>>
普通GPIO模拟SPI通信协议(软件SPI)
查看>>
USART配置成SPI实例代码
查看>>
延时函数sleep和delay的区别
查看>>
C语言字符串的处理
查看>>
什么是达夫设备(Duff's Device)
查看>>
J-Link v8固件丢失修复
查看>>