Skip to content

Read GPS DoP from GPS9 cameras, which report GPSDOP - #840

Open
caglarpir wants to merge 1 commit into
mapillary:mainfrom
caglarpir:fix-exiftool-gps9-dop
Open

caglarpir wants to merge 1 commit into
mapillary:mainfrom
caglarpir:fix-exiftool-gps9-dop

Conversation

@caglarpir

Copy link
Copy Markdown
Contributor

Problem

The exiftool reader looks for GPSHPositioningError only. Cameras with GPS9 telemetry (GoPro MAX 2, HERO11 and newer) do not write that tag — they write GPSDOP.

So every point came back with precision=None, the DoP test in remove_noisy_points() was skipped entirely, and the reader accepted tracks the native GPMF parser rejects as noise. On a MAX 2 clip the two readers disagree completely:

native    n=267  precision=185.0 / 207.0
exiftool  n=267  precision=None  (x267)

This is why --geotag_source exiftool_runtime accepts the noisy MAX 2 clip from the report that --geotag_source native rejects.

Fix

The tags are mutually exclusive per telemetry generation, and both scale by 100 — though for different reasons: GPSDOP is a dilution of precision, which is what GPMF's GPSP holds, while GPSHPositioningError is a horizontal error in metres and only approximates it. Read GPSDOP first, fall back to GPSHPositioningError:

camera tag emitted read as native GPMF
MAX 2 (GPS9) GPSDOP 1.85 / 2.07 185 / 207 185 / 207 ✓
hero8 (GPS5) GPSHPositioningError 99.99 9999 9999 ✓

GPS5 cameras are untouched.

Relationship to #831

This hole pre-dates #831main forced through --geotag_source exiftool_runtime already yields the unfiltered track. #831 briefly made the default chain reach it, and was revised (898988b) so it no longer does. This PR closes the hole itself, independently.

Verification

Tag reading verified on real MAX 2 footage. The rejection behaviour is covered by unit tests rather than a fixture: the MAX 2 files available locally all happen to have good DoP, and the reported noisy clip is not on this machine.

Full suite passes, mypy and ruff clean. (test_persistent_cache::test_multiprocess_shared_cache_comprehensive is flaky under parallel load on this machine — it passes in isolation both with and without this change.)

The exiftool reader looked for GPSHPositioningError only. Cameras with
GPS9 telemetry (GoPro MAX 2, HERO11 and newer) do not write that tag;
they write GPSDOP. So every point came back with precision=None, the DoP
test in remove_noisy_points() was skipped entirely, and the reader
accepted tracks the native GPMF parser rejects as noise.

On a MAX 2 clip the two readers disagreed completely:

  native    n=267  precision=185.0 / 207.0
  exiftool  n=267  precision=None  (x267)

The tags are mutually exclusive per telemetry generation and both scale
by 100, though for different reasons: GPSDOP is a dilution of precision,
which is what GPMF's GPSP holds, while GPSHPositioningError is a
horizontal error in meters and only approximates it. Read GPSDOP first
and fall back to GPSHPositioningError, so GPS5 cameras are untouched:

  MAX 2 (GPS9)   GPSDOP 1.85, 2.07  -> 185, 207   matches native exactly
  hero8 (GPS5)   GPSHPositioningError 99.99 -> 9999   unchanged

This is why "--geotag_source exiftool_runtime" accepts the noisy MAX 2
clip from T288698491 that "--geotag_source native" rejects. The hole
pre-dates PR 831; that PR only made the default chain reach it, and was
revised so it no longer does.

Verified on real MAX 2 footage for the tag reading. The rejection
behaviour is covered by unit tests rather than a fixture: the MAX 2
files available locally all have good DoP, and the reported noisy clip
is not on this machine.
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.

1 participant