예제 #1
0
파일: mask.py 프로젝트: Vincent-Methot/dipy
def median_otsu(input_volume, median_radius=4, numpass=4, autocrop=False, b0Slices=None):
    """
    Simple brain extraction tool method for images from DWI data. It uses a
    median filter smoothing of the input_volumes b0Slices and an automatic
    histogram Otsu thresholding technique, hence the name medain_otsu.

    It mimics the MRtrix bet from the documentation.
    (mrconvert dwi.nii -coord 3 0 - | threshold - - | median3D - - | median3D - mask.nii)
    MRtrix uses default mean_radius=3 and numpass=2

    However, from tests on multiple 1.5T and 3T data from
    GE, Philips, Siemens, the most robust choice is median_radius=4, numpass=4

    Parameters
    ----------
    input_volume : ndarray
        ndarray of the brain volume
    median_radius : int
        Radius (in voxels) of the applied median filter(default 4)
    numpass: int
        Number of pass of the median filter (default 4)
    autocrop: bool, optional
        if True, the masked input_volume will also be cropped using the bounding
        box defined by the masked data. Should be on if DWI is upsampled to 1x1x1
        resolution. (default False)
    b0Slices : array
        1D array representing indexes of the volume where b=0

    Returns
    -------
    maskedvolume : ndarray
        Masked input_volume
    mask : 3D ndarray
        The binary brain mask
    """

    if len(input_volume.shape) == 4:
        if b0Slices is not None:
            b0vol = np.mean(input_volume[..., tuple(b0Slices)], axis=3)
        else:
            b0vol = input_volume[..., 0].copy()
    else:
        b0vol = input_volume.copy()

    # Make a mask using a multiple pass median filter and histogram thresholding.
    mask = multi_median(b0vol, median_radius, numpass)
    thresh = otsu(mask)
    mask = binary_threshold(mask, thresh)

    # Auto crop the volumes using the mask as input_volume for bounding box computing.
    if autocrop:
        mins, maxs = bounding_box(mask)
        mask = crop(mask, mins, maxs)
        croppedvolume = crop(input_volume, mins, maxs)
        maskedvolume = applymask(croppedvolume, mask)
    else:
        maskedvolume = applymask(input_volume, mask)

    return maskedvolume, mask
예제 #2
0
def nuclear_dots(file, t=0, c='g'):
    '''
    t: threshold
    c: color, 'r', 'g', 'b'
    '''
    im = imread(file)[:, :, RGB[c]]
    if t == 0:
        t = otsu(im)
    return label(im >= t)
예제 #3
0
def edited_to_segmentation(tivfn, brfn, s0fn):
    outfn = tivfn.replace('.nii', '_segmentation.nii')
    brnii = nib.load(brfn)
    brain = brnii.get_data()
    tiv = nib.load(tivfn).get_data()
    seg = np.zeros_like(tiv)
    csf = tiv.copy()
    csf[brain > 0] = 0
    s0 = nib.load(s0fn).get_data()
    s0[s0 < 0.01] = 0.01
    csf_other_thresh = np.exp(otsu(np.log(s0[csf > 0])))
    other = csf.copy()
    csf[s0 < csf_other_thresh] = 0
    other[csf > 0] = 0
    seg[brain > 0] = 1
    seg[csf > 0] = 2
    seg[other > 0] = 3
    nib.save(nib.Nifti1Image(seg, brnii.affine), outfn)
    return outfn
