]> Creatis software - clitk.git/blobdiff - segmentation/clitkExtractLymphStationsFilter.txx
Merge branch 'master' of /home/dsarrut/clitk3.server
[clitk.git] / segmentation / clitkExtractLymphStationsFilter.txx
index b81ae07ab7e5748f0edf12ee673b03cced2d434e..58f2991d348426b184c92a37c6c7baf93848399a 100644 (file)
@@ -34,6 +34,7 @@
 #include <itkRegionOfInterestImageFilter.h>
 #include <itkBinaryThresholdImageFilter.h>
 #include <itkImageSliceConstIteratorWithIndex.h>
+#include <itkImageSliceIteratorWithIndex.h>
 #include <itkBinaryThinningImageFilter.h>
 
 // itk ENST
@@ -45,16 +46,18 @@ clitk::ExtractLymphStationsFilter<TImageType>::
 ExtractLymphStationsFilter():
   clitk::FilterBase(),
   clitk::FilterWithAnatomicalFeatureDatabaseManagement(),
-  itk::ImageToImageFilter<TImageType, TImageType>()
+  itk::ImageToImageFilter<TImageType, MaskImageType>()
 {
   this->SetNumberOfRequiredInputs(1);
-  SetBackgroundValueMediastinum(0);
-  SetBackgroundValueTrachea(0);
   SetBackgroundValue(0);
   SetForegroundValue(1);
-  SetIntermediateSpacing(6);
-  SetFuzzyThreshold1(0.6);  
-  m_CarinaZPositionInMMIsSet = false;
+
+  // Default values
+  ExtractStation_8_SetDefaultValues();
+  ExtractStation_3P_SetDefaultValues();
+  ExtractStation_2RL_SetDefaultValues();
+  ExtractStation_3A_SetDefaultValues();
+  ExtractStation_7_SetDefaultValues();
 }
 //--------------------------------------------------------------------
 
@@ -63,9 +66,57 @@ ExtractLymphStationsFilter():
 template <class TImageType>
 void 
 clitk::ExtractLymphStationsFilter<TImageType>::
