视频跟踪——meanshift算法
部分内容转载于
http://blog.csdn./google19890102/article/details/51030884
http://.blogs./liqizhou/archive/2012/05/12/2497220.html
meanShift,均值漂移,在聚类、图像平滑、分割、跟踪等方面有着广泛的应用。meanShift这个概念最早是由Fukunage在1975年提出的,其最初的含义正如其名偏移的均值向量;但随着理论的发展,meanShift的含义已经发生了很多变化。如今,我们说的meanShift算法,一般是指一个迭代的步骤,即先算出当前点的偏移均值,然后以此为新的起始点,继续移动,直到满足一定的结束条件。
meanShift的两大特色
1.定义了核函数。
2.增加了权重系数。
先解释一下核函数在Mean Shift算法中引入核函数的目的是使得随着样本与被偏移点的距离不同,其偏移量对均值偏移向量的贡献也不同。核函数是机器学习中常用的一种方式。核函数的定义如下所示
X表示一个d维的欧式空间,x是该空间中的一个点x={x1,x2,x3⋯,xd},其中,x的模∥x∥2=xxT,R表示实数域,如果一个函数K:XR存在一个剖面函数k:[0,∞]R,即
K(x)=k(∥x∥2)
并且满足
(1)、k是非负的
(2)、k是非增的
(3)、k是分段连续的
那么,函数K(x)就称为核函数。
而权重系数使得不同样本点的重要性不一样,这大大扩展了meanShift的应用范围。
在Mean Shift算法中,实际上是利用了概率密度,求得概率密度的局部最优解。
概率密度梯度
对一个概率密度函数f(x),已知d维空间中n个采样点xi,i=1,⋯,n,f(x)的核函数估计(也称为Parzen窗估计)为
f^(x)=∑ni=1K(xi−xh)(xi)hd∑ni=1(xi)
其中
(xi)⩾0是一个赋给采样点xi的权重
K(x)是一个核函数
概率密度函数f(x)的梯度f(x)的估计为
f^(x)=2∑ni=1(x−xi)k′(∥∥xi−xh∥∥2)(xi)hd+2∑ni=1(xi)
令g(x)=−k′(x),G(x)=g(∥x∥2),则有
f^(x)=2∑ni=1(xi−x)G(∥∥xi−xh∥∥2)(xi)hd+2∑ni=1(xi)=2h2∑ni=1G(xi−xh)(xi)hd∑ni=1(xi)∑ni=1(xi−x)G(∥∥xi−xh∥∥2)(xi)∑ni=1G(xi−xh)(xi)
其中,第二个方括号中的就是Mean Shift向量,其与概率密度梯度成正比。
Mean Shift向量的修正
Mh(x)=∑ni=1G(∥∥xi−xh∥∥2)(xi)xi∑ni=1G(xi−xh)(xi)−x
记mh(x)=∑ni=1G(∥∥xi−xh∥∥2)(xi)xi∑ni=1G(xi−xh)(xi),则上式变成
Mh(x)=mh(x)+x
这与梯度上升的过程一致。
Mean Shift算法流程
Mean Shift算法的算法流程如下
计算mh(x)
令x=mh(x)
如果∥mh(x)−x∥<ε,结束循环,否则,重复上述步骤
基于均值漂移的目标跟踪算法通过分别计算目标区域和候选区域内像素的特征值概率得到关于目标模型和候选模型的描述,然后利用相似函数度量初始帧目标模型和当前帧的候选模版的相似性,选择使相似函数最大的候选模型并得到关于目标模型的Meanshift向量,这个向量正是目标由初始位置向正确位置移动的向量。由于均值漂移算法的快速收敛性,通过不断迭代计算Meanshift向量,算法最终将收敛到目标的真实位置,达到跟踪的目的。
下面通过图示直观的说明MeanShift跟踪算法的基本原理。如下图所示目标跟踪开始于数据点xi0(空心圆点xi0,xi1,…,xiN表示的是中心点,上标表示的是的迭代次数,周围的黑色圆点表示不断移动中的窗口样本点,虚线圆圈代表的是密度估计窗口的大小)。箭头表示样本点相对于核函数中心点的漂移向量,平均的漂移向量会指向样本点最密集的方向,也就是梯度方向。因为 Meanshift 算法是收敛的,在当前帧中通过反复迭代搜索特征空间中样本点最密集的区域,搜索点沿着样本点密度增加的方向“漂移”到局部密度极大点点xiN,也就是被认为的目标位置,从而达到跟踪的目的,MeanShift 跟踪过程结束。
相关代码
#include "stdafx.h"#include "cv.h"#include "highgui.h"#define u_char unsigned char#define DIST 0.5#define NUM 20//全局变量bool pause = false;bool is_tracking = false;CvRect draing_box;IplImage current;double hist1, hist2;double m_ei; //权值矩阵double C = 0.0; //归一化系数void init_target(double hist1, double m_ei, IplImage current){ IplImage pic_hist = 0; int t_h, t_, t_x, t_y; double h, dist; int i, j; int q_r, q_g, q_b, q_temp; t_h = draing_box.height; t_ = draing_box.idth; t_x = draing_box.x; t_y = draing_box.y; h = po(((double)t_)/2,2) + po(((double)t_h)/2,2); //带宽 pic_hist = cvCreateImage(cvSize(300,200),IPL_DEPTH_8U,3); //生成直方图图像 //初始化权值矩阵和目标直方图 for (i = 0;i < t_t_h;i++) { m_ei[i] = 0.0; } for (i=0;i<4096;i++) { hist1[i] = 0.0; } for (i = 0;i < t_h; i++) { for (j = 0;j < t_; j++) { dist = po(i - (double)t_h/2,2) + po(j - (double)t_/2,2); m_ei[i t_ + j] = 1 - dist / h; //printf("%fn",m_ei[i t_ + j]); C += m_ei[i t_ + j] ; } } //计算目标权值直方 for (i = t_y;i < t_y + t_h; i++) { for (j = t_x;j < t_x + t_; j++) { //rgb颜色空间量化为161616 bins q_r = ((u_char)current->imageData[i current->idthStep + j 3 + 2]) / 16; q_g = ((u_char)current->imageData[i current->idthStep + j 3 + 1]) / 16; q_b = ((u_char)current->imageData[i current->idthStep + j 3 + 0]) / 16; q_temp = q_r 256 + q_g 16 + q_b; hist1[q_temp] = hist1[q_temp] + m_ei[(i - t_y) t_ + (j - t_x)] ; } } //归一化直方图 for (i=0;i<4096;i++) { hist1[i] = hist1[i] / C; //printf("%fn",hist1[i]); } //生成目标直方图 double temp_max=0.0; for (i = 0;i < 4096;i++) //求直方图最大值,为了归一化 { //printf("%fn",val_hist[i]); if (temp_max < hist1[i]) { temp_max = hist1[i]; } } //画直方图 CvPoint p1,p2; double bin_idth=(double)pic_hist->idth/4096; double bin_unith=(double)pic_hist->height/temp_max; for (i = 0;i < 4096; i++) { p1.x = i bin_idth; p1.y = pic_hist->height; p2.x = (i + 1)bin_idth; p2.y = pic_hist->height - hist1[i] bin_unith; //printf("%d,%d,%d,%dn",p1.x,p1.y,p2.x,p2.y); cvRectangle(pic_hist,p1,p2,cvScalar(0,255,0),-1,8,0); } cvSaveImage("hist1.jpg",pic_hist); cvReleaseImage(&pic_hist);}void MeanShift_Tracking(IplImage current){ int num = 0, i = 0, j = 0; int t_ = 0, t_h = 0, t_x = 0, t_y = 0; double = 0, hist2 = 0; double sum_ = 0, x1 = 0, x2 = 0,y1 = 2.0, y2 = 2.0; int q_r, q_g, q_b; int q_temp; IplImage pic_hist = 0; t_ = draing_box.idth; t_h = draing_box.height; pic_hist = cvCreateImage(cvSize(300,200),IPL_DEPTH_8U,3); //生成直方图图像 hist2 = (double )malloc(sizeof(double)4096); = (double )malloc(sizeof(double)4096); q_temp = (int )malloc(sizeof(int)t_t_h); hile ((po(y2,2) + po(y1,2) > 0.5)&& (num < NUM)) { num++; t_x = draing_box.x; t_y = draing_box.y; memset(q_temp,0,sizeof(int)t_t_h); for (i = 0;i<4096;i++) { [i] = 0.0; hist2[i] = 0.0; } for (i = t_y;i < t_h + t_y;i++) { for (j = t_x;j < t_ + t_x;j++) { //rgb颜色空间量化为161616 bins q_r = ((u_char)current->imageData[i current->idthStep + j 3 + 2]) / 16; q_g = ((u_char)current->imageData[i current->idthStep + j 3 + 1]) / 16; q_b = ((u_char)current->imageData[i current->idthStep + j 3 + 0]) / 16; q_temp[(i - t_y) t_ + j - t_x] = q_r 256 + q_g 16 + q_b; hist2[q_temp[(i - t_y) t_ + j - t_x]] = hist2[q_temp[(i - t_y) t_ + j - t_x]] + m_ei[(i - t_y) t_ + j - t_x] ; } } //归一化直方图 for (i=0;i<4096;i++) { hist2[i] = hist2[i] / C; //printf("%fn",hist2[i]); } //生成目标直方图 double temp_max=0.0; for (i=0;i<4096;i++) //求直方图最大值,为了归一化 { if (temp_max < hist2[i]) { temp_max = hist2[i]; } } //画直方图 CvPoint p1,p2; double bin_idth=(double)pic_hist->idth/(4368); double bin_unith=(double)pic_hist->height/temp_max; for (i = 0;i < 4096; i++) { p1.x = i bin_idth; p1.y = pic_hist->height; p2.x = (i + 1)bin_idth; p2.y = pic_hist->height - hist2[i] bin_unith; cvRectangle(pic_hist,p1,p2,cvScalar(0,255,0),-1,8,0); } cvSaveImage("hist2.jpg",pic_hist); for (i = 0;i < 4096;i++) { if (hist2[i] != 0) { [i] = sqrt(hist1[i]/hist2[i]); }else { [i] = 0; } } sum_ = 0.0; x1 = 0.0; x2 = 0.0; for (i = 0;i < t_h; i++) { for (j = 0;j < t_; j++) { //printf("%dn",q_temp[i t_ + j]); sum_ = sum_ + [q_temp[i t_ + j]]; x1 = x1 + [q_temp[i t_ + j]] (i - t_h/2); x2 = x2 + [q_temp[i t_ + j]] (j - t_/2); } } y1 = x1 / sum_; y2 = x2 / sum_; //中心点位置更新 draing_box.x += y2; draing_box.y += y1; //printf("%d,%dn",draing_box.x,draing_box.y); } free(hist2); free(); free(q_temp); //显示跟踪结果 cvRectangle(current,cvPoint(draing_box.x,draing_box.y),cvPoint(draing_box.x+draing_box.idth,draing_box.y+draing_box.height),CV_RGB(255,0,0),2); cvShoImage("Meanshift",current); //cvSaveImage("result.jpg",current); cvReleaseImage(&pic_hist);}void onMouse( int event, int x, int y, int flags, void param ){ if (pause) { sitch(event) { case CV_EVENT_LBUTTONDOWN: //the left up point of the rect draing_box.x=x; draing_box.y=y; break; case CV_EVENT_LBUTTONUP: //finish draing the rect (use color green for finish) draing_box.idth=x-draing_box.x; draing_box.height=y-draing_box.y; cvRectangle(current,cvPoint(draing_box.x,draing_box.y),cvPoint(draing_box.x+draing_box.idth,draing_box.y+draing_box.height),CV_RGB(255,0,0),2); cvShoImage("Meanshift",current); //目标初始化 hist1 = (double )malloc(sizeof(double)161616); m_ei = (double )malloc(sizeof(double)draing_box.heightdraing_box.idth); init_target(hist1, m_ei, current); is_tracking = true; break; } return; }}int _tmain(int argc, _TCHAR argv[]){ CvCapture capture=cvCreateFileCapture("test.avi"); current = cvQueryframe(capture); char res[20]; int nframe = 0; hile (1) { if(is_tracking) { MeanShift_Tracking(current); } int c=cvWaitKey(1); //暂停 if(c == 'p') { pause = true; cvSetMouseCallback( "Meanshift", onMouse, 0 ); } hile(pause){ if(cvWaitKey(0) == 'p') pause = false; } cvShoImage("Meanshift",current); current = cvQueryframe(capture); //抓取一帧 } cvNamedWindo("Meanshift",1); cvReleaseCapture(&capture); cvDestroyWindo("Meanshift"); return 0;}
空调维修
- 海信电视维修站 海信电视维修站点
- 格兰仕空调售后电话 格兰仕空调维修售后服务电
- 家电售后服务 家电售后服务流程
- 华扬太阳能维修 华扬太阳能维修收费标准表
- 三菱电机空调维修 三菱电机空调维修费用高吗
- 美的燃气灶维修 美的燃气灶维修收费标准明细
- 科龙空调售后服务 科龙空调售后服务网点
- 华帝热水器维修 华帝热水器维修常见故障
- 康泉热水器维修 康泉热水器维修故障
- 华凌冰箱维修电话 华凌冰箱维修点电话
- 海尔维修站 海尔维修站点地址在哪里
- 北京海信空调维修 北京海信空调售后服务
- 科龙空调维修 科龙空调维修故障
- 皇明太阳能售后 皇明太阳能售后维修点
- 海信冰箱售后服务 海信冰箱售后服务热线电话
- 海尔热水器服务热线