3.5 KiB
Signature verification baseline
A small research starter project for online handwritten-signature verification. It includes common-format CSV/JSON loading, preprocessing, feature extraction, DTW matching, threshold metrics, and a local FastAPI capture demo.
Setup
From the project root:
py -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -e ".[dev]"
$env:SIGVERIFY_FERNET_KEY = python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
uvicorn app.main:app --reload
Open http://127.0.0.1:8000/. The generated Fernet key is for local testing; keep the same key between runs to read previously enrolled templates. Store a production key in a secret manager, never in source control. Without a key, the API rejects enrollment and verification rather than storing plaintext.
Run tests with pytest. The package can also be installed with pip install -e ..
Data format
The common signature format has one sample per point with user_id, t, x,
y, optional p (pressure), optional area (contact area), and optional
pen_down. CSV loaders expect these names by default; pass column overrides
for a dataset with different headers. A JSON signature uses the same names
with array-valued t, x, and y. For MOBISIG, check the downloaded release's
layout is supported directly by load_mobisig: timestamp, x, y,
pressure, and fingerarea are mapped automatically. Names such as
SIGN_GEN_USER1_USER1_1.csv and SIGN_FOR_USER1_USER2_1.csv determine the
claimed user and genuine/forgery label; metadata files such as users.csv are
ignored. Put downloaded or self-collected material under data/raw/. Raw data
is ignored by Git.
Baseline workflow
- Load signatures into
Signature. - Sort timestamps, collapse repeated times, lightly smooth, resample, and translate/scale positions. Preprocessing records the original bounding-box diagonal because size may itself be discriminative. Pen-up samples are excluded from the baseline trajectory.
- Extract x/y and motion features; pressure and contact area can be enabled as explicit ablations.
- Enroll several genuine examples, compare using band-constrained DTW, and divide by the median within-enrollment distance.
- Tune global and per-user thresholds on a development split; evaluate only on held-out attempts. Thresholds in the demo are illustrative, not research results.
experiments/ contains starter scripts for inspecting data, running a simple
split, and comparing feature sets. Report user-disjoint development/test
results separately from the API demo. Do not train or tune on the test set.
For the included MOBISIG layout, run:
python experiments/02_baseline_dtw.py --data-dir data/raw/mobisig `
--output results/mobisig_baseline.json
Capture and consent
The browser sends pointer positions, elapsed milliseconds, and optional
pressure. It does not persist anything in the browser. Review
docs/data_collection_protocol.md and
docs/consent_form.md before collecting data; adapt
them to institutional requirements and obtain approval where required.
The SQLite demo stores encrypted template JSON and a small lockout counter in process memory. Lockout state resets when the server restarts, so this is not a production account-security system. Use HTTPS, authentication, durable rate-limiting, access controls, key management, and a retention/deletion policy before exposing a service beyond localhost.