mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-14 11:18:06 +08:00
docstring changes and code movement
This commit is contained in:
@@ -74,7 +74,5 @@ def cut_cost(cut, W):
|
||||
row = indices[row_index]
|
||||
if cut_mask[row] != cut_mask[col]:
|
||||
cost += data[row_index]
|
||||
row_index += 1
|
||||
col += 1
|
||||
|
||||
return cost * 0.5
|
||||
|
||||
+55
-29
@@ -9,7 +9,7 @@ from . import _ncut_cy
|
||||
from scipy.sparse import linalg
|
||||
|
||||
|
||||
def cut_threshold(labels, rag, thresh):
|
||||
def cut_threshold(labels, rag, thresh, in_place=True):
|
||||
"""Combine regions seperated by weight less than threshold.
|
||||
|
||||
Given an image's labels and its RAG, output new labels by
|
||||
@@ -25,6 +25,10 @@ def cut_threshold(labels, rag, thresh):
|
||||
thresh : float
|
||||
The threshold. Regions connected by edges with smaller weights are
|
||||
combined.
|
||||
in_place : bool
|
||||
If set, modifies `rag` in place. The function will remove the edges
|
||||
with weights less that `thresh`. If set to `False` the function
|
||||
makes a copy of `rag` before proceeding.
|
||||
|
||||
Returns
|
||||
-------
|
||||
@@ -47,7 +51,9 @@ def cut_threshold(labels, rag, thresh):
|
||||
|
||||
"""
|
||||
# Because deleting edges while iterating through them produces an error.
|
||||
rag = rag.copy()
|
||||
if not in_place:
|
||||
rag = rag.copy()
|
||||
|
||||
to_remove = [(x, y) for x, y, d in rag.edges_iter(data=True)
|
||||
if d['weight'] >= thresh]
|
||||
rag.remove_edges_from(to_remove)
|
||||
@@ -66,7 +72,7 @@ def cut_threshold(labels, rag, thresh):
|
||||
return map_array[labels]
|
||||
|
||||
|
||||
def cut_normalized(labels, rag, thresh=0.001, num_cuts=10):
|
||||
def cut_normalized(labels, rag, thresh=0.001, num_cuts=10, in_place=True):
|
||||
"""Perform Normalized Graph cut on the Region Adjacency Graph.
|
||||
|
||||
Given an image's labels and its similarity RAG, recursively perform
|
||||
@@ -85,6 +91,9 @@ def cut_normalized(labels, rag, thresh=0.001, num_cuts=10):
|
||||
value of the N-cut exceeds `thresh`.
|
||||
num_cuts : int
|
||||
The number or N-cuts to perform before determining the optimal one.
|
||||
in_place : bool
|
||||
If set, modifies `rag` in place. For each node `n` the function will
|
||||
set a new attribute ``rag.node[n]['ncut label]``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
@@ -106,8 +115,15 @@ def cut_normalized(labels, rag, thresh=0.001, num_cuts=10):
|
||||
IEEE Transactions on , vol.22, no.8, pp.888,905, August 2000
|
||||
|
||||
"""
|
||||
map_array = np.arange(labels.max() + 1)
|
||||
_ncut_relabel(rag, thresh, num_cuts, map_array)
|
||||
if not in_place:
|
||||
rag = rag.copy()
|
||||
|
||||
_ncut_relabel(rag, thresh, num_cuts)
|
||||
|
||||
map_array = np.zeros(labels.max() + 1)
|
||||
# Mapping from old labels to new
|
||||
for n, d in rag.nodes_iter(data=True):
|
||||
map_array[d['labels']] = d['ncut label']
|
||||
|
||||
return map_array[labels]
|
||||
|
||||
@@ -128,6 +144,16 @@ def partition_by_cut(cut, rag):
|
||||
sub1, sub2 : RAG
|
||||
The two resulting subgraphs from the bi-partition.
|
||||
"""
|
||||
# `cut` is derived from `D` and `W` matrices, which also follow the
|
||||
# ordering returned by `rag.nodes()` because we use
|
||||
# nx.to_scipy_sparce_matrix.
|
||||
|
||||
# Example
|
||||
# rag.nodes() = [3, 7, 9, 13]
|
||||
# cut = [True, False, True, False]
|
||||
# nodes1 = [3, 9]
|
||||
# nodes2 = [7, 10]
|
||||
|
||||
nodes1 = [n for i, n in enumerate(rag.nodes()) if cut[i]]
|
||||
nodes2 = [n for i, n in enumerate(rag.nodes()) if not cut[i]]
|
||||
|
||||
@@ -153,9 +179,10 @@ def get_min_ncut(ev, d, w, num_cuts):
|
||||
|
||||
Returns
|
||||
-------
|
||||
threshold, mcut : float
|
||||
The threshold which produced the minimum ncut, and the value of the
|
||||
ncut itself.
|
||||
mask : array
|
||||
The array of booleans which denotes the bi-partition.
|
||||
mcut : float
|
||||
The value of the minimum ncut.
|
||||
"""
|
||||
mcut = np.inf
|
||||
|
||||
@@ -165,13 +192,21 @@ def get_min_ncut(ev, d, w, num_cuts):
|
||||
mask = ev > t
|
||||
cost = _ncut.ncut_cost(mask, d, w)
|
||||
if cost < mcut:
|
||||
min_mask = mask
|
||||
mcut = cost
|
||||
threshold = t
|
||||
|
||||
return threshold, mcut
|
||||
return min_mask, mcut
|
||||
|
||||
|
||||
def _ncut_relabel(rag, thresh, num_cuts, map_array):
|
||||
def _label_all(rag, attr_name):
|
||||
node = rag.nodes()[0]
|
||||
new_label = rag.node[node]['labels'][0]
|
||||
for n, d in rag.nodes_iter(data=True):
|
||||
for l in d['labels']:
|
||||
d[attr_name] = new_label
|
||||
|
||||
|
||||
def _ncut_relabel(rag, thresh, num_cuts):
|
||||
"""Perform Normalized Graph cut on the Region Adjacency Graph.
|
||||
|
||||
Recursively partition the graph into 2, until further subdivision
|
||||
@@ -195,46 +230,37 @@ def _ncut_relabel(rag, thresh, num_cuts, map_array):
|
||||
the function.
|
||||
"""
|
||||
d, w = _ncut.DW_matrices(rag)
|
||||
stop = False
|
||||
m = w.shape[0]
|
||||
|
||||
if m > 2:
|
||||
d2 = d.copy()
|
||||
# Since d is diagonal, we can directly operate on it's data
|
||||
# the inverse
|
||||
d2.data = 1.0 / d2.data
|
||||
# the square root
|
||||
d2.data = np.sqrt(d2.data)
|
||||
# the inverse of the square root
|
||||
d2.data = np.reciprocal(np.sqrt(d2.data, out=d2.data), out=d2.data)
|
||||
|
||||
# Refer Shi & Malik 2001, Equation 7, Page 891
|
||||
vals, vectors = linalg.eigsh(d2 * (d - w) * d2, which='SM',
|
||||
k=min(100, m - 2))
|
||||
else:
|
||||
stop = True
|
||||
|
||||
if not stop:
|
||||
# Pick second smalles eigenvector.
|
||||
# Pick second smallest eigenvector.
|
||||
# Refer Shi & Malik 2001, Section 3.2.3, Page 893
|
||||
vals, vectors = np.real(vals), np.real(vectors)
|
||||
index2 = _ncut_cy.argmin2(vals)
|
||||
ev = _ncut.normalize(vectors[:, index2])
|
||||
|
||||
threshold, mcut = get_min_ncut(ev, d, w, num_cuts)
|
||||
cut_mask, mcut = get_min_ncut(ev, d, w, num_cuts)
|
||||
if (mcut < thresh):
|
||||
cut_mask = ev > threshold
|
||||
# Sub divide and perform N-cut again
|
||||
# Refer Shi & Malik 2001, Section 3.2.5, Page 893
|
||||
sub1, sub2 = partition_by_cut(cut_mask, rag)
|
||||
|
||||
_ncut_relabel(sub1, thresh, num_cuts, map_array)
|
||||
_ncut_relabel(sub2, thresh, num_cuts, map_array)
|
||||
_ncut_relabel(sub1, thresh, num_cuts)
|
||||
_ncut_relabel(sub2, thresh, num_cuts)
|
||||
return
|
||||
|
||||
# The N-cut wasn't small enough, or could not be computed.
|
||||
# The remaining graph is a region.
|
||||
# Assign `ncut label` by picking any label from the existing nodes, since
|
||||
# `labels` are unique, `new_label` is also unique.
|
||||
node = rag.nodes()[0]
|
||||
new_label = rag.node[node]['labels'][0]
|
||||
for n, d in rag.nodes_iter(data=True):
|
||||
for l in d['labels']:
|
||||
map_array[l] = new_label
|
||||
|
||||
_label_all(rag, 'ncut label')
|
||||
|
||||
@@ -2,6 +2,7 @@ try:
|
||||
import networkx as nx
|
||||
except ImportError:
|
||||
msg = "Graph functions require networkx, which is not installed"
|
||||
|
||||
class nx:
|
||||
class Graph:
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -119,7 +120,7 @@ def _add_edge_filter(values, graph):
|
||||
return 0
|
||||
|
||||
|
||||
def rag_mean_color(image, labels, connectivity=2, mode='dissimilarity',
|
||||
def rag_mean_color(image, labels, connectivity=2, mode='distance',
|
||||
sigma=255.0):
|
||||
"""Compute the Region Adjacency Graph using mean colors.
|
||||
|
||||
@@ -142,15 +143,15 @@ def rag_mean_color(image, labels, connectivity=2, mode='dissimilarity',
|
||||
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`.
|
||||
mode : str['similarity' | 'dissimilarity']
|
||||
mode : {'distance', 'similarity'}, optional
|
||||
The strategy to assign edge weights.
|
||||
|
||||
'similarity' : The weight between two adjacent regions is the
|
||||
'distance' : The weight between two adjacent regions is the
|
||||
:math:`|c_1 - c_2|`, where :math:`c_1` and :math:`c_2` are the mean
|
||||
colors of the two regions. It represents how different two regions
|
||||
are.
|
||||
colors of the two regions. It represents the Euclidian distance in
|
||||
their average color.
|
||||
|
||||
'dissimilarity' : The weight between two adjacent is
|
||||
'similarity' : The weight between two adjacent is
|
||||
:math:`e^{-d^2/sigma}` where :math:`d=|c_1 - c_2|`, where
|
||||
:math:`c_1` and :math:`c_2` are the mean colors of the two regions.
|
||||
It represents how similar two regions are.
|
||||
@@ -229,9 +230,9 @@ def rag_mean_color(image, labels, connectivity=2, mode='dissimilarity',
|
||||
diff = np.linalg.norm(diff)
|
||||
if mode == 'similarity':
|
||||
d['weight'] = math.e ** (-(diff ** 2) / sigma)
|
||||
elif mode == 'dissimilarity':
|
||||
elif mode == 'distance':
|
||||
d['weight'] = diff
|
||||
else:
|
||||
raise ValueError("The mode '%s' is not recodnized" % mode)
|
||||
raise ValueError("The mode '%s' is not recognised" % mode)
|
||||
|
||||
return graph
|
||||
|
||||
Reference in New Issue
Block a user