Пример #1
0
def make_unfiltered(in_path,
                    nrm_path,
                    temp_token,
                    color_code,
                    color_band,
                    keep=False):
    tt = f"{temp_token}_{color_code}"
    in_p = Path(in_path)
    unfiltered_p = in_p.with_name(
        in_p.name.replace("COLOR", "UNFILTERED_COLOR"))
    shutil.copyfile(in_p, unfiltered_p)
    # run ISIS algebra program to create unfiltered
    # (normalized-IR/RED)*RED files
    alg_unfiltered_path = in_p.with_suffix(f".{tt}.algebra.cub")
    isis.algebra(
        nrm_path,
        from2="{}+2".format(in_p),
        to=alg_unfiltered_path,
        operator="MULTIPLY",
    )
    # Update the output file with the non-filtered normalized IR and BG bands
    isis.handmos(
        alg_unfiltered_path,
        mosaic=unfiltered_p,
        outsample=1,
        outline=1,
        matchbandbin=False,
        outband=color_band,
    )
    if not keep:
        alg_unfiltered_path.unlink()
    return unfiltered_p
Пример #2
0
def make_balance(cube, conf, balance_path):
    a_param = None
    c_param = None
    if conf["HiccdStitch_Balance_Correction"] == "MULTIPLY":
        a_param = cube.correction
        c_param = 0
    elif conf["HiccdStitch_Balance_Correction"] == "ADD":
        a_param = 1
        c_param = cube.correction

    to_s = "{}+SignedWord+{}:{}".format(
        balance_path,
        conf["HiccdStitch_Normalization_Minimum"],
        conf["HiccdStitch_Normalization_Maximum"],
    )
    isis.algebra(cube.nextpath,
                 to=to_s,
                 operator="unary",
                 a=a_param,
                 c=c_param)
    logger.info(f"Created {balance_path}")
Пример #3
0
def subtract_over_thresh(
    in_path: Path, out_path: Path, thresh: int, delta: int, keep=False
):
    """This is a convenience function that runs ISIS programs to add or
    subtract a value to DN values for pixels that are above or below
    a threshold.

    For all pixels in the *in_path* ISIS cube, if *delta* is positive,
    then pixels with a value greater than *thresh* will have *delta*
    subtracted from them.  If *delta* is negative, then all pixels
    less than *thresh* will have *delta* added to them.
    """

    # Originally, I wanted to just do this simply with fx:
    # eqn = "\(f1 + ((f1{glt}={thresh}) * {(-1 * delta)}))"
    # However, fx writes out floating point pixel values, and we really
    # need to keep DNs as ints as long as possible.  Sigh.

    shutil.copyfile(in_path, out_path)

    mask_p = in_path.with_suffix(".threshmask.cub")
    mask_args = {"from": in_path, "to": mask_p}
    if delta > 0:
        mask_args["min"] = thresh
    else:
        mask_args["max"] = thresh
    isis.mask(**mask_args)

    delta_p = in_path.with_suffix(".delta.cub")
    isis.algebra(
        mask_p, from2=in_path, to=delta_p, op="add", a=0, c=(-1 * delta)
    )

    isis.handmos(delta_p, mosaic=out_path)

    if not keep:
        mask_p.unlink()
        delta_p.unlink()

    return
