From d3fd227348ad23d5080910be0da845bc28407b9a Mon Sep 17 00:00:00 2001 From: Ruixiang Du Date: Fri, 25 Oct 2024 23:29:25 +0800 Subject: [PATCH] widget: updated image widget --- src/imview/CMakeLists.txt | 9 +- .../include/imview/buffer/buffer_registry.hpp | 1 + .../widget/buffered_cv_image_widget.hpp | 39 ++++++++ .../{ => widget}/cairo/cairo_context.hpp | 10 +- .../imview/{ => widget}/cairo/cairo_draw.hpp | 2 - .../imview/{cairo => widget}/cairo_widget.hpp | 31 ++---- .../include/imview/widget/cv_image_widget.hpp | 40 ++++++++ .../include/imview/widget/image_widget.hpp | 98 ------------------- .../src/widget/buffered_cv_image_widget.cpp | 83 ++++++++++++++++ .../src/{ => widget}/cairo/cairo_context.cpp | 6 +- .../src/{ => widget}/cairo/cairo_draw.cpp | 4 +- .../src/{ => widget}/cairo/cairo_widget.cpp | 88 +++-------------- src/imview/src/widget/cv_image_widget.cpp | 83 ++++++++++++++++ src/imview/test/feature/CMakeLists.txt | 10 +- ....cpp => test_buffered_cv_image_widget.cpp} | 9 +- src/imview/test/feature/test_cairo_widget.cpp | 66 +++++++++++++ .../test/feature/test_cv_image_widget.cpp | 66 +++++++++++++ 17 files changed, 425 insertions(+), 220 deletions(-) create mode 100644 src/imview/include/imview/widget/buffered_cv_image_widget.hpp rename src/imview/include/imview/{ => widget}/cairo/cairo_context.hpp (96%) rename src/imview/include/imview/{ => widget}/cairo/cairo_draw.hpp (97%) rename src/imview/include/imview/{cairo => widget}/cairo_widget.hpp (63%) create mode 100644 src/imview/include/imview/widget/cv_image_widget.hpp delete mode 100644 src/imview/include/imview/widget/image_widget.hpp create mode 100644 src/imview/src/widget/buffered_cv_image_widget.cpp rename src/imview/src/{ => widget}/cairo/cairo_context.cpp (96%) rename src/imview/src/{ => widget}/cairo/cairo_draw.cpp (98%) rename src/imview/src/{ => widget}/cairo/cairo_widget.cpp (51%) create mode 100644 src/imview/src/widget/cv_image_widget.cpp rename src/imview/test/feature/{test_image_widget.cpp => test_buffered_cv_image_widget.cpp} (89%) create mode 100644 src/imview/test/feature/test_cairo_widget.cpp create mode 100644 src/imview/test/feature/test_cv_image_widget.cpp diff --git a/src/imview/CMakeLists.txt b/src/imview/CMakeLists.txt index 9c0455e..0a1952b 100644 --- a/src/imview/CMakeLists.txt +++ b/src/imview/CMakeLists.txt @@ -19,14 +19,15 @@ add_library(imview src/box.cpp src/layer.cpp # src/popup.cpp - # src/cairo_context.cpp # src/data_buffer.cpp - # src/cairo_widget.cpp - # src/cairo_draw.cpp # utils src/utils/image_utils.cpp # widgets -# src/widget/image_widget.cpp + src/widget/cv_image_widget.cpp + src/widget/buffered_cv_image_widget.cpp + src/widget/cairo/cairo_context.cpp + src/widget/cairo/cairo_widget.cpp + src/widget/cairo/cairo_draw.cpp # data buffer src/buffer/buffer_registry.cpp # event handling diff --git a/src/imview/include/imview/buffer/buffer_registry.hpp b/src/imview/include/imview/buffer/buffer_registry.hpp index 9289969..525a4f5 100644 --- a/src/imview/include/imview/buffer/buffer_registry.hpp +++ b/src/imview/include/imview/buffer/buffer_registry.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "imview/buffer/buffer_interface.hpp" diff --git a/src/imview/include/imview/widget/buffered_cv_image_widget.hpp b/src/imview/include/imview/widget/buffered_cv_image_widget.hpp new file mode 100644 index 0000000..7e448c8 --- /dev/null +++ b/src/imview/include/imview/widget/buffered_cv_image_widget.hpp @@ -0,0 +1,39 @@ +/* + * @file image_widget.hpp + * @date 10/10/24 + * @brief + * + * @copyright Copyright (c) 2024 Ruixiang Du (rdu) + */ + +#ifndef QUICKVIZ_CV_IMAGE_WIDGET_HPP +#define QUICKVIZ_IMAGE_WIDGET_HPP + +#include + +#include "imview/panel.hpp" +#include "imview/buffer/buffer_registry.hpp" + +#include "glad/glad.h" + +#include + +namespace quickviz { +class BufferedCvImageWidget : public Panel { + public: + BufferedCvImageWidget(const std::string& widget_name, + const std::string& buffer_name); + ~BufferedCvImageWidget(); + + // public methods + void SetKeepAspectRatio(bool keep); + void Draw() override; + + private: + GLuint image_texture_; + std::shared_ptr> buffer_; + bool keep_aspect_ratio_ = false; +}; +} // namespace quickviz + +#endif // QUICKVIZ_CV_IMAGE_WIDGET_HPP \ No newline at end of file diff --git a/src/imview/include/imview/cairo/cairo_context.hpp b/src/imview/include/imview/widget/cairo/cairo_context.hpp similarity index 96% rename from src/imview/include/imview/cairo/cairo_context.hpp rename to src/imview/include/imview/widget/cairo/cairo_context.hpp index c075c1a..61aed16 100644 --- a/src/imview/include/imview/cairo/cairo_context.hpp +++ b/src/imview/include/imview/widget/cairo/cairo_context.hpp @@ -10,14 +10,13 @@ #ifndef CAIRO_CONTEXT_HPP #define CAIRO_CONTEXT_HPP -#include -#include - #include #include +#include +#include + namespace quickviz { -namespace swviz { class CairoContext { struct Scaler { double x; @@ -74,7 +73,6 @@ class CairoContext { void CreateSurface(); void GenGlTexture(); }; -} // namespace swviz -} // namespace xmotion +} // namespace quickviz #endif /* CAIRO_CONTEXT_HPP */ diff --git a/src/imview/include/imview/cairo/cairo_draw.hpp b/src/imview/include/imview/widget/cairo/cairo_draw.hpp similarity index 97% rename from src/imview/include/imview/cairo/cairo_draw.hpp rename to src/imview/include/imview/widget/cairo/cairo_draw.hpp index 96c1b00..2b1e8c8 100644 --- a/src/imview/include/imview/cairo/cairo_draw.hpp +++ b/src/imview/include/imview/widget/cairo/cairo_draw.hpp @@ -15,7 +15,6 @@ #include "imgui.h" namespace quickviz { -namespace swviz { enum ColorName { BLACK = 0, WHITE, @@ -65,7 +64,6 @@ void DrawRing(cairo_t *cr, ImVec2 center, float inner_radius, void DrawRectangle(cairo_t *cr, ImVec2 pos1, ImVec2 pos2, double thickness = 2, ImVec4 color = colors[BLACK], bool fill = false); -} // namespace swviz } // namespace xmotion #endif /* CAIRO_DRAW_HPP */ diff --git a/src/imview/include/imview/cairo/cairo_widget.hpp b/src/imview/include/imview/widget/cairo_widget.hpp similarity index 63% rename from src/imview/include/imview/cairo/cairo_widget.hpp rename to src/imview/include/imview/widget/cairo_widget.hpp index 49709f1..6d06cf0 100644 --- a/src/imview/include/imview/cairo/cairo_widget.hpp +++ b/src/imview/include/imview/widget/cairo_widget.hpp @@ -19,37 +19,30 @@ #include "imgui.h" -#include "imview/details/cairo_context.hpp" +#include "imview/panel.hpp" +#include "imview/widget/cairo/cairo_context.hpp" namespace quickviz { -namespace swviz { -class CairoWidget { +class CairoWidget : public Panel { public: - CairoWidget(uint32_t width, uint32_t height, + CairoWidget(const std::string& widget_name, uint32_t width, uint32_t height, bool normalize_coordinate = false); - ~CairoWidget(); + ~CairoWidget() override; - // load image texture (before entering rendering loop) - void LoadImage(std::string png_file); + void Draw() override; + void OnResize(float width, float height) override; + + float GetAspectRatio() const; // resize/fill cairo surface void Resize(uint32_t width, uint32_t height); void Fill(ImVec4 color = {1, 1, 1, 0.6}); void Clear(); - float GetAspectRatio() const; - // draw vector graphics with user function using CairoDrawFunc = std::function; void Draw(CairoDrawFunc DrawFunc); - // draw from png image (avoid if possible, slow) - enum class ScaleMode { MANUAL, AUTO_STRETCH, AUTO_KEEP_ASPECT_RATIO }; - void Draw(std::string png_file, double pos_x, double pos_y, - double angle = 0.0, - ScaleMode scale_mode = ScaleMode::AUTO_KEEP_ASPECT_RATIO, - double scale_x = 1.0, double scale_y = 1.0); - // draw text to cairo surface void DrawText(std::string text, double pos_x, double pos_y, double angle = 0.0, ImVec4 color = {0, 0, 0, 1}, @@ -64,11 +57,7 @@ class CairoWidget { private: std::unique_ptr ctx_; - std::unordered_map images_; - - cairo_surface_t* GetImageSurface(std::string png_file); }; -} // namespace swviz -} // namespace xmotion +} // namespace quickviz #endif /* CAIRO_WIDGET_HPP */ diff --git a/src/imview/include/imview/widget/cv_image_widget.hpp b/src/imview/include/imview/widget/cv_image_widget.hpp new file mode 100644 index 0000000..2997ce4 --- /dev/null +++ b/src/imview/include/imview/widget/cv_image_widget.hpp @@ -0,0 +1,40 @@ +/* + * @file image_widget.hpp + * @date 10/10/24 + * @brief + * + * @copyright Copyright (c) 2024 Ruixiang Du (rdu) + */ + +#ifndef QUICKVIZ_CV_IMAGE_WIDGET_HPP +#define QUICKVIZ_CV_IMAGE_WIDGET_HPP + +#include "glad/glad.h" + +#include +#include + +#include + +#include "imview/panel.hpp" + +namespace quickviz { +class CvImageWidget : public Panel { + public: + CvImageWidget(const std::string& widget_name); + ~CvImageWidget(); + + // public methods + void SetKeepAspectRatio(bool keep); + void UpdateImage(const cv::Mat& image); + void Draw() override; + + private: + std::mutex image_mutex_; + cv::Mat image_mat_; + GLuint image_texture_; + bool keep_aspect_ratio_ = false; +}; +} // namespace quickviz + +#endif // QUICKVIZ_CV_IMAGE_WIDGET_HPP \ No newline at end of file diff --git a/src/imview/include/imview/widget/image_widget.hpp b/src/imview/include/imview/widget/image_widget.hpp deleted file mode 100644 index de2b119..0000000 --- a/src/imview/include/imview/widget/image_widget.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * @file image_widget.hpp - * @date 10/10/24 - * @brief - * - * @copyright Copyright (c) 2024 Ruixiang Du (rdu) - */ - -#ifndef QUICKVIZ_IMAGE_WIDGET_HPP -#define QUICKVIZ_IMAGE_WIDGET_HPP - -#include - -#include "imview/panel.hpp" -#include "imview/buffer/buffer_registry.hpp" - -#include "glad/glad.h" - -namespace quickviz { -template -class ImageWidget : public Panel { - public: - using CopyTextureFunc = std::function; - ImageWidget(std::string widget_name, const std::string& buffer_name, - CopyTextureFunc func) - : Panel(widget_name), copy_texture_func_(func) { - this->SetAutoLayout(false); - // this->SetNoResize(true); - // this->SetNoMove(true); - this->SetWindowNoMenuButton(); - this->SetNoBackground(true); - - auto& buffer_registry = BufferRegistry::GetInstance(); - buffer_ = buffer_registry.GetBuffer(buffer_name); - - glGenTextures(1, &image_texture_); - } - - ~ImageWidget() { glDeleteTextures(1, &image_texture_); } - - void SetKeepAspectRatio(bool keep) { keep_aspect_ratio_ = keep; } - - void Draw() override { - Begin(); - { - ImVec2 contentSize = ImGui::GetContentRegionAvail(); - float width = contentSize.x; - float height = contentSize.y; - - T mat; - buffer_->Read(mat); - - if (!mat.empty()) { - if (keep_aspect_ratio_) { - cv::Mat proc = mat; - float aspect_ratio = mat.cols / (float)mat.rows; - float img_width = width; - float img_height = height; - if (width / height > aspect_ratio) { - img_width = height * aspect_ratio; - } else { - img_height = width / aspect_ratio; - } - if (img_width > width) { - // need to scale down - img_width = width; - img_height = width / aspect_ratio; - } else { - // need to scale down - img_height = height; - img_width = height * aspect_ratio; - } - cv::resize(mat, proc, cv::Size(img_width, img_height), 0, 0, - cv::INTER_CUBIC); - // copy display to center of image - cv::Mat display = cv::Mat::zeros(height, width, mat.type()); - cv::Rect roi((width - proc.cols) / 2, (height - proc.rows) / 2, - proc.cols, proc.rows); - proc.copyTo(display(roi)); - copy_texture_func_(display, image_texture_); - } else { - copy_texture_func_(mat, image_texture_); - } - } - ImGui::Image((void*)(intptr_t)image_texture_, ImVec2(width, height)); - } - End(); - } - - private: - GLuint image_texture_; - std::shared_ptr> buffer_; - CopyTextureFunc copy_texture_func_; - bool keep_aspect_ratio_ = false; -}; -} // namespace quickviz - -#endif // QUICKVIZ_IMAGE_WIDGET_HPP \ No newline at end of file diff --git a/src/imview/src/widget/buffered_cv_image_widget.cpp b/src/imview/src/widget/buffered_cv_image_widget.cpp new file mode 100644 index 0000000..eeeb833 --- /dev/null +++ b/src/imview/src/widget/buffered_cv_image_widget.cpp @@ -0,0 +1,83 @@ +/* + * @file buffered_cv_image_widget.cpp + * @date 10/25/24 + * @brief + * + * @copyright Copyright (c) 2024 Ruixiang Du (rdu) + */ + +#include "imview/widget/buffered_cv_image_widget.hpp" + +#include "imview/utils/image_utils.hpp" + +namespace quickviz { +BufferedCvImageWidget::BufferedCvImageWidget(const std::string& widget_name, + const std::string& buffer_name) + : Panel(widget_name) { + this->SetAutoLayout(false); + // this->SetNoResize(true); + // this->SetNoMove(true); + this->SetWindowNoMenuButton(); + this->SetNoBackground(true); + + auto& buffer_registry = BufferRegistry::GetInstance(); + buffer_ = buffer_registry.GetBuffer(buffer_name); + + glGenTextures(1, &image_texture_); +} + +BufferedCvImageWidget::~BufferedCvImageWidget() { + glDeleteTextures(1, &image_texture_); +} + +void BufferedCvImageWidget::SetKeepAspectRatio(bool keep) { + keep_aspect_ratio_ = keep; +} + +void BufferedCvImageWidget::Draw() { + Begin(); + { + ImVec2 contentSize = ImGui::GetContentRegionAvail(); + float width = contentSize.x; + float height = contentSize.y; + + cv::Mat mat; + buffer_->Read(mat); + + if (!mat.empty()) { + if (keep_aspect_ratio_) { + cv::Mat proc = mat; + float aspect_ratio = mat.cols / (float)mat.rows; + float img_width = width; + float img_height = height; + if (width / height > aspect_ratio) { + img_width = height * aspect_ratio; + } else { + img_height = width / aspect_ratio; + } + if (img_width > width) { + // need to scale down + img_width = width; + img_height = width / aspect_ratio; + } else { + // need to scale down + img_height = height; + img_width = height * aspect_ratio; + } + cv::resize(mat, proc, cv::Size(img_width, img_height), 0, 0, + cv::INTER_CUBIC); + // copy display to center of image + cv::Mat display = cv::Mat::zeros(height, width, mat.type()); + cv::Rect roi((width - proc.cols) / 2, (height - proc.rows) / 2, + proc.cols, proc.rows); + proc.copyTo(display(roi)); + CopyTextureFromCvMat(display, image_texture_); + } else { + CopyTextureFromCvMat(mat, image_texture_); + } + } + ImGui::Image((void*)(intptr_t)image_texture_, ImVec2(width, height)); + } + End(); +} +} // namespace quickviz \ No newline at end of file diff --git a/src/imview/src/cairo/cairo_context.cpp b/src/imview/src/widget/cairo/cairo_context.cpp similarity index 96% rename from src/imview/src/cairo/cairo_context.cpp rename to src/imview/src/widget/cairo/cairo_context.cpp index ce291fe..ec7433e 100644 --- a/src/imview/src/cairo/cairo_context.cpp +++ b/src/imview/src/widget/cairo/cairo_context.cpp @@ -7,12 +7,11 @@ * Copyright (c) 2021 Ruixiang Du (rdu) */ -#include "imview/details/cairo_context.hpp" +#include "imview/widget/cairo//cairo_context.hpp" #include namespace quickviz { -namespace swviz { CairoContext::CairoContext(uint32_t width, uint32_t height, bool normalize_coordinate) : width_(width), @@ -107,5 +106,4 @@ GLuint CairoContext::RenderToGlTexture() { return image_texture_; } -} // namespace swviz -} // namespace xmotion \ No newline at end of file +} // namespace quickviz \ No newline at end of file diff --git a/src/imview/src/cairo/cairo_draw.cpp b/src/imview/src/widget/cairo/cairo_draw.cpp similarity index 98% rename from src/imview/src/cairo/cairo_draw.cpp rename to src/imview/src/widget/cairo/cairo_draw.cpp index 6876754..978f9ba 100644 --- a/src/imview/src/cairo/cairo_draw.cpp +++ b/src/imview/src/widget/cairo/cairo_draw.cpp @@ -7,12 +7,11 @@ * Copyright (c) 2021 Ruixiang Du (rdu) */ -#include "imview/cairo_draw.hpp" +#include "imview/widget/cairo/cairo_draw.hpp" #include namespace quickviz { -namespace swviz { void DrawPoint(cairo_t *cr, ImVec2 pos, double size, ImVec4 color) { cairo_set_source_rgba(cr, color.x, color.y, color.z, color.w); cairo_arc(cr, pos.x, pos.y, size, 0, 2 * M_PI); @@ -136,5 +135,4 @@ void DrawRectangle(cairo_t *cr, ImVec2 pos1, ImVec2 pos2, double thickness, DrawLine(cr, start, end, std::abs(pos1.x - pos2.x), color); } } -} // namespace swviz } // namespace xmotion \ No newline at end of file diff --git a/src/imview/src/cairo/cairo_widget.cpp b/src/imview/src/widget/cairo/cairo_widget.cpp similarity index 51% rename from src/imview/src/cairo/cairo_widget.cpp rename to src/imview/src/widget/cairo/cairo_widget.cpp index b245366..f17363c 100644 --- a/src/imview/src/cairo/cairo_widget.cpp +++ b/src/imview/src/widget/cairo/cairo_widget.cpp @@ -7,7 +7,7 @@ * Copyright (c) 2021 Ruixiang Du (rdu) */ -#include "imview/cairo_widget.hpp" +#include "imview/widget/cairo_widget.hpp" #include #include @@ -15,10 +15,10 @@ #include namespace quickviz { -namespace swviz { -CairoWidget::CairoWidget(uint32_t width, uint32_t height, - bool normalize_coordinate) - : ctx_(new CairoContext(width, height, normalize_coordinate)) {} +CairoWidget::CairoWidget(const std::string& widget_name, uint32_t width, + uint32_t height, bool normalize_coordinate) + : Panel(widget_name), + ctx_(new CairoContext(width, height, normalize_coordinate)) {} CairoWidget::~CairoWidget() { // font-related memory cleanup @@ -28,21 +28,22 @@ CairoWidget::~CairoWidget() { // [2] https://gitlab.freedesktop.org/cairo/cairo/-/issues/393 cairo_debug_reset_static_data(); FcFini(); +} + +void CairoWidget::Draw() {} - // cleanup image surfaces - for (auto& img : images_) { - cairo_surface_destroy(img.second); - } +void CairoWidget::OnResize(float width, float height) { + Panel::OnResize(width, height); } +float CairoWidget::GetAspectRatio() const { return ctx_->GetAspectRatio(); } + void CairoWidget::Fill(ImVec4 color) { auto cr = ctx_->GetCairoObject(); cairo_set_source_rgba(cr, color.x, color.y, color.z, color.w); cairo_paint(cr); } -float CairoWidget::GetAspectRatio() const { return ctx_->GetAspectRatio(); } - void CairoWidget::Clear() { // Reference: // [1] https://www.cairographics.org/FAQ/#clear_a_surface @@ -58,17 +59,6 @@ void CairoWidget::Draw(CairoDrawFunc DrawFunc) { DrawFunc(ctx_->GetCairoObject()); } -void CairoWidget::LoadImage(std::string png_file) { - assert(images_.find(png_file) == images_.end()); - auto surface = cairo_image_surface_create_from_png(png_file.c_str()); - images_[png_file] = surface; -} - -cairo_surface_t* CairoWidget::GetImageSurface(std::string png_file) { - assert(images_.find(png_file) != images_.end()); - return images_[png_file]; -} - void CairoWidget::Resize(uint32_t width, uint32_t height) { ctx_->Resize(width, height); } @@ -96,62 +86,10 @@ void CairoWidget::DrawText(std::string text, double pos_x, double pos_y, cairo_restore(cr); } -void CairoWidget::Draw(std::string png_file, double pos_x, double pos_y, - double angle, ScaleMode scale_mode, double scale_x, - double scale_y) { - auto cr = ctx_->GetCairoObject(); - - auto surface = GetImageSurface(png_file); - double sx = 1.0, sy = 1.0; - double pos_offset_x = 0, pos_offset_y = 0; - - if (scale_mode != ScaleMode::MANUAL) { - auto width = cairo_image_surface_get_width(surface); - auto height = cairo_image_surface_get_height(surface); - - auto region = ImGui::GetContentRegionAvail(); - sx = region.x / width; - sy = region.y / height; - - if (scale_mode == ScaleMode::AUTO_KEEP_ASPECT_RATIO) { - double ratio = width / height; - double dx = region.y * ratio, dy = 0; - if (dx > region.x) { - // height is too high, y offset needed - dx = region.x; - dy = dx / ratio; - pos_offset_y = (region.y - dy) / 2.0f; - } else { - // width is too wide, x offset needed - dy = region.y; - dx = dy * ratio; - pos_offset_x = (region.x - dx) / 2.0f; - } - sx = dx / width; - sy = dy / height; - } - } else { - sx = scale_x; - sy = scale_y; - } - - cairo_save(cr); - - cairo_translate(cr, pos_x + pos_offset_x, pos_y + pos_offset_y); - cairo_rotate(cr, angle); - - cairo_scale(cr, sx, sy); - cairo_set_source_surface(cr, surface, 0, 0); - cairo_paint(cr); - - cairo_restore(cr); -} - void CairoWidget::Render(const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) { GLuint image = ctx_->RenderToGlTexture(); ImGui::Image((void*)(intptr_t)image, ImGui::GetContentRegionAvail(), uv0, uv1, tint_col, border_col); } -} // namespace swviz -} // namespace xmotion \ No newline at end of file +} // namespace quickviz \ No newline at end of file diff --git a/src/imview/src/widget/cv_image_widget.cpp b/src/imview/src/widget/cv_image_widget.cpp new file mode 100644 index 0000000..d3f9052 --- /dev/null +++ b/src/imview/src/widget/cv_image_widget.cpp @@ -0,0 +1,83 @@ +/* + * @file cv_image_widget.cpp + * @date 10/25/24 + * @brief + * + * @copyright Copyright (c) 2024 Ruixiang Du (rdu) + */ + +#include "imview/widget/cv_image_widget.hpp" + +#include "imview/utils/image_utils.hpp" + +namespace quickviz { +CvImageWidget::CvImageWidget(const std::string& widget_name) + : Panel(widget_name) { + this->SetAutoLayout(false); + // this->SetNoResize(true); + // this->SetNoMove(true); + this->SetWindowNoMenuButton(); + this->SetNoBackground(true); + + glGenTextures(1, &image_texture_); +} + +CvImageWidget::~CvImageWidget() { glDeleteTextures(1, &image_texture_); } + +void CvImageWidget::SetKeepAspectRatio(bool keep) { keep_aspect_ratio_ = keep; } + +void CvImageWidget::UpdateImage(const cv::Mat& image) { + std::lock_guard lock(image_mutex_); + image_mat_ = image.clone(); +} + +void CvImageWidget::Draw() { + Begin(); + { + ImVec2 contentSize = ImGui::GetContentRegionAvail(); + float width = contentSize.x; + float height = contentSize.y; + + cv::Mat mat; + { + std::lock_guard lock(image_mutex_); + mat = image_mat_.clone(); + } + + if (!mat.empty()) { + if (keep_aspect_ratio_) { + cv::Mat proc = mat; + float aspect_ratio = mat.cols / (float)mat.rows; + float img_width = width; + float img_height = height; + if (width / height > aspect_ratio) { + img_width = height * aspect_ratio; + } else { + img_height = width / aspect_ratio; + } + if (img_width > width) { + // need to scale down + img_width = width; + img_height = width / aspect_ratio; + } else { + // need to scale down + img_height = height; + img_width = height * aspect_ratio; + } + cv::resize(mat, proc, cv::Size(img_width, img_height), 0, 0, + cv::INTER_CUBIC); + // copy display to center of image + cv::Mat display = cv::Mat::zeros(height, width, mat.type()); + cv::Rect roi((width - proc.cols) / 2, (height - proc.rows) / 2, + proc.cols, proc.rows); + proc.copyTo(display(roi)); + CopyTextureFromCvMat(display, image_texture_); + } else { + CopyTextureFromCvMat(mat, image_texture_); + } + } + ImGui::Image((void*)(intptr_t)image_texture_, ImVec2(width, height)); + } + End(); +} +} // namespace quickviz \ No newline at end of file diff --git a/src/imview/test/feature/CMakeLists.txt b/src/imview/test/feature/CMakeLists.txt index 7e2be37..e01e040 100644 --- a/src/imview/test/feature/CMakeLists.txt +++ b/src/imview/test/feature/CMakeLists.txt @@ -4,5 +4,11 @@ target_link_libraries(test_window PRIVATE imview) add_executable(test_viewer test_viewer.cpp) target_link_libraries(test_viewer PRIVATE imview) -add_executable(test_image_widget test_image_widget.cpp) -target_link_libraries(test_image_widget PRIVATE imview) +add_executable(test_cv_image_widget test_cv_image_widget.cpp) +target_link_libraries(test_cv_image_widget PRIVATE imview) + +add_executable(test_buffered_cv_image_widget test_buffered_cv_image_widget.cpp) +target_link_libraries(test_buffered_cv_image_widget PRIVATE imview) + +add_executable(test_cairo_widget test_cairo_widget.cpp) +target_link_libraries(test_cairo_widget PRIVATE imview) diff --git a/src/imview/test/feature/test_image_widget.cpp b/src/imview/test/feature/test_buffered_cv_image_widget.cpp similarity index 89% rename from src/imview/test/feature/test_image_widget.cpp rename to src/imview/test/feature/test_buffered_cv_image_widget.cpp index 868b845..ec8a209 100644 --- a/src/imview/test/feature/test_image_widget.cpp +++ b/src/imview/test/feature/test_buffered_cv_image_widget.cpp @@ -1,5 +1,5 @@ /* - * test_image_widget.cpp + * test_buffered_cv_image_widget.cpp * * Created on: Jul 27, 2021 09:07 * Description: @@ -19,8 +19,7 @@ #include "imview/buffer/double_buffer.hpp" #include "scene_objects/gl_triangle_scene_object.hpp" -#include "imview/widget/image_widget.hpp" -#include "imview/utils/image_utils.hpp" +#include "imview/widget/buffered_cv_image_widget.hpp" using namespace quickviz; @@ -66,8 +65,8 @@ int main(int argc, char* argv[]) { auto gl_triangle = std::make_shared(); viewer.AddSceneObject(gl_triangle); - auto image_widget = std::make_shared>( - "camera", buffer_name, CopyTextureFromCvMat); + auto image_widget = + std::make_shared("camera", buffer_name); image_widget->OnResize(300, 200); image_widget->SetPosition(0, 0); viewer.AddSceneObject(image_widget); diff --git a/src/imview/test/feature/test_cairo_widget.cpp b/src/imview/test/feature/test_cairo_widget.cpp new file mode 100644 index 0000000..9090d3e --- /dev/null +++ b/src/imview/test/feature/test_cairo_widget.cpp @@ -0,0 +1,66 @@ +/* + * test_cairo_widget.cpp + * + * Created on: Jul 27, 2021 09:07 + * Description: + * + * Copyright (c) 2021 Ruixiang Du (rdu) + */ + +#include +#include + +#include + +#include "imview/viewer.hpp" +#include "imview/widget/cv_image_widget.hpp" + +#include "scene_objects/gl_triangle_scene_object.hpp" + +using namespace quickviz; + +bool keep_running = true; +std::shared_ptr image_widget; + +void CaptureVideo() { + cv::VideoCapture cap(0); // Open the default camera + if (!cap.isOpened()) { + std::cerr << "Error: Could not open video capture device." << std::endl; + return; + } + + while (keep_running) { + cv::Mat frame; + cap >> frame; // Capture a new frame + if (frame.empty()) { + break; // End of video stream + } + + if (image_widget != nullptr) image_widget->UpdateImage(frame); + std::this_thread::sleep_for( + std::chrono::milliseconds(30)); // Simulate frame rate + } +} + +int main(int argc, char* argv[]) { + // set up video capture thread --> producer + std::thread capture_thread(CaptureVideo); + + // set up viewer --> consumer + Viewer viewer; + auto gl_triangle = std::make_shared(); + viewer.AddSceneObject(gl_triangle); + + image_widget = std::make_shared("camera"); + image_widget->OnResize(300, 200); + image_widget->SetPosition(0, 0); + viewer.AddSceneObject(image_widget); + + viewer.Show(); + + // clean up + keep_running = false; + capture_thread.join(); + + return 0; +} \ No newline at end of file diff --git a/src/imview/test/feature/test_cv_image_widget.cpp b/src/imview/test/feature/test_cv_image_widget.cpp new file mode 100644 index 0000000..d5fce0e --- /dev/null +++ b/src/imview/test/feature/test_cv_image_widget.cpp @@ -0,0 +1,66 @@ +/* + * test_cv_image_widget.cpp + * + * Created on: Jul 27, 2021 09:07 + * Description: + * + * Copyright (c) 2021 Ruixiang Du (rdu) + */ + +#include +#include + +#include + +#include "imview/viewer.hpp" +#include "imview/widget/cv_image_widget.hpp" + +#include "scene_objects/gl_triangle_scene_object.hpp" + +using namespace quickviz; + +bool keep_running = true; +std::shared_ptr image_widget; + +void CaptureVideo() { + cv::VideoCapture cap(0); // Open the default camera + if (!cap.isOpened()) { + std::cerr << "Error: Could not open video capture device." << std::endl; + return; + } + + while (keep_running) { + cv::Mat frame; + cap >> frame; // Capture a new frame + if (frame.empty()) { + break; // End of video stream + } + + if (image_widget != nullptr) image_widget->UpdateImage(frame); + std::this_thread::sleep_for( + std::chrono::milliseconds(30)); // Simulate frame rate + } +} + +int main(int argc, char* argv[]) { + // set up video capture thread --> producer + std::thread capture_thread(CaptureVideo); + + // set up viewer --> consumer + Viewer viewer; + auto gl_triangle = std::make_shared(); + viewer.AddSceneObject(gl_triangle); + + image_widget = std::make_shared("camera"); + image_widget->OnResize(300, 200); + image_widget->SetPosition(0, 0); + viewer.AddSceneObject(image_widget); + + viewer.Show(); + + // clean up + keep_running = false; + capture_thread.join(); + + return 0; +} \ No newline at end of file