Isis 3 Programmer Reference
Stretch.cpp
1
6/* SPDX-License-Identifier: CC0-1.0 */
7#include <iostream>
8
9#include <QDebug>
10
11#include "Stretch.h"
12#include "Histogram.h"
13#include "IString.h"
14#include "SpecialPixel.h"
15#include "IException.h"
16#include "Pvl.h"
17
18using namespace std;
19namespace Isis {
20
26 p_null = Isis::NULL8;
27 p_lis = Isis::LOW_INSTR_SAT8;
28 p_lrs = Isis::LOW_REPR_SAT8;
29 p_his = Isis::HIGH_INSTR_SAT8;
30 p_hrs = Isis::HIGH_REPR_SAT8;
33 p_pairs = 0;
34 }
35
36
48 void Stretch::AddPair(const double input, const double output) {
49 if(p_pairs > 0) {
50 if(input <= p_input[p_pairs-1]) {
51 string msg = "Input pairs must be in ascending order";
52 throw IException(IException::Programmer, msg, _FILEINFO_);
53 }
54 }
55
56 p_input.push_back(input);
57 p_output.push_back(output);
58 p_pairs++;
59 }
60
69 double Stretch::Map(const double value) const {
70 // Check special pixels first
71 if(!Isis::IsValidPixel(value)) {
72 if(Isis::IsNullPixel(value)) return p_null;
73 if(Isis::IsHisPixel(value)) return p_his;
74 if(Isis::IsHrsPixel(value)) return p_hrs;
75 if(Isis::IsLisPixel(value)) return p_lis;
76 return p_lrs;
77 }
78
79 // Check to see if we have any pairs
80 if(p_input.size() == 0) return value;
81
82 // Check to see if outside the minimum and maximum next
83 if(value < p_input[0]) {
89 return p_lrs;
90 }
91 return p_minimum;
92 }
93
94 if(value > p_input[p_pairs-1]) {
100 return p_lrs;
101 }
102 return p_maximum;
103 }
104
105 // Check the end points
106 if(value == p_input[0]) return p_output[0];
107 if(value == p_input[p_pairs-1]) return p_output[p_pairs-1];
108
109 // Ok find the surrounding pairs with a binary search
110 int start = 0;
111 int end = p_pairs - 1;
112 while(start != end) {
113 int middle = (start + end) / 2;
114
115 if(middle == start) {
116 end = middle;
117 }
118 else if(value < p_input[middle]) {
119 end = middle;
120 }
121 else {
122 start = middle;
123 }
124 }
125
126 end = start + 1;
127
128 // Apply the stretch
129 double slope = (p_output[end] - p_output[start]) / (p_input[end] - p_input[start]);
130 return slope * (value - p_input[end]) + p_output[end];
131 }
132
145 std::pair<double, double> Stretch::NextPair(QString &pairs) {
146 std::pair<double, double> io;
147 io.first = Null;
148 io.second = Null;
149
150 pairs = pairs.simplified().trimmed();
151
152 if (pairs.contains(":")) {
153 QStringList pairList = pairs.split(" ");
154
155 QString firstPair = pairList.takeFirst();
156
157 QStringList firstPairValues = firstPair.split(":");
158
159 if (firstPairValues.count() == 2) {
160 io.first = toDouble(firstPairValues.first());
161 io.second = toDouble(firstPairValues.last());
162
163 pairs = pairList.join(" ");
164 }
165 }
166
167 return io;
168 }
169
181 void Stretch::Parse(const QString &pairs) {
182 // Zero out the stretch arrays
183 p_input.clear();
184 p_output.clear();
185 p_pairs = 0;
186
187 std::pair<double, double> pear;
188
189 QString p = pairs.simplified().trimmed();
190 p.replace(QRegExp("[\\s]*:"), ":");
191 p.replace(QRegExp(":[\\s]*"), ":");
192 QStringList pairList = p.split(" ", QString::SkipEmptyParts);
193
194 try {
195 foreach(QString singlePair, pairList) {
196 pear = Stretch::NextPair(singlePair);
197 Stretch::AddPair(pear.first, pear.second);
198 }
199 }
200 catch(IException &e) {
201 throw IException(e, IException::User, "Invalid stretch pairs [" + pairs + "]", _FILEINFO_);
202 }
203 }
204
218 void Stretch::Parse(const QString &pairs, const Isis::Histogram *hist) {
219 // Zero out the stretch arrays
220 p_input.clear();
221 p_output.clear();
222 p_pairs = 0;
223
224 QString p(pairs);
225 std::pair<double, double> pear;
226
227 // need to save the input dn values in order to
228 // to detect collisions
229 std::vector<double> converted;
230
231 try {
232 while(p.size() > 0) {
233 pear = Stretch::NextPair(p);
234 pear.first = hist->Percent(pear.first);
235
236 // test for collision!
237 // if collision occurs then ignore this pair and move on
238 // to next pair
239 bool collision = false;
240 unsigned int k = 0;
241 while(!collision && k < converted.size()) {
242 if(pear.first == converted[k]) {
243 collision = true;
244 }
245 else {
246 k++;
247 }
248 }
249 if(!collision) {
250 Stretch::AddPair(pear.first, pear.second);
251 converted.push_back(pear.first);
252 }
253 }
254 }
255
256 catch(IException &e) {
257 throw IException(e, IException::User, "Invalid stretch pairs [" +
258 pairs + "]", _FILEINFO_);
259 }
260 }
261
262
268 QString Stretch::Text() const {
269
270 if(p_pairs < 0) return "";
271
272 QString p("");
273 for(int i = 0; i < p_pairs; i++) {
274 p += toString(p_input[i]) + ":" + toString(p_output[i]) + " ";
275 }
276 return p.trimmed();
277 }
278
287 double Stretch::Input(int index) const {
288 if(index >= p_pairs || index < 0) {
289 return -1;
290 }
291 return p_input[index];
292 }
293
302 double Stretch::Output(int index) const {
303 if(index >= p_pairs || index < 0) {
304 return -1;
305 }
306 return p_output[index];
307 }
308
323 void Stretch::Load(QString &file, QString &grpName) {
324 Pvl pvl(file);
325 Load(pvl, grpName);
326 }
327
342 void Stretch::Load(Isis::Pvl &pvl, QString &grpName) {
343 PvlGroup grp = pvl.findGroup(grpName, Isis::PvlObject::Traverse);
344 PvlKeyword inputs = grp.findKeyword("Input");
345 PvlKeyword outputs = grp.findKeyword("Output");
346
347 if(inputs.size() != outputs.size()) {
348 QString msg = "Invalid Pvl file: The number of Input values must equal the number of Output values";
349 throw IException(IException::User, msg, _FILEINFO_);
350 }
351 for(int i = 0; i < inputs.size(); i++) {
352 AddPair(toDouble(inputs[i]), toDouble(outputs[i]));
353 }
354 }
355
356
367 void Stretch::Save(QString &file, QString &grpName) {
368 Pvl p;
369 Save(p, grpName);
370 p.write(file);
371 }
372
373 void Stretch::Save(Isis::Pvl &pvl, QString &grpName) {
374 PvlGroup *grp = new PvlGroup(grpName);
375 PvlKeyword inputs("Input");
376 PvlKeyword outputs("Output");
377 for(int i = 0; i < Pairs(); i++) {
378 inputs.addValue(toString(Input(i)));
379 outputs.addValue(toString(Output(i)));
380 }
381 grp->addKeyword(inputs);
382 grp->addKeyword(outputs);
383 pvl.addGroup(*grp);
384 }
385
392 void Stretch::CopyPairs(const Stretch &other) {
393 this->p_pairs = other.p_pairs;
394 this->p_input = other.p_input;
395 this->p_output = other.p_output;
396 }
397} // end namespace isis
Container of a cube histogram.
Definition Histogram.h:74
Isis exception class.
Definition IException.h:91
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
Definition IException.h:126
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition IException.h:146
Contains multiple PvlContainers.
Definition PvlGroup.h:41
Container for cube-like labels.
Definition Pvl.h:119
A single keyword-value pair.
Definition PvlKeyword.h:87
@ Traverse
Search child objects.
Definition PvlObject.h:158
Pixel value mapper.
Definition Stretch.h:58
void CopyPairs(const Stretch &other)
Copies the stretch pairs from another Stretch object, but maintains special pixel values.
Definition Stretch.cpp:392
void Parse(const QString &pairs)
Parses a string of the form "i1:o1 i2:o2...iN:oN" where each i:o represents an input:output pair.
Definition Stretch.cpp:181
void AddPair(const double input, const double output)
Adds a stretch pair to the list of pairs.
Definition Stretch.cpp:48
int p_pairs
Number of stretch pairs.
Definition Stretch.h:62
double p_null
Mapping of input NULL values go to this value (default NULL)
Definition Stretch.h:64
Stretch()
Constructs a Stretch object with default mapping of special pixel values to themselves.
Definition Stretch.cpp:25
std::pair< double, double > NextPair(QString &pairs)
Given a string containing stretch pairs for example "0:0 50:0 100:255 255:255" evaluate the first pai...
Definition Stretch.cpp:145
std::vector< double > p_output
Array for output side of stretch pairs.
Definition Stretch.h:61
double p_lrs
Mapping of input LRS values go to this value (default LRS)
Definition Stretch.h:68
double Output(const int index) const
Returns the value of the output side of the stretch pair at the specified index.
Definition Stretch.cpp:302
double p_minimum
By default this value is set to p_lrs.
Definition Stretch.h:74
double Input(const int index) const
Returns the value of the input side of the stretch pair at the specified index.
Definition Stretch.cpp:287
double p_maximum
By default this value is set to p_hrs.
Definition Stretch.h:75
std::vector< double > p_input
Array for input side of stretch pairs.
Definition Stretch.h:60
double p_hrs
Mapping of input HRS values go to this value (default HRS)
Definition Stretch.h:72
double p_his
Mapping of input HIS values go to this value (default HIS)
Definition Stretch.h:70
double Map(const double value) const
Maps an input value to an output value based on the stretch pairs and/or special pixel mappings.
Definition Stretch.cpp:69
int Pairs() const
Returns the number of stretch pairs.
Definition Stretch.h:162
void Load(Pvl &pvl, QString &grpName)
Loads the stretch pairs from the pvl file into the Stretch object.
Definition Stretch.cpp:342
double p_lis
Mapping of input LIS values go to this value (default LIS)
Definition Stretch.h:66
QString Text() const
Converts stretch pair to a string.
Definition Stretch.cpp:268
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition IString.cpp:211
bool IsNullPixel(const double d)
Returns if the input pixel is null.
bool IsHrsPixel(const double d)
Returns if the input pixel is high representation saturation.
bool IsValidPixel(const double d)
Returns if the input pixel is valid.
const double Null
Value for an Isis Null pixel.
bool IsHisPixel(const double d)
Returns if the input pixel is high instrument saturation.
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition IString.cpp:149
bool IsLisPixel(const double d)
Returns if the input pixel is low instrument saturation.
Namespace for the standard library.