title: "Keypoint-size-normalised reprojection error: the kps metric"
status: unverified
applies_to: Metashape Pro 2.x — and PhotoScan 1.x via the same TiePoints.Projection.size (1.x: PointCloud.Projection.size) API surface
edition: "Pro / Standard"
last_reviewed: 2026-06-01
diataxis: explanation
confidence: high
Keypoint-size-normalised reprojection error: the kps metric¶
Confidence: high. The official Metashape Pro 2.3 manual (page 90, Processing Parameters) states explicitly that the kps form "is the quantity that is minimized during bundle adjustment"; the dual-reporting (kps and pix) is documented there and corroborated by Metashape report excerpts in the forum. The
TiePoints.Projection.sizeAPI attribute is introspection-confirmed on Metashape 2.2 and documented as "size" in the Python API Reference.
Problem¶
Open the Metashape chunk-info dialog, or look at a generated PDF report's Survey Data / Cameras page, and the RMS reprojection error line shows two numbers separated by a parenthesis:
RMS reprojection error 0.130199 (0.363276 pix)
Max reprojection error 0.503363 (1.66923 pix)
Mean key point size 2.75397 pix
Two things to notice:
- The first number has no unit suffix.
- The second number is in pixels.
The first number is the keypoint-size-normalised
reprojection error — the same residual divided by the
keypoint scale. It's referred to as kps in some contexts
(short for "keypoint size") and is the quantity Metashape's
bundle adjustment actually minimises. The pixel form is
shown for convenience but is not what the optimiser fits to.
This article explains what the kps metric is, why Metashape reports both, and when you should reach for kps rather than the pixel form.
What is keypoint size?¶
Every tie-point projection in Metashape carries a size
attribute exposed via Metashape.TiePoints.Projection.size.
The official manual defines this:
"Key point size is the Sigma of the Gaussian blur at the pyramid level of scales at which the key point was found." — Metashape Pro User Manual 2.3, p. 90
In plain terms: feature detectors like SIFT search for
keypoints across a scale-space pyramid — the image is
progressively blurred (Gaussian blur with increasing σ) and
downsampled, and keypoints are picked at the level where they
are most distinctive. The σ at the level where the keypoint
was located is reported as proj.size. A keypoint detected at
a coarse pyramid level has a large size (say 8 px); one
detected at fine detail has a small size (say 1 px). The
keypoint's descriptor is computed over a patch proportional
to this size, so a 0.5-pixel residual on an 8-pixel keypoint
represents a much smaller fraction of the descriptor extent
than a 0.5-pixel residual on a 1-pixel keypoint.
Metashape uses the keypoint size to weight the bundle adjustment's projection observations. The Reference pane's Tie point accuracy parameter (under Settings) corresponds to the normalised accuracy — the accuracy of a tie-point projection at scale 1. Tie points detected at other scales inherit accuracy proportional to their scale, which is what makes the bundle adjustment correctly weight fine-scale and coarse-scale features against each other.
The chunk-wide mean key point size in the report excerpt
above (2.75 px) is the average of proj.size across all
projections that contributed to the bundle.
Defining the kps error¶
For a single projection, the kps error is the pixel error normalised by the projection's keypoint size:
Where error_pix is the standard 2D residual computed via
Camera.error (the Brown-distortion-aware primitive — see
the Caveats below for why this differs from a naive
camera.project minus proj.coord):
For a chunk-wide RMS, sum the squared kps errors across all projections of all valid tie points, divide by the projection count, and take the square root — the same aggregation pattern as the pixel-form RMS, just computed on the kps values:
Demo verified: ✗ — pending Tier 3 reproduction on a real Metashape install.
import math
import Metashape
chunk = Metashape.app.document.chunk
tps = chunk.tie_points
# track_id → 3D coord lookup, valid points only
coord_by_track = {p.track_id: p.coord for p in tps.points if p.valid}
err_pix_sumsq = 0.0
err_kps_sumsq = 0.0
n_pix = 0 # projections with a valid 3D point
n_kps = 0 # subset of n_pix with proj.size > 0
for camera in chunk.cameras:
if not camera.transform:
continue
for proj in tps.projections[camera]:
coord = coord_by_track.get(proj.track_id)
if coord is None:
continue
residual = camera.error(coord, proj.coord)
err_pix = residual.norm()
err_pix_sumsq += err_pix * err_pix
n_pix += 1
if proj.size > 0:
err_kps = err_pix / proj.size
err_kps_sumsq += err_kps * err_kps
n_kps += 1
if n_pix > 0:
rms_pix = math.sqrt(err_pix_sumsq / n_pix)
rms_kps = math.sqrt(err_kps_sumsq / n_kps) if n_kps > 0 else 0.0
print(f"RMS reprojection error: {rms_kps:.4f} ({rms_pix:.4f} pix)")
The output should match the chunk-info dialog's first two
numbers within rounding. The two counters (n_pix and
n_kps) are kept separate because legacy / imported tie
points can carry proj.size == 0; including them in the
pixel sum but excluding them from the kps sum keeps each RMS
on its proper denominator.
Why Metashape reports both¶
The kps form is what the bundle adjustment actually minimises. The official Metashape Pro 2.3 manual states this explicitly:
"On the processing parameters page of the report (as well as in chunk information dialog) two reprojection errors are provided: the reprojection error in the units of key point scale (this is the quantity that is minimized during bundle adjustment), and the reprojection error in pixels (for convenience)." — Metashape Pro User Manual 2.3 (and Standard edition), p. 90, Processing Parameters
The pixel form is reported alongside as a convenience for human readers who think in pixels. It's not a separately computed quantity — the same per-projection residual is just expressed in the two units.
The two metrics therefore answer different questions:
| Metric | Question | Comparable across... |
|---|---|---|
error_pix |
How many pixels off is the bundle, in this image's coordinate system? | Same camera; same image resolution. |
error_kps |
How well-localised is each keypoint within its detection scale? | Different cameras, different resolutions, different focal lengths — anything that changes the ratio of pixel size to scene-size. |
Concretely, two scenarios produce the same error_pix but
different error_kps:
- Scenario 1 — a 60 MP camera, keypoint size 1 px, residual 0.5 px → kps error = 0.5. The bundle reproduces a fine-detail feature to half its descriptor extent.
- Scenario 2 — a 20 MP camera, keypoint size 4 px, residual 0.5 px → kps error = 0.125. The bundle reproduces a coarser feature to one-eighth of its descriptor extent.
Both have the same 0.5-pixel residual, but the second is intrinsically a tighter fit because the bundle agrees to within a much smaller fraction of the feature's spatial extent. The kps metric captures this: 0.125 < 0.5.
Practical interpretation¶
For a healthy aligned project:
- kps error ≤ ~1.0 indicates the bundle has reproduced most keypoints within roughly one keypoint-size unit. This is the regime where reprojection-error filtering can meaningfully improve the cloud.
- kps error > 1 indicates many projections lie further from their reprojected 3D positions than the keypoint's descriptor patch — a signal that the bundle is struggling even after distortion correction.
The pixel-form thresholds in Reprojection error analysis ("≤ 1 px healthy, > 2 px problematic") translate to kps thresholds via the chunk's mean keypoint size. For the Metashape 1.5.3 report excerpted above (mean keypoint size 2.75 px, RMS 0.36 px), the kps RMS of 0.13 fits comfortably in the "healthy" range. A project with mean keypoint size 1 px would need much tighter pixel residuals to hit the same kps score.
Per-camera and per-sensor kps¶
The kps metric is most useful per-sensor or per-camera, not just chunk-wide:
- Per-camera kps highlights cameras whose projections systematically diverge — masking, removal, or separate calibration-group candidates.
- Per-sensor kps is invariant to the camera count per sensor. A chunk with 4 sensors of 50 cameras each, where one sensor has kps RMS 1.5 and the others 0.3, has a mis-calibrated or mis-mounted sensor; the sensor-RMS makes this immediately obvious where the chunk-wide RMS would bury it.
The aggregation pattern for per-sensor or per-camera kps is
the same: maintain errors_sumsq_kps, errors_sumsq_pix, and
num_projections accumulators per sensor / camera, then take
the square root of sumsq / count at the end.
For a working pattern that does both the per-sensor and per-camera aggregation in a single pass, see Reprojection error analysis.
Aggregation choice: per-projection vs per-point¶
A subtle issue when computing RMS: weight every projection equally, not every point. Metashape's chunk-info value uses projection-weighting, which means a tie point seen in 8 cameras contributes 8 squared errors to the sum and 8 to the count; a tie point seen in 2 cameras contributes 2.
The same convention applies to both kps and pix forms.
Switching to point-weighting (one entry per tie point, averaged
across its projections) gives a different, smaller number that
won't match the GUI.
Caveats¶
proj.size > 0is a necessary guard. Some legacy formats or imported tie points havesize = 0and would produce a divide-by-zero. The recipe above guards explicitly.- Projections without valid 3D points are silently skipped.
A
coord_by_tracklookup that returnsNone(the track triangulated to no valid point, or the point was filtered out as invalid) means the kps contribution is undefined for that projection. - Cross-version naming. In Metashape 1.x the projection is
reached via
chunk.point_cloud.projections[camera]; in 2.x it'schunk.tie_points.projections[camera]. TheProjection.sizeattribute name is the same in both. Camera.error(coord, proj.coord)is the right primitive. It applies the Brown-distortion correction;camera.project(coord) - proj.coordskips that step and produces a slightly different number that won't match the GUI. See Reprojection error analysis.- Mean keypoint size depends on the matching pipeline. Increasing image quality, changing pre-selection mode, or switching between Generic and Reference Preselection changes which keypoints survive matching, and therefore the mean keypoint size. Compare kps values across re-runs of the same parameters; comparisons across pipelines are apples-to-oranges.
- The kps metric is dimensionless, despite intuitions to the contrary. It's a ratio of two pixel-quantities. The PDF report displays it without a unit on purpose — the "0.130199" in the excerpt is a pure number.
See also¶
- Reproducing chunk-info statistics in Python — the broader chunk-info reproduction recipe; this article's kps focus complements its pixel-form RMS computation.
- Reprojection error analysis: per-camera and per-tie-point — pixel-space residual recipes; pair with this article for full per-camera kps + pix monitoring.
- Tie-point multiplicity: track length, distribution, and what it tells you — the other novel chunk-info statistic; complements kps for comprehensive QA.
- DSM ridge-line artefacts: alignment-quality diagnosis — symptom-driven entry into reprojection-error analysis.
References¶
- Metashape Pro User Manual 2.3 (and Standard edition),
p. 90, General workflow → Processing Parameters. Two
canonical statements:
- "Key point size is the Sigma of the Gaussian blur at the pyramid level of scales at which the key point was found."
- "the reprojection error in the units of key point scale (this is the quantity that is minimized during bundle adjustment), and the reprojection error in pixels (for convenience)."
- Metashape Python API Reference (2.3.1):
TiePoints.Projection.size,TiePoints.Projection.coord,TiePoints.Projection.track_id,Camera.error,Camera.transform,Chunk.tie_points. - Forum thread, Average Tie point multiplicity parameter — community forum users and Pasumansky, 2019-07-15, Metashape 1.5. Quotes the chunk-info dialog format with both kps and pix forms of RMS reprojection error, plus the Mean key point size line that anchors the kps interpretation.
- Forum thread, Reproduce chunk info reprojection error — Agisoft support, 2019-11-22, Metashape 1.5. The canonical pixel-form RMS recipe, which this article extends to the kps form.
- Forum thread, Point cloud gradual selection threshold — a community forum user and Agisoft support, 2021-05-19, Metashape 1.7. The community user states empirically that the Reprojection Error gradual-selection criterion uses the kps form (pixel error divided by keypoint size); the reply points at the manual's description without contradicting this.