예제 #4
0
def remove_disconnected_components(mask,
                                   aff=None,
                                   dilrad=0,
                                   inplace=True,
                                   verbose=False,
                                   nkeep=1,
                                   weight=None):
    """
    Return a version of mask with all but the largest nkeep regions removed.

    Parameters
    ----------
    mask: array-like
        3D array which is true where there is a component, and 0 elsewhere.
    aff: None or 4x4 float array
        The voxel-to-world coordinate affine array of the mask.
        Must be given if dilrad > 0.
    dilrad: float
        Radius in aff's units (mm by the Nifti standard) to dilate by
        before determining how mask's voxels are connected.  This does not
        affect mask (even if inplace is True), just a copy used in finding
        connected components.  A moderate radius will ensure that tenuously
        tethered components are considered to be connected, but too large a
        radius will make everything appear connected.
    inplace: bool
        Whether to operate on mask in place or return a new array.
    verbose: bool
        Chattiness controller
    nkeep: None or int > 0
        Keep the nkeep largest components. If None it will be determined by Otsu
        thresholding the region sizes, optionally weighted by weight.
    weight: None or array-like
        An optional image with the same shape as mask which can be used to
        weight regions if nkeep is None. It is useful for preferring bright
        medium regions over large regions just above 0.

    Output
    ------
    mask: array-like
        3D array which is true for the largest component, and 0 elsewhere.
    """
    if verbose:
        print("Removing disconnected components")
    cmask = mask.copy()
    if aff is None:
        aff = np.eye(4)
    if dilrad:
        ball = make_structural_sphere(aff, dilrad)
        # Closing isn't really necessary since mask itself is not dilated.
        cmask = ndi.morphology.binary_dilation(cmask, ball)
    labelled, nb_labels = ndi.label(cmask)
    if verbose:
        print("Found %d components" % nb_labels)
    del cmask

    labels = np.arange(1, nb_labels + 1)
    if weight is None:
        weight = np.ones(mask.shape)
    sizes = np.array([weight[labelled == label].sum() for label in labels])
    if nkeep is None:
        if len(sizes) > 1:
            thresh = otsu(sizes)
            nkeep = max(1, len(sizes[sizes > thresh]))
        else:
            nkeep = 1
    keep_indices = np.argpartition(
        sizes, -nkeep)[-nkeep:]  # O(n), requires numpy >= 1.8

    if inplace:
        mymask = mask
    else:
        mymask = mask.copy()
    mymask[mask > 0] = 0
    for ki in keep_indices:
        mymask[labelled == labels[ki]] = 1
    return mymask
예제 #5
0
파일: mask.py 프로젝트: AndrewLawrence/dipy
def median_otsu(input_volume, median_radius=4, numpass=4,
                autocrop=False, vol_idx=None, dilate=None):
    """ Simple brain extraction tool method for images from DWI data

    It uses a median filter smoothing of the input_volumes `vol_idx` and an
    automatic histogram Otsu thresholding technique, hence the name
    *median_otsu*.

    This function is inspired from Mrtrix's bet which has default values
    ``median_radius=3``, ``numpass=2``. However, from tests on multiple 1.5T
    and 3T data     from GE, Philips, Siemens, the most robust choice is
    ``median_radius=4``, ``numpass=4``.

    Parameters
    ----------
    input_volume : ndarray
        ndarray of the brain volume
    median_radius : int
        Radius (in voxels) of the applied median filter(default 4)
    numpass: int
        Number of pass of the median filter (default 4)
    autocrop: bool, optional
        if True, the masked input_volume will also be cropped using the bounding
        box defined by the masked data. Should be on if DWI is upsampled to 1x1x1
        resolution. (default False)
    vol_idx : None or array, optional
        1D array representing indices of ``axis=3`` of a 4D `input_volume`
        None (the default) corresponds to ``(0,)`` (assumes first volume in 4D array)
    dilate : None or int, optional
        number of iterations for binary dilation

    Returns
    -------
    maskedvolume : ndarray
        Masked input_volume
    mask : 3D ndarray
        The binary brain mask
    """
    if len(input_volume.shape) == 4:
        if vol_idx is not None:
            b0vol = np.mean(input_volume[..., tuple(vol_idx)], axis=3)
        else:
            b0vol = input_volume[..., 0].copy()
    else:
        b0vol = input_volume.copy()
    # Make a mask using a multiple pass median filter and histogram thresholding.
    mask = multi_median(b0vol, median_radius, numpass)
    thresh = otsu(mask)
    mask = mask > thresh

    if dilate is not None:
        cross = generate_binary_structure(3, 1)
        mask = binary_dilation(mask, cross, iterations=dilate)

    # Auto crop the volumes using the mask as input_volume for bounding box computing.
    if autocrop:
        mins, maxs = bounding_box(mask)
        mask = crop(mask, mins, maxs)
        croppedvolume = crop(input_volume, mins, maxs)
        maskedvolume = applymask(croppedvolume, mask)
    else:
        maskedvolume = applymask(input_volume, mask)
    return maskedvolume, mask
