ANIMA  4.0
animaMorphologicalOperations.cxx
Go to the documentation of this file.
1 #include <itkGrayscaleErodeImageFilter.h>
2 #include <itkGrayscaleDilateImageFilter.h>
3 #include <itkGrayscaleMorphologicalClosingImageFilter.h>
4 #include <itkGrayscaleMorphologicalOpeningImageFilter.h>
5 #include <itkBinaryBallStructuringElement.h>
7 #include <tclap/CmdLine.h>
8 
9 int main(int argc, char **argv)
10 {
11  TCLAP::CmdLine cmd("INRIA / IRISA - VisAGeS/Empenn Team", ' ',ANIMA_VERSION);
12 
13  TCLAP::ValueArg<std::string> inArg("i","inputfile","Input image",true,"","input image",cmd);
14  TCLAP::ValueArg<std::string> outArg("o","outputfile","Output image",true,"","output image",cmd);
15  TCLAP::ValueArg<unsigned int> nbpArg("p","nbcores","Number of cores to run on (default: all cores)",false,itk::MultiThreaderBase::GetGlobalDefaultNumberOfThreads(),"Number of cores",cmd);
16 
17  TCLAP::ValueArg<std::string> actArg("a","action","Action to perform ([clos], open, dil, er)",false,"clos","Action to perform",cmd);
18  TCLAP::ValueArg<double> radiusArg("r","radius","Radius of morphological operation (in mm by default, see -R)",false,1,"morphological radius",cmd);
19  TCLAP::SwitchArg radiusVoxelArg("R","r-in-voxel","Use the radius in voxels",cmd);
20 
21  try
22  {
23  cmd.parse(argc,argv);
24  }
25  catch (TCLAP::ArgException& e)
26  {
27  std::cerr << "Error: " << e.error() << "for argument " << e.argId() << std::endl;
28  return EXIT_FAILURE;
29  }
30 
31  typedef itk::Image <double,3> ImageType;
32 
33  typedef itk::BinaryBallStructuringElement <unsigned short, 3> BallElementType;
34  typedef itk::GrayscaleErodeImageFilter <ImageType,ImageType,BallElementType> ErodeFilterType;
35  typedef itk::GrayscaleDilateImageFilter <ImageType,ImageType,BallElementType> DilateFilterType;
36  typedef itk::GrayscaleMorphologicalClosingImageFilter <ImageType,ImageType,BallElementType> ClosingFilterType;
37  typedef itk::GrayscaleMorphologicalOpeningImageFilter <ImageType, ImageType, BallElementType> OpeningFilterType;
38 
39  ImageType::Pointer inputImage = anima::readImage <ImageType> (inArg.getValue());
40 
41  ImageType::Pointer resPointer;
42  BallElementType tmpBall;
43 
44  unsigned int radiusInVoxel0 = radiusArg.getValue();
45  unsigned int radiusInVoxel1 = radiusArg.getValue();
46  unsigned int radiusInVoxel2 = radiusArg.getValue();
47 
48  if (!radiusVoxelArg.isSet())
49  {
50  // Compute Image Spacing
51  ImageType::SpacingType spacing = inputImage->GetSpacing();
52  ImageType::SpacingValueType spacing0 = spacing[0];
53  ImageType::SpacingValueType spacing1 = spacing[1];
54  ImageType::SpacingValueType spacing2 = spacing[2];
55 
56  double radiusInVoxelD0 = radiusArg.getValue() / spacing0;
57  double radiusInVoxelD1 = radiusArg.getValue() / spacing1;
58  double radiusInVoxelD2 = radiusArg.getValue() / spacing2;
59 
60  double radiusInVoxelD0_round = std::round(radiusInVoxelD0);
61  double radiusInVoxelD1_round = std::round(radiusInVoxelD1);
62  double radiusInVoxelD2_round = std::round(radiusInVoxelD2);
63 
64  radiusInVoxel0 = static_cast<unsigned int>(radiusInVoxelD0_round);
65  radiusInVoxel1 = static_cast<unsigned int>(radiusInVoxelD1_round);
66  radiusInVoxel2 = static_cast<unsigned int>(radiusInVoxelD2_round);
67 
68  std::cout << "Image spacing: " << spacing0 << "*" << spacing1 << "*" << spacing2 << std::endl;
69  std::cout << "Radius: " << radiusArg.getValue() << " mm3 --> " << "process on " << radiusInVoxel0 << "*" << radiusInVoxel1 << "*" << radiusInVoxel2 << " voxel(s)" << std::endl;
70 
71  double diff0 = std::abs(radiusInVoxelD0-radiusInVoxelD0_round);
72  double diff1 = std::abs(radiusInVoxelD1-radiusInVoxelD1_round);
73  double diff2 = std::abs(radiusInVoxelD2-radiusInVoxelD2_round);
74 
75  if (diff0 > 1.0e-6)
76  {
77  std::cout << "-- Warning: operation is not complete, on dimension 0 process is performed on " << (double)(radiusInVoxel0)*spacing0 << " mm3 (" << radiusInVoxel0 << " voxel(s)) "
78  << "instead of " << radiusArg.getValue() << " mm3 (" << radiusInVoxelD0 << " voxel(s))" << std::endl;
79  }
80 
81  if (diff1 > 1.0e-6)
82  {
83  std::cout << "-- Warning: operation is not complete, on dimension 1 process is performed on " << (double)(radiusInVoxel1)*spacing1 << " mm3 (" << radiusInVoxel1 << " voxel(s)) "
84  << "instead of " << radiusArg.getValue() << " mm3 (" << radiusInVoxelD1 << " voxel(s))" << std::endl;
85  }
86 
87  if (diff2 > 1.0e-6)
88  {
89  std::cout << "-- Warning: operation is not complete, on dimension 2 process is performed on " << (double)(radiusInVoxel2)*spacing2 << " mm3 (" << radiusInVoxel2 << " voxel(s)) "
90  << "instead of " << radiusArg.getValue() << " mm3 (" << radiusInVoxelD2 << " voxel(s))" << std::endl;
91  }
92  }
93 
94  BallElementType::SizeType ballSize;
95  ballSize[0] = radiusInVoxel0;
96  ballSize[1] = radiusInVoxel1;
97  ballSize[2] = radiusInVoxel2;
98  tmpBall.SetRadius(ballSize);
99  tmpBall.CreateStructuringElement();
100 
101  if (actArg.getValue() == "er")
102  {
103  std::cout << "Performing erosion with radius " << radiusArg.getValue() << "..." << std::endl;
104 
105  ErodeFilterType::Pointer mainFilter = ErodeFilterType::New();
106  mainFilter->SetInput(inputImage);
107  mainFilter->SetNumberOfWorkUnits(nbpArg.getValue());
108  mainFilter->SetKernel(tmpBall);
109 
110  mainFilter->Update();
111 
112  resPointer = mainFilter->GetOutput();
113  }
114  else if (actArg.getValue() == "dil")
115  {
116  std::cout << "Performing dilation with radius " << radiusArg.getValue() << "..." << std::endl;
117 
118  DilateFilterType::Pointer mainFilter = DilateFilterType::New();
119  mainFilter->SetInput(inputImage);
120  mainFilter->SetNumberOfWorkUnits(nbpArg.getValue());
121  mainFilter->SetKernel(tmpBall);
122 
123  mainFilter->Update();
124 
125  resPointer = mainFilter->GetOutput();
126  }
127  else if (actArg.getValue() == "open")
128  {
129  std::cout << "Performing opening with radius " << radiusArg.getValue() << "..." << std::endl;
130 
131  OpeningFilterType::Pointer mainFilter = OpeningFilterType::New();
132  mainFilter->SetInput(inputImage);
133  mainFilter->SetNumberOfWorkUnits(nbpArg.getValue());
134  mainFilter->SetKernel(tmpBall);
135 
136  mainFilter->Update();
137 
138  resPointer = mainFilter->GetOutput();
139  }
140  else
141  {
142  std::cout << "Performing closing with radius " << radiusArg.getValue() << "..." << std::endl;
143 
144  ClosingFilterType::Pointer mainFilter = ClosingFilterType::New();
145  mainFilter->SetInput(inputImage);
146  mainFilter->SetNumberOfWorkUnits(nbpArg.getValue());
147  mainFilter->SetKernel(tmpBall);
148 
149  mainFilter->Update();
150 
151  resPointer = mainFilter->GetOutput();
152  }
153 
154  anima::writeImage <ImageType> (outArg.getValue(),resPointer);
155 
156  return EXIT_SUCCESS;
157 }
int main(int argc, char **argv)