본문 바로가기

Image Processing/Feature Extraction

[구현(c)/no ref.] fast and approximated HOG(Histogram of Oriented Gradients) using Integral Image

link: no

 

#define RESIZED_SAMPLE_X_SIZE				64  
#define RESIZED_SAMPLE_Y_SIZE				128

#define CELL_SIZE							8 
#define BLOCK_SIZE							2 
#define ORIENTATION_NUM						9
#define FEAT_DIM							(BLOCK_SIZE*BLOCK_SIZE*ORIENTATION_NUM)*(BLOCK_NUM_IN_X)*(BLOCK_NUM_IN_Y)

#define CELL_NUM_IN_X						(RESIZED_SAMPLE_X_SIZE/CELL_SIZE)  
#define CELL_NUM_IN_Y						(RESIZED_SAMPLE_Y_SIZE/CELL_SIZE) 
#define BLOCK_NUM_IN_X						(CELL_NUM_IN_X-BLOCK_SIZE+1) 
#define BLOCK_NUM_IN_Y						(CELL_NUM_IN_Y-BLOCK_SIZE+1) 

#define PI									3.14f
#define LN_E								1.0f

#define LUT_SIZE							511

float MAGNITUDE_LUT[LUT_SIZE][LUT_SIZE] = {0, };
int   GRADIENT_LUT[LUT_SIZE][LUT_SIZE] = {0, };
float INTEGRAL_IMAGE[ORIENTATION_NUM][RESIZED_SAMPLE_Y_SIZE][RESIZED_SAMPLE_X_SIZE] = {0, };

float CELL_HISTOGRAM[CELL_NUM_IN_X][CELL_NUM_IN_Y][ORIENTATION_NUM] = {0, };

void ExtractIntegralHOGFeature(unsigned char *image, int imageWidth, int imageHeight)
{
	int width = imageWidth;
	int height = imageHeight;

	assert(width == RESIZED_SAMPLE_X_SIZE);
	assert(height == RESIZED_SAMPLE_Y_SIZE);

	float HOG_FEATURE[FEAT_DIM] = {0, };
	CreateGradientLUT();
	InitIntegralImage();
	CreateIntegralHOG(image, width, height);
	GetIntegralHOGFeature(HOG_FEATURE, 0, 0, width, height); 

}

void CreateGradientLUT()
{
	memset(MAGNITUDE_LUT, 0, sizeof(MAGNITUDE_LUT));
	memset(GRADIENT_LUT, 0, sizeof(GRADIENT_LUT));

	register int i, j;
	int x, y;

	float gradient;

	float degreeFactor = 180/PI;

	for(j=0; j<LUT_SIZE; j++)
	{
		y = j-255;

		for(i=0; i<LUT_SIZE; i++)
		{
			x = i-255;

			MAGNITUDE_LUT[j][i] = sqrt((float)(x*x + y*y));

			gradient = atan2((float)y, (float)x);

			gradient = gradient*degreeFactor;
			gradient -= 1.0; 

			if(gradient < 0.0)
			{
				gradient += 360.0f;
			}

			if(gradient > 180.0)
			{
				gradient = gradient-180.0f;
			}

			GRADIENT_LUT[j][i] = (int)gradient/20.0f; 

		}
	}

}

void InitIntegralImage()
{
	memset(INTEGRAL_IMAGE, 0, sizeof(INTEGRAL_IMAGE));
}

void CreateIntegralHOG(unsigned char *image, int width, int height)
{
	register int x, y;

	int xGradient, yGradient, gradient;

	for(y=0; y<height; y++)
	{
		for(x=0; x<width; x++)
		{
			if(x == 0)
			{
				xGradient = image[y*width+x] - image[y*width+(x+1)];
			}

			else if(x == width-1)
			{
				xGradient = image[y*width+(x-1)] - image[y*width+x];
			}

			else
			{
				xGradient = image[y*width+(x-1)] - image[y*width+(x+1)];						
			}

			if(y == 0)
			{
				yGradient = image[y*width+x] - image[(y+1)*width+x];
			}

			else if(y == height-1)
			{
				yGradient = image[(y-1)*width+x] - image[y*width+x];
			}

			else
			{
				yGradient = image[(y-1)*width+x] - image[(y+1)*width+x];
			}

			xGradient = xGradient+255;
			yGradient = yGradient+255;

			gradient = GRADIENT_LUT[yGradient][xGradient];

			INTEGRAL_IMAGE[gradient][y][x] = MAGNITUDE_LUT[yGradient][xGradient];
		}
	}

	ComputeIntegralImage(width, height);

}

