def is_valid_calibration(filename: Path) -> bool: if not filename.is_file(): return False # First, Try and parse the file try: parse_calibration_file(filename) except (SystemError, ValueError): return False with tempfile.NamedTemporaryFile(suffix=".png") as temp_file: marker_camera = MarkerCamera(0, 200, marker_type=MarkerType.APRILTAG_36H11) marker_camera.save_frame(Path(temp_file.name)) image_camera = ImageFileCamera( Path(temp_file.name), marker_size=200, marker_type=MarkerType.APRILTAG_36H11, calibration_file=filename, ) # Sanity check the image camera if image_camera.get_visible_markers() != [0]: return False # Then, confirm the detection works if len(list(marker_camera.process_frame_eager())) != 1: return False return True
def test_saving_calibrations(extension, make_temp_file): original_params = get_fake_calibration_parameters(200) calibrations_file = Path(make_temp_file("." + extension)) save_calibrations(original_params, calibrations_file) read_params = parse_calibration_file(calibrations_file) assert read_params[0].tolist() == original_params[0].tolist() assert read_params[1].tolist() == original_params[1].tolist()
def test_different_resolution_to_calibration( mocker: MockerFixture, fixtures_dir: Path ) -> None: VideoCapture = mocker.patch("zoloto.cameras.camera.VideoCapture") VideoCapture.return_value.get.side_effect = [1920, 1080] calibration_file = fixtures_dir / "example-calibreation-params.xml" calibrations = parse_calibration_file(calibration_file) assert calibrations.resolution == (1280, 720) with pytest.raises(ValueError): zoloto.cameras.Camera( 0, marker_type=MarkerType.ARUCO_6X6, calibration_file=calibration_file )
def __init__( self, *, marker_size: Optional[int] = None, marker_type: MarkerType, calibration_file: Optional[Path] = None ) -> None: self.marker_type = marker_type self.marker_dictionary = cv2.aruco.getPredefinedDictionary(self.marker_type) self._marker_size = marker_size self.detector_params = self.get_detector_params() self.calibration_params = None if calibration_file is not None: self.calibration_params = parse_calibration_file(calibration_file)
def test_loading_example(fixtures_dir: Path) -> None: calibrations = parse_calibration_file(fixtures_dir / "example-calibreation-params.xml") assert calibrations.camera_matrix.tolist() == [ [1.2519588293098975e03, 0, 6.6684948780852471e02], [0, 1.2519588293098975e03, 3.6298123112613683e02], [0, 0, 1], ] assert calibrations.distance_coefficients.tolist() == [[ 1.3569117181595716e-01, -8.2513063822554633e-01, 0, 0, 1.6412101575010554e00, ]] assert calibrations.resolution == (1280, 720)
def test_override_camera_resolution_from_calibration( mocker: MockerFixture, fixtures_dir: Path ) -> None: calibration_file = fixtures_dir / "example-calibreation-params.xml" calibrations = parse_calibration_file(calibration_file) assert calibrations.resolution == (1280, 720) VideoCapture = mocker.patch("zoloto.cameras.camera.VideoCapture") VideoCapture.return_value.get.side_effect = [1920, 1080, 1920, 1080, 1280, 720] with warnings.catch_warnings(record=True) as w: zoloto.cameras.Camera( 0, marker_type=MarkerType.ARUCO_6X6, calibration_file=calibration_file, resolution=(1920, 1080), ) assert len(w) == 1 assert "Overriding camera resolution with calibrated resolution" in str( w[0].message ) VideoCapture.return_value.set.assert_any_call(CAP_PROP_FRAME_WIDTH, 1920) VideoCapture.return_value.set.assert_any_call(CAP_PROP_FRAME_HEIGHT, 1080)
def test_loading_missing_file(extension): filename = Path("doesnt-exist." + extension) with pytest.raises(FileNotFoundError): parse_calibration_file(filename)
def test_cant_load_invalid_extension(make_temp_file): with pytest.raises(ValueError) as e: parse_calibration_file(Path(make_temp_file(".unknown"))) assert "Unknown calibration file format" in e.value.args[0]
def test_loading_missing_file() -> None: filename = Path("doesnt-exist.xml") assert not filename.exists() with pytest.raises(FileNotFoundError): parse_calibration_file(filename)
def get_calibrations(self): if self.calibration_file is None: return None return parse_calibration_file(self.calibration_file)
def get_calibrations(self) -> Optional[CalibrationParameters]: if self.calibration_file is None: return None return parse_calibration_file(self.calibration_file)