1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 15:53:03 +04:00

highgui: backends and plugins

This commit is contained in:
Alexander Alekhin
2021-05-01 13:13:58 +00:00
committed by Alexander Alekhin
parent 7d66f1e391
commit 70f69cb265
28 changed files with 2395 additions and 187 deletions
+396 -3
View File
@@ -40,14 +40,159 @@
//M*/
#include "precomp.hpp"
#include <map>
#include "backend.hpp"
#include "opencv2/core/opengl.hpp"
#include "opencv2/core/utils/logger.hpp"
// in later times, use this file as a dispatcher to implementations like cvcap.cpp
using namespace cv;
using namespace cv::highgui_backend;
namespace cv {
Mutex& getWindowMutex()
{
static Mutex* g_window_mutex = new Mutex();
return *g_window_mutex;
}
namespace impl {
typedef std::map<std::string, highgui_backend::UIWindowBase::Ptr> WindowsMap_t;
static WindowsMap_t& getWindowsMap()
{
static WindowsMap_t g_windowsMap;
return g_windowsMap;
}
static std::shared_ptr<UIWindow> findWindow_(const std::string& name)
{
cv::AutoLock lock(cv::getWindowMutex());
auto& windowsMap = getWindowsMap();
auto i = windowsMap.find(name);
if (i != windowsMap.end())
{
const auto& ui_base = i->second;
if (ui_base)
{
if (!ui_base->isActive())
{
windowsMap.erase(i);
return std::shared_ptr<UIWindow>();
}
auto window = std::dynamic_pointer_cast<UIWindow>(ui_base);
return window;
}
}
return std::shared_ptr<UIWindow>();
}
static void cleanupTrackbarCallbacksWithData_(); // forward declaration
static void cleanupClosedWindows_()
{
cv::AutoLock lock(cv::getWindowMutex());
auto& windowsMap = getWindowsMap();
for (auto it = windowsMap.begin(); it != windowsMap.end();)
{
const auto& ui_base = it->second;
bool erase = (!ui_base || !ui_base->isActive());
if (erase)
{
it = windowsMap.erase(it);
}
else
{
++it;
}
}
cleanupTrackbarCallbacksWithData_();
}
// Just to support deprecated API, to be removed
struct TrackbarCallbackWithData
{
std::weak_ptr<UITrackbar> trackbar_;
int* data_;
TrackbarCallback callback_;
void* userdata_;
TrackbarCallbackWithData(int* data, TrackbarCallback callback, void* userdata)
: data_(data)
, callback_(callback), userdata_(userdata)
{
// trackbar_ is initialized separatelly
}
~TrackbarCallbackWithData()
{
CV_LOG_DEBUG(NULL, "UI/Trackbar: Cleanup deprecated TrackbarCallbackWithData");
}
void onChange(int pos)
{
if (data_)
*data_ = pos;
if (callback_)
callback_(pos, userdata_);
}
static void onChangeCallback(int pos, void* userdata)
{
TrackbarCallbackWithData* thiz = (TrackbarCallbackWithData*)userdata;
CV_Assert(thiz);
return thiz->onChange(pos);
}
};
typedef std::vector< std::shared_ptr<TrackbarCallbackWithData> > TrackbarCallbacksWithData_t;
static TrackbarCallbacksWithData_t& getTrackbarCallbacksWithData()
{
static TrackbarCallbacksWithData_t g_trackbarCallbacksWithData;
return g_trackbarCallbacksWithData;
}
static void cleanupTrackbarCallbacksWithData_()
{
cv::AutoLock lock(cv::getWindowMutex());
auto& callbacks = getTrackbarCallbacksWithData();
for (auto it = callbacks.begin(); it != callbacks.end();)
{
const auto& cb = *it;
bool erase = (!cb || cb->trackbar_.expired());
if (erase)
{
it = callbacks.erase(it);
}
else
{
++it;
}
}
}
}} // namespace cv::impl
using namespace cv::impl;
CV_IMPL void cvSetWindowProperty(const char* name, int prop_id, double prop_value)
{
CV_TRACE_FUNCTION();
CV_Assert(name);
{
auto window = findWindow_(name);
if (window)
{
/*bool res = */window->setProperty(prop_id, prop_value);
return;
}
}
switch(prop_id)
{
//change between fullscreen or not.
@@ -109,8 +254,19 @@ CV_IMPL void cvSetWindowProperty(const char* name, int prop_id, double prop_valu
/* return -1 if error */
CV_IMPL double cvGetWindowProperty(const char* name, int prop_id)
{
if (!name)
return -1;
CV_TRACE_FUNCTION();
CV_Assert(name);
{
auto window = findWindow_(name);
if (window)
{
double v = window->getProperty(prop_id);
if (cvIsNaN(v))
return -1;
return v;
}
}
switch(prop_id)
{
@@ -209,9 +365,18 @@ CV_IMPL double cvGetWindowProperty(const char* name, int prop_id)
cv::Rect cvGetWindowImageRect(const char* name)
{
CV_TRACE_FUNCTION();
if (!name)
return cv::Rect(-1, -1, -1, -1);
{
auto window = findWindow_(name);
if (window)
{
return window->getImageRect();
}
}
#if defined (HAVE_QT)
return cvGetWindowRect_QT(name);
#elif defined(HAVE_WIN32UI)
@@ -234,24 +399,90 @@ cv::Rect cv::getWindowImageRect(const String& winname)
void cv::namedWindow( const String& winname, int flags )
{
CV_TRACE_FUNCTION();
CV_Assert(!winname.empty());
{
cv::AutoLock lock(cv::getWindowMutex());
cleanupClosedWindows_();
auto& windowsMap = getWindowsMap();
auto i = windowsMap.find(winname);
if (i != windowsMap.end())
{
auto ui_base = i->second;
if (ui_base)
{
auto window = std::dynamic_pointer_cast<UIWindow>(ui_base);
if (!window)
{
CV_LOG_ERROR(NULL, "OpenCV/UI: Can't create window: '" << winname << "'");
}
return;
}
}
auto backend = getCurrentUIBackend();
if (backend)
{
auto window = backend->createWindow(winname, flags);
if (!window)
{
CV_LOG_ERROR(NULL, "OpenCV/UI: Can't create window: '" << winname << "'");
return;
}
windowsMap.emplace(winname, window);
return;
}
}
cvNamedWindow( winname.c_str(), flags );
}
void cv::destroyWindow( const String& winname )
{
CV_TRACE_FUNCTION();
{
auto window = findWindow_(winname);
if (window)
{
window->destroy();
cleanupClosedWindows_();
return;
}
}
cvDestroyWindow( winname.c_str() );
}
void cv::destroyAllWindows()
{
CV_TRACE_FUNCTION();
{
cv::AutoLock lock(cv::getWindowMutex());
auto backend = getCurrentUIBackend();
if (backend)
{
backend->destroyAllWindows();
cleanupClosedWindows_();
return;
}
}
cvDestroyAllWindows();
}
void cv::resizeWindow( const String& winname, int width, int height )
{
CV_TRACE_FUNCTION();
{
auto window = findWindow_(winname);
if (window)
{
return window->resize(width, height);
}
}
cvResizeWindow( winname.c_str(), width, height );
}
@@ -264,6 +495,15 @@ void cv::resizeWindow(const String& winname, const cv::Size& size)
void cv::moveWindow( const String& winname, int x, int y )
{
CV_TRACE_FUNCTION();
{
auto window = findWindow_(winname);
if (window)
{
return window->move(x, y);
}
}
cvMoveWindow( winname.c_str(), x, y );
}
@@ -282,6 +522,16 @@ double cv::getWindowProperty(const String& winname, int prop_id)
int cv::waitKeyEx(int delay)
{
CV_TRACE_FUNCTION();
{
cv::AutoLock lock(cv::getWindowMutex());
auto backend = getCurrentUIBackend();
if (backend)
{
return backend->waitKeyEx(delay);
}
}
return cvWaitKey(delay);
}
@@ -308,6 +558,16 @@ int cv::waitKey(int delay)
int cv::pollKey()
{
CV_TRACE_FUNCTION();
{
cv::AutoLock lock(cv::getWindowMutex());
auto backend = getCurrentUIBackend();
if (backend)
{
return backend->pollKey();
}
}
// fallback. please implement a proper polling function
return cvWaitKey(1);
}
@@ -318,6 +578,44 @@ int cv::createTrackbar(const String& trackbarName, const String& winName,
void* userdata)
{
CV_TRACE_FUNCTION();
CV_LOG_IF_WARNING(NULL, value, "UI/Trackbar(" << trackbarName << "@" << winName << "): Using 'value' pointer is unsafe and deprecated. Use NULL as value pointer. "
"To fetch trackbar value setup callback.");
{
cv::AutoLock lock(cv::getWindowMutex());
auto window = findWindow_(winName);
if (window)
{
if (value)
{
auto cb = std::make_shared<TrackbarCallbackWithData>(value, callback, userdata);
auto trackbar = window->createTrackbar(trackbarName, count, TrackbarCallbackWithData::onChangeCallback, cb.get());
if (!trackbar)
{
CV_LOG_ERROR(NULL, "OpenCV/UI: Can't create trackbar: '" << trackbarName << "'@'" << winName << "'");
return 0;
}
cb->trackbar_ = trackbar;
getTrackbarCallbacksWithData().emplace_back(cb);
getWindowsMap().emplace(trackbar->getID(), trackbar);
trackbar->setPos(*value);
return 1;
}
else
{
auto trackbar = window->createTrackbar(trackbarName, count, callback, userdata);
if (!trackbar)
{
CV_LOG_ERROR(NULL, "OpenCV/UI: Can't create trackbar: '" << trackbarName << "'@'" << winName << "'");
return 0;
}
getWindowsMap().emplace(trackbar->getID(), trackbar);
return 1;
}
}
}
return cvCreateTrackbar2(trackbarName.c_str(), winName.c_str(),
value, count, callback, userdata);
}
@@ -325,30 +623,92 @@ int cv::createTrackbar(const String& trackbarName, const String& winName,
void cv::setTrackbarPos( const String& trackbarName, const String& winName, int value )
{
CV_TRACE_FUNCTION();
{
cv::AutoLock lock(cv::getWindowMutex());
auto window = findWindow_(winName);
if (window)
{
auto trackbar = window->findTrackbar(trackbarName);
CV_Assert(trackbar);
return trackbar->setPos(value);
}
}
cvSetTrackbarPos(trackbarName.c_str(), winName.c_str(), value );
}
void cv::setTrackbarMax(const String& trackbarName, const String& winName, int maxval)
{
CV_TRACE_FUNCTION();
{
cv::AutoLock lock(cv::getWindowMutex());
auto window = findWindow_(winName);
if (window)
{
auto trackbar = window->findTrackbar(trackbarName);
CV_Assert(trackbar);
Range old_range = trackbar->getRange();
Range range(std::min(old_range.start, maxval), maxval);
return trackbar->setRange(range);
}
}
cvSetTrackbarMax(trackbarName.c_str(), winName.c_str(), maxval);
}
void cv::setTrackbarMin(const String& trackbarName, const String& winName, int minval)
{
CV_TRACE_FUNCTION();
{
cv::AutoLock lock(cv::getWindowMutex());
auto window = findWindow_(winName);
if (window)
{
auto trackbar = window->findTrackbar(trackbarName);
CV_Assert(trackbar);
Range old_range = trackbar->getRange();
Range range(minval, std::max(minval, old_range.end));
return trackbar->setRange(range);
}
}
cvSetTrackbarMin(trackbarName.c_str(), winName.c_str(), minval);
}
int cv::getTrackbarPos( const String& trackbarName, const String& winName )
{
CV_TRACE_FUNCTION();
{
cv::AutoLock lock(cv::getWindowMutex());
auto window = findWindow_(winName);
if (window)
{
auto trackbar = window->findTrackbar(trackbarName);
CV_Assert(trackbar);
return trackbar->getPos();
}
}
return cvGetTrackbarPos(trackbarName.c_str(), winName.c_str());
}
void cv::setMouseCallback( const String& windowName, MouseCallback onMouse, void* param)
{
CV_TRACE_FUNCTION();
{
cv::AutoLock lock(cv::getWindowMutex());
auto window = findWindow_(windowName);
if (window)
{
return window->setMouseCallback(onMouse, param);
}
}
cvSetMouseCallback(windowName.c_str(), onMouse, param);
}
@@ -403,6 +763,39 @@ namespace
void cv::imshow( const String& winname, InputArray _img )
{
CV_TRACE_FUNCTION();
{
cv::AutoLock lock(cv::getWindowMutex());
cleanupClosedWindows_();
auto& windowsMap = getWindowsMap();
auto i = windowsMap.find(winname);
if (i != windowsMap.end())
{
auto ui_base = i->second;
if (ui_base)
{
auto window = std::dynamic_pointer_cast<UIWindow>(ui_base);
if (!window)
{
CV_LOG_ERROR(NULL, "OpenCV/UI: invalid window name: '" << winname << "'");
}
return window->imshow(_img);
}
}
auto backend = getCurrentUIBackend();
if (backend)
{
auto window = backend->createWindow(winname, WINDOW_NORMAL);
if (!window)
{
CV_LOG_ERROR(NULL, "OpenCV/UI: Can't create window: '" << winname << "'");
return;
}
windowsMap.emplace(winname, window);
return window->imshow(_img);
}
}
const Size size = _img.size();
#ifndef HAVE_OPENGL
CV_Assert(size.width>0 && size.height>0);