USGS

Isis 3.0 Object Programmers' Reference

Home

Stretch.cpp
Go to the documentation of this file.
1 
23 #include <iostream>
24 
25 #include <QDebug>
26 
27 #include "Stretch.h"
28 #include "Histogram.h"
29 #include "IString.h"
30 #include "SpecialPixel.h"
31 #include "IException.h"
32 #include "Pvl.h"
33 
34 using namespace std;
35 namespace Isis {
36 
41  Stretch::Stretch() {
42  p_null = Isis::NULL8;
43  p_lis = Isis::LOW_INSTR_SAT8;
44  p_lrs = Isis::LOW_REPR_SAT8;
45  p_his = Isis::HIGH_INSTR_SAT8;
46  p_hrs = Isis::HIGH_REPR_SAT8;
47  p_minimum = p_lrs;
48  p_maximum = p_hrs;
49  p_pairs = 0;
50  }
51 
63  void Stretch::AddPair(const double input, const double output) {
64  if(p_pairs > 0) {
65  if(input <= p_input[p_pairs-1]) {
66  string msg = "Input pairs must be in ascending order";
67  throw IException(IException::Programmer, msg, _FILEINFO_);
68  }
69  }
70 
71  p_input.push_back(input);
72  p_output.push_back(output);
73  p_pairs++;
74  }
75 
84  double Stretch::Map(const double value) const {
85  // Check special pixels first
86  if(!Isis::IsValidPixel(value)) {
87  if(Isis::IsNullPixel(value)) return p_null;
88  if(Isis::IsHisPixel(value)) return p_his;
89  if(Isis::IsHrsPixel(value)) return p_hrs;
90  if(Isis::IsLisPixel(value)) return p_lis;
91  return p_lrs;
92  }
93 
94  // Check to see if we have any pairs
95  if(p_input.size() == 0) return value;
96 
97  // Check to see if outside the minimum and maximum next
98  if(value < p_input[0]) {
99  if(!Isis::IsValidPixel(p_minimum)) {
100  if(Isis::IsNullPixel(p_minimum)) return p_null;
101  if(Isis::IsHisPixel(p_minimum)) return p_his;
102  if(Isis::IsHrsPixel(p_minimum)) return p_hrs;
103  if(Isis::IsLisPixel(p_minimum)) return p_lis;
104  return p_lrs;
105  }
106  return p_minimum;
107  }
108 
109  if(value > p_input[p_pairs-1]) {
110  if(!Isis::IsValidPixel(p_maximum)) {
111  if(Isis::IsNullPixel(p_maximum)) return p_null;
112  if(Isis::IsHisPixel(p_maximum)) return p_his;
113  if(Isis::IsHrsPixel(p_maximum)) return p_hrs;
114  if(Isis::IsLisPixel(p_maximum)) return p_lis;
115  return p_lrs;
116  }
117  return p_maximum;
118  }
119 
120  // Check the end points
121  if(value == p_input[0]) return p_output[0];
122  if(value == p_input[p_pairs-1]) return p_output[p_pairs-1];
123 
124  // Ok find the surrounding pairs with a binary search
125  int start = 0;
126  int end = p_pairs - 1;
127  while(start != end) {
128  int middle = (start + end) / 2;
129 
130  if(middle == start) {
131  end = middle;
132  }
133  else if(value < p_input[middle]) {
134  end = middle;
135  }
136  else {
137  start = middle;
138  }
139  }
140 
141  end = start + 1;
142 
143  // Apply the stretch
144  double slope = (p_output[end] - p_output[start]) / (p_input[end] - p_input[start]);
145  return slope * (value - p_input[end]) + p_output[end];
146  }
147 
160  std::pair<double, double> Stretch::NextPair(QString &pairs) {
161  std::pair<double, double> io;
162  io.first = Null;
163  io.second = Null;
164 
165  pairs = pairs.simplified().trimmed();
166 
167  if (pairs.contains(":")) {
168  QStringList pairList = pairs.split(" ");
169 
170  QString firstPair = pairList.takeFirst();
171 
172  QStringList firstPairValues = firstPair.split(":");
173 
174  if (firstPairValues.count() == 2) {
175  io.first = toDouble(firstPairValues.first());
176  io.second = toDouble(firstPairValues.last());
177 
178  pairs = pairList.join(" ");
179  }
180  }
181 
182  return io;
183  }
184 
196  void Stretch::Parse(const QString &pairs) {
197  // Zero out the stretch arrays
198  p_input.clear();
199  p_output.clear();
200  p_pairs = 0;
201 
202  std::pair<double, double> pear;
203 
204  QString p = pairs.simplified().trimmed();
205  p.replace(QRegExp("[\\s]*:"), ":");
206  p.replace(QRegExp(":[\\s]*"), ":");
207  QStringList pairList = p.split(" ", QString::SkipEmptyParts);
208 
209  try {
210  foreach(QString singlePair, pairList) {
211  pear = Stretch::NextPair(singlePair);
212  Stretch::AddPair(pear.first, pear.second);
213  }
214  }
215  catch(IException &e) {
216  throw IException(e, IException::User, "Invalid stretch pairs [" + pairs + "]", _FILEINFO_);
217  }
218  }
219 
233  void Stretch::Parse(const QString &pairs, const Isis::Histogram *hist) {
234  // Zero out the stretch arrays
235  p_input.clear();
236  p_output.clear();
237  p_pairs = 0;
238 
239  QString p(pairs);
240  std::pair<double, double> pear;
241 
242  // need to save the input dn values in order to
243  // to detect collisions
244  std::vector<double> converted;
245 
246  try {
247  while(p.size() > 0) {
248  pear = Stretch::NextPair(p);
249  pear.first = hist->Percent(pear.first);
250 
251  // test for collision!
252  // if collision occurs then ignore this pair and move on
253  // to next pair
254  bool collision = false;
255  unsigned int k = 0;
256  while(!collision && k < converted.size()) {
257  if(pear.first == converted[k]) {
258  collision = true;
259  }
260  else {
261  k++;
262  }
263  }
264  if(!collision) {
265  Stretch::AddPair(pear.first, pear.second);
266  converted.push_back(pear.first);
267  }
268  }
269  }
270 
271  catch(IException &e) {
272  throw IException(e, IException::User, "Invalid stretch pairs [" +
273  pairs + "]", _FILEINFO_);
274  }
275  }
276 
277 
283  QString Stretch::Text() const {
284 
285  if(p_pairs < 0) return "";
286 
287  QString p("");
288  for(int i = 0; i < p_pairs; i++) {
289  p += toString(p_input[i]) + ":" + toString(p_output[i]) + " ";
290  }
291  return p.trimmed();
292  }
293 
302  double Stretch::Input(int index) const {
303  if(index >= p_pairs || index < 0) {
304  return -1;
305  }
306  return p_input[index];
307  }
308 
317  double Stretch::Output(int index) const {
318  if(index >= p_pairs || index < 0) {
319  return -1;
320  }
321  return p_output[index];
322  }
323 
338  void Stretch::Load(QString &file, QString &grpName) {
339  Pvl pvl(file);
340  Load(pvl, grpName);
341  }
342 
357  void Stretch::Load(Isis::Pvl &pvl, QString &grpName) {
358  PvlGroup grp = pvl.findGroup(grpName, Isis::PvlObject::Traverse);
359  PvlKeyword inputs = grp.findKeyword("Input");
360  PvlKeyword outputs = grp.findKeyword("Output");
361 
362  if(inputs.size() != outputs.size()) {
363  QString msg = "Invalid Pvl file: The number of Input values must equal the number of Output values";
364  throw IException(IException::User, msg, _FILEINFO_);
365  }
366  for(int i = 0; i < inputs.size(); i++) {
367  AddPair(toDouble(inputs[i]), toDouble(outputs[i]));
368  }
369  }
370 
371 
382  void Stretch::Save(QString &file, QString &grpName) {
383  Pvl p;
384  Save(p, grpName);
385  p.write(file);
386  }
387 
388  void Stretch::Save(Isis::Pvl &pvl, QString &grpName) {
389  PvlGroup *grp = new PvlGroup(grpName);
390  PvlKeyword inputs("Input");
391  PvlKeyword outputs("Output");
392  for(int i = 0; i < Pairs(); i++) {
393  inputs.addValue(toString(Input(i)));
394  outputs.addValue(toString(Output(i)));
395  }
396  grp->addKeyword(inputs);
397  grp->addKeyword(outputs);
398  pvl.addGroup(*grp);
399  }
400 
407  void Stretch::CopyPairs(const Stretch &other) {
408  this->p_pairs = other.p_pairs;
409  this->p_input = other.p_input;
410  this->p_output = other.p_output;
411  }
412 
413 } // end namespace isis
414 
415