]> Creatis software - clitk.git/commitdiff
merge cvs -> git
authordsarrut <david.sarrut@gmail.com>
Thu, 21 Apr 2011 05:05:39 +0000 (07:05 +0200)
committerdsarrut <david.sarrut@gmail.com>
Thu, 21 Apr 2011 05:05:39 +0000 (07:05 +0200)
32 files changed:
.gitignore
itk/clitkMeshToBinaryImageFilter.h [new file with mode: 0644]
itk/clitkMeshToBinaryImageFilter.txx [new file with mode: 0644]
itk/clitkSegmentationUtils.h
itk/clitkSegmentationUtils.txx
itk/clitkSliceBySliceRelativePositionFilter.h
itk/clitkSliceBySliceRelativePositionFilter.txx
itk/itkVTKImageToImageFilter.h
itk/itkVTKImageToImageFilter.txx
notes.org~ [new file with mode: 0644]
segmentation/CMakeLists.txt
segmentation/clitkExtractLymphStation_2RL.txx [new file with mode: 0644]
segmentation/clitkExtractLymphStation_3A.txx
segmentation/clitkExtractLymphStation_3P.txx
segmentation/clitkExtractLymphStation_4RL.txx
segmentation/clitkExtractLymphStation_7.txx
segmentation/clitkExtractLymphStation_8.txx
segmentation/clitkExtractLymphStations.cxx
segmentation/clitkExtractLymphStations.ggo
segmentation/clitkExtractLymphStationsFilter.h
segmentation/clitkExtractLymphStationsFilter.old.h [new file with mode: 0644]
segmentation/clitkExtractLymphStationsFilter.old.txx [new file with mode: 0644]
segmentation/clitkExtractLymphStationsFilter.txx
segmentation/clitkExtractLymphStationsFilter.txx.save [new file with mode: 0644]
segmentation/clitkExtractLymphStationsGenericFilter.h
segmentation/clitkExtractLymphStationsGenericFilter.txx
segmentation/clitkExtractPatientFilter.h
segmentation/clitkReconstructThroughDilationImageFilter.txx [changed mode: 0755->0644]
segmentation/clitkTestArtery.cxx [new file with mode: 0644]
segmentation/clitkTestFilter.cxx [new file with mode: 0644]
segmentation/clitkTestFilter.ggo [new file with mode: 0644]
tools/clitkCropImage.ggo [changed mode: 0755->0644]

index 4b17a8839181cae7053820c81b84675fab5bd403..8453ef6974c7f4ef811514eb1571563ff9306f43 100644 (file)
@@ -13,3 +13,5 @@ CMakeCache.txt
 build/*
 */.vimrc
 _*
+#*#
+notes.org
diff --git a/itk/clitkMeshToBinaryImageFilter.h b/itk/clitkMeshToBinaryImageFilter.h
new file mode 100644 (file)
index 0000000..b681a98
--- /dev/null
@@ -0,0 +1,94 @@
+/*=========================================================================
+  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 CLITKMESHTOBINARYIMAGEFILTER_H
+#define CLITKMESHTOBINARYIMAGEFILTER_H
+
+// clitk
+#include "clitkCommon.h"
+
+namespace clitk {
+    
+  /* --------------------------------------------------------------------     
+     Convert a mesh composed of a list of 2D contours, into a 3D binray
+     image.     
+     -------------------------------------------------------------------- */
+  
+  template <class ImageType>
+  class ITK_EXPORT MeshToBinaryImageFilter: public itk::ImageSource<ImageType>
+  {
+
+  public:
+    /** Standard class typedefs. */
+    typedef itk::ImageSource<ImageType>   Superclass;
+    typedef MeshToBinaryImageFilter       Self;
+    typedef itk::SmartPointer<Self>       Pointer;
+    typedef itk::SmartPointer<const Self> ConstPointer;
+       
+    /** Method for creation through the object factory. */
+    itkNewMacro(Self);
+    
+    /** Run-time type information (and related methods). */
+    itkTypeMacro(MeshToBinaryImageFilter, Superclass);
+
+    /** ImageDimension constants */
+    itkStaticConstMacro(ImageDimension, unsigned int, ImageType::ImageDimension);
+    typedef itk::Image<float, ImageDimension> FloatImageType;
+
+    /** Some convenient typedefs. */
+    typedef typename ImageType::ConstPointer ImageConstPointer;
+    typedef typename ImageType::Pointer      ImagePointer;
+    typedef typename ImageType::RegionType   RegionType; 
+    typedef typename ImageType::PixelType    PixelType;
+    typedef typename ImageType::SpacingType  SpacingType;
+    typedef typename ImageType::SizeType     SizeType;
+    typedef typename ImageType::PointType    PointType;
+    typedef itk::Image<PixelType, ImageDimension-1> SliceType;
+    
+    /** Input : initial image and object */
+    itkSetMacro(Mesh, vtkSmartPointer<vtkPolyData>);
+    itkGetConstMacro(Mesh, vtkSmartPointer<vtkPolyData>);
+
+    itkSetMacro(LikeImage, ImagePointer);
+    itkGetConstMacro(LikeImage, ImagePointer);
+
+  protected:
+    MeshToBinaryImageFilter();
+    virtual ~MeshToBinaryImageFilter() {}
+    
+    virtual void GenerateOutputInformation();
+    virtual void GenerateData();
+
+    ImagePointer m_LikeImage;
+    vtkSmartPointer<vtkPolyData> m_Mesh;
+
+  private:
+    MeshToBinaryImageFilter(const Self&); //purposely not implemented
+    void operator=(const Self&); //purposely not implemented
+    
+  }; // end class
+  //--------------------------------------------------------------------
+
+} // end namespace clitk
+//--------------------------------------------------------------------
+
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "clitkMeshToBinaryImageFilter.txx"
+#endif
+
+#endif
diff --git a/itk/clitkMeshToBinaryImageFilter.txx b/itk/clitkMeshToBinaryImageFilter.txx
new file mode 100644 (file)
index 0000000..db98970
--- /dev/null
@@ -0,0 +1,144 @@
+/*=========================================================================
+  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 <vtkPolyDataToImageStencil.h>
+#include <vtkLinearExtrusionFilter.h>
+#include <vtkImageStencil.h>
+#include <vtkMetaImageWriter.h>
+
+#include "itkVTKImageImport.h"
+#include "vtkImageExport.h"
+#include "vtkImageData.h"
+
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+clitk::MeshToBinaryImageFilter<ImageType>::
+MeshToBinaryImageFilter():itk::ImageSource<ImageType>()
+{
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void 
+clitk::MeshToBinaryImageFilter<ImageType>::
+GenerateOutputInformation() 
+{
+  ImagePointer output = this->GetOutput(0);
+  
+  // Set the region to output
+  typename ImageType::RegionType m_Region = m_LikeImage->GetLargestPossibleRegion();
+  typename ImageType::SizeType size = m_Region.GetSize();
+  size[0]++;
+  size[1]++;
+  size[2]++;
+  m_Region.SetSize(size);  
+  output->SetLargestPossibleRegion(m_Region);
+  output->SetRequestedRegion(m_Region);
+  output->SetBufferedRegion(m_Region);
+  output->SetRegions(m_Region);
+  output->Allocate();
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void 
+clitk::MeshToBinaryImageFilter<ImageType>::
+GenerateData() 
+{
+  // GO
+  vtkSmartPointer<vtkImageData> binary_image=vtkSmartPointer<vtkImageData>::New();
+  binary_image->SetScalarTypeToUnsignedChar();
+
+  // Set spacing
+  PointType samp_origin = m_LikeImage->GetOrigin();
+  SpacingType spacing=m_LikeImage->GetSpacing();
+  double * spacing2 = new double[3];
+  spacing2[0] = spacing[0];
+  spacing2[1] = spacing[1];
+  spacing2[2] = spacing[2];
+  binary_image->SetSpacing(spacing2);
+
+  // Set origin
+  /// Put the origin on a voxel to avoid small skips
+  binary_image->SetOrigin(samp_origin[0], samp_origin[1], samp_origin[2]);
+
+  // Compute image bounds
+  binary_image->SetExtent(0,m_LikeImage->GetLargestPossibleRegion().GetSize()[0],
+                          0,m_LikeImage->GetLargestPossibleRegion().GetSize()[1],
+                          0,m_LikeImage->GetLargestPossibleRegion().GetSize()[2] 
+                          );
+  
+  // Allocate data
+  binary_image->AllocateScalars();
+  memset(binary_image->GetScalarPointer(),0,
+         binary_image->GetDimensions()[0]*binary_image->GetDimensions()[1]*binary_image->GetDimensions()[2]*sizeof(unsigned char));
+
+  // Image stencil 
+  vtkSmartPointer<vtkPolyDataToImageStencil> sts=vtkSmartPointer<vtkPolyDataToImageStencil>::New();
+  //The following line is extremely important
+  //http://www.nabble.com/Bug-in-vtkPolyDataToImageStencil--td23368312.html#a23370933
+  sts->SetTolerance(0);
+  sts->SetInformationInput(binary_image);
+    
+  // Extrusion
+  vtkSmartPointer<vtkLinearExtrusionFilter> extrude=vtkSmartPointer<vtkLinearExtrusionFilter>::New();
+  extrude->SetInput(m_Mesh);
+  // We extrude in the -slice_spacing direction to respect the FOCAL convention 
+  extrude->SetVector(0, 0, -m_LikeImage->GetSpacing()[2]);
+  sts->SetInput(extrude->GetOutput());
+
+  // Stencil
+  vtkSmartPointer<vtkImageStencil> stencil=vtkSmartPointer<vtkImageStencil>::New();
+  stencil->SetStencil(sts->GetOutput());
+  stencil->SetInput(binary_image);
+
+  // Convert VTK to ITK
+  vtkImageExport * m_Exporter = vtkImageExport::New();
+  typedef itk::VTKImageImport< ImageType >   ImporterFilterType;
+  typename ImporterFilterType::Pointer m_Importer = ImporterFilterType::New();
+
+  m_Importer->SetUpdateInformationCallback( m_Exporter->GetUpdateInformationCallback());
+  m_Importer->SetPipelineModifiedCallback( m_Exporter->GetPipelineModifiedCallback());
+  m_Importer->SetWholeExtentCallback( m_Exporter->GetWholeExtentCallback());
+  m_Importer->SetSpacingCallback( m_Exporter->GetSpacingCallback());
+  m_Importer->SetOriginCallback( m_Exporter->GetOriginCallback());
+  m_Importer->SetScalarTypeCallback( m_Exporter->GetScalarTypeCallback());
+  m_Importer->SetNumberOfComponentsCallback( m_Exporter->GetNumberOfComponentsCallback());
+  m_Importer->SetPropagateUpdateExtentCallback( m_Exporter->GetPropagateUpdateExtentCallback());
+  m_Importer->SetUpdateDataCallback( m_Exporter->GetUpdateDataCallback());
+  m_Importer->SetDataExtentCallback( m_Exporter->GetDataExtentCallback());
+  m_Importer->SetBufferPointerCallback( m_Exporter->GetBufferPointerCallback());
+  m_Importer->SetCallbackUserData( m_Exporter->GetCallbackUserData());
+
+  m_Exporter->SetInput( stencil->GetOutput() );
+  m_Importer->Update();
+
+  writeImage<ImageType>(m_Importer->GetOutput(), "f.mhd");
+
+  this->SetNthOutput(0, m_Importer->GetOutput());
+
+  return;
+}
+//--------------------------------------------------------------------
+
index fcc7f2840ac88d2fd8d29742b94c63e29807e65e..5aa9b9aefbb92cd73b2463e44e07d98a675be2b0 100644 (file)
@@ -3,7 +3,7 @@
 
   Authors belong to: 
   - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://www.centreleonberard.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
@@ -14,7 +14,7 @@
 
   - BSD        See included LICENSE.txt file
   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
-  ===========================================================================**/
+  ======================================================================-====*/
 
 #ifndef CLITKSEGMENTATIONUTILS_H
 #define CLITKSEGMENTATIONUTILS_H
@@ -209,6 +209,11 @@ namespace clitk {
   ComputeCentroids(const ImageType * image, 
                    typename ImageType::PixelType BG, 
                    std::vector<typename ImageType::PointType> & centroids);
+  template<class ImageType>
+  void
+  ComputeCentroids2(const ImageType * image, 
+                   typename ImageType::PixelType BG, 
+                   std::vector<typename ImageType::PointType> & centroids);
   //--------------------------------------------------------------------
 
 
@@ -258,14 +263,20 @@ namespace clitk {
     
     typedef std::map<int, PointType2D> MapPoint2DType;
     typedef std::vector<PointType3D> VectorPoint3DType;
+    typedef std::vector<PointType2D> VectorPoint2DType;
+
   public:
     static void Convert2DTo3D(const PointType2D & p2D, 
                               const ImageType * image, 
                               const int slice, 
                               PointType3D & p3D);
-    static void Convert2DTo3DList(const MapPoint2DType & map, 
+    static void Convert2DMapTo3DList(const MapPoint2DType & map, 
                                   const ImageType * image, 
                                   VectorPoint3DType & list);
+    static void Convert2DListTo3DList(const VectorPoint2DType & p, 
+                                      int slice,
+                                      const ImageType * image, 
+                                      VectorPoint3DType & list);
   };
 
   //--------------------------------------------------------------------
index d2e17587cfdf246044231ad309059c7c662e8a0f..7acec2087eee0da0f898af71a47cf99caf331092 100644 (file)
@@ -14,7 +14,7 @@
 
   - BSD        See included LICENSE.txt file
   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
-  ===========================================================================**/
+  ======================================================================-====*/
 
 // clitk
 #include "clitkSetBackgroundImageFilter.h"
@@ -516,6 +516,47 @@ namespace clitk {
   //--------------------------------------------------------------------
 
 
+  //--------------------------------------------------------------------
+  template<class ImageType>
+  void
+  ComputeCentroids2(const ImageType * image, 
+                   typename ImageType::PixelType BG, 
+                   std::vector<typename ImageType::PointType> & centroids) 
+  {
+    typedef long LabelType;
+    static const unsigned int Dim = ImageType::ImageDimension;
+    typedef itk::ShapeLabelObject< LabelType, Dim > LabelObjectType;
+    typedef itk::LabelMap< LabelObjectType > LabelMapType;
+    typedef itk::LabelImageToLabelMapFilter<ImageType, LabelMapType> ImageToMapFilterType;
+    typename ImageToMapFilterType::Pointer imageToLabelFilter = ImageToMapFilterType::New(); 
+    typedef itk::ShapeLabelMapFilter<LabelMapType, ImageType> ShapeFilterType; 
+    typename ShapeFilterType::Pointer statFilter = ShapeFilterType::New();
+    imageToLabelFilter->SetBackgroundValue(BG);
+    imageToLabelFilter->SetInput(image);
+    statFilter->SetInput(imageToLabelFilter->GetOutput());
+    statFilter->Update();
+    typename LabelMapType::Pointer labelMap = statFilter->GetOutput();
+
+    centroids.clear();
+    typename ImageType::PointType dummy;
+    centroids.push_back(dummy); // label 0 -> no centroid, use dummy point
+    for(uint i=1; i<labelMap->GetNumberOfLabelObjects()+1; i++) {
+      centroids.push_back(labelMap->GetLabelObject(i)->GetCentroid());
+    } 
+    
+    for(uint i=1; i<labelMap->GetNumberOfLabelObjects()+1; i++) {
+      DD(labelMap->GetLabelObject(i)->GetBinaryPrincipalAxes());
+      DD(labelMap->GetLabelObject(i)->GetBinaryFlatness());
+      DD(labelMap->GetLabelObject(i)->GetRoundness ());      
+
+      // search for the point on the boundary alog PA
+
+    }
+
+  }
+  //--------------------------------------------------------------------
+
+
   //--------------------------------------------------------------------
   template<class ImageType>
   void
@@ -558,7 +599,7 @@ namespace clitk {
   //--------------------------------------------------------------------
   template<class ImageType>
   void 
-  PointsUtils<ImageType>::Convert2DTo3DList(const MapPoint2DType & map, 
+  PointsUtils<ImageType>::Convert2DMapTo3DList(const MapPoint2DType & map, 
                                             const ImageType * image, 
                                             VectorPoint3DType & list)
   {
@@ -572,6 +613,24 @@ namespace clitk {
   }
   //--------------------------------------------------------------------
 
+
+  //--------------------------------------------------------------------
+  template<class ImageType>
+  void 
+  PointsUtils<ImageType>::Convert2DListTo3DList(const VectorPoint2DType & p2D, 
+                                                int slice,
+                                                const ImageType * image, 
+                                                VectorPoint3DType & list) 
+  {
+    for(uint i=0; i<p2D.size(); i++) {
+      PointType3D p;
+      Convert2DTo3D(p2D[i], image, slice, p);
+      list.push_back(p);
+    }
+  }
+  //--------------------------------------------------------------------
+
+
   //--------------------------------------------------------------------
   template<class ImageType>
   void 
@@ -940,7 +999,7 @@ namespace clitk {
     }
     
     // Convert 2D points in slice into 3D points
-    clitk::PointsUtils<ImageType>::Convert2DTo3DList(position2D, input, A);
+    clitk::PointsUtils<ImageType>::Convert2DMapTo3DList(position2D, input, A);
     
     // Create additional point just right to the previous ones, on the
     // given lineDirection, in order to create a horizontal/vertical line.
index 35b3b8d88afefefa7edba6a1b96eeea29637ffc4..53c5a87c1b345815eb7a3e05a218d334daa2ab56 100644 (file)
@@ -3,7 +3,7 @@
 
   Authors belong to: 
   - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://www.centreleonberard.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
@@ -14,7 +14,7 @@
 
   - BSD        See included LICENSE.txt file
   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
-  ===========================================================================**/
+  ======================================================================-====*/
 
 #ifndef CLITKSLICEBYSLICERELATIVEPOSITIONFILTER_H
 #define CLITKSLICEBYSLICERELATIVEPOSITIONFILTER_H
@@ -86,6 +86,17 @@ namespace clitk {
     itkSetMacro(UseASingleObjectConnectedComponentBySliceFlag, bool);
     itkBooleanMacro(UseASingleObjectConnectedComponentBySliceFlag);
 
+    itkGetConstMacro(CCLSelectionFlag, bool);
+    itkSetMacro(CCLSelectionFlag, bool);
+    itkBooleanMacro(CCLSelectionFlag);
+    itkGetConstMacro(CCLSelectionDimension, int);
+    itkSetMacro(CCLSelectionDimension, int);
+    itkGetConstMacro(CCLSelectionDirection, int);
+    itkSetMacro(CCLSelectionDirection, int);
+    itkGetConstMacro(CCLSelectionIgnoreSingleCCLFlag, bool);
+    itkSetMacro(CCLSelectionIgnoreSingleCCLFlag, bool);
+    itkBooleanMacro(CCLSelectionIgnoreSingleCCLFlag);
+
   protected:
     SliceBySliceRelativePositionFilter();
     virtual ~SliceBySliceRelativePositionFilter() {}
@@ -102,6 +113,10 @@ namespace clitk {
     int          m_Direction;
     bool         m_IgnoreEmptySliceObjectFlag;
     bool         m_UseASingleObjectConnectedComponentBySliceFlag;
+    bool         m_CCLSelectionFlag;
+    int          m_CCLSelectionDimension;
+    int          m_CCLSelectionDirection;
+    bool         m_CCLSelectionIgnoreSingleCCLFlag;
 
   private:
     SliceBySliceRelativePositionFilter(const Self&); //purposely not implemented
index 9d355bfe39941ecff8807939043599e0c3421ffc..76b0fec9cb35281aa8b8860a1f30313c1902013a 100644 (file)
@@ -3,7 +3,7 @@
 
   Authors belong to: 
   - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://www.centreleonberard.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
@@ -14,7 +14,7 @@
 
   - BSD        See included LICENSE.txt file
   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
-  ===========================================================================**/
+  ======================================================================-====*/
 
 // clitk
 #include "clitkSegmentationUtils.h"
@@ -37,6 +37,10 @@ SliceBySliceRelativePositionFilter():
   this->VerboseStepFlagOff();
   this->WriteStepFlagOff();
   this->SetCombineWithOrFlag(false);
+  CCLSelectionFlagOn();
+  SetCCLSelectionDimension(0);
+  SetCCLSelectionDirection(1);
+  CCLSelectionIgnoreSingleCCLFlagOff();
 }
 //--------------------------------------------------------------------
 
@@ -187,6 +191,39 @@ GenerateOutputInformation()
         mObjectSlices[i] = KeepLabels<SliceType>(mObjectSlices[i], 0, 1, 1, 1, true);
       }
 
+      // Select a single according to a position if more than one CCL
+      if (GetCCLSelectionFlag()) {
+        // if several CCL, choose the most extrema according a direction, 
+        // if not -> should we consider this slice ? 
+        if (nb<2) {
+          if (GetCCLSelectionIgnoreSingleCCLFlag()) {
+            mObjectSlices[i] = SetBackground<SliceType, SliceType>(mObjectSlices[i], mObjectSlices[i], 
+                                                                   1, this->GetBackgroundValue(), 
+                                                                   true);
+          }
+        }
+        int dim = GetCCLSelectionDimension();
+        int direction = GetCCLSelectionDirection();
+        std::vector<typename SliceType::PointType> centroids;
+        ComputeCentroids<SliceType>(mObjectSlices[i], this->GetBackgroundValue(), centroids);
+        uint index=1;
+        for(uint j=1; j<centroids.size(); j++) {
+          if (direction == 1) {
+            if (centroids[j][dim] > centroids[index][dim]) index = j;
+          }
+          else {
+            if (centroids[j][dim] < centroids[index][dim]) index = j;
+          }
+        }
+        for(uint v=1; v<centroids.size(); v++) {
+          if (v != index) {
+            mObjectSlices[i] = SetBackground<SliceType, SliceType>(mObjectSlices[i], mObjectSlices[i], 
+                                                                   (char)v, this->GetBackgroundValue(), 
+                                                                   true);
+          }
+        }
+      }
+
       // Relative position
       typedef clitk::AddRelativePositionConstraintToLabelImageFilter<SliceType> RelPosFilterType;
       typename RelPosFilterType::Pointer relPosFilter = RelPosFilterType::New();
@@ -216,6 +253,15 @@ GenerateOutputInformation()
         mInputSlices[i] = KeepLabels<SliceType>(mInputSlices[i], 0, 1, 1, 1, true);
       }
 
+      /*
+      // Select unique CC according to the most in a given direction
+      if (GetUniqueConnectedComponentBySliceAccordingToADirection()) {
+        int nb;
+        mInputSlices[i] = LabelizeAndCountNumberOfObjects<SliceType>(mInputSlices[i], 0, true, 1, nb);
+        std::vector<typename ImageType::PointType> & centroids;
+        ComputeCentroids
+        }
+      */
     }
   }
 
index 0d1204f44ede6b81335a88f3aef9008f98dc4c41..7d0eb97d5f26632be323b0c4508a076030c581fe 100644 (file)
@@ -3,7 +3,7 @@
 
   Authors belong to: 
   - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://www.centreleonberard.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
 
   - BSD        See included LICENSE.txt file
   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
-===========================================================================**/
-#ifndef __itkVTKImageToImageFilter_h\r
-#define __itkVTKImageToImageFilter_h\r
-#include "itkVTKImageImport.h"\r
-#include "vtkImageExport.h"\r
-#include "vtkImageData.h"\r
-\r
-#ifndef vtkFloatingPointType\r
-#define vtkFloatingPointType float\r
-#endif\r
-\r
-namespace itk\r
-{\r
-\r
-/** \class VTKImageToImageFilter\r
- * \brief Converts a VTK image into an ITK image and plugs a\r
- *  vtk data pipeline to an ITK datapipeline.\r
- *\r
- *  This class puts together an itkVTKImageImporter and a vtkImageExporter.\r
- *  It takes care of the details related to the connection of ITK and VTK\r
- *  pipelines. The User will perceive this filter as an adaptor to which\r
- *  a vtkImage can be plugged as input and an itk::Image is produced as\r
- *  output.\r
- *\r
- * \ingroup   ImageFilters\r
- */\r
-template <class TOutputImage >\r
-class ITK_EXPORT VTKImageToImageFilter : public ProcessObject\r
-{\r
-public:\r
-    /** Standard class typedefs. */\r
-    typedef VTKImageToImageFilter       Self;\r
-    typedef ProcessObject             Superclass;\r
-    typedef SmartPointer<Self>        Pointer;\r
-    typedef SmartPointer<const Self>  ConstPointer;\r
-\r
-    /** Method for creation through the object factory. */\r
-    itkNewMacro(Self);\r
-\r
-    /** Run-time type information (and related methods). */\r
-    itkTypeMacro(VTKImageToImageFilter, ProcessObject);\r
-\r
-    /** Some typedefs. */\r
-    typedef TOutputImage OutputImageType;\r
-    typedef typename    OutputImageType::ConstPointer    OutputImagePointer;\r
-    typedef VTKImageImport< OutputImageType >   ImporterFilterType;\r
-    typedef typename ImporterFilterType::Pointer         ImporterFilterPointer;\r
-\r
-    /** Get the output in the form of a vtkImage.\r
-        This call is delegated to the internal vtkImageImporter filter  */\r
-    const OutputImageType *  GetOutput() const;\r
-\r
-    /** Set the input in the form of a vtkImageData */\r
-    void SetInput( vtkImageData * );\r
-\r
-    /** Return the internal VTK image exporter filter.\r
-        This is intended to facilitate users the access\r
-        to methods in the exporter */\r
-    vtkImageExport * GetExporter() const;\r
-\r
-    /** Return the internal ITK image importer filter.\r
-        This is intended to facilitate users the access\r
-        to methods in the importer */\r
-    ImporterFilterType * GetImporter() const;\r
-\r
-    /** This call delegate the update to the importer */\r
-    void Update();\r
-\r
-protected:\r
-    VTKImageToImageFilter();\r
-    virtual ~VTKImageToImageFilter();\r
-\r
-private:\r
-    VTKImageToImageFilter(const Self&); //purposely not implemented\r
-    void operator=(const Self&); //purposely not implemented\r
-\r
-    ImporterFilterPointer       m_Importer;\r
-    vtkImageExport            * m_Exporter;\r
-\r
-};\r
-\r
-} // end namespace itk\r
-\r
-#ifndef ITK_MANUAL_INSTANTIATION\r
-#include "itkVTKImageToImageFilter.txx"\r
-#endif\r
-\r
-#endif\r
-\r
-\r
-\r
+======================================================================-====*/
+#ifndef __itkVTKImageToImageFilter_h
+#define __itkVTKImageToImageFilter_h
+#include "itkVTKImageImport.h"
+#include "vtkImageExport.h"
+#include "vtkImageData.h"
+
+#ifndef vtkFloatingPointType
+#define vtkFloatingPointType float
+#endif
+
+namespace itk
+{
+
+/** \class VTKImageToImageFilter
+ * \brief Converts a VTK image into an ITK image and plugs a
+ *  vtk data pipeline to an ITK datapipeline.
+ *
+ *  This class puts together an itkVTKImageImporter and a vtkImageExporter.
+ *  It takes care of the details related to the connection of ITK and VTK
+ *  pipelines. The User will perceive this filter as an adaptor to which
+ *  a vtkImage can be plugged as input and an itk::Image is produced as
+ *  output.
+ *
+ * \ingroup   ImageFilters
+ */
+template <class TOutputImage >
+class ITK_EXPORT VTKImageToImageFilter : public ProcessObject
+{
+public:
+    /** Standard class typedefs. */
+    typedef VTKImageToImageFilter       Self;
+    typedef ProcessObject             Superclass;
+    typedef SmartPointer<Self>        Pointer;
+    typedef SmartPointer<const Self>  ConstPointer;
+
+    /** Method for creation through the object factory. */
+    itkNewMacro(Self);
+
+    /** Run-time type information (and related methods). */
+    itkTypeMacro(VTKImageToImageFilter, ProcessObject);
+
+    /** Some typedefs. */
+    typedef TOutputImage OutputImageType;
+    typedef typename    OutputImageType::ConstPointer    OutputImagePointer;
+    typedef VTKImageImport< OutputImageType >   ImporterFilterType;
+    typedef typename ImporterFilterType::Pointer         ImporterFilterPointer;
+
+    /** Get the output in the form of a vtkImage.
+        This call is delegated to the internal vtkImageImporter filter  */
+    //    const 
+    OutputImageType *  GetOutput() const;
+
+    /** Set the input in the form of a vtkImageData */
+    void SetInput( vtkImageData * );
+
+    /** Return the internal VTK image exporter filter.
+        This is intended to facilitate users the access
+        to methods in the exporter */
+    vtkImageExport * GetExporter() const;
+
+    /** Return the internal ITK image importer filter.
+        This is intended to facilitate users the access
+        to methods in the importer */
+    ImporterFilterType * GetImporter() const;
+
+    /** This call delegate the update to the importer */
+    void Update();
+
+protected:
+    VTKImageToImageFilter();
+    virtual ~VTKImageToImageFilter();
+
+private:
+    VTKImageToImageFilter(const Self&); //purposely not implemented
+    void operator=(const Self&); //purposely not implemented
+
+    ImporterFilterPointer       m_Importer;
+    vtkImageExport            * m_Exporter;
+
+};
+
+} // end namespace itk
+
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "itkVTKImageToImageFilter.txx"
+#endif
+
+#endif
+
+
+
index 27474df0254783d7f358407afeeec03a901bac8b..27a6595385a3fc2ef2daf2b8d36b318c0edc07e9 100644 (file)
@@ -3,7 +3,7 @@
 
   Authors belong to:
   - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://www.centreleonberard.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
@@ -14,7 +14,7 @@
 
   - BSD        See included LICENSE.txt file
   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
-===========================================================================**/
+======================================================================-====*/
 #ifndef _itkVTKImageToImageFilter_txx
 #define _itkVTKImageToImageFilter_txx
 #include "itkVTKImageToImageFilter.h"
@@ -86,7 +86,8 @@ VTKImageToImageFilter<TOutputImage>
  * Get an itk::Image as output
  */
 template <class TOutputImage>
-const typename VTKImageToImageFilter<TOutputImage>::OutputImageType *
+//const 
+typename VTKImageToImageFilter<TOutputImage>::OutputImageType *
 VTKImageToImageFilter<TOutputImage>
 ::GetOutput() const
 {
diff --git a/notes.org~ b/notes.org~
new file mode 100644 (file)
index 0000000..ec58a0b
--- /dev/null
@@ -0,0 +1,12 @@
+
+* GIT emacs command
+C-x v d 
+.gitignore -> contains ignored files
+commit (local)
+push (repository)
+pull
+
+* Test in temp
+git clone http://www.creatis.insa-lyon.fr/~dsarrut/clitk3.pub.git clitk3
+need itk4 (git) ?
+
index b3e22d2a0b84c5fb7445328bf02f5ee00d40d90e..75250cdab44293a310b8e7b36403075dbb524aa1 100644 (file)
@@ -43,9 +43,9 @@ IF(CLITK_BUILD_SEGMENTATION)
     ADD_EXECUTABLE(clitkExtractMediastinum clitkExtractMediastinum.cxx ${clitkExtractMediastinum_GGO_C})
     TARGET_LINK_LIBRARIES(clitkExtractMediastinum clitkCommon clitkSegmentationGgoLib ${ITK_LIBRARIES})
 
-    WRAP_GGO(clitkExtractLymphStations_GGO_C clitkExtractLymphStations.ggo)
-    ADD_EXECUTABLE(clitkExtractLymphStations clitkExtractLymphStations.cxx clitkFilterWithAnatomicalFeatureDatabaseManagement.cxx ${clitkExtractLymphStations_GGO_C})
-    # TARGET_LINK_LIBRARIES(clitkExtractLymphStations clitkSegmentationGgoLib clitkCommon ${ITK_LIBRARIES} ITKStatistics)
+    WRAP_GGO(clitkExtractLymphStations_GGO_C clitkExtractLymphStations.ggo)
+    ADD_EXECUTABLE(clitkExtractLymphStations clitkExtractLymphStations.cxx clitkFilterWithAnatomicalFeatureDatabaseManagement.cxx ${clitkExtractLymphStations_GGO_C})
+    TARGET_LINK_LIBRARIES(clitkExtractLymphStations clitkSegmentationGgoLib clitkCommon ITKIO ITKStatistics vtkHybrid)
 
     WRAP_GGO(clitkMorphoMath_GGO_C clitkMorphoMath.ggo)
     ADD_EXECUTABLE(clitkMorphoMath clitkMorphoMath.cxx ${clitkMorphoMath_GGO_C})
@@ -83,6 +83,10 @@ IF(CLITK_BUILD_SEGMENTATION)
     ADD_EXECUTABLE(clitkFillImageRegion clitkFillImageRegion.cxx clitkFillImageRegionGenericFilter.cxx ${clitkFillImageRegion_GGO_C})
     TARGET_LINK_LIBRARIES(clitkFillImageRegion clitkCommon ${ITK_LIBRARIES})
 
+    WRAP_GGO(clitkTestFilter_GGO_C clitkTestFilter.ggo)
+    ADD_EXECUTABLE(clitkTestFilter clitkTestFilter.cxx ${clitkTestFilter_GGO_C})
+    TARGET_LINK_LIBRARIES(clitkTestFilter clitkSegmentationGgoLib clitkCommon vtkHybrid ITKIO)
+
 ENDIF(CLITK_BUILD_SEGMENTATION)
 
 # ADD_EXECUTABLE(ScalarImageMarkovRandomField1 ScalarImageMarkovRandomField1.cxx)
diff --git a/segmentation/clitkExtractLymphStation_2RL.txx b/segmentation/clitkExtractLymphStation_2RL.txx
new file mode 100644 (file)
index 0000000..baa5730
--- /dev/null
@@ -0,0 +1,853 @@
+
+
+// vtk
+#include <vtkAppendPolyData.h>
+#include <vtkPolyDataWriter.h>
+#include <vtkCellArray.h>
+
+// clitk
+#include "clitkMeshToBinaryImageFilter.h"
+
+// itk
+#include <itkImageDuplicator.h>
+
+//--------------------------------------------------------------------
+template<class PointType>
+class comparePointsX {
+public:
+  bool operator() (PointType i, PointType j) { return (i[0]<j[0]); }
+};
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template<class PairType>
+class comparePointsWithAngle {
+public:
+  bool operator() (PairType i, PairType j) { return (i.second < j.second); } 
+};
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template<int Dim>
+void HypercubeCorners(std::vector<itk::Point<double, Dim> > & out) {
+  std::vector<itk::Point<double, Dim-1> > previous;
+  HypercubeCorners<Dim-1>(previous);
+  out.resize(previous.size()*2);
+  for(uint i=0; i<out.size(); i++) {
+    itk::Point<double, Dim> p;
+    if (i<previous.size()) p[0] = 0; 
+    else p[0] = 1;
+    for(int j=0; j<Dim-1; j++) 
+      {
+        p[j+1] = previous[i%previous.size()][j];
+      }
+    out[i] = p;
+  }
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template<>
+void HypercubeCorners<1>(std::vector<itk::Point<double, 1> > & out) {
+  out.resize(2);
+  out[0][0] = 0;
+  out[1][0] = 1;
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template<class ImageType>
+void ComputeImageBoundariesCoordinates(typename ImageType::Pointer image, 
+                                       std::vector<typename ImageType::PointType> & bounds) 
+{
+  // Get image max/min coordinates
+  const uint dim=ImageType::ImageDimension;
+  typedef typename ImageType::PointType PointType;
+  typedef typename ImageType::IndexType IndexType;
+  PointType min_c, max_c;
+  IndexType min_i, max_i;
+  min_i = image->GetLargestPossibleRegion().GetIndex();
+  for(uint i=0; i<dim; i++) max_i[i] = image->GetLargestPossibleRegion().GetSize()[i] + min_i[i];
+  image->TransformIndexToPhysicalPoint(min_i, min_c);
+  image->TransformIndexToPhysicalPoint(max_i, max_c);
+  
+  // Get corners coordinates
+  HypercubeCorners<ImageType::ImageDimension>(bounds);
+  for(uint i=0; i<bounds.size(); i++) {
+    for(uint j=0; j<dim; j++) {
+      if (bounds[i][j] == 0) bounds[i][j] = min_c[j];
+      if (bounds[i][j] == 1) bounds[i][j] = max_c[j];
+    }
+  }
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void 
+clitk::ExtractLymphStationsFilter<ImageType>::
+ExtractStation_2RL_SetDefaultValues()
+{
+  SetFuzzyThreshold("2RL", "CommonCarotidArtery", 0.7);
+  SetFuzzyThreshold("2RL", "BrachioCephalicTrunk", 0.7);
+  SetFuzzyThreshold("2RL", "BrachioCephalicVein", 0.3);
+  SetFuzzyThreshold("2RL", "Aorta", 0.7);
+  SetFuzzyThreshold("2RL", "SubclavianArteryRight", 0.5);
+  SetFuzzyThreshold("2RL", "SubclavianArteryLeft", 0.8);
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void 
+clitk::ExtractLymphStationsFilter<ImageType>::
+ExtractStation_2RL_SI_Limits() 
+{
+  // Apex of the chest or Sternum & Carina.
+  StartNewStep("[Station 2RL] Inf/Sup limits with Sternum and TopOfAorticArch/CaudalMarginOfLeftBrachiocephalicVein");
+
+  /* Rod says: "For the inferior border, unlike in Atlas – UM, there
+   is now a difference between 2R and 2L.  2R stops at the
+   intersection of the caudal margin of the innominate vein with the
+   trachea.  2L extends less inferiorly to the superior border of the
+   aortic arch." */
+
+  /* Get TopOfAorticArch and CaudalMarginOfLeftBrachiocephalicVein 
+     - TopOfAorticArch -> can be obtain from Aorta -> most sup part.  
+     - CaudalMarginOfLeftBrachiocephalicVein -> must inf part of BrachicephalicVein
+   */
+  MaskImagePointer Aorta = GetAFDB()->template GetImage<MaskImageType>("Aorta");
+  MaskImagePointType p = Aorta->GetOrigin(); // initialise to avoid warning 
+  clitk::FindExtremaPointInAGivenDirection<MaskImageType>(Aorta, GetBackgroundValue(), 2, false, p);
+  double TopOfAorticArchZ=p[2];
+  GetAFDB()->SetDouble("TopOfAorticArchZ", TopOfAorticArchZ);
+
+  MaskImagePointer BrachioCephalicVein = GetAFDB()->template GetImage<MaskImageType>("BrachioCephalicVein");
+  clitk::FindExtremaPointInAGivenDirection<MaskImageType>(BrachioCephalicVein, GetBackgroundValue(), 2, true, p);
+  double CaudalMarginOfLeftBrachiocephalicVeinZ=p[2];
+  GetAFDB()->SetDouble("CaudalMarginOfLeftBrachiocephalicVeinZ", CaudalMarginOfLeftBrachiocephalicVeinZ);
+  
+  // First, cut on the most inferior part. Add one slice because this
+  // inf slice should not be included.
+  double inf = std::min(CaudalMarginOfLeftBrachiocephalicVeinZ, TopOfAorticArchZ) + m_Working_Support->GetSpacing()[2];
+
+  // Get Sternum and search for the upper position
+  MaskImagePointer Sternum = GetAFDB()->template GetImage<MaskImageType>("Sternum");
+
+  // Search most sup point
+  clitk::FindExtremaPointInAGivenDirection<MaskImageType>(Sternum, GetBackgroundValue(), 2, false, p);
+  double m_SternumZ = p[2];
+  // +Sternum->GetSpacing()[2]; // One more slice, because it is below this point // NOT HERE ?? WHY DIFFERENT FROM 3A ??
+
+  //* Crop support :
+  m_Working_Support = 
+    clitk::CropImageAlongOneAxis<MaskImageType>(m_Working_Support, 2, 
+                                                inf, m_SternumZ, true,
+                                                GetBackgroundValue());
+
+  StopCurrentStep<MaskImageType>(m_Working_Support);
+  m_ListOfStations["2R"] = m_Working_Support;
+  m_ListOfStations["2L"] = m_Working_Support;
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void 
+clitk::ExtractLymphStationsFilter<ImageType>::
+ExtractStation_2RL_Ant_Limits() 
+{
+  // -----------------------------------------------------
+  /* Rod says: "The anterior border, as with the Atlas – UM, is
+    posterior to the vessels (right subclavian vein, left
+    brachiocephalic vein, right brachiocephalic vein, left subclavian
+    artery, left common carotid artery and brachiocephalic trunk).
+    These vessels are not included in the nodal station.  The anterior
+    border is drawn to the midpoint of the vessel and an imaginary
+    line joins the middle of these vessels.  Between the vessels,
+    station 2 is in contact with station 3a." */
+
+  // -----------------------------------------------------
+  StartNewStep("[Station 2RL] Ant limits with CommonCarotidArtery");
+
+  // Get CommonCarotidArtery
+  MaskImagePointer CommonCarotidArtery = GetAFDB()->template GetImage<MaskImageType>("CommonCarotidArtery");
+  
+  // Remove Ant to CommonCarotidArtery
+  typedef SliceBySliceRelativePositionFilter<MaskImageType> SliceRelPosFilterType;
+  typename SliceRelPosFilterType::Pointer sliceRelPosFilter = SliceRelPosFilterType::New();
+  sliceRelPosFilter->VerboseStepFlagOff();
+  sliceRelPosFilter->WriteStepFlagOff();
+  sliceRelPosFilter->SetInput(m_Working_Support);
+  sliceRelPosFilter->SetInputObject(CommonCarotidArtery);
+  sliceRelPosFilter->SetDirection(2);
+  sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThreshold("2RL", "CommonCarotidArtery"));
+  sliceRelPosFilter->AddOrientationTypeString("NotAntTo");
+  sliceRelPosFilter->IntermediateSpacingFlagOn();
+  sliceRelPosFilter->SetIntermediateSpacing(2);
+  sliceRelPosFilter->UniqueConnectedComponentBySliceOff();
+  sliceRelPosFilter->UseASingleObjectConnectedComponentBySliceFlagOff();
+  sliceRelPosFilter->AutoCropFlagOn(); 
+  sliceRelPosFilter->IgnoreEmptySliceObjectFlagOn();
+  sliceRelPosFilter->RemoveObjectFlagOff();
+  sliceRelPosFilter->Update();
+  m_Working_Support = sliceRelPosFilter->GetOutput();
+
+  // End
+  StopCurrentStep<MaskImageType>(m_Working_Support);
+  m_ListOfStations["2R"] = m_Working_Support;
+  m_ListOfStations["2L"] = m_Working_Support;
+
+  // -----------------------------------------------------
+  // Remove Ant to H line from the Ant most part of the
+  // CommonCarotidArtery until we reach the first slice of
+  // BrachioCephalicTrunk
+  StartNewStep("[Station 2RL] Ant limits with CommonCarotidArtery, H line");
+
+  // First, find the first slice of BrachioCephalicTrunk
+  MaskImagePointer BrachioCephalicTrunk = GetAFDB()->template GetImage<MaskImageType>("BrachioCephalicTrunk");
+  MaskImagePointType p = BrachioCephalicTrunk->GetOrigin(); // initialise to avoid warning 
+  clitk::FindExtremaPointInAGivenDirection<MaskImageType>(BrachioCephalicTrunk, GetBackgroundValue(), 2, false, p);
+  double TopOfBrachioCephalicTrunkZ=p[2] + BrachioCephalicTrunk->GetSpacing()[2]; // Add one slice
+
+  // Remove CommonCarotidArtery below this point
+  CommonCarotidArtery = clitk::CropImageBelow<MaskImageType>(CommonCarotidArtery, 2, TopOfBrachioCephalicTrunkZ, true, GetBackgroundValue());  
+
+  // Find most Ant points
+  std::vector<MaskImagePointType> ccaAntPositionA;
+  std::vector<MaskImagePointType> ccaAntPositionB;
+  clitk::SliceBySliceBuildLineSegmentAccordingToExtremaPosition<MaskImageType>(CommonCarotidArtery, 
+                                                                               GetBackgroundValue(), 2,
+                                                                               1, true, // Ant
+                                                                               0, // Horizontal line
+                                                                               -3, // margin
+                                                                               ccaAntPositionA, 
+                                                                               ccaAntPositionB);
+  // Cut ant to this line
+  clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_Working_Support, 
+                                                                    ccaAntPositionA,
+                                                                    ccaAntPositionB,
+                                                                    GetBackgroundValue(), 1, 10); 
+
+  // End
+  StopCurrentStep<MaskImageType>(m_Working_Support);
+  m_ListOfStations["2R"] = m_Working_Support;
+  m_ListOfStations["2L"] = m_Working_Support;
+
+  // -----------------------------------------------------
+  // Ant limit with the BrachioCephalicTrunk
+  StartNewStep("[Station 2RL] Ant limits with BrachioCephalicTrunk line");
+
+  // Remove Ant to BrachioCephalicTrunk
+  m_Working_Support = 
+    clitk::SliceBySliceRelativePosition<MaskImageType>(m_Working_Support, BrachioCephalicTrunk, 2, 
+                                                       GetFuzzyThreshold("2RL", "BrachioCephalicTrunk"), "NotAntTo", false, 2, true, false);
+  // End
+  StopCurrentStep<MaskImageType>(m_Working_Support);
+  m_ListOfStations["2R"] = m_Working_Support;
+  m_ListOfStations["2L"] = m_Working_Support;
+
+  // -----------------------------------------------------
+  // Ant limit with the BrachioCephalicTrunk H line
+  StartNewStep("[Station 2RL] Ant limits with BrachioCephalicTrunk, Horizontal line");
+  
+  // Find most Ant points
+  std::vector<MaskImagePointType> bctAntPositionA;
+  std::vector<MaskImagePointType> bctAntPositionB;
+  clitk::SliceBySliceBuildLineSegmentAccordingToExtremaPosition<MaskImageType>(BrachioCephalicTrunk, 
+                                                                               GetBackgroundValue(), 2,
+                                                                               1, true, // Ant
+                                                                               0, // Horizontal line
+                                                                               -1, // margin
+                                                                               bctAntPositionA, 
+                                                                               bctAntPositionB);
+  // Cut ant to this line
+  clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_Working_Support, 
+                                                                    bctAntPositionA,
+                                                                    bctAntPositionB,
+                                                                    GetBackgroundValue(), 1, 10); 
+ // End
+  StopCurrentStep<MaskImageType>(m_Working_Support);
+  m_ListOfStations["2R"] = m_Working_Support;
+  m_ListOfStations["2L"] = m_Working_Support;
+
+  // -----------------------------------------------------
+  // Ant limit with the BrachioCephalicVein
+  StartNewStep("[Station 2RL] Ant limits with BrachioCephalicVein");
+
+  // Remove Ant to BrachioCephalicVein
+  MaskImagePointer BrachioCephalicVein = GetAFDB()->template GetImage<MaskImageType>("BrachioCephalicVein");
+  m_Working_Support = 
+    clitk::SliceBySliceRelativePosition<MaskImageType>(m_Working_Support, BrachioCephalicVein, 2, 
+                                                       GetFuzzyThreshold("2RL", "BrachioCephalicVein"), "NotAntTo", false, 2, true, false);
+  // End
+  StopCurrentStep<MaskImageType>(m_Working_Support);
+  m_ListOfStations["2R"] = m_Working_Support;
+  m_ListOfStations["2L"] = m_Working_Support;
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void 
+clitk::ExtractLymphStationsFilter<ImageType>::
+ExtractStation_2RL_Ant_Limits2() 
+{
+  // -----------------------------------------------------
+  /* Rod says: "The anterior border, as with the Atlas – UM, is
+    posterior to the vessels (right subclavian vein, left
+    brachiocephalic vein, right brachiocephalic vein, left subclavian
+    artery, left common carotid artery and brachiocephalic trunk).
+    These vessels are not included in the nodal station.  The anterior
+    border is drawn to the midpoint of the vessel and an imaginary
+    line joins the middle of these vessels.  Between the vessels,
+    station 2 is in contact with station 3a." */
+
+  // -----------------------------------------------------
+  StartNewStep("[Station 2RL] Ant limits with vessels centroids");
+
+  /* Here, we consider the vessels form a kind of anterior barrier. We
+     link all vessels centroids and remove what is post to it.
+    - select the list of structure
+            vessel1 = BrachioCephalicTrunk
+            vessel2 = BrachioCephalicVein (warning several CCL, keep most at Right)
+            vessel3 = CommonCarotidArtery
+            vessel4 = SubclavianArtery
+            other   = Thyroid
+            other   = Aorta 
+     - crop images as needed
+     - slice by slice, choose the CCL and extract centroids
+     - slice by slice, sort according to polar angle wrt Trachea centroid.
+     - slice by slice, link centroids and close contour
+     - remove outside this contour
+     - merge with support 
+  */
+
+  // Read structures
+  MaskImagePointer BrachioCephalicTrunk = GetAFDB()->template GetImage<MaskImageType>("BrachioCephalicTrunk");
+  MaskImagePointer BrachioCephalicVein = GetAFDB()->template GetImage<MaskImageType>("BrachioCephalicVein");
+  MaskImagePointer CommonCarotidArtery = GetAFDB()->template GetImage<MaskImageType>("CommonCarotidArtery");
+  MaskImagePointer SubclavianArtery = GetAFDB()->template GetImage<MaskImageType>("SubclavianArtery");
+  MaskImagePointer Thyroid = GetAFDB()->template GetImage<MaskImageType>("Thyroid");
+  MaskImagePointer Aorta = GetAFDB()->template GetImage<MaskImageType>("Aorta");
+  MaskImagePointer Trachea = GetAFDB()->template GetImage<MaskImageType>("Trachea");
+  
+  // Resize all structures like support
+  BrachioCephalicTrunk = 
+    clitk::ResizeImageLike<MaskImageType>(BrachioCephalicTrunk, m_Working_Support, GetBackgroundValue());
+  CommonCarotidArtery = 
+    clitk::ResizeImageLike<MaskImageType>(CommonCarotidArtery, m_Working_Support, GetBackgroundValue());
+  SubclavianArtery = 
+    clitk::ResizeImageLike<MaskImageType>(SubclavianArtery, m_Working_Support, GetBackgroundValue());
+  Thyroid = 
+    clitk::ResizeImageLike<MaskImageType>(Thyroid, m_Working_Support, GetBackgroundValue());
+  Aorta = 
+    clitk::ResizeImageLike<MaskImageType>(Aorta, m_Working_Support, GetBackgroundValue());
+  BrachioCephalicVein = 
+    clitk::ResizeImageLike<MaskImageType>(BrachioCephalicVein, m_Working_Support, GetBackgroundValue());
+  Trachea = 
+    clitk::ResizeImageLike<MaskImageType>(Trachea, m_Working_Support, GetBackgroundValue());
+
+  // Extract slices
+  std::vector<MaskSlicePointer> slices_BrachioCephalicTrunk;
+  clitk::ExtractSlices<MaskImageType>(BrachioCephalicTrunk, 2, slices_BrachioCephalicTrunk);
+  std::vector<MaskSlicePointer> slices_BrachioCephalicVein;
+  clitk::ExtractSlices<MaskImageType>(BrachioCephalicVein, 2, slices_BrachioCephalicVein);
+  std::vector<MaskSlicePointer> slices_CommonCarotidArtery;
+  clitk::ExtractSlices<MaskImageType>(CommonCarotidArtery, 2, slices_CommonCarotidArtery);
+  std::vector<MaskSlicePointer> slices_SubclavianArtery;
+  clitk::ExtractSlices<MaskImageType>(SubclavianArtery, 2, slices_SubclavianArtery);
+  std::vector<MaskSlicePointer> slices_Thyroid;
+  clitk::ExtractSlices<MaskImageType>(Thyroid, 2, slices_Thyroid);
+  std::vector<MaskSlicePointer> slices_Aorta;
+  clitk::ExtractSlices<MaskImageType>(Aorta, 2, slices_Aorta);
+  std::vector<MaskSlicePointer> slices_Trachea;
+  clitk::ExtractSlices<MaskImageType>(Trachea, 2, slices_Trachea);
+  uint n= slices_BrachioCephalicTrunk.size();
+  
+  // Get the boundaries of one slice
+  std::vector<MaskSlicePointType> bounds;
+  ComputeImageBoundariesCoordinates<MaskSliceType>(slices_BrachioCephalicTrunk[0], bounds);
+
+  // For all slices, for all structures, find the centroid and build the contour
+  // List of 3D points (for debug)
+  std::vector<MaskImagePointType> p3D;
+
+  vtkSmartPointer<vtkAppendPolyData> append = vtkSmartPointer<vtkAppendPolyData>::New();
+  for(uint i=0; i<n; i++) {
+    // Labelize the slices
+    slices_CommonCarotidArtery[i] = Labelize<MaskSliceType>(slices_CommonCarotidArtery[i], 
+                                                            GetBackgroundValue(), true, 1);
+    slices_SubclavianArtery[i] = Labelize<MaskSliceType>(slices_SubclavianArtery[i], 
+                                                         GetBackgroundValue(), true, 1);
+    slices_BrachioCephalicTrunk[i] = Labelize<MaskSliceType>(slices_BrachioCephalicTrunk[i], 
+                                                             GetBackgroundValue(), true, 1);
+    slices_BrachioCephalicVein[i] = Labelize<MaskSliceType>(slices_BrachioCephalicVein[i], 
+                                                            GetBackgroundValue(), true, 1);
+    slices_Thyroid[i] = Labelize<MaskSliceType>(slices_Thyroid[i], 
+                                                GetBackgroundValue(), true, 1);
+    slices_Aorta[i] = Labelize<MaskSliceType>(slices_Aorta[i], 
+                                              GetBackgroundValue(), true, 1);
+
+    // Search centroids
+    std::vector<MaskSlicePointType> points2D;
+    std::vector<MaskSlicePointType> centroids1;
+    std::vector<MaskSlicePointType> centroids2;
+    std::vector<MaskSlicePointType> centroids3;
+    std::vector<MaskSlicePointType> centroids4;
+    std::vector<MaskSlicePointType> centroids5;
+    std::vector<MaskSlicePointType> centroids6;
+    ComputeCentroids<MaskSliceType>(slices_CommonCarotidArtery[i], GetBackgroundValue(), centroids1);
+    ComputeCentroids<MaskSliceType>(slices_SubclavianArtery[i], GetBackgroundValue(), centroids2);
+    ComputeCentroids<MaskSliceType>(slices_BrachioCephalicTrunk[i], GetBackgroundValue(), centroids3);
+    ComputeCentroids<MaskSliceType>(slices_Thyroid[i], GetBackgroundValue(), centroids4);
+    ComputeCentroids<MaskSliceType>(slices_Aorta[i], GetBackgroundValue(), centroids5);
+    ComputeCentroids<MaskSliceType>(slices_BrachioCephalicVein[i], GetBackgroundValue(), centroids6);
+
+    // BrachioCephalicVein -> when it is separated into two CCL, we
+    // only consider the most at Right one
+    if (centroids6.size() > 2) {
+      if (centroids6[1][0] < centroids6[2][0]) centroids6.erase(centroids6.begin()+2);
+      else centroids6.erase(centroids6.begin()+1);
+    }
+    
+    // BrachioCephalicVein -> when SubclavianArtery has 2 CCL
+    // (BrachioCephalicTrunk is divided) -> forget BrachioCephalicVein
+    if ((centroids3.size() ==1) && (centroids2.size() > 2)) {
+      centroids6.clear();
+    }
+
+    for(uint j=1; j<centroids1.size(); j++) points2D.push_back(centroids1[j]);
+    for(uint j=1; j<centroids2.size(); j++) points2D.push_back(centroids2[j]);
+    for(uint j=1; j<centroids3.size(); j++) points2D.push_back(centroids3[j]);
+    for(uint j=1; j<centroids4.size(); j++) points2D.push_back(centroids4[j]);
+    for(uint j=1; j<centroids5.size(); j++) points2D.push_back(centroids5[j]);
+    for(uint j=1; j<centroids6.size(); j++) points2D.push_back(centroids6[j]);
+    
+    // Sort by angle according to trachea centroid and vertical line,
+    // in polar coordinates :
+    // http://en.wikipedia.org/wiki/Polar_coordinate_system
+    std::vector<MaskSlicePointType> centroids_trachea;
+    ComputeCentroids<MaskSliceType>(slices_Trachea[i], GetBackgroundValue(), centroids_trachea);
+    typedef std::pair<MaskSlicePointType, double> PointAngleType;
+    std::vector<PointAngleType> angles;
+    for(uint j=0; j<points2D.size(); j++) {
+      //double r = centroids_trachea[1].EuclideanDistanceTo(points2D[j]);
+      double x = (points2D[j][0]-centroids_trachea[1][0]); // X : Right to Left
+      double y = (centroids_trachea[1][1]-points2D[j][1]); // Y : Post to Ant
+      double angle = 0;
+      if (x>0) angle = atan(y/x);
+      if ((x<0) && (y>=0)) angle = atan(y/x)+M_PI;
+      if ((x<0) && (y<0)) angle = atan(y/x)-M_PI;
+      if (x==0) {
+        if (y>0) angle = M_PI/2.0;
+        if (y<0) angle = -M_PI/2.0;
+        if (y==0) angle = 0;
+      }
+      angle = clitk::rad2deg(angle);
+      // Angle is [-180;180] wrt the X axis. We change the X axis to
+      // be the vertical line, because we want to sort from Right to
+      // Left from Post to Ant.
+      if (angle>0) 
+        angle = (270-angle);
+      if (angle<0) {
+        angle = -angle-90;
+        if (angle<0) angle = 360-angle;
+      }
+      PointAngleType a;
+      a.first = points2D[j];
+      a.second = angle;
+      angles.push_back(a);
+    }
+
+    // Do nothing if less than 2 points --> n
+    if (points2D.size() < 3) { //continue;
+      continue;
+    }
+
+    // Sort points2D according to polar angles
+    std::sort(angles.begin(), angles.end(), comparePointsWithAngle<PointAngleType>());
+    for(uint j=0; j<angles.size(); j++) {
+      points2D[j] = angles[j].first;
+    }
+    //    DDV(points2D, points2D.size());
+
+    /* When vessels are far away, we try to replace the line segment
+       with a curved line that join the two vessels but stay
+       approximately at the same distance from the trachea centroids
+       than the vessels.
+
+       For that: 
+       - let a and c be two successive vessels centroids
+       - id distance(a,c) < threshold, next point
+
+       TODO HERE
+       
+       - compute mid position between two successive points -
+       compute dist to trachea centroid for the 3 pts - if middle too
+       low, add one point
+    */
+    std::vector<MaskSlicePointType> toadd;
+    uint index = 0;
+    double dmax = 5;
+    while (index<points2D.size()-1) {
+      MaskSlicePointType a = points2D[index];
+      MaskSlicePointType c = points2D[index+1];
+
+      double dac = a.EuclideanDistanceTo(c);
+      if (dac>dmax) {
+        
+        MaskSlicePointType b;
+        b[0] = a[0]+(c[0]-a[0])/2.0;
+        b[1] = a[1]+(c[1]-a[1])/2.0;
+        
+        // Compute distance to trachea centroid
+        MaskSlicePointType m = centroids_trachea[1];
+        double da = m.EuclideanDistanceTo(a);
+        double db = m.EuclideanDistanceTo(b);
+        //double dc = m.EuclideanDistanceTo(c);
+        
+        // Mean distance, find point on the line from trachea centroid
+        // to b
+        double alpha = (da+db)/2.0;
+        MaskSlicePointType v;
+        double n = sqrt( pow(b[0]-m[0], 2) + pow(b[1]-m[1], 2));
+        v[0] = (b[0]-m[0])/n;
+        v[1] = (b[1]-m[1])/n;
+        MaskSlicePointType r;
+        r[0] = m[0]+alpha*v[0];
+        r[1] = m[1]+alpha*v[1];
+        points2D.insert(points2D.begin()+index+1, r);
+      }
+      else {
+        index++;
+      }
+    }
+    //    DDV(points2D, points2D.size());
+
+    // Add some points to close the contour 
+    // - H line towards Right
+    MaskSlicePointType p = points2D[0]; 
+    p[0] = bounds[0][0];
+    points2D.insert(points2D.begin(), p);
+    // - corner Right/Post
+    p = bounds[0];
+    points2D.insert(points2D.begin(), p);
+    // - H line towards Left
+    p = points2D.back(); 
+    p[0] = bounds[2][0];
+    points2D.push_back(p);
+    // - corner Right/Post
+    p = bounds[2];
+    points2D.push_back(p);
+    // Close contour with the first point
+    points2D.push_back(points2D[0]);
+    //    DDV(points2D, points2D.size());
+      
+    // Build 3D points from the 2D points
+    std::vector<ImagePointType> points3D;
+    clitk::PointsUtils<MaskImageType>::Convert2DListTo3DList(points2D, i, m_Working_Support, points3D);
+    for(uint x=0; x<points3D.size(); x++) p3D.push_back(points3D[x]);
+
+    // Build the mesh from the contour's points
+    vtkSmartPointer<vtkPolyData> mesh = Build3DMeshFrom2DContour(points3D);
+    append->AddInput(mesh);
+  }
+
+  // DEBUG: write points3D
+  clitk::WriteListOfLandmarks<MaskImageType>(p3D, "vessels-centroids.txt");
+
+  // Build the final 3D mesh form the list 2D mesh
+  append->Update();
+  vtkSmartPointer<vtkPolyData> mesh = append->GetOutput();
+  
+  // Debug, write the mesh
+  /*
+    vtkSmartPointer<vtkPolyDataWriter> w = vtkSmartPointer<vtkPolyDataWriter>::New();
+    w->SetInput(mesh);
+    w->SetFileName("bidon.vtk");
+    w->Write();    
+  */
+  
+  // Compute a single binary 3D image from the list of contours
+  clitk::MeshToBinaryImageFilter<MaskImageType>::Pointer filter = 
+    clitk::MeshToBinaryImageFilter<MaskImageType>::New();
+  filter->SetMesh(mesh);
+  filter->SetLikeImage(m_Working_Support);
+  filter->Update();
+  MaskImagePointer binarizedContour = filter->GetOutput();  
+  
+  // Inverse binary mask if needed. We test a point that we know must be in FG. If it is not, inverse
+  ImagePointType p = p3D[2]; // This is the first centroid of the first slice
+  p[1] += 50; // 50 mm Post from this point must be kept
+  ImageIndexType index;
+  binarizedContour->TransformPhysicalPointToIndex(p, index);
+  bool isInside = (binarizedContour->GetPixel(index) != GetBackgroundValue());
+
+  // remove from support
+  typedef clitk::BooleanOperatorLabelImageFilter<MaskImageType> BoolFilterType;
+  typename BoolFilterType::Pointer boolFilter = BoolFilterType::New(); 
+  boolFilter->InPlaceOn();
+  boolFilter->SetInput1(m_Working_Support);
+  boolFilter->SetInput2(binarizedContour);
+  boolFilter->SetBackgroundValue1(GetBackgroundValue());
+  boolFilter->SetBackgroundValue2(GetBackgroundValue());
+  if (isInside)
+    boolFilter->SetOperationType(BoolFilterType::And);
+  else
+    boolFilter->SetOperationType(BoolFilterType::AndNot);
+  boolFilter->Update();
+  m_Working_Support = boolFilter->GetOutput();
+
+  // End
+  StopCurrentStep<MaskImageType>(m_Working_Support);
+  m_ListOfStations["2R"] = m_Working_Support;
+  m_ListOfStations["2L"] = m_Working_Support;
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void 
+clitk::ExtractLymphStationsFilter<ImageType>::
+ExtractStation_2RL_Post_Limits() 
+{
+  StartNewStep("[Station 2RL] Post limits with post wall of Trachea");
+
+  // Get Trachea
+  MaskImagePointer Trachea = GetAFDB()->template GetImage<MaskImageType>("Trachea");
+  
+  // Resize like the current support (to have the same number of slices)
+  Trachea = clitk::ResizeImageLike<MaskImageType>(Trachea, m_Working_Support, GetBackgroundValue());
+
+  // Find extrema post positions
+  std::vector<MaskImagePointType> tracheaPostPositionsA;
+  std::vector<MaskImagePointType> tracheaPostPositionsB;
+  clitk::SliceBySliceBuildLineSegmentAccordingToExtremaPosition<MaskImageType>(Trachea, 
+                                                                               GetBackgroundValue(), 2, 
+                                                                               1, false, // Post
+                                                                               0, // Horizontal line 
+                                                                               1, 
+                                                                               tracheaPostPositionsA, 
+                                                                               tracheaPostPositionsB);
+  // Cut post to this line
+  clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_Working_Support, 
+                                                                    tracheaPostPositionsA,
+                                                                    tracheaPostPositionsB,
+                                                                    GetBackgroundValue(), 1, -10); 
+  // END
+  StopCurrentStep<MaskImageType>(m_Working_Support);
+  m_ListOfStations["2R"] = m_Working_Support;
+  m_ListOfStations["2L"] = m_Working_Support;
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+// Build a vtk mesh from a list of slice number/closed-contours
+template <class ImageType>
+vtkSmartPointer<vtkPolyData> 
+clitk::ExtractLymphStationsFilter<ImageType>::
+Build3DMeshFrom2DContour(const std::vector<ImagePointType> & points)
+{
+  // create a contour, polydata. 
+  vtkSmartPointer<vtkPolyData> mesh = vtkSmartPointer<vtkPolyData>::New();
+  mesh->Allocate(); //for cell structures
+  mesh->SetPoints(vtkPoints::New());
+  vtkIdType ids[2];
+  int point_number = points.size();
+  for (unsigned int i=0; i<points.size(); i++) {
+    mesh->GetPoints()->InsertNextPoint(points[i][0],points[i][1],points[i][2]);
+    ids[0]=i;
+    ids[1]=(ids[0]+1)%point_number; //0-1,1-2,...,n-1-0
+    mesh->GetLines()->InsertNextCell(2,ids);
+  }
+  // Return
+  return mesh;
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void
+clitk::ExtractLymphStationsFilter<ImageType>::
+ExtractStation_2RL_LR_Limits()
+{
+  // ---------------------------------------------------------------------------
+  StartNewStep("[Station 2RL] Left/Right limits with Aorta");
+  MaskImagePointer Aorta = GetAFDB()->template GetImage<MaskImageType>("Aorta");
+  //  DD(GetFuzzyThreshold("2RL", "BrachioCephalicVein"));
+  m_Working_Support = 
+    clitk::SliceBySliceRelativePosition<MaskImageType>(m_Working_Support, Aorta, 2, 
+                                                       GetFuzzyThreshold("2RL", "Aorta"),
+                                                       "RightTo", false, 2, true, false);  
+  // END
+  StopCurrentStep<MaskImageType>(m_Working_Support);
+  m_ListOfStations["2R"] = m_Working_Support;
+  m_ListOfStations["2L"] = m_Working_Support;
+
+  // ---------------------------------------------------------------------------
+  StartNewStep("[Station 2RL] Left/Right limits with SubclavianArtery (Right)");
+  
+  // SliceBySliceRelativePosition + select CCL most at Right
+  MaskImagePointer SubclavianArtery = GetAFDB()->template GetImage<MaskImageType>("SubclavianArtery");
+  typedef SliceBySliceRelativePositionFilter<MaskImageType> SliceRelPosFilterType;
+  typename SliceRelPosFilterType::Pointer sliceRelPosFilter = SliceRelPosFilterType::New();
+  sliceRelPosFilter->VerboseStepFlagOff();
+  sliceRelPosFilter->WriteStepFlagOff();
+  sliceRelPosFilter->SetInput(m_Working_Support);
+  sliceRelPosFilter->SetInputObject(SubclavianArtery);
+  sliceRelPosFilter->SetDirection(2);
+  sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThreshold("2RL", "SubclavianArteryRight"));
+  sliceRelPosFilter->AddOrientationTypeString("NotRightTo");
+  sliceRelPosFilter->IntermediateSpacingFlagOn();
+  sliceRelPosFilter->SetIntermediateSpacing(2);
+  sliceRelPosFilter->UniqueConnectedComponentBySliceOff();
+  sliceRelPosFilter->UseASingleObjectConnectedComponentBySliceFlagOff();
+
+  sliceRelPosFilter->CCLSelectionFlagOn(); // select one CCL by slice
+  sliceRelPosFilter->SetCCLSelectionDimension(0); // select according to X (0) axis
+  sliceRelPosFilter->SetCCLSelectionDirection(-1); // select most at Right
+  sliceRelPosFilter->CCLSelectionIgnoreSingleCCLFlagOn(); // ignore if only one CCL
+
+  sliceRelPosFilter->AutoCropFlagOn(); 
+  sliceRelPosFilter->IgnoreEmptySliceObjectFlagOn();
+  sliceRelPosFilter->RemoveObjectFlagOff();
+  sliceRelPosFilter->Update();
+  m_Working_Support = sliceRelPosFilter->GetOutput();
+
+  // END
+  StopCurrentStep<MaskImageType>(m_Working_Support);
+  m_ListOfStations["2R"] = m_Working_Support;
+  m_ListOfStations["2L"] = m_Working_Support;
+
+
+  // ---------------------------------------------------------------------------
+  StartNewStep("[Station 2RL] Left/Right limits with SubclavianArtery (Left)");
+  
+  // SliceBySliceRelativePosition + select CCL most at Right
+   sliceRelPosFilter = SliceRelPosFilterType::New();
+  sliceRelPosFilter->VerboseStepFlagOff();
+  sliceRelPosFilter->WriteStepFlagOff();
+  sliceRelPosFilter->SetInput(m_Working_Support);
+  sliceRelPosFilter->SetInputObject(SubclavianArtery);
+  sliceRelPosFilter->SetDirection(2);
+  sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThreshold("2RL", "SubclavianArteryLeft"));
+  sliceRelPosFilter->AddOrientationTypeString("NotLeftTo");
+  sliceRelPosFilter->IntermediateSpacingFlagOn();
+  sliceRelPosFilter->SetIntermediateSpacing(2);
+  sliceRelPosFilter->UniqueConnectedComponentBySliceOff();
+  sliceRelPosFilter->UseASingleObjectConnectedComponentBySliceFlagOff();
+
+  sliceRelPosFilter->CCLSelectionFlagOn(); // select one CCL by slice
+  sliceRelPosFilter->SetCCLSelectionDimension(0); // select according to X (0) axis
+  sliceRelPosFilter->SetCCLSelectionDirection(+1); // select most at Left
+  sliceRelPosFilter->CCLSelectionIgnoreSingleCCLFlagOff(); // do not ignore if only one CCL
+
+  sliceRelPosFilter->AutoCropFlagOn(); 
+  sliceRelPosFilter->IgnoreEmptySliceObjectFlagOn();
+  sliceRelPosFilter->RemoveObjectFlagOff();
+  sliceRelPosFilter->Update();
+  m_Working_Support = sliceRelPosFilter->GetOutput();
+
+  // END
+  StopCurrentStep<MaskImageType>(m_Working_Support);
+  m_ListOfStations["2R"] = m_Working_Support;
+  m_ListOfStations["2L"] = m_Working_Support;
+}
+//--------------------------------------------------------------------
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void
+clitk::ExtractLymphStationsFilter<ImageType>::
+ExtractStation_2RL_Remove_Structures()
+{
+  Remove_Structures("2RL", "BrachioCephalicVein");
+  Remove_Structures("2RL", "CommonCarotidArtery");
+  Remove_Structures("2RL", "SubclavianArtery");
+  Remove_Structures("2RL", "Thyroid");
+  Remove_Structures("2RL", "Aorta");
+  
+  // END
+  StopCurrentStep<MaskImageType>(m_Working_Support);
+  m_ListOfStations["2R"] = m_Working_Support;
+  m_ListOfStations["2L"] = m_Working_Support;
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void
+clitk::ExtractLymphStationsFilter<ImageType>::
+ExtractStation_2RL_SeparateRL()
+{
+  // ---------------------------------------------------------------------------
+  StartNewStep("[Station 2RL] Separate 2R/2L according to Trachea");
+
+  /*Rod says: 
+    
+   "For station 2 there is a shift, dividing 2R from 2L, from midline
+   to the left paratracheal border."
+
+   Algo: 
+    - Consider Trachea SliceBySlice
+    - find extrema at Left
+    - add margins towards Right
+    - remove what is at Left of this line
+   */
+
+  // Get Trachea
+  MaskImagePointer Trachea = GetAFDB()->template GetImage<MaskImageType>("Trachea");
+  
+  // Resize like the current support (to have the same number of slices)
+  Trachea = clitk::ResizeImageLike<MaskImageType>(Trachea, m_Working_Support, GetBackgroundValue());
+
+  // Find extrema post positions
+  std::vector<MaskImagePointType> tracheaLeftPositionsA;
+  std::vector<MaskImagePointType> tracheaLeftPositionsB;
+  clitk::SliceBySliceBuildLineSegmentAccordingToExtremaPosition<MaskImageType>(Trachea, 
+                                                                               GetBackgroundValue(), 2, 
+                                                                               0, false, // Left
+                                                                               1, // Vertical line 
+                                                                               1, // margins 
+                                                                               tracheaLeftPositionsA, 
+                                                                               tracheaLeftPositionsB);
+  // Copy support for R and L
+  typedef itk::ImageDuplicator<MaskImageType> DuplicatorType;
+  DuplicatorType::Pointer duplicator = DuplicatorType::New();
+  duplicator->SetInputImage(m_Working_Support);
+  duplicator->Update();
+  MaskImageType::Pointer m_Working_Support2 = duplicator->GetOutput();
+  
+  // Cut post to this line for Right part
+  clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_Working_Support, 
+                                                                    tracheaLeftPositionsA,
+                                                                    tracheaLeftPositionsB,
+                                                                    GetBackgroundValue(), 0, -10); 
+  writeImage<MaskImageType>(m_Working_Support, "R.mhd");
+
+  // Cut post to this line for Left part
+  clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_Working_Support2, 
+                                                                    tracheaLeftPositionsA,
+                                                                    tracheaLeftPositionsB,
+                                                                    GetBackgroundValue(), 0, +10); 
+  writeImage<MaskImageType>(m_Working_Support2, "L.mhd");
+
+  // END
+  StopCurrentStep<MaskImageType>(m_Working_Support);
+  m_ListOfStations["2R"] = m_Working_Support;
+  m_ListOfStations["2L"] = m_Working_Support2;
+}
+//--------------------------------------------------------------------
index 044691304971179c1507e3efac5ea2becd75c79e..a55071c19e5874d3f9804e03befa2a1509bff152 100644 (file)
@@ -1,23 +1,3 @@
-/*=========================================================================
-  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
-
-  Authors belong to:
-  - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://www.centreleonberard.fr
-  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the copyright notices for more information.
-
-  It is distributed under dual licence
-
-  - BSD        See included LICENSE.txt file
-  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
-===========================================================================*/
-
-#include <itkBinaryDilateImageFilter.h>
-#include <itkMirrorPadImageFilter.h>
 
 //--------------------------------------------------------------------
 template <class ImageType>
@@ -25,6 +5,8 @@ void
 clitk::ExtractLymphStationsFilter<ImageType>::
 ExtractStation_3A_SetDefaultValues()
 {
+  SetFuzzyThreshold("3A", "Sternum", 0.5);
+  SetFuzzyThreshold("3A", "SubclavianArtery", 0.5);
 }
 //--------------------------------------------------------------------
 
@@ -73,7 +55,27 @@ ExtractStation_3A_Ant_Limits()
   MaskImagePointer Sternum = GetAFDB()->template GetImage<MaskImageType>("Sternum");
   m_Working_Support = 
     clitk::SliceBySliceRelativePosition<MaskImageType>(m_Working_Support, Sternum, 2, 
-                                                       0.5, "PostTo", 
+                                                       GetFuzzyThreshold("3A", "Sternum"), "PostTo", 
+                                                       false, 3, true, false);
+  StopCurrentStep<MaskImageType>(m_Working_Support);
+  m_ListOfStations["3A"] = m_Working_Support;
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void 
+clitk::ExtractLymphStationsFilter<ImageType>::
+ExtractStation_3A_Post_Limits() 
+{
+  StartNewStep("[Station 3A] Post limits with SubclavianArtery");
+
+  // Get Sternum, keep posterior part.
+  MaskImagePointer SubclavianArtery = GetAFDB()->template GetImage<MaskImageType>("SubclavianArtery");
+  m_Working_Support = 
+    clitk::SliceBySliceRelativePosition<MaskImageType>(m_Working_Support, SubclavianArtery, 2, 
+                                                       GetFuzzyThreshold("3A", "SubclavianArtery"), "AntTo", 
                                                        false, 3, true, false);
   StopCurrentStep<MaskImageType>(m_Working_Support);
   m_ListOfStations["3A"] = m_Working_Support;
index 7f1d5bf7d9eaef0b2fc15c72c1b0c18d4e4b199c..1c9fdc0f81d82ffe0001331f3e13a0ee05cf4a2b 100644 (file)
@@ -1,23 +1,3 @@
-/*=========================================================================
-  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
-
-  Authors belong to:
-  - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://www.centreleonberard.fr
-  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the copyright notices for more information.
-
-  It is distributed under dual licence
-
-  - BSD        See included LICENSE.txt file
-  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
-===========================================================================*/
-
-#include <itkBinaryDilateImageFilter.h>
-#include <itkMirrorPadImageFilter.h>
 
 //--------------------------------------------------------------------
 template <class ImageType>
@@ -82,13 +62,13 @@ ExtractStation_3P_Remove_Structures()
 
   StartNewStep("[Station 3P] Remove some structures.");
 
-  Remove_Structures("Aorta");
-  Remove_Structures("VertebralBody");
-  Remove_Structures("SubclavianArtery");
-  Remove_Structures("Esophagus");
-  Remove_Structures("Azygousvein");
-  Remove_Structures("Thyroid");
-  Remove_Structures("VertebralArtery");
+  Remove_Structures("3P", "Aorta");
+  Remove_Structures("3P", "VertebralBody");
+  Remove_Structures("3P", "SubclavianArtery");
+  Remove_Structures("3P", "Esophagus");
+  Remove_Structures("3P", "Azygousvein");
+  Remove_Structures("3P", "Thyroid");
+  Remove_Structures("3P", "VertebralArtery");
 
   StopCurrentStep<MaskImageType>(m_Working_Support);
   m_ListOfStations["3P"] = m_Working_Support;
index 5aad362ff9fc88823a3b8a6051e396a6d8d06eda..462ae9d34e142a7d8a40f1ec7168166730dabfce 100644 (file)
@@ -1,20 +1,3 @@
-/*=========================================================================
-  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
-
-  Authors belong to:
-  - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://www.centreleonberard.fr
-  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the copyright notices for more information.
-
-  It is distributed under dual licence
-
-  - BSD        See included LICENSE.txt file
-  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
-===========================================================================*/
 //--------------------------------------------------------------------
 template <class TImageType>
 void 
index c5811661712d1a16ebffc34bbebcf47933cc5c11..7bb4643cfcae9fcd6dd11ddc1060cdfee07db359 100644 (file)
@@ -1,20 +1,3 @@
-/*=========================================================================
-  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
-
-  Authors belong to:
-  - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://www.centreleonberard.fr
-  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the copyright notices for more information.
-
-  It is distributed under dual licence
-
-  - BSD        See included LICENSE.txt file
-  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
-===========================================================================*/
 
 //--------------------------------------------------------------------
 template <class TImageType>
@@ -22,38 +5,12 @@ void
 clitk::ExtractLymphStationsFilter<TImageType>::
 ExtractStation_7_SetDefaultValues()
 {
-  SetFuzzyThresholdForS7("Bronchi", 0.1);
-  SetFuzzyThresholdForS7("LeftSuperiorPulmonaryVein", 0.3);
-  SetFuzzyThresholdForS7("RightSuperiorPulmonaryVein", 0.2);
-  SetFuzzyThresholdForS7("RightPulmonaryArtery", 0.3);
-  SetFuzzyThresholdForS7("LeftPulmonaryArtery", 0.5);
-  SetFuzzyThresholdForS7("SVC", 0.2);
-}
-//--------------------------------------------------------------------
-
-//--------------------------------------------------------------------
-template <class TImageType>
-void 
-clitk::ExtractLymphStationsFilter<TImageType>::
-SetFuzzyThresholdForS7(std::string tag, double value)
-{
-  m_FuzzyThresholdForS7[tag] = value;
-}
-//--------------------------------------------------------------------
-
-
-//--------------------------------------------------------------------
-template <class TImageType>
-double 
-clitk::ExtractLymphStationsFilter<TImageType>::
-GetFuzzyThresholdForS7(std::string tag)
-{
-  if (m_FuzzyThresholdForS7.find(tag) != m_FuzzyThresholdForS7.end()) {
-    return m_FuzzyThresholdForS7[tag]; 
-  }
-  else {
-    clitkExceptionMacro("Could not find options "+tag+" in the m_FuzzyThresholdForS7 list");
-  }
+  SetFuzzyThreshold("7", "Bronchi", 0.1);
+  SetFuzzyThreshold("7", "LeftSuperiorPulmonaryVein", 0.3);
+  SetFuzzyThreshold("7", "RightSuperiorPulmonaryVein", 0.2);
+  SetFuzzyThreshold("7", "RightPulmonaryArtery", 0.3);
+  SetFuzzyThreshold("7", "LeftPulmonaryArtery", 0.5);
+  SetFuzzyThreshold("7", "SVC", 0.2);
 }
 //--------------------------------------------------------------------
 
@@ -175,7 +132,7 @@ ExtractStation_7_RL_Limits()
 
   m_Working_Support = 
     clitk::SliceBySliceRelativePosition<MaskImageType>(m_Working_Support, m_LeftBronchus, 2, 
-                                                       GetFuzzyThresholdForS7("Bronchi"), "RightTo", 
+                                                       GetFuzzyThreshold("7", "Bronchi"), "RightTo", 
                                                        false, 3, false);
   StopCurrentStep<MaskImageType>(m_Working_Support);
 
@@ -184,7 +141,7 @@ ExtractStation_7_RL_Limits()
   StartNewStep("[Station7] Limits with bronchus : LeftTo the right bronchus");
   m_Working_Support = 
     clitk::SliceBySliceRelativePosition<MaskImageType>(m_Working_Support, m_RightBronchus, 2, 
-                                                       GetFuzzyThresholdForS7("Bronchi"), "LeftTo", 
+                                                       GetFuzzyThreshold("7", "Bronchi"), "LeftTo", 
                                                        false, 3, false); 
   StopCurrentStep<MaskImageType>(m_Working_Support);
 
@@ -198,7 +155,7 @@ ExtractStation_7_RL_Limits()
     sliceRelPosFilter->SetInput(m_Working_Support);
     sliceRelPosFilter->SetInputObject(LeftSuperiorPulmonaryVein);
     sliceRelPosFilter->SetDirection(2);
-    sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThresholdForS7("LeftSuperiorPulmonaryVein"));
+    sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThreshold("7", "LeftSuperiorPulmonaryVein"));
     sliceRelPosFilter->AddOrientationTypeString("NotLeftTo");
     sliceRelPosFilter->AddOrientationTypeString("NotAntTo");
     sliceRelPosFilter->SetIntermediateSpacingFlag(true);
@@ -223,7 +180,7 @@ ExtractStation_7_RL_Limits()
     sliceRelPosFilter->SetInput(m_Working_Support);
     sliceRelPosFilter->SetInputObject(RightSuperiorPulmonaryVein);
     sliceRelPosFilter->SetDirection(2);
-    sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThresholdForS7("RightSuperiorPulmonaryVein"));
+    sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThreshold("7", "RightSuperiorPulmonaryVein"));
     sliceRelPosFilter->AddOrientationTypeString("NotRightTo");
     sliceRelPosFilter->AddOrientationTypeString("NotAntTo");
     sliceRelPosFilter->AddOrientationTypeString("NotPostTo");
@@ -248,7 +205,7 @@ ExtractStation_7_RL_Limits()
   sliceRelPosFilter->SetInput(m_Working_Support);
   sliceRelPosFilter->SetInputObject(RightPulmonaryArtery);
   sliceRelPosFilter->SetDirection(2);
-  sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThresholdForS7("RightPulmonaryArtery"));
+  sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThreshold("7", "RightPulmonaryArtery"));
   sliceRelPosFilter->AddOrientationTypeString("NotAntTo");
   sliceRelPosFilter->SetIntermediateSpacingFlag(true);
   sliceRelPosFilter->SetIntermediateSpacing(3);
@@ -266,7 +223,7 @@ ExtractStation_7_RL_Limits()
   sliceRelPosFilter->SetInput(m_Working_Support);
   sliceRelPosFilter->SetInputObject(LeftPulmonaryArtery);
   sliceRelPosFilter->SetDirection(2);
-  sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThresholdForS7("LeftPulmonaryArtery"));
+  sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThreshold("7", "LeftPulmonaryArtery"));
   sliceRelPosFilter->AddOrientationTypeString("NotAntTo");
   sliceRelPosFilter->SetIntermediateSpacingFlag(true);
   sliceRelPosFilter->SetIntermediateSpacing(3);
