OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimIndexToRgbLutFilter.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: ossimIndexToRgbLutFilter.cpp 23242 2015-04-08 17:31:35Z dburken $
15 #include <ossim/base/ossimCommon.h>
17 #include <ossim/base/ossimTrace.h>
21 
22 RTTI_DEF1(ossimIndexToRgbLutFilter, "ossimIndexToRgbLutFilter", ossimImageSourceFilter);
23 
24 static const char* MIN_VALUE_KW = "min_value";
25 static const char* MAX_VALUE_KW = "max_value";
26 static const char* MODE_KW = "mode";
27 static const char* LUT_FILE_KW = "lut_file";
28 
31  theMinValue(ossim::nan()),
32  theMaxValue(ossim::nan()),
33  theMinValueOverride(false),
34  theMaxValueOverride(false),
35  theMode(REGULAR),
36  theTile(0),
37  theLutFile("")
38 {
39  setDescription("Look-up-table remapper from single-band index image to 24-bit RGB.");
40 }
41 
43 {
44 }
45 
47  ossim_uint32 resLevel)
48 {
49  if(!theInputConnection || (theLut.size() == 0))
50  return 0;
51 
52  ossimRefPtr<ossimImageData> tile = theInputConnection->getTile(tileRect, resLevel);
53  if (!tile || !tile->getBuf())
54  return 0;
55  if(!theTile)
56  {
57  allocate();
58  if (!theTile)
59  return 0;
60  }
61 
62  theTile->setImageRectangle(tileRect);
63  theTile->makeBlank();
64 
65  // Quick handling special case of empty input tile:
66  if (tile->getDataObjectStatus() == OSSIM_EMPTY)
67  return theTile;
68 
69  ossim_uint8* outBuf[3];
70  outBuf[0] = (ossim_uint8*)(theTile->getBuf(0));
71  outBuf[1] = (ossim_uint8*)(theTile->getBuf(1));
72  outBuf[2] = (ossim_uint8*)(theTile->getBuf(2));
73 
74  ossim_uint32 maxLength = tile->getWidth()*tile->getHeight();
75  ossimRgbVector color;
76  const ossimRgbVector null_color (theTile->getNullPix(0), theTile->getNullPix(1), theTile->getNullPix(2));
77  double index;
78  std::map<double, ossimRgbVector>::const_iterator lut_entry;
79  double null_index = theInputConnection->getNullPixelValue();
80 
81  for (ossim_uint32 pixel=0; pixel<maxLength; ++pixel)
82  {
83  // Convert input pixel to a double index value:
84  switch(tile->getScalarType())
85  {
86  case OSSIM_DOUBLE:
87  index = ((double*) tile->getBuf())[pixel];
88  break;
89  case OSSIM_SSHORT16:
90  index = (double)(((ossim_sint16*) tile->getBuf())[pixel]);
91  break;
92  case OSSIM_FLOAT:
94  index = (double)(((float*) tile->getBuf())[pixel]);
95  break;
96  case OSSIM_UCHAR:
97  index = (double)(((ossim_uint8*) tile->getBuf())[pixel]);
98  break;
99  case OSSIM_USHORT16:
100  case OSSIM_USHORT11:
101  case OSSIM_USHORT12:
102  case OSSIM_USHORT13:
103  case OSSIM_USHORT14:
104  case OSSIM_USHORT15:
105  index = (double)(((ossim_uint16*) tile->getBuf())[pixel]);
106  break;
107  default:
108  break;
109  }
110 
111  // Do not remap null pixels, leave the output pixel "blank" which is null-pixel value:
112  if (index == null_index)
113  continue;
114 
115  // REGULAR mode needs to clamp the indices to min max for non-null pixels:
116  if (theMode == REGULAR)
117  {
118  if (index < theMinValue)
119  index = theMinValue;
120  else if (index > theMaxValue)
121  index = theMaxValue;
122  }
123 
124  // Now perform look-up depending on mode:
125  if (theMode == LITERAL)
126  {
127  lut_entry = theLut.find(index);
128  if (lut_entry == theLut.end())
129  color = null_color;
130  else
131  color = lut_entry->second;
132  }
133  else
134  {
135  // Vertices and Regular mode perform same interpolation here between the line segments
136  // vertices:
137  lut_entry = theLut.find(index);
138  if (lut_entry != theLut.end())
139  {
140  // Got exact match, no interpolation needed:
141  color = lut_entry->second;
142  }
143  else
144  {
145  lut_entry = theLut.upper_bound(index);
146  if ((lut_entry == theLut.end()) || (lut_entry == theLut.begin()))
147  color = null_color;
148  else
149  {
150  // Need to linearly interpolate:
151  double index_hi = lut_entry->first;
152  ossimRgbVector color_hi (lut_entry->second);
153  --lut_entry;
154  double index_lo = lut_entry->first;
155  ossimRgbVector color_lo (lut_entry->second);
156  double w_lo = (index_hi - index)/(index_hi - index_lo);
157  double w_hi = 1.0 - w_lo;
158  color.setR(ossim::round<ossim_uint8, double>( color_hi.getR()*w_hi + color_lo.getR()*w_lo ));
159  color.setG(ossim::round<ossim_uint8, double>( color_hi.getG()*w_hi + color_lo.getG()*w_lo ));
160  color.setB(ossim::round<ossim_uint8, double>( color_hi.getB()*w_hi + color_lo.getB()*w_lo ));
161  }
162  }
163  }
164 
165  // Assign this output pixel:
166  outBuf[0][pixel] = color.getR();
167  outBuf[1][pixel] = color.getG();
168  outBuf[2][pixel] = color.getB();
169 
170  } // end loop over tile's pixels
171 
172  theTile->validate();
173  return theTile;
174 }
175 
177 {
178  if(!theInputConnection) return;
179 
180  theTile = ossimImageDataFactory::instance()->create(this, 3, this);
181  if(theTile.valid())
182  {
183  theTile->initialize();
184  }
185 }
186 
188 {
189  // This assigns theInputConnection if one is there.
191 
192  // theTile will get allocated on first getTile call.
193  theTile = 0;
194 
195  if ( theInputConnection )
196  {
197  // Initialize the chain on the left hand side of us.
204  swap(theMinValue, theMaxValue);
205  }
206 }
207 
208 bool ossimIndexToRgbLutFilter::saveState(ossimKeywordlist& kwl, const char* prefix)const
209 {
211  kwl.add(prefix, MIN_VALUE_KW, theMinValue, true);
212 
214  kwl.add(prefix, MAX_VALUE_KW, theMaxValue, true);
215 
216  ossimString value;
217  switch (theMode)
218  {
219  case LITERAL:
220  value = "literal";
221  break;
222  case VERTICES:
223  value = "vertices";
224  break;
225  default:
226  value = "regular";
227  }
228  kwl.add(prefix, MODE_KW, value.c_str(), true);
229 
230  bool rtn_stat = true;
231 
232  // Save the actual LUT:
233  const ossimString entry_kw ("entry");
234  ossimString color_keyword, base_keyword;
235  ossimRgbVector rgbVector;
236  ossimString blank(" ");
237 
238  ossim_uint32 entry = 0;
239  std::map<double, ossimRgbVector>::const_iterator iter = theLut.begin();
240  while (iter != theLut.end())
241  {
242  base_keyword = entry_kw + ossimString::toString(entry);
243  if ((theMode == LITERAL) || (theMode == VERTICES))
244  {
245  // Index and color are sub-entries for these modes:
246  kwl.add(prefix, (base_keyword+".index").chars(), iter->first);
247  color_keyword = base_keyword + ".color";
248  }
249  else
250  {
251  color_keyword = base_keyword;
252  }
253 
254  rgbVector = iter->second;
255  value = ossimString::toString((int)rgbVector.getR()) + blank +
256  ossimString::toString((int)rgbVector.getG()) + blank +
257  ossimString::toString((int)rgbVector.getB());
258  kwl.add(prefix, color_keyword.chars(), value.chars());
259  ++iter;
260  ++entry;
261  }
262 
263  rtn_stat &= ossimImageSourceFilter::saveState(kwl, prefix);
264  return rtn_stat;
265 }
266 
267 bool ossimIndexToRgbLutFilter::loadState(const ossimKeywordlist& orig_kwl, const char* prefix)
268 {
269  bool return_state = true;
270  ossimKeywordlist* kwl = new ossimKeywordlist(orig_kwl); // need non-const copy
271 
272  // First look for a LUT filename, and add its contents to the original KWL:
273  theLutFile = kwl->find(prefix, LUT_FILE_KW);
274  if (!theLutFile.empty())
275  {
276  // Need new (non const) KWL to hold merged contents, maintaining proper prefix if any:
277  ossimKeywordlist lut_kwl;
278  if (lut_kwl.addFile(theLutFile))
279  kwl->add(prefix, lut_kwl, false); // appends all entries of lut_kwl with prefix before adding
280  }
281 
282  theMinValueOverride = false;
283  ossimString lookup = kwl->find(prefix, MIN_VALUE_KW);
284  if(!lookup.empty())
285  {
286  theMinValue =lookup.toDouble();
287  theMinValueOverride = true;
288  }
289 
290  theMaxValueOverride = false;
291  lookup = kwl->find(prefix, MAX_VALUE_KW);
292  if(!lookup.empty())
293  {
294  theMaxValue = lookup.toDouble();
295  theMaxValueOverride = true;
296  }
297 
298  lookup = kwl->find(prefix, MODE_KW);
299  if (lookup.contains("literal"))
300  theMode = LITERAL;
301  else if (lookup.contains("vertices"))
302  theMode = VERTICES;
303  else
304  theMode = REGULAR;
305 
306  return_state &= initializeLut(kwl, prefix);
307  return_state &= ossimImageSourceFilter::loadState(orig_kwl, prefix);
308 
309  delete kwl;
310  return return_state;
311 }
312 
313 bool ossimIndexToRgbLutFilter::initializeLut(const ossimKeywordlist* kwl, const char* prefix)
314 {
315  theLut.clear();
316 
317  const ossimString entry_kw ("entry");
318  ossimString keyword, base_keyword;
319  ossimString indexStr, rgbStr;
320  ossimString blank(" ");
321  std::vector<ossimString> rgbList;
322  double index;
323  ossimRgbVector rgbVector (0,0,0);
324  bool rtn_state = true;
325 
326  ossim_uint32 numEntries=0;
327  while (true)
328  {
329  base_keyword = entry_kw + ossimString::toString(numEntries);
330  if ((theMode == LITERAL) || (theMode == VERTICES))
331  {
332  // Index and color are subentries for this mode:
333  keyword = base_keyword + ".index";
334  indexStr = kwl->find(prefix, keyword.chars());
335  if (indexStr.empty())
336  break;
337 
338  index = indexStr.toDouble();
339  keyword = base_keyword + ".color";
340  rgbStr = kwl->find(prefix, keyword.chars());
341  }
342  else
343  {
344  // REGULAR mode: index is computed later to arrive at equally-spaced vertices. For now,
345  // just store entry number as index:
346  index = (double) numEntries;
347  keyword = base_keyword;
348  rgbStr = kwl->find(prefix, keyword.chars());
349  if (rgbStr.empty())
350  {
351  // Perhaps old bloated form with separate keywords for R, G, B
352  rgbStr = kwl->find(prefix, (keyword + ".r").chars());
353  rgbStr += " ";
354  rgbStr += kwl->find(prefix, (keyword + ".g").chars());
355  rgbStr += " ";
356  rgbStr += kwl->find(prefix, (keyword + ".b").chars());
357  if (rgbStr.length() < 5)
358  break;
359  }
360  }
361 
362  rgbStr.split(rgbList, blank, true);
363  if (rgbList.size() != 3)
364  {
365  ossimNotify(ossimNotifyLevel_WARN)<<"ossimIndexToRgbLutFilter::initializeLut() -- "
366  "Bad color specification in LUT KWL. LUT is not properly initialized."<<endl;
367  return false;
368  }
369 
370  rgbVector.setR(rgbList[0].toUInt8());
371  rgbVector.setG(rgbList[1].toUInt8());
372  rgbVector.setB(rgbList[2].toUInt8());
373  theLut.insert(std::pair<double, ossimRgbVector>(index, rgbVector));
374  rgbList.clear();
375  ++numEntries;
376  }
377 
378  // For REGULAR mode, need to adjust the indices to reflect a piecewise linear LUT with equally
379  // spaced vertices:
380  if (theMode == REGULAR)
381  {
382  std::map<double, ossimRgbVector> orig_lut = theLut;
383  std::map<double, ossimRgbVector>::iterator iter = orig_lut.begin();
384  theLut.clear();
385 
386  if (numEntries == 1)
387  {
388  // Insert the implied start index at black and endpoint at specified color:
389  theLut.insert(std::pair<double, ossimRgbVector>(theMinValue, ossimRgbVector (1, 1, 1)));
390  theLut.insert(std::pair<double, ossimRgbVector>(theMaxValue, iter->second));
391  }
392  else
393  {
394  // Loop to create equally-spaced vertices between min and max index values:
395  double interval = (theMaxValue - theMinValue) / (numEntries - 1);
396  while (iter != orig_lut.end())
397  {
398  index = theMinValue + iter->first*interval;
399  theLut.insert(std::pair<double, ossimRgbVector>(index, iter->second));
400  ++iter;
401  }
402  }
403  }
404 
405  return rtn_state;
406 }
407 
409 {
410  if(isSourceEnabled())
411  {
412  return 3;
413  }
415 }
416 
418 {
419  if(isSourceEnabled())
420  {
421  return OSSIM_UCHAR;
422  }
423 
425 }
426 
428 {
429  theLutFile = file;
430  if(file.exists())
431  {
433  loadState(kwl);
434  }
435 }
436 
438 {
439  return theMinValue;
440 }
441 
443 {
444  return theMaxValue;
445 }
446 
448 {
449  theMinValue = value;
450 }
451 
453 {
454  theMaxValue = value;
455 }
456 
458 {
459  return 0.0;
460 }
461 
463 {
464  return 1.0;
465 }
466 
468 {
469  return 255.0;
470 }
471 
472 
16 bit unsigned integer (15 bits used)
virtual ossim_uint32 getWidth() const
virtual bool isSourceEnabled() const
Definition: ossimSource.cpp:79
ossim_uint32 getNumberOfOutputBands() const
Returns the number of bands in a tile returned from this TileSource.
virtual void setDescription(const ossimString &description)
unsigned char getR() const
virtual void setImageRectangle(const ossimIrect &rect)
void allocate()
Called on first getTile, will initialize all data needed.
Represents serializable keyword/value map.
bool addFile(const char *file)
virtual ossim_uint32 getNumberOfOutputBands() const
Returns the number of bands in a tile returned from this TileSource.
bool valid() const
Definition: ossimRefPtr.h:75
const char * find(const char *key) const
double nan()
Method to return ieee floating point double precision NAN.
Definition: ossimCommon.h:135
This code was derived from https://gist.github.com/mshockwave.
Definition: Barrier.h:8
void setR(unsigned char R)
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=NULL) const
Method to save the state of an object to a keyword list.
bool contains(char aChar) const
Definition: ossimString.h:58
static ossimString toString(bool aValue)
Numeric to string methods.
virtual double getMaxPixelValue(ossim_uint32 band=0) const
Returns the max pixel of the band.
void split(std::vector< ossimString > &result, const ossimString &separatorList, bool skipBlankFields=false) const
Splits this string into a vector of strings (fields) using the delimiter list specified.
virtual ossimDataObjectStatus getDataObjectStatus() const
virtual ossim_uint32 getHeight() const
16 bit unsigned integer (14 bits used)
bool initializeLut(const ossimKeywordlist *kwl, const char *prefix=0)
16 bit unsigned integer (13 bits used)
unsigned short ossim_uint16
virtual double getNullPixelValue(ossim_uint32 band=0) const
Each band has a null pixel associated with it.
virtual void initialize()
Initialize the data buffer.
virtual ossimScalarType getOutputScalarType() const
This will be used to query the output pixel type of the tile source.
void setB(unsigned char B)
virtual double getMinPixelValue(ossim_uint32 band=0) const
Returns the min pixel of the band.
void add(const char *prefix, const ossimKeywordlist &kwl, bool overwrite=true)
static ossimImageDataFactory * instance()
virtual ossimDataObjectStatus validate() const
bool exists() const
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=NULL)
Method to the load (recreate) the state of an object from a keyword list.
std::string::size_type length() const
Definition: ossimString.h:408
signed short ossim_sint16
virtual double getMinPixelValue(ossim_uint32 band=0) const
Returns the min pixel of the band.
void setLut(const ossimFilename &file)
Set lookup table(lut) method.
ossimImageSource * theInputConnection
unsigned int ossim_uint32
virtual const ossim_float64 * getNullPix() const
const char * chars() const
For backward compatibility.
Definition: ossimString.h:77
32 bit normalized floating point
double toDouble() const
unsigned char getB() 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.
virtual ossimRefPtr< ossimImageData > create(ossimSource *owner, ossimScalarType scalar, ossim_uint32 bands=1) const
void setG(unsigned char G)
ossimScalarType
RTTI_DEF1(ossimIndexToRgbLutFilter, "ossimIndexToRgbLutFilter", ossimImageSourceFilter)
unsigned char getG() const
virtual ossimScalarType getScalarType() const
virtual void makeBlank()
Initializes data to null pixel values.
16 bit unsigned integer (11 bits used)
virtual ossimScalarType getOutputScalarType() const
This will be used to query the output pixel type of the tile source.
virtual bool saveState(ossimKeywordlist &kwl, const char *prefix=0) const
Method to save the state of an object to a keyword list.
virtual double getMaxPixelValue(ossim_uint32 band=0) const
Returns the max pixel of the band.
virtual ossimRefPtr< ossimImageData > getTile(const ossimIrect &origin, ossim_uint32 resLevel=0)
virtual const void * getBuf() const
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
std::map< double, ossimRgbVector > theLut
virtual void initialize()=0
32 bit floating point
ossimRefPtr< ossimImageData > theTile
16 bit unsigned iteger
64 bit floating point
16 bit signed integer
unsigned char ossim_uint8
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)