def __init__(self, sim_fp, x_size, y_size, h5_data, nm_per_pixel, zmn, wavelength=pf_wavelength, refractive_index=pf_refractive_index, numerical_aperture=pf_numerical_aperture, pf_size=pf_size, geo_sim_pf=True): """ zmn is a list of lists containing the zernike mode terms, e.g. [[1.3, 2, 2]] for pure astigmatism. wavelength is the mean emission wavelength in nm. """ super(PupilFunction, self).__init__(sim_fp, x_size, y_size, h5_data, nm_per_pixel) self.saveJSON({ "psf": { "class": "PupilFunction", "geo_sim_pf": str(geo_sim_pf), "nm_per_pixel": str(nm_per_pixel), "numerical_aperture": str(numerical_aperture), "pf_size": str(pf_size), "refactrive_index": str(refractive_index), "wavelength": str(wavelength), "zmn": str(zmn) } }) if geo_sim_pf: self.geo = pupilMath.GeometrySim(pf_size, nm_per_pixel * 0.001, wavelength * 0.001, refractive_index, numerical_aperture) else: self.geo = pupilMath.Geometry(pf_size, nm_per_pixel * 0.001, wavelength * 0.001, refractive_index, numerical_aperture) self.pf = self.geo.createFromZernike(1.0, zmn) self.psf_size = self.geo.r.shape[0] if ((self.psf_size % 2) == 0): self.margin = int(self.psf_size / 2) + 1 else: self.margin = int(self.psf_size / 2) + 2 self.im_size_x = self.x_size + 2 * self.margin self.im_size_y = self.y_size + 2 * self.margin
def __init__(self, psf_filename=None, zmax=None, zmin=None, **kwds): kwds["psf_filename"] = psf_filename super(CRPupilFn, self).__init__(**kwds) # Load the pupil function data. with open(psf_filename, 'rb') as fp: pf_data = pickle.load(fp) # Get the pupil function and verify that the type is correct. pf = pf_data['pf'] assert (pf.dtype == numpy.complex128) # Get the pupil function pixel size. self.pupil_size = pf.shape[0] # Create geometry object. if pf_data.get("geo_sim_pf", False): geo = pupilMath.GeometrySim(self.pupil_size, pf_data['pixel_size'], pf_data['wavelength'], pf_data['immersion_index'], pf_data['numerical_aperture']) else: geo = pupilMath.Geometry(self.pupil_size, pf_data['pixel_size'], pf_data['wavelength'], pf_data['immersion_index'], pf_data['numerical_aperture']) # Create C pupil function object. self.pupil_fn_c = pupilFnC.PupilFunction(geo) self.pupil_fn_c.setPF(pf) # Additional initializations. self.zmax = zmax * 1.0e+3 self.zmin = zmin * 1.0e+3 # CR weights approximately every 25nm. self.n_zvals = int(round((self.zmax - self.zmin) / 25.0)) self.delta_xy = self.pixel_size self.delta_z = 1000.0
def test_pupilfn_8(): """ Test that pupilfn.make_pupil_fn.makePupilFunction works as expected. """ pf_size = 30 zmn = [[1.3, 2, 2]] z_offset = -0.3 # Create & save pupil function. pf_file = storm_analysis.getPathOutputTest("pf_test.pfn") makePupilFn.makePupilFunction(pf_file, pf_size, 0.1, zmn, z_offset=z_offset) # Load PF. with open(pf_file, "rb") as fp: pf_data = pickle.load(fp) test_pf = pf_data["pf"] # Create comparison PF. geo = pupilMath.GeometrySim(pf_size, pf_data["pixel_size"], pf_data["wavelength"], pf_data["immersion_index"], pf_data["numerical_aperture"]) ref_pf = geo.createFromZernike(1.0, zmn) # Normalize reference to also have height 1.0 (at z = 0.0). psf = pupilMath.intensity(pupilMath.toRealSpace(ref_pf)) ref_pf = ref_pf * 1.0 / math.sqrt(numpy.max(psf)) # Test that they are the same. for z in [-0.2, -0.1, 0.0, 0.1, 0.2]: test_psf = pupilMath.intensity( pupilMath.toRealSpace(geo.changeFocus(test_pf, z))) ref_psf = pupilMath.intensity( pupilMath.toRealSpace(geo.changeFocus(ref_pf, z - z_offset))) #print(numpy.max(numpy.abs(test_psf - ref_psf))) assert numpy.allclose(test_psf, ref_psf)
def __init__(self, pf_filename = None, zmin = None, zmax = None, **kwds): """ Technically a pupil function would cover any z range, but in fitting we are limit it to a finite range. Also, zmin and zmax should be specified in nanometers. """ super(PupilFunction, self).__init__(**kwds) self.zmax = zmax self.zmin = zmin # Load the pupil function data. with open(pf_filename, 'rb') as fp: pf_data = pickle.load(fp) # Get the pupil function and verify that the type is correct. pf = pf_data['pf'] assert (pf.dtype == numpy.complex128) # Get the pupil function size and pixel size. self.pixel_size = pf_data['pixel_size'] self.pupil_size = pf.shape[0] # Create geometry object. if pf_data.get("geo_sim_pf", False): geo = pupilMath.GeometrySim(self.pupil_size, self.pixel_size, pf_data['wavelength'], pf_data['immersion_index'], pf_data['numerical_aperture']) else: geo = pupilMath.Geometry(self.pupil_size, self.pixel_size, pf_data['wavelength'], pf_data['immersion_index'], pf_data['numerical_aperture']) # Create C pupil function object. self.pupil_fn_c = pupilFnC.PupilFunction(geo) self.pupil_fn_c.setPF(pf)
def makePupilFunction(filename, size, pixel_size, zmn, z_offset=0.0, geo_sim_pf=True): """ geo_sim_pf - Use the 'simulation' PF with 1/2 the pixel size. pixel_size - pixel size in microns. zmn - Zernike coefficients. z_offset - Amount to change the focus by in microns. """ # This is a requirement of the C library. assert ((size % 2) == 0) # Physical constants. Note that these match the default values for # simulator.psf.PupilFunction(). # wavelength = 1.0e-3 * simPSF.pf_wavelength # Fluorescence wavelength in microns. imm_index = simPSF.pf_refractive_index # Immersion media index (oil objective). NA = simPSF.pf_numerical_aperture # Numerical aperture of the objective. # Create geometry object. if geo_sim_pf: geo = pupilMath.GeometrySim(size, pixel_size, wavelength, imm_index, NA) else: geo = pupilMath.Geometry(size, pixel_size, wavelength, imm_index, NA) # Create PF. pf = geo.createFromZernike(1.0, zmn) # Normalize to have height 1.0. psf = pupilMath.intensity(pupilMath.toRealSpace(pf)) pf = pf * 1.0 / math.sqrt(numpy.max(psf)) # Verify normalization. print("Height:", numpy.max(pupilMath.intensity(pupilMath.toRealSpace(pf)))) # Heh, if zmn is an empty list the pupil function will be perfectly # symmetric at z = 0 and the solver will fail because dz = 0. So we # solve this we adding a little noise. if (len(zmn) == 0): print("Plane wave PF detected! Adding noise to break z = 0 symmetry!") n_mag = numpy.real(pf) * 1.0e-3 pf = pf + n_mag * (numpy.random.uniform(size=pf.shape) - 0.5) # Change focus by z_offset. # # The convention is that if z_offset + localization z is the final # z position, so if localization z is = -z_offset then you will get # the PSF at z = 0. # pf = geo.changeFocus(pf, -z_offset) # Pickle and save. pfn_dict = { "pf": pf, "pixel_size": pixel_size, "geo_sim_pf": geo_sim_pf, "wavelength": wavelength, "immersion_index": imm_index, "numerical_aperture": NA } with open(filename, 'wb') as fp: pickle.dump(pfn_dict, fp)