Isis 3 Programmer Reference
Equalization.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 #include "Equalization.h"
8 
9 #include <iomanip>
10 #include <vector>
11 
12 #include <QString>
13 #include <QStringList>
14 #include <QVector>
15 
16 #include "Buffer.h"
17 #include "Cube.h"
18 #include "FileList.h"
19 #include "IException.h"
20 #include "LeastSquares.h"
21 #include "LineManager.h"
22 #include "OverlapNormalization.h"
23 #include "OverlapStatistics.h"
24 #include "Process.h"
25 #include "ProcessByLine.h"
26 #include "Projection.h"
27 #include "Pvl.h"
28 #include "PvlGroup.h"
29 #include "PvlObject.h"
30 #include "Statistics.h"
31 
32 using namespace std;
33 
34 namespace Isis {
35 
36 
40  Equalization::Equalization() {
41  init();
42  }
43 
44 
52  Equalization::Equalization(OverlapNormalization::SolutionType sType, QString fromListName) {
53  init();
54 
55  m_sType = sType;
56  loadInputs(fromListName);
57  }
58 
59 
63  Equalization::~Equalization() {
64  clearAdjustments();
65  clearNormalizations();
66  clearOverlapStatistics();
67 
68  if (m_results != NULL) {
69  delete m_results;
70  m_results = NULL;
71  }
72  }
73 
74 
84  void Equalization::addHolds(QString holdListName) {
85  FileList holdList;
86  holdList.read(FileName(holdListName));
87 
88  if (holdList.size() > m_imageList.size()) {
89  QString msg = "The list of identifiers to be held must be less than or ";
90  msg += "equal to the total number of identitifers.";
91  throw IException(IException::User, msg, _FILEINFO_);
92  }
93 
94  // Make sure each file in the holdlist matches a file in the fromlist
95  for (int i = 0; i < holdList.size(); i++) {
96  bool matched = false;
97  for (int j = 0; j < m_imageList.size(); j++) {
98  if (holdList[i] == m_imageList[j]) {
99  matched = true;
100  m_holdIndices.push_back(j);
101  break;
102  }
103  }
104  if (!matched) {
105  QString msg = "The hold list file [" + holdList[i].toString() +
106  "] does not match a file in the from list";
107  throw IException(IException::User, msg, _FILEINFO_);
108  }
109  }
110  }
111 
112 
136  void Equalization::calculateStatistics(double percent, int mincnt, bool wtopt,
137  LeastSquares::SolveMethod methodType) {
138 
139  // We're going to redetermine which file are non-overlapping (if recalculating)
140  m_badFiles.clear();
141 
142  m_mincnt = mincnt;
143  m_samplingPercent = percent;
144  m_wtopt = wtopt;
145  m_lsqMethod = methodType;
146 
147  // Calculate statistics for each image+band (they've already been calculated if recalculating)
148  if (!m_recalculating) {
149  calculateBandStatistics();
150  }
151 
152  calculateOverlapStatistics();
153 
154  // We can't solve the normalizations if we have invalid overlaps
155  for (int img = 0; img < m_imageList.size(); img++) {
156  // Record name of each input cube without an overlap
157  if (!m_doesOverlapList[img]) {
158  m_badFiles += m_imageList[img].toString();
159  }
160  }
161  if (!m_badFiles.isEmpty()) {
162  // Make sure we set the results for the already calculated overlap statistics
163  setResults();
164 
165  QString msg;
166  // Let user know where to find list of non-overlapping files so they can make corrections.
167  msg = "There are input images that do not overlap with enough valid pixels. ";
168  msg += "See application log or \"NonOverlaps\" keyword in output statistics file.";
169  throw IException(IException::User, msg, _FILEINFO_);
170  }
171 
172  // Loop through each band making all necessary calculations
173  try {
174  for (int band = 0; band < m_maxBand; band++) {
175  m_overlapNorms[band]->Solve(m_sType, methodType);
176 
177  for (unsigned int img = 0; img < m_adjustments.size(); img++) {
178  m_adjustments[img]->addGain(m_overlapNorms[band]->Gain(img));
179  if (qFuzzyCompare(m_overlapNorms[band]->Gain(img), 0.0)) { // if gain == 0
180  cout << img << endl;
181  cout << band << endl;
182  cout << m_overlapNorms[band]->Gain(img) << endl;
183  setResults();
184  throw IException(IException::Unknown,
185  "Calculation for equalization statistics failed. Gain = 0.",
186  _FILEINFO_);
187  }
188  m_adjustments[img]->addOffset(m_overlapNorms[band]->Offset(img));
189  m_adjustments[img]->addAverage(m_overlapNorms[band]->Average(img));
190  }
191  }
192  m_normsSolved = true;
193  }
194  catch (IException &e) {
195  setResults();
196  QString msg = "Unable to calculate the equalization statistics. You may "
197  "want to try another LeastSquares::SolveMethod.";
198  throw IException(e, IException::Unknown, msg, _FILEINFO_);
199  }
200 
201  setResults();
202  }
203 
204 
212  void Equalization::calculateBandStatistics() {
213  // Loop through all the input cubes, calculating statistics for each cube
214  // to use later
215  for (int band = 1; band <= m_maxBand; band++) {
216  // OverlapNormalization will take ownership of these pointers
217  vector<Statistics *> statsList;
218  for (int img = 0; img < (int) m_imageList.size(); img++) {
219  ProcessByLine p;
220  QString bandStr(toString(band));
221  QString statMsg = "Calculating Statistics for Band " + bandStr +
222  " of " + toString(m_maxBand) + " in Cube " + toString(img + 1) +
223  " of " + toString(m_maxCube);
224  p.Progress()->SetText(statMsg);
225  CubeAttributeInput att("+" + bandStr);
226  QString inp = m_imageList[img].toString();
227  p.SetInputCube(inp, att);
228 
229  Statistics *stats = new Statistics();
230 
231  CalculateFunctor func(stats, m_samplingPercent);
232  p.ProcessCubeInPlace(func, false);
233  p.EndProcess();
234 
235  statsList.push_back(stats);
236  }
237 
238  // Create a separate OverlapNormalization object for every band
239  OverlapNormalization *oNorm = new OverlapNormalization(statsList);
240  loadHolds(oNorm);
241  m_overlapNorms.push_back(oNorm);
242  }
243  }
244 
245 
252  void Equalization::calculateOverlapStatistics() {
253  // Add adjustments for all input images
254  for (int img = 0; img < m_imageList.size(); img++) {
255  addAdjustment(new ImageAdjustment(m_sType));
256  }
257 
258  // Find overlapping areas and add them to the set of known overlaps for
259  // each band shared amongst cubes
260  for (int i = 0; i < m_imageList.size(); i++) {
261  Cube cube1;
262  cube1.open(m_imageList[i].toString());
263 
264  for (int j = (i + 1); j < m_imageList.size(); j++) {
265  // Skip if overlap already calculated
266  if (m_alreadyCalculated[i] == true && m_alreadyCalculated[j] == true) {
267  //cout << " *** Cube " << i << " vs Cube " << j << " already calculated." << endl;
268  //cout << endl << " " << i << " = " << m_imageList[i].toString() << " ; " << j
269  // << " = " << m_imageList[j].toString() << endl << endl;
270  continue;
271  }
272 
273  Cube cube2;
274  cube2.open(m_imageList[j].toString());
275  QString cubeStr1 = toString((int)(i + 1));
276  QString cubeStr2 = toString((int)(j + 1));
277  QString statMsg = "Gathering Overlap Statisitcs for Cube " +
278  cubeStr1 + " vs " + cubeStr2 + " of " +
279  toString(m_maxCube);
280 
281  // Get overlap statistics for new cubes
282  OverlapStatistics *oStats = new OverlapStatistics(cube1, cube2, statMsg, m_samplingPercent);
283  // Only push the stats onto the overlap statistics vector if there is an overlap in at
284  // least one of the bands
285  if (oStats->HasOverlap()) {
286  m_overlapStats.push_back(oStats);
287  oStats->SetMincount(m_mincnt);
288  for (int band = 1; band <= m_maxBand; band++) {
289  // Fill wt vector with 1's if the overlaps are not to be weighted, or
290  // fill the vector with the number of valid pixels in each overlap
291  int weight = 1;
292  if (m_wtopt) weight = oStats->GetMStats(band).ValidPixels();
293 
294  // Make sure overlap has at least MINCOUNT valid pixels and add
295  if (oStats->GetMStats(band).ValidPixels() >= m_mincnt) {
296  m_overlapNorms[band - 1]->AddOverlap(
297  oStats->GetMStats(band).X(), i,
298  oStats->GetMStats(band).Y(), j, weight);
299  m_doesOverlapList[i] = true;
300  m_doesOverlapList[j] = true;
301  }
302  }
303  }
304  }
305  }
306 
307  // Compute the number valid and invalid overlaps
308  for (unsigned int o = 0; o < m_overlapStats.size(); o++) {
309  for (int band = 1; band <= m_maxBand; band++) {
310  (m_overlapStats[o]->IsValid(band)) ? m_validCnt++ : m_invalidCnt++;
311  }
312  }
313  }
314 
315 
324  void Equalization::setResults() {
325  if (m_results != NULL) {
326  delete m_results;
327  m_results = NULL;
328  }
329 
330  m_results = new Pvl();
331  m_results->setTerminator("");
332 
333  PvlObject equ("EqualizationInformation");
334  PvlGroup gen("General");
335  gen += PvlKeyword("TotalOverlaps", toString(m_validCnt + m_invalidCnt));
336  gen += PvlKeyword("ValidOverlaps", toString(m_validCnt));
337  gen += PvlKeyword("InvalidOverlaps", toString(m_invalidCnt));
338  gen += PvlKeyword("MinCount", toString(m_mincnt));
339  gen += PvlKeyword("SamplingPercent", toString(m_samplingPercent));
340  gen += PvlKeyword("Weighted", (m_wtopt) ? "true" : "false");
341  int solType = m_sType;
342  int lsqMethod = m_lsqMethod;
343  gen += PvlKeyword("SolutionType", toString(solType));
344  gen += PvlKeyword("SolveMethod" , toString(lsqMethod));
345  PvlKeyword nonOverlaps("NonOverlaps");
346  for (int img = 0; img < m_badFiles.size(); img++) {
347  nonOverlaps += m_badFiles[img];
348  }
349  gen += nonOverlaps;
350  gen += PvlKeyword("HasCorrections", (m_normsSolved) ? "true" : "false");
351  equ.addGroup(gen);
352 
353  // Add normalization statistics
354  for (int img = 0; img < m_imageList.size(); img++) {
355  // Format and name information
356  // It is important that the variable names are listed in the same
357  // order as they are added to the PvlKeyword in the for loop.
358  PvlGroup norm("Normalization");
359  switch(m_sType) {
360  case OverlapNormalization::Both:
361  norm.addComment("Formula: newDN = (oldDN - AVERAGE) * GAIN + AVERAGE + OFFSET");
362  norm.addComment("BandN = (GAIN, OFFSET, AVERAGE)");
363  break;
364  case OverlapNormalization::Gains:
365  norm.addComment("Formula: newDN = oldDN * GAIN + AVERAGE * GAIN");
366  norm.addComment("BandN = (GAIN, AVERAGE)");
367  break;
368  case OverlapNormalization::Offsets:
369  norm.addComment("Formula: newDN = OFFSET + AVERAGE");
370  norm.addComment("BandN = (OFFSET, AVERAGE)");
371  break;
372  case OverlapNormalization::GainsWithoutNormalization:
373  norm.addComment("Formula: newDN = oldDN * GAIN");
374  norm.addComment("BandN = (GAIN)");
375  break;
376  }
377  norm += PvlKeyword("FileName", m_imageList[img].original());
378 
379  if (m_normsSolved) {
380  // Band by band statistics
381  for (int band = 1; band <= m_maxBand; band++) {
382  QString bandNum = toString(band);
383  QString bandStr = "Band" + bandNum;
384  PvlKeyword bandStats(bandStr);
385  // GAIN
386  if (m_sType == OverlapNormalization::Both ||
387  m_sType == OverlapNormalization::Gains ||
388  m_sType == OverlapNormalization::GainsWithoutNormalization) {
389  bandStats += toString(m_adjustments[img]->getGain(band - 1));
390  }
391  // OFFSET
392  if (m_sType == OverlapNormalization::Both ||
393  m_sType == OverlapNormalization::Offsets) {
394  bandStats += toString(m_adjustments[img]->getOffset(band - 1));
395  }
396  // AVERAGE
397  if (m_sType == OverlapNormalization::Both ||
398  m_sType == OverlapNormalization::Gains ||
399  m_sType == OverlapNormalization::Offsets) {
400  bandStats += toString(m_adjustments[img]->getAverage(band - 1));
401  }
402  norm += bandStats;
403  }
404  }
405 
406  equ.addGroup(norm);
407  }
408 
409  m_results->addObject(equ);
410 
411  // Add overlap statistics
412  for (unsigned int i = 0; i < m_overlapStats.size(); i++) {
413  PvlObject oStat = m_overlapStats[i]->toPvl();
414  m_results->addObject(m_overlapStats[i]->toPvl());
415  }
416  }
417 
418 
428  void Equalization::recalculateStatistics(QString instatsFileName) {
429  m_recalculating = true;
430  Pvl inStats(instatsFileName);
431  fromPvl(inStats);
432  calculateStatistics(m_samplingPercent, m_mincnt, m_wtopt, m_lsqMethod);
433  }
434 
435 
447  void Equalization::importStatistics(QString instatsFileName) {
448 
449  // Check for errors with the input statistics
450  QVector<int> normIndices = validateInputStatistics(instatsFileName);
451  Pvl inStats(instatsFileName);
452  PvlObject &equalInfo = inStats.findObject("EqualizationInformation");
453  PvlGroup &general = equalInfo.findGroup("General");
454 
455  // Determine if normalizations were solved
456  // First condition allows backward compatibility so users can use old stats files
457  if (!general.hasKeyword("HasCorrections") || general["HasCorrections"][0] == "true") {
458  m_normsSolved = true;
459 
460  clearAdjustments();
461  for (int img = 0; img < (int) m_imageList.size(); img++) {
462  // Apply correction based on pre-determined statistics information
463  PvlGroup &normalization = equalInfo.group(normIndices[img]);
464 
465  // TODO should we also get the valid and invalid count?
466 
467  ImageAdjustment *adjustment = new ImageAdjustment(m_sType);
468 
469  // Get and store the modifiers for each band
470  for (int band = 1; band < normalization.keywords(); band++) {
471  adjustment->addGain(toDouble(normalization[band][0]));
472  adjustment->addOffset(toDouble(normalization[band][1]));
473  adjustment->addAverage(toDouble(normalization[band][2]));
474  }
475 
476  addAdjustment(adjustment);
477  }
478  }
479  else {
480  m_normsSolved = false;
481  }
482 
483  }
484 
485 
496  void Equalization::applyCorrection(QString toListName="") {
497  if (!isSolved()) {
498  QString msg = "Corrective factors have not yet been determined. ";
499  if (m_badFiles.size() > 0) {
500  msg += "Fix any non-overlapping images and recalculate the image statistics. ";
501  msg += "File(s) without overlaps: ";
502  for (int img = 0; img < m_badFiles.size(); img++) {
503  msg += " [" + m_badFiles[img] + "] ";
504  }
505  }
506  else {
507  msg += "Add more images to create more overlaps and recalculate, ";
508  msg += "or try another solve method.";
509  }
510  throw IException(IException::User, msg, _FILEINFO_);
511  }
512 
513  FileList outList;
514  fillOutList(outList, toListName);
515 
516  QString maxCubeStr = toString((int) m_imageList.size());
517  for (int img = 0; img < m_imageList.size(); img++) {
518  // Set up for progress bar
519  ProcessByLine p;
520  p.Progress()->SetText("Equalizing Cube " + toString((int) img + 1) +
521  " of " + maxCubeStr);
522 
523  // Open input cube
524  CubeAttributeInput att;
525  const QString inp = m_imageList[img].toString();
526  Cube *icube = p.SetInputCube(inp, att);
527 
528  // Allocate output cube
529  QString out = outList[img].toString();
530  CubeAttributeOutput outAtt;
531  p.SetOutputCube(out, outAtt, icube->sampleCount(),
532  icube->lineCount(), icube->bandCount());
533 
534  // Apply gain/offset to the image
535  ApplyFunctor func(m_adjustments[img]);
536  p.ProcessCube(func, false);
537  p.EndProcess();
538  }
539  }
540 
541 
549  PvlGroup Equalization::getResults() {
550  // TODO combine summary info into getSummary method and use with write
551  PvlGroup results = m_results->findObject("EqualizationInformation").findGroup("General");
552  if (m_normsSolved) {
553 
554  // Name and band modifiers for each image
555  for (int img = 0; img < m_imageList.size(); img++) {
556  results += PvlKeyword("FileName", m_imageList[img].toString());
557 
558  // Band by band statistics
559  for (int band = 1; band <= m_maxBand; band++) {
560  QString mult = toString(m_adjustments[img]->getGain(band - 1));
561  QString base = toString(m_adjustments[img]->getOffset(band - 1));
562  QString avg = toString(m_adjustments[img]->getAverage(band - 1));
563  QString bandNum = toString(band);
564  QString bandStr = "Band" + bandNum;
565  PvlKeyword bandStats(bandStr);
566  bandStats += mult;
567  bandStats += base;
568  bandStats += avg;
569  results += bandStats;
570  }
571  }
572  }
573  return results;
574  }
575 
576 
582  void Equalization::write(QString outstatsFileName) {
583  // Write the equalization and overlap statistics to the file
584  m_results->write(outstatsFileName);
585  }
586 
587 
588  double Equalization::evaluate(double dn, int imageIndex, int bandIndex) const {
589  return m_adjustments[imageIndex]->evaluate(dn, bandIndex);
590  }
591 
592 
602  void Equalization::loadInputs(QString fromListName) {
603  // Get the list of cubes to mosaic
604  m_imageList.read(fromListName);
605  m_maxCube = m_imageList.size();
606 
607  if (m_imageList.size() < 2) {
608  QString msg = "The input file [" + fromListName +
609  "] must contain at least 2 file names";
610  throw IException(IException::User, msg, _FILEINFO_);
611  }
612 
613  Cube tempCube;
614  tempCube.open(m_imageList[0].toString());
615  m_maxBand = tempCube.bandCount();
616 
617  m_doesOverlapList.resize(m_imageList.size(), false);
618  m_alreadyCalculated.resize(m_imageList.size(), false);
619 
620  errorCheck(fromListName);
621  }
622 
623 
624  void Equalization::setInput(int index, QString value) {
625  m_imageList[index] = value;
626  }
627 
628 
629  const FileList &Equalization::getInputs() const {
630  return m_imageList;
631  }
632 
633 
634  void Equalization::fillOutList(FileList &outList, QString toListName) {
635  if (toListName.isEmpty()) {
636  generateOutputs(outList);
637  }
638  else {
639  loadOutputs(outList, toListName);
640  }
641  }
642 
643 
650  void Equalization::errorCheck(QString fromListName) {
651  for (int i = 0; i < m_imageList.size(); i++) {
652  Cube cube1;
653  cube1.open(m_imageList[i].toString());
654 
655  for (int j = (i + 1); j < m_imageList.size(); j++) {
656  Cube cube2;
657  cube2.open(m_imageList[j].toString());
658 
659  // Make sure number of bands match
660  if (m_maxBand != cube2.bandCount()) {
661  QString msg = "Number of bands do not match between cubes [" +
662  m_imageList[i].toString() + "] and [" + m_imageList[j].toString() + "]";
663  throw IException(IException::User, msg, _FILEINFO_);
664  }
665 
666  //Create projection from each cube
667  Projection *proj1 = cube1.projection();
668  Projection *proj2 = cube2.projection();
669 
670  // Test to make sure projection parameters match
671  if (*proj1 != *proj2) {
672  QString msg = "Mapping groups do not match between cubes [" +
673  m_imageList[i].toString() + "] and [" + m_imageList[j].toString() + "]";
674  throw IException(IException::User, msg, _FILEINFO_);
675  }
676  }
677  }
678  }
679 
680 
684  void Equalization::generateOutputs(FileList &outList) {
685  for (int img = 0; img < m_imageList.size(); img++) {
686  FileName file(m_imageList[img]);
687  QString filename = file.path() + "/" + file.baseName() +
688  ".equ." + file.extension();
689  outList.push_back(FileName(filename));
690  }
691  }
692 
693 
702  void Equalization::loadOutputs(FileList &outList, QString toListName) {
703  outList.read(FileName(toListName));
704 
705  // Make sure each file in the tolist matches a file in the fromlist
706  if (outList.size() != m_imageList.size()) {
707  QString msg = "Each input file in the FROM LIST must have a ";
708  msg += "corresponding output file in the TO LIST.";
709  throw IException(IException::User, msg, _FILEINFO_);
710  }
711 
712  // Make sure that all output files do not have the same names as their
713  // corresponding input files
714  for (int i = 0; i < outList.size(); i++) {
715  if (outList[i].toString().compare(m_imageList[i].toString()) == 0) {
716  QString msg = "The to list file [" + outList[i].toString() +
717  "] has the same name as its corresponding from list file.";
718  throw IException(IException::User, msg, _FILEINFO_);
719  }
720  }
721  }
722 
723 
724  void Equalization::loadHolds(OverlapNormalization *oNorm) {
725  for (unsigned int h = 0; h < m_holdIndices.size(); h++)
726  oNorm->AddHold(m_holdIndices[h]);
727  }
728 
729 
733  void Equalization::clearAdjustments() {
734  for (unsigned int adj = 0; adj < m_adjustments.size(); adj++) {
735  delete m_adjustments[adj];
736  }
737  m_adjustments.clear();
738  }
739 
740 
748  void Equalization::addAdjustment(ImageAdjustment *adjustment) {
749  m_adjustments.push_back(adjustment);
750  }
751 
752 
756  void Equalization::clearNormalizations() {
757  for (unsigned int oNorm = 0; oNorm < m_overlapNorms.size(); oNorm++) {
758  delete m_overlapNorms[oNorm];
759  }
760  m_overlapNorms.clear();
761  }
762 
763 
767  void Equalization::clearOverlapStatistics() {
768  for (unsigned int oStat = 0; oStat < m_overlapStats.size(); oStat++) {
769  delete m_overlapStats[oStat];
770  }
771  m_overlapStats.clear();
772  }
773 
774 
780  void Equalization::addValid(int count) {
781  m_validCnt += count;
782  }
783 
784 
790  void Equalization::addInvalid(int count) {
791  m_invalidCnt += count;
792  }
793 
794 
803  void Equalization::fromPvl(const PvlObject &inStats) {
804 
805  // Make a copy of our image list with names only (instead of full path)
806  QList<QString> imgNames;
807  for (int img = 0; img < m_imageList.size(); img++) {
808  imgNames.append(m_imageList[img].name());
809  }
810 
811  // Load in previous user params
812  const PvlObject &eqInfo = inStats.findObject("EqualizationInformation");
813  const PvlGroup &eqGen = eqInfo.findGroup("General");
814  m_samplingPercent = eqGen["SamplingPercent"];
815  m_mincnt = eqGen["MinCount"];
816  m_wtopt = (eqGen["Weighted"][0] == "true") ? true : false;
817  m_sType = static_cast<OverlapNormalization::SolutionType>((int)eqGen["SolutionType"]);
818  m_lsqMethod = static_cast<LeastSquares::SolveMethod>(eqGen["SolveMethod"][0].toInt());
819 
820  // Unserialize previous overlap statistics
821  PvlObject::ConstPvlObjectIterator curObj = inStats.beginObject();
822  while (curObj < inStats.endObject()) {
823  if (curObj->isNamed("OverlapStatistics")) {
824  OverlapStatistics *o = new OverlapStatistics(*curObj);
825  m_overlapStats.push_back(o);
826 
827  const PvlObject &oStat = *curObj;
828  QString fileX = oStat["File1"][0];
829  QString fileY = oStat["File2"][0];
830 
831  // Determine already calculated overlaps
832  int x = imgNames.indexOf(fileX);
833  int y = imgNames.indexOf(fileY);
834  m_alreadyCalculated[x] = true;
835  m_alreadyCalculated[y] = true;
836 
837  // Determine which calculated overlaps have valid overlaps
838  // (i.e. valid pixels > mincount)
839  if (oStat["Valid"][0] == "true") {
840  m_doesOverlapList[x] = true;
841  m_doesOverlapList[y] = true;
842  }
843  }
844  curObj++;
845  }
846 
847  // Calculate the image+band statistics
848  calculateBandStatistics();
849 
850  // Calculate x/y indices that map the overlap x/y statistics to the input image index
851  // { {olap1idxX, olap1indxY}, {olap2idxX, olap12idxY} ... }
852  // vector< vector<int> > overlapIndices(m_overlapStats.size(),
853  // vector<int>(2));
854  //int overlapIndices[m_overlapStats.size()][2];
855  QVector< QVector<int> > overlapIndices(m_overlapStats.size());
856  for (int o = 0; o < (int) m_overlapStats.size(); o++) {
857  OverlapStatistics *oStat = m_overlapStats[o];
858 
859  // Calculate the indices - we want to ensure that no matter how the input list of images
860  // changes (e.g. the order is changed), we always add overlaps that same way.
861  // This means ensuring that each overlap has the X overlap statistics associated with
862  // the X index and the Y overlap statistics associated with the Y index.
863  for (int i = 0; i < m_imageList.size(); i++) {
864  QString imageName(m_imageList[i].name());
865 
866  // Always push the X file index to the front (0)
867  if (oStat->FileNameX() == imageName)
868  //overlapIndices[o].insert(overlapIndices[o].begin(), i);
869  //overlapIndices[o][0] = i;
870  overlapIndices[o].push_front(i);
871  // Always push the Y file index to the back (1)
872  if (oStat->FileNameY() == imageName)
873  //overlapIndices[o].push_back(i);
874  //overlapIndices[o][1] = i;
875  overlapIndices[o].push_back(i);
876  }
877  }
878 
879  // Add the overlap
880  for (int o = 0; o < (int) m_overlapStats.size(); o++) {
881  OverlapStatistics *oStat = m_overlapStats[o];
882  for (int band = 1; band <= oStat->Bands(); band++) {
883  int weight = 1;
884  if (m_wtopt) weight = oStat->GetMStats(band).ValidPixels();
885  if (oStat->GetMStats(band).ValidPixels() >= m_mincnt) {
886  m_overlapNorms[band-1]->AddOverlap(oStat->GetMStats(band).X(), overlapIndices[o][0],
887  oStat->GetMStats(band).Y(), overlapIndices[o][1], weight);
888  }
889  }
890  }
891  }
892 
893 
899  void Equalization::setSolved(bool solved) {
900  m_normsSolved = solved;
901  }
902 
903 
909  bool Equalization::isSolved() const {
910  return m_normsSolved;
911  }
912 
913 
917  void Equalization::init() {
918  m_validCnt = 0;
919  m_invalidCnt = 0;
920 
921  m_mincnt = 1000;
922  m_samplingPercent = 100.0;
923  m_wtopt = false;
924 
925  m_maxCube = 0;
926  m_maxBand = 0;
927 
928  m_sType = OverlapNormalization::Both;
929  m_lsqMethod = LeastSquares::SPARSE;
930 
931  m_badFiles.clear();
932  m_doesOverlapList.clear();
933  m_alreadyCalculated.clear();
934  m_normsSolved = false;
935  m_recalculating = false;
936 
937  m_results = NULL;
938  }
939 
940 
956  QVector<int> Equalization::validateInputStatistics(QString instatsFileName) {
957  QVector<int> normIndices;
958 
959  Pvl inStats(instatsFileName);
960  PvlObject &equalInfo = inStats.findObject("EqualizationInformation");
961 
962  // Make sure each file in the instats matches a file in the fromlist
963  if (m_imageList.size() > equalInfo.groups() - 1) {
964  QString msg = "Each input file in the FROM LIST must have a ";
965  msg += "corresponding input file in the INPUT STATISTICS.";
966  throw IException(IException::User, msg, _FILEINFO_);
967  }
968 
969  // Check that each file in the FROM LIST is present in the INPUT STATISTICS
970  for (int i = 0; i < m_imageList.size(); i++) {
971  QString fromFile = m_imageList[i].original();
972  bool foundFile = false;
973  for (int j = 1; j < equalInfo.groups(); j++) {
974  PvlGroup &normalization = equalInfo.group(j);
975  QString normFile = normalization["FileName"][0];
976  if (fromFile == normFile) {
977 
978  // Store the index in INPUT STATISTICS file corresponding to the
979  // current FROM LIST file
980  normIndices.push_back(j);
981  foundFile = true;
982  }
983  }
984  if (!foundFile) {
985  QString msg = "The from list file [" + fromFile +
986  "] does not have any corresponding file in the stats list.";
987  throw IException(IException::User, msg, _FILEINFO_);
988  }
989  }
990 
991  return normIndices;
992  }
993 
994 
995  void Equalization::CalculateFunctor::operator()(Buffer &in) const {
996  // Make sure we consider the last line
997  if ((in.Line() - 1) % m_linc == 0 || in.Line() == in.LineDimension()) {
998  addStats(in);
999  }
1000  }
1001 
1002 
1003  void Equalization::CalculateFunctor::addStats(Buffer &in) const {
1004  // Add data to Statistics object by line
1005  m_stats->AddData(&in[0], in.size());
1006  }
1007 
1008 
1009  void Equalization::ApplyFunctor::operator()(Buffer &in, Buffer &out) const {
1010  int index = in.Band() - 1;
1011  for (int i = 0; i < in.size(); i++) {
1012  out[i] = (IsSpecial(in[i])) ?
1013  in[i] : m_adjustment->evaluate(in[i], index);
1014  }
1015  }
1016 
1017 
1018 }
Isis::Statistics
This class is used to accumulate statistics on double arrays.
Definition: Statistics.h:94
Isis::PvlObject::findGroup
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition: PvlObject.h:129
Isis::PvlObject::group
PvlGroup & group(const int index)
Return the group at the specified index.
Definition: PvlObject.cpp:452
Isis::OverlapNormalization::SolutionType
SolutionType
Enumeration for whether user/programmer wants to calculate new gains, offsets, or both when solving.
Definition: OverlapNormalization.h:111
Isis::PvlObject
Contains Pvl Groups and Pvl Objects.
Definition: PvlObject.h:61
Isis::PvlKeyword
A single keyword-value pair.
Definition: PvlKeyword.h:82
Isis::Average
Functor for reduce using average functionality.
Definition: Reduce.h:107
Isis::ProcessByLine::ProcessCube
void ProcessCube(const Functor &funct, bool threaded=true)
Same functionality as StartProcess(void funct(Isis::Buffer &in, Isis::Buffer &out)) using Functors.
Definition: ProcessByLine.h:153
QList< QString >
Isis::MultivariateStatistics::Y
Isis::Statistics Y() const
Returns a Stats object for all of the Y data fed through the AddData method.
Definition: MultivariateStatistics.cpp:262
Isis::PvlObject::beginObject
PvlObjectIterator beginObject()
Returns the index of the beginning object.
Definition: PvlObject.h:235
Isis::OverlapStatistics::HasOverlap
bool HasOverlap(int band) const
Checks the specified band for an overlap.
Definition: OverlapStatistics.h:76
Isis::FileName
File name manipulation and expansion.
Definition: FileName.h:100
Isis::MultivariateStatistics::ValidPixels
BigInt ValidPixels() const
Returns the number of valid pixels processed.
Definition: MultivariateStatistics.cpp:201
Isis::PvlObject::groups
int groups() const
Returns the number of groups contained.
Definition: PvlObject.h:75
Isis::PvlObject::endObject
PvlObjectIterator endObject()
Returns the index of the ending object.
Definition: PvlObject.h:253
Isis::OverlapStatistics::Bands
int Bands() const
Returns the number of bands both cubes have.
Definition: OverlapStatistics.h:138
Isis::ProcessByBrick::SetOutputCube
virtual Cube * SetOutputCube(const QString &fname, const CubeAttributeOutput &att)
Create the output file.
Definition: ProcessByBrick.cpp:364
Isis::PvlContainer::hasKeyword
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
Definition: PvlContainer.cpp:159
Isis::Pvl
Container for cube-like labels.
Definition: Pvl.h:119
Isis::CubeAttributeOutput
Manipulate and parse attributes of output cube filenames.
Definition: CubeAttribute.h:473
Isis::PvlObject::addObject
void addObject(const PvlObject &object)
Add a PvlObject.
Definition: PvlObject.h:307
Isis::LeastSquares::SolveMethod
SolveMethod
Definition: LeastSquares.h:112
Isis::toString
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:211
Isis::IsSpecial
bool IsSpecial(const double d)
Returns if the input pixel is special.
Definition: SpecialPixel.h:197
Isis::ProcessByLine
Process cubes by line.
Definition: ProcessByLine.h:97
Isis::Buffer
Buffer for reading and writing cube data.
Definition: Buffer.h:53
Isis::MultivariateStatistics::X
Isis::Statistics X() const
Returns a Stats object for all of the X data fed through the AddData method.
Definition: MultivariateStatistics.cpp:252
Isis::ProcessByLine::ProcessCubeInPlace
void ProcessCubeInPlace(const Functor &funct, bool threaded=true)
Same functionality as StartProcess(void funct(Isis::Buffer &inout)) using Functors.
Definition: ProcessByLine.h:133
Isis::FileName::baseName
QString baseName() const
Returns the name of the file without the path and without extensions.
Definition: FileName.cpp:145
Isis::Equalization::ApplyFunctor
This class is used as a functor to apply adjustments (equalize) to an image.
Definition: Equalization.h:243
Isis::PvlGroup
Contains multiple PvlContainers.
Definition: PvlGroup.h:41
Isis::OverlapStatistics::FileNameY
Isis::FileName FileNameY() const
Returns the filename of the second cube.
Definition: OverlapStatistics.h:96
Isis::Cube::lineCount
int lineCount() const
Definition: Cube.cpp:1734
Isis::FileList::read
void read(FileName listFile)
reads in a FileName obj
Definition: FileList.cpp:52
Isis::Progress::SetText
void SetText(const QString &text)
Changes the value of the text string reported just before 0% processed.
Definition: Progress.cpp:61
Isis::OverlapNormalization
Calculate the bases and multipliers for normalizing overlapping "data sets" (e.g.,...
Definition: OverlapNormalization.h:61
Isis::Buffer::LineDimension
int LineDimension() const
Returns the number of lines in the shape buffer.
Definition: Buffer.h:79
Isis::Equalization::ImageAdjustment
Definition: Equalization.h:150
Isis::OverlapNormalization::AddHold
void AddHold(unsigned holdIndex)
Sets the list of files to be held during the solving process.
Definition: OverlapNormalization.h:103
Isis::PvlObject::findObject
PvlObjectIterator findObject(const QString &name, PvlObjectIterator beg, PvlObjectIterator end)
Find the index of object with a specified name, between two indexes.
Definition: PvlObject.h:274
Isis::Cube::sampleCount
int sampleCount() const
Definition: Cube.cpp:1807
Isis::Process::Progress
Isis::Progress * Progress()
This method returns a pointer to a Progress object.
Definition: Process.h:259
Isis::Cube
IO Handler for Isis Cubes.
Definition: Cube.h:167
Isis::Equalization::CalculateFunctor
This class is used as a functor calculate image statistics.
Definition: Equalization.h:210
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::Cube::bandCount
virtual int bandCount() const
Returns the number of virtual bands for the cube.
Definition: Cube.cpp:1410
Isis::PvlObject::addGroup
void addGroup(const Isis::PvlGroup &group)
Add a group to the object.
Definition: PvlObject.h:186
Isis::FileName::extension
QString extension() const
Returns the last extension of the file name.
Definition: FileName.cpp:178
Isis::toDouble
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition: IString.cpp:149
Isis::OverlapStatistics::SetMincount
void SetMincount(unsigned int mincnt)
Sets the minimum number of valid pixels for the overlap to be considered valid for PVL output.
Definition: OverlapStatistics.h:229
std
Namespace for the standard library.
Isis::OverlapStatistics
Calculates statistics in the area of overlap between two projected cubes.
Definition: OverlapStatistics.h:61
Isis::CubeAttributeInput
Manipulate and parse attributes of input cube filenames.
Definition: CubeAttribute.h:381
Isis::PvlContainer::keywords
int keywords() const
Returns the number of keywords contained in the PvlContainer.
Definition: PvlContainer.h:86
QVector< int >
Isis::OverlapStatistics::FileNameX
Isis::FileName FileNameX() const
Returns the filename of the first cube.
Definition: OverlapStatistics.h:87
Isis::Projection
Base class for Map Projections.
Definition: Projection.h:155
Isis::Cube::open
void open(const QString &cfile, QString access="r")
This method will open an isis cube for reading or reading/writing.
Definition: Cube.cpp:627
Isis::ProcessByBrick::EndProcess
void EndProcess()
End the processing sequence and cleans up by closing cubes, freeing memory, etc.
Definition: ProcessByBrick.cpp:669
Isis::FileList
Internalizes a list of files.
Definition: FileList.h:54
Isis::ProcessByLine::SetInputCube
Isis::Cube * SetInputCube(const QString &parameter, const int requirements=0)
Opens an input cube specified by the user and verifies requirements are met.
Definition: ProcessByLine.cpp:41
Isis::Cube::projection
Projection * projection()
Definition: Cube.cpp:1794
Isis::OverlapStatistics::GetMStats
Isis::MultivariateStatistics GetMStats(int band) const
Returns the MultivariateStatistics object containing all the data from both cubes in the overlapping ...
Definition: OverlapStatistics.h:111
Isis::Buffer::Line
int Line(const int index=0) const
Returns the line position associated with a shape buffer index.
Definition: Buffer.cpp:145
Isis::FileName::path
QString path() const
Returns the path of the file name.
Definition: FileName.cpp:103
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16