small-fish-gui 1.3.5__py3-none-any.whl → 1.5.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.
- small_fish_gui/.readthedocs.yaml +21 -0
- small_fish_gui/README.md +2 -3
- small_fish_gui/__init__.py +1 -1
- small_fish_gui/batch/__init__.py +5 -0
- small_fish_gui/batch/input.py +62 -0
- small_fish_gui/batch/integrity.py +158 -0
- small_fish_gui/batch/output.py +0 -0
- small_fish_gui/batch/pipeline.py +218 -0
- small_fish_gui/batch/prompt.py +428 -0
- small_fish_gui/batch/test.py +10 -0
- small_fish_gui/batch/update.py +132 -0
- small_fish_gui/batch/utils.py +66 -0
- small_fish_gui/batch/values.py +3 -0
- small_fish_gui/batch/values.txt +65 -0
- small_fish_gui/docs/conf.py +1 -0
- small_fish_gui/gui/animation.py +24 -15
- small_fish_gui/gui/layout.py +28 -7
- small_fish_gui/gui/prompts.py +11 -9
- small_fish_gui/interface/output.py +8 -4
- small_fish_gui/pipeline/__init__.py +21 -0
- small_fish_gui/pipeline/_napari_wrapper.py +63 -90
- small_fish_gui/pipeline/_preprocess.py +86 -28
- small_fish_gui/pipeline/_segmentation.py +165 -16
- small_fish_gui/pipeline/actions.py +6 -1
- small_fish_gui/pipeline/detection.py +75 -16
- small_fish_gui/pipeline/main.py +12 -5
- small_fish_gui/pipeline/utils.py +16 -0
- small_fish_gui/utils.py +6 -1
- {small_fish_gui-1.3.5.dist-info → small_fish_gui-1.5.0.dist-info}/METADATA +1 -1
- small_fish_gui-1.5.0.dist-info/RECORD +52 -0
- small_fish_gui/gui/batch.py +0 -312
- small_fish_gui/gui/test.py +0 -5
- small_fish_gui-1.3.5.dist-info/RECORD +0 -39
- {small_fish_gui-1.3.5.dist-info → small_fish_gui-1.5.0.dist-info}/WHEEL +0 -0
- {small_fish_gui-1.3.5.dist-info → small_fish_gui-1.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -67,9 +67,9 @@ def map_channels(user_parameters) :
|
|
|
67
67
|
multichannel = user_parameters['multichannel']
|
|
68
68
|
|
|
69
69
|
try :
|
|
70
|
-
map = _auto_map_channels(
|
|
70
|
+
map = _auto_map_channels(is_3D_stack, is_time_stack, multichannel, image=image)
|
|
71
71
|
except MappingError as e :
|
|
72
|
-
sg.popup("Automatic dimension mapping went wrong. Please indicate
|
|
72
|
+
sg.popup("Automatic dimension mapping went wrong. Please indicate dimensions positions in the array.")
|
|
73
73
|
map = _ask_channel_map(image.shape, is_3D_stack, is_time_stack, multichannel, preset_map= e.get_map())
|
|
74
74
|
|
|
75
75
|
else :
|
|
@@ -77,8 +77,9 @@ def map_channels(user_parameters) :
|
|
|
77
77
|
|
|
78
78
|
return map
|
|
79
79
|
|
|
80
|
-
def _auto_map_channels(image: np.ndarray,
|
|
81
|
-
shape
|
|
80
|
+
def _auto_map_channels(is_3D_stack, is_time_stack, multichannel, image: np.ndarray=None, shape=None) :
|
|
81
|
+
if type(shape) == type(None) :
|
|
82
|
+
shape = image.shape
|
|
82
83
|
reducing_list = list(shape)
|
|
83
84
|
|
|
84
85
|
#Set the biggest dimension to y
|
|
@@ -124,14 +125,16 @@ def _auto_map_channels(image: np.ndarray, is_3D_stack, is_time_stack, multichann
|
|
|
124
125
|
def _ask_channel_map(shape, is_3D_stack, is_time_stack, multichannel, preset_map: dict= {}) :
|
|
125
126
|
while True :
|
|
126
127
|
relaunch = False
|
|
128
|
+
save_preset = preset_map.copy()
|
|
127
129
|
x = preset_map.setdefault('x',0)
|
|
128
130
|
y = preset_map.setdefault('y',0)
|
|
129
131
|
z = preset_map.setdefault('z',0)
|
|
130
132
|
c = preset_map.setdefault('c',0)
|
|
131
133
|
t = preset_map.setdefault('t',0)
|
|
132
134
|
|
|
135
|
+
|
|
133
136
|
layout = [
|
|
134
|
-
add_header("Dimensions mapping"
|
|
137
|
+
add_header("Dimensions mapping") + [sg.Text("Image shape : {0}".format(shape))]
|
|
135
138
|
]
|
|
136
139
|
layout += [parameters_layout(['x','y'], default_values=[x,y])]
|
|
137
140
|
if is_3D_stack : layout += [parameters_layout(['z'], default_values=[z])]
|
|
@@ -139,7 +142,7 @@ def _ask_channel_map(shape, is_3D_stack, is_time_stack, multichannel, preset_map
|
|
|
139
142
|
if is_time_stack : layout += [parameters_layout(['t'], default_values=[t])]
|
|
140
143
|
|
|
141
144
|
event, preset_map = prompt_with_help(layout,help= 'mapping', add_scrollbar=False)
|
|
142
|
-
if event == 'Cancel' :
|
|
145
|
+
if event == 'Cancel' : return save_preset
|
|
143
146
|
|
|
144
147
|
#Check integrity
|
|
145
148
|
channels_values = np.array(list(preset_map.values()), dtype= int)
|
|
@@ -156,24 +159,26 @@ def _ask_channel_map(shape, is_3D_stack, is_time_stack, multichannel, preset_map
|
|
|
156
159
|
return preset_map
|
|
157
160
|
|
|
158
161
|
def _show_mapping(shape, map, is_3D_stack, is_time_stack, multichannel) :
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
162
|
+
while True :
|
|
163
|
+
layout = [
|
|
164
|
+
[sg.Text("Image shape : {0}".format(shape))],
|
|
165
|
+
[sg.Text('Dimensions mapping was set to :')],
|
|
166
|
+
[sg.Text('x : {0} \ny : {1} \nz : {2} \nc : {3} \nt : {4}'.format(
|
|
167
|
+
map['x'], map['y'], map.get('z'), map.get("c"), map.get('t')
|
|
168
|
+
))],
|
|
169
|
+
[sg.Button('Change mapping')]
|
|
170
|
+
]
|
|
171
|
+
|
|
172
|
+
event, values = prompt_with_help(layout, help='mapping', add_scrollbar=False)
|
|
173
|
+
|
|
174
|
+
if event == 'Ok' :
|
|
175
|
+
return map
|
|
176
|
+
elif event == 'Change mapping':
|
|
177
|
+
map = _ask_channel_map(shape, is_3D_stack, is_time_stack, multichannel, preset_map=map)
|
|
178
|
+
elif event == 'Cancel' :
|
|
179
|
+
return None
|
|
180
|
+
else : raise AssertionError('Unforseen event')
|
|
175
181
|
|
|
176
|
-
return map
|
|
177
182
|
|
|
178
183
|
def convert_parameters_types(values:dict) :
|
|
179
184
|
"""
|
|
@@ -194,8 +199,8 @@ def convert_parameters_types(values:dict) :
|
|
|
194
199
|
else : values[tuple_parameter] = tuple_values
|
|
195
200
|
|
|
196
201
|
#Parameters
|
|
197
|
-
int_list = ['threshold', 'channel_to_compute', 'min number of spots', 'cluster size','nucleus channel signal']
|
|
198
|
-
float_list = ['
|
|
202
|
+
int_list = ['threshold', 'channel_to_compute', 'channel to compute', 'min number of spots', 'cluster size','nucleus channel signal']
|
|
203
|
+
float_list = ['alpha', 'beta', 'gamma', 'threshold penalty']
|
|
199
204
|
|
|
200
205
|
for parameter in int_list :
|
|
201
206
|
try :
|
|
@@ -213,7 +218,15 @@ def convert_parameters_types(values:dict) :
|
|
|
213
218
|
|
|
214
219
|
return values
|
|
215
220
|
|
|
216
|
-
def check_integrity(
|
|
221
|
+
def check_integrity(
|
|
222
|
+
values: dict,
|
|
223
|
+
do_dense_region_deconvolution,
|
|
224
|
+
do_clustering,
|
|
225
|
+
multichannel,
|
|
226
|
+
segmentation_done,
|
|
227
|
+
map,
|
|
228
|
+
shape
|
|
229
|
+
):
|
|
217
230
|
"""
|
|
218
231
|
Checks that parameters given in input by user are fit to be used for bigfish detection.
|
|
219
232
|
"""
|
|
@@ -233,10 +246,22 @@ def check_integrity(values: dict, do_dense_region_deconvolution, multichannel,se
|
|
|
233
246
|
_warning_popup('No gamma found; image will not be denoised before deconvolution.')
|
|
234
247
|
values['gamma'] = 0
|
|
235
248
|
|
|
249
|
+
if values['alpha'] > 1 or values['alpha'] < 0 :
|
|
250
|
+
raise ParameterInputError("alpha must be set between 0 and 1.")
|
|
251
|
+
|
|
252
|
+
if do_clustering :
|
|
253
|
+
if not isinstance(values['min number of spots'], (int)) :
|
|
254
|
+
raise ParameterInputError("Incorrect min spot number parameter.")
|
|
255
|
+
if not isinstance(values['cluster size'], (int)) :
|
|
256
|
+
raise ParameterInputError("Incorrect cluster size parameter.")
|
|
257
|
+
|
|
236
258
|
#channel
|
|
237
259
|
if multichannel :
|
|
238
260
|
ch_len = shape[int(map['c'])]
|
|
239
|
-
|
|
261
|
+
|
|
262
|
+
if type(segmentation_done) == type(None) :
|
|
263
|
+
pass
|
|
264
|
+
elif segmentation_done :
|
|
240
265
|
try : nuc_signal_ch = int(values['nucleus channel signal'])
|
|
241
266
|
except Exception :
|
|
242
267
|
raise ParameterInputError("Incorrect channel for nucleus signal measure.")
|
|
@@ -259,7 +284,6 @@ def check_integrity(values: dict, do_dense_region_deconvolution, multichannel,se
|
|
|
259
284
|
|
|
260
285
|
return values
|
|
261
286
|
|
|
262
|
-
|
|
263
287
|
def reorder_shape(shape, map) :
|
|
264
288
|
x = [int(map['x']),]
|
|
265
289
|
y = [int(map['y']),]
|
|
@@ -275,6 +299,40 @@ def reorder_shape(shape, map) :
|
|
|
275
299
|
|
|
276
300
|
return new_shape
|
|
277
301
|
|
|
302
|
+
def _check_segmentation_parameters(
|
|
303
|
+
user_parameters,
|
|
304
|
+
shape,
|
|
305
|
+
is_multichannel,
|
|
306
|
+
) :
|
|
307
|
+
|
|
308
|
+
available_channels = list(range(len(shape)))
|
|
309
|
+
do_only_nuc = user_parameters['Segment only nuclei']
|
|
310
|
+
cyto_model_name = user_parameters['cyto_model_name']
|
|
311
|
+
cyto_size = user_parameters['cytoplasm diameter']
|
|
312
|
+
cytoplasm_channel = user_parameters['cytoplasm channel']
|
|
313
|
+
nucleus_model_name = user_parameters['nucleus_model_name']
|
|
314
|
+
nucleus_size = user_parameters['nucleus diameter']
|
|
315
|
+
nucleus_channel = user_parameters['nucleus channel']
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
if type(cyto_model_name) != str and not do_only_nuc:
|
|
319
|
+
raise ParameterInputError('Invalid cytoplasm model name.')
|
|
320
|
+
if cytoplasm_channel not in available_channels and not do_only_nuc and is_multichannel:
|
|
321
|
+
raise ParameterInputError('For given input image please select channel in {0}\ncytoplasm channel : {1}'.format(available_channels, cytoplasm_channel))
|
|
322
|
+
|
|
323
|
+
if type(cyto_size) not in [int, float] and not do_only_nuc:
|
|
324
|
+
raise ParameterInputError("Incorrect cytoplasm size.")
|
|
325
|
+
|
|
326
|
+
if type(nucleus_model_name) != str :
|
|
327
|
+
raise ParameterInputError('Invalid nucleus model name.')
|
|
328
|
+
|
|
329
|
+
if nucleus_channel not in available_channels and is_multichannel:
|
|
330
|
+
raise ParameterInputError('For given input image please select channel in {0}\nnucleus channel : {1}'.format(available_channels, nucleus_channel))
|
|
331
|
+
|
|
332
|
+
if type(nucleus_size) not in [int, float] :
|
|
333
|
+
raise ParameterInputError("Incorrect nucleus size.")
|
|
334
|
+
|
|
335
|
+
|
|
278
336
|
def clean_unused_parameters_cache(user_parameters: dict) :
|
|
279
337
|
"""
|
|
280
338
|
Clean unused parameters that were set to None in previous run.
|
|
@@ -6,14 +6,19 @@ from cellpose.core import use_gpu
|
|
|
6
6
|
from skimage.measure import label
|
|
7
7
|
from ..gui.layout import _segmentation_layout
|
|
8
8
|
from ..gui import prompt, prompt_with_help, ask_cancel_segmentation
|
|
9
|
+
from ..interface import open_image
|
|
9
10
|
from ._napari_wrapper import show_segmentation as napari_show_segmentation
|
|
11
|
+
from .utils import from_label_get_centeroidscoords
|
|
12
|
+
from matplotlib.colors import ListedColormap
|
|
10
13
|
|
|
14
|
+
import matplotlib as mpl
|
|
11
15
|
import cellpose.models as models
|
|
12
16
|
import numpy as np
|
|
13
17
|
import bigfish.multistack as multistack
|
|
14
18
|
import bigfish.stack as stack
|
|
15
19
|
import bigfish.plot as plot
|
|
16
20
|
import PySimpleGUI as sg
|
|
21
|
+
import matplotlib.pyplot as plt
|
|
17
22
|
import os
|
|
18
23
|
|
|
19
24
|
def launch_segmentation(image: np.ndarray, user_parameters: dict) :
|
|
@@ -38,6 +43,7 @@ def launch_segmentation(image: np.ndarray, user_parameters: dict) :
|
|
|
38
43
|
nucleus_model_name = user_parameters.setdefault('nucleus_model_name', 'nuclei')
|
|
39
44
|
nucleus_size = user_parameters.setdefault('nucleus diameter', 130)
|
|
40
45
|
nucleus_channel = user_parameters.setdefault('nucleus channel', 0)
|
|
46
|
+
other_nucleus_image = user_parameters.setdefault('other_nucleus_image',None)
|
|
41
47
|
path = os.getcwd()
|
|
42
48
|
show_segmentation = user_parameters.setdefault('show segmentation', False)
|
|
43
49
|
segment_only_nuclei = user_parameters.setdefault('Segment only nuclei', False)
|
|
@@ -56,6 +62,7 @@ def launch_segmentation(image: np.ndarray, user_parameters: dict) :
|
|
|
56
62
|
nucleus_channel_preset= nucleus_channel,
|
|
57
63
|
cyto_diameter_preset= cyto_size,
|
|
58
64
|
nucleus_diameter_preset= nucleus_size,
|
|
65
|
+
other_nucleus_image_preset=other_nucleus_image,
|
|
59
66
|
saving_path_preset= path,
|
|
60
67
|
show_segmentation_preset=show_segmentation,
|
|
61
68
|
segment_only_nuclei_preset=segment_only_nuclei,
|
|
@@ -81,10 +88,11 @@ def launch_segmentation(image: np.ndarray, user_parameters: dict) :
|
|
|
81
88
|
nucleus_model_name = values['nucleus_model_name']
|
|
82
89
|
nucleus_size = values['nucleus diameter']
|
|
83
90
|
nucleus_channel = values['nucleus channel']
|
|
91
|
+
other_nucleus_image = values['other_nucleus_image']
|
|
84
92
|
path = values['saving path'] if values['saving path'] != '' else None
|
|
85
93
|
show_segmentation = values['show segmentation']
|
|
86
94
|
filename = values['filename'] if type(path) != type(None) else None
|
|
87
|
-
channels = [cytoplasm_channel, nucleus_channel]
|
|
95
|
+
channels = [cytoplasm_channel, nucleus_channel] if multichannel else [...,...]
|
|
88
96
|
|
|
89
97
|
relaunch= False
|
|
90
98
|
#Checking integrity of parameters
|
|
@@ -92,10 +100,13 @@ def launch_segmentation(image: np.ndarray, user_parameters: dict) :
|
|
|
92
100
|
sg.popup('Invalid cytoplasm model name.')
|
|
93
101
|
values['cyto_model_name'] = user_parameters.setdefault('cyto_model_name', 'cyto2')
|
|
94
102
|
relaunch= True
|
|
95
|
-
if
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
103
|
+
if multichannel :
|
|
104
|
+
if cytoplasm_channel not in available_channels and not do_only_nuc:
|
|
105
|
+
sg.popup('For given input image please select channel in {0}\ncytoplasm channel : {1}'.format(available_channels, cytoplasm_channel))
|
|
106
|
+
relaunch= True
|
|
107
|
+
values['cytoplasm channel'] = user_parameters.setdefault('cytoplasm channel',0)
|
|
108
|
+
else :
|
|
109
|
+
cytoplasm_channel = ...
|
|
99
110
|
|
|
100
111
|
if type(cyto_size) not in [int, float] and not do_only_nuc:
|
|
101
112
|
sg.popup("Incorrect cytoplasm size.")
|
|
@@ -106,14 +117,46 @@ def launch_segmentation(image: np.ndarray, user_parameters: dict) :
|
|
|
106
117
|
sg.popup('Invalid nucleus model name.')
|
|
107
118
|
values['nucleus_model_name'] = user_parameters.setdefault('nucleus_model_name', 'nuclei')
|
|
108
119
|
relaunch= True
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
120
|
+
|
|
121
|
+
if multichannel :
|
|
122
|
+
if nucleus_channel not in available_channels :
|
|
123
|
+
sg.popup('For given input image please select channel in {0}\nnucleus channel : {1}'.format(available_channels, nucleus_channel))
|
|
124
|
+
relaunch= True
|
|
125
|
+
values['nucleus channel'] = user_parameters.setdefault('nucleus_channel', 0)
|
|
126
|
+
else :
|
|
127
|
+
nucleus_channel = ...
|
|
128
|
+
|
|
113
129
|
if type(nucleus_size) not in [int, float] :
|
|
114
130
|
sg.popup("Incorrect nucleus size.")
|
|
115
131
|
relaunch= True
|
|
116
132
|
values['nucleus diameter'] = user_parameters.setdefault('nucleus diameter', 30)
|
|
133
|
+
if other_nucleus_image != '' :
|
|
134
|
+
if not os.path.isfile(other_nucleus_image) :
|
|
135
|
+
sg.popup("Nucleus image is not a file.")
|
|
136
|
+
relaunch=True
|
|
137
|
+
values['other_nucleus_image'] = None
|
|
138
|
+
else :
|
|
139
|
+
try :
|
|
140
|
+
nucleus_image = open_image(other_nucleus_image)
|
|
141
|
+
except Exception as e :
|
|
142
|
+
sg.popup("Could not open image.\n{0}".format(e))
|
|
143
|
+
relaunch=True
|
|
144
|
+
values['other_nucleus_image'] = user_parameters.setdefault('other_nucleus_image', None)
|
|
145
|
+
else :
|
|
146
|
+
if nucleus_image.ndim != image.ndim - multichannel :
|
|
147
|
+
sg.popup("Nucleus image dimension missmatched. Expected same dimension as cytoplasm_image for monochannel or same dimension as cytoplasm_image -1 for multichannel\ncytoplasm dimension : {0}, nucleus dimension : {1}".format(image.ndim, nucleus_image.ndim))
|
|
148
|
+
nucleus_image = None
|
|
149
|
+
relaunch=True
|
|
150
|
+
values['other_nucleus_image'] = user_parameters.setdefault('other_nucleus_image', None)
|
|
151
|
+
|
|
152
|
+
elif nucleus_image.shape != image[cytoplasm_channel] :
|
|
153
|
+
sg.popup("Nucleus image shape missmatched. Expected same shape as cytoplasm_image \ncytoplasm shape : {0}, nucleus shape : {1}".format(image[cytoplasm_channel].shape, nucleus_image.shape))
|
|
154
|
+
nucleus_image = None
|
|
155
|
+
relaunch=True
|
|
156
|
+
values['other_nucleus_image'] = user_parameters.setdefault('other_nucleus_image', None)
|
|
157
|
+
|
|
158
|
+
else :
|
|
159
|
+
nucleus_image = None
|
|
117
160
|
|
|
118
161
|
user_parameters.update(values)
|
|
119
162
|
if not relaunch : break
|
|
@@ -149,14 +192,15 @@ def launch_segmentation(image: np.ndarray, user_parameters: dict) :
|
|
|
149
192
|
nucleus_model_name= nucleus_model_name,
|
|
150
193
|
nucleus_diameter= nucleus_size,
|
|
151
194
|
channels=channels,
|
|
152
|
-
do_only_nuc=do_only_nuc
|
|
195
|
+
do_only_nuc=do_only_nuc,
|
|
196
|
+
external_nucleus_image = nucleus_image,
|
|
153
197
|
)
|
|
154
198
|
|
|
155
199
|
finally : window.close()
|
|
156
200
|
|
|
157
201
|
if show_segmentation :
|
|
158
202
|
nucleus_label, cytoplasm_label = napari_show_segmentation(
|
|
159
|
-
nuc_image=image[nucleus_channel],
|
|
203
|
+
nuc_image=image[nucleus_channel] if type(nucleus_image) == type(None) else nucleus_image,
|
|
160
204
|
nuc_label= nucleus_label,
|
|
161
205
|
cyto_image=image[cytoplasm_channel],
|
|
162
206
|
cyto_label=cytoplasm_label,
|
|
@@ -175,16 +219,30 @@ def launch_segmentation(image: np.ndarray, user_parameters: dict) :
|
|
|
175
219
|
continue
|
|
176
220
|
|
|
177
221
|
if type(output_path) != type(None) :
|
|
222
|
+
|
|
223
|
+
#Get backgrounds
|
|
178
224
|
nuc_proj = image[nucleus_channel]
|
|
179
225
|
im_proj = image[cytoplasm_channel]
|
|
180
226
|
if im_proj.ndim == 3 :
|
|
181
227
|
im_proj = stack.maximum_projection(im_proj)
|
|
182
228
|
if nuc_proj.ndim == 3 :
|
|
183
229
|
nuc_proj = stack.maximum_projection(nuc_proj)
|
|
230
|
+
|
|
231
|
+
#Call plots
|
|
184
232
|
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,)
|
|
185
233
|
if not do_only_nuc :
|
|
186
234
|
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)
|
|
187
|
-
|
|
235
|
+
plot_labels(
|
|
236
|
+
nucleus_label,
|
|
237
|
+
path_output=output_path + "_nucleus_label_map.png",
|
|
238
|
+
show=False
|
|
239
|
+
)
|
|
240
|
+
if not do_only_nuc :
|
|
241
|
+
plot_labels(
|
|
242
|
+
cytoplasm_label,
|
|
243
|
+
path_output=output_path + "_cytoplasm_label_map.png",
|
|
244
|
+
show=False
|
|
245
|
+
)
|
|
188
246
|
|
|
189
247
|
|
|
190
248
|
|
|
@@ -204,7 +262,14 @@ def launch_segmentation(image: np.ndarray, user_parameters: dict) :
|
|
|
204
262
|
user_parameters.update(values)
|
|
205
263
|
return cytoplasm_label, nucleus_label, user_parameters
|
|
206
264
|
|
|
207
|
-
def cell_segmentation(
|
|
265
|
+
def cell_segmentation(
|
|
266
|
+
image, cyto_model_name,
|
|
267
|
+
nucleus_model_name,
|
|
268
|
+
channels, cyto_diameter,
|
|
269
|
+
nucleus_diameter,
|
|
270
|
+
do_only_nuc=False,
|
|
271
|
+
external_nucleus_image = None,
|
|
272
|
+
) :
|
|
208
273
|
|
|
209
274
|
nuc_channel = channels[1]
|
|
210
275
|
if not do_only_nuc :
|
|
@@ -214,10 +279,13 @@ def cell_segmentation(image, cyto_model_name, nucleus_model_name, channels, cyto
|
|
|
214
279
|
else :
|
|
215
280
|
cyto = image[cyto_channel]
|
|
216
281
|
|
|
217
|
-
if
|
|
218
|
-
nuc =
|
|
219
|
-
else :
|
|
282
|
+
if type(external_nucleus_image) != type(None) :
|
|
283
|
+
nuc = external_nucleus_image
|
|
284
|
+
else :
|
|
220
285
|
nuc = image[nuc_channel]
|
|
286
|
+
|
|
287
|
+
if nuc.ndim >= 3 :
|
|
288
|
+
nuc = stack.maximum_projection(nuc)
|
|
221
289
|
|
|
222
290
|
if not do_only_nuc :
|
|
223
291
|
image = np.zeros(shape=(2,) + cyto.shape)
|
|
@@ -351,3 +419,84 @@ def remove_disjoint(image):
|
|
|
351
419
|
image_cleaned = image_cleaned.astype(bool)
|
|
352
420
|
|
|
353
421
|
return image_cleaned
|
|
422
|
+
|
|
423
|
+
def plot_segmentation(
|
|
424
|
+
cyto_image : np.ndarray,
|
|
425
|
+
cyto_label : np.ndarray,
|
|
426
|
+
nuc_image : np.ndarray,
|
|
427
|
+
nuc_label : np.ndarray,
|
|
428
|
+
path :str,
|
|
429
|
+
do_only_nuc=False
|
|
430
|
+
) :
|
|
431
|
+
|
|
432
|
+
if nuc_image.ndim == 3 :
|
|
433
|
+
nuc_image = np.max(nuc_image,axis=0)
|
|
434
|
+
|
|
435
|
+
plot.plot_segmentation_boundary(
|
|
436
|
+
image=nuc_image,
|
|
437
|
+
nuc_label= nuc_label,
|
|
438
|
+
boundary_size= 3,
|
|
439
|
+
contrast=True,
|
|
440
|
+
path_output=path + "_nuclei_segmentation.png",
|
|
441
|
+
show=False,
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
if not do_only_nuc :
|
|
446
|
+
if cyto_image.ndim == 3 :
|
|
447
|
+
cyto_image = np.max(cyto_image,axis=0)
|
|
448
|
+
|
|
449
|
+
plot.plot_segmentation_boundary(
|
|
450
|
+
image=cyto_image,
|
|
451
|
+
cell_label= cyto_label,
|
|
452
|
+
nuc_label= nuc_label,
|
|
453
|
+
boundary_size= 3,
|
|
454
|
+
contrast=True,
|
|
455
|
+
path_output=path + "_cytoplasm_segmentation.png",
|
|
456
|
+
show=False,
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
def plot_labels(labelled_image: np.ndarray, path_output:str = None, show= True, axis= False, close= True):
|
|
460
|
+
"""
|
|
461
|
+
Plot a labelled image and indicate the label number at the center of each region.
|
|
462
|
+
"""
|
|
463
|
+
stack.check_parameter(labelled_image = (np.ndarray, list), show = (bool))
|
|
464
|
+
if isinstance(labelled_image, np.ndarray) :
|
|
465
|
+
stack.check_array(labelled_image, ndim= 2)
|
|
466
|
+
labelled_image = [labelled_image]
|
|
467
|
+
|
|
468
|
+
#Setting a colormap with background to white so all cells can be visible
|
|
469
|
+
viridis = mpl.colormaps['viridis'].resampled(256)
|
|
470
|
+
newcolors = viridis(np.linspace(0, 1, 256))
|
|
471
|
+
white = np.array([1, 1, 1, 1])
|
|
472
|
+
newcolors[0, :] = white
|
|
473
|
+
newcmp = ListedColormap(newcolors)
|
|
474
|
+
|
|
475
|
+
plt.figure(figsize= (10,10))
|
|
476
|
+
rescaled_image = stack.rescale(np.array(labelled_image[0], dtype= np.int32), channel_to_stretch= 0)
|
|
477
|
+
rescaled_image[rescaled_image == 0] = -100
|
|
478
|
+
plot = plt.imshow(rescaled_image, cmap=newcmp)
|
|
479
|
+
plot.axes.get_xaxis().set_visible(axis)
|
|
480
|
+
plot.axes.get_yaxis().set_visible(axis)
|
|
481
|
+
plt.tight_layout()
|
|
482
|
+
|
|
483
|
+
for index in range(0, len(labelled_image)) :
|
|
484
|
+
centroid_dict = from_label_get_centeroidscoords(labelled_image[index])
|
|
485
|
+
labels = centroid_dict["label"]
|
|
486
|
+
Y = centroid_dict["centroid-0"]
|
|
487
|
+
X = centroid_dict["centroid-1"]
|
|
488
|
+
centroids = zip(Y,X)
|
|
489
|
+
|
|
490
|
+
for label in labels :
|
|
491
|
+
y,x = next(centroids)
|
|
492
|
+
y,x = round(y), round(x)
|
|
493
|
+
an = plt.annotate(str(label), [round(x), round(y)])
|
|
494
|
+
|
|
495
|
+
if not axis : plt.cla
|
|
496
|
+
if show : plt.show()
|
|
497
|
+
if path_output != None :
|
|
498
|
+
stack.check_parameter(path_output = (str))
|
|
499
|
+
plt.savefig(path_output)
|
|
500
|
+
if close : plt.close()
|
|
501
|
+
|
|
502
|
+
return plot
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This submodule groups all the possible actions of the user in the main windows. It is the start of each action the user can do.
|
|
3
|
+
"""
|
|
4
|
+
|
|
1
5
|
from ..gui.prompts import output_image_prompt, ask_detection_confirmation, ask_cancel_detection
|
|
2
6
|
from ..interface.output import write_results
|
|
3
7
|
from ._preprocess import map_channels, prepare_image_detection, reorder_shape, reorder_image_stack
|
|
@@ -25,6 +29,8 @@ def add_detection(user_parameters, segmentation_done, acquisition_id, cytoplasm_
|
|
|
25
29
|
user_parameters.update(new_parameters)
|
|
26
30
|
|
|
27
31
|
map = map_channels(user_parameters)
|
|
32
|
+
if type(map) == type(None) : #User clicks Cancel
|
|
33
|
+
return new_results_df, new_cell_results_df, acquisition_id, user_parameters, segmentation_done, cytoplasm_label, nucleus_label
|
|
28
34
|
user_parameters['reordered_shape'] = reorder_shape(user_parameters['shape'], map)
|
|
29
35
|
|
|
30
36
|
|
|
@@ -89,7 +95,6 @@ def add_detection(user_parameters, segmentation_done, acquisition_id, cytoplasm_
|
|
|
89
95
|
if user_parameters['spots_extraction_folder'] != '' and type(user_parameters['spots_extraction_folder']) != type(None) :
|
|
90
96
|
if user_parameters['spots_filename'] != '' and type(user_parameters['spots_filename']) != type(None) :
|
|
91
97
|
if any((user_parameters['do_spots_excel'], user_parameters['do_spots_csv'], user_parameters['do_spots_feather'])) :
|
|
92
|
-
print((user_parameters['do_spots_excel'], user_parameters['do_spots_csv'], user_parameters['do_spots_feather']))
|
|
93
98
|
launch_spots_extraction(
|
|
94
99
|
acquisition_id=acquisition_id,
|
|
95
100
|
user_parameters=user_parameters,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Contains code to handle detection as well as bigfish wrappers related to spot detection.
|
|
3
3
|
"""
|
|
4
|
-
|
|
5
4
|
from ._preprocess import ParameterInputError
|
|
6
5
|
from ._preprocess import check_integrity, convert_parameters_types
|
|
7
6
|
from ._signaltonoise import compute_snr_spots
|
|
@@ -26,6 +25,7 @@ import bigfish.classification as classification
|
|
|
26
25
|
from bigfish.detection.spot_detection import get_object_radius_pixel
|
|
27
26
|
from types import GeneratorType
|
|
28
27
|
from skimage.measure import regionprops
|
|
28
|
+
from scipy.ndimage import binary_dilation
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
def ask_input_parameters(ask_for_segmentation=True) :
|
|
@@ -278,11 +278,18 @@ def initiate_detection(user_parameters, segmentation_done, map, shape) :
|
|
|
278
278
|
segmentation_done= segmentation_done,
|
|
279
279
|
default_dict=user_parameters
|
|
280
280
|
)
|
|
281
|
-
|
|
282
281
|
if type(user_parameters) == type(None) : return user_parameters
|
|
283
282
|
try :
|
|
284
283
|
user_parameters = convert_parameters_types(user_parameters)
|
|
285
|
-
user_parameters = check_integrity(
|
|
284
|
+
user_parameters = check_integrity(
|
|
285
|
+
user_parameters,
|
|
286
|
+
do_dense_region_deconvolution,
|
|
287
|
+
do_clustering,
|
|
288
|
+
is_multichannel,
|
|
289
|
+
segmentation_done,
|
|
290
|
+
map,
|
|
291
|
+
shape
|
|
292
|
+
)
|
|
286
293
|
except ParameterInputError as error:
|
|
287
294
|
sg.popup(error)
|
|
288
295
|
else :
|
|
@@ -306,7 +313,7 @@ def _launch_detection(image, image_input_values: dict) :
|
|
|
306
313
|
threshold_user_selection = image_input_values.get('Interactive threshold selector')
|
|
307
314
|
|
|
308
315
|
if type(threshold) == type(None) :
|
|
309
|
-
threshold = compute_auto_threshold(image, voxel_size=voxel_size, spot_radius=spot_size, log_kernel_size=log_kernel_size, minimum_distance=minimum_distance)
|
|
316
|
+
threshold = threshold_penalty * compute_auto_threshold(image, voxel_size=voxel_size, spot_radius=spot_size, log_kernel_size=log_kernel_size, minimum_distance=minimum_distance)
|
|
310
317
|
|
|
311
318
|
filtered_image = _apply_log_filter(
|
|
312
319
|
image=image,
|
|
@@ -403,7 +410,7 @@ def launch_post_detection(image, spots, image_input_values: dict,) :
|
|
|
403
410
|
#appending results
|
|
404
411
|
fov_res.update(snr_res)
|
|
405
412
|
|
|
406
|
-
return
|
|
413
|
+
return fov_res
|
|
407
414
|
|
|
408
415
|
def _compute_cell_snr(image: np.ndarray, bbox, spots, voxel_size, spot_size) :
|
|
409
416
|
|
|
@@ -592,7 +599,8 @@ def launch_detection(
|
|
|
592
599
|
other_image,
|
|
593
600
|
user_parameters,
|
|
594
601
|
cell_label= None,
|
|
595
|
-
nucleus_label = None
|
|
602
|
+
nucleus_label = None,
|
|
603
|
+
hide_loading=False,
|
|
596
604
|
) :
|
|
597
605
|
"""
|
|
598
606
|
Main call for features computation :
|
|
@@ -618,18 +626,17 @@ def launch_detection(
|
|
|
618
626
|
do_dense_region_deconvolution = user_parameters['Dense regions deconvolution']
|
|
619
627
|
do_clustering = user_parameters['Cluster computation']
|
|
620
628
|
|
|
621
|
-
spots, threshold = _launch_detection(image, user_parameters)
|
|
629
|
+
spots, threshold = _launch_detection(image, user_parameters, hide_loading = hide_loading)
|
|
622
630
|
|
|
623
631
|
if do_dense_region_deconvolution :
|
|
624
|
-
spots = launch_dense_region_deconvolution(image, spots, user_parameters)
|
|
632
|
+
spots = launch_dense_region_deconvolution(image, spots, user_parameters, hide_loading = hide_loading)
|
|
625
633
|
|
|
626
634
|
if do_clustering :
|
|
627
|
-
clusters = launch_clustering(spots, user_parameters) #012 are coordinates #3 is number of spots per cluster, #4 is cluster index
|
|
635
|
+
clusters = launch_clustering(spots, user_parameters, hide_loading = hide_loading) #012 are coordinates #3 is number of spots per cluster, #4 is cluster index
|
|
628
636
|
clusters = _update_clusters(clusters, spots, voxel_size=user_parameters['voxel_size'], cluster_size=user_parameters['cluster size'], min_spot_number= user_parameters['min number of spots'], shape=image.shape)
|
|
629
637
|
|
|
630
638
|
else : clusters = None
|
|
631
639
|
|
|
632
|
-
spots, post_detection_dict = launch_post_detection(image, spots, user_parameters)
|
|
633
640
|
user_parameters['threshold'] = threshold
|
|
634
641
|
|
|
635
642
|
if user_parameters['Napari correction'] :
|
|
@@ -645,7 +652,7 @@ def launch_detection(
|
|
|
645
652
|
nucleus_label=nucleus_label,
|
|
646
653
|
other_images=other_image
|
|
647
654
|
)
|
|
648
|
-
|
|
655
|
+
post_detection_dict = launch_post_detection(image, spots, user_parameters, hide_loading = hide_loading)
|
|
649
656
|
fov_result.update(post_detection_dict)
|
|
650
657
|
|
|
651
658
|
return user_parameters, fov_result, spots, clusters
|
|
@@ -773,12 +780,13 @@ def _create_threshold_slider(
|
|
|
773
780
|
'size': 5,
|
|
774
781
|
'scale' : scale,
|
|
775
782
|
'face_color' : 'transparent',
|
|
776
|
-
'edge_color' : '
|
|
777
|
-
'symbol' : '
|
|
783
|
+
'edge_color' : 'red',
|
|
784
|
+
'symbol' : 'disc',
|
|
778
785
|
'opacity' : 0.7,
|
|
779
|
-
'blending' : '
|
|
786
|
+
'blending' : 'translucent',
|
|
780
787
|
'name': 'single spots',
|
|
781
|
-
'features' : {'threshold' : threshold}
|
|
788
|
+
'features' : {'threshold' : threshold},
|
|
789
|
+
'visible' : True,
|
|
782
790
|
}
|
|
783
791
|
return (spots, layer_args , 'points')
|
|
784
792
|
return threshold_slider
|
|
@@ -825,4 +833,55 @@ def _local_maxima_mask(
|
|
|
825
833
|
ndim=ndim)
|
|
826
834
|
mask_local_max = detection.local_maximum_detection(image_filtered, minimum_distance)
|
|
827
835
|
|
|
828
|
-
return mask_local_max.astype(bool)
|
|
836
|
+
return mask_local_max.astype(bool)
|
|
837
|
+
|
|
838
|
+
def output_spot_tiffvisual(channel,spots_list, path_output, dot_size = 3, rescale = True):
|
|
839
|
+
|
|
840
|
+
"""
|
|
841
|
+
Outputs a tiff image with one channel being {channel} and the other a mask containing dots where sports are located.
|
|
842
|
+
|
|
843
|
+
Parameters
|
|
844
|
+
----------
|
|
845
|
+
channel : np.ndarray
|
|
846
|
+
3D monochannel image
|
|
847
|
+
spots : list[np.ndarray] or np.ndarray
|
|
848
|
+
Spots arrays are ndarray where each element corresponds is a tuple(z,y,x) corresponding to 3D coordinate of a spot
|
|
849
|
+
To plot different spots on different channels a list of spots ndarray can be passed.
|
|
850
|
+
path_output : str
|
|
851
|
+
dot_size : int
|
|
852
|
+
in pixels
|
|
853
|
+
"""
|
|
854
|
+
|
|
855
|
+
stack.check_parameter(channel = (np.ndarray), spots_list= (list, np.ndarray), path_output = (str), dot_size = (int))
|
|
856
|
+
stack.check_array(channel, ndim= [2,3])
|
|
857
|
+
if isinstance(spots_list, np.ndarray) : spots_list = [spots_list]
|
|
858
|
+
|
|
859
|
+
if channel.ndim == 3 :
|
|
860
|
+
channel = stack.maximum_projection(channel)
|
|
861
|
+
|
|
862
|
+
im = np.zeros([1 + len(spots_list)] + list(channel.shape))
|
|
863
|
+
im[0,:,:] = channel
|
|
864
|
+
|
|
865
|
+
for level in range(len(spots_list)) :
|
|
866
|
+
if len(spots_list[level]) == 0 : continue
|
|
867
|
+
else :
|
|
868
|
+
spots_mask = np.zeros_like(channel)
|
|
869
|
+
|
|
870
|
+
#Unpacking spots
|
|
871
|
+
if len(spots_list[level][0]) == 2 :
|
|
872
|
+
Y,X = zip(*spots_list[level])
|
|
873
|
+
elif len(spots_list[level][0]) == 3 :
|
|
874
|
+
Z,Y,X = zip(*spots_list[level])
|
|
875
|
+
del Z
|
|
876
|
+
else :
|
|
877
|
+
Z,Y,X,*_ = zip(*spots_list[level])
|
|
878
|
+
del Z,_
|
|
879
|
+
|
|
880
|
+
#Reconstructing signal
|
|
881
|
+
spots_mask[Y,X] = 1
|
|
882
|
+
if dot_size > 1 : spots_mask = binary_dilation(spots_mask, iterations= dot_size-1)
|
|
883
|
+
spots_mask = stack.rescale(np.array(spots_mask, dtype = channel.dtype))
|
|
884
|
+
im[level + 1] = spots_mask
|
|
885
|
+
|
|
886
|
+
if rescale : channel = stack.rescale(channel, channel_to_stretch= 0)
|
|
887
|
+
stack.save_image(im, path_output, extension= 'tif')
|