In many cases, we estimate the location and orientation of a camera as it moves over time while sharing a single unknown calibration object. PinholePose<CALIBRATION> supports this pattern by treating calibration as shared external data, so its optimization state is only the six-dimensional camera pose.
import gtsam
import numpy as npCreating a pose-only camera¶
The wrapper provides specializations for the same calibration families as PinholeCamera. Supply a calibration when projection needs pixels; the pose remains the only manifold state.
K = gtsam.Cal3_S2(800.0, 790.0, 0.0, 320.0, 240.0)
pose = gtsam.Pose3(gtsam.Rot3.Yaw(0.1), np.array([1.0, 0.0, 0.0]))
camera = gtsam.PinholePoseCal3_S2(pose, K)
print("manifold dimension:", camera.dim())
print("calibration fx:", camera.calibration().fx())Projection and backprojection¶
The projection API mirrors PinholeCamera: project(), projectSafe(), backproject(), range(), and pose() all operate on the shared calibration and stored pose.
point = np.array([1.5, 0.2, 5.0])
pixel = camera.project(point)
depth = camera.pose().transformTo(point)[2]
recovered = camera.backproject(pixel, depth)
print("pixel:", pixel)
np.testing.assert_allclose(recovered, point, atol=1e-9)Pose manifold¶
retract() applies a six-vector pose increment, and localCoordinates() compares two pose-only cameras. Calibration is not part of that tangent vector.
delta = np.array([0.01, -0.01, 0.02, 0.1, 0.0, -0.05])
perturbed = camera.retract(delta)
np.testing.assert_allclose(camera.localCoordinates(perturbed), delta, atol=1e-8)Choosing between PinholePose and PinholeCamera¶
Use PinholePose when many cameras share a fixed calibration or calibration is managed separately. Use PinholeCamera when pose and calibration should travel as one value—and potentially be optimized together in a calibration-specific manifold.