def _morphed_stc_as_volume(morph, stc, mri_resolution, mri_space, output): """Return volume source space as Nifti1Image and/or save to disk.""" if isinstance(stc, VolVectorSourceEstimate): stc = stc.magnitude() if not isinstance(stc, VolSourceEstimate): raise ValueError('Only volume source estimates can be converted to ' 'volumes') _check_dep(nibabel='2.1.0', dipy=False) NiftiImage, NiftiHeader = _triage_output(output) # if MRI resolution is set manually as a single value, convert to tuple if isinstance(mri_resolution, (int, float)): # use iso voxel size new_zooms = (float(mri_resolution),) * 3 elif isinstance(mri_resolution, tuple): new_zooms = mri_resolution # if full MRI resolution, compute zooms from shape and MRI zooms if isinstance(mri_resolution, bool): new_zooms = _get_zooms_orig(morph) if mri_resolution else None # create header hdr = NiftiHeader() hdr.set_xyzt_units('mm', 'msec') hdr['pixdim'][4] = 1e3 * stc.tstep # setup empty volume if morph.src_data['to_vox_map'] is not None: shape = morph.src_data['to_vox_map'][0] affine = morph.src_data['to_vox_map'][1] else: shape = morph.shape affine = morph.affine assert stc.data.ndim == 2 n_times = stc.data.shape[1] img = np.zeros((np.prod(shape), n_times)) img[stc.vertices, :] = stc.data img = img.reshape(shape + (n_times,), order='F') # match order='F' above del shape # make nifti from data with warnings.catch_warnings(): # nibabel<->numpy warning img = NiftiImage(img, affine, header=hdr) # reslice in case of manually defined voxel size zooms = morph.zooms[:3] if new_zooms is not None: from dipy.align.reslice import reslice new_zooms = new_zooms[:3] img, affine = reslice(_get_img_fdata(img), img.affine, # MRI to world registration zooms, # old voxel size in mm new_zooms) # new voxel size in mm with warnings.catch_warnings(): # nibabel<->numpy warning img = NiftiImage(img, affine) zooms = new_zooms # set zooms in header img.header.set_zooms(tuple(zooms) + (1,)) return img
def _interpolate_data(stc, morph, mri_resolution, mri_space, output): """Interpolate source estimate data to MRI.""" _check_dep(nibabel='2.1.0', dipy=False) NiftiImage, NiftiHeader = _triage_output(output) assert morph.kind == 'volume' voxel_size_defined = False if isinstance(mri_resolution, (int, float)) and not isinstance( mri_resolution, bool): # use iso voxel size mri_resolution = (float(mri_resolution),) * 3 if isinstance(mri_resolution, tuple): _check_dep(nibabel=False, dipy='0.10.1') # nibabel was already checked from dipy.align.reslice import reslice voxel_size = mri_resolution voxel_size_defined = True mri_resolution = True # if data wasn't morphed yet - necessary for call of # stc_unmorphed.as_volume. Since only the shape of src is known, it cannot # be resliced to a given voxel size without knowing the original. if isinstance(morph, SourceSpaces): assert morph.kind == 'volume' if voxel_size_defined: raise ValueError( "Cannot infer original voxel size for reslicing... " "set mri_resolution to boolean value or apply morph first.") # Now deal with the fact that we may have multiple sub-volumes inuse = [morph[k]['inuse'] for k in range(len(morph))] src_shape = [morph[k]['shape'] for k in range(len(morph))] assert len(set(map(tuple, src_shape))) == 1 morph = BunchConst(src_data=_get_src_data(morph)[0]) else: # Make a list as we may have many inuse when using multiple sub-volumes inuse = [morph.src_data['inuse']] n_times = stc.data.shape[1] shape = morph.src_data['src_shape'][::-1] + (n_times,) # SAR->RAST vols = np.zeros((np.prod(shape[:3]), shape[3]), order='F') # flatten n_vertices_seen = 0 for this_inuse in inuse: this_inuse = this_inuse.astype(np.bool) n_vertices = np.sum(this_inuse) stc_slice = slice(n_vertices_seen, n_vertices_seen + n_vertices) vols[this_inuse] = stc.data[stc_slice] n_vertices_seen += n_vertices # use mri resolution as represented in src if mri_resolution: shape = morph.src_data['src_shape_full'][::-1] + (n_times,) vols = _csr_dot( morph.src_data['interpolator'], vols, np.zeros((np.prod(shape[:3]), shape[3]), order='F')) # reshape back to proper shape vols = np.reshape(vols, shape, order='F') # set correct space if mri_resolution: affine = morph.src_data['src_affine_vox'] else: affine = morph.src_data['src_affine_src'] if mri_space: affine = np.dot(morph.src_data['src_affine_ras'], affine) affine[:3] *= 1e3 # pre-define header header = NiftiHeader() header.set_xyzt_units('mm', 'msec') header['pixdim'][4] = 1e3 * stc.tstep with warnings.catch_warnings(): # nibabel<->numpy warning img = NiftiImage(vols, affine, header=header) # if a specific voxel size was targeted (only possible after morphing) if voxel_size_defined: # reslice mri img, img_affine = reslice( _get_img_fdata(img), img.affine, _get_zooms_orig(morph), voxel_size) with warnings.catch_warnings(): # nibabel<->numpy warning img = NiftiImage(img, img_affine, header=header) return img
def _interpolate_data(stc, morph, mri_resolution=True, mri_space=True, output='nifti1'): """Interpolate source estimate data to MRI.""" _check_dep(nibabel='2.1.0', dipy=False) if output not in ('nifti', 'nifti1', 'nifti2'): raise ValueError("invalid output specifier %s. Must be 'nifti1' or" " 'nifti2'" % output) if output in ('nifti', 'nifti1'): from nibabel import (Nifti1Image as NiftiImage, Nifti1Header as NiftiHeader) else: assert output == 'nifti2' from nibabel import (Nifti2Image as NiftiImage, Nifti2Header as NiftiHeader) assert morph.kind == 'volume' voxel_size_defined = False if isinstance(mri_resolution, (int, float)) and not isinstance( mri_resolution, bool): # use iso voxel size mri_resolution = (float(mri_resolution),) * 3 if isinstance(mri_resolution, tuple): _check_dep(nibabel=False, dipy='0.10.1') # nibabel was already checked from dipy.align.reslice import reslice voxel_size = mri_resolution voxel_size_defined = True mri_resolution = True # if data wasn't morphed yet - necessary for call of # stc_unmorphed.as_volume. Since only the shape of src is known, it cannot # be resliced to a given voxel size without knowing the original. if isinstance(morph, SourceSpaces): assert morph.kind == 'volume' if voxel_size_defined: raise ValueError( "Cannot infer original voxel size for reslicing... " "set mri_resolution to boolean value or apply morph first.") from mne.io.constants import BunchConst # Now deal with the fact that we may have multiple sub-volumes inuse = [morph[k]['inuse'] for k in range(len(morph))] src_shape = [morph[k]['shape'] for k in range(len(morph))] assert len(set(map(tuple, src_shape))) == 1 morph = BunchConst(src_data=_get_src_data(morph)[0]) else: # Make a list as we may have many inuse when using multiple sub-volumes inuse = [morph.src_data['inuse']] shape3d = morph.src_data['src_shape'] # setup volume parameters n_times = stc.data.shape[1] shape = (n_times,) + shape3d vols = np.zeros(shape) n_vertices_seen = 0 for this_inuse in inuse: mask3d = this_inuse.reshape(shape3d).astype(np.bool) n_vertices = np.sum(mask3d) stc_slice = slice(n_vertices_seen, n_vertices_seen + n_vertices) for k, vol in enumerate(vols): # loop over time instants vol[mask3d] = stc.data[stc_slice, k] n_vertices_seen += n_vertices # use mri resolution as represented in src if mri_resolution: mri_shape3d = morph.src_data['src_shape_full'] mri_shape = (n_times,) + mri_shape3d mri_vol = np.zeros(mri_shape) interpolator = morph.src_data['interpolator'] for k, vol in enumerate(vols): mri_vol[k] = (interpolator * vol.ravel()).reshape(mri_shape3d) vols = mri_vol vols = vols.T # set correct space affine = morph.src_data['src_affine_vox'] if not mri_resolution: affine = morph.src_data['src_affine_src'] if mri_space: affine = np.dot(morph.src_data['src_affine_ras'], affine) affine[:3] *= 1e3 # pre-define header header = NiftiHeader() header.set_xyzt_units('mm', 'msec') header['pixdim'][4] = 1e3 * stc.tstep with warnings.catch_warnings(): # nibabel<->numpy warning img = NiftiImage(vols, affine, header=header) # if a specific voxel size was targeted (only possible after morphing) if voxel_size_defined: # reslice mri img, img_affine = reslice( img.get_data(), img.affine, _get_zooms_orig(morph), voxel_size) with warnings.catch_warnings(): # nibabel<->numpy warning img = NiftiImage(img, img_affine, header=header) return img
def _morphed_stc_as_volume(morph, stc, mri_resolution=False, mri_space=True, output='nifti1'): """Return volume source space as Nifti1Image and/or save to disk.""" if not isinstance(stc, VolSourceEstimate): raise ValueError('Only volume source estimates can be converted to ' 'volumes') _check_dep(nibabel='2.1.0', dipy=False) known_types = ('nifti', 'nifti1', 'nifti2') if output not in known_types: raise ValueError('output must be one of %s, got %s' % (known_types, output)) if output in ('nifti', 'nifti1'): from nibabel import (Nifti1Image as NiftiImage, Nifti1Header as NiftiHeader) else: assert output == 'nifti2' from nibabel import (Nifti2Image as NiftiImage, Nifti2Header as NiftiHeader) new_zooms = None # if full MRI resolution, compute zooms from shape and MRI zooms if isinstance(mri_resolution, bool) and mri_resolution: new_zooms = _get_zooms_orig(morph) # if MRI resolution is set manually as a single value, convert to tuple if isinstance(mri_resolution, (int, float)) and not isinstance( mri_resolution, bool): # use iso voxel size new_zooms = (float(mri_resolution),) * 3 # if MRI resolution is set manually as a tuple, use it if isinstance(mri_resolution, tuple): new_zooms = mri_resolution # create header hdr = NiftiHeader() hdr.set_xyzt_units('mm', 'msec') hdr['pixdim'][4] = 1e3 * stc.tstep # setup empty volume img = np.zeros(morph.shape + (stc.shape[1],)).reshape(-1, stc.shape[1]) img[stc.vertices, :] = stc.data img = img.reshape(morph.shape + (-1,)) # make nifti from data with warnings.catch_warnings(): # nibabel<->numpy warning img = NiftiImage(img, morph.affine, header=hdr) # reslice in case of manually defined voxel size zooms = morph.zooms[:3] if new_zooms is not None: from dipy.align.reslice import reslice new_zooms = new_zooms[:3] img, affine = reslice(img.get_data(), img.affine, # MRI to world registration zooms, # old voxel size in mm new_zooms) # new voxel size in mm with warnings.catch_warnings(): # nibabel<->numpy warning img = NiftiImage(img, affine) zooms = new_zooms # set zooms in header img.header.set_zooms(tuple(zooms) + (1,)) return img