KCF代码分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_28306361/article/details/78336941

很多都是参考网上的大神分析

KCF代码具体分析

KCF知乎专栏


放几个KCF中主要的cpp和hpp文件,回去接着看代码

fhog.cpp

#include "fhog.hpp"

#ifdef HAVE_TBB
#include <tbb/tbb.h>
#include “tbb/parallel_for.h”
#include “tbb/blocked_range.h”
#endif

#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif

#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif

/**********************************************************************************
函数功能:计算image的hog特征,结果在map结构中的map大小为sizeXsizeYNUM_SECTOR3(Getting feature map for the selected subimage)
函数参数:选中的子图,cell的大小,返回的特征图
RESULT:Error status
**********************************************************************************/
int getFeatureMaps( const IplImage
image, const int k, CvLSVMFeatureMapCaskade **map )
{
//总体过程是:
//1.计算每个像素的水平梯度dx和垂直梯度dy
//2.计算每个像素的通道间最大梯度大小r及其最邻近梯度方向的索引值
//3.计算每个block(2+4+2)
(2+4+2)的梯度直方图(分为9和18bin)存于map中//每个block的特征是以一个cell为中心,根据像素的位置以及像素点的梯度强度进行加权获得的
int sizeX, sizeY;
int p, px, stringSize;
int height, width, numChannels;
int i, j, kk, c, ii, jj, d;
float * datadx, *datady;

int   ch;
float magnitude, x, y, tx, ty;

IplImage * dx, *dy;
int *nearest;
float *w, a_x, b_x;

// 横向和纵向的3长度{-1,0,1}矩阵 
float kernel[3] = { -1.f, 0.f, 1.f };
CvMat kernel_dx = cvMat( 1, 3, CV_32F, kernel );          // 1*3的矩阵
CvMat kernel_dy = cvMat( 3, 1, CV_32F, kernel );          // 3*1的矩阵

float * r;//记录每个像素点的每个通道的最大梯度
int   * alfa;//记录每个像素的梯度方向的索引值,分别为9份时的索引值和18份时的索引值。

float boundary_x[NUM_SECTOR + 1];                        // boundary_x[10]
float boundary_y[NUM_SECTOR + 1];
float max, dotProd;
int   maxi;

height = image-&gt;height;
width = image-&gt;width;

numChannels = image-&gt;nChannels;

// 采样图像大小的Ipl图像
dx = cvCreateImage( cvSize( image-&gt;width, image-&gt;height ),
	IPL_DEPTH_32F, 3 );
dy = cvCreateImage( cvSize( image-&gt;width, image-&gt;height ),
	IPL_DEPTH_32F, 3 );

// 向下取整的(边界大小/4),k = cell_size
sizeX = width / k;			// 将图像分割成多个元胞(cell),x方向上cell的个数
sizeY = height / k;			// y方向上cell的个数
px = 3 * NUM_SECTOR;		// 三通道?NUM_SECTOR=9 Hog特征中的9个角度范围
p = px;						// p=27
stringSize = sizeX * p;		// stringSize = 27*sizeX
allocFeatureMapObject( map, sizeX, sizeY, p );			// 为map初始化内存sizeX*sizeY*p=sizeY*stringSize

// image:输入图像.  
// dx:输出图像.  
// kernel_dx:卷积核, 单通道浮点矩阵. 如果想要应用不同的核于不同的通道,先用 cvSplit 函数分解图像到单个色彩通道上,然后单独处理。  
// cvPoint(-1, 0):核的锚点表示一个被滤波的点在核内的位置。 锚点应该处于核内部。缺省值 (-1,-1) 表示锚点在核中心。  
// 函数 cvFilter2D 对图像进行线性滤波,支持 In-place 操作。当核运算部分超出输入图像时,函数从最近邻的图像内部象素差值得到边界外面的象素值。
cvFilter2D( image, dx, &amp;kernel_dx, cvPoint( -1, 0 ) );      // 起点在(x-1,y),按x方向滤波
cvFilter2D( image, dy, &amp;kernel_dy, cvPoint( 0, -1 ) );      // 起点在(x,y-1),按y方向滤波 

// 初始化cos和sin函数
float arg_vector;

// 计算梯度角的边界,并存储在boundary__y中
for( i = 0; i &lt;= NUM_SECTOR; i++ )
{
	arg_vector = ( ( float ) i ) * ( ( float ) ( PI ) / ( float ) ( NUM_SECTOR ) );		// 每个角的角度
	boundary_x[i] = cosf( arg_vector );			// 每个角度对应的余弦值
	boundary_y[i] = sinf( arg_vector );			// 每个角度对应的正弦值
}/*for(i = 0; i &lt;= NUM_SECTOR; i++) */

r	 = ( float * ) malloc( sizeof( float ) * ( width * height ) );
alfa = ( int   * ) malloc( sizeof( int ) * ( width * height * 2 ) );

//2.
for( j = 1; j &lt; height - 1; j++ )
{
	// 记录每一行的首地址
	datadx = ( float* ) ( dx-&gt;imageData + dx-&gt;widthStep * j );
	datady = ( float* ) ( dy-&gt;imageData + dy-&gt;widthStep * j );
	for( i = 1; i &lt; width - 1; i++ )				// 遍历一行中的非边界像素
	{
		c = 0;										// 第一颜色通道
		x = ( datadx[i * numChannels + c] );
		y = ( datady[i * numChannels + c] );

		r[j * width + i] = sqrtf( x * x + y * y );	// 计算0通道的梯度大小

		// 使用向量大小最大的通道替代储存值
		for( ch = 1; ch &lt; numChannels; ch++ )		// 计算其他两个通道
		{
			tx = ( datadx[i * numChannels + ch] );
			ty = ( datady[i * numChannels + ch] );
			magnitude = sqrtf( tx * tx + ty * ty );		// 计算幅值
			if( magnitude &gt; r[j * width + i] )			// 找出每个像素点的梯度的最大值(有三个颜色空间对应的梯度),并记录通道数以及水平梯度以及垂直梯度
			{
				r[j * width + i] = magnitude;			// r表示最大幅值
				c = ch;									// c表示这个幅值来自的通道序号
				x = tx;									// x表示这个幅值对应的坐标处的x梯度
				y = ty;									// y表示这个幅值对应的坐标处的y梯度
			}
		}/*for(ch = 1; ch &lt; numChannels; ch++)*/

		// 使用sqrt(cos*x*cos*x+sin*y*sin*y)最大的替换掉
		max = boundary_x[0] * x + boundary_y[0] * y;
		maxi = 0;
		// 假设像素点的梯度方向为a,梯度方向为t,梯度大小为r,则dotProd=r*cosa*cost+r*sina*sint=r*cos(a-t)
		for( kk = 0; kk &lt; NUM_SECTOR; kk++ )							// 遍历9个HOG划分的角度范围
		{
			dotProd = boundary_x[kk] * x + boundary_y[kk] * y;			// 计算两个向量的点乘
			// 若dotProd最大,则说明t最接近a
			if( dotProd &gt; max )
			{
				max = dotProd;
				maxi = kk;
			}
			// 若-dotProd最大,则说明t最接近a+pi
			else
			{
				if( -dotProd &gt; max )
				{
					max = -dotProd;										// 取相反数
					maxi = kk + NUM_SECTOR;								// ?
				}
			}
		}
		// 看起来有点像储存cos和sin的周期值
		alfa[j * width * 2 + i * 2] = maxi % NUM_SECTOR;				// 
		alfa[j * width * 2 + i * 2 + 1] = maxi;
	}/*for(i = 0; i &lt; width; i++)*/
}/*for(j = 0; j &lt; height; j++)*/

// nearest=[-1,-1,1,1];
nearest = ( int  * ) malloc( sizeof( int ) *  k );
w		= ( float* ) malloc( sizeof( float ) * ( k * 2 ) );
// 给nearest初始化,为了方便以后利用相邻的cell的特征计算block(8*8,每个block以一个cell为中心,以半个cell为边界厚度)的属性
for( i = 0; i &lt; k / 2; i++ )
{
	nearest[i] = -1;
}/*for(i = 0; i &lt; k / 2; i++)*/
for( i = k / 2; i &lt; k; i++ )
{
	nearest[i] = 1;
}/*for(i = k / 2; i &lt; k; i++)*/

//给w初始化?不明白w的作用,可能是cell(4*4)中每个像素贡献给直方图的权值(1/8+3/8+5/8+7/8+7/8+5/8+3/8+1/8)*(1/8+3/8+5/8+7/8+7/8+5/8+3/8+1/8)=4*4
for( j = 0; j &lt; k / 2; j++ )
{
	b_x = k / 2 + j + 0.5f;
	a_x = k / 2 - j - 0.5f;
	w[j * 2] = 1.0f / a_x * ( ( a_x * b_x ) / ( a_x + b_x ) );
	w[j * 2 + 1] = 1.0f / b_x * ( ( a_x * b_x ) / ( a_x + b_x ) );
}/*for(j = 0; j &lt; k / 2; j++)*/
for( j = k / 2; j &lt; k; j++ )
{
	a_x = j - k / 2 + 0.5f;
	b_x = -j + k / 2 - 0.5f + k;
	w[j * 2] = 1.0f / a_x * ( ( a_x * b_x ) / ( a_x + b_x ) );
	w[j * 2 + 1] = 1.0f / b_x * ( ( a_x * b_x ) / ( a_x + b_x ) );
}/*for(j = k / 2; j &lt; k; j++)*/

//3.
for( i = 0; i &lt; sizeY; i++ )
{
	for( j = 0; j &lt; sizeX; j++ )
	{
		for( ii = 0; ii &lt; k; ii++ )
		{
			for( jj = 0; jj &lt; k; jj++ )
			{
				//第i行的第j个cell的第ii行第jj个像素
				if( ( i * k + ii &gt; 0 ) &amp;&amp;
					( i * k + ii &lt; height - 1 ) &amp;&amp;
					( j * k + jj &gt; 0 ) &amp;&amp;
					( j * k + jj &lt; width - 1 ) )//要跳过厚度为1的边界像素,因为边界的梯度值不准确,但这样会导致含有边界的cell统计不完整
				{
					d = ( k * i + ii ) * width + ( j * k + jj );
					( *map )-&gt;map[i * stringSize + j * ( *map )-&gt;numFeatures + alfa[d * 2]] +=
						r[d] * w[ii * 2] * w[jj * 2];//第i行第j个cell的第alfa[d * 2]个梯度方向(0-8)
					( *map )-&gt;map[i * stringSize + j * ( *map )-&gt;numFeatures + alfa[d * 2 + 1] + NUM_SECTOR] +=
						r[d] * w[ii * 2] * w[jj * 2];//第i行第j个cell的第alfa[d * 2+1]个梯度方向(9-26)
					if( ( i + nearest[ii] &gt;= 0 ) &amp;&amp;
						( i + nearest[ii] &lt;= sizeY - 1 ) )
					{
						( *map )-&gt;map[( i + nearest[ii] ) * stringSize + j * ( *map )-&gt;numFeatures + alfa[d * 2]] +=
							r[d] * w[ii * 2 + 1] * w[jj * 2];
						( *map )-&gt;map[( i + nearest[ii] ) * stringSize + j * ( *map )-&gt;numFeatures + alfa[d * 2 + 1] + NUM_SECTOR] +=
							r[d] * w[ii * 2 + 1] * w[jj * 2];
					}
					if( ( j + nearest[jj] &gt;= 0 ) &amp;&amp;
						( j + nearest[jj] &lt;= sizeX - 1 ) )
					{
						( *map )-&gt;map[i * stringSize + ( j + nearest[jj] ) * ( *map )-&gt;numFeatures + alfa[d * 2]] +=
							r[d] * w[ii * 2] * w[jj * 2 + 1];
						( *map )-&gt;map[i * stringSize + ( j + nearest[jj] ) * ( *map )-&gt;numFeatures + alfa[d * 2 + 1] + NUM_SECTOR] +=
							r[d] * w[ii * 2] * w[jj * 2 + 1];
					}
					if( ( i + nearest[ii] &gt;= 0 ) &amp;&amp;
						( i + nearest[ii] &lt;= sizeY - 1 ) &amp;&amp;
						( j + nearest[jj] &gt;= 0 ) &amp;&amp;
						( j + nearest[jj] &lt;= sizeX - 1 ) )
					{
						( *map )-&gt;map[( i + nearest[ii] ) * stringSize + ( j + nearest[jj] ) * ( *map )-&gt;numFeatures + alfa[d * 2]] +=
							r[d] * w[ii * 2 + 1] * w[jj * 2 + 1];
						( *map )-&gt;map[( i + nearest[ii] ) * stringSize + ( j + nearest[jj] ) * ( *map )-&gt;numFeatures + alfa[d * 2 + 1] + NUM_SECTOR] +=
							r[d] * w[ii * 2 + 1] * w[jj * 2 + 1];
					}
				}
			}/*for(jj = 0; jj &lt; k; jj++)*/
		}/*for(ii = 0; ii &lt; k; ii++)*/
	}/*for(j = 1; j &lt; sizeX - 1; j++)*/
}/*for(i = 1; i &lt; sizeY - 1; i++)*/

// 释放变量
cvReleaseImage( &amp;dx );
cvReleaseImage( &amp;dy );

free( w );
free( nearest );

free( r );
free( alfa );

return LATENT_SVM_OK;

}