@@ -283,7 +240,7 @@ ExtractStation_7_RL_Limits()
   sliceRelPosFilter->SetInput(m_Working_Support);
   sliceRelPosFilter->SetInputObject(SVC);
   sliceRelPosFilter->SetDirection(2);
-  sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThresholdForS7("SVC"));
+  sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThreshold("7", "SVC"));
   sliceRelPosFilter->AddOrientationTypeString("NotRightTo");
   sliceRelPosFilter->AddOrientationTypeString("NotAntTo");
   sliceRelPosFilter->SetIntermediateSpacingFlag(true);
@@ -386,14 +343,14 @@ ExtractStation_7_Remove_Structures()
   //--------------------------------------------------------------------
   StartNewStep("[Station7] remove some structures");
 
-  Remove_Structures("AzygousVein");
-  Remove_Structures("Aorta");
-  Remove_Structures("Esophagus");
-  Remove_Structures("RightPulmonaryArtery");
-  Remove_Structures("LeftPulmonaryArtery");
-  Remove_Structures("LeftSuperiorPulmonaryVein");
-  Remove_Structures("PulmonaryTrunk");
-  Remove_Structures("VertebralBody");
+  Remove_Structures("7", "AzygousVein");
+  Remove_Structures("7", "Aorta");
+  Remove_Structures("7", "Esophagus");
+  Remove_Structures("7", "RightPulmonaryArtery");
+  Remove_Structures("7", "LeftPulmonaryArtery");
+  Remove_Structures("7", "LeftSuperiorPulmonaryVein");
+  Remove_Structures("7", "PulmonaryTrunk");
+  Remove_Structures("7", "VertebralBody");
 
   // END
   StopCurrentStep<MaskImageType>(m_Working_Support);
