Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Normalized Cut on RAGs (WIP) #1080

Merged
merged 36 commits into from Aug 15, 2014

Conversation

@vighneshbirodkar
Copy link
Contributor

commented Jul 22, 2014

I will upload the test case real soon, till then I would like to invite comments/suggestions on the code.

All of the below results were computed with the same default values.

Results

Images from data

camera_cut
coffee_cut
coin_cut

Custom Images

Input

baby

Output

baby_cut

Input

fruit

Output

fruit_cut

Input

car

Output

car_cut

try:
m = w.shape[0]
vals, vectors = linalg.eigsh(d - w, M=d, which='SM',
k=min(100, m - 2))

This comment has been minimized.

Copy link
@vighneshbirodkar

vighneshbirodkar Jul 22, 2014

Author Contributor

@jni , @stefanv , @ahojnnes
Can you suggest what the best thing to do here would be ? k=100 was just something I arrived at by trial and error.

@@ -56,3 +61,134 @@ def cut_threshold(labels, rag, thresh):
map_array[label] = i

return map_array[labels]


def cut_n(labels, rag, thresh=0.001, num_cuts=10):

This comment has been minimized.

Copy link
@jni

jni Jul 23, 2014

Contributor

Avoid functions with side effects, in this case, modifying the RAG in-place. If you want to do that, it should be a method of the RAG. I can't remember though, did we follow this policy for the previous PR?

This comment has been minimized.

Copy link
@jni

jni Jul 23, 2014

Contributor

I also don't like cut_n as a name. I suggest we either rename this to ncut and cut_threshold to threshold_cut, or, we rename this cut_normalized.

This comment has been minimized.

Copy link
@vighneshbirodkar

vighneshbirodkar Jul 23, 2014

Author Contributor

In the previous PR, the RAG wasn't modified once created, I will rewrite this part to avoid it.

This comment has been minimized.

Copy link
@vighneshbirodkar

vighneshbirodkar Jul 23, 2014

Author Contributor

I think we should go with cut_normalzed then, to be consistent with the rest of the library.

mcut = np.inf
threshold = None
# Perform evenly spaced n-cuts and determine the optimal one.
for t in np.linspace(0, 1, num_cuts, endpoint=False):

This comment has been minimized.

Copy link
@jni

jni Jul 23, 2014

Contributor

I don't understand what's happening here.

This comment has been minimized.

Copy link
@vighneshbirodkar

vighneshbirodkar Jul 23, 2014

Author Contributor

The eigenvector ev minimizes the cut, but it is real valued, instead of being composed of 0s and 1s. The original paper, suggests 3 strategies to make it into a boolean vector.

  1. Threshold above and below 0.
  2. Threshold above and below the median.
  3. Threshold above and below a threshold t such that the cut is minimized.

The 3rd strategy gives the best results.

This comment has been minimized.

Copy link
@jni

jni Jul 23, 2014

Contributor

Actually, you know what would be cool? Write down for each part of the algorithm the page/line/eqn number in the paper that it is implementing. That would make this codebase extremely easy to maintain going forward!

This comment has been minimized.

Copy link
@vighneshbirodkar

vighneshbirodkar Jul 23, 2014

Author Contributor

Ok. What do you think about the results ?

This comment has been minimized.

Copy link
@jni

jni Jul 23, 2014

Contributor

They look decent! I'm not sure how they compare to other methods. (Coins is particularly cool for a couple of function calls!) We are not trying to break segmentation accuracy records, but to get good, reliable implementations of reference algorithms. Come to think of it, it would also be valuable to see if you can find a reference ncut implementation to which you could feed the same superpixels, and compare the results.

Another thing I would like to see is the k-means based ncut where you specify the number of segments and it specifies the cut in a single step, rather than recursing down. I'm not sure whether that would fit in this PR or a different one — I leave it up to you. As to the interface, one option would be to provide an n_segments kwarg that is set to None by default (recursive 2-way), but that becomes k-means ncut when an integer is given.

@vighneshbirodkar

This comment has been minimized.

Copy link
Contributor Author

commented Jul 23, 2014

@jni @stefanv
The failure on Travis is caused by scipy v0.9. Any suggestions ?
I was thinking we could install from pip ?

