Пример #1
0
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
Пример #2
0
    def __init__(self, param=None, hdr=None, orientation=None, absolutepath=None, dim=None, verbose=1):
        from nibabel import Nifti1Header

        # initialization of all parameters
        self.im_file = None
        self.data = None
        self._path = None
        self.ext = ""

        if hdr is None:
            hdr = self.hdr = Nifti1Header()  # an empty header
        else:
            self.hdr = hdr

        if absolutepath is not None:
            self._path = os.path.abspath(absolutepath)

        self.verbose = verbose

        # load an image from file
        if isinstance(param, str) or (sys.hexversion < 0x03000000 and isinstance(param, unicode)):
            self.loadFromPath(param, verbose)
        # copy constructor
        elif isinstance(param, type(self)):
            self.copy(param)
        # create an empty image (full of zero) of dimension [dim]. dim must be [x,y,z] or (x,y,z). No header.
        elif isinstance(param, list):
            self.data = np.zeros(param)
            self.hdr = hdr
        # create a copy of im_ref
        elif isinstance(param, (np.ndarray, np.generic)):
            self.data = param
            self.hdr = hdr
        else:
            raise TypeError('Image constructor takes at least one argument.')
Пример #3
0
def test_output_dtypes():
    shape = (4, 2, 3)
    rng = np.random.RandomState(19441217)  # IN-S BD
    data = rng.normal(4, 20, size=shape)
    aff = np.diag([2.2, 3.3, 4.1, 1])
    cmap = vox2mni(aff)
    img = Image(data, cmap)
    fname_root = 'my_file'
    with InTemporaryDirectory():
        for ext in 'img', 'nii':
            out_fname = fname_root + '.' + ext
            # Default is for data to come from data dtype
            save_image(img, out_fname)
            img_back = load_image(out_fname)
            hdr = img_back.metadata['header']
            assert_dt_no_end_equal(hdr.get_data_dtype(), np.float)
            del img_back  # lets window re-use the file
            # All these types are OK for both output formats
            for out_dt in 'i2', 'i4', np.int16, '<f4', '>f8':
                # Specified output dtype
                save_image(img, out_fname, out_dt)
                img_back = load_image(out_fname)
                hdr = img_back.metadata['header']
                assert_dt_no_end_equal(hdr.get_data_dtype(), out_dt)
                del img_back  # windows file re-use
                # Output comes from data by default
                data_typed = data.astype(out_dt)
                img_again = Image(data_typed, cmap)
                save_image(img_again, out_fname)
                img_back = load_image(out_fname)
                hdr = img_back.metadata['header']
                assert_dt_no_end_equal(hdr.get_data_dtype(), out_dt)
                del img_back
                # Even if header specifies otherwise
                in_hdr = Nifti1Header()
                in_hdr.set_data_dtype(np.dtype('c8'))
                img_more = Image(data_typed, cmap, metadata={'header': in_hdr})
                save_image(img_more, out_fname)
                img_back = load_image(out_fname)
                hdr = img_back.metadata['header']
                assert_dt_no_end_equal(hdr.get_data_dtype(), out_dt)
                del img_back
                # But can come from header if specified
                save_image(img_more, out_fname, dtype_from='header')
                img_back = load_image(out_fname)
                hdr = img_back.metadata['header']
                assert_dt_no_end_equal(hdr.get_data_dtype(), 'c8')
                del img_back
        # u2 only OK for nifti
        save_image(img, 'my_file.nii', 'u2')
        img_back = load_image('my_file.nii')
        hdr = img_back.metadata['header']
        assert_dt_no_end_equal(hdr.get_data_dtype(), 'u2')
        # Check analyze can't save u2 datatype
        assert_raises(HeaderDataError, save_image, img, 'my_file.img', 'u2')
        del img_back
Пример #4
0
def parse_descrip(header: nib.Nifti1Header) -> dict[str, float]:
    descrip_dict = dict()

    descrip_array = header.get("descrip")
    assert isinstance(descrip_array, np.ndarray)
    descrip = descrip_array.tolist().decode()

    for m in descrip_pattern.finditer(descrip):

        var_name = m.group("var_name")
        value = m.group("value")
        unit = m.group("unit")

        assert isinstance(var_name, str)

        var_name = var_name.lower()
        value = float(value)

        key = None

        if var_name == "te":
            if unit is None:
                if value < 1:  # heuristic
                    unit = "s"
                else:
                    unit = "ms"

            key = "echo_time"

        elif var_name == "tr":
            if unit is None:
                if value > 100:  # heuristic
                    unit = "ms"
                else:
                    unit = "s"

            key = "repetition_time"

        if key is not None:
            base_quantity = ureg(unit)
            assert isinstance(base_quantity, pint.Quantity)

            quantity = value * base_quantity

            descrip_dict[key] = quantity.m_as(ureg.seconds)

    return descrip_dict
