diff --git a/modules/viz2d/include/opencv2/viz2d/viz2d.hpp b/modules/viz2d/include/opencv2/viz2d/viz2d.hpp index e50ce14cf..401e10b7e 100644 --- a/modules/viz2d/include/opencv2/viz2d/viz2d.hpp +++ b/modules/viz2d/include/opencv2/viz2d/viz2d.hpp @@ -101,6 +101,9 @@ template void find_widgets(nanogui::Widget* parent, std::vector& */ CV_EXPORTS cv::Scalar colorConvert(const cv::Scalar& src, cv::ColorConversionCodes code); +CV_EXPORTS void resizeKeepAspectRatio(const cv::UMat& src, cv::UMat& output, const cv::Size& dstSize, + const cv::Scalar& bgcolor = {0,0,0,255}); + using namespace cv::viz::detail; class NVG; @@ -119,8 +122,6 @@ CV_EXPORTS class Viz2D { int minor_; int samples_; bool debug_; - std::filesystem::path capturePath_; - std::filesystem::path writerPath_; GLFWwindow* glfwWindow_ = nullptr; FrameBufferContext* clglContext_ = nullptr; CLVAContext* clvaContext_ = nullptr; @@ -144,7 +145,8 @@ public: * @param title The window title. * @param debug Create a debug OpenGL context. */ - CV_EXPORTS static cv::Ptr make(const cv::Size& size, const string& title, bool debug = false); + CV_EXPORTS static cv::Ptr make(const cv::Size& size, const string& title, bool debug = + false); /*! * Creates a Viz2D object which is the central object to perform visualizations with. @@ -157,8 +159,9 @@ public: * @param samples MSAA samples. * @param debug Create a debug OpenGL context. */ - CV_EXPORTS static cv::Ptr make(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); + CV_EXPORTS static cv::Ptr make(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 */ @@ -203,18 +206,18 @@ public: */ CV_EXPORTS void nvg(std::function fn); /*! - * Execute function object fn inside a nanogui context. - * The context 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. - */ + * Execute function object fn inside a nanogui context. + * The context 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. + */ CV_EXPORTS void nanogui(std::function fn); /*! - * Execute function object fn in a loop. - * This function main purpose is to abstract the run loop for portability reasons. - * @param fn A functor that will be called repeatetly until the application terminates or the functor returns false - */ + * Execute function object fn in a loop. + * This function main purpose is to abstract the run loop for portability reasons. + * @param fn A functor that will be called repeatetly until the application terminates or the functor returns false + */ CV_EXPORTS void run(std::function fn); /*! diff --git a/modules/viz2d/samples/cpp/display_image_fb.cpp b/modules/viz2d/samples/cpp/display_image_fb.cpp new file mode 100644 index 000000000..53a590161 --- /dev/null +++ b/modules/viz2d/samples/cpp/display_image_fb.cpp @@ -0,0 +1,24 @@ +#include + +using namespace cv; +using namespace cv::viz; + +constexpr int WIDTH = 1280; +constexpr int HEIGHT = 720; + +int main() { + //Creates a Viz2D object for on screen rendering + Ptr v2d = Viz2D::make(Size(WIDTH, HEIGHT), "Show image"); + //Read an image as UMat + UMat image = imread(samples::findFile("lena.jpg")).getUMat(ACCESS_READ); + UMat resized; + //Resize the image to framebuffer size + resize(image, resized, v2d->getFrameBufferSize()); + v2d->fb([&](const UMat& framebuffer) { + //Color convert the resized UMat. The framebuffer has alpha. + cvtColor(resized, framebuffer, COLOR_RGB2BGRA); + }); + //Display the framebuffer in the native window + while(v2d->display()); +} + diff --git a/modules/viz2d/src/detail/clvacontext.cpp b/modules/viz2d/src/detail/clvacontext.cpp index be7e40b0a..008fe6875 100644 --- a/modules/viz2d/src/detail/clvacontext.cpp +++ b/modules/viz2d/src/detail/clvacontext.cpp @@ -43,7 +43,7 @@ bool CLVAContext::capture(std::function fn) { return false; cv::Size fbSize = clglContext_.getSize(); - cv::resize(videoFrame_, rgbBuffer_, fbSize); + resizeKeepAspectRatio(videoFrame_, rgbBuffer_, fbSize); cv::cvtColor(rgbBuffer_, frameBuffer_, cv::COLOR_RGB2BGRA); assert(frameBuffer_.size() == fbSize); diff --git a/modules/viz2d/src/viz2d.cpp b/modules/viz2d/src/viz2d.cpp index b032b3491..d8f688b4c 100644 --- a/modules/viz2d/src/viz2d.cpp +++ b/modules/viz2d/src/viz2d.cpp @@ -47,14 +47,32 @@ cv::Scalar colorConvert(const cv::Scalar& src, cv::ColorConversionCodes code) { return dst; } +void resizeKeepAspectRatio(const cv::UMat& src, cv::UMat& output, const cv::Size& dstSize, + const cv::Scalar& bgcolor) { + double h1 = dstSize.width * (src.rows / (double) src.cols); + double w2 = dstSize.height * (src.cols / (double) src.rows); + if (h1 <= dstSize.height) { + cv::resize(src, output, cv::Size(dstSize.width, h1)); + } else { + cv::resize(src, output, cv::Size(w2, dstSize.height)); + } + + int top = (dstSize.height - output.rows) / 2; + int down = (dstSize.height - output.rows + 1) / 2; + int left = (dstSize.width - output.cols) / 2; + int right = (dstSize.width - output.cols + 1) / 2; + + cv::copyMakeBorder(output, output, top, down, left, right, cv::BORDER_CONSTANT, bgcolor); +} + cv::Ptr Viz2D::make(const cv::Size& size, const string& title, bool debug) { cv::Ptr v2d = new Viz2D(size, size, false, title, 4, 6, 0, debug); v2d->setVisible(true); return v2d; } -cv::Ptr Viz2D::make(const cv::Size& initialSize, const cv::Size& frameBufferSize, bool offscreen, - const string& title, int major, int minor, int samples, bool debug) { +cv::Ptr Viz2D::make(const cv::Size& initialSize, const cv::Size& frameBufferSize, + bool offscreen, const string& title, int major, int minor, int samples, bool debug) { return new Viz2D(initialSize, frameBufferSize, offscreen, title, major, minor, samples, debug); } @@ -195,11 +213,11 @@ bool Viz2D::initializeWindowing() { find_widgets(&v2d->screen(), widgets); for (auto* w : widgets) { auto mousePos = nanogui::Vector2i(v2d->getMousePosition()[0] / v2d->getXPixelRatio(), v2d->getMousePosition()[1] / v2d->getYPixelRatio()); - if(contains_absolute(w, mousePos)) { - v2d->screen().scroll_callback_event(x, y); - return; - } - } + if(contains_absolute(w, mousePos)) { + v2d->screen().scroll_callback_event(x, y); + return; + } +} v2d->zoom(y < 0 ? 1.1 : 0.9); } @@ -295,13 +313,13 @@ void Viz2D::nanogui(std::function fn) { void Viz2D::run(std::function fn) { #ifndef __EMSCRIPTEN__ - while(keepRunning() && fn()); + while (keepRunning() && fn()) + ; #else emscripten_set_main_loop(fn, -1, true); #endif } - void Viz2D::setSource(const Source& src) { if (!clva().hasContext()) clva().copyContext();