def getImageBoundingBox(filePath): """Returns (minLon, maxLon, minLat, maxLat) for a georeferenced image file""" extension = os.path.splitext(filePath)[1] if '.cub' in extension: return IrgIsisFunctions.getIsisBoundingBox(filePath) else: # Handle all other types return getGeoTiffBoundingBox(filePath)
def main(): val = IrgIsisFunctions.getCubeCenterLatitude('/u/smcmich1/data/lronacProduction/NAC_DTM_M115108088_M115114873/workDir/M115114873LE.correctedMosaic.cub') print val return 0 try: try: usage = "usage: makePcAlignPlots.py [--help][--manual]\n " parser = optparse.OptionParser(usage=usage) parser.add_option("-i", "--input", dest="inputPath", help="Path to the input file.") parser.add_option("-o", "--output", dest="outputPath", help="Where to write the output file.") parser.add_option("-s", "--skip", dest="skip", help="Only plot every N points.") parser.add_option("--manual", action="callback", callback=man, help="Read the manual.") (options, args) = parser.parse_args() if not options.inputPath: parser.error("Need input file!") if not options.outputPath: parser.error("Need output file!") if not options.skip: options.skip = 1 except optparse.OptionError, msg: raise Usage(msg) print "Beginning processing....." #filePath = '/home/smcmich1/data/stereoCorrectionTest/M120168714LE.corrected.cub_stereoCalibrationTemp2/pcAlignOutput-beg_errors.csv' #outputPath = '/home/smcmich1/data/stereoCorrectionTest/begErrors.png' fileContents = readErrorFile(options.inputPath) plotError(fileContents, options.outputPath, int(options.skip)) print "Finished" return 0
def main(argsIn): print "Started lronacCameraRotationCorrector.py" try: try: usage = "usage: lronacCameraRotationCorrector.py [--output <path>][--manual]\n " parser = optparse.OptionParser(usage=usage) parser.add_option("--left", dest="leftPath", help="Path to LE .cub file") parser.add_option("--right", dest="rightPath", help="Path to RE .cub file") parser.add_option("--rotation", dest="rotationPath", help="Path to already computed new rotation") parser.add_option("-g", "--gdcLogPath", dest="gdcLogPath", help="Optional path to save computed GDC points to") parser.add_option("-s", "--spk", dest="spkPath", help="Path to optional specified SPK (position) file to use.") parser.add_option("-c", "--ck", dest="ckPath", help="Path to optional specified CK (orientation) file to use.") parser.add_option("--workDir", dest="workDir", help="Folder to store temporary files in") parser.add_option("-o", "--output", dest="outputPath", help="Where to write the output (RE) file.") parser.add_option("--manual", action="callback", callback=man, help="Read the manual.") parser.add_option("--keep", action="store_true", dest="keep", help="Do not delete the temporary files.") (options, args) = parser.parse_args(argsIn) if not options.leftPath: parser.error("Need left input path") if not options.rightPath: parser.error("Need right input path") if not options.outputPath: parser.error("Need output path") except optparse.OptionError, msg: raise Usage(msg) print "Beginning processing....." startTime = time.time() outputFolder = os.path.dirname(options.outputPath) inputBaseName = os.path.basename(options.leftPath) tempFolder = outputFolder + '/' + inputBaseName + '_rotCorrectTemp/' if options.workDir: tempFolder = options.workDir if not os.path.exists(tempFolder): os.mkdir(tempFolder) # File must already have had spiceinit called # Copy the input file to the output location (only the RE image is modified cmd = "cp " + options.rightPath + " " + options.outputPath #print cmd os.system(cmd) # Call head -120 on file cmd = ['head', '-120', options.outputPath] p = subprocess.Popen(cmd, stdout=subprocess.PIPE) headText, err = p.communicate() # Parse output looking for the IK frame file print 'Looking for source frame file...' kernels = IrgIsisFunctions.parseHeadOutput(headText, options.outputPath) if not ('Frame' in kernels): os.remove(options.outputPath) raise Exception('Error! Unable to find frame file!') inputFramePath = kernels['Frame'][0] if not os.path.exists(inputFramePath): os.remove(options.outputPath) raise Exception('Unable to find any IK kernel file in ' + tempTextPath) if not options.rotationPath: # Make sure the output path does not already exist rotationAnglePath = os.path.join(tempFolder, "solvedRotationAngles.txt") if os.path.exists(rotationAnglePath): os.remove(rotationAnglePath) # Call lronacSpkParser to generate modified text file gdcText = '' if options.gdcLogPath: # Handle GDC point logging option gdcText = ' --gdcPointsOutPath ' + options.gdcLogPath cmd = 'lronacAngleSolver --outputPath '+ \ rotationAnglePath + gdcText + ' ' + options.leftPath + ' ' + options.rightPath print cmd os.system(cmd) if not os.path.exists(rotationAnglePath): os.remove(options.outputPath) raise Exception('Failed to solve for rotation angles!') else: # New rotation provided as a command line argument, skip computation rotationAnglePath = options.rotationPath # Read the rotation angles newRotation = readRotationFile(rotationAnglePath) # Generate a modified frame file tempIkPath = os.path.join(tempFolder, "angleCorrectedIkFile.tf") modifyFrameFile(inputFramePath, tempIkPath, newRotation) # Re-run spiceinit (on the copied RE file) using the new frame file cmd = ['spiceinit', 'attach=', 'true', 'from=', options.outputPath, 'fk=', tempIkPath] if (options.spkPath): # Add forced SPK path if needed cmd.append('spk=') cmd.append(options.spkPath) if (options.ckPath): # Add forced CK path if needed cmd.append('ck=') cmd.append(options.ckPath) #print cmd p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) outputText, err = p.communicate() if (outputText.find('ERROR') >= 0): print cmd print outputText raise Exception('Found error when calling spiceinit!') # Clean up temporary files if not options.keep: os.remove(rotationAnglePath) os.remove(tempIkPath) os.remove(options.spkPath) endTime = time.time() print "Finished in " + str(endTime - startTime) + " seconds." return 0
def getImageSize(imagePath): return IrgIsisFunctions.getImageSize(imagePath)
def fetchAndPrepFile(db, setName, subtype, remoteURL, workDir): '''Retrieves a remote file and prepares it for upload''' #print 'Uploading file ' + setName # Images with a center over this latitude will use polar stereographic projection # instead of simple cylindrical projection. HIGH_LATITUDE_CUTOFF = 65 # Degrees asuImagePath = os.path.join(workDir, setName + '_noGeo.jp2') # Map projected image from ASU asuLabelPath = os.path.join(workDir, setName + '_noGeo.lbl') # Label from ASU edrPath = os.path.join(workDir, setName + '.IMG') # Raw image from PDS timePath = os.path.join(workDir, setName + '.time') # Contains only the file capture time string #cubPath = os.path.join(workDir, setName + '.cub') # Output of mroctx2isis #calPath = os.path.join(workDir, setName + '.cal.cub') # Output of ctxcal mapPath = os.path.join(workDir, setName + '.map.cub') # Output of cam2map mapLabelPath = os.path.join(workDir, setName + '.map.pvl') # Specify projection to cam2map # Generate the remote URLs from the data prefix and volume stored in these parameters asuImageUrl, asuLabelUrl, edrUrl = generatePdsPath(setName, subtype) if True: # Map project the EDR ourselves <-- This takes way too long! print 'Projecting the EDR image using ISIS...' localFilePath = os.path.join(workDir, setName + '.tif') # The output file we will upload # Check if this is a "flat" calibration image badImage = checkForBadFile(edrUrl) if badImage: raise Exception('TODO: Remove bad images from the DB!') if not os.path.exists(edrPath): # Download the EDR file cmd = 'wget ' + edrUrl + ' -O ' + edrPath print cmd os.system(cmd) # Extract the image capture time from the .IMG file if not os.path.exists(timePath): timeString = getCreationTimeHelper(edrPath) f = open(timePath, 'w') f.write(timeString) f.close() # Convert and apply calibration to the CTX file calPath = IrgIsisFunctions.prepareCtxImage(edrPath, workDir, False) ## Find out the center latitude of the file and determine if it is high latitude centerLat = IrgIsisFunctions.getCubeCenterLatitude(calPath, workDir) print centerLat highLat = abs(float(centerLat)) > HIGH_LATITUDE_CUTOFF if True:#not os.path.exists(mapLabelPath): # Generate the map label file generateDefaultMappingPvl(mapLabelPath, highLat) if True:#not os.path.exists(mapPath): # Generate the map projected file cmd = ['timeout', '6h', 'cam2map', 'matchmap=','False', 'from=', calPath, 'to=', mapPath, 'map=', mapLabelPath] print cmd #os.system(cmd) p = subprocess.Popen(cmd) p.communicate() if (p.returncode != 0): raise Exception('Error or timeout running cam2map, returnCode = ' + str(p.returncode)) if True: #not os.path.exists(localFilePath): # Generate the final image to upload cmd = 'gdal_translate -of GTiff ' + mapPath + ' ' + localFilePath print cmd os.system(cmd) # Clean up intermediate files os.remove(mapLabelPath) os.remove(edrPath) os.remove(calPath) os.remove(mapPath) # Two local files are left around, the first should be uploaded. return [localFilePath, timePath] else: # Use the map projected image from the ASU web site print 'Using ASU projected image...' localFilePath = os.path.join(workDir, setName + '.jp2') # The output file we will upload # Note: ASU seems to be missing some files! # We are using the label path in both projection cases if not os.path.exists(asuLabelPath): # Download the label file cmd = 'wget "' + asuLabelUrl + '" -O ' + asuLabelPath print cmd os.system(cmd) if not IrgFileFunctions.fileIsNonZero(asuLabelPath): # Try the alternate label path os.remove(asuLabelPath) asuLabelUrl = asuLabelUrl.replace( '.scyl.', '.ps.') asuLabelPath = asuLabelPath.replace('.scyl.', '.ps.') print 'Trying alternate label path: ' + asuLabelUrl # Download the label file cmd = 'wget "' + asuLabelUrl + '" -O ' + asuLabelPath print cmd os.system(cmd) if not IrgFileFunctions.fileIsNonZero(asuLabelPath): raise Exception('Failed to download file label at URL: ' + asuLabelUrl) # Check the projection type projType = IrgGeoFunctions.getProjectionFromIsisLabel(asuLabelPath) if projType != 'SimpleCylindrical': print 'WARNING: projType = ' + projType print 'Maps Engine may fail to ingest this file!' #os.remove(asuLabelPath) #raise Exception(projType + ' images on hold until Google fixes a bug!') if not os.path.exists(asuImagePath): # Download the image file cmd = 'wget "' + asuImageUrl + '" -O ' + asuImagePath print cmd os.system(cmd) if not IrgFileFunctions.fileIsNonZero(asuImagePath): raise Exception('Failed to download image file at URL: ' + asuImageUrl) ## Correct the ISIS header if needed #fixedAsuHeaderPath = putIsisHeaderIn180(asuLabelPath) #if (fixedAsuHeaderPath != asuLabelPath): # os.remove(asuLabelPath) # Delete replaced header if True: # This is fast now, so do it every time # Correct the file - The JP2 file from ASU needs the geo data from the label file! #cmd = 'addGeoToAsuCtxJp2.py --keep --label '+ asuLabelPath +' '+ asuImagePath +' '+ localFilePath #print cmd #os.system(cmd) # TODO: Remove unnecessary image copy here (correctedPath, sidecarPath) = addGeoDataToAsuJp2File(asuImagePath, asuLabelPath, localFilePath, keep=False) if not IrgFileFunctions.fileIsNonZero(sidecarPath): raise Exception('Script to add geo data to JP2 file failed!') # Clean up os.remove(asuImagePath) # Three local files are left around, the first should be uploaded. return [correctedPath, sidecarPath, asuLabelPath]
#generateKmlFromGdcPoints(os.path.join(doubleCalWorkFolder, 'initialGdcCheck'), tempFolder, 'dem-trans_source.csv', 'transformedPoints' 1000, 'blue', 'normal', , False) generateKmlFromGdcPoints(os.path.join(doubleCalWorkFolder, 'pcAlignOutput'), tempFolder, 'dem-trans_reference.csv', 'transformedGdcPoints', 160, 'red', 'tiny', carry) generateKmlFromGdcPoints(os.path.join(doubleCalWorkFolder, 'pcAlignOutput'), tempFolder, 'dem-beg_errors.csv', 'beg-errors', 2, 'yellow', 'tiny', carry) generateKmlFromGdcPoints(os.path.join(doubleCalWorkFolder, 'pcAlignOutput'), tempFolder, 'dem-end_errors.csv', 'end-errors', 2, 'green', 'tiny', carry) print 'Finished generating KML plots' # Delay check for left path to allow debug KML files to be generated if caughtException or not os.path.exists(leftCorrectedPath) or not os.path.exists(rightStereoCorrectedPath): raise Exception('Failed to run stereo calibration process - ' + exceptionText) print '\n-------------------------------------------------------------------------\n' # Generate a PVL file that we need for noproj pvlPath = os.path.join(tempFolder, 'noprojInstruments.pvl') imageSize = IrgIsisFunctions.getImageSize(leftCorrectedPath) isHalfRes = imageSize[0] < 5000 if not os.path.exists(pvlPath): print 'Writing PVL' IsisTools.writeLronacPvlFile(pvlPath, isHalfRes) correctTime = time.time() logging.info('Nav correction finished in %f seconds', correctTime - startTime) # Noproj the corrected data leftNoprojPath = os.path.join(tempFolder, 'leftFinalCorrected.noproj.cub') rightNoprojPath = os.path.join(tempFolder, 'rightFinalCorrected.noproj.cub') leftStereoNoprojPath = os.path.join(tempFolder, 'leftStereoFinalCorrected.noproj.cub') rightStereoNoprojPath = os.path.join(tempFolder, 'rightStereoFinalCorrected.noproj.cub') # Set up thread objects
except optparse.OptionError, msg: raise Usage(msg) startTime = time.time() # Determine if this is a main copy or a spawned copy spawnedCopy = ( (options.pixelStartX is not None) and (options.pixelStartY is not None) and (options.pixelStopX is not None) and (options.pixelStopY is not None) and options.workDir ) if spawnedCopy: # This copy was spawned to process a single tile return writeSingleTile(options) # Just call a function to handle this and then we are done! # If the input image is NOT an ISIS image AND we are running on a single machine we can # just use the multi-threading capability of the ordinary mapproject call. if (not IrgIsisFunctions.isIsisFile(options.imagePath)) and (not options.nodesListPath): cmd = ['mapproject', options.imagePath, options.demPath, options.outputPath] cmd = cmd + options.extraArgs subprocess.call(cmd) return 0 # Otherwise this is the original called process and there are multiple steps to go through # Call mapproject on the input data using subprocess and record output cmd = ['mapproject', '--query-projection', options.demPath, options.imagePath, options.outputPath] cmd = cmd + options.extraArgs # Append other options p = subprocess.Popen(cmd, stdout=subprocess.PIPE) projectionInfo, err = p.communicate() if not options.suppressOutput: print projectionInfo
def fetchAndPrepFile(db, setName, subtype, remoteURL, workDir): '''Retrieves a remote file and prepares it for upload''' #print 'Uploading file ' + setName if subtype != 'DEM': # Handles RED and COLOR images # The label file URL is the same as the image but with a different extension remoteLabelURL = getLabelPathFromImagePath(remoteURL) localFilePath = os.path.join(workDir, os.path.basename(remoteURL)) localLabelPath = os.path.join(workDir, os.path.basename(remoteLabelURL)) # Retrieve the header file if not os.path.exists(localLabelPath): # Try to get the label locally! pdsStart = remoteLabelURL.find('PDS') localPdsPath = os.path.join('/HiRISE/Data/', remoteLabelURL[pdsStart:]) print localPdsPath if os.path.exists( localPdsPath): # File available locally, just copy it! cmd = 'cp ' + localPdsPath + ' ' + localLabelPath else: # Download the image cmd = 'wget ' + remoteLabelURL + ' -O ' + localLabelPath print cmd os.system(cmd) # Retrieve the image file if not os.path.exists(localFilePath): # Need to get it from somewhere # Try to get the image locally! pdsStart = remoteURL.find('PDS') localPdsPath = os.path.join('/HiRISE/Data/', remoteURL[pdsStart:]) if os.path.exists( localPdsPath): # File available locally, just copy it! cmd = 'cp ' + localPdsPath + ' ' + localFilePath else: # Download the image cmd = 'wget ' + remoteURL + ' -O ' + localFilePath print cmd os.system(cmd) if not IrgFileFunctions.fileIsNonZero(localFilePath): if not IrgFileFunctions.fileIsNonZero(localLabelPath): print 'Could not find label or image file, DELETING DATA RECORD!' common.removeDataRecord(db, common.SENSOR_TYPE_HiRISE, subtype, setName) raise Exception('Unable to download from URL: ' + remoteURL) # Check if there is geo data in the JP2 file jp2HasGeoData = IrgGeoFunctions.doesImageHaveGeoData(localFilePath) # If there is no label file, try to generate an artificial one. fakeLabelFile = False if not IrgFileFunctions.fileIsNonZero(localLabelPath): #raise Exception('Unable to download from URL: ' + remoteLabelURL) print 'WARNING: Unable to download from URL: ' + remoteLabelURL if not jp2HasGeoData: raise Exception( 'No geo data in JP2 and no Label file! Cannot handle this!' ) print 'Generating a fake LBL file to proceed...' localLabelPath = writeFakeLabelFromJp2(localFilePath) fakeLabelFile = True # At this point we always have a label file but it may be fake # Some images are missing geo information but we can add it from the label file localImageIsTiff = False localImagePath = localFilePath if not jp2HasGeoData: print 'Correcting JP2 file with no geo information!!!!' # Correct the local file, then remove the old (bad) file outputPrefix = localFilePath[0:-4] localImagePath = correctAndCropImage(localFilePath, localLabelPath, outputPrefix) print 'Generated ' + localImagePath if localFilePath != localImagePath: print 'Deleting JP2 file without metadata!' os.remove(localFilePath) localImageIsTiff = (localImagePath[-4:] == ".TIF") if not localImageIsTiff: # Call code to fix the header information in the JP2 file! cmd = FIX_JP2_TOOL + ' ' + localImagePath print cmd os.system(cmd) # Check the projection type projType = IrgGeoFunctions.getProjectionFromIsisLabel(localLabelPath) (width, height) = IrgIsisFunctions.getImageSize(localImagePath) if (projType == 'POLAR STEREOGRAPHIC' ) and False: #(width < MAX_POLAR_UPLOAD_WIDTH): # Google has trouble digesting these files so handle them differently. #os.remove(localLabelPath) #raise Exception('POLAR STEREOGRAPHIC images on hold until Google fixes a bug!') print 'Special handling for POLAR STEROGRAPHIC image!' if fakeLabelFile: print 'Cannot reprocess polar image without a label file!' print 'All we can do is upload the file and hope for the best.' # First file is for upload, second contains the timestamp. return [localImagePath, localLabelPath] # Compute how many chunks are needed for this image numChunks = ceil(width / POLAR_WIDTH_CHUNK_SIZE) # Determine which chunk this DB entry is for chunkNum = getChunkNum(setName) print 'This is chunk number ' + str(chunkNum) if chunkNum >= numChunks: # Check for chunk number error raise Exception('Illegal chunk number: ' + setName) # If this is the main DB entry, we need to make sure the other DB entries exist! if chunkNum == 0: # Go ahead and try to add each chunk, the call will only go through if it does not already exist. for i in range(1, numChunks): chunkSetName = makeChunkSetName(setName, i) print 'Add chunk set name to DB: ' + chunkSetName common.addDataRecord(db, common.SENSOR_TYPE_HiRISE, subtype, chunkSetName, remoteURL) raise Exception('DEBUG') # Now actually generate the desired chunk # - Need to use PIRL tools to extract a chunk to an IMG format, then convert that back to JP2 so that Google can read it. fileBasePath = os.path.splitext(localImagePath)[0] localImgPath = fileBasePath + '.IMG' localChunkPrefix = fileBasePath + '_' + str(chunkNum) chunkBB = getChunkBoundingBox(width, height, chunkNum) localChunkPath = correctAndCropImage(localImagePath, localLabelPath, localChunkPrefix, chunkBB) # Just use the same label file, we don't care if the DB has per-chunk boundaries. return [localChunkPath, localLabelPath] else: # A normal, non-polar file. # First file is for upload, second contains the timestamp. return [localImagePath, localLabelPath] # TODO: Handle POLAR DEMS else: # Handle DEMs # For DEMs there is no label file localFilePath = os.path.join(workDir, os.path.basename(remoteURL)) if not os.path.exists(localFilePath): # Download the image cmd = 'wget ' + remoteURL + ' -O ' + localFilePath print cmd os.system(cmd) if not IrgFileFunctions.fileIsNonZero( localFilePath): # Make sure we got the file raise Exception('Unable to download from URL: ' + remoteURL) # Generate a header file from the IMG file localLabelPath = localFilePath[:-4] + '.LBL' cmd = 'head -n 90 ' + localFilePath + ' > ' + localLabelPath print cmd os.system(cmd) # Check if this is a polar stereographic image isPolar = False f = open(localLabelPath) for line in f: if ("MAP_PROJECTION_TYPE" in line) and ("POLAR STEREOGRAPHIC" in line): isPolar = True print 'WARNING: POLAR STEREOGRAPHIC DEM MAY NOT UPLOAD PROPERLY' break #os.remove(localFilePath) #os.remove(localLabelPath) #raise Exception('POLAR STEREOGRAPHIC DEMs on hold until Google fixes a bug!') f.close() # Convert from IMG to TIF tiffFilePath = localFilePath[:-4] + '.TIF' if not os.path.exists(tiffFilePath): cmd = 'gdal_translate -of GTiff ' + localFilePath + ' ' + tiffFilePath print cmd os.system(cmd) if not isPolar: # Only EQC files need to be corrected # Correct projected coordinates problems cmd = 'python /home/pirl/smcmich1/repo/Tools/geoTiffTool.py --normalize-eqc-lon ' + tiffFilePath print cmd os.system(cmd) os.remove(localFilePath) # Clean up source image return [tiffFilePath, localLabelPath]
def fetchAndPrepFile(db, setName, subtype, remoteURL, workDir): '''Retrieves a remote file and prepares it for upload''' #print 'Uploading file ' + setName # Images with a center over this latitude will use polar stereographic projection # instead of simple cylindrical projection. HIGH_LATITUDE_CUTOFF = 65 # Degrees asuImagePath = os.path.join(workDir, setName + '_noGeo.jp2') # Map projected image from ASU asuLabelPath = os.path.join(workDir, setName + '_noGeo.lbl') # Label from ASU edrPath = os.path.join(workDir, setName + '.IMG') # Raw image from PDS timePath = os.path.join( workDir, setName + '.time') # Contains only the file capture time string #cubPath = os.path.join(workDir, setName + '.cub') # Output of mroctx2isis #calPath = os.path.join(workDir, setName + '.cal.cub') # Output of ctxcal mapPath = os.path.join(workDir, setName + '.map.cub') # Output of cam2map mapLabelPath = os.path.join(workDir, setName + '.map.pvl') # Specify projection to cam2map # Generate the remote URLs from the data prefix and volume stored in these parameters asuImageUrl, asuLabelUrl, edrUrl = generatePdsPath(setName, subtype) if True: # Map project the EDR ourselves <-- This takes way too long! print 'Projecting the EDR image using ISIS...' localFilePath = os.path.join(workDir, setName + '.tif') # The output file we will upload # Check if this is a "flat" calibration image badImage = checkForBadFile(edrUrl) if badImage: raise Exception('TODO: Remove bad images from the DB!') if not os.path.exists(edrPath): # Download the EDR file cmd = 'wget ' + edrUrl + ' -O ' + edrPath print cmd os.system(cmd) # Extract the image capture time from the .IMG file if not os.path.exists(timePath): timeString = getCreationTimeHelper(edrPath) f = open(timePath, 'w') f.write(timeString) f.close() # Convert and apply calibration to the CTX file calPath = IrgIsisFunctions.prepareCtxImage(edrPath, workDir, False) ## Find out the center latitude of the file and determine if it is high latitude centerLat = IrgIsisFunctions.getCubeCenterLatitude(calPath, workDir) print centerLat highLat = abs(float(centerLat)) > HIGH_LATITUDE_CUTOFF if True: #not os.path.exists(mapLabelPath): # Generate the map label file generateDefaultMappingPvl(mapLabelPath, highLat) if True: #not os.path.exists(mapPath): # Generate the map projected file cmd = [ 'timeout', '6h', 'cam2map', 'matchmap=', 'False', 'from=', calPath, 'to=', mapPath, 'map=', mapLabelPath ] print cmd #os.system(cmd) p = subprocess.Popen(cmd) p.communicate() if (p.returncode != 0): raise Exception( 'Error or timeout running cam2map, returnCode = ' + str(p.returncode)) if True: #not os.path.exists(localFilePath): # Generate the final image to upload cmd = 'gdal_translate -of GTiff ' + mapPath + ' ' + localFilePath print cmd os.system(cmd) # Clean up intermediate files os.remove(mapLabelPath) os.remove(edrPath) os.remove(calPath) os.remove(mapPath) # Two local files are left around, the first should be uploaded. return [localFilePath, timePath] else: # Use the map projected image from the ASU web site print 'Using ASU projected image...' localFilePath = os.path.join(workDir, setName + '.jp2') # The output file we will upload # Note: ASU seems to be missing some files! # We are using the label path in both projection cases if not os.path.exists(asuLabelPath): # Download the label file cmd = 'wget "' + asuLabelUrl + '" -O ' + asuLabelPath print cmd os.system(cmd) if not IrgFileFunctions.fileIsNonZero( asuLabelPath): # Try the alternate label path os.remove(asuLabelPath) asuLabelUrl = asuLabelUrl.replace('.scyl.', '.ps.') asuLabelPath = asuLabelPath.replace('.scyl.', '.ps.') print 'Trying alternate label path: ' + asuLabelUrl # Download the label file cmd = 'wget "' + asuLabelUrl + '" -O ' + asuLabelPath print cmd os.system(cmd) if not IrgFileFunctions.fileIsNonZero(asuLabelPath): raise Exception('Failed to download file label at URL: ' + asuLabelUrl) # Check the projection type projType = IrgGeoFunctions.getProjectionFromIsisLabel(asuLabelPath) if projType != 'SimpleCylindrical': print 'WARNING: projType = ' + projType print 'Maps Engine may fail to ingest this file!' #os.remove(asuLabelPath) #raise Exception(projType + ' images on hold until Google fixes a bug!') if not os.path.exists(asuImagePath): # Download the image file cmd = 'wget "' + asuImageUrl + '" -O ' + asuImagePath print cmd os.system(cmd) if not IrgFileFunctions.fileIsNonZero(asuImagePath): raise Exception('Failed to download image file at URL: ' + asuImageUrl) ## Correct the ISIS header if needed #fixedAsuHeaderPath = putIsisHeaderIn180(asuLabelPath) #if (fixedAsuHeaderPath != asuLabelPath): # os.remove(asuLabelPath) # Delete replaced header if True: # This is fast now, so do it every time # Correct the file - The JP2 file from ASU needs the geo data from the label file! #cmd = 'addGeoToAsuCtxJp2.py --keep --label '+ asuLabelPath +' '+ asuImagePath +' '+ localFilePath #print cmd #os.system(cmd) # TODO: Remove unnecessary image copy here (correctedPath, sidecarPath) = addGeoDataToAsuJp2File(asuImagePath, asuLabelPath, localFilePath, keep=False) if not IrgFileFunctions.fileIsNonZero(sidecarPath): raise Exception('Script to add geo data to JP2 file failed!') # Clean up os.remove(asuImagePath) # Three local files are left around, the first should be uploaded. return [correctedPath, sidecarPath, asuLabelPath]
def fetchAndPrepFile(db, setName, subtype, remoteURL, workDir): '''Retrieves a remote file and prepares it for upload''' #print 'Uploading file ' + setName if subtype != 'DEM': # Handles RED and COLOR images # The label file URL is the same as the image but with a different extension remoteLabelURL = getLabelPathFromImagePath(remoteURL) localFilePath = os.path.join(workDir, os.path.basename(remoteURL)) localLabelPath = os.path.join(workDir, os.path.basename(remoteLabelURL)) # Retrieve the header file if not os.path.exists(localLabelPath): # Try to get the label locally! pdsStart = remoteLabelURL.find('PDS') localPdsPath = os.path.join('/HiRISE/Data/', remoteLabelURL[pdsStart:]) print localPdsPath if os.path.exists(localPdsPath): # File available locally, just copy it! cmd = 'cp ' + localPdsPath +' '+ localLabelPath else: # Download the image cmd = 'wget ' + remoteLabelURL + ' -O ' + localLabelPath print cmd os.system(cmd) # Retrieve the image file if not os.path.exists(localFilePath): # Need to get it from somewhere # Try to get the image locally! pdsStart = remoteURL.find('PDS') localPdsPath = os.path.join('/HiRISE/Data/', remoteURL[pdsStart:]) if os.path.exists(localPdsPath): # File available locally, just copy it! cmd = 'cp ' + localPdsPath +' '+ localFilePath else: # Download the image cmd = 'wget ' + remoteURL + ' -O ' + localFilePath print cmd os.system(cmd) if not IrgFileFunctions.fileIsNonZero(localFilePath): if not IrgFileFunctions.fileIsNonZero(localLabelPath): print 'Could not find label or image file, DELETING DATA RECORD!' common.removeDataRecord(db, common.SENSOR_TYPE_HiRISE, subtype, setName) raise Exception('Unable to download from URL: ' + remoteURL) # Check if there is geo data in the JP2 file jp2HasGeoData = IrgGeoFunctions.doesImageHaveGeoData(localFilePath) # If there is no label file, try to generate an artificial one. fakeLabelFile = False if not IrgFileFunctions.fileIsNonZero(localLabelPath): #raise Exception('Unable to download from URL: ' + remoteLabelURL) print 'WARNING: Unable to download from URL: ' + remoteLabelURL if not jp2HasGeoData: raise Exception('No geo data in JP2 and no Label file! Cannot handle this!') print 'Generating a fake LBL file to proceed...' localLabelPath = writeFakeLabelFromJp2(localFilePath) fakeLabelFile = True # At this point we always have a label file but it may be fake # Some images are missing geo information but we can add it from the label file localImageIsTiff = False localImagePath = localFilePath if not jp2HasGeoData: print 'Correcting JP2 file with no geo information!!!!' # Correct the local file, then remove the old (bad) file outputPrefix = localFilePath[0:-4] localImagePath = correctAndCropImage(localFilePath, localLabelPath, outputPrefix) print 'Generated ' + localImagePath if localFilePath != localImagePath: print 'Deleting JP2 file without metadata!' os.remove(localFilePath) localImageIsTiff = (localImagePath[-4:] == ".TIF") if not localImageIsTiff: # Call code to fix the header information in the JP2 file! cmd = FIX_JP2_TOOL +' '+ localImagePath print cmd os.system(cmd) # Check the projection type projType = IrgGeoFunctions.getProjectionFromIsisLabel(localLabelPath) (width, height) = IrgIsisFunctions.getImageSize(localImagePath) if (projType == 'POLAR STEREOGRAPHIC') and False: #(width < MAX_POLAR_UPLOAD_WIDTH): # Google has trouble digesting these files so handle them differently. #os.remove(localLabelPath) #raise Exception('POLAR STEREOGRAPHIC images on hold until Google fixes a bug!') print 'Special handling for POLAR STEROGRAPHIC image!' if fakeLabelFile: print 'Cannot reprocess polar image without a label file!' print 'All we can do is upload the file and hope for the best.' # First file is for upload, second contains the timestamp. return [localImagePath, localLabelPath] # Compute how many chunks are needed for this image numChunks = ceil(width / POLAR_WIDTH_CHUNK_SIZE) # Determine which chunk this DB entry is for chunkNum = getChunkNum(setName) print 'This is chunk number ' + str(chunkNum) if chunkNum >= numChunks: # Check for chunk number error raise Exception('Illegal chunk number: ' + setName) # If this is the main DB entry, we need to make sure the other DB entries exist! if chunkNum == 0: # Go ahead and try to add each chunk, the call will only go through if it does not already exist. for i in range(1,numChunks): chunkSetName = makeChunkSetName(setName, i) print 'Add chunk set name to DB: ' + chunkSetName common.addDataRecord(db, common.SENSOR_TYPE_HiRISE, subtype, chunkSetName, remoteURL) raise Exception('DEBUG') # Now actually generate the desired chunk # - Need to use PIRL tools to extract a chunk to an IMG format, then convert that back to JP2 so that Google can read it. fileBasePath = os.path.splitext(localImagePath)[0] localImgPath = fileBasePath + '.IMG' localChunkPrefix = fileBasePath + '_' + str(chunkNum) chunkBB = getChunkBoundingBox(width, height, chunkNum) localChunkPath = correctAndCropImage(localImagePath, localLabelPath, localChunkPrefix, chunkBB) # Just use the same label file, we don't care if the DB has per-chunk boundaries. return [localChunkPath, localLabelPath] else: # A normal, non-polar file. # First file is for upload, second contains the timestamp. return [localImagePath, localLabelPath] # TODO: Handle POLAR DEMS else: # Handle DEMs # For DEMs there is no label file localFilePath = os.path.join(workDir, os.path.basename(remoteURL)) if not os.path.exists(localFilePath): # Download the image cmd = 'wget ' + remoteURL + ' -O ' + localFilePath print cmd os.system(cmd) if not IrgFileFunctions.fileIsNonZero(localFilePath): # Make sure we got the file raise Exception('Unable to download from URL: ' + remoteURL) # Generate a header file from the IMG file localLabelPath = localFilePath[:-4] + '.LBL' cmd = 'head -n 90 ' + localFilePath +' > '+ localLabelPath print cmd os.system(cmd) # Check if this is a polar stereographic image isPolar = False f = open(localLabelPath) for line in f: if ("MAP_PROJECTION_TYPE" in line) and ("POLAR STEREOGRAPHIC" in line): isPolar = True print 'WARNING: POLAR STEREOGRAPHIC DEM MAY NOT UPLOAD PROPERLY' break #os.remove(localFilePath) #os.remove(localLabelPath) #raise Exception('POLAR STEREOGRAPHIC DEMs on hold until Google fixes a bug!') f.close() # Convert from IMG to TIF tiffFilePath = localFilePath[:-4] + '.TIF' if not os.path.exists(tiffFilePath): cmd = 'gdal_translate -of GTiff ' + localFilePath +' '+ tiffFilePath print cmd os.system(cmd) if not isPolar: # Only EQC files need to be corrected # Correct projected coordinates problems cmd = 'python /home/pirl/smcmich1/repo/Tools/geoTiffTool.py --normalize-eqc-lon ' + tiffFilePath print cmd os.system(cmd) os.remove(localFilePath) # Clean up source image return [tiffFilePath, localLabelPath]
def main(argsIn): print '#################################################################################' print "Running makeDemAndCompare.py" try: try: usage = "usage: makeDemAndCompare.py [--output <path>][--manual]\n " parser = optparse.OptionParser(usage=usage) inputGroup = optparse.OptionGroup(parser, 'Input Paths') inputGroup.add_option("--left", dest="leftPath", help="Path to left cube file") inputGroup.add_option("--right", dest="rightPath", help="Path to right cube file") inputGroup.add_option("--lola", dest="lolaPath", help="Path to LOLA DEM") inputGroup.add_option("--asu", dest="asuPath", help="Path to ASU DEM") inputGroup.add_option("--node-file", dest="nodeFilePath", help="Path to file containing list of available nodes") parser.add_option_group(inputGroup) # The default working directory path is kind of ugly... parser.add_option("--workDir", dest="workDir", help="Folder to store temporary files in") parser.add_option("--prefix", dest="prefix", help="Output prefix.") parser.add_option("--log-path", dest="logPath", help="Where to write the output log file.") parser.add_option("--crop", dest="cropAmount", help="Crops the output image to reduce processing time.") parser.add_option("--manual", action="callback", callback=man, help="Read the manual.") parser.add_option("--keep", action="store_true", dest="keep", help="Do not delete the temporary files.") (options, args) = parser.parse_args(argsIn) if not options.leftPath: parser.error("Need left input path") if not options.rightPath: parser.error("Need right input path") if not options.prefix: parser.error("Need output prefix") except optparse.OptionError, msg: raise Usage(msg) print "Beginning processing....." startTime = time.time() # Make sure we have all the functions we need functionStartupCheck() # Set this to true to force steps after it to activate carry = False # Set up the output folders outputFolder = os.path.dirname(options.prefix) inputBaseName = os.path.basename(options.leftPath) tempFolder = outputFolder + '/' + inputBaseName + '_stereoCalibrationTemp/' if (options.workDir): tempFolder = options.workDir if not os.path.exists(outputFolder): os.mkdir(outputFolder) hadToCreateTempFolder = not os.path.exists(tempFolder) if not os.path.exists(tempFolder): os.mkdir(tempFolder) # Set up logging if not options.logPath: options.logPath = options.prefix + '-Log.txt' logging.basicConfig(filename=options.logPath,level=logging.INFO) # Go ahead and set up all the output paths # -- Deliverables demPath = options.prefix + '-DEM.tif' intersectionErrorPath = options.prefix + '-IntersectionErr.tif' hillshadePath = options.prefix + '-Hillshade.tif' colormapPath = options.prefix + '-Colormap.tif' colormapLegendPath = options.prefix + '-ColormapLegend.csv' mapProjectLeftPath = options.prefix + '-MapProjLeft.tif' mapProjectRightPath = options.prefix + '-MapProjRight.tif' confidenceLevelPath = options.prefix + '-Confidence.tif' confidenceLegendPath = options.prefix + '-ConfidenceLegend.csv' # -- Diagnostic intersectionViewPathX = options.prefix + '-IntersectionErrorX.tif' intersectionViewPathY = options.prefix + '-IntersectionErrorY.tif' intersectionViewPathZ = options.prefix + '-IntersectionErrorZ.tif' lolaDiffStatsPath = options.prefix + '-LOLA_diff_stats.txt' lolaDiffPointsPath = options.prefix + '-LOLA_diff_points.csv' lolaAsuDiffStatsPath = options.prefix + '-ASU_LOLA_diff_stats.txt' lolaAsuDiffPointsPath = options.prefix + '-ASU_LOLA_diff_points.csv' mapProjectLeftUint8Path = options.prefix + '-MapProjLeftUint8.tif' mapProjectRightUint8Path = options.prefix + '-MapProjRightUint8.tif' # If specified, crop the inputs that will be passed into the stereo function to reduce processing time mainMosaicCroppedPath = os.path.join(tempFolder, 'mainMosaicCropped.cub') stereoMosaicCroppedPath = os.path.join(tempFolder, 'stereoMosaicCropped.cub') if options.cropAmount and (options.cropAmount > 0): # Verify input files are present if not os.path.exists(options.leftPath): raise Exception('Input file ' + options.leftPath + ' not found!') if not os.path.exists(options.rightPath): raise Exception('Input file ' + options.rightPath + ' not found!') if (not os.path.exists(mainMosaicCroppedPath)) or carry: cmd = ('crop from= ' + options.leftPath + ' to= ' + mainMosaicCroppedPath + ' nlines= ' + str(options.cropAmount))# + ' line=24200') print cmd os.system(cmd) if (not os.path.exists(stereoMosaicCroppedPath) or carry): cmd = ('crop from= ' + options.rightPath + ' to= ' + stereoMosaicCroppedPath + ' nlines= ' + str(options.cropAmount))# + ' line=24200') print cmd os.system(cmd) options.leftPath = mainMosaicCroppedPath options.rightPath = stereoMosaicCroppedPath print '\n-------------------------------------------------------------------------\n' # Call stereo to generate a point cloud from the two images # - This step takes a really long time. stereoOutputPrefix = os.path.join(tempFolder, 'stereoWorkDir/stereo') stereoOutputFolder = os.path.join(tempFolder, 'stereoWorkDir') pointCloudPath = stereoOutputPrefix + '-PC.tif' stereoOptionString = ('--corr-timeout 400 --alignment-method AffineEpipolar --subpixel-mode ' + str(SUBPIXEL_MODE) + ' ' + options.leftPath + ' ' + options.rightPath + ' --job-size-w 4096 --job-size-h 4096 ' + # Reduce number of tile files created ' ' + stereoOutputPrefix + ' --processes 10 --threads-multiprocess 4' + ' --threads-singleprocess 32 --compute-error-vector' + ' --filter-mode 1' + ' --erode-max-size 5000 --subpixel-kernel 35 35 --subpixel-max-levels 0') if (not os.path.exists(pointCloudPath) and not os.path.exists(demPath)) or carry: # Verify input files are present if not os.path.exists(options.leftPath): raise Exception('Input file ' + options.leftPath + ' not found!') if not os.path.exists(options.rightPath): raise Exception('Input file ' + options.rightPath + ' not found!') cmd = ('parallel_stereo ' + stereoOptionString) print cmd os.system(cmd) # Compute percentage of good pixels percentGood = IrgAspFunctions.getStereoGoodPixelPercentage(stereoOutputPrefix) print 'Stereo completed with good pixel percentage: ' + str(percentGood) logging.info('Final stereo completed with good pixel percentage: %s', str(percentGood)) else: print 'Stereo file ' + pointCloudPath + ' already exists, skipping stereo step.' stereoTime = time.time() logging.info('Stereo finished in %f seconds', stereoTime - startTime) # Find out the center latitude of the mosaic if os.path.exists(options.leftPath): centerLat = IrgIsisFunctions.getCubeCenterLatitude(options.leftPath, tempFolder) elif os.path.exists(demPath): # Input file has been deleted but we still have the info demInfo = IrgGeoFunctions.getImageGeoInfo(demPath, False) centerLat = demInfo['standard_parallel_1'] else: raise Exception("Can't delete the input files before creating the DEM!") # Generate a DEM if (not os.path.exists(demPath)) or carry: # Equirectangular style projection # - Latitude of true scale = center latitude = lat_ts # - Latitude of origin = 0 = lat+0 # - Longitude of projection center = Central meridian = lon+0 cmd = ('point2dem --dem-hole-fill-len 15 --remove-outliers --errorimage -o ' + options.prefix + ' ' + pointCloudPath + ' -r moon --tr ' + str(DEM_METERS_PER_PIXEL) + ' --t_srs "+proj=eqc +lat_ts=' + str(centerLat) + ' +lat_0=0 +a='+str(MOON_RADIUS)+' +b='+str(MOON_RADIUS)+' +units=m" --nodata ' + str(DEM_NODATA)) os.system(cmd) else: print 'DEM file ' + demPath + ' already exists, skipping point2dem step.' # Create a hillshade image to visualize the output if (not os.path.exists(hillshadePath)) or carry: cmd = 'hillshade ' + demPath + ' -o ' + hillshadePath print cmd os.system(cmd) else: print 'Output file ' + hillshadePath + ' already exists, skipping hillshade step.' # Create a colorized version of the hillshade # - Uses a blue-red color map from here: http://www.sandia.gov/~kmorel/documents/ColorMaps/ if (not os.path.exists(colormapPath)) or (not os.path.exists(colormapLegendPath)) or carry: # The color LUT is kept with the source code lutFilePath = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'colorProfileBlueRed.csv') # Generate the initial version of colormap colormapTempPath = options.prefix + '-ColormapTemp.tif' cmd = 'colormap ' + demPath + ' -o ' + colormapTempPath + ' -s ' + hillshadePath + ' --lut-file ' + lutFilePath print cmd os.system(cmd) # Now convert to the final output version (remove transparency layer) and remove the temp file IrgFileFunctions.stripRgbImageAlphaChannel(colormapTempPath, colormapPath) os.remove(colormapTempPath) # Generate another file storing the colormap info writeColorMapInfo(colormapPath, lutFilePath, demPath, colormapLegendPath) else: print 'Output file ' + colormapPath + ' already exists, skipping colormap step.' ## Create a 3d mesh of the point cloud #meshPath = os.path.join(outputFolder, 'mesh.ive') #meshPrefix = os.path.join(outputFolder, 'mesh') #cmd = 'point2mesh ' + pointCloudPath + ' ' + options.leftPath + ' -o ' + meshPrefix #if not os.path.exists(meshPath): # print cmd # os.system(cmd) if not options.keep: # Remove stereo folder here to cut down on file count before mapproject calls IrgFileFunctions.removeFolderIfExists(stereoOutputFolder) # Convert the intersection error to a viewable format cmdX = 'gdal_translate -ot byte -scale 0 10 0 255 -outsize 50% 50% -b 1 ' + intersectionErrorPath + ' ' + intersectionViewPathX cmdY = 'gdal_translate -ot byte -scale 0 10 0 255 -outsize 50% 50% -b 2 ' + intersectionErrorPath + ' ' + intersectionViewPathY cmdZ = 'gdal_translate -ot byte -scale 0 10 0 255 -outsize 50% 50% -b 3 ' + intersectionErrorPath + ' ' + intersectionViewPathZ if not os.path.exists(intersectionViewPathX) or carry: print cmdX os.system(cmdX) if not os.path.exists(intersectionViewPathY) or carry: print cmdY os.system(cmdY) if not os.path.exists(intersectionViewPathZ) or carry: print cmdZ os.system(cmdZ) # Generate a confidence plot from the intersection error if not os.path.exists(confidenceLevelPath): thresholdString = str(PIXEL_ACCURACY_THRESHOLDS)[1:-1].replace(',', '') cmd = ('maskFromIntersectError ' + intersectionErrorPath + ' ' + confidenceLevelPath + ' --legend ' + confidenceLegendPath + ' --scaleOutput --thresholds ' + thresholdString) print cmd os.system(cmd) hillshadeTime = time.time() logging.info('DEM and hillshade finished in %f seconds', hillshadeTime - stereoTime) # Call script to compare LOLA data with the DEM if options.lolaPath: compareDemToLola(options.lolaPath, demPath, lolaDiffStatsPath, lolaDiffPointsPath, carry) # Call script to compare LOLA data with the ASU DEM if options.asuPath: compareDemToLola(options.lolaPath, options.asuPath, lolaAsuDiffStatsPath, lolaAsuDiffPointsPath, carry) # Generate a map projected version of the left and right images # - This step is done last since it is so slow! mapProjectImage(options.leftPath, demPath, mapProjectLeftPath, MAP_PROJECT_METERS_PER_PIXEL, centerLat, options.nodeFilePath, carry) mapProjectImage(options.rightPath, demPath, mapProjectRightPath, MAP_PROJECT_METERS_PER_PIXEL, centerLat, options.nodeFilePath, carry) # Generate 8 bit versions of the mapproject files for debugging cmdLeft = 'gdal_translate -scale -ot byte ' + mapProjectLeftPath + ' ' + mapProjectLeftUint8Path cmdRight = 'gdal_translate -scale -ot byte ' + mapProjectRightPath + ' ' + mapProjectRightUint8Path if not os.path.exists(mapProjectLeftUint8Path) or carry: print cmdLeft os.system(cmdLeft) if not os.path.exists(mapProjectRightUint8Path) or carry: print cmdRight os.system(cmdRight) mapProjectTime = time.time() logging.info('Map project finished in %f seconds', mapProjectTime - hillshadeTime) # Clean up temporary files if not options.keep: print 'Removing temporary files' IrgFileFunctions.removeIfExists(mainMosaicCroppedPath) IrgFileFunctions.removeIfExists(stereoMosaicCroppedPath) #IrgFileFunctions.removeIntermediateStereoFiles(stereoOutputPrefix) # Limited clear IrgFileFunctions.removeFolderIfExists(stereoOutputFolder) # Larger clear #if (hadToCreateTempFolder): Not done since stereo output needs to be retained # IrgFileFunctions.removeFolderIfExists(tempFolder) endTime = time.time() logging.info('makeDemAndCompare.py finished in %f seconds', endTime - startTime) print "Finished in " + str(endTime - startTime) + " seconds." print '#################################################################################' return 0
def main(argsIn): print "Started positionCorrector.py" try: try: usage = "usage: positionCorrector.py [--input <cube file>][--output <path>][--manual]\n " parser = optparse.OptionParser(usage=usage) parser.add_option("-i", "--input", dest="inputPath", help="Path to the input file.") parser.add_option("-o", "--output", dest="outputPath", help="Where to write the output file.") # The default working directory path is kind of ugly... parser.add_option("--workDir", dest="workDir", help="Folder to store temporary files in") parser.add_option("--manual", action="callback", callback=man, help="Read the manual.") parser.add_option("--keep", action="store_true", dest="keep", help="Do not delete the temporary files.") parser.add_option("--spk", dest="spkPath", help='Output SPK path (always keep)') (options, args) = parser.parse_args(argsIn) if not options.inputPath: parser.error("Need input path") if not options.outputPath: parser.error("Need output path") except optparse.OptionError, msg: raise Usage(msg) print "Beginning processing....." startTime = time.time() outputFolder = os.path.dirname(options.outputPath) inputBaseName = os.path.basename(options.inputPath) tempFolder = outputFolder + '/' + inputBaseName + '_posCorrectTemp/' if (options.workDir): tempFolder = options.workDir if not os.path.exists(tempFolder): os.mkdir(tempFolder) # Copy the input file to the output location cmd = "cp " + options.inputPath + " " + options.outputPath #print cmd os.system(cmd) # Retrieve a list of all the kernels needed by the input cube file kernelDict = IrgIsisFunctions.getKernelsFromCube(options.outputPath) # Find the leap second file if not ('LeapSecond' in kernelDict): os.remove(options.outputPath) raise Exception('Error! Unable to find leap second file!') else: leapSecondFilePath = kernelDict['LeapSecond'][0] # Only deal with a single file # Convert the kernels into a list of strings to pass as arguments kernelStringList = [] for k, v in kernelDict.iteritems(): # Iterate through dictionary entries # Add everything except the gigantic shape model (DEM) if k != 'ShapeModel': for i in v: # Iterate through type lists kernelStringList.append(str(i)) # Determine if the input file is LE or RE lePos = options.inputPath.rfind('LE') rePos = options.inputPath.rfind('RE') # Set the offsets from LRO spacecraft to the LRONAC cameras in meters if (lePos > rePos): lronacOffset = [1.3462, 0.8890, -0.1778] # LE else: lronacOffset = [1.0160, 0.8890, -0.1778] # RE # Write out a file containing the LRONAC camera offset lronacOffsetPath = os.path.join(tempFolder, "lronacCameraOffset.csv") f = open(lronacOffsetPath, 'w') f.write('1 0 0 ' + str(lronacOffset[0]) + '\n') f.write('0 1 0 ' + str(lronacOffset[1]) + '\n') f.write('0 0 1 ' + str(lronacOffset[2]) + '\n') f.write('0 0 0 1') f.close() # Make sure the SPK data path does not already exist tempDataPrefix = os.path.join(tempFolder, "tempNavData") spkDataPath = tempDataPrefix + "-spkData.txt" if os.path.exists(spkDataPath): os.remove(spkDataPath) # Call lronac spice editor tool to generate modified text file # - Call is silent unless there is an error cmd = ['spiceEditor', '--transformType', '1', '--transformFile', lronacOffsetPath, '--outputPrefix', tempDataPrefix, '--sourceCube', options.inputPath, '--kernels'] + kernelStringList p = subprocess.Popen(cmd, stdout=subprocess.PIPE) outputText, err = p.communicate() if not os.path.exists(spkDataPath): os.remove(options.outputPath) print cmd print outputText raise Exception('Failed to create modified SPK data!') # Write the config file needed for the mkspk function #print 'Writing mkspk config file...' mkspkConfigPath = os.path.join(tempFolder, "spkConfig.txt") IsisTools.makeSpkSetupFile(leapSecondFilePath, mkspkConfigPath) # If the file already exists, delete it and rewrite it. if options.spkPath: tempSpkPath = options.spkPath #print 'Storing modified SPK file ' + tempSpkPath else: tempSpkPath = os.path.join(tempFolder, "modifiedLrocSpk.bsp") if os.path.exists(tempSpkPath): os.remove(tempSpkPath) #TODO: Temp trick to make sure this works for long paths # Create new SPK file using modified data # - Call is silent unless there is an error cmd = ['mkspk', '-setup', mkspkConfigPath, '-input', spkDataPath, '-output', tempSpkPath] p = subprocess.Popen(cmd, stdout=subprocess.PIPE) outputText, err = p.communicate() if not os.path.exists(tempSpkPath): os.remove(options.outputPath) print cmd print outputText raise Exception('Failed to create modified SPK file!') # Re-run spiceinit using the new SPK file cmd = ['spiceinit', 'attach=', 'true', 'from=', options.outputPath, "spk=", tempSpkPath] #print cmd p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) outputText, err = p.communicate() if (outputText.find('ERROR') >= 0): print cmd print outputText raise Exception('Found error when calling spiceinit!') # Clean up temporary files if not options.keep: os.remove(spkDataPath) os.remove(mkspkConfigPath) endTime = time.time() print "Finished in " + str(endTime - startTime) + " seconds." return 0