PYME-extra 1.0.4.post0__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 (101) hide show
  1. PYMEcs/Acquire/Actions/__init__.py +0 -0
  2. PYMEcs/Acquire/Actions/custom.py +167 -0
  3. PYMEcs/Acquire/Hardware/LPthreadedSimple.py +248 -0
  4. PYMEcs/Acquire/Hardware/LPthreadedSimpleSim.py +246 -0
  5. PYMEcs/Acquire/Hardware/NikonTiFlaskServer.py +45 -0
  6. PYMEcs/Acquire/Hardware/NikonTiFlaskServerT.py +59 -0
  7. PYMEcs/Acquire/Hardware/NikonTiRESTClient.py +73 -0
  8. PYMEcs/Acquire/Hardware/NikonTiSim.py +35 -0
  9. PYMEcs/Acquire/Hardware/__init__.py +0 -0
  10. PYMEcs/Acquire/Hardware/driftTrackGUI.py +329 -0
  11. PYMEcs/Acquire/Hardware/driftTrackGUI_n.py +472 -0
  12. PYMEcs/Acquire/Hardware/driftTracking.py +424 -0
  13. PYMEcs/Acquire/Hardware/driftTracking_n.py +433 -0
  14. PYMEcs/Acquire/Hardware/fakeCamX.py +15 -0
  15. PYMEcs/Acquire/Hardware/offsetPiezoRESTCorrelLog.py +38 -0
  16. PYMEcs/Acquire/__init__.py +0 -0
  17. PYMEcs/Analysis/MBMcollection.py +552 -0
  18. PYMEcs/Analysis/MINFLUX.py +280 -0
  19. PYMEcs/Analysis/MapUtils.py +77 -0
  20. PYMEcs/Analysis/NPC.py +1176 -0
  21. PYMEcs/Analysis/Paraflux.py +218 -0
  22. PYMEcs/Analysis/Simpler.py +81 -0
  23. PYMEcs/Analysis/Sofi.py +140 -0
  24. PYMEcs/Analysis/__init__.py +0 -0
  25. PYMEcs/Analysis/decSofi.py +211 -0
  26. PYMEcs/Analysis/eventProperties.py +50 -0
  27. PYMEcs/Analysis/fitDarkTimes.py +569 -0
  28. PYMEcs/Analysis/objectVolumes.py +20 -0
  29. PYMEcs/Analysis/offlineTracker.py +130 -0
  30. PYMEcs/Analysis/stackTracker.py +180 -0
  31. PYMEcs/Analysis/timeSeries.py +63 -0
  32. PYMEcs/Analysis/trackFiducials.py +186 -0
  33. PYMEcs/Analysis/zerocross.py +91 -0
  34. PYMEcs/IO/MINFLUX.py +851 -0
  35. PYMEcs/IO/NPC.py +117 -0
  36. PYMEcs/IO/__init__.py +0 -0
  37. PYMEcs/IO/darkTimes.py +19 -0
  38. PYMEcs/IO/picasso.py +219 -0
  39. PYMEcs/IO/tabular.py +11 -0
  40. PYMEcs/__init__.py +0 -0
  41. PYMEcs/experimental/CalcZfactor.py +51 -0
  42. PYMEcs/experimental/FRC.py +338 -0
  43. PYMEcs/experimental/ImageJROItools.py +49 -0
  44. PYMEcs/experimental/MINFLUX.py +1537 -0
  45. PYMEcs/experimental/NPCcalcLM.py +560 -0
  46. PYMEcs/experimental/Simpler.py +369 -0
  47. PYMEcs/experimental/Sofi.py +78 -0
  48. PYMEcs/experimental/__init__.py +0 -0
  49. PYMEcs/experimental/binEventProperty.py +187 -0
  50. PYMEcs/experimental/chaining.py +23 -0
  51. PYMEcs/experimental/clusterTrack.py +179 -0
  52. PYMEcs/experimental/combine_maps.py +104 -0
  53. PYMEcs/experimental/eventProcessing.py +93 -0
  54. PYMEcs/experimental/fiducials.py +323 -0
  55. PYMEcs/experimental/fiducialsNew.py +402 -0
  56. PYMEcs/experimental/mapTools.py +271 -0
  57. PYMEcs/experimental/meas2DplotDh5view.py +107 -0
  58. PYMEcs/experimental/mortensen.py +131 -0
  59. PYMEcs/experimental/ncsDenoise.py +158 -0
  60. PYMEcs/experimental/onTimes.py +295 -0
  61. PYMEcs/experimental/procPoints.py +77 -0
  62. PYMEcs/experimental/pyme2caml.py +73 -0
  63. PYMEcs/experimental/qPAINT.py +965 -0
  64. PYMEcs/experimental/randMap.py +188 -0
  65. PYMEcs/experimental/regExtraCmaps.py +11 -0
  66. PYMEcs/experimental/selectROIfilterTable.py +72 -0
  67. PYMEcs/experimental/showErrs.py +51 -0
  68. PYMEcs/experimental/showErrsDh5view.py +58 -0
  69. PYMEcs/experimental/showShiftMap.py +56 -0
  70. PYMEcs/experimental/snrEvents.py +188 -0
  71. PYMEcs/experimental/specLabeling.py +51 -0
  72. PYMEcs/experimental/splitRender.py +246 -0
  73. PYMEcs/experimental/testChannelByName.py +36 -0
  74. PYMEcs/experimental/timedSpecies.py +28 -0
  75. PYMEcs/experimental/utils.py +31 -0
  76. PYMEcs/misc/ExtraCmaps.py +177 -0
  77. PYMEcs/misc/__init__.py +0 -0
  78. PYMEcs/misc/configUtils.py +169 -0
  79. PYMEcs/misc/guiMsgBoxes.py +27 -0
  80. PYMEcs/misc/mapUtils.py +230 -0
  81. PYMEcs/misc/matplotlib.py +136 -0
  82. PYMEcs/misc/rectsFromSVG.py +182 -0
  83. PYMEcs/misc/shellutils.py +1110 -0
  84. PYMEcs/misc/utils.py +205 -0
  85. PYMEcs/misc/versionCheck.py +20 -0
  86. PYMEcs/misc/zcInfo.py +90 -0
  87. PYMEcs/pyme_warnings.py +4 -0
  88. PYMEcs/recipes/__init__.py +0 -0
  89. PYMEcs/recipes/base.py +75 -0
  90. PYMEcs/recipes/localisations.py +2380 -0
  91. PYMEcs/recipes/manipulate_yaml.py +83 -0
  92. PYMEcs/recipes/output.py +177 -0
  93. PYMEcs/recipes/processing.py +247 -0
  94. PYMEcs/recipes/simpler.py +290 -0
  95. PYMEcs/version.py +2 -0
  96. pyme_extra-1.0.4.post0.dist-info/METADATA +114 -0
  97. pyme_extra-1.0.4.post0.dist-info/RECORD +101 -0
  98. pyme_extra-1.0.4.post0.dist-info/WHEEL +5 -0
  99. pyme_extra-1.0.4.post0.dist-info/entry_points.txt +3 -0
  100. pyme_extra-1.0.4.post0.dist-info/licenses/LICENSE +674 -0
  101. pyme_extra-1.0.4.post0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,433 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on Fri Mar 28 15:02:50 2014
