7#include "Equalization.h"
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"
30#include "Statistics.h"
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.";
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]) {
105 QString msg =
"The hold list file [" + holdList[i].toString() +
106 "] does not match a file in the from list";
155 for (
int img = 0; img < m_imageList.size(); img++) {
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.";
174 for (
int band = 0; band <
m_maxBand; band++) {
177 for (
unsigned int img = 0; img < m_adjustments.size(); img++) {
181 cout << band << endl;
185 "Calculation for equalization statistics failed. Gain = 0.",
196 QString msg =
"Unable to calculate the equalization statistics. You may "
197 "want to try another LeastSquares::SolveMethod.";
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 +
224 p.Progress()->SetText(statMsg);
226 QString inp = m_imageList[img].toString();
227 p.SetInputCube(inp, att);
232 p.ProcessCubeInPlace(func,
false);
235 statsList.push_back(stats);
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++) {
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 " +
285 if (oStats->HasOverlap()) {
288 for (
int band = 1; band <=
m_maxBand; band++) {
292 if (
m_wtopt) weight = oStats->GetMStats(band).ValidPixels();
295 if (oStats->GetMStats(band).ValidPixels() >=
m_mincnt) {
297 oStats->GetMStats(band).X(), i,
298 oStats->GetMStats(band).Y(), j, weight);
309 for (
int band = 1; band <=
m_maxBand; band++) {
333 PvlObject equ(
"EqualizationInformation");
346 for (
int img = 0; img <
m_badFiles.size(); img++) {
354 for (
int img = 0; img < m_imageList.size(); img++) {
361 norm.addComment(
"Formula: newDN = (oldDN - AVERAGE) * GAIN + AVERAGE + OFFSET");
362 norm.addComment(
"BandN = (GAIN, OFFSET, AVERAGE)");
365 norm.addComment(
"Formula: newDN = oldDN * GAIN + AVERAGE * GAIN");
366 norm.addComment(
"BandN = (GAIN, AVERAGE)");
369 norm.addComment(
"Formula: newDN = OFFSET + AVERAGE");
370 norm.addComment(
"BandN = (OFFSET, AVERAGE)");
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;
389 bandStats +=
toString(m_adjustments[img]->getGain(band - 1));
394 bandStats +=
toString(m_adjustments[img]->getOffset(band - 1));
400 bandStats +=
toString(m_adjustments[img]->getAverage(band - 1));
430 Pvl inStats(instatsFileName);
451 Pvl inStats(instatsFileName);
453 PvlGroup &general = equalInfo.findGroup(
"General");
457 if (!general.hasKeyword(
"HasCorrections") || general[
"HasCorrections"][0] ==
"true") {
461 for (
int img = 0; img < (int) m_imageList.size(); img++) {
463 PvlGroup &normalization = equalInfo.group(normIndices[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]));
498 QString msg =
"Corrective factors have not yet been determined. ";
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++) {
507 msg +=
"Add more images to create more overlaps and recalculate, ";
508 msg +=
"or try another solve method.";
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();
526 Cube *icube = p.SetInputCube(inp, att);
529 QString out = outList[img].toString();
531 p.SetOutputCube(out, outAtt, icube->sampleCount(),
532 icube->lineCount(), icube->bandCount());
536 p.ProcessCube(func,
false);
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;
588 double Equalization::evaluate(
double dn,
int imageIndex,
int bandIndex)
const {
589 return m_adjustments[imageIndex]->evaluate(dn, bandIndex);
604 m_imageList.
read(fromListName);
607 if (m_imageList.size() < 2) {
608 QString msg =
"The input file [" + fromListName +
609 "] must contain at least 2 file names";
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()) {
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() +
"]";
671 if (*proj1 != *proj2) {
672 QString msg =
"Mapping groups do not match between cubes [" +
673 m_imageList[i].toString() +
"] and [" + m_imageList[j].toString() +
"]";
685 for (
int img = 0; img < m_imageList.size(); img++) {
687 QString filename = file.path() +
"/" + file.baseName() +
688 ".equ." + file.extension();
689 outList.push_back(
FileName(filename));
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.";
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.";
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);
757 for (
unsigned int oNorm = 0; oNorm <
m_overlapNorms.size(); oNorm++) {
768 for (
unsigned int oStat = 0; oStat <
m_overlapStats.size(); oStat++) {
806 QList<QString> imgNames;
807 for (
int img = 0; img < m_imageList.size(); img++) {
808 imgNames.append(m_imageList[img].name());
813 const PvlGroup &eqGen = eqInfo.findGroup(
"General");
816 m_wtopt = (eqGen[
"Weighted"][0] ==
"true") ?
true :
false;
821 PvlObject::ConstPvlObjectIterator curObj = inStats.beginObject();
822 while (curObj < inStats.endObject()) {
823 if (curObj->isNamed(
"OverlapStatistics")) {
828 QString fileX = oStat[
"File1"][0];
829 QString fileY = oStat[
"File2"][0];
832 int x = imgNames.indexOf(fileX);
833 int y = imgNames.indexOf(fileY);
839 if (oStat[
"Valid"][0] ==
"true") {
863 for (
int i = 0; i < m_imageList.size(); i++) {
864 QString imageName(m_imageList[i].name());
867 if (oStat->FileNameX() == imageName)
870 overlapIndices[o].push_front(i);
872 if (oStat->FileNameY() == imageName)
875 overlapIndices[o].push_back(i);
882 for (
int band = 1; band <= oStat->Bands(); band++) {
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);
957 QVector<int> normIndices;
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.";
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) {
980 normIndices.push_back(j);
985 QString msg =
"The from list file [" + fromFile +
986 "] does not have any corresponding file in the stats list.";
995 void Equalization::CalculateFunctor::operator()(
Buffer &in)
const {
997 if ((in.Line() - 1) %
m_linc == 0 || in.Line() == in.LineDimension()) {
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);
Functor for reduce using average functionality.
Buffer for reading and writing cube data.
Manipulate and parse attributes of output cube filenames.
IO Handler for Isis Cubes.
void open(const QString &cfile, QString access="r")
This method will open an existing isis cube for reading or reading/writing.
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.
void read(FileName listFile)
reads in a FileName obj
File name manipulation and expansion.
@ Unknown
A type of error that cannot be classified as any of the other error types.
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
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.
Isis::Progress * Progress()
This method returns a pointer to a Progress object.
void SetText(const QString &text)
Changes the value of the text string reported just before 0% processed.
Base class for Map Projections.
Contains multiple PvlContainers.
Container for cube-like labels.
void write(const QString &file)
Opens and writes PVL information to a file and handles the end of line sequence.
void setTerminator(const QString &term)
Sets the terminator used to signify the end of the PVL informationDefaults to "END".
A single keyword-value pair.
Contains Pvl Groups and Pvl Objects.
PvlObjectIterator findObject(const QString &name, PvlObjectIterator beg, PvlObjectIterator end)
Find the index of object with a specified name, between two indexes.
void addObject(const PvlObject &object)
Add a PvlObject.
This class is used to accumulate statistics on double arrays.
This is free and unencumbered software released into the public domain.
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
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.
Namespace for the standard library.