Example #1
0
def labelisation_seeded_watershed(graph, edge_weights, vertex_seeds):
    """
    Seeded watershed cut on an edge weighted graph.
    Seeds are defined as vertex weights: any flat zone of value strictly greater than 0 is considered as a seed.

    Note that if two different seeds are places in a minima of the edge weighted graph, and if the altitude of this minima
    is equal to the smallest representable value for the given `dtype` of the edge weights, then the algorithm won't be able
    to produce two different regions for these two seeds.

    :param graph: input graph
    :param edge_weights: Weights on the edges of the graph
    :param vertex_seeds: Seeds on the vertices of the graph
    :return: A labelisation of the graph vertices
    """
    # edges inside a seed take the value of the seed and 0 otherwise
    edges_in_or_between_seeds = hg.weight_graph(graph, vertex_seeds,
                                                hg.WeightFunction.L0)
    edges_outside_seeds = hg.weight_graph(graph, vertex_seeds,
                                          hg.WeightFunction.min)
    edges_in_seed = np.logical_and(edges_outside_seeds > 0,
                                   1 - edges_in_or_between_seeds)

    # set edges inside seeds at minimum level
    edge_weights = edge_weights.copy()
    edge_weights[edges_in_seed > 0] = hg.dtype_info(edge_weights.dtype).min

    tree, altitudes = hg.watershed_hierarchy_by_attribute(
        graph, edge_weights, lambda tree, _: hg.accumulate_sequential(
            tree, vertex_seeds, hg.Accumulators.max))

    return hg.labelisation_hierarchy_supervertices(tree, altitudes)
Example #2
0
def watershed_hierarchy_by_number_of_parents(graph, edge_weights):
    """
    Watershed hierarchy by number of parents.

    The definition of *number of parents* was proposed in:

        B. Perret, J. Cousty, S. J. F. GuimarĂ£es and D. S. Maia,
        `Evaluation of Hierarchical Watersheds <https://hal.archives-ouvertes.fr/hal-01430865/file/PCGM%20-%20TIP%202018%20-%20Evaluation%20of%20hierarchical%20watersheds.pdf>`_ ,
        in IEEE Transactions on Image Processing, vol. 27, no. 4, pp. 1676-1688, April 2018.
        doi: 10.1109/TIP.2017.2779604


    The definition of hierarchical watershed follows the one given in:

        J. Cousty, L. Najman.
        `Incremental algorithm for hierarchical minimum spanning forests and saliency of watershed cuts <https://hal-upec-upem.archives-ouvertes.fr/hal-00622505/document>`_.
        ISMM 2011: 272-283.

    The algorithm used is described in:

        Laurent Najman, Jean Cousty, Benjamin Perret.
        `Playing with Kruskal: Algorithms for Morphological Trees in Edge-Weighted Graphs <https://hal.archives-ouvertes.fr/file/index/docid/798621/filename/ismm2013-algo.pdf>`_.
        ISMM 2013: 135-146.


    :param graph: input graph
    :param edge_weights: edge weights of the input graph
    :return: a tree (Concept :class:`~higra.CptHierarchy`) and its node altitudes
    """
    def num_parents(bpt_tree, altitudes):
        # construct quasi flat zone hierarchy from input bpt
        tree, node_map = hg.simplify_tree(
            bpt_tree, altitudes == altitudes[bpt_tree.parents()])

        # determine inner nodes of the min tree, i.e. nodes of qfz having at least one node that is not a leaf
        num_children = tree.num_children(np.arange(tree.num_vertices()))
        num_children_leaf = np.zeros((tree.num_vertices(), ), dtype=np.int64)
        np.add.at(num_children_leaf, tree.parents()[:tree.num_leaves()], 1)
        inner_nodes = num_children != num_children_leaf

        # go back into bpt space
        inner_nodes_bpt = np.zeros((bpt_tree.num_vertices(), ), dtype=np.int64)
        inner_nodes_bpt[node_map] = inner_nodes
        inner_nodes = inner_nodes_bpt

        # count number of min tree inner nodes in the subtree rooted in the given node
        res = hg.accumulate_and_add_sequential(bpt_tree, inner_nodes,
                                               inner_nodes[:tree.num_leaves()],
                                               hg.Accumulators.sum)

        # add 1 to avoid having a zero measure in a minima
        res[bpt_tree.num_leaves():] = res[bpt_tree.num_leaves():] + 1

        return res

    return hg.watershed_hierarchy_by_attribute(graph, edge_weights,
                                               num_parents)
    def test_watershed_hierarchy_by_attribute(self):
        g = hg.get_4_adjacency_graph((1, 19))
        edge_weights = np.asarray(
            (0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0))
        # watershed hierarchy by area...
        t, altitudes = hg.watershed_hierarchy_by_attribute(
            g, edge_weights, lambda tree, _: hg.attribute_area(tree))

        ref_parents = np.asarray(
            (19, 19, 20, 20, 20, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22,
             23, 23, 23, 24, 24, 25, 26, 26, 25, 27, 27, 27),
            dtype=np.int64)
        ref_tree = hg.Tree(ref_parents)
        ref_altitudes = np.asarray((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3, 5))

        self.assertTrue(hg.test_tree_isomorphism(t, ref_tree))
        self.assertTrue(np.allclose(altitudes, ref_altitudes))