Skip to main content

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.

Project description

getframes

CI PyPI Python License: MIT

Realistic synthetic camera frames for scientific imaging pipelines.

getframes gives you a clean, small API for generating physically realistic frames from CCD, CMOS, EMCCD, eAPD, and sCMOS detectors — with accurate, auditable noise physics (read noise, dark current, shot noise, fixed-pattern non-uniformity, a unified stochastic gain stage, clock-induced charge, nonlinearity, and cosmic rays) so you can build and validate image-processing pipelines against ground truth.

It generates dark, bias, and flat frames, and renders star fields through a PSF and telescope into a realistic science frame — the full photon → electron → ADU signal path, with optional opt-in spectral mode.

Status: stable. getframes 2.0 freezes the full public surface — the detector, scene, calibration, observation, radiometry, and dataset APIs — under Semantic Versioning; see API stability.

Install

pip install getframes

From source (for development):

git clone https://github.com/jacotay7/getframes
cd getframes
pip install -e ".[dev]"

Quick start

import getframes as gf

# Pick a camera from the built-in preset library...
cam = gf.Camera.from_preset("andor_ikon_m934")

# ...and generate a reproducible dark frame.
frame = cam.dark_frame(exposure=60.0, temperature=-60.0, seed=0)

frame.data            # 2-D numpy array of ADU, shape (1024, 1024)
frame.stats()         # {'mean': ..., 'median': ..., 'std': ..., 'min': ..., 'max': ...}
frame.metadata        # camera/exposure/temperature provenance

Frame is array-like, so it drops straight into NumPy:

import numpy as np
master_dark = np.mean([np.asarray(f) for f in cam.dark_series(60.0, n_frames=20, seed=1)], axis=0)

Define your own camera

cam = gf.Camera(
    gf.CameraConfig(
        name="My Lab CMOS",
        sensor_type="CMOS",
        resolution=(2048, 2048),       # (height, width)
        pixel_size_um=6.5,
        quantum_efficiency=0.82,
        full_well_e=30_000,
        bit_depth=12,
        gain_e_per_adu=0.8,
        bias_offset_adu=300,
        read_noise_e=1.8,
        dark_current_e_per_s=0.5,      # at the reference temperature
        dark_current_ref_temp_c=20.0,
        dark_current_doubling_temp_c=6.0,
    )
)
frame = cam.dark_frame(exposure=30.0, temperature=-10.0)

Observe a simulated star field

Render astronomical sources through a PSF and telescope, then expose them on a detector — the full photon → electron → ADU path:

scene = gf.Scene(
    shape=(256, 256),
    optics=gf.Telescope(aperture_diameter_m=2.5, throughput=0.3,
                        plate_scale_arcsec_per_pixel=0.4, band=gf.Bandpass.johnson("V")),
    psf=gf.MoffatPSF(fwhm_arcsec=1.1, beta=3.0),
    sources=[gf.PointSource(x=128, y=128, magnitude=20.0)],
    sky=gf.Sky(surface_brightness_mag_arcsec2=21.0),
)
cam = gf.Camera.from_preset("zwo_asi2600mm").with_config(resolution=(256, 256))
frame = cam.observe(scene, exposure=300.0, seed=0)   # a realistic science frame

You can also drive the detector directly with a photon-rate map (a scalar for a uniform flat, or a per-pixel array): cam.expose(photon_rate, exposure).

Browse the preset library

from getframes import available_presets
from getframes.presets import preset_info

available_presets()   # ['andor_ikon_m934', 'andor_ixon_ultra_888', 'generic_ccd', ...]
preset_info()         # rich descriptors for each preset
Preset Sensor Notes
andor_ikon_m934 CCD Deep-cooled back-illuminated scientific CCD
andor_ixon_ultra_888 EMCCD Single-photon-sensitive EMCCD
leonardo_saphira EAPD HgCdTe avalanche IR array (AO wavefront sensing)
zwo_asi2600mm CMOS Sony IMX571 cooled CMOS
hamamatsu_orca_fusion sCMOS Back-thinned sCMOS with per-pixel read noise
generic_ccd / generic_cmos / generic_emccd / generic_eapd / generic_scmos Idealised references for teaching/testing

How the dark-frame model works

The dark signal chain (see getframes/noise.py):

  1. Dark current vs. temperatureD(T) = D_ref · 2^((T − T_ref) / T_double)
  2. Fixed-pattern non-uniformity (DSNU) and hot pixels modulate the per-pixel mean
  3. Shot noise — Poisson statistics on the dark electrons
  4. Clock-induced charge (EMCCD) — small Poisson term
  5. EM gain (EMCCD) — stochastic multiplication with realistic excess noise
  6. Read noise — Gaussian at the output amplifier
  7. Digitisation — gain conversion to ADU, bias pedestal, saturation, quantisation

All randomness flows through a seeded numpy.random.Generator, so every frame is reproducible.

Documentation

Roadmap

1.0 is shipped: the full photon → electron → ADU signal path (dark, bias, flat, and rendered scenes) across CCD / CMOS / EMCCD / eAPD / sCMOS, with a unified gain stage, detector-realism effects, opt-in spectral mode, analysis helpers, and a frozen API.

The 2.0 plan moves from a frame to an observation — closing the raw → reduced → ground-truth validation loop, making time-series (variability, jitter, persistence) and richer scenes (extended sources, catalogs, sky coordinates) first-class, and deepening detector and radiometric fidelity. See docs/roadmap.md for the full critique, phased plan, and worked examples.

Contributing

Contributions — especially new camera presets — are welcome. See CONTRIBUTING.md. Run the checks locally with:

ruff check . && ruff format --check . && mypy && pytest

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

getframes-2.0.0.tar.gz (121.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

getframes-2.0.0-py3-none-any.whl (88.0 kB view details)

Uploaded Python 3

File details

Details for the file getframes-2.0.0.tar.gz.

File metadata

  • Download URL: getframes-2.0.0.tar.gz
  • Upload date:
  • Size: 121.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for getframes-2.0.0.tar.gz
Algorithm Hash digest
SHA256 efe8b0f408d23e8e62421b99078e649a09016e256c99f5efc1a2e6cafb1c9639
MD5 46dd9b75e19006dbf783474f7636c115
BLAKE2b-256 08dc930cf45235644e2a9114dfe643ff6b46647a1009e944930ee007a52966e0

See more details on using hashes here.

Provenance

The following attestation bundles were made for getframes-2.0.0.tar.gz:

Publisher: release.yml on jacotay7/getframes

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file getframes-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: getframes-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 88.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for getframes-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 619ecb468aef89c39b8d8c5964f503da5ec87e6d053a10d5efcb05b550ebc996
MD5 9f5992217d3be6ad31f5dc096c9bc6ec
BLAKE2b-256 826467acc09941c47776945033772e4f564d9440ea757efab919da5247fe1420

See more details on using hashes here.

Provenance

The following attestation bundles were made for getframes-2.0.0-py3-none-any.whl:

Publisher: release.yml on jacotay7/getframes

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page