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