Exemple #1
0
 def rawToNifti(infile, sizefile=None, outfile=None, dimorder=None, diskorder='F', dtype=None, split4=False):
   """Converts a raw file to a NIfTI file.
   
   Arguments:
     infile:    Filename of a raw file.
     sizefile:  Filename of a size_info config file.  If None, attempts to find
                this file in the same directory as infile.
     outfile:   Filename (including .nii) of the NIfTI file to generate.
                If None, it will be generated from infile.
     dimorder:  Four-character string that is a permutation of "XYZI",
                indicating the dimension order of the image in "infile".
                  The purpose of this argument is to rearrange the order of the
                dimensions in the infile to match the NIfTI canonical order of
                (X, Y, Z, I), where I is the dimension along which multiple
                acquisitions are concatenated.
                  The default value, None, is equivalent to "XYZI".
                  Note that this argument will be overridden if the size_info
                file contains a "dimension_order" value.
     diskorder: A string, 'F' or 'C', representing the order in which the data
                values are stored in the raw file.
     dtype:     The numpy dtype for the infile.  If None, it is inferred from
                infile's extension.
     split4:    If True, output numbered 3-D images from 4-D input.
   """
   (raw, cfg) = readRawWithSizeInfo(infile, sizefile=sizefile, dtype=dtype,
                                    dimorder=dimorder, diskorder=diskorder,
                                    memorder='C')
   vox_sz = cfg['voxel_size_(mm)']
   
   # Rearrange dimensions.
   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))
   raw_transp = raw.transpose(_miraw_helpers.dimorderToReverseDimmap(dimorder))
   
   if split4 and len(raw_transp.shape) == 4:
     raw_stack = [raw_transp[:,:,:,i] for i in range(raw_transp.shape[3])]
   else:
     raw_stack = [raw_transp]
   i = 0
   for img in raw_stack:
     nii = nifti1.Nifti1Pair(img, np.diag(vox_sz + [0.0]))
     nii.get_header().set_xyzt_units('mm')
     outfname = outfile
     if outfname is None:
       outfname = os.path.splitext(infile)[0] + '.nii'
     if split4:
       outfname = os.path.splitext(outfname)[0] + ('_%03i.nii' % i)
       i += 1
     nifti1.save(nii, outfname)
Exemple #2
0
def saveSizeInfo(f, img, vox_sz=(1,1,1), dimorder=None, size_cfg={}, infer_name=False):
  """Writes a size_info metadata file to disk for a given array.
  
  A size_info file stores image (array) dimensions for raw images, as well as
  voxel size and cropping information (indicating that the array is cropped
  from a larger volume).  Note that size_info is designed for 3-D or 4-D
  arrays only, and stores the extents of the first three dimensions
  separately from that of the fourth.
  
  Arguments:
    f:          An open file handle or a filename for the destination file.
    img:        A numpy.ndarray.
    vox_sz:     Optional array-like object with 2 or 3 entries.
    dimorder:   Four-character string that is a permutation of "XYZI",
                indicating the dimension order of the image "img".
                  The purpose of this argument is to map from the dimension
                extents represented in img.shape to the extents stored in the
                size_info file, which are always stored in a canonical "XYZI"
                order.  Namely, if we create a 4-tuple "dimmap" by converting
                each character X->0, Y->1, Z->2, I->3, then
                   sz[dimmap[i]] = img.shape[i]
                for i from 0 to 3, where sz is the volume size, in (X,Y,Z,I)
                order, that will be stored in the size_info.
                  The default value, None, is equivalent to "XYZI".
    size_cfg:   Optional dictionary of other config key-value pairs.  The data
                stored in this dictionary override all values computed by or
                passed into this function, even if they're inconsistent with
                the size of the image.  Be careful!  This includes the
                "dimension_order" value, which overrides the dimorder argument
                above.
    infer_name: Optional boolean.  If True, and f is a filename, then the
                file actually written will be in the same directory as f
                (or in f if f is a path ending with a slash), and named
                "size_info".  If f is not a string, this option has no effect.
  """
  # Deal with filenames and open a file for writing, if necessary.
  if isinstance(f, str):
    if infer_name:
      f = os.path.join(os.path.dirname(f), 'size_info')
    fid = open(f, 'w')
    close_after = True
  else:
    fid = f
    close_after = False
  
  # Set up dimension mapping.
  shape = list(img.shape) + [1]*4
  try:
    dimorder = size_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))
  shape = np.take(shape, _miraw_helpers.dimorderToReverseDimmap(dimorder), axis=0).tolist()
  
  # Extract metadata from the arguments.
  base_keys = ['voxel_size_(mm)', 'full_image_size_(voxels)',
               'low_end_crop_(voxels)', 'cropped_image_size_(voxels)',
               'num_dwis', 'dimension_order']
  auto_cfg = {
    base_keys[0] : vox_sz,
    base_keys[1] : shape[:3],
    base_keys[2] : [0, 0, 0],
    base_keys[3] : shape[:3],
    base_keys[4] : shape[3],
    base_keys[5] : dimorder
  }
  
  # Overwrite metadata with what the user gave us.
  for (k,v) in size_cfg.items():
    auto_cfg[k] = v
  
  # Now write the key-value pairs and we're done!
  def spaceSepStr(a):
    if isinstance(a, list) or isinstance(a, tuple):
      return ' '.join([str(x) for x in a])
    return str(a)
  
  for k in base_keys:
    fid.write(k + ': ' + spaceSepStr(auto_cfg[k]) + '\n')
    del(auto_cfg[k])
  for (k, v) in auto_cfg.items():
    fid.write(k + ': ' + spaceSepStr(v) + '\n')
  
  if close_after:
    fid.close()
Exemple #3
0
 def niftiToRaw(infile, outfile=None, sizefile=None, dimorder=None, diskorder='F', dtype=None, dtype_as_ext=False):
   """Converts a NIfTI file (or set of files) to a raw file.
   
   Arguments:
     infile:       Filename of a NIfTI file, or a list of strings.  The list
                   indicates a sequence of files to be concatenated together,
                   in the order given, along dimension 4 (where 1 is the
                   fastest-changing).
     outfile:      Filename of a raw file to generate.  If None, the filename
                   will be copied from infile, but with an extension indicating
                   the dtype.  See also dtype_as_ext.
     sizefile:     Filename of a size_info metadata file.  If None, it will go
                   in the same directory as outfile.  If empty string, no
                   size_info file will be generated.
     dimorder:     Four-character string that is a permutation of "XYZI",
                   indicating the desired dimension order of the output image.
                     The default value, None, is equivalent to "XYZI".
     diskorder:    'F' or 'C' --- the order for storage on disk.
     dtype:        A numpy data type to cast to.  If None, the data type
                   either remains whatever the NIfTI header specifies, or is
                   cast to the type specified by the extension on outfile.
     dtype_as_ext: If True, and if outfile is not None, then this appends the
                   dtype to the end of outfile.
   """
   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))
   
   # Figure out the desired dtype.
   fname_dtype = None
   try:
     fname_dtype = _miraw_helpers.inferDtypeFromFilename(outfile)
   except:
     pass
   
   if dtype is not None and fname_dtype is not None:
     if fname_dtype != np.dtype(dtype):
       raise ValueError("Arguments specify contradictory dtypes:\n  outfile: {}\n  dtype:   {}".format(outfile, dtype))
   elif dtype is None:
     dtype = fname_dtype
   
   # Now either dtype is None, because both the outfile and dtype arguments
   # failed to set it, or it and the outfile agree.  If it's None, then we'll
   # just keep the dtype from the NIfTI file.
   
   # Read the file and set the dtype once and for all.
   (img, cfg, header) = readNifti(infile, dtype)
   dtype = img.dtype
   
   # Apply any dimension flips or permutations according to the header.
   (img, xform, vox_sz) = applyNiftiXform(img, niftiGetXform(header), cfg)
   
   # And finally put the data in the requested storage order.
   img = applyDimOrder(img, dimorder)
   
   # Generate new names for the output files as necessary.
   if outfile is None:
     if not isinstance(infile, str):
       raise ValueError("No outfile specified, but infile %s is not a string!" % repr(infile))
     (base, ext) = os.path.splitext(infile)
     if ext == ".gz":
       (base, ext) = os.path.splitext(base)
     outfile = base + "." + str(dtype)
   elif dtype_as_ext:
     outfile += "." + str(dtype)
   
   if sizefile is None:
     sizefile = os.path.join(os.path.dirname(outfile), "size_info")
   
   # Write the size_info file.
   if len(sizefile) > 0:
     saveSizeInfo(sizefile, img, size_cfg=cfg, infer_name=False)
   
   # And finally write the raw file.
   saveRaw(outfile, img, diskorder, dtype_as_ext)
Exemple #4
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)