diff --git a/applications/gui/src/camera.cpp b/applications/gui/src/camera.cpp index a541d910d9031df9d305cff9ded337f776bcc1e1..f7aa5d74ed22140c8b6f5463cc43efa4b2241538 100644 --- a/applications/gui/src/camera.cpp +++ b/applications/gui/src/camera.cpp @@ -271,6 +271,7 @@ void ftl::gui::Camera::_draw(std::vector<ftl::rgbd::FrameSet*> &fss) { if (!usesFrameset(fs->id)) continue; // FIXME: Should perhaps remain locked until after end is called? + // Definitely: causes flashing if not. UNIQUE_LOCK(fs->mtx,lk); renderer_->submit(fs, Channels<0>(channel_), transforms_[fs->id]); } diff --git a/applications/gui/src/src_window.cpp b/applications/gui/src/src_window.cpp index c8adf88195352bd3e1ab543a9855048eed0e8501..8b4090b7c47849d97ad4a290b3f501f0fe4f406a 100644 --- a/applications/gui/src/src_window.cpp +++ b/applications/gui/src/src_window.cpp @@ -39,10 +39,21 @@ using ftl::gui::Screen; using ftl::gui::Scene; using ftl::rgbd::Source; using ftl::codecs::Channel; +using ftl::codecs::Channels; using std::string; using std::vector; using ftl::config::json_t; +static ftl::rgbd::Generator *createSourceGenerator(const std::vector<ftl::rgbd::Source*> &srcs) { + + auto *grp = new ftl::rgbd::Group(); + for (auto s : srcs) { + s->setChannel(Channel::Depth); + grp->addSource(s); + } + return grp; +} + SourceWindow::SourceWindow(ftl::gui::Screen *screen) : nanogui::Window(screen, ""), screen_(screen) { setLayout(new nanogui::BoxLayout(nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 20, 5)); @@ -80,50 +91,7 @@ SourceWindow::SourceWindow(ftl::gui::Screen *screen) paused_ = false; cycle_ = 0; receiver_->onFrameSet([this](ftl::rgbd::FrameSet &fs) { - // Request the channels required by current camera configuration - interceptor_->select(fs.id, _aggregateChannels(fs.id)); - - /*if (fs.id > 0) { - LOG(INFO) << "Got frameset: " << fs.id; - return true; - }*/ - - // Make sure there are enough framesets allocated - _checkFrameSets(fs.id); - - if (!paused_) { - // Enforce interpolated colour - for (int i=0; i<fs.frames.size(); ++i) { - fs.frames[i].createTexture<uchar4>(Channel::Colour, true); - } - - pre_pipelines_[fs.id]->apply(fs, fs, 0); - - fs.swapTo(*framesets_[fs.id]); - } - - /*if (fs.frames[0].hasChannel(Channel::Data)) { - int data = 0; - fs.frames[0].get(Channel::Data, data); - LOG(INFO) << "GOT DATA : " << data; - }*/ - - const auto *cstream = interceptor_; - _createDefaultCameras(*framesets_[fs.id], true); // cstream->available(fs.id).has(Channel::Depth) - - //LOG(INFO) << "Channels = " << (unsigned int)cstream->available(fs.id); - - int i=0; - for (auto cam : cameras_) { - // Only update the camera periodically unless the active camera - if (screen_->activeCamera() == cam.second.camera || - (screen_->activeCamera() == nullptr && cycle_ % cameras_.size() == i++)) cam.second.camera->update(framesets_); - - cam.second.camera->update(cstream->available(fs.id)); - } - ++cycle_; - - return true; + return _processFrameset(fs, true); }); speaker_ = ftl::create<ftl::audio::Speaker>(screen_->root(), "speaker_test"); @@ -145,6 +113,7 @@ SourceWindow::SourceWindow(ftl::gui::Screen *screen) return true; }); + // Add network sources _updateCameras(screen_->control()->getNet()->findAll<string>("list_streams")); // Also check for a file on command line. @@ -163,12 +132,78 @@ SourceWindow::SourceWindow(ftl::gui::Screen *screen) auto *fstream = ftl::create<ftl::stream::File>(screen->root(), std::string("ftlfile-")+std::to_string(ftl_count+1)); fstream->set("filename", path); stream_->add(fstream, ftl_count++); + } else if (path.rfind("device:", 0) == 0) { + ftl::URI uri(path); + uri.to_json(screen->root()->getConfig()["sources"].emplace_back()); } } + // Finally, check for any device sources configured + std::vector<Source*> devices; + // Create a vector of all input RGB-Depth sources + if (screen->root()->getConfig()["sources"].size() > 0) { + devices = ftl::createArray<Source>(screen->root(), "sources", screen->control()->getNet()); + auto *gen = createSourceGenerator(devices); + gen->onFrameSet([this, ftl_count](ftl::rgbd::FrameSet &fs) { + fs.id = ftl_count; // Set a frameset id to something unique. + return _processFrameset(fs, false); + }); + } + stream_->begin(); } +bool SourceWindow::_processFrameset(ftl::rgbd::FrameSet &fs, bool fromstream) { + // Request the channels required by current camera configuration + if (fromstream) interceptor_->select(fs.id, _aggregateChannels(fs.id)); + + /*if (fs.id > 0) { + LOG(INFO) << "Got frameset: " << fs.id; + return true; + }*/ + + // Make sure there are enough framesets allocated + _checkFrameSets(fs.id); + + if (!paused_) { + // Enforce interpolated colour and GPU upload + for (int i=0; i<fs.frames.size(); ++i) { + fs.frames[i].createTexture<uchar4>(Channel::Colour, true); + + // TODO: Do all channels. This is a fix for screen capture sources. + if (!fs.frames[i].isGPU(Channel::Colour)) fs.frames[i].upload(Channels<0>(Channel::Colour), pre_pipelines_[fs.id]->getStream()); + } + + pre_pipelines_[fs.id]->apply(fs, fs, 0); + + fs.swapTo(*framesets_[fs.id]); + } + + /*if (fs.frames[0].hasChannel(Channel::Data)) { + int data = 0; + fs.frames[0].get(Channel::Data, data); + LOG(INFO) << "GOT DATA : " << data; + }*/ + + const auto *cstream = interceptor_; + _createDefaultCameras(*framesets_[fs.id], true); // cstream->available(fs.id).has(Channel::Depth) + + //LOG(INFO) << "Channels = " << (unsigned int)cstream->available(fs.id); + + int i=0; + for (auto cam : cameras_) { + // Only update the camera periodically unless the active camera + if (screen_->activeCamera() == cam.second.camera || + (screen_->activeCamera() == nullptr && cycle_ % cameras_.size() == i++)) cam.second.camera->update(framesets_); + + if (fromstream) cam.second.camera->update(cstream->available(fs.id)); + else if (fs.frames.size() > 0) cam.second.camera->update(fs.frames[0].getChannels()); + } + ++cycle_; + + return true; +} + void SourceWindow::_checkFrameSets(int id) { while (framesets_.size() <= id) { auto *p = ftl::config::create<ftl::operators::Graph>(screen_->root(), "pre_filters"); diff --git a/applications/gui/src/src_window.hpp b/applications/gui/src/src_window.hpp index 6eb0236f7e6dec7826381282ef40225a2f0f88f1..da001950efa65ea19883a5bed50fd9d10ecc31df 100644 --- a/applications/gui/src/src_window.hpp +++ b/applications/gui/src/src_window.hpp @@ -81,6 +81,7 @@ class SourceWindow : public nanogui::Window { void _createDefaultCameras(ftl::rgbd::FrameSet &fs, bool makevirtual); ftl::codecs::Channels<0> _aggregateChannels(int id); void _checkFrameSets(int id); + bool _processFrameset(ftl::rgbd::FrameSet &fs, bool); }; diff --git a/components/common/cpp/include/ftl/uri.hpp b/components/common/cpp/include/ftl/uri.hpp index 05325b346088596aac9b723f0b15a44c1f08c68c..24123f168102de184130bb5f1391349b393d877b 100644 --- a/components/common/cpp/include/ftl/uri.hpp +++ b/components/common/cpp/include/ftl/uri.hpp @@ -1,6 +1,7 @@ #ifndef _FTL_URI_HPP_ #define _FTL_URI_HPP_ +#include <nlohmann/json_fwd.hpp> #include <uriparser/Uri.h> #include <string> #include <vector> @@ -62,6 +63,8 @@ namespace ftl { std::string to_string() const; + void to_json(nlohmann::json &); + private: void _parse(uri_t puri); diff --git a/components/common/cpp/src/uri.cpp b/components/common/cpp/src/uri.cpp index 90fb33522c1c2d701fac47b0a6d43a5a6afee3a7..39ddb47e107a8a9a8dd499d9d4ab7e7e9ec1ae26 100644 --- a/components/common/cpp/src/uri.cpp +++ b/components/common/cpp/src/uri.cpp @@ -1,7 +1,8 @@ #include <ftl/uri.hpp> +#include <nlohmann/json.hpp> // #include <filesystem> TODO When available #include <cstdlib> -#include <loguru.hpp> +//#include <loguru.hpp> #ifndef WIN32 #include <unistd.h> @@ -176,3 +177,26 @@ void URI::setAttribute(const string &key, const string &value) { void URI::setAttribute(const string &key, int value) { m_qmap[key] = std::to_string(value); } + +void URI::to_json(nlohmann::json &json) { + std::string uri = getBaseURI(); + if (m_frag.size() > 0) uri += std::string("#") + getFragment(); + + json["uri"] = uri; + for (auto i : m_qmap) { + auto *current = &json; + + size_t pos = 0; + size_t lpos = 0; + while ((pos = i.first.find('/', lpos)) != std::string::npos) { + current = &((*current)[i.first.substr(lpos, pos-lpos)]); + lpos = pos+1; + } + auto p = nlohmann::json::parse(i.second, nullptr, false); + if (!p.is_discarded()) { + (*current)[i.first.substr(lpos)] = p; + } else { + (*current)[i.first.substr(lpos)] = i.second; + } + } +} diff --git a/components/common/cpp/test/uri_unit.cpp b/components/common/cpp/test/uri_unit.cpp index be94d76c12c6eee26af890b8178def8fd5914b4b..59c5391f35f93050b42a6df8835de6b7ab22adfc 100644 --- a/components/common/cpp/test/uri_unit.cpp +++ b/components/common/cpp/test/uri_unit.cpp @@ -1,5 +1,6 @@ #include "catch.hpp" #include <ftl/uri.hpp> +#include <nlohmann/json.hpp> using ftl::URI; using std::string; @@ -124,6 +125,36 @@ SCENARIO( "URI::to_string() from a valid URI" ) { } } +SCENARIO( "URI::to_json() from a valid URI" ) { + GIVEN( "no query component" ) { + URI uri("http://localhost:1000/hello"); + + nlohmann::json object; + uri.to_json(object); + + REQUIRE( object["uri"].get<std::string>() == "http://localhost:1000/hello" ); + } + + GIVEN( "one numeric query item" ) { + URI uri("http://localhost:1000/hello?a=45"); + + nlohmann::json object; + uri.to_json(object); + + REQUIRE( object["a"].get<int>() == 45 ); + } + + GIVEN( "multiple query items" ) { + URI uri("http://localhost:1000/hello?a=45&b=world"); + + nlohmann::json object; + uri.to_json(object); + + REQUIRE( object["a"].get<int>() == 45 ); + REQUIRE( object["b"].get<std::string>() == "world" ); + } +} + SCENARIO( "URI::getAttribute() from query" ) { GIVEN( "a string value" ) { URI uri("http://localhost:1000/hello?x=world"); diff --git a/components/operators/include/ftl/operators/operator.hpp b/components/operators/include/ftl/operators/operator.hpp index 79cd008fdba46447dd4a79e51ba6521868604aa9..c8522cb9889b8f2c7a1de3291174917431ab4985 100644 --- a/components/operators/include/ftl/operators/operator.hpp +++ b/components/operators/include/ftl/operators/operator.hpp @@ -113,6 +113,8 @@ class Graph : public ftl::Configurable { bool apply(ftl::rgbd::FrameSet &in, ftl::rgbd::FrameSet &out, cudaStream_t stream=0); bool apply(ftl::rgbd::FrameSet &in, ftl::rgbd::Frame &out, cudaStream_t stream=0); + cudaStream_t getStream() const { return stream_; } + private: std::list<ftl::operators::detail::OperatorNode> operators_; std::map<std::string, ftl::Configurable*> configs_; diff --git a/components/rgbd-sources/src/sources/stereovideo/local.cpp b/components/rgbd-sources/src/sources/stereovideo/local.cpp index b571f35f46c519c60df9745c082db8820c01ab5b..023105bdc7bc7cd8eb69c3c86229477b8aeab099 100644 --- a/components/rgbd-sources/src/sources/stereovideo/local.cpp +++ b/components/rgbd-sources/src/sources/stereovideo/local.cpp @@ -66,6 +66,8 @@ LocalSource::LocalSource(nlohmann::json &config) camera_a_->set(cv::CAP_PROP_FRAME_WIDTH, value("width", 640)); camera_a_->set(cv::CAP_PROP_FRAME_HEIGHT, value("height", 480)); + //TODO: CAP_PROP_FPS + // CAP_PROP_BUFFERSIZE Mat frame; camera_a_->grab(); @@ -224,17 +226,6 @@ bool LocalSource::grab() { return false; } - // Record timestamp - double timestamp = duration_cast<duration<double>>( - high_resolution_clock::now().time_since_epoch()).count(); - - // Limit max framerate - //if (timestamp - timestamp_ < tps_) { - // sleep_for(milliseconds((int)std::round((tps_ - (timestamp - timestamp_))*1000))); - //} - - timestamp_ = timestamp; - return true; } diff --git a/components/rgbd-sources/src/sources/stereovideo/stereovideo.cpp b/components/rgbd-sources/src/sources/stereovideo/stereovideo.cpp index 7d5fb662fe467a07912fd6a4f208af5d5aadc11d..ae78c70aebf2b71b4dd13925d49f0bad93654009 100644 --- a/components/rgbd-sources/src/sources/stereovideo/stereovideo.cpp +++ b/components/rgbd-sources/src/sources/stereovideo/stereovideo.cpp @@ -51,6 +51,7 @@ StereoVideoSource::~StereoVideoSource() { void StereoVideoSource::init(const string &file) { capabilities_ = kCapVideo | kCapStereo; + calibrated_ = false; if (ftl::is_video(file)) { // Load video file @@ -95,6 +96,7 @@ void StereoVideoSource::init(const string &file) { if (calib_->loadCalibration(fname)) { calib_->calculateRectificationParameters(); calib_->setRectify(true); + calibrated_ = true; } } else { @@ -135,6 +137,8 @@ void StereoVideoSource::init(const string &file) { } } + calibrated_ = true; // Means we have intrinsics + return true; }); @@ -199,25 +203,41 @@ void StereoVideoSource::updateParameters() { // left - K = calib_->getCameraMatrixLeft(color_size_); - state_.getLeft() = { - static_cast<float>(K.at<double>(0,0)), // Fx - static_cast<float>(K.at<double>(1,1)), // Fy - static_cast<float>(-K.at<double>(0,2)), // Cx - static_cast<float>(-K.at<double>(1,2)), // Cy - (unsigned int) color_size_.width, - (unsigned int) color_size_.height, - min_depth, - max_depth, - baseline, - doff - }; - - host_->getConfig()["focal"] = params_.fx; - host_->getConfig()["centre_x"] = params_.cx; - host_->getConfig()["centre_y"] = params_.cy; - host_->getConfig()["baseline"] = params_.baseline; - host_->getConfig()["doffs"] = params_.doffs; + // FIXME: Check this change doesn't break anything (adding of calibrated_) + if (calibrated_) { + K = calib_->getCameraMatrixLeft(color_size_); + state_.getLeft() = { + static_cast<float>(K.at<double>(0,0)), // Fx + static_cast<float>(K.at<double>(1,1)), // Fy + static_cast<float>(-K.at<double>(0,2)), // Cx + static_cast<float>(-K.at<double>(1,2)), // Cy + (unsigned int) color_size_.width, + (unsigned int) color_size_.height, + min_depth, + max_depth, + baseline, + doff + }; + + host_->getConfig()["focal"] = params_.fx; + host_->getConfig()["centre_x"] = params_.cx; + host_->getConfig()["centre_y"] = params_.cy; + host_->getConfig()["baseline"] = params_.baseline; + host_->getConfig()["doffs"] = params_.doffs; + } else { + state_.getLeft() = { + host_->value("focal", 500.0f), // Fx + host_->value("focal", 500.0f), // Fy + host_->value("centre_x", -color_size_.width/2.0f), // Cx + host_->value("centre_y", -color_size_.height/2.0f), // Cy + (unsigned int) color_size_.width, + (unsigned int) color_size_.height, + min_depth, + max_depth, + baseline, + doff + }; + } // right diff --git a/components/rgbd-sources/src/sources/stereovideo/stereovideo.hpp b/components/rgbd-sources/src/sources/stereovideo/stereovideo.hpp index 4b6b60e63a522c8031f5cc386fe6211eba064b9f..2dfe96c3b789a47b5eb11f71ae554772889130b1 100644 --- a/components/rgbd-sources/src/sources/stereovideo/stereovideo.hpp +++ b/components/rgbd-sources/src/sources/stereovideo/stereovideo.hpp @@ -38,6 +38,7 @@ class StereoVideoSource : public detail::Source { LocalSource *lsrc_; Calibrate *calib_; + bool calibrated_; cv::Size color_size_; cv::Size depth_size_;