Skip to content

Commit

Permalink
Merge pull request #44 from ImperialCollegeLondon/default_function
Browse files Browse the repository at this point in the history
Default function
  • Loading branch information
github-actions[bot] authored Sep 3, 2024
2 parents f2e2eaf + 420bedf commit e967d35
Show file tree
Hide file tree
Showing 14 changed files with 2,155 additions and 12 deletions.
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ repos:
rev: "v1.10.0"
hooks:
- id: mypy
additional_dependencies: ["types-toml"]
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.40.0
hooks:
Expand Down
5 changes: 5 additions & 0 deletions bubble_analyser/__main__.py
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
"""The entry point for the Bubble Analyser program."""

from .default import default

if __name__ == "__main__":
default()
107 changes: 107 additions & 0 deletions bubble_analyser/background_subtraction_threshold.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
"""Background Subtraction and Thresholding: Isolate objects from backgrounds.
This module provides tools for image preprocessing including grayscale conversion,
background subtraction, and thresholding. It is designed to handle images where objects
of interest need to be isolated from their backgrounds for further analysis.
Functions:
convert_grayscale(image): Converts a color image to grayscale.
background_subtraction(target_img, background_img): Subtracts the background image
from the target image to highlight differences.
threshold(difference_img, threshold_value): Applies a binary threshold to an image
to create a binary mask.
background_subtraction_threshold(target_img, background_img, threshold_value):
Combines background subtraction and thresholding to isolate objects of interest in
an image.
These functions are used to preprocess images for applications such as object detection,
where isolating the changes between images or from a background is necessary. Each
function is designed to be modular, allowing them to be used independently or in
sequence depending on the requirements of the task.
"""

from typing import cast

import cv2
import numpy as np
from numpy import typing as npt


def convert_grayscale(image: npt.NDArray[np.int_]) -> npt.NDArray[np.int_]:
"""Converts an image to grayscale.
Args:
image (npt.NDArray): The input image to be converted.
Returns:
npt.NDArray: The converted image in grayscale.
"""
if len(image.shape) == 3:
image = cast(npt.NDArray[np.int_], cv2.cvtColor(image, cv2.COLOR_BGR2GRAY))
return image


def background_subtraction(
target_img: npt.NDArray[np.int_], background_img: npt.NDArray[np.int_]
) -> npt.NDArray[np.int_]:
"""Performs background subtraction on two images.
Args:
target_img (npt.NDArray): The target image where the objects of interest are
located.
background_img (npt.NDArray): The background image (without object of interest).
Returns:
npt.NDArray: The difference image after background subtraction.
"""
difference_img = cv2.absdiff(target_img, background_img)
return cast(npt.NDArray[np.int_], difference_img)


def threshold(
difference_img: npt.NDArray[np.int_], threshold_value: float
) -> npt.NDArray[np.bool_]:
"""Applies a binary threshold to the given difference image.
Args:
difference_img (npt.NDArray): The input difference image to be thresholded.
threshold_value (int): The threshold value to apply to the difference image.
Returns:
npt.NDArray: The thresholded image.
"""
_, thresholded_img = cv2.threshold(
difference_img, threshold_value, 255, cv2.THRESH_BINARY
)
return cast(npt.NDArray[np.bool_], thresholded_img)


def background_subtraction_threshold(
target_img: npt.NDArray[np.int_],
background_img: npt.NDArray[np.int_],
threshold_value: float,
) -> npt.NDArray[np.bool_]:
"""Perform background subtraction and apply thresholding.
Args:
target_img: The target image where the objects of interest are located.
background_img: The background image (without objects of interest).
threshold_value: The threshold value to apply after background subtraction.
Returns:
A binary image with the objects of interest isolated.
"""
# Ensure both images are in grayscale
target_img = convert_grayscale(target_img)
background_img = convert_grayscale(background_img)

# Subtract the background image from the target image
difference_img = background_subtraction(target_img, background_img)

# Apply a threshold to the difference image
thresholded_img = threshold(difference_img, threshold_value)

return thresholded_img
83 changes: 83 additions & 0 deletions bubble_analyser/calculate_circle_properties.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"""Calculate Circle Properties.
This module contains functions for calculating geometric properties of regions
identified in an image. It is particularly focused on regions that are labeled in terms
of their circularity attributes.
The `calculate_circle_properties` function evaluates the geometric features of labeled
regions within an image, which have been identified as separate entities, often through
a segmentation process. It measures various properties related to the shape and size of
the regions, adjusted to real-world dimensions using a provided pixel-to-centimeter
conversion ratio.
Function:
calculate_circle_properties(labels, px2cm): Computes area, equivalent diameter,
eccentricity, solidity, and circularity for each labeled region.
Each computed property is defined as follows:
- Area: Total area of the region converted from pixels to square centimeters.
- Equivalent diameter: Diameter of a circle with the equivalent area as the region,
provided in centimeters.
- Eccentricity: Measure of the deviation of the region from a perfect circle, where
0 indicates a perfect circle and values closer to 1 indicate elongated shapes.
- Solidity: Ratio of the region's area to the area of its convex hull, indicating
the compactness of the shape.
- Circularity: A value that describes how closely the shape of the region approaches
that of a perfect circle, calculated from the area and the perimeter.
The function returns a list of dictionaries, with each dictionary holding the properties
for a specific region, facilitating easy access and manipulation of these metrics in
subsequent analysis or reporting stages.
"""

import numpy as np
from numpy import typing as npt
from skimage import measure


def calculate_circle_properties(
labels: npt.NDArray[np.int_], px2cm: float
) -> list[dict[str, float]]:
"""Calculate geometric properties of labeled regions in an image.
This function computes various properties that describe the "circularity" of regions
within the labeled image, such as area, equivalent diameter, eccentricity, solidity,
and circularity. These properties are calculated in centimeters based on the
provided pixel-to-centimeter ratio.
Args:
labels: A labeled image where each distinct region (or "circle") is represented
by unique labels.
px2cm: The ratio of centimeters per pixel, used to convert measurements from
pixels to centimeters.
Returns:
A list of dictionaries, each containing the following properties for a region:
- area: The area of the region in square centimeters.
- equivalent_diameter: The diameter of a circle with the same area as the region
, in centimeters.
- eccentricity: The eccentricity of the ellipse that has the same second-moments
as the region.
- solidity: The proportion of the pixels in the convex hull that are also in the
region.
- circularity: A measure of how close the shape is to a perfect circle,
calculated using the perimeter and area.
"""
properties = measure.regionprops(labels)
circle_properties = []
for prop in properties:
area = prop.area * (px2cm**2)
equivalent_diameter = prop.equivalent_diameter * px2cm
eccentricity = prop.eccentricity
solidity = prop.solidity
circularity = (4 * np.pi * area) / (prop.perimeter * px2cm) ** 2
circle_properties.append(
{
"area": area,
"equivalent_diameter": equivalent_diameter,
"eccentricity": eccentricity,
"solidity": solidity,
"circularity": circularity,
}
)
return circle_properties
Loading

0 comments on commit e967d35

Please sign in to comment.