Hog行人检测







HOG特征向量归一化

对block块内的HOG特征向量进行归一化。对block块内特征向量的归一化主要是为了使特征向量空间对光照,阴影和边缘变化具有鲁棒性。还有归一化是针对每一个block进行的,一般采用的归一化函数有以下四种:


在人体检测系统中进行HOG计算时一般使用L2-norm,Dalal的文章也验证了对于人体检测系统使用L2-norm的时候效果最好。

关于就算直方图时用到的三线性插值














1.第一步的作用在于将图像规范化,通过两个方面GAMMA和COLOUR, GAMMA方面的话,其规范化后图像中的参量可以被直接提取出来,方便后面的操作,颜色的规范化则是去除图像中光强值同时保留颜色值,例如去除阴影或者光强变化的像素。
在低FPPW中,均方根的GAMMA压缩能够提高其表现。而LOG则起到了反作用。
2.斜率的计算直接影响识别的表现,不同的斜率计算方法在FPPW的表现上不同,总体而言,较为简单的斜率计算能够获得更好的效果,此外,对于颜色的斜率计算则是对每一个颜色通道进行独立的斜率测量,并且寻找到最标准的一个作为像素的斜率向量。求导不仅能够捕捉人物轮廓信息,也能进一步削弱光强差异。
3.这个模块的主要目的在于通过计算每个像素的权重投票,通过局部空间地区(CELL)累计投票,投票是用来反映某像素的斜率幅度的大小。
4.针对图像中前景和背景之间的信息的不同,运用归一化使得信息得以统一,通过局部空间单元的信息组成向量(最关键部分),空间中的模块是重合的,这样每个单元可以包含多个单元的信息,使得向量能够反映更多的图像信息。这可以大幅度提高图像识别能力。
5.HOG技术在人物识别窗口中共有16个像素,这大大降低了识别的错误率,而这一步就是将像素收集并整理信息。
6.将之前整理的向量送入SVM进行分级,来判断其是否是人物。





Hog.h

#pragma once
#include<vector>
#include<map>
#define PI 3.1416
typedef unsigned char BYTE;
#define GradType BYTE
#define MagType BYTE
#define FeaType double
class BlockManager
{
private:
	std::map<std::pair<int, int>, double*>cache;
	int level;

public:
	bool find(int y, int x)
	{
		return cache.find(std::pair<int, int>(y, x)) != cache.end();
	}
	double*GetBlockData(int y, int x)
	{
		return cache[std::pair<int, int>(y, x)];
	}
	void AddBlock(int y, int x, double*data)
	{
		cache.insert(std::pair<std::pair<int, int>, double*>(std::pair<int, int>(y, x), data));
	}
	void SetLevel(const int lev)
	{
		level = lev;
	}
	void deleteBlock(int y, int x)
	{
		delete[]cache[std::pair<int, int>(y, x)];
		cache.erase(std::pair<int, int>(y, x));
	}
	void deleteAllBlocks()
	{
		std::map<std::pair<int, int>, double*>::iterator it;
		for (it = cache.begin(); it != cache.end(); it++)
		{
			delete[](*it).second;
			cache.erase(it);
			it = cache.begin();
			if (cache.empty())
				return;
		}
	}
	~BlockManager()
	{
		deleteAllBlocks();
	}
};
class Hog
{
public:
	int img_width;//待检测图片的宽度
	int img_height;//待检测图片的高度
	int window_width;//检测窗口的宽度,64
	int window_height;//检测窗口的高度,128
	int CellSize;//cell的大小,设为8
	int blkcell;//block尺寸是cell的几倍,2*2
	int blocksize;//block的大小
	int blockSkipStep;//Block在检测窗口中上下移动尺寸为8,与blocksize=16相比,
	//即overlap=1/2,blockSkipStep减小到4使得overlap增加到3/4后,可使精度增加,但计算量增大
	int windowSkipStep;//滑动窗口在检测图片中滑动的尺寸为8
	int m_histBin;//180度分几个区间,设为9,即1个cell的梯度直方图化成9个bin
	int win_fea_dim;
	int xblkSkipStepNum;
	int yblkSkipStepNum;
private:

	int max_pyramid_height;//图像金字塔高度
	int current_pyramid_height;//当前图像金字塔高度
	double ratio;//缩放比例
	bool isGaussianWeight;//是否使用高斯权重
	BYTE*RGBdata;
	BYTE*greydata;
	GradType*grad;//梯度矩阵
	MagType*theta;//角度矩阵
	std::vector < FeaType* > windowHOGFeature;
	BlockManager blockmanager;

	bool GetImgData();

	void Gamma();
	void RGB2Grey();
	double* GetBlkFeature(int offsetX, int offsetY);
	double GaussianKernel(int x, int y, int cent_x, int cent_y, int Hx, int Hy);
	void NextPyramid();
public:
	GradType*get_grad(){ return grad; }
	MagType*get_mag(){ return theta; }
	void ComputeGradient();
	Hog(const int winW, const int winH, const int CellSize,
		const int blkcell, const int blockSkipStep, const int windowSkipStep,
		const int m_histBin, const double rat) :ratio(rat),
		window_width(winW), window_height(winH),
		CellSize(CellSize), blkcell(blkcell), blockSkipStep(blockSkipStep),
		windowSkipStep(windowSkipStep), m_histBin(m_histBin)
	{
		blocksize = CellSize*blkcell;
		//RGBdata = new BYTE[imgw*imgh * 3]; 
		max_pyramid_height = 0;
		current_pyramid_height = 1;
		int ww = img_width = 64;
		int hh = img_height = 128;
		while (ww >= window_width&&hh >= window_height)
		{
			ww = ww / 2;
			hh = hh / 2;
			max_pyramid_height++;
		}
		xblkSkipStepNum = floor((window_width - blkcell * CellSize) / blockSkipStep + 1);
		yblkSkipStepNum = floor((window_height - blkcell * CellSize) / blockSkipStep + 1);
		win_fea_dim = xblkSkipStepNum*yblkSkipStepNum*blkcell*blkcell*m_histBin;
		_ASSERTE(max_pyramid_height >= 1);
	};
	int getwindow_width(){ return window_width; };
	int getwindow_height(){ return window_height; };
	void GetWindowFeature(const int offsetY_againstImg, const int offsetX_againstImg);
	void L2Normalize(double*vec, int length);
	void set_img_size(const int h, const int w){ img_height = h; img_width = w; }
	void SingleScaleDetect();
	void MultiScaleDetect();
	void setgreyData(BYTE*src){ this->greydata = src; }
	GradType*get_grad_data(){ return grad; }
	void writeHogFea2File();
	std::vector < FeaType* >getwindowHOGFeature(){ return windowHOGFeature; }
	~Hog()
	{
		if (RGBdata != NULL)
			delete[]RGBdata;
		if (greydata != NULL)
		{
			delete[]greydata;
		}
		for (int i = 0; i < windowHOGFeature.size(); i++)
			if (windowHOGFeature[i] != NULL)
				delete[]windowHOGFeature[i];
		delete[]grad;
		delete[]theta;
	};
};

Hog.cpp

#include "stdafx.h"
#include "Hog.h"
#include<cmath>
#include <fstream>


void Hog::writeHogFea2File()
{
	std::ofstream myfile;
	myfile.open("example.txt");
	myfile << "Writing HOG Feature to File.
";
	_ASSERTE(windowHOGFeature.size() == 105);
	for (int z = 0; z < 105; ++z)
	{
		for (int i = 0; i < 36; i++)
			myfile << windowHOGFeature[z][i] << std::endl;
	}
	myfile.close();
}
void Hog::ComputeGradient()
{
	if (grad != NULL)
		delete[]grad;
	grad = new GradType[img_height*img_width];
	if (theta != NULL)
		delete[]theta;
	theta = new MagType[img_height*img_width];
	for (int i = 1; i < img_height; i++)
		for (int j = 1; j < img_width; j++)
		{
			double dx = greydata[i*img_width + j + 1] - greydata[i*img_width + j - 1];
			double dy = greydata[(i + 1)*img_width + j] - greydata[(i - 1)*img_width + j];
			if (fabs(dx) <= 1.0e-6 && fabs(dy) <= 1.0e-6) {
				grad[i*img_width + j] = 0;
			}
			else
				grad[i*img_width + j] = (sqrt(dx*dx + dy*dy));
			double theta = atan2(dy, dx);
			if (theta < 0)
				theta = (theta + PI);   // normalize to [0, PI], CV_PI   
			if (theta > PI)
				theta = theta - PI;
			theta = (theta * 180 / PI);
			this->theta[i*img_width + j] = theta;
			std::cout << theta + 0 << std::endl;
		}
	// 边界点的梯度取其近邻点的值   
	int i = 0;
	for (int j = 0; j < img_width; j++) {
		grad[i*img_width + j] = grad[(i + 1)*img_width + j];
		this->theta[i*img_width + j] = this->theta[(i + 1)*img_width + j];
	}
	i = img_height - 1;
	for (int j = 0; j < img_width; j++) {
		grad[i*img_width + j] = grad[(i - 1)*img_width + j];
		this->theta[i*img_width + j] = this->theta[(i - 1)*img_width + j];
	}
	int j = 0;
	for (i = 0; i < img_height; i++) {
		grad[i*img_width + j] = grad[i*img_width + j + 1];
		this->theta[i*img_width + j] = this->theta[i*img_width + j + 1];
	}
	j = img_width - 1;
	for (i = 0; i < img_height; i++) {
		grad[i*img_width + j] = grad[i*img_width + j - 1];
		this->theta[i*img_width + j] = this->theta[i*img_width + j - 1];
	}

}

