]> Creatis software - clitk.git/blobdiff - segmentation/clitkExtractPatientFilter.txx
Merge branch 'master' of tux.creatis.insa-lyon.fr:clitk
[clitk.git] / segmentation / clitkExtractPatientFilter.txx
index cfc2ab2f8d4544c992374864ab38364b5da187d3..fedf853c82590918849ddc8df2e9e58ec06a7f9e 100644 (file)
@@ -1,9 +1,9 @@
 /*=========================================================================
   Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
 
-  Authors belong to: 
+  Authors belong to:
   - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://oncora1.lyon.fnclcc.fr
+  - Léon Bérard cancer center       http://www.centreleonberard.fr
   - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
 
   This software is distributed WITHOUT ANY WARRANTY; without even
@@ -14,7 +14,7 @@
 
   - 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
@@ -24,6 +24,8 @@
 #include "clitkSetBackgroundImageFilter.h"
 #include "clitkDecomposeAndReconstructImageFilter.h"
 #include "clitkAutoCropFilter.h"
+#include "clitkMemoryUsage.h"
+#include "clitkSegmentationUtils.h"
 
 // itk
 #include "itkBinaryThresholdImageFilter.h"
 #include "itkBinaryMorphologicalOpeningImageFilter.h"
 #include "itkBinaryBallStructuringElement.h"
 #include "itkCastImageFilter.h"
+#include "itkConstantPadImageFilter.h"
 
 //--------------------------------------------------------------------
-template <class TInputImageType, class TOutputImageType>
-clitk::ExtractPatientFilter<TInputImageType, TOutputImageType>::
+template <class TInputImageType>
+clitk::ExtractPatientFilter<TInputImageType>::
 ExtractPatientFilter():
   clitk::FilterBase(),
-  itk::ImageToImageFilter<TInputImageType, TOutputImageType>()
+  clitk::FilterWithAnatomicalFeatureDatabaseManagement(),
+  itk::ImageToImageFilter<TInputImageType, MaskImageType>()
 {
   this->SetNumberOfRequiredInputs(1);
   SetBackgroundValue(0); // Must be zero
   SetForegroundValue(1);
+  SetPrimaryOpeningRadius(0);
 
   // Step 1: Threshold + CC + sort (Find low density areas)
   SetUpperThreshold(-300);
@@ -65,23 +70,23 @@ ExtractPatientFilter():
   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();
+  FinalOpenCloseOff();
+  AutoCropOn();
 }
 //--------------------------------------------------------------------
 
 
 //--------------------------------------------------------------------
-template <class TInputImageType, class TOutputImageType>
-void 
-clitk::ExtractPatientFilter<TInputImageType, TOutputImageType>::
-SetInput(const TInputImageType * image) 
+template <class TInputImageType>
+void
+clitk::ExtractPatientFilter<TInputImageType>::
+SetInput(const TInputImageType * image)
 {
   this->SetNthInput(0, const_cast<TInputImageType *>(image));
 }
@@ -89,88 +94,97 @@ SetInput(const TInputImageType * image)
 
 
 //--------------------------------------------------------------------
-template <class TInputImageType, class TOutputImageType>
-template<class ArgsInfoType>
-void 
-clitk::ExtractPatientFilter<TInputImageType, TOutputImageType>::
-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 <class TInputImageType>
+void
+clitk::ExtractPatientFilter<TInputImageType>::
+GenerateOutputInformation() {
 
-
-//--------------------------------------------------------------------
-template <class TInputImageType, class TOutputImageType>
-void 
-clitk::ExtractPatientFilter<TInputImageType, TOutputImageType>::
-GenerateOutputInformation() { 
+  clitk::PrintMemory(GetVerboseMemoryFlag(), "Initial memory"); // OK
 
   Superclass::GenerateOutputInformation();
   input = dynamic_cast<const TInputImageType*>(itk::ProcessObject::GetInput(0));
 
-  // OutputImagePointer outputImage = this->GetOutput(0);
+  // MaskImagePointer outputImage = this->GetOutput(0);
 //   outputImage->SetRegions(input->GetLargestPossibleRegion());
 
   // Get input pointers
   static const unsigned int Dim = InputImageType::ImageDimension;
   //input = dynamic_cast<const TInputImageType*>(itk::ProcessObject::GetInput(0));
-    
+
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
-  // Step 1: 
+  // Step 1:
   StartNewStep("Find low densities areas");
-  typedef itk::BinaryThresholdImageFilter<InputImageType, InternalImageType> BinarizeFilterType;  
+
+  // Pad images with air to prevent patient touching the image border
+  typedef itk::ConstantPadImageFilter<InputImageType, InputImageType> PadFilterType;
+  typename PadFilterType::Pointer padFilter = PadFilterType::New();
+  padFilter->SetInput(input);
+  padFilter->SetConstant(GetUpperThreshold() - 1);
+  typename InputImageType::SizeType bounds;
+  for (unsigned i = 0; i < Dim - 1; ++i)
+    bounds[i] = 1;
+  bounds[Dim - 1] = 0;
+  padFilter->SetPadLowerBound(bounds);
+  padFilter->SetPadUpperBound(bounds);
+  padFilter->Update();
+  
+  typedef itk::BinaryThresholdImageFilter<InputImageType, InternalImageType> BinarizeFilterType;
   typename BinarizeFilterType::Pointer binarizeFilter=BinarizeFilterType::New();
-  binarizeFilter->SetInput(input);
+  binarizeFilter->SetInput(padFilter->GetOutput());
   if (m_UseLowerThreshold) binarizeFilter->SetLowerThreshold(GetLowerThreshold());
   binarizeFilter->SetUpperThreshold(GetUpperThreshold());
   binarizeFilter ->SetInsideValue(this->GetForegroundValue());
   binarizeFilter ->SetOutsideValue(this->GetBackgroundValue());
+  padFilter->GetOutput()->ReleaseData();
+  working_image = binarizeFilter->GetOutput();
+
+  typedef itk::BinaryBallStructuringElement<InternalPixelType,Dim> KernelType;
+  unsigned int radius = this->GetPrimaryOpeningRadius();
+  if (radius > 0)
+  {
+    if (this->GetVerboseOptionFlag()) std::cout << ("Opening after threshold; R = ") << radius << std::endl;
+    KernelType kernel;
+    kernel.SetRadius(radius);
+    
+    typedef itk::BinaryMorphologicalOpeningImageFilter<InternalImageType, InternalImageType , KernelType> OpenFilterType2;
+    typename OpenFilterType2::Pointer openFilter2 = OpenFilterType2::New();
+    openFilter2->SetInput(working_image);
+    openFilter2->SetBackgroundValue(0);
+    openFilter2->SetForegroundValue(1);
+    openFilter2->SetKernel(kernel);
+    openFilter2->Update();
+    working_image->ReleaseData();
+    working_image = openFilter2->GetOutput();
+  }
 
+  if (this->GetVerboseOptionFlag()) std::cout << ("Labelling") << std::endl;
   // Connected component labeling
   typedef itk::ConnectedComponentImageFilter<InternalImageType, InternalImageType> ConnectFilterType;
   typename ConnectFilterType::Pointer connectFilter=ConnectFilterType::New();
-  connectFilter->SetInput(binarizeFilter->GetOutput());
+  connectFilter->SetInput(working_image);
   connectFilter->SetBackgroundValue(this->GetBackgroundValue());
   connectFilter->SetFullyConnected(false);
-  
+  connectFilter->Update();
+  working_image->ReleaseData();
+  working_image = connectFilter->GetOutput();
+
+  if (this->GetVerboseOptionFlag()) std::cout << ("RelabelComponentImageFilter") << std::endl;
   // Sort labels according to size
   typedef itk::RelabelComponentImageFilter<InternalImageType, InternalImageType> RelabelFilterType;
   typename RelabelFilterType::Pointer relabelFilter=RelabelFilterType::New();
   relabelFilter->InPlaceOn();
   relabelFilter->SetInput(connectFilter->GetOutput());
   relabelFilter->Update();
+  working_image->ReleaseData();
   working_image = relabelFilter->GetOutput();
-  
+
   // End
   StopCurrentStep<InternalImageType>(working_image);
 
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
-  // [Optional] 
+  // [Optional]
   if (GetDecomposeAndReconstructDuringFirstStep()) {
     StartNewStep("First Decompose & Reconstruct step");
     typedef clitk::DecomposeAndReconstructImageFilter<InternalImageType,InternalImageType> FilterType;
@@ -184,36 +198,48 @@ GenerateOutputInformation() {
     f->SetFullyConnected(true);
     f->SetNumberOfNewLabels(GetNumberOfNewLabels1());
     f->Update();
+    working_image->ReleaseData();
     working_image = f->GetOutput();
     StopCurrentStep<InternalImageType>(working_image);
   }
-  
+
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
+  if (this->GetVerboseOptionFlag()) std::cout << ("Remove the air (largest area)") << std::endl;
   StartNewStep("Remove the air (largest area)");
-  typedef itk::BinaryThresholdImageFilter<InternalImageType, InternalImageType> iBinarizeFilterType;  
+  typedef itk::BinaryThresholdImageFilter<InternalImageType, InternalImageType> 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 ?
+  binarizeFilter2->SetLowerThreshold(GetFirstKeep());
+  binarizeFilter2->SetUpperThreshold(GetLastKeep());
+  binarizeFilter2 ->SetInsideValue(0);
+  binarizeFilter2 ->SetOutsideValue(1);
+  binarizeFilter2 ->Update();
+  working_image->ReleaseData();
+  working_image = binarizeFilter2->GetOutput();
 
   typename ConnectFilterType::Pointer connectFilter2 = ConnectFilterType::New();
-  connectFilter2->SetInput(binarizeFilter2->GetOutput());
+  connectFilter2->SetInput(working_image);
   connectFilter2->SetBackgroundValue(this->GetBackgroundValue());
   connectFilter2->SetFullyConnected(false);
+  connectFilter2->Update();
+  working_image->ReleaseData();
+  working_image = connectFilter2->GetOutput();
 
   typename RelabelFilterType::Pointer relabelFilter2 = RelabelFilterType::New();
-  relabelFilter2->SetInput(connectFilter2->GetOutput());
+  relabelFilter2->SetInput(working_image);
   relabelFilter2->Update();
+  working_image->ReleaseData();
   working_image = relabelFilter2->GetOutput();
+
+  // Keep main label
+  working_image = KeepLabels<InternalImageType>
+    (working_image, GetBackgroundValue(), GetForegroundValue(), 1, 1, true);
   StopCurrentStep<InternalImageType>(working_image);
 
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
-  // [Optional] 
+  // [Optional]
   if (GetDecomposeAndReconstructDuringSecondStep()) {
     StartNewStep("Second Decompose & Reconstruct step");
     typedef clitk::DecomposeAndReconstructImageFilter<InternalImageType,InternalImageType> FilterType;
@@ -227,30 +253,17 @@ GenerateOutputInformation() {
     f->SetFullyConnected(true);
     f->SetNumberOfNewLabels(GetNumberOfNewLabels2());
     f->Update();
+    working_image->ReleaseData();
     working_image = f->GetOutput();
     StopCurrentStep<InternalImageType>(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<InternalImageType>(working_image);
-  
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
   // [Optional]
   if (GetFinalOpenClose()) {
     StartNewStep("Final OpenClose");
     // Open
-    typedef itk::BinaryBallStructuringElement<InternalPixelType,Dim> KernelType;
     KernelType structuringElement;
     structuringElement.SetRadius(1);
     structuringElement.CreateStructuringElement();
@@ -259,7 +272,7 @@ GenerateOutputInformation() {
     openFilter->SetInput(working_image);
     openFilter->SetBackgroundValue(this->GetBackgroundValue());
     openFilter->SetForegroundValue(this->GetForegroundValue());
-    openFilter->SetKernel(structuringElement);  
+    openFilter->SetKernel(structuringElement);
     // Close
     typedef itk::BinaryMorphologicalClosingImageFilter<InternalImageType, InternalImageType , KernelType> CloseFilterType;
     typename CloseFilterType::Pointer closeFilter = CloseFilterType::New();
@@ -268,18 +281,20 @@ GenerateOutputInformation() {
     closeFilter->SetForegroundValue(this->GetForegroundValue());
     //  closeFilter->SetBackgroundValue(SetBackgroundValue());
     closeFilter->SetKernel(structuringElement);
-    closeFilter->Update();  
+    closeFilter->Update();
+    working_image->ReleaseData();
     working_image = closeFilter->GetOutput();
     StopCurrentStep<InternalImageType>(working_image);
   }
 
   //--------------------------------------------------------------------
   //--------------------------------------------------------------------
-  // Final Cast 
-  typedef itk::CastImageFilter<InternalImageType, OutputImageType> CastImageFilterType;
+  // Final Cast
+  typedef itk::CastImageFilter<InternalImageType, MaskImageType> CastImageFilterType;
   typename CastImageFilterType::Pointer caster= CastImageFilterType::New();
   caster->SetInput(working_image);
   caster->Update();
+  working_image->ReleaseData();
   output = caster->GetOutput();
 
   //--------------------------------------------------------------------
@@ -287,27 +302,43 @@ GenerateOutputInformation() {
   // [Optional]
   if (GetAutoCrop()) {
   StartNewStep("AutoCrop");
-    typedef clitk::AutoCropFilter<OutputImageType> CropFilterType;
+    typedef clitk::AutoCropFilter<MaskImageType> CropFilterType;
     typename CropFilterType::Pointer cropFilter = CropFilterType::New();
     cropFilter->SetInput(output);
     cropFilter->SetBackgroundValue(GetBackgroundValue());
-    cropFilter->Update();   
+    cropFilter->Update();
+    output->ReleaseData();
+    output = cropFilter->GetOutput();
+    StopCurrentStep<MaskImageType>(output);
+  }
+  else
+  {
+    // Remove Padding region
+    typedef itk::CropImageFilter<MaskImageType, MaskImageType> CropFilterType;
+    typename CropFilterType::Pointer cropFilter = CropFilterType::New();
+    cropFilter->SetInput(output);
+    cropFilter->SetLowerBoundaryCropSize(bounds);
+    cropFilter->SetUpperBoundaryCropSize(bounds);
+    cropFilter->Update();
+    output->ReleaseData();
     output = cropFilter->GetOutput();
-    StopCurrentStep<OutputImageType>(output);
   }
 }
 //--------------------------------------------------------------------
 
 
 //--------------------------------------------------------------------
-template <class TInputImageType, class TOutputImageType>
-void 
-clitk::ExtractPatientFilter<TInputImageType, TOutputImageType>::
+template <class TInputImageType>
+void
+clitk::ExtractPatientFilter<TInputImageType>::
 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();
 }
 //--------------------------------------------------------------------
-  
+
 
 #endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX