nanopyx.core.generate.beads

  1import numpy as np
  2from math import sqrt
  3from skimage.filters import gaussian
  4from skimage.transform import EuclideanTransform, warp
  5
  6from ..transform.blocks import assemble_frame_from_blocks
  7
  8
  9def generate_random_position(n_rows, n_cols):
 10    """
 11    Generates a random position given number of rows and columns.
 12    :param n_rows: int; number of rows
 13    :param n_cols: int; number of columns
 14    :return: int, int; random position constrained to 0.1 and 0.9 of n_rows and n_cols
 15    """
 16
 17    min_r = int(n_rows * 0.1)
 18    max_r = int(n_rows * 0.9)
 19
 20    min_c = int(n_cols * 0.1)
 21    max_c = int(n_cols * 0.9)
 22
 23    r = np.random.randint(min_r, max_r)
 24    c = np.random.randint(min_c, max_c)
 25
 26    return r, c
 27
 28
 29def generate_image(n_objects=10, shape=(2, 300, 300), dtype=np.float16):
 30    """
 31    Generates a random image with objects in random positions
 32    :param n_objects: int; number of objects to generate
 33    :param shape: tuple; with shape (z, y, x)
 34    :param dtype: data type to be used in the generated numpy array
 35    :return: numpy array with shape (z, y, x) and defined data type and n_objects
 36    """
 37
 38    img = np.zeros(shape).astype(dtype)
 39
 40    n_rows = img.shape[1]
 41    n_cols = img.shape[2]
 42
 43    for i in range(n_objects):
 44        r, c = generate_random_position(n_rows, n_cols)
 45        img[:, r, c] = np.finfo(np.float16).max
 46
 47    for i in range(img.shape[0]):
 48        img[i] = gaussian(img[i], sigma=3)
 49
 50    return img
 51
 52
 53def generate_timelapse_drift(
 54    n_objects=10, shape=(10, 300, 300), dtype=np.float16, drift=None, drift_mode="directional"
 55):
 56    """
 57    Generate random timelapse image with drift over time.
 58    :param n_objects: int; number of objects to generate
 59    :param shape: tuple; with shape (t, y, x)
 60    :param dtype: data type to be used in the generated numpy array
 61    :param drift: None or int; number of pixels corresponding to drift between frames. If None, automatic drift is
 62    calculated based on 0.02 of image dimensions.
 63    :param drift_mode: str; "directional" (default) or "random";
 64    :return: numpy array with shape (t, y, x) and defined data type and n_objects
 65    """
 66
 67    if drift is None:
 68        drift = min(shape[1] * 0.02, shape[2] * 0.02)
 69
 70    img = generate_image(n_objects=n_objects, shape=shape, dtype=dtype)
 71
 72    if drift_mode == "directional":
 73        transformation_matrix = EuclideanTransform(translation=(-drift, -drift))
 74        for i in range(shape[0] - 1):
 75            img[i + 1] = warp(img[i], transformation_matrix.inverse, order=3, preserve_range=True)
 76
 77    elif drift_mode == "random":
 78        for i in range(shape[0] - 1):
 79            state = np.random.randint(0, 3)
 80
 81            if state == 1:
 82                transformation_matrix = EuclideanTransform(translation=(-sqrt(drift), -sqrt(drift)))
 83            elif state == 2:
 84                transformation_matrix = EuclideanTransform(translation=(-sqrt(drift), sqrt(drift)))
 85            elif state == 3:
 86                transformation_matrix = EuclideanTransform(translation=(sqrt(drift), -sqrt(drift)))
 87            else:
 88                transformation_matrix = EuclideanTransform(translation=(sqrt(drift), sqrt(drift)))
 89
 90            img[i + 1] = warp(img[i], transformation_matrix.inverse, order=3, preserve_range=True)
 91
 92    return img.astype(np.float32)
 93
 94
 95def generate_channel_misalignment():
 96    """
 97    Generates an image with shape (3, 300, 300) with 1 object centered on each 3x3 block of the image.
 98    Slices corresponding to channel 2 and 3 are shifted relative to channel 1 (template).
 99    :return: numpy array of shape (3, 300, 300) corresponding to a random image with misalignment between channels.
100    """
101
102    n_blocks = 3
103    h = 300
104    w = 300
105
106    block_img = np.zeros((int(h / n_blocks), int(w / n_blocks)))
107    block_h = int(h / n_blocks)
108    block_w = int(w / n_blocks)
109    block_img[int(block_h / 2), int(block_w / 2)] = 1
110    block_img = gaussian(block_img, sigma=3)
111
112    ref_channel = np.zeros((h, w))
113    misaligned_blocks = []
114    misaligned_blocks_2 = []
115
116    for x_i in range(n_blocks):
117        for y_i in range(n_blocks):
118            ref_channel[y_i * block_h : y_i * block_h + block_h, x_i * block_w : x_i * block_w + block_w] += block_img
119
120    misalignments = [(-3, -3), (-3, 0), (-3, 3), (0, -3), (0, 0), (0, 3), (3, -3), (3, 0), (3, 3)]
121
122    for mis in misalignments:
123        block_img = np.zeros((int(h / n_blocks), int(w / n_blocks)))
124        block_h = h / n_blocks
125        block_w = w / n_blocks
126        block_img[int(block_h / 2) + mis[0], int(block_w / 2) + mis[1]] = 1
127        block_img = gaussian(block_img, sigma=3)
128        misaligned_blocks.append(block_img)
129
130    misalignments.reverse()
131
132    for mis in misalignments:
133        block_img = np.zeros((int(h / n_blocks), int(w / n_blocks)))
134        block_h = h / n_blocks
135        block_w = w / n_blocks
136        block_img[int(block_h / 2) + mis[0], int(block_w / 2) + mis[1]] = 1
137        block_img = gaussian(block_img, sigma=3)
138        misaligned_blocks_2.append(block_img)
139
140    misaligned_channel = assemble_frame_from_blocks(np.array(misaligned_blocks), 3, 3)
141    misaligned_channel_2 = assemble_frame_from_blocks(np.array(misaligned_blocks_2), 3, 3)
142
143    return np.array([ref_channel, misaligned_channel, misaligned_channel_2]).astype(np.float32)
def generate_random_position(n_rows, n_cols):
10def generate_random_position(n_rows, n_cols):
11    """
12    Generates a random position given number of rows and columns.
13    :param n_rows: int; number of rows
14    :param n_cols: int; number of columns
15    :return: int, int; random position constrained to 0.1 and 0.9 of n_rows and n_cols
16    """
17
18    min_r = int(n_rows * 0.1)
19    max_r = int(n_rows * 0.9)
20
21    min_c = int(n_cols * 0.1)
22    max_c = int(n_cols * 0.9)
23
24    r = np.random.randint(min_r, max_r)
25    c = np.random.randint(min_c, max_c)
26
27    return r, c