void Hog::L2Normalize(double*vec, int length)//归一化
{
	double sum = 0;
	for (int i = 0; i < length; i++)
		sum += vec[i] * vec[i];
	sum = (double)1.0 / sqrt(sum + FLT_EPSILON);
	for (int i = 0; i < length; i++)
		vec[i] = vec[i] * sum;
}

double* Hog::GetBlkFeature(int offsetY_againstImg, int offsetX_againstImg)
{
	double *blkHOG = new double[blkcell*blkcell*m_histBin];
	int aa = sizeof(char);
	memset(blkHOG, 0, 36 * sizeof(double));
	int center_cell_0_X = CellSize / 2;
	int center_cell_0_Y = CellSize / 2;
	/*int center_cell_1_X = CellSize / 2+CellSize;
	int center_cell_1_Y = CellSize / 2;
	int center_cell_2_X = CellSize / 2;
	int center_cell_2_Y = CellSize / 2+CellSize;
	int center_cell_3_X = CellSize / 2+CellSize;
	int center_cell_3_Y = CellSize / 2+CellSize;*/
	int regionsize = CellSize;
	for (int cell_no_y = 0; cell_no_y < blkcell; cell_no_y++) {
		for (int cell_no_x = 0; cell_no_x < blkcell; cell_no_x++) {
			// cell index in the blk  
			int cell_idx = cell_no_y*blkcell + cell_no_x;
			// start of a cell  
			int cell_start_y = cell_no_y*CellSize;
			int cell_start_x = cell_no_x*CellSize;
			// compute in the cell  
			for (int y = cell_start_y; y < cell_start_y + CellSize; y++) {
				for (int x = cell_start_x; x<cell_start_x + CellSize; x++) {
					double theta = this->theta[(offsetY_againstImg + y)*img_width + offsetX_againstImg + x];
					double magn = grad[(offsetY_againstImg + y)*img_width + offsetX_againstImg + x];
					// 如果幅值为0, 没有梯度则不处理  
					if (magn >= 0.0) {
						int theta_idx = (int)(theta / (180.0 / m_histBin));
						//double gaussweight = isGaussianWeight == true ? GaussianKernel(x, y, CellSize, CellSize, CellSize, CellSize) : 1;
						//magn= magn*gaussweight;//用高斯核函数调制

						double tt = 1.0 - fabs(double(theta) / (180.0 / double(m_histBin)) - (double(theta_idx) + 0.5));
						double fx0 = 1.0 - fabs(double(x - center_cell_0_X)) / double(regionsize);
						double fy0 = 1.0 - fabs(double(y - center_cell_0_Y)) / double(regionsize);
						if (y <= CellSize / 2 && x <= CellSize / 2 || y >= CellSize*blkcell - CellSize / 2 && x <= CellSize / 2
							|| y >= CellSize*blkcell - CellSize / 2 && x >= CellSize*blkcell - CellSize / 2
							|| x >= CellSize*blkcell - CellSize / 2 && y <= CellSize / 2)//四个角点不做三线性插值
						{
							blkHOG[m_histBin*cell_idx + theta_idx] = blkHOG[m_histBin*cell_idx + theta_idx] + double(magn)*tt;
							blkHOG[m_histBin*cell_idx + (theta_idx + 1) % m_histBin] += double(magn)*(1.0 - tt);
						}
						if (x>CellSize / 2 && x < CellSize && (y < CellSize / 2 || y> CellSize*blkcell - CellSize / 2))
						{
							blkHOG[m_histBin*cell_idx + theta_idx] += double(magn)*tt*fx0;
							blkHOG[m_histBin*(cell_idx + 1) + theta_idx] += double(magn)*tt*(1.0 - fx0);
							blkHOG[m_histBin*cell_idx + (theta_idx + 1) % m_histBin] += double(magn)*(1.0 - tt)*fx0;
							blkHOG[m_histBin*(cell_idx + 1) + (theta_idx + 1) % m_histBin] += double(magn)*(1.0 - tt)*(1.0 - fx0);
						}
						if (x>CellSize && x < CellSize*blkcell - CellSize / 2 && (y < CellSize / 2 || y> CellSize*blkcell - CellSize / 2))
						{
							blkHOG[m_histBin*cell_idx + theta_idx] += double(magn)*tt*fx0;
							blkHOG[m_histBin*(cell_idx - 1) + theta_idx] += double(magn)*tt*(1.0 - fx0);
							blkHOG[m_histBin*cell_idx + (theta_idx + 1) % m_histBin] += double(magn)*(1.0 - tt)*fx0;
							blkHOG[m_histBin*(cell_idx - 1) + (theta_idx + 1) % m_histBin] += double(magn)*(1.0 - tt)*(1.0 - fx0);
						}
						if (y>CellSize / 2 && y < CellSize && (x < CellSize / 2 || x> CellSize*blkcell - CellSize / 2))
						{
							blkHOG[m_histBin*cell_idx + theta_idx] += double(magn)*tt*fy0;
							blkHOG[m_histBin*(cell_idx + blkcell) + theta_idx] += double(magn)*tt*(1.0 - fy0);
							blkHOG[m_histBin*cell_idx + (theta_idx + 1) % m_histBin] += double(magn)*(1.0 - tt)*fy0;
							blkHOG[m_histBin*(cell_idx + blkcell) + (theta_idx + 1) % m_histBin] += double(magn)*(1.0 - tt)*(1.0 - fy0);
						}
						if (y>CellSize && y < CellSize*blkcell - CellSize / 2 && (x < CellSize / 2 || x> CellSize*blkcell - CellSize / 2))
						{
							blkHOG[m_histBin*cell_idx + theta_idx] += double(magn)*tt*fy0;
							blkHOG[m_histBin*(cell_idx - blkcell) + theta_idx] += double(magn)*tt*(1.0 - fy0);
							blkHOG[m_histBin*cell_idx + (theta_idx + 1) % m_histBin] += double(magn)*(1.0 - tt)*fy0;
							blkHOG[m_histBin*(cell_idx - blkcell) + (theta_idx + 1) % m_histBin] += double(magn)*(1.0 - tt)*(1.0 - fy0);
						}
						else//做三线性插值,将 4 个cell中的直方图串接起来
						{
							blkHOG[m_histBin * 0 + theta_idx] += double(magn)*tt*fx0*fy0;
							blkHOG[m_histBin * 0 + (theta_idx + 1) % m_histBin] += double(magn)*(1.0 - tt)*fx0*fy0;
							blkHOG[m_histBin * 1 + theta_idx] += double(magn)*tt*(1.0 - fx0)*fy0;
							blkHOG[m_histBin * 1 + (theta_idx + 1) % m_histBin] += double(magn)*(1.0 - tt)*(1.0 - fx0)*fy0;
							blkHOG[m_histBin * 2 + theta_idx] += double(magn)*tt*fx0*(1.0 - fy0);
							blkHOG[m_histBin * 2 + (theta_idx + 1) % m_histBin] += double(magn)*(1.0 - tt)*fx0*(1.0 - fy0);
							blkHOG[m_histBin * 3 + theta_idx] += double(magn)*tt*(1.0 - fx0)*(1.0 - fy0);
							blkHOG[m_histBin * 3 + (theta_idx + 1) % m_histBin] += double(magn)*(1.0 - tt)*(1.0 - fx0)*(1.0 - fy0);

						}
					}
				} // for(x)  
			}   // for(y)                 
		}   // for(cell_no_x)  
	}   // for(cell_no_y)   
	/*for (int i = 0; i < 36; i++)
		std::cout << blkHOG[i] << std::endl;
		std::cout << std::endl << std::endl;*/
	L2Normalize(blkHOG, blkcell*blkcell*m_histBin);//以一个block为单位进行归一化
	/*for (int i = 0; i < 36; i++)
		std::cout << blkHOG[i] << std::endl;*/
	blockmanager.AddBlock(offsetY_againstImg, offsetX_againstImg, blkHOG);//存入cache避免重复计算
	return blkHOG;
}
double Hog::GaussianKernel(int x, int y, int cent_x, int cent_y, int Hx, int Hy)//高斯核函数
{
	int dx = x - cent_x;
	int dy = y - cent_y;
	double temp = 1 - ((double)(dx*dx) / (Hx*Hx) + (double)(dy*dy) / (Hy*Hy)) / 2;
	if (temp >= 0)
	{
		return (double)(4.0 * temp / (2 * PI));
	}
	else
	{
		return 0.0f;
	}
}

