1 //*******************************************************************
2 // Copyright (C) 2005 SANZ Inc.
3 //
4 // License:  LGPL
5 //
6 // See LICENSE.txt file in the top level directory for more details.
7 //
8 // Author: Kenneth Melero (kmelero@sanz.com)
9 //
10 // Description: This combiner is designed to "float" the maximum pixel value
11 //              of all inputs to top of the mosaic output.
12 //
13 //*************************************************************************
14 // $Id: ossimMaxMosaic.cpp 23257 2015-04-13 16:57:14Z dburken $
15 
16 #include <ossim/imaging/ossimMaxMosaic.h>
17 #include <ossim/imaging/ossimImageData.h>
18 #include <ossim/imaging/ossimImageDataFactory.h>
19 #include <ossim/base/ossimTrace.h>
20 
21 static const ossimTrace traceDebug("ossimMaxMosaic:debug");
22 
23 using namespace std;
24 
25 RTTI_DEF1(ossimMaxMosaic, "ossimMaxMosaic", ossimImageCombiner)
ossimMaxMosaic()26 ossimMaxMosaic::ossimMaxMosaic()
27    :ossimImageCombiner(),
28     theTile(NULL)
29 {
30 }
31 
ossimMaxMosaic(ossimConnectableObject::ConnectableObjectList & inputSources)32 ossimMaxMosaic::ossimMaxMosaic(ossimConnectableObject::ConnectableObjectList& inputSources)
33     : ossimImageCombiner(inputSources),
34       theTile(NULL)
35 {
36 }
37 
38 
~ossimMaxMosaic()39 ossimMaxMosaic::~ossimMaxMosaic()
40 {
41 }
42 
getTile(const ossimIrect & tileRect,ossim_uint32 resLevel)43 ossimRefPtr<ossimImageData> ossimMaxMosaic::getTile(
44    const ossimIrect& tileRect,
45    ossim_uint32 resLevel)
46 {
47    long size = getNumberOfInputs();
48    ossim_uint32 layerIdx = 0;
49    // If there is only one in the mosaic then just return it.
50    if(size == 1)
51    {
52       return getNextTile(layerIdx, 0, tileRect, resLevel);
53    }
54 
55    ossimIpt origin = tileRect.ul();
56    ossim_uint32 w = tileRect.width();
57    ossim_uint32 h = tileRect.height();
58 
59    if(!theTile.valid())
60    {
61       // First time through...
62       allocate();
63 
64       // If we still don't have a buffer then we will leave.
65       if(!theTile.valid())
66       {
67          return ossimRefPtr<ossimImageData>();
68       }
69    }
70 
71    ossim_uint32 tileW = theTile->getWidth();
72    ossim_uint32 tileH = theTile->getHeight();
73    if((w != tileW)||
74       (h != tileH))
75    {
76       theTile->setWidth(w);
77       theTile->setHeight(h);
78       if((w*h)!=(tileW*tileH))
79       {
80          theTile->initialize();
81       }
82    }
83    theTile->setOrigin(origin);
84 
85    //---
86    // General Note:
87    //
88    // Note: I will not check for disabled or enabled since we have
89    // no clear way to handle this within a mosaic. The default will be
90    // to do a simple a A over B type mosaic.  Derived classes should
91    // check for the enabled and disabled and always
92    // use this default implementation if they are disabled.
93    //---
94    theTile->setOrigin(origin);
95    theTile->makeBlank();
96    switch(theTile->getScalarType())
97    {
98       case OSSIM_UCHAR:
99       {
100          if(!hasDifferentInputs())
101          {
102             return combine(static_cast<ossim_uint8>(0),
103                            tileRect,
104                            resLevel);
105          }
106          else
107          {
108             return combineNorm(static_cast<ossim_uint8>(0),
109                                tileRect,
110                                resLevel);
111          }
112       }
113       case OSSIM_SINT8:
114       {
115          if(!hasDifferentInputs())
116          {
117             return combine(static_cast<ossim_sint8>(0),
118                            tileRect,
119                            resLevel);
120          }
121          else
122          {
123             return combineNorm(static_cast<ossim_sint8>(0),
124                                tileRect,
125                                resLevel);
126          }
127       }
128       case OSSIM_FLOAT:
129       case OSSIM_NORMALIZED_FLOAT:
130       {
131          if(!hasDifferentInputs())
132          {
133             return combine(static_cast<float>(0),
134                            tileRect,
135                            resLevel);
136          }
137          else
138          {
139             return combineNorm(static_cast<float>(0),
140                                tileRect,
141                                resLevel);
142          }
143       }
144       case OSSIM_USHORT16:
145       case OSSIM_USHORT11:
146       case OSSIM_USHORT12:
147       case OSSIM_USHORT13:
148       case OSSIM_USHORT14:
149       case OSSIM_USHORT15:
150       {
151          if(!hasDifferentInputs())
152          {
153             return combine(static_cast<ossim_uint16>(0),
154                            tileRect,
155                            resLevel);
156          }
157          else
158          {
159             return combineNorm(static_cast<ossim_uint16>(0),
160                                tileRect,
161                                resLevel);
162          }
163       }
164       case OSSIM_SSHORT16:
165       {
166          if(!hasDifferentInputs())
167          {
168             return combine(static_cast<ossim_sint16>(0),
169                            tileRect,
170                            resLevel);
171          }
172          else
173          {
174             return combineNorm(static_cast<ossim_sint16>(0),
175                                tileRect,
176                                resLevel);
177          }
178       }
179       case OSSIM_SINT32:
180       {
181          if(!hasDifferentInputs())
182          {
183             return combine(static_cast<ossim_sint32>(0),
184                            tileRect,
185                            resLevel);
186          }
187          else
188          {
189             return combineNorm(static_cast<ossim_sint32>(0),
190                                tileRect,
191                                resLevel);
192          }
193       }
194       case OSSIM_UINT32:
195       {
196          if(!hasDifferentInputs())
197          {
198             return combine(static_cast<ossim_uint32>(0),
199                            tileRect,
200                            resLevel);
201          }
202          else
203          {
204             return combineNorm(static_cast<ossim_uint32>(0),
205                                tileRect,
206                                resLevel);
207          }
208       }
209       case OSSIM_DOUBLE:
210       case OSSIM_NORMALIZED_DOUBLE:
211       {
212          if(!hasDifferentInputs())
213          {
214             return combine(static_cast<double>(0),
215                            tileRect,
216                            resLevel);
217          }
218          else
219          {
220             return combineNorm(static_cast<double>(0),
221                                tileRect,
222                                resLevel);
223          }
224       }
225       case OSSIM_SCALAR_UNKNOWN:
226       default:
227       {
228          ossimNotify(ossimNotifyLevel_WARN)
229             << "Scalar type = " << theTile->getScalarType()
230             << " Not supported by ossimMaxMosaic" << endl;
231       }
232    }
233 
234    return ossimRefPtr<ossimImageData>();
235 }
236 
initialize()237 void ossimMaxMosaic::initialize()
238 {
239   ossimImageCombiner::initialize();
240   theTile = NULL;
241 }
242 
allocate()243 void ossimMaxMosaic::allocate()
244 {
245    theTile = NULL;
246 
247    if( (getNumberOfInputs() > 0) && getInput(0) )
248    {
249       theTile = ossimImageDataFactory::instance()->create(this, this);
250       theTile->initialize();
251    }
252 }
253 
saveState(ossimKeywordlist & kwl,const char * prefix) const254 bool ossimMaxMosaic::saveState(ossimKeywordlist& kwl,
255                                  const char* prefix)const
256 {
257    return ossimImageCombiner::saveState(kwl, prefix);
258 }
259 
loadState(const ossimKeywordlist & kwl,const char * prefix)260 bool ossimMaxMosaic::loadState(const ossimKeywordlist& kwl,
261                                  const char* prefix)
262 {
263    return ossimImageCombiner::loadState(kwl, prefix);
264 }
265 
combineNorm(T,const ossimIrect & tileRect,ossim_uint32 resLevel)266 template <class T> ossimRefPtr<ossimImageData> ossimMaxMosaic::combineNorm(
267    T,// dummy template variable
268    const ossimIrect& tileRect,
269    ossim_uint32 resLevel)
270 {
271    ossim_uint32 layerIdx = 0;
272    ossimRefPtr<ossimImageData> destination = theTile;
273 
274    ossimRefPtr<ossimImageData> currentImageData =
275       getNextNormTile(layerIdx, 0, tileRect, resLevel);
276 
277    if(!currentImageData)
278    {
279       return currentImageData;
280    }
281 
282    std::vector<float*> srcBands(theLargestNumberOfInputBands);
283    std::vector<float> srcBandsNullPix(theLargestNumberOfInputBands);
284    std::vector<T*> destBands(theLargestNumberOfInputBands);
285    std::vector<T> destBandsNullPix(theLargestNumberOfInputBands);
286    std::vector<T> destBandsMinPix(theLargestNumberOfInputBands);
287    std::vector<T> destBandsMaxPix(theLargestNumberOfInputBands);
288    //float** srcBands        = new float*[theLargestNumberOfInputBands];
289    //float* srcBandsNullPix  = new float[theLargestNumberOfInputBands];
290    //T** destBands = new T*[theLargestNumberOfInputBands];
291    //T* destBandsNullPix = new T[theLargestNumberOfInputBands];
292    //T* destBandsMinPix = new T[theLargestNumberOfInputBands];
293    //T* destBandsMaxPix = new T[theLargestNumberOfInputBands];
294 
295    ossim_uint32 band;
296    ossim_uint32 upperBound = destination->getWidth()*destination->getHeight();
297    ossim_uint32 minNumberOfBands = currentImageData->getNumberOfBands();
298    for(band = 0; band < minNumberOfBands; ++band)
299    {
300       srcBands[band]  = static_cast<float*>(currentImageData->getBuf(band));
301       srcBandsNullPix[band]  = static_cast<float>(currentImageData->getNullPix(band));
302 
303       destBands[band] = static_cast<T*>(theTile->getBuf(band));
304       destBandsNullPix[band] = static_cast<T>(theTile->getNullPix(band));
305       destBandsMinPix[band] = static_cast<T>(theTile->getMinPix(band));
306       destBandsMaxPix[band] = static_cast<T>(theTile->getMaxPix(band));
307    }
308    // if the src is smaller than the destination in number
309    // of bands we will just duplicate the last band.
310    for(;band < theLargestNumberOfInputBands; ++band)
311    {
312       srcBands[band]  = static_cast<float*>(srcBands[minNumberOfBands - 1]);
313       srcBandsNullPix[band] = static_cast<float>(currentImageData->getNullPix(minNumberOfBands - 1));
314 
315       destBands[band] = static_cast<T*>(theTile->getBuf(band));
316       destBandsNullPix[band] = static_cast<T>(theTile->getNullPix(band));
317       destBandsMinPix[band] = static_cast<T>(theTile->getMinPix(band));
318       destBandsMaxPix[band] = static_cast<T>(theTile->getMaxPix(band));
319    }
320    // most of the time we will not overlap so let's
321    // copy the first tile into destination and check later.
322    //
323    ossim_uint32 tempBandIdx = 0;
324    for(band = 0; band < theTile->getNumberOfBands();++band)
325    {
326       if(band < currentImageData->getNumberOfBands())
327       {
328          theTile->copyNormalizedBufferToTile(band,
329                                              (float*)currentImageData->getBuf(band));
330          ++tempBandIdx;
331       }
332       else
333       {
334          if(tempBandIdx)
335          {
336             theTile->copyNormalizedBufferToTile(band,
337                                                 (float*)currentImageData->getBuf(tempBandIdx-1));
338          }
339       }
340    }
341    destination->validate();
342 
343    currentImageData = getNextNormTile(layerIdx, tileRect, resLevel);
344 
345    while(currentImageData.valid())
346    {
347       ossim_uint32 minNumberOfBands           = currentImageData->getNumberOfBands();
348       ossimDataObjectStatus currentStatus     = currentImageData->getDataObjectStatus();
349       ossimDataObjectStatus destinationStatus = destination->getDataObjectStatus();
350 
351       if(destinationStatus == OSSIM_FULL)
352       {
353          return destination;
354       }
355       for(band = 0; band < minNumberOfBands; ++band)
356       {
357          srcBands[band]        = static_cast<float*>(currentImageData->getBuf(band));
358          srcBandsNullPix[band] = static_cast<float>(currentImageData->getNullPix(band));
359       }
360       // if the src is smaller than the destination in number
361       // of bands we will just duplicate the last band.
362       for(;band < theLargestNumberOfInputBands; ++band)
363       {
364          srcBands[band] = srcBands[minNumberOfBands - 1];
365          srcBandsNullPix[band] = static_cast<T>(currentImageData->getNullPix(minNumberOfBands - 1));
366       }
367 
368       if((destinationStatus == OSSIM_EMPTY)&&
369          (currentStatus     != OSSIM_EMPTY)&&
370          (currentStatus     != OSSIM_NULL))
371       {
372          ossim_uint32 upperBound = destination->getWidth()*destination->getHeight();
373          for(band=0; band < theLargestNumberOfInputBands; ++band)
374          {
375             float delta = destBandsMaxPix[band] - destBandsMinPix[band];
376             float minP  = destBandsMinPix[band];
377             for(ossim_uint32 offset = 0; offset < upperBound; ++offset)
378             {
379                destBands[band][offset] = (T)( minP + delta*srcBands[band][offset]);
380             }
381          }
382       }
383       else if((destinationStatus == OSSIM_PARTIAL)&&
384               (currentStatus     != OSSIM_EMPTY)&&
385               (currentStatus     != OSSIM_NULL))
386       {
387          for(band = 0; band < theLargestNumberOfInputBands; ++band)
388          {
389 
390             float delta = destBandsMaxPix[band] - destBandsMinPix[band];
391             float minP  = destBandsMinPix[band];
392             for(ossim_uint32 offset = 0;
393                 offset < upperBound;
394                 ++offset)
395             {
396 
397                if(destBands[band][offset] == destBandsNullPix[band])
398                {
399                   destBands[band][offset] = (T)(minP + delta*srcBands[band][offset]);
400                }
401             }
402          }
403       }
404       destination->validate();
405 
406       currentImageData = getNextNormTile(layerIdx, tileRect, resLevel);
407    }
408    // Cleanup...
409   // delete [] srcBands;
410   // delete [] srcBandsNullPix;
411   // delete [] destBands;
412   // delete [] destBandsNullPix;
413   // delete [] destBandsMinPix;
414   // delete [] destBandsMaxPix;
415 
416    return destination;
417 }
418 
combine(T,const ossimIrect & tileRect,ossim_uint32 resLevel)419 template <class T> ossimRefPtr<ossimImageData> ossimMaxMosaic::combine(
420    T,// dummy template variable
421    const ossimIrect& tileRect,
422    ossim_uint32 resLevel)
423 {
424    ossim_uint32 layerIdx = 0;
425    ossimRefPtr<ossimImageData> destination = theTile;
426 
427    ossimRefPtr<ossimImageData> currentImageData = getNextTile(layerIdx, 0, tileRect, resLevel);
428    if(!currentImageData)
429    {
430       return currentImageData;
431    }
432 
433    T** srcBands         = new T*[theLargestNumberOfInputBands];
434    T*  srcBandsNullPix  = new T[theLargestNumberOfInputBands];
435    T** destBands        = new T*[theLargestNumberOfInputBands];
436    T*  destBandsNullPix = new T[theLargestNumberOfInputBands];
437 
438    ossim_uint32 band;
439    ossim_uint32 upperBound = destination->getWidth()*destination->getHeight();
440    ossim_uint32 bandIndex  = 0;
441 
442    ossim_uint32 offset=0;
443    ossim_uint32 minNumberOfBands = currentImageData->getNumberOfBands();
444    for(band = 0; band < minNumberOfBands; ++band)
445    {
446       srcBands[band]  = static_cast<T*>(currentImageData->getBuf(band));
447       destBands[band] = static_cast<T*>(theTile->getBuf(band));
448       srcBandsNullPix[band]  = static_cast<T>(currentImageData->getNullPix(band));
449       destBandsNullPix[band] = static_cast<T>(theTile->getNullPix(band));
450    }
451    // if the src is smaller than the destination in number
452    // of bands we will just duplicate the last band.
453    for(;band < theLargestNumberOfInputBands; ++band)
454    {
455       srcBands[band]  = static_cast<T*>(srcBands[minNumberOfBands - 1]);
456       destBands[band] = static_cast<T*>(theTile->getBuf(band));
457       srcBandsNullPix[band] = static_cast<T>(currentImageData->getNullPix(minNumberOfBands - 1));
458       destBandsNullPix[band] = static_cast<T>(theTile->getNullPix(band));
459    }
460    // most of the time we will not overlap so let's
461    // copy the first tile into destination and check later.
462    //
463    for(band = 0; band < theTile->getNumberOfBands();++band)
464    {
465       T* destBand = destBands[band];
466       T* srcBand  = srcBands[band];
467       if(destBand&&srcBand)
468       {
469          for(offset = 0; offset < upperBound;++offset)
470          {
471             *destBand = *srcBand;
472             ++srcBand; ++destBand;
473          }
474       }
475    }
476    destination->setDataObjectStatus(currentImageData->getDataObjectStatus());
477 
478    currentImageData = getNextTile(layerIdx,
479                                   tileRect,
480                                   resLevel);
481 
482    while(currentImageData.valid())
483    {
484       ossim_uint32 minNumberOfBands           = currentImageData->getNumberOfBands();
485       ossimDataObjectStatus currentStatus     = currentImageData->getDataObjectStatus();
486       ossimDataObjectStatus destinationStatus = destination->getDataObjectStatus();
487 
488       for(band = 0; band < minNumberOfBands; ++band)
489       {
490          srcBands[band]        = static_cast<T*>(currentImageData->getBuf(band));
491          srcBandsNullPix[band] = static_cast<T>(currentImageData->getNullPix(band));
492       }
493       // if the src is smaller than the destination in number
494       // of bands we will just duplicate the last band.
495       for(;band < theLargestNumberOfInputBands; ++band)
496       {
497          srcBands[band] = srcBands[minNumberOfBands - 1];
498          srcBandsNullPix[band] = static_cast<T>(currentImageData->getNullPix(minNumberOfBands - 1));
499       }
500 
501       if((destinationStatus == OSSIM_PARTIAL)&&
502 	 (currentStatus     != OSSIM_EMPTY)&&
503 	 (currentStatus     != OSSIM_NULL))
504       {
505          for(bandIndex = 0; bandIndex < theLargestNumberOfInputBands; ++bandIndex)
506          {
507 
508             for(ossim_uint32 offset = 0;
509                 offset < upperBound;
510                 ++offset)
511             {
512                if(srcBands[bandIndex][offset] > destBands[bandIndex][offset])
513                {
514                   destBands[bandIndex][offset] = srcBands[bandIndex][offset];
515                }
516             }
517          }
518       }
519       else
520       {
521          ossim_uint32 upperBound = destination->getWidth()*destination->getHeight();
522          for(ossim_uint32 band=0; band < theLargestNumberOfInputBands; ++band)
523          {
524             for(ossim_uint32 offset = 0; offset < upperBound; ++offset)
525             {
526                if(srcBands[band][offset] > destBands[band][offset])
527                {
528                   destBands[band][offset] = srcBands[band][offset];
529                }
530             }
531          }
532       }
533 
534       destination->validate();
535 
536       currentImageData = getNextTile(layerIdx,tileRect, resLevel);
537    }
538    // Cleanup...
539    delete [] srcBands;
540    delete [] srcBandsNullPix;
541    delete [] destBands;
542    delete [] destBandsNullPix;
543    return destination;
544 }
545 
getShortName() const546 ossimString ossimMaxMosaic::getShortName()const
547 {
548    return ossimString("ossimMaxMosaic");
549 }
550 
getLongName() const551 ossimString ossimMaxMosaic::getLongName()const
552 {
553    return ossimString("Max Mosaic");
554 }
555 
getDescription() const556 ossimString ossimMaxMosaic::getDescription()const
557 {
558    return ossimString("Combiner which puts maximum dn value on image.");
559 }
560