/**
* Compute the granulometric function with a smarter algorithm that uses the medial axis (see report for more details)
*
* @param image The input image 
*
* @param granuloImage The image where we store the granulometric function values
*/
unsigned int granuloWithMedialAxis(myLittleImage& image, myLittleImage& granuloImage)
{
	PointPredicate predicate(image,0);
	Z2i::L2PowerMetric l2power;
	unsigned int nbBalls = 0;
	unsigned int nbPoints = 0;
	DTL2 dtL2(image.domain(), predicate, l2Metric);
    Map power(image.domain(), dtL2, l2power);
	RMA::Type rma = RMA::getReducedMedialAxisFromPowerMap(power);
	for (myLittleImage::Domain::ConstIterator it = granuloImage.domain().begin(); it != granuloImage.domain().end(); ++it)
	{
		if (dtL2(*it) > 0) // Inside the image
			nbPoints++;

		if (rma(*it) > 0) // Center of a ball
		{
			nbBalls++;
			unsigned int radius = static_cast<unsigned int>(dtL2(*it));
			RealPoint center = *it;
			ImplicitBall<Space> ball(center,radius);
			// To iterate on the sphere, we build a tangent bounding box around it and iterate into the box
			Point top = center + Point::diagonal(radius +1);
			Point bottom = center - Point::diagonal(radius +1);
			Domain sphereDomain(bottom,top);
			for (Domain::ConstIterator ite = sphereDomain.begin(); ite != sphereDomain.end(); ++ite)
			{
				if ((granuloImage.domain().isInside(*ite)) // Point inside the image
					&& (ball(*ite) > 0)					  // Point inside the ball
					&& (granuloImage(*ite) < radius)) 	  // Granulometric value has to be updated
				{
					granuloImage.setValue(*ite,radius);
				}
			}
		}
	}
	trace.info() << "Granulometric function computed with " << nbBalls << " balls" << endl;
	return nbPoints;
}