Sign in

Photomatch

— solve a site photo's camera from its vanishing points

Open in new tab

Drag two (or three) bundles of parallel building edges onto a site photograph and read back the camera that took it: focal length, field of view, and — with one known height — the eye height. Rectify mode flattens a façade into a measurable elevation. When the lines can't describe a real camera, it says which bundle is the problem and refuses.

Runs entirely in your browser. No sign-in, no upload, no AI.

Nothing is uploaded — the photograph is decoded in this browser and stays here. It is scaled to 2400 px on its long side, and every coordinate below is in that space.

Drag bundles of parallel edges; two perpendicular bundles give the lens and the orientation.

Draw each line the way the positive axis runs. The vanishing point can't tell +X from −X, so the drawn direction is what decides it.

X — one horizontal run of the building0
Y — the verticals0
Z — the other horizontal run0

Two bundles is the minimum, and each needs at least two lines. A third bundle is not needed for the solve — it is an independent check on it.

m

6'-11" — the true vertical distance between the two handles.

Two vanishing points fix where the camera LOOKS and how wide, never where it stands. One vertical thing of known height — clicked at its foot, dragged to its top — is what turns the shape into a size.

MatchDragging: X — one horizontal run of the building
Load a site photograph

Then drag along the building’s edges. Two bundles of parallel lines — one horizontal run and the verticals — are enough to recover the lens and the direction the camera was pointing.

Load a site photograph to begin.

The camera

Load a site photograph, then drag along the building’s edges to build the first bundle.

Sources & methods

The relation the whole tool turns on. Work in image coordinates centred on the principal point. Two vanishing points v₁, v₂ belonging to directions that are perpendicular in the world satisfy v₁·v₂ + f² = 0, so the focal length in pixels is f = √(−(v₁·v₂)). Each world direction is then d = ±normalize([v.x, v.y, f]) in camera coordinates, and the rotation is those directions as the columns of R, Gram-Schmidt orthonormalised. The ± genuinely cannot be read off a vanishing point — the image of a direction and of its reverse is the same point — so it comes from the direction you DRAGGED each line, which is why the tool asks you to draw along the positive axis.

The assumption you are making. The principal point is taken to be the image centre. That is exactly true for an uncropped frame from a rectilinear lens and approximately true otherwise; a photograph that has been cropped off-centre, or shot on a shift lens, breaks it and the focal length comes out wrong in proportion. Two vanishing points give two constraints, and solving for the focal length AND the principal point needs three — so nothing here re-derives it. Pixels are assumed square and the lens undistorted: no barrel correction is applied.

When it refuses, and why that is the point. The solve is underdetermined — and Photomatch says so instead of printing a number — when a bundle has fewer than two lines; when a bundle’s lines are parallel on the page, so its vanishing point is at infinity; when two bundles vanish to nearly the same point, so they are the same world direction twice; when two bundles are labelled the same axis; and when v₁·v₂ ≥ 0, which means the principal point falls outside the triangle of the vanishing points, the focal length that would make those bundles perpendicular is imaginary, and no camera took that photograph with those lines. Each refusal names the bundle at fault and says what to change. A plausible-looking wrong camera is the worst thing this tool could hand you, so it does not have a code path that produces one.

What two vanishing points do NOT give you. A position. They fix the orientation and the lens and stop dead: the same photograph is consistent with a doll’s house at two metres and a tower block at two hundred. The eye height comes from the one measurement you supply — a vertical thing of known height, clicked foot and top, whose two rays are intersected in the least-squares sense. Until you give one, the exported camera says in its own note that its position is a placeholder.

Rectify. A plane in the world maps to its image by a homography — a 3×3 matrix with eight degrees of freedom, which is exactly what four corner correspondences pin down. The 8×8 system is solved by Gaussian elimination with partial pivoting on isotropically normalised coordinates (Hartley), then the image is inverse-warped with bilinear sampling. It refuses on a degenerate quad — two corners on the same spot, or three on one line — because those do not determine a plane. The flattened drawing is only as flat as the façade really is: a bay window, a batter or a bowed wall will not come out straight, and the scale is only true for things ON that plane.

Where the numbers come from. Focal length is quoted in millimetres on a 36×24 mm full-frame gate, the number Rhino and every camera use; the field of view follows from it. Lengths are metric internally with a foot-and-inch read-along. The mathematics is in src/lib/photomatch/ — pure, headless and covered by its own selftest, which synthesises a known camera, projects known parallel lines through it, and checks that the solver gets the camera back.

Photomatch · Good Tools