waveorder 2.2.0__py3-none-any.whl → 2.2.0rc0__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.
waveorder/_version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '2.2.0'
15
+ __version__ = version = '2.2.0rc0'
16
16
  __version_tuple__ = version_tuple = (2, 2, 0)
@@ -7,7 +7,7 @@ from torch import Tensor
7
7
  from waveorder import correction, stokes, util
8
8
 
9
9
 
10
- def generate_test_phantom(yx_shape: Tuple[int, int]) -> Tuple[Tensor, Tensor, Tensor, Tensor]:
10
+ def generate_test_phantom(yx_shape):
11
11
  star, theta, _ = util.generate_star_target(yx_shape, blur_px=0.1)
12
12
  retardance = 0.25 * star
13
13
  orientation = (theta % np.pi) * (star > 1e-3)
@@ -17,13 +17,13 @@ def generate_test_phantom(yx_shape: Tuple[int, int]) -> Tuple[Tensor, Tensor, Te
17
17
 
18
18
 
19
19
  def calculate_transfer_function(
20
- swing: float,
21
- scheme: str,
22
- ) -> Tensor:
20
+ swing,
21
+ scheme,
22
+ ):
23
23
  return stokes.calculate_intensity_to_stokes_matrix(swing, scheme=scheme)
24
24
 
25
25
 
26
- def visualize_transfer_function(viewer, intensity_to_stokes_matrix: Tensor) -> None:
26
+ def visualize_transfer_function(viewer, intensity_to_stokes_matrix):
27
27
  viewer.add_image(
28
28
  intensity_to_stokes_matrix.cpu().numpy(),
29
29
  name="Intensity to stokes matrix",
@@ -31,12 +31,12 @@ def visualize_transfer_function(viewer, intensity_to_stokes_matrix: Tensor) -> N
31
31
 
32
32
 
33
33
  def apply_transfer_function(
34
- retardance: Tensor,
35
- orientation: Tensor,
36
- transmittance: Tensor,
37
- depolarization: Tensor,
38
- intensity_to_stokes_matrix: Tensor,
39
- ) -> Tensor:
34
+ retardance,
35
+ orientation,
36
+ transmittance,
37
+ depolarization,
38
+ intensity_to_stokes_matrix,
39
+ ):
40
40
  stokes_params = stokes.stokes_after_adr(
41
41
  retardance, orientation, transmittance, depolarization
42
42
  )
@@ -59,7 +59,7 @@ def apply_inverse_transfer_function(
59
59
  project_stokes_to_2d: bool = False,
60
60
  flip_orientation: bool = False,
61
61
  rotate_orientation: bool = False,
62
- ) -> Tuple[Tensor, Tensor, Tensor, Tensor]:
62
+ ) -> Tuple[Tensor]:
63
63
  """Reconstructs retardance, orientation, transmittance, and depolarization
64
64
  from czyx_data and an intensity_to_stokes_matrix, providing options for
65
65
  background correction, projection, and orientation transformations.
@@ -1,19 +1,17 @@
1
1
  from typing import Literal
2
2
 
3
- import numpy as np
4
3
  import torch
5
4
  from torch import Tensor
6
5
 
7
- from waveorder import optics, sampling, util
8
- from waveorder.visuals.napari_visuals import add_transfer_function_to_viewer
6
+ from waveorder import optics, util
9
7
 
10
8
 
11
9
  def generate_test_phantom(
12
- zyx_shape: tuple[int, int, int],
13
- yx_pixel_size: float,
14
- z_pixel_size: float,
15
- sphere_radius: float,
16
- ) -> Tensor:
10
+ zyx_shape,
11
+ yx_pixel_size,
12
+ z_pixel_size,
13
+ sphere_radius,
14
+ ):
17
15
  sphere, _, _ = util.generate_sphere_target(
18
16
  zyx_shape, yx_pixel_size, z_pixel_size, sphere_radius
19
17
  )
@@ -22,57 +20,14 @@ def generate_test_phantom(
22
20
 
23
21
 
24
22
  def calculate_transfer_function(
25
- zyx_shape: tuple[int, int, int],
26
- yx_pixel_size: float,
27
- z_pixel_size: float,
28
- wavelength_emission: float,
29
- z_padding: int,
30
- index_of_refraction_media: float,
31
- numerical_aperture_detection: float,
32
- ) -> Tensor:
33
-
34
- transverse_nyquist = sampling.transverse_nyquist(
35
- wavelength_emission,
36
- numerical_aperture_detection, # ill = det for fluorescence
37
- numerical_aperture_detection,
38
- )
39
- axial_nyquist = sampling.axial_nyquist(
40
- wavelength_emission,
41
- numerical_aperture_detection,
42
- index_of_refraction_media,
43
- )
44
-
45
- yx_factor = int(np.ceil(yx_pixel_size / transverse_nyquist))
46
- z_factor = int(np.ceil(z_pixel_size / axial_nyquist))
47
-
48
- optical_transfer_function = _calculate_wrap_unsafe_transfer_function(
49
- (
50
- zyx_shape[0] * z_factor,
51
- zyx_shape[1] * yx_factor,
52
- zyx_shape[2] * yx_factor,
53
- ),
54
- yx_pixel_size / yx_factor,
55
- z_pixel_size / z_factor,
56
- wavelength_emission,
57
- z_padding,
58
- index_of_refraction_media,
59
- numerical_aperture_detection,
60
- )
61
- zyx_out_shape = (zyx_shape[0] + 2 * z_padding,) + zyx_shape[1:]
62
- return sampling.nd_fourier_central_cuboid(
63
- optical_transfer_function, zyx_out_shape
64
- )
65
-
66
-
67
- def _calculate_wrap_unsafe_transfer_function(
68
- zyx_shape: tuple[int, int, int],
69
- yx_pixel_size: float,
70
- z_pixel_size: float,
71
- wavelength_emission: float,
72
- z_padding: int,
73
- index_of_refraction_media: float,
74
- numerical_aperture_detection: float,
75
- ) -> Tensor:
23
+ zyx_shape,
24
+ yx_pixel_size,
25
+ z_pixel_size,
26
+ wavelength_emission,
27
+ z_padding,
28
+ index_of_refraction_media,
29
+ numerical_aperture_detection,
30
+ ):
76
31
  radial_frequencies = util.generate_radial_frequencies(
77
32
  zyx_shape[1:], yx_pixel_size
78
33
  )
@@ -108,18 +63,27 @@ def _calculate_wrap_unsafe_transfer_function(
108
63
  return optical_transfer_function
109
64
 
110
65
 
111
- def visualize_transfer_function(viewer, optical_transfer_function: Tensor, zyx_scale: tuple[float, float, float]) -> None:
112
- add_transfer_function_to_viewer(
113
- viewer,
114
- torch.real(optical_transfer_function),
115
- zyx_scale,
116
- clim_factor=0.05,
117
- )
66
+ def visualize_transfer_function(viewer, optical_transfer_function, zyx_scale):
67
+ arrays = [
68
+ (torch.imag(optical_transfer_function), "Im(OTF)"),
69
+ (torch.real(optical_transfer_function), "Re(OTF)"),
70
+ ]
71
+
72
+ for array in arrays:
73
+ lim = 0.1 * torch.max(torch.abs(array[0]))
74
+ viewer.add_image(
75
+ torch.fft.ifftshift(array[0]).cpu().numpy(),
76
+ name=array[1],
77
+ colormap="bwr",
78
+ contrast_limits=(-lim, lim),
79
+ scale=1 / zyx_scale,
80
+ )
81
+ viewer.dims.order = (0, 1, 2)
118
82
 
119
83
 
120
84
  def apply_transfer_function(
121
- zyx_object: Tensor, optical_transfer_function: Tensor, z_padding: int, background: int = 10
122
- ) -> Tensor:
85
+ zyx_object, optical_transfer_function, z_padding, background=10
86
+ ):
123
87
  """Simulate imaging by applying a transfer function
