getframes 2.0.0__py3-none-any.whl

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.
Files changed (40) hide show
  1. getframes/__about__.py +4 -0
  2. getframes/__init__.py +91 -0
  3. getframes/analysis/__init__.py +18 -0
  4. getframes/analysis/apertures.py +92 -0
  5. getframes/analysis/ptc.py +109 -0
  6. getframes/calibrate.py +182 -0
  7. getframes/camera.py +649 -0
  8. getframes/cli.py +214 -0
  9. getframes/config.py +420 -0
  10. getframes/dataset.py +294 -0
  11. getframes/frame.py +107 -0
  12. getframes/noise.py +637 -0
  13. getframes/observation.py +162 -0
  14. getframes/presets/__init__.py +90 -0
  15. getframes/presets/data/__init__.py +3 -0
  16. getframes/presets/data/andor_ikon_m934.toml +22 -0
  17. getframes/presets/data/andor_ixon_ultra_888.toml +22 -0
  18. getframes/presets/data/generic_ccd.toml +18 -0
  19. getframes/presets/data/generic_cmos.toml +18 -0
  20. getframes/presets/data/generic_eapd.toml +20 -0
  21. getframes/presets/data/generic_emccd.toml +20 -0
  22. getframes/presets/data/generic_scmos.toml +21 -0
  23. getframes/presets/data/hamamatsu_orca_fusion.toml +25 -0
  24. getframes/presets/data/leonardo_saphira.toml +32 -0
  25. getframes/presets/data/zwo_asi2600mm.toml +20 -0
  26. getframes/py.typed +0 -0
  27. getframes/scene/__init__.py +51 -0
  28. getframes/scene/optics.py +180 -0
  29. getframes/scene/photometry.py +311 -0
  30. getframes/scene/psf.py +371 -0
  31. getframes/scene/scene.py +205 -0
  32. getframes/scene/sources.py +683 -0
  33. getframes/scene/thermal.py +114 -0
  34. getframes/scene/wcs.py +110 -0
  35. getframes/spectral.py +449 -0
  36. getframes-2.0.0.dist-info/METADATA +218 -0
  37. getframes-2.0.0.dist-info/RECORD +40 -0
  38. getframes-2.0.0.dist-info/WHEEL +4 -0
  39. getframes-2.0.0.dist-info/entry_points.txt +2 -0
  40. getframes-2.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,218 @@