Пример #4
0
def HiFurrow_Fix(in_cube: os.PathLike,
                 out_cube: os.PathLike,
                 max_mean: float,
                 keep=False):
    """Perform a normalization of the furrow region of bin 2 or 4
    HiRISE images. The input to this script is a HiRISE stitch
    product containing both channels of a CCD.
    """
    in_cub = Path(in_cube)

    binning = int(isis.getkey_k(in_cub, "Instrument", "Summing"))
    lines = int(isis.getkey_k(in_cub, "Dimensions", "Lines"))
    samps = int(isis.getkey_k(in_cub, "Dimensions", "Samples"))

    if binning != 2 and binning != 4:
        raise ValueError("HiFurrow_Fix only supports correction for "
                         "bin 2 or 4 data.")
    if binning == 2 and samps != 1024:
        raise ValueError(f"HiFurrowFix: improper number of samples: {samps}, "
                         "for a stitch product with bin 2 (should be 1024).")

    # This string will get placed in the filename for all of our
    # temporary files. It will (hopefully) prevent collisions with
    # existing files and also allow for easy clean-up if keep=True
    temp_token = datetime.now().strftime("HFF-%y%m%d%H%M%S")
    to_del = isis.PathSet()

    # For bin2 and bin4 imaging, specify width of furrow based on
    # image average DN range
    range_low = {2: (512, 513), 4: (256, 257)}  # 2 pixel furrow width
    range_mid = {2: (511, 514), 4: (255, 258)}  # 4 pixel furrow width
    range_hgh = {2: (511, 514), 4: (255, 258)}  # 4 pixel furrow width
    range_max = {2: (510, 515), 4: (254, 259)}  # 6 pixel furrow width

    # Original code had low/mid/hgh for bin2 and bin4, but they
    # were hard-coded to be identical.
    dn_range_low = 9000
    dn_range_mid = 10000
    dn_range_hgh = 12000

    if max_mean > dn_range_hgh:
        dn_range = range_max[binning]
    elif max_mean > dn_range_mid:
        dn_range = range_hgh[binning]
    elif max_mean > dn_range_low:
        dn_range = range_mid[binning]
    else:
        dn_range = range_low[binning]

    lpf_samp = int((dn_range[1] - dn_range[0] + 1) / 2) * 4 + 1
    lpf_line = int(lpf_samp / 2) * 20 + 1

    # Create a mask file
    # DN=1 for non-furrow area
    # DN=0 for furrow area
    eqn = rf"\(1*(sample<{dn_range[0]})+ 1*(sample>{dn_range[1]}) + 0)"
    fx_cub = to_del.add(in_cub.with_suffix(f".{temp_token}.fx.cub"))
    isis.fx(to=fx_cub,
            mode="OUTPUTONLY",
            lines=lines,
            samples=samps,
            equation=eqn)

    # Create a file where the furrow area is set to null
    mask1_cub = to_del.add(in_cub.with_suffix(f".{temp_token}.mask1.cub"))
    isis.mask(
        in_cub,
        mask=fx_cub,
        to=mask1_cub,
        min_=1,
        max_=1,
        preserve="INSIDE",
        spixels="NULL",
    )

    # Lowpass filter to fill in the null pixel area
    lpf_cub = to_del.add(in_cub.with_suffix(f".{temp_token}.lpf.cub"))
    isis.lowpass(
        mask1_cub,
        to=lpf_cub,
        sample=lpf_samp,
        line=lpf_line,
        null=True,
        hrs=False,
        his=False,
        lis=False,
    )

    # Create a file where non-furrow columns are set to null
    mask2_cub = to_del.add(in_cub.with_suffix(f".{temp_token}.mask2.cub"))
    isis.mask(
        in_cub,
        mask=fx_cub,
        to=mask2_cub,
        min_=0,
        max_=0,
        preserve="INSIDE",
        spixels="NULL",
    )

    # Highpass filter the furrow region
    hpf_cub = to_del.add(in_cub.with_suffix(f".{temp_token}.hpf.cub"))
    isis.highpass(mask2_cub, to=hpf_cub, sample=1, line=lpf_line)

    # Add lowpass and highpass together to achieve desired result
    alg_cub = to_del.add(in_cub.with_suffix(f".{temp_token}.alg.cub"))
    isis.algebra(from_=lpf_cub,
                 from2=hpf_cub,
                 to=alg_cub,
                 operator="ADD",
                 A=1.0,
                 B=1.0)

    # copy the input file to the output file then mosaic the
    # furrow area as needed.
    logger.info(f"Copy {in_cub} to {out_cube}.")
    shutil.copyfile(in_cub, out_cube)
    isis.handmos(
        alg_cub,
        mosaic=out_cube,
        outsample=1,
        outline=1,
        outband=1,
        insample=1,
        inline=1,
        inband=1,
        create="NO",
    )

    if not keep:
        to_del.unlink()

    return
