microeye 2.3.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. microEye/__init__.py +47 -0
  2. microEye/_version.py +2 -0
  3. microEye/analysis/__init__.py +1 -0
  4. microEye/analysis/checklist_dialog.py +143 -0
  5. microEye/analysis/cmosMaps.py +228 -0
  6. microEye/analysis/filters/__init__.py +9 -0
  7. microEye/analysis/filters/base.py +21 -0
  8. microEye/analysis/filters/spatial.py +338 -0
  9. microEye/analysis/filters/temporal.py +76 -0
  10. microEye/analysis/fitting/__init__.py +0 -0
  11. microEye/analysis/fitting/fit.py +680 -0
  12. microEye/analysis/fitting/nena.py +375 -0
  13. microEye/analysis/fitting/phasor_fit.py +90 -0
  14. microEye/analysis/fitting/processing.py +317 -0
  15. microEye/analysis/fitting/psf/__init__.py +6 -0
  16. microEye/analysis/fitting/psf/extract.py +1129 -0
  17. microEye/analysis/fitting/psf/rubost_mean.py +150 -0
  18. microEye/analysis/fitting/psf/spline.py +167 -0
  19. microEye/analysis/fitting/psf/stats/__init__.py +12 -0
  20. microEye/analysis/fitting/psf/stats/core.py +295 -0
  21. microEye/analysis/fitting/psf/stats/curve_fit.py +708 -0
  22. microEye/analysis/fitting/psf/stats/io.py +104 -0
  23. microEye/analysis/fitting/psf/stats/slope_fit.py +171 -0
  24. microEye/analysis/fitting/psf/temp.py +147 -0
  25. microEye/analysis/fitting/psf/test.py +47 -0
  26. microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUfunctions.py +657 -0
  27. microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUmleFit_LM.py +1336 -0
  28. microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUsplineLib.py +270 -0
  29. microEye/analysis/fitting/pyfit3Dcspline/CPU/__init__.py +1 -0
  30. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUfunctions.py +609 -0
  31. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUmleFit_LM_EMCCD.py +1396 -0
  32. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUmleFit_LM_sCMOS.py +1426 -0
  33. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUsplineLib.py +231 -0
  34. microEye/analysis/fitting/pyfit3Dcspline/GPU/__init__.py +2 -0
  35. microEye/analysis/fitting/pyfit3Dcspline/__init__.py +10 -0
  36. microEye/analysis/fitting/pyfit3Dcspline/constants.py +27 -0
  37. microEye/analysis/fitting/pyfit3Dcspline/mainfunctions.py +903 -0
  38. microEye/analysis/fitting/results.py +917 -0
  39. microEye/analysis/fitting/results_stats.py +251 -0
  40. microEye/analysis/fitting/tardis.py +209 -0
  41. microEye/analysis/multi_viewer.py +568 -0
  42. microEye/analysis/processing/__init__.py +1 -0
  43. microEye/analysis/processing/frc.py +120 -0
  44. microEye/analysis/rendering/__init__.py +3 -0
  45. microEye/analysis/rendering/base.py +452 -0
  46. microEye/analysis/rendering/cloud.py +215 -0
  47. microEye/analysis/rendering/core.py +47 -0
  48. microEye/analysis/rendering/volumetric.py +198 -0
  49. microEye/analysis/tools/__init__.py +0 -0
  50. microEye/analysis/tools/kymograms.py +1079 -0
  51. microEye/analysis/tools/roi_selectors.py +556 -0
  52. microEye/analysis/utils/__init__.py +3 -0
  53. microEye/analysis/utils/coordinates.py +18 -0
  54. microEye/analysis/utils/images.py +68 -0
  55. microEye/analysis/utils/windows.py +19 -0
  56. microEye/analysis/viewer/__init__.py +3 -0
  57. microEye/analysis/viewer/image_options_widget.py +615 -0
  58. microEye/analysis/viewer/images.py +1225 -0
  59. microEye/analysis/viewer/layers_widget.py +415 -0
  60. microEye/analysis/viewer/localizations.py +1304 -0
  61. microEye/analysis/viewer/psf.py +1003 -0
  62. microEye/analysis/viewer/volume.py +456 -0
  63. microEye/hardware/__init__.py +3 -0
  64. microEye/hardware/cams/__init__.py +29 -0
  65. microEye/hardware/cams/camera_calibration.py +99 -0
  66. microEye/hardware/cams/camera_list.py +528 -0
  67. microEye/hardware/cams/camera_options.py +694 -0
  68. microEye/hardware/cams/camera_panel.py +941 -0
  69. microEye/hardware/cams/dummy/__init__.py +1 -0
  70. microEye/hardware/cams/dummy/dummy_panel.py +759 -0
  71. microEye/hardware/cams/jobs.py +497 -0
  72. microEye/hardware/cams/line_profiler.py +99 -0
  73. microEye/hardware/cams/linescan/IR_Cam.py +474 -0
  74. microEye/hardware/cams/linescan/__init__.py +1 -0
  75. microEye/hardware/cams/micam.py +524 -0
  76. microEye/hardware/cams/pco/__init__.py +58 -0
  77. microEye/hardware/cams/pco/enums.py +382 -0
  78. microEye/hardware/cams/pco/pco_cam.py +761 -0
  79. microEye/hardware/cams/pco/pco_panel.py +477 -0
  80. microEye/hardware/cams/shortcuts.py +312 -0
  81. microEye/hardware/cams/thorlabs/__init__.py +1 -0
  82. microEye/hardware/cams/thorlabs/thorlabs.py +1508 -0
  83. microEye/hardware/cams/thorlabs/thorlabs_panel.py +850 -0
  84. microEye/hardware/cams/ueye/__init__.py +1 -0
  85. microEye/hardware/cams/ueye/ueye_camera.py +1023 -0
  86. microEye/hardware/cams/ueye/ueye_panel.py +861 -0
  87. microEye/hardware/cams/vimba/__init__.py +1 -0
  88. microEye/hardware/cams/vimba/vimba_cam.py +1000 -0
  89. microEye/hardware/cams/vimba/vimba_panel.py +813 -0
  90. microEye/hardware/device.py +60 -0
  91. microEye/hardware/lasers/__init__.py +13 -0
  92. microEye/hardware/lasers/io_matchbox.py +791 -0
  93. microEye/hardware/lasers/io_params.py +85 -0
  94. microEye/hardware/lasers/io_single_laser.py +742 -0
  95. microEye/hardware/lasers/laser_relay.py +594 -0
  96. microEye/hardware/mieye/__init__.py +1 -0
  97. microEye/hardware/mieye/acquisition_manager.py +467 -0
  98. microEye/hardware/mieye/devices_manager.py +533 -0
  99. microEye/hardware/mieye/miEye.py +659 -0
  100. microEye/hardware/misc/__init__.py +0 -0
  101. microEye/hardware/misc/acquisition_view.py +71 -0
  102. microEye/hardware/misc/reglo.py +761 -0
  103. microEye/hardware/misc/temp.py +188 -0
  104. microEye/hardware/port_config.py +59 -0
  105. microEye/hardware/protocols/__init__.py +2 -0
  106. microEye/hardware/protocols/actions.py +402 -0
  107. microEye/hardware/protocols/actions_items.py +703 -0
  108. microEye/hardware/protocols/designer.py +244 -0
  109. microEye/hardware/protocols/scene_manager.py +191 -0
  110. microEye/hardware/protocols/serialization.py +97 -0
  111. microEye/hardware/pycromanager/__init__.py +16 -0
  112. microEye/hardware/pycromanager/core.py +1433 -0
  113. microEye/hardware/pycromanager/devices.py +461 -0
  114. microEye/hardware/pycromanager/enums.py +107 -0
  115. microEye/hardware/pycromanager/headless.py +153 -0
  116. microEye/hardware/pycromanager/utils.py +34 -0
  117. microEye/hardware/pycromanager/widgets/__init__.py +5 -0
  118. microEye/hardware/pycromanager/widgets/bridges.py +407 -0
  119. microEye/hardware/pycromanager/widgets/headless_manager.py +258 -0
  120. microEye/hardware/pycromanager/widgets/headless_options.py +224 -0
  121. microEye/hardware/pycromanager/widgets/pycro_panel.py +455 -0
  122. microEye/hardware/stages/__init__.py +18 -0
  123. microEye/hardware/stages/elliptec/__init__.py +5 -0
  124. microEye/hardware/stages/elliptec/baseDevice.py +314 -0
  125. microEye/hardware/stages/elliptec/device.py +384 -0
  126. microEye/hardware/stages/elliptec/deviceID.py +212 -0
  127. microEye/hardware/stages/elliptec/devicePort.py +379 -0
  128. microEye/hardware/stages/elliptec/deviceStatus.py +65 -0
  129. microEye/hardware/stages/elliptec/devicesView.py +706 -0
  130. microEye/hardware/stages/elliptec/ellDevices.py +134 -0
  131. microEye/hardware/stages/elliptec/messageUpdater.py +34 -0
  132. microEye/hardware/stages/elliptec/motorInfo.py +153 -0
  133. microEye/hardware/stages/elliptec/stage.py +62 -0
  134. microEye/hardware/stages/elliptec/test.py +139 -0
  135. microEye/hardware/stages/kinesis/__init__.py +1 -0
  136. microEye/hardware/stages/kinesis/kdc101/__init__.py +1 -0
  137. microEye/hardware/stages/kinesis/kdc101/enums.py +1002 -0
  138. microEye/hardware/stages/kinesis/kdc101/factory.py +171 -0
  139. microEye/hardware/stages/kinesis/kdc101/kdc101.py +718 -0
  140. microEye/hardware/stages/kinesis/kinesis.py +776 -0
  141. microEye/hardware/stages/piezo_concept.py +607 -0
  142. microEye/hardware/stages/stabilizer.py +785 -0
  143. microEye/hardware/stages/stage.py +89 -0
  144. microEye/hardware/widgets/__init__.py +10 -0
  145. microEye/hardware/widgets/controller.py +246 -0
  146. microEye/hardware/widgets/devices.py +133 -0
  147. microEye/hardware/widgets/focusWidget.py +264 -0
  148. microEye/hardware/widgets/qlist_slider.py +113 -0
  149. microEye/hardware/widgets/scan_acquisition.py +424 -0
  150. microEye/icons/1024.png +0 -0
  151. microEye/icons/128.png +0 -0
  152. microEye/icons/16.png +0 -0
  153. microEye/icons/24.png +0 -0
  154. microEye/icons/256.png +0 -0
  155. microEye/icons/32.png +0 -0
  156. microEye/icons/48.png +0 -0
  157. microEye/icons/512.png +0 -0
  158. microEye/icons/64.png +0 -0
  159. microEye/icons/__init__.py +0 -0
  160. microEye/icons/close.svg +88 -0
  161. microEye/icons/mieye.png +0 -0
  162. microEye/icons/min.svg +83 -0
  163. microEye/icons/viewer.png +0 -0
  164. microEye/launcher.py +42 -0
  165. microEye/qt.py +181 -0
  166. microEye/utils/__init__.py +2 -0
  167. microEye/utils/enum_encoder.py +10 -0
  168. microEye/utils/expandable_groupbox.py +93 -0
  169. microEye/utils/gui_helper.py +457 -0
  170. microEye/utils/hid/__init__.py +8 -0
  171. microEye/utils/hid/controller.py +153 -0
  172. microEye/utils/hid/device.py +63 -0
  173. microEye/utils/hid/enums.py +140 -0
  174. microEye/utils/hid/utils.py +58 -0
  175. microEye/utils/labelled_slider.py +134 -0
  176. microEye/utils/metadata.py +599 -0
  177. microEye/utils/metadata_tree.py +718 -0
  178. microEye/utils/micro_launcher.py +245 -0
  179. microEye/utils/parameter_tree.py +325 -0
  180. microEye/utils/pyscripting.py +444 -0
  181. microEye/utils/retry_exec.py +35 -0
  182. microEye/utils/start_gui.py +112 -0
  183. microEye/utils/thread_worker.py +115 -0
  184. microEye/utils/uImage.py +1512 -0
  185. microeye-2.3.2.dist-info/METADATA +401 -0
  186. microeye-2.3.2.dist-info/RECORD +190 -0
  187. microeye-2.3.2.dist-info/WHEEL +5 -0
  188. microeye-2.3.2.dist-info/entry_points.txt +2 -0
  189. microeye-2.3.2.dist-info/licenses/LICENSE +674 -0
  190. microeye-2.3.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,467 @@
