aigarmic

Submodules

Classes

Plate

PlateSet

Model

Helper class that provides a standard way to create an ABC using

BinaryModel

Helper class that provides a standard way to create an ABC using

BinaryNestedModel

Helper class that provides a standard way to create an ABC using

SoftmaxModel

SoftmaxModel is a one-stop model when more than one growth category is present, e.g.:

Functions

plate_set_from_dir(→ PlateSet)

Create a PlateSet from a directory of images. Images are annotated using the provided model.

create_dataset_from_directory(...)

Create a training and validation dataset from a directory containing subdirectories for each class of image data.

predict_colony_images_from_directory(→ list[dict])

Predict the class of images in a directory using a trained model, and compare prediction to

save_training_log(→ None)

Save training log to CSV file

get_paths_from_directory(→ dict[str, list[str]])

Returns a dict of abx_names: [image1_path, image2_path, etc.]

get_concentration_from_path(→ float)

get concentration from plate image path, e.g.

convert_cv2_to_keras(→ numpy.ndarray)

Convert a cv2 image to a keras image

keras_image_to_cv2(→ numpy.ndarray)

Convert a keras image to a cv2 image

find_threshold_value(→ Optional[tuple[list, int]])

Find threshold value that correctly splits an agar plate image into colony sub-images. Assumes that a black grid

split_by_grid(→ list[list[numpy.ndarray]])

Split an agar plate image into individual colony sub-images using a grid overlay.

train_binary(...)

Train a binary classification model to differentiate between two classes of colony images.

train_softmax(...)

Train a softmax classification model to differentiate between multiple classes (2 or more) of colony images.

visualise_training(→ None)

Visualise training and validation accuracy and loss over epochs.

Package Contents

class aigarmic.Plate(drug: str, concentration: float, image: str | cv2.typing.MatLike | None = None, n_row: int | None = None, n_col: int | None = None, growth_code_matrix: list[list[int]] | None = None, visualise_contours: bool = False, model: aigarmic.model.Model | None = None, key: list[str] | None = None)[source]
add_growth_code_matrix(growth_code_matrix: list[list[int]]) None[source]
valid_growth_code_matrix(growth_code_matrix: list[list[int]]) bool[source]
static matrix_dimensions(matrix) tuple[int, Ellipsis][source]

Get dimensions of a matrix

Parameters:

matrix – matrix to get dimensions of

Raises:

ValueError – if matrix is not 2D or is not a valid matrix

Returns:

tuple of dimensions

split_images(visualise_contours: bool = False) None[source]

Splits images into individual colony images using grid

Parameters:

visualise_contours – Visualise the contours of the plate (useful for validation of grid splitting)

import_image(image: numpy.ndarray) None[source]

Import and save image of agar plate

Parameters:

image – loaded using cv2.imread

get_colony_image(index: tuple[int, int] | None = None) tuple[numpy.ndarray, str][source]

Pulls colony image and associated code-stamp Code-stamps are strings containing, in sequence: - Antibiotic name - Antibiotic concentration - Row (i) index - Column (j) index

If no index is provided (default) a random image is given

@param index: tuple of row and column index @return: tuple of image and code-stamp (e.g., “drug_0.125_i_1_j_2”)

Link model to plate for predictions

Parameters:

model – Model to link

get_key() list[str] | None[source]

Get key from linked Model

Raises:

LookupError: No linked model to get key from

Returns:

Key (or None if one is not found)

set_key(key: list[str]) None[source]

Set plate key. Checks whether differs from linked model key (if any), and warns if different.

Parameters:

key – List of growth categories (zero-indexed)

annotate_images(model: aigarmic.model.Model | None = None) list[list[str]][source]

Annotate plate images

Parameters:

model – linked model to use for predictions

Returns:

Two-dimensional list of growth annotations

print_matrix() None[source]

Print growth matrix in human-readable format

get_inaccurate_images(threshold: float = 0.9) set[tuple[int, int]][source]

Get indexes of images with prediction accuracy below threshold :param threshold: Prediction threshold :return: Set containing indices of inaccurate images

review_poor_images(threshold: float = 0.9, save_dir: str = None) list[tuple[int, int]][source]

