-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Seeds segmentation #1557
base: main
Are you sure you want to change the base?
Seeds segmentation #1557
Conversation
Thanks for your contribution, @Britefury! This looks really interesting. Our Travis continuous integration build is having trouble because it uses Bento. The new Cython file needs to be added to the I'll do a full review once the CI builds are happy. |
Whew. That took a while to get right! :) |
skimage/segmentation/_seeds.pyx
Outdated
self.w = metrics.w | ||
self.block_h = metrics.block_h * 2 | ||
self.block_w = metrics.block_w * 2 | ||
self.n_blocks_y = metrics.n_blocks_y // 2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These need to be updated to use r/c instead of y/x. See our coordinate conventions guide. (This is a new standard, which is why you might see some xyz in the code still. But we aim to transition to r/c completely.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
@Britefury thanks for submitting this! I hadn't heard of SEEDS and it looks to me like a great algorithm, worthy of inclusion in scikit-image. That's the good news. The bad news is that I think the implementation will need a lot of refinement before getting merged. Functions like A lot of the code can be simplified using scipy and numpy functions. In fact, from what I've seen, the implementation can be made n-dimensional and the code simplified, to boot. For example, instead of your 2D histogram downsampling function, you can use import numpy as np
# 2D histogram for 9 x 16 image, 3 bins
h = np.random.rand(9, 16, 3)
hs = h
for ax in range(hs.ndim - 1):
hs = np.add.reduceat(hs, np.arange(0, hs.shape[ax] - 1, 2), axis=ax)
|
Also, we tend to prefer a functional approaches here... The We're definitely willing to iterate with you on this! I don't want to discourage you! But it's going to take a few tries to get right, I think. |
PEP8 fixes. _relabel_check* functions renamed to _relabel_will_disconnect*. Improved docstring of _relabel_check.
@jni I benchmarked As for Admittedly, these functions that I have just benchmarked may not be on the critical path. As for the |
What's the overall runtime for a 256x256 input image?
|
We also need to know how they scale. 256, 512, and 1024 square benchmarks for both would be ideal. |
@JDWarner Have found a compromise: it seems that applying Some quick tests show that all 3 approaches (original hand-rolled, |
This feature looks cool. What's the status of this PR guys? |
Hi @scikit-image/core, |
@alexandrejaguar if we can make it ND I'm all for it! =) Thank you for all your work on picking up dropped PRs, it's wonderful to see! |
I think this ND requirements really need to be discussed. |
You are right. I am firm in my assessment, though, but could be overruled... Assuming we get governance #3585 through soon! =\ Please see recent commits in #3544 for work I'm doing getting our transforms to support 3D/nD data. If we aim to be "maximally" nD compliant, which I think we do (as nD is important to a growing proportion of our users), then merging before code is nD amounts to taking on technical debt, of which we already have too much imho. Part of this can be fixed with labeling function names as If we had users banging on the door asking for SEEDS in skimage, I'd be inclined to be more flexible, but 2D SEEDS is already available in OpenCV. What can we bring to the table? As someone who teaches git and open source contribution using GitHub on a regular basis, I very much sympathise with the “all contributions are good, let's have more of them!” mindset, but for a project like scikit-image, it needs to be balanced with maintenance cost. We should push to get contributions in if they meet a certain level of utility. imho, nD SEEDS would meet that threshold, while 2D SEEDS is borderline. |
Gah. Sorry @jni, didn't see this when I sent out the email on the smiling list, should we move the discussion to an issue on GitHub? |
The smiling list! We should rename it that. =P I think this is worth discussing in both places, as they reach different audiences. Your point about the API is a very good one. |
cdef int[:,:] up_labels_2d = np.zeros((metrics.h, metrics.w), dtype=np.int32) | ||
cdef int c, r, i, j, block_w, block_h | ||
|
||
for r in range(metrics.n_blocks_r): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you release the GIL here?
cdef int[:,:,:] hist_2d = np.zeros((metrics.n_blocks_r, metrics.n_blocks_c, | ||
hist_size), dtype=np.int32) | ||
cdef int c, r, i, j, block_h, block_w, n | ||
for r in range(metrics.n_blocks_r): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can ou release the GIL here?
cdef int c, r, i | ||
cdef int rem_r = hist_2d.shape[0] & 1 | ||
cdef int rem_c = hist_2d.shape[1] & 1 | ||
for r in range(h2): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you release the GIL here?
cdef double l0n = 0.0, l1n = 0.0, bn = 0.0, l0int=0.0, l1int=0.0; | ||
cdef int i | ||
|
||
if label_0 != label_1: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you release the GIL here?
|
||
@cython.boundscheck(False) | ||
cdef bint _relabel_will_disconnect(int a0, int a1, int b0, int b1, | ||
int c0, int c1): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be declared nogil
|
||
@cython.boundscheck(False) | ||
cdef bint relabel_will_disconnect_above(int[:,:] labels_2d, int r, int c, | ||
int h, int w): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are these internal function? if so, these little C helper routines should be declared nogil
|
||
|
||
@cython.boundscheck(False) | ||
cdef bint relabel_will_disconnect_above(int[:,:] labels_2d, int r, int c, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should lablels_2d
be declared contiguous? int [:, ::1] labels_2d
????
cdef int refine_it, r, c | ||
|
||
# For each refinement iteration | ||
for refine_it in range(refine_iters): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be nogil
cdef int refine_it, r, c | ||
|
||
# For each refinement iteration | ||
for refine_it in range(refine_iters): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nogil?
Proceedings of the European Conference on Computer Vision, | ||
pages 13-26, 2012. | ||
""" | ||
assert n_levels >= 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These assert statements should be replaced by real if
statements that raising meaningful error messages
seed_h = max(int(block_finest_h_f+0.5), 1) | ||
|
||
# Get an index image; determine what to do. | ||
if len(input_2d.shape) == 3 and input_2d.shape[2] == 3: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've been working against this kind of "magic". Not too sure what to do in this case, but I'm just flagging it for now. We have been going with the multichannel
keyword argument asking users to explicitely label their images.
iter=50) | ||
index_2d = index_1d.reshape(input_2d.shape[:2]) | ||
elif len(input_2d.shape) == 2: | ||
if input_2d.dtype == float or input_2d.dtype == np.float32: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can check issubtype
assert_equal(labels[:16, 16:], 2) | ||
assert_equal(labels[16:, 16:], 4) | ||
|
||
if __name__ == '__main__': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is no longer necessary. Pytest will just find the test above.
|
||
|
||
@test_parallel() | ||
def test_color_2d(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You take in so many different parameters, and check for all of the. You should really test many more keyword argument and "bad input" cases.
Especially since you take in and special case many different types of dtypes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't really dwelve too much into the code, but at first glance:
- Try to release the GIL. Not sure if it is always possible.
- If you are special casing dtypes, then you should test for all the dtypes you consider.
I've knocked together an implementation of the SEEDS algorithm - or perhaps - an attempt at one. It produces colour based segmentations much like SLIC, except that it does not show the regular grid structure that is seen in the literature.
Much of my reference was based on David Stutz's implementation and to a lesser extent an implementation contributed to OpenCV. I hope my implementation is correct; I apologise if it isn't. If it is - with any luck - it can be used as a starting point for something better.