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.