1
+ Metadata-Version: 2.4
2
+ Name: getframes
3
+ Version: 2.0.0
4
+ Summary: Generate physically realistic synthetic camera frames (CCD/CMOS/EMCCD/eAPD/sCMOS) — dark, bias, flat, and rendered star fields — with auditable noise physics for scientific imaging pipelines.
5
+ Project-URL: Homepage, https://github.com/jacotay7/getframes
6
+ Project-URL: Documentation, https://jacotay7.github.io/getframes/
7
+ Project-URL: Repository, https://github.com/jacotay7/getframes
8
+ Project-URL: Issues, https://github.com/jacotay7/getframes/issues
9
+ Project-URL: Changelog, https://github.com/jacotay7/getframes/blob/main/CHANGELOG.md
10
+ Author-email: Jacob Taylor <jacobataylor7@gmail.com>
11
+ License: MIT
12
+ License-File: LICENSE
13
+ Keywords: astronomy,camera,ccd,cmos,detector,emccd,imaging,noise,simulation
14
+ Classifier: Development Status :: 5 - Production/Stable
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Scientific/Engineering :: Astronomy
24
+ Classifier: Topic :: Scientific/Engineering :: Image Processing
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.10
27
+ Requires-Dist: astropy>=5.0
28
+ Requires-Dist: numpy>=1.23
29
+ Requires-Dist: scipy>=1.10
30
+ Requires-Dist: tomli>=2.0; python_version < '3.11'
31
+ Provides-Extra: dev
32
+ Requires-Dist: build>=1.0; extra == 'dev'
33
+ Requires-Dist: mypy>=1.8; extra == 'dev'
34
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
35
+ Requires-Dist: pytest>=7.0; extra == 'dev'
36
+ Requires-Dist: ruff>=0.6; extra == 'dev'
37
+ Provides-Extra: docs
38
+ Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
39
+ Requires-Dist: mkdocs>=1.5; extra == 'docs'
40
+ Requires-Dist: mkdocstrings[python]>=0.24; extra == 'docs'
41
+ Provides-Extra: examples
42
+ Requires-Dist: matplotlib>=3.7; extra == 'examples'
43
+ Description-Content-Type: text/markdown
44
+
45
+ # getframes
46
+
47
+ [![CI](https://github.com/jacotay7/getframes/actions/workflows/ci.yml/badge.svg)](https://github.com/jacotay7/getframes/actions/workflows/ci.yml)
48
+ [![PyPI](https://img.shields.io/pypi/v/getframes.svg)](https://pypi.org/project/getframes/)
49
+ [![Python](https://img.shields.io/pypi/pyversions/getframes.svg)](https://pypi.org/project/getframes/)
50
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
51
+
52
+ **Realistic synthetic camera frames for scientific imaging pipelines.**
53
+
54
+ `getframes` gives you a clean, small API for generating physically realistic frames
55
+ from **CCD**, **CMOS**, **EMCCD**, **eAPD**, and **sCMOS** detectors — with
56
+ accurate, auditable noise physics (read noise, dark current, shot noise,
57
+ fixed-pattern non-uniformity, a unified stochastic gain stage, clock-induced
58
+ charge, nonlinearity, and cosmic rays) so you can build and validate
59
+ image-processing pipelines against ground truth.
60
+
61
+ It generates **dark**, **bias**, and **flat** frames, and renders **star fields**
62
+ through a PSF and telescope into a realistic science frame — the full
63
+ photon → electron → ADU signal path, with optional opt-in spectral mode.
64
+
65
+ > **Status:** stable. `getframes` 2.0 freezes the full public surface — the
66
+ > detector, scene, calibration, observation, radiometry, and dataset APIs — under
67
+ > [Semantic Versioning](https://semver.org/spec/v2.0.0.html); see
68
+ > [API stability](docs/stability.md).
69
+
70
+ ## Install
71
+
72
+ ```bash
73
+ pip install getframes
74
+ ```
75
+
76
+ From source (for development):
77
+
78
+ ```bash
79
+ git clone https://github.com/jacotay7/getframes
80
+ cd getframes
81
+ pip install -e ".[dev]"
82
+ ```
83
+
84
+ ## Quick start
85
+
86
+ ```python
87
+ import getframes as gf
88
+
89
+ # Pick a camera from the built-in preset library...
90
+ cam = gf.Camera.from_preset("andor_ikon_m934")
91
+
92
+ # ...and generate a reproducible dark frame.
93
+ frame = cam.dark_frame(exposure=60.0, temperature=-60.0, seed=0)
94
+
95
+ frame.data # 2-D numpy array of ADU, shape (1024, 1024)
96
+ frame.stats() # {'mean': ..., 'median': ..., 'std': ..., 'min': ..., 'max': ...}
97
+ frame.metadata # camera/exposure/temperature provenance
98
+ ```
99
+
100
+ `Frame` is array-like, so it drops straight into NumPy:
101
+
102
+ ```python
103
+ import numpy as np
104
+ master_dark = np.mean([np.asarray(f) for f in cam.dark_series(60.0, n_frames=20, seed=1)], axis=0)
105
+ ```
106
+
107
+ ### Define your own camera
108
+
109
+ ```python
110
+ cam = gf.Camera(
111
+ gf.CameraConfig(
112
+ name="My Lab CMOS",
113
+ sensor_type="CMOS",
114
+ resolution=(2048, 2048), # (height, width)
115
+ pixel_size_um=6.5,
116
+ quantum_efficiency=0.82,
117
+ full_well_e=30_000,
118
+ bit_depth=12,
119
+ gain_e_per_adu=0.8,
120
+ bias_offset_adu=300,
121
+ read_noise_e=1.8,
122
+ dark_current_e_per_s=0.5, # at the reference temperature
123
+ dark_current_ref_temp_c=20.0,
124
+ dark_current_doubling_temp_c=6.0,
125
+ )
126
+ )
127
+ frame = cam.dark_frame(exposure=30.0, temperature=-10.0)
128
+ ```
129
+
130
+ ### Observe a simulated star field
131
+
132
+ Render astronomical sources through a PSF and telescope, then expose them on a
133
+ detector — the full photon → electron → ADU path:
134
+
135
+ ```python
136
+ scene = gf.Scene(
137
+ shape=(256, 256),
138
+ optics=gf.Telescope(aperture_diameter_m=2.5, throughput=0.3,
139
+ plate_scale_arcsec_per_pixel=0.4, band=gf.Bandpass.johnson("V")),
140
+ psf=gf.MoffatPSF(fwhm_arcsec=1.1, beta=3.0),
141
+ sources=[gf.PointSource(x=128, y=128, magnitude=20.0)],
142
+ sky=gf.Sky(surface_brightness_mag_arcsec2=21.0),
143
+ )
144
+ cam = gf.Camera.from_preset("zwo_asi2600mm").with_config(resolution=(256, 256))
145
+ frame = cam.observe(scene, exposure=300.0, seed=0) # a realistic science frame
146
+ ```
147
+
148
+ You can also drive the detector directly with a photon-rate map (a scalar for a
149
+ uniform flat, or a per-pixel array): `cam.expose(photon_rate, exposure)`.
150
+
151
+ ### Browse the preset library
152
+
153
+ ```python
154
+ from getframes import available_presets
155
+ from getframes.presets import preset_info
156
+
157
+ available_presets() # ['andor_ikon_m934', 'andor_ixon_ultra_888', 'generic_ccd', ...]
158
+ preset_info() # rich descriptors for each preset
159
+ ```
160
+
161
+ | Preset | Sensor | Notes |
162
+ | --- | --- | --- |
163
+ | `andor_ikon_m934` | CCD | Deep-cooled back-illuminated scientific CCD |
164
+ | `andor_ixon_ultra_888` | EMCCD | Single-photon-sensitive EMCCD |
165
+ | `leonardo_saphira` | EAPD | HgCdTe avalanche IR array (AO wavefront sensing) |
166
+ | `zwo_asi2600mm` | CMOS | Sony IMX571 cooled CMOS |
167
+ | `hamamatsu_orca_fusion` | sCMOS | Back-thinned sCMOS with per-pixel read noise |
168
+ | `generic_ccd` / `generic_cmos` / `generic_emccd` / `generic_eapd` / `generic_scmos` | — | Idealised references for teaching/testing |
169
+
170
+ ## How the dark-frame model works
171
+
172
+ The dark signal chain (see [`getframes/noise.py`](src/getframes/noise.py)):
173
+
174
+ 1. **Dark current vs. temperature** — `D(T) = D_ref · 2^((T − T_ref) / T_double)`
175
+ 2. **Fixed-pattern non-uniformity (DSNU)** and **hot pixels** modulate the per-pixel mean
176
+ 3. **Shot noise** — Poisson statistics on the dark electrons
177
+ 4. **Clock-induced charge** (EMCCD) — small Poisson term
178
+ 5. **EM gain** (EMCCD) — stochastic multiplication with realistic excess noise
179
+ 6. **Read noise** — Gaussian at the output amplifier
180
+ 7. **Digitisation** — gain conversion to ADU, bias pedestal, saturation, quantisation
181
+
182
+ All randomness flows through a seeded `numpy.random.Generator`, so every frame is
183
+ reproducible.
184
+
185
+ ## Documentation
186
+
187
+ - [Guides & API reference](docs/) (built with MkDocs) — getting started, the
188
+ noise model, observing scenes, spectral mode, and presets
189
+ - [API stability & versioning](docs/stability.md)
190
+ - [Runnable examples](examples/) — PTC, star-field exposure planning, AO limiting
191
+ magnitude, transit photometry, detector realism
192
+
193
+ ## Roadmap
194
+
195
+ **1.0 is shipped:** the full photon → electron → ADU signal path (dark, bias,
196
+ flat, and rendered scenes) across CCD / CMOS / EMCCD / eAPD / sCMOS, with a
197
+ unified gain stage, detector-realism effects, opt-in spectral mode, analysis
198
+ helpers, and a frozen API.
199
+
200
+ The **2.0 plan** moves from a *frame* to an *observation* — closing the
201
+ raw → reduced → ground-truth validation loop, making time-series (variability,
202
+ jitter, persistence) and richer scenes (extended sources, catalogs, sky
203
+ coordinates) first-class, and deepening detector and radiometric fidelity. See
204
+ [docs/roadmap.md](docs/roadmap.md) for the full critique, phased plan, and worked
205
+ examples.
206
+
207
+ ## Contributing
208
+
209
+ Contributions — especially new camera presets — are welcome. See
210
+ [CONTRIBUTING.md](CONTRIBUTING.md). Run the checks locally with:
211
+
212
+ ```bash
213
+ ruff check . && ruff format --check . && mypy && pytest
214
+ ```
215
+
216
+ ## License
217
+
218
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,40 @@
1
+ getframes/__about__.py,sha256=QgrU1hx8R7GlRUzJZZj2iK3ti2_QxCajvahTgdpUWCU,108
2
+ getframes/__init__.py,sha256=vDGPTcDWCclmU9p5HauzxRgusg28WrKMUzVbSDXeYWY,1846
3
+ getframes/calibrate.py,sha256=nkIuuUWT0tn0lWsPsxHOBpTCJW2v1h0xwB19O9QRFug,6609
4
+ getframes/camera.py,sha256=whMsL51Sc96zgtJMu1vnEuf3BScMN1Yrk0Cp7Ic-i2Y,25178
5
+ getframes/cli.py,sha256=XJNvz6LvXhi6mJJL2vCjhu6yNMeNyyZ6IBYQmMQDqRk,7973
6
+ getframes/config.py,sha256=hoQ_qjy_O24s4kb0OA3S0d5651rQpOoMl344cHcWrD0,20635
7
+ getframes/dataset.py,sha256=mGyCz2jb73d5Ymvqrva2x_xWe_MJbpisaD6MS69_QS8,10882
8
+ getframes/frame.py,sha256=hbWQpvZLKIuw0iXpwOAutSbXd5NI6LZjgUqbjjRQi3g,3871
9
+ getframes/noise.py,sha256=x2Mb8VzGn-R8izBcildhYZujj_e0AE1nabatsNt_V60,26731
10
+ getframes/observation.py,sha256=voFRO5dB3bta_W5e494ZkTsezd6T7CsCchvla93e72w,5961
11
+ getframes/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ getframes/spectral.py,sha256=nRN5GaIO80NelOkDqoWBfwIQHWLtWxtcA8LoXSpL3Qc,18602
13
+ getframes/analysis/__init__.py,sha256=zpVsy3qcZmhoyjB_WNrTxgCdEgDDp3Jx8fhvTJ6Pshg,499
14
+ getframes/analysis/apertures.py,sha256=jffwmSAKfFsqS93K_iL7QJ7K69DpEhWwgNAv-Py4JfU,3212
15
+ getframes/analysis/ptc.py,sha256=XvxzjinZ6ruQ6BYAFOilEQRh-P-Lr_MNJRff1lB0AkM,4012
16
+ getframes/presets/__init__.py,sha256=B-hdvW_hzJjNnq3oh26RRCeyWlNvd11eJnf4lbJrXtI,2753
17
+ getframes/presets/data/__init__.py,sha256=AEjme3yN51EOw-w3ZtoeOq_kXVeiZX_Vib3zY7qLZmM,162
18
+ getframes/presets/data/andor_ikon_m934.toml,sha256=KMk3nWTTaMCD3QR_X0uu5xA5ZKGzI6xiz7g1bCTNoDw,861
19
+ getframes/presets/data/andor_ixon_ultra_888.toml,sha256=J_A9j0HDtyXCuCNGPGj2WiogXuZlM03eJj5sF55AxGM,812
20
+ getframes/presets/data/generic_ccd.toml,sha256=zsZgDQZN_oAdwc8KkNaw315KwrP5D41UPrW_7aba6oY,523
21
+ getframes/presets/data/generic_cmos.toml,sha256=-bBn_-GhMvdrcDUPKoHqpo278yre8PSWvXywj8jEE0g,539
22
+ getframes/presets/data/generic_eapd.toml,sha256=IEnFxouV4h3VQCzv1EJ1KFWtcpI9nIQ3mfxD73GPsOg,709
23
+ getframes/presets/data/generic_emccd.toml,sha256=txGHZeCZLefCYce5N0Jp7BvBLA6ppuAU1ahg5YywpfM,566
24
+ getframes/presets/data/generic_scmos.toml,sha256=Y3yWEnOe_16mg9xt7lGaUMEtr-wd6ZpfvlkSI0o5SbI,670
25
+ getframes/presets/data/hamamatsu_orca_fusion.toml,sha256=WKyiZOzEvDzOqNZ2P7_EYY2FdEignAW-5LDDQbfnUCQ,927
26
+ getframes/presets/data/leonardo_saphira.toml,sha256=NySszBi6EJ_T3pPbqOpkqA14nvsC9u4sFqRXbM5O_B8,1601
27
+ getframes/presets/data/zwo_asi2600mm.toml,sha256=rWhKY14MhZKTyKlREo8X_lRtdfJZcKgFoqyf4YfhU4Y,696
28
+ getframes/scene/__init__.py,sha256=dv-1UUKLct0-At6mHie-TaHO7ODRX1mki0Ol7Wt_x3s,1195
29
+ getframes/scene/optics.py,sha256=3nHhEUNWPuLianUfhnY2ls7ia_zgvyY242_rdYNEIC8,7448
30
+ getframes/scene/photometry.py,sha256=COyGs6Y1he6VpeBPsnblPpjPzI2YlZS-ctVI8KB0NPY,13053
31
+ getframes/scene/psf.py,sha256=zhCxog6naqbg46JydgZuwd_Q1KpsvJv4TQlTxXPxekU,14245
32
+ getframes/scene/scene.py,sha256=fbtMDKnVBPWNWWtIKqAeNx3bHot5XgnQ7dnqjifUM_Q,8450
33
+ getframes/scene/sources.py,sha256=S-6evDUQWwKFzFPwpfs9Z9fBKXBOgRD4rvbWv0hnoC4,26984
34
+ getframes/scene/thermal.py,sha256=D3qaXjkTWTEZOAaWhzXz5C10I8LbJMxJEYRaPXpZIEs,4533
35
+ getframes/scene/wcs.py,sha256=OKiQ61GKRrCERdOzR5YDIAa-yB9tLRGdvZM2L387aSc,4311
36
+ getframes-2.0.0.dist-info/METADATA,sha256=whb3WX5CLwyXjzMaJHTg-BXHzjiWd5AV4FTYNiz3N1c,8643
37
+ getframes-2.0.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
38
+ getframes-2.0.0.dist-info/entry_points.txt,sha256=T0YhnQ84VNBUdT9zVkqgQFBIwXxQ12Gg51aE3iqwLkQ,49
39
+ getframes-2.0.0.dist-info/licenses/LICENSE,sha256=Rq27HaZyzpe1GFxNTVS3xJaRD_O4IauJs9fdQlEOuis,1069
40
+ getframes-2.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.30.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ getframes = getframes.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jacob Taylor
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.