def test_tree_fusion3(self): im1 = np.asarray( (0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 2, 1, 1, 1, 3, 3, 3, 2, 1, 1, 1, 3, 3, 3, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0), dtype=np.float32) im2 = np.asarray( (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 2, 0, 0, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), dtype=np.float32) g = hg.get_4_adjacency_implicit_graph((6, 7)) t1, _ = hg.component_tree_max_tree(g, im1) t2, _ = hg.component_tree_max_tree(g, im2) res = hg.tree_fusion_depth_map((t1, t2)) expected = np.asarray( (0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 2, 1, 1, 1, 3, 4, 3, 2, 2, 3, 1, 3, 3, 3, 2, 2, 3, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0), dtype=np.float32) diff = expected - res self.assertTrue(np.all(diff == diff[0]))
def component_tree_tree_of_shapes_image2d(image, padding='mean', original_size=True, exterior_vertex=0): """ Tree of shapes of a 2d image. The Tree of Shapes was described in [1]_. The algorithm used in this implementation was first described in [2]_. The tree is computed in the interpolated multivalued Khalimsky space to provide a continuous and autodual representation of input image. Possible values of `padding` are `'none'`, `'mean'`, and `'zero'`. If `padding` is different from 'none', an extra border of pixels is added to the input image before anything else. This will ensure the existence of a shape encompassing all the shapes inside the input image (if exterior_vertex is inside the extra border): this shape will be the root of the tree. The padding value can be: - 0 if :attr:`padding` is equal to ``"zero"``; - the mean value of the boundary pixels of the input image if :attr:`padding` is equal to ``"mean"``. If :attr:`original_size` is ``True``, all the nodes corresponding to pixels not belonging to the input image are removed (except for the root node). If :attr:`original_size` is ``False``, the returned tree is the tree constructed in the interpolated/padded space. In practice if the size of the input image is :math:`(h, w)`, the leaves of the returned tree will correspond to an image of size: - :math:`(h, w)` if :attr:`original_size` is ``True``; - :math:`(h * 2 - 1, w * 2 - 1)` is :attr:`original_size` is ``False`` and padding is ``"none"``; and - :math:`((h + 2) * 2 - 1, (w + 2) * 2 - 1)` otherwise. :attr:`Exterior_vertex` defines the linear coordinates of the pixel corresponding to the exterior (interior and exterior of a shape is defined with respect to this point). The coordinate of this point must be given in the padded/interpolated space. .. [1] Pa. Monasse, and F. Guichard, "Fast computation of a contrast-invariant image representation," \ Image Processing, IEEE Transactions on, vol.9, no.5, pp.860-872, May 2000 .. [2] Th. Géraud, E. Carlinet, S. Crozet, and L. Najman, "A Quasi-linear Algorithm to Compute the Tree \ of Shapes of nD Images", ISMM 2013. :param image: must be a 2d array :param padding: possible values are `'none'`, `'zero'`, and `'mean'` (default = `'mean'`) :param original_size: remove all nodes corresponding to interpolated/padded pixels (default = `True`) :param exterior_vertex: linear coordinate of the exterior point :return: a tree (Concept :class:`~higra.CptHierarchy`) and its node altitudes """ res = hg.cpp._component_tree_tree_of_shapes_image2d( image, padding, original_size, exterior_vertex) tree = res.tree() altitudes = res.altitudes() g = hg.get_4_adjacency_implicit_graph(image.shape) hg.CptHierarchy.link(tree, g) return tree, altitudes
def test_create_graph(self): shape = (2, 3) nl = ((-1, 0), (0, -1), (0, 1), (1, 0)) g1 = hg.RegularGraph2d(hg.EmbeddingGrid2d(shape), nl) g2 = hg.get_4_adjacency_implicit_graph(shape) g3 = hg.get_8_adjacency_implicit_graph(shape) for g in (g1, g2, g3): self.assertTrue(g.num_vertices() == 6)
def test_reconstruct_leaf_data_component_tree_default(self): g = hg.get_4_adjacency_implicit_graph((1, 6)) vertex_values = np.asarray((1, 5, 4, 3, 3, 6), dtype=np.int32) tree, altitudes = hg.component_tree_max_tree(g, vertex_values) area = hg.attribute_area(tree) output = hg.reconstruct_leaf_data(tree, area) ref = np.asarray((6, 1, 2, 5, 5, 1), dtype=np.int32) self.assertTrue(np.all(ref == output))
def test_reconstruct_leaf_data_component_tree(self): g = hg.get_4_adjacency_implicit_graph((1, 6)) vertex_values = np.asarray((1, 5, 4, 3, 3, 6), dtype=np.int32) tree, altitudes = hg.component_tree_max_tree(g, vertex_values) condition = np.asarray((True, False, True, False, True, True, False, True, False, True, False), np.bool_) output = hg.reconstruct_leaf_data(tree, altitudes, condition) ref = np.asarray((1, 4, 4, 1, 1, 6), dtype=np.int32) self.assertTrue(np.all(ref == output))
def test_tree_attribute_extrema2(self): graph = hg.get_4_adjacency_implicit_graph((4, 4)) vertex_weights = np.asarray( (0, 1, 4, 4, 7, 5, 6, 8, 2, 3, 4, 1, 9, 8, 6, 7)) tree, altitudes = hg.component_tree_max_tree(graph, vertex_weights) extrema = hg.attribute_extrema(tree, altitudes) expected_extrema = np.asarray( (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0)) self.assertTrue(np.all(expected_extrema == extrema))
def test_out_edge_iterator4(self): shape = (2, 3) g = hg.get_4_adjacency_implicit_graph(shape) ref = [[(0, 1), (0, 3)], [(1, 0), (1, 2), (1, 4)], [(2, 1), (2, 5)], [(3, 0), (3, 4)], [(4, 1), (4, 3), (4, 5)], [(5, 2), (5, 4)]] for v in g.vertices(): res = [] for e in g.out_edges(v): res.append((g.source(e), g.target(e))) self.assertTrue(res == ref[v])
def test_vertices_iterator(self): shape = (2, 3) g1 = hg.get_4_adjacency_implicit_graph(shape) g2 = hg.get_8_adjacency_implicit_graph(shape) vref = [0, 1, 2, 3, 4, 5]; for g in (g1, g2): vtest = []; for v in g.vertices(): vtest.append(v) self.assertTrue(vtest == vref)
def test_as_explicit_graph(self): shape = (2, 3) g_imp = hg.get_4_adjacency_implicit_graph(shape) g_exp = g_imp.as_explicit_graph() self.assertTrue( TestRegularGraph.graph_implicit_explicit_equal(g_imp, g_exp)) g_imp = hg.get_8_adjacency_implicit_graph(shape) g_exp = g_imp.as_explicit_graph() self.assertTrue( TestRegularGraph.graph_implicit_explicit_equal(g_imp, g_exp))
def test_component_tree_max_tree(self): graph = hg.get_4_adjacency_implicit_graph((4, 4)) vertex_weights = np.asarray( ((0, 1, 4, 4), (7, 5, 6, 8), (2, 3, 4, 1), (9, 8, 6, 7)), dtype=np.float64) tree, altitudes = hg.component_tree_max_tree(graph, vertex_weights) expected_parents = np.asarray( (28, 27, 24, 24, 20, 23, 22, 18, 26, 25, 24, 27, 16, 17, 21, 19, 17, 21, 22, 21, 23, 24, 23, 24, 25, 26, 27, 28, 28), np.int64) expected_altitudes = np.asarray( (0., 1., 4., 4., 7., 5., 6., 8., 2., 3., 4., 1., 9., 8., 6., 7., 9., 8., 8., 7., 7., 6., 6., 5., 4., 3., 2., 1., 0.), np.float64) self.assertTrue(np.all(expected_parents == tree.parents())) self.assertTrue(np.allclose(expected_altitudes, altitudes))
def test_simplify_tree_propagate_category(self): g = hg.get_4_adjacency_implicit_graph((1, 6)) vertex_values = np.asarray((1, 5, 4, 3, 3, 6), dtype=np.int32) tree, altitudes = hg.component_tree_max_tree(g, vertex_values) condition = np.asarray((False, False, False, False, False, False, False, True, False, True, False), np.bool) new_tree, node_map = hg.simplify_tree(tree, condition) self.assertTrue( np.all(new_tree.parents() == (8, 7, 7, 8, 8, 6, 8, 8, 8))) self.assertTrue(np.all(node_map == (0, 1, 2, 3, 4, 5, 6, 8, 10))) self.assertTrue(new_tree.category() == hg.TreeCategory.ComponentTree) rec = hg.reconstruct_leaf_data(new_tree, altitudes[node_map]) self.assertTrue(np.all(rec == (1, 4, 4, 1, 1, 6)))
def test_create_graph(self): shape = (2, 3) nl = ((-1, 0), (0, -1), (0, 1), (1, 0)) g1 = hg.RegularGraph2d(hg.EmbeddingGrid2d(shape), nl) g2 = hg.get_4_adjacency_implicit_graph(shape) g3 = hg.get_8_adjacency_implicit_graph(shape) for g in (g1, g2, g3): self.assertTrue(g.num_vertices() == 6) self.assertTrue(np.all(g1.shape() == shape)) self.assertTrue(np.all(g1.neighbour_list() == nl)) g4 = hg.RegularGraph2d(g1.shape(), g1.neighbour_list()) self.assertTrue(np.all(g4.shape() == shape)) self.assertTrue(np.all(g4.neighbour_list() == nl))
def test_area_filter_max_tree(self): graph = hg.get_4_adjacency_implicit_graph((5, 5)) vertex_weights = np.asarray( ((-5, 2, 2, 5, 5), (-4, 2, 2, 6, 5), (3, 3, 3, 3, 3), (-2, -2, -2, 9, 7), (-1, 0, -2, 8, 9)), dtype=np.float64) tree, altitudes = hg.component_tree_max_tree(graph, vertex_weights) area = hg.attribute_area(tree) filtered_weights = hg.reconstruct_leaf_data(tree, altitudes, area <= 4) expected_filtered_weights = \ np.asarray(((-5, 2, 2, 3, 3), (-4, 2, 2, 3, 3), (3, 3, 3, 3, 3), (-2, -2, -2, 3, 3), (-2, -2, -2, 3, 3)), dtype=np.float64) self.assertTrue(np.all(filtered_weights == expected_filtered_weights))
def test_attribute_extinction_value2(self): graph = hg.get_4_adjacency_implicit_graph((4, 4)) vertex_weights = np.asarray( (0, 1, 4, 4, 7, 5, 6, 8, 2, 3, 4, 1, 9, 8, 6, 7)) tree, altitudes = hg.component_tree_max_tree(graph, vertex_weights) area = hg.attribute_area(tree) expected_ext = np.asarray( (0, 0, 0, 0, 1, 0, 0, 4, 0, 0, 0, 0, 16, 0, 0, 1, 16, 16, 4, 1, 1, 16, 4, 4, 16, 16, 16, 16, 16)) ext = hg.attribute_extinction_value(tree, altitudes, area) self.assertTrue(np.all(expected_ext == ext)) ext = hg.attribute_extinction_value(tree, altitudes, area, False) self.assertTrue(np.all(expected_ext == ext)) ext = hg.attribute_extinction_value(tree, altitudes, area, "decreasing") self.assertTrue(np.all(expected_ext == ext))
def test_moment_of_inertia(self): """ The test image is a binary image of 5x15 pixels: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1 1 1 0 0 1 1 1 0 1 0 1 1 1 0 1 1 1 0 0 0 1 0 0 1 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 The max-tree of this image is composed of five non-leaf nodes: the root and the four maxima (a cross, a vertical line, a horizontal line and a square) Using the formula given in https://en.wikipedia.org/wiki/Image_moment, the moment of inertia of each shape is: - Cross: 0.16 - Square: 0.1481 - Vertical and horizontal lines: 0.2222 - Rectangle (root): 0.2756 The moment of inertia of the leaf nodes are set to 0.0 """ graph = hg.get_4_adjacency_implicit_graph((5, 15)) vertex_weights = np.asarray( [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0], [0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0], [0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) tree, altitudes = hg.component_tree_max_tree(graph, vertex_weights) res = hg.attribute_moment_of_inertia(tree) ref = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.1481, 0.2222, 0.16, 0.2222, 0.2756) self.assertTrue(np.allclose(res, ref, atol=0.0001))
def test_argument_helper_accept_RegularGraph2d(self): g = hg.get_4_adjacency_implicit_graph((2, 3)) self.assertTrue(accept_RegularGraph2d(g) == 2) self.assertRaises(MyException, accept_RegularGraph2d, (4, 5), (2, 3)) hg.clear_all_attributes()
def test_dynamic_attributes(self): shape = (2, 3) g = hg.get_4_adjacency_implicit_graph(shape) g.new_attribute = 42 self.assertTrue(g.new_attribute == 42)