コード例 #1
0
ファイル: utils.py プロジェクト: MICA-MNI/BrainStat
def mesh_edges(surf: Union[dict, BSPolyData, "SLM", Nifti1Image],
               mask: Optional[ArrayLike] = None) -> np.ndarray:
    """Converts the triangles or lattices of a mesh to edges.

    Parameters
    ----------
        surf : dict, BSPolyData, SLM, Nifti1Image
            One of the following:
             - A dictionary with key 'tri' where tri is numpy array of triangle indices, t:#triangles.
                Note that, for compatibility with SurfStat, these triangles are 1-indexed, not 0-indexed.
             - A dictionary with key 'lat' where lat is a 3D numpy array of 1's and 0's (1:in, 0:out).
             - A BrainSpace surface object
             - An SLM object with an associated surface.

    Returns
    -------
        np.ndarray
            A e-by-2 numpy array containing the indices of the edges, where
            e is the number of edges. Note that these are 0-indexed.
    """

    # Convert all inputs to a compatible dictionary, retain BSPolyData.
    if type(surf).__name__ == "SLM":
        if surf.tri is not None:  # type: ignore
            edg = triangles_to_edges(surf.tri)  # type: ignore
        elif surf.lat is not None:  # type: ignore
            edg = lattice_to_edges(surf.lat)  # type: ignore
        else:
            ValueError("SLM object does not have triangle/lattice data.")
    elif isinstance(surf, dict):
        if "tri" in surf:
            edg = triangles_to_edges(surf["tri"])
        if "lat" in surf:
            edg = lattice_to_edges(surf["lat"])
    elif isinstance(surf, Nifti1Image):
        if mask is not None:
            raise ValueError(
                "Masks are currently not compatible with a NIFTI image lattice input."
            )
        edg = lattice_to_edges(surf.get_fdata() != 0)
    elif isinstance(surf, BSPolyData):
        edg = get_edges(surf)
    else:
        raise ValueError("Unknown surface format.")

    if mask is not None:
        edg, _ = _mask_edges(edg, mask)

    return edg
コード例 #2
0
def generate_random_slm(surf,
                        n_var=1,
                        dfs=None,
                        mask=None,
                        cluster_threshold=0.001):
    """Generates a valid SLM for a surface.

    Parameters
    ----------
    surf : BSPolyData
        Brain surface.
    n_var : int, optional
        slm.k, by default 1.
    dfs : np.array, None, optional
        Effective degrees of freedom, by default None.
    mask : np.array, optional
        Boolean mask, by default None.
    cluster_threshold : float, optional
        Cluster threshold, by default 0.001.

    Returns
    -------
    brainstat.stats.SLM
        SLM object.
    """
    edges = get_edges(surf)
    vertices = get_points(surf)

    n_vertices = vertices.shape[0]
    n_edges = edges.shape[0]

    slm = generate_slm(
        t=np.random.random_sample((1, n_vertices)),
        df=np.random.randint(2, 100),
        k=n_var,
        resl=np.random.random_sample((n_edges, 1)),
        surf=surf,
        dfs=dfs,
        mask=mask,
        cluster_threshold=cluster_threshold,
    )
    return slm
