Official websites use .gov
A .gov website belongs to an official government organization in the United States.

Secure .gov websites use HTTPS
A lock ( ) or https:// means you’ve safely connected to the .gov website. Share sensitive information only on official, secure websites.

Isis 3 Programmer Reference
Stretch.cpp
1
5
6/* SPDX-License-Identifier: CC0-1.0 */
7#include <iostream>
8
9#include <QDebug>
10#include <QRegularExpression>
11
12#include "Stretch.h"
13#include "Histogram.h"
14#include "IString.h"
15#include "SpecialPixel.h"
16#include "IException.h"
17#include "Pvl.h"
18
19using namespace std;
20namespace Isis {
21
27 p_null = Isis::NULL8;
28 p_lis = Isis::LOW_INSTR_SAT8;
29 p_lrs = Isis::LOW_REPR_SAT8;
30 p_his = Isis::HIGH_INSTR_SAT8;
31 p_hrs = Isis::HIGH_REPR_SAT8;
34 p_pairs = 0;
35 }
36
37
49 void Stretch::AddPair(const double input, const double output) {
50 if(p_pairs > 0) {
51 if(input <= p_input[p_pairs-1]) {
52 string msg = "Input pairs must be in ascending order";
53 throw IException(IException::Programmer, msg, _FILEINFO_);
54 }
55 }
56
57 p_input.push_back(input);
58 p_output.push_back(output);
59 p_pairs++;
60 }
61
70 double Stretch::Map(const double value) const {
71 // Check special pixels first
72 if(!Isis::IsValidPixel(value)) {
73 if(Isis::IsNullPixel(value)) return p_null;
74 if(Isis::IsHisPixel(value)) return p_his;
75 if(Isis::IsHrsPixel(value)) return p_hrs;
76 if(Isis::IsLisPixel(value)) return p_lis;
77 return p_lrs;
78 }
79
80 // Check to see if we have any pairs
81 if(p_input.size() == 0) return value;
82
83 // Check to see if outside the minimum and maximum next
84 if(value < p_input[0]) {
85 if(!Isis::IsValidPixel(p_minimum)) {
86 if(Isis::IsNullPixel(p_minimum)) return p_null;
87 if(Isis::IsHisPixel(p_minimum)) return p_his;
88 if(Isis::IsHrsPixel(p_minimum)) return p_hrs;
89 if(Isis::IsLisPixel(p_minimum)) return p_lis;
90 return p_lrs;
91 }
92 return p_minimum;
93 }
94
95 if(value > p_input[p_pairs-1]) {
96 if(!Isis::IsValidPixel(p_maximum)) {
97 if(Isis::IsNullPixel(p_maximum)) return p_null;
98 if(Isis::IsHisPixel(p_maximum)) return p_his;
99 if(Isis::IsHrsPixel(p_maximum)) return p_hrs;
100 if(Isis::IsLisPixel(p_maximum)) return p_lis;
101 return p_lrs;
102 }
103 return p_maximum;
104 }
105
106 // Check the end points
107 if(value == p_input[0]) return p_output[0];
108 if(value == p_input[p_pairs-1]) return p_output[p_pairs-1];
109
110 // Ok find the surrounding pairs with a binary search
111 int start = 0;
112 int end = p_pairs - 1;
113 while(start != end) {
114 int middle = (start + end) / 2;
115
116 if(middle == start) {
117 end = middle;
118 }
119 else if(value < p_input[middle]) {
120 end = middle;
121 }
122 else {
123 start = middle;
124 }
125 }
126
127 end = start + 1;
128
129 // Apply the stretch
130 double slope = (p_output[end] - p_output[start]) / (p_input[end] - p_input[start]);
131 return slope * (value - p_input[end]) + p_output[end];
132 }
133
146 std::pair<double, double> Stretch::NextPair(QString &pairs) {
147 std::pair<double, double> io;
148 io.first = Null;
149 io.second = Null;
150
151 pairs = pairs.simplified().trimmed();
152
153 if (pairs.contains(":")) {
154 QStringList pairList = pairs.split(" ");
155
156 QString firstPair = pairList.takeFirst();
157
158 QStringList firstPairValues = firstPair.split(":");
159
160 if (firstPairValues.count() == 2) {
161 io.first = toDouble(firstPairValues.first());
162 io.second = toDouble(firstPairValues.last());
163
164 pairs = pairList.join(" ");
165 }
166 }
167
168 return io;
169 }
170
182 void Stretch::Parse(const QString &pairs) {
183 // Zero out the stretch arrays
184 p_input.clear();
185 p_output.clear();
186 p_pairs = 0;
187
188 std::pair<double, double> pear;
189
190 QString p = pairs.simplified().trimmed();
191 p.replace(QRegularExpression("[\\s]*:"), ":");
192 p.replace(QRegularExpression(":[\\s]*"), ":");
193 QStringList pairList = p.split(" ", Qt::SkipEmptyParts);
194
195 try {
196 foreach(QString singlePair, pairList) {
197 pear = Stretch::NextPair(singlePair);
198 Stretch::AddPair(pear.first, pear.second);
199 }
200 }
201 catch(IException &e) {
202 throw IException(e, IException::User, "Invalid stretch pairs [" + pairs + "]", _FILEINFO_);
203 }
204 }
205
219 void Stretch::Parse(const QString &pairs, const Isis::Histogram *hist) {
220 // Zero out the stretch arrays
221 p_input.clear();
222 p_output.clear();
223 p_pairs = 0;
224
225 QString p(pairs);
226 std::pair<double, double> pear;
227
228 // need to save the input dn values in order to
229 // to detect collisions
230 std::vector<double> converted;
231
232 try {
233 while(p.size() > 0) {
234 pear = Stretch::NextPair(p);
235 pear.first = hist->Percent(pear.first);
236
237 // test for collision!
238 // if collision occurs then ignore this pair and move on
239 // to next pair
240 bool collision = false;
241 unsigned int k = 0;
242 while(!collision && k < converted.size()) {
243 if(pear.first == converted[k]) {
244 collision = true;
245 }
246 else {
247 k++;
248 }
249 }
250 if(!collision) {
251 Stretch::AddPair(pear.first, pear.second);
252 converted.push_back(pear.first);
253 }
254 }
255 }
256
257 catch(IException &e) {
258 throw IException(e, IException::User, "Invalid stretch pairs [" +
259 pairs + "]", _FILEINFO_);
260 }
261 }
262
263
269 QString Stretch::Text() const {
270
271 if(p_pairs < 0) return "";
272
273 QString p("");
274 for(int i = 0; i < p_pairs; i++) {
275 p += toString(p_input[i]) + ":" + toString(p_output[i]) + " ";
276 }
277 return p.trimmed();
278 }
279
288 double Stretch::Input(int index) const {
289 if(index >= p_pairs || index < 0) {
290 return -1;
291 }
292 return p_input[index];
293 }
294
303 double Stretch::Output(int index) const {
304 if(index >= p_pairs || index < 0) {
305 return -1;
306 }
307 return p_output[index];
308 }
309
324 void Stretch::Load(QString &file, QString &grpName) {
325 Pvl pvl(file);
326 Load(pvl, grpName);
327 }
328
343 void Stretch::Load(Isis::Pvl &pvl, QString &grpName) {
344 PvlGroup grp = pvl.findGroup(grpName, Isis::PvlObject::Traverse);
345 PvlKeyword inputs = grp.findKeyword("Input");
346 PvlKeyword outputs = grp.findKeyword("Output");
347
348 if(inputs.size() != outputs.size()) {
349 QString msg = "Invalid Pvl file: The number of Input values must equal the number of Output values";
350 throw IException(IException::User, msg, _FILEINFO_);
351 }
352 for(int i = 0; i < inputs.size(); i++) {
353 AddPair(toDouble(inputs[i]), toDouble(outputs[i]));
354 }
355 }
356
357
368 void Stretch::Save(QString &file, QString &grpName) {
369 Pvl p;
370 Save(p, grpName);
371 p.write(file);
372 }
373
374 void Stretch::Save(Isis::Pvl &pvl, QString &grpName) {
375 PvlGroup *grp = new PvlGroup(grpName);
376 PvlKeyword inputs("Input");
377 PvlKeyword outputs("Output");
378 for(int i = 0; i < Pairs(); i++) {
379 inputs.addValue(toString(Input(i)));
380 outputs.addValue(toString(Output(i)));
381 }
382 grp->addKeyword(inputs);
383 grp->addKeyword(outputs);
384 pvl.addGroup(*grp);
385 }
386
393 void Stretch::CopyPairs(const Stretch &other) {
394 this->p_pairs = other.p_pairs;
395 this->p_input = other.p_input;
396 this->p_output = other.p_output;
397 }
398} // end namespace isis
Container of a cube histogram.
Definition Histogram.h:74
double Percent(const double percent) const
Computes and returns the value at X percent of the histogram.
void CopyPairs(const Stretch &other)
Copies the stretch pairs from another Stretch object, but maintains special pixel values.
Definition Stretch.cpp:393
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:182
void AddPair(const double input, const double output)
Adds a stretch pair to the list of pairs.
Definition Stretch.cpp:49
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:26
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:146
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:303
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:288
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:70
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:343
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:269
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
QString toString(const LinearAlgebra::Vector &vector, int precision)
A global function to format LinearAlgebra::Vector as a QString with the given precision.
Namespace for the standard library.