/**------------------------------------------------------------------------
 * @file
 *
 * Copyright 2001 by the University of Toronto (UT).
 *
 *                       All Rights Reserved
 * 
 * Permission to copy and modify this software and its documentation 
 * only for internal use in your organization is hereby granted, 
 * provided that this notice is retained thereon and on all copies.  
 * UT makes no representations as to the suitability and operability 
 * of this software for any purpose.  It is provided "as is" without 
 * express or implied warranty.
 *
 * UT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
 * SHALL UT BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
 * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * No other rights, including for example, the right to redistribute 
 * this software and its documentation or the right to prepare 
 * derivative works, are granted unless specifically provided in a 
 * separate license agreement.
 *
 * Author: Diego Macrini
 * 
 * $Log: ImageProcessing.cpp,v $
 *
 *-----------------------------------------------------------------------*/
#include <functional>
#include <tools/connected.h>
#include "field.h"
#include <CImg/CImg.h>
#include "ImageProcessing.h"

struct MyComparator
{
	bool operator()(const float& a, const float& b) { return a == b; }
};

typedef std::vector<int> IntVector;

/*!
	@brief Removes non-maximum components
	
	Finds the largest white component and the largest black component. It removes the 
	remaining components. Note: if there are "rings" in the image that must be removed, then
	this function must be called multiple times until it returns 2.

	It uses the connected components funtion from http://people.csail.mit.edu/rahimi/connected/
	
	@return the orginal number of components in the image. If greater than 2, it means that
	some components were removed.
*/
int RemoveNonMaxComponents(cimg_library::CImg<float>& img)
{
	cimg_library::CImg<int> pixLbl(img.dimx(), img.dimy());
	ConnectedComponents cc(10); // this number is just an initial size that can grow if necessary

	// find components. this is a template function whose params' types get defined implicitly
#ifndef WIN32
	int n = cc.connected(img.ptr(), pixLbl.ptr(), img.dimx(), img.dimy(),
		 std::equal_to<float>(),
		 constant<bool,true>());
#else
	int n = cc.connected(img.ptr(), pixLbl.ptr(), img.dimx(), img.dimy(),
		 std::equal_to<float>(),
		 true);
#endif
	
	//pixLbl.save_ascii("labels.raw");
	
	if (n > 2)
	{	
		IntVector whiteLbls(n, 0), blackLbls(n, 0); 
		int i, maxWhiteLbl = 0, maxBlackLbl = 0, maxWhiteSz = 0, maxBlackSz = 0;
		
		// count number of black and white labels
		cimg_mapXY(img,x,y)
		{
			if (img(x,y) == 0)
				blackLbls[pixLbl(x,y)]++;
			else
				whiteLbls[pixLbl(x,y)]++;
		}
		
		// find the largest white group and the largest black group
		for (i = 0; i < n; i++)
		{
			if (whiteLbls[i] > maxWhiteSz) {
				maxWhiteSz = whiteLbls[i];
				maxWhiteLbl = i;
			}
			
			if (blackLbls[i] > maxBlackSz) {
				maxBlackSz = blackLbls[i];
				maxBlackLbl = i;
			}
		}
		
		// remove non-maximum components
		cimg_mapXY(img,xx,yy)
		{
			i = pixLbl(xx,yy);
			
			if (i != maxWhiteLbl && i != maxBlackLbl)
				img(xx,yy) = (img(xx,yy) == 0) ? 255:0;
		}
	}
	
	return n;
}

/*!
	@brief Returns a pointer to a FIELD<float> object with a copy of img.

	The returned pointer must be deleted by the last user of the FIELD.
*/
FIELD<float>* CopyImageToField(const cimg_library::CImg<float>& img)
{
	FIELD<float>* pField = new FIELD<float>(img.dimx(), img.dimy());
	float* const p = pField->data();
	
	for (int y = 0; y < img.dimy(); y++)
		for (int x = 0; x < img.dimx(); x++)
			*(p + y * img.dimx() + x) = img(x, y);

	return pField;
}
