def main(): args = parse_args() syris.init() # Propagate to 20 cm d = 5 * q.cm # Compute grid n_camera = 256 n = n_camera * args.supersampling shape = (n, n) material = get_material("pmma_5_30_kev.mat") energy = 15 * q.keV ps = 1 * q.um ps_hd = ps / args.supersampling radius = n / 4.0 * ps_hd fmt = " Wavelength: {}" print(fmt.format(energy_to_wavelength(energy))) fmt = "Pixel size used for propagation: {}" print(fmt.format(ps_hd.rescale(q.um))) print(" Field of view: {}".format(n * ps_hd.rescale(q.um))) fmt = " Sphere diameter: {}" print(fmt.format(2 * radius)) sample = make_sphere(n, radius, pixel_size=ps_hd, material=material) projection = sample.project((n, n), ps_hd).get() * 1e6 projection = decimate(projection, (n_camera, n_camera), average=True).get() # Propagation with a monochromatic plane incident wave hd = propagate([sample], shape, [energy], d, ps_hd).get() ld = decimate(hd, (n_camera, n_camera), average=True).get() kernel = compute_tie_kernel(n_camera, ps, d, material, energy) mju = material.get_attenuation_coefficient(energy).rescale(1 / q.m).magnitude f_ld = fft_2(ld) f_ld *= get_array(kernel.astype(cfg.PRECISION.np_float)) retrieved = ifft_2(f_ld).get().real retrieved = -1 / mju * np.log(retrieved) * 1e6 if args.output_thickness: imageio.imwrite(args.output_thickness, projection) if args.output_projection: imageio.imwrite(args.output_projection, ld) if args.output_retrieved: imageio.imwrite(args.output_retrieved, retrieved) show(hd, title="High resolution") show(ld, title="Low resolution (detector)") show(retrieved, title="Retrieved [um]") show(projection, title="Projection [um]") show(projection - retrieved, title="Projection - retrieved") plt.show()
def test_decimate(self): n = 16 sigma = fwnm_to_sigma(1) shape = (n // 2, n // 2) image = np.arange(n * n).reshape(n, n).astype(cfg.PRECISION.np_float) // n ** 2 fltr = get_gauss_2d((n, n), sigma, fourier=True) filtered = np.fft.ifft2(np.fft.fft2(image) * fltr).real gt = bin_cpu(filtered, shape) res = ip.decimate(image, shape, sigma=sigma, average=False).get() np.testing.assert_almost_equal(gt, res, decimal=6) # With averaging res = ip.decimate(image, shape, sigma=sigma, average=True).get() gt = gt / 4 np.testing.assert_almost_equal(gt, res, decimal=6)
def test_decimate(self): n = 16 sigma = fwnm_to_sigma(1) shape = (n / 2, n / 2) image = np.arange(n * n).reshape(n, n).astype(cfg.PRECISION.np_float) / n ** 2 fltr = get_gauss_2d((n, n), sigma, fourier=True) filtered = np.fft.ifft2(np.fft.fft2(image) * fltr).real gt = bin_cpu(filtered, shape) res = ip.decimate(image, shape, sigma=sigma, average=False).get() np.testing.assert_almost_equal(gt, res, decimal=6) # With averaging res = ip.decimate(image, shape, sigma=sigma, average=True).get() gt = gt / 4 np.testing.assert_almost_equal(gt, res, decimal=6)
def get_image(self, photons, shot_noise=True, amplifier_noise=True, psf=True, queue=None): """Get digital counts image from incoming *photons*. The resulting image is based on the incoming photons and dark current. We apply noise based on EMVA 1288 standard according to which the variance :math:`\sigma_y^2 = K^2 ( \sigma_e^2 + \sigma_d^2 ) + \sigma_q^2`, where :math:`K` is the system gain, :math:`\sigma_e^2` is the poisson- distributed shot noise variance, :math:`\sigma_d^2` is the normal distributed electronics noise variance and :math:`\sigma_q^2` is the quantization noise variance. If *shot_noise* is False don't apply it. If *amplifier_noise* is False don't apply it as well. If *psf* is False don't apply the point spread function. """ if self._last_input_shape != photons.shape: self._last_input_shape = photons.shape self._bin_factor = (photons.shape[0] / self.shape[0], photons.shape[1] / self.shape[1]) if queue is None: queue = cfg.OPENCL.queue # Shot noise # Adjust dark current for later binning and gain dark = float( self.dark_current) / self._bin_factor[0] / self._bin_factor[1] electrons = dark + gutil.get_host(photons) if self._bin_factor != (1, 1): if psf: sigma = (fwnm_to_sigma(self._bin_factor[0]), fwnm_to_sigma(self._bin_factor[1])) small = decimate(electrons, self.shape, sigma=sigma, queue=queue) else: small = bin_image(electrons, self.shape, queue=queue) electrons = gutil.get_host(small) if shot_noise: electrons = np.random.poisson(electrons) if amplifier_noise and self.amplifier_sigma > 0: # Add electronics noise electrons = np.random.normal(electrons, self.amplifier_sigma) counts = self.gain * electrons # Cut the values beyond the maximum represented grey value given by # bytes per pixel. counts[counts > self.max_grey_value] = self.max_grey_value # Apply quantization noise return counts.astype(self.dtype)
def get_image(self, photons, shot_noise=True, amplifier_noise=True, psf=True, queue=None): """Get digital counts image from incoming *photons*. The resulting image is based on the incoming photons and dark current. We apply noise based on EMVA 1288 standard according to which the variance :math:`\sigma_y^2 = K^2 ( \sigma_e^2 + \sigma_d^2 ) + \sigma_q^2`, where :math:`K` is the system gain, :math:`\sigma_e^2` is the poisson- distributed shot noise variance, :math:`\sigma_d^2` is the normal distributed electronics noise variance and :math:`\sigma_q^2` is the quantization noise variance. If *shot_noise* is False don't apply it. If *amplifier_noise* is False don't apply it as well. If *psf* is False don't apply the point spread function. """ if self._last_input_shape != photons.shape: self._last_input_shape = photons.shape self._bin_factor = (photons.shape[0] / self.shape[0], photons.shape[1] / self.shape[1]) if queue is None: queue = cfg.OPENCL.queue # Shot noise # Adjust dark current for later binning and gain dark = float(self.dark_current) / self._bin_factor[0] / self._bin_factor[1] electrons = dark + gutil.get_host(photons) if self._bin_factor != (1, 1): if psf: sigma = (fwnm_to_sigma(self._bin_factor[0]), fwnm_to_sigma(self._bin_factor[1])) small = decimate(electrons, self.shape, sigma=sigma, queue=queue) else: small = bin_image(electrons, self.shape, queue=queue) electrons = gutil.get_host(small) if shot_noise: electrons = np.random.poisson(electrons) if amplifier_noise and self.amplifier_sigma > 0: # Add electronics noise electrons = np.random.normal(electrons, self.amplifier_sigma) counts = self.gain * electrons # Cut the values beyond the maximum represented grey value given by # bytes per pixel. counts[counts > self.max_grey_value] = self.max_grey_value # Apply quantization noise return counts.astype(self.dtype)