def main(): try: try: usage = "usage: cam2map4stereo.py [--help][--manual][--map mapfile][--pixres CAMERA|MAP|MPP|PPD][--resolution float][--interp NN|BI|CC][--lat min:max][--lon min:max][--prefix string] [--suffix string] image1.cub image2.cub\n" + get_asp_version( ) parser = optparse.OptionParser(usage=usage) parser.set_defaults(dryrun=False) parser.set_defaults(pixres='MPP') parser.set_defaults(prefix='') parser.set_defaults(suffix='map') parser.add_option("--manual", action="callback", callback=man, help="Read the manual.") parser.add_option("-m", "--map", dest="map", help="The mapfile to use for cam2map.") parser.add_option( "-p", "--pixres", dest="pixres", help="The pixel resolution mode to use for cam2map.") parser.add_option("-r", "--resolution", dest="resolution", help="Resolution of final map for cam2map.") parser.add_option("-i", "--interp", dest="interp", help="Pixel interpolation scheme for cam2map.") parser.add_option( "-a", "--lat", dest="lat", help="Latitude range for cam2map where LAT is minlat:maxlat.") parser.add_option( "-o", "--lon", dest="lon", help="Longitude range for cam2map where LON is minlon:maxlon.") parser.add_option( "--prefix", dest="prefix", help= "Make all output files use this prefix. Default: no prefix.") parser.add_option( "-s", "--suffix", dest="suffix", help="Suffix that gets inserted in the output file names.") parser.add_option( "-n", "--dry-run", dest="dryrun", action="store_true", help= "Make calculations, but print cam2map command, but don't actually run it." ) (options, args) = parser.parse_args() if not args: parser.error("need .cub files") except optparse.OptionError as msg: raise Usage(msg) # Call camrange to get bounds. If the lon bounds come as [0, 360] then try a different group. success = False lonGroupNames = [ 'UniversalGroundRange', 'PositiveEast180', 'PositiveWest180', 'PositiveWest360' ] for lonGroupName in lonGroupNames: image1 = camrange(args[0], lonGroupName, options) image2 = camrange(args[1], lonGroupName, options) lonRange = float(max(image1.maxlon, image2.maxlon)) - \ float(min(image1.minlon, image2.minlon)) if lonRange >= 360.0: print("With lonGroupName = " + lonGroupName + " found a longitude range of " + \ str(lonRange) + ". Will try the next group from: " + (" ".join(lonGroupNames))) else: success = True break if not success: raise Exception( 'ProcessError', 'The longitude range keeps on coming as encompasing the entire planet. Something is wrong.' ) mapout = ImgInfo() mapout.minlat = max(image1.minlat, image2.minlat) mapout.maxlat = min(image1.maxlat, image2.maxlat) mapout.minlon = max(image1.minlon, image2.minlon) mapout.maxlon = min(image1.maxlon, image2.maxlon) mapout.resolution = max(image1.resolution, image2.resolution) if (options.resolution): mapout.resolution = options.resolution if (options.lat): latrange = options.lat.split(':') if latrange[0]: mapout.minlat = latrange[0] if latrange[1]: mapout.maxlat = latrange[1] if (options.lon): lonrange = options.lon.split(':') if lonrange[0]: mapout.minlon = lonrange[0] if lonrange[1]: mapout.maxlon = lonrange[1] # call cam2map with the arguments cam2map = [ 'cam2map', 'from=' + args[0], 'to=' + mapfile(args[0], options.prefix, options.suffix) ] if (options.map): cam2map.append('map=' + options.map) if (options.interp): cam2map.append('interp=' + options.interp) cam2map.append('pixres=' + options.pixres) cam2map.append('resolution=' + mapout.resolution) cam2map.append('defaultrange=MAP') cam2map.append('minlat=' + mapout.minlat) cam2map.append('maxlat=' + mapout.maxlat) cam2map.append('minlon=' + mapout.minlon) cam2map.append('maxlon=' + mapout.maxlon) # Run for first image # Need to put these together to keep ISIS from calling the GUI cam2map_cmd = ' '.join(cam2map) print(cam2map_cmd) if (not options.dryrun): code = subprocess.call(cam2map_cmd, shell=True) if not code == 0: raise Exception('ProcessError', 'Non zero return code (' + str(code) + ')') # Run for second image cam2map[1] = 'from=' + args[1] cam2map[2] = 'to=' + mapfile(args[1], options.prefix, options.suffix) cam2map_cmd = ' '.join(cam2map) print(cam2map_cmd) if (not options.dryrun): code = subprocess.call(cam2map_cmd, shell=True) if not code == 0: raise Exception('ProcessError', 'Non zero return code (' + str(code) + ')') print("Finished") return 0 except Usage as err: print(err.msg, file=sys.stderr) # print >>sys.stderr, "for help use --help" return 2 except MapExists as e: print('The file ' + e.msg + ' already exists, delete first.', file=sys.stderr) return 3
def main(): try: try: usage = "usage: hiedr2mosaic.py [--help][--manual][--threads N][--keep][-m match] HiRISE-EDR.IMG-files\n " + get_asp_version() parser = optparse.OptionParser(usage=usage) parser.set_defaults(delete=True) parser.set_defaults(match=5) parser.set_defaults(threads=4) parser.add_option("--manual", action="callback", callback=man, help="Read the manual.") parser.add_option("--stop-at-no-proj", dest="stop_no_proj", action="store_true", help="Process the IMG files only to have SPICE attached. This allows jigsaw to happen") parser.add_option("--resume-at-no-proj", dest="resume_no_proj", action="store_true", help="Pick back up after spiceinit has happened or jigsaw. This was noproj uses your new camera information") parser.add_option("-t", "--threads", dest="threads", help="Number of threads to use.",type="int") parser.add_option("-m", "--match", dest="match",type="int", help="CCD number of match CCD, passed as the match argument to noproj (default 5).") parser.add_option("-k", "--keep", action="store_false", dest="delete", help="Will not delete intermediate files.") parser.add_option("--download-folder", dest="download_folder", default=None, help="Download files to this folder. Hence the second argument to this is the URL of the page to download the files from.") (options, args) = parser.parse_args() if not args: parser.error("need .IMG files or a URL") if options.download_folder: print ('Downloading HiRISE images from URL...') # For now we only fetch RED images. args = fetch_files(args[0], options.download_folder, image_type='RED') print ('Finished downloading ' + str(len(args)) + ' images.') # Verify that we have both of the specified match CCD's. # This is applicable only when we start with initial IMG files. if not options.resume_no_proj: matchCount = 0 for a in args: if get_ccd(a) == options.match: matchCount += 1 if matchCount != 2: print ('Error: Found ' + str(matchCount) + ' files for match CCD ' + str(options.match) + ' instead of 2.') return -1 numCcds = len(args) / 2 except optparse.OptionError as msg: raise Usage(msg) if not options.resume_no_proj: # hi2isis hi2isised = hi2isis( args, options.threads ) # hical hicaled = hical( hi2isised, options.threads, options.delete ) # histitch histitched = histitch( hicaled, options.threads, options.delete ) # attach spice spice( histitched, options.threads ) if options.stop_no_proj: print("Finished") return 0 if options.resume_no_proj: histitched = args CCD_files = CCDs( histitched, options.match ) # noproj noprojed_CCDs = noproj( CCD_files, options.threads, options.delete ) # hijitreg averages = hijitreg( noprojed_CCDs, options.threads, options.delete ) # mosaic handmos mosaicked = mosaic( noprojed_CCDs, averages ) # Clean up noproj files if options.delete: for cub in noprojed_CCDs.values(): os.remove( cub ) # Run a final cubenorm across the image: cubenorm( mosaicked, options.delete ) print("Finished") return 0 except Usage as err: print (err.msg, file = sys.stderr) return 2
def main(): try: try: usage = "usage: lronac2mosaic.py [--help][--manual][--crop][--threads N]" \ "[--keep] LRONAC.IMG-files\n " + get_asp_version() parser = optparse.OptionParser(usage=usage) parser.set_defaults(delete=True) parser.set_defaults(cropAmount=0) parser.set_defaults(threads=4) parser.set_defaults(fakePvl=True) parser.add_option("--manual", action="callback", callback=man, help="Read the manual.") parser.add_option("-o", "--output-dir", dest="outputFolder", help="Output folder (default to input folder).", type="string") parser.add_option( "--stop-at-no-proj", dest="stop_no_proj", action="store_true", help="Process the IMG files only to have SPICE attached.") parser.add_option( "--resume-at-no-proj", dest="resume_no_proj", action="store_true", help= "Pick back up after spiceinit has happened. This was noproj uses your new camera information" ) parser.add_option( "-c", "--crop", dest="cropAmount", help="Process only the first N lines of the image.", type="int") parser.add_option("-t", "--threads", dest="threads", help="Number of threads to use.", type="int") parser.add_option("-k", "--keep", action="store_false", dest="delete", help="Will not delete intermediate files.") parser.add_option( "--p", dest="fakePvl", action="store_true", help="Don't automatically create a LRONAC pvl file") (options, args) = parser.parse_args() if not args: parser.error("need .IMG files") except optparse.OptionError as msg: raise Usage(msg) # Make sure only one pair of cubes was passed in input_file_pair = build_cube_pairs(args) if len(input_file_pair) > 1: raise Usage( 'Input error: Only one pair of input files are allowed!') if not options.outputFolder: # Set the output folder equal to the input folder options.outputFolder = os.path.dirname(args[0]) print('Using output folder: ' + options.outputFolder) if not os.path.exists( options.outputFolder) and len(options.outputFolder) > 1: os.makedirs(options.outputFolder) print("Beginning processing.....") if not options.resume_no_proj: # If not skipping to later point print( "lronac2isis") # Per-file operation, returns list of new files lronac2isised = lronac2isis(args, options.threads, options.outputFolder) print("lronaccal") # Per-file operation, returns list of new files lronaccaled = lronaccal(lronac2isised, options.threads, options.delete) print( "lronacecho") # Per-file operation, returns list of new files lronacechod = lronacecho(lronaccaled, options.threads, options.delete) if (options.cropAmount > 0): # Crop the input files as soon as ISIS calls allow it lronacechod = cropInputs(lronacechod, options.outputFolder, options.cropAmount, options.threads, options.delete) print( "spice") # Attach spice info to cubes (adds to existing files) spice(lronacechod, options.threads) if options.stop_no_proj: # Stop early if requested print("Finished") return 0 if options.resume_no_proj: # If resume option was set lronacechod = args print("build_cube_pairs") # Detected corresponding pairs of cubes lronac_file_pairs = build_cube_pairs(lronacechod) print("noproj") # Per-file operation noprojed_file_pairs = noproj(lronac_file_pairs, options.threads, options.delete, options.fakePvl, options.outputFolder) print("lronacjitreg") # Determines mean shift for each file pair averages = lronacjitreg(noprojed_file_pairs, options.threads, options.delete) print("mosaic") # handmos - Use mean shifts to combine the file pairs mosaicked = mosaic(noprojed_file_pairs, averages, options.threads) # Clean up noproj files if (options.delete): for cub in noprojed_file_pairs.values(): os.remove(cub[0]) os.remove(cub[1]) # Run a final cubenorm across the image: cubenorm(mosaicked, options.threads, options.delete) print("Finished") return 0 except Usage as err: print >> sys.stderr, err.msg return 2
def main(): try: try: usage = "usage: lronac2mosaic.py [--help][--manual][--crop][--threads N]" \ "[--keep] LRONAC.IMG-files\n " + get_asp_version() parser = optparse.OptionParser(usage=usage) parser.set_defaults(delete =True) parser.set_defaults(cropAmount=0) parser.set_defaults(threads=4) parser.set_defaults(fakePvl=True) parser.add_option("--manual", action="callback", callback=man, help="Read the manual.") parser.add_option("-o", "--output-dir", dest="outputFolder", help="Output folder (default to input folder).",type="string") parser.add_option("--stop-at-no-proj", dest="stop_no_proj", action="store_true", help="Process the IMG files only to have SPICE attached.") parser.add_option("--resume-at-no-proj", dest="resume_no_proj", action="store_true", help="Pick back up after spiceinit has happened. This was noproj uses your new camera information") parser.add_option("-c", "--crop", dest="cropAmount", help="Process only the first N lines of the image.",type="int") parser.add_option("-t", "--threads", dest="threads", help="Number of threads to use.",type="int") parser.add_option("-k", "--keep", action="store_false", dest="delete", help="Will not delete intermediate files.") parser.add_option("--p", dest="fakePvl", action="store_true", help="Don't automatically create a LRONAC pvl file") (options, args) = parser.parse_args() if not args: parser.error("need .IMG files") except optparse.OptionError as msg: raise Usage(msg) # Make sure only one pair of cubes was passed in input_file_pair = build_cube_pairs( args ) if len(input_file_pair) > 1: raise Usage('Input error: Only one pair of input files are allowed!') if not options.outputFolder: # Set the output folder equal to the input folder options.outputFolder = os.path.dirname(args[0]) print('Using output folder: ' + options.outputFolder) if not os.path.exists(options.outputFolder) and len(options.outputFolder) > 1: os.makedirs(options.outputFolder) print("Beginning processing.....") if not options.resume_no_proj: # If not skipping to later point print("lronac2isis") # Per-file operation, returns list of new files lronac2isised = lronac2isis( args, options.threads, options.outputFolder ) print("lronaccal") # Per-file operation, returns list of new files lronaccaled = lronaccal( lronac2isised, options.threads, options.delete ) print("lronacecho") # Per-file operation, returns list of new files lronacechod = lronacecho( lronaccaled, options.threads, options.delete ) if (options.cropAmount > 0): # Crop the input files as soon as ISIS calls allow it lronacechod = cropInputs(lronacechod, options.outputFolder, options.cropAmount, options.threads, options.delete) print("spice") # Attach spice info to cubes (adds to existing files) spice( lronacechod, options.threads ) if options.stop_no_proj: # Stop early if requested print("Finished") return 0 if options.resume_no_proj: # If resume option was set lronacechod = args print("build_cube_pairs") # Detected corresponding pairs of cubes lronac_file_pairs = build_cube_pairs( lronacechod ) print("noproj") # Per-file operation noprojed_file_pairs = noproj( lronac_file_pairs, options.threads, options.delete, options.fakePvl, options.outputFolder) print("lronacjitreg") # Determines mean shift for each file pair averages = lronacjitreg( noprojed_file_pairs, options.threads, options.delete ) print("mosaic") # handmos - Use mean shifts to combine the file pairs mosaicked = mosaic( noprojed_file_pairs, averages, options.threads ) # Clean up noproj files if( options.delete ): for cub in noprojed_file_pairs.values(): os.remove( cub[0] ) os.remove( cub[1] ) # Run a final cubenorm across the image: cubenorm( mosaicked, options.threads, options.delete ) print("Finished") return 0 except Usage as err: print(err.msg, file=sys.stderr) return 2
def main(): try: try: usage = "usage: cam2map4stereo.py [--help][--manual][--map mapfile][--pixres CAMERA|MAP|MPP|PPD][--resolution float][--interp NN|BI|CC][--lat min:max][--lon min:max][--prefix string] [--suffix string] image1.cub image2.cub\n" + get_asp_version() parser = optparse.OptionParser(usage=usage) parser.set_defaults(dryrun=False) parser.set_defaults(pixres='MPP') parser.set_defaults(prefix='') parser.set_defaults(suffix='map') parser.add_option("--manual", action="callback", callback=man, help="Read the manual.") parser.add_option("-m", "--map", dest="map", help="The mapfile to use for cam2map.") parser.add_option("-p", "--pixres", dest="pixres", help="The pixel resolution mode to use for cam2map.") parser.add_option("-r", "--resolution", dest="resolution", help="Resolution of final map for cam2map.") parser.add_option("-i", "--interp", dest="interp", help="Pixel interpolation scheme for cam2map.") parser.add_option("-a", "--lat", dest="lat", help="Latitude range for cam2map where LAT is minlat:maxlat.") parser.add_option("-o", "--lon", dest="lon", help="Longitude range for cam2map where LON is minlon:maxlon.") parser.add_option("--prefix", dest="prefix", help="Make all output files use this prefix. Default: no prefix.") parser.add_option("-s", "--suffix", dest="suffix", help="Suffix that gets inserted in the output file names.") parser.add_option("-n", "--dry-run", dest="dryrun", action="store_true", help="Make calculations, but print cam2map command, but don't actually run it.") (options, args) = parser.parse_args() if not args: parser.error("need .cub files") except optparse.OptionError as msg: raise Usage(msg) # Call camrange to get bounds. If the lon bounds come as [0, 360] then try a different group. success = False lonGroupNames = ['UniversalGroundRange', 'PositiveEast180', 'PositiveWest180', 'PositiveWest360'] for lonGroupName in lonGroupNames: image1 = camrange( args[0], lonGroupName, options) image2 = camrange( args[1], lonGroupName, options) lonRange = float(max(image1.maxlon, image2.maxlon)) - \ float(min(image1.minlon, image2.minlon)) if lonRange >= 360.0: print("With lonGroupName = " + lonGroupName + " found a longitude range of " + \ str(lonRange) + ". Will try the next group from: " + (" ".join(lonGroupNames))) else: success = True break if not success: raise Exception('ProcessError', 'The longitude range keeps on coming as encompasing the entire planet. Something is wrong.') mapout = ImgInfo() mapout.minlat = max( image1.minlat, image2.minlat ) mapout.maxlat = min( image1.maxlat, image2.maxlat ) mapout.minlon = max( image1.minlon, image2.minlon ) mapout.maxlon = min( image1.maxlon, image2.maxlon ) mapout.resolution = max( image1.resolution, image2.resolution ) if( options.resolution ): mapout.resolution = options.resolution if( options.lat ): latrange = options.lat.split(':') if latrange[0]: mapout.minlat = latrange[0] if latrange[1]: mapout.maxlat = latrange[1] if( options.lon ): lonrange = options.lon.split(':') if lonrange[0]: mapout.minlon = lonrange[0] if lonrange[1]: mapout.maxlon = lonrange[1] # call cam2map with the arguments cam2map = ['cam2map', 'from=' + args[0], 'to=' + mapfile( args[0], options.prefix, options.suffix )] if( options.map ): cam2map.append( 'map=' + options.map ) if( options.interp): cam2map.append( 'interp=' + options.interp) cam2map.append( 'pixres=' + options.pixres ) cam2map.append( 'resolution=' + mapout.resolution ) cam2map.append( 'defaultrange=MAP' ) cam2map.append( 'minlat=' + mapout.minlat ) cam2map.append( 'maxlat=' + mapout.maxlat ) cam2map.append( 'minlon=' + mapout.minlon ) cam2map.append( 'maxlon=' + mapout.maxlon ) # Run for first image # Need to put these together to keep ISIS from calling the GUI cam2map_cmd = ' '.join(cam2map) print(cam2map_cmd) if( not options.dryrun ): code = subprocess.call(cam2map_cmd, shell=True) if not code == 0: raise Exception('ProcessError', 'Non zero return code ('+str(code)+')') # Run for second image cam2map[1] = 'from=' + args[1] cam2map[2] = 'to='+ mapfile( args[1], options.prefix, options.suffix ) cam2map_cmd = ' '.join(cam2map) print(cam2map_cmd) if( not options.dryrun ): code = subprocess.call(cam2map_cmd, shell=True) if not code == 0: raise Exception('ProcessError', 'Non zero return code ('+str(code)+')') print("Finished") return 0 except Usage as err: print (err.msg, file=sys.stderr) return 2 except MapExists as e: print ('The file '+ e.msg +' already exists, delete first.', file=sys.stderr) return 3
def main(): try: try: usage = "usage: hiedr2mosaic.py [--help][--manual][--threads N][--keep][-m match] HiRISE-EDR.IMG-files\n " + get_asp_version( ) parser = optparse.OptionParser(usage=usage) parser.set_defaults(delete=True) parser.set_defaults(match=5) parser.set_defaults(threads=4) parser.add_option("--manual", action="callback", callback=man, help="Read the manual.") parser.add_option( "--stop-at-no-proj", dest="stop_no_proj", action="store_true", help= "Process the IMG files only to have SPICE attached. This allows jigsaw to happen" ) parser.add_option( "--resume-at-no-proj", dest="resume_no_proj", action="store_true", help= "Pick back up after spiceinit has happened or jigsaw. This was noproj uses your new camera information" ) parser.add_option("-t", "--threads", dest="threads", help="Number of threads to use.", type="int") parser.add_option("-m", "--match", dest="match", help="CCD number of match CCD") parser.add_option("-k", "--keep", action="store_false", dest="delete", help="Will not delete intermediate files.") (options, args) = parser.parse_args() if not args: parser.error("need .IMG files") # Make sure there is a valid match CCD if len(args) % 2 != 0: raise Exception( 'An even number of input CCD files is required!') numCcds = len(args) / 2 if options.match >= numCcds: print 'Warning: match argument is greater than number of input CCDs, forcing it lower!' options.match = numCcds - 1 except optparse.OptionError as msg: raise Usage(msg) # # Determine Isis Version # post_isis_20 = is_post_isis_3_1_20(); isisversion(True) if not options.resume_no_proj: # hi2isis hi2isised = hi2isis(args, options.threads) # hical hicaled = hical(hi2isised, options.threads, options.delete) # histitch histitched = histitch(hicaled, options.threads, options.delete) # attach spice spice(histitched, options.threads) if options.stop_no_proj: print("Finished") return 0 if options.resume_no_proj: histitched = args CCD_files = CCDs(histitched, options.match) # noproj noprojed_CCDs = noproj(CCD_files, options.threads, options.delete) # hijitreg averages = hijitreg(noprojed_CCDs, options.threads) # mosaic handmos mosaicked = mosaic(noprojed_CCDs, averages) # Clean up noproj files if (options.delete): for cub in noprojed_CCDs.values(): os.remove(cub) # Run a final cubenorm across the image: cubenorm(mosaicked, options.delete) print("Finished") return 0 except Usage as err: print >> sys.stderr, err.msg # print >>sys.stderr, "for help use --help" return 2
def main(): try: try: usage = "usage: hiedr2mosaic.py [--help][--manual][--threads N][--keep][-m match] HiRISE-EDR.IMG-files\n " + get_asp_version() parser = optparse.OptionParser(usage=usage) parser.set_defaults(delete=True) parser.set_defaults(match=5) parser.set_defaults(threads=4) parser.add_option("--manual", action="callback", callback=man, help="Read the manual.") parser.add_option("--stop-at-no-proj", dest="stop_no_proj", action="store_true", help="Process the IMG files only to have SPICE attached. This allows jigsaw to happen") parser.add_option("--resume-at-no-proj", dest="resume_no_proj", action="store_true", help="Pick back up after spiceinit has happened or jigsaw. This was noproj uses your new camera information") parser.add_option("-t", "--threads", dest="threads", help="Number of threads to use.",type="int") parser.add_option("-m", "--match", dest="match",type="int", help="CCD number of match CCD, passed as the match argument to noproj (default 5).") parser.add_option("-k", "--keep", action="store_false", dest="delete", help="Will not delete intermediate files.") parser.add_option("--download-folder", dest="download_folder", default=None, help="Download files to this folder. Hence the second argument to this is the URL of the page to download the files from.") (options, args) = parser.parse_args() if not args: parser.error("need .IMG files or a URL") if options.download_folder: print ('Downloading HiRISE images from URL...') # For now we only fetch RED images. args = fetch_files(args[0], options.download_folder, image_type='RED') print ('Finished downloading ' + str(len(args)) + ' images.') # Make sure there is a valid match CCD if len(args) % 2 != 0 and not options.resume_no_proj: raise Exception('An even number of input CCD files is required!') # Verify that we have both of the specified match CCD's. # This is applicable only when we start with initial IMG files. if not options.resume_no_proj: matchCount = 0 for a in args: if get_ccd(a) == options.match: matchCount += 1 if matchCount != 2: print ('Error: Found ' + str(matchCount) + ' files for match CCD ' + str(options.match) + ' instead of 2.') return -1 numCcds = len(args) / 2 except optparse.OptionError as msg: raise Usage(msg) # # Determine Isis Version # post_isis_20 = is_post_isis_3_1_20(); isisversion( True ) if not options.resume_no_proj: # hi2isis hi2isised = hi2isis( args, options.threads ) # hical hicaled = hical( hi2isised, options.threads, options.delete ) # histitch histitched = histitch( hicaled, options.threads, options.delete ) # attach spice spice( histitched, options.threads ) if options.stop_no_proj: print("Finished") return 0 if options.resume_no_proj: histitched = args CCD_files = CCDs( histitched, options.match ) # noproj noprojed_CCDs = noproj( CCD_files, options.threads, options.delete ) # hijitreg averages = hijitreg( noprojed_CCDs, options.threads ) # mosaic handmos mosaicked = mosaic( noprojed_CCDs, averages ) # Clean up noproj files if( options.delete ): for cub in noprojed_CCDs.values(): os.remove( cub ) # Run a final cubenorm across the image: cubenorm( mosaicked, options.delete ) print("Finished") return 0 except Usage as err: print (err.msg, file = sys.stderr) return 2