waveorder 3.0.0a2__py3-none-any.whl → 3.0.0a3__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.
@@ -10,15 +10,95 @@ from waveorder.models import isotropic_fluorescent_thick_3d
10
10
  from waveorder.reconstruct import tikhonov_regularized_inverse_filter
11
11
  from waveorder.visuals.napari_visuals import add_transfer_function_to_viewer
12
12
 
13
+ """
14
+ Phase Thick 3D Model - Units and Conventions
15
+ =============================================
16
+
17
+ This module implements phase-from-defocus optical diffraction tomography (ODT)
18
+ for thick phase objects using the weak object transfer function (first Born
19
+ approximation).
20
+
21
+ Units Convention
22
+ ----------------
23
+ This model uses "cycles" as the fundamental unit for phase:
24
+ - 1 cycle = 2π radians = 1 wavelength of optical path difference
25
+
26
+ Phantom (input):
27
+ Phase in cycles per voxel = (Δn × z_pixel_size) / λ_medium
28
+ where:
29
+ - Δn = n_sample - n_media (refractive index difference)
30
+ - z_pixel_size = voxel thickness
31
+ - λ_medium = λ_vacuum / n_media (wavelength in medium)
32
+
33
+ Reconstruction (output):
34
+ Phase in cycles per voxel (same units as phantom)
35
+
36
+ Converting Between Units
37
+ ------------------------
38
+ From cycles to radians:
39
+ phase_radians = 2 * np.pi * phase_cycles
40
+
41
+ From cycles to refractive index difference:
42
+ wavelength_medium = wavelength_vacuum / n_media
43
+ delta_n = phase_cycles * wavelength_medium / z_pixel_size
44
+
45
+ From cycles to optical path length:
46
+ optical_path_length = phase_cycles * wavelength_medium
47
+
48
+ Physics Background
49
+ ------------------
50
+ The weak object approximation (first Born approximation) assumes:
51
+ 1. Small refractive index variations: |Δn| << n_media
52
+ 2. Weak scattering: no multiple scattering
53
+ 3. Linear relationship between object and measured intensity
54
+
55
+ Reference
56
+ ---------
57
+ J. M. Soto, J. A. Rodrigo, and T. Alieva, "Label-free quantitative 3D
58
+ tomographic imaging for partially coherent light microscopy,"
59
+ Opt. Express 25, 15699-15712 (2017)
60
+ """
61
+
13
62
 
14
63
  def generate_test_phantom(
15
64
  zyx_shape: tuple[int, int, int],
16
65
  yx_pixel_size: float,
17
66
  z_pixel_size: float,
67
+ wavelength_illumination: float,
18
68
  index_of_refraction_media: float,
19
69
  index_of_refraction_sample: float,
20
70
  sphere_radius: float,
21
71
  ) -> np.ndarray:
72
+ """
73
+ Generate a spherical phantom with phase in cycles per voxel.
74
+
75
+ Parameters
76
+ ----------
77
+ zyx_shape : tuple[int, int, int]
78
+ Shape of the 3D volume (Z, Y, X)
79
+ yx_pixel_size : float
80
+ Pixel size in transverse (Y, X) dimensions (length)
81
+ z_pixel_size : float
82
+ Pixel size in axial (Z) dimension (length)
83
+ wavelength_illumination : float
84
+ Wavelength of illumination light (length, same units as pixel sizes)
85
+ index_of_refraction_media : float
86
+ Refractive index of the surrounding medium
87
+ index_of_refraction_sample : float
88
+ Refractive index of the sphere
89
+ sphere_radius : float
90
+ Radius of the sphere (length, same units as pixel sizes)
91
+
92
+ Returns
93
+ -------
94
+ np.ndarray
95
+ 3D array of phase in cycles per voxel.
96
+ Units: (n_sample - n_media) × z_pixel_size / λ_medium [cycles/voxel]
97
+
98
+ Each voxel value represents the phase shift (in cycles) that light
99
+ acquires when passing through that voxel. This matches the units
100
+ returned by apply_inverse_transfer_function().
101
+ """
22
102
  sphere, _, _ = util.generate_sphere_target(
23
103
  zyx_shape,
24
104
  yx_pixel_size,
@@ -26,9 +106,13 @@ def generate_test_phantom(
26
106
  radius=sphere_radius,
27
107
  blur_size=2 * yx_pixel_size,
28
108
  )
29
- zyx_phase = sphere * (
30
- index_of_refraction_sample - index_of_refraction_media
31
- ) # refractive index increment
109
+
110
+ # Compute refractive index difference
111
+ delta_n = sphere * (index_of_refraction_sample - index_of_refraction_media)
112
+
113
+ # Convert to phase in cycles per voxel
114
+ wavelength_medium = wavelength_illumination / index_of_refraction_media
115
+ zyx_phase = delta_n * z_pixel_size / wavelength_medium
32
116
 
33
117
  return zyx_phase
34
118
 
@@ -234,7 +318,22 @@ def apply_inverse_transfer_function(
234
318
  Returns
235
319
  -------
236
320
  Tensor
237
- zyx_phase (radians)
321
+ zyx_phase : Phase in cycles per voxel
322
+ Units: (Δn × z_pixel_size) / λ_medium [cycles/voxel]
323
+
324
+ Each voxel represents the phase shift (in cycles) that light acquires
325
+ when passing through that voxel. This matches the units of the input
326
+ phantom from generate_test_phantom().
327
+
328
+ To convert to phase in radians:
329
+ phase_radians = 2 * np.pi * zyx_phase
330
+
331
+ To convert to refractive index difference:
332
+ wavelength_medium = wavelength_illumination / index_of_refraction_media
333
+ delta_n = zyx_phase * wavelength_medium / z_pixel_size
334
+
335
+ Note: One cycle corresponds to 2π radians of phase shift, or one
336
+ wavelength of optical path length difference.
238
337
 
239
338
  Raises
240
339
  ------