index 75c012998366232a6be82df8c307cf87d1e7e372..bb1ce79044a209e1c125d6b705383484c87c2f0c 100644 (file)
@@ -1,20 +1,3 @@
-/*=========================================================================
-  Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
-
-  Authors belong to:
-  - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://www.centreleonberard.fr
-  - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
-
-  This software is distributed WITHOUT ANY WARRANTY; without even
-  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the copyright notices for more information.
-
-  It is distributed under dual licence
-
-  - BSD        See included LICENSE.txt file
-  - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
-===========================================================================*/
 
 #include <itkBinaryDilateImageFilter.h>
 #include <itkMirrorPadImageFilter.h>
@@ -31,7 +14,7 @@ ExtractStation_8_SetDefaultValues()
   SetEsophagusDiltationForAnt(p);
   p[0] = 5; p[1] = 10; p[2] = 1;
   SetEsophagusDiltationForRight(p);
-  SetFuzzyThresholdForS8(0.5);
+  SetFuzzyThreshold("8", "Esophagus", 0.5);
   SetInjectedThresholdForS8(150);
 }
 //--------------------------------------------------------------------
@@ -180,9 +163,9 @@ ExtractStation_8_Post_Limits()
 
   // Convert 2D points in slice into 3D points
   std::vector<MaskImagePointType> vertebralAntPositions;
-  clitk::PointsUtils<MaskImageType>::Convert2DTo3DList(vertebralAntPositionBySlice, 
-                                                       VertebralBody, 
-                                                       vertebralAntPositions);
+  clitk::PointsUtils<MaskImageType>::Convert2DMapTo3DList(vertebralAntPositionBySlice, 
+                                                          VertebralBody, 
+                                                          vertebralAntPositions);
 
   // DEBUG : write list of points
   clitk::WriteListOfLandmarks<MaskImageType>(vertebralAntPositions, 
@@ -485,7 +468,7 @@ ExtractStation_8_Ant_Inf_Limits()
   relPosFilter->UniqueConnectedComponentBySliceOff();
   relPosFilter->SetIntermediateSpacing(3);
   relPosFilter->IntermediateSpacingFlagOn();
-  relPosFilter->SetFuzzyThreshold(GetFuzzyThresholdForS8());
+  relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold("8", "Esophagus"));
   relPosFilter->RemoveObjectFlagOff(); // Do not exclude here because it is dilated
   relPosFilter->CombineWithOrFlagOff(); // NO !
   relPosFilter->IgnoreEmptySliceObjectFlagOn();
@@ -1148,8 +1131,8 @@ ExtractStation_8_Remove_Structures()
   //--------------------------------------------------------------------
   StartNewStep("[Station8] remove some structures");
 
-  Remove_Structures("Aorta");
-  Remove_Structures("Esophagus");
+  Remove_Structures("8", "Aorta");
+  Remove_Structures("8", "Esophagus");
 
   // END
   StopCurrentStep<MaskImageType>(m_Working_Support);
index 6ddd81869a8d633dddaf2897ff9ced149ebd34ae..ec41a4e5acac639048cf6b1508b9066d6d50279e 100644 (file)
@@ -3,7 +3,7 @@
 
   Authors belong to:
   - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://www.centreleonberard.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
@@ -14,7 +14,7 @@
 
   - BSD        See included LICENSE.txt file
   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
-===========================================================================**/
+======================================================================-====*/
 
 // clitk
 #include "clitkExtractLymphStations_ggo.h"
index 57cf24ad659af9679ae5260a3653e50e2137c5dc..d789824756ce33ad9d6fb37e9adf725d44b6a0db 100644 (file)
@@ -20,16 +20,28 @@ option "output"        o    "Output lungs mask filename"      string        no
 option "station"       -       "Force to compute station even if already exist in the DB"      string  no multiple
 
 section "Options for Station 8"
-option "maxAntSpine" - "Distance max to anterior part of the spine in mm"  double no default="10"
-option "esophagusDilatationForAnt" - "Dilatation of esophagus, in mm, for 'anterior' limits (default=15,2,1)" double no multiple
+option "maxAntSpine"                 - "Distance max to anterior part of the spine in mm"  double no default="10"
+option "esophagusDilatationForAnt"   - "Dilatation of esophagus, in mm, for 'anterior' limits (default=15,2,1)" double no multiple
 option "esophagusDilatationForRight" - "Dilatation of esophagus, in mm, for 'right' limits (default=5,10,1)" double no multiple
-option "fuzzyThresholdForS8" - "Threshold for 'Post' to dilated Esophagus" double default="0.5" no 
-option "injectedThresholdForS8" - "Threshold injected areas in the ct" double default="150" no 
+option "tS8_Esophagus"               - "Threshold for 'Post' to dilated Esophagus" double default="0.5" no 
+option "injectedThresholdForS8"      - "Threshold injected areas in the ct" double default="150" no 
 
 section "Options for Station 7"
-option "tS7_Bronchi" - "Threshold for Left/Right bronchi" double default="0.1" no 
-option "tS7_LeftSuperiorPulmonaryVein" - "Threshold for LeftSuperiorPulmonaryVein" double default="0.3" no 
+option "tS7_Bronchi"                    - "Threshold for Left/Right bronchi" double default="0.1" no 
+option "tS7_LeftSuperiorPulmonaryVein"  - "Threshold for LeftSuperiorPulmonaryVein" double default="0.3" no 
 option "tS7_RightSuperiorPulmonaryVein" - "Threshold for RightSuperiorPulmonaryVein" double default="0.2" no 
-option "tS7_RightPulmonaryArtery" - "Threshold for RightPulmonaryArtery" double default="0.3" no 
-option "tS7_LeftPulmonaryArtery" - "Threshold for LeftPulmonaryArtery (NOT USEFUL YET)" double default="0.5" no 
-option "tS7_SVC" - "Threshold for SVC" double default="0.2" no 
\ No newline at end of file
+option "tS7_RightPulmonaryArtery"       - "Threshold for RightPulmonaryArtery" double default="0.3" no 
+option "tS7_LeftPulmonaryArtery"        - "Threshold for LeftPulmonaryArtery (NOT USEFUL YET)" double default="0.5" no 
+option "tS7_SVC"                        - "Threshold for SVC" double default="0.2" no 
+
+section "Options for Station 3A"
+option "tS3A_Sternum"          - "Threshold for Post to Sternum" double default="0.5" no 
+option "tS3A_SubclavianArtery" - "Threshold for Ant to SubclavianArtery" double default="0.2" no 
+
+section "Options for Station 2RL"
+option "tS2RL_CommonCarotidArtery"   - "Threshold for NotAntTo to CommonCarotidArtery"   double default="0.7" no 
+option "tS2RL_BrachioCephalicTrunk"  - "Threshold for NotAntTo to BrachioCephalicTrunk"  double default="0.7" no 
+option "tS2RL_BrachioCephalicVein"   - "Threshold for NotAntTo to BrachioCephalicVein"   double default="0.3" no 
+option "tS2RL_Aorta"                 - "Threshold for RightTo  to Aorta"                 double default="0.7" no 
+option "tS2RL_SubclavianArteryRight" - "Threshold for NotLeft  to SubclavianArteryRight" double default="0.5" no 
+option "tS2RL_SubclavianArteryLeft"  - "Threshold for NotRight to SubclavianArteryLeft"  double default="0.8" no 
index 6f81423fe20cbcfdfc14921839faa48c8c631add..8d160b1aad557945d3b13be3f54b7435b991f0b0 100644 (file)
@@ -3,7 +3,7 @@
 
   Authors belong to: 
   - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://www.centreleonberard.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
@@ -14,7 +14,7 @@
 
   - 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
@@ -23,6 +23,9 @@
 #include "clitkFilterBase.h"
 #include "clitkFilterWithAnatomicalFeatureDatabaseManagement.h"
 
+// vtk
+#include <vtkPolyData.h>
+
 namespace clitk {
   
   //--------------------------------------------------------------------
@@ -72,6 +75,7 @@ namespace clitk {
 
     typedef itk::Image<MaskImagePixelType, 2>    MaskSliceType;
     typedef typename MaskSliceType::Pointer      MaskSlicePointer;
+    typedef typename MaskSliceType::PointType    MaskSlicePointType;
 
     /** ImageDimension constants */
     itkStaticConstMacro(ImageDimension, unsigned int, ImageType::ImageDimension);
@@ -89,19 +93,16 @@ namespace clitk {
     itkGetConstMacro(EsophagusDiltationForAnt, MaskImagePointType);
     itkSetMacro(EsophagusDiltationForRight, MaskImagePointType);
     itkGetConstMacro(EsophagusDiltationForRight, MaskImagePointType);
-    itkSetMacro(FuzzyThresholdForS8, double);
-    itkGetConstMacro(FuzzyThresholdForS8, double);
-
     itkSetMacro(InjectedThresholdForS8, double);
     itkGetConstMacro(InjectedThresholdForS8, double);
 
     // Station 7
-    void SetFuzzyThresholdForS7(std::string tag, double value);
-    double GetFuzzyThresholdForS7(std::string tag);
 
     // All stations
     bool GetComputeStation(std::string s);
     void AddComputeStation(std::string station) ;
+    void SetFuzzyThreshold(std::string station, std::string tag, double value);
+    double GetFuzzyThreshold(std::string station, std::string tag);
 
   protected:
     ExtractLymphStationsFilter();
@@ -120,14 +121,17 @@ namespace clitk {
     std::map<std::string, bool> m_ComputeStationMap;
 
     bool CheckForStation(std::string station);
-    void Remove_Structures(std::string s);
+    void Remove_Structures(std::string station, std::string s);
+
+    // Global parameters
+    typedef std::map<std::string, double> FuzzyThresholdByStructureType;
+    std::map<std::string, FuzzyThresholdByStructureType> m_FuzzyThreshold;    
 
     // Station 8
     double m_DistanceMaxToAnteriorPartOfTheSpine;
     double m_DiaphragmInferiorLimit;
     double m_CarinaZ;
     double m_OriginOfRightMiddleLobeBronchusZ;
-    double m_FuzzyThresholdForS8;
     double m_InjectedThresholdForS8;
     MaskImagePointer m_Esophagus;
     MaskImagePointType m_EsophagusDiltationForAnt;
@@ -159,11 +163,24 @@ namespace clitk {
     void ExtractStation_3P_LR_sup_Limits_2();
     void ExtractStation_3P_LR_inf_Limits();
 
+    // Station 2RL
+    void ExtractStation_2RL();
+    void ExtractStation_2RL_SetDefaultValues();
+    void ExtractStation_2RL_SI_Limits();
+    void ExtractStation_2RL_Ant_Limits();
+    void ExtractStation_2RL_Ant_Limits2();
+    void ExtractStation_2RL_Post_Limits();
+    void ExtractStation_2RL_LR_Limits();
+    void ExtractStation_2RL_Remove_Structures();
+    void ExtractStation_2RL_SeparateRL();
+    vtkSmartPointer<vtkPolyData> Build3DMeshFrom2DContour(const std::vector<ImagePointType> & points);
+
     // Station 3A
     void ExtractStation_3A();
     void ExtractStation_3A_SetDefaultValues();
     void ExtractStation_3A_SI_Limits();
     void ExtractStation_3A_Ant_Limits();
+    void ExtractStation_3A_Post_Limits();
 
     // Station 7
     void ExtractStation_7();
@@ -173,7 +190,6 @@ namespace clitk {
     void ExtractStation_7_Posterior_Limits();   
     void ExtractStation_7_Remove_Structures();
     MaskImagePointer m_Working_Trachea;
-    std::map<std::string, double> m_FuzzyThresholdForS7;
     MaskImagePointer m_LeftBronchus;
     MaskImagePointer m_RightBronchus;
     typedef std::vector<MaskImageType::PointType> ListOfPointsType;
@@ -212,6 +228,7 @@ namespace clitk {
 #include "clitkExtractLymphStationsFilter.txx"
 #include "clitkExtractLymphStation_8.txx"
 #include "clitkExtractLymphStation_3P.txx"
+#include "clitkExtractLymphStation_2RL.txx"
 #include "clitkExtractLymphStation_3A.txx"
 #include "clitkExtractLymphStation_7.txx"
 #include "clitkExtractLymphStation_4RL.txx"
diff --git a/segmentation/clitkExtractLymphStationsFilter.old.h b/segmentation/clitkExtractLymphStationsFilter.old.h
new file mode 100644 (file)
index 0000000..6be4764
--- /dev/null
@@ -0,0 +1,124 @@
+/*=========================================================================
+  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
+
+// clitk
+#include "clitkFilterBase.h"
+#include "clitkFilterWithAnatomicalFeatureDatabaseManagement.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 TImageType>
+  class ITK_EXPORT ExtractLymphStationsFilter: 
+    public virtual clitk::FilterBase, 
+    public clitk::FilterWithAnatomicalFeatureDatabaseManagement,
+    public itk::ImageToImageFilter<TImageType, itk::Image<uchar, 3> >
+  {
+
+  public:
+    /** Standard class typedefs. */
+    typedef itk::ImageToImageFilter<TImageType, itk::Image<uchar, 3> > Superclass;
+    typedef ExtractLymphStationsFilter          Self;
+    typedef itk::SmartPointer<Self>             Pointer;
+    typedef itk::SmartPointer<const Self>       ConstPointer;
+    
+    /** Method for creation through the object factory. */
+    itkNewMacro(Self);
+    
+    /** Run-time type information (and related methods). */
+    itkTypeMacro(ExtractLymphStationsFilter, InPlaceImageFilter);
+
+    /** 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; 
+    typedef typename ImageType::PointType    ImagePointType; 
+        
+    typedef uchar MaskImagePixelType;
+    typedef itk::Image<MaskImagePixelType, 3> MaskImageType;  
+    typedef typename MaskImageType::Pointer   MaskImagePointer;
+
+    /** Connect inputs */
+    //    void SetInput(const TImageType * image);
+  
+    /** ImageDimension constants */
+    itkStaticConstMacro(ImageDimension, unsigned int, TImageType::ImageDimension);
+    FILTERBASE_INIT;
+   
+    itkGetConstMacro(BackgroundValue, ImagePixelType);
+    itkGetConstMacro(ForegroundValue, ImagePixelType);
+    itkSetMacro(BackgroundValue, ImagePixelType);
+    itkSetMacro(ForegroundValue, ImagePixelType);
+    
+    itkSetMacro(FuzzyThreshold, double);
+    itkGetConstMacro(FuzzyThreshold, double);
+
+  protected:
+    ExtractLymphStationsFilter();
+    virtual ~ExtractLymphStationsFilter() {}
+    
+    virtual void GenerateOutputInformation();
+    virtual void GenerateInputRequestedRegion();
+    virtual void GenerateData();
+       
+    MaskImagePointer m_mediastinum;
+    MaskImagePointer m_trachea;
+    MaskImagePointer m_working_mediastinum;
+    MaskImagePointer m_working_trachea;  
+    MaskImagePointer m_output;  
+    
+    ImagePixelType m_BackgroundValue;
+    ImagePixelType m_ForegroundValue;
+    double m_CarinaZPositionInMM;
+    bool   m_CarinaZPositionInMMIsSet;
+    double m_MiddleLobeBronchusZPositionInMM; 
+
+    double m_IntermediateSpacing;
+    double m_FuzzyThreshold;
+    
+  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.old.txx b/segmentation/clitkExtractLymphStationsFilter.old.txx
new file mode 100644 (file)
index 0000000..c95be39
--- /dev/null
@@ -0,0 +1,395 @@
+/*=========================================================================
+  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 "clitkSegmentationUtils.h"
+#include "clitkAutoCropFilter.h"
+#include "clitkSegmentationUtils.h"
+#include "clitkSliceBySliceRelativePositionFilter.h"
+
+// itk
+#include <itkStatisticsLabelMapFilter.h>
+#include <itkLabelImageToStatisticsLabelMapFilter.h>
+#include <itkRegionOfInterestImageFilter.h>
+#include <itkBinaryThresholdImageFilter.h>
+#include <itkImageSliceConstIteratorWithIndex.h>
+#include <itkImageSliceIteratorWithIndex.h>
+#include <itkBinaryThinningImageFilter.h>
+
+// itk ENST
+#include "RelativePositionPropImageFilter.h"
+
+//--------------------------------------------------------------------
+template <class TImageType>
+clitk::ExtractLymphStationsFilter<TImageType>::
+ExtractLymphStationsFilter():
+  clitk::FilterBase(),
+  clitk::FilterWithAnatomicalFeatureDatabaseManagement(),
+  itk::ImageToImageFilter<TImageType, MaskImageType>()
+{
+  this->SetNumberOfRequiredInputs(1);
+  SetBackgroundValue(0);
+  SetForegroundValue(1);
+  SetFuzzyThreshold(0.5);
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class TImageType>
+void 
+clitk::ExtractLymphStationsFilter<TImageType>::
+GenerateOutputInformation() { 
+  //  Superclass::GenerateOutputInformation();
+  
+  // Get input
+  LoadAFDB();
+  m_mediastinum = GetAFDB()->template GetImage <MaskImageType>("mediastinum");  
+  m_trachea = GetAFDB()->template GetImage <MaskImageType>("trachea");  
+  ImagePointType carina;
+  GetAFDB()->GetPoint3D("carina", carina);
+  m_CarinaZPositionInMM = carina[2];
+  DD(m_CarinaZPositionInMM);
+  ImagePointType mlb;
+  GetAFDB()->GetPoint3D("middleLobeBronchus", mlb);
+  m_MiddleLobeBronchusZPositionInMM = mlb[2];
+  DD(m_MiddleLobeBronchusZPositionInMM);
+
+  // ----------------------------------------------------------------
+  // ----------------------------------------------------------------
+  // Superior limit = carina
+  // Inferior limit = origin right middle lobe bronchus
+  StartNewStep("Inf/Sup mediastinum limits with carina/bronchus");
+  m_working_mediastinum = 
+    clitk::CropImageAlongOneAxis<MaskImageType>(m_mediastinum, 2, 
+                                                m_MiddleLobeBronchusZPositionInMM, 
+                                                m_CarinaZPositionInMM, true,
+                                                GetBackgroundValue());
+  StopCurrentStep<MaskImageType>(m_working_mediastinum);
+  m_output = m_working_mediastinum;
+
+  // ----------------------------------------------------------------
+  // ----------------------------------------------------------------
+  // Superior limit = carina
+  // Inferior limit = origin right middle lobe bronchus
+  StartNewStep("Inf/Sup trachea limits with carina/bronchus");
+  m_working_trachea = 
+    clitk::CropImageAlongOneAxis<MaskImageType>(m_trachea, 2, 
+                                                m_MiddleLobeBronchusZPositionInMM, 
+                                                m_CarinaZPositionInMM, true,
+                                                GetBackgroundValue());
+  StopCurrentStep<MaskImageType>(m_working_trachea);
+
+  // ----------------------------------------------------------------
+  // ----------------------------------------------------------------
+  // Separate trachea in two CCL
+  StartNewStep("Separate trachea under carina");
+
+  // Labelize and consider two main labels
+  m_working_trachea = Labelize<MaskImageType>(m_working_trachea, 0, true, 1);
+
+  // Carina position must at the first slice that separate the two main bronchus (not superiorly) 
+  // Check that upper slice is composed of at least two labels
+  typedef itk::ImageSliceIteratorWithIndex<MaskImageType> SliceIteratorType;
+  SliceIteratorType iter(m_working_trachea, m_working_trachea->GetLargestPossibleRegion());
+  iter.SetFirstDirection(0);
+  iter.SetSecondDirection(1);
+  iter.GoToReverseBegin(); // Start from the end (because image is IS not SI)
+  int maxLabel=0;
+  while (!iter.IsAtReverseEndOfSlice()) {
+    while (!iter.IsAtReverseEndOfLine()) {    
+      //  DD(iter.GetIndex());
+      if (iter.Get() > maxLabel) maxLabel = iter.Get();
+      --iter;
+    }
+    iter.PreviousLine();
+  }
+  if (maxLabel < 2) {
+    clitkExceptionMacro("First slice form Carina does not seems to seperate the two main bronchus. Abort");
+  }
+
+  // Compute centroid of both parts to identify the left from the right bronchus
+  typedef long LabelType;
+  static const unsigned int Dim = ImageType::ImageDimension;
+  typedef itk::ShapeLabelObject< LabelType, Dim > LabelObjectType;
+  typedef itk::LabelMap< LabelObjectType > LabelMapType;
+  typedef itk::LabelImageToLabelMapFilter<MaskImageType, LabelMapType> ImageToMapFilterType;
+  typename ImageToMapFilterType::Pointer imageToLabelFilter = ImageToMapFilterType::New(); 
+  typedef itk::ShapeLabelMapFilter<LabelMapType, MaskImageType> ShapeFilterType; 
+  typename ShapeFilterType::Pointer statFilter = ShapeFilterType::New();
+  imageToLabelFilter->SetBackgroundValue(GetBackgroundValue());
+  imageToLabelFilter->SetInput(m_working_trachea);
+  statFilter->SetInput(imageToLabelFilter->GetOutput());
+  statFilter->Update();
+  typename LabelMapType::Pointer labelMap = statFilter->GetOutput();
+
+  ImagePointType C1 = labelMap->GetLabelObject(1)->GetCentroid();
+  ImagePointType C2 = labelMap->GetLabelObject(2)->GetCentroid();
+
+  ImagePixelType leftLabel;
+  ImagePixelType rightLabel;  
+  if (C1[0] < C2[0]) { leftLabel = 1; rightLabel = 2; }
+  else { leftLabel = 2; rightLabel = 1; }
+  DD(leftLabel);
+  DD(rightLabel);
+
+  StopCurrentStep<MaskImageType>(m_working_trachea);
+
+  //-----------------------------------------------------
+  StartNewStep("Left limits with bronchus (slice by slice)");  
+  // Select LeftLabel (set one label to Backgroundvalue)
+  MaskImagePointer leftBronchus = 
+    SetBackground<MaskImageType, MaskImageType>(m_working_trachea, m_working_trachea, 
+                                                rightLabel, GetBackgroundValue());
+  MaskImagePointer rightBronchus  = 
+    SetBackground<MaskImageType, MaskImageType>(m_working_trachea, m_working_trachea, 
+                                                leftLabel, GetBackgroundValue());
+  writeImage<MaskImageType>(leftBronchus, "left.mhd");
+  writeImage<MaskImageType>(rightBronchus, "right.mhd");
+
+  m_working_mediastinum = 
+    clitk::SliceBySliceRelativePosition<MaskImageType>(m_working_mediastinum, 
+                                                      leftBronchus, 2, 
+                                                       GetFuzzyThreshold(), "RightTo", 
+                                                       true, 4);
+  m_working_mediastinum = 
+    clitk::SliceBySliceRelativePosition<MaskImageType>(m_working_mediastinum, 
+                                                      rightBronchus, 
+                                                      2, GetFuzzyThreshold(), "LeftTo", 
+                                                       true, 4);
+  m_working_mediastinum = 
+    clitk::SliceBySliceRelativePosition<MaskImageType>(m_working_mediastinum, 
+                                                      leftBronchus, 
+                                                      2, GetFuzzyThreshold(), "AntTo", 
+                                                       true, 4, true); // NOT
+  m_working_mediastinum = 
+    clitk::SliceBySliceRelativePosition<MaskImageType>(m_working_mediastinum, 
+                                                      rightBronchus, 
+                                                      2, GetFuzzyThreshold(), "AntTo", 
+                                                       true, 4, true);
+  m_working_mediastinum = 
+    clitk::SliceBySliceRelativePosition<MaskImageType>(m_working_mediastinum, 
+                                                      leftBronchus, 
+                                                      2, GetFuzzyThreshold(), "PostTo", 
+                                                       true, 4, true);
+  m_working_mediastinum = 
+    clitk::SliceBySliceRelativePosition<MaskImageType>(m_working_mediastinum, 
+                                                      rightBronchus, 
+                                                      2, GetFuzzyThreshold(), "PostTo", 
+                                                       true, 4, true);
+  m_output = m_working_mediastinum;
+  StopCurrentStep<MaskImageType>(m_output);
+
+  //-----------------------------------------------------
+  //-----------------------------------------------------
+  StartNewStep("Posterior limits");  
+
+  // Left Bronchus slices
+  typedef clitk::ExtractSliceFilter<MaskImageType> ExtractSliceFilterType;
+  typedef typename ExtractSliceFilterType::SliceType SliceType;
+  typename ExtractSliceFilterType::Pointer 
+    extractSliceFilter = ExtractSliceFilterType::New();
+  extractSliceFilter->SetInput(leftBronchus);
+  extractSliceFilter->SetDirection(2);
+  extractSliceFilter->Update();
+  std::vector<typename SliceType::Pointer> leftBronchusSlices;
+  extractSliceFilter->GetOutputSlices(leftBronchusSlices);
+  
+  // Right Bronchus slices
+  extractSliceFilter = ExtractSliceFilterType::New();
+  extractSliceFilter->SetInput(rightBronchus);
+  extractSliceFilter->SetDirection(2);
+  extractSliceFilter->Update();
+  std::vector<typename SliceType::Pointer> rightBronchusSlices ;
+  extractSliceFilter->GetOutputSlices(rightBronchusSlices);
+  
+  assert(leftBronchusSlices.size() == rightBronchusSlices.size());
+  
+  std::vector<MaskImageType::PointType> leftPoints;
+  std::vector<MaskImageType::PointType> rightPoints;
+  for(uint i=0; i<leftBronchusSlices.size(); i++) {
+    // Keep main CCL
+    leftBronchusSlices[i] = Labelize<SliceType>(leftBronchusSlices[i], 0, true, 10);
+    leftBronchusSlices[i] = KeepLabels<SliceType>(leftBronchusSlices[i], 
+                                                  GetBackgroundValue(), 
+                                                  GetForegroundValue(), 1, 1, true);
+    rightBronchusSlices[i] = Labelize<SliceType>(rightBronchusSlices[i], 0, true, 10);
+    rightBronchusSlices[i] = KeepLabels<SliceType>(rightBronchusSlices[i], 
+                                                   GetBackgroundValue(), 
+                                                   GetForegroundValue(), 1, 1, true);
+    double distance_max_from_center_point = 15;
+
+    // ------- Find point in left Bronchus ------- 
+    // find right most point in left  = rightMost
+    SliceType::PointType a;
+    SliceType::PointType rightMost = 
+      clitk::FindExtremaPointInAGivenDirection<SliceType>(leftBronchusSlices[i], 
+                                                          GetBackgroundValue(), 
+                                                          0, false, a, 0);
+    // find post most point in left, not far away from rightMost
+    SliceType::PointType p = 
+      clitk::FindExtremaPointInAGivenDirection<SliceType>(leftBronchusSlices[i], 
+                                                          GetBackgroundValue(), 
+                                                          1, false, rightMost, 
+                                                          distance_max_from_center_point);
+    MaskImageType::PointType pp;
+    pp[0] = p[0]; pp[1] = p[1];
+    pp[2] = i*leftBronchus->GetSpacing()[2] + leftBronchus->GetOrigin()[2];
+    leftPoints.push_back(pp);
+
+    // ------- Find point in right Bronchus ------- 
+    // find left most point in right  = leftMost
+    SliceType::PointType leftMost = 
+      clitk::FindExtremaPointInAGivenDirection<SliceType>(rightBronchusSlices[i], 
+                                                          GetBackgroundValue(), 
+                                                          0, true, a, 0);
+    // find post most point in left, not far away from leftMost
+    p = clitk::FindExtremaPointInAGivenDirection<SliceType>(rightBronchusSlices[i], 
+                                                            GetBackgroundValue(), 
+                                                            1, false, leftMost, 
+                                                            distance_max_from_center_point);
+    pp[0] = p[0]; pp[1] = p[1];
+    pp[2] = i*rightBronchus->GetSpacing()[2] + rightBronchus->GetOrigin()[2];
+    rightPoints.push_back(pp);
+  }
+
+  // DEBUG
+  std::ofstream osl;
+  openFileForWriting(osl, "left.txt");
+  osl << "LANDMARKS1" << std::endl;
+  std::ofstream osr;
+  openFileForWriting(osr, "right.txt");
+  osr << "LANDMARKS1" << std::endl;
+  for(uint i=0; i<leftBronchusSlices.size(); i++) {
+    osl << i << " " << leftPoints[i][0] << " " << leftPoints[i][1] 
+        << " " << leftPoints[i][2] << " 0 0 " << std::endl;
+    osr << i << " " << rightPoints[i][0] << " " << rightPoints[i][1] 
+        << " " << rightPoints[i][2] << " 0 0 " << std::endl;
+  }
+  osl.close();
+  osr.close();
+
+  // Now uses these points to limit, slice by slice 
+  // http://www.gamedev.net/community/forums/topic.asp?topic_id=542870
+  /*
+    Assuming the points are (Ax,Ay) (Bx,By) and (Cx,Cy), you need to compute:
+    (Bx - Ax) * (Cy - Ay) - (By - Ay) * (Cx - Ax)
+    This will equal zero if the point C is on the line formed by points A and B, and will have a different sign depending on the side. Which side this is depends on the orientation of your (x,y) coordinates, but you can plug test values for A,B and C into this formula to determine whether negative values are to the left or to the right.
+
+    => to accelerate, start with formula, when change sign -> stop and fill
+  */
+  //  typedef itk::ImageSliceIteratorWithIndex<MaskImageType> SliceIteratorType;
+  iter = SliceIteratorType(m_working_mediastinum, m_working_mediastinum->GetLargestPossibleRegion());
+  iter.SetFirstDirection(0);
+  iter.SetSecondDirection(1);
+  iter.GoToBegin();
+  int i=0;
+  MaskImageType::PointType A;
+  MaskImageType::PointType B;
+  MaskImageType::PointType C;
+  while (!iter.IsAtEnd()) {
+    A = leftPoints[i];
+    B = rightPoints[i];
+    C = A;
+    C[1] -= 10; // I know I must keep this point
+    double s = (B[0] - A[0]) * (C[1] - A[1]) - (B[1] - A[1]) * (C[0] - A[0]);
+    bool isPositive = s<0;
+    while (!iter.IsAtEndOfSlice()) {
+      while (!iter.IsAtEndOfLine()) {
+        // Very slow, I know ... but image should be very small
+        m_working_mediastinum->TransformIndexToPhysicalPoint(iter.GetIndex(), C);
+        double s = (B[0] - A[0]) * (C[1] - A[1]) - (B[1] - A[1]) * (C[0] - A[0]);
+        if (s == 0) iter.Set(2);
+        if (isPositive) {
+          if (s > 0) iter.Set(GetBackgroundValue());
+        }
+        else {
+          if (s < 0) iter.Set(GetBackgroundValue());
+        }
+        ++iter;
+      }
+      iter.NextLine();
+    }
+    iter.NextSlice();
+    ++i;
+  }
+
+  //-----------------------------------------------------
+  //-----------------------------------------------------
+  // StartNewStep("Anterior limits");  
+
+  // MISSING FROM NOW 
+  
+  // Station 4R, Station 4L, the right pulmonary artery, and/or the
+  // left superior pulmonary vein
+
+
+  //-----------------------------------------------------
+  //-----------------------------------------------------
+  // ALSO SUBSTRACT ARTERY/VEIN (initially in the support)
+
+  
+  // Set output image information (required)
+  MaskImagePointer outputImage = this->GetOutput(0);
+  outputImage->SetRegions(m_working_mediastinum->GetLargestPossibleRegion());
+  outputImage->SetOrigin(m_working_mediastinum->GetOrigin());
+  outputImage->SetRequestedRegion(m_working_mediastinum->GetLargestPossibleRegion());
+
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class TImageType>
+void 
+clitk::ExtractLymphStationsFilter<TImageType>::
+GenerateInputRequestedRegion() {
+  DD("GenerateInputRequestedRegion");
+  // Call default
+  //  Superclass::GenerateInputRequestedRegion();
+  // Following needed because output region can be greater than input (trachea)
+  //ImagePointer mediastinum = dynamic_cast<TImageType*>(itk::ProcessObject::GetInput(0));
+  //ImagePointer trachea = dynamic_cast<TImageType*>(itk::ProcessObject::GetInput(1));
+  DD("set reg");
+  m_mediastinum->SetRequestedRegion(m_mediastinum->GetLargestPossibleRegion());
+  m_trachea->SetRequestedRegion(m_trachea->GetLargestPossibleRegion());
+  DD("end");
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class TImageType>
+void 
+clitk::ExtractLymphStationsFilter<TImageType>::
+GenerateData() {
+  DD("GenerateData");
+  // Final Step -> graft output (if SetNthOutput => redo)
+  this->GraftOutput(m_output);
+}
+//--------------------------------------------------------------------
+  
+
+#endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX
index 801aeeb6725f46909482559666fbd9dc657c4d81..1823e998c40cf228444cb29439c5adc760d5cd0e 100644 (file)
@@ -3,7 +3,7 @@
 
   Authors belong to: 
   - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://www.centreleonberard.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
@@ -14,7 +14,7 @@
 
   - 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
@@ -55,6 +55,7 @@ ExtractLymphStationsFilter():
   // Default values
   ExtractStation_8_SetDefaultValues();
   ExtractStation_3P_SetDefaultValues();
+  ExtractStation_2RL_SetDefaultValues();
   ExtractStation_3A_SetDefaultValues();
   ExtractStation_7_SetDefaultValues();
 }
@@ -83,6 +84,12 @@ GenerateOutputInformation() {
   ExtractStation_3P();
   StopSubStep();
 
+  // Extract Station2RL
+  StartNewStep("Station 2RL");
+  StartSubStep(); 
+  ExtractStation_2RL();
+  StopSubStep();
+
   // Extract Station3A
   StartNewStep("Station 3A");
   StartSubStep(); 
@@ -102,20 +109,6 @@ GenerateOutputInformation() {
     //ExtractStation_4RL();
     StopSubStep();
   }
-
-
-  //
-  //  typedef clitk::BooleanOperatorLabelImageFilter<MaskImageType> BFilter;
-  //BFilter::Pointer merge = BFilter::New();  
-  // writeImage<MaskImageType>(m_Output, "ouput.mhd");
-  //writeImage<MaskImageType>(m_Working_Support, "ws.mhd");
-  /*merge->SetInput1(m_Station7);
-    merge->SetInput2(m_Station4RL); // support
-    merge->SetOperationType(BFilter::AndNot); CHANGE OPERATOR
-    merge->SetForegroundValue(4);
-    merge->Update();
-    m_Output = merge->GetOutput();
-  */
 }
 //--------------------------------------------------------------------
 
@@ -275,6 +268,7 @@ ExtractStation_3A()
   if (CheckForStation("3A")) {
     ExtractStation_3A_SI_Limits();
     ExtractStation_3A_Ant_Limits();
+    ExtractStation_3A_Post_Limits();
     // Store image filenames into AFDB 
     writeImage<MaskImageType>(m_ListOfStations["3A"], "seg/Station3A.mhd");
     GetAFDB()->SetImageFilename("Station3A", "seg/Station3A.mhd"); 
@@ -284,6 +278,32 @@ ExtractStation_3A()
 //--------------------------------------------------------------------
 
 
+//--------------------------------------------------------------------
+template <class TImageType>
+void 
+clitk::ExtractLymphStationsFilter<TImageType>::
+ExtractStation_2RL()
+{
+  if (CheckForStation("2RL")) {
+    ExtractStation_2RL_SI_Limits();
+    ExtractStation_2RL_Post_Limits();
+    ExtractStation_2RL_Ant_Limits2();
+    ExtractStation_2RL_Ant_Limits(); 
+    ExtractStation_2RL_LR_Limits(); 
+    ExtractStation_2RL_Remove_Structures(); 
+    ExtractStation_2RL_SeparateRL(); 
+    
+    // Store image filenames into AFDB 
+    writeImage<MaskImageType>(m_ListOfStations["2R"], "seg/Station2R.mhd");
+    writeImage<MaskImageType>(m_ListOfStations["2L"], "seg/Station2L.mhd");
+    GetAFDB()->SetImageFilename("Station2R", "seg/Station2R.mhd"); 
+    GetAFDB()->SetImageFilename("Station2L", "seg/Station2L.mhd"); 
+    WriteAFDB(); 
+  }
+}
+//--------------------------------------------------------------------
+
+
 //--------------------------------------------------------------------
 template <class TImageType>
 void 
@@ -305,10 +325,10 @@ ExtractStation_4RL() {
 template <class ImageType>
 void 
 clitk::ExtractLymphStationsFilter<ImageType>::
-Remove_Structures(std::string s)
+Remove_Structures(std::string station, std::string s)
 {
   try {
-    StartNewStep("[Station7] Remove "+s);  
+    StartNewStep("[Station"+station+"] Remove "+s);  
     MaskImagePointer Structure = GetAFDB()->template GetImage<MaskImageType>(s);
     clitk::AndNot<MaskImageType>(m_Working_Support, Structure, GetBackgroundValue());
   }
@@ -319,5 +339,38 @@ Remove_Structures(std::string s)
 //--------------------------------------------------------------------
 
 
+//--------------------------------------------------------------------
+template <class TImageType>
+void 
+clitk::ExtractLymphStationsFilter<TImageType>::
+SetFuzzyThreshold(std::string station, std::string tag, double value)
+{
+  m_FuzzyThreshold[station][tag] = value;
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class TImageType>
+double 
+clitk::ExtractLymphStationsFilter<TImageType>::
+GetFuzzyThreshold(std::string station, std::string tag)
+{
+  if (m_FuzzyThreshold.find(station) == m_FuzzyThreshold.end()) {
+    clitkExceptionMacro("Could not find options for station "+station+" in the list (while searching for tag "+tag+").");
+    return 0.0;
+  }
+
+  if (m_FuzzyThreshold[station].find(tag) == m_FuzzyThreshold[station].end()) {
+    clitkExceptionMacro("Could not find options "+tag+" in the list of FuzzyThreshold for station "+station+".");
+    return 0.0;
+  }
+  
+  return m_FuzzyThreshold[station][tag]; 
+}
+//--------------------------------------------------------------------
+
+
+
 
 #endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX
diff --git a/segmentation/clitkExtractLymphStationsFilter.txx.save b/segmentation/clitkExtractLymphStationsFilter.txx.save
new file mode 100644 (file)
index 0000000..a7b3244
--- /dev/null
@@ -0,0 +1,289 @@
+/*=========================================================================
+  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 "clitkSegmentationUtils.h"
+#include "clitkAutoCropFilter.h"
+#include "clitkSegmentationUtils.h"
+#include "clitkSliceBySliceRelativePositionFilter.h"
+
+// itk
+#include <itkStatisticsLabelMapFilter.h>
+#include <itkLabelImageToStatisticsLabelMapFilter.h>
+#include <itkRegionOfInterestImageFilter.h>
+#include <itkBinaryThresholdImageFilter.h>
+#include <itkImageSliceConstIteratorWithIndex.h>
+#include <itkBinaryThinningImageFilter.h>
+
+// itk ENST
+#include "RelativePositionPropImageFilter.h"
+
+//--------------------------------------------------------------------
+template <class TImageType>
+clitk::ExtractLymphStationsFilter<TImageType>::
+ExtractLymphStationsFilter():
+  clitk::FilterBase(),
+  clitk::FilterWithAnatomicalFeatureDatabaseManagement(),
+  itk::ImageToImageFilter<TImageType, MaskImageType>()
+{
+  this->SetNumberOfRequiredInputs(1);
+  SetBackgroundValue(0);
+  SetForegroundValue(1);
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class TImageType>
+void 
+clitk::ExtractLymphStationsFilter<TImageType>::
+GenerateOutputInformation() { 
+  //  Superclass::GenerateOutputInformation();
+  
+  // Get input
+  LoadAFDB();
+  m_mediastinum = GetAFDB()->template GetImage <MaskImageType>("mediastinum");  
+  m_trachea = GetAFDB()->template GetImage <MaskImageType>("trachea");  
+  ImagePointType carina;
+  GetAFDB()->GetPoint3D("carina", carina);
+  DD(carina);
+  m_CarinaZPositionInMM = carina[2];
+  DD(m_CarinaZPositionInMM);
+  ImagePointType mlb;
+  GetAFDB()->GetPoint3D("middleLobeBronchus", mlb);
+  m_MiddleLobeBronchusZPositionInMM = mlb[2];
+  DD(m_MiddleLobeBronchusZPositionInMM);
+
+  // ----------------------------------------------------------------
+  // ----------------------------------------------------------------
+  // Superior limit = carina
+  // Inferior limit = origin right middle lobe bronchus
+  StartNewStep("Inf/Sup mediastinum limits with carina/bronchus");
+  ImageRegionType region = m_mediastinum->GetLargestPossibleRegion(); DD(region);
+  ImageSizeType size = region.GetSize();
+  ImageIndexType index = region.GetIndex();
+  DD(m_CarinaZPositionInMM);
+  DD(m_MiddleLobeBronchusZPositionInMM);
+  index[2] = floor((m_MiddleLobeBronchusZPositionInMM - m_mediastinum->GetOrigin()[2]) / m_mediastinum->GetSpacing()[2]);
+  size[2] = 1+ceil((m_CarinaZPositionInMM-m_MiddleLobeBronchusZPositionInMM) / m_mediastinum->GetSpacing()[2]); // +1 to 
+  region.SetSize(size);
+  region.SetIndex(index);
+  DD(region);
+  typedef itk::RegionOfInterestImageFilter<MaskImageType, MaskImageType> 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<MaskImageType>(m_working_image, 0); 
+  StopCurrentStep<MaskImageType>(m_working_image);
+  m_output = m_working_image;
+
+  // ----------------------------------------------------------------
+  // ----------------------------------------------------------------
+  // Separate trachea in two CCL
+  StartNewStep("Separate trachea under carina");
+  // 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<MaskImageType, MaskImageType> 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<MaskImageType>(m_working_trachea, 0, true, 1);
+
+  // Detect wich label is at Left
+  typedef itk::ImageSliceConstIteratorWithIndex<MaskImageType> SliceIteratorType;
+  SliceIteratorType iter(m_working_trachea, m_working_trachea->GetLargestPossibleRegion());
+  iter.SetFirstDirection(0);
+  iter.SetSecondDirection(1);
+  iter.GoToBegin();
+  bool stop = false;
+  ImagePixelType leftLabel;
+  ImagePixelType rightLabel;
+  while (!stop) {
+    if (iter.Get() != GetBackgroundValue()) {
+      //     DD(iter.GetIndex());
+      //       DD((int)iter.Get());
+      leftLabel = iter.Get();
+      stop = true;
+    }
+    ++iter;
+  }
+  if (leftLabel == 1) rightLabel = 2;
+  else rightLabel = 1;
+  DD((int)leftLabel);
+  DD((int)rightLabel);  
+
+  // End step
+  StopCurrentStep<MaskImageType>(m_working_trachea);
+  
+  //-----------------------------------------------------
+  /*  DD("TEST Skeleton");
+  typedef itk::BinaryThinningImageFilter<MaskImageType, MaskImageType> SkeletonFilterType;
+  typename SkeletonFilterType::Pointer skeletonFilter = SkeletonFilterType::New();
+  skeletonFilter->SetInput(m_working_trachea);
+  skeletonFilter->Update();
+  writeImage<MaskImageType>(skeletonFilter->GetOutput(), "skel.mhd");
+  writeImage<MaskImageType>(skeletonFilter->GetThinning(), "skel2.mhd");  
+  */
+
+  //-----------------------------------------------------
+  StartNewStep("Left limits with bronchus (slice by slice)");  
+  // Select LeftLabel (set right label to 0)
+  MaskImagePointer temp = SetBackground<MaskImageType, MaskImageType>(m_working_trachea, m_working_trachea, rightLabel, 0);
+  writeImage<MaskImageType>(temp, "temp1.mhd");
+
+  m_working_image = 
+    clitk::SliceBySliceRelativePosition<MaskImageType>(m_working_image, 
+                                                      temp, 
+                                                      2, GetFuzzyThreshold(), "RightTo");
+  /*
+  typedef clitk::SliceBySliceRelativePositionFilter<MaskImageType> SliceRelPosFilterType;
+  typename SliceRelPosFilterType::Pointer sliceRelPosFilter = SliceRelPosFilterType::New();
+  sliceRelPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId());
+  sliceRelPosFilter->VerboseStepOn();
+  sliceRelPosFilter->WriteStepOn();
+  sliceRelPosFilter->SetInput(m_working_image);
+  sliceRelPosFilter->SetInputObject(temp);
+  sliceRelPosFilter->SetDirection(2);
+  sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThreshold());
+  sliceRelPosFilter->SetOrientationTypeString("RightTo");
+  sliceRelPosFilter->Update();
+  m_working_image = sliceRelPosFilter->GetOutput();*/
+  writeImage<MaskImageType>(m_working_image, "afterslicebyslice.mhd");
+
+
+  typedef clitk::SliceBySliceRelativePositionFilter<MaskImageType> SliceRelPosFilterType;
+  typename SliceRelPosFilterType::Pointer sliceRelPosFilter = SliceRelPosFilterType::New();
+
+
+  //-----------------------------------------------------
+  StartNewStep("Right limits with bronchus (slice by slice)");
+  // Select LeftLabel (set right label to 0)
+  temp = SetBackground<MaskImageType, MaskImageType>(m_working_trachea, m_working_trachea, leftLabel, 0);
+  writeImage<MaskImageType>(temp, "temp2.mhd");
+
+  sliceRelPosFilter = SliceRelPosFilterType::New();
+  sliceRelPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId());
+  sliceRelPosFilter->VerboseStepOff();
+  sliceRelPosFilter->WriteStepOff();
+  sliceRelPosFilter->SetInput(m_working_image);
+  sliceRelPosFilter->SetInputObject(temp);
+  sliceRelPosFilter->SetDirection(2);
+  sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThreshold());
+  sliceRelPosFilter->SetOrientationTypeString("LeftTo");
+  sliceRelPosFilter->Update();
+  m_working_image = sliceRelPosFilter->GetOutput();
+  writeImage<MaskImageType>(m_working_image, "afterslicebyslice.mhd");
+  DD("end");
+  m_output = m_working_image;
+  StopCurrentStep<MaskImageType>(m_output);
+
+  //-----------------------------------------------------
+  StartNewStep("Trial Post position according to trachea");
+  // Post: do not extend past the post wall of the 2 main bronchi
+  sliceRelPosFilter = SliceRelPosFilterType::New();
+  sliceRelPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId());
+  sliceRelPosFilter->VerboseStepOn();
+  sliceRelPosFilter->WriteStepOn();
+  sliceRelPosFilter->SetInput(m_output);
+  sliceRelPosFilter->SetInputObject(m_trachea);
+  sliceRelPosFilter->SetDirection(2);
+  sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThreshold());
+  // It means "not PostTo" (different from AntTo)
+  sliceRelPosFilter->NotFlagOn();
+  //sliceRelPosFilter->SetOrientationType(SliceRelPosFilterType::RelPosFilterType::PostTo);
+  sliceRelPosFilter->SetOrientationTypeString("PostTo");
+  sliceRelPosFilter->Update();
+  m_output = sliceRelPosFilter->GetOutput();
+  writeImage<MaskImageType>(m_output, "postrelpos.mhd");
+
+
+  // Set output image information (required)
+  MaskImagePointer 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 <class TImageType>
+void 
+clitk::ExtractLymphStationsFilter<TImageType>::
+GenerateInputRequestedRegion() {
+  DD("GenerateInputRequestedRegion");
+  // Call default
+  //  Superclass::GenerateInputRequestedRegion();
+  // Following needed because output region can be greater than input (trachea)
+  //ImagePointer mediastinum = dynamic_cast<TImageType*>(itk::ProcessObject::GetInput(0));
+  //ImagePointer trachea = dynamic_cast<TImageType*>(itk::ProcessObject::GetInput(1));
+  DD("set reg");
+  m_mediastinum->SetRequestedRegion(m_mediastinum->GetLargestPossibleRegion());
+  m_trachea->SetRequestedRegion(m_trachea->GetLargestPossibleRegion());
+  DD("end");
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class TImageType>
+void 
+clitk::ExtractLymphStationsFilter<TImageType>::
+GenerateData() {
+  DD("GenerateData");
+  // Final Step -> graft output (if SetNthOutput => redo)
+  this->GraftOutput(m_output);
+}
+//--------------------------------------------------------------------
+  
+
+#endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX
index 389e68dd96668a728f732becfd7f6757eba0c18d..afeb66b0d7e9a4e7de851e71516cb89c732ecd8e 100644 (file)
@@ -3,7 +3,7 @@
 
   Authors belong to: 
   - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://www.centreleonberard.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
@@ -14,7 +14,7 @@
 
   - 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
index 977cf93444e3a442139a3e0daaa2c0f63e8b63be..ffa6c3c87e6a668373182b87b629a3a47040fd75 100644 (file)
@@ -3,7 +3,7 @@
 
   Authors belong to: 
   - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://www.centreleonberard.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
@@ -14,7 +14,7 @@
 
   - 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
@@ -68,8 +68,10 @@ SetOptionsFromArgsInfoToFilter(FilterType * f)
   f->SetWriteStepFlag(mArgsInfo.writeStep_flag);
   f->SetVerboseMemoryFlag(mArgsInfo.verboseMemory_flag);
   f->SetAFDBFilename(mArgsInfo.afdb_arg);  
+
+  // Station 8
   f->SetDistanceMaxToAnteriorPartOfTheSpine(mArgsInfo.maxAntSpine_arg);
-  f->SetFuzzyThresholdForS8(mArgsInfo.fuzzyThresholdForS8_arg);
+  f->SetFuzzyThreshold("8", "Esophagus", mArgsInfo.tS8_Esophagus_arg);
   f->SetInjectedThresholdForS8(mArgsInfo.injectedThresholdForS8_arg);
 
   // Check multiple options for radius dilatation
@@ -110,12 +112,24 @@ SetOptionsFromArgsInfoToFilter(FilterType * f)
     f->AddComputeStation(mArgsInfo.station_arg[i]);
 
   // Station 7
-  f->SetFuzzyThresholdForS7("Bronchi", mArgsInfo.tS7_Bronchi_arg);
-  f->SetFuzzyThresholdForS7("LeftSuperiorPulmonaryVein", mArgsInfo.tS7_LeftSuperiorPulmonaryVein_arg);
-  f->SetFuzzyThresholdForS7("RightSuperiorPulmonaryVein", mArgsInfo.tS7_RightSuperiorPulmonaryVein_arg);
-  f->SetFuzzyThresholdForS7("RightPulmonaryArtery", mArgsInfo.tS7_RightPulmonaryArtery_arg);
-  f->SetFuzzyThresholdForS7("LeftPulmonaryArtery", mArgsInfo.tS7_LeftPulmonaryArtery_arg);
-  f->SetFuzzyThresholdForS7("SVC", mArgsInfo.tS7_SVC_arg);
+  f->SetFuzzyThreshold("7", "Bronchi", mArgsInfo.tS7_Bronchi_arg);
+  f->SetFuzzyThreshold("7", "LeftSuperiorPulmonaryVein", mArgsInfo.tS7_LeftSuperiorPulmonaryVein_arg);
+  f->SetFuzzyThreshold("7", "RightSuperiorPulmonaryVein", mArgsInfo.tS7_RightSuperiorPulmonaryVein_arg);
+  f->SetFuzzyThreshold("7", "RightPulmonaryArtery", mArgsInfo.tS7_RightPulmonaryArtery_arg);
+  f->SetFuzzyThreshold("7", "LeftPulmonaryArtery", mArgsInfo.tS7_LeftPulmonaryArtery_arg);
+  f->SetFuzzyThreshold("7", "SVC", mArgsInfo.tS7_SVC_arg);
+
+  // Station 3A
+  f->SetFuzzyThreshold("3A", "Sternum", mArgsInfo.tS3A_Sternum_arg);
+  f->SetFuzzyThreshold("3A", "SubclavianArtery", mArgsInfo.tS3A_SubclavianArtery_arg);
+  
+  // Station 2RL
+  f->SetFuzzyThreshold("2RL", "CommonCarotidArtery", mArgsInfo.tS2RL_CommonCarotidArtery_arg);
+  f->SetFuzzyThreshold("2RL", "BrachioCephalicTrunk", mArgsInfo.tS2RL_BrachioCephalicTrunk_arg);
+  f->SetFuzzyThreshold("2RL", "BrachioCephalicVein", mArgsInfo.tS2RL_BrachioCephalicVein_arg);
+  f->SetFuzzyThreshold("2RL", "Aorta", mArgsInfo.tS2RL_Aorta_arg);
+  f->SetFuzzyThreshold("2RL", "SubclavianArteryLeft", mArgsInfo.tS2RL_SubclavianArteryLeft_arg);
+  f->SetFuzzyThreshold("2RL", "SubclavianArteryRight", mArgsInfo.tS2RL_SubclavianArteryRight_arg);
 }
 //--------------------------------------------------------------------
 
index 8ff1943d708a6fde111c3ef27647b28b59489276..b612fd3f7eba02ba344e2e814bdafbcf944dcfa1 100644 (file)
@@ -3,7 +3,7 @@
 
   Authors belong to: 
   - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://www.centreleonberard.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
 
   - 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"
 #include "clitkFilterWithAnatomicalFeatureDatabaseManagement.h"
+#include "clitkSegmentationUtils.h"
 
 namespace clitk {
   
old mode 100755 (executable)
new mode 100644 (file)
index 5522766..613f10b
@@ -3,7 +3,7 @@
 
   Authors belong to: 
   - University of LYON              http://www.universite-lyon.fr/
-  - Léon Bérard cancer center       http://www.centreleonberard.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
 
   - BSD        See included LICENSE.txt file
   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
-===========================================================================**/
+======================================================================-====*/
 #ifndef clitkReconstructThroughDilationImageFilter_txx
 #define clitkReconstructThroughDilationImageFilter_txx
 
-/* =================================================
- * @file   clitkReconstructThroughDilationImageFilter.txx
- * @author 
- * @date   
- * 
- * @brief 
- * 
- ===================================================*/
-
-
 namespace clitk
 {
 
diff --git a/segmentation/clitkTestArtery.cxx b/segmentation/clitkTestArtery.cxx
new file mode 100644 (file)
index 0000000..8e36523
--- /dev/null
@@ -0,0 +1,39 @@
+/*=========================================================================
+  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 "clitkCommon.h"
+
+//--------------------------------------------------------------------
+int main(int argc, char * argv[])
+{
+  // Typedef
+  typedef uchar MaskImagePixelType; 
+  typedef short ImagePixelType;
+  typedef itk::Image<ImagePixelType, 3> ImageType;
+  typedef itk::Image<MaskImagePixelType, 3> MaskImageType;
+  
+  // Input
+  
+  
+
+
+
+  return EXIT_SUCCESS;
+} // This is the end, my friend
+//--------------------------------------------------------------------
diff --git a/segmentation/clitkTestFilter.cxx b/segmentation/clitkTestFilter.cxx
new file mode 100644 (file)
index 0000000..64716ed
--- /dev/null
@@ -0,0 +1,523 @@
+
+/*=========================================================================
+  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"
+//#include "clitkTestStation7.h"
+#include "clitkSegmentationUtils.h"
+#include "clitkMorphoMathFilter.h"
+
+// ITK ENST
+#include "RelativePositionPropImageFilter.h"
+
+// VTK
+#include <vtkSmartPointer.h>
+#include <vtkPolyData.h>
+#include <vtkCellArray.h>
+#include <vtkPolyDataWriter.h>
+#include <vtkImageData.h>
+#include <vtkMetaImageWriter.h>
+#include <vtkPolyDataToImageStencil.h>
+#include <vtkLinearExtrusionFilter.h>
+#include <vtkImageStencil.h>
+
+#include <algorithm>
+
+
+template<class PointType>
+class comparePointsX {
+public:
+  bool operator() (PointType i, PointType j) { return (i[0]<j[0]); }
+};
+
+template<int Dim>
+void HypercubeCorners(std::vector<itk::Point<double, Dim> > & out) {
+  std::vector<itk::Point<double, Dim-1> > previous;
+  HypercubeCorners<Dim-1>(previous);
+  out.resize(previous.size()*2);
+  for(uint i=0; i<out.size(); i++) {
+    itk::Point<double, Dim> p;
+    if (i<previous.size()) p[0] = 0; 
+    else p[0] = 1;
+    for(int j=0; j<Dim; j++) p[j+1] = previous[i%previous.size()][j]; //NON i p
+    out[i] = p;
+  }
+}
+
+template<>
+void HypercubeCorners<1>(std::vector<itk::Point<double, 1> > & out) {
+  out.resize(2);
+  out[0][0] = 0;
+  out[1][0] = 1;
+}
+
+
+//--------------------------------------------------------------------
+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<PixelType, Dim> InputImageType;
+
+  // Read inputs
+  InputImageType::Pointer input1;
+  InputImageType::Pointer input2;
+  InputImageType::Pointer input3;
+  if (args_info.input1_given) input1 = clitk::readImage<InputImageType>(args_info.input1_arg, true);
+  if (args_info.input2_given) input2 = clitk::readImage<InputImageType>(args_info.input2_arg, true);
+  if (args_info.input3_given) input3 = clitk::readImage<InputImageType>(args_info.input3_arg, true);
+  
+  // Declare output
+  InputImageType::Pointer output;
+
+  //--------------------------------------------------------------------
+  // Filter test BooleanOperatorLabelImageFilter
+  if (0) {
+    typedef clitk::BooleanOperatorLabelImageFilter<InputImageType> FilterType;
+    FilterType::Pointer filter = FilterType::New();
+    filter->SetInput1(input1);
+    filter->SetInput2(input2);
+    output = clitk::NewImageLike<InputImageType>(input1);
+    filter->GraftOutput(output);  /// TO VERIFY !!!
+    filter->Update();  
+    filter->SetInput2(input3);
+    filter->Update();    
+    output = filter->GetOutput();
+    clitk::writeImage<InputImageType>(output, args_info.output_arg);
+  }
+  
+  //--------------------------------------------------------------------
+  // Filter test AutoCropLabelImageFilter
+  if (0) {
+    typedef clitk::AutoCropFilter<InputImageType> FilterType;
+    FilterType::Pointer filter = FilterType::New();
+    filter->SetInput(input1);
+    filter->Update();    
+    output = filter->GetOutput();
+    clitk::writeImage<InputImageType>(output, args_info.output_arg);
+  }
+
+  //--------------------------------------------------------------------
+  // Filter test RelativePositionPropImageFilter
+  if (0) {
+    typedef itk::Image<float, Dim> OutputImageType;
+    OutputImageType::Pointer outputf;
+    typedef itk::RelativePositionPropImageFilter<InputImageType, OutputImageType> 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<OutputImageType>(filter->GetOutput(), args_info.output_arg);
+  }
+
+  //--------------------------------------------------------------------
+  // Filter test 
+  if (0) {
+    typedef itk::Image<short, Dim> OutputImageType;
+    typedef clitk::ResampleImageWithOptionsFilter<InputImageType, OutputImageType> FilterType;
+    FilterType::Pointer filter = FilterType::New();
+    filter->SetInput(input1); 
+    filter->SetOutputIsoSpacing(1);
+    //filter->SetNumberOfThreads(4); // auto
+    filter->SetGaussianFilteringEnabled(false);
+    filter->Update();    
+    clitk::writeImage<OutputImageType>(filter->GetOutput(), args_info.output_arg);
+  }
+
+  //--------------------------------------------------------------------
+  // Filter AddRelativePositionConstraintToLabelImageFilter test 
+  if (0) {
+    /*
+    typedef clitk::AddRelativePositionConstraintToLabelImageFilter<InputImageType> 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<InputImageType>(filter->GetOutput(), args_info.output_arg);
+    */
+  }
+
+  //--------------------------------------------------------------------
+  // Filter test ExtractPatientFilter
+  if (0) {
+    /*
+    typedef itk::Image<char, Dim> OutputImageType;
+    typedef clitk::ExtractPatientFilter<InputImageType, OutputImageType> 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<OutputImageType>(output, args_info.output_arg);
+    */
+  }
+
+  //--------------------------------------------------------------------
+  // Filter test ExtractLungsFilter
+  if (0) {
+    /*
+    typedef itk::Image<PixelType, Dim> OutputImageType; // to change into char
+    typedef clitk::ExtractLungFilter<InputImageType, OutputImageType> 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<OutputImageType>(output, args_info.output_arg);
+    */
+  }
+
+  //--------------------------------------------------------------------
+  // Filter test ExtractMediastinumFilter
+  if (0) {
+    /*
+    typedef clitk::ExtractMediastinumFilter<InputImageType> 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<InputImageType>(output, args_info.output_arg);
+    */
+  }
+
+  //--------------------------------------------------------------------
+  // Test for auto register sub-task in a segmentation process
+  if (0) {
+    // ExtractLymphStation_7 * s7 = new ExtractLymphStation_7;
+    //    s7->SetArgsInfo<args_info_clitkTestFilter>(args_info);
+    // GetParent->SetArgsInfo<>
+    //s7->StartSegmentation();
+  }
+
+  //--------------------------------------------------------------------
+  // Test for biinary image from a contour set
+  if (0) {
+    DD("here");
+
+    // Type of a slice
+    typedef itk::Image<InputImageType::PixelType, InputImageType::ImageDimension-1> SliceType;
+    
+    // Build the list of slices
+    std::vector<SliceType::Pointer> slices;
+    clitk::ExtractSlices<InputImageType>(input1, 2, slices);
+    DD(slices.size());
+
+    // HOW TO DO SEVERAL BY SLICE !!! not a map ?
+
+    // Compute centroids 3D centroids by slices
+    int BG = 0;
+    std::map<int, std::vector<InputImageType::PointType> > centroids3D;    
+    for(uint i=0; i<slices.size(); i++) {
+      // Labelize
+      slices[i] = clitk::Labelize<SliceType>(slices[i], BG, true, 1);
+      // ComputeCentroids
+      std::vector<SliceType::PointType> temp;
+      clitk::ComputeCentroids<SliceType>(slices[i], BG, temp);
+      for(uint j=1; j<temp.size(); j++) {
+        InputImageType::PointType a;
+        clitk::PointsUtils<InputImageType>::Convert2DTo3D(temp[j], input1, i, a);
+        centroids3D[i].push_back(a);
+      }
+    }
+
+    // REPRENDRE POUR TOUT FAIRE BY SLICE (pas de i);
+    
+    // Take a given slice i=29
+    int index=29;
+    SliceType::Pointer slice = slices[index];
+    std::vector<InputImageType::PointType> points = centroids3D[index];
+    
+    // Sort points from R to L
+    std::sort(points.begin(), points.end(), 
+              comparePointsX<InputImageType::PointType>());
+    
+    // Slice corners (quel sens ?)
+
+    // Compute min and max coordinates
+    const uint dim=3;
+    typedef InputImageType::PointType PointType;
+    typedef InputImageType::IndexType IndexType;
+    PointType min_c, max_c;
+    IndexType min_i, max_i;
+    min_i = input1->GetLargestPossibleRegion().GetIndex();
+    for(uint i=0; i<dim; i++) max_i[i] = input1->GetLargestPossibleRegion().GetSize()[i] + min_i[i];
+    input1->TransformIndexToPhysicalPoint(min_i, min_c);
+    input1->TransformIndexToPhysicalPoint(max_i, max_c);
+
+    // Compute the corners coordinates
+    std::vector<itk::Point<double, dim> > l;
+    HypercubeCorners<dim>(l);
+    for(uint i=0; i<l.size(); i++) {
+      for(uint j=0; j<dim; j++) {
+        if (l[i][j] == 0) l[i][j] = min_c[j];
+        if (l[i][j] == 1) l[i][j] = max_c[j];
+      }
+    }
+    DDV(l, 8);
+
+
+    // Add first/last point, horizontally to the image boundaries
+
+    double sz = points[0][2]; // slice Z
+    double margin = 2; // needed (if not forget to remove the first line)
+    // Corners 1
+    InputImageType::PointType p = min_c;
+    p[0] -= margin; // margins
+    p[1] -= margin; // margins
+    p[2] = sz;
+    points.insert(points.begin(), p);
+    // vertical p
+    p = points[0];
+    p[0] = min_c[0] - margin; //margin
+    points.insert(points.begin(), p);
+    // last H point
+    p = points.back();
+    p[0] = max_c[0];
+    points.push_back(p);
+    // last corners
+    p[0] = max_c[0];
+    p[1] = min_c[1]-margin;
+    p[2] = sz;
+    points.push_back(p);
+    // Same first point
+    p = points[0];
+    points.push_back(p);
+
+    DDV(points, points.size());
+
+    // create a contour, polydata. 
+    vtkSmartPointer<vtkPolyData> mesh = vtkSmartPointer<vtkPolyData>::New();
+    mesh->Allocate(); //for cell structures
+    mesh->SetPoints(vtkPoints::New());
+    vtkIdType ids[2];
+    int point_number = points.size();
+    for (unsigned int i=0; i<points.size(); i++) {
+      mesh->GetPoints()->InsertNextPoint(points[i][0],points[i][1],points[i][2]);
+      ids[0]=i;
+      ids[1]=(ids[0]+1)%point_number; //0-1,1-2,...,n-1-0
+      mesh->GetLines()->InsertNextCell(2,ids);
+    }
+
+    vtkSmartPointer<vtkPolyDataWriter> w = vtkSmartPointer<vtkPolyDataWriter>::New();
+    w->SetInput(mesh);
+    w->SetFileName("bidon.vtk");
+    w->Write();    
+
+    // binarize
+    DD("binarize");
+    double *bounds=mesh->GetBounds();
+    DDV(bounds, 6);
+
+    DD("create image");
+    vtkSmartPointer<vtkImageData> binary_image=vtkSmartPointer<vtkImageData>::New();
+    binary_image->SetScalarTypeToUnsignedChar();
+    ///Use the smallest mask in which the mesh fits
+    // Add two voxels on each side to make sure the mesh fits
+    //    double * samp_origin=
+    InputImageType::PointType samp_origin = input1->GetOrigin();
+    //    double * 
+    InputImageType::SpacingType spacing=input1->GetSpacing();
+    double * spacing2 = new double[3];
+    spacing2[0] = spacing[0];
+    spacing2[1] = spacing[1];
+    spacing2[2] = spacing[2];
+    DD(spacing2[0]);
+    binary_image->SetSpacing(spacing2);
+    /// Put the origin on a voxel to avoid small skips
+    DD(floor((bounds[0]-samp_origin[0])/spacing[0]-2)*spacing[0]);
+    DD(bounds[0]);
+    DD(samp_origin[0]);
+    DD(spacing[0]);
+    binary_image->SetOrigin(//samp_origin[0], samp_origin[1], samp_origin[2]);
+                            floor((bounds[0]-samp_origin[0])/spacing[0]-2)*spacing[0]+samp_origin[0],
+                            floor((bounds[2]-samp_origin[1])/spacing[1]-2)*spacing[1]+samp_origin[1],
+                            floor((bounds[4]-samp_origin[2])/spacing[2]-2)*spacing[2]+samp_origin[2]);
+    double * origin=binary_image->GetOrigin();
+    binary_image->SetExtent(0,ceil((bounds[1]-origin[0])/spacing[0]+4), // Joel used +4 here (?)
+                            0,ceil((bounds[3]-origin[1])/spacing[1]+4),
+                            0,ceil((bounds[5]-origin[2])/spacing[2]+4));
+    binary_image->AllocateScalars();
+    memset(binary_image->GetScalarPointer(),0,
+           binary_image->GetDimensions()[0]*binary_image->GetDimensions()[1]*binary_image->GetDimensions()[2]*sizeof(unsigned char));
+
+    vtkSmartPointer<vtkPolyDataToImageStencil> sts=vtkSmartPointer<vtkPolyDataToImageStencil>::New();
+    //The following line is extremely important
+    //http://www.nabble.com/Bug-in-vtkPolyDataToImageStencil--td23368312.html#a23370933
+    sts->SetTolerance(0);
+    sts->SetInformationInput(binary_image);
+    
+    bool extrude=true;
+    if (extrude) {
+      vtkSmartPointer<vtkLinearExtrusionFilter> extrude=vtkSmartPointer<vtkLinearExtrusionFilter>::New();
+      extrude->SetInput(mesh);
+      
+      /// NO ????We extrude in the -slice_spacing direction to respect the FOCAL convention ???
+
+      extrude->SetVector(0, 0, input1->GetSpacing()[2]);//slice_spacing); // 2* ? yes use a single one
+      sts->SetInput(extrude->GetOutput());
+    } else
+      sts->SetInput(mesh);
+
+    DD("stencil");
+    vtkSmartPointer<vtkImageStencil> stencil=vtkSmartPointer<vtkImageStencil>::New();
+    stencil->SetStencil(sts->GetOutput());
+    stencil->SetInput(binary_image);
+    stencil->Update();    
+    
+    DD("write");
+    vtkSmartPointer<vtkMetaImageWriter> ww = vtkSmartPointer<vtkMetaImageWriter>::New();
+    ww->SetInput(stencil->GetOutput());
+    ww->SetFileName("binary.mhd");
+    ww->Write();
+  }
+  //--------------------------------------------------------------------
+
+  //--------------------------------------------------------------------
+  // Test for vessels ReconstructionByDilatation
+  if (1) {
+    // Read input CT (already croped)
+    // treshold 3D
+    // erode n times (or in 2D ?)
+    // slices extract
+    // SBS
+    //    - CCL (keep mask)
+    //    - for all CCL, ReconstructionByDilatation in initial mask
+    // joint for output
+
+    // input1
+    DD("binarize")
+    int BG = 0;
+    int FG = 1;
+    typedef itk::Image<unsigned char, InputImageType::ImageDimension> MaskImageType;
+    typedef itk::BinaryThresholdImageFilter<InputImageType, MaskImageType> BinarizeFilterType; 
+    BinarizeFilterType::Pointer binarizeFilter = BinarizeFilterType::New();
+    binarizeFilter->SetInput(input1);
+    binarizeFilter->SetLowerThreshold(150);
+    binarizeFilter->SetInsideValue(FG);
+    binarizeFilter->SetOutsideValue(BG);
+    binarizeFilter->Update();
+    MaskImageType::Pointer mask = binarizeFilter->GetOutput();
+    clitk::writeImage<MaskImageType>(mask, "m.mhd");
+    
+    // Extract slices
+    typedef itk::Image<MaskImageType::PixelType, MaskImageType::ImageDimension-1> SliceType;
+    std::vector<SliceType> slices_mask;
+    clitk::ExtractSlices<MaskImageType>(mask, 2, slices_mask);
+    DD(slices_mask.size());
+
+    std::vector<SliceType> debug_eroded;
+    std::vector<SliceType> debug_labeled;
+    
+    // Loop
+    for(uint i=0; i<slices_mask.size(); i++) {
+      DD(i);
+      // erode
+      DD("erosion");
+      clitk::MorphoMathFilter<SliceType>::Pointer f = clitk::MorphoMathFilter<SliceType>::New();
+      f->SetInput(slices_mask[i]);
+      f->SetBackgroundValue(BG);
+      f->SetForegroundValue(FG);
+      f->SetRadius(1);
+      f->SetOperationType(0); // Erode
+      f->Update();
+      SliceType::Pointer eroded = f->GetOutput();
+      debug_eroded.push_back(eroded);
+      
+      // CCL
+      DD("CCL");
+      SliceType::Pointer labeled = Labelize<MaskSliceType>(slices_mask[i], 0, false, 10);
+      debug_labeled.push_back(labeled);
+      
+      // ReconstructionByDilatation 
+      
+      
+    } // end loop
+
+    MaskImageType::Pointer eroded = clitk::JoinSlices<MaskImageType>(debug_eroded, mask, 2);
+    clitk::writeImage<MaskImageType>(eroded, "eroded.mhd");
+
+    MaskImageType::Pointer labeled = clitk::JoinSlices<MaskImageType>(debug_labeled, mask, 2);
+    clitk::writeImage<MaskImageType>(labeled, "labeled.mhd");
+
+  }
+  //--------------------------------------------------------------------
+
+  // 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 (file)
index 0000000..6ab0ebb
--- /dev/null
@@ -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        no
+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        no
+
+option "angle1"        a       "First angle (degree)"            float         default = "0" no
+option "angle2"        b       "Second angle (degree)"           float         default = "0" no
+
old mode 100755 (executable)
new mode 100644 (file)
index 4931b5b..e8650de
@@ -15,9 +15,9 @@ option "input"                i       "Input image filename"            string        yes
 option "output"        o       "Output image filename"           string        yes
 
 section "Used determined crop"
-option "boundingBox"           b       "Bounding box of the crop region" int   no  multiple
-option "lower"         l       "Size of the lower crop region"   int   no  multiple
-option "upper"         u       "Size of the upper crop region"   int   no  multiple
+option "boundingBox"           b       "Bounding box of the crop region (in 2D: =x1,y2, x2,y2)"  int   no  multiple
+option "lower"         l       "Size of the lower crop region (multiple values)"         int   no  multiple
+option "upper"         u       "Size of the upper crop region (multiple values)"         int   no  multiple
 option "origin"        -       "Set new origin to zero"          flag  off  
 
 section "AutoCrop with BG value"