1 //*******************************************************************
2 //
3 // License: MIT
4 //
5 // Author: Garrett Potts
6 //
7 // Description:
8 //
9 // Contains class declaration for ossimBandSelector.
10 //
11 //*******************************************************************
12 // $Id$
13
14 #include <ossim/imaging/ossimBandSelector.h>
15 #include <ossim/base/ossimTrace.h>
16 #include <ossim/base/ossimKeywordlist.h>
17 #include <ossim/base/ossimKeywordNames.h>
18 #include <ossim/base/ossimNotifyContext.h>
19 #include <ossim/base/ossimVisitor.h>
20 #include <ossim/imaging/ossimImageDataFactory.h>
21 #include <ossim/imaging/ossimImageHandler.h>
22 #include <ossim/base/ossimStringProperty.h>
23 #include <iostream>
24 #include <algorithm>
25
26 static ossimTrace traceDebug("ossimBandSelector:debug");
27
28 RTTI_DEF1(ossimBandSelector,"ossimBandSelector", ossimImageSourceFilter)
29
30 using namespace std;
31
ossimBandSelector()32 ossimBandSelector::ossimBandSelector()
33 :
34 ossimImageSourceFilter(),
35 m_tile(0),
36 m_outputBandList(0),
37 m_withinRangeFlag(ossimBandSelectorWithinRangeFlagState_NOT_SET),
38 m_passThroughFlag(false),
39 m_delayLoadRgbFlag(false),
40 m_inputIsSelectable(false)
41 {
42 // theEnableFlag = false; // Start off disabled.
43 theEnableFlag = true;
44 }
45
~ossimBandSelector()46 ossimBandSelector::~ossimBandSelector()
47 {
48 m_tile = 0;
49 }
50
getTile(const ossimIrect & tileRect,ossim_uint32 resLevel)51 ossimRefPtr<ossimImageData> ossimBandSelector::getTile(
52 const ossimIrect& tileRect,
53 ossim_uint32 resLevel)
54 {
55 if (!theInputConnection)
56 {
57 return ossimRefPtr<ossimImageData>();
58 }
59
60 // Get the tile from the source.
61 ossimRefPtr<ossimImageData> t = theInputConnection->getTile(tileRect, resLevel);
62
63
64 if (!isSourceEnabled()||m_passThroughFlag)
65 {
66 return t; // This tile source bypassed, return the input tile source.
67 }
68
69 if(!m_tile.valid()) // First time through, might not be initialized...
70 {
71 allocate();
72 if (!m_tile.valid())
73 {
74 // Should never happen...
75 return t; // initialize failed.
76 }
77 }
78
79 m_tile->setImageRectangle(tileRect);
80 if(m_withinRangeFlag == ossimBandSelectorWithinRangeFlagState_NOT_SET)
81 {
82 m_withinRangeFlag = ((outputBandsWithinInputRange() == true) ?
83 ossimBandSelectorWithinRangeFlagState_IN_RANGE:
84 ossimBandSelectorWithinRangeFlagState_OUT_OF_RANGE);
85 }
86 if(m_withinRangeFlag == ossimBandSelectorWithinRangeFlagState_OUT_OF_RANGE)
87 {
88 m_tile->makeBlank();
89 return m_tile;
90 }
91
92 if ( !t.valid() ||
93 (t->getDataObjectStatus() == OSSIM_EMPTY) ||
94 (t->getDataObjectStatus() == OSSIM_NULL))
95 {
96 //---
97 // Since we're enabled, we must return our tile not "t" so the
98 // correct number of bands goes through the chain.
99 //---
100 m_tile->makeBlank();
101 return m_tile;
102 }
103
104 // Copy selected bands to our tile.
105 for ( ossim_uint32 i = 0; i < m_outputBandList.size(); ++i)
106 {
107 m_tile->assignBand(t.get(), m_outputBandList[i], i);
108 }
109
110 m_tile->validate();
111
112 return m_tile;
113 }
114
setThreeBandRgb()115 void ossimBandSelector::setThreeBandRgb()
116 {
117 m_outputBandList.clear();
118 m_delayLoadRgbFlag = true;
119 initialize();
120 }
121
setOutputBandList(const vector<ossim_uint32> & outputBandList,bool disablePassThru)122 void ossimBandSelector::setOutputBandList( const vector<ossim_uint32>& outputBandList,
123 bool disablePassThru)
124 {
125 if ( outputBandList.size() )
126 {
127 m_outputBandList = outputBandList; // Assign the new list.
128 m_passThroughFlag = false; // Assume no pass thru first
129 if ( !disablePassThru )
130 {
131 bool setBands = false;
132 ossimRefPtr<ossimImageHandler> ih = getBandSelectableImageHandler();
133 if ( ih.valid() )
134 {
135 // Our input is a single image chain that can do band selection.
136 if ( ih->setOutputBandList( outputBandList ) )
137 {
138 m_passThroughFlag = true;
139 setBands = true;
140 m_tile = 0; // Don't need.
141 }
142 }
143
144 if ( setBands == false )
145 {
146 if ( m_tile.valid() )
147 {
148 // Check the tile band size and scalar.
149 if ( ( m_tile->getNumberOfBands() != outputBandList.size() ) ||
150 ( m_tile->getScalarType() != theInputConnection->getOutputScalarType() ) )
151 {
152 m_tile = 0; // Force an allocate call next getTile.
153 }
154 }
155 m_withinRangeFlag = ossimBandSelectorWithinRangeFlagState_NOT_SET;
156 checkPassThrough();
157 //theOrderedCorrectlyFlag = isOrderedCorrectly();
158 }
159 }
160 }
161 }
162
getNumberOfOutputBands() const163 ossim_uint32 ossimBandSelector::getNumberOfOutputBands() const
164 {
165 ossim_uint32 bands;
166
167 if(isSourceEnabled())
168 {
169 bands = static_cast<ossim_uint32>(m_outputBandList.size());
170 }
171 else
172 {
173 //---
174 // Note:
175 // This returns theInputConnection->getNumberOfOutputBands() which is our
176 // input. Calling ossimBandSelector::getNumberOfInputBands() will produce
177 // an error if we are bypassed due to a band selectable image handler.
178 //---
179 bands = ossimImageSourceFilter::getNumberOfInputBands();
180 }
181
182 return bands;
183 }
184
getNumberOfInputBands() const185 ossim_uint32 ossimBandSelector::getNumberOfInputBands() const
186 {
187 ossim_uint32 bands;
188
189 // See if we have a single image chain with band selectable image handler.
190 ossimRefPtr<ossimImageHandler> ih = getBandSelectableImageHandler();
191 if ( ih.valid() )
192 {
193 bands = ih->getNumberOfInputBands();
194 }
195 else
196 {
197 bands = ossimImageSourceFilter::getNumberOfInputBands();
198 }
199
200 return bands;
201 }
202
203
initialize()204 void ossimBandSelector::initialize()
205 {
206 if(traceDebug())
207 {
208 ossimNotify(ossimNotifyLevel_WARN) << "ossimBandSelector::initialize() entered...\n";
209 }
210
211 // Base class will recapture "theInputConnection".
212 ossimImageSourceFilter::initialize();
213
214 m_withinRangeFlag = ossimBandSelectorWithinRangeFlagState_NOT_SET;
215
216 if(theInputConnection)
217 {
218 if ( !m_outputBandList.size() )
219 {
220 // First time through...
221 if ( m_delayLoadRgbFlag )
222 {
223 //---
224 // "bands" key was set to "rgb" or "default" in loadState but there
225 // was not a connection to derive rgb bands from image handler.
226 //---
227 if ( getRgbBandList( m_outputBandList ) == false )
228 {
229 //---
230 // Could not derive from input. Assuming caller wanted three bands.
231 // Call to checkPassThrough()->outputBandsWithinInputRange()
232 // will check the range of output band list.
233 //---
234 if( theInputConnection->getNumberOfOutputBands() > 2 )
235 {
236 m_outputBandList.resize(3);
237 m_outputBandList[0] = 0;
238 m_outputBandList[1] = 1;
239 m_outputBandList[2] = 2;
240 }
241 else
242 {
243 m_outputBandList.resize(1);
244 m_outputBandList[0] = 0;
245 }
246 }
247
248 m_delayLoadRgbFlag = false; // clear flag.
249 }
250
251 if ( !m_outputBandList.size() )
252 {
253 // Set the output band list to input if not set above.
254 theInputConnection->getOutputBandList( m_outputBandList );
255 }
256
257 if( m_outputBandList.size() )
258 {
259 // Call to setOutputBandList configures band selector.
260 setOutputBandList(m_outputBandList);
261 }
262
263 } // if ( !m_outputBandList.size() )
264
265 } // if(theInputConnection)
266
267 if ( !isSourceEnabled() )
268 {
269 m_tile = 0;
270 }
271
272 if(traceDebug())
273 {
274 ossimNotify(ossimNotifyLevel_WARN) << "ossimBandSelector::initialize() exited...\n";
275 }
276 }
277
allocate()278 void ossimBandSelector::allocate()
279 {
280 //initialize(); // Update the connection.
281 //theOrderedCorrectlyFlag = isOrderedCorrectly();
282 m_tile = ossimImageDataFactory::instance()->create(this, this);
283 m_tile->initialize();
284 }
285
isSourceEnabled() const286 bool ossimBandSelector::isSourceEnabled()const
287 {
288 bool result = ossimImageSourceFilter::isSourceEnabled();
289 if(result)
290 {
291 // if I am not marked to pass information on through then enable me
292 result = !m_passThroughFlag;
293 }
294
295 return result;
296 }
297
getMinPixelValue(ossim_uint32 band) const298 double ossimBandSelector::getMinPixelValue(ossim_uint32 band)const
299 {
300 if(theInputConnection)
301 {
302 if (isSourceEnabled())
303 {
304 if(band < m_outputBandList.size())
305 {
306 return theInputConnection->
307 getMinPixelValue(m_outputBandList[band]);
308 }
309 else
310 {
311 return theInputConnection->getMinPixelValue(band);
312 }
313 }
314 else
315 {
316 return theInputConnection->getMinPixelValue(band);
317 }
318 }
319 return 0;
320 }
321
getNullPixelValue(ossim_uint32 band) const322 double ossimBandSelector::getNullPixelValue(ossim_uint32 band)const
323 {
324 if(theInputConnection)
325 {
326 if (isSourceEnabled())
327 {
328 if(band < m_outputBandList.size())
329 {
330 return theInputConnection->
331 getNullPixelValue(m_outputBandList[band]);
332 }
333 else
334 {
335 return theInputConnection->getNullPixelValue(band);
336 }
337 }
338 else
339 {
340 return theInputConnection->getNullPixelValue(band);
341 }
342 }
343
344 return 0;
345 }
346
getMaxPixelValue(ossim_uint32 band) const347 double ossimBandSelector::getMaxPixelValue(ossim_uint32 band)const
348 {
349 if(theInputConnection)
350 {
351 if (isSourceEnabled())
352 {
353 if(band < m_outputBandList.size())
354 {
355 return theInputConnection->
356 getMaxPixelValue(m_outputBandList[band]);
357 }
358 else
359 {
360 return theInputConnection->getMaxPixelValue(band);
361 }
362 }
363 else
364 {
365 return theInputConnection->getMaxPixelValue(band);
366 }
367 }
368 return 1.0/DBL_EPSILON;
369 }
370
saveState(ossimKeywordlist & kwl,const char * prefix) const371 bool ossimBandSelector::saveState(ossimKeywordlist& kwl,
372 const char* prefix)const
373 {
374 ossimString temp;
375
376 kwl.add(prefix,
377 ossimKeywordNames::NUMBER_OUTPUT_BANDS_KW,
378 static_cast<int>(m_outputBandList.size()),
379 true);
380
381 ossimString bandsString;
382 ossim::toSimpleStringList(bandsString,
383 m_outputBandList);
384 kwl.add(prefix,
385 ossimKeywordNames::BANDS_KW,
386 bandsString,
387 true);
388 /*
389 for(ossim_uint32 counter = 0; counter < m_outputBandList.size();counter++)
390 {
391 temp = ossimKeywordNames::BAND_KW;
392 temp += ossimString::toString(counter+1);
393
394 kwl.add(prefix,
395 temp.c_str(),
396 ossimString::toString(m_outputBandList[counter]+1).c_str());
397 }
398 */
399 return ossimImageSourceFilter::saveState(kwl, prefix);
400 }
401
loadState(const ossimKeywordlist & kwl,const char * prefix)402 bool ossimBandSelector::loadState(const ossimKeywordlist& kwl,
403 const char* prefix)
404 {
405 bool result = false;
406
407 ossimImageSourceFilter::loadState(kwl, prefix);
408
409 m_outputBandList.clear();
410
411 ossimString copyPrefix = prefix;
412
413 ossimString bands = kwl.find(prefix, ossimKeywordNames::BANDS_KW);
414 if(!bands.empty())
415 {
416 ossimString bs = bands;
417 bs.downcase();
418 if ( (bs == "rgb" ) || (bs == "default"))
419 {
420 // Flag initialize() to set the band list on first connection.
421 m_delayLoadRgbFlag = true;
422 }
423 else
424 {
425 // Load from key:value, e.g. bands:(2,1,0)
426 ossim::toSimpleVector(m_outputBandList, bands);
427 result = true;
428 }
429 }
430 else
431 {
432 ossimString regExpression = ossimString("^(") + copyPrefix + "band[0-9]+)";
433
434 vector<ossimString> keys = kwl.getSubstringKeyList( regExpression );
435 long numberOfBands = (long)keys.size();
436 ossim_uint32 offset = (ossim_uint32)(copyPrefix+"band").size();
437 std::vector<int>::size_type idx = 0;
438 std::vector<int> numberList(numberOfBands);
439 for(idx = 0; idx < keys.size();++idx)
440 {
441 ossimString numberStr(keys[idx].begin() + offset,
442 keys[idx].end());
443 numberList[idx] = numberStr.toInt();
444 }
445 std::sort(numberList.begin(), numberList.end());
446 for(idx=0;idx < numberList.size();++idx)
447 {
448 const char* bandValue =
449 kwl.find(copyPrefix,
450 ("band"+ossimString::toString(numberList[idx])).c_str());
451 m_outputBandList.push_back( ossimString(bandValue).toLong()-1);
452 }
453 result = true;
454 }
455
456 initialize();
457
458 return result;
459 }
460
checkPassThrough()461 void ossimBandSelector::checkPassThrough()
462 {
463 m_passThroughFlag = ((theInputConnection == 0)||!outputBandsWithinInputRange());
464
465 // check if marked with improper bands
466 if(m_passThroughFlag)
467 return;
468
469 if(theInputConnection)
470 {
471 std::vector<ossim_uint32> inputList;
472 theInputConnection->getOutputBandList(inputList);
473
474 if ( inputList.size() == m_outputBandList.size() )
475 {
476 const std::vector<ossim_uint32>::size_type SIZE = m_outputBandList.size();
477
478 std::vector<ossim_uint32>::size_type i = 0;
479 while (i < SIZE)
480 {
481 if ( inputList[i] != m_outputBandList[i] )
482 {
483 break;
484 }
485 ++i;
486 }
487 if (i == SIZE)
488 {
489 m_passThroughFlag = true;
490 }
491 }
492 }
493 else
494 {
495 if(traceDebug())
496 {
497 ossimNotify(ossimNotifyLevel_WARN) << "ossimBandSelector::isOrderedCorrectly() ERROR: "
498 "Method called prior to initialization!\n";
499 }
500 }
501
502 }
503
outputBandsWithinInputRange() const504 bool ossimBandSelector::outputBandsWithinInputRange() const
505 {
506 bool result = false;
507
508 if(theInputConnection)
509 {
510 result = true;
511 const ossim_uint32 HIGHEST_BAND = getNumberOfInputBands() - 1;
512 const ossim_uint32 OUTPUT_BANDS = (ossim_uint32)m_outputBandList.size();
513 for (ossim_uint32 i=0; i<OUTPUT_BANDS; ++i)
514 {
515 if (m_outputBandList[i] > HIGHEST_BAND)
516 {
517 if(traceDebug())
518 {
519 ossimNotify(ossimNotifyLevel_WARN)
520 << "ossimBandSelector::outputBandsWithinInputRange() ERROR:"
521 << "Output band greater than highest input band. "
522 << m_outputBandList[i] << " > " << HIGHEST_BAND << "."
523 << std::endl;
524 }
525 result = false;
526 break;
527 }
528 }
529 }
530 else
531 {
532 if(traceDebug())
533 {
534 ossimNotify(ossimNotifyLevel_WARN)
535 << "ossimBandSelector::outputBandsWithinInputRange() ERROR:"
536 << "Method called prior to initialization!" << std::endl;
537 }
538 }
539 return result;
540 }
541
getOutputBandList(std::vector<ossim_uint32> & bandList) const542 void ossimBandSelector::getOutputBandList(std::vector<ossim_uint32>& bandList) const
543 {
544 if ( isSourceEnabled()&&m_outputBandList.size() )
545 {
546 bandList = m_outputBandList;
547 }
548 else if (theInputConnection)
549 {
550 theInputConnection->getOutputBandList(bandList);
551 }
552 else
553 {
554 bandList.clear();
555 }
556 }
557
getLongName() const558 ossimString ossimBandSelector::getLongName()const
559 {
560 return ossimString("Band Selector, maps an input band to the output band.");
561 }
562
getShortName() const563 ossimString ossimBandSelector::getShortName()const
564 {
565 return ossimString("Band Selector");
566 }
567
setProperty(ossimRefPtr<ossimProperty> property)568 void ossimBandSelector::setProperty(ossimRefPtr<ossimProperty> property)
569 {
570 if( property.valid() )
571 {
572 if(property->getName() == "bands")
573 {
574 std::vector<ossim_uint32> selection;
575 if(ossim::toSimpleVector(selection, property->valueToString()))
576 {
577 m_outputBandList = selection;
578 setOutputBandList( m_outputBandList );
579 }
580 }
581 else if(property->getName() == "bandSelection")
582 {
583 ossimString str = property->valueToString();
584 std::vector<ossimString> str_vec;
585 std::vector<ossim_uint32> int_vec;
586
587 str.split( str_vec, " " );
588
589 for ( ossim_uint32 i = 0; i < str_vec.size(); ++i )
590 {
591 if(!str_vec[i].empty())
592 {
593 int_vec.push_back( str_vec[i].toUInt32() );
594 }
595 }
596 setOutputBandList( int_vec );
597 }
598 else
599 {
600 ossimImageSourceFilter::setProperty(property);
601 }
602 }
603 }
604
getProperty(const ossimString & name) const605 ossimRefPtr<ossimProperty> ossimBandSelector::getProperty(const ossimString& name)const
606 {
607 if( name == "bands" )
608 {
609 ossimString bandsString;
610 ossim::toSimpleStringList(bandsString,
611 m_outputBandList);
612 ossimStringProperty* stringProp = new ossimStringProperty(name, bandsString);
613
614 stringProp->clearChangeType();
615 stringProp->setReadOnlyFlag(false);
616 stringProp->setCacheRefreshBit();
617
618 return stringProp;
619 }
620 else if( name == "bandSelection" )
621 {
622 std::vector<ossim_uint32> bands;
623
624 getOutputBandList( bands );
625
626 std::vector<ossimString> bandNames;
627
628 for(ossim_uint32 i = 0; i < bands.size(); i++)
629 {
630 bandNames.push_back( ossimString::toString( bands[i] ) );
631 }
632
633 ossimString str;
634
635 str.join( bandNames, " " );
636
637 ossimStringProperty* stringProp = new ossimStringProperty(name, str);
638
639 stringProp->clearChangeType();
640 stringProp->setReadOnlyFlag(false);
641 stringProp->setCacheRefreshBit();
642
643 return stringProp;
644 }
645
646 return ossimImageSourceFilter::getProperty(name);
647 }
648
getPropertyNames(std::vector<ossimString> & propertyNames) const649 void ossimBandSelector::getPropertyNames(std::vector<ossimString>& propertyNames)const
650 {
651 ossimImageSourceFilter::getPropertyNames(propertyNames);
652 propertyNames.push_back("bands");
653 }
654
getBandSelectableImageHandler() const655 ossimRefPtr<ossimImageHandler> ossimBandSelector::getBandSelectableImageHandler() const
656 {
657 ossimRefPtr<ossimImageHandler> ih = 0;
658
659 if ( theInputConnection )
660 {
661 /**
662 * GP: We will only allow the immediate input check for an image handler
663 * and if one is present then check if selectable
664 */
665 ossimTypeNameVisitor visitor(ossimString("ossimImageHandler"),
666 true,
667 ossimVisitor::VISIT_CHILDREN|ossimVisitor::VISIT_INPUTS);
668 ossimTypeNameVisitor bandSelectorVisitor(ossimString("ossimBandSelector"),
669 true,
670 ossimVisitor::VISIT_CHILDREN|ossimVisitor::VISIT_INPUTS);
671
672 theInputConnection->accept(visitor);
673 theInputConnection->accept(bandSelectorVisitor);
674 // if there is a band selector before us then do not
675 // set the image handler
676 if(bandSelectorVisitor.getObjects().size() < 1)
677 {
678 // If there are multiple image handlers, e.g. a mosaic do not uses.
679 if ( visitor.getObjects().size() == 1 )
680 {
681 ih = visitor.getObjectAs<ossimImageHandler>( 0 );
682 if ( ih.valid() )
683 {
684 if ( ih->isBandSelector() == false )
685 {
686 ih = 0;
687 }
688 }
689 }
690
691 }
692
693 } // Matches: if ( theInputConnection )
694 return ih;
695
696 } // End: ossimBandSelector::getBandSelectableImageHandler()
697
getRgbBandList(std::vector<ossim_uint32> & bandList) const698 bool ossimBandSelector::getRgbBandList(std::vector<ossim_uint32>& bandList) const
699 {
700 bool result = false;
701
702 if ( theInputConnection )
703 {
704 ossimTypeNameVisitor visitor(ossimString("ossimImageHandler"),
705 true,
706 ossimVisitor::VISIT_CHILDREN|ossimVisitor::VISIT_INPUTS);
707
708 theInputConnection->accept(visitor);
709
710 // If there are multiple image handlers, e.g. a mosaic do not uses.
711 if ( visitor.getObjects().size() == 1 )
712 {
713 ossimRefPtr<ossimImageHandler> ih = visitor.getObjectAs<ossimImageHandler>( 0 );
714 if ( ih.valid() )
715 {
716 result = ih->getRgbBandList( bandList );
717 }
718 }
719
720 } // Matches: if ( theInputConnection )
721
722 return result;
723
724 } // End: ossimBandSelector::getRgbBandList( ... )
725