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
32using namespace std;
33
34namespace Isis {
35
36
43
44
53 init();
54
55 m_sType = sType;
56 loadInputs(fromListName);
57 }
58
59
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) {
150 }
151
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();
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
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++) {
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
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
253 // Add adjustments for all input images
254 for (int img = 0; img < m_imageList.size(); img++) {
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 " +
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
325 if (m_results != NULL) {
326 delete m_results;
327 m_results = NULL;
328 }
329
330 m_results = new Pvl();
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) {
361 norm.addComment("Formula: newDN = (oldDN - AVERAGE) * GAIN + AVERAGE + OFFSET");
362 norm.addComment("BandN = (GAIN, OFFSET, AVERAGE)");
363 break;
365 norm.addComment("Formula: newDN = oldDN * GAIN + AVERAGE * GAIN");
366 norm.addComment("BandN = (GAIN, AVERAGE)");
367 break;
369 norm.addComment("Formula: newDN = OFFSET + AVERAGE");
370 norm.addComment("BandN = (OFFSET, AVERAGE)");
371 break;
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
389 bandStats += toString(m_adjustments[img]->getGain(band - 1));
390 }
391 // OFFSET
394 bandStats += toString(m_adjustments[img]->getOffset(band - 1));
395 }
396 // AVERAGE
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);
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
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
520 p.Progress()->SetText("Equalizing Cube " + toString((int) img + 1) +
521 " of " + maxCubeStr);
522
523 // Open input cube
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
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
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
734 for (unsigned int adj = 0; adj < m_adjustments.size(); adj++) {
735 delete m_adjustments[adj];
736 }
737 m_adjustments.clear();
738 }
739
740
749 m_adjustments.push_back(adjustment);
750 }
751
752
757 for (unsigned int oNorm = 0; oNorm < m_overlapNorms.size(); oNorm++) {
758 delete m_overlapNorms[oNorm];
759 }
760 m_overlapNorms.clear();
761 }
762
763
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
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++) {
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++) {
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
910 return m_normsSolved;
911 }
912
913
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
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}
Functor for reduce using average functionality.
Definition Reduce.h:107
Buffer for reading and writing cube data.
Definition Buffer.h:53
Manipulate and parse attributes of input cube filenames.
Manipulate and parse attributes of output cube filenames.
IO Handler for Isis Cubes.
Definition Cube.h:168
void open(const QString &cfile, QString access="r")
This method will open an existing isis cube for reading or reading/writing.
Definition Cube.cpp:622
This class is used as a functor to apply adjustments (equalize) to an image.
This class is used as a functor calculate image statistics.
int m_linc
Line increment value when calculating statistics.
void calculateBandStatistics()
Calculates the image statistics on a band-by-band basis.
void importStatistics(QString instatsFileName)
Imports statistics for applying correction.
void generateOutputs(FileList &outList)
Generates the names of the equalized cubes if no output list is provided.
void clearAdjustments()
Frees image adjustments.
void loadOutputs(FileList &outList, QString toListName)
Checks that the output image list is correct.
bool m_wtopt
Whether or not overlaps should be weighted.
virtual void errorCheck(QString fromListName)
Checks that the input images have the same mapping groups and same number of bands.
vector< OverlapNormalization * > m_overlapNorms
Normalization data for input images.
void calculateStatistics(double samplingPercent, int mincnt, bool wtopt, LeastSquares::SolveMethod methodType)
Calculates the image and overlap statistics, and then determines corrective factors if possible.
LeastSquares::SolveMethod m_lsqMethod
Least squares method for solving normalization correcitve factors.
PvlGroup getResults()
Returns general information about the equalization.
void addAdjustment(ImageAdjustment *adjustment)
Adds an image adjustment.
void fromPvl(const PvlObject &inStats)
Loads a previous Equalization state from an input pvl object.
void applyCorrection(QString toListName)
Equalizes the input images.
void setSolved(bool solved)
Sets solved state indicating if OverlapNormalizations (corrective factors) were solved.
void clearNormalizations()
Frees overlap normalizations.
int m_maxBand
Number of bands in each input image.
bool m_normsSolved
Indicates if corrective factors were solved.
void clearOverlapStatistics()
Frees overlap statistics.
void recalculateStatistics(QString inStatsFileName)
Recalculates statistics for any new input images.
vector< int > m_holdIndices
Indices of images being held.
void addInvalid(int count)
Increments the number of invalid overlaps by a given amount.
OverlapNormalization::SolutionType m_sType
The normalization solution type for solving normalizations (offsets, gains, or both)
void init()
Initializes member variables to default values.
int m_mincnt
Minimum number of pixels for an overlap to be considered valid.
int m_invalidCnt
Number of invalid overlaps.
bool m_recalculating
Indicates if recalculating with loaded statistics.
void write(QString outstatsFileName)
Write the equalization information (results) to a file.
void addHolds(QString holdListName)
Adds a list of images to be held in the equalization.
void loadInputs(QString fromListName)
Loads in the input images.
double m_samplingPercent
Percentage of the lines to consider when gathering cube and overlap statistics (process-by-line)
Equalization()
Default constructor.
void addValid(int count)
Increments the number of valid overlaps by a given amount.
Pvl * m_results
Calculation results and normalization corrective factors (if solved)
vector< bool > m_doesOverlapList
Which images have a valid overlap.
bool isSolved() const
Indicates if the corrective factors were solved.
int m_maxCube
Number of input images.
void calculateOverlapStatistics()
Calculates the overlap statistics for each pair of input images.
vector< OverlapStatistics * > m_overlapStats
Calculated overlap statistics.
QStringList m_badFiles
List of image names that don't overlap.
void setResults()
Creates the results pvl containing statistics and corrective factors.
vector< bool > m_alreadyCalculated
Which images that have statistics already calculated.
virtual ~Equalization()
Destructor.
QVector< int > validateInputStatistics(QString instatsFileName)
Validates the input statistics pvl file.
int m_validCnt
Number of valid overlaps.
Internalizes a list of files.
Definition FileList.h:54
void read(FileName listFile)
reads in a FileName obj
Definition FileList.cpp:52
File name manipulation and expansion.
Definition FileName.h:100
Isis exception class.
Definition IException.h:91
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition IException.h:118
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
Definition IException.h:126
Calculate the bases and multipliers for normalizing overlapping "data sets" (e.g.,...
SolutionType
Enumeration for whether user/programmer wants to calculate new gains, offsets, or both when solving.
@ Offsets
Calculate only the offsets.
@ Both
Calculate both gains and offsets.
@ Gains
Calculate only the gains.
@ GainsWithoutNormalization
The equation being solved for Gains, Offsets, and Both is output = (input - average) * gain + offset ...
Calculates statistics in the area of overlap between two projected cubes.
Process cubes by line.
Isis::Progress * Progress()
This method returns a pointer to a Progress object.
Definition Process.h:259
void SetText(const QString &text)
Changes the value of the text string reported just before 0% processed.
Definition Progress.cpp:61
Base class for Map Projections.
Definition Projection.h:155
Contains multiple PvlContainers.
Definition PvlGroup.h:41
Container for cube-like labels.
Definition Pvl.h:119
void write(const QString &file)
Opens and writes PVL information to a file and handles the end of line sequence.
Definition Pvl.cpp:130
void setTerminator(const QString &term)
Sets the terminator used to signify the end of the PVL informationDefaults to "END".
Definition Pvl.h:144
A single keyword-value pair.
Definition PvlKeyword.h:87
Contains Pvl Groups and Pvl Objects.
Definition PvlObject.h:61
PvlObjectIterator findObject(const QString &name, PvlObjectIterator beg, PvlObjectIterator end)
Find the index of object with a specified name, between two indexes.
Definition PvlObject.h:276
void addObject(const PvlObject &object)
Add a PvlObject.
Definition PvlObject.h:309
This class is used to accumulate statistics on double arrays.
Definition Statistics.h:94
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 IsSpecial(const double d)
Returns if the input pixel is special.
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition IString.cpp:149
Namespace for the standard library.