Esempio n. 1
0
def bench_suite():
    times = OrderedDict()
    skeleton = np.load(os.path.join(rundir, 'infected3.npz'))['skeleton']
    with timer() as t_build_graph:
        g, indices = csr.skeleton_to_csgraph(skeleton, spacing=2.24826)
    times['build graph'] = t_build_graph[0]
    with timer() as t_build_graph2:
        g, indices = csr.skeleton_to_csgraph(skeleton, spacing=2.24826)
    times['build graph again'] = t_build_graph2[0]
    with timer() as t_stats:
        stats = csr.branch_statistics(g)
    times['compute statistics'] = t_stats[0]
    with timer() as t_stats2:
        stats = csr.branch_statistics(g)
    times['compute statistics again'] = t_stats2[0]
    with timer() as t_skeleton:
        skel_obj = csr.Skeleton(skeleton)
    times['skeleton object'] = t_skeleton[0]
    with timer() as t_skeleton2:
        skel_obj = csr.Skeleton(skeleton)
    times['skeleton object again'] = t_skeleton2[0]
    with timer() as t_summary:
        summary = csr.summarize(skel_obj)
    times['compute per-skeleton statistics'] = t_summary[0]
    return times
Esempio n. 2
0
def test_junction_multiplicity():
    """Test correct distances when a junction has more than one pixel."""
    g, idxs = csr.skeleton_to_csgraph(skeleton0)
    assert_almost_equal(g[3, 5], 2.0155644)
    g, idxs = csr.skeleton_to_csgraph(skeleton0, unique_junctions=False)
    assert_almost_equal(g[2, 3], 1.0)
    assert_almost_equal(g[3, 6], np.sqrt(2))
Esempio n. 3
0
def test_mst_junctions():
    g, _ = csr.skeleton_to_csgraph(skeleton0)
    h = csr._mst_junctions(g)
    hprime, _ = csr.skeleton_to_csgraph(skeleton0)

    G = g.todense()
    G[G > 1.1] = 0

    np.testing.assert_equal(G, h.todense())
    np.testing.assert_equal(G, hprime.todense())
Esempio n. 4
0
def test_networkx_plot():
    g0, c0 = csr.skeleton_to_csgraph(_testdata.skeleton0)
    g1, c1 = csr.skeleton_to_csgraph(_testdata.skeleton1)
    fig, axes = plt.subplots(1, 2)
    draw.overlay_skeleton_networkx(g0, c0, image=_testdata.skeleton0,
                                   axis=axes[0])
    draw.overlay_skeleton_networkx(g1, c1, image=_testdata.skeleton1,
                                   axis=axes[1])
    # test axis=None and additional coordinates
    c2 = np.concatenate((c1, np.random.random(c1[:1].shape)), axis=0)
    draw.overlay_skeleton_networkx(g1, c2, image=_testdata.skeleton1)
Esempio n. 5
0
    def test_skeletons_swc(self):
        config = SkeletonWorkflow.get_config()['skeletonize']
        config.update({'chunk_len': 50})
        with open(os.path.join(self.config_folder, 'skeletonize.config'), 'w') as f:
            json.dump(config, f)

        self._run_skel_wf(format_='swc', max_jobs=8)
        # check output for correctness
        seg, ids = self.ids_and_seg()
        out_folder = os.path.join(self.output_path, self.output_prefix, 's0')
        for seg_id in ids:
            # read the result from file
            out_file = os.path.join(out_folder, '%i.swc' % seg_id)
            skel_ids, coords, parents = su.read_swc(out_file)
            coords = np.array(coords, dtype='float')

            # compute the expected result
            mask = seg == seg_id
            skel_vol = skeletonize_3d(mask)
            try:
                pix_graph, coords_exp, _ = csr.skeleton_to_csgraph(skel_vol)
            except ValueError:
                continue

            # check coordinates
            coords_exp = coords_exp[1:]
            self.assertEqual(coords.shape, coords_exp.shape)
            self.assertTrue(np.allclose(coords, coords_exp))
Esempio n. 6
0
def thinning(obj, resolution, *args, **kwargs):
    """
    Skeletonize object with thinning based method.

    Wrapper around implementation from
    https://scikit-image.org/docs/dev/api/skimage.morphology.html#skimage.morphology.skeletonize_3d

    Arguments:
        obj [np.ndarray] - binary object mask
        resolution [list] - size of the voxels in physical unit
    """

    # skeletonize with thinning
    vol = skeletonize_3d(obj)

    # use skan to extact skeleon node coordinates and edges
    adj_mat, nodes, _ = csr.skeleton_to_csgraph(vol, spacing=resolution)
    graph = csr.csr_to_nbgraph(adj_mat)

    # I think we need to substract 1 here, beacuse skan uses 1-based indexing
    n_nodes = len(nodes)
    edges = np.array([[u - 1, v - 1] for u in range(1, n_nodes + 1)
                      for v in graph.neighbors(u) if u < v],
                     dtype='uint64')

    # retunr node coordinate list and edges
    return nodes.astype('uint64'), edges
