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,903 @@
1
+ import math
2
+ import time
3
+
4
+ import numba as nb
5
+ import numpy as np
6
+ from numba import cuda
7
+ from scipy import ndimage
8
+
9
+ from microEye.analysis.fitting.pyfit3Dcspline import CPU
10
+ from microEye.analysis.fitting.pyfit3Dcspline.constants import *
11
+
12
+ if cuda.is_available():
13
+ from microEye.analysis.fitting.pyfit3Dcspline import GPU
14
+
15
+ def GPUmleFit_LM(
16
+ data: np.ndarray,
17
+ fittype: int,
18
+ PSFparam: np.ndarray,
19
+ varim: np.ndarray,
20
+ initZ: float,
21
+ iterations: int = 30,
22
+ ):
23
+ '''
24
+ GPU Fit
25
+
26
+ Parameters
27
+ ----------
28
+ data : np.ndarray
29
+ image stack in shape (roi_index, roi_size)
30
+ fittype : int
31
+ fitting mode:
32
+
33
+ 1. fix PSF.
34
+ 2. free PSF.
35
+ 3. Gauss fit z. (SMAP developers suppressed this)
36
+ 4. fit PSFx, PSFy elliptical.
37
+ 5. cspline.
38
+
39
+ PSFparam : np.ndarray
40
+ paramters for fitters:
41
+
42
+ 1. fix PSF: PSFxy sigma.
43
+ 2. free PSF: start PSFxy.
44
+ 3. Gauss fit z parameters:
45
+ PSFx, Ax, Ay, Bx, By, gamma, d, PSFy.
46
+
47
+ 4. fit PSFx, PSFy elliptical: start PSFx, PSFy.
48
+ 5. cspline: cspline coefficients.
49
+ varim : np.ndarray
50
+ Variance map for CMOS, if None then EMCCD, default is None.
51
+ initZ : float
52
+ z start parameter.
53
+ unit: distance of stack calibration, center-based.
54
+ iterations : int
55
+ number of fit iterations (if None default=30)
56
+
57
+ Returns
58
+ -------
59
+ Parameters : np.ndarray
60
+ fitting results in shape (roi_index, column) for each fit mode:
61
+
62
+ 1. x, y, I, bg, iteration.
63
+ 2. x, y, I, bg, sigma, iteration.
64
+ 3. ???
65
+ 4. x, y, I, bg, sigmax, sigmay, iteration.
66
+ 5. x, y, I, bg, z, iteration.
67
+ CRLBs : np.ndarray
68
+ Cramer-Rao Lower Bounds for fitting results
69
+ in shape (roi_index, column).
70
+ LogLikelihood : np.ndarray
71
+ Log Likelihood in shape (roi_index).
72
+ '''
73
+ blockx = 0
74
+ threadx = 0
75
+ PSFSigma = 1
76
+ startParameters = 0
77
+ d_data = None
78
+ Ndim = Nfitraw = sz = cameratype = 0 # default cameratype 0 EMCCD
79
+ noParameters = 0
80
+
81
+ # CMOS
82
+ d_varim = None
83
+
84
+ # Spline
85
+ spline_xsize = spline_ysize = spline_zsize = 0
86
+ coeff = d_coeff = 0
87
+ # d_Parameters = d_CRLBs = d_LogLikelihood = 0
88
+ BlockSize = BSZ # for no shared scenario, we don't care!
89
+
90
+ # fun with timing
91
+ freq = 0
92
+ togpu = 0
93
+ fit = 0
94
+ fromgpu = 0
95
+ cleanup = 0
96
+ start = stop = 0
97
+ start = time.perf_counter_ns()
98
+ # QueryPerformanceFrequency(&freq)
99
+ # QueryPerformanceCounter(&start)
100
+
101
+ # input checks
102
+ sz = math.sqrt(data.shape[1])
103
+ Nfitraw = data.shape[0]
104
+
105
+ # if fittype == 1: # fixed sigma
106
+ # pass
107
+ # elif fittype == 2: # free sigma
108
+ # pass
109
+ if fittype == 4: # fixed sigmax and sigmay
110
+ PSFSigma = float(PSFparam[0])
111
+ elif fittype == 5: # spline fit
112
+ coeff = PSFparam.flatten()
113
+ spline_xsize = PSFparam.shape[1]
114
+ spline_ysize = PSFparam.shape[2]
115
+ spline_zsize = PSFparam.shape[3]
116
+
117
+ # EMCCD = 0, sCMOS = 1
118
+ cameratype = 0 if varim is None else 1
119
+
120
+ # query GPUs
121
+ assert cuda.is_available(), 'No GPU is available.'
122
+ deviceCount = len(cuda.gpus)
123
+
124
+ # check if we are allocating more memory than the card has
125
+ availableMemory = cuda.current_context().get_memory_info()[0]
126
+ requiredMemory = 0
127
+ float_size = 4 # in bytes
128
+
129
+ if fittype == 1: # fixed sigma
130
+ requiredMemory += (2 * NV_P + 2) * Nfitraw * float_size
131
+ elif fittype == 2: # free sigma
132
+ requiredMemory += (2 * NV_PS + 2) * Nfitraw * float_size
133
+ elif fittype == 4: # fixed sigmax and sigmay
134
+ requiredMemory += (2 * NV_PS2 + 2) * Nfitraw * float_size
135
+ elif fittype == 5: # spline fit
136
+ requiredMemory += (2 * NV_PS + 2) * Nfitraw * float_size
137
+ requiredMemory += (
138
+ spline_xsize * spline_ysize * spline_zsize * 64 * float_size
139
+ )
140
+
141
+ if cameratype == 0: # EMCCD
142
+ requiredMemory += sz * sz * Nfitraw * float_size
143
+ elif cameratype == 1: # sCMOS
144
+ requiredMemory += 2 * sz * sz * Nfitraw * float_size
145
+
146
+ assert requiredMemory < 0.9 * availableMemory, (
147
+ f'Trying to allocation {requiredMemory / (1024 * 1024):.3f}MB.',
148
+ f'GPU only has {availableMemory / (1024 * 1024):.0f}MB.\n'
149
+ + 'Please break your fitting into multiple smaller runs.\n',
150
+ )
151
+ print(
152
+ f'Allocating {100 * requiredMemory / availableMemory:.3e}% out of',
153
+ f'available GPU memory {availableMemory / (1024 * 1024):.0f}MB.',
154
+ )
155
+
156
+ # copy data to device
157
+ d_data = cuda.to_device(data.flatten().astype(np.float32))
158
+
159
+ # CMOS
160
+ if cameratype == 1:
161
+ d_varim = cuda.to_device(varim.flatten().astype(np.float32))
162
+
163
+ if fittype == 5:
164
+ d_coeff = cuda.to_device(coeff.flatten().astype(np.float32))
165
+
166
+ # create output for parameters and CRLBs
167
+ if fittype == 1: # (x,y,bg,I)
168
+ d_Parameters = cuda.to_device(np.zeros((NV_P + 1) * Nfitraw, np.float32))
169
+ d_CRLBs = cuda.to_device(np.zeros(NV_P * Nfitraw, np.float32))
170
+ elif fittype == 2: # (x,y,bg,I,Sigma)
171
+ d_Parameters = cuda.to_device(np.zeros((NV_PS + 1) * Nfitraw, np.float32))
172
+ d_CRLBs = cuda.to_device(np.zeros(NV_PS * Nfitraw, np.float32))
173
+ elif fittype == 4: # (x,y,bg,I,Sx,Sy)
174
+ d_Parameters = cuda.to_device(np.zeros((NV_PS2 + 1) * Nfitraw, np.float32))
175
+ d_CRLBs = cuda.to_device(np.zeros(NV_PS2 * Nfitraw, np.float32))
176
+ elif fittype == 5: # (x,y,bg,I,z)
177
+ d_Parameters = cuda.to_device(np.zeros((NV_PS + 1) * Nfitraw, np.float32))
178
+ d_CRLBs = cuda.to_device(np.zeros(NV_PS * Nfitraw, np.float32))
179
+
180
+ d_LogLikelihood = cuda.to_device(np.zeros(Nfitraw, np.float32))
181
+
182
+ # print(
183
+ # d_data.nbytes +
184
+ # (d_varim.nbytes if d_varim is not None else 0) +
185
+ # (d_coeff.nbytes if fittype == 5 else 0) +
186
+ # d_Parameters.nbytes +
187
+ # d_CRLBs.nbytes +
188
+ # d_LogLikelihood.nbytes,
189
+ # requiredMemory
190
+ # )
191
+
192
+ stop = time.perf_counter_ns()
193
+ togpu = stop - start
194
+ print(f'Data copied to GPU in {togpu/1e9:.6f}s.\n')
195
+ start = time.perf_counter_ns()
196
+
197
+ # setup kernel
198
+ blockx = math.ceil(Nfitraw / BlockSize)
199
+ threadx = BlockSize
200
+
201
+ if fittype == 1: # fit x,y,bg,I
202
+ if cameratype == 0:
203
+ GPU.kernel_MLEFit_LM_EMCCD[blockx, threadx](
204
+ d_data,
205
+ PSFSigma,
206
+ int(sz),
207
+ iterations,
208
+ d_Parameters,
209
+ d_CRLBs,
210
+ d_LogLikelihood,
211
+ Nfitraw,
212
+ )
213
+ elif cameratype == 1:
214
+ GPU.kernel_MLEFit_LM_sCMOS[blockx, threadx](
215
+ d_data,
216
+ PSFSigma,
217
+ int(sz),
218
+ iterations,
219
+ d_Parameters,
220
+ d_CRLBs,
221
+ d_LogLikelihood,
222
+ int(Nfitraw),
223
+ d_varim,
224
+ )
225
+ elif fittype == 2: # fit x,y,bg,I,sigma
226
+ if cameratype == 0:
227
+ GPU.kernel_MLEFit_LM_Sigma_EMCCD[blockx, threadx](
228
+ d_data,
229
+ PSFSigma,
230
+ int(sz),
231
+ iterations,
232
+ d_Parameters,
233
+ d_CRLBs,
234
+ d_LogLikelihood,
235
+ int(Nfitraw),
236
+ )
237
+ elif cameratype == 1:
238
+ GPU.kernel_MLEFit_LM_Sigma_sCMOS[blockx, threadx](
239
+ d_data,
240
+ PSFSigma,
241
+ int(sz),
242
+ iterations,
243
+ d_Parameters,
244
+ d_CRLBs,
245
+ d_LogLikelihood,
246
+ int(Nfitraw),
247
+ d_varim,
248
+ )
249
+ elif fittype == 4: # fit x,y,bg,I,sigmax,sigmay
250
+ if cameratype == 0:
251
+ GPU.kernel_MLEFit_LM_sigmaxy_EMCCD[blockx, threadx](
252
+ d_data,
253
+ PSFSigma,
254
+ int(sz),
255
+ iterations,
256
+ d_Parameters,
257
+ d_CRLBs,
258
+ d_LogLikelihood,
259
+ int(Nfitraw),
260
+ )
261
+ elif cameratype == 1:
262
+ GPU.kernel_MLEFit_LM_sigmaxy_sCMOS[blockx, threadx](
263
+ d_data,
264
+ PSFSigma,
265
+ int(sz),
266
+ iterations,
267
+ d_Parameters,
268
+ d_CRLBs,
269
+ d_LogLikelihood,
270
+ int(Nfitraw),
271
+ d_varim,
272
+ )
273
+ elif fittype == 5: # fit x,y,bg,I,z
274
+ if initZ < 0:
275
+ initZ = spline_zsize / 2.0
276
+
277
+ if cameratype == 0:
278
+ GPU.kernel_splineMLEFit_z_EMCCD[blockx, threadx](
279
+ d_data,
280
+ d_coeff,
281
+ spline_xsize,
282
+ spline_ysize,
283
+ spline_zsize,
284
+ int(sz),
285
+ iterations,
286
+ d_Parameters,
287
+ d_CRLBs,
288
+ d_LogLikelihood,
289
+ initZ,
290
+ int(Nfitraw),
291
+ )
292
+ elif cameratype == 1:
293
+ GPU.kernel_splineMLEFit_z_sCMOS[blockx, threadx](
294
+ d_data,
295
+ d_coeff,
296
+ spline_xsize,
297
+ spline_ysize,
298
+ spline_zsize,
299
+ int(sz),
300
+ iterations,
301
+ d_Parameters,
302
+ d_CRLBs,
303
+ d_LogLikelihood,
304
+ initZ,
305
+ int(Nfitraw),
306
+ d_varim,
307
+ )
308
+
309
+ cuda.synchronize()
310
+
311
+ stop = time.perf_counter_ns()
312
+ fit = stop - start
313
+ print(f'Fitted {Nfitraw:d} localizations in {fit/1e9:6f}s.\n')
314
+ start = time.perf_counter_ns()
315
+
316
+ # copy to matlab output
317
+ if fittype == 1: # (x,y,bg,I)
318
+ Parameters = d_Parameters.copy_to_host()
319
+ CRLBs = d_CRLBs.copy_to_host()
320
+ elif fittype == 2: # (x,y,bg,I,Sigma)
321
+ Parameters = d_Parameters.copy_to_host()
322
+ CRLBs = d_CRLBs.copy_to_host()
323
+ elif fittype == 4: # (x,y,bg,I,Sx,Sy)
324
+ Parameters = d_Parameters.copy_to_host()
325
+ CRLBs = d_CRLBs.copy_to_host()
326
+ elif fittype == 5: # (x,y,bg,I,z)
327
+ Parameters = d_Parameters.copy_to_host()
328
+ CRLBs = d_CRLBs.copy_to_host()
329
+
330
+ LogLikelihood = d_LogLikelihood.copy_to_host()
331
+
332
+ stop = time.perf_counter_ns()
333
+ fromgpu = stop - start
334
+ print(f'Data copied to Host in {fromgpu/1e9:.6f}s.\n')
335
+ start = time.perf_counter_ns()
336
+
337
+ # cleanup
338
+ # cuda.current_context().reset()
339
+
340
+ # cuda.close()
341
+
342
+ stop = time.perf_counter_ns()
343
+
344
+ # reshape output for parameters and CRLBs
345
+ if fittype == 1: # (x,y,bg,I)
346
+ Parameters = Parameters.reshape((-1, (NV_P + 1)))
347
+ CRLBs = CRLBs.reshape((-1, NV_P))
348
+ elif fittype == 2: # (x,y,bg,I,Sigma)
349
+ Parameters = Parameters.reshape((-1, (NV_PS + 1)))
350
+ CRLBs = CRLBs.reshape((-1, NV_PS))
351
+ elif fittype == 4: # (x,y,bg,I,Sx,Sy)
352
+ Parameters = Parameters.reshape((-1, (NV_PS2 + 1)))
353
+ CRLBs = CRLBs.reshape((-1, NV_PS2))
354
+ elif fittype == 5: # (x,y,bg,I,z)
355
+ Parameters = Parameters.reshape((-1, (NV_PS + 1)))
356
+ CRLBs = CRLBs.reshape((-1, NV_PS))
357
+
358
+ return Parameters, CRLBs, LogLikelihood
359
+
360
+
361
+ def CPUmleFit_LM(
362
+ data: np.ndarray,
363
+ fittype: int,
364
+ PSFparam: np.ndarray,
365
+ varim: np.ndarray,
366
+ initZ: float,
367
+ iterations: int = 60,
368
+ ):
369
+ '''
370
+ CPU Fit
371
+
372
+ Parameters
373
+ ----------
374
+ data : np.ndarray
375
+ image stack in shape (roi_index, roi_size)
376
+ fittype : int
377
+ fitting mode:
378
+
379
+ 1. fix PSF.
380
+ 2. free PSF.
381
+ 3. Gauss fit z. (SMAP developers suppressed this)
382
+ 4. fit PSFx, PSFy elliptical.
383
+ 5. cspline.
384
+
385
+ PSFparam : np.ndarray
386
+ paramters for fitters:
387
+
388
+ 1. fix PSF: PSFxy sigma.
389
+ 2. free PSF: start PSFxy.
390
+ 3. Gauss fit z: parameters: PSFx, Ax, Ay, Bx, By, gamma, d, PSFy.
391
+ 4. fit PSFx, PSFy elliptical: start PSFx, PSFy.
392
+ 5. cspline: cspline coefficients.
393
+ varim : np.ndarray
394
+ Variance map for CMOS, if None then EMCCD, default is None.
395
+ initZ : float
396
+ z start parameter. unit: distance of stack calibration, center based.
397
+ iterations : int
398
+ number of fit iterations (default=30)
399
+
400
+ Returns
401
+ -------
402
+ Parameters : np.ndarray
403
+ fitting results in shape (roi_index, column) for each fit mode:
404
+
405
+ 1. x, y, I, bg, iteration.
406
+ 2. x, y, I, bg, sigma, iteration.
407
+ 3. ???
408
+ 4. x, y, I, bg, sigmax, sigmay, iteration.
409
+ 5. x, y, I, bg, z, iteration.
410
+ CRLBs : np.ndarray
411
+ Cramer-Rao Lower Bounds for fitting results
412
+ in shape (roi_index, column).
413
+ LogLikelihood : np.ndarray
414
+ Log Likelihood in shape (roi_index).
415
+ '''
416
+ PSFSigma = 1
417
+ cameratype = 0 # default cameratype 0 EMCCD
418
+ noParameters = 0
419
+
420
+ # Spline
421
+ spline_xsize = spline_ysize = spline_zsize = 0
422
+ coeff = 0
423
+
424
+ # fun with timing
425
+ freq = 0
426
+ togpu = 0
427
+ fit = 0
428
+ fromgpu = 0
429
+ cleanup = 0
430
+ start = stop = 0
431
+ start = time.perf_counter_ns()
432
+ # QueryPerformanceFrequency(&freq)
433
+ # QueryPerformanceCounter(&start)
434
+
435
+ # input checks
436
+ sz = math.sqrt(data.shape[1])
437
+ Nfitraw = data.shape[0]
438
+
439
+ if fittype == 1: # fixed sigma
440
+ PSFSigma = float(PSFparam[0])
441
+ elif fittype == 2: # free sigma
442
+ PSFSigma = float(PSFparam[0])
443
+ elif fittype == 4: # fixed sigmax and sigmay
444
+ PSFSigma = float(PSFparam[0])
445
+ elif fittype == 5: # spline fit
446
+ coeff = PSFparam.flatten()
447
+ spline_xsize = PSFparam.shape[1]
448
+ spline_ysize = PSFparam.shape[2]
449
+ spline_zsize = PSFparam.shape[3]
450
+
451
+ # EMCCD = 0, sCMOS = 1
452
+ cameratype = 0 if varim is None else 1
453
+
454
+ # create output for parameters and CRLBs
455
+ if fittype == 1: # (x,y,bg,I)
456
+ Parameters = np.zeros((Nfitraw, (NV_P + 1)), np.float32)
457
+ CRLBs = np.zeros((Nfitraw, NV_P), np.float32)
458
+ elif fittype == 2: # (x,y,bg,I,Sigma)
459
+ Parameters = np.zeros((Nfitraw, (NV_PS + 1)), np.float32)
460
+ CRLBs = np.zeros((Nfitraw, NV_PS), np.float32)
461
+ elif fittype == 4: # (x,y,bg,I,Sx,Sy)
462
+ Parameters = np.zeros((Nfitraw, (NV_PS2 + 1)), np.float32)
463
+ CRLBs = np.zeros((Nfitraw, NV_PS2), np.float32)
464
+ elif fittype == 5: # (x,y,bg,I,z)
465
+ Parameters = np.zeros((Nfitraw, (NV_PS + 1)), np.float32)
466
+ CRLBs = np.zeros((Nfitraw, NV_PS), np.float32)
467
+
468
+ LogLikelihood = np.zeros(Nfitraw, np.float32)
469
+
470
+ stop = time.perf_counter_ns()
471
+ togpu = stop - start
472
+ start = time.perf_counter_ns()
473
+
474
+ # if fittype == 1: # fit x,y,bg,I
475
+ # for ii in range(Nfitraw):
476
+ # Parameters[ii, :], CRLBs[ii, :], LogLikelihood[ii] = \
477
+ # CPU.kernel_MLEFit_LM(
478
+ # data[ii, :], PSFSigma, int(sz), iterations,
479
+ # varim if varim is None else varim[ii, :])
480
+ # elif fittype == 2: # fit x,y,bg,I,sigma
481
+ # for ii in range(Nfitraw):
482
+ # Parameters[ii, :], CRLBs[ii, :], LogLikelihood[ii] = \
483
+ # CPU.kernel_MLEFit_LM_Sigma(
484
+ # data[ii, :], PSFSigma, int(sz), iterations,
485
+ # varim if varim is None else varim[ii, :])
486
+ # elif fittype == 4: # fit x,y,bg,I,sigmax,sigmay
487
+ # for ii in range(Nfitraw):
488
+ # Parameters[ii, :], CRLBs[ii, :], LogLikelihood[ii] = \
489
+ # CPU.kernel_MLEFit_LM_sigmaxy(
490
+ # data[ii, :], PSFSigma, int(sz), iterations,
491
+ # varim if varim is None else varim[ii, :])
492
+ if fittype == 5: # fit x,y,bg,I,z
493
+ if initZ < 0:
494
+ initZ = spline_zsize / 2.0
495
+
496
+ CPU_parallel_fit_3D_scpline(
497
+ data,
498
+ varim,
499
+ coeff,
500
+ spline_xsize,
501
+ spline_ysize,
502
+ spline_zsize,
503
+ sz,
504
+ Nfitraw,
505
+ initZ,
506
+ iterations,
507
+ Parameters,
508
+ CRLBs,
509
+ LogLikelihood,
510
+ )
511
+ else:
512
+ CPU_parallel_fit_2D(
513
+ data,
514
+ fittype,
515
+ PSFSigma,
516
+ varim,
517
+ sz,
518
+ Nfitraw,
519
+ initZ,
520
+ iterations,
521
+ Parameters,
522
+ CRLBs,
523
+ LogLikelihood,
524
+ )
525
+
526
+ stop = time.perf_counter_ns()
527
+ fit = stop - start
528
+ start = time.perf_counter_ns()
529
+
530
+ stop = time.perf_counter_ns()
531
+ fromgpu = stop - start
532
+ start = time.perf_counter_ns()
533
+
534
+ # cleanup
535
+ stop = time.perf_counter_ns()
536
+
537
+ return Parameters, CRLBs, LogLikelihood
538
+
539
+
540
+ def init_numba_CPU():
541
+ n = 21
542
+ sigma = 4
543
+ x = np.arange(n, dtype=np.float32)
544
+ y = 100 * np.exp(-((x - n / 2) ** 2) / (2 * sigma**2))
545
+ y = np.tile(y, n).reshape((n, n))
546
+ z = (y * y.T).flatten().astype(np.float32)
547
+ z = z[np.newaxis, ...]
548
+
549
+ varim = np.ones(z.shape, dtype=np.float32)
550
+ LogLikelihood = np.zeros((1, 1), dtype=np.float32)
551
+ # varim=None
552
+ Parameters = np.zeros((1, (NV_P + 1)), np.float32)
553
+ CRLBs = np.zeros((1, NV_P), np.float32)
554
+ CPU_parallel_fit_2D(z, 1, 1.5, None, n, 1, 0, 1, Parameters, CRLBs, LogLikelihood)
555
+ Parameters = np.zeros((1, (NV_PS + 1)), np.float32)
556
+ CRLBs = np.zeros((1, NV_PS), np.float32)
557
+ CPU_parallel_fit_2D(z, 2, 1.5, None, n, 1, 0, 1, Parameters, CRLBs, LogLikelihood)
558
+ Parameters = np.zeros((1, (NV_PS2 + 1)), np.float32)
559
+ CRLBs = np.zeros((1, NV_PS2), np.float32)
560
+ CPU_parallel_fit_2D(z, 4, 1.5, None, n, 1, 0, 1, Parameters, CRLBs, LogLikelihood)
561
+ Parameters = np.zeros((1, (NV_PS + 1)), np.float32)
562
+ CRLBs = np.zeros((1, NV_PS), np.float32)
563
+ CPU_parallel_fit_3D_scpline(
564
+ z,
565
+ varim,
566
+ np.ones((64, 4, 4, 4), dtype=np.float32).flatten(),
567
+ 4,
568
+ 4,
569
+ 4,
570
+ int(n),
571
+ 1,
572
+ 0,
573
+ 30,
574
+ Parameters,
575
+ CRLBs,
576
+ LogLikelihood,
577
+ )
578
+ # varim not None
579
+ Parameters = np.zeros((1, (NV_P + 1)), np.float32)
580
+ CRLBs = np.zeros((1, NV_P), np.float32)
581
+ CPU_parallel_fit_2D(z, 1, 1.5, varim, n, 1, 0, 1, Parameters, CRLBs, LogLikelihood)
582
+ Parameters = np.zeros((1, (NV_PS + 1)), np.float32)
583
+ CRLBs = np.zeros((1, NV_PS), np.float32)
584
+ CPU_parallel_fit_2D(z, 2, 1.5, varim, n, 1, 0, 1, Parameters, CRLBs, LogLikelihood)
585
+ Parameters = np.zeros((1, (NV_PS2 + 1)), np.float32)
586
+ CRLBs = np.zeros((1, NV_PS2), np.float32)
587
+ CPU_parallel_fit_2D(z, 4, 1.5, varim, n, 1, 0, 1, Parameters, CRLBs, LogLikelihood)
588
+ Parameters = np.zeros((1, (NV_PS + 1)), np.float32)
589
+ CRLBs = np.zeros((1, NV_PS), np.float32)
590
+ CPU_parallel_fit_3D_scpline(
591
+ z,
592
+ varim,
593
+ np.ones((64, 4, 4, 4), dtype=np.float32).flatten(),
594
+ 4,
595
+ 4,
596
+ 4,
597
+ int(n),
598
+ 1,
599
+ 0,
600
+ 30,
601
+ Parameters,
602
+ CRLBs,
603
+ LogLikelihood,
604
+ )
605
+
606
+
607
+ @nb.njit
608
+ def fit_single_iteration(data, PSFSigma, sz, iterations, varim, fittype):
609
+ ll = np.float64(np.nan)
610
+
611
+ try:
612
+ if fittype == 1:
613
+ result, crb, ll = CPU.kernel_MLEFit_LM(
614
+ data, PSFSigma, int(sz), iterations, varim
615
+ )
616
+ elif fittype == 2:
617
+ result, crb, ll = CPU.kernel_MLEFit_LM_Sigma(
618
+ data, PSFSigma, int(sz), iterations, varim
619
+ )
620
+ elif fittype == 4:
621
+ result, crb, ll = CPU.kernel_MLEFit_LM_sigmaxy(
622
+ data, PSFSigma, int(sz), iterations, varim
623
+ )
624
+
625
+ return result, crb, ll
626
+ except Exception:
627
+ if fittype == 1:
628
+ result = np.zeros(NV_P + 1, dtype=np.float32)
629
+ crb = np.zeros(NV_P, dtype=np.float32)
630
+ elif fittype == 2:
631
+ result = np.zeros(NV_PS + 1, dtype=np.float32)
632
+ crb = np.zeros(NV_PS, dtype=np.float32)
633
+ elif fittype == 4:
634
+ result = np.zeros(NV_PS2 + 1, dtype=np.float32)
635
+ crb = np.zeros(NV_PS2, dtype=np.float32)
636
+
637
+ return result, crb, ll
638
+
639
+
640
+ @nb.njit(parallel=True, cache=True)
641
+ def CPU_parallel_fit_2D(
642
+ data,
643
+ fittype,
644
+ PSFSigma,
645
+ varim,
646
+ sz,
647
+ Nfitraw,
648
+ initZ,
649
+ iterations,
650
+ Parameters,
651
+ CRLBs,
652
+ LogLikelihood,
653
+ ):
654
+ for ii in nb.prange(Nfitraw):
655
+ varim_ii = None if varim is None else varim[ii, :]
656
+ Parameters[ii, :], CRLBs[ii, :], LogLikelihood[ii] = fit_single_iteration(
657
+ data[ii, :], PSFSigma, sz, iterations, varim_ii, fittype
658
+ )
659
+
660
+ return Parameters, CRLBs, LogLikelihood
661
+
662
+
663
+ # @nb.njit(parallel=True, cache=True)
664
+ # def CPU_parallel_fit_2D(
665
+ # data,
666
+ # fittype,
667
+ # PSFSigma,
668
+ # varim,
669
+ # sz,
670
+ # Nfitraw,
671
+ # initZ,
672
+ # iterations,
673
+ # Parameters,
674
+ # CRLBs,
675
+ # LogLikelihood,
676
+ # ):
677
+ # if fittype == 1: # fit x,y,bg,I
678
+ # for ii in nb.prange(Nfitraw):
679
+ # try:
680
+ # Parameters[ii, :], CRLBs[ii, :], LogLikelihood[ii] = (
681
+ # CPU.kernel_MLEFit_LM(
682
+ # data[ii, :],
683
+ # PSFSigma,
684
+ # int(sz),
685
+ # iterations,
686
+ # None if varim is None else varim[ii, :],
687
+ # )
688
+ # )
689
+ # except Exception:
690
+ # Parameters[ii, :] = -1
691
+ # CRLBs[ii, :] = -1
692
+ # LogLikelihood[ii] = -1
693
+ # elif fittype == 2: # fit x,y,bg,I,sigma
694
+ # for ii in nb.prange(Nfitraw):
695
+ # try:
696
+ # Parameters[ii, :], CRLBs[ii, :], LogLikelihood[ii] = (
697
+ # CPU.kernel_MLEFit_LM_Sigma(
698
+ # data[ii, :],
699
+ # PSFSigma,
700
+ # int(sz),
701
+ # iterations,
702
+ # None if varim is None else varim[ii, :],
703
+ # )
704
+ # )
705
+ # except Exception:
706
+ # Parameters[ii, :] = -1
707
+ # CRLBs[ii, :] = -1
708
+ # LogLikelihood[ii] = -1
709
+ # elif fittype == 4: # fit x,y,bg,I,sigmax,sigmay
710
+ # for ii in nb.prange(Nfitraw):
711
+ # try:
712
+ # Parameters[ii, :], CRLBs[ii, :], LogLikelihood[ii] = (
713
+ # CPU.kernel_MLEFit_LM_sigmaxy(
714
+ # data[ii, :],
715
+ # PSFSigma,
716
+ # int(sz),
717
+ # iterations,
718
+ # None if varim is None else varim[ii, :],
719
+ # )
720
+ # )
721
+ # except Exception:
722
+ # Parameters[ii, :] = -1
723
+ # CRLBs[ii, :] = -1
724
+ # LogLikelihood[ii] = -1
725
+
726
+
727
+ @nb.njit(parallel=True, cache=True)
728
+ def CPU_parallel_fit_3D_scpline(
729
+ data,
730
+ varim,
731
+ coeff,
732
+ spline_xsize,
733
+ spline_ysize,
734
+ spline_zsize,
735
+ sz,
736
+ Nfitraw,
737
+ initZ,
738
+ iterations,
739
+ Parameters,
740
+ CRLBs,
741
+ LogLikelihood,
742
+ ):
743
+ for ii in nb.prange(Nfitraw):
744
+ try:
745
+ Parameters[ii, :], CRLBs[ii, :], LogLikelihood[ii] = (
746
+ CPU.kernel_splineMLEFit_z(
747
+ data[ii, :],
748
+ coeff,
749
+ spline_xsize,
750
+ spline_ysize,
751
+ spline_zsize,
752
+ int(sz),
753
+ iterations,
754
+ initZ,
755
+ None if varim is None else varim[ii, :],
756
+ )
757
+ )
758
+ except Exception:
759
+ Parameters[ii, :] = -1
760
+ CRLBs[ii, :] = -1
761
+ LogLikelihood[ii] = -1
762
+
763
+
764
+ @nb.njit(cache=True)
765
+ def get_roi_list(image: np.ndarray, points: np.ndarray, roi_size=7):
766
+ '''
767
+ Gets the roi list of specific size around the supplied (x, y) points
768
+
769
+ Parameters
770
+ ----------
771
+ image : np.ndarray
772
+ The single channel image
773
+ points : np.ndarray
774
+ The points list of preliminary detection
775
+ roi_size : int, optional
776
+ roi size, by default 7
777
+
778
+ Returns
779
+ -------
780
+ tuple[np.ndarray, np.ndarray]
781
+ roi_list array of shape (nRoi, roi_size**2),
782
+ coord_list of roi top left corner
783
+ '''
784
+ if len(points) < 1:
785
+ return None
786
+
787
+ assert len(image.shape) == 2, 'image should be a 2D ndarray!'
788
+
789
+ roi_list = np.zeros((points.shape[0], roi_size**2), np.float32)
790
+ coord_list = np.zeros_like(points)
791
+
792
+ for r in nb.prange(points.shape[0]):
793
+ x, y = points[r, :]
794
+ idx = int(x - roi_size // 2)
795
+ idy = int(y - roi_size // 2)
796
+ if idx < 0:
797
+ idx = 0
798
+ if idy < 0:
799
+ idy = 0
800
+ if idx + roi_size > image.shape[1]:
801
+ idx = image.shape[1] - roi_size
802
+ if idy + roi_size > image.shape[0]:
803
+ idy = image.shape[0] - roi_size
804
+ coord_list[r, :] = [idx, idy]
805
+ roi_list[r, :] = image[idy : idy + roi_size, idx : idx + roi_size].flatten()
806
+
807
+ return roi_list, coord_list
808
+
809
+
810
+ @nb.njit(cache=True)
811
+ def get_roi_list_CMOS(
812
+ image: np.ndarray, varim: np.ndarray, points: np.ndarray, roi_size=7
813
+ ):
814
+ '''
815
+ Gets the roi list of specific size around the supplied (x, y) points
816
+
817
+ Parameters
818
+ ----------
819
+ image : np.ndarray
820
+ The single channel image
821
+ varim : np.ndarray
822
+ The CMOS pixel variance map
823
+ points : np.ndarray
824
+ The points list of preliminary detection
825
+ roi_size : int, optional
826
+ roi size, by default 7
827
+
828
+ Returns
829
+ -------
830
+ tuple[np.ndarray, np.ndarray, np.ndarray]
831
+ roi_list array of shape (nRoi, roi_size**2),
832
+ coord_list of roi top left corner
833
+ '''
834
+ if len(points) < 1:
835
+ return None
836
+
837
+ assert len(image.shape) == 2, 'image should be a 2D ndarray!'
838
+
839
+ assert image.shape == varim.shape, 'image & varim must have equal shape!'
840
+
841
+ roi_list = np.zeros((2, points.shape[0], roi_size**2), np.float32)
842
+ coord_list = np.zeros_like(points)
843
+
844
+ for r in nb.prange(points.shape[0]):
845
+ x, y = points[r, :]
846
+ idx = int(x - roi_size // 2)
847
+ idy = int(y - roi_size // 2)
848
+ if idx < 0:
849
+ idx = 0
850
+ if idy < 0:
851
+ idy = 0
852
+ if idx + roi_size > image.shape[1]:
853
+ idx = image.shape[1] - roi_size
854
+ if idy + roi_size > image.shape[0]:
855
+ idy = image.shape[0] - roi_size
856
+ coord_list[r, :] = [idx, idy]
857
+ roi_list[0, r, :] = image[idy : idy + roi_size, idx : idx + roi_size].flatten()
858
+ roi_list[1, r, :] = varim[idy : idy + roi_size, idx : idx + roi_size].flatten()
859
+
860
+ return roi_list[0], roi_list[1], coord_list
861
+
862
+
863
+ def psf2cspline_np(psf):
864
+ # calculate A
865
+ A = np.zeros((64, 64))
866
+ for i in range(1, 5):
867
+ dx = (i - 1) / 3
868
+ for j in range(1, 5):
869
+ dy = (j - 1) / 3
870
+ for k in range(1, 5):
871
+ dz = (k - 1) / 3
872
+ for ll in range(1, 5):
873
+ for m in range(1, 5):
874
+ for n in range(1, 5):
875
+ A[
876
+ (i - 1) * 16 + (j - 1) * 4 + k - 1,
877
+ (ll - 1) * 16 + (m - 1) * 4 + n - 1,
878
+ ] = dx ** (ll - 1) * dy ** (m - 1) * dz ** (n - 1)
879
+
880
+ # upsample psf with factor of 3
881
+ psf_up = ndimage.zoom(psf, 3.0, mode='grid-constant', grid_mode=True)[
882
+ 1:-1, 1:-1, 1:-1
883
+ ]
884
+ A = np.float32(A)
885
+ coeff = calsplinecoeff(A, psf, psf_up)
886
+ return coeff
887
+
888
+
889
+ def calsplinecoeff(A, psf, psf_up):
890
+ # calculate cspline coefficients
891
+ coeff = np.zeros((64, psf.shape[0] - 1, psf.shape[1] - 1, psf.shape[2] - 1))
892
+ for i in range(coeff.shape[1]):
893
+ for j in range(coeff.shape[2]):
894
+ for k in range(coeff.shape[3]):
895
+ temp = psf_up[
896
+ i * 3 : 3 * (i + 1) + 1,
897
+ j * 3 : 3 * (j + 1) + 1,
898
+ k * 3 : 3 * (k + 1) + 1,
899
+ ]
900
+ x = np.linalg.solve(A, temp.flatten())
901
+ coeff[:, i, j, k] = x
902
+
903
+ return coeff