Skip to main content
Version: 3.4.20 (unreleased)

SfM: Quality Report, Run Log and Troubleshooting

Requires the SfM licence feature

The photogrammetry workflow appears only when your licence includes the SFM feature. See Why Is This Greyed Out?.

When a reconstruction is not what you expected, start with the troubleshooting table, then read the run log to see which stage lost the data. Running the reconstruction is in the SfM user guide.

Troubleshooting​

SymptomLikely cause / fix
HEIC photos not added; the log says Windows cannot decode themInstall HEIF Image Extensions and HEVC Video Extensions from the Microsoft Store, then Add Photos… again — see iPhone (HEIC) photos. If only some HEIC photos fail, the log names the first one and the reason.
Few photos register (5/20 views)Too little overlap, too few features, or matching too strict. Raise Max features and/or Alignment image scale; lower Lowe ratio test slightly; only lower Min geometric inliers as a last resort. Check the photos aren't blurry.
Dense cloud nearly empty / very sparseCheck the per-view depth diagnostic first — if it reports RANGE-LIMITED or TEXTURE-LIMITED, the depth was never measured and relaxing the gates only adds noise. Otherwise read the fusion funnel and relax the stage that cuts most: lower confidence cutoff, loosen depth tolerance, or lower consistent views.
Dense cloud has gaps where the sparse cloud has pointsNormal, and explained here — dense matching needs three views and a whole patch to correlate, sparse needs two views and one feature. Use the per-reference yield line to tell a localised hole from uniform thinning, and the confidence profile to see whether lowering the cutoff would actually recover anything.
A few specific views contribute no dense pointsRead their (p/e) partner counts in the per-reference yield line. p0/e0 or p1/e0 is a coverage gap (add photos from that angle); p8/e0 means overlapping views were found but disagree on the depth, which points at a bad camera pose rather than the imagery — re-check that stretch of the flight path in the sparse solution.
seeded from a 50 mm ASSUMPTION warningThose photographs carry no EXIF FocalLengthIn35mmFilm, so the solve started from a guess about 2.5× too long for typical drone or phone imagery. See where the starting focal length comes from; attach a camera calibration if registration is poor.
Dense cloud is noisyTighten the same three: raise confidence cutoff, raise consistent views, tighten depth tolerance.
Points look laid out on a regular gridThe Dense MVS fusion voxel is much coarser than a ground sample, so each point is the mean of many observations and that mean lands near its cell centre. Set the voxel to 0 for the automatic size. Divide voxels by consistency>=2 in the fusion funnel: a handful of observations per point is healthy, hundreds is not.
Points project away from the camera below the outcropDepth quantisation on a wide depth range, not a matching failure. Check the bin width ... near / ... far figures in the per-view depth diagnostic and raise Dense MVS depth hypotheses — see that setting for the resolution table.
Small floating patches of noise below the modelRemoved by default by the component filter; raise Dense MVS min component size if some survive. If a genuinely separate structure disappears instead, lower it or set 0.
Blue/white halo around the outcropLeave the Dense MVS sky filter on and re-run Dense MVS. Check the log for SkyWater semantic masks enabled and a non-zero sky-masked count. If VRGS reports that the model is unavailable, verify that the installed VRGS_ml folder contains skywater_segformer_b2_fp16.onnx and skywater_segformer_b2_fp32.onnx; the colour/confidence fallback is less reliable around white cloud and pale sky.
Sky filter is slow on the first runWithout compatible CUDA, VRGS deliberately falls back to the FP32 CPU model. Let the first run finish: masks are cached under <workspace>/sky_masks/, so unchanged photographs are substantially cheaper on later dense runs.
Sky filter removes part of the subjectThe semantic filter removes only border-connected sky, but an object touching the image edge can still be misclassified. Turn the filter off for that workflow and compare the result; avoid lowering dense confidence or consistency thresholds, because those do not correct a segmentation error.
GPS-tagged run looks worse than expectedCheck the EXIF GPS is valid; raise GPS sigma XY/Z (trust GPS less), or turn Use GPS prior off to reconstruct in a purely visual frame.
CASMVSNET backend does nothingIt needs casmvsnet.onnx in the project MODELS folder and a CUDA GPU; otherwise use PLANE_SWEEP.
"No mesh to texture"Run Create Mesh on the workflow first — texturing needs a <name> mesh.
Texture looks coarse / blurryColour the mesh by Texture resolution 0-1 and check the log's GSD line first. If most triangles are source-limited the photographs are the ceiling and more pages will not help. If texture-limited, use more pages or a larger Page size — or accept the recommended budget, which sizes this for you. Also check for a "density coarsened" note; you may have hit the 8-page safety cap.
Mesh has holesPoisson Trim factor too aggressive — raise it or set 0 for a watertight surface; or you used Greedy, which leaves gaps in sparse areas (switch to Poisson).
Small loose pieces float beside a Poisson meshRaise Smallest piece (25 → 50–100), or delete them with Progressive Component Select. If an isolated patch of real ground went missing, lower it or set 0.
Patches show flat colour, not photo detailThose triangles were seen by no photograph (occluded or outside every image), so they fall back to per-vertex colour. Add photos covering that area or re-shoot it.
Faint seams across the textureEvery texel is blended from up to three photographs weighted by how well each sees that point, so exposure seams should dissolve. If they persist, lower Texture blend sharpness (4 → 1) to spread the blend wider.
Smeared or ghosted bands across the textureA lens-distortion mismatch, not a texturing fault. Check the bake's distortion self-check line — if it says the other setting agrees better, change Texture apply lens distortion and re-bake. The lasting fix is to re-run the reconstruction so the camera model is solved correctly for a firmware-corrected camera.
Flat single-colour triangles among good textureCheck the occlusion outcome line. Triangles "framed by NO photo at all" are a coverage gap — that part of the outcrop was never shot from a usable angle.
Texture bake sits a long time in UV unwrapNormal on a large mesh — it is the slow stage. Check the log for the chunk split (N unwrap chunk(s)); the bar advances as chunks finish. Cancel with the ✕ on the progress bar if you would rather decimate the mesh first.
Log warns about texels per triangleThe mesh is much denser than the atlas can resolve. Tick Bake onto a decimated copy of in the bake dialog, decimate the mesh before texturing, or raise the page size or page count.

