# ----------------------------------------------------------------------------# SymForce - Copyright 2022, Skydio, Inc.# This source code is under the Apache 2.0 license found in the LICENSE file.# ----------------------------------------------------------------------------importnumpyasnpimportsymforce.symbolicassffromsymforceimporttypingasTfromsymforce.opsimportStorageOpsfromsymforce.test_utilimportTestCaseifT.TYPE_CHECKING:_Base=TestCaseelse:_Base=object
[docs]classCamTestMixin(_Base):""" Test helper for camera objects. Inherit a test case from this. """# Small number to avoid singularitiesEPSILON=1e-8
[docs]@classmethoddefelement(cls)->T.Any:""" Overriden by child to provide an example of a camera or camera calibration object. """raiseNotImplementedError()
[docs]deftest_pixel_from_camera_point(self)->None:""" Tests: - pixel_from_camera_point """ifnotself.element().has_camera_ray_from_pixel():# TODO(aaron, dominic, brad): Back projection is not implemented for SphericalCameraCal# or PolynomialCameraCal.# NOTE(peter): Back projection is also not implemented for OrthographicCameraCal because# it is a non-central camera model.self.skipTest(f"camera_ray_from_pixel not implemented for {type(self.element())}.")# Check that we can project a point in 3D into the image and backfor_inrange(10):cam_cal=self.element()point=sf.V3(np.random.uniform(low=-1.0,high=1.0,size=(3,)))pixel,is_valid_forward_proj=cam_cal.pixel_from_camera_point(point)camera_ray,is_valid_back_proj=cam_cal.camera_ray_from_pixel(pixel)ifabs(StorageOps.evalf(is_valid_forward_proj)-1)<self.EPSILON:self.assertTrue(sf.Matrix.are_parallel(point,camera_ray,tolerance=self.EPSILON))self.assertStorageNear(is_valid_back_proj,1)else:self.assertStorageNear(is_valid_forward_proj,0)
[docs]deftest_camera_ray_from_pixel(self)->None:""" Tests: - camera_ray_from_pixel """ifnotself.element().has_camera_ray_from_pixel():# TODO(aaron, dominic, brad): Back projection is not implemented for SphericalCameraCal or# PolynomialCameraCal.self.skipTest(f"camera_ray_from_pixel not implemented for {type(self.element())}.")# Check that we can project a point in the image into 3D and backfor_inrange(10):cam_cal=self.element()# Try to generate pixels over a range that includes both valid and invalid pixel coordinatescx,cy=cam_cal.principal_pointpixel=sf.V2(np.random.uniform(low=-0.5*cx,high=2.5*cx),np.random.uniform(low=-0.5*cy,high=2.5*cy),)camera_ray,is_valid_back_proj=cam_cal.camera_ray_from_pixel(pixel)(pixel_reprojected,is_valid_forward_proj)=cam_cal.pixel_from_camera_point(camera_ray)ifabs(StorageOps.evalf(is_valid_back_proj)-1)<self.EPSILON:self.assertStorageNear(pixel,pixel_reprojected)self.assertStorageNear(is_valid_forward_proj,1)else:self.assertStorageNear(is_valid_back_proj,0)