]> Creatis software - clitk.git/commitdiff
Merge branch 'master' of git.creatis.insa-lyon.fr:clitk
authorDavid Sarrut <david.sarrut@gmail.com>
Mon, 29 Oct 2012 15:45:31 +0000 (16:45 +0100)
committerDavid Sarrut <david.sarrut@gmail.com>
Mon, 29 Oct 2012 15:45:31 +0000 (16:45 +0100)
30 files changed:
common/clitkImageUtilities.h [deleted file]
common/clitkImageUtilities.txx [deleted file]
itk/clitkAutoCropFilter.txx
itk/clitkCropLikeImageFilter.txx
itk/clitkLabelImageOverlapMeasureFilter.h
itk/clitkLabelImageOverlapMeasureFilter.txx
itk/clitkSegmentationUtils.txx
itk/clitkSliceBySliceRelativePositionFilter.txx
segmentation/CMakeLists.txt
segmentation/clitkExtractLungFilter.txx
segmentation/clitkRegionGrowing.cxx [moved from common/clitkImageUtilities.cxx with 55% similarity]
segmentation/clitkRegionGrowing.ggo [new file with mode: 0644]
segmentation/clitkRegionGrowingGenericFilter.cxx [new file with mode: 0644]
segmentation/clitkRegionGrowingGenericFilter.h [new file with mode: 0644]
segmentation/clitkRegionGrowingGenericFilter.txx [new file with mode: 0644]
tools/clitkCropImageGenericFilter.cxx
tools/clitkImageStatistics.cxx
tools/clitkImageStatistics.ggo
tools/clitkImageStatisticsGenericFilter.cxx
tools/clitkImageStatisticsGenericFilter.h
tools/clitkImageStatisticsGenericFilter.txx
vv/CMakeLists.txt
vv/qt_ui/vvToolSegmentation.ui
vv/vvROIActor.cxx
vv/vvSlicerManager.cxx
vv/vvSlicerManager.h
vv/vvSlicerManagerCommand.cxx
vv/vvToolROIManager.cxx
vv/vvToolSegmentation.cxx
vv/vvToolSegmentation.h