/*****************************************************************************
函数功能:特征图标准化与截断(Feature map Normalization and Truncation)
函数参数:特征图,截断阈值
函数输出:标准化与截断之后的特征图
RESULT:Error status
*****************************************************************************/
int normalizeAndTruncate( CvLSVMFeatureMapCaskade map, const float alfa )
{
//计算步骤:
//1.分别计算每个block(除去边界)的9分特性的9个特性的平方和
//2.分别计算每个block在各个方向上的9分特性的2范数
//3.用各个属性(共27个)除以各个方向上的2范数,得到归一化的27
4个属性
int i, j, ii;
int sizeX, sizeY, p, pos, pp, xp, pos1, pos2;
float * partOfNorm; // norm of C(i, j)
float * newData;
float valOfNorm;//大小为block的总数,计算每个block的前九个特征的2范数

sizeX = map-&gt;sizeX;
sizeY = map-&gt;sizeY;
partOfNorm = ( float * ) malloc( sizeof( float ) * ( sizeX * sizeY ) );

p = NUM_SECTOR;//每个cell的bin的数目
xp = NUM_SECTOR * 3;//每个block的总特征数(9+18)
pp = NUM_SECTOR * 12;

for( i = 0; i &lt; sizeX * sizeY; i++ )
{
	valOfNorm = 0.0f;
	pos = i * map-&gt;numFeatures;//第i个block的第一个特征点索引号
	for( j = 0; j &lt; p; j++ )
	{
		valOfNorm += map-&gt;map[pos + j] * map-&gt;map[pos + j];//计算第i个block的前9个特征的平方和
	}/*for(j = 0; j &lt; p; j++)*/
	partOfNorm[i] = valOfNorm;
}/*for(i = 0; i &lt; sizeX * sizeY; i++)*/

sizeX -= 2;//去掉第一列和最后一列的block
sizeY -= 2;//去掉一第行和最后一行的block

newData = ( float * ) malloc( sizeof( float ) * ( sizeX * sizeY * pp ) );
//normalization
for( i = 1; i &lt;= sizeY; i++ )
{
	for( j = 1; j &lt;= sizeX; j++ )
	{
		//右下
		valOfNorm = sqrtf(
			partOfNorm[( i ) *( sizeX + 2 ) + ( j )] +
			partOfNorm[( i ) *( sizeX + 2 ) + ( j + 1 )] +
			partOfNorm[( i + 1 )*( sizeX + 2 ) + ( j )] +
			partOfNorm[( i + 1 )*( sizeX + 2 ) + ( j + 1 )] ) + FLT_EPSILON;//计算该block右下四个block的9分属性的2范数
		pos1 = ( i ) * ( sizeX + 2 ) * xp + ( j ) * xp;//第i行第j列的block的属性的第一个值的索引值
		pos2 = ( i - 1 ) * ( sizeX ) * pp + ( j - 1 ) * pp;//除掉边框后的第i-1行第j-列的block的newdata的首地址
		for( ii = 0; ii &lt; p; ii++ )
		{
			newData[pos2 + ii] = map-&gt;map[pos1 + ii] / valOfNorm;
		}/*for(ii = 0; ii &lt; p; ii++)*/
		for( ii = 0; ii &lt; 2 * p; ii++ )
		{
			newData[pos2 + ii + p * 4] = map-&gt;map[pos1 + ii + p] / valOfNorm;
		}/*for(ii = 0; ii &lt; 2 * p; ii++)*/
		//右上
		valOfNorm = sqrtf(
			partOfNorm[( i ) *( sizeX + 2 ) + ( j )] +
			partOfNorm[( i ) *( sizeX + 2 ) + ( j + 1 )] +
			partOfNorm[( i - 1 )*( sizeX + 2 ) + ( j )] +
			partOfNorm[( i - 1 )*( sizeX + 2 ) + ( j + 1 )] ) + FLT_EPSILON;
		for( ii = 0; ii &lt; p; ii++ )
		{
			newData[pos2 + ii + p] = map-&gt;map[pos1 + ii] / valOfNorm;
		}/*for(ii = 0; ii &lt; p; ii++)*/
		for( ii = 0; ii &lt; 2 * p; ii++ )
		{
			newData[pos2 + ii + p * 6] = map-&gt;map[pos1 + ii + p] / valOfNorm;
		}/*for(ii = 0; ii &lt; 2 * p; ii++)*/
		//左下
		valOfNorm = sqrtf(
			partOfNorm[( i ) *( sizeX + 2 ) + ( j )] +
			partOfNorm[( i ) *( sizeX + 2 ) + ( j - 1 )] +
			partOfNorm[( i + 1 )*( sizeX + 2 ) + ( j )] +
			partOfNorm[( i + 1 )*( sizeX + 2 ) + ( j - 1 )] ) + FLT_EPSILON;
		for( ii = 0; ii &lt; p; ii++ )
		{
			newData[pos2 + ii + p * 2] = map-&gt;map[pos1 + ii] / valOfNorm;
		}/*for(ii = 0; ii &lt; p; ii++)*/
		for( ii = 0; ii &lt; 2 * p; ii++ )
		{
			newData[pos2 + ii + p * 8] = map-&gt;map[pos1 + ii + p] / valOfNorm;
		}/*for(ii = 0; ii &lt; 2 * p; ii++)*/
		//左上
		valOfNorm = sqrtf(
			partOfNorm[( i ) *( sizeX + 2 ) + ( j )] +
			partOfNorm[( i ) *( sizeX + 2 ) + ( j - 1 )] +
			partOfNorm[( i - 1 )*( sizeX + 2 ) + ( j )] +
			partOfNorm[( i - 1 )*( sizeX + 2 ) + ( j - 1 )] ) + FLT_EPSILON;
		for( ii = 0; ii &lt; p; ii++ )
		{
			newData[pos2 + ii + p * 3] = map-&gt;map[pos1 + ii] / valOfNorm;
		}/*for(ii = 0; ii &lt; p; ii++)*/
		for( ii = 0; ii &lt; 2 * p; ii++ )
		{
			newData[pos2 + ii + p * 10] = map-&gt;map[pos1 + ii + p] / valOfNorm;
		}/*for(ii = 0; ii &lt; 2 * p; ii++)*/
	}/*for(j = 1; j &lt;= sizeX; j++)*/
}/*for(i = 1; i &lt;= sizeY; i++)*/
//truncation
for( i = 0; i &lt; sizeX * sizeY * pp; i++ )
{
	if( newData[i] &gt; alfa ) newData[i] = alfa;
}/*for(i = 0; i &lt; sizeX * sizeY * pp; i++)*/
//swop data

map-&gt;numFeatures = pp;
map-&gt;sizeX = sizeX;
map-&gt;sizeY = sizeY;

free( map-&gt;map );
free( partOfNorm );

map-&gt;map = newData;

return LATENT_SVM_OK;

}

