Extract the ISO 11146 beam size from an image file

Overview

laserbeamsize


Simple and fast calculation of beam sizes from a single monochrome image based on the ISO 11146 method of variances. Some effort has been made to make the algorithm less sensitive to background offset and noise.

This module also supports M² calculations based on a series of images collected at various distances from the focused beam.

Extensive documentation can be found at <https://laserbeamsize.readthedocs.io>

Using laserbeamsize

  1. Install with pip:

    pip install --user laserbeamsize
    
  2. or run this code in the cloud using Google Collaboratory by selecting the Jupyter notebook that interests you.

  3. use binder which will create a new environment that allows you to run Jupyter notebooks. This takes a bit longer to start, but it automatically installs laserbeamsize.

  4. clone the laserbeamsize github repository and then add the repository to your PYTHONPATH environment variable

Determining the beam size in an image

Finding the center and dimensions of a good beam image:

import imageio
import numpy as np
import matplotlib.pyplot as plt
import laserbeamsize as lbs

beam = imageio.imread("t-hene.pgm")
x, y, dx, dy, phi = lbs.beam_size(beam)

print("The center of the beam ellipse is at (%.0f, %.0f)" % (x,y))
print("The ellipse diameter (closest to horizontal) is %.0f pixels" % dx)
print("The ellipse diameter (closest to   vertical) is %.0f pixels" % dy)
print("The ellipse is rotated %.0f° ccw from horizontal" % (phi*180/3.1416))

to produce:

The center of the beam ellipse is at (651, 491)
The ellipse diameter (closest to horizontal) is 334 pixels
The ellipse diameter (closest to   vertical) is 327 pixels
The ellipse is rotated 29° ccw from the horizontal

A visual report can be done with one function call:

lbs.beam_size_plot(beam)
plt.show()

produces something like

hene-report.png

or:

lbs.beam_size_plot(beam, r"Original Image $\lambda$=4µm beam", pixel_size = 12, units='µm')
plt.show()

produces something like

astigmatic-report.png

Non-gaussian beams work too:

# 12-bit pixel image stored as high-order bits in 16-bit values
tem02 = imageio.imread("TEM02_100mm.pgm") >> 4
lbs.beam_size_plot(tem02, title = r"TEM$_{02}$ at z=100mm", pixel_size=3.75)
plt.show()

produces

tem02.png

Determining M²

Determining M² for a laser beam is also straightforward. Just collect beam diameters from five beam locations within one Rayleigh distance of the focus and from five locations more than two Rayleigh distances:

lambda1=308e-9 # meters
z1_all=np.array([-200,-180,-160,-140,-120,-100,-80,-60,-40,-20,0,20,40,60,80,99,120,140,160,180,200])*1e-3
d1_all=2*np.array([416,384,366,311,279,245,216,176,151,120,101,93,102,120,147,177,217,256,291,316,348])*1e-6
lbs.M2_radius_plot(z1_all, d1_all, lambda1, strict=True)
plt.show()

produces

m2fit.png

Here is an analysis of a set of images that were insufficient for ISO 11146:

lambda0 = 632.8e-9 # meters
z10 = np.array([247,251,259,266,281,292])*1e-3 # meters
filenames = ["sb_%.0fmm_10.pgm" % (number*1e3) for number in z10]

# the 12-bit pixel images are stored in high-order bits in 16-bit values
tem10 = [imageio.imread(name)>>4 for name in filenames]

# remove top to eliminate artifact
for i in range(len(z10)):
    tem10[i] = tem10[i][200:,:]

# find beam in all the images and create arrays of beam diameters
options = {'pixel_size': 3.75, 'units': "µm", 'crop': [1400,1400], 'z':z10}
dy, dx= lbs.beam_size_montage(tem10, **options)  # dy and dx in microns
plt.show()

produces

sbmontage.png

Here is one way to plot the fit using the above diameters:

