From c971d70337f6981e5561e228de28913f83897575 Mon Sep 17 00:00:00 2001
From: Nicolas Pope <nwpope@utu.fi>
Date: Tue, 12 Mar 2019 10:48:19 +0200
Subject: [PATCH] Potentially working calibration code

---
 cv-node/CMakeLists.txt            |   2 +-
 cv-node/include/ftl/calibrate.hpp |  73 +++-
 cv-node/include/ftl/local.hpp     |   4 +-
 cv-node/src/calibrate.cpp         | 555 +++++++++++++-----------------
 cv-node/src/local.cpp             |  63 +++-
 cv-node/src/main.cpp              |   4 +-
 6 files changed, 372 insertions(+), 329 deletions(-)

diff --git a/cv-node/CMakeLists.txt b/cv-node/CMakeLists.txt
index 17f4d3d72..a5dfa5f78 100644
--- a/cv-node/CMakeLists.txt
+++ b/cv-node/CMakeLists.txt
@@ -33,7 +33,7 @@ endif (WIN32)
 
 if (UNIX)
 	add_definitions(-DUNIX)
-	set(FTL_CONFIG_ROOT "$ENV{HOME}/.config/ftl")
+	set(FTL_CONFIG_ROOT "\"$ENV{HOME}/.config/ftl\"")
 	set(FTL_CACHE_ROOT "$ENV{HOME}/.cache/ftl")
 	set(FTL_DATA_ROOT "$ENV{HOME}/.local/share/ftl")
 endif (UNIX)
diff --git a/cv-node/include/ftl/calibrate.hpp b/cv-node/include/ftl/calibrate.hpp
index fee7647e2..e8d450828 100644
--- a/cv-node/include/ftl/calibrate.hpp
+++ b/cv-node/include/ftl/calibrate.hpp
@@ -4,13 +4,70 @@
 #include <opencv2/opencv.hpp>
 #include <ftl/local.hpp>
 #include <string>
