|
Isis 3.0 Application Source Code Reference |
Home |
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 }