Skip to content

Size digital frames from their camera's sensor (#32) - #39

Merged
NewGraphEnvironment merged 3 commits into
mainfrom
32-establish-sensor-widths-for-digital-fram
Aug 30, 2026
Merged

Size digital frames from their camera's sensor (#32)#39
NewGraphEnvironment merged 3 commits into
mainfrom
32-establish-sensor-widths-for-digital-fram

Conversation

@NewGraphEnvironment

Copy link
Copy Markdown
Owner

What

fly_footprint() marked every digital frame unknown_format with an empty geometry.
#30 made that gap honest; it did not close it. Province-wide it is 223,667 of
1,670,471 frames (13.4%)
, so fly was quietly film-only for anything after ~2010.

Digital frames now get real footprints. Sensor dimensions are read from the camera
calibration reports the catalogue already links to through camera_calibration_url,
parsed into inst/extdata/camera_formats.csv by data-raw/make_camera_formats.R
14 calibrations covering 169,688 frames, plus focal-length fallback rows.

Two findings that reshaped the work

Both were measured during exploration and confirmed with the user before implementation.

1. The catalogue's SCALE is not the true image scale for a digital frame. Verified
on 40 UltraCam Eagle frames against MRDEM-30 terrain:

route width
pixel count x GSD 6003 m
sensor width x (flying_height - terrain) / focal 6070 m
sensor width x SCALE (the old arithmetic) 2081 m

The first two agree to ~1% and reproduce the catalogue's own GROUND_SAMPLE_DISTANCE
to a 1.011 median ratio. SCALE is a derived nominal figure — the pixel pitch it
implies is ~12.5 um for every camera regardless of model, against real pitches of
3.9-12 um. Shipping a sensor width while keeping the scale path would have drawn
digital footprints at a third of true size, still overlapping neighbours and still
producing coverage percentages. SCALE is no longer used for a frame fly sized itself.

2. Digital sensors are not square — 1.10:1 (Leica DMC II) to 1.80:1 (Intergraph
DMC), and widths run 87.1 to 165.9 mm. A square footprint was up to 76% too deep, and a
single invented "digital" default would have been wrong by up to 90%. Non-square
footprints are rotated onto the flight line via fly_bearing(). Film stays square and
its output is unchanged.

How the numbers are trusted

They are parsed, never typed, and four checks gate the write:

check what it constrains result
B px x pitch vs the report's own stated mm, both axes 12/15 constrainable, max err 1.8e-16
C report focal vs the catalogue's focal 14/15 — flagged dmc100039
D plausibility bounds (width, aspect, pitch, focal) 15/15
F implied ground elevation must be a real BC elevation 14/15 — withheld 72914123
E an independent second reading of every report agreed exactly on all 14 shipped rows

B is skipped where the report did not state millimetres independently, rather than
counted as a vacuous pass. F's sensitivity is stated rather than assumed: doubling every
pitch makes only 8 of 14 cameras implausible, so it is a gross-error net and B is what
gives precision.

Check E earned its keep beyond confirmation. It recovered three reports that exist only
as scanned images, and established that the focal-83 frames are a 53.9 mm
medium-format body
— so the fallback that would have inferred a 104 mm UltraCam for
them is refused. That was a 93% error caught before it shipped.

Extrapolation is now opt-in per focal length with a written argument, because
extrapolation distance does not predict the error: the refused focal-83 row reached
across a 3.6% gap and was 93% wrong, while focal 120 reaches across a larger 5.5% gap
and is right.

Things caught by restoring the defect, not by reading

  • The rotation matrix was backwards — bearing 90 deg pointed the along-track axis west.
  • The orientation test was decoration: with the defect restored it still passed,
    because %% 180 discarded exactly the sign it existed to catch.
  • The 2013 UltraCam report renders 20010 as 2001O and drops the micron sign
    entirely — Pixel Size 5.200 m, which reads as metres.

Review

