|
@@ -160,6 +160,17 @@ namespace camera_calibrator_impl {
|
|
|
ref_t_vec.push_back(to_cv_mat(t_vec));
|
|
ref_t_vec.push_back(to_cv_mat(t_vec));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// if (simulate_conventional) {
|
|
|
|
|
+// cv::Mat ret_r, ret_t;
|
|
|
|
|
+// cv::calibrateRobotWorldHandEye(
|
|
|
|
|
+// cam_r_vec, cam_t_vec, // chess board in camera
|
|
|
|
|
+// ref_r_vec, ref_t_vec, // tracker in reference
|
|
|
|
|
+// aux_r, aux_t, // tracker in chess board
|
|
|
|
|
+// ret_r, ret_t); // reference in camera
|
|
|
|
|
+//// SPDLOG_DEBUG("OpenCV: {}", glm::to_string(to_transform_mat(to_vec3(aux_t), to_mat3(aux_r))));
|
|
|
|
|
+// return to_transform_mat(to_vec3(ret_t), to_mat3(ret_r));
|
|
|
|
|
+// }
|
|
|
|
|
+
|
|
|
auto inv_op = [](const cv::Mat &r, const cv::Mat &t) {
|
|
auto inv_op = [](const cv::Mat &r, const cv::Mat &t) {
|
|
|
return glm::inverse(to_transform_mat(to_vec3(t), to_mat3(r)));
|
|
return glm::inverse(to_transform_mat(to_vec3(t), to_mat3(r)));
|
|
|
};
|
|
};
|
|
@@ -212,15 +223,6 @@ namespace camera_calibrator_impl {
|
|
|
aux_t = to_cv_mat(to_translation(aux_mat));
|
|
aux_t = to_cv_mat(to_translation(aux_mat));
|
|
|
// SPDLOG_DEBUG("Shah: {}", glm::to_string(aux_mat));
|
|
// SPDLOG_DEBUG("Shah: {}", glm::to_string(aux_mat));
|
|
|
return glm::inverse(to_mat4(X));
|
|
return glm::inverse(to_mat4(X));
|
|
|
-
|
|
|
|
|
-// cv::Mat ret_r, ret_t;
|
|
|
|
|
-// cv::calibrateRobotWorldHandEye(
|
|
|
|
|
-// cam_r_vec, cam_t_vec, // chess board in camera
|
|
|
|
|
-// ref_r_vec, ref_t_vec, // tracker in reference
|
|
|
|
|
-// aux_r, aux_t, // tracker in chess board
|
|
|
|
|
-// ret_r, ret_t); // reference in camera
|
|
|
|
|
-// SPDLOG_DEBUG("OpenCV: {}", glm::to_string(to_transform_mat(to_vec3(aux_t), to_mat3(aux_r))));
|
|
|
|
|
-// return to_transform_mat(to_vec3(ret_t), to_mat3(ret_r));
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
cv::Scalar hand_eye_calib::evaluate_hand_eye(const glm::mat4 &ret_mat) {
|
|
cv::Scalar hand_eye_calib::evaluate_hand_eye(const glm::mat4 &ret_mat) {
|
|
@@ -310,8 +312,8 @@ namespace camera_calibrator_impl {
|
|
|
hand_eye_calib::camera_calib_result
|
|
hand_eye_calib::camera_calib_result
|
|
|
hand_eye_calib::camera_calib_ransac() {
|
|
hand_eye_calib::camera_calib_ransac() {
|
|
|
static constexpr auto max_iter = 32; // TODO: make configurable
|
|
static constexpr auto max_iter = 32; // TODO: make configurable
|
|
|
- static constexpr auto calib_img_num = 5;
|
|
|
|
|
- static constexpr auto accept_threshold = 0.7f; // pix
|
|
|
|
|
|
|
+ static constexpr auto calib_img_num = 10;
|
|
|
|
|
+ static constexpr auto accept_threshold = 0.4f; // pix
|
|
|
static constexpr auto valid_ratio = 0.8f; // percentage
|
|
static constexpr auto valid_ratio = 0.8f; // percentage
|
|
|
|
|
|
|
|
auto rd = std::random_device();
|
|
auto rd = std::random_device();
|
|
@@ -331,7 +333,15 @@ namespace camera_calibrator_impl {
|
|
|
std::ranges::transform(img_pool, std::back_inserter(err_vec),
|
|
std::ranges::transform(img_pool, std::back_inserter(err_vec),
|
|
|
[=, this](const auto &img) { return reproject_error(cur, img.corner); });
|
|
[=, this](const auto &img) { return reproject_error(cur, img.corner); });
|
|
|
auto err_mean = std::accumulate(err_vec.begin(), err_vec.end(), 0.f) / sample_num;
|
|
auto err_mean = std::accumulate(err_vec.begin(), err_vec.end(), 0.f) / sample_num;
|
|
|
- SPDLOG_DEBUG("Iter {}, error = {:.2f}pix.", k, err_mean);
|
|
|
|
|
|
|
+ SPDLOG_INFO("Iter {}, error = {:.2f}pix.", k, err_mean);
|
|
|
|
|
+
|
|
|
|
|
+ if (save_calib_error) {
|
|
|
|
|
+ auto fout = std::ofstream(fmt::format("calib_{}.txt", k));
|
|
|
|
|
+ for (auto val: err_vec) {
|
|
|
|
|
+ fout << val << std::endl;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
auto ratio = 1.f * std::ranges::count_if(
|
|
auto ratio = 1.f * std::ranges::count_if(
|
|
|
err_vec, [=](auto err) { return err <= accept_threshold; }) / sample_num;
|
|
err_vec, [=](auto err) { return err <= accept_threshold; }) / sample_num;
|
|
|
if (ratio < valid_ratio) continue;
|
|
if (ratio < valid_ratio) continue;
|
|
@@ -375,7 +385,18 @@ namespace camera_calibrator_impl {
|
|
|
sample_num = img_pool.size();
|
|
sample_num = img_pool.size();
|
|
|
corner_num = img_pool.begin()->corner.size();
|
|
corner_num = img_pool.begin()->corner.size();
|
|
|
|
|
|
|
|
|
|
+ if (sub_sample_count != 0) {
|
|
|
|
|
+ assert(sample_num >= sub_sample_count);
|
|
|
|
|
+ std::random_device rd;
|
|
|
|
|
+ std::mt19937 g(rd());
|
|
|
|
|
+ std::shuffle(img_pool.begin(), img_pool.end(), g);
|
|
|
|
|
+ img_pool.erase(img_pool.begin() + sub_sample_count, img_pool.end());
|
|
|
|
|
+ sample_num = img_pool.size();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ auto ts = current_timestamp();
|
|
|
cam_cv = camera_calib_ransac();
|
|
cam_cv = camera_calib_ransac();
|
|
|
|
|
+ SPDLOG_INFO("Used time: {}ms", (current_timestamp() - ts) / 1000);
|
|
|
intrinsic_mat = to_mat3(cam_cv.intrinsic);
|
|
intrinsic_mat = to_mat3(cam_cv.intrinsic);
|
|
|
|
|
|
|
|
assert(cam_cv.dist_coeffs.size().height == 1);
|
|
assert(cam_cv.dist_coeffs.size().height == 1);
|
|
@@ -437,9 +458,13 @@ namespace camera_calibrator_impl {
|
|
|
auto ret_mat = calib_hand_eye();
|
|
auto ret_mat = calib_hand_eye();
|
|
|
return evaluate_hand_eye(ret_mat);
|
|
return evaluate_hand_eye(ret_mat);
|
|
|
};
|
|
};
|
|
|
- auto better_op = [](const cv::Scalar &lhs, // is lhs better than rhs ?
|
|
|
|
|
- const cv::Scalar &rhs) {
|
|
|
|
|
- return lhs[1] < rhs[1]; // use 2d error
|
|
|
|
|
|
|
+ auto weight_op = [](const cv::Scalar &w) {
|
|
|
|
|
+// return w[1];
|
|
|
|
|
+ return w[0] * 10 + w[1]; // w[0]: 3d, w[1]: 2d
|
|
|
|
|
+ };
|
|
|
|
|
+ auto better_op = [=](const cv::Scalar &lhs, // is lhs better than rhs ?
|
|
|
|
|
+ const cv::Scalar &rhs) {
|
|
|
|
|
+ return weight_op(lhs) < weight_op(rhs);
|
|
|
};
|
|
};
|
|
|
for (; offset_r - offset_l > eps;) {
|
|
for (; offset_r - offset_l > eps;) {
|
|
|
auto l_sec = (2 * offset_l + offset_r) / 3;
|
|
auto l_sec = (2 * offset_l + offset_r) / 3;
|
|
@@ -454,6 +479,51 @@ namespace camera_calibrator_impl {
|
|
|
}
|
|
}
|
|
|
result_ts_offset = (offset_l + offset_r) / 2;
|
|
result_ts_offset = (offset_l + offset_r) / 2;
|
|
|
|
|
|
|
|
|
|
+ if (simulate_conventional) {
|
|
|
|
|
+ static constexpr auto select_num = 4;
|
|
|
|
|
+ auto step = (float) sample_num / (select_num + 1);
|
|
|
|
|
+ auto select_ind = img_index_list_type(select_num);
|
|
|
|
|
+ for (auto k = 1; k < select_num; ++k) {
|
|
|
|
|
+ select_ind[k] = sample_num - step * k;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ cam_cv = camera_calib(select_ind);
|
|
|
|
|
+ intrinsic_mat = to_mat3(cam_cv.intrinsic);
|
|
|
|
|
+ dist_coeffs.clear();
|
|
|
|
|
+ for (auto k = 0; k < 8; ++k) {
|
|
|
|
|
+ dist_coeffs.push_back(cam_cv.dist_coeffs.at<double>(0, k));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ auto img_pool_new = image_pool_type();
|
|
|
|
|
+ std::ranges::transform(select_ind, std::back_inserter(img_pool_new),
|
|
|
|
|
+ [this](auto k) { return img_pool[k]; });
|
|
|
|
|
+ img_pool = img_pool_new;
|
|
|
|
|
+ sample_num = select_num;
|
|
|
|
|
+
|
|
|
|
|
+ // solve PnP for each image
|
|
|
|
|
+ cam_r_vec = std::vector<cv::Mat>(); // chess board in camera
|
|
|
|
|
+ cam_t_vec = std::vector<cv::Mat>();
|
|
|
|
|
+ for (auto &img: img_pool) {
|
|
|
|
|
+ auto &corner = img.corner;
|
|
|
|
|
+ cv::Mat chess_r, chess_t; // chess board in camera
|
|
|
|
|
+ bool ok = cv::solvePnP(obj_ps_pnp, corner,
|
|
|
|
|
+ cam_cv.intrinsic, cam_cv.dist_coeffs,
|
|
|
|
|
+ chess_r, chess_t);
|
|
|
|
|
+ auto ret_mat = to_transform_mat(to_vec3(chess_t),
|
|
|
|
|
+ rodrigues_to_mat(chess_r));
|
|
|
|
|
+ auto cam_r = to_cv_mat(glm::mat3(ret_mat)); // rotation part
|
|
|
|
|
+ auto cam_t = to_cv_mat(to_translation(ret_mat)); // translation part
|
|
|
|
|
+ cam_r_vec.push_back(cam_r);
|
|
|
|
|
+ cam_t_vec.push_back(cam_t);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // reset weights
|
|
|
|
|
+ sample_w = std::vector<float>(sample_num, 1.f);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (disable_temporl_offset) {
|
|
|
|
|
+ result_ts_offset = 0;
|
|
|
|
|
+ }
|
|
|
ts_offset = result_ts_offset;
|
|
ts_offset = result_ts_offset;
|
|
|
result_mat = glm::inverse(calib_hand_eye());
|
|
result_mat = glm::inverse(calib_hand_eye());
|
|
|
SPDLOG_INFO("Estimated temporal offset is {}ms", result_ts_offset / 1000);
|
|
SPDLOG_INFO("Estimated temporal offset is {}ms", result_ts_offset / 1000);
|
|
@@ -481,7 +551,7 @@ namespace camera_calibrator_impl {
|
|
|
|
|
|
|
|
camera_calibrator::impl::impl(const create_config &_conf) {
|
|
camera_calibrator::impl::impl(const create_config &_conf) {
|
|
|
conf = _conf;
|
|
conf = _conf;
|
|
|
- vg = nvgCreateGL3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
|
|
|
|
|
|
|
+// vg = nvgCreateGL3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
camera_calibrator::impl::~impl() {
|
|
camera_calibrator::impl::~impl() {
|