Skip to content

Repository files navigation

Glamour Ships

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.

Slit-scan stitch of the OHIO tanker, assembled from a fixed-camera video

How it works

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

What works

  • 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.

What doesn't / work in progress

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.

Tech stack

  • 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.

Disclaimer

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.

Setup

python3 -m venv .venv
.venv/bin/pip install numpy Pillow websockets

Try it

./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 image

The 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).

Map

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.

About

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.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages