diff --git a/CMakeLists.txt b/CMakeLists.txt index 1991d5345a5c0b567b5d69897fdf57b3c6689d7d..c4192b464b45274d3bccf77f5719df45e7b677dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -225,6 +225,23 @@ find_library(UUID_LIBRARIES NAMES uuid libuuid) else() endif() +# For screen capture +if (WIN32) + message(STATUS "Screen capture not supported") +else() + find_package(X11) + if (X11_FOUND) + if (X11_XShm_FOUND) + message(STATUS "Using X11 for screen capture") + set(HAVE_X11 TRUE) + else() + message(STATUS "No X11 Shared memory extension") + endif() + else() + message(STATUS "No X11, screen capture disabled") + endif() +endif() + # For ftl2mkv check_include_file("libavformat/avformat.h" HAVE_AVFORMAT) diff --git a/applications/gui/src/camera.cpp b/applications/gui/src/camera.cpp index 615cdd86f06390bc405a1d0c7d51ddc2b82de939..a6f578179789ec079e2f58722257b645e30dccbf 100644 --- a/applications/gui/src/camera.cpp +++ b/applications/gui/src/camera.cpp @@ -141,7 +141,9 @@ static Eigen::Affine3d create_rotation_matrix(float ax, float ay, float az) { return rz * rx * ry; } -ftl::gui::Camera::Camera(ftl::gui::Screen *screen, int fsid, int fid, ftl::codecs::Channel c) : screen_(screen), fsid_(fsid), fid_(fid), channel_(c),channels_(0u) { +static int vcamcount = 0; + +ftl::gui::Camera::Camera(ftl::gui::Screen *screen, int fsmask, int fid, ftl::codecs::Channel c) : screen_(screen), fsmask_(fsmask), fid_(fid), channel_(c),channels_(0u) { eye_ = Eigen::Vector3d(0.0f, 0.0f, 0.0f); neye_ = Eigen::Vector4d(0.0f, 0.0f, 0.0f, 0.0f); rotmat_.setIdentity(); @@ -170,6 +172,7 @@ ftl::gui::Camera::Camera(ftl::gui::Screen *screen, int fsid, int fid, ftl::codec renderer_ = nullptr; post_pipe_ = nullptr; record_stream_ = nullptr; + transform_ix_ = -1; /*src->setCallback([this](int64_t ts, ftl::rgbd::Frame &frame) { UNIQUE_LOCK(mutex_, lk); @@ -189,35 +192,29 @@ ftl::gui::Camera::Camera(ftl::gui::Screen *screen, int fsid, int fid, ftl::codec } });*/ - auto *host = screen->root(); + //auto *host = screen->root(); // Is virtual camera? if (fid == 255) { - state_.getLeft().width = host->value("width", 1280); - state_.getLeft().height = host->value("height", 720); - state_.getLeft().fx = host->value("focal", 700.0f); - state_.getLeft().fy = state_.getLeft().fx; - state_.getLeft().cx = -(double)state_.getLeft().width / 2.0; - state_.getLeft().cy = -(double)state_.getLeft().height / 2.0; - state_.getLeft().minDepth = host->value("minDepth", 0.1f); - state_.getLeft().maxDepth = host->value("maxDepth", 15.0f); - state_.getLeft().doffs = 0; - state_.getLeft().baseline = host->value("baseline", 0.05f); - - state_.getRight().width = host->value("width", 1280); - state_.getRight().height = host->value("height", 720); - state_.getRight().fx = host->value("focal_right", 700.0f); - state_.getRight().fy = state_.getRight().fx; - state_.getRight().cx = host->value("centre_x_right", -(double)state_.getLeft().width / 2.0); - state_.getRight().cy = host->value("centre_y_right", -(double)state_.getLeft().height / 2.0); - state_.getRight().minDepth = host->value("minDepth", 0.1f); - state_.getRight().maxDepth = host->value("maxDepth", 15.0f); - state_.getRight().doffs = 0; - state_.getRight().baseline = host->value("baseline", 0.05f); + renderer_ = ftl::create<ftl::render::CUDARender>(screen_->root(), std::string("vcam")+std::to_string(vcamcount++)); + // Allow mask to be changed + fsmask_ = renderer_->value("fsmask", fsmask_); + renderer_->on("fsmask", [this](const ftl::config::Event &e) { + fsmask_ = renderer_->value("fsmask", fsmask_); + }); + + intrinsics_ = ftl::create<ftl::Configurable>(renderer_, "intrinsics"); + + state_.getLeft() = ftl::rgbd::Camera::from(intrinsics_); + state_.getRight() = state_.getLeft(); Eigen::Matrix4d pose; pose.setIdentity(); state_.setPose(pose); + + for (auto &t : transforms_) { + t.setIdentity(); + } } } @@ -228,13 +225,14 @@ ftl::gui::Camera::~Camera() { void ftl::gui::Camera::draw(std::vector<ftl::rgbd::FrameSet*> &fss) { if (fid_ != 255) return; - if (fsid_ >= fss.size()) return; + //if (fsid_ >= fss.size()) return; + + //auto &fs = *fss[fsid_]; - auto &fs = *fss[fsid_]; - - UNIQUE_LOCK(fs.mtx,lk); UNIQUE_LOCK(mutex_, lk2); - _draw(fs); + //state_.getLeft().fx = intrinsics_->value("focal", 700.0f); + //state_.getLeft().fy = state_.getLeft().fx; + _draw(fss); for (auto *fset : fss) { for (const auto &f : fset->frames) { @@ -264,16 +262,19 @@ void ftl::gui::Camera::draw(std::vector<ftl::rgbd::FrameSet*> &fss) { } } -void ftl::gui::Camera::_draw(ftl::rgbd::FrameSet &fs) { +void ftl::gui::Camera::_draw(std::vector<ftl::rgbd::FrameSet*> &fss) { frame_.reset(); frame_.setOrigin(&state_); - if (!renderer_) renderer_ = ftl::create<ftl::render::Triangular>(screen_->root(), "vcam1"); - Eigen::Matrix4d t; - t.setIdentity(); - renderer_->render(fs, frame_, channel_, t); - // TODO: Insert post-render pipeline. - // FXAA + Bad colour removal + renderer_->begin(frame_); + for (auto *fs : fss) { + if (!usesFrameset(fs->id)) continue; + + // FIXME: Should perhaps remain locked until after end is called? + UNIQUE_LOCK(fs->mtx,lk); + renderer_->submit(fs, Channels<0>(channel_), transforms_[fs->id]); + } + renderer_->end(); if (!post_pipe_) { post_pipe_ = ftl::config::create<ftl::operators::Graph>(screen_->root(), "post_filters"); @@ -289,14 +290,17 @@ void ftl::gui::Camera::_draw(ftl::rgbd::FrameSet &fs) { over_col.create(im1_.size(), CV_8UC4); over_depth.create(im1_.size(), CV_32F); - for (int i=0; i<fs.frames.size(); ++i) { - auto pose = fs.frames[i].getPose().inverse() * state_.getPose(); - Eigen::Vector4d pos = pose.inverse() * Eigen::Vector4d(0,0,0,1); - pos /= pos[3]; + for (auto *fs : fss) { + if (!usesFrameset(fs->id)) continue; + for (int i=0; i<fs->frames.size(); ++i) { + auto pose = fs->frames[i].getPose().inverse() * state_.getPose(); + Eigen::Vector4d pos = pose.inverse() * Eigen::Vector4d(0,0,0,1); + pos /= pos[3]; - auto name = fs.frames[i].get<std::string>("name"); - ftl::overlay::drawCamera(state_.getLeft(), im1_, over_depth, fs.frames[i].getLeftCamera(), pose, cv::Scalar(0,0,255,255), 0.2,screen_->root()->value("show_frustrum", false)); - if (name) ftl::overlay::drawText(state_.getLeft(), im1_, over_depth, *name, pos, 0.5, cv::Scalar(0,0,255,255)); + auto name = fs->frames[i].get<std::string>("name"); + ftl::overlay::drawCamera(state_.getLeft(), im1_, over_depth, fs->frames[i].getLeftCamera(), pose, cv::Scalar(0,0,255,255), 0.2,screen_->root()->value("show_frustrum", false)); + if (name) ftl::overlay::drawText(state_.getLeft(), im1_, over_depth, *name, pos, 0.5, cv::Scalar(0,0,255,255)); + } } } @@ -308,7 +312,7 @@ void ftl::gui::Camera::_draw(ftl::rgbd::FrameSet &fs) { fs2.mask = 1; fs2.stale = false; frame_.swapTo(Channels<0>(Channel::Colour), f); // Channel::Colour + Channel::Depth - fs2.timestamp = fs.timestamp; + fs2.timestamp = ftl::timer::get_time(); fs2.id = 0; record_sender_->post(fs2); record_stream_->select(0, Channels<0>(Channel::Colour)); @@ -341,27 +345,30 @@ void ftl::gui::Camera::_downloadFrames(ftl::rgbd::Frame *frame) { void ftl::gui::Camera::update(std::vector<ftl::rgbd::FrameSet*> &fss) { UNIQUE_LOCK(mutex_, lk); - if (fss.size() <= fsid_) return; - auto &fs = *fss[fsid_]; - - ftl::rgbd::Frame *frame = nullptr; - + //if (fss.size() <= fsid_) return; if (fid_ == 255) { name_ = "Virtual Camera"; // Do a draw if not active. If active the draw function will be called // directly. if (screen_->activeCamera() != this) { - _draw(fs); + _draw(fss); } } else { - if (fid_ >= fs.frames.size()) return; - frame = &fs.frames[fid_]; - _downloadFrames(frame); - auto n = frame->get<std::string>("name"); - if (n) { - name_ = *n; - } else { - name_ = "No name"; + for (auto *fs : fss) { + if (!usesFrameset(fs->id)) continue; + + ftl::rgbd::Frame *frame = nullptr; + + if (fid_ >= fs->frames.size()) return; + frame = &fs->frames[fid_]; + _downloadFrames(frame); + auto n = frame->get<std::string>("name"); + if (n) { + name_ = *n; + } else { + name_ = "No name"; + } + return; } } } @@ -424,6 +431,10 @@ void ftl::gui::Camera::keyMovement(int key, int modifiers) { float scalar = (key == 266) ? -mag : mag; neye_ += rotmat_*Eigen::Vector4d(0.0,scalar,0.0,1.0); return; + } else if (key >= '0' && key <= '5') { + int ix = key - (int)('0'); + transform_ix_ = ix-1; + return; } } @@ -623,7 +634,13 @@ const GLTexture &ftl::gui::Camera::captureFrame() { Eigen::Affine3d t(trans); Eigen::Matrix4d viewPose = t.matrix() * rotmat_; - if (isVirtual()) state_.setPose(viewPose); + if (isVirtual()) { + if (transform_ix_ < 0) { + state_.setPose(viewPose); + } else { + transforms_[transform_ix_] = viewPose; + } + } //src_->grab(); diff --git a/applications/gui/src/camera.hpp b/applications/gui/src/camera.hpp index 15f373e9bc9834c9f1f16856c167c40e4eb8a7ee..b92f241541c7af9e8a2f284eab6cf60cdf55bf56 100644 --- a/applications/gui/src/camera.hpp +++ b/applications/gui/src/camera.hpp @@ -2,7 +2,7 @@ #define _FTL_GUI_CAMERA_HPP_ #include <ftl/rgbd/frameset.hpp> -#include <ftl/render/tri_render.hpp> +#include <ftl/render/CUDARender.hpp> #include <ftl/codecs/writer.hpp> #include "gltexture.hpp" @@ -10,6 +10,7 @@ #include <ftl/streams/sender.hpp> #include <string> +#include <array> #ifdef HAVE_OPENVR #include <openvr/openvr.h> @@ -25,7 +26,7 @@ class PoseWindow; class Camera { public: - Camera(ftl::gui::Screen *screen, int fsid, int fid, ftl::codecs::Channel chan=ftl::codecs::Channel::Colour); + Camera(ftl::gui::Screen *screen, int fsmask, int fid, ftl::codecs::Channel chan=ftl::codecs::Channel::Colour); ~Camera(); Camera(const Camera &)=delete; @@ -33,7 +34,9 @@ class Camera { int width() const { return width_; } int height() const { return height_; } - int getFramesetId() const { return fsid_; } + int getFramesetMask() const { return fsmask_; } + + bool usesFrameset(int id) const { return fsmask_ & (1 << id); } void setPose(const Eigen::Matrix4d &p); @@ -93,7 +96,7 @@ class Camera { cv::Mat visualizeActiveChannel(); Screen *screen_; - int fsid_; + unsigned int fsmask_; // Frameset Mask int fid_; int width_; @@ -119,7 +122,8 @@ class Camera { cv::Mat im1_; // first channel (left) cv::Mat im2_; // second channel ("right") - ftl::render::Triangular *renderer_; + ftl::render::CUDARender *renderer_; + ftl::Configurable *intrinsics_; ftl::operators::Graph *post_pipe_; ftl::rgbd::Frame frame_; ftl::rgbd::FrameState state_; @@ -128,6 +132,9 @@ class Camera { std::string name_; + int transform_ix_; + std::array<Eigen::Matrix4d,ftl::stream::kMaxStreams> transforms_; // Frameset transforms for virtual cam + MUTEX mutex_; #ifdef HAVE_OPENVR @@ -137,7 +144,7 @@ class Camera { #endif void _downloadFrames(ftl::rgbd::Frame *frame); - void _draw(ftl::rgbd::FrameSet &fs); + void _draw(std::vector<ftl::rgbd::FrameSet*> &fss); }; } diff --git a/applications/gui/src/screen.cpp b/applications/gui/src/screen.cpp index 9a997d8403702bfab5fc2a26cf41bea4d1726cf5..70a79163b4a8ab7716df5bfbcf1846805301e962 100644 --- a/applications/gui/src/screen.cpp +++ b/applications/gui/src/screen.cpp @@ -463,7 +463,7 @@ bool ftl::gui::Screen::keyboardEvent(int key, int scancode, int action, int modi } else { //LOG(INFO) << "Key press " << key << " - " << action << " - " << modifiers; - if (key >= 262 && key <= 267) { + if ((key >= 262 && key <= 267) || (key >= '0' && key <= '9')) { if (camera_) camera_->keyMovement(key, modifiers); return true; } else if (action == 1 && key == 'H') { diff --git a/applications/gui/src/src_window.cpp b/applications/gui/src/src_window.cpp index 2ec91f8e41387f57fc3d4a8f163fb33863ba1e3f..c8adf88195352bd3e1ab543a9855048eed0e8501 100644 --- a/applications/gui/src/src_window.cpp +++ b/applications/gui/src/src_window.cpp @@ -109,7 +109,7 @@ SourceWindow::SourceWindow(ftl::gui::Screen *screen) }*/ const auto *cstream = interceptor_; - _createDefaultCameras(*framesets_[fs.id], cstream->available(fs.id).has(Channel::Depth)); + _createDefaultCameras(*framesets_[fs.id], true); // cstream->available(fs.id).has(Channel::Depth) //LOG(INFO) << "Channels = " << (unsigned int)cstream->available(fs.id); @@ -151,7 +151,7 @@ SourceWindow::SourceWindow(ftl::gui::Screen *screen) // Check paths for FTL files to load. auto paths = (*screen->root()->get<nlohmann::json>("paths")); - int ftl_count = 0; + int ftl_count = available_.size(); for (auto &x : paths.items()) { std::string path = x.value().get<std::string>(); auto eix = path.find_last_of('.'); @@ -205,7 +205,7 @@ void SourceWindow::stopRecordingVideo() { ftl::codecs::Channels<0> SourceWindow::_aggregateChannels(int id) { ftl::codecs::Channels<0> cs = ftl::codecs::Channels<0>(Channel::Colour); for (auto cam : cameras_) { - if (cam.second.camera->getFramesetId() == id) { + if (cam.second.camera->usesFrameset(id)) { if (cam.second.camera->isVirtual()) { cs += Channel::Depth; } else { @@ -215,6 +215,7 @@ ftl::codecs::Channels<0> SourceWindow::_aggregateChannels(int id) { } } } + return cs; } @@ -222,7 +223,7 @@ void SourceWindow::_createDefaultCameras(ftl::rgbd::FrameSet &fs, bool makevirtu for (int i=0; i<fs.frames.size(); ++i) { int id = (fs.id << 8) + i; if (cameras_.find(id) == cameras_.end()) { - auto *cam = new ftl::gui::Camera(screen_, fs.id, i); + auto *cam = new ftl::gui::Camera(screen_, 1 << fs.id, i); cameras_[id] = { cam, nullptr @@ -231,7 +232,7 @@ void SourceWindow::_createDefaultCameras(ftl::rgbd::FrameSet &fs, bool makevirtu } if (makevirtual && cameras_.find((fs.id << 8) + 255) == cameras_.end()) { - auto *cam = new ftl::gui::Camera(screen_, fs.id, 255); + auto *cam = new ftl::gui::Camera(screen_, 1 << fs.id, 255); cameras_[(fs.id << 8) + 255] = { cam, nullptr diff --git a/applications/reconstruct/src/main.cpp b/applications/reconstruct/src/main.cpp index 0b5a71d7d8a15ee025e5135d4f703df528f2963d..3e35b5ad96eec52c81a26dd50d6e66e8ac52405c 100644 --- a/applications/reconstruct/src/main.cpp +++ b/applications/reconstruct/src/main.cpp @@ -19,9 +19,6 @@ #include "reconstruction.hpp" -#include "ilw/ilw.hpp" -#include <ftl/render/tri_render.hpp> - #include <fstream> #include <string> #include <vector> diff --git a/applications/reconstruct/src/reconstruction.cpp b/applications/reconstruct/src/reconstruction.cpp index 524128dd5af15784609c89fd1f3c5681a566bb54..9ae89fc0d15fb791cb7c7b35ba9fe979b0757e4b 100644 --- a/applications/reconstruct/src/reconstruction.cpp +++ b/applications/reconstruct/src/reconstruction.cpp @@ -128,7 +128,7 @@ void Reconstruction::addRawCallback(const std::function<void(ftl::rgbd::Source * group_->addRawCallback(cb); }*/ -bool Reconstruction::render(ftl::rgbd::VirtualSource *vs, ftl::rgbd::Frame &out) { +/*bool Reconstruction::render(ftl::rgbd::VirtualSource *vs, ftl::rgbd::Frame &out) { { UNIQUE_LOCK(exchange_mtx_, lk); if (new_frame_) { @@ -136,11 +136,7 @@ bool Reconstruction::render(ftl::rgbd::VirtualSource *vs, ftl::rgbd::Frame &out) fs_align_.swapTo(fs_render_); } } - /*if (fs_render_.stale || fs_render_.timestamp <= 0) { - LOG(ERROR) << "STALE FRAME TO RENDER"; - return false; - } - fs_render_.stale = true;*/ + // Create scene transform, intended for axis aligning the walls and floor Eigen::Matrix4d transform; @@ -166,4 +162,4 @@ bool Reconstruction::render(ftl::rgbd::VirtualSource *vs, ftl::rgbd::Frame &out) bool res = false; //renderer_->render(vs, out, sm.matrix() * transform); //fs_render_.resetFull(); return res; -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/applications/reconstruct/src/reconstruction.hpp b/applications/reconstruct/src/reconstruction.hpp index 82cecd9ed8fa3466c15f1608c039dd8f2a9f8a8a..4e545cf8520158e23891d6d37819f354768c95b9 100644 --- a/applications/reconstruct/src/reconstruction.hpp +++ b/applications/reconstruct/src/reconstruction.hpp @@ -7,7 +7,6 @@ #include "ftl/rgbd/group.hpp" #include "ftl/rgbd/frameset.hpp" #include "ftl/operators/operator.hpp" -#include "ftl/render/tri_render.hpp" namespace ftl { @@ -22,11 +21,6 @@ class Reconstruction : public ftl::Configurable, public ftl::rgbd::Generator { void setGenerator(ftl::rgbd::Generator *); - /** - * Do the render for a specified virtual camera. - */ - bool render(ftl::rgbd::VirtualSource *vs, ftl::rgbd::Frame &out); - /** Number of frames in last frameset. This can change over time. */ size_t size() override; @@ -51,7 +45,6 @@ class Reconstruction : public ftl::Configurable, public ftl::rgbd::Generator { ftl::rgbd::FrameSet fs_align_; ftl::rgbd::Generator *gen_; ftl::operators::Graph *pipeline_; - ftl::render::Triangular *renderer_; ftl::rgbd::VideoCallback cb_; diff --git a/components/common/cpp/include/ftl/config.h.in b/components/common/cpp/include/ftl/config.h.in index f36fe3b73b61d3d32b5a2ee564430cf56d7eec89..bcbebd958a9b6f1c6aff58f9c0907a882905ae15 100644 --- a/components/common/cpp/include/ftl/config.h.in +++ b/components/common/cpp/include/ftl/config.h.in @@ -25,6 +25,7 @@ #cmakedefine HAVE_OPENVR #cmakedefine HAVE_NVPIPE #cmakedefine HAVE_PORTAUDIO +#cmakedefine HAVE_X11 extern const char *FTL_BRANCH; extern const char *FTL_VERSION_LONG; diff --git a/components/renderers/cpp/CMakeLists.txt b/components/renderers/cpp/CMakeLists.txt index 0d292b397c07d5406ab68e9d8084fb27cc9129b7..66a930c2c515c818010ddae5557ad976a9ca2d70 100644 --- a/components/renderers/cpp/CMakeLists.txt +++ b/components/renderers/cpp/CMakeLists.txt @@ -6,7 +6,7 @@ add_library(ftlrender src/screen.cu src/triangle_render.cu src/reprojection.cu - src/tri_render.cpp + src/CUDARender.cpp ) target_include_directories(ftlrender PUBLIC diff --git a/components/renderers/cpp/include/ftl/render/tri_render.hpp b/components/renderers/cpp/include/ftl/render/CUDARender.hpp similarity index 74% rename from components/renderers/cpp/include/ftl/render/tri_render.hpp rename to components/renderers/cpp/include/ftl/render/CUDARender.hpp index 8e47d80e0d2e0a74f6ca9f9a1b9c7be4997f4f24..616f78a199a4fa0e36ced654e7c18b8a3452c450 100644 --- a/components/renderers/cpp/include/ftl/render/tri_render.hpp +++ b/components/renderers/cpp/include/ftl/render/CUDARender.hpp @@ -1,10 +1,11 @@ -#ifndef _FTL_RECONSTRUCTION_TRI_HPP_ -#define _FTL_RECONSTRUCTION_TRI_HPP_ +#ifndef _FTL_RENDER_CUDA_HPP_ +#define _FTL_RENDER_CUDA_HPP_ #include <ftl/render/renderer.hpp> #include <ftl/rgbd/frameset.hpp> #include <ftl/render/splat_params.hpp> #include <ftl/cuda/points.hpp> +#include <ftl/codecs/channels.hpp> //#include <ftl/filters/filter.hpp> namespace ftl { @@ -14,12 +15,15 @@ namespace render { * Generate triangles between connected points and render those. Colour is done * by weighted reprojection to the original source images. */ -class Triangular : public ftl::render::Renderer { +class CUDARender : public ftl::render::Renderer { public: - explicit Triangular(nlohmann::json &config); - ~Triangular(); + explicit CUDARender(nlohmann::json &config); + ~CUDARender(); - bool render(ftl::rgbd::FrameSet &in, ftl::rgbd::Frame &out, ftl::codecs::Channel, const Eigen::Matrix4d &t) override; + void begin(ftl::rgbd::Frame &) override; + void end() override; + + bool submit(ftl::rgbd::FrameSet *in, ftl::codecs::Channels<0>, const Eigen::Matrix4d &t) override; //void setOutputDevice(int); protected: @@ -29,6 +33,7 @@ class Triangular : public ftl::render::Renderer { int device_; ftl::rgbd::Frame temp_; ftl::rgbd::Frame accum_; + ftl::rgbd::Frame *out_; ftl::rgbd::FrameSet *scene_; ftl::cuda::ClipSpace clip_; bool clipping_; @@ -51,6 +56,14 @@ class Triangular : public ftl::render::Renderer { //ftl::Filters *filters_; + struct SubmitState { + ftl::rgbd::FrameSet *fs; + ftl::codecs::Channels<0> channels; + Eigen::Matrix4d transform; + }; + + std::vector<SubmitState> sets_; + template <typename T> void __reprojectChannel(ftl::rgbd::Frame &, ftl::codecs::Channel in, ftl::codecs::Channel out, const Eigen::Matrix4d &t, cudaStream_t); void _reprojectChannel(ftl::rgbd::Frame &, ftl::codecs::Channel in, ftl::codecs::Channel out, const Eigen::Matrix4d &t, cudaStream_t); @@ -65,7 +78,8 @@ class Triangular : public ftl::render::Renderer { void _renderDensity(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t); void _renderRight(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t); void _renderSecond(ftl::rgbd::Frame &out, ftl::codecs::Channel chan, const Eigen::Matrix4d &t); - void _render(ftl::rgbd::FrameSet &in, ftl::rgbd::Frame &out, ftl::codecs::Channel, const Eigen::Matrix4d &t); + void _renderPass1(const Eigen::Matrix4d &t); + void _renderPass2(ftl::codecs::Channels<0>, const Eigen::Matrix4d &t); bool _alreadySeen() const { return last_frame_ == scene_->timestamp; } }; @@ -73,4 +87,4 @@ class Triangular : public ftl::render::Renderer { } } -#endif // _FTL_RECONSTRUCTION_TRI_HPP_ +#endif // _FTL_RENDER_CUDA_HPP_ diff --git a/components/renderers/cpp/include/ftl/render/renderer.hpp b/components/renderers/cpp/include/ftl/render/renderer.hpp index 3a36655147fc58a34c2b5605f28f949d93238fab..ec479ce51e3b494b4df6818303c1aeb5db480bad 100644 --- a/components/renderers/cpp/include/ftl/render/renderer.hpp +++ b/components/renderers/cpp/include/ftl/render/renderer.hpp @@ -21,11 +21,26 @@ class Renderer : public ftl::Configurable { explicit Renderer(nlohmann::json &config) : Configurable(config) {}; virtual ~Renderer() {}; + /** + * Begin a new render. This clears memory, allocates buffers etc. The RGBD + * frame given as parameter is where the output channels are rendered to. + */ + virtual void begin(ftl::rgbd::Frame &)=0; + + /** + * Finish a render. Post process the output as required, or finish + * generating it from internal buffers. The output frame is only valid + * after this is called. + */ + virtual void end()=0; + /** - * Generate a single virtual frame. The frame takes its pose and calibration - * from the output frame pose and calibration channels. + * Render all frames of a frameset into the output frame. This can be called + * multiple times between `begin` and `end` to combine multiple framesets. + * Note that the frameset pointer must remain valid until `end` is called, + * and ideally should not be swapped between */ - virtual bool render(ftl::rgbd::FrameSet &, ftl::rgbd::Frame &, ftl::codecs::Channel, const Eigen::Matrix4d &)=0; + virtual bool submit(ftl::rgbd::FrameSet *, ftl::codecs::Channels<0>, const Eigen::Matrix4d &)=0; }; } diff --git a/components/renderers/cpp/include/ftl/render/splat_render.hpp b/components/renderers/cpp/include/ftl/render/splat_render.hpp deleted file mode 100644 index 8e51aadf15b8e32d05b3253e72cb2adc7e69f98b..0000000000000000000000000000000000000000 --- a/components/renderers/cpp/include/ftl/render/splat_render.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef _FTL_RECONSTRUCTION_SPLAT_HPP_ -#define _FTL_RECONSTRUCTION_SPLAT_HPP_ - -#include <ftl/render/renderer.hpp> -#include <ftl/rgbd/frameset.hpp> -#include <ftl/render/splat_params.hpp> -#include <ftl/cuda/points.hpp> - -namespace ftl { -namespace render { - -/** - * Render the voxel hash structure by generating image points for surface - * voxels and expanding those into interpolated splats. This is a two pass - * algorithm with the option of completing the second pass on a separate GPU. - * It also possible to only complete the first pass and perform the second step - * on a separate machine or at a later time, the advantage being to save local - * processing resources and that the first pass result may compress better. - */ -class Splatter : public ftl::render::Renderer { - public: - explicit Splatter(nlohmann::json &config, ftl::rgbd::FrameSet *fs); - ~Splatter(); - - bool render(ftl::rgbd::VirtualSource *src, ftl::rgbd::Frame &out, const Eigen::Matrix4d &t) override; - //void setOutputDevice(int); - - protected: - void _renderChannel(ftl::rgbd::Frame &out, ftl::codecs::Channel channel_in, ftl::codecs::Channel channel_out, cudaStream_t stream); - - private: - int device_; - /*ftl::cuda::TextureObject<int> depth1_; - ftl::cuda::TextureObject<int> depth3_; - ftl::cuda::TextureObject<uchar4> colour1_; - ftl::cuda::TextureObject<float4> colour_tmp_; - ftl::cuda::TextureObject<float> depth2_; - ftl::cuda::TextureObject<uchar4> colour2_; - ftl::cuda::TextureObject<float4> normal1_;*/ - //SplatParams params_; - - ftl::rgbd::Frame temp_; - ftl::rgbd::Frame accum_; - ftl::rgbd::FrameSet *scene_; - ftl::cuda::ClipSpace clip_; - bool clipping_; - float norm_filter_; - bool backcull_; - cv::Scalar background_; - bool splat_; - float3 light_dir_; - uchar4 light_diffuse_; - uchar4 light_ambient_; - ftl::render::SplatParams params_; - cudaStream_t stream_; - float3 light_pos_; - - template <typename T> - void __blendChannel(ftl::rgbd::Frame &, ftl::codecs::Channel in, ftl::codecs::Channel out, cudaStream_t); - void _blendChannel(ftl::rgbd::Frame &, ftl::codecs::Channel in, ftl::codecs::Channel out, cudaStream_t); - void _dibr(cudaStream_t); -}; - -} -} - -#endif // _FTL_RECONSTRUCTION_SPLAT_HPP_ diff --git a/components/renderers/cpp/src/tri_render.cpp b/components/renderers/cpp/src/CUDARender.cpp similarity index 78% rename from components/renderers/cpp/src/tri_render.cpp rename to components/renderers/cpp/src/CUDARender.cpp index 5120746fc12d32ed60fd2fed28bc4420d966e548..a40c792251dfce60f88ee0f6883307b7fa727cc7 100644 --- a/components/renderers/cpp/src/tri_render.cpp +++ b/components/renderers/cpp/src/CUDARender.cpp @@ -1,4 +1,4 @@ -#include <ftl/render/tri_render.hpp> +#include <ftl/render/CUDARender.hpp> #include <ftl/utility/matrix_conversion.hpp> #include "splatter_cuda.hpp" #include <ftl/cuda/points.hpp> @@ -16,7 +16,7 @@ #include <string> -using ftl::render::Triangular; +using ftl::render::CUDARender; using ftl::codecs::Channel; using ftl::codecs::Channels; using ftl::rgbd::Format; @@ -72,7 +72,7 @@ static uchar4 parseCUDAColour(const std::string &colour) { return make_uchar4(0,0,0,0); } -Triangular::Triangular(nlohmann::json &config) : ftl::render::Renderer(config), scene_(nullptr) { +CUDARender::CUDARender(nlohmann::json &config) : ftl::render::Renderer(config), scene_(nullptr) { /*if (config["clipping"].is_object()) { auto &c = config["clipping"]; float rx = c.value("pitch", 0.0f); @@ -155,7 +155,7 @@ Triangular::Triangular(nlohmann::json &config) : ftl::render::Renderer(config), last_frame_ = -1; } -Triangular::~Triangular() { +CUDARender::~CUDARender() { } @@ -173,66 +173,12 @@ struct AccumSelector<float> { //static constexpr cv::Scalar value = cv::Scalar(0.0f); }; -/*template <typename T> -void Triangular::__blendChannel(ftl::rgbd::Frame &output, ftl::codecs::Channel in, ftl::codecs::Channel out, cudaStream_t stream) { - cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream); - temp_.create<GpuMat>( - AccumSelector<T>::channel, - Format<typename AccumSelector<T>::type>(params_.camera.width, params_.camera.height) - ).setTo(cv::Scalar(0.0f), cvstream); - temp_.get<GpuMat>(Channel::Contribution).setTo(cv::Scalar(0.0f), cvstream); - - temp_.createTexture<float>(Channel::Contribution); - - for (auto &f : scene_->frames) { - if (f.get<GpuMat>(in).type() == CV_8UC3) { - // Convert to 4 channel colour - auto &col = f.get<GpuMat>(in); - GpuMat tmp(col.size(), CV_8UC4); - cv::cuda::swap(col, tmp); - cv::cuda::cvtColor(tmp,col, cv::COLOR_BGR2BGRA); - } - - ftl::cuda::dibr_attribute( - f.createTexture<T>(in), - f.createTexture<float4>(Channel::Points), - temp_.getTexture<int>(Channel::Depth2), - temp_.createTexture<typename AccumSelector<T>::type>(AccumSelector<T>::channel), - temp_.getTexture<float>(Channel::Contribution), - params_, stream - ); - } - - ftl::cuda::dibr_normalise( - temp_.getTexture<typename AccumSelector<T>::type>(AccumSelector<T>::channel), - output.createTexture<T>(out), - temp_.getTexture<float>(Channel::Contribution), - stream - ); -}*/ - template <typename T> -void Triangular::__reprojectChannel(ftl::rgbd::Frame &output, ftl::codecs::Channel in, ftl::codecs::Channel out, const Eigen::Matrix4d &t, cudaStream_t stream) { +void CUDARender::__reprojectChannel(ftl::rgbd::Frame &output, ftl::codecs::Channel in, ftl::codecs::Channel out, const Eigen::Matrix4d &t, cudaStream_t stream) { cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream); - temp_.create<GpuMat>( - AccumSelector<T>::channel, - Format<typename AccumSelector<T>::type>(params_.camera.width, params_.camera.height) - ).setTo(cv::Scalar(0.0f), cvstream); - temp_.get<GpuMat>(Channel::Contribution).setTo(cv::Scalar(0.0f), cvstream); - - temp_.createTexture<float>(Channel::Contribution); for (size_t i=0; i < scene_->frames.size(); ++i) { auto &f = scene_->frames[i]; - //auto *s = scene_->sources[i]; - - /*if (f.get<GpuMat>(in).type() == CV_8UC3) { - // Convert to 4 channel colour - auto &col = f.get<GpuMat>(in); - GpuMat tmp(col.size(), CV_8UC4); - cv::cuda::swap(col, tmp); - cv::cuda::cvtColor(tmp,col, cv::COLOR_BGR2BGRA); - }*/ if (!f.hasChannel(in)) { LOG(ERROR) << "Reprojecting unavailable channel"; @@ -243,52 +189,59 @@ void Triangular::__reprojectChannel(ftl::rgbd::Frame &output, ftl::codecs::Chann auto transformR = MatrixConversion::toCUDA(f.getPose().cast<float>().inverse()).getFloat3x3(); if (mesh_) { - ftl::cuda::reproject( - f.createTexture<T>(in), - f.createTexture<float>(Channel::Depth), - output.getTexture<float>(Channel::Depth), - output.getTexture<float4>(Channel::Normals), - temp_.createTexture<typename AccumSelector<T>::type>(AccumSelector<T>::channel), - temp_.getTexture<float>(Channel::Contribution), - params_, - f.getLeftCamera(), - transform, transformR, stream - ); + if (f.hasChannel(Channel::Depth)) { + ftl::cuda::reproject( + f.createTexture<T>(in), + f.createTexture<float>(Channel::Depth), + output.getTexture<float>(Channel::Depth), + output.getTexture<float4>(Channel::Normals), + temp_.createTexture<typename AccumSelector<T>::type>(AccumSelector<T>::channel), + temp_.getTexture<float>(Channel::Contribution), + params_, + f.getLeftCamera(), + transform, transformR, stream + ); + } else { + // Reproject without depth channel or normals + ftl::cuda::reproject( + f.createTexture<T>(in), + output.getTexture<float>(Channel::Depth), + temp_.createTexture<typename AccumSelector<T>::type>(AccumSelector<T>::channel), + temp_.getTexture<float>(Channel::Contribution), + params_, + f.getLeftCamera(), + transform, stream + ); + } } else { // Can't use normals with point cloud version - ftl::cuda::reproject( - f.createTexture<T>(in), - f.createTexture<float>(Channel::Depth), - output.getTexture<float>(Channel::Depth), - temp_.createTexture<typename AccumSelector<T>::type>(AccumSelector<T>::channel), - temp_.getTexture<float>(Channel::Contribution), - params_, - f.getLeftCamera(), - transform, stream - ); + if (f.hasChannel(Channel::Depth)) { + ftl::cuda::reproject( + f.createTexture<T>(in), + f.createTexture<float>(Channel::Depth), + output.getTexture<float>(Channel::Depth), + temp_.createTexture<typename AccumSelector<T>::type>(AccumSelector<T>::channel), + temp_.getTexture<float>(Channel::Contribution), + params_, + f.getLeftCamera(), + transform, stream + ); + } else { + ftl::cuda::reproject( + f.createTexture<T>(in), + output.getTexture<float>(Channel::Depth), + temp_.createTexture<typename AccumSelector<T>::type>(AccumSelector<T>::channel), + temp_.getTexture<float>(Channel::Contribution), + params_, + f.getLeftCamera(), + transform, stream + ); + } } } - - ftl::cuda::dibr_normalise( - temp_.getTexture<typename AccumSelector<T>::type>(AccumSelector<T>::channel), - output.createTexture<T>(out), - temp_.getTexture<float>(Channel::Contribution), - stream - ); } -/*void Triangular::_blendChannel(ftl::rgbd::Frame &output, ftl::codecs::Channel in, ftl::codecs::Channel out, cudaStream_t stream) { - int type = output.get<GpuMat>(out).type(); // == CV_32F; //ftl::rgbd::isFloatChannel(channel); - - switch (type) { - case CV_32F : __blendChannel<float>(output, in, out, stream); break; - case CV_32FC4 : __blendChannel<float4>(output, in, out, stream); break; - case CV_8UC4 : __blendChannel<uchar4>(output, in, out, stream); break; - default : LOG(ERROR) << "Invalid output channel format"; - } -}*/ - -void Triangular::_reprojectChannel(ftl::rgbd::Frame &output, ftl::codecs::Channel in, ftl::codecs::Channel out, const Eigen::Matrix4d &t, cudaStream_t stream) { +void CUDARender::_reprojectChannel(ftl::rgbd::Frame &output, ftl::codecs::Channel in, ftl::codecs::Channel out, const Eigen::Matrix4d &t, cudaStream_t stream) { int type = output.get<GpuMat>(out).type(); // == CV_32F; //ftl::rgbd::isFloatChannel(channel); switch (type) { @@ -299,7 +252,7 @@ void Triangular::_reprojectChannel(ftl::rgbd::Frame &output, ftl::codecs::Channe } } -void Triangular::_dibr(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t, cudaStream_t stream) { +void CUDARender::_dibr(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t, cudaStream_t stream) { cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream); temp_.get<GpuMat>(Channel::Depth2).setTo(cv::Scalar(0x7FFFFFFF), cvstream); @@ -307,27 +260,36 @@ void Triangular::_dibr(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t, cudaStre auto &f = scene_->frames[i]; //auto *s = scene_->sources[i]; - if (f.empty(Channel::Depth + Channel::Colour)) { + if (f.empty(Channel::Colour)) { LOG(ERROR) << "Missing required channel"; continue; } auto transform = params_.m_viewMatrix * MatrixConversion::toCUDA(t.cast<float>() * f.getPose().cast<float>()); - ftl::cuda::dibr_merge( - f.createTexture<float>(Channel::Depth), - temp_.createTexture<int>(Channel::Depth2), - transform, - f.getLeftCamera(), - params_, stream - ); + if (f.hasChannel(Channel::Depth)) { + ftl::cuda::dibr_merge( + f.createTexture<float>(Channel::Depth), + temp_.createTexture<int>(Channel::Depth2), + transform, + f.getLeftCamera(), + params_, stream + ); + } else { + ftl::cuda::dibr_merge( + temp_.createTexture<int>(Channel::Depth2), + transform, + f.getLeftCamera(), + params_, stream + ); + } } // Convert from int depth to float depth temp_.get<GpuMat>(Channel::Depth2).convertTo(out.get<GpuMat>(Channel::Depth), CV_32F, 1.0f / 100000.0f, cvstream); } -void Triangular::_mesh(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t, cudaStream_t stream) { +void CUDARender::_mesh(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t, cudaStream_t stream) { cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream); bool do_blend = value("mesh_blend", true); @@ -344,7 +306,7 @@ void Triangular::_mesh(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t, cudaStre auto &f = scene_->frames[i]; //auto *s = scene_->sources[i]; - if (f.empty(Channel::Depth + Channel::Colour)) { + if (f.empty(Channel::Colour)) { LOG(ERROR) << "Missing required channel"; continue; } @@ -353,12 +315,21 @@ void Triangular::_mesh(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t, cudaStre auto transform = params_.m_viewMatrix * MatrixConversion::toCUDA(t.cast<float>() * f.getPose().cast<float>()); // Calculate and save virtual view screen position of each source pixel - ftl::cuda::screen_coord( - f.createTexture<float>(Channel::Depth), - f.createTexture<float>(Channel::Depth2, Format<float>(f.get<GpuMat>(Channel::Depth).size())), - f.createTexture<short2>(Channel::Screen, Format<short2>(f.get<GpuMat>(Channel::Depth).size())), - params_, transform, f.getLeftCamera(), stream - ); + if (f.hasChannel(Channel::Depth)) { + ftl::cuda::screen_coord( + f.createTexture<float>(Channel::Depth), + f.createTexture<float>(Channel::Depth2, Format<float>(f.get<GpuMat>(Channel::Depth).size())), + f.createTexture<short2>(Channel::Screen, Format<short2>(f.get<GpuMat>(Channel::Depth).size())), + params_, transform, f.getLeftCamera(), stream + ); + } else { + // Constant depth version + ftl::cuda::screen_coord( + f.createTexture<float>(Channel::Depth2, Format<float>(f.get<GpuMat>(Channel::Colour).size())), + f.createTexture<short2>(Channel::Screen, Format<short2>(f.get<GpuMat>(Channel::Colour).size())), + params_, transform, f.getLeftCamera(), stream + ); + } // Must reset depth channel if blending if (do_blend) { @@ -399,7 +370,7 @@ void Triangular::_mesh(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t, cudaStre params_.camera, params_.m_viewMatrix.getFloat3x3(), params_.m_viewMatrixInverse.getFloat3x3(), stream_); } -void Triangular::_renderChannel( +void CUDARender::_renderChannel( ftl::rgbd::Frame &out, Channel channel_in, Channel channel_out, const Eigen::Matrix4d &t, cudaStream_t stream) { @@ -476,7 +447,7 @@ static cv::Scalar HSVtoRGB(int H, double S, double V) { return cv::Scalar((Bs + m) * 255, (Gs + m) * 255, (Rs + m) * 255, 0); } -void Triangular::_allocateChannels(ftl::rgbd::Frame &out) { +void CUDARender::_allocateChannels(ftl::rgbd::Frame &out) { const auto &camera = out.getLeftCamera(); cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream_); @@ -497,7 +468,7 @@ void Triangular::_allocateChannels(ftl::rgbd::Frame &out) { temp_.createTexture<int>(Channel::Depth); } -void Triangular::_updateParameters(ftl::rgbd::Frame &out) { +void CUDARender::_updateParameters(ftl::rgbd::Frame &out) { const auto &camera = out.getLeftCamera(); // Parameters object to pass to CUDA describing the camera @@ -510,7 +481,7 @@ void Triangular::_updateParameters(ftl::rgbd::Frame &out) { params_.camera = camera; } -void Triangular::_preprocessColours() { +void CUDARender::_preprocessColours() { bool show_discon = value("show_discontinuity_mask", false); bool show_fill = value("show_filled", false); bool colour_sources = value("colour_sources", false); @@ -540,7 +511,7 @@ void Triangular::_preprocessColours() { } } -void Triangular::_postprocessColours(ftl::rgbd::Frame &out) { +void CUDARender::_postprocessColours(ftl::rgbd::Frame &out) { if (value("cool_effect", false)) { auto pose = params_.m_viewMatrixInverse.getFloat3x3(); auto col = parseCUDAColour(value("cool_effect_colour", std::string("#2222ff"))); @@ -574,7 +545,7 @@ void Triangular::_postprocessColours(ftl::rgbd::Frame &out) { } } -void Triangular::_renderNormals(ftl::rgbd::Frame &out) { +void CUDARender::_renderNormals(ftl::rgbd::Frame &out) { cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream_); // Visualise normals to RGBA @@ -586,14 +557,14 @@ void Triangular::_renderNormals(ftl::rgbd::Frame &out) { light_ambient_, stream_); } -void Triangular::_renderDensity(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t) { +void CUDARender::_renderDensity(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t) { cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream_); out.create<GpuMat>(Channel::Density, Format<float>(params_.camera.width, params_.camera.height)); out.get<GpuMat>(Channel::Density).setTo(cv::Scalar(0.0f), cvstream); _renderChannel(out, Channel::Depth, Channel::Density, t, stream_); } -void Triangular::_renderRight(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t) { +void CUDARender::_renderRight(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t) { cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream_); float baseline = params_.camera.baseline; @@ -619,7 +590,7 @@ void Triangular::_renderRight(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t) { _renderChannel(out, Channel::Left, Channel::Right, t, stream_); } -void Triangular::_renderSecond(ftl::rgbd::Frame &out, ftl::codecs::Channel chan, const Eigen::Matrix4d &t) { +void CUDARender::_renderSecond(ftl::rgbd::Frame &out, ftl::codecs::Channel chan, const Eigen::Matrix4d &t) { cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream_); if (ftl::codecs::isFloatChannel(chan)) { @@ -632,10 +603,49 @@ void Triangular::_renderSecond(ftl::rgbd::Frame &out, ftl::codecs::Channel chan, _renderChannel(out, chan, chan, t, stream_); } -void Triangular::_render(ftl::rgbd::FrameSet &in, ftl::rgbd::Frame &out, Channel chan, const Eigen::Matrix4d &t) { +void CUDARender::_renderPass1(const Eigen::Matrix4d &t) { + const auto &camera = out_->getLeftCamera(); + cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream_); + + // Render source specific debug info into colour channels + _preprocessColours(); + + if (mesh_) { + // Render depth channel using triangles + _mesh(*out_, t, stream_); + } else { + // Render depth channel as a point cloud + _dibr(*out_, t, stream_); + } +} + +void CUDARender::_renderPass2(Channels<0> chans, const Eigen::Matrix4d &t) { + const auto &camera = out_->getLeftCamera(); + cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream_); + + // Reprojection of colours onto surface + auto main_channel = (scene_->frames[0].hasChannel(Channel::ColourHighRes)) ? Channel::ColourHighRes : Channel::Colour; + _renderChannel(*out_, main_channel, Channel::Colour, t, stream_); + + + // Support rendering of a second channel without redoing all the work + for (auto chan : chans) { + switch(chan) { + case Channel::None : + case Channel::Left : + case Channel::Depth : break; + case Channel::ColourNormals : _renderNormals(*out_); break; + case Channel::Density : _renderDensity(*out_, t); break; + case Channel::Right : _renderRight(*out_, t); break; + default : _renderSecond(*out_, chan, t); + } + } +} + +void CUDARender::begin(ftl::rgbd::Frame &out) { + out_ = &out; const auto &camera = out.getLeftCamera(); cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream_); - //cudaSafeCall(cudaSetDevice(scene_->getCUDADevice())); _updateParameters(out); @@ -653,52 +663,54 @@ void Triangular::_render(ftl::rgbd::FrameSet &in, ftl::rgbd::Frame &out, Channel camera, pose, stream_); } - //cudaSafeCall(cudaStreamSynchronize(stream_)); + temp_.create<GpuMat>( + AccumSelector<uchar4>::channel, + Format<typename AccumSelector<uchar4>::type>(params_.camera.width, params_.camera.height) + ).setTo(cv::Scalar(0.0f), cvstream); + temp_.get<GpuMat>(Channel::Contribution).setTo(cv::Scalar(0.0f), cvstream); - // Render source specific debug info into colour channels - _preprocessColours(); + temp_.createTexture<float>(Channel::Contribution); - //cudaSafeCall(cudaStreamSynchronize(stream_)); + sets_.clear(); +} - if (mesh_) { - // Render depth channel using triangles - _mesh(out, t, stream_); - } else { - // Render depth channel as a point cloud - _dibr(out, t, stream_); +void CUDARender::end() { + /*ftl::cuda::dibr_normalise( + temp_.getTexture<typename AccumSelector<T>::type>(AccumSelector<T>::channel), + output.createTexture<T>(out), + temp_.getTexture<float>(Channel::Contribution), + stream + );*/ + + for (auto &s : sets_) { + scene_ = s.fs; + try { + _renderPass2(s.channels, s.transform); + } catch(std::exception &e) { + LOG(ERROR) << "Exception in render: " << e.what(); + } } + scene_ = nullptr; - //cudaSafeCall(cudaStreamSynchronize(stream_)); - - // Reprojection of colours onto surface - auto main_channel = (scene_->frames[0].hasChannel(Channel::ColourHighRes)) ? Channel::ColourHighRes : Channel::Colour; - _renderChannel(out, main_channel, Channel::Colour, t, stream_); - - //cudaSafeCall(cudaStreamSynchronize(stream_)); - - // Debug colour info relating to the rendering process - _postprocessColours(out); + // FIXME: Allow for other channel accumulations + ftl::cuda::dibr_normalise( + temp_.getTexture<typename AccumSelector<uchar4>::type>(AccumSelector<uchar4>::channel), + out_->createTexture<uchar4>(Channel::Colour), + temp_.getTexture<float>(Channel::Contribution), + stream_ + ); - //cudaSafeCall(cudaStreamSynchronize(stream_)); + _postprocessColours(*out_); - // Support rendering of a second channel without redoing all the work - switch(chan) { - case Channel::None : - case Channel::Left : - case Channel::Depth : break; - case Channel::ColourNormals : _renderNormals(out); break; - case Channel::Density : _renderDensity(out, t); break; - case Channel::Right : _renderRight(out, t); break; - default : _renderSecond(out, chan, t); - } + cudaSafeCall(cudaStreamSynchronize(stream_)); } -bool Triangular::render(ftl::rgbd::FrameSet &in, ftl::rgbd::Frame &out, Channel chan, const Eigen::Matrix4d &t) { +bool CUDARender::submit(ftl::rgbd::FrameSet *in, Channels<0> chans, const Eigen::Matrix4d &t) { if (scene_) { LOG(WARNING) << "Already rendering..."; return false; } - scene_ = ∈ + scene_ = in; if (scene_->frames.size() == 0) { scene_ = nullptr; return false; @@ -707,13 +719,18 @@ bool Triangular::render(ftl::rgbd::FrameSet &in, ftl::rgbd::Frame &out, Channel bool success = true; try { - _render(in, out, chan, t); - cudaSafeCall(cudaStreamSynchronize(stream_)); + _renderPass1(t); + //cudaSafeCall(cudaStreamSynchronize(stream_)); } catch (std::exception &e) { LOG(ERROR) << "Exception in render: " << e.what(); success = false; } + auto &s = sets_.emplace_back(); + s.fs = in; + s.channels = chans; + s.transform = t; + last_frame_ = scene_->timestamp; scene_ = nullptr; return success; diff --git a/components/renderers/cpp/src/reprojection.cu b/components/renderers/cpp/src/reprojection.cu index 2e342d1e2ceb903416fd7e22f668a0819127cd27..79b01ff534cf36d26c4d58c3e15d3b32fbd95020 100644 --- a/components/renderers/cpp/src/reprojection.cu +++ b/components/renderers/cpp/src/reprojection.cu @@ -286,6 +286,103 @@ template void ftl::cuda::reproject( const ftl::rgbd::Camera &camera, const float4x4 &poseInv, cudaStream_t stream); +//============================================================================== +// Without normals or depth +//============================================================================== + +/* + * Pass 2: Accumulate attribute contributions if the points pass a visibility test. + */ + template <typename A, typename B> +__global__ void reprojection_kernel( + TextureObject<A> in, // Attribute input + TextureObject<float> depth_in, // Virtual depth map + TextureObject<B> out, // Accumulated output + TextureObject<float> contrib, + SplatParams params, + Camera camera, float4x4 poseInv) { + + const int x = (blockIdx.x*blockDim.x + threadIdx.x); + const int y = blockIdx.y*blockDim.y + threadIdx.y; + + const float d = depth_in.tex2D((int)x, (int)y); + if (d < params.camera.minDepth || d > params.camera.maxDepth) return; + + //const float3 worldPos = params.m_viewMatrixInverse * params.camera.screenToCam(x, y, d); + //if (worldPos.x == MINF || (!(params.m_flags & ftl::render::kShowDisconMask) && worldPos.w < 0.0f)) return; + + const float3 camPos = poseInv * params.camera.screenToCam(x, y, d); + //if (camPos.z < camera.minDepth) return; + //if (camPos.z > camera.maxDepth) return; + const float2 screenPos = camera.camToScreen<float2>(camPos); + + // Not on screen so stop now... + if (screenPos.x >= in.width() || screenPos.y >= in.height()) return; + + const float d2 = camera.maxDepth; + + const auto input = in.tex2D(screenPos.x, screenPos.y); //generateInput(in.tex2D((int)screenPos.x, (int)screenPos.y), params, worldPos); + + float weight = ftl::cuda::weighting(fabs(camPos.z - d2), 0.02f); + const B weighted = make<B>(input) * weight; + + if (weight > 0.0f) { + accumulateOutput(out, contrib, make_uint2(x,y), weighted, weight); + //out(screenPos.x, screenPos.y) = input; + } +} + + +template <typename A, typename B> +void ftl::cuda::reproject( + TextureObject<A> &in, + TextureObject<float> &depth_in, // Virtual depth map + TextureObject<B> &out, // Accumulated output + TextureObject<float> &contrib, + const SplatParams ¶ms, + const Camera &camera, const float4x4 &poseInv, cudaStream_t stream) { + const dim3 gridSize((out.width() + T_PER_BLOCK - 1)/T_PER_BLOCK, (out.height() + T_PER_BLOCK - 1)/T_PER_BLOCK); + const dim3 blockSize(T_PER_BLOCK, T_PER_BLOCK); + + reprojection_kernel<<<gridSize, blockSize, 0, stream>>>( + in, + depth_in, + out, + contrib, + params, + camera, + poseInv + ); + cudaSafeCall( cudaGetLastError() ); +} + +template void ftl::cuda::reproject( + ftl::cuda::TextureObject<uchar4> &in, // Original colour image + ftl::cuda::TextureObject<float> &depth_in, // Virtual depth map + ftl::cuda::TextureObject<float4> &out, // Accumulated output + ftl::cuda::TextureObject<float> &contrib, + const ftl::render::SplatParams ¶ms, + const ftl::rgbd::Camera &camera, + const float4x4 &poseInv, cudaStream_t stream); + +template void ftl::cuda::reproject( + ftl::cuda::TextureObject<float> &in, // Original colour image + ftl::cuda::TextureObject<float> &depth_in, // Virtual depth map + ftl::cuda::TextureObject<float> &out, // Accumulated output + ftl::cuda::TextureObject<float> &contrib, + const ftl::render::SplatParams ¶ms, + const ftl::rgbd::Camera &camera, + const float4x4 &poseInv, cudaStream_t stream); + +template void ftl::cuda::reproject( + ftl::cuda::TextureObject<float4> &in, // Original colour image + ftl::cuda::TextureObject<float> &depth_in, // Virtual depth map + ftl::cuda::TextureObject<float4> &out, // Accumulated output + ftl::cuda::TextureObject<float> &contrib, + const ftl::render::SplatParams ¶ms, + const ftl::rgbd::Camera &camera, + const float4x4 &poseInv, cudaStream_t stream); + // ===== Equirectangular Reprojection ========================================== diff --git a/components/renderers/cpp/src/screen.cu b/components/renderers/cpp/src/screen.cu index c4991ee6e65dd6801acd847a67a4713be8edfd13..f12f255f0b9a3fbdd5f418864567f5688e489ba2 100644 --- a/components/renderers/cpp/src/screen.cu +++ b/components/renderers/cpp/src/screen.cu @@ -47,3 +47,42 @@ void ftl::cuda::screen_coord(TextureObject<float> &depth, TextureObject<float> & screen_coord_kernel<<<gridSize, blockSize, 0, stream>>>(depth, depth_out, screen_out, params.camera, pose, camera); cudaSafeCall( cudaGetLastError() ); } + + +// ==== Constant depth version ================================================= + +/* + * Convert source screen position to output screen coordinates. Assumes a + * constant depth of 1m instead of using a depth channel input. + */ + __global__ void screen_coord_kernel(TextureObject<float> depth_out, + TextureObject<short2> screen_out, Camera vcamera, float4x4 pose, Camera camera) { + const int x = blockIdx.x*blockDim.x + threadIdx.x; + const int y = blockIdx.y*blockDim.y + threadIdx.y; + + if (x >= 0 && y >= 0 && x < depth_out.width() && y < depth_out.height()) { + uint2 screenPos = make_uint2(30000,30000); + const float d = camera.maxDepth; + + // Find the virtual screen position of current point + const float3 camPos = pose * camera.screenToCam(x,y,d); + screenPos = vcamera.camToScreen<uint2>(camPos); + + if ( camPos.z < vcamera.minDepth || + camPos.z > vcamera.maxDepth || + screenPos.x >= vcamera.width || + screenPos.y >= vcamera.height) + screenPos = make_uint2(30000,30000); + + screen_out(x,y) = make_short2(screenPos.x, screenPos.y); + depth_out(x,y) = camPos.z; + } +} + +void ftl::cuda::screen_coord(TextureObject<float> &depth_out, TextureObject<short2> &screen_out, const SplatParams ¶ms, const float4x4 &pose, const Camera &camera, cudaStream_t stream) { + const dim3 gridSize((screen_out.width() + T_PER_BLOCK - 1)/T_PER_BLOCK, (screen_out.height() + T_PER_BLOCK - 1)/T_PER_BLOCK); + const dim3 blockSize(T_PER_BLOCK, T_PER_BLOCK); + + screen_coord_kernel<<<gridSize, blockSize, 0, stream>>>(depth_out, screen_out, params.camera, pose, camera); + cudaSafeCall( cudaGetLastError() ); +} diff --git a/components/renderers/cpp/src/splatter.cpp b/components/renderers/cpp/src/splatter.cpp deleted file mode 100644 index 731efec404dc24a972f290c61d8fc0c6d2ba34c7..0000000000000000000000000000000000000000 --- a/components/renderers/cpp/src/splatter.cpp +++ /dev/null @@ -1,498 +0,0 @@ -#include <ftl/render/splat_render.hpp> -#include <ftl/utility/matrix_conversion.hpp> -#include "splatter_cuda.hpp" -#include <ftl/cuda/points.hpp> -#include <ftl/cuda/normals.hpp> -#include <ftl/cuda/mask.hpp> - -#include <opencv2/core/cuda_stream_accessor.hpp> - -#include <string> - -using ftl::render::Splatter; -using ftl::codecs::Channel; -using ftl::codecs::Channels; -using ftl::rgbd::Format; -using cv::cuda::GpuMat; -using std::stoul; -using ftl::cuda::Mask; - -static Eigen::Affine3d create_rotation_matrix(float ax, float ay, float az) { - Eigen::Affine3d rx = - Eigen::Affine3d(Eigen::AngleAxisd(ax, Eigen::Vector3d(1, 0, 0))); - Eigen::Affine3d ry = - Eigen::Affine3d(Eigen::AngleAxisd(ay, Eigen::Vector3d(0, 1, 0))); - Eigen::Affine3d rz = - Eigen::Affine3d(Eigen::AngleAxisd(az, Eigen::Vector3d(0, 0, 1))); - return rz * rx * ry; -} - -/* - * Parse a CSS style colour string into a scalar. - */ -static cv::Scalar parseCVColour(const std::string &colour) { - std::string c = colour; - if (c[0] == '#') { - c.erase(0, 1); - unsigned long value = stoul(c.c_str(), nullptr, 16); - return cv::Scalar( - (value >> 0) & 0xff, - (value >> 8) & 0xff, - (value >> 16) & 0xff, - (value >> 24) & 0xff - ); - } - - return cv::Scalar(0,0,0,0); -} - -/* - * Parse a CSS style colour string into a scalar. - */ -static uchar4 parseCUDAColour(const std::string &colour) { - std::string c = colour; - if (c[0] == '#') { - c.erase(0, 1); - unsigned long value = stoul(c.c_str(), nullptr, 16); - return make_uchar4( - (value >> 0) & 0xff, - (value >> 8) & 0xff, - (value >> 16) & 0xff, - (value >> 24) & 0xff - ); - } - - return make_uchar4(0,0,0,0); -} - -Splatter::Splatter(nlohmann::json &config, ftl::rgbd::FrameSet *fs) : ftl::render::Renderer(config), scene_(fs) { - if (config["clipping"].is_object()) { - auto &c = config["clipping"]; - float rx = c.value("pitch", 0.0f); - float ry = c.value("yaw", 0.0f); - float rz = c.value("roll", 0.0f); - float x = c.value("x", 0.0f); - float y = c.value("y", 0.0f); - float z = c.value("z", 0.0f); - float width = c.value("width", 1.0f); - float height = c.value("height", 1.0f); - float depth = c.value("depth", 1.0f); - - Eigen::Affine3f r = create_rotation_matrix(rx, ry, rz).cast<float>(); - Eigen::Translation3f trans(Eigen::Vector3f(x,y,z)); - Eigen::Affine3f t(trans); - - clip_.origin = MatrixConversion::toCUDA(r.matrix() * t.matrix()); - clip_.size = make_float3(width, height, depth); - clipping_ = value("clipping_enabled", true); - } else { - clipping_ = false; - } - - on("clipping_enabled", [this](const ftl::config::Event &e) { - clipping_ = value("clipping_enabled", true); - }); - - norm_filter_ = value("normal_filter", -1.0f); - on("normal_filter", [this](const ftl::config::Event &e) { - norm_filter_ = value("normal_filter", -1.0f); - }); - - backcull_ = value("back_cull", true); - on("back_cull", [this](const ftl::config::Event &e) { - backcull_ = value("back_cull", true); - }); - - splat_ = value("splatting", true); - on("splatting", [this](const ftl::config::Event &e) { - splat_ = value("splatting", true); - }); - - background_ = parseCVColour(value("background", std::string("#4c4c4c"))); - on("background", [this](const ftl::config::Event &e) { - background_ = parseCVColour(value("background", std::string("#4c4c4c"))); - }); - - light_diffuse_ = parseCUDAColour(value("diffuse", std::string("#e0e0e0"))); - on("diffuse", [this](const ftl::config::Event &e) { - light_diffuse_ = parseCUDAColour(value("diffuse", std::string("#e0e0e0"))); - }); - - light_ambient_ = parseCUDAColour(value("ambient", std::string("#0e0e0e"))); - on("ambient", [this](const ftl::config::Event &e) { - light_ambient_ = parseCUDAColour(value("ambient", std::string("#0e0e0e"))); - }); - - light_pos_ = make_float3(value("light_x", 0.3f), value("light_y", 0.2f), value("light_z", 1.0f)); - on("light_x", [this](const ftl::config::Event &e) { light_pos_.x = value("light_x", 0.3f); }); - on("light_y", [this](const ftl::config::Event &e) { light_pos_.y = value("light_y", 0.3f); }); - on("light_z", [this](const ftl::config::Event &e) { light_pos_.z = value("light_z", 0.3f); }); - - cudaSafeCall(cudaStreamCreate(&stream_)); -} - -Splatter::~Splatter() { - -} - -template <typename T> -struct AccumSelector { - typedef float4 type; - static constexpr Channel channel = Channel::Colour; - //static constexpr cv::Scalar value = cv::Scalar(0.0f,0.0f,0.0f,0.0f); -}; - -template <> -struct AccumSelector<float> { - typedef float type; - static constexpr Channel channel = Channel::Colour2; - //static constexpr cv::Scalar value = cv::Scalar(0.0f); -}; - -template <typename T> -void Splatter::__blendChannel(ftl::rgbd::Frame &output, ftl::codecs::Channel in, ftl::codecs::Channel out, cudaStream_t stream) { - cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream); - temp_.create<GpuMat>( - AccumSelector<T>::channel, - Format<typename AccumSelector<T>::type>(params_.camera.width, params_.camera.height) - ).setTo(cv::Scalar(0.0f), cvstream); - temp_.get<GpuMat>(Channel::Contribution).setTo(cv::Scalar(0.0f), cvstream); - - temp_.createTexture<float>(Channel::Contribution); - - for (auto &f : scene_->frames) { - if (f.get<GpuMat>(in).type() == CV_8UC3) { - // Convert to 4 channel colour - auto &col = f.get<GpuMat>(in); - GpuMat tmp(col.size(), CV_8UC4); - cv::cuda::swap(col, tmp); - cv::cuda::cvtColor(tmp,col, cv::COLOR_BGR2BGRA); - } - - ftl::cuda::dibr_attribute( - f.createTexture<T>(in), - f.createTexture<float4>(Channel::Points), - temp_.getTexture<int>(Channel::Depth2), - temp_.createTexture<typename AccumSelector<T>::type>(AccumSelector<T>::channel), - temp_.getTexture<float>(Channel::Contribution), - params_, stream - ); - } - - ftl::cuda::dibr_normalise( - temp_.getTexture<typename AccumSelector<T>::type>(AccumSelector<T>::channel), - output.createTexture<T>(out), - temp_.getTexture<float>(Channel::Contribution), - stream - ); -} - -void Splatter::_blendChannel(ftl::rgbd::Frame &output, ftl::codecs::Channel in, ftl::codecs::Channel out, cudaStream_t stream) { - int type = output.get<GpuMat>(out).type(); // == CV_32F; //ftl::rgbd::isFloatChannel(channel); - - switch (type) { - case CV_32F : __blendChannel<float>(output, in, out, stream); break; - case CV_32FC4 : __blendChannel<float4>(output, in, out, stream); break; - case CV_8UC4 : __blendChannel<uchar4>(output, in, out, stream); break; - default : LOG(ERROR) << "Invalid output channel format"; - } -} - -void Splatter::_dibr(cudaStream_t stream) { - cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream); - temp_.get<GpuMat>(Channel::Depth2).setTo(cv::Scalar(0x7FFFFFFF), cvstream); - - for (size_t i=0; i < scene_->frames.size(); ++i) { - auto &f = scene_->frames[i]; - //auto *s = scene_->sources[i]; - - if (f.empty(Channel::Depth + Channel::Colour)) { - LOG(ERROR) << "Missing required channel"; - continue; - } - - ftl::cuda::dibr_merge( - f.createTexture<float4>(Channel::Points), - f.createTexture<float4>(Channel::Normals), - temp_.createTexture<int>(Channel::Depth2), - params_, backcull_, stream - ); - - //LOG(INFO) << "DIBR DONE"; - } -} - -void Splatter::_renderChannel( - ftl::rgbd::Frame &out, - Channel channel_in, Channel channel_out, cudaStream_t stream) -{ - if (channel_out == Channel::None || channel_in == Channel::None) return; - cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream); - - if (scene_->frames.size() < 1) return; - bool is_float = out.get<GpuMat>(channel_out).type() == CV_32F; //ftl::rgbd::isFloatChannel(channel); - bool is_4chan = out.get<GpuMat>(channel_out).type() == CV_32FC4; - - - temp_.createTexture<float4>(Channel::Colour); - temp_.createTexture<float>(Channel::Contribution); - - // Generate initial normals for the splats - accum_.create<GpuMat>(Channel::Normals, Format<float4>(params_.camera.width, params_.camera.height)); - _blendChannel(accum_, Channel::Normals, Channel::Normals, stream); - // Put normals in camera space here... - ftl::cuda::transform_normals(accum_.getTexture<float4>(Channel::Normals), params_.m_viewMatrix.getFloat3x3(), stream); - - // Estimate point density - accum_.create<GpuMat>(Channel::Density, Format<float>(params_.camera.width, params_.camera.height)); - _blendChannel(accum_, Channel::Depth, Channel::Density, stream); - - // FIXME: Using colour 2 in this way seems broken since it is already used - if (is_4chan) { - accum_.create<GpuMat>(channel_out, Format<float4>(params_.camera.width, params_.camera.height)); - accum_.get<GpuMat>(channel_out).setTo(cv::Scalar(0.0f,0.0f,0.0f,0.0f), cvstream); - } else if (is_float) { - accum_.create<GpuMat>(channel_out, Format<float>(params_.camera.width, params_.camera.height)); - accum_.get<GpuMat>(channel_out).setTo(cv::Scalar(0.0f), cvstream); - } else { - accum_.create<GpuMat>(channel_out, Format<uchar4>(params_.camera.width, params_.camera.height)); - accum_.get<GpuMat>(channel_out).setTo(cv::Scalar(0,0,0,0), cvstream); - } - - //if (splat_) { - _blendChannel(accum_, channel_in, channel_out, stream); - //} else { - // _blendChannel(out, channel, channel, stream); - //} - - // Now splat the points - if (splat_) { - if (is_4chan) { - ftl::cuda::splat( - accum_.getTexture<float4>(Channel::Normals), - accum_.getTexture<float>(Channel::Density), - accum_.getTexture<float4>(channel_out), - temp_.getTexture<int>(Channel::Depth2), - out.createTexture<float>(Channel::Depth), - out.createTexture<float4>(channel_out), - params_, stream - ); - } else if (is_float) { - ftl::cuda::splat( - accum_.getTexture<float4>(Channel::Normals), - accum_.getTexture<float>(Channel::Density), - accum_.getTexture<float>(channel_out), - temp_.getTexture<int>(Channel::Depth2), - out.createTexture<float>(Channel::Depth), - out.createTexture<float>(channel_out), - params_, stream - ); - } else { - ftl::cuda::splat( - accum_.getTexture<float4>(Channel::Normals), - accum_.getTexture<float>(Channel::Density), - accum_.getTexture<uchar4>(channel_out), - temp_.getTexture<int>(Channel::Depth2), - out.createTexture<float>(Channel::Depth), - out.createTexture<uchar4>(channel_out), - params_, stream - ); - } - } else { - // Swap accum frames directly to output. - accum_.swapTo(Channels(channel_out), out); - } -} - -bool Splatter::render(ftl::rgbd::VirtualSource *src, ftl::rgbd::Frame &out, const Eigen::Matrix4d &t) { - SHARED_LOCK(scene_->mtx, lk); - if (!src->isReady()) return false; - - scene_->upload(Channel::Colour + Channel::Depth, stream_); - - const auto &camera = src->parameters(); - //cudaSafeCall(cudaSetDevice(scene_->getCUDADevice())); - - // Create all the required channels - - out.create<GpuMat>(Channel::Depth, Format<float>(camera.width, camera.height)); - out.create<GpuMat>(Channel::Colour, Format<uchar4>(camera.width, camera.height)); - - - if (scene_->frames.size() == 0) return false; - auto &g = scene_->frames[0].get<GpuMat>(Channel::Colour); - - temp_.create<GpuMat>(Channel::Colour, Format<float4>(camera.width, camera.height)); - temp_.create<GpuMat>(Channel::Contribution, Format<float>(camera.width, camera.height)); - temp_.create<GpuMat>(Channel::Depth, Format<int>(camera.width, camera.height)); - temp_.create<GpuMat>(Channel::Depth2, Format<int>(camera.width, camera.height)); - temp_.create<GpuMat>(Channel::Normals, Format<float4>(g.cols, g.rows)); - - cv::cuda::Stream cvstream = cv::cuda::StreamAccessor::wrapStream(stream_); - - // Parameters object to pass to CUDA describing the camera - SplatParams ¶ms = params_; - params.m_flags = 0; - //if () params.m_flags |= ftl::render::kShowDisconMask; - if (value("normal_weight_colours", true)) params.m_flags |= ftl::render::kNormalWeightColours; - params.m_viewMatrix = MatrixConversion::toCUDA(src->getPose().cast<float>().inverse()); - params.m_viewMatrixInverse = MatrixConversion::toCUDA(src->getPose().cast<float>()); - params.camera = camera; - // Clear all channels to 0 or max depth - - out.get<GpuMat>(Channel::Depth).setTo(cv::Scalar(1000.0f), cvstream); - out.get<GpuMat>(Channel::Colour).setTo(background_, cvstream); - - //LOG(INFO) << "Render ready: " << camera.width << "," << camera.height; - - bool show_discon = value("show_discontinuity_mask", false); - bool show_fill = value("show_filled", false); - - temp_.createTexture<int>(Channel::Depth); - //temp_.get<GpuMat>(Channel::Normals).setTo(cv::Scalar(0.0f,0.0f,0.0f,0.0f), cvstream); - - // First make sure each input has normals - temp_.createTexture<float4>(Channel::Normals); - for (int i=0; i<scene_->frames.size(); ++i) { - auto &f = scene_->frames[i]; - //auto s = scene_->sources[i]; - - if (f.hasChannel(Channel::Mask)) { - if (show_discon) { - ftl::cuda::show_mask(f.getTexture<uchar4>(Channel::Colour), f.getTexture<int>(Channel::Mask), Mask::kMask_Discontinuity, make_uchar4(0,0,255,255), stream_); - } - if (show_fill) { - ftl::cuda::show_mask(f.getTexture<uchar4>(Channel::Colour), f.getTexture<int>(Channel::Mask), Mask::kMask_Filled, make_uchar4(0,255,0,255), stream_); - } - } - - // Needs to create points channel first? - if (!f.hasChannel(Channel::Points)) { - //LOG(INFO) << "Creating points... " << s->parameters().width; - - auto &t = f.createTexture<float4>(Channel::Points, Format<float4>(f.get<GpuMat>(Channel::Colour).size())); - auto pose = MatrixConversion::toCUDA(f.getPose().cast<float>()); //.inverse()); - ftl::cuda::point_cloud(t, f.createTexture<float>(Channel::Depth), f.getLeftCamera(), pose, 0, stream_); - - //LOG(INFO) << "POINTS Added"; - } - - // Clip first? - if (clipping_) { - ftl::cuda::clipping(f.createTexture<float4>(Channel::Points), clip_, stream_); - } - - if (!f.hasChannel(Channel::Normals)) { - Eigen::Matrix4f matrix = f.getPose().cast<float>().transpose(); - auto pose = MatrixConversion::toCUDA(matrix); - - auto &g = f.get<GpuMat>(Channel::Colour); - ftl::cuda::normals(f.createTexture<float4>(Channel::Normals, Format<float4>(g.cols, g.rows)), - temp_.getTexture<float4>(Channel::Normals), - f.getTexture<float4>(Channel::Points), - 1, 0.02f, - f.getLeftCamera(), pose.getFloat3x3(), stream_); - - if (norm_filter_ > -0.1f) { - ftl::cuda::normal_filter(f.getTexture<float4>(Channel::Normals), f.getTexture<float4>(Channel::Points), f.getLeftCamera(), pose, norm_filter_, stream_); - } - } - } - - Channel chan = src->getChannel(); - - int aligned_source = value("aligned_source",-1); - if (aligned_source >= 0 && aligned_source < scene_->frames.size()) { - // FIXME: Output may not be same resolution as source! - cudaSafeCall(cudaStreamSynchronize(stream_)); - scene_->frames[aligned_source].copyTo(Channel::Depth + Channel::Colour, out); - - if (chan == Channel::Normals) { - // Convert normal to single float value - temp_.create<GpuMat>(Channel::Colour, Format<uchar4>(camera.width, camera.height)).setTo(cv::Scalar(0,0,0,0), cvstream); - ftl::cuda::normal_visualise(scene_->frames[aligned_source].getTexture<float4>(Channel::Normals), temp_.createTexture<uchar4>(Channel::Colour), - light_pos_, - light_diffuse_, - light_ambient_, stream_); - - // Put in output as single float - cv::cuda::swap(temp_.get<GpuMat>(Channel::Colour), out.create<GpuMat>(Channel::Normals)); - out.resetTexture(Channel::Normals); - } - - return true; - } - - _dibr(stream_); - _renderChannel(out, Channel::Colour, Channel::Colour, stream_); - - if (chan == Channel::Depth) - { - //temp_.get<GpuMat>(Channel::Depth).convertTo(out.get<GpuMat>(Channel::Depth), CV_32F, 1.0f / 1000.0f, cvstream); - } else if (chan == Channel::Normals) { - out.create<GpuMat>(Channel::Normals, Format<float4>(camera.width, camera.height)); - - // Render normal attribute - _renderChannel(out, Channel::Normals, Channel::Normals, stream_); - - // Convert normal to single float value - temp_.create<GpuMat>(Channel::Colour, Format<uchar4>(camera.width, camera.height)).setTo(cv::Scalar(0,0,0,0), cvstream); - ftl::cuda::normal_visualise(out.getTexture<float4>(Channel::Normals), temp_.createTexture<uchar4>(Channel::Colour), - light_pos_, - light_diffuse_, - light_ambient_, stream_); - - // Put in output as single float - cv::cuda::swap(temp_.get<GpuMat>(Channel::Colour), out.create<GpuMat>(Channel::Normals)); - out.resetTexture(Channel::Normals); - } - //else if (chan == Channel::Contribution) - //{ - // cv::cuda::swap(temp_.get<GpuMat>(Channel::Contribution), out.create<GpuMat>(Channel::Contribution)); - //} - else if (chan == Channel::Density) { - out.create<GpuMat>(chan, Format<float>(camera.width, camera.height)); - out.get<GpuMat>(chan).setTo(cv::Scalar(0.0f), cvstream); - _renderChannel(out, Channel::Depth, Channel::Density, stream_); - } - else if (chan == Channel::Right) - { - float baseline = camera.baseline; - - //Eigen::Translation3f translation(baseline, 0.0f, 0.0f); - //Eigen::Affine3f transform(translation); - //Eigen::Matrix4f matrix = transform.matrix() * src->getPose().cast<float>(); - - Eigen::Matrix4f transform = Eigen::Matrix4f::Identity(); - transform(0, 3) = baseline; - Eigen::Matrix4f matrix = transform.inverse() * src->getPose().cast<float>(); - - params.m_viewMatrix = MatrixConversion::toCUDA(matrix.inverse()); - params.m_viewMatrixInverse = MatrixConversion::toCUDA(matrix); - - params.camera = src->parameters(Channel::Right); - - out.create<GpuMat>(Channel::Right, Format<uchar4>(camera.width, camera.height)); - out.get<GpuMat>(Channel::Right).setTo(background_, cvstream); - - _dibr(stream_); // Need to re-dibr due to pose change - _renderChannel(out, Channel::Left, Channel::Right, stream_); - - } else if (chan != Channel::None) { - if (ftl::codecs::isFloatChannel(chan)) { - out.create<GpuMat>(chan, Format<float>(camera.width, camera.height)); - out.get<GpuMat>(chan).setTo(cv::Scalar(0.0f), cvstream); - } else { - out.create<GpuMat>(chan, Format<uchar4>(camera.width, camera.height)); - out.get<GpuMat>(chan).setTo(background_, cvstream); - } - _renderChannel(out, chan, chan, stream_); - } - - cudaSafeCall(cudaStreamSynchronize(stream_)); - return true; -} - -//void Splatter::setOutputDevice(int device) { -// device_ = device; -//} diff --git a/components/renderers/cpp/src/splatter.cu b/components/renderers/cpp/src/splatter.cu index 55706b0856750738134a3417dfdb017205ab2bdf..7696433bd78f6187132a0bf2547cc653cc5c9b2e 100644 --- a/components/renderers/cpp/src/splatter.cu +++ b/components/renderers/cpp/src/splatter.cu @@ -137,6 +137,39 @@ using ftl::cuda::warpSum; } } +/* + * Pass 1: Directly render each camera into virtual view but with no upsampling + * for sparse points. + */ + __global__ void dibr_merge_kernel( + TextureObject<int> depth_out, + float4x4 transform, + ftl::rgbd::Camera cam, + SplatParams params) { + const int x = blockIdx.x*blockDim.x + threadIdx.x; + const int y = blockIdx.y*blockDim.y + threadIdx.y; + + const float d0 = 1.0f; + + const float3 camPos = transform * cam.screenToCam(x,y,d0); + //if (worldPos.x == MINF || (!(params.m_flags & ftl::render::kShowDisconMask) && worldPos.w < 0.0f)) return; + + // Find the virtual screen position of current point + //const float3 camPos = params.m_viewMatrix * make_float3(worldPos); + //if (camPos.z < params.camera.minDepth) return; + //if (camPos.z > params.camera.maxDepth) return; + + const float d = camPos.z; + + const uint2 screenPos = params.camera.camToScreen<uint2>(camPos); + const unsigned int cx = screenPos.x; + const unsigned int cy = screenPos.y; + if (d > params.camera.minDepth && d < params.camera.maxDepth && cx < depth_out.width() && cy < depth_out.height()) { + // Transform estimated point to virtual cam space and output z + atomicMin(&depth_out(cx,cy), d * 100000.0f); + } +} + void ftl::cuda::dibr_merge(TextureObject<float4> &points, TextureObject<float4> &normals, TextureObject<int> &depth, SplatParams params, bool culling, cudaStream_t stream) { const dim3 gridSize((depth.width() + T_PER_BLOCK - 1)/T_PER_BLOCK, (depth.height() + T_PER_BLOCK - 1)/T_PER_BLOCK); const dim3 blockSize(T_PER_BLOCK, T_PER_BLOCK); @@ -155,13 +188,21 @@ void ftl::cuda::dibr_merge(TextureObject<float4> &points, TextureObject<int> &de } void ftl::cuda::dibr_merge(TextureObject<float> &depth, TextureObject<int> &depth_out, const float4x4 &transform, const ftl::rgbd::Camera &cam, SplatParams params, cudaStream_t stream) { - const dim3 gridSize((depth_out.width() + T_PER_BLOCK - 1)/T_PER_BLOCK, (depth_out.height() + T_PER_BLOCK - 1)/T_PER_BLOCK); + const dim3 gridSize((depth.width() + T_PER_BLOCK - 1)/T_PER_BLOCK, (depth.height() + T_PER_BLOCK - 1)/T_PER_BLOCK); const dim3 blockSize(T_PER_BLOCK, T_PER_BLOCK); dibr_merge_kernel<<<gridSize, blockSize, 0, stream>>>(depth, depth_out, transform, cam, params); cudaSafeCall( cudaGetLastError() ); } +void ftl::cuda::dibr_merge(TextureObject<int> &depth_out, const float4x4 &transform, const ftl::rgbd::Camera &cam, SplatParams params, cudaStream_t stream) { + const dim3 gridSize((cam.width + T_PER_BLOCK - 1)/T_PER_BLOCK, (cam.height + T_PER_BLOCK - 1)/T_PER_BLOCK); + const dim3 blockSize(T_PER_BLOCK, T_PER_BLOCK); + + dibr_merge_kernel<<<gridSize, blockSize, 0, stream>>>(depth_out, transform, cam, params); + cudaSafeCall( cudaGetLastError() ); +} + //============================================================================== diff --git a/components/renderers/cpp/src/splatter_cuda.hpp b/components/renderers/cpp/src/splatter_cuda.hpp index 5d027b2c6ff0c12efa28ca277d0404c11c5eb49c..33f0340f2a94007a87981dbf400e953869624392 100644 --- a/components/renderers/cpp/src/splatter_cuda.hpp +++ b/components/renderers/cpp/src/splatter_cuda.hpp @@ -15,6 +15,14 @@ namespace cuda { const ftl::rgbd::Camera &camera, cudaStream_t stream); + void screen_coord( + ftl::cuda::TextureObject<float> &depth_out, + ftl::cuda::TextureObject<short2> &screen_out, + const ftl::render::SplatParams ¶ms, + const float4x4 &pose, + const ftl::rgbd::Camera &camera, + cudaStream_t stream); + void triangle_render1( ftl::cuda::TextureObject<float> &depth_in, ftl::cuda::TextureObject<int> &depth_out, @@ -51,6 +59,13 @@ namespace cuda { ftl::render::SplatParams params, cudaStream_t stream); + void dibr_merge( + ftl::cuda::TextureObject<int> &depth_out, + const float4x4 &transform, + const ftl::rgbd::Camera &cam, + ftl::render::SplatParams params, + cudaStream_t stream); + template <typename T> void splat( ftl::cuda::TextureObject<float4> &normals, @@ -93,6 +108,16 @@ namespace cuda { const ftl::rgbd::Camera &camera, const float4x4 &poseInv, cudaStream_t stream); + template <typename A, typename B> + void reproject( + ftl::cuda::TextureObject<A> &in, // Original colour image + ftl::cuda::TextureObject<float> &depth_in, // Virtual depth map + ftl::cuda::TextureObject<B> &out, // Accumulated output + ftl::cuda::TextureObject<float> &contrib, + const ftl::render::SplatParams ¶ms, + const ftl::rgbd::Camera &camera, + const float4x4 &poseInv, cudaStream_t stream); + void equirectangular_reproject( ftl::cuda::TextureObject<uchar4> &image_in, ftl::cuda::TextureObject<uchar4> &image_out, diff --git a/components/renderers/cpp/src/triangle_render.cu b/components/renderers/cpp/src/triangle_render.cu index 61f44f320e0b889649d1f82c5f2c090d326e1221..fbbeee9fe3636aaa801366287f4f0f6361f9b5b8 100644 --- a/components/renderers/cpp/src/triangle_render.cu +++ b/components/renderers/cpp/src/triangle_render.cu @@ -145,8 +145,9 @@ float getZAtCoordinate(const float3 &barycentricCoord, const float (&tri)[3]) { // Remove really large triangles if ((maxX - minX) * (maxY - minY) > params.triangle_limit) return; - for (int sy=minY; sy <= maxY; ++sy) { - for (int sx=minX; sx <= maxX; ++sx) { + // TODO: Verify that < is correct, was <= before but < is faster. + for (int sy=minY; sy < maxY; ++sy) { + for (int sx=minX; sx < maxX; ++sx) { if (sx >= params.camera.width || sx < 0 || sy >= params.camera.height || sy < 0) continue; float3 baryCentricCoordinate = calculateBarycentricCoordinate(v, make_short2(sx, sy)); @@ -154,6 +155,7 @@ float getZAtCoordinate(const float3 &barycentricCoord, const float (&tri)[3]) { if (isBarycentricCoordInBounds(baryCentricCoordinate)) { float new_depth = getZAtCoordinate(baryCentricCoordinate, d); atomicMin(&depth_out(sx,sy), int(new_depth*100000.0f)); + //depth_out(sx,sy) = int(new_depth*100000.0f); } } } diff --git a/components/rgbd-sources/CMakeLists.txt b/components/rgbd-sources/CMakeLists.txt index e611e97d55a89fef5a83f0bd1d5520eee5b62ef3..c45597f8b6777c972b8754fc5207daef0018d0eb 100644 --- a/components/rgbd-sources/CMakeLists.txt +++ b/components/rgbd-sources/CMakeLists.txt @@ -14,6 +14,8 @@ set(RGBDSRC #src/sources/virtual/virtual.cpp #src/sources/ftlfile/file_source.cpp #src/sources/ftlfile/player.cpp + src/sources/screencapture/screencapture.cpp + src/camera.cpp ) if (HAVE_REALSENSE) @@ -41,7 +43,7 @@ if (CUDA_FOUND) set_property(TARGET ftlrgbd PROPERTY CUDA_SEPARABLE_COMPILATION OFF) endif() -target_link_libraries(ftlrgbd ftlcommon ${OpenCV_LIBS} ${LIBSGM_LIBRARIES} ${CUDA_LIBRARIES} Eigen3::Eigen realsense ftlnet ${LibArchive_LIBRARIES} ftlcodecs ftloperators ftldata) +target_link_libraries(ftlrgbd ftlcommon ${OpenCV_LIBS} ${LIBSGM_LIBRARIES} ${CUDA_LIBRARIES} Eigen3::Eigen realsense ftlnet ${LibArchive_LIBRARIES} ftlcodecs ftloperators ftldata ${X11_X11_LIB} ${X11_Xext_LIB}) if (BUILD_TESTS) add_subdirectory(test) diff --git a/components/rgbd-sources/include/ftl/rgbd/camera.hpp b/components/rgbd-sources/include/ftl/rgbd/camera.hpp index 82a981d736e97ed42f403e62ef67f2f3a1dd2909..772a884b0b47b963d3ba8db0dcc8a6532cd83412 100644 --- a/components/rgbd-sources/include/ftl/rgbd/camera.hpp +++ b/components/rgbd-sources/include/ftl/rgbd/camera.hpp @@ -8,6 +8,7 @@ #ifndef __CUDACC__ #include <ftl/utility/msgpack.hpp> +#include <ftl/configurable.hpp> #endif namespace ftl{ @@ -18,16 +19,16 @@ namespace rgbd { * operate on CPU and GPU. */ struct __align__(16) Camera { - double fx; // Focal length X - double fy; // Focal length Y (usually same as fx) - double cx; // Principle point Y - double cy; // Principle point Y + float fx; // Focal length X + float fy; // Focal length Y (usually same as fx) + float cx; // Principle point Y + float cy; // Principle point Y unsigned int width; // Pixel width unsigned int height; // Pixel height - double minDepth; // Near clip in meters - double maxDepth; // Far clip in meters - double baseline; // For stereo pair - double doffs; // Disparity offset + float minDepth; // Near clip in meters + float maxDepth; // Far clip in meters + float baseline; // For stereo pair + float doffs; // Disparity offset Camera scaled(int width, int height) const; @@ -43,6 +44,11 @@ struct __align__(16) Camera { #ifndef __CUDACC__ MSGPACK_DEFINE(fx,fy,cx,cy,width,height,minDepth,maxDepth,baseline,doffs); + + /** + * Make a camera struct from a configurable. + */ + static Camera from(ftl::Configurable*); #endif }; diff --git a/components/rgbd-sources/src/camera.cpp b/components/rgbd-sources/src/camera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..90d77f34ba1226405e5cb1c0a5b98459033294d6 --- /dev/null +++ b/components/rgbd-sources/src/camera.cpp @@ -0,0 +1,18 @@ +#include <ftl/rgbd/camera.hpp> + +using ftl::rgbd::Camera; + +Camera Camera::from(ftl::Configurable *cfg) { + Camera r; + r.width = cfg->value("width", 1280); + r.height = cfg->value("height", 720); + r.fx = cfg->value("focal", 700.0f); + r.fy = r.fx; + r.cx = -(float)r.width / 2.0f; + r.cy = -(float)r.height / 2.0f; + r.minDepth = cfg->value("minDepth", 0.1f); + r.maxDepth = cfg->value("maxDepth", 15.0f); + r.doffs = 0; + r.baseline = cfg->value("baseline", 0.05f); + return r; +} diff --git a/components/rgbd-sources/src/source.cpp b/components/rgbd-sources/src/source.cpp index a71ea24e9ed6106425bf88f3726f226416a39e76..84a20c710b61d2282b658ea341005c789e0910a6 100644 --- a/components/rgbd-sources/src/source.cpp +++ b/components/rgbd-sources/src/source.cpp @@ -6,6 +6,7 @@ #include "sources/stereovideo/stereovideo.hpp" #include "sources/image/image.hpp" #include "sources/middlebury/middlebury_source.hpp" +#include "sources/screencapture/screencapture.hpp" #ifdef HAVE_LIBARCHIVE #include <ftl/rgbd/snapshot.hpp> @@ -28,6 +29,7 @@ using ftl::rgbd::detail::StereoVideoSource; //using ftl::rgbd::detail::NetSource; using ftl::rgbd::detail::ImageSource; using ftl::rgbd::detail::MiddleburySource; +using ftl::rgbd::detail::ScreenCapture; using ftl::rgbd::capability_t; using ftl::codecs::Channel; //using ftl::rgbd::detail::FileSource; @@ -177,6 +179,8 @@ ftl::rgbd::detail::Source *Source::_createDeviceImpl(const ftl::URI &uri) { #else LOG(ERROR) << "You do not have 'librealsense2' installed"; #endif + } else if (uri.getPathSegment(0) == "screen") { + return new ScreenCapture(this); } else { /*params_.width = value("width", 1280); params_.height = value("height", 720); diff --git a/components/rgbd-sources/src/sources/screencapture/screencapture.cpp b/components/rgbd-sources/src/sources/screencapture/screencapture.cpp new file mode 100644 index 0000000000000000000000000000000000000000..baf7091bbe1c04be7b4328d91b9d902ff58a646e --- /dev/null +++ b/components/rgbd-sources/src/sources/screencapture/screencapture.cpp @@ -0,0 +1,140 @@ +#include "screencapture.hpp" + +#define LOGURU_REPLACE_GLOG 1 +#include <loguru.hpp> +#include <ftl/threads.hpp> +#include <ftl/rgbd/source.hpp> + +using ftl::rgbd::detail::ScreenCapture; +using ftl::codecs::Channel; +using cv::cuda::GpuMat; + +#ifdef HAVE_X11 +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#include <X11/extensions/XShm.h> +#include <sys/ipc.h> +#include <sys/shm.h> + +namespace ftl { +namespace rgbd { +namespace detail { +struct X11State { + Display* display; + Window root; + XWindowAttributes window_attributes; + Screen* screen = window_attributes.screen; + XShmSegmentInfo shminfo; + XImage* ximg; +}; +} +} +} +#endif + +ScreenCapture::ScreenCapture(ftl::rgbd::Source *host) + : ftl::rgbd::detail::Source(host) { + capabilities_ = kCapVideo; + + const uint WIDTH = 1280; + const uint HEIGHT = 720; + + ready_ = false; + + #ifdef HAVE_X11 + + impl_state_ = new X11State; + auto &s = *impl_state_; + + s.display = XOpenDisplay(NULL); + if (!s.display) { + LOG(ERROR) << "Could not open X11 display"; + return; + } + + s.root = DefaultRootWindow(s.display); // TODO: Could choose windows? + + if (!XGetWindowAttributes(s.display, s.root, &s.window_attributes)) { + LOG(ERROR) << "Could not get X11 window attributes"; + return; + } + + s.screen = s.window_attributes.screen; + params_.width = s.window_attributes.width; + params_.height = s.window_attributes.height; + + s.ximg = XShmCreateImage(s.display, DefaultVisualOfScreen(s.screen), + DefaultDepthOfScreen(s.screen), ZPixmap, NULL, &s.shminfo, + params_.width, params_.height); + + // TODO: Can this happen? + if (!s.ximg) { + LOG(ERROR) << "Didn't get shared memory image from X11 screen"; + return; + } + + s.shminfo.shmid = shmget(IPC_PRIVATE, s.ximg->bytes_per_line * s.ximg->height, IPC_CREAT|0777); + s.shminfo.shmaddr = s.ximg->data = (char*)shmat(s.shminfo.shmid, 0, 0); + s.shminfo.readOnly = False; + if(s.shminfo.shmid < 0) { + LOG(ERROR) << "Fatal shminfo error!"; + return; + } + + if (!XShmAttach(impl_state_->display, &impl_state_->shminfo)) { + LOG(ERROR) << "X11 Shared Memory attach failure"; + return; + } + + ready_ = true; + + #endif + + params_.cx = -(params_.width / 2.0); + params_.cy = -(params_.height / 2.0); + params_.fx = 700.0; + params_.fy = 700.0; + params_.maxDepth = host_->value("depth", 1.0f); + params_.minDepth = 0.0f; + params_.doffs = 0.0; + + state_.getLeft() = params_; + +} + +ScreenCapture::~ScreenCapture() { + #ifdef HAVE_X11 + delete impl_state_; + #endif +} + +bool ScreenCapture::retrieve() { + if (!ready_) return false; + cv::Mat img; + + #ifdef HAVE_X11 + XShmGetImage(impl_state_->display, impl_state_->root, impl_state_->ximg, 0, 0, 0x00ffffff); + img = cv::Mat(params_.height, params_.width, CV_8UC4, impl_state_->ximg->data); + #endif + + frame_.reset(); + frame_.setOrigin(&state_); + + if (!img.empty()) { + frame_.create<cv::cuda::GpuMat>(Channel::Colour).upload(img); + } + + return true; +} + +bool ScreenCapture::compute(int n, int b) { + if (!ready_) return false; + host_->notify(timestamp_, frame_); + return true; +} + +bool ScreenCapture::isReady() { + return ready_; +} + diff --git a/components/rgbd-sources/src/sources/screencapture/screencapture.hpp b/components/rgbd-sources/src/sources/screencapture/screencapture.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e1511cb9abf39b47fe14d84a55697e0199761ab8 --- /dev/null +++ b/components/rgbd-sources/src/sources/screencapture/screencapture.hpp @@ -0,0 +1,40 @@ +#ifndef _FTL_RGBD_SCREENCAPTURE_HPP_ +#define _FTL_RGBD_SCREENCAPTURE_HPP_ + +#include <ftl/rgbd/detail/source.hpp> +#include <ftl/config.h> + +namespace ftl { + +namespace rgbd { + +namespace detail { + +#ifdef HAVE_X11 +struct X11State; +typedef X11State ImplState; +#else +typedef int ImplState; +#endif + +class ScreenCapture : public ftl::rgbd::detail::Source { + public: + explicit ScreenCapture(ftl::rgbd::Source *host); + ~ScreenCapture(); + + bool capture(int64_t ts) { timestamp_ = ts; return true; }; + bool retrieve(); + bool compute(int n=-1, int b=-1); + bool isReady(); + + private: + bool ready_; + + ImplState *impl_state_; +}; + +} +} +} + +#endif // _FTL_RGBD_SCREENCAPTURE_HPP_ diff --git a/components/rgbd-sources/src/sources/stereovideo/stereovideo.cpp b/components/rgbd-sources/src/sources/stereovideo/stereovideo.cpp index fd97848563536de22cde51796c4350795f5eaac9..7d5fb662fe467a07912fd6a4f208af5d5aadc11d 100644 --- a/components/rgbd-sources/src/sources/stereovideo/stereovideo.cpp +++ b/components/rgbd-sources/src/sources/stereovideo/stereovideo.cpp @@ -192,19 +192,19 @@ void StereoVideoSource::updateParameters() { cv::Mat K; // same for left and right - double baseline = 1.0 / calib_->getQ().at<double>(3,2); - double doff = -calib_->getQ().at<double>(3,3) * baseline; - double min_depth = this->host_->getConfig().value<double>("min_depth", 0.0); - double max_depth = this->host_->getConfig().value<double>("max_depth", 15.0); + float baseline = static_cast<float>(1.0 / calib_->getQ().at<double>(3,2)); + float doff = static_cast<float>(-calib_->getQ().at<double>(3,3) * baseline); + float min_depth = this->host_->getConfig().value<double>("min_depth", 0.0); + float max_depth = this->host_->getConfig().value<double>("max_depth", 15.0); // left K = calib_->getCameraMatrixLeft(color_size_); state_.getLeft() = { - K.at<double>(0,0), // Fx - K.at<double>(1,1), // Fy - -K.at<double>(0,2), // Cx - -K.at<double>(1,2), // Cy + 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, @@ -223,10 +223,10 @@ void StereoVideoSource::updateParameters() { K = calib_->getCameraMatrixRight(color_size_); state_.getRight() = { - K.at<double>(0,0), // Fx - K.at<double>(1,1), // Fy - -K.at<double>(0,2), // Cx - -K.at<double>(1,2), // Cy + 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, diff --git a/components/rgbd-sources/test/source_unit.cpp b/components/rgbd-sources/test/source_unit.cpp index 4ff46d7649694055bade34278feeb74042f00044..c1dbd76f5daf060f20fb8f09a7e1357dc783e4c7 100644 --- a/components/rgbd-sources/test/source_unit.cpp +++ b/components/rgbd-sources/test/source_unit.cpp @@ -45,6 +45,18 @@ class ImageSource : public ftl::rgbd::detail::Source { bool isReady() { return true; }; }; +class ScreenCapture : public ftl::rgbd::detail::Source { + public: + explicit ScreenCapture(ftl::rgbd::Source *host) : ftl::rgbd::detail::Source(host) { + last_type = "screen"; + } + + bool capture(int64_t ts) { return true; } + bool retrieve() { return true; } + bool compute(int n, int b) { return true; }; + bool isReady() { return true; }; +}; + class StereoVideoSource : public ftl::rgbd::detail::Source { public: explicit StereoVideoSource(ftl::rgbd::Source *host) : ftl::rgbd::detail::Source(host) { @@ -133,6 +145,7 @@ class MiddleburySource : public ftl::rgbd::detail::Source { #define _FTL_RGBD_SNAPSHOT_SOURCE_HPP_ #define _FTL_RGBD_IMAGE_HPP_ #define _FTL_RGBD_REALSENSE_HPP_ +#define _FTL_RGBD_SCREENCAPTURE_HPP_ #define _FTL_RGBD_MIDDLEBURY_SOURCE_HPP_ #define _FTL_RGBD_FILE_SOURCE_HPP_ diff --git a/components/streams/src/injectors.cpp b/components/streams/src/injectors.cpp index c9ccce40121ca3789bbf030ccc6a037ac760f4d7..2a58e5eac0fe174233b39a4a7ba501f3a54e3795 100644 --- a/components/streams/src/injectors.cpp +++ b/components/streams/src/injectors.cpp @@ -62,7 +62,7 @@ void ftl::stream::injectCalibration(ftl::stream::Stream *stream, const ftl::rgbd ftl::codecs::StreamPacket spkt = { 4, ts, - fsid, + static_cast<uint8_t>(fsid), static_cast<uint8_t>(ix), (right) ? Channel::Calibration2 : Channel::Calibration }; diff --git a/components/streams/src/netstream.cpp b/components/streams/src/netstream.cpp index d9533de4958646edc3e0b03bbfbb04f1023cdfb3..bd16f8c0a6becce1bcc3e6a1ba4dcfb047199065 100644 --- a/components/streams/src/netstream.cpp +++ b/components/streams/src/netstream.cpp @@ -81,7 +81,7 @@ bool Net::post(const ftl::codecs::StreamPacket &spkt, const ftl::codecs::Packet // Quality filter the packets if (pkt.bitrate > 0 && pkt.bitrate != client.quality) { //++c; - LOG(INFO) << "Incorrect quality: " << (int)pkt.bitrate << " but requested " << (int)client.quality; + //LOG(INFO) << "Incorrect quality: " << (int)pkt.bitrate << " but requested " << (int)client.quality; //continue; } diff --git a/components/streams/src/receiver.cpp b/components/streams/src/receiver.cpp index 6ef07b742476ab3fd86a8d63cfcc911f30e534df..6338b1943520ef992be559f36ec2f22ac1987fdf 100644 --- a/components/streams/src/receiver.cpp +++ b/components/streams/src/receiver.cpp @@ -259,7 +259,8 @@ void Receiver::_processVideo(const StreamPacket &spkt, const Packet &pkt) { InternalVideoStates &vidstate = _getVideoFrame(spkt,i); auto &frame = builder_[spkt.streamID].get(spkt.timestamp, spkt.frame_number+i); - auto sel = stream_->selected(spkt.frameSetID()); + const auto *cs = stream_; + auto sel = stream_->selected(spkt.frameSetID()) & cs->available(spkt.frameSetID()); frame.create<cv::cuda::GpuMat>(spkt.channel); diff --git a/components/streams/test/receiver_unit.cpp b/components/streams/test/receiver_unit.cpp index d683d4abddfc5f3e764150aa50710fa242718829..062dce960ab7daab5fec0ec6a354c9247f1a5869 100644 --- a/components/streams/test/receiver_unit.cpp +++ b/components/streams/test/receiver_unit.cpp @@ -306,21 +306,21 @@ TEST_CASE( "Receiver sync bugs" ) { return true; }); - stream.post(spkt, pkt); + try { stream.post(spkt, pkt); } catch(...) {} spkt.timestamp = 10; spkt.channel = Channel::ColourHighRes; - stream.post(spkt, pkt); + try { stream.post(spkt, pkt); } catch(...) {} spkt.timestamp = 20; spkt.channel = Channel::Colour2; - stream.post(spkt, pkt); + try { stream.post(spkt, pkt); } catch(...) {} spkt.timestamp = 20; spkt.channel = Channel::Colour; - stream.post(spkt, pkt); + try { stream.post(spkt, pkt); } catch(...) {} int i=10; - while (i-- > 0 && count < 1) std::this_thread::sleep_for(std::chrono::milliseconds(10)); + while (i-- > 0 && count < 2) std::this_thread::sleep_for(std::chrono::milliseconds(10)); - REQUIRE( count == 1 ); + REQUIRE( count == 2 ); REQUIRE( ts == 20 ); REQUIRE( !haswrongchan ); }