pybeamprofiler 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pybeamprofiler-0.0.1/.github/workflows/ci.yml +47 -0
- pybeamprofiler-0.0.1/.gitignore +156 -0
- pybeamprofiler-0.0.1/.pre-commit-config.yaml +33 -0
- pybeamprofiler-0.0.1/LICENSE +21 -0
- pybeamprofiler-0.0.1/PKG-INFO +457 -0
- pybeamprofiler-0.0.1/README.md +394 -0
- pybeamprofiler-0.0.1/pyproject.toml +104 -0
- pybeamprofiler-0.0.1/src/pybeamprofiler/__init__.py +22 -0
- pybeamprofiler-0.0.1/src/pybeamprofiler/__main__.py +5 -0
- pybeamprofiler-0.0.1/src/pybeamprofiler/basler.py +108 -0
- pybeamprofiler-0.0.1/src/pybeamprofiler/beamprofiler.py +1655 -0
- pybeamprofiler-0.0.1/src/pybeamprofiler/camera.py +645 -0
- pybeamprofiler-0.0.1/src/pybeamprofiler/constants.py +31 -0
- pybeamprofiler-0.0.1/src/pybeamprofiler/flir.py +91 -0
- pybeamprofiler-0.0.1/src/pybeamprofiler/gen_camera.py +579 -0
- pybeamprofiler-0.0.1/src/pybeamprofiler/simulated.py +132 -0
- pybeamprofiler-0.0.1/src/pybeamprofiler/utils.py +156 -0
- pybeamprofiler-0.0.1/tests/conftest.py +48 -0
- pybeamprofiler-0.0.1/tests/test_camera.py +1878 -0
- pybeamprofiler-0.0.1/tests/test_definitions.py +494 -0
- pybeamprofiler-0.0.1/tests/test_edge_cases.py +287 -0
- pybeamprofiler-0.0.1/tests/test_fitting.py +189 -0
- pybeamprofiler-0.0.1/tests/test_genicam.py +344 -0
- pybeamprofiler-0.0.1/tests/test_profiler.py +980 -0
- pybeamprofiler-0.0.1/tests/test_streaming.py +771 -0
- pybeamprofiler-0.0.1/tests/test_utils.py +326 -0
- pybeamprofiler-0.0.1/uv.lock +2019 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ "main" ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ "main" ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
# Allow the 3.14 prerelease job to fail without blocking the overall status
|
|
13
|
+
continue-on-error: ${{ matrix.experimental == true }}
|
|
14
|
+
strategy:
|
|
15
|
+
fail-fast: false
|
|
16
|
+
matrix:
|
|
17
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
18
|
+
experimental: [false]
|
|
19
|
+
include:
|
|
20
|
+
- python-version: "3.14"
|
|
21
|
+
experimental: true
|
|
22
|
+
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
|
|
26
|
+
- name: Install uv
|
|
27
|
+
uses: astral-sh/setup-uv@v7
|
|
28
|
+
with:
|
|
29
|
+
enable-cache: true
|
|
30
|
+
|
|
31
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
32
|
+
run: uv python install ${{ matrix.python-version }}
|
|
33
|
+
|
|
34
|
+
- name: Install dependencies
|
|
35
|
+
run: uv sync --locked --extra dev
|
|
36
|
+
|
|
37
|
+
- name: Lint with ruff
|
|
38
|
+
run: uv run ruff check src tests
|
|
39
|
+
|
|
40
|
+
- name: Format check with ruff
|
|
41
|
+
run: uv run ruff format --check src tests
|
|
42
|
+
|
|
43
|
+
- name: Type check with ty
|
|
44
|
+
run: uv run ty check src tests
|
|
45
|
+
|
|
46
|
+
- name: Test with pytest
|
|
47
|
+
run: uv run pytest tests/ --cov=pybeamprofiler --cov-report=term-missing
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
*.manifest
|
|
31
|
+
*.spec
|
|
32
|
+
|
|
33
|
+
# Installer logs
|
|
34
|
+
pip-log.txt
|
|
35
|
+
pip-delete-this-directory.txt
|
|
36
|
+
|
|
37
|
+
# Unit test / coverage reports
|
|
38
|
+
htmlcov/
|
|
39
|
+
.tox/
|
|
40
|
+
.nox/
|
|
41
|
+
.coverage
|
|
42
|
+
.coverage.*
|
|
43
|
+
.cache
|
|
44
|
+
nosetests.xml
|
|
45
|
+
coverage.xml
|
|
46
|
+
*.cover
|
|
47
|
+
*.py,cover
|
|
48
|
+
.hypothesis/
|
|
49
|
+
.pytest_cache/
|
|
50
|
+
cover/
|
|
51
|
+
|
|
52
|
+
# Translations
|
|
53
|
+
*.mo
|
|
54
|
+
*.pot
|
|
55
|
+
|
|
56
|
+
# Django stuff:
|
|
57
|
+
*.log
|
|
58
|
+
local_settings.py
|
|
59
|
+
db.sqlite3
|
|
60
|
+
db.sqlite3-journal
|
|
61
|
+
|
|
62
|
+
# Flask stuff:
|
|
63
|
+
instance/
|
|
64
|
+
.webassets-cache
|
|
65
|
+
|
|
66
|
+
# Scrapy stuff:
|
|
67
|
+
.scrapy
|
|
68
|
+
|
|
69
|
+
# Sphinx documentation
|
|
70
|
+
docs/_build/
|
|
71
|
+
|
|
72
|
+
# PyBuilder
|
|
73
|
+
.pybuilder/
|
|
74
|
+
target/
|
|
75
|
+
|
|
76
|
+
# Jupyter Notebook
|
|
77
|
+
.ipynb_checkpoints
|
|
78
|
+
*-checkpoint.ipynb
|
|
79
|
+
|
|
80
|
+
# IPython
|
|
81
|
+
profile_default/
|
|
82
|
+
ipython_config.py
|
|
83
|
+
|
|
84
|
+
# pyenv
|
|
85
|
+
.python-version
|
|
86
|
+
|
|
87
|
+
# pipenv
|
|
88
|
+
Pipfile.lock
|
|
89
|
+
|
|
90
|
+
# poetry
|
|
91
|
+
poetry.lock
|
|
92
|
+
|
|
93
|
+
# pdm
|
|
94
|
+
.pdm.toml
|
|
95
|
+
|
|
96
|
+
# PEP 582
|
|
97
|
+
__pypackages__/
|
|
98
|
+
|
|
99
|
+
# Celery stuff
|
|
100
|
+
celerybeat-schedule
|
|
101
|
+
celerybeat.pid
|
|
102
|
+
|
|
103
|
+
# SageMath parsed files
|
|
104
|
+
*.sage.py
|
|
105
|
+
|
|
106
|
+
# Environments
|
|
107
|
+
.env
|
|
108
|
+
.venv
|
|
109
|
+
env/
|
|
110
|
+
venv/
|
|
111
|
+
ENV/
|
|
112
|
+
env.bak/
|
|
113
|
+
venv.bak/
|
|
114
|
+
|
|
115
|
+
# Spyder project settings
|
|
116
|
+
.spyderproject
|
|
117
|
+
.spyproject
|
|
118
|
+
|
|
119
|
+
# Rope project settings
|
|
120
|
+
.ropeproject
|
|
121
|
+
|
|
122
|
+
# mkdocs documentation
|
|
123
|
+
/site
|
|
124
|
+
|
|
125
|
+
# mypy
|
|
126
|
+
.mypy_cache/
|
|
127
|
+
.dmypy.json
|
|
128
|
+
dmypy.json
|
|
129
|
+
|
|
130
|
+
# Pyre type checker
|
|
131
|
+
.pyre/
|
|
132
|
+
|
|
133
|
+
# pytype static type analyzer
|
|
134
|
+
.pytype/
|
|
135
|
+
|
|
136
|
+
# Cython debug symbols
|
|
137
|
+
cython_debug/
|
|
138
|
+
|
|
139
|
+
# IDEs
|
|
140
|
+
.vscode/
|
|
141
|
+
.idea/
|
|
142
|
+
*.swp
|
|
143
|
+
*.swo
|
|
144
|
+
*~
|
|
145
|
+
.DS_Store
|
|
146
|
+
|
|
147
|
+
# Project specific
|
|
148
|
+
summary/
|
|
149
|
+
|
|
150
|
+
# Output files
|
|
151
|
+
*.png
|
|
152
|
+
*.jpg
|
|
153
|
+
*.jpeg
|
|
154
|
+
*.bmp
|
|
155
|
+
*.tif
|
|
156
|
+
*.tiff
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
3
|
+
rev: v6.0.0
|
|
4
|
+
hooks:
|
|
5
|
+
- id: check-merge-conflict
|
|
6
|
+
- id: check-json
|
|
7
|
+
- id: check-yaml
|
|
8
|
+
args: [--unsafe]
|
|
9
|
+
- id: end-of-file-fixer
|
|
10
|
+
- id: no-commit-to-branch
|
|
11
|
+
- id: sort-simple-yaml
|
|
12
|
+
- id: trailing-whitespace
|
|
13
|
+
|
|
14
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
15
|
+
rev: v0.14.0
|
|
16
|
+
hooks:
|
|
17
|
+
- id: ruff-format
|
|
18
|
+
- id: ruff
|
|
19
|
+
args: [
|
|
20
|
+
--fix,
|
|
21
|
+
--exit-non-zero-on-fix,
|
|
22
|
+
--config,
|
|
23
|
+
'lint.extend-fixable = ["F401","F841"]',
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
- repo: local
|
|
27
|
+
hooks:
|
|
28
|
+
- id: ty
|
|
29
|
+
name: ty type check
|
|
30
|
+
entry: uv run ty check src tests
|
|
31
|
+
language: system
|
|
32
|
+
types_or: [python, pyi]
|
|
33
|
+
pass_filenames: false
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 C.-A. Chen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pybeamprofiler
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Real-time laser beam profiler with Gaussian fitting for GenICam cameras
|
|
5
|
+
Project-URL: Homepage, https://github.com/acechenx/pybeamprofiler
|
|
6
|
+
Project-URL: Bug Tracker, https://github.com/acechenx/pybeamprofiler/issues
|
|
7
|
+
Author-email: "C.-A. Chen" <acechen@cirx.org>
|
|
8
|
+
License: MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2026 C.-A. Chen
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Keywords: basler,beam-profiling,camera,flir,gaussian-fitting,genicam,laser
|
|
31
|
+
Classifier: Development Status :: 4 - Beta
|
|
32
|
+
Classifier: Intended Audience :: Science/Research
|
|
33
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
34
|
+
Classifier: Operating System :: OS Independent
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
41
|
+
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
|
42
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
43
|
+
Requires-Python: >=3.10
|
|
44
|
+
Requires-Dist: dash[async]
|
|
45
|
+
Requires-Dist: harvesters>=1.4.0
|
|
46
|
+
Requires-Dist: ipywidgets
|
|
47
|
+
Requires-Dist: numpy
|
|
48
|
+
Requires-Dist: pillow
|
|
49
|
+
Requires-Dist: plotly
|
|
50
|
+
Requires-Dist: scipy
|
|
51
|
+
Provides-Extra: dev
|
|
52
|
+
Requires-Dist: pre-commit>=4.5.0; extra == 'dev'
|
|
53
|
+
Requires-Dist: pytest-cov>=7.0; extra == 'dev'
|
|
54
|
+
Requires-Dist: pytest>=9.0; extra == 'dev'
|
|
55
|
+
Requires-Dist: ruff>=0.15.0; extra == 'dev'
|
|
56
|
+
Requires-Dist: ty>=0.0.25; extra == 'dev'
|
|
57
|
+
Provides-Extra: matplotlib
|
|
58
|
+
Requires-Dist: matplotlib>=3.0; extra == 'matplotlib'
|
|
59
|
+
Provides-Extra: test
|
|
60
|
+
Requires-Dist: pytest-cov>=7.0; extra == 'test'
|
|
61
|
+
Requires-Dist: pytest>=9.0; extra == 'test'
|
|
62
|
+
Description-Content-Type: text/markdown
|
|
63
|
+
|
|
64
|
+
# pyBeamprofiler
|
|
65
|
+
|
|
66
|
+
Real-time laser beam profiler with Gaussian fitting for GenICam cameras.
|
|
67
|
+
|
|
68
|
+
[](https://www.python.org/downloads/)
|
|
69
|
+
[](https://opensource.org/licenses/MIT)
|
|
70
|
+
|
|
71
|
+
## Features
|
|
72
|
+
|
|
73
|
+
* **Fast Gaussian fitting:** 850+ fps for 1D, 95 fps for 2D
|
|
74
|
+
* **Live streaming:** Dash web interface (10 Hz) or Jupyter notebooks (6-10 Hz)
|
|
75
|
+
* **Multiple fitting methods:** 1D projections, 2D Gaussian, linecut
|
|
76
|
+
* **Multiple width definitions:** Gaussian (1/e²), FWHM, D4σ (ISO 11146)
|
|
77
|
+
* **Interactive controls:** Jupyter widgets for camera settings
|
|
78
|
+
* **Flexible inputs:** Static images or camera streams
|
|
79
|
+
* **Hardware support:** FLIR, Basler cameras via GenICam/[Harvesters](https://github.com/genicam/harvesters)
|
|
80
|
+
* **Simulated camera:** Included for testing without hardware
|
|
81
|
+
* **Auto-configuration:** Pixel size detection, auto-exposure/gain disabled by default
|
|
82
|
+
* **ROI support:** Region of Interest with full sensor default
|
|
83
|
+
|
|
84
|
+
## Quick Start
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Install (creates/updates a reproducible environment from the lockfile)
|
|
88
|
+
uv sync
|
|
89
|
+
|
|
90
|
+
# Run with simulated camera (no hardware needed)
|
|
91
|
+
uv run pybeamprofiler --camera simulated
|
|
92
|
+
|
|
93
|
+
# Browser opens automatically at http://127.0.0.1:8050
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Installation
|
|
97
|
+
|
|
98
|
+
### Basic Installation
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
uv sync
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`uv sync` installs the exact versions recorded in `uv.lock`, giving you a reproducible environment. This is the recommended path for both users and CI.
|
|
105
|
+
|
|
106
|
+
> **Installing into an existing environment?** If you are managing your own virtualenv or conda environment and do not want to use the lockfile, you can run `uv pip install .` (or plain `pip install .`) instead. Be aware that this resolves dependencies independently and may produce a different set of package versions than the lockfile.
|
|
107
|
+
|
|
108
|
+
### Development Installation
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
uv sync --extra dev
|
|
112
|
+
pre-commit install # Optional: enable git hooks
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Optional Dependencies
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
uv sync --extra matplotlib # Matplotlib fallback for CLI
|
|
119
|
+
uv sync --extra test # Testing tools only
|
|
120
|
+
uv sync --extra dev # All development tools
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Usage
|
|
124
|
+
|
|
125
|
+
### Command Line Interface
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Simulated camera (no hardware needed)
|
|
129
|
+
pybeamprofiler --camera simulated
|
|
130
|
+
|
|
131
|
+
# Real cameras (requires SDK installation)
|
|
132
|
+
pybeamprofiler --camera flir # FLIR/Spinnaker
|
|
133
|
+
pybeamprofiler --camera basler # Basler/Pylon
|
|
134
|
+
|
|
135
|
+
# Single shot acquisition
|
|
136
|
+
pybeamprofiler --num-img 1
|
|
137
|
+
|
|
138
|
+
# Static image analysis
|
|
139
|
+
pybeamprofiler --file beam.png
|
|
140
|
+
|
|
141
|
+
# Custom fitting and definitions
|
|
142
|
+
pybeamprofiler --fit 2d --definition fwhm
|
|
143
|
+
|
|
144
|
+
# Set exposure time (in seconds)
|
|
145
|
+
pybeamprofiler --exposure-time 0.05
|
|
146
|
+
|
|
147
|
+
# Fast display mode (heatmap only)
|
|
148
|
+
pybeamprofiler --heatmap-only
|
|
149
|
+
|
|
150
|
+
# See all options
|
|
151
|
+
pybeamprofiler --help
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
> **Tip:** If you installed via `uv sync`, prefix commands with `uv run` (e.g., `uv run pybeamprofiler --help`).
|
|
155
|
+
> You can also use `python -m pybeamprofiler` as an alternative.
|
|
156
|
+
|
|
157
|
+
**Continuous streaming** automatically opens a browser with live beam profile and fitting results at http://127.0.0.1:8050.
|
|
158
|
+
|
|
159
|
+
### Python API
|
|
160
|
+
|
|
161
|
+
#### Basic Usage
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
from pybeamprofiler import BeamProfiler
|
|
165
|
+
|
|
166
|
+
# Initialize with simulated camera
|
|
167
|
+
bp = BeamProfiler(camera="simulated")
|
|
168
|
+
bp.plot() # Opens Dash web interface
|
|
169
|
+
|
|
170
|
+
# For real hardware
|
|
171
|
+
bp = BeamProfiler(camera="flir") # or camera="basler"
|
|
172
|
+
bp.plot()
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
#### Single Measurement
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
from pybeamprofiler import BeamProfiler
|
|
179
|
+
|
|
180
|
+
bp = BeamProfiler(camera="simulated")
|
|
181
|
+
bp.plot(num_img=1)
|
|
182
|
+
|
|
183
|
+
# Access results
|
|
184
|
+
print(f"Beam width: {bp.width:.1f} μm")
|
|
185
|
+
print(f"Width X: {bp.width_x:.1f} μm, Y: {bp.width_y:.1f} μm")
|
|
186
|
+
print(f"Center: ({bp.center_x:.1f}, {bp.center_y:.1f}) pixels")
|
|
187
|
+
print(f"Peak intensity: {bp.peak_value:.0f}")
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
#### Static Image Analysis
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
from pybeamprofiler import BeamProfiler
|
|
194
|
+
|
|
195
|
+
bp = BeamProfiler(file="beam_image.png")
|
|
196
|
+
bp.plot(num_img=1)
|
|
197
|
+
|
|
198
|
+
print(f"Width X: {bp.width_x:.1f} μm")
|
|
199
|
+
print(f"Width Y: {bp.width_y:.1f} μm")
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
#### Camera Control
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
# List available cameras
|
|
206
|
+
from pybeamprofiler import print_camera_info
|
|
207
|
+
print_camera_info()
|
|
208
|
+
|
|
209
|
+
# Set exposure time (three ways)
|
|
210
|
+
bp = BeamProfiler(camera="simulated", exposure_time=0.05) # 1. During init
|
|
211
|
+
|
|
212
|
+
bp.exposure_time = 0.01 # 2. Direct attribute
|
|
213
|
+
|
|
214
|
+
bp.setting(exposure_time=0.05) # 3. Via setting() method
|
|
215
|
+
|
|
216
|
+
# Set multiple parameters
|
|
217
|
+
bp.setting(
|
|
218
|
+
exposure_time=0.025,
|
|
219
|
+
Gain=10.0,
|
|
220
|
+
ExposureAuto=False,
|
|
221
|
+
GammaEnable=False
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
# Interactive widget (Jupyter only)
|
|
225
|
+
bp.setting() # Opens interactive control panel
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
#### Fitting Methods
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
# 1D Gaussian fitting (fastest, 850+ fps)
|
|
232
|
+
bp.fit_method = '1d'
|
|
233
|
+
bp.plot(num_img=1)
|
|
234
|
+
|
|
235
|
+
# 2D Gaussian fitting with rotation
|
|
236
|
+
bp.fit_method = '2d'
|
|
237
|
+
bp.plot(num_img=1)
|
|
238
|
+
print(f"Rotation angle: {bp.angle_deg:.1f}°")
|
|
239
|
+
|
|
240
|
+
# Linecut through peak
|
|
241
|
+
bp.fit_method = 'linecut'
|
|
242
|
+
bp.plot(num_img=1)
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
#### Width Definitions
|
|
246
|
+
|
|
247
|
+
```python
|
|
248
|
+
# Gaussian (1/e²) - standard laser beam width
|
|
249
|
+
bp.definition = 'gaussian'
|
|
250
|
+
bp.plot(num_img=1)
|
|
251
|
+
|
|
252
|
+
# Full Width at Half Maximum
|
|
253
|
+
bp.definition = 'fwhm'
|
|
254
|
+
bp.plot(num_img=1)
|
|
255
|
+
|
|
256
|
+
# D4σ (ISO 11146 second moment)
|
|
257
|
+
bp.definition = 'd4s'
|
|
258
|
+
bp.plot(num_img=1)
|
|
259
|
+
|
|
260
|
+
# Access all width metrics
|
|
261
|
+
print(f"1/e² width: {bp.fw_1e2_x:.1f} μm")
|
|
262
|
+
print(f"FWHM: {bp.fwhm_x:.1f} μm")
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
#### Region of Interest (ROI)
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
# Get ROI info
|
|
269
|
+
roi = bp.camera.roi_info
|
|
270
|
+
print(f"ROI: {roi['width']}×{roi['height']} at ({roi['offset_x']}, {roi['offset_y']})")
|
|
271
|
+
|
|
272
|
+
# Set ROI (GenICam cameras only)
|
|
273
|
+
bp.camera.set_roi(offset_x=100, offset_y=100, width=800, height=600)
|
|
274
|
+
|
|
275
|
+
# Reset to full sensor
|
|
276
|
+
bp.camera.set_roi(offset_x=0, offset_y=0, width=None, height=None)
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Jupyter Notebook
|
|
280
|
+
|
|
281
|
+
pyBeamprofiler works natively in Jupyter notebooks with interactive widgets:
|
|
282
|
+
- Camera discovery and initialization
|
|
283
|
+
- Interactive controls with widgets (`bp.setting()`)
|
|
284
|
+
- Single-shot and continuous acquisition
|
|
285
|
+
- Multiple fitting methods and width definitions
|
|
286
|
+
- Programmatic camera control
|
|
287
|
+
|
|
288
|
+
## Hardware Setup
|
|
289
|
+
|
|
290
|
+
### FLIR Cameras ([Spinnaker SDK](https://www.teledynevisionsolutions.com/products/spinnaker-sdk/))
|
|
291
|
+
|
|
292
|
+
**macOS/Linux:**
|
|
293
|
+
```bash
|
|
294
|
+
# Install Spinnaker SDK from FLIR website
|
|
295
|
+
# Then set environment variable
|
|
296
|
+
export GENICAM_GENTL64_PATH=/usr/local/lib/spinnaker-gentl
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Windows:**
|
|
300
|
+
```cmd
|
|
301
|
+
set GENICAM_GENTL64_PATH=C:\Program Files\FLIR Systems\Spinnaker\cti64\vs2015
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Basler Cameras ([Pylon SDK](https://www.baslerweb.com/en-us/software/pylon/sdk/))
|
|
305
|
+
|
|
306
|
+
**macOS:**
|
|
307
|
+
```bash
|
|
308
|
+
export GENICAM_GENTL64_PATH=/Library/Frameworks/pylon.framework/Libraries/gentlproducer/gtl
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
**Linux:**
|
|
312
|
+
```bash
|
|
313
|
+
export GENICAM_GENTL64_PATH=/opt/pylon/lib64/gentlproducer/gtl
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**Windows:**
|
|
317
|
+
```cmd
|
|
318
|
+
set GENICAM_GENTL64_PATH=C:\Program Files\Basler\pylon\Runtime\x64
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
**Note:** GenICam cameras can only be accessed by one application at a time. Close other camera software before using pyBeamprofiler.
|
|
322
|
+
|
|
323
|
+
## Supported Cameras
|
|
324
|
+
|
|
325
|
+
### FLIR
|
|
326
|
+
- Blackfly S (BFS-PGE, BFS-U3, etc.)
|
|
327
|
+
- Grasshopper3 (GS3)
|
|
328
|
+
- Auto-detected sensors: Sony IMX273, IMX174, IMX183, IMX250, IMX252, etc.
|
|
329
|
+
|
|
330
|
+
### Basler
|
|
331
|
+
- ace (acA series) - USB3, GigE
|
|
332
|
+
- ace 2 (a2A series)
|
|
333
|
+
- Auto-detected sensors: Sony IMX253, IMX226, IMX249, IMX255, etc.
|
|
334
|
+
|
|
335
|
+
### Pixel Size Auto-Detection
|
|
336
|
+
Automatic pixel size detection for 40+ sensor models including:
|
|
337
|
+
- Sony IMX series (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)
|
|
338
|
+
- Direct Basler model lookups (acA4024-8gm, acA4024-29um, acA1920-155um, acA2440-75um, acA3800-14um)
|
|
339
|
+
|
|
340
|
+
## Performance
|
|
341
|
+
|
|
342
|
+
- **Gaussian fitting:** 850+ fps (1D), 95 fps (2D) - Not the bottleneck!
|
|
343
|
+
- **Display rates:**
|
|
344
|
+
- Jupyter notebook: 6-10 Hz (standard), 25-30 Hz (heatmap only)
|
|
345
|
+
- Dash web interface: 10 Hz
|
|
346
|
+
- Matplotlib fallback: ~5 Hz
|
|
347
|
+
|
|
348
|
+
## Dependencies
|
|
349
|
+
|
|
350
|
+
**Core:**
|
|
351
|
+
- numpy, scipy - Numerical computing and optimization
|
|
352
|
+
- plotly, dash - Interactive visualization and web interface
|
|
353
|
+
- ipywidgets - Jupyter notebook controls
|
|
354
|
+
- Pillow - Image file loading
|
|
355
|
+
- harvesters - GenICam camera interface
|
|
356
|
+
|
|
357
|
+
**Optional:**
|
|
358
|
+
- matplotlib - Fallback plotting (CLI only)
|
|
359
|
+
|
|
360
|
+
**Development:**
|
|
361
|
+
- pytest, pytest-cov - Testing framework
|
|
362
|
+
- ruff - Fast linter and formatter
|
|
363
|
+
- ty - Static type checking
|
|
364
|
+
- pre-commit - Git hooks for code quality
|
|
365
|
+
|
|
366
|
+
## Testing
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
# Run all tests (coverage is enabled by default via pyproject.toml)
|
|
370
|
+
uv run pytest
|
|
371
|
+
|
|
372
|
+
# Run with HTML coverage report
|
|
373
|
+
uv run pytest --cov-report=html
|
|
374
|
+
|
|
375
|
+
# Run specific test file
|
|
376
|
+
uv run pytest tests/test_fitting.py -v
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
## Development
|
|
380
|
+
|
|
381
|
+
```bash
|
|
382
|
+
# Install in development mode
|
|
383
|
+
uv sync --extra dev
|
|
384
|
+
|
|
385
|
+
# Install pre-commit hooks
|
|
386
|
+
pre-commit install
|
|
387
|
+
|
|
388
|
+
# Run linter
|
|
389
|
+
uv run ruff check src tests
|
|
390
|
+
|
|
391
|
+
# Run formatter
|
|
392
|
+
uv run ruff format src tests
|
|
393
|
+
|
|
394
|
+
# Run type checker
|
|
395
|
+
uv run ty check src tests
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
## Troubleshooting
|
|
399
|
+
|
|
400
|
+
### Camera Not Found
|
|
401
|
+
|
|
402
|
+
1. **Check SDK installation:**
|
|
403
|
+
- FLIR: Install [Spinnaker SDK](https://www.teledynevisionsolutions.com/products/spinnaker-sdk/)
|
|
404
|
+
- Basler: Install [Pylon SDK](https://www.baslerweb.com/en-us/software/pylon/sdk/)
|
|
405
|
+
|
|
406
|
+
2. **Set GENICAM_GENTL64_PATH:**
|
|
407
|
+
```bash
|
|
408
|
+
export GENICAM_GENTL64_PATH=/path/to/cti/files
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
3. **Check camera connection:**
|
|
412
|
+
```python
|
|
413
|
+
from pybeamprofiler import print_camera_info
|
|
414
|
+
print_camera_info() # Lists all detected cameras
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
4. **Access denied error:**
|
|
418
|
+
- Close other camera software (Spinnaker GUI, Pylon Viewer, etc.)
|
|
419
|
+
- GenICam cameras allow only one connection at a time
|
|
420
|
+
|
|
421
|
+
### GigE vs USB3
|
|
422
|
+
- Basler cameras: Code auto-detects and prefers GigE over USB3
|
|
423
|
+
- For USB3 cameras, explicitly pass the USB3 CTI file path:
|
|
424
|
+
```python
|
|
425
|
+
from pybeamprofiler.basler import BaslerCamera
|
|
426
|
+
cam = BaslerCamera(cti_file="/path/to/ProducerU3V.cti")
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### Jupyter Kernel Restart
|
|
430
|
+
When re-initializing cameras in Jupyter, restart the kernel first:
|
|
431
|
+
- Kernel → Restart Kernel
|
|
432
|
+
- This releases the camera hardware lock
|
|
433
|
+
|
|
434
|
+
## License
|
|
435
|
+
|
|
436
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
437
|
+
|
|
438
|
+
## Author
|
|
439
|
+
|
|
440
|
+
C.-A. Chen (acechen@cirx.org)
|
|
441
|
+
|
|
442
|
+
## Contributing
|
|
443
|
+
|
|
444
|
+
Contributions welcome! Please:
|
|
445
|
+
1. Fork the repository
|
|
446
|
+
2. Create a feature branch
|
|
447
|
+
3. Add tests for new functionality
|
|
448
|
+
4. Ensure all tests pass: `uv run pytest`
|
|
449
|
+
5. Run code quality checks: `uv run ruff check src tests` and `uv run ruff format src tests`
|
|
450
|
+
6. Submit a pull request
|
|
451
|
+
|
|
452
|
+
## Acknowledgments
|
|
453
|
+
|
|
454
|
+
- Built on [Harvesters](https://github.com/genicam/harvesters) for GenICam camera interface
|
|
455
|
+
- Uses [Plotly/Dash](https://plotly.com/dash/) for interactive visualization
|
|
456
|
+
- Inspired by various beam profiling tools: LaseView (old freeware version), [ptomato/Beams](https://github.com/ptomato/Beams), [jordens/bullseye](https://github.com/jordens/bullseye)
|
|
457
|
+
- FLIR and Basler cameras loaned from [Atom Computing](https://atom-computing.com/) for testing
|