Orfeo Toolbox  3.16
otbImageFileReader.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: ORFEO Toolbox
4  Language: C++
5  Date: $Date$
6  Version: $Revision$
7 
8 
9  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
10  See OTBCopyright.txt for details.
11 
12 
13  This software is distributed WITHOUT ANY WARRANTY; without even
14  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  PURPOSE. See the above copyright notices for more information.
16 
17 =========================================================================*/
18 #ifndef __otbImageFileReader_txx
19 #define __otbImageFileReader_txx
20 
21 #include "otbImageFileReader.h"
22 
23 #include <fstream>
24 
25 #include "itksys/SystemTools.hxx"
26 #include "itkMetaDataObject.h"
27 
28 #include "otbMacro.h"
29 #include "otbSystem.h"
30 #include "otbImageIOFactory.h"
31 #include "otbImageKeywordlist.h"
32 #include "otbMetaDataKey.h"
33 
34 #include "otbGDALImageIO.h" //FIXME avoid requiring GDALImageIO here
35 #include "otbTileMapImageIO.h" //FIXME avoid requiring TileMapImageIO here
36 #include "otbCurlHelper.h"
37 
38 namespace otb
39 {
40 
41 template<class T>
42 bool PixelIsComplex(const std::complex<T>& /*dummy*/)
43 {
44  return true;
45 }
46 template<class T>
47 bool PixelIsComplex(const T& /*dummy*/)
48 {
49  return false;
50 }
51 
52 template <class TOutputImage>
54 ::ImageFileReader() : itk::ImageFileReader<TOutputImage>()
55 {
56  m_Curl = CurlHelper::New();
57 
58  m_FilenameHelper = FNameHelperType::New();
59 
60  m_AdditionalNumber = 0;
61 }
62 
63 template <class TOutputImage>
66 {
67 }
68 
69 template <class TOutputImage>
71 ::PrintSelf(std::ostream& os, itk::Indent indent) const
72 {
73  Superclass::PrintSelf(os, indent);
74 
75  if (this->m_ImageIO)
76  {
77  os << indent << "ImageIO: \n";
78  this->m_ImageIO->Print(os, indent.GetNextIndent());
79  }
80  else
81  {
82  os << indent << "ImageIO: (null)" << "\n";
83  }
84 
85  os << indent << "UserSpecifiedImageIO flag: " << this->m_UserSpecifiedImageIO << "\n";
86  os << indent << "m_FileName: " << this->m_FileName << "\n";
87 }
88 
89 template <class TOutputImage>
90 void
93 {
94 
95  typename TOutputImage::Pointer output = this->GetOutput();
96 
97  // allocate the output buffer
98  output->SetBufferedRegion(output->GetRequestedRegion());
99  output->Allocate();
100 
101  // Test if the file exist and if it can be open.
102  // An exception will be thrown otherwise.
103  this->TestFileExistanceAndReadability();
104 
105  // Tell the ImageIO to read the file
106  OutputImagePixelType *buffer =
107  output->GetPixelContainer()->GetBufferPointer();
108  this->m_ImageIO->SetFileName(this->m_FileName.c_str());
109 
110  itk::ImageIORegion ioRegion(TOutputImage::ImageDimension);
111 
112  itk::ImageIORegion::SizeType ioSize = ioRegion.GetSize();
113  itk::ImageIORegion::IndexType ioStart = ioRegion.GetIndex();
114 
115  /* Init IORegion with size or streaming size */
116  SizeType dimSize;
117  for (unsigned int i = 0; i < TOutputImage::ImageDimension; ++i)
118  {
119  if (i < this->m_ImageIO->GetNumberOfDimensions())
120  {
121  if (!this->m_ImageIO->CanStreamRead()) dimSize[i] = this->m_ImageIO->GetDimensions(i);
122  else dimSize[i] = output->GetRequestedRegion().GetSize()[i];
123  }
124  else
125  {
126  // Number of dimensions in the output is more than number of dimensions
127  // in the ImageIO object (the file). Use default values for the size,
128  // spacing, and origin for the final (degenerate) dimensions.
129  dimSize[i] = 1;
130  }
131  }
132 
133  for (unsigned int i = 0; i < dimSize.GetSizeDimension(); ++i)
134  {
135  ioSize[i] = dimSize[i];
136  }
137 
138  typedef typename TOutputImage::IndexType IndexType;
139  IndexType start;
140  if (!this->m_ImageIO->CanStreamRead()) start.Fill(0);
141  else start = output->GetRequestedRegion().GetIndex();
142  for (unsigned int i = 0; i < start.GetIndexDimension(); ++i)
143  {
144  ioStart[i] = start[i];
145  }
146 
147  ioRegion.SetSize(ioSize);
148  ioRegion.SetIndex(ioStart);
149 
150  this->m_ImageIO->SetIORegion(ioRegion);
151 
154 
155  if (this->m_ImageIO->GetComponentTypeInfo()
156  == typeid(typename ConvertPixelTraits::ComponentType)
157  && (this->m_ImageIO->GetNumberOfComponents()
158  == ConvertIOPixelTraits::GetNumberOfComponents()))
159  {
160  // Have the ImageIO read directly into the allocated buffer
161  this->m_ImageIO->Read(buffer);
162  return;
163  }
164  else // a type conversion is necessary
165  {
166  // note: char is used here because the buffer is read in bytes
167  // regardless of the actual type of the pixels.
168  ImageRegionType region = output->GetBufferedRegion();
169 
170  // Adapt the image size with the region
171  std::streamoff nbBytes = (this->m_ImageIO->GetComponentSize() * this->m_ImageIO->GetNumberOfComponents())
172  * static_cast<std::streamoff>(region.GetNumberOfPixels());
173 
174  char * loadBuffer = new char[nbBytes];
175 
176  otbMsgDevMacro(<< "size of Buffer to GDALImageIO::read = " << nbBytes << " = \n"
177  << "ComponentSize ("<< this->m_ImageIO->GetComponentSize() << ") x " \
178  << "Nb of Component (" << this->m_ImageIO->GetNumberOfComponents() << ") x " \
179  << "Nb of Pixel to read (" << region.GetNumberOfPixels() << ")" );
180 
181  this->m_ImageIO->Read(loadBuffer);
182 
183  this->DoConvertBuffer(loadBuffer, region.GetNumberOfPixels());
184 
185  delete[] loadBuffer;
186  }
187 }
188 
189 template <class TOutputImage>
190 void
193 {
194  typename TOutputImage::Pointer out = dynamic_cast<TOutputImage*>(output);
195 
196  // If the ImageIO object cannot stream, then set the RequestedRegion to the
197  // LargestPossibleRegion
198  if (!this->m_ImageIO->CanStreamRead())
199  {
200  if (out)
201  {
202  out->SetRequestedRegion(out->GetLargestPossibleRegion());
203  }
204  else
205  {
206  throw itk::ImageFileReaderException(__FILE__, __LINE__,
207  "Invalid output object type");
208  }
209  }
210 }
211 
212 template <class TOutputImage>
213 void
216 {
217 
218  typename TOutputImage::Pointer output = this->GetOutput();
219 
220  itkDebugMacro(<< "Reading file for GenerateOutputInformation()" << this->m_FileName);
221 
222  // Check to see if we can read the file given the name or prefix
223  //
224  if (this->m_FileName == "")
225  {
226  throw itk::ImageFileReaderException(__FILE__, __LINE__, "FileName must be specified");
227  }
228 
229  // Find real image file name
230  // !!!! Update FileName
231  std::string lFileName;
232  bool found = GetGdalReadImageFileName(this->m_FileName, lFileName);
233  if (found == false)
234  {
235  otbMsgDebugMacro(<< "Filename was NOT unknown. May be recognized by a Image factory ! ");
236  }
237  // Update FileName
238  this->m_FileName = lFileName;
239 
240  std::string lFileNameOssimKeywordlist = this->m_FileName;
241 
242  // Test if the file exists and if it can be opened.
243  // An exception will be thrown otherwise.
244  // We catch the exception because some ImageIO's may not actually
245  // open a file. Still reports file error if no ImageIO is loaded.
246 
247  try
248  {
249  m_ExceptionMessage = "";
250  this->TestFileExistanceAndReadability();
251  }
252  catch (itk::ExceptionObject & err)
253  {
254  m_ExceptionMessage = err.GetDescription();
255  }
256 
257  if (this->m_UserSpecifiedImageIO == false) //try creating via factory
258  {
259  this->m_ImageIO = ImageIOFactory::CreateImageIO(this->m_FileName.c_str(), itk::ImageIOFactory::ReadMode);
260  }
261 
262  if (this->m_ImageIO.IsNull())
263  {
264  this->Print(std::cerr);
265  itk::ImageFileReaderException e(__FILE__, __LINE__);
266  std::ostringstream msg;
267  msg << " Could not create IO object for file "
268  << this->m_FileName.c_str() << std::endl;
269  msg << " Tried to create one of the following:" << std::endl;
270  std::list<itk::LightObject::Pointer> allobjects =
272  for (std::list<itk::LightObject::Pointer>::iterator i = allobjects.begin();
273  i != allobjects.end(); ++i)
274  {
275  itk::ImageIOBase* io = dynamic_cast<itk::ImageIOBase*>(i->GetPointer());
276  msg << " " << io->GetNameOfClass() << std::endl;
277  }
278  msg << " You probably failed to set a file suffix, or" << std::endl;
279  msg << " set the suffix to an unsupported type." << std::endl;
280  e.SetDescription(msg.str().c_str());
281  throw e;
282  return;
283  }
284 
285 
286  // Get the ImageIO MetaData Dictionary
287  itk::MetaDataDictionary& dict = this->m_ImageIO->GetMetaDataDictionary();
288 
289  // Special actions for the gdal image IO
290  if (strcmp(this->m_ImageIO->GetNameOfClass(), "GDALImageIO") == 0)
291  {
292  typename GDALImageIO::Pointer imageIO = dynamic_cast<GDALImageIO*>(this->GetImageIO());
293 
294  // Hint the IO whether the OTB image type takes complex pixels
295  // this will determine the strategy to fill up a vector image
296  OutputImagePixelType dummy;
297  imageIO->SetIsComplex(PixelIsComplex(dummy));
298 
299  // VectorImage ??
300  if (strcmp(output->GetNameOfClass(), "VectorImage") == 0)
301  imageIO->SetIsVectorImage(true);
302  else
303  imageIO->SetIsVectorImage(false);
304 
305  // Pass the dataset number (used for hdf files for example)
306  if (m_FilenameHelper->SubDatasetIndexIsSet())
307  {
308  imageIO->SetDatasetNumber(m_FilenameHelper->GetSubDatasetIndex());
309  }
310  else
311  {
312  imageIO->SetDatasetNumber(m_AdditionalNumber);
313  }
314  }
315 
316  // Special actions for the JPEG2000ImageIO
317  if( strcmp(this->m_ImageIO->GetNameOfClass(), "JPEG2000ImageIO") == 0 )
318  {
319  if (m_FilenameHelper->ResolutionFactorIsSet())
320  {
321  itk::EncapsulateMetaData<unsigned int>(dict,
322  MetaDataKey::ResolutionFactor, m_FilenameHelper->GetResolutionFactor());
323  }
324  else
325  {
326  itk::EncapsulateMetaData<unsigned int>(dict,
327  MetaDataKey::ResolutionFactor, m_AdditionalNumber);
328  }
329  itk::EncapsulateMetaData<unsigned int>(dict,
330  MetaDataKey::CacheSizeInBytes, 135000000);
331  }
332 
333  // Got to allocate space for the image. Determine the characteristics of
334  // the image.
335  //
336  this->m_ImageIO->SetFileName(this->m_FileName.c_str());
337  this->m_ImageIO->ReadImageInformation();
338  // Initialization du nombre de Composante par pixel
339 // THOMAS ceci n'est pas dans ITK !!
340 // output->SetNumberOfComponentsPerPixel(this->m_ImageIO->GetNumberOfComponents());
341 
342  SizeType dimSize;
343  double spacing[TOutputImage::ImageDimension];
344  double origin[TOutputImage::ImageDimension];
345  typename TOutputImage::DirectionType direction;
346  std::vector<double> axis;
347 
348  for (unsigned int i = 0; i < TOutputImage::ImageDimension; ++i)
349  {
350  if (i < this->m_ImageIO->GetNumberOfDimensions())
351  {
352  dimSize[i] = this->m_ImageIO->GetDimensions(i);
353  spacing[i] = this->m_ImageIO->GetSpacing(i);
354  origin[i] = this->m_ImageIO->GetOrigin(i);
355 // Please note: direction cosines are stored as columns of the
356 // direction matrix
357  axis = this->m_ImageIO->GetDirection(i);
358  for (unsigned j = 0; j < TOutputImage::ImageDimension; ++j)
359  {
360  if (j < this->m_ImageIO->GetNumberOfDimensions())
361  {
362  direction[j][i] = axis[j];
363  }
364  else
365  {
366  direction[j][i] = 0.0;
367  }
368  }
369  }
370  else
371  {
372  // Number of dimensions in the output is more than number of dimensions
373  // in the ImageIO object (the file). Use default values for the size,
374  // spacing, origin and direction for the final (degenerate) dimensions.
375  dimSize[i] = 1;
376  spacing[i] = 1.0;
377  origin[i] = 0.0;
378  for (unsigned j = 0; j < TOutputImage::ImageDimension; ++j)
379  {
380  if (i == j)
381  {
382  direction[j][i] = 1.0;
383  }
384  else
385  {
386  direction[j][i] = 0.0;
387  }
388  }
389  }
390  }
391 
392  if (m_FilenameHelper->GetSkipCarto())
393  {
394  for (unsigned int i = 0; i < TOutputImage::ImageDimension; ++i)
395  {
396  origin[i] = 0.0;
397  if ( m_FilenameHelper->GetResolutionFactor() != 0 )
398  {
399  spacing[i] = 1.0*vcl_pow((double)2, (double)m_FilenameHelper->GetResolutionFactor());
400  }
401  else
402  {
403  spacing[i] = 1.0;
404  }
405  }
406  }
407 
408  output->SetSpacing(spacing); // Set the image spacing
409  output->SetOrigin(origin); // Set the image origin
410  output->SetDirection(direction); // Set the image direction cosines
411 
412  // Update otb Keywordlist
413  ImageKeywordlist otb_kwl;
414  if (!m_FilenameHelper->ExtGEOMFileNameIsSet())
415  {
416  otb_kwl = ReadGeometryFromImage(lFileNameOssimKeywordlist);
417  otbMsgDevMacro(<< "Loading internal kwl");
418  }
419  else
420  {
421  otb_kwl = ReadGeometryFromGEOMFile(m_FilenameHelper->GetExtGEOMFileName());
422  otbMsgDevMacro(<< "Loading external kwl");
423  }
424 
425  // Pass the depth parameter from the tilemap around
426  if (strcmp(this->m_ImageIO->GetNameOfClass(), "TileMapImageIO") == 0)
427  {
428  typename TileMapImageIO::Pointer imageIO = dynamic_cast<TileMapImageIO*>(this->GetImageIO());
429  std::ostringstream depth;
430  depth << imageIO->GetDepth();
431  otb_kwl.AddKey("depth", depth.str());
432  }
433 
434  otbMsgDevMacro(<< otb_kwl);
435 
436  // Don't add an empty ossim keyword list
437  if( otb_kwl.GetSize() != 0 )
438  {
439  itk::EncapsulateMetaData<ImageKeywordlist>(dict,
441  }
442  else
443  {
444  //
445  // For image with world file, we have a non-null GeoTransform, an empty kwl, but no projection ref.
446  // Decision made here : if the keywordlist is empty, and the geotransform is not the identity,
447  // then assume the file is in WGS84
448  //
449  std::string projRef;
451 
452  const double Epsilon = 1.0E-12;
453  if ( projRef.empty()
454  && vcl_abs(origin[0]) > Epsilon
455  && vcl_abs(origin[1]) > Epsilon
456  && vcl_abs(spacing[0] - 1) > Epsilon
457  && vcl_abs(spacing[1] - 1) > Epsilon)
458  {
459  std::string wgs84ProjRef =
460  "GEOGCS[\"GCS_WGS_1984\", DATUM[\"D_WGS_1984\", SPHEROID[\"WGS_1984\", 6378137, 298.257223563]],"
461  "PRIMEM[\"Greenwich\", 0], UNIT[\"Degree\", 0.017453292519943295]]";
462 
463  itk::EncapsulateMetaData<std::string>(dict, MetaDataKey::ProjectionRefKey, wgs84ProjRef);
464  }
465  }
466 
467  // If Skip ProjectionRef is activated, remove ProjRef from dict
468  if (m_FilenameHelper->GetSkipCarto())
469  {
470  itk::EncapsulateMetaData<std::string>(dict, MetaDataKey::ProjectionRefKey, "");
471  }
472 
473  //Copy MetaDataDictionary from instantiated reader to output image.
474  if (!m_FilenameHelper->GetSkipGeom())
475  {
476  output->SetMetaDataDictionary(this->m_ImageIO->GetMetaDataDictionary());
477  this->SetMetaDataDictionary(this->m_ImageIO->GetMetaDataDictionary());
478  }
479  else
480  {
481  itk::MetaDataDictionary dictLight;
482  std::string projRef;
484  itk::EncapsulateMetaData<std::string>(dictLight, MetaDataKey::ProjectionRefKey, projRef);
485  output->SetMetaDataDictionary(dictLight);
486  this->SetMetaDataDictionary(dictLight);
487  }
488 
489  typedef typename TOutputImage::IndexType IndexType;
490 
491  IndexType start;
492  start.Fill(0);
493 
494  ImageRegionType region;
495  region.SetSize(dimSize);
496  region.SetIndex(start);
497 
498 // THOMAS : ajout
499 // If a VectorImage, this requires us to set the
500 // VectorLength before allocate
501  if (strcmp(output->GetNameOfClass(), "VectorImage") == 0)
502  {
503  typedef typename TOutputImage::AccessorFunctorType AccessorFunctorType;
504  AccessorFunctorType::SetVectorLength(output, this->m_ImageIO->GetNumberOfComponents());
505  }
506 
507  output->SetLargestPossibleRegion(region);
508 
509 }
510 
511 template <class TOutputImage>
512 void
515 {
516  // Test if the file a server name
517  if (this->m_FileName[0] == 'h'
518  && this->m_FileName[1] == 't'
519  && this->m_FileName[2] == 't'
520  && this->m_FileName[3] == 'p')
521  {
522  // If the url is not available
523  if (!m_Curl->TestUrlAvailability(this->m_FileName))
524  {
525  itk::ImageFileReaderException e(__FILE__, __LINE__);
526  std::ostringstream msg;
527  msg << "File name is an http address, but curl fails to connect to it "
528  << std::endl << "Filename = " << this->m_FileName
529  << std::endl;
530  e.SetDescription(msg.str().c_str());
531  throw e;
532  }
533  return;
534  }
535 
536  // Test if the file exists.
537  if (!itksys::SystemTools::FileExists(this->m_FileName.c_str()))
538  {
539  itk::ImageFileReaderException e(__FILE__, __LINE__);
540  std::ostringstream msg;
541  msg << "The file doesn't exist. "
542  << std::endl << "Filename = " << this->m_FileName
543  << std::endl;
544  e.SetDescription(msg.str().c_str());
545  throw e;
546  return;
547  }
548 
549  // Test if the file can be open for reading access.
550  //Only if m_FileName specify a filename (not a dirname)
551  if (System::IsAFileName(this->m_FileName) == true)
552  {
553  std::ifstream readTester;
554  readTester.open(this->m_FileName.c_str());
555  if (readTester.fail())
556  {
557  readTester.close();
558  std::ostringstream msg;
559  msg << "The file couldn't be opened for reading. "
560  << std::endl << "Filename: " << this->m_FileName
561  << std::endl;
562  itk::ImageFileReaderException e(__FILE__, __LINE__, msg.str().c_str(), ITK_LOCATION);
563  throw e;
564  return;
565 
566  }
567  readTester.close();
568  }
569 }
570 
571 template <class TOutputImage>
572 bool
574 ::GetGdalReadImageFileName(const std::string& filename, std::string& GdalFileName)
575 {
576  std::vector<std::string> listFileSearch;
577  listFileSearch.push_back("DAT_01.001");
578  listFileSearch.push_back("dat_01.001"); // RADARSAT or SAR_ERS2
579  listFileSearch.push_back("IMAGERY.TIF");
580  listFileSearch.push_back("imagery.tif"); //For format SPOT5TIF
581 // Not recognized as a supported file format by GDAL.
582 // listFileSearch.push_back("IMAGERY.BIL"); listFileSearch.push_back("imagery.bil"); //For format SPOT5BIL
583  listFileSearch.push_back("IMAG_01.DAT");
584  listFileSearch.push_back("imag_01.dat"); //For format SPOT4
585 
586  std::string str_FileName;
587  bool fic_trouve(false);
588 
589  // Si c'est un repertoire, on regarde le contenu pour voir si c'est pas du RADARSAT, ERS
590  std::vector<std::string> listFileFind;
591  listFileFind = System::Readdir(filename);
592  if (listFileFind.empty() == false)
593  {
594  unsigned int cpt(0);
595  while ((cpt < listFileFind.size()) && (fic_trouve == false))
596  {
597  str_FileName = std::string(listFileFind[cpt]);
598  for (unsigned int i = 0; i < listFileSearch.size(); ++i)
599  {
600  if (str_FileName.compare(listFileSearch[i]) == 0)
601  {
602  GdalFileName = std::string(filename) + str_FileName; //listFileSearch[i];
603  fic_trouve = true;
604  }
605  }
606  ++cpt;
607  }
608  }
609  else
610  {
611  std::string strFileName(filename);
612 
613  std::string extension = System::GetExtension(strFileName);
614  if ((extension == "HDR") || (extension == "hdr"))
615  {
616  //Supprime l'extension
617  GdalFileName = System::GetRootName(strFileName);
618  }
619 
620  else
621  {
622  // Sinon le filename est le nom du fichier a ouvrir
623  GdalFileName = std::string(filename);
624  }
625  fic_trouve = true;
626  }
627  otbMsgDevMacro(<< "lFileNameGdal : " << GdalFileName.c_str());
628  otbMsgDevMacro(<< "fic_trouve : " << fic_trouve);
629  return (fic_trouve);
630 }
631 
632 template <class TOutputImage>
633 void
635 ::SetFileName(std::string extendedFileName)
636 {
637  this->SetFileName(extendedFileName.c_str());
638 }
639 
640 template <class TOutputImage>
641 void
643 ::SetFileName(const char* extendedFileName)
644 {
645  this->m_FilenameHelper->SetExtendedFileName(extendedFileName);
646  this->m_FileName = this->m_FilenameHelper->GetSimpleFileName();
647  this->Modified();
648 }
649 
650 template <class TOutputImage>
651 const char*
654 {
655 return this->m_FilenameHelper->GetSimpleFileName();
656 }
657 
658 } //namespace otb
659 
660 #endif

Generated at Sun Feb 3 2013 00:26:07 for Orfeo Toolbox with doxygen 1.8.1.1