Isis 3 Programmer Reference
OverlapNormalization.cpp
1
6/* SPDX-License-Identifier: CC0-1.0 */
7#include "OverlapNormalization.h"
8
9#include <iomanip>
10
11#include "BasisFunction.h"
12#include "IException.h"
13#include "LeastSquares.h"
14#include "Statistics.h"
15
16using namespace std;
17
18namespace Isis {
19
29 OverlapNormalization::OverlapNormalization(std::vector<Statistics *> statsList) {
30 m_gainFunction = NULL;
31 m_gainLsq = NULL;
32 m_offsetFunction = NULL;
33 m_offsetLsq = NULL;
34
35 m_statsList = statsList;
36 m_gainFunction = new BasisFunction("BasisFunction",
37 statsList.size(), statsList.size());
39 m_offsetFunction = new BasisFunction("BasisFunction",
40 statsList.size(), statsList.size());
42
43 m_gains.resize(statsList.size());
44 m_offsets.resize(statsList.size());
45 for (unsigned int i = 0; i < statsList.size(); i++) {
46 m_gains[i] = 1.0;
47 m_offsets[i] = 0.0;
48 }
49 m_solved = false;
50 }
51
57 if (m_gainFunction != NULL) delete m_gainFunction;
58 if (m_offsetFunction != NULL) delete m_offsetFunction;
59 if (m_gainLsq != NULL) delete m_gainLsq;
60 if (m_offsetLsq != NULL) delete m_offsetLsq;
61 for (unsigned int i = 0; i < m_statsList.size(); i++) delete m_statsList[i];
62 };
63
91 const Statistics &area1, const unsigned index1,
92 const Statistics &area2, const unsigned index2,
93 double weight) {
94 if (index1 >= m_statsList.size()) {
95 string msg = "The index 1 is outside the bounds of the list.";
96 throw IException(IException::Programmer, msg, _FILEINFO_);
97 }
98 if (index2 >= m_statsList.size()) {
99 string msg = "The index 2 is outside the bounds of the list.";
100 throw IException(IException::Programmer, msg, _FILEINFO_);
101 }
102
103 // If there is no overlapping area, then the overlap is invalid
104 if (area1.ValidPixels() == 0 || area2.ValidPixels() == 0) {
105 return NoOverlap;
106 }
107
108 // The weight must be a positive real number
109 if (weight <= 0.0) {
110 string msg = "All weights must be positive real numbers.";
111 throw IException(IException::Programmer, msg, _FILEINFO_);
112 }
113
115 o.area1 = area1;
116 o.area2 = area2;
117 o.index1 = index1;
118 o.index2 = index2;
119
120 double avg1 = area1.Average();
121 double avg2 = area2.Average();
122
123 // Averages must not be 0 to avoid messing up least squares
124 if (avg1 == 0 || avg2 == 0) return NoContrast;
125
126 m_overlapList.push_back(o);
127 m_deltas.push_back(avg2 - avg1);
128 m_weights.push_back(weight);
129 m_solved = false;
130 return Success;
131 }
132
149 // Make sure that there is at least one overlap
150 if (m_overlapList.size() == 0) {
151 string msg = "None of the input images overlap";
152 throw IException(IException::User, msg, _FILEINFO_);
153 }
154
155 // Make sure the number of valid overlaps + hold images is greater than the
156 // number of input images (otherwise the least squares equation will be
157 // unsolvable due to having more unknowns than knowns)
158 if (m_overlapList.size() + m_idHoldList.size() < m_statsList.size()) {
159 string msg = "Unable to normalize overlaps. The number of overlaps and "
160 "holds must be greater than the number of input images";
161 throw IException(IException::User, msg, _FILEINFO_);
162 }
163
164 if ( method == LeastSquares::SPARSE ) {
165 m_offsetLsq = NULL;
166 m_gainLsq = NULL;
167 delete m_offsetLsq;
168 delete m_gainLsq;
169 int sparseMatrixRows = m_overlapList.size() + m_idHoldList.size();
170 int sparseMatrixCols = m_offsetFunction->Coefficients();
171 m_offsetLsq = new LeastSquares(*m_offsetFunction, true, sparseMatrixRows, sparseMatrixCols, true);
172 sparseMatrixCols = m_gainFunction->Coefficients();
173 m_gainLsq = new LeastSquares(*m_gainFunction, true, sparseMatrixRows, sparseMatrixCols, true);
174 const std::vector<double> alphaWeight(sparseMatrixCols, 1/1000.0);
175 m_offsetLsq->SetParameterWeights( alphaWeight );
176 m_gainLsq->SetParameterWeights( alphaWeight );
177 }
178
179 // Calculate offsets
180 if (type != Gains && type != GainsWithoutNormalization) {
181 // Add knowns to least squares for each overlap
182 for (int overlap = 0; overlap < (int)m_overlapList.size(); overlap++) {
183 Overlap curOverlap = m_overlapList[overlap];
184 int id1 = curOverlap.index1;
185 int id2 = curOverlap.index2;
186
187 vector<double> input;
188 input.resize(m_statsList.size());
189 for (int i = 0; i < (int)input.size(); i++) input[i] = 0.0;
190 input[id1] = 1.0;
191 input[id2] = -1.0;
192
193 m_offsetLsq->AddKnown(input, m_deltas[overlap], m_weights[overlap]);
194 }
195
196 // Add a known to the least squares for each hold image
197 for (int h = 0; h < (int)m_idHoldList.size(); h++) {
198 int hold = m_idHoldList[h];
199
200 vector<double> input;
201 input.resize(m_statsList.size());
202 for (int i = 0; i < (int)input.size(); i++) input[i] = 0.0;
203 input[hold] = 1.0;
204 m_offsetLsq->AddKnown(input, 0.0, 1e30);
205 }
206
207 // Solve the least squares and get the offset coefficients to apply to the
208 // images
209 m_offsets.resize(m_statsList.size());
210 m_offsetLsq->Solve(method);
211 for (int i = 0; i < m_offsetFunction->Coefficients(); i++) {
213 }
214 }
215
216 // Calculate Gains
217 if (type != Offsets) {
218 // Add knowns to least squares for each overlap
219 for (int overlap = 0; overlap < (int)m_overlapList.size(); overlap++) {
220 Overlap curOverlap = m_overlapList[overlap];
221 int id1 = curOverlap.index1;
222 int id2 = curOverlap.index2;
223
224 vector<double> input;
225 input.resize(m_statsList.size());
226 for (int i = 0; i < (int)input.size(); i++) input[i] = 0.0;
227 input[id1] = 1.0;
228 input[id2] = -1.0;
229
230 double tanp;
231
232 if (type != GainsWithoutNormalization) {
233 if (curOverlap.area1.StandardDeviation() == 0.0) {
234 tanp = 0.0; // Set gain to 1.0
235 }
236 else {
237 tanp = curOverlap.area2.StandardDeviation()
238 / curOverlap.area1.StandardDeviation();
239 }
240 }
241 else {
242 if (curOverlap.area1.Average() == 0.0) {
243 tanp = 0.0;
244 }
245 else {
246 tanp = curOverlap.area2.Average() / curOverlap.area1.Average();
247 }
248 }
249
250 if (tanp > 0.0) {
251 m_gainLsq->AddKnown(input, log(tanp), m_weights[overlap]);
252 }
253 else {
254 m_gainLsq->AddKnown(input, 0.0, 1e10); // Set gain to 1.0
255 }
256 }
257
258 // Add a known to the least squares for each hold image
259 for (int h = 0; h < (int)m_idHoldList.size(); h++) {
260 int hold = m_idHoldList[h];
261
262 vector<double> input;
263 input.resize(m_statsList.size());
264 for (int i = 0; i < (int)input.size(); i++) input[i] = 0.0;
265 input[hold] = 1.0;
266 m_gainLsq->AddKnown(input, 0.0, 1e10);
267 }
268
269 // Solve the least squares and get the gain coefficients to apply to the
270 // images
271 m_gains.resize(m_statsList.size());
272 m_gainLsq->Solve(method);
273 for (int i = 0; i < m_gainFunction->Coefficients(); i++) {
274 m_gains[i] = exp(m_gainFunction->Coefficient(i));
275 }
276 }
277
278 m_solved = true;
279 }
280
293 double OverlapNormalization::Average(const unsigned index) const {
294 if (index >= m_statsList.size()) {
295 string msg = "The index was out of bounds for the list of statistics.";
296 throw IException(IException::Programmer, msg, _FILEINFO_);
297 }
298
299 return m_statsList[index]->Average();
300 }
301
314 double OverlapNormalization::Gain(const unsigned index) const {
315 if (index >= m_statsList.size()) {
316 string msg = "The index was out of bounds for the list of statistics.";
317 throw IException(IException::Programmer, msg, _FILEINFO_);
318 }
319
320 return m_gains[index];
321 }
322
335 double OverlapNormalization::Offset(const unsigned index) const {
336 if (index >= m_statsList.size()) {
337 string msg = "The index was out of bounds for the list of statistics.";
338 throw IException(IException::Programmer, msg, _FILEINFO_);
339 }
340
341 return m_offsets[index];
342 }
343
358 double OverlapNormalization::Evaluate(double dn, unsigned index) const {
359 if (!m_solved) {
360 string msg = "The least squares equation has not been successfully ";
361 msg += "solved yet.";
362 throw IException(IException::Programmer, msg, _FILEINFO_);
363 }
364
365 if (Isis::IsSpecial(dn)) return dn;
366 return (dn - Average(index)) * Gain(index) + Average(index) + Offset(index);
367 }
368}
Generic linear equation class.
int Coefficients() const
Returns the number of coefficients for the equation.
double Coefficient(int i) const
Returns the ith coefficient.
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
Generic least square fitting class.
int Solve(Isis::LeastSquares::SolveMethod method=SVD)
After all the data has been registered through AddKnown, invoke this method to solve the system of eq...
void AddKnown(const std::vector< double > &input, double expected, double weight=1.0)
Invoke this method for each set of knowns.
Store statistics pertaining to the overlapping areas and indices (corresponding to the statistics lis...
int index1
Index corresponding to m_statsList for the first overlapping data set.
Statistics area1
Overlapping area for the first data set.
std::vector< double > m_gains
Vector of calculated gains filled by the Solve method.
std::vector< int > m_idHoldList
Vector of indices corresponding to the m_statsList vector representing data sets to be held in soluti...
OverlapNormalization(std::vector< Statistics * > statsList)
Constructs an OverlapNormalization object.
std::vector< double > m_weights
Vector of weights for every valid overlap.
bool m_solved
Whether or not the least squares solution has been solved.
BasisFunction * m_offsetFunction
The offset function to be solved.
double Offset(const unsigned index) const
Returns the calculated offset (base) for the given data set.
std::vector< double > m_deltas
Vector of delta values (differences between the averages of two overlapping data sets) for every vali...
LeastSquares * m_offsetLsq
The least squares object that calculates offsets.
BasisFunction * m_gainFunction
The gain function to be solved.
std::vector< Overlap > m_overlapList
Vector of valid overlaps collected.
double Average(const unsigned index) const
Returns the calculated average DN value for the given data set.
std::vector< double > m_offsets
Vector of calculated offsets filled by the Solve method.
virtual ~OverlapNormalization()
Destroys the OverlapNormalization object, frees up pointers.
AddStatus AddOverlap(const Statistics &area1, const unsigned index1, const Statistics &area2, const unsigned index2, double weight=1.0)
Attempts to add the given overlap data to a collection of valid overlaps, and returns the success or ...
SolutionType
Enumeration for whether user/programmer wants to calculate new gains, offsets, or both when solving.
@ Offsets
Calculate only the offsets.
@ Gains
Calculate only the gains.
@ GainsWithoutNormalization
The equation being solved for Gains, Offsets, and Both is output = (input - average) * gain + offset ...
AddStatus
The result of the attempt to add overlap data to the list of valid overlaps, where Success is a succe...
@ NoOverlap
Data sets do not overlap one another.
@ Success
Overlap is valid and was added successfully.
@ NoContrast
One or both areas contain no valid average.
std::vector< Statistics * > m_statsList
Vector of Statistics objects for each data set.
double Evaluate(double dn, unsigned index) const
Returns a new DN from an old using the calculated gains and offsets of the data set the pixel belongs...
LeastSquares * m_gainLsq
The least squares object that solves for the new gains.
double Gain(const unsigned index) const
Returns the calculated gain (multiplier) for the given data set.
void Solve(SolutionType type=Both, LeastSquares::SolveMethod method=LeastSquares::QRD)
Attempts to solve the least squares equation for all data sets.
This class is used to accumulate statistics on double arrays.
Definition Statistics.h:94
double Average() const
Computes and returns the average.
BigInt ValidPixels() const
Returns the total number of valid pixels processed.
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
bool IsSpecial(const double d)
Returns if the input pixel is special.
Namespace for the standard library.