```python
import imageio.v2 as imageio
import matplotlib.pyplot as plt
import numpy as np
from scipy import ndimage

# sensor horizontal size
sensor_width = 7.75

# image file
laser = imageio.imread("laser-img/2025-09-07-012621-2mm-aperture.jpg")
```


```python
dimensions = np.array([sensor_width * laser.shape[0] / laser.shape[1], sensor_width])
half_size = dimensions / 2

# Mean of all color channels as an approximation of the monochrome image
laser_monochrome = np.mean(laser, axis=2)
# Normalized intensity map
intensity_map = laser_monochrome / np.max(laser_monochrome)

# Summed intensity in each axis
intensity_x = np.sum(laser_monochrome, axis=0)
intensity_y = np.sum(laser_monochrome, axis=1)

# Center of mass of the laser beam
center = (
    (ndimage.center_of_mass(laser_monochrome) / np.array(laser_monochrome.shape) - 0.5)
    * dimensions
    * [-1, 1]
)
print(f"Center of the beam is at {center[0]:.3f}/{center[1]:.3f}")


# Calculate FWHM in each axis
def fwhm(curve, width):
    assert curve.ndim == 1
    half_max = (np.max(curve) + np.min(curve)) / 2
    diff = curve - half_max
    indices = np.where(diff > 0)[0]
    return (indices[-1] - indices[0]) / curve.size * width


fwhm_y = fwhm(intensity_y, dimensions[0])
fwhm_x = fwhm(intensity_x, dimensions[1])
print(f"FWHM in X/Y: {fwhm_x:.2f}/{fwhm_y:.2f}")

eccentricity = np.sqrt(1 - (min(fwhm_y, fwhm_x) ** 2 / max(fwhm_y, fwhm_x) ** 2))
print(f"Eccentricity (along cartesian axes): {eccentricity:.5f}")
```

    Center of the beam is at -0.088/0.238
    FWHM in X/Y: 2.16/1.46
    Eccentricity (along cartesian axes): 0.73687



```python
with plt.style.context("dark_background"):
    fig, ax = plt.subplots(figsize=(14, 14))
    im = ax.imshow(
        intensity_map,
        cmap="magma",
        extent=(-half_size[1], half_size[1], -half_size[0], half_size[0]),
        interpolation="none",
        vmin=0,
    )
    ax.set_xlim(-np.max(half_size), np.max(half_size))
    ax.set_ylim(-np.max(half_size), np.max(half_size))

    xy_scale = max(np.max(intensity_x), np.max(intensity_y))
    ax.plot(
        np.linspace(-half_size[1], half_size[1], intensity_x.size),
        intensity_x / xy_scale - np.max(half_size),
        color="red",
    )
    ax.plot(
        intensity_y / xy_scale - np.max(half_size),
        np.linspace(half_size[0], -half_size[0], intensity_y.size),
        color="red",
    )

    # reticle
    ax.axvline(x=center[1], color="white", linestyle=":")
    ax.axhline(y=center[0], color="white", linestyle=":")

    ax.axvline(x=center[1] - fwhm_x / 2, color="gray", linestyle=":")
    ax.axvline(x=center[1] + fwhm_x / 2, color="gray", linestyle=":")
    ax.axhline(y=center[0] - fwhm_y / 2, color="gray", linestyle=":")
    ax.axhline(y=center[0] + fwhm_y / 2, color="gray", linestyle=":")

    cax = fig.add_axes(
        [
            ax.get_position().x1 + 0.01,
            ax.get_position().y0,
            0.02,
            ax.get_position().height,
        ]
    )
    fig.colorbar(im, cax=cax)

    text = (
        f"FWHM X/Y: {fwhm_x:.2f} mm/{fwhm_y:.2f} mm\n"
        f"Eccentricity: {eccentricity:.5f}\n"
        f"Offset X/Y: {center[1]:+.3f} mm/{center[0]:+.3f} mm"
    )
    fig.text(0.5, 0.05, text, ha="center")

fig
```




    
![png](Laserbeam_files/Laserbeam_2_0.png)
    




    
![png](Laserbeam_files/Laserbeam_2_1.png)
    



```python

```