-SetInputMediastinumLabelImage(const TImageType * image, ImagePixelType bg) {
-  this->SetNthInput(0, const_cast<TImageType *>(image));
-  SetBackgroundValueMediastinum(bg);
+GenerateOutputInformation() { 
+  // Get inputs
+  LoadAFDB();
+  m_Input = dynamic_cast<const ImageType*>(itk::ProcessObject::GetInput(0));
+  m_Mediastinum = GetAFDB()->template GetImage <MaskImageType>("Mediastinum");
+
+  // Global supports for stations
+  StartNewStep("Supports for stations");
+  StartSubStep(); 
+  ExtractStationSupports();
+  StopSubStep();  
+
+  // Extract Station8
+  StartNewStep("Station 8");
+  StartSubStep(); 
+  ExtractStation_8();
+  StopSubStep();
+
+  // Extract Station3P
+  StartNewStep("Station 3P");
+  StartSubStep(); 
+  ExtractStation_3P();
+  StopSubStep();
+
+  // Extract Station2RL
+  /*
+    StartNewStep("Station 2RL");
+    StartSubStep(); 
+    ExtractStation_2RL();
+    StopSubStep();
+  */
+
+  // Extract Station3A
+  StartNewStep("Station 3A");
+  StartSubStep(); 
+  ExtractStation_3A();
+  StopSubStep();
+
+  // Extract Station7
+  StartNewStep("Station 7");
+  StartSubStep();
+  ExtractStation_7();
+  StopSubStep();
+
+  if (0) { // temporary suppress
+    // Extract Station4RL
+    StartNewStep("Station 4RL");
+    StartSubStep();
+    //ExtractStation_4RL();
+    StopSubStep();
+  }
 }
 //--------------------------------------------------------------------
 
@@ -74,30 +125,74 @@ SetInputMediastinumLabelImage(const TImageType * image, ImagePixelType bg) {
 template <class TImageType>
 void 
 clitk::ExtractLymphStationsFilter<TImageType>::
-SetInputTracheaLabelImage(const TImageType * image, ImagePixelType bg) {
-  this->SetNthInput(1, const_cast<TImageType *>(image));
-  SetBackgroundValueTrachea(bg);
+GenerateInputRequestedRegion() {
+  //DD("GenerateInputRequestedRegion (nothing?)");
 }
 //--------------------------------------------------------------------
 
 
 //--------------------------------------------------------------------
 template <class TImageType>
-template<class ArgsInfoType>
 void 
 clitk::ExtractLymphStationsFilter<TImageType>::
-SetArgsInfo(ArgsInfoType mArgsInfo)
+GenerateData() {
+  // Final Step -> graft output (if SetNthOutput => redo)
+  this->GraftOutput(m_ListOfStations["8"]);
+}
+//--------------------------------------------------------------------
+  
+
+//--------------------------------------------------------------------
+template <class TImageType>
+bool 
+clitk::ExtractLymphStationsFilter<TImageType>::
+CheckForStation(std::string station) 
+{
+  // Compute Station name
+  std::string s = "Station"+station;
+  
+
+  // Check if station already exist in DB
+  bool found = false;
+  if (GetAFDB()->TagExist(s)) {
+    m_ListOfStations[station] = GetAFDB()->template GetImage<MaskImageType>(s);
+    found = true;
+  }
+
+  // Define the starting support 
+  if (found && GetComputeStation(station)) {
+    std::cout << "Station " << station << " already exists, but re-computation forced." << std::endl;
+  }
+  if (!found || GetComputeStation(station)) {
+    m_Working_Support = m_Mediastinum = GetAFDB()->template GetImage<MaskImageType>("Mediastinum", true);
+    return true;
+  }
+  else {
+    std::cout << "Station " << station << " found. I used it" << std::endl;
+    return false;
+  }
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class TImageType>
+bool
+clitk::ExtractLymphStationsFilter<TImageType>::
+GetComputeStation(std::string station) 
 {
-  SetVerboseOption_GGO(mArgsInfo);
-  SetVerboseStep_GGO(mArgsInfo);
-  SetWriteStep_GGO(mArgsInfo);
-  SetVerboseWarningOff_GGO(mArgsInfo);
-  SetAFDBFilename_GGO(mArgsInfo);
-  SetCarinaZPositionInMM_GGO(mArgsInfo);
-  m_CarinaZPositionInMMIsSet = false;
-  SetMiddleLobeBronchusZPositionInMM_GGO(mArgsInfo);
-  SetIntermediateSpacing_GGO(mArgsInfo);
-  SetFuzzyThreshold1_GGO(mArgsInfo);
+  return (m_ComputeStationMap.find(station) != m_ComputeStationMap.end());
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class TImageType>
+void
+clitk::ExtractLymphStationsFilter<TImageType>::
+AddComputeStation(std::string station) 
+{
+  m_ComputeStationMap[station] = true;
 }
 //--------------------------------------------------------------------
 
@@ -106,172 +201,67 @@ SetArgsInfo(ArgsInfoType mArgsInfo)
 template <class TImageType>
 void 
 clitk::ExtractLymphStationsFilter<TImageType>::
-GenerateOutputInformation() { 
-  //  Superclass::GenerateOutputInformation();
-  
-  // Get input
-  m_mediastinum = dynamic_cast<const TImageType*>(itk::ProcessObject::GetInput(0));
-  m_trachea = dynamic_cast<const TImageType*>(itk::ProcessObject::GetInput(1));
-
-  // Get landmarks information
-  if (!m_CarinaZPositionInMMIsSet) {
-    ImagePointType carina;
-    LoadAFDB();
-    GetAFDB()->GetPoint3D("Carina", carina);
-    DD(carina);
-    m_CarinaZPositionInMM = carina[2];
-  }
-  DD(m_CarinaZPositionInMM);
-
-  // ----------------------------------------------------------------
-  // ----------------------------------------------------------------
-  // 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<ImageType, ImageType> 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<ImageType>(m_working_image, 0); 
-  StopCurrentStep<ImageType>(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];
-    }
+ExtractStation_3P()
+{
+  if (CheckForStation("3P")) {
+    ExtractStation_3P_SI_Limits();
+    ExtractStation_3P_Ant_Limits();
+    ExtractStation_3P_Post_Limits();
+    ExtractStation_3P_LR_sup_Limits();
+    //    ExtractStation_3P_LR_sup_Limits_2();
+    ExtractStation_3P_LR_inf_Limits();
+    ExtractStation_8_Single_CCL_Limits(); // YES 8 !
+    ExtractStation_3P_Remove_Structures(); // after CCL
+    // Store image filenames into AFDB 
+    writeImage<MaskImageType>(m_ListOfStations["3P"], "seg/Station3P.mhd");
+    GetAFDB()->SetImageFilename("Station3P", "seg/Station3P.mhd"); 
+    WriteAFDB(); 
   }
-  // DD(index);
-  //   DD(size);
-  region.SetIndex(index);
-  region.SetSize(size);  
-  //  typedef itk::RegionOfInterestImageFilter<ImageType, ImageType> 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<ImageType>(m_working_trachea, 0, true, 1);
-
-  // Detect wich label is at Left
-  typedef itk::ImageSliceConstIteratorWithIndex<ImageType> 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() != m_BackgroundValueTrachea) {
-      //     DD(iter.GetIndex());
-      //       DD((int)iter.Get());
-      leftLabel = iter.Get();
-      stop = true;
-    }
-    ++iter;
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class TImageType>
+void 
+clitk::ExtractLymphStationsFilter<TImageType>::
+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"); 
+    WriteAFDB(); 
   }
-  if (leftLabel == 1) rightLabel = 2;
-  else rightLabel = 1;
-  DD((int)leftLabel);
-  DD((int)rightLabel);  
+}
+//--------------------------------------------------------------------
 
-  // End step
-  StopCurrentStep<ImageType>(m_working_trachea);
-  
-  //-----------------------------------------------------
-  /*  DD("TEST Skeleton");
-  typedef itk::BinaryThinningImageFilter<ImageType, ImageType> SkeletonFilterType;
-  typename SkeletonFilterType::Pointer skeletonFilter = SkeletonFilterType::New();
-  skeletonFilter->SetInput(m_working_trachea);
-  skeletonFilter->Update();
-  writeImage<ImageType>(skeletonFilter->GetOutput(), "skel.mhd");
-  writeImage<ImageType>(skeletonFilter->GetThinning(), "skel2.mhd");  
-  */
 
-  //-----------------------------------------------------
-  StartNewStep("Left limits with bronchus (slice by slice)");  
-  // Select LeftLabel (set right label to 0)
-  ImagePointer temp = SetBackground<ImageType, ImageType>(m_working_trachea, m_working_trachea, rightLabel, 0);
-  writeImage<ImageType>(temp, "temp1.mhd");
-
-  typedef clitk::SliceBySliceRelativePositionFilter<ImageType> 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(0.6);
-  sliceRelPosFilter->SetOrientationType(SliceRelPosFilterType::RelPosFilterType::RightTo);
-  sliceRelPosFilter->Update();
-  m_working_image = sliceRelPosFilter->GetOutput();
-  writeImage<ImageType>(m_working_image, "afterslicebyslice.mhd");
-
-
-  //-----------------------------------------------------
-  StartNewStep("Right limits with bronchus (slice by slice)");
-  // Select LeftLabel (set right label to 0)
-  temp = SetBackground<ImageType, ImageType>(m_working_trachea, m_working_trachea, leftLabel, 0);
-  writeImage<ImageType>(temp, "temp2.mhd");
-
-  sliceRelPosFilter = SliceRelPosFilterType::New();
-  sliceRelPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId());
-  sliceRelPosFilter->VerboseStepOn();
-  sliceRelPosFilter->WriteStepOn();
-  sliceRelPosFilter->SetInput(m_working_image);
-  sliceRelPosFilter->SetInputObject(temp);
-  sliceRelPosFilter->SetDirection(2);
-  sliceRelPosFilter->SetFuzzyThreshold(0.6);
-  sliceRelPosFilter->SetOrientationType(SliceRelPosFilterType::RelPosFilterType::LeftTo);
-  sliceRelPosFilter->Update();
-  m_working_image = sliceRelPosFilter->GetOutput();
-  writeImage<ImageType>(m_working_image, "afterslicebyslice.mhd");
-
-
-  DD("end");
-  m_output = m_working_image;
-  StopCurrentStep<ImageType>(m_output);
-
-  // Set output image information (required)
-  ImagePointer outputImage = this->GetOutput(0);
-  outputImage->SetRegions(m_working_image->GetLargestPossibleRegion());
-  outputImage->SetOrigin(m_working_image->GetOrigin());
-  outputImage->SetRequestedRegion(m_working_image->GetLargestPossibleRegion());
-  DD("end2");
+//--------------------------------------------------------------------
+template <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(); 
+  }
 }
 //--------------------------------------------------------------------
 
