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 
16 using namespace std;
17 
18 namespace 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());
38  m_gainLsq = new LeastSquares(*m_gainFunction);
39  m_offsetFunction = new BasisFunction("BasisFunction",
40  statsList.size(), statsList.size());
41  m_offsetLsq = new LeastSquares(*m_offsetFunction);
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 
56  OverlapNormalization::~OverlapNormalization() {
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 
90  OverlapNormalization::AddStatus OverlapNormalization::AddOverlap(
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 
147  void OverlapNormalization::Solve(SolutionType type,
148  LeastSquares::SolveMethod method) {
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++) {
212  m_offsets[i] = m_offsetFunction->Coefficient(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 }
Isis::Statistics
This class is used to accumulate statistics on double arrays.
Definition: Statistics.h:94
Isis::OverlapNormalization::SolutionType
SolutionType
Enumeration for whether user/programmer wants to calculate new gains, offsets, or both when solving.
Definition: OverlapNormalization.h:111
Isis::OverlapNormalization::Overlap::index1
int index1
Index corresponding to m_statsList for the first overlapping data set.
Definition: OverlapNormalization.h:186
Isis::Average
Functor for reduce using average functionality.
Definition: Reduce.h:107
Isis::BasisFunction
Generic linear equation class.
Definition: BasisFunction.h:48
Isis::OverlapNormalization::Overlap::area2
Statistics area2
Overlapping area for the second data set.
Definition: OverlapNormalization.h:180
Isis::Statistics::ValidPixels
BigInt ValidPixels() const
Returns the total number of valid pixels processed.
Definition: Statistics.cpp:433
Isis::LeastSquares::SolveMethod
SolveMethod
Definition: LeastSquares.h:112
Isis::IsSpecial
bool IsSpecial(const double d)
Returns if the input pixel is special.
Definition: SpecialPixel.h:197
Isis::LeastSquares
Generic least square fitting class.
Definition: LeastSquares.h:99
Isis::OverlapNormalization::Overlap
Store statistics pertaining to the overlapping areas and indices (corresponding to the statistics lis...
Definition: OverlapNormalization.h:169
Isis::OverlapNormalization::AddStatus
AddStatus
The result of the attempt to add overlap data to the list of valid overlaps, where Success is a succe...
Definition: OverlapNormalization.h:75
Isis::Statistics::StandardDeviation
double StandardDeviation() const
Computes and returns the standard deviation.
Definition: Statistics.cpp:312
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::Statistics::Average
double Average() const
Computes and returns the average.
Definition: Statistics.cpp:300
std
Namespace for the standard library.
Isis::OverlapNormalization::Overlap::index2
int index2
Index corresponding to m_statsList for the second overlapping data set.
Definition: OverlapNormalization.h:192
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16
Isis::OverlapNormalization::Overlap::area1
Statistics area1
Overlapping area for the first data set.
Definition: OverlapNormalization.h:175