/*****************************************************************************
函数功能:特征图降维(Feature map reduction)
In each cell we reduce dimension of the feature vector according to original paper special procedure
函数参数:特征图
函数输出:特征图
RESULT:Error status
*****************************************************************************/
int PCAFeatureMaps( CvLSVMFeatureMapCaskade *map )
{
//步骤:
//1.计算每个18分属性在4个方向上的和
//2.计算每个9分属性在4个方向上的和
//3.计算4个方向上18分属性的和
int i, j, ii, jj, k;
int sizeX, sizeY, p, pp, xp, yp, pos1, pos2;
float * newData;
float val;
float nx, ny;

sizeX = map-&gt;sizeX;
sizeY = map-&gt;sizeY;
p = map-&gt;numFeatures;
pp = NUM_SECTOR * 3 + 4;
yp = 4;
xp = NUM_SECTOR;

nx = 1.0f / sqrtf( ( float ) ( xp * 2 ) );
ny = 1.0f / sqrtf( ( float ) ( yp ) );

newData = ( float * ) malloc( sizeof( float ) * ( sizeX * sizeY * pp ) );

for( i = 0; i &lt; sizeY; i++ )
{
	for( j = 0; j &lt; sizeX; j++ )
	{
		pos1 = ( ( i ) *sizeX + j )*p;//去掉边界后的第i行第j列的block的的第一个属性值的索引值
		pos2 = ( ( i ) *sizeX + j )*pp;//newData关于第i行第j列的block的的第一个属性值的索引值
		k = 0;
		for( jj = 0; jj &lt; xp * 2; jj++ )//18分属性
		{
			val = 0;
			for( ii = 0; ii &lt; yp; ii++ )
			{
				val += map-&gt;map[pos1 + yp * xp + ii * xp * 2 + jj];//计算每个block的18分属性在四个方向的和
			}/*for(ii = 0; ii &lt; yp; ii++)*/
			newData[pos2 + k] = val * ny;
			k++;
		}/*for(jj = 0; jj &lt; xp * 2; jj++)*/
		for( jj = 0; jj &lt; xp; jj++ )//9分属性
		{
			val = 0;
			for( ii = 0; ii &lt; yp; ii++ )
			{
				val += map-&gt;map[pos1 + ii * xp + jj];
			}/*for(ii = 0; ii &lt; yp; ii++)*/
			newData[pos2 + k] = val * ny;
			k++;
		}/*for(jj = 0; jj &lt; xp; jj++)*/
		for( ii = 0; ii &lt; yp; ii++ )
		{
			val = 0;
			for( jj = 0; jj &lt; 2 * xp; jj++ )
			{
				val += map-&gt;map[pos1 + yp * xp + ii * xp * 2 + jj];//计算每个block的18分属性在一个方向上的和,
			}/*for(jj = 0; jj &lt; xp; jj++)*/
			newData[pos2 + k] = val * nx;
			k++;
		} /*for(ii = 0; ii &lt; yp; ii++)*/
	}/*for(j = 0; j &lt; sizeX; j++)*/
}/*for(i = 0; i &lt; sizeY; i++)*/
//swop data

map-&gt;numFeatures = pp;

free( map-&gt;map );

map-&gt;map = newData;

return LATENT_SVM_OK;

}