Quality report​

Right-click the workflow → Results → Show Quality Report. It goes to the messages panel and to quality_report.txt in the workflow's workspace folder, so it can be handed over with a deliverable.

It answers, in one place:

  • Registration — how many photos registered, and which ones did not.
  • Reprojection error — RMS plus median, 90th and 99th percentiles, taken over every observation of every point: the same residuals bundle adjustment minimised, so the figure agrees with the solver's own. (Releases before 3.4.20 took them over each point's average, which read smaller and hid the tail.) If the 99th exceeds 5× the median the report says so: a handful of outliers is dominating the RMS, the bulk of the model is better than that number suggests, and the fix is to find the outliers rather than to distrust the whole thing. Each photograph's own reprojection figure, in the photo browser and the worst-photographs list, is the mean of that photograph's own residuals, so a badly posed camera no longer borrows the good residuals of the cameras it shares points with.
  • Georeferencing — what placed the model (GCPs, GPS, or nothing) and how well it fitted.
  • Ground control accuracy — per-point dX/dY/dZ and 3D error, with control and check points RMS'd separately. A point that was never measured is reported as such, not as a zero error.
  • Scale bars — expected vs. actual, and whether they were applied or are acting as a check.
  • Worst photographs — the ten with the highest reprojection error, which is usually where a bad solve is hiding.
  • Run timeline — how long each stage of the last run took and the memory it reached, which is where the run plan's time and memory figures come from.

Reading the run log​

Ask Athos to read it for you

The Athos AI assistant can interpret all of this for you. Right-click the SfM workflow in the project tree and choose Ask Athos about this Model, or ask something like "why does my dense cloud have holes?" in the chat. Athos reads the same settings, run statistics, and per-view diagnostics described below and answers with your actual numbers — including which photos failed, whether gaps are a coverage or a pose problem, and which parameters to change. It can also apply a change or start a re-run for you, always after showing you what it will do.

Two summary lines tell you most of what you need to tune a run.

Sparse summary​

SFM done: 20/21 views, 22196 points (reproj px: med=0.34, p90=0.81, p99=2.10, rms=0.55)
  • 20/21 views — registered vs. total photos. If many photos fail to register, the cause is usually too little overlap, too few features, or too strict matching thresholds.
  • 22196 points — size of the sparse cloud.
  • reproj px — per-point reprojection error percentiles. A sub-pixel median is healthy. A small median with a large p99 means a few outliers; a large median everywhere means a weak solve.

Dense fusion funnel​

Fusion: 5836800 -> 4443855 depth>0 -> 3841509 conf>=0.75 -> 2241200 consistency>=2 -> 12844 conflict-cut -> 31840 sky-masked -> 706202 voxels -> 698061 after SOR -> 697620 after component filter(min=200 pts: dropped 28 islands / 441 pts)

Each arrow shows how many pixels/points survive a stage, so you can see where points are lost and which knob to turn:

  • big drop at conf>= → lower Dense MVS confidence cutoff;
  • big drop at consistency>= → loosen Dense MVS depth tolerance or lower Dense MVS consistent views;
  • conflict-cut counts consistency survivors that were vetoed because more neighbouring views measured a clearly different surface along the same ray than agreed with the point — the signature of a correlated mismatch buried below (or floating in front of) the real surface. A very large number here means the per-view depth maps disagree badly: check overlap and texture before loosening anything;
  • with the sky filter on, an extra sky-masked term shows how many semantic sky depth pixels were removed (or colour/confidence fallback pixels if the model was unavailable);
  • the final component filter term reports the isolated islands removed — see Dense MVS min component size.
Tune from the funnel, not by guesswork

Run once with defaults, read the funnel, then change the one stage that is cutting too much (or too little). Re-run and compare.

Confidence profile​

Fusion confidence profile over 67332814 px with depth (cutoff 0.75): ... | 48.3%
below cutoff, of which 12.7% of all depth px would be admitted by relaxing the
cutoff to 0.6

The funnel tells you the confidence gate cut half your pixels; this tells you whether that was worth doing. The histogram is collected before the gate, so the buckets below the cutoff are populated, and the closing figure answers the only question that matters in practice: how much would come back if you lowered the cutoff.

Mass piled just under the cutoff means real surface is being rejected on close calls, and lowering Dense MVS confidence cutoff will recover geometry. Mass piled far below it is noise, and lowering the cutoff will only admit rubbish.

Per-reference yield​

Fusion per-ref yield: median 119255 pts/ref, range 0-280048; 44 of 252 ref(s)
yielded <=10% of median (partners p=nominal/e=effective) (weakest views:
115=0(p8/e0) 144=0(p6/e1) 146=0(p7/e0) ...)

This separates a hole from thinning. If every view sits near the median, the cloud is uniformly sparse and the funnel tells you which gate to relax. If a handful of views yielded almost nothing, the loss is concentrated in whatever those cameras were looking at — and since the numbers are view IDs, you can find that stretch of the flight path and check its overlap, lighting and angle.

Each weak view carries (p<nominal>/e<effective>), which splits a near-zero yield into its two possible causes:

  • p (nominal) — how many overlapping views the matcher assigned to this reference.
  • e (effective) — how many of those actually confirmed its depth at one or more pixels.

