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
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