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