/*********************************************************************
 * 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 $
 *********************************************************************/

#ifndef _COOCCURENCE_H
#define _COOCCURENCE_H

#include <Matrix.h>
#include "../ImageTransform.h"
#include "../FeatureExtractor.h"

#include <math.h>

namespace prapi { namespace texture {
	/**
	 * A class for calculating co-occurence matrices.
	 **/
	class CoOccurence : public ImageTransform<int,int>, public FeatureExtractor<double, util::Matrix<int> >
	{
	public:
		/**
		 * This enumeration specifies the angle of made cooccurence matrix
		 * The posibilities are: DIR0,DIR45,DIR90,DIR135 and ALL.
		 **/
		enum CoOccurenceAngle { DIR0, DIR45, DIR90, DIR135 , ALL };    

		/**
		 * An enumeration for the features calculated from co-occurrence matrices.
		 * Possibilities:
		 * <pre>
		 * MOMENT          - The k element difference moment.[ Sum(Sum((i-j)'k*mat(i,j))) ]
		 * INVERSE_MOMENT  - The k element inverse difference moment. [ Sum(Sum(mat(i,j)/(i-j)'k ]
		 * CONTRAST        - The contrast. [ Sum(Sum( |i-j|'k*mat(i,j)'n ]
		 * HOMOGENITY      - Homogenity. [ Sum(Sum(mat(i,j)/(i+ |i-j|)))
		 * ENTROPY         - Entropy. [ -Sum(Sum(mat(i,j)*log(mat(i,j)))) ]
		 * </pre>
		 **/
		enum Feature { MOMENT, INVERSE_MOMENT, CONTRAST, HOMOGENITY, ENTROPY };
	
		/**
		 * The constructor of CoOccurence matrix.
		 *
		 * @param angle The Ange on which direction the matrix is wanted.
		 * @param radius The radius how far the matrix will be calculated.
		 **/
		CoOccurence(CoOccurenceAngle angle, int radius): _CoOccurenceAngle(angle),_iRadius(radius) {}
		/**
		 * Set the angle.
		 **/
		void setAngle(CoOccurenceAngle angle){_CoOccurenceAngle=angle;}
		/**
		 * Set the radius.
		 **/
		void setRadius(int radius){_iRadius=radius;}
		/**
		 * Get the angle.
		 **/
		CoOccurenceAngle getAngle(){return _CoOccurenceAngle;}
		/**
		 * Get the radius.
		 **/
		int getRadius(){return _iRadius;}

		/**
		 * The function makes the co-occurence matrix for the specified
		 * direction(s). The returned matrices will be of size NxN where
		 * N&nbsp;=&nbsp;min(256,max(mat)).
		 *
		 * @param mat The matrix from which the matrix wanted to calculate.
		 * @return a list of co-occurrence matrices for the wanted directions
		 **/
		util::Matrix<int> getTransformedImage(const util::Matrix<int>& mat) throw (ImageTransformException&);
		/**
		 * Calculate a feature from a co-occurrence matrix.
		 *
		 * @param mat The covariance matrix where the feature will be calculated.
		 * @param feature The feature which wanted to calculate.
		 * @param k The power of (i-j).
		 * @param n The power of mat(i,j) in contrast feature.
		 **/
		double getFeature(const util::Matrix<int>& mat, Feature feature, int k=1, int n=1);
		/**
		 * Create a feature vector containing all co-occurrence features
		 * listed in the Feature enumeration.
		 *
		 * @param mat The matrix from which the statistics will be
		 * calculated.
		 **/
		util::List<double> getFeatureVector(const util::Matrix<int>& mat) throw (FeatureExtractionException&);
		
	private:
		/**
		 * For the direction.
		 **/
		CoOccurenceAngle _CoOccurenceAngle;
		/**
		 * For The radius.
		 **/
		int _iRadius;
	};
}}
#endif
