Images with a variety of backgroundss

Scott Prahl

Sept 2023

It is common to have images with significant background. These images were collected by students trying to measure M² for a helium-neon laser beam that they had assembled.

[1]:
import imageio.v3 as iio
import numpy as np
import matplotlib.pyplot as plt
import laserbeamsize as lbs

repo = "https://github.com/scottprahl/laserbeamsize/raw/master/docs/"

%config InlineBackend.figure_format = 'retina'

Background algorithm used by lbs.beam_size()

We follow the ISO 11146-3 guidelines:

Since the beam's centroid, orientation and widths are initially unknown, the procedure starts with an approximation for the integration area. The approximation should include the beam's extent, orientation and position. Using this integration area, initial values for the beam position, size and orientation are obtained which are used to redefine the integration area. From the new integration area, new values for the beam size, orientation and position are calculated. This procedure shall be
repeated until convergence of the results is obtained.

The initial beam parameters are extracted from the entire image with the background removed (using the corner method). New parameters are then calculated using the appropriate integration area. The process is repeated until convergence.

Example

First import the 16 images

[2]:
# pixel size in mm for the camera
pixel_size_µm = 3.75 # microns

# array of distances at which images were collected
z2 = np.array([200,300,400,420,470,490,500,520,540,550,570,590,600,650,700,800]) #mm

# array of filenames associated with each image
fn2 = [repo + ("k-%dmm.png" % number) for number in z2]

# read them all into memory
test_img = [iio.imread(fn) for fn in fn2]

Find beam sizes for each image using default settings

The lbs.beam_size() algorithm works on most files without modification. Notice the change in range on the color bars between the original and after background was removed — in this case the background was about 40% of the maximum!

[3]:
im = test_img[1]
plt.subplots(1,2,figsize=(10,3))

plt.subplot(1,2,1)
plt.imshow(im)
plt.title('Raw Image')
plt.colorbar()

plt.subplot(1,2,2)
test = lbs.subtract_iso_background(im)
plt.imshow(test)
plt.title('ISO Background Removed')

plt.colorbar()
plt.show()
_images/03-Background_7_0.png

The integration rectangle and fitted ellipse

Here we cheat and use iso_noise=False

[4]:
test = lbs.subtract_corner_background(test_img[1])
xc, yc, dx, dy, phi = lbs.beam_size(test, iso_noise=False)

plt.title('phi=%.0f°, z=%dmm' % (np.degrees(phi),z2[1]))
plt.imshow(test)
plt.plot(xc,yc,'ob',markersize=1)
xp,yp = lbs.ellipse_arrays(xc,yc,dx,dy,phi)
plt.plot(xp,yp,':r')

xp,yp = lbs.rotated_rect_arrays(xc,yc,dx,dy,phi)
plt.plot(xp,yp,':y')


plt.show()

r = lbs.rotated_rect_mask(test,xc,yc,dx,dy,phi)
plt.imshow(r)
plt.plot(xc,yc,'ok')
xp,yp = lbs.ellipse_arrays(xc,yc,dx,dy,phi)
plt.plot(xp,yp,':r')
plt.show()

_images/03-Background_9_0.png
_images/03-Background_9_1.png

Beam Size estimates for all the images in pixels

This shows that the algorithm correctly locates the beam in images. Notice that the background varies widely between the different images.

[5]:
# vmax sets the colorbar range to 0-255 for all images

dx,dy=lbs.plot_image_montage(test_img, cols=4, z=z2*1e-3, vmax=255, iso_noise=False)
_images/03-Background_11_0.png

Close-up of beam profiles

Here we use a few more options for the beam_size_montage() function. The close-up of the beams show that the beams all have some flare towards the right side … which will likely increase the diameters in that direction

[6]:
options = {'z':z2*1e-3,                 # beam_size_montage assumes z locations in meters
           'pixel_size':pixel_size_µm,  # convert pixels to microns
           'units': 'µm',               # define units
           'vmax':255,                  # use same colorbar 0-255 for all images
           'cols':4,                    # 4 columns in montage
           'crop':[2000,2000],          # crop to 2x2mm area around beam center
           'iso_noise': False           # images are too noisy for default settings
          }

dx,dy=lbs.plot_image_montage(test_img, **options)
_images/03-Background_13_0.png

Diameters greater horizontally than vertically

The above montage shows that the horizontal beams all have some flare on the right side … which will likely increase the diameters in that direction. If we plot the results we see that the horizontal diameters are about 55 microns larger across the entire set of images.

One possible explanation for these results is that the lens used to focus the beam in these experiments was tilted relative to the axis of propagation and imparts something that looks like comatic aberration to the beam.

[7]:
plt.plot(z2,dx,'ob',label='horizontal')
plt.plot(z2,dy,'sr',label='vertical')
plt.legend()
plt.xlabel('axial position of beam (mm)')
plt.ylabel('diameter of beam (microns)')
plt.show()
_images/03-Background_15_0.png

Beam montage fails when iso_noise=True

These are not great beam images and therefore stray background elements can throw off the entire beam size calculation.

[8]:
options = {'z':z2*1e-3,                 # beam_size_montage assumes z locations in meters
           'pixel_size':pixel_size_µm,  # convert pixels to microns
           'units': 'µm',               # define units
           'vmin':-10,                  # use same colorbar 0-255 for all images
           'vmax':255,                  # use same colorbar 0-255 for all images
           'cols':4,                    # 4 columns in montage
           'crop':False,                # easier to see failures
           'iso_noise':True,
          }

dx,dy=lbs.plot_image_montage(test_img, **options)
_images/03-Background_17_0.png
[ ]: