|
Isis 3.0 Application Source Code Reference |
Home |
00001 #include <cmath> 00002 #include "Isis.h" 00003 #include "QuickFilter.h" 00004 #include "NumericalApproximation.h" 00005 #include "ProcessByLine.h" 00006 #include "SpecialPixel.h" 00007 #include "Pvl.h" 00008 00009 #include "Buffer.h" 00010 #include "Statistics.h" 00011 #include "MultivariateStatistics.h" 00012 #include "Table.h" 00013 00014 #include "tnt_array1d.h" 00015 00016 typedef TNT::Array1D<double> HiVector; //!< 1-D Buffer 00017 00018 using namespace Isis; 00019 using namespace std; 00020 00021 void histitch(vector<Buffer *> &in, vector<Buffer *> &out); 00022 void getStats(std::vector<Isis::Buffer *> &in, 00023 std::vector<Isis::Buffer *> &out); 00024 00025 Statistics stats0; 00026 Statistics stats1; 00027 MultivariateStatistics stats; 00028 00029 struct ChannelInfo { 00030 int ChnNumber; 00031 unsigned nLines; 00032 unsigned nSamples; 00033 unsigned offset; 00034 HiVector mult, add; 00035 ChannelInfo() : ChnNumber(1), nLines(0), nSamples(0), offset(0) { } 00036 }; 00037 00038 static ChannelInfo fromData[2]; 00039 double average0 = Isis::Null; 00040 double average1 = Isis::Null; 00041 HiVector f0LineAvg; 00042 HiVector f1LineAvg; 00043 double coeff; 00044 QString balance; 00045 int seamSize; 00046 int skipSize; 00047 00048 00049 inline HiVector filter(const HiVector &v, int width) { 00050 QuickFilter lowpass(v.dim(), width, 1); 00051 lowpass.AddLine(&v[0]); 00052 HiVector vout(v.dim()); 00053 for(int i = 0 ; i < v.dim() ; i ++) { 00054 vout[i] = lowpass.Average(i); 00055 } 00056 return (vout); 00057 } 00058 00059 //2008-11-05 Jeannie Walldren Replaced references to DataInterp class with NumericalApproximation. 00060 inline HiVector filler(const HiVector &v, int &nfilled) { 00061 NumericalApproximation spline(NumericalApproximation::CubicNatural); 00062 for(int i = 0 ; i < v.dim() ; i++) { 00063 if(!IsSpecial(v[i])) { 00064 spline.AddData(i, v[i]); 00065 } 00066 } 00067 00068 // Compute the spline and fill missing data 00069 HiVector vout(v.dim()); 00070 nfilled = 0; 00071 for(int j = 0 ; j < v.dim() ; j++) { 00072 if(IsSpecial(v[j])) { 00073 vout[j] = spline.Evaluate(j, NumericalApproximation::NearestEndpoint); 00074 nfilled++; 00075 } 00076 else { 00077 vout[j] = v[j]; 00078 } 00079 } 00080 return (vout); 00081 } 00082 00083 HiVector compRatio(const HiVector &c0, const HiVector &c1, int &nNull) { 00084 nNull = 0; 00085 HiVector vout(c0.dim()); 00086 for(int i = 0 ; i < c0.dim() ; i++) { 00087 if(IsSpecial(c0[i]) || IsSpecial(c1[i]) || (c1[i] == 0.0)) { 00088 vout[i] = 1.0; 00089 nNull++; 00090 } 00091 else { 00092 vout[i] = c0[i] / c1[i]; 00093 } 00094 } 00095 return (vout); 00096 } 00097 00098 HiVector compAdd(const HiVector &c0, const HiVector &c1, int &nNull) { 00099 nNull = 0; 00100 HiVector vout(c0.dim()); 00101 for(int i = 0 ; i < c0.dim() ; i++) { 00102 if(IsSpecial(c0[i]) || IsSpecial(c1[i])) { 00103 vout[i] = 0.0; 00104 nNull++; 00105 } 00106 else { 00107 vout[i] = c0[i] - c1[i]; 00108 } 00109 } 00110 return (vout); 00111 } 00112 00113 00114 00115 void IsisMain() { 00116 // Get user interface to test for input conditions 00117 UserInterface &ui = Application::GetUserInterface(); 00118 balance = ui.GetString("BALANCE"); 00119 seamSize = ui.GetInteger("SEAMSIZE"); 00120 skipSize = ui.GetInteger("SKIP"); 00121 int filterWidth = ui.GetInteger("WIDTH"); 00122 bool fillNull = ui.GetBoolean("FILL"); 00123 int hiChannel = ui.GetInteger("CHANNEL"); 00124 QString fixop = ui.GetString("OPERATOR"); 00125 coeff = 1; 00126 00127 // Define the processing to be by line 00128 ProcessByLine p; 00129 00130 //Set string to gather ProductIds. 00131 QString stitchedProductIds; 00132 00133 // Obtain lines and samples of the input files. Note that conditions 00134 // are obtained from the first input file only unless provided from a 00135 // second file 00136 Cube *icube1 = p.SetInputCube("FROM1"); 00137 fromData[0].nLines = fromData[1].nLines = icube1->lineCount(); 00138 fromData[0].nSamples = fromData[1].nSamples = icube1->sampleCount(); 00139 fromData[0].mult = HiVector(icube1->lineCount(), 1.0); 00140 fromData[0].add = HiVector(icube1->lineCount(), 0.0); 00141 00142 if(seamSize + skipSize > icube1->sampleCount()) { 00143 QString msg = "SEAMSIZE [" + toString(seamSize) + "] + SKIP [" + toString(skipSize) + "] must "; 00144 msg += " be less than the number of samples [" + toString(icube1->sampleCount()) + "] in "; 00145 msg += "[" + ui.GetAsString("FROM1") + "]"; 00146 throw IException(IException::User, msg, _FILEINFO_); 00147 } 00148 00149 PvlGroup &from1Archive = icube1->group("ARCHIVE"); 00150 PvlGroup &from1Instrument = icube1->group("INSTRUMENT"); 00151 fromData[0].ChnNumber = from1Instrument["ChannelNumber"]; 00152 00153 stitchedProductIds = (QString)from1Archive["ProductId"][0]; 00154 00155 // Set initial conditions for one input file 00156 if(fromData[0].ChnNumber == 1) { 00157 fromData[0].offset = 0; 00158 } 00159 else { 00160 if(fromData[0].ChnNumber != 0) { 00161 string msg = "FROM1 channel number must be 1 or 2"; 00162 throw IException(IException::User, msg, _FILEINFO_); 00163 } 00164 fromData[0].offset = fromData[0].nSamples; 00165 } 00166 00167 // Only get the second input file if entered by the user 00168 if(ui.WasEntered("FROM2")) { 00169 Cube *icube2 = p.SetInputCube("FROM2"); 00170 fromData[1].nLines = icube2->lineCount(); 00171 fromData[1].nSamples = icube2->sampleCount(); 00172 fromData[1].mult = HiVector(icube2->lineCount(), 1.0); 00173 fromData[1].add = HiVector(icube2->lineCount(), 0.0); 00174 00175 if(seamSize + skipSize > icube2->sampleCount()) { 00176 QString msg = "SEAMSIZE [" + toString(seamSize) + "] + SKIP [" + toString(skipSize) + "] must "; 00177 msg += " be less than the number of samples [" + toString(icube2->sampleCount()) + " in "; 00178 msg += "[" + ui.GetAsString("FROM2") + "]"; 00179 throw IException(IException::User, msg, _FILEINFO_); 00180 } 00181 00182 //Test to make sure input files are compatable 00183 PvlGroup &from2Archive = icube2->group("ARCHIVE"); 00184 00185 //Make sure observation id's are the same 00186 QString from1ObsId = from1Archive["ObservationId"]; 00187 QString from2ObsId = from2Archive["ObservationId"]; 00188 if(from1ObsId != from2ObsId) { 00189 QString msg = "The input files Observation Id's are not compatable"; 00190 throw IException(IException::User, msg, _FILEINFO_); 00191 } 00192 stitchedProductIds = "(" + stitchedProductIds + ", " + 00193 (QString)from2Archive["ProductId"][0] + ")"; 00194 00195 PvlGroup &from2Instrument = icube2->group("INSTRUMENT"); 00196 00197 //Make sure CCD Id's are the same 00198 QString from1CcdId = from1Instrument["CCDId"]; 00199 QString from2CcdId = from2Instrument["CCDId"]; 00200 if(from1CcdId != from2CcdId) { 00201 string msg = "The input files CCD Id's are not compatable"; 00202 throw IException(IException::User, msg, _FILEINFO_); 00203 } 00204 00205 //Make sure channel numbers are equal to 0 & 1 00206 fromData[1].ChnNumber = from2Instrument["ChannelNumber"]; 00207 if(!((fromData[0].ChnNumber == 0) && (fromData[1].ChnNumber == 1)) && 00208 !((fromData[0].ChnNumber == 1) && (fromData[1].ChnNumber == 0))) { 00209 string msg = "The input files Channel numbers must be equal to 0 and 1"; 00210 throw IException(IException::User, msg, _FILEINFO_); 00211 } 00212 00213 // Set up offsets 00214 if(fromData[0].ChnNumber == 1) { 00215 fromData[0].offset = 0; 00216 fromData[1].offset = fromData[0].nSamples; 00217 } 00218 else { 00219 fromData[1].offset = 0; 00220 fromData[0].offset = fromData[1].nSamples; 00221 } 00222 } 00223 00224 unsigned int LinesOut = max(fromData[0].nLines, fromData[1].nLines); 00225 unsigned int SampsOut = fromData[0].nSamples + fromData[1].nSamples; 00226 unsigned int BandsOut = 1; 00227 00228 Cube *ocube = p.SetOutputCube("TO", SampsOut, LinesOut, BandsOut); 00229 00230 // Change Channel Number on output cube to 2 00231 PvlGroup &InstrumentOut = ocube->group("INSTRUMENT"); 00232 InstrumentOut["ChannelNumber"] = "2"; 00233 00234 // Set StitchedChannels and Stitched ProductIds keywords 00235 if(ui.WasEntered("FROM2")) { 00236 InstrumentOut += PvlKeyword("StitchedChannels", "(0,1)"); 00237 InstrumentOut += PvlKeyword("StitchedProductIds", stitchedProductIds); 00238 } 00239 else { 00240 InstrumentOut += PvlKeyword("StitchedChannels", toString(fromData[0].ChnNumber)); 00241 InstrumentOut += PvlKeyword("StitchedProductIds", stitchedProductIds); 00242 } 00243 00244 // Do balance correction 00245 PvlGroup results("Results"); 00246 results += PvlKeyword("Balance", balance); 00247 if((balance == "TRUE") || (balance == "EQUALIZE")) { 00248 ProcessByLine pAvg; 00249 00250 if(ui.WasEntered("FROM2")) { 00251 00252 00253 int ch0Index = 0; 00254 int ch1Index = 1; 00255 if(fromData[0].ChnNumber == 0) { 00256 pAvg.SetInputCube("FROM1"); 00257 pAvg.SetInputCube("FROM2"); 00258 } 00259 00260 if(fromData[1].ChnNumber == 0) { 00261 ch0Index = 1; 00262 ch1Index = 0; 00263 pAvg.SetInputCube("FROM2"); 00264 pAvg.SetInputCube("FROM1"); 00265 } 00266 00267 stats.Reset(); 00268 f0LineAvg = HiVector(icube1->lineCount()); 00269 f1LineAvg = HiVector(icube1->lineCount()); 00270 pAvg.StartProcess(getStats); 00271 pAvg.EndProcess(); 00272 00273 if(balance == "TRUE") { 00274 average0 = stats.X().Average(); 00275 average1 = stats.Y().Average(); 00276 if(hiChannel == 0) { 00277 if(average1 != Isis::Null) { 00278 coeff = average0 / average1; 00279 fromData[ch1Index].mult = coeff; 00280 } 00281 } 00282 else { 00283 if(average0 != Isis::Null) { 00284 coeff = average1 / average0; 00285 fromData[ch0Index].mult = coeff; 00286 } 00287 } 00288 results += PvlKeyword("TruthChannel", toString(hiChannel)); 00289 results += PvlKeyword("BalanceRatio", toString(coeff)); 00290 } 00291 else { 00292 // Store off original averages for table 00293 HiVector ch0_org = f0LineAvg; 00294 HiVector ch1_org = f1LineAvg; 00295 00296 results += PvlKeyword("FilterWidth", toString(filterWidth)); 00297 if(filterWidth > 0) { 00298 f0LineAvg = filter(f0LineAvg, filterWidth); 00299 f1LineAvg = filter(f1LineAvg, filterWidth); 00300 } 00301 00302 results += PvlKeyword("Fill", ((fillNull) ? "TRUE" : "FALSE")); 00303 if(fillNull) { 00304 int nfilled; 00305 f0LineAvg = filler(f0LineAvg, nfilled); 00306 results += PvlKeyword("Channel0Filled", toString(nfilled)); 00307 f1LineAvg = filler(f1LineAvg, nfilled); 00308 results += PvlKeyword("Channel1Filled", toString(nfilled)); 00309 } 00310 00311 results += PvlKeyword("TruthChannel", toString(hiChannel)); 00312 results += PvlKeyword("Operator", fixop); 00313 int nunfilled(0); 00314 HiVector ch0_fixed(icube1->lineCount(), 1.0); 00315 HiVector ch1_fixed(icube1->lineCount(), 1.0); 00316 if(fixop == "MULTIPLY") { 00317 if(hiChannel == 0) { 00318 fromData[ch1Index].mult = compRatio(f0LineAvg, f1LineAvg, nunfilled); 00319 ch1_fixed = fromData[ch1Index].mult; 00320 } 00321 else { 00322 fromData[ch0Index].mult = compRatio(f1LineAvg, f0LineAvg, nunfilled); 00323 ch0_fixed = fromData[ch0Index].mult; 00324 } 00325 } 00326 else { 00327 if(hiChannel == 0) { 00328 fromData[ch1Index].add = compAdd(f0LineAvg, f1LineAvg, nunfilled); 00329 ch1_fixed = fromData[ch1Index].add; 00330 ch0_fixed = 0.0; 00331 } 00332 else { 00333 fromData[ch0Index].add = compAdd(f1LineAvg, f0LineAvg, nunfilled); 00334 ch0_fixed = fromData[ch0Index].mult; 00335 ch1_fixed = 0.0; 00336 } 00337 } 00338 results += PvlKeyword("UnFilled", toString(nunfilled)); 00339 00340 // Add a table to the output file of the data values 00341 TableField f1("Channel1Original", Isis::TableField::Double); 00342 TableField f2("Channel0Original", Isis::TableField::Double); 00343 TableField f3("Channel1Correction", Isis::TableField::Double); 00344 TableField f4("Channel0Correction", Isis::TableField::Double); 00345 TableRecord rec; 00346 rec += f1; 00347 rec += f2; 00348 rec += f3; 00349 rec += f4; 00350 Table table("HistitchStats", rec); 00351 for(int i = 0 ; i < ch1_org.dim() ; i++) { 00352 rec[0] = ch1_org[i]; 00353 rec[1] = ch0_org[i]; 00354 rec[2] = ch1_fixed[i]; 00355 rec[3] = ch0_fixed[i]; 00356 table += rec; 00357 } 00358 00359 PvlGroup stitch = results; 00360 stitch.SetName("HiStitch"); 00361 table.Label().AddGroup(stitch); 00362 ocube->write(table); 00363 } 00364 } 00365 00366 } // end if balance = TRUE 00367 00368 // Begin processing the input cubes to output cube. 00369 p.StartProcess(histitch); 00370 // All Done 00371 PvlGroup stitch = results; 00372 stitch.SetName("HiStitch"); 00373 ocube->putGroup(stitch); 00374 p.EndProcess(); 00375 Application::Log(results); 00376 } 00377 00378 void getStats(std::vector<Buffer *> &in, std::vector<Buffer *> &out) { 00379 Buffer &channel0 = *in[0]; 00380 Buffer &channel1 = *in[1]; 00381 double x, y; 00382 00383 Statistics c0, c1; 00384 for(int i = 0; i < seamSize + 1; i++) { 00385 00386 // set the x value 00387 x = channel0[skipSize + i]; 00388 c0.AddData(x); 00389 00390 // set the y value 00391 y = channel1[channel1.size() - (skipSize + 1) - i] ; 00392 c1.AddData(y); 00393 00394 stats.AddData(&x, &y, 1); 00395 } 00396 00397 f0LineAvg[channel0.Line()-1] = c0.Average(); 00398 f1LineAvg[channel1.Line()-1] = c1.Average(); 00399 } 00400 00401 // Line processing routine 00402 void histitch(vector<Buffer *> &in, vector<Buffer *> &out) { 00403 Buffer &ot = *out[0]; 00404 00405 // Initialize the buffer 00406 for(int n = 0 ; n < ot.size() ; n++) ot[n] = NULL8; 00407 00408 // Place the channel data into the output buffer 00409 vector<Buffer *>::iterator ibuf; 00410 int ifrom; 00411 int line = ot.Line() - 1; 00412 for(ibuf = in.begin(), ifrom = 0 ; ibuf != in.end() ; ++ibuf, ++ifrom) { 00413 Buffer &inbuf = *(*ibuf); 00414 const HiVector &mult = fromData[ifrom].mult; 00415 const HiVector &add = fromData[ifrom].add; 00416 00417 unsigned int oIndex(fromData[ifrom].offset); 00418 for(int i = 0; i < inbuf.size(); i++, oIndex++) { 00419 if(Isis::IsSpecial(inbuf[i])) { 00420 ot[oIndex] = inbuf[i]; 00421 } 00422 else { 00423 ot[oIndex] = inbuf[i] * mult[line] + add[line]; 00424 } 00425 } 00426 } 00427 return; 00428 }