Qt 5.3 下OpenCV 2.4.11 开发(11)CamShift 目标跟踪

控制台应用下,使用鼠标在预览摄像头上进行截图,截图内容为目标所在区域的矩形,然后利用函数CamShift 函数对目标进行跟踪,代码如下,要记得添加项目引用库,章节目录有:

#include <QCoreApplication>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/video/tracking.hpp>
#include <iostream>

using namespace cv;
using namespace std;

Mat image;
Mat frame;//保存帧图像
Point origin;//用于保存鼠标选择第一次单击时点的位置
Rect selection;//用于保存鼠标选择的矩形框
int trackObject = 0; //代表跟踪目标数目
bool selectObject = false;//代表是否在选要跟踪的初始目标,true表示正在用鼠标选择
bool backprojMode = false; //表示是否要进入反向投影模式,ture表示准备进入反向投影模式

void onMouse( int event, int x, int y, int, void* )
{
    if( selectObject )//只有当鼠标左键按下去时才有效,然后通过if里面代码就可以确定所选择的矩形区域selection了
    {
        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);//矩形高

        selection &= Rect(0, 0, frame.cols, frame.rows);//用于确保所选的矩形区域在图片范围内
    }

    switch( event )
    {
    case CV_EVENT_LBUTTONDOWN:
        origin = Point(x,y);
        selection = Rect(x,y,0,0);//鼠标刚按下去时初始化了一个矩形区域
        selectObject = true;
        break;
    case CV_EVENT_LBUTTONUP:
        selectObject = false;
        if( selection.width > 0 && selection.height > 0 )
            trackObject = -1;
        break;
    }
}

int main()
{
    bool stop = false;
    VideoCapture cap(0);
    Rect trackWindow;
    Mat hsv, hue, hist, backproj, mask;
    int hsize = 32;
    float hranges[] = {0,180};//hranges在后面的计算直方图函数中要用到
    const float* phranges = hranges;

    if(!cap.isOpened())
    {
        return -1;
    }
    namedWindow("image",0);
    setMouseCallback( "image", onMouse, 0 );//消息响应机制
    while(!stop)
    {
        cap>>frame;
        frame.copyTo(image);
        cvtColor(image, hsv, CV_BGR2HSV);
        if( trackObject )//trackObject初始化为0,当鼠标单击松开后为-1
        {
            //inRange函数的功能是检查输入数组每个元素大小是否在2个给定数值之间,
            //可以有多通道,mask保存0通道的最小值,也就是h分量这里利用了hsv的3个通道,
            //比较h,0~180,s,smin~256,v,min(vmin,vmax),max(vmin,vmax).如果3个通道都在对应的范围内,则
            //mask对应的那个点的值全为1(0xff),否则为0(0x00).
            inRange(hsv, Scalar(0, 30, 10), Scalar(180, 256, 256), mask);
            int ch[] = {0, 0};
            hue.create(hsv.size(), hsv.depth());//hue初始化为与hsv大小深度一样的矩阵,色调的度量是用角度表示的,
                                                //红绿蓝之间相差120度,反色相差180度
            mixChannels(&hsv, 1, &hue, 1, ch, 1);//将hsv第一个通道(也就是色调)的数复制到hue中,0索引数组

            if( trackObject < 0 )//鼠标选择区域松开后,该函数内部又将其赋值-1
            {
                Mat roi(hue, selection), maskroi(mask, selection);//mask保存的hsv的最小值
                //calcHist()函数第一个参数为输入矩阵序列,第2个参数表示输入的矩阵数目,
                //第3个参数表示将被计算直方图维数通道的列表,第4个参数表示可选的掩码函数
                //第5个参数表示输出直方图,第6个参数表示直方图的维数,第7个参数为每一维
                //直方图数组的大小,第8个参数为每一维直方图bin的边界
                calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);//将roi的0通道计算直方图并通过mask
                                                                          //放入hist中,hsize为每一维直方图的大小
                normalize(hist, hist, 0, 255, CV_MINMAX);//将hist矩阵进行数组范围归一化,都归一化到0~255
                trackWindow = selection;
                trackObject = 1;
            }
            calcBackProject(&hue, 1, 0, hist, backproj, &phranges);//计算直方图的反向投影,
                                                        //计算hue图像0通道直方图hist的反向投影,并让入backproj中
            backproj &= mask;
            //opencv2.0以后的版本函数命名前没有cv两字了,并且如果函数名是由2个意思的单词片段组成的话,
            //且前面那个片段不够成单词,则第一个字母要大写,比如Camshift,如果第一个字母是个单词,
            //则小写,比如meanShift,但是第二个字母一定要大写
            RotatedRect trackBox = CamShift(backproj, trackWindow,
                                TermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ));
            //trackWindow为鼠标选择的区域,TermCriteria为确定迭代终止的准则
            //CV_TERMCRIT_EPS是通过forest_accuracy,
            //CV_TERMCRIT_ITER是通过max_num_of_trees_in_the_forest
            if( backprojMode )
                cvtColor( backproj, image, CV_GRAY2BGR );//因此投影模式下显示的也是rgb图
            ellipse( image, trackBox, Scalar(0,0,255), 3, CV_AA );//跟踪的时候以椭圆为代表目标
        }
        if( selectObject && selection.width > 0 && selection.height > 0 )
        {
            Mat ROI(image, selection);//这句话是将frame帧图片中的选中矩形区域的地址指向ROI,
                                      //对于内存而言,frame和ROI是公用内存的,所以下面这句实际
                                      //是将frame帧图像中的选中矩形区域块图像进行操作,而不是新创建
                                      //一个内存来进行操作
            //当然所截图的矩形区域ROI,可以使用imwrite函数来保存
            bitwise_not(ROI, ROI);//bitwise_not为将每一个bit位取反
        }
        imshow("image",image);
        if( waitKey(30) == 27 )//ESC键退出
            stop = true;
    }
    return 0;
}

