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标志位
};



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

猜你喜欢

转载自blog.csdn.net/zjc910997316/article/details/82902682
KCF