85 f_scale = scale_focal / focal_px
88 X_img_plane = np.ones((4,5))
89 X_img_plane[0:3,0] = [-width, height, f_scale]
90 X_img_plane[0:3,1] = [width, height, f_scale]
91 X_img_plane[0:3,2] = [width, -height, f_scale]
92 X_img_plane[0:3,3] = [-width, -height, f_scale]
93 X_img_plane[0:3,4] = [-width, height, f_scale]
96 X_triangle = np.ones((4,3))
97 X_triangle[0:3,0] = [-width, -height, f_scale]
98 X_triangle[0:3,1] = [0, -2*height, f_scale]
99 X_triangle[0:3,2] = [width, -height, f_scale]
102 X_center1 = np.ones((4,2))
103 X_center1[0:3,0] = [0, 0, 0]
104 X_center1[0:3,1] = [-width, height, f_scale]
106 X_center2 = np.ones((4,2))
107 X_center2[0:3,0] = [0, 0, 0]
108 X_center2[0:3,1] = [width, height, f_scale]
110 X_center3 = np.ones((4,2))
111 X_center3[0:3,0] = [0, 0, 0]
112 X_center3[0:3,1] = [width, -height, f_scale]
114 X_center4 = np.ones((4,2))
115 X_center4[0:3,0] = [0, 0, 0]
116 X_center4[0:3,1] = [-width, -height, f_scale]
119 X_frame1 = np.ones((4,2))
120 X_frame1[0:3,0] = [0, 0, 0]
121 X_frame1[0:3,1] = [f_scale/2, 0, 0]
123 X_frame2 = np.ones((4,2))
124 X_frame2[0:3,0] = [0, 0, 0]
125 X_frame2[0:3,1] = [0, f_scale/2, 0]
127 X_frame3 = np.ones((4,2))
128 X_frame3[0:3,0] = [0, 0, 0]
129 X_frame3[0:3,1] = [0, 0, f_scale/2]
132 return [X_img_plane, X_triangle, X_center1, X_center2, X_center3, X_center4, X_frame1, X_frame2, X_frame3]
134 return [X_img_plane, X_triangle, X_center1, X_center2, X_center3, X_center4]
137 width = board_width*square_size
138 height = board_height*square_size
141 X_board = np.ones((4,5))
142 X_board[0:3,0] = [0,0,0]
143 X_board[0:3,1] = [width,0,0]
144 X_board[0:3,2] = [width,height,0]
145 X_board[0:3,3] = [0,height,0]
146 X_board[0:3,4] = [0,0,0]
149 X_frame1 = np.ones((4,2))
150 X_frame1[0:3,0] = [0, 0, 0]
151 X_frame1[0:3,1] = [height/2, 0, 0]
153 X_frame2 = np.ones((4,2))
154 X_frame2[0:3,0] = [0, 0, 0]
155 X_frame2[0:3,1] = [0, height/2, 0]
157 X_frame3 = np.ones((4,2))
158 X_frame3[0:3,0] = [0, 0, 0]
159 X_frame3[0:3,1] = [0, 0, height/2]
162 return [X_board, X_frame1, X_frame2, X_frame3]
166def draw(ax, cam_width, cam_height, focal_px, scale_focal,
167 extrinsics, board_width, board_height, square_size,
169 from matplotlib
import cm
171 min_values = np.zeros((3,1))
173 max_values = np.zeros((3,1))
177 X_static =
create_board_model(extrinsics, board_width, board_height, square_size,
True)
180 cm_subsection = linspace(0.0, 1.0, extrinsics.shape[0])
181 colors = [ cm.jet(x)
for x
in cm_subsection ]
183 patternCentric =
True
185 for i
in range(len(X_static)):
186 X = np.zeros(X_static[i].shape)
187 for j
in range(X_static[i].shape[1]):
189 ax.plot3D(X[0,:], X[1,:], X[2,:], color=
'r')
190 min_values = np.minimum(min_values, X[0:3,:].min(1))
191 max_values = np.maximum(max_values, X[0:3,:].max(1))
193 for idx
in range(extrinsics.shape[0]):
195 for i
in range(len(X_moving)):
196 X = np.zeros(X_moving[i].shape)
197 for j
in range(X_moving[i].shape[1]):
199 ax.plot3D(X[0,:], X[1,:], X[2,:], color=colors[idx])
200 min_values = np.minimum(min_values, X[0:3,:].min(1))
201 max_values = np.maximum(max_values, X[0:3,:].max(1))
204 oX = np.zeros((4,2), dtype=np.float64)
205 oY = np.zeros((4,2), dtype=np.float64)
206 oZ = np.zeros((4,2), dtype=np.float64)
207 ec = np.zeros((4,2), dtype=np.float64)
211 ax.plot3D(oX[0,:], oX[1,:], oX[2,:], color=
'r')
215 ax.plot3D(oY[0,:], oY[1,:], oY[2,:], color=
'g')
219 ax.plot3D(oZ[0,:], oZ[1,:], oZ[2,:], color=
'b')
223 ax.plot3D(ec[0,:], ec[1,:], ec[2,:], color=colors[idx])
225 return min_values, max_values
230 parser = argparse.ArgumentParser(description=
'Plot hand-eye calibration extrinsics.',
231 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
232 parser.add_argument(
'--ndata', type=int, required=
True,
233 help=
'Number of camera poses.')
234 parser.add_argument(
'--eMc-yaml', type=str, required=
True,
235 help=
'Path to the estimated eMc yaml file.')
236 parser.add_argument(
'--start-index', type=int, default=1,
238 parser.add_argument(
'--cPo-file-pattern', type=str, default=
'pose_cPo_%d.yaml',
239 help=
'cPo filename pattern for camera poses.')
240 parser.add_argument(
'--cam-width', type=float, default=0.064/2,
241 help=
'Width/2 of the displayed camera.')
242 parser.add_argument(
'--cam-height', type=float, default=0.048/2,
243 help=
'Height/2 of the displayed camera.')
244 parser.add_argument(
'--focal-px', type=float, default=600,
245 help=
'Camera focal length to draw the camera visualization.')
246 parser.add_argument(
'--scale-focal', type=float, default=40,
247 help=
'Value to scale the focal length.')
248 parser.add_argument(
'--board-width', type=int, default=9,
249 help=
'Calibration board width.')
250 parser.add_argument(
'--board-height', type=int, default=6,
251 help=
'Calibration board height.')
252 parser.add_argument(
'--square-size', type=float, default=0.025,
253 help=
'Calibration board square size.')
254 parser.add_argument(
'--frame-size', type=float, default=0.025,
255 help=
'End-effector frame size for visualization.')
256 args = parser.parse_args()
258 def load_yaml_pose(filename):
259 with open(filename)
as file:
260 pose_dict = yaml.load(file, Loader=yaml.FullLoader)
261 return np.array(pose_dict[
'data']).flatten()
263 camera_poses = np.empty((args.ndata, 6), dtype=np.float64)
264 for idx
in range(args.start_index, args.start_index + args.ndata):
265 camera_pose_filename = args.cPo_file_pattern % (idx)
266 camera_poses[idx-args.start_index,:] = load_yaml_pose(camera_pose_filename)
268 print(
'camera_poses:\n', camera_poses)
269 eMc = load_yaml_pose(args.eMc_yaml)
270 print(
'eMc:', eMc.transpose())
272 import matplotlib.pyplot
as plt
273 from mpl_toolkits.mplot3d
import Axes3D
277 ax = fig.add_subplot(projection=
'3d')
280 cam_width = args.cam_width
281 cam_height = args.cam_height
282 scale_focal = args.scale_focal
283 min_values, max_values =
draw(ax, cam_width, cam_height, args.focal_px,
284 scale_focal, camera_poses, args.board_width,
285 args.board_height, args.square_size,
288 X_min = min_values[0]
289 X_max = max_values[0]
290 Y_min = min_values[1]
291 Y_max = max_values[1]
292 Z_min = min_values[2]
293 Z_max = max_values[2]
294 max_range = np.array([X_max-X_min, Y_max-Y_min, Z_max-Z_min]).max() / 2.0
296 mid_x = (X_max+X_min) * 0.5
297 mid_y = (Y_max+Y_min) * 0.5
298 mid_z = (Z_max+Z_min) * 0.5
299 ax.set_xlim(mid_x - max_range, mid_x + max_range)
300 ax.set_ylim(mid_y - max_range, mid_y + max_range)
301 ax.set_zlim(mid_z - max_range, mid_z + max_range)
306 ax.set_title(
'Hand-Eye Calibration Visualization')