/*********************************************************************
 * This file is part of the PRAPI library.
 *
 * Copyright (C) 2001 Topi Mäenpää and Jaakko Viertola
 * All rights reserved.
 *
 * This program is free software. You can redistribute and/or modify
 * it under the terms of the free software licence found in the
 * accompanying file "COPYING". The licence terms must always be
 * redistributed with this source file. The above copyright notice
 * must be reproduced in all modified and unmodified copies of this
 * source file.
 *
 * $Revision: 1.5 $
 *********************************************************************/

#include "CoOccurence.h"

using namespace util;

namespace prapi{ namespace texture {
	
	Matrix<int> CoOccurence::getTransformedImage(const Matrix<int>& mat)
		throw (ImageTransformException&)
	{
		int rows=mat.getRows();
		int cols=mat.getColumns();
		if(rows <= 0 || cols <=0)
			throw ImageTransformException("CoOccurence<T,U>::getTransformedImage(const Matrix<U>&): Cannot calculate anything for an empty matrix.");

		// check the maximum value of matrix
		int max=mat.max()+1;
		int min=mat.min();
		if(max <= 1 || min < 0)
			throw ImageTransformException("CoOccurence<T,U>::getTransformedImage(const Matrix<U>&): Matrix values should be bigger than zero.");
		
		int row=0,col=0;
		max-=min;
		Matrix<int> result(max,max);

		// then check the angle
		if(_CoOccurenceAngle == DIR135 || _CoOccurenceAngle == ALL)
			{
				for(int r=_iRadius;r<rows;r++)
					for(int c=_iRadius;c<cols;c++)
						{
							row = mat(r,c);
							col = mat(r-_iRadius,c-_iRadius);
							result(row-min,col-min)++;
						}
			}
		if(_CoOccurenceAngle == DIR90 || _CoOccurenceAngle == ALL)
			{
				for(int r=_iRadius;r<rows;r++)
					for(int c=0;c<cols;c++)
						{
							row = mat(r,c);
							col = mat(r-_iRadius,c);
							result(row-min,col-min)++;
						}
			}
		if(_CoOccurenceAngle == DIR45 || _CoOccurenceAngle == ALL)
			{
				for(int r=_iRadius;r<rows;r++)
					for(int c=0;c<cols-_iRadius;c++)
						{
							row = mat(r,c);
							col = mat(r-_iRadius,c+_iRadius);
							result(row-min,col-min)++;
						}
			}
		if(_CoOccurenceAngle == DIR0 || _CoOccurenceAngle == ALL)
			{
				for(int r=0;r<rows;r++)
					for(int c=0;c<cols-_iRadius;c++)
						{
							row = mat(r,c);
							col = mat(r,c+_iRadius);
							result(row-min,col-min)++;
						}
			}
		return result;
	}

	double CoOccurence::getFeature(const Matrix<int>& mat,Feature feature, int k,int n)
	{
		int rows=mat.getRows();
		int cols=mat.getColumns();
		double result= 0.0;

		if(feature == MOMENT)
			{
				for(int r=0;r<rows;r++)
					for(int c=0;c<cols;c++)
						result += pow((r-c),k)*double(mat(r,c));
			}
		else if(feature == INVERSE_MOMENT)
			{
				for(int r=0;r<rows;r++)
					for(int c=0;c<cols;c++) 
						if(r!=c)result += pow((r-c),k)*double(mat(r,c));
			}
		else if(feature == CONTRAST)
			{
				for(int r=0;r<rows;r++)
					for(int c=0;c<cols;c++) 
						result += pow(double(abs(r-c)),double(k))*pow(double(mat(r,c)),n);
			}
		else if(feature == HOMOGENITY)
			{
				for(int r=0;r<rows;r++)
					for(int c=0;c<cols;c++) 
						result += double(mat(r,c))/(1+abs(r-c));
			}
		else if(feature == ENTROPY)
			{
				for(int r=0;r<rows;r++)
					for(int c=0;c<cols;c++)
						{
							int tmp = mat(r,c);
							if(tmp != 0)result -= double(tmp)*log(double(tmp));
						}
			}
		
		return result;
	}

	List<double> CoOccurence::getFeatureVector(const Matrix<int>& mat)
		throw (FeatureExtractionException&)
	{
		List<double> result(5);
		Matrix<int> tmp(getTransformedImage(mat));
		result += getFeature(tmp,MOMENT);
		result += getFeature(tmp,INVERSE_MOMENT);
		result += getFeature(tmp,CONTRAST);
		result += getFeature(tmp,HOMOGENITY);
		result += getFeature(tmp,ENTROPY);
		
		return result;
	}
}}
