]> Creatis software - clitk.git/commitdiff
Merge branch 'master' of git.creatis.insa-lyon.fr:clitk
authorDavid Sarrut <david.sarrut@gmail.com>
Wed, 1 Feb 2012 06:20:06 +0000 (07:20 +0100)
committerDavid Sarrut <david.sarrut@gmail.com>
Wed, 1 Feb 2012 06:20:06 +0000 (07:20 +0100)
19 files changed:
itk/clitkBoundingBoxUtils.h
itk/clitkBoundingBoxUtils.txx
itk/clitkRelativePositionAnalyzerFilter.txx
itk/clitkSegmentationUtils.txx
itk/clitkSliceBySliceRelativePositionFilter.txx
segmentation/clitkExtractLymphStation_Supports.txx
segmentation/clitkExtractLymphStationsFilter.txx
segmentation/clitkRelativePositionList.txx
vv/qt_ui/vvToolStructureSetManager.ui
vv/vvBinaryImageOverlayActor.cxx
vv/vvBinaryImageOverlayActor.h
vv/vvImageContour.cxx
vv/vvImageContour.h
vv/vvMeshActor.cxx
vv/vvROIActor.cxx
vv/vvROIActor.h
vv/vvStructureSetActor.cxx
vv/vvToolStructureSetManager.cxx
vv/vvToolStructureSetManager.h

index 311e67da1204d52b8fe6be2dd60665ecc6200342..2fcaddd2dda8c6e2ee00a2f81524e7590b382377 100644 (file)
@@ -40,6 +40,13 @@ namespace clitk {
                              typename itk::BoundingBox<unsigned long, Dimension>::Pointer bbi1, 
                              typename itk::BoundingBox<unsigned long, Dimension>::Pointer bbi2);
 
+  //--------------------------------------------------------------------
+  template<int Dimension>
+  void ComputeBBIntersection(typename itk::BoundingBox<unsigned long, Dimension>::Pointer bbo, 
+                             typename itk::BoundingBox<unsigned long, Dimension>::Pointer bbi1, 
+                             typename itk::BoundingBox<unsigned long, Dimension>::Pointer bbi2, 
+                             int dimension);
+
   //--------------------------------------------------------------------
   template<int Dimension>
   void ComputeBBUnion(typename itk::BoundingBox<unsigned long, Dimension>::Pointer bbo, 
index d6fbc24b7eaa0248c4a9a78bdb0297f829da4a72..9f277cbe6ad93f2ed50d0397a60511fbbecad3ea 100644 (file)
@@ -67,6 +67,24 @@ namespace clitk {
 
   ///--------------------------------------------------------------------
   template<int Dimension>
+  void ComputeBBIntersection(typename itk::BoundingBox<unsigned long, Dimension>::Pointer bbo, 
+                             typename itk::BoundingBox<unsigned long, Dimension>::Pointer bbi1, 
+                             typename itk::BoundingBox<unsigned long, Dimension>::Pointer bbi2, 
+                             int dimension) {
+    typedef itk::BoundingBox<unsigned long, Dimension> BBType;
+    typedef typename BBType::PointType PointType;
+    PointType lastPoint;
+    PointType firstPoint;
+    firstPoint[dimension] = std::max(bbi1->GetMinimum()[dimension], bbi2->GetMinimum()[dimension]);
+    lastPoint[dimension] = std::min(bbi1->GetMaximum()[dimension], bbi2->GetMaximum()[dimension]);
+    bbo->SetMaximum(lastPoint);
+    bbo->SetMinimum(firstPoint);
+  }
+  //--------------------------------------------------------------------
+
+
+  //--------------------------------------------------------------------
+  template<int Dimension>
   void ComputeBBUnion(typename itk::BoundingBox<unsigned long, Dimension>::Pointer bbo, 
                       typename itk::BoundingBox<unsigned long, Dimension>::Pointer bbi1, 
                       typename itk::BoundingBox<unsigned long, Dimension>::Pointer bbi2) {
index df12ea33437c42975282662ad74015745d625041..63af1191987386dfac0b632f0af23559ef967e10 100644 (file)
@@ -103,12 +103,17 @@ GenerateData()
 {
   ImagePointer temp = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(0));
   m_Object = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(1));
-  m_Target = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(2));
+  ImagePointer temp2 = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(2));
 
   // Remove object from support (keep initial image)
   m_Support = clitk::Clone<ImageType>(temp);
   clitk::AndNot<ImageType>(m_Support, m_Object, GetBackgroundValue());
   
+  // Remove object from target. Important because sometimes, there is
+  // overlap between target and object.
+  m_Target = clitk::Clone<ImageType>(temp2);
+  clitk::AndNot<ImageType>(m_Target, m_Object, GetBackgroundValue());
+  
   // Define filter to compute statics on mask image
   typedef itk::LabelStatisticsImageFilter<ImageType, ImageType> StatFilterType;
   typename StatFilterType::Pointer statFilter = StatFilterType::New();
@@ -142,6 +147,9 @@ GenerateData()
   double mReverseThreshold=1.0;
   ComputeOptimalThresholds(map, m_Target, bins, tolerance, mThreshold, mReverseThreshold);
 
+  // DD(mThreshold);
+  // DD(mReverseThreshold);
+
   // Use the threshold to compute new support
   int s1 = GetSupportSize();
   if (mThreshold > 0.0) {
@@ -176,6 +184,13 @@ GenerateData()
     s2 = statFilter->GetCount(GetForegroundValue());
   }
   
+  // Check threshold, if we gain nothing, we force to max/min thresholds
+  // DD(GetSupportSize());
+  // DD(s1);
+  // DD(s2);
+  if (s1 >= GetSupportSize()) mThreshold = 0.0;
+  if (s2 >= GetSupportSize()) mReverseThreshold = 1.0;
+
   // Set results values
   m_Info.threshold = mThreshold;
   m_Info.sizeAfterThreshold = s1;
