def _check_dtype(self, nii: nib.Nifti1Image) -> nib.Nifti1Image: """ Checks the NIfTI header datatype and converts the data to the matching numpy dtype. Parameters ---------- nii : nib.Nifti1Image Input image Returns ------- nib.Nifti1Image Converted input image """ header = nii.header.copy() datatype = int(header["datatype"]) self._warn_suspicious_dtype(datatype) try: dtype = NUMPY_DTYPE[datatype] except KeyError: return nii else: header.set_data_dtype(dtype) converted = nii.get_data().astype(dtype) return nib.Nifti1Image(converted, nii.affine, header)
def resample_nii(nifti: nib.Nifti1Image, new_pix_dims: Tuple[float, ...], num_workers: int) -> Tuple[np.ndarray, ...]: "Resamples nifti pixels to new_pix_dims and returns the new array and new affine using num_workers threads." return reslice(nifti.get_data(), nifti.affine, nifti.header.get_zooms(), new_pix_dims, num_processes=num_workers)
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 morph = BunchConst(src_data=_get_src_data(morph)[0]) # setup volume parameters n_times = stc.data.shape[1] shape3d = morph.src_data['src_shape'] shape = (n_times,) + shape3d vols = np.zeros(shape) mask3d = morph.src_data['inuse'].reshape(shape3d).astype(np.bool) n_vertices = np.sum(mask3d) n_vertices_seen = 0 for k, vol in enumerate(vols): # loop over time instants stc_slice = slice(n_vertices_seen, n_vertices_seen + n_vertices) 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
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 weight(echo: nib.Nifti1Image, TE: float): data = echo.get_data() mean = data[..., -n_vols:].mean(axis=-1) std = data[..., -n_vols:].std(axis=-1) return TE * mean / std