The Wayback Machine - https://web.archive.org/web/20201010215631/https://github.com/scikit-image/scikit-image/pull/5006
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

Refactoring: threshold methods with histogram parameters #5006

Draft
wants to merge 3 commits into
base: master
from

Conversation

@haesleinhuepf
Copy link

@haesleinhuepf haesleinhuepf commented Oct 4, 2020

added method threshold_otsu_from_histogram as shortcut in case the histogram is known in advance

Description

Hi all, hi @jni ,

this PR-draft refactors thresholding_otsu method so that one can call it also with a histogram instead of an image. I would like to use it in a GPU-accelerated image processing library where we can determine the histogram on the GPU, but lack threshold-method implementations.

I would wonder what you think about this implementation. If it makes sense, I would offer to implement the same startegy for other threshold methods.

Best,
Robert

Checklist

[x] Docstrings for all functions
[ ] Gallery example in ./doc/examples (new features only)
[ ] Benchmark in ./benchmarks, if your changes aren't covered by an existing benchmark
[ ] Unit tests
[ ] Clean style in the spirit of PEP8

For reviewers

  • Check that the PR title is short, concise, and will make sense 1 year
    later.
  • Check that new functions are imported in corresponding __init__.py.
  • Check that new features, API changes, and deprecations are mentioned in
    doc/release/release_dev.rst.
added method threshold_otsu_from_histogram as shortcut in case the histogram is known in advance
@emmanuelle
Copy link
Member

@emmanuelle emmanuelle commented Oct 4, 2020

Hi @haesleinhuepf thanks for starting this discussion! I'll let other devs chime in, but my gut feeling is that rather than adding one function to the API we could just add one keyword argument histogram (which would default to None) to the existing function. I see the interest of precomputing the histogram also for comparing different thresholding functions which require the histogram.

@sciunto you've worked extensively on thresholding functions what do you think of these additions?

@jni
Copy link
Contributor

@jni jni commented Oct 5, 2020

I think the same as @emmanuelle: let's add histogram=None to the functions that benefit from a pre-computed histogram. We could potentially then also make image=None, and make sure one of the two is provided, with preference given to the histogram.

@haesleinhuepf
Copy link
Author

@haesleinhuepf haesleinhuepf commented Oct 5, 2020

Hey @emmanuelle and @jni ,

at the beginning I thought so, too. But then I saw that we need the histogram and the bin_centers array. Otherwise, we can only return the bin_index and not the corresponding grey value. I didn't know how force the user to provide both together or both none. Assert statements came to my mind. Any better idea how to achieve this?

Thanks for the feedback! 😃

@jni
Copy link
Contributor

@jni jni commented Oct 5, 2020

A great point that I had overlooked! 😅

My preferred option given this would be to provide a tuple of counts, bin_centers, same as returned by exposure.histogram. Perhaps we also support a single array and then use the bin index (bin_centers = np.arange(len(counts))), which is convenient for uint16 and uint8 images.

@haesleinhuepf
Copy link
Author

@haesleinhuepf haesleinhuepf commented Oct 5, 2020

Perhaps we also support a single array and then use the bin index (bin_centers = np.arange(len(counts))), which is convenient for uint16 and uint8 images.

Just to make sure I understand correctly: That would mean the threshold_otsu method returns a conceptually different thing (histogram index versus grey value) depending on input parameters. If that's ok, I'm happy to implement it.

@sciunto
Copy link
Member

@sciunto sciunto commented Oct 5, 2020

I'm +1 with you @emmanuelle and this can be applied to several of our functions as well.

@jni
Copy link
Contributor

@jni jni commented Oct 5, 2020

a conceptually different thing

It's not, the point is that for integer-valued images they are one and the same thing! So it is a shortcut for users of those images. If someone decides to misuse the shortcut, that's on them! 😜

At any rate, you can implement the tuple input version first and later we can decide if we want to provide this shortcut. 😊

@pep8speaks
Copy link

@pep8speaks pep8speaks commented Oct 5, 2020

Hello @haesleinhuepf! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:

Line 292:80: E501 line too long (81 > 79 characters)

Comment last updated at 2020-10-05 15:03:51 UTC
instead of adding another method
@haesleinhuepf
Copy link
Author

@haesleinhuepf haesleinhuepf commented Oct 5, 2020

Alright @emmanuelle and @jni ,

I just implemented it like you suggested. The function header is now

def threshold_otsu(image=None, nbins=256, hist=None, bin_centers=None)

If prefers the hist over the image as @jni suggested and returns the bin index in case no bin_centers are given. The only thing I didn't manage is the tuple-thingy @jni suggested. I assume one needs to add some more brakets to the function defintion, but I'm not sure how this works with bin_centers being optional. You know, I just recently arrived in snake county. ;-)

Thanks again for your feedback. I appreciate it :-)

Let me know what you think!

Cheers,
Robert

@jni
Copy link
Contributor

@jni jni commented Oct 6, 2020

@haesleinhuepf I think you were expecting more magic than Python provides here. 😂 I merely meant that a single argument, histogram=, takes in as input a tuple of arrays, which you unpack inside the function:

def threshold_otsu(image=None, nbins=256, *, histogram=None):
    if histogram is not None:
        counts, bin_centers = histogram
    else:
        counts, bin_centers = exposure.histogram(image, nbins)

or

def threshold_otsu(image=None, nbins=256, *, histogram=None):
    if histogram is not None:
        if isinstance(histogram, (tuple, list)):
            counts, bin_centers = histogram
        else:
            counts = histogram
            bin_centers = np.arange(counts.size)
    else:
        counts, bin_centers = exposure.histogram(image, nbins)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

5 participants
You can’t perform that action at this time.