diff --git a/src/common/util.cpp b/src/common/util.cpp index 2067731d7..803605d43 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -131,7 +131,12 @@ bool keep_running() { return !finish_requested; } -void update_fps(cv::Ptr v2d, bool graphically) { +/*! + * Little helper function to keep track of FPS and optionally display it using NanoVG + * @param v2d The Viz2D object to operate on + * @param graphical if this parameter is true the FPS drawn on display + */ +void update_fps(cv::Ptr v2d, bool graphical) { static uint64_t cnt = 0; static cv::TickMeter tick; static float fps; @@ -150,7 +155,7 @@ void update_fps(cv::Ptr v2d, bool graphically) { tick.reset(); } - if (graphically) { + if (graphical) { v2d->nvg([&](const cv::Size& size) { using namespace cv; string text = "FPS: " + std::to_string(fps); diff --git a/src/common/util.hpp b/src/common/util.hpp index 049cd80bd..d2f01ab97 100644 --- a/src/common/util.hpp +++ b/src/common/util.hpp @@ -54,10 +54,11 @@ void print_system_info(); * @return true if the program should keep on running */ bool keep_running(); + /*! - * Little helper program to keep track of FPS and optionally display it using NanoVG + * Little helper function to keep track of FPS and optionally display it using NanoVG * @param v2d The Viz2D object to operate on - * @param graphically if this parameter is true the FPS drawn on display + * @param graphical if this parameter is true the FPS drawn on display */ void update_fps(cv::Ptr viz2d, bool graphical); @@ -101,6 +102,13 @@ Sink make_writer_sink(const string& outputFilename, const int fourcc, const floa */ Source make_capture_source(const string& inputFilename); #else +/*! + * Creates a WebCam source object to use in conjunction with #Viz2D::setSource(). + * In the background it uses emscripten's file system implementation to transfer frames from the camera to the source object + * @param width The frame width to capture (usually the initial width of the Viz2D object) + * @param height The frame height to capture (usually the initial height of the Viz2D object) + * @return A WebCam source object. + */ Source make_capture_source(int width, int height); #endif diff --git a/src/common/viz2d.cpp b/src/common/viz2d.cpp index 6973e7aff..18a8913f4 100644 --- a/src/common/viz2d.cpp +++ b/src/common/viz2d.cpp @@ -29,22 +29,12 @@ void gl_check_error(const std::filesystem::path& file, unsigned int line, const void glfw_error_callback(int error, const char* description) { fprintf(stderr, "GLFW Error: %s\n", description); } -} - -template void find_widgets(nanogui::Widget* parent, std::vector& widgets) { - T w; - for (auto* child : parent->children()) { - find_widgets(child, widgets); - if ((w = dynamic_cast(child)) != nullptr) { - widgets.push_back(w); - } - } -} bool contains_absolute(nanogui::Widget* w, const nanogui::Vector2i& p) { nanogui::Vector2i d = p - w->absolute_position(); return d.x() >= 0 && d.y() >= 0 && d.x() < w->size().x() && d.y() < w->size().y(); } +} cv::Scalar color_convert(const cv::Scalar& src, cv::ColorConversionCodes code) { cv::Mat tmpIn(1, 1, CV_8UC3); @@ -346,11 +336,11 @@ void Viz2D::makeNoneCurrent() { glfwMakeContextCurrent(nullptr); } -void Viz2D::clear(const cv::Scalar& rgba) { - const float& r = rgba[0] / 255.0f; - const float& g = rgba[1] / 255.0f; - const float& b = rgba[2] / 255.0f; - const float& a = rgba[3] / 255.0f; +void Viz2D::clear(const cv::Scalar& bgra) { + const float& b = bgra[0] / 255.0f; + const float& g = bgra[1] / 255.0f; + const float& r = bgra[2] / 255.0f; + const float& a = bgra[3] / 255.0f; GL_CHECK(glClearColor(r, g, b, a)); GL_CHECK(glClear(GL_COLOR_BUFFER_BIT)); } diff --git a/src/common/viz2d.hpp b/src/common/viz2d.hpp index 0126dc9be..c82ae3e61 100644 --- a/src/common/viz2d.hpp +++ b/src/common/viz2d.hpp @@ -62,6 +62,28 @@ void gl_check_error(const std::filesystem::path& file, unsigned int line, const * @param description Error description */ void glfw_error_callback(int error, const char* description); +/*! + * Checks if a widget contains an absolute point. + * @param w The widget. + * @param p The point. + * @return true if the points is inside the widget + */ +bool contains_absolute(nanogui::Widget* w, const nanogui::Vector2i& p); +/*! + * Find widgets that are of type T. + * @tparam T The type of widget to find + * @param parent The parent widget + * @param widgets A vector of widgets of type T to append newly found widgets to. + */ +template void find_widgets(nanogui::Widget* parent, std::vector& widgets) { + T w; + for (auto* child : parent->children()) { + find_widgets(child, widgets); + if ((w = dynamic_cast(child)) != nullptr) { + widgets.push_back(w); + } + } +} } /*! @@ -109,36 +131,124 @@ class Viz2D { Sink sink_; std::function keyEventCb_; public: + /*! + * Creates a Viz2D object which is the central object to perform visualizations with. + * @param initialSize The initial size of the heavy-weight window. + * @param frameBufferSize The initial size of the framebuffer backing the window (needs to be equal or greate then initial size). + * @param offscreen Don't create a window and rather render offscreen. + * @param title The window title. + * @param major The OpenGL major version to request. + * @param minor The OpenGL minor version to request. + * @param samples MSAA samples. + * @param debug Create a debug OpenGL context. + */ Viz2D(const cv::Size& initialSize, const cv::Size& frameBufferSize, bool offscreen, const string& title, int major = 4, int minor = 6, int samples = 0, bool debug = false); + /*! + * Default destructor + */ virtual ~Viz2D(); - bool initializeWindowing(); + /*! + * In case several Viz2D objects are in use all objects not in use have to + * call #makeNoneCurrent() and only the one to be active call #makeCurrent(). + */ void makeCurrent(); + /*! + * To make it possible for other Viz2D objects to become current all other + * Viz2d instances have to become non-current. + */ void makeNoneCurrent(); + /*! + * The internal framebuffer exposed as OpenGL Texture2D. + * @return The texture object. + */ cv::ogl::Texture2D& texture(); + /*! + * Execute function object fn inside an opengl scope. + * This is how all OpenGL operations should be executed. + * @param fn A function object that is passed the size of the framebuffer + */ void gl(std::function fn); + /*! + * Execute function object fn inside a framebuffer scope. + * The scope acquires the framebuffer from OpenGL (either by up-/download or by cl-gl sharing) + * and provides it to the functon object. This is a good place to use OpenCL + * directly on the framebuffer. + * @param fn A function object that is passed the framebuffer to be read/manipulated. + */ void fb(std::function fn); + /*! + * Execute function object fn inside a nanovg scope. + * The scope takes care of setting up opengl and nanovg states. + * A function object passed like that can use the functions in cv::viz::nvg. + * @param fn A function that is passed the size of the framebuffer + * and performs drawing using cv::viz::nvg + */ void nvg(std::function fn); + /*! + * Execute function object fn inside a nanogui scope. + * The scope provides a #cv::viz::FormHelper instance to the function object + * which can be used to build a gui. + * @param fn A function that is passed the size of the framebuffer + * and performs drawing using cv::viz::nvg. + */ void nanogui(std::function); - void clear(const cv::Scalar& rgba = cv::Scalar(0, 0, 0, 255)); - + /*! + * Clear the framebuffer. + * @param bgra The color to use for clearing. + */ + void clear(const cv::Scalar& bgra = cv::Scalar(0, 0, 0, 255)); + /*! + * Called to capture to the framebuffer from a #cv::viz::Source object provided via #Viz2D::setSource(). + * @return true if successful. + */ bool capture(); + /*! + * Called to capture from a function object. + * The functor fn is passed a UMat which it writes to which in turn is captured to the framebuffer. + * @param fn The functor that provides the data. + * @return true if successful- + */ bool capture(std::function fn); + /*! + * Called to write the framebuffer to a #cv::viz::Sink object provided via #Viz2D::setSink() + */ void write(); + /*! + * Called to pass the frambuffer to a functor which consumes it (e.g. writes to a video file). + * @param fn The functor that consumes the data, + */ void write(std::function fn); + /*! + * Set the current #cv::viz::Source object. Usually created using #make_capture_source(). + * @param src A #cv::viz::Source object. + */ void setSource(const Source& src); + /*! + * Checks if the current #cv::viz::Source is ready. + * @return true if it is ready. + */ bool isSourceReady(); + /*! + * Set the current #cv::viz::Sink object. Usually created using #make_writer_sink(). + * @param sink A #cv::viz::Sink object. + */ void setSink(const Sink& sink); + /*! + * Checks if the current #cv::viz::Sink is ready. + * @return true if it is ready. + */ bool isSinkReady(); - + /*! + * Shows or hides the GUI. + * @param s if true show the GUI. + */ void showGui(bool s); - void setMouseDrag(bool d); - bool isMouseDrag(); void pan(int x, int y); void zoom(float factor); cv::Vec2f getPosition(); @@ -172,6 +282,9 @@ public: void setKeyboardEventCallback( std::function fn); private: + bool initializeWindowing(); + void setMouseDrag(bool d); + bool isMouseDrag(); bool keyboard_event(int key, int scancode, int action, int modifiers); void setMousePosition(int x, int y); nanogui::Screen& screen();