def mean_pb_hierarchy(graph, edge_weights, shape, edge_orientations=None): """ Mean probability boundary hierarchy. The method is described in: P. Arbelaez, M. Maire, C. Fowlkes and J. Malik, "Contour Detection and Hierarchical Image Segmentation," in IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 33, no. 5, pp. 898-916, May 2011. doi: 10.1109/TPAMI.2010.161 This does not include gradient estimation. The returned hierarchy is defined on the gradient watershed super-pixels. The final sigmoid scaling of the hierarchy altitude is not performed. :param graph: must be a 4 adjacency graph (Concept :class:`~higra.CptGridGraph`) :param edge_weights: gradient value on edges :param shape: shape of the graph, i.e. a pair (height, width) (deduced from :class:`~higra.CptGridGraph`) :param edge_orientations: estimated orientation of the gradient on edges (optional) :return: a tree (Concept :class:`~higra.CptHierarchy`) and its node altitudes """ shape = hg.normalize_shape(shape) if edge_orientations is not None: edge_weights, edge_orientations = hg.cast_to_common_type( edge_weights, edge_orientations) rag, vertex_map, edge_map, tree, altitudes = hg.cpp._mean_pb_hierarchy( graph, shape, edge_weights, edge_orientations) hg.CptRegionAdjacencyGraph.link(rag, graph, vertex_map, edge_map) hg.CptHierarchy.link(tree, rag) return tree, altitudes
def oriented_watershed(graph, edge_weights, shape, edge_orientations=None): """ Creates a region adjacency graph (rag) with the oriented watershed transform. The method is described in: P. Arbelaez, M. Maire, C. Fowlkes and J. Malik, "Contour Detection and Hierarchical Image Segmentation," in IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 33, no. 5, pp. 898-916, May 2011. doi: 10.1109/TPAMI.2010.161 If no edge orientations are provided, then the weight of a rag edge between region i and j is the mean weight of the edges linking a vertex of i to a vertex of j. This does not include gradient estimation. :param graph: must be a 4 adjacency graph (Concept :class:`~higra.CptGridGraph`) :param edge_weights: gradient value on edges :param shape: shape of the graph, i.e. a pair (height, width) (deduced from :class:`~higra.CptGridGraph`) :param edge_orientations: estimated orientation of the gradient on edges (optional) :return: a pair (rag, rag_edge_weights): the region adjacency graph (Concept :class:`~higra.CptRegionAdjacencyGraph`) and its estimated edge_weights """ shape = hg.normalize_shape(shape) if edge_orientations is not None: edge_weights, edge_orientations = hg.cast_to_common_type( edge_weights, edge_orientations) rag, vertex_map, edge_map, rag_edge_weights = hg.cpp._oriented_watershed( graph, shape, edge_weights, edge_orientations) hg.CptRegionAdjacencyGraph.link(rag, graph, vertex_map, edge_map) return rag, rag_edge_weights
def get_nd_regular_implicit_graph(shape, neighbour_list): """ Creates an implicit regular graph of the given :attr:`shape` with the adjacency given as a :attr:`neighbour_list`. See the helper function :func:`~higra.mask_2_neighbours` to create a suitable :attr:`neighbour_list`. :Example: Create a 2d 4-adjacency implicit graph of size ``(13, 24)``: >>> graph = get_nd_regular_implicit_graph((13, 24), ((-1, 0), (0, -1), (0, 1), (1, 0))) Create a 3d 6-adjacency implicit graph of size ``(10, 13, 24)``: >>> mask = [[[0, 0, 0], [0, 1, 0], [0, 0, 0]], >>> [[0, 1, 0], [1, 0, 1], [0, 1, 0]], >>> [[0, 0, 0], [0, 1, 0], [0, 0, 0]]] >>> neighbours = mask_2_neighbours(mask) >>> graph = get_nd_regular_implicit_graph((10, 13, 24), neighbours) :param shape: a tuple of :math:`n` elements representing the dimension of the graph vertices. :param neighbour_list: a 2d array of :math:`k` :math:`n`-d integer vectors :return: an implicit regular graph """ neighbour_list = np.asarray(neighbour_list) if not np.issubdtype(neighbour_list.dtype, np.integer): raise ValueError("'neighbour_list' must be of integral type.") if neighbour_list.ndim != 2: raise ValueError("'neighbour_list' must be a 2d array.") shape = hg.normalize_shape(shape) if len(shape) != neighbour_list.shape[1]: raise ValueError( "Shape size does not match provided adjacency dimension.") if len(shape) > 5 or len(shape) == 0: raise ValueError("Shape size must between 1 and 5 (included).") if len(shape) == 1: graph = hg.RegularGraph1d(shape, neighbour_list) elif len(shape) == 2: graph = hg.RegularGraph2d(shape, neighbour_list) elif len(shape) == 3: graph = hg.RegularGraph3d(shape, neighbour_list) elif len(shape) == 4: graph = hg.RegularGraph4d(shape, neighbour_list) elif len(shape) == 5: graph = hg.RegularGraph5d(shape, neighbour_list) hg.CptGridGraph.link(graph, shape) hg.set_attribute(graph, "no_border_vertex_out_degree", neighbour_list.shape[0]) return graph
def rebuild_mean_pb_hierarchy(self, rag, vertex_map, edge_map, tree, altitudes, shape): shape = hg.normalize_shape(shape) graph = hg.get_4_adjacency_graph(shape) hg.CptRegionAdjacencyGraph.link(rag, graph, vertex_map, edge_map) hg.CptHierarchy.link(tree, rag) return tree, altitudes
def ___new__(cls, shape, neighbour_list): if hg.is_iterable(shape): shape = hg.normalize_shape(shape) elif str(type(shape)).find("EmbeddingGrid") != -1: shape = shape.shape() else: raise ValueError("Invalid shape type.") g = cls._make_instance(shape, neighbour_list) hg.CptGridGraph.link(g, shape) return g
def get_8_adjacency_implicit_graph(shape): """ Create an implicit undirected 8 adjacency graph of the given shape (edges are not stored). :param shape: a pair (height, width) :return: a graph (Concept :class:`~higra.CptGridGraph`) """ shape = hg.normalize_shape(shape) graph = hg.cpp._get_8_adjacency_implicit_graph(shape) hg.CptGridGraph.link(graph, shape) hg.set_attribute(graph, "no_border_vertex_out_degree", 8) return graph
def graph_4_adjacency_2_khalimsky(graph, edge_weights, shape, add_extra_border=False): """ Create a contour image in the Khalimsky grid from a 4 adjacency edge-weighted graph. :param graph: must be a 4 adjacency 2d graph (Concept :class:`~higra.CptGridGraph`) :param edge_weights: edge weights of the graph :param shape: shape of the graph (deduced from :class:`~higra.CptGridGraph`) :param add_extra_border: if False result size is 2 * shape - 1 and 2 * shape + 1 otherwise :return: a 2d array """ shape = hg.normalize_shape(shape) return hg.cpp._graph_4_adjacency_2_khalimsky(graph, shape, edge_weights, add_extra_border)
def khalimsky_2_graph_4_adjacency(khalimsky, extra_border=False): """ Create a 4 adjacency edge-weighted graph from a contour image in the Khalimsky grid. :param khalimsky: a 2d array :param extra_border: if False the shape of the Khalimsky image is 2 * shape - 1 and 2 * shape + 1 otherwise, where shape is the shape of the resulting grid graph :return: a graph (Concept :class:`~higra.CptGridGraph`) and its edge weights """ graph, embedding, edge_weights = hg.cpp._khalimsky_2_graph_4_adjacency( khalimsky, extra_border) hg.CptGridGraph.link(graph, hg.normalize_shape(embedding.shape())) hg.set_attribute(graph, "no_border_vertex_out_degree", 4) return graph, edge_weights
def get_4_adjacency_implicit_graph(shape): """ Create an implicit undirected 4 adjacency graph of the given shape (edges are not stored). :param shape: a pair (height, width) :return: a graph (Concept :class:`~higra.CptGridGraph`) """ shape = hg.normalize_shape(shape) if len(shape) != 2: raise ValueError("Shape must be a 1d array of size 2.") neighbours = np.array(((-1, 0), (0, -1), (0, 1), (1, 0)), dtype=np.int64) graph = hg.RegularGraph2d(shape, neighbours) hg.CptGridGraph.link(graph, shape) hg.set_attribute(graph, "no_border_vertex_out_degree", 4) return graph
def multiscale_mean_pb_hierarchy(graph, fine_edge_weights, others_edge_weights, shape, edge_orientations=None): """ Multiscale mean probability boundary hierarchy. The method is described in: J. Pont-Tuset, P. Arbeláez, J. Barron, F. Marques, and J. Malik Multiscale Combinatorial Grouping for Image Segmentation and Object Proposal Generation IEEE Transactions on Pattern Analysis and Machine Intelligence (TPAMI), vol. 39, no. 1, pp. 128 - 140, 2017. and in: K.K. Maninis, J. Pont-Tuset, P. Arbeláez and L. Van Gool Convolutional Oriented Boundaries: From Image Segmentation to High-Level Tasks IEEE Transactions on Pattern Analysis and Machine Intelligence (TPAMI), vol. 40, no. 4, pp. 819 - 833, 2018. This does not include gradient estimation. The returned hierarchy is defined on the gradient watershed super-pixels. The final sigmoid scaling of the hierarchy altitude is not performed. :param graph: must be a 4 adjacency graph (Concept :class:`~higra.CptGridGraph`) :param fine_edge_weights: edge weights of the finest gradient :param others_edge_weights: tuple of gradient value on edges :param shape: shape of the graph, i.e. a pair (height, width) (deduced from :class:`~higra.CptGridGraph`) :param edge_orientations: estimated orientation of the gradient on edges (optional) :return: a tree (Concept :class:`~higra.CptHierarchy`) and its node altitudes """ shape = hg.normalize_shape(shape) tree_fine, altitudes_fine = hg.mean_pb_hierarchy( graph, fine_edge_weights, shape=shape, edge_orientations=edge_orientations) saliency_fine = hg.saliency(tree_fine, altitudes_fine) super_vertex_fine = hg.labelisation_hierarchy_supervertices( tree_fine, altitudes_fine) other_hierarchies = [] for edge_weights in others_edge_weights: tree_coarse, altitudes_coarse = hg.mean_pb_hierarchy( graph, edge_weights, shape=shape, edge_orientations=edge_orientations) other_hierarchies.append((tree_coarse, altitudes_coarse)) aligned_saliencies = hg.align_hierarchies(graph, super_vertex_fine, other_hierarchies) for saliency in aligned_saliencies: saliency_fine += saliency saliency_fine *= (1.0 / (1 + len(others_edge_weights))) return hg.mean_pb_hierarchy(graph, saliency_fine, shape=shape)