fhog在KCF和DSST中都用到了,当时看KCF的时候做了总结,放在这里。
传统hog特征提取。
关于HOG特征(梯度统计直方图)简单介绍一下,首先是对原图进行灰度化(hog统计的是梯度信息,色彩几乎没有贡献),再进行gamma压缩和归一化(减轻光照影响)。然后进行统计,首先是统计每个cell(代码里用的是4_4)里的梯度(包括大小和方向,大小用来加权方向)统计直方图,再把几个cell合并成一个block,作为这个block的hog的特征,并对这个特征进行归一化处理,可以进一步减轻光照影响。
合并成block的时候有两种方式,一种overlap一种non-overlap的,就是分块之间是否有重叠,各有优缺点,没有重叠速度快,但是可能由于连续的图像没有分到一个block里降低特征的描述能力,有重叠的就可以很好的解决这个问题,但是会带来运算开支加大。
如图,是一个11_9的图像,我们把橙色的3_3当作一个cell,统计其中的梯度方向并用幅值加权,假设我们分为9个方向,这样的话每个cell中可以得到9个特征,蓝色(2_2个cell)作为一个block,则每个block就会得到4_9=36个特征,这些特征是按照顺序串联起来的(保证空间特征),如果是overlap的话(边界不够一个block的舍弃),那么行方向可以有2个block,列方向也是有2个block,这样就会得到2_2_36=144维的一个特征,可以发现特征的维度还是很大的。
那么hog特征怎么用到CSK的框架中呢?直接用显然是不可以的,因为很难把一个一维特征和pos信息联系起来,而且对一个hog特征进行循环移位也是没有意义的。
FHOG
作者在传统的hog特征上进行了一些改进,这种改进的思路提供了一种把高维特征融入到相关滤波框架中的一种方法:这种方法在论文中作者基本没提,只说了参考论文:Object Detection with Discriminatively Trained Part Based Models,论文的第六部分详细说明了hog特征和fhog特征的提取方法,对于传统的hog特征还是做了一些改进。
下面说明这种方法:
1.建立像素级特征映射
首先是计算每个像素的梯度大小和方向,分别记为:然后把每个像素的梯度方向离散到p的值中的一个,可以使用对方向敏感 B1(0-360度)也可以使用对方向不敏感 B2(0-180度)。
下面使用B表示B1和B2。
我们定义一个像素级的特征映射,指定每个像素梯度幅值的稀疏直方图,设b的取值为: 则 (x,y)处的特征向量为:
其他情况都为0.
这样的描述看起来很高级,实际上说明的问题很简单,和传统hog统计是基本一致的,我们可以认为F是有p个方向通道的映射,对于每个像素来说,通过其方向算出来的B,可以用来计算它在F的哪个方向有映射,而这个映射的带下使用其幅值来加权的。
2. 空间聚合。
设F是一个w*h大小图像的像素级特征映射,K>0是我们定义的cell的大小,通过像素级特征映射的空间聚合来得到基于cell的特征映射,也就是每一个cell一个特征,特征向量记为: 其中:这种形式可以使特征具有对微小形变的不变性,并可以减少特征映射尺寸。
最简单的方法是将像素 (x,y)映射到一个cell中,定义这个cell的特征为整个cell内所有像素特征的均值或和(都是一样的,后期还要进行归一化处理),这是一种很暴力的方法,简单也有效,如果要进一步提高hog特征的描述性能。作者还提供了一种方法,利用三线插值进行处理,这种处理也是合理的。能进一步较小混叠效应,关于插值处理的具体理论和方法见:hog之三线插值。通过插值可以使得每个像素对其周围的四个cell的特征向量产生贡献。
3.归一化和截断。
梯度对偏置改变具有不变性,这种不变性是通过归一化获得的,这篇论文里作者定义了四种不同的归一化因子。将这些因子定义为 : 其中 :归一化因子定义为:
每个因子都包含四个cell的能量,这里用的是二范数。
上面这个式子表示了这四种不同的归一化方式,分别是用当前这个cell周围和包括自己的cell能量来进行归一化,下面用一个示意图来表示:
如图1-9分别是9个cell,考虑cell5,27式所表达的四个归一化因子分别是:cell 1,2,4,5的能量和,cell2,3,5,6的能量和等。也就是说对于每个cell来说分别用包括自身在内的9个cell分别组合来归一化cell的特征,然后再截断,假设我们选择角度区间为9个,那么对于每个cell来说,这样的操作会获得36维的一个特征,这就是相关滤波框架中使用的hog特征,在论文中,作者还提供了一种特征选项,称之为Fhog,下面介绍。
4.FHOG PCA降维
在论文的6.2部分,作者着重介绍了fhog的来源和取法。
作者从大量各种分辨率的图片中收集了很多36维特征(按照之前的定义),并且在这些特征上进行了PCA分析,发现了了一个现象:由前11个主特征向量定义的线性子空间基本包含了hog特征的所有信息。并且用降维之后的特征在他们的任务(目标检测)中取得了和用36维特征一样的结果。
上图显示了36维hog特征的主成分分析,每个特征向量显示为4*9的矩阵,这样也是合理的,每一列对应梯度直方图的一个bin,特征值在特征向量的上方。注意到,前十一个特征向量的行或者列近似为一个定值。所以说,主特征向量所依赖的线性子空间可以由沿其矩阵表达的某一行或者某一列稀疏向量表示。
这样我们可以定义一个13维特征,其中的元素是36为特征与每个u_k和v_k的点积。作者通过实验发现:36维特征PCA降维之后的11维特征和我们刚才这样定义得到的13维特征,在实验任务中可以取得相同的表现,而且13维特征要比PCA计算11维特征简单的多(只需36维特征求每行和及每列和)。而且13为特征有一个比较简单的解释:9个方向特征以及反映cell周围区域能量的四个特征。
前面谈到了对方向不敏感的bin划分和敏感的bin划分,作者在最后提出了一种结合这两种方式的划分方式:分别对原图进行对方向敏感和不敏感的像素级特征映射(这样会获得9+18维特征向量),然后再利用式26和27进行归一化和截断处理,这样会获得一个4*(18+9)=108维的特征向量,如果用这么大的特征维数显然是复杂的,于是我们和上面36维的处理一样,对这些进行投影和点积处理。
最终得到的是一个27+4=31维的向量,其中包括:27个在不同归一化因子上的累加和(列和)以及4个在不同方向上的累加和(行和)。27维中包含了27个bin通道,其中18个对方向敏感,9个对方向不敏感,4维分别捕获了当前cell周围4个cell组成的梯度能量。下图形象描述了这一个过程:
至此,hog的两个改进版本介绍完毕。所有的精华都浓缩到这张图里。可惜我是写到这里猜找到的这张图,看论文看了好久才完全看懂这里。
5.hog特征融合入相关滤波之中
剩下的东西就简单很多了,在2中我们获得了图像的hog特征的cell级映射,无论是31维的或者是36维的,在下面的处理都是一样的了。无论是在训练或者检测,我们都用获得的hog特征去替代CSK中的灰度特征。简单的叠加肯定是不行的了,完全失去了统计hog特征的意义。
无论是训练还是检测都用到核相关矩阵,所以hog特征的融合主要是在这个过程中进行的。
我们把特征记为X[36],Y[36],是一个36维的容器,每个维度都是mn的矩阵。
① 首先分别对每个维度进行傅里叶变换,得到xf[36]和yf[36].
② xx的计算:计算xf在每一维的二范数除以(mn)。然后累加起来,就是xx。yy也是一样,这一步得到的都是一个实数。
③ xy的计算:计算xf[i]和yf[i]的共轭在频域的点积(element-wise),这样得到的是36个mn的复数矩阵,分别对每个矩阵都进行傅里叶逆变换得到xy[36],是36个mn的实数矩阵,分别也要除以(mn),然后把36个矩阵对应点求和得到一个矩阵记作xy,是一个mn的实数矩阵。
上面两个除以的m*n都是在处理公式中的numel(x).即总的像素点数。
可能看这个代码会更好理解一些:
cv::Mat KCF::GaussianCorrelation(std::vector<cv::Mat> xf, std::vector<cv::Mat> yf) {
int N = xf[0].size().area(); //这就是一个面积,也就是总的像素数
double xx = 0, yy = 0;
std::vector<cv::Mat> xyf_vector(xf.size());
cv::Mat xy(xf[0].size(), CV_32FC1, Scalar(0.0)), xyf, xy_temp;
for (unsigned int i = 0; i < xf.size(); ++i) //特征维数
{
xx += cv::norm(xf[i]) * cv::norm(xf[i]) / N; //这里算的是二范数,是一个double。并除以N
yy += cv::norm(yf[i]) * cv::norm(yf[i]) / N;
cv::mulSpectrums(xf[i], yf[i], xyf, 0, true); //傅里叶域点乘
cv::idft(xyf, xy_temp, cv::DFT_SCALE | cv::DFT_REAL_OUTPUT); // Applying IDFT,这里也除以N了,DFT_SCALE就是标志
xy += xy_temp;
} //把所有层的特征都加起来,实际上是在复数域加起来
float numel_xf = N * xf.size();
cv::Mat k, kf;
exp((-1 / (kernel_sigma_ * kernel_sigma_)) * max(0.0, (xx + yy - 2 * xy) / numel_xf), k);
//计算核相关矩阵
k.convertTo(k, CV_32FC1);
cv::dft(k, kf, DFT_COMPLEX_OUTPUT); //转换到频域
return kf;
}
这样就得到了核相关矩阵,剩余的方法和CSK中的就基本一致了,还有一个要处理的地方就是我们得到的图像hog特征的大小和原图像是成比例关系的(比例因子为cell的大小),所以在最后得到响应的位置要进一步处理。
参考:
- Object Detection with Discriminatively Trained Part Based Models ,这篇论文第六部分详述了hog及fhog。
- http://blog.csdn.net/li_dongxuan/article/details/70667137?locationNum=5&fps=1,这片博客在宏观上回答了KCF的几个关键问题。
- http://www.robots.ox.ac.uk/~joao/publications/henriques_tpami2015.pdf,原文。
- code 我加了中文注释和视频接口以及鼠标选框之后的代码,c++版本。
网友评论