예제 #6
0
    def guessFLAIRity(self):
        """
        Guess at whether data's contrast suppressed free water or not, i.e. return
        True for FLAIR DTI and False otherwise.  It operates by doing a rough
        segmentation of brain tissue and CSF, and checking whether the tissue is
        brighter than CSF for b ~ 0.

        Sets self.mask as a side-effect.
        """
        b = np.asarray(self.bvals)
        b0 = utils.calc_average_s0(self.data,
                                   b,
                                   self.relbthresh,
                                   estimator=np.median)
        embDt = np.exp(-b * self.Dt)
        embDCSF = np.exp(-b * self.DCSF)
        w = (embDt * (1.0 - embDCSF))**2
        tisssig = np.zeros(b0.shape)
        embb0s = {}
        sw = 0.0
        for v, emb in enumerate(embDCSF):
            if emb not in embb0s:
                embb0s[emb] = emb * b0
            tisssig += w[v] * (self.data[..., v] - embb0s[emb])
            sw += w[v]
        del embb0s
        tisssig /= sw

        # Don't use median_otsu because it assumes isotropic voxels.
        if self.nmed > 0:
            if self.medrad >= 1:
                ball = utils.make_structural_sphere(
                    self.aff, self.medrad * self.maxscale)
                if self.verbose:
                    print("Median filtering %d times with radius %f." %
                          (self.nmed, self.medrad * self.maxscale))
                for i in range(self.nmed):
                    tisssig = median_filter(tisssig, footprint=ball)
            elif self.medrad > 0:
                print("Warning: not median filtering since medrad < 1.")

        if self.verbose:
            print("Getting the Otsu threshold.")
        thresh = otsu(tisssig)
        self._mask = np.zeros(tisssig.shape, np.bool)
        self._mask[tisssig >= thresh] = 1

        ball = utils.make_structural_sphere(self.aff, max(10.0, self.maxscale))
        self._csfmask = utils.binary_closing(self._mask, ball)
        gaprad = max(self.closerad, 2 * self.maxscale)
        self._csfmask, success = utils.fill_holes(self._csfmask, self.aff,
                                                  gaprad, self.verbose)
        self._csfmask = utils.binary_opening(self._csfmask, ball)
        self._csfmask[self._mask > 0] = 0
        csfmed = np.median(b0[self._csfmask > 0])
        b0tiss = b0[self._mask > 0]

        # Now we have an approximate brain, and we know it is surrounded by CSF
        # (in vivo) or solution (ex vivo), which we'll call CSF.  Figure out
        # whether CSF is brighter or darker than tissue in the b0.
        tissmed = np.median(b0tiss)
        return tissmed > 2.0 * csfmed
