def calc_maxtree(img, roi): if len(roi) == 4: x0, x1, y0, y1, z = roi patch = img[z, y0:y1, x0:x1] return max_tree(patch) elif len(roi) == 6: x0, x1, y0, y1, z0, z1 = roi assert z0 >= 0 and z1 >= 0, "invalid ROI" patch = img[z0:z1, y0:y1, x0:x1] return max_tree(patch)
def get_nodes(img): shape = img.shape P, S = max_tree(img) keys = np.unique(P) nodes = {} for i, k in enumerate(keys): # declare a node, its key is unique_value nodes[k] = {} # get brother node bro_coord = to_coord(k, shape) nodes[k]["brother"] = bro_coord # get parent parent = P[bro_coord] nodes[k]["parent_key"] = parent nodes[k]["parent"] = to_coord(parent, shape) # if parent not exist, create it if parent not in nodes.keys(): nodes[parent] = {} # set parent node's child if "child_list" not in nodes[parent].keys(): nodes[parent]["child_list"] = [bro_coord] else: nodes[parent]["child_list"].append(bro_coord) # root node's parent is None nodes[S[0]]["parent"] = None nodes[S[0]]["parent_key"] = None return P, S, nodes
def test_area_closing(self): "Test for Area Closing (2 thresholds, all types)" # original image img = np.array( [[240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240], [240, 200, 200, 240, 200, 240, 200, 200, 240, 240, 200, 240], [240, 200, 40, 240, 240, 240, 240, 240, 240, 240, 40, 240], [240, 240, 240, 240, 100, 240, 100, 100, 240, 240, 200, 240], [240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240], [200, 200, 200, 200, 200, 200, 200, 240, 200, 200, 255, 255], [200, 255, 200, 200, 200, 255, 200, 240, 255, 255, 255, 40], [200, 200, 200, 100, 200, 200, 200, 240, 255, 255, 255, 255], [200, 200, 200, 100, 200, 200, 200, 240, 200, 200, 255, 255], [200, 200, 200, 200, 200, 40, 200, 240, 240, 100, 255, 255], [200, 40, 255, 255, 255, 40, 200, 255, 200, 200, 255, 255], [200, 200, 200, 200, 200, 200, 200, 255, 255, 255, 255, 255]], dtype=np.uint8) # expected area closing with area 2 expected_2 = np.array( [[240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240], [240, 200, 200, 240, 240, 240, 200, 200, 240, 240, 200, 240], [240, 200, 200, 240, 240, 240, 240, 240, 240, 240, 200, 240], [240, 240, 240, 240, 240, 240, 100, 100, 240, 240, 200, 240], [240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240], [200, 200, 200, 200, 200, 200, 200, 240, 200, 200, 255, 255], [200, 255, 200, 200, 200, 255, 200, 240, 255, 255, 255, 255], [200, 200, 200, 100, 200, 200, 200, 240, 255, 255, 255, 255], [200, 200, 200, 100, 200, 200, 200, 240, 200, 200, 255, 255], [200, 200, 200, 200, 200, 40, 200, 240, 240, 200, 255, 255], [200, 200, 255, 255, 255, 40, 200, 255, 200, 200, 255, 255], [200, 200, 200, 200, 200, 200, 200, 255, 255, 255, 255, 255]], dtype=np.uint8) # expected diameter closing with diameter 4 expected_4 = np.array( [[240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240], [240, 200, 200, 240, 240, 240, 240, 240, 240, 240, 240, 240], [240, 200, 200, 240, 240, 240, 240, 240, 240, 240, 240, 240], [240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240], [240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240], [200, 200, 200, 200, 200, 200, 200, 240, 240, 240, 255, 255], [200, 255, 200, 200, 200, 255, 200, 240, 255, 255, 255, 255], [200, 200, 200, 200, 200, 200, 200, 240, 255, 255, 255, 255], [200, 200, 200, 200, 200, 200, 200, 240, 200, 200, 255, 255], [200, 200, 200, 200, 200, 200, 200, 240, 240, 200, 255, 255], [200, 200, 255, 255, 255, 200, 200, 255, 200, 200, 255, 255], [200, 200, 200, 200, 200, 200, 200, 255, 255, 255, 255, 255]], dtype=np.uint8) # _full_type_test makes a test with many image types. _full_type_test(img, 2, expected_2, area_closing, connectivity=2) _full_type_test(img, 4, expected_4, area_closing, connectivity=2) P, S = max_tree(invert(img), connectivity=2) _full_type_test(img, 4, expected_4, area_closing, parent=P, tree_traverser=S)
def test_diameter_closing(self): "Test for Diameter Opening (2 thresholds, all types)" img = np.array([[97, 95, 93, 92, 91, 90, 90, 90, 91, 92, 93, 95], [95, 93, 91, 89, 88, 88, 88, 88, 88, 89, 91, 93], [93, 63, 63, 63, 63, 86, 86, 86, 87, 43, 43, 91], [92, 89, 88, 86, 85, 85, 84, 85, 85, 43, 43, 89], [91, 88, 87, 85, 84, 84, 83, 84, 84, 85, 87, 88], [90, 88, 86, 85, 84, 83, 83, 83, 84, 85, 86, 88], [90, 88, 86, 84, 83, 83, 82, 83, 83, 84, 86, 88], [90, 88, 86, 85, 84, 83, 83, 83, 84, 85, 86, 88], [91, 88, 87, 85, 84, 84, 83, 84, 84, 85, 87, 88], [92, 89, 23, 23, 85, 85, 84, 85, 85, 3, 3, 89], [93, 91, 23, 23, 87, 86, 86, 86, 87, 88, 3, 91], [95, 93, 91, 89, 88, 88, 88, 88, 88, 89, 91, 93]], dtype=np.uint8) ex2 = np.array([[97, 95, 93, 92, 91, 90, 90, 90, 91, 92, 93, 95], [95, 93, 91, 89, 88, 88, 88, 88, 88, 89, 91, 93], [93, 63, 63, 63, 63, 86, 86, 86, 87, 43, 43, 91], [92, 89, 88, 86, 85, 85, 84, 85, 85, 43, 43, 89], [91, 88, 87, 85, 84, 84, 83, 84, 84, 85, 87, 88], [90, 88, 86, 85, 84, 83, 83, 83, 84, 85, 86, 88], [90, 88, 86, 84, 83, 83, 83, 83, 83, 84, 86, 88], [90, 88, 86, 85, 84, 83, 83, 83, 84, 85, 86, 88], [91, 88, 87, 85, 84, 84, 83, 84, 84, 85, 87, 88], [92, 89, 23, 23, 85, 85, 84, 85, 85, 3, 3, 89], [93, 91, 23, 23, 87, 86, 86, 86, 87, 88, 3, 91], [95, 93, 91, 89, 88, 88, 88, 88, 88, 89, 91, 93]], dtype=np.uint8) ex4 = np.array([[97, 95, 93, 92, 91, 90, 90, 90, 91, 92, 93, 95], [95, 93, 91, 89, 88, 88, 88, 88, 88, 89, 91, 93], [93, 63, 63, 63, 63, 86, 86, 86, 87, 84, 84, 91], [92, 89, 88, 86, 85, 85, 84, 85, 85, 84, 84, 89], [91, 88, 87, 85, 84, 84, 83, 84, 84, 85, 87, 88], [90, 88, 86, 85, 84, 83, 83, 83, 84, 85, 86, 88], [90, 88, 86, 84, 83, 83, 83, 83, 83, 84, 86, 88], [90, 88, 86, 85, 84, 83, 83, 83, 84, 85, 86, 88], [91, 88, 87, 85, 84, 84, 83, 84, 84, 85, 87, 88], [92, 89, 84, 84, 85, 85, 84, 85, 85, 84, 84, 89], [93, 91, 84, 84, 87, 86, 86, 86, 87, 88, 84, 91], [95, 93, 91, 89, 88, 88, 88, 88, 88, 89, 91, 93]], dtype=np.uint8) # _full_type_test makes a test with many image types. _full_type_test(img, 2, ex2, diameter_closing, connectivity=2) _full_type_test(img, 4, ex4, diameter_closing, connectivity=2) P, S = max_tree(invert(img), connectivity=2) _full_type_test(img, 4, ex4, diameter_opening, parent=P, tree_traverser=S)
def test_diameter_opening(self): "Test for Diameter Opening (2 thresholds, all types)" img = np.array([[5, 7, 9, 11, 12, 12, 12, 12, 12, 11, 9, 7], [7, 10, 11, 13, 14, 14, 15, 14, 14, 13, 11, 10], [9, 40, 40, 40, 40, 16, 16, 16, 16, 60, 60, 11], [11, 13, 15, 16, 17, 18, 18, 18, 17, 60, 60, 13], [12, 14, 16, 17, 18, 19, 19, 19, 18, 17, 16, 14], [12, 14, 16, 18, 19, 19, 19, 19, 19, 18, 16, 14], [12, 15, 16, 18, 19, 19, 20, 19, 19, 18, 16, 15], [12, 14, 16, 18, 19, 19, 19, 19, 19, 18, 16, 14], [12, 14, 16, 17, 18, 19, 19, 19, 18, 17, 16, 14], [11, 13, 80, 80, 17, 18, 18, 18, 17, 100, 100, 13], [9, 11, 80, 80, 16, 16, 16, 16, 16, 15, 100, 11], [7, 10, 11, 13, 14, 14, 15, 14, 14, 13, 11, 10]]) ex2 = np.array([[5, 7, 9, 11, 12, 12, 12, 12, 12, 11, 9, 7], [7, 10, 11, 13, 14, 14, 15, 14, 14, 13, 11, 10], [9, 40, 40, 40, 40, 16, 16, 16, 16, 60, 60, 11], [11, 13, 15, 16, 17, 18, 18, 18, 17, 60, 60, 13], [12, 14, 16, 17, 18, 19, 19, 19, 18, 17, 16, 14], [12, 14, 16, 18, 19, 19, 19, 19, 19, 18, 16, 14], [12, 15, 16, 18, 19, 19, 19, 19, 19, 18, 16, 15], [12, 14, 16, 18, 19, 19, 19, 19, 19, 18, 16, 14], [12, 14, 16, 17, 18, 19, 19, 19, 18, 17, 16, 14], [11, 13, 80, 80, 17, 18, 18, 18, 17, 100, 100, 13], [9, 11, 80, 80, 16, 16, 16, 16, 16, 15, 100, 11], [7, 10, 11, 13, 14, 14, 15, 14, 14, 13, 11, 10]]) ex4 = np.array([[5, 7, 9, 11, 12, 12, 12, 12, 12, 11, 9, 7], [7, 10, 11, 13, 14, 14, 15, 14, 14, 13, 11, 10], [9, 40, 40, 40, 40, 16, 16, 16, 16, 18, 18, 11], [11, 13, 15, 16, 17, 18, 18, 18, 17, 18, 18, 13], [12, 14, 16, 17, 18, 19, 19, 19, 18, 17, 16, 14], [12, 14, 16, 18, 19, 19, 19, 19, 19, 18, 16, 14], [12, 15, 16, 18, 19, 19, 19, 19, 19, 18, 16, 15], [12, 14, 16, 18, 19, 19, 19, 19, 19, 18, 16, 14], [12, 14, 16, 17, 18, 19, 19, 19, 18, 17, 16, 14], [11, 13, 18, 18, 17, 18, 18, 18, 17, 18, 18, 13], [9, 11, 18, 18, 16, 16, 16, 16, 16, 15, 18, 11], [7, 10, 11, 13, 14, 14, 15, 14, 14, 13, 11, 10]]) # _full_type_test makes a test with many image types. _full_type_test(img, 2, ex2, diameter_opening, connectivity=2) _full_type_test(img, 4, ex4, diameter_opening, connectivity=2) P, S = max_tree(img, connectivity=2) _full_type_test(img, 4, ex4, diameter_opening, parent=P, tree_traverser=S)
def test_max_tree(self): "Test for max tree" img_type = np.uint8 img = np.array([[10, 8, 8, 9], [7, 7, 9, 9], [8, 7, 10, 10], [9, 9, 10, 10]], dtype=img_type) P_exp = np.array([[1, 4, 1, 1], [4, 4, 3, 3], [1, 4, 3, 10], [3, 3, 10, 10]], dtype=np.int64) S_exp = np.array([4, 5, 9, 1, 2, 8, 3, 6, 7, 12, 13, 0, 10, 11, 14, 15], dtype=np.int64) for img_type in [np.uint8, np.uint16, np.uint32, np.uint64]: img = img.astype(img_type) P, S = max_tree(img, connectivity=2) assert_array_equal(P, P_exp) assert_array_equal(S, S_exp) for img_type in [np.int8, np.int16, np.int32, np.int64]: img = img.astype(img_type) img_shifted = img - 9 P, S = max_tree(img_shifted, connectivity=2) assert_array_equal(P, P_exp) assert_array_equal(S, S_exp) img_float = img.astype(float) img_float = (img_float - 8) / 2.0 for img_type in [np.float32, np.float64]: img_float = img_float.astype(img_type) P, S = max_tree(img_float, connectivity=2) assert_array_equal(P, P_exp) assert_array_equal(S, S_exp) return
def test_max_tree(self): "Test for max tree" img_type = np.uint8 img = np.array([[10, 8, 8, 9], [7, 7, 9, 9], [8, 7, 10, 10], [9, 9, 10, 10]], dtype=img_type) P_exp = np.array([[1, 4, 1, 1], [4, 4, 3, 3], [1, 4, 3, 10], [3, 3, 10, 10]], dtype=np.int64) S_exp = np.array([4, 5, 9, 1, 2, 8, 3, 6, 7, 12, 13, 0, 10, 11, 14, 15], dtype=np.int64) for img_type in [np.uint8, np.uint16, np.uint32, np.uint64]: img = img.astype(img_type) P, S = max_tree(img, connectivity=2) assert_array_equal(P, P_exp) assert_array_equal(S, S_exp) for img_type in [np.int8, np.int16, np.int32, np.int64]: img = img.astype(img_type) img_shifted = img - 9 P, S = max_tree(img_shifted, connectivity=2) assert_array_equal(P, P_exp) assert_array_equal(S, S_exp) img_float = img.astype(np.float) img_float = (img_float - 8) / 2.0 for img_type in [np.float32, np.float64]: img_float = img_float.astype(img_type) P, S = max_tree(img_float, connectivity=2) assert_array_equal(P, P_exp) assert_array_equal(S, S_exp) return
def test_local_maxima(self): "local maxima for various data types" data = np.array([[10, 11, 13, 14, 14, 15, 14, 14, 13, 11], [11, 13, 15, 16, 16, 16, 16, 16, 15, 13], [13, 15, 40, 40, 18, 18, 18, 60, 60, 15], [14, 16, 40, 40, 19, 19, 19, 60, 60, 16], [14, 16, 18, 19, 19, 19, 19, 19, 18, 16], [15, 16, 18, 19, 19, 20, 19, 19, 18, 16], [14, 16, 18, 19, 19, 19, 19, 19, 18, 16], [14, 16, 80, 80, 19, 19, 19, 100, 100, 16], [13, 15, 80, 80, 18, 18, 18, 100, 100, 15], [11, 13, 15, 16, 16, 16, 16, 16, 15, 13]], dtype=np.uint8) expected_result = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=np.uint64) for dtype in [np.uint8, np.uint64, np.int8, np.int64]: test_data = data.astype(dtype) out = max_tree_local_maxima(test_data, connectivity=1) out_bin = out > 0 assert_array_equal(expected_result, out_bin) assert out.dtype == expected_result.dtype assert np.max(out) == 5 P, S = max_tree(test_data) out = max_tree_local_maxima(test_data, parent=P, tree_traverser=S) assert_array_equal(expected_result, out_bin) assert out.dtype == expected_result.dtype assert np.max(out) == 5
def test_area_opening(self): "Test for Area Opening (2 thresholds, all types)" # original image img = np.array([[15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15], [15, 55, 55, 15, 55, 15, 55, 55, 15, 15, 55, 15], [15, 55, 215, 15, 15, 15, 15, 15, 15, 15, 215, 15], [15, 15, 15, 15, 155, 15, 155, 155, 15, 15, 55, 15], [15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15], [55, 55, 55, 55, 55, 55, 55, 15, 55, 55, 0, 0], [55, 0, 55, 55, 55, 0, 55, 15, 0, 0, 0, 215], [55, 55, 55, 155, 55, 55, 55, 15, 0, 0, 0, 0], [55, 55, 55, 155, 55, 55, 55, 15, 55, 55, 0, 0], [55, 55, 55, 55, 55, 215, 55, 15, 15, 155, 0, 0], [55, 215, 0, 0, 0, 215, 55, 0, 55, 55, 0, 0], [55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0]], dtype=np.uint8) # expected area closing with area 2 expected_2 = np.array([[15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15], [15, 55, 55, 15, 15, 15, 55, 55, 15, 15, 55, 15], [15, 55, 55, 15, 15, 15, 15, 15, 15, 15, 55, 15], [15, 15, 15, 15, 15, 15, 155, 155, 15, 15, 55, 15], [15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15], [55, 55, 55, 55, 55, 55, 55, 15, 55, 55, 0, 0], [55, 0, 55, 55, 55, 0, 55, 15, 0, 0, 0, 0], [55, 55, 55, 155, 55, 55, 55, 15, 0, 0, 0, 0], [55, 55, 55, 155, 55, 55, 55, 15, 55, 55, 0, 0], [55, 55, 55, 55, 55, 215, 55, 15, 15, 55, 0, 0], [55, 55, 0, 0, 0, 215, 55, 0, 55, 55, 0, 0], [55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0]], dtype=np.uint8) # expected diameter closing with diameter 4 expected_4 = np.array([[15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15], [15, 55, 55, 15, 15, 15, 15, 15, 15, 15, 15, 15], [15, 55, 55, 15, 15, 15, 15, 15, 15, 15, 15, 15], [15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15], [15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15], [55, 55, 55, 55, 55, 55, 55, 15, 15, 15, 0, 0], [55, 0, 55, 55, 55, 0, 55, 15, 0, 0, 0, 0], [55, 55, 55, 55, 55, 55, 55, 15, 0, 0, 0, 0], [55, 55, 55, 55, 55, 55, 55, 15, 55, 55, 0, 0], [55, 55, 55, 55, 55, 55, 55, 15, 15, 55, 0, 0], [55, 55, 0, 0, 0, 55, 55, 0, 55, 55, 0, 0], [55, 55, 55, 55, 55, 55, 55, 0, 0, 0, 0, 0]], dtype=np.uint8) # _full_type_test makes a test with many image types. _full_type_test(img, 2, expected_2, area_opening, connectivity=2) _full_type_test(img, 4, expected_4, area_opening, connectivity=2) P, S = max_tree(img, connectivity=2) _full_type_test(img, 4, expected_4, area_opening, parent=P, tree_traverser=S)
# We define a small test image. # For clarity, we choose an example image, where image values cannot be # confounded with indices (different range). image = np.array([[40, 40, 39, 39, 38], [40, 41, 39, 39, 39], [30, 30, 30, 32, 32], [33, 33, 30, 32, 35], [30, 30, 30, 33, 36]], dtype=np.uint8) ##################################################################### # Max-tree # ======== # Next, we calculate the max-tree of this image. # max-tree of the image P, S = max_tree(image) P_rav = P.ravel() ##################################################################### # Image plots # =========== # Then, we visualize the image and its raveled indices. # Concretely, we plot the image with the following overlays: # - the image values # - the raveled indices (serve as pixel identifiers) # - the output of the max_tree function # raveled image image_rav = image.ravel()