1
+ import os
2
+ import threading
3
+ import traceback
4
+
5
+ import cv2
6
+ import numpy as np
7
+ import pyqtgraph as pg
8
+ import tabulate
9
+ import tifffile as tf
10
+
11
+ from microEye.hardware.cams import *
12
+ from microEye.hardware.mieye.devices_manager import DeviceManager
13
+ from microEye.hardware.protocols import WeakObjects
14
+ from microEye.hardware.stages import FocusStabilizer, KinesisView
15
+ from microEye.hardware.widgets import (
16
+ ScanAcquisitionWidget,
17
+ TiledImageSelector,
18
+ TileImage,
19
+ )
20
+ from microEye.qt import (
21
+ QtCore,
22
+ Signal,
23
+ )
24
+ from microEye.utils.thread_worker import QThreadWorker
25
+ from microEye.utils.uImage import uImage
26
+
27
+
28
+ class AcquisitionManager(QtCore.QObject):
29
+ acquisitionStarted = Signal()
30
+ acquisitionFinished = Signal(object)
31
+
32
+ def __init__(self):
33
+ super().__init__()
34
+
35
+ self.acquisitionWidget = ScanAcquisitionWidget()
36
+ WeakObjects.addObject(self.acquisitionWidget)
37
+
38
+ self._init_acquisition_signals()
39
+
40
+ self.lastTile = None
41
+ self.scan_worker = None
42
+ self._stop_scan = False
43
+ self._scanning = False
44
+
45
+ def _init_acquisition_signals(self):
46
+ self.acquisitionWidget.startAcquisitionXY.connect(self.start_scan_acquisitionXY)
47
+ self.acquisitionWidget.startAcquisitionZ.connect(self.start_scan_acquisitionZ)
48
+ self.acquisitionWidget.startCalibrationZ.connect(self.start_calibration_Z)
49
+ self.acquisitionWidget.stopAcquisitionXY.connect(self.stop_scan_acquisition)
50
+ self.acquisitionWidget.stopAcquisitionZ.connect(self.stop_scan_acquisition)
51
+ self.acquisitionWidget.openLastTileXY.connect(self.show_last_tile)
52
+ self.acquisitionWidget.directoryChanged.connect(self.update_directories)
53
+ self.acquisitionWidget.moveZ.connect(DeviceManager.instance().moveStage)
54
+
55
+ def result_scan_acquisition(self, data):
56
+ self._scanning = False
57
+ self.acquisitionWidget.setActionsStatus(True)
58
+
59
+ if data:
60
+ self.lastTile = TiledImageSelector(data)
61
+ self._connect_tile_position_signal(self.lastTile)
62
+ self.lastTile.show()
63
+
64
+ def _connect_tile_position_signal(self, tile: TiledImageSelector):
65
+ tile.positionSelected.connect(
66
+ lambda x, y: DeviceManager.instance().stage_xy.move_absolute(x, y)
67
+ )
68
+
69
+ def result_z_calibration(self, data):
70
+ self._scanning = False
71
+ self.acquisitionWidget.setActionsStatus(True)
72
+
73
+ if data is not None:
74
+ coeff = np.polyfit(data[:, 0], data[:, 1], 1)
75
+ FocusStabilizer.instance().setPixelCalCoeff(coeff[0])
76
+ plot_z_cal(data, coeff)
77
+
78
+ def result_scan_export(self, data: list[TileImage]):
79
+ self._scanning = False
80
+ self.acquisitionWidget.setActionsStatus(True)
81
+
82
+ if data:
83
+ self._export_tile_images(data)
84
+
85
+ def _export_tile_images(self, data: list[TileImage]):
86
+ directory = self.acquisitionWidget._directory
87
+ if len(directory) > 0:
88
+ index = self._get_next_index(directory)
89
+ path = os.path.join(directory, f'{index:03d}_XY/')
90
+ os.makedirs(path, exist_ok=True)
91
+
92
+ for idx, tile_img in enumerate(data):
93
+ filename = (
94
+ f'{idx:03d}_image_y{tile_img.index[0]:02d}'
95
+ + f'_x{tile_img.index[1]:02d}.tif'
96
+ )
97
+ tf.imwrite(
98
+ os.path.join(path, filename),
99
+ tile_img.uImage.image,
100
+ photometric='minisblack',
101
+ )
102
+
103
+ def _get_next_index(self, directory):
104
+ index = 0
105
+ while os.path.exists(os.path.join(directory, f'{index:03d}_XY/')):
106
+ index += 1
107
+ return index
108
+
109
+ def start_scan_acquisitionXY(self, params):
110
+ if not self._scanning:
111
+ self._stop_scan = False
112
+ self._scanning = True
113
+
114
+ self.scan_worker = QThreadWorker(
115
+ scanAcquisition,
116
+ [params[0], params[1]],
117
+ [params[2], params[3]],
118
+ params[4],
119
+ params[5],
120
+ )
121
+ self.scan_worker.signals.result.connect(self.result_scan_acquisition)
122
+ # Execute
123
+ QtCore.QThreadPool.globalInstance().start(self.scan_worker)
124
+
125
+ self.acquisitionWidget.setActionsStatus(False)
126
+
127
+ def start_scan_acquisitionZ(self, params):
128
+ if not self._scanning:
129
+ self._stop_scan = False
130
+ self._scanning = True
131
+
132
+ self.scan_worker = QThreadWorker(
133
+ z_stack_acquisition,
134
+ self,
135
+ params[0],
136
+ params[1],
137
+ params[2],
138
+ params[3],
139
+ params[4],
140
+ )
141
+ self.scan_worker.signals.result.connect(self.result_scan_acquisition)
142
+ # Execute
143
+ QtCore.QThreadPool.globalInstance().start(self.scan_worker)
144
+
145
+ self.acquisitionWidget.setActionsStatus(False)
146
+
147
+ def start_calibration_Z(self, params):
148
+ if not self._scanning:
149
+ self._stop_scan = False
150
+ self._scanning = True
151
+
152
+ self.scan_worker = QThreadWorker(
153
+ z_calibration,
154
+ self,
155
+ params[0],
156
+ params[1],
157
+ params[2],
158
+ params[3],
159
+ params[4],
160
+ )
161
+ self.scan_worker.signals.result.connect(self.result_z_calibration)
162
+ # Execute
163
+ QtCore.QThreadPool.globalInstance().start(self.scan_worker)
164
+
165
+ self.acquisitionWidget.setActionsStatus(False)
166
+
167
+ def stop_scan_acquisition(self):
168
+ self._stop_scan = True
169
+ if self.scan_worker:
170
+ self.scan_worker.stop()
171
+
172
+ def update_directories(self, value: str):
173
+ for _, cam_list in CameraList.CAMERAS.items():
174
+ for cam in cam_list:
175
+ panel: Camera_Panel = cam['Panel']
176
+ panel._directory = value
177
+ panel.camera_options.set_param_value(CamParams.SAVE_DIRECTORY, value)
178
+
179
+ def show_last_tile(self):
180
+ if self.lastTile is not None:
181
+ self.lastTile.show()
182
+
183
+
184
+ def scanAcquisition(steps, step_size, delay, average=1, **kwargs):
185
+ '''Scan Acquisition (works with Allied Vision Cams only)
186
+
187
+ Parameters
188
+ ----------
189
+ steps : (int, int)
190
+ number of grid steps (x ,y)
191
+ step_size : (float, float)
192
+ step size in um (x ,y)
193
+ delay : float
194
+ delay in ms after moving before acquiring images
195
+ average : int
196
+ number of frames to average, default 1 (no averaging)
197
+ **kwargs : dict
198
+ additional arguments
199
+ - event : `threading.Event`
200
+ event to stop the acquisition
201
+
202
+ Returns
203
+ -------
204
+ list[TileImage]
205
+ result data list of TileImages
206
+ '''
207
+ try:
208
+ event: threading.Event = kwargs.get('event')
209
+ if event and event.is_set():
210
+ return
211
+
212
+ device_manager = DeviceManager.instance()
213
+
214
+ data = []
215
+ vimba_cams = [cam for cam in CameraList.CAMERAS['Vimba'] if not cam['IR']]
216
+ if device_manager.stage_xy.isOpen() and len(vimba_cams) > 0:
217
+ cam: vimba_cam = vimba_cams[0]['Camera']
218
+ for x in range(steps[0]):
219
+ device_manager.stage_xy.move_relative(
220
+ round(step_size[0] / 1000, 4), 0, False
221
+ )
222
+ for y in range(steps[1]):
223
+ if event and event.is_set():
224
+ return
225
+
226
+ if y > 0:
227
+ device_manager.stage_xy.move_relative(
228
+ 0, ((-1) ** x) * round(step_size[1] / 1000, 4), False
229
+ )
230
+ frame = None
231
+ with cam.cam:
232
+ QtCore.QThread.msleep(delay)
233
+ if average > 1:
234
+ frames_avg = []
235
+ for _n in range(average):
236
+ frames_avg.append(
237
+ cam.cam.get_frame().as_numpy_ndarray()[..., 0]
238
+ )
239
+ frame = uImage(
240
+ np.array(frames_avg).mean(axis=0, dtype=np.uint16)
241
+ )
242
+ else:
243
+ frame = uImage(
244
+ cam.cam.get_frame().as_numpy_ndarray()[..., 0]
245
+ )
246
+ frame.equalizeLUT(None, True)
247
+ frame._view = cv2.resize(
248
+ frame._view,
249
+ (0, 0),
250
+ fx=0.5,
251
+ fy=0.5,
252
+ interpolation=cv2.INTER_NEAREST,
253
+ )
254
+ Y = (x % 2) * (steps[1] - 1) + ((-1) ** x) * y
255
+ data.append(
256
+ TileImage(frame, [Y, x], device_manager.stage_xy.position)
257
+ )
258
+ cv2.imshow(cam.name, frame._view)
259
+ cv2.waitKey(1)
260
+
261
+ # device_manager.stage_xy.update()
262
+ else:
263
+ return
264
+ except Exception:
265
+ traceback.print_exc()
266
+ finally:
267
+ try:
268
+ cv2.destroyAllWindows()
269
+ except Exception:
270
+ traceback.print_exc()
271
+
272
+ return data
273
+
274
+
275
+ def z_stack_acquisition(
276
+ acquisition_manager: AcquisitionManager,
277
+ n,
278
+ step_size,
279
+ delay=100,
280
+ nFrames=1,
281
+ reverse=False,
282
+ **kwargs,
283
+ ):
284
+ '''Z-Stack Acquisition (works with Allied Vision Cams only)
285
+
286
+ Parameters
287
+ ----------
288
+ acq_manager : AcquisitionManager
289
+ acquisition manager instance
290
+ n : int
291
+ number of z-stacks
292
+ step_size : int
293
+ step size in nm along z-axis
294
+ delay : float
295
+ delay in ms after moving before acquiring images
296
+ nFrames : int
297
+ number of frames for each stack
298
+ reverse : bool
299
+ reverse the direction of the movement
300
+ **kwargs : dict
301
+ additional arguments
302
+ - event : `threading.Event`
303
+ event to stop the acquisition
304
+ '''
305
+ try:
306
+ event: threading.Event = kwargs.get('event')
307
+ if event and event.is_set():
308
+ return
309
+
310
+ device_manager = DeviceManager.instance()
311
+
312
+ data = []
313
+ peak = None
314
+ vimba_cams = [cam for cam in CameraList.CAMERAS['Vimba'] if not cam['IR']]
315
+ if device_manager.stage.isOpen() and len(vimba_cams) > 0 and nFrames > 0:
316
+ cam: miCamera = vimba_cams[0]['Camera']
317
+ cam_pan: Camera_Panel = vimba_cams[0]['Panel']
318
+ if cam.acquisition:
319
+ return
320
+
321
+ cam_pan.camera_options.set_param_value(CamParams.FRAMES, nFrames)
322
+ cam_pan.camera_options.set_param_value(CamParams.SAVE_DATA, True)
323
+
324
+ peak = FocusStabilizer.instance().getPeakPosition()
325
+ for x in range(n):
326
+ if x > 0:
327
+ if event and event.is_set():
328
+ return
329
+
330
+ if (
331
+ FocusStabilizer.instance().isFocusStabilized()
332
+ and FocusStabilizer.instance().useCal()
333
+ ):
334
+ value = FocusStabilizer.instance().pixelCalCoeff() * step_size
335
+ if reverse:
336
+ value *= -1
337
+ FocusStabilizer.instance().setPeakPosition(value, True)
338
+ QtCore.QThread.msleep(delay)
339
+ else:
340
+ if FocusStabilizer.instance().isFocusStabilized():
341
+ FocusStabilizer.instance().toggleFocusStabilization(False)
342
+ acquisition_manager.acquisitionWidget.moveZ.emit(
343
+ reverse, step_size
344
+ )
345
+ QtCore.QThread.msleep(delay)
346
+ FocusStabilizer.instance().toggleFocusStabilization(True)
347
+ frame = None
348
+ prefix = f'Z_{x:04d}_'
349
+
350
+ cam_event = threading.Event()
351
+
352
+ cam_pan.asyncFreerun.emit(prefix, cam_event)
353
+
354
+ cam_event.wait()
355
+ QtCore.QThread.msleep(100)
356
+ else:
357
+ print('Z-scan failed!')
358
+ info = [
359
+ {
360
+ 'Z-Stage Open': device_manager.stage.isOpen(),
361
+ 'Camera Available': len(vimba_cams) > 0,
362
+ 'Frames > 0': nFrames > 0,
363
+ }
364
+ ]
365
+ print(tabulate.tabulate(info, headers='keys', tablefmt='rounded_grid'))
366
+ except Exception:
367
+ traceback.print_exc()
368
+ finally:
369
+ if peak:
370
+ FocusStabilizer.instance().setPeakPosition(peak)
371
+ return
372
+
373
+
374
+ def z_calibration(
375
+ acquisition_manager: AcquisitionManager,
376
+ n,
377
+ step_size,
378
+ delay=100,
379
+ nFrames=50,
380
+ reverse=False,
381
+ **kwargs,
382
+ ):
383
+ '''Z-Stack Acquisition (works with Allied Vision Cams only)
384
+
385
+ Parameters
386
+ ----------
387
+ acq_manager : AcquisitionManager
388
+ acquisition manager instance
389
+ n : int
390
+ number of z-stacks
391
+ step_size : int
392
+ step size in nm along z-axis
393
+ delay : float
394
+ delay in ms per measurement
395
+ nFrames : int
396
+ number of frames used for each measurement
397
+ reverse : bool
398
+ reverse the direction of the movement
399
+ **kwargs : dict
400
+ additional arguments
401
+ - event : `threading.Event`
402
+ event to stop the acquisition
403
+ '''
404
+ positions = np.zeros((n, 2))
405
+ try:
406
+ event: threading.Event = kwargs.get('event')
407
+ if event and event.is_set():
408
+ return
409
+
410
+ device_manager = DeviceManager.instance()
411
+
412
+ data = []
413
+ if device_manager.stage.isOpen():
414
+ if FocusStabilizer.instance().isFocusStabilized():
415
+ FocusStabilizer.instance().toggleFocusStabilization(False)
416
+ for x in range(n):
417
+ if event and event.is_set():
418
+ return
419
+
420
+ if x > 0:
421
+ acquisition_manager.acquisitionWidget.moveZ.emit(reverse, step_size)
422
+ QtCore.QThread.msleep(delay * nFrames)
423
+ positions[x, 0] = x * step_size
424
+ positions[x, 1] = np.mean(
425
+ FocusStabilizer.instance().peak_positions[-nFrames:]
426
+ )
427
+ except Exception:
428
+ traceback.print_exc()
429
+ positions = None
430
+ return positions
431
+
432
+
433
+ def plot_z_cal(data, coeff):
434
+ model = np.poly1d(coeff)
435
+
436
+ x = np.linspace(data[0, 0], data[-1, 0], 1001)
437
+
438
+ # plot results
439
+ plt = pg.plot()
440
+
441
+ plt.showGrid(x=True, y=True)
442
+ plt.addLegend()
443
+
444
+ # set properties of the label for y axis
445
+ plt.setLabel('left', 'Central Pixel', units='')
446
+
447
+ # set properties of the label for x axis
448
+ plt.setLabel('bottom', 'Z [nm]', units='')
449
+
450
+ plt.setWindowTitle(f'Slope: {coeff[0]} | Intercept {coeff[1]}')
451
+
452
+ # setting horizontal range
453
+ plt.setXRange(data[0, 0], data[-1, 0])
454
+
455
+ # setting vertical range
456
+ plt.setYRange(data[0, 1], data[-1, 1])
457
+
458
+ line1 = plt.plot(
459
+ data[:, 0],
460
+ data[:, 1],
461
+ pen='g',
462
+ symbol='x',
463
+ symbolPen='g',
464
+ symbolBrush=0.2,
465
+ name='Data',
466
+ )
467
+ line2 = plt.plot(x, model(x), pen='b', name='Fit')