lbs.M2_diameter_plot(z10, dx*1e-6, lambda0, dy=dy*1e-6)
plt.show()

In the graph on the below right, the dashed line shows the expected divergence of a pure gaussian beam. Since real beams should diverge faster than this (not slower) there is some problem with the measurements (too few!). On the other hand, the M² value the semi-major axis 2.6±0.7 is consistent with the expected value of 3 for the TEM₁₀ mode.

sbfit.png

License

laserbeamsize is licensed under the terms of the MIT license.

Comments
  • Gaussian fit problem for asymmetric (astigmatic) beams

    Gaussian fit problem for asymmetric (astigmatic) beams

    Dear Scott,

    Thank you for this amazingly useful library. I have just discovered that Gaussian fit seems to be invalid for heavily astigmatic beams, and therefore, the function returns the incorrect beam diameters. Please refer to the image below. Picture1

    Is there any parameter to overcome the problem?

    UPD It seems (from the values) that dx and dy are just mixed up here

    Regards

    opened by Werefkin 7
  • Working with the highly astigmatic beams

    Working with the highly astigmatic beams

    Hello!

    I have a highly astigmatic laser diode. At some point after a lens I getting this with lbs.beam_size_montage():

    image image

    No problems with estimating the center of the beam, but axes are rotated by 45 degrees. Laser modes are aligned along x and y axes, no need to rotate them (almost).

    Is there any type of workaround for this problem?

    Here is the original image from Thorlabs DCC1545M: astigmatic_beam.zip

    P.S. Thanks a lot for this project !!!

    opened by arktrin 6
  • definition of fitting function in m2.py

    definition of fitting function in m2.py

    I like this module, as is makes analysis very easy. However, I wonder about the fitting for M2. Especially I refer to

    def _beam_fit_fn_(z, d0, z0, Theta): """Fitting function for d0, z0, and Theta.""" return d0**2 + (Theta*(z-z0))**2

    I understand the idea of fitting d(z)^2 = ... wwithout the sqrt. But if I change the input from d**2 to d and also the function from d0**2 + (Theta*(z-z0))**2 to np.sqrt(d0**2 + (Theta*(z-z0))**2), I get different results.

    Has anyone an idea, where this change comes from and how to get the proper output? Which of the two versions is right?

    opened by SReich-EMI 3
  • added BPP as output parameter

    added BPP as output parameter

    added the BPP=Theta*d0/4 to the calculations. For us this is always an important value, knowing that it is easily to calculate from M2. I don't know if I have found all poisitions, where to add the BPP, as I could only test one type of analysis with my data.

    opened by SReich-EMI 3
  • Beam diameter estimation

    Beam diameter estimation

    Hello!

    I'm getting wrong beam diameter estimation. Here is the result of lbs.beam_size_plot(beam, pixel_size=5.2, units='µm') :

    image

    Original image: image.zip

    opened by arktrin 1
  • rotated_rect_mask speedup

    rotated_rect_mask speedup

    I want to use this package on data coming at 10Hz but found that the current version was too slow for this. After some profiling, I found that rotated_rect_mask is slow as it rotates the whole image instead of just drawing a rotated rectangle. I wrote an alternative implementation that does that.

    I also added a test to make sure that the result is the same as for the normal implementation and changed depreciated np.float to float.

    opened by HTuennermann 1
  • Bump jinja2 from 2.11.2 to 2.11.3 in /docs

    Bump jinja2 from 2.11.2 to 2.11.3 in /docs

    Bumps jinja2 from 2.11.2 to 2.11.3.

    Release notes

    Sourced from jinja2's releases.

    2.11.3

    This contains a fix for a speed issue with the urlize filter. urlize is likely to be called on untrusted user input. For certain inputs some of the regular expressions used to parse the text could take a very long time due to backtracking. As part of the fix, the email matching became slightly stricter. The various speedups apply to urlize in general, not just the specific input cases.

    Changelog

    Sourced from jinja2's changelog.

    Version 2.11.3

    Released 2021-01-31

    • Improve the speed of the urlize filter by reducing regex backtracking. Email matching requires a word character at the start of the domain part, and only word characters in the TLD. :pr:1343
    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • beam centers as float

    beam centers as float

    As my beams are not always perfeclty located at a pixel, I need the position as float and not int. Is there a reason for this restriction?

    for disc of round beam ISO says abs(2*xy)

    opened by SReich-EMI 0
  • New subtract_tilted_background

    New subtract_tilted_background

    I rewrote subtract_tilted_background so it now samples every point around a perimeter with width equal to the width of the corner boxes. I made a new function, perimeter_mask, to enable this. The new function works just as fast despite fitting many more points, and the result is now consistent from one run to the next because the randomness is removed. I updated the notebook to show the perimeter mask function.

    opened by scottbreitenstein 0
  • subtract_image / subtract_threshold implementation iso conform?

    subtract_image / subtract_threshold implementation iso conform?

    A colleague of mine brought up that the clipping to zero done in these functions is not mentioned in the iso standard. Therefore this wouldn't be completely iso conform. Instead, negative numbers should be used for the next steps. Would you be interested in changing this?

    opened by HTuennermann 1
