aboutsummaryrefslogtreecommitdiff
path: root/src/argaze/ArUcoMarkers/ArUcoOpticCalibrator.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/argaze/ArUcoMarkers/ArUcoOpticCalibrator.py')
-rw-r--r--src/argaze/ArUcoMarkers/ArUcoOpticCalibrator.py163
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