Skip to content

Add forensics & analytical geolocation: resection, reverse-heading, horizon, tz-crosscheck, fingerprinting, batch triage/timeline#12

Open
cognis-digital wants to merge 4 commits into
mainfrom
feature/forensics-analytical-geolocation
Open

Add forensics & analytical geolocation: resection, reverse-heading, horizon, tz-crosscheck, fingerprinting, batch triage/timeline#12
cognis-digital wants to merge 4 commits into
mainfrom
feature/forensics-analytical-geolocation

Conversation

@cognis-digital

Copy link
Copy Markdown
Owner

Summary

Adds geolens.forensics — an offline, standard-library-only layer of defensive analytical geolocation that multiplies what the toolkit can do for verification / OSINT / IR analysts. Everything is additive: the existing public API is unchanged and every new symbol is re-exported from the geolens package.

Scope: verification / analysis / defense only. No targeting, no network, no side effects — plain dicts in and out.

New capabilities

  • Geodesyhaversine_km, initial_bearing, destination_point, and resection (recover an observer position from two landmarks + the bearing to each; recovers a synthetic observer to within a few metres, with a residual_km quality figure).
  • Reverse headingreverse_heading: true bearing to a landmark from its pixel position + lens FOV, using the rectilinear (pinhole) projection so frame edges are handled correctly.
  • Horizon / terrain cueshorizon_distance_km, max_visible_distance_km, is_peak_visible: refraction-corrected geometry for a "could this peak even be seen from here?" falsification test.
  • Timezone cross-checktimezone_crosscheck: EXIF local clock vs GPS-UTC → implied UTC offset → longitude band; flags an image whose GPS longitude is inconsistent with its own clock (edited timestamp / transplanted GPS).
  • Camera fingerprint consistencycamera_fingerprint, fingerprint_consistency: tamper/splice signals across a set (mixed makes/models, editing-software tag, dimension drift).
  • Batch triage + clusteringcluster_locations, batch_triage: single-linkage spatial clustering + geotagged-vs-scrubbed folder triage.
  • Movement timelinebuild_timeline, timeline_to_geojson: time-ordered timeline with per-leg distance / elapsed / implied speed, exported as a GeoJSON Point series + LineString track.

CLI

New subcommands: resect, heading, horizon, tzcheck, fingerprint, triage, timeline. horizon / tzcheck / fingerprint exit 3 on a detected inconsistency (scriptable gate).

Demos & docs

  • demos/21_resection_and_horizon.py — metadata-free geolocation + falsification.
  • demos/22_batch_triage_timeline.py — folder → clusters + movement timeline (GeoJSON) + fingerprint tamper flag.
  • New docs/FORENSICS.md; README feature list + demo table + docs/DEMOS.md updated.

Both demos run offline and exit 0 (PYTHONUTF8=1 on Windows).

Tests

python -m pytest -q: 161 → 205 passing (new tests/test_forensics.py + forensics CLI-edge cases). Resection accuracy, rectilinear reverse-heading, horizon falsification, timezone consistency/spoof detection, fingerprint flags, clustering, and timeline ordering/GeoJSON are all covered.

…eck, fingerprinting, batch triage/clustering, movement timeline

Adds geolens.forensics (offline, stdlib-only) that multiplies the toolkit
with defensive analytical geolocation, all additive to the public API:

- Geodesy: haversine_km, initial_bearing, destination_point, resection
  (recover observer position from two landmark bearings, ~metre accuracy)
- reverse_heading: true landmark bearing from pixel position + lens FOV
  (rectilinear projection, correct at frame edges)
- Horizon cues: horizon_distance_km, max_visible_distance_km, is_peak_visible
  (refraction-corrected 'shot from here' falsification test)
- timezone_crosscheck: EXIF local clock vs GPS-UTC vs GPS longitude band,
  flags edited timestamps / transplanted GPS
- camera_fingerprint + fingerprint_consistency: tamper/splice signals
  across an image set (mixed makes, editing software, dimension drift)
- cluster_locations + batch_triage: single-linkage spatial clustering,
  geotagged-vs-scrubbed folder triage
- build_timeline + timeline_to_geojson: time-ordered movement timeline with
  per-leg distance/elapsed/implied-speed, exported as a GeoJSON track

New CLI subcommands: resect, heading, horizon, tzcheck, fingerprint, triage,
timeline (horizon/tzcheck/fingerprint exit 3 on a detected inconsistency).

Two runnable offline demos (21, 22), docs/FORENSICS.md, README + DEMOS
updates. Tests: 161 -> 205 (new tests/test_forensics.py + CLI-edge cases).
Comment thread demos/21_resection_and_horizon.py Fixed
Comment thread demos/22_batch_triage_timeline.py Fixed
Comment thread demos/22_batch_triage_timeline.py Fixed
Comment thread demos/22_batch_triage_timeline.py Fixed
Comment thread demos/22_batch_triage_timeline.py Fixed
Comment thread demos/22_batch_triage_timeline.py Fixed
Comment thread geolens/cli.py Fixed
Demo scripts intentionally print the lat/lon being analyzed — geolocation
output, the tool's purpose — which CodeQL's name heuristic misreads as
clear-text logging of sensitive data. Analyze geolens/ (the package) and
leave demos/tests/ports/integrations out via a codeql-config.yml.
@github-actions github-actions Bot added the ci label Jul 1, 2026
…to user stdout, not a secret sink

The py/clear-text-logging-sensitive-data query keys off lat/lon/location
variable names and flags the CLI's own output (the product), not any real
credential leak. Exclude that single query; all other CodeQL queries run.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants