OpenCV学习笔记02: 剖析cv::createTrackbar()及回调函数的用法

#include  //highgui.hpp中已经包含了core.hpp, imgcodecs.hpp, videoio.hpp头文件
#include  //imgproc.hpp已经包含了core.hpp头文件
#include 
#include 
#include 
#include 
#include 

using namespace std;

int g_slider_position = 0; //滑动条的滑块初始位置
int g_run = 1, g_dontset = 0; //通过g_run和g_dontset两个参数设置单步模式
cv::VideoCapture g_cap;

std::string readFile(){
    QString fileName = QDir::currentPath() + "/../srcVideo.avi";
    return fileName.toStdString();
}

void onTrackbarSlide( int pos, void *) { 
    //此回调函数由cv::createTrackbar()函数调用,pos参数由g_slider_position给定
    g_cap.set( cv::CAP_PROP_POS_FRAMES, pos ); //设置下一帧待解码/捕获的基于0的索引值为pos
    if( !g_dontset ){
        g_run = 1;
    } 
    g_dontset = 0;
}

int main( int argc, char** argv ) {
    cv::namedWindow( "WinName", cv::WINDOW_AUTOSIZE );
    g_cap.open(readFile());

    int frames = (int) g_cap.get( CV_CAP_PROP_FRAME_COUNT  );
    int tmpw   = (int) g_cap.get( CV_CAP_PROP_FRAME_WIDTH  );
    int tmph   = (int) g_cap.get( CV_CAP_PROP_FRAME_HEIGHT );

    cout<< "当前视频有: " << frames << "帧, 视频的图像尺寸为: " << tmpw << "x" << tmph << endl;
    cv::createTrackbar( //该函数不仅会创建一个滑动条对象, 
    //当滑动条事件产生时, 会自动调用本函数的回调函数来设置下一帧的索引值为g_slider_position
        "Position",
        "WinName",
        &g_slider_position, //当滑动条被拖时,OpenCV的事件处理函数会自动将滑动条的当前值传递给g_slider_position
        //然后会调用回调函数, 回调函数会将g_slider_position的值设置为下一帧的索引
        frames, //滑块最大值为视频的总帧数
        onTrackbarSlide //回调函数
        //本质上就是一个函数指针: typedef void(* cv::TrackbarCallback) (int pos, void *userdata)
    );
    cv::Mat frame;

    for(;;){

        if( g_run != 0 ){ 
            //当g_run == 0时, 停止播放视频, 即视频一开始是停止播放的, 当g_run == 1时, 
            //单帧播放, 当g_run <= -1时, 连续播放.
            g_cap >> frame;
            if(frame.empty()){
                break;
            }
            int current_pos = (int)g_cap.get( CV_CAP_PROP_POS_FRAMES ); //读取下一帧的索引值
            //读取属性值的流程: VideoCapture -> 后端API -> 操作系统 -> 设备驱动 -> 设备硬件
            g_dontset = 1;
            cv::setTrackbarPos("Position", "WinName", current_pos);//设置滑动条的滑块位置
            cv::imshow( "WinName", frame );
            g_run-=1; //将g_run设置为0, 接下来会停止播放
        }
        char c = (char) cv::waitKey(30); //程序每隔30ms就会循环执行该语句一次
        if( c == 's' ){ // 单步播放
            g_run = 1;
            cout << "Single step, run = " << g_run << endl;
        }
        if( c == 'r' ){ // 正常播放
            g_run = -1;
            cout << "Run mode, run = " << g_run <if( c == 27 ){
            break; //退出程序
        }
    }
    return(0);
}

当用户通过鼠标滑动滑块时, 会触鼠标左键单击, 鼠标左键移动和鼠标左键释放等事件, 操作系统的硬件接口会捕获这些事件并将其分发给应用程序, 接着OpenCV的事件处理函数会将发生的鼠标事件所处位置所对应的滑动条的值赋给g_slider_position, 并调用回调函数来设置为视频下一帧的索引为g_slider_position, 然后通过cv::VideoCapture::get函数获取视频下一帧的索引值, 并通过cv::setTrackbarPos()函数设置滑块的位置, 方便用户观察当前视频帧的索引值.

你可能感兴趣的:(OpenCV)