diff options
Diffstat (limited to 'src/argaze/ArUcoMarkers/ArUcoOpticCalibrator.py')
-rw-r--r-- | src/argaze/ArUcoMarkers/ArUcoOpticCalibrator.py | 163 |
1 files changed, 85 insertions, 78 deletions
diff --git a/src/argaze/ArUcoMarkers/ArUcoOpticCalibrator.py b/src/argaze/ArUcoMarkers/ArUcoOpticCalibrator.py index 4fd1bd6..12cbc54 100644 --- a/src/argaze/ArUcoMarkers/ArUcoOpticCalibrator.py +++ b/src/argaze/ArUcoMarkers/ArUcoOpticCalibrator.py @@ -25,129 +25,136 @@ import numpy import cv2 import cv2.aruco as aruco + def K0(focal_length: tuple, width: int, height: int) -> numpy.array: - """Define default optic intrinsic parameters matrix. + """Define default optic intrinsic parameters' matrix. Parameters: + focal_length: width: in pixel. height: in pixel. """ - return numpy.array([[focal_length[0], 0., width/2], [0., focal_length[1], height/2], [0., 0., 1.]]) + return numpy.array([[focal_length[0], 0., width / 2], [0., focal_length[1], height / 2], [0., 0., 1.]]) + D0 = numpy.array([0.0, 0.0, 0.0, 0.0, 0.0]) -"""Define default optic distorsion coefficients vector.""" +"""Define default optic distortion coefficients vector.""" + @dataclass class OpticParameters(): - """Define optic parameters outputed by optic calibrator.""" + """Define optic parameters output by optic calibrator.""" - rms: float = field(default=0) - """Root Mean Square error of calibration.""" + rms: float = field(default=0) + """Root Mean Square error of calibration.""" - dimensions: numpy.array = field(default_factory=lambda : numpy.array([0, 0])) - """Image dimensions in pixels from which the calibration have been done.""" + dimensions: numpy.array = field(default_factory=lambda: numpy.array([0, 0])) + """Image dimensions in pixels from which the calibration have been done.""" - K: numpy.array = field(default_factory=lambda : K0((0, 0), 0, 0)) - """Intrinsic parameters matrix (focal lengths and principal point).""" + K: numpy.array = field(default_factory=lambda: K0((0, 0), 0, 0)) + """Intrinsic parameters matrix (focal lengths and principal point).""" - D: numpy.array = field(default_factory=lambda : D0) - """Distorsion coefficients vector.""" + D: numpy.array = field(default_factory=lambda: D0) + """Distortion coefficients vector.""" - @classmethod - def from_json(self, json_filepath): - """Load optical parameters from .json file.""" + @classmethod + def from_json(cls, json_filepath): + """Load optical parameters from .json file.""" - with open(json_filepath) as calibration_file: + with open(json_filepath) as calibration_file: + return OpticParameters(**json.load(calibration_file)) - return OpticParameters(**json.load(calibration_file)) + def to_json(self, json_filepath): + """Save optical parameters into .json file.""" - def to_json(self, json_filepath): - """Save optical parameters into .json file.""" + with open(json_filepath, 'w', encoding='utf-8') as calibration_file: + json.dump(self, calibration_file, ensure_ascii=False, indent=4, cls=DataFeatures.JsonEncoder) - with open(json_filepath, 'w', encoding='utf-8') as calibration_file: + def __str__(self) -> str: + """String display""" - json.dump(self, calibration_file, ensure_ascii=False, indent=4, cls=DataFeatures.JsonEncoder) + output = f'\trms: {self.rms}\n' + output += f'\tdimensions: {self.dimensions}\n' + output += f'\tK: {self.K}\n' + output += f'\tD: {self.D}\n' - def __str__(self) -> str: - """String display""" + return output - output = f'\trms: {self.rms}\n' - output += f'\tdimensions: {self.dimensions}\n' - output += f'\tK: {self.K}\n' - output += f'\tD: {self.D}\n' + def draw(self, image: numpy.array, width: float = 0., height: float = 0., z: float = 0., point_size: int = 1, + point_color: tuple = (0, 0, 0)): + """Draw grid to display K and D""" - return output + if width * height > 0.: - def draw(self, image: numpy.array, width: float = 0., height:float = 0., z: float = 0., point_size: int = 1, point_color: tuple = (0, 0, 0)): - """Draw grid to display K and D""" + # Edit 3D grid + grid_3D = [] + for x in range(-int(width / 2), int(width / 2)): + for y in range(-int(height / 2), int(height / 2)): + grid_3D.append([x, y, z]) - if width * height > 0.: + # Project 3d grid + grid_2D, _ = cv2.projectPoints(numpy.array(grid_3D).astype(float), numpy.array([0., 0., 0.]), + numpy.array([0., 0., 0.]), numpy.array(self.K), -numpy.array(self.D)) - # Edit 3D grid - grid_3D = [] - for x in range(-int(width/2), int(width/2)): - for y in range(-int(height/2), int(height/2)): - grid_3D.append([x, y, z]) + # Draw projection + for point in grid_2D: - # Project 3d grid - grid_2D, _ = cv2.projectPoints(numpy.array(grid_3D).astype(float), numpy.array([0., 0., 0.]), numpy.array([0., 0., 0.]), numpy.array(self.K), -numpy.array(self.D)) + # Ignore point out field + try: - # Draw projection - for point in grid_2D: + cv2.circle(image, point.astype(int)[0], point_size, point_color, -1) - # Ignore point out out field - try: + except: - cv2.circle(image, point.astype(int)[0], point_size, point_color, -1) + pass - except: - - pass class ArUcoOpticCalibrator(): - """Handle optic calibration process.""" - - def __init__(self,): - - # Calibration data - self.__corners_set_number = 0 - self.__corners_set = [] - self.__corners_set_ids = [] + """Handle optic calibration process.""" - def calibrate(self, board, dimensions:tuple = (0, 0)) -> OpticParameters: - """Retrieve K and D parameters from stored calibration data. + def __init__(self, ): + # Calibration data + self.__corners_set_number = 0 + self.__corners_set = [] + self.__corners_set_ids = [] - Parameters: - dimensions: camera image dimensions + def calibrate(self, board, dimensions=None) -> OpticParameters: + """Retrieve K and D parameters from stored calibration data. - Returns: - Optic parameters - """ + Parameters: + board: + dimensions: camera image dimensions - if self.__corners_set_number > 0: + Returns: + Optic parameters + """ - rms, K, D, r, t = aruco.calibrateCameraCharuco(self.__corners_set, self.__corners_set_ids, board.model, dimensions, None, None) + if dimensions is None: + dimensions = [0, 0] - return OpticParameters(rms, dimensions, K, D) + if self.__corners_set_number > 0: + rms, K, D, r, t = aruco.calibrateCameraCharuco(self.__corners_set, self.__corners_set_ids, board.model, + dimensions, None, None) - def reset_calibration_data(self): - """Clear all calibration data.""" + return OpticParameters(rms, dimensions, K, D) - self.__corners_set_number = 0 - self.__corners_set = [] - self.__corners_set_ids = [] + def reset_calibration_data(self): + """Clear all calibration data.""" - def store_calibration_data(self, corners, corners_identifiers): - """Store calibration data.""" + self.__corners_set_number = 0 + self.__corners_set = [] + self.__corners_set_ids = [] - self.__corners_set_number += 1 - self.__corners_set.append(corners) - self.__corners_set_ids.append(corners_identifiers) + def store_calibration_data(self, corners, corners_identifiers): + """Store calibration data.""" - @property - def calibration_data_count(self) -> int: - """Get how much calibration data are stored.""" + self.__corners_set_number += 1 + self.__corners_set.append(corners) + self.__corners_set_ids.append(corners_identifiers) - return self.__corners_set_number + @property + def calibration_data_count(self) -> int: + """Get how much calibration data are stored.""" + return self.__corners_set_number |