【例1】创建一个滚动条
【代码】
#include "stdafx.h" #include "cv.h" #include "highgui.h" int g_slider_pos=0; void on_changed(int pos) { printf("The g_slider_pos is %d\n",g_slider_pos); } int main(int argc, char* argv[]) { cvNamedWindow("win"); cvCreateTrackbar( "Position", "win", &g_slider_pos, 400, on_changed ); cvShowImage("win",NULL); cvWaitKey(0); cvDestroyWindow("win"); return 0; }【运行结果】
【代码分析】
1、创建滚动条
(1)定义:CV_EXTERN_C_FUNCPTR( void (*CvTrackbarCallback)(int pos) );
该函数为开放计算机视觉(OpenCV)库库函数,创建trackbar并将它添加到指定的窗口。
int cvCreateTrackbar( const char* trackbar_name, const char* window_name, int* value, int count, CvTrackbarCallback on_change );
(2)参数:
trackbar_name 被创建的trackbar名字。
window_name 窗口名字,这个窗口将为被创建trackbar的父对象。
value 整数指针,它的值将反映滑块的位置。这个变量指定创建时的滑块位置。
count 滑块位置的最大值。最小值一直是0。
on_change 每次滑块位置被改变的时候,被调用函数的指针。这个函数应该被声明为void Foo(int); 如果没有回调函数,这个值可以设为NULL。
(3)作用:
函数cvCreateTrackbar用指定的名字和范围来创建trackbar(滑块或者范围控制),指定与trackbar位置同步的变量,并且指定当trackbar位置被改变的时候调用的回调函数。
被创建的trackbar默认显示在指定窗口的顶端,可以通过函数cvGetTrackbarPos来获取trackbar显示的位置信息,以及通过函数cvSetTrackbarPos来重新设置trackbar的显示位置。
2、回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
=============================================================================
2、 视频播放控制(视频的拖动:快进,倒退等)
【代码1】在例1的基础上进行改变,程序实现了在视频播放窗口添加滚动条,并且拖动滚动条来拖动视频的播放。(存在问题:拖动后视频继续播放,但滚动条不再移动)
#include "stdafx.h" #include "cv.h" #include "highgui.h" CvCapture* g_capture=NULL;//声明一个CvCapture类型指针,用于接收cvCreateFileCapture的返回值 int g_slider_pos=0;//记录滚动条的当前位置 //滚动条的回调函数 参数int pos 是指当前滚动条所在位置 void on_changed(int pos) { //设置g_capture的属性,使得从位置pos开始播放视频 cvSetCaptureProperty(g_capture,CV_CAP_PROP_POS_FRAMES,pos); } int main(int argc, char* argv[]) { cvNamedWindow("win"); g_capture=cvCreateFileCapture("f:\\1.avi"); //打开有一个视频文件 //获取视频的总帧数 int framecount=(int)cvGetCaptureProperty(g_capture,CV_CAP_PROP_FRAME_COUNT); //在窗口show上创建名字为Position的滚动条 if(framecount>0) { cvCreateTrackbar( "Position", "win", &g_slider_pos, framecount, on_changed ); } while(1) { IplImage* frame=cvQueryFrame(g_capture); if(!frame) break; cvShowImage("win",frame); char c=cvWaitKey(33); if(c==27) break; } cvReleaseCapture(&g_capture); cvDestroyWindow("win"); return 0; }【运行结果】
【代码1的分析】
1、cvSetCaptureProperty :设置视频获取属性
int cvSetCaptureProperty( CvCapture* capture, int property_id, double value );
注意此方法定位并不准确。
capture 视频获取结构。
property_id 属性标识符。可以是下面之一:
CV_CAP_PROP_POS_MSEC - 从文件开始的位置,单位为毫秒
CV_CAP_PROP_POS_FRAMES - 单位为帧数的位置(只对视频文件有效)
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的四个字符(只对摄像头有效)
value 属性的值。
函数cvSetCaptureProperty设置指定视频获取的属性。目前这个函数对视频文件只支持: CV_CAP_PROP_POS_MSEC,CV_CAP_PROP_POS_FRAMES, CV_CAP_PROP_POS_AVI_RATIO
2、cvGetCaptureProperty
double cvGetCaptureProperty( CvCapture* capture, int property_id ) //返回值为double类型
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 - 视频文件中帧的总数
【注】:有时候这个函数在cvQueryFrame被调用一次后,再调用cvGetCaptureProperty才会返回正确的数值。这是一个bug,建议在调用此函数前先调用cvQueryFrame。
============================================================================================
【代码2】在代码1的基础上再进行改动,实现拖动和视频播放同步。
#include "stdafx.h" #include "cv.h" #include "highgui.h" CvCapture* g_capture=NULL;//声明一个CvCapture类型指针,用于接收cvCreateFileCapture的返回值 int g_slider_pos=0;//记录滚动条的当前位置 int frame_count=0;//对视频帧进行计数的变量 //滚动条的回调函数 参数int pos 是指当前滚动条所在位置 void on_changed(int pos) { //设置g_capture的属性,使得从位置pos开始播放视频 cvSetCaptureProperty(g_capture,CV_CAP_PROP_POS_FRAMES,pos); //在拉动滚动条后 保持变量frame_count与滚动条的位置是同步的 frame_count = pos ; } int main(int argc, char* argv[]) { cvNamedWindow("win"); g_capture=cvCreateFileCapture("f:\\1.avi"); //打开有一个视频文件 //获取视频的总帧数 int framecount=(int)cvGetCaptureProperty(g_capture,CV_CAP_PROP_FRAME_COUNT); //在窗口show上创建名字为Position的滚动条 if(framecount>0) { cvCreateTrackbar( "Position", "win", &g_slider_pos, framecount, on_changed ); } while(1) { IplImage* frame=cvQueryFrame(g_capture); if(!frame) break; cvShowImage("win",frame); char c=cvWaitKey(33); if(c==27) break; //滚动条 随着视频的播放 进行移动 cvSetTrackbarPos("Position","win", frame_count); frame_count++; } cvReleaseCapture(&g_capture); cvDestroyWindow("win"); return 0; }【运行结果】
【代码2的分析】
1、第7行代码:int frame_count=0;//对视频帧进行计数的变量
2、第15行代码: frame_count = pos ;//在拉动滚动条后 保持变量frame_count与滚动条的位置是同步的
3、第46、47行代码://滚动条 随着视频的播放 进行移动
cvSetTrackbarPos("Position","win", frame_count);
frame_count++;