small-fish-gui 1.1.0__py3-none-any.whl → 1.3.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/README.md +48 -1
- small_fish_gui/Segmentation example.jpg +0 -0
- small_fish_gui/__init__.py +1 -1
- small_fish_gui/__main__.py +16 -2
- small_fish_gui/gui/layout.py +3 -3
- small_fish_gui/gui/prompts.py +24 -5
- small_fish_gui/interface/output.py +13 -6
- small_fish_gui/napari_detection_example.png +0 -0
- small_fish_gui/pipeline/_colocalisation.py +7 -7
- small_fish_gui/pipeline/{_detection_visualisation.py → _napari_wrapper.py} +93 -4
- small_fish_gui/pipeline/_preprocess.py +19 -2
- small_fish_gui/pipeline/_segmentation.py +33 -14
- small_fish_gui/pipeline/actions.py +54 -7
- small_fish_gui/pipeline/detection.py +163 -28
- small_fish_gui/pipeline/main.py +9 -3
- small_fish_gui/pipeline/spots.py +71 -0
- {small_fish_gui-1.1.0.dist-info → small_fish_gui-1.3.0.dist-info}/METADATA +1 -1
- small_fish_gui-1.3.0.dist-info/RECORD +38 -0
- {small_fish_gui-1.1.0.dist-info → small_fish_gui-1.3.0.dist-info}/WHEEL +1 -1
- small_fish_gui/start.py +0 -7
- small_fish_gui-1.1.0.dist-info/RECORD +0 -36
- {small_fish_gui-1.1.0.dist-info → small_fish_gui-1.3.0.dist-info}/licenses/LICENSE +0 -0
small_fish_gui/README.md
CHANGED
|
@@ -15,13 +15,16 @@ Time stacks are not yet supported.
|
|
|
15
15
|
- Signal to noise analysis
|
|
16
16
|
- multichannel colocalisation
|
|
17
17
|
|
|
18
|
+
<img src="https://github.com/2Echoes/small_fish_gui/blob/main/Segmentation%20example.jpg" width="500" title="Cell segmentation with Cellpose" alt="Cell segmentation - cellpose">| <img src="https://github.com/2Echoes/small_fish_gui/blob/main/napari_detection_example.png" width="500" title="Spot detection; clustering visualisation on Napari" alt="detection; Napari example">
|
|
19
|
+
|
|
18
20
|
## Installation
|
|
21
|
+
If you don't have a python installation yet I would recommend the [miniconda distribution](https://docs.anaconda.com/free/miniconda/miniconda-other-installer-links/); but any distribution should work.
|
|
19
22
|
|
|
20
23
|
It is higly recommanded to create a specific [conda](https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html) or [virtual](https://docs.python.org/3.6/library/venv.html) environnement to install small fish.
|
|
21
24
|
|
|
22
25
|
```bash
|
|
23
26
|
conda create -n small_fish python=3.8
|
|
24
|
-
activate small_fish
|
|
27
|
+
conda activate small_fish
|
|
25
28
|
```
|
|
26
29
|
Then download the small_fish package :
|
|
27
30
|
```bash
|
|
@@ -43,6 +46,50 @@ Then launch Small fish :
|
|
|
43
46
|
```bash
|
|
44
47
|
python -m small_fish_gui
|
|
45
48
|
```
|
|
49
|
+
|
|
50
|
+
## Cellpose configuration
|
|
51
|
+
|
|
52
|
+
For the following steps first activate your small fish environnement :
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
conda activate small_fish
|
|
56
|
+
```
|
|
57
|
+
### Setting up your GPU for cellpose (Windows / Linux)
|
|
58
|
+
This instructions describe how I installed CUDA and GPU cellpose on the machines I tested, unfortunatly, drivers installations don't always run smoothly, if you run into any difficulties please have a look at the *GPU version (CUDA) on Windows or Linux* section of the [cellpose documentation](https://github.com/MouseLand/cellpose) for assistance.
|
|
59
|
+
|
|
60
|
+
First step is to check that your GPU is CUDA compatible which it should be if from the brand NVIIDA.
|
|
61
|
+
Then you need to install CUDA from the [NVIDIA archives](https://developer.nvidia.com/cuda-toolkit-archive), any 11.x version should work but I recommend the 11.8 version.
|
|
62
|
+
|
|
63
|
+
Finally we need to make some modifcation to your small fish environnement :
|
|
64
|
+
|
|
65
|
+
Remove the CPU version of torch
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip uninstall torch
|
|
69
|
+
```
|
|
70
|
+
Then install pytorch and cudatoolkit :
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
conda install pytorch==1.12.0 cudatoolkit=11.3 -c pytorch
|
|
74
|
+
```
|
|
75
|
+
If the installation succeeded next time your run segmentation with small fish you should see the "GPU is ON" notice upon entering the segmentation parameters.
|
|
76
|
+
If you run into any problems I would recommend following the official cellpose instructions as mentionned above.
|
|
77
|
+
|
|
78
|
+
|
|
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
|
|
81
|
+
|
|
82
|
+
To install the GUI run :
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pip install cellpose[gui]
|
|
86
|
+
```
|
|
87
|
+
Then to run cellpose
|
|
88
|
+
```bash
|
|
89
|
+
cellpose
|
|
90
|
+
```
|
|
91
|
+
Note that for training it is recommended to first set up your GPU as training computation can be quite long otherwise. To get started with how to train your models you can watch the [video](https://www.youtube.com/watch?v=5qANHWoubZU) from cellpose authors.
|
|
92
|
+
|
|
46
93
|
## Developpement
|
|
47
94
|
|
|
48
95
|
Optional features to include in future versions :
|
|
Binary file
|
small_fish_gui/__init__.py
CHANGED
small_fish_gui/__main__.py
CHANGED
|
@@ -1,12 +1,26 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
import os
|
|
1
|
+
import sys, subprocess
|
|
3
2
|
import PySimpleGUI as sg
|
|
4
3
|
|
|
5
4
|
def main():
|
|
6
5
|
import small_fish_gui.pipeline.main
|
|
7
6
|
|
|
7
|
+
def is_last_version() :
|
|
8
|
+
latest_version = str(subprocess.run([sys.executable, '-m', 'pip', 'install', '{}==random'.format('small_fish_gui')], capture_output=True, text=True))
|
|
9
|
+
latest_version = latest_version[latest_version.find('(from versions:')+15:]
|
|
10
|
+
latest_version = latest_version[:latest_version.find(')')]
|
|
11
|
+
latest_version = latest_version.replace(' ','').split(',')[-1]
|
|
12
|
+
|
|
13
|
+
current_version = str(subprocess.run([sys.executable, '-m', 'pip', 'show', '{}'.format('small_fish_gui')], capture_output=True, text=True))
|
|
14
|
+
current_version = current_version[current_version.find('Version:')+8:]
|
|
15
|
+
current_version = current_version[:current_version.find('\\n')].replace(' ','')
|
|
16
|
+
|
|
17
|
+
return current_version == latest_version
|
|
8
18
|
|
|
9
19
|
if __name__ == "__main__":
|
|
20
|
+
|
|
21
|
+
if not is_last_version() :
|
|
22
|
+
print("A new version of Small Fish is available. To update close small fish and type :\npip install --upgrade small_fish_gui")
|
|
23
|
+
|
|
10
24
|
try :
|
|
11
25
|
sys.exit(main())
|
|
12
26
|
except Exception as error :
|
small_fish_gui/gui/layout.py
CHANGED
|
@@ -151,7 +151,7 @@ def radio_layout(values, header=None) :
|
|
|
151
151
|
layout = add_header(header, layout=layout)
|
|
152
152
|
return layout
|
|
153
153
|
|
|
154
|
-
def _segmentation_layout(cytoplasm_model_preset= 'cyto2', nucleus_model_preset= 'nuclei', cytoplasm_channel_preset=0, nucleus_channel_preset=0, cyto_diameter_preset=30, nucleus_diameter_preset= 30, show_segmentation_preset= False, segment_only_nuclei_preset=False, saving_path_preset=os.getcwd(), filename_preset='cell_segmentation.png') :
|
|
154
|
+
def _segmentation_layout(multichannel, cytoplasm_model_preset= 'cyto2', nucleus_model_preset= 'nuclei', cytoplasm_channel_preset=0, nucleus_channel_preset=0, cyto_diameter_preset=30, nucleus_diameter_preset= 30, show_segmentation_preset= False, segment_only_nuclei_preset=False, saving_path_preset=os.getcwd(), filename_preset='cell_segmentation.png',) :
|
|
155
155
|
|
|
156
156
|
USE_GPU = use_gpu()
|
|
157
157
|
|
|
@@ -165,14 +165,14 @@ def _segmentation_layout(cytoplasm_model_preset= 'cyto2', nucleus_model_preset=
|
|
|
165
165
|
layout += [add_header("Cell Segmentation", [sg.Text("Choose cellpose model for cytoplasm: \n")]),
|
|
166
166
|
[combo_layout(models_list, key='cyto_model_name', default_value= cytoplasm_model_preset)]
|
|
167
167
|
]
|
|
168
|
-
layout += [parameters_layout(['cytoplasm channel'],default_values= [cytoplasm_channel_preset])]
|
|
168
|
+
if multichannel : layout += [parameters_layout(['cytoplasm channel'],default_values= [cytoplasm_channel_preset])]
|
|
169
169
|
layout += [parameters_layout(['cytoplasm diameter'], unit= "px", default_values= [cyto_diameter_preset])]
|
|
170
170
|
#Nucleus parameters
|
|
171
171
|
layout += [
|
|
172
172
|
add_header("Nucleus segmentation",[sg.Text("Choose cellpose model for nucleus: \n")]),
|
|
173
173
|
combo_layout(models_list, key='nucleus_model_name', default_value= nucleus_model_preset)
|
|
174
174
|
]
|
|
175
|
-
layout += [parameters_layout(['nucleus channel'], default_values= [nucleus_channel_preset])]
|
|
175
|
+
if multichannel : layout += [parameters_layout(['nucleus channel'], default_values= [nucleus_channel_preset])]
|
|
176
176
|
layout += [parameters_layout([ 'nucleus diameter'],unit= "px", default_values= [nucleus_diameter_preset])]
|
|
177
177
|
layout += [bool_layout(["Segment only nuclei"], preset=segment_only_nuclei_preset)]
|
|
178
178
|
|
small_fish_gui/gui/prompts.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import PySimpleGUI as sg
|
|
2
2
|
import pandas as pd
|
|
3
3
|
import os
|
|
4
|
-
|
|
4
|
+
import numpy as np
|
|
5
|
+
from .layout import path_layout, parameters_layout, bool_layout, tuple_layout, combo_layout, add_header, path_layout
|
|
5
6
|
from ..interface import open_image, check_format, FormatError
|
|
6
7
|
from .help_module import ask_help
|
|
7
8
|
|
|
@@ -112,7 +113,7 @@ def output_image_prompt(filename) :
|
|
|
112
113
|
relaunch = False
|
|
113
114
|
layout = path_layout(['folder'], look_for_dir= True, header= "Output parameters :")
|
|
114
115
|
layout += parameters_layout(["filename"], default_values= [filename + "_quantification"], size=25)
|
|
115
|
-
layout += bool_layout(['Excel', 'Feather'])
|
|
116
|
+
layout += bool_layout(['csv','Excel', 'Feather'])
|
|
116
117
|
layout.append([sg.Button('Cancel')])
|
|
117
118
|
|
|
118
119
|
event,values= prompt(layout)
|
|
@@ -203,6 +204,23 @@ def detection_parameters_promt(is_3D_stack, is_multichannel, do_dense_region_dec
|
|
|
203
204
|
default_segmentation = [default_dict.setdefault('nucleus channel signal', default_dict.setdefault('nucleus channel',0))]
|
|
204
205
|
layout += parameters_layout(['nucleus channel signal'], default_values=default_segmentation) + [[sg.Text(" channel from which signal will be measured for nucleus features.")]]
|
|
205
206
|
|
|
207
|
+
layout += bool_layout(['Interactive threshold selector'], preset=[False])
|
|
208
|
+
layout += path_layout(
|
|
209
|
+
keys=['spots_extraction_folder'],
|
|
210
|
+
look_for_dir=True,
|
|
211
|
+
header= "Individual spot extraction",
|
|
212
|
+
preset= default_dict.setdefault('spots_extraction_folder', '')
|
|
213
|
+
)
|
|
214
|
+
layout += parameters_layout(
|
|
215
|
+
parameters=['spots_filename'],
|
|
216
|
+
default_values=[default_dict.setdefault('spots_filename','spots_extraction')],
|
|
217
|
+
size= 13
|
|
218
|
+
)
|
|
219
|
+
layout += bool_layout(
|
|
220
|
+
parameters= ['do_spots_csv', 'do_spots_excel', 'do_spots_feather'],
|
|
221
|
+
preset= [default_dict.setdefault('do_spots_csv',False), default_dict.setdefault('do_spots_excel',False),default_dict.setdefault('do_spots_feather',False)]
|
|
222
|
+
)
|
|
223
|
+
|
|
206
224
|
event, values = prompt_with_help(layout, help='detection')
|
|
207
225
|
if event == 'Cancel' : return None
|
|
208
226
|
if is_3D_stack : values['dim'] = 3
|
|
@@ -266,6 +284,7 @@ def _warning_popup(warning:str) :
|
|
|
266
284
|
def _sumup_df(results: pd.DataFrame) :
|
|
267
285
|
|
|
268
286
|
if len(results) > 0 :
|
|
287
|
+
if 'channel to compute' not in results : results['channel to compute'] = np.NaN
|
|
269
288
|
res = results.loc[:,['acquisition_id', 'spot_number', 'cell_number', 'filename', 'channel to compute']]
|
|
270
289
|
else :
|
|
271
290
|
res = pd.DataFrame(columns= ['acquisition_id', 'spot_number', 'cell_number', 'filename', 'channel to compute'])
|
|
@@ -284,9 +303,9 @@ def hub_prompt(fov_results, do_segmentation=False) :
|
|
|
284
303
|
layout = [
|
|
285
304
|
[sg.Text('RESULTS', font= 'bold 13')],
|
|
286
305
|
[sg.Table(values= list(sumup_df.values), headings= list(sumup_df.columns), row_height=20, num_rows= 5, vertical_scroll_only=False, key= "result_table"), segmentation_object],
|
|
287
|
-
[sg.Button('Add detection'), sg.Button('Compute colocalisation')
|
|
288
|
-
|
|
289
|
-
[sg.Button('Save results', button_color= 'green'), sg.Button('Reset results',button_color= 'gray')]
|
|
306
|
+
[sg.Button('Add detection'), sg.Button('Compute colocalisation')],#, sg.Button('Batch detection')],
|
|
307
|
+
[sg.Button('Save results', button_color= 'green'), sg.Button('Delete acquisitions',button_color= 'gray'), sg.Button('Reset segmentation',button_color= 'gray'), sg.Button('Reset results',button_color= 'gray')]
|
|
308
|
+
# [sg.Button('Save results', button_color= 'green'), sg.Button('Reset results',button_color= 'gray')]
|
|
290
309
|
]
|
|
291
310
|
|
|
292
311
|
window = sg.Window('small fish', layout= layout, margins= (10,10))
|
|
@@ -2,7 +2,7 @@ import os
|
|
|
2
2
|
import pandas as pd
|
|
3
3
|
from bigfish.stack import check_parameter
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
MAX_LEN_EXCEL = 1048576
|
|
6
6
|
|
|
7
7
|
def _cast_spot_to_tuple(spot) :
|
|
8
8
|
return tuple([coord for coord in spot])
|
|
@@ -10,11 +10,11 @@ def _cast_spot_to_tuple(spot) :
|
|
|
10
10
|
def _cast_spots_to_tuple(spots) :
|
|
11
11
|
return tuple(list(map(_cast_spot_to_tuple, spots)))
|
|
12
12
|
|
|
13
|
-
def write_results(dataframe: pd.DataFrame, path:str, filename:str, do_excel= True, do_feather= False) :
|
|
13
|
+
def write_results(dataframe: pd.DataFrame, path:str, filename:str, do_excel= True, do_feather= False, do_csv=False) :
|
|
14
14
|
check_parameter(dataframe= pd.DataFrame, path= str, filename = str, do_excel = bool, do_feather = bool)
|
|
15
15
|
|
|
16
16
|
if len(dataframe) == 0 : return True
|
|
17
|
-
if not do_excel and not do_feather :
|
|
17
|
+
if not do_excel and not do_feather and not do_csv :
|
|
18
18
|
return False
|
|
19
19
|
|
|
20
20
|
if not path.endswith('/') : path +='/'
|
|
@@ -23,7 +23,7 @@ def write_results(dataframe: pd.DataFrame, path:str, filename:str, do_excel= Tru
|
|
|
23
23
|
|
|
24
24
|
new_filename = filename
|
|
25
25
|
i= 1
|
|
26
|
-
while new_filename + '.xlsx' in os.listdir(path) or new_filename + '.feather' in os.listdir(path) :
|
|
26
|
+
while new_filename + '.xlsx' in os.listdir(path) or new_filename + '.feather' in os.listdir(path) or new_filename + '.csv' in os.listdir(path) :
|
|
27
27
|
new_filename = filename + '_{0}'.format(i)
|
|
28
28
|
i+=1
|
|
29
29
|
|
|
@@ -36,7 +36,14 @@ def write_results(dataframe: pd.DataFrame, path:str, filename:str, do_excel= Tru
|
|
|
36
36
|
if 'clusters' in dataframe.columns :
|
|
37
37
|
dataframe = dataframe.drop(['clusters'], axis= 1)
|
|
38
38
|
|
|
39
|
-
if
|
|
40
|
-
if
|
|
39
|
+
if do_feather : dataframe.reset_index(drop=True).to_feather(path + new_filename + '.feather')
|
|
40
|
+
if do_csv : dataframe.reset_index(drop=True).to_csv(path + new_filename + '.csv', sep=";")
|
|
41
|
+
if do_excel :
|
|
42
|
+
if len(dataframe) < MAX_LEN_EXCEL :
|
|
43
|
+
dataframe.reset_index(drop=True).to_excel(path + new_filename + '.xlsx')
|
|
44
|
+
else :
|
|
45
|
+
print("Error : Table too big to be saved in excel format.")
|
|
46
|
+
return False
|
|
47
|
+
|
|
41
48
|
|
|
42
49
|
return True
|
|
Binary file
|
|
@@ -204,13 +204,9 @@ def launch_colocalisation(result_tables, result_dataframe, colocalisation_distan
|
|
|
204
204
|
voxel_size = voxel_size1
|
|
205
205
|
|
|
206
206
|
if shape1 != shape2 :
|
|
207
|
-
print(shape1)
|
|
208
|
-
print(shape2)
|
|
209
207
|
raise MissMatchError("shape 1 different than shape 2")
|
|
210
208
|
else :
|
|
211
209
|
shape = shape1
|
|
212
|
-
print(shape1)
|
|
213
|
-
print(shape2)
|
|
214
210
|
|
|
215
211
|
acquisition_couple = (acquisition1.at['acquisition_id'], acquisition2.at['acquisition_id'])
|
|
216
212
|
|
|
@@ -235,6 +231,9 @@ def launch_colocalisation(result_tables, result_dataframe, colocalisation_distan
|
|
|
235
231
|
except MissMatchError as e :
|
|
236
232
|
sg.popup(str(e))
|
|
237
233
|
fraction_spots2_coloc_cluster1 = np.NaN
|
|
234
|
+
except TypeError : # Clusters not computed
|
|
235
|
+
fraction_spots2_coloc_cluster1 = np.NaN
|
|
236
|
+
|
|
238
237
|
|
|
239
238
|
else : fraction_spots2_coloc_cluster1 = np.NaN
|
|
240
239
|
|
|
@@ -242,9 +241,12 @@ def launch_colocalisation(result_tables, result_dataframe, colocalisation_distan
|
|
|
242
241
|
try :
|
|
243
242
|
clusters2 = acquisition2['clusters'][:,:len(voxel_size)]
|
|
244
243
|
fraction_spots1_coloc_cluster2 = spots_colocalisation(image_shape=shape, spot_list1=spots1, spot_list2=clusters2, distance= colocalisation_distance, voxel_size=voxel_size) / spot1_total
|
|
245
|
-
except MissMatchError as e
|
|
244
|
+
except MissMatchError as e :# Clusters not computed
|
|
246
245
|
sg.popup(str(e))
|
|
247
246
|
fraction_spots1_coloc_cluster2 = np.NaN
|
|
247
|
+
except TypeError :
|
|
248
|
+
fraction_spots1_coloc_cluster2 = np.NaN
|
|
249
|
+
|
|
248
250
|
|
|
249
251
|
else : fraction_spots1_coloc_cluster2 = np.NaN
|
|
250
252
|
|
|
@@ -261,6 +263,4 @@ def launch_colocalisation(result_tables, result_dataframe, colocalisation_distan
|
|
|
261
263
|
'fraction_spots1_coloc_cluster2' : [fraction_spots1_coloc_cluster2],
|
|
262
264
|
})
|
|
263
265
|
|
|
264
|
-
print(coloc_df.loc[:,['fraction_spots1_coloc_spots2','fraction_spots2_coloc_spots1', 'fraction_spots2_coloc_cluster1', 'fraction_spots1_coloc_cluster2']])
|
|
265
|
-
|
|
266
266
|
return coloc_df
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Contains Napari wrappers to visualise and correct spots/clusters.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
|
|
6
5
|
import numpy as np
|
|
7
6
|
import scipy.ndimage as ndi
|
|
8
7
|
import napari
|
|
@@ -96,15 +95,15 @@ def correct_spots(image, spots, voxel_size= (1,1,1), clusters= None, cluster_siz
|
|
|
96
95
|
scale = compute_anisotropy_coef(voxel_size)
|
|
97
96
|
try :
|
|
98
97
|
Viewer = napari.Viewer(ndisplay=2, title= 'Spot correction', axis_labels=['z','y','x'], show= False)
|
|
99
|
-
Viewer.add_image(image, scale=scale, name= "rna signal", blending= 'additive', colormap='red')
|
|
98
|
+
Viewer.add_image(image, scale=scale, name= "rna signal", blending= 'additive', colormap='red', contrast_limits=[image.min(), image.max()])
|
|
100
99
|
other_colors = ['green', 'blue', 'gray', 'cyan', 'bop orange', 'bop purple'] * ((len(other_images)-1 // 7) + 1)
|
|
101
100
|
for im, color in zip(other_images, other_colors) :
|
|
102
|
-
Viewer.add_image(im, scale=scale, blending='additive', visible=False, colormap=color)
|
|
101
|
+
Viewer.add_image(im, scale=scale, blending='additive', visible=False, colormap=color, contrast_limits=[im.min(), im.max()])
|
|
103
102
|
layer_offset = len(other_images)
|
|
104
103
|
|
|
105
104
|
Viewer.add_points(spots, size = 5, scale=scale, face_color= 'green', opacity= 1, symbol= 'ring', name= 'single spots') # spots
|
|
106
105
|
if type(clusters) != type(None) : Viewer.add_points(clusters[:,:dim], size = 10, scale=scale, face_color= 'blue', opacity= 0.7, symbol= 'diamond', name= 'foci', features= {"spot_number" : clusters[:,dim], "id" : clusters[:,dim+1]}, feature_defaults= {"spot_number" : 0, "id" : -1}) # cluster
|
|
107
|
-
if type(cell_label) != type(None) and np.array_equal(nucleus_label, cell_label) : Viewer.add_labels(cell_label, scale=scale, opacity= 0.2, blending= 'additive')
|
|
106
|
+
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')
|
|
108
107
|
if type(nucleus_label) != type(None) : Viewer.add_labels(nucleus_label, scale=scale, opacity= 0.2, blending= 'additive')
|
|
109
108
|
|
|
110
109
|
#prepare cluster update
|
|
@@ -136,4 +135,94 @@ def correct_spots(image, spots, voxel_size= (1,1,1), clusters= None, cluster_siz
|
|
|
136
135
|
|
|
137
136
|
return new_spots, new_clusters
|
|
138
137
|
|
|
138
|
+
def show_segmentation(
|
|
139
|
+
nuc_image : np.ndarray,
|
|
140
|
+
nuc_label : np.ndarray,
|
|
141
|
+
cyto_image : np.ndarray = None,
|
|
142
|
+
cyto_label : np.ndarray = None,
|
|
143
|
+
) :
|
|
144
|
+
dim = nuc_image.ndim
|
|
145
|
+
|
|
146
|
+
if type(cyto_image) != type(None) :
|
|
147
|
+
if cyto_image.ndim != nuc_image.ndim : raise ValueError("Cyto and Nuc dimensions missmatch.")
|
|
148
|
+
if type(cyto_label) == type(None) : raise ValueError("If cyto image is passed cyto label must be passed too.")
|
|
149
|
+
|
|
150
|
+
if dim == 3 and nuc_label.ndim == 2 :
|
|
151
|
+
nuc_label = np.repeat(
|
|
152
|
+
nuc_label[np.newaxis],
|
|
153
|
+
repeats= len(nuc_image),
|
|
154
|
+
axis=0
|
|
155
|
+
)
|
|
156
|
+
if type(cyto_label) != type(None) :
|
|
157
|
+
|
|
158
|
+
if type(cyto_image) == type(None) : raise ValueError("If cyto label is passed cyto image must be passed too.")
|
|
159
|
+
|
|
160
|
+
if dim == 3 and cyto_label.ndim == 2 :
|
|
161
|
+
cyto_label = np.repeat(
|
|
162
|
+
cyto_label[np.newaxis],
|
|
163
|
+
repeats= len(nuc_image),
|
|
164
|
+
axis=0
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
#Init Napari viewer
|
|
168
|
+
Viewer = napari.Viewer(ndisplay=2, title= 'Show segmentation', axis_labels=['z','y','x'] if dim == 3 else ['y', 'x'], show= False)
|
|
169
|
+
|
|
170
|
+
# 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')
|
|
173
|
+
|
|
174
|
+
#Adding labels
|
|
175
|
+
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) : Viewer.add_labels(cyto_label, opacity= 0.4, blending= 'additive')
|
|
177
|
+
|
|
178
|
+
#Launch Napari
|
|
179
|
+
Viewer.show(block=False)
|
|
180
|
+
napari.run()
|
|
181
|
+
|
|
182
|
+
new_nuc_label = Viewer.layers[1].data
|
|
183
|
+
if type(cyto_label) != type(None) : new_cyto_label = Viewer.layers[3].data
|
|
184
|
+
|
|
185
|
+
return new_nuc_label, new_cyto_label
|
|
186
|
+
|
|
139
187
|
|
|
188
|
+
|
|
189
|
+
def threshold_selection(
|
|
190
|
+
image : np.ndarray,
|
|
191
|
+
filtered_image : np.ndarray,
|
|
192
|
+
threshold_slider,
|
|
193
|
+
voxel_size : tuple,
|
|
194
|
+
) :
|
|
195
|
+
|
|
196
|
+
"""
|
|
197
|
+
To view code for spot selection please have a look at magicgui instance created with `detection._create_threshold_slider` which is then passed to this napari wrapper as 'threshold_slider' argument.
|
|
198
|
+
"""
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
Viewer = napari.Viewer(title= "Small fish - Threshold selector", ndisplay=2, show=True)
|
|
202
|
+
Viewer.add_image(
|
|
203
|
+
data= image,
|
|
204
|
+
contrast_limits= [image.min(), image.max()],
|
|
205
|
+
name= "raw signal",
|
|
206
|
+
colormap= 'green',
|
|
207
|
+
scale= voxel_size,
|
|
208
|
+
blending= 'additive'
|
|
209
|
+
)
|
|
210
|
+
Viewer.add_image(
|
|
211
|
+
data= filtered_image,
|
|
212
|
+
contrast_limits= [filtered_image.min(), filtered_image.max()],
|
|
213
|
+
colormap= 'gray',
|
|
214
|
+
scale=voxel_size,
|
|
215
|
+
blending='additive'
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
Viewer.window.add_dock_widget(threshold_slider, name='threshold_selector')
|
|
219
|
+
threshold_slider() #First occurence with auto or entered threshold.
|
|
220
|
+
napari.run()
|
|
221
|
+
|
|
222
|
+
spots = Viewer.layers[-1].data.astype(int)
|
|
223
|
+
if len(spots) == 0 :
|
|
224
|
+
threshold = filtered_image.max()
|
|
225
|
+
else :
|
|
226
|
+
threshold = Viewer.layers[-1].properties.get('threshold')[0]
|
|
227
|
+
|
|
228
|
+
return spots, threshold
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import numpy as np
|
|
2
|
-
import
|
|
2
|
+
import os
|
|
3
3
|
import PySimpleGUI as sg
|
|
4
4
|
from ..gui import _error_popup, _warning_popup, parameters_layout, add_header, prompt, prompt_with_help
|
|
5
5
|
|
|
@@ -253,6 +253,11 @@ def check_integrity(values: dict, do_dense_region_deconvolution, multichannel,se
|
|
|
253
253
|
raise ParameterInputError("Channel to compute is out of range for image.\nPlease select from {0}".format(list(range(ch_len))))
|
|
254
254
|
values['channel to compute'] = ch
|
|
255
255
|
|
|
256
|
+
#Spot extraction
|
|
257
|
+
if not os.path.isdir(values['spots_extraction_folder']) and values['spots_extraction_folder'] != '':
|
|
258
|
+
raise ParameterInputError("Incorrect spot extraction folder.")
|
|
259
|
+
|
|
260
|
+
|
|
256
261
|
return values
|
|
257
262
|
|
|
258
263
|
|
|
@@ -269,4 +274,16 @@ def reorder_shape(shape, map) :
|
|
|
269
274
|
np.array(shape)[source]
|
|
270
275
|
)
|
|
271
276
|
|
|
272
|
-
return new_shape
|
|
277
|
+
return new_shape
|
|
278
|
+
|
|
279
|
+
def clean_unused_parameters_cache(user_parameters: dict) :
|
|
280
|
+
"""
|
|
281
|
+
Clean unused parameters that were set to None in previous run.
|
|
282
|
+
"""
|
|
283
|
+
parameters = ['alpha', 'beta', 'gamma', 'cluster size', 'min number of spots']
|
|
284
|
+
for parameter in parameters :
|
|
285
|
+
if parameter in user_parameters.keys() :
|
|
286
|
+
if type(user_parameters[parameter]) == type(None) :
|
|
287
|
+
del user_parameters[parameter]
|
|
288
|
+
|
|
289
|
+
return user_parameters
|
|
@@ -6,6 +6,7 @@ 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 ._napari_wrapper import show_segmentation as napari_show_segmentation
|
|
9
10
|
|
|
10
11
|
import cellpose.models as models
|
|
11
12
|
import numpy as np
|
|
@@ -31,7 +32,7 @@ def launch_segmentation(image: np.ndarray, user_parameters: dict) :
|
|
|
31
32
|
|
|
32
33
|
while True : # Loop if show_segmentation
|
|
33
34
|
#Default parameters
|
|
34
|
-
cyto_model_name = user_parameters.setdefault('cyto_model_name', '
|
|
35
|
+
cyto_model_name = user_parameters.setdefault('cyto_model_name', 'cyto3')
|
|
35
36
|
cyto_size = user_parameters.setdefault('cytoplasm diameter', 180)
|
|
36
37
|
cytoplasm_channel = user_parameters.setdefault('cytoplasm channel', 0)
|
|
37
38
|
nucleus_model_name = user_parameters.setdefault('nucleus_model_name', 'nuclei')
|
|
@@ -42,6 +43,7 @@ def launch_segmentation(image: np.ndarray, user_parameters: dict) :
|
|
|
42
43
|
segment_only_nuclei = user_parameters.setdefault('Segment only nuclei', False)
|
|
43
44
|
filename = user_parameters['filename']
|
|
44
45
|
available_channels = list(range(image.shape[0]))
|
|
46
|
+
multichannel = user_parameters.get('multichannel')
|
|
45
47
|
|
|
46
48
|
|
|
47
49
|
#Ask user for parameters
|
|
@@ -58,6 +60,7 @@ def launch_segmentation(image: np.ndarray, user_parameters: dict) :
|
|
|
58
60
|
show_segmentation_preset=show_segmentation,
|
|
59
61
|
segment_only_nuclei_preset=segment_only_nuclei,
|
|
60
62
|
filename_preset=filename,
|
|
63
|
+
multichannel=multichannel,
|
|
61
64
|
)
|
|
62
65
|
|
|
63
66
|
event, values = prompt_with_help(layout, help='segmentation')
|
|
@@ -150,19 +153,18 @@ def launch_segmentation(image: np.ndarray, user_parameters: dict) :
|
|
|
150
153
|
)
|
|
151
154
|
|
|
152
155
|
finally : window.close()
|
|
153
|
-
|
|
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)
|
|
156
|
+
|
|
165
157
|
if show_segmentation :
|
|
158
|
+
nucleus_label, cytoplasm_label = napari_show_segmentation(
|
|
159
|
+
nuc_image=image[nucleus_channel],
|
|
160
|
+
nuc_label= nucleus_label,
|
|
161
|
+
cyto_image=image[cytoplasm_channel],
|
|
162
|
+
cyto_label=cytoplasm_label,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
if nucleus_label.ndim == 3 : nucleus_label = np.max(nucleus_label, axis=0)
|
|
166
|
+
if cytoplasm_label.ndim == 3 : cytoplasm_label = np.max(cytoplasm_label, axis=0)
|
|
167
|
+
|
|
166
168
|
layout = [
|
|
167
169
|
[sg.Text("Proceed with current segmentation ?")],
|
|
168
170
|
[sg.Button("Yes"), sg.Button("No")]
|
|
@@ -172,6 +174,20 @@ def launch_segmentation(image: np.ndarray, user_parameters: dict) :
|
|
|
172
174
|
if event == "No" :
|
|
173
175
|
continue
|
|
174
176
|
|
|
177
|
+
if type(output_path) != type(None) :
|
|
178
|
+
nuc_proj = image[nucleus_channel]
|
|
179
|
+
im_proj = image[cytoplasm_channel]
|
|
180
|
+
if im_proj.ndim == 3 :
|
|
181
|
+
im_proj = stack.maximum_projection(im_proj)
|
|
182
|
+
if nuc_proj.ndim == 3 :
|
|
183
|
+
nuc_proj = stack.maximum_projection(nuc_proj)
|
|
184
|
+
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
|
+
if not do_only_nuc :
|
|
186
|
+
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
|
+
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
175
191
|
if cytoplasm_label.max() == 0 : #No cell segmented
|
|
176
192
|
layout = [
|
|
177
193
|
[sg.Text("No cell segmented. Proceed anyway ?")],
|
|
@@ -236,7 +252,10 @@ def _segmentate_object(im, model_name, object_size_px, channels = [0,0]) :
|
|
|
236
252
|
|
|
237
253
|
return label
|
|
238
254
|
|
|
239
|
-
def _cast_segmentation_parameters(values) :
|
|
255
|
+
def _cast_segmentation_parameters(values:dict) :
|
|
256
|
+
|
|
257
|
+
values.setdefault('cytoplasm channel',0)
|
|
258
|
+
values.setdefault('nucleus channel',0)
|
|
240
259
|
|
|
241
260
|
if values['cyto_model_name'] == '' :
|
|
242
261
|
values['cyto_model_name'] = None
|
|
@@ -4,13 +4,14 @@ from ._preprocess import map_channels, prepare_image_detection, reorder_shape, r
|
|
|
4
4
|
from .detection import ask_input_parameters, initiate_detection, launch_detection, launch_features_computation, get_nucleus_signal
|
|
5
5
|
from ._segmentation import launch_segmentation
|
|
6
6
|
from ._colocalisation import initiate_colocalisation, launch_colocalisation
|
|
7
|
+
from .spots import launch_spots_extraction
|
|
7
8
|
|
|
8
9
|
import pandas as pd
|
|
9
10
|
import PySimpleGUI as sg
|
|
10
11
|
|
|
11
12
|
def add_detection(user_parameters, segmentation_done, acquisition_id, cytoplasm_label, nucleus_label) :
|
|
12
13
|
"""
|
|
13
|
-
#TODO : list all keys added to user_parameters when returned
|
|
14
|
+
#TODO : list all keys added to user_parameters when returned.
|
|
14
15
|
"""
|
|
15
16
|
|
|
16
17
|
new_results_df = pd.DataFrame()
|
|
@@ -31,7 +32,8 @@ def add_detection(user_parameters, segmentation_done, acquisition_id, cytoplasm_
|
|
|
31
32
|
if user_parameters['Segmentation'] and not segmentation_done:
|
|
32
33
|
im_seg = reorder_image_stack(map, user_parameters)
|
|
33
34
|
cytoplasm_label, nucleus_label, user_parameters = launch_segmentation(im_seg, user_parameters=user_parameters)
|
|
34
|
-
|
|
35
|
+
elif segmentation_done :
|
|
36
|
+
pass
|
|
35
37
|
else :
|
|
36
38
|
cytoplasm_label, nucleus_label = None,None
|
|
37
39
|
|
|
@@ -83,7 +85,20 @@ def add_detection(user_parameters, segmentation_done, acquisition_id, cytoplasm_
|
|
|
83
85
|
if ask_detection_confirmation(user_parameters.get('threshold')) : break
|
|
84
86
|
else :
|
|
85
87
|
break
|
|
86
|
-
|
|
88
|
+
|
|
89
|
+
if user_parameters['spots_extraction_folder'] != '' and type(user_parameters['spots_extraction_folder']) != type(None) :
|
|
90
|
+
if user_parameters['spots_filename'] != '' and type(user_parameters['spots_filename']) != type(None) :
|
|
91
|
+
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
|
+
launch_spots_extraction(
|
|
94
|
+
acquisition_id=acquisition_id,
|
|
95
|
+
user_parameters=user_parameters,
|
|
96
|
+
image=image,
|
|
97
|
+
spots=spots,
|
|
98
|
+
nucleus_label= nucleus_label,
|
|
99
|
+
cell_label= cytoplasm_label,
|
|
100
|
+
)
|
|
101
|
+
|
|
87
102
|
#Features computation
|
|
88
103
|
new_results_df, new_cell_results_df = launch_features_computation(
|
|
89
104
|
acquisition_id=acquisition_id,
|
|
@@ -107,9 +122,10 @@ def save_results(result_df, cell_result_df, coloc_df) :
|
|
|
107
122
|
filename = dic['filename']
|
|
108
123
|
do_excel = dic['Excel']
|
|
109
124
|
do_feather = dic['Feather']
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
125
|
+
do_csv = dic['csv']
|
|
126
|
+
sucess1 = write_results(result_df, path= path, filename=filename, do_excel= do_excel, do_feather= do_feather, do_csv=do_csv)
|
|
127
|
+
sucess2 = write_results(cell_result_df, path= path, filename=filename + '_cell_result', do_excel= do_excel, do_feather= do_feather, do_csv=do_csv)
|
|
128
|
+
sucess3 = write_results(coloc_df, path= path, filename=filename + '_coloc_result', do_excel= do_excel, do_feather= do_feather, do_csv=do_csv)
|
|
113
129
|
if sucess1 and sucess2 and sucess3 : sg.popup("Sucessfully saved at {0}.".format(path))
|
|
114
130
|
|
|
115
131
|
else :
|
|
@@ -124,4 +140,35 @@ def compute_colocalisation(result_tables, result_dataframe) :
|
|
|
124
140
|
else :
|
|
125
141
|
res_coloc = launch_colocalisation(result_tables, result_dataframe=result_dataframe, colocalisation_distance=colocalisation_distance)
|
|
126
142
|
|
|
127
|
-
return res_coloc
|
|
143
|
+
return res_coloc
|
|
144
|
+
|
|
145
|
+
def delete_acquisitions(selected_acquisitions : pd.DataFrame,
|
|
146
|
+
result_df : pd.DataFrame,
|
|
147
|
+
cell_result_df : pd.DataFrame,
|
|
148
|
+
coloc_df : pd.DataFrame
|
|
149
|
+
) :
|
|
150
|
+
|
|
151
|
+
if len(result_df) == 0 :
|
|
152
|
+
sg.popup("No acquisition to delete.")
|
|
153
|
+
return result_df, cell_result_df, coloc_df
|
|
154
|
+
|
|
155
|
+
if len(selected_acquisitions) == 0 :
|
|
156
|
+
sg.popup("Please select the acquisitions you would like to delete.")
|
|
157
|
+
else :
|
|
158
|
+
acquisition_ids = list(result_df.iloc[list(selected_acquisitions)]['acquisition_id'])
|
|
159
|
+
result_drop_idx = result_df[result_df['acquisition_id'].isin(acquisition_ids)].index
|
|
160
|
+
print("{0} acquisitions deleted.".format(len(result_drop_idx)))
|
|
161
|
+
|
|
162
|
+
if len(cell_result_df) > 0 :
|
|
163
|
+
cell_result_df_drop_idx = cell_result_df[cell_result_df['acquisition_id'].isin(acquisition_ids)].index
|
|
164
|
+
print("{0} cells deleted.".format(len(cell_result_df_drop_idx)))
|
|
165
|
+
cell_result_df = cell_result_df.drop(cell_result_df_drop_idx, axis=0)
|
|
166
|
+
|
|
167
|
+
if len(coloc_df) > 0 :
|
|
168
|
+
coloc_df_drop_idx = coloc_df[(coloc_df["acquisition_id_1"].isin(acquisition_ids)) | (coloc_df['acquisition_id_2'].isin(acquisition_ids))].index
|
|
169
|
+
print("{0} coloc measurement deleted.".format(len(coloc_df_drop_idx)))
|
|
170
|
+
coloc_df = coloc_df.drop(coloc_df_drop_idx, axis=0)
|
|
171
|
+
|
|
172
|
+
result_df = result_df.drop(result_drop_idx, axis=0)
|
|
173
|
+
|
|
174
|
+
return result_df, cell_result_df, coloc_df
|
|
@@ -5,9 +5,13 @@ Contains code to handle detection as well as bigfish wrappers related to spot de
|
|
|
5
5
|
from ._preprocess import ParameterInputError
|
|
6
6
|
from ._preprocess import check_integrity, convert_parameters_types
|
|
7
7
|
from ._signaltonoise import compute_snr_spots
|
|
8
|
-
from .
|
|
8
|
+
from ._napari_wrapper import correct_spots, _update_clusters, threshold_selection
|
|
9
9
|
from ..gui import add_default_loading
|
|
10
10
|
from ..gui import detection_parameters_promt, input_image_prompt
|
|
11
|
+
from .spots import compute_Spots
|
|
12
|
+
from magicgui import magicgui
|
|
13
|
+
from napari.layers import Image, Points
|
|
14
|
+
from napari.types import LayerDataTuple
|
|
11
15
|
|
|
12
16
|
import numpy as np
|
|
13
17
|
import pandas as pd
|
|
@@ -20,6 +24,7 @@ import bigfish.multistack as multistack
|
|
|
20
24
|
import bigfish.classification as classification
|
|
21
25
|
from bigfish.detection.spot_detection import get_object_radius_pixel
|
|
22
26
|
from types import GeneratorType
|
|
27
|
+
from skimage.measure import regionprops
|
|
23
28
|
|
|
24
29
|
|
|
25
30
|
def ask_input_parameters(ask_for_segmentation=True) :
|
|
@@ -284,7 +289,7 @@ def initiate_detection(user_parameters, segmentation_done, map, shape) :
|
|
|
284
289
|
return user_parameters
|
|
285
290
|
|
|
286
291
|
@add_default_loading
|
|
287
|
-
def _launch_detection(image, image_input_values: dict
|
|
292
|
+
def _launch_detection(image, image_input_values: dict) :
|
|
288
293
|
|
|
289
294
|
"""
|
|
290
295
|
Performs spots detection
|
|
@@ -297,25 +302,48 @@ def _launch_detection(image, image_input_values: dict, time_stack_gen=None) :
|
|
|
297
302
|
spot_size = image_input_values.get('spot_size')
|
|
298
303
|
log_kernel_size = image_input_values.get('log_kernel_size')
|
|
299
304
|
minimum_distance = image_input_values.get('minimum_distance')
|
|
305
|
+
threshold_user_selection = image_input_values.get('Interactive threshold selector')
|
|
300
306
|
|
|
301
|
-
if type(threshold) == type(None) :
|
|
302
|
-
|
|
303
|
-
if type(time_stack_gen) != type(None) :
|
|
304
|
-
image_sample = time_stack_gen()
|
|
305
|
-
else :
|
|
306
|
-
image_sample = image
|
|
307
|
-
|
|
308
|
-
threshold = compute_auto_threshold(image_sample, voxel_size=voxel_size, spot_radius=spot_size) * threshold_penalty
|
|
307
|
+
if type(threshold) == type(None) :
|
|
308
|
+
threshold = compute_auto_threshold(image, voxel_size=voxel_size, spot_radius=spot_size, log_kernel_size=log_kernel_size, minimum_distance=minimum_distance) * threshold_penalty
|
|
309
309
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
310
|
+
filtered_image = _apply_log_filter(
|
|
311
|
+
image=image,
|
|
312
|
+
voxel_size=voxel_size,
|
|
313
|
+
spot_radius=spot_size,
|
|
314
|
+
log_kernel_size = log_kernel_size,
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
local_maxima = _local_maxima_mask(
|
|
318
|
+
image_filtered=filtered_image,
|
|
314
319
|
voxel_size=voxel_size,
|
|
315
|
-
spot_radius=
|
|
316
|
-
log_kernel_size=log_kernel_size,
|
|
320
|
+
spot_radius=spot_size,
|
|
317
321
|
minimum_distance=minimum_distance
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
if threshold_user_selection :
|
|
325
|
+
|
|
326
|
+
threshold_slider = _create_threshold_slider(
|
|
327
|
+
logfiltered_image=filtered_image,
|
|
328
|
+
local_maxima=local_maxima,
|
|
329
|
+
default=threshold,
|
|
330
|
+
min=filtered_image[local_maxima].min(),
|
|
331
|
+
max=filtered_image[local_maxima].max(),
|
|
332
|
+
voxel_size=voxel_size
|
|
318
333
|
)
|
|
334
|
+
|
|
335
|
+
spots, threshold = threshold_selection(
|
|
336
|
+
image=image,
|
|
337
|
+
filtered_image=filtered_image,
|
|
338
|
+
threshold_slider=threshold_slider,
|
|
339
|
+
voxel_size=voxel_size
|
|
340
|
+
)
|
|
341
|
+
else :
|
|
342
|
+
spots = detection.spots_thresholding(
|
|
343
|
+
image=filtered_image,
|
|
344
|
+
mask_local_max=local_maxima,
|
|
345
|
+
threshold=threshold
|
|
346
|
+
)[0]
|
|
319
347
|
|
|
320
348
|
return spots, threshold
|
|
321
349
|
|
|
@@ -357,15 +385,17 @@ def launch_post_detection(image, spots, image_input_values: dict,) :
|
|
|
357
385
|
#features
|
|
358
386
|
fov_res['spot_number'] = len(spots)
|
|
359
387
|
snr_res = compute_snr_spots(image, spots, voxel_size, spot_size)
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
Z,Y,X = list(zip(*spots))
|
|
363
|
-
spots_values = image[Z,Y,X]
|
|
388
|
+
if len(spots) == 0 :
|
|
389
|
+
fov_res['spotsSignal_median'], fov_res['spotsSignal_mean'], fov_res['spotsSignal_std'] = np.NaN, np.NaN, np.NaN
|
|
364
390
|
else :
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
391
|
+
if dim == 3 :
|
|
392
|
+
Z,Y,X = list(zip(*spots))
|
|
393
|
+
spots_values = image[Z,Y,X]
|
|
394
|
+
else :
|
|
395
|
+
Y,X = list(zip(*spots))
|
|
396
|
+
spots_values = image[Y,X]
|
|
397
|
+
fov_res['spotsSignal_median'], fov_res['spotsSignal_mean'], fov_res['spotsSignal_std'] = np.median(spots_values), np.mean(spots_values), np.std(spots_values)
|
|
398
|
+
|
|
369
399
|
fov_res['median_pixel'] = np.median(image)
|
|
370
400
|
fov_res['mean_pixel'] = np.mean(image)
|
|
371
401
|
|
|
@@ -447,6 +477,7 @@ def launch_cell_extraction(acquisition_id, spots, clusters, image, nucleus_signa
|
|
|
447
477
|
#Nucleus features : area is computed in bigfish
|
|
448
478
|
features_names += ['nucleus_mean_signal', 'nucleus_median_signal', 'nucleus_max_signal', 'nucleus_min_signal']
|
|
449
479
|
features_names += ['snr_mean', 'snr_median', 'snr_std']
|
|
480
|
+
features_names += ['cell_center_coord','foci_number','foci_in_nuc_number']
|
|
450
481
|
|
|
451
482
|
result_frame = pd.DataFrame()
|
|
452
483
|
|
|
@@ -483,6 +514,30 @@ def launch_cell_extraction(acquisition_id, spots, clusters, image, nucleus_signa
|
|
|
483
514
|
compute_topography=True
|
|
484
515
|
)
|
|
485
516
|
|
|
517
|
+
#center of cell coordinates
|
|
518
|
+
local_cell_center = regionprops(
|
|
519
|
+
label_image=cell_mask.astype(int)
|
|
520
|
+
)[0]['centroid']
|
|
521
|
+
cell_center = (local_cell_center[0] + min_y, local_cell_center[1] + min_x)
|
|
522
|
+
|
|
523
|
+
#foci in nucleus
|
|
524
|
+
if type(foci_coords) != type(None) :
|
|
525
|
+
if len(foci_coords) == 0 :
|
|
526
|
+
foci_number = 0
|
|
527
|
+
foci_in_nuc_number = 0
|
|
528
|
+
else :
|
|
529
|
+
foci_number = len(foci_coords)
|
|
530
|
+
foci_index = list(zip(*foci_coords))
|
|
531
|
+
if len(foci_index) == 5 :
|
|
532
|
+
foci_index = foci_index[1:3]
|
|
533
|
+
elif len(foci_index) == 4 :
|
|
534
|
+
foci_index = foci_index[:2]
|
|
535
|
+
else : raise AssertionError("Impossible number of dim for foci : ", len(foci_index))
|
|
536
|
+
foci_in_nuc_number = nuc_mask[tuple(foci_index)].astype(bool).sum()
|
|
537
|
+
else :
|
|
538
|
+
foci_number = np.NaN
|
|
539
|
+
foci_in_nuc_number = np.NaN
|
|
540
|
+
|
|
486
541
|
#Signal to noise
|
|
487
542
|
snr_dict = _compute_cell_snr(
|
|
488
543
|
image,
|
|
@@ -499,6 +554,7 @@ def launch_cell_extraction(acquisition_id, spots, clusters, image, nucleus_signa
|
|
|
499
554
|
features = list(features)
|
|
500
555
|
features += [np.mean(nuc_signal), np.median(nuc_signal), np.max(nuc_signal), np.min(nuc_signal)]
|
|
501
556
|
features += [snr_mean, snr_median, snr_std]
|
|
557
|
+
features += [cell_center, foci_number, foci_in_nuc_number]
|
|
502
558
|
|
|
503
559
|
features = [acquisition_id, cell_id, cell_bbox] + features
|
|
504
560
|
|
|
@@ -601,9 +657,9 @@ def launch_features_computation(acquisition_id, image, nucleus_signal, spots, cl
|
|
|
601
657
|
if user_parameters['Cluster computation'] :
|
|
602
658
|
frame_results['cluster_number'] = len(clusters)
|
|
603
659
|
if dim == 3 :
|
|
604
|
-
frame_results['total_spots_in_clusters'] = clusters.sum(axis=0)[3]
|
|
660
|
+
frame_results['total_spots_in_clusters'] = clusters.sum(axis=0)[3] if len(clusters) >0 else 0
|
|
605
661
|
else :
|
|
606
|
-
frame_results['total_spots_in_clusters'] = clusters.sum(axis=0)[2]
|
|
662
|
+
frame_results['total_spots_in_clusters'] = clusters.sum(axis=0)[2] if len(clusters) >0 else 0
|
|
607
663
|
|
|
608
664
|
if type(cell_label) != type(None) and type(nucleus_label) != type(None):
|
|
609
665
|
cell_result_dframe = launch_cell_extraction(
|
|
@@ -673,7 +729,7 @@ def get_nucleus_signal(image, other_images, user_parameters) :
|
|
|
673
729
|
return np.zeros(shape=image.shape)
|
|
674
730
|
|
|
675
731
|
if rna_signal_channel == nucleus_signal_channel :
|
|
676
|
-
nucleus_signal
|
|
732
|
+
nucleus_signal = image
|
|
677
733
|
|
|
678
734
|
elif nucleus_signal_channel > rna_signal_channel :
|
|
679
735
|
nucleus_signal_channel -=1
|
|
@@ -684,4 +740,83 @@ def get_nucleus_signal(image, other_images, user_parameters) :
|
|
|
684
740
|
|
|
685
741
|
return nucleus_signal
|
|
686
742
|
else :
|
|
687
|
-
return image
|
|
743
|
+
return image
|
|
744
|
+
|
|
745
|
+
def _create_threshold_slider(
|
|
746
|
+
logfiltered_image : np.ndarray,
|
|
747
|
+
local_maxima : np.ndarray,
|
|
748
|
+
default : int,
|
|
749
|
+
min : int,
|
|
750
|
+
max : int,
|
|
751
|
+
voxel_size
|
|
752
|
+
) :
|
|
753
|
+
|
|
754
|
+
if isinstance(default, float) : default = round(default)
|
|
755
|
+
|
|
756
|
+
@magicgui(
|
|
757
|
+
threshold={'widget_type' : 'Slider', 'value' : default, 'min' : min, 'max' : max},
|
|
758
|
+
auto_call=True
|
|
759
|
+
)
|
|
760
|
+
def threshold_slider(threshold: int) -> LayerDataTuple:
|
|
761
|
+
spots = detection.spots_thresholding(
|
|
762
|
+
image=logfiltered_image,
|
|
763
|
+
mask_local_max=local_maxima,
|
|
764
|
+
threshold=threshold
|
|
765
|
+
)[0]
|
|
766
|
+
layer_args = {
|
|
767
|
+
'size': 7,
|
|
768
|
+
'scale' : voxel_size,
|
|
769
|
+
'face_color' : 'transparent',
|
|
770
|
+
'edge_color' : 'blue',
|
|
771
|
+
'symbol' : 'ring',
|
|
772
|
+
'opacity' : 0.7,
|
|
773
|
+
'blending' : 'additive',
|
|
774
|
+
'name': 'single spots',
|
|
775
|
+
'features' : {'threshold' : threshold}
|
|
776
|
+
}
|
|
777
|
+
return (spots, layer_args , 'points')
|
|
778
|
+
return threshold_slider
|
|
779
|
+
|
|
780
|
+
def _apply_log_filter(
|
|
781
|
+
image: np.ndarray,
|
|
782
|
+
voxel_size : tuple,
|
|
783
|
+
spot_radius : tuple,
|
|
784
|
+
log_kernel_size,
|
|
785
|
+
|
|
786
|
+
) :
|
|
787
|
+
"""
|
|
788
|
+
Apply spot detection steps until local maxima step (just before final threshold).
|
|
789
|
+
Return filtered image.
|
|
790
|
+
"""
|
|
791
|
+
|
|
792
|
+
ndim = image.ndim
|
|
793
|
+
|
|
794
|
+
if type(log_kernel_size) == type(None) :
|
|
795
|
+
log_kernel_size = get_object_radius_pixel(
|
|
796
|
+
voxel_size_nm=voxel_size,
|
|
797
|
+
object_radius_nm=spot_radius,
|
|
798
|
+
ndim=ndim)
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
image_filtered = stack.log_filter(image, log_kernel_size)
|
|
802
|
+
|
|
803
|
+
return image_filtered
|
|
804
|
+
|
|
805
|
+
def _local_maxima_mask(
|
|
806
|
+
image_filtered: np.ndarray,
|
|
807
|
+
voxel_size : tuple,
|
|
808
|
+
spot_radius : tuple,
|
|
809
|
+
minimum_distance
|
|
810
|
+
|
|
811
|
+
) :
|
|
812
|
+
|
|
813
|
+
ndim = image_filtered.ndim
|
|
814
|
+
|
|
815
|
+
if type(minimum_distance) == type(None) :
|
|
816
|
+
minimum_distance = get_object_radius_pixel(
|
|
817
|
+
voxel_size_nm=voxel_size,
|
|
818
|
+
object_radius_nm=spot_radius,
|
|
819
|
+
ndim=ndim)
|
|
820
|
+
mask_local_max = detection.local_maximum_detection(image_filtered, minimum_distance)
|
|
821
|
+
|
|
822
|
+
return mask_local_max.astype(bool)
|
small_fish_gui/pipeline/main.py
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import pandas as pd
|
|
3
3
|
import PySimpleGUI as sg
|
|
4
4
|
from ..gui import hub_prompt
|
|
5
|
-
from .actions import add_detection, save_results, compute_colocalisation
|
|
5
|
+
from .actions import add_detection, save_results, compute_colocalisation, delete_acquisitions
|
|
6
|
+
from ._preprocess import clean_unused_parameters_cache
|
|
6
7
|
|
|
7
8
|
#'Global' parameters
|
|
8
9
|
user_parameters = dict() # Very important object containg all choice from user that will influence the behavior of the main loop.
|
|
@@ -15,10 +16,15 @@ cytoplasm_label = None
|
|
|
15
16
|
nucleus_label = None
|
|
16
17
|
|
|
17
18
|
while True : #Break this loop to close small_fish
|
|
19
|
+
result_df = result_df.reset_index(drop=True)
|
|
20
|
+
cell_result_df = cell_result_df.reset_index(drop=True)
|
|
21
|
+
coloc_df = coloc_df.reset_index(drop=True)
|
|
18
22
|
try :
|
|
19
23
|
event, values = hub_prompt(result_df, segmentation_done)
|
|
20
24
|
|
|
21
25
|
if event == 'Add detection' :
|
|
26
|
+
user_parameters = clean_unused_parameters_cache(user_parameters)
|
|
27
|
+
|
|
22
28
|
|
|
23
29
|
new_result_df, new_cell_result_df, acquisition_id, user_parameters, segmentation_done, cytoplasm_label, nucleus_label = add_detection(
|
|
24
30
|
user_parameters=user_parameters,
|
|
@@ -64,8 +70,8 @@ while True : #Break this loop to close small_fish
|
|
|
64
70
|
nucleus_label = None
|
|
65
71
|
|
|
66
72
|
elif event == "Delete acquisitions" :
|
|
67
|
-
|
|
68
|
-
|
|
73
|
+
selected_acquisitions = values.setdefault('result_table', []) #Contains the lines selected by the user on the sum-up array.
|
|
74
|
+
result_df, cell_result_df, coloc_df = delete_acquisitions(selected_acquisitions, result_df, cell_result_df, coloc_df)
|
|
69
75
|
|
|
70
76
|
elif event == "Batch detection" :
|
|
71
77
|
#TODO
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Sub-module to handle individual spot extraction.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import pandas as pd
|
|
8
|
+
from ..interface.output import write_results
|
|
9
|
+
|
|
10
|
+
def launch_spots_extraction(
|
|
11
|
+
acquisition_id,
|
|
12
|
+
user_parameters,
|
|
13
|
+
image,
|
|
14
|
+
spots,
|
|
15
|
+
nucleus_label,
|
|
16
|
+
cell_label,
|
|
17
|
+
) :
|
|
18
|
+
Spots = compute_Spots(
|
|
19
|
+
acquisition_id=acquisition_id,
|
|
20
|
+
image=image,
|
|
21
|
+
spots=spots,
|
|
22
|
+
nucleus_label=nucleus_label,
|
|
23
|
+
cell_label=cell_label,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
did_output = write_results(
|
|
27
|
+
Spots,
|
|
28
|
+
path= user_parameters['spots_extraction_folder'],
|
|
29
|
+
filename= user_parameters['spots_filename'],
|
|
30
|
+
do_excel=user_parameters['do_spots_excel'],
|
|
31
|
+
do_csv=user_parameters['do_spots_csv'],
|
|
32
|
+
do_feather=user_parameters['do_spots_feather'],
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
if did_output : print("Individual spots extracted at {0}".format(user_parameters['spots_extraction_folder']))
|
|
36
|
+
|
|
37
|
+
def compute_Spots(
|
|
38
|
+
acquisition_id : int,
|
|
39
|
+
image : np.ndarray,
|
|
40
|
+
spots : np.ndarray,
|
|
41
|
+
nucleus_label = None,
|
|
42
|
+
cell_label = None,
|
|
43
|
+
) :
|
|
44
|
+
|
|
45
|
+
index = list(zip(*spots))
|
|
46
|
+
index = tuple(index)
|
|
47
|
+
spot_intensities_list = list(image[index])
|
|
48
|
+
if type(nucleus_label) != type(None) :
|
|
49
|
+
in_nuc_list = list(nucleus_label.astype(bool)[index[-2:]]) #Only plane coordinates
|
|
50
|
+
else :
|
|
51
|
+
in_nuc_list = np.NaN
|
|
52
|
+
if type(cell_label) != type(None) :
|
|
53
|
+
cell_label_list = list(cell_label[index[-2:]]) #Only plane coordinates
|
|
54
|
+
else :
|
|
55
|
+
cell_label_list = np.NaN
|
|
56
|
+
id_list = np.arange(len(spots))
|
|
57
|
+
|
|
58
|
+
coord_list = list(zip(*index))
|
|
59
|
+
|
|
60
|
+
Spots = pd.DataFrame({
|
|
61
|
+
'acquisition_id' : [acquisition_id] * len(spots),
|
|
62
|
+
'spot_id' : id_list,
|
|
63
|
+
'intensity' : spot_intensities_list,
|
|
64
|
+
'cell_label' : cell_label_list,
|
|
65
|
+
'in_nucleus' : in_nuc_list,
|
|
66
|
+
'coordinates' : coord_list,
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
return Spots
|
|
70
|
+
|
|
71
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: small_fish_gui
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.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
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
small_fish_gui/LICENSE,sha256=-iFy8VGBYs5VsHglKpk4D-hxqQ2jMJaqmfq_ulIzDks,1303
|
|
2
|
+
small_fish_gui/README.md,sha256=2c_homYDJXX6VsBiEs5obhBh3HpcTSMdyjLo-35WzE4,4062
|
|
3
|
+
small_fish_gui/Segmentation example.jpg,sha256=opfiSbjmfF6z8kBs08sg_FNR2Om0AcMPU5sSwSLHdoQ,215038
|
|
4
|
+
small_fish_gui/__init__.py,sha256=1eF6detE4uCLLHVMeTw-aRG6fjoUMdhrvnf-b48bVSk,1941
|
|
5
|
+
small_fish_gui/__main__.py,sha256=EzSCoJ7jpSdK-QbzUwQLGZeQWjybNeq8VnCBucA8MZw,1372
|
|
6
|
+
small_fish_gui/napari_detection_example.png,sha256=l5EZlrbXemLiGqb5inSVsD6Kko1Opz528-go-fBfrw8,977350
|
|
7
|
+
small_fish_gui/requirements.txt,sha256=9OMfUAnLdHevq6w_fVoDmVmkSMJeFofkOK_86_fu9C0,321
|
|
8
|
+
small_fish_gui/utils.py,sha256=tSoMb8N69WdKTtMItPb1DYZiIAz1mjI26BCKJAi6vuc,1798
|
|
9
|
+
small_fish_gui/.github/workflows/python-publish.yml,sha256=5Ltnuhw9TevhzndlBmdUgYMnS73xEAxSyd1u8DHdn5s,1084
|
|
10
|
+
small_fish_gui/gui/__init__.py,sha256=178HC3t2z4EnP0iBnMcaP_pyh5xHwOkEE6p3WJwBQeU,911
|
|
11
|
+
small_fish_gui/gui/animation.py,sha256=6_Y15_NzJ_TYBYseu3sSKaVkYRp2UCsVClAWOk3dESY,714
|
|
12
|
+
small_fish_gui/gui/general_help_screenshot.png,sha256=X4E6Td5f04K-pBUPDaBJRAE3D5b8fuEdiAUKhkIDr-0,54210
|
|
13
|
+
small_fish_gui/gui/help_module.py,sha256=PmgkkDs7bZ2-po83A_PK9uldQcHjehYmqre21nYb6DQ,9600
|
|
14
|
+
small_fish_gui/gui/layout.py,sha256=_ErOS2IUejeUuPLkDmPB3FzLkoHOWR-Iaxz-aUeETks,7695
|
|
15
|
+
small_fish_gui/gui/mapping_help_screenshot.png,sha256=HcuRh5TYciUogUasza5vZ_QSshaiHsskQK23mh9vQS8,34735
|
|
16
|
+
small_fish_gui/gui/prompts.py,sha256=NAR7qjKwybiZZ2caO_lB8_CEttG8i4lHdt9lxjh6ESM,13160
|
|
17
|
+
small_fish_gui/gui/segmentation_help_screenshot.png,sha256=rbSgIydT0gZtfMh1qk4mdMbEIyCaakvHmxa2eOrLwO0,118944
|
|
18
|
+
small_fish_gui/gui/test.py,sha256=Pf-GW9AgW-0VL1mFbYtqRvPAaa8DgwCThv2dDUHCcmU,156
|
|
19
|
+
small_fish_gui/interface/__init__.py,sha256=PB86R4Y9kV80aGZ-vP0ZW2KeaCwGbBbCtFCmbN2yl28,275
|
|
20
|
+
small_fish_gui/interface/image.py,sha256=X1L7S5svxUwdoDcI3QM1PbN-c4Nz5w30hixq3IgqSn8,1130
|
|
21
|
+
small_fish_gui/interface/output.py,sha256=dyhpO1YrRCIbQYpqU_52E1DTNPf0wdktd--CB15iT3k,1712
|
|
22
|
+
small_fish_gui/interface/parameters.py,sha256=lUugD-4W2TZyJF3TH1q70TlktEYhhPtcPCrvxm5Dk50,36
|
|
23
|
+
small_fish_gui/interface/testing.py,sha256=MY5-GcPOUHagcrwR8A7QOjAmjZIDVC8Wz3NibLe3KQw,321
|
|
24
|
+
small_fish_gui/pipeline/_colocalisation.py,sha256=peBw2Qz5m6wSejDkDz240UgvWl8ohNelrnmEgznbEsw,9635
|
|
25
|
+
small_fish_gui/pipeline/_custom_errors.py,sha256=tQ-AUhgzIFpK30AZiQQrtHCHyGVRDdAoIjzL0Fk-1pA,43
|
|
26
|
+
small_fish_gui/pipeline/_napari_wrapper.py,sha256=WtqxxcM4l4NsEnqU-YDvm7-KJgXlsGur1HFUWUgvuao,9124
|
|
27
|
+
small_fish_gui/pipeline/_preprocess.py,sha256=szNoav19Xo3USmiUTjcFgkMn9QK53ZOydbLV5aMFLws,10676
|
|
28
|
+
small_fish_gui/pipeline/_segmentation.py,sha256=M2bQzgzw7Zt_DBeM3qvI0V4Pn0HFLwj0l8yV8M5aToo,12977
|
|
29
|
+
small_fish_gui/pipeline/_signaltonoise.py,sha256=7A9t7xu7zghI6cr201Ldm-LjJ5NOuP56VSeJ8KIzcUo,8497
|
|
30
|
+
small_fish_gui/pipeline/actions.py,sha256=EIGIOlwJ_DADX1NcLWwrTP_AidDX-4f4ggZV0gkIb58,7988
|
|
31
|
+
small_fish_gui/pipeline/detection.py,sha256=sZjcDeHujdmXHVifI_Ir0xudb30Y1cuJxI6YGtp4mRQ,31778
|
|
32
|
+
small_fish_gui/pipeline/main.py,sha256=AAW-zK3b7Ece9cdHn9y6QG8lTa1HXG-8JtnvJ3m0HwA,3149
|
|
33
|
+
small_fish_gui/pipeline/spots.py,sha256=yHvqf1eD25UltELpzcouYXhLkxiXI_mOL1ANSzXK5pw,1907
|
|
34
|
+
small_fish_gui/pipeline/test.py,sha256=w4ZMGDmUDXxVgWTlZ2TKw19W8q5gcE9gLMKe0SWnRrw,2827
|
|
35
|
+
small_fish_gui-1.3.0.dist-info/METADATA,sha256=i9buygANVdkEX6uNgJjUIiQU_0xxPTg3tsWFMfxZxw0,2567
|
|
36
|
+
small_fish_gui-1.3.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
37
|
+
small_fish_gui-1.3.0.dist-info/licenses/LICENSE,sha256=-iFy8VGBYs5VsHglKpk4D-hxqQ2jMJaqmfq_ulIzDks,1303
|
|
38
|
+
small_fish_gui-1.3.0.dist-info/RECORD,,
|
small_fish_gui/start.py
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
small_fish_gui/LICENSE,sha256=-iFy8VGBYs5VsHglKpk4D-hxqQ2jMJaqmfq_ulIzDks,1303
|
|
2
|
-
small_fish_gui/README.md,sha256=Q8_AtxcruV2TUA6ODjfccatoTAP8AZkmP7G1MWY8f5U,1612
|
|
3
|
-
small_fish_gui/__init__.py,sha256=aAh4brM-eTSnFOWpYSFgMIqJzbjJX45RHIWi7ppl_nA,1941
|
|
4
|
-
small_fish_gui/__main__.py,sha256=sQ_HejagRTOcVpMuwUnLSO4MTZwqZ8uEplLHgqVpa6o,464
|
|
5
|
-
small_fish_gui/requirements.txt,sha256=9OMfUAnLdHevq6w_fVoDmVmkSMJeFofkOK_86_fu9C0,321
|
|
6
|
-
small_fish_gui/start.py,sha256=HTbzsVcaMji1BZnWyjfn3bDGIQeXGG4zFzvCBepqFvA,108
|
|
7
|
-
small_fish_gui/utils.py,sha256=tSoMb8N69WdKTtMItPb1DYZiIAz1mjI26BCKJAi6vuc,1798
|
|
8
|
-
small_fish_gui/.github/workflows/python-publish.yml,sha256=5Ltnuhw9TevhzndlBmdUgYMnS73xEAxSyd1u8DHdn5s,1084
|
|
9
|
-
small_fish_gui/gui/__init__.py,sha256=178HC3t2z4EnP0iBnMcaP_pyh5xHwOkEE6p3WJwBQeU,911
|
|
10
|
-
small_fish_gui/gui/animation.py,sha256=6_Y15_NzJ_TYBYseu3sSKaVkYRp2UCsVClAWOk3dESY,714
|
|
11
|
-
small_fish_gui/gui/general_help_screenshot.png,sha256=X4E6Td5f04K-pBUPDaBJRAE3D5b8fuEdiAUKhkIDr-0,54210
|
|
12
|
-
small_fish_gui/gui/help_module.py,sha256=PmgkkDs7bZ2-po83A_PK9uldQcHjehYmqre21nYb6DQ,9600
|
|
13
|
-
small_fish_gui/gui/layout.py,sha256=E_Z87S1YUR1gx2447OM0156dKXbzMA_q9joCO4hsZd8,7644
|
|
14
|
-
small_fish_gui/gui/mapping_help_screenshot.png,sha256=HcuRh5TYciUogUasza5vZ_QSshaiHsskQK23mh9vQS8,34735
|
|
15
|
-
small_fish_gui/gui/prompts.py,sha256=mlw9NT5k3I8kTMB7w6W6QETbSIav_A7RhCmMVD7NFV0,12279
|
|
16
|
-
small_fish_gui/gui/segmentation_help_screenshot.png,sha256=rbSgIydT0gZtfMh1qk4mdMbEIyCaakvHmxa2eOrLwO0,118944
|
|
17
|
-
small_fish_gui/gui/test.py,sha256=Pf-GW9AgW-0VL1mFbYtqRvPAaa8DgwCThv2dDUHCcmU,156
|
|
18
|
-
small_fish_gui/interface/__init__.py,sha256=PB86R4Y9kV80aGZ-vP0ZW2KeaCwGbBbCtFCmbN2yl28,275
|
|
19
|
-
small_fish_gui/interface/image.py,sha256=X1L7S5svxUwdoDcI3QM1PbN-c4Nz5w30hixq3IgqSn8,1130
|
|
20
|
-
small_fish_gui/interface/output.py,sha256=wqXJHk-PzqZwYr8NHLg9jcEJlZQXZk8R76aeWcTxsEw,1337
|
|
21
|
-
small_fish_gui/interface/parameters.py,sha256=lUugD-4W2TZyJF3TH1q70TlktEYhhPtcPCrvxm5Dk50,36
|
|
22
|
-
small_fish_gui/interface/testing.py,sha256=MY5-GcPOUHagcrwR8A7QOjAmjZIDVC8Wz3NibLe3KQw,321
|
|
23
|
-
small_fish_gui/pipeline/_colocalisation.py,sha256=-zz_kvghpMSaBhQT0moHvwC6ee92S-oq-j9qZWqgZMY,9677
|
|
24
|
-
small_fish_gui/pipeline/_custom_errors.py,sha256=tQ-AUhgzIFpK30AZiQQrtHCHyGVRDdAoIjzL0Fk-1pA,43
|
|
25
|
-
small_fish_gui/pipeline/_detection_visualisation.py,sha256=CNxCQpiCzC9Uk-2RqSuTp55Glf1URCL_s8zidwljY9Y,5774
|
|
26
|
-
small_fish_gui/pipeline/_preprocess.py,sha256=AlB86KuCA0UKA0XbTgXTJbg92Az34hzba_hsVs-uZl0,10035
|
|
27
|
-
small_fish_gui/pipeline/_segmentation.py,sha256=IaeqsjwIweKH9LEm6qbDqssGW7R0MRZSh7PtF4etIEI,12772
|
|
28
|
-
small_fish_gui/pipeline/_signaltonoise.py,sha256=7A9t7xu7zghI6cr201Ldm-LjJ5NOuP56VSeJ8KIzcUo,8497
|
|
29
|
-
small_fish_gui/pipeline/actions.py,sha256=n6lr_LqV4PT5uw6KfovehUuUK-yTJ66G-IhY2uhHF_k,5472
|
|
30
|
-
small_fish_gui/pipeline/detection.py,sha256=e8EpXZD8zt8daA3dou4RvKNFZEYZS7bKGAOqfd4fJmw,27250
|
|
31
|
-
small_fish_gui/pipeline/main.py,sha256=4_Qk-NRhjOEsgN7T35NXOHj4OdDmZGS5kVeKde-yCiI,2593
|
|
32
|
-
small_fish_gui/pipeline/test.py,sha256=w4ZMGDmUDXxVgWTlZ2TKw19W8q5gcE9gLMKe0SWnRrw,2827
|
|
33
|
-
small_fish_gui-1.1.0.dist-info/METADATA,sha256=VuIyufjeCNpPSx9d4gmoxz7VEcRtgP11rbPOf9v_SUc,2567
|
|
34
|
-
small_fish_gui-1.1.0.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
|
|
35
|
-
small_fish_gui-1.1.0.dist-info/licenses/LICENSE,sha256=-iFy8VGBYs5VsHglKpk4D-hxqQ2jMJaqmfq_ulIzDks,1303
|
|
36
|
-
small_fish_gui-1.1.0.dist-info/RECORD,,
|
|
File without changes
|