/*========================================================================= Program: vv http://www.creatis.insa-lyon.fr/rio/vv Authors belong to: - University of LYON http://www.universite-lyon.fr/ - Léon Bérard cancer center http://www.centreleonberard.fr - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the copyright notices for more information. It is distributed under dual licence - BSD See included LICENSE.txt file - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html ===========================================================================*/ #ifndef __clitkExplosionControlledThresholdConnectedImageFilter_txx #define __clitkExplosionControlledThresholdConnectedImageFilter_txx #include "clitkExplosionControlledThresholdConnectedImageFilter.h" #include "itkBinaryThresholdImageFunction.h" #include "itkFloodFilledImageFunctionConditionalIterator.h" #include "itkShapedFloodFilledImageFunctionConditionalIterator.h" #include "itkProgressReporter.h" namespace clitk { //-------------------------------------------------------------------- /** * Constructor */ template ExplosionControlledThresholdConnectedImageFilter ::ExplosionControlledThresholdConnectedImageFilter() { m_Lower = itk::NumericTraits::NonpositiveMin(); m_Upper = itk::NumericTraits::max(); m_FinalLower = itk::NumericTraits::NonpositiveMin(); m_FinalUpper = itk::NumericTraits::max(); m_AdaptLowerBorder=false; m_AdaptUpperBorder=false; m_MaximumUpperThreshold=itk::NumericTraits::max(); m_MinimumLowerThreshold=itk::NumericTraits::NonpositiveMin(); m_Multiplier=2.0; m_ReplaceValue = itk::NumericTraits::One; m_MinimumThresholdStepSize=itk::NumericTraits::One; m_ThresholdStepSize=64; m_Verbose=false; m_FullyConnected=false; m_MinimumSize=5000; } //-------------------------------------------------------------------- //-------------------------------------------------------------------- template void ExplosionControlledThresholdConnectedImageFilter ::ClearSeeds() { if( this->m_Seeds.size() > 0 ) { this->m_Seeds.clear(); this->Modified(); } } //-------------------------------------------------------------------- //-------------------------------------------------------------------- template void ExplosionControlledThresholdConnectedImageFilter ::SetSeed(const IndexType & seed) { this->ClearSeeds(); this->AddSeed ( seed ); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- template void ExplosionControlledThresholdConnectedImageFilter ::AddSeed ( const IndexType & seed ) { this->m_Seeds.push_back ( seed ); this->Modified(); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- /** * Standard PrintSelf method. */ template void ExplosionControlledThresholdConnectedImageFilter ::PrintSelf(std::ostream& os, itk::Indent indent) const { this->Superclass::PrintSelf(os, indent); os << indent << "Upper: " << static_cast::PrintType>(m_Upper) << std::endl; os << indent << "Lower: " << static_cast::PrintType>(m_Lower) << std::endl; os << indent << "ReplaceValue: " << static_cast(m_Multiplier) << std::endl; os << indent << "ReplaceValue: " << static_cast::PrintType>(m_ReplaceValue) << std::endl; } //-------------------------------------------------------------------- //-------------------------------------------------------------------- template void ExplosionControlledThresholdConnectedImageFilter ::GenerateInputRequestedRegion() { Superclass::GenerateInputRequestedRegion(); if ( this->GetInput() ) { InputImagePointer image = const_cast< InputImageType * >( this->GetInput() ); image->SetRequestedRegionToLargestPossibleRegion(); } } //-------------------------------------------------------------------- //-------------------------------------------------------------------- template void ExplosionControlledThresholdConnectedImageFilter ::EnlargeOutputRequestedRegion(itk::DataObject *output) { Superclass::EnlargeOutputRequestedRegion(output); output->SetRequestedRegionToLargestPossibleRegion(); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- template void ExplosionControlledThresholdConnectedImageFilter ::GenerateData() { typename Superclass::InputImageConstPointer inputImage = this->GetInput(); typename Superclass::OutputImagePointer outputImage = this->GetOutput(); // Zero the output outputImage->SetBufferedRegion( outputImage->GetRequestedRegion() ); outputImage->Allocate(); outputImage->FillBuffer ( itk::NumericTraits::Zero ); //-------------------------------------------------- // Get initial region size //-------------------------------------------------- typedef itk::BinaryThresholdImageFunction FunctionType; //typedef itk::ShapedFloodFilledImageFunctionConditionalIterator IteratorType; typedef itk::FloodFilledImageFunctionConditionalIterator IteratorType; typename FunctionType::Pointer function = FunctionType::New(); function->SetInputImage ( inputImage ); function->ThresholdBetween ( m_Lower, m_Upper ); IteratorType it = IteratorType ( outputImage, function, m_Seeds ); //it.SetFullyConnected(m_FullyConnected); unsigned int initialSize=0; it.GoToBegin(); while( !it.IsAtEnd()) { ++initialSize; ++it; } if (m_Verbose) std::cout<<"Initial region size using thresholds ["< m_MinimumLowerThreshold) && ( (unsigned int) currentSize <= (unsigned int )m_Multiplier* previousSize) ) ) { // Update threshold currentLower-=m_ThresholdStepSize; function->ThresholdBetween(currentLower, m_Upper); // Get current region size previousSize=currentSize; currentSize=0; IteratorType it = IteratorType ( outputImage, function, m_Seeds ); it.GoToBegin(); while( !it.IsAtEnd()) { ++currentSize; ++it; } if (m_Verbose) std::cout<<"Decreasing lower threshold to "< m_Multiplier*(double) previousSize) { // Raise lower threshold if (m_Verbose) std::cout<<"Explosion detected, adapting lower threshold ..."<m_MinimumThresholdStepSize) { currentStepSize/=2; currentLower-=currentStepSize; // Get current region size currentSize=0; IteratorType it = IteratorType ( outputImage, function, m_Seeds ); it.GoToBegin(); while( !it.IsAtEnd()) { ++currentSize; ++it; } if (m_Verbose) std::cout<<"Adapting lower threshold to "< m_Multiplier* (double) previousSize) currentLower+=currentStepSize; // No explosion: adapt previous else previousSize=currentSize; } // Converged m_FinalLower=currentLower; if (m_Verbose) std::cout<<"Final lower threshold (precision="<ThresholdBetween(m_Lower,currentUpper); // Get current region size previousSize=currentSize; currentSize=0; IteratorType it = IteratorType ( outputImage, function, m_Seeds ); it.GoToBegin(); while( !it.IsAtEnd()) { ++currentSize; ++it; } if (m_Verbose) std::cout<<"Increasing upper threshold to "< m_Multiplier* (double) previousSize) { // Lower upper threshold if (m_Verbose) std::cout<<"Explosion detected, adapting upper threshold ..."<m_MinimumThresholdStepSize) { currentStepSize/=2; currentUpper+=currentStepSize; // Get current region size currentSize=0; function->ThresholdBetween(m_Lower,currentUpper); IteratorType it = IteratorType ( outputImage, function, m_Seeds ); it.GoToBegin(); while( !it.IsAtEnd()) { ++currentSize; ++it; } if (m_Verbose) std::cout<<"Adapting upper threshold to "< m_Multiplier* (double) previousSize) currentUpper-=currentStepSize; // No explosion: adapt previous else previousSize=currentSize; } // Converged m_FinalUpper=currentUpper; if (m_Verbose) std::cout<<"Final upper threshold (precision="<ThresholdBetween(m_FinalLower, m_FinalUpper); IteratorType it2 = IteratorType ( outputImage, function, m_Seeds ); it2.GoToBegin(); while( !it2.IsAtEnd()) { it2.Set(m_ReplaceValue); ++it2; } } //-------------------------------------------------------------------- } // end namespace clitk #endif