cellects 0.1.2__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 (44) 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 +155 -0
  5. cellects/core/__init__.py +0 -0
  6. cellects/core/cellects_paths.py +31 -0
  7. cellects/core/cellects_threads.py +1451 -0
  8. cellects/core/motion_analysis.py +2010 -0
  9. cellects/core/one_image_analysis.py +1061 -0
  10. cellects/core/one_video_per_blob.py +540 -0
  11. cellects/core/program_organizer.py +1316 -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 +790 -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 +2066 -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/image_segmentation.py +706 -0
  29. cellects/image_analysis/morphological_operations.py +1635 -0
  30. cellects/image_analysis/network_functions.py +1757 -0
  31. cellects/image_analysis/one_image_analysis_threads.py +289 -0
  32. cellects/image_analysis/progressively_add_distant_shapes.py +508 -0
  33. cellects/image_analysis/shape_descriptors.py +1016 -0
  34. cellects/utils/__init__.py +0 -0
  35. cellects/utils/decorators.py +14 -0
  36. cellects/utils/formulas.py +637 -0
  37. cellects/utils/load_display_save.py +1054 -0
  38. cellects/utils/utilitarian.py +490 -0
  39. cellects-0.1.2.dist-info/LICENSE.odt +0 -0
  40. cellects-0.1.2.dist-info/METADATA +132 -0
  41. cellects-0.1.2.dist-info/RECORD +44 -0
  42. cellects-0.1.2.dist-info/WHEEL +5 -0
  43. cellects-0.1.2.dist-info/entry_points.txt +2 -0
  44. cellects-0.1.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2066 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Genereate the Image analysis window of the user interface of Cellects
