110 lines
4.5 KiB
Julia
110 lines
4.5 KiB
Julia
# src/ImageProcessing
|
|
|
|
using Images
|
|
using ImageBinarization
|
|
using ImageMorphology
|
|
using ImageComponentAnalysis
|
|
using Colors # For converting to grayscale
|
|
|
|
export process_image_pipeline
|
|
export load_and_prepare_mask # Export the new function
|
|
|
|
"""
|
|
load_and_prepare_mask(mask_path::String, target_dims::Tuple{Int, Int})
|
|
|
|
Loads a PNG image mask, converts it to a binary (Boolean) matrix,
|
|
and resizes it to the specified `target_dims`. White pixels in the mask
|
|
are considered `true` (part of the ROI), and black pixels are `false`.
|
|
|
|
# Arguments
|
|
- `mask_path`: Absolute path to the PNG mask file.
|
|
- `target_dims`: A tuple `(width, height)` representing the desired output dimensions.
|
|
|
|
# Returns
|
|
- A `BitMatrix` of `target_dims` where `true` indicates the ROI.
|
|
"""
|
|
function load_and_prepare_mask(mask_path::String, target_dims::Tuple{Int, Int})
|
|
if !isfile(mask_path)
|
|
error("Mask file not found: $(mask_path)")
|
|
end
|
|
|
|
# Load the image
|
|
img = Images.load(mask_path)
|
|
|
|
# Convert to grayscale if it's a color image
|
|
gray_img = Gray.(img)
|
|
|
|
# Binarize using Otsu's method - white regions become 'true'
|
|
binary_img = binarize(gray_img, Otsu())
|
|
|
|
# Resize to target dimensions
|
|
resized_img = imresize(binary_img, (target_dims[2], target_dims[1]))
|
|
|
|
# Ensure the output is a BitMatrix, as imresize can change the type
|
|
return resized_img .> 0.5
|
|
end
|
|
|
|
# ===================================================================
|
|
# CORE PROCESSING PIPELINE
|
|
# ===================================================================
|
|
|
|
"""
|
|
process_image_pipeline(gray_img; otsu_scale=1.0, noise_size_percent=0.1, hole_size_percent=0.05, smoothing=2)
|
|
|
|
Applies a multi-step image processing pipeline to a grayscale image to segment regions of interest.
|
|
|
|
The pipeline consists of:
|
|
1. **Binarization**: An adjusted Otsu's threshold is used to create a binary image.
|
|
2. **Noise Removal**: Small white regions (noise) are removed using an area opening operation.
|
|
3. **Hole Filling**: Small black regions (holes) within larger objects are filled.
|
|
4. **Edge Smoothing**: The edges of the final regions are smoothed using a morphological closing operation.
|
|
|
|
# Arguments
|
|
- `gray_img`: The input grayscale image (`Matrix{<:Gray}`).
|
|
|
|
# Keyword Arguments
|
|
- `otsu_scale`: A factor to scale the automatically determined Otsu threshold. Values > 1.0 make the threshold stricter (less white), < 1.0 make it more lenient (more white). Default: `1.0`.
|
|
- `noise_size_percent`: The percentage of the total image area used as a threshold to remove small white noise components. Default: `0.1`.
|
|
- `hole_size_percent`: The percentage of the total image area used as a threshold to fill black holes in white components. Default: `0.05`.
|
|
- `smoothing`: The size of the kernel for the final edge smoothing (closing) operation. Default: `2`.
|
|
|
|
# Returns
|
|
- A tuple containing four images representing the intermediate steps of the pipeline:
|
|
1. `binary_img`: The result of the initial binarization.
|
|
2. `noise_removed_img`: The image after noise removal.
|
|
3. `holes_filled_img`: The image after filling holes.
|
|
4. `smoothed_img`: The final smoothed image.
|
|
"""
|
|
function process_image_pipeline(gray_img;
|
|
otsu_scale=1.0,
|
|
noise_size_percent=0.1,
|
|
hole_size_percent=0.05,
|
|
smoothing=2)
|
|
|
|
# --- Step 1: Otsu Binarization ---
|
|
otsu_threshold = find_threshold(gray_img, Otsu())
|
|
adjusted_threshold = otsu_threshold * otsu_scale
|
|
binary_img = gray_img .>= adjusted_threshold
|
|
|
|
# --- Smart Parameter Scaling ---
|
|
image_area = length(gray_img)
|
|
noise_size_pixels = round(Int, image_area * noise_size_percent)
|
|
hole_size_pixels = round(Int, image_area * hole_size_percent)
|
|
|
|
# --- Step 2: Remove Small White Regions (Noise) ---
|
|
# area_opening is the correct morphological operation for this.
|
|
noise_removed_img = area_opening(binary_img, min_area=noise_size_pixels)
|
|
|
|
# --- Step 3: Fill Small Black Holes ---
|
|
# area_closing is the dual of area_opening and fills holes.
|
|
holes_filled_img = area_closing(noise_removed_img, min_area=hole_size_pixels)
|
|
|
|
# --- Step 4: Smooth Edges ---
|
|
# A morphological closing with a small disk smooths outlines.
|
|
smoothing_kernel = ones(Bool, (smoothing, smoothing))
|
|
smoothed_img = closing(holes_filled_img, smoothing_kernel)
|
|
|
|
# --- Return all intermediate steps for visualization ---
|
|
return binary_img, noise_removed_img, holes_filled_img, smoothed_img
|
|
end
|