summaryrefslogtreecommitdiffhomepage
path: root/cv
diff options
context:
space:
mode:
Diffstat (limited to 'cv')
-rw-r--r--cv/CMakeLists.txt15
-rw-r--r--cv/affine.cpp35
-rw-r--r--cv/affine.hpp34
-rw-r--r--cv/init.cpp24
-rw-r--r--cv/init.hpp2
-rw-r--r--cv/lang/de_DE.ts4
-rw-r--r--cv/lang/zh_CN.ts4
-rw-r--r--cv/numeric.hpp21
-rw-r--r--cv/ocv-check.cxx7
-rw-r--r--cv/translation-calibrator.cpp86
-rw-r--r--cv/translation-calibrator.hpp44
-rw-r--r--cv/video-property-page.cpp182
-rw-r--r--cv/video-property-page.hpp23
-rw-r--r--cv/video-widget.cpp108
-rw-r--r--cv/video-widget.hpp35
15 files changed, 267 insertions, 357 deletions
diff --git a/cv/CMakeLists.txt b/cv/CMakeLists.txt
index 67a27ee9..3a8798cc 100644
--- a/cv/CMakeLists.txt
+++ b/cv/CMakeLists.txt
@@ -1,6 +1,15 @@
-find_package(OpenCV 3.0 QUIET COMPONENTS ${opencv-modules})
+include(opentrack-opencv)
+find_package(OpenCV QUIET)
if(OpenCV_FOUND)
+ try_compile(cv_use-ipp "${CMAKE_CURRENT_BINARY_DIR}"
+ SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/ocv-check.cxx"
+ CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${OpenCV_INCLUDE_DIRS}"
+ "-DCXX_STANDARD=20" "-DCXX_STANDARD_REQUIRED=1"
+ OUTPUT_VARIABLE krap)
otr_module(cv STATIC)
- target_link_libraries(opentrack-cv ${OpenCV_LIBS})
- target_include_directories(opentrack-cv SYSTEM PUBLIC ${OpenCV_INCLUDE_DIRS})
+ target_link_libraries(${self} opencv_core opentrack-video)
+ target_include_directories(${self} SYSTEM PRIVATE ${OpenCV_INCLUDE_DIRS})
+ if(cv_use-ipp)
+ target_compile_definitions(${self} PUBLIC -DOTR_HAS_CV_IPP)
+ endif()
endif()
diff --git a/cv/affine.cpp b/cv/affine.cpp
new file mode 100644
index 00000000..66e21aa6
--- /dev/null
+++ b/cv/affine.cpp
@@ -0,0 +1,35 @@
+/* Copyright (c) 2012 Patrick Ruoff
+ *
+ * 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.
+ */
+
+#include "affine.hpp"
+
+namespace affine_impl {
+
+Affine::Affine() = default;
+Affine::Affine(const mat33& R, const vec3& t) : R(R), t(t) {}
+
+Affine operator*(const Affine& X, const Affine& Y)
+{
+ return { X.R*Y.R, X.R*Y.t + X.t };
+}
+
+Affine operator*(const mat33& X, const Affine& Y)
+{
+ return { X*Y.R, X*Y.t };
+}
+
+Affine operator*(const Affine& X, const mat33& Y)
+{
+ return { X.R*Y, X.t };
+}
+
+vec3 operator*(const Affine& X, const vec3& v)
+{
+ return X.R*v + X.t;
+}
+
+} // ns affine_impl
diff --git a/cv/affine.hpp b/cv/affine.hpp
new file mode 100644
index 00000000..4640e24e
--- /dev/null
+++ b/cv/affine.hpp
@@ -0,0 +1,34 @@
+/* Copyright (c) 2012 Patrick Ruoff
+ *
+ * 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 "numeric.hpp"
+
+namespace affine_impl {
+
+using namespace numeric_types;
+
+class Affine final
+{
+public:
+ Affine();
+ Affine(const mat33& R, const vec3& t);
+
+ mat33 R { mat33::eye() };
+ vec3 t { 0, 0, 0 };
+};
+
+Affine operator*(const Affine& X, const Affine& Y);
+Affine operator*(const mat33& X, const Affine& Y);
+Affine operator*(const Affine& X, const mat33& Y);
+vec3 operator*(const Affine& X, const vec3& v);
+
+} // ns affine_impl
+
+using Affine = affine_impl::Affine;
+//using affine_impl::operator *;
diff --git a/cv/init.cpp b/cv/init.cpp
new file mode 100644
index 00000000..d883365b
--- /dev/null
+++ b/cv/init.cpp
@@ -0,0 +1,24 @@
+#include "init.hpp"
+#include <type_traits>
+#include <opencv2/core/base.hpp>
+#include <opencv2/core/utility.hpp>
+
+[[noreturn]]
+static
+int error_handler(int, const char* fn, const char* msg, const char* filename, int line, void*)
+{
+ fprintf(stderr, "[%s:%d] opencv: %s at %s\n", filename, line, msg, fn);
+ fflush(stderr);
+ std::abort();
+}
+
+void opencv_init()
+{
+ cv::redirectError(error_handler);
+ cv::setBreakOnError(false);
+ cv::setNumThreads(1);
+#ifdef OTR_HAS_CV_IPP
+ cv::ipp::setUseIPP(true);
+ cv::ipp::setUseIPP_NotExact(true);
+#endif
+}
diff --git a/cv/init.hpp b/cv/init.hpp
new file mode 100644
index 00000000..4c529549
--- /dev/null
+++ b/cv/init.hpp
@@ -0,0 +1,2 @@
+#pragma once
+void opencv_init();
diff --git a/cv/lang/de_DE.ts b/cv/lang/de_DE.ts
new file mode 100644
index 00000000..1552582e
--- /dev/null
+++ b/cv/lang/de_DE.ts
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+</TS>
diff --git a/cv/lang/zh_CN.ts b/cv/lang/zh_CN.ts
new file mode 100644
index 00000000..e5ca8aa9
--- /dev/null
+++ b/cv/lang/zh_CN.ts
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="zh_CN">
+</TS>
diff --git a/cv/numeric.hpp b/cv/numeric.hpp
new file mode 100644
index 00000000..2050e8e4
--- /dev/null
+++ b/cv/numeric.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <type_traits>
+#include <opencv2/core/matx.hpp>
+
+namespace numeric_types {
+ using f = float;
+
+ static_assert(std::is_floating_point_v<f>);
+
+ static constexpr f eps = f(1e-8);
+ static constexpr f pi = f(M_PI);
+
+ template<int n> using vec = cv::Vec<f, n>;
+ using vec2 = vec<2>;
+ using vec3 = vec<3>;
+
+ template<int y, int x> using mat = cv::Matx<f, y, x>;
+ using mat33 = mat<3, 3>;
+ using mat22 = mat<2, 2>;
+}
diff --git a/cv/ocv-check.cxx b/cv/ocv-check.cxx
new file mode 100644
index 00000000..9efe3610
--- /dev/null
+++ b/cv/ocv-check.cxx
@@ -0,0 +1,7 @@
+#include <opencv2/core.hpp>
+
+void check1()
+{
+ cv::ipp::setUseIPP(true);
+ cv::ipp::setUseIPP_NotExact(true);
+}
diff --git a/cv/translation-calibrator.cpp b/cv/translation-calibrator.cpp
index cdd573bc..6fb3e638 100644
--- a/cv/translation-calibrator.cpp
+++ b/cv/translation-calibrator.cpp
@@ -7,16 +7,16 @@
#include "translation-calibrator.hpp"
#include "compat/euler.hpp"
-#include "compat/util.hpp"
+#include "compat/math.hpp"
+#include "compat/macros.h"
+#include <opencv2/core.hpp>
#include <tuple>
-constexpr double TranslationCalibrator::pitch_spacing_in_degrees;
-constexpr double TranslationCalibrator::yaw_spacing_in_degrees;
-constexpr double TranslationCalibrator::roll_spacing_in_degrees;
+#include <QDebug>
-TranslationCalibrator::TranslationCalibrator(unsigned yaw_rdof, unsigned pitch_rdof, unsigned roll_rdof) :
- yaw_rdof(yaw_rdof), pitch_rdof(pitch_rdof), roll_rdof(roll_rdof)
+TranslationCalibrator::TranslationCalibrator(unsigned yaw_rdof, unsigned pitch_rdof) :
+ yaw_rdof(yaw_rdof), pitch_rdof(pitch_rdof)
{
reset();
}
@@ -24,11 +24,10 @@ TranslationCalibrator::TranslationCalibrator(unsigned yaw_rdof, unsigned pitch_r
void TranslationCalibrator::reset()
{
P = cv::Matx66f::zeros();
- y = cv::Vec6f(0,0,0, 0,0,0);
+ y = { 0,0,0, 0,0,0 };
- used_yaw_poses = vec(1 + iround(360 / yaw_spacing_in_degrees), 0);
- used_pitch_poses = vec(1 + iround(360 / pitch_spacing_in_degrees), 0);
- used_roll_poses = vec(1 + iround(360 / roll_spacing_in_degrees), 0);
+ used_yaw_poses = vec_i(1 + iround(360 / yaw_spacing_in_degrees), 0);
+ used_pitch_poses = vec_i(1 + iround(360 / pitch_spacing_in_degrees), 0);
nsamples = 0;
}
@@ -54,65 +53,70 @@ void TranslationCalibrator::update(const cv::Matx33d& R_CM_k, const cv::Vec3d& t
y += H_k_T * t_CM_k;
}
-std::tuple<cv::Vec3f, unsigned> TranslationCalibrator::get_estimate()
+using cv_out_vec = TranslationCalibrator::cv_nsample_vec;
+using cv_in_vec = TranslationCalibrator::cv_cal_vec;
+using tt = TranslationCalibrator::tt;
+
+tt TranslationCalibrator::get_estimate()
{
cv::Vec6f x = P.inv() * y;
- qDebug() << "calibrator:" << nsamples << "samples total";
-
- unsigned values[3] {};
- vec* in[] { &used_yaw_poses, &used_pitch_poses, &used_roll_poses };
+ vec_i const* in[num_nsample_axis] = { &used_yaw_poses, &used_pitch_poses, };
+ unsigned nsamples[num_cal_axis] {};
- for (unsigned k = 0; k < 3; k++)
+ for (unsigned k = 0; k < num_nsample_axis; k++)
{
- const vec& data = *in[k];
- for (unsigned i = 0; i < data.size(); i++)
- if (data[i])
- values[k]++;
+ vec_i const& data = *in[k];
+ for (unsigned i : data)
+ if (i)
+ nsamples[k]++;
}
- qDebug() << "samples"
- << "yaw" << values[0]
- << "pitch" << values[1]
- << "roll" << values[2];
+ qDebug() << "samples total" << nsamples
+ << "yaw" << nsamples[0]
+ << "pitch" << nsamples[1];
- return std::make_tuple(cv::Vec3f(-x[0], -x[1], -x[2]), nsamples);
+ return {
+ { -x[0], -x[1], -x[2] },
+ { nsamples[0], nsamples[1] },
+ };
}
+static constexpr double r2d = 180/M_PI;
+
bool TranslationCalibrator::check_bucket(const cv::Matx33d& R_CM_k)
{
using namespace euler;
- static constexpr double r2d = 180/M_PI;
rmat r;
for (unsigned j = 0; j < 3; j++)
for (unsigned i = 0; i < 3; i++)
r(j, i) = R_CM_k(j, i);
- const euler_t ypr = rmat_to_euler(r) * r2d;
+ const Pose_ ypr = rmat_to_euler(r) * r2d;
- const unsigned yaw_k = iround((ypr(yaw_rdof) + 180)/yaw_spacing_in_degrees);
- const unsigned pitch_k = iround((ypr(pitch_rdof) + 180)/pitch_spacing_in_degrees);
- const unsigned roll_k = iround((ypr(roll_rdof) + 180)/roll_spacing_in_degrees);
+ auto array_index = [](double val, double spacing) {
+ return (unsigned)iround((val + 180)/spacing);
+ };
- if (yaw_k < used_yaw_poses.size() &&
- pitch_k < used_pitch_poses.size() &&
- roll_k < used_roll_poses.size())
+ const unsigned yaw_k = array_index(ypr(yaw_rdof), yaw_spacing_in_degrees);
+ const unsigned pitch_k = array_index(ypr(pitch_rdof), pitch_spacing_in_degrees);
+ if (yaw_k < used_yaw_poses.size() &&
+ pitch_k < used_pitch_poses.size())
{
used_yaw_poses[yaw_k]++;
used_pitch_poses[pitch_k]++;
- used_roll_poses[roll_k]++;
return used_yaw_poses[yaw_k] == 1 ||
- used_pitch_poses[pitch_k] == 1 ||
- used_roll_poses[roll_k] == 1;
+ used_pitch_poses[pitch_k] == 1;
}
else
- qDebug() << "calibrator: index out of range"
- << "yaw" << yaw_k
- << "pitch" << pitch_k
- << "roll" << roll_k;
+ {
+ eval_once(qDebug() << "calibrator: index out of range"
+ << "yaw" << yaw_k
+ << "pitch" << pitch_k);
- return false;
+ return false;
+ }
}
diff --git a/cv/translation-calibrator.hpp b/cv/translation-calibrator.hpp
index 40ba19e9..3912c938 100644
--- a/cv/translation-calibrator.hpp
+++ b/cv/translation-calibrator.hpp
@@ -7,7 +7,7 @@
#pragma once
-#include <opencv2/core.hpp>
+#include <opencv2/core/matx.hpp>
#include <vector>
//-----------------------------------------------------------------------------
@@ -19,34 +19,38 @@
class TranslationCalibrator
{
-public:
- TranslationCalibrator(unsigned yaw_rdof, unsigned pitch_rdof, unsigned roll_rdof);
+ bool check_bucket(const cv::Matx33d& R_CM_k);
+
+ cv::Matx66f P; // normalized precision matrix = inverse covariance
+ cv::Vec6f y; // P*(-t_MH, t_CH)
+
+ using vec_i = std::vector<unsigned>;
+
+ vec_i used_yaw_poses {};
+ vec_i used_pitch_poses {};
+
+ unsigned yaw_rdof, pitch_rdof, nsamples = 0;
- // reset the calibration process
+public:
+ TranslationCalibrator(unsigned yaw_rdof, unsigned pitch_rdof);
void reset();
// update the current estimate
void update(const cv::Matx33d& R_CM_k, const cv::Vec3d& t_CM_k);
- // get the current estimate for t_MH
- std::tuple<cv::Vec3f, unsigned> get_estimate();
-
-private:
- bool check_bucket(const cv::Matx33d& R_CM_k);
- static int get_index(int yaw, int pitch, int roll);
+ // we're bringing in 3DOF samples but the calibrator only
+ // checks yaw and pitch
- cv::Matx66f P; // normalized precision matrix = inverse covariance
- cv::Vec6f y; // P*(-t_MH, t_CH)
+ static constexpr unsigned num_cal_axis = 3;
+ static constexpr unsigned num_nsample_axis = 2;
- using vec = std::vector<unsigned>;
+ using cv_cal_vec = cv::Vec<float, num_cal_axis>;
+ using cv_nsample_vec = cv::Vec<unsigned, num_nsample_axis>;
+ using tt = std::tuple<cv_cal_vec, cv_nsample_vec>;
- vec used_yaw_poses;
- vec used_pitch_poses;
- vec used_roll_poses;
+ // get the current estimate for t_MH
+ tt get_estimate();
- static constexpr double yaw_spacing_in_degrees = 2.5;
+ static constexpr double yaw_spacing_in_degrees = 2;
static constexpr double pitch_spacing_in_degrees = 1.5;
- static constexpr double roll_spacing_in_degrees = 3.5;
-
- unsigned yaw_rdof, pitch_rdof, roll_rdof, nsamples;
};
diff --git a/cv/video-property-page.cpp b/cv/video-property-page.cpp
deleted file mode 100644
index b542a9c4..00000000
--- a/cv/video-property-page.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-/* Copyright (c) 2016 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.
- */
-
-#include "video-property-page.hpp"
-
-#ifdef _WIN32
-
-#include <cstring>
-#include <QRegularExpression>
-#include <QDebug>
-
-#define CHECK(expr) if (FAILED(hr = (expr))) { qDebug() << QStringLiteral(#expr) << hr; goto done; }
-#define CHECK2(expr) if (!(expr)) { qDebug() << QStringLiteral(#expr); goto done; }
-
-bool video_property_page::show_from_capture(cv::VideoCapture& cap, int)
-{
- cap.set(cv::CAP_PROP_SETTINGS, 0);
- return true;
-}
-
-bool video_property_page::should_show_dialog(const QString& camera_name)
-{
- using re = QRegularExpression;
- static const re regexen[] =
- {
- re("^PS3Eye Camera$"),
- re("^A4 TECH "),
- };
- bool avail = true;
- for (const re& r : regexen)
- {
- avail &= !r.match(camera_name).hasMatch();
- if (!avail)
- break;
- }
- return avail;
-}
-
-bool video_property_page::show(int id)
-{
- IBaseFilter* filter = NULL;
- bool ret = false;
-
- CHECK2(filter = get_device(id));
-
- ret = SUCCEEDED(ShowFilterPropertyPages(filter));
-
-done:
- if (filter)
- filter->Release();
-
- return ret;
-}
-
-HRESULT video_property_page::ShowFilterPropertyPages(IBaseFilter* filter)
-{
- ISpecifyPropertyPages* pProp = NULL;
- IUnknown* unk = NULL;
- CAUUID caGUID = { 0, NULL };
- FILTER_INFO FilterInfo = { {0}, NULL };
- HRESULT hr;
-
- CHECK(filter->QueryInterface(IID_ISpecifyPropertyPages, (void**)&pProp));
- CHECK(pProp->GetPages(&caGUID));
- CHECK(filter->QueryFilterInfo(&FilterInfo));
-
- filter->QueryInterface(IID_IUnknown, (void**)&unk);
-
- // OleInitialize, CoCreateInstance et al. don't help with ps3 eye.
-
- // cl-eye uses this
- // perhaps more than IBaseFilter* -> IUnknown* needs be passed to lplpUnk
- // and the OleCreatePropertyFrame equiv
-#if 0
- OCPFIPARAMS params;
- params.cbStructSize = sizeof(params);
- params.hWndOwner = GetActiveWindow();
- params.x = 0;
- params.y = 0;
- params.lpszCaption = L"camera props";
- params.cObjects = 1;
- params.lplpUnk = &unk;
- params.cPages = 1;
- //OleCreatePropertyFrameIndirect()
-#endif
-
- OleCreatePropertyFrame(
- NULL, // Parent window
- 0, 0, // Reserved
- FilterInfo.achName, // Caption for the dialog box
- 1, // Number of objects (just the filter)
- &unk, // Array of object pointers.
- caGUID.cElems, // Number of property pages
- caGUID.pElems, // Array of property page CLSIDs
- 0, // Locale identifier
- 0, NULL // Reserved
- );
-
-done:
- if (FilterInfo.pGraph)
- FilterInfo.pGraph->Release();
-
- if (caGUID.pElems)
- CoTaskMemFree(caGUID.pElems);
-
- if (pProp)
- pProp->Release();
-
- if (unk)
- unk->Release();
-
- return hr;
-}
-
-IBaseFilter* video_property_page::get_device(int id)
-{
- ICreateDevEnum* pSysDevEnum = NULL;
- IEnumMoniker* pEnumCat = NULL;
- IMoniker* pMoniker = NULL;
- IBaseFilter* filter = NULL;
- HRESULT hr;
-
- CHECK(CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pSysDevEnum));
- CHECK(pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0));
-
- for (int i = 0; !filter && SUCCEEDED(pEnumCat->Next(1, &pMoniker, NULL)); pMoniker->Release(), i++)
- {
- if (i == id)
- {
- CHECK(pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&filter));
- break;
- }
- }
-
-done:
- if (pMoniker)
- pMoniker->Release();
-
- if (pEnumCat)
- pEnumCat->Release();
-
- if (pSysDevEnum)
- pSysDevEnum->Release();
-
- return filter;
-}
-
-#elif defined(__linux)
-# include <QProcess>
-# include "compat/camera-names.hpp"
-
-bool video_property_page::should_show_dialog(const QString&)
-{
- return true;
-}
-
-bool video_property_page::show(int idx)
-{
- const QList<QString> camera_names(get_camera_names());
-
- if (idx >= 0 && idx < camera_names.size())
- return QProcess::startDetached("qv4l2", QStringList() << "-d" << camera_names[idx]);
- else
- return false;
-}
-
-bool video_property_page::show_from_capture(cv::VideoCapture&, int idx)
-{
- return show(idx);
-}
-#else
-bool video_property_page::show(int) { return false; }
-bool video_property_page::show_from_capture(cv::VideoCapture&, int) { return false; }
-bool video_property_page::should_show_dialog(const QString& camera_name)
-{
- return false;
-}
-#endif
diff --git a/cv/video-property-page.hpp b/cv/video-property-page.hpp
deleted file mode 100644
index 4e53e2ab..00000000
--- a/cv/video-property-page.hpp
+++ /dev/null
@@ -1,23 +0,0 @@
-#pragma once
-
-#include <QString>
-
-#ifdef _WIN32
-# include <windows.h>
-# include <dshow.h>
-#endif
-
-#include "opencv2/videoio.hpp"
-
-struct video_property_page final
-{
- video_property_page() = delete;
- static bool show(int id);
- static bool show_from_capture(cv::VideoCapture& cap, int idx);
- static bool should_show_dialog(const QString& camera_name);
-private:
-#ifdef _WIN32
- static HRESULT ShowFilterPropertyPages(IBaseFilter* filter);
- static IBaseFilter* get_device(int id);
-#endif
-};
diff --git a/cv/video-widget.cpp b/cv/video-widget.cpp
index acaf06a6..7accd275 100644
--- a/cv/video-widget.cpp
+++ b/cv/video-widget.cpp
@@ -1,78 +1,64 @@
-/* Copyright (c) 2012 Patrick Ruoff
- * Copyright (c) 2014-2016 Stanislaw Halik <sthalik@misaki.pl>
- *
- * 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.
- */
-
#include "video-widget.hpp"
+#include "compat/macros.h"
#include <opencv2/imgproc.hpp>
-cv_video_widget::cv_video_widget(QWidget* parent) :
- QWidget(parent), freshp(false)
-{
- connect(&timer, SIGNAL(timeout()), this, SLOT(update_and_repaint()));
- timer.start(65);
-}
-
void cv_video_widget::update_image(const cv::Mat& frame)
{
- QMutexLocker l(&mtx);
-
- if (!freshp)
- {
- const int w = preview_size.width(), h = preview_size.height();
-
- if (w < 1 || h < 1)
- return;
-
- if (_frame.cols != frame.cols || _frame.rows != frame.rows)
- _frame = cv::Mat(frame.rows, frame.cols, CV_8UC3);
- frame.copyTo(_frame);
- freshp = true;
-
- if (_frame2.cols != _frame.cols || _frame2.rows != _frame.rows)
- _frame2 = cv::Mat(_frame.rows, _frame.cols, CV_8UC3);
-
- if (_frame3.cols != w || _frame3.rows != h)
- _frame3 = cv::Mat(h, w, CV_8UC3);
-
- cv::cvtColor(_frame, _frame2, cv::COLOR_RGB2BGR);
-
- const cv::Mat* img_;
+ if (fresh())
+ return;
- if (_frame.cols != w || _frame.rows != h)
- {
- cv::resize(_frame2, _frame3, cv::Size(w, h), 0, 0, cv::INTER_NEAREST);
+ auto [ W, H ] = preview_size();
- img_ = &_frame3;
- }
- else
- img_ = &_frame2;
+ if (W < 1 || H < 1 || frame.rows < 1 || frame.cols < 1)
+ return;
- const cv::Mat& img = *img_;
+ cv::Mat const* __restrict scaled = nullptr;
+ frame3.create(H, W, frame.type());
+ frame2.create(H, W, CV_8UC4);
- texture = QImage((const unsigned char*) img.data, w, h, QImage::Format_RGB888);
+ if (frame.cols != W || frame.rows != H)
+ {
+ cv::resize(frame, frame3, { W, H }, 0, 0, cv::INTER_NEAREST);
+ scaled = &frame3;
}
-}
+ else if (!frame.isContinuous())
+ {
+ frame.copyTo(frame3);
+ scaled = &frame3;
+ }
+ else
+ scaled = &frame;
-void cv_video_widget::paintEvent(QPaintEvent*)
-{
- QMutexLocker foo(&mtx);
- QPainter painter(this);
- painter.drawImage(rect(), texture);
-}
+ int color_cvt = cv::COLOR_COLORCVT_MAX;
-void cv_video_widget::update_and_repaint()
-{
- QMutexLocker l(&mtx);
+ switch (scaled->channels())
+ {
+ case 1:
+ color_cvt = cv::COLOR_GRAY2BGRA;
+ break;
+ case 3:
+ color_cvt = cv::COLOR_BGR2BGRA;
+ break;
+ case 4:
+ break;
+ default:
+ unreachable();
+ break;
+ }
- preview_size = size();
+ cv::Mat const* color;
- if (freshp)
+ if (color_cvt != cv::COLOR_COLORCVT_MAX)
{
- freshp = false;
- update();
+ cv::cvtColor(*scaled, frame2, color_cvt);
+ color = &frame2;
}
+ else
+ color = scaled;
+
+ int width = color->cols, height = color->rows;
+ unsigned stride = color->step.p[0];
+ set_image(color->data, width, height, stride, QImage::Format_ARGB32);
+
+ set_fresh(true);
}
diff --git a/cv/video-widget.hpp b/cv/video-widget.hpp
index 3b29ffc6..24f8d7f3 100644
--- a/cv/video-widget.hpp
+++ b/cv/video-widget.hpp
@@ -1,5 +1,4 @@
-/* Copyright (c) 2012 Patrick Ruoff
- * Copyright (c) 2014-2016 Stanislaw Halik <sthalik@misaki.pl>
+/* Copyright (c) 2019 Stanislaw Halik <sthalik@misaki.pl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -8,32 +7,14 @@
#pragma once
-#include <opencv2/core/core.hpp>
-#include <memory>
-#include <QObject>
-#include <QWidget>
-#include <QPainter>
-#include <QPaintEvent>
-#include <QTimer>
-#include <QMutex>
-#include <QMutexLocker>
-#include <QSize>
-#include <QDebug>
+#include "video/video-widget.hpp"
+#include <opencv2/core/mat.hpp>
-class cv_video_widget final : public QWidget
+struct cv_video_widget final : video_widget
{
- Q_OBJECT
-public:
- cv_video_widget(QWidget *parent);
- void update_image(const cv::Mat &frame);
-protected slots:
- void paintEvent(QPaintEvent*) override;
- void update_and_repaint();
+ using video_widget::video_widget;
+ void update_image(const cv::Mat& frame);
+
private:
- QMutex mtx;
- QImage texture;
- QTimer timer;
- QSize preview_size;
- cv::Mat _frame, _frame2, _frame3;
- bool freshp;
+ cv::Mat frame2, frame3;
};