Review and re-classify images with prediction accuracy below threshold. Classes should be zero indexed (e.g., 0, 1, 2). Currently, only supports up to 9. If save_dir provided then colony images will also be saved to a subdirectory (named after the new classification), to allow for future use in training.

Enter new classification for each image using numbers (e.g., 0/1/2) on keyboard, press enter to skip, press esc to stop reviewing the plate.

Parameters:
  • threshold – Prediction threshold to identify inaccurate images

  • save_dir – Directory to save re-classified images

Returns:

List of indices of re-classified images

convert_growth_codes(key: list[str]) list[list[str]][source]

Convert growth codes to human-readable format using key E.g., [0, 1, 2] -> [“No growth”, “Poor growth”, “Good growth”] Sets self.growth_matrix

Parameters:

key – List of growth codes (zero-indexed)

Returns:

Growth matrix

__repr__() str[source]

Return repr(self).

__lt__(other) bool[source]

Return self<value.

__eq__(other) bool[source]

Return self==value.

__gt__(other) bool[source]

Return self>value.

__le__(other) bool[source]

Return self<=value.

__ge__(other) bool[source]

Return self>=value.

__ne__(other) bool[source]

Return self!=value.

__hash__() int[source]

Return hash(self).

class aigarmic.PlateSet(plates_list: list[Plate], key: list[str] | None = None)[source]
valid_dimensions() bool[source]

Check if all plates in PlateSet have the same x and y dimensions

Returns:

True if all plates have the same dimensions, False otherwise

get_all_plates() list[Plate][source]

Returns a sorted list of all plates in the PlateSet, including the control plate

Returns:

List of Plate objects

convert_mic_matrix(mic_format: str = 'string') numpy.array[source]

Converts format of MIC matrix

Parameters:

mic_format – Format to convert to (only “string” is supported)

Returns:

matrix (array) of MIC values

calculate_mic(no_growth_key_items: tuple[int, Ellipsis]) numpy.array[source]

Calculate MIC matrix using image predictions. Sets self.mic_matrix

Parameters:

no_growth_key_items – tuple of key items that should be classified as “no growth” for MIC purposes

Returns:

MIC matrix

generate_qc() numpy.array[source]

Generate QC matrix for PlateSet, as follows:

“F” = FAIL - no growth in positive control plate, result should be disregarded “W” = WARNING - more than one change in concentration gradient. There should only be one change at the MIC breakpoint (where the images change from growth to no/poor growth). Depending on the application of the results, manual confirmation should be considered for warnings. “P” = PASS - no QC issues found

Returns:

Matrix of QC values (strings)

review_poor_images(threshold: float = 0.9, save_dir: str | None = None) list[list[tuple[int, int]]][source]

Review and re-classify images with prediction accuracy below threshold. Currently, supports up to 0–9 classes. If save_dir provided then colony images will also be saved to a subdirectory (named after the new classification), to allow for future use in training.

Enter new classification for each image using 0/1/2 on keyboard, or press enter (or esc) to skip.

Parameters:
  • threshold – Prediction threshold to identify inaccurate images

  • save_dir – Directory to save re-classified images

Returns:

List of indices of re-classified images

get_csv_data() list[dict][source]

Get MIC and QC data in a format suitable for CSV export: List of dicts containing: - Antibiotic: Antibiotic name - Position: Position of the colony (e.g., A1, B2, etc.) - MIC: MIC value - QC: QC value (P, W, F)

Returns:

List of dicts with MIC and QC data

__repr__() str[source]

Return repr(self).

aigarmic.plate_set_from_dir(path: str | pathlib.Path, drug: str, model: aigarmic.model.Model, n_row: int = 8, n_col: int = 12, **kwargs) PlateSet[source]

Create a PlateSet from a directory of images. Images are annotated using the provided model.

Parameters:
  • path – directory containing plate images (.jpg) with filenames indicating antibiotic concentration

  • drug – name of drug

  • model – model file to use for predictions

  • n_row – number of rows in the plates

  • n_col – number of columns in the plates

  • kwargs – additional keyword arguments to pass to Plate constructor

Returns:

PlateSet with MIC and QC values

class aigarmic.Model(key: list[str] | None)[source]