p1/e0 or p0/e0 is a coverage gap — nothing overlaps that viewpoint, and the only fix is more photographs from that angle. p8/e0 is a pose fault — eight views should see that surface and none agree, so the camera (or its neighbours) was placed wrong in the reconstruction, and no amount of extra imagery or dense-setting tuning will fill it until the pose is corrected. This matters because a mis-placed camera can still have a low reprojection error, so the pose looks fine by the usual measure; the effective-partner count is the check that catches it.

A view with no depth map at all adds nothing to the cloud as a reference. A warning in the messages panel names each such view and its photo file, under one of two reasons: no neighbour passed selection (too little co-visibility, parallax or overlap with any other registered view), or neighbours were found but the sweep returned no depth map, when the debug log has that view's reason.

Per-view depth diagnostic​

One line per reference view describes how the plane sweep behaved:

MVS depth diag view 37: bracket 34.2-106.8 m over 64 bins (bin width 0.371 m
near / 3.52 m far); winners 41% edge-far, 2.1% edge-near, 3.4% flat-cost, 0.6%
non-parabolic, 52.9% refined (18.9% by <0.05 bin) => 66.0% on a bin centre
<-- RANGE-LIMITED: surface outside the depth bracket; more bins will NOT help

The bracket is the depth range searched for that view, derived from the sparse points it can see. Depth hypotheses are spaced evenly in inverse depth, so the metric step grows with the square of distance — hence a bin 0.37 m thick near the camera and 3.5 m thick at the far end of the same view. When the far figure exceeds the Dense MVS depth tolerance applied at that range, distant surface in that view cannot pass the cross-view consistency check however well it was photographed.

The percentages say where each best match landed, and the trailing verdict names the dominant cause:

  • RANGE-LIMITED — most matches sat against a wall of the bracket, so the true surface lies outside the range searched. Usually the view is dominated by sky or distant background, or the sparse cloud within it is too thin to bracket it properly. Better sparse coverage helps; the dense settings cannot.
  • TEXTURE-LIMITED — the correlation curve is flat, so no depth is distinguishable from any other. The surface carries no usable texture at the scale the matcher works at. Nothing in the settings panel fixes this; it needs closer or better-lit photographs.
  • OVER-QUANTISED — the matches landed cleanly inside the volume, but the far bin is coarser than the depth tolerance that has to confirm it, so distant surface in this view cannot be verified by any other view. This is the one a finer depth search improves, and it is invisible to the other counters — a view can refine every winner cleanly and still emit nothing.
  • TERRACED — depths are quantised onto discrete shells. Also answered by a finer depth search.
Two of these are not settings problems

Read this line before spending a run turning knobs. If your views report RANGE-LIMITED or TEXTURE-LIMITED, lowering the confidence cutoff or loosening the depth tolerance will add noise without filling the gaps, because the depth was never measured in the first place. OVER-QUANTISED and TERRACED are the opposite — the depth was measured but sampled too coarsely, and a finer sweep (handled internally) recovers it.

Why the dense cloud has gaps where the sparse cloud has points​

This is expected, not a fault — the two clouds are not built to comparable standards:

  • a sparse point needs one distinctive feature matched in two photographs, at full image resolution;
  • a dense point needs an entire correlation patch to match in three or more views, all agreeing on depth within the tolerance, at the reduced resolution the dense stage works at.

So the sparse cloud thins gracefully as conditions worsen while the dense cloud tends toward all-or-nothing: full density where matching succeeds, empty where it fails. Shadowed recesses, smooth or uniform rock, and surfaces seen only at a grazing angle are the usual empty areas. The last one catches people out — a well-textured face photographed obliquely correlates just as badly as a featureless one photographed straight on, because the correlation patch is foreshortened differently in each view.

The dense stage also runs at a reduced image resolution, which puts a floor under point spacing no matter how good the photographs are. If the dense cloud is uniformly coarser than you expected rather than patchy, that floor is what you are seeing, and no setting will move it.