opencv3/C++ meanshift与camshift目标跟踪

mean shift基本原理:

给定d维空间  Rd 中的n个样本点  xi,i=1,2,...,n,  x 点的mean shift向量的基本形式定义为:
 Mh(x)=1kxiSk(xix)
其中,  Sh 是一个半径为h的高维球区域,满足以下关系的y点的集合,
 Sh(x)={y:(yx)T(yx)h2}
k表示在这n个样本点  xi 中落入  Sh 区域中。
 (xxi) 是样本点  xi 相对于点 x 的偏移量,mean shift向量 Mh(x)就是对落入区域 Sh 中的k个样本点相对于点x的偏移量求和然后再平均。
mean shift 示意图:
这里写图片描述
可以看出平均偏移量  Mh(x) 会指向样本分布最多的区域。公式中落入  Sh 的采样点,无论离中心x的远近,对最终计算的影响都一样。但现实跟踪过程中,较远的像素容易受背景或遮挡等因素的影响,因此靠近中心较近的像素应该更重要。故每个样本点的重要性应与其与中心的距离成反比。故引入核函数和权重系数来提高算法的鲁棒性。

核函数即窗口函数,在核估计中起到平滑的作用。常见的有:
Flat 核函数:
 k(x)={1,ifxλ0,ifx>λ
Gaussian 核函数:
 k(x)=ex2σ2

部分核函数:

这里写图片描述

给出一个核函数:
 K(xxi)
该函数确定重新估计平均值的附近点的权重。当选择的搜索窗口类型为高斯核时:

 K(xxi)=ecXXi2

概率分布近似为:

 P(x)=1nni=1K(xxi)

由K确定的窗口密度的加权平均值是:

 m(x)=ni=1xig(xxi)ni=1g(xxi)

其中:
 g(x)=K(x)

P(x) 求梯度:

 P(x)=cnni=1Ki=cn[ni=1gi[xxib]][ni=1xig(xxi)ni=1g(xxi)x]

表达式构成如图:

这里写图片描述
这里写图片描述
mean shift算法主要应用于聚类、平滑和跟踪。

mean shift跟踪算法:

mean shift算法用于视觉跟踪时,将基于前一图像中的对象的颜色直方图在新图像中创建置信度图,并使用均值平移来找到靠近对象旧位置的置信度图的峰值。 置信度图是新图像上的概率密度函数,为新图像的每个像素指定一个概率,该概率是前一图像中的对象中出现的像素颜色的概率。

mean shift跟踪算法步骤:
① 选择搜索窗口,包括窗口的初始位置、大小、形状(对称或歪斜,矩形或圆心)、类型(均匀、多项式、指数或高斯);
② 计算窗口的重心;
③ 将窗口的中心设置在计算出的重心处;
④ 返回②步,直到窗口位置不再变化。

设目标区域的中心为x,其中n个像素用  xi,i=1,...,n 表示,特征值个数为m,则目标模型的特征值  u=1,...,m 的概率密度估计为:
 qu=Cni=1k[xxih2]σ[b(xi)u]

 q={qu}u=1,...,m
 mu=1qu=1
其中,k为权值系数,赋予靠近中心的像素一个较大权值,远离中心的像素给定较小的权值。
 σ[b(xi)u] 的作用是判断目标区域中像素值是否属于第u个特征值。属于时为1,不属于时为0;  b(xi) 为灰度值索引函数。
C为一标准化的常量系数:

 C=1ni=1k[xxih2]

这样可以使  mu=1qu=1

于是可以得到基于图像灰度特征的颜色直方图。

运动目标在第二帧以后的每帧中可能包含目标的区域称为候选区域,其中心坐标即核函数的中心坐标y。该区域中的像素用  xi,i=1,...,nk 表示;候选模型的特征值  u=1,...,m 的概率密度为:
 pu(y)=Chnki=1k[yxih2]σ[b(xi)u]

 p(y)={pu(y)}u=1,...,m
 mu=1pu=1

 Ch 为标准化常量:

 Ch=1nki=1k[yxih2]

Bhattacharyya系数

利用相似函数描述目标模型和候选模型之间的相似度,理想情况下两个模型的概率分布一样。使用Bhattacharyya系数作为相似函数。
 BC(p,q) 为Bhattacharyya系数。
Bhattacharyya系数是衡量两个统计样本之间重叠量或相对接近度的指标。
对于离散概率分布:  BC(p,q)=xXp(x)q(x)
对于连续概率分布:  BC(p,q)=p(x)q(x)dx
另,Bhattacharyya距离为:  DB(p,q)=ln(BC(p,q))

模板区域:  q=(q1,...,qm)
候选区域:  p(y)=(p1(y),...,pm(y))
相似性函数:  f(y)=f[p(y),q]=mu=1pu(y)qu
这里写图片描述
Bhattacharyya系数的值在0到1之间,值越大表示两个模型月相似。跟踪时选择使Bhattacharyya系数最大的候选区域作为当前帧中的目标位置。

camshift算法

camshift算法就是将meanshift算法扩展到连续图像序列。camshift将视频的所有帧做meanshift运算,并将上一帧的结果(搜索窗的大小和中心),作为下一帧meanshift算法搜索窗的初始值。然后一直迭代下去,实现对目标的跟踪。

函数CamShift()参数说明:

//查找对象中心,大小和方向。
RotatedRect CamShift(
InputArray probImage,//对象直方图的反向投影
CV_IN_OUT Rect& window,//初始搜索窗口
TermCriteria criteria//底层meanShift的停止标准
);

OpenCV3 camshift跟踪

#include<opencv2/opencv.hpp>
#include<opencv2/tracking.hpp>
using namespace cv;

int main()
{
    VideoCapture capture;
    Mat frame;
    //保存目标轨迹  
    std::vector<Point> pt; 
    capture.open(0);
    if (!capture.isOpened())
    {
        printf("can not open camera \n");
        return -1;
    }
    namedWindow("input", WINDOW_AUTOSIZE);
    namedWindow("output", WINDOW_AUTOSIZE);
    capture.read(frame);
    if (frame.empty())
        return -1;
    Rect2d first = selectROI("output", frame);
    Rect selectionROI;
    selectionROI.width = first.width;
    selectionROI.height = first.height;
    selectionROI.x = first.x;
    selectionROI.y = first.y;
    printf("x= %d, y=%d, width=%d, height=%d",selectionROI.x,selectionROI.y,selectionROI.width,selectionROI.height);

    Mat mask, hist, backproject;
    int bins = 120;
    Mat drawImg = Mat::zeros(300, 300, CV_8UC3);

    while (capture.read(frame))
    {
        Mat hsvimage;
        cvtColor(frame, hsvimage, CV_BGR2HSV);
        inRange(hsvimage, Scalar(25, 43, 46), Scalar(35, 256, 256), mask);
        Mat hue = Mat(hsvimage.size(), hsvimage.depth());
        int channels[] = {0, 0};
        mixChannels(&hsvimage, 1, &hue, 1, channels, 1);

        //ROI直方图计算
        Mat roi(hue, first);
        Mat maskroi(mask, first);
        float hrange[] = {0, 180};
        const float* hranges = hrange;
        //直方图
        calcHist(&roi, 1, 0, maskroi, hist, 1, &bins, &hranges);
        normalize(hist, hist, 0, 255, NORM_MINMAX);

        int binw = drawImg.cols/ bins;
        Mat colorIndex = Mat(1, bins, CV_8UC3);
        for (int i = 0; i < bins; i++)
        {
            colorIndex.at<Vec3b>(0, i) = Vec3b(saturate_cast<uchar>(i * 180 / bins), 255, 255);
        }
        cvtColor(colorIndex, colorIndex, COLOR_HSV2BGR);
        for (int i = 0; i < bins; i++)
        {
            int val = saturate_cast<int>(hist.at<float>(i)*drawImg.rows/255);
            rectangle(drawImg, Point(i*binw, drawImg.rows), Point((i+1)*binw, drawImg.rows * val), Scalar(colorIndex.at<Vec3b>(0, i)), -1, 8, 0);
        }

        //计算直方图的反投影
        calcBackProject(&hue, 1, 0, hist, backproject, &hranges);
        backproject &= mask;
        RotatedRect trackBox = CamShift(backproject, selectionROI, TermCriteria((TermCriteria::COUNT | TermCriteria::EPS), 10, 1));
        Rect rect; 
        rect.x = trackBox.center.x - trackBox.size.width/2.0;
        rect.y = trackBox.center.y - trackBox.size.height/2.0;
        rect.width = trackBox.size.width;
        rect.height = trackBox.size.height;

        rectangle(frame, rect, Scalar(255, 255, 0),3);

        pt.push_back(Point(rect.x+rect.width/2,rect.y+rect.height/2));  
        for(int i=0;i<pt.size()-1;i++) 
        {    
            line(frame,pt[i],pt[i+1],Scalar(0,255,0),2.5);    
        } 
        imshow("input", frame);
        imshow("output", drawImg);
        waitKey(10);
    }

    capture.release();
    return 0;
}

这里写图片描述
这里写图片描述
这里写图片描述

  • 2
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值