Bases: abc.ABC

Helper class that provides a standard way to create an ABC using inheritance.

get_key() list[str][source]

Return key to convert model output to human-readable label :return:

abstract predict(image) dict[source]
class aigarmic.BinaryModel(path: str, trained_x: int, trained_y: int, key: list[str] | None, threshold: float = 0.5)[source]

Bases: KerasModel

Helper class that provides a standard way to create an ABC using inheritance.

predict(image: numpy.ndarray) dict[source]

Predict growth category from image

Parameters:

image – image loaded using cv2.imread

Returns:

dictionary with keys ‘prediction’, ‘score’, ‘growth_code’, ‘growth’, ‘accuracy’

class aigarmic.BinaryNestedModel(first_line_model: BinaryModel, second_line_model: BinaryModel, first_model_accuracy_acceptance: float = 0.9, suppress_first_model_accuracy_check: bool = False)[source]

Bases: Model

Helper class that provides a standard way to create an ABC using inheritance.

predict(image: numpy.ndarray) dict[source]

Predict colony growth from image

Parameters:

image – image loaded using cv2.imread

Returns:

dictionary with keys ‘prediction’, ‘score’, ‘growth_code’, ‘growth’, ‘accuracy’

class aigarmic.SoftmaxModel(path: str, trained_x: int, trained_y: int, key: list[str] | None)[source]

Bases: KerasModel

SoftmaxModel is a one-stop model when more than one growth category is present, e.g.: [‘No growth’, ‘Poor growth’, ‘Good growth’]

predict(image: numpy.ndarray) dict[source]

Predict growth category from image

Parameters:

image – loaded using cv2.imread

Returns:

dictionary with keys ‘prediction’, ‘score’, ‘growth_code’, ‘growth’, ‘accuracy’

aigarmic.create_dataset_from_directory(directory: str, label_mode: str, image_width: int, image_height: int, seed: int = 12345, val_split: float = 0.2, batch_size: int = 32) tuple[tensorflow.data.Dataset, tensorflow.data.Dataset][source]

Create a training and validation dataset from a directory containing subdirectories for each class of image data.

Parameters:
  • directory – path containing images, each in subdirectory corresponding to class

  • label_mode – Labelling depending on model type (“binary” for binary or “int” for softmax)

  • image_width – Image width in pixels

  • image_height – Image height in pixels

  • seed – Random seed for dataset splitting

  • val_split – Proportion of data to use for validation

  • batch_size – Batch size for datasets

Returns:

Tuple containing training and validation datasets

aigarmic.predict_colony_images_from_directory(directory: str | pathlib.Path | None, model: tensorflow.keras.models.Model, class_names: list[str], image_width: int, image_height: int, model_type: str, save_path: str | pathlib.Path | None = None, binary_threshold: float = 0.5) list[dict][source]

Predict the class of images in a directory using a trained model, and compare prediction to true class (based on subdirectory in which image is located, which should correspond to class name).

Parameters:
  • directory – Directory containing images to predict

  • model – Model to use for prediction

  • class_names – List of class names

  • image_width – Image width in pixels

  • image_height – Image height in pixels

  • model_type – “binary” or “softmax”

  • save_path – Path to save prediction log

  • binary_threshold – For binary models, threshold for classifying as positive

Returns:

List of dictionaries containing image, path, prediction, predicted class, and true class (for each image)

aigarmic.save_training_log(model_history: keras.callbacks.History, save_path: str | pathlib.Path) None[source]

Save training log to CSV file

Parameters:
  • model_history – Training history object

  • save_path – Directory to save training log

aigarmic.get_paths_from_directory(path: str | pathlib.Path) dict[str, list[str]][source]

Returns a dict of abx_names: [image1_path, image2_path, etc.] If there are no antibiotic subdirectories, “unnamed” is used for abx_names (length = 1)

Parameters:

path – Path to directory containing antibiotic subdirectories

Returns:

dict of abx_names: [image1_path, image2_path, etc.]

aigarmic.get_concentration_from_path(path: str | pathlib.Path) float[source]

get concentration from plate image path, e.g. antibiotic1/0.125.jpg -> 0.125

Parameters:

