Skip to content

Repository files navigation

Iriscope

Iriscope is a local-first capture and enhancement pipeline for a Raspberry Pi Zero W with an IMX477 Raspberry Pi HQ camera. The Pi captures DNG/JPEG frames with rpicam-still; the computer pulls the session and performs RAW development, frame filtering, alignment, stacking, iris masking, enhancement, and review export.

Iris images are biometric data. This tool keeps processing local and intentionally does not upload images or perform identity matching. See SECURITY.md for local data-handling and remote API guidance.

Quick Start

python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e .[dev]
Copy-Item config.example.toml .iriscope.toml

Edit .iriscope.toml for your Pi hostname/user, then verify the camera:

iriscope calibrate

Capture a session:

iriscope capture --subject S001 --eye left --count 12

Process a pulled or manually copied session:

iriscope process captures\S001_left_20260616_153000
iriscope review captures\S001_left_20260616_153000 --open

Raspberry Pi Setup

Use Raspberry Pi OS (Legacy) Lite, 32-bit on the original Pi Zero W. See provision/pi-zero-w/README.md for the SD-card image choice and provisioning script.

Enable SSH, configure Wi-Fi, and verify the camera:

rpicam-hello --list-cameras

The capture command generated by Iriscope follows this pattern:

rpicam-still --raw --immediate --nopreview \
  --awb auto --metering centre --exposure normal --denoise cdn_fast \
  --metadata frame_0001.json --metadata-format json \
  --quality 95 -o frame_0001.jpg

rpicam-still --raw writes a paired .dng next to the JPEG. The Zero W should only capture frames; RAW processing and stacking happen on the computer.

Capture Advice

  • Use a fixed camera stand, fixed head/chin support, fixed camera distance, and manual lens focus.
  • Use diffuse, consistent white LED illumination.
  • Add cross-polarization if corneal reflections dominate.
  • Capture dark, flat-field, and white/color reference frames at the start of a session when possible.
  • Use 8-20 same-focus frames for denoising/detail stacking.
  • Use a separate focus bracket only when depth of field is visibly insufficient.

Outputs

Processing writes files under SESSION/processed/:

  • enhanced.tif: 16-bit enhanced master.
  • enhanced.jpg: review/share JPEG.
  • stacked.tif: stacked pre-enhancement image.
  • iris_mask.png: detected iris enhancement mask.
  • contact_sheet.jpg: before/after and frame overview.
  • report.json: deterministic processing report.
  • review.html: generated by iriscope review.

Dataset Evaluation

For offline algorithm testing, use a local iris dataset folder whose leaf directories contain same-eye frame stacks. I tested with the CASIA-Iris-Interval subset from CASIA-IrisV4. The original CASIA page describes it as 8-bit grayscale JPEG NIR iris imagery and releases it for research/educational use only, so keep downloads and derived reports local.

Example:

iriscope eval-dataset datasets\CASIA-Iris-Interval --offset 0 --limit 60 --max-working-edge 640

The evaluator writes dataset_report.json and dataset_sessions.csv under datasets\eval-runs\.... It records frame quality, post-alignment stack frame count, mask geometry, contrast/edge gains, and heuristic flags such as heavy clipping, weak alignment, bad mask geometry, and possible oversharpening.

Processing quality thresholds are configurable under [processing.quality] in .iriscope.toml. The defaults preserve the built-in heuristics for clipping, focus, luminance, alignment, mask coverage, pupil/iris ratio, dataset geometry checks, and oversharpening flags.

Useful Commands

iriscope init-config --output .iriscope.toml
iriscope calibrate --host raspberrypi.local
iriscope capture --subject S001 --eye right --count 16 --awb auto --iso 0
iriscope process captures\S001_right_20260616_154500 --dark calibration\dark.dng --flat calibration\flat.dng
iriscope eval-dataset datasets\CASIA-Iris-Interval --offset 60 --limit 60 --max-working-edge 640

Web GUI

The host-side GUI is a React/Vite app backed by the local Python API.

Install everything:

python -m pip install -e ".[web,webrtc,ssh,dev]"
cd web
npm install

