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