OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimBandLutFilter.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 //*************************************************************************
10 // $Id: ossimBandLutFilter.cpp 23242 2015-04-08 17:31:35Z dburken $
15 #include <ossim/base/ossimCommon.h>
20 
22 
23 static const char* MODE_KW = "mode";
24 static const char* LUT_FILE_KW = "lut_file";
25 
28  theMode(INTERPOLATED),
29  theTile(0),
30  theLutFile(""),
31  theOutputScalarType(OSSIM_SCALAR_UNKNOWN)
32 {
33  setDescription("Look-up-table remapper for band-independent remapping.");
34 }
35 
37 {
38 }
39 
41  ossim_uint32 resLevel)
42 {
43  if(!theInputConnection || (theLut.size() == 0))
44  return 0;
45 
46  ossimRefPtr<ossimImageData> inputTile = theInputConnection->getTile(tileRect, resLevel);
47  if (!inputTile || !inputTile->getBuf())
48  return 0;
49 
50  if(!theTile)
51  {
52  allocate();
53  if (!theTile)
54  return 0;
55  }
56 
57  theTile->setImageRectangle(tileRect);
58  theTile->makeBlank();
59 
60  // Quick handling special case of empty input tile:
61  if (inputTile->getDataObjectStatus() == OSSIM_EMPTY)
62  return theTile;
63 
64  const double null_index = theInputConnection->getNullPixelValue();
65  const double null_value = theTile->getNullPix(0); // assuming same null for all bands
66  ossim_uint32 maxLength = inputTile->getWidth()*inputTile->getHeight();
67 
68  double index, value;
69  double min_value=OSSIM_DEFAULT_MAX_PIX_DOUBLE;
70  double max_value=OSSIM_DEFAULT_MIN_PIX_DOUBLE;
71 
73  for (ossim_uint32 band = 0; band < numBands; ++band)
74  {
75  map<double, double>& bandMap = theLut[band];
76  std::map<double, double>::const_iterator lut_entry;
77  for (ossim_uint32 pixel=0; pixel<maxLength; ++pixel)
78  {
79  // Do not remap null pixels, leave the output pixel "blank" which is null-pixel value:
80  index = inputTile->getPix(pixel, band);
81  if (index == null_index)
82  continue;
83 
84  // Now perform look-up depending on mode:
85  if (theMode == LITERAL)
86  {
87  lut_entry = bandMap.find(index);
88  if (lut_entry == bandMap.end())
89  value = null_value;
90  else
91  value = lut_entry->second;
92  }
93  else
94  {
95  // Interpolated mode performs interpolation here between the line segments vertices:
96  lut_entry = bandMap.find(index);
97  if (lut_entry != bandMap.end())
98  {
99  // Got exact match, no interpolation needed:
100  value = lut_entry->second;
101  }
102  else
103  {
104  lut_entry = bandMap.upper_bound(index);
105  if ((lut_entry == bandMap.end()) || (lut_entry == bandMap.begin()))
106  value = null_value;
107  else
108  {
109  // Need to linearly interpolate:
110  double index_hi = lut_entry->first;
111  double value_hi (lut_entry->second);
112  --lut_entry;
113  double index_lo = lut_entry->first;
114  double value_lo (lut_entry->second);
115  double w_lo = (index_hi - index)/(index_hi - index_lo);
116  double w_hi = 1.0 - w_lo;
117  value = value_hi*w_hi + value_lo*w_lo;
118  }
119  }
120  }
121 
122  if (value < min_value)
123  min_value = value;
124  if (value > max_value)
125  max_value = value;
126 
127  // Assign this output pixel according to desired scalar type:
128  switch(theOutputScalarType)
129  {
130  case OSSIM_DOUBLE:
131  theTile->getDoubleBuf(band)[pixel] = value;
132  theTile->setMinPix(min_value);
133  theTile->setMaxPix(max_value);
134  break;
135  case OSSIM_SSHORT16:
136  theTile->getSshortBuf(band)[pixel] = value;
137  break;
138  case OSSIM_FLOAT:
139  theTile->setMinPix(min_value);
140  theTile->setMaxPix(max_value);
141  theTile->getFloatBuf(band)[pixel] = value;
142  break;
144  theTile->getFloatBuf(band)[pixel] = value;
145  break;
146  case OSSIM_UCHAR:
147  theTile->getUcharBuf(band)[pixel] = value;
148  break;
149  case OSSIM_USHORT16:
150  theTile->getUshortBuf(band)[pixel] = value;
151  break;
152  case OSSIM_USHORT11:
153  case OSSIM_USHORT12:
154  case OSSIM_USHORT13:
155  case OSSIM_USHORT14:
156  case OSSIM_USHORT15:
157  theTile->getUshortBuf(band)[pixel] = value;
158  break;
159  default:
160  break;
161  }
162  } // end loop over band's pixels
163  } // end loop over tile's bands
164 
165  theTile->validate();
166  return theTile;
167 }
168 
170 {
171  if(!theInputConnection)
172  return;
173 
175  if(!theTile.valid())
176  return;
177 
178  switch(theOutputScalarType)
179  {
180  case OSSIM_SSHORT16:
181  theTile->setMinPix(-32768);
182  theTile->setMaxPix(32767);
183  break;
185  theTile->setMinPix(0.0);
186  theTile->setMaxPix(1.0);
187  break;
188  case OSSIM_UCHAR:
189  theTile->setMinPix(0);
190  theTile->setMaxPix(255);
191  break;
192  case OSSIM_USHORT16:
193  theTile->setMinPix(0);
194  theTile->setMaxPix(65535);
195  break;
196  case OSSIM_USHORT11:
197  theTile->setMinPix(0);
198  theTile->setMaxPix(2047);
199  break;
200  case OSSIM_USHORT12:
201  theTile->setMinPix(0);
202  theTile->setMaxPix(4095);
203  break;
204  case OSSIM_USHORT13:
205  theTile->setMinPix(0);
206  theTile->setMaxPix(8191);
207  break;
208  case OSSIM_USHORT14:
209  theTile->setMinPix(0);
210  theTile->setMaxPix(16383);
211  break;
212  case OSSIM_USHORT15:
213  theTile->setMinPix(0);
214  theTile->setMaxPix(32767);
215  break;
216  default:
217  break;
218  }
219 
220  theTile->initialize();
221 }
222 
224 {
225  // This assigns theInputConnection if one is there.
227 
228  // theTile will get allocated on first getTile call.
229  theTile = 0;
230  if ( theInputConnection )
231  {
232  // Initialize the chain on the left hand side of us.
234  }
235 }
236 
237 bool ossimBandLutFilter::saveState(ossimKeywordlist& kwl, const char* prefix)const
238 {
239  if (theLut.empty())
240  return true;
241 
242  ossimString value;
243  switch (theMode)
244  {
245  case LITERAL:
246  value = "literal";
247  break;
248  case INTERPOLATED:
249  default:
250  value = "interpolated";
251  break;
252  }
253  kwl.add(prefix, MODE_KW, value.c_str(), true);
254 
255  bool rtn_stat = true;
256 
257  // Save the actual LUT:
258  int numBands = theLut.size();
259  for (int band=0; band<numBands; ++band)
260  {
261  ostringstream base_keyword;
262  if (numBands > 1)
263  base_keyword << "band" << band << ".";
264 
265  std::map<double, double>::const_iterator iter = theLut[band].begin();
266  ossim_uint32 entry = 0;
267  while (iter != theLut[band].end())
268  {
269  ostringstream inKey, outKey;
270  inKey << base_keyword.str() << "entry" << entry <<".in";
271  outKey << base_keyword.str() << "entry" << entry <<".out";
272 
273  ostringstream inVal, outVal;
274  inVal << iter->first;
275  outVal << iter->second;
276 
277  kwl.add(prefix, inKey.str().c_str(), inVal.str().c_str());
278  kwl.add(prefix, outKey.str().c_str(), outVal.str().c_str());
279  ++iter;
280  ++entry;
281  }
282  }
283  rtn_stat &= ossimImageSourceFilter::saveState(kwl, prefix);
284  return rtn_stat;
285 }
286 
287 bool ossimBandLutFilter::loadState(const ossimKeywordlist& orig_kwl, const char* prefix)
288 {
289  bool return_state = true;
290  ossimKeywordlist kwl (orig_kwl); // need non-const copy
291 
292  // First look for a LUT filename, and add its contents to the original KWL:
293  theLutFile = kwl.find(prefix, LUT_FILE_KW);
294  if (!theLutFile.empty())
295  {
296  // Need new (non const) KWL to hold merged contents, maintaining proper prefix if any:
297  ossimKeywordlist lut_kwl;
298  if (lut_kwl.addFile(theLutFile))
299  kwl.add(prefix, lut_kwl, false); // appends all entries of lut_kwl with prefix before adding
300  }
301 
303  ossimString lookup = kwl.find(prefix, MODE_KW);
304  if (lookup.contains("literal"))
305  theMode = LITERAL;
306 
307  int scalar = ossimScalarTypeLut::instance()->getEntryNumber(kwl, prefix);
308  if (scalar != ossimLookUpTable::NOT_FOUND)
309  setOutputScalarType(static_cast<ossimScalarType>(scalar));
310 
311  return_state &= initializeLut(kwl, prefix);
312  return_state &= ossimImageSourceFilter::loadState(orig_kwl, prefix);
313 
314  return return_state;
315 }
316 
317 bool ossimBandLutFilter::initializeLut(const ossimKeywordlist& kwl, const char* prefix)
318 {
319  theLut.clear();
320  ossim_uint32 numBands = getNumberOfInputBands();
321  bool usingBandPrefix = true;
322  if (numBands <= 1)
323  {
324  ossim_uint32 numEntries = kwl.numberOf(prefix, "band0.in");
325  if (numEntries == 0)
326  {
327  usingBandPrefix = false;
328  numBands = 1;
329  }
330  }
331 
332  ossim_uint32 band = 0;
333  while (true)
334  {
335  ossim_uint32 entry = 0;
336  map<double,double> bandMap;
337  while (true)
338  {
339  ostringstream inKey, outKey;
340  if (usingBandPrefix)
341  {
342  inKey << "band" << band << ".entry" << entry <<".in";
343  outKey << "band" << band << ".entry" << entry <<".out";
344  }
345  else
346  {
347  inKey << "entry" << entry <<".in";
348  outKey << "entry" << entry <<".out";
349  }
350 
351  ossimString inVal = kwl.find(prefix, inKey.str().c_str());
352  if (inVal.empty())
353  break;
354  ossimString outVal = kwl.find(prefix, outKey.str().c_str());
355  if (outVal.empty())
356  break;
357 
358  bandMap.insert(std::pair<double,double>(inVal.toDouble(), outVal.toDouble()));
359  ++entry;
360  }
361 
362  if (bandMap.empty())
363  break;
364 
365  theLut.push_back(bandMap);
366 
367  ++band;
368  if ((numBands == 1) || !usingBandPrefix)
369  break;
370 
371  }
372 
373  // Band still 0 would indicate a failure reading the first band entry:
374  if (band == 0)
375  return false;
376 
377  // Check that the correct number of bands are represented:
378  if (theInputConnection && (numBands > band))
379  {
380  if (!usingBandPrefix)
381  {
382  // Use the same map for all bands
383  for (ossim_uint32 i=1; i<numBands; ++i)
384  theLut.push_back(theLut[0]);
385  }
386  else
387  {
388  // Not enough bands were specified in the KWL to represent all input bands. Set remaining
389  // bands to no entries:
390  map<double,double> nullBandMap;
391  for (; band<numBands; ++band)
392  theLut.push_back(nullBandMap);
393  }
394  }
395  return true;
396 }
397 
399 {
400  theLutFile = file;
401  if(file.exists())
402  {
404  loadState(kwl);
405  }
406 }
407 
409 {
410  if (scalarType == OSSIM_SCALAR_UNKNOWN)
411  {
413  << "ossimScalarRemapper::setOutputScalarType WARN:\n"
414  << "OSSIM_SCALAR_UNKNOWN passed to method. No action taken..."
415  << std::endl;
416  return;
417  }
418 
419  theOutputScalarType = scalarType;
420  allocate();
421 }
422 
424 {
425  int scalar = ossimScalarTypeLut::instance()->getEntryNumber(scalarType.c_str());
426 
427  if (scalar != ossimLookUpTable::NOT_FOUND)
428  {
429  setOutputScalarType(static_cast<ossimScalarType>(scalar));
430  }
431  else
432  {
434  << "ossimScalarRemapper ERROR:"
435  << "\nUnknown scalar type: " << scalarType.c_str() << std::endl;
436  }
437 }
438 
16 bit unsigned integer (15 bits used)
void allocate()
Called on first getTile, will initialize all data needed.
virtual ossim_uint32 getWidth() const
virtual void setDescription(const ossimString &description)
virtual ossim_uint32 getNumberOfInputBands() const
ossim_uint32 numberOf(const char *str) const
std::basic_ostringstream< char > ostringstream
Class for char output memory streams.
Definition: ossimIosFwd.h:35
virtual void setImageRectangle(const ossimIrect &rect)
virtual const ossim_uint16 * getUshortBuf() const
virtual const ossim_uint8 * getUcharBuf() const
Represents serializable keyword/value map.
bool addFile(const char *file)
#define OSSIM_DEFAULT_MAX_PIX_DOUBLE
bool valid() const
Definition: ossimRefPtr.h:75
const char * find(const char *key) const
bool contains(char aChar) const
Definition: ossimString.h:58
ossimScalarType theOutputScalarType
virtual ossimDataObjectStatus getDataObjectStatus() const
virtual ossim_uint32 getHeight() const
16 bit unsigned integer (14 bits used)
16 bit unsigned integer (13 bits used)
virtual ossim_float64 getPix(const ossimIpt &position, ossim_uint32 band=0) const
Will return the pixel at location position.
virtual const ossim_sint16 * getSshortBuf() const
void setLut(const ossimFilename &file)
This opens the keyword list and initializes lut.
virtual void initialize()
Initialize the data buffer.
virtual ossim_int32 getEntryNumber(const char *entry_string, bool case_insensitive=true) const
void add(const char *prefix, const ossimKeywordlist &kwl, bool overwrite=true)
static ossimScalarTypeLut * instance()
Returns the static instance of an ossimScalarTypeLut object.
static ossimImageDataFactory * instance()
#define OSSIM_DEFAULT_MIN_PIX_DOUBLE
virtual ossimDataObjectStatus validate() const
bool exists() const
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=NULL) const
Method to save the state of an object to a keyword list.
ossimImageSource * theInputConnection
unsigned int ossim_uint32
virtual const ossim_float64 * getNullPix() const
32 bit normalized floating point
double toDouble() const
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
Method to the load (recreate) the state of an object from a keyword list.
ossimRefPtr< ossimImageData > theTile
virtual ossimRefPtr< ossimImageData > create(ossimSource *owner, ossimScalarType scalar, ossim_uint32 bands=1) const
ossimScalarType
virtual const ossim_float32 * getFloatBuf() const
ossimFilename theLutFile
std::vector< std::map< double, double > > theLut
virtual void makeBlank()
Initializes data to null pixel values.
virtual void setOutputScalarType(ossimScalarType scalarType)
Sets the output scalar type.
16 bit unsigned integer (11 bits used)
virtual void setMaxPix(ossim_float64 max_pix)
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
Method to save the state of an object to a keyword list.
virtual const void * getBuf() const
RTTI_DEF1(ossimBandLutFilter, "ossimBandLutFilter", ossimImageSourceFilter)
const char * c_str() const
Returns a pointer to a null-terminated array of characters representing the string&#39;s contents...
Definition: ossimString.h:396
bool empty() const
Definition: ossimString.h:411
virtual ossimRefPtr< ossimImageData > getTile(const ossimIrect &origin, ossim_uint32 resLevel=0)
virtual void initialize()=0
bool initializeLut(const ossimKeywordlist &kwl, const char *prefix=0)
32 bit floating point
virtual void setMinPix(ossim_float64 min_pix)
16 bit unsigned iteger
64 bit floating point
16 bit signed integer
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=NULL)
Method to the load (recreate) the state of an object from a keyword list.
virtual double getNullPixelValue(ossim_uint32 band=0) const
Each band has a null pixel associated with it.
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
8 bit unsigned iteger
virtual ossimRefPtr< ossimImageData > getTile(const ossimIpt &origin, ossim_uint32 resLevel=0)
16 bit unsigned integer (12 bits used)
virtual const ossim_float64 * getDoubleBuf() const