Skip to content

Commit

Permalink
Merge pull request #500 from WilhelmusLab/493-get_new23-final
Browse files Browse the repository at this point in the history
feat: regularize/final
  • Loading branch information
cpaniaguam authored Nov 19, 2024
2 parents 86dffe3 + 5362d04 commit f6551c7
Show file tree
Hide file tree
Showing 12 changed files with 16,424 additions and 8 deletions.
8 changes: 1 addition & 7 deletions src/IceFloeTracker.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,7 @@ include("morph_fill.jl")
include("imcomplement.jl")
include("imadjust.jl")
include("ice_masks.jl")

const sk_measure = PyNULL()
const sk_exposure = PyNULL()
const getlatlon = PyNULL()



include("regularize-final.jl")

function get_version_from_toml(pth=dirname(dirname(pathof(IceFloeTracker))))::VersionNumber
toml = TOML.parsefile(joinpath(pth, "Project.toml"))
Expand Down
113 changes: 113 additions & 0 deletions src/regularize-final.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
using IceFloeTracker: unsharp_mask, to_uint8, hbreak, morph_fill

# TODO: Add tests for regularize_fill_holes, regularize_sharpening, get_final

"""
regularize_fill_holes(img, local_maxima_mask, factor, segment_mask, L0mask)
Regularize `img` by:
1. increasing the maxima of `img` by a factor of `factor`
2. filtering `img` at positions where either `segment_mask` or `L0mask` are true
3. filling holes
# Arguments
- `img`: The morphological residue image.
- `local_maxima_mask`: The local maxima mask.
- `factor`: The factor to apply to the local maxima mask.
- `segment_mask`: The segment mask -- intersection of bw1 and bw2 in first tiled workflow of `master.m`.
- `L0mask`: zero-labeled pixels from watershed.
"""
function regularize_fill_holes(img, local_maxima_mask, segment_mask, L0mask, factor)
new2 = to_uint8(img .+ local_maxima_mask .* factor)
new2[segment_mask .|| L0mask] .= 0
return IceFloeTracker.MorphSE.fill_holes(new2)
end

"""
regularize_sharpening(img, L0mask, radius, amount, local_maxima_mask, factor, segment_mask, se)
Regularize `img` via sharpening, filtering, reconstruction, and maxima elevating.
# Arguments
- `img`: The input image.
- `L0mask`: zero-labeled pixels from watershed.
- `radius`: The radius of the unsharp mask.
- `amount`: The amount of unsharp mask.
- `local_maxima_mask`: The local maxima mask.
- `factor`: The factor to apply to the local maxima mask.
- `segment_mask`: The segment mask -- intersection of bw1 and bw2 in first tiled workflow of `master.m`.
"""
function regularize_sharpening(
img, L0mask, local_maxima_mask, segment_mask, se, radius, amount, factor
)
new3 = unsharp_mask(img, radius, amount, 255)
new3[L0mask] .= 0
new3 = IceFloeTracker.reconstruct(new3, se, "dilation", false)
new3[segment_mask] .= 0
return to_uint8(new3 + local_maxima_mask .* factor)
end

function _regularize(
morph_residue, local_maxima_mask, segment_mask, L0mask, se; factor, radius, amount
)
reg_fill_holes = regularize_fill_holes(
morph_residue, local_maxima_mask, segment_mask, L0mask, factor[1]
)
reg_sharpened = regularize_sharpening(
reg_fill_holes,
L0mask,
local_maxima_mask,
segment_mask,
se,
radius,
amount,
factor[end],
)
return reg_sharpened
end

"""
get_final(img, label, segment_mask, se_erosion, se_dilation)
Final processing following the tiling workflow.
# Arguments
- `img`: The input image.
- `label`: Mode of most common label in the find_ice_labels workflow.
- `segment_mask`: The segment mask.
- `se_erosion`: structuring element for erosion.
- `se_dilation`: structuring element for dilation.
- `apply_segment_mask=true`: Whether to filter `img` the segment mask.
"""
function get_final(
# this function is used in preprocessing_tiling
img,
segment_mask,
se_erosion,
se_dilation,
apply_segment_mask::Bool=true,
)
_img = hbreak(img)

