USGS

Isis 3.0 Application Source Code Reference

Home

apollo2isis.cpp

Go to the documentation of this file.
00001 #include "Isis.h"
00002 #include "Chip.h"
00003 #include "UserInterface.h"
00004 #include "FileName.h"
00005 #include "Pvl.h"
00006 #include "IString.h"
00007 #include "IException.h"
00008 #include "iTime.h"
00009 #include "Apollo.h"
00010 #include "PvlTranslationTable.h"
00011 #include "Statistics.h"
00012 #include "ProcessImportPds.h"
00013 
00014 #include <cstdio>
00015 
00016 using namespace std;
00017 using namespace Isis;
00018 
00019 bool FindCode();
00020 void CalculateTransform();
00021 void RefineCodeLocation();
00022 void TranslateCode();
00023 void TranslateApolloLabels (IString filename, Cube *pack);
00024 bool IsValidCode();
00025 QString FrameTime();
00026 int Altitude();
00027 double ShutterInterval();
00028 QString FMC();
00029 
00030 int codeSample, codeLine;
00031 bool code[4][32];
00032 bool codeFound = true;
00033 
00034 Cube cube;
00035 Apollo *apollo;
00036 QString utcTime;
00037 
00038 int RADIUS = 46;
00039 double rotation, sampleTranslation, lineTranslation;
00040 
00041 // Main program
00042 void IsisMain() {
00043   ProcessImportPds p;
00044   Pvl pdsLabel;
00045   UserInterface &ui = Application::GetUserInterface();
00046   FileName inFile = ui.GetFileName("FROM");
00047 
00048   p.SetPdsFile(inFile.expanded(), "", pdsLabel);
00049 
00050   QString filename = FileName(ui.GetFileName("FROM")).baseName();
00051   FileName toFile = ui.GetFileName("TO");
00052   
00053   apollo = new Apollo(filename);
00054 
00055   utcTime = (QString)pdsLabel["START_TIME"];  
00056   
00057   // Setup the output cube attributes for a 16-bit unsigned tiff
00058   Isis::CubeAttributeOutput cao;
00059   cao.setPixelType(Isis::Real);
00060   p.SetOutputCube(toFile.expanded(), cao);
00061 
00062   // Import image
00063   p.StartProcess();
00064   p.EndProcess();
00065 
00066   cube.open(toFile.expanded(), "rw");
00067   
00068   // Once the image is imported, we need to find and decrypt the code
00069   if (apollo->IsMetric() && FindCode())
00070     TranslateCode();
00071     
00072   CalculateTransform();
00073   // Once we have decrypted the code, we need to populate the image labels
00074   TranslateApolloLabels(filename, &cube);
00075   cube.close();
00076 }
00077 
00078 // Find the location of the code
00079 bool FindCode() {
00080   // start by looking for a high value pixel
00081   int CENTER_SAMPLE = 1030,
00082        CENTER_LINE = 21350,
00083        DELTAX = 1000,
00084        DELTAY = 250;
00085   Chip chip(2*DELTAX+2*RADIUS, 2*DELTAY+4*RADIUS);
00086   chip.TackCube(CENTER_SAMPLE+RADIUS, CENTER_LINE+2*RADIUS);
00087   chip.Load(cube);
00088   for (int i=1; i<chip.Samples()-6*RADIUS-1; i+=RADIUS/8) {
00089     for (int j=1; j<=chip.Lines()-4*RADIUS-1; j+=RADIUS/8) {
00090       if ( chip.GetValue(i,j) > 60000 && chip.GetValue(i+2*RADIUS, j) > 60000 &&
00091                   chip.GetValue(i+2*RADIUS, j+2*RADIUS) < 60000 && 
00092                   chip.GetValue(i+2*RADIUS, j+4*RADIUS) > 60000)  {
00093         // Now that we've found one, let's refine the location
00094         codeFound = true;
00095         codeSample = CENTER_SAMPLE - DELTAX + i;
00096         codeLine = CENTER_LINE - DELTAY + j;
00097         RefineCodeLocation();
00098         return true;
00099       }
00100     }
00101   }
00102   
00103   // If the code was not found, we will use the default location
00104   codeFound = false;
00105   codeSample = CENTER_SAMPLE;
00106   codeLine = CENTER_LINE;
00107   return false;
00108 }
00109 
00110 // Calculate the translation and rotation of the scan
00111 void CalculateTransform() {
00112   if (!apollo->IsMetric() || !codeFound) {
00113     sampleTranslation = 0.0;
00114     lineTranslation = 0.0;
00115     rotation = 0.0;
00116     return;
00117   }
00118   double sampleUL, lineUL,
00119       sampleUR, lineUR,
00120       sampleLL, lineLL,
00121       sampleLR, lineLR;
00122       
00123   RefineCodeLocation();
00124   sampleUL = codeSample;
00125   lineUL = codeLine;
00126   codeSample += 6*RADIUS;
00127   RefineCodeLocation();
00128   sampleUR = codeSample;
00129   lineUR = codeLine;
00130   codeLine += 62*RADIUS;
00131   RefineCodeLocation();
00132   sampleLR = codeSample;
00133   lineLR = codeLine;
00134   codeSample -= 6*RADIUS;
00135   RefineCodeLocation();
00136   sampleLL = codeSample;
00137   lineLL = codeLine;
00138   
00139   if (code[0][0] == 1 && code[0][31] ==1 && code[3][0] == 1 && code[3][31] == 1) {
00140   rotation = -1*atan((sampleLR-sampleUR+sampleLL-sampleUL)/(lineLR-lineUR+lineLL-lineUL)) - 0.00281891751001 - 0.000648055741779;
00141   sampleTranslation = (sampleUL+sampleUR+sampleLL+sampleLR)/4;
00142   lineTranslation = (lineUL+lineUR+lineLL+lineLR)/4;
00143   }
00144   else if (code[0][0] == 1 && code[0][31] == 1) {
00145           rotation = -1*atan((sampleLL-sampleUL)/(lineLL-lineUL)) - 0.00281891751001 - 0.000648055741779;
00146           sampleTranslation = (sampleUL + sampleLL)/2 + 3*RADIUS;
00147           lineTranslation = (lineUL + lineLL)/2;
00148   }
00149   else {
00150           rotation = -0.00281891751001 - 0.000648055741779;
00151           sampleTranslation = 600;
00152           lineTranslation = 22700;
00153   }
00154   
00155   if (apollo->IsApollo17())
00156           rotation += 0.0111002410269388;
00157 }
00158 
00159 void RefineCodeLocation() {
00160   Chip chip(2*RADIUS, 2*RADIUS);
00161   chip.TackCube(codeSample, codeLine);
00162   chip.Load(cube);
00163   int bestSample = 0,
00164       bestLine = 0;
00165   double max = 0.0;
00166   for (int s = RADIUS/2+1; s < 3*RADIUS/2; s++) {
00167     for (int l = RADIUS/2+1; l < 3*RADIUS/2; l++) {
00168       double value = 0.0;
00169       // Run a quick gaussian-esch filter
00170       for (int x=RADIUS/-2; x<=RADIUS/2; x++) {
00171         for (int y=RADIUS/-2; y<=RADIUS/2; y++) {
00172           //value += chip(s+x,l+y)/Exp(x*x + y*y);
00173           if (sqrt(x*x + y*y) < RADIUS/2)
00174             value += chip.GetValue(s+x,l+y);
00175         }
00176       }
00177       if (value > max) {
00178         bestSample = s;
00179         bestLine = l;
00180         max = value;
00181       }
00182     }
00183   }
00184 
00185   codeSample = codeSample - (chip.Samples()+1)/2 + bestSample;
00186   codeLine = codeLine - (chip.Lines()+1)/2 + bestLine;
00187 }
00188 
00189 // translate the code once it is found
00190 void TranslateCode() {
00191   // read the code from the image
00192   Chip chip(8*RADIUS, 64*RADIUS);
00193   chip.TackCube(codeSample+3*RADIUS, codeLine+31*RADIUS);
00194   chip.Load(cube);
00195   for (int j=0; j<32; j++) {
00196     for (int i=0; i<4; i++) {
00197       Statistics stats;
00198       // Get the average of the subchip
00199       for (int x=1; x<=2*RADIUS; x++) {
00200         for (int y=1; y<=2*RADIUS; y++) {
00201           stats.AddData(chip.GetValue(i*2*RADIUS + x,j*2*RADIUS + y));
00202         }
00203       }
00204       // see if it is on or off
00205       if (stats.Average() > 20000)
00206         code[i][31-j] = true;
00207       else code[i][31-j] = false;
00208     }
00209   }
00210   
00211   for (int j=0; j<32; j++) {
00212     for (int i=0; i<4; i++) {
00213     }
00214   }
00215 }
00216 
00217 // Populate cube label using filname and film code
00218 // Code decrypted as specified in film decoder document (July 23, 1971 Revision)
00219 //     available at ASU Apollo Resources archive
00220 void TranslateApolloLabels (IString filename, Cube *opack) {
00221   //Instrument group
00222   PvlGroup inst("Instrument");
00223   PvlGroup kern("Kernels");
00224   PvlGroup codeGroup("Code");
00225   
00226   inst += PvlKeyword("SpacecraftName", apollo->SpacecraftName());
00227   inst += PvlKeyword("InstrumentId", apollo->InstrumentId());
00228   inst += PvlKeyword("TargetName", apollo->TargetName());
00229   
00230   if ( !IsValidCode() ){
00231     PvlGroup error("ERROR");
00232     error.AddComment("The decrypted code is invalid.");
00233     for (int i=0; i<4; i++) {
00234       PvlKeyword keyword("Column"+toString(i+1));
00235       for (int j=0; j<32; j++) {
00236         keyword += toString((int)code[i][j]);
00237       }
00238       error.AddKeyword(keyword);
00239       codeGroup += keyword;
00240     }
00241     Application::Log(error);
00242   }
00243   else {
00244     codeGroup += PvlKeyword("StartTime", FrameTime());
00245     codeGroup += PvlKeyword("SpacecraftAltitude", toString(Altitude()),"meters");
00246   
00247     if (apollo->IsMetric()){
00248       codeGroup += PvlKeyword("ExposureDuration", toString(ShutterInterval()), "milliseconds");
00249       codeGroup += PvlKeyword("ForwardMotionCompensation", FMC());
00250     }
00251     
00252     for (int i=0; i<4; i++) {
00253       PvlKeyword keyword("Column"+toString(i+1));
00254       for (int j=0; j<32; j++) {
00255         keyword += toString((int)code[i][j]);
00256       }
00257       codeGroup += keyword;
00258     }
00259   }
00260     
00261   PvlGroup bandBin("BandBin");
00262   // There are no filters on the camera, so the default is clear with id # of 1
00263   // the BandBin group is only included to work with the spiceinit application
00264   bandBin += PvlKeyword("FilterName", "CLEAR");
00265   bandBin += PvlKeyword("FilterId", "1");
00266   
00267   kern += PvlKeyword("NaifFrameCode", apollo->NaifFrameCode());
00268 
00269   // Set up the nominal reseaus group
00270   Isis::PvlGroup &dataDir = Isis::Preference::Preferences().FindGroup("DataDirectory");
00271   Process p;
00272   PvlTranslationTable tTable(
00273       (QString)p.MissionData("base", "translations/MissionName2DataDir.trn"));
00274   QString missionDir = dataDir[tTable.Translate("MissionName", apollo->SpacecraftName())][0];
00275   Pvl resTemplate(missionDir + "/reseaus/" + apollo->InstrumentId() + "_NOMINAL.pvl");
00276   PvlGroup *reseaus = &resTemplate.FindGroup("Reseaus");
00277   
00278   // Update reseau locations based on refined code location
00279   for (int i=0; i<(reseaus->FindKeyword("Type")).Size(); i++) {
00280     double x = toDouble(reseaus->FindKeyword("Sample")[i]) + sampleTranslation + 2278,
00281            y = toDouble(reseaus->FindKeyword("Line")[i]) + lineTranslation - 20231;
00282     
00283     if (apollo->IsApollo17()) {
00284         x += 50;
00285         y += 20;
00286     }
00287     
00288     reseaus->FindKeyword("Sample")[i] = toString(
00289         cos(rotation)*(x-sampleTranslation) - sin(rotation)*(y-lineTranslation) + sampleTranslation);
00290     reseaus->FindKeyword("Line")[i] = toString(
00291         sin(rotation)*(x-sampleTranslation) + cos(rotation)*(y-lineTranslation) + lineTranslation);
00292   }
00293   inst += PvlKeyword("StartTime", utcTime);
00294     
00295   opack->putGroup(inst);
00296   opack->putGroup(bandBin);
00297   opack->putGroup(kern);
00298   opack->putGroup(*reseaus);
00299   opack->putGroup(codeGroup);
00300 }
00301 
00302 // Validates the code based on February 1971 Revision
00303 bool IsValidCode() {
00304   return codeFound && ( code[0][0] || !code[0][3] || !code[0][5] || code[0][10] ||  !code[0][11] || !code[0][12] || code[0][15] || !code[0][16] || code[0][21] || !code[0][22] || !code[0][26] || code[0][31] ||
00305                          code[1][0] || !code[1][6] || !code[1][11] || code[1][12] || !code[1][13] || !code[1][14] || code[1][15] || !code[1][28] || code[1][29] || !code[1][30] || code[1][31] ||
00306                          code[2][0] || code[2][15] || !code[2][21] || code[2][22] || !code[2][23] || !code[2][24] || !code[2][25] || !code[2][26] || !code[2][27] || !code[2][28] || !code[2][29] || !code[2][30] || code[2][31] )
00307                    && (!(apollo->IsMetric()) || (code[3][0] || !code[3][13] || !code[3][14] || code[3][15] || !code[3][16] || !code[3][17] || !code[3][18] || !code[3][19] || !code[3][20] || !code[3][21] || 
00308                                                    !code[3][22] || !code[3][23] || !code[3][24] || !code[3][25] || !code[3][26] || !code[3][27] || !code[3][28] || !code[3][30] || code[3][31]));
00309 }
00310 
00311 QString FrameTime() {
00312   iTime launch = apollo->LaunchDate();
00313     int year = launch.Year(),
00314         month = launch.Month(),
00315         days = launch.Day(),
00316         hours = launch.Hour(),
00317         minutes = launch.Minute();
00318     double seconds = launch.Second();
00319     for (int i=0; i<5; i++) {
00320       if (i<4) days += (int)pow(2.0, i)*code[0][9-i];
00321       else days += 10*(int)pow(2.0, i-4)*code[0][8-i];
00322     }
00323     
00324     for (int i=0; i<6; i++) {
00325       if (i<4) hours += (int)pow(2.0, i)*code[0][20-i];
00326       else hours += 10*(int)pow(2.0, i-4)*code[0][18-i];
00327     }
00328     
00329     for (int i=0; i<7; i++) {
00330       if (i<4) minutes += (int)pow(2.0, i)*code[0][30-i];
00331       else minutes += 10*(int)pow(2.0, i-4)*code[0][29-i];
00332     }
00333     
00334     for (int i=0; i<7; i++) {
00335       if (i<4) seconds += (int)pow(2.0, i)*code[1][10-i];
00336       else seconds += 10*(int)pow(2.0, i-4)*code[1][9-i];
00337     }
00338     
00339     // And the milliseconds
00340     for (int i=0; i<12; i++) {
00341       if (i<4) seconds += 0.001* pow(2.0, i)*code[1][27-i];
00342       else if (i<8) seconds += 0.01*pow(2.0, i-4)*code[1][27-i];
00343       else seconds += 0.1*pow(2.0, i-8)*code[1][27-i];
00344     }
00345     
00346     // Perform checks to make sure the time is correct
00347     //   (i.e. convert 60 seconds to a minute, etc.)
00348     if (seconds > 60) {
00349       seconds -= 60;
00350       minutes += 1;
00351     }
00352     if (minutes >= 60) {
00353       minutes -= 60;
00354       hours += 1;
00355     }
00356     if ( hours >= 24) {
00357       hours -= 24;
00358       days +=1;
00359     }
00360     // This last check will only affect Apollo 15 which launched in July (31 days) and landed in August
00361     // Both Apollo 16 and Apollo 17 launched and landed in the same month
00362     if (days > 31){ 
00363       days -= 31;
00364       month += 1;
00365     }
00366   
00367     QString sTime = toString(year) + "-";
00368     if (month < 10) sTime += "0";
00369     sTime += toString(month)+ "-";
00370     if (days <10) sTime += "0";
00371     sTime += toString(days) + "T";
00372     if (hours <10) sTime += "0";
00373     sTime += toString(hours) + ":";
00374     if (minutes <10) sTime += "0";
00375     sTime += toString(minutes) + ":";
00376     if (seconds <10) sTime += "0";
00377     sTime += toString(seconds);
00378     
00379     return sTime;
00380 }
00381 
00382 int Altitude() {
00383   int altitude = 0;
00384   for (int i=0; i<18; i++) {
00385     if (i<5) altitude += (int)pow(2.0, i)*code[2][20-i];
00386     else altitude += (int)pow(2.0, i)*code[2][19-i];
00387   }
00388   return altitude;
00389 }
00390 
00391 double ShutterInterval() {
00392   int shutterInterval = 0;
00393   for (int i=0; i<10; i++) {
00394     shutterInterval += (int)pow(2.0, i)*code[3][12-i];
00395   }
00396   return 0.1*shutterInterval;
00397 }
00398 
00399 QString FMC() {
00400   if (code[3][29]) return "True";
00401   return "False";
00402 }