<commit_before>/******************************************************************
  FILE: computed_field_gabor_filter.c

  LAST MODIFIED: 25 August 2004

  DESCRIPTION:Implement image filter with Gabor filter.
==================================================================*/
#include <math.h>
#include "computed_field/computed_field.h"
#include "computed_field/computed_field_find_xi.h"
#include "computed_field/computed_field_private.h"
#include "computed_field/computed_field_set.h"
#include "image_processing/image_cache.h"
#include "general/image_utilities.h"
#include "general/debug.h"
#include "general/mystring.h"
#include "user_interface/message.h"
#include "image_processing/computed_field_gabor_filter.h"

#define my_Min(x,y) ((x) <= (y) ? (x) : (y))
#define my_Max(x,y) ((x) <= (y) ? (y) : (x))

extern double ceil(double x);
extern double pow(double x, double y);

struct Computed_field_gabor_filter_package
/*******************************************************************************
LAST MODIFIED : 17 March 2004

DESCRIPTION :
A container for objects required to define fields in this module.
==============================================================================*/
{
	struct MANAGER(Computed_field) *computed_field_manager;
	struct Cmiss_region *root_region;
	struct Graphics_buffer_package *graphics_buffer_package;
};


struct Computed_field_gabor_filter_type_specific_data
{
	/* The std of Gaussian function */
	double sigma;
	int *direction;
	FE_value *frequencies;

	float cached_time;
	int element_dimension;
	struct Cmiss_region *region;
	struct Graphics_buffer_package *graphics_buffer_package;
	struct Image_cache *image;
	struct MANAGER(Computed_field) *computed_field_manager;
	void *computed_field_manager_callback_id;
};

static char computed_field_gabor_filter_type_string[] = "gabor_filter";

int Computed_field_is_type_gabor_filter(struct Computed_field *field)
/*******************************************************************************
LAST MODIFIED : 6 January 2004

DESCRIPTION :
==============================================================================*/
{
	int return_code;


	ENTER(Computed_field_is_type_gabor_filter);
	if (field)
	{
		return_code =
		  (field->type_string == computed_field_gabor_filter_type_string);
	}
	else
	{
		display_message(ERROR_MESSAGE,
			"Computed_field_is_type_gabor_filter.  Missing field");
		return_code = 0;
	}

	return (return_code);
} /* Computed_field_is_type_gabor_filter */

static void Computed_field_gabor_filter_field_change(
	struct MANAGER_MESSAGE(Computed_field) *message, void *field_void)
/*******************************************************************************
LAST MODIFIED : 5 August 2004

DESCRIPTION :
Manager function called back when either of the source fields change so that
we know to invalidate the image cache.
==============================================================================*/
{
	struct Computed_field *field;
	struct Computed_field_gabor_filter_type_specific_data *data;

	ENTER(Computed_field_gabor_filter_source_field_change);
	if (message && (field = (struct Computed_field *)field_void) && (data =
		(struct Computed_field_gabor_filter_type_specific_data *)
		field->type_specific_data))
	{
		switch (message->change)
		{
			case MANAGER_CHANGE_OBJECT_NOT_IDENTIFIER(Computed_field):
			case MANAGER_CHANGE_OBJECT(Computed_field):
			{
				if (Computed_field_depends_on_Computed_field_in_list(
					field->source_fields[0], message->changed_object_list) ||
					Computed_field_depends_on_Computed_field_in_list(
					field->source_fields[1], message->changed_object_list))
				{
					if (data->image)
					{
						data->image->valid = 0;
					}
				}
			} break;
			case MANAGER_CHANGE_ADD(Computed_field):
			case MANAGER_CHANGE_REMOVE(Computed_field):
			case MANAGER_CHANGE_IDENTIFIER(Computed_field):
			{
				/* do nothing */
			} break;
		}
	}
	else
	{
		display_message(ERROR_MESSAGE,
			"Computed_field_gabor_filter_source_field_change.  "
			"Invalid arguments.");
	}
	LEAVE;
} /* Computed_field_gabor_filter_source_field_change */