Esempio n. 7
0
def write_swc(output_path, skel_vol, resolution=None, invert_coords=False):
    """ Write skeleton to .swc

    For details on the swc format for skeletons, see
    http://research.mssm.edu/cnic/swc.html.
    This writes the swc catmaid flavor.

    Arguments:
        output_path [str]: output_path for swc file
        skel_vol [np.ndarray]: binary volume containing the skeleton
        resolution [list or float]: pixel resolution (default: None)
        invert_coords [bool]: whether to invert the coordinates
            This may be useful because swc expects xyz, but input is zyx (default: False)
    """
    # extract the skeleton graph
    # NOTE looks like skan function names are about to change in 0.8:
    # csr.numba_csgraph -> csr.csr_to_nbgraph

    # this may fail for small skeletons with a value-error
    try:
        pix_graph, coords, _ = csr.skeleton_to_csgraph(skel_vol)
    except ValueError:
        return
    graph = csr.numba_csgraph(pix_graph)

    # map coords to resolution and invert if necessary
    if resolution is not None:
        if isinstance(resolution, float):
            resolution = 3 * [resolution]
        assert len(resolution) == 3, str(len(resolution))
        coords *= resolution
    if invert_coords:
        coords = coords[:, ::-1]

    # TODO if this becomes a bottle-neck think about moving to numba, cython or c++
    n_points = pix_graph.shape[0]
    with open(output_path, 'w') as f:
        for node_id in range(1, n_points):
            # swc: node-id
            #      type (hard-coded to 0 = undefined)
            #      coordinates
            #      radius (hard-coded to 0.0)
            #      parent id
            ngbs = graph.neighbors(node_id)

            # only a single neighbor -> terminal node and no parent
            # also, for some reasons ngbs can be empty
            if len(ngbs) in (0, 1):
                parent = -1
            # two neighbors -> path node
            # more than two neighbors -> junction
            else:
                # TODO can we just assume that we get consistent output if we set parent to min ???
                parent = np.min(ngbs)
            coord = coords[node_id]
            line = '%i 0 %f %f %f 0.0 %i \n' % (node_id, coord[0], coord[1],
                                                coord[2], parent)
            f.write(line)
Esempio n. 8
0
def test_junctions(unique_junctions=True):
    x = np.zeros((7, 7), dtype='uint8')
    x[3, :] = 1
    x[:, 3] = 1
    print("input image")
    print(x)
    _, coords, _ = csr.skeleton_to_csgraph(x,
                                           unique_junctions=unique_junctions)
    print("coord for skel node 3, expected [2., 3.]")
    print(coords[3])
Esempio n. 9
0
def test_tiny_cycle():
    g, idxs = csr.skeleton_to_csgraph(tinycycle)
    expected_indptr = [0, 2, 4, 6, 8]
    expected_indices = [1, 2, 0, 3, 0, 3, 1, 2]
    expected_data = np.sqrt(2)

    assert_equal(g.indptr, expected_indptr)
    assert_equal(g.indices, expected_indices)
    assert_almost_equal(g.data, expected_data)

    assert_equal(np.ravel_multi_index(idxs, tinycycle.shape), [1, 3, 5, 7])
Esempio n. 10
0
def test_tiny_cycle():
    g, idxs, degimg = csr.skeleton_to_csgraph(tinycycle)
    expected_indptr = [0, 0, 2, 4, 6, 8]
    expected_indices = [2, 3, 1, 4, 1, 4, 2, 3]
    expected_data = np.sqrt(2)

    assert_equal(g.indptr, expected_indptr)
    assert_equal(g.indices, expected_indices)
    assert_almost_equal(g.data, expected_data)

    expected_degrees = np.array([[0, 2, 0], [2, 0, 2], [0, 2, 0]])
    assert_equal(degimg, expected_degrees)
    assert_equal(np.ravel_multi_index(idxs.astype(int).T, tinycycle.shape),
                 [0, 1, 3, 5, 7])