コード例 #3
0
def test_mesh_elements():
    s = _generate_sphere()

    ee = vtk.vtkExtractEdges()
    ee.SetInputData(s.VTKObject)
    ee.Update()
    ee = wrap_vtk(ee.GetOutput())
    n_edges = ee.n_cells

    assert np.all(me.get_points(s) == s.Points)
    assert np.all(me.get_cells(s) == s.GetCells2D())
    assert me.get_extent(s).shape == (3, )

    pc = me.get_point2cell_connectivity(s)
    assert pc.shape == (s.n_points, s.n_cells)
    assert pc.dtype == np.uint8
    assert np.all(pc.sum(axis=0) == 3)

    cp = me.get_cell2point_connectivity(s)
    assert pc.dtype == np.uint8
    assert (pc - cp.T).nnz == 0

    adj = me.get_immediate_adjacency(s)
    assert adj.shape == (s.n_points, s.n_points)
    assert adj.dtype == np.uint8
    assert adj.nnz == (2 * n_edges + s.n_points)

    adj2 = me.get_immediate_adjacency(s, include_self=False)
    assert adj2.shape == (s.n_points, s.n_points)
    assert adj2.dtype == np.uint8
    assert adj2.nnz == (2 * n_edges)

    radj = me.get_ring_adjacency(s)
    assert radj.dtype == np.uint8
    assert (adj - radj).nnz == 0

    radj2 = me.get_ring_adjacency(s, include_self=False)
    assert radj2.dtype == np.uint8
    assert (adj2 - radj2).nnz == 0

    radj3 = me.get_ring_adjacency(s, n_ring=2, include_self=False)
    assert radj3.dtype == np.uint8
    assert (radj3 - adj2).nnz > 0

    d = me.get_immediate_distance(s)
    assert d.shape == (s.n_points, s.n_points)
    assert d.dtype == np.float
    assert d.nnz == adj2.nnz

    d2 = me.get_immediate_distance(s, metric='sqeuclidean')
    d_sq = d.copy()
    d_sq.data **= 2
    assert np.allclose(d_sq.A, d2.A)

    rd = me.get_ring_distance(s)
    assert rd.dtype == np.float
    assert np.allclose(d.A, rd.A)

    rd2 = me.get_ring_distance(s, n_ring=2)
    assert (rd2 - d).nnz > 0

    assert me.get_cell_neighbors(s).shape == (s.n_cells, s.n_cells)
    assert me.get_edges(s).shape == (n_edges, 2)
    assert me.get_edge_length(s).shape == (n_edges, )

    assert me.get_boundary_points(s).size == 0
    assert me.get_boundary_edges(s).size == 0
    assert me.get_boundary_cells(s).size == 0
コード例 #4
0
ファイル: SurfStatEdg.py プロジェクト: sdrakulich/BrainStat
def py_SurfStatEdg(surf):
    """Converts the triangles or lattices of a mesh to edges. 

	Args:
		surf (dict): = a dictionary with key 'tri' or 'lat'
	        surf['tri'] = (t x 3) numpy array of triangle indices, t:#triangles, or,
	        surf['lat'] = 3D numpy array of 1's and 0's (1:in, 0:out).
		or
		surf (BSPolyData) = a BrainSpace surface object. 
	Returns:
		edg (np.array): A e-by-2 numpy array containing the indices of the edges, where
  			e is the number of edges. 
	"""

    # For BSPolyData, simply use BrainSpace's functionality to grab edges.
    if isinstance(surf, BSPolyData):
        edg = get_edges(surf)

    # Convert triangles to edges by grabbing all unique edges within triangles.
    elif 'tri' in surf:
        tri = np.sort(surf['tri'], axis=1)
        edg =  np.unique(np.concatenate((np.concatenate((tri[:,[0, 1]], \
                         tri[:,[0, 2]])),  tri[:,[1, 2]] )) , axis=0)
        edg = edg - 1

    elif 'lat' in surf:
        # See the comments of SurfStatResels for a full explanation.
        if surf['lat'].ndim == 2:
            surf['lat'] = np.expand_dims(surf['lat'], axis=2)

        I, J, K = np.shape(surf['lat'])
        IJ = I * J

        a = np.arange(1, int(I) + 1, dtype='int')
        b = np.arange(1, int(J) + 1, dtype='int')

        i, j = np.meshgrid(a, b)
        i = i.T.flatten('F')
        j = j.T.flatten('F')

        n1 = (I - 1) * (J - 1) * 6 + (I - 1) * 3 + (J - 1) * 3 + 1
        n2 = (I - 1) * (J - 1) * 3 + (I - 1) + (J - 1)

        edg = np.zeros(((K - 1) * n1 + n2, int(2)), dtype='int')

        for f in range(0, 2):

            c1 = np.where((np.remainder((i + j), 2) == f) & (i < I)
                          & (j < J))[0]
            c2 = np.where((np.remainder((i + j), 2) == f) & (i > 1)
                          & (j < J))[0]
            c11 = np.where((np.remainder((i + j), 2) == f) & (i == I)
                           & (j < J))[0]
            c21 = np.where((np.remainder((i + j), 2) == f) & (i == I)
                           & (j > 1))[0]
            c12 = np.where((np.remainder((i + j), 2) == f) & (i < I)
                           & (j == J))[0]
            c22 = np.where((np.remainder((i + j), 2) == f) & (i > 1)
                           & (j == J))[0]

            # bottom slice
            edg0 = np.block([[ c1, c1, c1, c2-1, c2-1, c2, c11, c21-I, c12, \
                c22-1 ], [ c1+1, c1+I, c1+1+I, c2, c2-1+I, c2-1+I, \
                c11+I, c21, c12+1, c22 ]]).T +1
            # between slices
            edg1 = np.block([[ c1, c1, c1, c11, c11, c12, c12], [c1+IJ, c1+1+IJ, \
                c1+I+IJ, c11+IJ, c11+I+IJ, c12+IJ, c12+1+IJ ]]).T +1

            edg2 = np.block([[c2-1, c2, c2-1+I, c21-I, c21, c22-1, c22], \
                [c2-1+IJ, c2-1+IJ, c2-1+IJ, c21-I+IJ, c21-I+IJ, \
                c22-1+IJ, c22-1+IJ]]).T +1

            if f:
                for k in colon(2, K - 1, 2):
                    edg[(k-1)*n1 + np.arange(0,n1), :]  = (np.block([[edg0], \
                     [edg2], [edg1], [IJ, 2*IJ]]) + (k-1) *IJ)

            else:
                for k in colon(1, K - 1, 2):
                    edg[(k-1)*n1 + np.arange(0,n1), :]  = (np.block([[edg0], \
                     [edg1], [edg2], [IJ, 2*IJ]]) + (k-1) *IJ)

            if np.remainder((K + 1), 2) == f:
                # top slice
                edg[ (K-1)*n1 + np.arange(0,n2), :]  = \
                 edg0[np.arange(0,n2),:] + (K-1) * IJ

        # index by voxels in the "lat"
        vid = np.array(np.multiply(np.cumsum(surf['lat'][:].T.flatten()), \
         surf['lat'][:].T.flatten()) , dtype='int')
        vid = vid.reshape(len(vid), 1)

        # only inside the lat
        all_idx = np.all(np.block([[surf['lat'].T.flatten()[edg[:,0] -1]], \
         [surf['lat'].T.flatten()[edg[:,1] -1]]]).T, axis=1)

        edg = vid[edg[all_idx, :] - 1].reshape(np.shape(edg[all_idx, :] - 1))
        edg = edg - 1

    else:
        sys.exit(
            'Input "surf" must have "lat" or "tri" key, or be a mesh object.')

    return edg
