From 2b10d9817944de7cac622a00f73a96876913584d Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Mon, 16 Jun 2014 02:04:42 +0530 Subject: [PATCH 01/59] Added mean color RAG construction code --- skimage/graph/_construct.pyx | 126 +++++++++++++++++++++++++++++++++++ skimage/graph/graph.py | 23 +++++++ skimage/graph/setup.py | 5 ++ 3 files changed, 154 insertions(+) create mode 100644 skimage/graph/_construct.pyx create mode 100644 skimage/graph/graph.py diff --git a/skimage/graph/_construct.pyx b/skimage/graph/_construct.pyx new file mode 100644 index 00000000..3b91fe64 --- /dev/null +++ b/skimage/graph/_construct.pyx @@ -0,0 +1,126 @@ +import networkx as nx +cimport numpy as cnp +import numpy as np + + +def construct_rag_meancolor_3d( img, arr): + cdef Py_ssize_t l, b, h, i, j, k + cdef cnp.int32_t current, next + l = arr.shape[0] + b = arr.shape[1] + h = arr.shape[2] + + g = nx.Graph() + + i = 0 + while i < l - 1: + j = 0 + while j < b - 1: + k = 0 + while k < h - 1: + current = arr[i, j, k] + + try : + g.node[current]['pixel_count'] += 1 + g.node[current]['total_color'] += img[i,j] + except KeyError: + g.add_node(current) + g.node[current]['pixel_count'] = 1 + g.node[current]['total_color'] = img[i,j].astype(np.long) + g.node[current]['labels'] = [arr[i,j]] + + next = arr[i + 1, j, k] + if current != next: + g.add_edge(current, next) + + next = arr[i, j + 1, k] + if current != next: + g.add_edge(current, next) + + next = arr[i + 1, j + 1, k] + if current != next: + g.add_edge(current, next) + + next = arr[i + 1, j, k + 1] + if current != next: + g.add_edge(current, next) + + next = arr[i, j + 1, k + 1] + if current != next: + g.add_edge(current, next) + + next = arr[i + 1, j + 1, k + 1] + if current != next: + g.add_edge(current, next) + + next = arr[i, j, k + 1] + if current != next: + g.add_edge(current, next) + + + k += 1 + + j += 1 + + i += 1 + + + for n in g.nodes(): + g.node[n]['mean_color'] = g.node[n]['total_color']/g.node[n]['pixel_count'] + + for x,y in g.edges_iter() : + diff = g.node[x]['mean_color'] - g.node[y]['mean_color'] + g[x][y]['weight'] = np.sqrt(diff.dot(diff)) + + return g + + +def construct_rag_meancolor_2d(img, arr): + cdef Py_ssize_t l, b, h, i, j, k + cdef cnp.int32_t current, next + l = arr.shape[0] + b = arr.shape[1] + + g = nx.Graph() + + i = 0 + while i < l - 1: + j = 0 + while j < b - 1: + current = arr[i, j] + + try : + g.node[current]['pixel_count'] += 1 + g.node[current]['total_color'] += img[i,j] + except KeyError: + g.add_node(current) + g.node[current]['pixel_count'] = 1 + g.node[current]['total_color'] = img[i,j].astype(np.long) + g.node[current]['labels'] = [arr[i,j]] + + next = arr[i + 1, j] + if current != next: + g.add_edge(current, next) + + next = arr[i, j + 1] + if current != next: + g.add_edge(current, next) + + next = arr[i + 1, j + 1] + if current != next: + g.add_edge(current, next) + + j += 1 + + i += 1 + + + for n in g.nodes(): + g.node[n]['mean_color'] = g.node[n]['total_color']/g.node[n]['pixel_count'] + + for x,y in g.edges_iter() : + diff = g.node[x]['mean_color'] - g.node[y]['mean_color'] + g[x][y]['weight'] = np.sqrt(diff.dot(diff)) + + + return g diff --git a/skimage/graph/graph.py b/skimage/graph/graph.py new file mode 100644 index 00000000..2597e985 --- /dev/null +++ b/skimage/graph/graph.py @@ -0,0 +1,23 @@ +import netwrokx as nx + +class Graph(nx.Graph): + + def merge_nodes(i,j): + if not self.has_edge(i, j): + raise ValueError('Cant merge non adjacent nodes') + + # print "before ",self.order() + for x in self.neighbors(i): + if x == j: + continue + w1 = self.get_edge_data(x, i)['weight'] + w2 = -1 + if self.has_edge(x, j): + w2 = self.get_edge_data(x, j)['weight'] + + w = max(w1, w2) + + self.add_edge(x, j, weight=w) + + self.node[j]['labels'] += self.node[i]['labels'] + self.remove_node(i) diff --git a/skimage/graph/setup.py b/skimage/graph/setup.py index 463d2739..252eeed2 100644 --- a/skimage/graph/setup.py +++ b/skimage/graph/setup.py @@ -17,6 +17,8 @@ def configuration(parent_package='', top_path=None): cython(['_spath.pyx'], working_path=base_path) cython(['_mcp.pyx'], working_path=base_path) cython(['heap.pyx'], working_path=base_path) + cython(['_construct.pyx'], working_path=base_path) + config.add_extension('_spath', sources=['_spath.c'], include_dirs=[get_numpy_include_dirs()]) @@ -24,6 +26,9 @@ def configuration(parent_package='', top_path=None): include_dirs=[get_numpy_include_dirs()]) config.add_extension('heap', sources=['heap.c'], include_dirs=[get_numpy_include_dirs()]) + config.add_extension('_construct', sources=['_construct.c'], + include_dirs=[get_numpy_include_dirs()]) + return config From 53077c9f227dac53a93edd50176ea2e6ce44ab3d Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Mon, 16 Jun 2014 03:30:01 +0530 Subject: [PATCH 02/59] Added edge threshold cut --- skimage/graph/graph_cut.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 skimage/graph/graph_cut.py diff --git a/skimage/graph/graph_cut.py b/skimage/graph/graph_cut.py new file mode 100644 index 00000000..bf55db84 --- /dev/null +++ b/skimage/graph/graph_cut.py @@ -0,0 +1,25 @@ +import networkx as nx +import numpy as np + +def threshold_cut(label, rag, thresh): + + #print [rag.edges_iter(data = True)] + to_remove = [(x,y) for x,y,d in rag.edges_iter(data = True) if d['weight'] >= thresh] + print "edges to remove",len(to_remove) + + rag.remove_edges_from(to_remove) + + + comps = nx.connected_components(rag) + out = np.copy(label) + print "comps",len(comps) + + for i, nodes in enumerate(comps) : + + for node in nodes : + for l in rag.node[node]['labels'] : + out[label == l] = i + + #print out + #print label + return out From a6c9a5a2a7e1b6f858134a1079f8e38d3a968f11 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Mon, 16 Jun 2014 17:55:40 +0530 Subject: [PATCH 03/59] Renamed graph.py to rag.py --- skimage/graph/_construct.pyx | 6 +++--- skimage/graph/rag.py | 35 +++++++++++++++++++++++++++++++++ skimage/graph/tests/test_rag.py | 10 ++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 skimage/graph/rag.py create mode 100644 skimage/graph/tests/test_rag.py diff --git a/skimage/graph/_construct.pyx b/skimage/graph/_construct.pyx index 3b91fe64..ece98143 100644 --- a/skimage/graph/_construct.pyx +++ b/skimage/graph/_construct.pyx @@ -1,4 +1,4 @@ -import networkx as nx +import rag cimport numpy as cnp import numpy as np @@ -10,7 +10,7 @@ def construct_rag_meancolor_3d( img, arr): b = arr.shape[1] h = arr.shape[2] - g = nx.Graph() + g = rag.RAG() i = 0 while i < l - 1: @@ -81,7 +81,7 @@ def construct_rag_meancolor_2d(img, arr): l = arr.shape[0] b = arr.shape[1] - g = nx.Graph() + g = rag.RAG() i = 0 while i < l - 1: diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py new file mode 100644 index 00000000..9795787b --- /dev/null +++ b/skimage/graph/rag.py @@ -0,0 +1,35 @@ +import networkx as nx +import _construct +from skimage import util + +class RAG(nx.Graph): + + def merge_nodes(i,j): + if not self.has_edge(i, j): + raise ValueError('Cant merge non adjacent nodes') + + # print "before ",self.order() + for x in self.neighbors(i): + if x == j: + continue + w1 = self.get_edge_data(x, i)['weight'] + w2 = -1 + if self.has_edge(x, j): + w2 = self.get_edge_data(x, j)['weight'] + + w = max(w1, w2) + + self.add_edge(x, j, weight=w) + + self.node[j]['labels'] += self.node[i]['labels'] + self.remove_node(i) + +def rag_meancolor(img,labels): + + img = util.img_as_ubyte(img) + if img.ndim == 3 : + return _construct.construct_rag_meancolor_3d(img,labels) + elif img.ndim == 2 : + return _construct.construct_rag_meancolor_2d(img,labels) + else : + raise ValueError("Image dimension not supported") diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py new file mode 100644 index 00000000..08d1a1cf --- /dev/null +++ b/skimage/graph/tests/test_rag.py @@ -0,0 +1,10 @@ +import numpy as np + +def test_threshold_cut(): + arr = np.array((100,100,3),dtype='uint8') + arr[:50,:50] = 0 + arr[:50,50:] = 1 + arr[50:,50:] = 2 + arr[50:,50:] = 3 + + From abcb9cf2efca91c320458fec7a67ba8782b30df0 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Mon, 16 Jun 2014 19:22:47 +0530 Subject: [PATCH 04/59] Added testcase --- skimage/graph/__init__.py | 6 +++++- skimage/graph/graph.py | 23 ----------------------- skimage/graph/graph_cut.py | 5 +++-- skimage/graph/rag.py | 4 ++-- skimage/graph/tests/test_rag.py | 29 ++++++++++++++++++++++++----- 5 files changed, 34 insertions(+), 33 deletions(-) delete mode 100644 skimage/graph/graph.py diff --git a/skimage/graph/__init__.py b/skimage/graph/__init__.py index a335971d..90da2088 100644 --- a/skimage/graph/__init__.py +++ b/skimage/graph/__init__.py @@ -1,9 +1,13 @@ from .spath import shortest_path from .mcp import MCP, MCP_Geometric, MCP_Connect, MCP_Flexible, route_through_array +from .rag import rag_meancolor +from .graph_cut import threshold_cut __all__ = ['shortest_path', 'MCP', 'MCP_Geometric', 'MCP_Connect', 'MCP_Flexible', - 'route_through_array'] \ No newline at end of file + 'route_through_array', + 'rag_meancolor', + 'threshold_cut'] diff --git a/skimage/graph/graph.py b/skimage/graph/graph.py deleted file mode 100644 index 2597e985..00000000 --- a/skimage/graph/graph.py +++ /dev/null @@ -1,23 +0,0 @@ -import netwrokx as nx - -class Graph(nx.Graph): - - def merge_nodes(i,j): - if not self.has_edge(i, j): - raise ValueError('Cant merge non adjacent nodes') - - # print "before ",self.order() - for x in self.neighbors(i): - if x == j: - continue - w1 = self.get_edge_data(x, i)['weight'] - w2 = -1 - if self.has_edge(x, j): - w2 = self.get_edge_data(x, j)['weight'] - - w = max(w1, w2) - - self.add_edge(x, j, weight=w) - - self.node[j]['labels'] += self.node[i]['labels'] - self.remove_node(i) diff --git a/skimage/graph/graph_cut.py b/skimage/graph/graph_cut.py index bf55db84..5d6a98e2 100644 --- a/skimage/graph/graph_cut.py +++ b/skimage/graph/graph_cut.py @@ -5,14 +5,15 @@ def threshold_cut(label, rag, thresh): #print [rag.edges_iter(data = True)] to_remove = [(x,y) for x,y,d in rag.edges_iter(data = True) if d['weight'] >= thresh] - print "edges to remove",len(to_remove) + #print "edges to remove",len(to_remove) rag.remove_edges_from(to_remove) + #print "to remove", to_remove comps = nx.connected_components(rag) out = np.copy(label) - print "comps",len(comps) + #print "comps",len(comps) for i, nodes in enumerate(comps) : diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 9795787b..dd721959 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -27,9 +27,9 @@ class RAG(nx.Graph): def rag_meancolor(img,labels): img = util.img_as_ubyte(img) - if img.ndim == 3 : + if img.ndim == 4 : return _construct.construct_rag_meancolor_3d(img,labels) - elif img.ndim == 2 : + elif img.ndim == 3 : return _construct.construct_rag_meancolor_2d(img,labels) else : raise ValueError("Image dimension not supported") diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index 08d1a1cf..d24c62c4 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -1,10 +1,29 @@ import numpy as np +from skimage import graph def test_threshold_cut(): - arr = np.array((100,100,3),dtype='uint8') - arr[:50,:50] = 0 - arr[:50,50:] = 1 - arr[50:,50:] = 2 - arr[50:,50:] = 3 + + 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 + + + #print labels + rag = graph.rag_meancolor(img, labels) + #print "no of edges",rag.number_of_edges() + new_labels = graph.threshold_cut(labels, rag, 10) + + assert new_labels.max() == 2 + #assert False From 10f91fe8b0174c03d56252f2a14c6018276db8d1 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Mon, 16 Jun 2014 21:59:36 +0530 Subject: [PATCH 05/59] Added docs --- skimage/graph/_construct.pyx | 76 +++++++++++++++++++++++++++--------- skimage/graph/graph_cut.py | 27 ++++++++++--- skimage/graph/rag.py | 47 +++++++++++++++++++++- 3 files changed, 124 insertions(+), 26 deletions(-) diff --git a/skimage/graph/_construct.pyx b/skimage/graph/_construct.pyx index ece98143..c4fbb465 100644 --- a/skimage/graph/_construct.pyx +++ b/skimage/graph/_construct.pyx @@ -3,7 +3,28 @@ cimport numpy as cnp import numpy as np -def construct_rag_meancolor_3d( img, arr): +def construct_rag_meancolor_3d(img, arr): + """Computes the Region Adjacency Graph of a 3D color image using + difference in mean color of regions as edge weights. + + Given an image and its segmentation, this method constructs the + corresponsing Region Adjacency Graph (RAG).Each node in the RAG + represents a contiguous pixels with in `img` the same label in + `arr` + + Parameters + ---------- + img : (width, height, depth, 3) ndarray + Input image. + arr : (width, height, depth) ndarray + The array with labels. + + Returns + ------- + out : RAG + The region adjacency graph. + """ + cdef Py_ssize_t l, b, h, i, j, k cdef cnp.int32_t current, next l = arr.shape[0] @@ -19,15 +40,15 @@ def construct_rag_meancolor_3d( img, arr): k = 0 while k < h - 1: current = arr[i, j, k] - - try : + + try: g.node[current]['pixel_count'] += 1 - g.node[current]['total_color'] += img[i,j] + g.node[current]['total_color'] += img[i, j] except KeyError: g.add_node(current) g.node[current]['pixel_count'] = 1 - g.node[current]['total_color'] = img[i,j].astype(np.long) - g.node[current]['labels'] = [arr[i,j]] + g.node[current]['total_color'] = img[i, j].astype(np.long) + g.node[current]['labels'] = [arr[i, j]] next = arr[i + 1, j, k] if current != next: @@ -57,18 +78,17 @@ def construct_rag_meancolor_3d( img, arr): if current != next: g.add_edge(current, next) - k += 1 j += 1 i += 1 - for n in g.nodes(): - g.node[n]['mean_color'] = g.node[n]['total_color']/g.node[n]['pixel_count'] + g.node[n]['mean_color'] = g.node[n][ + 'total_color'] / g.node[n]['pixel_count'] - for x,y in g.edges_iter() : + for x, y in g.edges_iter(): diff = g.node[x]['mean_color'] - g.node[y]['mean_color'] g[x][y]['weight'] = np.sqrt(diff.dot(diff)) @@ -76,6 +96,27 @@ def construct_rag_meancolor_3d( img, arr): def construct_rag_meancolor_2d(img, arr): + """Computes the Region Adjacency Graph of a 2D color image using + difference in mean color of regions as edge weights. + + Given an image and its segmentation, this method constructs the + corresponsing Region Adjacency Graph (RAG).Each node in the RAG + represents a contiguous pixels with in `img` the same label in + `arr` + + Parameters + ---------- + img : (width, height, 3) ndarray + Input image. + arr : (width, height) ndarray + The array with labels. + + Returns + ------- + out : RAG + The region adjacency graph. + """ + cdef Py_ssize_t l, b, h, i, j, k cdef cnp.int32_t current, next l = arr.shape[0] @@ -89,14 +130,14 @@ def construct_rag_meancolor_2d(img, arr): while j < b - 1: current = arr[i, j] - try : + try: g.node[current]['pixel_count'] += 1 - g.node[current]['total_color'] += img[i,j] + g.node[current]['total_color'] += img[i, j] except KeyError: g.add_node(current) g.node[current]['pixel_count'] = 1 - g.node[current]['total_color'] = img[i,j].astype(np.long) - g.node[current]['labels'] = [arr[i,j]] + g.node[current]['total_color'] = img[i, j].astype(np.long) + g.node[current]['labels'] = [arr[i, j]] next = arr[i + 1, j] if current != next: @@ -114,13 +155,12 @@ def construct_rag_meancolor_2d(img, arr): i += 1 - for n in g.nodes(): - g.node[n]['mean_color'] = g.node[n]['total_color']/g.node[n]['pixel_count'] + g.node[n]['mean_color'] = g.node[n][ + 'total_color'] / g.node[n]['pixel_count'] - for x,y in g.edges_iter() : + for x, y in g.edges_iter(): diff = g.node[x]['mean_color'] - g.node[y]['mean_color'] g[x][y]['weight'] = np.sqrt(diff.dot(diff)) - return g diff --git a/skimage/graph/graph_cut.py b/skimage/graph/graph_cut.py index 5d6a98e2..939681af 100644 --- a/skimage/graph/graph_cut.py +++ b/skimage/graph/graph_cut.py @@ -2,18 +2,34 @@ import networkx as nx import numpy as np def threshold_cut(label, rag, thresh): + """Combines regions seperated by weight less than threshold. - #print [rag.edges_iter(data = True)] + Given an image's labels and its RAG, outputs new labels by + combining regions whose nodes are seperated by a weight less + than the given threshold. + + Parameters + ---------- + label : (width, height, 3) or (width, height, depth, 3) ndarray + The array of labels. + rag : RAG + The region adjacency graph. + thresh : float + The threshold, regions with edge weights less than this + are combined. + + Returns + ------- + out : (width, height, 3) or (width, height, depth, 3) ndarray + The new labelled array. + """ to_remove = [(x,y) for x,y,d in rag.edges_iter(data = True) if d['weight'] >= thresh] - #print "edges to remove",len(to_remove) rag.remove_edges_from(to_remove) - #print "to remove", to_remove comps = nx.connected_components(rag) out = np.copy(label) - #print "comps",len(comps) for i, nodes in enumerate(comps) : @@ -21,6 +37,5 @@ def threshold_cut(label, rag, thresh): for l in rag.node[node]['labels'] : out[label == l] = i - #print out - #print label + return out diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index dd721959..44ec76f9 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -3,8 +3,30 @@ import _construct from skimage import util class RAG(nx.Graph): + """ + The class for holding the Region Adjacency Graph (RAG). + + Each region is a contiguous set of pixels in an image, usuall + sharing some common property.Adjacent regions have an edge + between their corresponding nodes. + """ + + def merge_nodes(self,i,j): + """Merges nodes `i` and `j`. + + The new combined node is adjacent to all the neighbors of `i` + and `j`. In case of conflicting edges, edge with higher weight + is chosen. + + Parameters + ---------- + i : int + Node to be merged. + j : int + Node to be merged. + + """ - def merge_nodes(i,j): if not self.has_edge(i, j): raise ValueError('Cant merge non adjacent nodes') @@ -24,7 +46,28 @@ class RAG(nx.Graph): self.node[j]['labels'] += self.node[i]['labels'] self.remove_node(i) -def rag_meancolor(img,labels): + +def rag_meancolor(img, labels): + """Computes the Region Adjacency Graph of a color image using + difference in mean color of regions as edge weights. + + Given an image and its segmentation, this method constructs the + corresponsing Region Adjacency Graph (RAG).Each node in the RAG + represents a contiguous pixels with in `img` the same label in + `arr` + + Parameters + ---------- + img : (width, height, 3) or (width, height, depth, 3) ndarray + Input image. + arr : (width, height) or (width, height, depth) ndarray + The array with labels. + + Returns + ------- + out : RAG + The region adjacency graph. + """ img = util.img_as_ubyte(img) if img.ndim == 4 : From 850f835114881b7ce179f322bb588c950461ae63 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Mon, 16 Jun 2014 22:17:13 +0530 Subject: [PATCH 06/59] Docs formatting --- skimage/graph/graph_cut.py | 18 +++++++++--------- skimage/graph/rag.py | 18 ++++++++++-------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/skimage/graph/graph_cut.py b/skimage/graph/graph_cut.py index 939681af..0f28b453 100644 --- a/skimage/graph/graph_cut.py +++ b/skimage/graph/graph_cut.py @@ -1,11 +1,12 @@ import networkx as nx import numpy as np + def threshold_cut(label, rag, thresh): """Combines regions seperated by weight less than threshold. Given an image's labels and its RAG, outputs new labels by - combining regions whose nodes are seperated by a weight less + combining regions whose nodes are seperated by a weight less than the given threshold. Parameters @@ -14,7 +15,7 @@ def threshold_cut(label, rag, thresh): The array of labels. rag : RAG The region adjacency graph. - thresh : float + thresh : float The threshold, regions with edge weights less than this are combined. @@ -23,19 +24,18 @@ def threshold_cut(label, rag, thresh): out : (width, height, 3) or (width, height, depth, 3) ndarray The new labelled array. """ - to_remove = [(x,y) for x,y,d in rag.edges_iter(data = True) if d['weight'] >= thresh] + to_remove = [(x, y) + for x, y, d in rag.edges_iter(data=True) if d['weight'] >= thresh] rag.remove_edges_from(to_remove) - comps = nx.connected_components(rag) out = np.copy(label) - for i, nodes in enumerate(comps) : - - for node in nodes : - for l in rag.node[node]['labels'] : + for i, nodes in enumerate(comps): + + for node in nodes: + for l in rag.node[node]['labels']: out[label == l] = i - return out diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 44ec76f9..2cf353de 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -2,16 +2,18 @@ import networkx as nx import _construct from skimage import util + class RAG(nx.Graph): + """ The class for holding the Region Adjacency Graph (RAG). Each region is a contiguous set of pixels in an image, usuall - sharing some common property.Adjacent regions have an edge + sharing some common property.Adjacent regions have an edge between their corresponding nodes. """ - def merge_nodes(self,i,j): + def merge_nodes(self, i, j): """Merges nodes `i` and `j`. The new combined node is adjacent to all the neighbors of `i` @@ -43,7 +45,7 @@ class RAG(nx.Graph): self.add_edge(x, j, weight=w) - self.node[j]['labels'] += self.node[i]['labels'] + self.node[j]['labels'] += self.node[i]['labels'] self.remove_node(i) @@ -70,9 +72,9 @@ def rag_meancolor(img, labels): """ img = util.img_as_ubyte(img) - if img.ndim == 4 : - return _construct.construct_rag_meancolor_3d(img,labels) - elif img.ndim == 3 : - return _construct.construct_rag_meancolor_2d(img,labels) - else : + if img.ndim == 4: + return _construct.construct_rag_meancolor_3d(img, labels) + elif img.ndim == 3: + return _construct.construct_rag_meancolor_2d(img, labels) + else: raise ValueError("Image dimension not supported") From 1ad8ad733b34cd67462e6bf526d87d97ec14d1fa Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Mon, 16 Jun 2014 22:59:23 +0530 Subject: [PATCH 07/59] Added examples in docstring --- skimage/graph/graph_cut.py | 9 +++++++++ skimage/graph/rag.py | 30 +++++++++++++++++++----------- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/skimage/graph/graph_cut.py b/skimage/graph/graph_cut.py index 0f28b453..2733bf0e 100644 --- a/skimage/graph/graph_cut.py +++ b/skimage/graph/graph_cut.py @@ -23,6 +23,15 @@ def threshold_cut(label, rag, thresh): ------- out : (width, height, 3) or (width, height, depth, 3) ndarray The new labelled array. + + Examples + -------- + >>> from skimage import data,graph,segmentation + >>> img = data.lena() + >>> labels = segmentation.slic(img) + >>> rag = graph.rag_meancolor(img, labels) + >>> new_labels = graph.threshold_cut(labels, rag, 10) + """ to_remove = [(x, y) for x, y, d in rag.edges_iter(data=True) if d['weight'] >= thresh] diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 2cf353de..af24af18 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -14,20 +14,20 @@ class RAG(nx.Graph): """ def merge_nodes(self, i, j): - """Merges nodes `i` and `j`. + """Merges nodes `i` and `j`. - The new combined node is adjacent to all the neighbors of `i` - and `j`. In case of conflicting edges, edge with higher weight - is chosen. + The new combined node is adjacent to all the neighbors of `i` + and `j`. In case of conflicting edges, edge with higher weight + is chosen. - Parameters - ---------- - i : int - Node to be merged. - j : int - Node to be merged. + Parameters + ---------- + i : int + Node to be merged. + j : int + Node to be merged. - """ + """ if not self.has_edge(i, j): raise ValueError('Cant merge non adjacent nodes') @@ -69,6 +69,14 @@ def rag_meancolor(img, labels): ------- out : RAG The region adjacency graph. + + Examples + -------- + >>> from skimage import data,graph,segmentation + >>> img = data.lena() + >>> labels = segmentation.slic(img) + >>> rag = graph.rag_meancolor(img, labels) + """ img = util.img_as_ubyte(img) From 3ea78096e7ef5bae3e97a89a132acb73e0a39f9c Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Mon, 16 Jun 2014 23:02:01 +0530 Subject: [PATCH 08/59] Formatting changes --- skimage/graph/graph_cut.py | 5 ++--- skimage/graph/tests/test_rag.py | 34 +++++++++++++++------------------ 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/skimage/graph/graph_cut.py b/skimage/graph/graph_cut.py index 2733bf0e..7c183689 100644 --- a/skimage/graph/graph_cut.py +++ b/skimage/graph/graph_cut.py @@ -31,10 +31,9 @@ def threshold_cut(label, rag, thresh): >>> labels = segmentation.slic(img) >>> rag = graph.rag_meancolor(img, labels) >>> new_labels = graph.threshold_cut(labels, rag, 10) - """ - to_remove = [(x, y) - for x, y, d in rag.edges_iter(data=True) if d['weight'] >= thresh] + to_remove = [(x, y) for x, y, d in rag.edges_iter(data=True) + if d['weight'] >= thresh] rag.remove_edges_from(to_remove) diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index d24c62c4..fdf3fee7 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -1,29 +1,25 @@ import numpy as np from skimage import graph + def test_threshold_cut(): - - 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 + 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 - labels = np.zeros((100,100),dtype='uint8') - labels[:50,:50] = 0 - labels[:50,50:] = 1 - labels[50:,:50] = 2 - labels[50:,50:] = 3 - - - #print labels + # print labels rag = graph.rag_meancolor(img, labels) - #print "no of edges",rag.number_of_edges() + # print "no of edges",rag.number_of_edges() new_labels = graph.threshold_cut(labels, rag, 10) - - assert new_labels.max() == 2 - #assert False - + assert new_labels.max() == 2 + # assert False From c08d96d2b5738395cc70f5152d88ed8d3b7c4b10 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Mon, 16 Jun 2014 23:03:36 +0530 Subject: [PATCH 09/59] Minor Foramtting --- skimage/graph/graph_cut.py | 1 - skimage/graph/tests/test_rag.py | 3 --- 2 files changed, 4 deletions(-) diff --git a/skimage/graph/graph_cut.py b/skimage/graph/graph_cut.py index 7c183689..d6e1d013 100644 --- a/skimage/graph/graph_cut.py +++ b/skimage/graph/graph_cut.py @@ -34,7 +34,6 @@ def threshold_cut(label, rag, thresh): """ to_remove = [(x, y) for x, y, d in rag.edges_iter(data=True) if d['weight'] >= thresh] - rag.remove_edges_from(to_remove) comps = nx.connected_components(rag) diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index fdf3fee7..8c28febe 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -16,10 +16,7 @@ def test_threshold_cut(): labels[50:, :50] = 2 labels[50:, 50:] = 3 - # print labels rag = graph.rag_meancolor(img, labels) - # print "no of edges",rag.number_of_edges() new_labels = graph.threshold_cut(labels, rag, 10) assert new_labels.max() == 2 - # assert False From 18a6535089712d40dae3e168d30107e53a71921b Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Mon, 16 Jun 2014 23:07:37 +0530 Subject: [PATCH 10/59] Corrected test mistake --- skimage/graph/tests/test_rag.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index 8c28febe..e239e79f 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -19,4 +19,5 @@ def test_threshold_cut(): rag = graph.rag_meancolor(img, labels) new_labels = graph.threshold_cut(labels, rag, 10) - assert new_labels.max() == 2 + # Two labels + assert new_labels.max() == 1 From bf89726c496256c9749b213222ef2357c338d604 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Mon, 16 Jun 2014 23:50:26 +0530 Subject: [PATCH 11/59] removed comments --- skimage/graph/graph_cut.py | 1 - skimage/graph/rag.py | 1 - 2 files changed, 2 deletions(-) diff --git a/skimage/graph/graph_cut.py b/skimage/graph/graph_cut.py index d6e1d013..0e7ea25c 100644 --- a/skimage/graph/graph_cut.py +++ b/skimage/graph/graph_cut.py @@ -40,7 +40,6 @@ def threshold_cut(label, rag, thresh): out = np.copy(label) for i, nodes in enumerate(comps): - for node in nodes: for l in rag.node[node]['labels']: out[label == l] = i diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index af24af18..d4ad6628 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -32,7 +32,6 @@ class RAG(nx.Graph): if not self.has_edge(i, j): raise ValueError('Cant merge non adjacent nodes') - # print "before ",self.order() for x in self.neighbors(i): if x == j: continue From 47e3b6ea67b64e5cf1d8f9ef0bc1b6fe152e6951 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Tue, 17 Jun 2014 00:10:56 +0530 Subject: [PATCH 12/59] Added example --- doc/examples/plot_rag_meancolor.py | 41 ++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 doc/examples/plot_rag_meancolor.py diff --git a/doc/examples/plot_rag_meancolor.py b/doc/examples/plot_rag_meancolor.py new file mode 100644 index 00000000..aee341f4 --- /dev/null +++ b/doc/examples/plot_rag_meancolor.py @@ -0,0 +1,41 @@ +from skimage import graph +from skimage import segmentation +from skimage import data, io +import numpy as np +from matplotlib import pyplot as plt + + +def label_mask_img(img, label): + + out = np.zeros_like(img) + + red = img[:, :, 0] + green = img[:, :, 1] + blue = img[:, :, 2] + + for i in range(label.max()): + mask = label == i + + r = np.average(red[mask]) + g = np.average(green[mask]) + b = np.average(blue[mask]) + + # print r,g,b + out[mask] = r, g, b + + return out + +img = data.coffee() + +labels1 = segmentation.slic(img, compactness=30, n_segments=400) +out1 = label_mask_img(img, labels1) + +g = graph.rag_meancolor(img, labels1) +labels2 = graph.threshold_cut(labels1, g, 30) +out2 = label_mask_img(img, labels2) + +plt.figure() +io.imshow(out1) +plt.figure() +io.imshow(out2) +io.show() From 602c8d869217949aef5c3c024e9ad81c6b60e3e0 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Tue, 17 Jun 2014 00:17:12 +0530 Subject: [PATCH 13/59] Added explanation to example --- doc/examples/plot_rag_meancolor.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/examples/plot_rag_meancolor.py b/doc/examples/plot_rag_meancolor.py index aee341f4..988572b5 100644 --- a/doc/examples/plot_rag_meancolor.py +++ b/doc/examples/plot_rag_meancolor.py @@ -1,3 +1,14 @@ +""" +================ +RAG Thresholding +================ + +This examples constructs a Region Adjacency Graph and merges region which are +similar in color. We construct a RAG and define edges as the difference in +mean color. We the join regions with similar mean color. + +""" + from skimage import graph from skimage import segmentation from skimage import data, io From 076b044e4548f509f29231f470e1f03b7f0f06f1 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Tue, 17 Jun 2014 00:37:26 +0530 Subject: [PATCH 14/59] Added bento.info --- bento.info | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bento.info b/bento.info index 227e51e8..68aa4319 100644 --- a/bento.info +++ b/bento.info @@ -154,6 +154,9 @@ Library: Extension: skimage.feature._hessian_det_appx Sources: skimage/exposure/_hessian_det_appx.pyx + Extension: skimage.graph._construct + Sources: + skimage/exposure/_construct.pyx Executable: skivi Module: skimage.scripts.skivi From dfee0685508f264aad1703c1652ad2817f93e325 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Tue, 17 Jun 2014 00:59:22 +0530 Subject: [PATCH 15/59] Added networkx to requirements --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 48e03b8b..7543d867 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ cython>=0.17 matplotlib>=1.0 numpy>=1.6 six>=1.3.0 +networkx>=1.8.0 From 5165ebe01ea5b5a93e5562890a772ff4995ce33d Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Tue, 17 Jun 2014 01:22:22 +0530 Subject: [PATCH 16/59] Added networkx installation --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 169b512b..1f292dfa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,6 +54,7 @@ before_install: - pip install cython - pip install flake8 - pip install six + - pip install networkx - pip install nose-cov - pip install coveralls From 53318c44dfcd7158b21a31346d362210c592aa7b Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Tue, 17 Jun 2014 22:36:48 +0530 Subject: [PATCH 17/59] CHanges to get Python3 working --- skimage/graph/_construct.pyx | 4 ++-- skimage/graph/rag.py | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/skimage/graph/_construct.pyx b/skimage/graph/_construct.pyx index c4fbb465..c3cde3b9 100644 --- a/skimage/graph/_construct.pyx +++ b/skimage/graph/_construct.pyx @@ -1,6 +1,6 @@ -import rag -cimport numpy as cnp import numpy as np +cimport numpy as cnp +import rag def construct_rag_meancolor_3d(img, arr): diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index d4ad6628..1129d4a9 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -1,6 +1,7 @@ import networkx as nx -import _construct from skimage import util +from ._construct import construct_rag_meancolor_2d +from ._construct import construct_rag_meancolor_3d class RAG(nx.Graph): @@ -80,8 +81,8 @@ def rag_meancolor(img, labels): img = util.img_as_ubyte(img) if img.ndim == 4: - return _construct.construct_rag_meancolor_3d(img, labels) + return construct_rag_meancolor_3d(img, labels) elif img.ndim == 3: - return _construct.construct_rag_meancolor_2d(img, labels) + return construct_rag_meancolor_2d(img, labels) else: raise ValueError("Image dimension not supported") From 2a7ec3afd42f807484be3077ef4ef8ed48ca5d02 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Wed, 18 Jun 2014 00:46:25 +0530 Subject: [PATCH 18/59] Renamed _construct.pyx to _build_rag.pyx and some code corrections --- doc/examples/plot_rag_meancolor.py | 4 +- .../graph/{_construct.pyx => _build_rag.pyx} | 68 +++++++++---------- skimage/graph/graph_cut.py | 2 +- skimage/graph/rag.py | 4 +- skimage/graph/setup.py | 4 +- 5 files changed, 41 insertions(+), 41 deletions(-) rename skimage/graph/{_construct.pyx => _build_rag.pyx} (64%) diff --git a/doc/examples/plot_rag_meancolor.py b/doc/examples/plot_rag_meancolor.py index 988572b5..aebfe6fc 100644 --- a/doc/examples/plot_rag_meancolor.py +++ b/doc/examples/plot_rag_meancolor.py @@ -3,9 +3,9 @@ RAG Thresholding ================ -This examples constructs a Region Adjacency Graph and merges region which are +This examples constructs a Region Adjacency Graph (RAG) and merges regions which are similar in color. We construct a RAG and define edges as the difference in -mean color. We the join regions with similar mean color. +mean color. We then join regions with similar mean color. """ diff --git a/skimage/graph/_construct.pyx b/skimage/graph/_build_rag.pyx similarity index 64% rename from skimage/graph/_construct.pyx rename to skimage/graph/_build_rag.pyx index c3cde3b9..e6825c9d 100644 --- a/skimage/graph/_construct.pyx +++ b/skimage/graph/_build_rag.pyx @@ -8,9 +8,9 @@ def construct_rag_meancolor_3d(img, arr): difference in mean color of regions as edge weights. Given an image and its segmentation, this method constructs the - corresponsing Region Adjacency Graph (RAG).Each node in the RAG - represents a contiguous pixels with in `img` the same label in - `arr` + corresponsing Region Adjacency Graph (RAG). Each node in the RAG + represents contiguous pixels with in `img` with the same label in + `arr`. There is an edge between each pair of adjacent regions. Parameters ---------- @@ -25,29 +25,29 @@ def construct_rag_meancolor_3d(img, arr): The region adjacency graph. """ - cdef Py_ssize_t l, b, h, i, j, k + cdef Py_ssize_t depth,width,height, i, j, k cdef cnp.int32_t current, next - l = arr.shape[0] - b = arr.shape[1] - h = arr.shape[2] + width = arr.shape[0] + height = arr.shape[1] + depth = arr.shape[2] g = rag.RAG() i = 0 - while i < l - 1: + for i in range(width-1): j = 0 - while j < b - 1: + for j in range(height-1): k = 0 - while k < h - 1: + for k in range(depth-1): current = arr[i, j, k] try: - g.node[current]['pixel_count'] += 1 - g.node[current]['total_color'] += img[i, j] + g.node[current]['pixel count'] += 1 + g.node[current]['total color'] += img[i, j] except KeyError: g.add_node(current) - g.node[current]['pixel_count'] = 1 - g.node[current]['total_color'] = img[i, j].astype(np.long) + g.node[current]['pixel count'] = 1 + g.node[current]['total color'] = img[i, j].astype(np.long) g.node[current]['labels'] = [arr[i, j]] next = arr[i + 1, j, k] @@ -85,12 +85,12 @@ def construct_rag_meancolor_3d(img, arr): i += 1 for n in g.nodes(): - g.node[n]['mean_color'] = g.node[n][ - 'total_color'] / g.node[n]['pixel_count'] + g.node[n]['mean color'] = g.node[n][ + 'total color'] / g.node[n]['pixel count'] for x, y in g.edges_iter(): - diff = g.node[x]['mean_color'] - g.node[y]['mean_color'] - g[x][y]['weight'] = np.sqrt(diff.dot(diff)) + diff = g.node[x]['mean color'] - g.node[y]['mean color'] + g[x][y]['weight'] = np.linalg.norm(diff) return g @@ -100,9 +100,9 @@ def construct_rag_meancolor_2d(img, arr): difference in mean color of regions as edge weights. Given an image and its segmentation, this method constructs the - corresponsing Region Adjacency Graph (RAG).Each node in the RAG - represents a contiguous pixels with in `img` the same label in - `arr` + corresponsing Region Adjacency Graph (RAG). Each node in the RAG + represents contiguous pixels with in `img` with the same label in + `arr`. There is an edge between each pair of adjacent regions. Parameters ---------- @@ -117,26 +117,26 @@ def construct_rag_meancolor_2d(img, arr): The region adjacency graph. """ - cdef Py_ssize_t l, b, h, i, j, k + cdef Py_ssize_t width, height, h, i, j, k cdef cnp.int32_t current, next - l = arr.shape[0] - b = arr.shape[1] + width = arr.shape[0] + height = arr.shape[1] g = rag.RAG() i = 0 - while i < l - 1: + for i in range(width-1): j = 0 - while j < b - 1: + for j in range(height-1): current = arr[i, j] try: - g.node[current]['pixel_count'] += 1 - g.node[current]['total_color'] += img[i, j] + g.node[current]['pixel count'] += 1 + g.node[current]['total color'] += img[i, j] except KeyError: g.add_node(current) - g.node[current]['pixel_count'] = 1 - g.node[current]['total_color'] = img[i, j].astype(np.long) + g.node[current]['pixel count'] = 1 + g.node[current]['total color'] = img[i, j].astype(np.long) g.node[current]['labels'] = [arr[i, j]] next = arr[i + 1, j] @@ -156,11 +156,11 @@ def construct_rag_meancolor_2d(img, arr): i += 1 for n in g.nodes(): - g.node[n]['mean_color'] = g.node[n][ - 'total_color'] / g.node[n]['pixel_count'] + g.node[n]['mean color'] = g.node[n][ + 'total color'] / g.node[n]['pixel count'] for x, y in g.edges_iter(): - diff = g.node[x]['mean_color'] - g.node[y]['mean_color'] - g[x][y]['weight'] = np.sqrt(diff.dot(diff)) + diff = g.node[x]['mean color'] - g.node[y]['mean color'] + g[x][y]['weight'] = np.linalg.norm(diff) return g diff --git a/skimage/graph/graph_cut.py b/skimage/graph/graph_cut.py index 0e7ea25c..40adcdf8 100644 --- a/skimage/graph/graph_cut.py +++ b/skimage/graph/graph_cut.py @@ -11,7 +11,7 @@ def threshold_cut(label, rag, thresh): Parameters ---------- - label : (width, height, 3) or (width, height, depth, 3) ndarray + label : (width, height) or (width, height, 3) ndarray The array of labels. rag : RAG The region adjacency graph. diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 1129d4a9..72befba9 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -1,7 +1,7 @@ import networkx as nx from skimage import util -from ._construct import construct_rag_meancolor_2d -from ._construct import construct_rag_meancolor_3d +from ._build_rag import construct_rag_meancolor_2d +from ._build_rag import construct_rag_meancolor_3d class RAG(nx.Graph): diff --git a/skimage/graph/setup.py b/skimage/graph/setup.py index 252eeed2..436029da 100644 --- a/skimage/graph/setup.py +++ b/skimage/graph/setup.py @@ -17,7 +17,7 @@ def configuration(parent_package='', top_path=None): cython(['_spath.pyx'], working_path=base_path) cython(['_mcp.pyx'], working_path=base_path) cython(['heap.pyx'], working_path=base_path) - cython(['_construct.pyx'], working_path=base_path) + cython(['_build_rag.pyx'], working_path=base_path) config.add_extension('_spath', sources=['_spath.c'], @@ -26,7 +26,7 @@ def configuration(parent_package='', top_path=None): include_dirs=[get_numpy_include_dirs()]) config.add_extension('heap', sources=['heap.c'], include_dirs=[get_numpy_include_dirs()]) - config.add_extension('_construct', sources=['_construct.c'], + config.add_extension('_build_rag', sources=['_build_rag.c'], include_dirs=[get_numpy_include_dirs()]) From f5f93f8ce32b53b24c1ec1d76692a60b5ac86f8d Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Wed, 18 Jun 2014 03:53:33 +0530 Subject: [PATCH 19/59] Removed cython file and added nd python function for RAG construction --- skimage/graph/_build_rag.pyx | 166 ----------------------------------- skimage/graph/rag.py | 65 +++++++++++--- skimage/graph/setup.py | 4 - 3 files changed, 54 insertions(+), 181 deletions(-) delete mode 100644 skimage/graph/_build_rag.pyx diff --git a/skimage/graph/_build_rag.pyx b/skimage/graph/_build_rag.pyx deleted file mode 100644 index e6825c9d..00000000 --- a/skimage/graph/_build_rag.pyx +++ /dev/null @@ -1,166 +0,0 @@ -import numpy as np -cimport numpy as cnp -import rag - - -def construct_rag_meancolor_3d(img, arr): - """Computes the Region Adjacency Graph of a 3D color image using - difference in mean color of regions as edge weights. - - Given an image and its segmentation, this method constructs the - corresponsing Region Adjacency Graph (RAG). Each node in the RAG - represents contiguous pixels with in `img` with the same label in - `arr`. There is an edge between each pair of adjacent regions. - - Parameters - ---------- - img : (width, height, depth, 3) ndarray - Input image. - arr : (width, height, depth) ndarray - The array with labels. - - Returns - ------- - out : RAG - The region adjacency graph. - """ - - cdef Py_ssize_t depth,width,height, i, j, k - cdef cnp.int32_t current, next - width = arr.shape[0] - height = arr.shape[1] - depth = arr.shape[2] - - g = rag.RAG() - - i = 0 - for i in range(width-1): - j = 0 - for j in range(height-1): - k = 0 - for k in range(depth-1): - current = arr[i, j, k] - - try: - g.node[current]['pixel count'] += 1 - g.node[current]['total color'] += img[i, j] - except KeyError: - g.add_node(current) - g.node[current]['pixel count'] = 1 - g.node[current]['total color'] = img[i, j].astype(np.long) - g.node[current]['labels'] = [arr[i, j]] - - next = arr[i + 1, j, k] - if current != next: - g.add_edge(current, next) - - next = arr[i, j + 1, k] - if current != next: - g.add_edge(current, next) - - next = arr[i + 1, j + 1, k] - if current != next: - g.add_edge(current, next) - - next = arr[i + 1, j, k + 1] - if current != next: - g.add_edge(current, next) - - next = arr[i, j + 1, k + 1] - if current != next: - g.add_edge(current, next) - - next = arr[i + 1, j + 1, k + 1] - if current != next: - g.add_edge(current, next) - - next = arr[i, j, k + 1] - if current != next: - g.add_edge(current, next) - - k += 1 - - j += 1 - - i += 1 - - for n in g.nodes(): - g.node[n]['mean color'] = g.node[n][ - 'total color'] / g.node[n]['pixel count'] - - for x, y in g.edges_iter(): - diff = g.node[x]['mean color'] - g.node[y]['mean color'] - g[x][y]['weight'] = np.linalg.norm(diff) - - return g - - -def construct_rag_meancolor_2d(img, arr): - """Computes the Region Adjacency Graph of a 2D color image using - difference in mean color of regions as edge weights. - - Given an image and its segmentation, this method constructs the - corresponsing Region Adjacency Graph (RAG). Each node in the RAG - represents contiguous pixels with in `img` with the same label in - `arr`. There is an edge between each pair of adjacent regions. - - Parameters - ---------- - img : (width, height, 3) ndarray - Input image. - arr : (width, height) ndarray - The array with labels. - - Returns - ------- - out : RAG - The region adjacency graph. - """ - - cdef Py_ssize_t width, height, h, i, j, k - cdef cnp.int32_t current, next - width = arr.shape[0] - height = arr.shape[1] - - g = rag.RAG() - - i = 0 - for i in range(width-1): - j = 0 - for j in range(height-1): - current = arr[i, j] - - try: - g.node[current]['pixel count'] += 1 - g.node[current]['total color'] += img[i, j] - except KeyError: - g.add_node(current) - g.node[current]['pixel count'] = 1 - g.node[current]['total color'] = img[i, j].astype(np.long) - g.node[current]['labels'] = [arr[i, j]] - - next = arr[i + 1, j] - if current != next: - g.add_edge(current, next) - - next = arr[i, j + 1] - if current != next: - g.add_edge(current, next) - - next = arr[i + 1, j + 1] - if current != next: - g.add_edge(current, next) - - j += 1 - - i += 1 - - for n in g.nodes(): - g.node[n]['mean color'] = g.node[n][ - 'total color'] / g.node[n]['pixel count'] - - for x, y in g.edges_iter(): - diff = g.node[x]['mean color'] - g.node[y]['mean color'] - g[x][y]['weight'] = np.linalg.norm(diff) - - return g diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 72befba9..92231280 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -1,7 +1,7 @@ import networkx as nx -from skimage import util -from ._build_rag import construct_rag_meancolor_2d -from ._build_rag import construct_rag_meancolor_3d +from . import rag +import numpy as np +from scipy.ndimage import filters class RAG(nx.Graph): @@ -49,7 +49,18 @@ class RAG(nx.Graph): self.remove_node(i) -def rag_meancolor(img, labels): +def _add_edge(values, g): + values = values.astype(int) + current = values[0] + + for value in values[1:]: + if value >= 0: + g.add_edge(current, value) + + return 0.0 + + +def rag_mean_color(img, arr): """Computes the Region Adjacency Graph of a color image using difference in mean color of regions as edge weights. @@ -78,11 +89,43 @@ def rag_meancolor(img, labels): >>> rag = graph.rag_meancolor(img, labels) """ + g = rag.RAG() - img = util.img_as_ubyte(img) - if img.ndim == 4: - return construct_rag_meancolor_3d(img, labels) - elif img.ndim == 3: - return construct_rag_meancolor_2d(img, labels) - else: - raise ValueError("Image dimension not supported") + fp = np.zeros((3,) * arr.ndim) + slc = slice(1, None, None) + fp[(slc,) * arr.ndim] = 1 + + filters.generic_filter( + arr, + function=_add_edge, + footprint=fp, + mode='constant', + cval=-1, + extra_arguments=(g, + )) + iter = np.nditer(arr, flags=['multi_index']) + + while not iter.finished: + + current = arr[iter.multi_index] + try: + g.node[current]['pixel count'] += 1 + g.node[current]['total color'] += img[iter.multi_index] + except KeyError: + g.add_node(current) + g.node[current]['pixel count'] = 1 + g.node[current]['total color'] = img[ + iter.multi_index].astype(np.long) + g.node[current]['labels'] = [arr[iter.multi_index]] + + iter.iternext() + + for n in g.nodes(): + g.node[n]['mean color'] = g.node[n][ + 'total color'] / g.node[n]['pixel count'] + + for x, y in g.edges_iter(): + diff = g.node[x]['mean color'] - g.node[y]['mean color'] + g[x][y]['weight'] = np.linalg.norm(diff) + + return g diff --git a/skimage/graph/setup.py b/skimage/graph/setup.py index 436029da..45dd205a 100644 --- a/skimage/graph/setup.py +++ b/skimage/graph/setup.py @@ -17,8 +17,6 @@ def configuration(parent_package='', top_path=None): cython(['_spath.pyx'], working_path=base_path) cython(['_mcp.pyx'], working_path=base_path) cython(['heap.pyx'], working_path=base_path) - cython(['_build_rag.pyx'], working_path=base_path) - config.add_extension('_spath', sources=['_spath.c'], include_dirs=[get_numpy_include_dirs()]) @@ -26,8 +24,6 @@ def configuration(parent_package='', top_path=None): include_dirs=[get_numpy_include_dirs()]) config.add_extension('heap', sources=['heap.c'], include_dirs=[get_numpy_include_dirs()]) - config.add_extension('_build_rag', sources=['_build_rag.c'], - include_dirs=[get_numpy_include_dirs()]) return config From 9b8e1333e838ace440a349d54c0fe1cf00731cd7 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Wed, 18 Jun 2014 03:59:12 +0530 Subject: [PATCH 20/59] Corrected rag import --- skimage/graph/rag.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 92231280..e788455d 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -1,5 +1,4 @@ import networkx as nx -from . import rag import numpy as np from scipy.ndimage import filters @@ -60,7 +59,7 @@ def _add_edge(values, g): return 0.0 -def rag_mean_color(img, arr): +def rag_meancolor(img, arr): """Computes the Region Adjacency Graph of a color image using difference in mean color of regions as edge weights. @@ -89,7 +88,7 @@ def rag_mean_color(img, arr): >>> rag = graph.rag_meancolor(img, labels) """ - g = rag.RAG() + g = RAG() fp = np.zeros((3,) * arr.ndim) slc = slice(1, None, None) From 78397bf54dc5f8598cd7cf2ea5ebeb2f050e9aca Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Thu, 19 Jun 2014 00:05:14 +0530 Subject: [PATCH 21/59] reverted benfo.info and setup.py --- bento.info | 3 --- skimage/graph/setup.py | 1 - 2 files changed, 4 deletions(-) diff --git a/bento.info b/bento.info index 68aa4319..227e51e8 100644 --- a/bento.info +++ b/bento.info @@ -154,9 +154,6 @@ Library: Extension: skimage.feature._hessian_det_appx Sources: skimage/exposure/_hessian_det_appx.pyx - Extension: skimage.graph._construct - Sources: - skimage/exposure/_construct.pyx Executable: skivi Module: skimage.scripts.skivi diff --git a/skimage/graph/setup.py b/skimage/graph/setup.py index 45dd205a..463d2739 100644 --- a/skimage/graph/setup.py +++ b/skimage/graph/setup.py @@ -25,7 +25,6 @@ def configuration(parent_package='', top_path=None): config.add_extension('heap', sources=['heap.c'], include_dirs=[get_numpy_include_dirs()]) - return config if __name__ == '__main__': From 53330496f8965b210b97be6717184fa01a02dc89 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Thu, 19 Jun 2014 01:11:26 +0530 Subject: [PATCH 22/59] Added references --- skimage/graph/graph_cut.py | 7 +++++++ skimage/graph/rag.py | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/skimage/graph/graph_cut.py b/skimage/graph/graph_cut.py index 40adcdf8..2e72ac2b 100644 --- a/skimage/graph/graph_cut.py +++ b/skimage/graph/graph_cut.py @@ -31,6 +31,13 @@ def threshold_cut(label, rag, thresh): >>> labels = segmentation.slic(img) >>> rag = graph.rag_meancolor(img, labels) >>> new_labels = graph.threshold_cut(labels, rag, 10) + + References + ---------- + .. [1] Alain Tremeau and Philippe Colantoni + "Regions Adjacency Graph Applied To Color Image Segmentation" + http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.11.5274 + """ to_remove = [(x, y) for x, y, d in rag.edges_iter(data=True) if d['weight'] >= thresh] diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index e788455d..0b01880d 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -66,7 +66,7 @@ def rag_meancolor(img, arr): Given an image and its segmentation, this method constructs the corresponsing Region Adjacency Graph (RAG).Each node in the RAG represents a contiguous pixels with in `img` the same label in - `arr` + `arr`. Parameters ---------- @@ -87,6 +87,12 @@ def rag_meancolor(img, arr): >>> labels = segmentation.slic(img) >>> rag = graph.rag_meancolor(img, labels) + References + ---------- + .. [1] Alain Tremeau and Philippe Colantoni + "Regions Adjacency Graph Applied To Color Image Segmentation" + http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.11.5274 + """ g = RAG() From 410aecb354e5ce72c05979b088defcfeab5c131e Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Thu, 19 Jun 2014 02:49:02 +0530 Subject: [PATCH 23/59] type casting to double instead of long --- skimage/graph/rag.py | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 0b01880d..74bed4ad 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -14,7 +14,7 @@ class RAG(nx.Graph): """ def merge_nodes(self, i, j): - """Merges nodes `i` and `j`. + """Merge node `i` into `j`. The new combined node is adjacent to all the neighbors of `i` and `j`. In case of conflicting edges, edge with higher weight @@ -48,7 +48,23 @@ class RAG(nx.Graph): self.remove_node(i) -def _add_edge(values, g): +def _add_edge_filter(values, g): + """Adds an edge between first element in `values` and + all other elements of ` in the graph `g`. + + Paramteres + ---------- + values : array + The array to process. + g : RAG + The graph to add edges in. + + Returns + ------- + 0.0 : float + Always returns 0. + + """ values = values.astype(int) current = values[0] @@ -102,32 +118,27 @@ def rag_meancolor(img, arr): filters.generic_filter( arr, - function=_add_edge, + function=_add_edge_filter, footprint=fp, mode='constant', cval=-1, extra_arguments=(g, )) - iter = np.nditer(arr, flags=['multi_index']) - while not iter.finished: - - current = arr[iter.multi_index] + for index in np.ndindex(arr.shape): + current = arr[index] try: g.node[current]['pixel count'] += 1 - g.node[current]['total color'] += img[iter.multi_index] + g.node[current]['total color'] += img[index] except KeyError: g.add_node(current) g.node[current]['pixel count'] = 1 - g.node[current]['total color'] = img[ - iter.multi_index].astype(np.long) - g.node[current]['labels'] = [arr[iter.multi_index]] + g.node[current]['total color'] = img[index].astype(np.double) + g.node[current]['labels'] = [arr[index]] - iter.iternext() - - for n in g.nodes(): - g.node[n]['mean color'] = g.node[n][ - 'total color'] / g.node[n]['pixel count'] + for n in g: + g.node[n]['mean color'] = (g.node[n]['total color'] / + g.node[n]['pixel count']) for x, y in g.edges_iter(): diff = g.node[x]['mean color'] - g.node[y]['mean color'] From 8a36040eb88a9c55243a63ccf9564aa97209ab1f Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Thu, 19 Jun 2014 02:54:20 +0530 Subject: [PATCH 24/59] rebased and used color.label2rgb --- doc/examples/plot_rag_meancolor.py | 32 ++++++------------------------ 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/doc/examples/plot_rag_meancolor.py b/doc/examples/plot_rag_meancolor.py index aebfe6fc..1f19dd5e 100644 --- a/doc/examples/plot_rag_meancolor.py +++ b/doc/examples/plot_rag_meancolor.py @@ -3,47 +3,27 @@ RAG Thresholding ================ -This examples constructs a Region Adjacency Graph (RAG) and merges regions which are -similar in color. We construct a RAG and define edges as the difference in -mean color. We then join regions with similar mean color. +This examples constructs a Region Adjacency Graph (RAG) and merges regions +which are similar in color. We construct a RAG and define edges as the +difference in mean color. We then join regions with similar mean color. """ from skimage import graph from skimage import segmentation from skimage import data, io -import numpy as np from matplotlib import pyplot as plt +from skimage import color -def label_mask_img(img, label): - - out = np.zeros_like(img) - - red = img[:, :, 0] - green = img[:, :, 1] - blue = img[:, :, 2] - - for i in range(label.max()): - mask = label == i - - r = np.average(red[mask]) - g = np.average(green[mask]) - b = np.average(blue[mask]) - - # print r,g,b - out[mask] = r, g, b - - return out - img = data.coffee() labels1 = segmentation.slic(img, compactness=30, n_segments=400) -out1 = label_mask_img(img, labels1) +out1 = color.label2rgb(labels1, img, kind='avg') g = graph.rag_meancolor(img, labels1) labels2 = graph.threshold_cut(labels1, g, 30) -out2 = label_mask_img(img, labels2) +out2 = color.label2rgb(labels2, img, kind='avg') plt.figure() io.imshow(out1) From 20cefcf50a31df3bd820492521abec2fbd752054 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Thu, 19 Jun 2014 16:18:53 +0530 Subject: [PATCH 25/59] Added comments and switched try with if --- skimage/graph/graph_cut.py | 1 + skimage/graph/rag.py | 16 +++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/skimage/graph/graph_cut.py b/skimage/graph/graph_cut.py index 2e72ac2b..a255d01e 100644 --- a/skimage/graph/graph_cut.py +++ b/skimage/graph/graph_cut.py @@ -39,6 +39,7 @@ def threshold_cut(label, rag, thresh): http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.11.5274 """ + # Because deleting edges while iterating through them produces an error. to_remove = [(x, y) for x, y, d in rag.edges_iter(data=True) if d['weight'] >= thresh] rag.remove_edges_from(to_remove) diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 74bed4ad..92f8c62e 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -50,9 +50,9 @@ class RAG(nx.Graph): def _add_edge_filter(values, g): """Adds an edge between first element in `values` and - all other elements of ` in the graph `g`. + all other elements of `values` in the graph `g`. - Paramteres + Parameters ---------- values : array The array to process. @@ -116,22 +116,24 @@ def rag_meancolor(img, arr): slc = slice(1, None, None) fp[(slc,) * arr.ndim] = 1 + # The footprint is constructed in such a way that the first + # element in the array being passed to _add_edge_filter is + # the central value. filters.generic_filter( arr, function=_add_edge_filter, footprint=fp, mode='constant', cval=-1, - extra_arguments=(g, - )) + extra_arguments=(g,)) for index in np.ndindex(arr.shape): current = arr[index] - try: + + if 'pixel count' in g.node[current]: g.node[current]['pixel count'] += 1 g.node[current]['total color'] += img[index] - except KeyError: - g.add_node(current) + else: g.node[current]['pixel count'] = 1 g.node[current]['total color'] = img[index].astype(np.double) g.node[current]['labels'] = [arr[index]] From d0e7a26f6fcb19013e018cf11f1137ffb0a19b7d Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Thu, 19 Jun 2014 16:36:17 +0530 Subject: [PATCH 26/59] Added RAG merge_nodes test case --- skimage/graph/tests/test_rag.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index e239e79f..39e99852 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -1,5 +1,22 @@ import numpy as np from skimage import graph +import random + + +def test_rag_merge(): + g = graph.rag.RAG() + for i in range(10): + g.add_edge(i, (i + 1) % 10, {'weight': i * 10}) + g.node[i]['labels'] = [i] + + for i in range(9): + x = random.choice(g.nodes()) + y = random.choice(g.neighbors(x)) + g.merge_nodes(x, y) + + idx = g.nodes()[0] + sorted(g.node[idx]['labels']) == range(10) + assert g.edges() == [] def test_threshold_cut(): From 76d3dbad57c305b3881e074d7caed0236b5420ef Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Thu, 19 Jun 2014 17:57:07 +0530 Subject: [PATCH 27/59] added merge_nodes test --- skimage/graph/tests/test_rag.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index 39e99852..f923de2e 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -3,6 +3,7 @@ from skimage import graph import random + def test_rag_merge(): g = graph.rag.RAG() for i in range(10): @@ -14,6 +15,8 @@ def test_rag_merge(): y = random.choice(g.neighbors(x)) g.merge_nodes(x, y) + np.testing.assert_raises(ValueError,g.merge_nodes,7,9) + idx = g.nodes()[0] sorted(g.node[idx]['labels']) == range(10) assert g.edges() == [] From 711de464e51e0315f76905e24023a7f2902b8386 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Thu, 19 Jun 2014 18:03:44 +0530 Subject: [PATCH 28/59] Formatting changes --- skimage/graph/tests/test_rag.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index f923de2e..6ac1c373 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -3,7 +3,6 @@ from skimage import graph import random - def test_rag_merge(): g = graph.rag.RAG() for i in range(10): @@ -15,7 +14,7 @@ def test_rag_merge(): y = random.choice(g.neighbors(x)) g.merge_nodes(x, y) - np.testing.assert_raises(ValueError,g.merge_nodes,7,9) + np.testing.assert_raises(ValueError, g.merge_nodes, 7, 9) idx = g.nodes()[0] sorted(g.node[idx]['labels']) == range(10) From 0e35c422b398f737f96264caa34e0543f60e3065 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Sun, 22 Jun 2014 13:58:00 +0530 Subject: [PATCH 29/59] Graph can now merge non adjacent nodes --- skimage/graph/rag.py | 5 ----- skimage/graph/tests/test_rag.py | 12 ++++++------ 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 92f8c62e..8bcb06b9 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -28,10 +28,6 @@ class RAG(nx.Graph): Node to be merged. """ - - if not self.has_edge(i, j): - raise ValueError('Cant merge non adjacent nodes') - for x in self.neighbors(i): if x == j: continue @@ -41,7 +37,6 @@ class RAG(nx.Graph): w2 = self.get_edge_data(x, j)['weight'] w = max(w1, w2) - self.add_edge(x, j, weight=w) self.node[j]['labels'] += self.node[i]['labels'] diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index 6ac1c373..1225e774 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -11,13 +11,13 @@ def test_rag_merge(): for i in range(9): x = random.choice(g.nodes()) - y = random.choice(g.neighbors(x)) - g.merge_nodes(x, y) - - np.testing.assert_raises(ValueError, g.merge_nodes, 7, 9) - + y = random.choice(g.nodes()) + while x == y : + y = random.choice(g.nodes()) + g.merge_nodes(x,y) + idx = g.nodes()[0] - sorted(g.node[idx]['labels']) == range(10) + assert sorted(g.node[idx]['labels']) == range(10) assert g.edges() == [] From 319530fb8922185efb645acd364b046078b4bc92 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Sun, 22 Jun 2014 19:48:52 +0530 Subject: [PATCH 30/59] Used mapping in graph_cut.py --- skimage/graph/graph_cut.py | 12 ++++++------ skimage/graph/rag.py | 9 ++++++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/skimage/graph/graph_cut.py b/skimage/graph/graph_cut.py index a255d01e..27e4400d 100644 --- a/skimage/graph/graph_cut.py +++ b/skimage/graph/graph_cut.py @@ -2,7 +2,7 @@ import networkx as nx import numpy as np -def threshold_cut(label, rag, thresh): +def threshold_cut(label_image, rag, thresh): """Combines regions seperated by weight less than threshold. Given an image's labels and its RAG, outputs new labels by @@ -11,7 +11,7 @@ def threshold_cut(label, rag, thresh): Parameters ---------- - label : (width, height) or (width, height, 3) ndarray + label_image : (width, height) or (width, height, 3) ndarray The array of labels. rag : RAG The region adjacency graph. @@ -45,11 +45,11 @@ def threshold_cut(label, rag, thresh): rag.remove_edges_from(to_remove) comps = nx.connected_components(rag) - out = np.copy(label) + map_array = np.arange(label_image.max()+1, dtype = np.int) for i, nodes in enumerate(comps): for node in nodes: - for l in rag.node[node]['labels']: - out[label == l] = i + for label in rag.node[node]['labels']: + map_array[label] = i - return out + return map_array[label_image] diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 8bcb06b9..e2f60195 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -13,12 +13,12 @@ class RAG(nx.Graph): between their corresponding nodes. """ - def merge_nodes(self, i, j): + def merge_nodes(self, i, j, function=max): """Merge node `i` into `j`. The new combined node is adjacent to all the neighbors of `i` - and `j`. In case of conflicting edges, edge with higher weight - is chosen. + and `j`. In case of conflicting edges the given function is + called. Parameters ---------- @@ -26,6 +26,9 @@ class RAG(nx.Graph): Node to be merged. j : int Node to be merged. + function : callable, optional + Function to decide which edge weight to keep when a node is + adjacent to both `i` and `j`. """ for x in self.neighbors(i): From 3db0a2f81fa939673b6f1755427fbded8c5323f8 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Sun, 22 Jun 2014 20:27:44 +0530 Subject: [PATCH 31/59] Naming changes and formatting --- skimage/graph/rag.py | 42 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index e2f60195..3217bda2 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -4,12 +4,11 @@ from scipy.ndimage import filters class RAG(nx.Graph): - """ The class for holding the Region Adjacency Graph (RAG). - Each region is a contiguous set of pixels in an image, usuall - sharing some common property.Adjacent regions have an edge + Each region is a contiguous set of pixels in an image, usually + sharing some common property. Adjacent regions have an edge between their corresponding nodes. """ @@ -22,14 +21,11 @@ class RAG(nx.Graph): Parameters ---------- - i : int - Node to be merged. - j : int - Node to be merged. + i, j : int + Nodes to be merged. The resulting node will have ID `j`. function : callable, optional Function to decide which edge weight to keep when a node is adjacent to both `i` and `j`. - """ for x in self.neighbors(i): if x == j: @@ -38,7 +34,6 @@ class RAG(nx.Graph): w2 = -1 if self.has_edge(x, j): w2 = self.get_edge_data(x, j)['weight'] - w = max(w1, w2) self.add_edge(x, j, weight=w) @@ -47,7 +42,7 @@ class RAG(nx.Graph): def _add_edge_filter(values, g): - """Adds an edge between first element in `values` and + """Add an edge between first element in `values` and all other elements of `values` in the graph `g`. Parameters @@ -65,7 +60,6 @@ def _add_edge_filter(values, g): """ values = values.astype(int) current = values[0] - for value in values[1:]: if value >= 0: g.add_edge(current, value) @@ -73,20 +67,20 @@ def _add_edge_filter(values, g): return 0.0 -def rag_meancolor(img, arr): - """Computes the Region Adjacency Graph of a color image using +def rag_meancolor(image, label_image): + """Compute the Region Adjacency Graph of a color image using difference in mean color of regions as edge weights. Given an image and its segmentation, this method constructs the - corresponsing Region Adjacency Graph (RAG).Each node in the RAG + corresponsing Region Adjacency Graph (RAG). Each node in the RAG represents a contiguous pixels with in `img` the same label in `arr`. Parameters ---------- - img : (width, height, 3) or (width, height, depth, 3) ndarray + image : (width, height, 3) or (width, height, depth, 3) ndarray Input image. - arr : (width, height) or (width, height, depth) ndarray + label_image : (width, height) or (width, height, depth) ndarray The array with labels. Returns @@ -110,31 +104,31 @@ def rag_meancolor(img, arr): """ g = RAG() - fp = np.zeros((3,) * arr.ndim) + fp = np.zeros((3,) * label_image.ndim) slc = slice(1, None, None) - fp[(slc,) * arr.ndim] = 1 + fp[(slc,) * label_image.ndim] = 1 # The footprint is constructed in such a way that the first # element in the array being passed to _add_edge_filter is # the central value. filters.generic_filter( - arr, + label_image, function=_add_edge_filter, footprint=fp, mode='constant', cval=-1, extra_arguments=(g,)) - for index in np.ndindex(arr.shape): - current = arr[index] + for index in np.ndindex(label_image.shape): + current = label_image[index] if 'pixel count' in g.node[current]: g.node[current]['pixel count'] += 1 - g.node[current]['total color'] += img[index] + g.node[current]['total color'] += image[index] else: g.node[current]['pixel count'] = 1 - g.node[current]['total color'] = img[index].astype(np.double) - g.node[current]['labels'] = [arr[index]] + g.node[current]['total color'] = image[index].astype(np.double) + g.node[current]['labels'] = [current] for n in g: g.node[n]['mean color'] = (g.node[n]['total color'] / From 0efca407477e6aeb87047824208251594d722463 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Mon, 23 Jun 2014 00:58:13 +0530 Subject: [PATCH 32/59] Added connectivity parameter and a function input to merge_nodes --- skimage/graph/rag.py | 43 ++++++++++++++++++++++++--------- skimage/graph/tests/test_rag.py | 13 +++++++++- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 3217bda2..dcda853b 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -1,6 +1,7 @@ import networkx as nx import numpy as np from scipy.ndimage import filters +from scipy import ndimage as nd class RAG(nx.Graph): @@ -12,7 +13,7 @@ class RAG(nx.Graph): between their corresponding nodes. """ - def merge_nodes(self, i, j, function=max): + def merge_nodes(self, i, j, function=None, extra_arguments=[], extra_keywords={}): """Merge node `i` into `j`. The new combined node is adjacent to all the neighbors of `i` @@ -25,7 +26,15 @@ class RAG(nx.Graph): Nodes to be merged. The resulting node will have ID `j`. function : callable, optional Function to decide which edge weight to keep when a node is - adjacent to both `i` and `j`. + adjacent to both `i` and `j`. The arguments passed to the + function are, the tuples represnting both the conflicting edges + and the graph.The default behaviour is that the edge with higher + weight is kept. + extra_arguments : sequence, optional + The sequence of extra positional arguments passed to + `function` + extra_keywords : + The dict of keyword arguments passed to the `function`. """ for x in self.neighbors(i): if x == j: @@ -34,7 +43,13 @@ class RAG(nx.Graph): w2 = -1 if self.has_edge(x, j): w2 = self.get_edge_data(x, j)['weight'] - w = max(w1, w2) + + w = w1 + if w2 > 0 : + if not function : + w = max(w1, w2) + else: + w = function((i, x), (j,x), self, *extra_arguments, **extra_keywords) self.add_edge(x, j, weight=w) self.node[j]['labels'] += self.node[i]['labels'] @@ -43,7 +58,8 @@ class RAG(nx.Graph): def _add_edge_filter(values, g): """Add an edge between first element in `values` and - all other elements of `values` in the graph `g`. + all other elements of `values` in the graph `g`.`values[0]` + is expected to be the central value of the footprint used. Parameters ---------- @@ -61,13 +77,12 @@ def _add_edge_filter(values, g): values = values.astype(int) current = values[0] for value in values[1:]: - if value >= 0: - g.add_edge(current, value) + g.add_edge(current, value) return 0.0 -def rag_meancolor(image, label_image): +def rag_meancolor(image, label_image, connectivity = 2): """Compute the Region Adjacency Graph of a color image using difference in mean color of regions as edge weights. @@ -82,6 +97,9 @@ def rag_meancolor(image, label_image): Input image. label_image : (width, height) or (width, height, depth) ndarray The array with labels. + connectivity : float, optional + Pixels with a squared distance less than `connectivity`from each other + are considered adjacent. Returns ------- @@ -104,9 +122,11 @@ def rag_meancolor(image, label_image): """ g = RAG() - fp = np.zeros((3,) * label_image.ndim) - slc = slice(1, None, None) - fp[(slc,) * label_image.ndim] = 1 + fp = nd.generate_binary_structure(label_image.ndim, connectivity) + for d in range(fp.ndim): + fp = fp.swapaxes(0, d) + fp[0, ...] = 0 + fp = fp.swapaxes(0, d) # The footprint is constructed in such a way that the first # element in the array being passed to _add_edge_filter is @@ -115,8 +135,7 @@ def rag_meancolor(image, label_image): label_image, function=_add_edge_filter, footprint=fp, - mode='constant', - cval=-1, + mode='nearest', extra_arguments=(g,)) for index in np.ndindex(label_image.shape): diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index 1225e774..c644560c 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -2,6 +2,10 @@ import numpy as np from skimage import graph import random +def _min_edge((a1,b1),(a2,b2),g): + w1 = g.edge[a1][b1]['weight'] + w2 = g.edge[a2][b2]['weight'] + return min(w1,w2) def test_rag_merge(): g = graph.rag.RAG() @@ -9,13 +13,20 @@ def test_rag_merge(): g.add_edge(i, (i + 1) % 10, {'weight': i * 10}) g.node[i]['labels'] = [i] - for i in range(9): + for i in range(4): x = random.choice(g.nodes()) y = random.choice(g.nodes()) while x == y : y = random.choice(g.nodes()) g.merge_nodes(x,y) + for i in range(5): + x = random.choice(g.nodes()) + y = random.choice(g.nodes()) + while x == y : + y = random.choice(g.nodes()) + g.merge_nodes(x,y,_min_edge) + idx = g.nodes()[0] assert sorted(g.node[idx]['labels']) == range(10) assert g.edges() == [] From a1bc2e95fd506a3fa343984d00fe0061410cad75 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Mon, 23 Jun 2014 01:15:00 +0530 Subject: [PATCH 33/59] Made test Python3 compatible --- skimage/graph/rag.py | 37 ++++++++++++++++++++------------- skimage/graph/tests/test_rag.py | 8 +++---- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index dcda853b..01376734 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -5,6 +5,7 @@ from scipy import ndimage as nd class RAG(nx.Graph): + """ The class for holding the Region Adjacency Graph (RAG). @@ -13,7 +14,8 @@ class RAG(nx.Graph): between their corresponding nodes. """ - def merge_nodes(self, i, j, function=None, extra_arguments=[], extra_keywords={}): + def merge_nodes(self, i, j, function=None, extra_arguments=[], + extra_keywords={}): """Merge node `i` into `j`. The new combined node is adjacent to all the neighbors of `i` @@ -33,7 +35,7 @@ class RAG(nx.Graph): extra_arguments : sequence, optional The sequence of extra positional arguments passed to `function` - extra_keywords : + extra_keywords : The dict of keyword arguments passed to the `function`. """ for x in self.neighbors(i): @@ -43,13 +45,14 @@ class RAG(nx.Graph): w2 = -1 if self.has_edge(x, j): w2 = self.get_edge_data(x, j)['weight'] - + w = w1 - if w2 > 0 : - if not function : + if w2 > 0: + if not function: w = max(w1, w2) else: - w = function((i, x), (j,x), self, *extra_arguments, **extra_keywords) + w = function((i, x), (j, x), self, + *extra_arguments, **extra_keywords) self.add_edge(x, j, weight=w) self.node[j]['labels'] += self.node[i]['labels'] @@ -82,7 +85,7 @@ def _add_edge_filter(values, g): return 0.0 -def rag_meancolor(image, label_image, connectivity = 2): +def rag_meancolor(image, label_image, connectivity=2): """Compute the Region Adjacency Graph of a color image using difference in mean color of regions as edge weights. @@ -131,6 +134,12 @@ def rag_meancolor(image, label_image, connectivity = 2): # The footprint is constructed in such a way that the first # element in the array being passed to _add_edge_filter is # the central value. + + for i in range(label_image.max() + 1): + g.add_node( + i, {'labels': [i], 'pixel count': 0, 'total color': + np.array([0, 0, 0], dtype=np.double)}) + filters.generic_filter( label_image, function=_add_edge_filter, @@ -141,13 +150,13 @@ def rag_meancolor(image, label_image, connectivity = 2): for index in np.ndindex(label_image.shape): current = label_image[index] - if 'pixel count' in g.node[current]: - g.node[current]['pixel count'] += 1 - g.node[current]['total color'] += image[index] - else: - g.node[current]['pixel count'] = 1 - g.node[current]['total color'] = image[index].astype(np.double) - g.node[current]['labels'] = [current] + # if 'pixel count' in g.node[current]: + g.node[current]['pixel count'] += 1 + g.node[current]['total color'] += image[index] + # else: + # g.node[current]['pixel count'] = 1 + # g.node[current]['total color'] = image[index].astype(np.double) + # g.node[current]['labels'] = [current] for n in g: g.node[n]['mean color'] = (g.node[n]['total color'] / diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index c644560c..015999f5 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -2,9 +2,9 @@ import numpy as np from skimage import graph import random -def _min_edge((a1,b1),(a2,b2),g): - w1 = g.edge[a1][b1]['weight'] - w2 = g.edge[a2][b2]['weight'] +def _min_edge(e1,e2,g): + w1 = g.edge[e1[0]][e1[1]]['weight'] + w2 = g.edge[e2[0]][e2[1]]['weight'] return min(w1,w2) def test_rag_merge(): @@ -28,7 +28,7 @@ def test_rag_merge(): g.merge_nodes(x,y,_min_edge) idx = g.nodes()[0] - assert sorted(g.node[idx]['labels']) == range(10) + assert sorted(g.node[idx]['labels']) == list(range(10)) assert g.edges() == [] From c14021a9cbd16f07526adf08a7aff508521b6f0a Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Mon, 23 Jun 2014 01:16:57 +0530 Subject: [PATCH 34/59] Formatting and typos --- skimage/graph/graph_cut.py | 2 +- skimage/graph/tests/test_rag.py | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/skimage/graph/graph_cut.py b/skimage/graph/graph_cut.py index 27e4400d..1105d423 100644 --- a/skimage/graph/graph_cut.py +++ b/skimage/graph/graph_cut.py @@ -46,7 +46,7 @@ def threshold_cut(label_image, rag, thresh): comps = nx.connected_components(rag) - map_array = np.arange(label_image.max()+1, dtype = np.int) + map_array = np.arange(label_image.max()+1, dtype=np.int) for i, nodes in enumerate(comps): for node in nodes: for label in rag.node[node]['labels']: diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index 015999f5..bdaf8277 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -2,10 +2,12 @@ import numpy as np from skimage import graph import random -def _min_edge(e1,e2,g): + +def _min_edge(e1, e2, g): w1 = g.edge[e1[0]][e1[1]]['weight'] w2 = g.edge[e2[0]][e2[1]]['weight'] - return min(w1,w2) + return min(w1, w2) + def test_rag_merge(): g = graph.rag.RAG() @@ -16,16 +18,16 @@ def test_rag_merge(): for i in range(4): x = random.choice(g.nodes()) y = random.choice(g.nodes()) - while x == y : + while x == y: y = random.choice(g.nodes()) - g.merge_nodes(x,y) - + g.merge_nodes(x, y) + for i in range(5): x = random.choice(g.nodes()) y = random.choice(g.nodes()) - while x == y : + while x == y: y = random.choice(g.nodes()) - g.merge_nodes(x,y,_min_edge) + g.merge_nodes(x, y, _min_edge) idx = g.nodes()[0] assert sorted(g.node[idx]['labels']) == list(range(10)) From 66d3ec3831b358e51f93d7599b0f98a38f3f6486 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Mon, 23 Jun 2014 01:28:10 +0530 Subject: [PATCH 35/59] removed commented stataments --- skimage/graph/rag.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 01376734..24c82a19 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -149,14 +149,8 @@ def rag_meancolor(image, label_image, connectivity=2): for index in np.ndindex(label_image.shape): current = label_image[index] - - # if 'pixel count' in g.node[current]: g.node[current]['pixel count'] += 1 g.node[current]['total color'] += image[index] - # else: - # g.node[current]['pixel count'] = 1 - # g.node[current]['total color'] = image[index].astype(np.double) - # g.node[current]['labels'] = [current] for n in g: g.node[n]['mean color'] = (g.node[n]['total color'] / From 27831d8e2ffd683d802572b1b71340268002f430 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Mon, 23 Jun 2014 22:26:53 +0530 Subject: [PATCH 36/59] Formatting and docstring changes --- skimage/graph/graph_cut.py | 4 ++-- skimage/graph/rag.py | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/skimage/graph/graph_cut.py b/skimage/graph/graph_cut.py index 1105d423..6cdd9f83 100644 --- a/skimage/graph/graph_cut.py +++ b/skimage/graph/graph_cut.py @@ -3,7 +3,7 @@ import numpy as np def threshold_cut(label_image, rag, thresh): - """Combines regions seperated by weight less than threshold. + """Combine regions seperated by weight less than threshold. Given an image's labels and its RAG, outputs new labels by combining regions whose nodes are seperated by a weight less @@ -46,7 +46,7 @@ def threshold_cut(label_image, rag, thresh): comps = nx.connected_components(rag) - map_array = np.arange(label_image.max()+1, dtype=np.int) + map_array = np.arange(label_image.max() + 1, dtype=np.int) for i, nodes in enumerate(comps): for node in nodes: for label in rag.node[node]['labels']: diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 24c82a19..673e7ead 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -96,10 +96,11 @@ def rag_meancolor(image, label_image, connectivity=2): Parameters ---------- - image : (width, height, 3) or (width, height, depth, 3) ndarray + image : ndarray Input image. - label_image : (width, height) or (width, height, depth) ndarray - The array with labels. + label_image : ndarray + The array with labels. This should have one dimention lesser than + `image` connectivity : float, optional Pixels with a squared distance less than `connectivity`from each other are considered adjacent. From bd9ab8f0fd9b4b6f6987ad9d86a1a10fe572901e Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Mon, 23 Jun 2014 23:04:16 +0530 Subject: [PATCH 37/59] Switch label_image to labels --- skimage/graph/graph_cut.py | 8 ++++---- skimage/graph/rag.py | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/skimage/graph/graph_cut.py b/skimage/graph/graph_cut.py index 6cdd9f83..87fa79a8 100644 --- a/skimage/graph/graph_cut.py +++ b/skimage/graph/graph_cut.py @@ -2,7 +2,7 @@ import networkx as nx import numpy as np -def threshold_cut(label_image, rag, thresh): +def threshold_cut(labels, rag, thresh): """Combine regions seperated by weight less than threshold. Given an image's labels and its RAG, outputs new labels by @@ -11,7 +11,7 @@ def threshold_cut(label_image, rag, thresh): Parameters ---------- - label_image : (width, height) or (width, height, 3) ndarray + labels : (width, height) or (width, height, 3) ndarray The array of labels. rag : RAG The region adjacency graph. @@ -46,10 +46,10 @@ def threshold_cut(label_image, rag, thresh): comps = nx.connected_components(rag) - map_array = np.arange(label_image.max() + 1, dtype=np.int) + map_array = np.arange(labels.max() + 1, dtype=np.int) for i, nodes in enumerate(comps): for node in nodes: for label in rag.node[node]['labels']: map_array[label] = i - return map_array[label_image] + return map_array[labels] diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 673e7ead..e42a5707 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -85,7 +85,7 @@ def _add_edge_filter(values, g): return 0.0 -def rag_meancolor(image, label_image, connectivity=2): +def rag_meancolor(image, labels, connectivity=2): """Compute the Region Adjacency Graph of a color image using difference in mean color of regions as edge weights. @@ -98,7 +98,7 @@ def rag_meancolor(image, label_image, connectivity=2): ---------- image : ndarray Input image. - label_image : ndarray + labels : ndarray The array with labels. This should have one dimention lesser than `image` connectivity : float, optional @@ -126,7 +126,7 @@ def rag_meancolor(image, label_image, connectivity=2): """ g = RAG() - fp = nd.generate_binary_structure(label_image.ndim, connectivity) + fp = nd.generate_binary_structure(labels.ndim, connectivity) for d in range(fp.ndim): fp = fp.swapaxes(0, d) fp[0, ...] = 0 @@ -136,20 +136,20 @@ def rag_meancolor(image, label_image, connectivity=2): # element in the array being passed to _add_edge_filter is # the central value. - for i in range(label_image.max() + 1): + for i in range(labels.max() + 1): g.add_node( i, {'labels': [i], 'pixel count': 0, 'total color': np.array([0, 0, 0], dtype=np.double)}) filters.generic_filter( - label_image, + labels, function=_add_edge_filter, footprint=fp, mode='nearest', extra_arguments=(g,)) - for index in np.ndindex(label_image.shape): - current = label_image[index] + for index in np.ndindex(labels.shape): + current = labels[index] g.node[current]['pixel count'] += 1 g.node[current]['total color'] += image[index] From b1f59fceee1cb2f9a11c9ff96412b771d2a63ae5 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Thu, 26 Jun 2014 00:11:49 +0530 Subject: [PATCH 38/59] Changed prototype of weight_func --- doc/examples/plot_rag_meancolor.py | 4 +- skimage/graph/graph_cut.py | 10 ++-- skimage/graph/rag.py | 95 +++++++++++++++--------------- skimage/graph/tests/test_rag.py | 18 ++++-- 4 files changed, 65 insertions(+), 62 deletions(-) diff --git a/doc/examples/plot_rag_meancolor.py b/doc/examples/plot_rag_meancolor.py index 1f19dd5e..129814e2 100644 --- a/doc/examples/plot_rag_meancolor.py +++ b/doc/examples/plot_rag_meancolor.py @@ -9,9 +9,7 @@ difference in mean color. We then join regions with similar mean color. """ -from skimage import graph -from skimage import segmentation -from skimage import data, io +from skimage import graph, data, io, segmentation, color from matplotlib import pyplot as plt from skimage import color diff --git a/skimage/graph/graph_cut.py b/skimage/graph/graph_cut.py index 87fa79a8..165091b1 100644 --- a/skimage/graph/graph_cut.py +++ b/skimage/graph/graph_cut.py @@ -5,13 +5,13 @@ import numpy as np def threshold_cut(labels, rag, thresh): """Combine regions seperated by weight less than threshold. - Given an image's labels and its RAG, outputs new labels by + Given an image's labels and its RAG, output new labels by combining regions whose nodes are seperated by a weight less than the given threshold. Parameters ---------- - labels : (width, height) or (width, height, 3) ndarray + labels : ndarray The array of labels. rag : RAG The region adjacency graph. @@ -21,12 +21,12 @@ def threshold_cut(labels, rag, thresh): Returns ------- - out : (width, height, 3) or (width, height, depth, 3) ndarray + out : ndarray The new labelled array. Examples -------- - >>> from skimage import data,graph,segmentation + >>> from skimage import data, graph, segmentation >>> img = data.lena() >>> labels = segmentation.slic(img) >>> rag = graph.rag_meancolor(img, labels) @@ -46,7 +46,7 @@ def threshold_cut(labels, rag, thresh): comps = nx.connected_components(rag) - map_array = np.arange(labels.max() + 1, dtype=np.int) + map_array = np.arange(labels.max() + 1, dtype=labels.dtype) for i, nodes in enumerate(comps): for node in nodes: for label in rag.node[node]['labels']: diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index e42a5707..1012ccb5 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -7,56 +7,50 @@ from scipy import ndimage as nd class RAG(nx.Graph): """ - The class for holding the Region Adjacency Graph (RAG). - - Each region is a contiguous set of pixels in an image, usually - sharing some common property. Adjacent regions have an edge - between their corresponding nodes. + The Region Adjacency Graph (RAG) of an image. """ - def merge_nodes(self, i, j, function=None, extra_arguments=[], + def merge_nodes(self, src, dst, weight_func=None, extra_arguments=[], extra_keywords={}): - """Merge node `i` into `j`. + """Merge two nodes. - The new combined node is adjacent to all the neighbors of `i` - and `j`. In case of conflicting edges the given function is + The new combined node is adjacent to all the neighbors of `src` + and `dst`. In case of conflicting edges the given function is called. Parameters ---------- i, j : int Nodes to be merged. The resulting node will have ID `j`. - function : callable, optional - Function to decide which edge weight to keep when a node is - adjacent to both `i` and `j`. The arguments passed to the - function are, the tuples represnting both the conflicting edges - and the graph.The default behaviour is that the edge with higher - weight is kept. + weight_func : callable, optional + Function to decide edge weight between existing nodes and the new + node.The arguments passed to the function are, the graph, `src`, + `dst` and the existing node whose edge weight need to be updated. extra_arguments : sequence, optional The sequence of extra positional arguments passed to - `function` + `weight_func` extra_keywords : - The dict of keyword arguments passed to the `function`. + The dict of keyword arguments passed to the `weight_func`. """ - for x in self.neighbors(i): - if x == j: + for neighbor in self.neighbors(src): + if neighbor == dst: continue - w1 = self.get_edge_data(x, i)['weight'] - w2 = -1 - if self.has_edge(x, j): - w2 = self.get_edge_data(x, j)['weight'] - - w = w1 - if w2 > 0: - if not function: - w = max(w1, w2) + w1 = self.get_edge_data(neighbor, src)['weight'] + w2 = None + if self.has_edge(neighbor, dst): + w2 = self.get_edge_data(neighbor, dst)['weight'] + if not weight_func: + if w2 is None: + w = w1 else: - w = function((i, x), (j, x), self, - *extra_arguments, **extra_keywords) - self.add_edge(x, j, weight=w) + w = min(w1, w2) + else: + w = weight_func(self, src, dst, neighbor, + *extra_arguments, **extra_keywords) + self.add_edge(neighbor, dst, weight=w) - self.node[j]['labels'] += self.node[i]['labels'] - self.remove_node(i) + self.node[dst]['labels'] += self.node[src]['labels'] + self.remove_node(src) def _add_edge_filter(values, g): @@ -86,24 +80,27 @@ def _add_edge_filter(values, g): def rag_meancolor(image, labels, connectivity=2): - """Compute the Region Adjacency Graph of a color image using - difference in mean color of regions as edge weights. + """Compute the Region Adjacency Graph using mean colors. Given an image and its segmentation, this method constructs the corresponsing Region Adjacency Graph (RAG). Each node in the RAG represents a contiguous pixels with in `img` the same label in - `arr`. + `arr`. The weight between two adjacent regions is the difference + int their mean color. Parameters ---------- image : ndarray Input image. labels : ndarray - The array with labels. This should have one dimention lesser than - `image` + The array with labels. This should have one dimention less than + `image`. If `image` has dimensions `(M,N,3)` `labels` should have + dimensions `(M, N)`. connectivity : float, optional - Pixels with a squared distance less than `connectivity`from each other - are considered adjacent. + Pixels with a squared distance less than `connectivity` from each other + are considered adjacent. It can range from 1 to `labels.ndim`. It's + behaviour is the same as `connectivity` parameter in + `scipy.ndimage.filters.generate_binary_structure`. Returns ------- @@ -126,28 +123,28 @@ def rag_meancolor(image, labels, connectivity=2): """ g = RAG() + # The footprint is constructed in such a way that the first + # element in the array being passed to _add_edge_filter is + # the central value. fp = nd.generate_binary_structure(labels.ndim, connectivity) for d in range(fp.ndim): fp = fp.swapaxes(0, d) fp[0, ...] = 0 fp = fp.swapaxes(0, d) - # The footprint is constructed in such a way that the first - # element in the array being passed to _add_edge_filter is - # the central value. - - for i in range(labels.max() + 1): - g.add_node( - i, {'labels': [i], 'pixel count': 0, 'total color': - np.array([0, 0, 0], dtype=np.double)}) - filters.generic_filter( labels, function=_add_edge_filter, footprint=fp, mode='nearest', + output=np.zeros(labels.shape, dtype=np.uint8), extra_arguments=(g,)) + for n in g: + g.node[n].update({'labels': [n], + 'pixel count': 0, + 'total color': np.array([0, 0, 0], dtype=np.double)}) + for index in np.ndindex(labels.shape): current = labels[index] g.node[current]['pixel count'] += 1 diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index bdaf8277..5d382a43 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -3,10 +3,18 @@ from skimage import graph import random -def _min_edge(e1, e2, g): - w1 = g.edge[e1[0]][e1[1]]['weight'] - w2 = g.edge[e2[0]][e2[1]]['weight'] - return min(w1, w2) +def _max_edge(g, src, dst, neighbor): + try: + w1 = g.edge[src][neighbor]['weight'] + except KeyError: + w1 = None + + try: + w2 = g.edge[dst][neighbor]['weight'] + except KeyError: + w2 = None + + return max(w1, w2) def test_rag_merge(): @@ -27,7 +35,7 @@ def test_rag_merge(): y = random.choice(g.nodes()) while x == y: y = random.choice(g.nodes()) - g.merge_nodes(x, y, _min_edge) + g.merge_nodes(x, y, _max_edge) idx = g.nodes()[0] assert sorted(g.node[idx]['labels']) == list(range(10)) From cbfa8aa6e12e03947c757ca644e76749d3a6fcf5 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Thu, 26 Jun 2014 00:54:16 +0530 Subject: [PATCH 39/59] docstring corrections --- skimage/graph/rag.py | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 1012ccb5..8017f1f6 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -15,22 +15,23 @@ class RAG(nx.Graph): """Merge two nodes. The new combined node is adjacent to all the neighbors of `src` - and `dst`. In case of conflicting edges the given function is - called. + and `dst`. `weight_func` is called to decide the weight of edges + incident on the new node. Parameters ---------- i, j : int - Nodes to be merged. The resulting node will have ID `j`. + Nodes to be merged. The resulting node will have ID `dst`. weight_func : callable, optional - Function to decide edge weight between existing nodes and the new - node.The arguments passed to the function are, the graph, `src`, - `dst` and the existing node whose edge weight need to be updated. + Function to decide edge weight of edges incident on the new node. + The arguments passed to the function are, the graph, `src`, `dst` + and the node which is adjacent to the new node. extra_arguments : sequence, optional The sequence of extra positional arguments passed to - `weight_func` + `weight_func`. extra_keywords : The dict of keyword arguments passed to the `weight_func`. + """ for neighbor in self.neighbors(src): if neighbor == dst: @@ -54,8 +55,11 @@ class RAG(nx.Graph): def _add_edge_filter(values, g): - """Add an edge between first element in `values` and - all other elements of `values` in the graph `g`.`values[0]` + """Create and edge between the first and the remaining + values in an array. + + Add an edge between first element in `values` and + all other elements of `values` in the graph `g`. `values[0]` is expected to be the central value of the footprint used. Parameters @@ -67,7 +71,7 @@ def _add_edge_filter(values, g): Returns ------- - 0.0 : float + 0 : int Always returns 0. """ @@ -76,7 +80,7 @@ def _add_edge_filter(values, g): for value in values[1:]: g.add_edge(current, value) - return 0.0 + return 0 def rag_meancolor(image, labels, connectivity=2): @@ -84,9 +88,9 @@ def rag_meancolor(image, labels, connectivity=2): Given an image and its segmentation, this method constructs the corresponsing Region Adjacency Graph (RAG). Each node in the RAG - represents a contiguous pixels with in `img` the same label in - `arr`. The weight between two adjacent regions is the difference - int their mean color. + represents a contiguous set pixels within `image` with the same + label in `labels`. The weight between two adjacent regions is the + difference int their mean color. Parameters ---------- @@ -94,7 +98,7 @@ def rag_meancolor(image, labels, connectivity=2): Input image. labels : ndarray The array with labels. This should have one dimention less than - `image`. If `image` has dimensions `(M,N,3)` `labels` should have + `image`. If `image` has dimensions `(M, N, 3)` `labels` should have dimensions `(M, N)`. connectivity : float, optional Pixels with a squared distance less than `connectivity` from each other @@ -109,7 +113,7 @@ def rag_meancolor(image, labels, connectivity=2): Examples -------- - >>> from skimage import data,graph,segmentation + >>> from skimage import data, graph, segmentation >>> img = data.lena() >>> labels = segmentation.slic(img) >>> rag = graph.rag_meancolor(img, labels) From b1284ee18015432a475128ff06195bce54539639 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Thu, 26 Jun 2014 00:57:50 +0530 Subject: [PATCH 40/59] update test for py3 --- skimage/graph/tests/test_rag.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index 5d382a43..71d44774 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -14,7 +14,12 @@ def _max_edge(g, src, dst, neighbor): except KeyError: w2 = None - return max(w1, w2) + if w1 == None: + return w2 + elif w2 == None: + return w1 + else: + return max(w1, w2) def test_rag_merge(): From bb874074c4d30b88d01d14e93ca96e2e69d7de7b Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Thu, 26 Jun 2014 00:58:54 +0530 Subject: [PATCH 41/59] None comparison --- skimage/graph/tests/test_rag.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index 71d44774..9f7c3ba8 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -14,9 +14,9 @@ def _max_edge(g, src, dst, neighbor): except KeyError: w2 = None - if w1 == None: + if w1 is None: return w2 - elif w2 == None: + elif w2 is None: return w1 else: return max(w1, w2) From f481724f35a24d0dfeac9f1893468dd14e45ec78 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Thu, 26 Jun 2014 02:02:33 +0530 Subject: [PATCH 42/59] Added RAG merge example --- doc/examples/plot_rag.py | 69 ++++++++++++++++++++++++++++++ doc/examples/plot_rag_meancolor.py | 1 - 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 doc/examples/plot_rag.py diff --git a/doc/examples/plot_rag.py b/doc/examples/plot_rag.py new file mode 100644 index 00000000..d0ed3089 --- /dev/null +++ b/doc/examples/plot_rag.py @@ -0,0 +1,69 @@ +""" +======================= +Region Adjacency Graphs +======================= + +This example demonstrates the use of `merge_nodes` function of a Region +Adjacency Graph (RAG). When a new node is formed by merging two nodes, the edge +weight of all the edges incident on it can be updated by a user defined +function `weight_func`. + +The default behaviour is to use the smaller edge weight incase of a conflict. +THe example below also shows how to use a custom function to take the larger +weight instead. + +""" +from skimage.graph import rag +import networkx as nx +from matplotlib import pyplot as plt + + +def max_edge(g, src, dst, neighbor): + try: + w1 = g.edge[src][neighbor]['weight'] + except KeyError: + w1 = None + + try: + w2 = g.edge[dst][neighbor]['weight'] + except KeyError: + w2 = None + + if w1 is None: + return w2 + elif w2 is None: + return w1 + else: + return max(w1, w2) + + +def display(g, title): + pos = nx.circular_layout(g) + plt.figure() + plt.title(title) + nx.draw(g, pos) + nx.draw_networkx_edge_labels(g, pos, font_size=20) + + +g = rag.RAG() +g.add_edge(1, 2, weight=10) +g.add_edge(2, 3, weight=20) +g.add_edge(3, 4, weight=30) +g.add_edge(4, 1, weight=40) +g.add_edge(1, 3, weight=50) + +# Assigning dummy labels. +for n in g.nodes(): + g.node[n]['labels'] = [n] + +gc = g.copy() + +display(g, "Original Graph") + +g.merge_nodes(1, 3) +display(g, "Merged with default (min)") + +gc.merge_nodes(1, 3, weight_func=max_edge) +display(gc, "Merged with max") + +plt.show() diff --git a/doc/examples/plot_rag_meancolor.py b/doc/examples/plot_rag_meancolor.py index 129814e2..11aca77c 100644 --- a/doc/examples/plot_rag_meancolor.py +++ b/doc/examples/plot_rag_meancolor.py @@ -11,7 +11,6 @@ difference in mean color. We then join regions with similar mean color. from skimage import graph, data, io, segmentation, color from matplotlib import pyplot as plt -from skimage import color img = data.coffee() From c08a6876d647448d520ad8893065a8baac4be46c Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Thu, 26 Jun 2014 02:05:20 +0530 Subject: [PATCH 43/59] Added comment about footprint --- skimage/graph/rag.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 8017f1f6..4943cf4a 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -136,6 +136,13 @@ def rag_meancolor(image, labels, connectivity=2): fp[0, ...] = 0 fp = fp.swapaxes(0, d) + # For example + # if labels.ndim = 2 and connectivity = 1 + # fp = [[0,0,0],[0,1,1],[0,1,0]] + # + # if labels.ndim = 2 and connectivity = 2 + # fp = [[0,0,0],[0,1,1],[0,1,1]] + filters.generic_filter( labels, function=_add_edge_filter, From c8480d3f6d4a6fd990f9b35975216615d1b18f9d Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Sat, 28 Jun 2014 01:17:44 +0530 Subject: [PATCH 44/59] Change merge_nodes code and test case --- skimage/graph/rag.py | 101 +++++++++++++++++++++----------- skimage/graph/tests/test_rag.py | 61 ++++++++----------- 2 files changed, 93 insertions(+), 69 deletions(-) diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 4943cf4a..be138e1e 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -4,13 +4,42 @@ from scipy.ndimage import filters from scipy import ndimage as nd +def min_weight(g, src, dst, n): + """Callback to handle merging nodes by choosing minimum weight. + + Returns either the weight between (`src`, `n`) or (`dst`, `n`) + in `g` or the minumum of the two when both exist. + + Parameters + ---------- + g : RAG + The graph to consider. + src, dst : int + Typically the verices in `g` to be merged. + n : int + A neighbor of `src` or `dst` or both + + Returns + ------- + weight : float + The weight between (`src`, `n`) or (`dst`, `n`) in `g` or the + minumum of the two when both exist. + + """ + + # cover the cases where n only has edge to either `src` or `dst` + w1 = g[n].get(src, {'weight': np.inf})['weight'] + w2 = g[n].get(dst, {'weight': np.inf})['weight'] + return min(w1, w2) + + class RAG(nx.Graph): """ The Region Adjacency Graph (RAG) of an image. """ - def merge_nodes(self, src, dst, weight_func=None, extra_arguments=[], + def merge_nodes(self, src, dst, weight_func=min_weight, extra_arguments=[], extra_keywords={}): """Merge two nodes. @@ -20,12 +49,13 @@ class RAG(nx.Graph): Parameters ---------- - i, j : int + src, dst : int Nodes to be merged. The resulting node will have ID `dst`. weight_func : callable, optional Function to decide edge weight of edges incident on the new node. - The arguments passed to the function are, the graph, `src`, `dst` - and the node which is adjacent to the new node. + For each neighbor `n` for `src and `dst`, `weight_func` will be + called as follows: `weight_func(src, dst, n, *extra_arguments, + **extra_keywords)` extra_arguments : sequence, optional The sequence of extra positional arguments passed to `weight_func`. @@ -33,21 +63,21 @@ class RAG(nx.Graph): The dict of keyword arguments passed to the `weight_func`. """ - for neighbor in self.neighbors(src): - if neighbor == dst: - continue - w1 = self.get_edge_data(neighbor, src)['weight'] - w2 = None - if self.has_edge(neighbor, dst): - w2 = self.get_edge_data(neighbor, dst)['weight'] - if not weight_func: - if w2 is None: - w = w1 - else: - w = min(w1, w2) - else: - w = weight_func(self, src, dst, neighbor, - *extra_arguments, **extra_keywords) + neighbors = self.adj[src].copy() + neighbors.update(self.adj[dst]) + + try: + del neighbors[src] + except KeyError: + pass + try: + del neighbors[dst] + except KeyError: + pass + + for neighbor in neighbors: + w = weight_func(self, src, dst, neighbor, *extra_arguments, + **extra_keywords) self.add_edge(neighbor, dst, weight=w) self.node[dst]['labels'] += self.node[src]['labels'] @@ -55,8 +85,7 @@ class RAG(nx.Graph): def _add_edge_filter(values, g): - """Create and edge between the first and the remaining - values in an array. + """Create edge in `g` between first element of `values` and the rest. Add an edge between first element in `values` and all other elements of `values` in the graph `g`. `values[0]` @@ -86,24 +115,24 @@ def _add_edge_filter(values, g): def rag_meancolor(image, labels, connectivity=2): """Compute the Region Adjacency Graph using mean colors. - Given an image and its segmentation, this method constructs the + Given an image and its initial segmentation, this method constructs the corresponsing Region Adjacency Graph (RAG). Each node in the RAG - represents a contiguous set pixels within `image` with the same - label in `labels`. The weight between two adjacent regions is the - difference int their mean color. + represents a set pixels within `image` with the same + label in `labels`. The weight between two adjacent regions is the + difference in their mean color. Parameters ---------- - image : ndarray + image : ndarray, shape(M, N, [..., P,] 3) Input image. - labels : ndarray - The array with labels. This should have one dimention less than + labels : ndarray, shape(M, N, [..., P,]) + The labelled image. This should have one dimension less than `image`. If `image` has dimensions `(M, N, 3)` `labels` should have dimensions `(M, N)`. - connectivity : float, optional + connectivity : int, optional Pixels with a squared distance less than `connectivity` from each other - are considered adjacent. It can range from 1 to `labels.ndim`. It's - behaviour is the same as `connectivity` parameter in + are considered adjacent. It can range from 1 to `labels.ndim`. Its + behavior is the same as `connectivity` parameter in `scipy.ndimage.filters.generate_binary_structure`. Returns @@ -136,12 +165,16 @@ def rag_meancolor(image, labels, connectivity=2): fp[0, ...] = 0 fp = fp.swapaxes(0, d) - # For example + # For example # if labels.ndim = 2 and connectivity = 1 - # fp = [[0,0,0],[0,1,1],[0,1,0]] + # fp = [[0,0,0], + # [0,1,1], + # [0,1,0]] # # if labels.ndim = 2 and connectivity = 2 - # fp = [[0,0,0],[0,1,1],[0,1,1]] + # fp = [[0,0,0], + # [0,1,1], + # [0,1,1]] filters.generic_filter( labels, diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index 9f7c3ba8..4e58ff3a 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -3,49 +3,40 @@ from skimage import graph import random -def _max_edge(g, src, dst, neighbor): - try: - w1 = g.edge[src][neighbor]['weight'] - except KeyError: - w1 = None - - try: - w2 = g.edge[dst][neighbor]['weight'] - except KeyError: - w2 = None - - if w1 is None: - return w2 - elif w2 is None: - return w1 - else: - return max(w1, w2) +def max_edge(g, src, dst, n): + w1 = g[n].get(src, {'weight': -np.inf})['weight'] + w2 = g[n].get(dst, {'weight': -np.inf})['weight'] + return max(w1, w2) def test_rag_merge(): g = graph.rag.RAG() - for i in range(10): - g.add_edge(i, (i + 1) % 10, {'weight': i * 10}) - g.node[i]['labels'] = [i] - - for i in range(4): - x = random.choice(g.nodes()) - y = random.choice(g.nodes()) - while x == y: - y = random.choice(g.nodes()) - g.merge_nodes(x, y) for i in range(5): - x = random.choice(g.nodes()) - y = random.choice(g.nodes()) - while x == y: - y = random.choice(g.nodes()) - g.merge_nodes(x, y, _max_edge) + g.add_node(i, {'labels': [i]}) - idx = g.nodes()[0] - assert sorted(g.node[idx]['labels']) == list(range(10)) - assert g.edges() == [] + g.add_edge(0, 1, {'weight': 10}) + g.add_edge(1, 2, {'weight': 20}) + g.add_edge(2, 3, {'weight': 30}) + g.add_edge(3, 0, {'weight': 40}) + g.add_edge(0, 2, {'weight': 50}) + g.add_edge(3, 4, {'weight': 60}) + gc = g.copy() + + g.merge_nodes(0, 2) + assert g.edge[1][2]['weight'] == 10 + assert g.edge[2][3]['weight'] == 30 + + gc.merge_nodes(0, 2, weight_func=max_edge) + assert gc.edge[1][2]['weight'] == 20 + assert gc.edge[2][3]['weight'] == 40 + + g.merge_nodes(1, 4) + g.merge_nodes(2, 3) + g.merge_nodes(3, 4) + assert sorted(g.node[4]['labels']) == range(5) + assert g.edges() == [] def test_threshold_cut(): From 1982a3246c9af702eafbcd1bdb43e84908fe8f6c Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Sat, 28 Jun 2014 01:32:55 +0530 Subject: [PATCH 45/59] Docstring changes. --- skimage/graph/rag.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index be138e1e..c7b5c66d 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -13,9 +13,9 @@ def min_weight(g, src, dst, n): Parameters ---------- g : RAG - The graph to consider. + The graph under consideration. src, dst : int - Typically the verices in `g` to be merged. + The verices in `g` to be merged. n : int A neighbor of `src` or `dst` or both @@ -59,7 +59,7 @@ class RAG(nx.Graph): extra_arguments : sequence, optional The sequence of extra positional arguments passed to `weight_func`. - extra_keywords : + extra_keywords : dictionary, optional The dict of keyword arguments passed to the `weight_func`. """ @@ -85,9 +85,9 @@ class RAG(nx.Graph): def _add_edge_filter(values, g): - """Create edge in `g` between first element of `values` and the rest. + """Create edge in `g` between the first element of `values` and the rest. - Add an edge between first element in `values` and + Add an edge between the first element in `values` and all other elements of `values` in the graph `g`. `values[0]` is expected to be the central value of the footprint used. From e63ae9450ac7b236e5dcbf859d8fc7f8741bf304 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Sat, 28 Jun 2014 01:35:41 +0530 Subject: [PATCH 46/59] merge_nodes docstring change --- skimage/graph/rag.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index c7b5c66d..9150bfc4 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -41,7 +41,7 @@ class RAG(nx.Graph): def merge_nodes(self, src, dst, weight_func=min_weight, extra_arguments=[], extra_keywords={}): - """Merge two nodes. + """Merge node `src` into `dst`. The new combined node is adjacent to all the neighbors of `src` and `dst`. `weight_func` is called to decide the weight of edges From 87465d91d71bb5ff8db7c010844d8fe3f8800656 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Sat, 28 Jun 2014 01:39:28 +0530 Subject: [PATCH 47/59] test_rag.py formatting --- skimage/graph/tests/test_rag.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index 4e58ff3a..af325215 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -1,6 +1,5 @@ import numpy as np from skimage import graph -import random def max_edge(g, src, dst, n): @@ -36,7 +35,8 @@ def test_rag_merge(): g.merge_nodes(2, 3) g.merge_nodes(3, 4) assert sorted(g.node[4]['labels']) == range(5) - assert g.edges() == [] + assert g.edges() == [] + def test_threshold_cut(): From f71ad51f57d262c973771c5709fe277af28dc8ed Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Sat, 28 Jun 2014 10:35:14 +0530 Subject: [PATCH 48/59] Got Py3 test to pass --- skimage/graph/tests/test_rag.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index af325215..8179b92f 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -34,7 +34,7 @@ def test_rag_merge(): g.merge_nodes(1, 4) g.merge_nodes(2, 3) g.merge_nodes(3, 4) - assert sorted(g.node[4]['labels']) == range(5) + assert sorted(g.node[4]['labels']) == list(range(5)) assert g.edges() == [] From dd67b3fce7eacdc8f97cb7dfa9c7fd51a2b00214 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Sat, 28 Jun 2014 11:06:30 +0530 Subject: [PATCH 49/59] Changed max_edge in example/plot_rag.py --- doc/examples/plot_rag.py | 24 ++++++------------------ skimage/graph/rag.py | 2 +- skimage/graph/tests/test_rag.py | 4 ++++ 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/doc/examples/plot_rag.py b/doc/examples/plot_rag.py index d0ed3089..203f9454 100644 --- a/doc/examples/plot_rag.py +++ b/doc/examples/plot_rag.py @@ -9,32 +9,20 @@ weight of all the edges incident on it can be updated by a user defined function `weight_func`. The default behaviour is to use the smaller edge weight incase of a conflict. -THe example below also shows how to use a custom function to take the larger +The example below also shows how to use a custom function to take the larger weight instead. """ from skimage.graph import rag import networkx as nx from matplotlib import pyplot as plt +import numpy as np -def max_edge(g, src, dst, neighbor): - try: - w1 = g.edge[src][neighbor]['weight'] - except KeyError: - w1 = None - - try: - w2 = g.edge[dst][neighbor]['weight'] - except KeyError: - w2 = None - - if w1 is None: - return w2 - elif w2 is None: - return w1 - else: - return max(w1, w2) +def max_edge(g, src, dst, n): + w1 = g[n].get(src, {'weight': -np.inf})['weight'] + w2 = g[n].get(dst, {'weight': -np.inf})['weight'] + return max(w1, w2) def display(g, title): diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 9150bfc4..69eed104 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -17,7 +17,7 @@ def min_weight(g, src, dst, n): src, dst : int The verices in `g` to be merged. n : int - A neighbor of `src` or `dst` or both + A neighbor of `src` or `dst` or both. Returns ------- diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index 8179b92f..37c31887 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -23,10 +23,14 @@ def test_rag_merge(): gc = g.copy() + # We merge nodes and ensure that the minimum weight is chosen + # when there is a conflict. g.merge_nodes(0, 2) assert g.edge[1][2]['weight'] == 10 assert g.edge[2][3]['weight'] == 30 + # We specify `max_edge` as `weight_func` as ensure that maximum + # weight is chosen in case on conflict gc.merge_nodes(0, 2, weight_func=max_edge) assert gc.edge[1][2]['weight'] == 20 assert gc.edge[2][3]['weight'] == 40 From 6abf194dd668dc295f4f9652b5e256d5560f9633 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Sat, 28 Jun 2014 21:02:25 +0530 Subject: [PATCH 50/59] Use sets instead of dictionaries in merge_nodes --- skimage/graph/rag.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 69eed104..39bd0a3e 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -63,17 +63,8 @@ class RAG(nx.Graph): The dict of keyword arguments passed to the `weight_func`. """ - neighbors = self.adj[src].copy() - neighbors.update(self.adj[dst]) - - try: - del neighbors[src] - except KeyError: - pass - try: - del neighbors[dst] - except KeyError: - pass + neighbors = (set(self.neighbors(src)) & set( + self.neighbors(dst))) - set([src, dst]) for neighbor in neighbors: w = weight_func(self, src, dst, neighbor, *extra_arguments, From 486f935db8f8f6e424524905826fb3874cc48a58 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Wed, 2 Jul 2014 00:19:11 +0530 Subject: [PATCH 51/59] Rename methods and edit docstrings --- ...ag_meancolor.py => plot_rag_mean_color.py} | 6 +- skimage/graph/__init__.py | 8 +-- skimage/graph/graph_cut.py | 9 ++- skimage/graph/rag.py | 67 ++++++++++--------- skimage/graph/tests/test_rag.py | 4 +- 5 files changed, 50 insertions(+), 44 deletions(-) rename doc/examples/{plot_rag_meancolor.py => plot_rag_mean_color.py} (77%) diff --git a/doc/examples/plot_rag_meancolor.py b/doc/examples/plot_rag_mean_color.py similarity index 77% rename from doc/examples/plot_rag_meancolor.py rename to doc/examples/plot_rag_mean_color.py index 11aca77c..7a1d24b9 100644 --- a/doc/examples/plot_rag_meancolor.py +++ b/doc/examples/plot_rag_mean_color.py @@ -3,7 +3,7 @@ RAG Thresholding ================ -This examples constructs a Region Adjacency Graph (RAG) and merges regions +This example constructs a Region Adjacency Graph (RAG) and merges regions which are similar in color. We construct a RAG and define edges as the difference in mean color. We then join regions with similar mean color. @@ -18,8 +18,8 @@ img = data.coffee() labels1 = segmentation.slic(img, compactness=30, n_segments=400) out1 = color.label2rgb(labels1, img, kind='avg') -g = graph.rag_meancolor(img, labels1) -labels2 = graph.threshold_cut(labels1, g, 30) +g = graph.rag_mean_color(img, labels1) +labels2 = graph.cut_threshold(labels1, g, 30) out2 = color.label2rgb(labels2, img, kind='avg') plt.figure() diff --git a/skimage/graph/__init__.py b/skimage/graph/__init__.py index 90da2088..ade8326a 100644 --- a/skimage/graph/__init__.py +++ b/skimage/graph/__init__.py @@ -1,7 +1,7 @@ from .spath import shortest_path from .mcp import MCP, MCP_Geometric, MCP_Connect, MCP_Flexible, route_through_array -from .rag import rag_meancolor -from .graph_cut import threshold_cut +from .rag import rag_mean_color +from .graph_cut import cut_threshold __all__ = ['shortest_path', 'MCP', @@ -9,5 +9,5 @@ __all__ = ['shortest_path', 'MCP_Connect', 'MCP_Flexible', 'route_through_array', - 'rag_meancolor', - 'threshold_cut'] + 'rag_mean_color', + 'cut_threshold'] diff --git a/skimage/graph/graph_cut.py b/skimage/graph/graph_cut.py index 165091b1..a870ff9e 100644 --- a/skimage/graph/graph_cut.py +++ b/skimage/graph/graph_cut.py @@ -2,7 +2,7 @@ import networkx as nx import numpy as np -def threshold_cut(labels, rag, thresh): +def cut_threshold(labels, rag, thresh): """Combine regions seperated by weight less than threshold. Given an image's labels and its RAG, output new labels by @@ -16,8 +16,8 @@ def threshold_cut(labels, rag, thresh): rag : RAG The region adjacency graph. thresh : float - The threshold, regions with edge weights less than this - are combined. + The threshold. Regions connected by edges with smaller weights are + combined. Returns ------- @@ -46,6 +46,9 @@ def threshold_cut(labels, rag, thresh): comps = nx.connected_components(rag) + # We construct an array which can map old labels to the new ones. + # All the labels within a connected component are assigned to a single + # label in the output. map_array = np.arange(labels.max() + 1, dtype=labels.dtype) for i, nodes in enumerate(comps): for node in nodes: diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 39bd0a3e..e20f7c5a 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -4,18 +4,18 @@ from scipy.ndimage import filters from scipy import ndimage as nd -def min_weight(g, src, dst, n): +def min_weight(graph, src, dst, n): """Callback to handle merging nodes by choosing minimum weight. Returns either the weight between (`src`, `n`) or (`dst`, `n`) - in `g` or the minumum of the two when both exist. + in `graph` or the minumum of the two when both exist. Parameters ---------- - g : RAG + graph : RAG The graph under consideration. src, dst : int - The verices in `g` to be merged. + The verices in `graph` to be merged. n : int A neighbor of `src` or `dst` or both. @@ -28,8 +28,8 @@ def min_weight(g, src, dst, n): """ # cover the cases where n only has edge to either `src` or `dst` - w1 = g[n].get(src, {'weight': np.inf})['weight'] - w2 = g[n].get(dst, {'weight': np.inf})['weight'] + w1 = graph[n].get(src, {'weight': np.inf})['weight'] + w2 = graph[n].get(dst, {'weight': np.inf})['weight'] return min(w1, w2) @@ -50,7 +50,7 @@ class RAG(nx.Graph): Parameters ---------- src, dst : int - Nodes to be merged. The resulting node will have ID `dst`. + Nodes to be merged. weight_func : callable, optional Function to decide edge weight of edges incident on the new node. For each neighbor `n` for `src and `dst`, `weight_func` will be @@ -63,8 +63,9 @@ class RAG(nx.Graph): The dict of keyword arguments passed to the `weight_func`. """ - neighbors = (set(self.neighbors(src)) & set( - self.neighbors(dst))) - set([src, dst]) + src_nbrs = set(self.neighbors(src)) + dst_nbrs = set(self.neighbors(dst)) + neighbors = (src_nbrs & dst_nbrs) - set([src, dst]) for neighbor in neighbors: w = weight_func(self, src, dst, neighbor, *extra_arguments, @@ -75,7 +76,7 @@ class RAG(nx.Graph): self.remove_node(src) -def _add_edge_filter(values, g): +def _add_edge_filter(values, graph): """Create edge in `g` between the first element of `values` and the rest. Add an edge between the first element in `values` and @@ -86,31 +87,32 @@ def _add_edge_filter(values, g): ---------- values : array The array to process. - g : RAG + graph : RAG The graph to add edges in. Returns ------- 0 : int - Always returns 0. + Always returns 0. The return value is required so that `generic_fitler` + can put it in the output array. """ values = values.astype(int) current = values[0] for value in values[1:]: - g.add_edge(current, value) + graph.add_edge(current, value) return 0 -def rag_meancolor(image, labels, connectivity=2): +def rag_mean_color(image, labels, connectivity=2): """Compute the Region Adjacency Graph using mean colors. Given an image and its initial segmentation, this method constructs the corresponsing Region Adjacency Graph (RAG). Each node in the RAG - represents a set pixels within `image` with the same - label in `labels`. The weight between two adjacent regions is the - difference in their mean color. + represents a set of pixels within `image` with the same label in `labels`. + The weight between two adjacent regions is the difference in their mean + color. Parameters ---------- @@ -145,7 +147,7 @@ def rag_meancolor(image, labels, connectivity=2): http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.11.5274 """ - g = RAG() + graph = RAG() # The footprint is constructed in such a way that the first # element in the array being passed to _add_edge_filter is @@ -173,24 +175,25 @@ def rag_meancolor(image, labels, connectivity=2): footprint=fp, mode='nearest', output=np.zeros(labels.shape, dtype=np.uint8), - extra_arguments=(g,)) + extra_arguments=(graph,)) - for n in g: - g.node[n].update({'labels': [n], - 'pixel count': 0, - 'total color': np.array([0, 0, 0], dtype=np.double)}) + for n in graph: + graph.node[n].update({'labels': [n], + 'pixel count': 0, + 'total color': np.array([0, 0, 0], + dtype=np.double)}) for index in np.ndindex(labels.shape): current = labels[index] - g.node[current]['pixel count'] += 1 - g.node[current]['total color'] += image[index] + graph.node[current]['pixel count'] += 1 + graph.node[current]['total color'] += image[index] - for n in g: - g.node[n]['mean color'] = (g.node[n]['total color'] / - g.node[n]['pixel count']) + for n in graph: + graph.node[n]['mean color'] = (graph.node[n]['total color'] / + graph.node[n]['pixel count']) - for x, y in g.edges_iter(): - diff = g.node[x]['mean color'] - g.node[y]['mean color'] - g[x][y]['weight'] = np.linalg.norm(diff) + for x, y in graph.edges_iter(): + diff = graph.node[x]['mean color'] - graph.node[y]['mean color'] + graph[x][y]['weight'] = np.linalg.norm(diff) - return g + return graph diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index 37c31887..7b4551f4 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -56,8 +56,8 @@ def test_threshold_cut(): labels[50:, :50] = 2 labels[50:, 50:] = 3 - rag = graph.rag_meancolor(img, labels) - new_labels = graph.threshold_cut(labels, rag, 10) + rag = graph.rag_mean_color(img, labels) + new_labels = graph.cut_threshold(labels, rag, 10) # Two labels assert new_labels.max() == 1 From 99a45baca823400fcda777e644069ee797df397b Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Wed, 2 Jul 2014 00:21:47 +0530 Subject: [PATCH 52/59] Changes to plot_rag.py --- doc/examples/plot_rag.py | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/doc/examples/plot_rag.py b/doc/examples/plot_rag.py index 203f9454..f46d86af 100644 --- a/doc/examples/plot_rag.py +++ b/doc/examples/plot_rag.py @@ -3,13 +3,14 @@ Region Adjacency Graphs ======================= -This example demonstrates the use of `merge_nodes` function of a Region -Adjacency Graph (RAG). When a new node is formed by merging two nodes, the edge -weight of all the edges incident on it can be updated by a user defined -function `weight_func`. +This example demonstrates the use of the `merge_nodes` function of a Region +Adjacency Graph (RAG).The `RAG` class represents a undirected weighted graph +which inherits from `networx.graph` class. When a new node is formed by merging +two nodes, the edge weight of all the edges incident on the resulting node can +be updated by a user defined function `weight_func`. -The default behaviour is to use the smaller edge weight incase of a conflict. -The example below also shows how to use a custom function to take the larger +The default behaviour is to use the smaller edge weight in case of a conflict. +The example below also shows how to use a custom function to select the larger weight instead. """ @@ -20,12 +21,37 @@ import numpy as np def max_edge(g, src, dst, n): + """Callback to handle merging nodes by choosing maximum weight. + + Returns either the weight between (`src`, `n`) or (`dst`, `n`) + in `g` or the maximum of the two when both exist. + + Parameters + ---------- + g : RAG + The graph under consideration. + src, dst : int + The verices in `g` to be merged. + n : int + A neighbor of `src` or `dst` or both. + + Returns + ------- + weight : float + The weight between (`src`, `n`) or (`dst`, `n`) in `g` or the + maximum of the two when both exist. + + """ + w1 = g[n].get(src, {'weight': -np.inf})['weight'] w2 = g[n].get(dst, {'weight': -np.inf})['weight'] return max(w1, w2) def display(g, title): + """Displays a graph with the given title. + + """ pos = nx.circular_layout(g) plt.figure() plt.title(title) From 6003ab2c7dd14361084676f3e0d7cd6d2ed13b34 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Wed, 2 Jul 2014 00:31:01 +0530 Subject: [PATCH 53/59] Typos --- doc/examples/plot_rag.py | 2 +- skimage/graph/rag.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/examples/plot_rag.py b/doc/examples/plot_rag.py index f46d86af..9dd3ca76 100644 --- a/doc/examples/plot_rag.py +++ b/doc/examples/plot_rag.py @@ -5,7 +5,7 @@ Region Adjacency Graphs This example demonstrates the use of the `merge_nodes` function of a Region Adjacency Graph (RAG).The `RAG` class represents a undirected weighted graph -which inherits from `networx.graph` class. When a new node is formed by merging +which inherits from `networkx.graph` class. When a new node is formed by merging two nodes, the edge weight of all the edges incident on the resulting node can be updated by a user defined function `weight_func`. diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index e20f7c5a..7aa65261 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -22,7 +22,7 @@ def min_weight(graph, src, dst, n): Returns ------- weight : float - The weight between (`src`, `n`) or (`dst`, `n`) in `g` or the + The weight between (`src`, `n`) or (`dst`, `n`) in `graph` or the minumum of the two when both exist. """ From c1cf8e63472769e01efe033ec1f74ddcc8187669 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Wed, 2 Jul 2014 23:13:17 +0530 Subject: [PATCH 54/59] Got doctest to pass and docstring changes --- doc/examples/plot_rag.py | 8 ++++---- skimage/graph/rag.py | 11 +++++++---- skimage/graph/tests/test_rag.py | 5 +++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/doc/examples/plot_rag.py b/doc/examples/plot_rag.py index 9dd3ca76..c3192ca2 100644 --- a/doc/examples/plot_rag.py +++ b/doc/examples/plot_rag.py @@ -4,10 +4,10 @@ Region Adjacency Graphs ======================= This example demonstrates the use of the `merge_nodes` function of a Region -Adjacency Graph (RAG).The `RAG` class represents a undirected weighted graph -which inherits from `networkx.graph` class. When a new node is formed by merging -two nodes, the edge weight of all the edges incident on the resulting node can -be updated by a user defined function `weight_func`. +Adjacency Graph (RAG). The `RAG` class represents a undirected weighted graph +which inherits from `networkx.graph` class. When a new node is formed by +merging two nodes, the edge weight of all the edges incident on the resulting +node can be updated by a user defined function `weight_func`. The default behaviour is to use the smaller edge weight in case of a conflict. The example below also shows how to use a custom function to select the larger diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 7aa65261..807e8cd3 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -28,8 +28,9 @@ def min_weight(graph, src, dst, n): """ # cover the cases where n only has edge to either `src` or `dst` - w1 = graph[n].get(src, {'weight': np.inf})['weight'] - w2 = graph[n].get(dst, {'weight': np.inf})['weight'] + default = {'weight': np.inf} + w1 = graph[n].get(src, default)['weight'] + w2 = graph[n].get(dst, default)['weight'] return min(w1, w2) @@ -55,7 +56,9 @@ class RAG(nx.Graph): Function to decide edge weight of edges incident on the new node. For each neighbor `n` for `src and `dst`, `weight_func` will be called as follows: `weight_func(src, dst, n, *extra_arguments, - **extra_keywords)` + **extra_keywords)`. `src`, `dst` and `n` are IDs of vertices in a + .. py:class:: RAG object which is in turn a subclass of + `networkx.Graph`. extra_arguments : sequence, optional The sequence of extra positional arguments passed to `weight_func`. @@ -138,7 +141,7 @@ def rag_mean_color(image, labels, connectivity=2): >>> from skimage import data, graph, segmentation >>> img = data.lena() >>> labels = segmentation.slic(img) - >>> rag = graph.rag_meancolor(img, labels) + >>> rag = graph.rag_mean_color(img, labels) References ---------- diff --git a/skimage/graph/tests/test_rag.py b/skimage/graph/tests/test_rag.py index 7b4551f4..af7481eb 100644 --- a/skimage/graph/tests/test_rag.py +++ b/skimage/graph/tests/test_rag.py @@ -3,8 +3,9 @@ from skimage import graph def max_edge(g, src, dst, n): - w1 = g[n].get(src, {'weight': -np.inf})['weight'] - w2 = g[n].get(dst, {'weight': -np.inf})['weight'] + default = {'weight': -np.inf} + w1 = g[n].get(src, default)['weight'] + w2 = g[n].get(dst, default)['weight'] return max(w1, w2) From e558854deccd91e047edbd3e483df468f41ed940 Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Wed, 2 Jul 2014 23:28:14 +0530 Subject: [PATCH 55/59] docstring change --- skimage/graph/rag.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 807e8cd3..17c8cab8 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -56,8 +56,8 @@ class RAG(nx.Graph): Function to decide edge weight of edges incident on the new node. For each neighbor `n` for `src and `dst`, `weight_func` will be called as follows: `weight_func(src, dst, n, *extra_arguments, - **extra_keywords)`. `src`, `dst` and `n` are IDs of vertices in a - .. py:class:: RAG object which is in turn a subclass of + **extra_keywords)`. `src`, `dst` and `n` are IDs of vertices in the + RAG object which is in turn a subclass of `networkx.Graph`. extra_arguments : sequence, optional The sequence of extra positional arguments passed to From a4bf278c5b811acea34fcdabae1bbb5dbe49c4ce Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Thu, 3 Jul 2014 00:26:22 +0530 Subject: [PATCH 56/59] Doctest Passing --- skimage/graph/graph_cut.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skimage/graph/graph_cut.py b/skimage/graph/graph_cut.py index a870ff9e..91d64aec 100644 --- a/skimage/graph/graph_cut.py +++ b/skimage/graph/graph_cut.py @@ -29,8 +29,8 @@ def cut_threshold(labels, rag, thresh): >>> from skimage import data, graph, segmentation >>> img = data.lena() >>> labels = segmentation.slic(img) - >>> rag = graph.rag_meancolor(img, labels) - >>> new_labels = graph.threshold_cut(labels, rag, 10) + >>> rag = graph.rag_mean_color(img, labels) + >>> new_labels = graph.cut_threshold(labels, rag, 10) References ---------- From fb706d12d575499e5886965f3cfd9f94d74c2e0d Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Thu, 3 Jul 2014 01:55:09 +0530 Subject: [PATCH 57/59] made RAG public and hyperlinked networkx.Graph documentation --- skimage/graph/__init__.py | 5 +++-- skimage/graph/rag.py | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/skimage/graph/__init__.py b/skimage/graph/__init__.py index ade8326a..68c1206c 100644 --- a/skimage/graph/__init__.py +++ b/skimage/graph/__init__.py @@ -1,6 +1,6 @@ from .spath import shortest_path from .mcp import MCP, MCP_Geometric, MCP_Connect, MCP_Flexible, route_through_array -from .rag import rag_mean_color +from .rag import rag_mean_color, RAG from .graph_cut import cut_threshold __all__ = ['shortest_path', @@ -10,4 +10,5 @@ __all__ = ['shortest_path', 'MCP_Flexible', 'route_through_array', 'rag_mean_color', - 'cut_threshold'] + 'cut_threshold', + 'RAG'] diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index 17c8cab8..aacba2ba 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -37,7 +37,8 @@ def min_weight(graph, src, dst, n): class RAG(nx.Graph): """ - The Region Adjacency Graph (RAG) of an image. + The Region Adjacency Graph (RAG) of an image, subclasses + `networx.Graph `_ """ def merge_nodes(self, src, dst, weight_func=min_weight, extra_arguments=[], From 351e7697331548cf6a19ef1ed8a512a95424517c Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Thu, 3 Jul 2014 09:54:34 +0530 Subject: [PATCH 58/59] Docstring change --- doc/examples/plot_rag.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/examples/plot_rag.py b/doc/examples/plot_rag.py index c3192ca2..b26a266d 100644 --- a/doc/examples/plot_rag.py +++ b/doc/examples/plot_rag.py @@ -49,9 +49,7 @@ def max_edge(g, src, dst, n): def display(g, title): - """Displays a graph with the given title. - - """ + """Displays a graph with the given title.""" pos = nx.circular_layout(g) plt.figure() plt.title(title) From df1d61e4618ab8ffb2a2a2d8567d8be3bc069bbd Mon Sep 17 00:00:00 2001 From: Vighnesh Birodkar Date: Thu, 3 Jul 2014 09:55:17 +0530 Subject: [PATCH 59/59] Spelling correction. --- skimage/graph/rag.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/graph/rag.py b/skimage/graph/rag.py index aacba2ba..84721736 100644 --- a/skimage/graph/rag.py +++ b/skimage/graph/rag.py @@ -97,7 +97,7 @@ def _add_edge_filter(values, graph): Returns ------- 0 : int - Always returns 0. The return value is required so that `generic_fitler` + Always returns 0. The return value is required so that `generic_filter` can put it in the output array. """