@@ -210,15 +225,19 @@ ComputeFuzzyMap(ImageType * object, ImageType * target, ImageType * support, dou
   // sliceRelPosFilter->PrintOptions();
   sliceRelPosFilter->Update();
   typename FloatImageType::Pointer map = sliceRelPosFilter->GetFuzzyMap();
+  writeImage<FloatImageType>(map, "fuzzy_0_"+toString(clitk::rad2deg(angle))+".mha");
 
-  // Resize map like object to allow SetBackground
-  map = clitk::ResizeImageLike<FloatImageType>(map, object, GetBackgroundValue());
+  // Resize object like map to allow SetBackground
+  ImagePointer temp = clitk::ResizeImageLike<ImageType>(object, map, GetBackgroundValue());
+  //  writeImage<FloatImageType>(map, "fuzzy_1_"+toString(clitk::rad2deg(angle))+".mha");
   
   // Remove initial object from the fuzzy map
-  map = clitk::SetBackground<FloatImageType, ImageType>(map, object, GetForegroundValue(), 0.0, true);
+  map = clitk::SetBackground<FloatImageType, ImageType>(map, temp, GetForegroundValue(), 0.0, true);
+  writeImage<FloatImageType>(map, "fuzzy_2_"+toString(clitk::rad2deg(angle))+".mha");
   
   // Resize the fuzzy map like the target, put 2.0 when outside
   map = clitk::ResizeImageLike<FloatImageType>(map, target, 2.0);  // Put 2.0 when out of initial map
+  writeImage<FloatImageType>(map, "fuzzy_3_"+toString(clitk::rad2deg(angle))+".mha");
   
   // end
   return map;
@@ -239,9 +258,10 @@ ComputeOptimalThresholds(FloatImageType * map, ImageType * target, int bins, dou
   f->SetInput(map);
   f->SetLabelInput(target);
   f->UseHistogramsOn();
-  f->SetHistogramParameters(bins, 0.0, 1.1);
+  f->SetHistogramParameters(bins, 0.0-(1.0/bins), 1.0+(1.0/bins));
   f->Update();
   int count = f->GetCount(GetForegroundValue());
+  // DD(count);
   typename FloatStatFilterType::HistogramPointer h = f->GetHistogram(GetForegroundValue());
 
   // Debug : dump histogram
@@ -253,18 +273,34 @@ ComputeOptimalThresholds(FloatImageType * map, ImageType * target, int bins, dou
                   << "\t" << (double)h->GetFrequency(j)/(double)count << std::endl;
   }
   histogramFile.close();  
+  std::ofstream histogramFile2(std::string("fuzzy_histo_R_"+toString(i)+".txt").c_str());
+  for(int j=bins-1; j>=0; j--) {
+    histogramFile2 << h->GetMeasurement(j,0) 
+                  << "\t" << h->GetFrequency(j) 
+                  << "\t" << (double)h->GetFrequency(j)/(double)count << std::endl;
+  }
+  histogramFile2.close();  
   i++;
 
   // Analyze the histogram (direct)
   double sum = 0.0;
   bool found = false;
   threshold = 0.0;
-  for(int j=0; j<bins; j++) {
+  for(int j=0; j<bins-1; j++) {
     sum += ((double)h->GetFrequency(j)/(double)count);
+     // DD(j);
+     // DD(sum);
+     // DD(threshold);
+     // DD(h->GetBinMin(0,j));
+     // DD(h->GetBinMax(0,j));
     if ((!found) && (sum > tolerance)) {
-      if (j==0) threshold = h->GetBinMin(0,j);
-      else threshold = h->GetBinMin(0,j-1); // the last before reaching the threshold
+      // We consider as threshold the laste before current, because 
+      if (j==0) 
+        threshold = h->GetBinMin(0,j);
+      else threshold = h->GetBinMin(0,j-1); // FIXME  ? the last before reaching the threshold
+      // DD(threshold);
       found = true;
+      j = bins;
     }
   }
 
@@ -272,14 +308,23 @@ ComputeOptimalThresholds(FloatImageType * map, ImageType * target, int bins, dou
   sum = 0.0;
   found = false;
   reverseThreshold = 1.0;
-  for(int j=bins-1; j>=0; j--) {
+  for(int j=bins-1; j>0; j--) {
     sum += ((double)h->GetFrequency(j)/(double)count);
+     // DD(j);
+     // DD(sum);
+     // DD(reverseThreshold);
+     // DD(h->GetBinMin(0,j));
+     // DD(h->GetBinMax(0,j));
     if ((!found) && (sum > tolerance)) {
-      if (j==bins-1) reverseThreshold = h->GetBinMax(0,j);
-      else reverseThreshold = h->GetBinMax(0,j+1);
+      if (j==bins-1) 
+      reverseThreshold = h->GetBinMax(0,j);
+      else reverseThreshold = h->GetBinMax(0,j-1);// FIXME  ? the last before reaching the threshold
+      // DD(reverseThreshold);
       found = true;
+      j = -1;
     }
   }
+
 }
 //--------------------------------------------------------------------
 
index 501c64f86fedd8ace7de88f1e7e9388c4e6fd807..6171030d9109807f0c2d2a9cf80782087c7c8279 100644 (file)
@@ -766,8 +766,7 @@ namespace clitk {
   {
     assert((mainDirection==0) || (mainDirection==1));
     typedef itk::ImageSliceIteratorWithIndex<ImageType> SliceIteratorType;
-    SliceIteratorType siter = SliceIteratorType(input, 
-                                                input->GetLargestPossibleRegion());
+    SliceIteratorType siter = SliceIteratorType(input, input->GetLargestPossibleRegion());
     siter.SetFirstDirection(0);
     siter.SetSecondDirection(1);
     siter.GoToBegin();
@@ -786,7 +785,6 @@ namespace clitk {
         A = lA[i];
         B = lB[i];
         C = A;
-      
         // Check that the line is not a point (A=B)
         bool p = (A[0] == B[0]) && (A[1] == B[1]);
       
index 0df2987312797c94f34fb72365359fda82b4043a..449ffff9f5a06162a5ed1b11b387a9ade104e549 100644 (file)
@@ -127,9 +127,13 @@ GenerateOutputInformation()
     PrintOptions();
   }
 
+  if (this->GetFuzzyMapOnlyFlag()) this->ComputeFuzzyMapFlagOn();
+
   // Get input pointer
   input = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(0));
   object = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(1));
+  m_working_object = object;
+  m_working_input = input;
 
   //--------------------------------------------------------------------
   // Resample object to the same spacing than input
@@ -138,36 +142,60 @@ GenerateOutputInformation()
     m_working_object = clitk::ResampleImageSpacing<ImageType>(object, input->GetSpacing());
     this->template StopCurrentStep<ImageType>(m_working_object);
   }
-  else {
-    m_working_object = object;
-  }
   
   //--------------------------------------------------------------------
-  // Pad object to the same size than input
+  // Resize image according to common area (except in Z)
   if (!clitk::HaveSameSizeAndSpacing<ImageType, ImageType>(m_working_object, input)) {
+    this->StartNewStep("Resize images (union in XY and like input in Z)");
+    
+    /* OLD STUFF
     this->StartNewStep("Pad object to the same size than input");
     m_working_object = clitk::ResizeImageLike<ImageType>(m_working_object, 
-                                                         input, 
-                                                         this->GetObjectBackgroundValue());
+    input, 
+    this->GetObjectBackgroundValue());
     this->template StopCurrentStep<ImageType>(m_working_object);
+    */
+
+    // Compute union of bounding boxes in X and Y
+    static const unsigned int dim = ImageType::ImageDimension;
+    typedef itk::BoundingBox<unsigned long, dim> BBType;
+    typename BBType::Pointer bb1 = BBType::New();
+    ComputeBBFromImageRegion<ImageType>(m_working_object, m_working_object->GetLargestPossibleRegion(), bb1);
+    typename BBType::Pointer bb2 = BBType::New();
+    ComputeBBFromImageRegion<ImageType>(input, input->GetLargestPossibleRegion(), bb2);
+    typename BBType::Pointer bbo = BBType::New();
+    ComputeBBUnion<dim>(bbo, bb1, bb2);
+
+    //We set Z BB like input
+    typename ImageType::PointType maxs = bbo->GetMaximum();
+    typename ImageType::PointType mins = bbo->GetMinimum();
+    maxs[2] = bb2->GetMaximum()[2];
+    mins[2] = bb2->GetMinimum()[2];
+    bbo->SetMaximum(maxs);
+    bbo->SetMinimum(mins);
+
+    // Crop
+    m_working_input = clitk::ResizeImageLike<ImageType>(input, bbo, this->GetBackgroundValue());    
+    m_working_object = clitk::ResizeImageLike<ImageType>(m_working_object, 
+                                                         m_working_input, 
+                                                         this->GetObjectBackgroundValue());
+    this->template StopCurrentStep<ImageType>(m_working_input);  
   }
-  else {
-  }
-
-  /*
+  
+  //--------------------------------------------------------------------
+  /* Steps : 
     - extract vector of slices in input, in object
     - slice by slice rel position
     - joint result
     - post process
   */
 
-
   //--------------------------------------------------------------------
   // Extract input slices
   this->StartNewStep("Extract input slices");
   typedef clitk::ExtractSliceFilter<ImageType> ExtractSliceFilterType;
   typename ExtractSliceFilterType::Pointer extractSliceFilter = ExtractSliceFilterType::New();
-  extractSliceFilter->SetInput(input);
+  extractSliceFilter->SetInput(m_working_input);
   extractSliceFilter->SetDirection(GetDirection());
   extractSliceFilter->Update();
   typedef typename ExtractSliceFilterType::SliceType SliceType;
@@ -179,7 +207,7 @@ GenerateOutputInformation()
   // Extract object slices
   this->StartNewStep("Extract object slices");
   extractSliceFilter = ExtractSliceFilterType::New();
-  extractSliceFilter->SetInput(m_working_object);//object);
+  extractSliceFilter->SetInput(m_working_object);
   extractSliceFilter->SetDirection(GetDirection());
   extractSliceFilter->Update();
   std::vector<typename SliceType::Pointer> mObjectSlices;
@@ -200,18 +228,18 @@ GenerateOutputInformation()
     int nb=0;
     mObjectSlices[i] = LabelizeAndCountNumberOfObjects<SliceType>(mObjectSlices[i], 0, true, 1, nb);
 
-    // If no object and empty slices :
-    if ((nb==0) && (this->GetFuzzyMapOnlyFlag())) {
+    // If no object and empty slices and if we need the full fuzzy map, create a dummy one.
+    if ((nb==0) && (this->GetComputeFuzzyMapFlag())) {
       typename FloatSliceType::Pointer one = FloatSliceType::New();
       one->CopyInformation(mObjectSlices[0]);
       one->SetRegions(mObjectSlices[0]->GetLargestPossibleRegion());
       one->Allocate();
       one->FillBuffer(2.0);
       mFuzzyMapSlices[i] = one;
-    }
+    } // End nb==0 && GetComputeFuzzyMapFlag
     else {
       if ((!GetIgnoreEmptySliceObjectFlag()) || (nb!=0)) {
-
+        
         // Select or not a single CCL ?
         if (GetUseTheLargestObjectCCLFlag()) {
           mObjectSlices[i] = KeepLabels<SliceType>(mObjectSlices[i], 0, 1, 1, 1, true);
@@ -256,20 +284,20 @@ GenerateOutputInformation()
 
         relPosFilter->VerboseStepFlagOff();
         relPosFilter->WriteStepFlagOff();
+        // relPosFilter->VerboseMemoryFlagOn();
+        relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId()+"-"+toString(i));
+        
         relPosFilter->SetBackgroundValue(this->GetBackgroundValue());
         relPosFilter->SetInput(mInputSlices[i]); 
         relPosFilter->SetInputObject(mObjectSlices[i]); 
         relPosFilter->SetRemoveObjectFlag(this->GetRemoveObjectFlag());
+        
         // This flag (InverseOrientation) *must* be set before
         // AddOrientation because AddOrientation can change it.
         relPosFilter->SetInverseOrientationFlag(this->GetInverseOrientationFlag());
         for(int j=0; j<this->GetNumberOfAngles(); j++) {
-          //          relPosFilter->AddOrientationTypeString(this->GetOrientationTypeString(j));
           relPosFilter->AddAnglesInRad(this->GetAngle1InRad(j), this->GetAngle2InRad(j));
-          // DD(this->GetOrientationTypeString(j));
         }
-        // DD(this->GetInverseOrientationFlag());
-        //relPosFilter->SetOrientationType(this->GetOrientationType());
         relPosFilter->SetIntermediateSpacing(this->GetIntermediateSpacing());
         relPosFilter->SetIntermediateSpacingFlag(this->GetIntermediateSpacingFlag());
         relPosFilter->SetFuzzyThreshold(this->GetFuzzyThreshold());
@@ -278,26 +306,29 @@ GenerateOutputInformation()
 
         // should we stop after fuzzy map ?
         relPosFilter->SetFuzzyMapOnlyFlag(this->GetFuzzyMapOnlyFlag());
+        relPosFilter->SetComputeFuzzyMapFlag(this->GetComputeFuzzyMapFlag());
       
         // Go !
         relPosFilter->Update();
 
         // If we stop after the fuzzy map, store the fuzzy slices
-        if (this->GetFuzzyMapOnlyFlag()) {
+        if (this->GetComputeFuzzyMapFlag()) {
           mFuzzyMapSlices[i] = relPosFilter->GetFuzzyMap();
           // writeImage<FloatSliceType>(mFuzzyMapSlices[i], "slice_"+toString(i)+".mha");
         }
-        else  {
+
+        // Set input slices
+        if (!this->GetFuzzyMapOnlyFlag())  {
           mInputSlices[i] = relPosFilter->GetOutput();
           // Select main CC if needed
           if (GetUniqueConnectedComponentBySliceFlag()) {
             mInputSlices[i] = Labelize<SliceType>(mInputSlices[i], 0, true, 1);
             mInputSlices[i] = KeepLabels<SliceType>(mInputSlices[i], 0, 1, 1, 1, true);
-          }
-        
+          }          
         }
 
       }
+
       /*
       // Select unique CC according to the most in a given direction
       if (GetUniqueConnectedComponentBySliceAccordingToADirection()) {
@@ -307,20 +338,22 @@ GenerateOutputInformation()
       ComputeCentroids
       }
       */
-    }
-  }
 
-  // Join the fuzzy map if needed
-  if (this->GetFuzzyMapOnlyFlag()) {
-    this->m_FuzzyMap = clitk::JoinSlices<FloatImageType>(mFuzzyMapSlices, input, GetDirection());
-    this->template StopCurrentStep<FloatImageType>(this->m_FuzzyMap);
-    return;
-  }
+    } // End nb!=0 || GetComputeFuzzyMapFlagOFF
+
+  } // end for i mInputSlices
 
   // Join the slices
-  m_working_input = clitk::JoinSlices<ImageType>(mInputSlices, input, GetDirection());
+  m_working_input = clitk::JoinSlices<ImageType>(mInputSlices, m_working_input, GetDirection());
   this->template StopCurrentStep<ImageType>(m_working_input);
 
+  // Join the fuzzy map if needed
+  if (this->GetComputeFuzzyMapFlag()) {
+    this->m_FuzzyMap = clitk::JoinSlices<FloatImageType>(mFuzzyMapSlices, m_working_input, GetDirection());
+    this->template StopCurrentStep<FloatImageType>(this->m_FuzzyMap);
+    if (this->GetFuzzyMapOnlyFlag()) return;
+  }
+
   //--------------------------------------------------------------------
   // Step 7: autocrop
   if (this->GetAutoCropFlag()) {
index a022392653df59bb5a3511295067980c43db274c..f480d842b2990cc3c16156b2500b5add84281ed7 100644 (file)
@@ -19,18 +19,6 @@ ExtractStationSupports()
   Support_SI_Limit("inferior", "Sup_to_Carina", "inferior", "Carina", 0); 
   Support_SI_Limit("superior", "Inf_to_Carina", "inferior", "Carina", m_Working_Support->GetSpacing()[2]); 
 
-  // Initialise all others supports
-  // m_ListOfSupports["S1R"] = m_ListOfSupports["Sup_to_Carina"];
-  // m_ListOfSupports["S1L"] = m_ListOfSupports["Sup_to_Carina"];
-  // m_ListOfSupports["S2R"] = m_ListOfSupports["Sup_to_Carina"];
-  // m_ListOfSupports["S2L"] = m_ListOfSupports["Sup_to_Carina"];
-  // m_ListOfSupports["S3A"] = m_ListOfSupports["Sup_to_Carina"];
-  // m_ListOfSupports["S3P"] = m_ListOfSupports["Sup_to_Carina"];
-  // m_ListOfSupports["S4R"] = m_ListOfSupports["Sup_to_Carina"];
-  // m_ListOfSupports["S4L"] = m_ListOfSupports["Sup_to_Carina"];
-  // m_ListOfSupports["S5"] = m_Mediastinum; // Not above Carina
-  // m_ListOfSupports["S6"] = m_Mediastinum; // Not above Carina
-  
   // Read all support limits in a file and apply them
   ReadSupportLimits(GetSupportLimitsFilename());  
   for(unsigned int i=0; i<m_ListOfSupportLimits.size(); i++) {
@@ -49,15 +37,26 @@ ExtractStationSupports()
   Support_LeftRight_S4R_S4L();
   
   // Post limits of S1,S2,S4
-  Support_Post_S1S2S4();
+  Support_Post_S2S4();
 
-  // S3P
+  // S3P : "the anterior border is an imaginary horizontal line
+  // extending along the posterior wall of the trachea"
   StartNewStep("[Support] Ant limits of S3P with trachea");
   m_ListOfSupports["S3P"] = LimitsWithTrachea(m_ListOfSupports["S3P"], 1, 0, 10);
 
-  // S3A
+  // S3A : "Posteriorly, the station is limited by station 2R and 2L,
+  // but excludes the great vessels. An imaginary line joins the
+  // midpoint of the vessel in the anterior to posterior plane. It is
+  // here that station 2 contacts station 3a" ===> here limit with
+  // trachea only
   StartNewStep("[Support] Ant limits of S3A with trachea");
   m_ListOfSupports["S3A"] = LimitsWithTrachea(m_ListOfSupports["S3A"], 1, 0, -10);
+
+  // S1RL - posterior limits when SI overlap with S3P
+  Support_Post_S1_S3P();
+  
+  // S1RL - posterior limits with S2RL above sternal notch
+  Support_Post_S1_Ant_S2RL();
   
   // I will do it later
   // Below Carina S7,8,9,10
@@ -235,6 +234,11 @@ void
 clitk::ExtractLymphStationsFilter<ImageType>::
 Support_LeftRight_S1R_S1L()
 {
+  /*
+    Medially, station 1R and 1L are separated by the midline of the
+    trachea, whilst excluding the thyroid gland.
+  */
+
   // Step S1RL : Left-Right
   StartNewStep("[Support] Left-Right S1R S1L");
   std::vector<ImagePointType> A;
@@ -265,13 +269,13 @@ Support_LeftRight_S1R_S1L()
 
   // Right part
   clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(S1R, A, B, 
-                                                                    GetBackgroundValue(), 0, 10);
+                                                                    GetBackgroundValue(), 0, -10);
   S1R = clitk::AutoCrop<MaskImageType>(S1R, GetBackgroundValue());
   m_ListOfSupports["S1R"] = S1R;
 
   // Left part
   clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(S1L, A, B, 
-                                                                    GetBackgroundValue(), 0, -10);
+                                                                    GetBackgroundValue(), 0, 10);
   S1L = clitk::AutoCrop<MaskImageType>(S1L, GetBackgroundValue());
   m_ListOfSupports["S1L"] = S1L;
   StopCurrentStep<MaskImageType>(m_ListOfSupports["S1L"]);
@@ -286,11 +290,14 @@ clitk::ExtractLymphStationsFilter<ImageType>::
 Support_LeftRight_S2R_S2L()
 {
   // ---------------------------------------------------------------------------
-  /* Step : S2RL LeftRight
-     As for lymph node station 4R, 2R includes nodes extending to the
-     left lateral border of the trachea
-     Rod says:  "For station 2 there is a shift, dividing 2R from 2L, from midline
-     to the left paratracheal border."
+  /* Step : S2RL LeftRight As for lymph node station 4R, 2R includes
+     nodes extending to the left lateral border of the trachea.
+
+     Rod says: "For station 2 there is a shift in the IASLC definition
+     dividing 2R from 2L, from the midline to the left lateral
+     tracheal border. This is represented in the atlas as a vertical
+     line passing tangentially along the left lateral tracheal border
+     "
   */
   StartNewStep("[Support] Separate 2R/2L according to Trachea");
   MaskImagePointer S2R = m_ListOfSupports["S2R"];
@@ -313,15 +320,10 @@ clitk::ExtractLymphStationsFilter<ImageType>::
 Support_LeftRight_S4R_S4L()
 {
   // ---------------------------------------------------------------------------
-  /* Step : S4RL LeftRight 
-     
-     - 4R: includes right paratracheal nodes, and pretracheal nodes
-     extending to the left lateral border of trachea
-     
-     - 4L: includes nodes to the left of the left lateral border of
-     the trachea, medial to the ligamentum arteriosum
-     
-     => same than 2RL
+  /*      
+          The medial border of station 4R is defined as an imaginary line
+          running vertically from the left lateral tracheal border. This is
+          the same medial border as was described for station 2R.
   */
   StartNewStep("[Support] Left Right separation of 4R/4L");
 
@@ -409,21 +411,21 @@ LimitsWithTrachea(MaskImageType * input, int extremaDirection, int lineDirection
 template <class ImageType>
 void
 clitk::ExtractLymphStationsFilter<ImageType>::
-Support_Post_S1S2S4()
+Support_Post_S2S4()
 {
-  StartNewStep("[Support] Post limits of S1RL, S2RL, S4RL");
+  StartNewStep("[Support] Post limits of S2RL, S4RL");
   
   double m_ApexOfTheChest = FindApexOfTheChest();
   
   // Post limits with Trachea 
-  MaskImagePointer S1R = m_ListOfSupports["S1R"];
-  MaskImagePointer S1L = m_ListOfSupports["S1L"];
+  // MaskImagePointer S1R = m_ListOfSupports["S1R"];
+  // MaskImagePointer S1L = m_ListOfSupports["S1L"];
   MaskImagePointer S2R = m_ListOfSupports["S2R"];
   MaskImagePointer S2L = m_ListOfSupports["S2L"];
   MaskImagePointer S4R = m_ListOfSupports["S4R"];
   MaskImagePointer S4L = m_ListOfSupports["S4L"];
-  m_ListOfSupports["S1R"] = LimitsWithTrachea(S1L, 1, 0, -10, m_ApexOfTheChest);
-  m_ListOfSupports["S1L"] = LimitsWithTrachea(S1R, 1, 0, -10, m_ApexOfTheChest);
+  // m_ListOfSupports["S1R"] = LimitsWithTrachea(S1L, 1, 0, -10, m_ApexOfTheChest);
+  // m_ListOfSupports["S1L"] = LimitsWithTrachea(S1R, 1, 0, -10, m_ApexOfTheChest);
   m_ListOfSupports["S2R"] = LimitsWithTrachea(S2R, 1, 0, -10, m_ApexOfTheChest);
   m_ListOfSupports["S2L"] = LimitsWithTrachea(S2L, 1, 0, -10, m_ApexOfTheChest);
   m_ListOfSupports["S4R"] = LimitsWithTrachea(S4R, 1, 0, -10, m_ApexOfTheChest);
@@ -432,3 +434,161 @@ Support_Post_S1S2S4()
 //--------------------------------------------------------------------
 
 
+//--------------------------------------------------------------------
+template <class ImageType>
+void
+clitk::ExtractLymphStationsFilter<ImageType>::
+Support_Post_S1_S3P()
+{
+  StartNewStep("[Support] If S1RL and S3P have Sup-Inf overlap, define S1RL posterior limits with S3P anterior limits (post wall trachea)");
+
+  // Get current supports
+  MaskImagePointer S1R = m_ListOfSupports["S1R"];
+  MaskImagePointer S1L = m_ListOfSupports["S1L"];
+
+  // Find extrema ant positions for 3P
+  std::vector<MaskImagePointType> A;
+  std::vector<MaskImagePointType> B;
+
+  // Crop S3P like S1R
+  MaskImagePointer S3P = clitk::Clone<MaskImageType>(m_ListOfSupports["S3P"]);
+  S3P = clitk::ResizeImageLike<MaskImageType>(S3P, S1R, GetBackgroundValue());
+
+  // Slice by slice, build the separation line 
+  clitk::SliceBySliceBuildLineSegmentAccordingToExtremaPosition<MaskImageType>(S3P, 
+                                                                               GetBackgroundValue(), 2, 
+                                                                               1, true, // Ant-Post
+                                                                               0, // Horizontal line 
+                                                                               0, // margins 
+                                                                               A, B);
+
+  // clitk::WriteListOfLandmarks<MaskImageType>(A, "A-S1S3P.txt");
+  // clitk::WriteListOfLandmarks<MaskImageType>(B, "B-S1S3P.txt");
+
+  // Cut post to this line 
+  clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(S1R, A, B,
+                                                                    GetBackgroundValue(), 
+                                                                    1, -10); 
+  
+  // Crop S3P like S1L  (Redo for S1L)
+  S3P = clitk::Clone<MaskImageType>(m_ListOfSupports["S3P"]);
+  S3P = clitk::ResizeImageLike<MaskImageType>(S3P, S1L, GetBackgroundValue());
+
+  // Slice by slice, build the separation line
+  A.clear();
+  B.clear();
+  clitk::SliceBySliceBuildLineSegmentAccordingToExtremaPosition<MaskImageType>(S3P, 
+                                                                               GetBackgroundValue(), 2, 
+                                                                               1, true, // Ant-Post
+                                                                               0, // Horizontal line 
+                                                                               0, // margins 
+                                                                               A, B);
+  // Cut post to this line 
+  clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(S1L, A, B,
+                                                                    GetBackgroundValue(), 
+                                                                    1, -10); 
+
+  // Crop both images
+  S1R = clitk::AutoCrop<MaskImageType>(S1R, GetBackgroundValue());
+  S1L = clitk::AutoCrop<MaskImageType>(S1L, GetBackgroundValue());
+
+  StopCurrentStep<MaskImageType>(S1R);
+  
+  m_ListOfSupports["S1R"] = S1R;
+  m_ListOfSupports["S1L"] = S1L;
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void
+clitk::ExtractLymphStationsFilter<ImageType>::
+Support_Post_S1_Ant_S2RL()
+{
+  StartNewStep("[Support] Define S1RL posterior limits with S2RL anterior limits when overlap");
+
+  // Get RightLung
+  MaskImagePointer RightLung = this->GetAFDB()->template GetImage<MaskImageType>("RightLung");
+
+  // Find common area between S1 and S2
+  MaskImagePointType p_min;
+  MaskImagePointType p_max;
+  clitk::FindExtremaPointInAGivenDirection<MaskImageType>(m_ListOfSupports["S2R"], 
+                                                          GetBackgroundValue(), 2, false, p_max);
+  clitk::FindExtremaPointInAGivenDirection<MaskImageType>(m_ListOfSupports["S1R"], 
+                                                          GetBackgroundValue(), 2, true, p_min);
+  p_min[2] -= RightLung->GetSpacing()[2]; // consider the slice below (remove lower or equal)
+  p_max[2] += RightLung->GetSpacing()[2]; // consider the slice abov  (remove greater or equal)
+  
+  if (p_min[2] > p_max[2]) {
+
+    // Crop RightLung
+    RightLung = clitk::Clone<MaskImageType>(RightLung);
+    RightLung = clitk::ResizeImageLike<MaskImageType>(RightLung, m_ListOfSupports["S1R"], GetBackgroundValue());
+    RightLung = clitk::CropImageRemoveLowerThan<MaskImageType>(RightLung, 2, p_min[2], true, GetBackgroundValue());
+    RightLung = clitk::CropImageRemoveGreaterThan<MaskImageType>(RightLung, 2, p_max[2], true, GetBackgroundValue());
+
+    // Find extrema ant positions for RightLung
+    std::vector<MaskImagePointType> A;
+    std::vector<MaskImagePointType> B;
+    clitk::SliceBySliceBuildLineSegmentAccordingToExtremaPosition<MaskImageType>(RightLung, 
+                                                                                 GetBackgroundValue(), 2, 
+                                                                                 1, true, // Ant-Post
+                                                                                 0, // Horizontal line 
+                                                                                 0, // margins 
+                                                                                 A, B);
+    clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_ListOfSupports["S1R"],
+                                                                      A, B,
+                                                                      GetBackgroundValue(), 
+                                                                      1, -10); 
+    // I add one pixel to abupt S2R to S1R
+    for(int i=0; i<A.size(); i++) {
+      A[i][1] -= RightLung->GetSpacing()[1];
+      B[i][1] -= RightLung->GetSpacing()[1];
+    }
+    clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_ListOfSupports["S2R"],
+                                                                      A, B,
+                                                                      GetBackgroundValue(), 
+                                                                      1, 10);
+  }
+
+  // Get LeftLung, crop
+  MaskImagePointer LeftLung = this->GetAFDB()->template GetImage<MaskImageType>("LeftLung");
+  clitk::FindExtremaPointInAGivenDirection<MaskImageType>(m_ListOfSupports["S2L"], 
+                                                          GetBackgroundValue(), 2, false, p_max);
+  clitk::FindExtremaPointInAGivenDirection<MaskImageType>(m_ListOfSupports["S1L"], 
+                                                          GetBackgroundValue(), 2, true, p_min);
+  p_min[2] -= LeftLung->GetSpacing()[2]; // consider the slice below (remove lower or equal)
+  p_max[2] += LeftLung->GetSpacing()[2]; // consider the slice abov  (remove greater or equal)  
+  
+  if (p_min[2] > p_max[2]) {
+    LeftLung = clitk::ResizeImageLike<MaskImageType>(LeftLung, m_ListOfSupports["S1L"], GetBackgroundValue());
+    LeftLung = clitk::CropImageRemoveLowerThan<MaskImageType>(LeftLung, 2, p_min[2], true, GetBackgroundValue());
+    LeftLung = clitk::CropImageRemoveGreaterThan<MaskImageType>(LeftLung, 2, p_max[2], true, GetBackgroundValue());
+
+    // Find extrema ant positions for LeftLung
+    std::vector<MaskImagePointType> A;
+    std::vector<MaskImagePointType> B;
+    clitk::SliceBySliceBuildLineSegmentAccordingToExtremaPosition<MaskImageType>(LeftLung, 
+                                                                                 GetBackgroundValue(), 2, 
+                                                                                 1, true, // Ant-Post
+                                                                                 0, // Horizontal line 
+                                                                                 0, // margins 
+                                                                                 A, B);
+    clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_ListOfSupports["S1L"],
+                                                                      A, B,
+                                                                      GetBackgroundValue(), 
+                                                                      1, -10); 
+    // I add one pixel to abupt S2R to S1R
+    for(int i=0; i<A.size(); i++) {
+      A[i][1] -= LeftLung->GetSpacing()[1];
+      B[i][1] -= LeftLung->GetSpacing()[1];
+    }
+    clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_ListOfSupports["S2L"],
+                                                                      A, B,
+                                                                      GetBackgroundValue(), 
+                                                                      1, 10); 
+  }
+}
+//--------------------------------------------------------------------
index 98768b278bfdaf105662efb118684db4d5c2713d..64455a87a218b79c28d86ee391b7b4a4e5c784e8 100644 (file)
@@ -85,6 +85,9 @@ GenerateOutputInformation() {
   m_Input = dynamic_cast<const ImageType*>(itk::ProcessObject::GetInput(0));
   m_Mediastinum = this->GetAFDB()->template GetImage <MaskImageType>("Mediastinum");
 
+  // DD(this->GetVerboseMemoryFlag());
+  // clitk::PrintMemory(this->GetVerboseMemoryFlag(), "Start"); 
+
   // Clean some computer landmarks to force the recomputation
   // FIXME -> to put elsewhere ?
   this->GetAFDB()->RemoveTag("AntPostVesselsSeparation");
index 254fa4c4581cd6895444789003d8b70138f8387f..e0258d5e71fb560e166c81d1a86a6608c6fe1bcb 100644 (file)
@@ -146,6 +146,7 @@ GenerateOutputInformation() {
   // Loop on RelativePositionList of operations
   std::string s = GetInputName();
   for(uint i=0; i<mArgsInfoList.size(); i++) {
+    // clitk::PrintMemory(true, "Start"); 
     std::string text = "["+s+"] limits ";
     if (mArgsInfoList[i].orientation_given) text += std::string(mArgsInfoList[i].orientation_arg[0])+" ";
     else text = text+"("+toString(mArgsInfoList[i].angle1_arg)+" "+
@@ -190,6 +191,7 @@ GenerateOutputInformation() {
     relPosFilter->Update();
     m_working_input = relPosFilter->GetOutput();  
     StopCurrentStep<ImageType>(m_working_input);
+    // clitk::PrintMemory(true, "End"); 
   }
 }
 //--------------------------------------------------------------------
index 6ceae4e917ff4270d46cfdcc987f6555412b0829..ea15504d48a7b0e8e9226a522f1d664ba01ad223 100644 (file)
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>301</width>
-    <height>480</height>
+    <width>411</width>
+    <height>534</height>
    </rect>
   </property>
   <property name="sizePolicy">
        <verstretch>0</verstretch>
       </sizepolicy>
      </property>
+     <property name="editTriggers">
+      <set>QAbstractItemView::AllEditTriggers</set>
+     </property>
+     <property name="tabKeyNavigation">
+      <bool>true</bool>
+     </property>
      <property name="alternatingRowColors">
-      <bool>false</bool>
+      <bool>true</bool>
      </property>
      <property name="selectionMode">
       <enum>QAbstractItemView::SingleSelection</enum>
        <string>Color</string>
       </property>
      </column>
+     <column>
+      <property name="text">
+       <string>Depth</string>
+      </property>
+     </column>
      <item>
       <property name="text">
        <string>10</string>
       <property name="text">
        <string>Red</string>
       </property>
+      <property name="text">
+       <string/>
+      </property>
      </item>
     </widget>
    </item>
       <string>Selected ROI</string>
      </property>
      <layout class="QVBoxLayout" name="verticalLayout">
-      <property name="spacing">
-       <number>1</number>
-      </property>
-      <property name="margin">
-       <number>1</number>
-      </property>
       <item>
        <layout class="QHBoxLayout" name="horizontalLayout_8">
         <item>
         </item>
         <item>
          <widget class="QSlider" name="mOpacitySlider">
+          <property name="maximum">
+           <number>100</number>
+          </property>
           <property name="orientation">
            <enum>Qt::Horizontal</enum>
           </property>
          </widget>
         </item>
         <item>
-         <widget class="QSpinBox" name="mOpacitySpinBox"/>
+         <widget class="QSpinBox" name="mOpacitySpinBox">
+          <property name="maximum">
+           <number>100</number>
+          </property>
+         </widget>
         </item>
        </layout>
       </item>
              <number>1</number>
             </property>
             <property name="maximum">
-             <number>5</number>
+             <number>10</number>
             </property>
            </widget>
           </item>
        </layout>
       </item>
       <item>
-       <widget class="QLabel" name="mROInameLabel">
-        <property name="sizePolicy">
-         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
-          <horstretch>0</horstretch>
-          <verstretch>0</verstretch>
-         </sizepolicy>
-        </property>
-        <property name="text">
-         <string>Name : Lung</string>
-        </property>
-       </widget>
+       <layout class="QHBoxLayout" name="horizontalLayout_3">
+        <item>
+         <widget class="QLabel" name="mROInameLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Name : Lung</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <spacer name="horizontalSpacer_5">
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>40</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item>
+         <widget class="QLabel" name="mROInameLabel_3">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Depth</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QSpinBox" name="mDepthSpinBox">
+          <property name="minimum">
+           <number>1</number>
+          </property>
+          <property name="maximum">
+           <number>999999</number>
+          </property>
+         </widget>
+        </item>
+       </layout>
       </item>
      </layout>
     </widget>
    <slot>setValue(int)</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>344</x>
-     <y>381</y>
+     <x>219</x>
+     <y>385</y>
     </hint>
     <hint type="destinationlabel">
-     <x>426</x>
-     <y>381</y>
+     <x>376</x>
+     <y>376</y>
     </hint>
    </hints>
   </connection>
    <slot>setValue(int)</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>432</x>
-     <y>386</y>
+     <x>376</x>
+     <y>367</y>
     </hint>
     <hint type="destinationlabel">
-     <x>351</x>
-     <y>386</y>
+     <x>222</x>
+     <y>373</y>
     </hint>
    </hints>
   </connection>
index d4b961751715db51fecd01becc776cbcb4c1fc16..612d9c01211cdfa66cd98bb5a8399b5cd547ce16 100644 (file)
@@ -42,6 +42,7 @@ vvBinaryImageOverlayActor::vvBinaryImageOverlayActor()
   mForegroundValue = 1;
   mBackgroundValue = 0;
   m_modeBG = true;
+  mDepth = 1.0;
 }
 //------------------------------------------------------------------------------
 
@@ -233,14 +234,15 @@ void vvBinaryImageOverlayActor::UpdateColor()
 //------------------------------------------------------------------------------
 
 //------------------------------------------------------------------------------
-void vvBinaryImageOverlayActor::UpdateSlice(int slicer, int slice)
+void vvBinaryImageOverlayActor::UpdateSlice(int slicer, int slice, bool force)
 {
   if (!mSlicer) return;
 
-  if (mPreviousSlice == mSlicer->GetSlice()) {
-    if (mPreviousTSlice == mSlicer->GetTSlice()) {
-      //DD("=========== NOTHING");
-      return; // Nothing to do
+  if (!force) {
+    if (mPreviousSlice == mSlicer->GetSlice()) {
+      if (mPreviousTSlice == mSlicer->GetTSlice()) {
+        return; // Nothing to do
+      }
     }
   }
 
@@ -253,14 +255,9 @@ void vvBinaryImageOverlayActor::UpdateSlice(int slicer, int slice)
   int orientation = mSlicer->GetOrientation();
   int maskExtent[6];
   ComputeExtent(orientation, mSlice, imageExtent, maskExtent);
-  //ComputeExtent(imageExtent, maskExtent, mSlicer->GetImage()->GetFirstVTKImageData(), mImage->GetFirstVTKImageData());
   ComputeExtent(maskExtent, maskExtent, mSlicer->GetImage()->GetFirstVTKImageData(), mImage->GetFirstVTKImageData());
-  // std::cout << "maskExtent = " << maskExtent[0] << " " << maskExtent[1] << " " << maskExtent[2] << " "
-  //       << maskExtent[3] << " " << maskExtent[4] << " " << maskExtent[5] << std::endl;
   mSlicer->ClipDisplayedExtent(maskExtent, mMapperList[mTSlice]->GetInput()->GetWholeExtent());
-  // std::cout << "maskExtent = " << maskExtent[0] << " " << maskExtent[1] << " " << maskExtent[2] << " "
-  //       << maskExtent[3] << " " << maskExtent[4] << " " << maskExtent[5] << std::endl;
-  SetDisplayExtentAndCameraPosition(orientation, mSlice, maskExtent, mImageActorList[mTSlice], 0.0);
+  SetDisplayExtentAndCameraPosition(orientation, mSlice, maskExtent, mImageActorList[mTSlice], mDepth);
 
   // set previous slice
   mPreviousTSlice = mSlicer->GetTSlice();
@@ -297,18 +294,12 @@ void vvBinaryImageOverlayActor::ComputeExtent(int orientation,
 //----------------------------------------------------------------------------
 void vvBinaryImageOverlayActor::ComputeExtent(int * inExtent, int * outExtent, vtkImageData * image, vtkImageData * overlay)
 {
-  outExtent[0] = (( image->GetOrigin()[0] + inExtent[0]*image->GetSpacing()[0] ) - overlay->GetOrigin()[0]) /
-                 overlay->GetSpacing()[0];
-  outExtent[1] = (( image->GetOrigin()[0] + inExtent[1]*image->GetSpacing()[0] ) - overlay->GetOrigin()[0]) /
-                 overlay->GetSpacing()[0];
-  outExtent[2] = (( image->GetOrigin()[1] + inExtent[2]*image->GetSpacing()[1] ) - overlay->GetOrigin()[1]) /
-                 overlay->GetSpacing()[1];
-  outExtent[3] = (( image->GetOrigin()[1] + inExtent[3]*image->GetSpacing()[1] ) - overlay->GetOrigin()[1]) /
-                 overlay->GetSpacing()[1];
-  outExtent[4] = (( image->GetOrigin()[2] + inExtent[4]*image->GetSpacing()[2] ) - overlay->GetOrigin()[2]) /
-                 overlay->GetSpacing()[2];
-  outExtent[5] = (( image->GetOrigin()[2] + inExtent[5]*image->GetSpacing()[2] ) - overlay->GetOrigin()[2]) /
-                 overlay->GetSpacing()[2];
+  outExtent[0] = (int)lrint(((image->GetOrigin()[0] + inExtent[0]*image->GetSpacing()[0]) - overlay->GetOrigin()[0]) / overlay->GetSpacing()[0]);
+  outExtent[1] = (int)lrint(((image->GetOrigin()[0] + inExtent[1]*image->GetSpacing()[0]) - overlay->GetOrigin()[0]) / overlay->GetSpacing()[0]);
+  outExtent[2] = (int)lrint(((image->GetOrigin()[1] + inExtent[2]*image->GetSpacing()[1]) - overlay->GetOrigin()[1]) / overlay->GetSpacing()[1]);
+  outExtent[3] = (int)lrint(((image->GetOrigin()[1] + inExtent[3]*image->GetSpacing()[1]) - overlay->GetOrigin()[1]) / overlay->GetSpacing()[1]);
+  outExtent[4] = (int)lrint(((image->GetOrigin()[2] + inExtent[4]*image->GetSpacing()[2]) - overlay->GetOrigin()[2]) / overlay->GetSpacing()[2]);
+  outExtent[5] = (int)lrint(((image->GetOrigin()[2] + inExtent[5]*image->GetSpacing()[2]) - overlay->GetOrigin()[2]) / overlay->GetSpacing()[2]);
 }
 //----------------------------------------------------------------------------
 
@@ -320,23 +311,27 @@ void vvBinaryImageOverlayActor::SetDisplayExtentAndCameraPosition(int orientatio
                                                                  vtkImageActor * actor,
                                                                  double position)
 {
+  /* FIXME
+     Error according to camera orientation
+   */
+
   // Set position
   if (orientation == vtkImageViewer2::SLICE_ORIENTATION_XY) {
-    if (mSlicer->GetRenderer()->GetActiveCamera()->GetPosition()[2] > slice)
-      actor->SetPosition(0,0, position);
-    else
+    //if (mSlicer->GetRenderer()->GetActiveCamera()->GetPosition()[2] > slice)
       actor->SetPosition(0,0, -position);
+      //else
+      //actor->SetPosition(0,0, position);
   }
   if (orientation == vtkImageViewer2::SLICE_ORIENTATION_XZ) {
-    if (mSlicer->GetRenderer()->GetActiveCamera()->GetPosition()[1] > slice)
-      actor->SetPosition(0,position,0);
-    else
+    //if (mSlicer->GetRenderer()->GetActiveCamera()->GetPosition()[1] > slice)
+    // actor->SetPosition(0,position,0);
+    //else
       actor->SetPosition(0,-position,0);
   }
   if (orientation == vtkImageViewer2::SLICE_ORIENTATION_YZ) {
-    if (mSlicer->GetRenderer()->GetActiveCamera()->GetPosition()[0] > slice)
-      actor->SetPosition(position,0, 0);
-    else
+    //if (mSlicer->GetRenderer()->GetActiveCamera()->GetPosition()[0] > slice)
+    //  actor->SetPosition(position,0, 0);
+    //else
       actor->SetPosition(-position,0, 0);
   }
   actor->SetDisplayExtent(extent);
index dfa310920e54aa8e2b3d42280c664305200f5e24..0b02c6277c350ce2f7c9826afcf6deae080e3da6 100644 (file)
@@ -41,9 +41,10 @@ class vvBinaryImageOverlayActor : public itk::LightObject
   void SetColor(double r, double g, double b);
   void SetOpacity(double d);
   void SetImage(vvImage * image, double bg, bool modeBG=true);
+  void SetDepth(double d) { mDepth = d; }
   void Initialize(bool IsVisible=true);
   void UpdateColor();
-  void UpdateSlice(int slicer, int slice);
+  void UpdateSlice(int slicer, int slice, bool force=false);
   void HideActors();
   void ShowActors();
 
@@ -60,6 +61,7 @@ class vvBinaryImageOverlayActor : public itk::LightObject
   double mForegroundValue;
   bool m_modeBG;
   vtkSmartPointer<vtkLookupTable> mColorLUT;
+  double mDepth;
 
   std::vector<vtkSmartPointer<vtkImageMapToRGBA> > mMapperList;
   std::vector<vtkSmartPointer<vtkImageActor> > mImageActorList;
index 94129031759648c7808a40f6216b12b95ef74d1d..173bde0e900e9f80b28cdf5c85bf87d906b8afb7 100644 (file)
@@ -36,6 +36,7 @@ vvImageContour::vvImageContour()
   mDisplayModeIsPreserveMemory = true;
   SetPreserveMemoryModeEnabled(true);
   mPreviousOrientation = -1;
+  mDepth = 1.0;
 }
 //------------------------------------------------------------------------------
 
@@ -291,8 +292,7 @@ void vvImageContour::UpdateActor(vtkActor * actor,
                                  vtkMarchingSquares * squares, 
                                  vtkImageClip * clipper, 
                                  double threshold, int orientation, int slice) {
-  
-   // Set parameter for the MarchigSquare
+  // Set parameter for the MarchigSquare
   squares->SetValue(0, threshold);
 
   // Get image extent
@@ -312,15 +312,16 @@ void vvImageContour::UpdateActor(vtkActor * actor,
     s = s-mHiddenImage->GetFirstVTKImageData()->GetOrigin()[orientation]; // from corner second image
     s = s/mHiddenImage->GetFirstVTKImageData()->GetSpacing()[orientation]; // in voxel
 
-    if (s == floor(s)) {
-      extent2[orientation*2] = extent2[orientation*2+1] = (int)floor(s);
-    } else {
-      extent2[orientation*2] = (int)floor(s);
-      extent2[orientation*2+1] = extent2[orientation*2];
-    }
+    // Rint to the closest slice
+    extent2[orientation*2+1] = extent2[orientation*2] = (int)lrint(s);
 
     // Do not display a contour if there is no contour on this slice
-    if (extent2[orientation*2+1] > extent3[orientation*2+1]) {
+    // DD(extent2[orientation*2+1]);
+    // DD(extent3[orientation*2+1]);
+    // DD(extent2[orientation*2]);
+    // DD(extent3[orientation*2]);
+    if ((extent2[orientation*2+1] > extent3[orientation*2+1]) ||
+        (extent2[orientation*2] < extent3[orientation*2])) {
       actor->VisibilityOff();
       return;
     }
@@ -338,7 +339,7 @@ void vvImageContour::UpdateActor(vtkActor * actor,
 
   // Move the actor to be visible
   double position[3] = {0, 0, 0};
-  position[orientation] = -1;
+  position[orientation] = -mDepth;
   actor->SetPosition(position);
   
   mapper->Update();
index d2be5129a6e00d6bb1d7c63dbe7f5b1ff1815b56..2c92abb07551028e6d0794dd99379ee2ceb6ec6f 100644 (file)
@@ -43,6 +43,7 @@ public:
   void SetLineWidth(double w);
   void SetImage(vvImage * image);
   void SetPreserveMemoryModeEnabled(bool b);
+  void SetDepth(double d) { mDepth = d; }
 
 protected:
   vvSlicer * mSlicer;
@@ -54,6 +55,7 @@ protected:
   bool mHiddenImageIsUsed;
   vvImage * mHiddenImage;
   bool mDisplayModeIsPreserveMemory;
+  double mDepth;
 
   // For preserveMemory mode
   std::vector<vtkSmartPointer<vtkActor> > mSquaresActorList;
index 3c50b8457c688b51a88a4fd0609a0b9044787205..bfc5343f62484176c130c229e6a0491b910ea441 100644 (file)
@@ -67,6 +67,8 @@ void vvMeshActor::Init(vvMesh::Pointer mesh,int time_slice,vvImage::Pointer vf)
 
 void vvMeshActor::SetCutSlice(double slice)
 {
+  DD("SetCutSlice");
+  DD(slice);
   mCutSlice=slice;
   vtkImageData* mask;
   if (static_cast<unsigned int>(mTimeSlice)<mMesh->GetNumberOfMasks())
index f4abf28fb9b4c785c08101264c0dd8bf311deee8..b46ae0ac990b0bcc058f6b864292fb3c1d467761 100644 (file)
@@ -40,6 +40,7 @@ vvROIActor::vvROIActor()
   mContourWidth = 1;
   mContourColor.resize(3);
   m_modeBG = true;
+  mDepth = 1.0;
 }
 //------------------------------------------------------------------------------
 
@@ -78,7 +79,7 @@ void vvROIActor::UpdateImage()
 {
   mOverlayActors.clear();
   mImageContour.clear();
-  Initialize(mIsVisible);
+  Initialize(mDepth, mIsVisible);
   Update(); // No Render
 }
 //------------------------------------------------------------------------------
@@ -133,10 +134,11 @@ bool vvROIActor::IsContourVisible() {
 
 
 //------------------------------------------------------------------------------
-void vvROIActor::Initialize(bool IsVisible) {
+void vvROIActor::Initialize(double depth, bool IsVisible) {
   if (mROI->GetImage()) {
     mImageContour.clear();
     mOverlayActors.clear();
+    mDepth = depth;
     for(int i=0; i<mSlicerManager->GetNumberOfSlicers(); i++) {
 
       mImageContour.push_back(vvImageContour::New());
@@ -148,6 +150,7 @@ void vvROIActor::Initialize(bool IsVisible) {
       mImageContour[i]->SetColor(mContourColor[0], mContourColor[1], mContourColor[2]);
       mImageContour[i]->SetLineWidth(mContourWidth);
       mImageContour[i]->SetPreserveMemoryModeEnabled(true);
+      mImageContour[i]->SetDepth(mDepth);
       //mImageContour[i]->SetPreserveMemoryModeEnabled(false); // SEG FAULT !!!
       mImageContour[i]->SetSlicer(mSlicerManager->GetSlicer(i));
       mImageContour[i]->HideActors();
@@ -168,7 +171,8 @@ void vvROIActor::Initialize(bool IsVisible) {
                                   mROI->GetDisplayColor()[2]);
       mOverlayActors[i]->SetOpacity(mOpacity);
       mOverlayActors[i]->SetSlicer(mSlicerManager->GetSlicer(i));
-      mOverlayActors[i]->Initialize(IsVisible);
+      mOverlayActors[i]->Initialize(IsVisible);      
+      mOverlayActors[i]->SetDepth(mDepth);
     }
 
     connect(mSlicerManager,SIGNAL(UpdateSlice(int,int)),this,SLOT(UpdateSlice(int, int)));
@@ -180,17 +184,30 @@ void vvROIActor::Initialize(bool IsVisible) {
 
 
 //------------------------------------------------------------------------------
-void vvROIActor::Update()
+void vvROIActor::SetDepth(double d)
+{
+  mDepth = d;
+  for(int i=0; i<mSlicerManager->GetNumberOfSlicers(); i++) {  
+    mOverlayActors[i]->SetDepth(d);
+    mImageContour[i]->SetDepth(d);
+  }
+  Update(true);
+}
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+void vvROIActor::Update(bool force)
 {
   for(int i=0; i<mSlicerManager->GetNumberOfSlicers(); i++) {
-    UpdateSlice(i, mSlicerManager->GetSlicer(i)->GetSlice());
+    UpdateSlice(i, mSlicerManager->GetSlicer(i)->GetSlice(), force);
   }
 }
 //------------------------------------------------------------------------------
 
 
 //------------------------------------------------------------------------------
-void vvROIActor::UpdateSlice(int slicer, int slices)
+void vvROIActor::UpdateSlice(int slicer, int slices, bool force)
 {
   if (!mROI->GetImage())  return;
   if ((!mIsVisible) && (!mIsContourVisible)) return; 
@@ -204,7 +221,7 @@ void vvROIActor::UpdateSlice(int slicer, int slices)
   }
 
   // Refresh overlays
-  mOverlayActors[slicer]->UpdateSlice(slicer, slices);
+  mOverlayActors[slicer]->UpdateSlice(slicer, slices, force);
 }
 //------------------------------------------------------------------------------
 
index fb85658773b8528a00d37c7a6d7aadaa7697ddf0..42182cbb11ee1314fb56122fc18281460346912a 100644 (file)
@@ -37,8 +37,8 @@ class vvROIActor: public QObject {
   void SetROI(clitk::DicomRT_ROI * r);
   clitk::DicomRT_ROI * GetROI() { return mROI; }
   void SetSlicerManager(vvSlicerManager * s);
-  void Update();
-  void Initialize(bool IsVisible=true);
+  void Update(bool force=false);
+  void Initialize(double d=1.0, bool IsVisible=true);
   void SetVisible(bool b);
   void SetContourVisible(bool b);
   bool IsVisible();
@@ -51,9 +51,11 @@ class vvROIActor: public QObject {
   void SetContourColor(double r, double v, double b);
   std::vector<double> & GetContourColor();
   void SetBGMode(bool b) { m_modeBG = b; }
+  void SetDepth(double d);
+  double GetDepth() { return mDepth; }
 
 public slots:
-  void UpdateSlice(int slicer, int slices);
+  void UpdateSlice(int slicer, int slices, bool force=false);
   void UpdateColor();
   void UpdateImage();
 
@@ -70,6 +72,7 @@ public slots:
   int mContourWidth;
   std::vector<double> mContourColor;
   bool m_modeBG;
+  double mDepth;
 
 }; // end class vvROIActor
 //------------------------------------------------------------------------------
index 7fcfb01149d04d012e8f0b3a925c7379001fb6eb..b7860d350ced70c255df6c1cafe6de881ed1473c 100644 (file)
@@ -103,7 +103,7 @@ void vvStructureSetActor::CreateNewROIActor(int n, bool modeBG)
   actor->SetBGMode(modeBG);
   actor->SetROI(roi);
   actor->SetSlicerManager(mSlicerManager);
-  actor->Initialize();
+  actor->Initialize(n+1); // depth is n+1 to start at 1
   mMapROIIndex[n] = mROIActors.size()-1;
 }
 //------------------------------------------------------------------------------
index f625e4cd46ef0945fa3c40df9036a2be50e547ee..097f5009e7b7700233ac710ff553f75a446b7c83 100644 (file)
@@ -159,6 +159,7 @@ void vvToolStructureSetManager::InputIsSelected(vvSlicerManager *m)
   connect(mContourCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleContourROIToggled(bool)));  
   connect(mChangeContourColorButton, SIGNAL(clicked()), this, SLOT(ChangeContourColor()));
   connect(mContourWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeContourWidth(int)));
+  connect(mDepthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeDepth(int)));
   connect(mReloadButton, SIGNAL(clicked()), this, SLOT(ReloadCurrentROI()));
   connect(mCheckBoxShowAll, SIGNAL(stateChanged(int)), this, SLOT(AllVisibleROIToggled(int)));
   connect(mContourCheckBoxShowAll, SIGNAL(toggled(bool)), this, SLOT(AllVisibleContourROIToggled(bool)));
@@ -188,6 +189,8 @@ void vvToolStructureSetManager::AddRoiInTreeWidget(clitk::DicomRT_ROI * roi, QTr
   QTreeWidgetItem * w = mTreeWidgetList.back().data();
   w->setText(0, QString("%1").arg(roi->GetROINumber()));
   w->setText(1, QString("%1").arg(roi->GetName().c_str()));
+  vvROIActor * actor = mStructureSetActorsList[0]->GetROIActor(roi->GetROINumber());  
+  w->setText(3, QString("%1").arg(actor->GetDepth()));  
   QBrush brush(QColor(roi->GetDisplayColor()[0]*255, roi->GetDisplayColor()[1]*255, roi->GetDisplayColor()[2]*255));
   brush.setStyle(Qt::SolidPattern);
   w->setBackground(2, brush);
@@ -441,24 +444,40 @@ void vvToolStructureSetManager::SelectedItemChangedInTree() {
   mCurrentROI = roi;
   mCurrentROIActor = actor;
 
+  // Warning -> avoid unuseful Render here by disconnect slider 
   // Update GUI
+  disconnect(mTree, SIGNAL(itemSelectionChanged()), this, SLOT(SelectedItemChangedInTree()));
+  disconnect(mCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleROIToggled(bool)));
+  disconnect(mOpacitySlider, SIGNAL(valueChanged(int)), this, SLOT(OpacityChanged(int)));
+  disconnect(mChangeColorButton, SIGNAL(clicked()), this, SLOT(ChangeColor()));
+  disconnect(mContourCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleContourROIToggled(bool)));  
+  disconnect(mChangeContourColorButton, SIGNAL(clicked()), this, SLOT(ChangeContourColor()));
+  disconnect(mContourWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeContourWidth(int)));
+  disconnect(mDepthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeDepth(int)));
+
   mGroupBoxROI->setEnabled(true);
   mROInameLabel->setText(roi->GetName().c_str());
   mCheckBoxShow->setChecked(actor->IsVisible());
   mContourCheckBoxShow->setChecked(actor->IsContourVisible());
   mContourWidthSpinBox->setValue(actor->GetContourWidth());
-  
-  // Warning -> avoir unuseful Render here by disconnect slider 
-  disconnect(mOpacitySlider, SIGNAL(valueChanged(int)), 
-            this, SLOT(OpacityChanged(int)));
+  mDepthSpinBox->setValue(actor->GetDepth());
+  w->setText(3, QString("%1").arg(actor->GetDepth()));
   mOpacitySlider->setValue((int)lrint(actor->GetOpacity()*100));
   mOpacitySpinBox->setValue((int)lrint(actor->GetOpacity()*100));
-  connect(mOpacitySlider, SIGNAL(valueChanged(int)), 
-         this, SLOT(OpacityChanged(int)));
-  actor->Update(); 
 
+  connect(mTree, SIGNAL(itemSelectionChanged()), this, SLOT(SelectedItemChangedInTree()));
+  connect(mCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleROIToggled(bool)));
+  connect(mOpacitySlider, SIGNAL(valueChanged(int)), this, SLOT(OpacityChanged(int)));
+  connect(mChangeColorButton, SIGNAL(clicked()), this, SLOT(ChangeColor()));
+  connect(mContourCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleContourROIToggled(bool)));  
+  connect(mChangeContourColorButton, SIGNAL(clicked()), this, SLOT(ChangeContourColor()));
+  connect(mContourWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeContourWidth(int)));
+  connect(mDepthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeDepth(int)));
+
+  // is this needed ?
+  //  actor->Update(); 
   // Final rendering
-  mCurrentSlicerManager->Render();
+  // mCurrentSlicerManager->Render();
 }
 //------------------------------------------------------------------------------
 
@@ -597,6 +616,18 @@ void vvToolStructureSetManager::ChangeContourWidth(int n) {
 //------------------------------------------------------------------------------
 
 
+//------------------------------------------------------------------------------
+void vvToolStructureSetManager::ChangeDepth(int n) {
+  mCurrentROIActor->SetDepth(n);
+  mCurrentROIActor->UpdateImage();
+  mCurrentSlicerManager->Render();
+  QList<QTreeWidgetItem *> l = mTree->selectedItems();
+  QTreeWidgetItem * w = l[0];
+  w->setText(3, QString("%1").arg(mCurrentROIActor->GetDepth()));
+}
+//------------------------------------------------------------------------------
+
+
 //------------------------------------------------------------------------------
 void vvToolStructureSetManager::ReloadCurrentROI() {
   // Reload image
index 4fd4d8ed4090e12b24688340ef92a01c46f80dcb..0f5ffec81a4c6d413fc0a5a85833c59153fbf6d4 100644 (file)
@@ -63,6 +63,7 @@ public slots:
   void ChangeColor();
   void ChangeContourColor();
   void ChangeContourWidth(int n);
+  void ChangeDepth(int n);
   void AllVisibleROIToggled(int b);
   void AllVisibleContourROIToggled(bool b);
   void ReloadCurrentROI();