Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: preprocess with tiling #504

Merged
merged 34 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
0f50b63
feat: preprocess with tiling
cpaniaguam Nov 9, 2024
8c21154
Update preprocess_tiling.jl
cpaniaguam Nov 11, 2024
8cce54c
feat: preprocess_tiling
cpaniaguam Nov 15, 2024
d2afca0
feat: add se_disk2
cpaniaguam Nov 15, 2024
c7df300
Merge branch 'main' into 503-orchestrate-into-a-macro-function
cpaniaguam Nov 19, 2024
6656dfe
fix: rename ref_img to ref_image for consistency in preprocess_tiling…
cpaniaguam Nov 19, 2024
9a65271
test: preprocess_tiling
cpaniaguam Nov 19, 2024
9653851
feat: include preprocess_tiling.jl in IceFloeTracker.jl
cpaniaguam Nov 19, 2024
34f75c6
feat: enhance test for preprocess_tiling with additional image proces…
cpaniaguam Nov 19, 2024
727b154
feat: add rgb2gray function to convert RGB channels to grayscale
cpaniaguam Nov 19, 2024
5857dd5
feat: re-include preprocess_tiling.jl in IceFloeTracker.jl for improv…
cpaniaguam Nov 19, 2024
3457103
feat: add overloaded to_uint8 function for single numeric input
cpaniaguam Nov 19, 2024
45037df
feat: move get_ice_masks helpers to ice_masks
cpaniaguam Nov 20, 2024
8ba5fec
chore: remove unused get_new2 and get_new3 functions from preprocess_…
cpaniaguam Nov 20, 2024
ad9335e
refactor: update preprocess_tiling.jl to process RGB channels and con…
cpaniaguam Nov 20, 2024
d23c2be
test: get_ice_masks and related functions
cpaniaguam Nov 20, 2024
e91942d
fix: update get_ice_labels_mask to use a default factor of 255 and im…
cpaniaguam Nov 20, 2024
233cc3d
test: update assertions in test-get-ice-masks.jl to use @test macro
cpaniaguam Nov 20, 2024
a0c7081
fix: correct typo in log message and update ice mask processing function
cpaniaguam Nov 20, 2024
55a752a
test: update kmeans_segmentation call and adjust expected ice mask sum
cpaniaguam Nov 20, 2024
9ebc728
fix: use k=3 for kmeans seg for tiled workflow
cpaniaguam Nov 20, 2024
b28f0e8
fix: add default k parameter to get_ice_masks function
cpaniaguam Nov 20, 2024
71b61b0
chore: format
cpaniaguam Nov 20, 2024
880c18b
fix: add k parameter for kmeans segmentation in ice masks parameters
cpaniaguam Nov 20, 2024
405aaec
refactor: make coherent groups in preprocess)tiling
cpaniaguam Nov 20, 2024
7890935
fix: update watershed function to return boolean boundary map
cpaniaguam Nov 20, 2024
ce0d4d5
fix: return BitMatrix from get_final function for improved data handling
cpaniaguam Nov 20, 2024
6156447
fix: optimize get_holes function for improved image processing and me…
cpaniaguam Nov 20, 2024
e30a127
fix: update get_segment_mask to use watershed1 for improved segmentation
cpaniaguam Nov 20, 2024
f39b5a4
fix: refactor watershed2 function to remove async tasks
cpaniaguam Nov 20, 2024
74b5c00
test: preprocess_tiling
cpaniaguam Nov 20, 2024
aed5691
Update src/ice_masks.jl
cpaniaguam Nov 25, 2024
a17a50e
docs: update docstring
cpaniaguam Nov 25, 2024
737d139
docs: update rgb2gray
cpaniaguam Nov 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/IceFloeTracker.jl
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ module MorphSE
include("morphSE/fill_holes.jl")
end

include("preprocess_tiling.jl")

module Register
include("Register/CenterIndexedArrays.jl-0.2.0/CenterIndexedArrays.jl")
include("Register/RegisterCore.jl-0.2.4/src/RegisterCore.jl")
Expand Down
168 changes: 0 additions & 168 deletions src/find_ice_labels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -84,171 +84,3 @@ function find_ice_labels(
# @info "Done with ice labels" # to uncomment when logger is added
return ice_labels
end

function get_image_peaks(arr, imgtype="uint8")
_, heights = imhist(arr, imgtype)

locs, heights, _ = Peaks.findmaxima(heights)

# TODO: make this conditional on input args
order = sortperm(heights; rev=true)
locs, heights = locs[order], heights[order]

return (locs=locs, heights=heights)
end


function get_ice_labels_mask(ref_img::Matrix{RGB{N0f8}}, thresholds, factor=1)
cv = channelview(ref_img)
cv = [float64.(cv[i, :, :]) .* factor for i in 1:3]
mask_ice_band_7 = cv[1] .< thresholds[1]
mask_ice_band_2 = cv[2] .> thresholds[2]
mask_ice_band_1 = cv[3] .> thresholds[3]
mask = mask_ice_band_7 .* mask_ice_band_2 .* mask_ice_band_1
@debug "Found $(sum(mask)) ice pixels"
return mask
end

function get_nlabel(
ref_img,
morph_residue_labels,
factor;
band_7_threshold::T=5,
band_2_threshold::T=230,
band_1_threshold::T=240,
band_7_threshold_relaxed::T=10,
band_1_threshold_relaxed::T=190,
possible_ice_threshold::T=75,
) where {T<:Integer}
_getnlabel(morphr, mask) = StatsBase.mode(morphr[mask])

# Initial attempt to get ice labels
thresholds = (band_7_threshold, band_2_threshold, band_1_threshold)
ice_labels_mask = get_ice_labels_mask(ref_img, thresholds, 255)
sum(ice_labels_mask) > 1 && return _getnlabel(morph_residue_labels, ice_labels_mask)

# First relaxation
thresholds = (band_7_threshold_relaxed, band_2_threshold, band_1_threshold_relaxed)
ice_labels_mask = get_ice_labels_mask(ref_img, thresholds, 255)
sum(ice_labels_mask) > 0 && return _getnlabel(morph_residue_labels, ice_labels_mask)

# Second/Third relaxation
return get_nlabel_relaxation(
ref_img,
morph_residue_labels,
factor,
possible_ice_threshold,
band_7_threshold_relaxed,
band_2_threshold,
)
end

function get_nlabel_relaxation(
ref_img,
morph_residue_labels,
factor,
possible_ice_threshold,
band_7_threshold_relaxed,
band_2_threshold,
)
# filter b/c channels (landmasked channels 2 and 3) and compute peaks
b, c = [float64.(channelview(ref_img)[i, :, :]) .* factor for i in 2:3]
b[b .< possible_ice_threshold] .= 0
c[c .< possible_ice_threshold] .= 0
pksb, pksc = get_image_peaks.([b, c])

# return early if no peaks are found
!all(length.([pksb.locs, pksc.locs]) .> 2) && return 1

relaxed_thresholds = [band_7_threshold_relaxed, pksb.locs[2], pksc.locs[2]]
ice_labels = get_ice_labels_mask(ref_img, relaxed_thresholds, factor)

sum(ice_labels) > 0 && return StatsBase.mode(morph_residue_labels[ice_labels])

# Final relaxation
mask_b = b .> band_2_threshold
sum(mask_b) > 0 && return StatsBase.mode(morph_residue_labels[mask_b])

# No mode found
return missing
end

"""
get_ice_masks(
falsecolor_image,
morph_residue,
landmask,
tiles,
binarize;
band_7_threshold,
band_2_threshold,
band_1_threshold,
band_7_threshold_relaxed,
band_1_threshold_relaxed,
possible_ice_threshold,
factor,
)
Get the ice masks from the falsecolor image and morphological residue given a particualr tiling configuration.
# Arguments
- `falsecolor_image`: The falsecolor image.
- `morph_residue`: The morphological residue image.
- `landmask`: The landmask.
- `tiles`: The tiles.
- `binarize::Bool=true`: Whether to binarize the tiling.
- `band_7_threshold=5`: The threshold for band 7.
- `band_2_threshold=230`: The threshold for band 2.
- `band_1_threshold=240`: The threshold for band 1.
- `band_7_threshold_relaxed=10`: The relaxed threshold for band 7.
- `band_1_threshold_relaxed=190`: The relaxed threshold for band 1.
- `possible_ice_threshold=75`: The threshold for possible ice.
- `factor=255`: normalization factor to convert images to uint8.
# Returns
- A named tuple `(icemask, bin)` where:
- `icemask`: The ice mask.
- `bin`: The binarized tiling.
"""
function get_ice_masks(
falsecolor_image,
morph_residue,
landmask::BitMatrix,
tiles,
binarize::Bool=true;
band_7_threshold::T=5,
band_2_threshold::T=230,
band_1_threshold::T=240,
band_7_threshold_relaxed::T=10,
band_1_threshold_relaxed::T=190,
possible_ice_threshold::T=75,
factor::T=255,
) where {T<:Integer}

# Make canvases
ice_mask = BitMatrix(zeros(Bool, size(falsecolor_image)))
binarized_tiling = zeros(Int, size(falsecolor_image))

fc_landmasked = apply_landmask(falsecolor_image, landmask)

for tile in tiles
# Conditionally update binarized_tiling as it's not used in some workflows
if binarize
binarized_tiling[tile...] .= imbinarize(morph_residue[tile...])
end

morph_residue_seglabels = kmeans_segmentation(Gray.(morph_residue[tile...] / 255))

floes_label = get_nlabel(
fc_landmasked[tile...],
morph_residue_seglabels,
factor;
band_7_threshold=band_7_threshold,
band_2_threshold=band_2_threshold,
band_1_threshold=band_1_threshold,
band_7_threshold_relaxed=band_7_threshold_relaxed,
band_1_threshold_relaxed=band_1_threshold_relaxed,
possible_ice_threshold=possible_ice_threshold,
)

ice_mask[tile...] .= (morph_residue_seglabels .== floes_label)
end
return (icemask=ice_mask, bin=binarized_tiling)
end
21 changes: 20 additions & 1 deletion src/histogram_equalization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ function to_uint8(arr::AbstractMatrix{T}) where {T<:Integer}
return img
end

function to_uint8(num::T) where {T<:Union{AbstractFloat,Int,Signed}}
num = Int(round(num, RoundNearestTiesAway))
return clamp(num, 0, 255)
end

function anisotropic_diffusion_3D(I)
rgbchannels = get_rgb_channels(I)

Expand Down Expand Up @@ -127,6 +132,20 @@ function get_rgb_channels(img)
return cat(redc, greenc, bluec; dims=3)
end

"""
rgb2gray(rgbchannels::Array{Float64, 3})

Convert an array of RGB channel data to grayscale in the range [0, 255].

Identical to MATLAB `rgb2gray` (https://www.mathworks.com/help/matlab/ref/rgb2gray.html).
"""
function rgb2gray(rgbchannels::Array{Float64,3})
r, g, b = [to_uint8(rgbchannels[:, :, i]) for i in 1:3]
# Reusing the r array to store the equalized gray image
r .= to_uint8(0.2989 * r .+ 0.5870 * g .+ 0.1140 * b)
cpaniaguam marked this conversation as resolved.
Show resolved Hide resolved
cpaniaguam marked this conversation as resolved.
Show resolved Hide resolved
return r
end

function _process_image_tiles(
true_color_image,
clouds_red,
Expand Down Expand Up @@ -287,7 +306,7 @@ end
Histogram equalization of `img` using `nbins` bins.
"""
function histeq(img::S; nbins=64)::S where {S<:AbstractArray{<:Integer}}
cpaniaguam marked this conversation as resolved.
Show resolved Hide resolved
return to_uint8(sk_exposure.equalize_hist(img, nbins=nbins) * 255)
return to_uint8(sk_exposure.equalize_hist(img; nbins=nbins) * 255)
end

function _imhist(img, rng)
Expand Down
Loading