@@ -280,15 +270,33 @@ GenerateOutputInformation() {
 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));
-  mediastinum->SetRequestedRegion(mediastinum->GetLargestPossibleRegion());
-  trachea->SetRequestedRegion(trachea->GetLargestPossibleRegion());
+ExtractStation_4RL() {
+  DD("TODO");
+  exit(0);
+  /*
+    WARNING ONLY 4R FIRST !!! (not same inf limits)
+  */    
+  ExtractStation_4RL_SI_Limits();
+  ExtractStation_4RL_LR_Limits();
+  ExtractStation_4RL_AP_Limits();
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void 
+clitk::ExtractLymphStationsFilter<ImageType>::
+Remove_Structures(std::string station, std::string s)
+{
+  try {
+    StartNewStep("[Station"+station+"] Remove "+s);  
+    MaskImagePointer Structure = GetAFDB()->template GetImage<MaskImageType>(s);
+    clitk::AndNot<MaskImageType>(m_Working_Support, Structure, GetBackgroundValue());
+  }
+  catch(clitk::ExceptionObject e) {
+    std::cout << s << " not found, skip." << std::endl;
+  }
 }
 //--------------------------------------------------------------------
 
@@ -297,12 +305,199 @@ GenerateInputRequestedRegion() {
 template <class TImageType>
 void 
 clitk::ExtractLymphStationsFilter<TImageType>::
-GenerateData() {
-  DD("GenerateData");
-  // Final Step -> graft output (if SetNthOutput => redo)
-  this->GraftOutput(m_output);
+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]; 
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class TImageType>
+void
+clitk::ExtractLymphStationsFilter<TImageType>::
+FindLineForS7S8Separation(MaskImagePointType & A, MaskImagePointType & B)
+{
+  // Create line from A to B with
+  // A = upper border of LLL at left
+  // B = lower border of bronchus intermedius (BI) or RightMiddleLobeBronchus
+  
+  try {
+    GetAFDB()->GetPoint3D("LineForS7S8Separation_Begin", A); 
+    GetAFDB()->GetPoint3D("LineForS7S8Separation_End", B);
+  }
+  catch(clitk::ExceptionObject & o) {
+    
+    DD("FindLineForS7S8Separation");
+    // Load LeftLowerLobeBronchus and get centroid point
+    MaskImagePointer LeftLowerLobeBronchus = 
+      GetAFDB()->template GetImage <MaskImageType>("LeftLowerLobeBronchus");
+    std::vector<MaskImagePointType> c;
+    clitk::ComputeCentroids<MaskImageType>(LeftLowerLobeBronchus, GetBackgroundValue(), c);
+    A = c[1];
+    
+    // Load RightMiddleLobeBronchus and get superior point (not centroid here)
+    MaskImagePointer RightMiddleLobeBronchus = 
+      GetAFDB()->template GetImage <MaskImageType>("RightMiddleLobeBronchus");
+    bool b = FindExtremaPointInAGivenDirection<MaskImageType>(RightMiddleLobeBronchus, 
+                                                              GetBackgroundValue(), 
+                                                              2, false, B);
+    if (!b) {
+      clitkExceptionMacro("Error while searching most superior point in RightMiddleLobeBronchus. Abort");
+    }
+    
+    // Insert into the DB
+    GetAFDB()->SetPoint3D("LineForS7S8Separation_Begin", A);
+    GetAFDB()->SetPoint3D("LineForS7S8Separation_End", B);
+  }
 }
 //--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class TImageType>
+double 
+clitk::ExtractLymphStationsFilter<TImageType>::
+FindCarinaSlicePosition()
+{
+  double z;
+  try {
+    z = GetAFDB()->GetDouble("CarinaZ");
+  }
+  catch(clitk::ExceptionObject e) {
+    DD("FindCarinaSlicePosition");
+    // Get Carina
+    MaskImagePointer Carina = GetAFDB()->template GetImage<MaskImageType>("Carina");
+    
+    // Get Centroid and Z value
+    std::vector<MaskImagePointType> centroids;
+    clitk::ComputeCentroids<MaskImageType>(Carina, GetBackgroundValue(), centroids);
+
+    // We dont need Carina structure from now
+    Carina->Delete();
+    
+    // Put inside the AFDB
+    GetAFDB()->SetPoint3D("CarinaPoint", centroids[1]);
+    GetAFDB()->SetDouble("CarinaZ", centroids[1][2]);
+    WriteAFDB();
+    z = centroids[1][2];
+  }
+  return z;
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class TImageType>
+void
+clitk::ExtractLymphStationsFilter<TImageType>::
+FindLeftAndRightBronchi()
+{
+  try {
+    m_RightBronchus = GetAFDB()->template GetImage <MaskImageType>("RightBronchus");
+    m_LeftBronchus = GetAFDB()->template GetImage <MaskImageType>("LeftBronchus");
+  }
+  catch(clitk::ExceptionObject & o) {
+
+    DD("FindLeftAndRightBronchi");
+    // The goal is to separate the trachea inferiorly to the carina into
+    // a Left and Right bronchus.
   
+    // Get the trachea
+    MaskImagePointer Trachea = GetAFDB()->template GetImage<MaskImageType>("Trachea");
+
+    // Get the Carina position
+    m_CarinaZ = FindCarinaSlicePosition();
+
+    // Consider only inferiorly to the Carina
+    MaskImagePointer m_Working_Trachea = 
+      clitk::CropImageRemoveGreaterThan<MaskImageType>(Trachea, 2, m_CarinaZ, true, // AutoCrop
+                                                       GetBackgroundValue());
+
+    // Labelize the trachea
+    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). We thus first check that the
+    // upper slice is composed of at least two labels
+    MaskImagePointer RightBronchus;
+    MaskImagePointer LeftBronchus;
+    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()) {    
+        if (iter.Get() > maxLabel) maxLabel = iter.Get();
+        --iter;
+      }
+      iter.PreviousLine();
+    }
+    if (maxLabel < 2) {
+      clitkExceptionMacro("First slice from Carina does not seems to seperate the two main bronchus. Abort");
+    }
+
+    // Compute 3D centroids of both parts to identify the left from the
+    // right bronchus
+    std::vector<ImagePointType> c;
+    clitk::ComputeCentroids<MaskImageType>(m_Working_Trachea, GetBackgroundValue(), c);
+    ImagePointType C1 = c[1];
+    ImagePointType C2 = c[2];
+
+    ImagePixelType rightLabel;
+    ImagePixelType leftLabel;  
+    if (C1[0] < C2[0]) { rightLabel = 1; leftLabel = 2; }
+    else { rightLabel = 2; leftLabel = 1; }
+
+    // Select LeftLabel (set one label to Backgroundvalue)
+    RightBronchus = 
+      clitk::Binarize<MaskImageType>(m_Working_Trachea, rightLabel, rightLabel, 
+                                     GetBackgroundValue(), GetForegroundValue());
+    /*
+      SetBackground<MaskImageType, MaskImageType>(m_Working_Trachea, m_Working_Trachea, 
+      leftLabel, GetBackgroundValue(), false);
+    */
+    LeftBronchus = clitk::Binarize<MaskImageType>(m_Working_Trachea, leftLabel, leftLabel, 
+                                                  GetBackgroundValue(), GetForegroundValue());
+    /*
+      SetBackground<MaskImageType, MaskImageType>(m_Working_Trachea, m_Working_Trachea, 
+      rightLabel, GetBackgroundValue(), false);
+    */
+
+    // Crop images
+    RightBronchus = clitk::AutoCrop<MaskImageType>(RightBronchus, GetBackgroundValue()); 
+    LeftBronchus = clitk::AutoCrop<MaskImageType>(LeftBronchus, GetBackgroundValue()); 
+
+    // Insert int AFDB if need after 
+    GetAFDB()->template SetImage <MaskImageType>("RightBronchus", "seg/rightBronchus.mhd", 
+                                                 RightBronchus, true);
+    GetAFDB()->template SetImage <MaskImageType>("LeftBronchus", "seg/leftBronchus.mhd", 
+                                                 LeftBronchus, true);
+  }
+}
+//--------------------------------------------------------------------
 
 #endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX