def create_RED45_mosaic(obsid, overwrite=False): gp_root = io.get_ground_projection_root() logger.info('Processing the EDR data associated with ' + obsid) mos_path = gp_root / obsid / f'{obsid}_mosaic_RED45.cub' # bail out if exists: if mos_path.exists() and not overwrite: print(f'{mos_path} already exists and I am not allowed to overwrite.') return obsid, True products = get_RED45_mosaic_inputs(obsid, gp_root) for prod in products: prod.download() nocal_hi(prod) norm_paths = [] for channel_products in [products[:2], products[2:]]: norm_paths.append(stitch_cubenorm(*channel_products)) # handmos part norm4, norm5 = norm_paths im0 = CubeFile.open(str(norm4)) # use CubeFile to get lines and samples # get binning mode from label bin_ = int( getkey(from_=str(norm4), objname="isiscube", grpname="instrument", keyword="summing")) # because there is a gap btw RED4 & 5, nsamples need to first make space # for 2 cubs then cut some overlap pixels try: handmos(from_=str(norm4), mosaic=str(mos_path), nbands=1, outline=1, outband=1, create='Y', outsample=1, nsamples=im0.samples * 2 - 48 // bin_, nlines=im0.lines) except ProcessError as e: print("STDOUT:", e.stdout) print("STDERR:", e.stderr) im0 = CubeFile.open(str(norm5)) # use CubeFile to get lines and samples # deal with the overlap gap between RED4 & 5: handmos(from_=str(norm5), mosaic=str(mos_path), outline=1, outband=1, create='N', outsample=im0.samples - 48 // bin_ + 1) for norm in [norm4, norm5]: norm.unlink() return obsid, True
def getPDSid(infile): """ Use ISIS to get the PDS Product ID of a cube. Using ISIS `getkey` is preferred over extracting the Product ID using the PVL library because of an edge case where PVL will erroneously convert Product IDs from string to floating point. Parameters ---------- infile : str A string file path from which the Product ID will be extracted. Returns ------- prod_id : str The PDS Product ID. """ for key in ['product_id', 'productid']: try: prod_id = isis.getkey(from_=infile, keyword=key, recursive="TRUE") break except ProcessError as e: prod_id = None if not prod_id: return None # in later versions of ISIS, key values are returned as bytes if isinstance(prod_id, bytes): prod_id = prod_id.decode() prod_id = prod_id.replace('\n', '') return prod_id
def check_label(self): """ Check label for target and fix if necessary. Forcing the target name to Saturn here, because some observations of the rings have moons as a target, but then the standard map projection onto the Saturn ring plane fails. See also -------- https://isis.astrogeology.usgs.gov/IsisSupport/index.php/topic,3922.0.html """ if not self.is_ring_data: return targetname = getkey( from_=self.pm.raw_cub, grp="instrument", keyword="targetname" ) if targetname.lower() != "saturn": editlab( from_=self.pm.raw_cub, options="modkey", keyword="TargetName", value="Saturn", grpname="Instrument", )
def is_lossy(label): """Check Label file for the compression type. """ val = getkey(from_=label, keyword='INST_CMPRS_TYPE').decode().strip() if val == 'LOSSY': return True else: return False
def download_LOLA_for_NAC_pair(left_nac, right_nac=None, nac_dir='/data/nac'): """ Function that downloads Lunar Orbital Laser Altimeter (LOLA) Reduced Data Records (RDR) for a given pair of LRO NAC paths. If no right_nac is given, will retrieve LOLA data for bounds of left_nac only. For a pair, the download will be saved to a file [nac_dir]/[left pair id]xx[right pair id]_lola.csv :param left_nac: Path to a map-projected NAC file in ISIS .cub format :param right_nac: Path to a map-projected NAC file in ISIS .cub format :return: Full path of downloaded LOLA EDR .csv """ from pysis.isis import getkey from pysis.exceptions import ProcessError left_file_path = path.join(nac_dir, left_nac) try: left_bounds = ( getkey(from_=left_file_path, grpname='Mapping', keyword='MinimumLongitude').strip(), getkey(from_=left_file_path, grpname='Mapping', keyword='MinimumLatitude').strip(), getkey(from_=left_file_path, grpname='Mapping', keyword='MaximumLongitude').strip(), getkey(from_=left_file_path, grpname='Mapping', keyword='MaximumLatitude').strip() ) if right_nac: right_file_path = path.join(nac_dir, right_nac) right_bounds = ( getkey(from_=right_file_path, grpname='Mapping', keyword='MinimumLongitude').strip(), getkey(from_=right_file_path, grpname='Mapping', keyword='MinimumLatitude').strip(), getkey(from_=right_file_path, grpname='Mapping', keyword='MaximumLongitude').strip(), getkey(from_=right_file_path, grpname='Mapping', keyword='MaximumLatitude').strip() ) lola_filename = path.join(nac_dir, f'{left_nac.split(".")[0]}xx{right_nac.split(".")[0]}_lola.csv') else: right_bounds = [None] * 4 lola_filename = path.join(nac_dir, f'{left_nac.split(".")[0]}_lola.csv') minlon, minlat = [ right_bound if float(right_bound) < float(left_bound) else left_bound for right_bound, left_bound in zip(right_bounds[0:2], left_bounds[0:2]) ] except ProcessError as e: print("STDOUT:", e.stdout) print("STDERR:", e.stderr) maxlon, maxlat = [ right_bound if float(right_bound) > float(left_bound) else left_bound for right_bound, left_bound in zip(right_bounds[2:4], left_bounds[2:4]) ] minlon, minlat, maxlon, maxlat = [float(val) for val in (minlon, minlat, maxlon, maxlat)] download_LOLA_by_bounds(minlon=minlon, minlat=minlat, maxlon=maxlon, maxlat=maxlat, lola_filename=lola_filename)
def create_RED45_mosaic(obsid, overwrite=False): gp_root = io.get_ground_projection_root() logger.info('Processing the EDR data associated with ' + obsid) mos_path = gp_root / obsid / f'{obsid}_mosaic_RED45.cub' # bail out if exists: if mos_path.exists() and not overwrite: print(f'{mos_path} already exists and I am not allowed to overwrite.') return obsid, True products = get_RED45_mosaic_inputs(obsid, gp_root) for prod in products: prod.download() nocal_hi(prod) norm_paths = [] for channel_products in [products[:2], products[2:]]: norm_paths.append(stitch_cubenorm(*channel_products)) # handmos part norm4, norm5 = norm_paths im0 = CubeFile.open(str(norm4)) # use CubeFile to get lines and samples # get binning mode from label bin_ = int(getkey(from_=str(norm4), objname="isiscube", grpname="instrument", keyword="summing")) # because there is a gap btw RED4 & 5, nsamples need to first make space # for 2 cubs then cut some overlap pixels try: handmos(from_=str(norm4), mosaic=str(mos_path), nbands=1, outline=1, outband=1, create='Y', outsample=1, nsamples=im0.samples * 2 - 48 // bin_, nlines=im0.lines) except ProcessError as e: print("STDOUT:", e.stdout) print("STDERR:", e.stderr) im0 = CubeFile.open(str(norm5)) # use CubeFile to get lines and samples # deal with the overlap gap between RED4 & 5: handmos(from_=str(norm5), mosaic=str(mos_path), outline=1, outband=1, create='N', outsample=im0.samples - 48 // bin_ + 1) for norm in [norm4, norm5]: norm.unlink() return obsid, True
def get_single_band_cube(cube,out_cube,band_list,keyname): """ Convenience function to extract a single band from an ISIS cube based on a prioritized list of band numbers, and the name of a keyword to search for in the BandBin group of the cube. This is necessary for generating browse/thumbnail images from multiband images where certain bands are preferred over others for use in the output, but there is no way of knowing whether the preferred band is present without inspecting the ingested ISIS cube. Parameters ---------- cube : str A string file path to the input cube. out_cube : str A string file path to the desired output cube. band_list : list A list of ints representing band numbers to search for in cube, in decreasing order of priority keyname : str The name of the keyword to look for in the BandBin group of the input cube. Returns ------- isis.cubeatt() : function Calls the ISIS function, cubeatt, in order to write out a single band cube """ bands_in_cube = isis.getkey(from_=cube, objname="IsisCube", grpname="BandBin", keyword=keyname) if isinstance(bands_in_cube, bytes): bands_in_cube = bands_in_cube.decode() bands_in_cube = bands_in_cube.replace('\n', '').replace(' ', '').split(',') bands_in_cube = [int(x) for x in bands_in_cube] for band in band_list: if band in bands_in_cube: isis.cubeatt(from_=cube + '+' + str(band), to=out_cube) break else: continue return
def main( argv = None ): inputlbl = None outputConfig = None run = None template = None if argv is None: argv = sys.argv argv = gdal.GeneralCmdLineProcessor( argv ) if argv is None: return 1 nArgc = len(argv) #/* -------------------------------------------------------------------- */ #/* Parse arguments. */ #/* -------------------------------------------------------------------- */ i = 1 while i < nArgc: if EQUAL(argv[i], '-run'): run = True elif EQUAL(argv[i], '-template'): i = i + 1 template = argv[i] elif inputlbl is None: inputlbl = argv[i] elif outputConfig is None: outputConfig = argv[i] else: return Usage(argv[0]) i = i + 1 if inputlbl is None: return Usage(argv[0]) if outputConfig is None: return Usage(argv[0]) if template is None: template = 'pds4_template.xml' #open output config file fileConfig = open(outputConfig, 'w') print('writing {}'.format(outputConfig)) #Write first comment line theLine = '#{0} {1} {2}\n'.format(sys.argv[0], sys.argv[1], sys.argv[2]) fileConfig.write(theLine) #Next lines are not available in ISIS3 label theLine = '-co VAR_TARGET_TYPE=Satellite\n' fileConfig.write(theLine) theLine = '-co VAR_INVESTIGATION_AREA_LID_REFERENCE="urn:nasa:pds:context:instrument_host:spacecraft.lro"\n' fileConfig.write(theLine) try: target = getkey(from_=inputlbl, keyword='TargetName', grp='Mapping') theLine = '-co VAR_TARGET={}'.format(target) fileConfig.write(theLine) except KeyError: print('No Target in ISIS3 Label') try: mission = getkey(from_=inputlbl, keyword='InstrumentHostName', grp='Archive') theLine = '-co VAR_INVESTIGATION_AREA_NAME="{}"\n'.format(mission.rstrip()) fileConfig.write(theLine) except KeyError: print('No InstrumentHostName in ISIS3 Label') try: dataSetID = getkey(from_=inputlbl, keyword='DataSetId', grp='Archive') theLine = '-co VAR_LOGICAL_IDENTIFIER={}'.format(dataSetID) fileConfig.write(theLine) except KeyError: print('No DataSetId in ISIS3 Label') try: observeID = getkey(from_=inputlbl, keyword='InstrumentId', grp='Archive') theLine = '-co VAR_OBSERVING_SYSTEM_NAME={}'.format(observeID) fileConfig.write(theLine) except KeyError: print('No InstrumentId in ISIS3 Label') try: fileName = getkey(from_=inputlbl, keyword='ProductId', grp='Archive') theLine = '-co VAR_TITLE={}'.format(fileName) fileConfig.write(theLine) except KeyError: print('No ProductId in ISIS3 Label') fileConfig.close() #write out helper line for gdal - can run from here too outPDS4 = inputlbl.replace('.cub','_pds4.xml') theCmd='gdal_translate -of PDS4 -co IMAGE_FORMAT=GEOTIFF -co TEMPLATE={0} --optfile {1} {2} {3}'.format(template, outputConfig, inputlbl, outPDS4) if run is None: print('\nRecommended gdal run:') print('{}\n'.format(theCmd)) else: #run gdal os.system(theCmd)
def calibrate_ciss(img_name, ringdata=True, map_project=False): """ Calibrate raw Cassini ISS images using ISIS. ISIS is using an official released version the calibration routine `cisscal` that is being developed under IDL, but has been converted to C++ for ISIS. I am using the pipeline as described here: https://isis.astrogeology.usgs.gov/IsisWorkshop/index.php/Working_with_Cassini_ISS_Data It is customary to indicate the pipeline of ISIS apps that a file went through with a chain of extensions, e.g. '.cal.dst.map.cub', indicating calibration, destriping, and map projection. Parameters ---------- img_name : pathlib.Path, str Absolute path to image Returns ------- str : absolute path to map-projected ISIS cube. """ # Check if img_name is maybe a PathManager object with a `raw_label` attribute: try: img_name = str(img_name.raw_label) except AttributeError: # doesn't seem to be the case, so I assume it's just a path img_name = str(img_name) (cub_name, cal_name, dst_name, map_name) = file_variations(img_name, ['.cub', '.cal.cub', '.cal.dst.cub', '.cal.dst.map.cub']) ciss2isis(from_=img_name, to=cub_name) logging.info("Import to ISIS done.") targetname = getkey(from_=cub_name, grp='instrument', keyword='targetname') # forcing the target name to Saturn here, because some observations of # the rings have moons as a target, but then the standard map projection # onto the Saturn ring plane fails. # see also # https://isis.astrogeology.usgs.gov/IsisSupport/index.php/topic,3922.0.html if targetname.lower() != 'saturn': editlab(from_=cub_name, options='modkey', keyword='TargetName', value='Saturn', grpname='Instrument') # perform either normal spiceinit or one for ringdata if ringdata is True: spiceinit(from_=cub_name, cksmithed='yes', spksmithed='yes', shape='ringplane') else: spiceinit(from_=cub_name, cksmithed='yes', spksmithed='yes') logging.info("spiceinit done.") cisscal(from_=cub_name, to=cal_name, units='I/F') logging.info('cisscal done.') dstripe(from_=cal_name, to=dst_name, mode='horizontal') logging.info('Destriping done.') if map_project: ringscam2map(from_=dst_name, to=map_name, defaultrange='Camera', map=ISISDATA / 'base/templates/maps/ringcylindrical.map') isis2std(from_=map_name, to=map_name[:-3]+'tif', format='tiff') logging.info('Map projecting done. Function finished.') else: isis2std(from_=dst_name, to=dst_name[:-3]+'tif', format='tiff', minpercent=0, maxpercent=100) logging.warning('Map projection was skipped, set map_project to True if wanted.') return map_name