mirror of https://github.com/opencv/opencv.git
parent
7d66f1e391
commit
70f69cb265
28 changed files with 2394 additions and 186 deletions
@ -0,0 +1,43 @@ |
||||
# --- GTK --- |
||||
ocv_clear_vars(HAVE_GTK HAVE_GTK3 HAVE_GTHREAD HAVE_GTKGLEXT) |
||||
if(WITH_GTK AND NOT HAVE_QT) |
||||
if(NOT WITH_GTK_2_X) |
||||
ocv_check_modules(GTK3 gtk+-3.0) |
||||
if(HAVE_GTK3) |
||||
ocv_add_external_target(gtk3 "${GTK3_INCLUDE_DIRS}" "${GTK3_LIBRARIES}" "HAVE_GTK3;HAVE_GTK") |
||||
set(HAVE_GTK TRUE) |
||||
set(GTK3_VERSION "${GTK3_VERSION}" PARENT_SCOPE) # informational |
||||
endif() |
||||
endif() |
||||
if(TRUE) |
||||
ocv_check_modules(GTK2 gtk+-2.0) |
||||
if(HAVE_GTK2) |
||||
set(MIN_VER_GTK "2.18.0") |
||||
if(GTK2_VERSION VERSION_LESS MIN_VER_GTK) |
||||
message(FATAL_ERROR "GTK support requires a minimum version of ${MIN_VER_GTK} (${GTK2_VERSION} found)") |
||||
else() |
||||
ocv_add_external_target(gtk2 "${GTK2_INCLUDE_DIRS}" "${GTK2_LIBRARIES}" "HAVE_GTK2;HAVE_GTK") |
||||
set(HAVE_GTK TRUE) |
||||
set(GTK2_VERSION "${GTK2_VERSION}" PARENT_SCOPE) # informational |
||||
endif() |
||||
endif() |
||||
endif() |
||||
ocv_check_modules(GTHREAD gthread-2.0) |
||||
if(HAVE_GTK AND NOT HAVE_GTHREAD) |
||||
message(FATAL_ERROR "gthread not found. This library is required when building with GTK support") |
||||
else() |
||||
ocv_add_external_target(gthread "${GTHREAD_INCLUDE_DIRS}" "${GTHREAD_LIBRARIES}" "HAVE_GTHREAD") |
||||
set(HAVE_GTHREAD "${HAVE_GTHREAD}" PARENT_SCOPE) # informational |
||||
set(GTHREAD_VERSION "${GTHREAD_VERSION}" PARENT_SCOPE) # informational |
||||
endif() |
||||
if(WITH_OPENGL AND NOT HAVE_GTK3) |
||||
ocv_check_modules(GTKGLEXT gtkglext-1.0) |
||||
if(HAVE_GTKGLEXT) |
||||
ocv_add_external_target(gtkglext "${GTKGLEXT_INCLUDE_DIRS}" "${GTKGLEXT_LIBRARIES}" "HAVE_GTKGLEXT") |
||||
set(HAVE_GTKGLEXT "${HAVE_GTKGLEXT}" PARENT_SCOPE) # informational |
||||
set(GTKGLEXT_VERSION "${GTKGLEXT_VERSION}" PARENT_SCOPE) # informational |
||||
endif() |
||||
endif() |
||||
endif() |
||||
|
||||
set(HAVE_GTK ${HAVE_GTK} PARENT_SCOPE) |
@ -0,0 +1,25 @@ |
||||
include(FindPkgConfig) |
||||
|
||||
# FIXIT: stop using PARENT_SCOPE in dependencies |
||||
if(PROJECT_NAME STREQUAL "OpenCV") |
||||
macro(add_backend backend_id cond_var) |
||||
if(${cond_var}) |
||||
include("${CMAKE_CURRENT_LIST_DIR}/detect_${backend_id}.cmake") |
||||
endif() |
||||
endmacro() |
||||
else() |
||||
function(add_backend backend_id cond_var) |
||||
if(${cond_var}) |
||||
include("${CMAKE_CURRENT_LIST_DIR}/detect_${backend_id}.cmake") |
||||
endif() |
||||
endfunction() |
||||
endif() |
||||
|
||||
add_backend("gtk" WITH_GTK) |
||||
|
||||
# TODO win32 |
||||
# TODO cocoa |
||||
# TODO qt |
||||
# TODO opengl |
||||
|
||||
# FIXIT: move content of cmake/OpenCVFindLibsGUI.cmake here (need to resolve CMake scope issues) |
@ -0,0 +1,61 @@ |
||||
function(ocv_create_builtin_highgui_plugin name target) |
||||
|
||||
ocv_debug_message("ocv_create_builtin_highgui_plugin(${ARGV})") |
||||
|
||||
if(NOT TARGET ${target}) |
||||
message(FATAL_ERROR "${target} does not exist!") |
||||
endif() |
||||
if(NOT OpenCV_SOURCE_DIR) |
||||
message(FATAL_ERROR "OpenCV_SOURCE_DIR must be set to build the plugin!") |
||||
endif() |
||||
|
||||
message(STATUS "HighGUI: add builtin plugin '${name}'") |
||||
|
||||
foreach(src ${ARGN}) |
||||
list(APPEND sources "${CMAKE_CURRENT_LIST_DIR}/src/${src}") |
||||
endforeach() |
||||
|
||||
add_library(${name} MODULE ${sources}) |
||||
target_include_directories(${name} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") |
||||
target_compile_definitions(${name} PRIVATE BUILD_PLUGIN) |
||||
target_link_libraries(${name} PRIVATE ${target}) |
||||
|
||||
foreach(mod opencv_highgui |
||||
opencv_core |
||||
opencv_imgproc |
||||
opencv_imgcodecs |
||||
opencv_videoio # TODO remove this dependency |
||||
) |
||||
ocv_target_link_libraries(${name} LINK_PRIVATE ${mod}) |
||||
ocv_target_include_directories(${name} "${OPENCV_MODULE_${mod}_LOCATION}/include") |
||||
endforeach() |
||||
|
||||
if(WIN32) |
||||
set(OPENCV_PLUGIN_VERSION "${OPENCV_DLLVERSION}" CACHE STRING "") |
||||
if(CMAKE_CXX_SIZEOF_DATA_PTR EQUAL 8) |
||||
set(OPENCV_PLUGIN_ARCH "_64" CACHE STRING "") |
||||
else() |
||||
set(OPENCV_PLUGIN_ARCH "" CACHE STRING "") |
||||
endif() |
||||
else() |
||||
set(OPENCV_PLUGIN_VERSION "" CACHE STRING "") |
||||
set(OPENCV_PLUGIN_ARCH "" CACHE STRING "") |
||||
endif() |
||||
|
||||
set_target_properties(${name} PROPERTIES |
||||
CXX_STANDARD 11 |
||||
CXX_VISIBILITY_PRESET hidden |
||||
DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" |
||||
OUTPUT_NAME "${name}${OPENCV_PLUGIN_VERSION}${OPENCV_PLUGIN_ARCH}" |
||||
) |
||||
|
||||
if(WIN32) |
||||
set_target_properties(${name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) |
||||
install(TARGETS ${name} OPTIONAL LIBRARY DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT plugins) |
||||
else() |
||||
install(TARGETS ${name} OPTIONAL LIBRARY DESTINATION ${OPENCV_LIB_INSTALL_PATH} COMPONENT plugins) |
||||
endif() |
||||
|
||||
add_dependencies(opencv_highgui_plugins ${name}) |
||||
|
||||
endfunction() |
@ -0,0 +1,69 @@ |
||||
#!/bin/bash |
||||
|
||||
set -e |
||||
|
||||
if [ -z $1 ] ; then |
||||
echo "$0 <destination directory>" |
||||
exit 1 |
||||
fi |
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" |
||||
OCV="$( cd "${DIR}/../../../.." >/dev/null 2>&1 && pwd )" |
||||
mkdir -p "${1}" # Docker creates non-existed mounts with 'root' owner, lets ensure that dir exists under the current user to avoid "Permission denied" problem |
||||
DST="$( cd "$1" >/dev/null 2>&1 && pwd )" |
||||
CFG=$2 |
||||
|
||||
do_build() |
||||
{ |
||||
TAG=$1 |
||||
D=$2 |
||||
F=$3 |
||||
shift 3 |
||||
docker build \ |
||||
--build-arg http_proxy \ |
||||
--build-arg https_proxy \ |
||||
$@ \ |
||||
-t $TAG \ |
||||
-f "${D}/${F}" \ |
||||
"${D}" |
||||
} |
||||
|
||||
do_run() |
||||
{ |
||||
TAG=$1 |
||||
shift 1 |
||||
docker run \ |
||||
-it \ |
||||
--rm \ |
||||
-v "${OCV}":/opencv:ro \ |
||||
-v "${DST}":/dst \ |
||||
-e CFG=$CFG \ |
||||
--user $(id -u):$(id -g) \ |
||||
$TAG \ |
||||
$@ |
||||
} |
||||
|
||||
build_gtk2_ubuntu() |
||||
{ |
||||
VER=$1 |
||||
TAG=opencv_highgui_ubuntu_gtk2_builder:${VER} |
||||
do_build $TAG "${DIR}/plugin_gtk" Dockerfile-ubuntu-gtk2 --build-arg VER=${VER} |
||||
do_run $TAG /opencv/modules/highgui/misc/plugins/plugin_gtk/build.sh /dst gtk2_ubuntu${VER} ${CFG} |
||||
|
||||
} |
||||
|
||||
build_gtk3_ubuntu() |
||||
{ |
||||
VER=$1 |
||||
TAG=opencv_highgui_ubuntu_gtk3_builder:${VER} |
||||
do_build $TAG "${DIR}/plugin_gtk" Dockerfile-ubuntu-gtk3 --build-arg VER=${VER} |
||||
do_run $TAG /opencv/modules/highgui/misc/plugins/plugin_gtk/build.sh /dst gtk3_ubuntu${VER} ${CFG} |
||||
} |
||||
|
||||
echo "OpenCV: ${OCV}" |
||||
echo "Destination: ${DST}" |
||||
|
||||
build_gtk2_ubuntu 16.04 |
||||
build_gtk2_ubuntu 18.04 |
||||
build_gtk3_ubuntu 18.04 |
||||
build_gtk3_ubuntu 20.04 |
@ -0,0 +1,44 @@ |
||||
cmake_minimum_required(VERSION 3.5) |
||||
project(opencv_highgui_gtk) |
||||
|
||||
get_filename_component(OpenCV_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../../.." ABSOLUTE) |
||||
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVPluginStandalone.cmake") |
||||
|
||||
# scan dependencies |
||||
set(WITH_GTK ON) |
||||
include("${OpenCV_SOURCE_DIR}/modules/highgui/cmake/init.cmake") |
||||
|
||||
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-deprecated-declarations) |
||||
|
||||
set(OPENCV_PLUGIN_DEPS core imgproc imgcodecs) |
||||
if(TARGET ocv.3rdparty.gtk3) |
||||
set(__deps ocv.3rdparty.gtk3) |
||||
elseif(TARGET ocv.3rdparty.gtk2) |
||||
set(__deps ocv.3rdparty.gtk2) |
||||
elseif(TARGET ocv.3rdparty.gtk) |
||||
set(__deps ocv.3rdparty.gtk) |
||||
else() |
||||
message(FATAL_ERROR "Missing dependency target for GTK libraries") |
||||
endif() |
||||
ocv_create_plugin(highgui "opencv_highgui_gtk" "${__deps}" "GTK" "src/window_gtk.cpp") |
||||
|
||||
message(STATUS "GTK: ${GTK2_VERSION}") |
||||
if(HAVE_GTK3) |
||||
message(STATUS "GTK+: ver ${GTK3_VERSION}") |
||||
elseif(HAVE_GTK) |
||||
message(STATUS "GTK+: ver ${GTK2_VERSION}") |
||||
else() |
||||
message(FATAL_ERROR "GTK+: NO") |
||||
endif() |
||||
if(HAVE_GTK) |
||||
if(HAVE_GTHREAD) |
||||
message(STATUS "GThread : YES (ver ${GTHREAD_VERSION})") |
||||
else() |
||||
message(STATUS "GThread : NO") |
||||
endif() |
||||
if(HAVE_GTKGLEXT) |
||||
message(STATUS "GtkGlExt: YES (ver ${GTKGLEXT_VERSION})") |
||||
else() |
||||
message(STATUS "GtkGlExt: NO") |
||||
endif() |
||||
endif() |
@ -0,0 +1,21 @@ |
||||
ARG VER |
||||
FROM ubuntu:$VER |
||||
|
||||
RUN \ |
||||
apt-get update && \ |
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ |
||||
pkg-config \ |
||||
cmake \ |
||||
g++ \ |
||||
ninja-build \ |
||||
&& \ |
||||
rm -rf /var/lib/apt/lists/* |
||||
|
||||
RUN \ |
||||
apt-get update && \ |
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ |
||||
libgtk2.0-dev \ |
||||
&& \ |
||||
rm -rf /var/lib/apt/lists/* |
||||
|
||||
WORKDIR /tmp |
@ -0,0 +1,21 @@ |
||||
ARG VER |
||||
FROM ubuntu:$VER |
||||
|
||||
RUN \ |
||||
apt-get update && \ |
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ |
||||
pkg-config \ |
||||
cmake \ |
||||
g++ \ |
||||
ninja-build \ |
||||
&& \ |
||||
rm -rf /var/lib/apt/lists/* |
||||
|
||||
RUN \ |
||||
apt-get update && \ |
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ |
||||
libgtk-3-dev \ |
||||
&& \ |
||||
rm -rf /var/lib/apt/lists/* |
||||
|
||||
WORKDIR /tmp |
@ -0,0 +1,13 @@ |
||||
#!/bin/bash |
||||
|
||||
set -e |
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" |
||||
|
||||
cmake -GNinja \ |
||||
-DOPENCV_PLUGIN_NAME=opencv_highgui_$2 \ |
||||
-DOPENCV_PLUGIN_DESTINATION=$1 \ |
||||
-DCMAKE_BUILD_TYPE=$3 \ |
||||
$DIR |
||||
|
||||
ninja -v |
@ -0,0 +1,181 @@ |
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
#include "precomp.hpp" |
||||
#include "backend.hpp" |
||||
|
||||
#include <opencv2/core/utils/configuration.private.hpp> |
||||
#include <opencv2/core/utils/logger.defines.hpp> |
||||
#ifdef NDEBUG |
||||
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_DEBUG + 1 |
||||
#else |
||||
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_VERBOSE + 1 |
||||
#endif |
||||
#include <opencv2/core/utils/logger.hpp> |
||||
|
||||
|
||||
#include "registry.hpp" |
||||
#include "registry.impl.hpp" |
||||
|
||||
#include "plugin_api.hpp" |
||||
#include "plugin_wrapper.impl.hpp" |
||||
|
||||
|
||||
namespace cv { namespace highgui_backend { |
||||
|
||||
UIBackend::~UIBackend() |
||||
{ |
||||
// nothing
|
||||
} |
||||
|
||||
UIWindowBase::~UIWindowBase() |
||||
{ |
||||
// nothing
|
||||
} |
||||
|
||||
UIWindow::~UIWindow() |
||||
{ |
||||
// nothing
|
||||
} |
||||
|
||||
UITrackbar::~UITrackbar() |
||||
{ |
||||
// nothing
|
||||
} |
||||
|
||||
static |
||||
std::string& getUIBackendName() |
||||
{ |
||||
static std::string g_backendName = toUpperCase(cv::utils::getConfigurationParameterString("OPENCV_UI_BACKEND", "")); |
||||
return g_backendName; |
||||
} |
||||
|
||||
static bool g_initializedUIBackend = false; |
||||
|
||||
static |
||||
std::shared_ptr<UIBackend> createUIBackend() |
||||
{ |
||||
const std::string& name = getUIBackendName(); |
||||
bool isKnown = false; |
||||
const auto& backends = getBackendsInfo(); |
||||
if (!name.empty()) |
||||
{ |
||||
CV_LOG_INFO(NULL, "UI: requested backend name: " << name); |
||||
} |
||||
for (size_t i = 0; i < backends.size(); i++) |
||||
{ |
||||
const auto& info = backends[i]; |
||||
if (!name.empty()) |
||||
{ |
||||
if (name != info.name) |
||||
{ |
||||
continue; |
||||
} |
||||
isKnown = true; |
||||
} |
||||
try |
||||
{ |
||||
CV_LOG_DEBUG(NULL, "UI: trying backend: " << info.name << " (priority=" << info.priority << ")"); |
||||
if (!info.backendFactory) |
||||
{ |
||||
CV_LOG_DEBUG(NULL, "UI: factory is not available (plugins require filesystem support): " << info.name); |
||||
continue; |
||||
} |
||||
std::shared_ptr<UIBackend> backend = info.backendFactory->create(); |
||||
if (!backend) |
||||
{ |
||||
CV_LOG_VERBOSE(NULL, 0, "UI: not available: " << info.name); |
||||
continue; |
||||
} |
||||
CV_LOG_INFO(NULL, "UI: using backend: " << info.name << " (priority=" << info.priority << ")"); |
||||
g_initializedUIBackend = true; |
||||
getUIBackendName() = info.name; |
||||
return backend; |
||||
} |
||||
catch (const std::exception& e) |
||||
{ |
||||
CV_LOG_WARNING(NULL, "UI: can't initialize " << info.name << " backend: " << e.what()); |
||||
} |
||||
catch (...) |
||||
{ |
||||
CV_LOG_WARNING(NULL, "UI: can't initialize " << info.name << " backend: Unknown C++ exception"); |
||||
} |
||||
} |
||||
if (name.empty()) |
||||
{ |
||||
CV_LOG_DEBUG(NULL, "UI: fallback on builtin code"); |
||||
} |
||||
else |
||||
{ |
||||
if (!isKnown) |
||||
CV_LOG_INFO(NULL, "UI: unknown backend: " << name); |
||||
} |
||||
g_initializedUIBackend = true; |
||||
return std::shared_ptr<UIBackend>(); |
||||
} |
||||
|
||||
static inline |
||||
std::shared_ptr<UIBackend> createDefaultUIBackend() |
||||
{ |
||||
CV_LOG_DEBUG(NULL, "UI: Initializing backend..."); |
||||
return createUIBackend(); |
||||
} |
||||
|
||||
std::shared_ptr<UIBackend>& getCurrentUIBackend() |
||||
{ |
||||
static std::shared_ptr<UIBackend> g_currentUIBackend = createDefaultUIBackend(); |
||||
return g_currentUIBackend; |
||||
} |
||||
|
||||
void setUIBackend(const std::shared_ptr<UIBackend>& api) |
||||
{ |
||||
getCurrentUIBackend() = api; |
||||
} |
||||
|
||||
bool setUIBackend(const std::string& backendName) |
||||
{ |
||||
CV_TRACE_FUNCTION(); |
||||
|
||||
std::string backendName_u = toUpperCase(backendName); |
||||
if (g_initializedUIBackend) |
||||
{ |
||||
// ... already initialized
|
||||
if (getUIBackendName() == backendName_u) |
||||
{ |
||||
CV_LOG_INFO(NULL, "UI: backend is already activated: " << (backendName.empty() ? "builtin(legacy)" : backendName)); |
||||
return true; |
||||
} |
||||
else |
||||
{ |
||||
// ... re-create new
|
||||
CV_LOG_DEBUG(NULL, "UI: replacing backend..."); |
||||
getUIBackendName() = backendName_u; |
||||
getCurrentUIBackend() = createUIBackend(); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
// ... no backend exists, just specify the name (initialization is triggered by getCurrentUIBackend() call)
|
||||
getUIBackendName() = backendName_u; |
||||
} |
||||
std::shared_ptr<UIBackend> api = getCurrentUIBackend(); |
||||
if (!api) |
||||
{ |
||||
if (!backendName.empty()) |
||||
{ |
||||
CV_LOG_WARNING(NULL, "UI: backend is not available: " << backendName << " (using builtin legacy code)"); |
||||
return false; |
||||
} |
||||
else |
||||
{ |
||||
CV_LOG_WARNING(NULL, "UI: switched to builtin code (legacy)"); |
||||
} |
||||
} |
||||
if (!backendName_u.empty()) |
||||
{ |
||||
CV_Assert(backendName_u == getUIBackendName()); // data race?
|
||||
} |
||||
return true; |
||||
} |
||||
|
||||
}} // namespace cv::highgui_backend
|
@ -0,0 +1,131 @@ |
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
#ifndef OPENCV_HIGHGUI_BACKEND_HPP |
||||
#define OPENCV_HIGHGUI_BACKEND_HPP |
||||
|
||||
#include <memory> |
||||
#include <map> |
||||
|
||||
namespace cv { namespace highgui_backend { |
||||
|
||||
class CV_EXPORTS UIWindowBase |
||||
{ |
||||
public: |
||||
typedef std::shared_ptr<UIWindowBase> Ptr; |
||||
typedef std::weak_ptr<UIWindowBase> WeakPtr; |
||||
|
||||
virtual ~UIWindowBase(); |
||||
|
||||
virtual const std::string& getID() const = 0; // internal name, used for logging
|
||||
|
||||
virtual bool isActive() const = 0; |
||||
|
||||
virtual void destroy() = 0; |
||||
}; // UIWindowBase
|
||||
|
||||
class UITrackbar; |
||||
|
||||
class CV_EXPORTS UIWindow : public UIWindowBase |
||||
{ |
||||
public: |
||||
virtual ~UIWindow(); |
||||
|
||||
virtual void imshow(InputArray image) = 0; |
||||
|
||||
virtual double getProperty(int prop) const = 0; |
||||
virtual bool setProperty(int prop, double value) = 0; |
||||
|
||||
virtual void resize(int width, int height) = 0; |
||||
virtual void move(int x, int y) = 0; |
||||
|
||||
virtual Rect getImageRect() const = 0; |
||||
|
||||
virtual void setTitle(const std::string& title) = 0; |
||||
|
||||
virtual void setMouseCallback(MouseCallback onMouse, void* userdata /*= 0*/) = 0; |
||||
|
||||
//TODO: handle both keys and mouse events (both with mouse coordinates)
|
||||
//virtual void setInputCallback(InputCallback onInputEvent, void* userdata /*= 0*/) = 0;
|
||||
|
||||
virtual std::shared_ptr<UITrackbar> createTrackbar( |
||||
const std::string& name, |
||||
int count, |
||||
TrackbarCallback onChange /*= 0*/, |
||||
void* userdata /*= 0*/ |
||||
) = 0; |
||||
|
||||
virtual std::shared_ptr<UITrackbar> findTrackbar(const std::string& name) = 0; |
||||
|
||||
#if 0 // QT only
|
||||
virtual void displayOverlay(const std::string& text, int delayms = 0) = 0; |
||||
virtual void displayStatusBar(const std::string& text, int delayms /*= 0*/) = 0; |
||||
virtual int createButton( |
||||
const std::string& bar_name, ButtonCallback on_change, |
||||
void* userdata = 0, int type /*= QT_PUSH_BUTTON*/, |
||||
bool initial_button_state /*= false*/ |
||||
) = 0; |
||||
// addText, QtFont stuff
|
||||
#endif |
||||
|
||||
#if 0 // OpenGL
|
||||
virtual void imshow(const ogl::Texture2D& tex) = 0; |
||||
virtual void setOpenGlDrawCallback(OpenGlDrawCallback onOpenGlDraw, void* userdata = 0) = 0; |
||||
virtual void setOpenGlContext() = 0; |
||||
virtual void updateWindow() = 0; |
||||
#endif |
||||
|
||||
}; // UIWindow
|
||||
|
||||
|
||||
class CV_EXPORTS UITrackbar : public UIWindowBase |
||||
{ |
||||
public: |
||||
virtual ~UITrackbar(); |
||||
|
||||
virtual int getPos() const = 0; |
||||
virtual void setPos(int pos) = 0; |
||||
|
||||
virtual cv::Range getRange() const = 0; |
||||
virtual void setRange(const cv::Range& range) = 0; |
||||
}; // UITrackbar
|
||||
|
||||
|
||||
class CV_EXPORTS UIBackend |
||||
{ |
||||
public: |
||||
virtual ~UIBackend(); |
||||
|
||||
virtual void destroyAllWindows() = 0; |
||||
|
||||
// namedWindow
|
||||
virtual std::shared_ptr<UIWindow> createWindow( |
||||
const std::string& winname, |
||||
int flags |
||||
) = 0; |
||||
|
||||
virtual int waitKeyEx(int delay /*= 0*/) = 0; |
||||
virtual int pollKey() = 0; |
||||
}; |
||||
|
||||
std::shared_ptr<UIBackend>& getCurrentUIBackend(); |
||||
void setUIBackend(const std::shared_ptr<UIBackend>& api); |
||||
bool setUIBackend(const std::string& backendName); |
||||
|
||||
#ifndef BUILD_PLUGIN |
||||
|
||||
#ifdef HAVE_GTK |
||||
std::shared_ptr<UIBackend> createUIBackendGTK(); |
||||
#endif |
||||
|
||||
#if 0 // TODO: defined HAVE_QT
|
||||
std::shared_ptr<UIBackend> createUIBackendQT(); |
||||
#endif |
||||
|
||||
#endif // BUILD_PLUGIN
|
||||
|
||||
} // namespace highgui_backend
|
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_HIGHGUI_BACKEND_HPP
|
@ -0,0 +1,48 @@ |
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef OPENCV_UI_FACTORY_HPP |
||||
#define OPENCV_UI_FACTORY_HPP |
||||
|
||||
#include "backend.hpp" |
||||
|
||||
namespace cv { namespace highgui_backend { |
||||
|
||||
class IUIBackendFactory |
||||
{ |
||||
public: |
||||
virtual ~IUIBackendFactory() {} |
||||
virtual std::shared_ptr<cv::highgui_backend::UIBackend> create() const = 0; |
||||
}; |
||||
|
||||
|
||||
class StaticBackendFactory CV_FINAL: public IUIBackendFactory |
||||
{ |
||||
protected: |
||||
std::function<std::shared_ptr<cv::highgui_backend::UIBackend>(void)> create_fn_; |
||||
|
||||
public: |
||||
StaticBackendFactory(std::function<std::shared_ptr<cv::highgui_backend::UIBackend>(void)>&& create_fn) |
||||
: create_fn_(create_fn) |
||||
{ |
||||
// nothing
|
||||
} |
||||
|
||||
~StaticBackendFactory() CV_OVERRIDE {} |
||||
|
||||
std::shared_ptr<cv::highgui_backend::UIBackend> create() const CV_OVERRIDE |
||||
{ |
||||
return create_fn_(); |
||||
} |
||||
}; |
||||
|
||||
//
|
||||
// PluginUIBackendFactory is implemented in plugin_wrapper
|
||||
//
|
||||
|
||||
std::shared_ptr<IUIBackendFactory> createPluginUIBackendFactory(const std::string& baseName); |
||||
|
||||
}} // namespace
|
||||
|
||||
#endif // OPENCV_UI_FACTORY_HPP
|
@ -0,0 +1,72 @@ |
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef UI_PLUGIN_API_HPP |
||||
#define UI_PLUGIN_API_HPP |
||||
|
||||
#include <opencv2/core/cvdef.h> |
||||
#include <opencv2/core/llapi/llapi.h> |
||||
|
||||
#include "backend.hpp" |
||||
|
||||
#if !defined(BUILD_PLUGIN) |
||||
|
||||
/// increased for backward-compatible changes, e.g. add new function
|
||||
/// Caller API <= Plugin API -> plugin is fully compatible
|
||||
/// Caller API > Plugin API -> plugin is not fully compatible, caller should use extra checks to use plugins with older API
|
||||
#define API_VERSION 0 // preview
|
||||
|
||||
/// increased for incompatible changes, e.g. remove function argument
|
||||
/// Caller ABI == Plugin ABI -> plugin is compatible
|
||||
/// Caller ABI > Plugin ABI -> plugin is not compatible, caller should use shim code to use old ABI plugins (caller may know how lower ABI works, so it is possible)
|
||||
/// Caller ABI < Plugin ABI -> plugin can't be used (plugin should provide interface with lower ABI to handle that)
|
||||
#define ABI_VERSION 0 // preview
|
||||
|
||||
#else // !defined(BUILD_PLUGIN)
|
||||
|
||||
#if !defined(ABI_VERSION) || !defined(API_VERSION) |
||||
#error "Plugin must define ABI_VERSION and API_VERSION before including plugin_api.hpp" |
||||
#endif |
||||
|
||||
#endif // !defined(BUILD_PLUGIN)
|
||||
|
||||
typedef cv::highgui_backend::UIBackend* CvPluginUIBackend; |
||||
|
||||
struct OpenCV_UI_Plugin_API_v0_0_api_entries |
||||
{ |
||||
/** @brief Get backend API instance
|
||||
|
||||
@param[out] handle pointer on backend API handle |
||||
|
||||
@note API-CALL 1, API-Version == 0 |
||||
*/ |
||||
CvResult (CV_API_CALL *getInstance)(CV_OUT CvPluginUIBackend* handle) CV_NOEXCEPT; |
||||
}; // OpenCV_UI_Plugin_API_v0_0_api_entries
|
||||
|
||||
typedef struct OpenCV_UI_Plugin_API_v0 |
||||
{ |
||||
OpenCV_API_Header api_header; |
||||
struct OpenCV_UI_Plugin_API_v0_0_api_entries v0; |
||||
} OpenCV_UI_Plugin_API_v0; |
||||
|
||||
#if ABI_VERSION == 0 && API_VERSION == 0 |
||||
typedef OpenCV_UI_Plugin_API_v0 OpenCV_UI_Plugin_API; |
||||
#else |
||||
#error "Not supported configuration: check ABI_VERSION/API_VERSION" |
||||
#endif |
||||
|
||||
#ifdef BUILD_PLUGIN |
||||
extern "C" { |
||||
|
||||
CV_PLUGIN_EXPORTS |
||||
const OpenCV_UI_Plugin_API* CV_API_CALL opencv_ui_plugin_init_v0 |
||||
(int requested_abi_version, int requested_api_version, void* reserved /*NULL*/) CV_NOEXCEPT; |
||||
|
||||
} // extern "C"
|
||||
#else // BUILD_PLUGIN
|
||||
typedef const OpenCV_UI_Plugin_API* (CV_API_CALL *FN_opencv_ui_plugin_init_t) |
||||
(int requested_abi_version, int requested_api_version, void* reserved /*NULL*/); |
||||
#endif // BUILD_PLUGIN
|
||||
|
||||
#endif // UI_PLUGIN_API_HPP
|
@ -0,0 +1,283 @@ |
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
//
|
||||
// Not a standalone header, part of backend.cpp
|
||||
//
|
||||
|
||||
//==================================================================================================
|
||||
// Dynamic backend implementation
|
||||
|
||||
#include "opencv2/core/utils/plugin_loader.private.hpp" |
||||
|
||||
namespace cv { namespace impl { |
||||
|
||||
using namespace cv::highgui_backend; |
||||
|
||||
#if OPENCV_HAVE_FILESYSTEM_SUPPORT && defined(ENABLE_PLUGINS) |
||||
|
||||
using namespace cv::plugin::impl; // plugin_loader.hpp
|
||||
|
||||
class PluginUIBackend CV_FINAL: public std::enable_shared_from_this<PluginUIBackend> |
||||
{ |
||||
protected: |
||||
void initPluginAPI() |
||||
{ |
||||
const char* init_name = "opencv_ui_plugin_init_v0"; |
||||
FN_opencv_ui_plugin_init_t fn_init = reinterpret_cast<FN_opencv_ui_plugin_init_t>(lib_->getSymbol(init_name)); |
||||
if (fn_init) |
||||
{ |
||||
CV_LOG_DEBUG(NULL, "Found entry: '" << init_name << "'"); |
||||
for (int supported_api_version = API_VERSION; supported_api_version >= 0; supported_api_version--) |
||||
{ |
||||
plugin_api_ = fn_init(ABI_VERSION, supported_api_version, NULL); |
||||
if (plugin_api_) |
||||
break; |
||||
} |
||||
if (!plugin_api_) |
||||
{ |
||||
CV_LOG_INFO(NULL, "UI: plugin is incompatible (can't be initialized): " << lib_->getName()); |
||||
return; |
||||
} |
||||
if (!checkCompatibility(plugin_api_->api_header, ABI_VERSION, API_VERSION, false)) |
||||
{ |
||||
plugin_api_ = NULL; |
||||
return; |
||||
} |
||||
CV_LOG_INFO(NULL, "UI: plugin is ready to use '" << plugin_api_->api_header.api_description << "'"); |
||||
} |
||||
else |
||||
{ |
||||
CV_LOG_INFO(NULL, "UI: plugin is incompatible, missing init function: '" << init_name << "', file: " << lib_->getName()); |
||||
} |
||||
} |
||||
|
||||
|
||||
bool checkCompatibility(const OpenCV_API_Header& api_header, unsigned int abi_version, unsigned int api_version, bool checkMinorOpenCVVersion) |
||||
{ |
||||
if (api_header.opencv_version_major != CV_VERSION_MAJOR) |
||||
{ |
||||
CV_LOG_ERROR(NULL, "UI: wrong OpenCV major version used by plugin '" << api_header.api_description << "': " << |
||||
cv::format("%d.%d, OpenCV version is '" CV_VERSION "'", api_header.opencv_version_major, api_header.opencv_version_minor)) |
||||
return false; |
||||
} |
||||
if (!checkMinorOpenCVVersion) |
||||
{ |
||||
// no checks for OpenCV minor version
|
||||
} |
||||
else if (api_header.opencv_version_minor != CV_VERSION_MINOR) |
||||
{ |
||||
CV_LOG_ERROR(NULL, "UI: wrong OpenCV minor version used by plugin '" << api_header.api_description << "': " << |
||||
cv::format("%d.%d, OpenCV version is '" CV_VERSION "'", api_header.opencv_version_major, api_header.opencv_version_minor)) |
||||
return false; |
||||
} |
||||
CV_LOG_DEBUG(NULL, "UI: initialized '" << api_header.api_description << "': built with " |
||||
<< cv::format("OpenCV %d.%d (ABI/API = %d/%d)", |
||||
api_header.opencv_version_major, api_header.opencv_version_minor, |
||||
api_header.min_api_version, api_header.api_version) |
||||
<< ", current OpenCV version is '" CV_VERSION "' (ABI/API = " << abi_version << "/" << api_version << ")" |
||||
); |
||||
if (api_header.min_api_version != abi_version) // future: range can be here
|
||||
{ |
||||
// actually this should never happen due to checks in plugin's init() function
|
||||
CV_LOG_ERROR(NULL, "UI: plugin is not supported due to incompatible ABI = " << api_header.min_api_version); |
||||
return false; |
||||
} |
||||
if (api_header.api_version != api_version) |
||||
{ |
||||
CV_LOG_INFO(NULL, "UI: NOTE: plugin is supported, but there is API version mismath: " |
||||
<< cv::format("plugin API level (%d) != OpenCV API level (%d)", api_header.api_version, api_version)); |
||||
if (api_header.api_version < api_version) |
||||
{ |
||||
CV_LOG_INFO(NULL, "UI: NOTE: some functionality may be unavailable due to lack of support by plugin implementation"); |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
public: |
||||
std::shared_ptr<cv::plugin::impl::DynamicLib> lib_; |
||||
const OpenCV_UI_Plugin_API* plugin_api_; |
||||
|
||||
PluginUIBackend(const std::shared_ptr<cv::plugin::impl::DynamicLib>& lib) |
||||
: lib_(lib) |
||||
, plugin_api_(NULL) |
||||
{ |
||||
initPluginAPI(); |
||||
} |
||||
|
||||
std::shared_ptr<cv::highgui_backend::UIBackend> create() const |
||||
{ |
||||
CV_Assert(plugin_api_); |
||||
|
||||
CvPluginUIBackend instancePtr = NULL; |
||||
|
||||
if (plugin_api_->v0.getInstance) |
||||
{ |
||||
if (CV_ERROR_OK == plugin_api_->v0.getInstance(&instancePtr)) |
||||
{ |
||||
CV_Assert(instancePtr); |
||||
// TODO C++20 "aliasing constructor"
|
||||
return std::shared_ptr<cv::highgui_backend::UIBackend>(instancePtr, [](cv::highgui_backend::UIBackend*){}); // empty deleter
|
||||
} |
||||
} |
||||
return std::shared_ptr<cv::highgui_backend::UIBackend>(); |
||||
} |
||||
}; |
||||
|
||||
|
||||
class PluginUIBackendFactory CV_FINAL: public IUIBackendFactory |
||||
{ |
||||
public: |
||||
std::string baseName_; |
||||
std::shared_ptr<PluginUIBackend> backend; |
||||
bool initialized; |
||||
public: |
||||
PluginUIBackendFactory(const std::string& baseName) |
||||
: baseName_(baseName) |
||||
, initialized(false) |
||||
{ |
||||
// nothing, plugins are loaded on demand
|
||||
} |
||||
|
||||
std::shared_ptr<cv::highgui_backend::UIBackend> create() const CV_OVERRIDE |
||||
{ |
||||
if (!initialized) |
||||
{ |
||||
const_cast<PluginUIBackendFactory*>(this)->initBackend(); |
||||
} |
||||
if (backend) |
||||
return backend->create(); |
||||
return std::shared_ptr<cv::highgui_backend::UIBackend>(); |
||||
} |
||||
protected: |
||||
void initBackend() |
||||
{ |
||||
AutoLock lock(getInitializationMutex()); |
||||
try |
||||
{ |
||||
if (!initialized) |
||||
loadPlugin(); |
||||
} |
||||
catch (...) |
||||
{ |
||||
CV_LOG_INFO(NULL, "UI: exception during plugin loading: " << baseName_ << ". SKIP"); |
||||
} |
||||
initialized = true; |
||||
} |
||||
void loadPlugin(); |
||||
}; |
||||
|
||||
static |
||||
std::vector<FileSystemPath_t> getPluginCandidates(const std::string& baseName) |
||||
{ |
||||
using namespace cv::utils; |
||||
using namespace cv::utils::fs; |
||||
const std::string baseName_l = toLowerCase(baseName); |
||||
const std::string baseName_u = toUpperCase(baseName); |
||||
const FileSystemPath_t baseName_l_fs = toFileSystemPath(baseName_l); |
||||
std::vector<FileSystemPath_t> paths; |
||||
// TODO OPENCV_PLUGIN_PATH
|
||||
const std::vector<std::string> paths_ = getConfigurationParameterPaths("OPENCV_CORE_PLUGIN_PATH", std::vector<std::string>()); |
||||
if (paths_.size() != 0) |
||||
{ |
||||
for (size_t i = 0; i < paths_.size(); i++) |
||||
{ |
||||
paths.push_back(toFileSystemPath(paths_[i])); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
FileSystemPath_t binaryLocation; |
||||
if (getBinLocation(binaryLocation)) |
||||
{ |
||||
binaryLocation = getParent(binaryLocation); |
||||
#ifndef CV_UI_PLUGIN_SUBDIRECTORY |
||||
paths.push_back(binaryLocation); |
||||
#else |
||||
paths.push_back(binaryLocation + toFileSystemPath("/") + toFileSystemPath(CV_UI_PLUGIN_SUBDIRECTORY_STR)); |
||||
#endif |
||||
} |
||||
} |
||||
const std::string default_expr = libraryPrefix() + "opencv_highgui_" + baseName_l + "*" + librarySuffix(); |
||||
const std::string plugin_expr = getConfigurationParameterString((std::string("OPENCV_UI_PLUGIN_") + baseName_u).c_str(), default_expr.c_str()); |
||||
std::vector<FileSystemPath_t> results; |
||||
#ifdef _WIN32 |
||||
FileSystemPath_t moduleName = toFileSystemPath(libraryPrefix() + "opencv_highgui_" + baseName_l + librarySuffix()); |
||||
if (plugin_expr != default_expr) |
||||
{ |
||||
moduleName = toFileSystemPath(plugin_expr); |
||||
results.push_back(moduleName); |
||||
} |
||||
for (const FileSystemPath_t& path : paths) |
||||
{ |
||||
results.push_back(path + L"\\" + moduleName); |
||||
} |
||||
results.push_back(moduleName); |
||||
#else |
||||
CV_LOG_DEBUG(NULL, "UI: " << baseName << " plugin's glob is '" << plugin_expr << "', " << paths.size() << " location(s)"); |
||||
for (const std::string& path : paths) |
||||
{ |
||||
if (path.empty()) |
||||
continue; |
||||
std::vector<std::string> candidates; |
||||
cv::glob(utils::fs::join(path, plugin_expr), candidates); |
||||
CV_LOG_DEBUG(NULL, " - " << path << ": " << candidates.size()); |
||||
copy(candidates.begin(), candidates.end(), back_inserter(results)); |
||||
} |
||||
#endif |
||||
CV_LOG_DEBUG(NULL, "Found " << results.size() << " plugin(s) for " << baseName); |
||||
return results; |
||||
} |
||||
|
||||
void PluginUIBackendFactory::loadPlugin() |
||||
{ |
||||
for (const FileSystemPath_t& plugin : getPluginCandidates(baseName_)) |
||||
{ |
||||
auto lib = std::make_shared<cv::plugin::impl::DynamicLib>(plugin); |
||||
if (!lib->isLoaded()) |
||||
{ |
||||
continue; |
||||
} |
||||
try |
||||
{ |
||||
auto pluginBackend = std::make_shared<PluginUIBackend>(lib); |
||||
if (!pluginBackend) |
||||
{ |
||||
continue; |
||||
} |
||||
if (pluginBackend->plugin_api_ == NULL) |
||||
{ |
||||
CV_LOG_ERROR(NULL, "UI: no compatible plugin API for backend: " << baseName_ << " in " << toPrintablePath(plugin)); |
||||
continue; |
||||
} |
||||
// NB: we are going to use UI backend, so prevent automatic library unloading
|
||||
lib->disableAutomaticLibraryUnloading(); |
||||
backend = pluginBackend; |
||||
return; |
||||
} |
||||
catch (...) |
||||
{ |
||||
CV_LOG_WARNING(NULL, "UI: exception during plugin initialization: " << toPrintablePath(plugin) << ". SKIP"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
#endif // OPENCV_HAVE_FILESYSTEM_SUPPORT && defined(ENABLE_PLUGINS)
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace highgui_backend { |
||||
|
||||
std::shared_ptr<IUIBackendFactory> createPluginUIBackendFactory(const std::string& baseName) |
||||
{ |
||||
#if OPENCV_HAVE_FILESYSTEM_SUPPORT && defined(ENABLE_PLUGINS) |
||||
return std::make_shared<impl::PluginUIBackendFactory>(baseName); |
||||
#else |
||||
CV_UNUSED(baseName); |
||||
return std::shared_ptr<IUIBackendFactory>(); |
||||
#endif |
||||
} |
||||
|
||||
}} // namespace
|
@ -0,0 +1,25 @@ |
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef OPENCV_HIGHGUI_REGISTRY_HPP |
||||
#define OPENCV_HIGHGUI_REGISTRY_HPP |
||||
|
||||
#include "factory.hpp" |
||||
|
||||
namespace cv { namespace highgui_backend { |
||||
|
||||
struct BackendInfo |
||||
{ |
||||
int priority; // 1000-<index*10> - default builtin priority
|
||||
// 0 - disabled (OPENCV_UI_PRIORITY_<name> = 0)
|
||||
// >10000 - prioritized list (OPENCV_UI_PRIORITY_LIST)
|
||||
std::string name; |
||||
std::shared_ptr<IUIBackendFactory> backendFactory; |
||||
}; |
||||
|
||||
const std::vector<BackendInfo>& getBackendsInfo(); |
||||
|
||||
}} // namespace
|
||||
|
||||
#endif // OPENCV_HIGHGUI_REGISTRY_HPP
|
@ -0,0 +1,183 @@ |
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
//
|
||||
// Not a standalone header, part of backend.cpp
|
||||
//
|
||||
|
||||
#include "opencv2/core/utils/filesystem.private.hpp" // OPENCV_HAVE_FILESYSTEM_SUPPORT |
||||
|
||||
namespace cv { namespace highgui_backend { |
||||
|
||||
#if OPENCV_HAVE_FILESYSTEM_SUPPORT && defined(ENABLE_PLUGINS) |
||||
#define DECLARE_DYNAMIC_BACKEND(name) \ |
||||
BackendInfo { \
|
||||
1000, name, createPluginUIBackendFactory(name) \
|
||||
}, |
||||
#else |
||||
#define DECLARE_DYNAMIC_BACKEND(name) /* nothing */ |
||||
#endif |
||||
|
||||
#define DECLARE_STATIC_BACKEND(name, createBackendAPI) \ |
||||
BackendInfo { \
|
||||
1000, name, std::make_shared<cv::highgui_backend::StaticBackendFactory>([=] () -> std::shared_ptr<cv::highgui_backend::UIBackend> { return createBackendAPI(); }) \
|
||||
}, |
||||
|
||||
static |
||||
std::vector<BackendInfo>& getBuiltinBackendsInfo() |
||||
{ |
||||
static std::vector<BackendInfo> g_backends |
||||
{ |
||||
#ifdef HAVE_GTK |
||||
DECLARE_STATIC_BACKEND("GTK", createUIBackendGTK) |
||||
#if defined(HAVE_GTK3) |
||||
DECLARE_STATIC_BACKEND("GTK3", createUIBackendGTK) |
||||
#elif defined(HAVE_GTK2) |
||||
DECLARE_STATIC_BACKEND("GTK2", createUIBackendGTK) |
||||
#else |
||||
#warning "HAVE_GTK definition issue. Register new GTK backend" |
||||
#endif |
||||
#elif defined(ENABLE_PLUGINS) |
||||
DECLARE_DYNAMIC_BACKEND("GTK") |
||||
DECLARE_DYNAMIC_BACKEND("GTK3") |
||||
DECLARE_DYNAMIC_BACKEND("GTK2") |
||||
#endif |
||||
|
||||
#if 0 // TODO
|
||||
#ifdef HAVE_QT |
||||
DECLARE_STATIC_BACKEND("QT", createUIBackendQT) |
||||
#elif defined(ENABLE_PLUGINS) |
||||
DECLARE_DYNAMIC_BACKEND("QT") |
||||
#endif |
||||
#endif |
||||
}; |
||||
return g_backends; |
||||
}; |
||||
|
||||
static |
||||
bool sortByPriority(const BackendInfo &lhs, const BackendInfo &rhs) |
||||
{ |
||||
return lhs.priority > rhs.priority; |
||||
} |
||||
|
||||
/** @brief Manages list of enabled backends
|
||||
*/ |
||||
class UIBackendRegistry |
||||
{ |
||||
protected: |
||||
std::vector<BackendInfo> enabledBackends; |
||||
UIBackendRegistry() |
||||
{ |
||||
enabledBackends = getBuiltinBackendsInfo(); |
||||
int N = (int)enabledBackends.size(); |
||||
for (int i = 0; i < N; i++) |
||||
{ |
||||
BackendInfo& info = enabledBackends[i]; |
||||
info.priority = 1000 - i * 10; |
||||
} |
||||
CV_LOG_DEBUG(NULL, "UI: Builtin backends(" << N << "): " << dumpBackends()); |
||||
if (readPrioritySettings()) |
||||
{ |
||||
CV_LOG_INFO(NULL, "UI: Updated backends priorities: " << dumpBackends()); |
||||
N = (int)enabledBackends.size(); |
||||
} |
||||
int enabled = 0; |
||||
for (int i = 0; i < N; i++) |
||||
{ |
||||
BackendInfo& info = enabledBackends[enabled]; |
||||
if (enabled != i) |
||||
info = enabledBackends[i]; |
||||
size_t param_priority = utils::getConfigurationParameterSizeT(cv::format("OPENCV_UI_PRIORITY_%s", info.name.c_str()).c_str(), (size_t)info.priority); |
||||
CV_Assert(param_priority == (size_t)(int)param_priority); // overflow check
|
||||
if (param_priority > 0) |
||||
{ |
||||
info.priority = (int)param_priority; |
||||
enabled++; |
||||
} |
||||
else |
||||
{ |
||||
CV_LOG_INFO(NULL, "UI: Disable backend: " << info.name); |
||||
} |
||||
} |
||||
enabledBackends.resize(enabled); |
||||
CV_LOG_DEBUG(NULL, "UI: Available backends(" << enabled << "): " << dumpBackends()); |
||||
std::sort(enabledBackends.begin(), enabledBackends.end(), sortByPriority); |
||||
CV_LOG_INFO(NULL, "UI: Enabled backends(" << enabled << ", sorted by priority): " << (enabledBackends.empty() ? std::string("N/A") : dumpBackends())); |
||||
} |
||||
|
||||
static std::vector<std::string> tokenize_string(const std::string& input, char token) |
||||
{ |
||||
std::vector<std::string> result; |
||||
std::string::size_type prev_pos = 0, pos = 0; |
||||
while((pos = input.find(token, pos)) != std::string::npos) |
||||
{ |
||||
result.push_back(input.substr(prev_pos, pos-prev_pos)); |
||||
prev_pos = ++pos; |
||||
} |
||||
result.push_back(input.substr(prev_pos)); |
||||
return result; |
||||
} |
||||
bool readPrioritySettings() |
||||
{ |
||||
bool hasChanges = false; |
||||
cv::String prioritized_backends = utils::getConfigurationParameterString("OPENCV_UI_PRIORITY_LIST", NULL); |
||||
if (prioritized_backends.empty()) |
||||
return hasChanges; |
||||
CV_LOG_INFO(NULL, "UI: Configured priority list (OPENCV_UI_PRIORITY_LIST): " << prioritized_backends); |
||||
const std::vector<std::string> names = tokenize_string(prioritized_backends, ','); |
||||
for (size_t i = 0; i < names.size(); i++) |
||||
{ |
||||
const std::string& name = names[i]; |
||||
int priority = (int)(100000 + (names.size() - i) * 1000); |
||||
bool found = false; |
||||
for (size_t k = 0; k < enabledBackends.size(); k++) |
||||
{ |
||||
BackendInfo& info = enabledBackends[k]; |
||||
if (name == info.name) |
||||
{ |
||||
info.priority = priority; |
||||
CV_LOG_DEBUG(NULL, "UI: New backend priority: '" << name << "' => " << info.priority); |
||||
found = true; |
||||
hasChanges = true; |
||||
break; |
||||
} |
||||
} |
||||
if (!found) |
||||
{ |
||||
CV_LOG_INFO(NULL, "UI: Adding backend (plugin): '" << name << "'"); |
||||
enabledBackends.push_back(BackendInfo{priority, name, createPluginUIBackendFactory(name)}); |
||||
hasChanges = true; |
||||
} |
||||
} |
||||
return hasChanges; |
||||
} |
||||
public: |
||||
std::string dumpBackends() const |
||||
{ |
||||
std::ostringstream os; |
||||
for (size_t i = 0; i < enabledBackends.size(); i++) |
||||
{ |
||||
if (i > 0) os << "; "; |
||||
const BackendInfo& info = enabledBackends[i]; |
||||
os << info.name << '(' << info.priority << ')'; |
||||
} |
||||
return os.str(); |
||||
} |
||||
|
||||
static UIBackendRegistry& getInstance() |
||||
{ |
||||
static UIBackendRegistry g_instance; |
||||
return g_instance; |
||||
} |
||||
|
||||
inline const std::vector<BackendInfo>& getEnabledBackends() const { return enabledBackends; } |
||||
}; |
||||
|
||||
|
||||
const std::vector<BackendInfo>& getBackendsInfo() |
||||
{ |
||||
return cv::highgui_backend::UIBackendRegistry::getInstance().getEnabledBackends(); |
||||
} |
||||
|
||||
}} // namespace
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue