ANIMA  4.0
animaConcatenateImages.cxx
Go to the documentation of this file.
1 #include <tclap/CmdLine.h>
2 
3 #include <itkImage.h>
4 #include <itkCommand.h>
5 #include <itkExtractImageFilter.h>
6 
8 
9 struct arguments
10 {
11  std::vector<std::string> inputs;
12  std::string base, output;
13  double origin, spacing;
14  unsigned int nbComponents;
15 };
16 
17 template <class InputImageType, unsigned int InputDim, class OutputImageType >
18 void
19 concatenate(const arguments &args)
20 {
21  unsigned int input = 0;
22 
23  typename OutputImageType::Pointer baseImg;
24  if(args.base == "") // create args fake base from the first input.
25  {
26  std::cout << "No base given, direction of the created one will be guessed....\n" << std::endl;
27 
28  typename InputImageType::Pointer fimage = anima::readImage<InputImageType>(args.inputs[input]);
29  ++input;
30 
31  typename OutputImageType::RegionType finalRegion;
32  typename OutputImageType::SizeType finalSize;
33  typename OutputImageType::IndexType finalIndex;
34  typename OutputImageType::PointType finalOrigin;
35  typename OutputImageType::SpacingType finalSpacing;
36  typename OutputImageType::DirectionType finalDirection;
37 
38  for (unsigned int d = 0; d < InputDim; ++d)
39  {
40 
41  finalIndex[d] = fimage->GetLargestPossibleRegion().GetIndex()[d];
42  finalSize[d] = fimage->GetLargestPossibleRegion().GetSize()[d];
43  finalOrigin[d] = fimage->GetOrigin()[d];
44  finalSpacing[d] = fimage->GetSpacing()[d];
45  for(unsigned int i = 0; i < InputDim; ++i)
46  finalDirection[d][i] = fimage->GetDirection()[d][i];
47  }
48  finalIndex[InputDim] = 0;
49  finalSize[InputDim] = 1;
50  finalOrigin[InputDim] = args.origin;
51  finalSpacing[InputDim] = args.spacing;
52 
53  for(unsigned int i = 0; i < InputDim; ++i)
54  {
55  finalDirection[InputDim][i] = 0;
56  finalDirection[i][InputDim] = 0;
57  }
58  finalDirection[InputDim][InputDim] = 1;
59 
60  finalRegion.SetIndex(finalIndex);
61  finalRegion.SetSize(finalSize);
62 
63  baseImg = OutputImageType::New();
64  baseImg->Initialize();
65  baseImg->SetRegions(finalRegion);
66  baseImg->SetOrigin(finalOrigin);
67  baseImg->SetSpacing(finalSpacing);
68  baseImg->SetDirection(finalDirection);
69  baseImg->SetNumberOfComponentsPerPixel(args.nbComponents);
70  baseImg->Allocate();
71 
72  typedef itk::ImageRegionIterator <OutputImageType> FillIteratorType;
73  FillIteratorType fillItr(baseImg, baseImg->GetLargestPossibleRegion());
74  typedef itk::ImageRegionConstIterator<InputImageType> SourceIteratorType;
75  SourceIteratorType srcItr(fimage, fimage->GetLargestPossibleRegion());
76  while(!srcItr.IsAtEnd())
77  {
78  fillItr.Set(srcItr.Get());
79  ++fillItr; ++srcItr;
80  }
81 
82  std::cout << "input " << input << " / " << args.inputs.size() << " concatenated..." << std::endl;
83  }
84  else // use given basis.
85  baseImg = anima::readImage<OutputImageType>(args.base);
86 
87  // allocate output
88  typename OutputImageType::Pointer outputImg;
89  typename OutputImageType::RegionType finalRegion;
90  typename OutputImageType::SizeType finalSize;
91  typename OutputImageType::IndexType finalIndex;
92  typename OutputImageType::PointType finalOrigin;
93  typename OutputImageType::SpacingType finalSpacing;
94  typename OutputImageType::DirectionType finalDirection;
95 
96  for (unsigned int d = 0; d < InputDim; ++d)
97  {
98  finalIndex[d] = baseImg->GetLargestPossibleRegion().GetIndex()[d];
99  finalSize[d] = baseImg->GetLargestPossibleRegion().GetSize()[d];
100  finalOrigin[d] = baseImg->GetOrigin()[d];
101  finalSpacing[d] = baseImg->GetSpacing()[d];
102 
103  for(unsigned int i = 0;i < InputDim;++i)
104  finalDirection[d][i] = baseImg->GetDirection()[d][i];
105  }
106 
107  for(unsigned int i = 0;i < InputDim + 1;++i)
108  {
109  finalDirection[InputDim][i] = baseImg->GetDirection()[InputDim][i];
110  finalDirection[i][InputDim] = baseImg->GetDirection()[i][InputDim];
111  }
112 
113  finalIndex[InputDim] = baseImg->GetLargestPossibleRegion().GetIndex()[InputDim];
114  finalSize[InputDim] = baseImg->GetLargestPossibleRegion().GetSize()[InputDim] + args.inputs.size() - input;
115  finalOrigin[InputDim] = baseImg->GetOrigin()[InputDim];
116  finalSpacing[InputDim] = baseImg->GetSpacing()[InputDim];
117 
118  finalRegion.SetIndex(finalIndex);
119  finalRegion.SetSize(finalSize);
120 
121  outputImg = OutputImageType::New();
122  outputImg->Initialize();
123  outputImg->SetRegions(finalRegion);
124  outputImg->SetOrigin(finalOrigin);
125  outputImg->SetSpacing(finalSpacing);
126  outputImg->SetDirection(finalDirection);
127  outputImg->SetNumberOfComponentsPerPixel(args.nbComponents);
128  outputImg->Allocate();
129 
130  // fill with the base:
131  typedef itk::ImageRegionIterator <OutputImageType> FillIteratorType;
132  FillIteratorType fillItr(outputImg, outputImg->GetLargestPossibleRegion());
133  typedef itk::ImageRegionConstIterator<OutputImageType> BaseIteratorType;
134  BaseIteratorType baseItr(baseImg, baseImg->GetLargestPossibleRegion());
135  while(!baseItr.IsAtEnd())
136  {
137  fillItr.Set(baseItr.Get());
138  ++fillItr; ++baseItr;
139  }
140 
141  //fill with the inputs:
142  for(unsigned int i = input; i < args.inputs.size();++i)
143  {
144  typename InputImageType::Pointer inputImg = anima::readImage<InputImageType>(args.inputs[i]);
145 
146  typedef itk::ImageRegionConstIterator<InputImageType> InputIteratorType;
147  InputIteratorType inputItr(inputImg, inputImg->GetLargestPossibleRegion());
148  while(!inputItr.IsAtEnd())
149  {
150  fillItr.Set(inputItr.Get());
151  ++fillItr; ++inputItr;
152  }
153 
154  std::cout << "input " << i+1 << " / " << args.inputs.size() << " concatenated..." << std::endl;
155  }
156 
157  // write res
158  anima::writeImage<OutputImageType>(args.output, outputImg);
159 }
160 
161 template <class ComponentType, unsigned int InputDim>
162 void
163 retrieveNbComponent(arguments &args, itk::ImageIOBase::Pointer imageIO)
164 {
165  args.nbComponents = imageIO->GetNumberOfComponents();
166  switch(args.nbComponents)
167  {
168  case 1:
169  typedef itk::Image<ComponentType, InputDim> InputImageType;
170  typedef itk::Image<ComponentType, InputDim + 1> OutputImageType;
171  concatenate <InputImageType, InputDim, OutputImageType >(args);
172  break;
173  case 3:
174  case 6:
175  typedef itk::VectorImage<ComponentType, InputDim> InputVectorImageType;
176  typedef itk::VectorImage<ComponentType, InputDim + 1> OutputVectorImageType;
177  concatenate < InputVectorImageType, InputDim, OutputVectorImageType >(args);
178  break;
179  default:
180  itk::ExceptionObject excp(__FILE__, __LINE__, "Number of component not supported.", ITK_LOCATION);
181  throw excp;
182  }
183 }
184 
185 template <class ComponentType >
186 void
187 retrieveNbDimensions(arguments &args, itk::ImageIOBase::Pointer imageIO)
188 {
189 
190  unsigned int nbDim = imageIO->GetNumberOfDimensions();
191 
192  switch(nbDim)
193  {
194  case 2:
195  retrieveNbComponent<ComponentType, 2>(args, imageIO);
196  break;
197  case 3:
198  retrieveNbComponent<ComponentType, 3>(args, imageIO);
199  break;
200  default:
201  itk::ExceptionObject excp(__FILE__, __LINE__, "Number of dimension not supported.", ITK_LOCATION);
202  throw excp;
203  }
204 }
205 
206 void
207 retrieveComponentType(arguments &args, itk::ImageIOBase::Pointer imageIO)
208 {
209  switch (imageIO->GetComponentType())
210  {
211  case itk::ImageIOBase::UCHAR:
212  case itk::ImageIOBase::USHORT:
213  case itk::ImageIOBase::UINT:
214  case itk::ImageIOBase::ULONG:
215  retrieveNbDimensions<unsigned int>(args, imageIO);
216  break;
217  case itk::ImageIOBase::CHAR:
218  case itk::ImageIOBase::SHORT:
219  case itk::ImageIOBase::INT:
220  case itk::ImageIOBase::LONG:
221  retrieveNbDimensions<int>(args, imageIO);
222  break;
223  case itk::ImageIOBase::FLOAT:
224  retrieveNbDimensions<double>(args, imageIO);
225  break;
226  case itk::ImageIOBase::DOUBLE:
227  retrieveNbDimensions<double>(args, imageIO);
228  break;
229  default:
230  itk::ExceptionObject excp(__FILE__, __LINE__, "Component type not supported.", ITK_LOCATION);
231  throw excp;
232  }
233 }
234 
235 
236 int main(int ac, const char** av)
237 {
238 
239  TCLAP::CmdLine cmd("Concatenate args serie of image between them.\nYou can give several -i input to concatenate.\n\
240 A -b base image is facultative, if it is given, all the inputs will be add at the end of the last dim of this base.\n\
241 if args base is given the geometry of the base is used otherwise it use the geometry of the first given input.\n\
242 with the origin -O(def = 0) and spacing -s(def = 1) passed as arguments.\
243 It's your responsability to give args set of well formed input.\n\n\
244 Example: the arguments -b 4x4x4x1 and -i 4x4x4 -i 4x4x4 will result on an outpu 4x4x4x3.\n\
245 INRIA / IRISA - VisAGeS/Empenn Team",
246  ' ',ANIMA_VERSION);
247 
248  TCLAP::ValueArg<std::string> baseArg("b",
249  "base",
250  "Inputs will be concatenate with this base image",
251  false,
252  "",
253  "Base image.",
254  cmd);
255 
256  TCLAP::MultiArg<std::string> inputArg("i",
257  "input",
258  "Input images to concatenate",
259  true,
260  "Inputs",
261  cmd);
262 
263  TCLAP::ValueArg<std::string> outputArg("o",
264  "output",
265  "Output image",
266  true,
267  "",
268  "Output",
269  cmd);
270  TCLAP::ValueArg<double> originArg("O",
271  "origin",
272  "Origin of the last dimension of the concatenated image. ignore if args base has been given",
273  false,
274  0,
275  "Origin",
276  cmd);
277  TCLAP::ValueArg<double> spacingArg("s",
278  "spacing",
279  "Spacing of the last dimension of the concatenated image. ignore if args base has been given",
280  false,
281  1,
282  "Spacing",
283  cmd);
284 
285  try
286  {
287  cmd.parse(ac,av);
288  }
289  catch (TCLAP::ArgException& e)
290  {
291  std::cerr << "Error: " << e.error() << "for argument " << e.argId() << std::endl;
292  return EXIT_FAILURE;
293  }
294 
295  arguments args;
296  args.inputs = inputArg.getValue();
297 
298  // Find out the type of the image in file
299  itk::ImageIOBase::Pointer imageIO = itk::ImageIOFactory::CreateImageIO(args.inputs[0].c_str(),
300  itk::ImageIOFactory::ReadMode);
301 
302  if( !imageIO )
303  {
304  std::ifstream fileIn(args.inputs[0].c_str());
305  std::vector <std::string> listInputNames;
306 
307  if (!fileIn.is_open())
308  {
309  std::cerr << "Unable to read file: " << args.inputs[0] << std::endl;
310  return EXIT_FAILURE;
311  }
312 
313  while (!fileIn.eof())
314  {
315  char tmpStr[2048];
316  fileIn.getline(tmpStr,2048);
317 
318  if (strcmp(tmpStr,"") == 0)
319  continue;
320 
321  listInputNames.push_back(tmpStr);
322  }
323 
324  fileIn.close();
325 
326  if (listInputNames.size() > 0)
327  imageIO = itk::ImageIOFactory::CreateImageIO(listInputNames[0].c_str(),itk::ImageIOFactory::ReadMode);
328 
329  if( !imageIO )
330  {
331  std::cerr << "Itk could not find suitable IO factory for the input" << std::endl;
332  return EXIT_FAILURE;
333  }
334 
335  args.inputs = listInputNames;
336  }
337 
338  // Now that we found the appropriate ImageIO class, ask it to read the meta data from the image file.
339  imageIO->SetFileName(args.inputs[0]);
340  imageIO->ReadImageInformation();
341 
342  std::cout<<"\npreparing filter...\n";
343 
344  args.output = outputArg.getValue();
345  args.base = baseArg.getValue();
346  args.origin = originArg.getValue();
347  args.spacing = spacingArg.getValue();
348 
349  try
350  {
351  retrieveComponentType(args, imageIO);
352  }
353  catch ( itk::ExceptionObject & err )
354  {
355  std::cerr << "Itk cannot concatenate, be sure to use valid arguments..." << std::endl;
356  std::cerr << err << std::endl;
357  return EXIT_FAILURE;
358  }
359 
360  return EXIT_SUCCESS;
361 }
void concatenate(const arguments &args)
std::vector< std::string > inputs
std::string output
void retrieveNbDimensions(arguments &args, itk::ImageIOBase::Pointer imageIO)
void retrieveNbComponent(arguments &args, itk::ImageIOBase::Pointer imageIO)
itk::ImageIOBase::Pointer imageIO
unsigned int nbComponents
int main(int ac, const char **av)
void retrieveComponentType(arguments &args, itk::ImageIOBase::Pointer imageIO)
std::string input