bec-widgets 0.53.2__py3-none-any.whl → 0.54.0__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.
- CHANGELOG.md +24 -25
- PKG-INFO +1 -1
- bec_widgets/cli/client.py +13 -13
- bec_widgets/cli/client_utils.py +0 -4
- bec_widgets/cli/generate_cli.py +7 -5
- bec_widgets/cli/server.py +5 -7
- bec_widgets/examples/jupyter_console/jupyter_console_window.py +7 -3
- bec_widgets/examples/motor_movement/motor_control_compilations.py +17 -16
- bec_widgets/widgets/__init__.py +0 -10
- bec_widgets/widgets/figure/figure.py +40 -23
- bec_widgets/widgets/figure/plots/__init__.py +0 -0
- bec_widgets/widgets/figure/plots/image/__init__.py +0 -0
- bec_widgets/widgets/{plots → figure/plots/image}/image.py +6 -416
- bec_widgets/widgets/figure/plots/image/image_item.py +277 -0
- bec_widgets/widgets/figure/plots/image/image_processor.py +152 -0
- bec_widgets/widgets/figure/plots/motor_map/__init__.py +0 -0
- bec_widgets/widgets/{plots → figure/plots/motor_map}/motor_map.py +2 -2
- bec_widgets/widgets/figure/plots/waveform/__init__.py +0 -0
- bec_widgets/widgets/{plots → figure/plots/waveform}/waveform.py +9 -222
- bec_widgets/widgets/figure/plots/waveform/waveform_curve.py +227 -0
- bec_widgets/widgets/motor_control/__init__.py +0 -7
- bec_widgets/widgets/motor_control/motor_control.py +2 -948
- bec_widgets/widgets/motor_control/motor_table/__init__.py +0 -0
- bec_widgets/widgets/motor_control/motor_table/motor_table.py +483 -0
- bec_widgets/widgets/motor_control/movement_absolute/__init__.py +0 -0
- bec_widgets/widgets/motor_control/movement_absolute/movement_absolute.py +157 -0
- bec_widgets/widgets/motor_control/movement_relative/__init__.py +0 -0
- bec_widgets/widgets/motor_control/movement_relative/movement_relative.py +227 -0
- bec_widgets/widgets/motor_control/selection/__init__.py +0 -0
- bec_widgets/widgets/motor_control/selection/selection.py +110 -0
- {bec_widgets-0.53.2.dist-info → bec_widgets-0.54.0.dist-info}/METADATA +1 -1
- {bec_widgets-0.53.2.dist-info → bec_widgets-0.54.0.dist-info}/RECORD +51 -52
- docs/requirements.txt +1 -0
- pyproject.toml +1 -1
- tests/end-2-end/test_bec_dock_rpc_e2e.py +1 -1
- tests/end-2-end/test_bec_figure_rpc_e2e.py +4 -4
- tests/end-2-end/test_rpc_register_e2e.py +1 -1
- tests/unit_tests/test_bec_dock.py +1 -1
- tests/unit_tests/test_bec_figure.py +6 -4
- tests/unit_tests/test_bec_motor_map.py +2 -3
- tests/unit_tests/test_motor_control.py +6 -5
- tests/unit_tests/test_waveform1d.py +13 -1
- bec_widgets/validation/__init__.py +0 -2
- bec_widgets/validation/monitor_config_validator.py +0 -258
- bec_widgets/widgets/monitor/__init__.py +0 -1
- bec_widgets/widgets/monitor/config_dialog.py +0 -574
- bec_widgets/widgets/monitor/config_dialog.ui +0 -210
- bec_widgets/widgets/monitor/example_configs/config_device.yaml +0 -60
- bec_widgets/widgets/monitor/example_configs/config_scans.yaml +0 -92
- bec_widgets/widgets/monitor/monitor.py +0 -845
- bec_widgets/widgets/monitor/tab_template.ui +0 -180
- bec_widgets/widgets/motor_map/__init__.py +0 -1
- bec_widgets/widgets/motor_map/motor_map.py +0 -594
- bec_widgets/widgets/plots/__init__.py +0 -4
- tests/unit_tests/test_bec_monitor.py +0 -220
- tests/unit_tests/test_config_dialog.py +0 -178
- tests/unit_tests/test_motor_map.py +0 -171
- tests/unit_tests/test_validator_errors.py +0 -110
- /bec_widgets/{cli → assets}/bec_widgets_icon.png +0 -0
- /bec_widgets/{examples/jupyter_console → assets}/terminal_icon.png +0 -0
- /bec_widgets/widgets/{plots → figure/plots}/plot_base.py +0 -0
- /bec_widgets/widgets/motor_control/{motor_control_table.ui → motor_table/motor_table.ui} +0 -0
- /bec_widgets/widgets/motor_control/{motor_control_absolute.ui → movement_absolute/movement_absolute.ui} +0 -0
- /bec_widgets/widgets/motor_control/{motor_control_relative.ui → movement_relative/movement_relative.ui} +0 -0
- /bec_widgets/widgets/motor_control/{motor_control_selection.ui → selection/selection.ui} +0 -0
- {bec_widgets-0.53.2.dist-info → bec_widgets-0.54.0.dist-info}/WHEEL +0 -0
- {bec_widgets-0.53.2.dist-info → bec_widgets-0.54.0.dist-info}/licenses/LICENSE +0 -0
@@ -4,50 +4,16 @@ from collections import defaultdict
|
|
4
4
|
from typing import Any, Literal, Optional
|
5
5
|
|
6
6
|
import numpy as np
|
7
|
-
import pyqtgraph as pg
|
8
7
|
from bec_lib.endpoints import MessageEndpoints
|
9
|
-
from pydantic import
|
10
|
-
from qtpy.QtCore import
|
11
|
-
from qtpy.QtCore import Signal as pyqtSignal
|
8
|
+
from pydantic import Field, ValidationError
|
9
|
+
from qtpy.QtCore import QThread
|
12
10
|
from qtpy.QtCore import Slot as pyqtSlot
|
13
11
|
from qtpy.QtWidgets import QWidget
|
14
12
|
|
15
|
-
from bec_widgets.utils import
|
16
|
-
|
17
|
-
from .
|
18
|
-
|
19
|
-
|
20
|
-
class ProcessingConfig(BaseModel):
|
21
|
-
fft: Optional[bool] = Field(False, description="Whether to perform FFT on the monitor data.")
|
22
|
-
log: Optional[bool] = Field(False, description="Whether to perform log on the monitor data.")
|
23
|
-
center_of_mass: Optional[bool] = Field(
|
24
|
-
False, description="Whether to calculate the center of mass of the monitor data."
|
25
|
-
)
|
26
|
-
transpose: Optional[bool] = Field(
|
27
|
-
False, description="Whether to transpose the monitor data before displaying."
|
28
|
-
)
|
29
|
-
rotation: Optional[int] = Field(
|
30
|
-
None, description="The rotation angle of the monitor data before displaying."
|
31
|
-
)
|
32
|
-
|
33
|
-
|
34
|
-
class ImageItemConfig(ConnectionConfig):
|
35
|
-
parent_id: Optional[str] = Field(None, description="The parent plot of the image.")
|
36
|
-
monitor: Optional[str] = Field(None, description="The name of the monitor.")
|
37
|
-
source: Optional[str] = Field(None, description="The source of the curve.")
|
38
|
-
color_map: Optional[str] = Field("magma", description="The color map of the image.")
|
39
|
-
downsample: Optional[bool] = Field(True, description="Whether to downsample the image.")
|
40
|
-
opacity: Optional[float] = Field(1.0, description="The opacity of the image.")
|
41
|
-
vrange: Optional[tuple[int, int]] = Field(
|
42
|
-
None, description="The range of the color bar. If None, the range is automatically set."
|
43
|
-
)
|
44
|
-
color_bar: Optional[Literal["simple", "full"]] = Field(
|
45
|
-
"simple", description="The type of the color bar."
|
46
|
-
)
|
47
|
-
autorange: Optional[bool] = Field(True, description="Whether to autorange the color bar.")
|
48
|
-
processing: ProcessingConfig = Field(
|
49
|
-
default_factory=ProcessingConfig, description="The post processing of the image."
|
50
|
-
)
|
13
|
+
from bec_widgets.utils import EntryValidator
|
14
|
+
from bec_widgets.widgets.figure.plots.image.image_item import BECImageItem, ImageItemConfig
|
15
|
+
from bec_widgets.widgets.figure.plots.image.image_processor import ImageProcessor, ProcessorWorker
|
16
|
+
from bec_widgets.widgets.figure.plots.plot_base import BECPlotBase, SubplotConfig
|
51
17
|
|
52
18
|
|
53
19
|
class ImageConfig(SubplotConfig):
|
@@ -57,251 +23,6 @@ class ImageConfig(SubplotConfig):
|
|
57
23
|
)
|
58
24
|
|
59
25
|
|
60
|
-
class BECImageItem(BECConnector, pg.ImageItem):
|
61
|
-
USER_ACCESS = [
|
62
|
-
"rpc_id",
|
63
|
-
"config_dict",
|
64
|
-
"set",
|
65
|
-
"set_fft",
|
66
|
-
"set_log",
|
67
|
-
"set_rotation",
|
68
|
-
"set_transpose",
|
69
|
-
"set_opacity",
|
70
|
-
"set_autorange",
|
71
|
-
"set_color_map",
|
72
|
-
"set_auto_downsample",
|
73
|
-
"set_monitor",
|
74
|
-
"set_vrange",
|
75
|
-
"get_data",
|
76
|
-
]
|
77
|
-
|
78
|
-
def __init__(
|
79
|
-
self,
|
80
|
-
config: Optional[ImageItemConfig] = None,
|
81
|
-
gui_id: Optional[str] = None,
|
82
|
-
parent_image: Optional[BECImageItem] = None,
|
83
|
-
**kwargs,
|
84
|
-
):
|
85
|
-
if config is None:
|
86
|
-
config = ImageItemConfig(widget_class=self.__class__.__name__)
|
87
|
-
self.config = config
|
88
|
-
else:
|
89
|
-
self.config = config
|
90
|
-
super().__init__(config=config, gui_id=gui_id)
|
91
|
-
pg.ImageItem.__init__(self)
|
92
|
-
|
93
|
-
self.parent_image = parent_image
|
94
|
-
self.colorbar_bar = None
|
95
|
-
|
96
|
-
self._add_color_bar(
|
97
|
-
self.config.color_bar, self.config.vrange
|
98
|
-
) # TODO can also support None to not have any colorbar
|
99
|
-
self.apply_config()
|
100
|
-
if kwargs:
|
101
|
-
self.set(**kwargs)
|
102
|
-
|
103
|
-
def apply_config(self):
|
104
|
-
"""
|
105
|
-
Apply current configuration.
|
106
|
-
"""
|
107
|
-
self.set_color_map(self.config.color_map)
|
108
|
-
self.set_auto_downsample(self.config.downsample)
|
109
|
-
if self.config.vrange is not None:
|
110
|
-
self.set_vrange(vrange=self.config.vrange)
|
111
|
-
|
112
|
-
def set(self, **kwargs):
|
113
|
-
"""
|
114
|
-
Set the properties of the image.
|
115
|
-
|
116
|
-
Args:
|
117
|
-
**kwargs: Keyword arguments for the properties to be set.
|
118
|
-
|
119
|
-
Possible properties:
|
120
|
-
- downsample
|
121
|
-
- color_map
|
122
|
-
- monitor
|
123
|
-
- opacity
|
124
|
-
- vrange
|
125
|
-
- fft
|
126
|
-
- log
|
127
|
-
- rot
|
128
|
-
- transpose
|
129
|
-
"""
|
130
|
-
method_map = {
|
131
|
-
"downsample": self.set_auto_downsample,
|
132
|
-
"color_map": self.set_color_map,
|
133
|
-
"monitor": self.set_monitor,
|
134
|
-
"opacity": self.set_opacity,
|
135
|
-
"vrange": self.set_vrange,
|
136
|
-
"fft": self.set_fft,
|
137
|
-
"log": self.set_log,
|
138
|
-
"rot": self.set_rotation,
|
139
|
-
"transpose": self.set_transpose,
|
140
|
-
}
|
141
|
-
for key, value in kwargs.items():
|
142
|
-
if key in method_map:
|
143
|
-
method_map[key](value)
|
144
|
-
else:
|
145
|
-
print(f"Warning: '{key}' is not a recognized property.")
|
146
|
-
|
147
|
-
def set_fft(self, enable: bool = False):
|
148
|
-
"""
|
149
|
-
Set the FFT of the image.
|
150
|
-
|
151
|
-
Args:
|
152
|
-
enable(bool): Whether to perform FFT on the monitor data.
|
153
|
-
"""
|
154
|
-
self.config.processing.fft = enable
|
155
|
-
|
156
|
-
def set_log(self, enable: bool = False):
|
157
|
-
"""
|
158
|
-
Set the log of the image.
|
159
|
-
|
160
|
-
Args:
|
161
|
-
enable(bool): Whether to perform log on the monitor data.
|
162
|
-
"""
|
163
|
-
self.config.processing.log = enable
|
164
|
-
if enable and self.color_bar and self.config.color_bar == "full":
|
165
|
-
self.color_bar.autoHistogramRange()
|
166
|
-
|
167
|
-
def set_rotation(self, deg_90: int = 0):
|
168
|
-
"""
|
169
|
-
Set the rotation of the image.
|
170
|
-
|
171
|
-
Args:
|
172
|
-
deg_90(int): The rotation angle of the monitor data before displaying.
|
173
|
-
"""
|
174
|
-
self.config.processing.rotation = deg_90
|
175
|
-
|
176
|
-
def set_transpose(self, enable: bool = False):
|
177
|
-
"""
|
178
|
-
Set the transpose of the image.
|
179
|
-
|
180
|
-
Args:
|
181
|
-
enable(bool): Whether to transpose the image.
|
182
|
-
"""
|
183
|
-
self.config.processing.transpose = enable
|
184
|
-
|
185
|
-
def set_opacity(self, opacity: float = 1.0):
|
186
|
-
"""
|
187
|
-
Set the opacity of the image.
|
188
|
-
|
189
|
-
Args:
|
190
|
-
opacity(float): The opacity of the image.
|
191
|
-
"""
|
192
|
-
self.setOpacity(opacity)
|
193
|
-
self.config.opacity = opacity
|
194
|
-
|
195
|
-
def set_autorange(self, autorange: bool = False):
|
196
|
-
"""
|
197
|
-
Set the autorange of the color bar.
|
198
|
-
|
199
|
-
Args:
|
200
|
-
autorange(bool): Whether to autorange the color bar.
|
201
|
-
"""
|
202
|
-
self.config.autorange = autorange
|
203
|
-
if self.color_bar is not None:
|
204
|
-
self.color_bar.autoHistogramRange()
|
205
|
-
|
206
|
-
def set_color_map(self, cmap: str = "magma"):
|
207
|
-
"""
|
208
|
-
Set the color map of the image.
|
209
|
-
|
210
|
-
Args:
|
211
|
-
cmap(str): The color map of the image.
|
212
|
-
"""
|
213
|
-
self.setColorMap(cmap)
|
214
|
-
if self.color_bar is not None:
|
215
|
-
if self.config.color_bar == "simple":
|
216
|
-
self.color_bar.setColorMap(cmap)
|
217
|
-
elif self.config.color_bar == "full":
|
218
|
-
self.color_bar.gradient.loadPreset(cmap)
|
219
|
-
self.config.color_map = cmap
|
220
|
-
|
221
|
-
def set_auto_downsample(self, auto: bool = True):
|
222
|
-
"""
|
223
|
-
Set the auto downsample of the image.
|
224
|
-
|
225
|
-
Args:
|
226
|
-
auto(bool): Whether to downsample the image.
|
227
|
-
"""
|
228
|
-
self.setAutoDownsample(auto)
|
229
|
-
self.config.downsample = auto
|
230
|
-
|
231
|
-
def set_monitor(self, monitor: str):
|
232
|
-
"""
|
233
|
-
Set the monitor of the image.
|
234
|
-
|
235
|
-
Args:
|
236
|
-
monitor(str): The name of the monitor.
|
237
|
-
"""
|
238
|
-
self.config.monitor = monitor
|
239
|
-
|
240
|
-
def set_vrange(self, vmin: float = None, vmax: float = None, vrange: tuple[int, int] = None):
|
241
|
-
"""
|
242
|
-
Set the range of the color bar.
|
243
|
-
|
244
|
-
Args:
|
245
|
-
vmin(float): Minimum value of the color bar.
|
246
|
-
vmax(float): Maximum value of the color bar.
|
247
|
-
"""
|
248
|
-
if vrange is not None:
|
249
|
-
vmin, vmax = vrange
|
250
|
-
self.setLevels([vmin, vmax])
|
251
|
-
self.config.vrange = (vmin, vmax)
|
252
|
-
self.config.autorange = False
|
253
|
-
if self.color_bar is not None:
|
254
|
-
if self.config.color_bar == "simple":
|
255
|
-
self.color_bar.setLevels(low=vmin, high=vmax)
|
256
|
-
elif self.config.color_bar == "full":
|
257
|
-
self.color_bar.setLevels(min=vmin, max=vmax)
|
258
|
-
self.color_bar.setHistogramRange(vmin - 0.1 * vmin, vmax + 0.1 * vmax)
|
259
|
-
|
260
|
-
def get_data(self) -> np.ndarray:
|
261
|
-
"""
|
262
|
-
Get the data of the image.
|
263
|
-
Returns:
|
264
|
-
np.ndarray: The data of the image.
|
265
|
-
"""
|
266
|
-
return self.image
|
267
|
-
|
268
|
-
def _add_color_bar(
|
269
|
-
self, color_bar_style: str = "simple", vrange: Optional[tuple[int, int]] = None
|
270
|
-
):
|
271
|
-
"""
|
272
|
-
Add color bar to the layout.
|
273
|
-
|
274
|
-
Args:
|
275
|
-
style(Literal["simple,full"]): The style of the color bar.
|
276
|
-
vrange(tuple[int,int]): The range of the color bar.
|
277
|
-
"""
|
278
|
-
if color_bar_style == "simple":
|
279
|
-
self.color_bar = pg.ColorBarItem(colorMap=self.config.color_map)
|
280
|
-
if vrange is not None:
|
281
|
-
self.color_bar.setLevels(low=vrange[0], high=vrange[1])
|
282
|
-
self.color_bar.setImageItem(self)
|
283
|
-
self.parent_image.addItem(self.color_bar) # , row=0, col=1)
|
284
|
-
self.config.color_bar = "simple"
|
285
|
-
elif color_bar_style == "full":
|
286
|
-
# Setting histogram
|
287
|
-
self.color_bar = pg.HistogramLUTItem()
|
288
|
-
self.color_bar.setImageItem(self)
|
289
|
-
self.color_bar.gradient.loadPreset(self.config.color_map)
|
290
|
-
if vrange is not None:
|
291
|
-
self.color_bar.setLevels(min=vrange[0], max=vrange[1])
|
292
|
-
self.color_bar.setHistogramRange(
|
293
|
-
vrange[0] - 0.1 * vrange[0], vrange[1] + 0.1 * vrange[1]
|
294
|
-
)
|
295
|
-
|
296
|
-
# Adding histogram to the layout
|
297
|
-
self.parent_image.addItem(self.color_bar) # , row=0, col=1)
|
298
|
-
|
299
|
-
# save settings
|
300
|
-
self.config.color_bar = "full"
|
301
|
-
else:
|
302
|
-
raise ValueError("style should be 'simple' or 'full'")
|
303
|
-
|
304
|
-
|
305
26
|
class BECImageShow(BECPlotBase):
|
306
27
|
USER_ACCESS = [
|
307
28
|
"rpc_id",
|
@@ -837,134 +558,3 @@ class BECImageShow(BECPlotBase):
|
|
837
558
|
image.cleanup()
|
838
559
|
|
839
560
|
super().cleanup()
|
840
|
-
|
841
|
-
|
842
|
-
class ImageProcessor:
|
843
|
-
"""
|
844
|
-
Class for processing the image data.
|
845
|
-
"""
|
846
|
-
|
847
|
-
def __init__(self, config: ProcessingConfig = None):
|
848
|
-
if config is None:
|
849
|
-
config = ProcessingConfig()
|
850
|
-
self.config = config
|
851
|
-
|
852
|
-
def set_config(self, config: ProcessingConfig):
|
853
|
-
"""
|
854
|
-
Set the configuration of the processor.
|
855
|
-
|
856
|
-
Args:
|
857
|
-
config(ProcessingConfig): The configuration of the processor.
|
858
|
-
"""
|
859
|
-
self.config = config
|
860
|
-
|
861
|
-
def FFT(self, data: np.ndarray) -> np.ndarray:
|
862
|
-
"""
|
863
|
-
Perform FFT on the data.
|
864
|
-
|
865
|
-
Args:
|
866
|
-
data(np.ndarray): The data to be processed.
|
867
|
-
|
868
|
-
Returns:
|
869
|
-
np.ndarray: The processed data.
|
870
|
-
"""
|
871
|
-
return np.abs(np.fft.fftshift(np.fft.fft2(data)))
|
872
|
-
|
873
|
-
def rotation(self, data: np.ndarray, rotate_90: int) -> np.ndarray:
|
874
|
-
"""
|
875
|
-
Rotate the data by 90 degrees n times.
|
876
|
-
|
877
|
-
Args:
|
878
|
-
data(np.ndarray): The data to be processed.
|
879
|
-
rotate_90(int): The number of 90 degree rotations.
|
880
|
-
|
881
|
-
Returns:
|
882
|
-
np.ndarray: The processed data.
|
883
|
-
"""
|
884
|
-
return np.rot90(data, k=rotate_90, axes=(0, 1))
|
885
|
-
|
886
|
-
def transpose(self, data: np.ndarray) -> np.ndarray:
|
887
|
-
"""
|
888
|
-
Transpose the data.
|
889
|
-
|
890
|
-
Args:
|
891
|
-
data(np.ndarray): The data to be processed.
|
892
|
-
|
893
|
-
Returns:
|
894
|
-
np.ndarray: The processed data.
|
895
|
-
"""
|
896
|
-
return np.transpose(data)
|
897
|
-
|
898
|
-
def log(self, data: np.ndarray) -> np.ndarray:
|
899
|
-
"""
|
900
|
-
Perform log on the data.
|
901
|
-
|
902
|
-
Args:
|
903
|
-
data(np.ndarray): The data to be processed.
|
904
|
-
|
905
|
-
Returns:
|
906
|
-
np.ndarray: The processed data.
|
907
|
-
"""
|
908
|
-
# TODO this is not final solution -> data should stay as int16
|
909
|
-
data = data.astype(np.float32)
|
910
|
-
offset = 1e-6
|
911
|
-
data_offset = data + offset
|
912
|
-
return np.log10(data_offset)
|
913
|
-
|
914
|
-
# def center_of_mass(self, data: np.ndarray) -> tuple: # TODO check functionality
|
915
|
-
# return np.unravel_index(np.argmax(data), data.shape)
|
916
|
-
|
917
|
-
def process_image(self, data: np.ndarray) -> np.ndarray:
|
918
|
-
"""
|
919
|
-
Process the data according to the configuration.
|
920
|
-
|
921
|
-
Args:
|
922
|
-
data(np.ndarray): The data to be processed.
|
923
|
-
|
924
|
-
Returns:
|
925
|
-
np.ndarray: The processed data.
|
926
|
-
"""
|
927
|
-
if self.config.fft:
|
928
|
-
data = self.FFT(data)
|
929
|
-
if self.config.rotation is not None:
|
930
|
-
data = self.rotation(data, self.config.rotation)
|
931
|
-
if self.config.transpose:
|
932
|
-
data = self.transpose(data)
|
933
|
-
if self.config.log:
|
934
|
-
data = self.log(data)
|
935
|
-
return data
|
936
|
-
|
937
|
-
|
938
|
-
class ProcessorWorker(QObject):
|
939
|
-
"""
|
940
|
-
Worker for processing the image data.
|
941
|
-
"""
|
942
|
-
|
943
|
-
processed = pyqtSignal(str, np.ndarray)
|
944
|
-
stopRequested = pyqtSignal()
|
945
|
-
finished = pyqtSignal()
|
946
|
-
|
947
|
-
def __init__(self, processor):
|
948
|
-
super().__init__()
|
949
|
-
self.processor = processor
|
950
|
-
self._isRunning = False
|
951
|
-
self.stopRequested.connect(self.stop)
|
952
|
-
|
953
|
-
@pyqtSlot(str, np.ndarray)
|
954
|
-
def process_image(self, device: str, image: np.ndarray):
|
955
|
-
"""
|
956
|
-
Process the image data.
|
957
|
-
|
958
|
-
Args:
|
959
|
-
device(str): The name of the device.
|
960
|
-
image(np.ndarray): The image data.
|
961
|
-
"""
|
962
|
-
self._isRunning = True
|
963
|
-
processed_image = self.processor.process_image(image)
|
964
|
-
self._isRunning = False
|
965
|
-
if not self._isRunning:
|
966
|
-
self.processed.emit(device, processed_image)
|
967
|
-
self.finished.emit()
|
968
|
-
|
969
|
-
def stop(self):
|
970
|
-
self._isRunning = False
|