Beispiel #1
0
def read_image(filename, pointer="IMAGE"):  # ^IMAGE
    """ Read a PDS IMG formatted file into an array.
    TODO: Check for and account for LINE_PREFIX.
    TODO: Check for and apply BIT_MASK.
    """
    label = parse_label(filename)
    if "IMAGE" in label.keys():
        BYTES_PER_PIXEL = int(label["IMAGE"]["SAMPLE_BITS"] / 8)
        DTYPE = sample_types(label["IMAGE"]["SAMPLE_TYPE"], BYTES_PER_PIXEL)
        nrows = label["IMAGE"]["LINES"]
        ncols = label["IMAGE"]["LINE_SAMPLES"]
        if "LINE_PREFIX_BYTES" in label["IMAGE"].keys():
            print("Accounting for a line prefix.")
            prefix_cols = int(label["IMAGE"]["LINE_PREFIX_BYTES"] /
                              BYTES_PER_PIXEL)
        else:
            prefix_cols = 0
        try:
            BANDS = label["IMAGE"]["BANDS"]
        except KeyError:
            BANDS = 1
        pixels = nrows * (ncols + prefix_cols) * BANDS
    else:
        print("*** IMG w/ old format attached label not currently supported.")
        print("\t{fn}".format(fn=filename))
        return None
    fmt = "{endian}{pixels}{fmt}".format(endian=DTYPE[0],
                                         pixels=pixels,
                                         fmt=DTYPE[-1])
    try:  # a little decision tree to seamlessly deal with compression
        if filename.endswith(".gz"):
            f = gzip.open(filename, "rb")
        elif filename.endswith(".bz2"):
            f = bz2.BZ2File(filename, "rb")
        elif filename.endswith(".ZIP"):
            f = ZipFile(filename, "r").open(
                ZipFile(filename, "r").infolist()[0].filename)
        else:
            f = open(filename, "rb")
        f.seek(data_start_byte(label, "^IMAGE"))
        image = np.array(struct.unpack(fmt, f.read(pixels * BYTES_PER_PIXEL)))
        # Make sure that single-band images are 2-dim arrays.
        if BANDS == 1:
            image = image.reshape(nrows, (ncols + prefix_cols))
            if prefix_cols:
                # Ignore the prefix data, if any.
                # TODO: Also return the prefix
                prefix = image[:, :prefix_cols]
                if pointer == "LINE_PREFIX_TABLE":
                    return prefix
                image = image[:, prefix_cols:]
        else:
            image = image.reshape(BANDS, nrows, ncols)
    finally:
        f.close()
    print("Displaying an image")
    plt.figure(figsize=(4, 4))
    plt.title(filename.split("/")[-1])
    plt.xticks([])
    plt.yticks([])
    if len(np.shape(image)) == 2:
        plt.imshow(image, cmap="gray")
        pass
    elif len(np.shape(image)) == 3:
        if np.shape(image)[0] == 3:
            image = np.stack([image[0, :, :], image[1, :, :], image[2, :, :]],
                             axis=2)
        if np.shape(image)[2] == 3:
            plt.imshow(image)
            pass
    return image