Run the API and frontend in two terminals:

python -m iriscope web --host 127.0.0.1 --port 8765
cd web
npm run dev -- --port 5173

Open http://127.0.0.1:5173.

Docker Host Runtime

The host GUI/API can also run as one Docker container. The image builds the Vite frontend into static files and serves it from the FastAPI process on port 8765.

Create a Docker environment file:

Copy-Item .env.example .env

Edit .env for your Pi. If Iriscope.local does not resolve inside Docker, use the Pi IP address instead. To use SSH from the container, set IRISCOPE_SSH_KEY_HOST_PATH to the host key path and keep IRISCOPE_PI_SSH_KEY=/run/secrets/iriscope_ssh_key.

Run without an SSH key mount:

docker compose up -d --build

Run with the SSH key mount enabled:

docker compose -f docker-compose.yml -f docker-compose.ssh.yml up -d --build

Open http://127.0.0.1:8765. Captures are persisted under the local captures/ folder, and .iriscope.toml is mounted as the container config file. Docker binds to 127.0.0.1 by default; set IRISCOPE_BIND_ADDRESS and IRISCOPE_ADMIN_TOKEN before exposing it on a shared network. Docker-specific environment variables such as IRISCOPE_PI_HOST, IRISCOPE_PI_USER, and IRISCOPE_PI_SSH_KEY override the mounted TOML at runtime.

Docker uses the MJPEG preview transport by default. WebRTC relies on dynamic UDP ICE candidates, which Docker Desktop does not expose through the single HTTP port mapping, so the app starts MJPEG directly instead of attempting WebRTC and falling back. Set IRISCOPE_WEBRTC_ENABLED=true only when the container is running with host networking or another relay setup that makes WebRTC ICE candidates reachable.

To stop the container:

docker compose down

Docker Watchdog

The Docker watchdog keeps a deployed checkout aligned with GitHub. It compares the local HEAD with origin/main; when GitHub is newer, it runs git fetch, resets the checkout to origin/main, cleans untracked files, and rebuilds/restarts iriscope-host.

Run one check:

.\scripts\iriscope-docker-watchdog.ps1 -Once

Run continuously:

.\scripts\iriscope-docker-watchdog.ps1

For Bash environments:

scripts/iriscope-docker-watchdog.sh --once
scripts/iriscope-docker-watchdog.sh

The watchdog intentionally discards local edits in the deployed checkout so it matches GitHub. Use a separate development checkout for uncommitted work.

The GUI provides:

  • local device/dependency status, including COM port, UVC camera, SSH config, and Python dependencies
  • live Pi HQ camera preview fed by rpicam-vid over SSH, using WebRTC when available and MJPEG/still snapshot fallbacks otherwise
  • UVC preview snapshots for a directly attached USB camera when no Pi host is configured
  • capture controls for subject, eye, frame count, shutter, gain/ISO equivalent, AWB mode/gains, metering, exposure, and tuning file
  • pre-processing inspection that writes preprocess_report.json
  • processing controls for the existing stacking/enhancement pipeline
  • biometric label sidecars written as iriscope_labels.json

For the most reliable preview, run the Pi Zero as a USB Ethernet gadget and set [pi].host to the USB-side address, for example 10.42.0.2. The preview stream uses the [preview] config section:

[preview]
width = 640
height = 480
framerate = 12
quality = 70
stream_timeout_s = 0

Before calibration, still snapshots, or RAW stack capture, the host API stops the preview stream so rpicam-still can acquire the camera.

Label records are for local dataset governance only. They track consent, allowed use, exclusion from model training, quality notes, lens/lighting metadata, and subject codes. Iriscope does not perform identity matching or biometric enrollment.

The API is unauthenticated only for loopback use. If you bind it to a non-loopback host, set IRISCOPE_ADMIN_TOKEN and pass it as Authorization: Bearer <token> or X-Iriscope-Token. Web API session and artifact paths are bounded to the configured capture root; calibration files are accepted only from the capture root or project calibration/ directory.

About

No description, website, or topics provided.

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages