blob: 1ef881df647304755360eb5fb6615121d296f86e [file] [log] [blame]
import copy
import cv2
import flatbuffers
import glog
import json
import numpy as np
import os
import sys
import frc971.vision.calibration.CalibrationData as CalibrationData
import frc971.vision.calibration.CameraCalibration as CameraCalibration
import frc971.vision.calibration.TransformationMatrix as TransformationMatrix
import glog
def bazel_name_fix(filename, year):
"""Quick fix to naming games that happen with bazel"""
ret_name = filename
try:
from bazel_tools.tools.python.runfiles import runfiles
r = runfiles.Create()
ret_name = r.Rlocation('org_frc971/y%s/vision/%s' % (year, filename))
except:
print("Failed bazel_name_fix")
pass
return ret_name
def list_to_transformation_matrix(values, fbb):
"""Puts a list of values into an FBB TransformationMatrix."""
TransformationMatrix.TransformationMatrixStartDataVector(fbb, len(values))
for n in reversed(values):
fbb.PrependFloat32(n)
list_offset = fbb.EndVector()
TransformationMatrix.TransformationMatrixStart(fbb)
TransformationMatrix.TransformationMatrixAddData(fbb, list_offset)
return TransformationMatrix.TransformationMatrixEnd(fbb)
def load_camera_definitions(year):
"""
CAMERA DEFINITIONS
We only load in cameras that have a calibration file
These are stored in y<year>/vision/calib_files
Or better yet, use //y2020/vision:calibration to calibrate the camera
using a Charuco target board
"""
dir_name = bazel_name_fix("calib_files", year)
if dir_name is not None:
glog.debug("Searching for calibration files in " + dir_name)
else:
glog.fatal("Failed to find calib_files directory")
camera_calib_list = []
for filename in sorted(os.listdir(dir_name)):
glog.debug("Inspecting %s", filename)
if ("cam-calib-int" in filename
or 'calibration' in filename) and filename.endswith(".json"):
# Extract intrinsics from file
calib_file = open(dir_name + "/" + filename, 'r')
calib_dict = json.loads(calib_file.read())
camera_calib_list.append(calib_dict)
return camera_calib_list
def generate_header(year):
"""
Generates a header file with a CalibrationData() function
returning the data as a binary flatbuffer.
Expects command line argument: output header path
Parameter year is a string, ex. "2023"
"""
camera_calib_list = load_camera_definitions(year)
output_path = sys.argv[1]
glog.debug("Writing file to %s", output_path)
fbb = flatbuffers.Builder(0)
images_vector = []
# Create camera calibration data
camera_calibration_vector = []
for camera_calib in camera_calib_list:
fixed_extrinsics_list = camera_calib["fixed_extrinsics"]
fixed_extrinsics_vector = list_to_transformation_matrix(
fixed_extrinsics_list, fbb)
turret_extrinsics_vector = None
if "turret_extrinsics" in camera_calib:
turret_extrinsics_list = camera_calib["turret_extrinsics"]
turret_extrinsics_vector = list_to_transformation_matrix(
turret_extrinsics_list, fbb)
camera_int_list = camera_calib["intrinsics"]
CameraCalibration.CameraCalibrationStartIntrinsicsVector(
fbb, len(camera_int_list))
for n in reversed(camera_int_list):
fbb.PrependFloat32(n)
intrinsics_vector = fbb.EndVector()
dist_coeffs_list = camera_calib["dist_coeffs"]
CameraCalibration.CameraCalibrationStartDistCoeffsVector(
fbb, len(dist_coeffs_list))
for n in reversed(dist_coeffs_list):
fbb.PrependFloat32(n)
dist_coeffs_vector = fbb.EndVector()
node_name_offset = fbb.CreateString(camera_calib["node_name"])
CameraCalibration.CameraCalibrationStart(fbb)
CameraCalibration.CameraCalibrationAddNodeName(fbb, node_name_offset)
CameraCalibration.CameraCalibrationAddTeamNumber(
fbb, camera_calib["team_number"])
CameraCalibration.CameraCalibrationAddIntrinsics(
fbb, intrinsics_vector)
CameraCalibration.CameraCalibrationAddDistCoeffs(
fbb, dist_coeffs_vector)
CameraCalibration.CameraCalibrationAddFixedExtrinsics(
fbb, fixed_extrinsics_vector)
if turret_extrinsics_vector is not None:
CameraCalibration.CameraCalibrationAddTurretExtrinsics(
fbb, turret_extrinsics_vector)
camera_calibration_vector.append(
CameraCalibration.CameraCalibrationEnd(fbb))
CalibrationData.CalibrationDataStartCameraCalibrationsVector(
fbb, len(camera_calibration_vector))
for camera_calibration in reversed(camera_calibration_vector):
fbb.PrependUOffsetTRelative(camera_calibration)
camera_calibration_vector_table = fbb.EndVector()
# Fill out TrainingData
CalibrationData.CalibrationDataStart(fbb)
CalibrationData.CalibrationDataAddCameraCalibrations(
fbb, camera_calibration_vector_table)
fbb.Finish(CalibrationData.CalibrationDataEnd(fbb))
bfbs = fbb.Output()
# "year" will get replaced by the variable
output_prefix = [
'#ifndef Y{year}_VISION_CALIBRATION_DATA_H_',
'#define Y{year}_VISION_CALIBRATION_DATA_H_',
'#include <stdint.h>',
'#include "absl/types/span.h"',
'namespace y{year} {{',
'namespace vision {{',
'inline absl::Span<const uint8_t> CalibrationData() {{',
]
output_suffix = [
' return absl::Span<const uint8_t>(reinterpret_cast<const uint8_t *>(kData), sizeof(kData));',
'}}',
'}} // namespace vision',
'}} // namespace y{year}',
'#endif // Y{year}_VISION_CALIBRATION_DATA_H_',
]
# Write out the header file
with open(output_path, 'wb') as output:
for line in output_prefix:
output.write(line.format(year=year).encode("utf-8"))
output.write(b'\n')
output.write(b'alignas(64) static constexpr char kData[] = "')
for byte in fbb.Output():
output.write(b'\\x' + (b'%x' % byte).zfill(2))
output.write(b'";\n')
for line in output_suffix:
output.write(line.format(year=year).encode("utf-8"))
output.write(b'\n')