From 0d71ed53fa514f6c5644e1ecc1404b7a354199ce Mon Sep 17 00:00:00 2001 From: Sebastian Hahta <joseha@utu.fi> Date: Tue, 28 Jul 2020 10:07:28 +0300 Subject: [PATCH] extrinsic calibration options --- .../src/modules/calibration/calibration.hpp | 242 +++++++++--------- .../src/modules/calibration/extrinsic.cpp | 34 ++- .../src/modules/calibration/intrinsic.cpp | 56 ++-- .../src/views/calibration/extrinsicview.cpp | 76 +++--- .../src/views/calibration/intrinsicview.cpp | 27 +- .../include/ftl/calibration/extrinsic.hpp | 2 +- components/calibration/src/extrinsic.cpp | 21 +- components/calibration/src/structures.cpp | 10 +- .../src/sources/stereovideo/stereovideo.cpp | 2 +- 9 files changed, 264 insertions(+), 206 deletions(-) diff --git a/applications/gui2/src/modules/calibration/calibration.hpp b/applications/gui2/src/modules/calibration/calibration.hpp index 991acc206..af27c0f82 100644 --- a/applications/gui2/src/modules/calibration/calibration.hpp +++ b/applications/gui2/src/modules/calibration/calibration.hpp @@ -179,6 +179,8 @@ public: /** Set principal point at image center */ void resetPrincipalPoint(); + void resetDistortion(); + /** get current frame */ cv::cuda::GpuMat getFrame(); bool hasFrame(); @@ -239,119 +241,6 @@ private: * parameters can be used to calculate paramters for stereo rectification. */ -/** Stereo calibration for OpenCV's calibrateStereo() */ - -class StereoCalibration : public CalibrationModule { -public: - using CalibrationModule::CalibrationModule; - virtual void init() override; - virtual ~StereoCalibration(); - - /** start calibration process, replaces active view */ - void start(ftl::data::FrameID id); - - bool hasChannel(ftl::codecs::Channel c); - - void setChessboard(cv::Size, double); - cv::Size chessboardSize(); - double squareSize(); - - /** Reset calibration instance, discards drops all state. */ - void reset(); - - OpenCVCalibrateFlagsStereo& flags() { return state_->flags; }; - void resetFlags(); - - /** Returns if capture/calibration is still processing in background. - * calib() instance must not be modifed while isBusy() is true. - */ - bool isBusy(); - - /** Start/stop capture. After stopping, use isBusy() to check when last - * frame is finished. - */ - void setCapture(bool v); - bool capturing(); - - /** get/set capture frequency: interval between processed frames in - * chessboard detection - */ - void setFrequency(float v); - float frequency(); - - /** Run calibration in another thread. Check status with isBusy(). */ - void run(); - - /** Save calibration */ - void save(); - - /** check if calibration valid: baseline > 0 */ - bool calibrated(); - - /** get current frame */ - cv::cuda::GpuMat getLeft(); - cv::cuda::GpuMat getRight(); - cv::cuda::GpuMat getLeftRectify(); - cv::cuda::GpuMat getRightRectify(); - bool hasFrame(); - - ftl::calibration::CalibrationData::Calibration calibrationLeft(); - ftl::calibration::CalibrationData::Calibration calibrationRight(); - double baseline(); - - /** get previous points (visualization) */ - std::vector<std::vector<cv::Point2f>> previousPoints(); - cv::cuda::GpuMat getLeftPrevious(); - cv::cuda::GpuMat getRightPrevious(); - int count() const { return state_->count; } - /** List sources which can be calibrated. - */ - std::vector<std::pair<std::string, ftl::data::FrameID>> listSources(bool all=false); - -private: - bool onFrame_(const ftl::data::FrameSetPtr& fs); - void calculateRectification(); - ftl::rgbd::Frame& frame_(); - - ftl::codecs::Channel channelLeft_(); - ftl::codecs::Channel channelRight_(); - - std::future<void> future_; - std::mutex mtx_; - ftl::data::FrameSetPtr fs_current_; - ftl::data::FrameSetPtr fs_update_; - - struct State { - cv::Mat gray_left; - cv::Mat gray_right; - - ftl::calibration::CalibrationData calib; - std::unique_ptr<ftl::calibration::ChessboardObject> object; - ftl::data::FrameID id; - bool highres = false; - cv::Size imsize; - std::atomic_bool capture = false; - std::atomic_bool running = false; - float last = 0.0f; - float frequency = 0.5f; - int count = 0; - float reprojection_error = NAN; - OpenCVCalibrateFlagsStereo flags; - - // maps for rectification (cv) - std::pair<cv::Mat, cv::Mat> map_l; - std::pair<cv::Mat, cv::Mat> map_r; - cv::Rect validROI_l; - cv::Rect validROI_r; - - ftl::data::FrameSetPtr fs_previous_points; - std::vector<std::vector<cv::Point2f>> points_l; - std::vector<std::vector<cv::Point2f>> points_r; - std::vector<std::vector<cv::Point3f>> points_object; - }; - std::unique_ptr<State> state_; -}; - class ExtrinsicCalibration : public CalibrationModule { public: using CalibrationModule::CalibrationModule; @@ -426,8 +315,17 @@ public: double reprojectionError(int camera=-1); - void setOptions(ftl::calibration::BundleAdjustment::Options options) { state_.calib.setOptions(options); } - ftl::calibration::BundleAdjustment::Options options() { return state_.calib.options(); } + enum Flags { + ZERO_DISTORTION = 1, + FIX_INTRINSIC = 2, + FIX_FOCAL = 4, + FIX_PRINCIPAL_POINT = 8, + FIX_DISTORTION = 16, + LOSS_CAUCHY = 32, + }; + + void setFlags(int flags); + int flags() const; protected: ftl::calibration::CalibrationData::Calibration getCalibration(CameraID id); @@ -455,6 +353,7 @@ private: struct State { bool capture = false; int min_cameras = 2; + int flags = 0; std::vector<Camera> cameras; std::unique_ptr<ftl::calibration::CalibrationObject> calib_object; @@ -468,5 +367,118 @@ private: //////////////////////////////////////////////////////////////////////////////// +/** Stereo calibration for OpenCV's calibrateStereo() */ + +class StereoCalibration : public CalibrationModule { +public: + using CalibrationModule::CalibrationModule; + virtual void init() override; + virtual ~StereoCalibration(); + + /** start calibration process, replaces active view */ + void start(ftl::data::FrameID id); + + bool hasChannel(ftl::codecs::Channel c); + + void setChessboard(cv::Size, double); + cv::Size chessboardSize(); + double squareSize(); + + /** Reset calibration instance, discards drops all state. */ + void reset(); + + OpenCVCalibrateFlagsStereo& flags() { return state_->flags; }; + void resetFlags(); + + /** Returns if capture/calibration is still processing in background. + * calib() instance must not be modifed while isBusy() is true. + */ + bool isBusy(); + + /** Start/stop capture. After stopping, use isBusy() to check when last + * frame is finished. + */ + void setCapture(bool v); + bool capturing(); + + /** get/set capture frequency: interval between processed frames in + * chessboard detection + */ + void setFrequency(float v); + float frequency(); + + /** Run calibration in another thread. Check status with isBusy(). */ + void run(); + + /** Save calibration */ + void save(); + + /** check if calibration valid: baseline > 0 */ + bool calibrated(); + + /** get current frame */ + cv::cuda::GpuMat getLeft(); + cv::cuda::GpuMat getRight(); + cv::cuda::GpuMat getLeftRectify(); + cv::cuda::GpuMat getRightRectify(); + bool hasFrame(); + + ftl::calibration::CalibrationData::Calibration calibrationLeft(); + ftl::calibration::CalibrationData::Calibration calibrationRight(); + double baseline(); + + /** get previous points (visualization) */ + std::vector<std::vector<cv::Point2f>> previousPoints(); + cv::cuda::GpuMat getLeftPrevious(); + cv::cuda::GpuMat getRightPrevious(); + int count() const { return state_->count; } + /** List sources which can be calibrated. + */ + std::vector<std::pair<std::string, ftl::data::FrameID>> listSources(bool all=false); + +private: + bool onFrame_(const ftl::data::FrameSetPtr& fs); + void calculateRectification(); + ftl::rgbd::Frame& frame_(); + + ftl::codecs::Channel channelLeft_(); + ftl::codecs::Channel channelRight_(); + + std::future<void> future_; + std::mutex mtx_; + ftl::data::FrameSetPtr fs_current_; + ftl::data::FrameSetPtr fs_update_; + + struct State { + cv::Mat gray_left; + cv::Mat gray_right; + + ftl::calibration::CalibrationData calib; + std::unique_ptr<ftl::calibration::ChessboardObject> object; + ftl::data::FrameID id; + bool highres = false; + cv::Size imsize; + std::atomic_bool capture = false; + std::atomic_bool running = false; + float last = 0.0f; + float frequency = 0.5f; + int count = 0; + float reprojection_error = NAN; + OpenCVCalibrateFlagsStereo flags; + + // maps for rectification (cv) + std::pair<cv::Mat, cv::Mat> map_l; + std::pair<cv::Mat, cv::Mat> map_r; + cv::Rect validROI_l; + cv::Rect validROI_r; + + ftl::data::FrameSetPtr fs_previous_points; + std::vector<std::vector<cv::Point2f>> points_l; + std::vector<std::vector<cv::Point2f>> points_r; + std::vector<std::vector<cv::Point3f>> points_object; + }; + std::unique_ptr<State> state_; +}; + } } diff --git a/applications/gui2/src/modules/calibration/extrinsic.cpp b/applications/gui2/src/modules/calibration/extrinsic.cpp index 18de0f373..83debcedf 100644 --- a/applications/gui2/src/modules/calibration/extrinsic.cpp +++ b/applications/gui2/src/modules/calibration/extrinsic.cpp @@ -242,11 +242,21 @@ bool ExtrinsicCalibration::isBusy() { void ExtrinsicCalibration::updateCalibration() { auto fs = std::atomic_load(&fs_current_); + std::map<ftl::data::FrameID, ftl::calibration::CalibrationData> update; + for (unsigned int i = 0; i < state_.cameras.size(); i++) { auto& c = state_.cameras[i]; - auto& frame = fs->frames[c.id]; - auto calib = frame.get<CalibrationData>(Channel::CalibrationData); - calib.get(c.id.channel) = state_.calib.calibration(i); + auto frame_id = ftl::data::FrameID(c.id); + + if (update.count(frame_id) == 0) { + auto& frame = fs->frames[c.id]; + update[frame_id] = frame.get<CalibrationData>(Channel::CalibrationData); + } + update[frame_id].get(c.id.channel) = state_.calib.calibrationOptimized(i); + } + + for (auto& [fid, calib] : update) { + auto& frame = fs->frames[fid]; setCalibration(frame, calib); } } @@ -296,7 +306,17 @@ void ExtrinsicCalibration::run() { << cv::norm(t1, t2); } + auto opt = state_.calib.options(); + opt.optimize_intrinsic = !(state_.flags & Flags::FIX_INTRINSIC); + opt.fix_focal = state_.flags & Flags::FIX_FOCAL; + opt.fix_distortion = state_.flags & Flags::FIX_DISTORTION; + opt.fix_principal_point = state_.flags & Flags::FIX_PRINCIPAL_POINT; + opt.loss = (state_.flags & Flags::LOSS_CAUCHY) ? + ftl::calibration::BundleAdjustment::Options::Loss::CAUCHY : + ftl::calibration::BundleAdjustment::Options::Loss::SQUARED; + state_.calib.setOptions(opt); state_.calib.run(); + for (int c = 0; c < cameraCount(); c += 2) { auto t1 = state_.calib.calibrationOptimized(c).extrinsic.tvec; auto t2 = state_.calib.calibrationOptimized(c + 1).extrinsic.tvec; @@ -360,6 +380,14 @@ int ExtrinsicCalibration::getFrameCount(int camera) { return state_.calib.points().getCount(unsigned(camera)); } +void ExtrinsicCalibration::setFlags(int flags) { + state_.flags = flags; +} + +int ExtrinsicCalibration::flags() const { + return state_.flags; +} + // debug method: save state to file (msgpack) void ExtrinsicCalibration::saveInput(const std::string& filename) { ftl::pool.push([this, filename](int){ diff --git a/applications/gui2/src/modules/calibration/intrinsic.cpp b/applications/gui2/src/modules/calibration/intrinsic.cpp index da9ff2199..43c08485d 100644 --- a/applications/gui2/src/modules/calibration/intrinsic.cpp +++ b/applications/gui2/src/modules/calibration/intrinsic.cpp @@ -64,6 +64,13 @@ void IntrinsicCalibration::start(ftl::data::FrameID id) { filter->on([this](const FrameSetPtr& fs){ return onFrame_(fs); }); + while(fs_current_ == nullptr) { + auto fss = filter->getLatestFrameSets(); + if (fss.size() == 1) { fs_current_ = fss.front(); } + } + auto fs = std::atomic_load(&fs_current_); + setChannel_(fs); + auto* view = new ftl::gui2::IntrinsicCalibrationView(screen, this); view->onClose([filter, this](){ // if calib_ caches images, also reset() here! @@ -77,14 +84,6 @@ void IntrinsicCalibration::start(ftl::data::FrameID id) { }); screen->setView(view); - - - while(fs_current_ == nullptr) { - auto fss = filter->getLatestFrameSets(); - if (fss.size() == 1) { fs_current_ = fss.front(); } - } - auto fs = std::atomic_load(&fs_current_); - setChannel_(fs); } void IntrinsicCalibration::setChannel(Channel channel) { @@ -95,6 +94,9 @@ void IntrinsicCalibration::setChannel(Channel channel) { void IntrinsicCalibration::setChannel_(FrameSetPtr fs) { // reset points, find if high res available and find correct resolution + // TODO/FIXME: channel might be missing from previous frameset; temporary + // fix uses left channel to set resulution (assumes left resolution always + // the same as right resolution). state_->calib = CalibrationData::Intrinsic(); state_->points.clear(); @@ -107,16 +109,27 @@ void IntrinsicCalibration::setChannel_(FrameSetPtr fs) { } auto& frame = (*fs)[state_->id.source()].cast<ftl::rgbd::Frame>(); + cv::Size size; - if ((state_->channel== Channel::Left) && frame.has(Channel::LeftHighRes)) { - state_->channel_alt = Channel::LeftHighRes; + if (state_->channel== Channel::Left) { + if(frame.has(Channel::LeftHighRes)) { + state_->channel_alt = Channel::LeftHighRes; + size = frame.get<cv::Mat>(state_->channel_alt).size(); + } + else { + size = frame.get<cv::Mat>(state_->channel_alt).size(); + } } - if ((state_->channel== Channel::Right) && frame.has(Channel::RightHighRes)) { - state_->channel_alt = Channel::RightHighRes; + else if (state_->channel== Channel::Right) { + if (frame.has(Channel::RightHighRes)) { + state_->channel_alt = Channel::RightHighRes; + size = frame.get<cv::Mat>(Channel::LeftHighRes).size(); + } + else { + size = frame.get<cv::Mat>(Channel::Left).size(); + } } - auto size = frame.get<cv::Mat>(state_->channel_alt).size(); - try { auto calib = frame.get<CalibrationData>(Channel::CalibrationData); if (calib.hasCalibration(state_->channel)) { @@ -321,17 +334,15 @@ void IntrinsicCalibration::setSensorSize(cv::Size2d sz) { } double IntrinsicCalibration::focalLength() { - return (sensorSize().width * state_->calib.fx)/(state_->calib.resolution.width); + return (state_->calib.fx)*(sensorSize().width/state_->calib.resolution.width); } void IntrinsicCalibration::setFocalLength(double value, cv::Size2d sensor_size) { setSensorSize(sensor_size); - double fx = (state_->calib.resolution.width * value)/(sensor_size.width); - double fy = (state_->calib.resolution.height * value)/(sensor_size.height); - LOG_IF(WARNING, fx != fy) << "fx != fy; is sensor size correct?"; + double f = value*(state_->calib.resolution.width/sensor_size.width); - state_->calib.cx = fx; - state_->calib.cy = fy; + state_->calib.cx = f; + state_->calib.cy = f; } void IntrinsicCalibration::resetPrincipalPoint() { @@ -340,6 +351,11 @@ void IntrinsicCalibration::resetPrincipalPoint() { state_->calib.cy = double(sz.height)/2.0; } +void IntrinsicCalibration::resetDistortion() { + state_->calib.distCoeffs = CalibrationData::Intrinsic::DistortionCoefficients(); +} + + bool IntrinsicCalibration::hasChannel(Channel c) { if (fs_current_) { return (*fs_current_)[state_->id.source()].hasChannel(c); diff --git a/applications/gui2/src/views/calibration/extrinsicview.cpp b/applications/gui2/src/views/calibration/extrinsicview.cpp index 606464e87..91b3b946d 100644 --- a/applications/gui2/src/views/calibration/extrinsicview.cpp +++ b/applications/gui2/src/views/calibration/extrinsicview.cpp @@ -266,7 +266,7 @@ private: nanogui::Label* status_; nanogui::Button* brun_; bool running_; // run button clicked - ftl::calibration::BundleAdjustment::Options opts_; + int flags_; public: EIGEN_MAKE_ALIGNED_OPERATOR_NEW @@ -290,51 +290,53 @@ ExtrinsicCalibrationView::CalibrationWindow::CalibrationWindow(nanogui::Widget* void ExtrinsicCalibrationView::CalibrationWindow::build() { + flags_ = ctrl_->flags(); + auto* wfreeze = new nanogui::Widget(this); wfreeze->setLayout(new nanogui::BoxLayout (nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0 , 5)); auto* floss = new nanogui::CheckBox(wfreeze, "Cauchy loss"); - floss->setChecked(opts_.loss == ftl::calibration::BundleAdjustment::Options::CAUCHY); - floss->setCallback([&opts = opts_](bool v) { - if (v) { - opts.loss = ftl::calibration::BundleAdjustment::Options::CAUCHY; - } - else { - opts.loss = ftl::calibration::BundleAdjustment::Options::SQUARED; - } + floss->setChecked(flags_ & ExtrinsicCalibration::Flags::LOSS_CAUCHY); + floss->setCallback([&flags = flags_](bool v) { + if (v) { flags |= ExtrinsicCalibration::Flags::LOSS_CAUCHY; } + else { flags &= ~ExtrinsicCalibration::Flags::LOSS_CAUCHY; } }); - opts_ = ctrl_->options(); auto* fall = new nanogui::CheckBox(wfreeze, "Freeze all intrinsic paramters"); - fall->setChecked(!(opts_.optimize_intrinsic)); - fall->setCallback([&opts = opts_](bool v) { - opts.optimize_intrinsic = !v; + fall->setChecked(flags_ & ExtrinsicCalibration::Flags::FIX_INTRINSIC); + fall->setCallback([&flags = flags_](bool v) { + if (v) { flags |= ExtrinsicCalibration::Flags::FIX_INTRINSIC; } + else { flags &= ~ExtrinsicCalibration::Flags::FIX_INTRINSIC; } }); auto* ff = new nanogui::CheckBox(wfreeze, "Fix focal length"); - ff->setChecked(opts_.fix_focal); - ff->setCallback([&opts = opts_](bool v) { - opts.fix_focal = v; + ff->setChecked(flags_ & ExtrinsicCalibration::Flags::FIX_FOCAL); + ff->setCallback([&flags = flags_](bool v) { + if (v) { flags |= ExtrinsicCalibration::Flags::FIX_FOCAL; } + else { flags &= ~ExtrinsicCalibration::Flags::FIX_FOCAL; } }); auto* fpp = new nanogui::CheckBox(wfreeze, "Fix principal point"); - fpp->setChecked(opts_.fix_principal_point); - fpp->setCallback([&opts = opts_](bool v) { - opts.fix_principal_point = v; + fpp->setChecked(flags_ & ExtrinsicCalibration::Flags::FIX_PRINCIPAL_POINT); + fpp->setCallback([&flags = flags_](bool v) { + if (v) { flags |= ExtrinsicCalibration::Flags::FIX_PRINCIPAL_POINT; } + else { flags &= ~ExtrinsicCalibration::Flags::FIX_PRINCIPAL_POINT; } }); auto* fdist = new nanogui::CheckBox(wfreeze, "Fix distortion coefficients"); - fdist->setChecked(opts_.fix_distortion); - fdist->setCallback([&opts = opts_](bool v) { - opts.fix_distortion = v; + fdist->setChecked(flags_ & ExtrinsicCalibration::Flags::FIX_DISTORTION); + fdist->setCallback([&flags = flags_](bool v) { + if (v) { flags |= ExtrinsicCalibration::Flags::FIX_DISTORTION; } + else { flags &= ~ExtrinsicCalibration::Flags::FIX_DISTORTION; } }); - auto* fzdist = new nanogui::CheckBox(wfreeze, "Assume zero distortion"); - /*fzdist->setChecked(opts_.fix_distortion); - fzdist->setCallback([&opts = opts_](bool v) { - opts.fix_distortion = v; - });*/ + auto* zdist = new nanogui::CheckBox(wfreeze, "Assume zero distortion"); + zdist->setChecked(flags_ & ExtrinsicCalibration::Flags::ZERO_DISTORTION); + zdist->setCallback([&flags = flags_](bool v) { + if (v) { flags |= ExtrinsicCalibration::Flags::ZERO_DISTORTION; } + else { flags &= ~ExtrinsicCalibration::Flags::ZERO_DISTORTION; } + }); fall->setCallback([wfreeze](bool value){ for (int i = 2; i < wfreeze->childCount(); i++) { @@ -344,28 +346,12 @@ void ExtrinsicCalibrationView::CalibrationWindow::build() { /* Needs thinking: visualize visibility graph? Use earlier alignment (if * some of the cameras already calibrated), do elsewhere? - - new nanogui::Label(this, "Select orgin camera"); - auto* wcameras = new nanogui::Widget(this); - wcameras->setLayout(new nanogui::BoxLayout - (nanogui::Orientation::Horizontal, nanogui::Alignment::Middle, 0 , 2)); - - auto* button = new nanogui::Button(wcameras, "A"); - button->setFlags(nanogui::Button::Flags::RadioButton); - button->setCallback([ctrl = ctrl_](){}); - button->setTooltip("Automatic"); - button->setPushed(true); - const auto cameras = ctrl_->cameras(); - for (unsigned i = 0; i < cameras.size(); i++) { - button = new nanogui::Button(wcameras, std::to_string(i)); - button->setFlags(nanogui::Button::Flags::RadioButton); - button->setCallback([ctrl = ctrl_](){}); - }*/ + */ status_ = new nanogui::Label(this, "Ready"); brun_ = new nanogui::Button(this, "Run"); brun_->setCallback([this](){ - ctrl_->setOptions(opts_); + ctrl_->setFlags(flags_); ctrl_->run(); running_ = true; }); diff --git a/applications/gui2/src/views/calibration/intrinsicview.cpp b/applications/gui2/src/views/calibration/intrinsicview.cpp index a8708183c..6129ce48d 100644 --- a/applications/gui2/src/views/calibration/intrinsicview.cpp +++ b/applications/gui2/src/views/calibration/intrinsicview.cpp @@ -84,6 +84,7 @@ public: class IntrinsicCalibrationView::CalibrationWindow : public FixedWindow { public: CalibrationWindow(nanogui::Widget* parent, IntrinsicCalibrationView* view); + void update(); virtual void draw(NVGcontext* ctx) override; private: @@ -95,7 +96,8 @@ private: nanogui::FloatBox<double>* sensor_width_; nanogui::FloatBox<double>* sensor_height_; nanogui::FloatBox<double>* focal_length_; - nanogui::CheckBox* pp_; + nanogui::CheckBox* reset_dist_; + nanogui::CheckBox* reset_pp_; bool calibrating_; public: @@ -407,14 +409,18 @@ IntrinsicCalibrationView::CalibrationWindow::CalibrationWindow(nanogui::Widget* sensor_height_->setUnits("mm"); new nanogui::Label(initial_values, "Focal length"); - focal_length_ = new nanogui::FloatBox<double>(initial_values, ctrl_->sensorSize().height); + focal_length_ = new nanogui::FloatBox<double>(initial_values, ctrl_->focalLength()); focal_length_->setEditable(true); focal_length_->setFormat("[0-9]*\\.?[0-9]+"); focal_length_->setUnits("mm"); new nanogui::Label(initial_values, "Reset principal point"); - pp_ = new nanogui::CheckBox(initial_values, ""); - pp_->setChecked(false); + reset_pp_ = new nanogui::CheckBox(initial_values, ""); + reset_pp_->setChecked(false); + + new nanogui::Label(initial_values, "Reset distortion coefficients"); + reset_dist_ = new nanogui::CheckBox(initial_values, ""); + reset_dist_->setChecked(false); // flags new nanogui::Label(this, "Flags"); @@ -427,19 +433,23 @@ IntrinsicCalibrationView::CalibrationWindow::CalibrationWindow(nanogui::Widget* if (!ctrl_->isBusy()) { ctrl_->setSensorSize({sensor_width_->value(), sensor_height_->value()}); ctrl_->setFocalLength(focal_length_->value(), ctrl_->sensorSize()); - if (pp_->checked()) { - ctrl_->resetPrincipalPoint(); - } + if (reset_pp_->checked()) { ctrl_->resetPrincipalPoint(); } + if (reset_dist_->checked()) { ctrl_->resetDistortion(); } ctrl_->run(); calibrating_ = true; } }); } +void IntrinsicCalibrationView::CalibrationWindow::update() { + focal_length_->setValue(ctrl_->focalLength()); +} + void IntrinsicCalibrationView::CalibrationWindow::draw(NVGcontext* ctx) { bool use_guess = ctrl_->flags().has(cv::CALIB_USE_INTRINSIC_GUESS); focal_length_->setEnabled(use_guess); - pp_->setEnabled(use_guess); + reset_pp_->setEnabled(use_guess); + reset_dist_->setEnabled(use_guess); if (ctrl_->isBusy()) { if (calibrating_) { @@ -601,6 +611,7 @@ void IntrinsicCalibrationView::setMode(Mode m) { ctrl_->setCapture(false); wcapture_->setVisible(false); wcontrol_->setVisible(false); + wcalibration_->update(); wcalibration_->setVisible(true); wresults_->setVisible(false); break; diff --git a/components/calibration/include/ftl/calibration/extrinsic.hpp b/components/calibration/include/ftl/calibration/extrinsic.hpp index 3dba4ffc6..5bded2bc3 100644 --- a/components/calibration/include/ftl/calibration/extrinsic.hpp +++ b/components/calibration/include/ftl/calibration/extrinsic.hpp @@ -221,7 +221,7 @@ private: CalibrationPoints<double> points_; std::set<std::pair<unsigned int, unsigned int>> mask_; - std::map<std::pair<unsigned int, unsigned int>, std::pair<cv::Mat, cv::Mat>> pairs_; + std::map<std::pair<unsigned int, unsigned int>, std::tuple<cv::Mat, cv::Mat, double>> pairs_; int min_points_ = 64; // minimum number of points required for pair calibration // TODO: add map {c1,c2}Â for existing calibration which is used if available. // diff --git a/components/calibration/src/extrinsic.cpp b/components/calibration/src/extrinsic.cpp index 0ad4fbe73..615b13034 100644 --- a/components/calibration/src/extrinsic.cpp +++ b/components/calibration/src/extrinsic.cpp @@ -395,7 +395,8 @@ void ExtrinsicCalibration::calculatePairPoses() { if (c1 == c2) { pairs_[{c1, c2}] = { cv::Mat::eye(cv::Size(3, 3), CV_64FC1), - cv::Mat(cv::Size(1, 3), CV_64FC1, cv::Scalar(0.0)) }; + cv::Mat(cv::Size(1, 3), CV_64FC1, cv::Scalar(0.0)), + 0.0}; continue; } @@ -419,21 +420,21 @@ void ExtrinsicCalibration::calculatePairPoses() { auto object = points().getObject(0); cv::Mat R, t; std::vector<cv::Point3d> points3d; - auto rms = calibratePair(K1, distCoeffs1, K2, distCoeffs2, + auto rmse = calibratePair(K1, distCoeffs1, K2, distCoeffs2, pts[0], pts[1], object, R, t, points3d, true); // debug info - LOG(INFO) << "RMSE (cameras " << c1 << " & " << c2 << "): " << rms; + LOG(INFO) << "RMSE (cameras " << c1 << " & " << c2 << "): " << rmse; points().setTriangulatedPoints(c1, c2, points3d); - pairs_[{c1, c2}] = {R, t}; + pairs_[{c1, c2}] = {R, t, rmse}; cv::Mat R_i, t_i; R.copyTo(R_i); t.copyTo(t_i); transform::inverse(R_i, t_i); - pairs_[{c2, c1}] = {R_i, t_i}; + pairs_[{c2, c1}] = {R_i, t_i, rmse}; }} } @@ -453,12 +454,16 @@ void ExtrinsicCalibration::calculateInitialPoses() { if (pairs_.count({c1, c2}) == 0) { visibility.mask(c1, c2); } + + // mask bad pairs (high rmse) + /*if (std::get<2>(pairs_.at({c1, c2})) > 16.0) { + visibility.mask(c1, c2); + }*/ }} // pick optimal camera: most views of calibration pattern unsigned int c_ref = visibility.argmax(); - // calculate transformation chains; TODO: use pair RMSE as well? auto paths = visibility.shortestPath(c_ref); for (unsigned int c = 0; c < camerasCount(); c++) { @@ -474,8 +479,8 @@ void ExtrinsicCalibration::calculateInitialPoses() { path.pop_back(); auto next = path.back(); - cv::Mat R = pairs_.at({prev, next}).first; - cv::Mat t = pairs_.at({prev, next}).second; + cv::Mat R = std::get<0>(pairs_.at({prev, next})); + cv::Mat t = std::get<1>(pairs_.at({prev, next})); CHECK_EQ(R.size(), cv::Size(3, 3)); CHECK_EQ(t.total(), 3); diff --git a/components/calibration/src/structures.cpp b/components/calibration/src/structures.cpp index 1e194bcd9..2c44a6b02 100644 --- a/components/calibration/src/structures.cpp +++ b/components/calibration/src/structures.cpp @@ -9,15 +9,15 @@ using ftl::calibration::CalibrationData; CalibrationData::Intrinsic::DistortionCoefficients::DistortionCoefficients() : - data_(12, 0.0) { + data_(14, 0.0) { } const cv::Mat CalibrationData::Intrinsic::DistortionCoefficients::Mat(int nparams) const { if (nparams <= 0) { return cv::Mat(); } - if (nparams > 12) { - nparams = 12; + if (nparams > 14) { + nparams = 14; } return cv::Mat(cv::Size(nparams, 1), CV_64FC1, const_cast<double*>(data_.data())); } @@ -26,8 +26,8 @@ cv::Mat CalibrationData::Intrinsic::DistortionCoefficients::Mat(int nparams) { if (nparams <= 0) { return cv::Mat(); } - if (nparams > 12) { - nparams = 12; + if (nparams > 14) { + nparams = 14; } return cv::Mat(cv::Size(nparams, 1), CV_64FC1, data_.data()); } diff --git a/components/rgbd-sources/src/sources/stereovideo/stereovideo.cpp b/components/rgbd-sources/src/sources/stereovideo/stereovideo.cpp index 547e84382..7458f5c53 100644 --- a/components/rgbd-sources/src/sources/stereovideo/stereovideo.cpp +++ b/components/rgbd-sources/src/sources/stereovideo/stereovideo.cpp @@ -301,7 +301,7 @@ void StereoVideoSource::updateParameters(ftl::rgbd::Frame &frame) { params.baseline = 0.1f; params.width = color_size_.width; params.height = color_size_.height;; - + float offsetz = host_->value("offset_z", 0.0f); //state_.setPose(matrix(cv::Vec3d(0.0, 3.14159, 0.0), cv::Vec3d(0.0,0.0,params_.maxDepth+offsetz))); pose = matrix(cv::Vec3d(0.0, 3.14159, 0.0), cv::Vec3d(0.0,0.0,params.maxDepth + offsetz)); -- GitLab