|
| 1 | +import numpy as np |
| 2 | +import pytest |
| 3 | + |
| 4 | +import bioimage_cpp as bic |
| 5 | + |
| 6 | + |
| 7 | +def _node_degrees(graph): |
| 8 | + return np.fromiter( |
| 9 | + ( |
| 10 | + len(graph.node_adjacency(node)) |
| 11 | + for node in range(graph.number_of_nodes) |
| 12 | + ), |
| 13 | + dtype=np.uint64, |
| 14 | + count=graph.number_of_nodes, |
| 15 | + ) |
| 16 | + |
| 17 | + |
| 18 | +def test_skeleton_to_graph_preserves_teasar_topology_and_vertex_ids(): |
| 19 | + mask = np.zeros((9, 11, 10), dtype=np.uint8) |
| 20 | + mask[4, 5, 1:5] = 1 |
| 21 | + for step in range(5): |
| 22 | + mask[4, 5 - step, 4 + step] = 1 |
| 23 | + mask[4, 5 + step, 4 + step] = 1 |
| 24 | + |
| 25 | + vertices, edges, _ = bic.skeleton.teasar(mask) |
| 26 | + graph = bic.skeleton.skeleton_to_graph(vertices, edges) |
| 27 | + |
| 28 | + assert isinstance(graph, bic.graph.UndirectedGraph) |
| 29 | + assert graph.number_of_nodes == len(vertices) |
| 30 | + assert graph.number_of_edges == len(edges) |
| 31 | + np.testing.assert_array_equal(graph.uv_ids(), edges) |
| 32 | + |
| 33 | + degrees = _node_degrees(graph) |
| 34 | + endpoints = { |
| 35 | + tuple(vertex.astype(int)) for vertex in vertices[degrees <= 1] |
| 36 | + } |
| 37 | + assert endpoints == {(4, 5, 1), (4, 1, 8), (4, 9, 8)} |
| 38 | + assert np.count_nonzero(degrees > 2) == 1 |
| 39 | + |
| 40 | + |
| 41 | +def test_skeleton_to_graph_preserves_empty_and_isolated_vertices(): |
| 42 | + empty = bic.skeleton.skeleton_to_graph( |
| 43 | + np.empty((0, 3), dtype=np.float64), |
| 44 | + np.empty((0, 2), dtype=np.uint64), |
| 45 | + ) |
| 46 | + assert empty.number_of_nodes == 0 |
| 47 | + assert empty.number_of_edges == 0 |
| 48 | + |
| 49 | + isolated = bic.skeleton.skeleton_to_graph( |
| 50 | + np.array([[2.0, 3.0, 4.0]]), |
| 51 | + np.empty((0, 2), dtype=np.uint64), |
| 52 | + ) |
| 53 | + assert isolated.number_of_nodes == 1 |
| 54 | + assert isolated.number_of_edges == 0 |
| 55 | + np.testing.assert_array_equal(_node_degrees(isolated), [0]) |
| 56 | + |
| 57 | + |
| 58 | +def test_skeleton_to_graph_rejects_invalid_inputs(): |
| 59 | + with pytest.raises(ValueError, match="vertices must be a 2D array"): |
| 60 | + bic.skeleton.skeleton_to_graph( |
| 61 | + np.array([0.0, 1.0, 2.0]), |
| 62 | + np.empty((0, 2), dtype=np.uint64), |
| 63 | + ) |
| 64 | + |
| 65 | + vertices = np.zeros((2, 3), dtype=np.float64) |
| 66 | + with pytest.raises(ValueError, match="uvs must have shape"): |
| 67 | + bic.skeleton.skeleton_to_graph(vertices, [0, 1]) |
| 68 | + with pytest.raises(IndexError, match="node id must be < number_of_nodes"): |
| 69 | + bic.skeleton.skeleton_to_graph(vertices, [[0, 2]]) |
0 commit comments