From d505c4c419601556da18c7492a0d3bbfb8c1a151 Mon Sep 17 00:00:00 2001 From: Nicolas Pope <nicolas.pope@utu.fi> Date: Tue, 25 Jun 2019 20:39:46 +0300 Subject: [PATCH] GUI Configuration Editing --- applications/gui/CMakeLists.txt | 2 + applications/gui/src/config_window.cpp | 115 +++++++++++++++ applications/gui/src/config_window.hpp | 33 +++++ applications/gui/src/ctrl_window.cpp | 70 ++++++++- applications/gui/src/ctrl_window.hpp | 2 + applications/gui/src/main.cpp | 122 +++++++++++++++- applications/gui/src/pose_window.cpp | 133 ++++++++++++++++++ applications/gui/src/pose_window.hpp | 38 +++++ applications/gui/src/src_window.cpp | 25 +++- .../reconstruct/include/ftl/ray_cast_sdf.hpp | 21 +++ .../include/ftl/scene_rep_hash_sdf.hpp | 59 ++++++-- applications/reconstruct/src/ray_cast_sdf.cu | 2 +- .../reconstruct/src/virtual_source.cpp | 13 ++ .../common/cpp/include/ftl/configuration.hpp | 2 + components/common/cpp/src/configuration.cpp | 8 ++ components/control/cpp/CMakeLists.txt | 2 +- components/control/cpp/include/ftl/master.hpp | 7 +- components/control/cpp/src/master.cpp | 28 +++- components/control/cpp/src/slave.cpp | 6 +- .../rgbd-sources/include/ftl/rgbd/camera.hpp | 1 + components/rgbd-sources/src/calibrate.cpp | 45 ++++-- components/rgbd-sources/src/calibrate.hpp | 8 +- components/rgbd-sources/src/net.cpp | 25 ++++ .../rgbd-sources/src/snapshot_source.cpp | 4 + components/rgbd-sources/src/stereovideo.cpp | 23 ++- components/rgbd-sources/src/streamer.cpp | 13 ++ 26 files changed, 749 insertions(+), 58 deletions(-) create mode 100644 applications/gui/src/config_window.cpp create mode 100644 applications/gui/src/config_window.hpp create mode 100644 applications/gui/src/pose_window.cpp create mode 100644 applications/gui/src/pose_window.hpp diff --git a/applications/gui/CMakeLists.txt b/applications/gui/CMakeLists.txt index ac9ae7ec2..6b0d3944c 100644 --- a/applications/gui/CMakeLists.txt +++ b/applications/gui/CMakeLists.txt @@ -6,6 +6,8 @@ set(GUISRC src/main.cpp src/ctrl_window.cpp src/src_window.cpp + src/config_window.cpp + src/pose_window.cpp ) add_executable(ftl-gui ${GUISRC}) diff --git a/applications/gui/src/config_window.cpp b/applications/gui/src/config_window.cpp new file mode 100644 index 000000000..cc422f495 --- /dev/null +++ b/applications/gui/src/config_window.cpp @@ -0,0 +1,115 @@ +#include "config_window.hpp" + +#include <nanogui/layout.h> +#include <nanogui/label.h> +#include <nanogui/combobox.h> +#include <nanogui/button.h> +#include <nanogui/entypo.h> +#include <nanogui/formhelper.h> + +#include <vector> +#include <string> + +using ftl::gui::ConfigWindow; +using std::string; +using std::vector; +using ftl::config::json_t; + + +ConfigWindow::ConfigWindow(nanogui::Widget *parent, ftl::ctrl::Master *ctrl, const ftl::UUID &peer) + : nanogui::Window(parent, "Settings"), ctrl_(ctrl), peer_(peer) { + using namespace nanogui; + + setLayout(new GroupLayout()); + setPosition(Vector2i(parent->width()/2.0f - 100.0f, parent->height()/2.0f - 100.0f)); + //setModal(true); + + configurables_ = ctrl->getConfigurables(peer); + + auto label = new Label(this, "Select Configurable","sans-bold"); + + auto select = new ComboBox(this, configurables_); + select->setCallback([this](int ix) { + LOG(INFO) << "Change configurable: " << ix; + _buildForm(configurables_[ix], ctrl_->get(peer_, configurables_[ix])); + + setVisible(false); + //this->parent()->removeChild(this); + //delete this; + //screen()->removeChild(this); + }); +} + +ConfigWindow::~ConfigWindow() { + +} + +void ConfigWindow::_addElements(nanogui::FormHelper *form, const std::string &suri, const ftl::config::json_t &data) { + using namespace nanogui; + + for (auto i=data.begin(); i!=data.end(); ++i) { + if (i.key() == "$id") continue; + + if (i.key() == "$ref" && i.value().is_string()) { + LOG(INFO) << "Follow $ref: " << i.value(); + _addElements(form, suri, ctrl_->get(peer_, i.value().get<string>())); + continue; + } + + if (i.value().is_boolean()) { + string key = i.key(); + form->addVariable<bool>(i.key(), [this,data,key,suri](const bool &b){ + ctrl_->set(peer_, suri + string("/") + key, json_t(b)); + }, [data,key]() -> bool { + return data[key].get<bool>(); + }); + } else if (i.value().is_number_integer()) { + string key = i.key(); + form->addVariable<int>(i.key(), [this,data,key,suri](const int &f){ + ctrl_->set(peer_, suri + string("/") + key, json_t(f)); + }, [data,key]() -> int { + return data[key].get<int>(); + }); + } else if (i.value().is_number_float()) { + string key = i.key(); + form->addVariable<float>(i.key(), [this,data,key,suri](const float &f){ + ctrl_->set(peer_, suri + string("/") + key, json_t(f)); + }, [data,key]() -> float { + return data[key].get<float>(); + }); + } else if (i.value().is_string()) { + string key = i.key(); + form->addVariable<string>(i.key(), [this,data,key,suri](const string &f){ + ctrl_->set(peer_, suri + string("/") + key, json_t(f)); + }, [data,key]() -> string { + return data[key].get<string>(); + }); + } else if (i.value().is_object()) { + string key = i.key(); + const ftl::config::json_t &v = i.value(); + + form->addButton(i.key(), [this,form,suri,key,v]() { + _buildForm(suri+string("/")+key, v); + })->setIcon(ENTYPO_ICON_FOLDER); + } + } +} + +void ConfigWindow::_buildForm(const std::string &suri, ftl::config::json_t data) { + using namespace nanogui; + + ftl::URI uri(suri); + + FormHelper *form = new FormHelper(this->screen()); + //form->setWindow(this); + form->addWindow(Vector2i(100,50), uri.getFragment()); + form->window()->setTheme(theme()); + + _addElements(form, suri, data); + + auto closebutton = form->addButton("Close", [form]() { + form->window()->setVisible(false); + delete form; + }); + closebutton->setIcon(ENTYPO_ICON_CROSS); +} diff --git a/applications/gui/src/config_window.hpp b/applications/gui/src/config_window.hpp new file mode 100644 index 000000000..87170b1d3 --- /dev/null +++ b/applications/gui/src/config_window.hpp @@ -0,0 +1,33 @@ +#ifndef _FTL_GUI_CFGWINDOW_HPP_ +#define _FTL_GUI_CFGWINDOW_HPP_ + +#include <nanogui/window.h> +#include <ftl/master.hpp> +#include <ftl/uuid.hpp> + +#include <nanogui/formhelper.h> + +namespace ftl { +namespace gui { + +/** + * Allow configurable editing. + */ +class ConfigWindow : public nanogui::Window { + public: + ConfigWindow(nanogui::Widget *parent, ftl::ctrl::Master *ctrl, const ftl::UUID &peer); + ~ConfigWindow(); + + private: + ftl::ctrl::Master *ctrl_; + ftl::UUID peer_; + std::vector<std::string> configurables_; + + void _buildForm(const std::string &uri, ftl::config::json_t data); + void _addElements(nanogui::FormHelper *form, const std::string &suri, const ftl::config::json_t &data); +}; + +} +} + +#endif // _FTL_GUI_CFGWINDOW_HPP_ diff --git a/applications/gui/src/ctrl_window.cpp b/applications/gui/src/ctrl_window.cpp index ef2854640..065438220 100644 --- a/applications/gui/src/ctrl_window.cpp +++ b/applications/gui/src/ctrl_window.cpp @@ -1,5 +1,7 @@ #include "ctrl_window.hpp" +#include "config_window.hpp" + #include <nanogui/layout.h> #include <nanogui/label.h> #include <nanogui/combobox.h> @@ -10,30 +12,38 @@ #include <string> using ftl::gui::ControlWindow; +using ftl::gui::ConfigWindow; using std::string; using std::vector; ControlWindow::ControlWindow(nanogui::Widget *parent, ftl::ctrl::Master *ctrl) - : nanogui::Window(parent, "Node Control"), ctrl_(ctrl) { + : nanogui::Window(parent, "Network Connections"), ctrl_(ctrl) { setLayout(new nanogui::GroupLayout()); using namespace nanogui; _updateDetails(); - auto button = new Button(this, "Add Node", ENTYPO_ICON_PLUS); + auto tools = new Widget(this); + tools->setLayout(new BoxLayout(Orientation::Horizontal, + Alignment::Middle, 0, 6)); + + auto button = new Button(tools, "", ENTYPO_ICON_PLUS); button->setCallback([this] { // Show new connection dialog + _addNode(); }); - button = new Button(this, "Restart All", ENTYPO_ICON_CYCLE); + button->setTooltip("Add new node"); + button = new Button(tools, "", ENTYPO_ICON_CYCLE); button->setCallback([this] { ctrl_->restart(); }); - button = new Button(this, "Pause All", ENTYPO_ICON_POWER_PLUG); + button = new Button(tools, "", ENTYPO_ICON_CONTROLLER_PAUS); button->setCallback([this] { ctrl_->pause(); }); + button->setTooltip("Pause all nodes"); new Label(this, "Select Node","sans-bold"); auto select = new ComboBox(this, node_titles_); @@ -42,15 +52,41 @@ ControlWindow::ControlWindow(nanogui::Widget *parent, ftl::ctrl::Master *ctrl) _changeActive(ix); }); - button = new Button(this, "Restart Node", ENTYPO_ICON_CYCLE); + new Label(this, "Node Options","sans-bold"); + + tools = new Widget(this); + tools->setLayout(new BoxLayout(Orientation::Horizontal, + Alignment::Middle, 0, 6)); + + button = new Button(tools, "", ENTYPO_ICON_INFO); + button->setCallback([this] { + + }); + button->setTooltip("Node status information"); + + button = new Button(tools, "", ENTYPO_ICON_COG); + button->setCallback([this,parent] { + auto cfgwin = new ConfigWindow(parent, ctrl_, _getActiveID()); + cfgwin->setTheme(theme()); + }); + button->setTooltip("Edit node configuration"); + + button = new Button(tools, "", ENTYPO_ICON_CYCLE); button->setCallback([this] { ctrl_->restart(_getActiveID()); }); + button->setTooltip("Restart this node"); - button = new Button(this, "Pause Node", ENTYPO_ICON_POWER_PLUG); + button = new Button(tools, "", ENTYPO_ICON_CONTROLLER_PAUS); button->setCallback([this] { ctrl_->pause(_getActiveID()); }); + button->setTooltip("Pause node processing"); + + ctrl->getNet()->onConnect([this,select](ftl::net::Peer *p) { + _updateDetails(); + select->setItems(node_titles_); + }); _changeActive(0); } @@ -59,6 +95,28 @@ ControlWindow::~ControlWindow() { } +void ControlWindow::_addNode() { + using namespace nanogui; + + FormHelper *form = new FormHelper(this->screen()); + form->addWindow(Vector2i(100,100), "Add Node"); + + auto var = form->addVariable("URI", add_node_uri_); + var->setValue("tcp://localhost:9001"); + var->setFixedWidth(200); + + form->addButton("Add", [this,form](){ + ctrl_->getNet()->connect(add_node_uri_); + form->window()->setVisible(false); + delete form; + })->setIcon(ENTYPO_ICON_PLUS); + + form->addButton("Close", [form]() { + form->window()->setVisible(false); + delete form; + })->setIcon(ENTYPO_ICON_CROSS); +} + void ControlWindow::_updateDetails() { node_details_ = ctrl_->getSlaves(); diff --git a/applications/gui/src/ctrl_window.hpp b/applications/gui/src/ctrl_window.hpp index 58df7b9be..93a45a47e 100644 --- a/applications/gui/src/ctrl_window.hpp +++ b/applications/gui/src/ctrl_window.hpp @@ -21,10 +21,12 @@ class ControlWindow : public nanogui::Window { std::vector<ftl::config::json_t> node_details_; std::vector<std::string> node_titles_; int active_ix_; + std::string add_node_uri_; void _updateDetails(); void _changeActive(int); ftl::UUID _getActiveID(); + void _addNode(); }; } diff --git a/applications/gui/src/main.cpp b/applications/gui/src/main.cpp index c9a807b61..69512cc07 100644 --- a/applications/gui/src/main.cpp +++ b/applications/gui/src/main.cpp @@ -15,6 +15,7 @@ #include <nanogui/imageview.h> #include <nanogui/combobox.h> #include <nanogui/label.h> +#include <nanogui/toolbutton.h> #include "ctrl_window.hpp" #include "src_window.hpp" @@ -241,16 +242,120 @@ static Eigen::Affine3f create_rotation_matrix(float ax, float ay, float az) { class FTLApplication : public nanogui::Screen { public: - explicit FTLApplication(ftl::Configurable *root, ftl::net::Universe *net, ftl::ctrl::Master *controller) : nanogui::Screen(Eigen::Vector2i(1024, 768), "FT-Lab GUI") { + explicit FTLApplication(ftl::Configurable *root, ftl::net::Universe *net, ftl::ctrl::Master *controller) : nanogui::Screen(Eigen::Vector2i(1024, 768), "FT-Lab Remote Presence") { using namespace nanogui; net_ = net; ctrl_ = controller; + status_ = "FT-Lab Remote Presence System"; + + setSize(Vector2i(1280,720)); + + Theme *toolbuttheme = new Theme(*theme()); + toolbuttheme->mBorderDark = nanogui::Color(0,0); + toolbuttheme->mBorderLight = nanogui::Color(0,0); + toolbuttheme->mButtonGradientBotFocused = nanogui::Color(60,255); + toolbuttheme->mButtonGradientBotUnfocused = nanogui::Color(0,0); + toolbuttheme->mButtonGradientTopFocused = nanogui::Color(60,255); + toolbuttheme->mButtonGradientTopUnfocused = nanogui::Color(0,0); + toolbuttheme->mButtonGradientTopPushed = nanogui::Color(60,180); + toolbuttheme->mButtonGradientBotPushed = nanogui::Color(60,180); + + Theme *windowtheme = new Theme(*theme()); + windowtheme->mWindowFillFocused = nanogui::Color(220, 200); + windowtheme->mWindowFillUnfocused = nanogui::Color(220, 200); + windowtheme->mWindowHeaderGradientBot = nanogui::Color(60,230); + windowtheme->mWindowHeaderGradientTop = nanogui::Color(60,230); + windowtheme->mTextColor = nanogui::Color(20,255); + windowtheme->mWindowCornerRadius = 2; + windowtheme->mButtonGradientBotFocused = nanogui::Color(210,255); + windowtheme->mButtonGradientBotUnfocused = nanogui::Color(190,255); + windowtheme->mButtonGradientTopFocused = nanogui::Color(230,255); + windowtheme->mButtonGradientTopUnfocused = nanogui::Color(230,255); + windowtheme->mButtonGradientTopPushed = nanogui::Color(170,255); + windowtheme->mButtonGradientBotPushed = nanogui::Color(210,255); + windowtheme->mBorderDark = nanogui::Color(150,255); + windowtheme->mBorderMedium = nanogui::Color(165,255); + windowtheme->mBorderLight = nanogui::Color(230,255); + windowtheme->mButtonFontSize = 16; + windowtheme->mTextColorShadow = nanogui::Color(0,0); + windowtheme->mWindowTitleUnfocused = windowtheme->mWindowTitleFocused; + windowtheme->mWindowTitleFocused = nanogui::Color(240,255); + windowtheme->mIconScale = 0.85f; + + auto toolbar = new Window(this, ""); + toolbar->setPosition(Vector2i(0,0)); + toolbar->setFixedWidth(50); + toolbar->setFixedHeight(height()); + //toolbar->setLayout(new BoxLayout(Orientation::Vertical, + // Alignment::Middle, 0, 10)); + + setResizeCallback([this,toolbar](Vector2i s) { + toolbar->setFixedHeight(s[1]); + }); + + auto innertool = new Widget(toolbar); + innertool->setLayout(new BoxLayout(Orientation::Vertical, + Alignment::Middle, 0, 10)); + innertool->setPosition(Vector2i(5,10)); + + // Padding widget + //auto w = new Widget(innertool); + //w->setHeight(10); + + auto button = new ToolButton(innertool, ENTYPO_ICON_HOME); + button->setIconExtraScale(1.5f); + button->setTheme(toolbuttheme); + button->setTooltip("Home"); + button->setFixedSize(Vector2i(40,40)); + button->setCallback([this]() { + //swindow_->setVisible(true); + }); + + button = new ToolButton(innertool, ENTYPO_ICON_EDIT); + button->setIconExtraScale(1.5f); + button->setTheme(toolbuttheme); + button->setTooltip("Edit Scene"); + button->setFixedSize(Vector2i(40,40)); + button->setCallback([this]() { + //swindow_->setVisible(true); + }); + + button = new ToolButton(innertool, ENTYPO_ICON_CAMERA); + button->setIconExtraScale(1.5f); + button->setTheme(toolbuttheme); + button->setTooltip("Camera Sources"); + button->setFixedSize(Vector2i(40,40)); + button->setCallback([this]() { + swindow_->setVisible(true); + }); + + button = new ToolButton(innertool, ENTYPO_ICON_SIGNAL); + button->setIconExtraScale(1.5f); + button->setTheme(toolbuttheme); + button->setTooltip("Connections"); + button->setFixedSize(Vector2i(40,40)); + button->setCallback([this]() { + cwindow_->setVisible(true); + }); + + button = new ToolButton(toolbar, ENTYPO_ICON_COG); + button->setIconExtraScale(1.5f); + button->setTheme(toolbuttheme); + button->setTooltip("Settings"); + button->setFixedSize(Vector2i(40,40)); + button->setPosition(Vector2i(5,height()-50)); + + //configwindow_ = new ConfigWindow(parent, ctrl_); cwindow_ = new ftl::gui::ControlWindow(this, controller); swindow_ = new ftl::gui::SourceWindow(this, controller); - cwindow_->setPosition(Eigen::Vector2i(20, 20)); - swindow_->setPosition(Eigen::Vector2i(20, 400)); + cwindow_->setPosition(Eigen::Vector2i(80, 20)); + swindow_->setPosition(Eigen::Vector2i(80, 400)); + cwindow_->setVisible(false); + swindow_->setVisible(false); + cwindow_->setTheme(windowtheme); + swindow_->setTheme(windowtheme); //src_ = nullptr; eye_ = Eigen::Vector3f(0.0f, 0.0f, 0.0f); @@ -358,8 +463,8 @@ class FTLApplication : public nanogui::Screen { neye_ += r.matrix()*Vector4f(0.0,scalar,0.0,1.0); return true; } else if (action == 1 && key == 'H') { - swindow_->setVisible(!swindow_->visible()); - cwindow_->setVisible(!cwindow_->visible()); + swindow_->setVisible(false); + cwindow_->setVisible(false); } else if (action == 1 && key == 32) { ctrl_->pause(); } @@ -434,8 +539,9 @@ class FTLApplication : public nanogui::Screen { } } + Vector2f screenSize = size().cast<float>(); + if (imageSize[0] > 0) { - Vector2f screenSize = size().cast<float>(); auto mScale = (screenSize.cwiseQuotient(imageSize).minCoeff()); Vector2f scaleFactor = mScale * imageSize.cwiseQuotient(screenSize); Vector2f positionInScreen(0.0f, 0.0f); @@ -457,7 +563,8 @@ class FTLApplication : public nanogui::Screen { //glDisable(GL_SCISSOR_TEST); } - nvgText(ctx, 10, 20, "FT-Lab Remote Presence System", NULL); + nvgTextAlign(ctx, NVG_ALIGN_RIGHT); + nvgText(ctx, screenSize[0]-10, screenSize[1]-20, status_.c_str(), NULL); /* Draw the user interface */ screen()->performLayout(ctx); @@ -484,6 +591,7 @@ class FTLApplication : public nanogui::Screen { float delta_; Eigen::Vector2f imageSize; ftl::ctrl::Master *ctrl_; + std::string status_; }; int main(int argc, char **argv) { diff --git a/applications/gui/src/pose_window.cpp b/applications/gui/src/pose_window.cpp new file mode 100644 index 000000000..a3d5da3ba --- /dev/null +++ b/applications/gui/src/pose_window.cpp @@ -0,0 +1,133 @@ +#include "pose_window.hpp" + +#include <nanogui/combobox.h> +#include <nanogui/label.h> +#include <nanogui/layout.h> +#include <nanogui/button.h> + +using ftl::gui::PoseWindow; +using std::string; + +PoseWindow::PoseWindow(nanogui::Widget *parent, ftl::ctrl::Master *ctrl, const std::string &src) + : nanogui::Window(parent, "Pose Adjust"), ctrl_(ctrl), src_(src) { + using namespace nanogui; + + //setLayout(new nanogui::GroupLayout()); + setLayout(new BoxLayout(Orientation::Vertical, + Alignment::Middle, 0, 6)); + + pose_param_ = kPoseTranslation; + pose_precision_ = 0.1; + + pose_ = ctrl_->getPose(src_); + + //Widget *tools = new Widget(this); + // tools->setLayout(new BoxLayout(Orientation::Horizontal, + // Alignment::Middle, 0, 6)); + + auto grouping = new Widget(this); + grouping->setLayout(new GroupLayout()); + + new Label(grouping, "Select source","sans-bold"); + available_ = ctrl->getNet()->findAll<string>("list_streams"); + auto select = new ComboBox(grouping, available_); + select->setSelectedIndex(std::distance(available_.begin(), std::find(available_.begin(), available_.end(), src_))); + select->setCallback([this,select](int ix) { + src_ = available_[ix]; + pose_ = ctrl_->getPose(src_); + }); + + ctrl->getNet()->onConnect([this,select](ftl::net::Peer *p) { + available_ = ctrl_->getNet()->findAll<string>("list_streams"); + select->setItems(available_); + }); + + new Label(grouping, "Pose Options","sans-bold"); + + auto tools = new Widget(grouping); + tools->setLayout(new BoxLayout(Orientation::Horizontal, + Alignment::Middle, 0, 6)); + + auto button_rgb = new Button(tools, "Translation"); + button_rgb->setTooltip("Adjust camera location"); + button_rgb->setFlags(Button::RadioButton); + button_rgb->setPushed(true); + button_rgb->setChangeCallback([this](bool state) { pose_param_ = kPoseTranslation; }); + + auto button_depth = new Button(tools, "Rotation"); + button_depth->setFlags(Button::RadioButton); + button_depth->setChangeCallback([this](bool state) { pose_param_ = kPoseRotation; }); + + auto button_stddev = new Button(tools, "Raw"); + button_stddev->setTooltip("Edit the numbers directly"); + button_stddev->setFlags(Button::RadioButton); + button_stddev->setChangeCallback([this](bool state) { pose_param_ = kPoseRaw; }); + + tools = new Widget(grouping); + tools->setLayout(new BoxLayout(Orientation::Horizontal, + Alignment::Middle, 0, 6)); + + auto button = new Button(tools, "0.1m"); + button->setFlags(Button::RadioButton); + button->setPushed(true); + button->setCallback([this](){ + pose_precision_ = 0.1f; + }); + + button = new Button(tools, "0.01m"); + button->setFlags(Button::RadioButton); + button->setCallback([this](){ + pose_precision_ = 0.01f; + }); + + button = new Button(tools, "0.001m"); + button->setFlags(Button::RadioButton); + button->setCallback([this](){ + pose_precision_ = 0.001f; + }); + + tools = new Widget(this); + auto grid = new GridLayout(Orientation::Horizontal, 3, Alignment::Middle, 5, 4); + tools->setLayout(grid); + tools->setFixedWidth(150); + + + new Widget(tools); + button = new Button(tools, "", ENTYPO_ICON_CHEVRON_UP); + button->setCallback([this]() { + Eigen::Affine3d transform(Eigen::Translation3d(0.0,0.0,-pose_precision_)); + Eigen::Matrix4d matrix = transform.matrix(); + pose_ *= matrix; + ctrl_->setPose(src_, pose_); + }); + new Widget(tools); + + button = new Button(tools, "", ENTYPO_ICON_CHEVRON_LEFT); + button->setCallback([this]() { + Eigen::Affine3d transform(Eigen::Translation3d(-pose_precision_,0.0,0.0)); + Eigen::Matrix4d matrix = transform.matrix(); + pose_ *= matrix; + ctrl_->setPose(src_, pose_); + }); + new Widget(tools); + button = new Button(tools, "", ENTYPO_ICON_CHEVRON_RIGHT); + button->setCallback([this]() { + Eigen::Affine3d transform(Eigen::Translation3d(pose_precision_,0.0,0.0)); + Eigen::Matrix4d matrix = transform.matrix(); + pose_ *= matrix; + ctrl_->setPose(src_, pose_); + }); + + new Widget(tools); + button = new Button(tools, "", ENTYPO_ICON_CHEVRON_DOWN); + button->setCallback([this]() { + Eigen::Affine3d transform(Eigen::Translation3d(0.0,0.0,pose_precision_)); + Eigen::Matrix4d matrix = transform.matrix(); + pose_ *= matrix; + ctrl_->setPose(src_, pose_); + }); +} + +PoseWindow::~PoseWindow() { + +} diff --git a/applications/gui/src/pose_window.hpp b/applications/gui/src/pose_window.hpp new file mode 100644 index 000000000..cfe03adff --- /dev/null +++ b/applications/gui/src/pose_window.hpp @@ -0,0 +1,38 @@ +#ifndef _FTL_GUI_POSEWINDOW_HPP_ +#define _FTL_GUI_POSEWINDOW_HPP_ + +#include <nanogui/window.h> +#include <ftl/master.hpp> +#include <ftl/uuid.hpp> + +namespace ftl { +namespace gui { + +/** + * Manage connected nodes and add new connections. + */ +class PoseWindow : public nanogui::Window { + public: + PoseWindow(nanogui::Widget *parent, ftl::ctrl::Master *ctrl, const std::string &src); + ~PoseWindow(); + + private: + ftl::ctrl::Master *ctrl_; + std::vector<std::string> available_; + std::string src_; + + enum poseparameter_t { + kPoseTranslation, + kPoseRotation, + kPoseRaw + }; + + poseparameter_t pose_param_; + float pose_precision_; + Eigen::Matrix4d pose_; +}; + +} +} + +#endif // _FTL_GUI_POSEWINDOW_HPP_ diff --git a/applications/gui/src/src_window.cpp b/applications/gui/src/src_window.cpp index ad61ccccb..0a6b0feb6 100644 --- a/applications/gui/src/src_window.cpp +++ b/applications/gui/src/src_window.cpp @@ -1,5 +1,7 @@ #include "src_window.hpp" +#include "pose_window.hpp" + #include <nanogui/imageview.h> #include <nanogui/textbox.h> #include <nanogui/slider.h> @@ -93,28 +95,41 @@ SourceWindow::SourceWindow(nanogui::Widget *parent, ftl::ctrl::Master *ctrl) select->setCallback([this,select](int ix) { LOG(INFO) << "Change source: " << ix; src_->set("uri", available_[ix]); -}); + }); ctrl->getNet()->onConnect([this,select](ftl::net::Peer *p) { available_ = ctrl_->getNet()->findAll<string>("list_streams"); select->setItems(available_); }); - auto button_rgb = new Button(this, "RGB (left)"); + new Label(this, "Source Options","sans-bold"); + + auto tools = new Widget(this); + tools->setLayout(new BoxLayout(Orientation::Horizontal, + Alignment::Middle, 0, 6)); + + auto button_rgb = new Button(tools, "RGB"); + button_rgb->setTooltip("RGB left image"); button_rgb->setFlags(Button::RadioButton); button_rgb->setPushed(true); button_rgb->setChangeCallback([this](bool state) { mode_ = Mode::rgb; }); - auto button_depth = new Button(this, "Depth"); + auto button_depth = new Button(tools, "Depth"); button_depth->setFlags(Button::RadioButton); button_depth->setChangeCallback([this](bool state) { mode_ = Mode::depth; }); - auto button_stddev = new Button(this, "Standard Deviation (25 frames)"); + auto button_stddev = new Button(tools, "SD. 25"); + button_stddev->setTooltip("Standard Deviation over 25 frames"); button_stddev->setFlags(Button::RadioButton); button_stddev->setChangeCallback([this](bool state) { mode_ = Mode::stddev; }); + auto button_pose = new Button(this, "Adjust Pose", ENTYPO_ICON_COMPASS); + button_pose->setCallback([this]() { + new PoseWindow(screen(), ctrl_, src_->getURI()); + }); + #ifdef HAVE_LIBARCHIVE - auto button_snapshot = new Button(this, "Snapshot"); + auto button_snapshot = new Button(this, "Snapshot", ENTYPO_ICON_IMAGES); button_snapshot->setCallback([this] { try { char timestamp[18]; diff --git a/applications/reconstruct/include/ftl/ray_cast_sdf.hpp b/applications/reconstruct/include/ftl/ray_cast_sdf.hpp index ff53d58c3..4f263065f 100644 --- a/applications/reconstruct/include/ftl/ray_cast_sdf.hpp +++ b/applications/reconstruct/include/ftl/ray_cast_sdf.hpp @@ -16,6 +16,27 @@ public: auto &cfg = ftl::config::resolve(config); create(parametersFromConfig(cfg)); hash_render_ = value("hash_renderer", false); + + on("hash_renderer", [this](const ftl::config::Event &e) { + hash_render_ = value("hash_renderer", false); + }); + + on("width", [this](const ftl::config::Event &e) { + m_params.m_width = value("width", 640); + }); + + on("height", [this](const ftl::config::Event &e) { + m_params.m_height = value("height", 480); + }); + + on("width", [this](const ftl::config::Event &e) { + m_params.m_width = value("width", 640); + }); + + on("showBlockBorders", [this](const ftl::config::Event &e) { + if (value("showBlockBorders", false)) m_params.m_flags |= kShowBlockBorders; + else m_params.m_flags &= ~kShowBlockBorders; + }); } bool isIntegerDepth() const { return hash_render_; } diff --git a/applications/reconstruct/include/ftl/scene_rep_hash_sdf.hpp b/applications/reconstruct/include/ftl/scene_rep_hash_sdf.hpp index 55303cef0..fa0d6f46e 100644 --- a/applications/reconstruct/include/ftl/scene_rep_hash_sdf.hpp +++ b/applications/reconstruct/include/ftl/scene_rep_hash_sdf.hpp @@ -35,7 +35,7 @@ namespace voxhash { class SceneRep : public ftl::Configurable { public: - SceneRep(nlohmann::json &config) : Configurable(config) { + SceneRep(nlohmann::json &config) : Configurable(config), do_reset_(false) { REQUIRED({ {"hashNumBuckets", "Desired hash entries divide bucket size", "number"}, {"hashMaxCollisionLinkedListSize", "", "number"}, @@ -47,30 +47,52 @@ class SceneRep : public ftl::Configurable { {"SDFIntegrationWeightSample", "", "number"}, {"SDFIntegrationWeightMax", "", "number"} }); - create(parametersFromConfig(config)); + create(parametersFromConfig()); + + on("SDFVoxelSize", [this](const ftl::config::Event &e) { + do_reset_ = true; + }); + on("hashNumSDFBlocks", [this](const ftl::config::Event &e) { + do_reset_ = true; + }); + on("hashNumBuckets", [this](const ftl::config::Event &e) { + do_reset_ = true; + }); + on("hashMaxCollisionLinkedListSize", [this](const ftl::config::Event &e) { + do_reset_ = true; + }); + on("SDFTruncation", [this](const ftl::config::Event &e) { + m_hashParams.m_truncation = value("SDFTruncation", 0.1f); + }); + on("SDFTruncationScale", [this](const ftl::config::Event &e) { + m_hashParams.m_truncScale = value("SDFTruncationScale", 0.01f); + }); + on("SDFMaxIntegrationDistance", [this](const ftl::config::Event &e) { + m_hashParams.m_maxIntegrationDistance = value("SDFMaxIntegrationDistance", 10.0f); + }); } ~SceneRep() { destroy(); } - static HashParams parametersFromConfig(nlohmann::json &config) { - auto &cfg = ftl::config::resolve(config); + HashParams parametersFromConfig() { + //auto &cfg = ftl::config::resolve(config); HashParams params; // First camera view is set to identity pose to be at the centre of // the virtual coordinate space. params.m_rigidTransform.setIdentity(); params.m_rigidTransformInverse.setIdentity(); - params.m_hashNumBuckets = cfg["hashNumBuckets"]; + params.m_hashNumBuckets = value("hashNumBuckets", 100000); params.m_hashBucketSize = HASH_BUCKET_SIZE; - params.m_hashMaxCollisionLinkedListSize = cfg["hashMaxCollisionLinkedListSize"]; + params.m_hashMaxCollisionLinkedListSize = value("hashMaxCollisionLinkedListSize", 7); params.m_SDFBlockSize = SDF_BLOCK_SIZE; - params.m_numSDFBlocks = cfg["hashNumSDFBlocks"]; - params.m_virtualVoxelSize = cfg["SDFVoxelSize"]; - params.m_maxIntegrationDistance = cfg["SDFMaxIntegrationDistance"]; - params.m_truncation = cfg["SDFTruncation"]; - params.m_truncScale = cfg["SDFTruncationScale"]; - params.m_integrationWeightSample = cfg["SDFIntegrationWeightSample"]; - params.m_integrationWeightMax = cfg["SDFIntegrationWeightMax"]; + params.m_numSDFBlocks = value("hashNumSDFBlocks",500000); + params.m_virtualVoxelSize = value("SDFVoxelSize", 0.006f); + params.m_maxIntegrationDistance = value("SDFMaxIntegrationDistance", 10.0f); + params.m_truncation = value("SDFTruncation", 0.1f); + params.m_truncScale = value("SDFTruncationScale", 0.01f); + params.m_integrationWeightSample = value("SDFIntegrationWeightSample", 10); + params.m_integrationWeightMax = value("SDFIntegrationWeightMax", 255); // Note (Nick): We are not streaming voxels in/out of GPU //params.m_streamingVoxelExtents = MatrixConversion::toCUDA(gas.s_streamingVoxelExtents); //params.m_streamingGridDimensions = MatrixConversion::toCUDA(gas.s_streamingGridDimensions); @@ -125,8 +147,14 @@ class SceneRep : public ftl::Configurable { /* Nick: To reduce weights between frames */ void nextFrame() { - starveVoxelsKernelCUDA(m_hashData, m_hashParams); - m_numIntegratedFrames = 0; + if (do_reset_) { + do_reset_ = false; + destroy(); + create(parametersFromConfig()); + } else { + starveVoxelsKernelCUDA(m_hashData, m_hashParams); + m_numIntegratedFrames = 0; + } } //! resets the hash to the initial state (i.e., clears all data) @@ -375,6 +403,7 @@ private: //CUDAScan m_cudaScan; unsigned int m_numIntegratedFrames; //used for garbage collect + bool do_reset_; // static Timer m_timer; }; diff --git a/applications/reconstruct/src/ray_cast_sdf.cu b/applications/reconstruct/src/ray_cast_sdf.cu index ee2c16a01..bf305af94 100644 --- a/applications/reconstruct/src/ray_cast_sdf.cu +++ b/applications/reconstruct/src/ray_cast_sdf.cu @@ -87,7 +87,7 @@ __global__ void clearDepthKernel(ftl::voxhash::HashData hashData, RayCastData ra if (x < rayCastParams.m_width && y < rayCastParams.m_height) { rayCastData.d_depth_i[y*rayCastParams.m_width+x] = 0x7FFFFFFF; //PINF; - rayCastData.d_colors[y*rayCastParams.m_width+x] = make_uchar3(0,0,0); + rayCastData.d_colors[y*rayCastParams.m_width+x] = make_uchar3(76,76,82); } } diff --git a/applications/reconstruct/src/virtual_source.cpp b/applications/reconstruct/src/virtual_source.cpp index 0bc4abf4a..80f08a0e3 100644 --- a/applications/reconstruct/src/virtual_source.cpp +++ b/applications/reconstruct/src/virtual_source.cpp @@ -27,6 +27,19 @@ VirtualSource::VirtualSource(ftl::rgbd::Source *host) rgb_ = cv::Mat(cv::Size(params_.width,params_.height), CV_8UC3); idepth_ = cv::Mat(cv::Size(params_.width,params_.height), CV_32SC1); depth_ = cv::Mat(cv::Size(params_.width,params_.height), CV_32FC1); + + rays_->on("focal", [this](const ftl::config::Event &e) { + params_.fx = rays_->value("focal", 430.0f); + params_.fy = params_.fx; + }); + + rays_->on("width", [this](const ftl::config::Event &e) { + params_.width = rays_->value("width", 640); + }); + + rays_->on("height", [this](const ftl::config::Event &e) { + params_.height = rays_->value("height", 480); + }); } VirtualSource::~VirtualSource() { diff --git a/components/common/cpp/include/ftl/configuration.hpp b/components/common/cpp/include/ftl/configuration.hpp index 18ce61f4c..db6cb1438 100644 --- a/components/common/cpp/include/ftl/configuration.hpp +++ b/components/common/cpp/include/ftl/configuration.hpp @@ -68,6 +68,8 @@ json_t &resolveWait(const std::string &); */ Configurable *find(const std::string &uri); +std::vector<std::string> list(); + /** * Adds a Configurable instance to the database of instances so that it can * then be resolved using find(). diff --git a/components/common/cpp/src/configuration.cpp b/components/common/cpp/src/configuration.cpp index b849c6ff1..20c07b978 100644 --- a/components/common/cpp/src/configuration.cpp +++ b/components/common/cpp/src/configuration.cpp @@ -189,6 +189,14 @@ ftl::Configurable *ftl::config::find(const std::string &uri) { else return (*ix).second; } +std::vector<std::string> ftl::config::list() { + vector<string> r; + for (auto i : config_instance) { + r.push_back(i.first); + } + return r; +} + void ftl::config::registerConfigurable(ftl::Configurable *cfg) { auto uri = cfg->get<string>("$id"); if (!uri) { diff --git a/components/control/cpp/CMakeLists.txt b/components/control/cpp/CMakeLists.txt index 0705bc6e0..f55ec9c19 100644 --- a/components/control/cpp/CMakeLists.txt +++ b/components/control/cpp/CMakeLists.txt @@ -7,7 +7,7 @@ target_include_directories(ftlctrl PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include> PRIVATE src) -target_link_libraries(ftlctrl ftlcommon ftlnet) +target_link_libraries(ftlctrl ftlcommon ftlnet Eigen3::Eigen) install(TARGETS ftlctrl EXPORT ftlctrl-config ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/components/control/cpp/include/ftl/master.hpp b/components/control/cpp/include/ftl/master.hpp index 91a913ed9..9b658aaad 100644 --- a/components/control/cpp/include/ftl/master.hpp +++ b/components/control/cpp/include/ftl/master.hpp @@ -7,6 +7,7 @@ #include <functional> #include <string> #include <vector> +#include <Eigen/Eigen> namespace ftl { namespace ctrl { @@ -36,7 +37,7 @@ class Master { void set(const std::string &uri, ftl::config::json_t &value); - void set(const ftl::UUID &peer, const std::string &uri, ftl::config::json_t &value); + void set(const ftl::UUID &peer, const std::string &uri, const ftl::config::json_t &value); std::vector<std::string> getConfigurables(); @@ -52,6 +53,10 @@ class Master { void watch(const std::string &uri, std::function<void()> f); + Eigen::Matrix4d getPose(const std::string &uri); + + void setPose(const std::string &uri, const Eigen::Matrix4d &pose); + // Events //void onError(); diff --git a/components/control/cpp/src/master.cpp b/components/control/cpp/src/master.cpp index 823939d64..086cfbcb1 100644 --- a/components/control/cpp/src/master.cpp +++ b/components/control/cpp/src/master.cpp @@ -65,8 +65,9 @@ void Master::set(const string &uri, json_t &value) { net_->broadcast("update_cfg", uri, (string)value); } -void Master::set(const ftl::UUID &peer, const string &uri, json_t &value) { - net_->send(peer, "update_cfg", uri, (string)value); +void Master::set(const ftl::UUID &peer, const string &uri, const json_t &value) { + LOG(INFO) << "CHANGE: " << uri; + net_->send(peer, "update_cfg", uri, value.dump()); } vector<json_t> Master::getSlaves() { @@ -83,7 +84,7 @@ vector<string> Master::getConfigurables() { } vector<string> Master::getConfigurables(const ftl::UUID &peer) { - return {}; + return net_->call<vector<string>>(peer, "list_configurables"); } vector<json_t> Master::get(const string &uri) { @@ -95,13 +96,32 @@ json_t Master::getOne(const string &uri) { } json_t Master::get(const ftl::UUID &peer, const string &uri) { - return {}; + return json_t::parse(net_->call<string>(peer, "get_cfg", uri)); } void Master::watch(const string &uri, function<void()> f) { } +Eigen::Matrix4d Master::getPose(const std::string &uri) { + auto r = net_->findOne<vector<unsigned char>>("get_pose", uri); + if (r) { + Eigen::Matrix4d pose; + memcpy(pose.data(), (*r).data(), (*r).size()); + return pose; + } else { + LOG(WARNING) << "No pose found for " << uri; + Eigen::Matrix4d pose; + pose.setIdentity(); + return pose; + } +} + +void Master::setPose(const std::string &uri, const Eigen::Matrix4d &pose) { + vector<unsigned char> vec((unsigned char*)pose.data(), (unsigned char*)(pose.data()+(pose.size()))); + net_->broadcast("set_pose", uri, vec); +} + // Events //void onError(); diff --git a/components/control/cpp/src/slave.cpp b/components/control/cpp/src/slave.cpp index b4823e1d1..88933ed7a 100644 --- a/components/control/cpp/src/slave.cpp +++ b/components/control/cpp/src/slave.cpp @@ -39,7 +39,11 @@ Slave::Slave(Universe *net, ftl::Configurable *root) : net_(net), in_log_(false) }); net->bind("get_cfg", [](const std::string &uri) -> std::string { - return ftl::config::resolve(uri); + return ftl::config::resolve(uri, false).dump(); + }); + + net->bind("list_configurables", []() { + return ftl::config::list(); }); net->bind("node_details", [net,root]() -> std::vector<std::string> { diff --git a/components/rgbd-sources/include/ftl/rgbd/camera.hpp b/components/rgbd-sources/include/ftl/rgbd/camera.hpp index 3f4614887..b5ad7ea1d 100644 --- a/components/rgbd-sources/include/ftl/rgbd/camera.hpp +++ b/components/rgbd-sources/include/ftl/rgbd/camera.hpp @@ -14,6 +14,7 @@ struct Camera { unsigned int height; double minDepth; double maxDepth; + double baseline; }; }; diff --git a/components/rgbd-sources/src/calibrate.cpp b/components/rgbd-sources/src/calibrate.cpp index 51767128e..f0b98a505 100644 --- a/components/rgbd-sources/src/calibrate.cpp +++ b/components/rgbd-sources/src/calibrate.cpp @@ -76,12 +76,11 @@ bool Calibrate::_loadCalibration(cv::Size img_size, std::pair<Mat, Mat> &map1, s return false; } - Mat M1, D1, M2, D2; - fs["M"] >> M1; - fs["D"] >> D1; + fs["M"] >> M1_; + fs["D"] >> D1_; - M2 = M1; - D2 = D1; + M2_ = M1_; + D2_ = D1_; auto efile = ftl::locateFile("extrinsics.yml"); if (efile) { @@ -97,24 +96,40 @@ bool Calibrate::_loadCalibration(cv::Size img_size, std::pair<Mat, Mat> &map1, s return false; } - Mat R, T, R1, P1, R2, P2; - fs["R"] >> R; - fs["T"] >> T; - fs["R1"] >> R1; - fs["R2"] >> R2; - fs["P1"] >> P1; - fs["P2"] >> P2; + fs["R"] >> R_; + fs["T"] >> T_; + fs["R1"] >> R1_; + fs["R2"] >> R2_; + fs["P1"] >> P1_; + fs["P2"] >> P2_; fs["Q"] >> Q_; - P_ = P1; + P_ = P1_; + + img_size_ = img_size; // cv::cuda::remap() works only with CV_32FC1 - initUndistortRectifyMap(M1, D1, R1, P1, img_size, CV_32FC1, map1.first, map2.first); - initUndistortRectifyMap(M2, D2, R2, P2, img_size, CV_32FC1, map1.second, map2.second); + initUndistortRectifyMap(M1_, D1_, R1_, P1_, img_size_, CV_32FC1, map1.first, map2.first); + initUndistortRectifyMap(M2_, D2_, R2_, P2_, img_size_, CV_32FC1, map1.second, map2.second); return true; } +void Calibrate::updateCalibration(const ftl::rgbd::Camera &p) { + std::pair<Mat, Mat> map1, map2; + + Q_.at<double>(3,2) = 1.0 / p.baseline; + + initUndistortRectifyMap(M1_, D1_, R1_, P1_, img_size_, CV_32FC1, map1.first, map2.first); + initUndistortRectifyMap(M2_, D2_, R2_, P2_, img_size_, CV_32FC1, map1.second, map2.second); + + // CHECK Is this thread safe!!!! + map1_gpu_.first.upload(map1.first); + map1_gpu_.second.upload(map1.second); + map2_gpu_.first.upload(map2.first); + map2_gpu_.second.upload(map2.second); +} + void Calibrate::rectifyStereo(GpuMat &l, GpuMat &r, Stream &stream) { // cv::cuda::remap() can not use same Mat for input and output diff --git a/components/rgbd-sources/src/calibrate.hpp b/components/rgbd-sources/src/calibrate.hpp index c967de2e5..b8b98116b 100644 --- a/components/rgbd-sources/src/calibrate.hpp +++ b/components/rgbd-sources/src/calibrate.hpp @@ -10,6 +10,7 @@ #include <string> #include <vector> #include <nlohmann/json.hpp> +#include <ftl/rgbd/camera.hpp> namespace cv { class FileStorage; @@ -39,7 +40,9 @@ class Calibrate : public ftl::Configurable { */ void rectifyStereo(cv::cuda::GpuMat &l, cv::cuda::GpuMat &r, cv::cuda::Stream &stream); - bool isCalibrated(); // TODO ??? + bool isCalibrated(); + + void updateCalibration(const ftl::rgbd::Camera &p); /** * Get the camera matrix. Used to convert disparity map back to depth and @@ -59,6 +62,9 @@ private: cv::Mat P_; cv::Mat Q_; + cv::Mat R_, T_, R1_, P1_, R2_, P2_; + cv::Mat M1_, D1_, M2_, D2_; + cv::Size img_size_; }; } diff --git a/components/rgbd-sources/src/net.cpp b/components/rgbd-sources/src/net.cpp index 6f915f127..b71d18e08 100644 --- a/components/rgbd-sources/src/net.cpp +++ b/components/rgbd-sources/src/net.cpp @@ -33,6 +33,12 @@ bool NetSource::_getCalibration(Universe &net, const UUID &peer, const string &s } LOG(INFO) << "Calibration received: " << p.cx << ", " << p.cy << ", " << p.fx << ", " << p.fy; + + // Put calibration into config manually + host_->getConfig()["focal"] = p.fx; + host_->getConfig()["centre_x"] = p.cx; + host_->getConfig()["centre_y"] = p.cy; + host_->getConfig()["baseline"] = p.baseline; return true; } else { @@ -51,6 +57,25 @@ NetSource::NetSource(ftl::rgbd::Source *host) gamma_ = host->value("gamma", 1.0f); temperature_ = host->value("temperature", 6500); + host->on("gamma", [this,host](const ftl::config::Event&) { + gamma_ = host->value("gamma", 1.0f); + }); + + host->on("temperature", [this,host](const ftl::config::Event&) { + temperature_ = host->value("temperature", 6500); + }); + + host->on("focal", [this,host](const ftl::config::Event&) { + params_.fx = host_->value("focal", 400.0); + params_.fy = params_.fx; + host_->getNet()->send(peer_, "update_cfg", host_->getURI() + "/focal", host_->getConfig()["focal"].dump()); + }); + + host->on("baseline", [this,host](const ftl::config::Event&) { + params_.baseline = host_->value("baseline", 400.0); + host_->getNet()->send(peer_, "update_cfg", host_->getURI() + "/baseline", host_->getConfig()["baseline"].dump()); + }); + _updateURI(); h_ = host_->getNet()->onConnect([this](ftl::net::Peer *p) { diff --git a/components/rgbd-sources/src/snapshot_source.cpp b/components/rgbd-sources/src/snapshot_source.cpp index 686e55b93..0e8dec08b 100644 --- a/components/rgbd-sources/src/snapshot_source.cpp +++ b/components/rgbd-sources/src/snapshot_source.cpp @@ -19,5 +19,9 @@ SnapshotSource::SnapshotSource(ftl::rgbd::Source *host, SnapshotReader &reader, ftl::rgbd::colourCorrection(rgb_, host->value("gamma", 1.0f), host->value("temperature", 6500)); + host->on("gamma", [this,host](const ftl::config::Event&) { + ftl::rgbd::colourCorrection(rgb_, host->value("gamma", 1.0f), host->value("temperature", 6500)); + }); + setPose(pose); } diff --git a/components/rgbd-sources/src/stereovideo.cpp b/components/rgbd-sources/src/stereovideo.cpp index 86a9e10b2..0fb5fd864 100644 --- a/components/rgbd-sources/src/stereovideo.cpp +++ b/components/rgbd-sources/src/stereovideo.cpp @@ -69,8 +69,29 @@ void StereoVideoSource::init(const string &file) { (unsigned int)lsrc_->width(), (unsigned int)lsrc_->height(), 0.0f, // 0m min - 15.0f // 15m max + 15.0f, // 15m max + 1.0 / calib_->getQ().at<double>(3,2) // Baseline }; + + // Add calibration to config object + host_->getConfig()["focal"] = params_.fx; + host_->getConfig()["centre_x"] = params_.cx; + host_->getConfig()["centre_y"] = params_.cy; + host_->getConfig()["baseline"] = params_.baseline; + + // Add event handlers to allow calibration changes... + host_->on("baseline", [this](const ftl::config::Event &e) { + params_.baseline = host_->value("baseline", params_.baseline); + std::unique_lock<std::shared_mutex> lk(host_->mutex()); + calib_->updateCalibration(params_); + }); + + host_->on("focal", [this](const ftl::config::Event &e) { + params_.fx = host_->value("focal", params_.fx); + params_.fy = params_.fx; + std::unique_lock<std::shared_mutex> lk(host_->mutex()); + calib_->updateCalibration(params_); + }); // left and right masks (areas outside rectified images) // only left mask used diff --git a/components/rgbd-sources/src/streamer.cpp b/components/rgbd-sources/src/streamer.cpp index 45ac6d496..9a6e20b5b 100644 --- a/components/rgbd-sources/src/streamer.cpp +++ b/components/rgbd-sources/src/streamer.cpp @@ -57,6 +57,19 @@ Streamer::Streamer(nlohmann::json &config, Universe *net) } }); + net->bind("get_pose", [this](const std::string &uri) -> std::vector<unsigned char> { + SHARED_LOCK(mutex_,slk); + + if (sources_.find(uri) != sources_.end()) { + Eigen::Matrix4d pose = sources_[uri]->src->getPose(); + vector<unsigned char> vec((unsigned char*)pose.data(), (unsigned char*)(pose.data()+(pose.size()))); + return vec; + } else { + LOG(WARNING) << "Requested pose not found: " << uri; + return {}; + } + }); + // Allow remote users to access camera calibration matrix net->bind("source_calibration", [this](const std::string &uri) -> vector<unsigned char> { vector<unsigned char> buf; -- GitLab