diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fb4951552e13202ac749781b49e97a3e1786cd90..cac2832a522a6b4b7e59668c683ad9760493fa06 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -175,7 +175,6 @@ ENDIF() IF( ITK_FOUND AND OW_USE_ITK ) SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DOW_USE_ITK" CACHE STRING "" FORCE ) SET( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DOW_USE_ITK" CACHE STRING "" FORCE ) - SET( ITK_LIBRARIES "ITKCommon" ) ENDIF( ITK_FOUND AND OW_USE_ITK ) SET( CMAKE_CXX_FLAGS_RELWITHDEBINFO "-g -DDEBUG -O2" CACHE STRING "" FORCE ) diff --git a/src/dataHandler/test/WITKImageConversion_test.h b/src/dataHandler/test/WITKImageConversion_test.h index bc56ac2611aa0577c511c8719b0cd1ec42b0c117..2e7d53852c73c8b611b5eaca52fb39a8f2971933 100644 --- a/src/dataHandler/test/WITKImageConversion_test.h +++ b/src/dataHandler/test/WITKImageConversion_test.h @@ -45,7 +45,7 @@ static WLogger logger; static bool loggerInitialized = false; /** - * Test important functionality of WDataHandler class + * Test functionality of WITKConversion class. */ class WITKImageConversionTest : public CxxTest::TestSuite { diff --git a/src/modules/scalarSegmentation/CMakeLists.txt b/src/modules/scalarSegmentation/CMakeLists.txt index 48b023ce5efc9e5516ced6799fb4d37a1550d6b8..105a6a7c30f19907e2cf4a900ef5a41d1c22f078 100644 --- a/src/modules/scalarSegmentation/CMakeLists.txt +++ b/src/modules/scalarSegmentation/CMakeLists.txt @@ -10,8 +10,11 @@ SET( MODULE_NAME "OWmodule_${MODULE_NAME}" ) # prefix all module names w # Build module lib ADD_LIBRARY( ${MODULE_NAME} SHARED ${MODULES_SRC} ) -TARGET_LINK_LIBRARIES( ${MODULE_NAME} OWkernel ) - +IF( ITK_FOUND AND OW_USE_ITK ) + TARGET_LINK_LIBRARIES( ${MODULE_NAME} OWkernel ${ITK_LIBRARIES}) +ELSE() + TARGET_LINK_LIBRARIES( ${MODULE_NAME} OWkernel ) +ENDIF() IF(MSVC_IDE) SET_TARGET_PROPERTIES( ${MODULE_NAME} PROPERTIES PREFIX "../") ENDIF(MSVC_IDE) diff --git a/src/modules/scalarSegmentation/WMScalarSegmentation.cpp b/src/modules/scalarSegmentation/WMScalarSegmentation.cpp index bf89fecacd32d017e5d693e7085057d881f32f45..373ea53fb40f92a2df131c2734171bfcd8decc3f 100644 --- a/src/modules/scalarSegmentation/WMScalarSegmentation.cpp +++ b/src/modules/scalarSegmentation/WMScalarSegmentation.cpp @@ -90,6 +90,7 @@ void WMScalarSegmentation::properties() m_algos = boost::shared_ptr< WItemSelection >( new WItemSelection ); m_algos->addItem( "Simple Threshold", "" ); m_algos->addItem( "Watershed", "" ); + m_algos->addItem( "Otsu Threshold", "" ); m_algoType = m_properties->addProperty( "Seg Algo", "Choose a segmentation method.", m_algos->getSelectorFirst(), m_propCondition ); @@ -97,6 +98,10 @@ void WMScalarSegmentation::properties() m_threshold->setMax( 100.0 ); m_threshold->setMin( 0.0 ); + m_level = m_properties->addProperty( "Level", "Watershed level value for segmentation.", 10.0, m_propCondition ); + m_level->setMax( 100.0 ); + m_level->setMin( 0.0 ); + WModule::properties(); } @@ -133,24 +138,12 @@ void WMScalarSegmentation::moduleMain() WAssert( m_dataSet->getValueSet()->order() == 0, "" ); } - //bool propChanged = false; - //if( !m_algoType->changed() ) - //{ - //WPVGroup::PropertyConstIterator it; - //for( it = m_propGroups[ m_algoIndex ]->begin(); it != m_propGroups[ m_algoIndex ]->end(); ++it ) - //{ - //propChanged = propChanged || it->changed(); - //} - //} - //else - //{ - //WItemSelector w = m_algoType.get( true ); - //m_algoIndex = w.getItemIndexOfSelected( 0 ); - //propChanged = true; - //} - - bool propChanged = m_threshold->changed(); - if( m_dataSet && ( dataChanged || propChanged ) ) + bool algoChanged = m_algoType->changed(); + WItemSelector w = m_algoType->get( true ); + m_algoIndex = w.getItemIndexOfSelected( 0 ); + + bool propChanged = m_threshold->changed() || m_level->changed(); + if( m_dataSet && ( dataChanged || propChanged || algoChanged ) ) { // redo calculation doSegmentation(); @@ -167,11 +160,22 @@ void WMScalarSegmentation::activate() void WMScalarSegmentation::doSegmentation() { boost::shared_ptr< WValueSetBase > vs; + + debugLog() << m_algoIndex; + switch( m_algoIndex ) { case 0: vs = m_dataSet->getValueSet()->applyFunction( SimpleSegmentation( m_threshold->get( true ) ) ); break; +#ifdef OW_USE_ITK + case 1: + vs = m_dataSet->getValueSet()->applyFunction( WatershedSegmentation( m_level->get( true ), m_threshold->get( true ), m_dataSet ) ); + break; + case 2: + vs = m_dataSet->getValueSet()->applyFunction( OtsuSegmentation( m_dataSet ) ); + break; +#endif // OW_USE_ITK default: errorLog() << "Invalid algorithm selected." << std::endl; } diff --git a/src/modules/scalarSegmentation/WMScalarSegmentation.h b/src/modules/scalarSegmentation/WMScalarSegmentation.h index dd655e1ea2facef26274098922a07ae160aa7c39..c5bcdc003c9841096c65ca2c7b2ced35cb449eb6 100644 --- a/src/modules/scalarSegmentation/WMScalarSegmentation.h +++ b/src/modules/scalarSegmentation/WMScalarSegmentation.h @@ -31,11 +31,26 @@ #include "../../common/WItemSelection.h" #include "../../common/WItemSelector.h" +#include "../../dataHandler/WITKImageConversion.h" + #include "../../kernel/WModule.h" #include "../../kernel/WModuleInputData.h" #include "../../kernel/WModuleOutputData.h" #include "../../dataHandler/WDataSetScalar.h" +#ifdef OW_USE_ITK + +#include "itkWatershedImageFilter.h" +#include "itkOtsuThresholdImageFilter.h" + +// smoothing filters +#include "itkGradientAnisotropicDiffusionImageFilter.h" +// other +#include "itkCastImageFilter.h" +#include "itkGradientMagnitudeImageFilter.h" + +#endif // OW_USE_ITK + /** * First version of a module that implements 3D-image segmentation algorithms. * @@ -159,6 +174,9 @@ private: */ WPropDouble m_threshold; + //! The watershed level. + WPropDouble m_level; + //! A function object that implements a simple threshold segmentation. class SimpleSegmentation : public boost::static_visitor< boost::shared_ptr< WValueSetBase > > { @@ -186,20 +204,136 @@ private: //! the threshold double m_threshold; }; + +#ifdef OW_USE_ITK + //! + class WatershedSegmentation : public boost::static_visitor< boost::shared_ptr< WValueSetBase > > + { + public: + /** + * Constructor. + * \param t The threshold for segmentation. + */ + WatershedSegmentation( double level, double t, boost::shared_ptr< WDataSetScalar > ds ) // NOLINT + : m_level( level ), + m_threshold( t ), + m_dataset( ds ) + { + } + + /** + * Do the segmentation. + * + * \tparam T The integral data type. + * \param valueset The valueset to segment. + * \return A pointer to a new valueset. + */ + template< typename T > + boost::shared_ptr< WValueSetBase > operator() ( WValueSet< T > const* ) const; + + private: + //! the level + double m_level; + //! the threshold + double m_threshold; + //! the dataset + boost::shared_ptr< WDataSetScalar > m_dataset; + }; + + //! + class OtsuSegmentation : public boost::static_visitor< boost::shared_ptr< WValueSetBase > > + { + public: + /** + * Constructor. + * \param t The threshold for segmentation. + */ + OtsuSegmentation( boost::shared_ptr< WDataSetScalar > ds ) // NOLINT + : m_dataset( ds ) + { + } + + /** + * Do the segmentation. + * + * \tparam T The integral data type. + * \param valueset The valueset to segment. + * \return A pointer to a new valueset. + */ + template< typename T > + boost::shared_ptr< WValueSetBase > operator() ( WValueSet< T > const* v ) const; + + private: + //! the dataset + boost::shared_ptr< WDataSetScalar > m_dataset; + }; +#endif // OW_USE_ITK }; template< typename T > boost::shared_ptr< WValueSetBase > WMScalarSegmentation::SimpleSegmentation::operator() ( WValueSet< T > const* valueset ) const { std::vector< T > values( valueset->size() ); - for( std::size_t k = 0; k < valueset->size(); ++k ) { values[ k ] = ( static_cast< double >( valueset->getScalar( k ) ) < m_threshold * ( valueset->getMaximumValue() - valueset->getMinimumValue() ) / 100.0 + valueset->getMinimumValue() - ? static_cast< T >( 0 ) : static_cast< T >( 1 ) ); + ? static_cast< T >( 0 ) : static_cast< T >( 100 ) ); } return boost::shared_ptr< WValueSet< T > >( new WValueSet< T >( 0, 1, values, DataType< T >::type ) ); } +#ifdef OW_USE_ITK + +template< typename T > +boost::shared_ptr< WValueSetBase > WMScalarSegmentation::WatershedSegmentation::operator() ( WValueSet< T > const* ) const +{ + typedef itk::Image< T, 3 > ImgType; + typedef itk::Image< double, 3 > RealType; + typedef itk::Image< uint64_t, 3 > LabelType; // this might be a problem on 32-bit systems + typedef itk::Image< float, 3 > FinalType; + + typedef itk::GradientAnisotropicDiffusionImageFilter< ImgType, RealType > SmoothingType; + typedef itk::CastImageFilter< LabelType, FinalType > CastFilter; + typedef itk::GradientMagnitudeImageFilter< RealType, RealType > GradFilter; + typedef itk::WatershedImageFilter< RealType > WaterFilter; + + typename ImgType::Pointer img = makeImageFromDataSet< T >( m_dataset ); + typename SmoothingType::Pointer sm = SmoothingType::New(); + typename CastFilter::Pointer cf = CastFilter::New(); + typename GradFilter::Pointer gf = GradFilter::New(); + typename WaterFilter::Pointer ws = WaterFilter::New(); + + sm->SetNumberOfIterations( 10 ); + sm->SetTimeStep( 0.0625 ); + sm->SetConductanceParameter( 2.0 ); + sm->SetInput( img ); + gf->SetInput( sm->GetOutput() ); + ws->SetInput( gf->GetOutput() ); + ws->SetLevel( m_level / 100.0 ); + ws->SetThreshold( m_threshold / 100.0 ); + cf->SetInput( ws->GetOutput() ); + cf->Update(); + boost::shared_ptr< WDataSetScalar > res = makeDataSetFromImage< float >( cf->GetOutput() ); + return res->getValueSet(); +} + +template< typename T > +boost::shared_ptr< WValueSetBase > WMScalarSegmentation::OtsuSegmentation::operator() ( WValueSet< T > const* v ) const +{ + typedef itk::Image< T, 3 > ImgType; + typedef itk::OtsuThresholdImageFilter< ImgType, ImgType > Otsu; + + typename ImgType::Pointer img = makeImageFromDataSet< T >( m_dataset ); + typename Otsu::Pointer o = Otsu::New(); + o->SetInput( img ); + o->SetOutsideValue( v->getMaximumValue() ); + o->SetInsideValue( v->getMinimumValue() ); + o->Update(); + boost::shared_ptr< WDataSetScalar > res = makeDataSetFromImage< T >( o->GetOutput() ); + return res->getValueSet(); +} + +#endif // OW_USE_ITK + #endif // WMSCALARSEGMENTATION_H diff --git a/src/modules/subtractDataSetScalar/WMSubtractDataSetScalar.h b/src/modules/subtractDataSetScalar/WMSubtractDataSetScalar.h index f0041edd02ddac42d83d29e67d922a94bef5ea9a..121ce92af042a5010d9327d8b92d215d1802b7c4 100644 --- a/src/modules/subtractDataSetScalar/WMSubtractDataSetScalar.h +++ b/src/modules/subtractDataSetScalar/WMSubtractDataSetScalar.h @@ -27,6 +27,7 @@ #include #include +#include #include "../../kernel/WModule.h" #include "../../kernel/WModuleInputData.h" @@ -143,7 +144,7 @@ void WMSubtractDataSetScalar::subtractTyped() std::vector< T > values( m_first->getGrid()->size() ); for( std::size_t k = 0; k < m_first->getGrid()->size(); ++k ) { - values[ k ] = firstValueSet->rawData()[ k ] - secondValueSet->rawData()[ k ]; + values[ k ] = std::max( 0, firstValueSet->rawData()[ k ] - secondValueSet->rawData()[ k ] ); } VSPtr vs( new VS( 0, 1, values, DataType< T >::type ) ); m_result = boost::shared_ptr< WDataSetScalar >( new WDataSetScalar( vs, m_first->getGrid() ) );