void Hog::GetWindowFeature(const int offsetY_againstImg, const int offsetX_againstImg)//获得window的feature
{
	windowHOGFeature.clear();

	//double*imgHOGFeature = new double[blkcell*blkcell*m_histBin*xSkipStepNum*ySkipStepNum];
	for (int i = 0; i < yblkSkipStepNum; i++)
		for (int j = 0; j < xblkSkipStepNum; j++)
		{
			double*blkFea;
			if (blockmanager.find(offsetY_againstImg + i*blockSkipStep, offsetX_againstImg + j*blockSkipStep))
				blkFea = blockmanager.GetBlockData(offsetY_againstImg + i*blockSkipStep,
				offsetX_againstImg + j*blockSkipStep);
			else
				blkFea = GetBlkFeature(offsetY_againstImg + i*blockSkipStep, offsetX_againstImg + j*blockSkipStep);
			/*memcpy(imgHOGFeature + (i*xSkipStepNum + j)*blkcell*blkcell*m_histBin, blkFea,
			blkcell*blkcell*m_histBin);
			delete[]blkFea;*/
			windowHOGFeature.push_back(blkFea);
		}
}

void Hog::RGB2Grey()
{
	if (greydata == NULL)
		greydata = new BYTE[img_width*img_height];
	for (int i = 0; i < img_height; i++)
		for (int j = 0; j < img_width; j++)
		{
			greydata[i*img_width + j] = 0.299*RGBdata[i*img_width * 3 + 3 * j] +
				0.587*RGBdata[i*img_width * 3 + 3 * j + 1] +
				0.114*RGBdata[i*img_width * 3 + 3 * j + 2];
		}
	delete[]RGBdata;
}