static int Computed_field_gabor_filter_clear_type_specific(
	struct Computed_field *field)
/*******************************************************************************
LAST MODIFIED : 6 January 2004

DESCRIPTION :
Clear the type specific data used by this type.
==============================================================================*/
{
	int return_code;
	struct Computed_field_gabor_filter_type_specific_data *data;

	ENTER(Computed_field_gabor_filter_clear_type_specific);
	if (field && (data =
		(struct Computed_field_gabor_filter_type_specific_data *)
		field->type_specific_data))
	{
		if (data->region)
		{
			DEACCESS(Cmiss_region)(&data->region);
		}
		if (data->image)
		{
			DEACCESS(Image_cache)(&data->image);
		}
		if (data->computed_field_manager && data->computed_field_manager_callback_id)
		{
			MANAGER_DEREGISTER(Computed_field)(
				data->computed_field_manager_callback_id,
				data->computed_field_manager);
		}
		if (data->direction)
		{
		        DEALLOCATE(data->direction);
		}
		if (data->frequencies)
		{
		        DEALLOCATE(data->frequencies);
		}
		DEALLOCATE(field->type_specific_data);
		return_code = 1;
	}
	else
	{
		display_message(ERROR_MESSAGE,
			"Computed_field_gabor_filter_clear_type_specific.  "
			"Invalid arguments.");
		return_code = 0;
	}
	LEAVE;

	return (return_code);
} /* Computed_field_gabor_filter_clear_type_specific */

static void *Computed_field_gabor_filter_copy_type_specific(
	struct Computed_field *source_field, struct Computed_field *destination_field)
/*******************************************************************************
LAST MODIFIED : 6 January 2004

DESCRIPTION :
Copy the type specific data used by this type.
==============================================================================*/
{
	struct Computed_field_gabor_filter_type_specific_data *destination,
		*source;

	ENTER(Computed_field_gabor_filter_copy_type_specific);
	if (source_field && destination_field && (source =
		(struct Computed_field_gabor_filter_type_specific_data *)
		source_field->type_specific_data))
	{
		if (ALLOCATE(destination,
			struct Computed_field_gabor_filter_type_specific_data, 1))
		{
			destination->sigma = source->sigma;
			destination->direction[0] = source->direction[0];
			destination->direction[1] = source->direction[1];
			destination->frequencies[0] = source->frequencies[0];
			destination->frequencies[1] = source->frequencies[1];
			destination->cached_time = source->cached_time;
			destination->region = ACCESS(Cmiss_region)(source->region);
			destination->element_dimension = source->element_dimension;
			destination->graphics_buffer_package = source->graphics_buffer_package;
			destination->computed_field_manager = source->computed_field_manager;
			destination->computed_field_manager_callback_id =
				MANAGER_REGISTER(Computed_field)(
				Computed_field_gabor_filter_field_change, (void *)destination_field,
				destination->computed_field_manager);
			if (source->image)
			{
				destination->image = ACCESS(Image_cache)(CREATE(Image_cache)());
				Image_cache_update_dimension(destination->image,
					source->image->dimension, source->image->depth,
					source->image->sizes, source->image->minimums,
					source->image->maximums);
			}
			else
			{
				destination->image = (struct Image_cache *)NULL;
			}
		}
		else
		{
			display_message(ERROR_MESSAGE,
				"Computed_field_gabor_filter_copy_type_specific.  "
				"Unable to allocate memory.");
			destination = NULL;
		}
	}
	else
	{
		display_message(ERROR_MESSAGE,
			"Computed_field_gabor_filter_copy_type_specific.  "
			"Invalid arguments.");
		destination = NULL;
	}
	LEAVE;

	return (destination);
} /* Computed_field_gabor_filter_copy_type_specific */