예제 #7
0
파일: mask.py 프로젝트: wrgr/dipy
def median_otsu(input_volume,
                median_radius=4,
                numpass=4,
                autocrop=False,
                vol_idx=None,
                dilate=None):
    """Simple brain extraction tool method for images from DWI data.

    It uses a median filter smoothing of the input_volumes `vol_idx` and an
    automatic histogram Otsu thresholding technique, hence the name
    *median_otsu*.

    This function is inspired from Mrtrix's bet which has default values
    ``median_radius=3``, ``numpass=2``. However, from tests on multiple 1.5T
    and 3T data     from GE, Philips, Siemens, the most robust choice is
    ``median_radius=4``, ``numpass=4``.

    Parameters
    ----------
    input_volume : ndarray
        ndarray of the brain volume
    median_radius : int
        Radius (in voxels) of the applied median filter (default: 4).
    numpass: int
        Number of pass of the median filter (default: 4).
    autocrop: bool, optional
        if True, the masked input_volume will also be cropped using the
        bounding box defined by the masked data. Should be on if DWI is
        upsampled to 1x1x1 resolution. (default: False).
    vol_idx : None or array, optional
        1D array representing indices of ``axis=3`` of a 4D `input_volume` None
        (the default) corresponds to ``(0,)`` (assumes first volume in
        4D array).

    dilate : None or int, optional
        number of iterations for binary dilation

    Returns
    -------
    maskedvolume : ndarray
        Masked input_volume
    mask : 3D ndarray
        The binary brain mask

    Notes
    -----
    Copyright (C) 2011, the scikit-image team
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are
    met:

     1. Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
     2. Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in
        the documentation and/or other materials provided with the
        distribution.
     3. Neither the name of skimage nor the names of its contributors may be
        used to endorse or promote products derived from this software without
        specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.
    """
    if len(input_volume.shape) == 4:
        if vol_idx is not None:
            b0vol = np.mean(input_volume[..., tuple(vol_idx)], axis=3)
        else:
            b0vol = input_volume[..., 0].copy()
    else:
        b0vol = input_volume.copy()
    # Make a mask using a multiple pass median filter and histogram
    # thresholding.
    mask = multi_median(b0vol, median_radius, numpass)
    thresh = otsu(mask)
    mask = mask > thresh

    if dilate is not None:
        cross = generate_binary_structure(3, 1)
        mask = binary_dilation(mask, cross, iterations=dilate)

    # Auto crop the volumes using the mask as input_volume for bounding box
    # computing.
    if autocrop:
        mins, maxs = bounding_box(mask)
        mask = crop(mask, mins, maxs)
        croppedvolume = crop(input_volume, mins, maxs)
        maskedvolume = applymask(croppedvolume, mask)
    else:
        maskedvolume = applymask(input_volume, mask)
    return maskedvolume, mask
예제 #8
0
파일: mask.py 프로젝트: gsangui/dipy
def median_otsu(input_volume, median_radius=4, numpass=4,
                autocrop=False, b0Slices=None):
    """ Simple brain extraction tool method for images from DWI data

    It uses a median filter smoothing of the input_volumes `b0Slices` and an
    automatic histogram Otsu thresholding technique, hence the name
    *median_otsu*.

    It mimics the ``MRtrix`` bet from the documentation::

        mrconvert dwi.nii -coord 3 0 - | threshold - - | median3D - - | \
                median3D - mask.nii

    ``MRtrix`` uses default ``mean_radius=3`` and ``numpass=2``

    However, from tests on multiple 1.5T and 3T data from GE, Philips, Siemens,
    the most robust choice is ``median_radius=4``, ``numpass=4``

    Parameters
    ----------
    input_volume : ndarray
        ndarray of the brain volume
    median_radius : int
        Radius (in voxels) of the applied median filter(default 4)
    numpass: int
        Number of pass of the median filter (default 4)
    autocrop: bool, optional
        if True, the masked input_volume will also be cropped using the bounding
        box defined by the masked data. Should be on if DWI is upsampled to 1x1x1
        resolution. (default False)
    b0Slices : None or array, optional
        1D array representing indices of ``axis=3`` of a 4D `input_volume` where
        the acquisition b value == 0. None (the default) corresponds to ``(0,)``
        (assumes first volume in 4D array is b == 0)

    Returns
    -------
    maskedvolume : ndarray
        Masked input_volume
    mask : 3D ndarray
        The binary brain mask
    """
    if len(input_volume.shape) == 4:
        if b0Slices is not None:
            b0vol = np.mean(input_volume[..., tuple(b0Slices)], axis=3)
        else:
            b0vol = input_volume[..., 0].copy()
    else:
        b0vol = input_volume.copy()
    # Make a mask using a multiple pass median filter and histogram thresholding.
    mask = multi_median(b0vol, median_radius, numpass)
    thresh = otsu(mask)
    mask = mask > thresh
    # Auto crop the volumes using the mask as input_volume for bounding box computing.
    if autocrop:
        mins, maxs = bounding_box(mask)
        mask = crop(mask, mins, maxs)
        croppedvolume = crop(input_volume, mins, maxs)
        maskedvolume = applymask(croppedvolume, mask)
    else:
        maskedvolume = applymask(input_volume, mask)
    return maskedvolume, mask
