diff --git a/cv-node/include/ftl/calibrate.hpp b/cv-node/include/ftl/calibrate.hpp index e8d450828f4836afd821de910f21a5da1e98e192..6ddf9a4793c1f8e83dc72f95e7862c23cb069044 100644 --- a/cv-node/include/ftl/calibrate.hpp +++ b/cv-node/include/ftl/calibrate.hpp @@ -76,7 +76,8 @@ class Calibrate { private: bool runCalibration(cv::Mat &img, cv::Mat &cam); - bool _recalibrate(size_t cam); + bool _recalibrate(size_t cam, std::vector<std::vector<cv::Point2f>> &imagePoints, + cv::Mat &cameraMatrix, cv::Mat &distCoeffs, cv::Size &imageSize); cv::Mat _nextImage(size_t cam); private: diff --git a/cv-node/include/ftl/local.hpp b/cv-node/include/ftl/local.hpp index 3ab86a2fb132c4dfd02aa3537b4d142cbcec147e..13196dd9e3231661b9f42525d24ab5051c411a68 100644 --- a/cv-node/include/ftl/local.hpp +++ b/cv-node/include/ftl/local.hpp @@ -11,8 +11,8 @@ namespace cv { namespace ftl { class LocalSource { public: - LocalSource(); - LocalSource(const std::string &vid); + LocalSource(bool flip=false); + LocalSource(const std::string &vid, bool flip=false); bool left(cv::Mat &m); bool right(cv::Mat &m); @@ -29,6 +29,7 @@ class LocalSource { double timestamp_; bool stereo_; //float fps_; + bool flip_; cv::VideoCapture *camera_a_; cv::VideoCapture *camera_b_; }; diff --git a/cv-node/src/calibrate.cpp b/cv-node/src/calibrate.cpp index 16f71b4031e746dd4ce8d1026504994e6b637166..c54eecf944cb60756197ade38ca40260c8b7792b 100644 --- a/cv-node/src/calibrate.cpp +++ b/cv-node/src/calibrate.cpp @@ -186,28 +186,100 @@ Calibrate::Calibrate(ftl::LocalSource *s, const std::string &cal) : local_(s) { map1_.resize(2); map2_.resize(2); + // TODO Load existing calibration if available... + calibrated_ = false; } bool Calibrate::recalibrate() { - bool r = _recalibrate(0); - if (local_->isStereo()) r &= _recalibrate(1); + vector<vector<Point2f> > imagePoints[2]; + Mat cameraMatrix[2], distCoeffs[2]; + Size imageSize[2]; + + bool r = _recalibrate(0, imagePoints[0], cameraMatrix[0], distCoeffs[0], imageSize[0]); + if (local_->isStereo()) r &= _recalibrate(1, imagePoints[1], cameraMatrix[1], distCoeffs[1], imageSize[1]); if (r) calibrated_ = true; + if (r && local_->isStereo()) { + int nimages = static_cast<int>(imagePoints[0].size()); + auto squareSize = settings_.squareSize; + vector<vector<Point3f>> objectPoints; + objectPoints.resize(nimages); + + for(auto i = 0; i < nimages; i++ ) + { + for(auto j = 0; j < settings_.boardSize.height; j++ ) + for(auto k = 0; k < settings_.boardSize.width; k++ ) + objectPoints[i].push_back(Point3f(k*squareSize, j*squareSize, 0)); + } + + Mat R, T, E, F; + + LOG(INFO) << "Running stereo calibration..."; + + double rms = stereoCalibrate(objectPoints, imagePoints[0], imagePoints[1], + cameraMatrix[0], distCoeffs[0], + cameraMatrix[1], distCoeffs[1], + imageSize[0], R, T, E, F, + CALIB_FIX_ASPECT_RATIO + + CALIB_ZERO_TANGENT_DIST + + CALIB_USE_INTRINSIC_GUESS + + CALIB_SAME_FOCAL_LENGTH + + CALIB_RATIONAL_MODEL + + CALIB_FIX_K3 + CALIB_FIX_K4 + CALIB_FIX_K5, + TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 100, 1e-5) ); + LOG(INFO) << "... done with RMS error=" << rms; + + // save intrinsic parameters + FileStorage fs(FTL_CONFIG_ROOT "/intrinsics.yml", FileStorage::WRITE); + if( fs.isOpened() ) + { + fs << "M1" << cameraMatrix[0] << "D1" << distCoeffs[0] << + "M2" << cameraMatrix[1] << "D2" << distCoeffs[1]; + fs.release(); + } + else + cout << "Error: can not save the intrinsic parameters\n"; + + Mat R1, R2, P1, P2, Q; + Rect validRoi[2]; + + stereoRectify(cameraMatrix[0], distCoeffs[0], + cameraMatrix[1], distCoeffs[1], + imageSize[0], R, T, R1, R2, P1, P2, Q, + CALIB_ZERO_DISPARITY, 1, imageSize[0], &validRoi[0], &validRoi[1]); + + fs.open(FTL_CONFIG_ROOT "/extrinsics.yml", FileStorage::WRITE); + if( fs.isOpened() ) + { + fs << "R" << R << "T" << T << "R1" << R1 << "R2" << R2 << "P1" << P1 << "P2" << P2 << "Q" << Q; + fs.release(); + } + else + cout << "Error: can not save the extrinsic parameters\n"; + + + //Precompute maps for cv::remap() + initUndistortRectifyMap(cameraMatrix[0], distCoeffs[0], R1, P1, imageSize[0], CV_16SC2, map1_[0], map2_[0]); + initUndistortRectifyMap(cameraMatrix[1], distCoeffs[1], R2, P2, imageSize[0], CV_16SC2, map1_[1], map2_[1]); + + } + return r; } -bool Calibrate::_recalibrate(size_t cam) { +bool Calibrate::_recalibrate(size_t cam, vector<vector<Point2f>> &imagePoints, + Mat &cameraMatrix, Mat &distCoeffs, Size &imageSize) { // TODO WHAT IS WINSIZE!! int winSize = 11; //parser.get<int>("winSize"); float grid_width = settings_.squareSize * (settings_.boardSize.width - 1); bool release_object = false; - vector<vector<Point2f> > imagePoints; - Mat cameraMatrix, distCoeffs; - Size imageSize; + //vector<vector<Point2f> > imagePoints; + //Mat cameraMatrix, distCoeffs; + //Size imageSize; int mode = CAPTURING; clock_t prevTimestamp = 0; const Scalar RED(0,0,255), GREEN(0,255,0); @@ -369,6 +441,7 @@ bool Calibrate::_recalibrate(size_t cam) { getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1, imageSize, 0), imageSize, CV_16SC2, map1_[cam], map2_[cam]); } + return true; } diff --git a/cv-node/src/local.cpp b/cv-node/src/local.cpp index 677c077295f373e2759734396e6bfc3e6aa91c90..075e19f394634cbe5c36de6dfc28cf0f18b7d752 100644 --- a/cv-node/src/local.cpp +++ b/cv-node/src/local.cpp @@ -13,10 +13,10 @@ using cv::Rect; using std::string; using namespace std::chrono; -LocalSource::LocalSource() : timestamp_(0.0) { +LocalSource::LocalSource(bool flip) : timestamp_(0.0), flip_(flip) { // Use cameras - camera_a_ = new VideoCapture(0); - camera_b_ = new VideoCapture(1); + camera_a_ = new VideoCapture((flip) ? 1 : 0); + camera_b_ = new VideoCapture((flip) ? 0 : 1); if (!camera_a_->isOpened()) { delete camera_a_; @@ -37,7 +37,7 @@ LocalSource::LocalSource() : timestamp_(0.0) { } } -LocalSource::LocalSource(const string &vid): timestamp_(0.0) { +LocalSource::LocalSource(const string &vid, bool flip): timestamp_(0.0), flip_(flip) { if (vid == "") { LOG(FATAL) << "No video file specified"; camera_a_ = nullptr; @@ -93,7 +93,11 @@ bool LocalSource::left(cv::Mat &l) { } int resx = frame.cols / 2; - l = Mat(frame, Rect(0,0,resx,frame.rows)); + if (flip_) { + l = Mat(frame, Rect(resx,0,frame.cols-resx,frame.rows)); + } else { + l = Mat(frame, Rect(0,0,resx,frame.rows)); + } } return true; @@ -127,7 +131,11 @@ bool LocalSource::right(cv::Mat &r) { } int resx = frame.cols / 2; - r = Mat(frame, Rect(resx,0,frame.cols-resx,frame.rows)); + if (flip_) { + r = Mat(frame, Rect(0,0,resx,frame.rows)); + } else { + r = Mat(frame, Rect(resx,0,frame.cols-resx,frame.rows)); + } } return true; @@ -166,8 +174,13 @@ bool LocalSource::get(cv::Mat &l, cv::Mat &r) { } int resx = frame.cols / 2; - l = Mat(frame, Rect(0,0,resx,frame.rows)); - r = Mat(frame, Rect(resx,0,frame.cols-resx,frame.rows)); + if (flip_) { + r = Mat(frame, Rect(0,0,resx,frame.rows)); + l = Mat(frame, Rect(resx,0,frame.cols-resx,frame.rows)); + } else { + l = Mat(frame, Rect(0,0,resx,frame.rows)); + r = Mat(frame, Rect(resx,0,frame.cols-resx,frame.rows)); + } } return true; diff --git a/cv-node/src/main.cpp b/cv-node/src/main.cpp index 82961d6c223cf970e4e895be719991df33b0562c..cc3e21921964767d3e4f3f02334f12f9cb4769e9 100644 --- a/cv-node/src/main.cpp +++ b/cv-node/src/main.cpp @@ -17,6 +17,7 @@ static string OPTION_calibration_config = FTL_CONFIG_ROOT "/calibration.xml"; static string OPTION_config; static bool OPTION_display = false; static bool OPTION_calibrate = false; +static bool OPTION_flip = false; void handle_options(char ***argv, int *argc) { while (*argc > 0) { @@ -39,6 +40,8 @@ void handle_options(char ***argv, int *argc) { OPTION_config = cmd; } else if (cmd.find("--display") == 0) { OPTION_display = true; + } else if (cmd.find("--flip") == 0) { + OPTION_flip = true; } (*argc)--; @@ -59,10 +62,10 @@ int main(int argc, char **argv) { if (argc) { // Load video file - lsrc = new LocalSource(argv[0]); + lsrc = new LocalSource(argv[0], OPTION_flip); } else { // Use cameras - lsrc = new LocalSource(); + lsrc = new LocalSource(OPTION_flip); } auto sync = new SyncSource(); // TODO Pass protocol object