int Computed_field_gabor_filter_clear_cache_type_specific
   (struct Computed_field *field)
/*******************************************************************************
LAST MODIFIED : 6 January 2004

DESCRIPTION :
==============================================================================*/
{
	int return_code;
	struct Computed_field_gabor_filter_type_specific_data *data;

	ENTER(Computed_field_gabor_filter_clear_type_specific);
	if (field && (data =
		(struct Computed_field_gabor_filter_type_specific_data *)
		field->type_specific_data))
	{
		if (data->image)
		{
			/* data->image->valid = 0; */
		}
		return_code = 1;
	}
	else
	{
		display_message(ERROR_MESSAGE,
			"Computed_field_gabor_filter_clear_type_specific.  "
			"Invalid arguments.");
		return_code = 0;
	}
	LEAVE;

	return (return_code);
} /* Computed_field_gabor_filter_clear_type_specific */

static int Computed_field_gabor_filter_type_specific_contents_match(
	struct Computed_field *field, struct Computed_field *other_computed_field)
/*******************************************************************************
LAST MODIFIED : 6 January 2004

DESCRIPTION :
Compare the type specific data
==============================================================================*/
{
	int return_code;
	struct Computed_field_gabor_filter_type_specific_data *data,
		*other_data;

	ENTER(Computed_field_gabor_filter_type_specific_contents_match);
	if (field && other_computed_field && (data =
		(struct Computed_field_gabor_filter_type_specific_data *)
		field->type_specific_data) && (other_data =
		(struct Computed_field_gabor_filter_type_specific_data *)
		other_computed_field->type_specific_data))
	{
		if ((data->sigma == other_data->sigma) &&
			data->image && other_data->image &&
			(data->image->dimension == other_data->image->dimension) &&
			(data->image->depth == other_data->image->depth))
		{
			/* Check sizes and minimums and maximums */
			return_code = 1;
		}
		else
		{
			return_code = 0;
		}
	}
	else
	{
		return_code = 0;
	}
	LEAVE;

	return (return_code);
} /* Computed_field_gabor_filter_type_specific_contents_match */

#define Computed_field_gabor_filter_is_defined_in_element \
	Computed_field_default_is_defined_in_element
/*******************************************************************************
LAST MODIFIED : 6 January 2004

DESCRIPTION :
Check the source fields using the default.
==============================================================================*/

#define Computed_field_gabor_filter_is_defined_at_node \
	Computed_field_default_is_defined_at_node
/*******************************************************************************
LAST MODIFIED : 6 January 2004

DESCRIPTION :
Check the source fields using the default.
==============================================================================*/

#define Computed_field_gabor_filter_has_numerical_components \
	Computed_field_default_has_numerical_components
/*******************************************************************************
LAST MODIFIED : 6 January 2004

DESCRIPTION :
Window projection does have numerical components.
==============================================================================*/

#define Computed_field_gabor_filter_not_in_use \
	(Computed_field_not_in_use_function)NULL
/*******************************************************************************
LAST MODIFIED : 6 January 2004

DESCRIPTION :
No special criteria.
==============================================================================*/


static int Image_cache_gabor_filter(struct Image_cache *image, double sigma,
        int *direction, FE_value *frequencies)