예제 #9
0
파일: mask.py 프로젝트: Vincent-Methot/dipy
def median_otsu(input_volume,
                median_radius=4,
                numpass=4,
                autocrop=False,
                b0Slices=None):
    """
    Simple brain extraction tool method for images from DWI data. It uses a
    median filter smoothing of the input_volumes b0Slices and an automatic
    histogram Otsu thresholding technique, hence the name medain_otsu.

    It mimics the MRtrix bet from the documentation.
    (mrconvert dwi.nii -coord 3 0 - | threshold - - | median3D - - | median3D - mask.nii)
    MRtrix uses default mean_radius=3 and numpass=2

    However, from tests on multiple 1.5T and 3T data from
    GE, Philips, Siemens, the most robust choice is median_radius=4, numpass=4

    Parameters
    ----------
    input_volume : ndarray
        ndarray of the brain volume
    median_radius : int
        Radius (in voxels) of the applied median filter(default 4)
    numpass: int
        Number of pass of the median filter (default 4)
    autocrop: bool, optional
        if True, the masked input_volume will also be cropped using the bounding
        box defined by the masked data. Should be on if DWI is upsampled to 1x1x1
        resolution. (default False)
    b0Slices : array
        1D array representing indexes of the volume where b=0

    Returns
    -------
    maskedvolume : ndarray
        Masked input_volume
    mask : 3D ndarray
        The binary brain mask
    """

    if len(input_volume.shape) == 4:
        if b0Slices is not None:
            b0vol = np.mean(input_volume[..., tuple(b0Slices)], axis=3)
        else:
            b0vol = input_volume[..., 0].copy()
    else:
        b0vol = input_volume.copy()

    # Make a mask using a multiple pass median filter and histogram thresholding.
    mask = multi_median(b0vol, median_radius, numpass)
    thresh = otsu(mask)
    mask = binary_threshold(mask, thresh)

    # Auto crop the volumes using the mask as input_volume for bounding box computing.
    if autocrop:
        mins, maxs = bounding_box(mask)
        mask = crop(mask, mins, maxs)
        croppedvolume = crop(input_volume, mins, maxs)
        maskedvolume = applymask(croppedvolume, mask)
    else:
        maskedvolume = applymask(input_volume, mask)

    return maskedvolume, mask
예제 #10
0
def median_otsu(input_volume,
                median_radius=4,
                numpass=4,
                autocrop=False,
                vol_idx=None,
                dilate=None):
    """ Simple brain extraction tool method for images from DWI data

    It uses a median filter smoothing of the input_volumes `vol_idx` and an
    automatic histogram Otsu thresholding technique, hence the name
    *median_otsu*.

    This function is inspired from Mrtrix's bet which has default values
    ``median_radius=3``, ``numpass=2``. However, from tests on multiple 1.5T
    and 3T data     from GE, Philips, Siemens, the most robust choice is
    ``median_radius=4``, ``numpass=4``.

    Parameters
    ----------
    input_volume : ndarray
        ndarray of the brain volume
    median_radius : int
        Radius (in voxels) of the applied median filter(default 4)
    numpass: int
        Number of pass of the median filter (default 4)
    autocrop: bool, optional
        if True, the masked input_volume will also be cropped using the bounding
        box defined by the masked data. Should be on if DWI is upsampled to 1x1x1
        resolution. (default False)
    vol_idx : None or array, optional
        1D array representing indices of ``axis=3`` of a 4D `input_volume`
        None (the default) corresponds to ``(0,)`` (assumes first volume in 4D array)
    dilate : None or int, optional
        number of iterations for binary dilation

    Returns
    -------
    maskedvolume : ndarray
        Masked input_volume
    mask : 3D ndarray
        The binary brain mask
    """
    if len(input_volume.shape) == 4:
        if vol_idx is not None:
            b0vol = np.mean(input_volume[..., tuple(vol_idx)], axis=3)
        else:
            b0vol = input_volume[..., 0].copy()
    else:
        b0vol = input_volume.copy()
    # Make a mask using a multiple pass median filter and histogram thresholding.
    mask = multi_median(b0vol, median_radius, numpass)
    thresh = otsu(mask)
    mask = mask > thresh

    if dilate is not None:
        cross = generate_binary_structure(3, 1)
        mask = binary_dilation(mask, cross, iterations=dilate)

    # Auto crop the volumes using the mask as input_volume for bounding box computing.
    if autocrop:
        mins, maxs = bounding_box(mask)
        mask = crop(mask, mins, maxs)
        croppedvolume = crop(input_volume, mins, maxs)
        maskedvolume = applymask(croppedvolume, mask)
    else:
        maskedvolume = applymask(input_volume, mask)
    return maskedvolume, mask
