今天我们来做个有趣的程序实现:利用OpenCV读取本地文件夹的视频文件,并且在窗口中创建拖动控制条来显示并且控制视频文件的读取进度。
此程序调试花费了笔者近一天时间,其实大体程序都已经很快写出,结果执行时却出现拖动条不能控制视频读取进度现象,结果发现是”一个大小写字母引发的血案“——在创建拖动条时命名为:Position,但是在设置拖动条的视频位置时却疏忽写为:position。为此笔者反复了N遍,由此可见程序的严格性,以及“搬砖码垛”时专注的重要性。
同样在附上程序之前我们有必要对程序中出现的关键函数给出深度解析,这个也会成为笔者对于学习笔记的博客书写风格:开篇小叙——程序实现功能——关键函数精析——附上完整测试程序;如果有更好的书写方案希望与大家不吝赐教,唯一的目的就是为了让技术道路上的我们能更快的从彼此哪里获取实用信息,这个也是衡量一个大牛是否技术精通的重要指标:所谓的助攻能力!!!共勉之
实现功能:
输入avi2.exe play2.avi命令符后,执行:Example2窗口播放play2.avi视频文件,并且在Position拖动条上显示进度,手动拖动能调节对应视频播放进度。
函数精析:
cvCreateFileCapture(const char* filename)/cvCaptureFromAVI(const char* filename)
- 从指定文件filename中获取视频流,分配和初始化CvCaputure*结构指针
- 两个函数等价,实现从文件夹中读取视频流;同时支持多种视频格式AVI、MP4、wmv等
- 只分配一帧的图像空间,每次调用时覆盖前面一次的数据(每次调用返回的指针是一样的)
- 倘若我们想分配自己的图像存储空间用:cvCreateImage(cvGetSize(image),IPL_DEPTH_8U,3)-《笔记一》
cvCaptureFromCAM(int index)
- 从摄像头中获取视频,多个摄像头的编号index;本地index=0;外部index=1
cvSetCaptureProperty(CvCapture* capture, int propId, double value)
- 设置视频的属性 (视频对象,属性标识符,属性)
- CV_CAP_PROP_POS_MSEC:视频当前位置,毫秒或者视频获取时间戳
- CV_CAP_PROP_POS_MSEC:将被下一步解压获取的帧索引,以0为起点
- CV_CAP_PROP_POS_AVI_RATIO:视频文件相对位置(0开头1结尾)
- propId可取值如下:
cvGetCaptureProperty(CvCapture* capture, int propId)
- 获取视频属性;propId同样适用上图
cvCreateTrackbar(barName, win1, int* value, int count, CvTrackbarCallback onChange)
- 创建拖动条(拖动条标识符,窗口标识符,拖动条位置数字指针,最大位置,调用函数更新拖动后的位置)
- 在win1窗口创建拖动条barName,count为其最大值,value为其当前值,onChange跟新拖动后的位置
cvSetTrackbarPos(barName,win1, int pos)
- 设置win1窗口下barName拖动条的最新位置pos
cvQueryFrame(g_capture)
- 从读取的视频流g_capture中读取一帧,并且解压返回这一帧,返回的图像可以被释放和修改
cvRetrieveFrame(g_capture)
- 返回抓取图像的指针,但是返回的图像不能被释放和修改
- 利用cvCloneImage()后可以对抓取的图像进行任何操作
cvGrabFrame(g_capture)
- 捕捉视频或者相机的下一帧图像,尤其是应用在多相机的情况下
附源代码:
#include "stdafx.h"
#include "highgui.h"
#include "cv.h"
#include <iostream>
using namespace std; /* 声明三个全局变量并初始化 */
int g_slider_position //定义拖动条当前位置变量
int frame_count =; //定义一个全局变量,控制滚动条的位置
CvCapture *g_capture = NULL; /* 定义拖动条函数:设置视频获取信息(对指定视频g_capture
设置属性标识符CV_CAP_PROP_POS_FRAMES的值pos) */ void onTrackbarSlide(int pos)
{
cvSetCaptureProperty(g_capture,CV_CAP_PROP_POS_FRAMES,pos);
frame_count = pos; //将设置的视频信息中的属性值保存到frame_count中
return;
} int main(int argc,char** argv)
{
if(argc == )
{ cvNamedWindow("Example2",);
g_capture = cvCaptureFromAVI(argv[]);
// cvCreateFileCapture(argv[1]); 读入AVI文件等价
int frames = (int) cvGetCaptureProperty(g_capture,CV_CAP_PROP_FRAME_COUNT);
//获取视频文件属性的总帧数
if(frames != )
{
/* "position"表示滚动条的名词,"Example3"表示滚动条所属窗口,
g_slider_position表示滚动条当前位置。 frames表示滚动条的最大值,
onTrackbarSlide表示滚动条的回调函数(被拖动时调用) */ cvCreateTrackbar("Position","Example2",&g_slider_position,frames,onTrackbarSlide);
} IplImage* frame = NULL ;
while() //实时捕捉视频帧显示,并且更新进度条
{
frame = cvQueryFrame(g_capture);//获得一帧图像
if(!frame) break;
cvShowImage("Example2",frame); cvSetTrackbarPos( "Position", "Example2", frame_count++ );
/* 进度条根据视频进度跟新位置
拖动条设置的时候跟之前的创建名称不同导致拖动条不能根据
视频进度更新调试了一天终于发现这里“position”应该为“Position”
cout << g_slider_position << endl ;//可以看到为止更新数据 */ char c = cvWaitKey(); //按下esc后退出
if( c == )break; }
}
cvReleaseCapture(&g_capture);
cvDestroyWindow("Example2");
return ;
}