|
Isis 3.0 Application Source Code Reference |
Home |
00001 #include "Isis.h" 00002 00003 // system include files go first 00004 #include <string> 00005 #include <iostream> 00006 #include <iomanip> 00007 #include <vector> 00008 #include <algorithm> 00009 00010 // Isis specific include files go next 00011 #include "ProcessByTile.h" 00012 #include "ProcessByLine.h" 00013 #include "SpecialPixel.h" 00014 #include "iException.h" 00015 #include "Pvl.h" 00016 #include "Statistics.h" 00017 #include "VecFilter.h" 00018 00019 using namespace std; 00020 using namespace Isis; 00021 00022 // These global vectors are used to keep track of info for columns 00023 // of image data. For example, a 100 sample x 200 line x 2 band cube will 00024 // have a vectors of 200 columns (100 samples x 2 bands). 00025 vector<double> stddev; 00026 vector<int> validpixels; 00027 vector<double> minimum; 00028 vector<double> maximum; 00029 vector<int> band; 00030 vector<int> element; 00031 vector<double> median; 00032 vector<double> average; 00033 vector<double> normalizer; 00034 00035 // Size of the cube 00036 int totalLines; 00037 int totalSamples; 00038 00039 enum Mode {SUBTRACT,DIVIDE}; 00040 00041 // function prototypes 00042 void getStats(Buffer &in); 00043 void multiply(Buffer &in, Buffer &out); 00044 void subtract(Buffer &in, Buffer &out); 00045 void pvlOut(const string &pv); 00046 void tableOut(const string &pv); 00047 void PVLIn(const Isis::Filename & filename); 00048 void tableIn(const Isis::Filename & filename); 00049 void keepSame(int &totalBands, int &rowcol, Mode mode); 00050 void filterStats(vector<double> &filter,int &filtsize, bool &pause_crop, 00051 int &channel); 00052 00053 // Main Program 00054 void IsisMain() { 00055 vector<double> filter; 00056 int rowcol; // how many rows or cols per band 00057 bool normalizeUsingAverage; // mult/sub using average or median? 00058 int totalBands; 00059 // Used for filtering the initial cubenorm averages and median values 00060 int filtsize; 00061 bool pause_crop; 00062 int channel; 00063 // ERROR CHECK: The user must specify at least the TO or STATS 00064 // parameters. 00065 UserInterface &ui = Application::GetUserInterface(); 00066 if (!(ui.WasEntered("TO")) && !(ui.WasEntered("STATS"))) { 00067 string msg = "User must specify a TO and/or STATS file."; 00068 throw iException::Message(iException::User,msg,_FILEINFO_); 00069 } 00070 00071 // We will be processing by tile. 00072 ProcessByTile p; 00073 00074 // Setup the input cube; 00075 // Obtain information from the input file 00076 Cube *icube = p.SetInputCube("FROM"); 00077 totalSamples = icube->Samples(); 00078 totalLines = icube->Lines(); 00079 totalBands = icube->Bands(); 00080 channel = icube->GetGroup("Instrument")["ChannelNumber"]; 00081 00082 // Setup the tile size for columnar processing 00083 p.SetTileSize(1, totalLines); 00084 rowcol = totalSamples; 00085 00086 // Now get the statistics for each column 00087 normalizeUsingAverage = ui.GetString("NORMALIZER") == "AVERAGE"; 00088 00089 //gather statistics 00090 if (ui.GetString("STATSOURCE") == "CUBE"){ 00091 p.StartProcess(getStats); 00092 } 00093 else if (ui.GetString("STATSOURCE") == "TABLE"){ 00094 tableIn(ui.GetFilename("FROMSTATS")); 00095 } 00096 else{ 00097 PVLIn(ui.GetFilename("FROMSTATS")); 00098 } 00099 00100 //check to make sure the first vector has as many elements as the last 00101 // vector, and that there is a vector element for each row/col 00102 if (band.size() != (unsigned int)(rowcol*totalBands)) { 00103 string message = "You have entered an invalid input file " + 00104 ui.GetFilename("FROMSTATS"); 00105 throw iException::Message(Isis::iException::Io, message, 00106 _FILEINFO_); 00107 } 00108 00109 //get information needed to filter the statistics 00110 filtsize = ui.GetInteger("FILTER"); 00111 pause_crop = ui.GetBoolean("PAUSECROP"); 00112 00113 //filter the column averages 00114 filter = average; 00115 filterStats(filter,filtsize,pause_crop,channel); 00116 average = filter; 00117 00118 //filter the column medians 00119 filter = median; 00120 filterStats(filter,filtsize,pause_crop,channel); 00121 median = filter; 00122 00123 //If a STATS file was specified then create statistics file 00124 if (ui.WasEntered("STATS")) { 00125 string op = ui.GetString("FORMAT"); 00126 if (op == "PVL") pvlOut(ui.GetFilename("STATS")); 00127 if (op == "TABLE") tableOut(ui.GetFilename("STATS")); 00128 } 00129 00130 // Update the statistics vectors before creating the output 00131 // file 00132 if (normalizeUsingAverage) { 00133 normalizer = average; 00134 } else { 00135 normalizer = median; 00136 } 00137 00138 // If an output file was specified then normalize the cube 00139 if (ui.WasEntered ("TO")) { 00140 // Before creating a normalized cube check to see if there 00141 // are any column averages less than or equal to zero. 00142 if (ui.GetString("MODE") == "MULTIPLY") { 00143 for (unsigned int i=0; i<band.size(); i++) { 00144 if (IsValidPixel(normalizer[i]) && normalizer[i]<=0.0) { 00145 string msg = "Cube file can not be normalized with [MULTIPLY] "; 00146 msg += "option, some column averages <= 0.0"; 00147 throw iException::Message(iException::User,msg,_FILEINFO_); 00148 } 00149 } 00150 } 00151 00152 // Setup the output file and apply the coefficients by either 00153 // subtracting or multipling them 00154 p.SetOutputCube("TO"); 00155 00156 // Should we preserve the average/median of the input image??? 00157 if (ui.GetBoolean("PRESERVE")) { 00158 if (ui.GetString("MODE") == "SUBTRACT") { 00159 keepSame(totalBands,rowcol,SUBTRACT); 00160 } else { 00161 keepSame(totalBands,rowcol,DIVIDE); 00162 } 00163 } 00164 00165 // Process based on the mode 00166 if (ui.GetString("MODE") == "SUBTRACT") { 00167 p.StartProcess(subtract); 00168 } 00169 else { 00170 p.StartProcess(multiply); 00171 } 00172 } 00173 00174 // Cleanup 00175 p.EndProcess(); 00176 stddev.clear(); 00177 validpixels.clear(); 00178 minimum.clear(); 00179 maximum.clear(); 00180 band.clear(); 00181 element.clear(); 00182 median.clear(); 00183 average.clear(); 00184 normalizer.clear(); 00185 filter.clear(); 00186 } 00187 00188 //********************************************************** 00189 // DOUSER - Get statistics on a column or row of pixels 00190 //********************************************************** 00191 void getStats(Buffer &in) { 00192 Statistics stats; 00193 stats.AddData(in.DoubleBuffer(),in.size()); 00194 00195 band.push_back(in.Band()); 00196 element.push_back(in.Sample()); 00197 00198 // Sort the input buffer 00199 vector<double> pixels; 00200 for (int i=0; i<in.size(); i++) { 00201 if (IsValidPixel(in[i])) pixels.push_back(in[i]); 00202 } 00203 sort(pixels.begin(),pixels.end()); 00204 00205 // Now obtain the median value and store in the median vector 00206 int size = pixels.size(); 00207 if (size != 0) { 00208 int med = size/2; 00209 if (size%2 == 0) { 00210 median.push_back((pixels[med-1]+pixels[med])/2.0); 00211 } 00212 else { 00213 median.push_back(pixels[med]); 00214 } 00215 } 00216 else { 00217 median.push_back(Isis::Null); 00218 } 00219 00220 // Store the statistics in the appropriate vectors 00221 average.push_back(stats.Average()); 00222 stddev.push_back(stats.StandardDeviation()); 00223 validpixels.push_back(stats.ValidPixels()); 00224 minimum.push_back(stats.Minimum()); 00225 maximum.push_back(stats.Maximum()); 00226 } 00227 00228 //******************************************************** 00229 // Create PVL output of statistics 00230 //******************************************************* 00231 void pvlOut(const string &StatFile) { 00232 PvlGroup results ("Results"); 00233 for (unsigned int i=0; i <band.size(); i++) { 00234 results += PvlKeyword("Band",band[i]); 00235 results += PvlKeyword("RowCol",element[i]); 00236 results += PvlKeyword("ValidPixels",validpixels[i]); 00237 if (validpixels[i] > 0) { 00238 results += PvlKeyword("Mean",average[i]); 00239 results += PvlKeyword("Median",median[i]); 00240 results += PvlKeyword("Std",stddev[i]); 00241 results += PvlKeyword("Minimum",minimum[i]); 00242 results += PvlKeyword("Maximum",maximum[i]); 00243 } 00244 else { 00245 results += PvlKeyword("Mean",0.0); 00246 results += PvlKeyword("Median",0.0); 00247 results += PvlKeyword("Std",0.0); 00248 results += PvlKeyword("Minimum",0.0); 00249 results += PvlKeyword("Maximum",0.0); 00250 } 00251 } 00252 00253 Pvl t; 00254 t.AddGroup(results); 00255 t.Write(StatFile); 00256 } 00257 00258 //******************************************************** 00259 // Create Tabular output of statistics 00260 //******************************************************* 00261 void tableOut(const string &StatFile) { 00262 // Open output file 00263 // TODO check status and throw error 00264 ofstream out; 00265 out.open(StatFile.c_str(),std::ios::out); 00266 00267 // Output a header 00268 out << std::setw(8) << "Band"; 00269 out << std::setw(8) << "RowCol"; 00270 out << std::setw(15) << "ValidPoints"; 00271 out << std::setw(15) << "Average"; 00272 out << std::setw(15) << "Median"; 00273 out << std::setw(15) << "StdDev"; 00274 out << std::setw(15) << "Minimum"; 00275 out << std::setw(15) << "Maximum"; 00276 out << endl; 00277 00278 // Print out the table results 00279 for (unsigned int i=0; i<band.size(); i++) { 00280 out << std::setw(8) << band[i]; 00281 out << std::setw(8) << element[i]; 00282 out << std::setw(15) << validpixels[i]; 00283 if (validpixels[i] > 0) { 00284 out << std::setw(15) << average[i]; 00285 out << std::setw(15) << median[i]; 00286 //Make sure the table's SD is 0 for RowCols with 1 or less valid pixels 00287 if( validpixels[i] > 1 ) { 00288 out << std::setw(15) << stddev[i]; 00289 } 00290 else { 00291 out << std::setw(15) << 0; 00292 } 00293 out << std::setw(15) << minimum[i]; 00294 out << std::setw(15) << maximum[i]; 00295 } 00296 else { 00297 out << std::setw(15) << 0; 00298 out << std::setw(15) << 0; 00299 out << std::setw(15) << 0; 00300 out << std::setw(15) << 0; 00301 out << std::setw(15) << 0; 00302 } 00303 out << endl; 00304 } 00305 out.close(); 00306 } 00307 00308 //******************************************************** 00309 // Gather statistics from a PVL input file 00310 //******************************************************* 00311 void PVLIn(const Isis::Filename &filename){ 00312 Pvl pvlFileIn; 00313 pvlFileIn.Read(filename.Name()); 00314 PvlGroup results = pvlFileIn.FindGroup("Results"); 00315 PvlObject::PvlKeywordIterator itr = results.Begin(); 00316 00317 while (itr != results.End()){ 00318 band.push_back((*itr)[0]); 00319 itr++; 00320 element.push_back((*itr)[0]); 00321 itr++; 00322 validpixels.push_back((*itr)[0]); 00323 itr++; 00324 average.push_back((*itr)[0]); 00325 itr++; 00326 median.push_back((*itr)[0]); 00327 itr++; 00328 stddev.push_back((*itr)[0]); 00329 itr++; 00330 minimum.push_back((*itr)[0]); 00331 itr++; 00332 maximum.push_back((*itr)[0]); 00333 itr++; 00334 } 00335 } 00336 00337 //******************************************************** 00338 // Gather statistics from a table input file 00339 //******************************************************* 00340 void tableIn(const Isis::Filename & filename){ 00341 ifstream in; 00342 string expanded(filename.Expanded()); 00343 in.open(expanded.c_str(),std::ios::in); 00344 00345 00346 if (!in){ 00347 string message = "Error opening " + filename.Expanded(); 00348 throw iException::Message(Isis::iException::Io, message, 00349 _FILEINFO_); 00350 } 00351 00352 //skip the header (106 bytes) 00353 in.seekg(106); 00354 00355 00356 //read it 00357 iString inString; 00358 while (in >> inString){ 00359 band.push_back(inString); 00360 in>> inString; 00361 element.push_back(inString); 00362 in>> inString; 00363 validpixels.push_back(inString); 00364 in >> inString; 00365 average.push_back(inString); 00366 in >> inString; 00367 median.push_back(inString); 00368 in >> inString; 00369 stddev.push_back(inString); 00370 in >> inString; 00371 minimum.push_back(inString); 00372 in >> inString; 00373 maximum.push_back(inString); 00374 //Make sure Standard Deviation is not < 0 when reading in from a table 00375 vector<double>::iterator p; 00376 p = stddev.end() - 1; 00377 if( *p < 0 ) { 00378 *p = 0; 00379 } 00380 } 00381 in.close(); 00382 } 00383 00384 //******************************************************** 00385 // Compute coefficients such that when we subtract/divide 00386 // using the coefficient the average or median of the 00387 // output image stays the same 00388 void keepSame(int &totalBands,int &rowcol,Mode mode) { 00389 // Loop for each band 00390 for (int iband=1; iband<=totalBands; iband++) { 00391 double sumAverage = 0.0; 00392 double sumValidPixels = 0; 00393 for (int i=0; i<rowcol; i++) { 00394 int index = (iband - 1) * rowcol + i; 00395 if (IsValidPixel(normalizer[index])) { 00396 sumAverage += normalizer[index] * validpixels[index]; 00397 sumValidPixels += validpixels[index]; 00398 } 00399 } 00400 00401 // Neither sumValidPixels nor totalAverage will be zero 00402 // because of a test done earlier in IsisMain 00403 double totalAverage = sumAverage/sumValidPixels; 00404 for (int i=0; i<rowcol; i++) { 00405 int index = (iband - 1) * rowcol + i; 00406 if (IsValidPixel(normalizer[index])) { 00407 if (mode == SUBTRACT) { 00408 normalizer[index] = normalizer[index] - totalAverage; 00409 } else { 00410 normalizer[index] = normalizer[index] / totalAverage; 00411 } 00412 } 00413 } 00414 } 00415 } 00416 00417 // Apply coefficients multiplicatively 00418 void multiply(Buffer &in, Buffer &out) { 00419 // Compute the index into the normalizer array 00420 // We have to tweak the index based on the shape of the buffer 00421 // either a column or line 00422 int index; 00423 if (in.SampleDimension() == 1) { 00424 index = (in.Band() - 1) * totalSamples; // Get to the proper band 00425 index += in.Sample() - 1; // Get to the proper column 00426 } 00427 else { 00428 index = (in.Band() - 1) * totalLines; // Get to the proper band 00429 index += in.Line() - 1; // Get to the proper row 00430 } 00431 double coeff = normalizer[index]; 00432 00433 // Now loop and apply the coefficents 00434 for (int i=0; i<in.size(); i++) { 00435 if (IsSpecial(in[i])) { 00436 out[i] = in[i]; 00437 } 00438 else { 00439 out[i] = Null; 00440 if (coeff != 0.0 && IsValidPixel(coeff)) { 00441 out[i] = in[i]/coeff; 00442 } 00443 } 00444 } 00445 } 00446 00447 // Apply coefficients subtractively 00448 void subtract(Buffer &in, Buffer &out) { 00449 // Compute the index into the normalizer array 00450 // We have to tweak the index based on the shape of the buffer 00451 // either a column or line 00452 int index; 00453 if (in.SampleDimension() == 1) { 00454 index = (in.Band() - 1) * totalSamples; // Get to the proper band 00455 index += in.Sample() - 1; // Get to the proper column 00456 } 00457 else { 00458 index = (in.Band() - 1) * totalLines; // Get to the proper band 00459 index += in.Line() - 1; // Get to the proper row 00460 } 00461 double coeff = normalizer[index]; 00462 00463 // Now loop and apply the coefficents 00464 for (int i=0; i<in.size(); i++) { 00465 if (IsSpecial(in[i])) { 00466 out[i] = in[i]; 00467 } 00468 else { 00469 out[i] = Null; 00470 if (IsValidPixel(coeff)) { 00471 out[i] = in[i] - coeff; 00472 } 00473 } 00474 } 00475 } 00476 00477 // Perform lowpass and highpass filters on statistics 00478 void filterStats(vector<double> &filter, int &filtsize, bool &pause_crop, 00479 int &channel) { 00480 int fsize = (int)filter.size(); 00481 const int left_cut = 4; 00482 const int right_cut = 4; 00483 const int ch_pause_cnt = 3; 00484 const int ch_pause[2][ch_pause_cnt] = {{252,515,778},{247,510,773}}; 00485 const int ch_width[2][ch_pause_cnt] = {{11,11,11},{11,11,11}}; 00486 const string ch_direc[2] = {"RIGHT","LEFT"}; 00487 const int iterations = 10; 00488 vector<double> filtin; 00489 vector<double> filtout; 00490 vector<double> filtorig; 00491 VecFilter vfilter; 00492 00493 filtorig = filter; 00494 00495 // To avoid filter ringing, cut out those areas in the data that 00496 // are especially problematic such as the left and right edges and 00497 // at the pause points 00498 for (int i=0; i<=left_cut-1; i++) { 00499 filter[i] = 0.0; 00500 } 00501 for (int i=fsize-1; i>=fsize-right_cut; i--) { 00502 filter[i] = 0.0; 00503 } 00504 00505 // Zero out the pause point pixels if requested and the input 00506 // image file has a bin mode of 1 00507 if (pause_crop && fsize == 1024) { 00508 for (int i=0; i<ch_pause_cnt; i++) { 00509 int i1; 00510 int i2; 00511 if (ch_direc[channel] == "LEFT") { 00512 i1 = ch_pause[channel][i] - ch_width[channel][i]; 00513 i2 = ch_pause[channel][i] - 1; 00514 } else { 00515 i1 = ch_pause[channel][i] - 1; 00516 i2 = ch_pause[channel][i] + ch_width[channel][i] - 2; 00517 } 00518 if (i1 < 0) i1 = 0; 00519 if (i2 > fsize-1) i2 = fsize - 1; 00520 for (int j=i1; j<=i2; j++) { 00521 filter[j] = 0.0; 00522 } 00523 } 00524 } 00525 00526 // Here is the boxfilter - the outer most loop is for the number 00527 // of filter iterations 00528 filtin = filter; 00529 00530 for (int pass=1; pass<=3; pass++) { 00531 for (int it=1; it<=iterations; it++) { 00532 filtout = vfilter.LowPass(filter,filtsize); 00533 filter = filtout; 00534 } 00535 00536 // Zero out any columns that are different from the average by more 00537 // than a specific percent 00538 if (pass < 3) { 00539 double frac = .25; 00540 if (pass == 2) frac = .125; 00541 for (int k=0; k<fsize; k++) { 00542 if (filter[k] != 0.0 && filtorig[k] != 0.0) { 00543 if (fabs(filtorig[k] - filter[k])/filter[k] > frac) { 00544 filtin[k] = 0.0; 00545 } 00546 } 00547 } 00548 filter = filtin; 00549 } 00550 } 00551 00552 // Perform the highpass by differencing the original from the lowpass 00553 filter = vfilter.HighPass(filtorig,filtout); 00554 00555 filtin.clear(); 00556 filtout.clear(); 00557 filtorig.clear(); 00558 }