// 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; }