From 85fc6ac25d350950be56ba47b06c247216f2e22a Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Mon, 11 Feb 2019 20:07:41 +0100 Subject: video/widget: externalize opencv code --- cv/CMakeLists.txt | 2 +- cv/video-widget.cpp | 78 +++++++++++++++++++++++ cv/video-widget.hpp | 20 ++++++ tracker-aruco/CMakeLists.txt | 2 +- tracker-aruco/ftnoir_tracker_aruco.h | 2 +- tracker-kinect-face/kinect_face_tracker.cpp | 2 +- tracker-kinect-face/kinect_face_tracker.h | 2 +- tracker-pt/CMakeLists.txt | 2 +- tracker-pt/ftnoir_tracker_pt.cpp | 8 +-- tracker-pt/ftnoir_tracker_pt.h | 4 +- video/CMakeLists.txt | 8 +-- video/export.hpp | 11 ++++ video/video-widget.cpp | 96 +++-------------------------- video/video-widget.hpp | 23 +++---- 14 files changed, 139 insertions(+), 121 deletions(-) create mode 100644 cv/video-widget.cpp create mode 100644 cv/video-widget.hpp create mode 100644 video/export.hpp diff --git a/cv/CMakeLists.txt b/cv/CMakeLists.txt index 60350a99..dfc983aa 100644 --- a/cv/CMakeLists.txt +++ b/cv/CMakeLists.txt @@ -1,6 +1,6 @@ find_package(OpenCV QUIET) if(OpenCV_FOUND) otr_module(cv STATIC) - target_link_libraries(${self} opencv_videoio opencv_core) + target_link_libraries(${self} opencv_videoio opencv_core opentrack-video) target_include_directories(${self} SYSTEM PRIVATE ${OpenCV_INCLUDE_DIRS}) endif() diff --git a/cv/video-widget.cpp b/cv/video-widget.cpp new file mode 100644 index 00000000..7cc6ca2d --- /dev/null +++ b/cv/video-widget.cpp @@ -0,0 +1,78 @@ +#include "video-widget.hpp" + +#include + +void cv_video_widget::update_image(const cv::Mat& frame) +{ + QMutexLocker l(&mtx); + + if (freshp) + return; + + if (W < 1 || H < 1 || frame.rows < 1 || frame.cols < 1) + return; + + cv::Mat const* __restrict frame_scaled = nullptr; + + if (frame3.cols != W || frame3.rows != H) + { + frame3 = cv::Mat(H, W, frame.type()); + frame2 = cv::Mat(H, W, CV_8UC4); + + if (!frame2.isContinuous() || !frame3.isContinuous()) + std::abort(); + } + + if (frame.cols != W || frame.rows != H) + { + cv::resize(frame, frame3, { W, H }, 0, 0, cv::INTER_NEAREST); + frame_scaled = &frame3; + } + else if (!frame.isContinuous()) + { + frame.copyTo(frame3); + frame_scaled = &frame3; + } + else + frame_scaled = &frame; + + freshp = true; + + int color_cvt = 0; + constexpr int nchannels = 4; + + switch (frame_scaled->channels()) + { + case 1: + color_cvt = cv::COLOR_GRAY2BGRA; + break; + case 3: + color_cvt = cv::COLOR_BGR2BGRA; + break; + case nchannels: + break; + default: + unreachable(); + break; + } + + cv::Mat const* frame_color; + + if (color_cvt != cv::COLOR_COLORCVT_MAX) + { + cv::cvtColor(*frame_scaled, frame2, color_cvt); + frame_color = &frame2; + } + else + frame_color = frame_scaled; + + int stride = frame_color->step.p[0], rows = frame_color->rows; + int nbytes = rows * stride; + vec.resize(nbytes); vec.shrink_to_fit(); + std::memcpy(vec.data(), frame_color->data, nbytes); + + texture = QImage((const unsigned char*) vec.data(), W, H, stride, QImage::Format_ARGB32); + texture.setDevicePixelRatio(devicePixelRatioF()); +} + +cv_video_widget::cv_video_widget(QWidget* parent) : video_widget(parent) {} diff --git a/cv/video-widget.hpp b/cv/video-widget.hpp new file mode 100644 index 00000000..9d62f19e --- /dev/null +++ b/cv/video-widget.hpp @@ -0,0 +1,20 @@ +/* Copyright (c) 2019 Stanislaw Halik + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#pragma once + +#include "video/video-widget.hpp" +#include + +struct cv_video_widget final : video_widget +{ + cv_video_widget(QWidget* parent = nullptr); + void update_image(const cv::Mat& frame); + +private: + cv::Mat frame2, frame3; +}; diff --git a/tracker-aruco/CMakeLists.txt b/tracker-aruco/CMakeLists.txt index f34b7420..bfa7a348 100644 --- a/tracker-aruco/CMakeLists.txt +++ b/tracker-aruco/CMakeLists.txt @@ -39,6 +39,6 @@ if(OpenCV_FOUND) otr_module(tracker-aruco) target_include_directories(${self} SYSTEM PUBLIC ${OpenCV_INCLUDE_DIRS} "${dir}") - target_link_libraries(${self} opentrack-cv opentrack-video ${modules}) + target_link_libraries(${self} opentrack-cv ${modules}) endif() endif() diff --git a/tracker-aruco/ftnoir_tracker_aruco.h b/tracker-aruco/ftnoir_tracker_aruco.h index 0477c4da..1d6fd107 100644 --- a/tracker-aruco/ftnoir_tracker_aruco.h +++ b/tracker-aruco/ftnoir_tracker_aruco.h @@ -11,7 +11,7 @@ #include "options/options.hpp" #include "cv/translation-calibrator.hpp" #include "api/plugin-api.hpp" -#include "video/video-widget.hpp" +#include "cv/video-widget.hpp" #include "compat/timer.hpp" #include "aruco/markerdetector.h" diff --git a/tracker-kinect-face/kinect_face_tracker.cpp b/tracker-kinect-face/kinect_face_tracker.cpp index e826f8b0..d4cf89e3 100644 --- a/tracker-kinect-face/kinect_face_tracker.cpp +++ b/tracker-kinect-face/kinect_face_tracker.cpp @@ -127,7 +127,7 @@ module_status KinectFaceTracker::start_tracker(QFrame* aFrame) if (SUCCEEDED(InitializeDefaultSensor())) { // Setup our video preview widget - iVideoWidget = std::make_unique(aFrame); + iVideoWidget = std::make_unique(aFrame); iLayout = std::make_unique(aFrame); iLayout->setContentsMargins(0, 0, 0, 0); iLayout->addWidget(iVideoWidget.get()); diff --git a/tracker-kinect-face/kinect_face_tracker.h b/tracker-kinect-face/kinect_face_tracker.h index 672047b1..3ed28bea 100644 --- a/tracker-kinect-face/kinect_face_tracker.h +++ b/tracker-kinect-face/kinect_face_tracker.h @@ -109,7 +109,7 @@ private: CameraSpacePoint iFaceRotation = { 0 }; CameraSpacePoint iFaceRotationCenter = { 0 }; // - std::unique_ptr iVideoWidget; + std::unique_ptr iVideoWidget; std::unique_ptr iLayout; // Id of the body currently being tracked diff --git a/tracker-pt/CMakeLists.txt b/tracker-pt/CMakeLists.txt index 94e0a9d5..f12f530b 100644 --- a/tracker-pt/CMakeLists.txt +++ b/tracker-pt/CMakeLists.txt @@ -2,7 +2,7 @@ find_package(OpenCV QUIET) if(OpenCV_FOUND) otr_module(tracker-pt-base STATIC) target_include_directories(${self} SYSTEM PUBLIC ${OpenCV_INCLUDE_DIRS}) - target_link_libraries(${self} opencv_imgproc opentrack-cv opentrack-video opencv_core) + target_link_libraries(${self} opencv_imgproc opentrack-cv opencv_core) set_property(TARGET ${self} PROPERTY OUTPUT_NAME "pt-base") endif() add_subdirectory(module) diff --git a/tracker-pt/ftnoir_tracker_pt.cpp b/tracker-pt/ftnoir_tracker_pt.cpp index ed29906f..b717e4a1 100644 --- a/tracker-pt/ftnoir_tracker_pt.cpp +++ b/tracker-pt/ftnoir_tracker_pt.cpp @@ -94,11 +94,11 @@ void Tracker_PT::run() vec3 p = X_GH.t; // head (center?) position in global space preview_frame->draw_head_center((p[0] * fx) / p[2], (p[1] * fx) / p[2]); - video_widget->update_image(preview_frame->get_bitmap()); + widget->update_image(preview_frame->get_bitmap()); { int w = -1, h = -1; - video_widget->get_preview_size(w, h); + widget->get_preview_size(w, h); if (w != preview_width || h != preview_height) { preview_width = w; preview_height = h; @@ -127,10 +127,10 @@ module_status Tracker_PT::start_tracker(QFrame* video_frame) { //video_frame->setAttribute(Qt::WA_NativeWindow); - video_widget = std::make_unique(video_frame); + widget = std::make_unique(video_frame); layout = std::make_unique(video_frame); layout->setContentsMargins(0, 0, 0, 0); - layout->addWidget(video_widget.get()); + layout->addWidget(widget.get()); video_frame->setLayout(layout.get()); //video_widget->resize(video_frame->width(), video_frame->height()); video_frame->show(); diff --git a/tracker-pt/ftnoir_tracker_pt.h b/tracker-pt/ftnoir_tracker_pt.h index 0226fd87..77835602 100644 --- a/tracker-pt/ftnoir_tracker_pt.h +++ b/tracker-pt/ftnoir_tracker_pt.h @@ -24,7 +24,7 @@ #include class TrackerDialog_PT; -class cv_video_widget; +class video_widget; namespace pt_module { @@ -69,7 +69,7 @@ private: pointer point_extractor; pointer camera; - pointer video_widget; + pointer widget; pointer frame; pointer preview_frame; diff --git a/video/CMakeLists.txt b/video/CMakeLists.txt index 3bf04d75..0a9dfd24 100644 --- a/video/CMakeLists.txt +++ b/video/CMakeLists.txt @@ -1,7 +1 @@ -find_package(OpenCV QUIET) -otr_module(video STATIC) -if(OpenCV_FOUND) - target_compile_definitions(${self} PUBLIC -DOTR_VIDEO_HAS_OPENCV) - target_link_libraries(${self} opencv_videoio opencv_core) -endif() - +otr_module(video BIN) diff --git a/video/export.hpp b/video/export.hpp new file mode 100644 index 00000000..fc850193 --- /dev/null +++ b/video/export.hpp @@ -0,0 +1,11 @@ +// generates export.hpp for each module from compat/linkage.hpp + +#pragma once + +#include "compat/linkage-macros.hpp" + +#ifdef BUILD_VIDEO +# define OTR_VIDEO_EXPORT OTR_GENERIC_EXPORT +#else +# define OTR_VIDEO_EXPORT OTR_GENERIC_IMPORT +#endif diff --git a/video/video-widget.cpp b/video/video-widget.cpp index 90975f0c..3e6d9038 100644 --- a/video/video-widget.cpp +++ b/video/video-widget.cpp @@ -6,103 +6,24 @@ #include #include -#ifdef OTR_VIDEO_HAS_OPENCV -# include -#endif - #include -void cv_video_widget::init_image_nolock() +void video_widget::init_image_nolock() { texture = QImage(W, H, QImage::Format_ARGB32); texture.setDevicePixelRatio(devicePixelRatioF()); } -cv_video_widget::cv_video_widget(QWidget* parent) : QWidget(parent) +video_widget::video_widget(QWidget* parent) : QWidget(parent) { W = width(); H = height(); init_image_nolock(); texture.fill(Qt::gray); - connect(&timer, &QTimer::timeout, this, &cv_video_widget::update_and_repaint, Qt::DirectConnection); + connect(&timer, &QTimer::timeout, this, &video_widget::update_and_repaint, Qt::DirectConnection); timer.start(65); } -#ifdef OTR_VIDEO_HAS_OPENCV -void cv_video_widget::update_image(const cv::Mat& frame) -{ - QMutexLocker l(&mtx); - - if (freshp) - return; - - if (W < 1 || H < 1 || frame.rows < 1 || frame.cols < 1) - return; - - cv::Mat const* __restrict frame_scaled = nullptr; - - if (frame3.cols != W || frame3.rows != H) - { - frame3 = cv::Mat(H, W, frame.type()); - frame2 = cv::Mat(H, W, CV_8UC4); - - if (!frame2.isContinuous() || !frame3.isContinuous()) - std::abort(); - } - - if (frame.cols != W || frame.rows != H) - { - cv::resize(frame, frame3, { W, H }, 0, 0, cv::INTER_NEAREST); - frame_scaled = &frame3; - } - else if (!frame.isContinuous()) - { - frame.copyTo(frame3); - frame_scaled = &frame3; - } - else - frame_scaled = &frame; - - freshp = true; - - int color_cvt = 0; - constexpr int nchannels = 4; - - switch (frame_scaled->channels()) - { - case 1: - color_cvt = cv::COLOR_GRAY2BGRA; - break; - case 3: - color_cvt = cv::COLOR_BGR2BGRA; - break; - case nchannels: - break; - default: - unreachable(); - break; - } - - cv::Mat const* frame_color; - - if (color_cvt != cv::COLOR_COLORCVT_MAX) - { - cv::cvtColor(*frame_scaled, frame2, color_cvt); - frame_color = &frame2; - } - else - frame_color = frame_scaled; - - int stride = frame_color->step.p[0], rows = frame_color->rows; - int nbytes = rows * stride; - vec.resize(nbytes); vec.shrink_to_fit(); - std::memcpy(vec.data(), frame_color->data, nbytes); - - texture = QImage((const unsigned char*) vec.data(), W, H, stride, QImage::Format_ARGB32); - texture.setDevicePixelRatio(devicePixelRatioF()); -} -#endif - -void cv_video_widget::update_image(const QImage& img) +void video_widget::update_image(const QImage& img) { QMutexLocker l(&mtx); @@ -118,7 +39,7 @@ void cv_video_widget::update_image(const QImage& img) texture.setDevicePixelRatio(devicePixelRatioF()); } -void cv_video_widget::paintEvent(QPaintEvent*) +void video_widget::paintEvent(QPaintEvent*) { QMutexLocker foo(&mtx); @@ -132,7 +53,7 @@ void cv_video_widget::paintEvent(QPaintEvent*) painter.drawImage(rect(), texture); } -void cv_video_widget::update_and_repaint() +void video_widget::update_and_repaint() { if (!check_is_visible()) return; @@ -146,7 +67,7 @@ void cv_video_widget::update_and_repaint() } } -void cv_video_widget::resizeEvent(QResizeEvent*) +void video_widget::resizeEvent(QResizeEvent*) { QMutexLocker l(&mtx); double dpr = devicePixelRatioF(); @@ -155,8 +76,9 @@ void cv_video_widget::resizeEvent(QResizeEvent*) init_image_nolock(); } -void cv_video_widget::get_preview_size(int& w, int& h) +void video_widget::get_preview_size(int& w, int& h) { QMutexLocker l(&mtx); w = W; h = H; } + diff --git a/video/video-widget.hpp b/video/video-widget.hpp index b610557d..563f468c 100644 --- a/video/video-widget.hpp +++ b/video/video-widget.hpp @@ -8,45 +8,38 @@ #pragma once #include "compat/math.hpp" +#include "export.hpp" #include -#ifdef OTR_VIDEO_HAS_OPENCV -# include -#endif - #include #include #include -class cv_video_widget final : public QWidget +class OTR_VIDEO_EXPORT video_widget : public QWidget { Q_OBJECT public: - cv_video_widget(QWidget *parent); + video_widget(QWidget* parent = nullptr); -#ifdef OTR_VIDEO_HAS_OPENCV - void update_image(const cv::Mat& frame); -#endif void update_image(const QImage& image); void get_preview_size(int& w, int& h); void resizeEvent(QResizeEvent*) override; -private slots: +protected slots: void paintEvent(QPaintEvent*) override; void update_and_repaint(); private: + QTimer timer; + +protected: QMutex mtx { QMutex::Recursive }; QImage texture; std::vector vec; - QTimer timer; -#ifdef OTR_VIDEO_HAS_OPENCV - cv::Mat frame2, frame3; -#endif bool freshp = false; - int W = iround(QWidget::width() * devicePixelRatioF()); + int W = iround(QWidget::width() * devicePixelRatioF()); int H = iround(QWidget::height() * devicePixelRatioF()); void init_image_nolock(); -- cgit v1.2.3