path – Path to plate image

Returns:

Concentration

aigarmic.convert_cv2_to_keras(image, size_x=160, size_y=160) numpy.ndarray[source]

Convert a cv2 image to a keras image

Parameters:
  • image – Image loaded using cv2.imread

  • size_x – Width to resize image to (pixels)

  • size_y – Height to resize image to (pixels)

Returns:

Image as a numpy array

aigarmic.keras_image_to_cv2(image: tensorflow.Tensor) numpy.ndarray[source]

Convert a keras image to a cv2 image

Parameters:

image – Image as a tensor

Returns:

Image as a numpy array

aigarmic.find_threshold_value(image: numpy.ndarray, look_for: int, start: int = 20, end: int = 100, by: int = 1, area_lower_bound: int = 1000) tuple[list, int] | None[source]

Find threshold value that correctly splits an agar plate image into colony sub-images. Assumes that a black grid overlays the image. :param image: Image file loaded using cv2.imread :param look_for: target sub-images :param start: starting threshold value :param end: ending threshold value :param by: threshold increment value :param area_lower_bound: minimum area for a contour to be considered :return: tuple of contours and threshold value

aigarmic.split_by_grid(image: numpy.ndarray, n_rows: int, n_cols: int, visualise_contours: bool = False, plate_name: str | None = None) list[list[numpy.ndarray]][source]

Split an agar plate image into individual colony sub-images using a grid overlay.

Parameters:
  • image – image file loaded using cv2.imread

  • n_rows – number of rows in the grid

  • n_cols – number of columns in the grid

  • visualise_contours – if True, display the contours found (useful for validation)

  • plate_name – name of plate to display in visualisation (useful for validation)

Returns:

matrix of sub-images

aigarmic.train_binary(annotations_path, model_design: tensorflow.keras.models.Sequential, val_split: float = 0.2, image_width: int = 160, image_height: int = 160, batch_size: int = 64, epochs: int = 300, stop_training_threshold: float = 0.98, learning_rate: float = 0.0001) tuple[tensorflow.keras.models.Sequential, list[str], keras.callbacks.History, list][source]

Train a binary classification model to differentiate between two classes of colony images. Provide a keras sequential model design to inform the neural network architecture. The final binary/sigmoid layer should not be included in the sequential model design, as this is added by the function.

Parameters:
  • annotations_path – Path to directory containing annotated images, with subdirectories for each class (usually ‘0’ and ‘1’)

  • model_design – Keras model design (Sequential) to inform neural network architecture, excluding final layer

  • val_split – Validation split proportion

  • image_width – Image width (pixels)

  • image_height – Image height (pixels)

  • batch_size – Training batch size

  • epochs – Max number of training epochs

  • stop_training_threshold – Accuracy threshold at which to accept model and stop training

  • learning_rate – Learning rate for the optimizer

Returns:

Tuple containing trained model, class names, training history, and evaluation results

aigarmic.train_softmax(annotations_path, model_design: tensorflow.keras.models.Sequential, val_split: float = 0.2, image_height: int = 160, image_width: int = 160, batch_size: int = 64, epochs: int = 300, stop_training_threshold: float = 0.98) tuple[tensorflow.keras.models.Sequential, list[str], keras.callbacks.History, list][source]

Train a softmax classification model to differentiate between multiple classes (2 or more) of colony images. The final softmax layer should not be included in the sequential model design, as this is added by the function.

Parameters:
  • annotations_path – Path to directory containing annotated images, with subdirectories for each class (e.g., ‘0’, ‘1’, ‘2’, …)

  • model_design – Keras model design (Sequential) to inform neural network architecture, excluding final layer

  • val_split – Validation split proportion

  • image_width – Image width (pixels)

  • image_height – Image height (pixels)

  • batch_size – Training batch size

  • epochs – Max number of training epochs

  • stop_training_threshold – Accuracy threshold at which to accept model and stop training

Returns:

Tuple containing trained model, class names, training history, and evaluation results

aigarmic.visualise_training(history: keras.callbacks.History) None[source]

Visualise training and validation accuracy and loss over epochs.

Parameters:

history – Training history object (usually returned by model.fit(), train_binary(), or train_softmax())