Skip to main content

focal

Image processing in C++20 with a zero-copy NumPy interface.

pip install focalpy
import focal

img = focal.imread("photo.jpg")            # linear float32, (h, w, c)
img = focal.exposure(img, 0.5)             # half a stop brighter
img = focal.resize(img, 1080, 1920)        # prefiltered, in linear light
img = focal.gaussian_blur(img, 2.0)
focal.imwrite("out.png", img)              # encodes back to sRGB

Why

Downscaling prefilters, so fine detail averages instead of aliasing. Shrinking by 4x means each output pixel must draw on about 4 input pixels. A resize that skips this doesn't lose fine detail gracefully — it invents patterns that were never in the image.

aliasing comparison

Filtering happens in linear light. Blurring and resizing mix pixels together, and mixing light is physics — it has to happen on linear values, not gamma-encoded ones. imread decodes sRGB on the way in and imwrite encodes on the way out, so every op in between is correct by construction.

linear light comparison

Averaging equal black and white gives half the light, which displays as light grey (182/255). Doing it on encoded values gives 128/255 — visibly too dark, and it compounds every time an image is resized.

Nothing converts silently. Array arguments are declared .noconvert(), so a float64 or non-contiguous array raises TypeError rather than quietly costing a full-size copy. Converting is the caller's decision, not a hidden one.

What's here

I/O imread, imwrite — PNG, JPEG, BMP, TGA
Resize resize — nearest, bilinear, Catmull-Rom, Mitchell, Lanczos3
Filtering gaussian_blur, correlate1d, separable_filter
Point ops gamma, exposure, brightness_contrast, invert, clip, blend, apply_lut
Sampling sample — nearest and bilinear at fractional coordinates
Color srgb_to_linear, linear_to_srgb

Box blur, Sobel, and unsharp mask fall out of the primitives above:

box    = focal.separable_filter(img, k, k)                    # k = ones(n)/n
sobel  = focal.separable_filter(img, [-1,0,1], [1,2,1])
sharp  = focal.blend(img, focal.gaussian_blur(img, 2.0), -0.5)

Border modes (clamp, reflect, reflect101, wrap, constant) are shared by every spatial op and match scipy.ndimage's semantics.

Design

Everything is a view. The core type is a non-owning {pointer, dtype, shape, strides} struct, so a crop, a single channel, and a NumPy array handed over from Python are all the same type, and none of them copy. Strides are in bytes, matching NumPy exactly, so wrapping an incoming array is copying six integers.

Ops run on float32 linear. dtype conversion happens at the edges of a pipeline, never per pixel inside an op.

Correctness is checked against independent oracles. The test suite compares against scipy.ndimage and PIL wherever one exists — border handling is verified for every index from -2n to 3n across four modes and four image sizes, and resize matches PIL's interior to 1e-7.

Building from source

Needs a C++20 compiler and CMake:

git clone https://github.com/edisons3608/focal
cd focal
pip install -e . --no-build-isolation
pytest

OpenMP is used when available (-DFOCAL_USE_OPENMP=OFF to disable). On macOS that means brew install libomp.

Status

Early, and the API will change. Missing so far: color space conversion beyond sRGB, geometric warps, histogram operations, 16-bit and HDR file formats.

License

MIT. Bundles stb (public domain).

Metadata

Release files for focalpy 0.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for focalpy 0.0.2
File Size Uploaded Provenance Actions
focalpy-0.0.2.tar.gz 255.3 kB With provenance Details for focalpy-0.0.2.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for focalpy 0.0.2
File Actions
focalpy-0.0.2-cp312-abi3-win_amd64.whl CPython 3.12 abi3 Windows x86-64 Details for focalpy-0.0.2-cp312-abi3-win_amd64.whl
focalpy-0.0.2-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.12 abi3 Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details for focalpy-0.0.2-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
focalpy-0.0.2-cp312-abi3-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl CPython 3.12 abi3 Linux glibc 2.27+ ARM64, Linux glibc 2.28+ ARM64 Details for focalpy-0.0.2-cp312-abi3-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
focalpy-0.0.2-cp312-abi3-macosx_11_0_arm64.whl CPython 3.12 abi3 macOS 11.0+ ARM64 Details for focalpy-0.0.2-cp312-abi3-macosx_11_0_arm64.whl
focalpy-0.0.2-cp312-abi3-macosx_10_15_x86_64.whl CPython 3.12 abi3 macOS 10.15+ x86-64 Details for focalpy-0.0.2-cp312-abi3-macosx_10_15_x86_64.whl

