cellects 0.1.0.dev1__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.
Files changed (46) hide show
  1. cellects/__init__.py +0 -0
  2. cellects/__main__.py +49 -0
  3. cellects/config/__init__.py +0 -0
  4. cellects/config/all_vars_dict.py +154 -0
  5. cellects/core/__init__.py +0 -0
  6. cellects/core/cellects_paths.py +30 -0
  7. cellects/core/cellects_threads.py +1464 -0
  8. cellects/core/motion_analysis.py +1931 -0
  9. cellects/core/one_image_analysis.py +1065 -0
  10. cellects/core/one_video_per_blob.py +679 -0
  11. cellects/core/program_organizer.py +1347 -0
  12. cellects/core/script_based_run.py +154 -0
  13. cellects/gui/__init__.py +0 -0
  14. cellects/gui/advanced_parameters.py +1258 -0
  15. cellects/gui/cellects.py +189 -0
  16. cellects/gui/custom_widgets.py +789 -0
  17. cellects/gui/first_window.py +449 -0
  18. cellects/gui/if_several_folders_window.py +239 -0
  19. cellects/gui/image_analysis_window.py +1909 -0
  20. cellects/gui/required_output.py +232 -0
  21. cellects/gui/video_analysis_window.py +656 -0
  22. cellects/icons/__init__.py +0 -0
  23. cellects/icons/cellects_icon.icns +0 -0
  24. cellects/icons/cellects_icon.ico +0 -0
  25. cellects/image_analysis/__init__.py +0 -0
  26. cellects/image_analysis/cell_leaving_detection.py +54 -0
  27. cellects/image_analysis/cluster_flux_study.py +102 -0
  28. cellects/image_analysis/extract_exif.py +61 -0
  29. cellects/image_analysis/fractal_analysis.py +184 -0
  30. cellects/image_analysis/fractal_functions.py +108 -0
  31. cellects/image_analysis/image_segmentation.py +272 -0
  32. cellects/image_analysis/morphological_operations.py +867 -0
  33. cellects/image_analysis/network_functions.py +1244 -0
  34. cellects/image_analysis/one_image_analysis_threads.py +289 -0
  35. cellects/image_analysis/progressively_add_distant_shapes.py +246 -0
  36. cellects/image_analysis/shape_descriptors.py +981 -0
  37. cellects/utils/__init__.py +0 -0
  38. cellects/utils/formulas.py +881 -0
  39. cellects/utils/load_display_save.py +1016 -0
  40. cellects/utils/utilitarian.py +516 -0
  41. cellects-0.1.0.dev1.dist-info/LICENSE.odt +0 -0
  42. cellects-0.1.0.dev1.dist-info/METADATA +131 -0
  43. cellects-0.1.0.dev1.dist-info/RECORD +46 -0
  44. cellects-0.1.0.dev1.dist-info/WHEEL +5 -0
  45. cellects-0.1.0.dev1.dist-info/entry_points.txt +2 -0
  46. cellects-0.1.0.dev1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1258 @@