@jni

This comment has been minimized.

Copy link
Contributor

commented Jul 23, 2014

@vighneshbirodkar well first, I would add scipy to requirements.txt... I don't understand why it's not there!

Secondly, this might just be extra motivation to start using conda for our Travis builds, which is something we've been considering for a long time. @stefanv shall we push that to the front of the queue?

My understanding is that building scipy with pip takes way too long and would slow down our Travis builds dramatically.

@vighneshbirodkar

This comment has been minimized.

Copy link
Contributor Author

commented Jul 24, 2014

@stefanv @jni
Should I work on a Pull Request to use conda instead of apt-get ?
https://gist.github.com/dan-blanchard/7045057
This link explains how to setup miniconda

@jni

This comment has been minimized.

Copy link
Contributor

commented Jul 24, 2014

@vighneshbirodkar that would be really valuable. If you think you can do so cleanly and quickly, go ahead!

@vighneshbirodkar

This comment has been minimized.

Copy link
Contributor Author

commented Jul 27, 2014

@jni
The code will work after merging #1082

from scipy import sparse


def DW_matrix(graph):

This comment has been minimized.

Copy link
@jni

jni Jul 28, 2014

Contributor

It's two matrices returned, so rename this to DW_matrices



def DW_matrix(graph):
"""Returns the diagonal and weight matrix of a graph.

This comment has been minimized.

Copy link
@jni

jni Jul 28, 2014

Contributor

matrices

Returns
-------
D : csc_matrix
The diagonal matrix of the graph. `D[i,i]` is the sum of weights of all

This comment has been minimized.

Copy link
@jni

jni Jul 28, 2014

Contributor

D[i, i] (PEP8 space after comma)

The diagonal matrix of the graph. `D[i,i]` is the sum of weights of all
edges incident on `i`. All other enteries are `0`.
W : csc_matrix
The weight matrix of the graph. `W[i,j]` is the weight of the edge

This comment has been minimized.

Copy link
@jni

jni Jul 28, 2014

Contributor

W[i, j]

The weight matrix of the graph. `W[i,j]` is the weight of the edge
joining `i` to `j`.
"""
#Cause sparse.eigsh prefers CSC format

This comment has been minimized.

Copy link
@jni

jni Jul 28, 2014

Contributor
# export nx graph to `sparse.eigsh`-preferred CSC format
"""
#Cause sparse.eigsh prefers CSC format
W = nx.to_scipy_sparse_matrix(graph, format='csc')
entries = W.sum(0)

This comment has been minimized.

Copy link
@jni

jni Jul 28, 2014

Contributor

axis=0 is more readable

"""
mask = np.array(mask)
mask_list = [np.logical_xor(mask[i], mask) for i in range(mask.shape[0])]
mask_array = np.array(mask_list)

This comment has been minimized.

Copy link
@jni

jni Jul 28, 2014

Contributor

Can you explain this computation? You get a 2D matrix of XORs (right?), but I don't understand why.

This comment has been minimized.

Copy link
@vighneshbirodkar

vighneshbirodkar Jul 28, 2014

Author Contributor

We need weights of the crossing edges, i.e. edges with one node in A and the other in B.
mask[x] is True if x is in A and mask[x] is False if x is in B
Therefore, we need weights w[i, j] such that mask[i] is True and mask[j] is False ( edit : or vice versa )
That is, the w[i, j] where mask[i] XOR mask [j] is True.
Hence the matrix of XORs

I will put that in a comment.

This comment has been minimized.

Copy link
@jni

jni Jul 28, 2014

Contributor

