CamMatch™ logo

Engineering Dynamics Company

CamMatch™

Camera Matching & Visualization for Blender

CamMatch™ — How-To Guide

A practical, step-by-step guide to solving a camera with CamMatch. It follows the add-on's panels in the order you actually use them and reflects the current UI.

CamMatch is built for fixed-focal-length footage — a camera whose lens does not zoom or change focus during the shot. You calibrate the lens once and that single calibration governs every solved frame. Zoom/variable-lens footage is supported as an advanced exception (see Lens type), but the whole workflow below assumes a fixed lens.

New to the add-on? Read Core concepts first — the rest of the guide assumes you know the difference between intrinsics and pose, and between a track and a 3D point.


Table of contents

  1. Core concepts
  2. The panels at a glance
  3. The full workflow
  4. Track list legend (icons & colors)
  5. Fixed lens vs variable lens — which to use
  6. Tips for reliable solves
  7. Troubleshooting
  8. Methods and references

Core concepts

CamMatch answers one question: given 2D image points that you know the real 3D location of, where was the camera (and what lens did it have)? That's the PnP ("Perspective-n-Point") problem.

You supply two things and CamMatch matches them:

You provide In Blender this is Example
2D points — where a feature appears in the footagea track (marker) in the Movie Clip Editorthe corner of a stop sign, tracked frame by frame
3D points — where that feature really is in the worldan object (usually an Empty) placed at the surveyed coordinatethe same stop-sign corner at its measured survey point

A link ties one track to one object. With enough good links on a frame, CamMatch can solve that frame.

Two things get solved, and it helps to keep them separate:

CamMatch's intended workflow is fixed-focal-length: the lens is assumed not to change during the shot, so you calibrate the lens once and then solve the camera's pose on every frame you need — the one calibration governs the entire shot. This keeps the lens well-constrained and every frame mutually consistent. Zoom/focus-pull footage (a variable lens) is the exception; see Lens type.


The panels at a glance

CamMatch is split into collapsible panels in the Clip Editor sidebar. Quick Actions sits at the top, then the panels below are gathered into the stages the work goes through — Solve the Camera, Check the Solution, Help & Reset — with Track & Links and Create 3D Tracker beside them, since a heading over a single panel is a click that buys nothing:

Panel What it's for
Quick Actions (top, always open)Camera selection, the big Calibrate / Solve buttons, links refresh, diagnostics, report export, background transparency, render overscan. Your day-to-day controls.
Status & ReprojectionA live read-out of the last solve/calibration: message, mean/worst error, inlier count, and which frame it came from. The headline error covers the RANSAC inliers only — see section 7.
CalibrationIntrinsics: which lens parameters to solve, distortion model, single-frame Calibrate Camera, and Multi-Frame Calibration.
Solve CameraPose: PnP method, acceptance gates, Solve Camera Pose, pose uncertainty settings, and Solve Multi-Frame.
Track & LinksThe track↔object link table, auto-linking, filtering, error thresholds, and per-track cleanup.
Create 3D TrackerMaking a 3D point from a ray, and asking how well it is known — including the distance between two points. Making a point and measuring it are the same piece of work, and the measurement needs a point, so they sit together in that order.
Camera ParametersThe raw tracking-camera parameters (focal, sensor, optical center, distortion) for inspection/manual edits. Under Solve the Camera, because Calibration writes them and Solve Camera reads them.
DiagnosticsOpen the generated heatmap / calibration / solve overlay images. Verbose logging toggle.
DocumentationOpen User Guide and Download Sample Project (the CalibrationCity scene, fetched once and cached). Both work with no clip loaded — the sample is a clip.
ResetReset Session — only if things get into a bad state. Distortion Match / Undistort Movie rebuild a compositor group you deleted, and Compositor Follows View Layer sets whether the groups follow the view layer you are looking at.

The 3D Viewport > Sidebar (N) > CamMatch tab has a small Quick Point Creation tool for placing control-point Empties by clicking in the viewport.


The full workflow

1. Set up footage and 3D points

  1. Open the Movie Clip Editor and load your footage.
  2. Bring your known 3D coordinates into the scene as objects (Empties are ideal). You can:
  3. Accuracy of these 3D points directly determines solve accuracy. Use real measurements wherever you can.

2. Track features in the clip

Use Blender's normal tracking tools to place a track on each image feature that corresponds to one of your 3D points. Each track needs a marker on every frame you intend to solve. Give tracks sensible names — matching names make linking automatic (next step).

Open Track & Links.

  1. Click the Refresh button (⟳, top of the side button column) to populate the table from the clip.
  2. Link tracks to objects using whichever is convenient:
  3. Each row shows a checkbox (usage), the reprojection Err % with a colored status dot, the Track name, and the linked Object. See the legend for what the icons mean.

Handy filters (under Auto-Link, Filter & Sort):

Keeping a track and what it made together. A 2D track and the 3D object it produced are two halves of one thing, and these do both halves at once:

4. Calibrate the lens (intrinsics)

Skip this only if you already trust the lens values. Open Calibration.

  1. Choose which parameters to solve (toggle buttons):
  2. Pick a distortion model and enable the coefficients to solve (K1/K2/K3, plus K4 and P1/P2 for Brown-Conrady). Polynomial is exactly Brown-Conrady with K4, P1 and P2 at zero. K4 is Blender's own r⁸ radial term, the one Blender's undistort and Movie Distortion node apply, and CamMatch solves it as such. It earns its place on a wide lens whose distortion keeps growing toward the corners; on one field calibration it cut the error on points left out of the fit from 9.3 px to 4.2 px. P1/P2 (tangential) rarely help a single view and can make the lens worse on points it was not fitted to. Every extra coefficient lowers the RMS on the points it was fitted to, so judge one by the calibration uncertainty and by frames it was not calibrated on, not by the RMS alone.
  3. Calibrate the fixed lens. Multi-Frame Calibration is the recommended path:

