Ejemplo n.º 1
0
def readRaw(f, shape, dtype=None, diskorder='F', memorder='C'):
  """Loads array data from a raw binary file on disk.
  
  This is a wrapper around numpy.fromfile, and returns a numpy.ndarray that
  owns its own memory.  Its particular purpose is to work with differing
  dimension orderings on disk and in memory.  The default is to interpret
  the file as "Fortran-ordered" (Matlab's default; column-major; first index
  is fastest-changing) and to produce an ndarray that is "C-ordered" (numpy's
  default; row-major; last index is fastest-changing).
  
  This function does not support memory mapping (yet), so it's not
  appropriate to use if your array is too big to fit comfortably in memory.
  numpy.load() and the h5py package are alternatives, but they put
  restrictions on the file format.  numpy.memmap() may be the right option.
  
  Arguments:
    f:         An open file object or a filename.
    shape:     A tuple of dimension extents.  One dimension may be given
               extent -1; if so, this dimension stretches to fit all the
               voxel values.
    dtype:     A numpy data type (like numpy.float32).  If None, dtype is
               inferred from the filename.
    diskorder: 'F' or 'C', default 'F'.
    memorder:  'F' or 'C', default 'C'.
  
  Throws a ValueError if shape does not match the number of voxels stored on
  disk, or if the product of the non-negative values in shape does not divide
  the number of voxels evenly.
  
  Returns a numpy.ndarray with the given shape and order=memorder.
  """
  # Read the data into a flat array.
  if dtype is None:
    dtype = _miraw_helpers.inferDtypeFromFilename(f)
  raw = np.fromfile(f, dtype=dtype)
  
  # Resolve the shape argument.
  shape = np.array(shape)
  num_voxels = np.prod(shape)
  if num_voxels < 0:
    num_voxels = -num_voxels
    missing_dim = int(raw.shape[0] / num_voxels)
    if num_voxels * missing_dim != raw.shape[0]:
      err = (('File has %i voxels; you gave me shape = %s = %i voxels,\n' +
              'which does not divide evenly.') %
             (raw.shape[0], repr(shape.tolist()), num_voxels))
      raise ValueError(err)
    # Replace the missing dimension.
    shape = np.where(shape < 0, missing_dim, shape)
  
  # Reshape the flat array, interpreting according to the disk order.
  try:
    X = np.ndarray(shape=shape, dtype=dtype, buffer=raw.data, order=diskorder)
  except TypeError:
    num_voxels = np.prod(shape)
    if num_voxels != raw.shape[0]:
      err = ('File has %i voxels; you gave me shape = %s = %i voxels.' %
             (raw.shape[0], repr(shape.tolist()), num_voxels))
      raise ValueError(err)
    else:
      raise
  
  # Now convert to the memory order and return.
  return _miraw_helpers.ndcopyWithOrder(X, memorder)
Ejemplo n.º 2
0
def readRawWithSizeInfo(f, sizefile=None, dtype=None, cropped=None, dimorder=None, diskorder='F', memorder='C'):
  """Loads a raw image file from disk, using a size_info metadata file.
  
  Arguments:
    f:         A filename or open file object for the raw data file.
    sizefile:  A filename for the size_info metadata file.
               If None, looks for a file called "size_info" in f's directory.
    dtype:     The numpy dtype of the raw data, or None.
    cropped:   A boolean: whether f is a cropped or full volume (as described in
               the sizefile), or None (in which case this will be inferred).
    dimorder:  Four-character string that is a permutation of "XYZI",
               indicating the dimension order of the image being read from
               disk.
                 The purpose of this argument is to map from the dimension
               extents stored in the size_info file, which are always stored
               in XYZI order, to the actual shape of the ndarray we create.
               Namely, if we create a 4-tuple "dimmap" by converting each
               character X->0, Y->1, Z->2, I->3, then
                   vol.shape[i] = sz[dimmap[i]]
               for i from 0 to 3, where vol is the returned volume and sz is
               the volume size, in (X,Y,Z,I) order, read from size_info.
                 The default value, None, is equivalent to "XYZI".
                 This can be a confusing argument, so please note:
                 - dimorder is overridden if the size_info file specifies a
                   "dimension_order" value.
                 - dimorder only indicates a rearrangement of dimension
                   extents from the default order (as read in the size_info
                   file) to the order that dictates the shape attribute of the
                   returned array.  Though it interacts in complicated ways
                   with the diskorder and memorder arguments, ultimately it is
                   not equivalent to calling transpose(dimmap) on the returned
                   array.
                 - dimorder does not change the order of the dimension extents
                   as stored in the returned dictionary "cfg".
    diskorder: The array traversal order of the file.
    memorder:  The desired traversal order of the output array.
  
  (See readRaw for more explanation of the last two arguments.)
  
  This function attempts, usually successfully, to infer the values of
  arguments left None.
  
  Returns (vol, cfg), where vol is a numpy ndarray and cfg is the dict of
  settings in sizefile.  In addition, this function defines an additional
  key, cfg['cropped'], with Boolean value.
  """
  
  # Read the image into a 1-D array.
  raw = readRaw(f, (-1,1), dtype=dtype, diskorder=diskorder, memorder=memorder)
  
  # Read the size file.
  imgname = _miraw_helpers.getFilename(f)
  if sizefile is None:
    try:
      sizefile = os.path.join(os.path.dirname(imgname), 'size_info')
    except:
      raise TypeError("Can't infer sizefile from filename '%s'." % imgname)
  cfg = readConfigFile(sizefile)
  sz = cfg['full_image_size_(voxels)']
  sz_c = cfg['cropped_image_size_(voxels)']
  try:
    n_imgs = cfg['num_dwis']
  except KeyError:
    n_imgs = 1
  
  # Try to figure out whether the image is cropped.
  cropped, threeD = _miraw_helpers.detectShapeAndCropping(raw.size,
    np.prod(sz), np.prod(sz_c), n_imgs, cropped)
  if cropped:
    sz = sz_c
  sz = sz + [n_imgs]
  cfg['cropped'] = cropped
  
  # Finally set the size and return.
  try:
    dimorder = cfg['dimension_order']
  except KeyError:
    if dimorder is None:
      dimorder = _miraw_helpers.DIM_DEFAULT_ORDER
  if not _miraw_helpers.isValidDimorder(dimorder):
    raise ValueError('"%s" is not a valid dimorder argument.' % repr(dimorder))
  
  if threeD:
    sz = sz[0:3]
  else:
    sz = np.take(sz, _miraw_helpers.dimorderToDimmap(dimorder), axis=0)
  return (_miraw_helpers.ndcopyWithOrder(raw.reshape(sz, order=diskorder),
                                         memorder),
          cfg)