Beispiel #2
0
def read_image(target, label, pointer="IMAGE"):  # ^IMAGE
    """Read a PDS IMG formatted file into an array.
    TODO: Check for and account for LINE_PREFIX.
    TODO: Check for and apply BIT_MASK.

    rasterio will read an ENVI file if the HDR metadata is present...
    However, it seems to read M3 L0 images incorrectly because it does
    not account for the L0_LINE_PREFIX_TABLE. So I am deprecating
    the use of rasterio until I can figure out how to produce consistent
    output.
    try:
        dataset = rasterio.open(filename)
        if len(dataset.indexes)==1:
            return dataset.read()[0,:,:] # Make 2D images actually 2D
        else:
            return dataset.read()
    except rasterio.errors.RasterioIOError:
        #print(' *** Not using rasterio. ***')
        pass
    """
    # TODO:
    # this should maybe always go in map_object_to_function,
    # but I'm not sure if read_image might want to get called
    # from other places that don't call that first.
    # probably best to check /decide this.
    # --Michael

    special_case = check_special_image_case(label, pointer)
    if special_case:
        props = special_case
    else:
        props = generic_image_props(label, pointer)

    # commented-out block here should work but it instead produces massive
    # quantities of bad spookiness. it specifically doesn't work
    # with certain variable names, variables pop in and out of existence,
    # somehow we hit undefined behavior:

    # read_image_namespace = locals()
    # for prop in image_props_list():
    #     read_image_namespace[prop] = props[prop]

    BYTES_PER_PIXEL = props["BYTES_PER_PIXEL"]
    start_byte = props["start_byte"]
    DTYPE = props["DTYPE"]
    nrows = props["nrows"]
    ncols = props["ncols"]
    prefix_bytes = props["prefix_bytes"]
    prefix_cols = props["prefix_cols"]
    BANDS = props["BANDS"]
    pixels = props["pixels"]
    band_storage_type = props["band_storage_type"]

    object_name = get_file_area(label, pointer)[1]

    # for attached labels, just point to the file
    # (which we should have assigned to a special key in the label)
    if isinstance(target, int):
        filename = label["attached_label_filename"]
    # otherwise point to the pointer target
    else:
        filename = target

    # a little decision tree to seamlessly deal with compression
    if filename.endswith(".gz"):
        f = gzip.open(filename, "rb")
    elif filename.endswith(".bz2"):
        f = bz2.BZ2File(filename, "rb")
    elif filename.endswith(".ZIP"):
        f = ZipFile(filename,
                    "r").open(ZipFile(filename, "r").infolist()[0].filename)
    else:
        f = open(filename, "rb")
    # Make sure that single-band images are 2-dim arrays.
    f.seek(start_byte)
    # TODO: I don't know what the band-sequential case should look
    #  like, because I don't have test data rn, but I suspect it should be
    #  rewritten to look like the line-interleaved case. --Michael
    if BANDS == 1:
        fmt = "{endian}{pixels}{length}".format(endian=DTYPE[0],
                                                pixels=pixels,
                                                length=DTYPE[-1])
        image = np.array(struct.unpack(fmt, f.read(
            pixels * BYTES_PER_PIXEL))).reshape(nrows, ncols + prefix_cols)
        if prefix_cols:
            # Ignore the prefix data, if any.
            # TODO: Also return the prefix
            prefix = image[:, :prefix_cols]
            if object_name == "LINE_PREFIX_TABLE":
                return prefix
            image = image[:, prefix_cols:]
    elif band_storage_type == "BAND_SEQUENTIAL":
        raise NotImplemented("BAND_SEQUENTIAL presently not implemented")
        # pixels_per_frame = BANDS * nrows
        # fmt = "{endian}{pixels}{length}".format(
        #     endian=DTYPE[0], pixels=pixels_per_frame, length=DTYPE[-1]
        # )
        # image = np.array(
        #     struct.unpack(fmt, f.read(pixels * BYTES_PER_PIXEL))
        # )
        # image = image.reshape(BANDS, nrows)
    elif band_storage_type == "LINE_INTERLEAVED":
        pixels_per_frame = BANDS * ncols
        fmt = "{endian}{pixels}{length}".format(endian=DTYPE[0],
                                                pixels=pixels_per_frame,
                                                length=DTYPE[-1])
        image, prefix = [], []
        for _ in np.arange(nrows):
            prefix.append(f.read(prefix_bytes))
            frame = np.array(
                struct.unpack(fmt,
                              f.read(pixels_per_frame *
                                     BYTES_PER_PIXEL))).reshape(BANDS, ncols)
            image.append(frame)
            del frame
        image = np.swapaxes(np.stack([frame for frame in image], axis=2), 1, 2)
    else:
        raise ValueError(f"Unknown BAND_STORAGE_TYPE={band_storage_type}")

    if f:
        f.close()
    if "PREFIX" in object_name:
        return prefix, image
    return image