예제 #11
0
파일: mask.py 프로젝트: ralphsol/dipy
def median_otsu(input_volume, median_radius=4, numpass=4,
                autocrop=False, vol_idx=None, dilate=None):
    """Simple brain extraction tool method for images from DWI data.

    It uses a median filter smoothing of the input_volumes `vol_idx` and an
    automatic histogram Otsu thresholding technique, hence the name
    *median_otsu*.

    This function is inspired from Mrtrix's bet which has default values
    ``median_radius=3``, ``numpass=2``. However, from tests on multiple 1.5T
    and 3T data     from GE, Philips, Siemens, the most robust choice is
    ``median_radius=4``, ``numpass=4``.

    Parameters
    ----------
    input_volume : ndarray
        ndarray of the brain volume
    median_radius : int
        Radius (in voxels) of the applied median filter (default: 4).
    numpass: int
        Number of pass of the median filter (default: 4).
    autocrop: bool, optional
        if True, the masked input_volume will also be cropped using the
        bounding box defined by the masked data. Should be on if DWI is
        upsampled to 1x1x1 resolution. (default: False).
    vol_idx : None or array, optional
        1D array representing indices of ``axis=3`` of a 4D `input_volume` None
        (the default) corresponds to ``(0,)`` (assumes first volume in
        4D array).

    dilate : None or int, optional
        number of iterations for binary dilation

    Returns
    -------
    maskedvolume : ndarray
        Masked input_volume
    mask : 3D ndarray
        The binary brain mask

    Notes
    -----
    Copyright (C) 2011, the scikit-image team
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are
    met:

     1. Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
     2. Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in
        the documentation and/or other materials provided with the
        distribution.
     3. Neither the name of skimage nor the names of its contributors may be
        used to endorse or promote products derived from this software without
        specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.
    """
    if len(input_volume.shape) == 4:
        if vol_idx is not None:
            b0vol = np.mean(input_volume[..., tuple(vol_idx)], axis=3)
        else:
            b0vol = input_volume[..., 0].copy()
    else:
        b0vol = input_volume.copy()
    # Make a mask using a multiple pass median filter and histogram
    # thresholding.
    mask = multi_median(b0vol, median_radius, numpass)
    thresh = otsu(mask)
    mask = mask > thresh

    if dilate is not None:
        cross = generate_binary_structure(3, 1)
        mask = binary_dilation(mask, cross, iterations=dilate)

    # Auto crop the volumes using the mask as input_volume for bounding box
    # computing.
    if autocrop:
        mins, maxs = bounding_box(mask)
        mask = crop(mask, mins, maxs)
        croppedvolume = crop(input_volume, mins, maxs)
        maskedvolume = applymask(croppedvolume, mask)
    else:
        maskedvolume = applymask(input_volume, mask)
    return maskedvolume, mask