def export(flnm, p): flnm = flnm + '.' + surface_format dt = np.int32 if np.issubdtype(p.dtype, np.dtype(int).type) else np.float32 img = fsmgh.MGHImage(np.asarray([[p]], dtype=dt), np.eye(4)) img.to_filename(flnm) return flnm
def export(flnm, d): if not pimms.is_nparray(d): d = np.asarray(d.dataobj) flnm = flnm + '.' + volume_format dt = np.int32 if np.issubdtype(d.dtype, np.dtype(int).type) else np.float32 img = fsmgh.MGHImage(np.asarray(d, dtype=dt), affmatrix) img.to_filename(flnm) return flnm
def write_voldata_to_mgh_file(mgh_file_name, vol_data, affine=None, header=None): """ Write volume data to a MGH format file. Write the volume data to a file in MGH format. The format is from FreeSurfer and stores volume images. Unless you supply a header, the header will be pretty empty. Thin wrapper around nibabels ```MGHImage``` class and the ```to_filename``` method inherited from ```FileBasedImage```. Note that if you just modified data that you loaded from a source image (e.g., you replaced some intensities), you should pass the affine and the header of the original image. Parameters ---------- mgh_file_name: str Path to output file. Will be overwritten if it exists. Should have file extension mgh. vol_data: the data to write, usually a multi-dimensional numpy array. Shape could be (256, 256, 256) for a 3D image, or (256, 256, 256, 50) for a 4D image containing 50 time points, but this is up to you. affine: numpy 2D array, optional The affine registration matrix (4x4) relating the voxel coordinates to world coordinates in RAS+ space. See nibabel docs for details. header: nibabel.freesurfer.mghformat.MGHHeader, optional The MGH file header. If not given, an empty default header will be used. """ if header is None: header = fsmgh.MGHHeader() image = fsmgh.MGHImage(vol_data, affine, header=header) image.to_filename(mgh_file_name)
def nsd_write_fs(data, outputfile, fsdir): """similar to nsd_vrite_vol but for surface mgz Args: data (nd-array): the surface data outputfile (filename/path): where to save fsdir (path): we need to know where the fsdir is. Raises: ValueError: if wrong file name provided, e.g doesn't have lh or rh in filename, error is raised. """ # load template # load template if outputfile.find('lh.') != -1: hemi = 'lh' elif outputfile.find('rh.') != -1: hemi = 'rh' else: raise ValueError('wrong outpufile.') mgh0 = f'{fsdir}/surf/{hemi}.w-g.pct.mgh' if not os.path.exists(mgh0): mgh0 = f'{fsdir}/surf/{hemi}.orig.avg.area.mgh' img = fsmgh.load(mgh0) header = img.header affine = img.affine # Okay, make a new object now... vol_h = data[:, np.newaxis].astype(np.float64) v_img = fsmgh.MGHImage(vol_h, affine, header=header, extra={}) v_img.to_filename(outputfile)
def export(flnm, d): flnm = flnm + '.' + volume_format dt = np.int32 if np.issubdtype(d.dtype, np.dtype(int).type) else np.float32 img = fsmgh.MGHImage(np.asarray(d, dtype=dt), subject.voxel_to_native_matrix) img.to_filename(flnm) return flnm
def to_mgh(obj, like=None, header=None, affine=None, extra=Ellipsis): ''' to_mgh(obj) yields an MGHmage object that is as equivalent as possible to the given object obj. If obj is an MGHImage already and no changes are requested, then it is returned unmolested; otherwise, the optional arguments can be used to edit the header, affine, and exta. The following options are accepted: * like (default: None) may be provided to give a guide for the various header- and meta-data that is included in the image. If this is a nifti image object, its meta-data are used; if this is a subject, then the meta-data are deduced from the subject's voxel and native orientation matrices. All other specific options below override anything deduced from the like argument. * header (default: None) may be a Nifti1 or Niti2 image header to be used as the nifti header or to replace the header in a new image. * affine (default: None) may specify the affine transform to be given to the image object. * extra (default: Ellipsis) may specify an extra mapping for storage with the image data; the default value Ellipsis indicates that such a mapping should be left as is if it already exists in the obj or in the like option and should otherwise be empty. ''' obj0 = obj # First go from like to explicit versions of affine and header: if like is not None: if isinstance(like, nib.analyze.AnalyzeHeader) or isinstance(obj, fsmgh.MGHHeader): if header is None: header = like elif isinstance(like, nib.analyze.SpatialImage): if header is None: header = like.header if affine is None: affine = like.affine if extra is Ellipsis: extra = like.extra elif isinstance(like, mri.Subject): if affine is None: affine = like.voxel_to_native_matrix else: raise ValueError('Could not interpret like argument with type %s' % type(like)) # check to make sure that we have to change something: elif (isinstance(obj, fsmgh.MGHImage)): if ((header is None or obj.header is header) and (extra is Ellipsis or extra == obj.extra or (extra is None and len(obj.extra) == 0))): return obj # okay, now look at the header and affine etc. if header is None: if isinstance(obj, nib.analyze.SpatialImage): header = obj.header else: header = None if affine is None: if isinstance(obj, nib.analyze.SpatialImage): affine = obj.affine else: affine = np.eye(4) if extra is None: extra = {} # Figure out what the data is if isinstance(obj, nib.analyze.SpatialImage): obj = obj.dataobj else: obj = np.asarray(obj) if len(obj.shape) < 3: obj = np.asarray([[obj]]) # make sure the dtype isn't a high-bit integer or float if np.issubdtype(obj.dtype, np.integer) and obj.dtype.itemsize > 4: obj = np.asarray(obj, dtype=np.int32) elif np.issubdtype(obj.dtype, np.floating) and obj.dtype.itemsize > 4: obj = np.asarray(obj, dtype=np.float32) # Okay, make a new object now... obj = fsmgh.MGHImage(obj, affine, header=header, extra=extra) # Okay, that's it! return obj
def _make_imm_mask(arr, val, eq=True): arr = (arr == val) if eq else (arr != val) arr.setflags(write=False) return fsmgh.MGHImage(arr, mgh_images['ribbon'].affine, mgh_images['ribbon'].header)
def export_anatomical_data(data, sub, anat_ids, hemis, name, output_dir, modality=None, create_dir=False, prefix='', suffix='', null=np.nan, dtype=None): ''' export_anatomical_data(data, sub, cortex_indices, hemis, name, output_dir) exports the prediction data in the given data vector or matrix, out to the given directory in a set of files appropriate to the modality; for surfaces, this is an lh.<name>.nii.gz and rh.<name>.nii.gz file; for volumes, this is just a <name>.nii.gz file. Parameters: * data must be a vector of data or a matrix of data whose rows match up to the anatomical ids * cortex_indices must be the voxel indices or vertex ids of the data rows * hemis must be a list of 1 or -1 values to indicate LH and RH respectively * name should be a name for the file, used as a part of the filename such as lh.<name>.nii.gz * output_dir must be the name of the output directory * freesurfer_subject: the freesurfer subject object Options: * create_dir (default: False) if True, will create the directory if it does not exist; otherwise raises an exception when the directory does not exist. * prefix (default: '') may be a string that is prepended to filenames; prepends are performed before other prefixes such as 'lh.<prefix><name><suffix>.nii.gz'. * suffix (default: '') may be a string that is appended the the filename; appends are performed before the file extension is appended, such as in 'lh.<prefix><name><suffix>.nii.gz'. * modality (default: None) may be specified explicitly as 'surface' or 'volume', but will auto-detect the modality based on the cortex_indices if None is given * null (default: nan) specifies the null value that should be written for values not in the cortex_indices; if this is nan and the dtype is an integer value, then 0 is used instead * dtype (default: None) specifies explicitly the dtype of the exported array; if None, the value np.asarray(data).dtype is used ''' anat_ids = np.asarray(anat_ids) if len(anat_ids.shape) == 2 and (anat_ids.shape[0] == 1 or anat_ids.shape[1] == 1): anat_ids = anat_ids.flatten() if modality is None: modality = 'volume' if len(anat_ids.shape) == 2 else 'surface' (prefix, suffix) = _sco_init_outputs(output_dir, create_dir, prefix, suffix) make_fname = lambda p, ext: os.path.join( output_dir, p + prefix + name + suffix + '.' + ext) modality = modality.lower() data = np.asarray(data) data = np.asarray([data]).T if len(data.shape) == 1 else data if len(data) != len(anat_ids): raise ValueError('anatomical id (%d) and data (%d) sizesmust match' % (len(anat_ids), len(data))) if dtype is None: dtype = data.dtype if np.issubdtype(dtype, np.dtype(int).type) and not np.isfinite(null): null = 0 affine = sub.mgh_images['lh.ribbon'].affine file_names = [] if modality == 'surface': for (hname, hid) in [('lh', 1), ('rh', -1)]: hobj = getattr(sub, hname.upper()) hidcs = np.where(hemis == hid)[0] n = hobj.vertex_count if np.issubdtype(dtype, np.float64): dtype = np.float32 if data.shape[1] == 1: vol = np.full((1, 1, n), null, dtype=dtype) vol[0, 0, anat_ids[hidcs]] = data[hidcs, 0] else: vol = np.full((1, 1, n, data.shape[1]), null, dtype=dtype) vol[0, 0, anat_ids[hidcs], :] = data[hidcs, :] #img = nibabel.Nifti2Image(vol, np.eye(4)) #fnm = make_fname(hname + '.', 'nii.gz') img = fsmgh.MGHImage(vol, np.eye(4)) fnm = make_fname(hname + '.', 'mgz') img.to_filename(fnm) file_names.append(fnm) elif modality == 'volume': vol = np.full(sub.mgh_images['lh.ribbon'].shape + (data.shape[1], ), null, dtype=dtype) for ((i, j, k), row) in zip(anat_ids, data): vol[i, j, k, :] = row img = nibabel.Nifti1Image(vol, affine) fnm = make_fname('', 'nii.gz') img.to_filename(fnm) file_names.append(fnm) else: raise ValueError('unrecognized modality: %s' % modality) return file_names
def benson14_retinotopy_command(*args): ''' benson14_retinotopy_command(args...) runs the benson14_retinotopy command; see benson14_retinotopy_help for mor information. ''' # Parse the arguments... (args, opts) = _benson14_parser(args) # help? if opts['help']: print benson14_retinotopy_help return 1 # verbose? verbose = opts['verbose'] def note(s): if verbose: print s return verbose # Add the subjects directory, if there is one if 'subjects_dir' in opts and opts['subjects_dir'] is not None: add_subject_path(opts['subjects_dir']) ow = not opts['no_overwrite'] nse = opts['no_surf_export'] nve = opts['no_vol_export'] tr = {'polar_angle': opts['angle_tag'], 'eccentricity': opts['eccen_tag'], 'visual_area': opts['label_tag']} # okay, now go through the subjects... for subnm in args: note('Processing subject %s:' % subnm) sub = freesurfer_subject(subnm) note(' - Interpolating template...') (lhdat, rhdat) = predict_retinotopy(sub, template=opts['template']) # Export surfaces if nse: note(' - Skipping surface export.') else: note(' - Exporting surfaces:') for (t,dat) in lhdat.iteritems(): flnm = os.path.join(sub.directory, 'surf', 'lh.' + tr[t] + '.mgz') if ow or not os.path.exist(flnm): note(' - Exporting LH prediction file: %s' % flnm) img = fsmgh.MGHImage( np.asarray([[dat]], dtype=(np.int32 if t == 'visual_area' else np.float32)), np.eye(4)) img.to_filename(flnm) else: note(' - Not overwriting existing file: %s' % flnm) for (t,dat) in rhdat.iteritems(): flnm = os.path.join(sub.directory, 'surf', 'rh.' + tr[t] + '.mgz') if ow or not os.path.exist(flnm): note(' - Exporting RH prediction file: %s' % flnm) img = fsmgh.MGHImage( np.asarray([[dat]], dtype=(np.int32 if t == 'visual_area' else np.float32)), np.eye(4)) img.to_filename(flnm) else: note(' - Not overwriting existing file: %s' % flnm) # Export volumes if nve: note(' - Skipping volume export.') else: surf2rib = cortex_to_ribbon_map(sub, hemi=None) note(' - Exporting Volumes:') for t in lhdat.keys(): flnm = os.path.join(sub.directory, 'mri', tr[t] + '.mgz') if ow or not os.path.exist(flnm): note(' - Preparing volume file: %s' % flnm) vol = cortex_to_ribbon(sub, (lhdat[t], rhdat[t]), map=surf2rib, method=('max' if t == 'visual_area' else 'weighted'), dtype=(np.int32 if t == 'visual_area' else np.float32)) note(' - Exporting volume file: %s' % flnm) vol.to_filename(flnm) else: note(' - Not overwriting existing file: %s' % flnm) note(' Subject %s finished!' % sub.id) return 0
def register_retinotopy_command(args): ''' register_retinotopy_command(args) can be given a list of arguments, such as sys.argv[1:]; these arguments may include any options and must include at least one subject id. All subjects whose ids are given are registered to a retinotopy model, and the resulting registration, as well as the predictions made by the model in the registration, are exported. ''' # Parse the arguments (args, opts) = _retinotopy_parser(args) # First, help? if opts['help']: print register_retinotopy_help return 1 # and if we are verbose, lets setup a note function verbose = opts['verbose'] def note(s): if verbose: print s return verbose # Add the subjects directory, if there is one if 'subjects_dir' in opts and opts['subjects_dir'] is not None: add_subject_path(opts['subjects_dir']) # Parse the simple numbers for o in [ 'weight_cutoff', 'edge_strength', 'angle_strength', 'func_strength', 'max_step_size', 'max_out_eccen' ]: opts[o] = float(opts[o]) opts['max_steps'] = int(opts['max_steps']) # These are for now not supported: #TODO if opts['angle_math'] or opts['angle_radians'] or opts['eccen_radians']: print 'Mathematical angles and angles not in degrees are not yet supported.' return 1 # The remainder of the args can wait for now; walk through the subjects: tag_key = { 'eccen': 'eccentricity', 'angle': 'polar_angle', 'label': 'visual_area' } for subnm in args: sub = freesurfer_subject(subnm) note('Processing subject: %s' % sub.id) # we need to register this subject... res = {} ow = not opts['no_overwrite'] for h in ['LH', 'RH']: note(' Processing hemisphere: %s' % h) hemi = sub.__getattr__(h) # See if we are loading custom values... (ang, ecc, wgt) = (None, None, None) suffix = '_' + h.lower() + '_file' if opts['angle' + suffix] is not None: ang = _guess_surf_file(opts['angle' + suffix]) if opts['eccen' + suffix] is not None: ecc = _guess_surf_file(opts['eccen' + suffix]) if opts['weight' + suffix] is not None: wgt = _guess_surf_file(opts['weight' + suffix]) # Do the registration note(' - Running Registration...') res[h] = register_retinotopy( hemi, retinotopy_model(), polar_angle=ang, eccentricity=ecc, weight=wgt, weight_cutoff=opts['weight_cutoff'], partial_voluming_correction=opts['part_vol_correct'], edge_scale=opts['edge_strength'], angle_scale=opts['angle_strength'], functional_scale=opts['func_strength'], prior=opts['prior'], max_predicted_eccen=opts['max_out_eccen'], max_steps=opts['max_steps'], max_step_size=opts['max_step_size']) # Perform the hemi-specific outputs now: if not opts['no_reg_export']: regnm = '.'.join( [h.lower(), opts['registration_name'], 'sphere', 'reg']) flnm = (os.path.join(sub.directory, 'surf', regnm) if h == 'LH' else os.path.join(sub.directory, 'xhemi', 'surf', regnm)) if ow or not os.path.exist(flnm): note(' - Exporting registration file: %s' % flnm) fsio.write_geometry( flnm, res[h].coordinates.T, res[h].faces.T, 'Created by neuropythy (github.com/noahbenson/neuropythy)' ) else: note(' - Skipping registration file: %s (file exists)' % flnm) if not opts['no_surf_export']: for dim in ['angle', 'eccen', 'label']: flnm = os.path.join( sub.directory, 'surf', '.'.join([h.lower(), opts[dim + '_tag'], 'mgz'])) if ow or not os.path.exist(flnm): note(' - Exporting prediction file: %s' % flnm) img = fsmgh.MGHImage( np.asarray([[res[h].prop(tag_key[dim])]], dtype=(np.int32 if dim == 'label' else np.float32)), np.eye(4)) img.to_filename(flnm) else: note(' - Skipping prediction file: %s (file exists)' % flnm) # Do the volume exports here if not opts['no_vol_export']: note(' Processing volume data...') note(' - Calculating cortex-to-ribbon mapping...') surf2rib = cortex_to_ribbon_map(sub, hemi=None) for dim in ['angle', 'eccen', 'label']: flnm = os.path.join(sub.directory, 'mri', opts[dim + '_tag'] + '.mgz') if ow or not os.path.exist(flnm): note(' - Generating volume file: %s' % flnm) vol = cortex_to_ribbon( sub, (res['LH'].prop(tag_key[dim]), res['RH'].prop( tag_key[dim])), map=surf2rib, method=('max' if dim == 'label' else 'weighted'), dtype=(np.int32 if dim == 'label' else np.float32)) note(' - Exporting volume file: %s' % flnm) vol.to_filename(flnm) else: note(' - Skipping volume file: %s (file exists)' % flnm) # That is it for this subject! note(' Subject %s finished!' % sub.id) # And if we made it here, all was successful. return 0