示例#1
0
def test_multiplicity_stats():
    stats1 = csr.summarise(skeleton0)
    stats2 = csr.summarise(skeleton0, spacing=2)
    assert_almost_equal(2 * stats1['branch-distance'].values,
                        stats2['branch-distance'].values)
    assert_almost_equal(2 * stats1['euclidean-distance'].values,
                        stats2['euclidean-distance'].values)
示例#2
0
def test_summarise_spacing():
    df = csr.summarise(skeleton2)
    df2 = csr.summarise(skeleton2, spacing=2)
    assert_equal(np.array(df['node-id-0']), np.array(df2['node-id-0']))
    assert_almost_equal(np.array(df2['euclidean-distance']),
                        np.array(2 * df['euclidean-distance']))
    assert_almost_equal(np.array(df2['branch-distance']),
                        np.array(2 * df['branch-distance']))
示例#3
0
def labelandskel(binary_im):
    # label, calculate properties, and skeletonize
    clean_im = binary_im
    lab_im = label(clean_im)
    props = regionprops(lab_im)
    skelim = skeletonize(clean_im)

    # calculate skeleton properties
    branch_data = csr.summarise(skelim)
    branch_data_short = branch_data

    cells = branch_data['skeleton-id'].max()
    nbranches = []

    for i in range(1, cells+1):
        bcount = branch_data[branch_data['skeleton-id'
                                         ] == i]['skeleton-id'].count()
        if bcount > 0:
            ids = branch_data.index[branch_data['skeleton-id'] == i].tolist()
            nbranches.append(bcount)
            for j in range(0, len(ids)):
                branch_data_short.drop([ids[j]])

    skel = Bunch(im=skelim, branchdat=branch_data_short, nbran=nbranches,
                 shortim=clean_im, props=props)
    return skel
示例#4
0
def test_topograph_summary():
    stats = csr.summarise(topograph1d, spacing=2.5, using_height=True)
    assert stats.loc[0, 'euclidean-distance'] == 5.0
    assert_almost_equal(
        stats.loc[
            0, ['coord-src-0', 'coord-src-1', 'coord-dst-0', 'coord-dst-1']],
        [3, 0, 3, 5])
示例#5
0
def path_length(pixel_path, skel_image, physicspacing):
    "Measure the euclidian length of a pixel path (e.g. skeleton branch)"
    prot = np.zeros(skel_image.shape)
    prot[pixel_path[:, 0], pixel_path[:, 1]] = 1

    length = csr.summarise(prot,
                           spacing=physicspacing)['euclidean-distance'][0]
    return length
示例#6
0
def skeleton_image(folder, image_file, threshold=50, area_thresh=50, figsize=(10, 10), show=False):
    """
    Skeletonizes the image and returns properties of each skeleton.

    Parameters
    ----------

    Returns
    -------

    Examples
    --------

    """
    # Median filtered image.
    fname = '{}/{}'.format(folder, image_file)
    image0 = sio.imread(fname)
    image0 = np.ceil(255* (image0[:, :, 1] / image0[:, :, 1].max())).astype(int)
    image0 = skimage.filters.median(image0)
    filt = 'filt_{}.png'.format(image_file.split('.')[0])
    sio.imsave(folder+'/'+filt, image0)

    #threshold the image
    binary0 = binary_image(folder, filt, threshold=threshold, close=True, show=False)
    clean = 'clean_{}'.format(filt)

    #label image
    short_image, props = label_image(folder, clean, area_thresh=area_thresh, show=False)
    short = 'short_{}'.format(clean)
    short_image = short_image > 1
    # Skeletonize
    skeleton0 = skeletonize(short_image)

    branch_data = csr.summarise(skeleton0)
    branch_data_short = branch_data

    #Remove small branches
    mglia = branch_data['skeleton-id'].max()
    nbranches = []

    ncount = 0
    for i in range(1, mglia+1):
        bcount = branch_data[branch_data['skeleton-id']==i]['skeleton-id'].count()
        if bcount > 0:
            ids = branch_data.index[branch_data['skeleton-id']==i].tolist()
            nbranches.append(bcount)
            for j in range(0, len(ids)):
                branch_data_short.drop([ids[j]])

            ncount = ncount + 1
    if show:
        fig, ax = plt.subplots(figsize=(10, 10))
        draw.overlay_euclidean_skeleton_2d(image0, branch_data_short,
                                           skeleton_color_source='branch-type', axes=ax)
        plt.savefig('{}/skel_{}'.format(folder, short))

    return skeleton0, branch_data_short, nbranches, short_image, props
