small-fish-gui 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,334 @@
1
+ """
2
+ Contains cellpose wrappers to segmentate images.
3
+ """
4
+
5
+ from cellpose.core import use_gpu
6
+ from skimage.measure import label
7
+ from ..gui.layout import _segmentation_layout
8
+ from ..gui import prompt, prompt_with_help, ask_cancel_segmentation
9
+
10
+ import cellpose.models as models
11
+ import numpy as np
12
+ import bigfish.multistack as multistack
13
+ import bigfish.stack as stack
14
+ import bigfish.plot as plot
15
+ import PySimpleGUI as sg
16
+ import os
17
+
18
+ def launch_segmentation(image: np.ndarray, user_parameters: dict) :
19
+ """
20
+ Ask user for necessary parameters and perform cell segmentation (cytoplasm + nucleus) with cellpose.
21
+
22
+ Input
23
+ -----
24
+ Image : np.ndarray[c,z,y,x]
25
+ Image to use for segmentation.
26
+
27
+ Returns
28
+ -------
29
+ cytoplasm_label, nucleus_label
30
+ """
31
+
32
+ while True : # Loop if show_segmentation
33
+ #Default parameters
34
+ cyto_model_name = user_parameters.setdefault('cyto_model_name', 'cyto2')
35
+ cyto_size = user_parameters.setdefault('cytoplasm diameter', 180)
36
+ cytoplasm_channel = user_parameters.setdefault('cytoplasm channel', 0)
37
+ nucleus_model_name = user_parameters.setdefault('nucleus_model_name', 'nuclei')
38
+ nucleus_size = user_parameters.setdefault('nucleus diameter', 130)
39
+ nucleus_channel = user_parameters.setdefault('nucleus channel', 0)
40
+ path = os.getcwd()
41
+ show_segmentation = user_parameters.setdefault('show segmentation', False)
42
+ segment_only_nuclei = user_parameters.setdefault('Segment only nuclei', False)
43
+ filename = user_parameters['filename']
44
+ available_channels = list(range(image.shape[0]))
45
+
46
+
47
+ #Ask user for parameters
48
+ #if incorrect parameters --> set relaunch to True
49
+ while True :
50
+ layout = _segmentation_layout(
51
+ cytoplasm_model_preset = cyto_model_name,
52
+ cytoplasm_channel_preset= cytoplasm_channel,
53
+ nucleus_model_preset = nucleus_model_name,
54
+ nucleus_channel_preset= nucleus_channel,
55
+ cyto_diameter_preset= cyto_size,
56
+ nucleus_diameter_preset= nucleus_size,
57
+ saving_path_preset= path,
58
+ show_segmentation_preset=show_segmentation,
59
+ segment_only_nuclei_preset=segment_only_nuclei,
60
+ filename_preset=filename,
61
+ )
62
+
63
+ event, values = prompt_with_help(layout, help='segmentation')
64
+ if event == 'Cancel' :
65
+ cancel_segmentation = ask_cancel_segmentation()
66
+
67
+ if cancel_segmentation :
68
+ return None, None, user_parameters
69
+ else :
70
+ continue
71
+
72
+ #Extract parameters
73
+ values = _cast_segmentation_parameters(values)
74
+ do_only_nuc = values['Segment only nuclei']
75
+ cyto_model_name = values['cyto_model_name']
76
+ cyto_size = values['cytoplasm diameter']
77
+ cytoplasm_channel = values['cytoplasm channel']
78
+ nucleus_model_name = values['nucleus_model_name']
79
+ nucleus_size = values['nucleus diameter']
80
+ nucleus_channel = values['nucleus channel']
81
+ path = values['saving path'] if values['saving path'] != '' else None
82
+ show_segmentation = values['show segmentation']
83
+ filename = values['filename'] if type(path) != type(None) else None
84
+ channels = [cytoplasm_channel, nucleus_channel]
85
+
86
+ relaunch= False
87
+ #Checking integrity of parameters
88
+ if type(cyto_model_name) != str and not do_only_nuc:
89
+ sg.popup('Invalid cytoplasm model name.')
90
+ values['cyto_model_name'] = user_parameters.setdefault('cyto_model_name', 'cyto2')
91
+ relaunch= True
92
+ if cytoplasm_channel not in available_channels and not do_only_nuc:
93
+ sg.popup('For given input image please select channel in {0}\ncytoplasm channel : {1}'.format(available_channels, cytoplasm_channel))
94
+ relaunch= True
95
+ values['cytoplasm channel'] = user_parameters.setdefault('cytoplasm channel',0)
96
+
97
+ if type(cyto_size) not in [int, float] and not do_only_nuc:
98
+ sg.popup("Incorrect cytoplasm size.")
99
+ relaunch= True
100
+ values['cytoplasm diameter'] = user_parameters.setdefault('diameter', 30)
101
+
102
+ if type(nucleus_model_name) != str :
103
+ sg.popup('Invalid nucleus model name.')
104
+ values['nucleus_model_name'] = user_parameters.setdefault('nucleus_model_name', 'nuclei')
105
+ relaunch= True
106
+ if nucleus_channel not in available_channels :
107
+ sg.popup('For given input image please select channel in {0}\nnucleus channel : {1}'.format(available_channels, nucleus_channel))
108
+ relaunch= True
109
+ values['nucleus channel'] = user_parameters.setdefault('nucleus_channel', 0)
110
+ if type(nucleus_size) not in [int, float] :
111
+ sg.popup("Incorrect nucleus size.")
112
+ relaunch= True
113
+ values['nucleus diameter'] = user_parameters.setdefault('nucleus diameter', 30)
114
+
115
+ user_parameters.update(values)
116
+ if not relaunch : break
117
+
118
+ #Launching segmentation
119
+ waiting_layout = [
120
+ [sg.Text("Running segmentation...")]
121
+ ]
122
+ window = sg.Window(
123
+ title= 'small_fish',
124
+ layout= waiting_layout,
125
+ grab_anywhere= True,
126
+ no_titlebar= False
127
+ )
128
+
129
+ window.read(timeout= 30, close= False)
130
+
131
+ try :
132
+ if type(path) != type(None) and filename != '':
133
+ output_path = path + '/' + filename
134
+ nuc_path = output_path + "_nucleus_segmentation"
135
+ cyto_path = output_path + "_cytoplasm_segmentation"
136
+ else :
137
+ output_path = None
138
+ nuc_path = None
139
+ cyto_path = None
140
+
141
+
142
+ cytoplasm_label, nucleus_label = cell_segmentation(
143
+ image,
144
+ cyto_model_name= cyto_model_name,
145
+ cyto_diameter= cyto_size,
146
+ nucleus_model_name= nucleus_model_name,
147
+ nucleus_diameter= nucleus_size,
148
+ channels=channels,
149
+ do_only_nuc=do_only_nuc
150
+ )
151
+
152
+ finally : window.close()
153
+ if show_segmentation or type(output_path) != type(None) :
154
+ nuc_proj = image[nucleus_channel]
155
+ im_proj = image[cytoplasm_channel]
156
+ if im_proj.ndim == 3 :
157
+ im_proj = stack.maximum_projection(im_proj)
158
+ if nuc_proj.ndim == 3 :
159
+ nuc_proj = stack.maximum_projection(nuc_proj)
160
+ plot.plot_segmentation_boundary(nuc_proj, cytoplasm_label, nucleus_label, boundary_size=2, contrast=True, show=show_segmentation, path_output=None, title= "Nucleus segmentation (blue)", remove_frame=False,)
161
+ if type(nuc_path) != type(None) : plot.plot_segmentation_boundary(nuc_proj, cytoplasm_label, nucleus_label, boundary_size=2, contrast=True, show=False, path_output=nuc_path, title= "Nucleus segmentation (blue)", remove_frame=True,)
162
+ if not do_only_nuc :
163
+ plot.plot_segmentation_boundary(im_proj, cytoplasm_label, nucleus_label, boundary_size=2, contrast=True, show=show_segmentation, path_output=cyto_path, title="Cytoplasm Segmentation (red)", remove_frame=False)
164
+ if type(cyto_path) != type(None) : plot.plot_segmentation_boundary(im_proj, cytoplasm_label, nucleus_label, boundary_size=2, contrast=True, show=False, path_output=cyto_path, title="Cytoplasm Segmentation (red)", remove_frame=True)
165
+ if show_segmentation :
166
+ layout = [
167
+ [sg.Text("Proceed with current segmentation ?")],
168
+ [sg.Button("Yes"), sg.Button("No")]
169
+ ]
170
+
171
+ event, values = prompt(layout=layout, add_ok_cancel=False)
172
+ if event == "No" :
173
+ continue
174
+
175
+ if cytoplasm_label.max() == 0 : #No cell segmented
176
+ layout = [
177
+ [sg.Text("No cell segmented. Proceed anyway ?")],
178
+ [sg.Button("Yes"), sg.Button("No")]
179
+ ]
180
+ event, values = prompt(layout=layout, add_ok_cancel=False)
181
+ if event == "Yes" :
182
+ return None, None, user_parameters
183
+ else :
184
+ break
185
+
186
+
187
+
188
+ user_parameters.update(values)
189
+ return cytoplasm_label, nucleus_label, user_parameters
190
+
191
+ def cell_segmentation(image, cyto_model_name, nucleus_model_name, channels, cyto_diameter, nucleus_diameter, do_only_nuc=False) :
192
+
193
+ nuc_channel = channels[1]
194
+ if not do_only_nuc :
195
+ cyto_channel = channels[0]
196
+ if image[cyto_channel].ndim >= 3 :
197
+ cyto = stack.maximum_projection(image[cyto_channel])
198
+ else :
199
+ cyto = image[cyto_channel]
200
+
201
+ if image[nuc_channel].ndim >= 3 :
202
+ nuc = stack.maximum_projection(image[nuc_channel])
203
+ else :
204
+ nuc = image[nuc_channel]
205
+
206
+ if not do_only_nuc :
207
+ image = np.zeros(shape=(2,) + cyto.shape)
208
+ image[0] = cyto
209
+ image[1] = nuc
210
+ image = np.moveaxis(image, source=(0,1,2), destination=(2,0,1))
211
+
212
+ nuc_label = _segmentate_object(nuc, nucleus_model_name, nucleus_diameter, [0,0])
213
+ if not do_only_nuc :
214
+ cytoplasm_label = _segmentate_object(image, cyto_model_name, cyto_diameter, [1,2])
215
+ nuc_label, cytoplasm_label = multistack.match_nuc_cell(nuc_label=nuc_label, cell_label=cytoplasm_label, single_nuc=True, cell_alone=False)
216
+ else :
217
+ cytoplasm_label = nuc_label
218
+
219
+ return cytoplasm_label, nuc_label
220
+
221
+ def _segmentate_object(im, model_name, object_size_px, channels = [0,0]) :
222
+
223
+ model = models.CellposeModel(
224
+ gpu= use_gpu(),
225
+ model_type= model_name,
226
+ )
227
+
228
+ label = model.eval(
229
+ im,
230
+ diameter= object_size_px,
231
+ channels= channels,
232
+ do_3D= False,
233
+ )[0]
234
+ label = np.array(label, dtype= np.int64)
235
+ label = remove_disjoint(label)
236
+
237
+ return label
238
+
239
+ def _cast_segmentation_parameters(values) :
240
+
241
+ if values['cyto_model_name'] == '' :
242
+ values['cyto_model_name'] = None
243
+
244
+ if values['nucleus_model_name'] == '' :
245
+ values['nucleus_model_name'] = None
246
+
247
+ try : #cytoplasm channel
248
+ values['cytoplasm channel'] = int(values['cytoplasm channel'])
249
+ except ValueError :
250
+ pass
251
+
252
+ try : #nucleus channel
253
+ values['nucleus channel'] = int(values['nucleus channel'])
254
+ except ValueError :
255
+ pass
256
+
257
+ try : #object size
258
+ values['cytoplasm diameter'] = float(values['cytoplasm diameter'])
259
+ except ValueError :
260
+ pass
261
+
262
+ try : #object size
263
+ values['nucleus diameter'] = float(values['nucleus diameter'])
264
+ except ValueError :
265
+ pass
266
+
267
+ return values
268
+
269
+ def remove_disjoint(image):
270
+ """
271
+ *CODE FROM BIG-FISH (LICENCE IN __INIT__.PY) IMPORTED TO AVOID IMPORT ERROR WHEN BIGFISH SEGMENTATION MODULE INITIALISES : try to import deprecated module for python 3.8
272
+
273
+ For each instances with disconnected parts, keep the larger one.
274
+
275
+ Parameters
276
+ ----------
277
+ image : np.ndarray, np.int, np.uint or bool
278
+ Labelled image with shape (z, y, x) or (y, x).
279
+
280
+ Returns
281
+ -------
282
+ image_cleaned : np.ndarray, np.int or np.uint
283
+ Cleaned image with shape (z, y, x) or (y, x).
284
+
285
+ """
286
+ # check parameters
287
+ stack.check_array(
288
+ image,
289
+ ndim=[2, 3],
290
+ dtype=[np.uint8, np.uint16, np.int32, np.int64, bool])
291
+
292
+ # handle boolean array
293
+ cast_to_bool = False
294
+ if image.dtype == bool:
295
+ cast_to_bool = bool
296
+ image = image.astype(np.uint8)
297
+
298
+ # initialize cleaned labels
299
+ image_cleaned = np.zeros_like(image)
300
+
301
+ # loop over instances
302
+ max_label = image.max()
303
+ for i in range(1, max_label + 1):
304
+
305
+ # get instance mask
306
+ mask = image == i
307
+
308
+ # check if an instance is labelled with this value
309
+ if mask.sum() == 0:
310
+ continue
311
+
312
+ # get an index for each disconnected part of the instance
313
+ labelled_mask = label(mask)
314
+ indices = sorted(list(set(labelled_mask.ravel())))
315
+ if 0 in indices:
316
+ indices = indices[1:]
317
+
318
+ # keep the largest part of the instance
319
+ max_area = 0
320
+ mask_instance = None
321
+ for j in indices:
322
+ mask_part_j = labelled_mask == j
323
+ area_j = mask_part_j.sum()
324
+ if area_j > max_area:
325
+ max_area = area_j
326
+ mask_instance = mask_part_j
327
+
328
+ # add instance in the final label
329
+ image_cleaned[mask_instance] = i
330
+
331
+ if cast_to_bool:
332
+ image_cleaned = image_cleaned.astype(bool)
333
+
334
+ return image_cleaned
@@ -0,0 +1,219 @@
1
+ """
2
+ Signal to noise wrapper from BigFish code.
3
+ """
4
+
5
+
6
+ # ### SNR ###
7
+ import bigfish.stack as stack
8
+ import numpy as np
9
+ from bigfish.detection.utils import get_object_radius_pixel, get_spot_volume, get_spot_surface
10
+
11
+ def compute_snr_spots(image, spots, voxel_size, spot_radius):
12
+ """
13
+ Modified version of bigfish.detection.utils compute_snr_spots :
14
+ # Author: Arthur Imbert <arthur.imbert.pro@gmail.com>
15
+ # License: BSD 3 clause
16
+
17
+ Compute signal-to-noise ratio (SNR) based on spot coordinates.
18
+
19
+ .. math::
20
+
21
+ \\mbox{SNR} = \\frac{\\mbox{max(spot signal)} -
22
+ \\mbox{mean(background)}}{\\mbox{std(background)}}
23
+
24
+ Background is a region twice larger surrounding the spot region. Only the
25
+ y and x dimensions are taking into account to compute the SNR.
26
+
27
+ Parameters
28
+ ----------
29
+ image : np.ndarray
30
+ Image with shape (z, y, x) or (y, x).
31
+ spots : np.ndarray
32
+ Coordinate of the spots, with shape (nb_spots, 3) or (nb_spots, 2).
33
+ One coordinate per dimension (zyx or yx coordinates).
34
+ voxel_size : int, float, Tuple(int, float), List(int, float) or None
35
+ Size of a voxel, in nanometer. One value per spatial dimension (zyx or
36
+ yx dimensions). If it's a scalar, the same value is applied to every
37
+ dimensions. Not used if 'log_kernel_size' and 'minimum_distance' are
38
+ provided.
39
+ spot_radius : int, float, Tuple(int, float), List(int, float) or None
40
+ Radius of the spot, in nanometer. One value per spatial dimension (zyx
41
+ or yx dimensions). If it's a scalar, the same radius is applied to
42
+ every dimensions. Not used if 'log_kernel_size' and 'minimum_distance'
43
+ are provided.
44
+
45
+ Returns
46
+ -------
47
+ res : dict
48
+ Median signal-to-noise ratio computed for every spots.
49
+ +
50
+ 'snr_median' : np.median(snr_spots),
51
+ 'snr_mean' : np.mean(snr_spots),
52
+ 'snr_std' : np.std(snr_spots),
53
+ 'cell_medianbackground_mean' : np.mean(median_background_list),
54
+ 'cell_medianbackground_std' : np.std(median_background_list),
55
+ 'cell_meanbackground_mean' : np.mean(mean_background_list),
56
+ 'cell_meanbackground_std' : np.std(mean_background_list),
57
+ 'cell_stdbackground_mean' : np.mean(std_background_list),
58
+ 'cell_stdbackground_std' : np.std(std_background_list)
59
+
60
+ """
61
+ # check parameters
62
+ stack.check_array(
63
+ image,
64
+ ndim=[2, 3],
65
+ dtype=[np.uint8, np.uint16, np.float32, np.float64])
66
+ stack.check_range_value(image, min_=0)
67
+ stack.check_array(
68
+ spots,
69
+ ndim=2,
70
+ dtype=[np.float32, np.float64, np.int32, np.int64])
71
+ stack.check_parameter(
72
+ voxel_size=(int, float, tuple, list),
73
+ spot_radius=(int, float, tuple, list))
74
+
75
+ # check consistency between parameters
76
+ ndim = image.ndim
77
+ if ndim != spots.shape[1]:
78
+ raise ValueError("Provided image has {0} dimensions but spots are "
79
+ "detected in {1} dimensions."
80
+ .format(ndim, spots.shape[1]))
81
+ if isinstance(voxel_size, (tuple, list)):
82
+ if len(voxel_size) != ndim:
83
+ raise ValueError(
84
+ "'voxel_size' must be a scalar or a sequence with {0} "
85
+ "elements.".format(ndim))
86
+ else:
87
+ voxel_size = (voxel_size,) * ndim
88
+ if isinstance(spot_radius, (tuple, list)):
89
+ if len(spot_radius) != ndim:
90
+ raise ValueError(
91
+ "'spot_radius' must be a scalar or a sequence with {0} "
92
+ "elements.".format(ndim))
93
+ else:
94
+ spot_radius = (spot_radius,) * ndim
95
+
96
+ # cast spots coordinates if needed
97
+ if spots.dtype == np.float64:
98
+ spots = np.round(spots).astype(np.int64)
99
+
100
+ # cast image if needed
101
+ image_to_process = image.copy().astype(np.float64)
102
+
103
+ # clip coordinate if needed
104
+ if ndim == 3:
105
+ spots[:, 0] = np.clip(spots[:, 0], 0, image_to_process.shape[0] - 1)
106
+ spots[:, 1] = np.clip(spots[:, 1], 0, image_to_process.shape[1] - 1)
107
+ spots[:, 2] = np.clip(spots[:, 2], 0, image_to_process.shape[2] - 1)
108
+ else:
109
+ spots[:, 0] = np.clip(spots[:, 0], 0, image_to_process.shape[0] - 1)
110
+ spots[:, 1] = np.clip(spots[:, 1], 0, image_to_process.shape[1] - 1)
111
+
112
+ # compute radius used to crop spot image
113
+ radius_pixel = get_object_radius_pixel(
114
+ voxel_size_nm=voxel_size,
115
+ object_radius_nm=spot_radius,
116
+ ndim=ndim)
117
+ radius_signal_ = [np.sqrt(ndim) * r for r in radius_pixel]
118
+ radius_signal_ = tuple(radius_signal_)
119
+
120
+ # compute the neighbourhood radius
121
+ radius_background_ = tuple(i * 2 for i in radius_signal_)
122
+
123
+ # ceil radii
124
+ radius_signal = np.ceil(radius_signal_).astype(int)
125
+ radius_background = np.ceil(radius_background_).astype(int)
126
+
127
+ # loop over spots
128
+ snr_spots = []
129
+ median_background_list = []
130
+ mean_background_list = []
131
+ std_background_list = []
132
+
133
+
134
+ for spot in spots:
135
+
136
+ # extract spot images
137
+ spot_y = spot[ndim - 2]
138
+ spot_x = spot[ndim - 1]
139
+ radius_signal_yx = radius_signal[-1]
140
+ radius_background_yx = radius_background[-1]
141
+ edge_background_yx = radius_background_yx - radius_signal_yx
142
+ if ndim == 3:
143
+ spot_z = spot[0]
144
+ radius_background_z = radius_background[0]
145
+ max_signal = image_to_process[spot_z, spot_y, spot_x]
146
+ spot_background_, _ = get_spot_volume(
147
+ image_to_process, spot_z, spot_y, spot_x,
148
+ radius_background_z, radius_background_yx)
149
+ spot_background = spot_background_.copy()
150
+
151
+ # discard spot if cropped at the border (along y and x dimensions)
152
+ expected_size = (2 * radius_background_yx + 1) ** 2
153
+ actual_size = spot_background.shape[1] * spot_background.shape[2]
154
+ if expected_size != actual_size:
155
+ continue
156
+
157
+ # remove signal from background crop
158
+ spot_background[:,
159
+ edge_background_yx:-edge_background_yx,
160
+ edge_background_yx:-edge_background_yx] = -1
161
+ spot_background = spot_background[spot_background >= 0]
162
+
163
+ else:
164
+ max_signal = image_to_process[spot_y, spot_x]
165
+ spot_background_, _ = get_spot_surface(
166
+ image_to_process, spot_y, spot_x, radius_background_yx)
167
+ spot_background = spot_background_.copy()
168
+
169
+ # discard spot if cropped at the border
170
+ expected_size = (2 * radius_background_yx + 1) ** 2
171
+ if expected_size != spot_background.size:
172
+ continue
173
+
174
+ # remove signal from background crop
175
+ spot_background[edge_background_yx:-edge_background_yx,
176
+ edge_background_yx:-edge_background_yx] = -1
177
+ spot_background = spot_background[spot_background >= 0]
178
+
179
+ # compute mean background
180
+ median_background = np.median(spot_background)
181
+ mean_background = np.mean(spot_background)
182
+
183
+ # compute standard deviation background
184
+ std_background = np.std(spot_background)
185
+
186
+ # compute SNR
187
+ snr = (max_signal - mean_background) / std_background
188
+ snr_spots.append(snr)
189
+ median_background_list.append(median_background)
190
+ mean_background_list.append(mean_background)
191
+ std_background_list.append(std_background)
192
+
193
+ # average SNR
194
+ if len(snr_spots) == 0:
195
+ res = {
196
+ 'snr_median' : 0,
197
+ 'snr_mean' : 0,
198
+ 'snr_std' : 0,
199
+ 'cell_medianbackground_mean' : 0,
200
+ 'cell_medianbackground_std' : 0,
201
+ 'cell_meanbackground_mean' : 0,
202
+ 'cell_meanbackground_std' : 0,
203
+ 'cell_stdbackground_mean' : 0,
204
+ 'cell_stdbackground_std' : 0
205
+ }
206
+ else:
207
+ res = {
208
+ 'snr_median' : np.median(snr_spots),
209
+ 'snr_mean' : np.mean(snr_spots),
210
+ 'snr_std' : np.std(snr_spots),
211
+ 'cell_medianbackground_mean' : np.mean(median_background_list),
212
+ 'cell_medianbackground_std' : np.std(median_background_list),
213
+ 'cell_meanbackground_mean' : np.mean(mean_background_list),
214
+ 'cell_meanbackground_std' : np.std(mean_background_list),
215
+ 'cell_stdbackground_mean' : np.mean(std_background_list),
216
+ 'cell_stdbackground_std' : np.std(std_background_list)
217
+ }
218
+
219
+ return res
@@ -0,0 +1,127 @@
1
+ from ..gui.prompts import output_image_prompt, ask_detection_confirmation, ask_cancel_detection
2
+ from ..interface.output import write_results
3
+ from ._preprocess import map_channels, prepare_image_detection, reorder_shape, reorder_image_stack
4
+ from .detection import ask_input_parameters, initiate_detection, launch_detection, launch_features_computation, get_nucleus_signal
5
+ from ._segmentation import launch_segmentation
6
+ from ._colocalisation import initiate_colocalisation, launch_colocalisation
7
+
8
+ import pandas as pd
9
+ import PySimpleGUI as sg
10
+
11
+ def add_detection(user_parameters, segmentation_done, acquisition_id, cytoplasm_label, nucleus_label) :
12
+ """
13
+ #TODO : list all keys added to user_parameters when returned
14
+ """
15
+
16
+ new_results_df = pd.DataFrame()
17
+ new_cell_results_df = pd.DataFrame()
18
+
19
+ #Ask for image parameters
20
+ new_parameters = ask_input_parameters(ask_for_segmentation= not segmentation_done) #The image is open and stored inside user_parameters
21
+ if type(new_parameters) == type(None) : #if user clicks 'Cancel'
22
+ return new_results_df, new_cell_results_df, acquisition_id, user_parameters, segmentation_done,cytoplasm_label, nucleus_label
23
+ else :
24
+ user_parameters.update(new_parameters)
25
+
26
+ map = map_channels(user_parameters)
27
+ user_parameters['reordered_shape'] = reorder_shape(user_parameters['shape'], map)
28
+
29
+
30
+ #Segmentation
31
+ if user_parameters['Segmentation'] and not segmentation_done:
32
+ im_seg = reorder_image_stack(map, user_parameters)
33
+ cytoplasm_label, nucleus_label, user_parameters = launch_segmentation(im_seg, user_parameters=user_parameters)
34
+
35
+ else :
36
+ cytoplasm_label, nucleus_label = None,None
37
+
38
+ if type(cytoplasm_label) == type(None) or type(nucleus_label) == type(None) :
39
+ user_parameters['Segmentation'] = False
40
+ segmentation_done = False
41
+
42
+ else : segmentation_done = True
43
+
44
+ #Detection
45
+ while True : # This loop allow user to try detection with different thresholds or parameters before launching features computation
46
+ detection_parameters = initiate_detection(
47
+ user_parameters,
48
+ segmentation_done,
49
+ map= map,
50
+ shape = user_parameters['image'].shape
51
+ )
52
+
53
+ if type(detection_parameters) != type(None) :
54
+ user_parameters.update(detection_parameters)
55
+ else : #If user clicks cancel
56
+ cancel = ask_cancel_detection()
57
+ if cancel :
58
+ return new_results_df, new_cell_results_df, acquisition_id, user_parameters, segmentation_done, cytoplasm_label, nucleus_label
59
+ else : continue
60
+
61
+ acquisition_id += 1
62
+ image, other_image = prepare_image_detection(map, user_parameters)
63
+ nucleus_signal = get_nucleus_signal(image, other_image, user_parameters)
64
+
65
+ try : # Catch error raised if user enter a spot size too small compare to voxel size
66
+ user_parameters, frame_result, spots, clusters = launch_detection(
67
+ image,
68
+ other_image,
69
+ user_parameters,
70
+ cell_label=cytoplasm_label,
71
+ nucleus_label=nucleus_label
72
+ )
73
+
74
+ except ValueError as error :
75
+ if "The array should have an upper bound of 1" in str(error) :
76
+ sg.popup("Spot size too small for current voxel size.")
77
+ continue
78
+ else :
79
+ raise(error)
80
+
81
+
82
+ if user_parameters['Napari correction'] :
83
+ if ask_detection_confirmation(user_parameters.get('threshold')) : break
84
+ else :
85
+ break
86
+
87
+ #Features computation
88
+ new_results_df, new_cell_results_df = launch_features_computation(
89
+ acquisition_id=acquisition_id,
90
+ image=image,
91
+ nucleus_signal = nucleus_signal,
92
+ spots=spots,
93
+ clusters=clusters,
94
+ nucleus_label = nucleus_label,
95
+ cell_label= cytoplasm_label,
96
+ user_parameters=user_parameters,
97
+ frame_results=frame_result,
98
+ )
99
+ return new_results_df, new_cell_results_df, acquisition_id, user_parameters, segmentation_done, cytoplasm_label, nucleus_label
100
+
101
+ def save_results(result_df, cell_result_df, coloc_df) :
102
+ if len(result_df) != 0 :
103
+ dic = output_image_prompt(filename=result_df.iloc[0].at['filename'])
104
+
105
+ if isinstance(dic, dict) :
106
+ path = dic['folder']
107
+ filename = dic['filename']
108
+ do_excel = dic['Excel']
109
+ do_feather = dic['Feather']
110
+ sucess1 = write_results(result_df, path= path, filename=filename, do_excel= do_excel, do_feather= do_feather)
111
+ sucess2 = write_results(cell_result_df, path= path, filename=filename + '_cell_result', do_excel= do_excel, do_feather= do_feather)
112
+ sucess3 = write_results(coloc_df, path= path, filename=filename + '_coloc_result', do_excel= do_excel, do_feather= do_feather)
113
+ if sucess1 and sucess2 and sucess3 : sg.popup("Sucessfully saved at {0}.".format(path))
114
+
115
+ else :
116
+ dic = None
117
+ sg.popup('No results to save.')
118
+
119
+ def compute_colocalisation(result_tables, result_dataframe) :
120
+ colocalisation_distance = initiate_colocalisation(result_tables)
121
+
122
+ if colocalisation_distance == False :
123
+ res_coloc = pd.DataFrame() # popup handled in initiate_colocalisation
124
+ else :
125
+ res_coloc = launch_colocalisation(result_tables, result_dataframe=result_dataframe, colocalisation_distance=colocalisation_distance)
126
+
127
+ return res_coloc