USGS

Isis 3.0 Application Source Code Reference

Home

hi2isis.cpp

Go to the documentation of this file.
00001 #include "Isis.h"
00002 
00003 #include <cstdio>
00004 #include <QString>
00005 
00006 #include "ProcessImportPds.h"
00007 #include "ProcessByLine.h"
00008 
00009 #include "UserInterface.h"
00010 #include "FileName.h"
00011 #include "IException.h"
00012 #include "iTime.h"
00013 #include "Preference.h"
00014 #include "Buffer.h"
00015 #include "PvlGroup.h"
00016 #include "PvlKeyword.h"
00017 #include "PvlSequence.h"
00018 #include "Stretch.h"
00019 
00020 using namespace std;
00021 using namespace Isis;
00022 
00023 // Global variables for processing functions
00024 Stretch stretch;
00025 
00026 // The input raw EDR contains 6 sections. The following counts keep track
00027 // of the types of pixels found in each section. The order of sections
00028 // is the order they arae encountered within the raw EDR. (i.e., calibration
00029 // buffer, calibration image, calibration dark/reference, image buffer,
00030 // image, image dark/reference)
00031 int gapCount[6];
00032 int suspectGapCount[6];
00033 int invalidCount[6];
00034 int lisCount[6];
00035 int hisCount[6];
00036 int validCount[6];
00037 int section;
00038 
00039 bool lsbGap;
00040 
00041 
00042 void IsisMain() {
00043   stretch.ClearPairs();
00044 
00045   for(int i = 0; i < 6; i++) {
00046     gapCount[i] = 0;
00047     suspectGapCount[i] = 0;
00048     invalidCount[i] = 0;
00049     lisCount[i] = 0;
00050     hisCount[i] = 0;
00051     validCount[i] = 0;
00052   }
00053 
00054   void TranslateHiriseEdrLabels(FileName & labelFile, Cube *);
00055   void SaveHiriseCalibrationData(ProcessImportPds & process, Cube *,
00056                                  Pvl & pdsLabel);
00057   void SaveHiriseAncillaryData(ProcessImportPds & process, Cube *);
00058   void FixDns8(Buffer & buf);
00059   void FixDns16(Buffer & buf);
00060 
00061   ProcessImportPds p;
00062   Pvl pdsLabel;
00063   UserInterface &ui = Application::GetUserInterface();
00064 
00065   // Get the input filename and make sure it is a HiRISE EDR
00066   FileName inFile = ui.GetFileName("FROM");
00067   QString id;
00068   bool projected;
00069   try {
00070     Pvl lab(inFile.expanded());
00071     id = (QString) lab.FindKeyword("DATA_SET_ID");
00072     projected = lab.HasObject("IMAGE_MAP_PROJECTION");
00073   }
00074   catch(IException &e) {
00075     QString msg = "Unable to read [DATA_SET_ID] from input file [" +
00076                  inFile.expanded() + "]";
00077     throw IException(e, IException::Io, msg, _FILEINFO_);
00078   }
00079 
00080   //Checks if in file is rdr
00081   if(projected) {
00082     QString msg = "[" + inFile.name() + "] appears to be an rdr file.";
00083     msg += " Use pds2isis.";
00084     throw IException(IException::User, msg, _FILEINFO_);
00085   }
00086 
00087   id = id.simplified().trimmed();
00088   if(id != "MRO-M-HIRISE-2-EDR-V1.0") {
00089     QString msg = "Input file [" + inFile.expanded() + "] does not appear to be " +
00090                  "in HiRISE EDR format. DATA_SET_ID is [" + id + "]";
00091     throw IException(IException::Io, msg, _FILEINFO_);
00092   }
00093 
00094   p.SetPdsFile(inFile.expanded(), "", pdsLabel);
00095 
00096   // Make sure the data we need for the BLOBs is saved by the Process
00097   p.SaveFileHeader();
00098   p.SaveDataPrefix();
00099   p.SaveDataSuffix();
00100 
00101   // Let the Process create the output file but override any commandline
00102   // output bit type and min/max. It has to be 16bit for the rest of hi2isis
00103   // to run.
00104   // Setting the min/max to the 16 bit min/max keeps all the dns (including
00105   // the 8 bit special pixels from changing their value when they are mapped
00106   // to the 16 bit output.
00107   CubeAttributeOutput &outAtt = ui.GetOutputAttribute("TO");
00108   outAtt.setPixelType(Isis::SignedWord);
00109   outAtt.setMinimum((double)VALID_MIN2);
00110   outAtt.setMaximum((double)VALID_MAX2);
00111   Cube *ocube = p.SetOutputCube(ui.GetFileName("TO"), outAtt);
00112   p.StartProcess();
00113   TranslateHiriseEdrLabels(inFile, ocube);
00114 
00115   // Pull out the lookup table so we can apply it in the second pass
00116   // and remove it from the labels.
00117   // Add the UNLUTTED keyword to the instrument group so we know
00118   // if the lut has been used to convert back to 14 bit data
00119   PvlGroup &instgrp = ocube->group("Instrument");
00120   PvlKeyword lutKey = instgrp["LookupTable"];
00121   PvlSequence lutSeq;
00122   lutSeq = lutKey;
00123 
00124   // Set up the Stretch object with the info from the lookup table
00125   // If the first entry is (0,0) then no lut was applied.
00126   if((lutKey.IsNull()) ||
00127       (lutSeq.Size() == 1 && lutSeq[0][0] == "0" && lutSeq[0][1] == "0")) {
00128     stretch.AddPair(0.0, 0.0);
00129     stretch.AddPair(65536.0, 65536.0);
00130     instgrp.AddKeyword(PvlKeyword("Unlutted", "TRUE"));
00131     instgrp.DeleteKeyword("LookupTable");
00132   }
00133   // The user wants it unlutted
00134   else if(ui.GetBoolean("UNLUT")) {
00135     for(int i = 0; i < lutSeq.Size(); i++) {
00136       stretch.AddPair(i, ((toDouble(lutSeq[i][0]) + toDouble(lutSeq[i][1])) / 2.0));
00137     }
00138     instgrp.AddKeyword(PvlKeyword("Unlutted", "TRUE"));
00139     instgrp.DeleteKeyword("LookupTable");
00140   }
00141   // The user does not want the data unlutted
00142   else {
00143     stretch.AddPair(0.0, 0.0);
00144     stretch.AddPair(65536.0, 65536.0);
00145     instgrp.AddKeyword(PvlKeyword("Unlutted", "FALSE"));
00146   }
00147 
00148   // Save the calibration and ancillary data as BLOBs. Both get run thru the
00149   // lookup table just like the image data.
00150   SaveHiriseCalibrationData(p, ocube, pdsLabel);
00151   SaveHiriseAncillaryData(p, ocube);
00152 
00153   // Save off the input bit type so we know how to process it on the
00154   // second pass below.
00155   Isis::PixelType inType = p.PixelType();
00156 
00157   // All finished with the ImportPds object
00158   p.EndProcess();
00159 
00160 
00161   // Make another pass thru the data using the output file in read/write mode
00162   // This allows us to correct gaps, remap special pixels and accumulate some
00163   // counts
00164   lsbGap = ui.GetBoolean("LSBGAP");
00165   ProcessByLine p2;
00166   QString ioFile = ui.GetFileName("TO");
00167   CubeAttributeInput att;
00168   p2.SetInputCube(ioFile, att, ReadWrite);
00169   p2.Progress()->SetText("Converting special pixels");
00170   section = 4;
00171   p2.StartProcess((inType == Isis::UnsignedByte) ? FixDns8 : FixDns16);
00172   p2.EndProcess();
00173 
00174 
00175   // Log the results of the image conversion
00176   PvlGroup results("Results");
00177   results += PvlKeyword("From", inFile.expanded());
00178 
00179   results += PvlKeyword("CalibrationBufferGaps", toString(gapCount[0]));
00180   results += PvlKeyword("CalibrationBufferLIS", toString(lisCount[0]));
00181   results += PvlKeyword("CalibrationBufferHIS", toString(hisCount[0]));
00182   results += PvlKeyword("CalibrationBufferPossibleGaps", toString(suspectGapCount[0]));
00183   results += PvlKeyword("CalibrationBufferInvalid", toString(invalidCount[0]));
00184   results += PvlKeyword("CalibrationBufferValid", toString(validCount[0]));
00185 
00186   results += PvlKeyword("CalibrationImageGaps", toString(gapCount[1]));
00187   results += PvlKeyword("CalibrationImageLIS", toString(lisCount[1]));
00188   results += PvlKeyword("CalibrationImageHIS", toString(hisCount[1]));
00189   results += PvlKeyword("CalibrationImagePossibleGaps", toString(suspectGapCount[1]));
00190   results += PvlKeyword("CalibrationImageInvalid", toString(invalidCount[1]));
00191   results += PvlKeyword("CalibrationImageValid", toString(validCount[1]));
00192 
00193   results += PvlKeyword("CalibrationDarkGaps", toString(gapCount[2]));
00194   results += PvlKeyword("CalibrationDarkLIS", toString(lisCount[2]));
00195   results += PvlKeyword("CalibrationDarkHIS", toString(hisCount[2]));
00196   results += PvlKeyword("CalibrationDarkPossibleGaps", toString(suspectGapCount[2]));
00197   results += PvlKeyword("CalibrationDarkInvalid", toString(invalidCount[2]));
00198   results += PvlKeyword("CalibrationDarkValid", toString(validCount[2]));
00199 
00200   results += PvlKeyword("ObservationBufferGaps", toString(gapCount[3]));
00201   results += PvlKeyword("ObservationBufferLIS", toString(lisCount[3]));
00202   results += PvlKeyword("ObservationBufferHIS", toString(hisCount[3]));
00203   results += PvlKeyword("ObservationBufferPossibleGaps", toString(suspectGapCount[3]));
00204   results += PvlKeyword("ObservationBufferInvalid", toString(invalidCount[3]));
00205   results += PvlKeyword("ObservationBufferValid", toString(validCount[3]));
00206 
00207   results += PvlKeyword("ObservationImageGaps", toString(gapCount[4]));
00208   results += PvlKeyword("ObservationImageLIS", toString(lisCount[4]));
00209   results += PvlKeyword("ObservationImageHIS", toString(hisCount[4]));
00210   results += PvlKeyword("ObservationImagePossibleGaps", toString(suspectGapCount[4]));
00211   results += PvlKeyword("ObservationImageInvalid", toString(invalidCount[4]));
00212   results += PvlKeyword("ObservationImageValid", toString(validCount[4]));
00213 
00214   results += PvlKeyword("ObservationDarkGaps", toString(gapCount[5]));
00215   results += PvlKeyword("ObservationDarkLIS", toString(lisCount[5]));
00216   results += PvlKeyword("ObservationDarkHIS", toString(hisCount[5]));
00217   results += PvlKeyword("ObservationDarkPossibleGaps", toString(suspectGapCount[5]));
00218   results += PvlKeyword("ObservationDarkInvalid", toString(invalidCount[5]));
00219   results += PvlKeyword("ObservationDarkValid", toString(validCount[5]));
00220 
00221   // Write the results to the log
00222   Application::Log(results);
00223 
00224   return;
00225 }
00226 
00227 
00228 void TranslateHiriseEdrLabels(FileName &labelFile, Cube *ocube) {
00229 
00230   //Create a PVL to store the translated labels
00231   Pvl outLabel;
00232 
00233   // Get the directory where the MRO HiRISE translation tables are.
00234   PvlGroup dataDir(Preference::Preferences().FindGroup("DataDirectory"));
00235   QString transDir = (QString) dataDir["Mro"] + "/translations/";
00236 
00237   // Get a filename for the HiRISE EDR label
00238   Pvl labelPvl(labelFile.expanded());
00239 
00240   // Translate the Instrument group
00241   FileName transFile(transDir + "hiriseInstrument.trn");
00242   PvlTranslationManager instrumentXlater(labelPvl, transFile.expanded());
00243   instrumentXlater.Auto(outLabel);
00244 
00245   // Translate the BandBin group
00246   transFile  = transDir + "hiriseBandBin.trn";
00247   PvlTranslationManager bandBinXlater(labelPvl, transFile.expanded());
00248   bandBinXlater.Auto(outLabel);
00249 
00250   // Translate the Archive group
00251   transFile  = transDir + "hiriseArchive.trn";
00252   PvlTranslationManager archiveXlater(labelPvl, transFile.expanded());
00253   archiveXlater.Auto(outLabel);
00254 
00255   // Create the Instrument group keyword CcdId from the ProductId
00256   // SCS 28-03-06 Do it in the instrument translation table instead of here
00257 //  PvlGroup &archiveGroup(outLabel.FindGroup("Archive", Pvl::Traverse));
00258 //  QString productId = (QString)archiveGroup.FindKeyword("ProductId");
00259 //  productId.Token("_");
00260 //  productId.Token("_");
00261 //  productId = productId.Token("_");
00262 //  outLabel.FindGroup("Instrument", Pvl::Traverse) +=
00263 //      PvlKeyword ("CcdId", productId);
00264 
00265   // Create the Kernel Group
00266   PvlGroup kerns("Kernels");
00267   kerns += PvlKeyword("NaifIkCode", "-74699");
00268 
00269   // Write the Instrument, BandBin, Archive, and Kernels groups to the output
00270   // cube label
00271   ocube->putGroup(outLabel.FindGroup("Instrument", Pvl::Traverse));
00272   ocube->putGroup(outLabel.FindGroup("BandBin", Pvl::Traverse));
00273   ocube->putGroup(outLabel.FindGroup("Archive", Pvl::Traverse));
00274   ocube->putGroup(kerns);
00275 }
00276 
00277 
00278 // The input buffer has a raw 16 bit buffer but the values are still 0 to 255
00279 void FixDns8(Buffer &buf) {
00280 
00281   // Convert all 8bit image values of =255 (xFF) to 16bit NULL, count as gap
00282   // Convert all 8bit image values of =254 (xFE) to 16bit HIS, count as HIS
00283   // Convert all 8bit image values of =0 (x00) to 16bit LIS, count as NULL
00284   // Convert 8bit image data to 16bit by applying the LUT
00285 
00286   short int *raw = (short int *)(buf.RawBuffer());
00287 
00288   for(int i = 0; i < buf.size(); i++) {
00289 
00290     if(raw[i] == (short int)255) {
00291       buf[i] = Isis::NULL8;
00292       gapCount[section]++;
00293     }
00294     else if(raw[i] == (short int)254) {
00295       buf[i] = Isis::HIGH_INSTR_SAT8;
00296       hisCount[section]++;
00297     }
00298     else if(raw[i] == (short int)0) {
00299       buf[i] = Isis::LOW_INSTR_SAT8;
00300       lisCount[section]++;
00301     }
00302     else { // It's valid so just run it thru the lookup table to get a 16 bit dn
00303       buf[i] = stretch.Map(buf[i]);
00304       validCount[section]++;
00305     }
00306   }
00307 }
00308 
00309 
00310 void FixDns16(Buffer &buf) {
00311 
00312   // Convert 16-bit image values of =65535 (xFFFF) to NULL, count as gap
00313   // Convert 16-bit image values of >16383 (x3FFF) to NULL, count as gap
00314   // Convert 16-bit image values of =16383 (x3FFF) to HIS, count as HIS
00315   // Convert 16-bit image values of =0 (x00) to LIS, count as LIS
00316 
00317   short int *raw = (short int *)(buf.RawBuffer());
00318 
00319   for(int i = 0; i < buf.size(); i++) {
00320 
00321     // This pixel is a gap
00322     if(raw[i] == (short int)0xffff) {  // 0xffff = -1 = 65535 = gap
00323       buf[i] = Isis::NULL8;
00324       gapCount[section]++;
00325     }
00326     // The low order byte of this pixel is the beginning of a gap
00327     else if((i + 1 < buf.size()) && // is there at least on more pixel to look at
00328             (raw[i+1] == (short int)0xffff) && // Is the next pixel a gap
00329             ((short int)(raw[i] & 0x00ff) == (short int)0x00ff)) { // Is the low byte 0xff
00330       suspectGapCount[section]++;
00331       if(lsbGap) {
00332         buf[i] = Isis::NULL8;
00333       }
00334     }
00335     // This pixel is not within the legal 14 bit range (0) to (16383=0x3fff)
00336     // It might be the end of a gap (0xff??) but it's still illegal
00337     else if((raw[i] > 16383) || (raw[i] < 0)) {
00338       buf[i] = Isis::NULL8;
00339       invalidCount[section]++;
00340     }
00341     // This pixel is saturated on the bright end
00342     else if(raw[i] == 16383) {  // Max value for instrument
00343       buf[i] = Isis::HIGH_INSTR_SAT8;
00344       hisCount[section]++;
00345     }
00346     // This pixel is saturated on the dark end
00347     // Shouldn't happen because dark currents are above zero (0)
00348     else if(raw[i] == 0) {
00349       buf[i] = Isis::LOW_INSTR_SAT8;
00350       lisCount[section]++;
00351     }
00352     // Pixel value is ok, so just leave it alone
00353     else {
00354       validCount[section]++;
00355     }
00356   }
00357 }
00358