图中:红色区域表示图像,绿色区域表示winSize,蓝色区域表示block,黄色区域表示cell,一般性的一个block中含有4个cell,其中cell是最小的单元,用来统计cell中梯度方向的直方图(如方向bin为9,具体方向的统计可以根据自己需要进行修改),图中给出了两组箭头,分别对应block和winSize,表示其可以进行左右和上下平移,其中步长一个维单个cell的大小,或者说winSize平移表示外循环,winSize平移表示内循环。对于小的图像块,例如20*20,如果选择的cell太小的话,很难描述局部的方向统计特性,如果cell选择太大,那么blcok也会变大,则产生的维度较小,因此,需要根据实际的需要进行参数的调节。
2. Hog描述子个数计算公式
其中9表示在一个cell中统计9个bin,16*16表示block的大小,8*8表示cell的大小,winSize 图像的大小。
例如:当图像的大小大于winSize的图像大小时,采用下面的计算方式:
首先计算出一根winSize可以产生多少维的特征,然后在看看图像大小能容纳多少个winSize,故计算公式如下:
我们可以通过下面的代码验证:
#include "stdafx.h"
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int _tmain(int argc, _TCHAR* argv[])
{
Mat img=imread("lena.jpg",0);
int w=img.cols;
int h=img.rows;
/*HOGDescriptor的默认构造函数
HOGDescriptor() : winSize(64,128), blockSize(16,16), blockStride(8,8),
cellSize(8,8), nbins(9), derivAperture(1), winSigma(-1),
histogramNormType(HOGDescriptor::L2Hys), L2HysThreshold(0.2), gammaCorrection(true),
nlevels(HOGDescriptor::DEFAULT_NLEVELS)
{}*/
HOGDescriptor *hog=new HOGDescriptor(Size(64,128),Size(16,16),Size(8,8),Size(8,8),9);
cout<<"图像的宽和高:"<<img.cols<<" "<<img.rows<<endl;
vector<float>descriptors;//结果数组
hog->compute(img, descriptors);
printf("descriptors.size():%d\n",descriptors.size());
int siz=hog->getDescriptorSize();
cout<<"OpenCV的getDescriptorSize:"<<siz<<endl;
float rat=descriptors.size()/siz;
cout<<"descriptors.size()/getDescriptorSize:"<<rat<<endl;
cout<<"sqrt(rat):"<<sqrt(rat)<<endl;
cout<<"图像大小可以容纳winSize多少个:"<<((img.cols-64)/8+1)*((img.rows-128)/8+1)<<endl;;
}
OpenCV函数中有一个Assert语句:
Assert((winSize.width-blockSize.width)%blockStride.width==0 &&(winSize.height-blockSize.height)%blockStride.height==0)
因此,我们输入的参数必须满足上面的要求。
因此对于小的块的图像中Hog特征,我们需要进行参数的调节,例如图像大小为20*20,那么我们选中winSize=[20 20],blockSize一般为blockStride(一般为一个cell的大小)的4倍,那么我们选择blockSize=[16 16],blockStride=8,例如:
#include "stdafx.h"
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int _tmain(int argc, _TCHAR* argv[])
{
Mat img=imread("lena.jpg",0);
int w=img.cols;
int h=img.rows;
Rect rect(100,100,20,20);
Mat patch_img=img(rect);
/*
HOGDescriptor() : winSize(64,128), blockSize(16,16), blockStride(8,8),
cellSize(8,8), nbins(9), derivAperture(1), winSigma(-1),
histogramNormType(HOGDescriptor::L2Hys), L2HysThreshold(0.2), gammaCorrection(true),
nlevels(HOGDescriptor::DEFAULT_NLEVELS)
{}*/
HOGDescriptor *hog=new HOGDescriptor(Size(20,20),Size(16,16),Size(4,4),Size(4,4),9);
cout<<"图像的宽和高:"<<img.cols<<" "<<img.rows<<endl;
vector<float>descriptors;//结果数组
hog->compute(patch_img, descriptors);
printf("descriptors.size():%d\n",descriptors.size());
int siz=hog->getDescriptorSize();
cout<<"OpenCV的getDescriptorSize:"<<siz<<endl;
//float rat=descriptors.size()/siz;
//cout<<"descriptors.size()/getDescriptorSize:"<<rat<<endl;
//cout<<"sqrt(rat):"<<sqrt(rat)<<endl;
//cout<<"图像大小可以容纳winSize多少个:"<<((img.cols-64)/8+1)*((img.rows-128)/8+1)<<endl;;
}
维度为:
576
- vlfeat中实现的hog特征。
hog特征的变种有很多,但是结果可能都很相似。vlfeat实现了两种类型的hog特征:
UoCTTI variant 和Dalal-Triggs variant
参考文献:
1. http://www.vlfeat.org/overview/hog.html [Tutorials>HOG features]
2. http://blog.csdn.net/augusdi/article/details/9005352
3. http://www.cnblogs.com/hrlnw/archive/2013/08/06/2826651.html
4. http://blog.csdn.net/liulina603/article/details/8291093
5. http://blog.csdn.net/wobuaishangdiao/article/details/7750723
6. http://m.blog.csdn.net/blog/fanjiaxia/19085141
7. http://blog.csdn.net/ttransposition/article/details/11874285
8. http://blog.csdn.net/raodotcong/article/details/6239431
9. http://blog.csdn.net/u011285477/article/details/50974230 [u011285477的专栏]
10. http://web.mit.edu/vondrick/ihog/index.html#code [hog可视化]