Generates a random position given number of rows and columns.

Parameters
  • n_rows: int; number of rows
  • n_cols: int; number of columns
Returns

int, int; random position constrained to 0.1 and 0.9 of n_rows and n_cols

def generate_image(n_objects=10, shape=(2, 300, 300), dtype=<class 'numpy.float16'>):
30def generate_image(n_objects=10, shape=(2, 300, 300), dtype=np.float16):
31    """
32    Generates a random image with objects in random positions
33    :param n_objects: int; number of objects to generate
34    :param shape: tuple; with shape (z, y, x)
35    :param dtype: data type to be used in the generated numpy array
36    :return: numpy array with shape (z, y, x) and defined data type and n_objects
37    """
38
39    img = np.zeros(shape).astype(dtype)
40
41    n_rows = img.shape[1]
42    n_cols = img.shape[2]
43
44    for i in range(n_objects):
45        r, c = generate_random_position(n_rows, n_cols)
46        img[:, r, c] = np.finfo(np.float16).max
47
48    for i in range(img.shape[0]):
49        img[i] = gaussian(img[i], sigma=3)
50
51    return img

Generates a random image with objects in random positions

Parameters
  • n_objects: int; number of objects to generate
  • shape: tuple; with shape (z, y, x)
  • dtype: data type to be used in the generated numpy array
Returns

numpy array with shape (z, y, x) and defined data type and n_objects

