def setUpClass(cls): """ Equidistant fisheye projection An equidistant fisheye projection with focal length f is defined as the relation r/f = tan(theta), with r being the radius in the image plane and theta the incident angle of the object point. """ x, y, z = 1.0, 0.0, 1.0 u, v = np.arctan2(x, z), 0.0 cls.obj_point = np.array([x, y, z]) cls.img_point = np.array([u, v]) p1 = [-1.0, 0.0, -1.0] p2 = [1.0, 0.0, -1.0] q1 = gtsam.Rot3(1.0, 0.0, 0.0, 0.0) q2 = gtsam.Rot3(1.0, 0.0, 0.0, 0.0) pose1 = gtsam.Pose3(q1, p1) pose2 = gtsam.Pose3(q2, p2) camera1 = gtsam.PinholeCameraCal3Fisheye(pose1) camera2 = gtsam.PinholeCameraCal3Fisheye(pose2) cls.origin = np.array([0.0, 0.0, 0.0]) cls.poses = gtsam.Pose3Vector([pose1, pose2]) cls.cameras = gtsam.CameraSetCal3Fisheye([camera1, camera2]) cls.measurements = gtsam.Point2Vector( [k.project(cls.origin) for k in cls.cameras])
def setUpClass(cls): """ Stereographic fisheye projection An equidistant fisheye projection with focal length f is defined as the relation r/f = 2*tan(theta/2), with r being the radius in the image plane and theta the incident angle of the object point. """ x, y, z = 1.0, 0.0, 1.0 r = np.linalg.norm([x, y, z]) u, v = 2*x/(z+r), 0.0 cls.obj_point = np.array([x, y, z]) cls.img_point = np.array([u, v]) fx, fy, s, u0, v0 = 2, 2, 0, 0, 0 k1, k2, p1, p2 = 0, 0, 0, 0 xi = 1 cls.stereographic = gtsam.Cal3Unified(fx, fy, s, u0, v0, k1, k2, p1, p2, xi) p1 = [-1.0, 0.0, -1.0] p2 = [ 1.0, 0.0, -1.0] q1 = gtsam.Rot3(1.0, 0.0, 0.0, 0.0) q2 = gtsam.Rot3(1.0, 0.0, 0.0, 0.0) pose1 = gtsam.Pose3(q1, p1) pose2 = gtsam.Pose3(q2, p2) camera1 = gtsam.PinholeCameraCal3Unified(pose1, cls.stereographic) camera2 = gtsam.PinholeCameraCal3Unified(pose2, cls.stereographic) cls.origin = np.array([0.0, 0.0, 0.0]) cls.poses = gtsam.Pose3Vector([pose1, pose2]) cls.cameras = gtsam.CameraSetCal3Unified([camera1, camera2]) cls.measurements = gtsam.Point2Vector([k.project(cls.origin) for k in cls.cameras])
def test_triangulation_robust_three_poses(self) -> None: """Ensure triangulation with a robust model works.""" sharedCal = Cal3_S2(1500, 1200, 0, 640, 480) # landmark ~5 meters infront of camera landmark = Point3(5, 0.5, 1.2) pose1 = Pose3(UPRIGHT, Point3(0, 0, 1)) pose2 = pose1 * Pose3(Rot3(), Point3(1, 0, 0)) pose3 = pose1 * Pose3(Rot3.Ypr(0.1, 0.2, 0.1), Point3(0.1, -2, -0.1)) camera1 = PinholeCameraCal3_S2(pose1, sharedCal) camera2 = PinholeCameraCal3_S2(pose2, sharedCal) camera3 = PinholeCameraCal3_S2(pose3, sharedCal) z1: Point2 = camera1.project(landmark) z2: Point2 = camera2.project(landmark) z3: Point2 = camera3.project(landmark) poses = gtsam.Pose3Vector([pose1, pose2, pose3]) measurements = Point2Vector([z1, z2, z3]) # noise free, so should give exactly the landmark actual = gtsam.triangulatePoint3(poses, sharedCal, measurements, rank_tol=1e-9, optimize=False) self.assertTrue(np.allclose(landmark, actual, atol=1e-2)) # Add outlier measurements[0] += Point2(100, 120) # very large pixel noise! # now estimate does not match landmark actual2 = gtsam.triangulatePoint3(poses, sharedCal, measurements, rank_tol=1e-9, optimize=False) # DLT is surprisingly robust, but still off (actual error is around 0.26m) self.assertTrue(np.linalg.norm(landmark - actual2) >= 0.2) self.assertTrue(np.linalg.norm(landmark - actual2) <= 0.5) # Again with nonlinear optimization actual3 = gtsam.triangulatePoint3(poses, sharedCal, measurements, rank_tol=1e-9, optimize=True) # result from nonlinear (but non-robust optimization) is close to DLT and still off self.assertTrue(np.allclose(actual2, actual3, atol=0.1)) # Again with nonlinear optimization, this time with robust loss model = gtsam.noiseModel.Robust.Create( gtsam.noiseModel.mEstimator.Huber.Create(1.345), gtsam.noiseModel.Unit.Create(2)) actual4 = gtsam.triangulatePoint3(poses, sharedCal, measurements, rank_tol=1e-9, optimize=True, model=model) # using the Huber loss we now have a quite small error!! nice! self.assertTrue(np.allclose(landmark, actual4, atol=0.05))