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

#include "Segmentation.h"

namespace prapi { namespace texture {

	using namespace util;
	
	Matrix<int> KernelSegmentator::getSegmentation(const List<Matrix<int> >& mats)
	{
		int rows = mats[0].getRows(), cols = mats[0].getColumns();
		Matrix<int> result(rows,cols);
		int r, c, x, y;
		int len = mats.getLength();
		List<int> pixels(len);
		pixels.setLength(len);

		Sample<int> sample;
		int histLength = _layerCombiner.getHistogramLength();
		sample.featureVector().setLength(histLength);

		
		int kRows = _kernel.getColumns();
		int kCols = _kernel.getRows();
		int centerX = kCols / 2;
		int centerY = kRows / 2;
		
		AllItems(r,c,mats[0])
			{
				memset(sample.featureVector().getData(),0,sizeof(int)*histLength);

				AllItems(y,x,_kernel)
					{
						int row = r+x-centerX, col=c+y-centerY;
						if (_kernel(y,x) &&
								row >= 0 && row < rows &&
								col >= 0 && col < cols)
							{
								for (int i=0;i<len;i++)
									pixels[i] = mats[i](row,col);
								_layerCombiner.modifyHistogram(pixels,sample.featureVector());
							}
					}
				//cerr << sample << endl;
				result(r,c) = _classifier.getClassification(sample);
			}
		return result;
	}

	Matrix<char> KernelSegmentator::createCircularKernel(int radius)
	{
		Matrix<char> result(radius*2+1);
		for (int x=-radius;x<=radius;x++)
			{
				int rad = (int)(sqrt(radius*radius-x*x)+0.5);
				for (int y=-rad;y<=rad;y++)
					result(y+radius,x+radius) = 1;
			}
		return result;
	}
	
	Matrix<char> KernelSegmentator::createSquareKernel(int radius)
	{
		Matrix<char> result(radius*2+1);
		result = 1;
		return result;
	}
	
	double KernelSegmentator::getError(const Matrix<int>& segmentation, const Matrix<int>& groundTruth)
		throw (InvalidArgumentException&)
	{
		if (segmentation.getRows() != groundTruth.getRows() ||
				segmentation.getColumns() != groundTruth.getColumns())
			throw InvalidArgumentException("KernelSegmentator::getError(const Matrix<int>&, const Matrix<int>&): matrix sizes do not match.");

		double result = 0;
		const int* sData = segmentation.getData(), *gData = groundTruth.getData();
		int size = segmentation.getRows() * segmentation.getColumns();
		for (int i=size;i--;sData++,gData++)
			if (*sData != *gData)
				result += 1;

		return result/size;
	}
}}