void Hog::NextPyramid()//双线性插值获得下一层图像
{
	int new_img_height = img_height / ratio;
	int new_img_width = img_width / ratio;

	BYTE*new_greydata = new BYTE[new_img_height*new_img_width];
	double fw = ratio;//double(nW) / W1;
	double fh = ratio;//double(nH) / H1;
	int y1, y2, x1, x2, x0, y0;
	double fx1, fx2, fy1, fy2;

	for (int i = 0; i < new_img_height; i++)
	{
		y0 = i*fh;
		y1 = int(y0);
		if (y1 == img_height - 1)    y2 = y1;
		else y2 = y1 + 1;
		fy1 = y1 - y0;
		fy2 = 1.0f - fy1;
		for (int j = 0; j < new_img_width; j++)
		{
			x0 = j*fw;
			x1 = int(x0);
			if (x1 == img_width - 1)    x2 = x1;
			else x2 = x1 + 1;
			fx1 = y1 - y0;
			fx2 = 1.0f - fx1;
			double s1 = fx1*fy1;
			double s2 = fx2*fy1;
			double s3 = fx2*fy2;
			double s4 = fx1*fy2;
			BYTE c1r, c2r, c3r, c4r;
			c1r = greydata[y1*img_width + x1];
			c2r = greydata[y1*img_width + x2];
			c3r = greydata[y2*img_width + x1];
			c4r = greydata[y2*img_width + x2];
			BYTE r;
			r = (BYTE)(c1r*s3) + (BYTE)(c2r*s4) + (BYTE)(c3r*s2) + (BYTE)(c4r*s1);
			new_greydata[i*new_img_width + j] = r;
		}
	}
	delete[]greydata;
	greydata = new_greydata;
	img_height = new_img_height;
	img_width = new_img_width;
	current_pyramid_height++;
	blockmanager.deleteAllBlocks();
	blockmanager.SetLevel(current_pyramid_height);
}
/*void Hog::SingleScaleDetect()
{
int xSkipStepNum = floor((img_width - window_width) / windowSkipStep + 1);
int ySkipStepNum = floor((img_height - window_width) / windowSkipStep + 1);
//double*imgHOGFeature = new double[blkcell*blkcell*m_histBin*xSkipStepNum*ySkipStepNum];
for (int i = 0; i < ySkipStepNum; i++)
for (int j = 0; j < xSkipStepNum; j++)
{
GetWindowFeature(i*windowSkipStep, j*windowSkipStep);
}
}


void Hog::MultiScaleDetect()
{
while (current_pyramid_height < max_pyramid_height)
{
SingleScaleDetect();
NextPyramid();
}
}*/




版权声明:

原文地址:https://www.cnblogs.com/walccott/p/4957075.html