all_lessons/3D Vision/03 · Where is the camera? Rigid motion on a curved spacelesson 3 / 14

Where is the camera? Rigid motion on a curved space

Lesson 2 pinned a point with two rays, but only because it was told where the second camera is. Here that is the unknown: a rotation and a translation. The translation is a vector. The rotation is not: the average of two rotations 90° apart has determinant 0.50, a "camera" that halves volumes, and descent on the nine entries of a rotation matrix passes through shrunken, sheared and even mirrored frames on the way to its target. This lesson shows why (rotations are a curved three-dimensional surface in nine dimensions), shows that no three-number labelling of them is safe everywhere (Euler angles lock), and derives the tool that is: differentiate the constraint, find the flat space of small rotations, and map it back with the exponential. That moves a pose without leaving the space of poses. It does not say which way to move.

The thesis, here
A rotation is a point on a curved three-dimensional surface inside the nine-dimensional space of matrices, so the operations that optimisation is built from (add, average, step) do not apply to it. What does apply is a small step from where you are: the small rotations at any rotation form a flat space of 3-vectors, the tangent space, and the exponential map carries each one back onto the surface exactly.
Linear position
Forced by: Two rays pin a point only because we were told where the second camera is. In practice that is the unknown: a robot, a phone or a scanner moves between measurements, and every depth map lives in its own sensor frame. To compare or merge frames we must write down a rotation and a translation, and a rotation cannot be added, averaged or stepped along like a vector. How do we describe a rigid motion so that a computer can estimate it?
New idea: a pose is never added to, only moved: a small rotation is a 3-vector δ in the tangent space, applied as R ← R·exp([δ]×). The exponential is exact, so the unknowns of a pose problem are six ordinary numbers per camera, re-centred at the current estimate.
Forces next: A pose is now a rotation and a translation, and a small correction is a rotation vector applied through the exponential map, a step that never leaves the space of rotations. That says how to move, but not in which direction. Two scans of the same room, taken from unknown poses, must coincide where they overlap. How do we turn "the scans should coincide" into an equation we can solve for the pose?
The plan
Seven moves. (1) Write the unknown as a pose and watch averaging fail. (2) Count why: a curved set, and steps that leave it. (3) Look for coordinates; each breaks somewhere. (4) Differentiate the constraint: tangent space, exponential, logarithm. (5) The same for a whole pose. (6) Run the rule against the alternatives. (7) See what a step still does not tell us.

1 · The unknown is a pose, and the first instinct fails

Lesson 2 ended with a point cloud in the frame of the sensor that took it. A second sensor, or the same one a moment later, gives a cloud in its own frame. A world point at xA in A's frame is at xB = R xA + t in B's: a 3×3 rotation matrix R and a vector t, twelve numbers that make a pose, the "where is the second camera" that lesson 2 was told and must now find. Poses compose, (R1, t1)∘(R2, t2) = (R1R2, R1t2 + t1) (the right one acts first), and invert, (R, t)−1 = (RT, −RTt); G3.se3 in the shared geom3.js does both. This lesson leaves Flatland: in a plane a rotation is one angle on a circle, rotations commute, and the circle's single seam is handled by one wrap (below). The full difficulty exists only in 3D, so the code here is true 3D.

The translation is harmless, a vector in a flat space whose average is a midpoint. The trouble is R. When two estimates of a rotation disagree, the first thing anyone tries is the entrywise average M = (R1 + R2)/2. For R1 = I and R2 a rotation by θ about any axis:

angle θ between the two30°90°180°
det M0.930.500.00
‖MTM − I‖0.0950.711.41

A rotation has determinant 1 and MTM = I: it keeps lengths and angles. At 90° the average has halved every volume and shortened lengths in the plane of the turn by 29%; at 180° it flattens that plane to a point. (In closed form det M = cos²(θ/2) and ‖MTM − I‖ = √2 sin²(θ/2).) The same failure shows up in one dimension. In a plane a rotation is an angle, and the average of 359° and 1° is 180° by arithmetic when the right answer is 0°. The cure is to average differences, wrapped the short way round: 359° + ½·wrap(1° − 359°) = 359° + ½·(+2°) = 360° ≡ 0°. A circle has one seam and the wrap steps over it. In 3D there is no single seam to hide, and the rest of the lesson is the 3D version of "average differences, not values".

2 · Nine numbers, six constraints: a curved set

