This notebook shows how to detect hot spots / local maxima / beads in an image and how to measure their FWHM. To make the algorithm work, the beads should be sufficiently sparse.
import pyclesperanto_prototype as cle
cle.get_device()
<Intel(R) Iris(R) Xe Graphics on Platform: Intel(R) OpenCL HD Graphics (1 refs)>
Let's start by making an image showing local maxima.
import numpy as np
from skimage.io import imshow
random_image = np.random.random([512,512])
binary_image = random_image > 0.9995
# push to GPU
input_image = cle.push(binary_image * random_image)
# blur the image
sigma = 3
starting_point = cle.gaussian_blur(input_image, sigma_x=sigma, sigma_y=sigma)
# show input image
starting_point
|
cle._ image
|
maxima = cle.detect_maxima_box(starting_point)
maxima
|
cle._ image
|
# Label maxima
labeled_maxima = cle.label_spots(maxima)
# read out intensities at the maxima
max_intensities = cle.read_intensities_from_map(labeled_maxima, starting_point)
print(max_intensities)
# calculate thresholds
thresholds = cle.multiply_image_and_scalar(max_intensities, scalar=0.5)
print(thresholds)
[[0. 0. 0.07530212 0.01768412 0.01768251 0.01768345 0.01768355 0.01767614 0.01768117 0.01768287 0.01767613 0.01767726 0.0176767 0.01767617 0.01770093 0.01768188 0.01769348 0.01768091 0.01768291 0.01767742 0.01767924 0.01767959 0.02023154 0.01767629 0.02023292 0.01767845 0.01767934 0.01768218 0.01767849 0.01767824 0.01768037 0.01767676 0.01767627 0.01768442 0.01767656 0.01768143 0.01768095 0.01768311 0.01783455 0.01767915 0.01783821 0.01768428 0.01767994 0.01768341 0.01767852 0.01768236 0.01768361 0.0176807 0.01768154 0.01767861 0.01767618 0.01767758 0.0176818 0.01768077 0.01767783 0.01768455 0.01768431 0.01767913 0.01767841 0.01768026 0.01768074 0.03163752 0.01798327 0.01768441 0.01768178 0.01767889 0.01798355 0.01768068 0.01768451 0.01768157 0.01767765 0.01768141 0.01768202 0.01767992 0.01768101 0.01767624 0.01768075 0.01768441 0.01768228 0.01768184 0.01767698 0.01768225 0.01768155 0.01767988 0.01767623 0.01768425 0.01768363 0.01767961 0.0176793 0.01767695 0.01768461 0.01768289 0.01767971 0.01768343 0.01768206 0.01768321 0.01768432 0.01768064 0.01768478 0.0176841 0.01768007 0.01767708 0.01768336 0.01768466 0.01770931 0.01788014 0.01787417 0.01771322 0.0176796 0.01767668 0.01767627 0.01768447 0.01767644 0.01768418 0.01768373 0.01768188 0.02103141 0.01768014 0.0210342 0.01767998 0.01767747 0.02028995 0.01767968 0.07532293]] [[0. 0. 0.03765106 0.00884206 0.00884125 0.00884173 0.00884178 0.00883807 0.00884058 0.00884144 0.00883806 0.00883863 0.00883835 0.00883809 0.00885046 0.00884094 0.00884674 0.00884045 0.00884145 0.00883871 0.00883962 0.00883979 0.01011577 0.00883814 0.01011646 0.00883923 0.00883967 0.00884109 0.00883925 0.00883912 0.00884018 0.00883838 0.00883813 0.00884221 0.00883828 0.00884072 0.00884047 0.00884156 0.00891728 0.00883957 0.0089191 0.00884214 0.00883997 0.0088417 0.00883926 0.00884118 0.00884181 0.00884035 0.00884077 0.00883931 0.00883809 0.00883879 0.0088409 0.00884039 0.00883892 0.00884228 0.00884215 0.00883956 0.00883921 0.00884013 0.00884037 0.01581876 0.00899163 0.00884221 0.00884089 0.00883945 0.00899178 0.00884034 0.00884226 0.00884078 0.00883882 0.0088407 0.00884101 0.00883996 0.00884051 0.00883812 0.00884037 0.00884221 0.00884114 0.00884092 0.00883849 0.00884112 0.00884077 0.00883994 0.00883812 0.00884212 0.00884181 0.00883981 0.00883965 0.00883847 0.00884231 0.00884144 0.00883986 0.00884171 0.00884103 0.00884161 0.00884216 0.00884032 0.00884239 0.00884205 0.00884004 0.00883854 0.00884168 0.00884233 0.00885465 0.00894007 0.00893709 0.00885661 0.0088398 0.00883834 0.00883813 0.00884224 0.00883822 0.00884209 0.00884187 0.00884094 0.01051571 0.00884007 0.0105171 0.00883999 0.00883874 0.01014498 0.00883984 0.03766147]]
# Extend labeled maxima until they touch
voronoi_label_image = cle.extend_labeling_via_voronoi(labeled_maxima)
voronoi_label_image
|
cle._ image
|
# Replace labels with thresholds
threshold_image = cle.replace_intensities(voronoi_label_image, thresholds)
threshold_image
|
cle._ image
|
# Apply threshold
binary_segmented = cle.greater(starting_point, threshold_image)
binary_segmented
|
cle._ image
|
# Label objects
labels = cle.connected_components_labeling_box(binary_segmented)
labels
|
cle._ image
|
# Derive statistics
stats = cle.statistics_of_labelled_pixels(label_image=labels)
print('Bounding box widths', stats['bbox_width'])
print('Bounding box heights', stats['bbox_height'])
Bounding box widths [ 7. 16. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 11. 7. 7. 7. 7. 7. 7. 15. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 13. 14. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 8. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7.] Bounding box heights [ 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 12. 7. 7. 7. 7. 7. 7. 10. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 9. 13. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 13. 7. 7. 7. 7. 7. 3. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7. 3. 7. 7. 7. 7. 7. 7. 7. 7. 7. 7.]
The bounding box width and height should be approximately twice as large as the sigma used for bluring the image at the very beginning.
print("Sigma", sigma)
Sigma 3