4
+
5
+ @author: David Baddeley
6
+ """
7
+
8
+ import numpy as np
9
+ from numpy.fft import fftn, ifftn, fftshift, ifftshift
10
+
11
+ import time
12
+ from scipy import ndimage
13
+ from PYME.Acquire import eventLog
14
+
15
+ import threading
16
+
17
+ import logging
18
+ logger = logging.getLogger(__name__)
19
+
20
+ from PYME.contrib import dispatch
21
+ class StandardFrameSource(object):
22
+ '''This is a simple source which emits frames once per polling interval of the frameWrangler
23
+ (i.e. corresponding to the onFrameGroup signal of the frameWrangler).
24
+
25
+ The intention is to reproduce the historical behaviour of the drift tracking code, whilst
26
+ abstracting some of the detailed knowledge of frame handling out of the actual tracking code.
27
+
28
+ '''
29
+ def __init__(self, frameWrangler):
30
+ self._fw = frameWrangler
31
+ self._on_frame = dispatch.Signal(['frameData'])
32
+ self._fw.onFrameGroup.connect(self.tick)
33
+
34
+
35
+ def tick(self, *args, **kwargs):
36
+ self._on_frame.send(sender=self, frameData=self._fw.currentFrame)
37
+
38
+ @property
39
+ def shape(self):
40
+ return self._fw.currentFrame.shape
41
+
42
+ def connect(self, callback):
43
+ self._on_frame.connect(callback)
44
+
45
+ def disconnect(self, callback):
46
+ self._on_frame.disconnect(callback)
47
+
48
+ class OIDICFrameSource(StandardFrameSource):
49
+ """ Emit frames from the camera to the tracking code only for a single OIDIC orientation.
50
+
51
+ Currently a straw man / skeleton pending details of OIDIC code.
52
+
53
+ TODO - should this reside here, or with the other OIDIC code (which I believe to be in a separate repo)?
54
+
55
+ """
56
+
57
+ def __init__(self, frameWrangler, oidic_controller, oidic_orientation=0):
58
+ super().__init__(frameWrangler)
59
+
60
+ self._oidic = oidic_controller
61
+ self._target_orientation = oidic_orientation
62
+
63
+ def tick(self, *args, **kwargs):
64
+ # FIXME - change to match actual naming etc ... in OIDIC code.
65
+ # FIXME - check when onFrameGroup is emitted relative to when the OIDIC orientation is set.
66
+ # Is this predictable, or does it depend on the order in which OIDIC and drift tracking are
67
+ # registered with the frameWrangler?
68
+ if self._oidic.orientation == self._target_orientation:
69
+ super().tick(*args, **kwargs)
70
+ else:
71
+ # clobber all frames coming from camera when not in the correct DIC orientation
72
+ pass
73
+
74
+ from enum import Enum
75
+ State = Enum('State', ['UNCALIBRATED', 'CALIBRATING', 'FINISHING_CALIBRATION', 'CALIBRATED'])
76
+
77
+ class Correlator(object):
78
+ def __init__(self, scope, piezo=None, frame_source=None, sub_roi=None, focusTolerance=.05, deltaZ=0.2, stackHalfSize=35):
79
+ self.piezo = piezo
80
+
81
+ if frame_source is None:
82
+ self.frame_source = StandardFrameSource(scope.frameWrangler)
83
+
84
+ # configuration parameters, accessible via keyword args
85
+ self.focusTolerance = focusTolerance # (in um) how far focus can drift before we correct
86
+ self.deltaZ = deltaZ #z increment (in um) used for calibration
87
+ self.stackHalfSize = stackHalfSize
88
+ # other configuration parameters - not currently accessible via keyword args
89
+ self.skipframes = 1 # number of frames to skip after changing position to let piezo settle
90
+ self.minDelay = 10
91
+ # NOTE: maxTotalCorrection parameter below - we may want to have a reset offset method
92
+ # to allow resetting the offset during the day as it tends to accumulate;
93
+ # this has already led to the lock giving up on occasion
94
+ self._maxTotalCorrection = 20.0 # maximum total correction in um
95
+ self.Zfactor = 1.0
96
+ self.logShifts = True
97
+
98
+ # we report our tracking info in nm by default
99
+ pixelsize_um = scope.GetPixelSize()
100
+ self.conversion = {'x': 1e3*pixelsize_um[0], 'y':1e3*pixelsize_um[1], 'z':1e3}
101
+ # we may or may not want to use the one below
102
+ # self.trackunits = {'x':'nm', 'y':'nm', 'z':'nm'}
103
+
104
+ # 'state-tracking' variables
105
+ self.NCalibFrames = 2*self.stackHalfSize + 1 # this gets recalculated in _prepare_calibration anyway
106
+ self.calibCurFrame = 0
107
+ self.state = State.UNCALIBRATED
108
+ self.tracking = False
109
+ self.lockActive = False
110
+ self.lockFocus = False
111
+ self._last_target_z = -1
112
+
113
+ def set_subroi(self, bounds):
114
+ """ Set the position of the roi to crop
115
+
116
+ Parameters
117
+ ----------
118
+
119
+ position : tuple
120
+ The pixel position (x0, x1, y0, y1) in int
121
+ """
122
+
123
+ self.sub_roi = bounds
124
+ self.reCalibrate()
125
+
126
+ def _crop_frame(self, frame_data):
127
+ if self.sub_roi is None:
128
+ return frame_data.squeeze() # we may as well do the squeeze here to avoid lots of squeezes elsewhere
129
+ else:
130
+ x0, x1, y0, y1 = self.sub_roi
131
+ return frame_data.squeeze()[x0:x1, y0:y1]
132
+
133
+ def set_focus_tolerance(self, tolerance):
134
+ """ Set the tolerance for locking position
135
+
136
+ Parameters
137
+ ----------
138
+
139
+ tolerance : float
140
+ The tolerance in um
141
+ """
142
+
143
+ self.focusTolerance = tolerance
144
+
145
+ def get_focus_tolerance(self):
146
+ return self.focusTolerance
147
+
148
+ def set_delta_Z(self, delta):
149
+ """ Set the Z increment for calibration stack
150
+
151
+ Parameters
152
+ ----------
153
+
154
+ delta : float
155
+ The delta in um. This should be the distance over which changes in PSF intensity with depth
156
+ can be approximated as being linear, with an upper bound of the Nyquist sampling in Z.
157
+ At Nyquist sampling, the linearity assumption is already getting a bit tenuous. Default = 0.2 um,
158
+ which is approximately Nyquist sampled at 1.4NA.
159
+ """
160
+
161
+ self.deltaZ = delta
162
+
163
+ def get_delta_Z(self):
164
+ return self.deltaZ
165
+
166
+ def set_stack_halfsize(self, halfsize):
167
+ """ Set the calibration stack half size
168
+
169
+ This dictates the maximum size of z-stack you can record whilst retaining focus lock. The resulting
170
+ calibration range can be calculated as deltaZ*(2*halfsize), and should extend about 1 micron above
171
+ and below the size of the the largest z-stack to ensure that lock can be maintained at the edges of
172
+ the stack. The default of 35 gives about 12 um of axial range.
173
+
174
+ Parameters
175
+ ----------
176
+
177
+ halfsize : int
178
+ """
179
+
180
+ self.stackHalfSize = halfsize
181
+
182
+ def get_stack_halfsize(self):
183
+ return self.stackHalfSize
184
+
185
+ def set_focus_lock(self, lock=True):
186
+ """ Set locking on or off
187
+
188
+ Parameters
189
+ ----------
190
+
191
+ lock : bool
192
+ whether the lock should be on
193
+ """
194
+
195
+ self.lockFocus = lock
196
+
197
+ def get_focus_lock(self):
198
+ return self.lockFocus
199
+
200
+ def get_history(self, length=1000):
201
+ try:
202
+ return self.history[-length:]
203
+ except AttributeError:
204
+ return []
205
+
206
+ def get_calibration_progress(self):
207
+ """ Returns the current calibration progress:
208
+ calibration is complete when state == State.CALIBRATED
209
+ """
210
+
211
+ if self.state == State.UNCALIBRATED:
212
+ curFrame = 0
213
+ elif self.state in [State.CALIBRATING,State.FINISHING_CALIBRATION]:
214
+ curFrame = self.calibCurFrame
215
+ else:
216
+ curFrame = self.NCalibFrames
217
+ return (self.state, self.NCalibFrames, curFrame)
218
+
219
+ def is_tracking(self):
220
+ return self.tracking
221
+
222
+ def _setRefN(self, frame_data, N):
223
+ d = 1.0*frame_data.squeeze()
224
+ ref = d/d.mean() - 1
225
+ self.refImages[:,:,N] = ref
226
+ self.calFTs[:,:,N] = ifftn(ref)
227
+ self.calImages[:,:,N] = ref*self.mask
228
+
229
+ def _prepare_calibration(self, frame_data):
230
+ # this should not be necessary as we SHOULD only get called if we are uncalibrated
231
+ # self.state = State.UNCALIBRATED #completely uncalibrated
232
+ if self.state != State.UNCALIBRATED:
233
+ raise RuntimeError("this method should only be called when uncalibrated; actual state is %s" % self.state)
234
+
235
+ d = 1.0*frame_data.squeeze()
236
+
237
+ self.X, self.Y = np.mgrid[0.0:d.shape[0], 0.0:d.shape[1]]
238
+ self.X -= np.ceil(d.shape[0]*0.5)
239
+ self.Y -= np.ceil(d.shape[1]*0.5)
240
+
241
+ #we want to discard edges after accounting for x-y drift
242
+ self.mask = np.ones_like(d)
243
+ self.mask[:10, :] = 0
244
+ self.mask[-10:, :] = 0
245
+ self.mask[:, :10] = 0
246
+ self.mask[:,-10:] = 0
247
+
248
+ self.corrRef = 0
249
+
250
+ self.calPositions = self.homePos + self.deltaZ*np.arange(-float(self.stackHalfSize), float(self.stackHalfSize + 1))
251
+ self.NCalibFrames = len(self.calPositions)
252
+
253
+ self.refImages = np.zeros(self.mask.shape[:2] + (self.NCalibFrames,))
254
+ self.calImages = np.zeros(self.mask.shape[:2] + (self.NCalibFrames,))
255
+ self.calFTs = np.zeros(self.mask.shape[:2] + (self.NCalibFrames,), dtype='complex64')
256
+
257
+ self.lockFocus = False
258
+ self.lockActive = False
259
+ self.logShifts = True
260
+ self.lastAdjustment = 5
261
+
262
+ def _finish_calibration(self):
263
+ if self.state != State.FINISHING_CALIBRATION:
264
+ raise RuntimeError("this method should only be called when finishing the calibration; actual state is %s" % self.state)
265
+
266
+ # calculate the gradient info (needed in compare calls) from a valid calImages stack
267
+ self.dz = np.gradient(self.calImages)[2].reshape(-1, self.NCalibFrames)
268
+ self.dzn = np.hstack([1./np.dot(self.dz[:,i], self.dz[:,i]) for i in range(self.NCalibFrames)])
269
+
270
+ def compare(self, frame_data):
271
+ d = 1.0*frame_data.squeeze()
272
+ dm = d/d.mean() - 1
273
+
274
+ #where is the piezo suppposed to be
275
+ #nomPos = self.piezo.GetPos(0)
276
+ nomPos = self.piezo.GetTargetPos(0)
277
+
278
+ #find closest calibration position
279
+ posInd = np.argmin(np.abs(nomPos - self.calPositions))
280
+
281
+ #retrieve calibration information at this location
282
+ calPos = self.calPositions[posInd]
283
+ FA = self.calFTs[:,:,posInd]
284
+ refA = self.calImages[:,:,posInd]
285
+
286
+ ddz = self.dz[:,posInd]
287
+ dzn = self.dzn[posInd]
288
+
289
+ #what is the offset between our target position and the calibration position
290
+ posDelta = nomPos - calPos
291
+
292
+ #print('%s' % [nomPos, posInd, calPos, posDelta])
293
+
294
+ #find x-y drift
295
+ C = ifftshift(np.abs(ifftn(fftn(dm)*FA)))
296
+
297
+ Cm = C.max()
298
+
299
+ Cp = np.maximum(C - 0.5*Cm, 0)
300
+ Cpsum = Cp.sum()
301
+
302
+ dx = (self.X*Cp).sum()/Cpsum
303
+ dy = (self.Y*Cp).sum()/Cpsum
304
+
305
+ ds = ndimage.shift(dm, [-dx, -dy])*self.mask
306
+
307
+ #print A.shape, As.shape
308
+
309
+ self.ds_A = (ds - refA)
310
+
311
+ #calculate z offset between actual position and calibration position
312
+ dz = self.Zfactor*self.deltaZ*np.dot(self.ds_A.ravel(), ddz)*dzn
313
+
314
+ #posInd += np.round(dz / self.deltaZ)
315
+ #posInd = int(np.clip(posInd, 0, self.NCalibStates))
316
+
317
+ #add the offset back to determine how far we are from the target position
318
+ dz = dz - posDelta
319
+
320
+ return dx, dy, dz, Cm, nomPos, posInd, calPos, posDelta
321
+
322
+ def compare_log_and_correct(self,frameData):
323
+ # compare returns pixel coordinates for dx, dy, um for dz
324
+ dx, dy, dz, cCoeff, nomPos, posInd, calPos, posDelta = self.compare(frameData)
325
+ self.corrRef = max(self.corrRef, cCoeff) # keep track of historically maximal correlation amplitude
326
+
327
+ #print dx, dy, dz
328
+ dx_nm, dy_nm, dz_nm = (self.conversion['x']*dx, self.conversion['y']*dy, self.conversion['z']*dz)
329
+
330
+ offset = self.piezo.GetOffset()
331
+ offset_nm = 1e3*offset
332
+
333
+ pos_um = self.piezo.GetPos(0)
334
+
335
+ #FIXME: logging shouldn't call piezo.GetOffset() etc ... for performance reasons
336
+ # (is this still true, we keep the values cached in memory??)
337
+ # this is the local logging, not to the actual localisation data acquiring instance of PYMEAcquire
338
+ self.history.append((time.time(), dx_nm, dy_nm, dz_nm, cCoeff, self.corrRef, offset_nm, pos_um))
339
+ eventLog.logEvent('PYME2ShiftMeasure', '%3.1f, %3.1f, %3.1f' % (dx_nm, dy_nm, dz_nm))
340
+
341
+ self.lockActive = self.lockFocus and (cCoeff > .5*self.corrRef) # we release the lock when the correlation becomes too weak
342
+ if self.lockActive:
343
+ if abs(offset) > self._maxTotalCorrection:
344
+ self.lockFocus = False
345
+ logger.info("focus lock released, maximal Offset value exceeded (%.1f um)" % self._maxTotalCorrection)
346
+ if abs(dz) > self.focusTolerance and self.lastAdjustment >= self.minDelay:
347
+ # this sets the correction on the connected piezo
348
+ self.piezo.SetOffset(offset - dz)
349
+ self.lastAdjustment = 0
350
+ else:
351
+ self.lastAdjustment += 1
352
+
353
+ if self.logShifts:
354
+ # this logs to the connected copy of PYMEAcquire via the RESTServer
355
+ if hasattr(self.piezo, 'LogShiftsCorrelAmp'):
356
+ self.piezo.LogShiftsCorrelAmp(dx_nm, dy_nm, dz_nm, self.lockActive, coramp=cCoeff/self.corrRef)
357
+ else:
358
+ self.piezo.LogShifts(dx_nm, dy_nm, dz_nm, self.lockActive)
359
+
360
+ def tick(self, frameData = None, **kwargs):
361
+ if frameData is None:
362
+ raise ValueError('frameData must be specified')
363
+ else:
364
+ frameData = self._crop_frame(frameData)
365
+
366
+ targetZ = self.piezo.GetTargetPos(0)
367
+
368
+ if not 'mask' in dir(self) or not self.frame_source.shape[:2] == self.mask.shape[:2]:
369
+ # this just sets the UNCALIBRATED state and leaves the rest to the _prepare_calibration call
370
+ self.state = State.UNCALIBRATED
371
+
372
+ #called on a new frame becoming available
373
+ if self.state == State.UNCALIBRATED:
374
+ #print "cal init"
375
+
376
+ #redefine our positions for the calibration
377
+ self.homePos = self.piezo.GetPos(0)
378
+ self._prepare_calibration(frameData)
379
+ self.calibCurFrame = 0
380
+ self.skipcounter = self.skipframes
381
+ # move to our first position in the calib stack
382
+ self.piezo.MoveTo(0, self.calPositions[0])
383
+
384
+ # preps done, now switch state to calibrating
385
+ self.state = State.CALIBRATING
386
+ elif self.state == State.CALIBRATING:
387
+ # print "cal proceed"
388
+ if self.skipcounter >= 1:
389
+ self.skipcounter -= 1 # we let the last move settle...
390
+ else:
391
+ # piezo step completed - record current image and move on to next position
392
+ self._setRefN(frameData, int(self.calibCurFrame))
393
+ if self.calibCurFrame == self.NCalibFrames-1: # we are mostly done, this was our last plane
394
+ self.state = State.FINISHING_CALIBRATION
395
+ else: # not done yet
396
+ self.skipcounter = self.skipframes # reset skip counter
397
+ self.calibCurFrame += 1 # and go to next frame position
398
+ self.piezo.MoveTo(0, self.calPositions[int(self.calibCurFrame)])
399
+
400
+ elif self.state == State.FINISHING_CALIBRATION:
401
+ # print "cal finishing"
402
+ self._finish_calibration()
403
+ self.piezo.MoveTo(0, self.homePos) # move back to where we started
404
+
405
+ #reset our history log
406
+ self.history = []
407
+ self.historyColNames = ['time','dx_nm','dy_nm','dz_nm','corrAmplitude','corrAmpMax','piezoOffset_nm','piezoPos_um']
408
+ self.historyStartTime = time.time()
409
+
410
+ self.state = State.CALIBRATED # now we are fully calibrated
411
+
412
+ elif self.state == State.CALIBRATED:
413
+ # print "fully calibrated"
414
+ if np.allclose(self._last_target_z, targetZ): # check we are on target in z
415
+ self.compare_log_and_correct(frameData)
416
+
417
+ else:
418
+ raise RuntimeError("unknown calibration state %s, giving up" % self.state)
419
+
420
+ self._last_target_z = targetZ
421
+
422
+ def reCalibrate(self):
423
+ self.state = State.UNCALIBRATED
424
+ self.corrRef = 0
425
+ self.lockActive = False
426
+
427
+ def register(self):
428
+ self.frame_source.connect(self.tick)
429
+ self.tracking = True
430
+
431
+ def deregister(self):
432
+ self.frame_source.disconnect(self.tick)
433
+ self.tracking = False
@@ -0,0 +1,15 @@
1
+ from PYME.Acquire.Hardware.Simulator.fakeCam import FakeCamera
2
+ from PYME.IO import MetaDataHandler
3
+
4
+ # the only difference of this class is to supply extra metadata to allow testing the
5
+ # camera map processing code
6
+ class FakeCameraX(FakeCamera):
7
+
8
+ def GenStartMetadata(self, mdh):
9
+ super().GenStartMetadata(mdh)
10
+ # these are useful when we want to test camera map making code
11
+ mdh.setEntry('Camera.SerialNumber', 'FAKE-007')
12
+ mdh.setEntry('Camera.SensorWidth',self.GetCCDWidth())
13
+ mdh.setEntry('Camera.SensorHeight',self.GetCCDHeight())
14
+ mdh.setEntry('Camera.Model', 'FakeCameraX')
15
+
@@ -0,0 +1,38 @@
1
+ from PYME.Acquire.Hardware.Piezos import offsetPiezoREST
2
+
3
+ from PYME.Acquire import eventLog
4
+ import time
5
+
6
+ from PYME.util import webframework
7
+
8
+ import logging
9
+ logger = logging.getLogger(__name__)
10
+
11
+ # we modify the OffsetPiezo server and client to do additional logging by preserving the correlation amplitude information
12
+ # this is simply achieved by inheriting from the classes in offsetPiezoREST and adding a couple new methods
13
+ # the final bit is a change in our version of driftTracking.py that checks if the LogShiftsCorrelAmp method is available
14
+ # in the client and uses it in that case for the additional event logging
15
+
16
+ class OffsetPiezoCorrelLog(offsetPiezoREST.OffsetPiezo):
17
+
18
+ @webframework.register_endpoint('/LogShiftsCA', output_is_json=False)
19
+ def LogShiftsCA(self, dx, dy, dz, active=True, coramp=-1.0):
20
+ import wx
21
+ #eventLog.logEvent('ShiftMeasure', '%3.4f, %3.4f, %3.4f' % (dx, dy, dz))
22
+ wx.CallAfter(eventLog.logEvent, 'ShiftMeasure', '%3.4f, %3.4f, %3.4f' % (float(dx), float(dy), float(dz)), time.time())
23
+ wx.CallAfter(eventLog.logEvent, 'PiezoOffset', '%3.4f, %d' % (self.GetOffset(), int(active)), time.time())
24
+ wx.CallAfter(eventLog.logEvent, 'CorrelationAmplitude', '%3.4f' % (float(coramp)), time.time())
25
+
26
+ class OffsetPiezoCorrelLogClient(offsetPiezoREST.OffsetPiezoClient):
27
+
28
+ def LogShiftsCorrelAmp(self, dx, dy, dz, active=True, coramp=-1.0):
29
+ res = self._session.get(self.urlbase +
30
+ '/LogShiftsCA?dx=%3.3f&dy=%3.3f&dz=%3.3f&active=%d&coramp=%3.3f' % (dx, dy, dz, active,coramp))
31
+
32
+
33
+ def getClient():
34
+ #TODO - move away from hard-coded ports!!!
35
+ return OffsetPiezoCorrelLogClient()
36
+
37
+ def getServer():
38
+ return offsetPiezoREST.server_class(offset_piezo_base_class=OffsetPiezoCorrelLog)
File without changes