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.
- PYMEcs/Acquire/Actions/__init__.py +0 -0
- PYMEcs/Acquire/Actions/custom.py +167 -0
- PYMEcs/Acquire/Hardware/LPthreadedSimple.py +248 -0
- PYMEcs/Acquire/Hardware/LPthreadedSimpleSim.py +246 -0
- PYMEcs/Acquire/Hardware/NikonTiFlaskServer.py +45 -0
- PYMEcs/Acquire/Hardware/NikonTiFlaskServerT.py +59 -0
- PYMEcs/Acquire/Hardware/NikonTiRESTClient.py +73 -0
- PYMEcs/Acquire/Hardware/NikonTiSim.py +35 -0
- PYMEcs/Acquire/Hardware/__init__.py +0 -0
- PYMEcs/Acquire/Hardware/driftTrackGUI.py +329 -0
- PYMEcs/Acquire/Hardware/driftTrackGUI_n.py +472 -0
- PYMEcs/Acquire/Hardware/driftTracking.py +424 -0
- PYMEcs/Acquire/Hardware/driftTracking_n.py +433 -0
- PYMEcs/Acquire/Hardware/fakeCamX.py +15 -0
- PYMEcs/Acquire/Hardware/offsetPiezoRESTCorrelLog.py +38 -0
- PYMEcs/Acquire/__init__.py +0 -0
- PYMEcs/Analysis/MBMcollection.py +552 -0
- PYMEcs/Analysis/MINFLUX.py +280 -0
- PYMEcs/Analysis/MapUtils.py +77 -0
- PYMEcs/Analysis/NPC.py +1176 -0
- PYMEcs/Analysis/Paraflux.py +218 -0
- PYMEcs/Analysis/Simpler.py +81 -0
- PYMEcs/Analysis/Sofi.py +140 -0
- PYMEcs/Analysis/__init__.py +0 -0
- PYMEcs/Analysis/decSofi.py +211 -0
- PYMEcs/Analysis/eventProperties.py +50 -0
- PYMEcs/Analysis/fitDarkTimes.py +569 -0
- PYMEcs/Analysis/objectVolumes.py +20 -0
- PYMEcs/Analysis/offlineTracker.py +130 -0
- PYMEcs/Analysis/stackTracker.py +180 -0
- PYMEcs/Analysis/timeSeries.py +63 -0
- PYMEcs/Analysis/trackFiducials.py +186 -0
- PYMEcs/Analysis/zerocross.py +91 -0
- PYMEcs/IO/MINFLUX.py +851 -0
- PYMEcs/IO/NPC.py +117 -0
- PYMEcs/IO/__init__.py +0 -0
- PYMEcs/IO/darkTimes.py +19 -0
- PYMEcs/IO/picasso.py +219 -0
- PYMEcs/IO/tabular.py +11 -0
- PYMEcs/__init__.py +0 -0
- PYMEcs/experimental/CalcZfactor.py +51 -0
- PYMEcs/experimental/FRC.py +338 -0
- PYMEcs/experimental/ImageJROItools.py +49 -0
- PYMEcs/experimental/MINFLUX.py +1537 -0
- PYMEcs/experimental/NPCcalcLM.py +560 -0
- PYMEcs/experimental/Simpler.py +369 -0
- PYMEcs/experimental/Sofi.py +78 -0
- PYMEcs/experimental/__init__.py +0 -0
- PYMEcs/experimental/binEventProperty.py +187 -0
- PYMEcs/experimental/chaining.py +23 -0
- PYMEcs/experimental/clusterTrack.py +179 -0
- PYMEcs/experimental/combine_maps.py +104 -0
- PYMEcs/experimental/eventProcessing.py +93 -0
- PYMEcs/experimental/fiducials.py +323 -0
- PYMEcs/experimental/fiducialsNew.py +402 -0
- PYMEcs/experimental/mapTools.py +271 -0
- PYMEcs/experimental/meas2DplotDh5view.py +107 -0
- PYMEcs/experimental/mortensen.py +131 -0
- PYMEcs/experimental/ncsDenoise.py +158 -0
- PYMEcs/experimental/onTimes.py +295 -0
- PYMEcs/experimental/procPoints.py +77 -0
- PYMEcs/experimental/pyme2caml.py +73 -0
- PYMEcs/experimental/qPAINT.py +965 -0
- PYMEcs/experimental/randMap.py +188 -0
- PYMEcs/experimental/regExtraCmaps.py +11 -0
- PYMEcs/experimental/selectROIfilterTable.py +72 -0
- PYMEcs/experimental/showErrs.py +51 -0
- PYMEcs/experimental/showErrsDh5view.py +58 -0
- PYMEcs/experimental/showShiftMap.py +56 -0
- PYMEcs/experimental/snrEvents.py +188 -0
- PYMEcs/experimental/specLabeling.py +51 -0
- PYMEcs/experimental/splitRender.py +246 -0
- PYMEcs/experimental/testChannelByName.py +36 -0
- PYMEcs/experimental/timedSpecies.py +28 -0
- PYMEcs/experimental/utils.py +31 -0
- PYMEcs/misc/ExtraCmaps.py +177 -0
- PYMEcs/misc/__init__.py +0 -0
- PYMEcs/misc/configUtils.py +169 -0
- PYMEcs/misc/guiMsgBoxes.py +27 -0
- PYMEcs/misc/mapUtils.py +230 -0
- PYMEcs/misc/matplotlib.py +136 -0
- PYMEcs/misc/rectsFromSVG.py +182 -0
- PYMEcs/misc/shellutils.py +1110 -0
- PYMEcs/misc/utils.py +205 -0
- PYMEcs/misc/versionCheck.py +20 -0
- PYMEcs/misc/zcInfo.py +90 -0
- PYMEcs/pyme_warnings.py +4 -0
- PYMEcs/recipes/__init__.py +0 -0
- PYMEcs/recipes/base.py +75 -0
- PYMEcs/recipes/localisations.py +2380 -0
- PYMEcs/recipes/manipulate_yaml.py +83 -0
- PYMEcs/recipes/output.py +177 -0
- PYMEcs/recipes/processing.py +247 -0
- PYMEcs/recipes/simpler.py +290 -0
- PYMEcs/version.py +2 -0
- pyme_extra-1.0.4.post0.dist-info/METADATA +114 -0
- pyme_extra-1.0.4.post0.dist-info/RECORD +101 -0
- pyme_extra-1.0.4.post0.dist-info/WHEEL +5 -0
- pyme_extra-1.0.4.post0.dist-info/entry_points.txt +3 -0
- pyme_extra-1.0.4.post0.dist-info/licenses/LICENSE +674 -0
- pyme_extra-1.0.4.post0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import matplotlib.pyplot as plt
|
|
3
|
+
|
|
4
|
+
import logging
|
|
5
|
+
logger = logging.getLogger(__file__)
|
|
6
|
+
|
|
7
|
+
# interpolate the key from the source to the selected datasource of the pipeline
|
|
8
|
+
def finterpDS(pipeline,sourcep,key):
|
|
9
|
+
tsource, idx = np.unique(sourcep['t'], return_index=True)
|
|
10
|
+
fsource = sourcep[key][idx]
|
|
11
|
+
fDS = np.interp(pipeline.selectedDataSource['t'], tsource, fsource)
|
|
12
|
+
return fDS
|
|
13
|
+
|
|
14
|
+
def zshift(t,data,navg=50):
|
|
15
|
+
ti,idx = np.unique(t.astype('int'),return_index=True)
|
|
16
|
+
di = data[idx]
|
|
17
|
+
nm = min(navg,di.shape[0])
|
|
18
|
+
offset = di[0:nm].mean()
|
|
19
|
+
return data - offset
|
|
20
|
+
|
|
21
|
+
from traits.api import HasTraits, Str, Int, CStr, List, Enum, Float
|
|
22
|
+
#from traitsui.api import View, Item, Group
|
|
23
|
+
#from traitsui.menu import OKButton, CancelButton, OKCancelButtons
|
|
24
|
+
|
|
25
|
+
class SetZPars(HasTraits):
|
|
26
|
+
scaleFactor = Float(-1e3)
|
|
27
|
+
shiftFrames = Int(0)
|
|
28
|
+
|
|
29
|
+
class FiducialTracker:
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
"""
|
|
33
|
+
def __init__(self, visFr):
|
|
34
|
+
self.visFr = visFr
|
|
35
|
+
self.pipeline = visFr.pipeline
|
|
36
|
+
|
|
37
|
+
visFr.AddMenuItem('Experimental>Deprecated>Fiducials', 'Add mean fiducial track', self.OnFiducialTrack,
|
|
38
|
+
helpText='Add mean fiducial track')
|
|
39
|
+
visFr.AddMenuItem('Experimental>Deprecated>Fiducials', 'New DS with mean fiducial track applied',
|
|
40
|
+
self.OnFiducialCorrectDS,
|
|
41
|
+
helpText='Apply mean fiducial track')
|
|
42
|
+
visFr.AddMenuItem('Experimental>Deprecated>Fiducials', "Plot Fiducial Track", self.OnPlotFiducial,
|
|
43
|
+
helpText='Plot mean fiducial tracks for all available dims')
|
|
44
|
+
visFr.AddMenuItem('Experimental>Deprecated>Fiducials', "Set Z Parameters", self.OnSetZPars,
|
|
45
|
+
helpText='Set shift and scale parameters for driftz track')
|
|
46
|
+
visFr.AddMenuItem('Experimental>Deprecated>Fiducials', "Set Z drift (from aligned driftz)", self.OnSetZDrift,
|
|
47
|
+
helpText='Set Z drift compensation from scaled and aligned driftz track')
|
|
48
|
+
visFr.AddMenuItem('Experimental>Deprecated>Fiducials', "Clear Z driftz mapping", self.clearDriftZ,
|
|
49
|
+
helpText='Remove Z drift mapping by popping any mapping for z')
|
|
50
|
+
visFr.AddMenuItem('Experimental>Deprecated>Fiducials', "Diagnose Fiducials", lambda e: self.fiducial_diagnosis(),
|
|
51
|
+
helpText='Diagnose quality of fiducial correction')
|
|
52
|
+
visFr.AddMenuItem('Experimental>Deprecated>Fiducials', "Compare fiducial and drift", self.fiducialvsdrift,
|
|
53
|
+
helpText='Compare fiducial and drift information')
|
|
54
|
+
visFr.AddMenuItem('Experimental>Corrections',"Fiducial - extract fiducial track and correct datasource",
|
|
55
|
+
self.OnFiducialCorrectNew,
|
|
56
|
+
helpText='faster tracking by inserting FiducialTrack and FiducialApplyFromFiducials modules')
|
|
57
|
+
|
|
58
|
+
self.scaleFactor = -1e3
|
|
59
|
+
self.shiftFrames = 0
|
|
60
|
+
self.zeroAlignFrames = 200
|
|
61
|
+
self.zDrift = None
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def OnFiducialCorrectNew(self, event=None):
|
|
65
|
+
from PYMEcs.recipes import localisations
|
|
66
|
+
recipe = self.pipeline.recipe
|
|
67
|
+
# change defaults back to median filter
|
|
68
|
+
ftrack = localisations.FiducialTrack(recipe, inputName='Fiducials',
|
|
69
|
+
filterMethod='Median',
|
|
70
|
+
outputName='fiducialAdded')
|
|
71
|
+
if not ftrack.configure_traits(kind='modal'):
|
|
72
|
+
return
|
|
73
|
+
recipe.add_module(ftrack)
|
|
74
|
+
recipe.add_module(localisations.FiducialApplyFromFiducials(recipe, inputData=self.pipeline.selectedDataSourceKey,
|
|
75
|
+
inputFiducials='fiducialAdded',
|
|
76
|
+
outputName='fiducialApplied',
|
|
77
|
+
outputFiducials='corrected_fiducials'))
|
|
78
|
+
recipe.execute()
|
|
79
|
+
self.pipeline.selectDataSource('fiducialApplied')
|
|
80
|
+
|
|
81
|
+
def OnFiducialTrack(self, event=None):
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
"""
|
|
85
|
+
from PYMEcs.recipes import localisations
|
|
86
|
+
|
|
87
|
+
if False:
|
|
88
|
+
fTracker = localisations.FiducialTrack(filterMethod = 'Gaussian')
|
|
89
|
+
if fTracker.configure_traits(kind='modal'):
|
|
90
|
+
# we call this with the pipeline to allow filtering etc
|
|
91
|
+
namespace = {fTracker.inputName: self.pipeline}
|
|
92
|
+
fTracker.execute(namespace)
|
|
93
|
+
|
|
94
|
+
# the fiducial needs to be entered for the whole data source
|
|
95
|
+
# otherwise we have an issue that fiducial data is not available
|
|
96
|
+
# when filters are changed; this makes the code a bit ugly
|
|
97
|
+
ds = namespace[fTracker.outputName]
|
|
98
|
+
for fiducial in ['fiducial_%s' % dim for dim in ['x','y','z']]:
|
|
99
|
+
if fiducial in ds.keys():
|
|
100
|
+
self.pipeline.selectedDataSource.addColumn(fiducial,
|
|
101
|
+
finterpDS(self.pipeline,
|
|
102
|
+
ds,
|
|
103
|
+
fiducial))
|
|
104
|
+
pds = self.pipeline.selectedDataSource
|
|
105
|
+
isfid = np.zeros(len(pds['x']), dtype='i')
|
|
106
|
+
isfid[self.pipeline.filter.Index] = ds['isFiducial']
|
|
107
|
+
pds.addColumn('isFiducial',isfid)
|
|
108
|
+
else:
|
|
109
|
+
recipe = self.pipeline.recipe
|
|
110
|
+
recipe.add_module(localisations.FiducialTrack(recipe, inputName=self.pipeline.selectedDataSourceKey,
|
|
111
|
+
outputName='with_fiducial'))
|
|
112
|
+
recipe.execute()
|
|
113
|
+
self.pipeline.selectDataSource('with_fiducial')
|
|
114
|
+
|
|
115
|
+
def OnFiducialCorrectDS(self, event=None):
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
"""
|
|
119
|
+
from PYMEcs.recipes.localisations import FiducialApply
|
|
120
|
+
recipe = self.pipeline.recipe
|
|
121
|
+
recipe.add_module(FiducialApply(recipe, inputName='with_fiducial',
|
|
122
|
+
outputName='corrected_from_fiducial'))
|
|
123
|
+
recipe.execute()
|
|
124
|
+
self.pipeline.selectDataSource('corrected_from_fiducial')
|
|
125
|
+
|
|
126
|
+
#self.visFr.RefreshView()
|
|
127
|
+
#self.visFr.CreateFoldPanel()
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def OnPlotFiducial(self, event):
|
|
131
|
+
import PYMEnf.DriftCorrection.compactFit as cf
|
|
132
|
+
|
|
133
|
+
pipeline = self.visFr.pipeline
|
|
134
|
+
t = pipeline['t']
|
|
135
|
+
x = pipeline['fiducial_x']
|
|
136
|
+
y = pipeline['fiducial_y']
|
|
137
|
+
z = pipeline['fiducial_z']
|
|
138
|
+
|
|
139
|
+
tu,idx = np.unique(t.astype('int'), return_index=True)
|
|
140
|
+
xu = x[idx]
|
|
141
|
+
yu = y[idx]
|
|
142
|
+
zu = z[idx]
|
|
143
|
+
|
|
144
|
+
hasdp = True
|
|
145
|
+
try:
|
|
146
|
+
driftPane = self.visFr.driftPane
|
|
147
|
+
except:
|
|
148
|
+
hasdp = False
|
|
149
|
+
|
|
150
|
+
import matplotlib.pyplot as plt
|
|
151
|
+
plt.figure()
|
|
152
|
+
plt.plot(tu, xu, label='x')
|
|
153
|
+
plt.plot(tu, yu, label='y')
|
|
154
|
+
plt.plot(tu, zu, label='z')
|
|
155
|
+
if hasdp:
|
|
156
|
+
if 'driftx' in driftPane.dp.driftExprX:
|
|
157
|
+
indepVars = { 't': t, 'driftx': pipeline['driftx'], 'drifty': pipeline['drifty'] }
|
|
158
|
+
dx,dy,tt = cf.xyDriftCurves(driftPane.dp.driftCorrFcn,driftPane.dp.driftCorrParams,indepVars,t)
|
|
159
|
+
plt.plot(tt,-zshift(tt,dx), '--', label='x-drift')
|
|
160
|
+
plt.plot(tt,-zshift(tt,dy), '--', label='y-drift')
|
|
161
|
+
ti = np.arange(tt.min(),tt.max(),dtype=t.dtype)
|
|
162
|
+
tu,iu = np.unique(t,return_index=True)
|
|
163
|
+
dzi = zshift(ti,np.interp(ti,tu,pipeline['driftz'][iu]),navg=self.zeroAlignFrames)
|
|
164
|
+
dzir = self.scaleFactor*np.roll(dzi,self.shiftFrames)
|
|
165
|
+
self.zDrift = [ti, dzir]
|
|
166
|
+
plt.plot(ti, dzir, '--', label='z-drift')
|
|
167
|
+
plt.legend()
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def OnSetZPars(self, event=None):
|
|
171
|
+
setPar = SetZPars(scaleFactor=self.scaleFactor,shiftFrames=self.shiftFrames,zeroAlignFrames = self.zeroAlignFrames)
|
|
172
|
+
if setPar.configure_traits(kind='modal'):
|
|
173
|
+
self.scaleFactor = setPar.scaleFactor
|
|
174
|
+
self.shiftFrames = setPar.shiftFrames
|
|
175
|
+
self.zeroAlignFrames = setPar.zeroAlignFrames
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def OnSetZDrift(self, event=None):
|
|
179
|
+
if self.zDrift is None:
|
|
180
|
+
logger.error('No zDrift found - cannot correct drift')
|
|
181
|
+
return
|
|
182
|
+
t, dz = self.zDrift
|
|
183
|
+
self.visFr.pipeline.mapping.dz = np.interp(self.visFr.pipeline.mapping['t'], t, dz)
|
|
184
|
+
self.visFr.pipeline.mapping.setMapping('z', 'z - dz')
|
|
185
|
+
|
|
186
|
+
self.visFr.pipeline.ClearGenerated()
|
|
187
|
+
|
|
188
|
+
def clearDriftZ(self, event=None):
|
|
189
|
+
try:
|
|
190
|
+
self.visFr.pipeline.mapping.mappings.pop('z')
|
|
191
|
+
except KeyError:
|
|
192
|
+
pass
|
|
193
|
+
|
|
194
|
+
self.visFr.pipeline.ClearGenerated()
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def fiducial_diagnosis(self):
|
|
198
|
+
import numpy as np
|
|
199
|
+
import matplotlib.pyplot as plt
|
|
200
|
+
from PYME.Analysis.points.fiducials import FILTER_FUNCS
|
|
201
|
+
pipeline = self.pipeline
|
|
202
|
+
|
|
203
|
+
fids = pipeline.dataSources['corrected_fiducials']
|
|
204
|
+
if 'clumpIndex' in fids.keys():
|
|
205
|
+
ci = fids['clumpIndex']
|
|
206
|
+
|
|
207
|
+
#cis = np.arange(1, ci.max())
|
|
208
|
+
|
|
209
|
+
#clump_lengths = [(ci == c).sum() for c in cis]
|
|
210
|
+
|
|
211
|
+
#largest_clump = ci == cis[np.argmax(clump_lengths)]
|
|
212
|
+
|
|
213
|
+
#x_c = fids['x'][largest_clump]
|
|
214
|
+
#y_c = fids['y'][largest_clump]
|
|
215
|
+
|
|
216
|
+
f1 = plt.figure()
|
|
217
|
+
a1 = plt.axes()
|
|
218
|
+
plt.title('Y residuals')
|
|
219
|
+
plt.grid()
|
|
220
|
+
f2 = plt.figure()
|
|
221
|
+
plt.title('X residuuals')
|
|
222
|
+
a2 = plt.axes()
|
|
223
|
+
plt.grid()
|
|
224
|
+
f3 = plt.figure()
|
|
225
|
+
plt.title('Z residuuals')
|
|
226
|
+
a3 = plt.axes()
|
|
227
|
+
plt.grid()
|
|
228
|
+
|
|
229
|
+
sel_ids = np.unique(fids['fiducialID'])
|
|
230
|
+
for pos in range(sel_ids.shape[0]):
|
|
231
|
+
a1.text(-250, pos * 50, "%d" % sel_ids[pos])
|
|
232
|
+
a2.text(-250, pos * 50, "%d" % sel_ids[pos])
|
|
233
|
+
a3.text(-250, pos * 150, "%d" % sel_ids[pos])
|
|
234
|
+
|
|
235
|
+
for i in range(1, ci.max()+1):
|
|
236
|
+
mask = fids['clumpIndex'] == i
|
|
237
|
+
if mask.sum() > 0:
|
|
238
|
+
f_id = fids['fiducialID'][mask][0]
|
|
239
|
+
pos = np.where(sel_ids==f_id)[0][0] # position in set of selected ids
|
|
240
|
+
|
|
241
|
+
fid_m = fids['fiducialID'] == f_id
|
|
242
|
+
|
|
243
|
+
ym = fids['y'][fid_m].mean()
|
|
244
|
+
xm = fids['x'][fid_m].mean()
|
|
245
|
+
zm = fids['z'][fid_m].mean()
|
|
246
|
+
|
|
247
|
+
# also plot a filtered version to see the trend in the noisy trace
|
|
248
|
+
yfilt = FILTER_FUNCS['Median'](fids['t'][mask],{'y':fids['y'][mask]},13)
|
|
249
|
+
xfilt = FILTER_FUNCS['Median'](fids['t'][mask],{'x':fids['x'][mask]},13)
|
|
250
|
+
zfilt = FILTER_FUNCS['Median'](fids['t'][mask],{'z':fids['z'][mask]},13)
|
|
251
|
+
|
|
252
|
+
a1.plot(fids['t'][mask], fids['y'][mask] - ym + pos * 50,
|
|
253
|
+
color=plt.cm.hsv( (i % 20.0)/20.))
|
|
254
|
+
a1.plot(fids['t'][mask], yfilt['y'] - ym + pos * 50, '--',
|
|
255
|
+
color='#b0b0b0', alpha=0.7)
|
|
256
|
+
|
|
257
|
+
a2.plot(fids['t'][mask], fids['x'][mask] - xm + pos * 50,
|
|
258
|
+
color=plt.cm.hsv((i % 20.0) / 20.))
|
|
259
|
+
a2.plot(fids['t'][mask], xfilt['x'] - xm + pos * 50, '--',
|
|
260
|
+
color='#b0b0b0', alpha=0.7)
|
|
261
|
+
|
|
262
|
+
a3.plot(fids['t'][mask], fids['z'][mask] - zm + pos * 150,
|
|
263
|
+
color=plt.cm.hsv((i % 20.0) / 20.))
|
|
264
|
+
a3.plot(fids['t'][mask], zfilt['z'] - zm + pos * 150, '--',
|
|
265
|
+
color='#b0b0b0', alpha=0.7)
|
|
266
|
+
|
|
267
|
+
else:
|
|
268
|
+
# stuff to do when no clumpIndex
|
|
269
|
+
f1 = plt.figure()
|
|
270
|
+
a1 = plt.axes()
|
|
271
|
+
plt.title('Y residuals')
|
|
272
|
+
plt.grid()
|
|
273
|
+
f2 = plt.figure()
|
|
274
|
+
plt.title('X residuuals')
|
|
275
|
+
a2 = plt.axes()
|
|
276
|
+
plt.grid()
|
|
277
|
+
f3 = plt.figure()
|
|
278
|
+
plt.title('Z residuuals')
|
|
279
|
+
a3 = plt.axes()
|
|
280
|
+
plt.grid()
|
|
281
|
+
|
|
282
|
+
ym = fids['y'].mean()
|
|
283
|
+
xm = fids['x'].mean()
|
|
284
|
+
zm = fids['z'].mean()
|
|
285
|
+
|
|
286
|
+
# also plot a filtered version to see the trend in the noisy trace
|
|
287
|
+
yfilt = FILTER_FUNCS['Median'](fids['t'],{'y':fids['y']},13)
|
|
288
|
+
xfilt = FILTER_FUNCS['Median'](fids['t'],{'x':fids['x']},13)
|
|
289
|
+
zfilt = FILTER_FUNCS['Median'](fids['t'],{'z':fids['z']},13)
|
|
290
|
+
|
|
291
|
+
a1.plot(fids['t'], fids['y'] - ym)
|
|
292
|
+
a1.plot(fids['t'], yfilt['y'] - ym, '--',
|
|
293
|
+
color='#b0b0b0', alpha=0.7)
|
|
294
|
+
|
|
295
|
+
a2.plot(fids['t'], fids['x'] - xm)
|
|
296
|
+
a2.plot(fids['t'], xfilt['x'] - xm, '--',
|
|
297
|
+
color='#b0b0b0', alpha=0.7)
|
|
298
|
+
|
|
299
|
+
a3.plot(fids['t'], fids['z'] - zm)
|
|
300
|
+
a3.plot(fids['t'], zfilt['z'] - zm, '--',
|
|
301
|
+
color='#b0b0b0', alpha=0.7)
|
|
302
|
+
|
|
303
|
+
# plot the trace derived from the fiducials
|
|
304
|
+
tuq, idx = np.unique(fids['t'], return_index=True)
|
|
305
|
+
fidz = fids['fiducial_z'][idx]
|
|
306
|
+
fidy = fids['fiducial_y'][idx]
|
|
307
|
+
fidx = fids['fiducial_x'][idx]
|
|
308
|
+
plt.figure()
|
|
309
|
+
plt.subplot(311)
|
|
310
|
+
plt.plot(tuq, -fidz, label = 'fiducial z')
|
|
311
|
+
plt.title('Fiducial z')
|
|
312
|
+
plt.subplot(312)
|
|
313
|
+
plt.plot(tuq, -fidx, label = 'fiducial x')
|
|
314
|
+
plt.title('Fiducial x')
|
|
315
|
+
plt.subplot(313)
|
|
316
|
+
plt.plot(tuq, -fidy, label = 'fiducial y')
|
|
317
|
+
plt.title('Fiducial y')
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def fiducialvsdrift(self, event=None):
|
|
321
|
+
from PYMEcs.misc.guiMsgBoxes import Warn
|
|
322
|
+
from scipy.optimize import leastsq
|
|
323
|
+
import PYMEcs.misc.shellutils as su
|
|
324
|
+
|
|
325
|
+
dfunc = lambda p, v: -100.0*p[0]*v[0]-100.0*p[1]*v[1]
|
|
326
|
+
efunc = lambda p, fx, fy, dx, dy: np.append(fx-dfunc(p[:2],[dx,dy]),
|
|
327
|
+
fy-dfunc(p[2:],[dx,dy]))
|
|
328
|
+
zfunc = lambda p, dz: p[0]*dz + p[1]
|
|
329
|
+
ezfunc = lambda p, fz, dz: fz-zfunc(p,dz)
|
|
330
|
+
|
|
331
|
+
pipeline = self.pipeline
|
|
332
|
+
if 'corrected_fiducials' not in pipeline.dataSources:
|
|
333
|
+
Warn(self.visFr,"no 'corrected_fiducials' data source")
|
|
334
|
+
return
|
|
335
|
+
|
|
336
|
+
if 'driftx' not in pipeline.keys():
|
|
337
|
+
Warn(self.visFr,"no 'driftx' property")
|
|
338
|
+
return
|
|
339
|
+
|
|
340
|
+
fids = pipeline.dataSources['corrected_fiducials']
|
|
341
|
+
|
|
342
|
+
tuq, idx = np.unique(fids['t'], return_index=True)
|
|
343
|
+
fidz = fids['fiducial_z'][idx]
|
|
344
|
+
fidy = fids['fiducial_y'][idx]
|
|
345
|
+
fidx = fids['fiducial_x'][idx]
|
|
346
|
+
|
|
347
|
+
# what do we do when these do not exist?
|
|
348
|
+
# answer: we may have to interpolate onto the times from the normal pipeline -> check that approach
|
|
349
|
+
|
|
350
|
+
tup, idxp = np.unique(pipeline['t'], return_index=True)
|
|
351
|
+
dxp = pipeline['driftx'][idxp]
|
|
352
|
+
dyp = pipeline['drifty'][idxp]
|
|
353
|
+
dzp = pipeline['driftz'][idxp]
|
|
354
|
+
|
|
355
|
+
dx = np.interp(tuq, tup, dxp)
|
|
356
|
+
dy = np.interp(tuq, tup, dyp)
|
|
357
|
+
dz = np.interp(tuq, tup, dzp)
|
|
358
|
+
|
|
359
|
+
#dy = fids['drifty'][idx]
|
|
360
|
+
#dx = fids['driftx'][idx]
|
|
361
|
+
|
|
362
|
+
fx = su.zs(fidx)
|
|
363
|
+
fy = su.zs(fidy)
|
|
364
|
+
fz = su.zs(fidz)
|
|
365
|
+
|
|
366
|
+
dxx = su.zs(dx)
|
|
367
|
+
dyy = su.zs(dy)
|
|
368
|
+
p,suc = leastsq(efunc,np.zeros(4),args=(fx,fy,dxx,dyy))
|
|
369
|
+
|
|
370
|
+
pz,sucz = leastsq(ezfunc,[-1e3,0],args=(fz,dz))
|
|
371
|
+
|
|
372
|
+
plt.figure()
|
|
373
|
+
plt.plot(tuq,fx,label='fiducial x')
|
|
374
|
+
plt.plot(tuq,dfunc(p[:2],[dxx,dyy]),label='best fit x drift')
|
|
375
|
+
|
|
376
|
+
plt.plot(tuq,fy,label='fiducial y')
|
|
377
|
+
plt.plot(tuq,dfunc(p[2:],[dxx,dyy]),label='best fit y drift')
|
|
378
|
+
plt.legend()
|
|
379
|
+
plt.xlabel('Time (frames)')
|
|
380
|
+
plt.ylabel('Drift (nm)')
|
|
381
|
+
plt.title("Best fit params (a11 %.2f,a12 %.2f,a21 %.2f,a22 %.2f): " % tuple(p.tolist()))
|
|
382
|
+
|
|
383
|
+
plt.figure()
|
|
384
|
+
plt.plot(tuq,fz,label='fiducial z')
|
|
385
|
+
plt.plot(tuq,zfunc(pz,dz),label='best fit z drift')
|
|
386
|
+
plt.legend()
|
|
387
|
+
plt.xlabel('Time (frames)')
|
|
388
|
+
plt.ylabel('Drift (nm)')
|
|
389
|
+
plt.title("Best fit parameters (zfactor %.2f, zoffs %.2f): " % tuple(pz.tolist()))
|
|
390
|
+
|
|
391
|
+
plt.figure()
|
|
392
|
+
plt.plot(tuq,fx-dfunc(p[:2],[dxx,dyy]),label='x difference')
|
|
393
|
+
plt.plot(tuq,fy-dfunc(p[2:],[dxx,dyy])+50,label='y difference (+50 nm offset)')
|
|
394
|
+
plt.plot(tuq,fz-zfunc(pz,dz)+100,label='z difference (+100 nm offset)')
|
|
395
|
+
plt.legend()
|
|
396
|
+
plt.xlabel('Time (frames)')
|
|
397
|
+
plt.ylabel('Drift (nm)')
|
|
398
|
+
plt.grid()
|
|
399
|
+
|
|
400
|
+
def Plug(visFr):
|
|
401
|
+
"""Plugs this module into the gui"""
|
|
402
|
+
FiducialTracker(visFr)
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import wx
|
|
2
|
+
from wx.lib.dialogs import ScrolledMessageDialog
|
|
3
|
+
|
|
4
|
+
from PYME.localization.remFitBuf import CameraInfoManager
|
|
5
|
+
import PYME.Analysis.gen_sCMOS_maps as gmaps
|
|
6
|
+
from PYME.IO.MetaDataHandler import NestedClassMDHandler
|
|
7
|
+
from PYME.IO.image import ImageStack
|
|
8
|
+
from PYME.DSView import ViewIm3D
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
from PYMEcs.misc.mapUtils import defaultCalibrationDir,defaultMapName,installedCams,install_map,\
|
|
12
|
+
checkAndInstallMap,installMapsFrom,getInstalledMapList,check_mapexists,mk_compositeMap,\
|
|
13
|
+
addMap2composite,export_mapFromComposite,_getDefaultMap,get_dark_default,get_variance_default,\
|
|
14
|
+
get_flatfield_default
|
|
15
|
+
|
|
16
|
+
import logging
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
# FUNCTIONAILITY that would be good to add
|
|
20
|
+
# - check all installed maps for sanity etc
|
|
21
|
+
# - install a single map file (rather than whole directory)
|
|
22
|
+
# - force option for install maps commands
|
|
23
|
+
# generally: better API for map functions than current ones in
|
|
24
|
+
# PYME.Analysis.gen_sCMOS_maps
|
|
25
|
+
# CameraInfoManager in PYME.localization.remFitBuf
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
from traits.api import HasTraits, Str, Int, CStr, List, Enum, Float
|
|
30
|
+
from traitsui.api import View, Item, Group
|
|
31
|
+
from traitsui.menu import OKButton, CancelButton, OKCancelButtons
|
|
32
|
+
|
|
33
|
+
from PYMEcs.misc.guiMsgBoxes import Warn
|
|
34
|
+
|
|
35
|
+
class cameraChoice(HasTraits):
|
|
36
|
+
_clist = List([])
|
|
37
|
+
Camera = Enum(values='_clist')
|
|
38
|
+
|
|
39
|
+
traits_view = View(Group(Item(name = 'Camera'),
|
|
40
|
+
label = 'Select Camera',
|
|
41
|
+
show_border = True),
|
|
42
|
+
buttons = OKCancelButtons)
|
|
43
|
+
|
|
44
|
+
def add_cams(self,camlist):
|
|
45
|
+
for cam in camlist:
|
|
46
|
+
if cam not in self._clist:
|
|
47
|
+
self._clist.append(cam)
|
|
48
|
+
|
|
49
|
+
class meanVarianceCalc(HasTraits):
|
|
50
|
+
Start = Int(0)
|
|
51
|
+
End = Int(-1)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class mapTools:
|
|
55
|
+
"""
|
|
56
|
+
GUI class to supply various map tools
|
|
57
|
+
"""
|
|
58
|
+
def __init__(self, dsviewer):
|
|
59
|
+
self.dsviewer = dsviewer
|
|
60
|
+
self.do = dsviewer.do
|
|
61
|
+
self.image = dsviewer.image
|
|
62
|
+
self.ci = CameraInfoManager()
|
|
63
|
+
self.loadedMaps = {}
|
|
64
|
+
|
|
65
|
+
dsviewer.AddMenuItem('Experimental>Map Tools',
|
|
66
|
+
'Convert current frame to photo-electron counts',
|
|
67
|
+
self.OnPhotonConvert)
|
|
68
|
+
dsviewer.AddMenuItem('Experimental>Map Tools',
|
|
69
|
+
'Calculate Mean and Variance of frame sequence',
|
|
70
|
+
self.OnMeanVariance)
|
|
71
|
+
dsviewer.AddMenuItem('Experimental>Map Tools',
|
|
72
|
+
'Show dark map',
|
|
73
|
+
self.OnShowDark)
|
|
74
|
+
dsviewer.AddMenuItem('Experimental>Map Tools',
|
|
75
|
+
'Show variance map',
|
|
76
|
+
self.OnShowVariance)
|
|
77
|
+
dsviewer.AddMenuItem('Experimental>Map Tools',
|
|
78
|
+
'Show flatfield map',
|
|
79
|
+
self.OnShowFlatField)
|
|
80
|
+
dsviewer.AddMenuItem('Experimental>Map Tools',
|
|
81
|
+
'List installed maps',
|
|
82
|
+
self.OnListMaps)
|
|
83
|
+
dsviewer.AddMenuItem('Experimental>Map Tools',
|
|
84
|
+
'Install maps to system calibration directory',
|
|
85
|
+
self.OnInstallMapsToSystem)
|
|
86
|
+
dsviewer.AddMenuItem('Experimental>Map Tools',
|
|
87
|
+
'Copy maps from system to user directory',
|
|
88
|
+
self.OnCopyMapsToUserDir)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def getMapSafely(self, type='dark'):
|
|
92
|
+
try:
|
|
93
|
+
mdh = self.dsviewer.LMAnalyser.analysisController.analysisMDH
|
|
94
|
+
except AttributeError:
|
|
95
|
+
mdh = self.image.mdh
|
|
96
|
+
try:
|
|
97
|
+
theMap = self.ci.getDarkMap(mdh)
|
|
98
|
+
self.loadedMaps[type] = mdh
|
|
99
|
+
except IOError:
|
|
100
|
+
logger.exception('Dark map specified but not found, falling back on defaults')
|
|
101
|
+
(theMap,mdh2) = _getDefaultMap(self.ci,mdh,type,return_loadedmdh=True)
|
|
102
|
+
self.loadedMaps[type] = mdh2
|
|
103
|
+
return theMap
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def showMap(self, type='dark'):
|
|
107
|
+
mdh2 = NestedClassMDHandler(self.image.mdh)
|
|
108
|
+
# # overwrite the map location with default maps if exist
|
|
109
|
+
# if check_mapexists(mdh2,type=type) is None:
|
|
110
|
+
# Warn(None,'no suitable map in default location')
|
|
111
|
+
# return
|
|
112
|
+
|
|
113
|
+
check_mapexists(mdh2,type=type)
|
|
114
|
+
|
|
115
|
+
theMap = self.getMapSafely(type)
|
|
116
|
+
twoDMap = np.ones(self.image.data.shape[0:2])*theMap # promote to 2D if necessary
|
|
117
|
+
|
|
118
|
+
im = ImageStack(twoDMap, titleStub = '%s Map' % type.capitalize())
|
|
119
|
+
im.mdh.copyEntriesFrom(mdh2)
|
|
120
|
+
|
|
121
|
+
if self.dsviewer.mode == 'visGUI':
|
|
122
|
+
mode = 'visGUI'
|
|
123
|
+
else:
|
|
124
|
+
mode = 'lite'
|
|
125
|
+
|
|
126
|
+
dv = ViewIm3D(im, mode=mode, glCanvas=self.dsviewer.glCanvas, parent=wx.GetTopLevelParent(self.dsviewer))
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def OnShowDark(self, event=None):
|
|
130
|
+
self.showMap(type='dark')
|
|
131
|
+
|
|
132
|
+
def OnShowVariance(self, event=None):
|
|
133
|
+
self.showMap(type='variance')
|
|
134
|
+
|
|
135
|
+
def OnShowFlatField(self, event=None):
|
|
136
|
+
self.showMap(type='flatfield')
|
|
137
|
+
|
|
138
|
+
def OnMeanVariance(self, event=None):
|
|
139
|
+
mvChoice = meanVarianceCalc(End=self.image.data.shape[2]-1)
|
|
140
|
+
if not mvChoice.configure_traits(kind='modal'):
|
|
141
|
+
return
|
|
142
|
+
|
|
143
|
+
m, v = gmaps._meanvards(self.image.data,start=mvChoice.Start,end=mvChoice.End)
|
|
144
|
+
mmdh = NestedClassMDHandler(self.image.mdh)
|
|
145
|
+
mmdh.setEntry('Analysis.name', 'mean-variance')
|
|
146
|
+
mmdh.setEntry('Analysis.start', mvChoice.Start)
|
|
147
|
+
mmdh.setEntry('Analysis.end', mvChoice.End)
|
|
148
|
+
mmdh.setEntry('Analysis.resultname', 'mean')
|
|
149
|
+
mmdh.setEntry('Analysis.units', 'ADU')
|
|
150
|
+
|
|
151
|
+
imm = ImageStack(m, mdh=mmdh, titleStub = 'Mean')
|
|
152
|
+
|
|
153
|
+
vmdh = NestedClassMDHandler(mmdh)
|
|
154
|
+
vmdh.setEntry('Analysis.resultname', 'variance')
|
|
155
|
+
vmdh.setEntry('Analysis.units', 'ADU^2')
|
|
156
|
+
|
|
157
|
+
imv = ImageStack(v, mdh=vmdh, titleStub = 'Variance')
|
|
158
|
+
|
|
159
|
+
if self.dsviewer.mode == 'visGUI':
|
|
160
|
+
mode = 'visGUI'
|
|
161
|
+
else:
|
|
162
|
+
mode = 'lite'
|
|
163
|
+
|
|
164
|
+
dv = ViewIm3D(imm, mode=mode, glCanvas=self.dsviewer.glCanvas,
|
|
165
|
+
parent=wx.GetTopLevelParent(self.dsviewer))
|
|
166
|
+
dv = ViewIm3D(imv, mode=mode, glCanvas=self.dsviewer.glCanvas,
|
|
167
|
+
parent=wx.GetTopLevelParent(self.dsviewer))
|
|
168
|
+
|
|
169
|
+
def OnPhotonConvert(self, event=None):
|
|
170
|
+
|
|
171
|
+
# we try color channel 0; should only be done on monochrome anyway
|
|
172
|
+
curFrame = self.image.data[:,:, self.do.zp, 0].squeeze()
|
|
173
|
+
|
|
174
|
+
# this makes a new metadata structure that copies all entries from the argument
|
|
175
|
+
mdh2 = NestedClassMDHandler(self.image.mdh)
|
|
176
|
+
# some old files do not have a camera serialname
|
|
177
|
+
# fake one, which ensures no map is found and we get uniform maps
|
|
178
|
+
try:
|
|
179
|
+
t = mdh2['Camera.SerialNumber']
|
|
180
|
+
except AttributeError:
|
|
181
|
+
mdh2['Camera.SerialNumber'] = 'XXXXX'
|
|
182
|
+
|
|
183
|
+
# overwrite the map location with default maps if exist
|
|
184
|
+
check_mapexists(mdh2,type='dark')
|
|
185
|
+
check_mapexists(mdh2,type='flatfield')
|
|
186
|
+
|
|
187
|
+
#darkf = self.ci.getDarkMap(mdh2)
|
|
188
|
+
darkf = self.getMapSafely(type='dark')
|
|
189
|
+
corrFrame = float(mdh2['Camera.ElectronsPerCount'])*self.ci.correctImage(mdh2, curFrame)/mdh2.getEntry('Camera.TrueEMGain')
|
|
190
|
+
|
|
191
|
+
im = ImageStack(corrFrame, titleStub = 'Frame %d in photoelectron units' % self.do.zp)
|
|
192
|
+
im.mdh.copyEntriesFrom(mdh2)
|
|
193
|
+
im.mdh['Parent'] = self.image.filename
|
|
194
|
+
im.mdh['Units'] = 'PhotoElectrons'
|
|
195
|
+
im.mdh['Camera.ElectronsPerCount'] = 1.0
|
|
196
|
+
im.mdh['Camera.TrueEMGain'] = 1.0
|
|
197
|
+
im.mdh['Camera.ADOffset'] = 0
|
|
198
|
+
|
|
199
|
+
if self.dsviewer.mode == 'visGUI':
|
|
200
|
+
mode = 'visGUI'
|
|
201
|
+
else:
|
|
202
|
+
mode = 'lite'
|
|
203
|
+
|
|
204
|
+
dv = ViewIm3D(im, mode=mode, glCanvas=self.dsviewer.glCanvas, parent=wx.GetTopLevelParent(self.dsviewer))
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def OnListMaps(self, event=None):
|
|
208
|
+
|
|
209
|
+
maps = getInstalledMapList()
|
|
210
|
+
if len(maps) > 0:
|
|
211
|
+
dlg = ScrolledMessageDialog(self.dsviewer, "\n".join(maps), "Installed maps", size=(900,400),
|
|
212
|
+
style=wx.RESIZE_BORDER | wx.DEFAULT_DIALOG_STYLE )
|
|
213
|
+
dlg.ShowModal()
|
|
214
|
+
dlg.Destroy()
|
|
215
|
+
else:
|
|
216
|
+
Warn(None,'no suitable maps found')
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def OnInstallMapsToSystem(self, event=None):
|
|
220
|
+
instmsg = 'Install maps from user directory...'
|
|
221
|
+
fdialog = wx.DirDialog(None, instmsg,
|
|
222
|
+
style=wx.DD_DEFAULT_STYLE|wx.DD_DIR_MUST_EXIST|wx.DD_CHANGE_DIR)
|
|
223
|
+
|
|
224
|
+
if fdialog.ShowModal() == wx.ID_OK:
|
|
225
|
+
dirSelection = fdialog.GetPath().encode()
|
|
226
|
+
fdialog.Destroy()
|
|
227
|
+
else:
|
|
228
|
+
fdialog.Destroy()
|
|
229
|
+
return
|
|
230
|
+
|
|
231
|
+
inst, msg = installMapsFrom(dirSelection, calibrationDir=defaultCalibrationDir)
|
|
232
|
+
|
|
233
|
+
dlg = ScrolledMessageDialog(self.dsviewer, msg, instmsg, size=(900,400),
|
|
234
|
+
style=wx.RESIZE_BORDER | wx.DEFAULT_DIALOG_STYLE )
|
|
235
|
+
dlg.ShowModal()
|
|
236
|
+
dlg.Destroy()
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def OnCopyMapsToUserDir(self, event=None):
|
|
240
|
+
import os
|
|
241
|
+
instmsg = 'Copy maps to user directory...'
|
|
242
|
+
cdict = {os.path.basename(camdir) : camdir for camdir in installedCams()}
|
|
243
|
+
cdict['All Cameras'] = defaultCalibrationDir
|
|
244
|
+
|
|
245
|
+
cChoice = cameraChoice()
|
|
246
|
+
cChoice.add_cams(sorted(cdict.keys()))
|
|
247
|
+
if not cChoice.configure_traits(kind='modal'):
|
|
248
|
+
return
|
|
249
|
+
camdir = cdict[cChoice.Camera]
|
|
250
|
+
|
|
251
|
+
fdialog = wx.DirDialog(None, instmsg,
|
|
252
|
+
style=wx.DD_DEFAULT_STYLE|wx.DD_DIR_MUST_EXIST|wx.DD_CHANGE_DIR)
|
|
253
|
+
|
|
254
|
+
if fdialog.ShowModal() == wx.ID_OK:
|
|
255
|
+
dirSelection = fdialog.GetPath().encode()
|
|
256
|
+
fdialog.Destroy()
|
|
257
|
+
else:
|
|
258
|
+
fdialog.Destroy()
|
|
259
|
+
return
|
|
260
|
+
|
|
261
|
+
inst, msg = installMapsFrom(camdir, calibrationDir=dirSelection)
|
|
262
|
+
|
|
263
|
+
dlg = ScrolledMessageDialog(self.dsviewer, msg, instmsg, size=(900,400),
|
|
264
|
+
style=wx.RESIZE_BORDER | wx.DEFAULT_DIALOG_STYLE )
|
|
265
|
+
dlg.ShowModal()
|
|
266
|
+
dlg.Destroy()
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def Plug(dsviewer):
|
|
271
|
+
dsviewer.mapTool = mapTools(dsviewer)
|