def read2DImageROI(path, dimensions, interval, pixelType=UnsignedShortType, header=0, byte_order=ByteOrder.LITTLE_ENDIAN): """ Read a region of interest (the interval) of an image in a file. Assumes the image is written with the first dimension moving slowest. path: the file path to the image file. dimensions: a sequence of integer values e.g. [512, 512, 512] interval: two sequences of integer values defining the min and max coordinates, e.g. [[20, 0], [400, 550]] pixeltype: e.g. UnsignedShortType, FloatType header: defaults to zero, the number of bytes between the start of the file and the start of the image data. Supports only these types: UnsignedByteType, UnsignedShortType, FloatType. Returns an ArrayImg of the given type. """ ra = RandomAccessFile(path, 'r') try: width, height = dimensions minX, minY = interval[0] maxX, maxY = interval[1] roi_width, roi_height = maxX - minX + 1, maxY - minY + 1 tailX = width - roi_width - minX #print minX, minY #print maxX, maxY #print roi_width, roi_height size = roi_width * roi_height n_bytes_per_pixel = pixelType().getBitsPerPixel() / 8 #print n_bytes_per_pixel bytes = zeros(size * n_bytes_per_pixel, 'b') # Read only the 2D ROI ra.seek(header + (minY * width + minX) * n_bytes_per_pixel) for h in xrange(roi_height): ra.readFully(bytes, h * roi_width * n_bytes_per_pixel, roi_width * n_bytes_per_pixel) ra.skipBytes((tailX + minX) * n_bytes_per_pixel) # Make an image roiDims = [roi_width, roi_height] if UnsignedByteType == pixelType: return ArrayImgs.unsignedBytes(bytes, roiDims) if UnsignedShortType == pixelType: shorts = zeros(size, 'h') ByteBuffer.wrap(bytes).order(byte_order).asShortBuffer().get(shorts) return ArrayImgs.shorts(shorts, roiDims) if FloatType == pixelType: floats = zeros(size, 'f') ByteBuffer.wrap(bytes).order(byte_order).asFloatBuffer().get(floats) return ArrayImgs.floats(floats, roiDims) 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()