Skip to main content

SPE SDK

CI Python versions License: MIT

Python SDK for the Spatial Intelligence Engine (SPE) — spatial-intelligence middleware that turns visual observations into a persistent spatial representation. The SDK gives Python applications two ways to work with SPE:

  • Local core — four-point planar calibration, coordinate transforms, grid rendering, point inspection, and detection spatialization, all in-process with no server required.
  • HTTP client — a typed, dependency-free client for a running SPE engine server (Flask API), with a synchronous SPEClient and an asyncio AsyncSPEClient.

Part of the SPE entry for the OpenCV AI Competition 2026.

Full SDK documentation → · Browse the static documentation files

Contents

Highlights

  • Calibrate a camera/plane from four image points (TL, TR, BR, BL) using OpenCV.
  • Map image pixels ⇄ normalized reference-plane coordinates via a reusable homography.
  • Resolve calibrated grid cells and semantic zones (A1, B3, AA2, ...).
  • Inspect single points against the canonical spatial state contract.
  • Enrich provider-neutral detections with calibrated spatial data.
  • Render image-space and perspective-correct calibrated grid overlays.
  • Talk to a live SPE server: sources, calibration, ROI, grids, inspection, models, detection, and video sessions.
  • Choose a synchronous or asyncio client, with swappable HTTP transports (stdlib urllib, requests, or httpx).
  • Fully typed (PEP 561 py.typed), linted with ruff, checked with mypy, and tested to ~99% line coverage.

Installation

pip install spe-engine            # published distribution
pip install "spe-engine[http]"    # + the optional httpx transport
pip install "spe-engine[docs]"    # + documentation tooling
pip install -e .                  # editable install from this repository
pip install -e ".[dev]"          # + test/lint/type/build tooling
pip install -e ".[docs]"         # + documentation tooling

For a published install, extras can be combined as pip install "spe-engine[http,docs]". From a source checkout, pip install -e ".[dev]" installs the development tools.

The PyPI distribution is named spe-engine; import it in Python as spe.

Runtime dependencies are intentionally small: numpy and opencv-python-headless. The synchronous HTTP client and the AsyncSPEClient wrapper use only the Python standard library; the http extra is only needed to opt into the httpx transport.

Requirements

  • Python 3.10 – 3.14
  • numpy >= 1.24
  • opencv-python-headless >= 4.8

Quick start — local core

from spe import SpatialEngine

# Four image points in TL, TR, BR, BL order for a 1280x720 frame.
engine = SpatialEngine(grid_rows=4, grid_columns=6)
engine.calibrate(
    [[180, 120], [1090, 150], [1180, 640], [90, 660]],
    source_width=1280,
    source_height=720,
)

image_point = [640, 360]
result = engine.inspect(image_point)

print(result["reference"])  # calibrated reference coordinates
print(result["grid_cell"])  # {"row": .., "column": .., "coordinate": [col, row]}
print(engine.zone_for_image_point(image_point))  # e.g. "C4"

Quick start — HTTP client

from spe import SPEClient

with SPEClient("http://127.0.0.1:5000") as client:
    print(client.health())
    print(client.list_models())

    source = client.create_source("frame.jpg", source_type="image")
    calibration = client.calibrate(
        [[180, 120], [1090, 150], [1180, 640], [90, 660]],
        source_width=1280,
        source_height=720,
    )
    inspection = client.inspect_point(
        [640, 360],
        calibration=calibration["calibration"],
        grid={"rows": 4, "columns": 6},
        source_dimensions={"width": 1280, "height": 720},
    )
    print(inspection)

Quick start — async client

AsyncSPEClient mirrors SPEClient with the same method names, each exposed as a coroutine. It offloads the blocking transport to a worker thread, so it adds no dependencies and is safe to await inside an event loop.

import asyncio

from spe import AsyncSPEClient


async def main() -> None:
    async with AsyncSPEClient("http://127.0.0.1:5000") as client:
        print(await client.health())
        models = await client.list_models()
        print(models)
        await client.set_grid(rows=4, columns=6)


asyncio.run(main())

Quick start — command line

spe health
spe --url http://127.0.0.1:5000 models
spe state
spe calibrate --size 1280x720 --points 180,120 1090,150 1180,640 90,660
spe inspect --x 640 --y 360 --calibration calibration.json --size 1280x720
spe --version

spe is installed as a console script; python -m spe ... works too. See the CLI reference for every option.

Configuration

Both clients accept the same connection options:

from spe import SPEClient, get_default_transport

