OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimTiledImageHandler.cpp
Go to the documentation of this file.
1 //*************************************************************************************************
2 //
3 // License: LGPL
4 //
5 // See LICENSE.txt file in the top level directory for more details.
6 //
7 // Author: Oscar Kramer
8 //
9 // Description:
10 //
11 // Image handler used for tile-files when the full image is distributed across multiple files,
12 // as is the case for tiled Quickbird imagery. This is not for use with band-separate formats,
13 // but only "spatially-separate" schemes.
14 //
15 //*************************************************************************************************
16 // $Id: ossimTiledImageHandler.cpp 2644 2011-05-26 15:20:11Z oscar.kramer $
17 
18 #include <algorithm>
19 
23 #include <ossim/base/ossimRegExp.h>
24 #include <ossim/base/ossimRefPtr.h>
28 #include <ossim/base/ossimNotify.h>
31 #include <ossim/base/ossimTrace.h>
34 
35 RTTI_DEF1(ossimTiledImageHandler, "ossimTiledImageHandler", ossimImageHandler)
36 
37 // Static trace for debugging
38 static ossimTrace traceDebug("ossimTiledImageHandler:debug");
39 
40 //*************************************************************************************************
42 //*************************************************************************************************
44  : m_tileFiles(0),
45  m_tile(0),
46  m_fullImgRect(),
48  m_startOvrResLevel(-1),
49  m_lockSubOvrs(false)
50 #else
51  m_startOvrResLevel(1)
52 #endif
53 {
54 }
55 
56 //*************************************************************************************************
58 //*************************************************************************************************
60 {
61  close();
62 }
63 
64 //*************************************************************************************************
67 //*************************************************************************************************
69 {
70  vector<ossimTileFile>::iterator iter = m_tileFiles.begin();
71  while (iter != m_tileFiles.end())
72  {
73  (*iter).imageHandler->close();
74  ++iter;
75  }
76  m_tileFiles.clear();
77 }
78 
79 //*************************************************************************************************
82 //*************************************************************************************************
84 {
85  if (m_tileFiles.size() > 0)
86  return true;
87 
88  return false;
89 }
90 
91 //*************************************************************************************************
93 //*************************************************************************************************
95 {
96  m_tile = 0;
97  if ((m_tileFiles.size() == 0))
98  return;
99 
100  // Just copy the image data tile of the first tile-file:
101  ossimRefPtr<ossimImageHandler> h0 = m_tileFiles[0].imageHandler;
102  ossimIrect rect (h0->getBoundingRect());
103  rect.set_lr(rect.ul() + ossimIpt(h0->getTileWidth()-1, h0->getTileHeight()-1));
104  ossimRefPtr<ossimImageData> source_tile = m_tileFiles[0].imageHandler->getTile(rect);
105  if (!source_tile.valid())
106  {
107  ossimNotify(ossimNotifyLevel_FATAL) << "ossimTiledImageHandler::allocate() -- Could not"
108  "determine file-tile image data for allocating image tile. Aborting."<<endl;
109  return;
110  }
111 
112  m_tile = (ossimImageData*) source_tile->dup();
113 }
114 
115 //*************************************************************************************************
117 //*************************************************************************************************
119  ossim_uint32 resLevel)
120 {
121  // First verify that there are file-tiles available:
122  if (m_tileFiles.size() == 0)
124 
125  // Allocate data tile if needed:
126  if(!m_tile.valid())
127  {
128  allocate();
129  if(!m_tile.valid())
131  }
132 
133  // Check if res level represents data inside the overall scene overview:
134  if (theOverview.valid() && (resLevel >= m_startOvrResLevel))
135  return theOverview->getTile(tile_rect, resLevel);
136 
137  // Loop over all tile-files to find which intersect the requested image rect. This necessarily
138  // needs to be done at full res coordinates, so need to adjust by res level requested:
139  ossimDpt decimation_factor;
140  // const ossim_uint32 BANDS = m_tile->getNumberOfBands();
141  // const ossim_uint32 PPB = m_tile->getSizePerBand(); // pixels per band
142  // bool none_found = true;
143 
144 
145  // ossim_uint32 wd, hd, ws, hs;
146  // m_tile->getWidthHeight(wd, hd);
147 
148  // Always start with blank tile.
149  m_tile->makeBlank();
150 
151  //---
152  // Add in the sub image offset if any for the rest of this method to work
153  // correctly.
154  //---
155  ossimIrect adjusted_tile_rect = tile_rect + m_fullImgRect.ul();
156 
157  // See if any point of the requested tile is in the image.
158  if ( adjusted_tile_rect.intersects( m_fullImgRect ) )
159  {
160  // This need to set for loadTile to work off the full image rect.
161  m_tile->setImageRectangle(adjusted_tile_rect);
162 
163  vector<ossimTileFile>::iterator tf_iter = m_tileFiles.begin();
164  ossimRefPtr<ossimImageData> source_tile = 0;
165  while (tf_iter != m_tileFiles.end())
166  {
167  if (( (*tf_iter).subImageRects.size() > resLevel) &&
168  adjusted_tile_rect.intersects((*tf_iter).subImageRects[resLevel]))
169  {
170  //---
171  // Current image handler lies within requested rect, need to adjust
172  // this rect to be relative to this subimage offset before fetching
173  // the tile:
174  //---
175  ossimIrect full_image_clip_rect =
176  adjusted_tile_rect.clipToRect( (*tf_iter).subImageRects[resLevel]);
177 
178  // Subtract the sub image offset to make zero base image rect.
179  ossimIrect relative_clip_rect( full_image_clip_rect -
180  (*tf_iter).subImageRects[resLevel].ul());
181 
182  source_tile = (*tf_iter).imageHandler->getTile(relative_clip_rect, resLevel);
183  if ( source_tile.valid() )
184  {
185  if ( (source_tile->getDataObjectStatus() != OSSIM_NULL) &&
186  (source_tile->getDataObjectStatus() != OSSIM_EMPTY) )
187  {
188  // Give the loadTile the clip rect relative to the full image.
189  m_tile->loadTile( source_tile->getBuf(),
190  full_image_clip_rect,
191  OSSIM_BSQ);
192  m_tile->validate();
194  {
195  break;
196  }
197  }
198  }
199  }
200  ++tf_iter;
201  }
202 
203  } // Matches: if ( adjusted_tile_rect.intersects( m_fullImgRect ) )
204 
205  // Set back to zero based rect.
206  m_tile->setImageRectangle(tile_rect);
207 
208  return m_tile;
209 }
210 
211 // Below code was core dumping on tiled DG data. drb - 20160822
212 #if 0
213 
214  ossimIrect relative_rect (tile_rect - (*tf_iter).subImageRects[resLevel].ul());
215  std::cout << "reletive_rect: " << relative_rect << std::endl;
216  source_tile = (*tf_iter).imageHandler->getTile(relative_rect, resLevel);
217 
218  // Quick check to see if a full tile was returned, in which case we can just return that
219  // tile instead of looping below:
220  //if (source_tile->getDataObjectStatus() == OSSIM_FULL)
221  //{
222  // source_tile->setImageRectangle(tile_rect);
223  // return source_tile;
224  //}
225 
226  // Set the tile's rect back to full image space before saving to the list:
227  source_tile->getWidthHeight(ws, hs);
228  std::cout << "ws: " << ws << " hs: " << hs << " wd: " << wd << " hd: " << hd
229  << std::endl;
230  for (ossim_uint32 band = 0; band < BANDS; ++band)
231  {
232  const ossim_uint16 null_pixel = (ossim_uint16) m_tile->getNullPix(band);
233  const ossim_uint16* s = (const ossim_uint16*) source_tile->getBuf(band);
234  ossim_uint16* d = (ossim_uint16*) m_tile->getBuf(band);
235  ossim_uint32 is = 0;
236  ossim_uint32 id = 0;
237  for (ossim_uint32 y=0; (y<hd)&&(y<hs); ++y)
238  {
239  for (ossim_uint32 x=0; x<wd; ++x)
240  {
241  if (x < ws)
242  {
243  // cout << "is: " << is << endl;
244  if (s[is] != null_pixel)
245  d[id] = s[is];
246  ++is;
247  }
248  ++id;
249  }
250  }
251  }
252 
253 
254  }
255  ++tf_iter;
256  }
257 
258  m_tile->validate();
259 
260  } // Matches: if ( tile_rect.intersects( m_fullImgRect ) )
261 
262  return m_tile;
263 }
264 #endif
265 
266 //*************************************************************************************************
270 //*************************************************************************************************
272 {
273  if (m_fullImgRect.hasNans())
274  return 0;
275 
276  // Using simple decimation by powers of 2:
277  ossim_uint32 numlines = m_fullImgRect.height() >> resLevel;
278  return numlines;
279 }
280 
281 //*************************************************************************************************
285 //*************************************************************************************************
287 {
288  if (m_fullImgRect.hasNans())
289  return 0;
290 
291  // Using simple decimation by powers of 2:
292  ossim_uint32 numsamps = m_fullImgRect.width() >> resLevel;
293  return numsamps;
294 }
295 
296 //*************************************************************************************************
299 //*************************************************************************************************
300 bool ossimTiledImageHandler::saveState(ossimKeywordlist& kwl, const char* prefix) const
301 {
302  return ossimImageHandler::saveState(kwl, prefix);
303 }
304 
305 //*************************************************************************************************
308 //*************************************************************************************************
309 bool ossimTiledImageHandler::loadState(const ossimKeywordlist& kwl, const char* prefix)
310 {
311  if (!ossimImageHandler::loadState(kwl, prefix))
312  return false;
313 
314  return open();
315 }
316 
317 //*************************************************************************************************
323 //*************************************************************************************************
325 {
326  return true;
327 }
328 
329 //*************************************************************************************************
330 // Returns the number of bands of the first tile since all tiles need to have the same pixel type.
331 //*************************************************************************************************
333 {
334  if ((m_tileFiles.size() == 0) || (!m_tileFiles[0].imageHandler.valid()))
335  return 0;
336 
337  return m_tileFiles[0].imageHandler->getNumberOfInputBands();
338 }
339 
340 //*************************************************************************************************
345 //*************************************************************************************************
347 {
348  if ((m_tileFiles.size() == 0) || (!m_tileFiles[0].imageHandler.valid()))
349  return 0;
350 
351  if (m_tileFiles[0].imageHandler->isImageTiled())
352  return m_tileFiles[0].imageHandler->getImageTileWidth();
353 
354  return m_tileFiles[0].imageHandler->getNumberOfSamples();
355 }
356 
357 //*************************************************************************************************
362 //*************************************************************************************************
364 {
365  if ((m_tileFiles.size() == 0) || (!m_tileFiles[0].imageHandler.valid()))
366  return 0;
367 
368  if (m_tileFiles[0].imageHandler->isImageTiled())
369  return m_tileFiles[0].imageHandler->getImageTileHeight();
370 
371  return m_tileFiles[0].imageHandler->getNumberOfLines();
372 }
373 
374 //*************************************************************************************************
376 //*************************************************************************************************
378 {
379  if ((m_tileFiles.size() == 0) || (!m_tileFiles[0].imageHandler.valid()))
380  return OSSIM_SCALAR_UNKNOWN;
381 
382  return m_tileFiles[0].imageHandler->getOutputScalarType();
383 }
384 
385 //*************************************************************************************************
387 //*************************************************************************************************
389 {
390  //---
391  // Note: Rectangle should be zero based. Sub image offset handled in
392  // getTile and getImageGeometry. drb
393  //---
395  if ( resLevel > 0 )
396  {
397  ossimDpt decimation;
398  getDecimationFactor(resLevel, decimation);
399 
400  rect = rect*decimation;
401  }
402  return rect;
403 
404 #if 0
405  if (resLevel == 0)
406  return m_fullImgRect;
407 
408  ossimDpt decimation;
409  getDecimationFactor(resLevel, decimation);
410 
411  return m_fullImgRect*decimation;
412 #endif
413 }
414 
415 
416 #if USING_SUB_OVRS
417 //*************************************************************************************************
418 // Overrides base class
419 //*************************************************************************************************
421 {
422  openOverview();
424 }
425 
426 //*************************************************************************************************
430 //*************************************************************************************************
431 bool ossimTiledImageHandler::buildOverview(ossimImageHandlerOverviewCompressionType ctype,
432  ossim_uint32 qual,
434  bool ifr_flag)
435 {
436  if (m_tileFiles.size() == 0)
437  return false;
438 
439  bool all_ok = true;
440  vector<ossimTileFile>::iterator iter = m_tileFiles.begin();
441  while ((iter != m_tileFiles.end()) && all_ok)
442  {
443  if (!(*iter).imageHandler->hasOverviews())
444  {
445  ossimNotify(ossimNotifyLevel_INFO)<<"\nBuilding overview for <"
446  <<(*iter).imageHandler->getFilename()<<">"<<std::endl;
447 
448  all_ok = (*iter).imageHandler->buildOverview(ctype, qual, rtype, ifr_flag);
449  }
450  ++iter;
451  }
452 
453  // Overviews for subimage tile-files have been processed. However, we need to check the
454  // preferences for the overview stop dimension to see if we need additional decimation of the
455  // overall scene to achieve the final desired dimension.
456  ossimString stop_dim_str =
458  if (!stop_dim_str.empty())
459  {
460  ossim_uint32 stop_dim = stop_dim_str.toUInt32();
461  ossimDpt decimation = theDecimationFactors.back();
462  ossim_uint32 nlines = decimation.y * m_fullImgRect.height();
463  ossim_uint32 nsamps = decimation.x * m_fullImgRect.width();
464  if ((nlines > stop_dim) || (nsamps > stop_dim))
465  {
466  // Need to continue decimating. These decimations are stored in an overall scene file.
467  // Need subimage OVRs open for this next operation:
468  openOverview();
469 
471  tob.setInputSource(this);
473 
474  // This magically takes over where we left off in decimating:
476  {
477  // Overview was successfully written, now open it:
479  all_ok = openOverview();
480  }
481  }
482  }
483 
484  return all_ok;
485 }
486 
487 //*************************************************************************************************
488 // Will open overview files for all tile files. Actually, the tile-files will already have opened
489 // their individual overviews, so this method only verifies the fact and initializes the
490 // associated subimage rects at all decimation levels.
491 //*************************************************************************************************
493 {
494  if (m_tileFiles.size() == 0)
495  return false;
496 
497  theDecimationFactors.clear();
498  bool all_ok = true;
499  ossimRefPtr<ossimImageHandler> handler = 0;
500  vector<ossimDpt> factors;
501  ossim_uint32 min_num_rlevels = 999;
502 
503  // Loop over all tile-files to verify their OVR was opened and to calculate the associated
504  // subimage rects at each res level:
505  vector<ossimTileFile>::iterator iter = m_tileFiles.begin();
506  while ((iter != m_tileFiles.end()) && all_ok)
507  {
508  handler = (*iter).imageHandler;
509  if (!handler.valid())
510  {
511  ++iter;
512  continue;
513  }
514 
515  if ((*iter).subImageRects.size() == 0)
516  {
517  ossimNotify(ossimNotifyLevel_INFO)<<"\nBounding image rectangle not defined for <"
518  <<(*iter).imageHandler->getFilename()<<">! Cannot proceed with overviews."<<std::endl;
519  all_ok = false;
520  }
521 
522  else if (handler->getOverview())
523  {
524  // Only verified that overview for tile-file was opened. Check number of decimation levels
525  // to latch minimum:
526  (*iter).overviewIsOpen = true;
527  handler->getDecimationFactors(factors);
528 
529  if (factors.size() < min_num_rlevels)
530  min_num_rlevels = (ossim_uint32) factors.size();
531 
532  // Need to determine the sub image rects at each decimation level:
533  ossimIrect subRectR0 ((*iter).subImageRects[0]);
534  for (ossim_uint32 i=1; i<(ossim_uint32)factors.size(); i++)
535  {
536  ossimIrect r (factors[i].x * subRectR0.ul().x, factors[i].y * subRectR0.ul().y,
537  factors[i].x * subRectR0.lr().x, factors[i].y * subRectR0.lr().y);
538  (*iter).subImageRects.push_back(r);
539  }
540  }
541  else
542  {
543  ossimNotify(ossimNotifyLevel_INFO)<<"\nNo overview available for <"
544  <<(*iter).imageHandler->getFilename()<<">"<<std::endl;
545  all_ok = false;
546  }
547  ++iter;
548  }
549 
550  // Assuming here that the first tile will always provide a good representation of the decimations
551  // for all res levels in all tile-files. This may not be true.
552  if (m_tileFiles.size() && m_tileFiles[0].imageHandler.valid())
553  {
554  m_tileFiles[0].imageHandler->getDecimationFactors(theDecimationFactors);
555  theDecimationFactors.resize(min_num_rlevels);
556  }
557 
558  // Check for overall scene overview file, that takes over where the individual tile-file
559  // overviews leave off:
561  if (!theOverviewFile.exists())
563  if (theOverviewFile.exists())
564  {
565  m_lockSubOvrs = true; // prevent closing and reopening of subimage ovrs
567  m_lockSubOvrs = false; // reset
568  if (theOverview.valid())
569  {
570  vector<ossimDpt> extra_decimations;
571  theOverview->getDecimationFactors(extra_decimations);
572  if (extra_decimations.size())
573  {
574  // Obtain the decimations and add it to our decimation list:
576  ossimDpt start_decimation (theDecimationFactors.back() * 0.5);
577  ossimDpt decimation;
578  for (ossim_uint32 i=0; i<extra_decimations.size(); i++)
579  {
580  decimation.x = start_decimation.x*extra_decimations[i].x;
581  decimation.y = start_decimation.y*extra_decimations[i].y;
582  theDecimationFactors.push_back(decimation);
583  }
584  }
585  }
586  }
587 
588  return all_ok;
589 }
590 
591 //*************************************************************************************************
593 //*************************************************************************************************
595 {
596  if (theOverview.valid())
597  theOverview = 0;
598 
599  if (m_lockSubOvrs == false)
600  {
601  vector<ossimTileFile>::iterator iter = m_tileFiles.begin();
602  while ((iter != m_tileFiles.end()))
603  {
604  if ((*iter).imageHandler.valid())
605  (*iter).imageHandler->closeOverview();
606 
607  ++iter;
608  }
609  }
610 }
611 
612 //*************************************************************************************************
614 //*************************************************************************************************
616 {
617  bool all_have_ovrs = true;
618  vector<ossimTileFile>::const_iterator iter = m_tileFiles.begin();
619  while ((iter != m_tileFiles.end()) && all_have_ovrs)
620  {
621  if (((*iter).imageHandler.valid()) && !((*iter).imageHandler->hasOverviews()))
622  all_have_ovrs = false;
623  ++iter;
624  }
625  return all_have_ovrs;
626 }
627 
628 //*************************************************************************************************
631 //*************************************************************************************************
633 {
634  return (ossim_uint32) theDecimationFactors.size();
635 }
636 
637 #endif /* #if USING_SUB_OVRS */
638 
ossim_uint32 x
virtual void getDecimationFactors(vector< ossimDpt > &decimations) const
This returns all decimation for all levels.
virtual ossim_uint32 getImageTileWidth() const
Returns the tile width of the image or 0 if the image is not tiled.
virtual void setImageRectangle(const ossimIrect &rect)
virtual bool buildOverview(ossimImageHandlerOverviewCompressionType compressionType=OSSIM_OVERVIEW_COMPRESSION_NONE, ossim_uint32 quality=75, ossimFilterResampler::ossimFilterResamplerType resampleType=ossimFilterResampler::ossimFilterResampler_BOX, bool includeFullResFlag=false)
Will build over file for theImageFile.
void allocate()
Initialize tile buffer to match image datatype.
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
Method to the load (recreate) the state of an object from a keyword list.
Represents serializable keyword/value map.
ossim_uint32 y
bool valid() const
Definition: ossimRefPtr.h:75
std::vector< ossimDpt > theDecimationFactors
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
Method to the load (recreate) the state of an object from a keyword list.
double y
Definition: ossimDpt.h:165
ossim_uint32 height() const
Definition: ossimIrect.h:487
virtual ossim_uint32 getTileHeight() const
Returns the default processing tile height.
virtual const ossimImageHandler * getOverview() const
virtual ossimIrect getImageRectangle(ossim_uint32 resLevel=0) const
Returns overall bounding rect in image space.
const ossimIpt & ul() const
Definition: ossimIrect.h:274
virtual ossimDataObjectStatus getDataObjectStatus() const
ossim_uint32 toUInt32() const
virtual void getDecimationFactor(ossim_uint32 resLevel, ossimDpt &result) const
virtual void closeOverview()
If theOverview is initialized it will be deleted and set to NULL.
bool intersects(const ossimIrect &rect) const
Definition: ossimIrect.cpp:183
unsigned short ossim_uint16
virtual ossim_uint32 getNumberOfSamples(ossim_uint32 resLevel=0) const
virtual bool openOverview()
Searches for an overview.
virtual ossim_uint32 getTileWidth() const
Returns the default processing tile width.
virtual ossimObject * dup() const
This class defines an abstract Handler which all image handlers(loaders) should derive from...
virtual ossim_uint32 getNumberOfDecimationLevels() const
This returns the total number of decimation levels.
virtual ossimRefPtr< ossimImageData > getTile(const ossimIrect &rect, ossim_uint32 resLevel)
Fills the requested tile by pulling pixels from multiple file tiles as needed.
virtual void loadTile(const void *src, const ossimIrect &src_rect, ossimInterleaveType il_type)
virtual ossim_uint32 getNumberOfInputBands() const
virtual ~ossimTiledImageHandler()
Destructor:
virtual bool open()=0
const char * findPreference(const char *key) const
*virtual void close()
Deletes the overview and clears the valid image vertices.
virtual ossimDataObjectStatus validate() const
bool exists() const
virtual bool setInputSource(ossimImageHandler *imageSource)
Sets the input to the builder.
unsigned int ossim_uint32
virtual ossim_uint32 getImageTileHeight() const
Returns the tile height of the image or 0 if the image is not tiled.
virtual bool isOpen() const
Derived classes must implement this method to be concrete.
virtual bool isImageTiled() const
Indicates whether or not the image is tiled internally.
ossimTiledImageHandler()
Constructor (default):
ossim_uint32 width() const
Definition: ossimIrect.h:500
ossimIrect clipToRect(const ossimIrect &rect) const
Definition: ossimIrect.cpp:501
virtual bool openValidVertices()
Creates vertices file name based on image, then tries to open.
static ossimPreferences * instance()
ossimScalarType
virtual ossimScalarType getOutputScalarType() const
Returns scalar type of first tile (should be the same for all tiles)
#define USING_SUB_OVRS
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
Method to save the state of an object to a keyword list.
virtual void makeBlank()
Initializes data to null pixel values.
virtual void completeOpen()
Will complete the opening process.
if(yy_init)
ossimRefPtr< ossimImageHandler > theOverview
void set_lr(const ossimIpt &pt)
Definition: ossimIrect.h:623
This class defines an abstract Handler which all image handlers(loaders) should derive from...
double x
Definition: ossimDpt.h:164
bool empty() const
Definition: ossimString.h:411
ossimFilename theOverviewFile
bool hasNans() const
Definition: ossimIrect.h:337
vector< ossimTileFile > m_tileFiles
virtual bool hasOverviews() const
virtual ossimIrect getBoundingRect(ossim_uint32 resLevel=0) const
Returns zero-based bounding rectangle of the image.
#define RTTI_DEF1(cls, name, b1)
Definition: ossimRtti.h:485
bool buildOverview(const ossimFilename &overview_file, bool copy_all=false)
Builds overview file and sets "theOutputFile" to that of the overview_file.
static const char * OVERVIEW_STOP_DIMENSION_KW
ossimFilename & setExtension(const ossimString &e)
Sets the extension of a file name.
virtual ossim_uint32 getNumberOfLines(ossim_uint32 resLevel=0) const
ossimFilename getFilenameWithThisExtension(const ossimString &ext, bool set_e0_prefix=false) const
Returns the image file with extension set using supplentary directory for dirname if set...
ossimRefPtr< ossimImageData > m_tile
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
Method to save the state of an object to a keyword list.
virtual ossimRefPtr< ossimImageData > getTile(const ossimIpt &origin, ossim_uint32 resLevel=0)