Releases(v1.9.4)
  • v1.9.4(Mar 19, 2022)

    v1.9.4

    • allow beam angle to be specified during fitting
    • new notebook to illustrate constrained fits
    • improve docstrings and therefore api documentation
    • still better ellipse and rect outlines
    • start adding examples

    v1.9.3

    • use faster version of creating rotated rect mask
    • move tests to their own directory
    • avoid deprecated np.float
    • improve drawing of rect and ellipse outlines
    • improve some docstrings
    Source code(tar.gz)
    Source code(zip)
  • v1.9.3(Mar 15, 2022)

    v1.9.3

    • use faster version of creating rotated rect mask
    • move tests to their own directory
    • avoid deprecated np.float
    • improve drawing of rect and ellipse outlines
    • improve some docstrings

    v1.9.2

    • use both black and white dashed lines
    • fit to d and not d**2
    • add more dunders to init.py
    • fix residual calculation broken in v1.9.1
    Source code(tar.gz)
    Source code(zip)
  • v1.9.2(Mar 13, 2022)

    M² is found by fitting to a hyperbola. Heretofore the hyperbola was fit using d², laserbeamsize now uses d. Both methods give nearly identical results, but I believe fitting to d is more correct.

    v1.9.2

    • use both black and white dashed lines
    • fit to d and not d**2
    • add more dunders to init.py
    • fix residual calculation broken in v1.9.1

    v1.9.1

    • centralize version number to a single place

    v1.9.0

    • add beam_ellipticity()
    • add beam_parameter_product()
    • rotate x-tick labels when more than 10 ticks
    • removed deprecated use of np.matrix()
    • M2_report now includes BPP values
    • improve API docs
    • code linting
    Source code(tar.gz)
    Source code(zip)
  • v1.9.1(Mar 10, 2022)

    No features. This just reduces the number of places version numbers are used from 3 (setup.cfg, docs/conf.py, laserbeamsize/__init__.py) down to just the __init__.py file.

    v1.9.1

    • centralize version number to a single place

    v1.9.0

    • add beam_ellipticity()
    • add beam_parameter_product()
    • rotate x-tick labels when more than 10 ticks
    • removed deprecated use of np.matrix()
    • M2_report now includes BPP values
    • improve API docs
    • code linting
    Source code(tar.gz)
    Source code(zip)
  • v1.9.0(Mar 9, 2022)

    v1.9.0

    • add beam_ellipticity()
    • add beam_parameter_product()
    • rotate x-tick labels when more than 10 ticks
    • removed deprecated use of np.matrix()
    • M2_report now includes BPP values
    • improve API docs
    • code linting

    v1.8.0

    • handle rotated masks properly
    • fix readthedoc configuration
    Source code(tar.gz)
    Source code(zip)
  • v1.8.0(Dec 15, 2021)

    Internally, laserbeamsize masks the laser spot in the image. This involves rotating a binary mask which sometimes creates pixels that are not exactly 1. Guilhem noticed this and suggested a fix.

    Additionally, building of doc files on readthedocs.io has been made more robust.

    Source code(tar.gz)
    Source code(zip)
  • v1.7.3(Aug 7, 2021)

    v1.7.3

    • create pure python packaging
    • include wheel file
    • package as python3 only

    v1.7.2

    • allow non-integer beam centers
    • add badges to docs
    • use sphinx-book-theme for docs

    v1.7.1

    • explicit warning for non-monochrome images in beam_size()
    • improve help() messages

    v1.7.0

    • fix error in identifying major/minor axes in beam_size_plot()
    Source code(tar.gz)
    Source code(zip)
  • v1.7.2(Mar 22, 2021)

    v1.7.2

    • allow non-integer beam centers
    • add badges to docs
    • use sphinx-book-theme for docs

    v1.7.1

    • explicit warning for non-monochrome images in beam_size()
    • improve help() messages

    v1.7.0

    • fix error in identifying major/minor axes in beam_size_plot()
    Source code(tar.gz)
    Source code(zip)
  • v1.7.1(Jan 3, 2021)

  • v1.7.0(Nov 11, 2020)

  • v1.6.1(Sep 30, 2020)

    Minor release.

    • Fix the deprecation warning for register_cmap
    • a sphinx and pydocstyle warnings
    • use all points on background rect for fitting tilted background
    Source code(tar.gz)
    Source code(zip)
  • v1.6.0(Aug 3, 2020)

    A number of small changes and

    • new function subtract_tilted_background()
    • M²=1 line added M2_radius_plot()
    • autoselect line color on images for visibility (still imperfect)
    • documentation tweaks
    Source code(tar.gz)
    Source code(zip)
  • v1.5.0(Jul 28, 2020)

    Support for ISO 11146 measurement of M² now. If you have an array of images, then analysis can be as simple as::

    import imageio
    import matplotlib.pyplot as plt
    import laserbeamsize as lbs
    
    images = [imageio.imread(name) for name in list_of_filenames]
    dy, dx= lbs.beam_size_montage(images, pixel_size=3.75)  # pixel_size in microns
    plt.show()
    lbs.M2_diameter_plot(z10, dx*1e-6, lambda0, dy=dy*1e-6)
    plt.show()
    
    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Jun 7, 2020)

    New feature. visual_report() creates four subplots to show the beam analysis. Other updates include::

    • Add routines to plot values along semi axes
    • Fix error when calculating circular radius
    • Add missing scipy requirement
    • Improve README.rst with figure
    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Jun 3, 2020)

    Previously, laserbeamsize used the standard definitions for the first and second order moments of the WIgner distribution to calculate beam parameters.

    This version now also follows ISO 11146 for

    • integration areas
    • background using corners
    • background subtraction

    The overall result is that beam parameters extraction is much more robust.

    Source code(tar.gz)
    Source code(zip)
  • v1.0.3(May 20, 2020)

