Orfeo Toolbox  3.16
itkImageFileWriter.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkImageFileWriter.txx,v $
5  Language: C++
6  Date: $Date: 2009-08-24 18:08:39 $
7  Version: $Revision: 1.62 $
8 
9  Copyright (c) Insight Software Consortium. All rights reserved.
10  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
11 
12  This software is distributed WITHOUT ANY WARRANTY; without even
13  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14  PURPOSE. See the above copyright notices for more information.
15 
16 =========================================================================*/
17 #ifndef __itkImageFileWriter_txx
18 #define __itkImageFileWriter_txx
19 
20 #include "itkImageFileWriter.h"
21 #include "itkDataObject.h"
22 #include "itkObjectFactoryBase.h"
23 #include "itkImageIOFactory.h"
24 #include "itkCommand.h"
25 #include "vnl/vnl_vector.h"
26 #include "itkVectorImage.h"
28 #include "itkImageRegionIterator.h"
29 
30 namespace itk
31 {
32 
33 //---------------------------------------------------------
34 template <class TInputImage>
37  m_PasteIORegion(TInputImage::ImageDimension)
38 {
39  m_UseCompression = false;
40  m_UseInputMetaDataDictionary = true;
41  m_FactorySpecifiedImageIO = false;
42  m_UserSpecifiedIORegion = false;
43  m_UserSpecifiedImageIO = false;
44  m_NumberOfStreamDivisions = 1;
45 }
46 
47 //---------------------------------------------------------
48 template <class TInputImage>
51 {
52 }
53 
54 //---------------------------------------------------------
55 template <class TInputImage>
56 void
59 {
60  // ProcessObject is not const_correct so this cast is required here.
62  const_cast<TInputImage *>(input ) );
63 }
64 
65 
66 //---------------------------------------------------------
67 template <class TInputImage>
71 {
72  if (this->GetNumberOfInputs() < 1)
73  {
74  return 0;
75  }
76 
77  return static_cast<TInputImage*>
78  (this->ProcessObject::GetInput(0));
79 }
80 
81 //---------------------------------------------------------
82 template <class TInputImage>
85 ::GetInput(unsigned int idx)
86 {
87  return static_cast<TInputImage*> (this->ProcessObject::GetInput(idx));
88 }
89 
90 //---------------------------------------------------------
91 template <class TInputImage>
92 void
94 ::SetIORegion (const ImageIORegion& region)
95 {
96  itkDebugMacro("setting IORegion to " << region );
97  if ( m_PasteIORegion != region)
98  {
99  m_PasteIORegion = region;
100  this->Modified();
101  m_UserSpecifiedIORegion = true;
102  }
103 }
104 
105 //---------------------------------------------------------
106 template <class TInputImage>
107 void
110 {
111  const InputImageType * input = this->GetInput();
112 
113  itkDebugMacro( <<"Writing an image file" );
114 
115  // Make sure input is available
116  if ( input == 0 )
117  {
118  itkExceptionMacro(<< "No input to writer!");
119  }
120 
121  // Make sure that we can write the file given the name
122  //
123  if ( m_FileName == "" )
124  {
125  itkExceptionMacro(<<"No filename was specified");
126  }
127 
128  if ( m_ImageIO.IsNull() ) //try creating via factory
129  {
130  itkDebugMacro(<<"Attempting factory creation of ImageIO for file: "
131  << m_FileName);
132  m_ImageIO = ImageIOFactory::CreateImageIO( m_FileName.c_str(),
134  m_FactorySpecifiedImageIO = true;
135  }
136  else
137  {
138  if( m_FactorySpecifiedImageIO && !m_ImageIO->CanWriteFile( m_FileName.c_str() ) )
139  {
140  itkDebugMacro(<<"ImageIO exists but doesn't know how to write file:"
141  << m_FileName );
142  itkDebugMacro(<<"Attempting creation of ImageIO with a factory for file:"
143  << m_FileName);
144  m_ImageIO = ImageIOFactory::CreateImageIO( m_FileName.c_str(),
146  m_FactorySpecifiedImageIO = true;
147  }
148  }
149 
150  if ( m_ImageIO.IsNull() )
151  {
152  ImageFileWriterException e(__FILE__, __LINE__);
153  OStringStream msg;
154  msg << " Could not create IO object for file "
155  << m_FileName.c_str() << std::endl;
156  msg << " Tried to create one of the following:" << std::endl;
157  {
158  std::list<LightObject::Pointer> allobjects =
159  ObjectFactoryBase::CreateAllInstance("itkImageIOBase");
160  for(std::list<LightObject::Pointer>::iterator i = allobjects.begin();
161  i != allobjects.end(); ++i)
162  {
163  ImageIOBase* io = dynamic_cast<ImageIOBase*>(i->GetPointer());
164  msg << " " << io->GetNameOfClass() << std::endl;
165  }
166  }
167  msg << " You probably failed to set a file suffix, or" << std::endl;
168  msg << " set the suffix to an unsupported type." << std::endl;
169  e.SetDescription(msg.str().c_str());
170  e.SetLocation(ITK_LOCATION);
171  throw e;
172  }
173 
174  // NOTE: this const_cast<> is due to the lack of const-correctness
175  // of the ProcessObject.
176  InputImageType * nonConstInput = const_cast<InputImageType *>(input);
177 
178  // Update the meta data
179  nonConstInput->UpdateOutputInformation();
180 
181  // Setup the ImageIO
182  //
183  m_ImageIO->SetNumberOfDimensions(TInputImage::ImageDimension);
184  InputImageRegionType largestRegion = input->GetLargestPossibleRegion();
185  const typename TInputImage::SpacingType& spacing = input->GetSpacing();
186  const typename TInputImage::DirectionType& direction = input->GetDirection();
187  // BUG 8436: Wrong origin when writing a file with non-zero index
188  // origin = input->GetOrigin();
189  const typename TInputImage::IndexType& startIndex = largestRegion.GetIndex();
190  typename TInputImage::PointType origin;
191  input->TransformIndexToPhysicalPoint(startIndex, origin);
192 
193 
194  for(unsigned int i=0; i<TInputImage::ImageDimension; i++)
195  {
196  m_ImageIO->SetDimensions(i,largestRegion.GetSize(i));
197  m_ImageIO->SetSpacing(i,spacing[i]);
198  m_ImageIO->SetOrigin(i,origin[i]);
199  vnl_vector< double > axisDirection(TInputImage::ImageDimension);
200  // Please note: direction cosines are stored as columns of the
201  // direction matrix
202  for(unsigned int j=0; j<TInputImage::ImageDimension; j++)
203  {
204  axisDirection[j] = direction[j][i];
205  }
206  m_ImageIO->SetDirection( i, axisDirection );
207  }
208 
209  // configure compression
210  m_ImageIO->SetUseCompression(m_UseCompression);
211 
212  // configure meta dictionary
213  if( m_UseInputMetaDataDictionary )
214  {
215  m_ImageIO->SetMetaDataDictionary(input->GetMetaDataDictionary());
216  }
217 
218  // Make sure that the image is the right type
219  // configure pixel type
220  if( strcmp( input->GetNameOfClass(), "VectorImage" ) == 0 )
221  {
222  typedef typename InputImageType::InternalPixelType VectorImageScalarType;
223  m_ImageIO->SetPixelTypeInfo( typeid(VectorImageScalarType) );
224 
225  typedef typename InputImageType::AccessorFunctorType AccessorFunctorType;
226  m_ImageIO->SetNumberOfComponents( AccessorFunctorType::GetVectorLength(input) );
227  }
228  else
229  {
230  // Set the pixel and component type; the number of components.
231  m_ImageIO->SetPixelTypeInfo(typeid(InputImagePixelType));
232  }
233 
234  // Setup the image IO for writing.
235  //
236  m_ImageIO->SetFileName(m_FileName.c_str());
237 
238  // Notify start event observers
239  this->InvokeEvent( StartEvent() );
240 
241  if (m_NumberOfStreamDivisions > 1 || m_UserSpecifiedIORegion)
242  {
243  m_ImageIO->SetUseStreamedWriting(true);
244  }
245 
246 
247 
248  ImageIORegion largestIORegion(TInputImage::ImageDimension);
250  Convert(largestRegion, largestIORegion, largestRegion.GetIndex());
251 
252  // this pasteIORegion is the region we are going to write
253  ImageIORegion pasteIORegion;
254  if ( m_UserSpecifiedIORegion )
255  {
256  pasteIORegion = m_PasteIORegion;
257  }
258  else
259  {
260  pasteIORegion = largestIORegion;
261  }
262 
263 
264  // Check whether the paste region is fully contained inside the
265  // largest region or not.
266  if( !largestIORegion.IsInside( pasteIORegion ) )
267  {
268  itkExceptionMacro(
269  << "Largest possible region does not fully contain requested paste IO region"
270  << "Paste IO region: " << pasteIORegion
271  << "Largest possible region: " << largestRegion);
272  }
273 
274  // Determin the actual number of divisions of the input. This is determined
275  // by what the ImageIO can do
276  unsigned int numDivisions;
277 
278  // this may fail and throw an exception if the configuration is not supported
279  numDivisions = m_ImageIO->GetActualNumberOfSplitsForWriting(m_NumberOfStreamDivisions,
280  pasteIORegion,
281  largestIORegion);
282 
283 
288  unsigned int piece;
289 
290  for (piece = 0;
291  piece < numDivisions && !this->GetAbortGenerateData();
292  piece++)
293  {
294 
295  // get the actual piece to write
296  ImageIORegion streamIORegion = m_ImageIO->GetSplitRegionForWriting(piece, numDivisions,
297  pasteIORegion, largestIORegion);
298 
299  // Check whether the paste region is fully contained inside the
300  // largest region or not.
301  if( !pasteIORegion.IsInside( streamIORegion ) )
302  {
303  itkExceptionMacro(
304  << "ImageIO returns streamable region that is not fully contain in paste IO region"
305  << "Paste IO region: " << pasteIORegion
306  << "Streamable region: " << streamIORegion);
307  }
308 
309 
310  InputImageRegionType streamRegion;
312  Convert(streamIORegion, streamRegion, largestRegion.GetIndex());
313 
314  // execute the the upstream pipeline with the requested
315  // region for streaming
316  nonConstInput->SetRequestedRegion(streamRegion);
317  nonConstInput->PropagateRequestedRegion();
318  nonConstInput->UpdateOutputData();
319 
320  // check to see if we tried to stream but got the largest possible region
321  if (piece == 0 && streamRegion != largestRegion)
322  {
323  InputImageRegionType bufferedRegion = input->GetBufferedRegion();
324  if (bufferedRegion == largestRegion)
325  {
326  // if so, then just write the entire image
327  itkDebugMacro("Requested stream region matches largest region input filter may not support streaming well.");
328  itkDebugMacro("Writer is not streaming now!");
329  numDivisions = 1;
330  streamRegion = largestRegion;
332  Convert(streamRegion, streamIORegion, largestRegion.GetIndex());
333  }
334  }
335 
336  m_ImageIO->SetIORegion(streamIORegion);
337 
338  // write the data
339  this->GenerateData();
340 
341  this->UpdateProgress((float) (piece+1) / numDivisions );
342  }
343 
344 
345  // Notify end event observers
346  this->InvokeEvent( EndEvent() );
347 
348  // Release upstream data if requested
349  this->ReleaseInputs();
350 
351 }
352 
353 
354 //---------------------------------------------------------
355 template <class TInputImage>
356 void
359 {
360  const InputImageType * input = this->GetInput();
361  InputImageRegionType largestRegion = input->GetLargestPossibleRegion();
362  InputImagePointer cacheImage;
363 
364  itkDebugMacro(<<"Writing file: " << m_FileName);
365 
366  // now extract the data as a raw buffer pointer
367  const void* dataPtr = (const void*) input->GetBufferPointer();
368 
369  // check that the image's buffered region is the same as
370  // ImageIO is expecting and we requested
371  InputImageRegionType ioRegion;
373  Convert(m_ImageIO->GetIORegion(), ioRegion, largestRegion.GetIndex());
374  InputImageRegionType bufferedRegion = input->GetBufferedRegion();
375 
376  // before this test, bad stuff would happend when they don't match
377  if (bufferedRegion != ioRegion)
378  {
379  if ( m_NumberOfStreamDivisions > 1 || m_UserSpecifiedIORegion)
380  {
381  itkDebugMacro("Requested stream region does not match generated output");
382  itkDebugMacro("input filter may not support streaming well");
383 
384  cacheImage = InputImageType::New();
385  cacheImage->CopyInformation(input);
386  cacheImage->SetBufferedRegion(ioRegion);
387  cacheImage->Allocate();
388 
389  typedef ImageRegionConstIterator<TInputImage> ConstIteratorType;
390  typedef ImageRegionIterator<TInputImage> IteratorType;
391 
392  ConstIteratorType in(input, ioRegion);
393  IteratorType out(cacheImage, ioRegion);
394 
395  // copy the data into a buffer to match the ioregion
396  for (in.GoToBegin(), out.GoToBegin(); !in.IsAtEnd(); ++in, ++out)
397  {
398  out.Set(in.Get());
399  }
400 
401  dataPtr = (const void*) cacheImage->GetBufferPointer();
402 
403  }
404  else
405  {
406  ImageFileWriterException e(__FILE__, __LINE__);
407  OStringStream msg;
408  msg << "Did not get requested region!" << std::endl;
409  msg << "Requested:" << std::endl;
410  msg << ioRegion;
411  msg << "Actual:" << std::endl;
412  msg << bufferedRegion;
413  e.SetDescription(msg.str().c_str());
414  e.SetLocation(ITK_LOCATION);
415  throw e;
416  }
417  }
418 
419 
420  m_ImageIO->Write(dataPtr);
421 }
422 
423 
424 //---------------------------------------------------------
425 template <class TInputImage>
426 void
428 ::PrintSelf(std::ostream& os, Indent indent) const
429 {
430  Superclass::PrintSelf(os,indent);
431 
432  os << indent << "File Name: "
433  << (m_FileName.data() ? m_FileName.data() : "(none)") << std::endl;
434 
435  os << indent << "Image IO: ";
436  if ( m_ImageIO.IsNull() )
437  {
438  os << "(none)\n";
439  }
440  else
441  {
442  os << m_ImageIO << "\n";
443  }
444 
445  os << indent << "IO Region: " << m_PasteIORegion << "\n";
446  os << indent << "Number of Stream Divisions: " << m_NumberOfStreamDivisions << "\n";
447 
448  if (m_UseCompression)
449  {
450  os << indent << "Compression: On\n";
451  }
452  else
453  {
454  os << indent << "Compression: Off\n";
455  }
456 
457  if (m_UseInputMetaDataDictionary)
458  {
459  os << indent << "UseInputMetaDataDictionary: On\n";
460  }
461  else
462  {
463  os << indent << "UseInputMetaDataDictionary: Off\n";
464  }
465 
466  if (m_FactorySpecifiedImageIO)
467  {
468  os << indent << "FactorySpecifiedmageIO: On\n";
469  }
470  else
471  {
472  os << indent << "FactorySpecifiedmageIO: Off\n";
473  }
474 
475 }
476 
477 } // end namespace itk
478 
479 #endif

Generated at Sat Feb 2 2013 23:42:44 for Orfeo Toolbox with doxygen 1.8.1.1