Skip to content

deprecate otsu_threshold and yen_threshold#897

Closed
johnnychen94 wants to merge 2 commits intomasterfrom
jc/yen_otsu
Closed

deprecate otsu_threshold and yen_threshold#897
johnnychen94 wants to merge 2 commits intomasterfrom
jc/yen_otsu

Conversation

@johnnychen94
Copy link
Copy Markdown
Member

@johnnychen94 johnnychen94 commented Jun 21, 2020

Comment thread src/deprecations.jl
# delete in Images v1.0.0
@deprecate otsu_threshold(img, bins=256) begin
edges, counts = ImageContrastAdjustment.build_histogram(img, bins)
eltype(img)(HistogramThresholding.find_threshold(Otsu(), counts[1:end], edges))
Copy link
Copy Markdown
Member Author

@johnnychen94 johnnychen94 Jun 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This difference raises a decision to be made: should we make the result of find_threshold always be eltype(img) type?

I feel it would be relatively good to restrict it as raw numbers (the status quo of HistogramThresholding) since it would always be a scalar in practice; there's no need to display it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a step backwards in usability? Could we create a version of find_threshold that takes the image as an input?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In #841 we aim to introduce ImageBinarization to Images, which means a user will be able to pass an image, choose Otsu as the thresholding algorithm, and obtain the binary image as a result.

The HistogramThresholding does the actual thresholding selection, and operates at the level of histograms so that one can use these algorithms outside the context of image processing.

The find_threshold methods takes an AbstractArray which it interprets as a histogram. If we want to make it work at the level of an images, do we just add another method which dispatches if the eltype of the array is a subtype of Gray?

Copy link
Copy Markdown
Member

@timholy timholy Jun 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hadn't looked at the find_threshold implementation, don't all the implementations in https://github.com/zygmuntszpak/HistogramThresholding.jl require two one-dimensional arrays (the counts and edges arrays)? In which case, wouldn't passing a single array be unambiguous? If not, then we should consider keyword variant, e.g. find_threshold(Otsu(), image=img). It's better to avoid dispatching on eltype wherever possible, as it decreases the generality of the code. We're expunging some of that code in ImageCore now: JuliaImages/ImageCore.jl#131. (It's fine for dispatching to optimized implementations, but changing behavior based on eltype should be considered carefully.)

Let me be clear that I think the new implementations are huge improvements from the standpoint of code organization and design. My only concern is that they have a tendency to lean towards the reduce(+, a) and away from sum(a) territory, and we need to be aware that some users will view this as an increased cognitive load even though others will appreciate the generality. I am not sure how to solve it, and maybe I am just reacting to the visual appearance of a single function call being converted into something substantially larger.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the moment they all take an AbstractArray as input, so if I understood you correctly I just need to refactor those functions so that they take an AbstractVector as input instead. Then the images ecosystem can define an AbstractArray dispatch which builds the necessary histogram. The user can then just type find_threshold(img, Otsu()), for example.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of JuliaImages supports 1d images---these are sometimes useful for debugging and algorithm development. So giving different meaning to different array dimensionalities isn't ideal.

But I'm still confused:

julia> methods(HistogramThresholding.find_threshold)
# 10 methods for generic function "find_threshold":
[1] find_threshold(algorithm::Otsu, histogram::AbstractArray, edges::AbstractRange) in HistogramThresholding at /home/tim/.julia/packages/HistogramThresholding/2ZlJN/src/otsu.jl:93
[2] find_threshold(algorithm::MinimumError, histogram::AbstractArray{T,N} where N, edges::AbstractRange) where T<:Int64 in HistogramThresholding at /home/tim/.julia/packages/HistogramThresholding/2ZlJN/src/minimum_error.jl:112
[3] find_threshold(algorithm::MinimumError, histogram::AbstractArray, edges::AbstractRange) in HistogramThresholding at /home/tim/.julia/packages/HistogramThresholding/2ZlJN/src/minimum_error.jl:85
[4] find_threshold(algorithm::UnimodalRosin, histogram::AbstractArray, edges::AbstractRange) in HistogramThresholding at /home/tim/.julia/packages/HistogramThresholding/2ZlJN/src/unimodal.jl:71
[5] find_threshold(algorithm::Moments, histogram::AbstractArray, edges::AbstractRange) in HistogramThresholding at /home/tim/.julia/packages/HistogramThresholding/2ZlJN/src/moments.jl:90
[6] find_threshold(algorithm::MinimumIntermodes, histogram::AbstractArray, edges::AbstractRange; maxiter) in HistogramThresholding at /home/tim/.julia/packages/HistogramThresholding/2ZlJN/src/minimum.jl:63
[7] find_threshold(algorithm::Intermodes, histogram::AbstractArray, edges::AbstractRange) in HistogramThresholding at /home/tim/.julia/packages/HistogramThresholding/2ZlJN/src/intermodes.jl:63
[8] find_threshold(algorithm::Balanced, histogram::AbstractArray, edges::AbstractRange) in HistogramThresholding at /home/tim/.julia/packages/HistogramThresholding/2ZlJN/src/balancedthreshold.jl:87
[9] find_threshold(algorithm::Yen, histogram::AbstractArray, edges::AbstractRange) in HistogramThresholding at /home/tim/.julia/packages/HistogramThresholding/2ZlJN/src/yen.jl:85
[10] find_threshold(algorithm::Entropy, counts::AbstractArray, edges::AbstractRange) in HistogramThresholding at /home/tim/.julia/packages/HistogramThresholding/2ZlJN/src/entropy_thresholding.jl:91

Unless I'm just overlooking something, all 10 of these require edges. If you pass in the image, will you also pass in edges? Or I should say, I guess that will be an option? The interface I'm proposing is to support

find_threshold(Otsu(), img; nbins=256)

That only has one input array, which can safely be interpreted as the image.

Copy link
Copy Markdown
Member Author

@johnnychen94 johnnychen94 Jun 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this usage is inspired by MATLAB's otsuthresh?

% matlab
[counts,x] = imhist(I,16);
T = otsuthresh(counts);
BW = imbinarize(I,T);

I also think find_threshold(img, Otsu()) would be more convenient, though.

Comment thread test/algorithms.jl Outdated
@codecov
Copy link
Copy Markdown

codecov bot commented Jun 21, 2020

Codecov Report

Merging #897 into master will decrease coverage by 0.50%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #897      +/-   ##
==========================================
- Coverage   76.38%   75.88%   -0.51%     
==========================================
  Files           9        9              
  Lines         720      705      -15     
==========================================
- Hits          550      535      -15     
  Misses        170      170              
Impacted Files Coverage Δ
src/Images.jl 0.00% <ø> (ø)
src/algorithms.jl 77.77% <ø> (-1.11%) ⬇️
src/deprecations.jl 82.35% <ø> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 988cd87...07591e5. Read the comment docs.

@johnnychen94 johnnychen94 added this to the v1.0 milestone Jun 22, 2020
@timholy
Copy link
Copy Markdown
Member

timholy commented Jun 22, 2020

I approve of the goal here.

@timholy
Copy link
Copy Markdown
Member

timholy commented Jul 23, 2023

Closed by #1030.

@timholy timholy closed this Jul 23, 2023
@timholy timholy deleted the jc/yen_otsu branch July 23, 2023 19:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

deprecate yen_threshold and otsu_threshold?

3 participants