t/file: Extend calibration save/load interfaces with new v2 format

This commit is contained in:
Mateo de Mayo 2021-11-23 17:19:53 -03:00
parent 1483ec32c5
commit 07bd614930
6 changed files with 155 additions and 57 deletions

View file

@ -1,8 +1,7 @@
{ {
"$schema": "https://monado.pages.freedesktop.org/monado/calibration_v2.schema.json", "$schema": "https://monado.pages.freedesktop.org/monado/calibration_v2.schema.json",
"file": { "metadata": {
"version": 2, "version": 2
"created_on": "2021-11-23T14:33:51Z"
}, },
"cameras": [ "cameras": [
{ {

View file

@ -3,7 +3,7 @@
"title": "Monado calibration file schema v2", "title": "Monado calibration file schema v2",
"type": "object", "type": "object",
"required": [ "required": [
"file", "metadata",
"cameras", "cameras",
"opencv_stereo_calibrate" "opencv_stereo_calibrate"
], ],
@ -13,7 +13,7 @@
"title": "JSON Schema directive", "title": "JSON Schema directive",
"default": "https://monado.pages.freedesktop.org/monado/calibration_v2.schema.json" "default": "https://monado.pages.freedesktop.org/monado/calibration_v2.schema.json"
}, },
"file": { "metadata": {
"description": "Calibration file metadata", "description": "Calibration file metadata",
"type": "object", "type": "object",
"required": [ "required": [
@ -22,9 +22,6 @@
"properties": { "properties": {
"version": { "version": {
"const": 2 "const": 2
},
"created_on": {
"$ref": "#/$defs/datetime"
} }
} }
}, },
@ -211,12 +208,6 @@
"type": "number" "type": "number"
} }
} }
},
"datetime": {
"$comment": "The format specification might not be asserted against, that's why we also provide a regex pattern",
"type": "string",
"format": "date-time",
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$"
} }
} }
} }

View file

