Skip to content

Commit

Permalink
[morphology] add imfill function (#9)
Browse files Browse the repository at this point in the history
This function can be used to fill objects of a certain size with some specified value.
  • Loading branch information
aquatiko authored and johnnychen94 committed May 21, 2022
1 parent 2e64eec commit ecedf4c
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 1 deletion.
1 change: 1 addition & 0 deletions ImageMorphology/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ bothat
morphogradient
morpholaplace
thinning
imfill
```

## Documentation
Expand Down
4 changes: 3 additions & 1 deletion ImageMorphology/src/ImageMorphology.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ include("connected.jl")

include("dilation_and_erosion.jl")
include("thinning.jl")
include("imfill.jl")

export
dilate,
Expand All @@ -36,7 +37,8 @@ export

# thinning.jl
thinning,
GuoAlgo
GuoAlgo,
imfill


end # module
43 changes: 43 additions & 0 deletions ImageMorphology/src/imfill.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""
Image filling Algorithm
```
filled_img = imfill(img, interval)
filled_img = imfill(img, interval, value)
filled_img = imfill(img, interval, value, connectivity)
```
Connected components of an image is found using flood-fill algorithm and returns a copy of
the original image after filling objects that falls in the range of interval.
For filling objects, represent the holes(part to be filled) with `true` in your array.
Parameters:
- img = Input image (Boolean array type)
- interval = objects of size in this range will be filled with `false`
- connectivity = connectivity takes the same values as in label_components (Default value is 1:ndims(img))
"""

function imfill(img::AbstractArray{Bool}, interval::Tuple{Real,Real}, connectivity::Union{Dims, AbstractVector{Int}, BitArray}=1:ndims(img))

if interval[1] > interval[2] || interval[1] < 0 || interval[2] < 0
throw(DomainError(interval,"Interval must be non-negative and in format (min_range,max_range)"))
end

labels = label_components(img,connectivity)

count_labels = Dict([(i,count(x->x==i,labels)) for i in unique(labels)])

new_img = similar(img)
for ind in eachindex(img)
if img[ind] == true && interval[1] <= count_labels[labels[ind]] <= interval[2]
new_img[ind] = false
else
new_img[ind] = img[ind]
end
end

return new_img
end
45 changes: 45 additions & 0 deletions ImageMorphology/test/imfill.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
@testset "imfill" begin
#2 Dimensional case
image = Bool.([0 0 0 0 0 0 1 0 0 0
0 1 1 1 1 1 0 0 0 0
0 1 0 0 1 1 0 0 0 0
0 1 1 1 0 1 0 0 0 0
0 1 1 1 1 1 0 0 0 0
0 0 0 0 0 0 0 1 1 1
0 0 0 0 0 0 0 1 0 1
0 0 0 0 0 0 0 1 1 1
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0])
answer = Bool.([0 0 0 0 0 0 1 0 0 0
0 1 1 1 1 1 0 0 0 0
0 1 1 1 1 1 0 0 0 0
0 1 1 1 1 1 0 0 0 0
0 1 1 1 1 1 0 0 0 0
0 0 0 0 0 0 0 1 1 1
0 0 0 0 0 0 0 1 1 1
0 0 0 0 0 0 0 1 1 1
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0])
@test imfill(.!image, (0,2)) == (.!answer)

#3 Dimensional case
A = zeros(Bool,3,size(image)[1],size(image)[2])
A[1,:,:] = image
A[2,:,:] = image
A[3,:,:] = image
B = zeros(Bool,3,size(answer)[1],size(answer)[2])
B[1,:,:] = answer
B[2,:,:] = answer
B[3,:,:] = answer
@test imfill(.!A, (0,8)) == (.!B)

# Complete white image and complete black image case
img = zeros(Bool,10,10)
@test imfill(img,(0,10)) == img
@test imfill(.!img,(0,99)) == .!img
# Miscellaneous case
img[5,5] = true
@test imfill(.!img,(0,10)) == .!img
@test imfill(.!img,(0,99)) == zeros(Bool,10,10)
end

1 change: 1 addition & 0 deletions ImageMorphology/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ using Test
include("connected.jl")
include("dilation_and_erosion.jl")
include("thinning.jl")
include("imfill.jl")
end

0 comments on commit ecedf4c

Please sign in to comment.