Esempio n. 11
0
def test_skeleton1_stats():
    g, idxs, degimg = csr.skeleton_to_csgraph(skeleton1)
    stats = csr.branch_statistics(g)
    assert_equal(stats.shape, (4, 4))
    keys = map(tuple, stats[:, :2].astype(int))
    dists = stats[:, 2]
    types = stats[:, 3].astype(int)
    ids2dist = dict(zip(keys, dists))
    assert (13, 8) in ids2dist
    assert (8, 13) in ids2dist
    d0, d1 = sorted((ids2dist[(13, 8)], ids2dist[(8, 13)]))
    assert_almost_equal(d0, 1 + np.sqrt(2))
    assert_almost_equal(d1, 5 * d0)
    assert_equal(np.bincount(types), [0, 2, 2])
    assert_almost_equal(np.unique(dists), [d0, 2 + np.sqrt(2), d1])
Esempio n. 12
0
def write_n5(ds, skel_id, skel_vol, coordinate_offset=None):
    """ Write skeleton to custom n5-based format

    The skeleton data is stored via varlen chunks: each chunk contains
    the data for one skeleton and stores:
    [n_skel_points, coord_z_0, coord_y_0, coord_x_0, ..., coord_z_n, coord_y_n, coord_x_n,
     n_edges, edge_0_u, edge_0_v, ..., edge_n_u, edge_n_v]

    Arguments:
        ds [z5py.Dataset]: output dataset
        skel_id [int]: id of the object corresponding to the skeleton
        skel_vol [np.ndarray]: binary volume containing the skeleton
        coordinate_offset [listlike]: offset to coordinate (default: None)
    """
    # NOTE looks like skan function names are about to change in 0.8:
    # csr.numba_csgraph -> csr.csr_to_nbgraph
    # extract the skeleton graph

    # this may fail for small skeletons with a value-error
    try:
        pix_graph, coords, _ = csr.skeleton_to_csgraph(skel_vol)
    except ValueError:
        return
    graph = csr.numba_csgraph(pix_graph)

    # skan-indexing is 1 based, so we need to get rid of first coordinate row
    coords = coords[1:]
    # check if we have offset and add up if we do
    if coordinate_offset is not None:
        assert len(coordinate_offset) == 3
        coords += coordinate_offset

    # make serialization for number of points and coordinates
    n_points = coords.shape[0]
    data = [np.array([n_points]), coords.flatten()]

    # make edges
    edges = [[u, v] for u in range(1, n_points + 1) for v in graph.neighbors(u)
             if u < v]
    edges = np.array(edges)
    # substract 1 to change to zero-based indexing
    edges -= 1
    # add number of edges and edges to the serialization
    n_edges = len(edges)
    data.extend([np.array([n_edges]), edges.flatten()])

    data = np.concatenate(data, axis=0)
    ds.write_chunk((skel_id, ), data.astype('uint64'), True)
Esempio n. 13
0
    def test_skeletons_n5(self):
        config = SkeletonWorkflow.get_config()['skeletonize']
        config.update({'chunk_len': 50})
        with open(os.path.join(self.config_folder, 'skeletonize.config'), 'w') as f:
            json.dump(config, f)

        self._run_skel_wf(format_='n5', max_jobs=8)

        # check output for correctness
        seg, ids = self.ids_and_seg()
        out_key = os.path.join(self.output_prefix, 's0')
        ds = z5py.File(self.output_path)[out_key]
        for seg_id in ids:
            # read the result from file
            coords, edges = su.read_n5(ds, seg_id)

            # compute the expected result
            mask = seg == seg_id
            skel_vol = skeletonize_3d(mask)
            try:
                pix_graph, coords_exp, _ = csr.skeleton_to_csgraph(skel_vol)
            except ValueError:
                continue

            # check coordinates
            coords_exp = coords_exp[1:].astype('uint64')
            self.assertEqual(coords.shape, coords_exp.shape)
            self.assertTrue(np.allclose(coords, coords_exp))

            # check edges
            graph = csr.numba_csgraph(pix_graph)
            n_points = len(coords)
            edges_exp = [[u, v] for u in range(1, n_points + 1)
                         for v in graph.neighbors(u) if u < v]
            edges_exp = np.array(edges_exp)
            edges_exp -= 1
            self.assertEqual(edges.shape, edges_exp.shape)
            self.assertTrue(np.allclose(edges, edges_exp))
