USGS

Isis 3.0 Application Source Code Reference

Home

histitch.cpp

Go to the documentation of this file.
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 }