Skip to content
Snippets Groups Projects
Commit 79fd48c2 authored by s212246's avatar s212246 Committed by fima
Browse files

3d blob detection - Difference of Gaussian (DoG) method

parent 54f01426
No related branches found
No related tags found
1 merge request!583d blob detection - Difference of Gaussian (DoG) method
import qim3d.io as io
import qim3d.gui as gui
import qim3d.viz as viz
import qim3d.utils as utils
import qim3d.models as models
import qim3d.processing as processing
# import qim3d.io as io
# import qim3d.gui as gui
# import qim3d.viz as viz
# import qim3d.utils as utils
# import qim3d.models as models
# import qim3d.processing as processing
from . import io, gui, viz, utils, models, processing
import logging
__version__ = '0.3.2'
......
from .filters import *
from .local_thickness import local_thickness
from .detection import *
import numpy as np
from qim3d.io.logger import log
from skimage.feature import blob_dog
__all__ = ["Blob"]
class Blob:
def __init__(
self,
background="dark",
min_sigma=1,
max_sigma=50,
sigma_ratio=1.6,
threshold=0.5,
overlap=0.5,
threshold_rel=None,
exclude_border=False,
):
"""
Initialize the blob detection object
Args:
background: 'dark' if background is darker than the blobs, 'bright' if background is lighter than the blobs
min_sigma: The minimum standard deviation for Gaussian kernel
max_sigma: The maximum standard deviation for Gaussian kernel
sigma_ratio: The ratio between the standard deviation of Gaussian Kernels
threshold: The absolute lower bound for scale space maxima. Reduce this to detect blobs with lower intensities.
overlap: The fraction of area of two blobs that overlap
threshold_rel: The relative lower bound for scale space maxima
exclude_border: If True, exclude blobs that are too close to the border of the image
"""
self.background = background
self.min_sigma = min_sigma
self.max_sigma = max_sigma
self.sigma_ratio = sigma_ratio
self.threshold = threshold
self.overlap = overlap
self.threshold_rel = threshold_rel
self.exclude_border = exclude_border
self.vol_shape = None
self.blobs = None
def detect(self, vol):
"""
Detect blobs in the volume
Args:
vol: The volume to detect blobs in
Returns:
blobs: The blobs found in the volume as (p, r, c, radius)
"""
self.vol_shape = vol.shape
if self.background == "bright":
log.info("Bright background selected, volume will be inverted.")
vol = np.invert(vol)
blobs = blob_dog(
vol,
min_sigma=self.min_sigma,
max_sigma=self.max_sigma,
sigma_ratio=self.sigma_ratio,
threshold=self.threshold,
overlap=self.overlap,
threshold_rel=self.threshold_rel,
exclude_border=self.exclude_border,
)
blobs[:, 3] = blobs[:, 3] * np.sqrt(3) # Change sigma to radius
self.blobs = blobs
return self.blobs
def get_mask(self):
'''
Retrieve a binary volume with the blobs marked as True
Returns:
binary_volume: A binary volume with the blobs marked as True
'''
binary_volume = np.zeros(self.vol_shape, dtype=bool)
for z, y, x, radius in self.blobs:
# Calculate the bounding box around the blob
z_start = max(0, int(z - radius))
z_end = min(self.vol_shape[0], int(z + radius) + 1)
y_start = max(0, int(y - radius))
y_end = min(self.vol_shape[1], int(y + radius) + 1)
x_start = max(0, int(x - radius))
x_end = min(self.vol_shape[2], int(x + radius) + 1)
z_indices, y_indices, x_indices = np.indices((z_end - z_start, y_end - y_start, x_end - x_start))
z_indices += z_start
y_indices += y_start
x_indices += x_start
# Calculate distances from the center of the blob to voxels within the bounding box
dist = np.sqrt((x_indices - x)**2 + (y_indices - y)**2 + (z_indices - z)**2)
binary_volume[z_start:z_end, y_start:y_end, x_start:x_end][dist <= radius] = True
return binary_volume
from .visualizations import plot_metrics
from .img import grid_pred, grid_overview, slices, slicer, orthogonal, plot_cc, local_thickness
from .k3d import vol
from .detection import circles
\ No newline at end of file
import matplotlib.pyplot as plt
from qim3d.viz import slices
from qim3d.io.logger import log
import numpy as np
import ipywidgets as widgets
from IPython.display import clear_output, display
def circles(blobs, vol, alpha=0.5, color="#ff9900", **kwargs):
"""
Plots the blobs found on a slice of the volume.
This function takes in a 3D volume and a list of blobs (detected features)
and plots the blobs on a specified slice of the volume. If no slice is specified,
it defaults to the middle slice of the volume.
Args:
blobs (array-like): An array-like object of blobs, where each blob is represented
as a 4-tuple (p, r, c, radius). Usally the result of qim3d.processing.detection.Blob()
vol (array-like): The 3D volume on which to plot the blobs.
z_slice (int, optional): The index of the slice to plot. If not provided, the middle slice is used.
**kwargs: Arbitrary keyword arguments for the `slices` function.
Returns:
matplotlib.figure.Figure: The resulting figure after adding the blobs to the slice.
"""
def _slicer(z_slice):
clear_output(wait=True)
fig = slices(
vol,
n_slices=1,
position=z_slice,
img_height=3,
img_width=3,
cmap="gray",
show_position=False,
)
# Add circles from deteced blobs
for detected in blobs:
z, y, x, s = detected
if abs(z - z_slice) < s: # The blob is in the slice
# Adjust the radius based on the distance from the center of the sphere
distance_from_center = abs(z - z_slice)
angle = (
np.pi / 2 * (distance_from_center / s)
) # Angle varies from 0 at the center to pi/2 at the edge
adjusted_radius = s * np.cos(angle) # Radius follows a cosine curve
if adjusted_radius > 0.5:
c = plt.Circle(
(x, y),
adjusted_radius,
color=color,
linewidth=0,
fill=True,
alpha=alpha,
)
fig.get_axes()[0].add_patch(c)
display(fig)
return fig
position_slider = widgets.IntSlider(
value=vol.shape[0] // 2,
min=0,
max=vol.shape[0] - 1,
description="Slice",
continuous_update=True,
)
slicer_obj = widgets.interactive(_slicer, z_slice=position_slider)
slicer_obj.layout = widgets.Layout(align_items="flex-start")
return slicer_obj
......@@ -399,7 +399,7 @@ def slicer(
img_height: int = 3,
img_width: int = 3,
show_position: bool = False,
interpolation: Optional[str] = None,
interpolation: Optional[str] = "none",
) -> widgets.interactive:
"""Interactive widget for visualizing slices of a 3D volume.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment