USGS

Isis 3.0 Application Source Code Reference

Home

cubediff.cpp

Go to the documentation of this file.
00001 #include "Isis.h"
00002 
00003 #include <sstream>
00004 #include <string>
00005 #include <float.h>
00006 #include <fstream>
00007 
00008 #include "ProcessByLine.h"
00009 
00010 #include "Statistics.h"
00011 #include "Pvl.h"
00012 #include "IException.h"
00013 #include "WriteTabular.h"
00014 #include "IString.h"
00015 #include "Pixel.h"
00016 
00017 using namespace std;
00018 using namespace Isis;
00019 
00020 void compare(vector<Buffer *> &in, vector<Buffer *> &out);
00021 
00022 void diffTable(ofstream &target, int precision);
00023 
00024 // This is only used for the difference table
00025 struct Difference {
00026   int lineNum;
00027   int sampNum;
00028   double cube1Val;
00029   double cube2Val;
00030 };
00031 
00032 double tolerance;
00033 bool filesEqual = true;
00034 bool firstDifferenceFound = false; // Set to true when first DN value difference is found
00035 int sample, line, band, spCount, diffCount, colWidth;
00036 Statistics stats;
00037 bool doTable;
00038 unsigned int sigFigAccuracy = DBL_DIG; // DBL_DIG is maximum accuracy for a double
00039 vector<Difference> diffset;
00040 int sigFigLine = 0;
00041 int sigFigSample = 0;
00042 int sigFigBand = 0;
00043 
00044 int gMaxDiffLine = 0, gMaxDiffSample = 0, gMaxDiffBand = 0;
00045 double gMaxDiff;
00046 
00047 void IsisMain() {
00048   // Set up the two input cubes
00049   ProcessByLine p;
00050   p.SetInputCube("FROM");
00051   p.SetInputCube("FROM2", SizeMatch);
00052 
00053   // Read tolerance value
00054   UserInterface &ui = Application::GetUserInterface();
00055   if(ui.WasEntered("TOLERANCE")) {
00056     tolerance = ui.GetDouble("TOLERANCE");
00057   }
00058   else {
00059     tolerance = DBL_EPSILON;
00060   }
00061 
00062   // See if we should output the difference table
00063   if(ui.GetBoolean("OUTPUTDIFFS")) {
00064     doTable = true;
00065     diffCount = ui.GetInteger("COUNT");
00066     if(!ui.WasEntered("TO")) {
00067       string message = "A target file is required for difference output";
00068       throw IException(IException::User, message, _FILEINFO_);
00069     }
00070 
00071   }
00072 
00073   // Compare the cubes
00074   filesEqual = true;
00075   spCount = 0;
00076   stats.Reset();
00077   colWidth = 0;
00078   gMaxDiff = tolerance;
00079   p.StartProcess(compare);
00080 
00081   // Write to log indicating if two files are filesEqual.
00082   PvlGroup results("Results");
00083   if(filesEqual) {
00084     results += PvlKeyword("Compare", "Identical");
00085   }
00086   else {
00087     results += PvlKeyword("Compare", "Different");
00088     results += PvlKeyword("Sample", toString(sample));
00089     results += PvlKeyword("Line", toString(line));
00090     results += PvlKeyword("Band", toString(band));
00091     if(stats.TotalPixels() < 1) {
00092       results += PvlKeyword("AverageDifference", "0");
00093       results += PvlKeyword("StandardDeviation", "0");
00094       results += PvlKeyword("Variance", "0");
00095       results += PvlKeyword("MinimumDifference", "0");
00096       results += PvlKeyword("MaximumDifference", "0");
00097     }
00098     else {
00099       results += PvlKeyword("AverageDifference", toString(stats.Average()));
00100       results += PvlKeyword("StandardDeviation", toString(stats.StandardDeviation()));
00101       results += PvlKeyword("Variance", toString(stats.Variance()));
00102       results += PvlKeyword("MinimumDifference", toString(stats.Minimum()));
00103       results += PvlKeyword("MaximumDifference", toString(stats.Maximum()));
00104       results += PvlKeyword("MaxDifferenceSample", toString(gMaxDiffSample));
00105       results += PvlKeyword("MaxDifferenceLine", toString(gMaxDiffLine));
00106       results += PvlKeyword("MaxDifferenceBand", toString(gMaxDiffBand));
00107     }
00108     results += PvlKeyword("ValidPixelDifferences", toString(stats.TotalPixels()));
00109     results += PvlKeyword("SpecialPixelDifferences", toString(spCount));
00110     results += PvlKeyword("SigFigAccuracy", toString(sigFigAccuracy));
00111     results += PvlKeyword("SigFigMaxDifferenceSample", toString(sigFigSample));
00112     results += PvlKeyword("SigFigMaxDifferenceLine", toString(sigFigLine));
00113     results += PvlKeyword("SigFigMaxDifferenceBand", toString(sigFigBand));
00114   }
00115   Application::Log(results);
00116 
00117   // Output a file if the user request it
00118   if(ui.WasEntered("TO")) {
00119     Pvl lab;
00120     lab.AddGroup(results);
00121     lab.Write(ui.GetFileName("TO", "txt"));
00122   }
00123   if(doTable) {
00124     QString filename = FileName(ui.GetFileName("TO", "txt")).expanded();
00125     ofstream ofile(filename.toAscii().data(), ios_base::app);
00126     diffTable(ofile, ui.GetInteger("PRECISION"));
00127   }
00128 
00129   p.EndProcess();
00130   filesEqual = true;
00131 }
00132 
00133 void compare(vector<Buffer *> &in, vector<Buffer *> &out) {
00134   Buffer &input1 = *in[0];
00135   Buffer &input2 = *in[1];
00136   int inputSize = input1.size();
00137   double MaxDiffTemp;
00138 
00139   for(int index = 0; index < inputSize; index ++) {
00140     bool pixelDifferent = false;
00141     bool pixelSpecial = false;
00142 
00143     // First check if there is a special pixel in either cube
00144     if(Pixel::IsSpecial(input1[index]) || Pixel::IsSpecial(input2[index])) {
00145       pixelSpecial = true;
00146 
00147       // We have special pixels, if they are both special compare them.
00148       if(Pixel::IsSpecial(input1[index]) && Pixel::IsSpecial(input2[index])) {
00149         if(input1[index] != input2[index]) {
00150           spCount ++;
00151           pixelDifferent = true;
00152         }
00153       }
00154       // At least one is special, but not both, so they must be different
00155       else {
00156         spCount ++;
00157         pixelDifferent = true;
00158       }
00159     }
00160     // We don't have any special pixels, run against tolerance
00161     else {
00162       MaxDiffTemp = abs(input1[index] - input2[index]);
00163       if(MaxDiffTemp > tolerance) {
00164         // This pixel is different.
00165         pixelDifferent = true;
00166 
00167         // Add the difference in dn to the stats object
00168         stats.AddData(MaxDiffTemp);
00169 
00170         // Store line, sample and band of max difference
00171         if(MaxDiffTemp > gMaxDiff) {
00172           gMaxDiff = MaxDiffTemp;
00173           gMaxDiffLine   = input1.Line(index);
00174           gMaxDiffSample = input1.Sample(index);
00175           gMaxDiffBand   = input1.Band(index);
00176         }
00177       }
00178     }
00179 
00180     // If pixels different & neither are special, calculate the significant figure difference
00181     if(pixelDifferent && !pixelSpecial) {
00182       unsigned int accuracy = 0;
00183 
00184       // Check positive/negative and ensure both positive
00185       if((input1[index] < 0 && input2[index] > 0) ||
00186           (input1[index] > 0 && input2[index] < 0)) {
00187         accuracy = 1;
00188       }
00189       else {
00190         double in1 = abs(input1[index]);
00191         double in2 = abs(input2[index]);
00192         int in1log = (int)floor(log10(in1));
00193         int in2log = (int)floor(log10(in2));
00194 
00195         // Check for zeros
00196         if(input1[index] == 0 || input2[index] == 0) {
00197           accuracy = 0;
00198         }
00199         // Check for different decimal places
00200         else if(in1log != in2log) {
00201           accuracy = 0;
00202         }
00203         else {
00204           // int values of log of original - log of difference = # sig fig accuracy
00205           // *The difference can not equal zero because pixelDifferent flag is set to true
00206           accuracy = in1log - (int)floor(log10(abs(in1 - in2)));
00207         }
00208       }
00209 
00210       if(accuracy < sigFigAccuracy) {
00211         sigFigSample = input1.Sample(index);
00212         sigFigLine = input1.Line(index);
00213         sigFigBand = input1.Band(index);
00214         sigFigAccuracy = accuracy;
00215       }
00216     }
00217 
00218     if(pixelDifferent) {
00219       filesEqual = false;
00220 
00221       if(!firstDifferenceFound) {
00222         firstDifferenceFound = true;
00223         sample = input1.Sample(index);
00224         line = input1.Line(index);
00225         band = input1.Band(index);
00226       }
00227     }
00228 
00229     // If the user indicated that we should make the table, add this entry
00230     if(pixelDifferent && doTable) {
00231       if((int)diffset.size() < diffCount) {
00232         Difference currDiff;
00233         currDiff.lineNum = input1.Line(index);
00234         currDiff.sampNum = input1.Sample(index);
00235         currDiff.cube1Val = input1[index];
00236         currDiff.cube2Val = input2[index];
00237         diffset.push_back(currDiff);
00238 
00239         // Check the character lengths of the values
00240         int val1Length = IString((int)currDiff.cube1Val).length();
00241         int val2Length = IString((int)currDiff.cube2Val).length();
00242         if(val1Length < colWidth) {
00243           colWidth = val1Length;
00244         }
00245         if(val2Length < colWidth) {
00246           colWidth = val2Length;
00247         }
00248       }
00249     }
00250   }
00251 }
00252 
00253 //Function to prepare the table to append to the
00254 void diffTable(ofstream &target, int precision) {
00255   vector<int> temp;
00256 
00257   //Make a list of all samples present
00258   for(unsigned int i = 0; i < diffset.size(); i++) {
00259     temp.push_back(diffset[i].sampNum);
00260   }
00261 
00262   //Sort the list
00263   sort(temp.begin(), temp.end());
00264 
00265   //Remove duplicates
00266   vector<int> samps;
00267   samps.push_back(temp[0]);
00268   for(unsigned int i = 1; i < temp.size(); i++) {
00269     if(temp[i] != samps.back()) {
00270       samps.push_back(temp[i]);
00271     }
00272   }
00273   vector<Column> cols;
00274   //Add the first Column
00275   Column first("Line#", 7, Column::Integer);
00276   cols.push_back(first);
00277 
00278   for(unsigned int i = 0; i < samps.size(); i++) {
00279     Column currCol;
00280     //Prepare and add the first file's column
00281     currCol.SetName(QString("File1_") + toString(samps[i]));
00282     if((int)(colWidth + precision + 1) < (int)currCol.Name().length()) {
00283       currCol.SetWidth(currCol.Name().length() + 1);
00284     }
00285     else currCol.SetWidth(colWidth + precision + 1);
00286 
00287     currCol.SetType(Column::Pixel);
00288     currCol.SetAlignment(Column::Decimal);
00289     currCol.SetPrecision(precision);
00290     cols.push_back(currCol);
00291 
00292     //Prepare and add the second file's column
00293     currCol.SetName(QString("File2_") + toString(samps[i]));
00294     cols.push_back(currCol);
00295   }
00296 
00297   WriteTabular diffs(target, cols);
00298 
00299   //Go through the entire list of differences and make the table
00300   for(unsigned int i = 0; i < diffset.size(); i++) {
00301     diffs.Write(diffset[i].lineNum);
00302     for(unsigned int j = 0; j < samps.size(); j++) {
00303       if(diffset[i].sampNum == samps[j]) {
00304         diffs.Write(diffset[i].cube1Val);
00305         diffs.Write(diffset[i].cube2Val);
00306       }
00307       else {
00308         diffs.Write();
00309         diffs.Write();
00310       }
00311     }
00312   }
00313 }