The open source OpenXR runtime

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

+155 -57
+2 -3
doc/example_configs/calibration_v2.example.json
··· 1 1 { 2 2 "$schema": "https://monado.pages.freedesktop.org/monado/calibration_v2.schema.json", 3 - "file": { 4 - "version": 2, 5 - "created_on": "2021-11-23T14:33:51Z" 3 + "metadata": { 4 + "version": 2 6 5 }, 7 6 "cameras": [ 8 7 {
+2 -11
doc/example_configs/calibration_v2.schema.json
··· 3 3 "title": "Monado calibration file schema v2", 4 4 "type": "object", 5 5 "required": [ 6 - "file", 6 + "metadata", 7 7 "cameras", 8 8 "opencv_stereo_calibrate" 9 9 ], ··· 13 13 "title": "JSON Schema directive", 14 14 "default": "https://monado.pages.freedesktop.org/monado/calibration_v2.schema.json" 15 15 }, 16 - "file": { 16 + "metadata": { 17 17 "description": "Calibration file metadata", 18 18 "type": "object", 19 19 "required": [ ··· 22 22 "properties": { 23 23 "version": { 24 24 "const": 2 25 - }, 26 - "created_on": { 27 - "$ref": "#/$defs/datetime" 28 25 } 29 26 } 30 27 }, ··· 211 208 "type": "number" 212 209 } 213 210 } 214 - }, 215 - "datetime": { 216 - "$comment": "The format specification might not be asserted against, that's why we also provide a regex pattern", 217 - "type": "string", 218 - "format": "date-time", 219 - "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$" 220 211 } 221 212 } 222 213 }
+110 -25
src/xrt/auxiliary/tracking/t_file.cpp
··· 16 16 #include "os/os_time.h" 17 17 18 18 19 - DEBUG_GET_ONCE_LOG_OPTION(calib_log, "CALIB_LOG", U_LOGGING_WARN) 19 + DEBUG_GET_ONCE_LOG_OPTION(calib_log, "CALIB_LOG", U_LOGGING_INFO) 20 20 21 21 #define CALIB_TRACE(...) U_LOG_IFL_T(debug_get_log_option_calib_log(), __VA_ARGS__) 22 22 #define CALIB_DEBUG(...) U_LOG_IFL_D(debug_get_log_option_calib_log(), __VA_ARGS__) ··· 212 212 extern "C" bool 213 213 t_stereo_camera_calibration_load_v1(FILE *calib_file, struct t_stereo_camera_calibration **out_data) 214 214 { 215 - using xrt::auxiliary::tracking::StereoCameraCalibrationWrapper; 215 + 216 216 t_stereo_camera_calibration *data_ptr = NULL; 217 217 t_stereo_camera_calibration_alloc(&data_ptr, 5); // Hardcoded to 5 distortion parameters. 218 218 StereoCameraCalibrationWrapper wrapped(data_ptr); ··· 274 274 wrapped.view[1].use_fisheye = wrapped.view[0].use_fisheye; 275 275 // clang-format on 276 276 277 - 278 277 CALIB_ASSERT_(wrapped.isDataStorageValid()); 279 278 280 279 t_stereo_camera_calibration_reference(out_data, data_ptr); ··· 283 282 return true; 284 283 } 285 284 285 + static bool 286 + t_stereo_camera_calibration_load_path_v1(const char *calib_path, struct t_stereo_camera_calibration **out_data) 287 + { 288 + CALIB_WARN("Deprecated function %s", __func__); 289 + 290 + FILE *calib_file = fopen(calib_path, "rb"); 291 + if (calib_file == nullptr) { 292 + CALIB_ERROR("Unable to open calibration file: '%s'", calib_path); 293 + return false; 294 + } 295 + 296 + bool success = t_stereo_camera_calibration_load_v1(calib_file, out_data); 297 + fclose(calib_file); 298 + 299 + return success; 300 + } 301 + 286 302 #define PINHOLE_RADTAN5 "pinhole_radtan5" 287 303 #define FISHEYE_EQUIDISTANT4 "fisheye_equidistant4" 288 304 ··· 368 384 return true; 369 385 } 370 386 371 - static bool 372 - t_stereo_camera_calibration_load_v2(const char *calib_path, struct t_stereo_camera_calibration **out_stereo) 387 + extern "C" bool 388 + t_stereo_camera_calibration_from_json_v2(cJSON *cjson, struct t_stereo_camera_calibration **out_stereo) 373 389 { 374 - JSONNode json = JSONNode::loadFromFile(calib_path); 375 - if (json.isInvalid()) { 376 - CALIB_ERROR("Unable to open calibration file: '%s'", calib_path); 377 - return false; 378 - } 379 - 390 + JSONNode json{cjson}; 380 391 StereoCameraCalibrationWrapper stereo{5}; // Hardcoded to 5 distortion parameters. 381 392 382 393 // Load file metadata 383 394 const int supported_version = 2; 384 - int version = json["file"]["version"].asInt(supported_version); 385 - if (json["file"]["version"].isInvalid()) { 386 - CALIB_WARN("'file.version' not found in %s, will assume v2", calib_path); 395 + int version = json["metadata"]["version"].asInt(supported_version); 396 + if (json["metadata"]["version"].isInvalid()) { 397 + CALIB_WARN("'metadata.version' not found, will assume version=%d", supported_version); 387 398 } 388 - CALIB_ASSERTR(version == supported_version, "Calibration file version (%d) != %d", version, supported_version); 399 + CALIB_ASSERTR(version == supported_version, "Calibration json version (%d) != %d", version, supported_version); 389 400 390 401 // Load cameras 391 402 vector<JSONNode> cameras = json["cameras"].asArray(); ··· 412 423 return true; 413 424 } 414 425 426 + static bool 427 + t_stereo_camera_calibration_load_path_v2(const char *calib_path, struct t_stereo_camera_calibration **out_stereo) 428 + { 429 + JSONNode json = JSONNode::loadFromFile(calib_path); 430 + if (json.isInvalid()) { 431 + CALIB_ERROR("Unable to open calibration file: '%s'", calib_path); 432 + return false; 433 + } 434 + return t_stereo_camera_calibration_from_json_v2(json.getCJSON(), out_stereo); 435 + } 436 + 415 437 416 438 /* 417 439 * ··· 422 444 extern "C" bool 423 445 t_stereo_camera_calibration_save_v1(FILE *calib_file, struct t_stereo_camera_calibration *data) 424 446 { 425 - using xrt::auxiliary::tracking::StereoCameraCalibrationWrapper; 447 + CALIB_WARN("Deprecated function: %s", __func__); 448 + 426 449 StereoCameraCalibrationWrapper wrapped(data); 427 450 // Dummy matrix 428 451 cv::Mat dummy; 429 - 430 452 431 453 write_cv_mat(calib_file, &wrapped.view[0].intrinsics_mat); 432 454 write_cv_mat(calib_file, &wrapped.view[1].intrinsics_mat); ··· 464 486 return true; 465 487 } 466 488 489 + static bool 490 + t_stereo_camera_calibration_save_path_v1(const char *calib_path, struct t_stereo_camera_calibration *data) 491 + { 492 + FILE *calib_file = fopen(calib_path, "wb"); 493 + if (calib_file == nullptr) { 494 + CALIB_ERROR("Unable to open calibration file: '%s'", calib_path); 495 + return false; 496 + } 497 + 498 + bool success = t_stereo_camera_calibration_save_v1(calib_file, data); 499 + fclose(calib_file); 500 + 501 + return success; 502 + } 503 + 467 504 //! Writes @p mat data into a @p jb as a json array. 468 505 static JSONBuilder & 469 506 operator<<(JSONBuilder &jb, const cv::Mat_<double> &mat) ··· 476 513 return jb; 477 514 } 478 515 479 - static bool 480 - t_stereo_camera_calibration_save_v2(const char *calib_path, struct t_stereo_camera_calibration *data) 516 + extern "C" bool 517 + t_stereo_camera_calibration_to_json_v2(cJSON **out_cjson, struct t_stereo_camera_calibration *data) 481 518 { 482 519 StereoCameraCalibrationWrapper wrapped(data); 483 520 JSONBuilder jb{}; ··· 485 522 jb << "{"; 486 523 jb << "$schema" 487 524 << "https://monado.pages.freedesktop.org/monado/calibration_v2.schema.json"; 488 - jb << "file"; 525 + jb << "metadata"; 489 526 jb << "{"; 490 527 jb << "version" << 2; 491 - char datetime[OS_ISO_STR_SIZE]; 492 - to_iso_string(os_realtime_get_ns(), datetime); 493 - jb << "created_on" << datetime; 494 528 jb << "}"; 495 529 496 530 jb << "cameras"; ··· 553 587 554 588 jb << "}"; 555 589 556 - CALIB_INFO("Saving calibration file: %s", jb.getBuiltNode()->toString().c_str()); 557 - return jb.getBuiltNode()->saveToFile(calib_path); 590 + cJSON *cjson = jb.getBuiltNode()->getCJSON(); 591 + *out_cjson = cJSON_Duplicate(cjson, true); 592 + return true; 558 593 } 559 594 595 + static bool 596 + t_stereo_camera_calibration_save_path_v2(const char *calib_path, struct t_stereo_camera_calibration *data) 597 + { 598 + cJSON *cjson = NULL; 599 + bool success = t_stereo_camera_calibration_to_json_v2(&cjson, data); 600 + if (!success) { 601 + return false; 602 + } 603 + 604 + JSONNode json{cjson, true, nullptr}; // is_owner=true so it will free cjson object when leaving scope 605 + CALIB_INFO("Saving calibration file: %s", json.toString(false).c_str()); 606 + return json.saveToFile(calib_path); 607 + } 608 + 609 + 560 610 /* 561 611 * 562 612 * Helpers ··· 630 680 CALIB_ERROR("Mat dimension unknown mismatch: '%s'", name); 631 681 return false; 632 682 } 683 + 684 + static bool 685 + has_json_extension(const char *filename) 686 + { 687 + const char extension[] = ".json"; 688 + size_t name_len = strlen(filename); 689 + size_t ext_len = strlen(extension); 690 + 691 + if (name_len > ext_len) { 692 + return strcmp(&filename[name_len - ext_len], extension) == 0; 693 + } 694 + 695 + return false; 696 + } 697 + 698 + 699 + /* 700 + * 701 + * Exported functions 702 + * 703 + */ 704 + 705 + extern "C" bool 706 + t_stereo_camera_calibration_load(const char *calib_path, struct t_stereo_camera_calibration **out_data) 707 + { 708 + return has_json_extension(calib_path) ? t_stereo_camera_calibration_load_path_v2(calib_path, out_data) 709 + : t_stereo_camera_calibration_load_path_v1(calib_path, out_data); 710 + } 711 + 712 + extern "C" bool 713 + t_stereo_camera_calibration_save(const char *calib_path, struct t_stereo_camera_calibration *data) 714 + { 715 + return has_json_extension(calib_path) ? t_stereo_camera_calibration_save_path_v2(calib_path, data) 716 + : t_stereo_camera_calibration_save_path_v1(calib_path, data); 717 + }
+36 -2
src/xrt/auxiliary/tracking/t_tracking.h
··· 13 13 14 14 #include "xrt/xrt_frame.h" 15 15 #include "util/u_misc.h" 16 + #include "cjson/cJSON.h" 16 17 17 18 #include <stdio.h> 18 19 ··· 165 166 t_stereo_camera_calibration_dump(struct t_stereo_camera_calibration *c); 166 167 167 168 /*! 168 - * Load stereo calibration data from a given file. 169 + * Load stereo calibration data from a given file in v1 format (binary). 169 170 * 170 171 * @relates t_stereo_camera_calibration 171 172 */ ··· 173 174 t_stereo_camera_calibration_load_v1(FILE *calib_file, struct t_stereo_camera_calibration **out_data); 174 175 175 176 /*! 176 - * Save the given stereo calibration data to the given file. 177 + * Save the given stereo calibration data to the given file in v1 format (binary). 177 178 * 178 179 * @relates t_stereo_camera_calibration 179 180 */ 180 181 bool 181 182 t_stereo_camera_calibration_save_v1(FILE *calib_file, struct t_stereo_camera_calibration *data); 183 + 184 + /*! 185 + * Parse the json object in v2 format into stereo calibration data. 186 + * 187 + * @relates t_stereo_camera_calibration 188 + */ 189 + bool 190 + t_stereo_camera_calibration_from_json_v2(cJSON *json, struct t_stereo_camera_calibration **out_data); 191 + 192 + /*! 193 + * Convert the given stereo calibration data into a json object in v2 format. 194 + * 195 + * @relates t_stereo_camera_calibration 196 + */ 197 + bool 198 + t_stereo_camera_calibration_to_json_v2(cJSON **out_json, struct t_stereo_camera_calibration *data); 199 + 200 + 201 + /*! 202 + * Load stereo calibration data from a given file path. 203 + * 204 + * @relates t_stereo_camera_calibration 205 + */ 206 + bool 207 + t_stereo_camera_calibration_load(const char *calib_path, struct t_stereo_camera_calibration **out_data); 208 + 209 + /*! 210 + * Save the given stereo calibration data to the given file path. 211 + * 212 + * @relates t_stereo_camera_calibration 213 + */ 214 + bool 215 + t_stereo_camera_calibration_save(const char *calib_path, struct t_stereo_camera_calibration *data); 182 216 183 217 184 218 /*
+4 -7
src/xrt/state_trackers/gui/gui_scene_calibrate.c
··· 77 77 78 78 saved_header(cs); 79 79 igSetNextItemWidth(115); 80 - igInputText(".calibration", cs->filename, sizeof(cs->filename), 0, NULL, NULL); 80 + igInputText(".calibration.json", cs->filename, sizeof(cs->filename), 0, NULL, NULL); 81 81 igSameLine(0.0f, 4.0f); 82 82 83 83 static ImVec2 button_dims = {0, 0}; ··· 93 93 * 94 94 */ 95 95 96 - char tmp[sizeof(cs->filename) + 16]; 97 - snprintf(tmp, sizeof(tmp), "%s.calibration", cs->filename); 96 + char tmp[sizeof(cs->filename) + 32]; 97 + snprintf(tmp, sizeof(tmp), "%s.calibration.json", cs->filename); 98 98 99 99 u_file_get_path_in_config_dir(tmp, cs->settings->calibration_path, sizeof(cs->settings->calibration_path)); 100 100 ··· 114 114 * 115 115 */ 116 116 117 - FILE *calib_file = fopen(cs->settings->calibration_path, "wb"); 118 - t_stereo_camera_calibration_save_v1(calib_file, cs->status.stereo_data); 119 - fclose(calib_file); 120 - calib_file = NULL; 117 + t_stereo_camera_calibration_save(cs->settings->calibration_path, cs->status.stereo_data); 121 118 122 119 cs->saved = true; 123 120 }
+1 -9
src/xrt/state_trackers/prober/p_tracking.c
··· 163 163 return; 164 164 } 165 165 166 - // Open the calibration file. 167 - FILE *file = fopen(fact->settings.calibration_path, "rb"); 168 - if (file == NULL) { 169 - return; 170 - } 171 - 172 166 // Parse the calibration data from the file. 173 - if (!t_stereo_camera_calibration_load_v1(file, &fact->data)) { 174 - fclose(file); 167 + if (!t_stereo_camera_calibration_load(fact->settings.calibration_path, &fact->data)) { 175 168 return; 176 169 } 177 - fclose(file); 178 170 179 171 struct xrt_frame_sink *xsink = NULL; 180 172 struct xrt_frame_sink *xsinks[4] = {0};