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