《学习OpenCV》这本书上的例子中有实现了播放一段视屏,但是一般看视屏时都要添加滚动条,没有滚动条不方便,现在我们就来实现这个事情,在播放的时候添加滚动条,让我们随心所欲的拉到想看的地方。
//包含了图像和视频的输入/输出
#include"highgui.h"
//用来标定滚动条当前的位置,为全局变量。为了区分局部变量,加g以表示区别。
int g_slider_position =0;
//将打开的视频文件作为一个全局变量使用
CvCapture *g_Capture=NULL;
//(回调函数:很有意义)当拖动滚动条后,会回调这个函数,同时会将当前滚动条的位置以32 位形式传递过来,为什么会调用回调函数,在创建 cvCreateTrackbar函数中在说明。我们在可以看看回调函数中的内容,回调函数中的内容cvSetCaptureproperty();就是对滚动条的位置进行设置了。
voidCallBackTrackBarSlide(int pos)
{
//这里便是重新设置视频文件当前播放的帧
cvSetCaptureProperty(g_Capture,CV_CAP_PROP_POS_FRAMES,pos);
}
//使用了命令行下运行的形式,其中要在命令行下传递参数,在DOS下执行命令。
int main(intargc,char *argv[])
{
cvNamedWindow("example2",CV_WINDOW_AUTOSIZE);
//根据参数打开指定的视频文件
g_Capture=cvCreateFileCapture(“D:\\test04.avi”);
//获得总的帧数
Int Frames= (int)cvGetCaptureProperty(g_Capture,CV_CAP_PROP_FRAME_COUNT);
if(Frames!=0)
{
//创建滚动条,在这里指定了滚动条拖动后的回调函数
//滚动条被拖动后会有两个动作,其都是将现在滚动条的位置信息传递出去,第一个传递的地方时将滚动条的位置信息传递给指针所指向的整数(&g_slider_position位置传递进去的其实为一个指针,所以第一个动作其实就是将当前帧的位置传递给整数g_slider_position),第二个动作就是调用回调函数,在cvCreateTrackBar的回调函数位置其实传入的也是指针,我们知道,在C语言中,函数名和数组名一样,都是引用传递,即代表的是地址,所以直接写函数名便可以了)。
cvCreateTrackbar("TrackBar","example2",&g_slider_position,Frames,CallBackTrackBarSlide);
}
IplImage * frame;
//循环的顺序的遍历所有的帧
while(1)
{
//获取当前帧的下一个帧,并将其加载到内存中
frame=cvQueryFrame(g_Capture);
if(frame==0){
break;
}
cvShowImage("example2",frame);
char ckeycode=cvWaitKey(33);
//ASCII码中27为ESC。
if(cKeyCode==27){
break;
}
}
cvReleaseCapture(&g_Capture);
cvDestroyWindow("example2");
return( 0);
}
从本质上说,这种方法是通过添加一个全局变量来表示滚动条位置并且添加一个回调函数更新变量以及重新设置视频读入位置。我们通过一个调用来创建滚动条和确定回调函数。下面让我们看看细节。
int g_slider_position = 0;
CvCapture* g_capture = NULL;
首先为滚动条位置定义一个全局变量。由于回调函数需要使用CvCapture对象,因此我们将它定义为全局变量。为了使我们的程序可读性更强,我们在所有全局变量名称前面加上g_。
void onTrackbarSlide(int pos) {
cvSetCaptureProperty(g_capture, CV_CAP_PROP_POS_FRAMES,pos);
现在我们定义一个回调函数,使其在滚动条被拖动时调用。滚动条的位置会被作为一个32位整数以参数形式传入。
后面我们会常常看到函数cvSetCaptureProperty()被调用,同时与之配套的函数cvGetCaptureProperty()也经常会被调用。这些函数允许我们设置(或查询)CvCapture对象的各种属性。在本程序中我们设置参数CV_CAP_PROP_POS_FRAMES(这个参数表示我们以帧数来设置读入位置,如果我们想通过视频长度比例来设置读入位置,我们可以通过用AVI_RATIO代替FRAMES来实现)。最后,我们把新的滚动条位置作为参数传入。因为HighGUI是高度智能化的,它会自动处理一些问题,比如滚动条对应位置不是关键帧,它会从前面一个关键帧开始运行并且快进到对应帧,而不需要我们来处理这些细节问题。
int frames=(int)cvGetCaptureProperty(g_capture,CV_CAP_PROP_FRAME_COUNT);
正如前面所说,当需要从CvCapture结构查询数据时,可使用cvGetCaptureProperty函数。在本程序中,我们希望获得视频文件的总帧数以对滚动条进行设置(具体实现在后面)。
if( frames!= 0 ){
cvCreateTrackbar("Position", "Example3", &g_slider_position,frames,onTrackbarSlide);
}
前面的代码用来创建滚动条,借助函数cvCreateTrackbar()(最好自己查找具体的函数参数看一下},我们可设置滚动条的名称并确定滚动条的所属窗口。我们将一个变量绑定到这个滚动条来表示滚动条的最大值和一个回调函数(不需要回调函数时置为空,当滚动条被拖动时触发)。仔细分析,你会发现一点:cvGetCaptureProperty()返回的帧数为0时,滚动条不会被创建。这是因为对于有些编码方式,总的帧数获取不到,在这种情况下,我们只能直接播放视频文件而看不到滚动条。
最后,运行程序我们发现虽然实现了“拖动”的功能,但是并没有将实现滚动条随着视频播放移动功能包含进来,下一步我们就解决这个问题。
Ok .让我们接着完善我们的工作,我们已经实现了带滚动条的播放视屏,我们可以随心所欲的拉到我们想看的地方,可惜的是,在播放视屏的时候滚动条却不随着播放时间的移动而移动,这样总让人看起来不舒服,看视屏时也不知道看到了多少,因此我们要继续完善,让滚动条不仅仅可以拉动,而且可以随着播放时间而动。要实现这个功能,肯定是必须利用前面已经完成的带滚动条的播放程序,让我们分析程序中的代码,其中我们定义的 s_slider_position全局变量是用来给滚动条定位了,在执行程序时通过cvCreateTrackbar子函数把滚动条的position信息给了s_slider_position,如果我们有拖动滚动条的话,就会调用回调函数callbackTrackbarslider;在回调函数中又是一个调用子函数cvSetCaptureProperty用来设置滚动条的信息,这样就显示在屏幕上滚动条的位置改变了,这样我们受启发,如果平时没有拖动滚动条时,只要我们在循环播放时加上这句不就可以了吧,OK,我们看见程序开始时 g_slider-position=0,然后建立了滚动条,然后进入循环体一帧一帧的显示,每次显示一帧后,我们让s_slider_position++,然后再用cvSetTrackbarPos("Trackbar","example2", g_slider_position);
便可以解决,此外如果拖动滚动条后s_slider_position的值有所改变,我们只需要在回调函数中增加一句s_slider_position=pos;便可以了,如果想看的更清楚整个程序执行的过程,那就毫不犹豫的按下F10(单步执行),然后跟着变量的值和地址,慢慢看吧!
#include "highgui.h"
#include "cv.h"
int g_slider_position=0;
CvCapture*g_capture=NULL;
void callbackTrackbarSlide(intpos){
g_slider_position=pos;
cvSetCaptureProperty(g_capture,CV_CAP_PROP_POS_FRAMES,pos);
}
int main(int argc,char *argv[]){
cvNamedWindow("example2",0);
g_capture=cvCreateFileCapture("d:\\test4.avi");
int frames=(int)cvGetCaptureProperty(g_capture,CV_CAP_PROP_FRAME_COUNT);
if(frames!=0){
cvCreateTrackbar(
"Trackbar",
"example2",
&g_slider_position,
frames,
callbackTrackbarSlide
);
}
IplImage *frame;
while(1){
frame=cvQueryFrame(g_capture);
if(frame==0){break;}
cvShowImage("example2",frame);
charckeycode=cvWaitKey(33);
if(ckeycode==27){break;}
g_slider_position++;
cvSetTrackbarPos("Trackbar","example2", g_slider_position);
}
cvReleaseCapture(&g_capture);
cvDestroyWindow("example2");
return(0);
}