示例#7
0
文件: bench_skan.py 项目: trasse/skan
def bench_suite():
    times = OrderedDict()
    skeleton = np.load(os.path.join(rundir, 'infected3.npz'))['skeleton']
    with timer() as t_build_graph:
        g, indices, degrees = csr.skeleton_to_csgraph(skeleton,
                                                      spacing=2.24826)
    times['build graph'] = t_build_graph[0]
    with timer() as t_build_graph2:
        g, indices, degrees = 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_summary:
        summary = csr.summarise(skeleton)
    times['compute per-skeleton statistics'] = t_summary[0]
    return times
示例#8
0
def prune_graph(skeleton, iter_index, file_name, prune_circle=True):
    def in_bounds(p):
        r, c = p
        if 0 <= r < skeleton.shape[1] and 0 <= c < skeleton.shape[0]:
            return True
        else:
            return False

    def add_range(tup):
        v_x, v_y = tup
        max_dist_v = [x for x in range(-7, 7 + 1)]
        max_dist_candidates_x = list(map(lambda x: x + v_x, max_dist_v))
        max_dist_candidates_y = list(map(lambda y: y + v_y, max_dist_v))
        return [(x, y) for x in max_dist_candidates_x for y in max_dist_candidates_y if in_bounds((x, y))]

    def unique_rows(a):
        a = np.ascontiguousarray(a)
        unique_a = np.unique(a.view([('', a.dtype)] * a.shape[1]))
        return unique_a.view(a.dtype).reshape((unique_a.shape[0], a.shape[1]))

    def identical(e1, e2):
        return e1[0] == e2[0] and e1[1] == e2[1]

    cv2.imwrite('./' + file_name + '/skel_' + str(iter_index) + '.png', skeleton.astype(np.uint8) * 255)
    cv2.imwrite('./' + file_name + '/skel_' + str(iter_index) + '_inverted.png', 255 - skeleton.astype(np.uint8) * 255)
    # important! removes pixels due to vertex removal from previous iteration
    skeleton = morphology.skeletonize(skeleton)

    branch_data = csr.summarise(skeleton)
    coords_cols = (['img-coord-0-%i' % i for i in [1, 0]] +
                   ['img-coord-1-%i' % i for i in [1, 0]])
    # removes duplicate entries! for some reason they are present in the result
    coords = unique_rows(branch_data[coords_cols].values).reshape((-1, 2, 2))
    try_again = False

    len_before = len(coords)
    excludes = [(0, 0), (skeleton.shape[1], 0), (0, skeleton.shape[0]), (skeleton.shape[1], skeleton.shape[0])]
    exclude = []
    excluded = []
    for ex in excludes:
        exclude.extend(add_range(ex))

    done = False
    while not done:
        changed = False
        flat_coords = [tuple(val) for sublist in coords for val in sublist]
        unique_flat_coords = list(set(flat_coords))
        current = 0
        while not changed and current < len(unique_flat_coords):
            item = unique_flat_coords[current]
            current += 1
            # print('item=', item, 'count=', flat_coords.count(item))
            # 1 degree vertexes are to be removed from graph
            if flat_coords.count(item) < 2:
                # print('item=', item)
                if item in exclude:
                    excluded.append((item[1], item[0]))
                    continue
                changed = True
                coords = list(filter(lambda x: tuple(x[0]) != item and tuple(x[1]) != item, coords))
                # print('flat_coords.count(item)=', flat_coords.count(item), 'fc=', fc)
            # 2 degree vertexes need their edges to be merged
            elif flat_coords.count(item) == 2:
                changed = True
                fc = list(filter(lambda x: tuple(x[0]) == item or tuple(x[1]) == item, coords))
                # print('flat_coords.count(item)=', flat_coords.count(item), 'fc=', fc)
                if len(fc) != 2:
                    print('item=', item, 'fc=', fc)
                coords = list(filter(lambda x: tuple(x[0]) != item and tuple(x[1]) != item, coords))
                e1_s = fc[0][0]
                e1_e = fc[0][1]
                e2_s = fc[1][0]
                e2_e = fc[1][1]
                if ft.reduce(op.and_, map(lambda e: e[0] == e[1], zip(e1_s, e2_s))) and \
                        not identical(e1_e, e2_e):
                    coords.append(np.array([e1_e, e2_e]))
                elif ft.reduce(op.and_, map(lambda e: e[0] == e[1], zip(e1_s, e2_e))) and \
                        not identical(e1_e, e2_s):
                    coords.append(np.array([e1_e, e2_s]))
                elif ft.reduce(op.and_, map(lambda e: e[0] == e[1], zip(e1_e, e2_s))) and \
                        not identical(e1_s, e2_e):
                    coords.append(np.array([e1_s, e2_e]))
                elif ft.reduce(op.and_, map(lambda e: e[0] == e[1], zip(e1_e, e2_e))) and \
                        not identical(e1_s, e2_s):
                    coords.append(np.array([e1_s, e2_s]))
                else:
                    changed = False
        if not changed:
            done = True
            time_print('before= ' + str(len_before) + ' after= ' + str(len(coords)))
            try_again = len_before != len(coords)

    tmp_skel = copy.deepcopy(skeleton)
    for coord in coords:
        start, end = coord
        start = (start[1], start[0])
        end = (end[1], end[0])
        # print(start, end)
        start_neighborhood = connected_candidates(start, skeleton)
        end_neighborhood = connected_candidates(end, skeleton)
        for point in start_neighborhood + end_neighborhood:
            tmp_skel[point] = False
        tmp_skel[start] = False
        tmp_skel[end] = False

    results = []
    results_dict = dict()
    for edge in coords:
        start, end = edge
        start = (start[1], start[0])
        end = (end[1], end[0])
        start_neighborhood = connected_candidates(start, skeleton)
        end_neighborhood = connected_candidates(end, skeleton)
        for point in start_neighborhood + end_neighborhood:
            tmp_skel[point] = True
        tmp_skel[start] = True
        tmp_skel[end] = True
        _, _, result = edge_bfs(start, end, tmp_skel)
        start_neighborhood = connected_candidates(start, skeleton)
        end_neighborhood = connected_candidates(end, skeleton)
        for point in start_neighborhood + end_neighborhood:
             tmp_skel[point] = False
        tmp_skel[start] = False
        tmp_skel[end] = False
        results.append((start, end, result))
        results_dict[(start, end)] = result

    # filter out circles -> (u,v) (v,w) (w,u), then (w,u) is removed
    # (w,u) is the longest line out of the three in a 3-edge circle
    remove_candidates = set()
    for result in results_dict.keys():
        v, u = result
        candidates_v = [e for e in results_dict.keys() if v in e and u not in e]
        candidates_v_w = [e[0] if e[1] == v else e[1] for e in candidates_v]
        candidates_u = [e for e in results_dict.keys() if u in e and v not in e]
        candidates_u_w = [e[0] if e[1] == u else e[1] for e in candidates_u]
        for vw in candidates_v_w:
            for uw in candidates_u_w:
                if vw == uw:
                    w = vw
                    if (v, u) in results_dict.keys():
                        candidate_vu = (v, u)
                        len_vu = len(results_dict[(v, u)])
                    else:
                        candidate_vu = (u, v)
                        len_vu = len(results_dict[(u, v)])

                    if (w, v) in results_dict.keys():
                        candidate_wv = (w, v)
                        len_wv = len(results_dict[(w, v)])
                    else:
                        candidate_wv = (v, w)
                        len_wv = len(results_dict[(v, w)])

                    if (u, w) in results_dict.keys():
                        candidate_uw = (u, w)
                        len_uw = len(results_dict[(u, w)])
                    else:
                        candidate_uw = (w, u)
                        len_uw = len(results_dict[(w, u)])
                    if len_vu > len_uw and len_vu > len_wv:
                        remove_candidates.add(candidate_vu)
                    elif len_uw > len_vu and len_uw > len_wv:
                        remove_candidates.add(candidate_uw)
                    elif len_wv > len_vu and len_wv > len_vu:
                        remove_candidates.add(candidate_wv)
    # remove all edges that create a 3-edged circle,
    # for each edge the removed edge is the longest of all 3-edges of the circle
    time_print('removing circles ...')
    remove_items = [(edge[0], edge[1], results_dict.pop(edge)) for edge in remove_candidates]
    # if no edge was removed above, but a circle is removed, we need a new iteration due to changes.
    if remove_items:
        try_again = True
    time_print('before= ' + str(len(results)) + ' to_remove= ' + str(len(remove_items)))
    results = list(filter(lambda element: element not in remove_items, results))

    # create new skeleton following graph pruning
    skel = np.zeros_like(skeleton)
    for result in results:
        u, v, pixel_list = result
        for point in pixel_list:
            skel[point] = True

    return skel, results, excluded, try_again
