blob: 2f8a127bac0da135927c88b417ed1bc4059722fa [file] [log] [blame]
Jim Ostrowski007e2ea2022-01-30 13:13:26 -08001import copy
2import glog
3import json
4import math
5import numpy as np
6import os
7
8glog.setLevel("INFO")
9
10
11# Quick fix to naming games that happen with bazel
12def bazel_name_fix(filename):
13 ret_name = filename
14 try:
15 from bazel_tools.tools.python.runfiles import runfiles
16 r = runfiles.Create()
17 ret_name = r.Rlocation('org_frc971/y2022/vision/' + filename)
18 #print("Trying directory: ", ret_name)
19 except:
20 print("Failed bazel_name_fix")
21 pass
22
23 ### TODO<Jim>: Need to figure out why this isn't working
24 ### Hardcoding for now
25 if ret_name == None:
26 ret_name = '/home/jim/code/FRC/971-Robot-Code/y2022/vision/calib_files'
27 return ret_name
28
29
30class CameraIntrinsics:
Ravago Jones5127ccc2022-07-31 16:32:45 -070031
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080032 def __init__(self):
33 self.camera_matrix = []
34 self.dist_coeffs = []
35
36 pass
37
38
39class CameraExtrinsics:
Ravago Jones5127ccc2022-07-31 16:32:45 -070040
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080041 def __init__(self):
42 self.R = []
43 self.T = []
44
45
46class CameraParameters:
Ravago Jones5127ccc2022-07-31 16:32:45 -070047
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080048 def __init__(self):
49 self.camera_int = CameraIntrinsics()
50 self.camera_ext = CameraExtrinsics()
51 self.turret_ext = None
52 self.node_name = ""
53 self.team_number = -1
Jim Ostrowskifec0c332022-02-06 23:28:26 -080054 self.camera_id = ""
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080055 self.timestamp = 0
56
57
Milind Upadhyay958d4462022-12-26 20:33:14 -080058def compute_extrinsic(camera_roll, camera_pitch, camera_yaw, T_camera,
59 is_turret):
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080060 # Compute the extrinsic calibration based on pitch and translation
61 # Includes camera rotation from robot x,y,z to opencv (z, -x, -y)
62
63 # Also, handle extrinsics for the turret
64 # The basic camera pose is relative to the center, base of the turret
65 # TODO<Jim>: Maybe store these to .json files, like with intrinsics?
66 base_cam_ext = CameraExtrinsics()
67 turret_cam_ext = CameraExtrinsics()
68
Milind Upadhyay958d4462022-12-26 20:33:14 -080069 camera_roll_matrix = np.array(
70 [[1.0, 0.0, 0.0], [0.0, np.cos(camera_roll), -np.sin(camera_roll)],
71 [0.0, np.sin(camera_roll),
72 np.cos(camera_roll)]])
73
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080074 camera_pitch_matrix = np.array(
75 [[np.cos(camera_pitch), 0.0,
76 np.sin(camera_pitch)], [0.0, 1.0, 0.0],
77 [-np.sin(camera_pitch), 0.0,
78 np.cos(camera_pitch)]])
79
80 camera_yaw_matrix = np.array(
81 [[np.cos(camera_yaw), -np.sin(camera_yaw), 0.0],
82 [np.sin(camera_yaw), np.cos(camera_yaw), 0.0], [0.0, 0.0, 1.0]])
83
84 robot_to_camera_rotation = np.array([[0., 0., 1.], [-1, 0, 0], [0, -1.,
85 0]])
86
87 if is_turret:
James Kuszmaul3f3b1d92022-03-13 18:01:37 -070088 # Turret is just an identity matrix in the middle of the robot.
89 base_cam_ext.R = np.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0],
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080090 [0.0, 0.0, 1.0]])
91 base_cam_ext.T = np.array([0.0, 0.0, 0.0])
Milind Upadhyay958d4462022-12-26 20:33:14 -080092 turret_cam_ext.R = camera_yaw_matrix @ camera_pitch_matrix @ camera_roll_matrix @ robot_to_camera_rotation
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080093 turret_cam_ext.T = T_camera
94 else:
Milind Upadhyay958d4462022-12-26 20:33:14 -080095 base_cam_ext.R = camera_yaw_matrix @ camera_pitch_matrix @ camera_roll_matrix @ robot_to_camera_rotation
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080096 base_cam_ext.T = T_camera
97 turret_cam_ext = None
98
99 return base_cam_ext, turret_cam_ext
100
101
Milind Upadhyay37f6fe82022-04-14 23:00:44 -0700102def compute_extrinsic_by_pi(pi_number, team_number):
James Kuszmaul3f3b1d92022-03-13 18:01:37 -0700103 # Defaults for all cameras
Milind Upadhyay958d4462022-12-26 20:33:14 -0800104 camera_roll = 0.0
James Kuszmaul3f3b1d92022-03-13 18:01:37 -0700105 camera_pitch = -35.0 * np.pi / 180.0
Jim Ostrowski007e2ea2022-01-30 13:13:26 -0800106 camera_yaw = 0.0
James Kuszmaul3f3b1d92022-03-13 18:01:37 -0700107 is_turret = True
Jim Ostrowski007e2ea2022-01-30 13:13:26 -0800108 # Default camera location to robot origin
109 T = np.array([0.0, 0.0, 0.0])
110
Milind Upadhyay37f6fe82022-04-14 23:00:44 -0700111 if team_number == 971:
112 if pi_number == "pi1":
113 camera_yaw = 90.0 * np.pi / 180.0
114 T = np.array([-11.0 * 0.0254, 5.5 * 0.0254, 29.5 * 0.0254])
115 elif pi_number == "pi2":
116 camera_yaw = 0.0
117 T = np.array([-9.5 * 0.0254, -3.5 * 0.0254, 34.5 * 0.0254])
118 elif pi_number == "pi3":
Austin Schuhd84d4312022-11-07 09:04:48 -0800119 camera_yaw = 182.0 * np.pi / 180.0
Milind Upadhyay37f6fe82022-04-14 23:00:44 -0700120 T = np.array([-9.5 * 0.0254, 3.5 * 0.0254, 34.5 * 0.0254])
121 elif pi_number == "pi4":
122 camera_yaw = -90.0 * np.pi / 180.0
123 T = np.array([-10.25 * 0.0254, -5.0 * 0.0254, 27.5 * 0.0254])
124 elif team_number == 9971:
125 if pi_number == "pi1":
Austin Schuhd84d4312022-11-07 09:04:48 -0800126 camera_yaw = 179.0 * np.pi / 180.0
Milind Upadhyayce851342022-09-10 22:57:48 -0700127 T = np.array([-9.5 * 0.0254, 3.25 * 0.0254, 35.5 * 0.0254])
Milind Upadhyay37f6fe82022-04-14 23:00:44 -0700128 elif pi_number == "pi2":
129 camera_yaw = 0.0
Milind Upadhyayce851342022-09-10 22:57:48 -0700130 T = np.array([-9.0 * 0.0254, -3.25 * 0.0254, 35.5 * 0.0254])
Milind Upadhyay37f6fe82022-04-14 23:00:44 -0700131 elif pi_number == "pi3":
132 camera_yaw = 90.0 * np.pi / 180.0
Austin Schuhd84d4312022-11-07 09:04:48 -0800133 T = np.array([-10.5 * 0.0254, 5.0 * 0.0254, 29.5 * 0.0254])
Milind Upadhyayce851342022-09-10 22:57:48 -0700134 elif pi_number == "pi4":
135 camera_yaw = -90.0 * np.pi / 180.0
Austin Schuhd84d4312022-11-07 09:04:48 -0800136 T = np.array([-10.5 * 0.0254, -5.0 * 0.0254, 28.5 * 0.0254])
Milind Upadhyay958d4462022-12-26 20:33:14 -0800137 elif team_number == 7971:
138 # Cameras are flipped upside down
139 camera_roll = 180.0 * np.pi / 180.0
140 if pi_number == "pi1":
141 camera_yaw = 90.0 * np.pi / 180.0
142 T = np.array([-6.0 * 0.0254, -8.0 * 0.0254, 0.5 * 0.0254])
143 elif pi_number == "pi2":
144 camera_yaw = 0.0
145 T = np.array([3.75 * 0.0254, 7.5 * 0.0254, 0.5 * 0.0254])
146 elif pi_number == "pi3":
147 camera_yaw = 0.0
148 T = np.array([3.75 * 0.0254, -4.25 * 0.0254, 0.5 * 0.0254])
149 elif pi_number == "pi4":
150 camera_yaw = 0.0
151 T = np.array([-6.0 * 0.0254, -7.0 * 0.0254, 0.5 * 0.0254])
Milind Upadhyay37f6fe82022-04-14 23:00:44 -0700152 else:
153 glog.fatal("Unknown team number for extrinsics")
Jim Ostrowski007e2ea2022-01-30 13:13:26 -0800154
Milind Upadhyay958d4462022-12-26 20:33:14 -0800155 return compute_extrinsic(camera_roll, camera_pitch, camera_yaw, T,
156 is_turret)
Jim Ostrowski007e2ea2022-01-30 13:13:26 -0800157
158
159def load_camera_definitions():
160 ### CAMERA DEFINITIONS
161 # We only load in cameras that have a calibration file
162 # These are stored in y2022/vision/calib_files
163 #
164 # Or better yet, use //y2020/vision:calibration to calibrate the camera
165 # using a Charuco target board
166
167 camera_list = []
168
169 dir_name = bazel_name_fix('calib_files')
170 if dir_name is not None:
171 glog.debug("Searching for calibration files in " + dir_name)
172 else:
173 glog.fatal("Failed to find calib_files directory")
174
175 for filename in sorted(os.listdir(dir_name)):
176 glog.debug("Inspecting %s", filename)
177 if ("cam-calib-int" in filename
178 or 'calibration' in filename) and filename.endswith(".json"):
Jim Ostrowski007e2ea2022-01-30 13:13:26 -0800179 # Extract intrinsics from file
180 calib_file = open(dir_name + "/" + filename, 'r')
181 calib_dict = json.loads(calib_file.read())
182
183 team_number = calib_dict["team_number"]
184 node_name = calib_dict["node_name"]
Jim Ostrowskifec0c332022-02-06 23:28:26 -0800185 camera_id = "UNKNOWN"
186 if "camera_id" in calib_dict:
187 camera_id = calib_dict["camera_id"]
188
Jim Ostrowski007e2ea2022-01-30 13:13:26 -0800189 camera_matrix = np.asarray(calib_dict["intrinsics"]).reshape(
190 (3, 3))
191 dist_coeffs = np.asarray(calib_dict["dist_coeffs"]).reshape((1, 5))
192
193 glog.debug("Found calib for " + node_name + ", team #" +
194 str(team_number))
195
196 camera_params = CameraParameters()
197 # TODO: Need to add reading in extrinsic camera parameters from json
198 camera_params.camera_ext, camera_params.turret_ext = compute_extrinsic_by_pi(
Milind Upadhyay37f6fe82022-04-14 23:00:44 -0700199 node_name, team_number)
Jim Ostrowski007e2ea2022-01-30 13:13:26 -0800200
201 camera_params.node_name = node_name
202 camera_params.team_number = team_number
Jim Ostrowskifec0c332022-02-06 23:28:26 -0800203 camera_params.camera_id = camera_id
Jim Ostrowski007e2ea2022-01-30 13:13:26 -0800204 camera_params.camera_int.camera_matrix = copy.copy(camera_matrix)
205 camera_params.camera_int.dist_coeffs = copy.copy(dist_coeffs)
206 camera_list.append(camera_params)
207
208 return camera_list