#include "stdafx.h"
#include "highgui.h"
#include "cv.h"
CvCapture* g_capture = NULL;
//记录滚动条的当前位置
int g_slider_pos = 0;
//对视频帧进行计数的变量
int frame_count = 0;
void onTrackbarSlider(int pos)//回调函数
{
//设置g_capture的属性,从位置pos开始播放视频
cvSetCaptureProperty(
g_capture,
CV_CAP_PROP_POS_FRAMES,//单位为帧数的位置
pos//当前滚动条的位置
);
frame_count =pos;
//printf("frame_count is %dpos is %d\n-------\n",frame_count,pos);
}
int main(int argc, char* argv[])
{
IplImage* frame;
cvNamedWindow("show");
CvCapture* tmp = cvCreateFileCapture("E:\\狸窝转换结果\\oldfriends.avi");
printf("使用代码1.2,屏蔽代码1.1和代码2.1\n");
/*-----------------1、获取总帧数---------*/
frame = cvQueryFrame(tmp);
//获取视频的总帧数
int frames = 0;
/*-----------------代码1.1---------*/
/*frames =(int)cvGetCaptureProperty(
tmp,
CV_CAP_PROP_FRAME_COUNT
);
*/
/*-----------------代码1.1end---------*/
/*-----------------代码1.2---------*/
while(frame != NULL ){
frame = cvQueryFrame(tmp);
frames++;
}
cvReleaseCapture(&tmp);
/*-----------------代码1.2end---------*/
printf("总帧数 is %3d\n",frames);
/*-----------------获取总帧数-----------*/
g_capture = cvCreateFileCapture("E:\\狸窝转换结果\\oldfriends.avi");
if(frames>0)
{
cvCreateTrackbar(
"Position",//创建的名字
"show",//窗口名字
&g_slider_pos,//整数指针,它的值将反应滑块位置
frames,//滑块位置的最大值
onTrackbarSlider//每次滑块位置被改变的时候,被调用的指针
);
}
int count = 0;
while(1)
{
frame = cvQueryFrame(g_capture);//返回视频文件的下一帧
if(!frame){
printf("NULL\n");
break;
}
cvShowImage("show",frame);
char c = cvWaitKey(33);
if(c==27)//Esc按键
{
cvWaitKey(0);//break;
}
/*-----------------2、设置滚动条位置---------*/
/*-----------------代码2.1---------*/
//cvSetTrackbarPos("Position","show",frame_count);//通过单步调试,发现执行这一步时会调用到onTrackbarSlider()函数
/*-----------------代码2.1end---------*/
/*-----------------设置滚动条位置-----------*/
frame_count++;
count++;
}
printf("累加值:frame_count is %3d,count is %3d\n",frame_count,count);
cvReleaseCapture(&g_capture);
cvDestroyWindow("show");
return 0;
}
上述代码中有几个函数值得深入研究
1、double cvGetCaptureProperty(CvCapture* capture, int property_id)//获取摄像头属性的函数
capture:源文件指针
property_id: 控制返回的属性,其中
CV_CAP_PROP_POS_MSEC - 影片目前位置,为毫秒数或者视频获取时间戳
CV_CAP_PROP_POS_FRAMES - 将被下一步解压/获取的帧索引,以0为起点
CV_CAP_PROP_POS_AVI_RATIO - 视频文件的相对位置(0 - 影片的开始,1 - 影片的结尾)
CV_CAP_PROP_FRAME_WIDTH - 视频流中的帧宽度
CV_CAP_PROP_FRAME_HEIGHT - 视频流中的帧高度
CV_CAP_PROP_FPS - 帧率
CV_CAP_PROP_FOURCC - 表示codec的四个字符
CV_CAP_PROP_FRAME_COUNT视频文件中帧的总数(本课时需要使用的属性)
注:1.有时调用函数cvGetCaptureProperty需要调用cvQueruFrame一次后才返回正确的值。这是软件存在的一个bug.
2.cvGetCaptureProperty函数实际是通过读取视频文件头信息返回数据,不是真正读取视频文件。因此不同格式视频文件转换成opencv所支持的avi格式后,使用该函数去读取时,会造成信息的不准确。(主要参考http://blog.sina.com.cn/s/blog_4b0020f301012dbz.html)
2、cvCreateTrackbar()创建滚动条
定义:
CV_EXTERN_C_FUNCPTR(void(*CvTrackbarCallback)(int pos));//回调函数的格式,返回值是void,参数是int。不能随意定义
int cvCreateTrackbar(const char* trackbar_name,//创建的名字
const char* window_name,//窗口名字
int* value,//整数指针,它的值将反应滑块位置
int count,//滑块位置的最大值
CvTrackbarCallback on_change//每次滑块位置被改变的时候,被调用的指针,回调函数
);
回调函数就是一个通过函数指针调用的函数。
如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。
3、int cvSetCaptureProperty( CvCapture* capture, int property_id, double value );//设置视频获取属性
4、cvSetTrackbarPos设置滚动条的值
根据cvGetCaptureProperty函数中提到的获取值不正确问题,我做了一个实验。
使用狸窝工具,将一个rmvb视频转成avi然后进行测试。测试数据如下:
对于这样的结果,我表示深深的疑惑。
首先图1图3和图2图4的对比可以看出,之前说到的cvGetCaptureProperty函数获取的值不正确这个问题是存在的。
其次,看到图3,为什么获取的总帧数是734,后来运行的时候帧数却可以达到879?对比了图1图2和图3图4之后,可以发现这个问题和cvSetTrackbarPos()、cvSetCaptureProperty()这两个函数有关。
是不是在使用函数的时候修改了什么东西,具体的还需要找到这两个函数的源代码看看才知道。