Camera#
With the camera object, the sensor size, the noise parameters and the particle image diameter can be controlled.
import matplotlib.pyplot as plt
import numpy as np
import synpivimage
Particle Image diameter#
According to Raffel et al., the particle image diameter (particle diameter on the sensor) is defined where the Gaussian distribution drops to e-2, thus where 95% of scattered light is contained. This is where the (half) width of the distribution is equal to \(2\sigma\).
In the following, we will create three different images where a particle sits at (x=4 px, y=4 px). We will vary the image particle diamter:
one_particle = synpivimage.Particles(
x=4,
y=4,
z=0,
size=2 # this is NOT the image particle size!
)
laser = synpivimage.Laser(shape_factor=10**3, width=1)
cam = synpivimage.Camera(
nx=8,
ny=8,
bit_depth=16,
qe=1,
sensitivity=1,
baseline_noise=0,
dark_noise=0,
shot_noise=False,
fill_ratio_x=1.0,
fill_ratio_y=1.0,
particle_image_diameter=2,
seed=10
)
cam.particle_image_diameter = 1
img1, _ = synpivimage.take_image(laser, cam, one_particle, 1000)
cam.particle_image_diameter = 2
img2, _ = synpivimage.take_image(laser, cam, one_particle, 1000)
cam.particle_image_diameter = 4
img4, _ = synpivimage.take_image(laser, cam, one_particle, 1000)
The plot below shows the different particle image distribution profiles for image particle diameters of 1, 2 and 4 pixels:
plt.plot(img1[4, : ], label='$d_p=1$ px')
plt.plot(img2[4, : ], label='$d_p=2$ px')
plt.plot(img4[4, : ], label='$d_p=4$ px')
plt.legend()
<matplotlib.legend.Legend at 0x7f2522143fa0>
Modelling of noise#
Two noise sources are modeled:
Gaussian noise (baseline+dark noise), which is independent of the photon counts
Photon shot noise, which is dependent on the photon counts (Poisson distribution)
Mind taking a look here, which shows a very similar implementation of a noise model.
import matplotlib.pyplot as plt
import numpy as np
import synpivimage
Let’s first take an image without a particle. This can be done by placing a particle outside of the sensor FOV:
no_particles = synpivimage.Particles(
x=-100,
y=-100,
z=0,
size=2
)
laser = synpivimage.Laser(shape_factor=10**3, width=1)
Settings#
The noise is controlled via the camera object (baseline, dark_noise and shot_noise). The “randomness” can be controlled via seed (to reproduce results, seed=None produces random results)
Gauss noise#
No noise (\(\mu\)=0/\(\sigma\)=0)#
cam = synpivimage.Camera(
nx=128,
ny=128,
bit_depth=16,
qe=1,
sensitivity=1,
baseline_noise=0,
dark_noise=0,
shot_noise=False,
fill_ratio_x=1.0,
fill_ratio_y=1.0,
particle_image_diameter=2,
seed=10
)
img, _ = synpivimage.take_image(particles=no_particles,
camera=cam, laser=laser,
particle_peak_count=1000)
plt.imshow(img)
plt.title(f"$\mu$= {cam.baseline_noise}, $\sigma$={cam.dark_noise}")
Text(0.5, 1.0, '$\\mu$= 0.0, $\\sigma$=0.0')
Noise \(\mu\)=50/\(\sigma\)=10#
cam = synpivimage.Camera( nx=128, ny=128, bit_depth=16, qe=1, sensitivity=1, baseline_noise=50, dark_noise=10, shot_noise=False, fill_ratio_x=1.0, fill_ratio_y=1.0, particle_image_diameter=2 )
cam.baseline_noise = 50
cam.dark_noise = 10
img, _ = synpivimage.take_image(particles=no_particles,
camera=cam, laser=laser,
particle_peak_count=1000)
plt.imshow(img)
plt.title(f"$\mu$= {cam.baseline_noise}, $\sigma$={cam.dark_noise}")
Text(0.5, 1.0, '$\\mu$= 50, $\\sigma$=10')
Noise \(\mu\)=0/\(\sigma\)=10#
cam.baseline_noise = 0
cam.dark_noise = 10
img, _ = synpivimage.take_image(particles=no_particles,
camera=cam, laser=laser,
particle_peak_count=1000)
plt.imshow(img)
plt.title(f"$\mu$= {cam.baseline_noise}, $\sigma$={cam.dark_noise}")
Text(0.5, 1.0, '$\\mu$= 0, $\\sigma$=10')
Noise \(\mu\)=10/\(\sigma\)=0#
cam.baseline_noise = 10
cam.dark_noise = 0
img, _ = synpivimage.take_image(particles=no_particles,
camera=cam, laser=laser,
particle_peak_count=1000)
plt.imshow(img)
plt.title(f"$\mu$= {cam.baseline_noise}, $\sigma$={cam.dark_noise}")
Text(0.5, 1.0, '$\\mu$= 10, $\\sigma$=0')
Shot Noise#
Let’s change the camera settings (smaller sensor, 8bit, …). We illuminate one central particle and investigate the influence of shot noise
cam = synpivimage.Camera(
nx=8,
ny=8,
bit_depth=16,
qe=1,
sensitivity=1,
baseline_noise=10,
dark_noise=0,
shot_noise=False,
fill_ratio_x=1.0,
fill_ratio_y=1.0,
particle_image_diameter=2,
seed=50
)
one_particles = synpivimage.Particles(
x=4,
y=4,
z=0,
size=2
)
one_particles = laser.illuminate(particles=one_particles)
cam.shot_noise = False
img_without_shot_noise, _ = synpivimage.take_image(particles=one_particles,
laser=laser,
particle_peak_count=1000,
camera=cam)
cam.shot_noise = True
img_with_shot_noise, _ = synpivimage.take_image(particles=one_particles,
laser=laser,
particle_peak_count=1000,
camera=cam)
fig, axs = plt.subplots(1, 3, tight_layout=True)
axs[0].imshow(img_without_shot_noise, cmap='gray', vmax=1000)
axs[0].set_title("No shot noise")
axs[1].imshow(img_with_shot_noise, cmap='gray', vmax=1000)
axs[1].set_title("With shot noise")
axs[2].plot(img_without_shot_noise[4, :], label='without')
axs[2].plot(img_with_shot_noise[4, :], label='with', alpha=0.5)
axs[2].set_xlim(3, 5)
axs[2].set_ylim(980, None)
axs[2].set_title('zoom to peak count')
asp = np.diff(axs[2].get_xlim())[0] / np.diff(axs[2].get_ylim())[0]
axs[2].set_aspect(asp)
plt.legend()
<matplotlib.legend.Legend at 0x7f251e2d8370>