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

#ifndef _SEGMENTATION_H
#define _SEGMENTATION_H

#include <List.h>
#include <Exception.h>
#include <Matrix.h>

#include "../Classifier.h"
#include "../Histogram.h"

namespace prapi { namespace texture {

	/**
	 * KernelSegmentator performs supervised segmentation on an matrix.
	 * On each pixel of an input matrix, classifier constructs a sample
	 * that is classified using a given classifier. The classification
	 * result is placed on an output matrix. The sample is constructed by
	 * placing a kernel over the input pixel and calculating a histogram
	 * over it. The segmentation problem is presented as a layered
	 * matrix. To get a histogram bin index for a pixel, the segmentator
	 * collects the corresponding pixels from each layer to a vector and
	 * consults a LayerCombiner to modify the local histogram.
	 **/
	class KernelSegmentator
	{
	public:
		/**
		 * Create a new Segmentator.
		 *
		 * @param classifier the classifier to be used in classifying pixels
		 * @param length the length of the histograms that are created
		 * @param kernel a kernel matrix with ones on the pixels that are
		 * considered in building up the local histogram.
		 * @param combiner a LayerCombiner that is used to modify the
		 * local histogram
		 **/
		KernelSegmentator(Classifier<int>& classifier,
											Matrix<char> kernel,
											const MultiFeatureHistogram::LayerCombiner& combiner) :
			_classifier(classifier), _kernel(kernel), _layerCombiner(combiner) {}

		/**
		 * Assign each pixel its classification.
		 *
		 * @param mats matrix layers.
		 * @param combine how to combine layers
		 **/
		Matrix<int> getSegmentation(const util::List<Matrix<int> >& mats);

		/**
		 * Create a circular kernel. The result is a
		 * (radius*2+1)x(radius*2+1) matrix with a "disk" of ones in the
		 * center.
		 *
		 * @param radius the radius of the kernel disk
		 **/
		static Matrix<char> createCircularKernel(int radius);
		/**
		 * Create a square kernel. The result is a
		 * (radius*2+1)x(radius*2+1) matrix with with all entries set to
		 * ones.
		 *
		 * @param radius the radius of the kernel
		 **/
		static Matrix<char> createSquareKernel(int radius);
		
		/**
		 * Get the fraction of misclassified pixels given a ground truth
		 * matrix. The ground truth matrix should contain the correct
		 * classifications for the pixels.
		 *
		 * @exception InvalidArgumentException& if the matrices are of
		 * different size
		 **/
		static double getError(const Matrix<int>& segmentation, const Matrix<int>& groundTruth)
			throw (InvalidArgumentException&);

	private:
		Classifier<int>& _classifier;
		Matrix<char> _kernel;
		int _iRadius;
		const MultiFeatureHistogram::LayerCombiner& _layerCombiner;
	};
	
}}

#endif
