The open source OpenXR runtime

a/tracking: Store distortion model in calibration, robust OpenCV distortion model support

Part-of: <https://gitlab.freedesktop.org/monado/monado/-/merge_requests/2519>

authored by

Joel-Valenciano and committed by
Beyley Cardellio
4a6a143f 1244d50c

+71 -23
+17 -11
src/xrt/auxiliary/tracking/t_calibration.cpp
··· 147 147 //! Number of frames to capture before restarting. 148 148 uint32_t num_collect_restart = 1; 149 149 150 - //! Is the camera fisheye. 151 - bool use_fisheye = false; 150 + //! Distortion model to use. 151 + enum t_camera_distortion_model distortion_model = T_DISTORTION_OPENCV_RADTAN_5; 152 152 //! From parameters. 153 153 bool stereo_sbs = false; 154 154 ··· 575 575 cv::Size image_size(cols, rows); 576 576 cv::Size new_image_size(cols, rows); 577 577 578 - StereoCameraCalibrationWrapper wrapped(c.use_fisheye ? T_DISTORTION_FISHEYE_KB4 : T_DISTORTION_OPENCV_RADTAN_5); 578 + StereoCameraCalibrationWrapper wrapped(c.distortion_model); 579 579 wrapped.view[0].image_size_pixels.w = image_size.width; 580 580 wrapped.view[0].image_size_pixels.h = image_size.height; 581 581 wrapped.view[1].image_size_pixels = wrapped.view[0].image_size_pixels; 582 582 583 583 584 584 float rp_error = 0.0f; 585 - if (c.use_fisheye) { 585 + if (t_camera_distortion_model_is_opencv_fisheye(c.distortion_model)) { 586 586 int flags = 0; 587 587 flags |= cv::fisheye::CALIB_FIX_SKEW; 588 588 flags |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC; ··· 599 599 wrapped.camera_rotation_mat, // R 600 600 wrapped.camera_translation_mat, // T 601 601 flags); 602 - } else { 602 + } else if (t_camera_distortion_model_is_opencv_non_fisheye(c.distortion_model)) { 603 603 // non-fisheye version 604 604 int flags = 0; 605 605 ··· 617 617 wrapped.camera_essential_mat, // E 618 618 wrapped.camera_fundamental_mat, // F 619 619 flags); // flags 620 + } else { 621 + assert(!"Unsupported distortion model"); 620 622 } 621 623 622 624 // Tell the user what has happened. ··· 636 638 std::cout << "calibration rp_error: " << rp_error << "\n"; 637 639 to_stdout("camera_rotation", wrapped.camera_rotation_mat); 638 640 to_stdout("camera_translation", wrapped.camera_translation_mat); 639 - if (!c.use_fisheye) { 641 + if (!t_camera_distortion_model_is_fisheye(c.distortion_model)) { 640 642 to_stdout("camera_essential", wrapped.camera_essential_mat); 641 643 to_stdout("camera_fundamental", wrapped.camera_fundamental_mat); 642 644 } ··· 683 685 U_LOG_RAW("};"); 684 686 } 685 687 686 - if (c.use_fisheye) { 688 + if (t_camera_distortion_model_is_opencv_fisheye(c.distortion_model)) { 687 689 int crit_flag = 0; 688 690 crit_flag |= cv::TermCriteria::EPS; 689 691 crit_flag |= cv::TermCriteria::COUNT; ··· 718 720 // Probably a busted work-around for busted function. 719 721 new_intrinsics_mat.at<double>(0, 2) = (cols - 1) / 2.0; 720 722 new_intrinsics_mat.at<double>(1, 2) = (rows - 1) / 2.0; 721 - } else { 723 + } else if (t_camera_distortion_model_is_opencv_non_fisheye(c.distortion_model)) { 722 724 int flags = 0; 723 725 724 726 // Go all out. ··· 747 749 cv::Size(), // newImgSize 748 750 NULL, // validPixROI 749 751 false); // centerPrincipalPoint 752 + } else { 753 + assert(!"Unsupported distortion model"); 750 754 } 751 755 752 756 P("CALIBRATION DONE RP ERROR %f", rp_error); ··· 759 763 std::cout << "distortion_mat:\n" << distortion_mat << "\n"; 760 764 // clang-format on 761 765 762 - if (c.use_fisheye) { 766 + if (t_camera_distortion_model_is_opencv_fisheye(c.distortion_model)) { 763 767 cv::fisheye::initUndistortRectifyMap(intrinsics_mat, // K 764 768 distortion_mat, // D 765 769 cv::Matx33d::eye(), // R ··· 771 775 772 776 // Set the maps as valid. 773 777 view.maps_valid = true; 774 - } else { 778 + } else if (t_camera_distortion_model_is_opencv_non_fisheye(c.distortion_model)) { 775 779 cv::initUndistortRectifyMap( // 776 780 intrinsics_mat, // K 777 781 distortion_mat, // D ··· 784 788 785 789 // Set the maps as valid. 786 790 view.maps_valid = true; 791 + } else { 792 + assert(!"Unsupported distortion model"); 787 793 } 788 794 789 795 c.state.calibrated = true; ··· 1276 1282 *out_sink = &c.base; 1277 1283 1278 1284 // Copy the parameters. 1279 - c.use_fisheye = params->use_fisheye; 1280 1285 c.stereo_sbs = params->stereo_sbs; 1281 1286 c.board.pattern = params->pattern; 1282 1287 switch (params->pattern) { ··· 1323 1328 c.mirror_rgb_image = params->mirror_rgb_image; 1324 1329 c.save_images = params->save_images; 1325 1330 c.status = status; 1331 + c.distortion_model = params->use_fisheye ? T_DISTORTION_FISHEYE_KB4 : T_DISTORTION_OPENCV_RADTAN_5; 1326 1332 1327 1333 1328 1334 // Setup a initial message.
+30
src/xrt/auxiliary/tracking/t_calibration_opencv.hpp
··· 34 34 default: return t_num_params_from_distortion_model(model); 35 35 } 36 36 } 37 + 38 + /*! 39 + * @brief Determines whether a camera distortion model is suitable for use in OpenCV as a fisheye distortion. 40 + * 41 + * @param model The distortion model in question. 42 + */ 43 + static inline bool 44 + t_camera_distortion_model_is_opencv_fisheye(const enum t_camera_distortion_model model) 45 + { 46 + return model == T_DISTORTION_FISHEYE_KB4; 47 + } 48 + 49 + /*! 50 + * @brief Determines whether a camera distortion model is suitable for use in OpenCV as a non-fisheye distortion. 51 + * 52 + * @param model The distortion model in question. 53 + */ 54 + static inline bool 55 + t_camera_distortion_model_is_opencv_non_fisheye(const enum t_camera_distortion_model model) 56 + { 57 + switch (model) { 58 + case T_DISTORTION_OPENCV_RADTAN_5: 59 + case T_DISTORTION_OPENCV_RADTAN_8: 60 + case T_DISTORTION_OPENCV_RADTAN_14: 61 + // @note WMR is not supported by OpenCV, but we re-interpret it into a format which is, so this is also valid. 62 + case T_DISTORTION_WMR: return true; 63 + default: return false; 64 + } 65 + } 66 + 37 67 /*! 38 68 * @brief Essential calibration data wrapped for C++. 39 69 *
+11 -12
src/xrt/auxiliary/tracking/t_file.cpp
··· 10 10 */ 11 11 12 12 #include "tracking/t_calibration_opencv.hpp" 13 + #include "tracking/t_tracking.h" 13 14 #include "util/u_misc.h" 14 15 #include "util/u_logging.h" 15 16 #include "util/u_json.hpp" ··· 82 83 // calibration for does not match what was saved 83 84 cv::Size image_size(calib.image_size_pixels.w, calib.image_size_pixels.h); 84 85 85 - switch (calib.distortion_model) { 86 - case (T_DISTORTION_FISHEYE_KB4): 86 + if (t_camera_distortion_model_is_opencv_fisheye(wrap.distortion_model)) { 87 87 cv::fisheye::initUndistortRectifyMap(wrap.intrinsics_mat, // cameraMatrix 88 88 wrap.distortion_mat, // distCoeffs 89 89 rectify_transform_optional, // R ··· 92 92 CV_32FC1, // m1type 93 93 ret.remap_x, // map1 94 94 ret.remap_y); // map2 95 - break; 96 - case T_DISTORTION_OPENCV_RADTAN_5: 95 + } else if (t_camera_distortion_model_is_opencv_non_fisheye(wrap.distortion_model)) { 97 96 cv::initUndistortRectifyMap(wrap.intrinsics_mat, // cameraMatrix 98 97 wrap.distortion_mat, // distCoeffs 99 98 rectify_transform_optional, // R ··· 102 101 CV_32FC1, // m1type 103 102 ret.remap_x, // map1 104 103 ret.remap_y); // map2 105 - break; 106 - default: assert(false); 104 + } else { 105 + assert(!"Unsupported distortion model"); 107 106 } 108 107 109 108 return ret; ··· 120 119 cv::Size image_size(data->view[0].image_size_pixels.w, data->view[0].image_size_pixels.h); 121 120 StereoCameraCalibrationWrapper wrapped(data); 122 121 122 + t_camera_distortion_model distortion_model = data->view[0].distortion_model; 123 + 123 124 /* 124 125 * Generate our rectification maps 125 126 * 126 127 * Here cv::noArray() means zero distortion. 127 128 */ 128 - switch (data->view[0].distortion_model) { 129 - case T_DISTORTION_FISHEYE_KB4: { 129 + if (t_camera_distortion_model_is_opencv_fisheye(distortion_model)) { 130 130 #if 0 131 131 //! @todo for some reason this looks weird? 132 132 // Alpha of 1.0 kinda works, not really. ··· 175 175 NULL, // validPixROI1 176 176 NULL); // validPixROI2 177 177 #endif 178 - } break; 179 - case T_DISTORTION_OPENCV_RADTAN_5: { 178 + } else if (t_camera_distortion_model_is_opencv_non_fisheye(distortion_model)) { 180 179 // Have the same principal point on both. 181 180 int flags = cv::CALIB_ZERO_DISPARITY; 182 181 // Get all of the pixels from the camera. ··· 201 200 cv::Size(), // newImageSize 202 201 NULL, // validPixROI1 203 202 NULL); // validPixROI2 204 - } break; 205 - default: assert(false); 203 + } else { 204 + assert(!"Unsupported distortion model"); 206 205 } 207 206 208 207 view[0].rectify = calibration_get_undistort_map(data->view[0], view[0].rotation_mat, view[0].projection_mat);
+13
src/xrt/auxiliary/tracking/t_tracking.h
··· 170 170 } 171 171 } 172 172 173 + static inline bool 174 + t_camera_distortion_model_is_fisheye(enum t_camera_distortion_model model) 175 + { 176 + switch (model) { 177 + case T_DISTORTION_FISHEYE_KB4: return true; 178 + case T_DISTORTION_OPENCV_RADTAN_5: 179 + case T_DISTORTION_OPENCV_RADTAN_8: 180 + case T_DISTORTION_OPENCV_RADTAN_14: 181 + case T_DISTORTION_WMR: return false; 182 + default: U_LOG_E("Invalid distortion_model! %d", model); return false; 183 + } 184 + } 185 + 173 186 /*! 174 187 * Parameters for @ref T_DISTORTION_OPENCV_RADTAN_5 175 188 * @ingroup aux_tracking