HOG特征提取
原理:
(一)预处理:
包括伽马校正和灰度化。这是可选的步骤,因为实验证明做不做影响不大。伽马校正是减少光度对实验的影响。灰度化是将彩色 图片变成灰度图。其实彩色图片也可以直接处理。不过是分别对三通道的颜色值进行梯度计算,最后选择梯度最大的那个。为简单起见,假设输入为灰度图,同时大小是64*128(这个大小是上面论文的大小,也可以自己确定不同的大小,但是实验效果就不能得到保证)。
代码:
//HOG特征提取(灰度图)
void* HOG(QImage &image,QImage &otp)
{
//分成8x8的小cell
int step = 8;
int bins = 9;
//获取图片的宽高,调整图像的尺寸,把图片尺寸改成8的整倍数,方便计算
int width = image.width();
int height = image.height();
int cols = width / step;
int rows = height / step;
width = cols * step;
height = rows * step;
//尺寸变化
image.scaled(width,height);
//创建一个空白的QImage对象,并初始化为0
QImage* out = new QImage(width,height,QImage::Format_ARGB32);
Init_Image(*out,0);
//遍历用的遍历
int i = 0, j = 0;
int x = 0,y = 0;
//计算梯度与方向
QVector<double> gradiant_x; //x 方向的梯度
QVector<double> gradiant_y; //y 方向的梯度
QVector<double> gradiant; //梯度幅值
QVector<double> direct; //梯度方向
//sobel 算子计算梯度
Sobel_mat(image,gradiant_x,0);
Sobel_mat(image,gradiant_y,1);
//计算梯度的幅值与梯度的方向
cartToPolar(gradiant_x,gradiant_y,gradiant,direct);
//int all_cell = width*height;
int curr_index = 0; //数组的下标指针
double gray = 0; //临时变量,存储梯度幅值
int theta = 0; //临时变量,存储梯度方向
int dire_temp = 0; //取方向20的倍数
int mo = 0; //取方向20的摸
double weight = 0; //权重
double wn = 0; //临时变量
QVector<double> histemp(bins,0); //每个8x8的cell直方图;
QVector<QVector<double>> histog; //总的直方图
//走8步一次
for(i = 0; i<height; i+=step)
{
for(j = 0; j<width; j+=step)
{
//8x8领域的梯度方向直方图
for(int k = 0; k<step;k++)
{
for(int l = 0; l<step; l++)
{
x = j + l;
y = i + k;
//下标指针
curr_index = y * width + x;
//梯度值
gray = gradiant[curr_index];
//方向
theta = (int)direct[curr_index];
//梯度的方向取值是(-π,π)
if(theta<0)
{
theta = theta + 180;
}
//双线性差值
mo = theta % 20;
dire_temp = theta / 20;
//计算偏移权重
if(mo >= 10)
{
wn = mo - 10;
weight = (20-wn) / 20.0f;
}
else {
wn = 10 - mo;
weight = (20-wn) / 20.0f;
}
//根据权重赋值
if(mo>=10)
{
histemp[dire_temp] += (weight * gray);
if(dire_temp < 8)
{
histemp[dire_temp+1] += ((1.0-weight)*gray);
}
}
else {
histemp[dire_temp] += (weight * gray);
if(dire_temp > 0)
{
histemp[dire_temp-1] += ((1.0-weight)*gray);
}
}
}
}
histog.push_back(histemp);
histemp.fill(0);
}
}
//归一化Naturalization
QVector<QVector<double>> blocks; //2x2的block = 4个cell(8x8) = 16x16个
QVector<double> cell_1;
QVector<double> cell_2;
QVector<double> cell_3;
QVector<double> cell_4;
for(i = 0; i<rows-1; i++)
{
for(j = 0; j<cols-1; j++)
{
x = j +1;
y = i + 1;
curr_index = i * cols + j;
cell_1 = histog[curr_index];
curr_index = i * cols + x;
cell_2 = histog[curr_index];
curr_index = y * cols + j;
cell_3 = histog[curr_index];
curr_index = y * cols + x;
cell_4 = histog[curr_index];
QVector<double> block_temp = generateBlockVector(cell_1,cell_2,cell_3,cell_4);
blocks.push_back(block_temp);
}
}
otp = *out;
return 0;
}
//向量的模长
QVector<double> generateBlockVector(QVector<double> cell_1,QVector<double> cell_2,QVector<double> cell_3,QVector<double> cell_4)
{
QVector<double> block;
block.append(cell_1);
block.append(cell_2);
block.append(cell_3);
block.append(cell_4);
double sum = 0;
for(int i = 0; i<cell_1.size(); i++)
{
sum += pow(cell_1[i],2.0) + pow(cell_2[i],2.0) + pow(cell_3[i],2.0) + pow(cell_4[i],2.0);
}
sum = sqrt(sum);
for(int i = 0; i<block.size(); i++)
{
block[i] = block[i] / sum;
}
return block;
}