Ejemplo n.º 1
0
def collapse_mask(mask, auto_label=True, custom_mask=None):
    """collapse separate masks into one mask with multiple integers
        overlapping areas are ignored

    Args:
        mask: nibabel or Brain_Data instance
        custom_mask: nibabel instance or string to file path; optional

    Returns:
        out: Brain_Data instance of a mask with different integers indicating
            different masks

    """

    from nltools.data import Brain_Data

    if not isinstance(mask, Brain_Data):
        if isinstance(mask, nib.Nifti1Image):
            mask = Brain_Data(mask, mask=custom_mask)
        else:
            raise ValueError("Make sure mask is a nibabel or Brain_Data "
                             "instance.")

    if len(mask.shape()) > 1:
        if len(mask) > 1:
            out = mask.empty()

            # Create list of masks and find any overlaps
            m_list = []
            for x in range(len(mask)):
                m_list.append(mask[x].to_nifti())
            intersect = intersect_masks(m_list, threshold=1, connected=False)
            intersect = Brain_Data(
                nib.Nifti1Image(np.abs(intersect.get_data() - 1),
                                intersect.get_affine()),
                mask=custom_mask,
            )

            merge = []
            if auto_label:
                # Combine all masks into sequential order
                # ignoring any areas of overlap
                for i in range(len(m_list)):
                    merge.append(
                        np.multiply(
                            Brain_Data(m_list[i], mask=custom_mask).data,
                            intersect.data) * (i + 1))
                out.data = np.sum(np.array(merge).T, 1).astype(int)
            else:
                # Collapse masks using value as label
                for i in range(len(m_list)):
                    merge.append(
                        np.multiply(
                            Brain_Data(m_list[i], mask=custom_mask).data,
                            intersect.data))
                out.data = np.sum(np.array(merge).T, 1)
            return out
    else:
        warnings.warn("Doesn't need to be collapased")
Ejemplo n.º 2
0
def create_sphere(coordinates, radius=5, mask=None):
    """ Generate a set of spheres in the brain mask space

    Args:
        radius: vector of radius.  Will create multiple spheres if
                len(radius) > 1
        centers: a vector of sphere centers of the form [px, py, pz] or
                [[px1, py1, pz1], ..., [pxn, pyn, pzn]]

    """
    from nltools.data import Brain_Data

    if mask is not None:
        if not isinstance(mask, nib.Nifti1Image):
            if type(mask) is str:
                if os.path.isfile(mask):
                    data = nib.load(mask)
            else:
                raise ValueError("mask is not a nibabel instance or a valid "
                                 "file name")
    else:
        mask = nib.load(
            os.path.join(get_resource_path(),
                         'MNI152_T1_2mm_brain_mask.nii.gz'))
    dims = mask.get_data().shape

    def sphere(r, p, mask):
        """ create a sphere of given radius at some point p in the brain mask

        Args:
            r: radius of the sphere
            p: point (in coordinates of the brain mask) of the center of the
                sphere

        """
        dims = mask.shape
        m = [dims[0] / 2, dims[1] / 2,
             dims[2] / 2]  # JC edit: default value for centers
        x, y, z = np.ogrid[-m[0]:dims[0] - m[0], -m[1]:dims[1] - m[1],
                           -m[2]:dims[2] - m[2]]  #JC edit: creates sphere
        # x, y, z = np.ogrid[-p[0]:dims[0]-p[0], -p[1]:dims[1]-p[1], -p[2]:dims[2]-p[2]]
        mask_r = x * x + y * y + z * z <= r * r

        activation = np.zeros(dims)
        activation[mask_r] = 1
        # JC edit shift mask to proper location
        translation_affine = np.array([[1, 0, 0, p[0] - m[0]],
                                       [0, 1, 0, p[1] - m[1]],
                                       [0, 0, 1, p[2] - m[2]], [0, 0, 0, 1]])

        # activation = np.multiply(activation, mask.get_data())
        # activation = nib.Nifti1Image(activation, affine=np.eye(4))
        activation = nib.Nifti1Image(activation, affine=translation_affine)
        #return the 3D numpy matrix of zeros containing the sphere as a region of ones
        # return activation.get_data(), translation_affine
        return activation

    # Initialize Spheres with options for multiple radii and centers of the spheres (or just an int and a 3D list)
    # return sphere(radius,coordinates,mask)
    if type(radius) is int:
        radius = [radius]
    if coordinates is None:
        coordinates = [[dims[0] / 2, dims[1] / 2, dims[2] / 2] * len(radius)
                       ]  #default value for centers
    elif type(coordinates) is list and type(
            coordinates[0]) is int and len(radius) is 1:
        coordinates = [coordinates]
    if (type(radius)) is list and (type(coordinates) is
                                   list) and (len(radius) == len(coordinates)):
        A = np.zeros_like(mask.get_data())
        A = Brain_Data(nib.Nifti1Image(A, affine=mask.affine), mask=mask)
        for i in range(len(radius)):
            A = A + Brain_Data(sphere(radius[i], coordinates[i], mask),
                               mask=mask)
        A = A.to_nifti()
        A.get_data()[A.get_data() > 0.5] = 1
        A.get_data()[A.get_data() < 0.5] = 0
        return A
    else:
        raise ValueError("Data type for sphere or radius(ii) or center(s) "
                         "not recognized.")