示例#9
0
def test_3skeletons():
    df = csr.summarise(skeleton2)
    assert_almost_equal(np.unique(df['euclidean-distance']), np.sqrt([5, 10]))
    assert_equal(np.unique(df['skeleton-id']), [1, 2])
    assert_equal(np.bincount(df['branch-type']), [0, 4, 4])
示例#10
0
def skeleton_image(folder, image_file, threshold=50, area_thresh=50,
                   tofilt=True, ajar=True, close=True, figsize=(10, 10),
                   show=False, channel=0, disp_binary=True, imname=None):
    """Skeletonizes the image and returns properties of each skeleton.

    Composite function of binary_image, clean_image and skeletonizing
    functionality from skan.

    Parameters
    ----------
    folder : string
        Directory containing image_file
    image_file : string
        Filename of image to be analyzed
    threshold : int or float
        Intensity threshold level for threshold.
    area_thresh : int or float
        Size cutoff level to remove small objects
    figsize : tuple of int or float
        Size out output figure
    show : bool
        If True, prints image to Jupyter notebook
    channel : int
        If multichannel is True, reads in image corresponding to this channel in
        file.
    disp_binary: bool
        If True, prints binary image instead of raw image
    imname : string
        Output filename

    Returns
    -------
    skeleton0 : numpy.ndarray
        Skeletonized version of input image_file
    branch_data_short : pandas.core.frame.DataFrame
        Data associated with each branch found in input image
    nbranches : list
        Number of branches on each cell in branch_data_short
    short_image : numpy.ndarray
        Cleaned up binary image from image_file prior to skeletonization
    props : skimage.object
        Contains all properties of objects identified in image

    Examples
    --------

    """

    # Median filtered image.
    fname = '{}/{}'.format(folder, image_file)
    image0 = sio.imread(fname)
    if channel is None:
        image0 = np.ceil(255 * (image0[:, :] / image0[:, :].max())).astype(int)
    else:
        image0 = np.ceil(255 * (image0[:, :, channel
                                       ] / image0[:, :, channel
                                                  ].max())).astype(int)

    if tofilt:
        image0 = skimage.filters.median(image0)
        image_file = 'filt_{}'.format(image_file)
        sio.imsave(folder+'/'+image_file, image0)

    # label image
    short_image, props = clean_image(folder, image_file, threshold=threshold,
                                     area_thresh=area_thresh, ajar=ajar,
                                     close=close, imname='labelim.tif',
                                     channel=None, show=False)
    short_image = short_image > 1
    # Skeletonize
    skeleton0 = skeletonize(short_image)

    branch_data = csr.summarise(skeleton0)
    branch_data_short = branch_data

    # Remove small branches
    mglia = branch_data['skeleton-id'].max()
    nbranches = []

    ncount = 0
    for i in range(1, mglia+1):
        bcount = branch_data[branch_data['skeleton-id'
                                         ] == i]['skeleton-id'].count()
        if bcount > 0:
            ids = branch_data.index[branch_data['skeleton-id'] == i].tolist()
            nbranches.append(bcount)
            for j in range(0, len(ids)):
                branch_data_short.drop([ids[j]])

            ncount = ncount + 1
    if show:
        fig, ax = plt.subplots(figsize=figsize)
        if disp_binary:
            draw.overlay_euclidean_skeleton_2d(short_image, branch_data_short,
                                               skeleton_color_source='branch-type',
                                               axes=ax)
        else:
            draw.overlay_euclidean_skeleton_2d(image0, branch_data_short,
                                               skeleton_color_source='branch-type',
                                               axes=ax)

    if imname is None:
        output = "skel_{}".format(image_file)
    else:
        output = imname
    plt.savefig('{}/{}'.format(folder, output))

    skel = Bunch(im=skeleton0, branchdat=branch_data_short, nbran=nbranches,
                 shortim=short_image, props=props)

    return skel
