From c5f8f27e4460316454ffa6ddb18507431de88b12 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Sun, 14 Dec 2014 06:27:57 +0530 Subject: [PATCH] code cleanup and removed test --- doc/examples/plot_rag_merge.py | 81 +++++++++++++++++++++- skimage/graph/__init__.py | 3 +- skimage/graph/graph_merge.py | 115 +++++++------------------------- skimage/graph/tests/test_rag.py | 20 ------ 4 files changed, 104 insertions(+), 115 deletions(-) diff --git a/doc/examples/plot_rag_merge.py b/doc/examples/plot_rag_merge.py index d15ee954..5120d96b 100644 --- a/doc/examples/plot_rag_merge.py +++ b/doc/examples/plot_rag_merge.py @@ -11,12 +11,91 @@ until no highly similar region pairs remain. """ from skimage import graph, data, io, segmentation, color +import numpy as np +def _weight_mean_color(graph, src, dst, n): + """Callback to handle merging nodes by recomputing mean color. + + The method expects that the mean color of `dst` is already computed. + + Parameters + ---------- + graph : RAG + The graph under consideration. + src, dst : int + The vertices in `graph` to be merged. + n : int + A neighbor of `src` or `dst` or both. + + Returns + ------- + weight : float + The absolute difference of the mean color between node `dst` and `n`. + """ + + #print 'merging + diff = graph.node[dst]['mean color'] - graph.node[n]['mean color'] + diff = np.linalg.norm(diff) + return diff + + +def _pre_merge_mean_color(graph, src, dst): + """Callback called before merging two nodes of a mean color distance graph. + + This method computes the mean color of `dst`. + + Parameters + ---------- + graph : RAG + The graph under consideration. + src, dst : int + The vertices in `graph` to be merged. + """ + graph.node[dst]['total color'] += graph.node[src]['total color'] + graph.node[dst]['pixel count'] += graph.node[src]['pixel count'] + graph.node[dst]['mean color'] = (graph.node[dst]['total color'] / + graph.node[dst]['pixel count']) + + +def merge_hierarchical_mean_color(labels, rag, thresh, rag_copy=True, + in_place_merge=False): + """Perform hierarchical merging of a color distance RAG. + + Greedily merges the most similar pair of nodes until no edges lower than + `thresh` remain. + + Parameters + ---------- + labels : ndarray + The array of labels. + rag : RAG + The Region Adjacency Graph. + thresh : float + Regions connected by an edge with weight smaller than `thresh` are + merged. + rag_copy : bool, optional + If set, the RAG copied before modifying. + in_place_merge : bool, optional + If set, the nodes are merged in place. Otherwise, a new node is + created for each merge. + + Examples + -------- + >>> from skimage import data, graph, segmentation + >>> img = data.coffee() + >>> labels = segmentation.slic(img) + >>> rag = graph.rag_mean_color(img, labels) + >>> new_labels = graph.merge_hierarchical_mean_color(labels, rag, 40) + """ + return graph.merge_hierarchical(labels, rag, thresh, rag_copy, + in_place_merge, _pre_merge_mean_color, + _weight_mean_color) + img = data.coffee() labels = segmentation.slic(img, compactness=30, n_segments=400) g = graph.rag_mean_color(img, labels) -labels2 = graph.merge_hierarchical_mean_color(labels, g, 40) +labels2 = merge_hierarchical_mean_color(labels, g, 40) g2 = graph.rag_mean_color(img, labels2) out = color.label2rgb(labels2, img, kind='avg') diff --git a/skimage/graph/__init__.py b/skimage/graph/__init__.py index 7122bb3c..f93708c9 100644 --- a/skimage/graph/__init__.py +++ b/skimage/graph/__init__.py @@ -2,7 +2,7 @@ from .spath import shortest_path from .mcp import MCP, MCP_Geometric, MCP_Connect, MCP_Flexible, route_through_array from .graph_cut import cut_threshold, cut_normalized from .rag import rag_mean_color, RAG, draw_rag -from .graph_merge import merge_hierarchical, merge_hierarchical_mean_color +from .graph_merge import merge_hierarchical ncut = cut_normalized @@ -18,5 +18,4 @@ __all__ = ['shortest_path', 'ncut', 'draw_rag', 'merge_hierarchical', - 'merge_hierarchical_mean_color', 'RAG'] diff --git a/skimage/graph/graph_merge.py b/skimage/graph/graph_merge.py index 4158b0cf..d101cd60 100644 --- a/skimage/graph/graph_merge.py +++ b/skimage/graph/graph_merge.py @@ -2,50 +2,6 @@ import numpy as np import heapq -def _weight_mean_color(graph, src, dst, n): - """Callback to handle merging nodes by recomputing mean color. - - The method expects that the mean color of `dst` is already computed. - - Parameters - ---------- - graph : RAG - The graph under consideration. - src, dst : int - The vertices in `graph` to be merged. - n : int - A neighbor of `src` or `dst` or both. - - Returns - ------- - weight : float - The absolute difference of the mean color between node `dst` and `n`. - """ - - #print 'merging - diff = graph.node[dst]['mean color'] - graph.node[n]['mean color'] - diff = np.linalg.norm(diff) - return diff - - -def _pre_merge_mean_color(graph, src, dst): - """Callback called before merging two nodes of a mean color distance graph. - - This method computes the mean color of `dst`. - - Parameters - ---------- - graph : RAG - The graph under consideration. - src, dst : int - The vertices in `graph` to be merged. - """ - graph.node[dst]['total color'] += graph.node[src]['total color'] - graph.node[dst]['pixel count'] += graph.node[src]['pixel count'] - graph.node[dst]['mean color'] = (graph.node[dst]['total color'] / - graph.node[dst]['pixel count']) - - def _revalidate_node_edges(rag, node, heap_list): """Handles validation and invalidation of edges incident to a node. @@ -81,38 +37,21 @@ def _revalidate_node_edges(rag, node, heap_list): heapq.heappush(heap_list, heap_item) -def merge_hierarchical_mean_color(labels, rag, thresh, in_place=True, merge_in_place=False): - """Perform hierarchical merging of a color distance RAG. +def _copy_node(graph, node_id, copy_id): + """ Copies `node_id` into `copy_id` along with all its edges. """ - Greedily merges the most similar pair of nodes until no edges lower than - `thresh` remain. + graph._add_node(copy_id) + graph.node[copy_id] = graph.node[node_id] - Parameters - ---------- - labels : ndarray - The array of labels. - rag : RAG - The Region Adjacency Graph. - thresh : float - Regions connected by an edge with weight smaller than `thresh` are - merged. - in_place : bool, optional - If set, the RAG is modified in place. + for nbr in graph.neighbors(node_id): + wt = graph[node_id][nbr]['weight'] + graph.add_edge(nbr, copy_id, {'weight': wt}) - Examples - -------- - >>> from skimage import data, graph, segmentation - >>> img = data.coffee() - >>> labels = segmentation.slic(img) - >>> rag = graph.rag_mean_color(img, labels) - >>> new_labels = graph.merge_hierarchical_mean_color(labels, rag, 40) - """ - return merge_hierarchical(labels, rag, thresh, in_place, merge_in_place, - _pre_merge_mean_color, _weight_mean_color) + graph.remove_node(node_id) -def merge_hierarchical(labels, rag, thresh, in_place, merge_in_place,pre_merge_func, - weight_func): +def merge_hierarchical(labels, rag, thresh, rag_copy, in_place_merge, + merge_func, weight_func): """Perform hierarchical merging of a RAG. Greedily merges the most similar pair of nodes until no edges lower than @@ -127,12 +66,15 @@ def merge_hierarchical(labels, rag, thresh, in_place, merge_in_place,pre_merge_f thresh : float Regions connected by an edge with weight smaller than `thresh` are merged. - in_place : bool, optional - If set, the RAG is modified in place. - pre_merge_func : callable + rag_copy : bool, optional + If set, the RAG copied before modifying. + in_place_merge : bool, optional + If set, the nodes are merged in place. Otherwise, a new node is + created for each merge.. + merge_func : callable This function is called before merging two nodes. For the RAG `graph` while merging `src` and `dst`, it is called as follows - ``pre_merge_func(graph, src, dst)``. + ``merge_func(graph, src, dst)``. weight_func : callable The function to compute the new weights of the nodes adjacent to the merged node. This is directly supplied as the argument `weight_func` @@ -144,7 +86,7 @@ def merge_hierarchical(labels, rag, thresh, in_place, merge_in_place,pre_merge_f The new labeled array. """ - if not in_place: + if rag_copy: rag = rag.copy() edge_heap = [] @@ -162,34 +104,23 @@ def merge_hierarchical(labels, rag, thresh, in_place, merge_in_place,pre_merge_f # Ensure popped edge is valid, if not, the edge is discarded if valid: - pre_merge_func(rag, n1, n2) # Invalidate all neigbors of `src` before its deleted for n in rag.neighbors(n1): rag[n1][n]['heap item'][3] = False - if not merge_in_place: + if not in_place_merge: for n in rag.neighbors(n2): rag[n2][n]['heap item'][3] = False - if not merge_in_place: - - #print 'added',next_id + if not in_place_merge: next_id = rag.next_id() - - rag._add_node(next_id) - rag.node[next_id] = rag.node[n2] - - for nbr in rag.neighbors(n2): - rag.add_edge(nbr, next_id, {'weight':rag[n][n2]['weight']}) - - rag.remove_node(n2) - + _copy_node(rag, n2, next_id) src, dst = n1, next_id else: src, dst = n1, n2 - + + merge_func(rag, src, dst) new_id = rag.merge_nodes(src, dst, weight_func) - _revalidate_node_edges(rag, new_id, edge_heap) arr = np.arange(labels.max() + 1) diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index ba9ef994..35eb5c38 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -108,23 +108,3 @@ def test_rag_error(): labels[5:, :] = 1 testing.assert_raises(ValueError, graph.rag_mean_color, img, labels, 2, 'non existant mode') - -@skipif(not is_installed('networkx')) -def test_merge_hierarchical(): - img = np.zeros((100, 100, 3), dtype='uint8') - img[:50, :50] = 255, 255, 255 - img[:50, 50:] = 254, 254, 254 - img[50:, :50] = 2, 2, 2 - img[50:, 50:] = 1, 1, 1 - - labels = np.zeros((100, 100), dtype='uint8') - labels[:50, :50] = 0 - labels[:50, 50:] = 1 - labels[50:, :50] = 2 - labels[50:, 50:] = 3 - - rag = graph.rag_mean_color(img, labels) - new_labels = graph.merge_hierarchical_mean_color(labels, rag, 10) - - # Two labels - assert new_labels.max() == 1