Ok, thanks, that makes it clearer. However, this should be limited to places where w[i, j] is not 0, right? (I see below that it's only used for a sum.) Do you think you could find a solution that doesn't involve instantiating an n x n dense matrix? In the worst case, this should be doable in O(len(w.data)) with a fast Cython call. In a better case, you might be able to quickly instantiate a selector on w.data based on mask_array, w.indices, and w.indptr...

This comment has been minimized.

Copy link
@vighneshbirodkar

vighneshbirodkar Jul 28, 2014

Author Contributor

I didn't realize I was instantiating a dense matrix there, I'll make the change.

@jni

This comment has been minimized.

Copy link
Contributor

commented Aug 5, 2014

@vighneshbirodkar You might need to rebase...

@@ -11,4 +11,5 @@
'route_through_array',
'rag_mean_color',
'cut_threshold',
'cut_normalized',

This comment has been minimized.

Copy link
@jni

jni Aug 5, 2014

Contributor

I think "ncut" is common enough in the literature that we actually want an alias for it: ncut = cut_normalized. You can add this to the source file and update this list. (And above.)

The weight matrix of the graph. `W[i, j]` is the weight of the edge
joining `i` to `j`.
"""
#Cause sparse.eigsh prefers CSC format

This comment has been minimized.

Copy link
@jni

jni Aug 5, 2014

Contributor

#Cause -> # sparse.eighsh is most efficient with CSC-formatted input

Parameters
----------
mask : ndarray
The mask for the nodes in the graph. Nodes corrsesponding to a `True`

This comment has been minimized.

Copy link
@jni

jni Aug 5, 2014

Contributor

Actually, I find mask confusing. Call this cut?

This comment has been minimized.

Copy link
@jni

jni Aug 5, 2014

Contributor

oh and fix "corresponding"

mask = np.array(mask)
cut = _ncut_cy.cut_cost(mask, W)

# Cause D has elements only along diagonal

This comment has been minimized.

Copy link
@jni

jni Aug 5, 2014

Contributor

Don't use such informal abbreviations in documentation.

"D has elements only along the diagonal, one per node, so we can directly index the data attribute with cut"

Returns
-------
cost : float
The cost of performing the N-cut.

This comment has been minimized.

Copy link
@jni

jni Aug 5, 2014

Contributor

Can you add a "References" section and point to the page, line, and equation number in the paper?

cdef Py_ssize_t i2 = 0
cdef Py_ssize_t i = 0

while i < array.shape[0]:

This comment has been minimized.

Copy link
@jni

jni Aug 5, 2014

Contributor

for loop

x = array[i]
if x < min1:
min2 = min1
i2 = i1

This comment has been minimized.

Copy link
@jni

jni Aug 5, 2014

Contributor

min_idx1 is more readable. Update the name of the return variable in the documentation, also.

return i2


def cut_cost(mask, W):

This comment has been minimized.

Copy link
@jni

jni Aug 5, 2014

Contributor

Add docstring, rename mask to cut

@vighneshbirodkar

This comment has been minimized.

Copy link
Contributor Author

commented Aug 9, 2014

Input

This image is featured in the paper
baseball

Memory - 90 MB

Line #    Mem usage    Increment   Line Contents
================================================
     5   55.496 MiB    0.000 MiB   @profile
     6                             def test():
     7                             
     8   57.141 MiB    1.645 MiB       img = io.imread('/home/vighnesh/Desktop/images/baseball.jpg')
     9   83.863 MiB   26.723 MiB       labels = segmentation.slic(img, compactness=30, n_segments=400)
    10   84.598 MiB    0.734 MiB       rag = graph.rag_mean_color(img, labels, mode='similarity')
    11   87.871 MiB    3.273 MiB       new_labels = graph.cut_normalized(labels, rag)
    12   87.879 MiB    0.008 MiB       out = color.label2rgb(new_labels, img, kind='avg')
    13   90.008 MiB    2.129 MiB       io.imsave('out.png',out)

Time - 20s

When not profiling code runs in ~20s

Total time: 31.7757 s

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     5                                           @profile
     6                                           def test():
     7                                           
     8         1        12581  12581.0      0.0      img = io.imread('/home/vighnesh/Desktop/images/baseball.jpg')
     9         1       725820 725820.0      2.3      labels = segmentation.slic(img, compactness=30, n_segments=400)
    10         1     13391961 13391961.0     42.1      rag = graph.rag_mean_color(img, labels, mode='similarity')
    11         1     17320646 17320646.0     54.5      new_labels = graph.cut_normalized(labels, rag)
    12         1       291413 291413.0      0.9      out = color.label2rgb(new_labels, img, kind='avg')
    13         1        33292  33292.0      0.1      io.imsave('out.png',out)

Output

out

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]``.

This comment has been minimized.

Copy link
@jni

jni Aug 10, 2014

Contributor

missing '

@@ -44,6 +51,9 @@ def cut_threshold(labels, rag, thresh):
"""
# Because deleting edges while iterating through them produces an error.

This comment has been minimized.

Copy link
@jni

jni Aug 10, 2014

Contributor

This comment should be immediately above the to_remove assignment.

"""
# `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.

This comment has been minimized.

Copy link
@jni

jni Aug 10, 2014

Contributor

sparse

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

This comment has been minimized.

Copy link
@jni

jni Aug 10, 2014

Contributor

You appear to be repeating this assignment operation len(d['labels']) times... =)



def _label_all(rag, attr_name):
"""Assign a uique integer to the given attribute in the RAG.

This comment has been minimized.

Copy link
@jni

jni Aug 10, 2014

Contributor

unique


if m > 2:
d2 = d.copy()
# Since d is diagonal, we can directly operate on it's data

This comment has been minimized.

Copy link
@jni

jni Aug 10, 2014

Contributor

it's -> its

'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 the Euclidian distance in

This comment has been minimized.

Copy link
@jni

jni Aug 10, 2014

Contributor

Euclidean

@jni

This comment has been minimized.

Copy link
Contributor

commented Aug 10, 2014

@vighneshbirodkar Thank you this is very close! Your refactor of _ncut_relabel reads very well now! I have added a few minor comments, after which I think it is ready. @stefanv do you want to have one last look?

I would also like to know whether you can vary the threshold to ncut to get segments similar to those shown on Fig4 in the paper, with your SLIC superpixels. (Reading the paper in more detail, I see that it would be extremely difficult to reproduce the image exactly with the current framework — maybe something interesting to do post-GSOC. =)

@vighneshbirodkar

This comment has been minimized.

Copy link
Contributor Author

commented Aug 10, 2014

@jni
If we define a RAG with grayscale floating point images, similar thresholds would work.

----------
.. [1] Shi, J.; Malik, J., "Normalized cuts and image segmentation",
Pattern Analysis and Machine Intelligence,
IEEE Transactions on , vol.22, no.8, pp.888,905, August 2000

This comment has been minimized.

Copy link
@stefanv

stefanv Aug 10, 2014

Member

Still not right

@coveralls

This comment has been minimized.

Copy link

commented Aug 10, 2014

Coverage Status

Coverage decreased (-0.04%) when pulling 4a231cf on vighneshbirodkar:ncut into 00456f9 on scikit-image:master.

@vighneshbirodkar

This comment has been minimized.

Copy link
Contributor Author

commented Aug 10, 2014

@stefanv The last commit should fix it.

@vighneshbirodkar

This comment has been minimized.

Copy link
Contributor Author

commented Aug 10, 2014

The coverage on the latest commit

Name                                              Stmts   Miss Branch BrMiss  Cover   Missing
---------------------------------------------------------------------------------------------
skimage                                              65     31      6      6    48%   70-71, 77-88, 92-109, 138-142, 145, 148, 151, 154, 159, 162, 165, 168
skimage._shared                                       0      0      0      0   100%   
skimage._shared._warnings                            21      0      8      1    97%   
skimage._shared.utils                                45      4     12      6    82%   58-59, 65, 133
skimage._shared.version_requirements                 53     26     20     14    45%   22, 25-32, 66, 70-71, 79, 105-117, 139-141
skimage.color                                         4      0      0      0   100%   
skimage.color.adapt_rgb                              24      0      2      0   100%   
skimage.color.colorconv                             242      1     26      1    99%   1293
skimage.color.colorlabel                             73      2     30      2    96%   165, 172
skimage.color.delta_e                               101      0      8      2    98%   
skimage.color.rgb_colors                            146      0      0      0   100%   
skimage.data                                         32      2      0      0    94%   145, 223
skimage.draw                                          4      0      0      0   100%   
skimage.draw.draw                                    22      0      2      0   100%   
skimage.draw.draw3d                                  35      2     12      2    91%   45, 90
skimage.exposure                                      3      0      0      0   100%   
skimage.exposure._adapthist                         136      2     34      2    98%   108, 144
skimage.exposure.exposure                            89      6     28      2    93%   255-257, 260-262
skimage.feature                                      14      0      0      0   100%   
skimage.feature._daisy                               97      0     49      1    99%   
skimage.feature._hog                                 55      0     22      0   100%   
skimage.feature.blob                                 73      0     20      0   100%   
skimage.feature.brief                                38      0      6      1    98%   
skimage.feature.censure                              99      0     28      2    98%   
skimage.feature.corner                              169      0     22      1    99%   
skimage.feature.match                                21      1     10      1    94%   52
skimage.feature.orb                                 125      1     20      1    99%   143
skimage.feature.peak                                 46      0     22      0   100%   
skimage.feature.template                             59      0     22      2    98%   
skimage.feature.texture                              68      0     20      1    99%   
skimage.feature.util                                 57      0     20      2    97%   
skimage.filter                                       14      0      0      0   100%   
skimage.filter._canny                                94      2     12      2    96%   156, 159
skimage.filter._gabor                                27      0      4      0   100%   
skimage.filter._gaussian                             20      0      8      1    96%   
skimage.filter._rank_order                           14      0      0      0   100%   
skimage.filter.edges                                 61      0      2      0   100%   
skimage.filter.lpi_filter                            68      1     12      1    98%   241
skimage.filter.rank                                   4      0      0      0   100%   
skimage.filter.rank._percentile                      26      5      0      0    81%   121, 195, 236, 315, 394
skimage.filter.rank.bilateral                        15      0      0      0   100%   
skimage.filter.rank.generic                          72      0     14      0   100%   
skimage.filter.thresholding                          54      1     14      2    96%   77
skimage.graph                                         6      0      0      0   100%   
skimage.graph._ncut                                  23      3      0      0    87%   3-5
skimage.graph.graph_cut                              66      2     22      0    98%   3-4
skimage.graph.mcp                                     9      0      2      0   100%   
skimage.graph.rag                                    60      3     18      0    96%   8-10
skimage.graph.spath                                  29      0      8      3    92%   
skimage.io                                           30      0      4      0   100%   
skimage.io._image_stack                               9      0      2      0   100%   
skimage.io._io                                       42      3      6      1    92%   50, 177, 200
skimage.io._plugins                                   0      0      0      0   100%   
skimage.io._plugins.freeimage_plugin                420     25     92     24    90%   82, 85-88, 94, 208, 220, 396, 401, 436, 446, 456, 536, 592, 603, 608, 625, 634, 662, 665-666, 673, 693, 696-698
skimage.io._plugins.matplotlib_plugin                 9      4      0      0    56%   5-7, 14
skimage.io._plugins.null_plugin                      10      0      0      0   100%   
skimage.io._plugins.pil_plugin                       59      6     24      3    89%   7-8, 95, 119, 136, 140
skimage.io._plugins.util                            168     69     37     21    56%   12-13, 18, 21, 38, 47, 67, 78-80, 133, 178, 183-185, 188, 194-220, 224-227, 263-272, 275, 278, 281-282, 285, 300-303, 318-321, 336-338, 341-343, 346-348, 366-368, 390-392, 412-413, 433-434
skimage.io.collection                               145     18     39      5    88%   121-122, 152-160, 189, 201, 310, 353, 380, 403, 415
skimage.io.manage_plugins                           135     10     62      7    91%   81, 124, 188, 205-206, 257, 304-306, 330-331
skimage.io.sift                                      22      2      6      2    86%   40, 56
skimage.io.util                                      22      0      4      0   100%   
skimage.measure                                      11      0      0      0   100%   
skimage.measure._find_contours                       70      6     25      3    91%   167-174
skimage.measure._label                                4      0      0      0   100%   
skimage.measure._marching_cubes                      41      1      8      1    96%   267
skimage.measure._polygon                             61      0     16      0   100%   
skimage.measure._regionprops                        188      6     26      4    95%   97, 308, 313, 319, 326-327
skimage.measure._structural_similarity               42      0     12      0   100%   
skimage.measure.block                                16      1      8      1    92%   56
skimage.measure.fit                                 188      1     38      5    97%   664
skimage.measure.profile                              23      0      2      0   100%   
skimage.morphology                                   12      0      0      0   100%   
skimage.morphology._skeletonize                      86      0     24      0   100%   
skimage.morphology.binary                            37      1      8      1    96%   91
skimage.morphology.convex_hull                       38      2      6      0    95%   53-54
skimage.morphology.grey                              49      0      8      0   100%   
skimage.morphology.greyreconstruct                   55      2     20      3    93%   128-129
skimage.morphology.misc                              40      1     16      1    96%   114
skimage.morphology.selem                             61      1      2      0    98%   146
skimage.morphology.watershed                        118     14     51     14    83%   135, 138, 164, 167, 171, 173, 176, 215, 226-227, 249, 302, 311, 332
skimage.novice                                        2      0      0      0   100%   
skimage.novice._novice                              229     24     54      9    88%   250-251, 366, 375, 378, 382-383, 394-395, 399, 403, 408, 412, 417, 421, 426, 430, 435, 439, 444, 453, 457, 480, 485
skimage.restoration                                   5      0      0      0   100%   
skimage.restoration._denoise                         91      0     22      2    98%   
skimage.restoration.deconvolution                    80      0     36      4    97%   
skimage.restoration.uft                              54      0     20      2    97%   
skimage.restoration.unwrap                           38      1     27      2    95%   103
skimage.scripts                                       0      0      0      0   100%   
skimage.scripts.skivi                                 9      8      2      2     9%   5-14
skimage.segmentation                                  8      0      0      0   100%   
skimage.segmentation._clear_border                   19      1      2      1    90%   46
skimage.segmentation._felzenszwalb                   21      2      8      2    86%   51, 58
skimage.segmentation._join                           30      1      8      0    97%   52
skimage.segmentation.boundaries                      20      0      4      2    92%   
skimage.segmentation.random_walker_segmentation     195     20     70     12    88%   28-29, 32-33, 37, 340-345, 507-516
skimage.segmentation.slic_superpixels                59      1     26      2    96%   109
skimage.transform                                     9      0      0      0   100%   
skimage.transform._geometric                        313      0    102      1    99%   
skimage.transform._warps                             75      0      8      1    99%   
skimage.transform.finite_radon_transform             30      2     12      2    90%   56, 121
skimage.transform.hough_transform                    52      0      8      1    98%   
skimage.transform.integral                           17      0      4      0   100%   
skimage.transform.pyramids                           81      0     20      4    96%   
skimage.transform.radon_transform                   162     12     72     12    90%   59, 175, 186, 220-223, 390, 393, 395, 401, 407, 412
skimage.util                                          7      0      0      0   100%   
skimage.util._regular_grid                           22      0      8      1    97%   
skimage.util.arraypad                               386     50    318     61    84%   64, 172, 206, 243, 298, 354, 358, 362-363, 405, 409, 413-414, 419, 461, 465, 513, 517, 522, 570, 574, 578-579, 622, 626, 630-631, 636, 680, 684, 688-689, 731, 735, 739-740, 745, 797, 882, 898, 919, 963, 1314, 1328, 1443-1450
skimage.util.dtype                                  150     14     68      9    89%   125, 135-136, 158-161, 171, 212-218
skimage.util.montage                                 23      0      8      0   100%   
skimage.util.noise                                   53      1     32      2    96%   121
skimage.util.shape                                   45      0     24      0   100%   
skimage.util.unique                                   9      0      2      0   100%   
skimage.version                                       1      0      0      0   100%   
skimage.viewer                                        8      1      2      1    80%   9
skimage.viewer.canvastools                            3      0      0      0   100%   
skimage.viewer.canvastools.base                      86      4     16      2    94%   5, 93, 162, 165
skimage.viewer.canvastools.linetool                  98      8     28      9    87%   5-6, 62, 86, 98, 104, 106, 169
skimage.viewer.canvastools.painttool                109     13     18      8    83%   8, 79, 103-104, 127-128, 133, 139, 144-146, 151-152
skimage.viewer.canvastools.recttool                 118      9     30     10    87%   3-4, 64, 134, 136-137, 147, 169, 182
skimage.viewer.plugins                                9      0      0      0   100%   
skimage.viewer.plugins.base                          98      6     18      6    90%   16, 99-100, 152-153, 250
skimage.viewer.plugins.canny                         18      0      0      0   100%   
skimage.viewer.plugins.color_histogram               51      1      0      0    98%   84
skimage.viewer.plugins.crop                          23      0      0      0   100%   
skimage.viewer.plugins.labelplugin                   39      2      0      0    95%   51, 59
skimage.viewer.plugins.lineprofile                   86      0     24      2    98%   
skimage.viewer.plugins.measure                       31      0      0      0   100%   
skimage.viewer.plugins.overlayplugin                 55      2     11      2    94%   104-105
skimage.viewer.plugins.plotplugin                    30      0      2      1    97%   
skimage.viewer.qt                                    16      3      4      2    75%   14-18
skimage.viewer.qt.QtCore                             16     10      4      2    40%   4, 12-22
skimage.viewer.qt.QtGui                               8      4      4      2    50%   4, 9-11
skimage.viewer.utils                                  1      0      0      0   100%   
skimage.viewer.utils.core                           100      5     20      7    90%   18-20, 50, 64
skimage.viewer.utils.dialogs                         22      4      8      3    77%   32-35
skimage.viewer.viewers                                1      0      0      0   100%   
skimage.viewer.viewers.core                         190     20     40     17    84%   10, 48-50, 117-121, 179, 181, 199, 201, 212, 237, 275, 279-281, 289-290, 373-375
skimage.viewer.widgets                                2      0      0      0   100%   
skimage.viewer.widgets.core                         130     10     22      4    91%   41-42, 119-120, 135-136, 150, 177-179
skimage.viewer.widgets.history                       71      3      6      3    92%   86, 88, 92
---------------------------------------------------------------------------------------------
TOTAL                                              8603    510   2333    370    92%   
----------------------------------------------------------------------
@jni

This comment has been minimized.

Copy link
Contributor

commented Aug 12, 2014

@stefanv are you ok with me merging this? I think it's ready.

@vighneshbirodkar

This comment has been minimized.

Copy link
Contributor Author

commented Aug 13, 2014

@stefanv
Can you please have a look and tell me if there are any mistakes/improvements ?

@stefanv

This comment has been minimized.

Copy link
Member

commented Aug 13, 2014

Sorry for the delay--I promise to have a look tomorrow morning first thing.

Parameters
----------
a : array

This comment has been minimized.

Copy link
@stefanv

stefanv Aug 14, 2014

Member

parameter has different name in signature above?

Given an image's labels and its similarity RAG, recursively perform
a 2-way normalized cut on it. All nodes belonging to a subgraph
which cannot be cut further, are assigned a unique label in the

This comment has been minimized.

Copy link
@stefanv

stefanv Aug 14, 2014

Member

remove comma

This comment has been minimized.

Copy link
@stefanv

stefanv Aug 14, 2014

Member

which -> that, if you want to be pedantic

@stefanv

This comment has been minimized.

Copy link
Member

commented Aug 14, 2014

Fantastic work, guys!

@coveralls

This comment has been minimized.

Copy link

commented Aug 14, 2014

Coverage Status

Coverage decreased (-0.04%) when pulling afa345f on vighneshbirodkar:ncut into 00456f9 on scikit-image:master.

@coveralls

This comment has been minimized.

Copy link

commented Aug 14, 2014

Coverage Status

Coverage decreased (-0.04%) when pulling afa345f on vighneshbirodkar:ncut into 00456f9 on scikit-image:master.

jni added a commit that referenced this pull request Aug 15, 2014
Merge pull request #1080 from vighneshbirodkar/ncut
Add normalized cut (ncut) on RAGs

@jni jni merged commit a363802 into scikit-image:master Aug 15, 2014

1 check passed

continuous-integration/travis-ci The Travis CI build passed
Details
@jni

This comment has been minimized.

Copy link
Contributor

commented Aug 15, 2014

@vighneshbirodkar Thank you very much! An excellent contribution! =D

@stefanv I'll add these to the release notes soon. I didn't want to hold this up any longer since we are on a time crunch (pencils-down on Monday).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants
You can’t perform that action at this time.