22
33from __future__ import annotations
44
5- from typing import Optional , TypedDict
5+ from abc import ABC , abstractmethod
6+ from typing import List , Optional , Tuple , TypedDict , Union
67
78import numpy as np
89
@@ -26,3 +27,128 @@ class CalibrationResults(TypedDict):
2627 R_handeye : Optional [np .ndarray ]
2728 T_handeye : Optional [np .ndarray ]
2829 average_reprojection_error : float
30+
31+
32+ class AutomaticCameraCalibrationRobot (ABC ):
33+ @abstractmethod
34+ def capture_images (self ) -> Union [List , np .ndarray ]:
35+ """
36+ Capture images from the cameras you wish to calibrate at the same moment in time
37+ (time-synchronized). Then, construct either a list or a NumPy array
38+ of these images. This will be called every time that your robot reaches a new
39+ calibration viewpoint, so ensure that image order to camera correlation is consistent
40+ across all calls. Also, it is important to ensure that the photos are as time-synchronized
41+ as possible, with as little motion blur as possible.
42+
43+ Returns:
44+ Union[List, np.ndarray]: The time-synchronized images from all relevant cameras.
45+ """
46+ pass
47+
48+ @abstractmethod
49+ def localize_target_to_principal_camera (self , images : Union [List , np .ndarray ]) -> Tuple [np .ndarray , np .ndarray ]:
50+ """
51+ Localize the charuco board relative to what is considered
52+ the principal camera for the calibration. This could be done
53+ either visually, or via kinematics and fixing the board relative
54+ to the robot. Visually is more flexible, although this
55+ implies some knowledge of the principal cameras intrinsics.
56+
57+ In this case, principal camera could be an actual camera, or could also be a "virtual"
58+ camera. The principal camera's frame is just what frame is used to sample viewpoints in.
59+
60+ The board pose's translation should be at the center of the board, with the orientation
61+ in OpenCV format, where the +Z points out of the board with
62+ the other axis being parallel to the sides of the board.
63+
64+ Your camera pose should be in OpenCV/ROS convention, where
65+ # +x should point to the right in the image
66+ # +y should point down in the image
67+ # +z should point into to plane of the image
68+
69+ If you'd like to do this through visual localization, you can use
70+
71+ def est_camera_t_charuco_board_center(
72+ img: np.ndarray,
73+ charuco_board: cv2.aruco_CharucoBoard,
74+ aruco_dict: cv2.aruco_Dictionary,
75+ camera_matrix: np.ndarray,
76+ dist_coeffs: np.ndarray,
77+ )
78+ from calibration_util.py
79+
80+ Args:
81+ images (Union[List, np.ndarray]): the images that could be used to determine
82+ how far the target is from the "principal" camera
83+
84+ Returns:
85+ Tuple[np.ndarray, np.ndarray]: _description_
86+ """
87+ pass
88+
89+ @abstractmethod
90+ def move_cameras_to_see_calibration_target (self ) -> np .ndarray :
91+ """
92+ This is a robot specific sequence to start the calibration. This
93+ could be as simple as a heuristic to move the robot to a known pose where
94+ it is generally looking at the checkerboard, or this could be a more sophisticated
95+ sequence to look around in the scene until a board is found
96+ (for example, grabbing images with self.capture_images(),
97+ and checking if a board is found with detect_charuco_corners from calibration_util.py)
98+
99+ Returns:
100+ np.ndarray: the 4x4 homogenous transform of the starting pose where the calibration
101+ board is visible.
102+ """
103+ pass
104+
105+ @abstractmethod
106+ def offset_cameras_from_current_view (
107+ self ,
108+ transform_offset : np .ndarray ,
109+ origin_t_planning_frame : Optional [np .ndarray ] = None ,
110+ duration_sec : float = 1.0 ,
111+ ) -> Tuple [np .ndarray , np .ndarray ]:
112+ """
113+ Move the robot to a desired position, such that the cameras move by transform_offset.
114+ This is how the robot visits desired viewpoints.
115+
116+ IMPORTANT: You likely have to convert transform_offset from the "principal"
117+ camera frame into the planning frame (if the camera frame isn't the planning frame).
118+ This can be done by calling
119+
120+ convert_camera_t_viewpoint_to_origin_t_planning_frame(
121+ origin_t_planning_frame=origin_t_planning_frame,
122+ planning_frame_t_opencv_camera=HOMOGENOUS_TRANSFORM_FROM_PLANNING_FRAME_TO_OPENCV_CAM,
123+ opencv_camera_t_viewpoint=transform_offset,
124+ )
125+ from calibration_util.py
126+
127+ Your camera pose should be in OpenCV/ROS convention, where
128+ +x should point to the right in the image
129+ +y should point down in the image
130+ +z should point into to plane of the image
131+
132+ Args:
133+ transform_offset (np.ndarray): the 4x4 homogenous transform of
134+ how far you'd like to shift your cameras
135+ origin_t_planning_frame (Optional[np.ndarray], optional): the 4x4 homogenous
136+ transform of your robot origin to planning frame. Could be hard-coded
137+ or read off of the robot. Defaults to None.
138+ duration_sec (float, optional): How many seconds provided to execute
139+ the move. Defaults to 1.0.
140+
141+ Returns:
142+ Tuple[np.ndarray, np.ndarray]: the 4x4 homogenous transform of origin_t_planning_frame
143+ before the move, and the 4x4 homogenous transform of origin_t_planning_frame
144+ after the move.
145+ """
146+ pass
147+
148+ @abstractmethod
149+ def shutdown (self ) -> None :
150+ """
151+ Cleanup the robot connection, and disconnect so that other programs can resume
152+ control of the robot while this program continues to solve the calibration parameters.
153+ """
154+ pass
0 commit comments