示例#11
0
def test_pixel_values():
    image = np.random.random((45, ))
    expected = np.mean(image[1:-1])
    stats = csr.summarise(image)
    assert_almost_equal(stats.loc[0, 'mean pixel value'], expected)
示例#12
0
def test_tip_junction_edges():
    stats1 = csr.summarise(skeleton4)
    assert stats1.shape[0] == 3  # ensure all three branches are counted
示例#13
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
def mask_2_obj(TIFFileName, OBJFileName, smp=4, ZRatio=1):

    # Read skeleton image
    Skl_ImFile = tiff.TiffFile(TIFFileName)
    Skl_np = Skl_ImFile.asarray()

    # Analyze skeleton
    branch_data = csr.summarise(Skl_np)
    NBranches = branch_data.shape[0]
    skel_obj = csr.Skeleton(Skl_np)
    Brch_vox = skel_obj.path_coordinates
    NSkeletons = np.unique(branch_data['skeleton-id']).shape[0]

    # Extract relevant data from skeleton branches
    NBranches = branch_data.shape[0]
    id_0 = np.zeros(NBranches, dtype=int)
    id_1 = np.zeros(NBranches, dtype=int)
    list = skel_obj.paths_list()
    for i in range(NBranches):
        id_0[i] = list[i][0]
        id_1[i] = list[i][-1]

    # Parse all nodes to find unique vertices
    AllNodes = (np.unique([id_0, id_1]))
    MaxVertexIdx = (np.amax(AllNodes))
    NVertices = AllNodes.size

    # Estimate total number of segments
    TotSegments = 1
    for i in range(NBranches):
        TotSegments = TotSegments + (
            1 + np.floor(Brch_vox(i).shape[0] / smp)).astype(int)

    # Display model information
    print("Number of skeletons: %i" % NSkeletons)
    print("Number of branches: %i" % NBranches)
    print("Number of nodes: %i" % NVertices)
    print("Estimated number of segments: %i" % TotSegments)

    # Build re-indexing LUT
    LUTVertices = np.zeros([MaxVertexIdx + 1, 1], dtype=int)
    for i in range(NVertices):
        LUTVertices[AllNodes[i]] = i

    # Fill OBJ v-data
    OBJ_Vdata = np.zeros([TotSegments, 3], dtype=int)
    for i in range(NBranches):
        OBJ_Vdata[LUTVertices[id_0[i]], 0] = Brch_vox(i)[0, 2]
        OBJ_Vdata[LUTVertices[id_0[i]], 1] = Brch_vox(i)[0, 1]
        OBJ_Vdata[LUTVertices[id_0[i]], 2] = Brch_vox(i)[0, 0] * ZRatio
        OBJ_Vdata[LUTVertices[id_1[i]], 0] = Brch_vox(i)[-1, 2]
        OBJ_Vdata[LUTVertices[id_1[i]], 1] = Brch_vox(i)[-1, 1]
        OBJ_Vdata[LUTVertices[id_1[i]], 2] = Brch_vox(i)[-1, 0] * ZRatio
    cntVertices = NVertices

    # Fill OBJ l-data
    OBJ_Ldata = np.ones((TotSegments, 2), dtype=int)
    cntSegments = 0
    for i in range(NBranches):
        Vox = Brch_vox(i)
        L = Vox.shape[0]
        nNodes = (1 + np.floor(L / smp)).astype(int)
        PrevNode = LUTVertices[id_0[i]] + 1
        for s in range(1, nNodes - 1):
            OBJ_Vdata[cntVertices, 0] = Vox[np.round(s * (L - 1) /
                                                     (nNodes - 1)).astype(int),
                                            2]
            OBJ_Vdata[cntVertices, 1] = Vox[np.round(s * (L - 1) /
                                                     (nNodes - 1)).astype(int),
                                            1]
            OBJ_Vdata[cntVertices,
                      2] = Vox[np.round(s * (L - 1) /
                                        (nNodes - 1)).astype(int), 0] * ZRatio
            OBJ_Ldata[cntSegments, 0] = PrevNode
            OBJ_Ldata[cntSegments, 1] = cntVertices + 1
            PrevNode = cntVertices + 1
            cntVertices = cntVertices + 1
            cntSegments = cntSegments + 1
        OBJ_Ldata[cntSegments, 0] = PrevNode
        OBJ_Ldata[cntSegments, 1] = LUTVertices[id_1[i]] + 1
        cntSegments = cntSegments + 1

    # Display status
    print("Actual number of vertices: %i" % cntVertices)
    print("Actual number of segments: %i" % cntSegments)

    # Export OBJ file
    with open(OBJFileName, "w") as f:
        f.write("")
    f.close()
    with open(OBJFileName, "a") as f:
        for i in range(cntVertices):
            f.write("v %i %i %i\n" %
                    (OBJ_Vdata[i, 0], OBJ_Vdata[i, 1], OBJ_Vdata[i, 2]))
    f.close()
    with open(OBJFileName, "a") as f:
        for i in range(cntSegments):
            f.write("l %i %i\n" % (OBJ_Ldata[i, 0], OBJ_Ldata[i, 1]))
    f.close()