//modified from “lsvmc_routine.cpp”

int allocFeatureMapObject( CvLSVMFeatureMapCaskade **obj, const int sizeX,
const int sizeY, const int numFeatures )
{
int i;
( *obj ) = ( CvLSVMFeatureMapCaskade * ) malloc( sizeof( CvLSVMFeatureMapCaskade ) );
( *obj )->sizeX = sizeX;
( *obj )->sizeY = sizeY;
( *obj )->numFeatures = numFeatures;
( *obj )->map = ( float * ) malloc( sizeof( float ) *
( sizeX * sizeY * numFeatures ) );
for( i = 0; i < sizeX * sizeY * numFeatures; i++ )
{
( *obj )->map[i] = 0.0f;
}
return LATENT_SVM_OK;
}

int freeFeatureMapObject( CvLSVMFeatureMapCaskade **obj )
{
if( *obj == NULL ) return LATENT_SVM_MEM_NULL;
free( ( *obj )->map );
free( *obj );
( *obj ) = NULL;
return LATENT_SVM_OK;
}

kcftracker.cpp

#ifndef _KCFTRACKER_HEADERS
#include "kcftracker.hpp"
#include "ffttools.hpp"
#include "recttools.hpp"
#include "fhog.hpp"
#include "labdata.hpp"
#endif

// Constructor
/*
根据配置选项初始化一些参数
*/
KCFTracker::KCFTracker( bool hog, bool fixed_window, bool multiscale, bool lab )
{

// Parameters equal in all cases
lambda = 0.0001;	//regularization
padding = 2.5;		//horizontal area surrounding the target, relative to its size

//output_sigma_factor = 0.1;
output_sigma_factor = 0.125;	//bandwidth of gaussian target


if( hog )
{    
	// HOG
	// VOT
	interp_factor = 0.012;		// linear interpolation factor for adaptation
	sigma = 0.6;				//gaussian kernel bandwidth
	
	// TPAMI
	//interp_factor = 0.02;
	//sigma = 0.5; 
	cell_size = 4;				//HOG cell size
	_hogfeatures = true;

	if( lab )
	{
		interp_factor = 0.005;
		sigma = 0.4;
		//output_sigma_factor = 0.025;
		output_sigma_factor = 0.1;

		_labfeatures = true;
		_labCentroids = cv::Mat( nClusters, 3, CV_32FC1, &amp;data );
		cell_sizeQ = cell_size*cell_size;
	}
	else
	{
		_labfeatures = false;
	}
}
else
{   
	// RAW
	interp_factor = 0.075;
	sigma = 0.2;
	cell_size = 1;
	_hogfeatures = false;

	if( lab )
	{
		printf( "Lab features are only used with HOG features.\n" );
		_labfeatures = false;
	}
}


if( multiscale )
{ 
	// multiscale
	template_size = 96;
	//template_size = 100;
	
	scale_step = 1.05;
	scale_weight = 0.95;
	if( !fixed_window )
	{
		//printf("Multiscale does not support non-fixed window.\n");
		fixed_window = true;
	}
}
else if( fixed_window )
{  
	// fit correction without multiscale
	template_size = 96;
	//template_size = 100;
	
	scale_step = 1;
}
else
{
	template_size = 1;
	scale_step = 1;
}

}

