ANIMA  4.0
animaConnectedComponents.cxx
Go to the documentation of this file.
1 #include <itkConnectedComponentImageFilter.h>
2 #include <itkRelabelComponentImageFilter.h>
3 #include <itkImageFileReader.h>
4 #include <itkImageFileWriter.h>
5 #include <itkImageRegionIterator.h>
6 
7 #include <tclap/CmdLine.h>
8 
10 
11 struct arguments
12 {
13  std::string input, output;
14  unsigned int pthread;
15  double min;
16  bool full;
17 };
18 
19 template <unsigned int Dimension>
20 void
22 {
23  typedef itk::Image <unsigned short,Dimension> ImageType;
24 
25  typedef itk::ConnectedComponentImageFilter <ImageType,ImageType> MainFilterType;
26  typedef itk::RelabelComponentImageFilter <ImageType,ImageType> RelabelComponentFilterType;
27 
28  typename MainFilterType::Pointer mainFilter = MainFilterType::New();
29  mainFilter->SetInput(anima::readImage<ImageType>(args.input));
30  mainFilter->SetFullyConnected(args.full);
31  if(args.pthread > 0)
32  mainFilter->SetNumberOfWorkUnits(args.pthread);
33  mainFilter->Update();
34 
35  // Compute Image Spacing, 4th dimension is not physical but temporal
36  typename ImageType::SpacingType spacing = mainFilter->GetInput(0)->GetSpacing();
37  typename ImageType::SpacingValueType spacingTot = spacing[0];
38  for (unsigned int i = 1;i < std::min(Dimension,(unsigned int)3);++i)
39  spacingTot *= spacing[i];
40 
41 
42  // Compute minsize in voxels
43  double minSizeInVoxelD = args.min / spacingTot;
44  double minSizeInVoxelD_floor = floor(minSizeInVoxelD);
45  unsigned int minSizeInVoxel = static_cast<unsigned int>(minSizeInVoxelD_floor);
46  minSizeInVoxel++; // to have strickly superior sizes
47  double diff = minSizeInVoxelD-minSizeInVoxelD_floor;
48 
49  typename RelabelComponentFilterType::Pointer relabelFilter = RelabelComponentFilterType::New();
50  relabelFilter->SetInput( mainFilter->GetOutput() );
51  relabelFilter->SetMinimumObjectSize(minSizeInVoxel);
52  if(args.pthread > 0)
53  relabelFilter->SetNumberOfWorkUnits(args.pthread);
54  relabelFilter->Update();
55 
56  std::cout << "Original number of objects: " << relabelFilter->GetOriginalNumberOfObjects() <<std::endl;
57  std::cout << "Total image spacing: " << spacingTot << std::endl;
58  std::cout << "Connected components minimum size: " << args.min << " mm3 --> " << "process on " << minSizeInVoxel-1 << " voxel(s)" << std::endl;
59 
60  if (diff > 1.0e-6)
61  {
62  std::cout << "-- Warning: operation is not complete, " << (double)(minSizeInVoxel-1)*spacingTot << " mm3 is/are removed (" << minSizeInVoxel-1 << " voxel(s)) "
63  << "instead of " << args.min << " mm3 (" << minSizeInVoxelD << " voxel(s))" << std::endl;
64  }
65 
66  std::cout << "Number of objects after cleaning too small ones: " << relabelFilter->GetNumberOfObjects() << std::endl;
67  std::cout << std::endl;
68 
69  anima::writeImage<ImageType>(args.output, relabelFilter->GetOutput());
70 }
71 
72 void
73 retrieveDimension(const arguments &args, itk::ImageIOBase::Pointer imageIO)
74 {
75  unsigned int nbDim = imageIO->GetNumberOfDimensions();
76 
77  switch(nbDim)
78  {
79  case 2:
80  connectedComponent<2>(args);
81  break;
82  case 3:
83  connectedComponent<3>(args);
84  break;
85  case 4:
86  connectedComponent<4>(args);
87  break;
88  default:
89  itk::ExceptionObject excp(__FILE__, __LINE__, "Number of dimension not supported.", ITK_LOCATION);
90  throw excp;
91  }
92 }
93 
94 int main(int argc, char **argv)
95 {
96  TCLAP::CmdLine cmd("INRIA / IRISA - VisAGeS/Empenn Team", ' ',ANIMA_VERSION);
97 
98  TCLAP::ValueArg<std::string> inArg("i","inputfile","Input image",true,"","input image",cmd);
99  TCLAP::ValueArg<std::string> outArg("o","outputfile","Output image",true,"","output image",cmd);
100  TCLAP::ValueArg<unsigned int> pArg("p","Thread","Number of thread",false,0,"Number of thread to use",cmd);
101 
102  TCLAP::ValueArg<double> minSizeArg("m","minsize","minimal component size in mm3",false,0,"minimal component size",cmd);
103  TCLAP::SwitchArg fullConnectArg("F","full-connect","Use 26-connectivity instead of 6-connectivity",cmd,false);
104 
105  try
106  {
107  cmd.parse(argc,argv);
108  }
109  catch (TCLAP::ArgException& e)
110  {
111  std::cerr << "Error: " << e.error() << "for argument " << e.argId() << std::endl;
112  return EXIT_FAILURE;
113  }
114 
115  // Find out the type of the image in file
116  itk::ImageIOBase::Pointer imageIO = itk::ImageIOFactory::CreateImageIO(inArg.getValue().c_str(),
117  itk::ImageIOFactory::ReadMode);
118  if( !imageIO )
119  {
120  std::cerr << "Itk could not find suitable IO factory for the input" << std::endl;
121  return EXIT_FAILURE;
122  }
123 
124  // Now that we found the appropriate ImageIO class, ask it to read the meta data from the image file.
125  imageIO->SetFileName(inArg.getValue());
126  imageIO->ReadImageInformation();
127 
128  std::cout<<"\npreparing filter...\n";
129 
130  arguments args;
131 
132  args.input = inArg.getValue();
133  args.output = outArg.getValue();
134  args.min = minSizeArg.getValue();
135  args.full= fullConnectArg.getValue();
136  args.pthread = pArg.getValue();
137 
138  try
139  {
140  retrieveDimension(args, imageIO);
141  }
142  catch (itk::ExceptionObject & err)
143  {
144  std::cerr << "Itk cannot concatenate, be sure to use valid arguments..." << std::endl;
145  std::cerr << err << std::endl;
146  return EXIT_FAILURE;
147  }
148 }
std::string output
void retrieveDimension(const arguments &args, itk::ImageIOBase::Pointer imageIO)
itk::ImageIOBase::Pointer imageIO
int main(int argc, char **argv)
void connectedComponent(const arguments &args)
std::string input