Skip to content

Commit

Permalink
Merge pull request #37 from johnnychen94/moments
Browse files Browse the repository at this point in the history
Refactor Moments using the functor API
  • Loading branch information
zygmuntszpak authored Jul 26, 2019
2 parents c83ee71 + a993c98 commit a804365
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 28 deletions.
40 changes: 22 additions & 18 deletions src/moments.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
struct Moments <: AbstractImageBinarizationAlgorithm end


@doc raw"""
```
binarize(Moments(), img)
```
Moments <: AbstractImageBinarizationAlgorithm
Moments()
binarize([T,] img, f::Moments)
binarize!([out,] img, f::Moments)
The following rule determines the binarization threshold: if one assigns all
observations below the threshold to a value z₀ and all observations above the
Expand All @@ -13,7 +12,8 @@ must match the moments of this specially constructed bilevel histogram.
# Output
Returns the binarized image as an `Array{Gray{Bool},2}`.
Return the binarized image as an `Array{Gray{T}}` of size `size(img)`. If
`T` is not specified, it is inferred from `out` and `img`.
# Details
Expand Down Expand Up @@ -57,9 +57,9 @@ the four equations to obtain ``q_0`` and ``q_1``, and then chooses the threshold
The function argument is described in more detail below.
## `img`
## `img::AbstractArray`
An `AbstractArray` representing an image. The image is automatically converted
The image that needs to be binarized. The image is automatically converted
to `Gray` in order to construct the requisite graylevel histogram.
Expand All @@ -71,19 +71,23 @@ Binarize the "cameraman" image in the `TestImages` package.
using TestImages, ImageBinarization
img = testimage("cameraman")
img_binary = binarize(Moments(), img)
img_binary = binarize(img, Moments())
```
# Reference
[1] W.-H. Tsai, “Moment-preserving thresolding: A new approach,” Computer Vision, Graphics, and Image Processing, vol. 29, no. 3, pp. 377–393, Mar. 1985. [doi:10.1016/0734-189x(85)90133-1](https://doi.org/10.1016/0734-189x%2885%2990133-1)
"""
function binarize(algorithm::Moments, img::AbstractArray{T,2}) where T <: Colorant
img₀₁ = zeros(Gray{Bool}, axes(img))
edges, counts = build_histogram(img, 256)
t = find_threshold(HistogramThresholding.Moments(), counts[1:end], edges)
for i in CartesianIndices(img)
img₀₁[i] = img[i] < t ? 0 : 1
end
img₀₁
struct Moments <: AbstractImageBinarizationAlgorithm end

function (f::Moments)(out::GenericGrayImage, img::GenericGrayImage)
edges, counts = build_histogram(img, 256)
t = find_threshold(HistogramThresholding.Moments(), counts[1:end], edges)
for i in CartesianIndices(img)
out[i] = img[i] < t ? 0 : 1
end
out
end

(f::Moments)(out::GenericGrayImage, img::AbstractArray{<:Color3}) =
f(out, of_eltype(Gray, img))
Binary file added test/References/Moments_Color3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/References/Moments_Gray.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
64 changes: 55 additions & 9 deletions test/moments.jl
Original file line number Diff line number Diff line change
@@ -1,23 +1,69 @@
@testset "moments" begin
original_image = testimage("lena")
for T in (Gray{N0f8}, Gray{N0f16}, Gray{Float32}, Gray{Float64})
img = T.(original_image)
img₀₁ = binarize(Moments(), img)
@info "Test: Moments"

# Check original image is unchanged.
@test img == T.(testimage("lena"))
@testset "API" begin
img_gray = imresize(testimage("lena_gray_256"); ratio=0.25)
img = copy(img_gray)

# binarize
f = Moments()
binarized_img_1 = binarize(img, f)
@test img == img_gray # img unchanged
@test eltype(binarized_img_1) == Gray{N0f8}

binarized_img_2 = binarize(Gray{Bool}, img, f)
@test img == img_gray # img unchanged
@test eltype(binarized_img_2) == Gray{Bool}

binarized_img_3 = similar(img, Bool)
binarize!(binarized_img_3, img, f)
@test img == img_gray # img unchanged
@test eltype(binarized_img_3) == Bool

binarized_img_4 = copy(img_gray)
binarize!(binarized_img_4, f)
@test eltype(binarized_img_4) == Gray{N0f8}

@test binarized_img_1 == binarized_img_2
@test binarized_img_1 == binarized_img_3
@test binarized_img_1 == binarized_img_4
end

@testset "Types" begin
# Gray
img_gray = imresize(testimage("lena_gray_256"); ratio=0.25)
f = Moments()

type_list = generate_test_types([Float32, N0f8], [Gray])
for T in type_list
img = T.(img_gray)
@test_reference "References/Moments_Gray.png" Gray.(binarize(img, f))
end

# Color3
img_color = imresize(testimage("lena_color_256"); ratio=0.25)
f = Moments()

type_list = generate_test_types([Float32, N0f8], [RGB, Lab])
for T in type_list
img = T.(img_gray)
@test_reference "References/Moments_Color3.png" Gray.(binarize(img, f))
end
end

@testset "Numerical" begin
# Check that the image only has ones or zeros.
img = imresize(testimage("lena_gray_256"); ratio=0.25)
f = Moments()
img₀₁ = binarize(img, f)
non_zeros = findall(x -> x != 0.0 && x != 1.0, img₀₁)
@test length(non_zeros) == 0

# Check type of binarized image.
@test typeof(img₀₁) == Array{Gray{Bool},2}

# Check that ones and zeros have been assigned to the correct side of the threshold.
maxval, maxpos = findmax(Gray.(img))
@test img₀₁[maxpos] == 1
minval, minpos = findmin(Gray.(img))
@test img₀₁[minpos] == 0
end

end
2 changes: 1 addition & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ include("testutils.jl")
# include("intermodes.jl")
# include("minimum.jl")
# include("minimum_error.jl")
# include("moments.jl")
include("moments.jl")
# include("niblack.jl")
include("otsu.jl")
# include("polysegment.jl")
Expand Down

0 comments on commit a804365

Please sign in to comment.