The exclusion stops there. The track itself stays in use, so every later solve gathers it again — with solvePnPRansac it may be thrown out frame by frame, with plain solvePnP it is used in full. The panel says so in red under the button, Robust excluded N track(s) still used by solves, and Set Excluded Tracks to Not Used takes them out of every solve, calibration and uncertainty in one click, the same as the link's own Not Used switch. From then on, and whatever you calibrate next, the panel shows Set Not Used after a Robust calibration: … with Use Them Again, which puts them back in use so you can recalibrate with them; so does Undo, and so does the link list's own Use This Track At All switch, one track at a time. Nothing does this automatically: Robust is a probe, and a probe that changed the solve by itself would change results you did not ask to change.

Robust calibration is a diagnostic, not a default. If it succeeds where a normal calibrate failed, that is telling you a link is wrong — find it and fix it rather than leaving the robust fit in place, because the discarded points are still wrong for every solve that follows.

  1. The panel shows the calibration status — e.g. Calibrated (multi-frame) @ 14, 28, 40-56 · last solve keyframed @ Y (or (single-frame) @ frame X) — and the Status & Reprojection box reports the RMS error. Diagnostic images and the compositor undistort nodes are created automatically.

Right after a calibration, the track colours and errors are the calibration's own fit: the lens together with the camera pose the calibration solved for itself. The scene camera has not moved. Solve the camera again (any frame solved before is now stale, see Recalibrating) before judging the overlay in the 3D view.

The second half of that line is about your poses, not the lens: it is the last frame a camera solve was keyframed at. On a range solve that is simply the end of the range and says nothing about the calibration. It only concerns the lens if Key Intrinsics is on, and then the panel says so in red, because the lens is animated and what you see between solved frames is interpolated.

  1. Calibration uncertainty is measured automatically as part of every calibration, and shown under the Calibrate buttons — e.g. Calibration uncertainty: 0.711% (1σ) · ~1.29% of range (95%).

It answers "how well is the focal length itself pinned?" by re-running the calibration on perturbed points and measuring how far the focal moves. The second figure translates it into something you can act on: camera position error from focal uncertainty runs about 1.82 × range × (σ_f/f) at the 95th percentile, so 0.711% of focal is about 1.29% of range — at 40 m from your targets, roughly half a metre of camera position.

The figure is carried into the pose uncertainty automatically. If it is large, the fix is almost always more calibration frames rather than more points on one frame: a single view cannot separate focal length from camera distance (move back and zoom in, and the image barely changes), and only extra views break that. On one real file a nine-frame calibration took the figure from 2.540% to 0.711% and collapsed k3 from −0.225 to 0.0007 — the distortion had been absorbing focal error.

Watch the k1/k2/k3 pattern, not the values. Large alternating signs mean the distortion model is trading against the focal length. Values that decay mean it is behaving.

  1. When you're happy, enable Lock Intrinsics to prevent accidental recalibration or reset. For a fixed lens this is the norm: calibrate once, then lock. (Locking only guards the Calibrate/Reset buttons — it never changes values you've already solved.)

Reset Intrinsics returns the lens to a sensible default (focal length scaled from the sensor width), available when intrinsics aren't locked.

5. Solve the camera pose

Open Solve Camera (or use the Solve button in Quick Actions).

  1. Confirm the target camera in Quick Actions (the dropdown next to Auto-Create Camera). Leave Auto-Create Camera on to let CamMatch make one if needed. The button beside it selects the camera in the scene.
  2. Pick the PnP function and method, or click Best Method to have CamMatch compare the available algorithms and automatically switch to the one with the lowest reprojection error.
  3. Set the acceptance gates (these apply to both single and multi-frame solves):
  4. Click Solve Camera Pose. The camera jumps into place, per-track errors populate the list, and diagnostics regenerate. The camera stays selected.

Solved frames, under the button, lists every frame that has a solve and how many there are — the same list the report's Solve Quality section opens with. The arrows at its right end jump the timeline to the previous or next solved frame from wherever you stand, and the triangle at its left unfolds the list into a button per frame; the one you are on shows pressed. The Calibration panel's status line is the matching list for the lens: which frames it was calibrated from.

6. Solve a moving camera (multi-frame)

This solves the camera's pose on many frames — the camera moves through space, but the lens stays fixed (calibrated once in step 4). In Solve Camera, enable Solve Multi-Frame.

  1. Choose Use Scene Range, or turn it off and type specific frames/ranges in Frames (e.g. 14, 28, 40-56, 89).