4
+
5
+ Cellects transforms the color images into grayscale images in a way that maximizes the contrast between the specimens and the background.
6
+ It has an automatic procedure, processed by the one_image_analysis class. If this automatic procedure does not produce good enough results, the user can manually label some areas of the picture as “cell” or “background” to help find a better color space combination. This is particularly useful when the background is heterogeneous, and Cellects can use this information in two ways: First; it can simply ignore the parts labeled as background (e.g. objects or manual writings). Second, it can use the manual annotation to train a more sophisticated segmentation method: A k-means algorithm to split the image into as many categories as necessary and use the “Cell” labelling to infer to what category the specimens are related to.
7
+ Then, Cellects will take into account the user’s input as follows: For each of the segmentations created in the previous steps, it will count the amount of pixels labeled as specimens by the user that were correctly labeled as cell in the segmentation, and will select the segmentation that achieves the highest number. Then, it will do the same thing for the pixels labeled as background. Then, it will use the AND operator between the two results having the best match with the areas labeled as specimens, the AND operator between the two results having the best match with the areas labeled as background, and the OR operator between the result having the best match with the areas labeled as specimens and the result having the best match with the areas labeled as background. Therefore, this optional labeling adds three new segmentations that take into account the user-labeled regions. If the results are still unsatisfactory, the user can continue labeling more areas until one of the segmentations matches their expectations.
8
+
9
+ """
10
+ import logging
11
+ import time
12
+ from copy import deepcopy
13
+ import numpy as np
14
+ from PySide6 import QtWidgets, QtCore, QtGui
15
+
16
+ from cellects.core.cellects_threads import (
17
+ GetFirstImThread, GetLastImThread, FirstImageAnalysisThread,
18
+ CropScaleSubtractDelineateThread, UpdateImageThread,
19
+ LastImageAnalysisThread, SaveManualDelineationThread, FinalizeImageAnalysisThread)
20
+ from cellects.gui.custom_widgets import (
21
+ MainTabsType, InsertImage, FullScreenImage, PButton, Spinbox,
22
+ Combobox, Checkbox, FixedText)
23
+ from cellects.core.one_image_analysis import OneImageAnalysis
24
+ from cellects.image_analysis.image_segmentation import filter_dict
25
+
26
+
27
+ class ImageAnalysisWindow(MainTabsType):
28
+ def __init__(self, parent, night_mode):
29
+ super().__init__(parent, night_mode)
30
+ self.setParent(parent)
31
+ self.csc_dict = self.parent().po.vars['convert_for_origin'] # To change
32
+ self.manual_delineation_flag: bool = False
33
+
34
+ def true_init(self):
35
+
36
+ logging.info("Initialize ImageAnalysisWindow")
37
+ self.data_tab.set_not_in_use()
38
+ self.image_tab.set_in_use()
39
+ self.video_tab.set_not_usable()
40
+ self.hold_click_flag: bool = False
41
+ self.is_first_image_flag: bool = True
42
+ self.is_image_analysis_running: bool = False
43
+ self.is_image_analysis_display_running: bool = False
44
+ self.asking_first_im_parameters_flag: bool = True
45
+ self.first_im_parameters_answered: bool = False
46
+ self.auto_delineation_flag: bool = False
47
+ self.delineation_done: bool = False
48
+ self.asking_delineation_flag: bool = False
49
+ self.asking_slower_or_manual_delineation_flag: bool = False
50
+ self.slower_delineation_flag: bool = False
51
+ self.asking_last_image_flag: bool = False
52
+ self.step = 0
53
+ self.temporary_mask_coord = []
54
+ self.saved_coord = []
55
+ self.back1_bio2 = 0
56
+ self.bio_masks_number = 0
57
+ self.back_masks_number = 0
58
+ self.arena_masks_number = 0
59
+ self.available_bio_names = np.arange(1, 1000, dtype=np.uint16)
60
+ self.available_back_names = np.arange(1, 1000, dtype=np.uint16)
61
+ self.parent().po.current_combination_id = 0
62
+ greyscale = len(self.parent().po.first_im.shape) == 2
63
+
64
+ self.display_image = np.zeros((self.parent().im_max_width, self.parent().im_max_width, 3), np.uint8)
65
+ self.display_image = InsertImage(self.display_image, self.parent().im_max_height, self.parent().im_max_width)
66
+ self.display_image.mousePressEvent = self.get_click_coordinates
67
+ self.display_image.mouseMoveEvent = self.get_mouse_move_coordinates
68
+ self.display_image.mouseReleaseEvent = self.get_mouse_release_coordinates
69
+
70
+ ## Title
71
+ # self.title_label = FixedText('One Image Analysis', police=30, night_mode=self.parent().po.all['night_mode'])
72
+ # self.title_label.setAlignment(QtCore.Qt.AlignHCenter)
73
+ self.image_number_label = FixedText('Image number',
74
+ tip="Change this number if cells are invisible on the first image, never otherwise\nIf they cannot be seen on the first image, increase this number and read until all cells have appeared.",
75
+ night_mode=self.parent().po.all['night_mode'])
76
+ self.image_number_label.setAlignment(QtCore.Qt.AlignVCenter)
77
+ self.image_number = Spinbox(min=1, max=self.parent().po.vars['img_number'], val=self.parent().po.all['first_detection_frame'], night_mode=self.parent().po.all['night_mode'])
78
+ self.read = PButton("Read", night_mode=self.parent().po.all['night_mode'])
79
+ self.read.clicked.connect(self.read_is_clicked)
80
+
81
+ self.one_blob_per_arena = Checkbox(not self.parent().po.vars['several_blob_per_arena'])
82
+ self.one_blob_per_arena.stateChanged.connect(self.several_blob_per_arena_check)
83
+ self.one_blob_per_arena_label = FixedText("One cell/colony per arena", valign="c",
84
+ tip="Check if there is always only one cell/colony per arena.\nUncheck if each experimental arena can contain several disconnected cells/colonies.",
85
+ night_mode=self.parent().po.all['night_mode'])
86
+
87
+
88
+ self.scale_with_label = FixedText('Scale with:', valign="c",
89
+ tip="What, on the image, should be considered to calculate pixel size in mm",
90
+ night_mode=self.parent().po.all['night_mode'])
91
+ self.scale_with = Combobox(["Image horizontal size", "Cell(s) horizontal size"], night_mode=self.parent().po.all['night_mode'])
92
+ self.scale_with.setFixedWidth(280)
93
+ self.scale_with.setCurrentIndex(self.parent().po.all['scale_with_image_or_cells'])
94
+ self.scale_size_label = FixedText('Scale size:', valign="c",
95
+ tip="True size (in mm) of the item(s) used for scaling",
96
+ night_mode=self.parent().po.all['night_mode'])
97
+ if self.parent().po.all['scale_with_image_or_cells'] == 0:
98
+ self.horizontal_size = Spinbox(min=0, max=100000,
99
+ val=self.parent().po.all['image_horizontal_size_in_mm'],
100
+ night_mode=self.parent().po.all['night_mode'])
101
+ else:
102
+ self.horizontal_size = Spinbox(min=0, max=100000,
103
+ val=self.parent().po.all['starting_blob_hsize_in_mm'],
104
+ night_mode=self.parent().po.all['night_mode'])
105
+ self.horizontal_size.valueChanged.connect(self.horizontal_size_changed)
106
+ self.scale_with.currentTextChanged.connect(self.scale_with_changed)
107
+ self.scale_unit_label = FixedText(' mm', night_mode=self.parent().po.all['night_mode'])
108
+
109
+ # 1) Open the first row layout
110
+ self.row1_widget = QtWidgets.QWidget()
111
+ self.row1_layout = QtWidgets.QHBoxLayout()
112
+ self.row1_layout.addWidget(self.image_number_label)
113
+ self.row1_layout.addWidget(self.image_number)
114
+ self.row1_layout.addWidget(self.read)
115
+ self.row1_layout.addItem(self.horizontal_space)
116
+ self.row1_layout.addWidget(self.one_blob_per_arena_label)
117
+ self.row1_layout.addWidget(self.one_blob_per_arena)
118
+ self.row1_layout.addItem(self.horizontal_space)
119
+ self.row1_layout.addWidget(self.scale_with_label)
120
+ self.row1_layout.addWidget(self.scale_with)
121
+ self.row1_layout.addItem(self.horizontal_space)
122
+ self.row1_layout.addWidget(self.scale_size_label)
123
+ self.row1_layout.addWidget(self.horizontal_size)
124
+
125
+ # self.row1_widget = QtWidgets.QWidget()
126
+ # self.row1_layout = QtWidgets.QHBoxLayout()
127
+ # self.row1_col1_widget = QtWidgets.QWidget()
128
+ # self.row1_col1_layout = QtWidgets.QVBoxLayout()
129
+ # self.row1_col2_widget = QtWidgets.QWidget()
130
+ # self.row1_col2_layout = QtWidgets.QVBoxLayout()
131
+ #
132
+ # self.im_number_widget = QtWidgets.QWidget()
133
+ # self.im_number_layout = QtWidgets.QHBoxLayout()
134
+ # self.im_number_layout.addWidget(self.image_number_label)
135
+ # self.im_number_layout.addWidget(self.image_number)
136
+ # self.im_number_layout.addWidget(self.read)
137
+ # self.im_number_widget.setLayout(self.im_number_layout)
138
+ # self.row1_col1_layout.addWidget(self.im_number_widget)
139
+ #
140
+ # self.specimen_number_widget = QtWidgets.QWidget()
141
+ # self.specimen_number_layout = QtWidgets.QHBoxLayout()
142
+ # self.specimen_number_layout.addWidget(self.one_blob_per_arena)
143
+ # self.specimen_number_layout.addWidget(self.one_blob_per_arena_label)
144
+ # self.specimen_number_widget.setLayout(self.specimen_number_layout)
145
+ # self.row1_col1_layout.addWidget(self.specimen_number_widget)
146
+ # self.row1_col1_widget.setLayout(self.row1_col1_layout)
147
+ # self.row1_layout.addWidget(self.row1_col1_widget)
148
+ #
149
+ # # self.row1_layout.addItem(self.horizontal_space)
150
+ # # self.row1_layout.addWidget(self.title_label)
151
+ # self.row1_layout.addItem(self.horizontal_space)
152
+ #
153
+ # self.scale_with_widget = QtWidgets.QWidget()
154
+ # self.scale_with_layout = QtWidgets.QHBoxLayout()
155
+ # self.scale_with_layout.addWidget(self.scale_with_label)
156
+ # self.scale_with_layout.addWidget(self.scale_with)
157
+ # self.scale_with_widget.setLayout(self.scale_with_layout)
158
+ # self.row1_col2_layout.addWidget(self.scale_with_widget)
159
+ #
160
+ # self.scale_size_widget = QtWidgets.QWidget()
161
+ # self.scale_size_layout = QtWidgets.QHBoxLayout()
162
+ # self.scale_size_layout.addWidget(self.scale_size_label)
163
+ # self.scale_size_layout.addWidget(self.horizontal_size)
164
+ # self.scale_size_widget.setLayout(self.scale_size_layout)
165
+ # self.row1_col2_layout.addWidget(self.scale_size_widget)
166
+ # self.row1_col2_widget.setLayout(self.row1_col2_layout)
167
+ # self.row1_layout.addWidget(self.row1_col2_widget)
168
+
169
+ self.row1_widget.setLayout(self.row1_layout)
170
+ self.Vlayout.addItem(self.vertical_space)
171
+ self.Vlayout.addWidget(self.row1_widget)
172
+ self.Vlayout.addItem(self.vertical_space)
173
+ self.Vlayout.setSpacing(0)
174
+
175
+ # 2) Open the central row layout
176
+ self.central_row_widget = QtWidgets.QWidget()
177
+ self.central_row_layout = QtWidgets.QGridLayout()
178
+ # self.central_row_widget.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
179
+
180
+ # it will contain a) the user drawn lines, b) the image, c) the csc
181
+ # 2)a) the user drawn lines
182
+ self.user_drawn_lines_widget = QtWidgets.QWidget()
183
+ self.user_drawn_lines_layout = QtWidgets.QVBoxLayout()
184
+ self.user_drawn_lines_label = FixedText("Select and draw:",
185
+ tip='By holding down mouse button on the image',
186
+ night_mode=self.parent().po.all['night_mode'])
187
+ self.user_drawn_lines_label.setAlignment(QtCore.Qt.AlignHCenter)
188
+ self.user_drawn_lines_layout.addWidget(self.user_drawn_lines_label)
189
+ self.pbuttons_widget = QtWidgets.QWidget()
190
+ self.pbuttons_layout = QtWidgets.QHBoxLayout()
191
+ self.cell = PButton("Cell", False, night_mode=self.parent().po.all['night_mode'])
192
+ self.cell.setFixedWidth(150)
193
+ self.background = PButton("Back", False, night_mode=self.parent().po.all['night_mode'])
194
+ self.background.setFixedWidth(150)
195
+ self.cell.clicked.connect(self.cell_is_clicked)
196
+ self.background.clicked.connect(self.background_is_clicked)
197
+ self.pbuttons_layout.addWidget(self.cell)
198
+ self.pbuttons_layout.addWidget(self.background)
199
+ self.pbuttons_widget.setLayout(self.pbuttons_layout)
200
+ self.user_drawn_lines_layout.addWidget(self.pbuttons_widget)
201
+
202
+ self.pbuttons_tables_widget = QtWidgets.QWidget()
203
+ self.pbuttons_tables_layout = QtWidgets.QHBoxLayout()
204
+ self.pbuttons_tables_layout.setAlignment(QtCore.Qt.AlignHCenter)
205
+ self.bio_pbuttons_table = QtWidgets.QScrollArea()#QTableWidget() # Scroll Area which contains the widgets, set as the centralWidget
206
+ self.bio_pbuttons_table.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
207
+ # self.bio_pbuttons_table.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
208
+ self.bio_pbuttons_table.setMinimumHeight(self.parent().im_max_height // 2)
209
+ self.bio_pbuttons_table.setFrameShape(QtWidgets.QFrame.NoFrame)
210
+ self.bio_pbuttons_table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
211
+ # self.bio_pbuttons_table.setColumnCount(1)
212
+ # self.bio_pbuttons_table.verticalHeader().hide()
213
+ # self.bio_pbuttons_table.horizontalHeader().hide()
214
+ self.back_pbuttons_table = QtWidgets.QScrollArea()#QTableWidget() # Scroll Area which contains the widgets, set as the centralWidget
215
+ self.back_pbuttons_table.setMinimumHeight(self.parent().im_max_height // 2)
216
+ self.back_pbuttons_table.setFrameShape(QtWidgets.QFrame.NoFrame)
217
+ # self.back_pbuttons_table.setShowGrid(False)
218
+ self.back_pbuttons_table.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
219
+ # self.back_pbuttons_table.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
220
+ self.back_pbuttons_table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
221
+ # self.back_pbuttons_table.setColumnCount(1)
222
+ # self.back_pbuttons_table.verticalHeader().hide()
223
+ # self.back_pbuttons_table.horizontalHeader().hide()
224
+
225
+ self.bio_added_lines_widget = QtWidgets.QWidget()
226
+ self.back_added_lines_widget = QtWidgets.QWidget()
227
+ self.bio_added_lines_layout = QtWidgets.QVBoxLayout()
228
+ self.back_added_lines_layout = QtWidgets.QVBoxLayout()
229
+ self.back_added_lines_widget.setLayout(self.back_added_lines_layout)
230
+ self.bio_added_lines_widget.setLayout(self.bio_added_lines_layout)
231
+ self.bio_pbuttons_table.setWidget(self.bio_added_lines_widget)
232
+ self.back_pbuttons_table.setWidget(self.back_added_lines_widget)
233
+ self.bio_pbuttons_table.setWidgetResizable(True)
234
+ self.back_pbuttons_table.setWidgetResizable(True)
235
+
236
+ self.pbuttons_tables_layout.addWidget(self.bio_pbuttons_table)
237
+ self.pbuttons_tables_layout.addWidget(self.back_pbuttons_table)
238
+ self.pbuttons_tables_widget.setLayout(self.pbuttons_tables_layout)
239
+ self.user_drawn_lines_layout.addWidget(self.pbuttons_tables_widget)
240
+
241
+ # self.added_lines_widget = QtWidgets.QWidget()
242
+ # self.added_lines_layout = QtWidgets.QHBoxLayout()
243
+ # self.bio_added_lines_widget = QtWidgets.QWidget()
244
+ # self.bio_added_lines_layout = QtWidgets.QVBoxLayout()
245
+ # self.back_added_lines_widget = QtWidgets.QWidget()
246
+ # self.back_added_lines_layout = QtWidgets.QVBoxLayout()
247
+ # # Dynamically add the lines
248
+ self.bio_lines = {}
249
+ self.back_lines = {}
250
+ self.arena_lines = {}
251
+ # self.bio_added_lines_widget.setLayout(self.bio_added_lines_layout)
252
+ # self.back_added_lines_widget.setLayout(self.back_added_lines_layout)
253
+ # self.added_lines_layout.addWidget(self.bio_added_lines_widget)
254
+ # self.added_lines_layout.addWidget(self.back_added_lines_widget)
255
+ # self.added_lines_widget.setLayout(self.added_lines_layout)
256
+ # self.user_drawn_lines_layout.addWidget(self.added_lines_widget)
257
+ # self.user_drawn_lines_layout.addItem(self.vertical_space)
258
+
259
+ self.user_drawn_lines_widget.setLayout(self.user_drawn_lines_layout)
260
+ # self.user_drawn_lines_widget.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
261
+ # self.user_drawn_lines_widget.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
262
+ self.user_drawn_lines_widget.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
263
+ # self.user_drawn_lines_widget.setFixedWidth(450)
264
+ self.central_row_layout.addWidget(self.user_drawn_lines_widget, 0, 0)
265
+
266
+ # 2)b) the image
267
+ # self.central_row_layout.columnStretch(1)
268
+ self.central_row_layout.addWidget(self.display_image, 0, 1)
269
+ # self.central_row_layout.columnStretch(2)
270
+
271
+ # Need to create this before self.generate_csc_editing()
272
+ self.message = FixedText("", halign="r", night_mode=self.parent().po.all['night_mode'])
273
+ self.message.setStyleSheet("color: rgb(230, 145, 18)")
274
+
275
+ # 2)c) The csc editing
276
+ self.central_right_widget = QtWidgets.QWidget()
277
+ self.central_right_layout = QtWidgets.QVBoxLayout()
278
+ self.generate_csc_editing()
279
+ self.central_right_layout.addWidget(self.edit_widget)
280
+ self.central_right_widget.setLayout(self.central_right_layout)
281
+ # self.central_right_widget.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
282
+ # self.central_right_widget.setFixedWidth(450)
283
+
284
+ self.central_row_layout.addWidget(self.central_right_widget, 0, 2)
285
+ self.central_row_layout.setAlignment(QtCore.Qt.AlignLeft)
286
+ self.central_row_layout.setAlignment(QtCore.Qt.AlignHCenter)
287
+ # 2) Close the central row layout
288
+ self.central_row_widget.setLayout(self.central_row_layout)
289
+ # self.central_row_widget.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
290
+ # self.central_row_widget.setFixedHeight(self.parent().im_max_height)
291
+ self.Vlayout.addWidget(self.central_row_widget)
292
+ # self.Vlayout.setSpacing(0)
293
+ self.Vlayout.addItem(self.vertical_space)
294
+
295
+ # 3) Add Set supplementary parameters row 1
296
+ self.sup_param_row1_widget = QtWidgets.QWidget()
297
+ self.sup_param_row1_layout = QtWidgets.QHBoxLayout()
298
+ # self.sample_number = Spinbox(min=0, max=255, val=self.parent().po.all['first_folder_sample_number'],
299
+ # decimals=0, night_mode=self.parent().po.all['night_mode'])
300
+ # self.sample_number_label = FixedText("Arena per image", night_mode=self.parent().po.all['night_mode'])
301
+ # self.sample_number.valueChanged.connect(self.sample_number_changed)
302
+
303
+ #HERE
304
+
305
+ # 4) Add Set supplementary parameters row2
306
+ self.sup_param_row2_widget = QtWidgets.QWidget()
307
+ self.sup_param_row2_layout = QtWidgets.QHBoxLayout()
308
+
309
+ self.arena_shape_label = FixedText("Arena shape", night_mode=self.parent().po.all['night_mode'])
310
+ self.arena_shape = Combobox(['circle', 'rectangle'], night_mode=self.parent().po.all['night_mode'])
311
+ self.arena_shape.setFixedWidth(160)
312
+ self.arena_shape.setCurrentText(self.parent().po.vars['arena_shape'])
313
+ self.arena_shape.currentTextChanged.connect(self.arena_shape_changed)
314
+ self.set_spot_shape = Checkbox(self.parent().po.all['set_spot_shape'])
315
+ self.set_spot_shape.stateChanged.connect(self.set_spot_shape_check)
316
+ self.spot_shape_label = FixedText("Set spot shape", tip="horizontal size in mm", night_mode=self.parent().po.all['night_mode'])
317
+ self.spot_shape = Combobox(['circle', 'rectangle'], night_mode=self.parent().po.all['night_mode'])
318
+ self.spot_shape.setFixedWidth(160)
319
+ if self.parent().po.all['starting_blob_shape'] is None:
320
+ self.spot_shape.setCurrentText('circle')
321
+ else:
322
+ self.spot_shape.setCurrentText(self.parent().po.all['starting_blob_shape'])
323
+ self.spot_shape.currentTextChanged.connect(self.spot_shape_changed)
324
+ self.set_spot_size = Checkbox(self.parent().po.all['set_spot_size'])
325
+ self.set_spot_size.stateChanged.connect(self.set_spot_size_check)
326
+ self.spot_size_label = FixedText("Set spot size", night_mode=self.parent().po.all['night_mode'])
327
+ self.spot_size = Spinbox(min=0, max=100000, val=self.parent().po.all['starting_blob_hsize_in_mm'], decimals=2,
328
+ night_mode=self.parent().po.all['night_mode'])
329
+ self.spot_size.valueChanged.connect(self.spot_size_changed)
330
+ self.sup_param_row2_layout.addItem(self.horizontal_space)
331
+ self.sup_param_row2_layout.addWidget(self.arena_shape_label)
332
+ self.sup_param_row2_layout.addWidget(self.arena_shape)
333
+ self.sup_param_row2_layout.addWidget(self.set_spot_shape)
334
+ self.sup_param_row2_layout.addWidget(self.spot_shape_label)
335
+ self.sup_param_row2_layout.addWidget(self.spot_shape)
336
+ self.sup_param_row2_layout.addWidget(self.set_spot_size)
337
+ self.sup_param_row2_layout.addWidget(self.spot_size_label)
338
+ self.sup_param_row2_layout.addWidget(self.spot_size)
339
+ self.sup_param_row2_widget.setLayout(self.sup_param_row2_layout)
340
+ self.sup_param_row2_layout.addItem(self.horizontal_space)
341
+ self.Vlayout.addWidget(self.sup_param_row2_widget)
342
+ self.Vlayout.setSpacing(0)
343
+
344
+ # self.sample_number.setVisible(False)
345
+ # self.sample_number_label.setVisible(False)
346
+ self.one_blob_per_arena.setVisible(True)
347
+ self.one_blob_per_arena_label.setVisible(True)
348
+ self.set_spot_shape.setVisible(False)
349
+ self.spot_shape_label.setVisible(False)
350
+ self.spot_shape.setVisible(False)
351
+ self.arena_shape_label.setVisible(False)
352
+ self.arena_shape.setVisible(False)
353
+ self.set_spot_size.setVisible(False)
354
+ self.spot_size_label.setVisible(False)
355
+ self.spot_size.setVisible(False)
356
+
357
+ # 5) Add the generate option row
358
+ self.generate_analysis_options = FixedText("Generate analysis options: ", night_mode=self.parent().po.all['night_mode'])
359
+ self.quickly = PButton("Quickly", night_mode=self.parent().po.all['night_mode'])
360
+ self.carefully = PButton("Carefully", night_mode=self.parent().po.all['night_mode'])
361
+ self.quickly.clicked.connect(self.quickly_is_clicked)
362
+ self.carefully.clicked.connect(self.carefully_is_clicked)
363
+ self.visualize = PButton('Visualize', night_mode=self.parent().po.all['night_mode'])
364
+ self.visualize.clicked.connect(self.visualize_is_clicked)
365
+ if self.parent().po.vars['already_greyscale']:
366
+ self.visualize_label = FixedText("Directly: ", night_mode=self.parent().po.all['night_mode'])
367
+ else:
368
+ self.visualize_label = FixedText("Or directly: ", night_mode=self.parent().po.all['night_mode'])
369
+
370
+ self.sup_param_row1_layout.addWidget(self.generate_analysis_options)
371
+ self.sup_param_row1_layout.addWidget(self.quickly)
372
+ self.sup_param_row1_layout.addWidget(self.carefully)
373
+ self.sup_param_row1_layout.addItem(self.horizontal_space)
374
+ # self.sup_param_row1_layout.addWidget(self.sample_number)
375
+ # self.sup_param_row1_layout.addWidget(self.sample_number_label)
376
+ self.sup_param_row1_layout.addItem(self.horizontal_space)
377
+ self.sup_param_row1_layout.addWidget(self.visualize_label)
378
+ self.sup_param_row1_layout.addWidget(self.visualize)
379
+
380
+ self.sup_param_row1_widget.setLayout(self.sup_param_row1_layout)
381
+ self.Vlayout.addWidget(self.sup_param_row1_widget)
382
+ self.Vlayout.setSpacing(0)
383
+
384
+ # 6) Open the choose best option row layout
385
+ self.options_row_widget = QtWidgets.QWidget()
386
+ self.options_row_layout = QtWidgets.QHBoxLayout()
387
+ self.select_option_label = FixedText('Select option to read', tip='Select the option allowing the best segmentation between the cell and the background',
388
+ night_mode=self.parent().po.all['night_mode'])
389
+ self.select_option = Combobox([], night_mode=self.parent().po.all['night_mode'])
390
+ if self.parent().po.vars['color_number'] == 2:
391
+ self.select_option.setCurrentIndex(self.parent().po.all['video_option'])
392
+ self.select_option.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
393
+ # self.select_option.setFixedWidth(120)
394
+ self.select_option.setMinimumWidth(145)
395
+ self.select_option.currentTextChanged.connect(self.option_changed)
396
+ self.n_shapes_detected = FixedText(f'', night_mode=self.parent().po.all['night_mode'])
397
+ self.select_option_label.setVisible(False)
398
+ self.select_option.setVisible(False)
399
+ self.n_shapes_detected.setVisible(False)
400
+ self.options_row_layout.addItem(self.horizontal_space)
401
+ self.options_row_layout.addWidget(self.select_option_label)
402
+ self.options_row_layout.addWidget(self.select_option)
403
+ self.options_row_layout.addWidget(self.n_shapes_detected)
404
+ self.options_row_layout.addItem(self.horizontal_space)
405
+ self.options_row_widget.setLayout(self.options_row_layout)
406
+ self.Vlayout.addWidget(self.options_row_widget)
407
+ self.Vlayout.setSpacing(0)
408
+
409
+ # 7) Open decision row layout
410
+ self.decision_row_widget = QtWidgets.QWidget()
411
+ self.decision_row_layout = QtWidgets.QHBoxLayout()
412
+ self.decision_label = FixedText("", night_mode=self.parent().po.all['night_mode'])
413
+ self.yes = PButton("Yes", night_mode=self.parent().po.all['night_mode'])
414
+ self.yes.clicked.connect(self.when_yes_is_clicked)
415
+ self.no = PButton("No", night_mode=self.parent().po.all['night_mode'])
416
+ self.no.clicked.connect(self.when_no_is_clicked)
417
+
418
+ self.decision_label.setVisible(False)
419
+ self.yes.setVisible(False)
420
+ self.no.setVisible(False)
421
+ self.decision_row_layout.addItem(self.horizontal_space)
422
+ self.decision_row_layout.addWidget(self.decision_label)
423
+ self.decision_row_layout.addWidget(self.yes)
424
+ self.decision_row_layout.addWidget(self.no)
425
+ self.decision_row_layout.addItem(self.horizontal_space)
426
+ self.decision_row_widget.setLayout(self.decision_row_layout)
427
+ self.Vlayout.addWidget(self.decision_row_widget)
428
+
429
+ # 8) Open the special cases layout
430
+ self.special_cases_widget = QtWidgets.QWidget()
431
+ self.special_cases_layout = QtWidgets.QHBoxLayout()
432
+ self.starting_differs_from_growing_cb = Checkbox(self.parent().po.vars['origin_state'] == 'constant')
433
+ self.starting_differs_from_growing_cb.stateChanged.connect(self.starting_differs_from_growing_check)
434
+ self.starting_differs_from_growing_label = FixedText("Check if the starting area differs from the growing area", tip="This option is only relevant for experiments in which the medium\n(e.g. agar) on which the cells grow is heterogeneous.\nMore precisely when the exploration areas on which the cells will grow and/or move\nare not the same color as the one they were initially on.", night_mode=self.parent().po.all['night_mode'])
435
+ self.starting_differs_from_growing_cb.setVisible(False)
436
+ self.starting_differs_from_growing_label.setVisible(False)
437
+ self.special_cases_layout.addWidget(self.starting_differs_from_growing_cb)
438
+ self.special_cases_layout.addWidget(self.starting_differs_from_growing_label)
439
+ self.special_cases_widget.setLayout(self.special_cases_layout)
440
+ self.Vlayout.addWidget(self.special_cases_widget)
441
+
442
+ self.Vlayout.setSpacing(0)
443
+
444
+ # 9) Open the last row layout
445
+ self.last_row_widget = QtWidgets.QWidget()
446
+ self.last_row_layout = QtWidgets.QHBoxLayout()
447
+ self.previous = PButton('Previous', night_mode=self.parent().po.all['night_mode'])
448
+ self.previous.clicked.connect(self.previous_is_clicked)
449
+ self.data_tab.clicked.connect(self.data_is_clicked)
450
+ self.video_tab.clicked.connect(self.video_is_clicked)
451
+ self.next = PButton("Next", night_mode=self.parent().po.all['night_mode'])
452
+ self.next.setVisible(False)
453
+ self.next.clicked.connect(self.go_to_next_widget)
454
+ self.last_row_layout.addWidget(self.previous)
455
+ self.last_row_layout.addWidget(self.message)
456
+ self.last_row_layout.addItem(self.horizontal_space)
457
+ self.last_row_layout.addWidget(self.next)
458
+ self.last_row_widget.setLayout(self.last_row_layout)
459
+ self.Vlayout.addWidget(self.last_row_widget)
460
+ self.setLayout(self.Vlayout)
461
+ self.Vlayout.setSpacing(0)
462
+
463
+ self.advanced_mode_check()
464
+
465
+ self.thread = {}
466
+ self.thread["GetFirstIm"] = GetFirstImThread(self.parent())
467
+ # self.thread["GetFirstIm"].start()
468
+ # self.thread["GetFirstIm"].message_when_thread_finished.connect(self.first_im_read)
469
+ self.reinitialize_image_and_masks(self.parent().po.first_im)
470
+ self.thread["GetLastIm"] = GetLastImThread(self.parent())
471
+ self.thread["GetLastIm"].start()
472
+ self.parent().po.first_image = OneImageAnalysis(self.parent().po.first_im)
473
+ self.thread["FirstImageAnalysis"] = FirstImageAnalysisThread(self.parent())
474
+ self.thread["LastImageAnalysis"] = LastImageAnalysisThread(self.parent())
475
+ self.thread['UpdateImage'] = UpdateImageThread(self.parent())
476
+ self.thread['CropScaleSubtractDelineate'] = CropScaleSubtractDelineateThread(self.parent())
477
+ self.thread['SaveManualDelineation'] = SaveManualDelineationThread(self.parent())
478
+ self.thread['FinalizeImageAnalysis'] = FinalizeImageAnalysisThread(self.parent())
479
+
480
+ def previous_is_clicked(self):
481
+ if self.is_image_analysis_running:
482
+ self.message.setText("Wait for the analysis to end, or restart Cellects")
483
+ else:
484
+ self.parent().firstwindow.instantiate = True
485
+ self.hold_click_flag: bool = False
486
+ self.is_first_image_flag: bool = True
487
+ self.is_image_analysis_running: bool = False
488
+ self.is_image_analysis_display_running: bool = False
489
+ self.asking_first_im_parameters_flag: bool = True
490
+ self.first_im_parameters_answered: bool = False
491
+ self.auto_delineation_flag: bool = False
492
+ self.delineation_done: bool = False
493
+ self.asking_delineation_flag: bool = False
494
+ self.asking_slower_or_manual_delineation_flag: bool = False
495
+ self.slower_delineation_flag: bool = False
496
+ self.asking_last_image_flag: bool = False
497
+ self.step = 0
498
+ self.temporary_mask_coord = []
499
+ self.saved_coord = []
500
+ self.back1_bio2 = 0
501
+ self.bio_masks_number = 0
502
+ self.back_masks_number = 0
503
+ self.arena_masks_number = 0
504
+ self.available_bio_names = np.arange(1, 1000, dtype=np.uint16)
505
+ self.available_back_names = np.arange(1, 1000, dtype=np.uint16)
506
+ self.parent().po.current_combination_id = 0
507
+ self.parent().last_tab = "data_specifications"
508
+ self.parent().change_widget(0) # First
509
+
510
+ def data_is_clicked(self):
511
+ if self.is_image_analysis_running:
512
+ self.message.setText("Wait for the analysis to end, or restart Cellects")
513
+ else:
514
+ self.parent().last_tab = "data_specifications"
515
+ self.parent().change_widget(0) # First
516
+
517
+ def video_is_clicked(self):
518
+
519
+ if self.video_tab.state != "not_usable":
520
+ if self.is_image_analysis_running:
521
+ self.message.setText("Wait for the analysis to end, or restart Cellects")
522
+ else:
523
+ self.parent().last_tab = "image_analysis"
524
+ self.parent().change_widget(3)
525
+
526
+ def read_is_clicked(self):
527
+ if not self.thread["GetFirstIm"].isRunning():
528
+ self.parent().po.all['first_detection_frame'] = int(self.image_number.value())
529
+ self.message.setText(f"Reading image n°{self.parent().po.all['first_detection_frame']}")
530
+ self.thread["GetFirstIm"].start()
531
+ # self.thread["GetFirstIm"].message_when_thread_finished.connect(self.reinitialize_image_and_masks)
532
+ self.reinitialize_bio_and_back_legend()
533
+ self.reinitialize_image_and_masks(self.parent().po.first_im)
534
+
535
+
536
+ def several_blob_per_arena_check(self):
537
+ is_checked = self.one_blob_per_arena.isChecked()
538
+ self.parent().po.vars['several_blob_per_arena'] = not is_checked
539
+ self.set_spot_size.setVisible(is_checked)
540
+ self.spot_size_label.setVisible(is_checked)
541
+ self.spot_size.setVisible(is_checked and self.set_spot_size.isChecked())
542
+
543
+ def set_spot_size_check(self):
544
+ is_checked = self.set_spot_size.isChecked()
545
+ if self.step == 1:
546
+ self.spot_size.setVisible(is_checked)
547
+ self.parent().po.all['set_spot_size'] = is_checked
548
+
549
+ def spot_size_changed(self):
550
+ self.parent().po.all['starting_blob_hsize_in_mm'] = self.spot_size.value()
551
+ if self.parent().po.all['scale_with_image_or_cells'] == 1:
552
+ self.horizontal_size.setValue(self.parent().po.all['starting_blob_hsize_in_mm'])
553
+ self.set_spot_size_check()
554
+
555
+ def set_spot_shape_check(self):
556
+ is_checked = self.set_spot_shape.isChecked()
557
+ self.spot_shape.setVisible(is_checked)
558
+ self.parent().po.all['set_spot_shape'] = is_checked
559
+ if not is_checked:
560
+ self.parent().po.all['starting_blob_shape'] = None
561
+
562
+ def spot_shape_changed(self):
563
+ self.parent().po.all['starting_blob_shape'] = self.spot_shape.currentText()
564
+ self.set_spot_shape_check()
565
+
566
+ def arena_shape_changed(self):
567
+ self.parent().po.vars['arena_shape'] = self.arena_shape.currentText()
568
+ if self.asking_delineation_flag:
569
+ if self.thread['CropScaleSubtractDelineate'].isRunning():
570
+ self.thread['CropScaleSubtractDelineate'].wait()
571
+ if self.thread['UpdateImage'].isRunning():
572
+ self.thread['UpdateImage'].wait()
573
+ self.message.setText("Updating display...")
574
+ self.decision_label.setVisible(False)
575
+ self.yes.setVisible(False)
576
+ self.no.setVisible(False)
577
+ self.reinitialize_bio_and_back_legend()
578
+ self.reinitialize_image_and_masks(self.parent().po.first_image.bgr)
579
+ self.delineation_done = True
580
+ if self.thread["UpdateImage"].isRunning():
581
+ self.thread["UpdateImage"].wait()
582
+ self.thread["UpdateImage"].start()
583
+ self.thread["UpdateImage"].message_when_thread_finished.connect(self.automatic_delineation_display_done)
584
+
585
+ # self.start_crop_scale_subtract_delineate()
586
+
587
+ def reinitialize_bio_and_back_legend(self):
588
+ lines_names_to_remove = []
589
+ for line_number, back_line_dict in self.back_lines.items():
590
+ line_name = u"\u00D7" + " Back" + str(line_number)
591
+ self.back_added_lines_layout.removeWidget(back_line_dict[line_name])
592
+ back_line_dict[line_name].deleteLater()
593
+ lines_names_to_remove.append(line_number)
594
+ for line_number in lines_names_to_remove:
595
+ self.back_lines.pop(line_number)
596
+ lines_names_to_remove = []
597
+ for line_number, bio_line_dict in self.bio_lines.items():
598
+ line_name = u"\u00D7" + " Cell" + str(line_number)
599
+ self.bio_added_lines_layout.removeWidget(bio_line_dict[line_name])
600
+ bio_line_dict[line_name].deleteLater()
601
+ lines_names_to_remove.append(line_number)
602
+ for line_number in lines_names_to_remove:
603
+ self.bio_lines.pop(line_number)
604
+ if len(self.arena_lines) > 0:
605
+ lines_names_to_remove = []
606
+ for i, (line_number, arena_line_dict) in enumerate(self.arena_lines.items()):
607
+ line_name = u"\u00D7" + " Arena" + str(line_number)
608
+ if i % 2 == 0:
609
+ self.bio_added_lines_layout.removeWidget(arena_line_dict[line_name])
610
+ else:
611
+ self.back_added_lines_layout.removeWidget(arena_line_dict[line_name])
612
+ arena_line_dict[line_name].deleteLater()
613
+ lines_names_to_remove.append(line_number)
614
+ for line_number in lines_names_to_remove:
615
+ self.arena_lines.pop(line_number)
616
+ self.bio_masks_number = 0
617
+ self.back_masks_number = 0
618
+
619
+ def reinitialize_image_and_masks(self, image):
620
+ if len(image.shape) == 2:
621
+ self.parent().po.current_image = np.stack((image, image, image), axis=2)
622
+
623
+ self.generate_analysis_options.setVisible(False)
624
+ self.quickly.setVisible(False)
625
+ self.carefully.setVisible(False)
626
+ self.select_option.setVisible(False)
627
+ self.select_option_label.setVisible(False)
628
+ self.visualize.setVisible(True)
629
+ self.visualize_label.setVisible(True)
630
+ else:
631
+ self.parent().po.current_image = deepcopy(image)
632
+ self.drawn_image = deepcopy(self.parent().po.current_image)
633
+ self.display_image.update_image(self.parent().po.current_image)
634
+
635
+ self.arena_mask = None
636
+ self.bio_mask = np.zeros(self.parent().po.current_image.shape[:2], dtype=np.uint16)
637
+ self.back_mask = np.zeros(self.parent().po.current_image.shape[:2], dtype=np.uint16)
638
+
639
+ def scale_with_changed(self):
640
+ self.parent().po.all['scale_with_image_or_cells'] = self.scale_with.currentIndex()
641
+ if self.parent().po.all['scale_with_image_or_cells'] == 0:
642
+ self.horizontal_size.setValue(self.parent().po.all['image_horizontal_size_in_mm'])
643
+ else:
644
+ self.horizontal_size.setValue(self.parent().po.all['starting_blob_hsize_in_mm'])
645
+
646
+ def horizontal_size_changed(self):
647
+ if self.parent().po.all['scale_with_image_or_cells'] == 0:
648
+ self.parent().po.all['image_horizontal_size_in_mm'] = self.horizontal_size.value()
649
+ else:
650
+ self.parent().po.all['starting_blob_hsize_in_mm'] = self.horizontal_size.value()
651
+ self.spot_size.setValue(self.parent().po.all['starting_blob_hsize_in_mm'])
652
+
653
+ def advanced_mode_check(self):
654
+ is_checked = self.advanced_mode_cb.isChecked()
655
+ color_analysis = is_checked and not self.parent().po.vars['already_greyscale']
656
+ self.parent().po.all['expert_mode'] = is_checked
657
+
658
+ if is_checked and (self.asking_first_im_parameters_flag or self.auto_delineation_flag):
659
+ self.arena_shape_label.setVisible(True)
660
+ self.arena_shape.setVisible(True)
661
+ self.set_spot_shape.setVisible(True)
662
+ self.spot_shape_label.setVisible(True)
663
+ self.spot_shape.setVisible(self.set_spot_shape.isChecked())
664
+ self.set_spot_size.setVisible(self.one_blob_per_arena.isChecked())
665
+ self.spot_size_label.setVisible(self.one_blob_per_arena.isChecked())
666
+ self.spot_size.setVisible(
667
+ self.one_blob_per_arena.isChecked() and self.set_spot_size.isChecked())
668
+ self.first_im_parameters_answered = True
669
+
670
+ self.space_label.setVisible(color_analysis)
671
+ # self.c1.setVisible(color_analysis)
672
+ # self.c2.setVisible(color_analysis)
673
+ # self.c3.setVisible(color_analysis)
674
+ display_logical = self.logical_operator_between_combination_result.currentText() != 'None'
675
+ self.logical_operator_between_combination_result.setVisible(color_analysis and display_logical)
676
+ self.logical_operator_label.setVisible(color_analysis and display_logical)
677
+
678
+ # if not self.parent().po.vars['already_greyscale']:
679
+ # self.visualize.setVisible(is_checked)
680
+ # self.visualize_label.setVisible(is_checked)
681
+ at_least_one_line_drawn = self.bio_masks_number > 0
682
+ self.more_than_two_colors.setVisible(is_checked and at_least_one_line_drawn)
683
+ self.more_than_two_colors_label.setVisible(is_checked and at_least_one_line_drawn)
684
+ self.distinct_colors_number.setVisible(is_checked and at_least_one_line_drawn and self.parent().po.all["more_than_two_colors"])
685
+
686
+ # Check whether filter 1 and its potential parameters should be visible
687
+ self.filter1.setVisible(is_checked)
688
+ self.filter1_label.setVisible(is_checked)
689
+ has_param1 = is_checked and 'Param1' in filter_dict[self.filter1.currentText()]
690
+ self.filter1_param1.setVisible(has_param1)
691
+ self.filter1_param1_label.setVisible(has_param1)
692
+ has_param2 = is_checked and 'Param2' in filter_dict[self.filter1.currentText()]
693
+ self.filter1_param2.setVisible(has_param2)
694
+ self.filter1_param2_label.setVisible(has_param2)
695
+
696
+ # Check whether filter 2 and its potential parameters should be visible
697
+ self.filter2.setVisible(is_checked and at_least_one_line_drawn)
698
+ self.filter2_label.setVisible(is_checked and at_least_one_line_drawn)
699
+ has_param1 = is_checked and at_least_one_line_drawn and 'Param1' in filter_dict[self.filter2.currentText()]
700
+ self.filter2_param1.setVisible(has_param1)
701
+ self.filter2_param1_label.setVisible(has_param1)
702
+ has_param2 = is_checked and at_least_one_line_drawn and 'Param2' in filter_dict[self.filter2.currentText()]
703
+ self.filter2_param2.setVisible(has_param2)
704
+ self.filter2_param2_label.setVisible(has_param2)
705
+
706
+ self.filter1_param1.setVisible(is_checked)
707
+ self.grid_segmentation.setVisible(is_checked)
708
+ self.grid_segmentation_label.setVisible(is_checked)
709
+
710
+ for i in range(5):
711
+ self.row1[i].setVisible(color_analysis and self.row1[0].currentText() != "None")
712
+ self.row21[i].setVisible(color_analysis and self.row21[0].currentText() != "None")
713
+ self.row2[i].setVisible(color_analysis and self.row2[0].currentText() != "None")
714
+ self.row22[i].setVisible(color_analysis and self.row22[0].currentText() != "None")
715
+ if i < 4:
716
+ self.row3[i].setVisible(color_analysis and self.row3[0].currentText() != "None")
717
+ self.row23[i].setVisible(color_analysis and self.row23[0].currentText() != "None")
718
+ if color_analysis:
719
+ if self.row1[0].currentText() != "None":
720
+ if self.row2[0].currentText() == "None":
721
+ self.row1[4].setVisible(True)
722
+ else:
723
+ self.row2[4].setVisible(True)
724
+ if self.row21[0].currentText() != "None":
725
+ if self.row22[0].currentText() == "None":
726
+ self.row21[4].setVisible(True)
727
+ else:
728
+ self.row22[4].setVisible(True)
729
+ else:
730
+ self.row1[4].setVisible(False)
731
+ self.row2[4].setVisible(False)
732
+ self.row21[4].setVisible(False)
733
+ self.row22[4].setVisible(False)
734
+
735
+ def cell_is_clicked(self):
736
+ if self.back1_bio2 == 2:
737
+ self.cell.night_mode_switch(night_mode=self.parent().po.all['night_mode'])
738
+ self.back1_bio2 = 0
739
+ else:
740
+ self.cell.color("rgb(230, 145, 18)")
741
+ self.background.night_mode_switch(night_mode=self.parent().po.all['night_mode'])
742
+ self.back1_bio2 = 2
743
+ self.saved_coord = []
744
+
745
+ def background_is_clicked(self):
746
+ if self.back1_bio2 == 1:
747
+ self.background.night_mode_switch(night_mode=self.parent().po.all['night_mode'])
748
+ self.back1_bio2 = 0
749
+ else:
750
+ self.background.color("rgb(81, 160, 224)")
751
+ self.cell.night_mode_switch(night_mode=self.parent().po.all['night_mode'])
752
+ self.back1_bio2 = 1
753
+ self.saved_coord = []
754
+
755
+ def get_click_coordinates(self, event):
756
+ if self.back1_bio2 > 0 or self.manual_delineation_flag:
757
+ if not self.is_image_analysis_display_running and not self.thread["UpdateImage"].isRunning():
758
+ self.hold_click_flag = True
759
+ self.saved_coord.append([event.pos().y(), event.pos().x()])
760
+ else:
761
+ self.popup_img = FullScreenImage(self.drawn_image, self.parent().screen_width, self.parent().screen_height)
762
+ self.popup_img.show()
763
+ # img = resize(self.drawn_image, (self.parent().screen_width, self.parent().screen_height))
764
+ # cv2.imshow("Full screen image display", img)
765
+ # waitKey(0)
766
+ # destroyAllWindows()
767
+
768
+ def get_mouse_move_coordinates(self, event):
769
+ # if not self.is_image_analysis_display_running:
770
+ # if self.back1_bio2 > 0 or self.manual_delineation_flag:
771
+ # if not self.thread["UpdateImage"].isRunning() and len(self.saved_coord) > 0:
772
+ # if self.saved_coord[0][0] != event.pos().y() and self.saved_coord[0][1] != event.pos().x():
773
+ # self.temporary_mask_coord = [self.saved_coord[0], [event.pos().y(), event.pos().x()]]
774
+ # self.thread["UpdateImage"].start()
775
+ if self.hold_click_flag:
776
+ if not self.thread["UpdateImage"].isRunning():
777
+ if self.saved_coord[0][0] != event.pos().y() and self.saved_coord[0][1] != event.pos().x():
778
+ self.temporary_mask_coord = [self.saved_coord[0], [event.pos().y(), event.pos().x()]]
779
+ self.thread["UpdateImage"].start()
780
+
781
+ def get_mouse_release_coordinates(self, event):
782
+ if self.hold_click_flag:
783
+ if self.thread["UpdateImage"].isRunning():
784
+ self.thread["UpdateImage"].wait()
785
+ # self.saved_coord = []
786
+ # self.background.night_mode_switch(night_mode=self.parent().po.all['night_mode'])
787
+ # self.background.night_mode_switch(night_mode=self.parent().po.all['night_mode'])
788
+ # self.back1_bio2 = 0
789
+ self.temporary_mask_coord = []
790
+ if self.manual_delineation_flag and len(self.parent().imageanalysiswindow.available_arena_names) == 0:
791
+ self.message.setText(f"The total number of arenas are already drawn ({self.parent().po.sample_number})")
792
+ self.saved_coord = []
793
+ else:
794
+ self.saved_coord.append([event.pos().y(), event.pos().x()])
795
+ self.thread["UpdateImage"].start()
796
+ self.thread["UpdateImage"].message_when_thread_finished.connect(self.user_defined_shape_displayed)
797
+ self.hold_click_flag = False
798
+
799
+
800
+ # if not self.is_image_analysis_display_running:
801
+ # if self.back1_bio2 > 0 or self.manual_delineation_flag:
802
+ # if len(self.saved_coord) > 0 and self.saved_coord[0][0] != event.pos().y() and self.saved_coord[0][1] != event.pos().x():
803
+ # if self.thread["UpdateImage"].isRunning():
804
+ # self.thread["UpdateImage"].wait()
805
+ # self.temporary_mask_coord = []
806
+ # if self.manual_delineation_flag and len(self.parent().imageanalysiswindow.available_arena_names) == 0:
807
+ # self.message.setText(f"The total number of arenas are already drawn ({self.parent().po.sample_number})")
808
+ # self.saved_coord = []
809
+ # else:
810
+ # self.saved_coord.append([event.pos().y(), event.pos().x()])
811
+ # self.thread["UpdateImage"].start()
812
+ # self.thread["UpdateImage"].message_when_thread_finished.connect(self.user_defined_shape_displayed)
813
+
814
+ def user_defined_shape_displayed(self, boole):
815
+ if self.back1_bio2 == 1:
816
+ back_name = self.parent().imageanalysiswindow.available_back_names[0]
817
+ self.back_lines[back_name] = {}
818
+ pbutton_name = u"\u00D7" + " Back" + str(back_name)
819
+ self.back_lines[back_name][pbutton_name] = self.new_pbutton_on_the_left(pbutton_name)
820
+ self.back_added_lines_layout.addWidget(self.back_lines[back_name][pbutton_name])
821
+ self.background.night_mode_switch(night_mode=self.parent().po.all['night_mode'])
822
+ self.available_back_names = self.available_back_names[1:]
823
+ elif self.back1_bio2 == 2:
824
+ bio_name = self.parent().imageanalysiswindow.available_bio_names[0]
825
+ self.bio_lines[bio_name] = {}
826
+ pbutton_name = u"\u00D7" + " Cell" + str(bio_name)
827
+ self.bio_lines[bio_name][pbutton_name] = self.new_pbutton_on_the_left(pbutton_name)
828
+ self.bio_added_lines_layout.addWidget(self.bio_lines[bio_name][pbutton_name])
829
+ self.cell.night_mode_switch(night_mode=self.parent().po.all['night_mode'])
830
+ self.available_bio_names = self.available_bio_names[1:]
831
+ if self.bio_masks_number == 0:
832
+ self.display_more_than_two_colors_option()
833
+
834
+ self.more_than_two_colors.setVisible(self.advanced_mode_cb.isChecked())
835
+ self.more_than_two_colors_label.setVisible(self.advanced_mode_cb.isChecked())
836
+ self.distinct_colors_number.setVisible(self.advanced_mode_cb.isChecked() and self.more_than_two_colors.isChecked())
837
+ elif self.manual_delineation_flag:
838
+ arena_name = self.parent().imageanalysiswindow.available_arena_names[0]
839
+ self.arena_lines[arena_name] = {}
840
+ pbutton_name = u"\u00D7" + " Arena" + str(arena_name)
841
+ self.arena_lines[arena_name][pbutton_name] = self.new_pbutton_on_the_left(pbutton_name)
842
+ if self.arena_masks_number % 2 == 1:
843
+ self.bio_added_lines_layout.addWidget(self.arena_lines[arena_name][pbutton_name])
844
+ else:
845
+ self.back_added_lines_layout.addWidget(self.arena_lines[arena_name][pbutton_name])
846
+ self.available_arena_names = self.available_arena_names[1:]
847
+ self.saved_coord = []
848
+ self.back1_bio2 = 0
849
+ try:
850
+ self.thread["UpdateImage"].message_when_thread_finished.disconnect()
851
+ except RuntimeError:
852
+ pass
853
+
854
+ def new_pbutton_on_the_left(self, pbutton_name):
855
+ pbutton = PButton(pbutton_name, False, night_mode=self.parent().po.all['night_mode'])
856
+ pbutton.setFixedHeight(20)
857
+ pbutton.setFixedWidth(100)
858
+ pbutton.setFont(QtGui.QFont("Segoe UI Semibold", 8, QtGui.QFont.Thin))
859
+ pbutton.textcolor("rgb(0, 0, 0)")
860
+ pbutton.border("0px")
861
+ pbutton.angles("10px")
862
+ if self.back1_bio2 == 1:
863
+ pbutton.color("rgb(81, 160, 224)")
864
+ elif self.back1_bio2 == 2:
865
+ pbutton.color("rgb(230, 145, 18)")
866
+ else:
867
+ pbutton.color("rgb(126, 126, 126)")
868
+ pbutton.clicked.connect(self.remove_line)
869
+ return pbutton
870
+
871
+ def remove_line(self):
872
+ if not self.is_image_analysis_display_running and not self.thread["UpdateImage"].isRunning() and hasattr(self.sender(), 'text'):
873
+ pbutton_name = self.sender().text()
874
+ if pbutton_name[2:6] == "Back":
875
+ line_name = np.uint8(pbutton_name[6:])
876
+ self.back_mask[self.back_mask == line_name] = 0
877
+ self.back_added_lines_layout.removeWidget(self.back_lines[line_name][pbutton_name])
878
+ self.back_lines[line_name][pbutton_name].deleteLater()
879
+ self.back_lines.pop(line_name)
880
+ self.back_masks_number -= 1
881
+ self.available_back_names = np.sort(np.concatenate(([line_name], self.available_back_names)))
882
+ # self.back_pbuttons_table.removeRow(line_name - 1)
883
+ elif pbutton_name[2:6] == "Cell":
884
+ line_name = np.uint8(pbutton_name[6:])
885
+ self.bio_mask[self.bio_mask == line_name] = 0
886
+ self.bio_added_lines_layout.removeWidget(self.bio_lines[line_name][pbutton_name])
887
+ self.bio_lines[line_name][pbutton_name].deleteLater()
888
+ self.bio_lines.pop(line_name)
889
+ self.bio_masks_number -= 1
890
+ self.available_bio_names = np.sort(np.concatenate(([line_name], self.available_bio_names)))
891
+ # self.bio_pbuttons_table.removeRow(line_name - 1)
892
+ self.display_more_than_two_colors_option()
893
+ else:
894
+ line_name = np.uint8(pbutton_name[7:])
895
+ self.arena_mask[self.arena_mask == line_name] = 0
896
+ if line_name % 2 == 1:
897
+ self.bio_added_lines_layout.removeWidget(self.arena_lines[line_name][pbutton_name])
898
+ else:
899
+ self.back_added_lines_layout.removeWidget(self.arena_lines[line_name][pbutton_name])
900
+ self.arena_lines[line_name][pbutton_name].deleteLater()
901
+ self.arena_lines.pop(line_name)
902
+
903
+ self.arena_masks_number -= 1
904
+ self.available_arena_names = np.sort(np.concatenate(([line_name], self.available_arena_names)))
905
+ # if line_name % 2 == 1:
906
+ # self.bio_pbuttons_table.removeRow((line_name + 1) // 2)
907
+ # else:
908
+ # self.back_pbuttons_table.removeRow((line_name + 1) // 2)
909
+ # if self.parent().po.first_image.im_combinations is not None:
910
+ # if self.thread["UpdateImage"].isRunning():
911
+ # self.thread["UpdateImage"].wait()
912
+ self.thread["UpdateImage"].start()
913
+
914
+ def quickly_is_clicked(self):
915
+ if not self.is_image_analysis_running:
916
+ self.is_image_analysis_running = True
917
+ self.message.setText('Loading, wait...')
918
+ self.parent().po.carefully = False
919
+ self.parent().po.visualize = False
920
+ if self.is_first_image_flag:
921
+ self.run_first_image_analysis()
922
+ else:
923
+ self.run_last_image_analysis()
924
+
925
+ def carefully_is_clicked(self):
926
+ if not self.is_image_analysis_running:
927
+ self.is_image_analysis_running = True
928
+ self.message.setText('Loading, wait...')
929
+ self.parent().po.carefully = True
930
+ self.parent().po.visualize = False
931
+ if self.is_first_image_flag:
932
+ self.run_first_image_analysis()
933
+ else:
934
+ self.run_last_image_analysis()
935
+
936
+ def visualize_is_clicked(self):
937
+ if not self.is_image_analysis_running:
938
+ self.is_image_analysis_running = True
939
+ self.message.setText('Loading, wait...')
940
+ self.parent().po.visualize = True
941
+ # if self.step == 0:
942
+ # self.select_option_label.setVisible(False)
943
+ # self.select_option.setVisible(False)
944
+ if self.is_first_image_flag:
945
+ self.run_first_image_analysis()
946
+ else:
947
+ self.run_last_image_analysis()
948
+
949
+ def run_first_image_analysis(self):
950
+ # logging.info('runfim' +str(self.parent().po.sample_number))
951
+ if self.first_im_parameters_answered:
952
+ # self.sample_number_changed()
953
+ self.several_blob_per_arena_check()
954
+ self.horizontal_size_changed()
955
+ self.spot_shape_changed()
956
+ self.arena_shape_changed()
957
+ logging.info(self.parent().po.sample_number)
958
+ logging.info(self.parent().po.vars['several_blob_per_arena'])
959
+ logging.info(self.parent().po.all['starting_blob_shape'])
960
+ logging.info(self.parent().po.vars['arena_shape'])
961
+
962
+ if self.parent().po.visualize:
963
+ self.save_user_defined_csc()
964
+ self.parent().po.vars["color_number"] = int(self.distinct_colors_number.value())
965
+ if self.csc_dict_is_empty:
966
+ self.message.setText('Choose a color space, modify a channel and visualize')
967
+ self.message.setStyleSheet("color: rgb(230, 145, 18)")
968
+ if not self.parent().po.visualize or not self.csc_dict_is_empty:
969
+ self.parent().po.vars['convert_for_origin'] = deepcopy(self.csc_dict)
970
+ self.thread["FirstImageAnalysis"].start()
971
+ self.thread["FirstImageAnalysis"].message_from_thread.connect(self.display_message_from_thread)
972
+ self.thread["FirstImageAnalysis"].message_when_thread_finished.connect(self.when_image_analysis_finishes)
973
+
974
+ def run_last_image_analysis(self):
975
+ logging.info('runlim')
976
+ if self.parent().po.visualize:
977
+ self.save_user_defined_csc()
978
+ self.parent().po.vars["color_number"] = int(self.distinct_colors_number.value())
979
+ if self.csc_dict_is_empty:
980
+ self.message.setText('Choose a color space, increase a channel and visualize')
981
+ self.message.setStyleSheet("color: rgb(230, 145, 18)")
982
+ else:
983
+ self.parent().po.vars['convert_for_motion'] = deepcopy(self.csc_dict)
984
+ self.thread["LastImageAnalysis"].start()
985
+ self.thread["LastImageAnalysis"].message_from_thread.connect(self.display_message_from_thread)
986
+ self.thread["LastImageAnalysis"].message_when_thread_finished.connect(
987
+ self.when_image_analysis_finishes)
988
+ else:
989
+ self.thread["LastImageAnalysis"].start()
990
+ self.thread["LastImageAnalysis"].message_from_thread.connect(self.display_message_from_thread)
991
+ self.thread["LastImageAnalysis"].message_when_thread_finished.connect(self.when_image_analysis_finishes)
992
+
993
+ def when_image_analysis_finishes(self):
994
+ logging.info('im_finish' + str(self.parent().po.sample_number))
995
+
996
+ if self.parent().po.visualize:
997
+ if self.parent().po.current_combination_id != self.select_option.currentIndex():
998
+ self.select_option.setCurrentIndex(self.parent().po.current_combination_id)
999
+ else:
1000
+ self.parent().po.current_combination_id = 0
1001
+ if self.is_first_image_flag:
1002
+ im_combinations = self.parent().po.first_image.im_combinations
1003
+ else:
1004
+ im_combinations = self.parent().po.last_image.im_combinations
1005
+ if len(im_combinations) > 0:
1006
+ self.csc_dict = im_combinations[self.parent().po.current_combination_id]["csc"]
1007
+
1008
+ if self.is_first_image_flag:
1009
+ self.parent().po.vars['convert_for_origin'] = deepcopy(self.csc_dict)
1010
+ else:
1011
+ self.parent().po.vars['convert_for_motion'] = deepcopy(self.csc_dict)
1012
+ option_number = len(im_combinations)
1013
+
1014
+ if option_number > 1:
1015
+ # Update the available options of the scrolling menu
1016
+ self.select_option.clear()
1017
+ for option in range(option_number):
1018
+ self.select_option.addItem(f"Option {option + 1}")
1019
+ self.update_csc_editing_display()
1020
+ else:
1021
+ self.message.setText("No options could be generated automatically, use the advanced mode")
1022
+
1023
+ if self.parent().po.visualize or len(im_combinations) > 0:
1024
+ self.is_image_analysis_display_running = True
1025
+ # Update image display
1026
+ if self.thread["UpdateImage"].isRunning():
1027
+ self.thread["UpdateImage"].wait()
1028
+ self.thread["UpdateImage"].start()
1029
+ self.thread["UpdateImage"].message_when_thread_finished.connect(self.image_analysis_displayed)
1030
+
1031
+ def image_analysis_displayed(self):
1032
+ color_analysis = not self.parent().po.vars['already_greyscale']
1033
+ self.message.setText("")
1034
+
1035
+
1036
+ if self.step < 2:
1037
+ detected_shape_nb = self.parent().po.first_image.im_combinations[self.parent().po.current_combination_id][
1038
+ 'shape_number']
1039
+ if detected_shape_nb == self.parent().po.sample_number or self.parent().po.vars['several_blob_per_arena']:
1040
+ self.decision_label.setText(
1041
+ f"{detected_shape_nb} distinct spots detected in {self.parent().po.sample_number} arena(s). Does the color match the cell(s)?")
1042
+ if self.step == 1:
1043
+ self.yes.setVisible(True)
1044
+ self.message.setText("If not, draw more Cell and Back ellipses on the image and retry")
1045
+ else:
1046
+ if self.no.isVisible():
1047
+ self.decision_label.setText(
1048
+ f"{detected_shape_nb} distinct spots detected in {self.parent().po.sample_number} arena(s). Click Yes when satisfied, Click No to fill in more parameters")
1049
+ self.yes.setVisible(True)
1050
+ self.no.setVisible(True)
1051
+ else:
1052
+ self.decision_label.setText(
1053
+ f"{detected_shape_nb} distinct spots detected in {self.parent().po.sample_number} arena(s). Click Yes when satisfied")
1054
+ self.yes.setVisible(True)
1055
+
1056
+ if self.parent().po.vars['several_blob_per_arena'] and (detected_shape_nb == self.parent().po.sample_number):
1057
+ self.message.setText("Beware: Contrary to what has been checked, there is one spot per arena")
1058
+
1059
+ if not self.parent().po.visualize:
1060
+ self.select_option.setVisible(color_analysis)
1061
+ self.select_option_label.setVisible(color_analysis)
1062
+ if self.step == 0:
1063
+ # self.decision_label.setText(f"Does the color correctly cover the cells? And, is {detected_shape_nb} the number of distinct arenas?")
1064
+ if self.parent().po.first_image.im_combinations[self.parent().po.current_combination_id]['shape_number'] == 0:
1065
+ self.message.setText("Make sure that scaling metric and spot size are correct")
1066
+ self.decision_label.setVisible(True)
1067
+ self.yes.setVisible(True)
1068
+ self.no.setVisible(True)
1069
+ self.arena_shape.setVisible(True)
1070
+ self.arena_shape_label.setVisible(True)
1071
+ # self.select_option_label.setVisible(color_analysis)
1072
+ # self.select_option.setVisible(color_analysis)
1073
+ self.n_shapes_detected.setVisible(True)
1074
+
1075
+ elif self.step == 2:
1076
+ self.generate_analysis_options.setVisible(color_analysis)
1077
+ self.quickly.setVisible(color_analysis)
1078
+ self.carefully.setVisible(color_analysis)
1079
+ self.visualize.setVisible(True)
1080
+
1081
+ self.decision_label.setText("Click next when color delimits the cell(s) correctly")
1082
+ self.yes.setVisible(False)
1083
+ self.no.setVisible(False)
1084
+ self.message.setText('When the resulting segmentation of the last image seems good, click next.')
1085
+ self.next.setVisible(True)
1086
+
1087
+ try:
1088
+ self.thread["UpdateImage"].message_when_thread_finished.disconnect()
1089
+ except RuntimeError:
1090
+ pass
1091
+ self.is_image_analysis_running = False
1092
+ self.is_image_analysis_display_running = False
1093
+
1094
+ def option_changed(self):
1095
+ """
1096
+ Save the csc, change the image displayed, the csc editing
1097
+ :return:
1098
+ """
1099
+ # Update the current image
1100
+ if self.is_first_image_flag:
1101
+ im_combinations = self.parent().po.first_image.im_combinations
1102
+ else:
1103
+ im_combinations = self.parent().po.last_image.im_combinations
1104
+ self.parent().po.current_combination_id = self.select_option.currentIndex()
1105
+ logging.info(im_combinations is None)
1106
+ if im_combinations is not None and len(im_combinations) > 0:
1107
+ if self.parent().po.current_combination_id + 1 > len(im_combinations):
1108
+ self.parent().po.current_combination_id = 0
1109
+ self.csc_dict = im_combinations[self.parent().po.current_combination_id]["csc"]
1110
+ self.parent().po.current_image = np.stack((im_combinations[self.parent().po.current_combination_id]['converted_image'],
1111
+ im_combinations[self.parent().po.current_combination_id]['converted_image'],
1112
+ im_combinations[self.parent().po.current_combination_id]['converted_image']), axis=2)
1113
+ self.drawn_image = deepcopy(self.parent().po.current_image)
1114
+
1115
+ # Update image display
1116
+ if self.thread["UpdateImage"].isRunning():
1117
+ self.thread["UpdateImage"].wait()
1118
+ self.thread["UpdateImage"].start()
1119
+ # Update csc editing
1120
+ self.update_csc_editing_display()
1121
+
1122
+ # Update the detected shape number
1123
+ if self.is_first_image_flag:
1124
+ self.parent().po.vars['convert_for_origin'] = im_combinations[self.parent().po.current_combination_id]["csc"]
1125
+ detected_shape_nb = \
1126
+ self.parent().po.first_image.im_combinations[self.parent().po.current_combination_id]['shape_number']
1127
+ if self.parent().po.vars['several_blob_per_arena']:
1128
+ if detected_shape_nb == self.parent().po.sample_number:
1129
+ self.message.setText("Beware: Contrary to what has been checked, there is one spot per arena")
1130
+ else:
1131
+ if detected_shape_nb == self.parent().po.sample_number:
1132
+ self.decision_label.setText(
1133
+ f"{detected_shape_nb} distinct spots detected in {self.parent().po.sample_number} arena(s). Does the color match the cell(s)?")
1134
+ self.yes.setVisible(True)
1135
+ else:
1136
+ self.decision_label.setText(
1137
+ f"{detected_shape_nb} distinct spots detected in {self.parent().po.sample_number} arena(s). Adjust settings, draw more cells and background, and try again")
1138
+ self.yes.setVisible(False)
1139
+ # self.decision_label.setText(f"Does the color correctly cover the cells?")
1140
+ # detected_shape_nb = \
1141
+ # self.parent().po.first_image.im_combinations[self.parent().po.current_combination_id]['shape_number']
1142
+ # self.decision_label.setText(
1143
+ # f"Does the color correctly cover the cells? And, is {detected_shape_nb} the number of distinct arenas?")
1144
+ if self.parent().po.first_image.im_combinations[self.parent().po.current_combination_id]['shape_number'] == 0:
1145
+ self.message.setText("Make sure that scaling metric and spot size are correct")
1146
+ else:
1147
+ self.parent().po.vars['convert_for_motion'] = im_combinations[self.parent().po.current_combination_id]["csc"]
1148
+ self.decision_label.setText("Do colored contours correctly match cell(s) contours?")
1149
+
1150
+ def generate_csc_editing(self):
1151
+ # self.edit_layout = QtWidgets.QGridLayout()
1152
+ self.edit_widget = QtWidgets.QWidget()
1153
+ self.edit_layout = QtWidgets.QVBoxLayout()
1154
+
1155
+ # 1) Advanced mode option
1156
+ self.advanced_mode_widget = QtWidgets.QWidget()
1157
+ self.advanced_mode_layout = QtWidgets.QHBoxLayout()
1158
+ self.advanced_mode_cb = Checkbox(self.parent().po.all['expert_mode'])
1159
+ self.advanced_mode_cb.setStyleSheet("margin-left:0%; margin-right:0%;")
1160
+ self.advanced_mode_cb.stateChanged.connect(self.advanced_mode_check)
1161
+ self.advanced_mode_label = FixedText('Advanced mode', halign='l',
1162
+ tip="Display the color space combination corresponding to the selected option",
1163
+ night_mode=self.parent().po.all['night_mode'])
1164
+ self.advanced_mode_label.setAlignment(QtCore.Qt.AlignTop)
1165
+ self.advanced_mode_layout.addWidget(self.advanced_mode_cb)
1166
+ self.advanced_mode_layout.addWidget(self.advanced_mode_label)
1167
+ self.advanced_mode_layout.addItem(self.horizontal_space)
1168
+ self.advanced_mode_widget.setLayout(self.advanced_mode_layout)
1169
+ self.edit_layout.addWidget(self.advanced_mode_widget)
1170
+
1171
+ self.csc_scroll_table = QtWidgets.QScrollArea() # QTableWidget() # Scroll Area which contains the widgets, set as the centralWidget
1172
+ # self.csc_scroll_table.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
1173
+ self.csc_scroll_table.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
1174
+ self.csc_scroll_table.setMinimumHeight(self.parent().im_max_height - 100)
1175
+ # self.csc_scroll_table.setMinimumWidth(300)
1176
+ self.csc_scroll_table.setFrameShape(QtWidgets.QFrame.NoFrame)
1177
+ self.csc_scroll_table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
1178
+ self.csc_scroll_table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
1179
+ self.csc_table_widget = QtWidgets.QWidget()
1180
+ self.csc_table_layout = QtWidgets.QVBoxLayout()
1181
+
1182
+ # 2) Titles
1183
+ self.edit_labels_widget = QtWidgets.QWidget()
1184
+ self.edit_labels_layout = QtWidgets.QHBoxLayout()
1185
+
1186
+ self.space_label = FixedText('Color space:', halign='l',
1187
+ 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",
1188
+ night_mode=self.parent().po.all['night_mode'])
1189
+ # self.c1 = FixedText(' C1', halign='c', tip="Increase if it increase cell detection", night_mode=self.parent().po.all['night_mode'])
1190
+ # self.c2 = FixedText(' C2', halign='c', tip="Increase if it increase cell detection", night_mode=self.parent().po.all['night_mode'])
1191
+ # self.c3 = FixedText(' C3', halign='c', tip="Increase if it increase cell detection", night_mode=self.parent().po.all['night_mode'])
1192
+
1193
+ self.edit_labels_layout.addWidget(self.space_label)
1194
+ # self.edit_labels_layout.addWidget(self.c1)
1195
+ # self.edit_labels_layout.addWidget(self.c2)
1196
+ # self.edit_labels_layout.addWidget(self.c3)
1197
+ self.edit_labels_layout.addItem(self.horizontal_space)
1198
+ self.space_label.setVisible(False)
1199
+ # self.c1.setVisible(False)
1200
+ # self.c2.setVisible(False)
1201
+ # self.c3.setVisible(False)
1202
+ self.edit_labels_widget.setLayout(self.edit_labels_layout)
1203
+ # self.edit_layout.addWidget(self.edit_labels_widget)
1204
+ self.csc_table_layout.addWidget(self.edit_labels_widget)
1205
+
1206
+ # 3) First CSC
1207
+ self.first_csc_widget = QtWidgets.QWidget()
1208
+ self.first_csc_layout = QtWidgets.QGridLayout()
1209
+ self.row1 = self.one_csc_editing()
1210
+ self.row1[4].clicked.connect(self.display_row2)
1211
+ self.row2 = self.one_csc_editing()
1212
+ self.row2[4].clicked.connect(self.display_row3)
1213
+ self.row3 = self.one_csc_editing()# Second CSC
1214
+ self.logical_operator_between_combination_result = Combobox(["None", "Or", "And", "Xor"],
1215
+ night_mode=self.parent().po.all['night_mode'])
1216
+ self.logical_operator_between_combination_result.setCurrentText(self.parent().po.vars['convert_for_motion']['logical'])
1217
+ self.logical_operator_between_combination_result.currentTextChanged.connect(self.logical_op_changed)
1218
+ self.logical_operator_between_combination_result.setFixedWidth(100)
1219
+ # self.logical_operator_between_combination_result.cha
1220
+ self.logical_operator_label = FixedText("Logical operator", tip="Between selected color space combinations",
1221
+ night_mode=self.parent().po.all['night_mode'])
1222
+
1223
+ self.row21 = self.one_csc_editing()
1224
+ self.row21[4].clicked.connect(self.display_row22)
1225
+ self.row22 = self.one_csc_editing()
1226
+ self.row22[4].clicked.connect(self.display_row23)
1227
+ self.row23 = self.one_csc_editing()
1228
+ if self.csc_dict is not None:
1229
+ self.update_csc_editing_display()
1230
+ else:
1231
+ self.row1[0].setCurrentIndex(4)
1232
+ self.row1[3].setValue(1)
1233
+ self.row21[0].setCurrentIndex(0)
1234
+ self.row21[3].setValue(0)
1235
+
1236
+ for i in range(5):
1237
+ self.first_csc_layout.addWidget(self.row1[i], 0, i, 1, 1)
1238
+ self.first_csc_layout.addWidget(self.row2[i], 1, i, 1, 1)
1239
+ self.first_csc_layout.addWidget(self.row3[i], 2, i, 1, 1)
1240
+ self.row1[i].setVisible(False)
1241
+ self.row2[i].setVisible(False)
1242
+ self.row3[i].setVisible(False)
1243
+ self.first_csc_layout.setHorizontalSpacing(0)
1244
+ self.first_csc_layout.addItem(self.horizontal_space, 0, 5, 3, 1)
1245
+ self.first_csc_widget.setLayout(self.first_csc_layout)
1246
+ self.csc_table_layout.addWidget(self.first_csc_widget)
1247
+ # self.edit_layout.addWidget(self.first_csc_widget)
1248
+
1249
+ # First filters
1250
+
1251
+ self.filter1_label = FixedText('Filter: ', halign='l',
1252
+ tip="The filter to apply to the image before segmentation",
1253
+ night_mode=self.parent().po.all['night_mode'])
1254
+ self.csc_table_layout.addWidget(self.filter1_label)
1255
+ self.filter1_widget = QtWidgets.QWidget()
1256
+ self.filter1_layout = QtWidgets.QHBoxLayout()
1257
+ self.filter1 = Combobox(list(filter_dict.keys()), night_mode=self.parent().po.all['night_mode'])
1258
+ self.filter1.setCurrentText(self.parent().po.vars['filter_spec']['filter1_type'])
1259
+ self.filter1.currentTextChanged.connect(self.filter1_changed)
1260
+ self.filter1.setFixedWidth(100)
1261
+ if "Param1" in filter_dict[self.parent().po.vars['filter_spec']['filter1_type']].keys():
1262
+ param1_name = filter_dict[self.parent().po.vars['filter_spec']['filter1_type']]["Param1"]["Name"]
1263
+ else:
1264
+ param1_name = ""
1265
+ self.filter1_param1_label = FixedText(param1_name, halign='l', tip="The parameter to adjust the filter effect",
1266
+ night_mode=self.parent().po.all['night_mode'])
1267
+ filter_param_spinbox_width = 60
1268
+ self.filter1_param1 = Spinbox(min=-1000, max=1000, val=self.parent().po.vars['filter_spec']['filter1_param'][0], decimals=3, night_mode=self.parent().po.all['night_mode'])
1269
+ self.filter1_param1.setFixedWidth(filter_param_spinbox_width)
1270
+ self.filter1_param1.valueChanged.connect(self.filter1_param1_changed)
1271
+ if "Param2" in filter_dict[self.parent().po.vars['filter_spec']['filter1_type']].keys():
1272
+ param2_name = filter_dict[self.parent().po.vars['filter_spec']['filter1_type']]["Param2"]["Name"]
1273
+ else:
1274
+ param2_name = ""
1275
+ self.filter1_param2_label = FixedText(param2_name, halign='l', tip="The parameter to adjust the filter effect",
1276
+ night_mode=self.parent().po.all['night_mode'])
1277
+ self.filter1_param2 = Spinbox(min=-1000, max=1000, val=self.parent().po.vars['filter_spec']['filter1_param'][1], decimals=3, night_mode=self.parent().po.all['night_mode'])
1278
+ self.filter1_param2.setFixedWidth(filter_param_spinbox_width)
1279
+ self.filter1_param2.valueChanged.connect(self.filter1_param2_changed)
1280
+ self.filter1_layout.addWidget(self.filter1)
1281
+ # self.filter1_layout.addWidget(self.filter1_label)
1282
+ self.filter1_layout.addItem(self.horizontal_space)
1283
+ self.filter1_layout.addWidget(self.filter1_param1_label)
1284
+ self.filter1_layout.addWidget(self.filter1_param1)
1285
+ self.filter1_layout.addItem(self.horizontal_space)
1286
+ self.filter1_layout.addWidget(self.filter1_param2_label)
1287
+ self.filter1_layout.addWidget(self.filter1_param2)
1288
+ self.filter1.setVisible(False)
1289
+ self.filter1_label.setVisible(False)
1290
+ self.filter1_param1_label.setVisible(False)
1291
+ self.filter1_param1.setVisible(False)
1292
+ self.filter1_param2_label.setVisible(False)
1293
+ self.filter1_param2.setVisible(False)
1294
+ self.filter1_widget.setLayout(self.filter1_layout)
1295
+ self.csc_table_layout.addWidget(self.filter1_widget)
1296
+
1297
+ # 4) logical_operator
1298
+ self.logical_op_widget = QtWidgets.QWidget()
1299
+ self.logical_op_layout = QtWidgets.QHBoxLayout()
1300
+ self.logical_op_layout.addWidget(self.logical_operator_label)
1301
+ self.logical_op_layout.addWidget(self.logical_operator_between_combination_result)
1302
+ self.logical_op_layout.addItem(self.horizontal_space)
1303
+ self.logical_operator_between_combination_result.setVisible(False)
1304
+ self.logical_operator_label.setVisible(False)
1305
+ self.logical_op_widget.setLayout(self.logical_op_layout)
1306
+ self.csc_table_layout.addWidget(self.logical_op_widget)
1307
+ # self.edit_layout.addWidget(self.logical_op_widget)
1308
+
1309
+ # 5) Second CSC
1310
+ self.second_csc_widget = QtWidgets.QWidget()
1311
+ self.second_csc_layout = QtWidgets.QGridLayout()
1312
+ for i in range(5):
1313
+ self.second_csc_layout.addWidget(self.row21[i], 0, i, 1, 1)
1314
+ self.second_csc_layout.addWidget(self.row22[i], 1, i, 1, 1)
1315
+ self.second_csc_layout.addWidget(self.row23[i], 2, i, 1, 1)
1316
+ self.row21[i].setVisible(False)
1317
+ self.row22[i].setVisible(False)
1318
+ self.row23[i].setVisible(False)
1319
+ self.second_csc_layout.setHorizontalSpacing(0)
1320
+ self.second_csc_layout.addItem(self.horizontal_space, 0, 5, 3, 1)
1321
+ self.second_csc_widget.setLayout(self.second_csc_layout)
1322
+ self.csc_table_layout.addWidget(self.second_csc_widget)
1323
+
1324
+ self.csc_table_widget.setLayout(self.csc_table_layout)
1325
+ self.csc_scroll_table.setWidget(self.csc_table_widget)
1326
+ self.csc_scroll_table.setWidgetResizable(True)
1327
+ # self.edit_layout.addWidget(self.second_csc_widget)
1328
+ self.edit_layout.addWidget(self.csc_scroll_table)
1329
+ self.edit_layout.addItem(self.vertical_space)
1330
+
1331
+ # Second filters
1332
+ self.filter2_label = FixedText('Filter: ', halign='l',
1333
+ tip="The filter to apply to the image before segmentation",
1334
+ night_mode=self.parent().po.all['night_mode'])
1335
+ self.csc_table_layout.addWidget(self.filter2_label)
1336
+ self.filter2_widget = QtWidgets.QWidget()
1337
+ self.filter2_layout = QtWidgets.QHBoxLayout()
1338
+ self.filter2 = Combobox(list(filter_dict.keys()), night_mode=self.parent().po.all['night_mode'])
1339
+ self.filter2.setCurrentText(self.parent().po.vars['filter_spec']['filter2_type'])
1340
+ self.filter2.currentTextChanged.connect(self.filter2_changed)
1341
+ self.filter2.setFixedWidth(100)
1342
+ if "Param1" in filter_dict[self.parent().po.vars['filter_spec']['filter2_type']].keys():
1343
+ param1_name = filter_dict[self.parent().po.vars['filter_spec']['filter2_type']]["Param1"]["Name"]
1344
+ else:
1345
+ param1_name = ""
1346
+ self.filter2_param1_label = FixedText(param1_name, halign='l',
1347
+ tip="The parameter to adjust the filter effect",
1348
+ night_mode=self.parent().po.all['night_mode'])
1349
+ self.filter2_param1 = Spinbox(min=-1000, max=1000, val=self.parent().po.vars['filter_spec']['filter2_param'][0], decimals=3, night_mode=self.parent().po.all['night_mode'])
1350
+ self.filter2_param1.setFixedWidth(filter_param_spinbox_width)
1351
+ self.filter2_param1.valueChanged.connect(self.filter2_param1_changed)
1352
+ if "Param2" in filter_dict[self.parent().po.vars['filter_spec']['filter2_type']].keys():
1353
+ param2_name = filter_dict[self.parent().po.vars['filter_spec']['filter2_type']]["Param2"]["Name"]
1354
+ else:
1355
+ param2_name = ""
1356
+ self.filter2_param2_label = FixedText(param2_name, halign='l', tip="The parameter to adjust the filter effect",
1357
+ night_mode=self.parent().po.all['night_mode'])
1358
+ self.filter2_param2 = Spinbox(min=-1000, max=1000, val=self.parent().po.vars['filter_spec']['filter2_param'][1], decimals=3, night_mode=self.parent().po.all['night_mode'])
1359
+ self.filter2_param2.setFixedWidth(filter_param_spinbox_width)
1360
+
1361
+ self.filter1_param2.valueChanged.connect(self.filter2_param2_changed)
1362
+ self.filter2_layout.addWidget(self.filter2)
1363
+ # self.filter2_layout.addWidget(self.filter2_label)
1364
+ self.filter2_layout.addItem(self.horizontal_space)
1365
+ self.filter2_layout.addWidget(self.filter2_param1_label)
1366
+ self.filter2_layout.addWidget(self.filter2_param1)
1367
+ self.filter2_layout.addItem(self.horizontal_space)
1368
+ self.filter2_layout.addWidget(self.filter2_param2_label)
1369
+ self.filter2_layout.addWidget(self.filter2_param2)
1370
+ self.filter2.setVisible(False)
1371
+ self.filter2_label.setVisible(False)
1372
+ self.filter2_widget.setLayout(self.filter2_layout)
1373
+ self.csc_table_layout.addWidget(self.filter2_widget)
1374
+
1375
+ # 6) Open the grid_segmentation row layout
1376
+ self.grid_segmentation_widget = QtWidgets.QWidget()
1377
+ self.grid_segmentation_layout = QtWidgets.QHBoxLayout()
1378
+ try:
1379
+ self.parent().po.vars["grid_segmentation"]
1380
+ except KeyError:
1381
+ self.parent().po.vars["grid_segmentation"] = False
1382
+ self.grid_segmentation = Checkbox(self.parent().po.vars["grid_segmentation"])
1383
+ self.grid_segmentation.setStyleSheet("margin-left:0%; margin-right:-10%;")
1384
+ self.grid_segmentation.stateChanged.connect(self.grid_segmentation_option)
1385
+
1386
+ self.grid_segmentation_label = FixedText("Grid segmentation",
1387
+ tip="Segment small squares of the images to detect local intensity valleys\nThis method segment the image locally using otsu thresholding on a rolling window", night_mode=self.parent().po.all['night_mode'])
1388
+ self.grid_segmentation_label.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
1389
+ # self.more_than_two_colors_label.setFixedWidth(300)
1390
+ self.grid_segmentation_label.setAlignment(QtCore.Qt.AlignLeft)
1391
+
1392
+ self.grid_segmentation_layout.addWidget(self.grid_segmentation)
1393
+ self.grid_segmentation_layout.addWidget(self.grid_segmentation_label)
1394
+ self.grid_segmentation_layout.addItem(self.horizontal_space)
1395
+ self.grid_segmentation_widget.setLayout(self.grid_segmentation_layout)
1396
+ self.edit_layout.addWidget(self.grid_segmentation_widget)
1397
+
1398
+ # 6) Open the more_than_2_colors row layout
1399
+ self.more_than_2_colors_widget = QtWidgets.QWidget()
1400
+ self.more_than_2_colors_layout = QtWidgets.QHBoxLayout()
1401
+ self.more_than_two_colors = Checkbox(self.parent().po.all["more_than_two_colors"])
1402
+ self.more_than_two_colors.setStyleSheet("margin-left:0%; margin-right:-10%;")
1403
+ self.more_than_two_colors.stateChanged.connect(self.display_more_than_two_colors_option)
1404
+
1405
+ self.more_than_two_colors_label = FixedText("More than two colors",
1406
+ tip="The program will split the image into categories\nand find the one corresponding to the cell(s)", night_mode=self.parent().po.all['night_mode'])
1407
+ self.more_than_two_colors_label.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
1408
+ # self.more_than_two_colors_label.setFixedWidth(300)
1409
+ self.more_than_two_colors_label.setAlignment(QtCore.Qt.AlignLeft)
1410
+ self.distinct_colors_number = Spinbox(min=2, max=5, val=self.parent().po.vars["color_number"], night_mode=self.parent().po.all['night_mode'])
1411
+
1412
+ self.distinct_colors_number.valueChanged.connect(self.distinct_colors_number_changed)
1413
+ self.display_more_than_two_colors_option()
1414
+ self.more_than_two_colors.setVisible(False)
1415
+ self.more_than_two_colors_label.setVisible(False)
1416
+ self.distinct_colors_number.setVisible(False)
1417
+ self.grid_segmentation.setVisible(False)
1418
+ self.grid_segmentation_label.setVisible(False)
1419
+
1420
+ self.more_than_2_colors_layout.addWidget(self.more_than_two_colors)
1421
+ self.more_than_2_colors_layout.addWidget(self.more_than_two_colors_label)
1422
+ self.more_than_2_colors_layout.addWidget(self.distinct_colors_number)
1423
+ self.more_than_2_colors_layout.addItem(self.horizontal_space)
1424
+ self.more_than_2_colors_widget.setLayout(self.more_than_2_colors_layout)
1425
+ self.edit_layout.addWidget(self.more_than_2_colors_widget)
1426
+
1427
+ self.edit_widget.setLayout(self.edit_layout)
1428
+
1429
+ def one_csc_editing(self):
1430
+ widget_list = []
1431
+ widget_list.insert(0, Combobox(["None", "bgr", "hsv", "hls", "lab", "luv", "yuv"],
1432
+ night_mode=self.parent().po.all['night_mode']))
1433
+ widget_list[0].setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
1434
+ widget_list[0].setFixedWidth(100)
1435
+ for i in [1, 2, 3]:
1436
+ widget_list.insert(i, Spinbox(min=-126, max=126, val=0, night_mode=self.parent().po.all['night_mode']))
1437
+ widget_list[i].setFixedWidth(45)
1438
+ widget_list.insert(i + 1, PButton("+", night_mode=self.parent().po.all['night_mode']))
1439
+
1440
+ return widget_list
1441
+
1442
+ def filter1_changed(self):
1443
+ current_filter = self.filter1.currentText()
1444
+ self.parent().po.vars['filter_spec']['filter1_type'] = current_filter
1445
+ show_param1 = "Param1" in filter_dict[current_filter].keys()
1446
+ self.filter1_param1_label.setVisible(show_param1)
1447
+ self.filter1_param1.setVisible(show_param1)
1448
+ if show_param1:
1449
+ self.filter1_param1_label.setText(filter_dict[current_filter]['Param1']['Name'])
1450
+ self.filter1_param1.setMinimum(filter_dict[current_filter]['Param1']['Minimum'])
1451
+ self.filter1_param1.setMaximum(filter_dict[current_filter]['Param1']['Maximum'])
1452
+ self.filter1_param1.setValue(filter_dict[current_filter]['Param1']['Default'])
1453
+ if 'Param2' in list(filter_dict[current_filter].keys()):
1454
+ self.filter1_param2_label.setText(filter_dict[current_filter]['Param2']['Name'])
1455
+ self.filter1_param2.setMinimum(filter_dict[current_filter]['Param2']['Minimum'])
1456
+ self.filter1_param2.setMaximum(filter_dict[current_filter]['Param2']['Maximum'])
1457
+ self.filter1_param2.setValue(filter_dict[current_filter]['Param2']['Default'])
1458
+ self.filter1_param2_label.setVisible(True)
1459
+ self.filter1_param2.setVisible(True)
1460
+ else:
1461
+ self.filter1_param2_label.setVisible(False)
1462
+ self.filter1_param2.setVisible(False)
1463
+
1464
+ def filter1_param1_changed(self):
1465
+ self.parent().po.vars['filter_spec']['filter1_param'][0] = float(self.filter1_param1.value())
1466
+
1467
+ def filter1_param2_changed(self):
1468
+ self.parent().po.vars['filter_spec']['filter1_param'][1] = float(self.filter1_param2.value())
1469
+
1470
+ def filter2_changed(self):
1471
+ current_filter = self.filter2.currentText()
1472
+ self.parent().po.vars['filter_spec']['filter2_type'] = current_filter
1473
+ show_param1 = "Param1" in filter_dict[current_filter].keys()
1474
+ self.filter2_param1_label.setVisible(show_param1)
1475
+ self.filter2_param1.setVisible(show_param1)
1476
+ if show_param1:
1477
+ self.filter2_param1_label.setText(filter_dict[current_filter]['Param1']['Name'])
1478
+ self.filter2_param1.setMinimum(filter_dict[current_filter]['Param1']['Minimum'])
1479
+ self.filter2_param1.setMaximum(filter_dict[current_filter]['Param1']['Maximum'])
1480
+ self.filter2_param1.setValue(filter_dict[current_filter]['Param2']['Default'])
1481
+ if 'Param2' in list(filter_dict[current_filter].keys()):
1482
+ self.filter2_param2_label.setText(filter_dict[current_filter]['Param2']['Name'])
1483
+ self.filter2_param2.setMinimum(filter_dict[current_filter]['Param2']['Minimum'])
1484
+ self.filter2_param2.setMaximum(filter_dict[current_filter]['Param2']['Maximum'])
1485
+ self.filter2_param2.setValue(filter_dict[current_filter]['Param2']['Default'])
1486
+ self.filter2_param2_label.setVisible(True)
1487
+ self.filter2_param2.setVisible(True)
1488
+ else:
1489
+ self.filter2_param2_label.setVisible(False)
1490
+ self.filter2_param2.setVisible(False)
1491
+
1492
+ def filter2_param1_changed(self):
1493
+ self.parent().po.vars['filter_spec']['filter2_param'][0] = float(self.filter2_param1.value())
1494
+
1495
+ def filter2_param2_changed(self):
1496
+ self.parent().po.vars['filter_spec']['filter2_param'][1] = float(self.filter2_param2.value())
1497
+
1498
+ def logical_op_changed(self):
1499
+ # show = self.logical_operator_between_combination_result.currentText() != 'None'
1500
+ if self.logical_operator_between_combination_result.currentText() == 'None':
1501
+ self.row21[0].setVisible(False)
1502
+ self.row21[0].setCurrentIndex(0)
1503
+ for i1 in [1, 2, 3]:
1504
+ self.row21[i1].setVisible(False)
1505
+ self.row21[i1].setValue(0)
1506
+ self.row21[i1 + 1].setVisible(False)
1507
+
1508
+ self.row22[0].setVisible(False)
1509
+ self.row22[0].setCurrentIndex(0)
1510
+ for i1 in [1, 2, 3]:
1511
+ self.row22[i1].setVisible(False)
1512
+ self.row22[i1].setValue(0)
1513
+ self.row22[i1 + 1].setVisible(False)
1514
+
1515
+ self.row23[0].setVisible(False)
1516
+ self.row23[0].setCurrentIndex(0)
1517
+ for i1 in [1, 2, 3]:
1518
+ self.row23[i1].setVisible(False)
1519
+ self.row23[i1].setValue(0)
1520
+ self.row23[i1 + 1].setVisible(False)
1521
+ else:
1522
+ self.filter2_label.setVisible(self.parent().po.all['expert_mode'])
1523
+ self.filter2.setVisible(self.parent().po.all['expert_mode'])
1524
+ self.filter2_changed()
1525
+ self.row21[0].setVisible(self.parent().po.all['expert_mode'])
1526
+ for i1 in [1, 2, 3]:
1527
+ self.row21[i1].setVisible(self.parent().po.all['expert_mode'])
1528
+ self.row21[i1 + 1].setVisible(self.parent().po.all['expert_mode'])
1529
+
1530
+ def display_logical_operator(self):
1531
+ self.logical_operator_between_combination_result.setVisible(self.parent().po.all['expert_mode'])
1532
+ self.logical_operator_label.setVisible(self.parent().po.all['expert_mode'])
1533
+
1534
+ def display_row2(self):
1535
+ self.row1[4].setVisible(False)
1536
+ for i in range(5):
1537
+ self.row2[i].setVisible(self.parent().po.all['expert_mode'])
1538
+ self.display_logical_operator()
1539
+
1540
+ def display_row3(self):
1541
+ self.row2[4].setVisible(False)
1542
+ for i in range(4):
1543
+ self.row3[i].setVisible(self.parent().po.all['expert_mode'])
1544
+ self.display_logical_operator()
1545
+
1546
+ def display_row22(self):
1547
+ self.row21[4].setVisible(False)
1548
+ for i in range(5):
1549
+ self.row22[i].setVisible(self.parent().po.all['expert_mode'])
1550
+ self.display_logical_operator()
1551
+
1552
+ def display_row23(self):
1553
+ self.row22[4].setVisible(False)
1554
+ for i in range(4):
1555
+ self.row23[i].setVisible(self.parent().po.all['expert_mode'])
1556
+ self.display_logical_operator()
1557
+
1558
+ def update_csc_editing_display(self):
1559
+ c_space_order = ["None", "bgr", "hsv", "hls", "lab", "luv", "yuv"]
1560
+ remaining_c_spaces = []
1561
+ row_number1 = 0
1562
+ row_number2 = 0
1563
+ for i, (k, v) in enumerate(self.csc_dict.items()):
1564
+ if k != "logical":
1565
+ if k[-1] != "2":
1566
+ if row_number1 == 0:
1567
+ row_to_change = self.row1
1568
+ elif row_number1 == 1:
1569
+ row_to_change = self.row2
1570
+ elif row_number1 == 2:
1571
+ row_to_change = self.row3
1572
+ else:
1573
+ remaining_c_spaces.append(k + " " + str(v))
1574
+ row_number1 += 1
1575
+ current_row_number = row_number1
1576
+ else:
1577
+ if row_number2 == 0:
1578
+ row_to_change = self.row21
1579
+ elif row_number2 == 1:
1580
+ row_to_change = self.row22
1581
+ elif row_number2 == 2:
1582
+ row_to_change = self.row23
1583
+ else:
1584
+ remaining_c_spaces.append(k + " " + str(v))
1585
+ row_number2 += 1
1586
+ current_row_number = row_number2
1587
+ k = k[:-1]
1588
+ if current_row_number <= 3:
1589
+ row_to_change[0].setCurrentIndex(np.nonzero(np.isin(c_space_order, k))[0][0])
1590
+ row_to_change[0].setVisible(self.parent().po.all['expert_mode'])
1591
+ for i1, i2 in zip([1, 2, 3], [0, 1, 2]):
1592
+ row_to_change[i1].setValue(v[i2])
1593
+ row_to_change[i1].setVisible(self.parent().po.all['expert_mode'])
1594
+ if current_row_number < 3:
1595
+ row_to_change[i1 + 1].setVisible(self.parent().po.all['expert_mode'])
1596
+
1597
+ # If not all color space combinations are filled, put None and 0 in boxes
1598
+ if row_number1 < 3:
1599
+ self.row3[0].setVisible(False)
1600
+ self.row3[0].setCurrentIndex(0)
1601
+ for i1 in [1, 2, 3]:
1602
+ self.row3[i1].setVisible(False)
1603
+ self.row3[i1].setValue(0)
1604
+ if row_number1 < 2:
1605
+ self.row2[0].setVisible(False)
1606
+ self.row2[0].setCurrentIndex(0)
1607
+ for i1 in [1, 2, 3]:
1608
+ self.row2[i1].setVisible(False)
1609
+ self.row2[i1].setValue(0)
1610
+ self.row2[i1 + 1].setVisible(False)
1611
+
1612
+ self.row1[4].setVisible(self.parent().po.all['expert_mode'] and row_number1 == 1)
1613
+ self.row2[4].setVisible(self.parent().po.all['expert_mode'] and row_number1 == 2)
1614
+ self.row21[4].setVisible(self.parent().po.all['expert_mode'] and row_number2 == 1)
1615
+ self.row22[4].setVisible(self.parent().po.all['expert_mode'] and row_number2 == 2)
1616
+ if row_number2 > 0:
1617
+ self.logical_operator_between_combination_result.setCurrentText(self.csc_dict['logical'])
1618
+ if row_number2 == 0:
1619
+ self.logical_operator_between_combination_result.setCurrentText('None')
1620
+ self.logical_operator_between_combination_result.setVisible(False)
1621
+ self.logical_operator_label.setVisible(False)
1622
+ self.row21[0].setVisible(False)
1623
+ self.row21[0].setCurrentIndex(0)
1624
+ for i1 in [1, 2, 3]:
1625
+ self.row21[i1].setVisible(False)
1626
+ self.row21[i1].setValue(0)
1627
+ self.row21[i1 + 1].setVisible(False)
1628
+
1629
+ self.logical_operator_between_combination_result.setVisible((row_number2 > 0) and self.parent().po.all['expert_mode'])
1630
+ self.logical_operator_label.setVisible((row_number2 > 0) and self.parent().po.all['expert_mode'])
1631
+
1632
+ if row_number2 < 3:
1633
+ self.row23[0].setVisible(False)
1634
+ self.row23[0].setCurrentIndex(0)
1635
+ for i1 in [1, 2, 3]:
1636
+ self.row23[i1].setVisible(False)
1637
+ self.row23[i1].setValue(0)
1638
+ self.row23[i1 + 1].setVisible(False)
1639
+ self.row22[4].setVisible(False)
1640
+ if row_number2 < 2:
1641
+ self.row22[0].setVisible(False)
1642
+ self.row22[0].setCurrentIndex(0)
1643
+ for i1 in [1, 2, 3]:
1644
+ self.row22[i1].setVisible(False)
1645
+ self.row22[i1].setValue(0)
1646
+ self.row22[i1 + 1].setVisible(False)
1647
+
1648
+ if self.advanced_mode_cb.isChecked():
1649
+ if len(remaining_c_spaces) > 0:
1650
+ self.message.setText(f'Combination also includes {remaining_c_spaces}')
1651
+ self.message.setStyleSheet("color: rgb(230, 145, 18)")
1652
+ else:
1653
+ self.message.setText(f'')
1654
+
1655
+ def save_user_defined_csc(self):
1656
+ self.csc_dict = {}
1657
+ spaces = np.array((self.row1[0].currentText(), self.row2[0].currentText(), self.row3[0].currentText()))
1658
+ channels = np.array(
1659
+ ((self.row1[1].value(), self.row1[2].value(), self.row1[3].value()),
1660
+ (self.row2[1].value(), self.row2[2].value(), self.row2[3].value()),
1661
+ (self.row3[1].value(), self.row3[2].value(), self.row3[3].value()),
1662
+ (self.row21[1].value(), self.row21[2].value(), self.row21[3].value()),
1663
+ (self.row22[1].value(), self.row22[2].value(), self.row22[3].value()),
1664
+ (self.row23[1].value(), self.row23[2].value(), self.row23[3].value())),
1665
+ dtype=np.int8)
1666
+ if self.logical_operator_between_combination_result.currentText() != 'None':
1667
+ spaces = np.concatenate((spaces, np.array((
1668
+ self.row21[0].currentText() + "2", self.row22[0].currentText() + "2",
1669
+ self.row23[0].currentText() + "2"))))
1670
+ channels = np.concatenate((channels, np.array(((self.row21[1].value(), self.row21[2].value(), self.row21[3].value()),
1671
+ (self.row22[1].value(), self.row22[2].value(), self.row22[3].value()),
1672
+ (self.row23[1].value(), self.row23[2].value(), self.row23[3].value())),
1673
+ dtype=np.int8)))
1674
+ self.csc_dict['logical'] = self.logical_operator_between_combination_result.currentText()
1675
+ else:
1676
+ self.csc_dict['logical'] = 'None'
1677
+ if not np.all(spaces == "None"):
1678
+ for i, space in enumerate(spaces):
1679
+ if space != "None" and space != "None2":
1680
+ self.csc_dict[space] = channels[i, :]
1681
+ if len(self.csc_dict) == 1 or channels.sum() == 0:
1682
+ self.csc_dict_is_empty = True
1683
+ else:
1684
+ self.csc_dict_is_empty = False
1685
+
1686
+ def grid_segmentation_option(self):
1687
+ self.parent().po.vars["grid_segmentation"] = self.grid_segmentation.isChecked()
1688
+
1689
+ def display_more_than_two_colors_option(self):
1690
+ """ should not do
1691
+
1692
+ self.parent().po.all["more_than_two_colors"] = self.more_than_two_colors.isChecked()
1693
+ when init
1694
+ """
1695
+ if self.bio_masks_number > 0 and self.advanced_mode_cb.isChecked():
1696
+ self.more_than_two_colors.setVisible(True)
1697
+ self.more_than_two_colors_label.setVisible(True)
1698
+ if self.more_than_two_colors.isChecked():
1699
+ self.distinct_colors_number.setVisible(True)
1700
+ self.more_than_two_colors_label.setText("How many distinct colors?")
1701
+ self.distinct_colors_number.setValue(3)
1702
+ else:
1703
+ self.more_than_two_colors_label.setText("Heterogeneous background")
1704
+ self.distinct_colors_number.setVisible(False)
1705
+ self.distinct_colors_number.setValue(2)
1706
+ self.parent().po.all["more_than_two_colors"] = self.more_than_two_colors.isChecked()
1707
+ else:
1708
+ self.more_than_two_colors.setChecked(False)
1709
+ self.more_than_two_colors.setVisible(False)
1710
+ self.more_than_two_colors_label.setVisible(False)
1711
+ self.distinct_colors_number.setVisible(False)
1712
+ self.distinct_colors_number.setValue(2)
1713
+ # self.parent().po.vars["color_number"] = 2
1714
+
1715
+ def distinct_colors_number_changed(self):
1716
+ self.parent().po.vars["color_number"] = int(self.distinct_colors_number.value())
1717
+
1718
+ def start_crop_scale_subtract_delineate(self):
1719
+ if not self.thread['CropScaleSubtractDelineate'].isRunning():
1720
+ self.message.setText("Looking for each arena contour, wait...")
1721
+ self.thread['CropScaleSubtractDelineate'].start()
1722
+ self.thread['CropScaleSubtractDelineate'].message_from_thread.connect(self.display_message_from_thread)
1723
+ self.thread['CropScaleSubtractDelineate'].message_when_thread_finished.connect(self.delineate_is_done)
1724
+
1725
+ self.yes.setVisible(False)
1726
+ self.no.setVisible(False)
1727
+ # self.times_clicked_yes += 1
1728
+ self.reinitialize_bio_and_back_legend()
1729
+ self.user_drawn_lines_label.setVisible(False)
1730
+ self.cell.setVisible(False)
1731
+ self.background.setVisible(False)
1732
+ # self.sample_number.setVisible(False)
1733
+ # self.sample_number_label.setVisible(False)
1734
+ self.one_blob_per_arena.setVisible(False)
1735
+ self.one_blob_per_arena_label.setVisible(False)
1736
+ self.set_spot_shape.setVisible(False)
1737
+ self.spot_shape.setVisible(False)
1738
+ self.spot_shape_label.setVisible(False)
1739
+ self.set_spot_size.setVisible(False)
1740
+ self.spot_size.setVisible(False)
1741
+ self.spot_size_label.setVisible(False)
1742
+ self.advanced_mode_cb.setChecked(False)
1743
+ self.advanced_mode_cb.setVisible(False)
1744
+ self.advanced_mode_label.setVisible(False)
1745
+ self.generate_analysis_options.setVisible(False)
1746
+ self.quickly.setVisible(False)
1747
+ self.carefully.setVisible(False)
1748
+ self.visualize.setVisible(False)
1749
+ self.visualize_label.setVisible(False)
1750
+ self.select_option.setVisible(False)
1751
+ self.select_option_label.setVisible(False)
1752
+
1753
+ def delineate_is_done(self, message):
1754
+ logging.info("Delineation is done, update GUI")
1755
+ self.message.setText(message)
1756
+ self.arena_shape_label.setVisible(False)
1757
+ self.arena_shape.setVisible(False)
1758
+ self.reinitialize_bio_and_back_legend()
1759
+ self.reinitialize_image_and_masks(self.parent().po.first_image.bgr)
1760
+ self.delineation_done = True
1761
+ if self.thread["UpdateImage"].isRunning():
1762
+ self.thread["UpdateImage"].wait()
1763
+ self.thread["UpdateImage"].start()
1764
+ self.thread["UpdateImage"].message_when_thread_finished.connect(self.automatic_delineation_display_done)
1765
+
1766
+ try:
1767
+ self.thread['CropScaleSubtractDelineate'].message_from_thread.disconnect()
1768
+ self.thread['CropScaleSubtractDelineate'].message_when_thread_finished.disconnect()
1769
+ except RuntimeError:
1770
+ pass
1771
+ if not self.slower_delineation_flag:
1772
+ self.asking_delineation_flag = True
1773
+
1774
+ def automatic_delineation_display_done(self, boole):
1775
+ # Remove this flag to not draw it again next time UpdateImage runs for another reason
1776
+ self.delineation_done = False
1777
+ self.auto_delineation_flag = False
1778
+ self.select_option_label.setVisible(False)
1779
+ self.select_option.setVisible(False)
1780
+
1781
+ self.arena_shape_label.setVisible(True)
1782
+ self.arena_shape.setVisible(True)
1783
+
1784
+ self.decision_label.setText('Is video delineation correct?')
1785
+ self.decision_label.setVisible(True)
1786
+ # self.message.setText('If not, restart the analysis (Previous) or manually draw each arena (No)')
1787
+ self.user_drawn_lines_label.setText('Draw each arena on the image')
1788
+ self.yes.setVisible(True)
1789
+ self.no.setVisible(True)
1790
+ try:
1791
+ self.thread["UpdateImage"].message_when_thread_finished.disconnect()
1792
+ except RuntimeError:
1793
+ pass
1794
+
1795
+ def display_message_from_thread(self, text_from_thread):
1796
+ self.message.setText(text_from_thread)
1797
+
1798
+ def starting_differs_from_growing_check(self):
1799
+ if self.parent().po.all['first_detection_frame'] > 1:
1800
+ self.parent().po.vars['origin_state'] = 'invisible'
1801
+ else:
1802
+ if self.starting_differs_from_growing_cb.isChecked():
1803
+ self.parent().po.vars['origin_state'] = 'constant'
1804
+ else:
1805
+ self.parent().po.vars['origin_state'] = 'fluctuating'
1806
+
1807
+ def when_yes_is_clicked(self):
1808
+ if not self.is_image_analysis_running:
1809
+ # self.message.setText('Loading, wait...')
1810
+ self.decision_tree(True)
1811
+
1812
+ def when_no_is_clicked(self):
1813
+ if not self.is_image_analysis_running:
1814
+ # self.message.setText('Loading, wait...')
1815
+ self.decision_tree(False)
1816
+
1817
+ def decision_tree(self, is_yes):
1818
+ color_analysis = not self.parent().po.vars['already_greyscale']
1819
+ if self.is_first_image_flag:
1820
+ if self.asking_first_im_parameters_flag:
1821
+ # Ask for the right number of distinct arenas, if not add parameters
1822
+ if not is_yes:
1823
+ self.first_im_parameters()
1824
+ else:
1825
+ self.auto_delineation()
1826
+ self.asking_first_im_parameters_flag = False
1827
+
1828
+ elif self.auto_delineation_flag:
1829
+ self.auto_delineation()
1830
+
1831
+ # Is automatic Video delineation correct?
1832
+ elif self.asking_delineation_flag:
1833
+ if not is_yes:
1834
+ self.asking_slower_or_manual_delineation()
1835
+ else:
1836
+ self.last_image_question()
1837
+ self.asking_delineation_flag = False
1838
+
1839
+ # Slower or manual delineation?
1840
+ elif self.asking_slower_or_manual_delineation_flag:
1841
+ if not is_yes:
1842
+ self.manual_delineation()
1843
+ else:
1844
+ self.slower_delineation_flag = True
1845
+ self.slower_delineation()
1846
+ self.asking_slower_or_manual_delineation_flag = False
1847
+
1848
+ # Is slower delineation correct?
1849
+ elif self.slower_delineation_flag:
1850
+ self.yes.setText("Yes")
1851
+ self.no.setText("No")
1852
+ if not is_yes:
1853
+ self.manual_delineation()
1854
+ else:
1855
+ self.last_image_question()
1856
+ self.slower_delineation_flag = False
1857
+
1858
+ elif self.manual_delineation_flag:
1859
+ if is_yes:
1860
+ if self.parent().po.sample_number == self.arena_masks_number:
1861
+ self.thread['SaveManualDelineation'].start()
1862
+ self.last_image_question()
1863
+ self.manual_delineation_flag = False
1864
+ else:
1865
+ self.message.setText(
1866
+ f"{self.arena_masks_number} arenas are drawn over the {self.parent().po.sample_number} expected")
1867
+
1868
+ elif self.asking_last_image_flag:
1869
+ self.parent().po.first_image.im_combinations = None
1870
+ self.select_option.clear()
1871
+ self.arena_shape.setVisible(False)
1872
+ self.arena_shape_label.setVisible(False)
1873
+ if is_yes:
1874
+ self.start_last_image()
1875
+ # if self.parent().po.vars['origin_state'] != 'invisible':
1876
+ # self.parent().po.vars['origin_state'] = "constant"
1877
+ else:
1878
+ # if self.parent().po.vars['origin_state'] != 'invisible':
1879
+ # self.parent().po.vars['origin_state'] = "fluctuating"
1880
+ self.parent().po.vars['convert_for_origin'] = deepcopy(self.csc_dict)
1881
+ self.parent().po.vars['convert_for_motion'] = deepcopy(self.csc_dict)
1882
+ self.go_to_next_widget()
1883
+ self.asking_last_image_flag = False
1884
+ else:
1885
+ if is_yes:
1886
+ self.parent().po.vars['convert_for_motion'] = deepcopy(self.csc_dict)
1887
+ self.go_to_next_widget()
1888
+
1889
+ def first_im_parameters(self):
1890
+ """ Method called in the decision tree"""
1891
+ self.step = 1
1892
+ self.decision_label.setText("Adjust settings, draw more cells and background, and try again")
1893
+ self.yes.setVisible(False)
1894
+ self.no.setVisible(False)
1895
+ # self.one_blob_per_arena.setVisible(True)
1896
+ # self.one_blob_per_arena_label.setVisible(True)
1897
+ self.set_spot_shape.setVisible(True)
1898
+ self.spot_shape_label.setVisible(True)
1899
+ self.spot_shape.setVisible(self.parent().po.all['set_spot_shape'])
1900
+ self.set_spot_size.setVisible(self.one_blob_per_arena.isChecked())
1901
+ self.spot_size_label.setVisible(self.one_blob_per_arena.isChecked())
1902
+ self.spot_size.setVisible(
1903
+ self.one_blob_per_arena.isChecked() and self.set_spot_size.isChecked())
1904
+ # self.arena_shape.setVisible(True)
1905
+ # self.arena_shape_label.setVisible(True)
1906
+ self.auto_delineation_flag = True
1907
+ self.first_im_parameters_answered = True
1908
+
1909
+ def auto_delineation(self):
1910
+ """ Method called in the decision tree"""
1911
+ # Do not proceed automatic delineation if there are more than one arena containing distinct spots
1912
+ # The automatic delineation algorithm cannot handle this situation
1913
+ if self.parent().po.vars['several_blob_per_arena'] and self.parent().po.sample_number > 1:
1914
+ self.manual_delineation()
1915
+ else:
1916
+ self.decision_label.setText(f"")
1917
+ # Save the current mask, its stats, remove useless memory and start delineation
1918
+ self.parent().po.first_image.update_current_images(self.parent().po.current_combination_id)
1919
+ self.parent().po.get_average_pixel_size()
1920
+ self.parent().po.all['are_gravity_centers_moving'] = 0
1921
+ self.start_crop_scale_subtract_delineate()
1922
+ self.visualize_label.setVisible(False)
1923
+ self.visualize.setVisible(False)
1924
+
1925
+ def asking_slower_or_manual_delineation(self):
1926
+ self.asking_slower_or_manual_delineation_flag = True
1927
+ self.decision_label.setText(f"Click yes to try a slower but more efficient delineation algorithm, no to do it manually")
1928
+ self.message.setText(f"Clicking no will allow you to draw each arena manually")
1929
+
1930
+ def slower_delineation(self):
1931
+ self.decision_label.setText(f"")
1932
+ self.arena_shape.setVisible(False)
1933
+ self.arena_shape_label.setVisible(False)
1934
+ # Save the current mask, its stats, remove useless memory and start delineation
1935
+ self.parent().po.first_image.update_current_images(self.parent().po.current_combination_id)
1936
+ self.parent().po.all['are_gravity_centers_moving'] = 1
1937
+ self.start_crop_scale_subtract_delineate()
1938
+
1939
+ def manual_delineation(self):
1940
+ """ Method called in the decision tree"""
1941
+ self.manual_delineation_flag = True
1942
+ self.parent().po.cropping(is_first_image=True)
1943
+ self.parent().po.get_average_pixel_size()
1944
+ self.reinitialize_image_and_masks(self.parent().po.first_image.bgr)
1945
+ self.reinitialize_bio_and_back_legend()
1946
+ self.available_arena_names = np.arange(1, self.parent().po.sample_number + 1)
1947
+ self.saved_coord = []
1948
+ self.arena_mask = np.zeros(self.parent().po.current_image.shape[:2], dtype=np.uint16)
1949
+ # self.next.setVisible(True)
1950
+ self.decision_label.setVisible(True)
1951
+ self.yes.setVisible(True)
1952
+ self.cell.setVisible(False)
1953
+ self.background.setVisible(False)
1954
+ self.arena_shape_label.setVisible(False)
1955
+ self.arena_shape.setVisible(False)
1956
+ self.no.setVisible(False)
1957
+ self.one_blob_per_arena.setVisible(False)
1958
+ self.one_blob_per_arena_label.setVisible(False)
1959
+ self.generate_analysis_options.setVisible(False)
1960
+ self.quickly.setVisible(False)
1961
+ self.carefully.setVisible(False)
1962
+ self.visualize.setVisible(False)
1963
+ self.visualize_label.setVisible(False)
1964
+ self.select_option.setVisible(False)
1965
+ self.select_option_label.setVisible(False)
1966
+ self.user_drawn_lines_label.setText("Draw each arena")
1967
+ self.user_drawn_lines_label.setVisible(True)
1968
+ self.decision_label.setText(
1969
+ f"Hold click to draw {self.parent().po.sample_number} arenas on the image")
1970
+ self.message.setText('Click Yes when it is done')
1971
+
1972
+ def last_image_question(self):
1973
+ """ Method called in the decision tree"""
1974
+ self.decision_label.setText(
1975
+ 'Do you want to check if the current parameters work for the last image:')
1976
+ self.message.setText('Click Yes if the cell color may change during the analysis.')
1977
+ self.yes.setVisible(True)
1978
+ self.no.setVisible(True)
1979
+ self.starting_differs_from_growing_cb.setVisible(True)
1980
+ self.starting_differs_from_growing_label.setVisible(True)
1981
+ self.image_number.setVisible(False)
1982
+ self.image_number_label.setVisible(False)
1983
+ self.read.setVisible(False)
1984
+ self.asking_last_image_flag = True
1985
+ # self.title_label.setVisible(False)
1986
+ self.step = 2
1987
+
1988
+ def start_last_image(self):
1989
+ self.is_first_image_flag = False
1990
+ # self.parent().po.vars["color_number"] = 2
1991
+ self.decision_label.setText('')
1992
+ self.yes.setVisible(False)
1993
+ self.no.setVisible(False)
1994
+ self.spot_size.setVisible(False)
1995
+ self.starting_differs_from_growing_cb.setVisible(False)
1996
+ self.starting_differs_from_growing_label.setVisible(False)
1997
+ self.message.setText('Gathering data and visualizing last image analysis result')
1998
+ self.parent().po.get_last_image()
1999
+ if self.thread['SaveManualDelineation'].isRunning():
2000
+ self.thread['SaveManualDelineation'].wait()
2001
+ self.parent().po.cropping(is_first_image=False)
2002
+ # self.parent().po.last_image = OneImageAnalysis(self.parent().po.last_im)
2003
+ self.reinitialize_image_and_masks(self.parent().po.last_image.bgr)
2004
+ self.reinitialize_bio_and_back_legend()
2005
+ self.parent().po.current_combination_id = 0
2006
+ # self.advanced_mode_cb.setChecked(True)
2007
+ self.visualize_is_clicked()
2008
+ self.user_drawn_lines_label.setText('Select and draw')
2009
+ self.user_drawn_lines_label.setVisible(True)
2010
+ self.cell.setVisible(True)
2011
+ self.background.setVisible(True)
2012
+ self.advanced_mode_cb.setVisible(True)
2013
+ self.advanced_mode_label.setVisible(True)
2014
+ self.visualize_label.setVisible(True)
2015
+ self.visualize.setVisible(True)
2016
+ self.row1_widget.setVisible(False)
2017
+ # self.title_label.setVisible(True)
2018
+ # self.row1_col1_widget.setVisible(False)
2019
+ # self.row1_col2_widget.setVisible(False)
2020
+
2021
+ def go_to_next_widget(self):
2022
+ if not self.thread['SaveManualDelineation'].isRunning() or not self.thread['FinalizeImageAnalysis'].isRunning() or not self.thread['SaveData'].isRunning():
2023
+
2024
+ self.popup = QtWidgets.QMessageBox()
2025
+ self.popup.setWindowTitle("Info")
2026
+ self.popup.setText("Final checks...")
2027
+ self.popup.setInformativeText("Close and wait until the video tracking window appears.")
2028
+ self.popup.setStandardButtons(QtWidgets.QMessageBox.Close)
2029
+ x = self.popup.exec_()
2030
+ self.decision_label.setVisible(False)
2031
+ self.yes.setVisible(False)
2032
+ self.no.setVisible(False)
2033
+ self.next.setVisible(True)
2034
+
2035
+
2036
+ self.message.setText(f"Final checks, wait... ")
2037
+ self.parent().last_tab = "image_analysis"
2038
+ self.thread['FinalizeImageAnalysis'].start()
2039
+ if self.parent().po.vars["color_number"] > 2:
2040
+ self.parent().videoanalysiswindow.select_option.clear()
2041
+ self.parent().videoanalysiswindow.select_option.addItem(f"1) Kmeans")
2042
+ self.parent().videoanalysiswindow.select_option.setCurrentIndex(0)
2043
+ self.parent().po.all['video_option'] = 0
2044
+ time.sleep(1 / 10)
2045
+ self.thread['FinalizeImageAnalysis'].wait()
2046
+ self.message.setText(f"")
2047
+
2048
+ self.video_tab.set_not_in_use()
2049
+ self.parent().last_tab = "image_analysis"
2050
+ self.parent().change_widget(3) # VideoAnalysisWindow
2051
+
2052
+ self.popup.close()
2053
+
2054
+ def closeEvent(self, event):
2055
+ event.accept
2056
+
2057
+
2058
+ # if __name__ == "__main__":
2059
+ # from cellects.gui.cellects import CellectsMainWidget
2060
+ # import sys
2061
+ # app = QtWidgets.QApplication([])
2062
+ # parent = CellectsMainWidget()
2063
+ # session = ImageAnalysisWindow(parent, False)
2064
+ # parent.insertWidget(0, session)
2065
+ # parent.show()
2066
+ # sys.exit(app.exec())