From 5668d4a49a5a6b68dc80fa28f0f82b54187cb70c Mon Sep 17 00:00:00 2001 From: dsarrut Date: Fri, 22 Oct 2010 07:37:10 +0000 Subject: [PATCH] small improvement --- .../clitkAnatomicalFeatureDatabase.cxx | 36 ++++- segmentation/clitkAnatomicalFeatureDatabase.h | 23 ++- .../clitkExtractAirwaysTreeInfoFilter.txx | 13 ++ segmentation/clitkExtractBones.ggo | 4 +- segmentation/clitkExtractBonesFilter.h | 53 ++++--- segmentation/clitkExtractBonesFilter.txx | 47 +++--- .../clitkExtractBonesGenericFilter.txx | 8 +- segmentation/clitkExtractLung.ggo | 14 +- segmentation/clitkExtractLungFilter.h | 52 +++++-- segmentation/clitkExtractLungFilter.txx | 144 +++++++++++------- segmentation/clitkExtractLungGenericFilter.h | 2 +- .../clitkExtractLungGenericFilter.txx | 10 +- .../clitkExtractMediastinumFilter.txx | 115 ++++++++------ segmentation/clitkExtractPatient.ggo | 11 +- segmentation/clitkExtractPatientFilter.h | 53 ++++--- segmentation/clitkExtractPatientFilter.txx | 48 +++--- .../clitkExtractPatientGenericFilter.txx | 9 +- 17 files changed, 401 insertions(+), 241 deletions(-) diff --git a/segmentation/clitkAnatomicalFeatureDatabase.cxx b/segmentation/clitkAnatomicalFeatureDatabase.cxx index afd082e..dbd05c6 100644 --- a/segmentation/clitkAnatomicalFeatureDatabase.cxx +++ b/segmentation/clitkAnatomicalFeatureDatabase.cxx @@ -47,6 +47,25 @@ void clitk::AnatomicalFeatureDatabase::Write() //-------------------------------------------------------------------- +//-------------------------------------------------------------------- +//http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring +// trim from start +static inline std::string <rim(std::string &s) { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(std::isspace)))); + return s; +} +// trim from end +static inline std::string &rtrim(std::string &s) { + s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(std::isspace))).base(), s.end()); + return s; +} +// trim from both ends +static inline std::string &trim(std::string &s) { + return ltrim(rtrim(s)); +} +//-------------------------------------------------------------------- + + //-------------------------------------------------------------------- void clitk::AnatomicalFeatureDatabase::Load() { @@ -59,6 +78,7 @@ void clitk::AnatomicalFeatureDatabase::Load() is >> tag; std::string value; std::getline(is,value,'\n'); + ltrim(value); // remove leading space m_MapOfTag[tag] = value; } } @@ -95,9 +115,7 @@ void clitk::AnatomicalFeatureDatabase::GetPoint3D(std::string tag, PointType3D & // parse the string into 3 doubles for(int i=0; i<3; i++) { - DD(results[i]); p[i] = atof(results[i].c_str()); - DD(p[i]); } /* @@ -109,12 +127,20 @@ void clitk::AnatomicalFeatureDatabase::GetPoint3D(std::string tag, PointType3D & boost::tokenizer > tokens(s, sep); int i=0; BOOST_FOREACH(std::string t, tokens) { - std::cout << t << "." << std::endl; - p[i] = atof(t.c_str()); - i++; + std::cout << t << "." << std::endl; + p[i] = atof(t.c_str()); + i++; } */ } } //-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +void clitk::AnatomicalFeatureDatabase::SetImageFilename(std::string tag, std::string f) +{ + m_MapOfTag[tag] = f; +} +//-------------------------------------------------------------------- + diff --git a/segmentation/clitkAnatomicalFeatureDatabase.h b/segmentation/clitkAnatomicalFeatureDatabase.h index 78f04e3..dcf7efd 100644 --- a/segmentation/clitkAnatomicalFeatureDatabase.h +++ b/segmentation/clitkAnatomicalFeatureDatabase.h @@ -21,9 +21,11 @@ // clitk #include "clitkCommon.h" +#include "clitkImageCommon.h" namespace clitk { + //-------------------------------------------------------------------- /* Class to store and retreive anatomical feature such as 3D @@ -34,6 +36,8 @@ namespace clitk { public: AnatomicalFeatureDatabase(); + typedef std::string TagType; + // Set/Get filename itkSetMacro(Filename, std::string); itkGetConstMacro(Filename, std::string); @@ -42,19 +46,30 @@ namespace clitk { void Write(); void Load(); - // Get landmarks + // Set Get landmarks typedef itk::Point PointType3D; - void SetPoint3D(std::string tag, PointType3D & p); - void GetPoint3D(std::string tag, PointType3D & p); + void SetPoint3D(TagType tag, PointType3D & p); + void GetPoint3D(TagType tag, PointType3D & p); + + // Set Get image + void SetImageFilename(TagType tag, std::string f); + template + typename ImageType::Pointer GetImage(TagType tag); + // Set Get Double + void SetDouble(TagType tag, double d); + double GetDouble(TagType tag); + protected: std::string m_Filename; - typedef std::map MapTagType; + typedef std::map MapTagType; MapTagType m_MapOfTag; }; // end class //-------------------------------------------------------------------- + #include "clitkAnatomicalFeatureDatabase.txx" + } // end namespace clitk //-------------------------------------------------------------------- diff --git a/segmentation/clitkExtractAirwaysTreeInfoFilter.txx b/segmentation/clitkExtractAirwaysTreeInfoFilter.txx index 69b7380..6145ad7 100644 --- a/segmentation/clitkExtractAirwaysTreeInfoFilter.txx +++ b/segmentation/clitkExtractAirwaysTreeInfoFilter.txx @@ -179,11 +179,19 @@ GenerateData() extractSliceFilter->GetOutputSlices(mInputSlices); DD(mInputSlices.size()); + + DD("REDO !!!!!!!!!!!!"); + /** + => chercher la bif qui a les plus important sous-arbres + **/ + bool stop = false; int slice_index = listOfBifurcations[0].index[2]; // first slice from carina in skeleton int i=0; TreeIterator firstIter = m_SkeletonTree.child(listOfBifurcations[0].treeIter, 0); TreeIterator secondIter = m_SkeletonTree.child(listOfBifurcations[0].treeIter, 1); + DD(firstIter.number_of_children()); + DD(secondIter.number_of_children()); typename SliceType::IndexType in1; typename SliceType::IndexType in2; while (!stop) { @@ -192,6 +200,8 @@ GenerateData() GetBackgroundValue(), true, 0); // min component size=0 + DD(*firstIter); + DD(*secondIter); // Check the value of the two skeleton points; in1[0] = (*firstIter)[0]; in1[1] = (*firstIter)[1]; @@ -283,6 +293,9 @@ TrackFromThisIndex(std::vector & listOfBifurcations, if (listOfTrackedPoint.size() == 2) { // m_SkeletonTree->Add(listOfTrackedPoint[0], index); // the parent is 'index' // m_SkeletonTree->Add(listOfTrackedPoint[1], index); // the parent is 'index' + DD("BifurcationType"); + DD(listOfTrackedPoint[0]); + DD(listOfTrackedPoint[1]); BifurcationType bif(index, label, label+1, label+2); bif.treeIter = currentNode; listOfBifurcations.push_back(bif); diff --git a/segmentation/clitkExtractBones.ggo b/segmentation/clitkExtractBones.ggo index 1700413..cd737e7 100644 --- a/segmentation/clitkExtractBones.ggo +++ b/segmentation/clitkExtractBones.ggo @@ -15,7 +15,7 @@ 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 +option "afdb" a "Output Anatomical Feature DB (Carina position)" string no section "Smoothing (curvature anistropic diffusion)" @@ -40,4 +40,4 @@ 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 +option "noAutoCrop" - "If set : do no crop final mask to BoundingBox" flag on diff --git a/segmentation/clitkExtractBonesFilter.h b/segmentation/clitkExtractBonesFilter.h index 70daa48..e803e5a 100644 --- a/segmentation/clitkExtractBonesFilter.h +++ b/segmentation/clitkExtractBonesFilter.h @@ -24,6 +24,7 @@ #include "clitkDecomposeAndReconstructImageFilter.h" #include "clitkExplosionControlledThresholdConnectedImageFilter.h" #include "clitkSegmentationUtils.h" +#include "clitkFilterWithAnatomicalFeatureDatabaseManagement.h" // itk #include "itkStatisticsImageFilter.h" @@ -36,18 +37,21 @@ namespace clitk { */ //-------------------------------------------------------------------- - template + template class ITK_EXPORT ExtractBonesFilter: - public clitk::FilterBase, - public itk::ImageToImageFilter + public virtual clitk::FilterBase, + public clitk::FilterWithAnatomicalFeatureDatabaseManagement, + public itk::ImageToImageFilter > { public: /** Standard class typedefs. */ - typedef ExtractBonesFilter Self; - typedef itk::ImageToImageFilter Superclass; - typedef itk::SmartPointer Pointer; - typedef itk::SmartPointer ConstPointer; + typedef itk::Image MaskImageType; + typedef ExtractBonesFilter Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); @@ -65,13 +69,12 @@ namespace clitk { 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; + 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; @@ -88,12 +91,17 @@ namespace clitk { void SetArgsInfo(ArgsInfoType arg); // Background / Foreground - itkGetConstMacro(BackgroundValue, OutputImagePixelType); - itkGetConstMacro(ForegroundValue, OutputImagePixelType); + itkGetConstMacro(BackgroundValue, MaskImagePixelType); + itkGetConstMacro(ForegroundValue, MaskImagePixelType); itkSetMacro(MinimalComponentSize, int); itkGetConstMacro(MinimalComponentSize, int); GGO_DefineOption(minSize, SetMinimalComponentSize, int); + + // Output filename (for AFBD) + itkSetMacro(OutputBonesFilename, std::string); + itkGetMacro(OutputBonesFilename, std::string); + GGO_DefineOption(output, SetOutputBonesFilename, std::string); // Step 0 itkBooleanMacro(InitialSmoothing); @@ -153,17 +161,17 @@ namespace clitk { itkSetMacro(AutoCrop, bool); itkGetConstMacro(AutoCrop, bool); itkBooleanMacro(AutoCrop); - GGO_DefineOption_Flag(autoCrop, SetAutoCrop); + GGO_DefineOption_Flag(noAutoCrop, SetAutoCrop); protected: ExtractBonesFilter(); virtual ~ExtractBonesFilter() {} // Global options - itkSetMacro(BackgroundValue, OutputImagePixelType); - itkSetMacro(ForegroundValue, OutputImagePixelType); - OutputImagePixelType m_BackgroundValue; - OutputImagePixelType m_ForegroundValue; + itkSetMacro(BackgroundValue, MaskImagePixelType); + itkSetMacro(ForegroundValue, MaskImagePixelType); + MaskImagePixelType m_BackgroundValue; + MaskImagePixelType m_ForegroundValue; bool m_AutoCrop; // Step 0 : Initial Filtering @@ -194,9 +202,10 @@ namespace clitk { void ExtractBones(); void RemoveTrachea(); void BonesSeparation(); + std::string m_OutputBonesFilename; InputImageConstPointer input; InputImagePointer filtered_input; - OutputImageConstPointer patient; + MaskImageConstPointer patient; InputImagePointer working_input; typename InternalImageType::Pointer working_image; typename InternalImageType::Pointer trachea; diff --git a/segmentation/clitkExtractBonesFilter.txx b/segmentation/clitkExtractBonesFilter.txx index ef3f944..3e8cc49 100644 --- a/segmentation/clitkExtractBonesFilter.txx +++ b/segmentation/clitkExtractBonesFilter.txx @@ -33,11 +33,12 @@ #include "itkCurvatureAnisotropicDiffusionImageFilter.h" //-------------------------------------------------------------------- -template -clitk::ExtractBonesFilter:: +template +clitk::ExtractBonesFilter:: ExtractBonesFilter(): clitk::FilterBase(), - itk::ImageToImageFilter() + clitk::FilterWithAnatomicalFeatureDatabaseManagement(), + itk::ImageToImageFilter() { // Default global options this->SetNumberOfRequiredInputs(1); @@ -61,15 +62,15 @@ ExtractBonesFilter(): s.Fill(1); SetRadius2(s); SetSampleRate2(0); - AutoCropOff(); + AutoCropOn(); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- -template +template void -clitk::ExtractBonesFilter:: +clitk::ExtractBonesFilter:: SetInput(const TInputImageType * image) { this->SetNthInput(0, const_cast(image)); @@ -78,10 +79,10 @@ SetInput(const TInputImageType * image) //-------------------------------------------------------------------- -template +template template void -clitk::ExtractBonesFilter:: +clitk::ExtractBonesFilter:: SetArgsInfo(ArgsInfoType mArgsInfo) { SetVerboseOption_GGO(mArgsInfo); @@ -89,6 +90,8 @@ SetArgsInfo(ArgsInfoType mArgsInfo) SetWriteStep_GGO(mArgsInfo); SetVerboseWarningOff_GGO(mArgsInfo); + SetOutputBonesFilename_GGO(mArgsInfo); + SetInitialSmoothing_GGO(mArgsInfo); SetSmoothingConductanceParameter_GGO(mArgsInfo); SetSmoothingNumberOfIterations_GGO(mArgsInfo); @@ -105,30 +108,35 @@ SetArgsInfo(ArgsInfoType mArgsInfo) SetRadius2_GGO(mArgsInfo); SetSampleRate2_GGO(mArgsInfo); SetAutoCrop_GGO(mArgsInfo); + + SetAFDBFilename_GGO(mArgsInfo); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- -template +template void -clitk::ExtractBonesFilter:: +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); + MaskImagePointer outputImage = this->GetOutput(0); outputImage->SetRegions(input->GetLargestPossibleRegion()); + // Read DB + LoadAFDB(); + // 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; + typedef itk::CastImageFilter CastImageFilterType; + typedef itk::ImageFileWriter WriterType; //--------------------------------- // Smoothing [Optional] @@ -274,20 +282,23 @@ GenerateOutputInformation() { //-------------------------------------------------------------------- -template +template void -clitk::ExtractBonesFilter:: +clitk::ExtractBonesFilter:: GenerateData() { //-------------------------------------------------------------------- //-------------------------------------------------------------------- // Final Cast - typedef itk::CastImageFilter CastImageFilterType; + typedef itk::CastImageFilter CastImageFilterType; typename CastImageFilterType::Pointer caster= CastImageFilterType::New(); caster->SetInput(output); caster->Update(); - //this->SetNthOutput(0, caster->GetOutput()); this->GraftOutput(caster->GetOutput()); + + // Store image filenames into AFDB + GetAFDB()->SetImageFilename("bones", this->GetOutputBonesFilename()); + WriteAFDB(); return; } //-------------------------------------------------------------------- diff --git a/segmentation/clitkExtractBonesGenericFilter.txx b/segmentation/clitkExtractBonesGenericFilter.txx index dd85634..285842e 100644 --- a/segmentation/clitkExtractBonesGenericFilter.txx +++ b/segmentation/clitkExtractBonesGenericFilter.txx @@ -66,13 +66,13 @@ template void clitk::ExtractBonesGenericFilter::UpdateWithInputImageType() { // Mask & output image type - typedef itk::Image OutputImageType; + typedef itk::Image MaskImageType; // Reading input typename ImageType::Pointer input = this->template GetInput(0); // Create filter - typedef clitk::ExtractBonesFilter FilterType; + typedef clitk::ExtractBonesFilter FilterType; typename FilterType::Pointer filter = FilterType::New(); // Set global Options @@ -83,8 +83,8 @@ void clitk::ExtractBonesGenericFilter::UpdateWithInputImageType() filter->Update(); // Write/Save results - typename OutputImageType::Pointer output = filter->GetOutput(); - this->template SetNextOutput(output); + typename MaskImageType::Pointer output = filter->GetOutput(); + this->template SetNextOutput(output); } //-------------------------------------------------------------------- diff --git a/segmentation/clitkExtractLung.ggo b/segmentation/clitkExtractLung.ggo index 37eada2..ddc1fe7 100644 --- a/segmentation/clitkExtractLung.ggo +++ b/segmentation/clitkExtractLung.ggo @@ -14,8 +14,7 @@ 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 "afdb" a "Output Anatomical Feature DB (Carina position)" string no option "output" o "Output lungs mask filename" string yes option "outputTrachea" t "Output trachea mask filename" string no @@ -50,6 +49,11 @@ option "remove3" - "Labels not to keep in lungs mask (trachea)" int no option "firstKeep3" - "First label to keep" int no default="1" option "lastKeep3" - "Last label to keep" int no default="2" -section "Step 5 : openclose" -option "openclose" - "Final OpenClose" flag off -option "opencloseRadius" - "Final OpenClose radius" int no default="1" +section "Step 5 : [optional] openclose" +option "openclose" - "Perform an OpenClose operation" flag off +option "opencloseRadius" - "OpenClose radius" int no default="1" + +section "Step 6 : fill holes" +option "doNotFillHoles" - "Do not fill holes if set" flag on +option "dir" d "Directions (axes) to perform filling (defaults to 2,1,0)" int multiple no + diff --git a/segmentation/clitkExtractLungFilter.h b/segmentation/clitkExtractLungFilter.h index 6ec698d..3183457 100644 --- a/segmentation/clitkExtractLungFilter.h +++ b/segmentation/clitkExtractLungFilter.h @@ -24,6 +24,7 @@ #include "clitkDecomposeAndReconstructImageFilter.h" #include "clitkExplosionControlledThresholdConnectedImageFilter.h" #include "clitkSegmentationUtils.h" +#include "clitkFilterWithAnatomicalFeatureDatabaseManagement.h" // itk #include "itkStatisticsImageFilter.h" @@ -55,15 +56,17 @@ namespace clitk { //-------------------------------------------------------------------- //-------------------------------------------------------------------- - template + template class ITK_EXPORT ExtractLungFilter: public virtual clitk::FilterBase, - public itk::ImageToImageFilter + public clitk::FilterWithAnatomicalFeatureDatabaseManagement, + public itk::ImageToImageFilter > { public: /** Standard class typedefs. */ - typedef itk::ImageToImageFilter Superclass; + typedef itk::Image MaskImageType; + typedef itk::ImageToImageFilter Superclass; typedef ExtractLungFilter Self; typedef itk::SmartPointer Pointer; typedef itk::SmartPointer ConstPointer; @@ -85,7 +88,6 @@ namespace clitk { typedef typename ImageType::IndexType InputImageIndexType; typedef typename ImageType::PointType InputImagePointType; - typedef TMaskImageType MaskImageType; typedef typename MaskImageType::ConstPointer MaskImageConstPointer; typedef typename MaskImageType::Pointer MaskImagePointer; typedef typename MaskImageType::RegionType MaskImageRegionType; @@ -103,11 +105,19 @@ namespace clitk { /** Connect inputs */ void SetInput(const ImageType * image); - void SetInputPatientMask(MaskImageType * mask, MaskImagePixelType BG); itkSetMacro(PatientMaskBackgroundValue, MaskImagePixelType); itkGetConstMacro(PatientMaskBackgroundValue, MaskImagePixelType); GGO_DefineOption(patientBG, SetPatientMaskBackgroundValue, MaskImagePixelType); + // Output filename (for AFBD) + itkSetMacro(OutputLungFilename, std::string); + itkGetMacro(OutputLungFilename, std::string); + GGO_DefineOption(output, SetOutputLungFilename, std::string); + + itkSetMacro(OutputTracheaFilename, std::string); + itkGetMacro(OutputTracheaFilename, std::string); + GGO_DefineOption(outputTrachea, SetOutputTracheaFilename, std::string); + // Set all options at a time template void SetArgsInfo(ArgsInfoType arg); @@ -180,14 +190,20 @@ namespace clitk { GGO_DefineOption_LabelParam(3, SetLabelizeParameters3, LabelParamType); // Step 5 final openclose - itkSetMacro(FinalOpenClose, bool); - itkGetConstMacro(FinalOpenClose, bool); - itkBooleanMacro(FinalOpenClose); - GGO_DefineOption_Flag(openclose, SetFinalOpenClose); - - itkSetMacro(FinalOpenCloseRadius, int); - itkGetConstMacro(FinalOpenCloseRadius, int); - GGO_DefineOption(opencloseRadius, SetFinalOpenCloseRadius, int); + itkSetMacro(OpenClose, bool); + itkGetConstMacro(OpenClose, bool); + itkBooleanMacro(OpenClose); + GGO_DefineOption_Flag(openclose, SetOpenClose); + + itkSetMacro(OpenCloseRadius, int); + itkGetConstMacro(OpenCloseRadius, int); + GGO_DefineOption(opencloseRadius, SetOpenCloseRadius, int); + + // Step 6 fill holes + itkSetMacro(FillHoles, bool); + itkGetConstMacro(FillHoles, bool); + itkBooleanMacro(FillHoles); + GGO_DefineOption_Flag(doNotFillHoles, SetFillHoles); protected: ExtractLungFilter(); @@ -197,6 +213,8 @@ namespace clitk { InputImageConstPointer input; MaskImageConstPointer patient; InputImagePointer working_input; + std::string m_OutputLungFilename; + std::string m_OutputTracheaFilename; typename InternalImageType::Pointer working_image; typename InternalImageType::Pointer trachea_tmp; MaskImagePointer trachea; @@ -233,8 +251,12 @@ namespace clitk { LabelParamType* m_LabelizeParameters3; // Step 5 - bool m_FinalOpenClose; - int m_FinalOpenCloseRadius; + bool m_OpenClose; + int m_OpenCloseRadius; + + // Step 6 + bool m_FillHoles; + InputImageSizeType m_FillHolesDirections; // Main functions virtual void GenerateOutputInformation(); diff --git a/segmentation/clitkExtractLungFilter.txx b/segmentation/clitkExtractLungFilter.txx index 3de027c..2147b88 100644 --- a/segmentation/clitkExtractLungFilter.txx +++ b/segmentation/clitkExtractLungFilter.txx @@ -24,6 +24,8 @@ #include "clitkSetBackgroundImageFilter.h" #include "clitkSegmentationUtils.h" #include "clitkAutoCropFilter.h" +#include "clitkCropLikeImageFilter.h" +#include "clitkFillMaskFilter.h" // itk #include "itkBinaryThresholdImageFilter.h" @@ -36,17 +38,18 @@ #include "itkBinaryMorphologicalClosingImageFilter.h" //-------------------------------------------------------------------- -template -clitk::ExtractLungFilter:: +template +clitk::ExtractLungFilter:: ExtractLungFilter(): clitk::FilterBase(), + clitk::FilterWithAnatomicalFeatureDatabaseManagement(), itk::ImageToImageFilter() { SetNumberOfSteps(10); m_MaxSeedNumber = 500; // Default global options - this->SetNumberOfRequiredInputs(2); + this->SetNumberOfRequiredInputs(1); SetPatientMaskBackgroundValue(0); SetBackgroundValue(0); // Must be zero SetForegroundValue(1); @@ -85,16 +88,19 @@ ExtractLungFilter(): SetLabelizeParameters3(p3); // Step 5 - FinalOpenCloseOff(); - SetFinalOpenCloseRadius(1); + OpenCloseOff(); + SetOpenCloseRadius(1); + + // Step 6 + FillHolesOn(); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- -template +template void -clitk::ExtractLungFilter:: +clitk::ExtractLungFilter:: SetInput(const ImageType * image) { this->SetNthInput(0, const_cast(image)); @@ -103,21 +109,9 @@ SetInput(const ImageType * image) //-------------------------------------------------------------------- -template -void -clitk::ExtractLungFilter:: -SetInputPatientMask(MaskImageType * image, MaskImagePixelType bg ) -{ - this->SetNthInput(1, const_cast(image)); - SetPatientMaskBackgroundValue(bg); -} -//-------------------------------------------------------------------- - - -//-------------------------------------------------------------------- -template +template void -clitk::ExtractLungFilter:: +clitk::ExtractLungFilter:: AddSeed(InternalIndexType s) { m_Seeds.push_back(s); @@ -126,10 +120,10 @@ AddSeed(InternalIndexType s) //-------------------------------------------------------------------- -template +template template void -clitk::ExtractLungFilter:: +clitk::ExtractLungFilter:: SetArgsInfo(ArgsInfoType mArgsInfo) { SetVerboseOption_GGO(mArgsInfo); @@ -137,6 +131,10 @@ SetArgsInfo(ArgsInfoType mArgsInfo) SetWriteStep_GGO(mArgsInfo); SetVerboseWarningOff_GGO(mArgsInfo); + SetAFDBFilename_GGO(mArgsInfo); + SetOutputLungFilename_GGO(mArgsInfo); + SetOutputTracheaFilename_GGO(mArgsInfo); + SetUpperThreshold_GGO(mArgsInfo); SetLowerThreshold_GGO(mArgsInfo); SetNumberOfSlicesToSkipBeforeSearchingSeed_GGO(mArgsInfo); @@ -159,34 +157,46 @@ SetArgsInfo(ArgsInfoType mArgsInfo) SetRadiusForTrachea_GGO(mArgsInfo); SetLabelizeParameters3_GGO(mArgsInfo); - SetFinalOpenCloseRadius_GGO(mArgsInfo); - SetFinalOpenClose_GGO(mArgsInfo); + SetOpenCloseRadius_GGO(mArgsInfo); + SetOpenClose_GGO(mArgsInfo); + + SetFillHoles_GGO(mArgsInfo); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- -template +template void -clitk::ExtractLungFilter:: +clitk::ExtractLungFilter:: GenerateOutputInformation() { Superclass::GenerateOutputInformation(); + + // Read DB + LoadAFDB(); // Get input pointers - patient = dynamic_cast(itk::ProcessObject::GetInput(1)); input = dynamic_cast(itk::ProcessObject::GetInput(0)); + patient = GetAFDB()->template GetImage ("patient"); - // Check image - if (!HaveSameSizeAndSpacing(input, patient)) { - clitkExceptionMacro("the 'input' and 'patient' masks must have the same size & spacing."); - } - + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + // Crop input like patient image (must have the same spacing) + StartNewStep("Crop input image to 'patient' extends"); + typedef clitk::CropLikeImageFilter CropImageFilter; + typename CropImageFilter::Pointer cropFilter = CropImageFilter::New(); + cropFilter->SetInput(input); + cropFilter->SetCropLikeImage(patient); + cropFilter->Update(); + working_input = cropFilter->GetOutput(); + StopCurrentStep(working_input); + //-------------------------------------------------------------------- //-------------------------------------------------------------------- StartNewStep("Set background to initial image"); working_input = SetBackground - (input, patient, GetPatientMaskBackgroundValue(), -1000); + (working_input, patient, GetPatientMaskBackgroundValue(), -1000); StopCurrentStep(working_input); //-------------------------------------------------------------------- @@ -313,15 +323,15 @@ GenerateOutputInformation() //-------------------------------------------------------------------- //-------------------------------------------------------------------- - typedef clitk::AutoCropFilter CropFilterType; - typename CropFilterType::Pointer cropFilter = CropFilterType::New(); + typedef clitk::AutoCropFilter AutoCropFilterType; + typename AutoCropFilterType::Pointer autocropFilter = AutoCropFilterType::New(); if (m_Seeds.size() != 0) { // if ==0 ->no trachea found - StartNewStep("Croping trachea"); - cropFilter->SetInput(trachea_tmp); - cropFilter->Update(); // Needed + StartNewStep("Cropping trachea"); + autocropFilter->SetInput(trachea_tmp); + autocropFilter->Update(); // Needed typedef itk::CastImageFilter CastImageFilterType; typename CastImageFilterType::Pointer caster= CastImageFilterType::New(); - caster->SetInput(cropFilter->GetOutput()); + caster->SetInput(autocropFilter->GetOutput()); caster->Update(); trachea = caster->GetOutput(); StopCurrentStep(trachea); @@ -329,23 +339,23 @@ GenerateOutputInformation() //-------------------------------------------------------------------- //-------------------------------------------------------------------- - StartNewStep("Croping lung"); - typename CropFilterType::Pointer cropFilter2 = CropFilterType::New(); // Needed to reset pipeline - cropFilter2->SetInput(working_image); - cropFilter2->Update(); - working_image = cropFilter2->GetOutput(); + StartNewStep("Cropping lung"); + typename AutoCropFilterType::Pointer autocropFilter2 = AutoCropFilterType::New(); // Needed to reset pipeline + autocropFilter2->SetInput(working_image); + autocropFilter2->Update(); + working_image = autocropFilter2->GetOutput(); StopCurrentStep(working_image); //-------------------------------------------------------------------- //-------------------------------------------------------------------- // Final OpenClose - if (GetFinalOpenClose()) { + if (GetOpenClose()) { StartNewStep("Open/Close"); // Structuring element typedef itk::BinaryBallStructuringElement KernelType; KernelType structuringElement; - structuringElement.SetRadius(GetFinalOpenCloseRadius()); + structuringElement.SetRadius(GetOpenCloseRadius()); structuringElement.CreateStructuringElement(); // Open @@ -367,6 +377,20 @@ GenerateOutputInformation() working_image = closeFilter->GetOutput(); } + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + // Fill Lungs + if (GetFillHoles()) { + StartNewStep("Fill Holes"); + /* + typename FillMaskFilterType::Pointer fillMaskFilter = FillMaskFilterType::New(); + fillMaskFilter(working_image); + fillMaskFilter->Update(); + working_image = fillMaskFilter->GetOutput(); + StopCurrentStep(working_image); + */ + } + //-------------------------------------------------------------------- //-------------------------------------------------------------------- StartNewStep("Separate Left/Right lungs"); @@ -426,28 +450,30 @@ GenerateOutputInformation() // Update output info this->GetOutput(0)->SetRegions(output->GetLargestPossibleRegion()); - - } //-------------------------------------------------------------------- //-------------------------------------------------------------------- -template +template void -clitk::ExtractLungFilter:: +clitk::ExtractLungFilter:: GenerateData() { // Set the output this->GraftOutput(output); // not SetNthOutput + // Store image filenames into AFDB + GetAFDB()->SetImageFilename("lungs", this->GetOutputLungFilename()); + GetAFDB()->SetImageFilename("trachea", this->GetOutputTracheaFilename()); + WriteAFDB(); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- -template +template bool -clitk::ExtractLungFilter:: +clitk::ExtractLungFilter:: SearchForTracheaSeed(int skip) { if (m_Seeds.size() == 0) { // try to find seed (if not zero, it is given by user) @@ -495,9 +521,9 @@ SearchForTracheaSeed(int skip) //-------------------------------------------------------------------- -template +template void -clitk::ExtractLungFilter:: +clitk::ExtractLungFilter:: TracheaRegionGrowing() { // Explosion controlled region growing @@ -536,9 +562,9 @@ TracheaRegionGrowing() //-------------------------------------------------------------------- -template +template double -clitk::ExtractLungFilter:: +clitk::ExtractLungFilter:: ComputeTracheaVolume() { typedef itk::ImageRegionConstIterator IteratorType; @@ -557,9 +583,9 @@ ComputeTracheaVolume() //-------------------------------------------------------------------- -template +template void -clitk::ExtractLungFilter:: +clitk::ExtractLungFilter:: SearchForTrachea() { // Search for seed among n slices, skip some slices before starting diff --git a/segmentation/clitkExtractLungGenericFilter.h b/segmentation/clitkExtractLungGenericFilter.h index 7d6306b..bc7b581 100644 --- a/segmentation/clitkExtractLungGenericFilter.h +++ b/segmentation/clitkExtractLungGenericFilter.h @@ -19,6 +19,7 @@ #ifndef CLITKEXTRACTLUNGSGENERICFILTER_H #define CLITKEXTRACTLUNGSGENERICFILTER_H +// clitk #include "clitkIO.h" #include "clitkImageToImageGenericFilter.h" #include "clitkExtractLungFilter.h" @@ -26,7 +27,6 @@ //-------------------------------------------------------------------- namespace clitk { - template class ITK_EXPORT ExtractLungGenericFilter: public ImageToImageGenericFilter > diff --git a/segmentation/clitkExtractLungGenericFilter.txx b/segmentation/clitkExtractLungGenericFilter.txx index 74317ed..64e7fb8 100644 --- a/segmentation/clitkExtractLungGenericFilter.txx +++ b/segmentation/clitkExtractLungGenericFilter.txx @@ -54,7 +54,6 @@ void clitk::ExtractLungGenericFilter::SetArgsInfo(const ArgsInfoTy 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); } @@ -69,15 +68,13 @@ 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; + typedef clitk::ExtractLungFilter FilterType; typename FilterType::Pointer filter = FilterType::New(); // Set the filter (needed for example for threaded monitoring) @@ -86,14 +83,13 @@ void clitk::ExtractLungGenericFilter::UpdateWithInputImageType() // Set global Options filter->SetArgsInfo(mArgsInfo); filter->SetInput(input); - filter->SetInputPatientMask(patient, mArgsInfo.patientBG_arg); // Go ! filter->Update(); // Write/Save results - typename OutputImageType::Pointer output = filter->GetOutput(); - this->template SetNextOutput(output); + typename MaskImageType::Pointer output = filter->GetOutput(); + this->template SetNextOutput(output); this->template SetNextOutput(filter->GetTracheaImage()); } //-------------------------------------------------------------------- diff --git a/segmentation/clitkExtractMediastinumFilter.txx b/segmentation/clitkExtractMediastinumFilter.txx index 7f5ca18..b76e617 100644 --- a/segmentation/clitkExtractMediastinumFilter.txx +++ b/segmentation/clitkExtractMediastinumFilter.txx @@ -25,6 +25,7 @@ #include "clitkAddRelativePositionConstraintToLabelImageFilter.h" #include "clitkSegmentationUtils.h" #include "clitkExtractAirwaysTreeInfoFilter.h" +#include "clitkCropLikeImageFilter.h" // std #include @@ -138,6 +139,8 @@ SetArgsInfo(ArgsInfoType mArgsInfo) SetFuzzyThreshold1_GGO(mArgsInfo); SetFuzzyThreshold2_GGO(mArgsInfo); SetFuzzyThreshold3_GGO(mArgsInfo); + + SetAFDBFilename_GGO(mArgsInfo); } //-------------------------------------------------------------------- @@ -162,11 +165,13 @@ 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)); - ImagePointer trachea = dynamic_cast(itk::ProcessObject::GetInput(3)); + + // Get input pointers + LoadAFDB(); + ImagePointer patient = GetAFDB()->template GetImage ("patient"); + ImagePointer lung = GetAFDB()->template GetImage ("lungs"); + ImagePointer bones = GetAFDB()->template GetImage ("bones"); + ImagePointer trachea = GetAFDB()->template GetImage ("trachea"); patient->SetRequestedRegion(patient->GetLargestPossibleRegion()); lung->SetRequestedRegion(lung->GetLargestPossibleRegion()); @@ -183,20 +188,39 @@ 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)); - ImageConstPointer trachea = dynamic_cast(itk::ProcessObject::GetInput(3)); + ImagePointer patient = GetAFDB()->template GetImage ("patient"); + ImagePointer lung = GetAFDB()->template GetImage ("lungs"); + ImagePointer bones = GetAFDB()->template GetImage ("bones"); + ImagePointer trachea = GetAFDB()->template GetImage ("trachea"); // Get output pointer ImagePointer output; + // Step 0: Crop support (patient) to lung extend in RL + StartNewStep("Crop support like lungs along LR"); + typedef clitk::CropLikeImageFilter CropFilterType; + typename CropFilterType::Pointer cropFilter = CropFilterType::New(); + cropFilter->SetInput(patient); + cropFilter->SetCropLikeImage(lung, 0);// Indicate that we only crop in X (Left-Right) axe + cropFilter->Update(); + output = cropFilter->GetOutput(); + this->template StopCurrentStep(output); + + // Step 0: Crop support (previous) to bones extend in AP + StartNewStep("Crop support like bones along AP"); + cropFilter = CropFilterType::New(); + cropFilter->SetInput(output); + cropFilter->SetCropLikeImage(bones, 1);// Indicate that we only crop in Y (Ant-Post) axe + cropFilter->Update(); + output = cropFilter->GetOutput(); + this->template StopCurrentStep(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->SetInput1(output); boolFilter->SetInput2(lung); boolFilter->SetOperationType(BoolFilterType::AndNot); boolFilter->Update(); @@ -213,13 +237,14 @@ GenerateData() // Step 2: LR limits from lung (need separate lung ?) StartNewStep("Left/Right limits with lungs"); - /* // WE DO NOT NEED THE FOLLOWING - // Get separate lung images to get only the right and left lung - // (label must be '1' because right is greater than left). - ImagePointer right_lung = clitk::SetBackground(lung, lung, 2, 0); - ImagePointer left_lung = clitk::SetBackground(lung, lung, 1, 0); - writeImage(right_lung, "right.mhd"); - writeImage(left_lung, "left.mhd"); + /* + // WE DO NOT NEED THE FOLLOWING ? + // Get separate lung images to get only the right and left lung (because RelativePositionPropImageFilter only consider fg=1); + // (label must be '1' because right is greater than left). + ImagePointer right_lung = clitk::SetBackground(lung, lung, 2, 0); + ImagePointer left_lung = clitk::SetBackground(lung, lung, 1, 0); + writeImage(right_lung, "right.mhd"); + writeImage(left_lung, "left.mhd"); */ typedef clitk::AddRelativePositionConstraintToLabelImageFilter RelPosFilterType; @@ -228,28 +253,26 @@ GenerateData() relPosFilter->VerboseStepOff(); relPosFilter->WriteStepOff(); relPosFilter->SetInput(output); - DD(output->GetLargestPossibleRegion().GetIndex()); - // relPosFilter->SetInputObject(left_lung); + //relPosFilter->SetInputObject(left_lung); relPosFilter->SetInputObject(lung); relPosFilter->SetOrientationType(RelPosFilterType::LeftTo); // warning left lung is at right ;) relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing()); relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold1()); relPosFilter->Update(); output = relPosFilter->GetOutput(); - DD(output->GetLargestPossibleRegion()); + // writeImage(right_lung, "step4-left.mhd"); relPosFilter->SetInput(output); relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId()); relPosFilter->VerboseStepOff(); relPosFilter->WriteStepOff(); - // relPosFilter->SetInputObject(right_lung); + //relPosFilter->SetInputObject(right_lung); relPosFilter->SetInputObject(lung); relPosFilter->SetOrientationType(RelPosFilterType::RightTo); relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing()); relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold1()); relPosFilter->Update(); output = relPosFilter->GetOutput(); - DD(output->GetLargestPossibleRegion()); this->template StopCurrentStep(output); // Step 3: AP limits from bones @@ -268,37 +291,37 @@ GenerateData() DD(index_trachea); // Split bone image first into two parts (ant and post) - typedef itk::RegionOfInterestImageFilter CropFilterType; - // typedef itk::ExtractImageFilter CropFilterType; - typename CropFilterType::Pointer cropFilter = CropFilterType::New(); + typedef itk::RegionOfInterestImageFilter ROIFilterType; + // typedef itk::ExtractImageFilter ROIFilterType; + typename ROIFilterType::Pointer roiFilter = ROIFilterType::New(); ImageRegionType region = bones->GetLargestPossibleRegion(); ImageSizeType size = region.GetSize(); DD(size); size[1] = index_trachea[1]; //size[1]/2.0; DD(size); region.SetSize(size); - cropFilter->SetInput(bones); - // cropFilter->SetExtractionRegion(region); - cropFilter->SetRegionOfInterest(region); - cropFilter->ReleaseDataFlagOff(); - cropFilter->Update(); - bones_ant = cropFilter->GetOutput(); + roiFilter->SetInput(bones); + // roiFilter->SetExtractionRegion(region); + roiFilter->SetRegionOfInterest(region); + roiFilter->ReleaseDataFlagOff(); + roiFilter->Update(); + bones_ant = roiFilter->GetOutput(); writeImage(bones_ant, "b_ant.mhd"); - // cropFilter->ResetPipeline();// = CropFilterType::New(); - cropFilter = CropFilterType::New(); + // roiFilter->ResetPipeline();// = ROIFilterType::New(); + roiFilter = ROIFilterType::New(); ImageIndexType index = region.GetIndex(); index[1] = bones->GetLargestPossibleRegion().GetIndex()[1] + size[1]-1; size[1] = bones->GetLargestPossibleRegion().GetSize()[1] - size[1]; DD(size); region.SetIndex(index); region.SetSize(size); - cropFilter->SetInput(bones); - // cropFilter->SetExtractionRegion(region); - cropFilter->SetRegionOfInterest(region); - cropFilter->ReleaseDataFlagOff(); - cropFilter->Update(); - bones_post = cropFilter->GetOutput(); + roiFilter->SetInput(bones); + // roiFilter->SetExtractionRegion(region); + roiFilter->SetRegionOfInterest(region); + roiFilter->ReleaseDataFlagOff(); + roiFilter->Update(); + bones_post = roiFilter->GetOutput(); writeImage(bones_post, "b_post.mhd"); // Go ! @@ -328,12 +351,14 @@ GenerateData() relPosFilter->Update(); output = relPosFilter->GetOutput(); this->template StopCurrentStep(output); + // Get CCL - output = clitk::Labelize(output, GetBackgroundValue(), true, 100); + StartNewStep("Keep main connected component"); + output = clitk::Labelize(output, GetBackgroundValue(), true, 500); // output = RemoveLabels(output, BG, param->GetLabelsToRemove()); output = clitk::KeepLabels(output, GetBackgroundValue(), GetForegroundValue(), 1, 1, 0); - + this->template StopCurrentStep(output); // Step : Lower limits from lung (need separate lung ?) StartNewStep("Lower limits with lungs"); @@ -353,10 +378,10 @@ GenerateData() DD(output->GetLargestPossibleRegion()); output = clitk::AutoCrop(output, GetBackgroundValue()); - // cropFilter = CropFilterType::New(); - //cropFilter->SetInput(output); - //cropFilter->Update(); - //output = cropFilter->GetOutput(); + // roiFilter = ROIFilterType::New(); + //roiFilter->SetInput(output); + //roiFilter->Update(); + //output = roiFilter->GetOutput(); // Final Step -> set output this->SetNthOutput(0, output); diff --git a/segmentation/clitkExtractPatient.ggo b/segmentation/clitkExtractPatient.ggo index 3a239e7..6b15a6a 100644 --- a/segmentation/clitkExtractPatient.ggo +++ b/segmentation/clitkExtractPatient.ggo @@ -1,7 +1,7 @@ #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." +purpose "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 @@ -13,8 +13,9 @@ 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 "input" i "Input image filename" string yes +option "afdb" a "Output Anatomical Feature in a DB" string no +option "output" o "Output image filename" string yes section "Binarize" @@ -47,7 +48,7 @@ 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 +option "openClose" - "Perform morphological opening and closing with unit radius" flag off +option "noAutoCrop" - "If set : do no crop final mask to BoundingBox" flag on diff --git a/segmentation/clitkExtractPatientFilter.h b/segmentation/clitkExtractPatientFilter.h index 9346d9a..b471747 100644 --- a/segmentation/clitkExtractPatientFilter.h +++ b/segmentation/clitkExtractPatientFilter.h @@ -20,6 +20,7 @@ #define CLITKEXTRACTPATIENTFILTER_H #include "clitkFilterBase.h" +#include "clitkFilterWithAnatomicalFeatureDatabaseManagement.h" namespace clitk { @@ -42,17 +43,20 @@ namespace clitk { */ //-------------------------------------------------------------------- - template + template class ITK_EXPORT ExtractPatientFilter: - public clitk::FilterBase, - public itk::ImageToImageFilter + public virtual clitk::FilterBase, + public clitk::FilterWithAnatomicalFeatureDatabaseManagement, + public itk::ImageToImageFilter > { public: /** Standard class typedefs. */ - typedef ExtractPatientFilter Self; - typedef itk::ImageToImageFilter Superclass; - typedef itk::SmartPointer Pointer; - typedef itk::SmartPointer ConstPointer; + typedef itk::Image MaskImageType; + typedef ExtractPatientFilter Self; + typedef itk::ImageToImageFilter Superclass; + typedef itk::SmartPointer Pointer; + typedef itk::SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); @@ -70,13 +74,12 @@ namespace clitk { 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; + 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; @@ -85,6 +88,9 @@ namespace clitk { /** Connect inputs */ void SetInput(const TInputImageType * image); + itkSetMacro(OutputPatientFilename, std::string); + itkGetMacro(OutputPatientFilename, std::string); + GGO_DefineOption(output, SetOutputPatientFilename, std::string); // Set all options at a time template @@ -157,19 +163,20 @@ namespace clitk { itkSetMacro(AutoCrop, bool); itkGetConstMacro(AutoCrop, bool); itkBooleanMacro(AutoCrop); - GGO_DefineOption_Flag(autoCrop, SetAutoCrop); + GGO_DefineOption_Flag(noAutoCrop, SetAutoCrop); protected: ExtractPatientFilter(); virtual ~ExtractPatientFilter() {} - itkSetMacro(BackgroundValue, OutputImagePixelType); - itkSetMacro(ForegroundValue, OutputImagePixelType); - itkGetConstMacro(BackgroundValue, OutputImagePixelType); - itkGetConstMacro(ForegroundValue, OutputImagePixelType); - OutputImagePixelType m_BackgroundValue; - OutputImagePixelType m_ForegroundValue; - + itkSetMacro(BackgroundValue, MaskImagePixelType); + itkSetMacro(ForegroundValue, MaskImagePixelType); + itkGetConstMacro(BackgroundValue, MaskImagePixelType); + itkGetConstMacro(ForegroundValue, MaskImagePixelType); + MaskImagePixelType m_BackgroundValue; + MaskImagePixelType m_ForegroundValue; + + std::string m_OutputPatientFilename; InputImagePixelType m_UpperThreshold; InputImagePixelType m_LowerThreshold; bool m_UseLowerThreshold; @@ -190,7 +197,7 @@ namespace clitk { virtual void GenerateData(); InputImageConstPointer input; - OutputImagePointer output; + MaskImagePointer output; typename InternalImageType::Pointer working_image; private: diff --git a/segmentation/clitkExtractPatientFilter.txx b/segmentation/clitkExtractPatientFilter.txx index e9dd6fe..bf84ef7 100644 --- a/segmentation/clitkExtractPatientFilter.txx +++ b/segmentation/clitkExtractPatientFilter.txx @@ -35,11 +35,12 @@ #include "itkCastImageFilter.h" //-------------------------------------------------------------------- -template -clitk::ExtractPatientFilter:: +template +clitk::ExtractPatientFilter:: ExtractPatientFilter(): clitk::FilterBase(), - itk::ImageToImageFilter() + clitk::FilterWithAnatomicalFeatureDatabaseManagement(), + itk::ImageToImageFilter() { this->SetNumberOfRequiredInputs(1); SetBackgroundValue(0); // Must be zero @@ -71,16 +72,16 @@ ExtractPatientFilter(): SetLastKeep(1); // Step 4: OpenClose (option) - FinalOpenCloseOn(); - AutoCropOff(); + FinalOpenCloseOff(); + AutoCropOn(); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- -template +template void -clitk::ExtractPatientFilter:: +clitk::ExtractPatientFilter:: SetInput(const TInputImageType * image) { this->SetNthInput(0, const_cast(image)); @@ -89,10 +90,10 @@ SetInput(const TInputImageType * image) //-------------------------------------------------------------------- -template +template template void -clitk::ExtractPatientFilter:: +clitk::ExtractPatientFilter:: SetArgsInfo(ArgsInfoType arg) { SetVerboseOption_GGO(arg); @@ -100,6 +101,8 @@ SetArgsInfo(ArgsInfoType arg) SetWriteStep_GGO(arg); SetVerboseWarningOff_GGO(arg); + SetOutputPatientFilename_GGO(arg); + SetUpperThreshold_GGO(arg); SetLowerThreshold_GGO(arg); @@ -118,20 +121,22 @@ SetArgsInfo(ArgsInfoType arg) SetFinalOpenClose_GGO(arg); SetAutoCrop_GGO(arg); + + SetAFDBFilename_GGO(arg); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- -template +template void -clitk::ExtractPatientFilter:: +clitk::ExtractPatientFilter:: GenerateOutputInformation() { Superclass::GenerateOutputInformation(); input = dynamic_cast(itk::ProcessObject::GetInput(0)); - // OutputImagePointer outputImage = this->GetOutput(0); + // MaskImagePointer outputImage = this->GetOutput(0); // outputImage->SetRegions(input->GetLargestPossibleRegion()); // Get input pointers @@ -209,6 +214,10 @@ GenerateOutputInformation() { relabelFilter2->SetInput(connectFilter2->GetOutput()); relabelFilter2->Update(); working_image = relabelFilter2->GetOutput(); + + // Keep main label + working_image = KeepLabels + (working_image, GetBackgroundValue(), GetForegroundValue(), 1, 1, true); StopCurrentStep(working_image); //-------------------------------------------------------------------- @@ -263,7 +272,7 @@ GenerateOutputInformation() { //-------------------------------------------------------------------- //-------------------------------------------------------------------- // Final Cast - typedef itk::CastImageFilter CastImageFilterType; + typedef itk::CastImageFilter CastImageFilterType; typename CastImageFilterType::Pointer caster= CastImageFilterType::New(); caster->SetInput(working_image); caster->Update(); @@ -274,25 +283,28 @@ GenerateOutputInformation() { // [Optional] if (GetAutoCrop()) { StartNewStep("AutoCrop"); - typedef clitk::AutoCropFilter CropFilterType; + typedef clitk::AutoCropFilter CropFilterType; typename CropFilterType::Pointer cropFilter = CropFilterType::New(); cropFilter->SetInput(output); cropFilter->SetBackgroundValue(GetBackgroundValue()); cropFilter->Update(); output = cropFilter->GetOutput(); - StopCurrentStep(output); + StopCurrentStep(output); } } //-------------------------------------------------------------------- //-------------------------------------------------------------------- -template +template void -clitk::ExtractPatientFilter:: +clitk::ExtractPatientFilter:: GenerateData() { - //this->SetNthOutput(0, output); // -> no because redo filter otherwise + // Final Graft this->GraftOutput(output); + // Store image filename into AFDB + GetAFDB()->SetImageFilename("patient", this->GetOutputPatientFilename()); + WriteAFDB(); } //-------------------------------------------------------------------- diff --git a/segmentation/clitkExtractPatientGenericFilter.txx b/segmentation/clitkExtractPatientGenericFilter.txx index 7fc0740..e2b2e97 100644 --- a/segmentation/clitkExtractPatientGenericFilter.txx +++ b/segmentation/clitkExtractPatientGenericFilter.txx @@ -69,7 +69,7 @@ void clitk::ExtractPatientGenericFilter::UpdateWithInputImageType( typename ImageType::Pointer input = this->template GetInput(0); // Create filter - typedef clitk::ExtractPatientFilter FilterType; + typedef clitk::ExtractPatientFilter FilterType; typename FilterType::Pointer filter = FilterType::New(); // Set the filter (needed for example for threaded monitoring) @@ -81,13 +81,6 @@ void clitk::ExtractPatientGenericFilter::UpdateWithInputImageType( // Go ! filter->Update(); - - // // Check if error - // if (filter->HasError()) { - // SetLastError(filter->GetLastError()); - // // No output - // return; - // } // Write/Save results typename OutputImageType::Pointer output = filter->GetOutput(); -- 2.47.1