/*******************************************************************************
LAST MODIFIED : 17 March 2004

DESCRIPTION : Implement image filtering with Gabor filter.

==============================================================================*/
{
	char *storage;
	FE_value *data_index, *result_index, *max, *re_kernel, *im_kernel;
	int i, j, k, return_code, kernel_size, filter_size, storage_size;
	int radius, m;
	FE_value re_dot, im_dot, s, t, g;
	int *offsets, *cord;
	int image_step, kernel_step;
	FE_value theta;

	ENTER(Image_cache_gabor_filter);
	if (image && (image->depth > 0))
	{
		return_code = 1;
		theta = M_PI * ((FE_value)direction[0]/(FE_value)direction[1]);

		radius = (int)(ceil(2.5 * sigma));
		filter_size = 1 + 2 * radius;

		kernel_size = 1;

		/* Allocate a new storage block for our data */
		storage_size = image->depth;
		for (i = 0 ; i < image->dimension ; i++)
		{
			storage_size *= image->sizes[i];
			kernel_size *= filter_size;
		}
		if (ALLOCATE(re_kernel, FE_value, kernel_size) &&
		        ALLOCATE(im_kernel, FE_value, kernel_size) &&
			ALLOCATE(storage, char, storage_size * sizeof(FE_value)) &&
			ALLOCATE(cord, int, 2) &&
			ALLOCATE(offsets, int, kernel_size) &&
			ALLOCATE(max, FE_value, image->depth))
		{
		        return_code = 1;
			result_index = (FE_value *)storage;
			for (k = 0; k < image->depth; k++)
			{
			        max[k] = 0.0;
			}
			for (i = 0 ; i < storage_size ; i++)
			{
				*result_index = 0.0;
				result_index++;
			}
			for (j = 0 ; j < kernel_size ; j++)
			{
				offsets[j] = 0;
				re_kernel[j] = 0.0;
				im_kernel[j] = 0.0;
			}
			for(j = 0; j < kernel_size; j++)
			{
			        kernel_step = 1;
				image_step = 1;
				for(m = 0; m < image->dimension; m++)
				{
				        cord[m] = ((int)((FE_value)j/((FE_value)kernel_step))) % filter_size;
					offsets[j] += (cord[m] - radius) * image_step * image->depth;
					kernel_step *= filter_size;
					image_step *= image->sizes[m];
				}
				s = ((FE_value)cord[0]) * cos(theta) + ((FE_value)cord[1]) * sin(theta);
				t = ((FE_value)cord[1]) * cos(theta) - ((FE_value)cord[0]) * sin(theta);
				g = 0.6 * pow(2.7, -0.5 * (s*s + 16.0 * t*t)/(sigma*sigma))/ (sigma*sigma);
				re_kernel[j] = g * cos(2.0 * M_PI *(((FE_value)cord[0]) * frequencies[0] + ((FE_value)cord[1]) * frequencies[1]));
				im_kernel[j] = g * sin(2.0 * M_PI *(((FE_value)cord[0]) * frequencies[0] + ((FE_value)cord[1]) * frequencies[1]));
			}

			data_index = (FE_value *)image->data;
			result_index = (FE_value *)storage;
			for (i = 0; i < storage_size / image->depth; i++)
			{
				for (k = 0; k < image->depth; k++)
				{
					re_dot = 0.0;
					im_dot = 0.0;
					for (j = 0; j < kernel_size; j++)
					{
						if ((result_index + offsets[j] >= (FE_value *)storage) &&
							         (result_index + offsets[j] < ((FE_value *)storage) + storage_size))
						{
							re_dot += *(data_index + offsets[j] + k) * re_kernel[j];
							im_dot += *(data_index + offsets[j] + k) * im_kernel[j];
						}
					}
					result_index[k] = sqrt(re_dot * re_dot + im_dot * im_dot);
					max[k] = my_Max(max[k], result_index[k]);
				}
				result_index += image->depth;
				data_index += image->depth;
			}
			for (i = (storage_size / image->depth) - 1; i >= 0; i--)
			{
				result_index -= image->depth;
				for (k = 0; k < image->depth; k++)
				{
					if (max[k] == 0.0)
					{
						result_index[k] = 0.0;
					}
					else
					{
					        result_index[k] /= max[k];
					}
				}
			}

			for (i = 0; i < storage_size / image->depth; i++)
			{
				for (k = 0; k < image->depth; k++)
				{
					result_index[k] = result_index[0];
				}
				result_index += image->depth;
			}
			<commit_msg>Fixed for deleting unnecessary code.<commit_after>/******************************************************************
  FILE: computed_field_gabor_filter.c

  LAST MODIFIED: 25 August 2004

  DESCRIPTION:Implement image filter with Gabor filter.
==================================================================*/
#include <math.h>
#include "computed_field/computed_field.h"
#include "computed_field/computed_field_find_xi.h"
#include "computed_field/computed_field_private.h"
#include "computed_field/computed_field_set.h"
#include "image_processing/image_cache.h"
#include "general/image_utilities.h"
#include "general/debug.h"
#include "general/mystring.h"
#include "user_interface/message.h"
#include "image_processing/computed_field_gabor_filter.h"

#define my_Min(x,y) ((x) <= (y) ? (x) : (y))
#define my_Max(x,y) ((x) <= (y) ? (y) : (x))

extern double ceil(double x);
extern double pow(double x, double y);

struct Computed_field_gabor_filter_package
/*******************************************************************************
LAST MODIFIED : 17 March 2004

DESCRIPTION :
A container for objects required to define fields in this module.
==============================================================================*/
{
	struct MANAGER(Computed_field) *computed_field_manager;
	struct Cmiss_region *root_region;
	struct Graphics_buffer_package *graphics_buffer_package;
};


struct Computed_field_gabor_filter_type_specific_data
{
	/* The std of Gaussian function */
	double sigma;
	int *direction;
	FE_value *frequencies;

	float cached_time;
	int element_dimension;
	struct Cmiss_region *region;
	struct Graphics_buffer_package *graphics_buffer_package;
	struct Image_cache *image;
	struct MANAGER(Computed_field) *computed_field_manager;
	void *computed_field_manager_callback_id;
};

static char computed_field_gabor_filter_type_string[] = "gabor_filter";

int Computed_field_is_type_gabor_filter(struct Computed_field *field)
/*******************************************************************************
LAST MODIFIED : 6 January 2004

DESCRIPTION :
==============================================================================*/
{
	int return_code;


	ENTER(Computed_field_is_type_gabor_filter);
	if (field)
	{
		return_code =
		  (field->type_string == computed_field_gabor_filter_type_string);
	}
	else
	{
		display_message(ERROR_MESSAGE,
			"Computed_field_is_type_gabor_filter.  Missing field");
		return_code = 0;
	}

	return (return_code);
} /* Computed_field_is_type_gabor_filter */

static void Computed_field_gabor_filter_field_change(
	struct MANAGER_MESSAGE(Computed_field) *message, void *field_void)
/*******************************************************************************
LAST MODIFIED : 5 August 2004

DESCRIPTION :
Manager function called back when either of the source fields change so that
we know to invalidate the image cache.
==============================================================================*/
{
	struct Computed_field *field;
	struct Computed_field_gabor_filter_type_specific_data *data;

	ENTER(Computed_field_gabor_filter_source_field_change);
	if (message && (field = (struct Computed_field *)field_void) && (data =
		(struct Computed_field_gabor_filter_type_specific_data *)
		field->type_specific_data))
	{
		switch (message->change)
		{
			case MANAGER_CHANGE_OBJECT_NOT_IDENTIFIER(Computed_field):
			case MANAGER_CHANGE_OBJECT(Computed_field):
			{
				if (Computed_field_depends_on_Computed_field_in_list(
					field->source_fields[0], message->changed_object_list) ||
					Computed_field_depends_on_Computed_field_in_list(
					field->source_fields[1], message->changed_object_list))
				{
					if (data->image)
					{
						data->image->valid = 0;
					}
				}
			} break;
			case MANAGER_CHANGE_ADD(Computed_field):
			case MANAGER_CHANGE_REMOVE(Computed_field):
			case MANAGER_CHANGE_IDENTIFIER(Computed_field):
			{
				/* do nothing */
			} break;
		}
	}
	else
	{
		display_message(ERROR_MESSAGE,
			"Computed_field_gabor_filter_source_field_change.  "
			"Invalid arguments.");
	}
	LEAVE;
} /* Computed_field_gabor_filter_source_field_change */

static int Computed_field_gabor_filter_clear_type_specific(
	struct Computed_field *field)
/*******************************************************************************
LAST MODIFIED : 6 January 2004

DESCRIPTION :
Clear the type specific data used by this type.
==============================================================================*/
{
	int return_code;
	struct Computed_field_gabor_filter_type_specific_data *data;

	ENTER(Computed_field_gabor_filter_clear_type_specific);
	if (field && (data =
		(struct Computed_field_gabor_filter_type_specific_data *)
		field->type_specific_data))
	{
		if (data->region)
		{
			DEACCESS(Cmiss_region)(&data->region);
		}
		if (data->image)
		{
			DEACCESS(Image_cache)(&data->image);
		}
		if (data->computed_field_manager && data->computed_field_manager_callback_id)
		{
			MANAGER_DEREGISTER(Computed_field)(
				data->computed_field_manager_callback_id,
				data->computed_field_manager);
		}
		if (data->direction)
		{
		        DEALLOCATE(data->direction);
		}
		if (data->frequencies)
		{
		        DEALLOCATE(data->frequencies);
		}
		DEALLOCATE(field->type_specific_data);
		return_code = 1;
	}
	else
	{
		display_message(ERROR_MESSAGE,
			"Computed_field_gabor_filter_clear_type_specific.  "
			"Invalid arguments.");
		return_code = 0;
	}
	LEAVE;

	return (return_code);
} /* Computed_field_gabor_filter_clear_type_specific */

static void *Computed_field_gabor_filter_copy_type_specific(
	struct Computed_field *source_field, struct Computed_field *destination_field)
/*******************************************************************************
LAST MODIFIED : 6 January 2004

DESCRIPTION :
Copy the type specific data used by this type.
==============================================================================*/
{
	struct Computed_field_gabor_filter_type_specific_data *destination,
		*source;

	ENTER(Computed_field_gabor_filter_copy_type_specific);
	if (source_field && destination_field && (source =
		(struct Computed_field_gabor_filter_type_specific_data *)
		source_field->type_specific_data))
	{
		if (ALLOCATE(destination,
			struct Computed_field_gabor_filter_type_specific_data, 1))
		{
			destination->sigma = source->sigma;
			destination->direction[0] = source->direction[0];
			destination->direction[1] = source->direction[1];
			destination->frequencies[0] = source->frequencies[0];
			destination->frequencies[1] = source->frequencies[1];
			destination->cached_time = source->cached_time;
			destination->region = ACCESS(Cmiss_region)(source->region);
			destination->element_dimension = source->element_dimension;
			destination->graphics_buffer_package = source->graphics_buffer_package;
			destination->computed_field_manager = source->computed_field_manager;
			destination->computed_field_manager_callback_id =
				MANAGER_REGISTER(Computed_field)(
				Computed_field_gabor_filter_field_change, (void *)destination_field,
				destination->computed_field_manager);
			if (source->image)
			{
				destination->image = ACCESS(Image_cache)(CREATE(Image_cache)());
				Image_cache_update_dimension(destination->image,
					source->image->dimension, source->image->depth,
					source->image->sizes, source->image->minimums,
					source->image->maximums);
			}
			else
			{
				destination->image = (struct Image_cache *)NULL;
			}
		}
		else
		{
			display_message(ERROR_MESSAGE,
				"Computed_field_gabor_filter_copy_type_specific.  "
				"Unable to allocate memory.");
			destination = NULL;
		}
	}
	else
	{
		display_message(ERROR_MESSAGE,
			"Computed_field_gabor_filter_copy_type_specific.  "
			"Invalid arguments.");
		destination = NULL;
	}
	LEAVE;

	return (destination);
} /* Computed_field_gabor_filter_copy_type_specific */

int Computed_field_gabor_filter_clear_cache_type_specific
   (struct Computed_field *field)
/*******************************************************************************
LAST MODIFIED : 6 January 2004

DESCRIPTION :
==============================================================================*/
{
	int return_code;
	struct Computed_field_gabor_filter_type_specific_data *data;

	ENTER(Computed_field_gabor_filter_clear_type_specific);
	if (field && (data =
		(struct Computed_field_gabor_filter_type_specific_data *)
		field->type_specific_data))
	{
		if (data->image)
		{
			/* data->image->valid = 0; */
		}
		return_code = 1;
	}
	else
	{
		display_message(ERROR_MESSAGE,
			"Computed_field_gabor_filter_clear_type_specific.  "
			"Invalid arguments.");
		return_code = 0;
	}
	LEAVE;

	return (return_code);
} /* Computed_field_gabor_filter_clear_type_specific */

static int Computed_field_gabor_filter_type_specific_contents_match(
	struct Computed_field *field, struct Computed_field *other_computed_field)
/*******************************************************************************
LAST MODIFIED : 6 January 2004

DESCRIPTION :
Compare the type specific data
==============================================================================*/
{
	int return_code;
	struct Computed_field_gabor_filter_type_specific_data *data,
		*other_data;

	ENTER(Computed_field_gabor_filter_type_specific_contents_match);
	if (field && other_computed_field && (data =
		(struct Computed_field_gabor_filter_type_specific_data *)
		field->type_specific_data) && (other_data =
		(struct Computed_field_gabor_filter_type_specific_data *)
		other_computed_field->type_specific_data))
	{
		if ((data->sigma == other_data->sigma) &&
			data->image && other_data->image &&
			(data->image->dimension == other_data->image->dimension) &&
			(data->image->depth == other_data->image->depth))
		{
			/* Check sizes and minimums and maximums */
			return_code = 1;
		}
		else
		{
			return_code = 0;
		}
	}
	else
	{
		return_code = 0;
	}
	LEAVE;

	return (return_code);
} /* Computed_field_gabor_filter_type_specific_contents_match */

#define Computed_field_gabor_filter_is_defined_in_element \
	Computed_field_default_is_defined_in_element
/*******************************************************************************
LAST MODIFIED : 6 January 2004

DESCRIPTION :
Check the source fields using the default.
==============================================================================*/

#define Computed_field_gabor_filter_is_defined_at_node \
	Computed_field_default_is_defined_at_node
/*******************************************************************************
LAST MODIFIED : 6 January 2004

DESCRIPTION :
Check the source fields using the default.
==============================================================================*/

#define Computed_field_gabor_filter_has_numerical_components \
	Computed_field_default_has_numerical_components
/*******************************************************************************
LAST MODIFIED : 6 January 2004

DESCRIPTION :
Window projection does have numerical components.
==============================================================================*/

#define Computed_field_gabor_filter_not_in_use \
	(Computed_field_not_in_use_function)NULL
/*******************************************************************************
LAST MODIFIED : 6 January 2004

DESCRIPTION :
No special criteria.
==============================================================================*/


static int Image_cache_gabor_filter(struct Image_cache *image, double sigma,
        int *direction, FE_value *frequencies)
/*******************************************************************************
LAST MODIFIED : 17 March 2004

DESCRIPTION : Implement image filtering with Gabor filter.

==============================================================================*/
{
	char *storage;
	FE_value *data_index, *result_index, *max, *re_kernel, *im_kernel;
	int i, j, k, return_code, kernel_size, filter_size, storage_size;
	int radius, m;
	FE_value re_dot, im_dot, s, t, g;
	int *offsets, *cord;
	int image_step, kernel_step;
	FE_value theta;

	ENTER(Image_cache_gabor_filter);
	if (image && (image->depth > 0))
	{
		return_code = 1;
		theta = M_PI * ((FE_value)direction[0]/(FE_value)direction[1]);

		radius = (int)(ceil(2.5 * sigma));
		filter_size = 1 + 2 * radius;

		kernel_size = 1;

		/* Allocate a new storage block for our data */
		storage_size = image->depth;
		for (i = 0 ; i < image->dimension ; i++)
		{
			storage_size *= image->sizes[i];
			kernel_size *= filter_size;
		}
		if (ALLOCATE(re_kernel, FE_value, kernel_size) &&
		        ALLOCATE(im_kernel, FE_value, kernel_size) &&
			ALLOCATE(storage, char, storage_size * sizeof(FE_value)) &&
			ALLOCATE(cord, int, 2) &&
			ALLOCATE(offsets, int, kernel_size) &&
			ALLOCATE(max, FE_value, image->depth))
		{
		        return_code = 1;
			result_index = (FE_value *)storage;
			for (k = 0; k < image->depth; k++)
			{
			        max[k] = 0.0;
			}
			for (i = 0 ; i < storage_size ; i++)
			{
				*result_index = 0.0;
				result_index++;
			}
			for (j = 0 ; j < kernel_size ; j++)
			{
				offsets[j] = 0;
				re_kernel[j] = 0.0;
				im_kernel[j] = 0.0;
			}
			for(j = 0; j < kernel_size; j++)
			{
			        kernel_step = 1;
				image_step = 1;
				for(m = 0; m < image->dimension; m++)
				{
				        cord[m] = ((int)((FE_value)j/((FE_value)kernel_step))) % filter_size;
					offsets[j] += (cord[m] - radius) * image_step * image->depth;
					kernel_step *= filter_size;
					image_step *= image->sizes[m];
				}
				s = ((FE_value)cord[0]) * cos(theta) + ((FE_value)cord[1]) * sin(theta);
				t = ((FE_value)cord[1]) * cos(theta) - ((FE_value)cord[0]) * sin(theta);
				g = 0.6 * pow(2.7, -0.5 * (s*s + 16.0 * t*t)/(sigma*sigma))/ (sigma*sigma);
				re_kernel[j] = g * cos(2.0 * M_PI *(((FE_value)cord[0]) * frequencies[0] + ((FE_value)cord[1]) * frequencies[1]));
				im_kernel[j] = g * sin(2.0 * M_PI *(((FE_value)cord[0]) * frequencies[0] + ((FE_value)cord[1]) * frequencies[1]));
			}

			data_index = (FE_value *)image->data;
			result_index = (FE_value *)storage;
			for (i = 0; i < storage_size / image->depth; i++)
			{
				for (k = 0; k < image->depth; k++)
				{
					re_dot = 0.0;
					im_dot = 0.0;
					for (j = 0; j < kernel_size; j++)
					{
						if ((result_index + offsets[j] >= (FE_value *)storage) &&
							         (result_index + offsets[j] < ((FE_value *)storage) + storage_size))
						{
							re_dot += *(data_index + offsets[j] + k) * re_kernel[j];
							im_dot += *(data_index + offsets[j] + k) * im_kernel[j];
						}
					}
					result_index[k] = sqrt(re_dot * re_dot + im_dot * im_dot);
					max[k] = my_Max(max[k], result_index[k]);
				}
				result_index += image->depth;
				data_index += image->depth;
			}
			for (i = (storage_size / image->depth) - 1; i >= 0; i--)
			{
				result_index -= image->depth;
				for (k = 0; k < image->depth; k++)
				{
					if (max[k] == 0.0)
					{
						result_index[k] = 0.0;
					}
					else
					{
					        result_index[k] /= max[k];
					}
				}
			}
			
{'fraction_non_alphanumeric': 0.23659086388649472, 'fraction_numerical': 0.010442219717562819, 'mean_word_length': 5.1502548419979615, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 206, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4247501', 'n_tokens_mistral': 10960, 'n_tokens_neox': 9372, 'n_words': 1739}