def skeletonize3D(cube):
    """
    Return the 3D skeleton dkel2 and converted it in form of graph and return
    pixel graph as a SciPy CSR matrix in which entry (i,j) is 0 if pixels 
    i and j are not connected, and otherwise is equal to the distance between
    pixels i and j in the skeleton.

    coordinates (in pixel units) of the points in the pixel graph. Finally, degrees 
    is an image of the skeleton, with each skeleton pixel containing the number of neighboring pixels.

 

    Parameters
    ----------
    cube : 3d numpy array

   
    
    
    Returns
    -------
    dskel2 :3D skeletonized binary image(numpy array)
    Pixel Graph,
    coordinates,
    degree 
       
    """

    selem = ball(3)

    ddilate = dilation(cube, selem)
    dclose = closing(ddilate)
    dskel2 = skeletonize_3d(dclose)

    pixel_graph0, coordinates0, degrees0 = csr.skeleton_to_csgraph(dskel2)

    return dskel2, pixel_graph0, coordinates0, degrees0
Esempio n. 15
0
def test_junction_multiplicity():
    """Test correct distances when a junction has more than one pixel."""
    g, _ = csr.skeleton_to_csgraph(skeleton0)
    assert_equal(g.data, 1.0)
    assert_equal(g[2, 5], 0.0)
Esempio n. 16
0
counts, bins = np.histogram(values, bins='auto')
counts.shape
bins.shape
counts, bins = np.histogram(values, bins=100)
fig, ax = plt.subplots()
ax.plot(bins[:-1]/2 + bins[1:]/2, counts)
ax.clear()
ax.hist(values, bins=bins);
np.sqrt(9**2 + 3**2 + 3**2)
ax.set_xlabel('distance from skan point to nearest Fiji point (µm)')
ax.set_ylabel('count')
fig.savefig('OP1-point-distance-histogram-new.png')
np.argmax(np.argmin(dmx, axis=1))
np.argmin(dmx[79])
all_points_skan[79]
all_points_fiji[99]
np.argmax(dmx[np.arange(dmx.shape[0]), np.argmin(dmx, axis=1)])
np.argmin(dmx[19])
all_points_skan[19]
all_points_fiji[27]
all_points_fiji[27] / spacing
all_points_skan[19] / spacing
get_ipython().magic('pinfo csr.skeleton_to_csgraph')
g, idx, deg = csr.skeleton_to_csgraph(skel1, spacing=spacing)
deg[22, 146, 410]
deg[20:25, 144:149, 408:413]
deg[20:26, 144:149, 408:413]
deg[21:28, 144:149, 408:413]
# above: clear difference in the branch point location due to
# cluster of junction points
#cube = fits.getdata('ngc3627_co21_12m+7m+tp_mask.fits')

#Parameter :
parameter = 5
cutnodes = []

selem = ball(3)

ddilate = dilation(cube, selem)
dclose = closing(ddilate)
dskel2 = skeletonize_3d(dclose)

#subcube = remove_holes[15:, 15:45, 15:45]

pixel_graph0, coordinates0, degrees0 = csr.skeleton_to_csgraph(dskel2)

subcube = dskel2[125:175, 300:500, 50:200]

#Graph

import networkx as nx

pixel_graph1, coordinates1, degrees1 = csr.skeleton_to_csgraph(subcube)

#print(pixel_graph1.paths_list())

nodes = range(15, 75)
G = nx.from_scipy_sparse_matrix(pixel_graph1)
#H = G.subgraph(nodes)
#graphs = list(nx.connected_component_subgraphs(G))
Esempio n. 18
0
def test_line():
    g, idxs = csr.skeleton_to_csgraph(tinyline)
    assert_equal(np.ravel(idxs), [1, 2, 3])
    assert_equal(g.shape, (3, 3))
    # source, dest, length, type
    assert_equal(_old_branch_statistics(tinyline), [[0, 2, 2, 0]])
