Will Perone

A popular function used in many image processing applications (like blurring) is the gaussian. This function is historically processor intensive to calculate though. Although it is possible to perform a gaussian on an analog signal via special lenses, those are hardly useful to game programmers.
Here I will cover a method of generating a 2 dimensional gaussian very fast and to the finest resolution available when using integer storage.

Let's declare a Gaussian interface using a simple singleton construct:
class Gaussian
{
private:
	static Gaussian *singleton;   //!< the singleton pointer	

public:
	static float *table;          //!< table of gaussian values
	static unsigned int tablesize;//!< gaussian table size
	
	Gaussian(unsigned int size);
	~Gaussian();

	//! call this when you want to delete the interface
	static void Delete() { delete singleton; }	

	//! generates a quantized 2d gaussian distribution into an integer array 
	//! notes: it is up to the caller to delete the array after they are done using it
	//!        size works better if it is not divisible by 2 for symmetry purposes
	//!        scale is the maximum of the gaussian; the map will fall off to 0 at the edge from quantization
	static unsigned int *GenerateMap(unsigned char size, float scale);
};

You can also use an STL::vector for the 1d reference table.

Now onto the actual meat:
#define GAUSSEXPMAX   10.f   //!< values less than e^-10 are assumed to be 0 

// initialize our stuff
float *Gaussian::table= 0;    
unsigned int Gaussian::tablesize= 0;
Gaussian *Gaussian::singleton= 0;


Gaussian::Gaussian(unsigned int size)
{
	singleton= this;

	tablesize= size;
	table= new float[size];

	// generates a 1d reference table of values of e^0 to e^-10
	// values beyond e^-GAUSSEXPMAX are assumed to be about 0
	for (unsigned short x= 0; x < size; ++x)
		 table[x]= expf(-x*GAUSSEXPMAX/size);
}


Gaussian::~Gaussian()
{
	delete []table;
	singleton= 0;
}

What follows is the main quantized 2d map generator; this could be easily expanded to make an N-dimensional gaussian. The 2d map (size x size) is returned by the function as a 1d array but the caller already knows the width of the 2d array from the size parameter. The scale is the value to scale the gaussian curve by, higher values result in a taller curve.
unsigned int *Gaussian::GenerateMap(unsigned char size, float scale)
{
	unsigned int *array, *array_ptr, index;
	int x, y, min= -size/2, max= (size+1)/2;
	unsigned int y_sq;
	float std_dev;


	// allocate room for the gaussian map
	array_ptr= array= new unsigned int[size*size];

	// trust me on this derivation
	std_dev= (float)( size/(2*sqrt(2*log(scale))) );

	// precalculate the scaling factor to be multiplied by distance^2
	// the -GAUSSEXPMAX factors out from the table generation
	std_dev= tablesize / (2*std_dev*std_dev * GAUSSEXPMAX);

	// generate the map
	for (y= min; y < max; ++y)
	{	
		y_sq= y*y;
		for (x= min; x < max; ++x)
		{
			index= (unsigned int)( (x*x + y_sq)*std_dev ); // get the power to raise e to
			if (index > tablesize-1) index= tablesize-1; // prevent overflow
			 *array_ptr++= (unsigned int)(table[(unsigned short)index]*scale);
		}
	}
		 
	return array;
}
That's pretty much it. Accessing the gaussian map is as simple as Gaussian::table[0 ... Gaussian::tablesize]

No Comments yet, be the first!
<- for private contact