void ComputeIntegralImage(int width, int height)
{
	register int i, j, k;

	for(k=0; k<ORIENTATION_NUM; k++)
	{
		for(j=1; j<height; j++)
		{
			for(i=0; i<width; i++)
			{
				INTEGRAL_IMAGE[k][j][i] = INTEGRAL_IMAGE[k][j-1][i] + INTEGRAL_IMAGE[k][j][i];
			}
		}

		for(j=0; j<height; j++)
		{
			for(i=1; i<width; i++)
			{
				INTEGRAL_IMAGE[k][j][i] = INTEGRAL_IMAGE[k][j][i-1] + INTEGRAL_IMAGE[k][j][i];
			}
		}
	}

}

void GetIntegralHOGFeature(float feature[], int x, int y, int sizeW, int sizeH)
{
	memset(feature, 0, sizeof(feature));
	memset(CELL_HISTOGRAM, 0, sizeof(CELL_HISTOGRAM));

	register int p, q, k;
	int x1, x2, y1, y2;

	int iW = sizeW/CELL_NUM_IN_X; 
	int iH = sizeH/CELL_NUM_IN_Y; 

	for(q=0; q<CELL_NUM_IN_Y; q++)
	{
		y1 = y + iH * q;
		y2 = y1 + iH - 1;

		for(p=0; p<CELL_NUM_IN_X; p++)
		{
			x1 = x + iW * p;
			x2 = x1 + iW - 1;

			if(x1 == 0)
			{
				if(y1 == 0)
				{
					for(k=0; k<ORIENTATION_NUM; k++)
					{
						CELL_HISTOGRAM[p][q][k] = INTEGRAL_IMAGE[k][y2][x2];
					}
				}

				else
				{
					for(k=0; k<ORIENTATION_NUM; k++)
					{
						CELL_HISTOGRAM[p][q][k] = INTEGRAL_IMAGE[k][y2][x2] - INTEGRAL_IMAGE[k][y1-1][x2];
					}
				}
			}

			else
			{
				if(y1 == 0)
				{
					for(k=0; k<ORIENTATION_NUM; k++)
					{
						CELL_HISTOGRAM[p][q][k] = INTEGRAL_IMAGE[k][y2][x2] - INTEGRAL_IMAGE[k][y2][x1-1];
					}
				}

				else
				{
					for(k=0; k<ORIENTATION_NUM; k++)
					{
						CELL_HISTOGRAM[p][q][k] = (INTEGRAL_IMAGE[k][y1-1][x1-1] + INTEGRAL_IMAGE[k][y2][x2]) - 
												  (INTEGRAL_IMAGE[k][y2][x1-1] + INTEGRAL_IMAGE[k][y1-1][x2]);
					}
				}
			}

		}	
	}

	Normalize(feature);

}

void Normalize(float feature[])
{
	register int i, j, p, q, k;
	int c = 0;
	float sumMagnitude = 0.0f;
	float e = LN_E;
	float divRegular;

	for(q=0; q<BLOCK_NUM_IN_Y; q++)
	{
		for(p=0; p<BLOCK_NUM_IN_X; p++)
		{
			sumMagnitude = 0.0f;

			for(j=0; j<BLOCK_SIZE; j++)
			{
				for(i=0; i<BLOCK_SIZE; i++)
				{
					for(k=0; k<ORIENTATION_NUM; k++)
					{
						sumMagnitude += CELL_HISTOGRAM[p+i][q+j][k] * CELL_HISTOGRAM[p+i][q+j][k];
					}
				}
			}

			divRegular = 1.0f/sqrt(sumMagnitude+e);

			for(j=0; j<BLOCK_SIZE; j++)
			{		
				for(i=0; i<BLOCK_SIZE; i++)
				{		
					for(k=0; k<ORIENTATION_NUM; k++)
					{
						feature[c] = CELL_HISTOGRAM[p+i][q+j][k] * divRegular;
						c++;
					}
				}
			}

			sumMagnitude = 0.0f;
		}
	}

}