cellects 0.1.3__py3-none-any.whl → 0.2.6__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/__main__.py +65 -25
- cellects/config/all_vars_dict.py +18 -17
- cellects/core/cellects_threads.py +1034 -396
- cellects/core/motion_analysis.py +1664 -2010
- cellects/core/one_image_analysis.py +1082 -1061
- cellects/core/program_organizer.py +1687 -1316
- cellects/core/script_based_run.py +80 -76
- cellects/gui/advanced_parameters.py +365 -326
- cellects/gui/cellects.py +102 -91
- cellects/gui/custom_widgets.py +4 -3
- cellects/gui/first_window.py +226 -104
- cellects/gui/if_several_folders_window.py +117 -68
- cellects/gui/image_analysis_window.py +841 -450
- cellects/gui/required_output.py +100 -56
- cellects/gui/ui_strings.py +840 -0
- cellects/gui/video_analysis_window.py +317 -135
- cellects/image_analysis/cell_leaving_detection.py +64 -4
- cellects/image_analysis/image_segmentation.py +451 -22
- cellects/image_analysis/morphological_operations.py +2166 -1635
- cellects/image_analysis/network_functions.py +616 -253
- cellects/image_analysis/one_image_analysis_threads.py +94 -153
- cellects/image_analysis/oscillations_functions.py +131 -0
- cellects/image_analysis/progressively_add_distant_shapes.py +2 -3
- cellects/image_analysis/shape_descriptors.py +517 -466
- cellects/utils/formulas.py +169 -6
- cellects/utils/load_display_save.py +362 -105
- cellects/utils/utilitarian.py +86 -9
- cellects-0.2.6.dist-info/LICENSE +675 -0
- cellects-0.2.6.dist-info/METADATA +829 -0
- cellects-0.2.6.dist-info/RECORD +44 -0
- cellects/core/one_video_per_blob.py +0 -540
- cellects/image_analysis/cluster_flux_study.py +0 -102
- cellects-0.1.3.dist-info/LICENSE.odt +0 -0
- cellects-0.1.3.dist-info/METADATA +0 -176
- cellects-0.1.3.dist-info/RECORD +0 -44
- {cellects-0.1.3.dist-info → cellects-0.2.6.dist-info}/WHEEL +0 -0
- {cellects-0.1.3.dist-info → cellects-0.2.6.dist-info}/entry_points.txt +0 -0
- {cellects-0.1.3.dist-info → cellects-0.2.6.dist-info}/top_level.txt +0 -0
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
"""Third main widget for Cellects GUI enabling video analysis configuration and execution.
|
|
3
|
+
|
|
4
|
+
This module implements a video tracking interface for analyzing cell movement through configurable parameters like
|
|
5
|
+
arena selection, segmentation methods, and smoothing thresholds. It provides interactive controls including spinboxes,
|
|
6
|
+
comboboxes, buttons for detection/post-processing, and an image display area with full-screen support. Threaded
|
|
7
|
+
operations (VideoReaderThread, OneArenaThread) handle background processing to maintain UI responsiveness.
|
|
8
|
+
|
|
9
|
+
Main Components
|
|
10
|
+
VideoAnalysisWindow : QWidget subclass implementing the video analysis interface with tab navigation, parameter
|
|
11
|
+
controls, and thread coordination
|
|
12
|
+
|
|
13
|
+
Notes
|
|
14
|
+
Uses QThread for background operations to maintain UI responsiveness.
|
|
6
15
|
"""
|
|
7
16
|
import logging
|
|
8
17
|
import numpy as np
|
|
9
|
-
import cv2
|
|
10
18
|
from PySide6 import QtWidgets, QtCore
|
|
11
19
|
|
|
12
20
|
from cellects.core.cellects_threads import (
|
|
@@ -15,13 +23,54 @@ from cellects.core.cellects_threads import (
|
|
|
15
23
|
from cellects.gui.custom_widgets import (
|
|
16
24
|
MainTabsType, InsertImage, FullScreenImage, PButton, Spinbox,
|
|
17
25
|
Combobox, Checkbox, FixedText)
|
|
26
|
+
from cellects.gui.ui_strings import FW, VAW
|
|
18
27
|
|
|
19
28
|
|
|
20
29
|
class VideoAnalysisWindow(MainTabsType):
|
|
21
30
|
def __init__(self, parent, night_mode):
|
|
31
|
+
"""
|
|
32
|
+
Initialize the VideoAnalysis window with a parent widget and night mode setting.
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
parent : QWidget
|
|
37
|
+
The parent widget to which this window will be attached.
|
|
38
|
+
night_mode : bool
|
|
39
|
+
A boolean indicating whether the night mode should be enabled.
|
|
40
|
+
|
|
41
|
+
Examples
|
|
42
|
+
--------
|
|
43
|
+
>>> from PySide6 import QtWidgets
|
|
44
|
+
>>> from cellects.gui.cellects import CellectsMainWidget
|
|
45
|
+
>>> from cellects.gui.video_analysis_window import VideoAnalysisWindow
|
|
46
|
+
>>> import sys
|
|
47
|
+
>>> app = QtWidgets.QApplication([])
|
|
48
|
+
>>> parent = CellectsMainWidget()
|
|
49
|
+
>>> session = VideoAnalysisWindow(parent, False)
|
|
50
|
+
>>> session.true_init()
|
|
51
|
+
>>> parent.insertWidget(0, session)
|
|
52
|
+
>>> parent.show()
|
|
53
|
+
>>> sys.exit(app.exec())
|
|
54
|
+
"""
|
|
22
55
|
super().__init__(parent, night_mode)
|
|
23
56
|
logging.info("Initialize VideoAnalysisWindow")
|
|
24
57
|
self.setParent(parent)
|
|
58
|
+
self.true_init()
|
|
59
|
+
|
|
60
|
+
def true_init(self):
|
|
61
|
+
"""
|
|
62
|
+
Initialize the video tracking interface and set up its UI components.
|
|
63
|
+
|
|
64
|
+
Extended Description
|
|
65
|
+
--------------------
|
|
66
|
+
This method initializes various tabs, threads, and UI elements for the video tracking interface. It sets up
|
|
67
|
+
event handlers for tab clicks and configures layout components such as labels, buttons, spinboxes, and
|
|
68
|
+
comboboxes.
|
|
69
|
+
|
|
70
|
+
Notes
|
|
71
|
+
-----
|
|
72
|
+
This method assumes that the parent widget has a 'po' attribute with specific settings and variables.
|
|
73
|
+
"""
|
|
25
74
|
self.data_tab.set_not_in_use()
|
|
26
75
|
self.image_tab.set_not_usable()
|
|
27
76
|
self.video_tab.set_in_use()
|
|
@@ -33,21 +82,10 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
33
82
|
self.thread['ChangeOneRepResult'] = ChangeOneRepResultThread(self.parent())
|
|
34
83
|
self.thread['RunAll'] = RunAllThread(self.parent())
|
|
35
84
|
self.previous_arena = 0
|
|
36
|
-
|
|
37
|
-
self.layout = QtWidgets.QGridLayout()
|
|
38
|
-
self.grid_widget = QtWidgets.QWidget()
|
|
39
|
-
|
|
40
|
-
# self.title = FixedText('Video tracking', police=30, night_mode=self.parent().po.all['night_mode'])
|
|
41
|
-
# self.title.setAlignment(QtCore.Qt.AlignHCenter)
|
|
42
85
|
curr_row_main_layout = 0
|
|
43
86
|
ncol = 1
|
|
44
|
-
|
|
45
|
-
# curr_row_main_layout += 2
|
|
46
|
-
self.layout.addItem(self.vertical_space, curr_row_main_layout, 0, 1, ncol)
|
|
87
|
+
self.Vlayout.addItem(self.vertical_space)#, curr_row_main_layout, 0, 1, ncol)
|
|
47
88
|
curr_row_main_layout += 1
|
|
48
|
-
#
|
|
49
|
-
# self.layout.addWidget(self.arena_widget, curr_row_main_layout, 0)
|
|
50
|
-
# curr_row_main_layout += 1
|
|
51
89
|
|
|
52
90
|
# Open subtitle
|
|
53
91
|
self.general_step_widget = QtWidgets.QWidget()
|
|
@@ -61,7 +99,7 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
61
99
|
self.general_step_layout.addWidget(self.general_step_button)
|
|
62
100
|
self.general_step_layout.addItem(self.horizontal_space)
|
|
63
101
|
self.general_step_widget.setLayout(self.general_step_layout)
|
|
64
|
-
self.
|
|
102
|
+
self.Vlayout.addWidget(self.general_step_widget)#, curr_row_main_layout, 0, 1, ncol)
|
|
65
103
|
curr_row_main_layout += 1
|
|
66
104
|
|
|
67
105
|
# Open central widget
|
|
@@ -72,18 +110,12 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
72
110
|
self.left_options_widget = QtWidgets.QWidget()
|
|
73
111
|
self.left_options_layout = QtWidgets.QVBoxLayout()
|
|
74
112
|
self.left_options_widget.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
|
|
75
|
-
# self.left_options_widget.setFixedWidth(420)
|
|
76
113
|
|
|
77
114
|
self.arena_widget = QtWidgets.QWidget()
|
|
78
115
|
self.arena_layout = QtWidgets.QHBoxLayout()
|
|
79
|
-
self.arena_label = FixedText(
|
|
80
|
-
tip="
|
|
116
|
+
self.arena_label = FixedText(VAW["Arena_to_analyze"]["label"] + ':',
|
|
117
|
+
tip=VAW["Arena_to_analyze"]["tips"],
|
|
81
118
|
night_mode=self.parent().po.all['night_mode'])
|
|
82
|
-
# if isinstance(self.parent().po.all['sample_number_per_folder'], int):
|
|
83
|
-
# self.parent().po.all['folder_number'] = 1
|
|
84
|
-
# if self.parent().po.all['folder_number'] > 1:
|
|
85
|
-
# sample_size = self.parent().po.all['sample_number_per_folder']
|
|
86
|
-
# else:
|
|
87
119
|
sample_size = self.parent().po.all['sample_number_per_folder'][0]
|
|
88
120
|
if self.parent().po.all['arena'] > sample_size:
|
|
89
121
|
self.parent().po.all['arena'] = 1
|
|
@@ -92,12 +124,9 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
92
124
|
night_mode=self.parent().po.all['night_mode'])
|
|
93
125
|
self.arena.valueChanged.connect(self.arena_changed)
|
|
94
126
|
|
|
95
|
-
# self.arena_layout.addItem(self.horizontal_space)
|
|
96
127
|
self.arena_layout.addWidget(self.arena_label)
|
|
97
128
|
self.arena_layout.addWidget(self.arena)
|
|
98
|
-
# self.arena_layout.addItem(self.horizontal_space)
|
|
99
129
|
self.arena_widget.setLayout(self.arena_layout)
|
|
100
|
-
# self.arena_layout.setAlignment(QtCore.Qt.AlignHCenter)
|
|
101
130
|
self.left_options_layout.addWidget(self.arena_widget)
|
|
102
131
|
|
|
103
132
|
|
|
@@ -110,13 +139,12 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
110
139
|
self.parent().po.vars['repeat_video_smoothing'] = self.parent().po.vars['iterate_smoothing']
|
|
111
140
|
self.maximal_growth_factor = Spinbox(min=0, max=0.5, val=self.parent().po.vars['maximal_growth_factor'],
|
|
112
141
|
decimals=3, night_mode=self.parent().po.all['night_mode'])
|
|
113
|
-
self.maximal_growth_factor_label = FixedText(
|
|
114
|
-
tip="
|
|
142
|
+
self.maximal_growth_factor_label = FixedText(VAW["Maximal_growth_factor"]["label"] + ':',
|
|
143
|
+
tip=VAW["Maximal_growth_factor"]["tips"],
|
|
115
144
|
night_mode=self.parent().po.all['night_mode'])
|
|
116
145
|
self.maximal_growth_factor.valueChanged.connect(self.maximal_growth_factor_changed)
|
|
117
146
|
self.growth_per_frame_layout.addWidget(self.maximal_growth_factor_label)
|
|
118
147
|
self.growth_per_frame_layout.addWidget(self.maximal_growth_factor)
|
|
119
|
-
# self.growth_per_frame_layout.setAlignment(QtCore.Qt.AlignHCenter)
|
|
120
148
|
self.growth_per_frame_widget.setLayout(self.growth_per_frame_layout)
|
|
121
149
|
self.left_options_layout.addWidget(self.growth_per_frame_widget)
|
|
122
150
|
|
|
@@ -124,45 +152,36 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
124
152
|
self.iterate_layout = QtWidgets.QHBoxLayout()
|
|
125
153
|
self.repeat_video_smoothing = Spinbox(min=0, max=10, val=self.parent().po.vars['repeat_video_smoothing'],
|
|
126
154
|
night_mode=self.parent().po.all['night_mode'])
|
|
127
|
-
self.repeat_video_smoothing_label = FixedText(
|
|
128
|
-
tip="
|
|
155
|
+
self.repeat_video_smoothing_label = FixedText(VAW["Temporal_smoothing"]["label"] + ':',
|
|
156
|
+
tip=VAW["Temporal_smoothing"]["tips"],
|
|
129
157
|
night_mode=self.parent().po.all['night_mode'])
|
|
130
158
|
self.repeat_video_smoothing.valueChanged.connect(self.repeat_video_smoothing_changed)
|
|
131
159
|
self.iterate_layout.addWidget(self.repeat_video_smoothing_label)
|
|
132
160
|
self.iterate_layout.addWidget(self.repeat_video_smoothing)
|
|
133
|
-
# self.iterate_layout.setAlignment(QtCore.Qt.AlignHCenter)
|
|
134
161
|
self.iterate_widget.setLayout(self.iterate_layout)
|
|
135
162
|
self.left_options_layout.addWidget(self.iterate_widget)
|
|
136
163
|
|
|
137
164
|
|
|
138
|
-
self.select_option_label = FixedText('
|
|
139
|
-
tip=
|
|
165
|
+
self.select_option_label = FixedText(VAW["Segmentation_method"]["label"] + ':',
|
|
166
|
+
tip=VAW["Segmentation_method"]["tips"],
|
|
140
167
|
night_mode=self.parent().po.all['night_mode'])
|
|
141
168
|
self.select_option = Combobox([], night_mode=self.parent().po.all['night_mode'])
|
|
142
169
|
self.select_option_label.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
|
|
143
170
|
self.select_option.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
|
|
144
171
|
self.select_option.setFixedWidth(175)
|
|
145
|
-
# self.select_option_label.setFixedWidth(265)
|
|
146
|
-
# self.select_option.setFixedWidth(150)
|
|
147
172
|
self.select_option.addItem("1. Frame by frame")
|
|
148
173
|
self.select_option.addItem("2. Dynamical threshold")
|
|
149
174
|
self.select_option.addItem("3. Dynamical slope")
|
|
150
175
|
self.select_option.addItem("4. Threshold and Slope")
|
|
151
176
|
self.select_option.addItem("5. Threshold or Slope")
|
|
152
|
-
# for option in range(5):
|
|
153
|
-
# self.select_option.addItem(f"Option {option + 1}")
|
|
154
177
|
self.select_option.setCurrentIndex(self.parent().po.all['video_option'])
|
|
155
178
|
self.select_option.currentTextChanged.connect(self.option_changed)
|
|
156
|
-
# self.select_option_label.setVisible(self.parent().po.vars["color_number"] == 2)
|
|
157
|
-
# self.select_option.setVisible(self.parent().po.vars["color_number"] == 2)
|
|
158
179
|
|
|
159
180
|
# Open the choose best option row layout
|
|
160
181
|
self.options_row_widget = QtWidgets.QWidget()
|
|
161
182
|
self.options_row_layout = QtWidgets.QHBoxLayout()
|
|
162
|
-
# self.options_row_layout.addItem(self.horizontal_space)
|
|
163
183
|
self.options_row_layout.addWidget(self.select_option_label)
|
|
164
184
|
self.options_row_layout.addWidget(self.select_option)
|
|
165
|
-
# self.options_row_layout.addItem(self.horizontal_space)
|
|
166
185
|
self.options_row_layout.setAlignment(QtCore.Qt.AlignHCenter)
|
|
167
186
|
self.options_row_layout.setAlignment(QtCore.Qt.AlignVCenter)
|
|
168
187
|
self.options_row_widget.setLayout(self.options_row_layout)
|
|
@@ -184,10 +203,9 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
184
203
|
self.right_options_widget = QtWidgets.QWidget()
|
|
185
204
|
self.right_options_layout = QtWidgets.QVBoxLayout()
|
|
186
205
|
self.right_options_widget.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
|
|
187
|
-
# self.right_options_widget.setFixedWidth(420)
|
|
188
206
|
|
|
189
207
|
self.compute_all_options_label = FixedText('Compute all options',
|
|
190
|
-
tip=
|
|
208
|
+
tip=VAW["Segmentation_method"]["tips"],
|
|
191
209
|
night_mode=self.parent().po.all['night_mode'])
|
|
192
210
|
self.compute_all_options_cb = Checkbox(self.parent().po.all['compute_all_options'])
|
|
193
211
|
self.compute_all_options_cb.setStyleSheet("QCheckBox::indicator {width: 12px;height: 12px;background-color: transparent;"
|
|
@@ -208,11 +226,13 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
208
226
|
self.all_options_row_widget.setLayout(self.all_options_row_layout)
|
|
209
227
|
self.right_options_layout.addWidget(self.all_options_row_widget)
|
|
210
228
|
|
|
211
|
-
self.load_one_arena = PButton(
|
|
229
|
+
self.load_one_arena = PButton(VAW["Load_one_arena"]["label"], tip=VAW["Load_one_arena"]["tips"],
|
|
230
|
+
night_mode=self.parent().po.all['night_mode'])
|
|
212
231
|
self.load_one_arena.clicked.connect(self.load_one_arena_is_clicked)
|
|
213
|
-
self.detection = PButton(
|
|
232
|
+
self.detection = PButton(VAW["Detection"]["label"], tip=VAW["Detection"]["tips"],
|
|
233
|
+
night_mode=self.parent().po.all['night_mode'])
|
|
214
234
|
self.detection.clicked.connect(self.detection_is_clicked)
|
|
215
|
-
self.read = PButton(
|
|
235
|
+
self.read = PButton(VAW["Read"]["label"], tip=VAW["Read"]["tips"], night_mode=self.parent().po.all['night_mode'])
|
|
216
236
|
self.read.clicked.connect(self.read_is_clicked)
|
|
217
237
|
self.read.setVisible(False)
|
|
218
238
|
self.right_options_layout.addWidget(self.load_one_arena, alignment=QtCore.Qt.AlignCenter)
|
|
@@ -226,10 +246,7 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
226
246
|
self.video_display_layout.addItem(self.horizontal_space)
|
|
227
247
|
# Close central widget
|
|
228
248
|
self.video_display_widget.setLayout(self.video_display_layout)
|
|
229
|
-
|
|
230
|
-
# self.video_display_widget.setAlignment(QtCore.Qt.AlignHCenter)
|
|
231
|
-
# self.video_display_widget.setFixedHeight(500)
|
|
232
|
-
self.layout.addWidget(self.video_display_widget, curr_row_main_layout, 0)
|
|
249
|
+
self.Vlayout.addWidget(self.video_display_widget)#, curr_row_main_layout, 0)
|
|
233
250
|
curr_row_main_layout += 1
|
|
234
251
|
|
|
235
252
|
# Open Second step row
|
|
@@ -252,11 +269,10 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
252
269
|
self.do_fading.stateChanged.connect(self.do_fading_check)
|
|
253
270
|
self.fading = Spinbox(min=- 1, max=1, val=self.parent().po.vars['fading'], decimals=2,
|
|
254
271
|
night_mode=self.parent().po.all['night_mode'])
|
|
255
|
-
self.fading_label = FixedText(
|
|
256
|
-
tip="
|
|
272
|
+
self.fading_label = FixedText(VAW["Fading_detection"]["label"],
|
|
273
|
+
tip=VAW["Fading_detection"]["tips"],
|
|
257
274
|
night_mode=self.parent().po.all['night_mode'])
|
|
258
275
|
self.fading.valueChanged.connect(self.fading_changed)
|
|
259
|
-
# self.fading.setVisible(self.parent().po.vars['do_fading'])
|
|
260
276
|
self.fading_layout.addWidget(self.do_fading)
|
|
261
277
|
self.fading_layout.addWidget(self.fading_label)
|
|
262
278
|
self.fading_layout.addWidget(self.fading)
|
|
@@ -264,23 +280,23 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
264
280
|
self.fading_widget.setLayout(self.fading_layout)
|
|
265
281
|
self.second_step_layout.addWidget(self.fading_widget)
|
|
266
282
|
|
|
267
|
-
self.post_processing = PButton(
|
|
283
|
+
self.post_processing = PButton(VAW["Post_processing"]["label"], tip=VAW["Post_processing"]["tips"],
|
|
284
|
+
night_mode=self.parent().po.all['night_mode'])
|
|
268
285
|
self.post_processing.clicked.connect(self.post_processing_is_clicked)
|
|
269
286
|
self.second_step_layout.addWidget(self.post_processing)
|
|
270
|
-
# self.second_step_layout.addWidget(self.post_processing, alignment=QtCore.Qt.AlignCenter)
|
|
271
287
|
|
|
272
|
-
self.save_one_result = PButton(
|
|
288
|
+
self.save_one_result = PButton(VAW["Save_one_result"]["label"], tip=VAW["Save_one_result"]["tips"],
|
|
289
|
+
night_mode=self.parent().po.all['night_mode'])
|
|
273
290
|
self.save_one_result.clicked.connect(self.save_one_result_is_clicked)
|
|
274
291
|
self.second_step_layout.addWidget(self.save_one_result)
|
|
275
|
-
# self.second_step_layout.addWidget(self.save_one_result, alignment=QtCore.Qt.AlignCenter)
|
|
276
292
|
|
|
277
293
|
# Close Second step row
|
|
278
294
|
self.second_step_layout.setAlignment(QtCore.Qt.AlignHCenter)
|
|
279
295
|
self.second_step_layout.addItem(self.horizontal_space)
|
|
280
296
|
self.second_step_widget.setLayout(self.second_step_layout)
|
|
281
|
-
self.
|
|
297
|
+
self.Vlayout.addItem(self.vertical_space)#, curr_row_main_layout, 0, 1, ncol)
|
|
282
298
|
curr_row_main_layout += 1
|
|
283
|
-
self.
|
|
299
|
+
self.Vlayout.addWidget(self.second_step_widget)#, curr_row_main_layout, 0)
|
|
284
300
|
curr_row_main_layout += 1
|
|
285
301
|
|
|
286
302
|
# Open last options row widget
|
|
@@ -288,24 +304,27 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
288
304
|
self.last_options_layout = QtWidgets.QHBoxLayout()
|
|
289
305
|
self.last_options_layout.addItem(self.horizontal_space)
|
|
290
306
|
|
|
291
|
-
self.advanced_parameters = PButton(
|
|
307
|
+
self.advanced_parameters = PButton(FW["Advanced_parameters"]["label"], tip=FW["Advanced_parameters"]["tips"],
|
|
308
|
+
night_mode=self.parent().po.all['night_mode'])
|
|
292
309
|
self.advanced_parameters.clicked.connect(self.advanced_parameters_is_clicked)
|
|
293
310
|
self.last_options_layout.addWidget(self.advanced_parameters)
|
|
294
311
|
|
|
295
312
|
# Required Outputs widget
|
|
296
|
-
self.required_outputs = PButton(
|
|
313
|
+
self.required_outputs = PButton(FW["Required_outputs"]["label"], tip=FW["Required_outputs"]["tips"],
|
|
314
|
+
night_mode=self.parent().po.all['night_mode'])
|
|
297
315
|
self.required_outputs.clicked.connect(self.required_outputs_is_clicked)
|
|
298
316
|
self.last_options_layout.addWidget(self.required_outputs)
|
|
299
317
|
|
|
300
318
|
# Save all choices widget
|
|
301
|
-
self.save_all_vars = PButton(
|
|
319
|
+
self.save_all_vars = PButton(VAW["Save_all_choices"]["label"], tip=VAW["Save_all_choices"]["tips"],
|
|
320
|
+
night_mode=self.parent().po.all['night_mode'])
|
|
302
321
|
self.save_all_vars.clicked.connect(self.save_current_settings)
|
|
303
322
|
self.last_options_layout.addWidget(self.save_all_vars)
|
|
304
323
|
|
|
305
324
|
# Close last options widget
|
|
306
325
|
self.last_options_layout.addItem(self.horizontal_space)
|
|
307
326
|
self.last_options_widget.setLayout(self.last_options_layout)
|
|
308
|
-
self.
|
|
327
|
+
self.Vlayout.addWidget(self.last_options_widget)#, curr_row_main_layout, 0)
|
|
309
328
|
curr_row_main_layout += 1
|
|
310
329
|
|
|
311
330
|
self.message = QtWidgets.QLabel(self)
|
|
@@ -316,7 +335,8 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
316
335
|
self.previous = PButton('Previous', night_mode=self.parent().po.all['night_mode'])
|
|
317
336
|
self.previous.clicked.connect(self.previous_is_clicked)
|
|
318
337
|
|
|
319
|
-
self.run_all = PButton(
|
|
338
|
+
self.run_all = PButton(VAW["Run_All"]["label"], tip=VAW["Run_All"]["tips"],
|
|
339
|
+
night_mode=self.parent().po.all['night_mode'])
|
|
320
340
|
self.run_all.clicked.connect(self.run_all_is_clicked)
|
|
321
341
|
|
|
322
342
|
# Open last row widget
|
|
@@ -328,21 +348,32 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
328
348
|
self.last_row_layout.addWidget(self.run_all)
|
|
329
349
|
# Close last row widget
|
|
330
350
|
self.last_row_widget.setLayout(self.last_row_layout)
|
|
331
|
-
self.
|
|
332
|
-
self.
|
|
351
|
+
self.Vlayout.addItem(self.vertical_space)#, curr_row_main_layout, 0, 1, ncol)
|
|
352
|
+
self.Vlayout.addWidget(self.last_row_widget)#, curr_row_main_layout + 1, 0)
|
|
333
353
|
|
|
334
|
-
self.grid_widget.setLayout(self.layout)
|
|
335
|
-
self.Vlayout.addItem(self.vertical_space)
|
|
336
|
-
self.Vlayout.addWidget(self.grid_widget)
|
|
337
354
|
self.setLayout(self.Vlayout)
|
|
338
|
-
# self.advanced_mode_check()
|
|
339
355
|
|
|
340
356
|
def display_conditionally_visible_widgets(self):
|
|
357
|
+
"""
|
|
358
|
+
Display Conditionally Visible Widgets
|
|
359
|
+
"""
|
|
341
360
|
self.select_option_label.setVisible(self.parent().po.vars["color_number"] == 2)
|
|
342
361
|
self.select_option.setVisible(self.parent().po.vars["color_number"] == 2)
|
|
343
362
|
self.fading.setVisible(self.parent().po.vars['do_fading'])
|
|
344
363
|
|
|
345
364
|
def step_done_is_clicked(self):
|
|
365
|
+
"""
|
|
366
|
+
Step the analysis progress when 'Done' button is clicked.
|
|
367
|
+
|
|
368
|
+
Increments the current step and updates the UI accordingly based on the
|
|
369
|
+
new step value. Updates labels, tooltips, and visibility of widgets.
|
|
370
|
+
|
|
371
|
+
Notes
|
|
372
|
+
-----
|
|
373
|
+
This method is automatically called when the 'Done' button is clicked.
|
|
374
|
+
It updates the GUI elements to reflect progress in a multi-step
|
|
375
|
+
analysis process.
|
|
376
|
+
"""
|
|
346
377
|
self.current_step += 1
|
|
347
378
|
if self.current_step == 1:
|
|
348
379
|
self.general_step_label.setText('Step 2: Tune fading and advanced parameters to improve Post processing')
|
|
@@ -357,6 +388,9 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
357
388
|
self.general_step_button.setVisible(False)
|
|
358
389
|
|
|
359
390
|
def reset_general_step(self):
|
|
391
|
+
"""
|
|
392
|
+
Reset the general step counter and update UI labels.
|
|
393
|
+
"""
|
|
360
394
|
self.current_step = 0
|
|
361
395
|
self.general_step_label.setText('Step 1: Tune parameters to improve Detection')
|
|
362
396
|
self.general_step_label.setToolTip('Detection uses only the visible parameters and those\npreviously determined on the first or last image.')
|
|
@@ -364,13 +398,29 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
364
398
|
self.second_step_widget.setVisible(False)
|
|
365
399
|
|
|
366
400
|
def full_screen_display(self, event):
|
|
401
|
+
"""
|
|
402
|
+
Full-screen display of an image.
|
|
403
|
+
|
|
404
|
+
This method creates a full-screen image popup and displays it. The
|
|
405
|
+
full-screen image is initialized with the current image to display,
|
|
406
|
+
and its size is set to match the screen dimensions.
|
|
407
|
+
"""
|
|
367
408
|
self.popup_img = FullScreenImage(self.parent().image_to_display, self.parent().screen_width, self.parent().screen_height)
|
|
368
409
|
self.popup_img.show()
|
|
369
410
|
|
|
370
411
|
def option_changed(self):
|
|
371
412
|
"""
|
|
372
|
-
|
|
373
|
-
|
|
413
|
+
Handles the logic for changing video option settings and logging the appropriate actions.
|
|
414
|
+
|
|
415
|
+
This method is responsible for updating various flags and configuration variables
|
|
416
|
+
based on the selected video option. It also logs informational messages regarding
|
|
417
|
+
the behavior of the segmentation algorithms being enabled or disabled.
|
|
418
|
+
|
|
419
|
+
Notes
|
|
420
|
+
-----
|
|
421
|
+
This function updates the parent object's configuration variables and logs messages
|
|
422
|
+
based on the selected video option. The behavior changes depending on the number of
|
|
423
|
+
colors detected and the specific video option chosen.
|
|
374
424
|
"""
|
|
375
425
|
self.parent().po.all['video_option'] = self.select_option.currentIndex()
|
|
376
426
|
self.parent().po.vars['frame_by_frame_segmentation'] = False
|
|
@@ -397,26 +447,17 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
397
447
|
elif self.parent().po.all['video_option'] == 4:
|
|
398
448
|
logging.info(f"This option will detect cell(s) using the dynamic threshold OR slope algorithms with a maximal growth factor of {self.parent().po.vars['maximal_growth_factor']}")
|
|
399
449
|
self.parent().po.vars['true_if_use_light_AND_slope_else_OR'] = False
|
|
400
|
-
# self.parent().po.motion
|
|
401
|
-
|
|
402
|
-
# def advanced_mode_check(self):
|
|
403
|
-
# advanced_mode = self.advanced_mode_cb.isChecked()
|
|
404
|
-
# self.parent().po.all['expert_mode'] = advanced_mode
|
|
405
|
-
# self.second_step_widget.setVisible(advanced_mode or self.current_step > 0)
|
|
406
|
-
# if advanced_mode:
|
|
407
|
-
# if self.current_step == 0:
|
|
408
|
-
# self.current_step += 1
|
|
409
|
-
# self.general_step_label.setText('Step 2: Tune fading and advanced parameters to improve Post processing')
|
|
410
|
-
# self.save_one_result.setVisible(self.current_step == 2)
|
|
411
|
-
|
|
412
|
-
# self.maximal_growth_factor.setVisible(advanced_mode)
|
|
413
|
-
# self.maximal_growth_factor_label.setVisible(advanced_mode)
|
|
414
|
-
# self.fading.setVisible(advanced_mode)
|
|
415
|
-
# self.fading_label.setVisible(advanced_mode)
|
|
416
|
-
# self.repeat_video_smoothing.setVisible(advanced_mode)
|
|
417
|
-
# self.repeat_video_smoothing_label.setVisible(advanced_mode)
|
|
418
450
|
|
|
419
451
|
def data_tab_is_clicked(self):
|
|
452
|
+
"""
|
|
453
|
+
Handles the logic for when the "Data specifications" button is clicked in the interface,
|
|
454
|
+
leading to the FirstWindow.
|
|
455
|
+
|
|
456
|
+
Notes
|
|
457
|
+
-----
|
|
458
|
+
This function displays an error message when a thread relative to the current window is running.
|
|
459
|
+
This function also save the id of the following window for later use.
|
|
460
|
+
"""
|
|
420
461
|
if self.thread['VideoReader'].isRunning() or self.thread['OneArena'].isRunning() or self.thread['ChangeOneRepResult'].isRunning() or self.parent().firstwindow.thread["RunAll"].isRunning():
|
|
421
462
|
self.message.setText("Wait for the analysis to end, or restart Cellects")
|
|
422
463
|
else:
|
|
@@ -424,6 +465,15 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
424
465
|
self.parent().change_widget(0) # FirstWidget
|
|
425
466
|
|
|
426
467
|
def image_tab_is_clicked(self):
|
|
468
|
+
"""
|
|
469
|
+
Handles the logic for when the "Image analysis" button is clicked in the interface,
|
|
470
|
+
leading to the image analysis window.
|
|
471
|
+
|
|
472
|
+
Notes
|
|
473
|
+
-----
|
|
474
|
+
This function displays an error message when a thread relative to the current window is running.
|
|
475
|
+
This function also save the id of the following window for later use.
|
|
476
|
+
"""
|
|
427
477
|
if self.image_tab.state != "not_usable":
|
|
428
478
|
if self.thread['VideoReader'].isRunning() or self.thread['OneArena'].isRunning() or self.thread[
|
|
429
479
|
'ChangeOneRepResult'].isRunning() or self.parent().firstwindow.thread["RunAll"].isRunning():
|
|
@@ -434,27 +484,59 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
434
484
|
|
|
435
485
|
|
|
436
486
|
def required_outputs_is_clicked(self):
|
|
487
|
+
"""
|
|
488
|
+
Sets the required outputs flag and changes the widget to the "Required Output" window.
|
|
489
|
+
"""
|
|
437
490
|
self.parent().last_is_first = False
|
|
438
491
|
self.parent().change_widget(4) # RequiredOutput
|
|
439
492
|
|
|
440
493
|
def advanced_parameters_is_clicked(self):
|
|
494
|
+
"""
|
|
495
|
+
Modifies the interface to display advanced parameters.
|
|
496
|
+
"""
|
|
441
497
|
self.parent().last_is_first = False
|
|
442
498
|
self.parent().widget(5).update_csc_editing_display()
|
|
443
499
|
self.parent().change_widget(5) # AdvancedParameters
|
|
444
500
|
|
|
445
501
|
def previous_is_clicked(self):
|
|
502
|
+
"""
|
|
503
|
+
Transition to the previous tab based on current tab history.
|
|
504
|
+
|
|
505
|
+
This method handles the logic for navigating back through the
|
|
506
|
+
application's tabs when "previous" is clicked. It updates the current
|
|
507
|
+
tab to the one that was last visited, cycling through the predefined
|
|
508
|
+
order of tabs.
|
|
509
|
+
|
|
510
|
+
Notes
|
|
511
|
+
-----
|
|
512
|
+
This function is part of a state-machine-like navigation system that
|
|
513
|
+
tracks tab history. It assumes the parent widget has methods `last_tab`
|
|
514
|
+
and `change_widget` for managing the current view.
|
|
515
|
+
"""
|
|
446
516
|
if self.parent().last_tab == "data_specifications":
|
|
447
517
|
self.parent().change_widget(0) # FirstWidget
|
|
448
518
|
elif self.parent().last_tab == "image_analysis":
|
|
449
519
|
self.parent().change_widget(2) # ThirdWidget
|
|
450
520
|
self.parent().last_tab = "video_analysis"
|
|
451
|
-
# self.parent().change_widget(2) # SecondWidget
|
|
452
521
|
|
|
453
522
|
def save_all_vars_thread(self):
|
|
523
|
+
"""
|
|
524
|
+
Start the 'SaveAllVars' thread if it is not already running.
|
|
525
|
+
|
|
526
|
+
This method is used to ensure that variable saving operations are performed
|
|
527
|
+
in a separate thread to avoid blocking the main application.
|
|
528
|
+
"""
|
|
454
529
|
if not self.parent().thread['SaveAllVars'].isRunning():
|
|
455
530
|
self.parent().thread['SaveAllVars'].start() # SaveAllVarsThreadInThirdWidget
|
|
456
531
|
|
|
457
532
|
def save_current_settings(self):
|
|
533
|
+
"""
|
|
534
|
+
Saves the current settings from UI components to persistent storage.
|
|
535
|
+
|
|
536
|
+
This method captures the values of various UI components and stores
|
|
537
|
+
them in a persistent data structure to ensure settings are saved across
|
|
538
|
+
sessions.
|
|
539
|
+
"""
|
|
458
540
|
self.parent().po.vars['maximal_growth_factor'] = self.maximal_growth_factor.value()
|
|
459
541
|
self.parent().po.vars['repeat_video_smoothing'] = int(np.round(self.repeat_video_smoothing.value()))
|
|
460
542
|
self.parent().po.vars['do_fading'] = self.do_fading.isChecked()
|
|
@@ -464,24 +546,40 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
464
546
|
self.save_all_vars_thread()
|
|
465
547
|
|
|
466
548
|
def repeat_video_smoothing_changed(self):
|
|
549
|
+
"""
|
|
550
|
+
Save the repeat_video_smoothing spinbox value to set how many times the pixel intensity dynamics will be
|
|
551
|
+
smoothed.
|
|
552
|
+
"""
|
|
467
553
|
self.parent().po.vars['repeat_video_smoothing'] = int(np.round(self.repeat_video_smoothing.value()))
|
|
468
|
-
# self.save_all_vars_is_clicked()
|
|
469
554
|
|
|
470
555
|
def do_fading_check(self):
|
|
556
|
+
"""
|
|
557
|
+
Save the fading checkbox value to allow cases where pixels can be left by the specimen(s).
|
|
558
|
+
"""
|
|
471
559
|
self.parent().po.vars['do_fading'] = self.do_fading.isChecked()
|
|
472
560
|
self.fading.setVisible(self.parent().po.vars['do_fading'])
|
|
473
561
|
|
|
474
562
|
def fading_changed(self):
|
|
563
|
+
"""
|
|
564
|
+
Save the fading spinbox value to modify how intensity must decrease to detect a pixel left by the specimen(s).
|
|
565
|
+
"""
|
|
475
566
|
self.parent().po.vars['fading'] = self.fading.value()
|
|
476
|
-
# self.save_all_vars_is_clicked()
|
|
477
567
|
|
|
478
568
|
def maximal_growth_factor_changed(self):
|
|
569
|
+
"""
|
|
570
|
+
Save the maximal_growth_factor spinbox value to modulate the maximal growth between two frames.
|
|
571
|
+
"""
|
|
479
572
|
self.parent().po.vars['maximal_growth_factor'] = self.maximal_growth_factor.value()
|
|
480
|
-
# self.save_all_vars_is_clicked()
|
|
481
573
|
|
|
482
574
|
def arena_changed(self):
|
|
483
575
|
"""
|
|
484
|
-
|
|
576
|
+
Resets the loaded arena when its video and processing threads are not running.
|
|
577
|
+
|
|
578
|
+
Notes
|
|
579
|
+
-----
|
|
580
|
+
This function is part of a larger class responsible for managing video and
|
|
581
|
+
arena processing threads. It should be called when all relevant threads are not
|
|
582
|
+
running to ensure the arena's state is properly reset.
|
|
485
583
|
"""
|
|
486
584
|
if not self.thread['VideoReader'].isRunning() and not self.thread['OneArena'].isRunning() and not self.thread['ChangeOneRepResult'].isRunning():
|
|
487
585
|
self.parent().po.motion = None
|
|
@@ -490,31 +588,64 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
490
588
|
self.parent().po.all['arena'] = int(np.round(self.arena.value()))
|
|
491
589
|
|
|
492
590
|
def load_one_arena_is_clicked(self):
|
|
591
|
+
"""
|
|
592
|
+
Load one arena if clicked.
|
|
593
|
+
|
|
594
|
+
Resets the general step, sets `load_quick_full` to 0, and runs the arena in a separate thread.
|
|
595
|
+
"""
|
|
493
596
|
self.reset_general_step()
|
|
494
|
-
# self.save_all_vars_is_clicked()
|
|
495
597
|
self.parent().po.load_quick_full = 0
|
|
496
598
|
self.run_one_arena_thread()
|
|
497
599
|
|
|
498
600
|
def compute_all_options_check(self):
|
|
601
|
+
"""
|
|
602
|
+
Save the compute_all_options checkbox value to process every video segmentation algorithms during the next run.
|
|
603
|
+
"""
|
|
499
604
|
self.parent().po.all['compute_all_options'] = self.compute_all_options_cb.isChecked()
|
|
500
605
|
|
|
501
606
|
def detection_is_clicked(self):
|
|
607
|
+
"""
|
|
608
|
+
Trigger detection when a button is clicked.
|
|
609
|
+
|
|
610
|
+
This method handles the logic when the user clicks the "detection" button.
|
|
611
|
+
It resets certain states, sets a flag for quick full processing,
|
|
612
|
+
and starts a thread to run the detection in one arena.
|
|
613
|
+
|
|
614
|
+
Notes
|
|
615
|
+
-----
|
|
616
|
+
This method is part of a larger state machine for handling user interactions.
|
|
617
|
+
It assumes that the parent object has a `po` attribute with a `load_quick_full`
|
|
618
|
+
flag and a method to run an arena thread.
|
|
619
|
+
"""
|
|
502
620
|
self.reset_general_step()
|
|
503
|
-
# self.save_all_vars_is_clicked()
|
|
504
621
|
self.parent().po.load_quick_full = 1
|
|
505
622
|
self.run_one_arena_thread()
|
|
506
623
|
|
|
507
624
|
def post_processing_is_clicked(self):
|
|
508
|
-
|
|
625
|
+
"""
|
|
626
|
+
Trigger post-processing when a button is clicked.
|
|
627
|
+
|
|
628
|
+
Extended Description
|
|
629
|
+
-------------------
|
|
630
|
+
This function updates the parent object's load_quick_full attribute,
|
|
631
|
+
logs a specific variable value, and runs an arena thread.
|
|
632
|
+
"""
|
|
509
633
|
self.parent().po.load_quick_full = 2
|
|
510
634
|
logging.info(self.parent().po.vars['maximal_growth_factor'])
|
|
511
635
|
self.run_one_arena_thread()
|
|
512
636
|
|
|
513
637
|
def run_one_arena_thread(self):
|
|
514
638
|
"""
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
639
|
+
Run the OneArena thread for processing.
|
|
640
|
+
|
|
641
|
+
Executes the OneArena thread to load video, initialize analysis,
|
|
642
|
+
stop any running instance of the thread, save settings, and connect
|
|
643
|
+
signals for displaying messages, images, and handling completion events.
|
|
644
|
+
|
|
645
|
+
Notes
|
|
646
|
+
-----
|
|
647
|
+
Ensures that the previous arena settings are cleared and connects signals
|
|
648
|
+
to display messages and images during thread execution.
|
|
518
649
|
"""
|
|
519
650
|
if self.thread['OneArena']._isRunning:
|
|
520
651
|
self.thread['OneArena'].stop()
|
|
@@ -522,20 +653,23 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
522
653
|
if self.previous_arena != self.parent().po.all['arena']:
|
|
523
654
|
self.parent().po.motion = None
|
|
524
655
|
self.message.setText("Load the video and initialize analysis, wait...")
|
|
525
|
-
# if not self.parent().po.first_exp_ready_to_run:
|
|
526
|
-
# self.parent().po.use_data_to_run_cellects_quickly = True
|
|
527
656
|
self.thread['OneArena'].start() # OneArenaThreadInThirdWidget
|
|
528
657
|
self.thread['OneArena'].message_from_thread_starting.connect(self.display_message_from_thread)
|
|
529
658
|
self.thread['OneArena'].when_loading_finished.connect(self.when_loading_thread_finished)
|
|
530
659
|
self.thread['OneArena'].when_detection_finished.connect(self.when_detection_finished)
|
|
531
660
|
self.thread['OneArena'].image_from_thread.connect(self.display_image_during_thread)
|
|
532
661
|
|
|
533
|
-
def when_loading_thread_finished(self, save_loaded_video):
|
|
662
|
+
def when_loading_thread_finished(self, save_loaded_video: bool):
|
|
663
|
+
"""
|
|
664
|
+
Ends the loading thread process and handles post-loading actions.
|
|
665
|
+
|
|
666
|
+
Notes
|
|
667
|
+
----------
|
|
668
|
+
This method assumes that the parent object has a `po` attribute with an
|
|
669
|
+
'arena' key and a `load_quick_full` attribute. It also assumes that the
|
|
670
|
+
parent object has a 'thread' dictionary and a message UI component.
|
|
671
|
+
"""
|
|
534
672
|
self.previous_arena = self.parent().po.all['arena']
|
|
535
|
-
# if not self.parent().po.vars['already_greyscale']:
|
|
536
|
-
# self.parent().po.motion.analysis_instance = self.parent().po.motion.visu.copy()
|
|
537
|
-
# else:
|
|
538
|
-
# self.parent().po.motion.analysis_instance = self.parent().po.motion.converted_video.copy()
|
|
539
673
|
if save_loaded_video:
|
|
540
674
|
self.thread['WriteVideo'] = WriteVideoThread(self.parent())
|
|
541
675
|
self.thread['WriteVideo'].start()
|
|
@@ -543,13 +677,32 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
543
677
|
self.message.setText("Loading done, you can watch the video")
|
|
544
678
|
self.read.setVisible(True)
|
|
545
679
|
|
|
546
|
-
def when_detection_finished(self, message):
|
|
547
|
-
|
|
680
|
+
def when_detection_finished(self, message: str):
|
|
681
|
+
"""
|
|
682
|
+
Handles the completion of video detection and updates the UI accordingly.
|
|
683
|
+
|
|
684
|
+
When the video detection is finished, this function waits for the
|
|
685
|
+
VideoReader thread to complete if it's running. It then processes the
|
|
686
|
+
last frame of the video based on the configured visualization and motion
|
|
687
|
+
detection settings. Finally, it updates the UI with the processed image
|
|
688
|
+
and sets appropriate labels' visibility.
|
|
689
|
+
|
|
690
|
+
Parameters
|
|
691
|
+
----------
|
|
692
|
+
message : str
|
|
693
|
+
The message to display upon completion of detection.
|
|
694
|
+
This could be a status update or any relevant information.
|
|
695
|
+
|
|
696
|
+
Notes
|
|
697
|
+
-----
|
|
698
|
+
This function assumes that the parent object has attributes `po` and
|
|
699
|
+
`image_to_display`, and methods like `display_image.update_image`.
|
|
700
|
+
"""
|
|
548
701
|
self.previous_arena = self.parent().po.all['arena']
|
|
549
702
|
if self.thread['VideoReader'].isRunning(): # VideoReaderThreadInThirdWidget
|
|
550
703
|
self.thread['VideoReader'].wait()
|
|
551
704
|
if self.parent().po.load_quick_full > 0:
|
|
552
|
-
image = self.parent().po.motion.
|
|
705
|
+
image = self.parent().po.motion.segmented[-1, ...]
|
|
553
706
|
if self.parent().po.motion.visu is None:
|
|
554
707
|
image = self.parent().po.motion.converted_video[-1, ...] * (1 - image)
|
|
555
708
|
image = np.round(image).astype(np.uint8)
|
|
@@ -559,20 +712,34 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
559
712
|
image = self.parent().po.motion.visu[-1, ...] * (1 - image)
|
|
560
713
|
self.parent().image_to_display = image
|
|
561
714
|
self.display_image.update_image(image)
|
|
562
|
-
|
|
563
715
|
self.message.setText(message)
|
|
564
|
-
|
|
565
716
|
self.select_option_label.setVisible(self.parent().po.vars["color_number"] == 2)
|
|
566
717
|
self.select_option.setVisible(self.parent().po.vars["color_number"] == 2)
|
|
567
718
|
self.read.setVisible(True)
|
|
568
|
-
# self.save_one_result.setVisible(True)
|
|
569
719
|
|
|
570
|
-
def display_image_during_thread(self, dictionary):
|
|
720
|
+
def display_image_during_thread(self, dictionary: dict):
|
|
721
|
+
"""
|
|
722
|
+
Display an image and set a message during a thread operation.
|
|
723
|
+
|
|
724
|
+
Parameters
|
|
725
|
+
----------
|
|
726
|
+
dictionary : dict
|
|
727
|
+
A dictionary containing the 'message' and 'current_image'.
|
|
728
|
+
The message is a string to display.
|
|
729
|
+
The current_image is the image data that will be displayed.
|
|
730
|
+
"""
|
|
571
731
|
self.message.setText(dictionary['message'])
|
|
572
732
|
self.parent().image_to_display = dictionary['current_image']
|
|
573
733
|
self.display_image.update_image(dictionary['current_image'])
|
|
574
734
|
|
|
575
735
|
def save_one_result_is_clicked(self):
|
|
736
|
+
"""
|
|
737
|
+
Finalize one arena analysis and save the result if conditions are met.
|
|
738
|
+
|
|
739
|
+
This function checks various conditions before starting a thread to
|
|
740
|
+
finalize the analysis and save the result. It ensures that certain
|
|
741
|
+
threads are not running before proceeding.
|
|
742
|
+
"""
|
|
576
743
|
if self.parent().po.motion is not None:
|
|
577
744
|
if self.parent().po.load_quick_full == 2:
|
|
578
745
|
if not self.thread['OneArena'].isRunning() and not self.thread['ChangeOneRepResult'].isRunning():
|
|
@@ -588,56 +755,71 @@ class VideoAnalysisWindow(MainTabsType):
|
|
|
588
755
|
self.message.setText("Run Post processing first")
|
|
589
756
|
|
|
590
757
|
def read_is_clicked(self):
|
|
758
|
+
"""
|
|
759
|
+
Read a video corresponding to a numbered arena (numbered using natural sorting) in the image
|
|
760
|
+
|
|
761
|
+
This function checks if the detection has been run and if the video reader or analysis thread is running.
|
|
762
|
+
If both threads are idle, it starts the video reading process. Otherwise, it updates the message accordingly.
|
|
763
|
+
"""
|
|
591
764
|
if self.parent().po.motion is not None:
|
|
592
|
-
if self.parent().po.motion.
|
|
765
|
+
if self.parent().po.motion.segmented is not None:
|
|
593
766
|
if not self.thread['OneArena'].isRunning() and not self.thread['VideoReader'].isRunning():
|
|
594
767
|
self.thread['VideoReader'].start() # VideoReaderThreadInThirdWidget
|
|
595
768
|
self.thread['VideoReader'].message_from_thread.connect(self.display_image_during_thread)
|
|
596
|
-
# if self.parent().po.computed_video_options[self.parent().po.all['video_option']]:
|
|
597
|
-
# self.message.setText("Run detection to visualize analysis")
|
|
598
769
|
else:
|
|
599
770
|
self.message.setText("Wait for the analysis to end")
|
|
600
771
|
else:
|
|
601
772
|
self.message.setText("Run detection first")
|
|
602
773
|
else:
|
|
603
774
|
self.message.setText("Run detection first")
|
|
604
|
-
#
|
|
605
|
-
# def video_display(self, dictionary):
|
|
606
|
-
# self.drawn_image = dictionary['image']
|
|
607
|
-
# self.display_image.update_image(dictionary['image'], self.parent().po.vars['contour_color'])
|
|
608
|
-
# self.message.setText(dictionary['message'])
|
|
609
|
-
# # self.message.setText(f"Reading done, try to change parameters if necessary")
|
|
610
775
|
|
|
611
776
|
def run_all_is_clicked(self):
|
|
777
|
+
"""
|
|
778
|
+
Handle the click event to start the complete analysis.
|
|
779
|
+
|
|
780
|
+
This function checks if any threads are running and starts the
|
|
781
|
+
'RunAll' thread if none of them are active. It also updates
|
|
782
|
+
various attributes and messages related to the analysis process.
|
|
783
|
+
|
|
784
|
+
Notes
|
|
785
|
+
-----
|
|
786
|
+
This function will only start the analysis if no other threads
|
|
787
|
+
are running. It updates several attributes of the parent object.
|
|
788
|
+
"""
|
|
612
789
|
if self.thread['OneArena'].isRunning() or self.thread['ChangeOneRepResult'].isRunning():
|
|
613
790
|
self.message.setText("Wait for the current analysis to end")
|
|
614
791
|
else:
|
|
615
792
|
if self.thread['VideoReader'].isRunning():
|
|
616
793
|
self.thread['VideoReader'].wait()
|
|
617
|
-
# self.save_all_vars_is_clicked()
|
|
618
|
-
# self.save_current_settings()
|
|
619
794
|
if self.parent().firstwindow.thread["RunAll"].isRunning():
|
|
620
795
|
self.message.setText('Analysis has already begun in the first window.')
|
|
621
796
|
else:
|
|
622
797
|
if not self.thread['RunAll'].isRunning():
|
|
623
|
-
# self.save_all_vars_is_clicked()
|
|
624
798
|
self.save_current_settings()
|
|
625
799
|
self.parent().po.motion = None
|
|
626
800
|
self.parent().po.converted_video = None
|
|
627
801
|
self.parent().po.converted_video2 = None
|
|
628
802
|
self.parent().po.visu = None
|
|
629
803
|
self.message.setText("Complete analysis has started, wait...")
|
|
630
|
-
# if not self.parent().po.first_exp_ready_to_run:
|
|
631
|
-
# self.parent().po.use_data_to_run_cellects_quickly = True
|
|
632
804
|
self.thread['RunAll'].start() # RunAllThread
|
|
633
805
|
self.thread['RunAll'].message_from_thread.connect(self.display_message_from_thread)
|
|
634
806
|
self.thread['RunAll'].image_from_thread.connect(self.display_image_during_thread)
|
|
635
|
-
# self.parent().imageanalysiswindow.true_init()
|
|
636
807
|
|
|
637
|
-
def display_message_from_thread(self, text_from_thread):
|
|
808
|
+
def display_message_from_thread(self, text_from_thread: str):
|
|
809
|
+
"""
|
|
810
|
+
Updates the message displayed in the UI with text from a thread.
|
|
811
|
+
|
|
812
|
+
Parameters
|
|
813
|
+
----------
|
|
814
|
+
text_from_thread : str
|
|
815
|
+
The text to be displayed in the UI message.
|
|
816
|
+
"""
|
|
638
817
|
self.message.setText(text_from_thread)
|
|
639
818
|
|
|
640
819
|
def closeEvent(self, event):
|
|
820
|
+
"""
|
|
821
|
+
Handle the close event for a QWidget.
|
|
822
|
+
"""
|
|
641
823
|
event.accept
|
|
642
824
|
|
|
643
825
|
|