+#include <vector>
+
+namespace cv {
+class FileStorage;
+class FileNode;
+};
 
 namespace ftl {
 class Calibrate {
+	public:
+	class Settings {
+		public:
+		Settings() : goodInput(false) {}
+		enum Pattern { NOT_EXISTING, CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };
+		enum InputType { INVALID, CAMERA, VIDEO_FILE, IMAGE_LIST };
+
+		void write(cv::FileStorage& fs) const;
+		void read(const cv::FileNode& node);
+		void validate();
+		//Mat nextImage();
+
+		static bool readStringList( const std::string& filename, std::vector<std::string>& l );
+
+		static bool isListOfImages( const std::string& filename);
+		public:
+		cv::Size boardSize;              // The size of the board -> Number of items by width and height
+		Pattern calibrationPattern;  // One of the Chessboard, circles, or asymmetric circle pattern
+		float squareSize;            // The size of a square in your defined unit (point, millimeter,etc).
+		int nrFrames;                // The number of frames to use from the input for calibration
+		float aspectRatio;           // The aspect ratio
+		int delay;                   // In case of a video input
+		bool writePoints;            // Write detected feature points
+		bool writeExtrinsics;        // Write extrinsic parameters
+		bool writeGrid;              // Write refined 3D target grid points
+		bool calibZeroTangentDist;   // Assume zero tangential distortion
+		bool calibFixPrincipalPoint; // Fix the principal point at the center
+		bool flipVertical;           // Flip the captured images around the horizontal axis
+		std::string outputFileName;       // The name of the file where to write
+		bool showUndistorsed;        // Show undistorted images after calibration
+		std::string input;                // The input ->
+		bool useFisheye;             // use fisheye camera model for calibration
+		bool fixK1;                  // fix K1 distortion coefficient
+		bool fixK2;                  // fix K2 distortion coefficient
+		bool fixK3;                  // fix K3 distortion coefficient
+		bool fixK4;                  // fix K4 distortion coefficient
+		bool fixK5;                  // fix K5 distortion coefficient
+
+		int cameraID;
+		std::vector<std::string> imageList;
+		size_t atImageList;
+		//cv::VideoCapture inputCapture;
+		InputType inputType;
+		bool goodInput;
+		int flag;
+
+		private:
+		std::string patternToUse;
+
+
+	};
 	public:
 	Calibrate(ftl::LocalSource *s, const std::string &cal);
 	
-	bool recalibrate(const std::string &conf);
+	bool recalibrate();
 	
 	bool undistort(cv::Mat &l, cv::Mat &r);
 	bool rectified(cv::Mat &l, cv::Mat &r);
@@ -19,11 +76,25 @@ class Calibrate {
 	
 	private:
 	bool runCalibration(cv::Mat &img, cv::Mat &cam);
+	bool _recalibrate(size_t cam);
+	cv::Mat _nextImage(size_t cam);
 	
 	private:
 	ftl::LocalSource *local_;
+	Settings settings_;
+	bool calibrated_;
+	std::vector<cv::Mat> map1_;
+	std::vector<cv::Mat> map2_;
 };
 };
 
+/*static inline void read(const cv::FileNode& node, ftl::Calibrate::Settings& x, const ftl::Calibrate::Settings& default_value = ftl::Calibrate::Settings())
+{
+    if(node.empty())
+        x = default_value;
+    else
+        x.read(node);
+}*/
+
 #endif // _FTL_CALIBRATION_HPP_
 
diff --git a/cv-node/include/ftl/local.hpp b/cv-node/include/ftl/local.hpp
index 54f3f6916..3ab86a2fb 100644
--- a/cv-node/include/ftl/local.hpp
+++ b/cv-node/include/ftl/local.hpp
@@ -14,8 +14,8 @@ class LocalSource {
 	LocalSource();
 	LocalSource(const std::string &vid);
 	
-	//bool left(cv::Mat &m);
-	//bool right(cv::Mat &m);
+	bool left(cv::Mat &m);
+	bool right(cv::Mat &m);
 	bool get(cv::Mat &l, cv::Mat &r);
 	
 	//void setFramerate(float fps);
diff --git a/cv-node/src/calibrate.cpp b/cv-node/src/calibrate.cpp
index 16e88d7db..a659e659f 100644
--- a/cv-node/src/calibrate.cpp
+++ b/cv-node/src/calibrate.cpp
@@ -14,336 +14,238 @@
 #include <opencv2/videoio.hpp>
 #include <opencv2/highgui.hpp>
 
+#include <glog/logging.h>
+
 using namespace cv;
 using namespace std;
 
 using ftl::Calibrate;
 
-class Settings
-{
-public:
-    Settings() : goodInput(false) {}
-    enum Pattern { NOT_EXISTING, CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };
-    enum InputType { INVALID, CAMERA, VIDEO_FILE, IMAGE_LIST };
 
-    void write(FileStorage& fs) const                        //Write serialization for this class
+void Calibrate::Settings::write(FileStorage& fs) const                        //Write serialization for this class
+{
+    fs << "{"
+              << "BoardSize_Width"  << boardSize.width
+              << "BoardSize_Height" << boardSize.height
+              << "Square_Size"         << squareSize
+              << "Calibrate_Pattern" << patternToUse
+              << "Calibrate_NrOfFrameToUse" << nrFrames
+              << "Calibrate_FixAspectRatio" << aspectRatio
+              << "Calibrate_AssumeZeroTangentialDistortion" << calibZeroTangentDist
+              << "Calibrate_FixPrincipalPointAtTheCenter" << calibFixPrincipalPoint
+
+              << "Write_DetectedFeaturePoints" << writePoints
+              << "Write_extrinsicParameters"   << writeExtrinsics
+              << "Write_gridPoints" << writeGrid
+              //<< "Write_outputFileName"  << outputFileName
+
+              //<< "Show_UndistortedImage" << showUndistorsed
+
+              << "Input_FlipAroundHorizontalAxis" << flipVertical
+              << "Input_Delay" << delay
+              //<< "Input" << input
+       << "}";
+}
+void Calibrate::Settings::read(const FileNode& node)                          //Read serialization for this class
+{
+    node["BoardSize_Width" ] >> boardSize.width;
+    node["BoardSize_Height"] >> boardSize.height;
+    node["Calibrate_Pattern"] >> patternToUse;
+    node["Square_Size"]  >> squareSize;
+    node["Calibrate_NrOfFrameToUse"] >> nrFrames;
+    node["Calibrate_FixAspectRatio"] >> aspectRatio;
+    node["Write_DetectedFeaturePoints"] >> writePoints;
+    node["Write_extrinsicParameters"] >> writeExtrinsics;
+    node["Write_gridPoints"] >> writeGrid;
+    //node["Write_outputFileName"] >> outputFileName;
+    node["Calibrate_AssumeZeroTangentialDistortion"] >> calibZeroTangentDist;
+    node["Calibrate_FixPrincipalPointAtTheCenter"] >> calibFixPrincipalPoint;
+    node["Calibrate_UseFisheyeModel"] >> useFisheye;
+    node["Input_FlipAroundHorizontalAxis"] >> flipVertical;
+    //node["Show_UndistortedImage"] >> showUndistorsed;
+    //node["Input"] >> input;
+    node["Input_Delay"] >> delay;
+    node["Fix_K1"] >> fixK1;
+    node["Fix_K2"] >> fixK2;
+    node["Fix_K3"] >> fixK3;
+    node["Fix_K4"] >> fixK4;
+    node["Fix_K5"] >> fixK5;
+
+    validate();
+}
+void Calibrate::Settings::validate()
+{
+    goodInput = true;
+    if (boardSize.width <= 0 || boardSize.height <= 0)
     {
-        fs << "{"
-                  << "BoardSize_Width"  << boardSize.width
-                  << "BoardSize_Height" << boardSize.height
-                  << "Square_Size"         << squareSize
-                  << "Calibrate_Pattern" << patternToUse
-                  << "Calibrate_NrOfFrameToUse" << nrFrames
-                  << "Calibrate_FixAspectRatio" << aspectRatio
-                  << "Calibrate_AssumeZeroTangentialDistortion" << calibZeroTangentDist
-                  << "Calibrate_FixPrincipalPointAtTheCenter" << calibFixPrincipalPoint
-
-                  << "Write_DetectedFeaturePoints" << writePoints
-                  << "Write_extrinsicParameters"   << writeExtrinsics
-                  << "Write_gridPoints" << writeGrid
-                  << "Write_outputFileName"  << outputFileName
-
-                  << "Show_UndistortedImage" << showUndistorsed
-
-                  << "Input_FlipAroundHorizontalAxis" << flipVertical
-                  << "Input_Delay" << delay
-                  << "Input" << input
-           << "}";
+        LOG(ERROR) << "Invalid Board size: " << boardSize.width << " " << boardSize.height;
+        goodInput = false;
     }
-    void read(const FileNode& node)                          //Read serialization for this class
+    if (squareSize <= 10e-6)
     {
-        node["BoardSize_Width" ] >> boardSize.width;
-        node["BoardSize_Height"] >> boardSize.height;
-        node["Calibrate_Pattern"] >> patternToUse;
-        node["Square_Size"]  >> squareSize;
-        node["Calibrate_NrOfFrameToUse"] >> nrFrames;
-        node["Calibrate_FixAspectRatio"] >> aspectRatio;
-        node["Write_DetectedFeaturePoints"] >> writePoints;
-        node["Write_extrinsicParameters"] >> writeExtrinsics;
-        node["Write_gridPoints"] >> writeGrid;
-        node["Write_outputFileName"] >> outputFileName;
-        node["Calibrate_AssumeZeroTangentialDistortion"] >> calibZeroTangentDist;
-        node["Calibrate_FixPrincipalPointAtTheCenter"] >> calibFixPrincipalPoint;
-        node["Calibrate_UseFisheyeModel"] >> useFisheye;
-        node["Input_FlipAroundHorizontalAxis"] >> flipVertical;
-        node["Show_UndistortedImage"] >> showUndistorsed;
-        node["Input"] >> input;
-        node["Input_Delay"] >> delay;
-        node["Fix_K1"] >> fixK1;
-        node["Fix_K2"] >> fixK2;
-        node["Fix_K3"] >> fixK3;
-        node["Fix_K4"] >> fixK4;
-        node["Fix_K5"] >> fixK5;
-
-        validate();
+        LOG(ERROR) << "Invalid square size " << squareSize;
+        goodInput = false;
     }
-    void validate()
+    if (nrFrames <= 0)
     {
-        goodInput = true;
-        if (boardSize.width <= 0 || boardSize.height <= 0)
-        {
-            cerr << "Invalid Board size: " << boardSize.width << " " << boardSize.height << endl;
-            goodInput = false;
-        }
-        if (squareSize <= 10e-6)
-        {
-            cerr << "Invalid square size " << squareSize << endl;
-            goodInput = false;
-        }
-        if (nrFrames <= 0)
-        {
-            cerr << "Invalid number of frames " << nrFrames << endl;
-            goodInput = false;
-        }
-
-        if (input.empty())      // Check for valid input
-                inputType = INVALID;
-        else
-        {
-            if (input[0] >= '0' && input[0] <= '9')
-            {
-                stringstream ss(input);
-                ss >> cameraID;
-                inputType = CAMERA;
-            }
-            else
-            {
-                if (isListOfImages(input) && readStringList(input, imageList))
-                {
-                    inputType = IMAGE_LIST;
-                    nrFrames = (nrFrames < (int)imageList.size()) ? nrFrames : (int)imageList.size();
-                }
-                else
-                    inputType = VIDEO_FILE;
-            }
-            if (inputType == CAMERA)
-                inputCapture.open(cameraID);
-            if (inputType == VIDEO_FILE)
-                inputCapture.open(input);
-            if (inputType != IMAGE_LIST && !inputCapture.isOpened())
-                    inputType = INVALID;
-        }
-        if (inputType == INVALID)
-        {
-            cerr << " Input does not exist: " << input;
-            goodInput = false;
-        }
-
-        flag = 0;
-        if(calibFixPrincipalPoint) flag |= CALIB_FIX_PRINCIPAL_POINT;
-        if(calibZeroTangentDist)   flag |= CALIB_ZERO_TANGENT_DIST;
-        if(aspectRatio)            flag |= CALIB_FIX_ASPECT_RATIO;
-        if(fixK1)                  flag |= CALIB_FIX_K1;
-        if(fixK2)                  flag |= CALIB_FIX_K2;
-        if(fixK3)                  flag |= CALIB_FIX_K3;
-        if(fixK4)                  flag |= CALIB_FIX_K4;
-        if(fixK5)                  flag |= CALIB_FIX_K5;
-
-        if (useFisheye) {
-            // the fisheye model has its own enum, so overwrite the flags
-            flag = fisheye::CALIB_FIX_SKEW | fisheye::CALIB_RECOMPUTE_EXTRINSIC;
-            if(fixK1)                   flag |= fisheye::CALIB_FIX_K1;
-            if(fixK2)                   flag |= fisheye::CALIB_FIX_K2;
-            if(fixK3)                   flag |= fisheye::CALIB_FIX_K3;
-            if(fixK4)                   flag |= fisheye::CALIB_FIX_K4;
-            if (calibFixPrincipalPoint) flag |= fisheye::CALIB_FIX_PRINCIPAL_POINT;
-        }
-
-        calibrationPattern = NOT_EXISTING;
-        if (!patternToUse.compare("CHESSBOARD")) calibrationPattern = CHESSBOARD;
-        if (!patternToUse.compare("CIRCLES_GRID")) calibrationPattern = CIRCLES_GRID;
-        if (!patternToUse.compare("ASYMMETRIC_CIRCLES_GRID")) calibrationPattern = ASYMMETRIC_CIRCLES_GRID;
-        if (calibrationPattern == NOT_EXISTING)
-        {
-            cerr << " Camera calibration mode does not exist: " << patternToUse << endl;
-            goodInput = false;
-        }
-        atImageList = 0;
-
+        LOG(ERROR) << "Invalid number of frames " << nrFrames;
+        goodInput = false;
     }
-    Mat nextImage()
-    {
-        Mat result;
-        if( inputCapture.isOpened() )
-        {
-            Mat view0;
-            inputCapture >> view0;
-            view0.copyTo(result);
-        }
-        else if( atImageList < imageList.size() )
-            result = imread(imageList[atImageList++], IMREAD_COLOR);
 
-        return result;
+    flag = 0;
+    if(calibFixPrincipalPoint) flag |= CALIB_FIX_PRINCIPAL_POINT;
+    if(calibZeroTangentDist)   flag |= CALIB_ZERO_TANGENT_DIST;
+    if(aspectRatio)            flag |= CALIB_FIX_ASPECT_RATIO;
+    if(fixK1)                  flag |= CALIB_FIX_K1;
+    if(fixK2)                  flag |= CALIB_FIX_K2;
+    if(fixK3)                  flag |= CALIB_FIX_K3;
+    if(fixK4)                  flag |= CALIB_FIX_K4;
+    if(fixK5)                  flag |= CALIB_FIX_K5;
+
+    if (useFisheye) {
+        // the fisheye model has its own enum, so overwrite the flags
+        flag = fisheye::CALIB_FIX_SKEW | fisheye::CALIB_RECOMPUTE_EXTRINSIC;
+        if(fixK1)                   flag |= fisheye::CALIB_FIX_K1;
+        if(fixK2)                   flag |= fisheye::CALIB_FIX_K2;
+        if(fixK3)                   flag |= fisheye::CALIB_FIX_K3;
+        if(fixK4)                   flag |= fisheye::CALIB_FIX_K4;
+        if (calibFixPrincipalPoint) flag |= fisheye::CALIB_FIX_PRINCIPAL_POINT;
     }
 
-    static bool readStringList( const string& filename, vector<string>& l )
+    calibrationPattern = NOT_EXISTING;
+    if (!patternToUse.compare("CHESSBOARD")) calibrationPattern = CHESSBOARD;
+    if (!patternToUse.compare("CIRCLES_GRID")) calibrationPattern = CIRCLES_GRID;
+    if (!patternToUse.compare("ASYMMETRIC_CIRCLES_GRID")) calibrationPattern = ASYMMETRIC_CIRCLES_GRID;
+    if (calibrationPattern == NOT_EXISTING)
     {
-        l.clear();
-        FileStorage fs(filename, FileStorage::READ);
-        if( !fs.isOpened() )
-            return false;
-        FileNode n = fs.getFirstTopLevelNode();
-        if( n.type() != FileNode::SEQ )
-            return false;
-        FileNodeIterator it = n.begin(), it_end = n.end();
-        for( ; it != it_end; ++it )
-            l.push_back((string)*it);
-        return true;
+        LOG(ERROR) << " Camera calibration mode does not exist: " << patternToUse;
+        goodInput = false;
     }
+    atImageList = 0;
 
-    static bool isListOfImages( const string& filename)
-    {
-        string s(filename);
-        // Look for file extension
-        if( s.find(".xml") == string::npos && s.find(".yaml") == string::npos && s.find(".yml") == string::npos )
-            return false;
-        else
-            return true;
-    }
-public:
-    Size boardSize;              // The size of the board -> Number of items by width and height
-    Pattern calibrationPattern;  // One of the Chessboard, circles, or asymmetric circle pattern
-    float squareSize;            // The size of a square in your defined unit (point, millimeter,etc).
-    int nrFrames;                // The number of frames to use from the input for calibration
-    float aspectRatio;           // The aspect ratio
-    int delay;                   // In case of a video input
-    bool writePoints;            // Write detected feature points
-    bool writeExtrinsics;        // Write extrinsic parameters
-    bool writeGrid;              // Write refined 3D target grid points
-    bool calibZeroTangentDist;   // Assume zero tangential distortion
-    bool calibFixPrincipalPoint; // Fix the principal point at the center
-    bool flipVertical;           // Flip the captured images around the horizontal axis
-    string outputFileName;       // The name of the file where to write
-    bool showUndistorsed;        // Show undistorted images after calibration
-    string input;                // The input ->
-    bool useFisheye;             // use fisheye camera model for calibration
-    bool fixK1;                  // fix K1 distortion coefficient
-    bool fixK2;                  // fix K2 distortion coefficient
-    bool fixK3;                  // fix K3 distortion coefficient
-    bool fixK4;                  // fix K4 distortion coefficient
-    bool fixK5;                  // fix K5 distortion coefficient
-
-    int cameraID;
-    vector<string> imageList;
-    size_t atImageList;
-    VideoCapture inputCapture;
-    InputType inputType;
-    bool goodInput;
-    int flag;
-
-private:
-    string patternToUse;
-
-
-};
-
-static inline void read(const FileNode& node, Settings& x, const Settings& default_value = Settings())
-{
-    if(node.empty())
-        x = default_value;
-    else
-        x.read(node);
-}
-
-Calibrate::Calibrate(ftl::LocalSource *s, const std::string &cal) : local_(s) {
-
-}
-	
-bool Calibrate::recalibrate(const std::string &conf) {
-	return false;
 }
-
-bool Calibrate::undistort(cv::Mat &l, cv::Mat &r) {
-	local_->get(l,r);
-	return false;
+Mat Calibrate::_nextImage(size_t cam)
+{
+    Mat result;
+    if (cam == 0) {
+    	local_->left(result);
+    } else if (cam == 1 && local_->isStereo()) {
+    	local_->right(result);
+    }
+    return result;
 }
 
-bool Calibrate::rectified(cv::Mat &l, cv::Mat &r) {
-	return undistort(l,r);
+bool Calibrate::Settings::readStringList( const string& filename, vector<string>& l )
+{
+    l.clear();
+    FileStorage fs(filename, FileStorage::READ);
+    if( !fs.isOpened() )
+        return false;
+    FileNode n = fs.getFirstTopLevelNode();
+    if( n.type() != FileNode::SEQ )
+        return false;
+    FileNodeIterator it = n.begin(), it_end = n.end();
+    for( ; it != it_end; ++it )
+        l.push_back((string)*it);
+    return true;
 }
 
-bool Calibrate::isCalibrated() {
-	return false;
+bool Calibrate::Settings::isListOfImages( const string& filename)
+{
+    string s(filename);
+    // Look for file extension
+    if( s.find(".xml") == string::npos && s.find(".yaml") == string::npos && s.find(".yml") == string::npos )
+        return false;
+    else
+        return true;
 }
 
 enum { DETECTION = 0, CAPTURING = 1, CALIBRATED = 2 };
 
-bool runCalibrationAndSave(Settings& s, Size imageSize, Mat&  cameraMatrix, Mat& distCoeffs,
+bool runCalibrationAndSave(Calibrate::Settings& s, Size imageSize, Mat&  cameraMatrix, Mat& distCoeffs,
                            vector<vector<Point2f> > imagePoints, float grid_width, bool release_object);
 
-int main2(int argc, char* argv[])
-{
-
 
-    //! [file_read]
-    Settings s;
-    const string inputSettingsFile = parser.get<string>(0);
-    FileStorage fs(inputSettingsFile, FileStorage::READ); // Read the settings
+Calibrate::Calibrate(ftl::LocalSource *s, const std::string &cal) : local_(s) {
+    FileStorage fs(cal, FileStorage::READ); // Read the settings
     if (!fs.isOpened())
     {
-        cout << "Could not open the configuration file: \"" << inputSettingsFile << "\"" << endl;
-        parser.printMessage();
-        return -1;
+        LOG(ERROR) << "Could not open the configuration file: \"" << cal << "\"";
+        return;
     }
-    fs["Settings"] >> s;
-    fs.release();                                         // close Settings file
-    //! [file_read]
-
-    //FileStorage fout("settings.yml", FileStorage::WRITE); // write config as YAML
-    //fout << "Settings" << s;
-
-    if (!s.goodInput)
+    //fs["Settings"] >> settings_;
+    settings_.read(fs["Settings"]);
+    fs.release();
+    
+    if (!settings_.goodInput)
     {
-        cout << "Invalid input detected. Application stopping. " << endl;
-        return -1;
+        LOG(ERROR) << "Invalid input detected. Application stopping.";
+        return;
     }
+    
+    map1_.resize(2);
+    map2_.resize(2);
+    
+    calibrated_ = false;
+}
 
-    int winSize = parser.get<int>("winSize");
+bool Calibrate::recalibrate() {
+	bool r = _recalibrate(0);
+	if (local_->isStereo()) r |= _recalibrate(1);
+	
+	if (r) calibrated_ = true;
+	
+	return r;
+}
 
-    float grid_width = s.squareSize * (s.boardSize.width - 1);
+bool Calibrate::_recalibrate(size_t cam) {
+	// TODO WHAT IS WINSIZE!!
+	int winSize = 11; //parser.get<int>("winSize");
+
+    float grid_width = settings_.squareSize * (settings_.boardSize.width - 1);
     bool release_object = false;
-    if (parser.has("d")) {
-        grid_width = parser.get<float>("d");
-        release_object = true;
-    }
 
     vector<vector<Point2f> > imagePoints;
     Mat cameraMatrix, distCoeffs;
     Size imageSize;
-    int mode = s.inputType == Settings::IMAGE_LIST ? CAPTURING : DETECTION;
+    int mode = CAPTURING;
     clock_t prevTimestamp = 0;
     const Scalar RED(0,0,255), GREEN(0,255,0);
-    const char ESC_KEY = 27;
+    
+    settings_.outputFileName = string(FTL_CONFIG_ROOT "/calib_cam") + std::to_string(cam) + ".yml";
 
     //! [get_input]
     for(;;)
     {
         Mat view;
-        bool blinkOutput = false;
+        //bool blinkOutput = false;
 
-        view = s.nextImage();
+        view = _nextImage(cam);
+        LOG(INFO) << "Grabbing calibration image...";
 
         //-----  If no more image, or got enough, then stop calibration and show result -------------
-        if( mode == CAPTURING && imagePoints.size() >= (size_t)s.nrFrames )
+        if( mode == CAPTURING && imagePoints.size() >= (size_t)settings_.nrFrames )
         {
-          if(runCalibrationAndSave(s, imageSize,  cameraMatrix, distCoeffs, imagePoints, grid_width,
-                                   release_object))
+          if(runCalibrationAndSave(settings_, imageSize,  cameraMatrix, distCoeffs, imagePoints, grid_width,
+                                   release_object)) {
+              LOG(INFO) << "Calibration completed";
               mode = CALIBRATED;
-          else
+        }  else
               mode = DETECTION;
         }
         if(view.empty())          // If there are no more images stop the loop
         {
+        	LOG(INFO) << "More calibration images are required";
             // if calibration threshold was not reached yet, calibrate now
             if( mode != CALIBRATED && !imagePoints.empty() )
-                runCalibrationAndSave(s, imageSize,  cameraMatrix, distCoeffs, imagePoints, grid_width,
+                runCalibrationAndSave(settings_, imageSize,  cameraMatrix, distCoeffs, imagePoints, grid_width,
                                       release_object);
             break;
         }
         //! [get_input]
 
         imageSize = view.size();  // Format input image.
-        if( s.flipVertical )    flip( view, view, 0 );
+        if( settings_.flipVertical )    flip( view, view, 0 );
 
         //! [find_pattern]
         vector<Point2f> pointBuf;
@@ -352,21 +254,21 @@ int main2(int argc, char* argv[])
 
         int chessBoardFlags = CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE;
 
-        if(!s.useFisheye) {
+        if(!settings_.useFisheye) {
             // fast check erroneously fails with high distortions like fisheye
             chessBoardFlags |= CALIB_CB_FAST_CHECK;
         }
 
-        switch( s.calibrationPattern ) // Find feature points on the input format
+        switch( settings_.calibrationPattern ) // Find feature points on the input format
         {
         case Settings::CHESSBOARD:
-            found = findChessboardCorners( view, s.boardSize, pointBuf, chessBoardFlags);
+            found = findChessboardCorners( view, settings_.boardSize, pointBuf, chessBoardFlags);
             break;
         case Settings::CIRCLES_GRID:
-            found = findCirclesGrid( view, s.boardSize, pointBuf );
+            found = findCirclesGrid( view, settings_.boardSize, pointBuf );
             break;
         case Settings::ASYMMETRIC_CIRCLES_GRID:
-            found = findCirclesGrid( view, s.boardSize, pointBuf, CALIB_CB_ASYMMETRIC_GRID );
+            found = findCirclesGrid( view, settings_.boardSize, pointBuf, CALIB_CB_ASYMMETRIC_GRID );
             break;
         default:
             found = false;
@@ -377,7 +279,7 @@ int main2(int argc, char* argv[])
         if ( found)                // If done with success,
         {
               // improve the found corners' coordinate accuracy for chessboard
-                if( s.calibrationPattern == Settings::CHESSBOARD)
+                if( settings_.calibrationPattern == Settings::CHESSBOARD)
                 {
                     Mat viewGray;
                     cvtColor(view, viewGray, COLOR_BGR2GRAY);
@@ -386,20 +288,22 @@ int main2(int argc, char* argv[])
                 }
 
                 if( mode == CAPTURING &&  // For camera only take new samples after delay time
-                    (!s.inputCapture.isOpened() || clock() - prevTimestamp > s.delay*1e-3*CLOCKS_PER_SEC) )
+                    (clock() - prevTimestamp > settings_.delay*1e-3*CLOCKS_PER_SEC) )
                 {
                     imagePoints.push_back(pointBuf);
                     prevTimestamp = clock();
-                    blinkOutput = s.inputCapture.isOpened();
+                   // blinkOutput = s.inputCapture.isOpened();
                 }
 
                 // Draw the corners.
-                drawChessboardCorners( view, s.boardSize, Mat(pointBuf), found );
+                drawChessboardCorners( view, settings_.boardSize, Mat(pointBuf), found );
+        } else {
+        	LOG(WARNING) << "No calibration pattern found";
         }
         //! [pattern_found]
         //----------------------------- Output Text ------------------------------------------------
         //! [output_text]
-        string msg = (mode == CAPTURING) ? "100/100" :
+        /*string msg = (mode == CAPTURING) ? "100/100" :
                       mode == CALIBRATED ? "Calibrated" : "Press 'g' to start";
         int baseLine = 0;
         Size textSize = getTextSize(msg, 1, 1, 1, &baseLine);
@@ -416,75 +320,76 @@ int main2(int argc, char* argv[])
         putText( view, msg, textOrigin, 1, 1, mode == CALIBRATED ?  GREEN : RED);
 
         if( blinkOutput )
-            bitwise_not(view, view);
+            bitwise_not(view, view);*/
         //! [output_text]
         //------------------------- Video capture  output  undistorted ------------------------------
         //! [output_undistorted]
-        if( mode == CALIBRATED && s.showUndistorsed )
+        /*if( mode == CALIBRATED && settings_.showUndistorsed )
         {
             Mat temp = view.clone();
-            if (s.useFisheye)
+            if (settings_.useFisheye)
               cv::fisheye::undistortImage(temp, view, cameraMatrix, distCoeffs);
             else
-              undistort(temp, view, cameraMatrix, distCoeffs);
-        }
+              cv::undistort(temp, view, cameraMatrix, distCoeffs);
+        }*/
         //! [output_undistorted]
         //------------------------------ Show image and check for input commands -------------------
         //! [await_input]
-        imshow("Image View", view);
+        /*imshow("Image View", view);
         char key = (char)waitKey(s.inputCapture.isOpened() ? 50 : s.delay);
 
         if( key  == ESC_KEY )
             break;
 
         if( key == 'u' && mode == CALIBRATED )
-           s.showUndistorsed = !s.showUndistorsed;
+           s.showUndistorsed = !s.showUndistorsed;*/
 
-        if( s.inputCapture.isOpened() && key == 'g' )
+        /*if( s.inputCapture.isOpened() && key == 'g' )
         {
             mode = CAPTURING;
             imagePoints.clear();
-        }
+        }*/
         //! [await_input]
+        if (mode == CALIBRATED) break;
     }
+    
+    if (mode != CALIBRATED) return false;
+    
+    Mat view, rview;
 
-    // -----------------------Show the undistorted image for the image list ------------------------
-    //! [show_results]
-    if( s.inputType == Settings::IMAGE_LIST && s.showUndistorsed )
+    if (settings_.useFisheye)
+    {
+        Mat newCamMat;
+        fisheye::estimateNewCameraMatrixForUndistortRectify(cameraMatrix, distCoeffs, imageSize,
+                                                            Matx33d::eye(), newCamMat, 1);
+        fisheye::initUndistortRectifyMap(cameraMatrix, distCoeffs, Matx33d::eye(), newCamMat, imageSize,
+                                         CV_16SC2, map1_[cam], map2_[cam]);
+    }
+    else
     {
-        Mat view, rview, map1, map2;
+        initUndistortRectifyMap(
+            cameraMatrix, distCoeffs, Mat(),
+            getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1, imageSize, 0), imageSize,
+            CV_16SC2, map1_[cam], map2_[cam]);
+    }
+	return true;
+}
 
-        if (s.useFisheye)
-        {
-            Mat newCamMat;
-            fisheye::estimateNewCameraMatrixForUndistortRectify(cameraMatrix, distCoeffs, imageSize,
-                                                                Matx33d::eye(), newCamMat, 1);
-            fisheye::initUndistortRectifyMap(cameraMatrix, distCoeffs, Matx33d::eye(), newCamMat, imageSize,
-                                             CV_16SC2, map1, map2);
-        }
-        else
-        {
-            initUndistortRectifyMap(
-                cameraMatrix, distCoeffs, Mat(),
-                getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1, imageSize, 0), imageSize,
-                CV_16SC2, map1, map2);
-        }
+bool Calibrate::undistort(cv::Mat &l, cv::Mat &r) {
+	local_->get(l,r);
+	if (!calibrated_) return false;
+	if (l.empty()) return false;
+	remap(l, l, map1_[0], map2_[0], INTER_LINEAR);
+	if (local_->isStereo()) remap(r, r, map1_[1], map2_[1], INTER_LINEAR);
+	return true;
+}
 
-        for(size_t i = 0; i < s.imageList.size(); i++ )
-        {
-            view = imread(s.imageList[i], IMREAD_COLOR);
-            if(view.empty())
-                continue;
-            remap(view, rview, map1, map2, INTER_LINEAR);
-            imshow("Image View", rview);
-            char c = (char)waitKey();
-            if( c  == ESC_KEY || c == 'q' || c == 'Q' )
-                break;
-        }
-    }
-    //! [show_results]
+bool Calibrate::rectified(cv::Mat &l, cv::Mat &r) {
+	return undistort(l,r);
+}
 
-    return 0;
+bool Calibrate::isCalibrated() {
+	return calibrated_;
 }
 
 //! [compute_errors]
@@ -523,20 +428,20 @@ static double computeReprojectionErrors( const vector<vector<Point3f> >& objectP
 //! [compute_errors]
 //! [board_corners]
 static void calcBoardCornerPositions(Size boardSize, float squareSize, vector<Point3f>& corners,
-                                     Settings::Pattern patternType /*= Settings::CHESSBOARD*/)
+                                     Calibrate::Settings::Pattern patternType /*= Settings::CHESSBOARD*/)
 {
     corners.clear();
 
     switch(patternType)
     {
-    case Settings::CHESSBOARD:
-    case Settings::CIRCLES_GRID:
+    case Calibrate::Settings::CHESSBOARD:
+    case Calibrate::Settings::CIRCLES_GRID:
         for( int i = 0; i < boardSize.height; ++i )
             for( int j = 0; j < boardSize.width; ++j )
                 corners.push_back(Point3f(j*squareSize, i*squareSize, 0));
         break;
 
-    case Settings::ASYMMETRIC_CIRCLES_GRID:
+    case Calibrate::Settings::ASYMMETRIC_CIRCLES_GRID:
         for( int i = 0; i < boardSize.height; i++ )
             for( int j = 0; j < boardSize.width; j++ )
                 corners.push_back(Point3f((2*j + i % 2)*squareSize, i*squareSize, 0));
@@ -546,7 +451,7 @@ static void calcBoardCornerPositions(Size boardSize, float squareSize, vector<Po
     }
 }
 //! [board_corners]
-static bool runCalibration( Settings& s, Size& imageSize, Mat& cameraMatrix, Mat& distCoeffs,
+static bool runCalibration( Calibrate::Settings& s, Size& imageSize, Mat& cameraMatrix, Mat& distCoeffs,
                             vector<vector<Point2f> > imagePoints, vector<Mat>& rvecs, vector<Mat>& tvecs,
                             vector<float>& reprojErrs,  double& totalAvgErr, vector<Point3f>& newObjPoints,
                             float grid_width, bool release_object)
@@ -613,12 +518,14 @@ static bool runCalibration( Settings& s, Size& imageSize, Mat& cameraMatrix, Mat
 }
 
 // Print camera parameters to the output file
-static void saveCameraParams( Settings& s, Size& imageSize, Mat& cameraMatrix, Mat& distCoeffs,
+static void saveCameraParams( Calibrate::Settings& s, Size& imageSize, Mat& cameraMatrix, Mat& distCoeffs,
                               const vector<Mat>& rvecs, const vector<Mat>& tvecs,
                               const vector<float>& reprojErrs, const vector<vector<Point2f> >& imagePoints,
                               double totalAvgErr, const vector<Point3f>& newObjPoints )
 {
     FileStorage fs( s.outputFileName, FileStorage::WRITE );
+    
+    LOG(INFO) << "Saving calibration to " << s.outputFileName;
 
     time_t tm;
     time( &tm );
@@ -731,7 +638,7 @@ static void saveCameraParams( Settings& s, Size& imageSize, Mat& cameraMatrix, M
 }
 
 //! [run_and_save]
-bool runCalibrationAndSave(Settings& s, Size imageSize, Mat& cameraMatrix, Mat& distCoeffs,
+bool runCalibrationAndSave(Calibrate::Settings& s, Size imageSize, Mat& cameraMatrix, Mat& distCoeffs,
                            vector<vector<Point2f> > imagePoints, float grid_width, bool release_object)
 {
     vector<Mat> rvecs, tvecs;
@@ -743,6 +650,8 @@ bool runCalibrationAndSave(Settings& s, Size imageSize, Mat& cameraMatrix, Mat&
                              totalAvgErr, newObjPoints, grid_width, release_object);
     cout << (ok ? "Calibration succeeded" : "Calibration failed")
          << ". avg re projection error = " << totalAvgErr << endl;
+         
+	//return ok;
 
     if (ok)
         saveCameraParams(s, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs, reprojErrs, imagePoints,
diff --git a/cv-node/src/local.cpp b/cv-node/src/local.cpp
index 1c4ddd0bd..1a4618210 100644
--- a/cv-node/src/local.cpp
+++ b/cv-node/src/local.cpp
@@ -68,6 +68,67 @@ LocalSource::LocalSource(const string &vid): timestamp_(0.0) {
 	}
 }
 
+bool LocalSource::left(cv::Mat &l) {
+	if (!camera_a_) return false;
+	
+	if (!camera_a_->grab()) {
+		LOG(ERROR) << "Unable to grab from camera A";
+		return false;
+	}
+	
+	// Record timestamp
+	timestamp_ = duration_cast<duration<double>>(
+			high_resolution_clock::now().time_since_epoch()).count();
+
+	if (camera_b_ || !stereo_) {
+		if (!camera_a_->retrieve(l)) {
+			LOG(ERROR) << "Unable to read frame from camera A";
+			return false;
+		}
+	} else {
+		Mat frame;
+		if (!camera_a_->retrieve(frame)) {
+			LOG(ERROR) << "Unable to read frame from video";
+			return false;
+		}
+		
+		int resx = frame.cols / 2;
+		l = Mat(frame, Rect(0,0,resx,frame.rows));
+	}
+	
+	return true;
+}
+
+bool LocalSource::right(cv::Mat &r) {
+	if (camera_b_ && !camera_b_->grab()) {
+		LOG(ERROR) << "Unable to grab from camera B";
+		return false;
+	}
+	
+	// Record timestamp
+	timestamp_ = duration_cast<duration<double>>(
+			high_resolution_clock::now().time_since_epoch()).count();
+
+	if (camera_b_ || !stereo_) {
+		if (camera_b_ && !camera_b_->retrieve(r)) {
+			LOG(ERROR) << "Unable to read frame from camera B";
+			return false;
+		}
+	} else {
+		Mat frame;
+		if (!camera_a_) return false;
+		if (!camera_a_->retrieve(frame)) {
+			LOG(ERROR) << "Unable to read frame from video";
+			return false;
+		}
+		
+		int resx = frame.cols / 2;
+		r = Mat(frame, Rect(resx,0,frame.cols-resx,frame.rows));
+	}
+	
+	return true;
+}
+
 bool LocalSource::get(cv::Mat &l, cv::Mat &r) {
 	if (!camera_a_) return false;
 	
@@ -102,7 +163,7 @@ 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,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 bf4221399..b7d32c6d2 100644
--- a/cv-node/src/main.cpp
+++ b/cv-node/src/main.cpp
@@ -13,7 +13,7 @@ using cv::Mat;
 
 static vector<string> OPTION_peers;
 static vector<string> OPTION_channels;
-static string OPTION_calibration_config;
+static string OPTION_calibration_config = FTL_CONFIG_ROOT "/calibration.xml";
 static string OPTION_config;
 static bool OPTION_display = false;
 static bool OPTION_calibrate = false;
@@ -73,6 +73,8 @@ int main(int argc, char **argv) {
 	
 	Calibrate calibrate(lsrc, OPTION_calibration_config);
 	
+	if (!calibrate.isCalibrated()) calibrate.recalibrate();
+	
 	while (true) {
 		Mat l, r;
 		
-- 
GitLab