def test_2d_autofocus_helmholtz_average_gradient_zero(): field = 1 * np.exp(1j * np.linspace(.1, .5, 256)).reshape(16, 16) d = 0 nm = 1.533 res = 8.25 method = "helmholtz" # first propagate the field rfield = nrefocus.refocus(field=field, d=d, nm=nm, res=res, method=method, padding=False) # then try to refocus it _, nfield = nrefocus.autofocus( field=rfield, nm=nm, res=res, ival=(-1.5 * d, -0.5 * d), roi=None, metric="average gradient", minimizer="legacy", padding=False, # without padding, result must be exact num_cpus=1, ) assert np.allclose(nfield.flatten().view(float), rfield.flatten().view(float))
def test_2d_refocus1(): myname = sys._getframe().f_code.co_name rfield = nrefocus.refocus(field=np.arange(256).reshape(16, 16), d=2.13, nm=1.533, res=8.25, method="helmholtz", padding=False) assert np.allclose(np.array(rfield).flatten().view(float), results[myname])
def refocus(self, distance, method="helmholtz", h5file=None, h5mode="a"): """Compute a numerically refocused QPImage Parameters ---------- distance: float Focusing distance [m] method: str Refocusing method, one of ["helmholtz","fresnel"] h5file: str, h5py.Group, h5py.File, or None A path to an hdf5 data file where the QPImage is cached. If set to `None` (default), all data will be handled in memory using the "core" driver of the :mod:`h5py`'s :class:`h5py:File` class. If the file does not exist, it is created. If the file already exists, it is opened with the file mode defined by `hdf5_mode`. If this is an instance of h5py.Group or h5py.File, then this will be used to internally store all data. h5mode: str Valid file modes are (only applies if `h5file` is a path) - "r": Readonly, file must exist - "r+": Read/write, file must exist - "w": Create file, truncate if exists - "w-" or "x": Create file, fail if exists - "a": Read/write if exists, create otherwise (default) Returns ------- qpi: qpimage.QPImage Refocused phase and amplitude data See Also -------- :mod:`nrefocus`: library used for numerical focusing """ field2 = nrefocus.refocus(field=self.field, d=distance/self["pixel size"], nm=self["medium index"], res=self["wavelength"]/self["pixel size"], method=method ) if "identifier" in self: ident = self["identifier"] else: ident = "" meta_data = self.meta meta_data["identifier"] = "{}@{}{:.5e}m".format(ident, method[0], distance) qpi2 = QPImage(data=field2, which_data="field", meta_data=meta_data, h5file=h5file, h5mode=h5mode) return qpi2
def test_refocus(): nrkw = { "res": 2, "nm": 1, "method": "helmholtz", "padding": True, "d": 5.5 } meta = { "wavelength": 1e-6, "pixel size": 1e-6 / nrkw["res"], "medium index": nrkw["nm"] } distance = 5.5 * meta["pixel size"] size = 40 x = (np.arange(size) - size / 2).reshape(-1, 1) y = (np.arange(size) - size / 2).reshape(1, -1) pha = .1 amp = .5 * (1 + (x**2 + y**2 < size / 3)) # make smooth to reduce ringing amp = gaussian_filter(amp, 1) field = amp * np.exp(1j * pha) newfield = nrefocus.refocus(field=field, **nrkw) qpi0 = qpimage.QPImage(data=newfield, which_data="field", meta_data=meta) with pytest.warns(DeprecationWarning, match="kernel"): qpi1 = qpi0.refocus(distance=-distance, method=nrkw["method"]) # sanity assert amp.min() < .51 assert amp.max() > .99 assert qpi1.amp.min() < .51 assert qpi1.amp.max() > .99 assert np.abs(qpi0.pha).max() > 2 * pha # refocusing result assert not np.allclose(qpi0.amp, amp, rtol=0, atol=8e-4) assert not np.allclose(qpi0.pha, pha, rtol=0, atol=3e-4) assert np.allclose(qpi1.amp, amp, rtol=0, atol=8e-4) assert np.allclose(qpi1.pha, pha, rtol=0, atol=3e-4)
def test_2d_autofocus_fresnel_average_gradient(): field = 1 * np.exp(1j * np.linspace(.1, .5, 256)).reshape(16, 16) d = 5 nm = 1.533 res = 8.25 method = "fresnel" # first propagate the field rfield = nrefocus.refocus(field=field, d=d, nm=nm, res=res, method=method) # then try to refocus it _, nfield = nrefocus.autofocus(field=rfield, nm=nm, res=res, ival=(-1.5 * d, -0.5 * d), roi=None, metric="average gradient", minimizer="legacy", padding=True, num_cpus=1) assert np.allclose(0, np.angle(nfield / rfield), atol=.125) assert np.allclose(1, np.abs(nfield / rfield), atol=.147)
def test_refocus_kernel_different(): nrkw1 = {"res": 2, "nm": 1, "padding": True, "d": 5.5} meta = { "wavelength": 1e-6, "pixel size": 1e-6 / nrkw1["res"], "medium index": nrkw1["nm"] } distance = 5.5 * meta["pixel size"] size = 40 x = (np.arange(size) - size / 2).reshape(-1, 1) y = (np.arange(size) - size / 2).reshape(1, -1) pha = .1 amp = .5 * (1 + (x**2 + y**2 < size / 3)) # make smooth to reduce ringing amp = gaussian_filter(amp, 1) field = amp * np.exp(1j * pha) newfield = nrefocus.refocus(field=field, **nrkw1) qpi0 = qpimage.QPImage(data=newfield, which_data="field", meta_data=meta) qpi1 = qpi0.refocus(distance=-distance, kernel="helmholtz") qpi2 = qpi0.refocus(distance=-distance, kernel="fresnel") assert not np.all(qpi1.pha == qpi2.pha)
def test_2d_autofocus_helmholtz_average_gradient(): field = 1 * np.exp(1j * np.linspace(.1, .5, 256)).reshape(16, 16) d = 5 nm = 1.533 res = 8.25 method = "helmholtz" # first propagate the field rfield = nrefocus.refocus(field=field, d=d, nm=nm, res=res, method=method) # then try to refocus it nfield = nrefocus.autofocus( field=rfield, nm=nm, res=res, ival=(-1.5 * d, -0.5 * d), roi=None, metric="average gradient", padding=True, ret_d=False, ret_grad=False, num_cpus=1, ) assert np.allclose(0, np.angle(nfield / rfield), atol=.047) assert np.allclose(1, np.abs(nfield / rfield), atol=.081)
def refocus(img, pixels): img_sqrt = np.sqrt(img.clip(0)) img_temp = nrefocus.refocus(img_sqrt, pixels, 1, 1) return (img_temp * np.conjugate(img_temp)).real
def mie_avg(radius=5e-6, sphere_index=1.339, medium_index=1.333, wavelength=550e-9, pixel_size=1e-7, grid_size=(80, 80), center=(39.5, 39.5), interpolate=3, focus=0, arp=True): """Mie-simulated non-polarized field behind a dielectric sphere Parameters ---------- radius: float Radius of the sphere [m] sphere_index: float Refractive index of the sphere medium_index: float Refractive index of the surrounding medium wavelength: float Vacuum wavelength of the imaging light [m] pixel_size: float Pixel size [m] grid_size: tuple of floats Resulting image size in x and y [px] center: tuple of floats Center position in image coordinates [px] interpolate: int Compute the radial field with sampling that is by a factor of `interpolate` higher than the required data and interpolate the 2D field from there. focus: float .. versionadded:: 0.5.0 Axial focus position [m] measured from the center of the sphere in the direction of light propagation. arp: bool Use arbitrary precision (ARPREC) in BHFIELD computations Returns ------- qpi: qpimage.QPImage Quantitative phase data set """ center = np.array(center) grid_size = np.array(grid_size) # simulation parameters radius_um = radius * 1e6 # radius of sphere in um propd_um = radius_um # simulate propagation through full sphere propd_lamd = radius / wavelength # radius in wavelengths wave_nm = wavelength * 1e9 kwargs = { "radius_sphere_um": radius_um, "refractive_index_medium": medium_index, "refractive_index_sphere": sphere_index, "measurement_position_um": propd_um, "wavelength_nm": wave_nm } upres = wavelength / pixel_size * interpolate max_off = np.max(np.abs(grid_size / 2 - .5 - center)) latsize = int(np.round((np.max(grid_size) + max_off))) num = latsize * upres / 2 # find the maximum interpolation range in the 2d image bignum = int( np.ceil(np.sqrt(np.sum( (np.array(grid_size) / 2 + max_off)**2))) * interpolate) # Compare this number to the radius of the sphere and cut it off at # three times the radius. radnum = int(np.ceil(3 * radius / pixel_size) * interpolate) bignum = min(bignum, radnum) latsize *= bignum / num latsize *= wavelength * 1e6 upres /= wavelength * 1e6 background = np.exp(1j * 2 * np.pi * propd_lamd * medium_index) # [sic]: Not times upres ofx_px = grid_size[0] / 2 - center[0] ofy_px = grid_size[1] / 2 - center[1] kwargsx = kwargs.copy() kwargsx.update({ "size_simulation_um": (latsize / 2, 1 / upres), "shape_grid": (bignum, 1), "offset_x_um": -latsize / 4, "offset_y_um": 0 }) fieldx = simulate_sphere(arp=arp, **kwargsx) / background kwargsy = kwargs.copy() kwargsy.update({ "size_simulation_um": (1 / upres, latsize / 2), "shape_grid": (1, bignum), "offset_x_um": 0, "offset_y_um": -latsize / 4 }) fieldy = simulate_sphere(arp=arp, **kwargsy) / background field = (fieldx.flatten() + fieldy.flatten()) / 2 xo = np.linspace(0, bignum, bignum, endpoint=True) / interpolate x = np.linspace(-grid_size[0] / 2, grid_size[0] / 2, grid_size[0] * interpolate, endpoint=True) y = np.linspace(-grid_size[1] / 2, grid_size[1] / 2, grid_size[1] * interpolate, endpoint=True) yv, xv = np.meshgrid(y, x) r = np.sqrt(xv**2 + yv**2) inpt_kwargs = { "kind": "linear", "assume_sorted": True, "bounds_error": False, } ipltph = spinterp.interp1d(xo, np.unwrap(np.angle(field)), fill_value=0, **inpt_kwargs) ipltam = spinterp.interp1d(xo, np.abs(field), fill_value=1, **inpt_kwargs) phase2d = ipltph(r) field2d = ipltam(r) * np.exp(1j * phase2d) # Numerical refocusing # We need to perform numerical focusing with the upsampled array, # or else we will loose spatial information and the resulting # spherical image becomes asymmetric. refoc_field2d = nrefocus.refocus(field2d, d=-((radius + focus) / pixel_size) * interpolate, nm=medium_index, res=wavelength / pixel_size * interpolate) # Phase (2PI offset corrected) and amplitude ampli, phase = field2ap_corr(refoc_field2d) # Perform new interpolation on requested grid intpp = spinterp.RectBivariateSpline(x, y, phase, kx=1, ky=1) intpa = spinterp.RectBivariateSpline(x, y, ampli, kx=1, ky=1) xp = np.linspace( -grid_size[0] / 2, grid_size[0] / 2, grid_size[0], endpoint=False) + ofx_px yp = np.linspace( -grid_size[1] / 2, grid_size[1] / 2, grid_size[1], endpoint=False) + ofy_px amp_off = intpa(xp, yp) pha_off = intpp(xp, yp) meta_data = { "pixel size": pixel_size, "wavelength": wavelength, "medium index": medium_index, "sim center": center, "sim radius": radius, "sim index": sphere_index, "sim model": "mie-avg", } qpi = qpimage.QPImage(data=(pha_off, amp_off), which_data="phase,amplitude", meta_data=meta_data) return qpi
MNIST_DIGIT_TRAIN_IMGS_PATH)[0] / 255 ten_input = tf.reshape(tf.convert_to_tensor(num_input), (1, 28, 28)) rect_input_no_pad = np.ones((28, 28)) ten_rect_input_no_pad = tf.reshape(tf.convert_to_tensor(rect_input_no_pad), (1, 28, 28)) rect_input = np.zeros((28, 28)) rect_input[10:18, 10:18] = 1 ten_rect_inputs = tf.reshape(tf.convert_to_tensor(rect_input), (1, 28, 28)) import nrefocus for d in D: tensor_out = my_fft_prop(ten_rect_inputs, d) out = nrefocus.refocus(rect_input, d, 1, 1) plt.subplot(311) plt.imshow(tf.abs(tensor_out[0])**2) plt.title("my func") plt.subplot(312) plt.imshow(np.abs(out**2)) plt.title("NREFOCUS") plt.subplot(313) distance = tf.abs(tf.abs(tensor_out[0])**2 - np.abs(out)**2) max = np.max(distance) mean = np.mean(distance) plt.imshow(distance) plt.title("Distance, max = {},mean err = {}".format(max, mean))
interferometry (SID4Bio, Phasics S.A., France). The diameter of the cell is about 20µm. """ import matplotlib.pylab as plt import numpy as np import unwrap import nrefocus from example_helper import load_cell # load initial cell cell1 = load_cell("HL60_field.zip") # refocus to two different positions cell2 = nrefocus.refocus(cell1, 15, 1, 1) # forward cell3 = nrefocus.refocus(cell1, -15, 1, 1) # backward # amplitude range vmina = np.min(np.abs(cell1)) vmaxa = np.max(np.abs(cell1)) ampkw = {"cmap": plt.get_cmap("gray"), "vmin": vmina, "vmax": vmaxa} # phase range cell1p = unwrap.unwrap(np.angle(cell1)) cell2p = unwrap.unwrap(np.angle(cell2)) cell3p = unwrap.unwrap(np.angle(cell3)) vminp = np.min(cell1p) vmaxp = np.max(cell1p) phakw = {"cmap": plt.get_cmap("coolwarm"), "vmin": vminp, "vmax": vmaxp}
def mie(radius=5e-6, sphere_index=1.339, medium_index=1.333, wavelength=550e-9, pixel_size=1e-7, grid_size=(80, 80), center=(39.5, 39.5), focus=0, arp=True): """Mie-simulated field behind a dielectric sphere Parameters ---------- radius: float Radius of the sphere [m] sphere_index: float Refractive index of the sphere medium_index: float Refractive index of the surrounding medium wavelength: float Vacuum wavelength of the imaging light [m] pixel_size: float Pixel size [m] grid_size: tuple of floats Resulting image size in x and y [px] center: tuple of floats Center position in image coordinates [px] focus: float .. versionadded:: 0.5.0 Axial focus position [m] measured from the center of the sphere in the direction of light propagation. arp: bool Use arbitrary precision (ARPREC) in BHFIELD computations Returns ------- qpi: qpimage.QPImage Quantitative phase data set """ # simulation parameters radius_um = radius * 1e6 # radius of sphere in um propd_um = radius_um # simulate propagation through full sphere propd_lamd = radius / wavelength # radius in wavelengths wave_nm = wavelength * 1e9 # Qpsphere models define the position of the sphere with an index in # the array (because it is easier to work with). The pixel # indices run from (0, 0) to grid_size (without endpoint). BHFIELD # requires the extent to be given in µm. The distance in µm between # first and last pixel (measured from pixel center) is # (grid_size - 1) * pixel_size, size_um = (np.array(grid_size) - 1) * pixel_size * 1e6 # The same holds for the offset. If we use size_um here, # we already take into account the half-pixel offset. offset_um = np.array(center) * pixel_size * 1e6 - size_um / 2 kwargs = {"radius_sphere_um": radius_um, "refractive_index_medium": medium_index, "refractive_index_sphere": sphere_index, "measurement_position_um": propd_um, "wavelength_nm": wave_nm, "size_simulation_um": size_um, "shape_grid": grid_size, "offset_x_um": offset_um[0], "offset_y_um": offset_um[1]} background = np.exp(1j * 2 * np.pi * propd_lamd * medium_index) field = simulate_sphere(arp=arp, **kwargs) / background # refocus refoc = nrefocus.refocus(field, d=-((radius+focus) / pixel_size), nm=medium_index, res=wavelength / pixel_size) # Phase (2PI offset corrected) and amplitude amp, pha = field2ap_corr(refoc) meta_data = {"pixel size": pixel_size, "wavelength": wavelength, "medium index": medium_index, "sim center": center, "sim radius": radius, "sim index": sphere_index, "sim model": "mie", } qpi = qpimage.QPImage(data=(pha, amp), which_data="phase,amplitude", meta_data=meta_data) return qpi
A = 200 print("Example: Backpropagation from 3D Mie scattering") print("Refractive index of medium:", cfg["nm"]) print("Measurement position from object center:", cfg["lD"]) print("Wavelength sampling:", cfg["res"]) print("Number of angles for reconstruction:", A) print("Performing backpropagation.") # Reconstruction angles angles = np.linspace(0, 2 * np.pi, A, endpoint=False) # Perform focusing Ex = nrefocus.refocus( Ex, d=-cfg["lD"] * cfg["res"], nm=cfg["nm"], res=cfg["res"], ) # Create sinogram u_sin = np.tile(Ex.flat, A).reshape(A, int(cfg["size"]), int(cfg["size"])) # Apply the Rytov approximation u_sinR = odt.sinogram_as_rytov(u_sin) # Backpropagation fR = odt.backpropagate_3d(uSin=u_sinR, angles=angles, res=cfg["res"], nm=cfg["nm"], lD=0,