def get(self, index): ra = None try: # Read cell origin and dimensions for cell at index cellMin = zeros(3, 'l') # long, 3 dimensions cellDims = zeros(3, 'i') # integer, 3 dimensions grid.getCellDimensions(index, cellMin, cellDims) # Unpack Cell origin (in pixel coordinates) x, y, z = cellMin # Unpack Cell dimensions: at margins, may be smaller than cell_width, cell_height width, height, _ = cellDims # ignore depth: it's 1 # Read cell from file into a byte array ra = RandomAccessFile(filepaths[z], 'r') read_width = width * bytesPerPixel bytes = zeros(read_width * height, 'b') # Initial offset to the Cell origin offset = (section_width * y + x) * bytesPerPixel n_read = 0 n_pixels = width * height # Read line by line while n_read < n_pixels: ra.seek(offset) ra.read(bytes, n_read, read_width) n_read += read_width offset += section_width * bytesPerPixel # Create a new Cell of the right pixel type return Cell(cellDims, cellMin, createAccess(bytes, bytesPerPixel)) except: print sys.exc_info() finally: if ra: ra.close()
def parse_TIFF_IFDs(filepath): """ Returns a generator of dictionaries of tags for each IFD in the TIFF file, as defined by the 'parseIFD' function above. """ ra = RandomAccessFile(filepath, 'r') try: # TIFF file format can have metadata at the end after the images, so the above approach can fail # TIFF file header is 8-bytes long: # (See: http://paulbourke.net/dataformats/tiff/tiff_summary.pdf ) # # Bytes 1 and 2: identifier. Either the value 4949h (II) or 4D4Dh (MM), # meaning little-endian and big-endian, respectively. # All data encountered past the first two bytes in the file obey # the byte-ordering scheme indicated by the identifier field. b1, b2 = ra.read(), ra.read() # as two java int, each one byte sized bigEndian = chr(b1) == 'M' parseNextInt = parseNextIntBigEndian if bigEndian else parseNextIntLittleEndian # Bytes 3 and 4: Version: Always 42 ra.skipBytes(2) # Bytes 5,6,7,8: IFDOffset: offset to first image file directory (IFD), the metadata entry for the first image. nextIFDoffset = parseNextInt(ra, 4) # offset to first IFD while nextIFDoffset != 0: ra.seek(nextIFDoffset) tags, nextIFDoffset = parseIFD(ra, parseNextInt) tags["bigEndian"] = bigEndian yield tags finally: ra.close()
def readFIBSEMdat(path, channel_index=-1, header=1024, magic_number=3555587570, asImagePlus=False, toUnsigned=True): """ Read a file from Shan Xu's FIBSEM software, where two or more channels are interleaved. Assumes channels are stored in 16-bit. path: the file path to the .dat file. channel_index: the 0-based index of the channel to parse, or -1 (default) for all. header: defaults to a length of 1024 bytes magic_number: defaults to that for version 8 of Shan Xu's .dat image file format. isSigned: defaults to True, will subtract the min value when negative. asImagePlus: return a list of ImagePlus instead of ArrayImg which is the default. """ ra = RandomAccessFile(path, 'r') try: # Check the magic number ra.seek(0) magic = ra.readInt() & 0xffffffff if magic != magic_number: msg = "magic number mismatch: v8 magic " + str(magic_number) + " != " + str(magic) + " for path:\n" + path System.out.println(msg) print msg # Continue: attempt to parse the file anyway # Read the number of channels ra.seek(32) numChannels = ra.readByte() & 0xff # a single byte as unsigned integer # Parse width and height ra.seek(100) width = ra.readInt() ra.seek(104) height = ra.readInt() # Read the whole interleaved pixel array ra.seek(header) bytes = zeros(width * height * 2 * numChannels, 'b') # 2 for 16-bit ra.read(bytes) # Parse as 16-bit array sb = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).asShortBuffer() bytes = None finally: ra.close() # shorts = zeros(width * height * numChannels, 'h') sb.get(shorts) sb = None # Deinterleave channels and convert to unsigned short # Shockingly, these values are signed shorts, not unsigned! (for first popeye2 squid volume, December 2021) # With ASM: fast channels = DAT_handler.deinterleave(shorts, numChannels, channel_index) shorts = None # if toUnsigned: for s in channels: DAT_handler.toUnsigned(s) # With python array sampling: very slow, and not just from iterating whole array once per channel #seq = xrange(numChannels) if -1 == channel_index else [channel_index] #channels = [shorts[i::numChannels] for i in seq] if asImagePlus: return [ImagePlus(str(i), ShortProcessor(width, height, s, None)) for i, s in enumerate(channels)] else: return [ArrayImgs.unsignedShorts(s, [width, height]) for s in channels]
def readBinaryMaskImg(filepath, width, height, depth, header_size): ra = RandomAccessFile(filepath, 'r') try: ra.skipBytes(header_size) bytes = zeros(width * height * depth, 'b') ra.read(bytes) return ArrayImgs.unsignedBytes(bytes, [width, height, depth]) finally: ra.close()
def readUnsignedBytes(path, dimensions, header=0): """ Read a file as an ArrayImg of UnsignedShortType """ ra = RandomAccessFile(path, 'r') try: if header < 0: # Interpret from the end: useful for files with variable header lengths # such as some types of uncompressed TIFF formats header = ra.length() + header ra.skipBytes(header) bytes = zeros(reduce(operator.mul, dimensions), 'b') ra.read(bytes) return ArrayImgs.unsignedBytes(bytes, dimensions) finally: ra.close()
def readFIBSEMdat(path, channel_index=-1, header=1024, magic_number=3555587570): """ Read a file from Shan Xu's FIBSEM software, where two channels are interleaved. Assumes channels are stored in 16-bit. path: the file path to the .dat file. channel_index: the 0-based index of the channel to parse, or -1 (default) for all. header: defaults to a length of 1024 bytes magic_number: defaults to that for version 8 of Shan Xu's .dat image file format. """ ra = RandomAccessFile(path, 'r') try: # Check the magic number ra.seek(0) if ra.readInt() & 0xffffffff != magic_number: print "Magic number mismatch" return None # Read the number of channels ra.seek(32) numChannels = ra.readByte() & 0xff # a single byte as unsigned integer # Parse width and height ra.seek(100) width = ra.readInt() ra.seek(104) height = ra.readInt() print numChannels, width, height # Read the whole interleaved pixel array ra.seek(header) bytes = zeros(width * height * 2 * numChannels, 'b') # 2 for 16-bit ra.read(bytes) print "read", len(bytes), "bytes" # takes ~2 seconds # Parse as 16-bit array sb = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).asShortBuffer() shorts = zeros(width * height * numChannels, 'h') sb.get(shorts) # Deinterleave channels # With Weaver: fast channels = w.deinterleave(shorts, numChannels, channel_index) # With python array sampling: very slow, and not just from iterating whole array once per channel # seq = xrange(numChannels) if -1 == channel_index else [channel_index] #channels = [shorts[i::numChannels] for i in seq] # With clojure: extremely slow, may be using reflection unexpectedly #channels = deinterleave.invoke(shorts, numChannels) print len(channels) # Shockingly, these values are signed shorts, not unsigned! return [ArrayImgs.shorts(s, [width, height]) for s in channels] finally: ra.close()
def readFloats(path, dimensions, header=0, byte_order=ByteOrder.LITTLE_ENDIAN): """ Read a file as an ArrayImg of FloatType """ size = reduce(operator.mul, dimensions) ra = RandomAccessFile(path, 'r') try: if header < 0: # Interpret from the end: useful for files with variable header lengths # such as some types of uncompressed TIFF formats header = ra.length() + header ra.skipBytes(header) bytes = zeros(size * 4, 'b') ra.read(bytes) floats = zeros(size, 'f') ByteBuffer.wrap(bytes).order(byte_order).asFloatBuffer().get(floats) return ArrayImgs.floats(floats, dimensions) finally: ra.close()
def readUnsignedShorts(path, dimensions, header=0, return_array=False, byte_order=ByteOrder.LITTLE_ENDIAN): """ Read a file as an ArrayImg of UnsignedShortType """ size = reduce(operator.mul, dimensions) ra = RandomAccessFile(path, 'r') try: if header < 0: # Interpret from the end: useful for files with variable header lengths # such as some types of uncompressed TIFF formats header = ra.length() + header ra.skipBytes(header) bytes = zeros(size * 2, 'b') ra.read(bytes) shorts = zeros(size, 'h') # h is for short ByteBuffer.wrap(bytes).order(byte_order).asShortBuffer().get(shorts) return shorts if return_array else ArrayImgs.unsignedShorts(shorts, dimensions) finally: ra.close()
def get(self, index): ra = None try: # Read cell origin and dimensions for cell at index cellMin = zeros(3, 'l') # long[3] cellDims = zeros(3, 'i') # integer[3] grid.getCellDimensions(index, cellMin, cellDims) # Unpack Cell origin (in pixel coordinates) x, y, z = cellMin # Unpack Cell dimensions: at margins, may be smaller than cell_width, cell_height width, height, _ = cellDims # ignore depth: it's 1 # Read cell from file into a byte array ra = RandomAccessFile(filepaths[z], 'r') read_width = width * bytesPerPixel bytes = zeros(read_width * height, 'b') # will contain the entire Cell pixel data # Initial offset to the Cell origin offset = (section_width * y + x) * bytesPerPixel n_pixels = width * height if width == section_width: # Read whole block in one go: cell data is continuous in the file ra.seek(offset) ra.read(bytes, 0, n_pixels * bytesPerPixel) else: # Read line by line n_read = 0 while n_read < n_pixels: ra.seek(offset) ra.read(bytes, n_read, read_width) n_read += read_width # ensure n_read advances in case file is truncated to avoid infinite loop offset += section_width * bytesPerPixel # Create a new Cell of the right pixel type return Cell(cellDims, cellMin, createAccess(bytes, bytesPerPixel)) except: print sys.exc_info() finally: if ra: ra.close()
nextIFDoffset = parseNextInt(ra, 4) return tags, nextIFDoffset if filepath.endswith("tif"): try: ra = RandomAccessFile(filepath, 'r') # TIFF file format can have metadata at the end after the images, so the above approach can fail # TIFF file header is 8-bytes long: # (See: http://paulbourke.net/dataformats/tiff/tiff_summary.pdf ) # # Bytes 1 and 2: identifier. Either the value 4949h (II) or 4D4Dh (MM), # meaning little-ending and big-endian, respectively. # All data encountered past the first two bytes in the file obey # the byte-ordering scheme indicated by the identifier field. b1, b2 = ra.read(), ra.read() # as two java int, each one byte sized bigEndian = chr(b1) == 'M' parseNextInt = parseNextIntBigEndian if bigEndian else parseNextIntLittleEndian # Bytes 3 and 4: Version: Always 42 ra.skipBytes(2) # Bytes 5,6,7,8: IFDOffset: offset to first image file directory (IFD), the metadata entry for the first image. firstIFDoffset = parseNextInt(ra, 4) ra.skipBytes(firstIFDoffset - ra.getFilePointer() ) # minus the current position: all offsets are absolute firstTags, _ = parseIFD(ra, parseNextInt) # Correct headerSize for TIFF files (and then assuming images are contiguous and in order, # which they don't have to be either in TIFF) headerSize = firstTags["offset"] # Sanity check: if width != firstTags["width"] or height != firstTags[ "height"] or bitDepth != firstTags["samples_per_pixel"] * 8:
# Parse the test file IFDs = list(parse_TIFF_IFDs(filepath)) # the tags of each IFD firstIFD = IFDs[0] print firstIFD ra = RandomAccessFile(filepath, 'r') try: # Read the image plane, compressed with packbits bytes_packedbits = zeros(sum(firstIFD["StripByteCounts"]), 'b') index = 0 for strip_offset, strip_length in zip(firstIFD["StripOffsets"], firstIFD["StripByteCounts"]): ra.seek(strip_offset) ra.read(bytes_packedbits, index, strip_length) index += strip_length print "Compressed:", bytes_packedbits # unpack bytes1 = unpackBits2(bytes_packedbits, firstIFD) bytes2 = unpackBits2(bytes_packedbits, firstIFD, use_imagereader=True) print "Decompressed jython:", bytes1 print "Decompressed imagej:", bytes2 # Check: if 0 == sum(a - b for a, b in zip(source_bytes, bytes1)): print "Image decompressed successfully by jython." if 0 == sum(a - b for a, b in zip(source_bytes, bytes2)): print "Image decompressed successfully by imagej." finally: ra.close()