Skip to content

Latest commit

 

History

History
176 lines (125 loc) · 7.34 KB

File metadata and controls

176 lines (125 loc) · 7.34 KB

helenenschacht — Processing Run 2 (corrected)

← Back to main repo | Run 1 (original) →

helenenschacht orthophoto preview, Run 2

TL;DR

Run 1 produced a gcp_errors.error.z of 17.58 m, originally suspected as a datum/height-reference mismatch. Per-observation inspection revealed a single mis-annotated image observation on GCP3 (MAX_0131.JPG). Removing that observation reduced the aggregate GCP Z error to 0.13 m — a 99% reduction. The 3D reconstruction error is essentially unchanged.

Result comparison

Metric Run 1 Run 2 Δ
gcp_errors.error.z 17.575 m 0.128 m −99.3%
gcp_errors.le90 39.299 m 0.198 m −99.5%
gcp_errors.error.x 0.240 m 0.032 m −86.7%
gcp_errors.error.y 0.631 m 0.023 m −96.4%
3d_errors.error.x 0.133 m 0.143 m +7%
3d_errors.error.y 0.101 m 0.147 m +46%
3d_errors.error.z 0.309 m 0.354 m +15%
3d_errors.le90 0.297 m 0.294 m ≈0%
Runtime (ODM) 29m 17s 22m 38s −23%

GCP residuals collapsed to centimeter-level. The 3D reconstruction error metrics ticked up slightly — the corrupted observation acted as an extra (incorrect) constraint that artificially tightened the internal self-consistency, and removing it restored honest residuals. LE90 vertical is unchanged.

Diagnostic walkthrough

Step 1 — observed anomaly

Run 1 stats.json → gcp_errors reported error.z = 17.575 m, with std.z = 15.71 m. The mean Z bias was only +7.88 m — far smaller than the standard deviation, indicating one outlier point pulling the aggregate, not a uniform datum offset.

Step 2 — narrow datum mismatch hypotheses

Pulled image GPS metadata with exiftool:

GPS Altitude     : 513 m Above Sea Level
GPS Altitude Ref : Above Sea Level

GCP file heights: ~460–464 m, range only 3.5 m. Image altitude reference is orthometric (MSL). GCPs in EPSG:4326. No obvious unit mismatch.

EGM2008 geoid undulation for Austria ≈ +46 m. If a datum mismatch were the cause, expected offset would be ~46 m; observed was 17 m. Hypothesis rejected — uniform datum shift does NOT fit the math.

Step 3 — per-GCP inspection

Opened opensfm/stats/ground_control_points.json (only generated when ≥ 2 observations per GCP):

GCP Z residual Run 1 Observations
1 +0.052 m 7
2 −0.151 m 7
3 +39.299 m 7
4 +0.095 m 7
5 +0.095 m 7

GCP3 alone accounted for the entire anomaly. All other GCPs were sub-decimeter.

Step 4 — per-observation inspection on GCP3

GCP3's 7 image observations were inspected by comparing annotated (where the operator clicked) vs reprojected (where the reconstruction triangulated the GCP). Six observations had pixel-level agreement. Observation 7 (MAX_0131.JPG) showed:

annotated (normalized) reprojected (normalized) Δ
x 0.7035 0.3401 0.363
y 0.7393 0.6560 0.083

In a 5472×3648 image, that pixel offset is ~1988 px X, 304 px Y — the annotated location was nowhere near the actual GCP target. Likely a misclick or wrong-image assignment during GCP marking.

Step 5 — fix and re-run

Removed the single line containing MAX_0131.JPG for GCP3 from gcp_list.txt:

GCP1: 7 observations  (unchanged)
GCP2: 7 observations  (unchanged)
GCP3: 7 → 6 observations  ← removed MAX_0131
GCP4: 7 observations  (unchanged)
GCP5: 7 observations  (unchanged)

Re-processed with identical preset (Default / GPU). Verified the corrected GCP file actually reached ODM by comparing md5sums on the container-side input vs the intended edit before letting the task progress past feature extraction (lesson: WebODM ingests GCP from upload bundle, not from filesystem reference).

Step 6 — verdict

Run 2 GCP3 Z residual: −0.1942 m (was +39.299 m). All other GCPs unchanged. Aggregate metrics in Result comparison above.

Source & Acquisition

Same as Run 1. See Run 1 README → Source & Acquisition.

GCP Configuration

  • Points: 5
  • Observations per point: 6 on GCP3, 7 on others (1 outlier removed)
  • Coordinate system: EPSG:4326 (geographic) — auto-reprojected by ODM
  • Removed observation: MAX_0131.JPG annotated for GCP3 (mis-pointed by ~2000 px)

Processing Parameters

  • Preset: Default / Medium
  • GPU: NVIDIA RTX 3060 (CUDA)
  • Processing date: 21 May 2026, 05:08 UTC
  • Total runtime: 22 min 38 s (ODM internal)

Results

Reconstruction error (3d_errors)

{
  "mean":  {"x": 0.054,  "y": 0.048,  "z": 0.130},
  "std":   {"x": 0.133,  "y": 0.139,  "z": 0.330},
  "error": {"x": 0.143,  "y": 0.147,  "z": 0.354},
  "ce90":  0.164,
  "le90":  0.294
}

GCP residuals (gcp_errors)

{
  "mean":  {"x":  0.005,  "y":  0.005,  "z": -0.056},
  "std":   {"x":  0.031,  "y":  0.022,  "z":  0.115},
  "error": {"x":  0.032,  "y":  0.023,  "z":  0.128},
  "ce90":  0.062,
  "le90":  0.198
}

Centimeter-level GCP residuals on all axes. CE90 6.2 cm, LE90 19.8 cm.

GPS errors (gps_errors) — RTK quality

{
  "error": {"x": 0.63,  "y": 0.58,  "z": 2.43},
  "ce90":  1.14,
  "le90":  2.67
}

Essentially identical to Run 1 — same RTK input, observation removal does not affect GPS pre-georeferencing baseline.

Artifact Inventory (this folder)

File Description
preview.jpg Orthophoto thumbnail (1200 px, native RGB, drop alpha)
stats.json Complete OpenSfM statistics
ground_control_points.json Per-GCP and per-observation residuals (the diagnostic file)
REPORT.md ODM-generated narrative report
report.pdf ODM-generated visual report
shots.geojson Camera positions and orientations
cameras.json Self-calibrated camera parameters
images.json, img_list.txt Per-image metadata
coords.txt, proj.txt, gcp_list_utm.txt Georeferencing metadata
options.json, benchmark.txt Processing config and stage timing
log.json, task_output.txt Processing logs

Heavy raster artifacts (orthophoto GeoTIFF, DSM, dense point cloud, mesh, textures, full OpenSfM workspace) preserved at E:\Portfolio0\uav-photogrammetry-pipeline\backup\helenenschacht-run2-task-fadc0dae-...\.

Caveats

  1. 3D reconstruction error metrics ticked up slightly. This is expected: the corrupted observation acted as an extra constraint that artificially tightened internal self-consistency. The corrected solution shows honest residuals.
  2. Single-image annotation errors can dominate aggregate GCP statistics. With 5 GCPs, one bad observation out of 35 was enough to make the dataset look like it had a datum problem. Future workflows should examine per-GCP residuals before reporting only aggregate gcp_errors.
  3. No further outliers checked. Per-observation inspection on Run 2 was not repeated; only GCP3 was re-examined.

References