Source code for derotation.analysis.blob_detection

"""
This module contains the BlobDetection class, which is used to detect the
largest blob in each image of an image stack.
The class uses the ``blob_log`` function from the
skimage.feature module to detect the blobs. The coordinates of the largest
blob in each image are returned as a numpy array. The class also has a method
to plot the first 4 blobs in each image, which is useful for debugging
purposes.
"""

import logging
from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np
from skimage.feature import blob_log
from tqdm import tqdm


[docs] class BlobDetection: """ The BlobDetection class is used to detect the largest blob in each image of an image stack. Parameters ---------- debugging_plots : bool, optional Whether to create debugging plots, by default False debug_plots_folder : Path, optional The folder to save the debugging plots, by default None blob_log_params : dict, optional The parameters for the blob detection, by default {"max_sigma": 12, "min_sigma": 7, "threshold": 0.95, "overlap": 0} which are the parameters that worked best for the 3-photon data. """ def __init__( self, debugging_plots: bool = False, debug_plots_folder: Path = Path("debug"), blob_log_params: dict = { "max_sigma": 12, "min_sigma": 7, "threshold": 0.95, "overlap": 0, }, ): """Initializes the BlobDetection class.""" self.debugging_plots = debugging_plots self.debug_plots_folder = debug_plots_folder self.blob_log_params = blob_log_params
[docs] def get_coords_of_largest_blob( self, image_stack: np.ndarray ) -> np.ndarray: """Get the coordinates of the largest blob in each image. Parameters ---------- image_stack : np.ndarray The image stack. Returns ------- np.ndarray The coordinates of the largest blob in each image. """ blobs = [ blob_log(img, **self.blob_log_params) for img in tqdm(image_stack) ] # sort blobs by size blobs = [ blobs[i][blobs[i][:, 2].argsort()] for i in range(len(image_stack)) ] coord_first_blob_of_every_image = [] for i, blob in enumerate(blobs): if len(blob) > 0: coord_first_blob_of_every_image.append(blob[0][:2].astype(int)) else: coord_first_blob_of_every_image.append([np.nan, np.nan]) logging.warning(f"No blobs were found in image {i}") # invert x, y order coord_first_blob_of_every_image = [ (coord[1], coord[0]) for coord in coord_first_blob_of_every_image ] # plot blobs on top of every frame if self.debugging_plots: self.plot_blob_detection(blobs, image_stack) return np.asarray(coord_first_blob_of_every_image)
[docs] def plot_blob_detection(self, blobs: list, image_stack: np.ndarray): """Plot the first 4 blobs in each image. This is useful to check if the blob detection is working correctly and to see if the identity of the largest blob is consistent across the images. Parameters ---------- blobs : list The list of blobs in each image. image_stack : np.ndarray The image stack. """ fig, ax = plt.subplots(4, 3, figsize=(10, 10)) for i, a in tqdm(enumerate(ax.flatten())): a.imshow(image_stack[i]) a.set_title(f"{i * 5} degrees") a.axis("off") for j, blob in enumerate(blobs[i][:4]): y, x, r = blob c = plt.Circle((x, y), r, color="red", linewidth=2, fill=False) a.add_patch(c) a.text(x, y, str(j), color="red") # save the plot Path(self.debug_plots_folder).mkdir(parents=True, exist_ok=True) plt.savefig(self.debug_plots_folder / "blobs.png") plt.close()