Watches live ship traffic near the Golden Gate via AIS, alerts on a qualifying transit, and stitches a fixed-camera video of the passing ship into one bow-to-stern image.
Two independent pipelines: a live AIS watcher that alerts on qualifying transits, and an offline slit-scan stitcher that turns a fixed-camera video into one bow-to-stern image.
WATCH + ALERT (live)
AIS feed (AISStream, wss://)
│ ship positions
▼
watch-and-ping.sh ─▶ ais_predictor/live.py websocket client
▼
ais_predictor/zones.py which zone is the ship in?
▼
ais_predictor/core.py qualifying (>=150m)? ETA to viewport?
│ qualifying transit
▼
notify/core.py macOS alert: "COMING IN: a 366m cargo ship..."
STITCH (offline, per video)
ship video
▼
ffmpeg frame extraction (5 fps)
▼
triage/core.py keep ship-present frames
▼
stitcher/core.py slit-scan: one vertical strip per frame,
strip width = velocity x frame-interval,
concatenate in transit order
│ (geometry.py supplies px/m + view gaps)
▼
one bow-to-stern "glamour" image
- Live AIS watching + transit alerts. A background watcher listens to live AIS broadcasts (every large ship reports its position, speed, and destination), detects big ships (≥150 m) heading toward a configured viewport, and pops a notification as they cross each zone — e.g. "COMING IN: a 366m cargo ship, bound for OAKLAND — eta to your viewport is 00:42:30." No AI in this loop; it's a deterministic AIS-to-notification pipeline. Verified against real ship traffic.
- Slit-scan stitching. The camera is stationary and the ship translates across the frame, so classic panorama tools don't apply. Instead: sample a thin vertical strip from every video frame, scale the strip width by the ship's AIS-reported velocity, and concatenate the strips side by side. The parade of strips reassembles the whole ship even though no single frame ever saw all of it. Proven end-to-end on one real transit — the tanker OHIO, shown above — from a fixed-camera video of the ship crossing the Gate.
This is a proof-of-concept snapshot, not a finished product:
- Capture is currently a human pointing a phone camera during the alert window, not an unattended mounted camera.
- No automated capture-trigger daemon, camera calibration, or capture app yet — those are still open work.
- Container counting, multi-ship handling, and anything beyond "recognizable bow-to-stern stitch" is out of scope for this snapshot.
- Python 3 — the AIS predictor, slit-scan stitcher, frame triage, notifications, and viewer.
- Bash — the watch-and-ping driver.
- numpy + Pillow — the stitching math and image I/O.
- websockets + asyncio — the live AIS feed.
- SQLite (stdlib) — the AIS log.
- ffmpeg (via subprocess) — frame extraction.
- macOS
osascript— desktop notifications. - Swift/Xcode (PLANNED, not yet present) — the mounted-camera capture daemon.
Local-only, no cloud.
Work in progress, provided as-is with no warranties of any kind. This
snapshot omits development history and internal process notes; see
LICENSE for the terms.
python3 -m venv .venv
.venv/bin/pip install numpy Pillow websockets./watch-and-ping.sh start # begin watching + notifications
./watch-and-ping.sh status # see what ships have crossed which zones
PYTHONPATH=src .venv/bin/python examples/stitch_demo.py # synthesize a simple transit and run the slit-scan stitcher -> writes a stitched imageThe stitch demo is a synthetic demonstration proving the stitcher runs end-to-end — no real ship footage or calibration required, so it runs on any clone as-is.
Full guide (config, filters, auto-start at boot): README-watch-and-ping.md.
Requires a free AIS key from AISStream (aisstream.io) (config.local.json,
gitignored — copy config.local.json.template) and a
calibration/view-geometry.json (copy calibration/view-geometry.json.template
and fill in your own camera + view geometry — the real file is
location-specific and not included).
| Where | What |
|---|---|
watch-and-ping.sh + README-watch-and-ping.md |
the daily-use tool + its guide |
src/ |
all pipeline code (see src/README.md) |
tests/ |
the test suite: PYTHONPATH=src .venv/bin/python -m unittest discover -s tests |
phase0/ |
the de-risking experiments that proved this could work |
calibration/ |
view geometry + zone boxes (local-only, not included) |
data/ |
AIS logs, video frames, stitched output (local-only, not included) |
All of it runs locally. The only network connection is the read-only AIS data feed — no cloud, no accounts beyond a free AIS key, and the day-to-day watcher involves no AI at all.
