celldetective 1.3.9.post5__py3-none-any.whl → 1.4.1__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.
- celldetective/__init__.py +0 -3
- celldetective/_version.py +1 -1
- celldetective/events.py +2 -4
- celldetective/exceptions.py +11 -0
- celldetective/extra_properties.py +132 -0
- celldetective/filters.py +7 -1
- celldetective/gui/InitWindow.py +37 -46
- celldetective/gui/__init__.py +3 -9
- celldetective/gui/about.py +19 -15
- celldetective/gui/analyze_block.py +34 -19
- celldetective/gui/base_annotator.py +786 -0
- celldetective/gui/base_components.py +23 -0
- celldetective/gui/classifier_widget.py +86 -94
- celldetective/gui/configure_new_exp.py +163 -46
- celldetective/gui/control_panel.py +76 -146
- celldetective/gui/{signal_annotator.py → event_annotator.py} +533 -1438
- celldetective/gui/generic_signal_plot.py +11 -13
- celldetective/gui/gui_utils.py +54 -23
- celldetective/gui/help/neighborhood.json +2 -2
- celldetective/gui/json_readers.py +5 -4
- celldetective/gui/layouts.py +265 -31
- celldetective/gui/{signal_annotator2.py → pair_event_annotator.py} +433 -635
- celldetective/gui/plot_measurements.py +21 -17
- celldetective/gui/plot_signals_ui.py +125 -72
- celldetective/gui/process_block.py +283 -188
- celldetective/gui/processes/compute_neighborhood.py +594 -0
- celldetective/gui/processes/downloader.py +37 -34
- celldetective/gui/processes/measure_cells.py +19 -8
- celldetective/gui/processes/segment_cells.py +47 -11
- celldetective/gui/processes/track_cells.py +18 -13
- celldetective/gui/seg_model_loader.py +21 -62
- celldetective/gui/settings/__init__.py +7 -0
- celldetective/gui/settings/_settings_base.py +70 -0
- celldetective/gui/{retrain_signal_model_options.py → settings/_settings_event_model_training.py} +54 -109
- celldetective/gui/{measurement_options.py → settings/_settings_measurements.py} +54 -92
- celldetective/gui/{neighborhood_options.py → settings/_settings_neighborhood.py} +10 -13
- celldetective/gui/settings/_settings_segmentation.py +49 -0
- celldetective/gui/{retrain_segmentation_model_options.py → settings/_settings_segmentation_model_training.py} +38 -92
- celldetective/gui/{signal_annotator_options.py → settings/_settings_signal_annotator.py} +78 -103
- celldetective/gui/{btrack_options.py → settings/_settings_tracking.py} +85 -116
- celldetective/gui/styles.py +2 -1
- celldetective/gui/survival_ui.py +49 -95
- celldetective/gui/tableUI.py +53 -25
- celldetective/gui/table_ops/__init__.py +0 -0
- celldetective/gui/table_ops/merge_groups.py +118 -0
- celldetective/gui/thresholds_gui.py +617 -1221
- celldetective/gui/viewers.py +107 -42
- celldetective/gui/workers.py +8 -4
- celldetective/io.py +137 -57
- celldetective/links/zenodo.json +145 -144
- celldetective/measure.py +94 -53
- celldetective/neighborhood.py +342 -268
- celldetective/preprocessing.py +56 -35
- celldetective/regionprops/_regionprops.py +16 -5
- celldetective/relative_measurements.py +50 -29
- celldetective/scripts/analyze_signals.py +4 -1
- celldetective/scripts/measure_cells.py +5 -5
- celldetective/scripts/measure_relative.py +20 -12
- celldetective/scripts/segment_cells.py +4 -10
- celldetective/scripts/segment_cells_thresholds.py +3 -3
- celldetective/scripts/track_cells.py +10 -8
- celldetective/scripts/train_segmentation_model.py +18 -6
- celldetective/signals.py +29 -14
- celldetective/tracking.py +14 -3
- celldetective/utils.py +91 -62
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/METADATA +24 -16
- celldetective-1.4.1.dist-info/RECORD +123 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/WHEEL +1 -1
- tests/gui/__init__.py +0 -0
- tests/gui/test_new_project.py +228 -0
- tests/gui/test_project.py +99 -0
- tests/test_preprocessing.py +2 -2
- celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +0 -79
- celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
- celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +0 -37
- celldetective/models/segmentation_effectors/test-transfer/config_input.json +0 -39
- celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
- celldetective/models/signal_detection/NucCond/classification_loss.png +0 -0
- celldetective/models/signal_detection/NucCond/classifier.h5 +0 -0
- celldetective/models/signal_detection/NucCond/config_input.json +0 -1
- celldetective/models/signal_detection/NucCond/log_classifier.csv +0 -126
- celldetective/models/signal_detection/NucCond/log_regressor.csv +0 -282
- celldetective/models/signal_detection/NucCond/regression_loss.png +0 -0
- celldetective/models/signal_detection/NucCond/regressor.h5 +0 -0
- celldetective/models/signal_detection/NucCond/scores.npy +0 -0
- celldetective/models/signal_detection/NucCond/test_confusion_matrix.png +0 -0
- celldetective/models/signal_detection/NucCond/test_regression.png +0 -0
- celldetective/models/signal_detection/NucCond/validation_confusion_matrix.png +0 -0
- celldetective/models/signal_detection/NucCond/validation_regression.png +0 -0
- celldetective-1.3.9.post5.dist-info/RECORD +0 -129
- tests/test_qt.py +0 -103
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/entry_points.txt +0 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info/licenses}/LICENSE +0 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/top_level.txt +0 -0
celldetective/gui/layouts.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import QCheckBox, QLineEdit,
|
|
1
|
+
from PyQt5.QtWidgets import QCheckBox, QLineEdit, QListWidget, QTabWidget, QHBoxLayout,QMessageBox, QPushButton, QVBoxLayout, QRadioButton, QLabel, QButtonGroup, QSizePolicy, QComboBox,QSpacerItem, QGridLayout
|
|
2
2
|
from celldetective.gui.gui_utils import ThresholdLineEdit, QuickSliderLayout, center_window
|
|
3
3
|
from PyQt5.QtCore import Qt, QSize
|
|
4
|
-
from PyQt5.QtGui import QIntValidator
|
|
4
|
+
from PyQt5.QtGui import QIntValidator, QDoubleValidator
|
|
5
5
|
|
|
6
6
|
from superqt import QLabeledRangeSlider, QLabeledDoubleSlider, QLabeledSlider, QLabeledDoubleRangeSlider, QSearchableComboBox
|
|
7
7
|
|
|
@@ -9,15 +9,223 @@ from superqt.fonticon import icon
|
|
|
9
9
|
from fonticon_mdi6 import MDI6
|
|
10
10
|
from celldetective.utils import _extract_channel_indices_from_config
|
|
11
11
|
from celldetective.gui.viewers import ThresholdedStackVisualizer, CellEdgeVisualizer, StackVisualizer, CellSizeViewer, ChannelOffsetViewer
|
|
12
|
-
from celldetective.gui import Styles
|
|
12
|
+
from celldetective.gui import Styles, CelldetectiveWidget
|
|
13
13
|
from celldetective.preprocessing import correct_background_model, correct_background_model_free, estimate_background_per_condition
|
|
14
14
|
from functools import partial
|
|
15
15
|
from glob import glob
|
|
16
16
|
import os
|
|
17
17
|
import pandas as pd
|
|
18
18
|
import numpy as np
|
|
19
|
+
from celldetective.io import locate_segmentation_model, locate_signal_model
|
|
20
|
+
import json
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
|
|
23
|
+
class SignalModelParamsWidget(CelldetectiveWidget):
|
|
24
|
+
|
|
25
|
+
def __init__(self, parent_window=None, model_name=None, *args, **kwargs):
|
|
26
|
+
|
|
27
|
+
super().__init__(*args)
|
|
28
|
+
self.setWindowTitle('Signals')
|
|
29
|
+
self.parent_window = parent_window
|
|
30
|
+
self.model_name = model_name
|
|
31
|
+
self.locate_model_path()
|
|
32
|
+
self.required_channels = self.input_config["channels"]
|
|
33
|
+
self.onlyFloat = QDoubleValidator()
|
|
34
|
+
|
|
35
|
+
# Setting up references to parent window attributes
|
|
36
|
+
if hasattr(self.parent_window.parent_window, 'locate_image'):
|
|
37
|
+
self.attr_parent = self.parent_window.parent_window
|
|
38
|
+
elif hasattr(self.parent_window.parent_window.parent_window, 'locate_image'):
|
|
39
|
+
self.attr_parent = self.parent_window.parent_window.parent_window
|
|
40
|
+
else:
|
|
41
|
+
self.attr_parent = self.parent_window.parent_window.parent_window.parent_window
|
|
42
|
+
|
|
43
|
+
# Set up layout and widgets
|
|
44
|
+
self.layout = QVBoxLayout()
|
|
45
|
+
self.populate_widgets()
|
|
46
|
+
self.setLayout(self.layout)
|
|
47
|
+
center_window(self)
|
|
48
|
+
|
|
49
|
+
def locate_model_path(self):
|
|
50
|
+
|
|
51
|
+
self.model_complete_path = locate_signal_model(self.model_name)
|
|
52
|
+
if self.model_complete_path is None:
|
|
53
|
+
print('Model could not be found. Abort.')
|
|
54
|
+
self.abort_process()
|
|
55
|
+
else:
|
|
56
|
+
print(f'Model path: {self.model_complete_path}...')
|
|
57
|
+
|
|
58
|
+
if not os.path.exists(self.model_complete_path+"config_input.json"):
|
|
59
|
+
print('The configuration for the inputs to the model could not be located. Abort.')
|
|
60
|
+
self.abort_process()
|
|
61
|
+
|
|
62
|
+
with open(self.model_complete_path+"config_input.json") as config_file:
|
|
63
|
+
self.input_config = json.load(config_file)
|
|
64
|
+
|
|
65
|
+
def populate_widgets(self):
|
|
66
|
+
|
|
67
|
+
self.n_channels = len(self.required_channels)
|
|
68
|
+
self.channel_cbs = [QComboBox() for i in range(self.n_channels)]
|
|
69
|
+
|
|
70
|
+
self.parent_window.load_available_tables()
|
|
71
|
+
available_channels = list(self.parent_window.signals)+['None']
|
|
72
|
+
# Populate the comboboxes with available channels from the experiment
|
|
73
|
+
for k in range(self.n_channels):
|
|
74
|
+
hbox_channel = QHBoxLayout()
|
|
75
|
+
hbox_channel.addWidget(QLabel(f'channel {k+1}: '), 33)
|
|
76
|
+
|
|
77
|
+
ch_vbox = QVBoxLayout()
|
|
78
|
+
ch_vbox.addWidget(QLabel(f'Req: {self.required_channels[k]}'), alignment=Qt.AlignLeft)
|
|
79
|
+
ch_vbox.addWidget(self.channel_cbs[k])
|
|
80
|
+
|
|
81
|
+
self.channel_cbs[k].addItems(available_channels) #Give none option for more than one channel input
|
|
82
|
+
idx = self.channel_cbs[k].findText(self.required_channels[k])
|
|
83
|
+
|
|
84
|
+
if idx>=0:
|
|
85
|
+
self.channel_cbs[k].setCurrentIndex(idx)
|
|
86
|
+
else:
|
|
87
|
+
self.channel_cbs[k].setCurrentIndex(len(available_channels)-1)
|
|
88
|
+
|
|
89
|
+
hbox_channel.addLayout(ch_vbox, 66)
|
|
90
|
+
self.layout.addLayout(hbox_channel)
|
|
91
|
+
|
|
92
|
+
# Button to apply the StarDist settings
|
|
93
|
+
self.set_btn = QPushButton('set')
|
|
94
|
+
self.set_btn.setStyleSheet(self.button_style_sheet)
|
|
95
|
+
self.set_btn.clicked.connect(self.parent_window.set_selected_signals_for_event_detection)
|
|
96
|
+
self.layout.addWidget(self.set_btn)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class SegModelParamsWidget(CelldetectiveWidget):
|
|
101
|
+
|
|
102
|
+
def __init__(self, parent_window=None, model_name='SD_versatile_fluo', *args, **kwargs):
|
|
103
|
+
|
|
104
|
+
super().__init__(*args)
|
|
105
|
+
self.setWindowTitle('Channels')
|
|
106
|
+
self.parent_window = parent_window
|
|
107
|
+
self.model_name = model_name
|
|
108
|
+
self.locate_model_path()
|
|
109
|
+
self.required_channels = self.input_config["channels"]
|
|
110
|
+
self.onlyFloat = QDoubleValidator()
|
|
111
|
+
|
|
112
|
+
# Setting up references to parent window attributes
|
|
113
|
+
if hasattr(self.parent_window.parent_window, 'locate_image'):
|
|
114
|
+
self.attr_parent = self.parent_window.parent_window
|
|
115
|
+
elif hasattr(self.parent_window.parent_window.parent_window, 'locate_image'):
|
|
116
|
+
self.attr_parent = self.parent_window.parent_window.parent_window
|
|
117
|
+
else:
|
|
118
|
+
self.attr_parent = self.parent_window.parent_window.parent_window.parent_window
|
|
119
|
+
|
|
120
|
+
# Set up layout and widgets
|
|
121
|
+
self.layout = QVBoxLayout()
|
|
122
|
+
self.populate_widgets()
|
|
123
|
+
self.setLayout(self.layout)
|
|
124
|
+
center_window(self)
|
|
125
|
+
|
|
126
|
+
def locate_model_path(self):
|
|
127
|
+
|
|
128
|
+
self.model_complete_path = locate_segmentation_model(self.model_name)
|
|
129
|
+
if self.model_complete_path is None:
|
|
130
|
+
print('Model could not be found. Abort.')
|
|
131
|
+
self.abort_process()
|
|
132
|
+
else:
|
|
133
|
+
print(f'Model path: {self.model_complete_path}...')
|
|
134
|
+
|
|
135
|
+
if not os.path.exists(self.model_complete_path+"config_input.json"):
|
|
136
|
+
print('The configuration for the inputs to the model could not be located. Abort.')
|
|
137
|
+
self.abort_process()
|
|
138
|
+
|
|
139
|
+
with open(self.model_complete_path+"config_input.json") as config_file:
|
|
140
|
+
self.input_config = json.load(config_file)
|
|
141
|
+
|
|
142
|
+
def populate_widgets(self):
|
|
143
|
+
|
|
144
|
+
self.n_channels = len(self.required_channels)
|
|
145
|
+
self.channel_cbs = [QComboBox() for i in range(self.n_channels)]
|
|
146
|
+
|
|
147
|
+
# Button to view the current stack with a scale bar
|
|
148
|
+
self.view_diameter_btn = QPushButton()
|
|
149
|
+
self.view_diameter_btn.setStyleSheet(self.button_select_all)
|
|
150
|
+
self.view_diameter_btn.setIcon(icon(MDI6.image_check, color="black"))
|
|
151
|
+
self.view_diameter_btn.setToolTip("View stack.")
|
|
152
|
+
self.view_diameter_btn.setIconSize(QSize(20, 20))
|
|
153
|
+
self.view_diameter_btn.clicked.connect(self.view_current_stack_with_scale_bar)
|
|
154
|
+
|
|
155
|
+
# Line edit for entering cell diameter
|
|
156
|
+
self.diameter_le = ThresholdLineEdit(init_value=40, connected_buttons=[self.view_diameter_btn],placeholder='cell diameter in µm', value_type='float')
|
|
157
|
+
|
|
158
|
+
available_channels = list(self.attr_parent.exp_channels)+['None']
|
|
159
|
+
# Populate the comboboxes with available channels from the experiment
|
|
160
|
+
for k in range(self.n_channels):
|
|
161
|
+
hbox_channel = QHBoxLayout()
|
|
162
|
+
hbox_channel.addWidget(QLabel(f'channel {k+1}: '), 33)
|
|
163
|
+
|
|
164
|
+
ch_vbox = QVBoxLayout()
|
|
165
|
+
ch_vbox.addWidget(QLabel(f'Req: {self.required_channels[k]}'), alignment=Qt.AlignLeft)
|
|
166
|
+
ch_vbox.addWidget(self.channel_cbs[k])
|
|
167
|
+
|
|
168
|
+
self.channel_cbs[k].addItems(available_channels) #Give none option for more than one channel input
|
|
169
|
+
idx = self.channel_cbs[k].findText(self.required_channels[k])
|
|
170
|
+
|
|
171
|
+
if idx>=0:
|
|
172
|
+
self.channel_cbs[k].setCurrentIndex(idx)
|
|
173
|
+
else:
|
|
174
|
+
self.channel_cbs[k].setCurrentIndex(len(available_channels)-1)
|
|
175
|
+
|
|
176
|
+
hbox_channel.addLayout(ch_vbox, 66)
|
|
177
|
+
self.layout.addLayout(hbox_channel)
|
|
178
|
+
|
|
179
|
+
if 'cell_size_um' in self.input_config:
|
|
180
|
+
|
|
181
|
+
# Layout for diameter input and button
|
|
182
|
+
hbox = QHBoxLayout()
|
|
183
|
+
hbox.addWidget(QLabel('cell size [µm]: '), 33)
|
|
184
|
+
hbox.addWidget(self.diameter_le, 61)
|
|
185
|
+
hbox.addWidget(self.view_diameter_btn)
|
|
186
|
+
self.layout.addLayout(hbox)
|
|
187
|
+
|
|
188
|
+
self.diameter_le.set_threshold(self.input_config['cell_size_um'])
|
|
189
|
+
|
|
190
|
+
# size_hbox = QHBoxLayout()
|
|
191
|
+
# size_hbox.addWidget(QLabel('cell size [µm]: '), 33)
|
|
192
|
+
# self.size_le = QLineEdit(str(self.input_config['cell_size_um']).replace('.',','))
|
|
193
|
+
# self.size_le.setValidator(self.onlyFloat)
|
|
194
|
+
# size_hbox.addWidget(self.size_le, 66)
|
|
195
|
+
# self.layout.addLayout(size_hbox)
|
|
196
|
+
|
|
197
|
+
# Button to apply the StarDist settings
|
|
198
|
+
self.set_btn = QPushButton('set')
|
|
199
|
+
self.set_btn.setStyleSheet(self.button_style_sheet)
|
|
200
|
+
self.set_btn.clicked.connect(self.parent_window.set_selected_channels_for_segmentation)
|
|
201
|
+
self.layout.addWidget(self.set_btn)
|
|
202
|
+
|
|
203
|
+
def view_current_stack_with_scale_bar(self):
|
|
204
|
+
|
|
205
|
+
"""
|
|
206
|
+
Displays the current image stack with a scale bar, allowing users to visually estimate cell diameters.
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
self.attr_parent.locate_image()
|
|
210
|
+
if self.attr_parent.current_stack is not None:
|
|
211
|
+
max_size = np.amax([self.attr_parent.shape_x, self.attr_parent.shape_y])
|
|
212
|
+
self.viewer = CellSizeViewer(
|
|
213
|
+
initial_diameter = float(self.diameter_le.text().replace(',', '.')),
|
|
214
|
+
parent_le = self.diameter_le,
|
|
215
|
+
stack_path=self.attr_parent.current_stack,
|
|
216
|
+
window_title=f'Position {self.attr_parent.position_list.currentText()}',
|
|
217
|
+
diameter_slider_range=(0,max_size*self.attr_parent.PxToUm),
|
|
218
|
+
frame_slider = True,
|
|
219
|
+
contrast_slider = True,
|
|
220
|
+
channel_cb = True,
|
|
221
|
+
channel_names = self.attr_parent.exp_channels,
|
|
222
|
+
n_channels = self.attr_parent.nbr_channels,
|
|
223
|
+
PxToUm = self.attr_parent.PxToUm,
|
|
224
|
+
)
|
|
225
|
+
self.viewer.show()
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class StarDistParamsWidget(CelldetectiveWidget):
|
|
21
229
|
|
|
22
230
|
"""
|
|
23
231
|
A widget to configure parameters for StarDist segmentation.
|
|
@@ -101,7 +309,7 @@ class StarDistParamsWidget(QWidget, Styles):
|
|
|
101
309
|
self.layout.addWidget(self.set_stardist_scale_btn)
|
|
102
310
|
|
|
103
311
|
|
|
104
|
-
class CellposeParamsWidget(
|
|
312
|
+
class CellposeParamsWidget(CelldetectiveWidget):
|
|
105
313
|
|
|
106
314
|
"""
|
|
107
315
|
A widget to configure parameters for Cellpose segmentation, allowing users to set the cell diameter,
|
|
@@ -204,7 +412,7 @@ class CellposeParamsWidget(QWidget, Styles):
|
|
|
204
412
|
|
|
205
413
|
# Flow threshold slider
|
|
206
414
|
self.flow_slider = QLabeledDoubleSlider()
|
|
207
|
-
self.flow_slider.setOrientation(
|
|
415
|
+
self.flow_slider.setOrientation(Qt.Horizontal)
|
|
208
416
|
self.flow_slider.setRange(-6,6)
|
|
209
417
|
self.flow_slider.setValue(0.4)
|
|
210
418
|
hbox = QHBoxLayout()
|
|
@@ -214,7 +422,7 @@ class CellposeParamsWidget(QWidget, Styles):
|
|
|
214
422
|
|
|
215
423
|
# Cell probability threshold slider
|
|
216
424
|
self.cellprob_slider = QLabeledDoubleSlider()
|
|
217
|
-
self.cellprob_slider.setOrientation(
|
|
425
|
+
self.cellprob_slider.setOrientation(Qt.Horizontal)
|
|
218
426
|
self.cellprob_slider.setRange(-6,6)
|
|
219
427
|
self.cellprob_slider.setValue(0.)
|
|
220
428
|
hbox = QHBoxLayout()
|
|
@@ -236,18 +444,20 @@ class CellposeParamsWidget(QWidget, Styles):
|
|
|
236
444
|
|
|
237
445
|
self.attr_parent.locate_image()
|
|
238
446
|
if self.attr_parent.current_stack is not None:
|
|
447
|
+
max_size = np.amax([self.attr_parent.shape_x, self.attr_parent.shape_y])
|
|
239
448
|
self.viewer = CellSizeViewer(
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
449
|
+
initial_diameter = float(self.diameter_le.text().replace(',', '.')),
|
|
450
|
+
parent_le = self.diameter_le,
|
|
451
|
+
stack_path=self.attr_parent.current_stack,
|
|
452
|
+
window_title=f'Position {self.attr_parent.position_list.currentText()}',
|
|
453
|
+
diameter_slider_range=(0, max_size),
|
|
454
|
+
frame_slider = True,
|
|
455
|
+
contrast_slider = True,
|
|
456
|
+
channel_cb = True,
|
|
457
|
+
channel_names = self.attr_parent.exp_channels,
|
|
458
|
+
n_channels = self.attr_parent.nbr_channels,
|
|
459
|
+
PxToUm = 1,
|
|
460
|
+
)
|
|
251
461
|
self.viewer.show()
|
|
252
462
|
|
|
253
463
|
class ChannelNormGenerator(QVBoxLayout, Styles):
|
|
@@ -672,7 +882,7 @@ class BackgroundFitCorrectionLayout(QGridLayout, Styles):
|
|
|
672
882
|
else:
|
|
673
883
|
clip = False
|
|
674
884
|
|
|
675
|
-
corrected_stack = correct_background_model(self.attr_parent.exp_dir,
|
|
885
|
+
corrected_stack = correct_background_model(self.attr_parent.exp_dir,
|
|
676
886
|
well_option=self.attr_parent.well_list.getSelectedIndices(), #+1 ??
|
|
677
887
|
position_option=self.attr_parent.position_list.getSelectedIndices(), #+1??
|
|
678
888
|
target_channel=self.channels_cb.currentText(),
|
|
@@ -687,14 +897,18 @@ class BackgroundFitCorrectionLayout(QGridLayout, Styles):
|
|
|
687
897
|
show_progress_per_pos = False,
|
|
688
898
|
)
|
|
689
899
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
900
|
+
if corrected_stack:
|
|
901
|
+
self.viewer = StackVisualizer(
|
|
902
|
+
stack=corrected_stack[0],
|
|
903
|
+
window_title='Corrected channel',
|
|
904
|
+
target_channel=self.channels_cb.currentIndex(),
|
|
905
|
+
frame_slider = True,
|
|
906
|
+
contrast_slider = True
|
|
907
|
+
)
|
|
908
|
+
self.viewer.show()
|
|
909
|
+
else:
|
|
910
|
+
print("Corrected stack could not be generated... No stack available...")
|
|
911
|
+
|
|
698
912
|
|
|
699
913
|
|
|
700
914
|
class LocalCorrectionLayout(BackgroundFitCorrectionLayout):
|
|
@@ -864,7 +1078,7 @@ class ProtocolDesignerLayout(QVBoxLayout, Styles):
|
|
|
864
1078
|
self.tabs.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
|
865
1079
|
|
|
866
1080
|
for k in range(len(self.tab_layouts)):
|
|
867
|
-
wg =
|
|
1081
|
+
wg = CelldetectiveWidget()
|
|
868
1082
|
self.tab_layouts[k].parent_window = self
|
|
869
1083
|
wg.setLayout(self.tab_layouts[k])
|
|
870
1084
|
self.tabs.addTab(wg, self.tab_names[k])
|
|
@@ -1120,6 +1334,8 @@ class BackgroundModelFreeCorrectionLayout(QGridLayout, Styles):
|
|
|
1120
1334
|
for c in self.coef_widgets:
|
|
1121
1335
|
c.setEnabled(False)
|
|
1122
1336
|
|
|
1337
|
+
self.interpolate_check = QCheckBox("interpolate NaNs")
|
|
1338
|
+
|
|
1123
1339
|
def add_to_layout(self):
|
|
1124
1340
|
|
|
1125
1341
|
channel_layout = QHBoxLayout()
|
|
@@ -1173,13 +1389,23 @@ class BackgroundModelFreeCorrectionLayout(QGridLayout, Styles):
|
|
|
1173
1389
|
coef_nbr_layout.addWidget(self.nbr_coef_le, 75)
|
|
1174
1390
|
self.addLayout(coef_nbr_layout, 7,0,1,3)
|
|
1175
1391
|
|
|
1392
|
+
offset_layout = QHBoxLayout()
|
|
1393
|
+
offset_layout.addWidget(QLabel("Offset: "), 25)
|
|
1394
|
+
self.camera_offset_le = QLineEdit("0")
|
|
1395
|
+
self.camera_offset_le.setPlaceholderText('camera black level')
|
|
1396
|
+
self.camera_offset_le.setValidator(QDoubleValidator())
|
|
1397
|
+
offset_layout.addWidget(self.camera_offset_le, 75)
|
|
1398
|
+
self.addLayout(offset_layout, 8, 0, 1, 3)
|
|
1399
|
+
|
|
1176
1400
|
self.operation_layout = OperationLayout()
|
|
1177
|
-
self.addLayout(self.operation_layout,
|
|
1401
|
+
self.addLayout(self.operation_layout, 9, 0, 1, 3)
|
|
1402
|
+
|
|
1403
|
+
self.addWidget(self.interpolate_check, 10, 0, 1, 1)
|
|
1178
1404
|
|
|
1179
1405
|
correction_layout = QHBoxLayout()
|
|
1180
1406
|
correction_layout.addWidget(self.add_correction_btn, 95)
|
|
1181
1407
|
correction_layout.addWidget(self.corrected_stack_viewer_btn, 5)
|
|
1182
|
-
self.addLayout(correction_layout,
|
|
1408
|
+
self.addLayout(correction_layout, 11, 0, 1, 3)
|
|
1183
1409
|
|
|
1184
1410
|
# verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
|
1185
1411
|
# self.addItem(verticalSpacer, 5, 0, 1, 3)
|
|
@@ -1221,6 +1447,11 @@ class BackgroundModelFreeCorrectionLayout(QGridLayout, Styles):
|
|
|
1221
1447
|
clip = True
|
|
1222
1448
|
else:
|
|
1223
1449
|
clip = False
|
|
1450
|
+
|
|
1451
|
+
if self.camera_offset_le.text()=="":
|
|
1452
|
+
offset = None
|
|
1453
|
+
else:
|
|
1454
|
+
offset = float(self.camera_offset_le.text().replace(",","."))
|
|
1224
1455
|
|
|
1225
1456
|
self.instructions = {
|
|
1226
1457
|
"target_channel": self.channels_cb.currentText(),
|
|
@@ -1232,7 +1463,9 @@ class BackgroundModelFreeCorrectionLayout(QGridLayout, Styles):
|
|
|
1232
1463
|
"opt_coef_range": opt_coef_range,
|
|
1233
1464
|
"opt_coef_nbr": opt_coef_nbr,
|
|
1234
1465
|
"operation": operation,
|
|
1235
|
-
"clip": clip
|
|
1466
|
+
"clip": clip,
|
|
1467
|
+
"offset": offset,
|
|
1468
|
+
"fix_nan": self.interpolate_check.isChecked(),
|
|
1236
1469
|
}
|
|
1237
1470
|
|
|
1238
1471
|
def set_target_channel(self):
|
|
@@ -1308,6 +1541,7 @@ class BackgroundModelFreeCorrectionLayout(QGridLayout, Styles):
|
|
|
1308
1541
|
clip = clip,
|
|
1309
1542
|
export= False,
|
|
1310
1543
|
return_stacks=True,
|
|
1544
|
+
fix_nan=self.interpolate_check.isChecked(),
|
|
1311
1545
|
show_progress_per_well = True,
|
|
1312
1546
|
show_progress_per_pos = False,
|
|
1313
1547
|
)
|