Skip to content

Commit 9fc02d6

Browse files
committed
Fix and test clustering
This has one breaking change: while the docs advertise that "All the segmentation algorithms (except Fuzzy C-means) return a struct SegmentedImage," that's not been true for `kmeans`. This changes the output so that `kmeans` does return a `SegmentedImage`. This is a breaking change, because the types are not interchangeable. This became apparent when trying to add tests for `kmeans`, which have been lacking. Before releasing this, we may want to make a second breaking change: currently, ImageSegmentation provides a new meaning for `Matrix{Gray{T}}` than Clustering.jl provides for `Matrix{T}`. This breaks our abstraction that `Gray ≈ Number`. A way to fix that would be to have `ImageSegmentation.kmeans` be a different function from `Clustering.kmeans`, and obviously have the one in ImageSegmentation call the one in Clustering.
1 parent 55c1310 commit 9fc02d6

File tree

5 files changed

+32
-8
lines changed

5 files changed

+32
-8
lines changed

src/ImageSegmentation.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Base: show
44

55
using LinearAlgebra, Statistics
66
using DataStructures, StaticArrays, ImageCore, ImageFiltering, ImageMorphology, LightGraphs, SimpleWeightedGraphs, RegionTrees, Distances, StaticArrays, Clustering, MetaGraphs
7+
using ImageCore.MappedArrays: of_eltype
78
import Clustering: kmeans, fuzzy_cmeans
89

910
include("compat.jl")
@@ -41,7 +42,7 @@ export
4142
kmeans,
4243
fuzzy_cmeans,
4344
merge_segments,
44-
45+
4546
# types
4647
SegmentedImage,
4748
ImageEdge

src/clustering.jl

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
function img_to_data(img::AbstractArray{T,N}) where T<:Colorant where N
2-
AT = accum_type(T)
3-
aimg = AT.(img)
4-
pimg = parent(aimg)
5-
ch = channelview(pimg)
6-
data = reshape(ch, :, *(size(pimg)...))
2+
aimg = of_eltype(accum_type(T), img)
3+
ch = channelview(aimg)
4+
return reshape(ch, :, *(size(img)...))
75
end
86

97
kmeans(img::AbstractArray{T,N}, args...; kwargs...) where {T<:Colorant,N} =
10-
kmeans(img_to_data(img), args...; kwargs...)
8+
SegmentedImage(kmeans(img_to_data(img), args...; kwargs...), img)
119

1210
fuzzy_cmeans(img::AbstractArray{T,N}, args...; kwargs...) where {T<:Colorant,N} =
1311
fuzzy_cmeans(img_to_data(img), args...; kwargs...)

src/core.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ struct SegmentedImage{T<:AbstractArray,U<:Union{Colorant,Real}}
1414
segment_pixel_count::Dict{Int,Int}
1515
end
1616

17+
SegmentedImage(r::Clustering.KmeansResult, img) =
18+
SegmentedImage(reshape(r.assignments, axes(img)),
19+
collect(1:length(r.counts)),
20+
Dict(zip(1:length(r.counts), colorview(ImageCore.ColorTypes.base_colorant_type(eltype(img)), r.centers))),
21+
Dict(zip(1:length(r.counts), r.counts))
22+
)
23+
1724
"""
1825
edge = ImageEdge(index1, index2, weight)
1926

test/clustering.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
@testset "Clustering" begin
2+
# Test the example in the docs
3+
path = download("https://github.com/JuliaImages/juliaimages.github.io/raw/source/docs/src/pkgs/segmentation/assets/flower.jpg")
4+
img = load(path)
5+
r = fuzzy_cmeans(img, 3, 2)
6+
@test size(r.centers) == (3,3)
7+
@test size(r.weights, 1) == length(img)
8+
@test all((1), sum(r.weights; dims=2))
9+
cmin, cmax = extrema(sum(r.weights; dims=1))
10+
@test cmax < 3*cmin
11+
12+
# Also with kmeans
13+
r = kmeans(img, 3)
14+
nc = last.(sort([pr for pr in segment_pixel_count(r)]; by=first))
15+
@test sum(nc) == length(img)
16+
@test 3*minimum(nc) > maximum(nc)
17+
end

test/runtests.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using ImageSegmentation, Images, Test, SimpleWeightedGraphs, LightGraphs, StaticArrays, DataStructures
2-
using RegionTrees: isleaf, Cell, split!
2+
using RegionTrees: isleaf, Cell, split!
33
using MetaGraphs: MetaGraph, clear_props!, get_prop, has_prop, set_prop!, props, vertices
44

55
using Documenter
@@ -12,4 +12,5 @@ include("fast_scanning.jl")
1212
include("watershed.jl")
1313
include("region_merging.jl")
1414
include("meanshift.jl")
15+
include("clustering.jl")
1516
include("merge_segments.jl")

0 commit comments

Comments
 (0)