blob: 1ef881df647304755360eb5fb6615121d296f86e [file] [log] [blame]
milind-u959d6bd2023-01-21 12:32:52 -08001import copy
2import cv2
3import flatbuffers
4import glog
5import json
6import numpy as np
7import os
8import sys
9
10import frc971.vision.calibration.CalibrationData as CalibrationData
11import frc971.vision.calibration.CameraCalibration as CameraCalibration
12import frc971.vision.calibration.TransformationMatrix as TransformationMatrix
13
14import glog
15
16
17def bazel_name_fix(filename, year):
18 """Quick fix to naming games that happen with bazel"""
19 ret_name = filename
20 try:
21 from bazel_tools.tools.python.runfiles import runfiles
22 r = runfiles.Create()
23 ret_name = r.Rlocation('org_frc971/y%s/vision/%s' % (year, filename))
24 except:
25 print("Failed bazel_name_fix")
26 pass
27
28 return ret_name
29
30
31def list_to_transformation_matrix(values, fbb):
32 """Puts a list of values into an FBB TransformationMatrix."""
33
34 TransformationMatrix.TransformationMatrixStartDataVector(fbb, len(values))
35 for n in reversed(values):
36 fbb.PrependFloat32(n)
37 list_offset = fbb.EndVector()
38
39 TransformationMatrix.TransformationMatrixStart(fbb)
40 TransformationMatrix.TransformationMatrixAddData(fbb, list_offset)
41 return TransformationMatrix.TransformationMatrixEnd(fbb)
42
43
44def load_camera_definitions(year):
45 """
46 CAMERA DEFINITIONS
47 We only load in cameras that have a calibration file
48 These are stored in y<year>/vision/calib_files
49
50 Or better yet, use //y2020/vision:calibration to calibrate the camera
51 using a Charuco target board
52 """
53
54 dir_name = bazel_name_fix("calib_files", year)
55 if dir_name is not None:
56 glog.debug("Searching for calibration files in " + dir_name)
57 else:
58 glog.fatal("Failed to find calib_files directory")
59
60 camera_calib_list = []
61 for filename in sorted(os.listdir(dir_name)):
62 glog.debug("Inspecting %s", filename)
63 if ("cam-calib-int" in filename
64 or 'calibration' in filename) and filename.endswith(".json"):
65 # Extract intrinsics from file
66 calib_file = open(dir_name + "/" + filename, 'r')
67 calib_dict = json.loads(calib_file.read())
68 camera_calib_list.append(calib_dict)
69 return camera_calib_list
70
71
72def generate_header(year):
73 """
74 Generates a header file with a CalibrationData() function
75 returning the data as a binary flatbuffer.
76 Expects command line argument: output header path
77 Parameter year is a string, ex. "2023"
78 """
79 camera_calib_list = load_camera_definitions(year)
80
81 output_path = sys.argv[1]
82 glog.debug("Writing file to %s", output_path)
83
84 fbb = flatbuffers.Builder(0)
85
86 images_vector = []
87
88 # Create camera calibration data
89 camera_calibration_vector = []
90 for camera_calib in camera_calib_list:
91 fixed_extrinsics_list = camera_calib["fixed_extrinsics"]
92 fixed_extrinsics_vector = list_to_transformation_matrix(
93 fixed_extrinsics_list, fbb)
94
95 turret_extrinsics_vector = None
96 if "turret_extrinsics" in camera_calib:
97 turret_extrinsics_list = camera_calib["turret_extrinsics"]
98 turret_extrinsics_vector = list_to_transformation_matrix(
99 turret_extrinsics_list, fbb)
100
101 camera_int_list = camera_calib["intrinsics"]
102 CameraCalibration.CameraCalibrationStartIntrinsicsVector(
103 fbb, len(camera_int_list))
104 for n in reversed(camera_int_list):
105 fbb.PrependFloat32(n)
106 intrinsics_vector = fbb.EndVector()
107
108 dist_coeffs_list = camera_calib["dist_coeffs"]
109 CameraCalibration.CameraCalibrationStartDistCoeffsVector(
110 fbb, len(dist_coeffs_list))
111 for n in reversed(dist_coeffs_list):
112 fbb.PrependFloat32(n)
113 dist_coeffs_vector = fbb.EndVector()
114
115 node_name_offset = fbb.CreateString(camera_calib["node_name"])
116 CameraCalibration.CameraCalibrationStart(fbb)
117 CameraCalibration.CameraCalibrationAddNodeName(fbb, node_name_offset)
118 CameraCalibration.CameraCalibrationAddTeamNumber(
119 fbb, camera_calib["team_number"])
120 CameraCalibration.CameraCalibrationAddIntrinsics(
121 fbb, intrinsics_vector)
122 CameraCalibration.CameraCalibrationAddDistCoeffs(
123 fbb, dist_coeffs_vector)
124 CameraCalibration.CameraCalibrationAddFixedExtrinsics(
125 fbb, fixed_extrinsics_vector)
126 if turret_extrinsics_vector is not None:
127 CameraCalibration.CameraCalibrationAddTurretExtrinsics(
128 fbb, turret_extrinsics_vector)
129 camera_calibration_vector.append(
130 CameraCalibration.CameraCalibrationEnd(fbb))
131
132 CalibrationData.CalibrationDataStartCameraCalibrationsVector(
133 fbb, len(camera_calibration_vector))
134 for camera_calibration in reversed(camera_calibration_vector):
135 fbb.PrependUOffsetTRelative(camera_calibration)
136 camera_calibration_vector_table = fbb.EndVector()
137
138 # Fill out TrainingData
139 CalibrationData.CalibrationDataStart(fbb)
140 CalibrationData.CalibrationDataAddCameraCalibrations(
141 fbb, camera_calibration_vector_table)
142 fbb.Finish(CalibrationData.CalibrationDataEnd(fbb))
143
144 bfbs = fbb.Output()
145
146 # "year" will get replaced by the variable
147 output_prefix = [
148 '#ifndef Y{year}_VISION_CALIBRATION_DATA_H_',
149 '#define Y{year}_VISION_CALIBRATION_DATA_H_',
150 '#include <stdint.h>',
151 '#include "absl/types/span.h"',
152 'namespace y{year} {{',
153 'namespace vision {{',
154 'inline absl::Span<const uint8_t> CalibrationData() {{',
155 ]
156 output_suffix = [
157 ' return absl::Span<const uint8_t>(reinterpret_cast<const uint8_t *>(kData), sizeof(kData));',
158 '}}',
159 '}} // namespace vision',
160 '}} // namespace y{year}',
161 '#endif // Y{year}_VISION_CALIBRATION_DATA_H_',
162 ]
163
164 # Write out the header file
165 with open(output_path, 'wb') as output:
166 for line in output_prefix:
167 output.write(line.format(year=year).encode("utf-8"))
168 output.write(b'\n')
169 output.write(b'alignas(64) static constexpr char kData[] = "')
170 for byte in fbb.Output():
171 output.write(b'\\x' + (b'%x' % byte).zfill(2))
172 output.write(b'";\n')
173 for line in output_suffix:
174 output.write(line.format(year=year).encode("utf-8"))
175 output.write(b'\n')