函数介绍:

1、cvtColor 将输入图像转换为目标图像,转换方式可以是BGR-》RGB、BGR-》GRAY、BGR-》HSV 等。HSV 色彩空间前面章节有介绍。之所以要将捕获的帧图像从BGR色彩空间转换到 HSV 色彩空间是因为,HSV 色彩空间比较接近与人的视觉感官,并且第一通道的 H 色调,包括了所有的颜色信息,因此在对该单通道图像进行处理不但可以达到速度要求,也能达到效果要求。

2、inRange 函数在代码中有介绍,Scalar 结构可以保存4个double 类型的变量,其实就是一个有4个元素的double类型的数组,这样对于三通道的 HSV 图像,可以使用inRange函数,将 HSV 图像中每个通道的像素范围进行检测和标记。

3、mixChannels 函数代码中有介绍。

4、Rect 类用来保存一个矩形区域,可以用构造函数来初始化,Rect(0, 0, frame.cols, frame.rows),第1、2个参数为矩形左上角坐标,3、4参数为矩形的宽和高。

5、MIN(x, origin.x) 选取两个参数中的最小值,同样有MAX(*,*)函数。

6、Point 结构用来保存一个二维点坐标,使用方法初始化方法跟 Rect 类似。

7、Mat roi(hue, selection) 这种构造方法是将rect 类型的selection 对象在Mat 类型的 hue 对象中选定的区域保存在 Mat 类型的 roi 对象中。并且roi 和 hue 共用内存,只是在同一个内存块上的两个不同位置的指针。

8、calcHist 函数在代码中有介绍,用于按照参数的规定,统计输入图像的和直方图。

9、normalize 用于对直方图做归一化,归一化的值域可以自己规定。

10、calcBackProject 函数用来在输入图像上借助直方图计算相应的反投影概率图像,即输入图像为一个正常的单通道或者三通道图像,输出是将此输入图像变成一幅概率分布图像,转换的介质就是输入的直方图参数,原理是将输入图像中的每个像素值映射到直方图的对应范围中,再将对应的直方图数值投影到输出图像的对应像素位置中。

