C++利用opencv实现目标跟踪,代码全注释

直接贴上代码,代码全部注释完成,需要学习的可以使用。代码有问题请留言。

#include //opencv头文件

bool selectObject = false; //用于是否有选取目标
int trackObject = 0; // 1表示有追踪对象 0 表示无追踪对象 
                     //-1表示追踪对象尚未计算camshift所需的属性                  
cv::Rect selection;//保存鼠标选择的区域
cv::Mat image;//用于缓存读取到的视频帧
/*
opencv 对所注册的鼠标回调函数定义为:
void onMouse(int event,int x,int y,int flag,void * param)
其中第四个flag为event下的附加状态,param是用户传入的参数
*/
void onMouse( int event, int x, int y, int, void* ) {
    static cv::Point origin;
    /*static关键字的作用:
      1、隐藏功能 利用这一特性可以在不同的文件中定义同名函数和同名变量
      2、保持变量内容的持久
    */
    if(selectObject) {//如果检测到选取目标进行下面的操作
        //确定鼠标选定区域的左上角坐标以及区域的长和宽
        selection.x = MIN(x, origin.x);
        selection.y = MIN(y, origin.y);
        selection.width = std::abs(x - origin.x);
        selection.height = std::abs(y - origin.y);
        //&运算符被cv::Rect进行重载
        //表示两个区域的交集,主要目的是为了处理当鼠标在选择区域时移除画面外
        selection &= cv::Rect(0, 0, image.cols, image.rows);
    }
    switch(event) {
        //处理鼠标左键被按下
        case CV_EVENT_LBUTTONDOWN:
            origin = cv::Point(x, y);
            selection = cv::Rect(x, y, 0, 0);
            selectObject = true;
            break;
            //处理鼠标左键被抬起
        case CV_EVENT_LBUTTONUP:
            selectObject = false;
            if( selection.width > 0 && selection.height > 0 )
                trackObject = -1;//追踪的目标还未计算camshift所需要的属性
            break;
    }
}

int main( int argc, const char** argv )
{
    cv::VideoCapture video("video.ogv");//读取文件
    //如果需要使用摄像头则代码为
    //cv::VideoCapture video(0);

    cv::namedWindow( "test" );
    //注册鼠标事件的回调函数,第三个参数是用户提供给回掉函数的
    //也就是回调函数中最后的param参数
    cv::setMouseCallback( "test", onMouse, 0 );

/*
捕获画面的容器,opencv中的mat对象
opencv中最关键的mat类,mat是matrix的缩写
opencv中延续了像素图的概念,用矩阵来描述由像素构成的图像
*/
    cv::Mat frame, hsv, hue, mask, hist, backproj;
    cv::Rect trackWindow; //追踪到的窗口
    int hsize = 16;//计算直方图所必备的内容
    float hranges[] = {0,180};//计算直方图所必备的内容
    const float* phranges = hranges;//计算直方图所必备的内容

    while(true) {
        //将video中的内容写入到frame中,
        //这里的>>运算符是经过opencv重载的
        video >> frame;
        if( frame.empty() )//没有帧可以读取的时候,退出循环
            break;
        //将frame中的图像写入全局变量image作为进行camshift的缓存
        frame.copyTo(image);
        //转换到的HSV空间
        cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);
        //当有目标时候进行处理
        if( trackObject ) {
            // 只处理像素值为H:0~180,S:30~256,V:10~256之间的部分,过滤掉其他的部分并复制给 mask
            cv::inRange(hsv, cv::Scalar(0, 30, 10), cv::Scalar(180, 256, 256), mask);
            //下面三句将hsv图像中的H通道分离出来
            int ch[] = {0, 0};
            hue.create(hsv.size(), hsv.depth());
            cv::mixChannels(&hsv, 1, &hue, 1, ch, 1);
            //如果需要追踪的物体还没有进行属性提取,则对选择的目标中的图像属性提取
            if( trackObject < 0 ) {
                //设置H通道和mask图像的ROI
                cv::Mat roi(hue, selection), maskroi(mask, selection);
                //计算ROI所在区域的直方图
                calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
                //将直方图归一
                normalize(hist, hist, 0, 255, CV_MINMAX);
                //设置追踪的窗口
                trackWindow = selection;
                //标记追踪的目标已经计算过直方图属性
                trackObject = 1;
            }
            //将直方图进行反向投影
            calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
            //取公共部分
            backproj &= mask;
            //调用camshift算法的接口
            cv::RotatedRect trackBox = CamShift(backproj, trackWindow, cv::TermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ));
            //处理追踪面积过小的情况
            if( trackWindow.area() <= 1 ) {
                int cols = backproj.cols, rows = backproj.rows, r = (MIN(cols, rows) + 5)/6;
                trackWindow = cv::Rect(trackWindow.x - r, trackWindow.y - r,
                                   trackWindow.x + r, trackWindow.y + r) &
                cv::Rect(0, 0, cols, rows);
            }
            //绘制追踪区域
            ellipse( image, trackBox, cv::Scalar(0,0,255), 3, CV_AA );

        }
        //如果正在选择追踪目标,则画出选择框
        if( selectObject && selection.width > 0 && selection.height > 0 ) {
            cv::Mat roi(image, selection);
            bitwise_not(roi, roi);//对选择的区域图像反色
        }

        imshow( "test", image );//显示当前帧
         // 录制视频帧率为 15, 等待 1000/15 保证视频播放流畅。
        // waitKey(int delay) 是 OpenCV 提供的一个等待函数,
        // 当运行到这个函数时会阻塞 delay 毫秒的时间来等待键盘输入
        char c = (char)cv::waitKey(1000/15.0);
        if( c == 27 )//当按键为esc时,退出循环
            break;
    }
    //释放申请的相关内存
    cv::destroyAllWindows();
    video.release();
    return 0;
}


/*以下为本程序仿真步骤
需要安装opencv、opengl
提供linux环境下安装opencv的方法
sudo apt-get install libopencv-dev
linux环境安装opengl的命令
//sudo apt-get update && sudo apt-get install freeglut3 freeglut3-dev

另外提供安装linux环境下的屏幕录制工具
sudo apt-get update && sudo apt-get install gtk-recordmydesktop
linux环境下编译命令
g++ main.cpp `pkg-config opencv --libs --cflags opencv` -o  main
*/

你可能感兴趣的:(计算机视觉,opencv,c++,linux)