Orfeo Toolbox  3.16
itkStreamingImageIOBase.cxx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkStreamingImageIOBase.cxx,v $
5  Language: C++
6  Date: $Date: 2010-06-14 13:26:11 $
7  Version: $Revision: 1.4 $
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 =========================================================================*/
18 
19 
20 #include <itksys/SystemTools.hxx>
21 
22 namespace itk
23 {
24 
26  : ImageIOBase()
27 {
28 }
29 
30 
31 void StreamingImageIOBase::PrintSelf(std::ostream& os, Indent indent) const
32 {
33  Superclass::PrintSelf(os, indent);
34 }
35 
36 
38 ::StreamReadBufferAsBinary(std::istream& file, void *_buffer)
39 {
40  itkDebugMacro( << "StreamingReadBufferAsBinary called" );
41 
42  char *buffer = static_cast<char*>(_buffer);
43  // Offset into file
44  std::streampos dataPos = this->GetDataPosition();
45 
46  std::streamsize sizeOfRegion = static_cast<std::streamsize>( m_IORegion.GetNumberOfPixels() )
47  *this->GetPixelSize();
48 
49 
50  // compute the number of continuous bytes to be read
51  std::streamsize sizeOfChunk = 1;
52  unsigned int movingDirection = 0;
53  do
54  {
55  sizeOfChunk *= m_IORegion.GetSize(movingDirection);
56  ++movingDirection;
57  }
58  while ( movingDirection < m_IORegion.GetImageDimension() &&
59  m_IORegion.GetSize(movingDirection-1) == this->GetDimensions(movingDirection-1) );
60  sizeOfChunk *= this->GetPixelSize();
61 
62  ImageIORegion::IndexType currentIndex = m_IORegion.GetIndex();
63  std::streamsize gcount = 0;
64  while ( m_IORegion.IsInside(currentIndex) )
65  {
66  // calculate the position to seek to in the file
67  std::streampos seekPos = 0;
68  size_t subDimensionQuantity = 1;
69  for ( unsigned int i = 0; i < m_IORegion.GetImageDimension(); ++i )
70  {
71  seekPos = seekPos + static_cast<std::streamoff> (subDimensionQuantity *
72  this->GetPixelSize() *
73  currentIndex[i]);
74  subDimensionQuantity *= this->GetDimensions(i);
75  }
76 
77 
78  itkDebugMacro(<< "Reading " << sizeOfChunk << " of " << sizeOfRegion << " bytes for " << m_FileName << " at " << dataPos+seekPos << " position in file");
79 
80  file.seekg( dataPos+seekPos, std::ios::beg );
81  this->ReadBufferAsBinary( file, buffer, sizeOfChunk );
82 
83  // increment the buffer pointer
84  buffer += sizeOfChunk;
85  gcount += file.gcount();
86 
87  if ( file.fail() )
88  {
89  itkExceptionMacro(<<"Fail reading");
90  }
91 
92  if (movingDirection == m_IORegion.GetImageDimension())
93  break;
94 
95  // increment index to next chunk
96  ++currentIndex[movingDirection];
97  for (unsigned int i = movingDirection; i < m_IORegion.GetImageDimension()-1; ++i)
98  {
99  // when reaching the end of the moving index dimension carry to
100  // higher dimensions
101  if (static_cast<ImageIORegion::SizeValueType>(currentIndex[i] - m_IORegion.GetIndex(i)) >= m_IORegion.GetSize(i) )
102  {
103  currentIndex[i] = m_IORegion.GetIndex(i);
104  ++currentIndex[i+1];
105  }
106  }
107  }
108 
109  if ( gcount != sizeOfRegion )
110  {
111  itkExceptionMacro("Data not read completely. Expected = " << sizeOfRegion << ", but only read " << gcount << " bytes.");
112  }
113 
114  return true;
115 }
116 
118 {
119 
120  // some systems have a limit of 2GB to be read at once
121  const SizeType maxChunk = 1024*1024*1024;
122 
123  std::streamsize bytesRemaining = static_cast<std::streamsize>( num );
124 
125  while (bytesRemaining)
126  {
127 
128  std::streamsize bytesToRead = bytesRemaining > maxChunk ? maxChunk : bytesRemaining;
129 
130  itkDebugMacro(<< "Reading " << bytesToRead << " of " << bytesRemaining << " bytes for " << m_FileName);
131 
132  is.read( static_cast<char *>( buffer ) , bytesToRead );
133 
134  if ( (is.gcount() != bytesToRead) || is.fail() )
135  {
136  return false;
137  }
138  buffer = static_cast<char *>( buffer ) + bytesToRead;
139  bytesRemaining -= bytesToRead;
140  }
141 
142  return true;
143 }
144 
145 
146 bool StreamingImageIOBase::WriteBufferAsBinary( std::ostream& os, const void *buffer, StreamingImageIOBase::SizeType num )
147 {
148  // some systems have a limit of 2GB to be written at once
149  const SizeType maxChunk = 1024*1024*1024;
150 
151  std::streamsize bytesRemaining = num;
152  while (bytesRemaining)
153  {
154 
155  SizeType bytesToWrite = bytesRemaining > maxChunk ? maxChunk : bytesRemaining;
156 
157  itkDebugMacro(<< "Writing " << bytesToWrite << " of " << bytesRemaining << " bytes for " << m_FileName);
158 
159  os.write(static_cast<const char*>(buffer) , bytesToWrite);
160  if ( os.fail() )
161  {
162  return false;
163  }
164 
165  buffer = static_cast<const char *>( buffer ) + bytesToWrite;
166  bytesRemaining -= bytesToWrite;
167  }
168 
169  return true;
170 }
171 
172 
173 bool StreamingImageIOBase::StreamWriteBufferAsBinary(std::ostream& file, const void *_buffer)
174 {
175  itkDebugMacro( << "StreamingWriteBufferAsBinary called" );
176 
177  const char *buffer = static_cast< const char* >( _buffer );
178  // Offset into file
179  std::streampos dataPos = this->GetDataPosition();
180 
181  // compute the number of continuous bytes to be written
182  std::streamsize sizeOfChunk = 1;
183  unsigned int movingDirection = 0;
184  do
185  {
186  sizeOfChunk *= m_IORegion.GetSize(movingDirection);
187  ++movingDirection;
188  }
189  while ( movingDirection < m_IORegion.GetImageDimension() &&
190  m_IORegion.GetSize(movingDirection-1) == this->GetDimensions(movingDirection-1) );
191  sizeOfChunk *= this->GetPixelSize();
192 
193 
195  while ( m_IORegion.IsInside(currentIndex) )
196  {
197  // calculate the position to seek to in the file
198  std::streampos seekPos = 0;
199  size_t subDimensionQuantity = 1;
200  for ( unsigned int i = 0; i < m_IORegion.GetImageDimension(); ++i )
201  {
202  seekPos = seekPos + static_cast<std::streamoff> (subDimensionQuantity *
203  this->GetPixelSize() *
204  currentIndex[i]);
205  subDimensionQuantity *= this->GetDimensions(i);
206  }
207 
208  file.seekp( dataPos+seekPos, std::ios::beg );
209  this->WriteBufferAsBinary( file, buffer, sizeOfChunk );
210 
211  // increment the buffer pointer
212  buffer += sizeOfChunk;
213 
214 
215  itkDebugMacro(<< "Writing " << sizeOfChunk << " of " << " ?? bytes for " << m_FileName << " at " << dataPos+seekPos << " position in file");
216 
217 
218  if ( file.fail() )
219  {
220  itkExceptionMacro(<<"Fail writing");
221  }
222 
223  if (movingDirection == m_IORegion.GetImageDimension())
224  break;
225 
226  // increment index to next chunk
227  ++currentIndex[movingDirection];
228  for (unsigned int i = movingDirection; i < m_IORegion.GetImageDimension()-1; ++i)
229  {
230  // when reaching the end of the movingDirection dimension carry to
231  // higher dimensions
232  if ( static_cast<ImageIORegion::SizeValueType>(currentIndex[i] - m_IORegion.GetIndex(i))
233  >= m_IORegion.GetSize(i) )
234  {
235  currentIndex[i] = m_IORegion.GetIndex(i);
236  ++currentIndex[i+1];
237  }
238  }
239  }
240 
241 
242  return true;
243 }
244 
245 
246 void StreamingImageIOBase::OpenFileForReading(std::ifstream& os, const char* filename)
247 {
248  // Make sure that we have a file to
249  if ( *filename == 0 )
250  {
251  itkExceptionMacro(<<"A FileName must be specified.");
252  }
253 
254  // Close file from any previous image
255  if ( os.is_open() )
256  {
257  os.close();
258  }
259 
260  // Open the new file for reading
261  itkDebugMacro(<< "Initialize: opening file " << filename);
262 
263  os.open(filename, std::ios::in | std::ios::binary );
264  if ( os.fail() )
265  {
266  itkExceptionMacro(<< "Could not open file for reading: " << filename);
267  }
268 
269 }
270 
271 void StreamingImageIOBase::OpenFileForWriting(std::ofstream& os, const char* filename, bool truncate)
272 {
273  // Make sure that we have a file to
274  if ( *filename == 0 )
275  {
276  itkExceptionMacro(<<"A FileName must be specified.");
277  }
278 
279  // Close file from any previous image
280  if ( os.is_open() )
281  {
282  os.close();
283  }
284 
285  // Open the new file for writing
286  itkDebugMacro(<< "Initialize: opening file " << filename);
287 
288  if (truncate)
289  {
290  // truncate
291  os.open( m_FileName.c_str(), std::ios::out | std::ios::binary | std::ios::trunc );
292 
293  }
294  else
295  {
296  os.open( m_FileName.c_str(), std::ios::out | std::ios::binary | std::ios::in );
297  }
298 
299  if ( os.fail() )
300  {
301  itkExceptionMacro(<< "Could not open file for writing: " << filename);
302  }
303 
304 }
305 
307 {
308  return true;
309 }
310 
312 {
313  return true;
314 }
315 
316 
317 unsigned int
318 StreamingImageIOBase::GetActualNumberOfSplitsForWriting(unsigned int numberOfRequestedSplits,
319  const ImageIORegion &pasteRegion,
320  const ImageIORegion &largestPossibleRegion)
321 {
322  if (!itksys::SystemTools::FileExists( m_FileName.c_str() ))
323  {
324  // file doesn't exits so we don't have potential problems
325  }
326  else if (pasteRegion != largestPossibleRegion)
327  {
328  // we are going to be pasting (may be streaming too)
329 
330  // need to check to see if the file is compatible
331  std::string errorMessage;
332  Pointer headerImageIOReader = dynamic_cast<StreamingImageIOBase*>(this->CreateAnother().GetPointer());
333 
334  try
335  {
336  headerImageIOReader->SetFileName(m_FileName.c_str());
337  headerImageIOReader->ReadImageInformation();
338  }
339  catch (...)
340  {
341  errorMessage = "Unable to read information from file: " + m_FileName;
342  }
343 
344  // we now need to check that the following match:
345  // 2)pixel type
346  // 3)dimensions
347  // 4)size/origin/spacing
348  // 5)direction cosines
349  //
350  // todo check for byte order
351 
352  if (errorMessage.size())
353  {
354  // 0) Can't read file
355  }
356  // 2)pixel type
357  // this->GetPixelType() is not verified becasue the metaio file format
358  // stores all multi-component types as arrays, so it does not
359  // distinguish between pixel types. Also as long as the compoent
360  // and number of compoents match we should be able to paste, that
361  // is the numbers should be the same it is just the interpretation
362  // that is not matching
363  else if ( headerImageIOReader->GetNumberOfComponents() != this->GetNumberOfComponents() ||
364  headerImageIOReader->GetComponentType() != this->GetComponentType() )
365  {
366  errorMessage = "Component type does not match in file: " + m_FileName;
367  }
368  // 3)dimensions/size
369  else if (headerImageIOReader->GetNumberOfDimensions() != this->GetNumberOfDimensions())
370  {
371  errorMessage = "Dimensions does not match in file: " + m_FileName;
372  }
373  else
374  {
375  for (unsigned int i = 0; i < this->GetNumberOfDimensions(); ++i)
376  {
377  // 4)size/origin/spacing
378  if (headerImageIOReader->GetDimensions(i) != this->GetDimensions(i) ||
379  headerImageIOReader->GetSpacing(i) != this->GetSpacing(i) ||
380  headerImageIOReader->GetOrigin(i) != this->GetOrigin(i))
381  {
382  errorMessage = "Size, spacing or origin does not match in file: " + m_FileName;
383  break;
384  }
385  // 5)direction cosines
386  if (headerImageIOReader->GetDirection(i) != this->GetDirection(i))
387  {
388  errorMessage = "Direction cosines does not match in file: " + m_FileName;
389  break;
390  }
391  }
392  }
393 
394  if (errorMessage.size())
395  {
396  itkExceptionMacro("Unable to paste because pasting file exists and is different. " << errorMessage);
397  }
398  else if ( headerImageIOReader->GetPixelType() != this->GetPixelType() )
399  {
400  // since there is currently poor support for pixel types in
401  // MetaIO we will just warn when it does not match
402  itkWarningMacro("Pixel types does not match file, but component type and number of components do.");
403  }
404  }
405  else if (numberOfRequestedSplits != 1)
406  {
407  // we are going be streaming
408 
409  // need to remove the file incase the file doesn't match our
410  // current header/meta data information
411  if (!itksys::SystemTools::RemoveFile(m_FileName.c_str()))
412  itkExceptionMacro("Unable to remove file for streaming: " << m_FileName);
413  }
414 
415  return GetActualNumberOfSplitsForWritingCanStreamWrite(numberOfRequestedSplits, pasteRegion);
416 
417 }
418 
419 
421 {
422  // This implementation returns the requestedRegion if
423  // "UseStreamedReading" is enabled
424 
425  ImageIORegion streamableRegion(this->m_NumberOfDimensions);
426  if( !m_UseStreamedReading )
427  {
428  for( unsigned int i=0; i < this->m_NumberOfDimensions; i++ )
429  {
430  streamableRegion.SetSize( i, this->m_Dimensions[i] );
431  streamableRegion.SetIndex( i, 0 );
432  }
433  }
434  else
435  {
436  streamableRegion = requestedRegion;
437  }
438 
439  return streamableRegion;
440 }
441 
442 
444 {
445  // we choose the max dimension and then pad the smaller with ones
446  //
447  // This enables a 2D request from a 3D volume to get the first slice,
448  // and a 4D with a 1-sized 4th dimension to equal the 3D volume
449  // aswell.
450  unsigned int maxNumberOfDimension = vnl_math_max( this->GetNumberOfDimensions(), this->GetIORegion().GetImageDimension() );
451 
452  ImageIORegion ioregion( maxNumberOfDimension );
453  ImageIORegion largestRegion( maxNumberOfDimension );
454  for(unsigned int i=0; i<maxNumberOfDimension; i++)
455  {
456 
457  largestRegion.SetIndex(i, 0);
458  if ( i < this->GetNumberOfDimensions() )
459  {
460  largestRegion.SetSize( i, this->GetDimensions(i) );
461  }
462  else
463  {
464  largestRegion.SetSize( i, 1 );
465  }
466 
467  if ( i < this->GetIORegion().GetImageDimension() )
468  {
469  ioregion.SetIndex( i, this->GetIORegion().GetIndex(i) );
470  ioregion.SetSize( i, this->GetIORegion().GetSize(i) );
471  }
472  else
473  {
474  ioregion.SetIndex( i, 0 );
475  ioregion.SetSize( i, 1 );
476  }
477 
478  }
479 
480  return (largestRegion != ioregion);
481 }
482 
483 } // namespace itk

Generated at Sun May 19 2013 00:09:45 for Orfeo Toolbox with doxygen 1.8.3.1