示例#15
0
    #plt.imsave(str('skel_') + str(m)+'skeleton2.tif', numpy.array(skeleton2), cmap= plt.matplotlib.cm.gray)
    print("Skeleton image saved!")
    #plt.imsave(str(m)+'CLEANINVERT.tif', numpy.array(CLEANEDAGAIN), cmap= plt.matplotlib.cm.gray)
    ##############################
    ###Threshold binary skeletonise
    skeletonthreshold = invert(binary5)
    skeletonthreshold = skeletonize(skeletonthreshold)
    plt.imsave(str(m) + '_skeletonthreshold.tif',
               numpy.array(skeletonthreshold),
               cmap=plt.matplotlib.cm.gray)

    ####################################
    #SKELETON ANALYSIS
    #ref: https://jni.github.io/skan/getting_started.html
    #In pixels
    branch = csr.summarise(skeleton)
    #save calculated branches to csv
    branch.to_csv(str(m) + '_branches.csv')
    print("Calculated branches saved!")
    ####################################
    #IMAGE OVERLAY
    #ref: https://docs.opencv.org/trunk/d0/d86/tutorial_py_image_arithmetics.html
    #ref: http://scikit-image.org/docs/dev/user_guide/numpy_images.html
    #ValueError: Image RGB array must be uint8 or floating point; found uint16
    colourskeleton = skeleton
    colourskeleton = img_as_ubyte(colourskeleton)  #8bit
    colourskeleton = grey2rgb(colourskeleton)
    #print(colourskeleton.shape)
    #colourskeleton = adjust_log(colourskeleton, gain = 80)
    mask = colourskeleton[:, :, 0] > 0
    #where it is greater than 0 and 0 is black
