Documentation

From install to first measurement.

Four steps: install the package, add your key, capture the chart well, read the output. Written for lab scripts and notebooks.

01

Install and license

CircleSFR targets Python 3.10+ · NumPy, SciPy, Pillow · macOS, Windows, Linux. The PyPI release is in preparation; until it publishes, evaluation installs are delivered as a wheel by email with your key.

$ pip install circlesfr
$ export CIRCLESFR_LICENSE=/path/to/license.key
# or place the key at ~/.circlesfr/license.key

Keys are Ed25519-signed files that verify offline — nothing phones home, and air-gapped machines work. Evaluation keys run 30 days with watermarked outputs. Request one by email.

02

Capture the chart

Frame the chart to fill the image width, square to the camera. What matters is the field of view the chart covers, not the distance: distance to fill the frame ≈ chart width ÷ (2 × tan(HFOV/2)). Light evenly, expose so neither the white field nor the dark rings clip — the software reports per-channel clipping fractions, so a bad exposure is caught on the first run.

Chart sizes and single-capture ratings: CircleSFR 400 (400 mm, ≤3 MP) · CircleSFR 800 (800 mm, ≤12 MP) · CircleSFR 1200 (1200 mm, ≤28 MP). See the size picker for a recommendation.

03

Run the analysis

>>> import circlesfr
>>> result = circlesfr.analyze("capture_042.tif")
>>> result.summary["sfr50_sag_l"]      # center SFR50, cy/px
0.2609
>>> result.clipping.high               # per-channel clipping
(0.0021, 0.0018, 0.0016)

The package linearizes the capture, registers all 83 ring markers, fits an ellipse to each ring, and measures four edge sectors per ring — sagittal left/right and meridional near/far — giving a dense MTF map across the field from a single image.

04

Read the output

result.summary
SFR50/SFR10 per sector (sagittal L/R, meridional near/far) and sampling efficiency vs Nyquist
result.sfr
Full SFR/MTF curves, 201 frequency samples per ring sector
result.clipping
Per-channel low/high clipping fractions for exposure checks
result.markers
Detected ring positions, ellipse axes, and optical/chart centers
render_annotated_image()
Capture overlay with sectors color-coded by normalized field radius

Results are Python objects today; CSV export, PDF reports, and a batch CLI are on the roadmap and will be announced when they ship. Frequencies are cycles/pixel with Nyquist at 0.50.

Stuck on a capture or an unexpected curve?

Send the capture and your chart serial number to rex@circlesfr.com. The serial ties your print to its QC certificate, which speeds up diagnosis.