USGS

Isis 3.0 Application Source Code Reference

Home

thmnoseam.cpp

Go to the documentation of this file.
00001 #include "Isis.h"
00002 
00003 #include <string>
00004 
00005 #include <QList>
00006 #include <QPair>
00007 
00008 #include "Chip.h"
00009 #include "ThemisVisCamera.h"
00010 #include "SpecialPixel.h"
00011 #include "ProcessByLine.h"
00012 #include "CameraFactory.h"
00013 #include "PushFrameCameraGroundMap.h"
00014 
00015 using namespace Isis;
00016 using namespace std;
00017 
00018 //! This is the method called by ProcessByBrick.
00019 void FixSeams(vector<Buffer *> &inBuffers, vector<Buffer *> &outBuffers);
00020 
00021 //! This function calculates about how much the framelets overlap 
00022 int FrameletOverlapSize();
00023 int frameletSize; //!< This is the number of lines in a framelet
00024 Cube *evenCube; //!< Input even framelet cube
00025 Cube *oddCube; //!< Input odd framelet cube
00026 Cube *outEven; //!< Output even framelet cube
00027 Cube *outOdd; //!< Output odd framelet cube
00028 int overlapSize; //!< This stores the result of FrameletOverlapSize()
00029 
00030 // sample,line -> DN
00031 QList< QPair< QPair<int, int>, double> > nextFrameletFixes;
00032 
00033 /**
00034  *
00035  * This class is used to remember a translation between the bottom of one
00036  *   framelet and the top of the next. These stay fairly constant for one band.
00037  *
00038  * @author ????-??-?? Unknown
00039  *
00040  * @internal
00041  */
00042 class Offset {
00043   public:
00044     Offset()
00045     {
00046       p_valid = false;
00047     }
00048     
00049     Offset(int sample, int frameletLine, int sampleOffset, int lineOffset)
00050     {
00051       p_valid = true;
00052       p_sample = sample;
00053       p_frameletLine = frameletLine;
00054       p_sampleOffset = sampleOffset;
00055       p_lineOffset = lineOffset;
00056     }
00057     
00058     //! Offset should be used
00059     bool Valid() { return p_valid; }
00060     //! Used to verify we're at the correct sample
00061     int Sample() { return p_sample; }
00062     //! Used to verify we're at the correct line
00063     int FrameletLine() { return p_frameletLine; }
00064     //! Translation between current sample and next framelet's sample
00065     int SampleOffset() { return p_sampleOffset; }
00066     //! Translation between current line and next framelet's line
00067     int LineOffset() { return p_lineOffset; }
00068     
00069   private:
00070     bool p_valid;
00071     int p_sample;
00072     int p_frameletLine;
00073     int p_sampleOffset;
00074     int p_lineOffset;
00075 };
00076 
00077 //! This is a list of all translations for a band between the bottom of one
00078 //!   framelet and the top of the next.
00079 QList< Offset > frameletOffsetsForBand;
00080 
00081 void IsisMain() {
00082   // Grab the file to import
00083   ProcessByBrick p;
00084   evenCube = p.SetInputCube("INEVEN");
00085   oddCube = p.SetInputCube("INODD");
00086   outEven = p.SetOutputCube("OUTEVEN");
00087   outOdd = p.SetOutputCube("OUTODD");
00088 
00089   UserInterface &ui = Application::GetUserInterface();
00090   // Make sure it is a Themis EDR/RDR
00091   try {
00092     if(evenCube->getGroup("Instrument")["InstrumentID"][0] != "THEMIS_VIS") {
00093       throw iException::Message(iException::User, "", _FILEINFO_);
00094     }
00095   }
00096   catch(iException &e) {
00097     e.Clear();
00098 
00099     string msg = "This program is intended for use on THEMIS VIS images only";
00100     msg += " [" + ui.GetFilename("INEVEN") + "] does not appear to be a ";
00101     msg += "THEMIS VIS image.";
00102     throw iException::Message(iException::User, msg, _FILEINFO_);
00103   }
00104 
00105   try {
00106     if(oddCube->getGroup("Instrument")["InstrumentID"][0] != "THEMIS_VIS") {
00107       throw iException::Message(iException::User, "", _FILEINFO_);
00108     }
00109   }
00110   catch(iException &e) {
00111     e.Clear();
00112 
00113     string msg = "This program is intended for use on THEMIS VIS images only";
00114     msg += " [" + ui.GetFilename("INODD") + "] does not appear to be a ";
00115     msg += "THEMIS VIS image.";
00116     throw iException::Message(iException::User, msg, _FILEINFO_);
00117   }
00118   
00119   if (evenCube->getGroup("Instrument")["Framelets"][0] != "Even") {
00120     string msg = "The image [" + ui.GetFilename("INEVEN") + "] does not appear "
00121         "to contain the EVEN framelets of a Themis VIS cube";
00122     throw iException::Message(iException::User, msg, _FILEINFO_);
00123   }
00124   
00125   if (oddCube->getGroup("Instrument")["Framelets"][0] != "Odd") {
00126     string msg = "The image [" + ui.GetFilename("ODDEVEN") + "] does not appear "
00127         "to contain the ODD framelets of a Themis VIS cube";
00128     throw iException::Message(iException::User, msg, _FILEINFO_);
00129   }
00130   
00131   PvlGroup &inputInstrumentGrp = evenCube->getGroup("Instrument");
00132   PvlKeyword &spatialSumming = inputInstrumentGrp["SpatialSumming"];
00133   frameletSize = 192 / (int)spatialSumming[0];
00134   overlapSize = FrameletOverlapSize();
00135 
00136   if(overlapSize == 0)
00137   {
00138     iString msg = "There must be overlap to remove seams";
00139     throw iException::Message(iException::Camera, msg, _FILEINFO_);
00140   }
00141   
00142   p.SetBrickSize(evenCube->getSampleCount(), frameletSize, 1);
00143   
00144   p.StartProcess(FixSeams);
00145   
00146   PvlGroup &evenInst = outEven->getGroup("Instrument");
00147   evenInst["Framelets"] = "Even";
00148   
00149   PvlGroup &oddInst = outOdd->getGroup("Instrument");
00150   oddInst["Framelets"] = "Odd";
00151   
00152   p.EndProcess();
00153 }
00154 
00155 //! This function corrects the DNs in a given brick.
00156 //! It also stores results in frameletOffsetsForBand every time the
00157 //! band changes so it doesn't have to re-project at every framelet.
00158 //! Equivalent changes are calculated for the next framelet... that is,
00159 //! equivalent pixels. This function both calculates and applies these.
00160 void RemoveSeam(Buffer &out, int framelet, int band, 
00161                 bool matchIsEven)
00162 {
00163   // Apply fixes from last pass. Basically all changes happen in two
00164   //   places, because the DNs exist in two cubes, this is the second
00165   //   place.
00166   for(int fix = 0; fix < nextFrameletFixes.size(); fix ++)
00167   {
00168     QPair<int, int> fixLoc = nextFrameletFixes[fix].first;
00169     double fixDn = nextFrameletFixes[fix].second;
00170 
00171     try
00172     {
00173       int outIndex = out.Index(fixLoc.first, fixLoc.second, band);
00174       out[outIndex] = fixDn;
00175     }
00176     catch(iException &e)
00177     {
00178       e.Clear();
00179     }
00180   }
00181   
00182   nextFrameletFixes.clear();
00183 
00184   // Match == goodData. "goodData" is the top of the next framelet.
00185   Cube *goodDataCube = (matchIsEven) ? evenCube : oddCube;
00186   // "badData" is the bottom of the current framelet, what we were given.
00187   Cube *badDataCube  = (matchIsEven) ? oddCube  : evenCube;
00188   
00189   Camera *goodCam = goodDataCube->getCamera();
00190   Camera *badCam  = badDataCube->getCamera();
00191   
00192   // Verify we're at the correct band
00193   goodCam->SetBand(band);
00194   badCam->SetBand(band);
00195   
00196   // Absolute line number for top of framelets.
00197   int goodDataStart = frameletSize * (framelet + 1);
00198   int badDataStart = frameletSize * framelet;
00199 
00200   // Start corrections to the current brick at this line
00201   int badLineStart = goodDataStart - overlapSize - 1;
00202   // End corrections to the current brick at this line
00203   int badLineEnd = goodDataStart - 1;
00204   
00205   int offsetSample = 0;
00206   int offsetLine = 0;
00207 
00208   // Loop left to right, top to bottom of problematic area at bottom of framelet
00209   for(int badLine = badLineStart; badLine <= badLineEnd; badLine ++)
00210   {
00211     for(int sample = 1; sample <= out.SampleDimension(); sample ++)
00212     {
00213       // A fair good data weight is the % across problematic area so fair
00214       double goodDataWeight = (double)(badLine - badLineStart) / 
00215                              (double)(badLineEnd - badLineStart);
00216       
00217       // But good data is good, so let's bias it towards the good data
00218       goodDataWeight *= 2;
00219       if(goodDataWeight > 1) goodDataWeight = 1;
00220 
00221       // Bad data weight is the inverse of the good data's weight.
00222       double badDataWeight = 1.0 - goodDataWeight;
00223 
00224       int outIndex = out.Index(sample, badLine, band);
00225       // This is the indexing scheme for frameletOffsetsForBand
00226       int optimizeIndex = (badLine - badLineStart) * out.SampleDimension() +
00227                           sample - 1;
00228 
00229       // Does the optimized (pre-calculated) translation from bad to good
00230       //  exist?
00231       if(optimizeIndex < frameletOffsetsForBand.size())
00232       {
00233         // This offset any good? If not then do nothing.
00234         if(!frameletOffsetsForBand[optimizeIndex].Valid())
00235           continue;
00236 
00237         // Use optimization!
00238         offsetSample = frameletOffsetsForBand[optimizeIndex].SampleOffset();
00239         offsetLine = frameletOffsetsForBand[optimizeIndex].LineOffset();
00240 
00241         ASSERT(frameletOffsetsForBand[optimizeIndex].Sample() == sample);
00242       }
00243       // There is no pre-calculated translation, calculate it
00244       else if(badCam->SetImage(sample, badLine))
00245       {
00246         double lat = badCam->UniversalLatitude();
00247         double lon = badCam->UniversalLongitude();
00248 
00249         if(goodCam->SetUniversalGround(lat, lon))
00250         {
00251           double goodSample = goodCam->Sample();
00252           double goodLine = goodCam->Line();
00253           
00254           // Set the current offset for correction
00255           offsetSample = (int)(goodSample - sample + 0.5);
00256           offsetLine = (int)(goodLine - badLine + 0.5);
00257 
00258           // Remember this calculation for future passes
00259           frameletOffsetsForBand.push_back(Offset(sample, badLine - badDataStart,
00260                                                   offsetSample, offsetLine));
00261         }
00262         else
00263         {
00264           // Don't do anything since we failed at this pixel; it will be copied
00265           //   from the input directly
00266           frameletOffsetsForBand.push_back(Offset());
00267           continue;
00268         }
00269       }
00270       
00271       // Translate current sample,line (bad) to (good) data's sample,line
00272       double goodSample = offsetSample + sample;
00273       double goodLine = offsetLine + badLine;
00274 
00275       // Get the pixel we're missing (good)
00276       Portal p(1, 1, goodDataCube->getPixelType());
00277       p.SetPosition(goodSample, goodLine, band);
00278       goodDataCube->read(p);
00279       
00280       // Attempt to apply weighted average
00281       if(!Isis::IsSpecial(p[0]) && !Isis::IsSpecial(out[outIndex]))
00282       {
00283         out[outIndex] = p[0] * goodDataWeight + out[outIndex] * badDataWeight;
00284       }
00285       else if(!Isis::IsSpecial(p[0]))
00286       {
00287         out[outIndex] = p[0];
00288       }
00289         
00290       // Apply change to next framelet also
00291       QPair<int, int> fixLoc((int)(goodSample + 0.5),
00292                              (int)(goodLine   + 0.5));
00293       QPair< QPair<int, int>, double > fix(fixLoc, out[outIndex]);
00294       nextFrameletFixes.push_back(fix);
00295     }
00296   }
00297 }
00298 
00299 
00300 /**
00301  * This is the main loop over the cube data. Statistics are used to
00302  *   calculate which brick actually contains DNs. The framelet with DNs
00303  *   is corrected by RemoveSeam and this also clears remembered offsets
00304  *   (used for speed optimization) when the band changes.
00305  */
00306 void FixSeams(vector<Buffer *> &inBuffers, vector<Buffer *> &outBuffers) {
00307   Buffer &evenBuffer    = *inBuffers[0];
00308   Buffer &oddBuffer     = *inBuffers[1];
00309   
00310   Buffer &outEvenBuffer = *outBuffers[0];
00311   Buffer &outOddBuffer  = *outBuffers[1];
00312   
00313   outEvenBuffer.Copy(evenBuffer);
00314   outOddBuffer.Copy(oddBuffer);
00315   
00316   Statistics evenStats;
00317   evenStats.AddData(evenBuffer.DoubleBuffer(), evenBuffer.size());
00318   
00319   Statistics oddStats;
00320   oddStats.AddData(oddBuffer.DoubleBuffer(), oddBuffer.size());
00321   
00322   int framelet = (evenBuffer.Line() - 1) / frameletSize;
00323   
00324   if(framelet == 0) {
00325     frameletOffsetsForBand.clear();
00326   }
00327   
00328   if(evenStats.ValidPixels() > oddStats.ValidPixels())
00329   {
00330     RemoveSeam(outEvenBuffer, framelet, evenBuffer.Band(), false);
00331   }
00332   else
00333   {
00334     RemoveSeam(outOddBuffer, framelet, oddBuffer.Band(), true);
00335   }
00336 }
00337 
00338 
00339 /**
00340  * This calculates the number of lines of overlap between framelets.
00341  */
00342 int FrameletOverlapSize() {
00343   Camera *camEven = evenCube->getCamera();
00344   Camera *camOdd = oddCube->getCamera();
00345   
00346   if(camEven == NULL || camOdd == NULL) {
00347     string msg = "A camera is required to automatically calculate the overlap "
00348                  "between framelets. Please run spiceinit on the input cube";
00349     throw iException::Message(iException::Camera, msg, _FILEINFO_);
00350   }
00351 
00352   int frameletOverlap = 0;
00353 
00354   // Framelet 2 is even, so let's use the even camera to find the lat,lon at it's beginning
00355   if(camEven->SetImage(1, frameletSize + 1)) {
00356     double framelet2StartLat = camEven->UniversalLatitude();
00357     double framelet2StartLon = camEven->UniversalLongitude();
00358 
00359     // Let's figure out where this is in the nearest odd framelet (hopefully framelet 1)
00360     if(camOdd->SetUniversalGround(framelet2StartLat, framelet2StartLon)) {
00361       // The equivalent line to the start of framelet 2 is this found line
00362       int equivalentLine = (int)(camOdd->Line() + 0.5);
00363       frameletOverlap = frameletSize - equivalentLine;
00364       if(frameletOverlap < 0) frameletOverlap = 0;
00365     }
00366   }
00367 
00368   return frameletOverlap;
00369 }