11、CamShift 函数中,调用了 meanShift 函数,关于meanShift 算法将单独有一节介绍。

12、RotatedRect 类用来保存一个旋转的矩形,这里暂不涉及该类的具体用法。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-10 17:42:11

Qt 5.3 下OpenCV 2.4.11 开发(11)CamShift 目标跟踪的相关文章

Qt 5.3 下OpenCV 2.4.11 开发 目录

Qt 5.3 下OpenCV2.4.11 开发(1)图片预览 Qt 5.3 下OpenCV 2.4.11 开发(2)摄像头采集 版权声明:本文为博主原创文章,未经博主允许不得转载.

opencv学习之基于背景提取等目标跟踪算法#20190704

/* *********************************************************************************************************************** 任务目标: 基于背景提取的目标跟踪算法实践及代码分析. ***************************************************************************************************

Qt 5.3 下OpenCV 2.4.11 开发(0)图像处理基本概念

1.普通情况下的RGB彩色图像:它的每一个像素点都是由三个通道组成,即红色(R).绿色(G)和蓝色(B).8位三通道彩色图像就是每一个像素中每一个通道的取值范围都是 0~255(即二进制下的8位数),而整幅彩色图像则是由三个通道的图像所组成.在数据中的存储方式是依照像素连续存储的,而每一个像素中的数据存储也是按RGB连续存储的.当然,有些图片格式中像素数据是按BGR存储的,这个视情况而定. 2.灰度图像:它仅仅有一个颜色通道,所以在做图像处理的时候速度非常快,它的每一个像素是通过彩色图像的三个通

Qt 5.3 下OpenCV 2.4.11 开发(10)使用鼠标回调函数对视频帧截图

Qt 新建控制台程序,main.cpp 代码如下: #include <QCoreApplication> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <iostream> using namespace cv; using namespace std;

Qt 5.3 下OpenCV 2.4.11 开发(3)简单的GUI项目

新建一个GUI项目,QT4为 Qt4 Gui Application,QT5为 Qt Widgets Application,基类选择 QMainWindow 项目实现功能:两个按钮,一个用于在文件夹中选择图片并预览图片,一个按钮用于反转该图片.项目代码如下: .pro 代码段,关于加入opencv头文件和库函数的代码根据自己开发环境而定. #------------------------------------------------- # # Project created by QtCr

Qt 5.3 下OpenCV 2.4.11 开发(5)最高效的像素引用

OpenCV 提供一个函数 getTickCount() ,能够用来測量一段代码的执行时间.另一个函数 getTickFrequency() 用来返回每秒内的时钟周期.代码操作例如以下: double duration; duration = static_cast<double>(getTickCount()); colorReduce(src); duration = static_cast<double>(getTickCount()) - duration; duratio

Qt 5.3 下OpenCV 2.4.11 开发(9)直方图均衡化

接着上面的章节,我们在 Histogram1D 类中加入一个新方法,即直方图均衡化的方法,现在贴出完整的代码,Histogram1D 类 头文件如下: #ifndef HISTOGRAM1D_H #define HISTOGRAM1D_H #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/opencv.hpp> using namespace

Qt 5.3 下OpenCV 2.4.11 开发(15)滤波函数

代码列出了高斯滤波.中值滤波.均值滤波和双边滤波: #include <QCoreApplication> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <iostream> using namespace cv; using namespace std;

Qt 5.3 下OpenCV 2.4.11 开发(8)查表法直方图修改图像

接着上节内容,本节添加两个方法 stretch() 方法和 applyLookUp() 方法.第一个方法用于拉伸直方图的准备工作,即排除直方图中没有像素值存在的项:第二个方法用查表法拉伸图像.现在贴出完整代码,Histogram1D.h 代码段如下: #ifndef HISTOGRAM1D_H #define HISTOGRAM1D_H #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #