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