small-fish-gui 1.4.0__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/prompt.py +6 -4
- small_fish_gui/docs/conf.py +1 -0
- small_fish_gui/gui/layout.py +21 -3
- small_fish_gui/gui/prompts.py +8 -6
- small_fish_gui/pipeline/_napari_wrapper.py +63 -90
- small_fish_gui/pipeline/_preprocess.py +24 -20
- small_fish_gui/pipeline/_segmentation.py +130 -17
- small_fish_gui/pipeline/actions.py +6 -1
- small_fish_gui/pipeline/detection.py +8 -10
- small_fish_gui/pipeline/main.py +5 -2
- small_fish_gui/pipeline/utils.py +16 -0
- {small_fish_gui-1.4.0.dist-info → small_fish_gui-1.5.0.dist-info}/METADATA +1 -1
- {small_fish_gui-1.4.0.dist-info → small_fish_gui-1.5.0.dist-info}/RECORD +18 -15
- {small_fish_gui-1.4.0.dist-info → small_fish_gui-1.5.0.dist-info}/WHEEL +0 -0
- {small_fish_gui-1.4.0.dist-info → small_fish_gui-1.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# .readthedocs.yaml
|
|
2
|
+
# Read the Docs configuration file
|
|
3
|
+
# See for details
|
|
4
|
+
|
|
5
|
+
# Required
|
|
6
|
+
version: 2
|
|
7
|
+
|
|
8
|
+
# Set the OS, Python version and other tools you might need
|
|
9
|
+
build:
|
|
10
|
+
os: ubuntu-22.04
|
|
11
|
+
tools:
|
|
12
|
+
python: "3.8"
|
|
13
|
+
|
|
14
|
+
# Build documentation in the "docs/" directory with Sphinx
|
|
15
|
+
sphinx:
|
|
16
|
+
configuration: docs/conf.py
|
|
17
|
+
|
|
18
|
+
# Optionally build your docs in additional formats such as PDF and ePub
|
|
19
|
+
formats:
|
|
20
|
+
- pdf
|
|
21
|
+
- epub
|
small_fish_gui/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Cell segmentation (**2D**) is peformed using *cellpose* (published work) : https
|
|
|
5
5
|
|
|
6
6
|
Spot detection is performed via *big-fish* (published work) : https://github.com/fish-quant/big-fish
|
|
7
7
|
|
|
8
|
-
Time stacks are not
|
|
8
|
+
**Time stacks are not supported.**
|
|
9
9
|
|
|
10
10
|
## What can you do with small fish ?
|
|
11
11
|
|
|
@@ -77,7 +77,7 @@ If you run into any problems I would recommend following the official cellpose i
|
|
|
77
77
|
|
|
78
78
|
|
|
79
79
|
### Training cellpose
|
|
80
|
-
If you want to train your own cellpose model or import custom model from exterior source I recommend doing so from the cellpose GUI
|
|
80
|
+
If you want to train your own cellpose model or import custom model from exterior source I recommend doing so from the cellpose GUI. Note that Small fish uses mean projection to segment images in 2D, if you want to retrain a cellpose model to fit your data it is recommended to do so on mean or max projection of your data.
|
|
81
81
|
|
|
82
82
|
To install the GUI run :
|
|
83
83
|
|
|
@@ -93,6 +93,5 @@ Note that for training it is recommended to first set up your GPU as training co
|
|
|
93
93
|
## Developpement
|
|
94
94
|
|
|
95
95
|
Optional features to include in future versions :
|
|
96
|
-
- batch processing
|
|
97
96
|
- time stack (which would include cell tracking)
|
|
98
97
|
- 3D segmentation
|
small_fish_gui/__init__.py
CHANGED
small_fish_gui/batch/prompt.py
CHANGED
|
@@ -35,7 +35,7 @@ def batch_promp(
|
|
|
35
35
|
sanity_header = sg.Text("Dimension sanity", font=('bold',15), pad=(0,10))
|
|
36
36
|
dimension_number_text = sg.Text("Dimension number : unknown")
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
#LAYOUT INIT
|
|
39
39
|
#########################################
|
|
40
40
|
##### COLUMNS
|
|
41
41
|
#########################################
|
|
@@ -182,8 +182,6 @@ def batch_promp(
|
|
|
182
182
|
[tab_col, launch_col],
|
|
183
183
|
[stream_output],
|
|
184
184
|
]
|
|
185
|
-
stream_output.restore_stderr()
|
|
186
|
-
stream_output.restore_stdout()
|
|
187
185
|
|
|
188
186
|
window = sg.Window("small fish", layout=layout, size= (800,800), auto_size_buttons=True, auto_size_text=True, resizable=True)
|
|
189
187
|
|
|
@@ -332,7 +330,11 @@ def batch_promp(
|
|
|
332
330
|
batch_name_input.update(value=values.get('batch_name'))
|
|
333
331
|
|
|
334
332
|
elif event == "Cancel" :
|
|
335
|
-
|
|
333
|
+
stream_output.restore_stderr()
|
|
334
|
+
stream_output.restore_stdout()
|
|
335
|
+
window.close()
|
|
336
|
+
return results_df, cell_results_df, acquisition_id, preset, False, None,None #Segmentation done : False, cell label : None, Nucleus label : None
|
|
337
|
+
|
|
336
338
|
|
|
337
339
|
elif event == None :
|
|
338
340
|
raise InterruptedError("closed")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#init conf file
|
small_fish_gui/gui/layout.py
CHANGED
|
@@ -95,7 +95,7 @@ def path_layout(keys= [],look_for_dir = False, header=None, preset=os.getcwd())
|
|
|
95
95
|
|
|
96
96
|
max_length = len(max(keys, key=len))
|
|
97
97
|
layout = [
|
|
98
|
-
[sg.Text(pad_right(name, max_length, ' ')), Browse(key= name, initial_folder= preset)] for name in keys
|
|
98
|
+
[sg.Text(pad_right(name, max_length, ' ')), Browse(key= name, target=(555666777,2), initial_folder= preset), sg.Text('')] for name in keys
|
|
99
99
|
]
|
|
100
100
|
if isinstance(header, str) :
|
|
101
101
|
layout = [add_header(header)] + layout
|
|
@@ -152,7 +152,20 @@ def radio_layout(values, header=None) :
|
|
|
152
152
|
layout = [add_header(header)] + layout
|
|
153
153
|
return layout
|
|
154
154
|
|
|
155
|
-
def _segmentation_layout(
|
|
155
|
+
def _segmentation_layout(
|
|
156
|
+
multichannel,
|
|
157
|
+
cytoplasm_model_preset= 'cyto3',
|
|
158
|
+
nucleus_model_preset= 'nuclei',
|
|
159
|
+
cytoplasm_channel_preset=0,
|
|
160
|
+
nucleus_channel_preset=0,
|
|
161
|
+
other_nucleus_image_preset = None,
|
|
162
|
+
cyto_diameter_preset=30,
|
|
163
|
+
nucleus_diameter_preset= 30,
|
|
164
|
+
show_segmentation_preset= False,
|
|
165
|
+
segment_only_nuclei_preset=False,
|
|
166
|
+
saving_path_preset=os.getcwd(),
|
|
167
|
+
filename_preset='cell_segmentation.png',
|
|
168
|
+
) :
|
|
156
169
|
|
|
157
170
|
USE_GPU = use_gpu()
|
|
158
171
|
|
|
@@ -160,7 +173,9 @@ def _segmentation_layout(multichannel, cytoplasm_model_preset= 'cyto2', nucleus_
|
|
|
160
173
|
if len(models_list) == 0 : models_list = ['no model found']
|
|
161
174
|
|
|
162
175
|
#Header : GPU availabality
|
|
163
|
-
layout = [
|
|
176
|
+
layout = [
|
|
177
|
+
[sg.Text("GPU is currently "), sg.Text('ON', text_color= 'green') if USE_GPU else sg.Text('OFF', text_color= 'red')]
|
|
178
|
+
]
|
|
164
179
|
|
|
165
180
|
#cytoplasm parameters
|
|
166
181
|
layout += [
|
|
@@ -170,6 +185,8 @@ def _segmentation_layout(multichannel, cytoplasm_model_preset= 'cyto2', nucleus_
|
|
|
170
185
|
]
|
|
171
186
|
|
|
172
187
|
if multichannel : layout += parameters_layout(['cytoplasm channel'],default_values= [cytoplasm_channel_preset])
|
|
188
|
+
|
|
189
|
+
|
|
173
190
|
layout += parameters_layout(['cytoplasm diameter'], unit= "px", default_values= [cyto_diameter_preset])
|
|
174
191
|
#Nucleus parameters
|
|
175
192
|
layout += [
|
|
@@ -179,6 +196,7 @@ def _segmentation_layout(multichannel, cytoplasm_model_preset= 'cyto2', nucleus_
|
|
|
179
196
|
]
|
|
180
197
|
|
|
181
198
|
if multichannel : layout += parameters_layout(['nucleus channel'], default_values= [nucleus_channel_preset])
|
|
199
|
+
layout += path_layout(['other_nucleus_image'], preset=other_nucleus_image_preset)
|
|
182
200
|
layout += parameters_layout([ 'nucleus diameter'],unit= "px", default_values= [nucleus_diameter_preset])
|
|
183
201
|
layout += bool_layout(["Segment only nuclei"], preset=segment_only_nuclei_preset)
|
|
184
202
|
|
small_fish_gui/gui/prompts.py
CHANGED
|
@@ -32,14 +32,14 @@ def prompt(layout, add_ok_cancel=True, timeout=None, timeout_key='TIMEOUT_KEY',
|
|
|
32
32
|
window.close()
|
|
33
33
|
return event, values
|
|
34
34
|
|
|
35
|
-
def prompt_with_help(layout, help =None, add_scrollbar=True) :
|
|
35
|
+
def prompt_with_help(layout, help =None, add_scrollbar=True, vertical_scroll_only=True) :
|
|
36
36
|
layout += [[]]
|
|
37
37
|
layout += [[sg.Button('Help')]]
|
|
38
38
|
layout += [[sg.Button('Ok'), sg.Button('Cancel')]]
|
|
39
39
|
|
|
40
40
|
if add_scrollbar :
|
|
41
41
|
size = (400,500)
|
|
42
|
-
col_elmt = sg.Column(layout, scrollable=True, vertical_scroll_only=
|
|
42
|
+
col_elmt = sg.Column(layout, scrollable=True, vertical_scroll_only=vertical_scroll_only, size=size)
|
|
43
43
|
layout = [[col_elmt]]
|
|
44
44
|
else :
|
|
45
45
|
size = (None,None)
|
|
@@ -280,11 +280,13 @@ def _warning_popup(warning:str) :
|
|
|
280
280
|
|
|
281
281
|
def _sumup_df(results: pd.DataFrame) :
|
|
282
282
|
|
|
283
|
+
COLUMNS = ['acquisition_id','threshold', 'spot_number', 'cell_number', 'filename', 'channel to compute']
|
|
284
|
+
|
|
283
285
|
if len(results) > 0 :
|
|
284
286
|
if 'channel to compute' not in results : results['channel to compute'] = np.NaN
|
|
285
|
-
res = results.loc[:,
|
|
287
|
+
res = results.loc[:,COLUMNS]
|
|
286
288
|
else :
|
|
287
|
-
res = pd.DataFrame(columns=
|
|
289
|
+
res = pd.DataFrame(columns= COLUMNS)
|
|
288
290
|
|
|
289
291
|
return res
|
|
290
292
|
|
|
@@ -293,9 +295,9 @@ def hub_prompt(fov_results, do_segmentation=False) :
|
|
|
293
295
|
sumup_df = _sumup_df(fov_results)
|
|
294
296
|
|
|
295
297
|
if do_segmentation :
|
|
296
|
-
segmentation_object = sg.Text('Segmentation
|
|
298
|
+
segmentation_object = sg.Text('Segmentation in memory', font='8', text_color= 'green')
|
|
297
299
|
else :
|
|
298
|
-
segmentation_object = sg.Text('
|
|
300
|
+
segmentation_object = sg.Text('No segmentation in memory', font='8', text_color= 'red')
|
|
299
301
|
|
|
300
302
|
layout = [
|
|
301
303
|
[sg.Text('RESULTS', font= 'bold 13')],
|
|
@@ -2,59 +2,26 @@
|
|
|
2
2
|
Contains Napari wrappers to visualise and correct spots/clusters.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
import napari.layers
|
|
6
|
+
import napari.types
|
|
5
7
|
import numpy as np
|
|
6
|
-
import scipy.ndimage as ndi
|
|
7
8
|
import napari
|
|
8
9
|
|
|
9
|
-
from napari.utils.events import Event
|
|
10
|
-
from napari.layers import Points
|
|
11
10
|
from bigfish.stack import check_parameter
|
|
12
11
|
from ..utils import compute_anisotropy_coef
|
|
13
12
|
from ._colocalisation import spots_multicolocalisation
|
|
14
13
|
|
|
15
|
-
class Points_callback :
|
|
16
|
-
"""
|
|
17
|
-
Custom class to handle points number evolution during Napari run.
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
def __init__(self, points, next_id) -> None:
|
|
21
|
-
self.points = points
|
|
22
|
-
self.next_id = next_id
|
|
23
|
-
self._set_callback()
|
|
24
|
-
|
|
25
|
-
def __str__(self) -> str:
|
|
26
|
-
string = 'Points_callback object state :\ncurrent_points_number : {0}\ncurrnet_id : {1}'.format(self.current_points_number, self.next_id)
|
|
27
|
-
return string
|
|
28
|
-
|
|
29
|
-
def get_points(self) :
|
|
30
|
-
return self.points
|
|
31
|
-
|
|
32
|
-
def get_next_id(self) :
|
|
33
|
-
return self.next_id
|
|
34
|
-
|
|
35
|
-
def _set_callback(self) :
|
|
36
|
-
def callback(event:Event) :
|
|
37
|
-
|
|
38
|
-
old_points = self.get_points()
|
|
39
|
-
new_points:Points = event.source.data
|
|
40
|
-
features = event.source.features
|
|
41
|
-
|
|
42
|
-
current_point_number = len(old_points)
|
|
43
|
-
next_id = self.get_next_id()
|
|
44
|
-
new_points_number = len(new_points)
|
|
45
|
-
|
|
46
|
-
if new_points_number > current_point_number :
|
|
47
|
-
features.at[new_points_number - 1, "id"] = next_id
|
|
48
|
-
self.next_id += 1
|
|
49
|
-
|
|
50
|
-
#preparing next callback
|
|
51
|
-
self.points = new_points
|
|
52
|
-
self._set_callback()
|
|
53
|
-
self.callback = callback
|
|
54
|
-
|
|
55
14
|
def _update_clusters(new_clusters: np.ndarray, spots: np.ndarray, voxel_size, cluster_size, min_spot_number, shape) :
|
|
56
15
|
if len(new_clusters) == 0 : return new_clusters
|
|
57
16
|
if len(spots) == 0 : return new_clusters
|
|
17
|
+
|
|
18
|
+
if len(new_clusters[0]) in [2,3] :
|
|
19
|
+
new_clusters = np.concatenate([
|
|
20
|
+
new_clusters,
|
|
21
|
+
np.zeros(shape=(len(new_clusters),1), dtype=int),
|
|
22
|
+
np.arange(len(new_clusters), dtype=int).reshape(len(new_clusters),1)
|
|
23
|
+
],axis=1, dtype=int)
|
|
24
|
+
|
|
58
25
|
assert len(new_clusters[0]) == 4 or len(new_clusters[0]) == 5, "Wrong number of coordinates for clusters should not happen."
|
|
59
26
|
|
|
60
27
|
# Update spots clusters
|
|
@@ -93,45 +60,48 @@ def correct_spots(image, spots, voxel_size= (1,1,1), clusters= None, cluster_siz
|
|
|
93
60
|
)
|
|
94
61
|
|
|
95
62
|
scale = compute_anisotropy_coef(voxel_size)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
63
|
+
Viewer = napari.Viewer(ndisplay=2, title= 'Spot correction', axis_labels=['z','y','x'], show= False)
|
|
64
|
+
Viewer.add_image(image, scale=scale, name= "rna signal", blending= 'additive', colormap='red', contrast_limits=[image.min(), image.max()])
|
|
65
|
+
other_colors = ['green', 'blue', 'gray', 'cyan', 'bop orange', 'bop purple'] * ((len(other_images)-1 // 7) + 1)
|
|
66
|
+
for im, color in zip(other_images, other_colors) :
|
|
67
|
+
Viewer.add_image(im, scale=scale, blending='additive', visible=False, colormap=color, contrast_limits=[im.min(), im.max()])
|
|
68
|
+
layer_offset = len(other_images)
|
|
69
|
+
|
|
70
|
+
Viewer.add_points( # single molecule spots; this layer can be update by user.
|
|
71
|
+
spots,
|
|
72
|
+
size = 5,
|
|
73
|
+
scale=scale,
|
|
74
|
+
face_color= 'transparent',
|
|
75
|
+
opacity= 1,
|
|
76
|
+
symbol= 'disc',
|
|
77
|
+
name= 'single spots'
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
if type(clusters) != type(None) : Viewer.add_points( # cluster; this layer can be update by user.
|
|
81
|
+
clusters[:,:dim],
|
|
82
|
+
size = 10,
|
|
83
|
+
scale=scale,
|
|
84
|
+
face_color= 'blue',
|
|
85
|
+
opacity= 0.7,
|
|
86
|
+
symbol= 'diamond',
|
|
87
|
+
name= 'foci',
|
|
88
|
+
features= {"spot_number" : clusters[:,dim], "id" : clusters[:,dim+1]},
|
|
89
|
+
feature_defaults= {"spot_number" : 0, "id" : -1}
|
|
90
|
+
)
|
|
119
91
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
],
|
|
126
|
-
axis= 1)
|
|
92
|
+
if type(cell_label) != type(None) and not np.array_equal(nucleus_label, cell_label) : Viewer.add_labels(cell_label, scale=scale, opacity= 0.2, blending= 'additive')
|
|
93
|
+
if type(nucleus_label) != type(None) : Viewer.add_labels(nucleus_label, scale=scale, opacity= 0.2, blending= 'additive')
|
|
94
|
+
|
|
95
|
+
Viewer.show(block=False)
|
|
96
|
+
napari.run()
|
|
127
97
|
|
|
128
|
-
|
|
129
|
-
else : new_clusters = None
|
|
98
|
+
new_spots = np.array(Viewer.layers['single spots'].data, dtype= int)
|
|
130
99
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
100
|
+
if type(clusters) != type(None) :
|
|
101
|
+
if len(clusters) > 0 :
|
|
102
|
+
new_clusters = np.array(Viewer.layers['foci'].data, dtype= int)
|
|
103
|
+
new_clusters = _update_clusters(new_clusters, new_spots, voxel_size=voxel_size, cluster_size=cluster_size, min_spot_number=min_spot_number, shape=image.shape)
|
|
104
|
+
else : new_clusters = None
|
|
135
105
|
|
|
136
106
|
return new_spots, new_clusters
|
|
137
107
|
|
|
@@ -168,25 +138,27 @@ def show_segmentation(
|
|
|
168
138
|
Viewer = napari.Viewer(ndisplay=2, title= 'Show segmentation', axis_labels=['z','y','x'] if dim == 3 else ['y', 'x'], show= False)
|
|
169
139
|
|
|
170
140
|
# Adding channels
|
|
171
|
-
Viewer.add_image(nuc_image, name= "nucleus signal", blending= 'additive', colormap='blue', contrast_limits=[nuc_image.min(), nuc_image.max()])
|
|
172
|
-
Viewer.add_labels(nuc_label, opacity= 0.5, blending= 'additive')
|
|
141
|
+
nuc_signal_layer = Viewer.add_image(nuc_image, name= "nucleus signal", blending= 'additive', colormap='blue', contrast_limits=[nuc_image.min(), nuc_image.max()])
|
|
142
|
+
nuc_label_layer = Viewer.add_labels(nuc_label, opacity= 0.5, blending= 'additive', name= 'nucleus_label',)
|
|
143
|
+
nuc_label_layer.preserve_labels = True
|
|
173
144
|
|
|
174
145
|
#Adding labels
|
|
175
146
|
if type(cyto_image) != type(None) : Viewer.add_image(cyto_image, name= "cytoplasm signal", blending= 'additive', colormap='red', contrast_limits=[cyto_image.min(), cyto_image.max()])
|
|
176
|
-
if type(cyto_label) != type(None) and not np.array_equal(cyto_label, nuc_label)
|
|
147
|
+
if (type(cyto_label) != type(None) and not np.array_equal(cyto_label, nuc_label) ) or (type(cyto_label) != type(None) and cyto_label.max() == 0):
|
|
148
|
+
cyto_label_layer = Viewer.add_labels(cyto_label, opacity= 0.4, blending= 'additive', name= 'cytoplasm_label')
|
|
149
|
+
cyto_label_layer.preserve_labels = True
|
|
177
150
|
|
|
178
151
|
#Launch Napari
|
|
179
152
|
Viewer.show(block=False)
|
|
180
153
|
napari.run()
|
|
181
154
|
|
|
182
|
-
|
|
183
|
-
|
|
155
|
+
|
|
156
|
+
new_nuc_label = Viewer.layers['nucleus_label'].data
|
|
157
|
+
if type(cyto_label) != type(None) and not np.array_equal(cyto_label, nuc_label) : new_cyto_label = Viewer.layers['cytoplasm_label'].data
|
|
184
158
|
else : new_cyto_label = new_nuc_label
|
|
185
159
|
|
|
186
160
|
return new_nuc_label, new_cyto_label
|
|
187
161
|
|
|
188
|
-
|
|
189
|
-
|
|
190
162
|
def threshold_selection(
|
|
191
163
|
image : np.ndarray,
|
|
192
164
|
filtered_image : np.ndarray,
|
|
@@ -195,7 +167,7 @@ def threshold_selection(
|
|
|
195
167
|
) :
|
|
196
168
|
|
|
197
169
|
"""
|
|
198
|
-
To view code for spot selection
|
|
170
|
+
To view code for spot selection have a look at magicgui instance created with `detection._create_threshold_slider` which is then passed to this napari wrapper as 'threshold_slider' argument.
|
|
199
171
|
"""
|
|
200
172
|
|
|
201
173
|
Viewer = napari.Viewer(title= "Small fish - Threshold selector", ndisplay=2, show=True)
|
|
@@ -218,12 +190,13 @@ def threshold_selection(
|
|
|
218
190
|
|
|
219
191
|
Viewer.window.add_dock_widget(threshold_slider, name='threshold_selector')
|
|
220
192
|
threshold_slider() #First occurence with auto or entered threshold.
|
|
193
|
+
|
|
221
194
|
napari.run()
|
|
222
195
|
|
|
223
|
-
spots = Viewer.layers[
|
|
196
|
+
spots = Viewer.layers['single spots'].data.astype(int)
|
|
224
197
|
if len(spots) == 0 :
|
|
225
|
-
|
|
198
|
+
pass
|
|
226
199
|
else :
|
|
227
|
-
threshold = Viewer.layers[
|
|
200
|
+
threshold = Viewer.layers['single spots'].properties.get('threshold')[0]
|
|
228
201
|
|
|
229
202
|
return spots, threshold
|
|
@@ -69,7 +69,7 @@ def map_channels(user_parameters) :
|
|
|
69
69
|
try :
|
|
70
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 :
|
|
@@ -125,14 +125,16 @@ def _auto_map_channels(is_3D_stack, is_time_stack, multichannel, image: np.ndarr
|
|
|
125
125
|
def _ask_channel_map(shape, is_3D_stack, is_time_stack, multichannel, preset_map: dict= {}) :
|
|
126
126
|
while True :
|
|
127
127
|
relaunch = False
|
|
128
|
+
save_preset = preset_map.copy()
|
|
128
129
|
x = preset_map.setdefault('x',0)
|
|
129
130
|
y = preset_map.setdefault('y',0)
|
|
130
131
|
z = preset_map.setdefault('z',0)
|
|
131
132
|
c = preset_map.setdefault('c',0)
|
|
132
133
|
t = preset_map.setdefault('t',0)
|
|
133
134
|
|
|
135
|
+
|
|
134
136
|
layout = [
|
|
135
|
-
add_header("Dimensions mapping"
|
|
137
|
+
add_header("Dimensions mapping") + [sg.Text("Image shape : {0}".format(shape))]
|
|
136
138
|
]
|
|
137
139
|
layout += [parameters_layout(['x','y'], default_values=[x,y])]
|
|
138
140
|
if is_3D_stack : layout += [parameters_layout(['z'], default_values=[z])]
|
|
@@ -140,7 +142,7 @@ def _ask_channel_map(shape, is_3D_stack, is_time_stack, multichannel, preset_map
|
|
|
140
142
|
if is_time_stack : layout += [parameters_layout(['t'], default_values=[t])]
|
|
141
143
|
|
|
142
144
|
event, preset_map = prompt_with_help(layout,help= 'mapping', add_scrollbar=False)
|
|
143
|
-
if event == 'Cancel' :
|
|
145
|
+
if event == 'Cancel' : return save_preset
|
|
144
146
|
|
|
145
147
|
#Check integrity
|
|
146
148
|
channels_values = np.array(list(preset_map.values()), dtype= int)
|
|
@@ -157,24 +159,26 @@ def _ask_channel_map(shape, is_3D_stack, is_time_stack, multichannel, preset_map
|
|
|
157
159
|
return preset_map
|
|
158
160
|
|
|
159
161
|
def _show_mapping(shape, map, is_3D_stack, is_time_stack, multichannel) :
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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')
|
|
176
181
|
|
|
177
|
-
return map
|
|
178
182
|
|
|
179
183
|
def convert_parameters_types(values:dict) :
|
|
180
184
|
"""
|
|
@@ -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)
|
|
@@ -386,4 +454,49 @@ def plot_segmentation(
|
|
|
386
454
|
contrast=True,
|
|
387
455
|
path_output=path + "_cytoplasm_segmentation.png",
|
|
388
456
|
show=False,
|
|
389
|
-
)
|
|
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
|
|
@@ -279,7 +278,6 @@ def initiate_detection(user_parameters, segmentation_done, map, shape) :
|
|
|
279
278
|
segmentation_done= segmentation_done,
|
|
280
279
|
default_dict=user_parameters
|
|
281
280
|
)
|
|
282
|
-
|
|
283
281
|
if type(user_parameters) == type(None) : return user_parameters
|
|
284
282
|
try :
|
|
285
283
|
user_parameters = convert_parameters_types(user_parameters)
|
|
@@ -315,7 +313,7 @@ def _launch_detection(image, image_input_values: dict) :
|
|
|
315
313
|
threshold_user_selection = image_input_values.get('Interactive threshold selector')
|
|
316
314
|
|
|
317
315
|
if type(threshold) == type(None) :
|
|
318
|
-
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)
|
|
319
317
|
|
|
320
318
|
filtered_image = _apply_log_filter(
|
|
321
319
|
image=image,
|
|
@@ -412,7 +410,7 @@ def launch_post_detection(image, spots, image_input_values: dict,) :
|
|
|
412
410
|
#appending results
|
|
413
411
|
fov_res.update(snr_res)
|
|
414
412
|
|
|
415
|
-
return
|
|
413
|
+
return fov_res
|
|
416
414
|
|
|
417
415
|
def _compute_cell_snr(image: np.ndarray, bbox, spots, voxel_size, spot_size) :
|
|
418
416
|
|
|
@@ -639,7 +637,6 @@ def launch_detection(
|
|
|
639
637
|
|
|
640
638
|
else : clusters = None
|
|
641
639
|
|
|
642
|
-
spots, post_detection_dict = launch_post_detection(image, spots, user_parameters, hide_loading = hide_loading)
|
|
643
640
|
user_parameters['threshold'] = threshold
|
|
644
641
|
|
|
645
642
|
if user_parameters['Napari correction'] :
|
|
@@ -655,7 +652,7 @@ def launch_detection(
|
|
|
655
652
|
nucleus_label=nucleus_label,
|
|
656
653
|
other_images=other_image
|
|
657
654
|
)
|
|
658
|
-
|
|
655
|
+
post_detection_dict = launch_post_detection(image, spots, user_parameters, hide_loading = hide_loading)
|
|
659
656
|
fov_result.update(post_detection_dict)
|
|
660
657
|
|
|
661
658
|
return user_parameters, fov_result, spots, clusters
|
|
@@ -783,12 +780,13 @@ def _create_threshold_slider(
|
|
|
783
780
|
'size': 5,
|
|
784
781
|
'scale' : scale,
|
|
785
782
|
'face_color' : 'transparent',
|
|
786
|
-
'edge_color' : '
|
|
787
|
-
'symbol' : '
|
|
783
|
+
'edge_color' : 'red',
|
|
784
|
+
'symbol' : 'disc',
|
|
788
785
|
'opacity' : 0.7,
|
|
789
|
-
'blending' : '
|
|
786
|
+
'blending' : 'translucent',
|
|
790
787
|
'name': 'single spots',
|
|
791
|
-
'features' : {'threshold' : threshold}
|
|
788
|
+
'features' : {'threshold' : threshold},
|
|
789
|
+
'visible' : True,
|
|
792
790
|
}
|
|
793
791
|
return (spots, layer_args , 'points')
|
|
794
792
|
return threshold_slider
|
small_fish_gui/pipeline/main.py
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
"""
|
|
2
|
+
This script is called when software starts; it is the main loop.
|
|
3
|
+
"""
|
|
4
|
+
|
|
2
5
|
import pandas as pd
|
|
3
6
|
import PySimpleGUI as sg
|
|
4
7
|
from ..gui import hub_prompt
|
|
@@ -7,7 +10,7 @@ from ._preprocess import clean_unused_parameters_cache
|
|
|
7
10
|
from ..batch import batch_promp
|
|
8
11
|
|
|
9
12
|
#'Global' parameters
|
|
10
|
-
user_parameters = dict() # Very important
|
|
13
|
+
user_parameters = dict() # Very important instance containg all choice from user that will influence the behavior of the actions loops.
|
|
11
14
|
acquisition_id = -1
|
|
12
15
|
result_df = pd.DataFrame()
|
|
13
16
|
cell_result_df = pd.DataFrame()
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from math import ceil
|
|
4
|
+
from itertools import zip_longest
|
|
5
|
+
from skimage.measure import regionprops_table
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def from_label_get_centeroidscoords(label: np.ndarray):
|
|
9
|
+
"""
|
|
10
|
+
Returns
|
|
11
|
+
--------
|
|
12
|
+
centroid : dict{"label": list, "centroid-n": list}
|
|
13
|
+
n should be replace with 1,2.. according to the axe you wish to access."""
|
|
14
|
+
|
|
15
|
+
centroid = regionprops_table(label, properties= ["label","centroid"])
|
|
16
|
+
return centroid
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: small_fish_gui
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.0
|
|
4
4
|
Summary: Small Fish is a python application for the analysis of smFish images. It provides a ready to use graphical interface to combine famous python packages for cell analysis without any need for coding.
|
|
5
5
|
Project-URL: Homepage, https://github.com/2Echoes/small_fish
|
|
6
6
|
Project-URL: Issues, https://github.com/2Echoes/small_fish/issues
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
small_fish_gui/.readthedocs.yaml,sha256=r2T0e_In8X8l0_ZwgPvuoWQ9c0PE9bSpFzV2W6EzW3g,409
|
|
1
2
|
small_fish_gui/LICENSE,sha256=-iFy8VGBYs5VsHglKpk4D-hxqQ2jMJaqmfq_ulIzDks,1303
|
|
2
|
-
small_fish_gui/README.md,sha256=
|
|
3
|
+
small_fish_gui/README.md,sha256=4RpEXKZW5vH6sUWeZb88yr1TLLPi20PqOk7KdA9O9Hk,4234
|
|
3
4
|
small_fish_gui/Segmentation example.jpg,sha256=opfiSbjmfF6z8kBs08sg_FNR2Om0AcMPU5sSwSLHdoQ,215038
|
|
4
|
-
small_fish_gui/__init__.py,sha256=
|
|
5
|
+
small_fish_gui/__init__.py,sha256=odndmnYjkNSVx0dzWpIehR8-0L2wqayHUx20vUHm-kg,1941
|
|
5
6
|
small_fish_gui/__main__.py,sha256=EzSCoJ7jpSdK-QbzUwQLGZeQWjybNeq8VnCBucA8MZw,1372
|
|
6
7
|
small_fish_gui/napari_detection_example.png,sha256=l5EZlrbXemLiGqb5inSVsD6Kko1Opz528-go-fBfrw8,977350
|
|
7
8
|
small_fish_gui/requirements.txt,sha256=9OMfUAnLdHevq6w_fVoDmVmkSMJeFofkOK_86_fu9C0,321
|
|
@@ -12,19 +13,20 @@ small_fish_gui/batch/input.py,sha256=mqnP8LBhyNbtlcqjVlUiVeuHw4YxOX3GgzJbq03isKE
|
|
|
12
13
|
small_fish_gui/batch/integrity.py,sha256=yzVWBwm4Mxftd1sDziQwKc7d3ALdgWOhkqQrU5-p430,4849
|
|
13
14
|
small_fish_gui/batch/output.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
15
|
small_fish_gui/batch/pipeline.py,sha256=uZCwkoiSnTHWAf7C4XPNXg4ldIjbpRiULpzZWq7R1i0,8798
|
|
15
|
-
small_fish_gui/batch/prompt.py,sha256=
|
|
16
|
+
small_fish_gui/batch/prompt.py,sha256=ZfOyWjmG2AZeB_wwbmqchEp6JM1duXM4GXj12r_eDZk,18788
|
|
16
17
|
small_fish_gui/batch/test.py,sha256=q04a1YstnDsxy2Bi5563BfcOU-O3VPE9c5WSJjvFjMg,211
|
|
17
18
|
small_fish_gui/batch/update.py,sha256=hR4kZ7tP2tvn1tmDa4oJb2e7-SUqN1Lf8JR6OCIOMS8,5037
|
|
18
19
|
small_fish_gui/batch/utils.py,sha256=HgfPwfhqWXOGtCny_nTdGs8csWB1BQp7-hYgrNVLB70,1774
|
|
19
20
|
small_fish_gui/batch/values.py,sha256=C1hRlCpTIDsg89DMKIIW5NUxeK876ODRUuJ2D-mJv6o,1519
|
|
20
21
|
small_fish_gui/batch/values.txt,sha256=PVxzIaaF6DGFRx_CMaStXZI6OrbjNub1-jR3pklXVjc,991
|
|
22
|
+
small_fish_gui/docs/conf.py,sha256=6YU8UEpTenKGMiz7H4aG42Of72_n4uLadDfHJvziqRk,16
|
|
21
23
|
small_fish_gui/gui/__init__.py,sha256=xQ_BfYcnQmKZtx_0leO4OmbkLNLv49ZPqEu_UXMgmDc,867
|
|
22
24
|
small_fish_gui/gui/animation.py,sha256=rnNP5FPp06Hu-R33c4AVTCknALBbxT2YlsKFCXHAp9k,981
|
|
23
25
|
small_fish_gui/gui/general_help_screenshot.png,sha256=X4E6Td5f04K-pBUPDaBJRAE3D5b8fuEdiAUKhkIDr-0,54210
|
|
24
26
|
small_fish_gui/gui/help_module.py,sha256=PmgkkDs7bZ2-po83A_PK9uldQcHjehYmqre21nYb6DQ,9600
|
|
25
|
-
small_fish_gui/gui/layout.py,sha256=
|
|
27
|
+
small_fish_gui/gui/layout.py,sha256=oB8Kg6s0rCA8yB4WM8JQY8BpjoPiBqTGb6YoOKDqEA8,13855
|
|
26
28
|
small_fish_gui/gui/mapping_help_screenshot.png,sha256=HcuRh5TYciUogUasza5vZ_QSshaiHsskQK23mh9vQS8,34735
|
|
27
|
-
small_fish_gui/gui/prompts.py,sha256=
|
|
29
|
+
small_fish_gui/gui/prompts.py,sha256=4QeYIqENmfffLv7255wVhG3N1tsOvRk33_r0prY11uY,13352
|
|
28
30
|
small_fish_gui/gui/segmentation_help_screenshot.png,sha256=rbSgIydT0gZtfMh1qk4mdMbEIyCaakvHmxa2eOrLwO0,118944
|
|
29
31
|
small_fish_gui/interface/__init__.py,sha256=PB86R4Y9kV80aGZ-vP0ZW2KeaCwGbBbCtFCmbN2yl28,275
|
|
30
32
|
small_fish_gui/interface/image.py,sha256=X1L7S5svxUwdoDcI3QM1PbN-c4Nz5w30hixq3IgqSn8,1130
|
|
@@ -34,16 +36,17 @@ small_fish_gui/interface/testing.py,sha256=MY5-GcPOUHagcrwR8A7QOjAmjZIDVC8Wz3Nib
|
|
|
34
36
|
small_fish_gui/pipeline/__init__.py,sha256=_Ey20GG8fJtqZvixbXNNYX6wTWMnCUArmARPqsNEhuQ,743
|
|
35
37
|
small_fish_gui/pipeline/_colocalisation.py,sha256=peBw2Qz5m6wSejDkDz240UgvWl8ohNelrnmEgznbEsw,9635
|
|
36
38
|
small_fish_gui/pipeline/_custom_errors.py,sha256=tQ-AUhgzIFpK30AZiQQrtHCHyGVRDdAoIjzL0Fk-1pA,43
|
|
37
|
-
small_fish_gui/pipeline/_napari_wrapper.py,sha256=
|
|
38
|
-
small_fish_gui/pipeline/_preprocess.py,sha256=
|
|
39
|
-
small_fish_gui/pipeline/_segmentation.py,sha256=
|
|
39
|
+
small_fish_gui/pipeline/_napari_wrapper.py,sha256=42c_PvKF8D_NW_CWysS4nZ2_Qp5vP9voaAH0bFJjJpc,8099
|
|
40
|
+
small_fish_gui/pipeline/_preprocess.py,sha256=ddocTXwc0vYq2VGUbWYaN9eUiHPyfiCuBpYQ2p6rQ8g,13084
|
|
41
|
+
small_fish_gui/pipeline/_segmentation.py,sha256=gcanidUOC9nULF6UffWLFmfIup-EOMxeckBz7Xldp3I,18852
|
|
40
42
|
small_fish_gui/pipeline/_signaltonoise.py,sha256=7A9t7xu7zghI6cr201Ldm-LjJ5NOuP56VSeJ8KIzcUo,8497
|
|
41
|
-
small_fish_gui/pipeline/actions.py,sha256=
|
|
42
|
-
small_fish_gui/pipeline/detection.py,sha256=
|
|
43
|
-
small_fish_gui/pipeline/main.py,sha256=
|
|
43
|
+
small_fish_gui/pipeline/actions.py,sha256=_egZlClWAeq6z2sEp2o031dL80ecmmGVDKwnouKTxkU,8185
|
|
44
|
+
small_fish_gui/pipeline/detection.py,sha256=JpT6IDiwyzbMzi2CcBu96RWWwdNbwlXgkVWI4fSr_Mw,34429
|
|
45
|
+
small_fish_gui/pipeline/main.py,sha256=igBR8cQ2H5xmpI2Q0w3DcAHt92wZSYxA0m217a7OG2c,3484
|
|
44
46
|
small_fish_gui/pipeline/spots.py,sha256=yHvqf1eD25UltELpzcouYXhLkxiXI_mOL1ANSzXK5pw,1907
|
|
45
47
|
small_fish_gui/pipeline/test.py,sha256=w4ZMGDmUDXxVgWTlZ2TKw19W8q5gcE9gLMKe0SWnRrw,2827
|
|
46
|
-
small_fish_gui
|
|
47
|
-
small_fish_gui-1.
|
|
48
|
-
small_fish_gui-1.
|
|
49
|
-
small_fish_gui-1.
|
|
48
|
+
small_fish_gui/pipeline/utils.py,sha256=run6qtqCAe_mFnE3o1CnmF1xBBmK3ydgc8-jOV9P-_w,448
|
|
49
|
+
small_fish_gui-1.5.0.dist-info/METADATA,sha256=TdTS-eCK_0wDVkBxz7RPNSUp2F9eYzoGwDIJpWawugY,2567
|
|
50
|
+
small_fish_gui-1.5.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
51
|
+
small_fish_gui-1.5.0.dist-info/licenses/LICENSE,sha256=-iFy8VGBYs5VsHglKpk4D-hxqQ2jMJaqmfq_ulIzDks,1303
|
|
52
|
+
small_fish_gui-1.5.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|