Owner
Scott Prahl
Scott Prahl
Image manipulation package used for EpicBot.

Image manipulation package used for EpicBot.

Nirlep_5252_ 7 May 26, 2022
Convert Image to ASCII Art

Convert Image to ASCII Art Persiapan aplikasi ini menggunakan bahasa python dan beberapa package python. oleh karena itu harus menginstall python dan

Huda Damar 48 Dec 20, 2022
Image comparison slider component for Streamlit

Streamlit Image Comparison Component A simple Streamlit Component to compare images with a slider in Streamlit apps using Knightlab's JuxtaposeJS. It

fatih 109 Dec 23, 2022
GPU-accelerated image processing using cupy and CUDA

napari-cupy-image-processing GPU-accelerated image processing using cupy and CUDA This napari plugin was generated with Cookiecutter using with @napar

Robert Haase 16 Oct 26, 2022
An add to make adding screenshots and copied images to the scene easy

Blender Clipboard to Scene It doesn't work with version 2.93 and higher (I tested it on 2.91 and 2.83) There is an issue with importing the Pillow mod

Mohammad Mehdi Afkhami 3 Dec 29, 2021
Steganography Image/Data Injector.

Byte Steganography Image/Data Injector. For artists or people to inject their own print/data into their images. TODO Add more file formats to support.