A rotation matrix has orthonormal columns, RTR = I, and det R = +1. The first equation compares two symmetric 3×3 matrices, so it is six independent equations (three unit lengths, three right angles) on nine unknowns: 9 − 6 = 3 degrees of freedom, matching a rotation's axis (two numbers) and angle (one). The condition det R = +1 excludes the mirror images. So the rotations are a three-dimensional surface in the nine-dimensional space of matrices, the way a sphere is a two-dimensional surface in three, and the midpoint of two points of a sphere lies inside it. M is that midpoint.

A step fails the same way, more slowly. Correct a rotation by a small turn δ (a 3-vector: turn by ‖δ‖ about the axis δ, in the frame's own axes) by adding the first-order change: R ← R + R[δ]× = R(I + [δ]×), where [δ]× is the skew-symmetric matrix with [δ]×v = δ × v. Skewness gives (I + [δ]×)T(I + [δ]×) = I + [δ]×T[δ]×, so one step leaves ‖RTR − I‖ = √2‖δ‖² and det R = 1 + ‖δ‖²: 0.0141 and 1.01 for ‖δ‖ = 0.1. Second order, and small, but it compounds: turning a frame through a full circle in 63 steps of 0.1 rad, as a naive integrator or optimiser would, leaves its axes 1.37 times too long and its determinant at 1.87. A computer that adds corrections to a rotation matrix soon estimates something that is not a camera.

3 · Coordinates for the set, and why none is safe everywhere

If the matrix is the problem, label the rotations by fewer numbers that obey no constraint, and let the optimiser add to those. A good labelling gives every rotation a label, makes a small change of label a small change of rotation everywhere, and uses exactly three numbers, so that the optimiser has neither redundant nor missing directions. Four are in common use:

LabellingNumbersWhat goes wrong
the nine entries9, six constraintsevery step leaves the set (§2)
Euler angles (yaw, pitch, roll)3at pitch ±90° two knobs turn the frame about the same axis
rotation vector ω = θn3ω and −ω are one rotation at θ = π; vectors do not add
unit quaternion4, one constrainth and −h are one rotation; a step leaves the unit sphere

Euler angles. Yaw ψ turns about the vertical z-axis, pitch θ about y, roll φ about x: R = Rz(ψ)Ry(θ)Rx(φ), and any triple is a rotation. Differentiating each factor shows how the knobs turn the frame: dψ about the world z-axis a1 = (0, 0, 1), dθ about a2 = (−sin ψ, cos ψ, 0), dφ about the frame's own x-axis a3 = (cos ψ cos θ, sin ψ cos θ, −sin θ). So the angular velocity, in world axes, is ω = A·(dψ, dθ, dφ)/dt with A = [a1 a2 a3], and |det A| = cos θ. At θ = ±90° we get a3 = ∓a1: yaw and roll turn the frame about the same axis, and the three knobs produce only a plane of angular velocities. The singular values of A are √(1 + sin θ), 1 and √(1 − sin θ), so turning the frame at 1 rad/s about its hardest direction takes a combined knob speed (the length of the vector of the three rates) of √(1 + sin θ)/cos θ rad/s:

pitch0°60°80°89°90°
|det A| = cos(pitch)10.500.170.0170
combined knob speed for 1 rad/s about the hardest axis12.78.181∞

That is gimbal lock. A different order of axes moves it to a different pose and does not remove it; a body whose x-axis points straight up or down is exactly there.

Rotation vector and quaternion. The vector ω = θn (axis n, angle θ) gives the rotation exp([ω]×) of §4 and is regular near zero, but it folds over itself on the sphere ‖ω‖ = π and does not add: the quarter-turns about x and about y have vectors (π/2, 0, 0) and (0, π/2, 0) whose sum has length 127.3°, while doing one turn and then the other is a single rotation by 120.0°. The quaternion h = (cos θ/2, sin θ/2·n) composes by the Hamilton product (16 multiplications against 27 for a matrix product, no trigonometry) and has no lock. But h and −h are one rotation, and a step leaves the unit sphere as R + δR leaves the rotations: ‖h + δh‖² = 1 + ‖δh‖² for a step tangent to the sphere. A quaternion is a good way to store a rotation. It does not remove the curvature.

No labelling by three numbers is safe everywhere, and this is not bad luck. The rotations form a closed surface without an edge, like a sphere, and as no flat map of the Earth is faithful everywhere, no smooth one-to-one labelling of all rotations by three real numbers exists. So ask for less: not one labelling of the whole set, but a good one around the rotation we are at, rebuilt after every step. The rotation vector is perfectly regular near ω = 0, and ω = 0 is wherever we stand if we re-centre.

4 · Differentiate the constraint: the tangent space and the exponential

Take any smooth path of rotations R(t) and differentiate RTR = I: (dR/dt)TR + RT(dR/dt) = 0. So Ω = RTdR/dt satisfies ΩT = −Ω: it is skew-symmetric, with zero diagonal and three free numbers, which we collect as Ω = [ω]× = (0, −ωz, ωy; ωz, 0, −ωx; −ωy, ωx, 0). Hence

dR/dt = R [ω]×,   ω ∈ ℝ³ free

At every rotation R the possible velocities are R[ω]× for a free 3-vector: a flat three-dimensional space (9 − 6 = 3 again), the tangent space at R, with ω the angular velocity in the frame's own axes. Hold ω constant. The linear equation has the solution R(t) = R(0)·exp(t[ω]×), where exp(A) = I + A + A²/2! + A³/3! + ⋯. Write ω = θn with n a unit vector. Since n × (n × (n × v)) = −n × v, [n]׳ = −[n]×; the odd powers of θ[n]× are ±θ2m+1[n]×, the even ones ±θ2m[n]ײ, and summing both series gives Rodrigues' formula

exp([ω]×) = I + sin θ [n]× + (1 − cos θ) [n]ײ

the rotation by angle θ about axis n, and a rotation exactly: exp(A)T = exp(−A) is its inverse because A and −A commute, and det exp(A) = etr A = 1. The first-order step of §2 is the first two terms of this series; the remaining terms put it back on the surface. The inverse, the logarithm, follows from tr R = 1 + 2 cos θ and R − RT = 2 sin θ [n]×: for 0 < θ < π, θ = arccos((tr R − 1)/2) and ω = θn (at exactly π there are two answers, ±n). With exp and log we can do what the nine entries would not let us:

we wantin the tangent spaceon the set
apply a small correctionδ, three free numbersR ← R·exp([δ]×)
the correction from Ra to Rblog(RaTRb)Ra·exp(log(RaTRb)) = Rb
how far apart they are‖log(RaTRb)‖ = arccos((tr(RaTRb) − 1)/2)the angle of the turn between them
their meanhalf that correctionRa·exp(½ log(RaTRb))

The mean is the repair of §1: for two rotations 90° apart it is the rotation by 45°, a rotation, 45° from each. The distance (G3.m3.dist) is an angle, not a matrix difference: the entrywise distance is the chord ‖Ra − Rb‖F = 2√2 sin(α/2) for a turn α, which is 2.00 where the arc is 1.57 at 90°, and 2.83 where it is 3.14 at 180°. Order matters: R·exp([δ]×) turns the frame about its own axes, exp([δ]×)·R about the fixed world axes, and they differ because rotations do not commute (Rx(90°)Ry(90°) and Ry(90°)Rx(90°) are 120.0° apart). We use the first form from here on.

Check the map δ ↦ R·exp([δ]×) against the three requirements of §3. Every rotation near R is R·exp([δ]×) for some small δ, so every one has a label. At δ = 0 the derivative is R[·]×, which loses no direction whatever R is. And it uses three numbers. The price is that it folds over at ‖δ‖ = π and is a good chart only near δ = 0, which is why we re-centre after every step.

5 · The same for a pose: SE(3)

A pose (R, t) is a point of a six-dimensional curved set, called SE(3), and moves the same way. Its velocity, seen from the pose, is a twist ξ = (ρ, ω): the velocity of the origin and the angular velocity, in the pose's own axes. As a 4×4 matrix T = (R, t; 0, 1) it obeys dT/dt = T ξ̂ with ξ̂ = ([ω]×, ρ; 0, 0), and a constant twist carries it to T·exp(ξ̂). With K = [ω]× the powers are ξ̂n = (Kn, Kn−1ρ; 0, 0), so

exp(ξ̂) = ( exp(K), Vρ ; 0, 1 ),   V = I + K/2! + K²/3! + ⋯ = I + ((1 − cos θ)/θ²) K + ((θ − sin θ)/θ³) K²

The translation after the motion is Vρ, not ρ. A body moving forward at 1 m/s while turning at π/2 rad/s follows a quarter circle of radius 2/π, and after one second it is at (0.64, 0.64) m, not at (1, 0). Only without rotation (V = I) do translations add. The rest is as for rotations: the update is T ← T∘exp(ξ), the correction from Ta to Tb is log(Ta−1Tb), and G3.se3.exp and G3.se3.log compute both.

6 · The rule, run against the alternatives

The rule: to improve a pose, differentiate the loss with respect to a 3-vector δ in the tangent space at δ = 0, step in that space, and apply the step with the exponential. The earlier sections ruled out the alternatives by argument; the widget runs them. A rigid body carries three markers, 1, 2 and 3 units out along its red, green and blue axes (a lopsided tripod, so that the problem is not symmetric). A target pose says where they should be, qk = R*pk, and the loss is the squared distance f(R) = ½ Σk ‖R pk − qk‖². One loss, one start, four ways to move:

movevariablesgradientupdate, one fixed step
(i) nine entriesR, 9 numbersΣk (Rpk − qk)pkTR ← R − 0.2·gradient
(i′) nine, projectedR, 9 numbersthe sameas (i), then R ← the nearest rotation
(ii) Euler angles(ψ, θ, φ)⟨∂f/∂R, [aj]×R⟩ per angleangle ← angle − (1/13)/(1 + |sin θ|)·gradient
(iii) tangent spaceδ, 3 numbersΣk (RTqk) × pkR ← R·exp([−0.1·gradient]×)

Each step is a round number chosen to be stable for its method. For (iii) the loss curves upward by Σ‖δ × pk‖² = δT(tr M·I − M)δ with M = ΣpkpkT = diag(1, 4, 9), that is by 13, 10 and 5 along the axes, so with step 0.1 the error components shrink by factors of 0.3, 0 and 0.5 per iteration (the slowest, 0.5, predicts about 20 iterations to 10⁻⁶). Method (i) sees curvatures 1, 4 and 9, and its best fixed step, 0.2, leaves a slowest factor of 0.8, about 62 iterations. Method (ii) sees curvatures up to 13(1 + sin θ) in the angle variables, so its step is 1/13 divided by 1 + |sin θ|, at most half the stability bound at the target. The step is not what makes Euler slow: a step 1.5 times larger finishes in 277 and 9618 iterations at pitches 60° and 85°, instead of 418 and 14395, and a step 2.5 times larger converges at none of the pitches 0°, 20°, 60°, 80° and 85°.

Four ways to turn a frame
A body with three markers (arms 1, 2, 3 along red, green, blue) goes from the start (dashed) to the target (ghost; squares are where the markers should be). Left: the marker paths up to the iterate shown, and that iterate's frame; a matrix that is not a rotation draws as a shrunken or sheared frame. Right: orthonormality error, distance to the best rotation and determinant at every iteration (log axis); the chosen move is the thick line. Target pitch changes the numbers only for Euler angles.
iterations until within 10⁻⁶ of the best rotation
—
distance to best rotation, at the end
—
worst orthonormality error on the way
—
orthonormality error at the end
—
smallest determinant on the way
—
loss at the end
—
loss of the best rotation
—
cos(pitch) of the iterate shown
—
Show the core JS
RM.gradTan = function (R, S) {
  var g = [0, 0, 0], Rt = m3.T(R);
  for (var k = 0; k < 3; k++) g = v3.add(g, v3.cross(m3.mulv(Rt, S.Q[k]), RM.P[k]));
  return g;
};
...
    if (method === 'exp') {
      Rn = m3.mul(R, m3.exp(v3.scale(RM.gradTan(R, S), -eta)));
    } else if (method === 'euler') {
      var G = RM.gradR(R, S), ax = RM.eulerAxes(ang[0], ang[1]), etak = eta / (1 + Math.abs(Math.sin(ang[1])));
      for (j = 0; j < 3; j++) { var dR = m3.mul(m3.skew(ax[j]), R), s = 0; for (i = 0; i < 9; i++) s += G[i] * dR[i]; ang[j] -= etak * s; }
      Rn = m3.eulerZYX(ang[0], ang[1], ang[2]);
    } else {
      var Gn = RM.gradR(R, S);
      Rn = R.map(function (v, q) { return v - eta * Gn[q]; });
      if (method === 'proj') Rn = m3.nearestRotation(Rn);
    }
...
m3.exp = function (w) {
  var th = v3.norm(w), K = m3.skew(w), K2 = m3.mul(K, K), a, b;
  if (th < 1e-8) { a = 1 - th * th / 6; b = 0.5 - th * th / 24; } else { a = Math.sin(th) / th; b = (1 - Math.cos(th)) / (th * th); }
  return m3.add(m3.add(m3.id(), m3.scale(K, a)), m3.scale(K2, b));
};

What to try. The page opens on (i), the nine entries, with exact markers and a start 100° from the target. With nine free numbers the loss pulls each marker straight toward its own target, so each path is a chord of the sphere the marker should stay on: red and green cut through the inside of theirs, and blue, whose step overshoots its target, zig-zags across it. The run needs 65 iterations, and on the way ‖RᵀR − I‖ reaches 2.77 and the determinant falls to 0.28; drag iterate shown to watch the frame shrink and shear. Raise the start to 170° and the determinant goes through zero to −0.21: the frame is turned inside out and recovers only because the target happens to be a rotation. Switch the markers to noisy. Now (i) settles on a matrix with ‖RᵀR − I‖ = 0.18 and determinant 1.06, 0.087 from the best rotation and never closer, with a loss of 0.0000 against 0.0048 for the best rotation: nine free numbers fit three noisy markers perfectly by not being a rotation. Methods (i′) and (iii) are rotations at every iterate and reach the best rotation in 20 and 22 iterations; for (iii) the count depends on how far the start is (18 at 10°, 27 at 170°) and on nothing else. Now (ii), Euler angles, with target pitch 0°: 28 iterations. Raise the pitch: 418 at 60°, 3778 at 80°, 14395 at 85°, and at 89° the run has not arrived after 20000 (it stops 0.010 short) while the dotted cos(pitch) curve sits near zero. The count grows like 1/cos²(pitch): iterations × cos²(pitch) is between 105 and 114 from 60° to 85°, because the weakest curvature in the angle variables lies between 5 and 13 times 1 − sin(pitch).

Road not taken · keep the nine entries and enforce the constraint another way
Two ways. A penalty adds (μ/2)‖RTR − I‖² to the loss, so the constraint becomes a preference. With the noisy markers the minimiser's orthonormality error is 0.0071 at μ = 10 and 0.00081 at μ = 100, while the gradient steps needed (at the largest stable step, 1/(9 + 4μ)) rise from 431 to 3611: each digit of orthonormality costs ten times the work, and nothing reaches the 10⁻¹⁵ of an exp step. Projection, method (i′), works, and the widget shows it converging: it is a legitimate way back onto the set. We do not build on it for three reasons. It needs a matrix decomposition per step, and it is undefined where the matrix is singular: the nearest rotation to diag(0, 0, 1), the average of I and a half turn about z, is every rotation about z at once (all at distance √2). It takes steps in nine dimensions and throws six away. And it gives no coordinates for the correction: the lessons ahead solve for corrections with linear algebra, and a solve needs each rotation's correction as three free numbers, which is what δ is.
Road not taken · Euler angles everywhere
Euler angles are what people read and write (three sliders, a file format, an instrument panel) and any triple is a pose. For an interface they are right, and graphics uses them there. For an optimiser they fail where §3 says: the widget's count grows like 1/cos²(pitch), and the same rotation has two Euler triples, (ψ, θ, φ) and (ψ + 180°, 180° − θ, φ + 180°), so even "the angle error" is ambiguous. The remedy is to convert at the boundary, from angles to R when reading and back when writing, and to estimate in the tangent space.

7 · What a step cannot tell us

A pose is now six free numbers, and the rule moves it exactly. The rule needs a step, and in the widget every optimiser was handed the answer: the loss was written with the target. Two scans come with no target. Take scan A and scan B of the same room corner and crate, 1200 points each, each in its own sensor frame (§1) and each a different random sample of the same surfaces. Apply the true pose to A and its points still do not sit on B's: the average distance from a point of A to the nearest point of B is 0.099 m, not zero, because the scans sample the surface in different places. Move A off the truth by a rigid motion of 15° and 27 cm and the average becomes 0.436 m. That number says how wrong the pose is. It does not say which of the six directions to move in: of 1000 random steps of 2° and 2 cm from the start, between 49.5% and 50.1% lower it (three seeds), and the average change is 0.25 mm against a standard error of 0.77 mm. A step with no direction is a coin flip.

What this lesson did not do
It did not say which pose to move to: every loss here was written with a target in hand, and scans have none (lesson 4 builds the loss from the data, with and without known matches). It used plain gradient descent with fixed steps; lesson 5 solves for all corrections at once, in these same three coordinates. It gave rotations no uncertainty, and left the logarithm undefined at exactly 180°, where the mean of two rotations is not unique. And it chose one way to combine the updates of rotation and translation; updating R by the exponential and t by addition is also valid.

Common mistakes / failure modes

"average the rotation matrices"
Two rotations 90° apart average to a matrix of determinant 0.50, not a rotation. Average in the tangent space, Ra·exp(½ log(RaTRb)) (§1, §4).
"a small step R + δR is safe"
One first-order step leaves ‖RTR − I‖ = √2‖δ‖² and the error compounds: axes 1.37 times too long after one turn. Only the exponential is exact (§2, §4).
"Euler angles are three numbers, so they are the right variables"
|det A| = cos(pitch): descent needs about 110/cos²(pitch) steps, 14395 at 85° (§3, widget).
"h and −h are different rotations"
They are one rotation: the unit quaternions cover the rotations twice (§3).
"exp of a twist moves the origin by ρ"
It moves it by Vρ: a quarter turn per second ends at (0.64, 0.64), not (1, 0) (§5).
"the angle between rotations is ‖Ra − Rb‖"
That is the chord, 2√2 sin(α/2): 2.00 where the angle is 1.57 rad. The angle is ‖log(RaTRb)‖ (§4).
"R·exp(δ) and exp(δ)·R are the same"
Rotations do not commute: the quarter turns about x then y, and y then x, are 120.0° apart. Right-multiplying turns about the frame's own axes (§4).

Checkpoint exercise

Try it
(a) A robot drives forward at 2 m/s while turning at 180°/s for one second, so its twist is ξ = (ρ, ω) = ((2, 0, 0), (0, 0, π)). Where does exp(ξ) put it, and how far off would t = ρ be? (b) A frame is advanced ten times by R ← R(I + [δ]×) with δ = (0, 0, 0.1). How long are its axes afterwards, and what is its determinant? Answer: (a) the path is a half circle of radius ‖ρ‖/‖ω‖ = 2/π, so the robot ends at (0, 4/π) = (0, 1.27) m facing backwards, whereas t = ρ would say (2, 0), 2.37 m away. (b) Each step multiplies lengths in the plane of the turn by √1.01 and the determinant by 1.01, so the axes are 1.01⁵ = 1.051 times too long and the determinant is 1.01¹⁰ = 1.105; the frame has turned 57.1° instead of 57.3°. Ten exponential steps keep the determinant at 1.

Where this points next

A pose is now six free numbers whose update never leaves the set of poses: small corrections are 3-vectors in the tangent space, applied with the exponential, and the distance between two rotations is an angle. What this cannot do is choose the step. In the widget every optimiser knew the target; two scans come with none, and the pose that makes them coincide is the unknown itself. Even at the true pose a point of scan A is 0.099 m from its nearest neighbour in B on average, because no point of one lies on a point of the other; from a start 15° and 27 cm off it is 0.436 m; and that number gives no direction, since about half of the random steps lower it and half raise it. Lesson 4 stays in the plane, where a rotation is one angle and the exponential step is plain addition, so it meets this lesson in its simplest form; what it derives carries to 3-D (its closed-form solve through an SVD), and lesson 5 returns to full 3-D with the machinery above. How do we turn "the scans should coincide" into an equation we can solve for the pose?

Takeaway
A pose is a rotation and a translation. The translation is an ordinary vector; the rotation is a point on a curved three-dimensional surface in the nine-dimensional space of matrices (RTR = I: nine numbers, six constraints). Adding, averaging and stepping take it off the surface: two rotations 90° apart average to determinant 0.50, and a gradient step on the nine entries passes through shrunken and mirrored frames. No labelling by three numbers is safe everywhere: Euler angles lock (|det A| = cos(pitch)), the rotation vector folds at π, and the quaternion keeps a constraint. What works is local. Differentiating RTR = I shows that the velocities at R are R[ω]× with ω a free 3-vector (the tangent space); the exponential, Rodrigues' formula, maps it back onto the set exactly; the logarithm inverts it, and ‖log(RTR*)‖ is the angle between two rotations. A pose is updated by T ← T∘exp(ξ) with a twist ξ = (ρ, ω) whose translation is Vρ. What remains is the direction: nothing here says which ξ makes two scans coincide.

Interview prompts

Companion reads: Computer Graphics · 02 Transforms and spaces (the matrices as a graphics tool; this lesson adds why they cannot be averaged or stepped), Computer Graphics · 13 Animation and motion (quaternions, slerp and gimbal lock from the animator's side), and Computer Vision · 04 Cameras and projection geometry (the extrinsics (R, t) that this lesson makes estimable).