124
88
 
125
89
  Parameters
@@ -133,7 +97,7 @@ def apply_transfer_function(
133
97
  Returns
134
98
  -------
135
99
  Simulated data : torch.Tensor
136
-
100
+
137
101
  """
138
102
  if (
139
103
  zyx_object.shape[0] + 2 * z_padding
@@ -164,7 +128,7 @@ def apply_inverse_transfer_function(
164
128
  regularization_strength: float = 1e-3,
165
129
  TV_rho_strength: float = 1e-3,
166
130
  TV_iterations: int = 10,
167
- ) -> Tensor:
131
+ ):
168
132
  """Reconstructs fluorescence density from zyx_data and
169
133
  an optical_transfer_function, providing options for z padding and
170
134
  reconstruction algorithms.
@@ -1,19 +1,19 @@
1
1
  from typing import Literal, Tuple
2
2
 
3
- import numpy as np
4
3
  import torch
5
4
  from torch import Tensor
6
5
 
7
- from waveorder import optics, sampling, util
6
+ from waveorder import optics, util
7
+
8
8
 
9
9
  def generate_test_phantom(
10
- yx_shape: Tuple[int, int],
11
- yx_pixel_size: float,
12
- wavelength_illumination: float,
13
- index_of_refraction_media: float,
14
- index_of_refraction_sample: float,
15
- sphere_radius: float,
16
- ) -> Tuple[Tensor, Tensor]:
10
+ yx_shape,
11
+ yx_pixel_size,
12
+ wavelength_illumination,
13
+ index_of_refraction_media,
14
+ index_of_refraction_sample,
15
+ sphere_radius,
16
+ ):
17
17
  sphere, _, _ = util.generate_sphere_target(
18
18
  (3,) + yx_shape,
19
19
  yx_pixel_size,
@@ -34,73 +34,15 @@ def generate_test_phantom(
34
34
 
35
35
 
36
36
  def calculate_transfer_function(
37
- yx_shape: Tuple[int, int],
38
- yx_pixel_size: float,
39
- z_position_list: list,
40
- wavelength_illumination: float,
41
- index_of_refraction_media: float,
42
- numerical_aperture_illumination: float,
43
- numerical_aperture_detection: float,
44
- invert_phase_contrast: bool = False,
45
- ) -> Tuple[Tensor, Tensor]:
46
- transverse_nyquist = sampling.transverse_nyquist(
47
- wavelength_illumination,
48
- numerical_aperture_illumination,
49
- numerical_aperture_detection,
50
- )
51
- yx_factor = int(np.ceil(yx_pixel_size / transverse_nyquist))
52
-
53
- absorption_2d_to_3d_transfer_function, phase_2d_to_3d_transfer_function = (
54
- _calculate_wrap_unsafe_transfer_function(
55
- (
56
- yx_shape[0] * yx_factor,
57
- yx_shape[1] * yx_factor,
58
- ),
59
- yx_pixel_size / yx_factor,
60
- z_position_list,
61
- wavelength_illumination,
62
- index_of_refraction_media,
63
- numerical_aperture_illumination,
64
- numerical_aperture_detection,
65
- invert_phase_contrast=invert_phase_contrast,
66
- )
67
- )
68
-
69
- absorption_2d_to_3d_transfer_function_out = torch.zeros(
70
- (len(z_position_list),) + tuple(yx_shape), dtype=torch.complex64
71
- )
72
- phase_2d_to_3d_transfer_function_out = torch.zeros(
73
- (len(z_position_list),) + tuple(yx_shape), dtype=torch.complex64
74
- )
75
-
76
- for z in range(len(z_position_list)):
77
- absorption_2d_to_3d_transfer_function_out[z] = (
78
- sampling.nd_fourier_central_cuboid(
79
- absorption_2d_to_3d_transfer_function[z], yx_shape
80
- )
81
- )
82
- phase_2d_to_3d_transfer_function_out[z] = (
83
- sampling.nd_fourier_central_cuboid(
84
- phase_2d_to_3d_transfer_function[z], yx_shape
85
- )
86
- )
87
-
88
- return (
89
- absorption_2d_to_3d_transfer_function_out,
90
- phase_2d_to_3d_transfer_function_out,
91
- )
92
-
93
-
94
- def _calculate_wrap_unsafe_transfer_function(
95
- yx_shape: Tuple[int, int],
96
- yx_pixel_size: float,
97
- z_position_list: list,
98
- wavelength_illumination: float,
99
- index_of_refraction_media: float,
100
- numerical_aperture_illumination: float,
101
- numerical_aperture_detection: float,
102
- invert_phase_contrast: bool = False,
103
- ) -> Tuple[Tensor, Tensor]:
37
+ yx_shape,
38
+ yx_pixel_size,
39
+ z_position_list,
40
+ wavelength_illumination,
41
+ index_of_refraction_media,
42
+ numerical_aperture_illumination,
43
+ numerical_aperture_detection,
44
+ invert_phase_contrast=False,
45
+ ):
104
46
  if invert_phase_contrast:
105
47
  z_position_list = torch.flip(torch.tensor(z_position_list), dims=(0,))
106
48
 
@@ -148,14 +90,10 @@ def _calculate_wrap_unsafe_transfer_function(
148
90
 
149
91
  def visualize_transfer_function(
150
92
  viewer,
151
- absorption_2d_to_3d_transfer_function: Tensor,
152
- phase_2d_to_3d_transfer_function: Tensor,
153
- ) -> None:
154
- """Note: unlike other `visualize_transfer_function` calls, this transfer
155
- function is a mixed 3D-to-2D transfer function, so it cannot reuse
156
- util.add_transfer_function_to_viewer. If more 3D-to-2D transfer functions
157
- are added, consider refactoring.
158
- """
93
+ absorption_2d_to_3d_transfer_function,
94
+ phase_2d_to_3d_transfer_function,
95
+ ):
96
+ # TODO: consider generalizing w/ phase_thick_3d.visualize_transfer_function
159
97
  arrays = [
160
98
  (torch.imag(absorption_2d_to_3d_transfer_function), "Im(absorb TF)"),
161
99
  (torch.real(absorption_2d_to_3d_transfer_function), "Re(absorb TF)"),
@@ -172,14 +110,14 @@ def visualize_transfer_function(
172
110
  contrast_limits=(-lim, lim),
173
111
  scale=(1, 1, 1),
174
112
  )
175
- viewer.dims.order = (2, 0, 1)
113
+ viewer.dims.order = (0, 1, 2)
176
114
 
177
115
 
178
116
  def visualize_point_spread_function(
179
117
  viewer,
180
- absorption_2d_to_3d_transfer_function: Tensor,
181
- phase_2d_to_3d_transfer_function: Tensor,
182
- ) -> None:
118
+ absorption_2d_to_3d_transfer_function,
119
+ phase_2d_to_3d_transfer_function,
120
+ ):
183
121
  arrays = [
184
122
  (torch.fft.ifftn(absorption_2d_to_3d_transfer_function), "absorb PSF"),
185
123
  (torch.fft.ifftn(phase_2d_to_3d_transfer_function), "phase PSF"),
@@ -198,11 +136,11 @@ def visualize_point_spread_function(
198
136
 
199
137
 
200
138
  def apply_transfer_function(
201
- yx_absorption: Tensor,
202
- yx_phase: Tensor,
203
- phase_2d_to_3d_transfer_function: Tensor,
204
- absorption_2d_to_3d_transfer_function: Tensor,
205
- ) -> Tensor:
139
+ yx_absorption,
140
+ yx_phase,
141
+ phase_2d_to_3d_transfer_function,
142
+ absorption_2d_to_3d_transfer_function,
143
+ ):
206
144
  # Very simple simulation, consider adding noise and bkg knobs
207
145
 
208
146
  # simulate absorbing object
@@ -239,7 +177,7 @@ def apply_inverse_transfer_function(
239
177
  TV_rho_strength: float = 1e-3,
240
178
  TV_iterations: int = 10,
241
179
  bg_filter: bool = True,
242
- ) -> Tuple[Tensor, Tensor]:
180
+ ) -> Tuple[Tensor]:
243
181
  """Reconstructs absorption and phase from zyx_data and a pair of
244
182
  3D-to-2D transfer functions named absorption_2d_to_3d_transfer_function and
245
183
  phase_2d_to_3d_transfer_function, providing options for reconstruction
@@ -4,19 +4,18 @@ import numpy as np
4
4
  import torch
5
5
  from torch import Tensor
6
6
 
7
- from waveorder import optics, sampling, util
7
+ from waveorder import optics, util
8
8
  from waveorder.models import isotropic_fluorescent_thick_3d
9
- from waveorder.visuals.napari_visuals import add_transfer_function_to_viewer
10
9
 
11
10
 
12
11
  def generate_test_phantom(
13
- zyx_shape: tuple[int, int, int],
14
- yx_pixel_size: float,
15
- z_pixel_size: float,
16
- index_of_refraction_media: float,
17
- index_of_refraction_sample: float,
18
- sphere_radius: float,
19
- ) -> np.ndarray:
12
+ zyx_shape,
13
+ yx_pixel_size,
14
+ z_pixel_size,
15
+ index_of_refraction_media,
16
+ index_of_refraction_sample,
17
+ sphere_radius,
18
+ ):
20
19
  sphere, _, _ = util.generate_sphere_target(
21
20
  zyx_shape,
22
21
  yx_pixel_size,
@@ -32,70 +31,16 @@ def generate_test_phantom(
32
31
 
33
32
 
34
33
  def calculate_transfer_function(
35
- zyx_shape: tuple[int, int, int],
36
- yx_pixel_size: float,
37
- z_pixel_size: float,
38
- wavelength_illumination: float,
39
- z_padding: int,
40
- index_of_refraction_media: float,
41
- numerical_aperture_illumination: float,
42
- numerical_aperture_detection: float,
43
- invert_phase_contrast: bool = False,
44
- ) -> tuple[np.ndarray, np.ndarray]:
45
- transverse_nyquist = sampling.transverse_nyquist(
46
- wavelength_illumination,
47
- numerical_aperture_illumination,
48
- numerical_aperture_detection,
49
- )
50
- axial_nyquist = sampling.axial_nyquist(
51
- wavelength_illumination,
52
- numerical_aperture_detection,
53
- index_of_refraction_media,
54
- )
55
-
56
- yx_factor = int(np.ceil(yx_pixel_size / transverse_nyquist))
57
- z_factor = int(np.ceil(z_pixel_size / axial_nyquist))
58
-
59
- real_potential_transfer_function, imag_potential_transfer_function = (
60
- _calculate_wrap_unsafe_transfer_function(
61
- (
62
- zyx_shape[0] * z_factor,
63
- zyx_shape[1] * yx_factor,
64
- zyx_shape[2] * yx_factor,
65
- ),
66
- yx_pixel_size / yx_factor,
67
- z_pixel_size / z_factor,
68
- wavelength_illumination,
69
- z_padding,
70
- index_of_refraction_media,
71
- numerical_aperture_illumination,
72
- numerical_aperture_detection,
73
- invert_phase_contrast=invert_phase_contrast,
74
- )
75
- )
76
-
77
- zyx_out_shape = (zyx_shape[0] + 2 * z_padding,) + zyx_shape[1:]
78
- return (
79
- sampling.nd_fourier_central_cuboid(
80
- real_potential_transfer_function, zyx_out_shape
81
- ),
82
- sampling.nd_fourier_central_cuboid(
83
- imag_potential_transfer_function, zyx_out_shape
84
- ),
85
- )
86
-
87
-
88
- def _calculate_wrap_unsafe_transfer_function(
89
- zyx_shape: tuple[int, int, int],
90
- yx_pixel_size: float,
91
- z_pixel_size: float,
92
- wavelength_illumination: float,
93
- z_padding: int,
94
- index_of_refraction_media: float,
95
- numerical_aperture_illumination: float,
96
- numerical_aperture_detection: float,
97
- invert_phase_contrast: bool = False,
98
- ) -> tuple[np.ndarray, np.ndarray]:
34
+ zyx_shape,
35
+ yx_pixel_size,
36
+ z_pixel_size,
37
+ wavelength_illumination,
38
+ z_padding,
39
+ index_of_refraction_media,
40
+ numerical_aperture_illumination,
41
+ numerical_aperture_detection,
42
+ invert_phase_contrast=False,
43
+ ):
99
44
  radial_frequencies = util.generate_radial_frequencies(
100
45
  zyx_shape[1:], yx_pixel_size
101
46
  )
@@ -127,7 +72,6 @@ def _calculate_wrap_unsafe_transfer_function(
127
72
  det_pupil,
128
73
  wavelength_illumination / index_of_refraction_media,
129
74
  z_position_list,
130
- axially_even=False,
131
75
  )
132
76
 
133
77
  (
@@ -147,28 +91,33 @@ def _calculate_wrap_unsafe_transfer_function(
147
91
 
148
92
  def visualize_transfer_function(
149
93
  viewer,
150
- real_potential_transfer_function: np.ndarray,
151
- imag_potential_transfer_function: np.ndarray,
152
- zyx_scale: tuple[float, float, float],
153
- ) -> None:
154
- add_transfer_function_to_viewer(
155
- viewer,
156
- imag_potential_transfer_function,
157
- zyx_scale,
158
- layer_name="Imag pot. TF",
159
- )
160
-
161
- add_transfer_function_to_viewer(
162
- viewer,
163
- real_potential_transfer_function,
164
- zyx_scale,
165
- layer_name="Real pot. TF",
166
- )
94
+ real_potential_transfer_function,
95
+ imag_potential_transfer_function,
96
+ zyx_scale,
97
+ ):
98
+ # TODO: consider generalizing w/ phase2Dto3D.visualize_TF
99
+ arrays = [
100
+ (torch.real(imag_potential_transfer_function), "Re(imag pot. TF)"),
101
+ (torch.imag(imag_potential_transfer_function), "Im(imag pot. TF)"),
102
+ (torch.real(real_potential_transfer_function), "Re(real pot. TF)"),
103
+ (torch.imag(real_potential_transfer_function), "Im(real pot. TF)"),
104
+ ]
105
+
106
+ for array in arrays:
107
+ lim = 0.5 * torch.max(torch.abs(array[0]))
108
+ viewer.add_image(
109
+ torch.fft.ifftshift(array[0]).cpu().numpy(),
110
+ name=array[1],
111
+ colormap="bwr",
112
+ contrast_limits=(-lim, lim),
113
+ scale=1 / zyx_scale,
114
+ )
115
+ viewer.dims.order = (0, 1, 2)
167
116
 
168
117
 
169
118
  def apply_transfer_function(
170
- zyx_object: np.ndarray, real_potential_transfer_function: np.ndarray, z_padding: int, brightness: float
171
- ) -> np.ndarray:
119
+ zyx_object, real_potential_transfer_function, z_padding, brightness
120
+ ):
172
121
  # This simplified forward model only handles phase, so it resuses the fluorescence forward model
173
122
  # TODO: extend to absorption
174
123
  return (
@@ -193,7 +142,7 @@ def apply_inverse_transfer_function(
193
142
  regularization_strength: float = 1e-3,
194
143
  TV_rho_strength: float = 1e-3,
195
144
  TV_iterations: int = 10,
196
- ) -> Tensor:
145
+ ):
197
146
  """Reconstructs 3D phase from labelfree defocus zyx_data and a pair of
198
147
  complex 3D transfer functions real_potential_transfer_function and
199
148
  imag_potential_transfer_function, providing options for reconstruction