Пример #5
0
def per_band(cubes,
             out_p,
             temp_token,
             color_code,
             furrow_flag,
             unfiltered,
             keep=False) -> float:
    to_del = isis.PathSet()

    # Generate the handmos of both the ratio and the croped ratio files
    if len(cubes) == 2:
        maxlines = max(c.lines for c in cubes)
        maxsamps = sum(c.samps for c in cubes)

        # Generate the mosaic of the ratio image
        mos_p = to_del.add(
            out_p.with_suffix(f".{temp_token}.{color_code}.mos.cub"))
        make_LR_mosaic(
            cubes[0].mask_path[color_code],
            cubes[1].mask_path[color_code],
            cubes[0].samps,
            mos_p,
            maxlines,
            maxsamps,
        )

        # Generate the mosaic of the crop ratio image
        maxlines = max(c.crop_lines for c in cubes)
        crpmos_p = to_del.add(
            out_p.with_suffix(f".{temp_token}.{color_code}.moscrop.cub"))
        make_LR_mosaic(
            cubes[0].crop_path[color_code],
            cubes[1].crop_path[color_code],
            cubes[0].samps,
            crpmos_p,
            maxlines,
            maxsamps,
        )
    else:
        mos_p = cubes[0].mask_path[color_code]
        crpmos_p = cubes[0].crop_path[color_code]

    mosnrm_p = to_del.add(
        out_p.with_suffix(f".{temp_token}.{color_code}.mosnorm.cub"))
    ratio_stddev = cubenorm_stats(crpmos_p, mos_p, mosnrm_p, keep=keep)

    # from the handmos cubes, pull out the individual CCDs with crop
    if len(cubes) == 2:
        samp = 1
        for i, c in enumerate(cubes):
            cubes[i].nrm_path[color_code] = c.path.with_suffix(
                f".{temp_token}.{color_code}.norm.cub")
            isis.crop(
                mosnrm_p,
                to=cubes[i].nrm_path[color_code],
                sample=samp,
                nsamples=c.samps,
            )
            samp += c.samps
    else:
        # If there was only one file then all we need to do is rename files
        cubes[0].nrm_path[color_code] = mosnrm_p

    if unfiltered:
        # Create the unfiltered color cubes, if needed
        for c in cubes:
            make_unfiltered(
                c.path,
                c.nrm_path[color_code],
                temp_token,
                color_code,
                c.band[color_code],
                keep=keep,
            )

    # low pass filter the files
    for c in cubes:
        # If $lpfz=1 then we're only interpolating null pixels caused by
        # noise or furrow removal

        lowpass_args = dict(
            minopt="PERCENT",
            minimum=25,
            low=0.00,
            high=2.0,
            null=True,
            hrs=True,
            lis=True,
            lrs=True,
        )

        # As the comment below states, I *think* that the OP had a copy
        # and paste error here, because even though it kept track of both
        # the IR and BG boxcar dimensions, they were always identical.
        logger.warning("The original Perl calculates the boxcar size for "
                       "both the IR and BG based only on the ratio of the "
                       "IR to the RED.")
        if c.get_boxcar_size(c.ir_bin) == 1:
            lowpass_args["lines"] = 3
            lowpass_args["samples"] = 3
            lowpass_args["filter"] = "OUTSIDE"
        else:
            lowpass_args["lines"] = 1
            lowpass_args["samples"] = 1

        lpf_path = to_del.add(
            c.path.with_suffix(f".{temp_token}.{color_code}.lpf.cub"))
        isis.lowpass(c.nrm_path[color_code], to=lpf_path, **lowpass_args)

        # Perform lpfz filters to interpolate null pixels due to furrows or
        #   bad pixels
        if furrow_flag:
            lpfz_path = c.path.with_suffix(
                f".{temp_token}.{color_code}.lpfz.cub")
            lpfz_triplefilter(lpf_path, lpfz_path, temp_token, keep=keep)
        else:
            lpfz_path = lpf_path

        # run ISIS algebra program to created (normalized-IR/RED)*RED files
        alg_path = to_del.add(
            c.path.with_suffix(f".{temp_token}.{color_code}.algebra.cub"))
        isis.algebra(lpfz_path,
                     from2=f"{c.path}+2",
                     to=alg_path,
                     operator="MULTIPLY")

        # Update the output file with the normalized IR and BG bands
        isis.handmos(
            alg_path,
            mosaic=c.final_path,
            outsample=1,
            outline=1,
            outband=c.band[color_code],
            matchbandbin=False,
        )

    if not keep:
        to_del.unlink()

    return ratio_stddev
Пример #6
0
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