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.