Total release size: 1.7 MB

Release files / focalpy-0.0.2.tar.gz

Download URL focalpy-0.0.2.tar.gz
Size 255.3 kB
Tags Source
SHA-256 checksum
How to use checksums
41a037d7e5147d47413d9a65f2c693659f41b88b6b7719c33f222ec0ae9aca65
BLAKE2b-256 checksum
How to use checksums
dd757771ba16b8c61d2ca41149f851e47c5accbd248d0861a447803a31f966f3
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 Sep 9, 2026.

Transparency log

Release files / focalpy-0.0.2-cp312-abi3-win_amd64.whl

Download URL focalpy-0.0.2-cp312-abi3-win_amd64.whl
Size 457.8 kB
Tags CPython 3.12 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
9fa06496d72dbc7e27ad965ab64b854b3f023666165a11e31774f8ce9c471dd1
BLAKE2b-256 checksum
How to use checksums
bf21df3a353cff54cc3c3df2b7e9df55d34679e1228469261b7fb5b144b25c8a
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 Sep 9, 2026.

Transparency log

Release files / focalpy-0.0.2-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL focalpy-0.0.2-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 334.0 kB
Tags CPython 3.12 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
0a0641edcaa311cf3ab00bc912987c7aee3e573c6c9559109a3bb462decc4d3b
BLAKE2b-256 checksum
How to use checksums
b3358860407393f21d1c6f8bae4cdf7461f417a428430cb098a4cf7848e8168f
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 Sep 9, 2026.

Transparency log

Release files / focalpy-0.0.2-cp312-abi3-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl

Download URL focalpy-0.0.2-cp312-abi3-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
Size 302.8 kB
Tags CPython 3.12 Linux glibc 2.27+ ARM64 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
4313c27468b4aafd00899a8f665573fac0996af4faf6c158c723f1c02253d034
BLAKE2b-256 checksum
How to use checksums
91361b0dc4d8bad3392befaad7113cd7e55531d9716a45d660c1fbfd2c4e291b
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 Sep 9, 2026.

Transparency log

Release files / focalpy-0.0.2-cp312-abi3-macosx_11_0_arm64.whl

Download URL focalpy-0.0.2-cp312-abi3-macosx_11_0_arm64.whl
Size 151.4 kB
Tags CPython 3.12 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
013e5ba3ad1bc576b8fe0fb40b8a64c0081dbd71cfab7b1c3c023ba6e288c595
BLAKE2b-256 checksum
How to use checksums
f6f770f7528daec7025750f72b7bfe3e66f4574f6794af8ce04eb62360163431
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 Sep 9, 2026.

Transparency log

Release files / focalpy-0.0.2-cp312-abi3-macosx_10_15_x86_64.whl

Download URL focalpy-0.0.2-cp312-abi3-macosx_10_15_x86_64.whl
Size 167.0 kB
Tags CPython 3.12 abi3 macOS 10.15+ x86-64
SHA-256 checksum
How to use checksums
bb2ba162e1f4cbe43ed447bd8425072fa5a0cca32d60398b0c1a1f3fd0914d95
BLAKE2b-256 checksum
How to use checksums
5e0e29007df9dca4a6bae7f489d6a5c24dc798dfedfa7731e76fe7c447207760
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 Sep 9, 2026.

Transparency log

Security for focalpy 0.0.2

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.

Full provenance

All 6 files in this release have been uploaded with provenance metadata.

Select from 6 files

Attestation for focalpy-0.0.2.tar.gz

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 Sep 9, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page