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.
- cellects/__init__.py +0 -0
- cellects/__main__.py +49 -0
- cellects/config/__init__.py +0 -0
- cellects/config/all_vars_dict.py +155 -0
- cellects/core/__init__.py +0 -0
- cellects/core/cellects_paths.py +31 -0
- cellects/core/cellects_threads.py +1451 -0
- cellects/core/motion_analysis.py +2010 -0
- cellects/core/one_image_analysis.py +1061 -0
- cellects/core/one_video_per_blob.py +540 -0
- cellects/core/program_organizer.py +1316 -0
- cellects/core/script_based_run.py +154 -0
- cellects/gui/__init__.py +0 -0
- cellects/gui/advanced_parameters.py +1258 -0
- cellects/gui/cellects.py +189 -0
- cellects/gui/custom_widgets.py +790 -0
- cellects/gui/first_window.py +449 -0
- cellects/gui/if_several_folders_window.py +239 -0
- cellects/gui/image_analysis_window.py +2066 -0
- cellects/gui/required_output.py +232 -0
- cellects/gui/video_analysis_window.py +656 -0
- cellects/icons/__init__.py +0 -0
- cellects/icons/cellects_icon.icns +0 -0
- cellects/icons/cellects_icon.ico +0 -0
- cellects/image_analysis/__init__.py +0 -0
- cellects/image_analysis/cell_leaving_detection.py +54 -0
- cellects/image_analysis/cluster_flux_study.py +102 -0
- cellects/image_analysis/image_segmentation.py +706 -0
- cellects/image_analysis/morphological_operations.py +1635 -0
- cellects/image_analysis/network_functions.py +1757 -0
- cellects/image_analysis/one_image_analysis_threads.py +289 -0
- cellects/image_analysis/progressively_add_distant_shapes.py +508 -0
- cellects/image_analysis/shape_descriptors.py +1016 -0
- cellects/utils/__init__.py +0 -0
- cellects/utils/decorators.py +14 -0
- cellects/utils/formulas.py +637 -0
- cellects/utils/load_display_save.py +1054 -0
- cellects/utils/utilitarian.py +490 -0
- cellects-0.1.2.dist-info/LICENSE.odt +0 -0
- cellects-0.1.2.dist-info/METADATA +132 -0
- cellects-0.1.2.dist-info/RECORD +44 -0
- cellects-0.1.2.dist-info/WHEEL +5 -0
- cellects-0.1.2.dist-info/entry_points.txt +2 -0
- 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())
|