+++ /dev/null
-/*=========================================================================
- 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 */
-
+++ /dev/null
-/*=========================================================================
- 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 */
-
{
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);
}
#include <itkImageToImageFilter.h>
#include <itkLabelStatisticsImageFilter.h>
+#include <iomanip>
+
namespace clitk {
//--------------------------------------------------------------------
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;
}
//--------------------------------------------------------------------
// 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);
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))
#=========================================================
# 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)
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)
/*=========================================================================
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
+
+//--------------------------------------------------------------------
--- /dev/null
+#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"
+
--- /dev/null
+/*=========================================================================
+ 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
--- /dev/null
+/*=========================================================================
+ 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
--- /dev/null
+/*=========================================================================
+ 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
#ifndef clitkCropImageGenericFilter_cxx
#define clitkCropImageGenericFilter_cxx
-/* =================================================
- * @file clitkCropImageGenericFilter.cxx
- * @author
- * @date
- *
- * @brief
- *
- ===================================================*/
-
#include "clitkCropImageGenericFilter.h"
-
//-----------------------------------------------------------
// Constructor
//-----------------------------------------------------------
- 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"
clitk::ImageStatisticsGenericFilter::Pointer genericFilter=clitk::ImageStatisticsGenericFilter::New();
genericFilter->SetArgsInfo(args_info);
- genericFilter->Update();
+ CLITK_TRY_CATCH_EXIT(genericFilter->Update());
return EXIT_SUCCESS;
}// end main
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
#ifndef clitkImageStatisticsGenericFilter_cxx
#define clitkImageStatisticsGenericFilter_cxx
-/* =================================================
- * @file clitkImageStatisticsGenericFilter.cxx
- * @author
- * @date
- *
- * @brief
- *
- ===================================================*/
-
#include "clitkImageStatisticsGenericFilter.h"
-
namespace clitk
{
m_Verbose=false;
m_InputFileName="";
}
-
+ //-----------------------------------------------------------
+
//-----------------------------------------------------------
// Update
#ifndef clitkImageStatisticsGenericFilter_h
#define clitkImageStatisticsGenericFilter_h
-/* =================================================
- * @file clitkImageStatisticsGenericFilter.h
- * @author
- * @date
- *
- * @brief
- *
- ===================================================*/
-
-
// clitk include
#include "clitkIO.h"
#include "clitkCommon.h"
namespace clitk
{
-
class ITK_EXPORT ImageStatisticsGenericFilter : public itk::LightObject
{
public:
#include "itkNthElementImageAdaptor.h"
#include "itkJoinSeriesImageFilter.h"
-/* =================================================
- * @file clitkImageStatisticsGenericFilter.txx
- * @author
- * @date
- *
- * @brief
- *
- ===================================================*/
#include "clitkImageStatisticsGenericFilter.h"
-
+#include "clitkCropLikeImageFilter.h"
+#include "clitkResampleImageWithOptionsFilter.h"
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,
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, ®, 0);
+ }
+ else {
+ std::cerr << "Mask image has a different size/spacing than input. Abort" << std::endl;
+ exit(-1);
+ }
+ }
+
}
}
vvToolMIP
vvToolConvert ## with dummy vvToolConvert.ui
vvToolROIManager
+ vvToolSegmentation
## these ones are for tests (not working)
# vvToolFoo
<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/>
if (argc >1) {
for (int i = 1; i < argc; i++) {
std::string current = argv[i];
+ if (!current.compare(0,2,"-h")) {
+ current = "--help";
+ }
if (!current.compare(0,2,"--")) { //We are parsing an option
if (parse_mode == P_SEQUENCE) {//First finish the current sequence
window.LoadImages(sequence_filenames, vvImageReader::MERGEDWITHTIME);
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);
}
//----------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+void vvSlicerManager::EmitMousePositionUpdated(int slicer)
+{
+ emit MousePositionUpdatedSignal(slicer);
+}
+//----------------------------------------------------------------------------
+
+
+//----------------------------------------------------------------------------
+void vvSlicerManager::EmitKeyPressed(std::string KeyPress)
+{
+ emit KeyPressedSignal(KeyPress);
+}
+//----------------------------------------------------------------------------
+
+
//----------------------------------------------------------------------------
void vvSlicerManager::SetSliceOrientation(int slicer, int orientation)
{
switch (mSlicers[slicer]->GetSliceOrientation()) {
case vtkImageViewer2::SLICE_ORIENTATION_XY:
- if (mSlicers[slicer]->GetSlice() != (int)floor(z))
- mSlicers[slicer]->SetSlice((int)floor(z));
+ if (mSlicers[slicer]->GetSlice() != (int)lrint(z)) //FIXME
+ mSlicers[slicer]->SetSlice((int)lrint(z));
break;
case vtkImageViewer2::SLICE_ORIENTATION_XZ:
- if (mSlicers[slicer]->GetSlice() != (int)floor(y))
- mSlicers[slicer]->SetSlice((int)floor(y));
+ if (mSlicers[slicer]->GetSlice() != (int)lrint(y))
+ mSlicers[slicer]->SetSlice((int)lrint(y));
break;
case vtkImageViewer2::SLICE_ORIENTATION_YZ:
- if (mSlicers[slicer]->GetSlice() != (int)floor(x))
- mSlicers[slicer]->SetSlice((int)floor(x));
+ if (mSlicers[slicer]->GetSlice() != (int)lrint(x))
+ mSlicers[slicer]->SetSlice((int)lrint(x));
break;
}
mSlicers[slicer]->Render();
}
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;
}
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);
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);
this->SM->UpdateSliceRange(VisibleInWindow);
}
+ this->SM->EmitKeyPressed(KeyPress);
}
//All type of mouse events
return;
}
- //DD(event);
// Mouse release HERE
if (event == vtkCommand::EndPickEvent) {
// DD(VisibleInWindow);
zWorld = z;
break;
}
+
this->SM->GetSlicer(VisibleInWindow)->SetCurrentPosition(xWorld,yWorld,zWorld,
- this->SM->GetSlicer(VisibleInWindow)->GetTSlice());
+ this->SM->GetSlicer(VisibleInWindow)->GetTSlice());
+ // We propagate the mouse position
+ this->SM->EmitMousePositionUpdated(VisibleInWindow);
+
if (newLandmark) {
this->SM->AddLandmark(xWorld,yWorld,zWorld,
this->SM->GetSlicer(VisibleInWindow)->GetTSlice());
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();
}
//------------------------------------------------------------------------------
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();
- 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>
// 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.
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"
+
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
vvToolSegmentation::~vvToolSegmentation()
{
+ DD("destructor");
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
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;
// 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)));
}
//------------------------------------------------------------------------------
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();
}
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();
}
//------------------------------------------------------------------------------
-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();
}
//------------------------------------------------------------------------------
#include "vvROIActor.h"
#include "ui_vvToolSegmentation.h"
+#include "vtkLookupTable.h"
+
//------------------------------------------------------------------------------
class vvToolSegmentation:
public vvToolWidgetBase,
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
//------------------------------------------------------------------------------