pyBeamprofiler
Real-time laser beam profiler with Gaussian fitting for GenICam cameras.
Features
- Real-time Gaussian fitting — 1D projections (230+ fps), 2D with rotation (50+ fps), linecut (300+ fps)
- Browser-based GUI — Dash web interface with live heatmap, fits, dark/light theme, 30+ color scales, and camera controls
- Multiple width definitions — Gaussian (1/e²), FWHM, D4σ (ISO 11146)
- GenICam hardware support — FLIR (Spinnaker) and Basler (Pylon) via Harvesters; auto-discovered features grouped by SFNC category
- Jupyter support — Live streaming with
bp.setting()interactive widgets - Simulated camera — Gaussian beam with noise, no hardware needed
- Auto-configuration — Pixel size detection for 40+ sensor models
Quick Start
pip install pybeamprofiler
# Run the browser GUI with a simulated camera (no hardware needed)
pybeamprofiler --camera simulated
# Or connect to real hardware
pybeamprofiler --camera flir # FLIR / Spinnaker
pybeamprofiler --camera basler # Basler / Pylon
The browser opens automatically at http://127.0.0.1:8050. Press Ctrl+C in the terminal to stop the server and exit.
Installation
pip install pybeamprofiler
For real hardware (FLIR or Basler), also install the corresponding SDK and set the CTI path:
| Vendor | SDK | GENICAM_GENTL64_PATH |
|---|---|---|
| FLIR | Spinnaker | /usr/local/lib/spinnaker-gentl (macOS/Linux) |
| Basler (macOS) | Pylon | /Library/Frameworks/pylon.framework/Libraries/gentlproducer/gtl |
| Basler (Linux) | Pylon | /opt/pylon/lib64/gentlproducer/gtl |
| Basler (Windows) | Pylon | C:\Program Files\Basler\pylon\Runtime\x64 |
export GENICAM_GENTL64_PATH=/path/to/cti/files
Note: GenICam cameras allow only one application to connect at a time — close Spinnaker GUI / Pylon Viewer first.
Usage
Command line
pybeamprofiler --camera simulated # simulated camera
pybeamprofiler --camera flir # FLIR / Spinnaker
pybeamprofiler --camera basler # Basler / Pylon
pybeamprofiler --file beam.png --pixel-size 5.86 # static image
pybeamprofiler --fit 2d --definition fwhm
pybeamprofiler --help # all options
--pixel-size is required with --file: an image on disk carries no scale, so
without it every width would be in pixels pretending to be micrometers. Cameras
report their own pitch, but you can still pass --pixel-size to override it
(useful with binning, or when the camera reports nothing).
Press Ctrl+C in the terminal to stop streaming and exit.
Python API
from pybeamprofiler import BeamProfiler, print_camera_info
print_camera_info() # list connected cameras
bp = BeamProfiler(camera="simulated")
bp.plot() # open browser GUI
bp.plot(num_img=1) # single shot
print(f"Width X: {bp.width_x:.1f} μm, Y: {bp.width_y:.1f} μm")
print(f"Center: ({bp.center_x:.1f}, {bp.center_y:.1f}) px")
# Change settings
bp.setting(exposure_time=0.05, Gain=10.0)
# In Jupyter: open interactive control panel
bp.setting()
See the API docs for fitting methods (1d, 2d, linecut), width definitions (gaussian, fwhm, d4s), ROI control, and more.
Width definitions
width_x / width_y are reported in whichever definition you select, and the
derived properties convert between them from the fitted Gaussian sigma:
| Property | Threshold | Multiple of σ |
|---|---|---|
fwhm_x / fwhm_y |
1/2 | 2·√(2·ln2) ≈ 2.3548 |
fw_1e_x / fw_1e_y |
1/e | 2·√2 ≈ 2.8284 |
fw_1e2_x / fw_1e2_y |
1/e² | 4 |
A lower threshold is crossed further out on the flanks, so the widths always
order as FWHM < FW@1/e < FW@1/e². d4s is the ISO 11146 second-moment width,
which equals 4σ for a Gaussian but — unlike a fit — stays meaningful for
flat-top and multi-lobed beams.
Choosing fwhm or d4s measures directly off the integrated profile with no
model, so it takes precedence over fit; the Gaussian fit still runs, but only
to draw the overlay.
Troubleshooting
- Camera not found — verify SDK install,
GENICAM_GENTL64_PATH, and runprint_camera_info(). - Access denied — close other camera software (Spinnaker GUI, Pylon Viewer).
- Jupyter camera stuck — restart the kernel to release the hardware lock.
- Basler USB3 — pass the USB3 CTI explicitly:
BaslerCamera(cti_file="/path/to/ProducerU3V.cti").
For Developers
Setup
git clone https://github.com/acechenx/pybeamprofiler.git
cd pybeamprofiler
uv sync --extra dev
uv run pre-commit install
Code quality
uv run ruff check src tests
uv run ruff format src tests
uv run ty check src tests
Testing
uv run pytest # all tests + coverage
uv run pytest --cov-report=html # HTML coverage report
uv run pytest tests/test_profiler.py # single file
Architecture
fitting.py— Gaussian models, direct width measurements, curve fits, decimation (pure functions over arrays; no camera or plotting state)beamprofiler.py—BeamProfilerclass, figure building, streaming, CLI entry pointcamera.py— abstractCamerabase class + Jupyter widget buildergen_camera.py—HarvesterCamerafor GenICam devicesflir.py/basler.py— vendor-specific subclassessimulated.py—SimulatedCamera(no hardware)dash_app.py— browser GUI with live updates, settings panel, pattern-matching callbacksutils.py— camera discovery helpersconstants.py— shared constants and conversion factors
Contributing
- Fork and create a feature branch
- Add tests for new functionality
- Ensure
uv run pytest,uv run ruff check, anduv run ty checkpass - Submit a pull request
Performance notes
- 2D fits downsample to 256 px on the longest edge and warm-start Levenberg-Marquardt from the previous frame; a failed fit is retried from a fresh estimate rather than left stuck on stale parameters
- Display decimation is nearest-neighbour fancy indexing (~4× faster than interpolated zoom at 1024 px, and it shows real sensor counts rather than blended ones)
- Projection profiles are cached between
analyze()and figure rendering - GenICam feature discovery is memoised per node map — the
.valueprobe it relies on is a register read per node, which costs hundreds of round trips on a GigE camera - The saturation check short-circuits on a
max()reduction, so a clean frame skips the full-frame comparison - In the current Dash implementation, live updates perform
bp.camera.get_image(timeout=0.1)andbp.analyze(img)synchronously while holding athreading.Lockto reduce segfault risk in the Harvesters C library
Supported sensors
Auto-detected pixel sizes (40+ models) — Sony IMX174, IMX183, IMX226, IMX249, IMX250, IMX252, IMX253, IMX255, IMX264, IMX265, IMX273, IMX287, IMX290, IMX291, IMX304, IMX392, IMX412, IMX477, IMX485, IMX530, IMX531, IMX540, IMX541, IMX542, IMX547, and direct Basler model lookups (acA4024-8gm, acA4024-29um, acA1920-155um, acA2440-75um, acA3800-14um).
License
MIT — see LICENSE.
Author
C.-A. Chen (acechen@cirx.org)
Acknowledgments
- Built on Harvesters, Plotly/Dash
- Inspired by LaseView (old freeware), ptomato/Beams, jordens/bullseye
- FLIR and Basler cameras loaned from Atom Computing for testing
Metadata
Release files for pybeamprofiler 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pybeamprofiler-0.3.0.tar.gz | 249.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pybeamprofiler-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 315.3 kB
Release files / pybeamprofiler-0.3.0.tar.gz
| Download URL | pybeamprofiler-0.3.0.tar.gz |
|---|---|
| Size | 249.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
48ab4a67be421d8332cdeaf591793819832929c3ce8c3835d074239484b2570b
|
|
BLAKE2b-256 checksum How to use checksums |
b6edd1863b4d9ac8f2cdf9b730238ee4ad2066b5556cff38a6895fc9ec9e009f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 20, 2026.
Transparency logRelease files / pybeamprofiler-0.3.0-py3-none-any.whl
| Download URL | pybeamprofiler-0.3.0-py3-none-any.whl |
|---|---|
| Size | 66.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e16ae1e886a6859bbb7bd4c7d933e3c5a323c5559167355a51e0bf5bd9a4f090
|
|
BLAKE2b-256 checksum How to use checksums |
c2767e2ac8f3142b7aa615caebefd071cc98231c5986ad00d3684d2038a1debc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 20, 2026.
Transparency log