Ori 4 Nov 16, 2022
Black-white image converter - Black-white photo colorization

Black-white image converter - Black-white photo colorization

1 Jan 02, 2022
Image histogram remapping

Hmap An image histogram remapping script written in Python 2.7 by Anthony Kesich and Ross Goodwin. Changes source image so that source image's histogr

Ross Goodwin 199 Nov 19, 2022
Simple utility to tinker with OPlus images

OPlus image utilities Prerequisites Linux running kernel 5.4 or up (check with uname -r) Image rebuilding Used to rebuild read-only erofs images into

Wiley Lau 15 Dec 28, 2022
⚡ZenGL is a minimalist Python module providing exactly one way to render scenes with OpenGL.

ZenGL is a minimalist Python module providing exactly one way to render scenes with OpenGL.

Szabolcs Dombi 133 Dec 17, 2022
A Python package implementing various HDRI / Radiance image processing algorithms.

Colour - HDRI A Python package implementing various HDRI / Radiance image processing algorithms. It is open source and freely available under the New

colour-science 111 Dec 06, 2022
CropImage is a simple toolkit for image cropping, detecting and cropping main body from pictures.

CropImage is a simple toolkit for image cropping, detecting and cropping main body from pictures. Support face and saliency detection.

Haofan Wang 15 Dec 22, 2022
Pythonocc nodes for Ryven

Pythonocc-nodes-for-Ryven Pythonocc nodes for Ryven Here a way to work on Pythonocc with a node editor, Ryven in that case. To get it functional you w

Tanneguy 30 Dec 18, 2022
A script to generate a profile picture and a banner that show the same image on Discord.

Discord profile picture & banner generator A script to generate a profile picture and a banner that show the same image on Discord. Installation / Upd

Victor B. 9 Nov 27, 2022
Tweet2Image - Convert tweets to Instagram-friendly images.

Convert tweets to Instagram-friendly images. How to use If you want to use this repository as a submodule, don't forget to put the fonts d

Janu Lingeswaran 1 Mar 11, 2022
HtmlWebShot - A python3 package which Can Create Images From url, Html-CSS, Svg and from any readable file and texts with many setup features.

A python3 package which Can Create Images From url, Html-CSS, Svg and from any readable file and texts with many setup features

Danish 24 Dec 14, 2022
Forza painter app with python

forza-painter Discord: A-Dawg#0001 (AE) Supports: Forza Horizon 5 Offically (OTHER v1.405.2.0, MS STORE v3.414.967.0, STEAM v1.414.967.0) Unofficially

320 Dec 31, 2022
PyPixelArt - A keyboard-centered pixel editor

PyPixelArt - A keyboard-centered pixel editor The idea behind PyPixelArt is uniting: a cmdpxl inspired pixel image editor applied to pixel art. vim 's

Douglas 18 Nov 14, 2022
The aim is to extract timeseries water level 2D information for any designed boundaries within the EasyGSH model domain

bct_file_generator_for_EasyGSH The aim is to extract timeseries water level 2D information for any designed boundaries within the EasyGSH model domain

Clayton Soares 1 Jul 08, 2022
Quickly 'anonymize' all people in an image. This script will put a black bar over all eye-pairs in an image

Face-Detacher Quickly 'anonymize' all people in an image. This script will put a black bar over all eye-pairs in an image This is a small python scrip

Don Cato 1 Oct 29, 2021