/*****************************************************************************
*函数功能:初始化跟踪器,包括回归参数的计算,变量的初始化(Initialize tracker)
*函数参数:目标初始框的引用,初始帧、
*****************************************************************************/
void KCFTracker::init( const cv::Rect &roi, cv::Mat image )
{
_roi = roi; //_roi是基类Tracker的protected成员变量
assert( roi.width >= 0 && roi.height >= 0 );
_tmpl = getFeatures( image, 1 ); // 获取特征,在train里面每帧修改
_prob = createGaussianPeak( size_patch[0], size_patch[1] ); // 这个不修改了,只初始化一次 24 14
_alphaf = cv::Mat( size_patch[0], size_patch[1], CV_32FC2, float( 0 ) ); // 获取特征,在train里面每帧修改
//_num = cv::Mat(size_patch[0], size_patch[1], CV_32FC2, float(0));
//_den = cv::Mat(size_patch[0], size_patch[1], CV_32FC2, float(0));
train( _tmpl, 1.0 ); // train with initial frame
}

/*****************************************************************************
*函数功能:获取当前帧的目标位置以及尺度(Update position based on the new frame)
*函数参数:当前帧的整幅图像
*****************************************************************************/
cv::Rect KCFTracker::update( cv::Mat image )
{
if( _roi.x + _roi.width <= 0 ) _roi.x = -_roi.width + 1;//如果越界,就让框框保持在开始越界的地方
if( _roi.y + _roi.height <= 0 ) _roi.y = -_roi.height + 1;
if( _roi.x >= image.cols - 1 ) _roi.x = image.cols - 2;
if( _roi.y >= image.rows - 1 ) _roi.y = image.rows - 2;

//跟踪框中心
float cx = _roi.x + _roi.width / 2.0f;
float cy = _roi.y + _roi.height / 2.0f;


float peak_value;    // 尺度不变时检测峰值结果
cv::Point2f res = detect( _tmpl, getFeatures( image, 0, 1.0f ), peak_value );

// 略大尺度和略小尺度进行检测
if( scale_step != 1 )
{
	// Test at a smaller _scale  使用较小的尺度进行检测
	float new_peak_value;
	
	cv::Point2f new_res = detect( _tmpl, getFeatures( image, 0, 1.0f / scale_step ), new_peak_value );

	// 做减益还比同尺度大就认为是目标 
	if( scale_weight * new_peak_value &gt; peak_value )
	{
		res = new_res;
		peak_value = new_peak_value;
		_scale /= scale_step;
		_roi.width /= scale_step;
		_roi.height /= scale_step;
	}

	// Test at a bigger _scale 使用较大的尺度进行检测
	new_res = detect( _tmpl, getFeatures( image, 0, scale_step ), new_peak_value );

	if( scale_weight * new_peak_value &gt; peak_value )
	{
		res = new_res;
		peak_value = new_peak_value;
		_scale *= scale_step;
		_roi.width *= scale_step;
		_roi.height *= scale_step;
	}
}

// Adjust by cell size and _scale
_roi.x = cx - _roi.width / 2.0f + ( ( float ) res.x * cell_size * _scale );
_roi.y = cy - _roi.height / 2.0f + ( ( float ) res.y * cell_size * _scale );

if( _roi.x &gt;= image.cols - 1 ) _roi.x = image.cols - 1;
if( _roi.y &gt;= image.rows - 1 ) _roi.y = image.rows - 1;
if( _roi.x + _roi.width &lt;= 0 ) _roi.x = -_roi.width + 2;
if( _roi.y + _roi.height &lt;= 0 ) _roi.y = -_roi.height + 2;

assert( _roi.width &gt;= 0 &amp;&amp; _roi.height &gt;= 0 );
cv::Mat x = getFeatures( image, 0 );
train( x, interp_factor );

return _roi;

}

/*****************************************************************************
*函数功能:根据上一帧结果计算当前帧的目标位置(Detect object in the current frame)
*函数参数:之前训练(初始化)的结果,当前的特征图,当前最高得分(引用)
*****************************************************************************/
cv::Point2f KCFTracker::detect( cv::Mat z, cv::Mat x, float &peak_value )
{
using namespace FFTTools;

// 做变换得到计算结果res
cv::Mat k = gaussianCorrelation( x, z );			// 计算x和z之间的高斯相关核(公式)
cv::Mat res = ( real( fftd( complexMultiplication( _alphaf, fftd( k ) ), true ) ) );  // 计算目标得分(公式)

// minMaxLoc only accepts doubles for the peak, and integer points for the coordinates
// 使用opencv的minMaxLoc来定位峰值坐标位置
cv::Point2i pi;
double pv;
cv::minMaxLoc( res, NULL, &amp;pv, NULL, &amp;pi );
peak_value = ( float ) pv;

// subpixel peak estimation, coordinates will be non-integer
// 子像素峰值检测,坐标是非整形的
cv::Point2f p( ( float ) pi.x, ( float ) pi.y );

if( pi.x &gt; 0 &amp;&amp; pi.x &lt; res.cols - 1 )
{
	p.x += subPixelPeak( res.at&lt;float&gt;( pi.y, pi.x - 1 ), peak_value, res.at&lt;float&gt;( pi.y, pi.x + 1 ) );
}

if( pi.y &gt; 0 &amp;&amp; pi.y &lt; res.rows - 1 )
{
	p.y += subPixelPeak( res.at&lt;float&gt;( pi.y - 1, pi.x ), peak_value, res.at&lt;float&gt;( pi.y + 1, pi.x ) );
}

p.x -= ( res.cols ) / 2;
p.y -= ( res.rows ) / 2;

return p;

}

/*****************************************************************************
*函数功能:根据每一帧的结果训练样本并更新模板(train tracker with a single image)
*函数参数:新的目标图像,训练因子train_interp_factor是interp_factor
*****************************************************************************/
void KCFTracker::train( cv::Mat x, float train_interp_factor )
{
using namespace FFTTools;

cv::Mat k = gaussianCorrelation( x, x );
cv::Mat alphaf = complexDivision( _prob, ( fftd( k ) + lambda ) );  //计算岭回归系数(公式)

// 更新模板的特征
_tmpl = ( 1 - train_interp_factor ) * _tmpl + ( train_interp_factor ) * x;		// 公式

// 更新岭回归系数的值
_alphaf = ( 1 - train_interp_factor ) * _alphaf + ( train_interp_factor ) * alphaf;    // 公式


/*cv::Mat kf = fftd(gaussianCorrelation(x, x));
cv::Mat num = complexMultiplication(kf, _prob);
cv::Mat den = complexMultiplication(kf, kf + lambda);

_tmpl = (1 - train_interp_factor) * _tmpl + (train_interp_factor) * x;
_num = (1 - train_interp_factor) * _num + (train_interp_factor) * num;
_den = (1 - train_interp_factor) * _den + (train_interp_factor) * den;

_alphaf = complexDivision(_num, _den);*/

}