示例#16
0
文件: test_draw.py 项目: mkcor/skan
def test_stats(test_skeleton):
    stats = csr.summarise(test_skeleton)
    return stats
def mask_2_swc(TIFFileName, SWCFileName, smp=4, ZRatio=1):

    # Read binary mask
    Skl_ImFile = tiff.TiffFile(TIFFileName)
    Skl_np = Skl_ImFile.asarray()
    branch_data = csr.summarise(Skl_np)
    skel_obj = csr.Skeleton(Skl_np)
    Brch_vox = skel_obj.path_coordinates
    NSkeletons = np.unique(branch_data['skeleton-id']).shape[0]

    # Check that the mask only holds one skeleton
    if NSkeletons > 1:
        exit("Error: more than one skeleton found in the mask!")

    # Extract relevant data from skeleton branches
    NBranches = branch_data.shape[0]
    id_0 = np.zeros(NBranches, dtype=int)
    id_1 = np.zeros(NBranches, dtype=int)
    list = skel_obj.paths_list()
    for i in range(NBranches):
        id_0[i] = list[i][0]
        id_1[i] = list[i][-1]

    # Count number of unique vertices and build renumbering LUT
    AllNodes = (np.unique([id_0, id_1]))
    MaxVertexIdx = (np.amax(AllNodes))
    NVertices = AllNodes.size
    LUTVertices = np.zeros(MaxVertexIdx + 1, dtype=int)
    VertExist = np.zeros(MaxVertexIdx + 1, dtype=int)

    # Estimate total number of segments
    TotSegments = 1
    for i in range(NBranches):
        TotSegments = TotSegments + (
            1 + np.floor(Brch_vox(i).shape[0] / smp)).astype(int)
    print("Number of branches: %i" % NBranches)
    print("Number of nodes: %i" % NVertices)
    print("Estimated number of segments: %i" % TotSegments)

    # Fill SWC array
    global SWC_data
    SWC_data = np.ones((TotSegments, 7), dtype=int)
    BranchOrphaned = np.zeros(NBranches, dtype=int)
    cntVert = 0

    # Insert first branch
    Idx0 = id_0[0]
    Idx1 = id_1[0]
    SWC_data[cntVert, 0] = cntVert
    LUTVertices[Idx0] = cntVert
    VertExist[Idx0] = 1
    SWC_data[cntVert, 6] = -1
    SWC_data[cntVert, 2] = Brch_vox(0)[0, 2]
    SWC_data[cntVert, 3] = Brch_vox(0)[0, 1]
    SWC_data[cntVert, 4] = Brch_vox(0)[0, 0] * ZRatio
    Vox = Brch_vox(0)
    (SWC_data, cntVert) = insertNodes(cntVert, LUTVertices[Idx0], Vox, smp,
                                      ZRatio)
    LUTVertices[Idx1] = cntVert
    VertExist[Idx1] = 1

    # Main loop
    BrchToBeAdded = np.arange(NBranches, dtype=int)
    cntIt = 0
    for it in range(10):
        if np.sum(BrchToBeAdded) == 0:
            break
        cntIt = cntIt + 1
        for j in range(1, NBranches):
            i = BrchToBeAdded[j]
            if i > 0:
                Idx0 = id_0[i]
                Idx1 = id_1[i]
                if VertExist[Idx0]:
                    # First node exists, it is then an ancestor
                    Vox = Brch_vox(i)
                    (SWC_data, cntVert) = insertNodes(cntVert,
                                                      LUTVertices[Idx0], Vox,
                                                      smp, ZRatio)
                    LUTVertices[Idx1] = cntVert
                    VertExist[Idx1] = 1
                    BrchToBeAdded[j] = 0
                else:
                    if VertExist[Idx1]:
                        # Second node exists, it is then an ancestor
                        Vox = np.flip(Brch_vox(i), 0)
                        (SWC_data,
                         cntVert) = insertNodes(cntVert, LUTVertices[Idx1],
                                                Vox, smp, ZRatio)
                        LUTVertices[Idx0] = cntVert
                        VertExist[Idx0] = 1
                        BrchToBeAdded[j] = 0

    # Truncate SWC array and add 1 to all IDs (SWC convention)
    SWC_data = SWC_data[0:cntVert + 1, :]
    for i in range(SWC_data.shape[0]):
        SWC_data[i, 0] = SWC_data[i, 0] + 1
        if SWC_data[i, 6] > -1:
            SWC_data[i, 6] = SWC_data[i, 6] + 1

    # Check for duplicated nodes
    unique_rows = np.unique(SWC_data[:, 2:4], axis=0)
    if unique_rows.shape[0] != SWC_data.shape[0]:
        #print("Warning: the skeleton holds loop(s), this is incompatible with SWC format and it will be encoded with duplicated nodes!")
        exit(
            "Error: the skeleton holds loop(s), this is incompatible with SWC format!"
        )

    # Display status
    print("Performed %i iterations" % cntIt)
    print("Remaining branches: %i " % np.count_nonzero(BrchToBeAdded))
    print("Number of segments: %i" % SWC_data.shape[0])

    # Write SWC file
    with open(SWCFileName, "w") as f:
        f.write("# ORIGINAL_SOURCE Mask2SWC 1.0\n# SCALE 1.0 1.0 1.0\n\n")
    f.close()
    with open(SWCFileName, "a") as f:
        np.savetxt(f, SWC_data, fmt='%i', delimiter=" ")
    f.close()
