mirror of
https://github.com/opencv/opencv.git
synced 2024-11-27 20:50:25 +08:00
highgui: backends and plugins
This commit is contained in:
parent
7d66f1e391
commit
70f69cb265
@ -11,7 +11,7 @@ if(WITH_WIN32UI)
|
||||
CMAKE_FLAGS "-DLINK_LIBRARIES:STRING=user32;gdi32")
|
||||
endif()
|
||||
|
||||
# --- QT4 ---
|
||||
# --- QT4/5 ---
|
||||
ocv_clear_vars(HAVE_QT HAVE_QT5)
|
||||
if(WITH_QT)
|
||||
if(NOT WITH_QT EQUAL 4)
|
||||
@ -34,41 +34,6 @@ if(WITH_QT)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# --- 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_append_build_options(HIGHGUI GTK3)
|
||||
set(HAVE_GTK TRUE)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT HAVE_GTK)
|
||||
ocv_check_modules(GTK2 gtk+-2.0)
|
||||
if(HAVE_GTK2)
|
||||
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_append_build_options(HIGHGUI GTK2)
|
||||
set(HAVE_GTK TRUE)
|
||||
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_append_build_options(HIGHGUI GTHREAD)
|
||||
endif()
|
||||
if(WITH_OPENGL AND NOT HAVE_GTK3)
|
||||
ocv_check_modules(GTKGLEXT gtkglext-1.0)
|
||||
if(HAVE_GTKGLEXT)
|
||||
ocv_append_build_options(HIGHGUI GTKGLEXT)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# --- OpenGl ---
|
||||
ocv_clear_vars(HAVE_OPENGL HAVE_QT_OPENGL)
|
||||
if(WITH_OPENGL)
|
||||
|
@ -6,4 +6,3 @@ set(MIN_VER_CUDNN 7.5)
|
||||
set(MIN_VER_PYTHON2 2.7)
|
||||
set(MIN_VER_PYTHON3 3.2)
|
||||
set(MIN_VER_ZLIB 1.2.3)
|
||||
set(MIN_VER_GTK 2.18.0)
|
||||
|
@ -1183,6 +1183,9 @@ function(ocv_add_perf_tests)
|
||||
if(TARGET opencv_videoio_plugins)
|
||||
add_dependencies(${the_target} opencv_videoio_plugins)
|
||||
endif()
|
||||
if(TARGET opencv_highgui_plugins)
|
||||
add_dependencies(${the_target} opencv_highgui_plugins)
|
||||
endif()
|
||||
|
||||
if(HAVE_HPX)
|
||||
message("Linking HPX to Perf test of module ${name}")
|
||||
@ -1278,6 +1281,9 @@ function(ocv_add_accuracy_tests)
|
||||
if(TARGET opencv_videoio_plugins)
|
||||
add_dependencies(${the_target} opencv_videoio_plugins)
|
||||
endif()
|
||||
if(TARGET opencv_highgui_plugins)
|
||||
add_dependencies(${the_target} opencv_highgui_plugins)
|
||||
endif()
|
||||
|
||||
if(HAVE_HPX)
|
||||
message("Linking HPX to Perf test of module ${name}")
|
||||
@ -1368,6 +1374,9 @@ function(ocv_add_samples)
|
||||
if(TARGET opencv_videoio_plugins)
|
||||
add_dependencies(${the_target} opencv_videoio_plugins)
|
||||
endif()
|
||||
if(TARGET opencv_highgui_plugins)
|
||||
add_dependencies(${the_target} opencv_highgui_plugins)
|
||||
endif()
|
||||
|
||||
if(INSTALL_BIN_EXAMPLES)
|
||||
install(TARGETS ${the_target} RUNTIME DESTINATION "${OPENCV_SAMPLES_BIN_INSTALL_PATH}/${module_id}" COMPONENT samples)
|
||||
|
@ -28,9 +28,6 @@
|
||||
/* Clp support */
|
||||
#cmakedefine HAVE_CLP
|
||||
|
||||
/* Cocoa API */
|
||||
#cmakedefine HAVE_COCOA
|
||||
|
||||
/* NVIDIA CUDA Runtime API*/
|
||||
#cmakedefine HAVE_CUDA
|
||||
|
||||
@ -56,12 +53,6 @@
|
||||
/* Geospatial Data Abstraction Library */
|
||||
#cmakedefine HAVE_GDAL
|
||||
|
||||
/* GTK+ 2.0 Thread support */
|
||||
#cmakedefine HAVE_GTHREAD
|
||||
|
||||
/* GTK+ 2.x toolkit */
|
||||
#cmakedefine HAVE_GTK
|
||||
|
||||
/* Halide support */
|
||||
#cmakedefine HAVE_HALIDE
|
||||
|
||||
@ -121,12 +112,6 @@
|
||||
/* parallel_for with pthreads */
|
||||
#cmakedefine HAVE_PTHREADS_PF
|
||||
|
||||
/* Qt support */
|
||||
#cmakedefine HAVE_QT
|
||||
|
||||
/* Qt OpenGL support */
|
||||
#cmakedefine HAVE_QT_OPENGL
|
||||
|
||||
/* Intel Threading Building Blocks */
|
||||
#cmakedefine HAVE_TBB
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
ocv_cmake_dump_vars("" TOFILE "CMakeVars2.txt")
|
||||
set(OCV_TEST_VAR 123)
|
||||
add_definitions(-D__OPENCV_BUILD=1)
|
||||
|
||||
if(NOT OPENCV_MODULES_PATH)
|
||||
|
@ -80,7 +80,9 @@ LibHandle_t libraryLoad_(const FileSystemPath_t& filename)
|
||||
return LoadLibraryW(filename.c_str());
|
||||
#endif
|
||||
#elif defined(__linux__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__HAIKU__) || defined(__GLIBC__)
|
||||
return dlopen(filename.c_str(), RTLD_NOW);
|
||||
void* handle = dlopen(filename.c_str(), RTLD_NOW);
|
||||
CV_LOG_IF_DEBUG(NULL, !handle, "dlopen() error: " << dlerror());
|
||||
return handle;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,46 @@
|
||||
set(the_description "High-level GUI")
|
||||
|
||||
set(ENABLE_PLUGINS_DEFAULT ON)
|
||||
if(EMSCRIPTEN OR IOS OR WINRT)
|
||||
set(ENABLE_PLUGINS_DEFAULT OFF)
|
||||
endif()
|
||||
set(HIGHGUI_PLUGIN_LIST "" CACHE STRING "List of GUI backends to be compiled as plugins (gtk, gtk2/gtk3, qt, win32 or special value 'all')")
|
||||
set(HIGHGUI_ENABLE_PLUGINS "${ENABLE_PLUGINS_DEFAULT}" CACHE BOOL "Allow building and using of GUI plugins")
|
||||
mark_as_advanced(HIGHGUI_PLUGIN_LIST HIGHGUI_ENABLE_PLUGINS)
|
||||
|
||||
string(REPLACE "," ";" HIGHGUI_PLUGIN_LIST "${HIGHGUI_PLUGIN_LIST}") # support comma-separated list (,) too
|
||||
if(NOT HIGHGUI_ENABLE_PLUGINS)
|
||||
if(HIGHGUI_PLUGIN_LIST)
|
||||
message(WARNING "HighGUI: plugins are disabled through HIGHGUI_ENABLE_PLUGINS, so HIGHGUI_PLUGIN_LIST='${HIGHGUI_PLUGIN_LIST}' is ignored")
|
||||
set(HIGHGUI_PLUGIN_LIST "")
|
||||
endif()
|
||||
else()
|
||||
# Make virtual plugins target
|
||||
if(NOT TARGET opencv_highgui_plugins)
|
||||
add_custom_target(opencv_highgui_plugins ALL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
ocv_add_module(highgui opencv_imgproc opencv_imgcodecs OPTIONAL opencv_videoio WRAP python)
|
||||
else()
|
||||
ocv_add_module(highgui opencv_imgproc opencv_imgcodecs OPTIONAL opencv_videoio WRAP python java)
|
||||
endif()
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/cmake/plugin.cmake)
|
||||
|
||||
set(tgts "PRIVATE")
|
||||
|
||||
set(highgui_hdrs
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/precomp.hpp
|
||||
)
|
||||
|
||||
set(highgui_srcs
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/backend.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/window.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/roiSelector.cpp
|
||||
)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# CMake file for highgui. See root CMakeLists.txt
|
||||
# Some parts taken from version of Hartmut Seichter, HIT Lab NZ.
|
||||
@ -24,15 +60,6 @@ if(HAVE_WEBP)
|
||||
add_definitions(-DHAVE_WEBP)
|
||||
endif()
|
||||
|
||||
set(highgui_hdrs
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/precomp.hpp
|
||||
)
|
||||
|
||||
set(highgui_srcs
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/window.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/roiSelector.cpp
|
||||
)
|
||||
|
||||
file(GLOB highgui_ext_hdrs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/*.hpp"
|
||||
@ -42,6 +69,8 @@ file(GLOB highgui_ext_hdrs
|
||||
list(REMOVE_ITEM highgui_ext_hdrs "${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/highgui_winrt.hpp")
|
||||
|
||||
if(HAVE_QT5)
|
||||
add_definitions(-DHAVE_QT)
|
||||
|
||||
# "Automoc" doesn't work properly with opencv_world build, use QT5_WRAP_CPP() directly
|
||||
#set(CMAKE_AUTOMOC ON)
|
||||
|
||||
@ -62,13 +91,16 @@ if(HAVE_QT5)
|
||||
endforeach()
|
||||
|
||||
if(HAVE_QT_OPENGL)
|
||||
add_definitions(-DHAVE_QT_OPENGL)
|
||||
add_definitions(${Qt5OpenGL_DEFINITIONS})
|
||||
include_directories(${Qt5OpenGL_INCLUDE_DIRS})
|
||||
list(APPEND HIGHGUI_LIBRARIES ${Qt5OpenGL_LIBRARIES})
|
||||
endif()
|
||||
|
||||
elseif(HAVE_QT)
|
||||
if (HAVE_QT_OPENGL)
|
||||
add_definitions(-DHAVE_QT)
|
||||
if(HAVE_QT_OPENGL)
|
||||
add_definitions(-DHAVE_QT_OPENGL)
|
||||
set(QT_USE_QTOPENGL TRUE)
|
||||
endif()
|
||||
include(${QT_USE_FILE})
|
||||
@ -121,13 +153,64 @@ elseif(HAVE_WIN32UI)
|
||||
if(OpenCV_ARCH STREQUAL "ARM64")
|
||||
list(APPEND HIGHGUI_LIBRARIES "comdlg32" "advapi32")
|
||||
endif()
|
||||
elseif(HAVE_GTK OR HAVE_GTK3)
|
||||
list(APPEND highgui_srcs ${CMAKE_CURRENT_LIST_DIR}/src/window_gtk.cpp)
|
||||
elseif(HAVE_COCOA)
|
||||
add_definitions(-DHAVE_COCOA)
|
||||
list(APPEND highgui_srcs ${CMAKE_CURRENT_LIST_DIR}/src/window_cocoa.mm)
|
||||
list(APPEND HIGHGUI_LIBRARIES "-framework Cocoa")
|
||||
endif()
|
||||
|
||||
if(TARGET ocv.3rdparty.gtk3 OR TARGET ocv.3rdparty.gtk2)
|
||||
if(TARGET ocv.3rdparty.gtk3 AND NOT WITH_GTK_2_X)
|
||||
set(__gtk_dependency "ocv.3rdparty.gtk3")
|
||||
else()
|
||||
set(__gtk_dependency "ocv.3rdparty.gtk2")
|
||||
endif()
|
||||
if(
|
||||
NOT HIGHGUI_PLUGIN_LIST STREQUAL "all"
|
||||
AND NOT "gtk" IN_LIST HIGHGUI_PLUGIN_LIST
|
||||
AND NOT "gtk2" IN_LIST HIGHGUI_PLUGIN_LIST
|
||||
AND NOT "gtk3" IN_LIST HIGHGUI_PLUGIN_LIST
|
||||
)
|
||||
list(APPEND highgui_srcs ${CMAKE_CURRENT_LIST_DIR}/src/window_gtk.cpp)
|
||||
list(APPEND tgts ${__gtk_dependency})
|
||||
if(TARGET ocv.3rdparty.gthread)
|
||||
list(APPEND tgts ocv.3rdparty.gthread)
|
||||
endif()
|
||||
if(TARGET ocv.3rdparty.gtkglext
|
||||
AND NOT OPENCV_GTK_DISABLE_GTKGLEXT
|
||||
)
|
||||
list(APPEND tgts ocv.3rdparty.gtkglext)
|
||||
endif()
|
||||
elseif("gtk" IN_LIST HIGHGUI_PLUGIN_LIST)
|
||||
ocv_create_builtin_highgui_plugin(opencv_highgui_gtk ${__gtk_dependency} "window_gtk.cpp")
|
||||
if(TARGET ocv.3rdparty.gthread)
|
||||
ocv_target_link_libraries(opencv_highgui_gtk ocv.3rdparty.gthread)
|
||||
endif()
|
||||
if(TARGET ocv.3rdparty.gtkglext)
|
||||
ocv_target_link_libraries(opencv_highgui_gtk ocv.3rdparty.gtkglext)
|
||||
endif()
|
||||
else()
|
||||
if(TARGET ocv.3rdparty.gtk3 AND ("gtk3" IN_LIST HIGHGUI_PLUGIN_LIST OR HIGHGUI_PLUGIN_LIST STREQUAL "all"))
|
||||
ocv_create_builtin_highgui_plugin(opencv_highgui_gtk3 ocv.3rdparty.gtk3 "window_gtk.cpp")
|
||||
if(TARGET ocv.3rdparty.gthread)
|
||||
ocv_target_link_libraries(opencv_highgui_gtk3 ocv.3rdparty.gthread)
|
||||
endif()
|
||||
if(TARGET ocv.3rdparty.gtkglext)
|
||||
ocv_target_link_libraries(opencv_highgui_gtk3 ocv.3rdparty.gtkglext)
|
||||
endif()
|
||||
endif()
|
||||
if(TARGET ocv.3rdparty.gtk2 AND ("gtk2" IN_LIST HIGHGUI_PLUGIN_LIST OR HIGHGUI_PLUGIN_LIST STREQUAL "all"))
|
||||
ocv_create_builtin_highgui_plugin(opencv_highgui_gtk2 ocv.3rdparty.gtk2 "window_gtk.cpp")
|
||||
if(TARGET ocv.3rdparty.gthread)
|
||||
ocv_target_link_libraries(opencv_highgui_gtk2 ocv.3rdparty.gthread)
|
||||
endif()
|
||||
if(TARGET ocv.3rdparty.gtkglext)
|
||||
ocv_target_link_libraries(opencv_highgui_gtk2 ocv.3rdparty.gtkglext)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(TRUE)
|
||||
# these variables are set by 'ocv_append_build_options(HIGHGUI ...)'
|
||||
foreach(P ${HIGHGUI_INCLUDE_DIRS})
|
||||
@ -139,6 +222,21 @@ if(TRUE)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(tgts STREQUAL "PRIVATE")
|
||||
set(tgts "")
|
||||
endif()
|
||||
|
||||
# install used dependencies only
|
||||
if(NOT BUILD_SHARED_LIBS
|
||||
AND NOT (CMAKE_VERSION VERSION_LESS "3.13.0") # upgrade CMake: https://gitlab.kitware.com/cmake/cmake/-/merge_requests/2152
|
||||
)
|
||||
foreach(tgt in ${tgts})
|
||||
if(tgt MATCHES "^ocv\.3rdparty\.")
|
||||
install(TARGETS ${tgt} EXPORT OpenCVModules)
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
source_group("Src" FILES ${highgui_srcs} ${highgui_hdrs})
|
||||
source_group("Include" FILES ${highgui_ext_hdrs})
|
||||
ocv_set_module_sources(HEADERS ${highgui_ext_hdrs} SOURCES ${highgui_srcs} ${highgui_hdrs})
|
||||
@ -162,5 +260,14 @@ if(NOT BUILD_opencv_world)
|
||||
ocv_highgui_configure_target()
|
||||
endif()
|
||||
|
||||
ocv_add_accuracy_tests()
|
||||
ocv_add_perf_tests()
|
||||
ocv_add_accuracy_tests(${tgts})
|
||||
#ocv_add_perf_tests(${tgts})
|
||||
|
||||
if(HIGHGUI_ENABLE_PLUGINS)
|
||||
ocv_target_compile_definitions(${the_module} PRIVATE ENABLE_PLUGINS)
|
||||
if(TARGET opencv_test_highgui)
|
||||
ocv_target_compile_definitions(opencv_test_highgui PRIVATE ENABLE_PLUGINS)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
ocv_target_link_libraries(${the_module} LINK_PRIVATE ${tgts})
|
||||
|
43
modules/highgui/cmake/detect_gtk.cmake
Normal file
43
modules/highgui/cmake/detect_gtk.cmake
Normal file
@ -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)
|
25
modules/highgui/cmake/init.cmake
Normal file
25
modules/highgui/cmake/init.cmake
Normal file
@ -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)
|
61
modules/highgui/cmake/plugin.cmake
Normal file
61
modules/highgui/cmake/plugin.cmake
Normal file
@ -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()
|
69
modules/highgui/misc/plugins/build_plugins.sh
Executable file
69
modules/highgui/misc/plugins/build_plugins.sh
Executable file
@ -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
|
44
modules/highgui/misc/plugins/plugin_gtk/CMakeLists.txt
Normal file
44
modules/highgui/misc/plugins/plugin_gtk/CMakeLists.txt
Normal file
@ -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
|
13
modules/highgui/misc/plugins/plugin_gtk/build.sh
Executable file
13
modules/highgui/misc/plugins/plugin_gtk/build.sh
Executable file
@ -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
|
181
modules/highgui/src/backend.cpp
Normal file
181
modules/highgui/src/backend.cpp
Normal file
@ -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
|
131
modules/highgui/src/backend.hpp
Normal file
131
modules/highgui/src/backend.hpp
Normal file
@ -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
|
48
modules/highgui/src/factory.hpp
Normal file
48
modules/highgui/src/factory.hpp
Normal file
@ -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
|
72
modules/highgui/src/plugin_api.hpp
Normal file
72
modules/highgui/src/plugin_api.hpp
Normal file
@ -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
|
283
modules/highgui/src/plugin_wrapper.impl.hpp
Normal file
283
modules/highgui/src/plugin_wrapper.impl.hpp
Normal file
@ -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
|
@ -42,10 +42,16 @@
|
||||
#ifndef __HIGHGUI_H_
|
||||
#define __HIGHGUI_H_
|
||||
|
||||
#if defined(__OPENCV_BUILD) && defined(BUILD_PLUGIN)
|
||||
#undef __OPENCV_BUILD // allow public API only
|
||||
#endif
|
||||
|
||||
#include "opencv2/highgui.hpp"
|
||||
|
||||
#include "opencv2/core/utility.hpp"
|
||||
#if defined(__OPENCV_BUILD)
|
||||
#include "opencv2/core/private.hpp"
|
||||
#endif
|
||||
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/imgproc/imgproc_c.h"
|
||||
@ -169,4 +175,11 @@ inline void convertToShow(const cv::Mat &src, const CvMat* arr, bool toRGB = tru
|
||||
}
|
||||
|
||||
|
||||
namespace cv {
|
||||
|
||||
CV_EXPORTS Mutex& getWindowMutex();
|
||||
static inline Mutex& getInitializationMutex() { return getWindowMutex(); }
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif /* __HIGHGUI_H_ */
|
||||
|
25
modules/highgui/src/registry.hpp
Normal file
25
modules/highgui/src/registry.hpp
Normal file
@ -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
|
183
modules/highgui/src/registry.impl.hpp
Normal file
183
modules/highgui/src/registry.impl.hpp
Normal file
@ -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
|
@ -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);
|
||||
|
@ -1219,9 +1219,6 @@ void GuiReceiver::addSlider2(QString bar_name, QString window_name, void* value,
|
||||
if (t) //trackbar exists
|
||||
return;
|
||||
|
||||
if (!value)
|
||||
CV_Error(CV_StsNullPtr, "NULL value pointer" );
|
||||
|
||||
if (count <= 0) //count is the max value of the slider, so must be bigger than 0
|
||||
CV_Error(CV_StsNullPtr, "Max value of the slider must be bigger than 0" );
|
||||
|
||||
@ -1342,7 +1339,8 @@ void CvTrackbar::create(CvWindow* arg, QString name, int* value, int _count)
|
||||
slider->setMinimum(0);
|
||||
slider->setMaximum(_count);
|
||||
slider->setPageStep(5);
|
||||
slider->setValue(*value);
|
||||
if (dataSlider)
|
||||
slider->setValue(*dataSlider);
|
||||
slider->setTickPosition(QSlider::TicksBelow);
|
||||
|
||||
|
||||
@ -1409,7 +1407,8 @@ void CvTrackbar::update(int myvalue)
|
||||
{
|
||||
setLabel(myvalue);
|
||||
|
||||
*dataSlider = myvalue;
|
||||
if (dataSlider)
|
||||
*dataSlider = myvalue;
|
||||
if (callback)
|
||||
{
|
||||
callback(myvalue);
|
||||
|
@ -256,7 +256,7 @@ private:
|
||||
QPointer<QPushButton > label;
|
||||
CvTrackbarCallback callback;
|
||||
CvTrackbarCallback2 callback2;//look like it is use by python binding
|
||||
int* dataSlider;
|
||||
int* dataSlider; // deprecated
|
||||
void* userdata;
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -47,13 +47,18 @@ namespace opencv_test { namespace {
|
||||
inline void verify_size(const std::string &nm, const cv::Mat &img)
|
||||
{
|
||||
EXPECT_NO_THROW(imshow(nm, img));
|
||||
EXPECT_EQ(-1, waitKey(500));
|
||||
EXPECT_EQ(-1, waitKey(200));
|
||||
Rect rc;
|
||||
EXPECT_NO_THROW(rc = getWindowImageRect(nm));
|
||||
EXPECT_EQ(rc.size(), img.size());
|
||||
}
|
||||
|
||||
#if !defined HAVE_GTK && !defined HAVE_QT && !defined HAVE_WIN32UI && !defined HAVE_COCOA
|
||||
#if (!defined(ENABLE_PLUGINS) \
|
||||
&& !defined HAVE_GTK \
|
||||
&& !defined HAVE_QT \
|
||||
&& !defined HAVE_WIN32UI \
|
||||
&& !defined HAVE_COCOA \
|
||||
)
|
||||
TEST(Highgui_GUI, DISABLED_regression)
|
||||
#else
|
||||
TEST(Highgui_GUI, regression)
|
||||
@ -126,11 +131,15 @@ static void Foo(int, void* counter)
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined HAVE_GTK && !defined HAVE_QT && !defined HAVE_WIN32UI
|
||||
// && !defined HAVE_COCOA - TODO: fails on Mac?
|
||||
TEST(Highgui_GUI, DISABLED_trackbar)
|
||||
#if (!defined(ENABLE_PLUGINS) \
|
||||
&& !defined HAVE_GTK \
|
||||
&& !defined HAVE_QT \
|
||||
&& !defined HAVE_WIN32UI \
|
||||
) \
|
||||
|| defined(__APPLE__) // test fails on Mac (cocoa)
|
||||
TEST(Highgui_GUI, DISABLED_trackbar_unsafe)
|
||||
#else
|
||||
TEST(Highgui_GUI, trackbar)
|
||||
TEST(Highgui_GUI, trackbar_unsafe)
|
||||
#endif
|
||||
{
|
||||
int value = 50;
|
||||
@ -142,9 +151,52 @@ TEST(Highgui_GUI, trackbar)
|
||||
ASSERT_NO_THROW(namedWindow(window_name));
|
||||
EXPECT_EQ((int)1, createTrackbar(trackbar_name, window_name, &value, 100, Foo, &callback_count));
|
||||
EXPECT_EQ(value, getTrackbarPos(trackbar_name, window_name));
|
||||
EXPECT_EQ(0, callback_count);
|
||||
EXPECT_GE(callback_count, 0);
|
||||
EXPECT_LE(callback_count, 1);
|
||||
int callback_count_base = callback_count;
|
||||
EXPECT_NO_THROW(setTrackbarPos(trackbar_name, window_name, 90));
|
||||
EXPECT_EQ(1, callback_count);
|
||||
EXPECT_EQ(callback_count_base + 1, callback_count);
|
||||
EXPECT_EQ(90, value);
|
||||
EXPECT_EQ(90, getTrackbarPos(trackbar_name, window_name));
|
||||
EXPECT_NO_THROW(destroyAllWindows());
|
||||
}
|
||||
|
||||
static
|
||||
void testTrackbarCallback(int pos, void* param)
|
||||
{
|
||||
CV_Assert(param);
|
||||
int* status = (int*)param;
|
||||
status[0] = pos;
|
||||
status[1]++;
|
||||
}
|
||||
|
||||
#if (!defined(ENABLE_PLUGINS) \
|
||||
&& !defined HAVE_GTK \
|
||||
&& !defined HAVE_QT \
|
||||
&& !defined HAVE_WIN32UI \
|
||||
) \
|
||||
|| defined(__APPLE__) // test fails on Mac (cocoa)
|
||||
TEST(Highgui_GUI, DISABLED_trackbar)
|
||||
#else
|
||||
TEST(Highgui_GUI, trackbar)
|
||||
#endif
|
||||
{
|
||||
int status[2] = {-1, 0}; // pos, counter
|
||||
const std::string window_name("trackbar_test_window");
|
||||
const std::string trackbar_name("trackbar");
|
||||
|
||||
EXPECT_NO_THROW(destroyAllWindows());
|
||||
ASSERT_NO_THROW(namedWindow(window_name));
|
||||
EXPECT_EQ((int)1, createTrackbar(trackbar_name, window_name, NULL, 100, testTrackbarCallback, status));
|
||||
EXPECT_EQ(0, getTrackbarPos(trackbar_name, window_name));
|
||||
int callback_count = status[1];
|
||||
EXPECT_GE(callback_count, 0);
|
||||
EXPECT_LE(callback_count, 1);
|
||||
int callback_count_base = callback_count;
|
||||
EXPECT_NO_THROW(setTrackbarPos(trackbar_name, window_name, 90));
|
||||
callback_count = status[1];
|
||||
EXPECT_EQ(callback_count_base + 1, callback_count);
|
||||
int value = status[0];
|
||||
EXPECT_EQ(90, value);
|
||||
EXPECT_EQ(90, getTrackbarPos(trackbar_name, window_name));
|
||||
EXPECT_NO_THROW(destroyAllWindows());
|
||||
|
Loading…
Reference in New Issue
Block a user