# slow for big images
_img .= morph_fill(_img)

# TODO: decide on criteria for applying segment mask
apply_segment_mask && (_img[segment_mask] .= false)

# tends to fill more than matlabs imfill
_img .= IceFloeTracker.MorphSE.fill_holes(_img)

# marker image
_img .= branch(_img)

#= opening to remove noise while preserving shape/size
Note the different structuring elements for erosion and dilation =#
mask = sk_morphology.erosion(_img, se_erosion)
mask .= sk_morphology.dilation(mask, se_dilation)

# Restore shape of floes based on the cleaned up `mask`
final = IceFloeTracker.MorphSE.mreconstruct(IceFloeTracker.MorphSE.dilate, _img, mask)
return final
end
8 changes: 7 additions & 1 deletion src/special_strels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,10 @@ function se_disk20()
se = [sum(c.I) <= 11 for c in CartesianIndices((39, 39))]
_generate_se!(se)
return se
end
end

function se_disk2()
se = [sum(c.I) <= 3 for c in CartesianIndices((5,5))]
_generate_se!(se)
return se
end
63 changes: 63 additions & 0 deletions test/test-regularize-final.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using IceFloeTracker:
get_tiles,
regularize_fill_holes,
regularize_sharpening,
_regularize,
se_disk2,
get_final
using DelimitedFiles: readdlm

se = collect(IceFloeTracker.MorphSE.strel_diamond((3, 3)))

test_files_dir = joinpath(@__DIR__, "test_inputs/regularize")

morph_residue = readdlm(joinpath(test_files_dir, "morph_residue.csv"), ',', Int)
local_maxima_mask = readdlm(joinpath(test_files_dir, "local_maxima_mask.csv"), ',', Int)
segment_mask = readdlm(joinpath(test_files_dir, "segment_mask.csv"), ',', Bool)
L0mask = readdlm(joinpath(test_files_dir, "L0mask.csv"), ',', Bool)
expected_regularized_holes_filled = readdlm(
joinpath(test_files_dir, "reg_holes_filled_expected.csv"), ',', Int
)
expected_regularized_sharpened = readdlm(
joinpath(test_files_dir, "reg_sharpened.csv"), ',', Int
)

get_final_input = readdlm(joinpath(test_files_dir, "get_final.csv"), ',', Bool)
se_erosion = se
se_dilation = se_disk2()
get_final_expected = readdlm(joinpath(test_files_dir, "get_final_expected.csv"), ',', Bool)

@testset "regularize/get_final" begin
@testset "regularize_fill_holes/sharpening" begin
reg_holes_filled = regularize_fill_holes(
morph_residue, local_maxima_mask, segment_mask, L0mask, 0.3
)

reg_sharpened = regularize_sharpening(
reg_holes_filled, L0mask, local_maxima_mask, segment_mask, se, 10, 2, 0.5
)

reg = _regularize(
morph_residue,
local_maxima_mask,
segment_mask,
L0mask,
se;
factor=(0.3, 0.5),
radius=10,
amount=2,
)

@test expected_regularized_holes_filled == reg_holes_filled
@test expected_regularized_sharpened == reg_sharpened
@test expected_regularized_sharpened == reg
end

@testset "get_final" begin
get_final_output = get_final(
get_final_input, segment_mask, se_erosion, se_dilation, true
)

@test get_final_output == get_final_expected
end
end
2,030 changes: 2,030 additions & 0 deletions test/test_inputs/regularize/L0mask.csv

Large diffs are not rendered by default.

2,030 changes: 2,030 additions & 0 deletions test/test_inputs/regularize/get_final.csv

Large diffs are not rendered by default.

2,030 changes: 2,030 additions & 0 deletions test/test_inputs/regularize/get_final_expected.csv

Large diffs are not rendered by default.

Loading

0 comments on commit f6551c7

Please sign in to comment.