waveorder 2.1.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.1.0'
16
- __version_tuple__ = version_tuple = (2, 1, 0)
15
+ __version__ = version = '2.2.0rc0'
16
+ __version_tuple__ = version_tuple = (2, 2, 0)
waveorder/focus.py CHANGED
@@ -3,6 +3,7 @@ from typing import Literal, Optional
3
3
  from waveorder import util
4
4
  import matplotlib.pyplot as plt
5
5
  import numpy as np
6
+ import warnings
6
7
 
7
8
 
8
9
  def focus_from_transverse_band(
@@ -60,10 +61,19 @@ def focus_from_transverse_band(
60
61
  >>> slice = focus_from_transverse_band(zyx_array, NA_det=0.55, lambda_ill=0.532, pixel_size=6.5/20)
61
62
  >>> in_focus_data = data[slice,:,:]
62
63
  """
63
- minmaxfunc = _check_focus_inputs(
64
- zyx_array, NA_det, lambda_ill, pixel_size, midband_fractions, mode
64
+ minmaxfunc = _mode_to_minmaxfunc(mode)
65
+
66
+ _check_focus_inputs(
67
+ zyx_array, NA_det, lambda_ill, pixel_size, midband_fractions
65
68
  )
66
69
 
70
+ # Check for single slice
71
+ if zyx_array.shape[0] == 1:
72
+ warnings.warn(
73
+ "The dataset only contained a single slice. Returning trivial slice index = 0."
74
+ )
75
+ return 0
76
+
67
77
  # Calculate coordinates
68
78
  _, Y, X = zyx_array.shape
69
79
  _, _, fxx, fyy = util.gen_coordinate((Y, X), pixel_size)
@@ -94,25 +104,35 @@ def focus_from_transverse_band(
94
104
  # Plot
95
105
  if plot_path is not None:
96
106
  _plot_focus_metric(
97
- plot_path, midband_sum, peak_index, in_focus_index, peak_results, threshold_FWHM
107
+ plot_path,
108
+ midband_sum,
109
+ peak_index,
110
+ in_focus_index,
111
+ peak_results,
112
+ threshold_FWHM,
98
113
  )
99
114
 
100
115
  return in_focus_index
101
116
 
102
117
 
118
+ def _mode_to_minmaxfunc(mode):
119
+ if mode == "min":
120
+ minmaxfunc = np.argmin
121
+ elif mode == "max":
122
+ minmaxfunc = np.argmax
123
+ else:
124
+ raise ValueError("mode must be either `min` or `max`")
125
+ return minmaxfunc
126
+
127
+
103
128
  def _check_focus_inputs(
104
- zyx_array, NA_det, lambda_ill, pixel_size, midband_fractions, mode
129
+ zyx_array, NA_det, lambda_ill, pixel_size, midband_fractions
105
130
  ):
106
131
  N = len(zyx_array.shape)
107
132
  if N != 3:
108
133
  raise ValueError(
109
134
  f"{N}D array supplied. `focus_from_transverse_band` only accepts 3D arrays."
110
135
  )
111
- if zyx_array.shape[0] == 1:
112
- print(
113
- "WARNING: The dataset only contained a single slice. Returning trivial slice index = 0."
114
- )
115
- return 0
116
136
 
117
137
  if NA_det < 0:
118
138
  raise ValueError("NA must be > 0")
@@ -121,7 +141,7 @@ def _check_focus_inputs(
121
141
  if pixel_size < 0:
122
142
  raise ValueError("pixel_size must be > 0")
123
143
  if not 0.4 < lambda_ill / pixel_size < 10:
124
- print(
144
+ warnings.warn(
125
145
  f"WARNING: lambda_ill/pixel_size = {lambda_ill/pixel_size}."
126
146
  f"Did you use the same units?"
127
147
  f"Did you enter the pixel size in (demagnified) object-space units?"
@@ -134,17 +154,15 @@ def _check_focus_inputs(
134
154
  raise ValueError("midband_fractions[0] must be between 0 and 1")
135
155
  if not (0 <= midband_fractions[1] <= 1):
136
156
  raise ValueError("midband_fractions[1] must be between 0 and 1")
137
- if mode == "min":
138
- minmaxfunc = np.argmin
139
- elif mode == "max":
140
- minmaxfunc = np.argmax
141
- else:
142
- raise ValueError("mode must be either `min` or `max`")
143
- return minmaxfunc
144
157
 
145
158
 
146
159
  def _plot_focus_metric(
147
- plot_path, midband_sum, peak_index, in_focus_index, peak_results, threshold_FWHM
160
+ plot_path,
161
+ midband_sum,
162
+ peak_index,
163
+ in_focus_index,
164
+ peak_results,
165
+ threshold_FWHM,
148
166
  ):
149
167
  _, ax = plt.subplots(1, 1, figsize=(4, 4))
150
168
  ax.plot(midband_sum, "-k")
@@ -81,7 +81,24 @@ def visualize_transfer_function(viewer, optical_transfer_function, zyx_scale):
81
81
  viewer.dims.order = (0, 1, 2)
82
82
 
83
83
 
84
- def apply_transfer_function(zyx_object, optical_transfer_function, z_padding):
84
+ def apply_transfer_function(
85
+ zyx_object, optical_transfer_function, z_padding, background=10
86
+ ):
87
+ """Simulate imaging by applying a transfer function
88
+
89
+ Parameters
90
+ ----------
91
+ zyx_object : torch.Tensor
92
+ optical_transfer_function : torch.Tensor
93
+ z_padding : int
94
+ background : int, optional
95
+ constant background counts added to each voxel, by default 10
96
+
97
+ Returns
98
+ -------
99
+ Simulated data : torch.Tensor
100
+
101
+ """
85
102
  if (
86
103
  zyx_object.shape[0] + 2 * z_padding
87
104
  != optical_transfer_function.shape[0]
@@ -99,7 +116,7 @@ def apply_transfer_function(zyx_object, optical_transfer_function, z_padding):
99
116
  zyx_data = zyx_obj_hat * optical_transfer_function
100
117
  data = torch.real(torch.fft.ifftn(zyx_data))
101
118
 
102
- data += 10 # Add a direct background
119
+ data += background # Add a direct background
103
120
  return data
104
121
 
105
122
 
@@ -12,7 +12,6 @@ def generate_test_phantom(
12
12
  zyx_shape,
13
13
  yx_pixel_size,
14
14
  z_pixel_size,
15
- wavelength_illumination,
16
15
  index_of_refraction_media,
17
16
  index_of_refraction_sample,
18
17
  sphere_radius,
@@ -24,12 +23,9 @@ def generate_test_phantom(
24
23
  radius=sphere_radius,
25
24
  blur_size=2 * yx_pixel_size,
26
25
  )
27
- zyx_phase = (
28
- sphere
29
- * (index_of_refraction_sample - index_of_refraction_media)
30
- * z_pixel_size
31
- / wavelength_illumination
32
- ) # phase in radians
26
+ zyx_phase = sphere * (
27
+ index_of_refraction_sample - index_of_refraction_media
28
+ ) # refractive index increment
33
29
 
34
30
  return zyx_phase
35
31
 
@@ -120,12 +116,19 @@ def visualize_transfer_function(
120
116
 
121
117
 
122
118
  def apply_transfer_function(
123
- zyx_object, real_potential_transfer_function, z_padding
119
+ zyx_object, real_potential_transfer_function, z_padding, brightness
124
120
  ):
125
121
  # This simplified forward model only handles phase, so it resuses the fluorescence forward model
126
122
  # TODO: extend to absorption
127
- return isotropic_fluorescent_thick_3d.apply_transfer_function(
128
- zyx_object, real_potential_transfer_function, z_padding
123
+ return (
124
+ isotropic_fluorescent_thick_3d.apply_transfer_function(
125
+ zyx_object,
126
+ real_potential_transfer_function,
127
+ z_padding,
128
+ background=0,
129
+ )
130
+ * brightness
131
+ + brightness
129
132
  )
130
133
 
131
134
 
@@ -134,8 +137,6 @@ def apply_inverse_transfer_function(
134
137
  real_potential_transfer_function: Tensor,
135
138
  imaginary_potential_transfer_function: Tensor,
136
139
  z_padding: int,
137
- z_pixel_size: float, # TODO: MOVE THIS PARAM TO OTF? (leaky param)
138
- wavelength_illumination: float, # TOOD: MOVE THIS PARAM TO OTF? (leaky param)
139
140
  absorption_ratio: float = 0.0,
140
141
  reconstruction_algorithm: Literal["Tikhonov", "TV"] = "Tikhonov",
141
142
  regularization_strength: float = 1e-3,
@@ -158,14 +159,6 @@ def apply_inverse_transfer_function(
158
159
  z_padding : int
159
160
  Padding for axial dimension. Use zero for defocus stacks that
160
161
  extend ~3 PSF widths beyond the sample. Pad by ~3 PSF widths otherwise.
161
- z_pixel_size : float
162
- spacing between axial samples in sample space
163
- units must be consistent with wavelength_illumination
164
- TODO: move this leaky parameter to calculate_transfer_function
165
- wavelength_illumination : float,
166
- illumination wavelength
167
- units must be consistent with z_pixel_size
168
- TODO: move this leaky parameter to calculate_transfer_function
169
162
  absorption_ratio : float, optional,
170
163
  Absorption-to-phase ratio in the sample.
171
164
  Use default 0 for purely phase objects.
@@ -223,4 +216,4 @@ def apply_inverse_transfer_function(
223
216
  if z_padding != 0:
224
217
  f_real = f_real[z_padding:-z_padding]
225
218
 
226
- return f_real * z_pixel_size / 4 / np.pi * wavelength_illumination
219
+ return f_real
waveorder/optics.py CHANGED
@@ -270,7 +270,7 @@ def Source_subsample(Source_cont, NAx_coord, NAy_coord, subsampled_NA=0.1):
270
270
  illu_list.append(i)
271
271
  first_idx = False
272
272
  elif (
273
- np.product(
273
+ np.prod(
274
274
  (NAx_list[i] - NAx_list[illu_list]) ** 2
275
275
  + (NAy_list[i] - NAy_list[illu_list]) ** 2
276
276
  >= subsampled_NA**2
@@ -739,19 +739,23 @@ def compute_weak_object_transfer_function_3D(
739
739
 
740
740
  H1 = torch.fft.ifft2(torch.conj(SPHz_hat) * PG_hat, dim=(1, 2))
741
741
  H1 = H1 * window[:, None, None]
742
- H1 = torch.fft.fft(H1, dim=0) * z_pixel_size
742
+ H1 = torch.fft.fft(H1, dim=0)
743
743
 
744
744
  H2 = torch.fft.ifft2(SPHz_hat * torch.conj(PG_hat), dim=(1, 2))
745
745
  H2 = H2 * window[:, None, None]
746
- H2 = torch.fft.fft(H2, dim=0) * z_pixel_size
746
+ H2 = torch.fft.fft(H2, dim=0)
747
747
 
748
- I_norm = torch.sum(
748
+ direct_intensity = torch.sum(
749
749
  illumination_pupil_support
750
750
  * detection_pupil
751
751
  * torch.conj(detection_pupil)
752
752
  )
753
- real_potential_transfer_function = (H1 + H2) / I_norm
754
- imag_potential_transfer_function = 1j * (H1 - H2) / I_norm
753
+ real_potential_transfer_function = (H1 + H2) / direct_intensity
754
+ imag_potential_transfer_function = 1j * (H1 - H2) / direct_intensity
755
+
756
+ # Discretization factor for unitless input and output
757
+ real_potential_transfer_function *= z_pixel_size
758
+ imag_potential_transfer_function *= z_pixel_size
755
759
 
756
760
  return real_potential_transfer_function, imag_potential_transfer_function
757
761
 
@@ -1,43 +1,66 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: waveorder
3
- Version: 2.1.0
4
- Summary: Wave optical simulations and deconvolution of optical properties
5
- Home-page: https://github.com/mehta-lab/waveorder
6
- Author: Computational Microscopy Platform, CZ Biohub
7
- Author-email: shalin.mehta@czbiohub.org
3
+ Version: 2.2.0rc0
4
+ Summary: Wave-optical simulations and deconvolution of optical properties
5
+ Author-email: CZ Biohub SF <compmicro@czbiohub.org>
6
+ Maintainer-email: Talon Chandler <talon.chandler@czbiohub.org>, Shalin Mehta <shalin.mehta@czbiohub.org>
8
7
  License: BSD 3-Clause License
9
- Project-URL: Bug Tracker, https://github.com/mehta-lab/waveorder/issues
10
- Project-URL: Documentation, https://github.com/mehta-lab/waveorder
11
- Project-URL: Source Code, https://github.com/mehta-lab/waveorder
12
- Project-URL: User Support, https://github.com/mehta-lab/waveorder/issues
8
+
9
+ Copyright (c) 2019, Chan Zuckerberg Biohub
10
+
11
+ Redistribution and use in source and binary forms, with or without
12
+ modification, are permitted provided that the following conditions are met:
13
+
14
+ 1. Redistributions of source code must retain the above copyright notice, this
15
+ list of conditions and the following disclaimer.
16
+
17
+ 2. Redistributions in binary form must reproduce the above copyright notice,
18
+ this list of conditions and the following disclaimer in the documentation
19
+ and/or other materials provided with the distribution.
20
+
21
+ 3. Neither the name of the copyright holder nor the names of its
22
+ contributors may be used to endorse or promote products derived from
23
+ this software without specific prior written permission.
24
+
25
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
29
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
+
36
+ Project-URL: Homepage, https://github.com/mehta-lab/waveorder
37
+ Project-URL: Repository, https://github.com/mehta-lab/waveorder
38
+ Project-URL: Issues, https://github.com/mehta-lab/waveorder/issues
39
+ Keywords: simulation,optics,phase,scattering,polarization,label-free,permittivity,reconstruction-algorithm,qlipp,mipolscope,permittivity-tensor-imaging
13
40
  Classifier: Development Status :: 4 - Beta
14
41
  Classifier: Intended Audience :: Science/Research
15
42
  Classifier: License :: OSI Approved :: BSD License
16
- Classifier: Programming Language :: Python :: 3 :: Only
17
- Classifier: Programming Language :: Python :: 3.8
18
- Classifier: Programming Language :: Python :: 3.9
43
+ Classifier: Programming Language :: Python :: 3
19
44
  Classifier: Programming Language :: Python :: 3.10
45
+ Classifier: Programming Language :: Python :: 3.11
46
+ Classifier: Programming Language :: Python :: 3.12
20
47
  Classifier: Topic :: Scientific/Engineering
21
48
  Classifier: Topic :: Scientific/Engineering :: Image Processing
22
- Classifier: Topic :: Scientific/Engineering :: Visualization
23
- Classifier: Topic :: Scientific/Engineering :: Information Analysis
24
49
  Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
50
+ Classifier: Operating System :: POSIX :: Linux
25
51
  Classifier: Operating System :: Microsoft :: Windows
26
- Classifier: Operating System :: POSIX
27
- Classifier: Operating System :: Unix
28
52
  Classifier: Operating System :: MacOS
29
- Requires-Python: >=3.8
53
+ Requires-Python: >=3.10
30
54
  Description-Content-Type: text/markdown
31
55
  License-File: LICENSE
32
- Requires-Dist: numpy >=1.21
56
+ Requires-Dist: numpy <2,>=1.21
33
57
  Requires-Dist: matplotlib >=3.1.1
34
58
  Requires-Dist: scipy >=1.3.0
35
59
  Requires-Dist: pywavelets >=1.1.1
36
60
  Requires-Dist: ipywidgets >=7.5.1
37
- Requires-Dist: torch >=2.0.0
61
+ Requires-Dist: torch >=2.2.1
38
62
  Provides-Extra: dev
39
- Requires-Dist: flake8 ; extra == 'dev'
40
- Requires-Dist: pytest >=5.0.0 ; extra == 'dev'
63
+ Requires-Dist: pytest ; extra == 'dev'
41
64
  Requires-Dist: pytest-cov ; extra == 'dev'
42
65
 
43
66
  # waveorder
@@ -93,7 +116,7 @@ Please cite this repository, along with the relevant preprint or paper, if you u
93
116
  (Optional but recommended) install [anaconda](https://www.anaconda.com/products/distribution) and create a virtual environment:
94
117
 
95
118
  ```sh
96
- conda create -y -n waveorder python=3.9
119
+ conda create -y -n waveorder python=3.11
97
120
  conda activate waveorder
98
121
  ```
99
122
 
@@ -1,20 +1,20 @@
1
1
  waveorder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- waveorder/_version.py,sha256=N_eoCB5RSZeFANRJsHZ9FylE5ILLKrp6YmjX8ezqFpA,411
2
+ waveorder/_version.py,sha256=y62tGqTh86kx1L4FG_Wu91vm4c-zkqBUqEkv0mTr0sY,414
3
3
  waveorder/background_estimator.py,sha256=gCIO6-232H0CGH4o6gnqW9KSYGOrXf5E9nD67WeF304,12399
4
4
  waveorder/correction.py,sha256=N0Ic6mqw3U7mqow4dKTOkNx2QYOLwedGNH7HiKV-M6s,3460
5
- waveorder/focus.py,sha256=bx6mbYdCJlKnS68344kFO0_qqowbpI3JNlV4ouT3vJo,6125
6
- waveorder/optics.py,sha256=64vFUq8DmmaHqBjXdLifWlnwpoXloQYsvm2KWTV7dkE,37478
5
+ waveorder/focus.py,sha256=4mg84Fe4V-oFplsuaU_VQU1_TEDoEfPggIAv6Is2dE4,6312
6
+ waveorder/optics.py,sha256=-mHYRMzDUNAz8kwF8xAR8RFuAEkWZzczKv2wnU5NuVs,37640
7
7
  waveorder/stokes.py,sha256=Wk9ZimzICIZLh1CkB0kQSCSBLeugkDeydwXTPd-M-po,15186
8
8
  waveorder/util.py,sha256=3k810fpb7pIEcc4fii6gP4wTerxCtFYgG82SiDzUTtQ,69898
9
9
  waveorder/visual.py,sha256=SFzkQdMit3HyqTqrgzX4w5bRwz8QuwGumzVayi3DwDM,58171
10
10
  waveorder/waveorder_reconstructor.py,sha256=5-jlbK8gcJqHbFhiWt-TcETV5cdLHSAXq9O3JupPXD0,151942
11
11
  waveorder/waveorder_simulator.py,sha256=_HCmDZkACUGzgwnaI-q0PjsL1gRE55IQuaWw-wtAjCU,45856
12
12
  waveorder/models/inplane_oriented_thick_pol3d.py,sha256=Z7rfufrDeEkUYf2MlZsXyvKsZWHIJWujK357_z1BBg0,5809
13
- waveorder/models/isotropic_fluorescent_thick_3d.py,sha256=H6BFI25PaWXhtx62Gsf42Y85cCdflwhKk_nKlcuD9T8,5007
13
+ waveorder/models/isotropic_fluorescent_thick_3d.py,sha256=Pzi2kM1OGmwQIrI6b5h9OeIOGzHssG30Wv8zDi4n4PQ,5395
14
14
  waveorder/models/isotropic_thin_3d.py,sha256=E__ly_xF6Tw_bHLSHHPpd3p60t01LhIPiFrqfd5u1r4,8493
15
- waveorder/models/phase_thick_3d.py,sha256=U3RMHCFaKvxptoARt_lyJEHMElfj1tSJpVHJNnceIcs,7158
16
- waveorder-2.1.0.dist-info/LICENSE,sha256=auz4oGH1A-xZtoiR2zuXIk-Hii4v9aGgFVBqn7nfpms,1509
17
- waveorder-2.1.0.dist-info/METADATA,sha256=IsQbwt64BSCXnO1CboPAFOWUPiUzMoD7gK0LQBSHcqM,6656
18
- waveorder-2.1.0.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
19
- waveorder-2.1.0.dist-info/top_level.txt,sha256=i3zReXiiMTnyPk93W7aEz_oEfsLnfR_Kzl7PW7kUslA,10
20
- waveorder-2.1.0.dist-info/RECORD,,
15
+ waveorder/models/phase_thick_3d.py,sha256=itGav-JUDcs7YXxxtdtFK95CuaKR759o9ubL7ms8lBk,6590
16
+ waveorder-2.2.0rc0.dist-info/LICENSE,sha256=auz4oGH1A-xZtoiR2zuXIk-Hii4v9aGgFVBqn7nfpms,1509
17
+ waveorder-2.2.0rc0.dist-info/METADATA,sha256=KItkcQO-Bl3Gj-rutxx1V89YkVGYovr-QFo-OUPnAHI,8249
18
+ waveorder-2.2.0rc0.dist-info/WHEEL,sha256=Z4pYXqR_rTB7OWNDYFOm1qRk0RX6GFP2o8LgvP453Hk,91
19
+ waveorder-2.2.0rc0.dist-info/top_level.txt,sha256=i3zReXiiMTnyPk93W7aEz_oEfsLnfR_Kzl7PW7kUslA,10
20
+ waveorder-2.2.0rc0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.2)
2
+ Generator: setuptools (70.3.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5