コード例 #5
0
ファイル: utils.py プロジェクト: ReinderVosDeWael/BrainStat
def mesh_edges(surf, mask=None):
    """Converts the triangles or lattices of a mesh to edges.

    Args:
        surf (dict): = a dictionary with key 'tri' or 'lat'
        surf['tri'] = (t x 3) numpy array of triangle indices, t:#triangles, or,
        surf['lat'] = 3D numpy array of 1's and 0's (1:in, 0:out).
        or
        surf (BSPolyData) = a BrainSpace surface object
        or
        surf (SLM) = a SLM object with an associated surface.

    Returns:
        edg (np.array): A e-by-2 numpy array containing the indices of the edges, where
        e is the number of edges.
    """

    # This doesn't strictly test that its BrainStat SLM, but we can't import
    # directly without causing a circular import.
    class_name = surf.__class__.__name__
    if class_name is "SLM":
        if surf.tri is not None:
            surf = {"tri": surf.tri}
        elif surf.lat is not None:
            surf = {"lat": surf.lat}
        elif surf.surf is not None:
            return mesh_edges(surf.surf)
        else:
            ValueError("SLM object does not have triangle/lattice data.")

    # For BSPolyData, simply use BrainSpace's functionality to grab edges.
    if isinstance(surf, BSPolyData):
        edg = get_edges(surf)

    # Convert triangles to edges by grabbing all unique edges within triangles.
    elif "tri" in surf:
        tri = np.sort(surf["tri"], axis=1)
        edg = np.unique(
            np.concatenate(
                (np.concatenate((tri[:, [0, 1]], tri[:, [0, 2]])), tri[:, [1, 2]])
            ),
            axis=0,
        )
        edg = edg - 1

    elif "lat" in surf:
        # See the comments of SurfStatResels for a full explanation.
        if surf["lat"].ndim == 2:
            surf["lat"] = np.expand_dims(surf["lat"], axis=2)

        I, J, K = np.shape(surf["lat"])
        IJ = I * J

        a = np.arange(1, int(I) + 1, dtype="int")
        b = np.arange(1, int(J) + 1, dtype="int")

        i, j = np.meshgrid(a, b)
        i = i.T.flatten("F")
        j = j.T.flatten("F")

        n1 = (I - 1) * (J - 1) * 6 + (I - 1) * 3 + (J - 1) * 3 + 1
        n2 = (I - 1) * (J - 1) * 3 + (I - 1) + (J - 1)

        edg = np.zeros(((K - 1) * n1 + n2, int(2)), dtype="int")

        for f in range(0, 2):

            c1 = np.where((np.remainder((i + j), 2) == f) & (i < I) & (j < J))[0]
            c2 = np.where((np.remainder((i + j), 2) == f) & (i > 1) & (j < J))[0]
            c11 = np.where((np.remainder((i + j), 2) == f) & (i == I) & (j < J))[0]
            c21 = np.where((np.remainder((i + j), 2) == f) & (i == I) & (j > 1))[0]
            c12 = np.where((np.remainder((i + j), 2) == f) & (i < I) & (j == J))[0]
            c22 = np.where((np.remainder((i + j), 2) == f) & (i > 1) & (j == J))[0]

            # bottom slice
            edg0 = (
                np.block(
                    [
                        [c1, c1, c1, c2 - 1, c2 - 1, c2, c11, c21 - I, c12, c22 - 1],
                        [
                            c1 + 1,
                            c1 + I,
                            c1 + 1 + I,
                            c2,
                            c2 - 1 + I,
                            c2 - 1 + I,
                            c11 + I,
                            c21,
                            c12 + 1,
                            c22,
                        ],
                    ]
                ).T
                + 1
            )
            # between slices
            edg1 = (
                np.block(
                    [
                        [c1, c1, c1, c11, c11, c12, c12],
                        [
                            c1 + IJ,
                            c1 + 1 + IJ,
                            c1 + I + IJ,
                            c11 + IJ,
                            c11 + I + IJ,
                            c12 + IJ,
                            c12 + 1 + IJ,
                        ],
                    ]
                ).T
                + 1
            )

            edg2 = (
                np.block(
                    [
                        [c2 - 1, c2, c2 - 1 + I, c21 - I, c21, c22 - 1, c22],
                        [
                            c2 - 1 + IJ,
                            c2 - 1 + IJ,
                            c2 - 1 + IJ,
                            c21 - I + IJ,
                            c21 - I + IJ,
                            c22 - 1 + IJ,
                            c22 - 1 + IJ,
                        ],
                    ]
                ).T
                + 1
            )

            if f:
                for k in colon(2, K - 1, 2):
                    edg[(k - 1) * n1 + np.arange(0, n1), :] = (
                        np.block([[edg0], [edg2], [edg1], [IJ, 2 * IJ]]) + (k - 1) * IJ
                    )

            else:
                for k in colon(1, K - 1, 2):
                    edg[(k - 1) * n1 + np.arange(0, n1), :] = (
                        np.block([[edg0], [edg1], [edg2], [IJ, 2 * IJ]]) + (k - 1) * IJ
                    )

            if np.remainder((K + 1), 2) == f:
                # top slice
                edg[(K - 1) * n1 + np.arange(0, n2), :] = (
                    edg0[np.arange(0, n2), :] + (K - 1) * IJ
                )

        # index by voxels in the "lat"
        vid = np.array(
            np.multiply(
                np.cumsum(surf["lat"][:].T.flatten()), surf["lat"][:].T.flatten()
            ),
            dtype="int",
        )
        vid = vid.reshape(len(vid), 1)

        # only inside the lat
        all_idx = np.all(
            np.block(
                [
                    [surf["lat"].T.flatten()[edg[:, 0] - 1]],
                    [surf["lat"].T.flatten()[edg[:, 1] - 1]],
                ]
            ).T,
            axis=1,
        )

        edg = vid[edg[all_idx, :] - 1].reshape(np.shape(edg[all_idx, :] - 1))
        edg = edg - 1

    else:
        sys.exit('Input "surf" must have "lat" or "tri" key, or be a mesh object.')

    if mask is not None:
        edg, _ = _mask_edges(edg, mask)

    return edg