/*****************************************************************************
*函数功能:使用带宽SIGMA计算高斯卷积核以用于所有图像X和Y之间的相对位移
必须都是MxN大小。二者必须都是周期的(即,通过一个cos窗口进行预处理)
Evaluates a Gaussian kernel with bandwidth SIGMA for all relative shifts between input images X and Y, which must both be MxN. They must also be periodic (ie., pre-processed with a cosine window)
*函数参数:高斯核的两个参数
*****************************************************************************/
cv::Mat KCFTracker::gaussianCorrelation( cv::Mat x1, cv::Mat x2 )
{
using namespace FFTTools;
cv::Mat c = cv::Mat( cv::Size( size_patch[1], size_patch[0] ), CV_32F, cv::Scalar( 0 ) );

// HOG features
if( _hogfeatures )
{
	cv::Mat caux;
	cv::Mat x1aux;
	cv::Mat x2aux;
	for( int i = 0; i &lt; size_patch[2]; i++ )
	{
		x1aux = x1.row( i );								// Procedure do deal with cv::Mat multichannel bug
		x1aux = x1aux.reshape( 1, size_patch[0] );			// 将第i个属性排列成原来cell的排列形式
		x2aux = x2.row( i ).reshape( 1, size_patch[0] );

		// 两个傅立叶频谱的每个元素的乘法 相乘-频谱
		// 输入数组1、输入数组2、输出数组(和输入数组有相同的类型和大小)
		cv::mulSpectrums( fftd( x1aux ), fftd( x2aux ), caux, 0, true );     // 核相关性公式
		caux = fftd( caux, true );
		rearrange( caux );
		caux.convertTo( caux, CV_32F );
		c = c + real( caux );
	}
}
else     // Gray features
{
	cv::mulSpectrums( fftd( x1 ), fftd( x2 ), c, 0, true );
	c = fftd( c, true );
	rearrange( c );
	c = real( c );
}
cv::Mat d;
cv::Mat testx1 = x1.mul( x1 );
cv::Mat testx2 = x2.mul( x2 );
cv::Scalar ax1 = cv::sum( testx1 );
cv::Scalar ax2 = cv::sum( testx2 );
cv::max( ( ( cv::sum( x1.mul( x1 ) )[0] + cv::sum( x2.mul( x2 ) )[0] ) - 2. * c ) / ( size_patch[0] * size_patch[1] * size_patch[2] ), 0, d );

cv::Mat k;
cv::exp( ( -d / ( sigma * sigma ) ), k );
return k;

}

/*****************************************************************************
*函数功能:创建高斯峰函数,仅在第一帧时被执行
*Create Gaussian Peak. Function called only in the first frame
*函数参数:二维高斯峰的X、Y的大小
*****************************************************************************/
cv::Mat KCFTracker::createGaussianPeak( int sizey, int sizex )
{
cv::Mat_<float> res( sizey, sizex );

int syh = ( sizey ) / 2;
int sxh = ( sizex ) / 2;

float output_sigma = std::sqrt( ( float ) sizex * sizey ) / padding * output_sigma_factor;//?
float mult = -0.5 / ( output_sigma * output_sigma );//?

for( int i = 0; i &lt; sizey; i++ )
{
	for( int j = 0; j &lt; sizex; j++ )
	{
		int ih = i - syh;
		int jh = j - sxh;
		res( i, j ) = std::exp( mult * ( float ) ( ih * ih + jh * jh ) );
	}
}		

return FFTTools::fftd( res );

}