def generate_timelapse_drift( n_objects=10, shape=(10, 300, 300), dtype=<class 'numpy.float16'>, drift=None, drift_mode='directional'):
54def generate_timelapse_drift(
55    n_objects=10, shape=(10, 300, 300), dtype=np.float16, drift=None, drift_mode="directional"
56):
57    """
58    Generate random timelapse image with drift over time.
59    :param n_objects: int; number of objects to generate
60    :param shape: tuple; with shape (t, y, x)
61    :param dtype: data type to be used in the generated numpy array
62    :param drift: None or int; number of pixels corresponding to drift between frames. If None, automatic drift is
63    calculated based on 0.02 of image dimensions.
64    :param drift_mode: str; "directional" (default) or "random";
65    :return: numpy array with shape (t, y, x) and defined data type and n_objects
66    """
67
68    if drift is None:
69        drift = min(shape[1] * 0.02, shape[2] * 0.02)
70
71    img = generate_image(n_objects=n_objects, shape=shape, dtype=dtype)
72
73    if drift_mode == "directional":
74        transformation_matrix = EuclideanTransform(translation=(-drift, -drift))
75        for i in range(shape[0] - 1):
76            img[i + 1] = warp(img[i], transformation_matrix.inverse, order=3, preserve_range=True)
77
78    elif drift_mode == "random":
79        for i in range(shape[0] - 1):
80            state = np.random.randint(0, 3)
81
82            if state == 1:
83                transformation_matrix = EuclideanTransform(translation=(-sqrt(drift), -sqrt(drift)))
84            elif state == 2:
85                transformation_matrix = EuclideanTransform(translation=(-sqrt(drift), sqrt(drift)))
86            elif state == 3:
87                transformation_matrix = EuclideanTransform(translation=(sqrt(drift), -sqrt(drift)))
88            else:
89                transformation_matrix = EuclideanTransform(translation=(sqrt(drift), sqrt(drift)))
90
91            img[i + 1] = warp(img[i], transformation_matrix.inverse, order=3, preserve_range=True)
92
93    return img.astype(np.float32)

Generate random timelapse image with drift over time.

Parameters
  • n_objects: int; number of objects to generate
  • shape: tuple; with shape (t, y, x)
  • dtype: data type to be used in the generated numpy array
  • drift: None or int; number of pixels corresponding to drift between frames. If None, automatic drift is calculated based on 0.02 of image dimensions.
  • drift_mode: str; "directional" (default) or "random";
Returns

numpy array with shape (t, y, x) and defined data type and n_objects

def generate_channel_misalignment():
 96def generate_channel_misalignment():
 97    """
 98    Generates an image with shape (3, 300, 300) with 1 object centered on each 3x3 block of the image.
 99    Slices corresponding to channel 2 and 3 are shifted relative to channel 1 (template).
100    :return: numpy array of shape (3, 300, 300) corresponding to a random image with misalignment between channels.
101    """
102
103    n_blocks = 3
104    h = 300
105    w = 300
106
107    block_img = np.zeros((int(h / n_blocks), int(w / n_blocks)))
108    block_h = int(h / n_blocks)
109    block_w = int(w / n_blocks)
110    block_img[int(block_h / 2), int(block_w / 2)] = 1
111    block_img = gaussian(block_img, sigma=3)
112
113    ref_channel = np.zeros((h, w))
114    misaligned_blocks = []
115    misaligned_blocks_2 = []
116
117    for x_i in range(n_blocks):
118        for y_i in range(n_blocks):
119            ref_channel[y_i * block_h : y_i * block_h + block_h, x_i * block_w : x_i * block_w + block_w] += block_img
120
121    misalignments = [(-3, -3), (-3, 0), (-3, 3), (0, -3), (0, 0), (0, 3), (3, -3), (3, 0), (3, 3)]
122
123    for mis in misalignments:
124        block_img = np.zeros((int(h / n_blocks), int(w / n_blocks)))
125        block_h = h / n_blocks
126        block_w = w / n_blocks
127        block_img[int(block_h / 2) + mis[0], int(block_w / 2) + mis[1]] = 1
128        block_img = gaussian(block_img, sigma=3)
129        misaligned_blocks.append(block_img)
130
131    misalignments.reverse()
132
133    for mis in misalignments:
134        block_img = np.zeros((int(h / n_blocks), int(w / n_blocks)))
135        block_h = h / n_blocks
136        block_w = w / n_blocks
137        block_img[int(block_h / 2) + mis[0], int(block_w / 2) + mis[1]] = 1
138        block_img = gaussian(block_img, sigma=3)
139        misaligned_blocks_2.append(block_img)
140
141    misaligned_channel = assemble_frame_from_blocks(np.array(misaligned_blocks), 3, 3)
142    misaligned_channel_2 = assemble_frame_from_blocks(np.array(misaligned_blocks_2), 3, 3)
143
144    return np.array([ref_channel, misaligned_channel, misaligned_channel_2]).astype(np.float32)

Generates an image with shape (3, 300, 300) with 1 object centered on each 3x3 block of the image. Slices corresponding to channel 2 and 3 are shifted relative to channel 1 (template).

Returns

numpy array of shape (3, 300, 300) corresponding to a random image with misalignment between channels.