client = SPEClient(
    "http://127.0.0.1:5000",
    timeout=30.0,  # per-request timeout, seconds
    retries=2,  # retries for idempotent requests on connection loss or 429/5xx
    backoff=0.5,  # base backoff, doubles each retry (or the Retry-After value)
    user_agent="my-app/1.0",  # optional User-Agent header
    api_key="...",  # optional X-API-Key header
    token="...",  # optional Authorization: Bearer token
    headers={"X-Trace": "abc"},  # extra headers on every request
    transport=get_default_transport("urllib"),  # force a transport backend
)

Read the base URL (and optional credentials) from the environment with from_env (default variable SPE_API_URL, falling back to http://127.0.0.1:5000; also reads SPE_API_KEY and SPE_API_TOKEN):

from spe import SPEClient, AsyncSPEClient

client = SPEClient.from_env()
async_client = AsyncSPEClient.from_env("SPE_API_URL")

Spatial model

SPE keeps three coordinate systems distinct:

  1. Image coordinates — pixels, origin at the top-left.
  2. Spatial / reference coordinates — a calibrated, application-defined plane (normalized 1000 x 600 by default; optional physical units).
  3. Virtual grid coordinates — logical cells and semantic zones over the plane.

A four-point calibration computes the homography that maps image coordinates to the reference plane; its inverse maps back. Units stay normalized unless you explicitly request physical dimensions — the SDK never fabricates physical scale. Grid cells are zero-based and exposed as (column, row); zones use spreadsheet-style ids such as A1, B3, and AA2.

Error handling

All errors derive from SPEError:

Exception Meaning
SPEError Base class for every error raised by the SDK.
SPEValidationError Invalid geometry or parameters (also a ValueError).
SPEEngineError Local processing cannot complete (also a RuntimeError).
SPEModelUnavailableError A perception model has no usable runtime.
SPETransportError Base class for HTTP transport failures (also a RuntimeError).
SPEConnectionError The server cannot be reached.
SPETimeoutError A request exceeded its timeout.
SPEAPIError The server returned an error (.status_code, .payload, .url, .retry_after).
SPEBadRequestError HTTP 400: invalid request payload.
SPEAuthenticationError HTTP 401/403: missing or rejected credentials.
SPENotFoundError HTTP 404: the resource does not exist.
SPEConflictError HTTP 409: the server state rejected the request.
SPERateLimitError HTTP 429: the client is being throttled.
SPEServerError HTTP 5xx: a server-side failure.

The status-specific errors subclass SPEAPIError, so existing except SPEAPIError handlers keep working.

from spe import SPEClient, SPEAPIError, SPEError

try:
    with SPEClient("http://127.0.0.1:5000") as client:
        client.get_source("missing")
except SPEAPIError as error:
    print(error.status_code, error.payload)
except SPEError as error:  # catch-all for the whole SDK
    print("SPE error:", error)

Examples

Runnable scripts live under examples/:

Script Shows
local_calibration.py In-process calibration, inspection, zones, and state round-tripping.
detect_and_spatialize.py Enriching provider-neutral detections with calibrated spatial data.
retail_zone_analytics.py Per-zone occupancy, unique visitors, and dwell time from a frame sequence.
security_intrusion_detection.py Alerting when a person's ground point enters a restricted polygon.
warehouse_grid_inventory.py Bay occupancy map, empty-bay list, and fill ratio from pallet detections.
traffic_lane_speed.py A metric reference plane (units="meters") for lane assignment and speed.
annotated_overlay.py Rendering the calibrated grid plus zone-labelled boxes to a PNG.
tracking_and_motion.py Stable track ids, per-track speed, and next-position prediction.
analytics_pipeline.py Zone occupancy, track summaries, line crossings, and observation persistence.
http_client.py Talking to a running engine with the synchronous client.
async_client.py The asyncio client (AsyncSPEClient).
http_analysis_session.py A full server analysis session: health, source, frames, complete.
stream_video.py Streaming video frames into the detection endpoint with OpenCV.

Stand-alone demo apps

Four self-contained apps install the built SDK wheel from examples/assets into their own virtual environments. They never import from src/, so each one demonstrates SDK independence end to end.

Demo Shows
examples/cli Interactive media shell driven by assets/link.json, with lane analytics, overlays, and JSON reports.
examples/powershell PowerShell bootstrap that invokes a real .bat batch analyzer over multiple clips.
examples/template Flask studio that applies spatial presets and Jinja JSON templates to media or uploads.
examples/web FlowTraffic OPS camera wall with selected-feed lane analytics, incident logging, advisories, and replay.

Run any demo with its run.ps1 / run.bat; the first run bootstraps its local .venv. The large sample videos stay local and are intentionally gitignored; the wheel and link.json are tracked so the demos remain installable.

Documentation site

The standalone documentation pages work without a JavaScript framework or external assets. Browse the static pages or open the complete Markdown API reference.

API overview

The full, exhaustive reference is in docs/index.md. At a glance:

Surface Key symbols
Local facade SpatialEngine
HTTP clients SPEClient, AsyncSPEClient
Uploads FileSource (bytes, path, or binary stream)
Transports Transport, UrllibTransport, RequestsTransport, HttpxTransport, get_default_transport
Value objects BoundingBox, Detection, ReferencePlane, GridCell, Zone, Calibration, ModelDescriptor
Geometry calculate_calibration, calculate_homography, transform_points, inverse_homography, validate_homography, validate_source_points, reprojection_error, warp_image, REFERENCE_WIDTH, REFERENCE_HEIGHT, POINT_ORDER
Spatial inspect_point, image_to_spatial, point_in_roi, spatial_point_to_grid_cell, spatialize_detection, spatialize_detection_result
Rendering GridConfig, generate_grid, generate_calibrated_grid
Inference InferenceContext, resolve_inference_context
Zones row_label, generate_zones, zone_for_cell
Tracking ModelAgnosticTracker, TrackingConfig
Motion SpatialTrackStateManager, MotionConfig
Analytics ZoneOccupancyTracker, LineCrossingCounter, TrackSummary, summarize_tracks
Observations create_observation, create_image_observation, ObservationBatchWriter
Errors SPEError, SPEValidationError, SPEEngineError, SPEModelUnavailableError, SPETransportError, SPEConnectionError, SPETimeoutError, SPEAPIError, SPEBadRequestError, SPEAuthenticationError, SPENotFoundError, SPEConflictError, SPERateLimitError, SPEServerError

Development

pip install -e ".[dev]"

ruff check .          # lint
ruff format --check . # formatting
mypy                  # types (config in pyproject.toml)
pytest --cov=spe      # tests + coverage

The suite covers geometry, inspection, zones, tracking, motion, observations, the engine facade, value objects, the sync and async HTTP clients (against a local mock server), the transports, and the CLI. Linting, formatting, and strict type checking all pass, with line coverage held at ~99%. See CONTRIBUTING.md for the quality gates and conventions.

Package layout

src/spe/
├── __init__.py       # public API surface
├── __main__.py       # `python -m spe`
├── engine.py         # SpatialEngine — stateful local facade
├── client.py         # SPEClient — stdlib HTTP client
├── aio.py            # AsyncSPEClient — asyncio wrapper
├── transport.py      # Transport protocol + urllib/requests/httpx backends
├── geometry.py       # homography + four-point calibration
├── spatial.py        # inspection + detection spatialization
├── grid.py           # image-space & calibrated grid rendering
├── zones.py          # semantic zone identifiers
├── tracking.py       # provider-neutral multi-object tracking
├── motion.py         # trajectories, velocity, direction & prediction
├── observations.py   # provider-neutral observation builders
├── models.py         # typed value objects
├── exceptions.py     # SPE error hierarchy
├── _version.py       # single source of truth for the version
└── cli.py            # `spe` command-line interface

Releasing

  1. Bump __version__ in src/spe/_version.py.
  2. Move the Unreleased entries in CHANGELOG.md under the new version.
  3. Build and validate the artifacts: python -m build and twine check dist/*.
  4. Upload with python -m twine upload dist/*, then tag the same version, e.g. git tag v0.2.1 && git push origin v0.2.1.

Contributing

Contributions are welcome — see CONTRIBUTING.md.

License

MIT © Peach LLC. See LICENSE.

Metadata

Release files for spe-engine 0.2.1

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

Source distribution (sdist)

Source distribution for spe-engine 0.2.1
File Size Uploaded Provenance
spe_engine-0.2.1.tar.gz 126.2 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for spe-engine 0.2.1
File Interpreter ABI Platform
spe_engine-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 183.2 kB

Release files / spe_engine-0.2.1.tar.gz

Download URL spe_engine-0.2.1.tar.gz
Size 126.2 kB
Tags Source
SHA-256 checksum
How to use checksums
f5e2b9b12932177b24dbd8128ed2fc5794026ae3ddfd8f7923c1a846907c05d7
BLAKE2b-256 checksum
How to use checksums
1e57028404910d6fd9e7124ffbeaf86c1f1d696371f15605d8f8bce7a2325971
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Release files / spe_engine-0.2.1-py3-none-any.whl

Download URL spe_engine-0.2.1-py3-none-any.whl
Size 56.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b57d829bf6ee265b0cb2b2417628e15dd8a8ad3860b3c5bca749d322b3ceaad1
BLAKE2b-256 checksum
How to use checksums
b6c7d097b788f57bccf93d41ac2a29e4377f49b263d0e648508653a020ac6427
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Security for spe-engine 0.2.1

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

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.

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files No provenance

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