/*****************************************************************************
*函数功能:提取目标窗口的特征(Obtain sub-window from image, with replication-padding and extract features)
*函数参数:图像,是否使用汉宁窗,尺度调整因子
*****************************************************************************/
cv::Mat KCFTracker::getFeatures( const cv::Mat & image, bool inithann, float scale_adjust )
{
//步骤:
//1.根据给定的框框找到合适的框框
//2.提取HOG特征
//3.对特征进行归一化和截断
//4.对特征进行降维
//5.获取Lab特征,并将结果与hog特征进行连接
//6.创建一个常数阵,对所有特征根据cell的位置进行加权?

cv::Rect extracted_roi;

//center point of ROI
float cx = _roi.x + _roi.width / 2;
float cy = _roi.y + _roi.height / 2;

// 初始化hanning窗, 其实只执行一次,只在第一帧的时候inithann=1
if( inithann )
{
	int padded_w = _roi.width * padding;
	int padded_h = _roi.height * padding;

	if( template_size &gt; 1 )                  // template_size=96
	{  
		// Fit largest dimension to the given template size
		// 按照长宽比例修改_tmpl长宽大小,保证比较大的边为template_size大小96
		if( padded_w &gt;= padded_h )
		{
			//fit to width
			_scale = padded_w / ( float ) template_size;
		}
		else
		{
			_scale = padded_h / ( float ) template_size;
		}				
		
		_tmpl_sz.width = padded_w / _scale;
		_tmpl_sz.height = padded_h / _scale;
	}
	else
	{  
		//No template size given, use ROI size
		_tmpl_sz.width = padded_w;
		_tmpl_sz.height = padded_h;
		_scale = 1;
		// original code from paper:
		/*if (sqrt(padded_w * padded_h) &gt;= 100) {   //Normal size
			_tmpl_sz.width = padded_w;
			_tmpl_sz.height = padded_h;
			_scale = 1;
			}
			else {   //ROI is too big, track at half size
			_tmpl_sz.width = padded_w / 2;
			_tmpl_sz.height = padded_h / 2;
			_scale = 2;
			}*/
	}

	// 设置_tmpl_sz的长宽:向上取原来长宽的最小2*cell_size倍  
	// 其中,较大边长为104 
	if( _hogfeatures )
	{
		// Round to cell size and also make it even
		_tmpl_sz.width = ( ( ( int ) ( _tmpl_sz.width / ( 2 * cell_size ) ) ) * 2 * cell_size ) + cell_size * 2;
		_tmpl_sz.height = ( ( ( int ) ( _tmpl_sz.height / ( 2 * cell_size ) ) ) * 2 * cell_size ) + cell_size * 2;
	}
	else
	{  
		// Make number of pixels even (helps with some logic involving half-dimensions)
		_tmpl_sz.width = ( _tmpl_sz.width / 2 ) * 2;
		_tmpl_sz.height = ( _tmpl_sz.height / 2 ) * 2;
	}
}
// 以上都是调整_tmpl_sz的大小为了各种适应

// 检测区域大小
extracted_roi.width = scale_adjust * _scale * _tmpl_sz.width;
extracted_roi.height = scale_adjust * _scale * _tmpl_sz.height;

// center roi with new size 检测区域的左上角坐标 
extracted_roi.x = cx - extracted_roi.width / 2;
extracted_roi.y = cy - extracted_roi.height / 2;

// 提取目标区域像素,超边界则做填充
cv::Mat FeaturesMap;
cv::Mat z = RectTools::subwindow( image, extracted_roi, cv::BORDER_REPLICATE );//检验extracted_roi似乎否在image范围内,若有超出部分,通过边界补全

// 按照比例缩小边界大小
if( z.cols != _tmpl_sz.width || z.rows != _tmpl_sz.height )
{
	cv::resize( z, z, _tmpl_sz );
}

// HOG features 提取HOG特征点
if( _hogfeatures )
{
	IplImage z_ipl = z;                             // 之前的图像类
	CvLSVMFeatureMapCaskade *map;					// 申请指针
	getFeatureMaps( &amp;z_ipl, cell_size, &amp;map );		// 对map赋值,获取hog特征map为sizeX*sizeY*3*NUM_SECTOR  
	normalizeAndTruncate( map, 0.2f );				// 对hog特征进行归一化和截断;结果由map指向,大小sizeX*sizeY*3*NUM_SECTOR*4,但是此时的sizeX和sizezY均比之前少2.
	PCAFeatureMaps( map );							// 对HOG特征进行降维
	size_patch[0] = map-&gt;sizeY;						// HOG特征的sizeY
	size_patch[1] = map-&gt;sizeX;						// HOG特征的sizeX
	size_patch[2] = map-&gt;numFeatures;				// HOG特征的特征个数

	FeaturesMap = cv::Mat( cv::Size( map-&gt;numFeatures, map-&gt;sizeX*map-&gt;sizeY ), CV_32F, map-&gt;map );  // Procedure do deal with cv::Mat multichannel bug
	FeaturesMap = FeaturesMap.t( );				    // 288*31
	freeFeatureMapObject( &amp;map );

	// Lab features
	// 我测试结果,带有Lab特征在一些跟踪环节效果并不好
	if( _labfeatures )
	{
		cv::Mat imgLab;
		cvtColor( z, imgLab, CV_BGR2Lab );
		unsigned char *input = ( unsigned char* ) ( imgLab.data );

		// Sparse output vector
		cv::Mat outputLab = cv::Mat( _labCentroids.rows, size_patch[0] * size_patch[1], CV_32F, float( 0 ) );//每一列是一个cell的nClusters个属性

		int cntCell = 0;//代表的是除边界以外的cell的索引号
		// Iterate through each cell
		for( int cY = cell_size; cY &lt; z.rows - cell_size; cY += cell_size )
		{
			for( int cX = cell_size; cX &lt; z.cols - cell_size; cX += cell_size )
			{//遍历除边界以外的cell,第cy行第cx列的cell
				// Iterate through each pixel of cell (cX,cY)
				//对每个cell的每个像素的lab值进行根据_labCentroids进行分类,分类标准:欧氏距离的平方
				for( int y = cY; y &lt; cY + cell_size; ++y )
				{
					for( int x = cX; x &lt; cX + cell_size; ++x )
					{//遍历cell中的每一个像素,第y行第x列的像素
						// Lab components for each pixel
						float l = ( float ) input[( z.cols * y + x ) * 3];//三个通道,分别代表LAB空间的三个值
						float a = ( float ) input[( z.cols * y + x ) * 3 + 1];
						float b = ( float ) input[( z.cols * y + x ) * 3 + 2];

						// Iterate trough each centroid(质心,矩心)
						float minDist = FLT_MAX;
						int minIdx = 0;
						float *inputCentroid = ( float* ) ( _labCentroids.data );
						for( int k = 0; k &lt; _labCentroids.rows; ++k )
						{
							float dist = ( ( l - inputCentroid[3 * k] ) * ( l - inputCentroid[3 * k] ) )
								+ ( ( a - inputCentroid[3 * k + 1] ) * ( a - inputCentroid[3 * k + 1] ) )
								+ ( ( b - inputCentroid[3 * k + 2] ) * ( b - inputCentroid[3 * k + 2] ) );//好像是求的lab和某一个特定lab的距离
							if( dist &lt; minDist )
							{
								minDist = dist;
								minIdx = k;
							}
						}
						// Store result at output
						outputLab.at&lt;float&gt;( minIdx, cntCell ) += 1.0 / cell_sizeQ;
						//((float*) outputLab.data)[minIdx * (size_patch[0]*size_patch[1]) + cntCell] += 1.0 / cell_sizeQ; 
					}
				}
				cntCell++;
			}
		}
		// Update size_patch[2] and add features to FeaturesMap
		size_patch[2] += _labCentroids.rows;
		FeaturesMap.push_back( outputLab );//将根据lab空间计算得到的结果和通过hog特征计算的结果进行合并
	}
}
else           //if not hog
{
	
	FeaturesMap = RectTools::getGrayImage( z );
	FeaturesMap -= ( float ) 0.5;					// In Paper;
	size_patch[0] = z.rows;
	size_patch[1] = z.cols;
	size_patch[2] = 1;
}

if( inithann )
{
	createHanningMats( );							// 创建了一个和FeatureMap大小相关的常数Mat(sizeX*sizezY)*size_patch[2]
}
FeaturesMap = hann.mul( FeaturesMap );				// 点乘
return FeaturesMap;

}

/*****************************************************************************
*函数功能:初始化cosine window,仅在第一帧调用(Initialize Hanning window. Function called only in the first frame.)
*函数参数:无
*****************************************************************************/
void KCFTracker::createHanningMats( )
{
cv::Mat hann1t = cv::Mat( cv::Size( size_patch[1], 1 ), CV_32F, cv::Scalar( 0 ) );
cv::Mat hann2t = cv::Mat( cv::Size( 1, size_patch[0] ), CV_32F, cv::Scalar( 0 ) );

for( int i = 0; i &lt; hann1t.cols; i++ )
	hann1t.at&lt;float &gt;( 0, i ) = 0.5 * ( 1 - std::cos( 2 * 3.14159265358979323846 * i / ( hann1t.cols - 1 ) ) );
for( int i = 0; i &lt; hann2t.rows; i++ )
	hann2t.at&lt;float &gt;( i, 0 ) = 0.5 * ( 1 - std::cos( 2 * 3.14159265358979323846 * i / ( hann2t.rows - 1 ) ) );

cv::Mat hann2d = hann2t * hann1t;
// HOG features
if( _hogfeatures )
{
	cv::Mat hann1d = hann2d.reshape( 1, 1 ); // Procedure do deal with cv::Mat multichannel bug

	hann = cv::Mat( cv::Size( size_patch[0] * size_patch[1], size_patch[2] ), CV_32F, cv::Scalar( 0 ) );
	for( int i = 0; i &lt; size_patch[2]; i++ )
	{
		for( int j = 0; j &lt; size_patch[0] * size_patch[1]; j++ )
		{
			hann.at&lt;float&gt;( i, j ) = hann1d.at&lt;float&gt;( 0, j );
		}
	}
}
// Gray features
else
{
	hann = hann2d;
}

}

/*****************************************************************************
*函数功能:对目标的位置插值,提高精度,计算一维亚像素峰值
*使用幅值做差来定位峰值的位置,返回的是需要改变的偏移量大小
*Calculate sub-pixel peak for one dimension
*函数参数:无
*****************************************************************************/
float KCFTracker::subPixelPeak( float left, float center, float right )
{
float divisor = 2 * center - right - left;

if( divisor == 0 )
	return 0;

return 0.5 * ( right - left ) / divisor;

}


kcftracker.hpp

#pragma once

#include “tracker.h”

#ifndef OPENCV_KCFTRACKER_HPP
#define OPENCV_KCFTRACKER_HPP
#endif

class KCFTracker : public Tracker
{
public:
// Constructor
// Constructor
// 构造KCF跟踪器的类
KCFTracker( bool hog = true, // 使用hog特征
bool fixed_window = true, // 使用固定窗口大小
bool multiscale = true, // 使用多尺度
bool lab = true ); // 使用lab色空间特征

// Initialize tracker 
virtual void init(const cv::Rect &amp;roi, cv::Mat image);

// Update position based on the new frame
virtual cv::Rect update(cv::Mat image);

float interp_factor; // linear interpolation factor for adaptation 自适应的线性插值因子,会因为hog,lab的选择而变化
float sigma;         // gaussian kernel bandwidth 高斯(卷积)核带宽,会因为hog,lab的选择而变化
float lambda;		 // regularization 正则化 0.0001
int cell_size;		 // HOG cell size  HOG特征中元胞的大小 4
int cell_sizeQ;		 // cell size^2, to avoid repeated operations 元胞数组内像素数目,16,为了计算省事
float padding;		 // extra area surrounding the target  目标扩展区域,2.5
float output_sigma_factor; // bandwidth of gaussian target  高斯目标的带宽,不同hog,lab会不同
int template_size;		   // template size 模板大小,在计算_tmpl_sz时,较大变成被归一成96,而较小边长按比例缩小
float scale_step;		   // scale step for multi-scale estimation 多尺度估计的尺度步长
float scale_weight;		   // to downweight detection scores of other scales for added stability 为了增加其他尺度检测时的稳定性,给检测结果峰值做一定衰减,为原来的0.95倍

protected:
// Detect object in the current frame.
cv::Point2f detect(cv::Mat z, cv::Mat x, float &peak_value);

// train tracker with a single image
void train(cv::Mat x, float train_interp_factor);

// Evaluates a Gaussian kernel with bandwidth SIGMA for all relative shifts between input images X and Y, which must both be MxN. They must    also be periodic (ie., pre-processed with a cosine window).
cv::Mat gaussianCorrelation(cv::Mat x1, cv::Mat x2);

// Create Gaussian Peak. Function called only in the first frame.
cv::Mat createGaussianPeak(int sizey, int sizex);

// Obtain sub-window from image, with replication-padding and extract features
cv::Mat getFeatures(const cv::Mat &amp; image, bool inithann, float scale_adjust = 1.0f);

// Initialize Hanning window. Function called only in the first frame.
void createHanningMats();

// Calculate sub-pixel peak for one dimension
float subPixelPeak(float left, float center, float right);

cv::Mat _alphaf;            // 初始化/训练结果alphaf,用于检测部分中结果的计算  
cv::Mat _prob;              // 初始化结果prob,不再更改,用于训练  
cv::Mat _tmpl;              // 初始化/训练的结果,用于detect的z  
cv::Mat _num;               // 貌似都被注释掉了  
cv::Mat _den;               // 貌似都被注释掉了  
cv::Mat _labCentroids;      // lab质心数组

private:
int size_patch[3]; // hog特征的sizeY,sizeX,numFeatures
cv::Mat hann; // createHanningMats()的计算结果
cv::Size _tmpl_sz; // hog元胞对应的数组大小
float _scale; // 修正成_tmpl_sz后的尺度大小
int _gaussian_size; // 未引用???
bool _hogfeatures; // hog标志位
bool _labfeatures; // lab标志位
};



  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
## Tracking with Kernelized Correlation Filters Code author : Tomas Vojir ________________ This is a C++ reimplementation of algorithm presented in "High-Speed Tracking with Kernelized Correlation Filters" paper. For more info and implementation in other languages visit the [autor's webpage!](http://home.isr.uc.pt/~henriques/circulant/). It is extended by a scale estimation (use several *7* different scales steps) and by a RGB (channels) and Color Names [2] features. Data for Color Names features were obtained from [SAMF tracker](https://github.com/ihpdep/samf). It is free for research use. If you find it useful or use it in your research, please acknowledge my git repository and cite the original paper [1]. The code depends on OpenCV 2.4+ library and is build via cmake toolchain. _________________ Quick start guide for linux: open terminal in the directory with the code $ mkdir build; cd build; cmake .. ; make This code compiles into binary **kcf_vot** ./kcf_vot - using VOT 2014 methodology (http://www.votchallenge.net/) - INPUT : expecting two files, images.txt (list of sequence images with absolute path) and region.txt with initial bounding box in the first frame in format "top_left_x, top_left_y, width, height" or four corner points listed clockwise starting from bottom left corner. - OUTPUT : output.txt containing the bounding boxes in the format "top_left_x, top_left_y, width, height" ./kcf_trax - using VOT 2014+ trax protocol (http://www.votchallenge.net/) - require [trax](https://github.com/votchallenge/trax) library to be compiled with opencv support and installed. See trax instruction for compiling and installing. ___________ Performance | | **VOT2016 - baseline EAO** | **VOT2016 - unsupervised EAO** | [**TV77**](http://cmp.felk.cvut.cz/~vojirtom/dataset/index.html) Avg. Recall | |:---------------|:--------------:|:------------------:|:----------------:| | kcf |0.1530 | 0.3859 | 51% | | skcf |0.1661 | 0.4155 | 56% | | skcf-cn |0.178 | 0.4136 | 58% | | kcf-master |**0.1994** | **0.4376** | **63%** | __________ References [1] João F. Henriques, Rui Caseiro, Pedro Martins, Jorge Batista, “High-Speed Tracking with Kernelized Correlation Filters“, IEEE Transactions on Pattern Analysis and Machine Intelligence, 2015 [2] J. van de Weijer, C. Schmid, J. J. Verbeek, and D. Larlus. "Learning color names for real-world applications." TIP, 18(7):1512–1524, 2009. _____________________________________ Copyright (c) 2014, Tomáš Vojíř Permission to use, copy, modify, and distribute this software for research purposes is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. __________________ Additional Library NOTE: The following files are part of Piotr's Toolbox, and were modified for usage with c++ src/piotr_fhog/gradientMex.cpp src/piotr_fhog/sse.hpp src/piotr_fhog/wrappers.hpp You are encouraged to get the [full version of this library here.](http://vision.ucsd.edu/~pdollar/toolbox/doc/index.html) ______________________________________________________________________________ Copyright (c) 2012, Piotr Dollar All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project.

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值