// This function is designed to compute the optimal threshold using OTSU method;
// this algoritm is implemented by xiao liang based on ITK's OTSU algorithm
double VolumeProcess::getXiaoLiangOtsuThreshold(ImageType::Pointer img)
{
	if(!img)
		return 0;

	double threshold = 0;
	unsigned char m_min = 255;
	unsigned char m_max = 0;
	double m_mean = 0.0;
	double m_variance = 0.0;

	ImageType::RegionType region = img->GetBufferedRegion();
	double numPix = region.GetSize(2)*region.GetSize(1)*region.GetSize(0);

	//Get min, max, and mean:
	itk::ImageRegionIterator< ImageType > itr( img, region );
	for(itr.GoToBegin(); !itr.IsAtEnd(); ++itr)
	{
		double val = itr.Get();
		if(val > m_max) m_max = val;
		if(val < m_min) m_min = val;
		m_mean += itr.Get();
	}
	m_mean  = m_mean/numPix;

	if(debug)
		std::cerr << "Max = " << (int)m_max << ", Min = " << (int)m_min << std::endl;

	//Do a sanity check
	if ( m_min >= m_max)
    {
		threshold=m_min;
		return threshold;
    }

	//Get the variance:
	for(itr.GoToBegin(); !itr.IsAtEnd(); ++itr)
	{
		double val = (double)itr.Get();
		m_variance += (val-m_mean)*(val-m_mean);
	}
	//These were not Xiao Liang's version:
	//m_variance = m_variance / numPix;
	//m_variance = sqrt(m_variance);

	threshold = m_mean - (m_variance/30); 
    // this step is only initialized a good experimental value for m_Threshold, because the 3D image
    // is sparse, there are lots of zero values; 

	//Create a histogram & init to zero
	double relativeFrequency[m_NumberOfHistogramBins];
	for ( unsigned char j = 0; j < m_NumberOfHistogramBins; j++ )
    {
       relativeFrequency[j] = 0.0;
    }

	double binMultiplier = (double)m_NumberOfHistogramBins/(double)(m_max-m_min);
	if(debug)
		std::cerr << "binMultiplier = " << binMultiplier << std::endl;

	unsigned int binNumber;
	for(itr.GoToBegin(); !itr.IsAtEnd(); ++itr)
	{
		double val = itr.Get();
		if ( val == m_min ) 
		{
			binNumber = 0;
		}
		else
		{
			binNumber = (unsigned int)(((val-m_min)*binMultiplier) - 1);
			if ( binNumber == m_NumberOfHistogramBins ) // in case of rounding errors
			{
				binNumber -= 1;
			}
		}
		relativeFrequency[binNumber] += 1.0;
	}

	// normalize the frequencies
	double totalMean = 0.0;
	for ( unsigned char j = 0; j < m_NumberOfHistogramBins; j++ )
    {
		relativeFrequency[j] /= numPix;
		totalMean += (j+1) * relativeFrequency[j];
    }

	// compute Otsu's threshold by maximizing the between-class variance
	double freqLeft = relativeFrequency[0];
	double meanLeft = 1.0;
	double meanRight = ( totalMean - freqLeft ) / ( 1.0 - freqLeft );

	double maxVarBetween = freqLeft * ( 1.0 - freqLeft ) * sqrt( meanLeft - meanRight );
	int maxBinNumber = 0;

	double freqLeftOld = freqLeft;
	double meanLeftOld = meanLeft;

	for ( unsigned char j = 1; j < m_NumberOfHistogramBins; j++ )
    {
		freqLeft += relativeFrequency[j];
		meanLeft = ( ((meanLeftOld * freqLeftOld)+(j+1)) * relativeFrequency[j] ) / freqLeft;
		if (freqLeft == 1.0)
		{
			meanRight = 0.0;
		}
		else
		{
			meanRight = ( totalMean - meanLeft * freqLeft ) / ( 1.0 - freqLeft );
		}
		
		double varBetween = freqLeft * ( 1.0 - freqLeft ) * sqrt( meanLeft - meanRight );
		if ( varBetween > maxVarBetween )
		{
			maxVarBetween = varBetween;
			maxBinNumber = j;
		}

		// cache old values
		freqLeftOld = freqLeft;
		meanLeftOld = meanLeft; 
    } 

	threshold = double( m_min + ( maxBinNumber + 1 ) / binMultiplier );
	return threshold; 
}
bool VolumeProcess::DialateImage(int iterations)
{
	int border = 2;

	ImageType::Pointer tempImg = ImageType::New();
	tempImg->SetRegions( m_outputImage->GetLargestPossibleRegion() );
	tempImg->Allocate();
	tempImg->FillBuffer(0);

	ImageType::RegionType fullRegion = m_outputImage->GetBufferedRegion();
	ImageType::RegionType borderRegion;
	borderRegion.SetIndex(0, fullRegion.GetIndex(0)+border);
	borderRegion.SetIndex(1, fullRegion.GetIndex(1)+border);
	borderRegion.SetIndex(2, fullRegion.GetIndex(2)+border);
	borderRegion.SetSize(0, fullRegion.GetSize(0)-(2*border));
	borderRegion.SetSize(1, fullRegion.GetSize(1)-(2*border));
	borderRegion.SetSize(2, fullRegion.GetSize(2)-(2*border));
	itk::ImageRegionIteratorWithIndex< ImageType > itr( m_outputImage, borderRegion );
	while(iterations > 0)
	{
		for(itr.GoToBegin(); !itr.IsAtEnd(); ++itr)
		{
			double blockMax = itr.Get();
			for(int k=-1; k<=1; k++)
			{
				for(int j=-1; j<=1; j++)
				{
					for(int i=-1; i<=1; i++)
					{
						ImageType::IndexType index = itr.GetIndex();
						index[0] += i;
						index[1] += j;
						index[2] += k;
						ImageType::PixelType pix = m_outputImage->GetPixel(index);
						if((double)pix > blockMax) 
						{
							blockMax = (double)pix;
						}
					}
				}
			}
			// Keep the peak of the original intensity
			if (blockMax == itr.Get() && blockMax != 0)
            {
				blockMax = blockMax + 1;
            }
			tempImg->SetPixel(itr.GetIndex(), blockMax);
		}

		//Copy temp img back to image for next dialation
		itk::ImageRegionIterator< ImageType > itr1( tempImg, tempImg->GetLargestPossibleRegion() );
		itk::ImageRegionIterator< ImageType > itr2( m_outputImage, m_outputImage->GetLargestPossibleRegion() );
		for(itr1.GoToBegin(), itr2.GoToBegin() ; !itr1.IsAtEnd(); ++itr1, ++itr2)
		{
			itr2.Set( itr1.Get() );
		}

		iterations--;
	}
	
	if(debug)
		std::cerr << "Dialation Done" << std::endl;
	return true;
}