Use Solved Frames, under that field, fills it with every frame that already has a camera solve — handy after a recalibration, or when re-solving with different settings. It only fills the list; you still press Solve. (A pose keyframe is written only by a solve, so the camera's own animation is the record of which frames were solved.)

  1. Options:
  2. Click Solve Scene Range / Solve Multi-Frame. Each frame is solved and keyframed using the acceptance gates above; the status line reports how many frames were accepted, skipped, rejected, or failed.

Every solved frame gets pose keyframes (and, if Key Intrinsics is on, lens keyframes too). Frames that fail the gates are left un-keyed so they don't pollute the result.

Removing a solve

Remove Solve @ N, under the Solved frames line, removes the solve on the current frame: its stored errors and pose uncertainty, and the camera's pose keyframes there (and its lens keyframes, if the solve keyed the lens). The camera then follows whatever keys remain — the neighbouring solves, or your own. That is the move when a range solve is right on every frame but one, and you would rather animate that one by hand than fight it.

If you have already animated over the solve, the key at that frame is yours. Open the operator's redo panel (bottom-left of the editor, or F9) and turn on Keep Keyframes: only the solve's records go, and the camera stays where you put it.

Remove All does the same for every solved frame, after a confirmation. The calibration is untouched either way. It is how you clear a solve out of a camera you are going to animate yourself.

Both are undoable. For the other case — the solve is fine but the markers on that frame have gone — the Status panel offers Drop Them, which forgets the records and leaves the keys.

If you delete the camera's keyframes by hand in the timeline instead, the solve is off the camera but its records remain, and the Solved frames line says so in red: N stored frame(s) have no camera keyframe. Forget Them, under it and in the Status panel, is the other half of that delete. A report made in the meantime prunes those frames itself.

When the camera or the lens has changed since the solve

Every solve records the pose it wrote, and every calibration records the lens values it left on the clip. From then on CamMatch compares.

A moved camera. If a solved frame's keys no longer hold the solved pose — you nudged the camera with auto-key on, or set a key by hand — the Solve panel says so under the Solved frames line: Camera moved since solving on N frame(s), with the distance and angle on the frame you are standing on, and the report marks those frames ⚠️ moved in the Per Solve table. The errors and the uncertainty for such a frame describe the solved pose, not the one the camera holds. Re-solve the frame, or Remove Solve with Keep Keyframes if the move was deliberate and the animation is now yours. An unkeyed nudge is not a move: Blender's keys snap it back at the next frame change.

An edited lens. If the focal length, principal point, distortion or sensor width on the clip's camera differ from what the calibration left, the Calibration panel says The lens has been edited since it was calibrated under the Calibrated @ line, with what changed, and the Solve panel and both reports repeat it. Every solve made since was made with the edited lens, while the calibration and its uncertainty describe the other one. Restore Calibrated Lens puts the calibrated values back without a recalibration; then re-solve. With Key Intrinsics on the lens varies between solved frames by design, so this check stays quiet.

Files solved or calibrated by earlier versions carry no recorded pose or lens, so nothing is compared for them until they are solved or calibrated again.

7. Review and clean up errors

After any solve, Status & Reprojection shows the mean/worst error and inlier count, and the Track & Links rows show each track's error and status dot.

The headline error covers inliers only. When a solve uses RANSAC, the mean/worst error in Status & Reprojection — and the |X|/|Y| means in the summary — are measured over the points the solve actually trusted. A single badly-placed marker would otherwise average its full residual into that figure and make a perfectly good consensus pose read as a failure.

Outliers are still fully visible, just not counted: the per-track rows keep their real error and their inlier flag (orange / OUT), and the message still reports RANSAC inliers: N/M along with the worst track. So the way to spot a bad link is the track list and the inlier count, not the headline number. Solves that don't use RANSAC mark every point an inlier.

Tools for finding and fixing bad correspondences (Track & Links > Auto-Link, Filter & Sort):

Automatic per-frame cleanup (in Solve Camera):

Per-track manual control lives in the list:

Selecting a track in the list also selects its linked 3D point in the viewport and outliner (and vice-versa when you move a track in the clip), so you can quickly see which control point is misbehaving. Turn on Show Error Points in 3D (Quick Actions) to visualize error-colored points in the viewport.

Where the points sit matters more than how many there are

A focal length is read from how image scale changes across the field, and there are two ways for that to be unreadable. Inside a small part of the frame the scale barely changes across it. And at a single distance a longer focal is almost exactly cancelled by moving the camera back, so the fit cannot separate the two. Either way the focal uncertainty runs to tens of percent, and that then becomes the whole of the camera position uncertainty; the tracking and survey terms are nothing beside it.

The status box measures both:

Calibration points cover 2.1% of the frame and span 17% of their mean range in depth Focal uncertainty dominates the solve

Depth is usually the lever you actually have. The image footprint is set by where the evidence is, but there is generally something nearer the camera that can be surveyed. On a real 14-point single-frame calibration, duplicating seven of the points nearer the camera took the depth spread from 17% to 107% with the hull unchanged at 2.1%, and the focal uncertainty from 5.08% to 0.67% — seven times better. Seven more points at the same depth were worth 1.2×.

Points span, in depth Focal uncertainty (1σ)
10% of their mean range8.0%
20%4.1%
30%2.0%
60%0.8%
100%0.5%

It flattens around 50–60%.

And across the frame, measured on the same kind of calibration holding the count and varying only the spread:

Points enclose Focal uncertainty (1σ)
1% of the frame19.2%
3%6.7%
6%3.6%
11%2.0%
29%1.0%
63%0.64%

Spreading the points you already have is worth far more than adding more in the same place — a factor of about 24 against the square root of the count. Fourteen points in a 2% patch calibrated to 18%; the same fourteen spread over the frame, to 0.8%.

It is measured as the area of the convex hull around the points, not their bounding box, because a diagonal line of points fills the bounding box and is degenerate: all on one line, there is nothing to pin the scale change against. Such a line scores 81% by bounding box, 0% by hull, and calibrates to 587%.

Note what "good" looks like in this figure: fourteen points scattered over the whole frame enclose about 35%, not 95%, because a handful of points does not reach the corners.

More frames is the other remedy, and often the easier one: a joint calibration over several views breaks the focal/distance ambiguity through parallax rather than through image coverage.

8. Recalibrating: stale frames

Recalibration changes the lens, so any frame you already solved against the old lens is now geometrically inconsistent.

Multi-frame calibration turns Key Intrinsics off on success, so the single calibration governs every solved frame.

9. Pose uncertainty

A solve returns one camera pose. It does not say how firmly the data pinned it down — and two solves with the same reprojection error can be pinned very differently, depending on how the points are spread.

CamMatch answers that by experiment. It takes your correspondences, jiggles them by an amount you declare, re-solves, and repeats a thousand times. The spread of the resulting poses is the answer: if a pixel of tracking noise moves the camera half an inch, the camera is known to about half an inch.

The two numbers you have to supply

They appear in Calibration, in Solve Camera and in 3D Tracker, because all three consume them. It is one pair, not three: they describe your tracker and your survey, not which step is running. Nothing runs until both are filled in, and neither has a default — blank is a real state, and the estimate says so rather than quietly assuming something.

Plus Samples, how many trials (default 1000); more is smoother, not more accurate, and the answer stops changing well before 1000.

Until both are filled in, every button that would run an estimate is greyed out, and hovering it says which figure it is waiting for.

Auto Monte Carlo on Solve

On by default: each solve measures that frame's pose uncertainty as part of solving, so the figure is always there without being asked for.

Switch it off to keep solving quickest. Once the lens is being re-fitted inside each trial (see below), the trials redo the entire calibration a thousand times, so the cost grows with the number of frames the calibration was run over. Those re-fits are drawn once per run, on every core the machine has, and shared by every frame of that run: a thousand of them over a nine-frame calibration take about 3 s on four cores, and each frame then costs about 0.2 s. A 100-frame range at a thousand trials is therefore around half a minute, where it was once a quarter of an hour.

With it off, solving only solves. The panel says so, and Estimate Pose Uncertainty measures the frames you actually want the figure for — or All Frames for every solved frame at once. The numbers are identical either way; only when they are computed changes.

The panel also shows how many frames the lens is re-fitted over, beside Lens re-fitted each trial, because that count is what sets the cost.

A stored estimate that is not this file's

A pose estimate is a function of the two noise figures, and each stored one carries the figures it was run at. The report compares them with the fields:

The calibration figure and every raycast point get the same comparison, in the panel and in the report.

Seeing what changed

Documentation → What's New opens the changelog in your browser. When you install a version you have not seen before, a line appears at the top of the CamMatch panel with a link to it and a button to dismiss it; it shows once.

While an estimate is running

Estimate Pose Uncertainty, All Frames, Estimate Point Uncertainty, Measure Distance Uncertainty and Measure Calibration Uncertainty run in the background of the interface: the viewport stays live, the progress readout on the cursor keeps moving, and Esc stops the run. Anything already measured stays measured; the frame walk puts you back on the frame you started from either way.

The multi-frame solve still holds the window while it works, and so does the calibration measurement when a calibration runs it for itself. If the solve is the slow one, that is Auto Monte Carlo — turn it off.

And Calibration, shown beside them but not typed.

If CamMatch calibrated this lens, it keeps the points the lens was fitted to, and the pose simulation re-fits the lens inside every trial from the same perturbed points. That matters because the focal uncertainty is not a separate error — it is caused by the 2D and 3D errors you declared. A trial where the points happen to spread outward produces both a longer focal and a pose further back, and the two compound. Measured against ground truth on six geometries, drawing the focal from its own distribution gave 0.46× to 1.25× of the truth — wrong in both directions by up to a factor of two, with nothing in the inputs to say which way. Re-fitting gave 0.96× to 1.03×. It costs about 0.7 seconds per thousand trials.

If the lens came from somewhere else — a chequerboard shot in the lab, a manufacturer figure — there is nothing to re-run, and the declared percentage is used instead. That is the correct model for that case: a calibration made from different data genuinely is independent of these control points.

If it reads Calibration assumed exact, the lens uncertainty was never measured and nothing in the figures below reflects it.

Why they are typed and not measured for you

The obvious place to get the 2D figure from is the solve's own residuals. It cannot come from there.

A residual is the gap between where a point appeared and where the fitted pose says it should appear. Everything that did not fit lands in that gap — your tracking, your survey error, and the lens model — and the pose has already absorbed a different share of each. One number cannot be taken apart into three. Use it as the tracking noise and then also declare a survey error, and the survey is counted twice.

Measured against ground truth — the same job redone 1500 times with fresh errors each time, on synthetic road geometry:

what the simulation was told absolute position distance
both figures declared honestly0.99×1.05×
2D derived from the residuals0.73×1.29×
derived, plus a declared survey error1.25×1.65×
declared tracking, survey left at zero0.22×0.39×

Only the first line is right. And note the last: calling the survey exact makes you four times too confident, which is the single worst thing this estimate can do.

The 2D figure is per coordinate, because each trial displaces x and y separately. The RMS in the Solve Quality report is a distance — two coordinates at once, about 1.41× larger — and it has the survey and lens errors in it besides. Do not copy one into the other.

How to get the 2D number

What none of these can see is whether you are centred on the right feature. They measure repeatability, not correctness — the same blind spot everything else here has.

Changing the settings afterwards

The estimate is only written when it is run, and a solve is what normally runs it. So changing the noise and regenerating a report moves nothing — the stored numbers are from the last solve.

Two buttons under the noise fields fix that without touching your solve:

Neither re-solves the camera: the pose, the lens and the links are read, not changed. The panel also lists, in red, any frames whose stored estimate was made under different settings, so a report cannot quietly mix two experiments in one table.

Reading the result

Why a dash and not a zero? Blender gives a property that was not in the .blend its declared default. For a measured output that makes "never recorded" look identical to "came out zero" — and a zero uncertainty is the most confident claim a report can make. Fields that cannot go negative carry a −1 marker. The signed ones (dX px / dY px) cannot, because −1.00 px is an ordinary residual, so those are judged by arithmetic instead: Err px is the hypotenuse of dX and dY, so a non-zero error with both at zero is impossible and can only be a record from before the split was kept. Re-solving or re-estimating fills the gaps in.

Both appear per solved frame in the exported reports. A report also carries a breakdown — What the 95th percentile is made of — with a column per source and an All sources column so the parts can be checked against the whole. Read position and rotation separately: they can rank differently, and on one real solve the calibration led position while the tracking led rotation on every frame.

When the lens was re-fitted (above), the rows read …, lens held and Both sources, with the lens held. The lens is then not a source that can be switched off — it is fitted from the same points, so there is no run in which the tracking moves and the lens does not. Those rows hold it at the calibrated value, which makes the gap between the last of them and the 95th percentile what the lens costs. On one real single-frame calibration that gap was 3.4 in against 31 in: the lens was the answer and nothing else in the table mattered. The report does not spell that out — the row labels say lens held and the gap is there to be read.

Why is P95 about three times the per-axis σ? Because it is a distance in three dimensions, not a one-dimensional interval. For a spherical cloud the 95th percentile of the distance from centre is 2.796 × the per-axis σ; real, stretched clouds run about 3.0–3.4. It is not "two sigma".

What it does and does not tell you

This is the most important paragraph in this section.

The result is sensitivity to the noise you declared. It answers: given that my tracking is good to about a pixel and my survey to about an inch, how well is the camera pinned down?

It does not measure whether those assumptions are true, and it cannot see an error that is not random:

Every one of those produces a confident, tight uncertainty around a wrong answer. A small σ means the data was consistent, not that it was right. Consistency is necessary and it is not sufficient — check the residuals, the link list, and the distortion diagnostics for the rest.

Garbage in, precise garbage out. The Monte Carlo will not tell you which.

10. Uncertainty of a reconstructed point

A point raycast from a track inherits everything the camera pose is unsure about, and adds something of its own: the pixel you picked it at is not known exactly either. Estimate Point Uncertainty, in the Create 3D Tracker panel, propagates both.

Trials at the top of that section sets how many times to run it. It is the same setting the pose estimate uses, shown here because this is the panel that prints the yield.

Rays. Set Create to Ray to draw the ray from a track without needing anything for it to hit. Ray Length sets how far it runs — leave it at 0 to follow the camera's clip end, as it always has. Ray Radius draws it as a tube rather than a hairline, which is what makes a ray findable in a busy scene; 0 is the hairline. Rays are placed in the camera's own collection, and carry the name of the track they came from so they are cleaned up with it.

Raycast the features into points first, then select one. The estimate needs a raycast point and not merely any Empty, because every trial re-solves the camera and shoots the ray again — so there has to be a ray, meaning the pixel it came from and the direction. A linked track's 3D point cannot be measured this way and does not need to be: it is an input to the solve, a coordinate you surveyed, and it does not move when the pose wobbles. To get the uncertainty of the distance between two tracked features, raycast both, select both, and use Measure Distance Uncertainty.

It runs the same experiment as the pose uncertainty — jiggle, re-solve, repeat — and then shoots the ray again through each trial's camera and records where it lands. What you get back is the cloud of places the point could be.

Select the raycast Empty, make sure you are on the frame it was raycast on, and press it. The camera is never moved: every trial's pose is arithmetic.

Pick uncertainty

Separate from the noise settings in Solve Camera, and deliberately so. Those describe how well the survey and the tracking pin the camera. This one describes how well you can say which pixel a feature is at — and a crisp corner and a blurred curb edge share a camera without being equally locatable.

Mode Use it when
NoneThe pixel is not in doubt, or you only want the camera's contribution
GaussianYou can centre on the feature but not exactly. Give the 1σ in pixels
Bounded"Somewhere in these few pixels." Give the maximum; it draws uniformly inside

Bounded is not a sigma. It claims a limit, and nothing is drawn outside it. Use it when that is what you mean, rather than inflating a Gaussian until it feels safe.

Reading the result — and the one trap

The panel and the report distinguish three things that are easy to conflate.

Per-axis σ — how far the cloud spreads along X, Y and Z separately.

Radial P50 / P68 / P95 / P99 — the distance from the nominal point, so these are radii, never ±. Radial displacement cannot be negative: "95% of trials within 3.5 in" describes a sphere of that radius, and writing it as ±3.5 in would read as a 7-inch interval. The reports say radius for exactly this reason.

Largest observed — the biggest displacement that turned up. Named for what it is. It is a property of how many samples you asked for and it grows if you ask for more, so it is not a confidence limit and must not be quoted as one.

Radial figures are always larger than the per-axis σ, for three reasons at once: they combine all three axes, they are measured from the nominal point rather than the cloud's centre, and P95 is about 2.8σ for a spherical cloud rather than 2σ.

When most of the trials are thrown away

The panel prints Samples: N of M. Below half, that row turns red and says what was discarded, because a low yield is the finding rather than a detail: the spread is then measured over the few trials that came through, which are a biased sample of the ones that started closest, so the figures understate the real uncertainty.

Which reason dominates tells you what to change:

Raising Trials does not fix either of the first two: ten times the trials draws ten times as many survivors from the same biased pool.

Which noise is actually driving it

The result lists the two noise figures it ran on:

PnP 2D noise: 2.70 px (1 sigma) PnP 3D noise: 0.2000 ft (1 sigma) — 1.4 px here

One is in pixels and the other in feet, so on their own they cannot be compared, and "is 0.2 ft of survey error a lot?" has no answer. It depends entirely on how far away the control points are: 0.2 ft on a point 40 ft away is a large angular error, and the same 0.2 ft at 400 ft is nothing.

— N px here is that conversion, measured for your scene rather than assumed. The control points are perturbed by the 3D noise and reprojected through the solved pose, and the figure is how far they move on the image. It is a per-coordinate σ, so it composes with the 2D noise the ordinary way:

2.7 px of tracking and 1.4 px of survey make √(2.7² + 1.4²) = 3.04 px — the survey error is adding about 13%, and the tracking is setting the result.

If instead it read 8 px here, the survey would be the thing to improve and better tracking would barely move the answer. The number tells you which.

The uncertainty has a shape, and the shape usually matters more

A point raycast onto a road from an oblique camera is not uncertain by the same amount in every direction. Along the line of sight, a small pose wobble swings the hit a long way downrange; across it, hardly at all. Ten to one is ordinary. The panel says so when it finds it:

This point is 18× less certain along one direction than across it.

When that appears, no single number is the answer. The radial P95 is dominated by a direction you are probably not measuring along, and the per-axis σ describes a box the cloud does not fill. The report gives the principal axes so the real shape is on the page.

Measuring along a direction

Tick Measurement Direction and give a world direction — or select the two points and press Direction From Two Selected, which fills it in from the line between them (the active object is the far end).

You then get a signed interval, which is the point of it:

Directional 95%: −0.42 / +1.86 in

Signed because it can be asymmetric, and often is. An interval of −0.42/+1.86 says the point is far more likely to be beyond where you placed it than short of it — which a ±1.14 would have thrown away.

No ± is given anywhere here. A half-width is a lossy restatement of a signed interval even where the two sides agree, and where they do not it is simply wrong — quote the two figures.

When the trials land in two places

A point near a depth edge — a kerb with a building behind it, the lip of a roof against the sky — is not simply uncertain. Most trials land on the near surface and a few land on the far one, tens of feet away, so the cloud is not one lump but two.

A percentile of that is not a summary of anything. The 95% interval sits on the boundary of the small far group: it reports the near figure while that group is under 2.5% of trials, and the far figure the moment it is over. The headline then swings on an input change that barely moves σ. Measured on a real pair of points, pressing the button again after nudging the pick σ:

95% interval σ correlation
−1.901 / +58.52 ft16.440.51
−1.911 / +7.598 ft16.240.54
−1.904 / +58.60 ft16.440.51

Nothing was miscalculated. Both are correct percentiles of a distribution that should not be handed one interval. The panel now says so:

3.1% of trials landed near 120.4 ft The interval above is unstable Without them: −1.9 / +7.6 ft Raycast Mode: Selected Object, then make the point again

The "without them" figure is the one to use, and the percentage is the thing to fix. Two other lines help you see it coming:

The same shape shows on the point itself, and it is worth recognising: an X sigma of 23.6 ft beside a 3D radial P95 of 5.97 ft cannot describe one tight cloud. A radial 95th percentile smaller than an axis σ means a tight core and a sparse far tail.

The fix is in the raycast, not the statistics. Raycast Mode: Visible Scene lets a perturbed ray hit anything in the scene, including whatever is behind your surface. Selected Object restricts it to one mesh, so a ray that leaves the surface produces nothing instead of jumping to the building behind. Note that the mode is recorded on the point when it is created — changing the dropdown does not change an existing point, so the point has to be made again to pick up the new mode.

Re-running a point after a solve

A point's figures are a spread about the hit it was raycast to, through the camera that was there when it was raycast. Re-running it shoots the same pixel through the camera as it is now. So before any trial is spent, CamMatch re-shoots that pixel once and compares where it lands with where the point sits — the position, and the object it lands on.

The object check is what catches geometry added to the scene. A new object in the way moves the hit by any amount — an inch or a hundred feet — so no distance threshold can see it, but the object's name can. In Selected Object mode the trials only ever meet the recorded target, so added geometry cannot change them; in scene mode it can.

Figures already stored get the same check the cheap way: the run records the camera it used, and the report and the panel compare that with where the camera is now.

Distance between two points

Measure Distance Uncertainty takes two selected points and reconstructs both ends in the same trial, through one perturbed camera. The second point may be another raycast point, or a fixed one — a surveyed Empty that does not move, so the distance inherits only the raycast end's uncertainty.

Do not estimate the two points separately and combine their uncertainties. That is not a safe approximation, it is a wrong answer:

Points Correct σ Combined separately Overstated by
12 units apart, across the view0.04100.04571.1×
2 units apart, across the view0.00680.01251.8×
2 units apart, along the view0.04090.14713.6×
0.1 units apart0.00040.013133×

Both points are seen through one camera. When its pose moves, they move together, and the separation survives what moved both. Combining them separately throws that away and charges twice for an error that cancelled — worst exactly where the points are close, which is where a tight number matters most: a contact point, a gouge, a short skid.

So the distance is often known better than either of its endpoints. That looks wrong until you see why, so the correlation between the two ends is reported beside it, along with the figure the wrong method would have given.

Each end is clicked separately. The pose is shared between the two ends and that is the point; the pick is not. Two features are picked independently, so each end draws its own pick displacement every trial. A displacement common to both ends would largely cancel out of the separation and leave the pick contributing almost nothing to a distance.

Distances are stored on both points, so either one shows them, and a point can be one end of as many as you like.

Two points raycast on different frames are refused. Two frames are two poses; nothing is shared, and what they share is the whole reason this works.

Clearing results

An X beside a distance removes it — from both of its points, since one left behind would come back in the report from the other end. The trash icon beside the point's name discards its uncertainty result while keeping the point itself, so it can be re-estimated. That is what to do after changing the noise settings or re-solving the camera: the stored numbers describe inputs that no longer apply.

What this does not tell you

Everything in Pose uncertainty applies here too, and one thing more: the ray is intersected with your scene geometry, so the result assumes that geometry is where the real surface is. A road plane an inch too high moves every point on it an inch, and no amount of sampling will notice — the trials all agree, because they all use the same wrong surface.

11. Diagnostics images

Diagnostic images are created automatically after each calibration and solve. Open them from the Diagnostics panel:

The Diagnostics button in Quick Actions opens the current frame's overlays directly. Enable Verbose Logging (bottom of Diagnostics) for detailed console output when troubleshooting.

12. Compositing and rendering

CamMatch solves a pinhole camera. Your footage came from a real lens, so the two only line up once one of them is bent to match the other. There are two ways round, and CamMatch builds a node group for each.

What it does Use it when
Distortion MatchDistorts the render to match the footage, then lays it over the untouched clipThe footage is evidence and must not be resampled
Undistort MovieStraightens the footage, then lays the render over itYou want straight lines straight — measuring, or matching a CG set

Both are created automatically whenever a calibration or a solve succeeds, named after the clip: <clip>_DistortionMatch and <clip>_UndistortMovie. They are node groups, kept with a fake user so they survive a save, and a node group does nothing until you put it in the scene's compositor. That is the step people miss.

Wiring one up

  1. Open the Compositing workspace and tick Use Nodes.
  2. Add > Group and pick <clip>_DistortionMatch (or _UndistortMovie).
  3. Connect its Image output to the Composite node.
  4. Add a Viewer node on the same output if you want the backdrop preview.

The group already contains everything else: Render Layers, the Map UV node carrying the calibration's distortion map, the Movie Clip, an Alpha Over, and a Scale node driven to the render size. Recalibrating refreshes that Scale node in place rather than rebuilding the group, so any wiring you added around it survives.

View layers. The group's Render Layers node follows the view layer you are looking at: switch view layers and the composite switches with it, in the viewport compositor and in an F12 render with Render Single Layer on. The Compositor Follows View Layer checkbox in Help & Reset > Reset turns this off, for a setup that should always composite one particular layer; each group then keeps the layer it was last on. With every view layer rendered at once, one group composites one layer, so a group following the active layer composites that one.

Fading between plate and render

Inside the group, the Alpha Over node's Fac input is the blend, and it is the compositor's equivalent of Background Transparency — the control you still have after setting that to 0.

The render is the Foreground in both groups and the plate is the Background in both, so Fac reads the same way whichever you are using:

Fac You see
1.0 (default)the render fully over the plate
0.5both at once — how you eyeball whether the solve lines up
0.0the plate alone

So Fac does not make the movie transparent; it sets how much of the render sits over it. Fading the movie itself is a different job and needs a Mix node, not this one.

Fac is keyable, which is the quick way to make a before/after wipe for a report.

Seeing it in the viewport, through the camera

The compositor normally only runs at render time. To see it live:

  1. Look through the camera (Numpad 0).
  2. Set viewport shading to Material Preview or Rendered.
  3. Open the Shading popover — the small down-arrow at the right of the 3D Viewport header, beside the four shading buttons.
  4. Set Compositor to Camera.
  5. Set Background Transparency (Quick Actions) to 0.
  6. Zoom out until the whole camera frame is inside the viewport.

Camera, not Always: the compositor result is only meaningful inside the camera frame, and Always runs it while you orbit, which is slow and shows you a composite of a view that does not exist.

The whole camera frame must be visible. The viewport compositor works on what the viewport is drawing, not on the camera frame as such. Zoom in far enough that the frame border leaves the viewport and the composite is being computed over a crop of itself — the plate no longer sits where the render thinks it does, and the result goes strange in a way that looks like a bad solve rather than a bad zoom. If the overlay drifts or smears, zoom out and check the whole frame is in view before touching anything else. Home frames it.

Background Transparency must be 0. The camera's background image is the raw clip, drawn flat behind the scene, and it takes no notice of the calibration. The compositor is already bringing the plate in through its own Movie Clip node — distorted to match the render, or undistorted, depending on the group. Leave the background visible and you are looking at two copies of the plate that disagree with each other by exactly the lens distortion you just solved for. Setting it to 0 leaves only the composited one.

If the viewport shows the raw render with no compositing, the realtime compositor has skipped a node it cannot run on the GPU — it supports a subset of the compositor. That is a viewport limitation only; F12 still renders the full tree correctly. Check with a render before assuming the setup is wrong.

Render Distortion Overscan

Why it exists. Distorting a render pulls pixels inward from beyond the frame edge. Those pixels were never rendered, so an un-overscanned render comes back with smeared or empty borders after Map UV — worst at the corners, which is exactly where lens distortion is strongest.

Overscan renders a larger frame so there is something out there to pull in.

How to use it. In Quick Actions, set Render Distortion Overscan and click Apply. A scale of 1.05–1.15 covers most lenses; a strong wide angle may want more. Applying it:

Order matters. Apply overscan after calibrating and solving. Calibration and solving work in the clip's own pixels, so CamMatch temporarily restores the base render size while they run and puts the overscan back afterwards — but the Map UV image is generated at whatever scale was current, so applying overscan last is what keeps it consistent.

Re-applying is safe and not cumulative: the compensation is computed from the scale already recorded on the camera, so going 1.10 → 1.20 adjusts by the difference rather than compounding.

Then crop back. The overscanned render is larger than your footage. The Scale node inside the CamMatch group already scales the composite to the render size; to deliver at the original clip size, set the output resolution back after the Map UV distortion, or crop in your editor. If your final frames come out larger than the clip, this is the step that was skipped.

Render size per camera. Render resolution is a scene setting in Blender, one size for every camera. CamMatch keeps a size of its own on every camera it solves, and swaps the scene's resolution and pixel aspect to match whenever the current camera changes — looking through another camera, picking one in Quick Actions, or switching clips in the Clip Editor. A camera CamMatch never solved has no size of its own, so when one is current the scene's own size is put back. The line under the camera picker says which applies.

Turn on Per-Camera Render Size (Quick Actions) to give every camera a size of its own. A camera then takes the scene's size the first time it is looked through, and from then on switching cameras switches the render size; changing the resolution in the Output properties changes it for the current camera only. Set All gives every camera that has no size yet the scene's current one in one click. Off, Blender's own rule holds for cameras CamMatch did not solve.

13. Export reports

Click Generate Reports (Quick Actions). Choose a folder and CamMatch writes one HTML file per report plus a combined AllReports file. Open any of them in a browser and use Print > Save as PDF for a PDF.

Reports include lens parameters, solve quality (per frame), track details, per-track-over-time, camera trajectory, pose uncertainty, a forensic summary, and a methodology section. Distances are reported in the active scene's length units. Frames whose camera pose keyframe was deleted are pruned automatically on export.


Track list legend (icons & colors)

Usage checkbox (left column):

Icon Meaning
Filled check / filled keyframeTrack is used on this frame (keyframe icon = a per-frame usage key is set)
Empty check / hollow keyframeTrack is not used on this frame
Hidden (eye-off)Track has no marker on this frame

The checkbox is per-frame. Use This Track At All is the whole clip, for a track that is mislinked or mistracked rather than momentarily awkward — it excludes the track from every solve and every calibration until you press it again.

If a track carries per-frame not used marks you did not set, select it and run Clear Per-Frame Usage from the F3 search to clear them for that track. Enable all usage clears every track's, including any frames you unticked on purpose.

Error status dot (Err % column):

Color Meaning
🟢 GreenError below the Warn threshold — good
🟡 YellowBetween Warn and Critical
🔴 RedAt/above Critical (a used inlier) — problem
🟠 Orange + OUTRANSAC outlier — the solve didn't use it
🟠 Orange + AUTOAuto-disabled (critical) — the solver dropped it this frame
⚪ GrayNot used on this frame (no marker or toggled off)

The 🔘 dot next to a track name means it's currently selected/active in the Clip Editor.

The error overlay image uses the same colours: an outlier is drawn orange with OUT after its name, and keeps its arrow, which points from where the tracker put the point to where the solve would, so the reason it was rejected can be seen. Red is reserved for a track the solve used that sits at or above Critical.


Fixed lens vs variable lens — which to use

Calibration precedence, briefly: calibration always writes an intrinsic keyframe at its own frame (constant interpolation). With Key Intrinsics off, a solved frame holds the most recent calibration forward — so recalibrating and re-solving picks up the new lens. With it on, a solved frame owns its lens and won't inherit a later recalibration.


Tips for reliable solves


Troubleshooting

Symptom Fix
OpenCV not foundClick Install OpenCV in Edit > Preferences > Add-ons > CamMatch (it installs the bundled copy, and falls back to downloading from the internet automatically), then restart Blender. Still stuck? See If OpenCV still won't install below.
Panels are empty / "Load a movie clip"Load footage in the Movie Clip Editor and make sure it's in Tracking mode.
Solve fails: "needs at least N points"Add more valid current-frame links. Under 6 points CamMatch falls back to methods that need fewer, but more points solve better.
Many RANSAC outliersCheck the track↔object links, re-track low-quality markers, and verify 3D point positions.
High reprojection errorUse the overlays and the Outside Critical filter to find bad correspondences; disable or fix them and re-solve.
Multi-frame calibration frame looks misalignedFixed — the overlay now uses the scene frame for its background plate. Update to the latest version.
Report shows a frame with no 2D pointsDelete that frame's camera pose keyframe, or re-export (stale-key frames are pruned on export).
A report frame is marked ⚠️ staleYou recalibrated after solving it. Click Re-solve Stale Frames in the Solve Camera panel.
Intrinsics changed unexpectedlyEnable Lock Intrinsics after calibration.
Range solve skips framesCheck Min Points / Min Inliers / Min Inlier Ratio, the Reject/Auto-Disable Critical gates, and whether the tracks have markers on those frames.
Session in a weird stateReset panel > Reset Session.

If OpenCV still won't install

CamMatch tries the bundled offline copy first and then the internet automatically, and it works with the numpy that Blender already ships, so a Python-version mismatch (for example Blender 5.1 on Python 3.13) does not block it. If it still can't install — an offline-only machine, or a corporate firewall blocking PyPI — install OpenCV into Blender's own Python by hand:

  1. Close Blender completely.
  2. Find Blender's bundled Python. It lives next to blender.exe — for example ...\Blender 5.1\5.1\python\bin\python.exe on Windows.
  3. In a terminal, install the headless build (Blender already bundles numpy, so no extra pin is needed): "<path-to>\python.exe" -m pip install "opencv-python-headless<5"
  4. Verify it imports: "<path-to>\python.exe" -c "import cv2; print(cv2.__version__)" should print a version number.
  5. Reopen Blender, open CamMatch, and click Diagnostics — the warning should be gone.

If OpenCV imports in Blender's Python but CamMatch still reports it missing, disable and re-enable the CamMatch extension (or restart Blender once more) so its dependency check re-runs.


Methods and references

CamMatch's geometry is standard published work; what it adds is the surrounding apparatus — links, uncertainty, reporting. The methods are named here because a reconstruction has to be able to say what produced its numbers, and "the software did it" is not an answer when the question is put properly.

Camera pose — the PnP Method setting

Setting Method Reference
solvePnP (SQPnP)Globally optimal perspective-n-point. The default, and it does not depend on a good starting pose.Terzakis, G. & Lourakis, M. A consistently fast and globally optimal solution to the perspective-n-point problem. ECCV 2020, LNCS 12346. doi:10.1007/978-3-030-58452-8_28
solvePnP (Iterative)Levenberg–Marquardt refinement of a direct linear solution.Hartley, R. & Zisserman, A. Multiple View Geometry in Computer Vision, 2nd ed., Cambridge University Press, 2004.
solvePnPRansacRandom sample consensus — what outlier and inlier mean in the track list and the report.Fischler, M.A. & Bolles, R.C. Random sample consensus: a paradigm for model fitting with applications to image analysis and automated cartography. Communications of the ACM 24(6), 1981, 381–395.

Lens and calibration

Feature Method Reference
Calibrate CameraFlexible camera calibration from 2D–3D correspondences. OpenCV starts each view from a pose it computes itself, which on near-flat points can be the mirror image; CamMatch also runs the same joint fit from solvePnP poses and keeps the better result.Zhang, Z. A flexible new technique for camera calibration. IEEE TPAMI 22(11), 2000, 1330–1334.
Brown-Conrady distortionRadial and tangential lens distortion. The Polynomial option is the same radial series without the tangential terms; Brown-Conrady adds k4, Blender's r⁸ term, which CamMatch solves itself because OpenCV has no such term.Brown, D.C. Decentering distortion of lenses. Photogrammetric Engineering, 1966, 444–462 — after Conrady's 1919 formulation.
Rotation conversionRodrigues' rotation formula, between OpenCV's axis–angle vector and Blender's matrix.Classical.

All of these are reached through OpenCV's implementations (cv2.solvePnP, cv2.solvePnPRansac, cv2.calibrateCamera, cv2.Rodrigues), so the behaviour is OpenCV's as well as the papers'. The exception is Brown-Conrady's K4: OpenCV has no r⁸ term, so with K4 in use the projection, undistortion and the K4 fit are CamMatch's own implementation of Blender's lens model, and poses are solved by OpenCV on exactly undistorted points. The OpenCV version in use is shown in Diagnostics, and belongs in a report alongside the CamMatch version.

The uncertainty figures are not from this literature: they are Monte Carlo, re-solving the camera many times under perturbed inputs. What is perturbed, and how many trials ran, is recorded in the report rather than assumed.


CamMatch™ is a trademark of Engineering Dynamics Company (Anthony Cornetto). The source code is GPL v3. CamMatch is a measurement/visualization aid, not a substitute for professional engineering judgment — independently validate every result. See NOTICE.md and README.md for licensing and the full disclaimer.