diff --git a/ImageMorphology/README.md b/ImageMorphology/README.md index 5b693047..be24bb64 100644 --- a/ImageMorphology/README.md +++ b/ImageMorphology/README.md @@ -26,6 +26,7 @@ bothat morphogradient morpholaplace thinning +imfill ``` ## Documentation diff --git a/ImageMorphology/src/ImageMorphology.jl b/ImageMorphology/src/ImageMorphology.jl index f0638a9f..c0af1e53 100644 --- a/ImageMorphology/src/ImageMorphology.jl +++ b/ImageMorphology/src/ImageMorphology.jl @@ -11,6 +11,7 @@ include("connected.jl") include("dilation_and_erosion.jl") include("thinning.jl") +include("imfill.jl") export dilate, @@ -36,7 +37,8 @@ export # thinning.jl thinning, - GuoAlgo + GuoAlgo, + imfill end # module diff --git a/ImageMorphology/src/imfill.jl b/ImageMorphology/src/imfill.jl new file mode 100644 index 00000000..55dff55f --- /dev/null +++ b/ImageMorphology/src/imfill.jl @@ -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 diff --git a/ImageMorphology/test/imfill.jl b/ImageMorphology/test/imfill.jl new file mode 100644 index 00000000..ca753205 --- /dev/null +++ b/ImageMorphology/test/imfill.jl @@ -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 + diff --git a/ImageMorphology/test/runtests.jl b/ImageMorphology/test/runtests.jl index 6a6bbd41..37205aa5 100644 --- a/ImageMorphology/test/runtests.jl +++ b/ImageMorphology/test/runtests.jl @@ -6,4 +6,5 @@ using Test include("connected.jl") include("dilation_and_erosion.jl") include("thinning.jl") + include("imfill.jl") end