def SpecialProcessingFlags(cube: HiccdStitchCube): """Set the special processing flags in the ISIS label.""" status = "NOMINAL" if cube.hical_status == "BadCal": status = "BADCAL" if cube.cubenormstep: status = "CUBENORM" try: isis.getkey_k(cube.nextpath, "Instrument", "Special_Processing_Flag") option = "MODKEY" except subprocess.CalledProcessError: option = "ADDKEY" isis.editlab( cube.nextpath, option=option, grpname="Instrument", keyword="Special_Processing_Flag", value=status, )
def fix_labels(cubes: list, path: os.PathLike, matched_cube: str, prodid: str) -> None: isis.editlab( path, option="modkey", grpname="Archive", keyword="ProductId", value=prodid, ) isis.editlab( path, option="modkey", grpname="Instrument", keyword="MatchedCube", value=str(matched_cube), ) # Fix ck kernel in InstrumentPointing in RED label # This doesn't seem to be needed, maybe it was HiROC-specific. # Add SourceProductIds to Archive group in label logger.info("Original Perl just assumes that both channels are included " "in the balance cube.") source_ids = list() for c in cubes: source_ids.append( isis.getkey_k(c.path, "Instrument", "StitchedProductIds")) isis.editlab( path, option="ADDKEY", grpname="Archive", keyword="SourceProductId", value="({})".format(", ".join(source_ids)), ) return
def match_red(cubes: list, base_cube, flat_path, elargement_ratio=1.0006): """Prepare cubs for hijitreg by matching size and binning to center red ccds. """ # Where does the 1.0006 value for OPTICAL_ENLARGEMENT_RATIO come from? # Not sure. red4 = list(filter(lambda x: int(x.ccdnumber) == 4, cubes))[0] red5 = list(filter(lambda x: int(x.ccdnumber) == 5, cubes))[0] if red4.bin != red5.bin: raise ValueError("RED4 and RED5 binning not equal.") for c in cubes: bin_ratio = c.bin / base_cube.bin # Differences in field of view between color and red are corrected # for by multiplying bin ratio by pre-determined constant for BG and # dividing bin ratio by that constant for IR mag = bin_ratio if c.ccdname == "BG": mag = bin_ratio * elargement_ratio elif c.ccdname == "IR": mag = bin_ratio / elargement_ratio # scale cubes as needed if mag > 1: isis.enlarge( c.path, to=c.next_path, sscale=mag, lscale=bin_ratio, interp="BILINEAR", ) elif mag < 1: isis.reduce( c.path, to=c.next_path, sscale=1 / mag, lscale=bin_ratio, mode="SCALE", ) else: shutil.copy(c.path, c.next_path) if c.ccdname != "RED": offset = int( (200 * (c.bin - base_cube.bin) + c.tdi - base_cube.tdi) / base_cube.bin ) mos_path = c.next_path.with_suffix(".mosaiced.cub") isis.handmos( c.next_path, mosaic=mos_path, create="Y", nlines=base_cube.lines, nsamples=base_cube.samps, nbands=1, outline=offset, outsamp=1, outband=1, ) shutil.move(mos_path, c.next_path) if bin_ratio != 1: isis.editlab( c.next_path, options="MODKEY", grpname="INSTRUMENT", KEYWORD="SUMMING", value=base_cube.bin, ) # This section creates flat.tabs for RED4-RED5 pair only rows = int(red5.lines / 50) isis.hijitreg( red4.next_path, match=red5.next_path, row=rows, flat=flat_path ) return
def make_dummy_IR(red: hicolor.HiColorCube, bg: hicolor.HiColorCube): bg_slither_path = get_slither_path(bg) ir_name = bg_slither_path.name.replace(bg.get_ccd(), "IR" + str(int(bg.ccdnumber) - 2)) ir_path = bg_slither_path.parent / ir_name if ir_path.exists(): raise FileExistsError("{} exists ".format(str(ir_path)) + "and we don't want to overwrite it.") ir_ccd = "IR" + str(int(red.ccdnumber) + 6) isis.mask(red.path, mask=red.path, to=ir_path, preserve="outside") isis.editlab( ir_path, options="modkey", grpname="Instrument", keyword="CpmmNumber", value=int(red.ccdnumber) + 2, ) isis.editlab( ir_path, options="modkey", grpname="Instrument", keyword="CcdId", value=ir_ccd, ) isis.editlab( ir_path, options="modkey", grpname="Archive", keyword="ProductID", value="{}_{}".format(red.get_obsid(), ir_ccd), ) isis.editlab( ir_path, options="modkey", grpname="BandBin", keyword="Name", value="NearInfrared", ) isis.editlab( ir_path, options="modkey", grpname="BandBin", keyword="Center", value=900, units="NANOMETERS", ) isis.editlab( ir_path, options="modkey", grpname="BandBin", keyword="Width", value=200, units="NANOMETERS", ) return ir_path
def HiNoProj(cubes: list, conf: dict, output="_RED.NOPROJ.cub", base=5, keep=False): logger.info(f"HiNoProj start: {', '.join(map(str, cubes))}") cubes = list(map(Cube, cubes)) cubes.sort() if not all(c.ccdname == "RED" for c in cubes): raise ValueError("Not all of the input files are RED CCD files.") sequences = list() for k, g in itertools.groupby( (int(c.ccdnumber) for c in cubes), lambda x, c=itertools.count(): next(c) - x, ): sequences.append(list(g)) if len(sequences) != 1: raise ValueError("The given cubes are not a single run of sequential " "HiRISE CCDs, instead there are " f"{len(sequences)} groups with these " f"CCD numbers: {sequences}.") if not isinstance(base, int): base = hirise.get_CCDID_fromfile(base) base_ccd = list(filter(lambda x: x.ccdnumber == str(base), cubes)) if len(base_ccd) != 1: raise ValueError(f"The base ccd, number {base}, " "is not one of the given cubes.") base_cube = base_ccd[0] conf_check(conf["HiNoProj"]) conf = conf["HiNoProj"] out_p = hcn.set_outpath(output, cubes) temp_token = datetime.now().strftime("HiNoProj-%y%m%d%H%M%S") to_del = isis.PathSet() polar = False if conf["Shape"] == "USER": polar = is_polar(cubes, conf["Pole_Tolerance"], temp_token) for c in cubes: temp_p = to_del.add(c.path.with_suffix(f".{temp_token}.spiced.cub")) copy_and_spice(c.path, temp_p, conf, polar) isis.spicefit(temp_p) c.next_path = to_del.add( c.path.with_suffix(f".{temp_token}.noproj.cub")) c.path = temp_p for c in cubes: isis.noproj(c.path, match=base_cube.path, to=c.next_path, source="frommatch") # Run hijitreg on adjacent noproj'ed ccds to get average line/sample offset (cubes, _) = add_offsets(cubes, int(base_cube.ccdnumber), temp_token, keep=keep) # Mosaic noproj'ed ccds using average line/sample offset shutil.copyfile(base_cube.next_path, out_p) logger.info("Original Perl hard codes this file copy from RED5, even if " "another cube is selected as the base_ccd.") handmos_side(cubes, base_cube, out_p, left=True) handmos_side(cubes, base_cube, out_p, left=False) isis.editlab( out_p, option="addkey", grpname="Instrument", keyword="ImageJitterCorrected", value=0, ) fix_labels( cubes, out_p, base_cube, "{}_{}".format(str(cubes[0].get_obsid()), cubes[0].ccdname), ) if not keep: to_del.unlink() logger.info(f"HiNoProj done: {out_p}") return
def HiBeautify(cube_paths: list, conf: dict, out_irb="_IRB.cub", out_rgb="_RGB.cub", keep=False): logger.info(f"HiBeautify start: {', '.join(map(str, cube_paths))}") # GetConfigurationParameters() cubes = list(map(hcn.ColorCube, cube_paths)) cubes.sort() irb_out_p = hcn.set_outpath(out_irb, cubes) rgb_out_p = hcn.set_outpath(out_rgb, cubes) temp_token = datetime.now().strftime("HiBeautify-%y%m%d%H%M%S") to_del = isis.PathSet() # Create an IRB mosaic from the HiColorNorm halves. # If a half is missing, we create a mosaic with the proper width and place # the half in it at the proper location. # Logic ofr image_midpoint and total_width come from original HiColorInit # irbmerged_p = to_del.add(out_p.with_suffix(f'.{temp_token}_IRB.cub')) image_midpoint = int((2000 / cubes[0].red_bin) + 1) outsample = image_midpoint if cubes[0].ccdnumber == "4": outsample = 1 total_width = int(2 * cubes[0].samps - (48 / cubes[0].red_bin)) isis.handmos( cubes[0].path, mosaic=irb_out_p, outline=1, outsample=outsample, outband=1, create="Y", nlines=cubes[0].lines, nsamp=total_width, nbands=3, ) if len(cubes) == 1: logger.info("Warning, missing one half!") else: logger.info("Using both halves") isis.handmos( cubes[1].path, mosaic=irb_out_p, outline=1, outsample=image_midpoint, outband=1, ) # Nothing is actually done to the pixels here regarding the FrostStats, so # I'm just going to skip them here. # # # Determine if Frost/ICE may be present using FrostStats module. # frost = None # if args.frost: # frost = True # logging.info('Frost override: disabling auto-detection and using ' # 'the frost/ice color stretch') # if args.nofrost: # frost = False # logging.info('Frost override: disable auto-detection and not using ' # 'the frost/ice color stretch') # if frost is None: # pass # # get frost stats # Subtract the unaltered RED band from the high pass filtered BG for # synthetic blue. logger.info("Creating synthetic B, subtracting RED from BG") rgbsynthb_p = to_del.add(irb_out_p.with_suffix(f".{temp_token}_B.cub")) isis.algebra( f"{irb_out_p}+3", from2=f"{irb_out_p}+2", op="subtract", to=rgbsynthb_p, A=conf["Beautify"]["Synthetic_A_Coefficient"], B=conf["Beautify"]["Synthetic_B_Coefficient"], ) # Adjust the BandBin group isis.editlab(rgbsynthb_p, grpname="BandBin", keyword="Name", value="Synthetic Blue") isis.editlab(rgbsynthb_p, grpname="BandBin", keyword="Center", value="0") isis.editlab(rgbsynthb_p, grpname="BandBin", keyword="Width", value="0") # HiBeautify gathers and writes a bunch of statistics to PVL that is # important to the HiRISE GDS, but not relevant to just producing pixels # so I'm omitting it. # # # Determine the min and max DN values of each band (RED, IR, BG, B) we're # # working with. # (upper, lower) = conf['Beautify']['Stretch_Exclude_Lines'] # if upper == 0 and lower == 0: # synthbcrp_p = rgbsynthb_p # irbmrgcrp_p = irbmerged_p # else: # synthbcrp_p = to_del.add( # out_p.with_suffix(f'.{temp_token}_Bx.cub')) # irbmrgcrp_p = to_del.add( # out_p.with_suffix(f'.{temp_token}_IRBx.cub')) # # for (f, t) in ((rgbsynthb_p, synthbcrp_p), # (irbmerged_p, irbmrgcrp_p)): # logging.info(isis.crop(f, to=t, propspice=False, # line=(1 + upper), # nlines=( # cubes[0].lines - lower + upper)).args) # # stats = dict() # stats['B'] = Get_MinMax(synthbcrp_p, # conf['Beautify']['Stretch_Reduction_Factor'], # temp_token, keep=keep) # # for band in cubes[0].band.keys(): # stats[band] = Get_MinMax('{}+{}'.format(str(irbmrgcrp_p), # cubes[0].band[band]), # conf['Beautify']['Stretch_Reduction_Factor'], # temp_token, keep=keep) # Create an RGB cube using the RED from the IRB mosaic, # the BG from the IRB mosaic and the synthetic B that we just made. isis.cubeit_k([f"{irb_out_p}+2", f"{irb_out_p}+3", rgbsynthb_p], to=rgb_out_p) if not keep: to_del.unlink() return
def process_set( red: HiColorCube, ir: HiColorCube, bg: HiColorCube, outsuffix: str, keep=False, ): """Do all of the scaling and cropping for a RED/IR/BG set.""" if (len( set( map( lambda c: c.get_obsid(), filter(lambda x: x is not None, [red, ir, bg]), ))) != 1): raise ValueError("These cube files don't all have the same " f"Observation ID: {red}, {ir}, {bg}") temp_token = datetime.now().strftime("HiColorInit-%y%m%d%H%M%S") # These two values are calculated but only written to a PVL file, # which I think we can skip. # # in bin1 there are 48 pixels of overlap # total_width = 2 * red.samps - (48 / red.bin) # # # in bin1, the right half starts at pixel 2001 # image_midpoint = 2000 / red.bin + 1 for c in filter(lambda x: x is not None, [ir, bg]): # Calculate delta offset in lines between red and color ccd offset = int((200 * (c.bin - red.bin) + c.tdi - red.tdi) / red.bin) bin_ratio = c.bin / red.bin # tdi_ratio = c.tdi / red.tdi mag_ratio = bin_ratio / 1.0006 # ratio of color to red for enlargement, correction of optical # distortion from OPTICAL_ENLARGEMENT_RATIO constant in original # HiColor.pm # Rescale the color by the bin ratio and mag ratio, to match the red. # These will be the BG and IR "pre-color" cubes. rescaled = c.path.with_suffix(f".{temp_token}.rescaled" + outsuffix) if mag_ratio < 1: s = 1 / mag_ratio isis.reduce( c.path, to=rescaled, sscale=s, lscale=bin_ratio, validper=1, algorithm="nearest", vper_replace="nearest", ) else: isis.enlarge( c.path, to=rescaled, sscale=mag_ratio, lscale=bin_ratio, interp="bilinear", ) # The original Perl had an additional step to divide c.bin by the # bin_ratio, and provide that to value= below, but that's # mathematically just red.bin, so we'll skip a calculation: isis.editlab( rescaled, options="modkey", grpname="Instrument", keyword="Summing", value=red.bin, ) # trim by placing in a new image isis.handmos( rescaled, mosaic=c.path.with_suffix(outsuffix), create="Y", nlines=red.lines, nsamp=red.samps, nband=1, outline=offset, outsamp=1, outband=1, ) if not keep: rescaled.unlink() logger.info(f"Created {c.path.with_suffix(outsuffix)}") return