celldetective 1.1.1.post3__tar.gz → 1.1.1.post4__tar.gz
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.
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/PKG-INFO +1 -1
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/__main__.py +17 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/classifier_widget.py +10 -3
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/control_panel.py +11 -4
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/layouts.py +9 -7
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/neighborhood_options.py +11 -5
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/signal_annotator.py +85 -25
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/tableUI.py +15 -6
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/io.py +69 -3
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/neighborhood.py +96 -26
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/preprocessing.py +81 -61
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/segmentation.py +67 -29
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/utils.py +51 -12
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective.egg-info/PKG-INFO +1 -1
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/setup.py +1 -1
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/tests/test_segmentation.py +1 -1
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/LICENSE +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/README.md +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/__init__.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/datasets/segmentation_annotations/blank +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/datasets/signal_annotations/blank +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/events.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/extra_properties.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/filters.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/__init__.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/about.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/analyze_block.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/btrack_options.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/configure_new_exp.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/gui_utils.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/json_readers.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/measurement_options.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/plot_measurements.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/plot_signals_ui.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/process_block.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/retrain_segmentation_model_options.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/retrain_signal_model_options.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/seg_model_loader.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/signal_annotator_options.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/styles.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/survival_ui.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/thresholds_gui.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/viewers.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/icons/logo-large.png +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/icons/logo.png +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/icons/signals_icon.png +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/icons/splash-test.png +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/icons/splash.png +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/icons/splash0.png +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/icons/survival2.png +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/icons/vignette_signals2.png +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/icons/vignette_signals2.svg +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/links/zenodo.json +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/measure.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/models/segmentation_effectors/blank +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/models/segmentation_effectors/primNK_cfse/config_input.json +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/models/segmentation_effectors/primNK_cfse/cp-cfse-transfer +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/models/segmentation_effectors/primNK_cfse/training_instructions.json +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/models/segmentation_generic/blank +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/models/segmentation_targets/blank +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/models/signal_detection/blank +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/models/tracking_configs/mcf7.json +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/models/tracking_configs/ricm.json +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/models/tracking_configs/ricm2.json +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/scripts/analyze_signals.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/scripts/measure_cells.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/scripts/segment_cells.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/scripts/segment_cells_thresholds.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/scripts/track_cells.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/scripts/train_segmentation_model.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/scripts/train_signal_model.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/signals.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/tracking.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective.egg-info/SOURCES.txt +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective.egg-info/dependency_links.txt +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective.egg-info/entry_points.txt +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective.egg-info/not-zip-safe +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective.egg-info/requires.txt +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective.egg-info/top_level.txt +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/setup.cfg +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/tests/__init__.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/tests/test_events.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/tests/test_filters.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/tests/test_io.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/tests/test_measure.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/tests/test_neighborhood.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/tests/test_preprocessing.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/tests/test_signals.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/tests/test_tracking.py +0 -0
- {celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/tests/test_utils.py +0 -0
|
@@ -108,6 +108,10 @@ class AppInitWindow(QMainWindow):
|
|
|
108
108
|
OptionsMenu.addAction(self.MemoryAndThreadsAction)
|
|
109
109
|
menuBar.addMenu(OptionsMenu)
|
|
110
110
|
|
|
111
|
+
PluginsMenu = QMenu("Plugins", self)
|
|
112
|
+
PluginsMenu.addAction(self.CorrectAnnotationAction)
|
|
113
|
+
menuBar.addMenu(PluginsMenu)
|
|
114
|
+
|
|
111
115
|
helpMenu = QMenu("Help", self)
|
|
112
116
|
helpMenu.clear()
|
|
113
117
|
helpMenu.addAction(self.DocumentationAction)
|
|
@@ -130,6 +134,8 @@ class AppInitWindow(QMainWindow):
|
|
|
130
134
|
|
|
131
135
|
self.MemoryAndThreadsAction = QAction('Memory & Threads...')
|
|
132
136
|
|
|
137
|
+
self.CorrectAnnotationAction = QAction('Correct a segmentation annotation...')
|
|
138
|
+
|
|
133
139
|
self.newExpAction = QAction('New', self)
|
|
134
140
|
self.newExpAction.setShortcut("Ctrl+N")
|
|
135
141
|
self.newExpAction.setShortcutVisibleInContextMenu(True)
|
|
@@ -156,6 +162,7 @@ class AppInitWindow(QMainWindow):
|
|
|
156
162
|
self.openModels.triggered.connect(self.open_models_folder)
|
|
157
163
|
self.AboutAction.triggered.connect(self.open_about_window)
|
|
158
164
|
self.MemoryAndThreadsAction.triggered.connect(self.set_memory_and_threads)
|
|
165
|
+
self.CorrectAnnotationAction.triggered.connect(self.correct_seg_annotation)
|
|
159
166
|
|
|
160
167
|
self.DocumentationAction.triggered.connect(self.open_documentation)
|
|
161
168
|
|
|
@@ -186,6 +193,15 @@ class AppInitWindow(QMainWindow):
|
|
|
186
193
|
for r in self.recentFileActs:
|
|
187
194
|
r.triggered.connect(lambda checked, item=r: self.load_recent_exp(item.text()))
|
|
188
195
|
|
|
196
|
+
def correct_seg_annotation(self):
|
|
197
|
+
|
|
198
|
+
self.filename,_ = QFileDialog.getOpenFileName(self,"Open Image", "/home/", "TIF Files (*.tif)")
|
|
199
|
+
if self.filename!='':
|
|
200
|
+
print('Opening ',self.filename,' in napari...')
|
|
201
|
+
correct_annotation(self.filename)
|
|
202
|
+
else:
|
|
203
|
+
return None
|
|
204
|
+
|
|
189
205
|
def set_memory_and_threads(self):
|
|
190
206
|
|
|
191
207
|
print('setting memory and threads')
|
|
@@ -405,6 +421,7 @@ if __name__ == "__main__":
|
|
|
405
421
|
import subprocess
|
|
406
422
|
import os
|
|
407
423
|
from celldetective.gui.about import AboutWidget
|
|
424
|
+
from celldetective.io import correct_annotation
|
|
408
425
|
import psutil
|
|
409
426
|
import subprocess
|
|
410
427
|
import json
|
{celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/classifier_widget.py
RENAMED
|
@@ -12,6 +12,7 @@ from sklearn.metrics import r2_score
|
|
|
12
12
|
from scipy.optimize import curve_fit
|
|
13
13
|
from celldetective.gui import Styles
|
|
14
14
|
from math import ceil
|
|
15
|
+
from celldetective.utils import extract_cols_from_query
|
|
15
16
|
|
|
16
17
|
def step_function(t, t_shift, dt):
|
|
17
18
|
return 1/(1+np.exp(-(t-t_shift)/dt))
|
|
@@ -263,17 +264,23 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
263
264
|
self.propscanvas.canvas.draw_idle()
|
|
264
265
|
|
|
265
266
|
def apply_property_query(self):
|
|
267
|
+
|
|
266
268
|
query = self.property_query_le.text()
|
|
267
269
|
self.df[self.class_name] = 1
|
|
268
270
|
|
|
269
|
-
|
|
271
|
+
cols = extract_cols_from_query(query)
|
|
272
|
+
print(cols)
|
|
273
|
+
cols_in_df = np.all([c in list(self.df.columns) for c in cols], axis=0)
|
|
274
|
+
print(f'Testing if columns from query are in the dataframe: {cols_in_df}...')
|
|
270
275
|
|
|
271
276
|
if query=='':
|
|
272
277
|
print('empty query')
|
|
273
278
|
else:
|
|
274
279
|
try:
|
|
275
|
-
|
|
276
|
-
|
|
280
|
+
if cols_in_df:
|
|
281
|
+
self.selection = self.df.dropna(subset=cols).query(query).index
|
|
282
|
+
else:
|
|
283
|
+
self.selection = self.df.query(query).index
|
|
277
284
|
self.df.loc[self.selection, self.class_name] = 0
|
|
278
285
|
except Exception as e:
|
|
279
286
|
print(e)
|
|
@@ -16,6 +16,7 @@ import subprocess
|
|
|
16
16
|
from celldetective.gui.viewers import StackVisualizer
|
|
17
17
|
from celldetective.utils import extract_experiment_channels
|
|
18
18
|
from celldetective.gui import Styles
|
|
19
|
+
import pandas as pd
|
|
19
20
|
|
|
20
21
|
class ControlPanel(QMainWindow, Styles):
|
|
21
22
|
|
|
@@ -452,26 +453,32 @@ class ControlPanel(QMainWindow, Styles):
|
|
|
452
453
|
self.ProcessEffectors.check_tracking_result_btn.setEnabled(False)
|
|
453
454
|
|
|
454
455
|
if os.path.exists(os.sep.join([self.pos,'output','tables','trajectories_effectors.csv'])):
|
|
456
|
+
cols = pd.read_csv(os.sep.join([self.pos,'output','tables','trajectories_effectors.csv']), nrows=1).columns.tolist()
|
|
455
457
|
self.ProcessEffectors.check_measurements_btn.setEnabled(True)
|
|
456
|
-
|
|
458
|
+
if 'TRACK_ID' in cols:
|
|
459
|
+
self.ProcessEffectors.check_signals_btn.setEnabled(True)
|
|
457
460
|
#self.ProcessEffectors.signal_analysis_action.setEnabled(True)
|
|
458
461
|
self.ProcessEffectors.view_tab_btn.setEnabled(True)
|
|
459
|
-
|
|
462
|
+
self.ProcessEffectors.classify_btn.setEnabled(True)
|
|
460
463
|
else:
|
|
461
464
|
self.ProcessEffectors.check_measurements_btn.setEnabled(False)
|
|
462
465
|
self.ProcessEffectors.check_signals_btn.setEnabled(False)
|
|
463
466
|
#self.ProcessEffectors.signal_analysis_action.setEnabled(False)
|
|
464
467
|
self.ProcessEffectors.view_tab_btn.setEnabled(False)
|
|
468
|
+
self.ProcessEffectors.classify_btn.setEnabled(False)
|
|
465
469
|
|
|
466
470
|
if os.path.exists(os.sep.join([self.pos,'output','tables','trajectories_targets.csv'])):
|
|
471
|
+
cols = pd.read_csv(os.sep.join([self.pos,'output','tables','trajectories_targets.csv']), nrows=1).columns.tolist()
|
|
467
472
|
self.ProcessTargets.check_measurements_btn.setEnabled(True)
|
|
468
|
-
|
|
473
|
+
if 'TRACK_ID' in cols:
|
|
474
|
+
self.ProcessTargets.check_signals_btn.setEnabled(True)
|
|
469
475
|
#self.ProcessTargets.signal_analysis_action.setEnabled(True)
|
|
470
476
|
self.ProcessTargets.view_tab_btn.setEnabled(True)
|
|
471
|
-
|
|
477
|
+
self.ProcessTargets.classify_btn.setEnabled(True)
|
|
472
478
|
else:
|
|
473
479
|
self.ProcessTargets.check_measurements_btn.setEnabled(False)
|
|
474
480
|
self.ProcessTargets.check_signals_btn.setEnabled(False)
|
|
475
481
|
#self.ProcessTargets.signal_analysis_action.setEnabled(False)
|
|
476
482
|
self.ProcessTargets.view_tab_btn.setEnabled(False)
|
|
483
|
+
self.ProcessTargets.classify_btn.setEnabled(False)
|
|
477
484
|
|
|
@@ -990,10 +990,12 @@ class BackgroundModelFreeCorrectionLayout(QGridLayout, Styles):
|
|
|
990
990
|
)
|
|
991
991
|
bg = bg[0]
|
|
992
992
|
bg = bg['bg']
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
993
|
+
print(bg)
|
|
994
|
+
if len(bg)>0:
|
|
995
|
+
|
|
996
|
+
self.viewer = StackVisualizer(
|
|
997
|
+
stack=[bg],
|
|
998
|
+
window_title='Reconstructed background',
|
|
999
|
+
frame_slider = False,
|
|
1000
|
+
)
|
|
1001
|
+
self.viewer.show()
|
{celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/neighborhood_options.py
RENAMED
|
@@ -319,16 +319,16 @@ class ConfigNeighborhoods(QWidget, Styles):
|
|
|
319
319
|
def fill_cbs_of_neighbor_population(self):
|
|
320
320
|
|
|
321
321
|
population = self.neighbor_population_cb.currentText()
|
|
322
|
-
class_cols, status_cols, time_cols = self.locate_population_specific_columns(population)
|
|
322
|
+
class_cols, status_cols, group_cols, time_cols = self.locate_population_specific_columns(population)
|
|
323
323
|
self.neighbor_population_status_cb.clear()
|
|
324
|
-
self.neighbor_population_status_cb.addItems(['--','class', 'status']+class_cols+status_cols)
|
|
324
|
+
self.neighbor_population_status_cb.addItems(['--','class', 'status']+class_cols+status_cols+group_cols)
|
|
325
325
|
|
|
326
326
|
def fill_cbs_of_reference_population(self):
|
|
327
327
|
|
|
328
328
|
population = self.reference_population_cb.currentText()
|
|
329
|
-
class_cols, status_cols, time_cols = self.locate_population_specific_columns(population)
|
|
329
|
+
class_cols, status_cols, group_cols, time_cols = self.locate_population_specific_columns(population)
|
|
330
330
|
self.reference_population_status_cb.clear()
|
|
331
|
-
self.reference_population_status_cb.addItems(['--','class', 'status']+class_cols+status_cols)
|
|
331
|
+
self.reference_population_status_cb.addItems(['--','class', 'status']+class_cols+status_cols+group_cols)
|
|
332
332
|
self.event_time_cb.addItems(['--', 't0']+time_cols)
|
|
333
333
|
|
|
334
334
|
def switch_not_reference(self):
|
|
@@ -364,6 +364,7 @@ class ConfigNeighborhoods(QWidget, Styles):
|
|
|
364
364
|
|
|
365
365
|
class_idx = np.array([s.startswith('class_') for s in self.all_columns])
|
|
366
366
|
status_idx = np.array([s.startswith('status_') for s in self.all_columns])
|
|
367
|
+
group_idx = np.array([s.startswith('group_') for s in self.all_columns])
|
|
367
368
|
time_idx = np.array([s.startswith('t_') for s in self.all_columns])
|
|
368
369
|
|
|
369
370
|
if len(class_idx)>0:
|
|
@@ -379,12 +380,17 @@ class ConfigNeighborhoods(QWidget, Styles):
|
|
|
379
380
|
else:
|
|
380
381
|
status_columns = []
|
|
381
382
|
|
|
383
|
+
if len(group_idx)>0:
|
|
384
|
+
group_columns = list(self.all_columns[group_idx])
|
|
385
|
+
else:
|
|
386
|
+
group_columns = []
|
|
387
|
+
|
|
382
388
|
if len(time_idx)>0:
|
|
383
389
|
time_columns = list(self.all_columns[time_idx])
|
|
384
390
|
else:
|
|
385
391
|
time_columns = []
|
|
386
392
|
|
|
387
|
-
return class_columns, status_columns, time_columns
|
|
393
|
+
return class_columns, status_columns, group_columns, time_columns
|
|
388
394
|
|
|
389
395
|
def write_instructions(self):
|
|
390
396
|
|
{celldetective-1.1.1.post3 → celldetective-1.1.1.post4}/celldetective/gui/signal_annotator.py
RENAMED
|
@@ -27,6 +27,7 @@ from matplotlib.cm import tab10
|
|
|
27
27
|
import pandas as pd
|
|
28
28
|
from sklearn.preprocessing import MinMaxScaler
|
|
29
29
|
from celldetective.gui import Styles
|
|
30
|
+
from celldetective.measure import contour_of_instance_segmentation
|
|
30
31
|
|
|
31
32
|
class SignalAnnotator(QMainWindow, Styles):
|
|
32
33
|
"""
|
|
@@ -76,9 +77,9 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
76
77
|
|
|
77
78
|
self.populate_widget()
|
|
78
79
|
|
|
79
|
-
self.setMinimumWidth(int(0.8 * self.screen_width))
|
|
80
|
+
#self.setMinimumWidth(int(0.8 * self.screen_width))
|
|
80
81
|
# self.setMaximumHeight(int(0.8*self.screen_height))
|
|
81
|
-
self.setMinimumHeight(int(0.8 * self.screen_height))
|
|
82
|
+
#self.setMinimumHeight(int(0.8 * self.screen_height))
|
|
82
83
|
# self.setMaximumHeight(int(0.8*self.screen_height))
|
|
83
84
|
|
|
84
85
|
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
@@ -119,7 +120,6 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
119
120
|
|
|
120
121
|
self.class_choice_cb.addItems(self.class_cols)
|
|
121
122
|
self.class_choice_cb.currentIndexChanged.connect(self.compute_status_and_colors)
|
|
122
|
-
self.class_choice_cb.setCurrentIndex(0)
|
|
123
123
|
|
|
124
124
|
class_hbox.addWidget(self.class_choice_cb, 70)
|
|
125
125
|
|
|
@@ -346,6 +346,8 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
346
346
|
main_layout.addLayout(self.right_panel, 65)
|
|
347
347
|
self.button_widget.adjustSize()
|
|
348
348
|
|
|
349
|
+
self.compute_status_and_colors(0)
|
|
350
|
+
|
|
349
351
|
self.setCentralWidget(self.button_widget)
|
|
350
352
|
self.show()
|
|
351
353
|
|
|
@@ -462,6 +464,7 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
462
464
|
self.newClassWidget.close()
|
|
463
465
|
|
|
464
466
|
def compute_status_and_colors(self, i):
|
|
467
|
+
|
|
465
468
|
self.class_name = self.class_choice_cb.currentText()
|
|
466
469
|
self.expected_status = 'status'
|
|
467
470
|
suffix = self.class_name.replace('class', '').replace('_', '', 1)
|
|
@@ -474,11 +477,15 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
474
477
|
self.status_name = self.expected_status
|
|
475
478
|
|
|
476
479
|
print('selection and expected names: ', self.class_name, self.expected_time, self.expected_status)
|
|
480
|
+
cols = list(self.df_tracks.columns)
|
|
477
481
|
|
|
478
|
-
if self.time_name in
|
|
482
|
+
if self.time_name in cols and self.class_name in cols and not self.status_name in cols:
|
|
479
483
|
# only create the status column if it does not exist to not erase static classification results
|
|
480
484
|
self.make_status_column()
|
|
481
|
-
elif self.time_name in
|
|
485
|
+
elif self.time_name in cols and self.class_name in cols and self.df_tracks[self.status_name].isnull().all():
|
|
486
|
+
print('this is the case!', )
|
|
487
|
+
self.make_status_column()
|
|
488
|
+
elif self.time_name in cols and self.class_name in cols:
|
|
482
489
|
# all good, do nothing
|
|
483
490
|
pass
|
|
484
491
|
else:
|
|
@@ -855,7 +862,7 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
855
862
|
self.cell_ax.legend()
|
|
856
863
|
self.cell_fcanvas.canvas.draw()
|
|
857
864
|
except Exception as e:
|
|
858
|
-
print(f"{e=}")
|
|
865
|
+
print(f"Plot signals: {e=}")
|
|
859
866
|
|
|
860
867
|
def extract_scatter_from_trajectories(self):
|
|
861
868
|
|
|
@@ -1109,7 +1116,7 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
1109
1116
|
if len(min_values) > 0:
|
|
1110
1117
|
self.cell_ax.set_ylim(np.amin(min_values), np.amax(max_values))
|
|
1111
1118
|
except Exception as e:
|
|
1112
|
-
print(e)
|
|
1119
|
+
print('Ylim error:',e)
|
|
1113
1120
|
|
|
1114
1121
|
def draw_frame(self, framedata):
|
|
1115
1122
|
|
|
@@ -1301,7 +1308,9 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
1301
1308
|
|
|
1302
1309
|
|
|
1303
1310
|
class MeasureAnnotator(SignalAnnotator):
|
|
1311
|
+
|
|
1304
1312
|
def __init__(self, parent_window=None):
|
|
1313
|
+
|
|
1305
1314
|
QMainWindow.__init__(self)
|
|
1306
1315
|
self.parent_window = parent_window
|
|
1307
1316
|
self.setWindowTitle("Signal annotator")
|
|
@@ -1315,11 +1324,11 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1315
1324
|
self.int_validator = QIntValidator()
|
|
1316
1325
|
self.current_alpha=0.5
|
|
1317
1326
|
if self.mode == "targets":
|
|
1318
|
-
self.instructions_path = self.exp_dir +
|
|
1319
|
-
self.trajectories_path = self.pos + 'output
|
|
1327
|
+
self.instructions_path = self.exp_dir + os.sep.join(['configs','signal_annotator_config_targets.json'])
|
|
1328
|
+
self.trajectories_path = self.pos + os.sep.join(['output','tables','trajectories_targets.csv'])
|
|
1320
1329
|
elif self.mode == "effectors":
|
|
1321
|
-
self.instructions_path = self.exp_dir +
|
|
1322
|
-
self.trajectories_path = self.pos + 'output
|
|
1330
|
+
self.instructions_path = self.exp_dir + os.sep.join(['configs','signal_annotator_config_effectors.json'])
|
|
1331
|
+
self.trajectories_path = self.pos + os.sep.join(['output','tables','trajectories_effectors.csv'])
|
|
1323
1332
|
|
|
1324
1333
|
self.screen_height = self.parent_window.parent_window.parent_window.screen_height
|
|
1325
1334
|
self.screen_width = self.parent_window.parent_window.parent_window.screen_width
|
|
@@ -1330,8 +1339,13 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1330
1339
|
center_window(self)
|
|
1331
1340
|
|
|
1332
1341
|
self.locate_stack()
|
|
1342
|
+
|
|
1333
1343
|
data, properties, graph, labels, _ = load_napari_data(self.pos, prefix=None, population=self.mode,return_stack=False)
|
|
1334
|
-
|
|
1344
|
+
if data is not None:
|
|
1345
|
+
self.labels = relabel_segmentation(labels,data,properties)
|
|
1346
|
+
else:
|
|
1347
|
+
self.labels = labels
|
|
1348
|
+
|
|
1335
1349
|
self.current_channel = 0
|
|
1336
1350
|
|
|
1337
1351
|
self.locate_tracks()
|
|
@@ -1577,8 +1591,10 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1577
1591
|
self.class_choice_cb = QComboBox()
|
|
1578
1592
|
|
|
1579
1593
|
cols = np.array(self.df_tracks.columns)
|
|
1580
|
-
self.class_cols = np.array([c.startswith('group') for c in list(self.df_tracks.columns)])
|
|
1594
|
+
self.class_cols = np.array([c.startswith('group') or c.startswith('status') for c in list(self.df_tracks.columns)])
|
|
1581
1595
|
self.class_cols = list(cols[self.class_cols])
|
|
1596
|
+
print(self.class_cols)
|
|
1597
|
+
|
|
1582
1598
|
try:
|
|
1583
1599
|
self.class_cols.remove('group_id')
|
|
1584
1600
|
except Exception:
|
|
@@ -1711,6 +1727,14 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1711
1727
|
btn_hbox.addWidget(self.save_btn, 90)
|
|
1712
1728
|
self.left_panel.addLayout(btn_hbox)
|
|
1713
1729
|
|
|
1730
|
+
self.export_btn = QPushButton('')
|
|
1731
|
+
self.export_btn.setStyleSheet(self.button_select_all)
|
|
1732
|
+
self.export_btn.clicked.connect(self.export_measurements)
|
|
1733
|
+
self.export_btn.setIcon(icon(MDI6.export, color="black"))
|
|
1734
|
+
self.export_btn.setIconSize(QSize(25, 25))
|
|
1735
|
+
btn_hbox.addWidget(self.export_btn, 10)
|
|
1736
|
+
self.left_panel.addLayout(btn_hbox)
|
|
1737
|
+
|
|
1714
1738
|
# Animation
|
|
1715
1739
|
animation_buttons_box = QHBoxLayout()
|
|
1716
1740
|
|
|
@@ -1810,6 +1834,28 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1810
1834
|
# del self.img
|
|
1811
1835
|
gc.collect()
|
|
1812
1836
|
|
|
1837
|
+
|
|
1838
|
+
def export_measurements(self):
|
|
1839
|
+
|
|
1840
|
+
auto_dataset_name = self.pos.split(os.sep)[-4] + '_' + self.pos.split(os.sep)[-2] + f'_{str(self.current_frame).zfill(3)}' + f'_{self.status_name}.npy'
|
|
1841
|
+
|
|
1842
|
+
if self.normalized_signals:
|
|
1843
|
+
self.normalize_features_btn.click()
|
|
1844
|
+
|
|
1845
|
+
subdf = self.df_tracks.loc[self.df_tracks['FRAME']==self.current_frame,:]
|
|
1846
|
+
subdf['class'] = subdf[self.status_name]
|
|
1847
|
+
dico = subdf.to_dict('records')
|
|
1848
|
+
|
|
1849
|
+
pathsave = QFileDialog.getSaveFileName(self, "Select file name", self.exp_dir + auto_dataset_name, ".npy")[0]
|
|
1850
|
+
if pathsave != '':
|
|
1851
|
+
if not pathsave.endswith(".npy"):
|
|
1852
|
+
pathsave += ".npy"
|
|
1853
|
+
try:
|
|
1854
|
+
np.save(pathsave, dico)
|
|
1855
|
+
print(f'File successfully written in {pathsave}.')
|
|
1856
|
+
except Exception as e:
|
|
1857
|
+
print(f"Error {e}...")
|
|
1858
|
+
|
|
1813
1859
|
def set_next_frame(self):
|
|
1814
1860
|
|
|
1815
1861
|
self.current_frame = self.current_frame + 1
|
|
@@ -1887,13 +1933,17 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1887
1933
|
|
|
1888
1934
|
def give_cell_information(self):
|
|
1889
1935
|
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1936
|
+
try:
|
|
1937
|
+
cell_selected = f"cell: {self.track_of_interest}\n"
|
|
1938
|
+
if 'TRACK_ID' in self.df_tracks.columns:
|
|
1939
|
+
cell_status = f"phenotype: {self.df_tracks.loc[self.df_tracks['TRACK_ID'] == self.track_of_interest, self.status_name].to_numpy()[0]}\n"
|
|
1940
|
+
else:
|
|
1941
|
+
cell_status = f"phenotype: {self.df_tracks.loc[self.df_tracks['ID'] == self.track_of_interest, self.status_name].to_numpy()[0]}\n"
|
|
1942
|
+
self.cell_info.setText(cell_selected + cell_status)
|
|
1943
|
+
except Exception as e:
|
|
1944
|
+
print('Cell info:',e)
|
|
1945
|
+
print(self.track_of_interest, self.status_name)
|
|
1946
|
+
|
|
1897
1947
|
def create_new_event_class(self):
|
|
1898
1948
|
|
|
1899
1949
|
# display qwidget to name the event
|
|
@@ -1978,8 +2028,14 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
1978
2028
|
self.frame_lbl.setText(f'position: {self.framedata}')
|
|
1979
2029
|
self.im.set_array(self.img)
|
|
1980
2030
|
self.status_scatter.set_offsets(self.positions[self.framedata])
|
|
1981
|
-
|
|
2031
|
+
try:
|
|
2032
|
+
self.status_scatter.set_edgecolors(self.colors[self.framedata][:, 0])
|
|
2033
|
+
except Exception as e:
|
|
2034
|
+
print('L1993: ',e)
|
|
2035
|
+
|
|
1982
2036
|
self.current_label = self.labels[self.current_frame]
|
|
2037
|
+
self.current_label = contour_of_instance_segmentation(self.current_label, 5)
|
|
2038
|
+
|
|
1983
2039
|
self.im_mask.remove()
|
|
1984
2040
|
self.im_mask = self.ax.imshow(np.ma.masked_where(self.current_label == 0, self.current_label),
|
|
1985
2041
|
cmap='viridis', interpolation='none',alpha=self.current_alpha,vmin=0,vmax=np.nanmax(self.labels.flatten()))
|
|
@@ -2108,9 +2164,9 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
2108
2164
|
|
|
2109
2165
|
self.extract_scatter_from_trajectories()
|
|
2110
2166
|
if 'TRACK_ID' in self.df_tracks.columns:
|
|
2111
|
-
self.track_of_interest = self.df_tracks['TRACK_ID'].min()
|
|
2167
|
+
self.track_of_interest = self.df_tracks.dropna(subset='TRACK_ID')['TRACK_ID'].min()
|
|
2112
2168
|
else:
|
|
2113
|
-
self.track_of_interest = self.df_tracks['ID'].min()
|
|
2169
|
+
self.track_of_interest = self.df_tracks.dropna(subset='ID')['ID'].min()
|
|
2114
2170
|
|
|
2115
2171
|
self.loc_t = []
|
|
2116
2172
|
self.loc_idx = []
|
|
@@ -2172,9 +2228,13 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
2172
2228
|
"""
|
|
2173
2229
|
self.current_frame = self.frame_slider.value()
|
|
2174
2230
|
self.reload_frame()
|
|
2175
|
-
if '
|
|
2231
|
+
if 'TRACK_ID' in list(self.df_tracks.columns):
|
|
2232
|
+
pass
|
|
2233
|
+
elif 'ID' in list(self.df_tracks.columns):
|
|
2234
|
+
print('ID in cols... change class of interest... ')
|
|
2176
2235
|
self.track_of_interest = self.df_tracks[self.df_tracks['FRAME'] == self.current_frame]['ID'].min()
|
|
2177
2236
|
self.modify()
|
|
2237
|
+
|
|
2178
2238
|
self.draw_frame(self.current_frame)
|
|
2179
2239
|
self.fcanvas.canvas.draw()
|
|
2180
2240
|
self.plot_signals()
|
|
@@ -2302,7 +2362,7 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
2302
2362
|
try:
|
|
2303
2363
|
self.selection.pop(0)
|
|
2304
2364
|
except Exception as e:
|
|
2305
|
-
print(e)
|
|
2365
|
+
print('Cancel selection: ',e)
|
|
2306
2366
|
|
|
2307
2367
|
try:
|
|
2308
2368
|
for k, (t, idx) in enumerate(zip(self.loc_t, self.loc_idx)):
|
|
@@ -65,9 +65,9 @@ class QueryWidget(QWidget):
|
|
|
65
65
|
|
|
66
66
|
def filter_table(self):
|
|
67
67
|
try:
|
|
68
|
-
query_text = self.query_le.text()
|
|
68
|
+
query_text = self.query_le.text() #.replace('class', '`class`')
|
|
69
69
|
tab = self.parent_window.data.query(query_text)
|
|
70
|
-
self.subtable = TableUI(tab, query_text, plot_mode="
|
|
70
|
+
self.subtable = TableUI(tab, query_text, plot_mode="static")
|
|
71
71
|
self.subtable.show()
|
|
72
72
|
self.close()
|
|
73
73
|
except Exception as e:
|
|
@@ -268,7 +268,6 @@ class RenameColWidget(QWidget):
|
|
|
268
268
|
old_name = self.column
|
|
269
269
|
new_name = self.new_col_name.text()
|
|
270
270
|
self.parent_window.data = self.parent_window.data.rename(columns={old_name: new_name})
|
|
271
|
-
print(self.parent.data.columns)
|
|
272
271
|
|
|
273
272
|
self.parent_window.model = PandasModel(self.parent_window.data)
|
|
274
273
|
self.parent_window.table_view.setModel(self.parent_window.model)
|
|
@@ -583,18 +582,20 @@ class TableUI(QMainWindow, Styles):
|
|
|
583
582
|
layout.addWidget(QLabel('Representations: '))
|
|
584
583
|
self.hist_check = QCheckBox('histogram')
|
|
585
584
|
self.kde_check = QCheckBox('KDE plot')
|
|
586
|
-
self.count_check = QCheckBox('
|
|
585
|
+
self.count_check = QCheckBox('countplot')
|
|
587
586
|
self.ecdf_check = QCheckBox('ECDF plot')
|
|
587
|
+
self.scat_check = QCheckBox('scatter plot')
|
|
588
588
|
self.swarm_check = QCheckBox('swarm')
|
|
589
589
|
self.violin_check = QCheckBox('violin')
|
|
590
590
|
self.strip_check = QCheckBox('strip')
|
|
591
|
-
self.box_check = QCheckBox('
|
|
592
|
-
self.boxenplot_check = QCheckBox('
|
|
591
|
+
self.box_check = QCheckBox('boxplot')
|
|
592
|
+
self.boxenplot_check = QCheckBox('boxenplot')
|
|
593
593
|
|
|
594
594
|
layout.addWidget(self.hist_check)
|
|
595
595
|
layout.addWidget(self.kde_check)
|
|
596
596
|
layout.addWidget(self.count_check)
|
|
597
597
|
layout.addWidget(self.ecdf_check)
|
|
598
|
+
layout.addWidget(self.scat_check)
|
|
598
599
|
layout.addWidget(self.swarm_check)
|
|
599
600
|
layout.addWidget(self.violin_check)
|
|
600
601
|
layout.addWidget(self.strip_check)
|
|
@@ -707,6 +708,14 @@ class TableUI(QMainWindow, Styles):
|
|
|
707
708
|
if self.ecdf_check.isChecked():
|
|
708
709
|
sns.ecdfplot(data=self.data, x=self.x, hue=hue_variable, legend=legend, ax=self.ax, palette=colors)
|
|
709
710
|
legend = False
|
|
711
|
+
|
|
712
|
+
if self.scat_check.isChecked():
|
|
713
|
+
if self.x_option:
|
|
714
|
+
sns.scatterplot(data=self.data, x=self.x,y=self.y, hue=hue_variable,legend=legend, ax=self.ax, palette=colors)
|
|
715
|
+
legend = False
|
|
716
|
+
else:
|
|
717
|
+
print('please provide a -x variable...')
|
|
718
|
+
pass
|
|
710
719
|
|
|
711
720
|
if self.swarm_check.isChecked():
|
|
712
721
|
if self.x_option:
|
|
@@ -26,6 +26,7 @@ from stardist import fill_label_holes
|
|
|
26
26
|
from celldetective.utils import interpolate_nan
|
|
27
27
|
from scipy.interpolate import griddata
|
|
28
28
|
|
|
29
|
+
|
|
29
30
|
def get_experiment_wells(experiment):
|
|
30
31
|
|
|
31
32
|
"""
|
|
@@ -801,6 +802,10 @@ def auto_load_number_of_frames(stack_path):
|
|
|
801
802
|
"""
|
|
802
803
|
|
|
803
804
|
# Try to estimate automatically # frames
|
|
805
|
+
|
|
806
|
+
if stack_path is None:
|
|
807
|
+
return None
|
|
808
|
+
|
|
804
809
|
stack_path = stack_path.replace('\\','/')
|
|
805
810
|
|
|
806
811
|
with TiffFile(stack_path) as tif:
|
|
@@ -1370,6 +1375,14 @@ def control_segmentation_napari(position, prefix='Aligned', population="target",
|
|
|
1370
1375
|
exp_name = os.path.split(expfolder)[-1]
|
|
1371
1376
|
print(exp_name)
|
|
1372
1377
|
|
|
1378
|
+
wells = get_experiment_wells(expfolder)
|
|
1379
|
+
well_idx = list(wells).index(str(parent1)+os.sep)
|
|
1380
|
+
ab = get_experiment_antibodies(expfolder)[well_idx]
|
|
1381
|
+
conc = get_experiment_concentrations(expfolder)[well_idx]
|
|
1382
|
+
ct = get_experiment_cell_types(expfolder)[well_idx]
|
|
1383
|
+
pa = get_experiment_pharmaceutical_agents(expfolder)[well_idx]
|
|
1384
|
+
|
|
1385
|
+
|
|
1373
1386
|
spatial_calibration = float(ConfigSectionMap(config,"MovieSettings")["pxtoum"])
|
|
1374
1387
|
channel_names, channel_indices = extract_experiment_channels(config)
|
|
1375
1388
|
|
|
@@ -1424,7 +1437,7 @@ def control_segmentation_napari(position, prefix='Aligned', population="target",
|
|
|
1424
1437
|
multichannel = np.array(multichannel)
|
|
1425
1438
|
save_tiff_imagej_compatible(annotation_folder + f"{exp_name}_{position.split(os.sep)[-2]}_{str(t).zfill(4)}_roi_{xmin}_{xmax}_{ymin}_{ymax}_labelled.tif", labels_layer[xmin:xmax,ymin:ymax].astype(np.int16), axes='YX')
|
|
1426
1439
|
save_tiff_imagej_compatible(annotation_folder + f"{exp_name}_{position.split(os.sep)[-2]}_{str(t).zfill(4)}_roi_{xmin}_{xmax}_{ymin}_{ymax}.tif", multichannel, axes='CYX')
|
|
1427
|
-
info = {"spatial_calibration": spatial_calibration, "channels": list(channel_names)}
|
|
1440
|
+
info = {"spatial_calibration": spatial_calibration, "channels": list(channel_names), 'cell_type': ct, 'antibody': ab, 'concentration': conc, 'pharmaceutical_agent': pa}
|
|
1428
1441
|
info_name = annotation_folder + f"{exp_name}_{position.split(os.sep)[-2]}_{str(t).zfill(4)}_roi_{xmin}_{xmax}_{ymin}_{ymax}.json"
|
|
1429
1442
|
with open(info_name, 'w') as f:
|
|
1430
1443
|
json.dump(info, f, indent=4)
|
|
@@ -1441,7 +1454,7 @@ def control_segmentation_napari(position, prefix='Aligned', population="target",
|
|
|
1441
1454
|
multichannel = np.array(multichannel)
|
|
1442
1455
|
save_tiff_imagej_compatible(annotation_folder + f"{exp_name}_{position.split(os.sep)[-2]}_{str(t).zfill(4)}_labelled.tif", labels_layer, axes='YX')
|
|
1443
1456
|
save_tiff_imagej_compatible(annotation_folder + f"{exp_name}_{position.split(os.sep)[-2]}_{str(t).zfill(4)}.tif", multichannel, axes='CYX')
|
|
1444
|
-
info = {"spatial_calibration": spatial_calibration, "channels": list(channel_names)}
|
|
1457
|
+
info = {"spatial_calibration": spatial_calibration, "channels": list(channel_names), 'cell_type': ct, 'antibody': ab, 'concentration': conc, 'pharmaceutical_agent': pa}
|
|
1445
1458
|
info_name = annotation_folder + f"{exp_name}_{position.split(os.sep)[-2]}_{str(t).zfill(4)}.json"
|
|
1446
1459
|
with open(info_name, 'w') as f:
|
|
1447
1460
|
json.dump(info, f, indent=4)
|
|
@@ -1481,6 +1494,59 @@ def control_segmentation_napari(position, prefix='Aligned', population="target",
|
|
|
1481
1494
|
del labels
|
|
1482
1495
|
gc.collect()
|
|
1483
1496
|
|
|
1497
|
+
def correct_annotation(filename):
|
|
1498
|
+
|
|
1499
|
+
"""
|
|
1500
|
+
New function to reannotate an annotation image in post, using napari and save update inplace.
|
|
1501
|
+
"""
|
|
1502
|
+
|
|
1503
|
+
def export_labels():
|
|
1504
|
+
labels_layer = viewer.layers['segmentation'].data
|
|
1505
|
+
for t,im in enumerate(tqdm(labels_layer)):
|
|
1506
|
+
|
|
1507
|
+
try:
|
|
1508
|
+
im = auto_correct_masks(im)
|
|
1509
|
+
except Exception as e:
|
|
1510
|
+
print(e)
|
|
1511
|
+
|
|
1512
|
+
save_tiff_imagej_compatible(existing_lbl, im.astype(np.int16), axes='YX')
|
|
1513
|
+
print("The labels have been successfully rewritten.")
|
|
1514
|
+
|
|
1515
|
+
@magicgui(call_button='Save the modified labels')
|
|
1516
|
+
def save_widget():
|
|
1517
|
+
return export_labels()
|
|
1518
|
+
|
|
1519
|
+
img = imread(filename.replace('\\','/'))
|
|
1520
|
+
if img.ndim==3:
|
|
1521
|
+
img = np.moveaxis(img, 0, -1)
|
|
1522
|
+
elif img.ndim==2:
|
|
1523
|
+
img = img[:,:,np.newaxis]
|
|
1524
|
+
|
|
1525
|
+
existing_lbl = filename.replace('.tif','_labelled.tif')
|
|
1526
|
+
if os.path.exists(existing_lbl):
|
|
1527
|
+
labels = imread(existing_lbl)[np.newaxis,:,:].astype(int)
|
|
1528
|
+
else:
|
|
1529
|
+
labels = np.zeros_like(img[:,:,0]).astype(int)[np.newaxis,:,:]
|
|
1530
|
+
|
|
1531
|
+
stack = img[np.newaxis,:,:,:]
|
|
1532
|
+
|
|
1533
|
+
viewer = napari.Viewer()
|
|
1534
|
+
viewer.add_image(stack,channel_axis=-1,colormap=["gray"]*stack.shape[-1])
|
|
1535
|
+
viewer.add_labels(labels, name='segmentation',opacity=0.4)
|
|
1536
|
+
viewer.window.add_dock_widget(save_widget, area='right')
|
|
1537
|
+
viewer.show(block=True)
|
|
1538
|
+
|
|
1539
|
+
# temporary fix for slight napari memory leak
|
|
1540
|
+
for i in range(100):
|
|
1541
|
+
try:
|
|
1542
|
+
viewer.layers.pop()
|
|
1543
|
+
except:
|
|
1544
|
+
pass
|
|
1545
|
+
del viewer
|
|
1546
|
+
del stack
|
|
1547
|
+
del labels
|
|
1548
|
+
gc.collect()
|
|
1549
|
+
|
|
1484
1550
|
|
|
1485
1551
|
def _view_on_napari(tracks=None, stack=None, labels=None):
|
|
1486
1552
|
|
|
@@ -1628,7 +1694,7 @@ def locate_segmentation_model(name):
|
|
|
1628
1694
|
"""
|
|
1629
1695
|
|
|
1630
1696
|
main_dir = os.sep.join([os.path.split(os.path.dirname(os.path.realpath(__file__)))[0],"celldetective"])
|
|
1631
|
-
modelpath = os.sep.join([main_dir, "models", "segmentation*"
|
|
1697
|
+
modelpath = os.sep.join([main_dir, "models", "segmentation*"]) + os.sep
|
|
1632
1698
|
print(f'Looking for {name} in {modelpath}')
|
|
1633
1699
|
models = glob(modelpath+f'*{os.sep}')
|
|
1634
1700
|
|