Three review rounds, 22 findings folded in. Round 2 found a blocker sitting inside
round 1's area: eligibility for the DEM route was keyed on the nominal-scale half-side,
which is NA for every camera-table row by construction — so the route the new docs
name as the only route for an inferred frame was unreachable, and silently. Reviews are
in planning/archive/.

Also

  • New width_source column names the calibration file or fallback rule per footprint
  • footprint_terrain gains "gsd_scaled"nominal_scale is documented as "sized
    from the reported scale", which this route never does
  • Frames naming a withheld calibration are refused rather than inferred
  • fly_georef() excludes non-square footprints: its corner mapping is calibrated for
    square, axis-aligned ones and would apply the bearing twice (follow-up: Georeference digital frames: the corner mapping assumes a square, axis-aligned footprint #38)
  • fly_bearing() no longer aborts on an NA film_roll
  • New inst/testdata/photo_centroids_digital.gpkg — 24 real frames from two cameras
    0.46 apart in aspect ratio, over the DEM that already ships
  • Corrects a CLAUDE.md claim that the bundled AOI has no digital frames; it has 181.
    That came from a BBOX(SHAPE, ...) CQL query returning 0 for a positive control — a
    broken probe, not an absence

Verification

  • 439 tests pass, 0 fail, 0 warnings
  • devtools::document() clean; NAMESPACE unchanged at 9 exports
  • lint +3 over the HEAD baseline, all confirmed installed-vs-source artifacts for the
    new internal functions
  • R CMD build ships inst/extdata; no planning/, data-raw/, dev/
  • Documented examples and the vignette's new chunk run

Fixes #32

NewGraphEnvironment and others added 3 commits August 30, 2026 09:21
Phases approved after plan-mode exploration against the live BC Data
Catalogue. The exploration answered the issue's "unknown at filing"
(14 cameras, 18 calibration files, not 2) and surfaced two findings that
reshaped the work: the catalogue's SCALE is not the true image scale for
digital frames, and digital sensors are not square.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GBKqedyBysV7hB4DuL98ZR
`fly_footprint()` marked every digital frame `unknown_format` with an empty
geometry, which #30 made honest but did not close. Province-wide that is
223,667 of 1,670,471 frames, so the package was quietly film-only for
anything after ~2010.

Sensor dimensions are recoverable from the calibration reports the catalogue
already links to through `camera_calibration_url`. They are parsed, never
typed, into `inst/extdata/camera_formats.csv` by
`data-raw/make_camera_formats.R` — 14 calibrations covering 169,688 frames,
plus focal-length fallback rows for frames carrying no calibration.

Two findings from the exploration reshaped the work:

`SCALE` is not the true image scale for a digital frame. Measured against
terrain on 40 UltraCam Eagle frames it gives 34% of true width — it is a
derived nominal figure, implying a ~12.5 um pixel pitch for every camera
regardless of model against real pitches of 3.9-12 um. Digital frames are
sized as `pixel count x ground_sample_distance` instead, needing neither
`scale` nor a DEM, and `SCALE` is no longer used for a frame fly sized itself.

Sensors are not square, from 1.10:1 to 1.80:1, so a square footprint was up
to 76% too deep. Non-square footprints are rotated onto the flight line via
`fly_bearing()`. Film stays square and its output is unchanged.

The numbers are gated on four checks before the table is written: pixel count
times pitch against the stated image size, report focal against the
catalogue's, plausibility bounds, and an implied ground elevation that must be
a real BC elevation. The last caught a camera whose catalogue metadata
contradicts its own report; it is withheld. An independent second reading of
every report agreed exactly on all 14 shipped rows.

`fly_georef()` excludes rotated footprints rather than double-applying its own
bearing rotation, which is calibrated for axis-aligned squares.

Fixes #32

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GBKqedyBysV7hB4DuL98ZR
@NewGraphEnvironment
NewGraphEnvironment merged commit 46aefd5 into main Aug 30, 2026
1 check passed
@NewGraphEnvironment
NewGraphEnvironment deleted the 32-establish-sensor-widths-for-digital-fram branch August 30, 2026 17:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Establish sensor dimensions for digital frames and ship them as a camera format table

1 participant