7 #include "Equalization.h"
13 #include <QStringList>
19 #include "IException.h"
20 #include "LeastSquares.h"
21 #include "LineManager.h"
22 #include "OverlapNormalization.h"
23 #include "OverlapStatistics.h"
25 #include "ProcessByLine.h"
26 #include "Projection.h"
29 #include "PvlObject.h"
30 #include "Statistics.h"
40 Equalization::Equalization() {
56 loadInputs(fromListName);
63 Equalization::~Equalization() {
65 clearNormalizations();
66 clearOverlapStatistics();
68 if (m_results != NULL) {
84 void Equalization::addHolds(QString holdListName) {
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_);
95 for (
int i = 0; i < holdList.size(); i++) {
97 for (
int j = 0; j < m_imageList.size(); j++) {
98 if (holdList[i] == m_imageList[j]) {
100 m_holdIndices.push_back(j);
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_);
136 void Equalization::calculateStatistics(
double percent,
int mincnt,
bool wtopt,
143 m_samplingPercent = percent;
145 m_lsqMethod = methodType;
148 if (!m_recalculating) {
149 calculateBandStatistics();
152 calculateOverlapStatistics();
155 for (
int img = 0; img < m_imageList.size(); img++) {
157 if (!m_doesOverlapList[img]) {
158 m_badFiles += m_imageList[img].toString();
161 if (!m_badFiles.isEmpty()) {
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_);
174 for (
int band = 0; band < m_maxBand; band++) {
175 m_overlapNorms[band]->Solve(m_sType, methodType);
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)) {
181 cout << band << endl;
182 cout << m_overlapNorms[band]->Gain(img) << endl;
185 "Calculation for equalization statistics failed. Gain = 0.",
188 m_adjustments[img]->addOffset(m_overlapNorms[band]->Offset(img));
189 m_adjustments[img]->addAverage(m_overlapNorms[band]->
Average(img));
192 m_normsSolved =
true;
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_);
212 void Equalization::calculateBandStatistics() {
215 for (
int band = 1; band <= m_maxBand; band++) {
217 vector<Statistics *> statsList;
218 for (
int img = 0; img < (int) m_imageList.size(); img++) {
221 QString statMsg =
"Calculating Statistics for Band " + bandStr +
226 QString inp = m_imageList[img].toString();
235 statsList.push_back(stats);
241 m_overlapNorms.push_back(oNorm);
252 void Equalization::calculateOverlapStatistics() {
254 for (
int img = 0; img < m_imageList.size(); img++) {
260 for (
int i = 0; i < m_imageList.size(); i++) {
264 for (
int j = (i + 1); j < m_imageList.size(); j++) {
266 if (m_alreadyCalculated[i] ==
true && m_alreadyCalculated[j] ==
true) {
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 " +
286 m_overlapStats.push_back(oStats);
288 for (
int band = 1; band <= m_maxBand; band++) {
296 m_overlapNorms[band - 1]->AddOverlap(
299 m_doesOverlapList[i] =
true;
300 m_doesOverlapList[j] =
true;
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++;
324 void Equalization::setResults() {
325 if (m_results != NULL) {
330 m_results =
new Pvl();
331 m_results->setTerminator(
"");
333 PvlObject equ(
"EqualizationInformation");
340 gen +=
PvlKeyword(
"Weighted", (m_wtopt) ?
"true" :
"false");
341 int solType = m_sType;
342 int lsqMethod = m_lsqMethod;
346 for (
int img = 0; img < m_badFiles.size(); img++) {
347 nonOverlaps += m_badFiles[img];
350 gen +=
PvlKeyword(
"HasCorrections", (m_normsSolved) ?
"true" :
"false");
354 for (
int img = 0; img < m_imageList.size(); img++) {
360 case OverlapNormalization::Both:
361 norm.addComment(
"Formula: newDN = (oldDN - AVERAGE) * GAIN + AVERAGE + OFFSET");
362 norm.addComment(
"BandN = (GAIN, OFFSET, AVERAGE)");
364 case OverlapNormalization::Gains:
365 norm.addComment(
"Formula: newDN = oldDN * GAIN + AVERAGE * GAIN");
366 norm.addComment(
"BandN = (GAIN, AVERAGE)");
368 case OverlapNormalization::Offsets:
369 norm.addComment(
"Formula: newDN = OFFSET + AVERAGE");
370 norm.addComment(
"BandN = (OFFSET, AVERAGE)");
372 case OverlapNormalization::GainsWithoutNormalization:
373 norm.addComment(
"Formula: newDN = oldDN * GAIN");
374 norm.addComment(
"BandN = (GAIN)");
377 norm +=
PvlKeyword(
"FileName", m_imageList[img].original());
381 for (
int band = 1; band <= m_maxBand; band++) {
383 QString bandStr =
"Band" + bandNum;
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));
392 if (m_sType == OverlapNormalization::Both ||
393 m_sType == OverlapNormalization::Offsets) {
394 bandStats +=
toString(m_adjustments[img]->getOffset(band - 1));
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));
409 m_results->addObject(equ);
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());
428 void Equalization::recalculateStatistics(QString instatsFileName) {
429 m_recalculating =
true;
430 Pvl inStats(instatsFileName);
432 calculateStatistics(m_samplingPercent, m_mincnt, m_wtopt, m_lsqMethod);
447 void Equalization::importStatistics(QString instatsFileName) {
450 QVector<int> normIndices = validateInputStatistics(instatsFileName);
451 Pvl inStats(instatsFileName);
457 if (!general.
hasKeyword(
"HasCorrections") || general[
"HasCorrections"][0] ==
"true") {
458 m_normsSolved =
true;
461 for (
int img = 0; img < (int) m_imageList.size(); img++) {
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]));
476 addAdjustment(adjustment);
480 m_normsSolved =
false;
496 void Equalization::applyCorrection(QString toListName=
"") {
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] +
"] ";
507 msg +=
"Add more images to create more overlaps and recalculate, ";
508 msg +=
"or try another solve method.";
510 throw IException(IException::User, msg, _FILEINFO_);
514 fillOutList(outList, toListName);
516 QString maxCubeStr =
toString((
int) m_imageList.size());
517 for (
int img = 0; img < m_imageList.size(); img++) {
521 " of " + maxCubeStr);
525 const QString inp = m_imageList[img].toString();
529 QString out = outList[img].toString();
551 PvlGroup results = m_results->findObject(
"EqualizationInformation").findGroup(
"General");
555 for (
int img = 0; img < m_imageList.size(); img++) {
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));
564 QString bandStr =
"Band" + bandNum;
569 results += bandStats;
582 void Equalization::write(QString outstatsFileName) {
584 m_results->write(outstatsFileName);
588 double Equalization::evaluate(
double dn,
int imageIndex,
int bandIndex)
const {
589 return m_adjustments[imageIndex]->evaluate(dn, bandIndex);
602 void Equalization::loadInputs(QString fromListName) {
604 m_imageList.read(fromListName);
605 m_maxCube = m_imageList.size();
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_);
617 m_doesOverlapList.resize(m_imageList.size(),
false);
618 m_alreadyCalculated.resize(m_imageList.size(),
false);
620 errorCheck(fromListName);
624 void Equalization::setInput(
int index, QString value) {
625 m_imageList[index] = value;
629 const FileList &Equalization::getInputs()
const {
634 void Equalization::fillOutList(FileList &outList, QString toListName) {
635 if (toListName.isEmpty()) {
636 generateOutputs(outList);
639 loadOutputs(outList, toListName);
650 void Equalization::errorCheck(QString fromListName) {
651 for (
int i = 0; i < m_imageList.size(); i++) {
655 for (
int j = (i + 1); j < m_imageList.size(); j++) {
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_);
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_);
684 void Equalization::generateOutputs(
FileList &outList) {
685 for (
int img = 0; img < m_imageList.size(); img++) {
687 QString filename = file.
path() +
"/" + file.
baseName() +
689 outList.push_back(
FileName(filename));
702 void Equalization::loadOutputs(
FileList &outList, QString toListName) {
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_);
714 for (
int i = 0; i < outList.size(); i++) {
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_);
725 for (
unsigned int h = 0; h < m_holdIndices.size(); h++)
726 oNorm->
AddHold(m_holdIndices[h]);
733 void Equalization::clearAdjustments() {
734 for (
unsigned int adj = 0; adj < m_adjustments.size(); adj++) {
735 delete m_adjustments[adj];
737 m_adjustments.clear();
749 m_adjustments.push_back(adjustment);
756 void Equalization::clearNormalizations() {
757 for (
unsigned int oNorm = 0; oNorm < m_overlapNorms.size(); oNorm++) {
758 delete m_overlapNorms[oNorm];
760 m_overlapNorms.clear();
767 void Equalization::clearOverlapStatistics() {
768 for (
unsigned int oStat = 0; oStat < m_overlapStats.size(); oStat++) {
769 delete m_overlapStats[oStat];
771 m_overlapStats.clear();
780 void Equalization::addValid(
int count) {
790 void Equalization::addInvalid(
int count) {
791 m_invalidCnt += count;
807 for (
int img = 0; img < m_imageList.size(); img++) {
808 imgNames.append(m_imageList[img].name());
814 m_samplingPercent = eqGen[
"SamplingPercent"];
815 m_mincnt = eqGen[
"MinCount"];
816 m_wtopt = (eqGen[
"Weighted"][0] ==
"true") ?
true :
false;
821 PvlObject::ConstPvlObjectIterator curObj = inStats.
beginObject();
823 if (curObj->isNamed(
"OverlapStatistics")) {
825 m_overlapStats.push_back(o);
828 QString fileX = oStat[
"File1"][0];
829 QString fileY = oStat[
"File2"][0];
832 int x = imgNames.indexOf(fileX);
833 int y = imgNames.indexOf(fileY);
834 m_alreadyCalculated[x] =
true;
835 m_alreadyCalculated[y] =
true;
839 if (oStat[
"Valid"][0] ==
"true") {
840 m_doesOverlapList[x] =
true;
841 m_doesOverlapList[y] =
true;
848 calculateBandStatistics();
856 for (
int o = 0; o < (int) m_overlapStats.size(); o++) {
863 for (
int i = 0; i < m_imageList.size(); i++) {
864 QString imageName(m_imageList[i].name());
870 overlapIndices[o].push_front(i);
875 overlapIndices[o].push_back(i);
880 for (
int o = 0; o < (int) m_overlapStats.size(); o++) {
882 for (
int band = 1; band <= oStat->
Bands(); band++) {
886 m_overlapNorms[band-1]->AddOverlap(oStat->
GetMStats(band).
X(), overlapIndices[o][0],
887 oStat->
GetMStats(band).
Y(), overlapIndices[o][1], weight);
899 void Equalization::setSolved(
bool solved) {
900 m_normsSolved = solved;
909 bool Equalization::isSolved()
const {
910 return m_normsSolved;
917 void Equalization::init() {
922 m_samplingPercent = 100.0;
928 m_sType = OverlapNormalization::Both;
929 m_lsqMethod = LeastSquares::SPARSE;
932 m_doesOverlapList.clear();
933 m_alreadyCalculated.clear();
934 m_normsSolved =
false;
935 m_recalculating =
false;
956 QVector<int> Equalization::validateInputStatistics(QString instatsFileName) {
959 Pvl inStats(instatsFileName);
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_);
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++) {
975 QString normFile = normalization[
"FileName"][0];
976 if (fromFile == normFile) {
980 normIndices.push_back(j);
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_);
995 void Equalization::CalculateFunctor::operator()(
Buffer &in)
const {
1003 void Equalization::CalculateFunctor::addStats(Buffer &in)
const {
1005 m_stats->AddData(&in[0], in.size());
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++) {
1013 in[i] : m_adjustment->evaluate(in[i], index);