@ -16,7 +16,7 @@
#include "os/os_time.h" #include "os/os_time.h"
DEBUG_GET_ONCE_LOG_OPTION(calib_log, "CALIB_LOG", U_LOGGING_WARN) DEBUG_GET_ONCE_LOG_OPTION(calib_log, "CALIB_LOG", U_LOGGING_INFO)
#define CALIB_TRACE(...) U_LOG_IFL_T(debug_get_log_option_calib_log(), __VA_ARGS__) #define CALIB_TRACE(...) U_LOG_IFL_T(debug_get_log_option_calib_log(), __VA_ARGS__)
#define CALIB_DEBUG(...) U_LOG_IFL_D(debug_get_log_option_calib_log(), __VA_ARGS__) #define CALIB_DEBUG(...) U_LOG_IFL_D(debug_get_log_option_calib_log(), __VA_ARGS__)
@ -212,7 +212,7 @@ using xrt::auxiliary::util::json::JSONNode;
extern "C" bool extern "C" bool
t_stereo_camera_calibration_load_v1(FILE *calib_file, struct t_stereo_camera_calibration **out_data) t_stereo_camera_calibration_load_v1(FILE *calib_file, struct t_stereo_camera_calibration **out_data)
{ {
using xrt::auxiliary::tracking::StereoCameraCalibrationWrapper;
t_stereo_camera_calibration *data_ptr = NULL; t_stereo_camera_calibration *data_ptr = NULL;
t_stereo_camera_calibration_alloc(&data_ptr, 5); // Hardcoded to 5 distortion parameters. t_stereo_camera_calibration_alloc(&data_ptr, 5); // Hardcoded to 5 distortion parameters.
StereoCameraCalibrationWrapper wrapped(data_ptr); StereoCameraCalibrationWrapper wrapped(data_ptr);
@ -274,7 +274,6 @@ t_stereo_camera_calibration_load_v1(FILE *calib_file, struct t_stereo_camera_cal
wrapped.view[1].use_fisheye = wrapped.view[0].use_fisheye; wrapped.view[1].use_fisheye = wrapped.view[0].use_fisheye;
// clang-format on // clang-format on
CALIB_ASSERT_(wrapped.isDataStorageValid()); CALIB_ASSERT_(wrapped.isDataStorageValid());
t_stereo_camera_calibration_reference(out_data, data_ptr); t_stereo_camera_calibration_reference(out_data, data_ptr);
@ -283,6 +282,23 @@ t_stereo_camera_calibration_load_v1(FILE *calib_file, struct t_stereo_camera_cal
return true; return true;
} }
static bool
t_stereo_camera_calibration_load_path_v1(const char *calib_path, struct t_stereo_camera_calibration **out_data)
{
CALIB_WARN("Deprecated function %s", __func__);
FILE *calib_file = fopen(calib_path, "rb");
if (calib_file == nullptr) {
CALIB_ERROR("Unable to open calibration file: '%s'", calib_path);
return false;
}
bool success = t_stereo_camera_calibration_load_v1(calib_file, out_data);
fclose(calib_file);
return success;
}
#define PINHOLE_RADTAN5 "pinhole_radtan5" #define PINHOLE_RADTAN5 "pinhole_radtan5"
#define FISHEYE_EQUIDISTANT4 "fisheye_equidistant4" #define FISHEYE_EQUIDISTANT4 "fisheye_equidistant4"
@ -368,24 +384,19 @@ t_camera_calibration_load_v2(cJSON *cjson_cam, t_camera_calibration *cc)
return true; return true;
} }
static bool extern "C" bool
t_stereo_camera_calibration_load_v2(const char *calib_path, struct t_stereo_camera_calibration **out_stereo) t_stereo_camera_calibration_from_json_v2(cJSON *cjson, struct t_stereo_camera_calibration **out_stereo)
{ {
JSONNode json = JSONNode::loadFromFile(calib_path); JSONNode json{cjson};
if (json.isInvalid()) {
CALIB_ERROR("Unable to open calibration file: '%s'", calib_path);
return false;
}
StereoCameraCalibrationWrapper stereo{5}; // Hardcoded to 5 distortion parameters. StereoCameraCalibrationWrapper stereo{5}; // Hardcoded to 5 distortion parameters.
// Load file metadata // Load file metadata
const int supported_version = 2; const int supported_version = 2;
int version = json["file"]["version"].asInt(supported_version); int version = json["metadata"]["version"].asInt(supported_version);
if (json["file"]["version"].isInvalid()) { if (json["metadata"]["version"].isInvalid()) {
CALIB_WARN("'file.version' not found in %s, will assume v2", calib_path); CALIB_WARN("'metadata.version' not found, will assume version=%d", supported_version);
} }
CALIB_ASSERTR(version == supported_version, "Calibration file version (%d) != %d", version, supported_version); CALIB_ASSERTR(version == supported_version, "Calibration json version (%d) != %d", version, supported_version);
// Load cameras // Load cameras
vector<JSONNode> cameras = json["cameras"].asArray(); vector<JSONNode> cameras = json["cameras"].asArray();
@ -412,6 +423,17 @@ t_stereo_camera_calibration_load_v2(const char *calib_path, struct t_stereo_came
return true; return true;
} }
static bool
t_stereo_camera_calibration_load_path_v2(const char *calib_path, struct t_stereo_camera_calibration **out_stereo)
{
JSONNode json = JSONNode::loadFromFile(calib_path);
if (json.isInvalid()) {
CALIB_ERROR("Unable to open calibration file: '%s'", calib_path);
return false;
}
return t_stereo_camera_calibration_from_json_v2(json.getCJSON(), out_stereo);
}
/* /*
* *
@ -422,12 +444,12 @@ t_stereo_camera_calibration_load_v2(const char *calib_path, struct t_stereo_came
extern "C" bool extern "C" bool
t_stereo_camera_calibration_save_v1(FILE *calib_file, struct t_stereo_camera_calibration *data) t_stereo_camera_calibration_save_v1(FILE *calib_file, struct t_stereo_camera_calibration *data)
{ {
using xrt::auxiliary::tracking::StereoCameraCalibrationWrapper; CALIB_WARN("Deprecated function: %s", __func__);
StereoCameraCalibrationWrapper wrapped(data); StereoCameraCalibrationWrapper wrapped(data);
// Dummy matrix // Dummy matrix
cv::Mat dummy; cv::Mat dummy;
write_cv_mat(calib_file, &wrapped.view[0].intrinsics_mat); write_cv_mat(calib_file, &wrapped.view[0].intrinsics_mat);
write_cv_mat(calib_file, &wrapped.view[1].intrinsics_mat); write_cv_mat(calib_file, &wrapped.view[1].intrinsics_mat);
write_cv_mat(calib_file, &wrapped.view[0].distortion_mat); write_cv_mat(calib_file, &wrapped.view[0].distortion_mat);
@ -464,6 +486,21 @@ t_stereo_camera_calibration_save_v1(FILE *calib_file, struct t_stereo_camera_cal
return true; return true;
} }
static bool
t_stereo_camera_calibration_save_path_v1(const char *calib_path, struct t_stereo_camera_calibration *data)
{
FILE *calib_file = fopen(calib_path, "wb");
if (calib_file == nullptr) {
CALIB_ERROR("Unable to open calibration file: '%s'", calib_path);
return false;
}
bool success = t_stereo_camera_calibration_save_v1(calib_file, data);
fclose(calib_file);
return success;
}
//! Writes @p mat data into a @p jb as a json array. //! Writes @p mat data into a @p jb as a json array.
static JSONBuilder & static JSONBuilder &
operator<<(JSONBuilder &jb, const cv::Mat_<double> &mat) operator<<(JSONBuilder &jb, const cv::Mat_<double> &mat)
@ -476,8 +513,8 @@ operator<<(JSONBuilder &jb, const cv::Mat_<double> &mat)
return jb; return jb;
} }
static bool extern "C" bool
t_stereo_camera_calibration_save_v2(const char *calib_path, struct t_stereo_camera_calibration *data) t_stereo_camera_calibration_to_json_v2(cJSON **out_cjson, struct t_stereo_camera_calibration *data)
{ {
StereoCameraCalibrationWrapper wrapped(data); StereoCameraCalibrationWrapper wrapped(data);
JSONBuilder jb{}; JSONBuilder jb{};
@ -485,12 +522,9 @@ t_stereo_camera_calibration_save_v2(const char *calib_path, struct t_stereo_came
jb << "{"; jb << "{";
jb << "$schema" jb << "$schema"
<< "https://monado.pages.freedesktop.org/monado/calibration_v2.schema.json"; << "https://monado.pages.freedesktop.org/monado/calibration_v2.schema.json";
jb << "file"; jb << "metadata";
jb << "{"; jb << "{";
jb << "version" << 2; jb << "version" << 2;
char datetime[OS_ISO_STR_SIZE];
to_iso_string(os_realtime_get_ns(), datetime);
jb << "created_on" << datetime;
jb << "}"; jb << "}";
jb << "cameras"; jb << "cameras";
@ -553,10 +587,26 @@ t_stereo_camera_calibration_save_v2(const char *calib_path, struct t_stereo_came
jb << "}"; jb << "}";
CALIB_INFO("Saving calibration file: %s", jb.getBuiltNode()->toString().c_str()); cJSON *cjson = jb.getBuiltNode()->getCJSON();
return jb.getBuiltNode()->saveToFile(calib_path); *out_cjson = cJSON_Duplicate(cjson, true);
return true;
} }
static bool
t_stereo_camera_calibration_save_path_v2(const char *calib_path, struct t_stereo_camera_calibration *data)
{
cJSON *cjson = NULL;
bool success = t_stereo_camera_calibration_to_json_v2(&cjson, data);
if (!success) {
return false;
}
JSONNode json{cjson, true, nullptr}; // is_owner=true so it will free cjson object when leaving scope
CALIB_INFO("Saving calibration file: %s", json.toString(false).c_str());
return json.saveToFile(calib_path);
}
/* /*
* *
* Helpers * Helpers
@ -630,3 +680,38 @@ read_cv_mat(FILE *f, cv::Mat *m, const char *name)
CALIB_ERROR("Mat dimension unknown mismatch: '%s'", name); CALIB_ERROR("Mat dimension unknown mismatch: '%s'", name);
return false; return false;
} }
static bool
has_json_extension(const char *filename)
{
const char extension[] = ".json";
size_t name_len = strlen(filename);
size_t ext_len = strlen(extension);
if (name_len > ext_len) {
return strcmp(&filename[name_len - ext_len], extension) == 0;
}
return false;
}
/*
*
* Exported functions
*
*/
extern "C" bool
t_stereo_camera_calibration_load(const char *calib_path, struct t_stereo_camera_calibration **out_data)
{
return has_json_extension(calib_path) ? t_stereo_camera_calibration_load_path_v2(calib_path, out_data)
: t_stereo_camera_calibration_load_path_v1(calib_path, out_data);
}
extern "C" bool
t_stereo_camera_calibration_save(const char *calib_path, struct t_stereo_camera_calibration *data)
{
return has_json_extension(calib_path) ? t_stereo_camera_calibration_save_path_v2(calib_path, data)
: t_stereo_camera_calibration_save_path_v1(calib_path, data);
}

View file

@ -13,6 +13,7 @@
#include "xrt/xrt_frame.h" #include "xrt/xrt_frame.h"
#include "util/u_misc.h" #include "util/u_misc.h"
#include "cjson/cJSON.h"
#include <stdio.h> #include <stdio.h>
@ -165,7 +166,7 @@ void
t_stereo_camera_calibration_dump(struct t_stereo_camera_calibration *c); t_stereo_camera_calibration_dump(struct t_stereo_camera_calibration *c);
/*! /*!
* Load stereo calibration data from a given file. * Load stereo calibration data from a given file in v1 format (binary).
* *
* @relates t_stereo_camera_calibration * @relates t_stereo_camera_calibration
*/ */
@ -173,13 +174,46 @@ bool
t_stereo_camera_calibration_load_v1(FILE *calib_file, struct t_stereo_camera_calibration **out_data); t_stereo_camera_calibration_load_v1(FILE *calib_file, struct t_stereo_camera_calibration **out_data);
/*! /*!
* Save the given stereo calibration data to the given file. * Save the given stereo calibration data to the given file in v1 format (binary).
* *
* @relates t_stereo_camera_calibration * @relates t_stereo_camera_calibration
*/ */
bool bool
t_stereo_camera_calibration_save_v1(FILE *calib_file, struct t_stereo_camera_calibration *data); t_stereo_camera_calibration_save_v1(FILE *calib_file, struct t_stereo_camera_calibration *data);
/*!
* Parse the json object in v2 format into stereo calibration data.
*
* @relates t_stereo_camera_calibration
*/
bool
t_stereo_camera_calibration_from_json_v2(cJSON *json, struct t_stereo_camera_calibration **out_data);
/*!
* Convert the given stereo calibration data into a json object in v2 format.
*
* @relates t_stereo_camera_calibration
*/
bool
t_stereo_camera_calibration_to_json_v2(cJSON **out_json, struct t_stereo_camera_calibration *data);
/*!
* Load stereo calibration data from a given file path.
*
* @relates t_stereo_camera_calibration
*/
bool
t_stereo_camera_calibration_load(const char *calib_path, struct t_stereo_camera_calibration **out_data);
/*!
* Save the given stereo calibration data to the given file path.
*
* @relates t_stereo_camera_calibration
*/
bool
t_stereo_camera_calibration_save(const char *calib_path, struct t_stereo_camera_calibration *data);
/* /*
* *

View file

@ -77,7 +77,7 @@ save_calibration(struct calibration_scene *cs)
saved_header(cs); saved_header(cs);
igSetNextItemWidth(115); igSetNextItemWidth(115);
igInputText(".calibration", cs->filename, sizeof(cs->filename), 0, NULL, NULL); igInputText(".calibration.json", cs->filename, sizeof(cs->filename), 0, NULL, NULL);
igSameLine(0.0f, 4.0f); igSameLine(0.0f, 4.0f);
static ImVec2 button_dims = {0, 0}; static ImVec2 button_dims = {0, 0};
@ -93,8 +93,8 @@ save_calibration(struct calibration_scene *cs)
* *
*/ */
char tmp[sizeof(cs->filename) + 16]; char tmp[sizeof(cs->filename) + 32];
snprintf(tmp, sizeof(tmp), "%s.calibration", cs->filename); snprintf(tmp, sizeof(tmp), "%s.calibration.json", cs->filename);
u_file_get_path_in_config_dir(tmp, cs->settings->calibration_path, sizeof(cs->settings->calibration_path)); u_file_get_path_in_config_dir(tmp, cs->settings->calibration_path, sizeof(cs->settings->calibration_path));
@ -114,10 +114,7 @@ save_calibration(struct calibration_scene *cs)
* *
*/ */
FILE *calib_file = fopen(cs->settings->calibration_path, "wb"); t_stereo_camera_calibration_save(cs->settings->calibration_path, cs->status.stereo_data);
t_stereo_camera_calibration_save_v1(calib_file, cs->status.stereo_data);
fclose(calib_file);
calib_file = NULL;
cs->saved = true; cs->saved = true;
} }

View file

@ -163,18 +163,10 @@ p_factory_ensure_frameserver(struct p_factory *fact)
return; return;
} }
// Open the calibration file.
FILE *file = fopen(fact->settings.calibration_path, "rb");
if (file == NULL) {
return;
}
// Parse the calibration data from the file. // Parse the calibration data from the file.
if (!t_stereo_camera_calibration_load_v1(file, &fact->data)) { if (!t_stereo_camera_calibration_load(fact->settings.calibration_path, &fact->data)) {
fclose(file);
return; return;
} }
fclose(file);
struct xrt_frame_sink *xsink = NULL; struct xrt_frame_sink *xsink = NULL;
struct xrt_frame_sink *xsinks[4] = {0}; struct xrt_frame_sink *xsinks[4] = {0};