diff --git a/applications/calibration-multi/src/main.cpp b/applications/calibration-multi/src/main.cpp index ebf72ab7893b8a0af9a02e79d187d1b5530347c8..bf301728e32efc26e22667f934327b5a2affd921 100644 --- a/applications/calibration-multi/src/main.cpp +++ b/applications/calibration-multi/src/main.cpp @@ -174,8 +174,8 @@ void visualizeCalibration( MultiCameraCalibrationNew &calib, Mat &out, vector<int> markers = {cv::MARKER_SQUARE, cv::MARKER_DIAMOND}; for (size_t c = 0; c < rgb.size(); c++) { - cv::rectangle(rgb[c], roi[c], Scalar(24, 224, 24), 2); cv::remap(rgb[c], rgb[c], map1[c], map2[c], cv::INTER_CUBIC); + cv::rectangle(rgb[c], roi[c], Scalar(24, 224, 24), 2); for (int r = 50; r < rgb[c].rows; r = r+50) { cv::line(rgb[c], cv::Point(0, r), cv::Point(rgb[c].cols-1, r), cv::Scalar(0,0,255), 1); @@ -241,7 +241,8 @@ void calibrate( MultiCameraCalibrationNew &calib, vector<string> &uri_cameras, size_t pos1 = uri_cameras[c/2].find("node"); size_t pos2 = uri_cameras[c/2].find("#", pos1); node_name = uri_cameras[c/2].substr(pos1, pos2 - pos1); - + //LOG(INFO) << c << ":" << calib.getCameraMatNormalized(c, 1280, 720); + //LOG(INFO) << c + 1 << ":" << calib.getCameraMatNormalized(c + 1, 1280, 720); if (params.save_extrinsic) { saveExtrinsics(params.output_path + node_name + "-extrinsic.yml", R_c1c2, T_c1c2, R1, R2, P1, P2, Q); LOG(INFO) << "Saved: " << params.output_path + node_name + "-extrinsic.yml"; @@ -295,7 +296,7 @@ void calibrateFromPath( const string &path, cv::FileStorage fs(path + filename, cv::FileStorage::READ); fs["uri"] >> uri_cameras; - //params.idx_cameras = {6, 7}; + //params.idx_cameras = {2, 3};//{0, 1, 4, 5, 6, 7, 8, 9, 10, 11}; params.idx_cameras.resize(uri_cameras.size() * 2); std::iota(params.idx_cameras.begin(), params.idx_cameras.end(), 0); diff --git a/applications/calibration-multi/src/multicalibrate.cpp b/applications/calibration-multi/src/multicalibrate.cpp index 1840e68275c24d9b6ac4538ba71d4713148da63c..074e778ed8323fed3f7a8625288b37f62e43f612 100644 --- a/applications/calibration-multi/src/multicalibrate.cpp +++ b/applications/calibration-multi/src/multicalibrate.cpp @@ -81,16 +81,18 @@ double CalibrationTarget::estimateScale(vector<Point3d> points) { } MultiCameraCalibrationNew::MultiCameraCalibrationNew( - size_t n_cameras, size_t reference_camera, CalibrationTarget target, int fix_intrinsics) : + size_t n_cameras, size_t reference_camera, Size resolution, + CalibrationTarget target, int fix_intrinsics) : target_(target), visibility_graph_(n_cameras), is_calibrated_(false), n_cameras_(n_cameras), reference_camera_(reference_camera), - min_visible_points_(25), + min_visible_points_(50), fix_intrinsics_(fix_intrinsics == 1 ? 5 : 0), + resolution_(resolution), K_(n_cameras), dist_coeffs_(n_cameras), R_(n_cameras), @@ -116,6 +118,23 @@ Mat MultiCameraCalibrationNew::getCameraMat(size_t idx) { return K; } + +Mat MultiCameraCalibrationNew::getCameraMatNormalized(size_t idx, double scale_x, double scale_y) +{ + Mat K = getCameraMat(idx); + CHECK((scale_x != 0.0 && scale_y != 0.0) || ((scale_x == 0.0) && scale_y == 0.0)); + + scale_x = scale_x / (double) resolution_.width; + scale_y = scale_y / (double) resolution_.height; + + Mat scale(Size(3, 3), CV_64F, 0.0); + scale.at<double>(0, 0) = scale_x; + scale.at<double>(1, 1) = scale_y; + scale.at<double>(2, 2) = 1.0; + + return (scale * K); +} + Mat MultiCameraCalibrationNew::getDistCoeffs(size_t idx) { DCHECK(idx < n_cameras_); Mat D; @@ -149,6 +168,7 @@ void MultiCameraCalibrationNew::addPoints(vector<vector<Point2d>> points, vector void MultiCameraCalibrationNew::reset() { is_calibrated_ = false; + weights_ = vector(n_cameras_, vector(points2d_[0].size(), 0.0)); inlier_ = vector(n_cameras_, vector(points2d_[0].size(), 0)); points3d_ = vector(n_cameras_, vector(points2d_[0].size(), Point3d())); points3d_optimized_ = vector(points2d_[0].size(), Point3d()); @@ -163,6 +183,7 @@ void MultiCameraCalibrationNew::saveInput(const string &filename) { } void MultiCameraCalibrationNew::saveInput(cv::FileStorage &fs) { + fs << "resolution" << resolution_; fs << "K" << K_; fs << "points2d" << points2d_; fs << "visible" << visible_; @@ -182,6 +203,7 @@ void MultiCameraCalibrationNew::loadInput(const std::string &filename, const vec fs["K"] >> K; fs["points2d"] >> points2d; fs["visible"] >> visible; + fs["resolution"] >> resolution_; fs.release(); vector<size_t> cameras; @@ -287,13 +309,13 @@ void MultiCameraCalibrationNew::updatePoints3D(size_t camera, Point3d new_point, // instead store all triangulations and handle outliers // (perhaps inverse variance weighted mean?) - if (euclideanDistance(point, new_point) > 1.0) { + if (euclideanDistance(point, new_point) > 10.0) { LOG(ERROR) << "bad value (skipping) " << "(" << point << " vs " << new_point << ")"; f = -1; } else { point = (point * f + new_point) / (double) (f + 1); - f = f + 1; + f++; } } else { @@ -365,8 +387,8 @@ double MultiCameraCalibrationNew::calibratePair(size_t camera_from, size_t camer // cameras possibly lack line of sight? DCHECK(points1.size() > 8); - Mat K1 = K_[camera_from]; - Mat K2 = K_[camera_to]; + Mat &K1 = K_[camera_from]; + Mat &K2 = K_[camera_to]; vector<uchar> inliers; Mat F, E; @@ -462,12 +484,12 @@ double MultiCameraCalibrationNew::calibratePair(size_t camera_from, size_t camer // Bundle Adjustment // vector<Point3d> points3d_triangulated; // points3d_triangulated.insert(points3d_triangulated.begin(), points3d.begin(), points3d.end()); - + LOG(INFO) << K1; double err; cvsba::Sba sba; { - sba.setParams(cvsba::Sba::Params(cvsba::Sba::TYPE::MOTION, 200, 1.0e-30, fix_intrinsics_, 5, false)); - + sba.setParams(cvsba::Sba::Params(cvsba::Sba::TYPE::MOTIONSTRUCTURE, 200, 1.0e-30, 5, 5, false)); + Mat rvec1, rvec2; cv::Rodrigues(R1, rvec1); cv::Rodrigues(R2, rvec2); @@ -488,16 +510,21 @@ double MultiCameraCalibrationNew::calibratePair(size_t camera_from, size_t camer cv::Rodrigues(r[1], R2); t1 = t[0]; t2 = t[1]; - err = sba.getFinalReprjError(); + // intrinsic parameters should only be optimized at final BA + //K1 = K[0]; + //K2 = K[1]; + + err = sba.getFinalReprjError(); LOG(INFO) << "SBA reprojection error before BA " << sba.getInitialReprjError(); LOG(INFO) << "SBA reprojection error after BA " << err; } calculateTransform(R2, t2, R1, t1, rmat, tvec); - + // Store and average 3D points for both cameras (skip garbage) if (err < 10.0) { + Mat rmat1, tvec1; updatePoints3D(camera_from, points3d, idx, R1, t1); updatePoints3D(camera_to, points3d, idx, R2, t2); } @@ -507,11 +534,8 @@ double MultiCameraCalibrationNew::calibratePair(size_t camera_from, size_t camer << "), not updating points!"; } - // LOG(INFO) << "Final error: " << reprojectionError(points3d, points2, K2, rmat, tvec); - //if (reprojectionError(points3d, points2, K2, rmat, tvec) > 10.0) { - // TODO: should ignore results - // LOG(ERROR) << "pairwise calibration failed! RMS: " << reprojectionError(points3d, points2, K2, rmat, tvec); - //}; + //LOG(INFO) << reprojectionError(points3d, points1, K1, R1, t1); + //LOG(INFO) << reprojectionError(points3d, points2, K2, R2, t2); return err; } @@ -598,16 +622,26 @@ double MultiCameraCalibrationNew::calibrateAll(int reference_camera) { ); continue; } - LOG(INFO) << "Running pairwise calibration for cameras " << c1 << " and " << c2; + size_t n_visible = getVisiblePointsCount({c1, c2}); - - if (n_visible < min_visible_points_) continue; + + if (n_visible < min_visible_points_) { + LOG(INFO) << "Not enough (" << min_visible_points_ << ") points between " + << "cameras " << c1 << " and " << c2 << " (" << n_visible << " points), " + << "skipping"; + continue; + } + LOG(INFO) << "Running pairwise calibration for cameras " + << c1 << " and " << c2 << "(" << n_visible << " points)"; + if (transformations.find(make_pair(c2, c1)) != transformations.end()) { continue; } Mat R, t, R_i, t_i; - if (calibratePair(c1, c2, R, t) > 10.0) { + // TODO: threshold parameter, 16.0 possibly too high + + if (calibratePair(c1, c2, R, t) > 16.0) { LOG(ERROR) << "Pairwise calibration failed, skipping cameras " << c1 << " and " << c2; continue; diff --git a/applications/calibration-multi/src/multicalibrate.hpp b/applications/calibration-multi/src/multicalibrate.hpp index e739bc0d9b60d42b6ded37f51dc0a0fa9742e8b5..0168e107d69730e72bcd60790e550c19ca16439a 100644 --- a/applications/calibration-multi/src/multicalibrate.hpp +++ b/applications/calibration-multi/src/multicalibrate.hpp @@ -34,7 +34,8 @@ private: class MultiCameraCalibrationNew { public: MultiCameraCalibrationNew( size_t n_cameras, size_t reference_camera, - CalibrationTarget target, int fix_intrinsics=1); + Size resolution, CalibrationTarget target, + int fix_intrinsics=1); void setCameraParameters(size_t idx, const Mat &K, const Mat &distCoeffs); void setCameraParameters(size_t idx, const Mat &K); @@ -56,6 +57,8 @@ public: void saveInput(const std::string &filename); Mat getCameraMat(size_t idx); + Mat getCameraMatNormalized(size_t idx, double scale_x = 1.0, double scale_y = 1.0); + Mat getDistCoeffs(size_t idx); double calibrateAll(int reference_camera = -1); @@ -133,6 +136,7 @@ private: size_t min_visible_points_; int fix_intrinsics_; + Size resolution_; vector<Mat> K_; vector<Mat> dist_coeffs_; vector<Mat> R_; @@ -143,6 +147,7 @@ private: vector<vector<Point2d>> points2d_; vector<vector<int>> visible_; vector<vector<int>> inlier_; // "inlier" + vector<vector<double>> weights_; int fm_method_; double fm_ransac_threshold_; diff --git a/applications/calibration/src/common.cpp b/applications/calibration/src/common.cpp index 49967754dc0dd4f6665db7dae9bd9c5e965e35d3..0098bba58c5e6cbcbc0b75185f4286894447f16c 100644 --- a/applications/calibration/src/common.cpp +++ b/applications/calibration/src/common.cpp @@ -89,7 +89,7 @@ bool loadIntrinsics(const string &ifile, vector<Mat> &K1, vector<Mat> &D1) { LOG(INFO) << "Intrinsics from: " << ifile; - fs["M"] >> K1; + fs["K"] >> K1; fs["D"] >> D1; return true; diff --git a/applications/calibration/src/lens.cpp b/applications/calibration/src/lens.cpp index 5d47043fd47fea2821ead3d0905886510a5a9a02..f793dbfc6907b79ac65dfcbcf4a921884e6ca5cc 100644 --- a/applications/calibration/src/lens.cpp +++ b/applications/calibration/src/lens.cpp @@ -33,12 +33,13 @@ void ftl::calibration::intrinsic(map<string, string> &opt) { const Size image_size = Size( getOptionInt(opt, "width", 1280), getOptionInt(opt, "height", 720)); const int n_cameras = getOptionInt(opt, "n_cameras", 2); - const int iter = getOptionInt(opt, "iter", 60); - const int delay = getOptionInt(opt, "delay", 750); + const int iter = getOptionInt(opt, "iter", 40); + const int delay = getOptionInt(opt, "delay", 1000); const double aperture_width = getOptionDouble(opt, "aperture_width", 6.2); const double aperture_height = getOptionDouble(opt, "aperture_height", 4.6); const string filename_intrinsics = getOptionString(opt, "profile", FTL_LOCAL_CONFIG_ROOT "/intrinsics.yml"); CalibrationChessboard calib(opt); + const bool use_guess = getOptionInt(opt, "use_guess", 1); LOG(INFO) << "Intrinsic calibration parameters"; LOG(INFO) << " profile: " << filename_intrinsics; @@ -49,12 +50,25 @@ void ftl::calibration::intrinsic(map<string, string> &opt) { LOG(INFO) << " delay: " << delay; LOG(INFO) << " aperture_width: " << aperture_width; LOG(INFO) << " aperture_height: " << aperture_height; + LOG(INFO) << " use_guess: " << use_guess; LOG(INFO) << "-----------------------------------"; - int calibrate_flags = cv::CALIB_ZERO_TANGENT_DIST | cv::CALIB_FIX_ASPECT_RATIO | - cv::CALIB_FIX_PRINCIPAL_POINT; + int calibrate_flags = cv::CALIB_ZERO_TANGENT_DIST | cv::CALIB_FIX_ASPECT_RATIO; + if (use_guess) { calibrate_flags |= cv::CALIB_USE_INTRINSIC_GUESS; } + // cv::CALIB_FIX_PRINCIPAL_POINT; // PARAMETERS + + vector<Mat> camera_matrix(n_cameras), dist_coeffs(n_cameras); + + if (use_guess) { + camera_matrix.clear(); + vector<Mat> tmp; + //dist_coeffs.clear(); + loadIntrinsics(filename_intrinsics, camera_matrix, tmp); + CHECK(camera_matrix.size() == n_cameras); // (camera_matrix.size() == dist_coeffs.size()) + } + vector<cv::VideoCapture> cameras; cameras.reserve(n_cameras); for (int c = 0; c < n_cameras; c++) { cameras.emplace_back(c); } @@ -102,8 +116,6 @@ void ftl::calibration::intrinsic(map<string, string> &opt) { cv::waitKey(delay); } - - vector<Mat> camera_matrix(n_cameras), dist_coeffs(n_cameras); for (int c = 0; c < n_cameras; c++) { LOG(INFO) << "Calculating intrinsic paramters for camera " << std::to_string(c); diff --git a/components/rgbd-sources/src/calibrate.cpp b/components/rgbd-sources/src/calibrate.cpp index c31fea5c5c2b7885b450a0ebcd51f6e0540dd67f..df7fac455b68d8ee326957053ae99da946aa941f 100644 --- a/components/rgbd-sources/src/calibrate.cpp +++ b/components/rgbd-sources/src/calibrate.cpp @@ -89,6 +89,8 @@ bool Calibrate::_loadCalibration(cv::Size img_size, std::pair<Mat, Mat> &map1, s D[1].copyTo(D2_); } + fs.release(); + CHECK(M1_.size() == Size(3, 3)); CHECK(M2_.size() == Size(3, 3)); CHECK(D1_.size() == Size(5, 1)); @@ -116,15 +118,18 @@ bool Calibrate::_loadCalibration(cv::Size img_size, std::pair<Mat, Mat> &map1, s fs["P1"] >> P1_; fs["P2"] >> P2_; fs["Q"] >> Q_; + + fs.release(); + img_size_ = img_size; // TODO: normalize calibration - double scale_x = 1.0 / 1280.0; - double scale_y = 1.0 / 720.0; - + double scale_x = ((double) img_size.width) / 1280.0; + double scale_y = ((double) img_size.height) / 720.0; + Mat scale(cv::Size(3, 3), CV_64F, 0.0); - scale.at<double>(0, 0) = (double) img_size.width * scale_x; - scale.at<double>(1, 1) = (double) img_size.height * scale_y; + scale.at<double>(0, 0) = scale_x; + scale.at<double>(1, 1) = scale_y; scale.at<double>(2, 2) = 1.0; M1_ = scale * M1_; @@ -132,9 +137,10 @@ bool Calibrate::_loadCalibration(cv::Size img_size, std::pair<Mat, Mat> &map1, s P1_ = scale * P1_; P2_ = scale * P2_; - Q_.at<double>(0, 3) = Q_.at<double>(3, 2) * (double) img_size.width * scale_x; - Q_.at<double>(1, 3) = Q_.at<double>(3, 2) * (double) img_size.height * scale_y; - Q_.at<double>(3, 3) = Q_.at<double>(3, 3) * (double) img_size.width * scale_x; + Q_.at<double>(0, 3) = Q_.at<double>(0, 3) * scale_x; + Q_.at<double>(1, 3) = Q_.at<double>(1, 3) * scale_y; + Q_.at<double>(2, 3) = Q_.at<double>(2, 3) * scale_x; // TODO: scaling? + Q_.at<double>(3, 3) = Q_.at<double>(3, 3) * scale_x; // cv::cuda::remap() works only with CV_32FC1 initUndistortRectifyMap(M1_, D1_, R1_, P1_, img_size_, CV_32FC1, map1.first, map2.first);