Esempio n. 19
0
def branch_parameters_extration(distmap, skelbranch, physicspacing):
    """
    Extract branches data from skeleton such as primary branche lengths, paths, initial and final pixels.
    :param skelBranches:
    :param physicspacing:
    :return:
    """

    skeldict = {
        'protusion_id': [],
        'initial_node-id': [],
        'initial_node-coord-0': [],
        'initial_node-coord-1': [],
        'final_node-id': [],
        'final_node-coord-0': [],
        'final_node-coord-1': [],
        'euclidean-length': [],
        'primary-path': [],
        'secondary-paths': [],
        'total-protlength': [],
        'physical-space': physicspacing,
    }

    # Intermediate objects to measure the length of skeleton branches, see the skan module
    _, c0, _ = csr.skeleton_to_csgraph(skelbranch)
    # c0 : An array of shape (Nnz + 1, skel.ndim), mapping indices in graph to pixel coordinates
    # in degree_image or skel.

    branch_data = csr.summarise(skelbranch, spacing=physicspacing)
    # total protusion length
    totprotlength = branch_data['euclidean-distance'].sum()
    skeldict['total-protlength'] = totprotlength

    skeletonEdges = edgepoint_detect(distmap > 0)
    branchEdges = edgepoint_detect(skelbranch)

    removeInd = np.where((branchEdges == skeletonEdges[:, None]).all(-1))[1]
    endbodycoord = np.delete(branchEdges, removeInd, 0)

    skeldict['initial_node-coord-0'] = endbodycoord[:, 0].tolist()
    skeldict['initial_node-coord-1'] = endbodycoord[:, 1].tolist()

    # Matrix that relates nodeid in the branch_data dataframe and pixel coordinates
    nodeIDallPixels = c0.astype(int)

    # Node id of endpoints, , by using NumPy broadcasting
    nodeIDendBody = np.where(
        (nodeIDallPixels == endbodycoord[:, None]).all(-1))[1]
    skeldict['initial_node-id'] = nodeIDendBody.tolist()

    # label separate branches starting from the cell body
    structure = np.ones(
        (3, 3), dtype=np.int)  # in this case we allow any kind of connection
    labeled, ncomponents = label(skelbranch, structure)

    labelValue = labeled[endbodycoord[:, 0], endbodycoord[:, 1]]
    skeldict['protusion_id'] = labelValue.tolist()
    skeldict['protusion_id'] = np.arange(ncomponents) + 1

    for i in range(ncomponents):

        # skeleton of single protusion
        skelProt = labeled == labelValue[i]

        # protusion edges in black background
        endprotCoord = edgepoint_detect(skelProt)
        # # remove cellbody endpoint from protusion endpoint list
        # endpointProt[endbodycoord[i - 1, 0], endbodycoord[i - 1, 1]] = 0
        removeInd = np.where((endprotCoord == endbodycoord[:,
                                                           None]).all(-1))[1]
        endprotCoord = np.delete(endprotCoord, removeInd, 0)

        # node id of protusion endpoints, by using NumPy broadcasting
        endprotNodeID = np.where(
            (nodeIDallPixels == endprotCoord[:, None]).all(-1))[1]

        protPaths = []
        protLengths = []
        for coord in endprotCoord:
            Path, _ = route_through_array(np.invert(skelProt),
                                          start=endbodycoord[i],
                                          end=coord)
            Path = np.array(Path)
            protPaths.append(Path)
            Length = path_length(Path, skelProt, physicspacing)
            protLengths.append(Length)

        maxLength = np.array(protLengths).max()
        skeldict['euclidean-length'].append(maxLength)

        primaryPathID = np.array(protLengths).argmax()
        primaryPath = protPaths[primaryPathID]
        skeldict['primary-path'].append(primaryPath)

        # get only secondary paths
        del (protPaths[primaryPathID])
        skeldict['secondary-paths'].append(protPaths)

        skeldict['final_node-id'].append(endprotNodeID[primaryPathID])
        skeldict['final_node-coord-0'].append(endprotCoord[primaryPathID, 0])
        skeldict['final_node-coord-1'].append(endprotCoord[primaryPathID, 1])

    return skeldict
Esempio n. 20
0
def test_line():
    g, idxs, degimg = csr.skeleton_to_csgraph(tinyline)
    assert_equal(np.ravel(idxs), [0, 1, 2, 3])
    assert_equal(degimg, [0, 1, 2, 1, 0])
    assert_equal(g.shape, (4, 4))
    assert_equal(csr.branch_statistics(g), [[1, 3, 2, 0]])
Esempio n. 21
0
def test_topograph():
    g, idxs, degimg = csr.skeleton_to_csgraph(topograph1d,
                                              value_is_height=True)
    stats = csr.branch_statistics(g)
    assert stats.shape == (1, 4)
    assert_almost_equal(stats[0], [1, 3, 2 * np.sqrt(2), 0])
Esempio n. 22
0
def test_3d_spacing():
    g, idxs, degimg = csr.skeleton_to_csgraph(skeleton3d, spacing=[5, 1, 1])
    stats = csr.branch_statistics(g)
    assert_equal(stats.shape, (5, 4))
    assert_almost_equal(stats[0], [1, 5, 10.467, 1], decimal=3)
    assert_equal(np.unique(stats[:, 3].astype(int)), [1, 2, 3])
Esempio n. 23
0
def test_cycle_stats():
    stats = csr.branch_statistics(csr.skeleton_to_csgraph(tinycycle)[0],
                                  buffer_size_offset=1)
    assert_almost_equal(stats, [[1, 1, 4 * np.sqrt(2), 3]])