Ejemplo n.º 3
0
def create_sphere(coordinates, radius=5, mask=None):
    """Generate a set of spheres in the brain mask space

    Args:
        radius: vector of radius.  Will create multiple spheres if
                len(radius) > 1
        centers: a vector of sphere centers of the form [px, py, pz] or
                [[px1, py1, pz1], ..., [pxn, pyn, pzn]]

    """
    from nltools.data import Brain_Data

    if mask is not None:
        if not isinstance(mask, nib.Nifti1Image):
            if isinstance(mask, str):
                if os.path.isfile(mask):
                    mask = nib.load(mask)
            else:
                raise ValueError("mask is not a nibabel instance or a valid "
                                 "file name")

    else:
        mask = nib.load(resolve_mni_path(MNI_Template)["mask"])

    def sphere(r, p, mask):
        """create a sphere of given radius at some point p in the brain mask

        Args:
            r: radius of the sphere
            p: point (in coordinates of the brain mask) of the center of the
                sphere

        """
        dims = mask.shape
        m = [dims[0] / 2, dims[1] / 2, dims[2] / 2]
        x, y, z = np.ogrid[-m[0]:dims[0] - m[0], -m[1]:dims[1] - m[1],
                           -m[2]:dims[2] - m[2]]
        mask_r = x * x + y * y + z * z <= r * r

        activation = np.zeros(dims)
        activation[mask_r] = 1
        translation_affine = np.array([
            [1, 0, 0, p[0] - m[0]],
            [0, 1, 0, p[1] - m[1]],
            [0, 0, 1, p[2] - m[2]],
            [0, 0, 0, 1],
        ])

        return nib.Nifti1Image(activation, affine=translation_affine)

    if any(isinstance(i, list) for i in coordinates):
        if isinstance(radius, list):
            if len(radius) != len(coordinates):
                raise ValueError("Make sure length of radius list matches"
                                 "length of coordinate list.")
        elif isinstance(radius, int):
            radius = [radius] * len(coordinates)
        out = Brain_Data(
            nib.Nifti1Image(np.zeros_like(mask.get_data()),
                            affine=mask.affine),
            mask=mask,
        )
        for r, c in zip(radius, coordinates):
            out = out + Brain_Data(sphere(r, c, mask), mask=mask)
    else:
        out = Brain_Data(sphere(radius, coordinates, mask), mask=mask)
    out = out.to_nifti()
    out.get_data()[out.get_data() > 0.5] = 1
    out.get_data()[out.get_data() < 0.5] = 0
    return out