1
+ #!/usr/bin/env python3
2
+ """This module creates the Advanced Parameters window of the user interface of Cellects
3
+ This windows contains most parameters
4
+ """
5
+
6
+
7
+ import logging
8
+ import os
9
+ from copy import deepcopy
10
+ from pathlib import Path
11
+
12
+ from PySide6 import QtWidgets, QtCore
13
+ import numpy as np
14
+ from cellects.config.all_vars_dict import DefaultDicts
15
+ from cellects.core.cellects_paths import CELLECTS_DIR, CONFIG_DIR
16
+ from cellects.gui.custom_widgets import (
17
+ WindowType, PButton, Spinbox, Combobox, Checkbox, FixedText)
18
+
19
+
20
+ class AdvancedParameters(WindowType):
21
+ """
22
+ This class creates the Advanced Parameters window.
23
+ In the app, it is accessible from the first and the Video tracking window. It allows the user to fill in
24
+ some parameters stored in the directory po.all (in RAM) and in all_vars.pkl (in ROM).
25
+ Clicking "Ok" save the directory in RAM and in ROM.
26
+ """
27
+ def __init__(self, parent, night_mode):
28
+ super().__init__(parent, night_mode)
29
+
30
+ logging.info("Initialize AdvancedParameters window")
31
+ self.setParent(parent)
32
+ try:
33
+ self.true_init()
34
+ except KeyError:
35
+ default_dicts = DefaultDicts()
36
+ self.parent().po.all = default_dicts.all
37
+ self.parent().po.vars = default_dicts.vars
38
+ self.true_init()
39
+
40
+ def true_init(self):
41
+ self.layout = QtWidgets.QVBoxLayout()
42
+
43
+ self.left_scroll_table = QtWidgets.QScrollArea() # QTableWidget() # Scroll Area which contains the widgets, set as the centralWidget
44
+ self.left_scroll_table.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
45
+ self.left_scroll_table.setMinimumHeight(150)#self.parent().im_max_height - 100
46
+ self.left_scroll_table.setFrameShape(QtWidgets.QFrame.NoFrame)
47
+ self.left_scroll_table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
48
+ self.left_scroll_table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
49
+
50
+ self.left_col_layout = QtWidgets.QVBoxLayout()
51
+ self.right_col_layout = QtWidgets.QVBoxLayout()
52
+ self.left_col_widget = QtWidgets.QWidget()
53
+ self.right_col_widget = QtWidgets.QWidget()
54
+ # curr_row_1st_col = 0
55
+ ncol = 11
56
+ # Create the main Title
57
+ self.title = FixedText('Advanced parameters', police=30, night_mode=self.parent().po.all['night_mode'])
58
+ self.title.setAlignment(QtCore.Qt.AlignHCenter)
59
+ # Create the main layout
60
+ self.layout.addWidget(self.title)
61
+ # self.layout.addItem(self.vertical_space)
62
+ # self.layout.addWidget(self.title, curr_row_1st_col, 0, 2, ncol)
63
+ # curr_row_1st_col += 2
64
+ # horzspaceItem = QtWidgets.QSpacerItem(1, 1, QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.MinimumExpanding)
65
+ # self.layout.addItem(horzspaceItem, 2, 0, 1, 5)
66
+ # curr_row_1st_col += 1
67
+ # Create the stylesheet for the boxes allowing to categorize advanced parameters.
68
+ boxstylesheet = \
69
+ ".QWidget {\n" \
70
+ + "border: 1px solid black;\n" \
71
+ + "border-radius: 20px;\n" \
72
+ + "}"
73
+
74
+
75
+ # I/ First box: General parameters
76
+ # I/A/ Title
77
+ self.general_param_box_label = FixedText('General parameters:', tip="",
78
+ night_mode=self.parent().po.all['night_mode'])
79
+ self.left_col_layout.addWidget(self.general_param_box_label)
80
+ # self.layout.addWidget(self.general_param_box_label, curr_row_1st_col, 1)
81
+ # curr_row_1st_col += 1
82
+ # I/B/ Create the box
83
+ self.general_param_box_layout = QtWidgets.QGridLayout()
84
+ self.general_param_box_widget = QtWidgets.QWidget()
85
+ self.general_param_box_widget.setStyleSheet(boxstylesheet)
86
+ # I/C/ Create widgets
87
+ self.automatically_crop = Checkbox(self.parent().po.all['automatically_crop'])
88
+ self.automatically_crop_label = FixedText('Automatically crop images', tip="If more than one cell shape are (or may appear) in each arena", night_mode=self.parent().po.all['night_mode'])
89
+
90
+ self.subtract_background = Checkbox(self.parent().po.vars['subtract_background'])
91
+ self.subtract_background.stateChanged.connect(self.subtract_background_check)
92
+ self.subtract_background_label = FixedText('Subtract background', tip="Apply an algorithm allowing to remove a potential brightness gradient from images during analysis", night_mode=self.parent().po.all['night_mode'])
93
+
94
+ self.keep_cell_and_back_for_all_folders = Checkbox(self.parent().po.all['keep_cell_and_back_for_all_folders'])
95
+ self.keep_cell_and_back_for_all_folders_label = FixedText('Keep Cell and Back drawings for all folders',
96
+ tip="During the first image analysis, if the user drew cell and back to help detection\n- Keep this information for all folders (if checked)\n- Only use this information for the current folder (if unchecked)",
97
+ night_mode=self.parent().po.all['night_mode'])
98
+
99
+ self.correct_errors_around_initial = Checkbox(self.parent().po.vars['correct_errors_around_initial'])
100
+ self.correct_errors_around_initial_label = FixedText('Correct errors around initial shape',
101
+ tip="Apply an algorithm allowing to correct some failure around the initial shape\nThese errors are most likely due to color variations\n themselves due to substrate width differences crossed by light\naround initial cell lying on an opaque substrate",
102
+ night_mode=self.parent().po.all['night_mode'])
103
+
104
+ self.prevent_fast_growth_near_periphery = Checkbox(self.parent().po.vars['prevent_fast_growth_near_periphery'])
105
+ self.prevent_fast_growth_near_periphery_label = FixedText('Prevent fast growth near periphery',
106
+ tip="During video analysis, the borders of the arena may create wrong detection\n- Remove the detection of the specimen(s) that move too fast near periphery (if checked)\n- Do not change the detection (if unchecked)",
107
+ night_mode=self.parent().po.all['night_mode'])
108
+
109
+ self.prevent_fast_growth_near_periphery.stateChanged.connect(self.prevent_fast_growth_near_periphery_check)
110
+ self.periphery_width = Spinbox(min=1, max=1000, val=self.parent().po.vars['periphery_width'],
111
+ decimals=0, night_mode=self.parent().po.all['night_mode'])
112
+ self.periphery_width_label = FixedText('Periphery width',
113
+ tip="The width, in pixels, of the arena s border designated as the peripheral region",
114
+ night_mode=self.parent().po.all['night_mode'])
115
+ self.max_periphery_growth = Spinbox(min=1, max=1000000, val=self.parent().po.vars['max_periphery_growth'],
116
+ decimals=0, night_mode=self.parent().po.all['night_mode'])
117
+ self.max_periphery_growth_label = FixedText('Max periphery growth',
118
+ tip="The maximum detectable size (in pixels) of a shape in a single frame near the periphery of the arena.\nLarger shapes will be considered as noise.",
119
+ night_mode=self.parent().po.all['night_mode'])
120
+ self.prevent_fast_growth_near_periphery_check()
121
+
122
+
123
+ # I/D/ Arrange widgets in the box
124
+ self.general_param_box_layout.addWidget(self.automatically_crop, 0, 0)
125
+ self.general_param_box_layout.addWidget(self.automatically_crop_label, 0, 1)
126
+ self.general_param_box_layout.addWidget(self.subtract_background, 1, 0)
127
+ self.general_param_box_layout.addWidget(self.subtract_background_label, 1, 1)
128
+ self.general_param_box_layout.addWidget(self.keep_cell_and_back_for_all_folders, 2, 0)
129
+ self.general_param_box_layout.addWidget(self.keep_cell_and_back_for_all_folders_label, 2, 1)
130
+ self.general_param_box_layout.addWidget(self.correct_errors_around_initial, 3, 0)
131
+ self.general_param_box_layout.addWidget(self.correct_errors_around_initial_label, 3, 1)
132
+ self.general_param_box_layout.addWidget(self.prevent_fast_growth_near_periphery, 4, 0)
133
+ self.general_param_box_layout.addWidget(self.prevent_fast_growth_near_periphery_label, 4, 1)
134
+ self.general_param_box_layout.addWidget(self.periphery_width, 5, 0)
135
+ self.general_param_box_layout.addWidget(self.periphery_width_label, 5, 1)
136
+ self.general_param_box_layout.addWidget(self.max_periphery_growth, 6, 0)
137
+ self.general_param_box_layout.addWidget(self.max_periphery_growth_label, 6, 1)
138
+ self.general_param_box_widget.setLayout(self.general_param_box_layout)
139
+ self.left_col_layout.addWidget(self.general_param_box_widget)
140
+ # self.layout.addWidget(self.general_param_box_widget, curr_row_1st_col, 1, 2, 2)
141
+ # curr_row_1st_col += 2
142
+
143
+ # II/ Second box: One cell/colony per arena
144
+ # II/A/ Title
145
+ self.one_per_arena_label = FixedText('One cell/colony per arena parameters:', tip="",
146
+ night_mode=self.parent().po.all['night_mode'])
147
+ self.left_col_layout.addWidget(self.one_per_arena_label)
148
+ # II/B/ Create the box
149
+ self.one_per_arena_box_layout = QtWidgets.QGridLayout()
150
+ self.one_per_arena_box_widget = QtWidgets.QWidget()
151
+ self.one_per_arena_box_widget.setStyleSheet(boxstylesheet)
152
+
153
+ # II/C/ Create widgets
154
+ self.all_specimens_have_same_direction = Checkbox(self.parent().po.all['all_specimens_have_same_direction'])
155
+ # self.all_specimens_have_same_direction.stateChanged.connect(self.all_specimens_have_same_direction_changed)
156
+ self.all_specimens_have_same_direction_label = FixedText('All specimens have the same direction',
157
+ tip="This parameter only affects the slow algorithm of automatic arena detection.\nChecking it will improve the chances to correctly detect arenas when\n all cells move in the same direction",
158
+ night_mode=self.parent().po.all['night_mode'])
159
+
160
+
161
+ connect_distant_shape = self.parent().po.all['connect_distant_shape_during_segmentation']
162
+ self.connect_distant_shape_during_segmentation = Checkbox(connect_distant_shape)
163
+ self.connect_distant_shape_during_segmentation.stateChanged.connect(self.do_distant_shape_int_changed)
164
+ self.connect_distant_shape_label = FixedText('Connect distant shapes',
165
+ tip="Allows a homemade algorithm allowing to\nprogressively (i.e. at the growth rate speed of neighboring pixels)\nconnect distant shapes to original shape(s)\nWarning: this option can drastically increase the duration of the analysis",
166
+ night_mode=self.parent().po.all['night_mode'])
167
+ self.detection_range_factor = Spinbox(min=0, max=1000000,
168
+ val=self.parent().po.vars['detection_range_factor'],
169
+ night_mode=self.parent().po.all['night_mode'])
170
+ self.detection_range_factor_label = FixedText('Detection range factor:',
171
+ tip="From 1 to 10, increase the allowed distance from original shape(s) to connect distant shapes",
172
+ night_mode=self.parent().po.all['night_mode'])
173
+
174
+ # Connect distant shape algo:
175
+ do_use_max_size = self.parent().po.vars['max_size_for_connection'] is not None and connect_distant_shape
176
+ do_use_min_size = self.parent().po.vars['min_size_for_connection'] is not None and connect_distant_shape
177
+ self.use_max_size = Checkbox(do_use_max_size, night_mode=self.parent().po.all['night_mode'])
178
+ self.use_min_size = Checkbox(do_use_min_size, night_mode=self.parent().po.all['night_mode'])
179
+ self.use_max_size.stateChanged.connect(self.use_max_size_changed)
180
+ self.use_min_size.stateChanged.connect(self.use_min_size_changed)
181
+
182
+ self.use_max_size_label = FixedText('Use max size as a threshold',
183
+ tip="To decide whether distant shapes should get connected",
184
+ night_mode=self.parent().po.all['night_mode'])
185
+ self.use_min_size_label = FixedText('Use min size as a threshold',
186
+ tip="To decide whether distant shapes should get connected",
187
+ night_mode=self.parent().po.all['night_mode'])
188
+ self.max_size_for_connection_label = FixedText('Max (pixels):', night_mode=self.parent().po.all['night_mode'])
189
+ self.min_size_for_connection_label = FixedText('Min (pixels):', night_mode=self.parent().po.all['night_mode'])
190
+ if do_use_max_size:
191
+ self.max_size_for_connection = Spinbox(min=0, max=1000000,
192
+ val=self.parent().po.vars['max_size_for_connection'],
193
+ night_mode=self.parent().po.all['night_mode'])
194
+ else:
195
+ self.max_size_for_connection = Spinbox(min=0, max=1000000, val=50,
196
+ night_mode=self.parent().po.all['night_mode'])
197
+ if do_use_min_size:
198
+ self.min_size_for_connection = Spinbox(min=0, max=1000000,
199
+ val=self.parent().po.vars['min_size_for_connection'],
200
+ night_mode=self.parent().po.all['night_mode'])
201
+ else:
202
+ self.min_size_for_connection = Spinbox(min=0, max=1000000, val=0,
203
+ night_mode=self.parent().po.all['night_mode'])
204
+ # set things visible or invisible:
205
+ # self.detection_range_factor.setVisible(connect_distant_shape)
206
+ # self.detection_range_factor_label.setVisible(connect_distant_shape)
207
+ # self.use_max_size.setVisible(connect_distant_shape)
208
+ # self.use_min_size.setVisible(connect_distant_shape)
209
+ # self.use_max_size_label.setVisible(connect_distant_shape)
210
+ # self.use_min_size_label.setVisible(connect_distant_shape)
211
+ #
212
+ # self.max_size_for_connection.setVisible(do_use_max_size)
213
+ # self.max_size_for_connection_label.setVisible(do_use_max_size)
214
+ # self.min_size_for_connection.setVisible(do_use_min_size)
215
+ # self.min_size_for_connection_label.setVisible(do_use_min_size)
216
+
217
+ self.use_min_size.setStyleSheet("margin-left:100%; margin-right:0%;")
218
+ self.min_size_for_connection_label.setAlignment(QtCore.Qt.AlignRight)
219
+ self.use_max_size.setStyleSheet("margin-left:100%; margin-right:0%;")
220
+ self.max_size_for_connection_label.setAlignment(QtCore.Qt.AlignRight)
221
+
222
+ # II/D/ Arrange widgets in the box
223
+ curr_box_row = 0
224
+ self.one_per_arena_box_layout.addWidget(self.connect_distant_shape_during_segmentation, curr_box_row, 0)
225
+ self.one_per_arena_box_layout.addWidget(self.connect_distant_shape_label, curr_box_row, 1)
226
+ curr_box_row += 1
227
+ self.one_per_arena_box_layout.addWidget(self.detection_range_factor, curr_box_row, 0)
228
+ self.one_per_arena_box_layout.addWidget(self.detection_range_factor_label, curr_box_row, 1)
229
+ curr_box_row += 1
230
+ self.one_per_arena_box_layout.addWidget(self.use_min_size, curr_box_row, 0)
231
+ self.one_per_arena_box_layout.addWidget(self.use_min_size_label, curr_box_row, 1)
232
+ curr_box_row += 1
233
+ self.one_per_arena_box_layout.addWidget(self.min_size_for_connection_label, curr_box_row, 0)
234
+ self.one_per_arena_box_layout.addWidget(self.min_size_for_connection, curr_box_row, 1)
235
+ curr_box_row += 1
236
+ self.one_per_arena_box_layout.addWidget(self.use_max_size, curr_box_row, 0)
237
+ self.one_per_arena_box_layout.addWidget(self.use_max_size_label, curr_box_row, 1)
238
+ curr_box_row += 1
239
+ self.one_per_arena_box_layout.addWidget(self.max_size_for_connection_label, curr_box_row, 0)
240
+ self.one_per_arena_box_layout.addWidget(self.max_size_for_connection, curr_box_row, 1)
241
+ curr_box_row += 1
242
+ self.one_per_arena_box_layout.addWidget(self.all_specimens_have_same_direction, curr_box_row, 0)
243
+ self.one_per_arena_box_layout.addWidget(self.all_specimens_have_same_direction_label, curr_box_row, 1)
244
+ curr_box_row += 1
245
+
246
+ self.one_per_arena_box_widget.setLayout(self.one_per_arena_box_layout)
247
+ self.left_col_layout.addWidget(self.one_per_arena_box_widget)
248
+ # self.layout.addWidget(self.one_per_arena_box_widget, curr_row_1st_col, 1, 3, 2)
249
+ # curr_row_1st_col += 2# curr_box_row
250
+
251
+ # III/ Third box: Appearing cell/colony
252
+ # III/A/ Title
253
+ self.appearing_cell_label = FixedText('Appearing cell/colony parameters:', tip="",
254
+ night_mode=self.parent().po.all['night_mode'])
255
+
256
+ self.left_col_layout.addWidget(self.appearing_cell_label)
257
+ # self.layout.addWidget(self.appearing_cell_label, curr_row_1st_col, 1)
258
+ # curr_row_1st_col += 1
259
+ # III/B/ Create the box
260
+ self.appearing_cell_box_layout = QtWidgets.QGridLayout()
261
+ self.appearing_cell_box_widget = QtWidgets.QWidget()
262
+ self.appearing_cell_box_widget.setStyleSheet(boxstylesheet)
263
+
264
+ # III/C/ Create widgets
265
+ self.first_move_threshold = Spinbox(min=0, max=1000000, val=self.parent().po.all['first_move_threshold_in_mm²'],
266
+ decimals=6, night_mode=self.parent().po.all['night_mode'])
267
+ self.first_move_threshold_label = FixedText('Minimal size to detect a cell/colony',
268
+ tip="In mm². All appearing cell/colony lesser than this value will be considered as noise",
269
+ night_mode=self.parent().po.all['night_mode'])
270
+ # self.first_move_threshold.setVisible(not self.parent().po.all['automatic_size_thresholding'])
271
+ # self.first_move_threshold_label.setVisible(not self.parent().po.all['automatic_size_thresholding'])
272
+ self.do_automatic_size_thresholding = Checkbox(self.parent().po.all['automatic_size_thresholding'])
273
+ self.do_automatic_size_thresholding_label = FixedText('Automatic size threshold for appearance/motion',
274
+ night_mode=self.parent().po.all['night_mode'])
275
+ self.do_automatic_size_thresholding.stateChanged.connect(self.do_automatic_size_thresholding_changed)
276
+ self.appearing_selection = Combobox(["largest", "most_central"], night_mode=self.parent().po.all['night_mode'])
277
+ self.appearing_selection_label = FixedText('Appearance detection method',
278
+ tip="When specimen(s) are invisible at the beginning of the experiment and appear progressively",
279
+ night_mode=self.parent().po.all['night_mode'])
280
+ self.appearing_selection.setCurrentText(self.parent().po.vars['appearance_detection_method'])
281
+ self.appearing_selection.setFixedWidth(190)
282
+
283
+ # III/D/ Arrange widgets in the box
284
+ curr_box_row = 0
285
+ self.appearing_cell_box_layout.addWidget(self.do_automatic_size_thresholding, curr_box_row, 0)
286
+ self.appearing_cell_box_layout.addWidget(self.do_automatic_size_thresholding_label, curr_box_row, 1)
287
+ curr_box_row += 1
288
+ self.appearing_cell_box_layout.addWidget(self.first_move_threshold, curr_box_row, 0)
289
+ self.appearing_cell_box_layout.addWidget(self.first_move_threshold_label, curr_box_row, 1)
290
+ curr_box_row += 1
291
+ self.appearing_cell_box_layout.addWidget(self.appearing_selection, curr_box_row, 0)
292
+ self.appearing_cell_box_layout.addWidget(self.appearing_selection_label, curr_box_row, 1)
293
+ curr_box_row += 1
294
+
295
+ self.appearing_cell_box_widget.setLayout(self.appearing_cell_box_layout)
296
+ self.left_col_layout.addWidget(self.appearing_cell_box_widget)
297
+ # self.layout.addWidget(self.appearing_cell_box_widget, curr_row_1st_col, 1, 2, 2)
298
+ # curr_row_1st_col += curr_box_row
299
+
300
+ # IV/ Fourth box: Oscillation period:#
301
+ # IV/A/ Title
302
+ self.oscillation_label = FixedText('Oscillatory parameters:', tip="",
303
+ night_mode=self.parent().po.all['night_mode'])
304
+ self.left_col_layout.addWidget(self.oscillation_label)
305
+
306
+ self.oscillation_period_layout = QtWidgets.QGridLayout()
307
+ self.oscillation_period_widget = QtWidgets.QWidget()
308
+ self.oscillation_period_widget.setStyleSheet(boxstylesheet)
309
+
310
+ self.oscillation_period = Spinbox(min=0, max=10000, val=self.parent().po.vars['expected_oscillation_period'], decimals=2,
311
+ night_mode=self.parent().po.all['night_mode'])
312
+ self.oscillation_period_label = FixedText('Expected oscillation period (min)',
313
+ tip="If one expect biotic oscillations to occur",
314
+ night_mode=self.parent().po.all['night_mode'])
315
+
316
+ self.minimal_oscillating_cluster_size = Spinbox(min=1, max=1000000000, decimals=0, val=self.parent().po.vars['minimal_oscillating_cluster_size'],
317
+ night_mode=self.parent().po.all['night_mode'])
318
+ self.minimal_oscillating_cluster_size_label = FixedText('Minimal oscillating cluster size',
319
+ tip="In pixels\nWhen analyzing oscillations within the detected specimen(s)\nCellects looks for clusters of pixels that oscillate synchronously\nThis parameter sets the minimal size (in pixels) of these clusters.",
320
+ night_mode=self.parent().po.all['night_mode'])
321
+
322
+ self.oscillation_period_layout.addWidget(self.oscillation_period, 0, 0)
323
+ self.oscillation_period_layout.addWidget(self.oscillation_period_label, 0, 1)
324
+ self.oscillation_period_layout.addWidget(self.minimal_oscillating_cluster_size, 1, 0)
325
+ self.oscillation_period_layout.addWidget(self.minimal_oscillating_cluster_size_label, 1, 1)
326
+
327
+ self.oscillation_period_widget.setLayout(self.oscillation_period_layout)
328
+ self.left_col_layout.addWidget(self.oscillation_period_widget)
329
+
330
+
331
+ # V/ Fifth box: Fractal parameters:#
332
+ # IV/A/ Title
333
+ # self.fractal_label = FixedText('Fractal parameters:', tip="",
334
+ # night_mode=self.parent().po.all['night_mode'])
335
+ # self.left_col_layout.addWidget(self.fractal_label)
336
+ #
337
+ # self.fractal_layout = QtWidgets.QGridLayout()
338
+ # self.fractal_widget = QtWidgets.QWidget()
339
+ # self.fractal_widget.setStyleSheet(boxstylesheet)
340
+ #
341
+ # self.fractal_box_side_threshold = Spinbox(min=0, max=100000, val=self.parent().po.vars['fractal_box_side_threshold'], decimals=0,
342
+ # night_mode=self.parent().po.all['night_mode'])
343
+ # self.fractal_box_side_threshold_label = FixedText('Fractal box side threshold',
344
+ # tip="Increase/decrease to adjust the minimal side length (pixels) of an image\nto compute the Minkowski dimension using the box counting method.",
345
+ # night_mode=self.parent().po.all['night_mode'])
346
+ # self.fractal_layout.addWidget(self.fractal_box_side_threshold, 3, 0)
347
+ # self.fractal_layout.addWidget(self.fractal_box_side_threshold_label, 3, 1)
348
+ # self.fractal_zoom_step = Spinbox(min=0, max=100000, val=self.parent().po.vars['fractal_zoom_step'], decimals=0,
349
+ # night_mode=self.parent().po.all['night_mode'])
350
+ # self.fractal_zoom_step_label = FixedText('Fractal zoom step',
351
+ # tip="When using the box counting method to compute the Minkowski dimension\nThe zoom step is the side length (pixels) difference between each zoom level.\nWhen set to 0, the default zoom step is all possible powers of two.",
352
+ # night_mode=self.parent().po.all['night_mode'])
353
+ # self.fractal_layout.addWidget(self.fractal_zoom_step, 4, 0)
354
+ # self.fractal_layout.addWidget(self.fractal_zoom_step_label, 4, 1)
355
+ #
356
+ # self.fractal_widget.setLayout(self.fractal_layout)
357
+ # self.left_col_layout.addWidget(self.fractal_widget)
358
+
359
+ # V/ Fifth box: Network detection parameters:#
360
+ # IV/A/ Title
361
+ self.network_label = FixedText('Network parameters:', tip="",
362
+ night_mode=self.parent().po.all['night_mode'])
363
+ self.left_col_layout.addWidget(self.network_label)
364
+
365
+ self.network_layout = QtWidgets.QGridLayout()
366
+ self.network_widget = QtWidgets.QWidget()
367
+ self.network_widget.setStyleSheet(boxstylesheet)
368
+
369
+
370
+ self.network_detection_threshold = Spinbox(min=0, max=255, val=self.parent().po.vars['network_detection_threshold'], decimals=0,
371
+ night_mode=self.parent().po.all['night_mode'])
372
+ self.network_detection_threshold_label = FixedText('Network detection threshold',
373
+ tip="To detect the network, Cellects segment small parts of the image using a sliding window.\nThis threshold is an intensity value [0, 255]\napplied to the sliding window to not consider homogeneous substes of the image\ni.e. This is the minimal variation in intensity to consider that some pixels are parts of the network.",
374
+ night_mode=self.parent().po.all['night_mode'])
375
+ # self.mesh_side_length = Spinbox(min=2, max=1000000, val=self.parent().po.vars['network_mesh_side_length'], decimals=0,
376
+ # night_mode=self.parent().po.all['night_mode'])
377
+ # self.mesh_side_length_label = FixedText('Mesh side length',
378
+ # tip="This is the side length (in pixels) of the sliding window used to detect the network.\nHigh values are faster but less precise.\nWhen too high, straight vertical or horizontal lines appear in the detected network.",
379
+ # night_mode=self.parent().po.all['night_mode'])
380
+ # self.mesh_step_length = Spinbox(min=1, max=100, val=self.parent().po.vars['network_mesh_step_length'], decimals=0,
381
+ # night_mode=self.parent().po.all['night_mode'])
382
+ # self.mesh_step_length_label = FixedText('Mesh step length',
383
+ # tip="This is the distance (in pixels) travelled by the sliding window\n(used to detect the network) at each stage.\nHigh values are faster but less precise.",
384
+ # night_mode=self.parent().po.all['night_mode'])
385
+
386
+ self.network_layout.addWidget(self.network_detection_threshold, 0, 0)
387
+ self.network_layout.addWidget(self.network_detection_threshold_label, 0, 1)
388
+ # self.network_layout.addWidget(self.mesh_side_length, 1, 0)
389
+ # self.network_layout.addWidget(self.mesh_side_length_label, 1, 1)
390
+ # self.network_layout.addWidget(self.mesh_step_length, 2, 0)
391
+ # self.network_layout.addWidget(self.mesh_step_length_label, 2, 1)
392
+
393
+ self.network_widget.setLayout(self.network_layout)
394
+ self.left_col_layout.addWidget(self.network_widget)
395
+
396
+
397
+ # self.layout.addWidget(self.oscillation_period_widget, curr_row_1st_col, 1)
398
+ # curr_row_1st_col + 1
399
+
400
+
401
+ # From here start the 2nd column of boxes in the advanced parameters window
402
+ # vertspaceItem = QtWidgets.QSpacerItem(1, 1, QtWidgets.QSizePolicy.MinimumExpanding,
403
+ # QtWidgets.QSizePolicy.Maximum)
404
+ # self.layout.addItem(vertspaceItem, 0, 3, 10, 1)
405
+ # curr_row_2nd_col = 3
406
+
407
+
408
+ # I/ First box: Scales
409
+ # I/A/ Title
410
+
411
+ self.right_scroll_table = QtWidgets.QScrollArea() # QTableWidget() # Scroll Area which contains the widgets, set as the centralWidget
412
+ self.right_scroll_table.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
413
+ self.right_scroll_table.setMinimumHeight(150)#self.parent().im_max_height - 100
414
+ self.right_scroll_table.setFrameShape(QtWidgets.QFrame.NoFrame)
415
+ self.right_scroll_table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
416
+ self.right_scroll_table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
417
+
418
+
419
+ self.scale_box_label = FixedText('Spatio-temporal scaling:', tip="",
420
+ night_mode=self.parent().po.all['night_mode'])
421
+ self.right_col_layout.addWidget(self.scale_box_label)
422
+ # self.layout.addWidget(self.scale_box_label, curr_row_2nd_col, 4)
423
+ # curr_row_2nd_col += 1
424
+ # I/B/ Create the box
425
+ self.scale_box_layout = QtWidgets.QGridLayout()
426
+ self.scale_box_widget = QtWidgets.QWidget()
427
+ self.scale_box_widget.setStyleSheet(boxstylesheet)
428
+ # I/C/ Create widgets
429
+
430
+ self.extract_time = Checkbox(self.parent().po.all['extract_time_interval'])
431
+ self.extract_time.clicked.connect(self.extract_time_is_clicked)
432
+
433
+ self.time_step = Spinbox(min=0, max=100000, val=self.parent().po.vars['time_step'], decimals=3,
434
+ night_mode=self.parent().po.all['night_mode'])
435
+ self.time_step.setFixedWidth(60)
436
+ if self.parent().po.all['extract_time_interval']:
437
+ self.time_step.setVisible(False)
438
+ self.time_step_label = FixedText('Automatically extract time interval between images',
439
+ tip="Uses the exif data of the images (if available), to extract these intervals\nOtherwise, default time interval is 1 min",
440
+ night_mode=self.parent().po.all['night_mode'])
441
+ else:
442
+ self.time_step_label = FixedText('Set the time interval between images',
443
+ tip="In minutes",
444
+ night_mode=self.parent().po.all['night_mode'])
445
+ # self.overwrite_cellects_data = Checkbox(self.parent().po.all['overwrite_cellects_data'],
446
+ # night_mode=self.parent().po.all['night_mode'])
447
+ # self.overwrite_cellects_data_label = FixedText('Do overwrite cellects data',
448
+ # tip="The file Data to run Cellects quickly.pkl allow to run\na complete analysis from the first and the video anaysis window",
449
+ # night_mode=self.parent().po.all['night_mode'])
450
+ self.pixels_to_mm = Checkbox(self.parent().po.vars['output_in_mm'])
451
+ self.pixels_to_mm_label = FixedText('Convert areas and distances from pixels to mm',
452
+ tip="Check if you want output variables to be in mm\nUncheck if you want output variables to be in pixels",
453
+ night_mode=self.parent().po.all['night_mode'])
454
+ # I/D/ Arrange widgets in the box
455
+ self.scale_box_layout.addWidget(self.extract_time, 0, 0)
456
+ self.scale_box_layout.addWidget(self.time_step_label, 0, 1)
457
+ self.scale_box_layout.addWidget(self.time_step, 0, 2)
458
+ # self.scale_box_layout.addWidget(self.overwrite_cellects_data, 1, 0)
459
+ # self.scale_box_layout.addWidget(self.overwrite_cellects_data_label, 1, 1)
460
+ self.scale_box_layout.addWidget(self.pixels_to_mm, 2, 0)
461
+ self.scale_box_layout.addWidget(self.pixels_to_mm_label, 2, 1)
462
+ self.scale_box_widget.setLayout(self.scale_box_layout)
463
+ self.right_col_layout.addWidget(self.scale_box_widget)
464
+ # self.layout.addWidget(self.scale_box_widget, curr_row_2nd_col, 4, 2, 2)
465
+ # curr_row_2nd_col += 3
466
+
467
+ # IV/ Fourth box: Computer resources
468
+ # IV/A/ Title
469
+ self.resources_label = FixedText('Computer resources:', tip="",
470
+ night_mode=self.parent().po.all['night_mode'])
471
+ self.right_col_layout.addWidget(self.resources_label)
472
+ # self.layout.addWidget(self.resources_label, curr_row_2nd_col, 4)
473
+ # curr_row_2nd_col += 1
474
+
475
+ # IV/B/ Create the box
476
+ self.resources_box_layout = QtWidgets.QGridLayout()
477
+ self.resources_box_widget = QtWidgets.QWidget()
478
+ self.resources_box_widget.setStyleSheet(boxstylesheet)
479
+
480
+ # IV/C/ Create widgets
481
+ self.do_multiprocessing = Checkbox(self.parent().po.all['do_multiprocessing'])
482
+ self.do_multiprocessing_label = FixedText('Run analysis in parallel', tip="Allow the use of more than one core of the computer processor", night_mode=self.parent().po.all['night_mode'])
483
+ self.do_multiprocessing.stateChanged.connect(self.do_multiprocessing_is_clicked)
484
+ self.max_core_nb = Spinbox(min=0, max=256, val=self.parent().po.all['cores'],
485
+ night_mode=self.parent().po.all['night_mode'])
486
+ self.max_core_nb_label = FixedText('Proc max core number', night_mode=self.parent().po.all['night_mode'])
487
+ # self.max_core_nb.setVisible(self.parent().po.all['do_multiprocessing'])
488
+ # self.max_core_nb_label.setVisible(self.parent().po.all['do_multiprocessing'])
489
+
490
+ self.min_memory_left = Spinbox(min=0, max=1024, val=self.parent().po.vars['min_ram_free'], decimals=1,
491
+ night_mode=self.parent().po.all['night_mode'])
492
+ self.min_memory_left_label = FixedText('Minimal RAM let free (Go)', night_mode=self.parent().po.all['night_mode'])
493
+
494
+ self.lose_accuracy_to_save_memory = Checkbox(self.parent().po.vars['lose_accuracy_to_save_memory'])
495
+ self.lose_accuracy_to_save_memory_label = FixedText('Lose accuracy to save RAM',
496
+ tip="Use 8 bits instead of 64 to study each pixel",
497
+ night_mode=self.parent().po.all['night_mode'])
498
+
499
+ # IV/D/ Arrange widgets in the box
500
+ self.resources_box_layout.addWidget(self.do_multiprocessing, 0, 0)
501
+ self.resources_box_layout.addWidget(self.do_multiprocessing_label, 0, 1)
502
+ self.resources_box_layout.addWidget(self.max_core_nb, 1, 0)
503
+ self.resources_box_layout.addWidget(self.max_core_nb_label, 1, 1)
504
+ self.resources_box_layout.addWidget(self.min_memory_left, 2, 0)
505
+ self.resources_box_layout.addWidget(self.min_memory_left_label, 2, 1)
506
+ self.resources_box_layout.addWidget(self.lose_accuracy_to_save_memory, 3, 0)
507
+ self.resources_box_layout.addWidget(self.lose_accuracy_to_save_memory_label, 3, 1)
508
+ self.resources_box_widget.setLayout(self.resources_box_layout)
509
+ self.right_col_layout.addWidget(self.resources_box_widget)
510
+ # self.layout.addWidget(self.resources_box_widget, curr_row_2nd_col, 4, 2, 2)
511
+ # curr_row_2nd_col += 3
512
+
513
+ # V/ Fifth box: Video saving
514
+ # V/A/ Title
515
+ self.video_saving_label = FixedText('Video saving:', tip="",
516
+ night_mode=self.parent().po.all['night_mode'])
517
+ self.right_col_layout.addWidget(self.video_saving_label)
518
+ # self.layout.addWidget(self.video_saving_label, curr_row_2nd_col, 4)
519
+ # curr_row_2nd_col += 1
520
+ # V/B/ Create the box
521
+ self.video_saving_layout = QtWidgets.QGridLayout()
522
+ self.video_saving_widget = QtWidgets.QWidget()
523
+ self.video_saving_widget.setStyleSheet(boxstylesheet)
524
+
525
+ # V/C/ Create widgets
526
+ self.video_fps = Spinbox(min=0, max=10000, val=self.parent().po.vars['video_fps'], decimals=2,
527
+ night_mode=self.parent().po.all['night_mode'])
528
+ self.video_fps_label = FixedText('Video fps', night_mode=self.parent().po.all['night_mode'])
529
+ # self.overwrite_unaltered_videos = Checkbox(self.parent().po.all['overwrite_unaltered_videos'])
530
+ # self.overwrite_unaltered_videos_label = FixedText('Do overwrite unaltered videos (.npy)', tip="If the analysis fails because of a bad detection of arenas\nChecking this may resolve failures during image analysis", night_mode=self.parent().po.all['night_mode'])
531
+ self.keep_unaltered_videos = Checkbox(self.parent().po.vars['keep_unaltered_videos'])
532
+ self.keep_unaltered_videos_label = FixedText('Keep unaltered videos', tip="Unaltered videos (.npy) takes a lot of hard drive space\nUsers should only keep these videos\nif they plan to redo the analysis soon and faster", night_mode=self.parent().po.all['night_mode'])
533
+ self.save_processed_videos = Checkbox(self.parent().po.vars['save_processed_videos'])
534
+ self.save_processed_videos_label = FixedText('Save processed videos', tip="Processed videos allow to check analysis accuracy\nThey do not take a lot of space", night_mode=self.parent().po.all['night_mode'])
535
+
536
+ # V/D/ Arrange widgets in the box
537
+ curr_box_row = 0
538
+ self.video_saving_layout.addWidget(self.video_fps, curr_box_row, 0)
539
+ self.video_saving_layout.addWidget(self.video_fps_label, curr_box_row, 1)
540
+ curr_box_row += 1
541
+ # self.video_saving_layout.addWidget(self.overwrite_unaltered_videos, curr_box_row, 0)
542
+ # self.video_saving_layout.addWidget(self.overwrite_unaltered_videos_label, curr_box_row, 1)
543
+ # curr_box_row += 1
544
+ self.video_saving_layout.addWidget(self.keep_unaltered_videos, curr_box_row, 0)
545
+ self.video_saving_layout.addWidget(self.keep_unaltered_videos_label, curr_box_row, 1)
546
+ curr_box_row += 1
547
+ self.video_saving_layout.addWidget(self.save_processed_videos, curr_box_row, 0)
548
+ self.video_saving_layout.addWidget(self.save_processed_videos_label, curr_box_row, 1)
549
+ curr_box_row += 1
550
+
551
+ self.video_saving_widget.setLayout(self.video_saving_layout)
552
+ self.right_col_layout.addWidget(self.video_saving_widget)
553
+ # self.layout.addWidget(self.video_saving_widget, curr_row_2nd_col, 4, 2, 2)
554
+ # curr_row_2nd_col += 2
555
+
556
+ # VII/ Seventh box: csc
557
+ # VII/A/ Title
558
+ # self.video_csc_label = FixedText('Color space combination for video analysis:', tip="",
559
+ # night_mode=self.parent().po.all['night_mode'])
560
+ # self.right_col_layout.addWidget(self.video_csc_label)
561
+ # self.layout.addWidget(self.video_csc_label, curr_row_2nd_col, 4)
562
+ # curr_row_2nd_col += 1
563
+
564
+ # VII/C/ Create widgets
565
+ self.generate_csc_editing()
566
+ # VII/D/ Arrange widgets in the box
567
+ self.right_col_layout.addWidget(self.edit_widget)
568
+ # self.layout.addWidget(self.edit_widget, curr_row_2nd_col, 4, 2, 2)
569
+ # curr_row_2nd_col += 3
570
+
571
+ # VIII/ Finalize layout and add the night mode option and the ok button
572
+ self.left_col_layout.addItem(self.vertical_space)
573
+ self.right_col_layout.addItem(self.vertical_space)
574
+ self.left_col_widget.setLayout(self.left_col_layout)
575
+
576
+
577
+ self.right_col_widget.setLayout(self.right_col_layout)
578
+ self.central_layout = QtWidgets.QHBoxLayout()
579
+ self.central_layout.addItem(self.horizontal_space)
580
+ #self.central_layout.addWidget(self.left_col_widget)
581
+
582
+ self.left_scroll_table.setWidget(self.left_col_widget)
583
+ self.left_scroll_table.setWidgetResizable(True)
584
+ self.central_layout.addWidget(self.left_scroll_table)
585
+
586
+
587
+ self.central_layout.addItem(self.horizontal_space)
588
+ self.right_scroll_table.setWidget(self.right_col_widget)
589
+ self.right_scroll_table.setWidgetResizable(True)
590
+ self.central_layout.addWidget(self.right_scroll_table)
591
+ # self.central_layout.addWidget(self.right_col_widget)
592
+ self.central_layout.addItem(self.horizontal_space)
593
+ self.central_widget = QtWidgets.QWidget()
594
+ self.central_widget.setLayout(self.central_layout)
595
+ self.layout.addWidget(self.central_widget)
596
+ self.layout.addItem(self.vertical_space)
597
+ # Last row
598
+ self.last_row_layout = QtWidgets.QHBoxLayout()
599
+ self.last_row_widget = QtWidgets.QWidget()
600
+ self.night_mode_cb = Checkbox(self.parent().po.all['night_mode'])
601
+ self.night_mode_cb.clicked.connect(self.night_mode_is_clicked)
602
+ self.night_mode_label = FixedText('Night mode', night_mode=self.parent().po.all['night_mode'])
603
+ self.reset_all_settings = PButton("Reset all settings", night_mode=self.parent().po.all['night_mode'])
604
+ self.reset_all_settings.clicked.connect(self.reset_all_settings_is_clicked)
605
+ self.message = FixedText('', night_mode=self.parent().po.all['night_mode'])
606
+ self.cancel = PButton('Cancel', night_mode=self.parent().po.all['night_mode'])
607
+ self.cancel.clicked.connect(self.cancel_is_clicked)
608
+ self.ok = PButton('Ok', night_mode=self.parent().po.all['night_mode'])
609
+ self.ok.clicked.connect(self.ok_is_clicked)
610
+ self.last_row_layout.addWidget(self.night_mode_cb)
611
+ self.last_row_layout.addWidget(self.night_mode_label)
612
+ self.last_row_layout.addWidget(self.reset_all_settings)
613
+ self.last_row_layout.addItem(self.horizontal_space)
614
+ self.last_row_layout.addWidget(self.message)
615
+ self.last_row_layout.addWidget(self.cancel)
616
+ self.last_row_layout.addWidget(self.ok)
617
+ self.last_row_widget.setLayout(self.last_row_layout)
618
+ self.layout.addWidget(self.last_row_widget)
619
+
620
+ self.setLayout(self.layout)
621
+
622
+ def display_conditionally_visible_widgets(self):
623
+ self.max_core_nb.setVisible(self.parent().po.all['do_multiprocessing'])
624
+ self.max_core_nb_label.setVisible(self.parent().po.all['do_multiprocessing'])
625
+ self.first_move_threshold.setVisible(not self.parent().po.all['automatic_size_thresholding'])
626
+ self.first_move_threshold_label.setVisible(not self.parent().po.all['automatic_size_thresholding'])
627
+ connect_distant_shape = self.parent().po.all['connect_distant_shape_during_segmentation']
628
+ do_use_max_size = self.parent().po.vars['max_size_for_connection'] is not None and connect_distant_shape
629
+ do_use_min_size = self.parent().po.vars['min_size_for_connection'] is not None and connect_distant_shape
630
+ self.detection_range_factor.setVisible(connect_distant_shape)
631
+ self.detection_range_factor_label.setVisible(connect_distant_shape)
632
+ self.use_max_size.setVisible(connect_distant_shape)
633
+ self.use_min_size.setVisible(connect_distant_shape)
634
+ self.use_max_size_label.setVisible(connect_distant_shape)
635
+ self.use_min_size_label.setVisible(connect_distant_shape)
636
+
637
+ self.max_size_for_connection.setVisible(do_use_max_size)
638
+ self.max_size_for_connection_label.setVisible(do_use_max_size)
639
+ self.min_size_for_connection.setVisible(do_use_min_size)
640
+ self.min_size_for_connection_label.setVisible(do_use_min_size)
641
+ self.display_more_than_two_colors_option()
642
+
643
+ if self.parent().po.vars['convert_for_motion'] is not None:
644
+ self.update_csc_editing_display()
645
+ else:
646
+ self.row1[0].setCurrentIndex(4)
647
+ self.row1[3].setValue(1)
648
+ self.row21[0].setCurrentIndex(0)
649
+ self.row21[3].setValue(0)
650
+
651
+ def subtract_background_check(self):
652
+ self.parent().po.motion = None
653
+ if self.subtract_background.isChecked():
654
+ self.parent().po.first_exp_ready_to_run = False
655
+
656
+ def prevent_fast_growth_near_periphery_check(self):
657
+ checked_status = self.prevent_fast_growth_near_periphery.isChecked()
658
+ self.periphery_width.setVisible(checked_status)
659
+ self.periphery_width_label.setVisible(checked_status)
660
+ self.max_periphery_growth.setVisible(checked_status)
661
+ self.max_periphery_growth_label.setVisible(checked_status)
662
+
663
+ def do_automatic_size_thresholding_changed(self):
664
+ """ Triggered when do_automatic_size_thresholding check status changes"""
665
+ self.first_move_threshold.setVisible(not self.do_automatic_size_thresholding.isChecked())
666
+ self.first_move_threshold_label.setVisible(not self.do_automatic_size_thresholding.isChecked())
667
+
668
+ def extract_time_is_clicked(self):
669
+ self.time_step.setVisible(not self.extract_time.isChecked())
670
+ if self.extract_time.isChecked():
671
+ self.time_step_label.setText("Automatically extract time interval between images")
672
+ self.time_step_label.setToolTip("Uses the exif data of the images (if available), to extract these intervals\nOtherwise, default time interval is 1 min")
673
+ else:
674
+ self.time_step_label.setText("Set the time interval between images")
675
+ self.time_step_label.setToolTip("In minutes")
676
+
677
+ def do_multiprocessing_is_clicked(self):
678
+ self.max_core_nb.setVisible(self.do_multiprocessing.isChecked())
679
+ self.max_core_nb_label.setVisible(self.do_multiprocessing.isChecked())
680
+
681
+ # def all_specimens_have_same_direction_changed(self):
682
+ # """ Triggered when all_specimens_have_same_direction check status changes"""
683
+ # self.parent().po.all['all_specimens_have_same_direction'] = self.all_specimens_have_same_direction.isChecked()
684
+
685
+ def do_distant_shape_int_changed(self):
686
+ """ Triggered when connect_distant_shape_during_segmentation check status changes"""
687
+ do_distant_shape_int = self.connect_distant_shape_during_segmentation.isChecked()
688
+ self.detection_range_factor.setVisible(do_distant_shape_int)
689
+ if do_distant_shape_int:
690
+ self.detection_range_factor.setValue(2)
691
+ self.detection_range_factor_label.setVisible(do_distant_shape_int)
692
+ self.use_max_size.setVisible(do_distant_shape_int)
693
+ self.use_min_size.setVisible(do_distant_shape_int)
694
+ self.use_max_size_label.setVisible(do_distant_shape_int)
695
+ self.use_min_size_label.setVisible(do_distant_shape_int)
696
+ do_use_max_size = do_distant_shape_int and self.use_max_size.isChecked()
697
+ self.max_size_for_connection.setVisible(do_use_max_size)
698
+ self.max_size_for_connection_label.setVisible(do_use_max_size)
699
+ do_use_min_size = do_distant_shape_int and self.use_min_size.isChecked()
700
+ self.min_size_for_connection.setVisible(do_use_min_size)
701
+ self.min_size_for_connection_label.setVisible(do_use_min_size)
702
+
703
+ def use_max_size_changed(self):
704
+ """ Triggered when use_max_size check status changes"""
705
+ do_use_max_size = self.use_max_size.isChecked()
706
+ self.max_size_for_connection.setVisible(do_use_max_size)
707
+ self.max_size_for_connection_label.setVisible(do_use_max_size)
708
+ if do_use_max_size:
709
+ self.max_size_for_connection.setValue(300)
710
+
711
+ def use_min_size_changed(self):
712
+ """ Triggered when use_min_size check status changes"""
713
+ do_use_min_size = self.use_min_size.isChecked()
714
+ self.min_size_for_connection.setVisible(do_use_min_size)
715
+ self.min_size_for_connection_label.setVisible(do_use_min_size)
716
+ if do_use_min_size:
717
+ self.min_size_for_connection.setValue(30)
718
+
719
+ def generate_csc_editing(self):
720
+ # self.edit_layout = QtWidgets.QGridLayout()
721
+ self.edit_widget = QtWidgets.QWidget()
722
+ # self.edit_widget.setVisible(False)
723
+ # self.edit_widget.setStyleSheet(boxstylesheet)
724
+ self.edit_layout = QtWidgets.QVBoxLayout()
725
+
726
+ # self.csc_scroll_table = QtWidgets.QScrollArea() # QTableWidget() # Scroll Area which contains the widgets, set as the centralWidget
727
+ # # self.csc_scroll_table.setVisible(False)
728
+ # # self.csc_scroll_table.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
729
+ # self.csc_scroll_table.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
730
+ # self.csc_scroll_table.setMinimumHeight(150)#self.parent().im_max_height - 100
731
+ # # self.csc_scroll_table.setMinimumWidth(300)
732
+ # self.csc_scroll_table.setFrameShape(QtWidgets.QFrame.NoFrame)
733
+ # self.csc_scroll_table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
734
+ # self.csc_scroll_table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
735
+ self.csc_table_widget = QtWidgets.QWidget()
736
+ self.csc_table_layout = QtWidgets.QVBoxLayout()
737
+
738
+ # 2) Titles
739
+ # self.edit_labels_widget = QtWidgets.QWidget()
740
+ # self.edit_labels_widget.setFixedHeight(50)
741
+ # self.edit_labels_layout = QtWidgets.QHBoxLayout()
742
+ # self.space_label = FixedText('Space', align='c',
743
+ # tip="Color spaces are transformations of the original BGR (Blue Green Red) image\nInstead of defining an image by 3 colors,\n they transform it into 3 different visual properties\n - hsv: hue (color), saturation, value (lightness)\n - hls: hue (color), lightness, saturation\n - lab: Lightness, Red/Green, Blue/Yellow\n - luv and yuv: l and y are Lightness, u and v are related to colors\n",
744
+ # night_mode=self.parent().po.all['night_mode'])
745
+ # self.c1 = FixedText(' C1', align='c', tip="Increase if it increase cell detection", night_mode=self.parent().po.all['night_mode'])
746
+ # self.c2 = FixedText(' C2', align='c', tip="Increase if it increase cell detection", night_mode=self.parent().po.all['night_mode'])
747
+ # self.c3 = FixedText(' C3', align='c', tip="Increase if it increase cell detection", night_mode=self.parent().po.all['night_mode'])
748
+ #
749
+ # self.edit_labels_layout.addWidget(self.space_label)
750
+ # self.edit_labels_layout.addWidget(self.c1)
751
+ # self.edit_labels_layout.addWidget(self.c2)
752
+ # self.edit_labels_layout.addWidget(self.c3)
753
+ # self.edit_labels_layout.addItem(self.horizontal_space)
754
+ # self.edit_labels_widget.setLayout(self.edit_labels_layout)
755
+ # # self.edit_layout.addWidget(self.edit_labels_widget)
756
+ # self.csc_table_layout.addWidget(self.edit_labels_widget)
757
+ self.video_csc_label = FixedText('Color space combination for video analysis:', tip="",
758
+ night_mode=self.parent().po.all['night_mode'])
759
+ self.video_csc_label.setFixedHeight(30)
760
+ self.csc_table_layout.addWidget(self.video_csc_label)
761
+
762
+ self.both_csc_widget = QtWidgets.QWidget()
763
+ self.both_csc_layout = QtWidgets.QHBoxLayout()
764
+ # 3) First CSC
765
+ self.first_csc_widget = QtWidgets.QWidget()
766
+ self.first_csc_layout = QtWidgets.QGridLayout()
767
+ self.row1 = self.one_csc_editing()
768
+ self.row1[4].clicked.connect(self.display_row2)
769
+ self.row2 = self.one_csc_editing()
770
+ self.row2[4].clicked.connect(self.display_row3)
771
+ self.row3 = self.one_csc_editing()# Second CSC
772
+ self.logical_operator_between_combination_result = Combobox(["None", "Or", "And", "Xor"],
773
+ night_mode=self.parent().po.all['night_mode'])
774
+ self.logical_operator_between_combination_result.setCurrentText(self.parent().po.vars['convert_for_motion']['logical'])
775
+ self.logical_operator_between_combination_result.currentTextChanged.connect(self.logical_op_changed)
776
+ self.logical_operator_between_combination_result.setFixedWidth(100)
777
+ # self.logical_operator_between_combination_result.cha
778
+ self.logical_operator_label = FixedText("Logical operator", halign='c', tip="Between selected color space combinations",
779
+ night_mode=self.parent().po.all['night_mode'])
780
+
781
+ self.row21 = self.one_csc_editing()
782
+ self.row21[4].clicked.connect(self.display_row22)
783
+ self.row22 = self.one_csc_editing()
784
+ self.row22[4].clicked.connect(self.display_row23)
785
+ self.row23 = self.one_csc_editing()
786
+
787
+
788
+ for i in range(5):
789
+ self.first_csc_layout.addWidget(self.row1[i], 0, i, 1, 1)
790
+ self.first_csc_layout.addWidget(self.row2[i], 1, i, 1, 1)
791
+ self.first_csc_layout.addWidget(self.row3[i], 2, i, 1, 1)
792
+ self.row1[i].setVisible(False)
793
+ self.row2[i].setVisible(False)
794
+ self.row3[i].setVisible(False)
795
+ self.first_csc_layout.setHorizontalSpacing(0)
796
+ self.first_csc_layout.addItem(self.horizontal_space, 0, 5, 3, 1)
797
+ self.first_csc_widget.setLayout(self.first_csc_layout)
798
+ self.both_csc_layout.addWidget(self.first_csc_widget)
799
+ # self.csc_table_layout.addWidget(self.first_csc_widget)
800
+ # self.edit_layout.addWidget(self.first_csc_widget)
801
+
802
+
803
+ # 5) Second CSC
804
+ self.second_csc_widget = QtWidgets.QWidget()
805
+ self.second_csc_layout = QtWidgets.QGridLayout()
806
+ for i in range(5):
807
+ self.second_csc_layout.addWidget(self.row21[i], 0, i, 1, 1)
808
+ self.second_csc_layout.addWidget(self.row22[i], 1, i, 1, 1)
809
+ self.second_csc_layout.addWidget(self.row23[i], 2, i, 1, 1)
810
+ self.row21[i].setVisible(False)
811
+ self.row22[i].setVisible(False)
812
+ self.row23[i].setVisible(False)
813
+ self.second_csc_layout.setHorizontalSpacing(0)
814
+ self.second_csc_layout.addItem(self.horizontal_space, 0, 5, 3, 1)
815
+ self.second_csc_widget.setLayout(self.second_csc_layout)
816
+ self.both_csc_layout.addItem(self.horizontal_space)
817
+ self.both_csc_layout.addWidget(self.second_csc_widget)
818
+ self.both_csc_widget.setLayout(self.both_csc_layout)
819
+ self.csc_table_layout.addWidget(self.both_csc_widget)
820
+ # self.csc_table_layout.addWidget(self.second_csc_widget)
821
+
822
+
823
+ # 4) logical_operator
824
+ self.logical_op_widget = QtWidgets.QWidget()
825
+ self.logical_op_widget.setFixedHeight(30)
826
+ self.logical_op_layout = QtWidgets.QHBoxLayout()
827
+ self.logical_op_layout.addWidget(self.logical_operator_label)
828
+ self.logical_op_layout.addWidget(self.logical_operator_between_combination_result)
829
+ self.logical_op_layout.addItem(self.horizontal_space)
830
+ self.logical_operator_between_combination_result.setVisible(False)
831
+ self.logical_operator_label.setVisible(False)
832
+ self.logical_op_widget.setLayout(self.logical_op_layout)
833
+ self.logical_op_widget.setFixedHeight(50)
834
+ self.csc_table_layout.addWidget(self.logical_op_widget)
835
+ # self.edit_layout.addWidget(self.logical_op_widget)
836
+
837
+ # 6) Open the more_than_2_colors row layout
838
+ self.more_than_2_colors_widget = QtWidgets.QWidget()
839
+ self.more_than_2_colors_layout = QtWidgets.QHBoxLayout()
840
+ self.more_than_two_colors = Checkbox(self.parent().po.all["more_than_two_colors"])
841
+ self.more_than_two_colors.setStyleSheet("margin-left:0%; margin-right:-10%;")
842
+ self.more_than_two_colors.stateChanged.connect(self.display_more_than_two_colors_option)
843
+
844
+ self.more_than_two_colors_label = FixedText("Heterogeneous back",
845
+ tip="The program will split the image into categories", night_mode=self.parent().po.all['night_mode'])
846
+ self.more_than_two_colors_label.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
847
+ # self.more_than_two_colors_label.setFixedWidth(300)
848
+ self.more_than_two_colors_label.setAlignment(QtCore.Qt.AlignLeft)
849
+ self.distinct_colors_number = Spinbox(min=2, max=5, val=self.parent().po.vars["color_number"], night_mode=self.parent().po.all['night_mode'])
850
+ # self.distinct_colors_number.valueChanged.connect(self.distinct_colors_number_changed)
851
+ # self.display_more_than_two_colors_option()
852
+ # self.more_than_two_colors.setVisible(False)
853
+ # self.more_than_two_colors_label.setVisible(False)
854
+ # self.distinct_colors_number.setVisible(False)
855
+ self.more_than_2_colors_layout.addWidget(self.more_than_two_colors)
856
+ self.more_than_2_colors_layout.addWidget(self.more_than_two_colors_label)
857
+ self.more_than_2_colors_layout.addWidget(self.distinct_colors_number)
858
+ self.more_than_2_colors_layout.addItem(self.horizontal_space)
859
+ self.more_than_2_colors_widget.setLayout(self.more_than_2_colors_layout)
860
+ self.more_than_2_colors_widget.setFixedHeight(50)
861
+ self.csc_table_layout.addWidget(self.more_than_2_colors_widget)
862
+ self.csc_table_layout.addItem(self.vertical_space)
863
+ self.csc_table_widget.setLayout(self.csc_table_layout)
864
+
865
+ self.edit_layout.addWidget(self.csc_table_widget)
866
+ # self.csc_scroll_table.setWidget(self.csc_table_widget)
867
+ # self.csc_scroll_table.setWidgetResizable(True)
868
+ # self.edit_layout.addWidget(self.csc_scroll_table)
869
+
870
+ # self.more_than_2_colors_layout.addWidget(self.more_than_two_colors)
871
+ # self.more_than_2_colors_layout.addWidget(self.more_than_two_colors_label)
872
+ # self.more_than_2_colors_layout.addWidget(self.distinct_colors_number)
873
+ # self.more_than_2_colors_layout.addItem(self.horizontal_space)
874
+ # self.more_than_2_colors_widget.setLayout(self.more_than_2_colors_layout)
875
+ # self.edit_layout.addWidget(self.more_than_2_colors_widget)
876
+
877
+ self.edit_widget.setLayout(self.edit_layout)
878
+
879
+ def one_csc_editing(self):
880
+ widget_list = []
881
+ widget_list.insert(0, Combobox(["None", "bgr", "hsv", "hls", "lab", "luv", "yuv"],
882
+ night_mode=self.parent().po.all['night_mode']))
883
+ widget_list[0].setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
884
+ widget_list[0].setFixedWidth(100)
885
+ for i in [1, 2, 3]:
886
+ widget_list.insert(i, Spinbox(min=-126, max=126, val=0, night_mode=self.parent().po.all['night_mode']))
887
+ widget_list[i].setFixedWidth(45)
888
+ widget_list.insert(i + 1, PButton("+", night_mode=self.parent().po.all['night_mode']))
889
+
890
+ return widget_list
891
+
892
+ def logical_op_changed(self):
893
+ # show = self.logical_operator_between_combination_result.currentText() != 'None'
894
+ if self.logical_operator_between_combination_result.currentText() == 'None':
895
+ self.row21[0].setVisible(False)
896
+ self.row21[0].setCurrentIndex(0)
897
+ for i1 in [1, 2, 3]:
898
+ self.row21[i1].setVisible(False)
899
+ self.row21[i1].setValue(0)
900
+ self.row21[i1 + 1].setVisible(False)
901
+
902
+ self.row22[0].setVisible(False)
903
+ self.row22[0].setCurrentIndex(0)
904
+ for i1 in [1, 2, 3]:
905
+ self.row22[i1].setVisible(False)
906
+ self.row22[i1].setValue(0)
907
+ self.row22[i1 + 1].setVisible(False)
908
+
909
+ self.row23[0].setVisible(False)
910
+ self.row23[0].setCurrentIndex(0)
911
+ for i1 in [1, 2, 3]:
912
+ self.row23[i1].setVisible(False)
913
+ self.row23[i1].setValue(0)
914
+ self.row23[i1 + 1].setVisible(False)
915
+ else:
916
+ self.row21[0].setVisible(True)
917
+ for i1 in [1, 2, 3]:
918
+ self.row21[i1].setVisible(True)
919
+ self.row21[i1 + 1].setVisible(True)
920
+
921
+ def display_logical_operator(self):
922
+ self.logical_operator_between_combination_result.setVisible(True)
923
+ self.logical_operator_label.setVisible(True)
924
+
925
+ def display_row2(self):
926
+ self.row1[4].setVisible(False)
927
+ for i in range(5):
928
+ self.row2[i].setVisible(True)
929
+ self.display_logical_operator()
930
+
931
+ def display_row3(self):
932
+ self.row2[4].setVisible(False)
933
+ for i in range(4):
934
+ self.row3[i].setVisible(True)
935
+ self.display_logical_operator()
936
+
937
+ def display_row22(self):
938
+ self.row21[4].setVisible(False)
939
+ for i in range(5):
940
+ self.row22[i].setVisible(True)
941
+ self.display_logical_operator()
942
+
943
+ def display_row23(self):
944
+ self.row22[4].setVisible(False)
945
+ for i in range(4):
946
+ self.row23[i].setVisible(True)
947
+ self.display_logical_operator()
948
+
949
+ def update_csc_editing_display(self):
950
+ c_space_order = ["None", "bgr", "hsv", "hls", "lab", "luv", "yuv"]
951
+ remaining_c_spaces = []
952
+ row_number1 = 0
953
+ row_number2 = 0
954
+ for i, (k, v) in enumerate(self.parent().po.vars['convert_for_motion'].items()):
955
+ if k != "logical":
956
+ if k[-1] != "2":
957
+ if row_number1 == 0:
958
+ row_to_change = self.row1
959
+ elif row_number1 == 1:
960
+ row_to_change = self.row2
961
+ elif row_number1 == 2:
962
+ row_to_change = self.row3
963
+ else:
964
+ remaining_c_spaces.append(k + " " + str(v))
965
+ row_number1 += 1
966
+ current_row_number = row_number1
967
+ else:
968
+ if row_number2 == 0:
969
+ row_to_change = self.row21
970
+ elif row_number2 == 1:
971
+ row_to_change = self.row22
972
+ elif row_number2 == 2:
973
+ row_to_change = self.row23
974
+ else:
975
+ remaining_c_spaces.append(k + " " + str(v))
976
+ row_number2 += 1
977
+ current_row_number = row_number2
978
+ k = k[:-1]
979
+ if current_row_number <= 3:
980
+ row_to_change[0].setCurrentIndex(np.nonzero(np.isin(c_space_order, k))[0][0])
981
+ row_to_change[0].setVisible(True)
982
+ for i1, i2 in zip([1, 2, 3], [0, 1, 2]):
983
+ row_to_change[i1].setValue(v[i2])
984
+ row_to_change[i1].setVisible(True)
985
+ if current_row_number < 3:
986
+ row_to_change[i1 + 1].setVisible(True)
987
+
988
+ # If not all color space combinations are filled, put None and 0 in boxes
989
+ if row_number1 < 3:
990
+ self.row3[0].setVisible(False)
991
+ self.row3[0].setCurrentIndex(0)
992
+ for i1 in [1, 2, 3]:
993
+ self.row3[i1].setVisible(False)
994
+ self.row3[i1].setValue(0)
995
+ if row_number1 < 2:
996
+ self.row2[0].setVisible(False)
997
+ self.row2[0].setCurrentIndex(0)
998
+ for i1 in [1, 2, 3]:
999
+ self.row2[i1].setVisible(False)
1000
+ self.row2[i1].setValue(0)
1001
+ self.row2[i1 + 1].setVisible(False)
1002
+
1003
+ self.row1[4].setVisible(row_number1 == 1)
1004
+ self.row2[4].setVisible(row_number1 == 2)
1005
+ self.row21[4].setVisible(row_number2 == 1)
1006
+ self.row22[4].setVisible(row_number2 == 2)
1007
+ if row_number2 > 0:
1008
+ self.logical_operator_between_combination_result.setCurrentText(self.parent().po.vars['convert_for_motion']['logical'])
1009
+ if row_number2 == 0:
1010
+ self.logical_operator_between_combination_result.setCurrentText('None')
1011
+ self.logical_operator_between_combination_result.setVisible(False)
1012
+ self.logical_operator_label.setVisible(False)
1013
+ self.row21[0].setVisible(False)
1014
+ self.row21[0].setCurrentIndex(0)
1015
+ for i1 in [1, 2, 3]:
1016
+ self.row21[i1].setVisible(False)
1017
+ self.row21[i1].setValue(0)
1018
+ self.row21[i1 + 1].setVisible(False)
1019
+
1020
+ self.logical_operator_between_combination_result.setVisible((row_number2 > 0))
1021
+ self.logical_operator_label.setVisible((row_number2 > 0))
1022
+
1023
+ if row_number2 < 3:
1024
+ self.row23[0].setVisible(False)
1025
+ self.row23[0].setCurrentIndex(0)
1026
+ for i1 in [1, 2, 3]:
1027
+ self.row23[i1].setVisible(False)
1028
+ self.row23[i1].setValue(0)
1029
+ self.row23[i1 + 1].setVisible(False)
1030
+ self.row22[4].setVisible(False)
1031
+ if row_number2 < 2:
1032
+ self.row22[0].setVisible(False)
1033
+ self.row22[0].setCurrentIndex(0)
1034
+ for i1 in [1, 2, 3]:
1035
+ self.row22[i1].setVisible(False)
1036
+ self.row22[i1].setValue(0)
1037
+ self.row22[i1 + 1].setVisible(False)
1038
+
1039
+ def save_user_defined_csc(self):
1040
+ self.parent().po.vars['convert_for_motion'] = {}
1041
+ spaces = np.array((self.row1[0].currentText(), self.row2[0].currentText(), self.row3[0].currentText()))
1042
+ channels = np.array(
1043
+ ((self.row1[1].value(), self.row1[2].value(), self.row1[3].value()),
1044
+ (self.row2[1].value(), self.row2[2].value(), self.row2[3].value()),
1045
+ (self.row3[1].value(), self.row3[2].value(), self.row3[3].value()),
1046
+ (self.row21[1].value(), self.row21[2].value(), self.row21[3].value()),
1047
+ (self.row22[1].value(), self.row22[2].value(), self.row22[3].value()),
1048
+ (self.row23[1].value(), self.row23[2].value(), self.row23[3].value())),
1049
+ dtype=np.int8)
1050
+ if self.logical_operator_between_combination_result.currentText() != 'None':
1051
+ spaces = np.concatenate((spaces, np.array((
1052
+ self.row21[0].currentText() + "2", self.row22[0].currentText() + "2",
1053
+ self.row23[0].currentText() + "2"))))
1054
+ channels = np.concatenate((channels, np.array(((self.row21[1].value(), self.row21[2].value(), self.row21[3].value()),
1055
+ (self.row22[1].value(), self.row22[2].value(), self.row22[3].value()),
1056
+ (self.row23[1].value(), self.row23[2].value(), self.row23[3].value())),
1057
+ dtype=np.int8)))
1058
+ self.parent().po.vars['convert_for_motion']['logical'] = self.logical_operator_between_combination_result.currentText()
1059
+ else:
1060
+ self.parent().po.vars['convert_for_motion']['logical'] = 'None'
1061
+ if not np.all(spaces == "None"):
1062
+ for i, space in enumerate(spaces):
1063
+ if space != "None" and space != "None2":
1064
+ self.parent().po.vars['convert_for_motion'][space] = channels[i, :]
1065
+ if len(self.parent().po.vars['convert_for_motion']) == 1 or channels.sum() == 0:
1066
+ self.csc_dict_is_empty = True
1067
+ else:
1068
+ self.csc_dict_is_empty = False
1069
+
1070
+ self.parent().po.all["more_than_two_colors"] = self.more_than_two_colors.isChecked()
1071
+ if self.more_than_two_colors.isChecked():
1072
+ self.parent().po.vars["color_number"] = int(self.distinct_colors_number.value())
1073
+ self.parent().videoanalysiswindow.select_option.setVisible(True)
1074
+ self.parent().videoanalysiswindow.select_option_label.setVisible(True)
1075
+
1076
+ def display_more_than_two_colors_option(self):
1077
+ if self.more_than_two_colors.isChecked():
1078
+ self.distinct_colors_number.setVisible(True)
1079
+ self.more_than_two_colors_label.setText("How many distinct colors?")
1080
+ self.distinct_colors_number.setValue(3)
1081
+ else:
1082
+ self.more_than_two_colors_label.setText("Heterogeneous background")
1083
+ self.distinct_colors_number.setVisible(False)
1084
+ self.distinct_colors_number.setValue(2)
1085
+
1086
+
1087
+ # self.parent().po.vars["color_number"] = 2
1088
+
1089
+ # def distinct_colors_number_changed(self):
1090
+ # self.parent().po.vars["color_number"] = int(self.distinct_colors_number.value())
1091
+
1092
+ def night_mode_is_clicked(self):
1093
+ """ Triggered when night_mode_cb check status changes"""
1094
+ self.parent().po.all['night_mode'] = self.night_mode_cb.isChecked()
1095
+ self.message.setText('Close and restart Cellects to apply night or light mode')
1096
+ self.message.setStyleSheet("color: rgb(230, 145, 18)")
1097
+
1098
+ def reset_all_settings_is_clicked(self):
1099
+ if os.path.isfile('Data to run Cellects quickly.pkl'):
1100
+ os.remove('Data to run Cellects quickly.pkl')
1101
+ if os.path.isfile('PickleRick.pkl'):
1102
+ os.remove('PickleRick.pkl')
1103
+ if os.path.isfile('PickleRick0.pkl'):
1104
+ os.remove('PickleRick0.pkl')
1105
+ if os.path.isfile(Path(CELLECTS_DIR.parent / 'PickleRick.pkl')):
1106
+ os.remove(Path(CELLECTS_DIR.parent / 'PickleRick.pkl'))
1107
+ if os.path.isfile(Path(CELLECTS_DIR.parent / 'PickleRick0.pkl')):
1108
+ os.remove(Path(CELLECTS_DIR.parent / 'PickleRick0.pkl'))
1109
+ if os.path.isfile(Path(CONFIG_DIR / 'PickleRick1.pkl')):
1110
+ os.remove(Path(CONFIG_DIR / 'PickleRick1.pkl'))
1111
+ current_dir = os.getcwd()
1112
+ os.chdir(CONFIG_DIR)
1113
+ DefaultDicts().save_as_pkl(self.parent().po)
1114
+ os.chdir(current_dir)
1115
+ self.message.setText('Close and restart Cellects to apply the settings reset')
1116
+ self.message.setStyleSheet("color: rgb(230, 145, 18)")
1117
+
1118
+ def cancel_is_clicked(self):
1119
+ self.automatically_crop.setChecked(self.parent().po.all['automatically_crop'])
1120
+ self.subtract_background.setChecked(self.parent().po.vars['subtract_background'])
1121
+ self.keep_cell_and_back_for_all_folders.setChecked(self.parent().po.all['keep_cell_and_back_for_all_folders'])
1122
+ self.correct_errors_around_initial.setChecked(self.parent().po.vars['correct_errors_around_initial'])
1123
+ self.prevent_fast_growth_near_periphery.setChecked(self.parent().po.vars['prevent_fast_growth_near_periphery'])
1124
+ self.periphery_width.setValue(self.parent().po.vars['periphery_width'])
1125
+ self.max_periphery_growth.setValue(self.parent().po.vars['max_periphery_growth'])
1126
+
1127
+
1128
+ self.first_move_threshold.setValue(self.parent().po.all['first_move_threshold_in_mm²'])
1129
+ self.pixels_to_mm.setChecked(self.parent().po.vars['output_in_mm'])
1130
+ self.do_automatic_size_thresholding.setChecked(self.parent().po.all['automatic_size_thresholding'])
1131
+ self.appearing_selection.setCurrentText(self.parent().po.vars['appearance_detection_method'])
1132
+ self.oscillation_period.setValue(self.parent().po.vars['expected_oscillation_period'])
1133
+ self.minimal_oscillating_cluster_size.setValue(self.parent().po.vars['minimal_oscillating_cluster_size'])
1134
+
1135
+ self.network_detection_threshold.setValue(self.parent().po.vars['network_detection_threshold'])
1136
+
1137
+ self.do_multiprocessing.setChecked(self.parent().po.all['do_multiprocessing'])
1138
+ self.max_core_nb.setValue(self.parent().po.all['cores'])
1139
+ self.min_memory_left.setValue(self.parent().po.vars['min_ram_free'])
1140
+ self.lose_accuracy_to_save_memory.setChecked(self.parent().po.vars['lose_accuracy_to_save_memory'])
1141
+ self.video_fps.setValue(self.parent().po.vars['video_fps'])
1142
+ self.keep_unaltered_videos.setChecked(self.parent().po.vars['keep_unaltered_videos'])
1143
+ self.save_processed_videos.setChecked(self.parent().po.vars['save_processed_videos'])
1144
+ self.time_step.setValue(self.parent().po.vars['time_step'])
1145
+ # self.parent().po.all['overwrite_cellects_data'] = self.overwrite_cellects_data.isChecked()
1146
+
1147
+ self.connect_distant_shape_during_segmentation.setChecked(self.parent().po.all['connect_distant_shape_during_segmentation'])
1148
+ do_use_max_size = self.parent().po.vars['max_size_for_connection'] is not None and self.parent().po.all['connect_distant_shape_during_segmentation']
1149
+ do_use_min_size = self.parent().po.vars['min_size_for_connection'] is not None and self.parent().po.all['connect_distant_shape_during_segmentation']
1150
+ self.use_max_size.setChecked(do_use_max_size)
1151
+ self.use_min_size.setChecked(do_use_min_size)
1152
+ if do_use_max_size:
1153
+ self.max_size_for_connection.setValue(self.parent().po.vars['max_size_for_connection'])
1154
+ else:
1155
+ self.max_size_for_connection.setValue(50)
1156
+ if do_use_min_size:
1157
+ self.min_size_for_connection.setValue(self.parent().po.vars['min_size_for_connection'])
1158
+ else:
1159
+ self.min_size_for_connection.setValue(0)
1160
+
1161
+ self.detection_range_factor.setValue(self.parent().po.vars['detection_range_factor'])
1162
+ self.all_specimens_have_same_direction.setChecked(self.parent().po.all['all_specimens_have_same_direction'])
1163
+ self.update_csc_editing_display()
1164
+
1165
+ if self.parent().last_is_first:
1166
+ self.parent().change_widget(0) # FirstWidget
1167
+ else:
1168
+ self.parent().change_widget(3) # ImageAnalysisWindow ThirdWidget
1169
+
1170
+ def ok_is_clicked(self):
1171
+ """ Triggered when ok is clicked, save the directory all_vars.pkl and go back to the previous window"""
1172
+ # if self.mesh_side_length.value() <= self.mesh_step_length.value():
1173
+ # self.message.setText('The mesh side has to be inferior to the mesh step')
1174
+ # self.message.setStyleSheet("color: rgb(230, 145, 18)")
1175
+ # else:
1176
+ self.parent().po.all['automatically_crop'] = self.automatically_crop.isChecked()
1177
+ self.parent().po.vars['subtract_background'] = self.subtract_background.isChecked()
1178
+ self.parent().po.all['keep_cell_and_back_for_all_folders'] = self.keep_cell_and_back_for_all_folders.isChecked()
1179
+ self.parent().po.vars['correct_errors_around_initial'] = self.correct_errors_around_initial.isChecked()
1180
+ self.parent().po.vars['prevent_fast_growth_near_periphery'] = self.prevent_fast_growth_near_periphery.isChecked()
1181
+ self.parent().po.vars['periphery_width'] = int(self.periphery_width.value())
1182
+ self.parent().po.vars['max_periphery_growth'] = int(self.max_periphery_growth.value())
1183
+
1184
+ # if self.parent().po.vars['origin_state'] == "invisible":
1185
+ self.parent().po.all['first_move_threshold_in_mm²'] = self.first_move_threshold.value()
1186
+ self.parent().po.vars['output_in_mm'] = self.pixels_to_mm.isChecked()
1187
+ self.parent().po.all['automatic_size_thresholding'] = self.do_automatic_size_thresholding.isChecked()
1188
+ self.parent().po.vars['appearance_detection_method'] = self.appearing_selection.currentText()
1189
+ self.parent().po.vars['expected_oscillation_period'] = self.oscillation_period.value()
1190
+ self.parent().po.vars['minimal_oscillating_cluster_size'] = int(self.minimal_oscillating_cluster_size.value())
1191
+
1192
+ self.parent().po.vars['network_detection_threshold'] = int(np.round(self.network_detection_threshold.value()))
1193
+
1194
+ self.parent().po.all['do_multiprocessing'] = self.do_multiprocessing.isChecked()
1195
+ self.parent().po.all['cores'] = np.uint8(self.max_core_nb.value())
1196
+ self.parent().po.vars['min_ram_free'] = self.min_memory_left.value()
1197
+ self.parent().po.vars['lose_accuracy_to_save_memory'] = self.lose_accuracy_to_save_memory.isChecked()
1198
+ self.parent().po.vars['video_fps'] = float(self.video_fps.value())
1199
+ self.parent().po.vars['keep_unaltered_videos'] = self.keep_unaltered_videos.isChecked()
1200
+ self.parent().po.vars['save_processed_videos'] = self.save_processed_videos.isChecked()
1201
+ self.parent().po.all['extract_time_interval'] = self.extract_time.isChecked()
1202
+ self.parent().po.vars['time_step'] = float(self.time_step.value())
1203
+
1204
+ do_distant_shape_int = self.connect_distant_shape_during_segmentation.isChecked()
1205
+ self.parent().po.all['connect_distant_shape_during_segmentation'] = do_distant_shape_int
1206
+ if do_distant_shape_int:
1207
+ self.parent().po.vars['detection_range_factor'] = int(
1208
+ np.round(self.detection_range_factor.value()))
1209
+ else:
1210
+ self.parent().po.vars['detection_range_factor'] = 0
1211
+ if self.use_max_size.isChecked():
1212
+ self.parent().po.vars['max_size_for_connection'] = int(np.round(self.max_size_for_connection.value()))
1213
+ else:
1214
+ self.parent().po.vars['max_size_for_connection'] = None
1215
+ if self.use_min_size.isChecked():
1216
+ self.parent().po.vars['min_size_for_connection'] = int(np.round(self.min_size_for_connection.value()))
1217
+ else:
1218
+ self.parent().po.vars['min_size_for_connection'] = None
1219
+
1220
+ self.parent().po.all['all_specimens_have_same_direction'] = self.all_specimens_have_same_direction.isChecked()
1221
+
1222
+ previous_csc = deepcopy(self.parent().po.vars['convert_for_motion'])
1223
+ self.save_user_defined_csc()
1224
+ print(self.parent().po.vars['convert_for_motion'])
1225
+ if self.parent().po.first_exp_ready_to_run:
1226
+ are_dicts_equal: bool = True
1227
+ for key in previous_csc.keys():
1228
+ if key != 'logical':
1229
+ are_dicts_equal = are_dicts_equal and np.all(key in self.parent().po.vars['convert_for_motion'] and previous_csc[key] == self.parent().po.vars['convert_for_motion'][key])
1230
+ for key in self.parent().po.vars['convert_for_motion'].keys():
1231
+ if key != 'logical':
1232
+ are_dicts_equal = are_dicts_equal and np.all(
1233
+ key in previous_csc and self.parent().po.vars['convert_for_motion'][key] ==
1234
+ previous_csc[key])
1235
+ if not are_dicts_equal:
1236
+ self.parent().po.find_if_lighter_background()
1237
+
1238
+ if not self.parent().thread['SaveAllVars'].isRunning():
1239
+ self.parent().thread['SaveAllVars'].start()
1240
+
1241
+ if self.parent().last_is_first:
1242
+ self.parent().change_widget(0) # FirstWidget
1243
+ else:
1244
+ self.parent().change_widget(3) # ImageAnalysisWindow ThirdWidget
1245
+
1246
+ def closeEvent(self, event):
1247
+ event.accept
1248
+
1249
+
1250
+ # if __name__ == "__main__":
1251
+ # from cellects.gui.cellects import CellectsMainWidget
1252
+ # import sys
1253
+ # app = QtWidgets.QApplication([])
1254
+ # parent = CellectsMainWidget()
1255
+ # session = AdvancedParameters(parent, False)
1256
+ # parent.insertWidget(0, session)
1257
+ # parent.show()
1258
+ # sys.exit(app.exec())