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 test_pupilfn_3(): """ Test PF X derivative (C library). """ dx = 1.0e-6 geo = pupilMath.Geometry(20, 0.1, 0.6, 1.5, 1.4) pf = geo.createFromZernike(1.0, [[1.3, 2, 2]]) pf_c = pfFnC.PupilFunction(geometry=geo) pf_c.setPF(pf) # Calculate derivative of magnitude as a function of x. psf_c = pf_c.getPSF() psf_c_dx = pf_c.getPSFdx() mag_dx_calc = 2.0 * (numpy.real(psf_c) * numpy.real(psf_c_dx) + numpy.imag(psf_c) * numpy.imag(psf_c_dx)) # Estimate derivative using (f(x+dx) - f(x))/dx mag = pupilMath.intensity(psf_c) pf_c.translate(dx, 0.0, 0.0) mag_dx_est = (pupilMath.intensity(pf_c.getPSF()) - mag) / dx if False: with tifffile.TiffWriter( storm_analysis.getPathOutputTest("test_pupilfn_3.tif")) as tf: #tf.save(mag.astype(numpy.float32)) tf.save(mag_dx_calc.astype(numpy.float32)) tf.save(mag_dx_est.astype(numpy.float32)) tf.save(numpy.abs(mag_dx_calc - mag_dx_est).astype(numpy.float32)) assert numpy.allclose(mag_dx_calc, mag_dx_est, atol=1.0e-6) pf_c.cleanup()
def test_pupilfn_4(): """ Test PF X derivative (Python library). """ dx = 1.0e-6 geo = pupilMath.Geometry(20, 0.1, 0.6, 1.5, 1.4) pf = geo.createFromZernike(1.0, [[1.3, 2, 2]]) # Calculate derivative of magnitude as a function of x. psf_py = pupilMath.toRealSpace(pf) psf_py_dx = pupilMath.toRealSpace(geo.dx(pf)) mag_dx_calc = 2.0 * (numpy.real(psf_py) * numpy.real(psf_py_dx) + numpy.imag(psf_py) * numpy.imag(psf_py_dx)) # Estimate derivative using (f(x+dx) - f(x))/dx mag = pupilMath.intensity(psf_py) translated = geo.translatePf(pf, dx, 0.0) mag_dx_est = (pupilMath.intensity(pupilMath.toRealSpace(translated)) - mag) / dx if False: with tifffile.TiffWriter( storm_analysis.getPathOutputTest("test_pupilfn_4.tif")) as tf: #tf.save(mag.astype(numpy.float32)) tf.save(mag_dx_calc.astype(numpy.float32)) tf.save(mag_dx_est.astype(numpy.float32)) tf.save(numpy.abs(mag_dx_calc - mag_dx_est).astype(numpy.float32)) assert numpy.allclose(mag_dx_calc, mag_dx_est, atol=1.0e-6)
def test_pupilfn_7(): """ Test that PF translation is correct (i.e. independent of size). """ sizes = [10, 20, 40] dx = 1.0 for size in sizes: geo = pupilMath.Geometry(size, 0.1, 0.6, 1.5, 1.4) pf = geo.createFromZernike(1.0, [[1.3, 2, 2]]) pf_c = pfFnC.PupilFunction(geometry = geo) pf_c.setPF(pf) psf_untranslated = numpy.roll(pupilMath.intensity(pf_c.getPSF()), 1, axis = 0) pf_c.translate(dx, 0.0, 0.0) psf_translated = pupilMath.intensity(pf_c.getPSF()) if False: with tifffile.TiffWriter(storm_analysis.getPathOutputTest("test_pupilfn_7.tif")) as tf: tf.save(psf_untranslated.astype(numpy.float32)) tf.save(psf_translated.astype(numpy.float32)) assert numpy.allclose(psf_untranslated, psf_translated) pf_c.cleanup()
def test_pupilfn_2(): """ Test PF translation. """ dx = 0.5 dy = 0.25 dz = 0.2 geo = pupilMath.Geometry(20, 0.1, 0.6, 1.5, 1.4) pf = geo.createFromZernike(1.0, [[1.3, 2, 2]]) pf_c = pfFnC.PupilFunction(geometry=geo) pf_c.setPF(pf) pf_c.translate(dx, dy, dz) psf_c = pupilMath.intensity(pf_c.getPSF()) defocused = geo.changeFocus(pf, dz) translated = geo.translatePf(defocused, dx, dy) psf_py = pupilMath.intensity(pupilMath.toRealSpace(translated)) if False: with tifffile.TiffWriter( storm_analysis.getPathOutputTest("test_pupilfn_2.tif")) as tf: tf.save(psf_c.astype(numpy.float32)) tf.save(psf_py.astype(numpy.float32)) assert numpy.allclose(psf_c, psf_py) pf_c.cleanup()
def test_pupilfn_7(): """ Test that PF translation is correct (i.e. independent of size). """ sizes = [10, 20, 40] dx = 1.0 for size in sizes: geo = pupilMath.Geometry(size, 0.1, 0.6, 1.5, 1.4) pf = geo.createFromZernike(1.0, [[1.3, 2, 2]]) pf_c = pfFnC.PupilFunction(geometry=geo) pf_c.setPF(pf) psf_untranslated = numpy.roll(pupilMath.intensity(pf_c.getPSF()), 1, axis=0) pf_c.translate(dx, 0.0, 0.0) psf_translated = pupilMath.intensity(pf_c.getPSF()) if False: with tifffile.TiffWriter( storm_analysis.getPathOutputTest( "test_pupilfn_7.tif")) as tf: tf.save(psf_untranslated.astype(numpy.float32)) tf.save(psf_translated.astype(numpy.float32)) assert numpy.allclose(psf_untranslated, psf_translated) pf_c.cleanup()
def test_pupilfn_3(): """ Test PF X derivative (C library). """ dx = 1.0e-6 geo = pupilMath.Geometry(20, 0.1, 0.6, 1.5, 1.4) pf = geo.createFromZernike(1.0, [[1.3, 2, 2]]) pf_c = pfFnC.PupilFunction(geometry = geo) pf_c.setPF(pf) # Calculate derivative of magnitude as a function of x. psf_c = pf_c.getPSF() psf_c_dx = pf_c.getPSFdx() mag_dx_calc = 2.0 * (numpy.real(psf_c)*numpy.real(psf_c_dx) + numpy.imag(psf_c)*numpy.imag(psf_c_dx)) # Estimate derivative using (f(x+dx) - f(x))/dx mag = pupilMath.intensity(psf_c) pf_c.translate(dx,0.0,0.0) mag_dx_est = (pupilMath.intensity(pf_c.getPSF()) - mag)/dx if False: with tifffile.TiffWriter(storm_analysis.getPathOutputTest("test_pupilfn_3.tif")) as tf: #tf.save(mag.astype(numpy.float32)) tf.save(mag_dx_calc.astype(numpy.float32)) tf.save(mag_dx_est.astype(numpy.float32)) tf.save(numpy.abs(mag_dx_calc - mag_dx_est).astype(numpy.float32)) assert numpy.allclose(mag_dx_calc, mag_dx_est, atol = 1.0e-6) pf_c.cleanup()
def test_pupilfn_2(): """ Test PF translation. """ dx = 0.5 dy = 0.25 dz = 0.2 geo = pupilMath.Geometry(20, 0.1, 0.6, 1.5, 1.4) pf = geo.createFromZernike(1.0, [[1.3, 2, 2]]) pf_c = pfFnC.PupilFunction(geometry = geo) pf_c.setPF(pf) pf_c.translate(dx, dy, dz) psf_c = pupilMath.intensity(pf_c.getPSF()) defocused = geo.changeFocus(pf, dz) translated = geo.translatePf(defocused, dx, dy) psf_py = pupilMath.intensity(pupilMath.toRealSpace(translated)) if False: with tifffile.TiffWriter(storm_analysis.getPathOutputTest("test_pupilfn_2.tif")) as tf: tf.save(psf_c.astype(numpy.float32)) tf.save(psf_py.astype(numpy.float32)) assert numpy.allclose(psf_c, psf_py) pf_c.cleanup()
def test_pupilfn_6(): """ Test PF Z derivative (C library). """ dz = 1.0e-6 geo = pupilMath.Geometry(20, 0.1, 0.6, 1.5, 1.4) pf = geo.createFromZernike(1.0, [[1.3, 2, 2]]) pf_c = pfFnC.PupilFunction(geometry=geo) pf_c.setPF(pf) # Calculate derivative of magnitude as a function of z. psf_c = pf_c.getPSF() psf_c_dz = pf_c.getPSFdz() mag_dz_calc = 2.0 * (numpy.real(psf_c) * numpy.real(psf_c_dz) + numpy.imag(psf_c) * numpy.imag(psf_c_dz)) # Estimate derivative using (f(z+dz) - f(z))/dz mag = pupilMath.intensity(psf_c) pf_c.translate(0.0, 0.0, dz) mag_dz_est = (pupilMath.intensity(pf_c.getPSF()) - mag) / dz if False: with tifffile.TiffWriter( storm_analysis.getPathOutputTest("test_pupilfn_6.tif")) as tf: #tf.save(mag.astype(numpy.float32)) tf.save(mag_dz_calc.astype(numpy.float32)) tf.save(mag_dz_est.astype(numpy.float32)) tf.save(numpy.abs(mag_dz_calc - mag_dz_est).astype(numpy.float32)) assert (numpy.max(numpy.abs(mag_dz_calc - mag_dz_est))) < 1.0e-6 pf_c.cleanup()
def test_pupilfn_4(): """ Test PF X derivative (Python library). """ dx = 1.0e-6 geo = pupilMath.Geometry(20, 0.1, 0.6, 1.5, 1.4) pf = geo.createFromZernike(1.0, [[1.3, 2, 2]]) # Calculate derivative of magnitude as a function of x. psf_py = pupilMath.toRealSpace(pf) psf_py_dx = pupilMath.toRealSpace(geo.dx(pf)) mag_dx_calc = 2.0 * (numpy.real(psf_py)*numpy.real(psf_py_dx) + numpy.imag(psf_py)*numpy.imag(psf_py_dx)) # Estimate derivative using (f(x+dx) - f(x))/dx mag = pupilMath.intensity(psf_py) translated = geo.translatePf(pf, dx, 0.0) mag_dx_est = (pupilMath.intensity(pupilMath.toRealSpace(translated)) - mag)/dx if False: with tifffile.TiffWriter(storm_analysis.getPathOutputTest("test_pupilfn_4.tif")) as tf: #tf.save(mag.astype(numpy.float32)) tf.save(mag_dx_calc.astype(numpy.float32)) tf.save(mag_dx_est.astype(numpy.float32)) tf.save(numpy.abs(mag_dx_calc - mag_dx_est).astype(numpy.float32)) assert numpy.allclose(mag_dx_calc, mag_dx_est, atol = 1.0e-6)
def makePSF(filename, size, pixel_size, zmn, zrange, zstep): """ pixel_size - pixel size in microns. zmn - Zernike coefficients. zrange - The final zrange will be +- zrange (microns). zstep - The z step size in microns. """ # # Physical constants. Note that these match the default values for # simulator.psf.PupilFunction(). # wavelength = 0.6 # Fluorescence wavelength in microns. imm_index = 1.5 # Immersion media index (oil objective). NA = 1.4 # Numerical aperture of the objective. # Create geometry object. geo = pupilMath.Geometry(size, pixel_size, wavelength, imm_index, NA) # Create PF. pf = geo.createFromZernike(1.0, zmn) # Normalize to have height 1.0 (at z = 0.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)))) # Create a PSF at each z value. z_values = numpy.arange(-zrange, zrange + 0.5*zstep, zstep) #print(z_values) if ((z_values.size%2)==0): print("The number of z slices must be an odd number.") assert False, "PSF creation failed." psf = numpy.zeros((z_values.size, size, size)) for i, z in enumerate(z_values): defocused = geo.changeFocus(pf, z) psf[i,:,:] = pupilMath.intensity(pupilMath.toRealSpace(defocused)) # Pickle and save. psf_dict = {"psf" : psf, "pixel_size" : pixel_size, "zmax" : 1000.0 * zrange, "zmin" : -1000.0 * zrange} with open(filename, 'wb') as fp: pickle.dump(psf_dict, fp) # Also save a .tif version. with tifffile.TiffWriter("psf.tif") as tf: for i in range(psf.shape[0]): tf.save(psf[i,:,:].astype(numpy.float32))
def makePSF(filename, size, pixel_size, zmn, zrange, zstep): """ pixel_size - pixel size in microns. zmn - Zernike coefficients. zrange - The final zrange will be +- zrange (microns). zstep - The z step size in microns. """ # # Physical constants. Note that these match the default values for # simulator.psf.PupilFunction(). # wavelength = 0.6 # Fluorescence wavelength in microns. imm_index = 1.5 # Immersion media index (oil objective). NA = 1.4 # Numerical aperture of the objective. # Create geometry object. geo = pupilMath.Geometry(size, pixel_size, wavelength, imm_index, NA) # Create PF. pf = geo.createFromZernike(1.0, zmn) # Normalize to have height 1.0 (at z = 0.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)))) # Create a PSF at each z value. z_values = numpy.arange(-zrange, zrange + 0.5 * zstep, zstep) #print(z_values) if ((z_values.size % 2) == 0): print("The number of z slices must be an odd number.") assert False, "PSF creation failed." psf = numpy.zeros((z_values.size, size, size)) for i, z in enumerate(z_values): defocused = geo.changeFocus(pf, z) psf[i, :, :] = pupilMath.intensity(pupilMath.toRealSpace(defocused)) # Pickle and save. psf_dict = { "psf": psf, "pixel_size": pixel_size, "zmax": 1000.0 * zrange, "zmin": -1000.0 * zrange } with open(filename, 'wb') as fp: pickle.dump(psf_dict, fp) # Also save a .tif version. with tifffile.TiffWriter("psf.tif") as tf: for i in range(psf.shape[0]): tf.save(psf[i, :, :].astype(numpy.float32))
def getPSFs(self, i3_data): """ The expected form for the i3 data fields are x,y in pixels and z in nanometers. """ image = numpy.zeros((self.im_size_x, self.im_size_y)) x = i3_data['x'] # Pixels y = i3_data['y'] # Pixels z = i3_data['z']*0.001 # Expected to be in nanometers. a = i3_data['a'] dx = x - numpy.floor(x) dy = y - numpy.floor(y) for i in range(x.size): ix = int(x[i]) iy = int(y[i]) if (ix >= 0.0) and (ix < self.x_size) and (iy >= 0.0) and (iy < self.y_size): # Shift to the desired z value. defocused = self.geo.changeFocus(self.pf, z[i]) # Translate to the correct sub-pixel position. #translated = defocused translated = self.geo.translatePf(defocused, dx[i], dy[i]) # Get real-space intensity. psf = pupilMath.intensity(pupilMath.toRealSpace(translated)) * a[i] i3_data['h'][i] = numpy.max(psf) image[ix:ix+self.psf_size,iy:iy+self.psf_size] += psf return image[self.margin:self.margin+self.x_size,self.margin:self.margin+self.y_size]
def getPSFs(self, i3_data): """ The expected form for the i3 data fields are x,y in pixels and z in nanometers. """ image = numpy.zeros((self.im_size_x, self.im_size_y)) x = i3_data['x'] # Pixels y = i3_data['y'] # Pixels z = i3_data['z']*0.001 # Expected to be in nanometers. a = i3_data['a'] dx = x - numpy.floor(x) dy = y - numpy.floor(y) for i in range(x.size): ix = int(x[i]) iy = int(y[i]) if (ix >= 0.0) and (ix < self.x_size) and (iy >= 0.0) and (iy < self.y_size): # Shift to the desired z value. defocused = self.geo.changeFocus(self.pf, z[i]) # Translate to the correct sub-pixel position. #translated = defocused translated = self.geo.translatePf(defocused, dx[i], dy[i]) # Get real-space intensity. psf = pupilMath.intensity(pupilMath.toRealSpace(translated)) * a[i] i3_data['h'][i] = numpy.max(psf) image[ix:ix+self.psf_size,iy:iy+self.psf_size] += psf return image[self.margin:self.margin+self.x_size,self.margin:self.margin+self.y_size]
def test_psf_fft2(): """ Test translated PSF calculation. """ dx = 0.5 dy = 0.25 dz = 0.2 [pf_psf, geo, pf] = makePSFAndPF(-0.4, 0.4, 0.05) pfft = psfFFTC.PSFFFT(pf_psf) pfft.translate(dy, dx, dz*(pf_psf.shape[0] - 1)/0.8) psf_fft = pfft.getPSF() defocused = geo.changeFocus(pf, dz) translated = geo.translatePf(defocused, dx, dy) psf_pf = pupilMath.intensity(pupilMath.toRealSpace(translated)) if False: print(numpy.max(numpy.abs(psf_fft - psf_pf))) with tifffile.TiffWriter(storm_analysis.getPathOutputTest("test_psf_fft2.tif")) as tf: tf.save(psf_fft.astype(numpy.float32)) tf.save(psf_pf.astype(numpy.float32)) assert (numpy.max(numpy.abs(psf_fft - psf_pf))) < 1.0e-10 pfft.cleanup()
def test_psf_fft2(): """ Test translated PSF calculation. """ dx = 0.5 dy = 0.25 dz = 0.2 [pf_psf, geo, pf] = makePSFAndPF(-0.4, 0.4, 0.05) pfft = psfFFTC.PSFFFT(pf_psf) pfft.translate(dy, dx, dz * (pf_psf.shape[0] - 1) / 0.8) psf_fft = pfft.getPSF() defocused = geo.changeFocus(pf, dz) translated = geo.translatePf(defocused, dx, dy) psf_pf = pupilMath.intensity(pupilMath.toRealSpace(translated)) if False: print(numpy.max(numpy.abs(psf_fft - psf_pf))) with tifffile.TiffWriter( storm_analysis.getPathOutputTest("test_psf_fft2.tif")) as tf: tf.save(psf_fft.astype(numpy.float32)) tf.save(psf_pf.astype(numpy.float32)) assert (numpy.max(numpy.abs(psf_fft - psf_pf))) < 1.0e-10 pfft.cleanup()
def getPSFs(self, h5_data): """ The expected form for the h5 data fields are x,y in pixels and z in microns. """ image = numpy.zeros((self.im_size_x, self.im_size_y)) x = h5_data['x'] + 1 # Pixels y = h5_data['y'] + 1 # Pixels z = h5_data['z'] # Expected to be in microns. a = h5_data['sum'] h5_data['height'] = numpy.zeros(a.size) dx = x - numpy.floor(x) dy = y - numpy.floor(y) for i in range(x.size): ix = int(x[i]) iy = int(y[i]) if (ix >= 0.0) and (ix < self.x_size) and (iy >= 0.0) and ( iy < self.y_size): pf = self.pf # Apply aberration function if available. ab_fn = self.getAberrationFn(z[i]) if ab_fn is not None: pf = pf * ab_fn # Shift to the desired z value. defocused = self.geo.changeFocus(pf, z[i]) # Translate to the correct sub-pixel position. #translated = defocused translated = self.geo.translatePf(defocused, dx[i], dy[i]) # Get real-space intensity. psf = pupilMath.intensity( pupilMath.toRealSpace(translated)) * a[i] # Apply OTF scaling if requested. if self.otf_scaler is not None: otf = scipy.fftpack.fftshift(scipy.fftpack.fft2(psf)) otf_scaled = otf * self.otf_scaler psf = numpy.abs(scipy.fftpack.ifft2(otf_scaled)) h5_data['height'][i] = numpy.max(psf) image[ix:ix + self.psf_size, iy:iy + self.psf_size] += psf return image[self.margin:self.margin + self.x_size, self.margin:self.margin + self.y_size]
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 test_pupilfn_1(): """ Test that the C and the Python library agree on the calculation of the untranslated PSF. """ geo = pupilMath.Geometry(20, 0.1, 0.6, 1.5, 1.4) pf = geo.createFromZernike(1.0, [[1.3, 2, 2]]) pf_c = pfFnC.PupilFunction(geometry = geo) pf_c.setPF(pf) psf_c = pupilMath.intensity(pf_c.getPSF()) psf_py = pupilMath.intensity(pupilMath.toRealSpace(pf)) if False: with tifffile.TiffWriter(storm_analysis.getPathOutputTest("test_pupilfn_1.tif")) as tf: tf.save(psf_c.astype(numpy.float32)) tf.save(psf_py.astype(numpy.float32)) assert numpy.allclose(psf_c, psf_py) pf_c.cleanup()
def test_pupilfn_1(): """ Test that the C and the Python library agree on the calculation of the untranslated PSF. """ geo = pupilMath.Geometry(20, 0.1, 0.6, 1.5, 1.4) pf = geo.createFromZernike(1.0, [[1.3, 2, 2]]) pf_c = pfFnC.PupilFunction(geometry=geo) pf_c.setPF(pf) psf_c = pupilMath.intensity(pf_c.getPSF()) psf_py = pupilMath.intensity(pupilMath.toRealSpace(pf)) if False: with tifffile.TiffWriter( storm_analysis.getPathOutputTest("test_pupilfn_1.tif")) as tf: tf.save(psf_c.astype(numpy.float32)) tf.save(psf_py.astype(numpy.float32)) assert numpy.allclose(psf_c, psf_py) pf_c.cleanup()
def test_pupilfn_10(): """ Test C library PSF intensity calculation. """ geo = pupilMath.Geometry(20, 0.1, 0.6, 1.5, 1.4) pf = geo.createFromZernike(1.0, [[1.3, -1, 3], [1.3, -2, 2]]) pf_c = pfFnC.PupilFunction(geometry=geo) pf_c.setPF(pf) psf_c = pf_c.getPSFIntensity() psf_py = pupilMath.intensity(pupilMath.toRealSpace(pf)) assert numpy.allclose(psf_c, psf_py) pf_c.cleanup()
def makePSFAndPF(zmin, zmax, zstep): """ Creates the PSF and PF used for testing. """ size = 20 geo = pupilMath.Geometry(size, 0.1, 0.6, 1.5, 1.4) pf = geo.createFromZernike(1.0, [[1.3, 2, 2]]) z_values = numpy.arange(zmin, zmax + 0.5*zstep, zstep) psf = numpy.zeros((z_values.size, size, size)) for i, z in enumerate(z_values): defocused = geo.changeFocus(pf, z) psf[i,:,:] = pupilMath.intensity(pupilMath.toRealSpace(defocused)) return [psf, geo, pf]
def makePSFAndPF(zmin, zmax, zstep): """ Creates the PSF and PF used for testing. """ size = 20 geo = pupilMath.Geometry(size, 0.1, 0.6, 1.5, 1.4) pf = geo.createFromZernike(1.0, [[1.3, 2, 2]]) z_values = numpy.arange(zmin, zmax + 0.5 * zstep, zstep) psf = numpy.zeros((z_values.size, size, size)) for i, z in enumerate(z_values): defocused = geo.changeFocus(pf, z) psf[i, :, :] = pupilMath.intensity(pupilMath.toRealSpace(defocused)) return [psf, geo, pf]
def test_pupilfn_10(): """ Test C library PSF intensity calculation. """ geo = pupilMath.Geometry(20, 0.1, 0.6, 1.5, 1.4) pf = geo.createFromZernike(1.0, [[1.3, -1, 3], [1.3, -2, 2]]) pf_c = pfFnC.PupilFunction(geometry = geo) pf_c.setPF(pf) psf_c = pf_c.getPSFIntensity() psf_py = pupilMath.intensity(pupilMath.toRealSpace(pf)) assert numpy.allclose(psf_c, psf_py) pf_c.cleanup()
def test_psf_fft1(): """ Test untranslated PSF calculation. """ [pf_psf, geo, pf] = makePSFAndPF(-0.4, 0.4, 0.05) pfft = psfFFTC.PSFFFT(pf_psf) psf_fft = pfft.getPSF() psf_pf = pupilMath.intensity(pupilMath.toRealSpace(pf)) if False: print(numpy.max(numpy.abs(psf_fft - psf_pf))) with tifffile.TiffWriter(storm_analysis.getPathOutputTest("test_psf_fft1.tif")) as tf: tf.save(psf_fft.astype(numpy.float32)) tf.save(psf_pf.astype(numpy.float32)) assert (numpy.max(numpy.abs(psf_fft - psf_pf))) < 1.0e-10 pfft.cleanup()
def test_pupilfn_11(): """ Test C library PF Z translation function. """ geo = pupilMath.Geometry(20, 0.1, 0.6, 1.5, 1.4) pf = geo.createFromZernike(1.0, [[1.3, -1, 3], [1.3, -2, 2]]) pf_c = pfFnC.PupilFunction(geometry = geo) pf_c.setPF(pf) for dz in [-0.2, 0.1, 0.0, 0.1, 0.2]: pf_c.translateZ(dz) psf_c = pf_c.getPSFIntensity() defocused = geo.changeFocus(pf, dz) psf_py = pupilMath.intensity(pupilMath.toRealSpace(defocused)) assert numpy.allclose(psf_c, psf_py) pf_c.cleanup()
def test_psf_fft1(): """ Test untranslated PSF calculation. """ [pf_psf, geo, pf] = makePSFAndPF(-0.4, 0.4, 0.05) pfft = psfFFTC.PSFFFT(pf_psf) psf_fft = pfft.getPSF() psf_pf = pupilMath.intensity(pupilMath.toRealSpace(pf)) if False: print(numpy.max(numpy.abs(psf_fft - psf_pf))) with tifffile.TiffWriter( storm_analysis.getPathOutputTest("test_psf_fft1.tif")) as tf: tf.save(psf_fft.astype(numpy.float32)) tf.save(psf_pf.astype(numpy.float32)) assert (numpy.max(numpy.abs(psf_fft - psf_pf))) < 1.0e-10 pfft.cleanup()
def test_pupilfn_11(): """ Test C library PF Z translation function. """ geo = pupilMath.Geometry(20, 0.1, 0.6, 1.5, 1.4) pf = geo.createFromZernike(1.0, [[1.3, -1, 3], [1.3, -2, 2]]) pf_c = pfFnC.PupilFunction(geometry=geo) pf_c.setPF(pf) for dz in [-0.2, 0.1, 0.0, 0.1, 0.2]: pf_c.translateZ(dz) psf_c = pf_c.getPSFIntensity() defocused = geo.changeFocus(pf, dz) psf_py = pupilMath.intensity(pupilMath.toRealSpace(defocused)) assert numpy.allclose(psf_c, psf_py) pf_c.cleanup()
def getPSF(self, z_value, shape=None, normalize=False): """ Z value is expected to be in nanometers. """ # Convert z_value to microns. z_value = 1.0e-3 * z_value # Translate to the correct z value. self.pupil_fn_c.translate(0.0, 0.0, z_value) # Get the (complex) PSF. psf = self.pupil_fn_c.getPSF() # Convert to intensity psf = pupilMath.intensity(psf) # Center into a (larger) array if requested. if shape is not None: psf_size = psf.shape[0] im_size_x = shape[0] im_size_y = shape[1] start_x = int(im_size_x / 2.0 - psf_size / 2.0) start_y = int(im_size_y / 2.0 - psf_size / 2.0) end_x = start_x + psf_size end_y = start_y + psf_size temp = numpy.zeros((im_size_x, im_size_y)) temp[start_x:end_x, start_y:end_y] = psf psf = temp # Normalize if requested. if normalize: psf = psf / numpy.sum(psf) return psf
def getPSF(self, z_value, shape = None, normalize = False): """ Z value is expected to be in nanometers. """ # Convert z_value to microns. z_value = 1.0e-3 * z_value # Translate to the correct z value. self.pupil_fn_c.translate(0.0, 0.0, z_value) # Get the (complex) PSF. psf = self.pupil_fn_c.getPSF() # Convert to intensity psf = pupilMath.intensity(psf) # Center into a (larger) array if requested. if shape is not None: psf_size = psf.shape[0] im_size_x = shape[0] im_size_y = shape[1] start_x = int(im_size_x/2.0 - psf_size/2.0) start_y = int(im_size_y/2.0 - psf_size/2.0) end_x = start_x + psf_size end_y = start_y + psf_size temp = numpy.zeros((im_size_x, im_size_y)) temp[start_x:end_x,start_y:end_y] = psf psf = temp # Normalize if requested. if normalize: psf = psf/numpy.sum(psf) return psf
def getPSF(self, z_value): self.translate(z_value) psf_c = self.pupil_fn_c.getPSF() return numpy.transpose(pupilMath.intensity(psf_c))
def getPSF(self, z_value): self.translate(z_value) psf_c = self.pupil_fn_c.getPSF() return numpy.transpose(pupilMath.intensity(psf_c))
def makePupilFunction(filename, size, pixel_size, zmn, z_offset = 0.0, geo_sim_pf = True): """ filename - The name of the file to save the pupil function in. size - The size of the pupil function in pixels. pixel_size - pixel size in microns. zmn - Zernike coefficients. z_offset - Amount to change the focus by in microns. geo_sim_pf - Use the 'simulation' PF with 1/2 the pixel size. """ # 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)
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)