示例#18
0
# IPython log file


get_ipython().magic('pwd')
current_directory = '/Users/jni/projects/skan-scripts'
skel1 = io.imread('OP_1_Rendered_Paths_thinned.tif')
from skan import csr
spacing = [3.033534 * 3, 3.033534, 3.033534]
spacing = np.asarray(spacing)
df = csr.summarise(skel1.astype(bool), spacing=spacing)
df2 = pd.read_excel('OP_1-Branch-information.xlsx')
dfs = df.sort_values(by='branch-distance', ascending=False)
df2s = df2.sort_values(by='Branch length', ascending=False)
dfs.shape
df2s.shape
bins = np.histogram(np.concatenate((df['branch-distance'],
                                    df2['Branch length'])),
                    bins=35)[1]
                    
fig, ax = plt.subplots()
ax.hist(df['branch-distance'], bins=bins, label='skan');
ax.hist(df2['Branch length'], bins=bins, label='Fiji', alpha=0.3)
ax.legend();
bins = np.histogram(np.concatenate((df['branch-distance'],
                                    df2['Branch length'])),
                    bins='auto')[1]
                    
fig, ax = plt.subplots()
ax.hist(df['branch-distance'], bins=bins, label='skan');
ax.hist(df2['Branch length'], bins=bins, label='Fiji', alpha=0.3);
get_ipython().magic('pinfo np.histogram')
示例#19
0
def skl2obj(Skl_np, smp, ZRatio, OBJToExport):

    # Analyze skeleton
    branch_data = csr.summarise(Skl_np)
    NBranches = branch_data.shape[0]
    skel_obj = csr.Skeleton(Skl_np)
    Brch_vox = skel_obj.path_coordinates
    NSkeletons = np.unique(branch_data['skeleton-id']).shape[0]

    # Extract required information on skeleton branches
    #NBranches = branch_data.shape[0]
    brclist = skel_obj.paths_list()
    NBranches = len(brclist)
    id_0 = np.zeros(NBranches, dtype=int)
    id_1 = np.zeros(NBranches, dtype=int)
    for i in range(NBranches):
        id_0[i] = brclist[i][0]
        id_1[i] = brclist[i][-1]

    # Parse all nodes to find unique vertices
    AllNodes = (np.unique([id_0, id_1]))
    MaxVertexIdx = (np.amax(AllNodes))
    NVertices = AllNodes.size

    # Over-estimate of total number of segments after skeleton sampling (node to node links)
    TotSegments = 1
    for i in range(NBranches):
        TotSegments = TotSegments + (
            1 + np.floor(Brch_vox(i).shape[0] / smp)).astype(int)

    # Display model information
    #print("Number of skeletons: %i"%NSkeletons)
    #print("Number of branches: %i"%NBranches)
    #print("Number of nodes: %i"%NVertices)
    #print("Estimated number of segments: %i"%TotSegments)

    # Build re-indexing LUT
    LUTVertices = np.zeros([MaxVertexIdx + 1, 1], dtype=int)
    for i in range(NVertices):
        LUTVertices[AllNodes[i]] = i

    # Fill OBJ v-data
    OBJ_Vdata = np.zeros([TotSegments, 3], dtype=int)
    for i in range(NBranches):
        OBJ_Vdata[LUTVertices[id_0[i]], 0] = Brch_vox(i)[0, 2]
        OBJ_Vdata[LUTVertices[id_0[i]], 1] = Brch_vox(i)[0, 1]
        OBJ_Vdata[LUTVertices[id_0[i]], 2] = Brch_vox(i)[0, 0] * ZRatio
        OBJ_Vdata[LUTVertices[id_1[i]], 0] = Brch_vox(i)[-1, 2]
        OBJ_Vdata[LUTVertices[id_1[i]], 1] = Brch_vox(i)[-1, 1]
        OBJ_Vdata[LUTVertices[id_1[i]], 2] = Brch_vox(i)[-1, 0] * ZRatio
    cntVertices = NVertices

    # Fill OBJ l-data
    OBJ_Ldata = np.ones((TotSegments, 2), dtype=int)
    cntSegments = 0
    for i in range(NBranches):
        Vox = Brch_vox(i)
        L = Vox.shape[0]
        nNodes = (1 + np.floor(L / smp)).astype(int)
        PrevNode = LUTVertices[id_0[i]] + 1
        for s in range(1, nNodes - 1):
            OBJ_Vdata[cntVertices, 0] = Vox[np.round(s * (L - 1) /
                                                     (nNodes - 1)).astype(int),
                                            2]
            OBJ_Vdata[cntVertices, 1] = Vox[np.round(s * (L - 1) /
                                                     (nNodes - 1)).astype(int),
                                            1]
            OBJ_Vdata[cntVertices,
                      2] = Vox[np.round(s * (L - 1) /
                                        (nNodes - 1)).astype(int), 0] * ZRatio
            OBJ_Ldata[cntSegments, 0] = PrevNode
            OBJ_Ldata[cntSegments, 1] = cntVertices + 1
            PrevNode = cntVertices + 1
            cntVertices = cntVertices + 1
            cntSegments = cntSegments + 1
        OBJ_Ldata[cntSegments, 0] = PrevNode
        OBJ_Ldata[cntSegments, 1] = LUTVertices[id_1[i]] + 1
        cntSegments = cntSegments + 1

    # Display model statistics
    #print("Actual number of vertices: %i" %cntVertices)
    #print("Actual number of segments: %i" %cntSegments)

    with open(OBJToExport, "w") as f:
        f.write("")
    f.close()
    with open(OBJToExport, "a") as f:
        for i in range(cntVertices):
            f.write("v %i %i %i\n" %
                    (OBJ_Vdata[i, 0], OBJ_Vdata[i, 1], OBJ_Vdata[i, 2]))
    f.close()
    with open(OBJToExport, "a") as f:
        for i in range(cntSegments):
            f.write("l %i %i\n" % (OBJ_Ldata[i, 0], OBJ_Ldata[i, 1]))
    f.close()