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