diff --git a/common/clitkImageUtilities.h b/common/clitkImageUtilities.h
deleted file mode 100644 (file)
index ab12d21..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*=========================================================================
-  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
-===========================================================================**/
-#ifndef CLITKIMAGEUTILITIES_H
-#define CLITKIMAGEUTILITIES_H
-/**
- ===================================================================
- * @file   clitkImageUtilities.h
- * @author David Sarrut <David.Sarrut@creatis.insa-lyon.fr>
- * @date   22 Sep 2006 10:38:36
-
- * @brief  
-
- ===================================================================*/
-
-// clitk
-#include "clitkCommon.h"
-#include "clitkImageCommon.h"
-
-// std
-#include <vector>
-#include <map>
-#include <set>
-
-// itk
-#include "itkImageRegionConstIterator.h"
-
-namespace clitk {
-  
-  template<class ImageType>
-  int ComputeHowManyDifferentIntensity(const typename ImageType::Pointer & image, 
-                                                                          std::vector<typename ImageType::PixelType> & listOfIntensities);
-  #include "clitkImageUtilities.txx"
-
-} // end namespace
-
-#endif /* end #define CLITKIMAGEUTILITIES_H */
-
diff --git a/common/clitkImageUtilities.txx b/common/clitkImageUtilities.txx
deleted file mode 100644 (file)
index 8f42551..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*=========================================================================
-  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
-===========================================================================**/
-#ifndef CLITKIMAGEUTILITIES_TXX
-#define CLITKIMAGEUTILITIES_TXX
-/**
- =================================================
- * @file   clitkImageUtilities.txx
- * @author David Sarrut <david.sarrut@creatis.insa-lyon.fr>
- * @date   22 Sep 2006 10:39:48
- *
- * @brief
- *
- *
- =================================================*/
-
-//====================================================================
-// Compute the number of different intensities in an image
-template<class ImageType>
-int ComputeHowManyDifferentIntensity(const typename ImageType::Pointer & image,
-                                     std::vector<typename ImageType::PixelType> & l)
-{
-  //std::set<typename ImageType::PixelType> listOfIntensities;
-  std::map<typename ImageType::PixelType, bool> listOfIntensities;
-  //  listOfIntensities.resize(0);
-  typedef itk::ImageRegionConstIterator<ImageType> ConstIteratorType;
-  ConstIteratorType pi(image, image->GetLargestPossibleRegion());
-  pi.Begin();
-  while (!pi.IsAtEnd()) {
-    if (!listOfIntensities[pi.Get()]) listOfIntensities[pi.Get()] = true;
-    // if (std::find(listOfIntensities.begin(),
-//                               listOfIntensities.end(),
-//                               pi.Get()) == listOfIntensities.end()) {
-//       listOfIntensities.insert(pi.Get());
-//     }
-    ++pi;
-  }
-
-  //typename std::set<typename ImageType::PixelType>::const_iterator ppi = listOfIntensities.begin();
-  typename std::map<typename ImageType::PixelType, bool>::const_iterator ppi = listOfIntensities.begin();
-  while (ppi != listOfIntensities.end()) {
-    l.push_back(ppi->first);
-    ++ppi;
-  }
-
-  return listOfIntensities.size();
-}
-//====================================================================
-
-//====================================================================
-template<class InputImageType, class MaskImageType>
-void ComputeWeightsOfEachClasses(const typename InputImageType::Pointer & input,
-                                 const typename MaskImageType::Pointer & mask,
-                                 const std::vector<typename MaskImageType::PixelType> & listOfIntensities,
-                                 std::map<typename MaskImageType::PixelType,
-                                 std::map<typename InputImageType::PixelType, double> > & mapOfLabelsAndWeights)
-{
-  // Check size
-  if (input->GetLargestPossibleRegion() != mask->GetLargestPossibleRegion()) {
-    itkGenericExceptionMacro(<< "Input and mask images have not the same size"
-                             << std::endl
-                             << "Input = " << input->GetLargestPossibleRegion()
-                             << std::endl
-                             << "Mask = " << mask->GetLargestPossibleRegion());
-  }
-
-  // reset weights list
-  mapOfLabelsAndWeights.clear();
-
-  // loop
-  typedef itk::ImageRegionConstIterator<InputImageType> ConstInputIteratorType;
-  ConstInputIteratorType pi(input, input->GetLargestPossibleRegion());
-  typedef itk::ImageRegionConstIterator<MaskImageType> ConstMaskIteratorType;
-  ConstMaskIteratorType pm(mask, mask->GetLargestPossibleRegion());
-  pi.Begin();
-  pm.Begin();
-  while (!pi.IsAtEnd()) {
-    mapOfLabelsAndWeights[pm.Get()][pi.Get()]++;
-    ++pi;
-    ++pm;
-  }
-}
-//====================================================================
-
-// //====================================================================
-// template<class ImageType>
-// typename ImageType::Pointer NewImage3D(int x, int y, int z, float dx, float dy, float dz) {
-//   typename ImageType::Pointer output = ImageType::New();
-//   typename ImageType::RegionType region;
-//   typename ImageType::SizeType size;
-//   size[0] = x;
-//   size[1] = y;
-//   size[2] = z;
-//   region.SetSize(size);
-//   output->SetRegions(region);
-//   output->Allocate();
-//   typename ImageType::SpacingType spacing;
-//   spacing[0] = dx;
-//   spacing[1] = dy;
-//   spacing[2] = dz;
-//   output->SetSpacing(spacing);
-//   return output;
-// }
-// //====================================================================
-
-
-#endif /* end #define CLITKIMAGEUTILITIES_TXX */
-
index 71f9ab08b0f07e93e3c3ec3495cef208e104c563..e31e424d43bb2ce99d25889edf74b25464aa048b 100644 (file)
@@ -97,8 +97,9 @@ namespace clitk {
     autoCropFilter->SetInput(imageToLabelFilter->GetOutput());
     //    autoCropFilter->ReleaseDataFlagOff(); 
     if (GetUseBorder()) {
-      DD("UseBorder seems buggy ?");
-      exit(0);
+      DD("Crop UseBorder : not correctly implemented do not use (use PadLabelMapFilter)");
+      // http://www.itk.org/Doxygen/html/classitk_1_1AutoCropLabelMapFilter.html#a54f49fdff8d9f2d2313134109d510285
+      exit(0); 
       typename ImageType::SizeType s;
       for(uint i=0; i<ImageType::ImageDimension; i++) s[i] = 1;
       autoCropFilter->SetCropBorder(s);
index 519c5fd4e6a8f3015112e081c152dc4c9844f595..6399ec6ac7e5419ca870e6e7cd61bf6b072810ef 100644 (file)
@@ -269,7 +269,10 @@ clitk::ResizeImageLike(const ImageType * input,
 {
   typename ImageType::Pointer output = ImageType::New();
   output->CopyInformation(input);
-  output->SetRegions(region);
+  typename ImageType::RegionType reg;
+  reg.SetIndex(region->GetIndex());
+  reg.SetSize(region->GetSize());
+  output->SetRegions(reg);
   output->Allocate();
   return clitk::ResizeImageLike<ImageType>(input, output, backgroundValue);
 }
index 17581f633ad9bb94d815b1e549ca19615dabaa58..17b7c21fce67e7f95f5b44e004d4e598caeda384 100644 (file)
@@ -29,6 +29,8 @@
 #include <itkImageToImageFilter.h>
 #include <itkLabelStatisticsImageFilter.h>
 
+#include <iomanip>
+
 namespace clitk {
   
   //--------------------------------------------------------------------
index 57516bb41634db8996e3822aa0d91ad748b2c110..a29aa6a3f810eb1987a8adbd2f62b82bc7d1e4a2 100644 (file)
@@ -121,8 +121,13 @@ GenerateData()
   statFilter->Update();
   int in2 = statFilter->GetCount(GetLabel1());
 
-  std::cout << in1 << " " << in2 << " " << inter << " " << u << " " 
-            << 2.0*(double)inter/(double)(in1+in2) << std::endl;
+  double dice = 2.0*(double)inter/(double)(in1+in2);
+  int width = 6;
+  std::cout << std::setw(width) << in1 << " "
+            << std::setw(width) << in2 << " "
+            << std::setw(width) << inter  << " "
+            << std::setw(width) << u  << " "
+            << std::setw(width) << dice << " "; //std::endl;
 }
 //--------------------------------------------------------------------
 
index b7a5de50693c5f078b19ea2245076f3c384c4657..a57d8136becb4b919b1b1bc9360f6343c6547028 100644 (file)
@@ -1321,11 +1321,11 @@ namespace clitk {
       // Compute dmap for S1 *TO PUT IN FONCTION*
       dmap = clitk::DistanceMap<SliceType>(slices_s1[i], BG);
       dmaps1.push_back(dmap);
-      writeImage<FloatImageType>(dmap, "dmap1.mha");
+      //writeImage<FloatImageType>(dmap, "dmap1.mha");
       // Compute dmap for S2
       dmap = clitk::DistanceMap<SliceType>(slices_s2[i], BG);
       dmaps2.push_back(dmap);
-      writeImage<FloatImageType>(dmap, "dmap2.mha");
+      //writeImage<FloatImageType>(dmap, "dmap2.mha");
       
       // Look in S2 for the point the closest to S1
       typename SliceType::PointType p = ComputeClosestPoint<SliceType>(slices_s1[i], dmaps2[i], BG);
index db3c677c0e8701c2a424676fcd72117e26576b12..e68514da031c0f6f1a6725a2df78f97d0c189fe7 100644 (file)
@@ -78,7 +78,7 @@ clitk::SliceBySliceRelativePositionFilter<ImageType>::
 PrintOptions(std::ostream & os) 
 {
   os << "Slice direction = " << this->GetDirection() << std::endl
-     << "BG value        = " << this->GetBackgroundValue() << std::endl;
+     << "BG value        = " << (int)this->GetBackgroundValue() << std::endl;
   for(int i=0; i<this->GetNumberOfAngles(); i++) {
     os << "Orientation     = " << this->GetOrientationTypeString()[i] << std::endl;
     os << "Angles     = " << clitk::rad2deg(this->GetAngle1InRad(i)) 
index e5ec8d4ca01dcbe5943aa104ad871bac9fa1bb70..f26ec74c203d0ee38e5df3dba5192b250d459a44 100644 (file)
@@ -1,7 +1,7 @@
 #=========================================================
 
 # Add Libraries used in vv and clitk to avoid recompilation
-FOREACH(clitkTool clitkExtractLung clitkExtractPatient)
+FOREACH(clitkTool clitkExtractLung clitkExtractPatient clitkConnectedComponentLabeling clitkRegionGrowing)
     WRAP_GGO(${clitkTool}_GGO_C ${clitkTool}.ggo)
     SET(GGO_C_FILES ${GGO_C_FILES} ${${clitkTool}_GGO_C})
 ENDFOREACH(clitkTool)
@@ -46,6 +46,10 @@ IF(CLITK_BUILD_SEGMENTATION)
     TARGET_LINK_LIBRARIES(clitkMotionMask clitkCommon ${ITK_LIBRARIES})
     SET(SEGMENTATION_INSTALL ${SEGMENTATION_INSTALL} clitkMotionMask)
     
+    WRAP_GGO(clitkRegionGrowing_GGO_C clitkRegionGrowing.ggo)
+    ADD_EXECUTABLE(clitkRegionGrowing clitkRegionGrowing.cxx ${clitkRegionGrowing_GGO_C} ${clitkRelativePosition_GGO_C})
+    TARGET_LINK_LIBRARIES(clitkRegionGrowing clitkCommon ${ITK_LIBRARIES})
+
     SET_TARGET_PROPERTIES(${SEGMENTATION_INSTALL} PROPERTIES INSTALL_RPATH "${VTK_DIR}:${ITK_DIR}" )  
     INSTALL (TARGETS ${SEGMENTATION_INSTALL} DESTINATION bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE)
 
index ffca1df50276062599cbcd22e76666cc25ce9a07..f84a0956fb61d1bc48cf202c5481267e132bf2cd 100644 (file)
@@ -47,6 +47,8 @@
 #include "itkOrientImageFilter.h"
 #include "itkSpatialOrientationAdapter.h"
 #include "itkImageDuplicator.h"
+#include "itkRelabelComponentImageFilter.h"
+
 #include <fcntl.h>
 
 //--------------------------------------------------------------------
@@ -67,6 +69,7 @@ ExtractLungFilter():
   SetForegroundValue(1);
   SetMinimalComponentSize(100);
   VerboseRegionGrowingFlagOff();
+  RemoveSmallLabelBeforeSeparationFlagOn();
 
   // Step 1 default values
   SetUpperThreshold(-300);
@@ -436,7 +439,7 @@ GenerateOutputInformation()
     //--------------------------------------------------------------------
     //--------------------------------------------------------------------
     StartNewStep("Separate Left/Right lungs");
-      PrintMemory(GetVerboseMemoryFlag(), "Before Separate");
+    PrintMemory(GetVerboseMemoryFlag(), "Before Separate");
     // Initial label
     working_mask = Labelize<MaskImageType>(working_mask, 
                                           GetBackgroundValue(), 
@@ -451,9 +454,33 @@ GenerateOutputInformation()
     statisticsImageFilter->SetInput(working_mask);
     statisticsImageFilter->Update();
     unsigned int initialNumberOfLabels = statisticsImageFilter->GetMaximum();
-    working_mask = statisticsImageFilter->GetOutput(); 
-    
+    working_mask = statisticsImageFilter->GetOutput();     
     PrintMemory(GetVerboseMemoryFlag(), "After count label");
+
+    // If already 2 labels, but a too big differences, remove the
+    // smalest one (sometimes appends with the stomach
+    if (initialNumberOfLabels >1) {
+      if (GetRemoveSmallLabelBeforeSeparationFlag()) {
+        DD(GetRemoveSmallLabelBeforeSeparationFlag());
+        typedef itk::RelabelComponentImageFilter<MaskImageType, MaskImageType> RelabelFilterType;
+        typename RelabelFilterType::Pointer relabelFilter = RelabelFilterType::New();
+        relabelFilter->SetInput(working_mask);
+        relabelFilter->SetMinimumObjectSize(10);
+        relabelFilter->Update();
+        const std::vector<float> & a = relabelFilter->GetSizeOfObjectsInPhysicalUnits();
+        std::vector<MaskImagePixelType> remove_label;
+        for(unsigned int i=1; i<a.size(); i++) {
+          if (a[i] < 0.5*a[0]) { // more than 0.5 difference
+            remove_label.push_back(i+1); // label zero is BG
+          }
+        }
+        working_mask = 
+          clitk::RemoveLabels<MaskImageType>(working_mask, GetBackgroundValue(), remove_label);
+        statisticsImageFilter->SetInput(working_mask);
+        statisticsImageFilter->Update();
+        initialNumberOfLabels = statisticsImageFilter->GetMaximum();
+      }
+    }
   
     // Decompose the first label
     if (initialNumberOfLabels<2) {
similarity index 55%
rename from common/clitkImageUtilities.cxx
rename to segmentation/clitkRegionGrowing.cxx
index eb3d1bcd792ee870aff9e7e6c745c09657d9e550..d24d2f72d9f3ec21ec4eb6708a0f4c297eac8519 100644 (file)
@@ -1,7 +1,7 @@
 /*=========================================================================
   Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
 
-  Authors belong to:
+  Authors belong to: 
   - University of LYON              http://www.universite-lyon.fr/
   - Léon Bérard cancer center       http://www.centreleonberard.fr
   - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
   - BSD        See included LICENSE.txt file
   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
 ===========================================================================**/
-#ifndef CLITKIMAGEUTILITIES_CXX
-#define CLITKIMAGEUTILITIES_CXX
-/**
- =================================================
- * @file   clitkImageUtilities.cxx
- * @author David Sarrut <david.sarrut@creatis.insa-lyon.fr>
- * @date   22 Sep 2006 10:39:40
- *
- * @brief
- *
- *
- =================================================*/
-
-#include "clitkImageUtilities.h"
-
-#endif /* end #define CLITKIMAGEUTILITIES_CXX */
 
+// clitk
+#include "clitkRegionGrowing_ggo.h"
+#include "clitkIO.h"
+#include "clitkRegionGrowingGenericFilter.h"
+
+//--------------------------------------------------------------------
+int main(int argc, char * argv[]) {
+
+  // Init command line
+  GGO(clitkRegionGrowing, args_info);
+  CLITK_INIT;
+
+  // Filter
+  typedef clitk::RegionGrowingGenericFilter<args_info_clitkRegionGrowing> FilterType;
+  FilterType::Pointer genericFilter = FilterType::New();
+  
+  genericFilter->SetArgsInfo(args_info);
+  genericFilter->Update();
+
+  return EXIT_SUCCESS;
+}// end main
+
+//--------------------------------------------------------------------
diff --git a/segmentation/clitkRegionGrowing.ggo b/segmentation/clitkRegionGrowing.ggo
new file mode 100644 (file)
index 0000000..cd2d03e
--- /dev/null
@@ -0,0 +1,34 @@
+#File clitkRegionGrowing.ggo
+package "clitkRegionGrowing"
+version "1.0"
+purpose "Region growing from a seed point using various types of conditions to control the growing"
+
+option "config"                -       "Config file"                     string        no
+option "verbose"       v       "Verbose"                         flag          off
+
+section "I/O"
+
+option "input"         i       "Input image filename"            string        yes
+option "output"        o       "Output image filename"           string        yes
+
+
+section "Parameters"
+
+option "type"          t       "Region growing filter type: 0=threshold , 1=neighborhood-threshold , 2=confidence , 3= locally-adaptive-threshold, 4= explosion-controlled-threshold" int      no      default="0"
+option "lower"         l       "1,2,3,4: Lower threshold value"                  double        no      default="310"
+option "upper"         u       "1,2,3,4: Upper threshold value"                  double        no      default="4000"
+option "maxUpper"      -       "4: Maximum upper threshold value"                double        no      default="2000"
+option "minLower"      -       "4: Minimum lower threshold value"                double        no      default="-1000"
+option "step"          -       "4: Threshold step size"                          double        no      default="64.0"
+option "minStep"       -       "4: Minimum threshold step size"                  double        no      default="1"
+option "adaptLower"    -       "3,4: (locally) adapt lower thresholding"         flag          off
+option "adaptUpper"    -       "3,4: (locally) adapt upper thresholding"         flag          off
+option "multiplier"            m       "2-4: (2-3) accept if within mean+-mutiplier*SD, (4) explosion if size increases multiplier times"      double  no      default="2.0"
+option "seed"          s       "Seed index postion (in voxels)"                  int           multiple        no      default="0"     
+option "seedRadius"            -       "Radius used for seed dilatation(in voxel)"       int           multiple        no      default="0"     
+option "pad"           p       "The replace padding value"                       double        no              default="1.0"   
+option "radius"        r       "1-3: The radius of the neighborhood"             int           no              multiple        default="1"
+option "maxSD"         -       "3: Limit to SD"                                  double        no       
+option "full"          -       "4: use full connectivity (not implemented yet)"  flag          off      
+option "iter"          -       "2: Iterations"                                   int           no      default="5"
+                
diff --git a/segmentation/clitkRegionGrowingGenericFilter.cxx b/segmentation/clitkRegionGrowingGenericFilter.cxx
new file mode 100644 (file)
index 0000000..f5092ba
--- /dev/null
@@ -0,0 +1,72 @@
+/*=========================================================================
+  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
+===========================================================================**/
+#ifndef clitkRegionGrowingGenericFilter_cxx
+#define clitkRegionGrowingGenericFilter_cxx
+
+/* =================================================
+ * @file   clitkRegionGrowingGenericFilter.cxx
+ * @author 
+ * @date   
+ * 
+ * @brief 
+ * 
+ ===================================================*/
+
+#include "clitkRegionGrowingGenericFilter.h"
+
+
+namespace clitk
+{
+
+
+  //-----------------------------------------------------------
+  // Constructor
+  //-----------------------------------------------------------
+  RegionGrowingGenericFilter::RegionGrowingGenericFilter()
+  {
+    m_Verbose=false;
+    m_InputFileName="";
+  }
+
+
+  //-----------------------------------------------------------
+  // Update
+  //-----------------------------------------------------------
+  void RegionGrowingGenericFilter::Update()
+  {
+    // Read the Dimension and PixelType
+    int Dimension;
+    std::string PixelType;
+    ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType);
+
+    
+    // Call UpdateWithDim
+    if(Dimension==2) UpdateWithDim<2>(PixelType);
+    else if(Dimension==3) UpdateWithDim<3>(PixelType);
+    // else if (Dimension==4)UpdateWithDim<4>(PixelType); 
+    else 
+      {
+       std::cout<<"Error, Only for 2 or 3  Dimensions!!!"<<std::endl ;
+       return;
+      }
+  }
+
+
+} //end clitk
+
+#endif  //#define clitkRegionGrowingGenericFilter_cxx
diff --git a/segmentation/clitkRegionGrowingGenericFilter.h b/segmentation/clitkRegionGrowingGenericFilter.h
new file mode 100644 (file)
index 0000000..225619d
--- /dev/null
@@ -0,0 +1,76 @@
+/*=========================================================================
+  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
+===========================================================================**/
+
+#ifndef CLITKREGIONGROWINGGENERICFILTER_H
+#define CLITKREGIONGROWINGGENERICFILTER_H
+
+// clitk include
+#include "clitkIO.h"
+#include "clitkImageToImageGenericFilter.h"
+#include "clitkLocallyAdaptiveThresholdConnectedImageFilter.h"
+#include "clitkExplosionControlledThresholdConnectedImageFilter.h"
+
+//itk include
+#include "itkLightObject.h"
+#include "itkConnectedThresholdImageFilter.h"
+#include "itkNeighborhoodConnectedImageFilter.h"
+#include "itkConfidenceConnectedImageFilter.h"
+#include "itkConfidenceConnectedImageFilter.h"
+
+//--------------------------------------------------------------------
+namespace clitk 
+{
+  template<class ArgsInfoType>
+  class ITK_EXPORT RegionGrowingGenericFilter: 
+    public ImageToImageGenericFilter<RegionGrowingGenericFilter<ArgsInfoType> >
+  {
+
+  public:
+    //----------------------------------------
+    RegionGrowingGenericFilter();
+
+    //----------------------------------------
+    typedef RegionGrowingGenericFilter         Self;
+    typedef itk::SmartPointer<Self>            Pointer;
+    typedef itk::SmartPointer<const Self>      ConstPointer;
+   
+    //----------------------------------------
+    itkNewMacro(Self);  
+    itkTypeMacro( RegionGrowingGenericFilter, LightObject );
+
+    //--------------------------------------------------------------------
+    void SetArgsInfo(const ArgsInfoType & a);
+
+    //--------------------------------------------------------------------
+    // Main function called each time the filter is updated
+    template<class ImageType>  
+    void UpdateWithInputImageType();
+
+  protected:
+    void Modified() {} // Need for using itkMacros
+    template<unsigned int Dim> void InitializeImageType();
+    ArgsInfoType mArgsInfo;
+
+  }; // end class
+} // end namespace clitk
+
+#ifndef ITK_MANUAL_INSTANTIATION
+#include "clitkRegionGrowingGenericFilter.txx"
+#endif
+
+#endif // #define CLITKREGIONGROWINGGENERICFILTER_H
diff --git a/segmentation/clitkRegionGrowingGenericFilter.txx b/segmentation/clitkRegionGrowingGenericFilter.txx
new file mode 100644 (file)
index 0000000..e8f3653
--- /dev/null
@@ -0,0 +1,300 @@
+/*=========================================================================
+  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
+  ===========================================================================**/
+
+#ifndef CLITKREGIONGROWINGGENERICFILTER_TXX
+#define CLITKREGIONGROWINGGENERICFILTER_TXX
+
+#include <itkBinaryBallStructuringElement.h>
+#include <itkConstShapedNeighborhoodIterator.h>
+
+
+//--------------------------------------------------------------------
+template<class ArgsInfoType>
+clitk::RegionGrowingGenericFilter<ArgsInfoType>::RegionGrowingGenericFilter():
+  ImageToImageGenericFilter<Self>("RegionGrowing") 
+{
+  InitializeImageType<2>();
+  InitializeImageType<3>();
+  //InitializeImageType<4>();
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template<class ArgsInfoType>
+template<unsigned int Dim>
+void clitk::RegionGrowingGenericFilter<ArgsInfoType>::InitializeImageType() 
+{  
+  ADD_IMAGE_TYPE(Dim, uchar);
+  ADD_IMAGE_TYPE(Dim, short);
+  // ADD_IMAGE_TYPE(Dim, int);
+  ADD_IMAGE_TYPE(Dim, float);
+}
+//--------------------------------------------------------------------
+  
+
+//--------------------------------------------------------------------
+template<class ArgsInfoType>
+void clitk::RegionGrowingGenericFilter<ArgsInfoType>::SetArgsInfo(const ArgsInfoType & a) 
+{
+  mArgsInfo=a;
+  this->SetIOVerbose(mArgsInfo.verbose_flag);
+  if (mArgsInfo.input_given)   this->AddInputFilename(mArgsInfo.input_arg);
+  if (mArgsInfo.output_given)  this->SetOutputFilename(mArgsInfo.output_arg);
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+// Update with the number of dimensions and the pixeltype
+//--------------------------------------------------------------------
+template<class ArgsInfoType>
+template<class ImageType>
+void clitk::RegionGrowingGenericFilter<ArgsInfoType>::UpdateWithInputImageType() 
+{ 
+  DD("UpdateWithInputImageType");
+  const int Dimension = ImageType::ImageDimension;
+
+  // ImageTypes
+  typedef ImageType InputImageType;
+  typedef ImageType OutputImageType;
+  typedef typename ImageType::PixelType PixelType;
+    
+  // Reading input
+  typename ImageType::Pointer input = this->template GetInput<ImageType>(0);
+
+  // Seed
+  typedef typename  std::vector<typename InputImageType::IndexType> SeedsType;
+  SeedsType seeds(1);
+  if (mArgsInfo.seed_given==Dimension)
+    for (unsigned int i=0; i<Dimension;i++)
+      seeds[0][i]=mArgsInfo.seed_arg[i];
+    
+  else if ( mArgsInfo.seed_given==1)
+    seeds[0].Fill(mArgsInfo.seed_arg[0]);
+    
+  else seeds[0].Fill(mArgsInfo.seed_arg[0]);
+  if (mArgsInfo.verbose_flag) std::cout<<"Setting seed seeds to "<<seeds[0]<<"..."<<std::endl;
+
+  if (mArgsInfo.seedRadius_given)
+    {
+      typedef itk::BinaryBallStructuringElement<PixelType, Dimension> BallType;
+      typename BallType::RadiusType r;
+
+      if (mArgsInfo.seedRadius_given == Dimension)
+        for (unsigned i = 0; i < Dimension; i++)
+          r[i] = mArgsInfo.seedRadius_arg[i];
+      else
+        r.Fill(mArgsInfo.seedRadius_arg[0]);
+
+      BallType ball;
+      ball.SetRadius(r);
+      ball.CreateStructuringElement();
+
+      typedef itk::ConstShapedNeighborhoodIterator<InputImageType> IteratorType;
+      IteratorType it(ball.GetRadius(),
+                      input,
+                      input->GetLargestPossibleRegion());
+#if ITK_VERSION_MAJOR < 4
+      typename BallType::ConstIterator nit;
+      unsigned idx = 0;
+      for (nit = ball.Begin(); nit != ball.End(); ++nit, ++idx)
+        {
+          if (*nit)
+            {
+              it.ActivateOffset(it.GetOffset(idx));
+            }
+          else
+            {
+              it.DeactivateOffset(it.GetOffset(idx));
+            }
+        }
+#else
+      it.CreateActiveListFromNeighborhood(ball);
+      it.NeedToUseBoundaryConditionOff();
+#endif
+
+      it.SetLocation(seeds[0]);
+      for (typename IteratorType::ConstIterator i = it.Begin(); !i.IsAtEnd(); ++i)
+        {
+          typename InputImageType::IndexType id = seeds[0] + i.GetNeighborhoodOffset();
+          if (id != seeds[0] && input->GetLargestPossibleRegion().IsInside(id))
+            seeds.push_back(id);
+        }
+    }
+
+  // Filter
+  typedef itk::ImageToImageFilter<InputImageType, OutputImageType> ImageToImageFilterType;
+  typename ImageToImageFilterType::Pointer filter;
+
+  switch (mArgsInfo.type_arg)
+    {
+    case 0: {
+               
+      typedef itk::ConnectedThresholdImageFilter<InputImageType, OutputImageType> ImageFilterType;
+      typename ImageFilterType::Pointer f= ImageFilterType::New();
+       
+      f->SetLower(mArgsInfo.lower_arg);
+      f->SetUpper(mArgsInfo.upper_arg);
+      f->SetReplaceValue(static_cast<PixelType>(mArgsInfo.pad_arg));
+      for (typename SeedsType::const_iterator it = seeds.begin(); it != seeds.end(); ++it)
+        f->AddSeed(*it);
+      filter=f;
+      if (mArgsInfo.verbose_flag) std::cout<<"Using the connected threshold image filter..."<<std::endl;
+
+      break;
+    }
+
+    case 1: {
+               
+      typedef itk::NeighborhoodConnectedImageFilter<InputImageType, OutputImageType> ImageFilterType;
+      typename ImageFilterType::Pointer f= ImageFilterType::New();
+       
+      // Radius
+      typename  InputImageType::SizeType size;
+      if (mArgsInfo.radius_given==Dimension)
+        for (unsigned int i=0; i<Dimension;i++)
+          size[i]=mArgsInfo.radius_arg[i];
+       
+      else if ( mArgsInfo.radius_given==1)
+        size.Fill(mArgsInfo.radius_arg[0]);
+       
+      else size.Fill(mArgsInfo.radius_arg[0]);
+      if (mArgsInfo.verbose_flag) std::cout<<"Setting neighborhood radius to "<<size<<"..."<<std::endl;
+
+      f->SetLower(mArgsInfo.lower_arg);
+      f->SetUpper(mArgsInfo.upper_arg);
+      f->SetReplaceValue(static_cast<PixelType>(mArgsInfo.pad_arg));
+      for (typename SeedsType::const_iterator it = seeds.begin(); it != seeds.end(); ++it)
+        f->AddSeed(*it);
+      f->SetRadius(size);
+      filter=f;
+      if (mArgsInfo.verbose_flag) std::cout<<"Using the neighborhood threshold connected image filter..."<<std::endl;
+
+      break;
+    }
+
+    case 2: {
+       
+      typedef itk::ConfidenceConnectedImageFilter<InputImageType, OutputImageType> ImageFilterType;
+      typename ImageFilterType::Pointer f= ImageFilterType::New();
+       
+      // Radius
+      typename  InputImageType::SizeType size;
+      if (mArgsInfo.radius_given==Dimension)
+        for (unsigned int i=0; i<Dimension;i++)
+          size[i]=mArgsInfo.radius_arg[i];
+       
+      else if ( mArgsInfo.radius_given==1)
+        size.Fill(mArgsInfo.radius_arg[0]);
+       
+      else size.Fill(mArgsInfo.radius_arg[0]);
+      if (mArgsInfo.verbose_flag) std::cout<<"Setting neighborhood radius to "<<size<<"..."<<std::endl;
+
+      f->SetMultiplier( mArgsInfo.multiplier_arg );
+      f->SetNumberOfIterations( mArgsInfo.multiplier_arg );
+      for (typename SeedsType::const_iterator it = seeds.begin(); it != seeds.end(); ++it)
+        f->AddSeed(*it);
+      f->SetNumberOfIterations( mArgsInfo.iter_arg);
+      f->SetReplaceValue(static_cast<PixelType>(mArgsInfo.pad_arg));
+      f->SetInitialNeighborhoodRadius(size[0]);
+      filter=f;
+      if (mArgsInfo.verbose_flag) std::cout<<"Using the confidence threshold connected image filter..."<<std::endl;
+       
+      break;
+    }
+
+    case 3: {
+               
+      typedef clitk::LocallyAdaptiveThresholdConnectedImageFilter<InputImageType, OutputImageType> ImageFilterType;
+      typename ImageFilterType::Pointer f= ImageFilterType::New();
+       
+      // Radius
+      typename  InputImageType::SizeType size;
+      if (mArgsInfo.radius_given==Dimension)
+        for (unsigned int i=0; i<Dimension;i++)
+          size[i]=mArgsInfo.radius_arg[i];
+      else size.Fill(mArgsInfo.radius_arg[0]);
+      if (mArgsInfo.verbose_flag) std::cout<<"Setting neighborhood radius to "<<size<<"..."<<std::endl;
+
+      // params
+      f->SetLower(mArgsInfo.lower_arg);
+      f->SetUpper(mArgsInfo.upper_arg);
+      f->SetLowerBorderIsGiven(mArgsInfo.adaptLower_flag);
+      f->SetLowerBorderIsGiven(mArgsInfo.adaptUpper_flag);
+      f->SetReplaceValue(static_cast<PixelType>(mArgsInfo.pad_arg));
+      f->SetMultiplier(mArgsInfo.multiplier_arg);
+      f->SetMaximumSDIsGiven(mArgsInfo.maxSD_given);
+      if (mArgsInfo.maxSD_given) f->SetMaximumSD(mArgsInfo.maxSD_arg);
+      for (typename SeedsType::const_iterator it = seeds.begin(); it != seeds.end(); ++it)
+        f->AddSeed(*it);
+      f->SetRadius(size);
+      filter=f;
+      if (mArgsInfo.verbose_flag) std::cout<<"Using the locally adaptive threshold connected image filter..."<<std::endl;
+
+      break;
+    }
+  
+    case 4: {
+               
+      typedef clitk::ExplosionControlledThresholdConnectedImageFilter<InputImageType, OutputImageType> ImageFilterType;
+      typename ImageFilterType::Pointer f= ImageFilterType::New();
+       
+      //       // Radius
+      //       typename  InputImageType::SizeType size;
+      //       if (mArgsInfo.radius_given==Dimension)
+      //         for (unsigned int i=0; i<Dimension;i++)
+      //           size[i]=mArgsInfo.radius_arg[i];
+      //       else size.Fill(mArgsInfo.radius_arg[0]);
+      //       if (mArgsInfo.verbose_flag) std::cout<<"Setting neighborhood radius to "<<size<<"..."<<std::endl;
+       
+      // params
+      f->SetVerbose(mArgsInfo.verbose_flag);
+      f->SetLower(mArgsInfo.lower_arg);
+      f->SetUpper(mArgsInfo.upper_arg);
+      f->SetMinimumLowerThreshold(mArgsInfo.minLower_arg);
+      f->SetMaximumUpperThreshold(mArgsInfo.maxUpper_arg);
+      f->SetAdaptLowerBorder(mArgsInfo.adaptLower_flag);
+      f->SetAdaptUpperBorder(mArgsInfo.adaptUpper_flag);
+      f->SetReplaceValue(static_cast<PixelType>(mArgsInfo.pad_arg));
+      f->SetMultiplier(mArgsInfo.multiplier_arg);
+      f->SetThresholdStepSize(mArgsInfo.step_arg);
+      f->SetMinimumThresholdStepSize(mArgsInfo.minStep_arg);
+      f->SetFullyConnected(mArgsInfo.full_flag);
+      for (typename SeedsType::const_iterator it = seeds.begin(); it != seeds.end(); ++it)
+        f->AddSeed(*it);
+      filter=f;
+      if (mArgsInfo.verbose_flag) std::cout<<"Using the explosion controlled threshold connected image filter..."<<std::endl;
+
+      break;
+    }
+  
+    }
+
+
+  filter->SetInput(input);
+  filter->Update();
+  typename OutputImageType::Pointer output=filter->GetOutput();
+
+  // Write/Save results
+  this->template SetNextOutput<OutputImageType>(output); 
+}
+//--------------------------------------------------------------------
+
+#endif //#define CLITKREGIONGROWINGGENERICFILTER_TXX
index d46f20e461a02f8a90c4e07784049b03b1ad6225..ede400746d028373718d3f3d45444ab6865a3468 100644 (file)
 #ifndef clitkCropImageGenericFilter_cxx
 #define clitkCropImageGenericFilter_cxx
 
-/* =================================================
- * @file   clitkCropImageGenericFilter.cxx
- * @author 
- * @date   
- * 
- * @brief 
- * 
- ===================================================*/
-
 #include "clitkCropImageGenericFilter.h"
 
-
 //-----------------------------------------------------------
 // Constructor
 //-----------------------------------------------------------
index 265871f0f63ca91aa7c85f2787013eb0c48d97d3..818a88c04c2ad693249db64231553a16176043df 100644 (file)
   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
 ===========================================================================**/
 
-/* =================================================
- * @file   clitkImageStatistics.cxx
- * @author 
- * @date   
- * 
- * @brief 
- * 
- ===================================================*/
-
-
 // clitk
 #include "clitkImageStatistics_ggo.h"
 #include "clitkIO.h"
@@ -43,7 +33,7 @@ int main(int argc, char * argv[]) {
   clitk::ImageStatisticsGenericFilter::Pointer genericFilter=clitk::ImageStatisticsGenericFilter::New();
   
   genericFilter->SetArgsInfo(args_info);
-  genericFilter->Update();
+  CLITK_TRY_CATCH_EXIT(genericFilter->Update());
 
   return EXIT_SUCCESS;
 }// end main
index bbb127b6fbdd30be1543c55a2b320ebf6c2bd37e..d2e55f36572162d451c80567924c92ba610eb68e 100644 (file)
@@ -15,3 +15,5 @@ option "histogram"    -       "Compute histogram, allows median calculation"  string  no
 option "bins"          -       "Number of histogram bins"                      int     no      default="100"
 option "lower"         -       "Lower histogram bound" double  no default="-1000"      
 option "upper"         -       "Upper histogram bound" double  no default="1000"               
+
+option "allow_resize"          r       "Resize mask if different from input"                     flag          off
index ddfe5e0293661220055a8aabd95259273d759403..931e1bfe7c12b8002cc2e18eeb5ba5181fb044e8 100644 (file)
 #ifndef clitkImageStatisticsGenericFilter_cxx
 #define clitkImageStatisticsGenericFilter_cxx
 
-/* =================================================
- * @file   clitkImageStatisticsGenericFilter.cxx
- * @author 
- * @date   
- * 
- * @brief 
- * 
- ===================================================*/
-
 #include "clitkImageStatisticsGenericFilter.h"
 
-
 namespace clitk
 {
 
@@ -42,7 +32,8 @@ namespace clitk
     m_Verbose=false;
     m_InputFileName="";
   }
-
+  //-----------------------------------------------------------
+  
 
   //-----------------------------------------------------------
   // Update
index 6511c0e0a0bcc30114f5606a5cc3a016e5a31dc3..00cfff8e9fad3908a391936199ab219ca909247e 100644 (file)
 #ifndef clitkImageStatisticsGenericFilter_h
 #define clitkImageStatisticsGenericFilter_h
 
-/* =================================================
- * @file   clitkImageStatisticsGenericFilter.h
- * @author 
- * @date   
- * 
- * @brief 
- * 
- ===================================================*/
-
-
 // clitk include
 #include "clitkIO.h"
 #include "clitkCommon.h"
@@ -41,7 +31,6 @@
 namespace clitk 
 {
 
-
   class ITK_EXPORT ImageStatisticsGenericFilter : public itk::LightObject
   {
   public:
index a0d2abfc609e101ece56b5b1e6606f13939f0064..7b9c78b1cb233a394cef58753e6f8a4d21374313 100644 (file)
 #include "itkNthElementImageAdaptor.h"
 #include "itkJoinSeriesImageFilter.h"
 
-/* =================================================
- * @file   clitkImageStatisticsGenericFilter.txx
- * @author 
- * @date   
- * 
- * @brief 
- * 
- ===================================================*/
 #include "clitkImageStatisticsGenericFilter.h"
-
+#include "clitkCropLikeImageFilter.h"
+#include "clitkResampleImageWithOptionsFilter.h"
 
 namespace clitk
 {
@@ -114,6 +107,7 @@ namespace clitk
       int maskDimension, maskComponents;
       std::string maskPixelType;
       ReadImageDimensionAndPixelType(m_ArgsInfo.mask_arg, maskDimension, maskPixelType, maskComponents);
+
       if (maskDimension == Dimension - 1) {
         // Due to a limitation of filter itk::LabelStatisticsImageFilter, InputImageType and LabelImageType
         // must have the same image dimension. However, we want to support label images with Dl = Di - 1,
@@ -143,6 +137,30 @@ namespace clitk
         labelImageReader->SetFileName(m_ArgsInfo.mask_arg);
         labelImageReader->Update();
         labelImage= labelImageReader->GetOutput();
+
+        // Check mask sampling/size
+        if (!HaveSameSizeAndSpacing<LabelImageType, InputImageType>(labelImage, input)) {
+          if (m_ArgsInfo.allow_resize_flag) {
+            if (m_ArgsInfo.verbose_flag) {
+              std::cout << "Resize mask image like input" << std::endl;
+            }
+            typedef clitk::ResampleImageWithOptionsFilter<LabelImageType> ResamplerType;
+            typename ResamplerType::Pointer resampler = ResamplerType::New();
+            resampler->SetInput(labelImage);
+            resampler->SetOutputSpacing(input->GetSpacing());
+            resampler->Update();
+            labelImage = resampler->GetOutput();
+
+            typename itk::ImageBase<LabelImageType::ImageDimension>::RegionType reg 
+              = input->GetLargestPossibleRegion();
+            labelImage = ResizeImageLike<LabelImageType>(labelImage, &reg, 0);
+          }
+          else {
+            std::cerr << "Mask image has a different size/spacing than input. Abort" << std::endl;
+            exit(-1);
+          }
+        }
+
       }
 
     }
index 8fb0ac5c5c45234e2b24c66e42b18d08a88f1691..3e279923ea2c78a96c481626be2ca0f0fb0f772f 100644 (file)
@@ -23,6 +23,7 @@ SET(vv_TOOLS
   vvToolMIP
   vvToolConvert ## with dummy vvToolConvert.ui
   vvToolROIManager
+  vvToolSegmentation
 
   ## these ones are for tests (not working)
   # vvToolFoo
index 4931841a1dd45545acf8528ad0702774f0a38890..625b4faec06cfc48a88f38f134092b06ae62524d 100644 (file)
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>408</width>
-    <height>285</height>
+    <width>401</width>
+    <height>489</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>Binarize image</string>
   </property>
-  <widget class="QPushButton" name="pushButton">
-   <property name="geometry">
-    <rect>
-     <x>140</x>
-     <y>120</y>
-     <width>86</width>
-     <height>27</height>
-    </rect>
-   </property>
-   <property name="text">
-    <string>PushButton</string>
-   </property>
-  </widget>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QFrame" name="frame">
+     <property name="frameShape">
+      <enum>QFrame::StyledPanel</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Raised</enum>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_2">
+      <item row="0" column="0">
+       <widget class="QLabel" name="label_2">
+        <property name="text">
+         <string>Ref mask size</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1">
+       <widget class="QLabel" name="mRefMaskSizeLabel">
+        <property name="text">
+         <string>12303 voxels (65464 mm3)</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="QLabel" name="label_3">
+        <property name="text">
+         <string>Current mask size</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <widget class="QLabel" name="mCurrentMaskSizeLabel">
+        <property name="text">
+         <string>12303 voxels (65464 mm3)</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="0">
+       <widget class="QLabel" name="label_4">
+        <property name="text">
+         <string>Label mask sizes</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="1">
+       <widget class="QTextEdit" name="textEdit">
+        <property name="maximumSize">
+         <size>
+          <width>16777215</width>
+          <height>50</height>
+         </size>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QFrame" name="frame_2">
+     <property name="frameShape">
+      <enum>QFrame::StyledPanel</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Raised</enum>
+     </property>
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="0" column="1">
+       <widget class="QLabel" name="label_10">
+        <property name="text">
+         <string>12 56 32</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="QLabel" name="label_12">
+        <property name="text">
+         <string>Current pos (mm)</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <widget class="QLabel" name="label_11">
+        <property name="text">
+         <string>12.3 56.6 32.9</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="0">
+       <widget class="QLabel" name="label_14">
+        <property name="text">
+         <string>Image value</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="1">
+       <widget class="QLabel" name="label_13">
+        <property name="text">
+         <string>236</string>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="0">
+       <widget class="QLabel" name="label_15">
+        <property name="text">
+         <string>Ref mask</string>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="1">
+       <widget class="QLabel" name="label_16">
+        <property name="text">
+         <string>Inside</string>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="0">
+       <widget class="QLabel" name="label_18">
+        <property name="text">
+         <string>Current mask</string>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="1">
+       <widget class="QLabel" name="label_17">
+        <property name="text">
+         <string>Outside</string>
+        </property>
+       </widget>
+      </item>
+      <item row="5" column="0">
+       <widget class="QLabel" name="label_19">
+        <property name="text">
+         <string>Label mask</string>
+        </property>
+       </widget>
+      </item>
+      <item row="5" column="1">
+       <widget class="QLabel" name="label_20">
+        <property name="text">
+         <string>Outside</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="0">
+       <widget class="QLabel" name="label_9">
+        <property name="text">
+         <string>Current pos (pix)</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>Log</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QTextEdit" name="mLogText">
+     <property name="readOnly">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QPushButton" name="pushButton_2">
+     <property name="text">
+      <string>Save current mask</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QPushButton" name="pushButton">
+     <property name="text">
+      <string>Quit</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
  </widget>
  <resources/>
  <connections/>
index e7f82f6b5fe084f2257ca3f8bba13205893b4b0f..74d588328865cdfa27ca192a0d44daf5cdcb7a3d 100644 (file)
@@ -35,7 +35,7 @@ vvROIActor::vvROIActor()
 {
   mIsVisible = true;
   mIsContourVisible = false;
-  mOpacity = 0.7;
+  mOpacity = 0.5;
   mIsSelected = false;
   mContourWidth = 1;
   mContourColor.resize(3);
@@ -166,10 +166,10 @@ void vvROIActor::Initialize(double depth, bool IsVisible) {
       mImageContour.push_back(vvImageContour::New());
       mImageContour[i]->SetSlicer(mSlicerManager->GetSlicer(i));
       mImageContour[i]->SetImage(mROI->GetImage());
-      // Color of the contour is "complement" of roi color
-      mContourColor[0] = 1-mROI->GetDisplayColor()[0];
-      mContourColor[1] = 1-mROI->GetDisplayColor()[1];
-      mContourColor[2] = 1-mROI->GetDisplayColor()[2];
+      // Color of the contour is same of roi color
+      mContourColor[0] = mROI->GetDisplayColor()[0];
+      mContourColor[1] = mROI->GetDisplayColor()[1];
+      mContourColor[2] = mROI->GetDisplayColor()[2];
       mImageContour[i]->SetColor(mContourColor[0], mContourColor[1], mContourColor[2]);
       mImageContour[i]->SetLineWidth(mContourWidth);
       mImageContour[i]->SetPreserveMemoryModeEnabled(true);
index 015409b2debdf12cc501dd6b0226eddabf77e6a8..b175c46ccc642665487641e20c102b2e8c8e5d37 100644 (file)
@@ -417,6 +417,23 @@ void vvSlicerManager::LeftButtonReleaseEvent(int slicer)
 }
 //----------------------------------------------------------------------------
 
+
+//----------------------------------------------------------------------------
+void vvSlicerManager::EmitMousePositionUpdated(int slicer)
+{
+  emit MousePositionUpdatedSignal(slicer);
+}
+//----------------------------------------------------------------------------
+
+
+//----------------------------------------------------------------------------
+void vvSlicerManager::EmitKeyPressed(std::string KeyPress)
+{
+  emit KeyPressedSignal(KeyPress);
+}
+//----------------------------------------------------------------------------
+
+
 //----------------------------------------------------------------------------
 void vvSlicerManager::SetSliceOrientation(int slicer, int orientation)
 {
@@ -641,18 +658,18 @@ void vvSlicerManager::UpdateViews(int current,int slicer)
         }
         switch (mSlicers[i]->GetSliceOrientation()) {
         case vtkImageViewer2::SLICE_ORIENTATION_XY:
-          if (mSlicers[i]->GetSlice() != (int)floor(z))
-            mSlicers[i]->SetSlice((int)floor(z));
+          if (mSlicers[i]->GetSlice() != (int)lrint(z))
+            mSlicers[i]->SetSlice((int)lrint(z));
           break;
 
         case vtkImageViewer2::SLICE_ORIENTATION_XZ:
-          if (mSlicers[i]->GetSlice() != (int)floor(y))
-            mSlicers[i]->SetSlice((int)floor(y));
+          if (mSlicers[i]->GetSlice() != (int)lrint(y))
+            mSlicers[i]->SetSlice((int)lrint(y));
           break;
 
         case vtkImageViewer2::SLICE_ORIENTATION_YZ:
-          if (mSlicers[i]->GetSlice() != (int)floor(x))
-            mSlicers[i]->SetSlice((int)floor(x));
+          if (mSlicers[i]->GetSlice() != (int)lrint(x))
+            mSlicers[i]->SetSlice((int)lrint(x));
           break;
         }
         
index dcac673216f1af7eef36b8394dfa32bb6dbbf8f9..4fc274c5e4723ce460984cc7850de60ea60dbc58 100644 (file)
@@ -212,6 +212,8 @@ class vvSlicerManager : public QObject {
   void Activated();
   void Picked();
   void UpdateInfoOnCursorPosition(int slicer);
+  void EmitMousePositionUpdated(int slicer);
+  void EmitKeyPressed(std::string keyPress);
   void UpdateWindowLevel();
   void UpdateSlice(int slicer);
   void UpdateTSlice(int slicer);
@@ -234,6 +236,8 @@ signals :
   void UpdateVector(int display, double x, double y, double z, double value);
   void UpdateOverlay(int display, double valueOver, double valueRef);
   void UpdateFusion(int display, double valueFus);
+  void MousePositionUpdatedSignal(int slicer);
+  void KeyPressedSignal(std::string KeyPressed);
   void UpdateOrientation(int slicer, int orientation);
   void UpdateSlice(int slicer, int slice);
   void UpdateTSlice(int slicer, int slice);
index 73a0ab5efda3e79ba42b604908662a2149806b4b..ad80b925a6d0b5bfc34fe6516e5f1d889bf9c003 100644 (file)
@@ -266,6 +266,7 @@ void vvSlicerManagerCommand::Execute(vtkObject *caller,
           this->SM->UpdateSliceRange(VisibleInWindow);
         }
 
+        this->SM->EmitKeyPressed(KeyPress);
       }
 
       //All type of mouse events
@@ -276,7 +277,6 @@ void vvSlicerManagerCommand::Execute(vtkObject *caller,
         return;
       }
 
-      //DD(event);
       // Mouse release HERE
       if (event == vtkCommand::EndPickEvent) {
         //           DD(VisibleInWindow);
@@ -363,12 +363,24 @@ void vvSlicerManagerCommand::Execute(vtkObject *caller,
         break;
       }
 
+      // <<<<<<< HEAD
+      //       this->SM->GetSlicer(VisibleInWindow)->SetCurrentPosition(xWorld,yWorld,zWorld,
+      //                           this->SM->GetSlicer(VisibleInWindow)->GetTSlice());
+      //       // We propagate the mouse position
+      //       this->SM->EmitMousePositionUpdated(VisibleInWindow);      
+      // =======
       double p[3]; p[0] = xWorld; p[1] = yWorld; p[2] = zWorld;
       double pt[3];
       this->SM->GetSlicer(VisibleInWindow)->GetSlicingTransform()->TransformPoint(p, pt);
 
       this->SM->GetSlicer(VisibleInWindow)->SetCurrentPosition(pt[0],pt[1],pt[2],
           this->SM->GetSlicer(VisibleInWindow)->GetMaxCurrentTSlice());
+
+      // We propagate the mouse position
+      this->SM->EmitMousePositionUpdated(VisibleInWindow);
+
+      //>>>>>>> 921642d767beba2442dacc8fdb40dc36396e1b7d
+
       if (newLandmark) {
         this->SM->AddLandmark(xWorld,yWorld,zWorld,
                               this->SM->GetSlicer(VisibleInWindow)->GetTSlice());
index 8b0a48753671fc735e6cfed736dae8d62bfda1d1..e1d2e5c534e2f586d45657d3911a14417d6e6641 100644 (file)
@@ -491,9 +491,7 @@ void vvToolROIManager::UpdateAllContours()
   for(unsigned int i=0; i<mROIList.size(); i++) {
     mROIActorsList[i]->Update();
   }
-  for(int i=0; i<mCurrentSlicerManager->GetNumberOfSlicers(); i++) {
-    mCurrentSlicerManager->GetSlicer(i)->Render();
-  }
+  mCurrentSlicerManager->Render();
 }
 //------------------------------------------------------------------------------
 
@@ -679,6 +677,8 @@ void vvToolROIManager::ChangeColor() {
                 mCurrentROIActor->GetROI()->GetDisplayColor()[1],
                 mCurrentROIActor->GetROI()->GetDisplayColor()[2]);
   QColor c = QColorDialog::getColor(color, this, "Choose the ROI color");
+  if (!c.isValid()) return;// User cancel
+
   mCurrentROIActor->GetROI()->SetDisplayColor(c.redF(), c.greenF(), c.blueF());
   mCurrentROIActor->UpdateColor();
 
index dea3513013aff27801512bdf4143ed40830bd990..341084df8a4792c316ef0533d6b98a64c45190d1 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
-===========================================================================**/
+  ===========================================================================**/
 
 // vv
 #include "vvToolSegmentation.h"
 #include "vvToolInputSelectorWidget.h"
 #include "vvImageWriter.h"
 
+// clitk
+#include "clitkConnectedComponentLabeling_ggo.h"
+#include "clitkConnectedComponentLabelingGenericFilter.h"
+#include "clitkRegionGrowing_ggo.h"
+#include "clitkRegionGrowingGenericFilter.h"
+
 // Qt
 #include <QFileDialog>
 #include <QMessageBox>
@@ -30,7 +36,8 @@
 // vtk
 #include "vtkImageContinuousErode3D.h"
 #include "vtkImageContinuousDilate3D.h"
+#include "vtkRenderWindow.h"
+
 //------------------------------------------------------------------------------
 // Create the tool and automagically (I like this word) insert it in
 // the main window menu.
@@ -64,7 +71,16 @@ vvToolSegmentation::vvToolSegmentation(vvMainWindowBase * parent, Qt::WindowFlag
   AddInputSelector("Select one image");
   
   // Init
+  mCurrentLabelUnderMousePointer = 0.0;
+  mCurrentMousePositionInMM.resize(3);
+  //  mCurrentMousePositionInPixel.resize(3);
+  mRefMaskImage = NULL;
+  mCurrentState = State_Default;
   mKernelValue = 3; // FIXME must be odd. If even -> not symmetrical
+  mDefaultLUTColor = vtkSmartPointer<vtkLookupTable>::New();
+  mDefaultLUTColor->SetNumberOfTableValues(256);
+#include "vvDefaultLut.h"
+  
 }
 //------------------------------------------------------------------------------
 
@@ -72,6 +88,7 @@ vvToolSegmentation::vvToolSegmentation(vvMainWindowBase * parent, Qt::WindowFlag
 //------------------------------------------------------------------------------
 vvToolSegmentation::~vvToolSegmentation()
 {
+  DD("destructor");
 }
 //------------------------------------------------------------------------------
 
@@ -79,7 +96,14 @@ vvToolSegmentation::~vvToolSegmentation()
 //------------------------------------------------------------------------------
 bool vvToolSegmentation::close()
 {
-  mRefMaskActor->RemoveActors();
+  DD("remo ref");
+  if (mRefMaskActor) mRefMaskActor->RemoveActors();
+  DD("remo mask");
+  if (mCurrentMaskActor) mCurrentMaskActor->RemoveActors();
+  for(int i=0; i<mCurrentCCLActors.size(); i++) {
+    if (mCurrentCCLActors[i]) mCurrentCCLActors[i]->RemoveActors();
+  }
+  DD("wclose");
   QWidget::close();  
   mCurrentSlicerManager->Render();
   return true;
@@ -106,6 +130,21 @@ void vvToolSegmentation::InputIsSelected(vvSlicerManager * m)
 
   // Open mask
   OpenBinaryImage();
+  
+  // If cancel: stop
+  if (mRefMaskActor == NULL) {
+    close();
+    return;
+  }
+
+  // Update gui
+  mToolInputSelectionWidget->hide();
+
+  // Connect mouse position
+  connect(mCurrentSlicerManager, SIGNAL(MousePositionUpdatedSignal(int)),
+          this, SLOT(MousePositionChanged(int)));
+  connect(mCurrentSlicerManager, SIGNAL(KeyPressedSignal(std::string)),
+          this, SLOT(KeyPressed(std::string)));
 }
 //------------------------------------------------------------------------------
 
@@ -149,69 +188,222 @@ void vvToolSegmentation::OpenBinaryImage()
     return;
   }
 
-  mMaskImage = reader->GetOutput();
-  int dim = mMaskImage->GetNumberOfDimensions();
+  mRefMaskImage = reader->GetOutput();
+  int dim = mRefMaskImage->GetNumberOfDimensions();
   if (dim != 3 ) {
     QMessageBox::information(this,tr("Sorry only 3D yet"), tr("Sorry only 3D yet"));
     close();
     return;
   }
 
-  // Add a new roi actor
-  mRefMaskActor = QSharedPointer<vvROIActor>(new vvROIActor);
-  std::vector<double> color;
-  color.push_back(1);
-  color.push_back(0);
-  color.push_back(0);
-  clitk::DicomRT_ROI::Pointer roi = clitk::DicomRT_ROI::New();
-  roi->SetFromBinaryImage(mMaskImage, 1, std::string("toto"), color, filename.toStdString());
-  mRefMaskActor->SetBGMode(true);
-  mRefMaskActor->SetROI(roi);
-  mRefMaskActor->SetSlicerManager(mCurrentSlicerManager);
-  mRefMaskActor->Initialize(10, true);
+  reader = vvImageReader::New();
+  reader->SetInputFilenames(filenames);
+  reader->Update(vvImageReader::IMAGE);
+  mCurrentMaskImage = reader->GetOutput();
+
+  // Add a new roi actor for the current mask
+  mCurrentMaskActor = CreateMaskActor(mCurrentMaskImage, 1, 0, false);
+  mCurrentMaskActor->Update(); // default color is red
+  UpdateMaskSize(mCurrentMaskImage, mCurrentMaskSizeInPixels, mCurrentMaskSizeInCC);  
+
+  // Add a mask actor for the reference
+  mRefMaskActor = CreateMaskActor(mRefMaskImage, 0, 1, true);
+  mRefMaskActor->SetContourVisible(true);
+  mRefMaskActor->SetVisible(false);
+  mRefMaskActor->SetContourColor(0,1,0); // green contour
+  mRefMaskActor->UpdateColor();
   mRefMaskActor->Update();
+  UpdateMaskSize(mRefMaskImage, mRefMaskSizeInPixels, mRefMaskSizeInCC);  
 
-  // Prepare widget to get keyboard event
-  grabKeyboard();
-  //connect(this, SIGNAL(keyPressEvent(QKeyEvent*)), this, SLOT(keyPressed(QKeyEvent*)));
+  // Update GUI
+  UpdateMaskSizeLabels();
 }
 //------------------------------------------------------------------------------
 
 
 //------------------------------------------------------------------------------
-void vvToolSegmentation::keyPressEvent(QKeyEvent * event)
+void vvToolSegmentation::UpdateMaskSizeLabels()
 {
-  vvToolWidgetBase::keyPressEvent(event);
-  //DD("key");
-  
-  if (event->text() == "e") {
+  QString s("%1 pix (%2 cm3)");
+  s = s.arg(mRefMaskSizeInPixels).arg(mRefMaskSizeInCC);
+  mRefMaskSizeLabel->setText(s);
+  QString s2("%1 pix (%2 cm3)");
+  s2 = s2.arg(mCurrentMaskSizeInPixels).arg(mCurrentMaskSizeInCC);
+  mCurrentMaskSizeLabel->setText(s2);
+}
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+void vvToolSegmentation::UpdateMaskSize(vvImage::Pointer image, long & pix, double & cc)
+{
+  pix = ComputeNumberOfPixels(image, GetForegroundValue());
+  double vol = image->GetSpacing()[0]*image->GetSpacing()[1]*image->GetSpacing()[2];
+  cc = pix * vol / (10*10*10);
+}
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+long vvToolSegmentation::ComputeNumberOfPixels(vvImage::Pointer image, double value) 
+{
+  int n=0;
+  vtkImageData * im = image->GetFirstVTKImageData();
+  char * pPix = (char*)im->GetScalarPointer(); // FIXME char ?
+  for(uint i=0; i<im->GetNumberOfPoints(); i++) {
+    if (pPix[i] == value) n++;
+  }
+  DD(n);
+  return n;
+}
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+void vvToolSegmentation::KeyPressed(std::string KeyPress)
+{ 
+  if (KeyPress == "G") {
+    RegionGrowing();
+  }
+  if (KeyPress == "e") {
     Erode();
   }
-  if (event->text() == "d") {
+  if (KeyPress == "d") {
     Dilate(); // FIXME -> extend image BB !!
   }
-  if (event->text() == "s") {
+  if (KeyPress == "L") {
+    Labelize(); 
+  }
+  if (KeyPress == "m") {
+    Merge(); 
+    UpdateAndRenderNewMask();
+  }
+  if (KeyPress == "s") { // Supress "Remove" one label
+    if (mCurrentState == State_CCL) RemoveLabel();
+  }
+  if (KeyPress == "t") { // display remove ref contour
+    mRefMaskActor->SetContourVisible(!mRefMaskActor->IsContourVisible());
+    mRefMaskActor->UpdateColor();
+    mCurrentSlicerManager->Render();
+  }
+  if (KeyPress == "w") {
     vvImageWriter::Pointer writer = vvImageWriter::New();
     writer->SetOutputFileName("a.mha");
-    writer->SetInput(mMaskImage);
+    writer->SetInput(mCurrentMaskImage);
     writer->Update();
   }
 }
 //------------------------------------------------------------------------------
 
 
+//------------------------------------------------------------------------------
+void vvToolSegmentation::RegionGrowing()
+{
+  DD("RegionGrowing");
+  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+  // Merge labels if needed
+  Merge();
+  // Get mouse location
+  DD(mCurrentLabelUnderMousePointer); 
+  DDV(mCurrentMousePositionInMM, 3);
+  //  DDV(mCurrentMousePositionInPixel, 3);
+
+  // Build RG filter parameters
+  typedef args_info_clitkRegionGrowing ArgsInfoType;
+  ArgsInfoType a;
+  cmdline_parser_clitkRegionGrowing_init(&a);
+  // FIXME parameters
+  a.type_arg = 4;  // FIXME set by gui 
+  DD(a.lower_arg);
+  a.lower_arg = 200;
+  a.upper_arg = 3000;
+  a.seed_given = 3;
+  a.seed_arg = new int[3];
+
+  DDV(mCurrentMousePositionInMM, 3);
+  vtkImageData * image = mCurrentImage->GetFirstVTKImageData();
+  double x = (mCurrentMousePositionInMM[0] - image->GetOrigin()[0]) / image->GetSpacing()[0];
+  double y = (mCurrentMousePositionInMM[1] - image->GetOrigin()[1]) / image->GetSpacing()[1];
+  double z = (mCurrentMousePositionInMM[2] - image->GetOrigin()[2]) / image->GetSpacing()[2];
+  a.seed_arg[0] = x;
+  a.seed_arg[1] = y;
+  a.seed_arg[2] = z;
+  a.verbose_flag = 1;
+
+  // Build RG filter parameters
+  typedef clitk::RegionGrowingGenericFilter<args_info_clitkRegionGrowing> FilterType;
+  FilterType::Pointer filter = FilterType::New();
+  filter->SetArgsInfo(a);
+  filter->SetInputVVImage(mCurrentImage);
+  filter->SetIOVerbose(true);  
+  filter->Update();
+  mCurrentMaskImage = filter->GetOutputVVImage();
+  DD("filter done");
+
+  mCurrentMaskActor->RemoveActors();
+  mCurrentMaskActor = CreateMaskActor(mCurrentMaskImage, 1, 0, false);
+  mCurrentMaskActor->Update(); // default color is red
+  UpdateAndRenderNewMask();
+  UpdateMaskSizeLabels();
+  DD("end");
+  
+  // mouse pointer
+  QApplication::restoreOverrideCursor();
+}  
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+void vvToolSegmentation::Merge()
+{
+  if (mCurrentState != State_CCL) return;
+  
+  DD("Merge");
+  // Remove actors
+  for(int i=0; i<mCurrentCCLActors.size(); i++) {
+    if (mCurrentCCLActors[i]) {
+      mCurrentCCLActors[i]->SetVisible(false);
+      mCurrentCCLActors[i]->RemoveActors();
+    }
+  }
+  mCurrentCCLActors.clear();
+
+  // Compute new mask
+  vtkImageData * ccl  = mCurrentCCLImage->GetFirstVTKImageData();
+  vtkImageData * mask = mCurrentMaskImage->GetFirstVTKImageData();
+  int * pCCL = (int*)ccl->GetScalarPointer();
+  char * pPix = (char*)mask->GetScalarPointer();
+  for(uint i=0; i<ccl->GetNumberOfPoints(); i++) {
+    if (pCCL[i] == 0) pPix[i] = GetBackgroundValue(); // copy BG. In CCL BG is always 0
+  }
+
+  // Display new mask and remove ccl
+  mCurrentCCLImage->Reset();
+  mCurrentMaskActor->RemoveActors(); // kill it
+  mCurrentMaskActor = CreateMaskActor(mCurrentMaskImage, 1, 0, false); // renew
+  mCurrentMaskActor->Update();
+  mCurrentMaskActor->SetVisible(true); 
+  // mCurrentSlicerManager->Render();
+  mCurrentState = State_Default;
+}
+//------------------------------------------------------------------------------
+
+
 //------------------------------------------------------------------------------
 void vvToolSegmentation::Erode()
 {
   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+  // Merge labels if needed
+  Merge();
+  // Get image and start erosion
   vtkImageContinuousErode3D* erode = vtkImageContinuousErode3D::New();
   erode->SetKernelSize(mKernelValue,mKernelValue,mKernelValue);
-  vtkImageData* image = mMaskImage->GetVTKImages()[0];
+  vtkImageData* image = mCurrentMaskImage->GetVTKImages()[0];
   erode->SetInput(image);
   erode->Update();
   image->DeepCopy(erode->GetOutput());
   image->Update();
-  UpdateAndRender();
+  UpdateAndRenderNewMask();
   erode->Delete();
   QApplication::restoreOverrideCursor();
 }
@@ -222,14 +414,17 @@ void vvToolSegmentation::Erode()
 void vvToolSegmentation::Dilate()
 {
   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+  // Merge labels if needed
+  Merge();
+  // Get image and start dilatation
   vtkImageContinuousDilate3D* dilate = vtkImageContinuousDilate3D::New();
   dilate->SetKernelSize(mKernelValue,mKernelValue,mKernelValue);
-  vtkImageData* image = mMaskImage->GetVTKImages()[0];
+  vtkImageData* image = mCurrentMaskImage->GetVTKImages()[0];
   dilate->SetInput(image);
   dilate->Update();
   image->DeepCopy(dilate->GetOutput());
   image->Update();
-  UpdateAndRender();
+  UpdateAndRenderNewMask();
   dilate->Delete();
   QApplication::restoreOverrideCursor();
 }
@@ -237,18 +432,177 @@ void vvToolSegmentation::Dilate()
 
 
 //------------------------------------------------------------------------------
-void vvToolSegmentation::UpdateAndRender()
+void vvToolSegmentation::UpdateAndRenderNewMask()
 {
-  bool visible = mRefMaskActor->IsVisible();
-  bool cvisible = mRefMaskActor->IsContourVisible();
-  mRefMaskActor->SetVisible(false);
-  mRefMaskActor->SetContourVisible(false);
+  bool visible = mCurrentMaskActor->IsVisible();
+  bool cvisible = mCurrentMaskActor->IsContourVisible();
+  mCurrentMaskActor->SetVisible(false);
+  mCurrentMaskActor->SetContourVisible(false);
+  mCurrentMaskActor->UpdateImage();
+  mCurrentMaskActor->SetVisible(visible);
+  mCurrentMaskActor->SetContourVisible(cvisible);
+
   mCurrentSlicerManager->Render();
+  UpdateMaskSize(mCurrentMaskImage, mCurrentMaskSizeInPixels, mCurrentMaskSizeInCC);
+  UpdateMaskSizeLabels();
+}
+//------------------------------------------------------------------------------
 
-  //mRefMaskActor->RemoveActors();
-  mRefMaskActor->UpdateImage();
-  mRefMaskActor->SetVisible(visible);
-  mRefMaskActor->SetContourVisible(cvisible);
+//------------------------------------------------------------------------------
+void vvToolSegmentation::Labelize()
+{
+  if (mCurrentState == State_CCL) return; // Do nothing in this case
+  DD("Labelize");
+  // Waiting cursos
+  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+  mCurrentMaskActor->SetVisible(false);
+  
+  // Build CCL filter
+  vtkImageData* image = mCurrentMaskImage->GetVTKImages()[0];
+  typedef args_info_clitkConnectedComponentLabeling ArgsInfoType;
+  ArgsInfoType a;
+  cmdline_parser_clitkConnectedComponentLabeling_init(&a);
+  a.inputBG_arg = GetBackgroundValue();
+  a.full_flag = false;  // FIXME set by gui
+  a.minSize_arg = 100;  // FIXME set by gui 
+  typedef clitk::ConnectedComponentLabelingGenericFilter<ArgsInfoType> FilterType;
+  FilterType::Pointer filter = FilterType::New();
+  filter->SetArgsInfo(a);
+  filter->SetInputVVImage(mCurrentMaskImage); // FIXME Check type is ok ? convert float ?
+  filter->SetIOVerbose(true);  
+  filter->Update();
+  DD(filter->GetOriginalNumberOfObjects());
+  DD(filter->GetSizeOfObjectsInPixels().size());
+  mCurrentCCLImage = filter->GetOutputVVImage();
+  DDV(filter->GetSizeOfObjectsInPixels(), filter->GetSizeOfObjectsInPixels().size());
+  DD("filter done");
+
+  /*
+  // DEBUG
+  vvImageWriter::Pointer writer = vvImageWriter::New();
+  writer->SetInput(mCurrentCCLImage);
+  writer->SetOutputFileName("bidon-ccl.mha");
+  writer->Update(); 
+  DD(mCurrentCCLImage->IsScalarTypeInteger());
+  */
+  
+  // Create actors 
+  int n = filter->GetSizeOfObjectsInPixels().size();
+  mCurrentCCLActors.clear();
+  for(int i=1; i<=std::min(n,10); i++) { // Start at 1 because 0 is BG. FIXME max by gui
+    QSharedPointer<vvROIActor> actor = CreateMaskActor(mCurrentCCLImage, i, i+1, false); 
+    mCurrentCCLActors.push_back( actor );
+    actor->Update();    
+  }
+  //  mCurrentMaskActor->Update();
   mCurrentSlicerManager->Render();
+  
+  // UpdateAndRender();
+  mCurrentState = State_CCL;
+  QApplication::restoreOverrideCursor();
+}
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+QSharedPointer<vvROIActor> vvToolSegmentation::CreateMaskActor(vvImage::Pointer image, int i, int colorID, bool BGMode)
+{
+  static int depth = 1;
+  depth += 1;
+  QSharedPointer<vvROIActor> actor = QSharedPointer<vvROIActor>(new vvROIActor);
+  double * color = mDefaultLUTColor->GetTableValue(colorID % mDefaultLUTColor->GetNumberOfTableValues ());
+  std::vector<double> c;
+  c.push_back(color[0]);
+  c.push_back(color[1]);
+  c.push_back(color[2]);
+  clitk::DicomRT_ROI::Pointer roi = clitk::DicomRT_ROI::New();
+  roi->SetFromBinaryImage(image, i, std::string("toto"), c, std::string("titi"));
+  if (BGMode) {
+    actor->SetBGMode(true);
+  }
+  else {
+    roi->SetForegroundValueLabelImage(i); // FG mode
+    actor->SetBGMode(false); // FG mode
+  }
+  actor->SetROI(roi);
+  actor->SetSlicerManager(mCurrentSlicerManager);
+  actor->Initialize(depth+i, true); // +1 to start at 1 not 0
+  actor->SetContourVisible(false);
+  actor->SetVisible(true);
+  return actor;
+}
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+void vvToolSegmentation::MousePositionChanged(int slicer)
+{
+  // DD("MousePositionChanged ");
+  // DD(slicer);
+  double x = mCurrentSlicerManager->GetSlicer(slicer)->GetCurrentPosition()[0];
+  double y = mCurrentSlicerManager->GetSlicer(slicer)->GetCurrentPosition()[1];
+  double z = mCurrentSlicerManager->GetSlicer(slicer)->GetCurrentPosition()[2];
+  mCurrentMousePositionInMM[0] = x;
+  mCurrentMousePositionInMM[1] = y;
+  mCurrentMousePositionInMM[2] = z;
+  // DDV(mCurrentMousePositionInMM, 3);
+
+  //  vtkImageData * image = mCurrentCCLImage->GetFirstVTKImageData();
+  vtkImageData * image = mCurrentMaskImage->GetFirstVTKImageData();
+  double Xover = (x - image->GetOrigin()[0]) / image->GetSpacing()[0];
+  double Yover = (y - image->GetOrigin()[1]) / image->GetSpacing()[1];
+  double Zover = (z - image->GetOrigin()[2]) / image->GetSpacing()[2];
+  int ix, iy, iz;
+  
+  // mCurrentMousePositionInPixel[0] = Xover;
+  // mCurrentMousePositionInPixel[1] = Yover;
+  // mCurrentMousePositionInPixel[2] = Zover;
+  // DDV(mCurrentMousePositionInPixel, 3);
+
+  if (Xover >= image->GetWholeExtent()[0] &&
+      Xover <= image->GetWholeExtent()[1] &&
+      Yover >= image->GetWholeExtent()[2] &&
+      Yover <= image->GetWholeExtent()[3] &&
+      Zover >= image->GetWholeExtent()[4] &&
+      Zover <= image->GetWholeExtent()[5]) {
+    if (mCurrentState == State_Default) { // inside the mask
+      mCurrentLabelUnderMousePointer = 1;
+      return; 
+    }
+    else { // inside the label image
+      vtkImageData * image = mCurrentCCLImage->GetFirstVTKImageData();
+      mCurrentLabelUnderMousePointer = 
+        mCurrentSlicerManager->GetSlicer(0)->GetScalarComponentAsDouble(image, Xover, Yover, Zover, ix, iy, iz, 0);
+      return;
+    }
+  }
+  else {
+    // DD("out of mask");
+    mCurrentLabelUnderMousePointer = 0; // BG is always 0 in CCL
+  }
+}
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+void vvToolSegmentation::RemoveLabel() {
+  DD("RemoveLabel");
+  if (mCurrentLabelUnderMousePointer == 0) return;
+  // First actor=0 and is label 1. Label 0 is not an actor, it is BG
+  int actorNumber = mCurrentLabelUnderMousePointer-1; 
+  // Set actor invisible
+  mCurrentCCLActors[actorNumber]->SetVisible(false);
+  mCurrentSlicerManager->Render();
+  // Set image label
+  vtkImageData * image = mCurrentCCLImage->GetFirstVTKImageData();
+  int * pPix = (int*)image->GetScalarPointer();
+  int n = 0;
+  for(uint i=0; i<image->GetNumberOfPoints(); i++) {
+    if (pPix[i] == mCurrentLabelUnderMousePointer) pPix[i] = 0;
+    if (pPix[i] != 0) n++; // count the number of pixels in the foreground
+  }
+  // Update mask size
+  mCurrentMaskSizeInPixels = n;
+  mCurrentMaskSizeInCC = mCurrentMaskImage->GetSpacing()[0] * mCurrentMaskImage->GetSpacing()[1] * mCurrentMaskImage->GetSpacing()[2] * n / (10*10*10);
+  UpdateMaskSizeLabels();
 }
 //------------------------------------------------------------------------------
index 7b8bb8c49ae297d73cb659d780f8079ffc4bfc45..5cd6e404b81d952b4237bd280b9378459a5b9521 100644 (file)
@@ -25,6 +25,8 @@
 #include "vvROIActor.h"
 #include "ui_vvToolSegmentation.h"
 
+#include "vtkLookupTable.h"
+
 //------------------------------------------------------------------------------
 class vvToolSegmentation:
   public vvToolWidgetBase,
@@ -40,23 +42,50 @@ class vvToolSegmentation:
   static void Initialize();
   virtual void InputIsSelected(vvSlicerManager * m);
   void OpenBinaryImage();
+  void RegionGrowing();
   void Erode();
   void Dilate();
-  void UpdateAndRender();
+  void Labelize();
+  void Merge();
+  void RemoveLabel();
+  void UpdateAndRenderNewMask();
 
   //-----------------------------------------------------
   public slots:
   virtual void apply();
-  virtual void keyPressEvent(QKeyEvent * event);
+  void KeyPressed(std::string KeyPress);
   virtual bool close();
-  // virtual void reject();
+  virtual void MousePositionChanged(int slicer);
 
  protected:
-  // virtual void closeEvent(QCloseEvent *event);
   Ui::vvToolSegmentation ui;
   QSharedPointer<vvROIActor> mRefMaskActor;
-  vvImage::Pointer mMaskImage;
+  QSharedPointer<vvROIActor> mCurrentMaskActor;
+  std::vector<QSharedPointer<vvROIActor> > mCurrentCCLActors;
+  vvImage::Pointer mRefMaskImage;
+  vvImage::Pointer mCurrentMaskImage;
+  vvImage::Pointer mCurrentCCLImage;
   int mKernelValue;
+  vtkSmartPointer<vtkLookupTable> mDefaultLUTColor;
+  enum { State_Default, State_CCL};
+  int mCurrentState;
+
+  QSharedPointer<vvROIActor> CreateMaskActor(vvImage::Pointer image, int i, int colorID, bool BGMode=false);
+  
+  double mCurrentLabelUnderMousePointer;
+  std::vector<double> mCurrentMousePositionInMM;
+  //std::vector<double> mCurrentMousePositionInPixel;
+  double GetBackgroundValue() { return 0; }
+  double GetForegroundValue() { return 1; }
+  long ComputeNumberOfPixels(vvImage::Pointer image, double value);
+
+  // Compute and store sizes of mask Foreground
+  void   UpdateMaskSize(vvImage::Pointer image, long & pix, double & cc);
+  void   UpdateMaskSizeLabels();
+  long   mRefMaskSizeInPixels;
+  double mRefMaskSizeInCC;
+  long   mCurrentMaskSizeInPixels;
+  double mCurrentMaskSizeInCC;
 
 }; // end class vvToolSegmentation
 //------------------------------------------------------------------------------