Пример #5
0
    def from_h5obj(cls, fileobj, check=True):
        """Read the struct from a file object."""
        xfm_list = []
        h5group = fileobj["TransformGroup"]
        typo_fallback = "Transform"
        try:
            h5group["1"][f"{typo_fallback}Parameters"]
        except KeyError:
            typo_fallback = "Tranform"

        for xfm in list(h5group.values())[1:]:
            if xfm["TransformType"][0].startswith(b"AffineTransform"):
                _params = np.asanyarray(xfm[f"{typo_fallback}Parameters"])
                xfm_list.append(
                    ITKLinearTransform(
                        parameters=from_matvec(_params[:-3].reshape(3, 3),
                                               _params[-3:]),
                        offset=np.asanyarray(
                            xfm[f"{typo_fallback}FixedParameters"]),
                    ))
                continue
            if xfm["TransformType"][0].startswith(
                    b"DisplacementFieldTransform"):
                _fixed = np.asanyarray(xfm[f"{typo_fallback}FixedParameters"])
                shape = _fixed[:3].astype("uint16").tolist()
                offset = _fixed[3:6].astype("uint16")
                zooms = _fixed[6:9].astype("float")
                directions = _fixed[9:].astype("float").reshape((3, 3))
                affine = from_matvec(directions * zooms, offset)
                field = np.asanyarray(
                    xfm[f"{typo_fallback}Parameters"]).reshape(
                        tuple(shape + [1, -1]))
                hdr = Nifti1Header()
                hdr.set_intent("vector")
                hdr.set_data_dtype("float")

                xfm_list.append(
                    ITKDisplacementsField.from_image(
                        Nifti1Image(field.astype("float"), affine, hdr)))
                continue

            raise NotImplementedError(
                f"Unsupported transform type {xfm['TransformType'][0]}")

        return xfm_list
Пример #6
0
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
Пример #7
0
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
Пример #8
0
def save_ics(icas, mask, threshold, output_dir, header, mean=None):
    """ Save the independant compnents to Nifti.

        Parameters
        -----------
        icas: 2D ndarray
            The independant components, as returned by CanICA.
        mask: 3D ndarray
            The 3D boolean array used to go from index to voxel space for
            each IC.
        threshold: float
            The threshold value used to threshold the ICs
        output_dir: string
            The directory in which maps and nifti files will be saved.
        header: dictionnary or Nifti1Header object
            The header for the nifti file, as returned by pynifti's
            header attribute, or
            nipy.io.imageformats.load().get_header().
    """
    # put in order n_ic, n_voxels
    icas = icas.T
    mask = mask.astype(np.bool)

    try:
        affine = header.get_best_affine()
    except:
        affine = header['sform']
        # XXX: I don't know how to convert a dictionnary to a
        # Nifti1Header.
        h = Nifti1Header()
        for k, v in header.iteritems():
            try:
                h[k] = v
            except ValueError:
                pass
        header = h

    header['cal_max'] = np.nanmax(icas)
    header['cal_min'] = np.nanmin(icas)

    if not os.path.exists(output_dir):
        os.mkdir(output_dir)

    icas = icas.copy()
    for ic in icas:
        ic *= auto_sign(ic, threshold=threshold)

    maps3d = np.zeros(list(mask.shape) + [len(icas)])

    maps3d[mask] = icas.T
    save(Nifti1Image(maps3d, affine, header=header),
         pjoin(output_dir, 'icas_no_thr.nii'))
    maps3d[np.abs(maps3d) < threshold] = 0
    save(Nifti1Image(maps3d, affine, header=header),
         pjoin(output_dir, 'icas.nii'))

    # Save the mask
    mask_header = header.copy()
    mask_header['cal_min'] = 0
    mask_header['cal_max'] = 1
    save(Nifti1Image(mask.astype(np.int), affine, header=mask_header),
         pjoin(output_dir, 'mask.nii'))

    if mean is not None:
        # save the mean
        mean_img = np.zeros(maps3d.shape[:-1])
        mean_img[mask] = mean
        mean_header = header.copy()
        mean_header['cal_min'] = mean.min()
        mean_header['cal_max'] = mean.max()
        save(Nifti1Image(mean_img, affine, header=mean_header),
             pjoin(output_dir, 'mean.nii'))
        return maps3d, affine, mean_img

    return maps3d, affine
Пример #9
0
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
Пример #10
0
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
Пример #11
0
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