From e008d74b0ecdc4ca2eaae8c429901a78f9ef5c31 Mon Sep 17 00:00:00 2001 From: dsarrut Date: Wed, 30 Jun 2010 06:09:06 +0000 Subject: [PATCH] some segmentation tools (most from jef) --- segmentation/CMakeLists.txt | 51 ++ .../clitkConnectedComponentLabeling.cxx | 44 ++ .../clitkConnectedComponentLabeling.ggo | 20 + ...kConnectedComponentLabelingGenericFilter.h | 76 +++ ...onnectedComponentLabelingGenericFilter.txx | 120 +++++ segmentation/clitkExtractBones.cxx | 40 ++ segmentation/clitkExtractBones.ggo | 34 ++ segmentation/clitkExtractBonesFilter.h | 189 ++++++++ segmentation/clitkExtractBonesFilter.txx | 263 +++++++++++ segmentation/clitkExtractBonesGenericFilter.h | 70 +++ .../clitkExtractBonesGenericFilter.txx | 98 ++++ segmentation/clitkExtractImageFilter.h | 98 ++++ segmentation/clitkExtractImageFilter.txx | 259 +++++++++++ segmentation/clitkExtractLung.cxx | 44 ++ segmentation/clitkExtractLung.ggo | 51 ++ segmentation/clitkExtractLungFilter.h | 247 ++++++++++ segmentation/clitkExtractLungFilter.txx | 439 ++++++++++++++++++ segmentation/clitkExtractLungGenericFilter.h | 70 +++ .../clitkExtractLungGenericFilter.txx | 105 +++++ segmentation/clitkExtractLymphStations.cxx | 44 ++ segmentation/clitkExtractLymphStations.ggo | 27 ++ .../clitkExtractLymphStationsFilter.h | 147 ++++++ .../clitkExtractLymphStationsFilter.txx | 286 ++++++++++++ .../clitkExtractLymphStationsGenericFilter.h | 70 +++ ...clitkExtractLymphStationsGenericFilter.txx | 99 ++++ segmentation/clitkExtractMediastinum.cxx | 44 ++ segmentation/clitkExtractMediastinum.ggo | 34 ++ segmentation/clitkExtractMediastinumFilter.h | 152 ++++++ .../clitkExtractMediastinumFilter.txx | 263 +++++++++++ .../clitkExtractMediastinumGenericFilter.h | 70 +++ .../clitkExtractMediastinumGenericFilter.txx | 102 ++++ segmentation/clitkExtractPatient.cxx | 43 ++ segmentation/clitkExtractPatient.ggo | 53 +++ segmentation/clitkExtractPatientFilter.h | 210 +++++++++ segmentation/clitkExtractPatientFilter.txx | 313 +++++++++++++ .../clitkExtractPatientGenericFilter.cxx | 55 +++ .../clitkExtractPatientGenericFilter.h | 69 +++ .../clitkExtractPatientGenericFilter.txx | 95 ++++ segmentation/clitkFillMask.cxx | 45 ++ segmentation/clitkFillMask.ggo | 13 + segmentation/clitkFillMaskGenericFilter.cxx | 78 ++++ segmentation/clitkFillMaskGenericFilter.h | 104 +++++ segmentation/clitkFillMaskGenericFilter.txx | 201 ++++++++ segmentation/clitkTestFilter.cxx | 211 +++++++++ segmentation/clitkTestFilter.ggo | 16 + 45 files changed, 5162 insertions(+) create mode 100644 segmentation/CMakeLists.txt create mode 100644 segmentation/clitkConnectedComponentLabeling.cxx create mode 100644 segmentation/clitkConnectedComponentLabeling.ggo create mode 100644 segmentation/clitkConnectedComponentLabelingGenericFilter.h create mode 100644 segmentation/clitkConnectedComponentLabelingGenericFilter.txx create mode 100644 segmentation/clitkExtractBones.cxx create mode 100644 segmentation/clitkExtractBones.ggo create mode 100644 segmentation/clitkExtractBonesFilter.h create mode 100644 segmentation/clitkExtractBonesFilter.txx create mode 100644 segmentation/clitkExtractBonesGenericFilter.h create mode 100644 segmentation/clitkExtractBonesGenericFilter.txx create mode 100644 segmentation/clitkExtractImageFilter.h create mode 100644 segmentation/clitkExtractImageFilter.txx create mode 100644 segmentation/clitkExtractLung.cxx create mode 100644 segmentation/clitkExtractLung.ggo create mode 100644 segmentation/clitkExtractLungFilter.h create mode 100644 segmentation/clitkExtractLungFilter.txx create mode 100644 segmentation/clitkExtractLungGenericFilter.h create mode 100644 segmentation/clitkExtractLungGenericFilter.txx create mode 100644 segmentation/clitkExtractLymphStations.cxx create mode 100644 segmentation/clitkExtractLymphStations.ggo create mode 100644 segmentation/clitkExtractLymphStationsFilter.h create mode 100644 segmentation/clitkExtractLymphStationsFilter.txx create mode 100644 segmentation/clitkExtractLymphStationsGenericFilter.h create mode 100644 segmentation/clitkExtractLymphStationsGenericFilter.txx create mode 100644 segmentation/clitkExtractMediastinum.cxx create mode 100644 segmentation/clitkExtractMediastinum.ggo create mode 100644 segmentation/clitkExtractMediastinumFilter.h create mode 100644 segmentation/clitkExtractMediastinumFilter.txx create mode 100644 segmentation/clitkExtractMediastinumGenericFilter.h create mode 100644 segmentation/clitkExtractMediastinumGenericFilter.txx create mode 100644 segmentation/clitkExtractPatient.cxx create mode 100644 segmentation/clitkExtractPatient.ggo create mode 100644 segmentation/clitkExtractPatientFilter.h create mode 100644 segmentation/clitkExtractPatientFilter.txx create mode 100644 segmentation/clitkExtractPatientGenericFilter.cxx create mode 100644 segmentation/clitkExtractPatientGenericFilter.h create mode 100644 segmentation/clitkExtractPatientGenericFilter.txx create mode 100644 segmentation/clitkFillMask.cxx create mode 100644 segmentation/clitkFillMask.ggo create mode 100644 segmentation/clitkFillMaskGenericFilter.cxx create mode 100644 segmentation/clitkFillMaskGenericFilter.h create mode 100644 segmentation/clitkFillMaskGenericFilter.txx create mode 100644 segmentation/clitkTestFilter.cxx create mode 100644 segmentation/clitkTestFilter.ggo diff --git a/segmentation/CMakeLists.txt b/segmentation/CMakeLists.txt new file mode 100644 index 0000000..dfa795b --- /dev/null +++ b/segmentation/CMakeLists.txt @@ -0,0 +1,51 @@ +#========================================================= + +INCLUDE(${PROJECT_SOURCE_DIR}/cmake/common.cmake) + +#========================================================= + +SET( CMAKE_VERBOSE_MAKEFILE off) + +#========================================================= + +WRAP_GGO(clitkSegmentationFilters_GGO_C + clitkFillMask.ggo + clitkConnectedComponentLabeling.ggo + clitkExtractLung.ggo + clitkExtractPatient.ggo + clitkExtractBones.ggo + clitkExtractMediastinum.ggo + clitkExtractLymphStations.ggo +) + +SET(clitkSegmentationFilters_SRC + ${clitkSegmentationFilters_GGO_C} +) + +ADD_LIBRARY(clitkSegmentationFilters STATIC ${clitkSegmentationFilters_SRC}) + +ADD_EXECUTABLE(clitkTestFilter clitkTestFilter.cxx clitkTestFilter_ggo.c) +TARGET_LINK_LIBRARIES(clitkTestFilter clitkCommon ITKIO clitkSegmentationFilters ITKStatistics) + +## Segmentation part + +ADD_EXECUTABLE(clitkConnectedComponentLabeling clitkConnectedComponentLabeling.cxx) +TARGET_LINK_LIBRARIES(clitkConnectedComponentLabeling clitkCommon ITKIO ITKStatistics clitkSegmentationFilters) + +ADD_EXECUTABLE(clitkFillMask clitkFillMask.cxx clitkFillMaskGenericFilter.cxx) +TARGET_LINK_LIBRARIES(clitkFillMask clitkCommon ITKIO ITKStatistics clitkSegmentationFilters) + +ADD_EXECUTABLE(clitkExtractPatient clitkExtractPatient.cxx) +TARGET_LINK_LIBRARIES(clitkExtractPatient clitkCommon ITKIO ITKStatistics clitkSegmentationFilters) + +ADD_EXECUTABLE(clitkExtractLung clitkExtractLung.cxx) +TARGET_LINK_LIBRARIES(clitkExtractLung clitkCommon ITKIO ITKStatistics clitkSegmentationFilters) + +ADD_EXECUTABLE(clitkExtractBones clitkExtractBones.cxx) +TARGET_LINK_LIBRARIES(clitkExtractBones clitkCommon ITKIO ITKStatistics clitkSegmentationFilters) + +ADD_EXECUTABLE(clitkExtractMediastinum clitkExtractMediastinum.cxx) +TARGET_LINK_LIBRARIES(clitkExtractMediastinum clitkCommon ITKIO ITKStatistics clitkSegmentationFilters) + +ADD_EXECUTABLE(clitkExtractLymphStations clitkExtractLymphStations.cxx) +TARGET_LINK_LIBRARIES(clitkExtractLymphStations clitkCommon ITKIO ITKStatistics clitkSegmentationFilters) diff --git a/segmentation/clitkConnectedComponentLabeling.cxx b/segmentation/clitkConnectedComponentLabeling.cxx new file mode 100644 index 0000000..620c5c4 --- /dev/null +++ b/segmentation/clitkConnectedComponentLabeling.cxx @@ -0,0 +1,44 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 +======================================================================-====*/ + +// clitk +#include "clitkConnectedComponentLabeling_ggo.h" +#include "clitkConnectedComponentLabelingGenericFilter.h" + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) +{ + + // Init command line + GGO(clitkConnectedComponentLabeling, args_info); + CLITK_INIT; + + // Filter + typedef clitk::ConnectedComponentLabelingGenericFilter FilterType; + FilterType::Pointer filter = FilterType::New(); + + filter->SetArgsInfo(args_info); + filter->Update(); + + if (filter->HasError()) { + std::cout << filter->GetLastError() << std::endl; + } + + return EXIT_SUCCESS; +} // This is the end, my friend +//-------------------------------------------------------------------- diff --git a/segmentation/clitkConnectedComponentLabeling.ggo b/segmentation/clitkConnectedComponentLabeling.ggo new file mode 100644 index 0000000..7777010 --- /dev/null +++ b/segmentation/clitkConnectedComponentLabeling.ggo @@ -0,0 +1,20 @@ +#File clitkConnectedComponentLabeling.ggo +package "clitkConnectedComponentLabeling" +version "1.0" +purpose "Basic segmentation : connected component labeling " + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off +option "imagetypes" - "Display allowed image types" flag off +option "verboseOption" - "Display options values" flag off + +section "I/O" + +option "input" i "Input image filename" string yes +option "inputBG" - "Input Background" int default="0" no +option "output" o "Output filename" string yes + +section "Labelize" + +option "minSize" - "Minimum component size in voxels" int no default="100" +option "full" - "Full connecticity" flag off diff --git a/segmentation/clitkConnectedComponentLabelingGenericFilter.h b/segmentation/clitkConnectedComponentLabelingGenericFilter.h new file mode 100644 index 0000000..82917d1 --- /dev/null +++ b/segmentation/clitkConnectedComponentLabelingGenericFilter.h @@ -0,0 +1,76 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKCONNECTEDCOMPONENTLABELINGSGENERICFILTER_H +#define CLITKCONNECTEDCOMPONENTLABELINGSGENERICFILTER_H + +#include "clitkIO.h" +#include "clitkImageToImageGenericFilter.h" +#include "itkMacro.h" + +//-------------------------------------------------------------------- +namespace clitk +{ + + template + class ITK_EXPORT ConnectedComponentLabelingGenericFilter: + public ImageToImageGenericFilter > + { + + public: + //-------------------------------------------------------------------- + ConnectedComponentLabelingGenericFilter(); + + //-------------------------------------------------------------------- + typedef ConnectedComponentLabelingGenericFilter Self; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + //-------------------------------------------------------------------- + itkNewMacro(Self); + itkTypeMacro(ConnectedComponentLabelingGenericFilter, LightObject); + + //-------------------------------------------------------------------- + void SetArgsInfo(const ArgsInfoType & a); + std::vector GetSizeOfObjectsInPixels() const { return m_SizeOfObjectsInPixels; } + std::vector GetSizeOfObjectsInPhysicalUnits() const { return m_SizeOfObjectsInPhysicalUnits; } + itkGetConstMacro(OriginalNumberOfObjects, unsigned long int); + + //-------------------------------------------------------------------- + // Main function called each time the filter is updated + template + void UpdateWithInputImageType(); + + protected: + void Modified() {} // Need for using itkMacros + template void InitializeImageType(); + ArgsInfoType mArgsInfo; + std::vector m_SizeOfObjectsInPixels; + std::vector m_SizeOfObjectsInPhysicalUnits; + unsigned long int m_OriginalNumberOfObjects; + + }; // end class + //-------------------------------------------------------------------- + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkConnectedComponentLabelingGenericFilter.txx" +#endif + +#endif // #define CLITKCONNECTEDCOMPONENTLABELINGSGENERICFILTER_H diff --git a/segmentation/clitkConnectedComponentLabelingGenericFilter.txx b/segmentation/clitkConnectedComponentLabelingGenericFilter.txx new file mode 100644 index 0000000..caf5cdf --- /dev/null +++ b/segmentation/clitkConnectedComponentLabelingGenericFilter.txx @@ -0,0 +1,120 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKCONNECTEDCOMPONENTLABELINGSGENERICFILTER_TXX +#define CLITKCONNECTEDCOMPONENTLABELINGSGENERICFILTER_TXX + +// clitk +#include "clitkImageCommon.h" + +// itk +#include "itkConnectedComponentImageFilter.h" +#include "itkRelabelComponentImageFilter.h" + +//-------------------------------------------------------------------- +template +clitk::ConnectedComponentLabelingGenericFilter::ConnectedComponentLabelingGenericFilter(): + ImageToImageGenericFilter("ConnectedComponentLabeling") +{ + // InitializeImageType<2>(); + InitializeImageType<3>(); + //InitializeImageType<4>(); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +template +void clitk::ConnectedComponentLabelingGenericFilter::InitializeImageType() +{ + ADD_IMAGE_TYPE(Dim, uchar); + ADD_IMAGE_TYPE(Dim, short); + // ADD_IMAGE_TYPE(Dim, int); + // ADD_IMAGE_TYPE(Dim, float); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void clitk::ConnectedComponentLabelingGenericFilter::SetArgsInfo(const ArgsInfoType & a) +{ + mArgsInfo=a; + SetIOVerbose(mArgsInfo.verbose_flag); + if (mArgsInfo.imagetypes_flag) this->PrintAvailableImageTypes(); + if (mArgsInfo.input_given) AddInputFilename(mArgsInfo.input_arg); + if (mArgsInfo.output_given) SetOutputFilename(mArgsInfo.output_arg); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +// Update with the number of dimensions and the pixeltype +//-------------------------------------------------------------------- +template +template +void clitk::ConnectedComponentLabelingGenericFilter::UpdateWithInputImageType() +{ + DD("UpdateWithInputImageType"); + + // Reading input + typename ImageType::Pointer input = this->template GetInput(0); + + // Output image type + typedef itk::Image OutputImageType; + + // Create CCL filter + DD("CCL"); + typedef itk::ConnectedComponentImageFilter ConnectFilterType; + typename ConnectFilterType::Pointer connectFilter = ConnectFilterType::New(); + connectFilter->SetInput(input); + connectFilter->SetBackgroundValue(mArgsInfo.inputBG_arg); + connectFilter->SetFullyConnected(mArgsInfo.full_flag); + + // TODO SetBackgroud to zero forr relabel ? + + + // Sort by size and remove too small area. + typedef itk::RelabelComponentImageFilter RelabelFilterType; + typename RelabelFilterType::Pointer relabelFilter = RelabelFilterType::New(); + // relabelFilter->InPlaceOn(); + relabelFilter->SetInput(connectFilter->GetOutput()); + relabelFilter->SetMinimumObjectSize(mArgsInfo.minSize_arg); + relabelFilter->Update(); + + DD(mArgsInfo.inputBG_arg); + DD(mArgsInfo.full_flag); + DD(mArgsInfo.minSize_arg); + + // Set information + const std::vector & a = relabelFilter->GetSizeOfObjectsInPixels(); + m_SizeOfObjectsInPixels.resize(a.size()); + for(unsigned int i=0; iGetSizeOfObjectsInPhysicalUnits(); + m_OriginalNumberOfObjects = relabelFilter->GetOriginalNumberOfObjects(); + DD(m_OriginalNumberOfObjects); + DD(m_SizeOfObjectsInPhysicalUnits.size()); + + // Write/Save results + typename OutputImageType::Pointer output = relabelFilter->GetOutput(); + this->template SetNextOutput(output); +} +//-------------------------------------------------------------------- + +#endif //#define CLITKCONNECTEDCOMPONENTLABELINGSGENERICFILTER_TXX diff --git a/segmentation/clitkExtractBones.cxx b/segmentation/clitkExtractBones.cxx new file mode 100644 index 0000000..2122fc7 --- /dev/null +++ b/segmentation/clitkExtractBones.cxx @@ -0,0 +1,40 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 +======================================================================-====*/ + +// clitk +#include "clitkExtractBones_ggo.h" +#include "clitkExtractBonesGenericFilter.h" + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) +{ + + // Init command line + GGO(clitkExtractBones, args_info); + CLITK_INIT; + + // Filter + typedef clitk::ExtractBonesGenericFilter FilterType; + FilterType::Pointer filter = FilterType::New(); + + filter->SetArgsInfo(args_info); + filter->Update(); + + return EXIT_SUCCESS; +} // This is the end, my friend +//-------------------------------------------------------------------- diff --git a/segmentation/clitkExtractBones.ggo b/segmentation/clitkExtractBones.ggo new file mode 100644 index 0000000..581392b --- /dev/null +++ b/segmentation/clitkExtractBones.ggo @@ -0,0 +1,34 @@ +#File clitkExtractBones.ggo +package "clitkExtractBones" +version "1.0" +purpose "Extract bony anatomy through thresholding and connected component labelling. Resample mask afterwards (interp= NN) to match another one (like)" + +option "config" - "Config file" string no +option "imagetypes" - "Display allowed image types" flag off +option "verbose" v "Verbose" flag off +option "verboseStep" - "Verbose each step" flag off +option "writeStep" w "Write image at each step" flag off +option "verboseOption" - "Display options values" flag off +option "verboseWarningOff" - "Do not display warning" flag off + +section "I/O" + +option "input" i "Input image filename" string yes +option "output" o "Output image filename" string yes +option "like" l "Resample like this image" string no + +section "Initial connected component labelling (CCL)" + +option "lower1" - "Lower threshold for CCL" double no default="100" +option "upper1" - "Upper threshold for CCL" double no default="1500" +option "minSize" - "Minimal Component Size for CCL" int no default="100" +option "full" - "Use full connectivity (one side is enough)" flag off + +section "Neighborhood Connected Region Growing (RG)" + +option "lower2" - "Lower threshold for RG" double no default="10" +option "upper2" - "Upper threshold for RG" double no default="1500" +option "radius2" - "Neighborhood radius" int no multiple default="1" +option "sampleRate2" - "Sample rate of label image for RG: number of voxels to skip between seeds" int no default="0" + +option "autoCrop" - "Crop final mask to BoundingBox" flag off diff --git a/segmentation/clitkExtractBonesFilter.h b/segmentation/clitkExtractBonesFilter.h new file mode 100644 index 0000000..b483f37 --- /dev/null +++ b/segmentation/clitkExtractBonesFilter.h @@ -0,0 +1,189 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKEXTRACTBONESSFILTER_H +#define CLITKEXTRACTBONESSFILTER_H + +// clitk +#include "clitkFilterBase.h" +#include "clitkDecomposeAndReconstructImageFilter.h" +#include "clitkExplosionControlledThresholdConnectedImageFilter.h" +#include "clitkSegmentationFunctions.h" + +// itk +#include "itkStatisticsImageFilter.h" + +namespace clitk { + + //-------------------------------------------------------------------- + /* + Extract bony anatomy through thresholding and connected component labelling. + */ + //-------------------------------------------------------------------- + + template + class ITK_EXPORT ExtractBonesFilter: + public clitk::FilterBase, + public itk::ImageToImageFilter + { + + public: + /** Standard class typedefs. */ + typedef ExtractBonesFilter Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(ExtractBonesFilter, ImageToImageFilter); + FILTERBASE_INIT; + + /** Some convenient typedefs */ + typedef TInputImageType InputImageType; + typedef typename InputImageType::ConstPointer InputImageConstPointer; + typedef typename InputImageType::Pointer InputImagePointer; + typedef typename InputImageType::RegionType InputImageRegionType; + typedef typename InputImageType::PixelType InputImagePixelType; + typedef typename InputImageType::SizeType InputImageSizeType; + typedef typename InputImageType::IndexType InputImageIndexType; + + typedef TOutputImageType OutputImageType; + typedef typename OutputImageType::ConstPointer OutputImageConstPointer; + typedef typename OutputImageType::Pointer OutputImagePointer; + typedef typename OutputImageType::RegionType OutputImageRegionType; + typedef typename OutputImageType::PixelType OutputImagePixelType; + typedef typename OutputImageType::SizeType OutputImageSizeType; + typedef typename OutputImageType::IndexType OutputImageIndexType; + + itkStaticConstMacro(ImageDimension, unsigned int, InputImageType::ImageDimension); + typedef int InternalPixelType; + typedef itk::Image InternalImageType; + typedef typename InternalImageType::Pointer InternalImagePointer; + typedef typename InternalImageType::IndexType InternalIndexType; + typedef LabelizeParameters LabelParamType; + + /** Connect inputs */ + void SetInput(const InputImageType * image); + + // Set all options at a time + template + void SetArgsInfo(ArgsInfoType arg); + + // Background / Foreground + itkGetConstMacro(BackgroundValue, OutputImagePixelType); + itkGetConstMacro(ForegroundValue, OutputImagePixelType); + + itkSetMacro(MinimalComponentSize, int); + itkGetConstMacro(MinimalComponentSize, int); + GGO_DefineOption(minSize, SetMinimalComponentSize, int); + + // Step 1 + itkSetMacro(UpperThreshold1, InputImagePixelType); + itkGetMacro(UpperThreshold1, InputImagePixelType); + GGO_DefineOption(upper1, SetUpperThreshold1, InputImagePixelType); + + itkSetMacro(LowerThreshold1, InputImagePixelType); + itkGetMacro(LowerThreshold1, InputImagePixelType); + GGO_DefineOption(lower1, SetLowerThreshold1, InputImagePixelType); + + itkSetMacro(FullConnectivity, bool); + itkGetConstMacro(FullConnectivity, bool); + itkBooleanMacro(FullConnectivity); + GGO_DefineOption_Flag(full, SetFullConnectivity); + + // Step 2 + itkSetMacro(UpperThreshold2, InputImagePixelType); + itkGetMacro(UpperThreshold2, InputImagePixelType); + GGO_DefineOption(upper2, SetUpperThreshold2, InputImagePixelType); + + itkSetMacro(LowerThreshold2, InputImagePixelType); + itkGetMacro(LowerThreshold2, InputImagePixelType); + GGO_DefineOption(lower2, SetLowerThreshold2, InputImagePixelType); + + itkSetMacro(Radius2, InputImageSizeType); + itkGetConstMacro(Radius2, InputImageSizeType); + GGO_DefineOption_Vector(radius2, SetRadius2, InputImageSizeType, ImageDimension, true); + + itkSetMacro(SampleRate2, int); + itkGetConstMacro(SampleRate2, int); + GGO_DefineOption(sampleRate2, SetSampleRate2, int); + + // Final Step + itkSetMacro(AutoCrop, bool); + itkGetConstMacro(AutoCrop, bool); + itkBooleanMacro(AutoCrop); + GGO_DefineOption_Flag(autoCrop, SetAutoCrop); + + protected: + ExtractBonesFilter(); + virtual ~ExtractBonesFilter() {} + + // Global options + itkSetMacro(BackgroundValue, OutputImagePixelType); + itkSetMacro(ForegroundValue, OutputImagePixelType); + OutputImagePixelType m_BackgroundValue; + OutputImagePixelType m_ForegroundValue; + + // Step 1 + InputImagePixelType m_UpperThreshold1; + InputImagePixelType m_LowerThreshold1; + int m_MinimalComponentSize; + bool m_FullConnectivity; + + // Step 2 + InputImagePixelType m_UpperThreshold2; + InputImagePixelType m_LowerThreshold2; + InputImageSizeType m_Radius2; + int m_SampleRate2; + + bool m_AutoCrop; + + virtual void GenerateOutputInformation(); + virtual void GenerateData(); + + // Steps + void RemoveAir(); + void FindTrachea(); + void ExtractBones(); + void RemoveTrachea(); + void BonesSeparation(); + InputImageConstPointer input; + OutputImageConstPointer patient; + InputImagePointer working_input; + typename InternalImageType::Pointer working_image; + typename InternalImageType::Pointer trachea; + typename InternalImageType::Pointer output; + + private: + ExtractBonesFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + }; // end class + //-------------------------------------------------------------------- + +} // end namespace clitk +//-------------------------------------------------------------------- + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkExtractBonesFilter.txx" +#endif + +#endif diff --git a/segmentation/clitkExtractBonesFilter.txx b/segmentation/clitkExtractBonesFilter.txx new file mode 100644 index 0000000..db29cc7 --- /dev/null +++ b/segmentation/clitkExtractBonesFilter.txx @@ -0,0 +1,263 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKEXTRACTBONESSFILTER_TXX +#define CLITKEXTRACTBONESSFILTER_TXX + +// clitk +#include "clitkImageCommon.h" +#include "clitkSetBackgroundImageFilter.h" +#include "clitkSegmentationFunctions.h" +#include "clitkAutoCropFilter.h" + +// itk +#include "itkBinaryThresholdImageFilter.h" +#include "itkConnectedComponentImageFilter.h" +#include "itkRelabelComponentImageFilter.h" +#include "itkNeighborhoodConnectedImageFilter.h" + +//-------------------------------------------------------------------- +template +clitk::ExtractBonesFilter:: +ExtractBonesFilter(): + clitk::FilterBase(), + itk::ImageToImageFilter() +{ + // Default global options + this->SetNumberOfRequiredInputs(1); + SetBackgroundValue(0); // Must be zero + SetForegroundValue(1); + + SetMinimalComponentSize(100); + SetUpperThreshold1(1500); + SetLowerThreshold1(100); + SetFullConnectivity(false); + + SetUpperThreshold2(1500); + SetLowerThreshold2(10); + InputImageSizeType s; + s.Fill(1); + SetRadius2(s); + SetSampleRate2(0); + AutoCropOff(); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractBonesFilter:: +SetInput(const TInputImageType * image) +{ + this->SetNthInput(0, const_cast(image)); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +template +void +clitk::ExtractBonesFilter:: +SetArgsInfo(ArgsInfoType mArgsInfo) +{ + SetVerboseOption_GGO(mArgsInfo); + SetVerboseStep_GGO(mArgsInfo); + SetWriteStep_GGO(mArgsInfo); + SetVerboseWarningOff_GGO(mArgsInfo); + + SetMinimalComponentSize_GGO(mArgsInfo); + SetUpperThreshold1_GGO(mArgsInfo); + SetLowerThreshold1_GGO(mArgsInfo); + SetFullConnectivity_GGO(mArgsInfo); + + SetUpperThreshold2_GGO(mArgsInfo); + SetLowerThreshold2_GGO(mArgsInfo); + SetRadius2_GGO(mArgsInfo); + SetSampleRate2_GGO(mArgsInfo); + SetAutoCrop_GGO(mArgsInfo); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractBonesFilter:: +GenerateOutputInformation() { + // Get input pointers + InputImagePointer input = dynamic_cast(itk::ProcessObject::GetInput(0)); + // InputImagePointer input = dynamic_cast(itk::ProcessObject::GetInput(0)); + Superclass::GenerateOutputInformation(); + OutputImagePointer outputImage = this->GetOutput(0); + outputImage->SetRegions(input->GetLargestPossibleRegion()); + + // typedefs + typedef itk::BinaryThresholdImageFilter InputBinarizeFilterType; + typedef itk::BinaryThresholdImageFilter BinarizeFilterType; + typedef itk::ConnectedComponentImageFilter ConnectFilterType; + typedef itk::RelabelComponentImageFilter RelabelFilterType; + typedef clitk::SetBackgroundImageFilter SetBackgroundFilterType; + typedef itk::CastImageFilter CastImageFilterType; + typedef itk::ImageFileWriter WriterType; + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + StartNewStep("Initial Labeling"); + + typename InternalImageType::Pointer firstLabelImage; + + //--------------------------------- + // Binarize the image + //--------------------------------- + typename InputBinarizeFilterType::Pointer binarizeFilter=InputBinarizeFilterType::New(); + binarizeFilter->SetInput(input); + binarizeFilter->SetLowerThreshold(GetLowerThreshold1()); + binarizeFilter->SetUpperThreshold(GetUpperThreshold1()); + binarizeFilter->SetInsideValue(this->GetForegroundValue()); + binarizeFilter->SetOutsideValue(this->GetBackgroundValue()); + + //--------------------------------- + // Label the connected components + //--------------------------------- + typename ConnectFilterType::Pointer connectFilter=ConnectFilterType::New(); + connectFilter->SetInput(binarizeFilter->GetOutput()); + connectFilter->SetBackgroundValue(this->GetBackgroundValue()); + connectFilter->SetFullyConnected(GetFullConnectivity()); + + //--------------------------------- + // Sort the labels according to size + //--------------------------------- + typename RelabelFilterType::Pointer relabelFilter=RelabelFilterType::New(); + relabelFilter->SetInput(connectFilter->GetOutput()); + relabelFilter->SetMinimumObjectSize(GetMinimalComponentSize()); + + //--------------------------------- + // Keep the label + //--------------------------------- + typename BinarizeFilterType::Pointer binarizeFilter2=BinarizeFilterType::New(); + binarizeFilter2->SetInput(relabelFilter->GetOutput()); + binarizeFilter2->SetLowerThreshold(1); + binarizeFilter2->SetUpperThreshold(1); + binarizeFilter2->SetInsideValue(this->GetForegroundValue()); + binarizeFilter2->SetOutsideValue(this->GetBackgroundValue()); + binarizeFilter2->Update(); + + firstLabelImage = binarizeFilter2->GetOutput(); + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + StartNewStep("Neighborhood connected filter"); + typename InternalImageType::Pointer secondLabelImage; + + //--------------------------------- + //Neighborhood connected RG + //--------------------------------- + typedef itk::NeighborhoodConnectedImageFilter + NeighborhoodConnectedImageFilterType; + typename NeighborhoodConnectedImageFilterType::Pointer neighborhoodConnectedImageFilter= + NeighborhoodConnectedImageFilterType::New(); + + // thresholds + neighborhoodConnectedImageFilter->SetLower(GetLowerThreshold2()); + neighborhoodConnectedImageFilter->SetUpper(GetUpperThreshold2()); + neighborhoodConnectedImageFilter->SetReplaceValue(this->GetForegroundValue()); + neighborhoodConnectedImageFilter->SetRadius(GetRadius2()); + neighborhoodConnectedImageFilter->SetInput(input); + + // Seeds from label image + typedef itk::ImageRegionIteratorWithIndex IteratorType; + IteratorType it(firstLabelImage, firstLabelImage->GetLargestPossibleRegion()); + typename InputImageType::IndexType index; + unsigned int counter=0; + while (!it.IsAtEnd()) + { + if (it.Get()==this->GetForegroundValue()) + { + counter++; + index=it.GetIndex(); + neighborhoodConnectedImageFilter->AddSeed(index); + ++it; + unsigned int i=0; + while (!it.IsAtEnd() && i< (unsigned int) GetSampleRate2()) + { + ++it; + i++; + } + } + else ++it; + } + + neighborhoodConnectedImageFilter->Update(); + secondLabelImage = neighborhoodConnectedImageFilter->GetOutput(); + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + StartNewStep("Combine de images"); + typedef clitk::SetBackgroundImageFilter + SetBackgroundImageFilterType; + typename SetBackgroundImageFilterType::Pointer setBackgroundFilter=SetBackgroundImageFilterType::New(); + setBackgroundFilter->SetInput(firstLabelImage); + setBackgroundFilter->SetInput2(secondLabelImage); + setBackgroundFilter->SetMaskValue(this->GetForegroundValue()); + setBackgroundFilter->SetOutsideValue(this->GetForegroundValue()); + setBackgroundFilter->Update(); + + output = setBackgroundFilter->GetOutput(); + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + // [Optional] + if (GetAutoCrop()) { + StartNewStep("AutoCrop"); + typedef clitk::AutoCropFilter CropFilterType; + typename CropFilterType::Pointer cropFilter = CropFilterType::New(); + cropFilter->SetInput(output); + cropFilter->SetBackgroundValue(GetBackgroundValue()); + cropFilter->Update(); + output = cropFilter->GetOutput(); + StopCurrentStep(output); + outputImage->SetRegions(output->GetLargestPossibleRegion()); + } + +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractBonesFilter:: +GenerateData() { + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + // Final Cast + typedef itk::CastImageFilter CastImageFilterType; + typename CastImageFilterType::Pointer caster= CastImageFilterType::New(); + caster->SetInput(output); + caster->Update(); + //this->SetNthOutput(0, caster->GetOutput()); + this->GraftOutput(caster->GetOutput()); + return; +} +//-------------------------------------------------------------------- + + +#endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX diff --git a/segmentation/clitkExtractBonesGenericFilter.h b/segmentation/clitkExtractBonesGenericFilter.h new file mode 100644 index 0000000..9093ac6 --- /dev/null +++ b/segmentation/clitkExtractBonesGenericFilter.h @@ -0,0 +1,70 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKEXTRACTBONESSGENERICFILTER_H +#define CLITKEXTRACTBONESSGENERICFILTER_H + +#include "clitkIO.h" +#include "clitkImageToImageGenericFilter.h" +#include "clitkExtractBonesFilter.h" + +//-------------------------------------------------------------------- +namespace clitk +{ + + template + class ITK_EXPORT ExtractBonesGenericFilter: + public ImageToImageGenericFilter > + { + + public: + //-------------------------------------------------------------------- + ExtractBonesGenericFilter(); + + //-------------------------------------------------------------------- + typedef ExtractBonesGenericFilter Self; + typedef ImageToImageGenericFilter > Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + //-------------------------------------------------------------------- + itkNewMacro(Self); + itkTypeMacro(ExtractBonesGenericFilter, LightObject); + + //-------------------------------------------------------------------- + void SetArgsInfo(const ArgsInfoType & a); + + //-------------------------------------------------------------------- + // Main function called each time the filter is updated + template + void UpdateWithInputImageType(); + + protected: + template void InitializeImageType(); + ArgsInfoType mArgsInfo; + + }; // end class + //-------------------------------------------------------------------- + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkExtractBonesGenericFilter.txx" +#endif + +#endif // #define CLITKEXTRACTBONESSGENERICFILTER_H diff --git a/segmentation/clitkExtractBonesGenericFilter.txx b/segmentation/clitkExtractBonesGenericFilter.txx new file mode 100644 index 0000000..5c72672 --- /dev/null +++ b/segmentation/clitkExtractBonesGenericFilter.txx @@ -0,0 +1,98 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKEXTRACTBONESSGENERICFILTER_TXX +#define CLITKEXTRACTBONESSGENERICFILTER_TXX + +#include "clitkImageCommon.h" + +//-------------------------------------------------------------------- +template +clitk::ExtractBonesGenericFilter::ExtractBonesGenericFilter(): + ImageToImageGenericFilter("ExtractBones") +{ + // Default values + cmdline_parser_clitkExtractBones_init(&mArgsInfo); + InitializeImageType<3>(); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +template +void clitk::ExtractBonesGenericFilter::InitializeImageType() +{ + ADD_IMAGE_TYPE(Dim, short); + // ADD_IMAGE_TYPE(Dim, int); + // ADD_IMAGE_TYPE(Dim, float); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void clitk::ExtractBonesGenericFilter::SetArgsInfo(const ArgsInfoType & a) +{ + mArgsInfo=a; + SetIOVerbose(mArgsInfo.verbose_flag); + if (mArgsInfo.imagetypes_flag) this->PrintAvailableImageTypes(); + if (mArgsInfo.input_given) AddInputFilename(mArgsInfo.input_arg); + if (mArgsInfo.output_given) AddOutputFilename(mArgsInfo.output_arg); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +// Update with the number of dimensions and the pixeltype +//-------------------------------------------------------------------- +template +template +void clitk::ExtractBonesGenericFilter::UpdateWithInputImageType() +{ + // Mask & output image type + typedef itk::Image OutputImageType; + + // Reading input + typename ImageType::Pointer input = this->template GetInput(0); + + // Create filter + typedef clitk::ExtractBonesFilter FilterType; + typename FilterType::Pointer filter = FilterType::New(); + + // Set global Options + filter->SetArgsInfo(mArgsInfo); + filter->SetInput(input); + + // Go ! + filter->Update(); + + // Check if error + if (filter->HasError()) { + SetLastError(filter->GetLastError()); + // No output + return; + } + + // Write/Save results + typename OutputImageType::Pointer output = filter->GetOutput(); + this->template SetNextOutput(output); +} +//-------------------------------------------------------------------- + +#endif //#define CLITKEXTRACTBONESSGENERICFILTER_TXX diff --git a/segmentation/clitkExtractImageFilter.h b/segmentation/clitkExtractImageFilter.h new file mode 100644 index 0000000..1d888f7 --- /dev/null +++ b/segmentation/clitkExtractImageFilter.h @@ -0,0 +1,98 @@ + +#ifndef __clitkExtractImageFilter_h +#define __clitkExtractImageFilter_h + +#include "itkImageToImageFilter.h" +#include "itkSmartPointer.h" +#include "itkExtractImageFilterRegionCopier.h" + +namespace clitk +{ + +template +class ITK_EXPORT ExtractImageFilter: + public itk::ImageToImageFilter +{ +public: + /** Standard class typedefs. */ + typedef ExtractImageFilter Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(ExtractImageFilter, ImageToImageFilter); + + /** Image type information. */ + typedef TInputImage InputImageType; + typedef TOutputImage OutputImageType; + + /** Typedef to describe the output and input image region types. */ + typedef typename TOutputImage::RegionType OutputImageRegionType; + typedef typename TInputImage::RegionType InputImageRegionType; + + /** Typedef to describe the type of pixel. */ + typedef typename TOutputImage::PixelType OutputImagePixelType; + typedef typename TInputImage::PixelType InputImagePixelType; + + /** Typedef to describe the output and input image index and size types. */ + typedef typename TOutputImage::IndexType OutputImageIndexType; + typedef typename TInputImage::IndexType InputImageIndexType; + typedef typename TOutputImage::SizeType OutputImageSizeType; + typedef typename TInputImage::SizeType InputImageSizeType; + + /** ImageDimension enumeration */ + itkStaticConstMacro(InputImageDimension, unsigned int, + TInputImage::ImageDimension); + itkStaticConstMacro(OutputImageDimension, unsigned int, + TOutputImage::ImageDimension); + + typedef itk::ImageToImageFilterDetail::ExtractImageFilterRegionCopier< + itkGetStaticConstMacro(InputImageDimension), + itkGetStaticConstMacro(OutputImageDimension)> ExtractImageFilterRegionCopierType; + + void SetExtractionRegion(InputImageRegionType extractRegion); + itkGetMacro(ExtractionRegion, InputImageRegionType); + +#ifdef ITK_USE_CONCEPT_CHECKING + /** Begin concept checking */ + itkConceptMacro(InputCovertibleToOutputCheck, + (itk::Concept::Convertible)); + /** End concept checking */ +#endif + +protected: + ExtractImageFilter(); + ~ExtractImageFilter() {}; + void PrintSelf(std::ostream& os, itk::Indent indent) const; + + + virtual void GenerateOutputInformation(); + + + virtual void CallCopyOutputRegionToInputRegion(InputImageRegionType &destRegion, + const OutputImageRegionType &srcRegion); + + + void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, + int threadId ); + InputImageRegionType m_ExtractionRegion; + OutputImageRegionType m_OutputImageRegion; + +private: + ExtractImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + +}; + + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkExtractImageFilter.txx" +#endif + +#endif diff --git a/segmentation/clitkExtractImageFilter.txx b/segmentation/clitkExtractImageFilter.txx new file mode 100644 index 0000000..020cbb1 --- /dev/null +++ b/segmentation/clitkExtractImageFilter.txx @@ -0,0 +1,259 @@ + +#ifndef _clitkExtractImageFilter_txx +#define _clitkExtractImageFilter_txx + +#include "clitkExtractImageFilter.h" +#include "itkImageRegionIterator.h" +#include "itkImageRegionConstIterator.h" +#include "itkObjectFactory.h" +#include "itkExtractImageFilterRegionCopier.h" +#include "itkProgressReporter.h" + + +namespace clitk +{ + +/** + * + */ +template +ExtractImageFilter +::ExtractImageFilter() +{ +} + + +/** + * + */ +template +void +ExtractImageFilter +::PrintSelf(std::ostream& os, itk::Indent indent) const +{ + Superclass::PrintSelf(os,indent); + + os << indent << "ExtractionRegion: " << m_ExtractionRegion << std::endl; + os << indent << "OutputImageRegion: " << m_OutputImageRegion << std::endl; +} + + +template +void +ExtractImageFilter +::CallCopyOutputRegionToInputRegion(InputImageRegionType &destRegion, + const OutputImageRegionType &srcRegion) +{ + ExtractImageFilterRegionCopierType extractImageRegionCopier; + extractImageRegionCopier(destRegion, srcRegion, m_ExtractionRegion); +} + + +template +void +ExtractImageFilter +::SetExtractionRegion(InputImageRegionType extractRegion) +{ + m_ExtractionRegion = extractRegion; + + unsigned int nonzeroSizeCount = 0; + InputImageSizeType inputSize = extractRegion.GetSize(); + OutputImageSizeType outputSize; + OutputImageIndexType outputIndex; + + /** + * check to see if the number of non-zero entries in the extraction region + * matches the number of dimensions in the output image. + **/ + for (unsigned int i = 0; i < InputImageDimension; ++i) + { + if (inputSize[i]) + { + outputSize[nonzeroSizeCount] = inputSize[i]; + outputIndex[nonzeroSizeCount] = extractRegion.GetIndex()[i]; + nonzeroSizeCount++; + } + } + + if (nonzeroSizeCount != OutputImageDimension) + { + itkExceptionMacro("Extraction Region not consistent with output image"); + } + + m_OutputImageRegion.SetSize(outputSize); + m_OutputImageRegion.SetIndex(outputIndex); + this->Modified(); +} + + + +/** + * ExtractImageFilter can produce an image which is a different resolution + * than its input image. As such, ExtractImageFilter needs to provide an + * implementation for GenerateOutputInformation() in order to inform + * the pipeline execution model. The original documentation of this + * method is below. + * + * \sa ProcessObject::GenerateOutputInformaton() + */ +template +void +ExtractImageFilter +::GenerateOutputInformation() +{ + // do not call the superclass' implementation of this method since + // this filter allows the input and the output to be of different dimensions + + // get pointers to the input and output + typename Superclass::OutputImagePointer outputPtr = this->GetOutput(); + typename Superclass::InputImageConstPointer inputPtr = this->GetInput(); + + if ( !outputPtr || !inputPtr) + { + return; + } + + // Set the output image size to the same value as the extraction region. + outputPtr->SetLargestPossibleRegion( m_OutputImageRegion ); + + // Set the output spacing and origin + const itk::ImageBase *phyData; + + phyData + = dynamic_cast*>(this->GetInput()); + + if (phyData) + { + // Copy what we can from the image from spacing and origin of the input + // This logic needs to be augmented with logic that select which + // dimensions to copy + + unsigned int i; + const typename InputImageType::SpacingType& + inputSpacing = inputPtr->GetSpacing(); + const typename InputImageType::DirectionType& + inputDirection = inputPtr->GetDirection(); + const typename InputImageType::PointType& + inputOrigin = inputPtr->GetOrigin(); + + typename OutputImageType::SpacingType outputSpacing; + typename OutputImageType::DirectionType outputDirection; + typename OutputImageType::PointType outputOrigin; + + if ( static_cast(OutputImageDimension) > + static_cast(InputImageDimension ) ) + { + // copy the input to the output and fill the rest of the + // output with zeros. + for (i=0; i < InputImageDimension; ++i) + { + outputSpacing[i] = inputSpacing[i]; + outputOrigin[i] = inputOrigin[i]; + for (unsigned int dim = 0; dim < InputImageDimension; ++dim) + { + outputDirection[i][dim] = inputDirection[i][dim]; + } + } + for (; i < OutputImageDimension; ++i) + { + outputSpacing[i] = 1.0; + outputOrigin[i] = 0.0; + for (unsigned int dim = 0; dim < InputImageDimension; ++dim) + { + outputDirection[i][dim] = 0.0; + } + outputDirection[i][i] = 1.0; + } + } + else + { + // copy the non-collapsed part of the input spacing and origing to the output + int nonZeroCount = 0; + for (i=0; i < InputImageDimension; ++i) + { + if (m_ExtractionRegion.GetSize()[i]) + { + outputSpacing[nonZeroCount] = inputSpacing[i]; + outputOrigin[nonZeroCount] = inputOrigin[i]; + int nonZeroCount2 = 0; + for (unsigned int dim = 0; dim < InputImageDimension; ++dim) + { + if (m_ExtractionRegion.GetSize()[dim]) + { + outputDirection[nonZeroCount][nonZeroCount2] = + inputDirection[i][dim]; + ++nonZeroCount2; + } + } + nonZeroCount++; + } + } + } + + // set the spacing and origin + outputPtr->SetSpacing( outputSpacing ); + outputPtr->SetDirection( outputDirection ); + outputPtr->SetOrigin( outputOrigin ); + outputPtr->SetNumberOfComponentsPerPixel(inputPtr->GetNumberOfComponentsPerPixel() ); + } + else + { + // pointer could not be cast back down + itkExceptionMacro(<< "itk::ExtractImageFilter::GenerateOutputInformation " + << "cannot cast input to " + << typeid(itk::ImageBase*).name() ); + } +} + +/** + * ExtractImageFilter can be implemented as a multithreaded filter. + * Therefore, this implementation provides a ThreadedGenerateData() + * routine which is called for each processing thread. The output + * image data is allocated automatically by the superclass prior to + * calling ThreadedGenerateData(). ThreadedGenerateData can only + * write to the portion of the output image specified by the + * parameter "outputRegionForThread" + * + * \sa ImageToImageFilter::ThreadedGenerateData(), + * ImageToImageFilter::GenerateData() + */ +template +void +ExtractImageFilter +::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, + int threadId) +{ + itkDebugMacro(<<"Actually executing"); + + // Get the input and output pointers + typename Superclass::InputImageConstPointer inputPtr = this->GetInput(); + typename Superclass::OutputImagePointer outputPtr = this->GetOutput(); + + // support progress methods/callbacks + itk::ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels()); + + // Define the portion of the input to walk for this thread + InputImageRegionType inputRegionForThread; + this->CallCopyOutputRegionToInputRegion(inputRegionForThread, outputRegionForThread); + + // Define the iterators. + typedef itk::ImageRegionIterator OutputIterator; + typedef itk::ImageRegionConstIterator InputIterator; + + OutputIterator outIt(outputPtr, outputRegionForThread); + InputIterator inIt(inputPtr, inputRegionForThread); + + // walk the output region, and sample the input image + while( !outIt.IsAtEnd() ) + { + // copy the input pixel to the output + outIt.Set( static_cast(inIt.Get())); + ++outIt; + ++inIt; + progress.CompletedPixel(); + } +} + +} // end namespace clitk + +#endif diff --git a/segmentation/clitkExtractLung.cxx b/segmentation/clitkExtractLung.cxx new file mode 100644 index 0000000..01ed6a8 --- /dev/null +++ b/segmentation/clitkExtractLung.cxx @@ -0,0 +1,44 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 +======================================================================-====*/ + +// clitk +#include "clitkExtractLung_ggo.h" +#include "clitkExtractLungGenericFilter.h" + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) +{ + + // Init command line + GGO(clitkExtractLung, args_info); + CLITK_INIT; + + // Filter + typedef clitk::ExtractLungGenericFilter FilterType; + FilterType::Pointer filter = FilterType::New(); + + filter->SetArgsInfo(args_info); + filter->Update(); + + if (filter->HasError()) { + std::cout << filter->GetLastError() << std::endl; + } + + return EXIT_SUCCESS; +} // This is the end, my friend +//-------------------------------------------------------------------- diff --git a/segmentation/clitkExtractLung.ggo b/segmentation/clitkExtractLung.ggo new file mode 100644 index 0000000..883a013 --- /dev/null +++ b/segmentation/clitkExtractLung.ggo @@ -0,0 +1,51 @@ +#File clitkExtractLungs.ggo +package "clitkExtractLungs" +version "1.0" +purpose "Segment lungs in CT image. Need 'patient' mask." + +option "config" - "Config file" string no +option "imagetypes" - "Display allowed image types" flag off +option "verbose" v "Verbose" flag off +option "verboseStep" - "Verbose each step" flag off +option "writeStep" w "Write image at each step" flag off +option "verboseOption" - "Display options values" flag off +option "verboseWarningOff" - "Do not display warning" flag off + +section "I/O" + +option "input" i "Input CT image filename" string yes +option "patient" p "Input patient mask filename" string yes +option "patientBG" - "Patient Background" int default="0" no +option "output" o "Output lungs mask filename" string yes +option "outputTrachea" t "Output trachea mask filename" string no + +section "Step 1 : Air remove" + +option "lower" - "Initial lower threshold" double no +option "upper" - "Initial upper threshold" double no default="-300" +option "minSize" - "Minimum component size in voxels" int no default="100" +option "remove1" - "Labels not to keep in air mask (lungs)" int no multiple default="2" +option "firstKeep1" - "First label to keep" int no default="1" +option "lastKeep1" - "Last label to keep" int no + +section "Step 2 : find trachea" + +option "upperThresholdForTrachea" - "Initial upper threshold for trachea" double no default="-900" +option "multiplierForTrachea" - "Multiplier for the region growing" double no default="5" +option "thresholdStepSizeForTrachea" - "Threshold step size" int no default="64" +option "seed" - "Index of the trachea seed point" int no multiple + +section "Step 3 : auto extract lung" + +option "bins" - "Number of bins to use for the Otsu thresholding" int no default="500" +option "remove2" - "Labels not to keep in air mask (gas)" int no multiple +option "firstKeep2" - "First label to keep" int no default="1" +option "lastKeep2" - "Last label to keep" int no + +section "Step 4 : remove trachea" + +option "radius" - "Radius for dilation" int no default="1" +option "remove3" - "Labels not to keep in lungs mask (trachea)" int no multiple +option "firstKeep3" - "First label to keep" int no default="1" +option "lastKeep3" - "Last label to keep" int no default="2" + diff --git a/segmentation/clitkExtractLungFilter.h b/segmentation/clitkExtractLungFilter.h new file mode 100644 index 0000000..1f6252d --- /dev/null +++ b/segmentation/clitkExtractLungFilter.h @@ -0,0 +1,247 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKEXTRACTLUNGSFILTER_H +#define CLITKEXTRACTLUNGSFILTER_H + +// clitk +#include "clitkFilterBase.h" +#include "clitkDecomposeAndReconstructImageFilter.h" +#include "clitkExplosionControlledThresholdConnectedImageFilter.h" +#include "clitkSegmentationFunctions.h" + +// itk +#include "itkStatisticsImageFilter.h" + +namespace clitk { + + //-------------------------------------------------------------------- + /* + Try to extract the Lung part of a thorax CT. Inspired by + Rikxoort2009, Section IIA, MedPhys. + + - First, all air besides lungs and thrachea is removed, by + removing the second largest label of the firstLabelImage and + setting the remainder to 0HU . This modified input is optimally + thresholded (Otsu1979). + + - Trachea and bronchi are grown from seeds in the top of the image + by explosion controlled region growing, slightly dilated and + removed from the second label image. + + - Left and right lung are separated (if necessary) by erosion and + reconstructed by conditional dilation. + + - TRACHEA is available at the end + + TODO ********** Remaining holes can be filled afterwards (clitkFillMask). + + */ + //-------------------------------------------------------------------- + + template + class ITK_EXPORT ExtractLungFilter: + public clitk::FilterBase, + public itk::ImageToImageFilter + { + + public: + /** Standard class typedefs. */ + typedef itk::ImageToImageFilter Superclass; + typedef ExtractLungFilter Self; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(ExtractLungFilter, ImageToImageFilter); + FILTERBASE_INIT; + + /** Some convenient typedefs */ + typedef TInputImageType InputImageType; + typedef typename InputImageType::ConstPointer InputImageConstPointer; + typedef typename InputImageType::Pointer InputImagePointer; + typedef typename InputImageType::RegionType InputImageRegionType; + typedef typename InputImageType::PixelType InputImagePixelType; + typedef typename InputImageType::SizeType InputImageSizeType; + typedef typename InputImageType::IndexType InputImageIndexType; + + typedef TMaskImageType MaskImageType; + typedef typename MaskImageType::ConstPointer MaskImageConstPointer; + typedef typename MaskImageType::Pointer MaskImagePointer; + typedef typename MaskImageType::RegionType MaskImageRegionType; + typedef typename MaskImageType::PixelType MaskImagePixelType; + typedef typename MaskImageType::SizeType MaskImageSizeType; + typedef typename MaskImageType::IndexType MaskImageIndexType; + + itkStaticConstMacro(ImageDimension, unsigned int, InputImageType::ImageDimension); + typedef int InternalPixelType; + typedef itk::Image InternalImageType; + typedef typename InternalImageType::Pointer InternalImagePointer; + typedef typename InternalImageType::IndexType InternalIndexType; + typedef LabelizeParameters LabelParamType; + + /** Connect inputs */ + void SetInput(const InputImageType * image); + void SetInputPatientMask(MaskImageType * mask, MaskImagePixelType BG); + itkSetMacro(PatientMaskBackgroundValue, MaskImagePixelType); + itkGetConstMacro(PatientMaskBackgroundValue, MaskImagePixelType); + GGO_DefineOption(patientBG, SetPatientMaskBackgroundValue, MaskImagePixelType); + + // Set all options at a time + template + void SetArgsInfo(ArgsInfoType arg); + + // Get output (only availabe after update !) + typename MaskImageType::Pointer GetTracheaImage() { return trachea; } + + // Background / Foreground + itkGetConstMacro(BackgroundValue, MaskImagePixelType); + itkGetConstMacro(ForegroundValue, MaskImagePixelType); + + // For common segmentation processes + itkSetMacro(MinimalComponentSize, int); + itkGetConstMacro(MinimalComponentSize, int); + GGO_DefineOption(minSize, SetMinimalComponentSize, int); + + // Step 1 options RemoveAir + itkSetMacro(UpperThreshold, InputImagePixelType); + itkGetConstMacro(UpperThreshold, InputImagePixelType); + GGO_DefineOption(upper, SetUpperThreshold, InputImagePixelType); + + itkSetMacro(LowerThreshold, InputImagePixelType); + itkGetConstMacro(LowerThreshold, InputImagePixelType); + itkSetMacro(UseLowerThreshold, bool); + itkGetConstMacro(UseLowerThreshold, bool); + itkBooleanMacro(UseLowerThreshold); + GGO_DefineOption_WithTest(lower, SetLowerThreshold, InputImagePixelType, UseLowerThreshold); + + void SetLabelizeParameters1(LabelParamType * a) { m_LabelizeParameters1 = a; } + itkGetConstMacro(LabelizeParameters1, LabelParamType*); + GGO_DefineOption_LabelParam(1, SetLabelizeParameters1, LabelParamType); + + // Step 2 options FindTrachea + itkSetMacro(UpperThresholdForTrachea, InputImagePixelType); + itkGetConstMacro(UpperThresholdForTrachea, InputImagePixelType); + GGO_DefineOption(upperThresholdForTrachea, SetUpperThresholdForTrachea, InputImagePixelType); + + itkSetMacro(MultiplierForTrachea, double); + itkGetConstMacro(MultiplierForTrachea, double); + GGO_DefineOption(multiplierForTrachea, SetMultiplierForTrachea, double); + + itkSetMacro(ThresholdStepSizeForTrachea, InputImagePixelType); + itkGetConstMacro(ThresholdStepSizeForTrachea, InputImagePixelType); + GGO_DefineOption(thresholdStepSizeForTrachea, SetThresholdStepSizeForTrachea, InputImagePixelType); + + void AddSeed(InternalIndexType s); + std::vector & GetSeeds() { return m_Seeds; } + GGO_DefineOption_Vector(seed, AddSeed, InternalIndexType, InputImageType::ImageDimension, true); + + // Step 3 options ExtractLung + itkSetMacro(NumberOfHistogramBins, int); + itkGetConstMacro(NumberOfHistogramBins, int); + GGO_DefineOption(bins, SetNumberOfHistogramBins, int); + + void SetLabelizeParameters2(LabelParamType* a) { m_LabelizeParameters2 = a; } + itkGetConstMacro(LabelizeParameters2, LabelParamType*); + GGO_DefineOption_LabelParam(2, SetLabelizeParameters2, LabelParamType); + + // Step 4 options RemoveTrachea + itkSetMacro(RadiusForTrachea, int); + itkGetConstMacro(RadiusForTrachea, int); + GGO_DefineOption(radius, SetRadiusForTrachea, int); + + void SetLabelizeParameters3(LabelParamType * a) { m_LabelizeParameters3 = a; } + itkGetConstMacro(LabelizeParameters3, LabelParamType*); + GGO_DefineOption_LabelParam(3, SetLabelizeParameters3, LabelParamType); + + // Step 5 options LungSeparation + // itkSetMacro(FinalOpenClose, bool); + // itkGetConstMacro(FinalOpenClose, bool); + // itkBooleanMacro(FinalOpenClose); + + // virtual void Update(); + + protected: + ExtractLungFilter(); + virtual ~ExtractLungFilter() {} + + // Global options + itkSetMacro(BackgroundValue, MaskImagePixelType); + itkSetMacro(ForegroundValue, MaskImagePixelType); + MaskImagePixelType m_PatientMaskBackgroundValue; + MaskImagePixelType m_BackgroundValue; + MaskImagePixelType m_ForegroundValue; + int m_MinimalComponentSize; + + // Step 1 + InputImagePixelType m_UpperThreshold; + InputImagePixelType m_LowerThreshold; + bool m_UseLowerThreshold; + LabelParamType* m_LabelizeParameters1; + + // Step 2 + InputImagePixelType m_UpperThresholdForTrachea; + InputImagePixelType m_ThresholdStepSizeForTrachea; + double m_MultiplierForTrachea; + std::vector m_Seeds; + + // Step 3 + int m_NumberOfHistogramBins; + LabelParamType* m_LabelizeParameters2; + + // Step 4 + int m_RadiusForTrachea; + LabelParamType* m_LabelizeParameters3; + + // Step 5 + // bool m_FinalOpenClose; + + virtual void GenerateOutputInformation(); + virtual void GenerateData(); + + // Steps + void RemoveAir(); + void FindTrachea(); + void ExtractLung(); + void RemoveTrachea(); + void LungSeparation(); + InputImageConstPointer input; + MaskImageConstPointer patient; + InputImagePointer working_input; + typename InternalImageType::Pointer working_image; + typename InternalImageType::Pointer trachea_tmp; + MaskImagePointer trachea; + + private: + ExtractLungFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + }; // end class + //-------------------------------------------------------------------- + +} // end namespace clitk +//-------------------------------------------------------------------- + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkExtractLungFilter.txx" +#endif + +#endif diff --git a/segmentation/clitkExtractLungFilter.txx b/segmentation/clitkExtractLungFilter.txx new file mode 100644 index 0000000..2c7be4c --- /dev/null +++ b/segmentation/clitkExtractLungFilter.txx @@ -0,0 +1,439 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKEXTRACTLUNGSFILTER_TXX +#define CLITKEXTRACTLUNGSFILTER_TXX + +// clitk +#include "clitkImageCommon.h" +#include "clitkSetBackgroundImageFilter.h" +#include "clitkSegmentationFunctions.h" +#include "clitkAutoCropFilter.h" + +// itk +#include "itkBinaryThresholdImageFilter.h" +#include "itkConnectedComponentImageFilter.h" +#include "itkRelabelComponentImageFilter.h" +#include "itkOtsuThresholdImageFilter.h" + +//-------------------------------------------------------------------- +template +clitk::ExtractLungFilter:: +ExtractLungFilter(): + clitk::FilterBase(), + itk::ImageToImageFilter() +{ + // Default global options + this->SetNumberOfRequiredInputs(2); + SetPatientMaskBackgroundValue(0); + SetBackgroundValue(0); // Must be zero + SetForegroundValue(1); + + // Step 1 default values + SetUpperThreshold(-300); + SetLowerThreshold(-1000); + UseLowerThresholdOff(); + LabelParamType * p1 = new LabelParamType; + p1->SetFirstKeep(1); + p1->UseLastKeepOff(); + p1->AddLabelToRemove(2); + SetLabelizeParameters1(p1); + + // Step 2 default values + SetUpperThresholdForTrachea(-900); + SetMultiplierForTrachea(5); + SetThresholdStepSizeForTrachea(64); + + // Step 3 default values + SetNumberOfHistogramBins(500); + LabelParamType * p2 = new LabelParamType; + p2->SetFirstKeep(1); + p2->UseLastKeepOff(); + // p->AddLabelToRemove(2); // No label to remove by default + SetLabelizeParameters2(p2); + + // Step 4 default values + SetRadiusForTrachea(1); + LabelParamType * p3 = new LabelParamType; + p3->SetFirstKeep(1); + p3->SetLastKeep(2); + p3->UseLastKeepOff(); + SetLabelizeParameters3(p3); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLungFilter:: +SetInput(const TInputImageType * image) +{ + this->SetNthInput(0, const_cast(image)); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLungFilter:: +SetInputPatientMask(TMaskImageType * image, MaskImagePixelType bg ) +{ + this->SetNthInput(1, const_cast(image)); + SetPatientMaskBackgroundValue(bg); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLungFilter:: +AddSeed(InternalIndexType s) +{ + m_Seeds.push_back(s); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +template +void +clitk::ExtractLungFilter:: +SetArgsInfo(ArgsInfoType mArgsInfo) +{ + SetVerboseOption_GGO(mArgsInfo); + SetVerboseStep_GGO(mArgsInfo); + SetWriteStep_GGO(mArgsInfo); + SetVerboseWarningOff_GGO(mArgsInfo); + + SetUpperThreshold_GGO(mArgsInfo); + SetLowerThreshold_GGO(mArgsInfo); + SetLabelizeParameters1_GGO(mArgsInfo); + if (!mArgsInfo.remove1_given) { + GetLabelizeParameters1()->AddLabelToRemove(2); + if (GetVerboseOption()) VerboseOption("remove1", 2); + } + + SetUpperThresholdForTrachea_GGO(mArgsInfo); + SetMultiplierForTrachea_GGO(mArgsInfo); + SetThresholdStepSizeForTrachea_GGO(mArgsInfo); + AddSeed_GGO(mArgsInfo); + + SetNumberOfHistogramBins_GGO(mArgsInfo); + SetLabelizeParameters2_GGO(mArgsInfo); + + SetRadiusForTrachea_GGO(mArgsInfo); + SetLabelizeParameters3_GGO(mArgsInfo); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLungFilter:: +GenerateOutputInformation() +{ + input = dynamic_cast(itk::ProcessObject::GetInput(0)); + Superclass::GenerateOutputInformation(); +// MaskImagePointer output = this->GetOutput(0); + + // Get input pointers + input = dynamic_cast(itk::ProcessObject::GetInput(0)); + patient = dynamic_cast(itk::ProcessObject::GetInput(1)); + + // Check image + if (!HasSameSizeAndSpacing(input, patient)) { + this->SetLastError("* ERROR * the images (input and patient mask) must have the same size & spacing"); + return; + } + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + StartNewStep("Set background to initial image"); + working_input = SetBackground + (input, patient, GetPatientMaskBackgroundValue(), -1000); + StopCurrentStep(working_input); + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + StartNewStep("Remove Air"); + // Threshold to get air + typedef itk::BinaryThresholdImageFilter InputBinarizeFilterType; + typename InputBinarizeFilterType::Pointer binarizeFilter=InputBinarizeFilterType::New(); + binarizeFilter->SetInput(working_input); + if (m_UseLowerThreshold) binarizeFilter->SetLowerThreshold(m_LowerThreshold); + binarizeFilter->SetUpperThreshold(m_UpperThreshold); + binarizeFilter ->SetInsideValue(this->GetForegroundValue()); + binarizeFilter ->SetOutsideValue(this->GetBackgroundValue()); + binarizeFilter->Update(); + working_image = binarizeFilter->GetOutput(); + + // Labelize and keep right labels + working_image = Labelize(working_image, GetBackgroundValue(), true, GetMinimalComponentSize()); + working_image = RemoveLabels + (working_image, GetBackgroundValue(), GetLabelizeParameters1()->GetLabelsToRemove()); + typename InternalImageType::Pointer air = KeepLabels + (working_image, + GetBackgroundValue(), + GetForegroundValue(), + GetLabelizeParameters1()->GetFirstKeep(), + GetLabelizeParameters1()->GetLastKeep(), + GetLabelizeParameters1()->GetUseLastKeep()); + + // Set Air to BG + working_input = SetBackground + (working_input, air, this->GetForegroundValue(), this->GetBackgroundValue()); + + // End + StopCurrentStep(working_input); + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + StartNewStep("Find the trachea"); + if (m_Seeds.size() == 0) { // try to find seed + // Search seed (parameters = UpperThresholdForTrachea) + static const unsigned int Dim = InputImageType::ImageDimension; + typename InternalImageType::RegionType sliceRegion = working_input->GetLargestPossibleRegion(); + typename InternalImageType::SizeType sliceRegionSize = sliceRegion.GetSize(); + typename InternalImageType::IndexType sliceRegionIndex = sliceRegion.GetIndex(); + sliceRegionIndex[Dim-1]=sliceRegionSize[Dim-1]-5; + sliceRegionSize[Dim-1]=5; + sliceRegion.SetSize(sliceRegionSize); + sliceRegion.SetIndex(sliceRegionIndex); + + typedef itk::ImageRegionConstIterator IteratorType; + IteratorType it(working_input, sliceRegion); + it.GoToBegin(); + while (!it.IsAtEnd()) { + if(it.Get() < GetUpperThresholdForTrachea() ) { + AddSeed(it.GetIndex()); + } + ++it; + } + } + + if (m_Seeds.size() != 0) { + // Explosion controlled region growing + typedef clitk::ExplosionControlledThresholdConnectedImageFilter ImageFilterType; + typename ImageFilterType::Pointer f= ImageFilterType::New(); + f->SetInput(working_input); + f->SetVerbose(false); + f->SetLower(-2000); + f->SetUpper(GetUpperThresholdForTrachea()); + f->SetMinimumLowerThreshold(-2000); + f->SetMaximumUpperThreshold(0); + f->SetAdaptLowerBorder(false); + f->SetAdaptUpperBorder(true); + f->SetMinimumSize(5000); + f->SetReplaceValue(1); + f->SetMultiplier(GetMultiplierForTrachea()); + f->SetThresholdStepSize(GetThresholdStepSizeForTrachea()); + f->SetMinimumThresholdStepSize(1); + for(unsigned int i=0; iAddSeed(m_Seeds[i]); + } + f->Update(); + trachea_tmp = f->GetOutput(); + // Set output + StopCurrentStep(trachea_tmp); + + } + else { // Trachea not found + this->SetWarning("* WARNING * No seed found for trachea."); + // Set output + StopCurrentStep(); + } + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + StartNewStep("Extract the lung with Otsu filter"); + // Automated Otsu thresholding and relabeling + typedef itk::OtsuThresholdImageFilter OtsuThresholdImageFilterType; + typename OtsuThresholdImageFilterType::Pointer otsuFilter=OtsuThresholdImageFilterType::New(); + otsuFilter->SetInput(working_input); + otsuFilter->SetNumberOfHistogramBins(GetNumberOfHistogramBins()); + otsuFilter->SetInsideValue(this->GetForegroundValue()); + otsuFilter->SetOutsideValue(this->GetBackgroundValue()); + otsuFilter->Update(); + working_image = otsuFilter->GetOutput(); + + // Set output + StopCurrentStep(working_image); + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + StartNewStep("Select labels"); + // Keep right labels + working_image = LabelizeAndSelectLabels + (working_image, + GetBackgroundValue(), + GetForegroundValue(), + false, + GetMinimalComponentSize(), + GetLabelizeParameters2()); + + // Set output + StopCurrentStep(working_image); + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + if (m_Seeds.size() != 0) { // if ==0 ->no trachea found + StartNewStep("Remove the trachea"); + // Set the trachea + working_image = SetBackground + (working_image, trachea_tmp, 1, -1); + + // Dilate the trachea + static const unsigned int Dim = InputImageType::ImageDimension; + typedef itk::BinaryBallStructuringElement KernelType; + KernelType structuringElement; + structuringElement.SetRadius(GetRadiusForTrachea()); + structuringElement.CreateStructuringElement(); + typedef clitk::ConditionalBinaryDilateImageFilter ConditionalBinaryDilateImageFilterType; + typename ConditionalBinaryDilateImageFilterType::Pointer dilateFilter = ConditionalBinaryDilateImageFilterType::New(); + dilateFilter->SetBoundaryToForeground(false); + dilateFilter->SetKernel(structuringElement); + dilateFilter->SetBackgroundValue (1); + dilateFilter->SetForegroundValue (-1); + dilateFilter->SetInput (working_image); + dilateFilter->Update(); + working_image = dilateFilter->GetOutput(); + + // Set trachea with dilatation + trachea_tmp = SetBackground + (trachea_tmp, working_image, -1, this->GetForegroundValue()); + + // Remove the trachea + working_image = SetBackground + (working_image, working_image, -1, this->GetBackgroundValue()); + + // Label + working_image = LabelizeAndSelectLabels + (working_image, + GetBackgroundValue(), + GetForegroundValue(), + false, + GetMinimalComponentSize(), + GetLabelizeParameters3()); + + // Set output + StopCurrentStep(working_image); + } + + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + typedef clitk::AutoCropFilter CropFilterType; + typename CropFilterType::Pointer cropFilter = CropFilterType::New(); + if (m_Seeds.size() != 0) { // if ==0 ->no trachea found + StartNewStep("Croping trachea"); + cropFilter->SetInput(trachea_tmp); + cropFilter->Update(); // Needed + typedef itk::CastImageFilter CastImageFilterType; + typename CastImageFilterType::Pointer caster= CastImageFilterType::New(); + caster->SetInput(cropFilter->GetOutput()); + caster->Update(); + trachea = caster->GetOutput(); + StopCurrentStep(trachea); + } + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + StartNewStep("Croping lung"); + cropFilter = CropFilterType::New(); // Needed to reset pipeline + cropFilter->SetInput(working_image); + cropFilter->Update(); + working_image = cropFilter->GetOutput(); + StopCurrentStep(working_image); + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + StartNewStep("Separate Left/Right lungs"); + // Initial label + working_image = Labelize(working_image, + GetBackgroundValue(), + false, + GetMinimalComponentSize()); + + // Count the labels + typedef itk::StatisticsImageFilter StatisticsImageFilterType; + typename StatisticsImageFilterType::Pointer statisticsImageFilter=StatisticsImageFilterType::New(); + statisticsImageFilter->SetInput(working_image); + statisticsImageFilter->Update(); + unsigned int initialNumberOfLabels = statisticsImageFilter->GetMaximum(); + working_image = statisticsImageFilter->GetOutput(); + + // Decompose the first label + static const unsigned int Dim = InputImageType::ImageDimension; + if (initialNumberOfLabels<2) { + // Structuring element radius + typename InputImageType::SizeType radius; + for (unsigned int i=0;i DecomposeAndReconstructFilterType; + typename DecomposeAndReconstructFilterType::Pointer decomposeAndReconstructFilter=DecomposeAndReconstructFilterType::New(); + decomposeAndReconstructFilter->SetInput(working_image); + decomposeAndReconstructFilter->SetVerbose(false); + decomposeAndReconstructFilter->SetRadius(radius); + decomposeAndReconstructFilter->SetMaximumNumberOfLabels(2); + decomposeAndReconstructFilter->SetMinimumObjectSize(this->GetMinimalComponentSize()); + decomposeAndReconstructFilter->SetMinimumNumberOfIterations(1); + decomposeAndReconstructFilter->SetBackgroundValue(this->GetBackgroundValue()); + decomposeAndReconstructFilter->SetForegroundValue(this->GetForegroundValue()); + decomposeAndReconstructFilter->SetFullyConnected(true); + decomposeAndReconstructFilter->SetNumberOfNewLabels(1); + decomposeAndReconstructFilter->Update(); + working_image = decomposeAndReconstructFilter->GetOutput(); + } + + // Retain labels (lungs) + typedef itk::ThresholdImageFilter ThresholdImageFilterType; + typename ThresholdImageFilterType::Pointer thresholdFilter = ThresholdImageFilterType::New(); + thresholdFilter->SetInput(working_image); + thresholdFilter->ThresholdAbove(2); + thresholdFilter->SetOutsideValue(this->GetBackgroundValue()); + thresholdFilter->Update(); + working_image = thresholdFilter->GetOutput(); + StopCurrentStep (working_image); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLungFilter:: +GenerateData() { + // Final Cast + typedef itk::CastImageFilter CastImageFilterType; + typename CastImageFilterType::Pointer caster= CastImageFilterType::New(); + caster->SetInput(working_image); + caster->Update(); + // Set output + //this->SetNthOutput(0, caster->GetOutput()); // -> no because redo filter otherwise + this->GraftOutput(caster->GetOutput()); + return; +} +//-------------------------------------------------------------------- + + +#endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX diff --git a/segmentation/clitkExtractLungGenericFilter.h b/segmentation/clitkExtractLungGenericFilter.h new file mode 100644 index 0000000..7d6306b --- /dev/null +++ b/segmentation/clitkExtractLungGenericFilter.h @@ -0,0 +1,70 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKEXTRACTLUNGSGENERICFILTER_H +#define CLITKEXTRACTLUNGSGENERICFILTER_H + +#include "clitkIO.h" +#include "clitkImageToImageGenericFilter.h" +#include "clitkExtractLungFilter.h" + +//-------------------------------------------------------------------- +namespace clitk +{ + + template + class ITK_EXPORT ExtractLungGenericFilter: + public ImageToImageGenericFilter > + { + + public: + //-------------------------------------------------------------------- + ExtractLungGenericFilter(); + + //-------------------------------------------------------------------- + typedef ExtractLungGenericFilter Self; + typedef ImageToImageGenericFilter > Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + //-------------------------------------------------------------------- + itkNewMacro(Self); + itkTypeMacro(ExtractLungGenericFilter, LightObject); + + //-------------------------------------------------------------------- + void SetArgsInfo(const ArgsInfoType & a); + + //-------------------------------------------------------------------- + // Main function called each time the filter is updated + template + void UpdateWithInputImageType(); + + protected: + template void InitializeImageType(); + ArgsInfoType mArgsInfo; + + }; // end class + //-------------------------------------------------------------------- + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkExtractLungGenericFilter.txx" +#endif + +#endif // #define CLITKEXTRACTLUNGSGENERICFILTER_H diff --git a/segmentation/clitkExtractLungGenericFilter.txx b/segmentation/clitkExtractLungGenericFilter.txx new file mode 100644 index 0000000..18fc2cf --- /dev/null +++ b/segmentation/clitkExtractLungGenericFilter.txx @@ -0,0 +1,105 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKEXTRACTLUNGSGENERICFILTER_TXX +#define CLITKEXTRACTLUNGSGENERICFILTER_TXX + +#include "clitkImageCommon.h" + +//-------------------------------------------------------------------- +template +clitk::ExtractLungGenericFilter::ExtractLungGenericFilter(): + ImageToImageGenericFilter("ExtractLung") +{ + // Default values + cmdline_parser_clitkExtractLung_init(&mArgsInfo); + InitializeImageType<3>(); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +template +void clitk::ExtractLungGenericFilter::InitializeImageType() +{ + ADD_IMAGE_TYPE(Dim, short); + // ADD_IMAGE_TYPE(Dim, int); + // ADD_IMAGE_TYPE(Dim, float); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void clitk::ExtractLungGenericFilter::SetArgsInfo(const ArgsInfoType & a) +{ + mArgsInfo=a; + SetIOVerbose(mArgsInfo.verbose_flag); + if (mArgsInfo.imagetypes_flag) this->PrintAvailableImageTypes(); + if (mArgsInfo.input_given) AddInputFilename(mArgsInfo.input_arg); + if (mArgsInfo.patient_given) AddInputFilename(mArgsInfo.patient_arg); + if (mArgsInfo.output_given) AddOutputFilename(mArgsInfo.output_arg); + if (mArgsInfo.outputTrachea_given) AddOutputFilename(mArgsInfo.outputTrachea_arg); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +// Update with the number of dimensions and the pixeltype +//-------------------------------------------------------------------- +template +template +void clitk::ExtractLungGenericFilter::UpdateWithInputImageType() +{ + // Mask & output image type + typedef itk::Image OutputImageType; + typedef itk::Image MaskImageType; + + // Reading input + typename ImageType::Pointer input = this->template GetInput(0); + typename MaskImageType::Pointer patient = this->template GetInput(1); + + // Create filter + typedef clitk::ExtractLungFilter FilterType; + typename FilterType::Pointer filter = FilterType::New(); + + // Set global Options + filter->SetArgsInfo(mArgsInfo); + filter->SetInput(input); + filter->SetInputPatientMask(patient, mArgsInfo.patientBG_arg); + + // Go ! + filter->Update(); + + // Check if error + if (filter->HasError()) { + SetLastError(filter->GetLastError()); + // No output + return; + } + + // Write/Save results + typename OutputImageType::Pointer output = filter->GetOutput(); + this->template SetNextOutput(output); + if (mArgsInfo.outputTrachea_given) + this->template SetNextOutput(filter->GetTracheaImage()); +} +//-------------------------------------------------------------------- + +#endif //#define CLITKEXTRACTLUNGSGENERICFILTER_TXX diff --git a/segmentation/clitkExtractLymphStations.cxx b/segmentation/clitkExtractLymphStations.cxx new file mode 100644 index 0000000..cf392f8 --- /dev/null +++ b/segmentation/clitkExtractLymphStations.cxx @@ -0,0 +1,44 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 +======================================================================-====*/ + +// clitk +#include "clitkExtractLymphStations_ggo.h" +#include "clitkExtractLymphStationsGenericFilter.h" + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) +{ + + // Init command line + GGO(clitkExtractLymphStations, args_info); + CLITK_INIT; + + // Filter + typedef clitk::ExtractLymphStationsGenericFilter FilterType; + FilterType::Pointer filter = FilterType::New(); + + filter->SetArgsInfo(args_info); + filter->Update(); + + if (filter->HasError()) { + std::cout << filter->GetLastError() << std::endl; + } + + return EXIT_SUCCESS; +} // This is the end, my friend +//-------------------------------------------------------------------- diff --git a/segmentation/clitkExtractLymphStations.ggo b/segmentation/clitkExtractLymphStations.ggo new file mode 100644 index 0000000..78efb35 --- /dev/null +++ b/segmentation/clitkExtractLymphStations.ggo @@ -0,0 +1,27 @@ +#File clitkExtractLymphStations.ggo +package "clitkExtractLymphStations" +version "1.0" +purpose "Extract LymphStations with help of TODO" + +option "config" - "Config file" string no +option "imagetypes" - "Display allowed image types" flag off +option "verbose" v "Verbose" flag off +option "verboseStep" - "Verbose each step" flag off +option "writeStep" w "Write image at each step" flag off +option "verboseOption" - "Display options values" flag off +option "verboseWarningOff" - "Do not display warning" flag off + +section "I/O" + +option "mediastinum" m "Input mediastinum mask filename" string yes +option "trachea" t "Input trachea mask filename" string yes +option "output" o "Output lungs mask filename" string yes + +option "carenaZposition" c "Sup-Inf position of the carena (in mm)" double no +option "middleLobeBronchusZposition" b "Sup-Inf position of the middle lobe bronchus (in mm)" double no +option "spacing" - "Intermediate resampling spacing" double no default="6" +option "fuzzy1" - "Fuzzy relative position threshold" double no default="0.6" + + + + diff --git a/segmentation/clitkExtractLymphStationsFilter.h b/segmentation/clitkExtractLymphStationsFilter.h new file mode 100644 index 0000000..e90abd4 --- /dev/null +++ b/segmentation/clitkExtractLymphStationsFilter.h @@ -0,0 +1,147 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKEXTRACTLYMPHSTATIONSFILTER_H +#define CLITKEXTRACTLYMPHSTATIONSFILTER_H + +#include "clitkFilterBase.h" + +namespace clitk { + + //-------------------------------------------------------------------- + /* + Try to extract the LymphStations part of a thorax CT. + Inputs : + - Patient label image + - Lungs label image + - Bones label image + */ + //-------------------------------------------------------------------- + + template + class ITK_EXPORT ExtractLymphStationsFilter: + public clitk::FilterBase, + public itk::ImageToImageFilter + { + + public: + /** Standard class typedefs. */ + typedef itk::ImageToImageFilter Superclass; + typedef ExtractLymphStationsFilter Self; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(ExtractLymphStationsFilter, InPlaceImageFilter); + FILTERBASE_INIT; + + /** Some convenient typedefs. */ + typedef TImageType ImageType; + typedef typename ImageType::ConstPointer ImageConstPointer; + typedef typename ImageType::Pointer ImagePointer; + typedef typename ImageType::RegionType ImageRegionType; + typedef typename ImageType::PixelType ImagePixelType; + typedef typename ImageType::SizeType ImageSizeType; + typedef typename ImageType::IndexType ImageIndexType; + + /** Connect inputs */ + void SetInputMediastinumLabelImage(const TImageType * image, ImagePixelType bg=0); + void SetInputTracheaLabelImage(const TImageType * image, ImagePixelType bg=0); + + /** ImageDimension constants */ + itkStaticConstMacro(ImageDimension, unsigned int, TImageType::ImageDimension); + + // Set all options at a time + template + void SetArgsInfo(ArgsInfoType arg); + + // Background / Foreground + itkSetMacro(BackgroundValueMediastinum, ImagePixelType); + itkGetConstMacro(BackgroundValueMediastinum, ImagePixelType); + //GGO_DefineOption(MediastinumBG, SetBackgroundValueMediastinum, ImagePixelType); + + itkSetMacro(BackgroundValueTrachea, ImagePixelType); + itkGetConstMacro(BackgroundValueTrachea, ImagePixelType); + //GGO_DefineOption(TracheaBG, SetBackgroundValueTrachea, ImagePixelType); + + itkGetConstMacro(BackgroundValue, ImagePixelType); + itkGetConstMacro(ForegroundValue, ImagePixelType); + + itkSetMacro(CarenaZPositionInMM, double); + itkGetConstMacro(CarenaZPositionInMM, double); + GGO_DefineOption(carenaZposition, SetCarenaZPositionInMM, double); + + itkSetMacro(MiddleLobeBronchusZPositionInMM, double); + itkGetConstMacro(MiddleLobeBronchusZPositionInMM, double); + GGO_DefineOption(middleLobeBronchusZposition, SetMiddleLobeBronchusZPositionInMM, double); + + itkSetMacro(IntermediateSpacing, double); + itkGetConstMacro(IntermediateSpacing, double); + GGO_DefineOption(spacing, SetIntermediateSpacing, double); + + itkSetMacro(FuzzyThreshold1, double); + itkGetConstMacro(FuzzyThreshold1, double); + GGO_DefineOption(fuzzy1, SetFuzzyThreshold1, double); + + + + protected: + ExtractLymphStationsFilter(); + virtual ~ExtractLymphStationsFilter() {} + + virtual void GenerateOutputInformation(); + virtual void GenerateInputRequestedRegion(); + virtual void GenerateData(); + + itkSetMacro(BackgroundValue, ImagePixelType); + itkSetMacro(ForegroundValue, ImagePixelType); + + ImageConstPointer m_mediastinum; + ImageConstPointer m_trachea; + ImagePointer m_working_image; + ImagePointer m_working_trachea; + ImagePointer m_output; + + ImagePixelType m_BackgroundValueMediastinum; + ImagePixelType m_BackgroundValueTrachea; + ImagePixelType m_BackgroundValue; + ImagePixelType m_ForegroundValue; + + double m_CarenaZPositionInMM; + double m_MiddleLobeBronchusZPositionInMM; + double m_IntermediateSpacing; + double m_FuzzyThreshold1; + + private: + ExtractLymphStationsFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + }; // end class + //-------------------------------------------------------------------- + +} // end namespace clitk +//-------------------------------------------------------------------- + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkExtractLymphStationsFilter.txx" +#endif + +#endif diff --git a/segmentation/clitkExtractLymphStationsFilter.txx b/segmentation/clitkExtractLymphStationsFilter.txx new file mode 100644 index 0000000..0bcb447 --- /dev/null +++ b/segmentation/clitkExtractLymphStationsFilter.txx @@ -0,0 +1,286 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKEXTRACTLYMPHSTATIONSFILTER_TXX +#define CLITKEXTRACTLYMPHSTATIONSFILTER_TXX + +// clitk +#include "clitkCommon.h" +#include "clitkExtractLymphStationsFilter.h" +#include "clitkAddRelativePositionConstraintToLabelImageFilter.h" +#include "clitkSegmentationFunctions.h" +#include "clitkAutoCropFilter.h" +#include "clitkSegmentationFunctions.h" + +// itk +#include +#include +#include +#include +#include +#include + +// itk ENST +#include "RelativePositionPropImageFilter.h" + +//-------------------------------------------------------------------- +template +clitk::ExtractLymphStationsFilter:: +ExtractLymphStationsFilter(): + clitk::FilterBase(), + itk::ImageToImageFilter() +{ + this->SetNumberOfRequiredInputs(1); + SetBackgroundValueMediastinum(0); + SetBackgroundValueTrachea(0); + SetBackgroundValue(0); + SetForegroundValue(1); + + SetIntermediateSpacing(6); + SetFuzzyThreshold1(0.6); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +SetInputMediastinumLabelImage(const TImageType * image, ImagePixelType bg) { + this->SetNthInput(0, const_cast(image)); + m_BackgroundValueMediastinum = bg; + SetCarenaZPositionInMM(image->GetOrigin()[2]+image->GetLargestPossibleRegion().GetSize()[2]*image->GetSpacing()[2]); + SetMiddleLobeBronchusZPositionInMM(image->GetOrigin()[2]); + // DD(m_CarenaZPositionInMM); +// DD(m_MiddleLobeBronchusZPositionInMM); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +SetInputTracheaLabelImage(const TImageType * image, ImagePixelType bg) { + this->SetNthInput(1, const_cast(image)); + m_BackgroundValueTrachea = bg; +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +template +void +clitk::ExtractLymphStationsFilter:: +SetArgsInfo(ArgsInfoType mArgsInfo) +{ + SetVerboseOption_GGO(mArgsInfo); + SetVerboseStep_GGO(mArgsInfo); + SetWriteStep_GGO(mArgsInfo); + SetVerboseWarningOff_GGO(mArgsInfo); + SetCarenaZPositionInMM_GGO(mArgsInfo); + SetMiddleLobeBronchusZPositionInMM_GGO(mArgsInfo); + SetIntermediateSpacing_GGO(mArgsInfo); + SetFuzzyThreshold1_GGO(mArgsInfo); + //SetBackgroundValueMediastinum_GGO(mArgsInfo); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +GenerateOutputInformation() { + // Superclass::GenerateOutputInformation(); + + // Get input + m_mediastinum = dynamic_cast(itk::ProcessObject::GetInput(0)); + m_trachea = dynamic_cast(itk::ProcessObject::GetInput(1)); + + // ---------------------------------------------------------------- + // ---------------------------------------------------------------- + // Superior limit = carena + // Inferior limit = origine middle lobe bronchus + StartNewStep("Inf/Sup limits with carena/bronchus"); + ImageRegionType region = m_mediastinum->GetLargestPossibleRegion(); DD(region); + ImageSizeType size = region.GetSize(); + ImageIndexType index = region.GetIndex(); + DD(m_CarenaZPositionInMM); + DD(m_MiddleLobeBronchusZPositionInMM); + index[2] = floor((m_MiddleLobeBronchusZPositionInMM - m_mediastinum->GetOrigin()[2]) / m_mediastinum->GetSpacing()[2]); + size[2] = ceil((m_CarenaZPositionInMM-m_MiddleLobeBronchusZPositionInMM) / m_mediastinum->GetSpacing()[2]); + region.SetSize(size); + region.SetIndex(index); + DD(region); + typedef itk::RegionOfInterestImageFilter CropFilterType; + typename CropFilterType::Pointer cropFilter = CropFilterType::New(); + cropFilter->SetInput(m_mediastinum); + cropFilter->SetRegionOfInterest(region); + cropFilter->Update(); + m_working_image = cropFilter->GetOutput(); + // Auto Crop (because following rel pos is faster) + m_working_image = clitk::AutoCrop(m_working_image, 0); + StopCurrentStep(m_working_image); + m_output = m_working_image; + + // ---------------------------------------------------------------- + // ---------------------------------------------------------------- + // Separate trachea in two CCL + StartNewStep("Separate trachea"); + // DD(region); + ImageRegionType trachea_region = m_trachea->GetLargestPossibleRegion(); + for(int i=0; i<3; i++) { + index[i] = floor(((index[i]*m_mediastinum->GetSpacing()[i])+m_mediastinum->GetOrigin()[i] + -m_trachea->GetOrigin()[i])/m_trachea->GetSpacing()[i]); + // DD(index[i]); + size[i] = ceil((size[i]*m_mediastinum->GetSpacing()[i])/m_trachea->GetSpacing()[i]); + // DD(size[i]); + if (index[i] < 0) { + size[i] += index[i]; + index[i] = 0; + } + if (size[i]+index[i] > (trachea_region.GetSize()[i] + trachea_region.GetIndex()[i])) { + size[i] = trachea_region.GetSize()[i] + trachea_region.GetIndex()[i] - index[i]; + } + } + // DD(index); + // DD(size); + region.SetIndex(index); + region.SetSize(size); + // typedef itk::RegionOfInterestImageFilter CropFilterType; + // typename CropFilterType::Pointer + cropFilter = CropFilterType::New(); + // m_trachea.Print(std::cout); + cropFilter->SetInput(m_trachea); + cropFilter->SetRegionOfInterest(region); + cropFilter->Update(); + m_working_trachea = cropFilter->GetOutput(); + + // Labelize and consider two main labels + m_working_trachea = Labelize(m_working_trachea, 0, true, 1); + StopCurrentStep(m_working_trachea); + + // Detect wich label is at Left + typedef itk::ImageSliceConstIteratorWithIndex SliceIteratorType; + SliceIteratorType iter(m_working_trachea, m_working_trachea->GetLargestPossibleRegion()); + iter.SetFirstDirection(0); + iter.SetSecondDirection(1); + iter.GoToBegin(); + bool stop = false; + ImagePixelType leftLabel; + while (!stop) { + if (iter.Get() != m_BackgroundValueTrachea) { + // DD(iter.GetIndex()); + // DD((int)iter.Get()); + leftLabel = iter.Get(); + stop = true; + } + ++iter; + } + DD((int)leftLabel); + + // Relative position + StartNewStep("Left/Right limits with trachea"); + + // Select LeftLabel (set label 1 to 0) + ImagePointer temp = SetBackground(m_working_trachea, m_working_trachea, 1, 0); + writeImage(temp, "temp1.mhd"); + + // Left relative position + typedef clitk::AddRelativePositionConstraintToLabelImageFilter RelPosFilterType; + typename RelPosFilterType::Pointer relPosFilter = RelPosFilterType::New(); + relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId()); + relPosFilter->VerboseStepOff(); + relPosFilter->WriteStepOff(); + relPosFilter->SetInput(m_working_image); + relPosFilter->SetInputObject(temp); + relPosFilter->SetOrientationType(RelPosFilterType::RightTo); + relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing()); + relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold1()); + relPosFilter->Update(); + m_working_image = relPosFilter->GetOutput(); + + // Select RightLabel (set label 2 to 0) + temp = SetBackground(m_working_trachea, m_working_trachea, 2, 0); + writeImage(temp, "temp2.mhd"); + + // Left relative position + relPosFilter = RelPosFilterType::New(); + relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId()); + relPosFilter->VerboseStepOn(); + relPosFilter->WriteStepOn(); + relPosFilter->SetInput(m_working_image); + relPosFilter->SetInputObject(temp); + relPosFilter->SetOrientationType(RelPosFilterType::LeftTo); + relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing()); + relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold1()); + relPosFilter->Update(); + m_working_image = relPosFilter->GetOutput(); + + + //----------------------------------------------------- + // StartNewStep("Left/Right limits with trachea (slice by slice"); + // typedef SliceBySliceImageFilter(m_output); + + // Set output image information (required) + ImagePointer outputImage = this->GetOutput(0); + outputImage->SetRegions(m_working_image->GetLargestPossibleRegion()); + outputImage->SetOrigin(m_working_image->GetOrigin()); + outputImage->SetRequestedRegion(m_working_image->GetLargestPossibleRegion()); + DD("end2"); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +GenerateInputRequestedRegion() { + DD("GenerateInputRequestedRegion"); + // Call default + Superclass::GenerateInputRequestedRegion(); + // Following needed because output region can be greater than input (trachea) + ImagePointer mediastinum = dynamic_cast(itk::ProcessObject::GetInput(0)); + ImagePointer trachea = dynamic_cast(itk::ProcessObject::GetInput(1)); + mediastinum->SetRequestedRegion(mediastinum->GetLargestPossibleRegion()); + trachea->SetRequestedRegion(trachea->GetLargestPossibleRegion()); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +GenerateData() { + DD("GenerateData"); + // Final Step -> graft output (if SetNthOutput => redo) + this->GraftOutput(m_output); +} +//-------------------------------------------------------------------- + + +#endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX diff --git a/segmentation/clitkExtractLymphStationsGenericFilter.h b/segmentation/clitkExtractLymphStationsGenericFilter.h new file mode 100644 index 0000000..fa2d18c --- /dev/null +++ b/segmentation/clitkExtractLymphStationsGenericFilter.h @@ -0,0 +1,70 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKEXTRACTLYMPHSTATIONSSGENERICFILTER_H +#define CLITKEXTRACTLYMPHSTATIONSSGENERICFILTER_H + +#include "clitkIO.h" +#include "clitkImageToImageGenericFilter.h" +#include "clitkExtractLymphStationsFilter.h" + +//-------------------------------------------------------------------- +namespace clitk +{ + + template + class ITK_EXPORT ExtractLymphStationsGenericFilter: + public ImageToImageGenericFilter > + { + + public: + //-------------------------------------------------------------------- + ExtractLymphStationsGenericFilter(); + + //-------------------------------------------------------------------- + typedef ExtractLymphStationsGenericFilter Self; + typedef ImageToImageGenericFilter > Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + //-------------------------------------------------------------------- + itkNewMacro(Self); + itkTypeMacro(ExtractLymphStationsGenericFilter, LightObject); + + //-------------------------------------------------------------------- + void SetArgsInfo(const ArgsInfoType & a); + + //-------------------------------------------------------------------- + // Main function called each time the filter is updated + template + void UpdateWithInputImageType(); + + protected: + template void InitializeImageType(); + ArgsInfoType mArgsInfo; + + }; // end class + //-------------------------------------------------------------------- + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkExtractLymphStationsGenericFilter.txx" +#endif + +#endif // #define CLITKEXTRACTLYMPHSTATIONSSGENERICFILTER_H diff --git a/segmentation/clitkExtractLymphStationsGenericFilter.txx b/segmentation/clitkExtractLymphStationsGenericFilter.txx new file mode 100644 index 0000000..2644c1f --- /dev/null +++ b/segmentation/clitkExtractLymphStationsGenericFilter.txx @@ -0,0 +1,99 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKEXTRACTLYMPHSTATIONSSGENERICFILTER_TXX +#define CLITKEXTRACTLYMPHSTATIONSSGENERICFILTER_TXX + +#include "clitkImageCommon.h" + +//-------------------------------------------------------------------- +template +clitk::ExtractLymphStationsGenericFilter::ExtractLymphStationsGenericFilter(): + ImageToImageGenericFilter("ExtractLymphStations") +{ + // Default values + cmdline_parser_clitkExtractLymphStations_init(&mArgsInfo); + InitializeImageType<3>(); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +template +void clitk::ExtractLymphStationsGenericFilter::InitializeImageType() +{ + ADD_IMAGE_TYPE(Dim, uchar); + // ADD_IMAGE_TYPE(Dim, short); + // ADD_IMAGE_TYPE(Dim, int); + // ADD_IMAGE_TYPE(Dim, float); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void clitk::ExtractLymphStationsGenericFilter::SetArgsInfo(const ArgsInfoType & a) +{ + mArgsInfo=a; + SetIOVerbose(mArgsInfo.verbose_flag); + if (mArgsInfo.imagetypes_flag) this->PrintAvailableImageTypes(); + if (mArgsInfo.mediastinum_given) AddInputFilename(mArgsInfo.mediastinum_arg); + if (mArgsInfo.trachea_given) AddInputFilename(mArgsInfo.trachea_arg); + if (mArgsInfo.output_given) AddOutputFilename(mArgsInfo.output_arg); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +// Update with the number of dimensions and the pixeltype +//-------------------------------------------------------------------- +template +template +void clitk::ExtractLymphStationsGenericFilter::UpdateWithInputImageType() +{ + // Reading input + typename ImageType::Pointer mediastinum = this->template GetInput(0); + typename ImageType::Pointer trachea = this->template GetInput(1); + + // Create filter + typedef clitk::ExtractLymphStationsFilter FilterType; + typename FilterType::Pointer filter = FilterType::New(); + + // Set global Options + filter->SetInputMediastinumLabelImage(mediastinum, 0); // change 0 with BG + filter->SetInputTracheaLabelImage(trachea, 0); // change 0 with BG + filter->SetArgsInfo(mArgsInfo); + + // Go ! + filter->Update(); + + // Check if error + if (filter->HasError()) { + SetLastError(filter->GetLastError()); + // No output + return; + } + + // Write/Save results + typename ImageType::Pointer output = filter->GetOutput(); + this->template SetNextOutput(output); +} +//-------------------------------------------------------------------- + +#endif //#define CLITKEXTRACTLYMPHSTATIONSSGENERICFILTER_TXX diff --git a/segmentation/clitkExtractMediastinum.cxx b/segmentation/clitkExtractMediastinum.cxx new file mode 100644 index 0000000..8a1feec --- /dev/null +++ b/segmentation/clitkExtractMediastinum.cxx @@ -0,0 +1,44 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 +======================================================================-====*/ + +// clitk +#include "clitkExtractMediastinum_ggo.h" +#include "clitkExtractMediastinumGenericFilter.h" + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) +{ + + // Init command line + GGO(clitkExtractMediastinum, args_info); + CLITK_INIT; + + // Filter + typedef clitk::ExtractMediastinumGenericFilter FilterType; + FilterType::Pointer filter = FilterType::New(); + + filter->SetArgsInfo(args_info); + filter->Update(); + + if (filter->HasError()) { + std::cout << filter->GetLastError() << std::endl; + } + + return EXIT_SUCCESS; +} // This is the end, my friend +//-------------------------------------------------------------------- diff --git a/segmentation/clitkExtractMediastinum.ggo b/segmentation/clitkExtractMediastinum.ggo new file mode 100644 index 0000000..490c673 --- /dev/null +++ b/segmentation/clitkExtractMediastinum.ggo @@ -0,0 +1,34 @@ +#File clitkExtractMediastinum.ggo +package "clitkExtractMediastinum" +version "1.0" +purpose "Extract mediastinum with help of patient/lungs/bones mask" + +option "config" - "Config file" string no +option "imagetypes" - "Display allowed image types" flag off +option "verbose" v "Verbose" flag off +option "verboseStep" - "Verbose each step" flag off +option "writeStep" w "Write image at each step" flag off +option "verboseOption" - "Display options values" flag off +option "verboseWarningOff" - "Do not display warning" flag off + +section "I/O" + +option "patient" p "Input patient mask filename" string yes +option "patientBG" - "Patient Background" int default="0" no +option "bones" b "Input bones mask filename" string yes +option "bonesBG" - "Bones Background" int default="0" no +option "lung" l "Input lung mask filename" string yes +option "lungBG" - "Lung Background" int default="0" no +option "lungLeft" - "Lung Left value" int default="1" no +option "lungRight" - "Lung Right value" int default="2" no + +option "output" o "Output lungs mask filename" string yes + +section "Step 1 : Left/Right limits with lungs" + +option "spacing" - "Intermediate resampling spacing" double no default="6" +option "fuzzy1" - "Fuzzy relative position threshold" double no default="0.6" + +section "Step 2 : Ant/Post limits with bones" + +option "fuzzy2" - "Fuzzy relative position threshold" double no default="0.6" diff --git a/segmentation/clitkExtractMediastinumFilter.h b/segmentation/clitkExtractMediastinumFilter.h new file mode 100644 index 0000000..6c252d4 --- /dev/null +++ b/segmentation/clitkExtractMediastinumFilter.h @@ -0,0 +1,152 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKEXTRACTMEDIASTINUMFILTER_H +#define CLITKEXTRACTMEDIASTINUMFILTER_H + +#include "clitkFilterBase.h" + +namespace clitk { + + //-------------------------------------------------------------------- + /* + Try to extract the mediastinum part of a thorax CT. + Inputs : + - Patient label image + - Lungs label image + - Bones label image + */ + //-------------------------------------------------------------------- + + template + class ITK_EXPORT ExtractMediastinumFilter: + public clitk::FilterBase, + public itk::ImageToImageFilter + { + + public: + /** Standard class typedefs. */ + typedef itk::ImageToImageFilter Superclass; + typedef ExtractMediastinumFilter Self; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(ExtractMediastinumFilter, InPlaceImageFilter); + FILTERBASE_INIT; + + /** Some convenient typedefs. */ + typedef TImageType ImageType; + typedef typename ImageType::ConstPointer ImageConstPointer; + typedef typename ImageType::Pointer ImagePointer; + typedef typename ImageType::RegionType ImageRegionType; + typedef typename ImageType::PixelType ImagePixelType; + typedef typename ImageType::SizeType ImageSizeType; + typedef typename ImageType::IndexType ImageIndexType; + + /** Connect inputs */ + void SetInputPatientLabelImage(const TImageType * image, ImagePixelType bg=0); + void SetInputLungLabelImage(const TImageType * image, ImagePixelType bg=0, + ImagePixelType fgLeftLung=1, ImagePixelType fgRightLung=2); + void SetInputBonesLabelImage(const TImageType * image, ImagePixelType bg=0); + + /** ImageDimension constants */ + itkStaticConstMacro(ImageDimension, unsigned int, TImageType::ImageDimension); + + // Set all options at a time + template + void SetArgsInfo(ArgsInfoType arg); + + // Background / Foreground + itkSetMacro(BackgroundValuePatient, ImagePixelType); + itkGetConstMacro(BackgroundValuePatient, ImagePixelType); + GGO_DefineOption(patientBG, SetBackgroundValuePatient, ImagePixelType); + + itkSetMacro(BackgroundValueLung, ImagePixelType); + itkGetConstMacro(BackgroundValueLung, ImagePixelType); + GGO_DefineOption(lungBG, SetBackgroundValueLung, ImagePixelType); + + itkSetMacro(BackgroundValueBones, ImagePixelType); + itkGetConstMacro(BackgroundValueBones, ImagePixelType); + GGO_DefineOption(bonesBG, SetBackgroundValueBones, ImagePixelType); + + itkGetConstMacro(BackgroundValue, ImagePixelType); + itkGetConstMacro(ForegroundValue, ImagePixelType); + + itkSetMacro(ForegroundValueLeftLung, ImagePixelType); + itkGetConstMacro(ForegroundValueLeftLung, ImagePixelType); + GGO_DefineOption(lungLeft, SetForegroundValueLeftLung, ImagePixelType); + + itkSetMacro(ForegroundValueRightLung, ImagePixelType); + itkGetConstMacro(ForegroundValueRightLung, ImagePixelType); + GGO_DefineOption(lungRight, SetForegroundValueRightLung, ImagePixelType); + + itkSetMacro(IntermediateSpacing, double); + itkGetConstMacro(IntermediateSpacing, double); + GGO_DefineOption(spacing, SetIntermediateSpacing, double); + + itkSetMacro(FuzzyThreshold1, double); + itkGetConstMacro(FuzzyThreshold1, double); + GGO_DefineOption(fuzzy1, SetFuzzyThreshold1, double); + + itkSetMacro(FuzzyThreshold2, double); + itkGetConstMacro(FuzzyThreshold2, double); + GGO_DefineOption(fuzzy2, SetFuzzyThreshold2, double); + + protected: + ExtractMediastinumFilter(); + virtual ~ExtractMediastinumFilter() {} + + virtual void GenerateOutputInformation(); + virtual void GenerateInputRequestedRegion(); + virtual void GenerateData(); + + itkSetMacro(BackgroundValue, ImagePixelType); + itkSetMacro(ForegroundValue, ImagePixelType); + + ImagePixelType m_BackgroundValuePatient; + ImagePixelType m_BackgroundValueLung; + ImagePixelType m_BackgroundValueBones; + ImagePixelType m_ForegroundValueLeftLung; + ImagePixelType m_ForegroundValueRightLung; + + ImagePixelType m_BackgroundValue; + ImagePixelType m_ForegroundValue; + + double m_IntermediateSpacing; + double m_FuzzyThreshold1; + double m_FuzzyThreshold2; + + private: + ExtractMediastinumFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + }; // end class + //-------------------------------------------------------------------- + +} // end namespace clitk +//-------------------------------------------------------------------- + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkExtractMediastinumFilter.txx" +#endif + +#endif diff --git a/segmentation/clitkExtractMediastinumFilter.txx b/segmentation/clitkExtractMediastinumFilter.txx new file mode 100644 index 0000000..b5535cf --- /dev/null +++ b/segmentation/clitkExtractMediastinumFilter.txx @@ -0,0 +1,263 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKEXTRACTMEDIASTINUMFILTER_TXX +#define CLITKEXTRACTMEDIASTINUMFILTER_TXX + +// clitk +#include "clitkCommon.h" +#include "clitkExtractMediastinumFilter.h" +#include "clitkAddRelativePositionConstraintToLabelImageFilter.h" +#include "clitkSegmentationFunctions.h" + +// itk +#include +#include "itkStatisticsLabelMapFilter.h" +#include "itkLabelImageToStatisticsLabelMapFilter.h" +#include "itkRegionOfInterestImageFilter.h" +#include "itkBinaryThresholdImageFilter.h" + +// itk ENST +#include "RelativePositionPropImageFilter.h" + +//-------------------------------------------------------------------- +template +clitk::ExtractMediastinumFilter:: +ExtractMediastinumFilter(): + clitk::FilterBase(), + itk::ImageToImageFilter() +{ + this->SetNumberOfRequiredInputs(3); + + SetBackgroundValuePatient(0); + SetBackgroundValueLung(0); + SetBackgroundValueBones(0); + SetForegroundValueLeftLung(1); + SetForegroundValueRightLung(2); + SetBackgroundValue(0); + SetForegroundValue(1); + + SetIntermediateSpacing(6); + SetFuzzyThreshold1(0.6); + SetFuzzyThreshold2(0.7); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractMediastinumFilter:: +SetInputPatientLabelImage(const TImageType * image, ImagePixelType bg) { + this->SetNthInput(0, const_cast(image)); + m_BackgroundValuePatient = bg; +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractMediastinumFilter:: +SetInputLungLabelImage(const TImageType * image, ImagePixelType bg, + ImagePixelType fgLeft, ImagePixelType fgRight) { + this->SetNthInput(1, const_cast(image)); + m_BackgroundValueLung = bg; + m_ForegroundValueLeftLung = fgLeft; + m_ForegroundValueRightLung = fgRight; +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractMediastinumFilter:: +SetInputBonesLabelImage(const TImageType * image, ImagePixelType bg) { + this->SetNthInput(2, const_cast(image)); + m_BackgroundValueBones = bg; +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +template +void +clitk::ExtractMediastinumFilter:: +SetArgsInfo(ArgsInfoType mArgsInfo) +{ + SetVerboseOption_GGO(mArgsInfo); + SetVerboseStep_GGO(mArgsInfo); + SetWriteStep_GGO(mArgsInfo); + SetVerboseWarningOff_GGO(mArgsInfo); + + SetBackgroundValuePatient_GGO(mArgsInfo); + SetBackgroundValueLung_GGO(mArgsInfo); + SetBackgroundValueBones_GGO(mArgsInfo); + + SetForegroundValueLeftLung_GGO(mArgsInfo); + SetForegroundValueRightLung_GGO(mArgsInfo); + + SetIntermediateSpacing_GGO(mArgsInfo); + SetFuzzyThreshold1_GGO(mArgsInfo); + SetFuzzyThreshold2_GGO(mArgsInfo); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractMediastinumFilter:: +GenerateOutputInformation() { + ImagePointer input = dynamic_cast(itk::ProcessObject::GetInput(0)); + ImagePointer outputImage = this->GetOutput(0); + outputImage->SetRegions(outputImage->GetLargestPossibleRegion()); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractMediastinumFilter:: +GenerateInputRequestedRegion() { + // Call default + Superclass::GenerateInputRequestedRegion(); + // Get input pointers + ImagePointer patient = dynamic_cast(itk::ProcessObject::GetInput(0)); + ImagePointer lung = dynamic_cast(itk::ProcessObject::GetInput(1)); + ImagePointer bones = dynamic_cast(itk::ProcessObject::GetInput(2)); + + patient->SetRequestedRegion(patient->GetLargestPossibleRegion()); + lung->SetRequestedRegion(lung->GetLargestPossibleRegion()); + bones->SetRequestedRegion(bones->GetLargestPossibleRegion()); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractMediastinumFilter:: +GenerateData() { + // Get input pointers + ImageConstPointer patient = dynamic_cast(itk::ProcessObject::GetInput(0)); + ImageConstPointer lung = dynamic_cast(itk::ProcessObject::GetInput(1)); + ImageConstPointer bones = dynamic_cast(itk::ProcessObject::GetInput(2)); + + // Get output pointer + ImagePointer output; + + // Step 1: patient minus lungs, minus bones + StartNewStep("Patient contours minus lungs and minus bones"); + typedef clitk::BooleanOperatorLabelImageFilter BoolFilterType; + typename BoolFilterType::Pointer boolFilter = BoolFilterType::New(); + boolFilter->InPlaceOn(); + boolFilter->SetInput1(patient); + boolFilter->SetInput2(lung); + boolFilter->SetOperationType(BoolFilterType::AndNot); + boolFilter->Update(); + boolFilter->SetInput1(boolFilter->GetOutput()); + boolFilter->SetInput2(bones); + boolFilter->SetOperationType(BoolFilterType::AndNot); + boolFilter->Update(); + output = boolFilter->GetOutput(); + + output = clitk::AutoCrop(output, GetBackgroundValue()); + ////autoCropFilter->GetOutput(); typedef clitk::AutoCropFilter CropFilterType; + //typename CropFilterType::Pointer cropFilter = CropFilterType::New(); + //cropFilter->SetInput(output); + //cropFilter->Update(); + //output = cropFilter->GetOutput(); + + this->template StopCurrentStep(output); + + // Step 2: LR limits from lung (need separate lung ?) + StartNewStep("Left/Right limits with lungs"); + typedef clitk::AddRelativePositionConstraintToLabelImageFilter RelPosFilterType; + typename RelPosFilterType::Pointer relPosFilter = RelPosFilterType::New(); + relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId()); + relPosFilter->VerboseStepOff(); + relPosFilter->WriteStepOff(); + relPosFilter->SetInput(output); + relPosFilter->SetInputObject(lung); + relPosFilter->SetOrientationType(RelPosFilterType::LeftTo); + relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing()); + relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold1()); + relPosFilter->Update(); + output = relPosFilter->GetOutput(); + + relPosFilter->SetInput(output); + relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId()); + relPosFilter->VerboseStepOff(); + relPosFilter->WriteStepOff(); + relPosFilter->SetInputObject(lung); + relPosFilter->SetOrientationType(RelPosFilterType::RightTo); + relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing()); + relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold1()); + relPosFilter->Update(); + output = relPosFilter->GetOutput(); + this->template StopCurrentStep(output); + + // Step 3: AP limits from bones + StartNewStep("Ant/Post limits with bones"); + relPosFilter->SetCurrentStepNumber(0); + relPosFilter->ResetPipeline();// = RelPosFilterType::New(); + relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId()); + relPosFilter->VerboseStepOff(); + relPosFilter->WriteStepOff(); + relPosFilter->SetInput(output); + relPosFilter->SetInputObject(bones); + relPosFilter->SetOrientationType(RelPosFilterType::AntTo); + relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing()); + relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold2()); + relPosFilter->Update(); + + relPosFilter->SetInput(relPosFilter->GetOutput()); + relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId()); + relPosFilter->VerboseStepOff(); + relPosFilter->WriteStepOff(); + relPosFilter->SetInputObject(bones); + relPosFilter->SetOrientationType(RelPosFilterType::PostTo); + relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing()); + relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold2()); + relPosFilter->Update(); + output = relPosFilter->GetOutput(); + this->template StopCurrentStep(output); + + // Get CCL + output = clitk::Labelize(output, GetBackgroundValue(), true, 100); + // output = RemoveLabels(output, BG, param->GetLabelsToRemove()); + output = clitk::KeepLabels(output, GetBackgroundValue(), + GetForegroundValue(), 1, 1, 0); + + output = clitk::AutoCrop(output, GetBackgroundValue()); + // cropFilter = CropFilterType::New(); + //cropFilter->SetInput(output); + //cropFilter->Update(); + //output = cropFilter->GetOutput(); + + // Final Step -> set output + this->SetNthOutput(0, output); +} +//-------------------------------------------------------------------- + + +#endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX diff --git a/segmentation/clitkExtractMediastinumGenericFilter.h b/segmentation/clitkExtractMediastinumGenericFilter.h new file mode 100644 index 0000000..70a4532 --- /dev/null +++ b/segmentation/clitkExtractMediastinumGenericFilter.h @@ -0,0 +1,70 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKEXTRACTMEDIASTINUMSGENERICFILTER_H +#define CLITKEXTRACTMEDIASTINUMSGENERICFILTER_H + +#include "clitkIO.h" +#include "clitkImageToImageGenericFilter.h" +#include "clitkExtractMediastinumFilter.h" + +//-------------------------------------------------------------------- +namespace clitk +{ + + template + class ITK_EXPORT ExtractMediastinumGenericFilter: + public ImageToImageGenericFilter > + { + + public: + //-------------------------------------------------------------------- + ExtractMediastinumGenericFilter(); + + //-------------------------------------------------------------------- + typedef ExtractMediastinumGenericFilter Self; + typedef ImageToImageGenericFilter > Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + //-------------------------------------------------------------------- + itkNewMacro(Self); + itkTypeMacro(ExtractMediastinumGenericFilter, LightObject); + + //-------------------------------------------------------------------- + void SetArgsInfo(const ArgsInfoType & a); + + //-------------------------------------------------------------------- + // Main function called each time the filter is updated + template + void UpdateWithInputImageType(); + + protected: + template void InitializeImageType(); + ArgsInfoType mArgsInfo; + + }; // end class + //-------------------------------------------------------------------- + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkExtractMediastinumGenericFilter.txx" +#endif + +#endif // #define CLITKEXTRACTMEDIASTINUMSGENERICFILTER_H diff --git a/segmentation/clitkExtractMediastinumGenericFilter.txx b/segmentation/clitkExtractMediastinumGenericFilter.txx new file mode 100644 index 0000000..5a2cead --- /dev/null +++ b/segmentation/clitkExtractMediastinumGenericFilter.txx @@ -0,0 +1,102 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKEXTRACTMEDIASTINUMSGENERICFILTER_TXX +#define CLITKEXTRACTMEDIASTINUMSGENERICFILTER_TXX + +#include "clitkImageCommon.h" + +//-------------------------------------------------------------------- +template +clitk::ExtractMediastinumGenericFilter::ExtractMediastinumGenericFilter(): + ImageToImageGenericFilter("ExtractMediastinum") +{ + // Default values + cmdline_parser_clitkExtractMediastinum_init(&mArgsInfo); + InitializeImageType<3>(); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +template +void clitk::ExtractMediastinumGenericFilter::InitializeImageType() +{ + ADD_IMAGE_TYPE(Dim, uchar); + // ADD_IMAGE_TYPE(Dim, short); + // ADD_IMAGE_TYPE(Dim, int); + // ADD_IMAGE_TYPE(Dim, float); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void clitk::ExtractMediastinumGenericFilter::SetArgsInfo(const ArgsInfoType & a) +{ + mArgsInfo=a; + SetIOVerbose(mArgsInfo.verbose_flag); + if (mArgsInfo.imagetypes_flag) this->PrintAvailableImageTypes(); + if (mArgsInfo.patient_given) AddInputFilename(mArgsInfo.patient_arg); + if (mArgsInfo.lung_given) AddInputFilename(mArgsInfo.lung_arg); + if (mArgsInfo.bones_given) AddInputFilename(mArgsInfo.bones_arg); + if (mArgsInfo.output_given) AddOutputFilename(mArgsInfo.output_arg); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +// Update with the number of dimensions and the pixeltype +//-------------------------------------------------------------------- +template +template +void clitk::ExtractMediastinumGenericFilter::UpdateWithInputImageType() +{ + // Reading input + typename ImageType::Pointer patient = this->template GetInput(0); + typename ImageType::Pointer lung = this->template GetInput(1); + typename ImageType::Pointer bones = this->template GetInput(2); + + // Create filter + typedef clitk::ExtractMediastinumFilter FilterType; + typename FilterType::Pointer filter = FilterType::New(); + + // Set global Options + filter->SetInputPatientLabelImage(patient, mArgsInfo.patientBG_arg); + filter->SetInputLungLabelImage(lung, mArgsInfo.lungBG_arg, mArgsInfo.lungRight_arg, mArgsInfo.lungLeft_arg); + filter->SetInputBonesLabelImage(bones, mArgsInfo.bonesBG_arg); + filter->SetArgsInfo(mArgsInfo); + + // Go ! + filter->Update(); + + // Check if error + if (filter->HasError()) { + SetLastError(filter->GetLastError()); + // No output + return; + } + + // Write/Save results + typename ImageType::Pointer output = filter->GetOutput(); + this->template SetNextOutput(output); +} +//-------------------------------------------------------------------- + +#endif //#define CLITKEXTRACTMEDIASTINUMSGENERICFILTER_TXX diff --git a/segmentation/clitkExtractPatient.cxx b/segmentation/clitkExtractPatient.cxx new file mode 100644 index 0000000..8e78809 --- /dev/null +++ b/segmentation/clitkExtractPatient.cxx @@ -0,0 +1,43 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 +======================================================================-====*/ + +// clitk +#include "clitkExtractPatient_ggo.h" +#include "clitkExtractPatientGenericFilter.h" + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkExtractPatient, args_info); + CLITK_INIT; + + // Filter + typedef clitk::ExtractPatientGenericFilter FilterType; + FilterType::Pointer filter = FilterType::New(); + + filter->SetArgsInfo(args_info); + filter->Update(); + + if (filter->HasError()) { + std::cout << filter->GetLastError() << std::endl; + } + + return EXIT_SUCCESS; +} // This is the end, my friend +//-------------------------------------------------------------------- diff --git a/segmentation/clitkExtractPatient.ggo b/segmentation/clitkExtractPatient.ggo new file mode 100644 index 0000000..3a239e7 --- /dev/null +++ b/segmentation/clitkExtractPatient.ggo @@ -0,0 +1,53 @@ +#File clitkExtractPatient.ggo +package "clitkExtractPatient" +version "1.0" +purpose "Prefer high resolution input and resample (NN) output at the end (like). Input is binarized using initial thresholds, connected components are labeled (firstLabel). The air label (1) is removed. The remaining is binarized and relabeled, patient should now be the principal label (secondLabel). Two mechanismes are provided to influence the label images. Crop to reduce connectivity (image is restored to original size), eg for SBF. Decomposition through ersion and reconstruction through dilation (slow), eg for Pulmo bellows. Choose which labels to keep from second Label image. Final mask is cleaned by opening and closing." + +option "config" - "Config file" string no +option "imagetypes" - "Display allowed image types" flag off +option "verbose" v "Verbose" flag off +option "verboseStep" - "Verbose each step" flag off +option "writeStep" w "Write image at each step" flag off +option "verboseOption" - "Display options values" flag off +option "verboseWarningOff" - "Do not display warning" flag off + +section "I/O" + +option "input" i "Input image filename" string yes +option "output" o "Output image filename" string yes + +section "Binarize" + +option "lower" - "Initial lower threshold" double no +option "upper" - "Initial upper threshold" double no default="-300" + +section "First Label Image (air=1)" + +option "erode1" - "Decompose through erosion" flag off +option "radius1" - "Radius for erosion and dilation" int multiple no default="1" +option "new1" - "Number of new labels" int no default="1" +option "max1" - "Max number of labels to consider" int no default="2" + +section "Second Label Image (air=1)" + +option "erode2" - "Decompose through erosion" flag off +option "radius2" - "Radius for erosion and dilation" int multiple no default="1" +option "new2" - "Number of new labels" int no default="1" +option "max2" - "Max number of labels to consider" int no default="2" +# option "crop" - "Crop the first label image" flag off +# option "boundingBox" b "Bounding box of the crop region (minX,maxX,...)" int no multiple +# option "lowerS" - "Size of the lower crop region" int no multiple +# option "upperS" - "Size of the upper crop region" int no multiple + +section "Labels to keep (air=1)" + +option "firstKeep" - "First label to keep" int no default="1" +option "lastKeep" - "Last label to keep" int no default="1" +option "remove" - "Labels to remove" int no multiple + +section "Clean-up" + +option "openClose" - "Perform morphological opening and closing with unit radius" flag on +option "autoCrop" - "Crop final mask to BoundingBox" flag off + + diff --git a/segmentation/clitkExtractPatientFilter.h b/segmentation/clitkExtractPatientFilter.h new file mode 100644 index 0000000..9346d9a --- /dev/null +++ b/segmentation/clitkExtractPatientFilter.h @@ -0,0 +1,210 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKEXTRACTPATIENTFILTER_H +#define CLITKEXTRACTPATIENTFILTER_H + +#include "clitkFilterBase.h" + +namespace clitk { + + //-------------------------------------------------------------------- + /* + Try to extract the Patient part of a thorax CT. + + Prefer high resolution input and resample (NN) output at the end + (like). Input is binarized using initial thresholds, connected + components are labeled (firstLabel). The air label (1) is + removed. The remaining is binarized and relabeled, patient should + now be the principal label (secondLabel). Two mechanismes are + provided to influence the label images. Crop to reduce + connectivity (image is restored to original size), eg for + SBF. Decomposition through ersion and reconstruction through + dilation (slow), eg for Pulmo bellows. Choose which labels to keep + from second Label image. Final mask is cleaned by opening and + closing. + + */ + //-------------------------------------------------------------------- + + template + class ITK_EXPORT ExtractPatientFilter: + public clitk::FilterBase, + public itk::ImageToImageFilter + { + public: + /** Standard class typedefs. */ + typedef ExtractPatientFilter Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(ExtractPatientFilter, ImageToImageFilter); + FILTERBASE_INIT; + + /** Some convenient typedefs. */ + typedef TInputImageType InputImageType; + typedef typename InputImageType::ConstPointer InputImageConstPointer; + typedef typename InputImageType::Pointer InputImagePointer; + typedef typename InputImageType::RegionType InputImageRegionType; + typedef typename InputImageType::PixelType InputImagePixelType; + typedef typename InputImageType::SizeType InputImageSizeType; + typedef typename InputImageType::IndexType InputImageIndexType; + + typedef TOutputImageType OutputImageType; + typedef typename OutputImageType::ConstPointer OutputImageConstPointer; + typedef typename OutputImageType::Pointer OutputImagePointer; + typedef typename OutputImageType::RegionType OutputImageRegionType; + typedef typename OutputImageType::PixelType OutputImagePixelType; + typedef typename OutputImageType::SizeType OutputImageSizeType; + typedef typename OutputImageType::IndexType OutputImageIndexType; + + itkStaticConstMacro(ImageDimension, unsigned int, InputImageType::ImageDimension); + typedef int InternalPixelType; + typedef itk::Image InternalImageType; + typedef typename InternalImageType::SizeType InternalImageSizeType; + + /** Connect inputs */ + void SetInput(const TInputImageType * image); + + // Set all options at a time + template + void SetArgsInfo(ArgsInfoType arg); + + // Step 1 + itkSetMacro(UpperThreshold, InputImagePixelType); + itkGetMacro(UpperThreshold, InputImagePixelType); + GGO_DefineOption(upper, SetUpperThreshold, InputImagePixelType); + + itkSetMacro(LowerThreshold, InputImagePixelType); + itkGetMacro(LowerThreshold, InputImagePixelType); + itkSetMacro(UseLowerThreshold, bool); + itkGetConstMacro(UseLowerThreshold, bool); + itkBooleanMacro(UseLowerThreshold); + GGO_DefineOption_WithTest(lower, SetLowerThreshold, InputImagePixelType, UseLowerThreshold); + + // Step 2 + itkSetMacro(DecomposeAndReconstructDuringFirstStep, bool); + itkGetConstMacro(DecomposeAndReconstructDuringFirstStep, bool); + itkBooleanMacro(DecomposeAndReconstructDuringFirstStep); + GGO_DefineOption_Flag(erode1, SetDecomposeAndReconstructDuringFirstStep); + + itkSetMacro(Radius1, InternalImageSizeType); + itkGetConstMacro(Radius1, InternalImageSizeType); + GGO_DefineOption_Vector(radius1, SetRadius1, InternalImageSizeType, ImageDimension, true); + + itkSetMacro(MaximumNumberOfLabels1, int); + itkGetConstMacro(MaximumNumberOfLabels1, int); + GGO_DefineOption(max1, SetMaximumNumberOfLabels1, int); + + itkSetMacro(NumberOfNewLabels1, int); + itkGetConstMacro(NumberOfNewLabels1, int); + GGO_DefineOption(new1, SetNumberOfNewLabels1, int); + + // Step 2 + itkSetMacro(DecomposeAndReconstructDuringSecondStep, bool); + itkGetConstMacro(DecomposeAndReconstructDuringSecondStep, bool); + itkBooleanMacro(DecomposeAndReconstructDuringSecondStep); + GGO_DefineOption_Flag(erode2, SetDecomposeAndReconstructDuringSecondStep); + + itkSetMacro(Radius2, InternalImageSizeType); + itkGetConstMacro(Radius2, InternalImageSizeType); + GGO_DefineOption_Vector(radius2, SetRadius2, InternalImageSizeType, ImageDimension, true) + + itkSetMacro(MaximumNumberOfLabels2, int); + itkGetConstMacro(MaximumNumberOfLabels2, int); + GGO_DefineOption(max2, SetMaximumNumberOfLabels2, int); + + itkSetMacro(NumberOfNewLabels2, int); + itkGetConstMacro(NumberOfNewLabels2, int); + GGO_DefineOption(new2, SetNumberOfNewLabels2, int); + + // Step 3 + itkSetMacro(FirstKeep, int); + itkGetConstMacro(FirstKeep, int); + GGO_DefineOption(firstKeep, SetFirstKeep, int); + + itkSetMacro(LastKeep, int); + itkGetConstMacro(LastKeep, int); + GGO_DefineOption(lastKeep, SetLastKeep, int); + + // Step 4 + itkSetMacro(FinalOpenClose, bool); + itkGetConstMacro(FinalOpenClose, bool); + itkBooleanMacro(FinalOpenClose); + GGO_DefineOption_Flag(openClose, SetFinalOpenClose); + + // Step 4 + itkSetMacro(AutoCrop, bool); + itkGetConstMacro(AutoCrop, bool); + itkBooleanMacro(AutoCrop); + GGO_DefineOption_Flag(autoCrop, SetAutoCrop); + + protected: + ExtractPatientFilter(); + virtual ~ExtractPatientFilter() {} + + itkSetMacro(BackgroundValue, OutputImagePixelType); + itkSetMacro(ForegroundValue, OutputImagePixelType); + itkGetConstMacro(BackgroundValue, OutputImagePixelType); + itkGetConstMacro(ForegroundValue, OutputImagePixelType); + OutputImagePixelType m_BackgroundValue; + OutputImagePixelType m_ForegroundValue; + + InputImagePixelType m_UpperThreshold; + InputImagePixelType m_LowerThreshold; + bool m_UseLowerThreshold; + bool m_DecomposeAndReconstructDuringFirstStep; + bool m_DecomposeAndReconstructDuringSecondStep; + bool m_FinalOpenClose; + InternalImageSizeType m_Radius1; + InternalImageSizeType m_Radius2; + int m_MaximumNumberOfLabels1; + int m_MaximumNumberOfLabels2; + int m_NumberOfNewLabels1; + int m_NumberOfNewLabels2; + int m_FirstKeep; + int m_LastKeep; + bool m_AutoCrop; + + virtual void GenerateOutputInformation(); + virtual void GenerateData(); + + InputImageConstPointer input; + OutputImagePointer output; + typename InternalImageType::Pointer working_image; + + private: + ExtractPatientFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + }; // end class + //-------------------------------------------------------------------- + +} // end namespace clitk +//-------------------------------------------------------------------- + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkExtractPatientFilter.txx" +#endif + +#endif diff --git a/segmentation/clitkExtractPatientFilter.txx b/segmentation/clitkExtractPatientFilter.txx new file mode 100644 index 0000000..cfc2ab2 --- /dev/null +++ b/segmentation/clitkExtractPatientFilter.txx @@ -0,0 +1,313 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 CLITKEXTRACTPATIENTFILTER_TXX +#define CLITKEXTRACTPATIENTFILTER_TXX + +// clitk +#include "clitkImageCommon.h" +#include "clitkSetBackgroundImageFilter.h" +#include "clitkDecomposeAndReconstructImageFilter.h" +#include "clitkAutoCropFilter.h" + +// itk +#include "itkBinaryThresholdImageFilter.h" +#include "itkConnectedComponentImageFilter.h" +#include "itkRelabelComponentImageFilter.h" +#include "itkBinaryMorphologicalClosingImageFilter.h" +#include "itkBinaryMorphologicalOpeningImageFilter.h" +#include "itkBinaryBallStructuringElement.h" +#include "itkCastImageFilter.h" + +//-------------------------------------------------------------------- +template +clitk::ExtractPatientFilter:: +ExtractPatientFilter(): + clitk::FilterBase(), + itk::ImageToImageFilter() +{ + this->SetNumberOfRequiredInputs(1); + SetBackgroundValue(0); // Must be zero + SetForegroundValue(1); + + // Step 1: Threshold + CC + sort (Find low density areas) + SetUpperThreshold(-300); + SetLowerThreshold(-1000); + UseLowerThresholdOff(); + + // Step 2: DecomposeAndReconstructImageFilter (optional) + DecomposeAndReconstructDuringFirstStepOff(); + InternalImageSizeType r; + r.Fill(1); + SetRadius1(r); + SetMaximumNumberOfLabels1(2); + SetNumberOfNewLabels1(1); + + // Step 3: Remove the air (largest area). + + // Step 4: 2nd DecomposeAndReconstructImageFilter + DecomposeAndReconstructDuringSecondStepOff(); + SetRadius2(r); + SetMaximumNumberOfLabels2(2); + SetNumberOfNewLabels2(1); + + // Step 5: Only keep label corresponding (Keep patient's labels) + SetFirstKeep(1); + SetLastKeep(1); + + // Step 4: OpenClose (option) + FinalOpenCloseOn(); + AutoCropOff(); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractPatientFilter:: +SetInput(const TInputImageType * image) +{ + this->SetNthInput(0, const_cast(image)); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +template +void +clitk::ExtractPatientFilter:: +SetArgsInfo(ArgsInfoType arg) +{ + SetVerboseOption_GGO(arg); + SetVerboseStep_GGO(arg); + SetWriteStep_GGO(arg); + SetVerboseWarningOff_GGO(arg); + + SetUpperThreshold_GGO(arg); + SetLowerThreshold_GGO(arg); + + SetDecomposeAndReconstructDuringFirstStep_GGO(arg); + SetRadius1_GGO(arg); + SetMaximumNumberOfLabels1_GGO(arg); + SetNumberOfNewLabels1_GGO(arg); + + SetDecomposeAndReconstructDuringSecondStep_GGO(arg); + SetRadius2_GGO(arg); + SetMaximumNumberOfLabels2_GGO(arg); + SetNumberOfNewLabels2_GGO(arg); + + SetFirstKeep_GGO(arg); + SetLastKeep_GGO(arg); + + SetFinalOpenClose_GGO(arg); + SetAutoCrop_GGO(arg); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractPatientFilter:: +GenerateOutputInformation() { + + Superclass::GenerateOutputInformation(); + input = dynamic_cast(itk::ProcessObject::GetInput(0)); + + // OutputImagePointer outputImage = this->GetOutput(0); +// outputImage->SetRegions(input->GetLargestPossibleRegion()); + + // Get input pointers + static const unsigned int Dim = InputImageType::ImageDimension; + //input = dynamic_cast(itk::ProcessObject::GetInput(0)); + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + // Step 1: + StartNewStep("Find low densities areas"); + typedef itk::BinaryThresholdImageFilter BinarizeFilterType; + typename BinarizeFilterType::Pointer binarizeFilter=BinarizeFilterType::New(); + binarizeFilter->SetInput(input); + if (m_UseLowerThreshold) binarizeFilter->SetLowerThreshold(GetLowerThreshold()); + binarizeFilter->SetUpperThreshold(GetUpperThreshold()); + binarizeFilter ->SetInsideValue(this->GetForegroundValue()); + binarizeFilter ->SetOutsideValue(this->GetBackgroundValue()); + + // Connected component labeling + typedef itk::ConnectedComponentImageFilter ConnectFilterType; + typename ConnectFilterType::Pointer connectFilter=ConnectFilterType::New(); + connectFilter->SetInput(binarizeFilter->GetOutput()); + connectFilter->SetBackgroundValue(this->GetBackgroundValue()); + connectFilter->SetFullyConnected(false); + + // Sort labels according to size + typedef itk::RelabelComponentImageFilter RelabelFilterType; + typename RelabelFilterType::Pointer relabelFilter=RelabelFilterType::New(); + relabelFilter->InPlaceOn(); + relabelFilter->SetInput(connectFilter->GetOutput()); + relabelFilter->Update(); + working_image = relabelFilter->GetOutput(); + + // End + StopCurrentStep(working_image); + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + // [Optional] + if (GetDecomposeAndReconstructDuringFirstStep()) { + StartNewStep("First Decompose & Reconstruct step"); + typedef clitk::DecomposeAndReconstructImageFilter FilterType; + typename FilterType::Pointer f = FilterType::New(); + f->SetInput(working_image); + // f->SetVerbose(m_Verbose); + f->SetRadius(GetRadius1()); + f->SetMaximumNumberOfLabels(GetMaximumNumberOfLabels1()); + f->SetBackgroundValue(this->GetBackgroundValue()); + f->SetForegroundValue(this->GetForegroundValue()); + f->SetFullyConnected(true); + f->SetNumberOfNewLabels(GetNumberOfNewLabels1()); + f->Update(); + working_image = f->GetOutput(); + StopCurrentStep(working_image); + } + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + StartNewStep("Remove the air (largest area)"); + typedef itk::BinaryThresholdImageFilter iBinarizeFilterType; + typename iBinarizeFilterType::Pointer binarizeFilter2 = iBinarizeFilterType::New(); + binarizeFilter2->SetInput(working_image); + binarizeFilter2->SetLowerThreshold(this->GetForegroundValue()); + binarizeFilter2->SetUpperThreshold(this->GetForegroundValue()); + binarizeFilter2 ->SetInsideValue(this->GetBackgroundValue()); + binarizeFilter2 ->SetOutsideValue(this->GetForegroundValue()); + // binarizeFilter2 ->Update(); // NEEDED ? + + typename ConnectFilterType::Pointer connectFilter2 = ConnectFilterType::New(); + connectFilter2->SetInput(binarizeFilter2->GetOutput()); + connectFilter2->SetBackgroundValue(this->GetBackgroundValue()); + connectFilter2->SetFullyConnected(false); + + typename RelabelFilterType::Pointer relabelFilter2 = RelabelFilterType::New(); + relabelFilter2->SetInput(connectFilter2->GetOutput()); + relabelFilter2->Update(); + working_image = relabelFilter2->GetOutput(); + StopCurrentStep(working_image); + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + // [Optional] + if (GetDecomposeAndReconstructDuringSecondStep()) { + StartNewStep("Second Decompose & Reconstruct step"); + typedef clitk::DecomposeAndReconstructImageFilter FilterType; + typename FilterType::Pointer f = FilterType::New(); + f->SetInput(working_image); + // f->SetVerbose(m_Verbose); + f->SetRadius(GetRadius2()); + f->SetMaximumNumberOfLabels(GetMaximumNumberOfLabels2()); + f->SetBackgroundValue(this->GetBackgroundValue()); + f->SetForegroundValue(this->GetForegroundValue()); + f->SetFullyConnected(true); + f->SetNumberOfNewLabels(GetNumberOfNewLabels2()); + f->Update(); + working_image = f->GetOutput(); + StopCurrentStep(working_image); + } + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + StartNewStep("Keep patient's labels"); + typename iBinarizeFilterType::Pointer binarizeFilter3 = iBinarizeFilterType::New(); + binarizeFilter3->SetInput(working_image); + binarizeFilter3->SetLowerThreshold(GetFirstKeep()); + binarizeFilter3->SetUpperThreshold(GetLastKeep()); + binarizeFilter3 ->SetInsideValue(this->GetForegroundValue()); + binarizeFilter3 ->SetOutsideValue(this->GetBackgroundValue()); + binarizeFilter3->Update(); + working_image = binarizeFilter3->GetOutput(); + StopCurrentStep(working_image); + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + // [Optional] + if (GetFinalOpenClose()) { + StartNewStep("Final OpenClose"); + // Open + typedef itk::BinaryBallStructuringElement KernelType; + KernelType structuringElement; + structuringElement.SetRadius(1); + structuringElement.CreateStructuringElement(); + typedef itk::BinaryMorphologicalOpeningImageFilter OpenFilterType; + typename OpenFilterType::Pointer openFilter = OpenFilterType::New(); + openFilter->SetInput(working_image); + openFilter->SetBackgroundValue(this->GetBackgroundValue()); + openFilter->SetForegroundValue(this->GetForegroundValue()); + openFilter->SetKernel(structuringElement); + // Close + typedef itk::BinaryMorphologicalClosingImageFilter CloseFilterType; + typename CloseFilterType::Pointer closeFilter = CloseFilterType::New(); + closeFilter->SetInput(openFilter->GetOutput()); + closeFilter->SetSafeBorder(true); + closeFilter->SetForegroundValue(this->GetForegroundValue()); + // closeFilter->SetBackgroundValue(SetBackgroundValue()); + closeFilter->SetKernel(structuringElement); + closeFilter->Update(); + working_image = closeFilter->GetOutput(); + StopCurrentStep(working_image); + } + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + // Final Cast + typedef itk::CastImageFilter CastImageFilterType; + typename CastImageFilterType::Pointer caster= CastImageFilterType::New(); + caster->SetInput(working_image); + caster->Update(); + output = caster->GetOutput(); + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + // [Optional] + if (GetAutoCrop()) { + StartNewStep("AutoCrop"); + typedef clitk::AutoCropFilter CropFilterType; + typename CropFilterType::Pointer cropFilter = CropFilterType::New(); + cropFilter->SetInput(output); + cropFilter->SetBackgroundValue(GetBackgroundValue()); + cropFilter->Update(); + output = cropFilter->GetOutput(); + StopCurrentStep(output); + } +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractPatientFilter:: +GenerateData() { + //this->SetNthOutput(0, output); // -> no because redo filter otherwise + this->GraftOutput(output); +} +//-------------------------------------------------------------------- + + +#endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX diff --git a/segmentation/clitkExtractPatientGenericFilter.cxx b/segmentation/clitkExtractPatientGenericFilter.cxx new file mode 100644 index 0000000..429729f --- /dev/null +++ b/segmentation/clitkExtractPatientGenericFilter.cxx @@ -0,0 +1,55 @@ +#ifndef clitkExtractPatientGenericFilter_cxx +#define clitkExtractPatientGenericFilter_cxx + +/* ================================================= + * @file clitkExtractPatientGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkExtractPatientGenericFilter.h" + + +namespace clitk +{ + + + //----------------------------------------------------------- + // Constructor + //----------------------------------------------------------- + ExtractPatientGenericFilter::ExtractPatientGenericFilter() + { + m_Verbose=false; + m_InputFileName=""; + } + + + //----------------------------------------------------------- + // Update + //----------------------------------------------------------- + void ExtractPatientGenericFilter::Update() + { + // Read the Dimension and PixelType + int Dimension; + std::string PixelType; + ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType); + + + // Call UpdateWithDim + if(Dimension==2) UpdateWithDim<2>(PixelType); + else if(Dimension==3) UpdateWithDim<3>(PixelType); + // else if (Dimension==4)UpdateWithDim<4>(PixelType); + else + { + std::cout<<"Error, Only for 2 or 3 Dimensions!!!"< + class ITK_EXPORT ExtractPatientGenericFilter: + public ImageToImageGenericFilter > + { + public: + //-------------------------------------------------------------------- + ExtractPatientGenericFilter(); + + //-------------------------------------------------------------------- + typedef ExtractPatientGenericFilter Self; + typedef ImageToImageGenericFilter > Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + //-------------------------------------------------------------------- + itkNewMacro(Self); + itkTypeMacro( ExtractPatientGenericFilter, LightObject ); + + //-------------------------------------------------------------------- + void SetArgsInfo(const ArgsInfoType & a); + + //-------------------------------------------------------------------- + // Main function called each time the filter is updated + template + void UpdateWithInputImageType(); + + protected: + template void InitializeImageType(); + ArgsInfoType mArgsInfo; + + };// end class + //-------------------------------------------------------------------- +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkExtractPatientGenericFilter.txx" +#endif + +#endif // #define CLITKEXTRACTPATIENTGENERICFILTER_H diff --git a/segmentation/clitkExtractPatientGenericFilter.txx b/segmentation/clitkExtractPatientGenericFilter.txx new file mode 100644 index 0000000..26252de --- /dev/null +++ b/segmentation/clitkExtractPatientGenericFilter.txx @@ -0,0 +1,95 @@ +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 + ======================================================================-====*/ + +#include "clitkImageCommon.h" + +//-------------------------------------------------------------------- +template +clitk::ExtractPatientGenericFilter::ExtractPatientGenericFilter(): + ImageToImageGenericFilter("ExtractPatient") +{ + // Default values + cmdline_parser_clitkExtractPatient_init(&mArgsInfo); + InitializeImageType<3>(); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +template +void clitk::ExtractPatientGenericFilter::InitializeImageType() +{ + ADD_IMAGE_TYPE(Dim, short); + // ADD_IMAGE_TYPE(Dim, int); + // ADD_IMAGE_TYPE(Dim, float); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void clitk::ExtractPatientGenericFilter::SetArgsInfo(const ArgsInfoType & a) +{ + mArgsInfo=a; + SetIOVerbose(mArgsInfo.verbose_flag); + if (mArgsInfo.imagetypes_flag) this->PrintAvailableImageTypes(); + if (mArgsInfo.input_given) SetInputFilename(mArgsInfo.input_arg); + if (mArgsInfo.output_given) AddOutputFilename(mArgsInfo.output_arg); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +// Update with the number of dimensions and the pixeltype +//-------------------------------------------------------------------- +template +template +void clitk::ExtractPatientGenericFilter::UpdateWithInputImageType() +{ + // Output image type + typedef itk::Image OutputImageType; + + // Reading input + typename ImageType::Pointer input = this->template GetInput(0); + + // Create filter + typedef clitk::ExtractPatientFilter FilterType; + typename FilterType::Pointer filter = FilterType::New(); + + // Set global Options + filter->SetArgsInfo(mArgsInfo); + filter->SetInput(input); + + // Go ! + filter->Update(); + + // Check if error + if (filter->HasError()) { + SetLastError(filter->GetLastError()); + // No output + return; + } + + // Write/Save results + typename OutputImageType::Pointer output = filter->GetOutput(); + this->template SetNextOutput(output); +} +//-------------------------------------------------------------------- + + diff --git a/segmentation/clitkFillMask.cxx b/segmentation/clitkFillMask.cxx new file mode 100644 index 0000000..209fbf7 --- /dev/null +++ b/segmentation/clitkFillMask.cxx @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------ + + Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de + l'Image). All rights reserved. See Doc/License.txt or + http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + ------------------------------------------------------------------------*/ + +/* ================================================= + * @file clitkFillMask.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk +#include "clitkFillMask_ggo.h" +#include "clitkIO.h" +#include "clitkFillMaskGenericFilter.h" + + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkFillMask,args_info); + CLITK_INIT; + + // Filter + clitk::FillMaskGenericFilter::Pointer genericFilter=clitk::FillMaskGenericFilter::New(); + + genericFilter->SetArgsInfo(args_info); + genericFilter->Update(); + + return EXIT_SUCCESS; +}// end main + +//-------------------------------------------------------------------- diff --git a/segmentation/clitkFillMask.ggo b/segmentation/clitkFillMask.ggo new file mode 100644 index 0000000..60e80e7 --- /dev/null +++ b/segmentation/clitkFillMask.ggo @@ -0,0 +1,13 @@ +#File clitkFillMask.ggo +package "clitkFillMask" +version "1.0" +purpose "Fill in holes (bg=0) in an object (fg=1) of a binary image, by running over the slices and retaining only one connected component bg." + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off + +option "input" i "Input image filename" string yes +option "output" o "Output image filename" string yes +option "dir" d "Directions (axes) to perform filling (defaults to 2,1,0)" int multiple no + + diff --git a/segmentation/clitkFillMaskGenericFilter.cxx b/segmentation/clitkFillMaskGenericFilter.cxx new file mode 100644 index 0000000..59a88e5 --- /dev/null +++ b/segmentation/clitkFillMaskGenericFilter.cxx @@ -0,0 +1,78 @@ +#ifndef clitkFillMaskGenericFilter_cxx +#define clitkFillMaskGenericFilter_cxx + +/* ================================================= + * @file clitkFillMaskGenericFilter.cxx + * @author + * @date + * + * @brief + * + ===================================================*/ + +#include "clitkFillMaskGenericFilter.h" + + +namespace clitk +{ + + + //----------------------------------------------------------- + // Constructor + //----------------------------------------------------------- + FillMaskGenericFilter::FillMaskGenericFilter() + { + m_Verbose=false; + m_InputFileName=""; + } + + + //----------------------------------------------------------- + // Update + //----------------------------------------------------------- + void FillMaskGenericFilter::Update() + { + // Read the Dimension and PixelType + int Dimension; + std::string PixelType; + ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType); + + + // Call UpdateWithPixelType + if (m_Verbose) std::cout << "Image was detected to be "<(); + } + + // else if(PixelType == "unsigned_short"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_short..." << std::endl; + // UpdateWithPixelType(); + // } + + else if (PixelType == "unsigned_char"){ + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and unsigned_char..." << std::endl; + UpdateWithPixelType(); + } + + // else if (PixelType == "char"){ + // if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed_char..." << std::endl; + // UpdateWithPixelType(); + // } + + else { + if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and float..." << std::endl; + UpdateWithPixelType(); + } + } + + +} //end clitk + +#endif //#define clitkFillMaskGenericFilter_cxx diff --git a/segmentation/clitkFillMaskGenericFilter.h b/segmentation/clitkFillMaskGenericFilter.h new file mode 100644 index 0000000..8a9b479 --- /dev/null +++ b/segmentation/clitkFillMaskGenericFilter.h @@ -0,0 +1,104 @@ +#ifndef clitkFillMaskGenericFilter_h +#define clitkFillMaskGenericFilter_h + +/* ================================================= + * @file clitkFillMaskGenericFilter.h + * @author + * @date + * + * @brief + * + ===================================================*/ + + +// clitk include +#include "clitkFillMask_ggo.h" +#include "clitkImageCommon.h" +#include "clitkExtractImageFilter.h" + +//itk include +#include "itkLightObject.h" +#include "itkJoinSeriesImageFilter.h" +#include "itkBinaryThresholdImageFilter.h" +#include "itkConnectedComponentImageFilter.h" +#include "itkRelabelComponentImageFilter.h" +#include "itkThresholdImageFilter.h" +#include "itkPermuteAxesImageFilter.h" +#include "itkExtractImageFilter.h" +#include "itkCastImageFilter.h" + +namespace clitk +{ + + + class ITK_EXPORT FillMaskGenericFilter : public itk::LightObject + { + public: + //---------------------------------------- + // ITK + //---------------------------------------- + typedef FillMaskGenericFilter Self; + typedef itk::LightObject Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; + + // Method for creation through the object factory + itkNewMacro(Self); + + // Run-time type information (and related methods) + itkTypeMacro( FillMaskGenericFilter, LightObject ); + + + //---------------------------------------- + // Typedefs + //---------------------------------------- + + + //---------------------------------------- + // Set & Get + //---------------------------------------- + void SetArgsInfo(const args_info_clitkFillMask & a) + { + m_ArgsInfo=a; + m_Verbose=m_ArgsInfo.verbose_flag; + m_InputFileName=m_ArgsInfo.input_arg; + } + + + //---------------------------------------- + // Update + //---------------------------------------- + void Update(); + + protected: + + //---------------------------------------- + // Constructor & Destructor + //---------------------------------------- + FillMaskGenericFilter(); + ~FillMaskGenericFilter() {}; + + + //---------------------------------------- + // Templated members + //---------------------------------------- + template void UpdateWithPixelType(); + + + //---------------------------------------- + // Data members + //---------------------------------------- + args_info_clitkFillMask m_ArgsInfo; + bool m_Verbose; + std::string m_InputFileName; + + }; + + +} // end namespace clitk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "clitkFillMaskGenericFilter.txx" +#endif + +#endif // #define clitkFillMaskGenericFilter_h diff --git a/segmentation/clitkFillMaskGenericFilter.txx b/segmentation/clitkFillMaskGenericFilter.txx new file mode 100644 index 0000000..d723e10 --- /dev/null +++ b/segmentation/clitkFillMaskGenericFilter.txx @@ -0,0 +1,201 @@ +#ifndef clitkFillMaskGenericFilter_txx +#define clitkFillMaskGenericFilter_txx + +/* ================================================= + * @file clitkFillMaskGenericFilter.txx + * @author + * @date + * + * @brief + * + ===================================================*/ + + +namespace clitk +{ + + //------------------------------------------------------------------- + // Update with the pixeltype + //------------------------------------------------------------------- + template + void + FillMaskGenericFilter::UpdateWithPixelType() + { + // Dim & Pix + const unsigned int Dimension=3; + typedef int InternalPixelType; + + // ImageTypes + typedef itk::Image InputImageType; + typedef itk::Image InternalImageType; + typedef itk::Image OutputImageType; + + // Read the input + typedef itk::ImageFileReader InputReaderType; + typename InputReaderType::Pointer reader = InputReaderType::New(); + reader->SetFileName( m_InputFileName); + reader->Update(); + typename InputImageType::Pointer input= reader->GetOutput(); + + // Read the directions over which to fill holes + std::vector direction; + if (m_ArgsInfo.dir_given) + for ( unsigned int i=0;i InputCastImageFilterType; + typename InputCastImageFilterType::Pointer inputCaster= InputCastImageFilterType::New(); + inputCaster->SetInput(input); + inputCaster->Update(); + + //---------------------------------------- + // Loop over directions + //---------------------------------------- + typename InternalImageType::Pointer output=inputCaster->GetOutput(); + for (unsigned int i=0; i ImageSliceType; + typedef itk::Image MaskSliceType; + typename InternalImageType::RegionType region3D= input->GetLargestPossibleRegion(); + typename InternalImageType::RegionType::SizeType size3D= region3D.GetSize(); + typename InternalImageType::RegionType::SizeType size2D=size3D; + size2D[direction[i]]=0; + typename InternalImageType::IndexType start2D; + start2D.Fill(0); + typename InternalImageType::RegionType desiredRegion; + desiredRegion.SetSize( size2D ); + desiredRegion.SetIndex( start2D ); + + // Extract and Join + typedef itk::ExtractImageFilter ExtractImageFilterType; + typedef itk::JoinSeriesImageFilter JoinSeriesFilterType; + typename JoinSeriesFilterType::Pointer joinFilter=JoinSeriesFilterType::New(); + joinFilter->SetSpacing(input->GetSpacing()[direction[i]]); + + //---------------------------------------- + // Run over the sliceIndexs + // ---------------------------------------- + for(unsigned int sliceIndex=0; sliceIndex SetInput(output); + start2D[direction[i]]=sliceIndex; + desiredRegion.SetIndex( start2D ); + extractFilter->SetExtractionRegion( desiredRegion ); + extractFilter->Update( ); + typename ImageSliceType::Pointer slice= extractFilter->GetOutput(); + + // Binarize the image (Before: OBJECT!=0, rest=0, After: object=1, rest=0 ) + typedef itk::BinaryThresholdImageFilter BinarizeFilterType; + typename BinarizeFilterType::Pointer binarizeFilter=BinarizeFilterType::New(); + binarizeFilter->SetInput(slice); + binarizeFilter->SetUpperThreshold(0); + binarizeFilter->SetOutsideValue(0); + binarizeFilter->SetInsideValue(1); + // writeImage(binarizeFilter->GetOutput(),"/home/jef/tmp/input.mhd"); + + // Perform connected labelling on the slice (body+air=0 ) + typedef itk::ConnectedComponentImageFilter ConnectFilterType; + typename ConnectFilterType::Pointer connectFilter=ConnectFilterType::New(); + connectFilter->SetInput(binarizeFilter->GetOutput()); + connectFilter->SetBackgroundValue(0); + connectFilter->SetFullyConnected(false); + //connectFilter->Update(); + //writeImage(connectFilter->GetOutput(),"/home/jef/tmp/connect.mhd"); + + // Sort the labels + typedef itk::RelabelComponentImageFilter RelabelFilterType; + typename RelabelFilterType::Pointer relabelFilter=RelabelFilterType::New(); + relabelFilter->SetInput(connectFilter->GetOutput()); + //relabelFilter->Update(); + //writeImage(relabelFilter->GetOutput(),"/home/jef/tmp/label.mhd"); + + // Keep the first + typedef itk::ThresholdImageFilter ThresholdFilterType; + typename ThresholdFilterType::Pointer thresholdFilter=ThresholdFilterType::New(); + thresholdFilter->SetInput(relabelFilter->GetOutput()); + thresholdFilter->SetUpper(1); + thresholdFilter->SetOutsideValue(0); + // thresholdFilter->Update(); + // writeImage(thresholdFilter->GetOutput(),"/home/jef/tmp/bin.mhd"); + + // Invert the labels (lung 1, rest 0) + typename BinarizeFilterType::Pointer switchFilter=BinarizeFilterType::New(); + switchFilter->SetInput(thresholdFilter->GetOutput()); + switchFilter->SetUpperThreshold(0); + switchFilter->SetOutsideValue(0); + switchFilter->SetInsideValue(1); + switchFilter->Update(); + //writeImage(switchFilter->GetOutput(),"/home/jef/tmp/inv_bin.mhd"); + + //Join + joinFilter->SetInput( sliceIndex, switchFilter->GetOutput()); + } + + // Join to a 3D image + if (m_Verbose) std::cout<<"Joining the slices..."<Update(); + + // Permute the axes to reset to orientation + typedef itk::PermuteAxesImageFilter PermuteFilterType; + typename PermuteFilterType::Pointer permuteFilter=PermuteFilterType::New(); + permuteFilter->SetInput(joinFilter->GetOutput()); + typename PermuteFilterType::PermuteOrderArrayType order; + order[direction[i]]=2; + if( direction[i]==2) + { + order[0]=0; + order[1]=1; + } + else if ( direction[i]==1) + { + order[0]=0; + order[2]=1; + } + else if (direction[i]==0) + { + order[1]=0; + order[2]=1; + } + permuteFilter->SetOrder(order); + permuteFilter->Update(); + output =permuteFilter->GetOutput(); + + // Set the image direction to the input one + output->SetDirection(input->GetDirection()); + output->SetOrigin(input->GetOrigin()); + } + + + // Cast + typedef itk::CastImageFilter OutputCastImageFilterType; + typename OutputCastImageFilterType::Pointer outputCaster =OutputCastImageFilterType::New(); + outputCaster->SetInput(output); + + // Output + typedef itk::ImageFileWriter WriterType; + typename WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(m_ArgsInfo.output_arg); + writer->SetInput(outputCaster->GetOutput()); + writer->Update(); + } + +}//end clitk + +#endif //#define clitkFillMaskGenericFilter_txx diff --git a/segmentation/clitkTestFilter.cxx b/segmentation/clitkTestFilter.cxx new file mode 100644 index 0000000..a0b386d --- /dev/null +++ b/segmentation/clitkTestFilter.cxx @@ -0,0 +1,211 @@ + +/*========================================================================= + 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://oncora1.lyon.fnclcc.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 + ======================================================================-====*/ + +// clitk +#include "clitkTestFilter_ggo.h" +#include "clitkImageCommon.h" +#include "clitkBooleanOperatorLabelImageFilter.h" +#include "clitkAutoCropFilter.h" +//#include "clitkRelativePositionConstraintLabelImageFilter.h" +#include "clitkResampleImageWithOptionsFilter.h" +#include "clitkAddRelativePositionConstraintToLabelImageFilter.h" + +#include "clitkExtractLungFilter.h" +#include "clitkExtractPatientFilter.h" +#include "clitkExtractMediastinumFilter.h" + +// ITK ENST +#include "RelativePositionPropImageFilter.h" + +//-------------------------------------------------------------------- +int main(int argc, char * argv[]) { + + // Init command line + GGO(clitkTestFilter, args_info); + + // Image types + //typedef unsigned char PixelType; + typedef short PixelType; + static const int Dim=3; + typedef itk::Image InputImageType; + + // Read inputs + InputImageType::Pointer input1; + InputImageType::Pointer input2; + InputImageType::Pointer input3; + input1 = clitk::readImage(args_info.input1_arg, true); + if (args_info.input2_given) input2 = clitk::readImage(args_info.input2_arg, true); + if (args_info.input3_given) input3 = clitk::readImage(args_info.input3_arg, true); + + // Declare output + InputImageType::Pointer output; + + //-------------------------------------------------------------------- + // Filter test BooleanOperatorLabelImageFilter + if (0) { + typedef clitk::BooleanOperatorLabelImageFilter FilterType; + FilterType::Pointer filter = FilterType::New(); + filter->SetInput1(input1); + filter->SetInput2(input2); + output = clitk::NewImageLike(input1); + filter->GraftOutput(output); /// TO VERIFY !!! + filter->Update(); + filter->SetInput2(input3); + filter->Update(); + output = filter->GetOutput(); + clitk::writeImage(output, args_info.output_arg); + } + + //-------------------------------------------------------------------- + // Filter test AutoCropLabelImageFilter + if (1) { + typedef clitk::AutoCropFilter FilterType; + FilterType::Pointer filter = FilterType::New(); + filter->SetInput(input1); + filter->Update(); + output = filter->GetOutput(); + clitk::writeImage(output, args_info.output_arg); + } + + //-------------------------------------------------------------------- + // Filter test RelativePositionPropImageFilter + if (0) { + typedef itk::Image OutputImageType; + OutputImageType::Pointer outputf; + typedef itk::RelativePositionPropImageFilter FilterType; + FilterType::Pointer filter = FilterType::New(); + filter->SetInput(input1); + + filter->SetAlpha1(clitk::deg2rad(args_info.angle1_arg)); // xy plane + filter->SetAlpha2(clitk::deg2rad(args_info.angle2_arg)); + filter->SetK1(M_PI/2.0); // Opening parameter, default = pi/2 + filter->SetFast(true); + filter->SetRadius(2); + filter->SetVerboseProgress(true); + + /* A1 A2 + Left 0 0 + Right 180 0 + Ant 90 0 + Post -90 0 + Inf 0 90 + Sup 0 -90 + */ + + filter->Update(); + clitk::writeImage(filter->GetOutput(), args_info.output_arg); + } + + //-------------------------------------------------------------------- + // Filter test + if (0) { + typedef itk::Image OutputImageType; + typedef clitk::ResampleImageWithOptionsFilter FilterType; + FilterType::Pointer filter = FilterType::New(); + filter->SetInput(input1); + filter->SetOutputIsoSpacing(1); + //filter->SetNumberOfThreads(4); // auto + filter->SetGaussianFilteringEnabled(false); + filter->Update(); + clitk::writeImage(filter->GetOutput(), args_info.output_arg); + } + + //-------------------------------------------------------------------- + // Filter AddRelativePositionConstraintToLabelImageFilter test + if (0) { + /* + typedef clitk::AddRelativePositionConstraintToLabelImageFilter FilterType; + FilterType::Pointer filter = FilterType::New(); + filter->SetInput(input1); + filter->SetInputObject(input2); + filter->SetOrientationType(FilterType::LeftTo); + filter->SetIntermediateSpacing(5); + filter->SetFuzzyThreshold(0.5); + filter->VerboseStepOn(); + filter->WriteStepOff(); + filter->Update(); + + filter->SetInput(filter->GetOutput()); + filter->SetInputObject(input2); + filter->SetOrientationType(FilterType::RightTo); + filter->SetIntermediateSpacing(5); + filter->SetFuzzyThreshold(0.5); + filter->Update(); + + clitk::writeImage(filter->GetOutput(), args_info.output_arg); + */ + } + + //-------------------------------------------------------------------- + // Filter test ExtractPatientFilter + if (0) { + typedef itk::Image OutputImageType; + typedef clitk::ExtractPatientFilter FilterType; + FilterType::Pointer filter = FilterType::New(); + filter->SetInput(input1); + filter->VerboseStepOn(); + filter->WriteStepOn(); + // options (default) + filter->SetUpperThreshold(-300); + filter->FinalOpenCloseOff(); // default=on (not rezally needed ?) + filter->Update(); + OutputImageType::Pointer output = filter->GetOutput(); + clitk::writeImage(output, args_info.output_arg); + } + + //-------------------------------------------------------------------- + // Filter test ExtractLungsFilter + if (0) { + typedef itk::Image OutputImageType; // to change into char + typedef clitk::ExtractLungFilter FilterType; + FilterType::Pointer filter = FilterType::New(); + // DD(filter->GetNumberOfSteps()); + filter->SetInput(input1); // CT + filter->SetInputPatientMask(input2, 0); // Patient mask and BG value + filter->VerboseStepOn(); + filter->WriteStepOn(); + // options (default) + //filter->SetBackgroundValue(0); + filter->SetUpperThreshold(-300); + // filter->SetMinimumComponentSize(100); + + filter->Update(); + OutputImageType::Pointer output = filter->GetOutput(); + clitk::writeImage(output, args_info.output_arg); + } + + //-------------------------------------------------------------------- + // Filter test ExtractMediastinumFilter + if (0) { + typedef clitk::ExtractMediastinumFilter FilterType; + FilterType::Pointer filter = FilterType::New(); + filter->SetInputPatientLabelImage(input1); + filter->SetInputLungLabelImage(input2, 0, 1, 2); // BG, FG Left Lung, FG Right Lung + filter->SetInputBonesLabelImage(input3); + filter->VerboseStepOn(); + filter->WriteStepOn(); + filter->Update(); + output = filter->GetOutput(); + clitk::writeImage(output, args_info.output_arg); + } + + // This is the end my friend + return EXIT_SUCCESS; +}// end main +//-------------------------------------------------------------------- diff --git a/segmentation/clitkTestFilter.ggo b/segmentation/clitkTestFilter.ggo new file mode 100644 index 0000000..d9778e7 --- /dev/null +++ b/segmentation/clitkTestFilter.ggo @@ -0,0 +1,16 @@ +#File clitkTestFilter.ggo +package "clitkTestFilter" +version "1.0" +purpose "Test a filter" + +option "config" - "Config file" string no +option "verbose" v "Verbose" flag off + +option "input1" i "Input 1 image filename" string yes +option "input2" j "Input 2 image filename" string no +option "input3" k "Input 3 image filename" string no +option "output" o "Output image filename" string yes + +option "angle1" a "First angle (degree)" float default = "0" no +option "angle2" b "Second angle (degree)" float default = "0" no + -- 2.47.1