diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index dd53e9508c..2b856bea24 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -15,12 +15,12 @@ body:
Please provide the following system information to help us diagnose the bug. For example:
// example for c++ user
- OpenCV version: 4.6.0
+ OpenCV version: 4.8.0
Operating System / Platform: Ubuntu 20.04
Compiler & compiler version: GCC 9.3.0
// example for python user
- OpenCV python version: 4.6.0.66
+ OpenCV python version: 4.8.0.74
Operating System / Platform: Ubuntu 20.04
Python version: 3.9.6
validations:
diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml
index d33c030972..8d4d3e440b 100644
--- a/.github/ISSUE_TEMPLATE/documentation.yml
+++ b/.github/ISSUE_TEMPLATE/documentation.yml
@@ -12,7 +12,7 @@ body:
attributes:
label: Describe the doc issue
description: >
- Please provide a clear and concise description of what content in https://docs.opencv.org/ is an issue. Note that there are multiple active branches, such as 3.4, 4.x and 5.x, so please specify the branch with the problem.
+ Please provide a clear and concise description of what content in https://docs.opencv.org/ is an issue. Note that there are multiple active branches, such as 4.x and 5.x, so please specify the branch with the problem.
placeholder: |
A clear and concise description of what content in https://docs.opencv.org/ is an issue.
diff --git a/3rdparty/ffmpeg/ffmpeg.cmake b/3rdparty/ffmpeg/ffmpeg.cmake
index f3ad63770a..da75e3d2ca 100644
--- a/3rdparty/ffmpeg/ffmpeg.cmake
+++ b/3rdparty/ffmpeg/ffmpeg.cmake
@@ -1,8 +1,8 @@
-# Binaries branch name: ffmpeg/4.x_20221225
-# Binaries were created for OpenCV: 4abe6dc48d4ec6229f332cc6cf6c7e234ac8027e
-ocv_update(FFMPEG_BINARIES_COMMIT "7dd0d4f1d6fe75f05f3d3b5e38cbc96c1a2d2809")
-ocv_update(FFMPEG_FILE_HASH_BIN32 "e598ae2ece1ddf310bc49b58202fd87a")
-ocv_update(FFMPEG_FILE_HASH_BIN64 "b2a40c142c20aef9fd663fc8f85c2971")
+# Binaries branch name: ffmpeg/4.x_20230622
+# Binaries were created for OpenCV: 61d48dd0f8d1cc1a115d26998705a61478f64a3c
+ocv_update(FFMPEG_BINARIES_COMMIT "7da61f0695eabf8972a2c302bf1632a3d99fb0d5")
+ocv_update(FFMPEG_FILE_HASH_BIN32 "4aaef1456e282e5ef665d65555f47f56")
+ocv_update(FFMPEG_FILE_HASH_BIN64 "38a638851e064c591ce812e27ed43f1f")
ocv_update(FFMPEG_FILE_HASH_CMAKE "8862c87496e2e8c375965e1277dee1c7")
function(download_win_ffmpeg script_var)
diff --git a/3rdparty/libtiff/tif_dirread.c b/3rdparty/libtiff/tif_dirread.c
index ba127ca917..45c1107697 100644
--- a/3rdparty/libtiff/tif_dirread.c
+++ b/3rdparty/libtiff/tif_dirread.c
@@ -4371,7 +4371,7 @@ static void
TIFFReadDirectoryCheckOrder(TIFF* tif, TIFFDirEntry* dir, uint16 dircount)
{
static const char module[] = "TIFFReadDirectoryCheckOrder";
- uint16 m;
+ uint32 m;
uint16 n;
TIFFDirEntry* o;
m=0;
diff --git a/3rdparty/openjpeg/openjp2/ht_dec.c b/3rdparty/openjpeg/openjp2/ht_dec.c
index 1eb4d525f1..e2f3afd6a3 100644
--- a/3rdparty/openjpeg/openjp2/ht_dec.c
+++ b/3rdparty/openjpeg/openjp2/ht_dec.c
@@ -69,7 +69,7 @@ static OPJ_BOOL only_cleanup_pass_is_decoded = OPJ_FALSE;
static INLINE
OPJ_UINT32 population_count(OPJ_UINT32 val)
{
-#ifdef OPJ_COMPILER_MSVC
+#if defined(OPJ_COMPILER_MSVC) && (defined(_M_IX86) || defined(_M_AMD64))
return (OPJ_UINT32)__popcnt(val);
#elif (defined OPJ_COMPILER_GNUC)
return (OPJ_UINT32)__builtin_popcount(val);
diff --git a/3rdparty/protobuf/CMakeLists.txt b/3rdparty/protobuf/CMakeLists.txt
index e39de9823a..5e8e3a9ed2 100644
--- a/3rdparty/protobuf/CMakeLists.txt
+++ b/3rdparty/protobuf/CMakeLists.txt
@@ -26,6 +26,7 @@ else()
-Wsuggest-override -Winconsistent-missing-override
-Wimplicit-fallthrough
-Warray-bounds # GCC 9+
+ -Wstringop-overflow -Wstringop-overread # GCC 11-12
)
endif()
if(CV_ICC)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 24e8fee7c4..64d89ed60b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -784,6 +784,15 @@ if(BUILD_JAVA)
include(cmake/android/OpenCVDetectAndroidSDK.cmake)
else()
include(cmake/OpenCVDetectApacheAnt.cmake)
+ if(ANT_EXECUTABLE AND NOT OPENCV_JAVA_IGNORE_ANT)
+ ocv_update(OPENCV_JAVA_SDK_BUILD_TYPE "ANT")
+ elseif(NOT ANDROID)
+ find_package(Java)
+ if(Java_FOUND)
+ include(UseJava)
+ ocv_update(OPENCV_JAVA_SDK_BUILD_TYPE "JAVA")
+ endif()
+ endif()
find_package(JNI)
endif()
endif()
@@ -1800,9 +1809,10 @@ if(BUILD_JAVA)
status(" Java:" BUILD_FAT_JAVA_LIB THEN "export all functions" ELSE "")
status(" ant:" ANT_EXECUTABLE THEN "${ANT_EXECUTABLE} (ver ${ANT_VERSION})" ELSE NO)
if(NOT ANDROID)
+ status(" Java:" Java_FOUND THEN "YES (ver ${Java_VERSION})" ELSE NO)
status(" JNI:" JNI_INCLUDE_DIRS THEN "${JNI_INCLUDE_DIRS}" ELSE NO)
endif()
- status(" Java wrappers:" HAVE_opencv_java THEN YES ELSE NO)
+ status(" Java wrappers:" HAVE_opencv_java THEN "YES (${OPENCV_JAVA_SDK_BUILD_TYPE})" ELSE NO)
status(" Java tests:" BUILD_TESTS AND opencv_test_java_BINARY_DIR THEN YES ELSE NO)
endif()
diff --git a/apps/createsamples/utility.cpp b/apps/createsamples/utility.cpp
index 0b6439daaf..5bc1a89443 100644
--- a/apps/createsamples/utility.cpp
+++ b/apps/createsamples/utility.cpp
@@ -70,7 +70,7 @@ using namespace cv;
static int icvMkDir( const char* filename )
{
- char path[PATH_MAX];
+ char path[PATH_MAX+1];
char* p;
int pos;
@@ -83,7 +83,8 @@ static int icvMkDir( const char* filename )
mode = 0755;
#endif /* _WIN32 */
- strcpy( path, filename );
+ path[0] = '\0';
+ strncat( path, filename, PATH_MAX );
p = path;
for( ; ; )
diff --git a/cmake/FindONNX.cmake b/cmake/FindONNX.cmake
index 56dd6d5098..b2c79a9031 100644
--- a/cmake/FindONNX.cmake
+++ b/cmake/FindONNX.cmake
@@ -16,7 +16,22 @@ if(ONNXRT_ROOT_DIR)
CMAKE_FIND_ROOT_PATH_BOTH)
endif()
+macro(detect_onxxrt_ep filename dir have_ep_var)
+ find_path(ORT_EP_INCLUDE ${filename} ${dir} CMAKE_FIND_ROOT_PATH_BOTH)
+ if(ORT_EP_INCLUDE)
+ set(${have_ep_var} TRUE)
+ endif()
+endmacro()
+
if(ORT_LIB AND ORT_INCLUDE)
+ # Check DirectML Execution Provider availability
+ get_filename_component(dml_dir ${ONNXRT_ROOT_DIR}/include/onnxruntime/core/providers/dml ABSOLUTE)
+ detect_onxxrt_ep(
+ dml_provider_factory.h
+ ${dml_dir}
+ HAVE_ONNX_DML
+ )
+
set(HAVE_ONNX TRUE)
# For CMake output only
set(ONNX_LIBRARIES "${ORT_LIB}" CACHE STRING "ONNX Runtime libraries")
diff --git a/cmake/OpenCVCompilerOptions.cmake b/cmake/OpenCVCompilerOptions.cmake
index 3f3358aae5..8bd8668130 100644
--- a/cmake/OpenCVCompilerOptions.cmake
+++ b/cmake/OpenCVCompilerOptions.cmake
@@ -108,6 +108,7 @@ elseif(CV_ICC)
elseif(CV_GCC OR CV_CLANG)
if(ENABLE_FAST_MATH)
add_extra_compiler_option(-ffast-math)
+ add_extra_compiler_option(-fno-finite-math-only)
endif()
endif()
@@ -260,7 +261,11 @@ if(CV_GCC OR CV_CLANG)
endif()
if(ENABLE_LTO)
- add_extra_compiler_option(-flto)
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12)
+ add_extra_compiler_option(-flto=auto)
+ else()
+ add_extra_compiler_option(-flto)
+ endif()
endif()
if(ENABLE_THIN_LTO)
add_extra_compiler_option(-flto=thin)
diff --git a/cmake/OpenCVFindCANN.cmake b/cmake/OpenCVFindCANN.cmake
index b0b8e35c6b..e1cd054a37 100644
--- a/cmake/OpenCVFindCANN.cmake
+++ b/cmake/OpenCVFindCANN.cmake
@@ -5,13 +5,24 @@ if("cann${CANN_INSTALL_DIR}" STREQUAL "cann" AND DEFINED ENV{ASCEND_TOOLKIT_HOME
message(STATUS "CANN: updated CANN_INSTALL_DIR from ASCEND_TOOLKIT_HOME=$ENV{ASCEND_TOOLKIT_HOME}")
endif()
+if(EXISTS "${CANN_INSTALL_DIR}/opp/op_proto/built-in/inc")
+ set(CANN_VERSION_BELOW_6_3_ALPHA002 "YES" )
+ add_definitions(-DCANN_VERSION_BELOW_6_3_ALPHA002="YES")
+endif()
+
if(CANN_INSTALL_DIR)
+ # Supported system: UNIX
+ if(NOT UNIX)
+ set(HAVE_CANN OFF)
+ message(WARNING "CANN: CANN toolkit supports unix but not ${CMAKE_SYSTEM_NAME}. Turning off HAVE_CANN")
+ return()
+ endif()
# Supported platforms: x86-64, arm64
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64")
else()
set(HAVE_CANN OFF)
- message(STATUS "CANN: CANN toolkit supports x86-64 and arm64 but not ${CMAKE_SYSTEM_PROCESSOR}. Turning off HAVE_CANN")
+ message(WARNING "CANN: CANN toolkit supports x86-64 and arm64 but not ${CMAKE_SYSTEM_PROCESSOR}. Turning off HAVE_CANN")
return()
endif()
@@ -31,7 +42,7 @@ if(CANN_INSTALL_DIR)
set(lib_ascendcl ${found_lib_ascendcl})
message(STATUS "CANN: libascendcl.so is found at ${lib_ascendcl}")
else()
- message(STATUS "CANN: Missing libascendcl.so. Turning off HAVE_CANN")
+ message(WARNING "CANN: Missing libascendcl.so. Turning off HAVE_CANN")
set(HAVE_CANN OFF)
return()
endif()
@@ -42,7 +53,7 @@ if(CANN_INSTALL_DIR)
set(lib_graph ${found_lib_graph})
message(STATUS "CANN: libgraph.so is found at ${lib_graph}")
else()
- message(STATUS "CANN: Missing libgraph.so. Turning off HAVE_CANN")
+ message(WARNING "CANN: Missing libgraph.so. Turning off HAVE_CANN")
set(HAVE_CANN OFF)
return()
endif()
@@ -53,29 +64,49 @@ if(CANN_INSTALL_DIR)
set(lib_ge_compiler ${found_lib_ge_compiler})
message(STATUS "CANN: libge_compiler.so is found at ${lib_ge_compiler}")
else()
- message(STATUS "CANN: Missing libge_compiler.so. Turning off HAVE_CANN")
+ message(WARNING "CANN: Missing libge_compiler.so. Turning off HAVE_CANN")
set(HAVE_CANN OFF)
return()
endif()
# * libopsproto.so
- set(lib_opsproto "${CANN_INSTALL_DIR}/opp/op_proto/built-in")
+ if (CANN_VERSION_BELOW_6_3_ALPHA002)
+ set(lib_opsproto "${CANN_INSTALL_DIR}/opp/op_proto/built-in/")
+ else()
+ if(EXISTS "${CANN_INSTALL_DIR}/opp/built-in/op_proto/lib/linux")
+ set(lib_opsproto "${CANN_INSTALL_DIR}/opp/built-in/op_proto/lib/linux/${CMAKE_HOST_SYSTEM_PROCESSOR}")
+ else()
+ set(lib_opsproto "${CANN_INSTALL_DIR}/opp/built-in/op_proto")
+ endif()
+ endif()
find_library(found_lib_opsproto NAMES opsproto PATHS ${lib_opsproto} NO_DEFAULT_PATH)
if(found_lib_opsproto)
set(lib_opsproto ${found_lib_opsproto})
message(STATUS "CANN: libopsproto.so is found at ${lib_opsproto}")
else()
- message(STATUS "CANN: Missing libopsproto.so. Turning off HAVE_CANN")
+ message(WARNING "CANN: Missing libopsproto.so can't found at ${lib_opsproto}. Turning off HAVE_CANN")
set(HAVE_CANN OFF)
return()
endif()
-
set(libs_cann "")
list(APPEND libs_cann ${lib_ascendcl})
list(APPEND libs_cann ${lib_opsproto})
list(APPEND libs_cann ${lib_graph})
list(APPEND libs_cann ${lib_ge_compiler})
+ # * lib_graph_base.so
+ if(NOT CANN_VERSION_BELOW_6_3_ALPHA002)
+ set(lib_graph_base "${CANN_INSTALL_DIR}/compiler/lib64")
+ find_library(found_libgraph_base NAMES graph_base PATHS ${lib_graph_base} NO_DEFAULT_PATH)
+ if(found_libgraph_base)
+ set(lib_graph_base ${found_libgraph_base})
+ message(STATUS "CANN: lib_graph_base.so is found at ${lib_graph_base}")
+ list(APPEND libs_cann ${lib_graph_base})
+ else()
+ message(STATUS "CANN: Missing lib_graph_base.so. It is only required after cann version 6.3.RC1.alpha002")
+ endif()
+ endif()
+
try_compile(VALID_ASCENDCL
"${OpenCV_BINARY_DIR}"
"${OpenCV_SOURCE_DIR}/cmake/checks/cann.cpp"
diff --git a/cmake/OpenCVPackaging.cmake b/cmake/OpenCVPackaging.cmake
index 67a65e262f..eee1c96869 100644
--- a/cmake/OpenCVPackaging.cmake
+++ b/cmake/OpenCVPackaging.cmake
@@ -52,8 +52,8 @@ else()
set(OPENCV_PACKAGE_ARCH_SUFFIX ${CMAKE_SYSTEM_PROCESSOR})
endif()
-set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${OPENCV_VCSVERSION}-${OPENCV_PACKAGE_ARCH_SUFFIX}")
-set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${OPENCV_VCSVERSION}-${OPENCV_PACKAGE_ARCH_SUFFIX}")
+set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION}-${OPENCV_PACKAGE_ARCH_SUFFIX}")
+set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION}-${OPENCV_PACKAGE_ARCH_SUFFIX}")
#rpm options
set(CPACK_RPM_COMPONENT_INSTALL TRUE)
diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake
index a0741a3e84..04a4441c92 100644
--- a/cmake/OpenCVUtils.cmake
+++ b/cmake/OpenCVUtils.cmake
@@ -1632,13 +1632,19 @@ function(ocv_add_external_target name inc link def)
endif()
endfunction()
+set(__OPENCV_EXPORTED_EXTERNAL_TARGETS "" CACHE INTERNAL "")
function(ocv_install_used_external_targets)
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 ${ARGN})
if(tgt MATCHES "^ocv\.3rdparty\.")
- install(TARGETS ${tgt} EXPORT OpenCVModules)
+ list(FIND __OPENCV_EXPORTED_EXTERNAL_TARGETS "${tgt}" _found)
+ if(_found EQUAL -1) # don't export target twice
+ install(TARGETS ${tgt} EXPORT OpenCVModules)
+ list(APPEND __OPENCV_EXPORTED_EXTERNAL_TARGETS "${tgt}")
+ set(__OPENCV_EXPORTED_EXTERNAL_TARGETS "${__OPENCV_EXPORTED_EXTERNAL_TARGETS}" CACHE INTERNAL "")
+ endif()
endif()
endforeach()
endif()
diff --git a/cmake/copy_files.cmake b/cmake/copy_files.cmake
index 423f7fff9c..f7e13a45d4 100644
--- a/cmake/copy_files.cmake
+++ b/cmake/copy_files.cmake
@@ -21,7 +21,7 @@ macro(copy_file_ src dst prefix)
endif()
if(use_symlink)
if(local_update OR NOT IS_SYMLINK "${dst}")
- message("${prefix}Symlink: '${dst_name}' ...")
+ #message("${prefix}Symlink: '${dst_name}' ...")
endif()
get_filename_component(target_path "${dst}" PATH)
file(MAKE_DIRECTORY "${target_path}")
@@ -38,7 +38,7 @@ macro(copy_file_ src dst prefix)
set(local_update 1)
endif()
if(local_update)
- message("${prefix}Copying: '${dst_name}' ...")
+ #message("${prefix}Copying: '${dst_name}' ...")
configure_file(${src} ${dst} COPYONLY)
else()
#message("${prefix}Up-to-date: '${dst_name}'")
@@ -55,7 +55,7 @@ if(NOT DEFINED COPYLIST_VAR)
set(COPYLIST_VAR "COPYLIST")
endif()
list(LENGTH ${COPYLIST_VAR} __length)
-message("${prefix}... ${__length} entries (${COPYLIST_VAR})")
+#message("${prefix}... ${__length} entries (${COPYLIST_VAR})")
foreach(id ${${COPYLIST_VAR}})
set(src "${${COPYLIST_VAR}_SRC_${id}}")
set(dst "${${COPYLIST_VAR}_DST_${id}}")
@@ -80,7 +80,7 @@ foreach(id ${${COPYLIST_VAR}})
endif()
file(GLOB_RECURSE _files RELATIVE "${src}" ${src_glob})
list(LENGTH _files __length)
- message("${prefix} ... directory '.../${src_name2}/${src_name}' with ${__length} files")
+ #message("${prefix} ... directory '.../${src_name2}/${src_name}' with ${__length} files")
foreach(f ${_files})
if(NOT EXISTS "${src}/${f}")
message(FATAL_ERROR "COPY ERROR: Source file is missing: ${src}/${f}")
@@ -98,12 +98,12 @@ else()
endif()
if(NOT "${__state}" STREQUAL "${__prev_state}")
file(WRITE "${STATE_FILE}" "${__state}")
- message("${prefix}Updated!")
+ #message("${prefix}Updated!")
set(update_dephelper 1)
endif()
if(NOT update_dephelper)
- message("${prefix}All files are up-to-date.")
+ #message("${prefix}All files are up-to-date.")
elseif(DEFINED DEPHELPER)
file(WRITE "${DEPHELPER}" "")
endif()
diff --git a/doc/opencv.bib b/doc/opencv.bib
index 412c5379f9..62c038de08 100644
--- a/doc/opencv.bib
+++ b/doc/opencv.bib
@@ -1383,3 +1383,11 @@
year={2005},
pages={70-74}
}
+@inproceedings{wang2016iros,
+ AUTHOR = {John Wang and Edwin Olson},
+ TITLE = {{AprilTag} 2: Efficient and robust fiducial detection},
+ BOOKTITLE = {Proceedings of the {IEEE/RSJ} International Conference on Intelligent
+ Robots and Systems {(IROS)}},
+ YEAR = {2016},
+ MONTH = {October},
+}
diff --git a/doc/tutorials/app/orbbec_astra.markdown b/doc/tutorials/app/orbbec_astra.markdown
index 849b2d7d19..84921fe121 100644
--- a/doc/tutorials/app/orbbec_astra.markdown
+++ b/doc/tutorials/app/orbbec_astra.markdown
@@ -9,7 +9,7 @@ Using Orbbec Astra 3D cameras {#tutorial_orbbec_astra}
### Introduction
-This tutorial is devoted to the Astra Series of Orbbec 3D cameras (https://orbbec3d.com/product-astra-pro/).
+This tutorial is devoted to the Astra Series of Orbbec 3D cameras (https://orbbec3d.com/index/Product/info.html?cate=38&id=36).
That cameras have a depth sensor in addition to a common color sensor. The depth sensors can be read using
the open source OpenNI API with @ref cv::VideoCapture class. The video stream is provided through the regular
camera interface.
@@ -18,9 +18,11 @@ camera interface.
In order to use the Astra camera's depth sensor with OpenCV you should do the following steps:
--# Download the latest version of Orbbec OpenNI SDK (from here ).
+-# Download the latest version of Orbbec OpenNI SDK (from here ).
Unzip the archive, choose the build according to your operating system and follow installation
- steps provided in the Readme file. For instance, if you use 64bit GNU/Linux run:
+ steps provided in the Readme file.
+
+-# For instance, if you use 64bit GNU/Linux run:
@code{.bash}
$ cd Linux/OpenNI-Linux-x64-2.3.0.63/
$ sudo ./install.sh
@@ -31,17 +33,44 @@ In order to use the Astra camera's depth sensor with OpenCV you should do the fo
@code{.bash}
$ source OpenNIDevEnvironment
@endcode
-
--# Run the following commands to verify that OpenNI library and header files can be found. You should see
- something similar in your terminal:
+ To verify that the source command works and OpenNI library and header files can be found, run the following
+ command and you should see something similar in your terminal:
@code{.bash}
$ echo $OPENNI2_INCLUDE
/home/user/OpenNI_2.3.0.63/Linux/OpenNI-Linux-x64-2.3.0.63/Include
$ echo $OPENNI2_REDIST
/home/user/OpenNI_2.3.0.63/Linux/OpenNI-Linux-x64-2.3.0.63/Redist
@endcode
- If the above two variables are empty, then you need to source `OpenNIDevEnvironment` again. Now you can
- configure OpenCV with OpenNI support enabled by setting the `WITH_OPENNI2` flag in CMake.
+ If the above two variables are empty, then you need to source `OpenNIDevEnvironment` again.
+
+ @note Orbbec OpenNI SDK version 2.3.0.86 and newer does not provide `install.sh` any more.
+ You can use the following script to initialize environment:
+ @code{.text}
+ # Check if user is root/running with sudo
+ if [ `whoami` != root ]; then
+ echo Please run this script with sudo
+ exit
+ fi
+
+ ORIG_PATH=`pwd`
+ cd `dirname $0`
+ SCRIPT_PATH=`pwd`
+ cd $ORIG_PATH
+
+ if [ "`uname -s`" != "Darwin" ]; then
+ # Install UDEV rules for USB device
+ cp ${SCRIPT_PATH}/orbbec-usb.rules /etc/udev/rules.d/558-orbbec-usb.rules
+ echo "usb rules file install at /etc/udev/rules.d/558-orbbec-usb.rules"
+ fi
+
+ OUT_FILE="$SCRIPT_PATH/OpenNIDevEnvironment"
+ echo "export OPENNI2_INCLUDE=$SCRIPT_PATH/../sdk/Include" > $OUT_FILE
+ echo "export OPENNI2_REDIST=$SCRIPT_PATH/../sdk/libs" >> $OUT_FILE
+ chmod a+r $OUT_FILE
+ echo "exit"
+ @endcode
+
+-# Now you can configure OpenCV with OpenNI support enabled by setting the `WITH_OPENNI2` flag in CMake.
You may also like to enable the `BUILD_EXAMPLES` flag to get a code sample working with your Astra camera.
Run the following commands in the directory containing OpenCV source code to enable OpenNI support:
@code{.bash}
diff --git a/doc/tutorials/introduction/config_reference/config_reference.markdown b/doc/tutorials/introduction/config_reference/config_reference.markdown
index 684355106f..16acc315f5 100644
--- a/doc/tutorials/introduction/config_reference/config_reference.markdown
+++ b/doc/tutorials/introduction/config_reference/config_reference.markdown
@@ -2,7 +2,7 @@ OpenCV configuration options reference {#tutorial_config_reference}
======================================
@prev_tutorial{tutorial_general_install}
-@next_tutorial{tutorial_linux_install}
+@next_tutorial{tutorial_env_reference}
@tableofcontents
diff --git a/doc/tutorials/introduction/env_reference/env_reference.markdown b/doc/tutorials/introduction/env_reference/env_reference.markdown
new file mode 100644
index 0000000000..2a850dc299
--- /dev/null
+++ b/doc/tutorials/introduction/env_reference/env_reference.markdown
@@ -0,0 +1,345 @@
+OpenCV environment variables reference {#tutorial_env_reference}
+======================================
+
+@prev_tutorial{tutorial_config_reference}
+@next_tutorial{tutorial_linux_install}
+
+@tableofcontents
+
+### Introduction
+
+OpenCV can change its behavior depending on the runtime environment:
+- enable extra debugging output or performance tracing
+- modify default locations and search paths
+- tune some algorithms or general behavior
+- enable or disable workarounds, safety features and optimizations
+
+**Notes:**
+- ⭐ marks most popular variables
+- variables with names like this `VAR_${NAME}` describes family of variables, where `${NAME}` should be changed to one of predefined values, e.g. `VAR_TBB`, `VAR_OPENMP`, ...
+
+##### Setting environment variable in Windows
+In terminal or cmd-file (bat-file):
+```.bat
+set MY_ENV_VARIABLE=true
+C:\my_app.exe
+```
+In GUI:
+- Go to "Settings -> System -> About"
+- Click on "Advanced system settings" in the right part
+- In new window click on the "Environment variables" button
+- Add an entry to the "User variables" list
+
+##### Setting environment variable in Linux
+
+In terminal or shell script:
+```.sh
+export MY_ENV_VARIABLE=true
+./my_app
+```
+or as a single command:
+```.sh
+MY_ENV_VARIABLE=true ./my_app
+```
+
+##### Setting environment variable in Python
+
+```.py
+import os
+os.environ["MY_ENV_VARIABLE"] = True
+import cv2 # variables set after this may not have effect
+```
+
+
+### Types
+
+- _non-null_ - set to anything to enable feature, in some cases can be interpreted as other types (e.g. path)
+- _bool_ - `1`, `True`, `true`, `TRUE` / `0`, `False`, `false`, `FALSE`
+- _number_/_size_ - unsigned number, suffixes `MB`, `Mb`, `mb`, `KB`, `Kb`, `kb`
+- _string_ - plain string or can have a structure
+- _path_ - to file, to directory
+- _paths_ - `;`-separated on Windows, `:`-separated on others
+
+
+### General, core
+| name | type | default | description |
+|------|------|---------|-------------|
+| OPENCV_SKIP_CPU_BASELINE_CHECK | non-null | | do not check that current CPU supports all features used by the build (baseline) |
+| OPENCV_CPU_DISABLE | `,` or `;`-separated | | disable code branches which use CPU features (dispatched code) |
+| OPENCV_SETUP_TERMINATE_HANDLER | bool | true (Windows) | use std::set_terminate to install own termination handler |
+| OPENCV_LIBVA_RUNTIME | file path | | libva for VA interoperability utils |
+| OPENCV_ENABLE_MEMALIGN | bool | true (except static analysis, memory sanitizer, fuzzying, _WIN32?) | enable aligned memory allocations |
+| OPENCV_BUFFER_AREA_ALWAYS_SAFE | bool | false | enable safe mode for multi-buffer allocations (each buffer separately) |
+| OPENCV_KMEANS_PARALLEL_GRANULARITY | num | 1000 | tune algorithm parallel work distribution parameter `parallel_for_(..., ..., ..., granularity)` |
+| OPENCV_DUMP_ERRORS | bool | true (Debug or Android), false (others) | print extra information on exception (log to Android) |
+| OPENCV_DUMP_CONFIG | non-null | | print build configuration to stderr (`getBuildInformation`) |
+| OPENCV_PYTHON_DEBUG | bool | false | enable extra warnings in Python bindings |
+| OPENCV_TEMP_PATH | non-null / path | `/tmp/` (Linux), `/data/local/tmp/` (Android), `GetTempPathA` (Windows) | directory for temporary files |
+| OPENCV_DATA_PATH_HINT | paths | | paths for findDataFile |
+| OPENCV_DATA_PATH | paths | | paths for findDataFile |
+| OPENCV_SAMPLES_DATA_PATH_HINT | paths | | paths for findDataFile |
+| OPENCV_SAMPLES_DATA_PATH | paths | | paths for findDataFile |
+
+Links:
+- https://github.com/opencv/opencv/wiki/CPU-optimizations-build-options
+
+
+### Logging
+| name | type | default | description |
+|------|------|---------|-------------|
+| ⭐ OPENCV_LOG_LEVEL | string | | logging level (see accepted values below) |
+| OPENCV_LOG_TIMESTAMP | bool | true | logging with timestamps |
+| OPENCV_LOG_TIMESTAMP_NS | bool | false | add nsec to logging timestamps |
+
+##### Levels:
+- `0`, `O`, `OFF`, `S`, `SILENT`, `DISABLE`, `DISABLED`
+- `F`, `FATAL`
+- `E`, `ERROR`
+- `W`, `WARNING`, `WARN`, `WARNINGS`
+- `I`, `INFO`
+- `D`, `DEBUG`
+- `V`, `VERBOSE`
+
+
+### core/parallel_for
+| name | type | default | description |
+|------|------|---------|-------------|
+| ⭐ OPENCV_FOR_THREADS_NUM | num | 0 | set number of threads |
+| OPENCV_THREAD_POOL_ACTIVE_WAIT_PAUSE_LIMIT | num | 16 | tune pthreads parallel_for backend |
+| OPENCV_THREAD_POOL_ACTIVE_WAIT_WORKER | num | 2000 | tune pthreads parallel_for backend |
+| OPENCV_THREAD_POOL_ACTIVE_WAIT_MAIN | num | 10000 | tune pthreads parallel_for backend |
+| OPENCV_THREAD_POOL_ACTIVE_WAIT_THREADS_LIMIT | num | 0 | tune pthreads parallel_for backend |
+| OPENCV_FOR_OPENMP_DYNAMIC_DISABLE | bool | false | use single OpenMP thread |
+
+
+### backends
+OPENCV_LEGACY_WAITKEY
+Some modules have multiple available backends, following variables allow choosing specific backend or changing default priorities in which backends will be probed (e.g. when opening a video file).
+
+| name | type | default | description |
+|------|------|---------|-------------|
+| OPENCV_PARALLEL_BACKEND | string | | choose specific paralel_for backend (one of `TBB`, `ONETBB`, `OPENMP`) |
+| OPENCV_PARALLEL_PRIORITY_${NAME} | num | | set backend priority, default is 1000 |
+| OPENCV_PARALLEL_PRIORITY_LIST | string, `,`-separated | | list of backends in priority order |
+| OPENCV_UI_BACKEND | string | | choose highgui backend for window rendering (one of `GTK`, `GTK3`, `GTK2`, `QT`, `WIN32`) |
+| OPENCV_UI_PRIORITY_${NAME} | num | | set highgui backend priority, default is 1000 |
+| OPENCV_UI_PRIORITY_LIST | string, `,`-separated | | list of hioghgui backends in priority order |
+| OPENCV_VIDEOIO_PRIORITY_${NAME} | num | | set videoio backend priority, default is 1000 |
+| OPENCV_VIDEOIO_PRIORITY_LIST | string, `,`-separated | | list of videoio backends in priority order |
+
+
+### plugins
+Some external dependencies can be detached into a dynamic library, which will be loaded at runtime (plugin). Following variables allow changing default search locations and naming pattern for these plugins.
+| name | type | default | description |
+|------|------|---------|-------------|
+| OPENCV_CORE_PLUGIN_PATH | paths | | directories to search for _core_ plugins |
+| OPENCV_CORE_PARALLEL_PLUGIN_${NAME} | string, glob | | parallel_for plugin library name (glob), e.g. default for TBB is "opencv_core_parallel_tbb*.so" |
+| OPENCV_DNN_PLUGIN_PATH | paths | | directories to search for _dnn_ plugins |
+| OPENCV_DNN_PLUGIN_${NAME} | string, glob | | parallel_for plugin library name (glob), e.g. default for TBB is "opencv_core_parallel_tbb*.so" |
+| OPENCV_CORE_PLUGIN_PATH | paths | | directories to search for _highgui_ plugins (YES it is CORE) |
+| OPENCV_UI_PLUGIN_${NAME} | string, glob | | _highgui_ plugin library name (glob) |
+| OPENCV_VIDEOIO_PLUGIN_PATH | paths | | directories to search for _videoio_ plugins |
+| OPENCV_VIDEOIO_PLUGIN_${NAME} | string, glob | | _videoio_ plugin library name (glob) |
+
+### OpenCL
+
+**Note:** OpenCL device specification format is `::`, e.g. `AMD:GPU:`
+
+| name | type | default | description |
+|------|------|---------|-------------|
+| OPENCV_OPENCL_RUNTIME | filepath or `disabled` | | path to OpenCL runtime library (e.g. `OpenCL.dll`, `libOpenCL.so`) |
+| ⭐ OPENCV_OPENCL_DEVICE | string or `disabled` | | choose specific OpenCL device. See specification format in the note above. See more details in the Links section. |
+| OPENCV_OPENCL_RAISE_ERROR | bool | false | raise exception if something fails during OpenCL kernel preparation and execution (Release builds only) |
+| OPENCV_OPENCL_ABORT_ON_BUILD_ERROR | bool | false | abort if OpenCL kernel compilation failed |
+| OPENCV_OPENCL_CACHE_ENABLE | bool | true | enable OpenCL kernel cache |
+| OPENCV_OPENCL_CACHE_WRITE | bool | true | allow writing to the cache, otherwise cache will be read-only |
+| OPENCV_OPENCL_CACHE_LOCK_ENABLE | bool | true | use .lock files to synchronize between multiple applications using the same OpenCL cache (may not work on network drives) |
+| OPENCV_OPENCL_CACHE_CLEANUP | bool | true | automatically remove old entries from cache (leftovers from older OpenCL runtimes) |
+| OPENCV_OPENCL_VALIDATE_BINARY_PROGRAMS | bool | false | validate loaded binary OpenCL kernels |
+| OPENCV_OPENCL_DISABLE_BUFFER_RECT_OPERATIONS | bool | true (Apple), false (others) | enable workaround for non-continuos data downloads |
+| OPENCV_OPENCL_BUILD_EXTRA_OPTIONS | string | | pass extra options to OpenCL kernel compilation |
+| OPENCV_OPENCL_ENABLE_MEM_USE_HOST_PTR | bool | true | workaround/optimization for buffer allocation |
+| OPENCV_OPENCL_ALIGNMENT_MEM_USE_HOST_PTR | num | 4 | parameter for OPENCV_OPENCL_ENABLE_MEM_USE_HOST_PTR |
+| OPENCV_OPENCL_DEVICE_MAX_WORK_GROUP_SIZE | num | 0 | allow to decrease maxWorkGroupSize |
+| OPENCV_OPENCL_PROGRAM_CACHE | num | 0 | limit number of programs in OpenCL kernel cache |
+| OPENCV_OPENCL_RAISE_ERROR_REUSE_ASYNC_KERNEL | bool | false | raise exception if async kernel failed |
+| OPENCV_OPENCL_BUFFERPOOL_LIMIT | num | 1 << 27 (Intel device), 0 (others) | limit memory used by buffer bool |
+| OPENCV_OPENCL_HOST_PTR_BUFFERPOOL_LIMIT | num | | same as OPENCV_OPENCL_BUFFERPOOL_LIMIT, but for HOST_PTR buffers |
+| OPENCV_OPENCL_BUFFER_FORCE_MAPPING | bool | false | force clEnqueueMapBuffer |
+| OPENCV_OPENCL_BUFFER_FORCE_COPYING | bool | false | force clEnqueueReadBuffer/clEnqueueWriteBuffer |
+| OPENCV_OPENCL_FORCE | bool | false | force running OpenCL kernel even if usual conditions are not met (e.g. dst.isUMat) |
+| OPENCV_OPENCL_PERF_CHECK_BYPASS | bool | false | force running OpenCL kernel even if usual performance-related conditions are not met (e.g. image is very small) |
+
+##### SVM (Shared Virtual Memory) - disabled by default
+| name | type | default | description |
+|------|------|---------|-------------|
+| OPENCV_OPENCL_SVM_DISABLE | bool | false | disable SVM |
+| OPENCV_OPENCL_SVM_FORCE_UMAT_USAGE | bool | false | |
+| OPENCV_OPENCL_SVM_DISABLE_UMAT_USAGE | bool | false | |
+| OPENCV_OPENCL_SVM_CAPABILITIES_MASK | num | | |
+| OPENCV_OPENCL_SVM_BUFFERPOOL_LIMIT | num | | same as OPENCV_OPENCL_BUFFERPOOL_LIMIT, but for SVM buffers |
+
+##### Links:
+- https://github.com/opencv/opencv/wiki/OpenCL-optimizations
+
+
+### Tracing/Profiling
+| name | type | default | description |
+|------|------|---------|-------------|
+| ⭐ OPENCV_TRACE | bool | false | enable trace |
+| OPENCV_TRACE_LOCATION | string | `OpenCVTrace` | trace file name ("${name}-$03d.txt") |
+| OPENCV_TRACE_DEPTH_OPENCV | num | 1 | |
+| OPENCV_TRACE_MAX_CHILDREN_OPENCV | num | 1000 | |
+| OPENCV_TRACE_MAX_CHILDREN | num | 1000 | |
+| OPENCV_TRACE_SYNC_OPENCL | bool | false | wait for OpenCL kernels to finish |
+| OPENCV_TRACE_ITT_ENABLE | bool | true | |
+| OPENCV_TRACE_ITT_PARENT | bool | false | set parentID for ITT task |
+| OPENCV_TRACE_ITT_SET_THREAD_NAME | bool | false | set name for OpenCV's threads "OpenCVThread-%03d" |
+
+##### Links:
+- https://github.com/opencv/opencv/wiki/Profiling-OpenCV-Applications
+
+
+##### Cache
+**Note:** Default tmp location is `%TMPDIR%` (Windows); `$XDG_CACHE_HOME`, `$HOME/.cache`, `/var/tmp`, `/tmp` (others)
+| name | type | default | description |
+|------|------|---------|-------------|
+| OPENCV_CACHE_SHOW_CLEANUP_MESSAGE | bool | true | show cache cleanup message |
+| OPENCV_DOWNLOAD_CACHE_DIR | path | default tmp location | cache directory for downloaded files (subdirectory `downloads`) |
+| OPENCV_DNN_IE_GPU_CACHE_DIR | path | default tmp location | cache directory for OpenVINO OpenCL kernels (subdirectory `dnn_ie_cache_${device}`) |
+| OPENCV_OPENCL_CACHE_DIR | path | default tmp location | cache directory for OpenCL kernels cache (subdirectory `opencl_cache`) |
+
+
+### dnn
+**Note:** In the table below `dump_base_name` equals to `ocv_dnn_net_%05d_%02d` where first argument is internal network ID and the second - dump level.
+| name | type | default | description |
+|------|------|---------|-------------|
+| OPENCV_DNN_BACKEND_DEFAULT | num | 3 (OpenCV) | set default DNN backend, see dnn.hpp for backends enumeration |
+| OPENCV_DNN_NETWORK_DUMP | num | 0 | level of information dumps, 0 - no dumps (default file name `${dump_base_name}.dot`) |
+| OPENCV_DNN_DISABLE_MEMORY_OPTIMIZATIONS | bool | false | |
+| OPENCV_DNN_CHECK_NAN_INF | bool | false | check for NaNs in layer outputs |
+| OPENCV_DNN_CHECK_NAN_INF_DUMP | bool | false | print layer data when NaN check has failed |
+| OPENCV_DNN_CHECK_NAN_INF_RAISE_ERROR | bool | false | also raise exception when NaN check has failed |
+| OPENCV_DNN_ONNX_USE_LEGACY_NAMES | bool | false | use ONNX node names as-is instead of "onnx_node!${node_name}" |
+| OPENCV_DNN_CUSTOM_ONNX_TYPE_INCLUDE_DOMAIN_NAME | bool | true | prepend layer domain to layer types ("domain.type") |
+| OPENCV_VULKAN_RUNTIME | file path | | set location of Vulkan runtime library for DNN Vulkan backend |
+| OPENCV_DNN_IE_SERIALIZE | bool | false | dump intermediate OpenVINO graph (default file names `${dump_base_name}_ngraph.xml`, `${dump_base_name}_ngraph.bin`) |
+| OPENCV_DNN_IE_EXTRA_PLUGIN_PATH | path | | path to extra OpenVINO plugins |
+| OPENCV_DNN_IE_VPU_TYPE | string | | Force using specific OpenVINO VPU device type ("Myriad2" or "MyriadX") |
+| OPENCV_TEST_DNN_IE_VPU_TYPE | string | | same as OPENCV_DNN_IE_VPU_TYPE, but for tests |
+| OPENCV_DNN_INFERENCE_ENGINE_HOLD_PLUGINS | bool | true | always hold one existing OpenVINO instance to avoid crashes on unloading |
+| OPENCV_DNN_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND | bool | true (Windows), false (other) | another OpenVINO lifetime workaround |
+| OPENCV_DNN_OPENCL_ALLOW_ALL_DEVICES | bool | false | allow running on CPU devices, allow FP16 on non-Intel device |
+| OPENCV_OCL4DNN_CONVOLUTION_IGNORE_INPUT_DIMS_4_CHECK | bool | false | workaround for OpenCL backend, see https://github.com/opencv/opencv/issues/20833 |
+| OPENCV_OCL4DNN_WORKAROUND_IDLF | bool | true | another workaround for OpenCL backend |
+| OPENCV_OCL4DNN_CONFIG_PATH | path | | path to kernel configuration cache for auto-tuning (must be existing directory), set this variable to enable auto-tuning |
+| OPENCV_OCL4DNN_DISABLE_AUTO_TUNING | bool | false | disable auto-tuning |
+| OPENCV_OCL4DNN_FORCE_AUTO_TUNING | bool | false | force auto-tuning |
+| OPENCV_OCL4DNN_TEST_ALL_KERNELS | num | 0 | test convolution kernels, number of iterations (auto-tuning) |
+| OPENCV_OCL4DNN_DUMP_FAILED_RESULT | bool | false | dump extra information on errors (auto-tuning) |
+| OPENCV_OCL4DNN_TUNING_RAISE_CHECK_ERROR | bool | false | raise exception on errors (auto-tuning) |
+
+
+### Tests
+| name | type | default | description |
+|------|------|---------|-------------|
+| ⭐ OPENCV_TEST_DATA_PATH | dir path | | set test data search location (e.g. `/home/user/opencv_extra/testdata`) |
+| ⭐ OPENCV_DNN_TEST_DATA_PATH | dir path | `$OPENCV_TEST_DATA_PATH/dnn` | set DNN model search location for tests (used by _dnn_, _gapi_, _objdetect_, _video_ modules) |
+| OPENCV_OPEN_MODEL_ZOO_DATA_PATH | dir path | `$OPENCV_DNN_TEST_DATA_PATH/omz_intel_models` | set OpenVINO models search location for tests (used by _dnn_, _gapi_ modules) |
+| INTEL_CVSDK_DIR | | | some _dnn_ tests can search OpenVINO models here too |
+| OPENCV_TEST_DEBUG | num | 0 | debug level for tests, same as `--test_debug` (0 - no debug (default), 1 - basic test debug information, >1 - extra debug information) |
+| OPENCV_TEST_REQUIRE_DATA | bool | false | same as `--test_require_data` option (fail on missing non-required test data instead of skip) |
+| OPENCV_TEST_CHECK_OPTIONAL_DATA | bool | false | assert when optional data is not found |
+| OPENCV_IPP_CHECK | bool | false | default value for `--test_ipp_check` and `--perf_ipp_check` |
+| OPENCV_PERF_VALIDATION_DIR | dir path | | location of files read/written by `--perf_read_validation_results`/`--perf_write_validation_results` |
+| ⭐ OPENCV_PYTEST_FILTER | string (glob) | | test filter for Python tests |
+
+##### Links:
+* https://github.com/opencv/opencv/wiki/QA_in_OpenCV
+
+
+### videoio
+**Note:** extra FFmpeg options should be pased in form `key;value|key;value|key;value`, for example `hwaccel;cuvid|video_codec;h264_cuvid|vsync;0` or `vcodec;x264|vprofile;high|vlevel;4.0`
+
+| name | type | default | description |
+|------|------|---------|-------------|
+| ⭐ OPENCV_FFMPEG_CAPTURE_OPTIONS | string (see note) | | extra options for VideoCapture FFmpeg backend |
+| ⭐ OPENCV_FFMPEG_WRITER_OPTIONS | string (see note) | | extra options for VideoWriter FFmpeg backend |
+| OPENCV_FFMPEG_THREADS | num | | set FFmpeg thread count |
+| OPENCV_FFMPEG_DEBUG | non-null | | enable logging messages from FFmpeg |
+| OPENCV_FFMPEG_LOGLEVEL | num | | set FFmpeg logging level |
+| OPENCV_FFMPEG_DLL_DIR | dir path | | directory with FFmpeg plugin (legacy) |
+| OPENCV_FFMPEG_IS_THREAD_SAFE | bool | false | enabling this option will turn off thread safety locks in the FFmpeg backend (use only if you are sure FFmpeg is built with threading support, tested on Linux) |
+| OPENCV_FFMPEG_READ_ATTEMPTS | num | 4096 | number of failed `av_read_frame` attempts before failing read procedure |
+| OPENCV_FFMPEG_DECODE_ATTEMPTS | num | 64 | number of failed `avcodec_receive_frame` attempts before failing decoding procedure |
+| OPENCV_VIDEOIO_GSTREAMER_CALL_DEINIT | bool | false | close GStreamer instance on end |
+| OPENCV_VIDEOIO_GSTREAMER_START_MAINLOOP | bool | false | start GStreamer loop in separate thread |
+| OPENCV_VIDEOIO_MFX_IMPL | num | | set specific MFX implementation (see MFX docs for enumeration) |
+| OPENCV_VIDEOIO_MFX_EXTRA_SURFACE_NUM | num | 1 | add extra surfaces to the surface pool |
+| OPENCV_VIDEOIO_MFX_POOL_TIMEOUT | num | 1 | timeout for waiting for free surface from the pool (in seconds) |
+| OPENCV_VIDEOIO_MFX_BITRATE_DIVISOR | num | 300 | this option allows to tune encoding bitrate (video quality/size) |
+| OPENCV_VIDEOIO_MFX_WRITER_TIMEOUT | num | 1 | timeout for encoding operation (in seconds) |
+| OPENCV_VIDEOIO_MSMF_ENABLE_HW_TRANSFORMS | bool | true | allow HW-accelerated transformations (DXVA) in MediaFoundation processing graph (may slow down camera probing process) |
+| OPENCV_DSHOW_DEBUG | non-null | | enable verbose logging in the DShow backend |
+| OPENCV_DSHOW_SAVEGRAPH_FILENAME | file path | | enable processing graph tump in the DShow backend |
+| OPENCV_VIDEOIO_V4L_RANGE_NORMALIZED | bool | false | use (0, 1) range for properties (V4L) |
+| OPENCV_VIDEOIO_V4L_SELECT_TIMEOUT | num | 10 | timeout for select call (in seconds) (V4L) |
+| OPENCV_VIDEOCAPTURE_DEBUG | bool | false | enable debug messages for VideoCapture |
+| OPENCV_VIDEOWRITER_DEBUG | bool | false | enable debug messages for VideoWriter |
+| ⭐ OPENCV_VIDEOIO_DEBUG | bool | false | debug messages for both VideoCapture and VideoWriter |
+
+##### videoio tests
+| name | type | default | description |
+|------|------|---------|-------------|
+| OPENCV_TEST_VIDEOIO_BACKEND_REQUIRE_FFMPEG | | | test app will exit if no FFmpeg backend is available |
+| OPENCV_TEST_V4L2_VIVID_DEVICE | file path | | path to VIVID virtual camera device for V4L2 test (e.g. `/dev/video5`) |
+| OPENCV_TEST_PERF_CAMERA_LIST | paths | | cameras to use in performance test (waitAny_V4L test) |
+| OPENCV_TEST_CAMERA_%d_FPS | num | | fps to set for N-th camera (0-based index) (waitAny_V4L test) |
+
+
+### gapi
+| name | type | default | description |
+|------|------|---------|-------------|
+| ⭐ GRAPH_DUMP_PATH | file path | | dump graph (dot format) |
+| PIPELINE_MODELS_PATH | dir path | | pipeline_modeling_tool sample application uses this var |
+| OPENCV_GAPI_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND | bool | true (Windows, Apple), false (others) | similar to OPENCV_DNN_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND |
+
+##### gapi tests/samples
+| name | type | default | description |
+|------|------|---------|-------------|
+| PLAIDML_DEVICE | string | | specific to PlaidML backend test |
+| PLAIDML_TARGET | string | | specific to PlaidML backend test |
+| OPENCV_GAPI_ONNX_MODEL_PATH | dir path | | search location for ONNX models test |
+| OPENCV_TEST_FREETYPE_FONT_PATH | file path | | location of TrueType font for one of tests |
+
+##### Links:
+* https://github.com/opencv/opencv/wiki/Using-G-API-with-OpenVINO-Toolkit
+* https://github.com/opencv/opencv/wiki/Using-G-API-with-MS-ONNX-Runtime
+
+
+### highgui
+
+| name | type | default | description |
+|------|------|---------|-------------|
+| OPENCV_LEGACY_WAITKEY | non-null | | switch `waitKey` return result (default behavior: `return code & 0xff` (or -1), legacy behavior: `return code`) |
+| $XDG_RUNTIME_DIR | | | Wayland backend specific - create shared memory-mapped file for interprocess communication (named `opencv-shared-??????`) |
+
+
+### imgproc
+| name | type | default | description |
+|------|------|---------|-------------|
+| OPENCV_OPENCL_IMGPROC_MORPH_SPECIAL_KERNEL | bool | true (Apple), false (others) | use special OpenCL kernel for small morph kernel (Intel devices) |
+| OPENCV_GAUSSIANBLUR_CHECK_BITEXACT_KERNELS | bool | false | validate Gaussian kernels before running (src is CV_16U, bit-exact version) |
+
+
+### imgcodecs
+| name | type | default | description |
+|------|------|---------|-------------|
+| OPENCV_IMGCODECS_AVIF_MAX_FILE_SIZE | num | 64MB | limit input AVIF size |
+| OPENCV_IMGCODECS_WEBP_MAX_FILE_SIZE | num | 64MB | limit input WEBM size |
+| OPENCV_IO_MAX_IMAGE_PARAMS | num | 50 | limit maximum allowed number of parameters in imwrite and imencode |
+| OPENCV_IO_MAX_IMAGE_WIDTH | num | 1 << 20, limit input image size to avoid large memory allocations | |
+| OPENCV_IO_MAX_IMAGE_HEIGHT | num | 1 << 20 | |
+| OPENCV_IO_MAX_IMAGE_PIXELS | num | 1 << 30 | |
+| OPENCV_IO_ENABLE_OPENEXR | bool | true (set build option OPENCV_IO_FORCE_OPENEXR or use external OpenEXR), false (otherwise) | enable OpenEXR backend |
+| OPENCV_IO_ENABLE_JASPER | bool | true (set build option OPENCV_IO_FORCE_JASPER), false (otherwise) | enable Jasper backend |
diff --git a/doc/tutorials/introduction/table_of_content_introduction.markdown b/doc/tutorials/introduction/table_of_content_introduction.markdown
index 8fa89d7d7f..4df7ad2c78 100644
--- a/doc/tutorials/introduction/table_of_content_introduction.markdown
+++ b/doc/tutorials/introduction/table_of_content_introduction.markdown
@@ -3,6 +3,7 @@ Introduction to OpenCV {#tutorial_table_of_content_introduction}
- @subpage tutorial_general_install
- @subpage tutorial_config_reference
+- @subpage tutorial_env_reference
##### Linux
- @subpage tutorial_linux_install
diff --git a/modules/3d/src/usac/essential_solver.cpp b/modules/3d/src/usac/essential_solver.cpp
index 6dad2a4b88..504fec6ab5 100644
--- a/modules/3d/src/usac/essential_solver.cpp
+++ b/modules/3d/src/usac/essential_solver.cpp
@@ -142,7 +142,7 @@ public:
}
std::vector c(11), rs;
- // filling coefficients of 10-degree polynomial satysfying zero-determinant constraint of essential matrix, ie., det(E) = 0
+ // filling coefficients of 10-degree polynomial satisfying zero-determinant constraint of essential matrix, ie., det(E) = 0
// based on "An Efficient Solution to the Five-Point Relative Pose Problem" (David Nister)
// same as in five-point.cpp
c[10] = (b[0]*b[17]*b[34]+b[26]*b[4]*b[21]-b[26]*b[17]*b[8]-b[13]*b[4]*b[34]-b[0]*b[21]*b[30]+b[13]*b[30]*b[8]);
diff --git a/modules/3d/src/usac/ransac_solvers.cpp b/modules/3d/src/usac/ransac_solvers.cpp
index d1748fc24e..35c09950cc 100644
--- a/modules/3d/src/usac/ransac_solvers.cpp
+++ b/modules/3d/src/usac/ransac_solvers.cpp
@@ -322,7 +322,7 @@ void UniversalRANSAC::initialize (int state, Ptr &min_solver, Ptr
params->getUpperIncompleteOfSigmaQuantile()); break;
case ScoreMethod::SCORE_METHOD_LMEDS :
quality = LMedsQuality::create(points_size, threshold, error); break;
- default: CV_Error(cv::Error::StsNotImplemented, "Score is not imeplemeted!");
+ default: CV_Error(cv::Error::StsNotImplemented, "Score is not implemented!");
}
const auto is_ge_solver = params->getRansacSolver() == GEM_SOLVER;
diff --git a/modules/3d/src/usac/sampler.cpp b/modules/3d/src/usac/sampler.cpp
index 2095ee8b4d..1938bde918 100644
--- a/modules/3d/src/usac/sampler.cpp
+++ b/modules/3d/src/usac/sampler.cpp
@@ -62,8 +62,8 @@ Ptr UniformSampler::create(int state, int sample_size_, int poin
/////////////////////////////////// PROSAC (SIMPLE) SAMPLER ///////////////////////////////////////
/*
* PROSAC (simple) sampler does not use array of precalculated T_n (n is subset size) samples, but computes T_n for
-* specific n directy in generateSample() function.
-* Also, the stopping length (or maximum subset size n*) by default is set to points_size (N) and does not updating
+* specific n directly in generateSample() function.
+* Also, the stopping length (or maximum subset size n*) by default is set to points_size (N) and does not update
* during computation.
*/
class ProsacSimpleSamplerImpl : public ProsacSimpleSampler {
@@ -176,7 +176,7 @@ protected:
// In our experiments, the parameter was set to T_N = 200000
int growth_max_samples;
- // how many time PROSAC generateSample() was called
+ // how many times PROSAC generateSample() was called
int kth_sample_number;
Ptr random_gen;
public:
@@ -488,7 +488,7 @@ public:
points_large_neighborhood_size = 0;
- // find indicies of points that have sufficient neighborhood (at least sample_size-1)
+ // find indices of points that have sufficient neighborhood (at least sample_size-1)
for (int pt_idx = 0; pt_idx < points_size; pt_idx++)
if ((int)neighborhood_graph->getNeighbors(pt_idx).size() >= sample_size-1)
points_large_neighborhood[points_large_neighborhood_size++] = pt_idx;
diff --git a/modules/3d/src/usac/termination.cpp b/modules/3d/src/usac/termination.cpp
index 803b060e41..26a9e331ed 100644
--- a/modules/3d/src/usac/termination.cpp
+++ b/modules/3d/src/usac/termination.cpp
@@ -19,7 +19,7 @@ public:
/*
* Get upper bound iterations for any sample number
- * n is points size, w is inlier ratio, p is desired probability, k is expceted number of iterations.
+ * n is points size, w is inlier ratio, p is desired probability, k is expected number of iterations.
* 1 - p = (1 - w^n)^k,
* k = log_(1-w^n) (1-p)
* k = ln (1-p) / ln (1-w^n)
diff --git a/modules/3d/test/test_solvepnp_ransac.cpp b/modules/3d/test/test_solvepnp_ransac.cpp
index 60c765b8af..be6f1342a7 100644
--- a/modules/3d/test/test_solvepnp_ransac.cpp
+++ b/modules/3d/test/test_solvepnp_ransac.cpp
@@ -1531,8 +1531,8 @@ TEST(Calib3d_SolvePnP, generic)
}
else
{
- p3f = p3f_;
- p2f = p2f_;
+ p3f = vector(p3f_.begin(), p3f_.end());
+ p2f = vector(p2f_.begin(), p2f_.end());
}
vector reprojectionErrors;
diff --git a/modules/calib3d/src/usac/bundle.cpp b/modules/calib3d/src/usac/bundle.cpp
new file mode 100644
index 0000000000..a621490575
--- /dev/null
+++ b/modules/calib3d/src/usac/bundle.cpp
@@ -0,0 +1,308 @@
+// Copyright (c) 2020, Viktor Larsson
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// * Neither the name of the copyright holder nor the
+// names of its contributors may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
+// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "../precomp.hpp"
+#include "../usac.hpp"
+
+namespace cv { namespace usac {
+class MlesacLoss {
+ public:
+ MlesacLoss(double threshold) : squared_thr(threshold * threshold), norm_thr(squared_thr*3), one_over_thr(1/norm_thr), inv_sq_thr(1/squared_thr) {}
+ double loss(double r2) const {
+ return r2 < norm_thr ? r2 * one_over_thr - 1 : 0;
+ }
+ double weight(double r2) const {
+ // use Cauchly weight
+ return 1.0 / (1.0 + r2 * inv_sq_thr);
+ }
+ const double squared_thr;
+ private:
+ const double norm_thr, one_over_thr, inv_sq_thr;
+};
+
+class RelativePoseJacobianAccumulator {
+private:
+ const Mat* correspondences;
+ const std::vector &sample;
+ const int sample_size;
+ const MlesacLoss &loss_fn;
+ const double *weights;
+
+public:
+ RelativePoseJacobianAccumulator(
+ const Mat& correspondences_,
+ const std::vector &sample_,
+ const int sample_size_,
+ const MlesacLoss &l,
+ const double *w = nullptr) :
+ correspondences(&correspondences_),
+ sample(sample_),
+ sample_size(sample_size_),
+ loss_fn(l),
+ weights(w) {}
+
+ Matx33d essential_from_motion(const CameraPose &pose) const {
+ return Matx33d(0.0, -pose.t(2), pose.t(1),
+ pose.t(2), 0.0, -pose.t(0),
+ -pose.t(1), pose.t(0), 0.0) * pose.R;
+ }
+
+ double residual(const CameraPose &pose) const {
+ const Matx33d E = essential_from_motion(pose);
+ const float m11=static_cast(E(0,0)), m12=static_cast(E(0,1)), m13=static_cast(E(0,2));
+ const float m21=static_cast(E(1,0)), m22=static_cast(E(1,1)), m23=static_cast(E(1,2));
+ const float m31=static_cast(E(2,0)), m32=static_cast(E(2,1)), m33=static_cast(E(2,2));
+ const auto * const pts = (float *) correspondences->data;
+ double cost = 0.0;
+ for (int k = 0; k < sample_size; ++k) {
+ const int idx = 4*sample[k];
+ const float x1=pts[idx], y1=pts[idx+1], x2=pts[idx+2], y2=pts[idx+3];
+ const float F_pt1_x = m11 * x1 + m12 * y1 + m13,
+ F_pt1_y = m21 * x1 + m22 * y1 + m23;
+ const float pt2_F_x = x2 * m11 + y2 * m21 + m31,
+ pt2_F_y = x2 * m12 + y2 * m22 + m32;
+ const float pt2_F_pt1 = x2 * F_pt1_x + y2 * F_pt1_y + m31 * x1 + m32 * y1 + m33;
+ const float r2 = pt2_F_pt1 * pt2_F_pt1 / (F_pt1_x * F_pt1_x + F_pt1_y * F_pt1_y +
+ pt2_F_x * pt2_F_x + pt2_F_y * pt2_F_y);
+ if (weights == nullptr)
+ cost += loss_fn.loss(r2);
+ else cost += weights[k] * loss_fn.loss(r2);
+ }
+ return cost;
+ }
+
+ void accumulate(const CameraPose &pose, Matx &JtJ, Matx &Jtr, Matx &tangent_basis) const {
+ const auto * const pts = (float *) correspondences->data;
+ // We start by setting up a basis for the updates in the translation (orthogonal to t)
+ // We find the minimum element of t and cross product with the corresponding basis vector.
+ // (this ensures that the first cross product is not close to the zero vector)
+ Vec3d tangent_basis_col0;
+ if (std::abs(pose.t(0)) < std::abs(pose.t(1))) {
+ // x < y
+ if (std::abs(pose.t(0)) < std::abs(pose.t(2))) {
+ tangent_basis_col0 = pose.t.cross(Vec3d(1,0,0));
+ } else {
+ tangent_basis_col0 = pose.t.cross(Vec3d(0,0,1));
+ }
+ } else {
+ // x > y
+ if (std::abs(pose.t(1)) < std::abs(pose.t(2))) {
+ tangent_basis_col0 = pose.t.cross(Vec3d(0,1,0));
+ } else {
+ tangent_basis_col0 = pose.t.cross(Vec3d(0,0,1));
+ }
+ }
+ tangent_basis_col0 /= norm(tangent_basis_col0);
+ Vec3d tangent_basis_col1 = pose.t.cross(tangent_basis_col0);
+ tangent_basis_col1 /= norm(tangent_basis_col1);
+ for (int i = 0; i < 3; i++) {
+ tangent_basis(i,0) = tangent_basis_col0(i);
+ tangent_basis(i,1) = tangent_basis_col1(i);
+ }
+
+ const Matx33d E = essential_from_motion(pose);
+
+ // Matrices contain the jacobians of E w.r.t. the rotation and translation parameters
+ // Each column is vec(E*skew(e_k)) where e_k is k:th basis vector
+ const Matx dR = {0., -E(0,2), E(0,1),
+ 0., -E(1,2), E(1,1),
+ 0., -E(2,2), E(2,1),
+ E(0,2), 0., -E(0,0),
+ E(1,2), 0., -E(1,0),
+ E(2,2), 0., -E(2,0),
+ -E(0,1), E(0,0), 0.,
+ -E(1,1), E(1,0), 0.,
+ -E(2,1), E(2,0), 0.};
+
+ Matx dt;
+ // Each column is vec(skew(tangent_basis[k])*R)
+ for (int i = 0; i <= 2; i+=1) {
+ const Vec3d r_i(pose.R(0,i), pose.R(1,i), pose.R(2,i));
+ for (int j = 0; j <= 1; j+= 1) {
+ const Vec3d v = (j == 0 ? tangent_basis_col0 : tangent_basis_col1).cross(r_i);
+ for (int k = 0; k < 3; k++) {
+ dt(3*i+k,j) = v[k];
+ }
+ }
+ }
+
+ for (int k = 0; k < sample_size; ++k) {
+ const auto point_idx = 4*sample[k];
+ const Vec3d pt1 (pts[point_idx], pts[point_idx+1], 1), pt2 (pts[point_idx+2], pts[point_idx+3], 1);
+ const double C = pt2.dot(E * pt1);
+
+ // J_C is the Jacobian of the epipolar constraint w.r.t. the image points
+ const Vec4d J_C ((E.col(0).t() * pt2)[0], (E.col(1).t() * pt2)[0], (E.row(0) * pt1)[0], (E.row(1) * pt1)[0]);
+ const double nJ_C = norm(J_C);
+ const double inv_nJ_C = 1.0 / nJ_C;
+ const double r = C * inv_nJ_C;
+
+ if (r*r > loss_fn.squared_thr) continue;
+
+ // Compute weight from robust loss function (used in the IRLS)
+ double weight = loss_fn.weight(r * r) / sample_size;
+ if (weights != nullptr)
+ weight = weights[k] * weight;
+
+ if(weight < DBL_EPSILON)
+ continue;
+
+ // Compute Jacobian of Sampson error w.r.t the fundamental/essential matrix (3x3)
+ Matx dF (pt1(0) * pt2(0), pt1(0) * pt2(1), pt1(0), pt1(1) * pt2(0), pt1(1) * pt2(1), pt1(1), pt2(0), pt2(1), 1.0);
+ const double s = C * inv_nJ_C * inv_nJ_C;
+ dF(0) -= s * (J_C(2) * pt1(0) + J_C(0) * pt2(0));
+ dF(1) -= s * (J_C(3) * pt1(0) + J_C(0) * pt2(1));
+ dF(2) -= s * (J_C(0));
+ dF(3) -= s * (J_C(2) * pt1(1) + J_C(1) * pt2(0));
+ dF(4) -= s * (J_C(3) * pt1(1) + J_C(1) * pt2(1));
+ dF(5) -= s * (J_C(1));
+ dF(6) -= s * (J_C(2));
+ dF(7) -= s * (J_C(3));
+ dF *= inv_nJ_C;
+
+ // and then w.r.t. the pose parameters (rotation + tangent basis for translation)
+ const Matx13d dFdR = dF * dR;
+ const Matx12d dFdt = dF * dt;
+ const Matx J (dFdR(0), dFdR(1), dFdR(2), dFdt(0), dFdt(1));
+
+ // Accumulate into JtJ and Jtr
+ Jtr += weight * C * inv_nJ_C * J.t();
+ JtJ(0, 0) += weight * (J(0) * J(0));
+ JtJ(1, 0) += weight * (J(1) * J(0));
+ JtJ(1, 1) += weight * (J(1) * J(1));
+ JtJ(2, 0) += weight * (J(2) * J(0));
+ JtJ(2, 1) += weight * (J(2) * J(1));
+ JtJ(2, 2) += weight * (J(2) * J(2));
+ JtJ(3, 0) += weight * (J(3) * J(0));
+ JtJ(3, 1) += weight * (J(3) * J(1));
+ JtJ(3, 2) += weight * (J(3) * J(2));
+ JtJ(3, 3) += weight * (J(3) * J(3));
+ JtJ(4, 0) += weight * (J(4) * J(0));
+ JtJ(4, 1) += weight * (J(4) * J(1));
+ JtJ(4, 2) += weight * (J(4) * J(2));
+ JtJ(4, 3) += weight * (J(4) * J(3));
+ JtJ(4, 4) += weight * (J(4) * J(4));
+ }
+ }
+};
+
+bool satisfyCheirality (const Matx33d& R, const Vec3d &t, const Vec3d &x1, const Vec3d &x2) {
+ // This code assumes that x1 and x2 are unit vectors
+ const auto Rx1 = R * x1;
+ // lambda_2 * x2 = R * ( lambda_1 * x1 ) + t
+ // [1 a; a 1] * [lambda1; lambda2] = [b1; b2]
+ // [lambda1; lambda2] = [1 -a; -a 1] * [b1; b2] / (1 - a*a)
+ const double a = -Rx1.dot(x2), b1 = -Rx1.dot(t), b2 = x2.dot(t);
+ // Note that we drop the factor 1.0/(1-a*a) since it is always positive.
+ return (b1 - a * b2 > 0) && (-a * b1 + b2 > 0);
+}
+
+int refine_relpose(const Mat &correspondences_,
+ const std::vector &sample_,
+ const int sample_size_,
+ CameraPose *pose,
+ const BundleOptions &opt,
+ const double* weights) {
+ MlesacLoss loss_fn(opt.loss_scale);
+ RelativePoseJacobianAccumulator accum(correspondences_, sample_, sample_size_, loss_fn, weights);
+ // return lm_5dof_impl(accum, pose, opt);
+
+ Matx JtJ;
+ Matx Jtr;
+ Matx tangent_basis;
+ Matx33d sw = Matx33d::zeros();
+ double lambda = opt.initial_lambda;
+
+ // Compute initial cost
+ double cost = accum.residual(*pose);
+ bool recompute_jac = true;
+ int iter;
+ for (iter = 0; iter < opt.max_iterations; ++iter) {
+ // We only recompute jacobian and residual vector if last step was successful
+ if (recompute_jac) {
+ std::fill(JtJ.val, JtJ.val+25, 0);
+ std::fill(Jtr.val, Jtr.val +5, 0);
+ accum.accumulate(*pose, JtJ, Jtr, tangent_basis);
+ if (norm(Jtr) < opt.gradient_tol)
+ break;
+ }
+
+ // Add dampening
+ JtJ(0, 0) += lambda;
+ JtJ(1, 1) += lambda;
+ JtJ(2, 2) += lambda;
+ JtJ(3, 3) += lambda;
+ JtJ(4, 4) += lambda;
+
+ Matx sol;
+ Matx JtJ_symm = JtJ;
+ for (int i = 0; i < 5; i++)
+ for (int j = i+1; j < 5; j++)
+ JtJ_symm(i,j) = JtJ(j,i);
+
+ const bool success = solve(-JtJ_symm, Jtr, sol);
+ if (!success || norm(sol) < opt.step_tol)
+ break;
+
+ Vec3d w (sol(0,0), sol(1,0), sol(2,0));
+ const double theta = norm(w);
+ w /= theta;
+ const double a = std::sin(theta);
+ const double b = std::cos(theta);
+ sw(0, 1) = -w(2);
+ sw(0, 2) = w(1);
+ sw(1, 2) = -w(0);
+ sw(1, 0) = w(2);
+ sw(2, 0) = -w(1);
+ sw(2, 1) = w(0);
+
+ CameraPose pose_new;
+ pose_new.R = pose->R + pose->R * (a * sw + (1 - b) * sw * sw);
+ // In contrast to the 6dof case, we don't apply R here
+ // (since this can already be added into tangent_basis)
+ pose_new.t = pose->t + Vec3d(Mat(tangent_basis * Matx21d(sol(3,0), sol(4,0))));
+ double cost_new = accum.residual(pose_new);
+
+ if (cost_new < cost) {
+ *pose = pose_new;
+ lambda /= 10;
+ cost = cost_new;
+ recompute_jac = true;
+ } else {
+ JtJ(0, 0) -= lambda;
+ JtJ(1, 1) -= lambda;
+ JtJ(2, 2) -= lambda;
+ JtJ(3, 3) -= lambda;
+ JtJ(4, 4) -= lambda;
+ lambda *= 10;
+ recompute_jac = false;
+ }
+ }
+ return iter;
+}
+}}
\ No newline at end of file
diff --git a/modules/core/include/opencv2/core/cuda.hpp b/modules/core/include/opencv2/core/cuda.hpp
index 9c948ce00a..5dca06df98 100644
--- a/modules/core/include/opencv2/core/cuda.hpp
+++ b/modules/core/include/opencv2/core/cuda.hpp
@@ -577,7 +577,7 @@ CV_EXPORTS_W void ensureSizeIsEnough(int rows, int cols, int type, OutputArray a
*/
CV_EXPORTS_W GpuMat inline createGpuMatFromCudaMemory(int rows, int cols, int type, size_t cudaMemoryAddress, size_t step = Mat::AUTO_STEP) {
return GpuMat(rows, cols, type, reinterpret_cast(cudaMemoryAddress), step);
-};
+}
/** @overload
@param size 2D array size: Size(cols, rows). In the Size() constructor, the number of rows and the number of columns go in the reverse order.
@@ -588,7 +588,7 @@ CV_EXPORTS_W GpuMat inline createGpuMatFromCudaMemory(int rows, int cols, int ty
*/
CV_EXPORTS_W inline GpuMat createGpuMatFromCudaMemory(Size size, int type, size_t cudaMemoryAddress, size_t step = Mat::AUTO_STEP) {
return GpuMat(size, type, reinterpret_cast(cudaMemoryAddress), step);
-};
+}
/** @brief BufferPool for use with CUDA streams
diff --git a/modules/core/include/opencv2/core/fast_math.hpp b/modules/core/include/opencv2/core/fast_math.hpp
index 47a2948222..08401afbb8 100644
--- a/modules/core/include/opencv2/core/fast_math.hpp
+++ b/modules/core/include/opencv2/core/fast_math.hpp
@@ -201,7 +201,7 @@ cvRound( double value )
{
#if defined CV_INLINE_ROUND_DBL
CV_INLINE_ROUND_DBL(value);
-#elif (defined _MSC_VER && defined _M_X64) && !defined(__CUDACC__)
+#elif ((defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __SSE2__)) && !defined(__CUDACC__)
__m128d t = _mm_set_sd( value );
return _mm_cvtsd_si32(t);
#elif defined _MSC_VER && defined _M_IX86
@@ -323,7 +323,7 @@ CV_INLINE int cvRound(float value)
{
#if defined CV_INLINE_ROUND_FLT
CV_INLINE_ROUND_FLT(value);
-#elif (defined _MSC_VER && defined _M_X64) && !defined(__CUDACC__)
+#elif ((defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __SSE2__)) && !defined(__CUDACC__)
__m128 t = _mm_set_ss( value );
return _mm_cvtss_si32(t);
#elif defined _MSC_VER && defined _M_IX86
@@ -354,7 +354,7 @@ CV_INLINE int cvFloor( float value )
#if defined CV__FASTMATH_ENABLE_GCC_MATH_BUILTINS || \
defined CV__FASTMATH_ENABLE_CLANG_MATH_BUILTINS
return (int)__builtin_floorf(value);
-#elif defined __loongarch
+#elif defined __loongarch__
int i;
float tmp;
__asm__ ("ftintrm.w.s %[tmp], %[in] \n\t"
@@ -381,7 +381,7 @@ CV_INLINE int cvCeil( float value )
#if defined CV__FASTMATH_ENABLE_GCC_MATH_BUILTINS || \
defined CV__FASTMATH_ENABLE_CLANG_MATH_BUILTINS
return (int)__builtin_ceilf(value);
-#elif defined __loongarch
+#elif defined __loongarch__
int i;
float tmp;
__asm__ ("ftintrp.w.s %[tmp], %[in] \n\t"
diff --git a/modules/core/include/opencv2/core/hal/intrin_rvv_scalable.hpp b/modules/core/include/opencv2/core/hal/intrin_rvv_scalable.hpp
index 60066ba041..dab82489f8 100644
--- a/modules/core/include/opencv2/core/hal/intrin_rvv_scalable.hpp
+++ b/modules/core/include/opencv2/core/hal/intrin_rvv_scalable.hpp
@@ -1651,6 +1651,10 @@ inline v_uint32 v_popcount(const v_uint32& a)
{
return v_hadd(v_hadd(v_popcount(vreinterpret_u8m1(a))));
}
+inline v_uint64 v_popcount(const v_uint64& a)
+{
+ return v_hadd(v_hadd(v_hadd(v_popcount(vreinterpret_u8m1(a)))));
+}
inline v_uint8 v_popcount(const v_int8& a)
{
@@ -1664,6 +1668,11 @@ inline v_uint32 v_popcount(const v_int32& a)
{
return v_popcount(v_abs(a));\
}
+inline v_uint64 v_popcount(const v_int64& a)
+{
+ // max(0 - a) is used, since v_abs does not support 64-bit integers.
+ return v_popcount(v_reinterpret_as_u64(vmax(a, v_sub(v_setzero_s64(), a), VTraits::vlanes())));
+}
//////////// SignMask ////////////
diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp
index 67653526c1..a5f244e8c0 100644
--- a/modules/core/include/opencv2/core/mat.hpp
+++ b/modules/core/include/opencv2/core/mat.hpp
@@ -1288,15 +1288,36 @@ public:
t(); // finally, transpose the Nx3 matrix.
// This involves copying all the elements
@endcode
+ 3-channel 2x2 matrix reshaped to 1-channel 4x3 matrix, each column has values from one of original channels:
+ @code
+ Mat m(Size(2, 2), CV_8UC3, Scalar(1, 2, 3));
+ vector new_shape {4, 3};
+ m = m.reshape(1, new_shape);
+ @endcode
+ or:
+ @code
+ Mat m(Size(2, 2), CV_8UC3, Scalar(1, 2, 3));
+ const int new_shape[] = {4, 3};
+ m = m.reshape(1, 2, new_shape);
+ @endcode
@param cn New number of channels. If the parameter is 0, the number of channels remains the same.
@param rows New number of rows. If the parameter is 0, the number of rows remains the same.
*/
Mat reshape(int cn, int rows=0) const;
- /** @overload */
+ /** @overload
+ * @param cn New number of channels. If the parameter is 0, the number of channels remains the same.
+ * @param newndims New number of dimentions.
+ * @param newsz Array with new matrix size by all dimentions. If some sizes are zero,
+ * the original sizes in those dimensions are presumed.
+ */
Mat reshape(int cn, int newndims, const int* newsz) const;
- /** @overload */
+ /** @overload
+ * @param cn New number of channels. If the parameter is 0, the number of channels remains the same.
+ * @param newshape Vector with new matrix size by all dimentions. If some sizes are zero,
+ * the original sizes in those dimensions are presumed.
+ */
Mat reshape(int cn, const std::vector& newshape) const;
/** @brief Transposes a matrix.
diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp
index c6db72f267..c9fc1d67a6 100644
--- a/modules/core/include/opencv2/core/mat.inl.hpp
+++ b/modules/core/include/opencv2/core/mat.inl.hpp
@@ -51,7 +51,7 @@
#ifdef _MSC_VER
#pragma warning( push )
-#pragma warning( disable: 4127 )
+#pragma warning( disable: 4127 5054 )
#endif
#if defined(CV_SKIP_DISABLE_CLANG_ENUM_WARNINGS)
diff --git a/modules/core/include/opencv2/core/optim.hpp b/modules/core/include/opencv2/core/optim.hpp
index f61a2b9407..59fe978c26 100644
--- a/modules/core/include/opencv2/core/optim.hpp
+++ b/modules/core/include/opencv2/core/optim.hpp
@@ -256,6 +256,7 @@ public:
//! return codes for cv::solveLP() function
enum SolveLPResult
{
+ SOLVELP_LOST = -3, //!< problem is feasible, but solver lost solution due to floating-point arithmetic errors
SOLVELP_UNBOUNDED = -2, //!< problem is unbounded (target function can achieve arbitrary high values)
SOLVELP_UNFEASIBLE = -1, //!< problem is unfeasible (there are no points that satisfy all the constraints imposed)
SOLVELP_SINGLE = 0, //!< there is only one maximum for target function
@@ -291,8 +292,12 @@ in the latter case it is understood to correspond to \f$c^T\f$.
and the remaining to \f$A\f$. It should contain 32- or 64-bit floating point numbers.
@param z The solution will be returned here as a column-vector - it corresponds to \f$c\f$ in the
formulation above. It will contain 64-bit floating point numbers.
+@param constr_eps allowed numeric disparity for constraints
@return One of cv::SolveLPResult
*/
+CV_EXPORTS_W int solveLP(InputArray Func, InputArray Constr, OutputArray z, double constr_eps);
+
+/** @overload */
CV_EXPORTS_W int solveLP(InputArray Func, InputArray Constr, OutputArray z);
//! @}
diff --git a/modules/core/include/opencv2/core/types.hpp b/modules/core/include/opencv2/core/types.hpp
index cf26309949..0e0aa980e1 100644
--- a/modules/core/include/opencv2/core/types.hpp
+++ b/modules/core/include/opencv2/core/types.hpp
@@ -527,23 +527,23 @@ The sample below demonstrates how to use RotatedRect:
@sa CamShift, fitEllipse, minAreaRect, CvBox2D
*/
-class CV_EXPORTS RotatedRect
+class CV_EXPORTS_W_SIMPLE RotatedRect
{
public:
//! default constructor
- RotatedRect();
+ CV_WRAP RotatedRect();
/** full constructor
@param center The rectangle mass center.
@param size Width and height of the rectangle.
@param angle The rotation angle in a clockwise direction. When the angle is 0, 90, 180, 270 etc.,
the rectangle becomes an up-right rectangle.
*/
- RotatedRect(const Point2f& center, const Size2f& size, float angle);
+ CV_WRAP RotatedRect(const Point2f& center, const Size2f& size, float angle);
/**
Any 3 end points of the RotatedRect. They must be given in order (either clockwise or
anticlockwise).
*/
- RotatedRect(const Point2f& point1, const Point2f& point2, const Point2f& point3);
+ CV_WRAP RotatedRect(const Point2f& point1, const Point2f& point2, const Point2f& point3);
/** returns 4 vertices of the rotated rectangle
@param pts The points array for storing rectangle vertices. The order is _bottomLeft_, _topLeft_, topRight, bottomRight.
@@ -552,16 +552,19 @@ public:
rectangle.
*/
void points(Point2f pts[]) const;
+
+ CV_WRAP void points(CV_OUT std::vector& pts) const;
+
//! returns the minimal up-right integer rectangle containing the rotated rectangle
- Rect boundingRect() const;
+ CV_WRAP Rect boundingRect() const;
//! returns the minimal (exact) floating point rectangle containing the rotated rectangle, not intended for use with images
Rect_ boundingRect2f() const;
//! returns the rectangle mass center
- Point2f center;
+ CV_PROP_RW Point2f center;
//! returns width and height of the rectangle
- Size2f size;
+ CV_PROP_RW Size2f size;
//! returns the rotation angle. When the angle is 0, 90, 180, 270 etc., the rectangle becomes an up-right rectangle.
- float angle;
+ CV_PROP_RW float angle;
};
template<> class DataType< RotatedRect >
diff --git a/modules/core/misc/java/src/java/core+Mat.java b/modules/core/misc/java/src/java/core+Mat.java
index 2d9ee314a3..8e98284dde 100644
--- a/modules/core/misc/java/src/java/core+Mat.java
+++ b/modules/core/misc/java/src/java/core+Mat.java
@@ -470,6 +470,7 @@ public class Mat {
* Element-wise multiplication with scale factor
* @param m operand with with which to perform element-wise multiplication
* @param scale scale factor
+ * @return reference to a new Mat object
*/
public Mat mul(Mat m, double scale) {
return new Mat(n_mul(nativeObj, m.nativeObj, scale));
@@ -478,6 +479,7 @@ public class Mat {
/**
* Element-wise multiplication
* @param m operand with with which to perform element-wise multiplication
+ * @return reference to a new Mat object
*/
public Mat mul(Mat m) {
return new Mat(n_mul(nativeObj, m.nativeObj));
@@ -487,6 +489,7 @@ public class Mat {
* Matrix multiplication
* @param m operand with with which to perform matrix multiplication
* @see Core#gemm(Mat, Mat, double, Mat, double, Mat, int)
+ * @return reference to a new Mat object
*/
public Mat matMul(Mat m) {
return new Mat(n_matMul(nativeObj, m.nativeObj));
diff --git a/modules/core/misc/python/package/mat_wrapper/__init__.py b/modules/core/misc/python/package/mat_wrapper/__init__.py
index 7309c32b01..7cbc0645de 100644
--- a/modules/core/misc/python/package/mat_wrapper/__init__.py
+++ b/modules/core/misc/python/package/mat_wrapper/__init__.py
@@ -1,12 +1,18 @@
__all__ = []
-import sys
import numpy as np
import cv2 as cv
+from typing import TYPE_CHECKING, Any
+
+# Same as cv2.typing.NumPyArrayGeneric, but avoids circular dependencies
+if TYPE_CHECKING:
+ _NumPyArrayGeneric = np.ndarray[Any, np.dtype[np.generic]]
+else:
+ _NumPyArrayGeneric = np.ndarray
# NumPy documentation: https://numpy.org/doc/stable/user/basics.subclassing.html
-class Mat(np.ndarray):
+class Mat(_NumPyArrayGeneric):
'''
cv.Mat wrapper for numpy array.
diff --git a/modules/core/src/channels.cpp b/modules/core/src/channels.cpp
index 6ceed44a28..efaeb91068 100644
--- a/modules/core/src/channels.cpp
+++ b/modules/core/src/channels.cpp
@@ -46,44 +46,44 @@ mixChannels_( const T** src, const int* sdelta,
}
-static void mixChannels8u( const uchar** src, const int* sdelta,
- uchar** dst, const int* ddelta,
+static void mixChannels8u( const void** src, const int* sdelta,
+ void** dst, const int* ddelta,
int len, int npairs )
{
- mixChannels_(src, sdelta, dst, ddelta, len, npairs);
+ mixChannels_((const uchar**)src, sdelta, (uchar**)dst, ddelta, len, npairs);
}
-static void mixChannels16u( const ushort** src, const int* sdelta,
- ushort** dst, const int* ddelta,
+static void mixChannels16u( const void** src, const int* sdelta,
+ void** dst, const int* ddelta,
int len, int npairs )
{
- mixChannels_(src, sdelta, dst, ddelta, len, npairs);
+ mixChannels_((const ushort**)src, sdelta, (ushort**)dst, ddelta, len, npairs);
}
-static void mixChannels32s( const int** src, const int* sdelta,
- int** dst, const int* ddelta,
+static void mixChannels32s( const void** src, const int* sdelta,
+ void** dst, const int* ddelta,
int len, int npairs )
{
- mixChannels_(src, sdelta, dst, ddelta, len, npairs);
+ mixChannels_((const int**)src, sdelta, (int**)dst, ddelta, len, npairs);
}
-static void mixChannels64s( const int64** src, const int* sdelta,
- int64** dst, const int* ddelta,
+static void mixChannels64s( const void** src, const int* sdelta,
+ void** dst, const int* ddelta,
int len, int npairs )
{
- mixChannels_(src, sdelta, dst, ddelta, len, npairs);
+ mixChannels_((const int64**)src, sdelta, (int64**)dst, ddelta, len, npairs);
}
-typedef void (*MixChannelsFunc)( const uchar** src, const int* sdelta,
- uchar** dst, const int* ddelta, int len, int npairs );
+typedef void (*MixChannelsFunc)( const void** src, const int* sdelta,
+ void** dst, const int* ddelta, int len, int npairs );
static MixChannelsFunc getMixchFunc(int depth)
{
static MixChannelsFunc mixchTab[] =
{
- (MixChannelsFunc)mixChannels8u, (MixChannelsFunc)mixChannels8u, (MixChannelsFunc)mixChannels16u,
- (MixChannelsFunc)mixChannels16u, (MixChannelsFunc)mixChannels32s, (MixChannelsFunc)mixChannels32s,
- (MixChannelsFunc)mixChannels64s, 0
+ mixChannels8u, mixChannels8u, mixChannels16u,
+ mixChannels16u, mixChannels32s, mixChannels32s,
+ mixChannels64s, 0
};
return mixchTab[depth];
@@ -158,7 +158,7 @@ void cv::mixChannels( const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts, cons
for( int t = 0; t < total; t += blocksize )
{
int bsz = std::min(total - t, blocksize);
- func( srcs, sdelta, dsts, ddelta, bsz, (int)npairs );
+ func( (const void**)srcs, sdelta, (void **)dsts, ddelta, bsz, (int)npairs );
if( t + blocksize < total )
for( k = 0; k < npairs; k++ )
diff --git a/modules/core/src/lpsolver.cpp b/modules/core/src/lpsolver.cpp
index 43fa73a025..b09fb0128b 100644
--- a/modules/core/src/lpsolver.cpp
+++ b/modules/core/src/lpsolver.cpp
@@ -90,7 +90,7 @@ static void swap_columns(Mat_& A,int col1,int col2);
#define SWAP(type,a,b) {type tmp=(a);(a)=(b);(b)=tmp;}
//return codes:-2 (no_sol - unbdd),-1(no_sol - unfsbl), 0(single_sol), 1(multiple_sol=>least_l2_norm)
-int solveLP(InputArray Func_, InputArray Constr_, OutputArray z_)
+int solveLP(InputArray Func_, InputArray Constr_, OutputArray z_, double constr_eps)
{
dprintf(("call to solveLP\n"));
@@ -143,9 +143,25 @@ int solveLP(InputArray Func_, InputArray Constr_, OutputArray z_)
}
z.copyTo(z_);
+
+ //check constraints feasibility
+ Mat prod = Constr(Rect(0, 0, Constr.cols - 1, Constr.rows)) * z;
+ Mat constr_check = Constr.col(Constr.cols - 1) - prod;
+ double min_value = 0.0;
+ minMaxIdx(constr_check, &min_value);
+ if (min_value < -constr_eps)
+ {
+ return SOLVELP_LOST;
+ }
+
return res;
}
+int solveLP(InputArray Func, InputArray Constr, OutputArray z)
+{
+ return solveLP(Func, Constr, z, 1e-12);
+}
+
static int initialize_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B,vector& indexToRow){
N.resize(c.cols);
N[0]=0;
@@ -255,7 +271,7 @@ static int initialize_simplex(Mat_& c, Mat_& b,double& v,vector<
static int inner_simplex(Mat_& c, Mat_& b,double& v,vector& N,vector& B,vector& indexToRow){
for(;;){
- static MatIterator_ pos_ptr;
+ MatIterator_ pos_ptr;
int e=-1,pos_ctr=0,min_var=INT_MAX;
bool all_nonzero=true;
for(pos_ptr=c.begin();pos_ptr!=c.end();pos_ptr++,pos_ctr++){
diff --git a/modules/core/src/matrix_transform.cpp b/modules/core/src/matrix_transform.cpp
index 57fd0c6509..7f1043fbbe 100644
--- a/modules/core/src/matrix_transform.cpp
+++ b/modules/core/src/matrix_transform.cpp
@@ -603,10 +603,10 @@ flipVert( const uchar* src0, size_t sstep, uchar* dst0, size_t dstep, Size size,
{
for (; i <= size.width - CV_SIMD_WIDTH; i += CV_SIMD_WIDTH)
{
- v_int32 t0 = vx_load((int*)(src0 + i));
- v_int32 t1 = vx_load((int*)(src1 + i));
- v_store((int*)(dst0 + i), t1);
- v_store((int*)(dst1 + i), t0);
+ v_int32 t0 = v_reinterpret_as_s32(vx_load(src0 + i));
+ v_int32 t1 = v_reinterpret_as_s32(vx_load(src1 + i));
+ v_store(dst0 + i, v_reinterpret_as_u8(t1));
+ v_store(dst1 + i, v_reinterpret_as_u8(t0));
}
}
#if CV_STRONG_ALIGNMENT
diff --git a/modules/core/src/mean.simd.hpp b/modules/core/src/mean.simd.hpp
index d94c887223..bb815adc1c 100644
--- a/modules/core/src/mean.simd.hpp
+++ b/modules/core/src/mean.simd.hpp
@@ -24,7 +24,7 @@ struct SumSqr_SIMD
}
};
-#if CV_SIMD
+#if CV_SIMD || CV_SIMD_SCALABLE
template <>
struct SumSqr_SIMD
@@ -39,37 +39,37 @@ struct SumSqr_SIMD
v_int32 v_sum = vx_setzero_s32();
v_int32 v_sqsum = vx_setzero_s32();
- const int len0 = len & -v_uint8::nlanes;
+ const int len0 = len & -VTraits::vlanes();
while(x < len0)
{
- const int len_tmp = min(x + 256*v_uint16::nlanes, len0);
+ const int len_tmp = min(x + 256*VTraits::vlanes(), len0);
v_uint16 v_sum16 = vx_setzero_u16();
- for ( ; x < len_tmp; x += v_uint8::nlanes)
+ for ( ; x < len_tmp; x += VTraits::vlanes())
{
v_uint16 v_src0 = vx_load_expand(src0 + x);
- v_uint16 v_src1 = vx_load_expand(src0 + x + v_uint16::nlanes);
- v_sum16 += v_src0 + v_src1;
+ v_uint16 v_src1 = vx_load_expand(src0 + x + VTraits::vlanes());
+ v_sum16 = v_add(v_sum16, v_add(v_src0, v_src1));
v_int16 v_tmp0, v_tmp1;
v_zip(v_reinterpret_as_s16(v_src0), v_reinterpret_as_s16(v_src1), v_tmp0, v_tmp1);
- v_sqsum += v_dotprod(v_tmp0, v_tmp0) + v_dotprod(v_tmp1, v_tmp1);
+ v_sqsum = v_add(v_sqsum, v_add(v_dotprod(v_tmp0, v_tmp0), v_dotprod(v_tmp1, v_tmp1)));
}
v_uint32 v_half0, v_half1;
v_expand(v_sum16, v_half0, v_half1);
- v_sum += v_reinterpret_as_s32(v_half0 + v_half1);
+ v_sum = v_add(v_sum, v_reinterpret_as_s32(v_add(v_half0, v_half1)));
}
- if (x <= len - v_uint16::nlanes)
+ if (x <= len - VTraits::vlanes())
{
v_uint16 v_src = vx_load_expand(src0 + x);
v_uint16 v_half = v_combine_high(v_src, v_src);
v_uint32 v_tmp0, v_tmp1;
- v_expand(v_src + v_half, v_tmp0, v_tmp1);
- v_sum += v_reinterpret_as_s32(v_tmp0);
+ v_expand(v_add(v_src, v_half), v_tmp0, v_tmp1);
+ v_sum = v_add(v_sum, v_reinterpret_as_s32(v_tmp0));
v_int16 v_tmp2, v_tmp3;
v_zip(v_reinterpret_as_s16(v_src), v_reinterpret_as_s16(v_half), v_tmp2, v_tmp3);
- v_sqsum += v_dotprod(v_tmp2, v_tmp2);
- x += v_uint16::nlanes;
+ v_sqsum = v_add(v_sqsum, v_dotprod(v_tmp2, v_tmp2));
+ x += VTraits::vlanes();
}
if (cn == 1)
@@ -79,13 +79,13 @@ struct SumSqr_SIMD
}
else
{
- int CV_DECL_ALIGNED(CV_SIMD_WIDTH) ar[2 * v_int32::nlanes];
+ int CV_DECL_ALIGNED(CV_SIMD_WIDTH) ar[2 * VTraits::max_nlanes];
v_store(ar, v_sum);
- v_store(ar + v_int32::nlanes, v_sqsum);
- for (int i = 0; i < v_int32::nlanes; ++i)
+ v_store(ar + VTraits::vlanes(), v_sqsum);
+ for (int i = 0; i < VTraits::vlanes(); ++i)
{
sum[i % cn] += ar[i];
- sqsum[i % cn] += ar[v_int32::nlanes + i];
+ sqsum[i % cn] += ar[VTraits::vlanes() + i];
}
}
v_cleanup();
@@ -106,37 +106,37 @@ struct SumSqr_SIMD
v_int32 v_sum = vx_setzero_s32();
v_int32 v_sqsum = vx_setzero_s32();
- const int len0 = len & -v_int8::nlanes;
+ const int len0 = len & -VTraits::vlanes();
while (x < len0)
{
- const int len_tmp = min(x + 256 * v_int16::nlanes, len0);
+ const int len_tmp = min(x + 256 * VTraits::vlanes(), len0);
v_int16 v_sum16 = vx_setzero_s16();
- for (; x < len_tmp; x += v_int8::nlanes)
+ for (; x < len_tmp; x += VTraits::vlanes())
{
v_int16 v_src0 = vx_load_expand(src0 + x);
- v_int16 v_src1 = vx_load_expand(src0 + x + v_int16::nlanes);
- v_sum16 += v_src0 + v_src1;
+ v_int16 v_src1 = vx_load_expand(src0 + x + VTraits::vlanes());
+ v_sum16 = v_add(v_sum16, v_add(v_src0, v_src1));
v_int16 v_tmp0, v_tmp1;
v_zip(v_src0, v_src1, v_tmp0, v_tmp1);
- v_sqsum += v_dotprod(v_tmp0, v_tmp0) + v_dotprod(v_tmp1, v_tmp1);
+ v_sqsum = v_add(v_sqsum, v_add(v_dotprod(v_tmp0, v_tmp0), v_dotprod(v_tmp1, v_tmp1)));
}
v_int32 v_half0, v_half1;
v_expand(v_sum16, v_half0, v_half1);
- v_sum += v_half0 + v_half1;
+ v_sum = v_add(v_sum, v_add(v_half0, v_half1));
}
- if (x <= len - v_int16::nlanes)
+ if (x <= len - VTraits::vlanes())
{
v_int16 v_src = vx_load_expand(src0 + x);
v_int16 v_half = v_combine_high(v_src, v_src);
v_int32 v_tmp0, v_tmp1;
- v_expand(v_src + v_half, v_tmp0, v_tmp1);
- v_sum += v_tmp0;
+ v_expand(v_add(v_src, v_half), v_tmp0, v_tmp1);
+ v_sum = v_add(v_sum, v_tmp0);
v_int16 v_tmp2, v_tmp3;
v_zip(v_src, v_half, v_tmp2, v_tmp3);
- v_sqsum += v_dotprod(v_tmp2, v_tmp2);
- x += v_int16::nlanes;
+ v_sqsum = v_add(v_sqsum, v_dotprod(v_tmp2, v_tmp2));
+ x += VTraits::vlanes();
}
if (cn == 1)
@@ -146,13 +146,13 @@ struct SumSqr_SIMD
}
else
{
- int CV_DECL_ALIGNED(CV_SIMD_WIDTH) ar[2 * v_int32::nlanes];
+ int CV_DECL_ALIGNED(CV_SIMD_WIDTH) ar[2 * VTraits::max_nlanes];
v_store(ar, v_sum);
- v_store(ar + v_int32::nlanes, v_sqsum);
- for (int i = 0; i < v_int32::nlanes; ++i)
+ v_store(ar + VTraits::vlanes(), v_sqsum);
+ for (int i = 0; i < VTraits::vlanes(); ++i)
{
sum[i % cn] += ar[i];
- sqsum[i % cn] += ar[v_int32::nlanes + i];
+ sqsum[i % cn] += ar[VTraits::vlanes() + i];
}
}
v_cleanup();
diff --git a/modules/core/src/ocl.cpp b/modules/core/src/ocl.cpp
index 946c9b16e6..e201d4a5af 100644
--- a/modules/core/src/ocl.cpp
+++ b/modules/core/src/ocl.cpp
@@ -51,7 +51,6 @@
#include
#include
#include
-#include // std::cerr
#include
#if !(defined _MSC_VER) || (defined _MSC_VER && _MSC_VER > 1700)
#include
diff --git a/modules/core/src/parallel.cpp b/modules/core/src/parallel.cpp
index c7c8b28f64..63e699f02c 100644
--- a/modules/core/src/parallel.cpp
+++ b/modules/core/src/parallel.cpp
@@ -128,6 +128,8 @@
#include
#elif defined HAVE_CONCURRENCY
#include
+#elif defined HAVE_PTHREADS_PF
+ #include
#endif
diff --git a/modules/core/src/system.cpp b/modules/core/src/system.cpp
index 0828e9cb89..4f26ff305e 100644
--- a/modules/core/src/system.cpp
+++ b/modules/core/src/system.cpp
@@ -2522,7 +2522,7 @@ public:
ippStatus = ippGetCpuFeatures(&cpuFeatures, NULL);
if(ippStatus < 0)
{
- std::cerr << "ERROR: IPP cannot detect CPU features, IPP was disabled " << std::endl;
+ CV_LOG_ERROR(NULL, "ERROR: IPP cannot detect CPU features, IPP was disabled");
useIPP = false;
return;
}
@@ -2560,7 +2560,7 @@ public:
if(env == "disabled")
{
- std::cerr << "WARNING: IPP was disabled by OPENCV_IPP environment variable" << std::endl;
+ CV_LOG_WARNING(NULL, "WARNING: IPP was disabled by OPENCV_IPP environment variable");
useIPP = false;
}
else if(env == "sse42")
@@ -2574,7 +2574,7 @@ public:
#endif
#endif
else
- std::cerr << "ERROR: Improper value of OPENCV_IPP: " << env.c_str() << ". Correct values are: disabled, sse42, avx2, avx512 (Intel64 only)" << std::endl;
+ CV_LOG_ERROR(NULL, "ERROR: Improper value of OPENCV_IPP: " << env.c_str() << ". Correct values are: disabled, sse42, avx2, avx512 (Intel64 only)");
// Trim unsupported features
ippFeatures &= cpuFeatures;
diff --git a/modules/core/src/types.cpp b/modules/core/src/types.cpp
index 15ba83a0f6..43e25ef045 100644
--- a/modules/core/src/types.cpp
+++ b/modules/core/src/types.cpp
@@ -186,6 +186,11 @@ void RotatedRect::points(Point2f pt[]) const
pt[3].y = 2*center.y - pt[1].y;
}
+void RotatedRect::points(std::vector& pts) const {
+ pts.resize(4);
+ points(pts.data());
+}
+
Rect RotatedRect::boundingRect() const
{
Point2f pt[4];
diff --git a/modules/core/test/test_intrin_utils.hpp b/modules/core/test/test_intrin_utils.hpp
index 01ca50a26e..481e6bb1f2 100644
--- a/modules/core/test/test_intrin_utils.hpp
+++ b/modules/core/test/test_intrin_utils.hpp
@@ -2048,6 +2048,7 @@ void test_hal_intrin_uint64()
.test_rotate<0>().test_rotate<1>()
.test_extract_n<0>().test_extract_n<1>()
.test_extract_highest()
+ .test_popcount()
//.test_broadcast_element<0>().test_broadcast_element<1>()
;
}
@@ -2069,6 +2070,7 @@ void test_hal_intrin_int64()
.test_extract_highest()
//.test_broadcast_element<0>().test_broadcast_element<1>()
.test_cvt64_double()
+ .test_popcount()
;
}
diff --git a/modules/core/test/test_lpsolver.cpp b/modules/core/test/test_lpsolver.cpp
index 99829cbefa..b46dc7ef79 100644
--- a/modules/core/test/test_lpsolver.cpp
+++ b/modules/core/test/test_lpsolver.cpp
@@ -151,4 +151,18 @@ TEST(Core_LPSolver, issue_12337)
EXPECT_ANY_THROW(Mat1b z_8u; cv::solveLP(A, B, z_8u));
}
+// NOTE: Test parameters found experimentally to get numerically inaccurate result.
+// The test behaviour may change after algorithm tuning and may removed.
+TEST(Core_LPSolver, issue_12343)
+{
+ Mat A = (cv::Mat_(4, 1) << 3., 3., 3., 4.);
+ Mat B = (cv::Mat_(4, 5) << 0., 1., 4., 4., 3.,
+ 3., 1., 2., 2., 3.,
+ 4., 4., 0., 1., 4.,
+ 4., 0., 4., 1., 4.);
+ Mat z;
+ int result = cv::solveLP(A, B, z);
+ EXPECT_EQ(SOLVELP_LOST, result);
+}
+
}} // namespace
diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp
index df2c42fdb8..dd7a49f22a 100644
--- a/modules/core/test/test_mat.cpp
+++ b/modules/core/test/test_mat.cpp
@@ -18,7 +18,7 @@ class Core_ReduceTest : public cvtest::BaseTest
public:
Core_ReduceTest() {}
protected:
- void run( int);
+ void run( int) CV_OVERRIDE;
int checkOp( const Mat& src, int dstType, int opType, const Mat& opRes, int dim );
int checkCase( int srcType, int dstType, int dim, Size sz );
int checkDim( int dim, Size sz );
@@ -495,7 +495,7 @@ public:
Core_ArrayOpTest();
~Core_ArrayOpTest();
protected:
- void run(int);
+ void run(int) CV_OVERRIDE;
};
@@ -599,6 +599,11 @@ static void setValue(SparseMat& M, const int* idx, double value, RNG& rng)
CV_Error(CV_StsUnsupportedFormat, "");
}
+#if defined(__GNUC__) && (__GNUC__ == 11 || __GNUC__ == 12)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+#endif
+
template
struct InitializerFunctor{
/// Initializer for cv::Mat::forEach test
@@ -621,6 +626,11 @@ struct InitializerFunctor5D{
}
};
+#if defined(__GNUC__) && (__GNUC__ == 11 || __GNUC__ == 12)
+#pragma GCC diagnostic pop
+#endif
+
+
template
struct EmptyFunctor
{
@@ -1023,7 +1033,7 @@ class Core_MergeSplitBaseTest : public cvtest::BaseTest
protected:
virtual int run_case(int depth, size_t channels, const Size& size, RNG& rng) = 0;
- virtual void run(int)
+ virtual void run(int) CV_OVERRIDE
{
// m is Mat
// mv is vector
@@ -1068,7 +1078,7 @@ public:
~Core_MergeTest() {}
protected:
- virtual int run_case(int depth, size_t matCount, const Size& size, RNG& rng)
+ virtual int run_case(int depth, size_t matCount, const Size& size, RNG& rng) CV_OVERRIDE
{
const int maxMatChannels = 10;
@@ -1126,7 +1136,7 @@ public:
~Core_SplitTest() {}
protected:
- virtual int run_case(int depth, size_t channels, const Size& size, RNG& rng)
+ virtual int run_case(int depth, size_t channels, const Size& size, RNG& rng) CV_OVERRIDE
{
Mat src(size, CV_MAKETYPE(depth, (int)channels));
rng.fill(src, RNG::UNIFORM, 0, 100, true);
@@ -1990,7 +2000,6 @@ TEST(Core_InputArray, fetch_MatExpr)
}
-#ifdef CV_CXX11
class TestInputArrayRangeChecking {
static const char *kind2str(cv::_InputArray ia)
{
@@ -2136,8 +2145,6 @@ TEST(Core_InputArray, range_checking)
{
TestInputArrayRangeChecking::run();
}
-#endif
-
TEST(Core_Vectors, issue_13078)
{
diff --git a/modules/dnn/include/opencv2/dnn/dnn.hpp b/modules/dnn/include/opencv2/dnn/dnn.hpp
index 60f68fce6e..d61f7191bc 100644
--- a/modules/dnn/include/opencv2/dnn/dnn.hpp
+++ b/modules/dnn/include/opencv2/dnn/dnn.hpp
@@ -894,7 +894,6 @@ CV__DNN_INLINE_NS_BEGIN
* @param cfgFile path to the .cfg file with text description of the network architecture.
* @param darknetModel path to the .weights file with learned network.
* @returns Network object that ready to do forward, throw an exception in failure cases.
- * @returns Net object.
*/
CV_EXPORTS_W Net readNetFromDarknet(const String &cfgFile, const String &darknetModel = String());
diff --git a/modules/dnn/include/opencv2/dnn/version.hpp b/modules/dnn/include/opencv2/dnn/version.hpp
index ea5a218904..a1cfca0e1d 100644
--- a/modules/dnn/include/opencv2/dnn/version.hpp
+++ b/modules/dnn/include/opencv2/dnn/version.hpp
@@ -6,7 +6,7 @@
#define OPENCV_DNN_VERSION_HPP
/// Use with major OpenCV version only.
-#define OPENCV_DNN_API_VERSION 20221220
+#define OPENCV_DNN_API_VERSION 20230620
#if !defined CV_DOXYGEN && !defined CV_STATIC_ANALYSIS && !defined CV_DNN_DONT_ADD_INLINE_NS
#define CV__DNN_INLINE_NS __CV_CAT(dnn5_v, OPENCV_DNN_API_VERSION)
diff --git a/modules/dnn/perf/perf_convolution.cpp b/modules/dnn/perf/perf_convolution.cpp
index bb890c6a00..99f425b712 100644
--- a/modules/dnn/perf/perf_convolution.cpp
+++ b/modules/dnn/perf/perf_convolution.cpp
@@ -744,7 +744,8 @@ static const ConvParam_t testConvolutionConfigs[] = {
/* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 4, 1, 1}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 864.},
/* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 96, 1, 1}}, 4, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 772.},
/* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 8, 1, 1}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 544.},
- /* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 32, 1, 1}}, 8, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 520.}
+ /* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 32, 1, 1}}, 8, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 520.},
+ /* GFLOPS 0.472 x 1 = 0.472 */ {{5, 5}, {{1, 32, 96, 96}}, 32, 32, {1, 1}, {1, 1}, {2, 2}, {0, 0}, "", true, 472154112.}
};
struct ConvParamID
{
diff --git a/modules/dnn/src/layers/cpu_kernels/conv_block.simd.hpp b/modules/dnn/src/layers/cpu_kernels/conv_block.simd.hpp
index 27b0d4ba1f..3310a91b6b 100644
--- a/modules/dnn/src/layers/cpu_kernels/conv_block.simd.hpp
+++ b/modules/dnn/src/layers/cpu_kernels/conv_block.simd.hpp
@@ -452,13 +452,13 @@ void convBlockMR1_F32(int np, const float * a, const float * b, float *c, const
if (init_c)
{
- c0 += vld1q_f32(c);
- c1 += vld1q_f32(c + 4);
- c2 += vld1q_f32(c + 8);
- c3 += vld1q_f32(c + 12);
- c4 += vld1q_f32(c + 16);
- c5 += vld1q_f32(c + 20);
- c6 += vld1q_f32(c + 24);
+ c0 = vaddq_f32(c0, vld1q_f32(c));
+ c1 = vaddq_f32(c1, vld1q_f32(c + 4));
+ c2 = vaddq_f32(c2, vld1q_f32(c + 8));
+ c3 = vaddq_f32(c3, vld1q_f32(c + 12));
+ c4 = vaddq_f32(c4, vld1q_f32(c + 16));
+ c5 = vaddq_f32(c5, vld1q_f32(c + 20));
+ c6 = vaddq_f32(c6, vld1q_f32(c + 24));
}
if (ifMinMaxAct)
diff --git a/modules/dnn/src/layers/cpu_kernels/convolution.cpp b/modules/dnn/src/layers/cpu_kernels/convolution.cpp
index c76b3494e2..68777ff65e 100644
--- a/modules/dnn/src/layers/cpu_kernels/convolution.cpp
+++ b/modules/dnn/src/layers/cpu_kernels/convolution.cpp
@@ -1290,7 +1290,7 @@ void runFastConv(InputArray _input, OutputArray _output, const Ptr& co
else
Kg_nblocks = 1;
- bool separateIm2col = fast_1x1 || stripes_per_plane == 1;
+ bool separateIm2col = (fast_1x1 || stripes_per_plane == 1) && conv->conv_type != CONV_TYPE_DEPTHWISE_REMAIN;
int Kstripes = Kg_nblocks * stripes_per_plane;
int nsubtasks = N * ngroups * Kstripes;
diff --git a/modules/dnn/src/layers/elementwise_layers.cpp b/modules/dnn/src/layers/elementwise_layers.cpp
index 28cf737044..2a34b9400b 100644
--- a/modules/dnn/src/layers/elementwise_layers.cpp
+++ b/modules/dnn/src/layers/elementwise_layers.cpp
@@ -138,7 +138,7 @@ public:
{
const float* srcptr = src_->ptr(i) + stripeStart;
float* dstptr = dst_->ptr(i) + stripeStart;
- func_->apply(srcptr, dstptr, (int)(stripeEnd - stripeStart), planeSize, 0, outCn);
+ func_->apply(srcptr, dstptr, stripeStart, (int)(stripeEnd - stripeStart), planeSize, 0, outCn);
}
}
};
@@ -268,7 +268,7 @@ public:
void forwardSlice(const float* src, float* dst, int len, size_t planeSize, int cn0, int cn1) const CV_OVERRIDE
{
- func.apply(src, dst, len, planeSize, cn0, cn1);
+ func.apply(src, dst, -1, len, planeSize, cn0, cn1);
}
#ifdef HAVE_CUDA
@@ -355,8 +355,9 @@ struct ReLUFunctor : public BaseFunctor
backendId == DNN_BACKEND_CANN;
}
- void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const
+ void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const
{
+ CV_UNUSED(stripeStart);
float s = slope;
for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize )
{
@@ -559,8 +560,9 @@ struct ReLU6Functor : public BaseFunctor
backendId == DNN_BACKEND_CANN;
}
- void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const
+ void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const
{
+ CV_UNUSED(stripeStart);
for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize )
{
int i = 0;
@@ -704,8 +706,9 @@ struct ReLU6Functor : public BaseFunctor
template
struct BaseDefaultFunctor : public BaseFunctor
{
- void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const
+ void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const
{
+ CV_UNUSED(stripeStart);
for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize )
{
for( int i = 0; i < len; i++ )
@@ -1100,7 +1103,14 @@ struct SigmoidFunctor : public BaseDefaultFunctor
inline float calculate(float x) const
{
- return 1.f / (1.f + exp(-x));
+ float y;
+ if (x >= 0)
+ y = 1.f / (1.f + exp(-x));
+ else {
+ y = exp(x);
+ y = y / (1 + y);
+ }
+ return y;
}
#ifdef HAVE_CUDA
@@ -2219,8 +2229,9 @@ struct PowerFunctor : public BaseFunctor
shift = originShift;
}
- void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const
+ void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const
{
+ CV_UNUSED(stripeStart);
float a = scale, b = shift, p = power;
if( p == 1.f )
{
@@ -2445,6 +2456,7 @@ struct ChannelsPReLUFunctor : public BaseFunctor
Mat scale;
#ifdef HAVE_OPENCL
UMat scale_umat;
+ std::string oclKernelName = "ChannelsPReLUForward";
#endif
explicit ChannelsPReLUFunctor(const Mat& scale_=Mat()) : scale(scale_)
@@ -2463,8 +2475,9 @@ struct ChannelsPReLUFunctor : public BaseFunctor
backendId == DNN_BACKEND_CANN;
}
- void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const
+ void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const
{
+ CV_UNUSED(stripeStart);
CV_Assert(scale.isContinuous() && scale.type() == CV_32F);
const float* scaleptr = scale.ptr();
@@ -2518,7 +2531,7 @@ struct ChannelsPReLUFunctor : public BaseFunctor
UMat& src = inputs[i];
UMat& dst = outputs[i];
- ocl::Kernel kernel("PReLUForward", ocl::dnn::activations_oclsrc, buildopt);
+ ocl::Kernel kernel(oclKernelName.c_str(), ocl::dnn::activations_oclsrc, buildopt);
kernel.set(0, (int)src.total());
kernel.set(1, (int)src.size[1]);
kernel.set(2, (int)total(shape(src), 2));
@@ -2598,6 +2611,75 @@ struct ChannelsPReLUFunctor : public BaseFunctor
int64 getFLOPSPerElement() const { return 1; }
};
+struct PReLUFunctor : public ChannelsPReLUFunctor
+{
+ explicit PReLUFunctor(const Mat& scale_=Mat()) : ChannelsPReLUFunctor(scale_)
+ {
+#ifdef HAVE_OPENCL
+ oclKernelName = "PReLUForward";
+#endif
+ }
+
+ bool supportBackend(int backendId, int)
+ {
+ return backendId == DNN_BACKEND_OPENCV ||
+ backendId == DNN_BACKEND_CANN ||
+ backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH;
+ }
+
+ void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const
+ {
+ CV_UNUSED(stripeStart);
+ CV_Assert(scale.isContinuous() && scale.type() == CV_32F);
+
+ if (stripeStart < 0)
+ CV_Error(Error::StsNotImplemented, "PReLUFunctor requires stripe offset parameter");
+
+ const float* scaleptr = scale.ptr() + cn0 * planeSize + stripeStart;
+ for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize, scaleptr += planeSize )
+ {
+ int i = 0;
+ #if CV_SIMD128
+ v_float32x4 z = v_setzero_f32();
+ for( ; i <= len - 16; i += 16 )
+ {
+ v_float32x4 x0 = v_load(srcptr + i);
+ v_float32x4 x1 = v_load(srcptr + i + 4);
+ v_float32x4 x2 = v_load(srcptr + i + 8);
+ v_float32x4 x3 = v_load(srcptr + i + 12);
+ v_float32x4 s0 = v_load(scaleptr + i);
+ v_float32x4 s1 = v_load(scaleptr + i + 4);
+ v_float32x4 s2 = v_load(scaleptr + i + 8);
+ v_float32x4 s3 = v_load(scaleptr + i + 12);
+ x0 = v_select(x0 >= z, x0, x0*s0);
+ x1 = v_select(x1 >= z, x1, x1*s1);
+ x2 = v_select(x2 >= z, x2, x2*s2);
+ x3 = v_select(x3 >= z, x3, x3*s3);
+ v_store(dstptr + i, x0);
+ v_store(dstptr + i + 4, x1);
+ v_store(dstptr + i + 8, x2);
+ v_store(dstptr + i + 12, x3);
+ }
+ #endif
+ for( ; i < len; i++ )
+ {
+ float x = srcptr[i];
+ float s = scaleptr[i];
+ dstptr[i] = x >= 0.f ? x : s*x;
+ }
+ }
+ }
+
+#ifdef HAVE_DNN_NGRAPH
+ std::shared_ptr initNgraphAPI(const std::shared_ptr& node)
+ {
+ auto shape = getShape(scale);
+ auto slope = std::make_shared(ngraph::element::f32, shape, scale.ptr());
+ return std::make_shared(node, slope);
+ }
+#endif // HAVE_DNN_NGRAPH
+};
+
struct SignFunctor : public BaseDefaultFunctor
{
typedef SignLayer Layer;
@@ -3033,13 +3115,26 @@ Ptr ExpLayer::create(const LayerParams& params)
Ptr ChannelsPReLULayer::create(const LayerParams& params)
{
CV_Assert(params.blobs.size() == 1);
- if (params.blobs[0].total() == 1)
+ Mat scale = params.blobs[0];
+ float slope = *scale.ptr();
+ if (scale.total() == 1 || countNonZero(scale != slope) == 0)
{
LayerParams reluParams = params;
- reluParams.set("negative_slope", *params.blobs[0].ptr());
+ reluParams.set("negative_slope", slope);
return ReLULayer::create(reluParams);
}
- Ptr l(new ElementWiseLayer(ChannelsPReLUFunctor(params.blobs[0])));
+
+ Ptr l;
+ // Check first two dimensions of scale (batch, channels)
+ MatShape scaleShape = shape(scale);
+ if (std::count_if(scaleShape.begin(), scaleShape.end(), [](int d){ return d != 1;}) > 1)
+ {
+ l = new ElementWiseLayer(PReLUFunctor(scale));
+ }
+ else
+ {
+ l = new ElementWiseLayer(ChannelsPReLUFunctor(scale));
+ }
l->setParamsFrom(params);
return l;
diff --git a/modules/dnn/src/layers/max_unpooling_layer.cpp b/modules/dnn/src/layers/max_unpooling_layer.cpp
index a44d25ce89..fd47c4c919 100644
--- a/modules/dnn/src/layers/max_unpooling_layer.cpp
+++ b/modules/dnn/src/layers/max_unpooling_layer.cpp
@@ -14,6 +14,7 @@ Implementation of Batch Normalization layer.
#include "../op_cuda.hpp"
#include "../op_halide.hpp"
#include
+#include
#ifdef HAVE_CUDA
#include "../cuda4dnn/primitives/max_unpooling.hpp"
@@ -110,17 +111,12 @@ public:
int index = idxptr[i_wh];
if (!(0 <= index && index < outPlaneTotal))
{
- std::cerr
- << "i_n=" << i_n << std::endl
- << "i_c=" << i_c << std::endl
- << "i_wh=" << i_wh << std::endl
- << "index=" << index << std::endl
- << "maxval=" << inptr[i_wh] << std::endl
- << "outPlaneTotal=" << outPlaneTotal << std::endl
- << "input.size=" << input.size << std::endl
- << "indices.size=" << indices.size << std::endl
- << "outBlob=" << outBlob.size << std::endl
- ;
+ CV_LOG_ERROR(NULL, cv::format(
+ "i_n=%d\ni_c=%d\ni_wh=%d\nindex=%d\nmaxval=%lf\noutPlaneTotal=%d\n",
+ i_n, i_c, i_wh, index, inptr[i_wh], outPlaneTotal));
+ CV_LOG_ERROR(NULL, "input.size=" << input.size);
+ CV_LOG_ERROR(NULL, "indices.size=" << indices.size);
+ CV_LOG_ERROR(NULL, "outBlob=" << outBlob.size);
CV_Assert(0 <= index && index < outPlaneTotal);
}
outptr[index] = inptr[i_wh];
diff --git a/modules/dnn/src/net_cann.cpp b/modules/dnn/src/net_cann.cpp
index a3eb52200f..103c7c8dd2 100644
--- a/modules/dnn/src/net_cann.cpp
+++ b/modules/dnn/src/net_cann.cpp
@@ -304,9 +304,9 @@ std::shared_ptr compileCannGraph(std::shared_ptr
bool ok;
if ((child=fork()) == 0)
{
- // initialize engine
+ // initialize engine Ascend310/Ascend310P3/Ascend910B/Ascend310B
std::map options = {
- {ge::AscendString(ge::ir_option::SOC_VERSION), ge::AscendString("Ascend310")},
+ {ge::AscendString(ge::ir_option::SOC_VERSION), ge::AscendString(aclrtGetSocName())},
};
ACL_CHECK_GRAPH_RET(ge::aclgrphBuildInitialize(options));
diff --git a/modules/dnn/src/net_impl.cpp b/modules/dnn/src/net_impl.cpp
index c8341e4c6f..16ae6d7bfb 100644
--- a/modules/dnn/src/net_impl.cpp
+++ b/modules/dnn/src/net_impl.cpp
@@ -662,14 +662,14 @@ void Net::Impl::forwardLayer(LayerData& ld)
m = u.getMat(ACCESS_READ);
if (!checkRange(m))
{
- std::cerr << "WARNING: NaN detected in layer output: id=" << ld.id << " name=" << layer->name << std::endl;
- std::cerr << "output id=" << i << " output shape=" << shape(m) << std::endl;
+ CV_LOG_WARNING(NULL, "NaN detected in layer output: id=" << ld.id << " name=" << layer->name
+ << " output id=" << i << " output shape=" << shape(m));
fail = true;
}
else if (!checkRange(m, true, NULL, -1e6, 1e6))
{
- std::cerr << "WARNING: Inf detected in layer output: id=" << ld.id << " name=" << layer->name << std::endl;
- std::cerr << "output id=" << i << " output shape=" << shape(m) << std::endl;
+ CV_LOG_WARNING(NULL, "Inf detected in layer output: id=" << ld.id << " name=" << layer->name
+ << " output id=" << i << " output shape=" << shape(m));
fail = true;
}
}
@@ -738,14 +738,14 @@ void Net::Impl::forwardLayer(LayerData& ld)
const Mat& m = ld.outputBlobs[i];
if (!checkRange(m))
{
- std::cerr << "WARNING: NaN detected in layer output: id=" << ld.id << " name=" << layer->name << std::endl;
- std::cerr << "output id=" << i << " output shape=" << shape(m) << std::endl;
+ CV_LOG_WARNING(NULL, "NaN detected in layer output: "
+ << cv::format("id=%d name=%s output id=%zu output shape=", ld.id, layer->name.c_str(), i) << shape(m));
fail = true;
}
else if (!checkRange(m, true, NULL, -1e6, 1e6))
{
- std::cerr << "WARNING: Inf detected in layer output: id=" << ld.id << " name=" << layer->name << std::endl;
- std::cerr << "output id=" << i << " output shape=" << shape(m) << std::endl;
+ CV_LOG_WARNING(NULL, "Inf detected in layer output: "
+ << cv::format("id=%d name=%s output id=%zu output shape=", ld.id, layer->name.c_str(), i) << shape(m));
fail = true;
}
}
diff --git a/modules/dnn/src/onnx/onnx_graph_simplifier.cpp b/modules/dnn/src/onnx/onnx_graph_simplifier.cpp
index 120cd936b7..8f9be6e961 100644
--- a/modules/dnn/src/onnx/onnx_graph_simplifier.cpp
+++ b/modules/dnn/src/onnx/onnx_graph_simplifier.cpp
@@ -1125,7 +1125,7 @@ Mat getMatFromTensor(const opencv_onnx::TensorProto& tensor_proto)
else if (datatype == opencv_onnx::TensorProto_DataType_FLOAT16)
{
// FIXME, for now, we only load FP16 Tensor as FP32 Mat, full support for FP16 is required in the future.
- CV_LOG_ONCE_WARNING(NULL, "DNN: load FP16 model as FP32 model, and it takes twice the FP16 RAM requirement.");
+ CV_LOG_ONCE_INFO(NULL, "DNN: load FP16 model as FP32 model, and it takes twice the FP16 RAM requirement.");
// ONNX saves float 16 data in two format: int32 and raw_data.
// Link: https://github.com/onnx/onnx/issues/4460#issuecomment-1224373746
diff --git a/modules/dnn/src/op_cann.hpp b/modules/dnn/src/op_cann.hpp
index c60c311b7f..1d15eab6a3 100644
--- a/modules/dnn/src/op_cann.hpp
+++ b/modules/dnn/src/op_cann.hpp
@@ -10,7 +10,11 @@
#include "graph/graph.h" // ge::Graph; ge::Operator from operator.h
#include "graph/ge_error_codes.h" // GRAPH_SUCCESS, ...
-#include "op_proto/built-in/inc/all_ops.h" // ge::Conv2D, ...
+#ifdef CANN_VERSION_BELOW_6_3_ALPHA002
+ #include "op_proto/built-in/inc/all_ops.h" // ge::Conv2D, ...
+#else
+ #include "built-in/op_proto/inc/all_ops.h" // ge::Conv2D, ...
+#endif
#include "graph/tensor.h" // ge::Shape, ge::Tensor, ge::TensorDesc
#include "graph/types.h" // DT_FLOAT, ... ; FORMAT_NCHW, ...
diff --git a/modules/dnn/src/opencl/activations.cl b/modules/dnn/src/opencl/activations.cl
index 317d2c1e62..96b56725fb 100644
--- a/modules/dnn/src/opencl/activations.cl
+++ b/modules/dnn/src/opencl/activations.cl
@@ -73,14 +73,23 @@ __kernel void ReLU6Forward(const int count, __global const T* in, __global T* ou
}
}
+__kernel void ChannelsPReLUForward(const int count, const int channels, const int plane_size,
+ __global const T* in, __global T* out,
+ __global const KERNEL_ARG_DTYPE* slope_data)
+{
+ int index = get_global_id(0);
+ int c = (index / plane_size) % channels;
+ if(index < count)
+ out[index] = in[index] > 0 ? in[index] : in[index] * slope_data[c];
+}
+
__kernel void PReLUForward(const int count, const int channels, const int plane_size,
__global const T* in, __global T* out,
__global const KERNEL_ARG_DTYPE* slope_data)
{
int index = get_global_id(0);
- int c = (index / plane_size) % channels;
if(index < count)
- out[index] = in[index] > 0 ? in[index] : in[index] * slope_data[c];
+ out[index] = in[index] > 0 ? in[index] : in[index] * slope_data[index];
}
__kernel void TanHForward(const int count, __global T* in, __global T* out) {
@@ -352,4 +361,4 @@ __kernel void ReciprocalForward(const int n, __global T* in, __global T* out)
int index = get_global_id(0);
if(index < n)
out[index] = 1.0f/in[index];
-}
\ No newline at end of file
+}
diff --git a/modules/dnn/src/tensorflow/tf_importer.cpp b/modules/dnn/src/tensorflow/tf_importer.cpp
index 8e9970528a..a23fac187b 100644
--- a/modules/dnn/src/tensorflow/tf_importer.cpp
+++ b/modules/dnn/src/tensorflow/tf_importer.cpp
@@ -589,6 +589,7 @@ private:
void parsePack (tensorflow::GraphDef& net, const tensorflow::NodeDef& layer, LayerParams& layerParams);
void parseClipByValue (tensorflow::GraphDef& net, const tensorflow::NodeDef& layer, LayerParams& layerParams);
void parseLeakyRelu (tensorflow::GraphDef& net, const tensorflow::NodeDef& layer, LayerParams& layerParams);
+ void parsePReLU (tensorflow::GraphDef& net, const tensorflow::NodeDef& layer, LayerParams& layerParams);
void parseActivation (tensorflow::GraphDef& net, const tensorflow::NodeDef& layer, LayerParams& layerParams);
void parseExpandDims (tensorflow::GraphDef& net, const tensorflow::NodeDef& layer, LayerParams& layerParams);
void parseSquare (tensorflow::GraphDef& net, const tensorflow::NodeDef& layer, LayerParams& layerParams);
@@ -668,6 +669,7 @@ TFImporter::DispatchMap TFImporter::buildDispatchMap()
dispatch["Pack"] = &TFImporter::parsePack;
dispatch["ClipByValue"] = &TFImporter::parseClipByValue;
dispatch["LeakyRelu"] = &TFImporter::parseLeakyRelu;
+ dispatch["PReLU"] = &TFImporter::parsePReLU;
dispatch["Abs"] = dispatch["Tanh"] = dispatch["Sigmoid"] = dispatch["Relu"] =
dispatch["Elu"] = dispatch["Exp"] = dispatch["Identity"] = dispatch["Relu6"] = &TFImporter::parseActivation;
dispatch["ExpandDims"] = &TFImporter::parseExpandDims;
@@ -2622,6 +2624,27 @@ void TFImporter::parseLeakyRelu(tensorflow::GraphDef& net, const tensorflow::Nod
connectToAllBlobs(layer_id, dstNet, parsePin(layer.input(0)), id, num_inputs);
}
+void TFImporter::parsePReLU(tensorflow::GraphDef& net, const tensorflow::NodeDef& layer, LayerParams& layerParams)
+{
+ const std::string& name = layer.name();
+
+ Mat scales;
+ blobFromTensor(getConstBlob(layer, value_id, 1), scales);
+
+ layerParams.blobs.resize(1);
+
+ if (scales.dims == 3) {
+ // Considering scales from Keras wih HWC layout;
+ transposeND(scales, {2, 0, 1}, layerParams.blobs[0]);
+ } else {
+ layerParams.blobs[0] = scales;
+ }
+
+ int id = dstNet.addLayer(name, "PReLU", layerParams);
+ layer_id[name] = id;
+ connect(layer_id, dstNet, parsePin(layer.input(0)), id, 0);
+}
+
// "Abs" "Tanh" "Sigmoid" "Relu" "Elu" "Exp" "Identity" "Relu6"
void TFImporter::parseActivation(tensorflow::GraphDef& net, const tensorflow::NodeDef& layer, LayerParams& layerParams)
{
diff --git a/modules/dnn/src/tflite/tflite_importer.cpp b/modules/dnn/src/tflite/tflite_importer.cpp
index 4a186eaee0..7feded69ce 100644
--- a/modules/dnn/src/tflite/tflite_importer.cpp
+++ b/modules/dnn/src/tflite/tflite_importer.cpp
@@ -59,6 +59,7 @@ private:
void parseUnpooling(const Operator& op, const std::string& opcode, LayerParams& layerParams);
void parseReshape(const Operator& op, const std::string& opcode, LayerParams& layerParams);
void parseConcat(const Operator& op, const std::string& opcode, LayerParams& layerParams);
+ void parsePack(const Operator& op, const std::string& opcode, LayerParams& layerParams);
void parseResize(const Operator& op, const std::string& opcode, LayerParams& layerParams);
void parseDeconvolution(const Operator& op, const std::string& opcode, LayerParams& layerParams);
void parseQuantize(const Operator& op, const std::string& opcode, LayerParams& layerParams);
@@ -70,6 +71,8 @@ private:
void parseActivation(const Operator& op, const std::string& opcode, LayerParams& layerParams, bool isFused);
void addLayer(LayerParams& layerParams, const Operator& op);
int addPermuteLayer(const std::vector& order, const std::string& permName, const std::pair& inpId, int dtype);
+ int addReshapeLayer(const std::vector& shape, int axis, int num_axes,
+ const std::string& name, const std::pair& inpId, int dtype);
inline bool isInt8(const Operator& op);
inline void getQuantParams(const Operator& op, float& inpScale, int& inpZero, float& outScale, int& outZero);
};
@@ -267,6 +270,7 @@ TFLiteImporter::DispatchMap TFLiteImporter::buildDispatchMap()
dispatch["PAD"] = &TFLiteImporter::parsePadding;
dispatch["RESHAPE"] = &TFLiteImporter::parseReshape;
dispatch["CONCATENATION"] = &TFLiteImporter::parseConcat;
+ dispatch["PACK"] = &TFLiteImporter::parsePack;
dispatch["RESIZE_BILINEAR"] = dispatch["RESIZE_NEAREST_NEIGHBOR"] = &TFLiteImporter::parseResize;
dispatch["Convolution2DTransposeBias"] = &TFLiteImporter::parseDeconvolution;
dispatch["QUANTIZE"] = &TFLiteImporter::parseQuantize;
@@ -596,16 +600,6 @@ void TFLiteImporter::parseUnpooling(const Operator& op, const std::string& opcod
void TFLiteImporter::parseReshape(const Operator& op, const std::string& opcode, LayerParams& layerParams) {
DataLayout inpLayout = layouts[op.inputs()->Get(0)];
- if (inpLayout == DNN_LAYOUT_NHWC) {
- // Permute to NCHW
- std::vector order = {0, 2, 3, 1};
- const std::string name = layerParams.name + "/permute";
- auto inpId = layerIds[op.inputs()->Get(0)];
- int permId = addPermuteLayer(order, name, inpId, isInt8(op) ? CV_8S : CV_32F); // NCHW -> NHWC
- layerIds[op.inputs()->Get(0)] = std::make_pair(permId, 0);
- layouts[op.outputs()->Get(0)] = DNN_LAYOUT_NCHW;
- }
-
layerParams.type = "Reshape";
std::vector shape;
if (op.inputs()->size() > 1) {
@@ -615,6 +609,22 @@ void TFLiteImporter::parseReshape(const Operator& op, const std::string& opcode,
CV_Assert(options);
shape.assign(options->new_shape()->begin(), options->new_shape()->end());
}
+
+ if (inpLayout == DNN_LAYOUT_NHWC) {
+ if (shape.size() == 4) {
+ // Keep data but change a shape to OpenCV's NCHW order
+ std::swap(shape[2], shape[3]);
+ std::swap(shape[1], shape[2]);
+ } else {
+ // Permute to NCHW entire data and reshape to given a shape
+ std::vector order = {0, 2, 3, 1};
+ const std::string name = layerParams.name + "/permute";
+ auto inpId = layerIds[op.inputs()->Get(0)];
+ int permId = addPermuteLayer(order, name, inpId, isInt8(op) ? CV_8S : CV_32F); // NCHW -> NHWC
+ layerIds[op.inputs()->Get(0)] = std::make_pair(permId, 0);
+ layouts[op.outputs()->Get(0)] = DNN_LAYOUT_NCHW;
+ }
+ }
layerParams.set("dim", DictValue::arrayInt(shape.data(), shape.size()));
addLayer(layerParams, op);
}
@@ -636,6 +646,47 @@ void TFLiteImporter::parseConcat(const Operator& op, const std::string& opcode,
parseFusedActivation(op, options->fused_activation_function());
}
+void TFLiteImporter::parsePack(const Operator& op, const std::string& opcode, LayerParams& layerParams) {
+ auto options = reinterpret_cast(op.builtin_options());
+ int axis = options->axis();
+
+ DataLayout inpLayout = layouts[op.inputs()->Get(0)];
+ if (inpLayout == DNN_LAYOUT_NHWC) {
+ // OpenCV works in NCHW data layout. So change the axis correspondingly.
+ axis = normalize_axis(axis, 5); // 5 because Pack adds a new axis so -1 would mean 4
+ static const int remap[] = {0, 1, 3, 4, 2};
+ axis = remap[axis];
+ }
+
+ // Replace Pack layer to Reshape + Concat
+ // Use a set because there are models which replicate single layer data by Pack.
+ std::set op_inputs(op.inputs()->begin(), op.inputs()->end());
+ std::map > originLayerIds;
+ for (int inp : op_inputs) {
+ auto inpId = layerIds[inp];
+ int dims = modelTensors->Get(inp)->shape()->size();
+
+ std::vector shape{1, -1};
+ if (axis == dims) {
+ std::swap(shape[0], shape[1]);
+ }
+ const auto name = modelTensors->Get(inp)->name()->str() + "/reshape";
+ int reshapeId = addReshapeLayer(shape, axis == dims ? dims - 1 : axis, 1,
+ name, inpId, isInt8(op) ? CV_8S : CV_32F);
+
+ originLayerIds[inp] = layerIds[inp];
+ layerIds[inp] = std::make_pair(reshapeId, 0);
+ }
+ layerParams.type = "Concat";
+ layerParams.set("axis", axis);
+ addLayer(layerParams, op);
+
+ // Restore origin layer inputs
+ for (const auto& ids : originLayerIds) {
+ layerIds[ids.first] = ids.second;
+ }
+}
+
void TFLiteImporter::parseResize(const Operator& op, const std::string& opcode, LayerParams& layerParams) {
layerParams.type = "Resize";
@@ -666,6 +717,18 @@ int TFLiteImporter::addPermuteLayer(const std::vector& order, const std::st
return permId;
}
+int TFLiteImporter::addReshapeLayer(const std::vector& shape, int axis, int num_axes,
+ const std::string& name, const std::pair& inpId, int dtype)
+{
+ LayerParams lp;
+ lp.set("axis", axis);
+ lp.set("dim", DictValue::arrayInt(shape.data(), shape.size()));
+ lp.set("num_axes", num_axes);
+ int id = dstNet.addLayer(name, "Reshape", dtype, lp);
+ dstNet.connect(inpId.first, inpId.second, id, 0);
+ return id;
+}
+
void TFLiteImporter::parseDeconvolution(const Operator& op, const std::string& opcode, LayerParams& layerParams) {
layerParams.type = "Deconvolution";
@@ -771,6 +834,8 @@ void TFLiteImporter::parseDetectionPostProcess(const Operator& op, const std::st
parameters[keys[i]] = *reinterpret_cast(data + offset + i * 4);
}
+ parameters["num_classes"] = modelTensors->Get(op.inputs()->Get(1))->shape()->Get(2);
+
layerParams.type = "DetectionOutput";
layerParams.set("num_classes", parameters["num_classes"]);
layerParams.set("share_location", true);
@@ -780,7 +845,6 @@ void TFLiteImporter::parseDetectionPostProcess(const Operator& op, const std::st
layerParams.set("top_k", parameters["max_detections"]);
layerParams.set("keep_top_k", parameters["max_detections"]);
layerParams.set("code_type", "CENTER_SIZE");
- layerParams.set("variance_encoded_in_target", true);
layerParams.set("loc_pred_transposed", true);
// Replace third input from tensor to Const layer with the priors
@@ -796,10 +860,27 @@ void TFLiteImporter::parseDetectionPostProcess(const Operator& op, const std::st
priors.col(2) = priors.col(0) + priors.col(3);
priors.col(3) = priors.col(1) + tmp;
+ float x_scale = *(float*)¶meters["x_scale"];
+ float y_scale = *(float*)¶meters["y_scale"];
+ float w_scale = *(float*)¶meters["w_scale"];
+ float h_scale = *(float*)¶meters["h_scale"];
+ if (x_scale != 1.0f || y_scale != 1.0f || w_scale != 1.0f || h_scale != 1.0f) {
+ int numPriors = priors.rows;
+ priors.resize(numPriors * 2);
+ Mat_ scales({1, 4}, {1.f / x_scale, 1.f / y_scale,
+ 1.f / w_scale, 1.f / h_scale});
+ repeat(scales, numPriors, 1, priors.rowRange(numPriors, priors.rows));
+ priors = priors.reshape(1, {1, 2, (int)priors.total() / 2});
+ layerParams.set("variance_encoded_in_target", false);
+ } else {
+ priors = priors.reshape(1, {1, 1, (int)priors.total()});
+ layerParams.set("variance_encoded_in_target", true);
+ }
+
LayerParams priorsLP;
priorsLP.name = layerParams.name + "/priors";
priorsLP.type = "Const";
- priorsLP.blobs.resize(1, priors.reshape(1, {1, 1, (int)priors.total()}));
+ priorsLP.blobs.resize(1, priors);
int priorsId = dstNet.addLayer(priorsLP.name, priorsLP.type, priorsLP);
layerIds[op.inputs()->Get(2)] = std::make_pair(priorsId, 0);
diff --git a/modules/dnn/test/test_tf_importer.cpp b/modules/dnn/test/test_tf_importer.cpp
index b795076f55..e2dfbc706e 100644
--- a/modules/dnn/test/test_tf_importer.cpp
+++ b/modules/dnn/test/test_tf_importer.cpp
@@ -1675,6 +1675,7 @@ TEST_P(Test_TensorFlow_layers, clip_by_value)
TEST_P(Test_TensorFlow_layers, tf2_prelu)
{
+ double l1 = 0, lInf = 0;
if (backend == DNN_BACKEND_CUDA)
applyTestTag(CV_TEST_TAG_DNN_SKIP_CUDA); // not supported; only across channels is supported
#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2022010000)
@@ -1686,6 +1687,11 @@ TEST_P(Test_TensorFlow_layers, tf2_prelu)
applyTestTag(target == DNN_TARGET_OPENCL ? CV_TEST_TAG_DNN_SKIP_IE_OPENCL : CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16,
CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION
);
+#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_GE(2023000000)
+ if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == DNN_TARGET_OPENCL) {
+ l1 = 1e-4;
+ lInf = 1e-3;
+ }
#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021040000)
if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
{
@@ -1705,7 +1711,7 @@ TEST_P(Test_TensorFlow_layers, tf2_prelu)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NGRAPH);
#endif
- runTensorFlowNet("tf2_prelu");
+ runTensorFlowNet("tf2_prelu", false, l1, lInf);
}
TEST_P(Test_TensorFlow_layers, tf2_permute_nhwc_ncwh)
diff --git a/modules/dnn/test/test_tflite_importer.cpp b/modules/dnn/test/test_tflite_importer.cpp
index 5a1742ed97..c5bee0c086 100644
--- a/modules/dnn/test/test_tflite_importer.cpp
+++ b/modules/dnn/test/test_tflite_importer.cpp
@@ -31,9 +31,8 @@ void testInputShapes(const Net& net, const std::vector& inps) {
}
}
-void testModel(const std::string& modelName, const Mat& input, double l1 = 1e-5, double lInf = 1e-4)
+void testModel(Net& net, const std::string& modelName, const Mat& input, double l1 = 1e-5, double lInf = 1e-4)
{
- Net net = readNet(findDataFile("dnn/tflite/" + modelName + ".tflite", false));
testInputShapes(net, {input});
net.setInput(input);
@@ -49,6 +48,12 @@ void testModel(const std::string& modelName, const Mat& input, double l1 = 1e-5,
}
}
+void testModel(const std::string& modelName, const Mat& input, double l1 = 1e-5, double lInf = 1e-4)
+{
+ Net net = readNet(findDataFile("dnn/tflite/" + modelName + ".tflite", false));
+ testModel(net, modelName, input, l1, lInf);
+}
+
void testModel(const std::string& modelName, const Size& inpSize, double l1 = 1e-5, double lInf = 1e-4)
{
Mat input = imread(findDataFile("cv/shared/lena.png"));
@@ -56,6 +61,13 @@ void testModel(const std::string& modelName, const Size& inpSize, double l1 = 1e
testModel(modelName, input, l1, lInf);
}
+void testLayer(const std::string& modelName, double l1 = 1e-5, double lInf = 1e-4)
+{
+ Mat inp = blobFromNPY(findDataFile("dnn/tflite/" + modelName + "_inp.npy"));
+ Net net = readNet(findDataFile("dnn/tflite/" + modelName + ".tflite"));
+ testModel(net, modelName, inp, l1, lInf);
+}
+
// https://google.github.io/mediapipe/solutions/face_mesh
TEST(Test_TFLite, face_landmark)
{
@@ -146,6 +158,10 @@ TEST(Test_TFLite, EfficientDet_int8) {
normAssertDetections(ref, out, "", 0.5, 0.05, 0.1);
}
+TEST(Test_TFLite, replicate_by_pack) {
+ testLayer("replicate_by_pack");
+}
+
}} // namespace
#endif // OPENCV_TEST_DNN_TFLITE
diff --git a/modules/dnn/test/test_torch_importer.cpp b/modules/dnn/test/test_torch_importer.cpp
index 8510ec4e64..ae39d5d22e 100644
--- a/modules/dnn/test/test_torch_importer.cpp
+++ b/modules/dnn/test/test_torch_importer.cpp
@@ -566,14 +566,14 @@ TEST_P(Test_Torch_nets, FastNeuralStyle_accuracy)
}
else if(target == DNN_TARGET_CUDA_FP16)
{
- normAssert(out, refBlob, "", 0.6, 25);
+ normAssert(out, refBlob, "", 0.6, 26);
}
else if (target == DNN_TARGET_CPU_FP16)
{
normAssert(out, refBlob, "", 0.62, 25);
}
else
- normAssert(out, refBlob, "", 0.5, 1.1);
+ normAssert(out, refBlob, "", 0.5, 1.11);
}
}
diff --git a/modules/flann/include/opencv2/flann/any.h b/modules/flann/include/opencv2/flann/any.h
index 4906fec081..2228bd1cfc 100644
--- a/modules/flann/include/opencv2/flann/any.h
+++ b/modules/flann/include/opencv2/flann/any.h
@@ -19,16 +19,39 @@
#include
#include
+#include "opencv2/core/cvdef.h"
+#include "opencv2/core/utility.hpp"
+
namespace cvflann
{
namespace anyimpl
{
-struct bad_any_cast
+struct bad_any_cast : public std::exception
{
+ bad_any_cast() = default;
+
+ bad_any_cast(const char* src, const char* dst)
+ : message_(cv::format("cvflann::bad_any_cast(from %s to %s)", src, dst)) {}
+
+
+ const char* what() const noexcept override
+ {
+ return message_.c_str();
+ }
+
+private:
+ std::string message_{"cvflann::bad_any_cast"};
};
+#ifndef CV_THROW_IF_TYPE_MISMATCH
+#define CV_THROW_IF_TYPE_MISMATCH(src_type_info, dst_type_info) \
+ if ((src_type_info) != (dst_type_info)) \
+ throw cvflann::anyimpl::bad_any_cast((src_type_info).name(), \
+ (dst_type_info).name())
+#endif
+
struct empty_any
{
};
@@ -271,7 +294,7 @@ public:
template
T& cast()
{
- if (policy->type() != typeid(T)) throw anyimpl::bad_any_cast();
+ CV_THROW_IF_TYPE_MISMATCH(policy->type(), typeid(T));
T* r = reinterpret_cast(policy->get_value(&object));
return *r;
}
@@ -280,7 +303,7 @@ public:
template
const T& cast() const
{
- if (policy->type() != typeid(T)) throw anyimpl::bad_any_cast();
+ CV_THROW_IF_TYPE_MISMATCH(policy->type(), typeid(T));
const T* r = reinterpret_cast(policy->get_value(&object));
return *r;
}
diff --git a/modules/flann/include/opencv2/flann/general.h b/modules/flann/include/opencv2/flann/general.h
index 29fa8be121..e65cba2f8a 100644
--- a/modules/flann/include/opencv2/flann/general.h
+++ b/modules/flann/include/opencv2/flann/general.h
@@ -31,6 +31,8 @@
#ifndef OPENCV_FLANN_GENERAL_H_
#define OPENCV_FLANN_GENERAL_H_
+#include "opencv2/core/version.hpp"
+
#if CV_VERSION_MAJOR <= 4
//! @cond IGNORED
diff --git a/modules/flann/include/opencv2/flann/matrix.h b/modules/flann/include/opencv2/flann/matrix.h
index fb871bd73c..bfbf91ef5c 100644
--- a/modules/flann/include/opencv2/flann/matrix.h
+++ b/modules/flann/include/opencv2/flann/matrix.h
@@ -35,6 +35,9 @@
#include
+#include "opencv2/core/cvdef.h"
+#include "opencv2/flann/defines.h"
+
namespace cvflann
{
diff --git a/modules/flann/include/opencv2/flann/params.h b/modules/flann/include/opencv2/flann/params.h
index c9093cde8c..1a8e127035 100644
--- a/modules/flann/include/opencv2/flann/params.h
+++ b/modules/flann/include/opencv2/flann/params.h
@@ -72,11 +72,16 @@ struct SearchParams : public IndexParams
template
-T get_param(const IndexParams& params, cv::String name, const T& default_value)
+T get_param(const IndexParams& params, const cv::String& name, const T& default_value)
{
IndexParams::const_iterator it = params.find(name);
if (it != params.end()) {
- return it->second.cast();
+ try {
+ return it->second.cast();
+ } catch (const std::exception& e) {
+ CV_Error_(cv::Error::StsBadArg,
+ ("FLANN '%s' param type mismatch: %s", name.c_str(), e.what()));
+ }
}
else {
return default_value;
@@ -84,11 +89,16 @@ T get_param(const IndexParams& params, cv::String name, const T& default_value)
}
template
-T get_param(const IndexParams& params, cv::String name)
+T get_param(const IndexParams& params, const cv::String& name)
{
IndexParams::const_iterator it = params.find(name);
if (it != params.end()) {
- return it->second.cast();
+ try {
+ return it->second.cast();
+ } catch (const std::exception& e) {
+ CV_Error_(cv::Error::StsBadArg,
+ ("FLANN '%s' param type mismatch: %s", name.c_str(), e.what()));
+ }
}
else {
FLANN_THROW(cv::Error::StsBadArg, cv::String("Missing parameter '")+name+cv::String("' in the parameters given"));
diff --git a/modules/flann/include/opencv2/flann/result_set.h b/modules/flann/include/opencv2/flann/result_set.h
index 47ad231105..c5d31e8ade 100644
--- a/modules/flann/include/opencv2/flann/result_set.h
+++ b/modules/flann/include/opencv2/flann/result_set.h
@@ -40,6 +40,9 @@
#include
#include
+#include "opencv2/core/base.hpp"
+#include "opencv2/core/cvdef.h"
+
namespace cvflann
{
diff --git a/modules/flann/misc/python/pyopencv_flann.hpp b/modules/flann/misc/python/pyopencv_flann.hpp
index 3d97edbb59..086ca5f09f 100644
--- a/modules/flann/misc/python/pyopencv_flann.hpp
+++ b/modules/flann/misc/python/pyopencv_flann.hpp
@@ -17,57 +17,89 @@ PyObject* pyopencv_from(const cvflann_flann_distance_t& value)
template<>
bool pyopencv_to(PyObject *o, cv::flann::IndexParams& p, const ArgInfo& info)
{
- CV_UNUSED(info);
- bool ok = true;
- PyObject* key = NULL;
- PyObject* item = NULL;
- Py_ssize_t pos = 0;
-
if (!o || o == Py_None)
+ {
return true;
+ }
+
+ if(!PyDict_Check(o))
+ {
+ failmsg("Argument '%s' is not a dictionary", info.name);
+ return false;
+ }
+
+ PyObject* key_obj = NULL;
+ PyObject* value_obj = NULL;
+ Py_ssize_t key_pos = 0;
- if(PyDict_Check(o)) {
- while(PyDict_Next(o, &pos, &key, &item))
+ while(PyDict_Next(o, &key_pos, &key_obj, &value_obj))
+ {
+ // get key
+ std::string key;
+ if (!getUnicodeString(key_obj, key))
{
- // get key
- std::string k;
- if (!getUnicodeString(key, k))
+ failmsg("Key at pos %lld is not a string", static_cast(key_pos));
+ return false;
+ }
+ // key_arg_info.name is bound to key lifetime
+ const ArgInfo key_arg_info(key.c_str(), false);
+
+ // get value
+ if (isBool(value_obj))
+ {
+ npy_bool npy_value = NPY_FALSE;
+ if (PyArray_BoolConverter(value_obj, &npy_value) >= 0)
{
- ok = false;
- break;
+ p.setBool(key, npy_value == NPY_TRUE);
+ continue;
}
- // get value
- if( !!PyBool_Check(item) )
+ PyErr_Clear();
+ }
+
+ int int_value = 0;
+ if (pyopencv_to(value_obj, int_value, key_arg_info))
+ {
+ if (key == "algorithm")
{
- p.setBool(k, item == Py_True);
+ p.setAlgorithm(int_value);
}
- else if( PyInt_Check(item) )
+ else
{
- int value = (int)PyInt_AsLong(item);
- if( strcmp(k.c_str(), "algorithm") == 0 )
- p.setAlgorithm(value);
- else
- p.setInt(k, value);
+ p.setInt(key, int_value);
}
- else if( PyFloat_Check(item) )
+ continue;
+ }
+ PyErr_Clear();
+
+ double flt_value = 0.0;
+ if (pyopencv_to(value_obj, flt_value, key_arg_info))
+ {
+ if (key == "eps")
{
- double value = PyFloat_AsDouble(item);
- p.setDouble(k, value);
+ p.setFloat(key, static_cast(flt_value));
}
else
{
- std::string val_str;
- if (!getUnicodeString(item, val_str))
- {
- ok = false;
- break;
- }
- p.setString(k, val_str);
+ p.setDouble(key, flt_value);
}
+ continue;
}
- }
+ PyErr_Clear();
- return ok && !PyErr_Occurred();
+ std::string str_value;
+ if (getUnicodeString(value_obj, str_value))
+ {
+ p.setString(key, str_value);
+ continue;
+ }
+ PyErr_Clear();
+ // All conversions are failed
+ failmsg("Failed to parse IndexParam with key '%s'. "
+ "Supported types: [bool, int, float, str]", key.c_str());
+ return false;
+
+ }
+ return true;
}
template<>
diff --git a/modules/flann/misc/python/test/test_flann_based_matcher.py b/modules/flann/misc/python/test/test_flann_based_matcher.py
new file mode 100644
index 0000000000..cf8c2ededd
--- /dev/null
+++ b/modules/flann/misc/python/test/test_flann_based_matcher.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import cv2
+import numpy as np
+
+from tests_common import NewOpenCVTests
+
+
+class FlannBasedMatcher(NewOpenCVTests):
+ def test_all_parameters_can_be_passed(self):
+ img1 = self.get_sample("samples/data/right01.jpg")
+ img2 = self.get_sample("samples/data/right02.jpg")
+
+ orb = cv2.ORB.create()
+
+ kp1, des1 = orb.detectAndCompute(img1, None)
+ kp2, des2 = orb.detectAndCompute(img2, None)
+ FLANN_INDEX_KDTREE = 1
+ index_param = dict(algorithm=FLANN_INDEX_KDTREE, trees=4)
+ search_param = dict(checks=32, sorted=True, eps=0.5,
+ explore_all_trees=False)
+ matcher = cv2.FlannBasedMatcher(index_param, search_param)
+ matches = matcher.knnMatch(np.float32(des1), np.float32(des2), k=2)
+ self.assertGreater(len(matches), 0)
+
+
+if __name__ == '__main__':
+ NewOpenCVTests.bootstrap()
diff --git a/modules/gapi/CMakeLists.txt b/modules/gapi/CMakeLists.txt
index 2433c41d95..9ecbb6d514 100644
--- a/modules/gapi/CMakeLists.txt
+++ b/modules/gapi/CMakeLists.txt
@@ -162,6 +162,7 @@ set(gapi_srcs
# ONNX backend
src/backends/onnx/gonnxbackend.cpp
+ src/backends/onnx/dml_ep.cpp
# Render backend
src/backends/render/grenderocv.cpp
@@ -254,6 +255,7 @@ ocv_target_link_libraries(${the_module} PRIVATE ade)
if(TARGET ocv.3rdparty.openvino AND OPENCV_GAPI_WITH_OPENVINO)
ocv_target_link_libraries(${the_module} PRIVATE ocv.3rdparty.openvino)
+ ocv_install_used_external_targets(ocv.3rdparty.openvino)
endif()
if(HAVE_TBB)
@@ -365,6 +367,9 @@ endif()
if(HAVE_ONNX)
ocv_target_link_libraries(${the_module} PRIVATE ${ONNX_LIBRARY})
ocv_target_compile_definitions(${the_module} PRIVATE HAVE_ONNX=1)
+ if(HAVE_ONNX_DML)
+ ocv_target_compile_definitions(${the_module} PRIVATE HAVE_ONNX_DML=1)
+ endif()
if(TARGET opencv_test_gapi)
ocv_target_compile_definitions(opencv_test_gapi PRIVATE HAVE_ONNX=1)
ocv_target_link_libraries(opencv_test_gapi PRIVATE ${ONNX_LIBRARY})
diff --git a/modules/gapi/include/opencv2/gapi/gkernel.hpp b/modules/gapi/include/opencv2/gapi/gkernel.hpp
index 50d2efdd55..1b910adc82 100644
--- a/modules/gapi/include/opencv2/gapi/gkernel.hpp
+++ b/modules/gapi/include/opencv2/gapi/gkernel.hpp
@@ -51,6 +51,7 @@ struct GAPI_EXPORTS GKernel
GShapes outShapes; // types (shapes) kernel's outputs
GKinds inKinds; // kinds of kernel's inputs (fixme: below)
GCtors outCtors; // captured constructors for template output types
+ GKinds outKinds; // kinds of kernel's outputs (fixme: below)
};
// TODO: It's questionable if inKinds should really be here. Instead,
// this information could come from meta.
@@ -227,7 +228,8 @@ public:
, &K::getOutMeta
, {detail::GTypeTraits::shape...}
, {detail::GTypeTraits::op_kind...}
- , {detail::GObtainCtor::get()...}});
+ , {detail::GObtainCtor::get()...}
+ , {detail::GTypeTraits::op_kind...}});
call.pass(args...); // TODO: std::forward() here?
return yield(call, typename detail::MkSeq::type());
}
@@ -251,7 +253,8 @@ public:
, &K::getOutMeta
, {detail::GTypeTraits::shape}
, {detail::GTypeTraits::op_kind...}
- , {detail::GObtainCtor::get()}});
+ , {detail::GObtainCtor::get()}
+ , {detail::GTypeTraits::op_kind}});
call.pass(args...);
return detail::Yield::yield(call, 0);
}
diff --git a/modules/gapi/include/opencv2/gapi/infer.hpp b/modules/gapi/include/opencv2/gapi/infer.hpp
index c1f9501873..abbd32ba20 100644
--- a/modules/gapi/include/opencv2/gapi/infer.hpp
+++ b/modules/gapi/include/opencv2/gapi/infer.hpp
@@ -101,8 +101,10 @@ public:
if (it == m_priv->blobs.end()) {
// FIXME: Avoid modifying GKernel
auto shape = cv::detail::GTypeTraits::shape;
+ auto kind = cv::detail::GTypeTraits::op_kind;
m_priv->call->kernel().outShapes.push_back(shape);
m_priv->call->kernel().outCtors.emplace_back(cv::detail::GObtainCtor::get());
+ m_priv->call->kernel().outKinds.emplace_back(kind);
auto out_idx = static_cast(m_priv->blobs.size());
it = m_priv->blobs.emplace(name,
cv::detail::Yield::yield(*(m_priv->call), out_idx)).first;
@@ -175,6 +177,7 @@ std::shared_ptr makeCall(const std::string &tag,
{}, // outShape will be filled later
std::move(kinds),
{}, // outCtors will be filled later
+ {}, // outKinds will be filled later
});
call->setArgs(std::move(args));
diff --git a/modules/gapi/include/opencv2/gapi/infer/bindings_onnx.hpp b/modules/gapi/include/opencv2/gapi/infer/bindings_onnx.hpp
index af9f3c6f6f..4ba829df09 100644
--- a/modules/gapi/include/opencv2/gapi/infer/bindings_onnx.hpp
+++ b/modules/gapi/include/opencv2/gapi/infer/bindings_onnx.hpp
@@ -33,6 +33,15 @@ public:
GAPI_WRAP
PyParams& cfgNormalize(const std::string &layer_name, bool flag);
+ GAPI_WRAP
+ PyParams& cfgAddExecutionProvider(ep::OpenVINO ep);
+
+ GAPI_WRAP
+ PyParams& cfgAddExecutionProvider(ep::DirectML ep);
+
+ GAPI_WRAP
+ PyParams& cfgDisableMemPattern();
+
GBackend backend() const;
std::string tag() const;
cv::util::any params() const;
diff --git a/modules/gapi/include/opencv2/gapi/infer/onnx.hpp b/modules/gapi/include/opencv2/gapi/infer/onnx.hpp
index dc9a51e541..64b855acd7 100644
--- a/modules/gapi/include/opencv2/gapi/infer/onnx.hpp
+++ b/modules/gapi/include/opencv2/gapi/infer/onnx.hpp
@@ -27,6 +27,126 @@ namespace gapi {
*/
namespace onnx {
+/**
+ * @brief This namespace contains Execution Providers structures for G-API ONNX Runtime backend.
+ */
+namespace ep {
+
+/**
+ * @brief This structure provides functions
+ * that fill inference options for ONNX OpenVINO Execution Provider.
+ * Please follow https://onnxruntime.ai/docs/execution-providers/OpenVINO-ExecutionProvider.html#summary-of-options
+ */
+struct GAPI_EXPORTS_W_SIMPLE OpenVINO {
+ // NB: Used from python.
+ /// @private -- Exclude this constructor from OpenCV documentation
+ GAPI_WRAP
+ OpenVINO() = default;
+
+ /** @brief Class constructor.
+
+ Constructs OpenVINO parameters based on device type information.
+
+ @param dev_type Target device type to use. ("CPU_FP32", "GPU_FP16", etc)
+ */
+ GAPI_WRAP
+ explicit OpenVINO(const std::string &dev_type)
+ : device_type(dev_type) {
+ }
+
+ /** @brief Specifies OpenVINO Execution Provider cache dir.
+
+ This function is used to explicitly specify the path to save and load
+ the blobs enabling model caching feature.
+
+ @param dir Path to the directory what will be used as cache.
+ @return reference to this parameter structure.
+ */
+ GAPI_WRAP
+ OpenVINO& cfgCacheDir(const std::string &dir) {
+ cache_dir = dir;
+ return *this;
+ }
+
+ /** @brief Specifies OpenVINO Execution Provider number of threads.
+
+ This function is used to override the accelerator default value
+ of number of threads with this value at runtime.
+
+ @param nthreads Number of threads.
+ @return reference to this parameter structure.
+ */
+ GAPI_WRAP
+ OpenVINO& cfgNumThreads(size_t nthreads) {
+ num_of_threads = nthreads;
+ return *this;
+ }
+
+ /** @brief Enables OpenVINO Execution Provider opencl throttling.
+
+ This function is used to enable OpenCL queue throttling for GPU devices
+ (reduces CPU utilization when using GPU).
+
+ @return reference to this parameter structure.
+ */
+ GAPI_WRAP
+ OpenVINO& cfgEnableOpenCLThrottling() {
+ enable_opencl_throttling = true;
+ return *this;
+ }
+
+ /** @brief Enables OpenVINO Execution Provider dynamic shapes.
+
+ This function is used to enable OpenCL queue throttling for GPU devices
+ (reduces CPU utilization when using GPU).
+ This function is used to enable work with dynamic shaped models
+ whose shape will be set dynamically based on the infer input
+ image/data shape at run time in CPU.
+
+ @return reference to this parameter structure.
+ */
+ GAPI_WRAP
+ OpenVINO& cfgEnableDynamicShapes() {
+ enable_dynamic_shapes = true;
+ return *this;
+ }
+
+ std::string device_type;
+ std::string cache_dir;
+ size_t num_of_threads = 0;
+ bool enable_opencl_throttling = false;
+ bool enable_dynamic_shapes = false;
+};
+
+/**
+ * @brief This structure provides functions
+ * that fill inference options for ONNX DirectML Execution Provider.
+ * Please follow https://onnxruntime.ai/docs/execution-providers/DirectML-ExecutionProvider.html#directml-execution-provider
+ */
+class GAPI_EXPORTS_W_SIMPLE DirectML {
+public:
+ // NB: Used from python.
+ /// @private -- Exclude this constructor from OpenCV documentation
+ GAPI_WRAP
+ DirectML() = default;
+
+ /** @brief Class constructor.
+
+ Constructs DirectML parameters based on device id.
+
+ @param device_id Target device id to use. ("0", "1", etc)
+ */
+ GAPI_WRAP
+ explicit DirectML(const int device_id) : ddesc(device_id) { };
+
+ using DeviceDesc = cv::util::variant;
+ DeviceDesc ddesc;
+};
+
+using EP = cv::util::variant;
+
+} // namespace ep
+
GAPI_EXPORTS cv::gapi::GBackend backend();
enum class TraitAs: int {
@@ -78,6 +198,9 @@ struct ParamDesc {
// when the generic infer parameters are unpacked (see GONNXBackendImpl::unpackKernel)
std::unordered_map > generic_mstd;
std::unordered_map generic_norm;
+
+ std::vector execution_providers;
+ bool disable_mem_pattern;
};
} // namespace detail
@@ -115,6 +238,7 @@ public:
desc.num_in = std::tuple_size::value;
desc.num_out = std::tuple_size::value;
desc.is_generic = false;
+ desc.disable_mem_pattern = false;
};
/** @brief Specifies sequence of network input layers names for inference.
@@ -279,6 +403,43 @@ public:
return *this;
}
+ /** @brief Adds execution provider for runtime.
+
+ The function is used to add ONNX Runtime OpenVINO Execution Provider options.
+
+ @param ep OpenVINO Execution Provider options.
+ @see cv::gapi::onnx::ep::OpenVINO.
+
+ @return the reference on modified object.
+ */
+ Params& cfgAddExecutionProvider(ep::OpenVINO&& ep) {
+ desc.execution_providers.emplace_back(std::move(ep));
+ return *this;
+ }
+
+ /** @brief Adds execution provider for runtime.
+
+ The function is used to add ONNX Runtime DirectML Execution Provider options.
+
+ @param ep DirectML Execution Provider options.
+ @see cv::gapi::onnx::ep::DirectML.
+
+ @return the reference on modified object.
+ */
+ Params& cfgAddExecutionProvider(ep::DirectML&& ep) {
+ desc.execution_providers.emplace_back(std::move(ep));
+ return *this;
+ }
+
+ /** @brief Disables the memory pattern optimization.
+
+ @return the reference on modified object.
+ */
+ Params& cfgDisableMemPattern() {
+ desc.disable_mem_pattern = true;
+ return *this;
+ }
+
// BEGIN(G-API's network parametrization API)
GBackend backend() const { return cv::gapi::onnx::backend(); }
std::string tag() const { return Net::tag(); }
@@ -306,18 +467,35 @@ public:
@param model_path path to model file (.onnx file).
*/
Params(const std::string& tag, const std::string& model_path)
- : desc{model_path, 0u, 0u, {}, {}, {}, {}, {}, {}, {}, {}, {}, true, {}, {} }, m_tag(tag) {}
+ : desc{model_path, 0u, 0u, {}, {}, {}, {}, {}, {}, {}, {}, {}, true, {}, {}, {}, false }, m_tag(tag) {}
+ /** @see onnx::Params::cfgMeanStdDev. */
void cfgMeanStdDev(const std::string &layer,
const cv::Scalar &m,
const cv::Scalar &s) {
desc.generic_mstd[layer] = std::make_pair(m, s);
}
+ /** @see onnx::Params::cfgNormalize. */
void cfgNormalize(const std::string &layer, bool flag) {
desc.generic_norm[layer] = flag;
}
+ /** @see onnx::Params::cfgAddExecutionProvider. */
+ void cfgAddExecutionProvider(ep::OpenVINO&& ep) {
+ desc.execution_providers.emplace_back(std::move(ep));
+ }
+
+ /** @see onnx::Params::cfgAddExecutionProvider. */
+ void cfgAddExecutionProvider(ep::DirectML&& ep) {
+ desc.execution_providers.emplace_back(std::move(ep));
+ }
+
+ /** @see onnx::Params::cfgDisableMemPattern. */
+ void cfgDisableMemPattern() {
+ desc.disable_mem_pattern = true;
+ }
+
// BEGIN(G-API's network parametrization API)
GBackend backend() const { return cv::gapi::onnx::backend(); }
std::string tag() const { return m_tag; }
diff --git a/modules/gapi/include/opencv2/gapi/streaming/desync.hpp b/modules/gapi/include/opencv2/gapi/streaming/desync.hpp
index 9e927872a3..0e04f5beb9 100644
--- a/modules/gapi/include/opencv2/gapi/streaming/desync.hpp
+++ b/modules/gapi/include/opencv2/gapi/streaming/desync.hpp
@@ -46,6 +46,7 @@ G desync(const G &g) {
, {cv::detail::GTypeTraits::shape} // output Shape
, {cv::detail::GTypeTraits::op_kind} // input data kinds
, {cv::detail::GObtainCtor::get()} // output template ctors
+ , {cv::detail::GTypeTraits::op_kind} // output data kinds
};
cv::GCall call(std::move(k));
call.pass(g);
diff --git a/modules/gapi/include/opencv2/gapi/streaming/meta.hpp b/modules/gapi/include/opencv2/gapi/streaming/meta.hpp
index cbcfc3aa37..cdd3d371cb 100644
--- a/modules/gapi/include/opencv2/gapi/streaming/meta.hpp
+++ b/modules/gapi/include/opencv2/gapi/streaming/meta.hpp
@@ -50,6 +50,7 @@ cv::GOpaque meta(G g, const std::string &tag) {
, {cv::detail::GTypeTraits::shape} // output Shape
, {cv::detail::GTypeTraits::op_kind} // input data kinds
, {cv::detail::GObtainCtor::get()} // output template ctors
+ , {cv::detail::GTypeTraits::op_kind} // output data kind
};
cv::GCall call(std::move(k));
call.pass(g);
diff --git a/modules/gapi/include/opencv2/gapi/util/variant.hpp b/modules/gapi/include/opencv2/gapi/util/variant.hpp
index f412110deb..48b55646c5 100644
--- a/modules/gapi/include/opencv2/gapi/util/variant.hpp
+++ b/modules/gapi/include/opencv2/gapi/util/variant.hpp
@@ -509,6 +509,11 @@ namespace util
return v.index() == util::variant::template index_of();
}
+#if defined(__GNUC__) && (__GNUC__ == 11 || __GNUC__ == 12)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+
template bool operator==(const variant &lhs,
const variant &rhs)
{
@@ -524,6 +529,10 @@ namespace util
return (eqs[lhs.index()])(lhs.memory, rhs.memory);
}
+#if defined(__GNUC__) && (__GNUC__ == 11 || __GNUC__ == 12)
+#pragma GCC diagnostic pop
+#endif
+
template bool operator!=(const variant &lhs,
const variant &rhs)
{
diff --git a/modules/gapi/misc/python/pyopencv_gapi.hpp b/modules/gapi/misc/python/pyopencv_gapi.hpp
index 70698ffd48..60d5f85479 100644
--- a/modules/gapi/misc/python/pyopencv_gapi.hpp
+++ b/modules/gapi/misc/python/pyopencv_gapi.hpp
@@ -29,6 +29,8 @@ using map_string_and_string = std::map;
using map_string_and_vector_size_t = std::map>;
using map_string_and_vector_float = std::map>;
using map_int_and_double = std::map;
+using ep_OpenVINO = cv::gapi::onnx::ep::OpenVINO;
+using ep_DirectML = cv::gapi::onnx::ep::DirectML;
// NB: Python wrapper generate T_U for T
// This behavior is only observed for inputs
diff --git a/modules/gapi/misc/python/python_bridge.hpp b/modules/gapi/misc/python/python_bridge.hpp
index 07d056abb7..53edf38b30 100644
--- a/modules/gapi/misc/python/python_bridge.hpp
+++ b/modules/gapi/misc/python/python_bridge.hpp
@@ -267,13 +267,14 @@ cv::gapi::wip::GOutputs::Priv::Priv(const std::string& id, cv::GKernel::M outMet
std::transform(args.begin(), args.end(), std::back_inserter(kinds),
[](const cv::GArg& arg) { return arg.opaque_kind; });
- m_call.reset(new cv::GCall{cv::GKernel{id, {}, outMeta, {}, std::move(kinds), {}}});
+ m_call.reset(new cv::GCall{cv::GKernel{id, {}, outMeta, {}, std::move(kinds), {}, {}}});
m_call->setArgs(std::move(args));
}
cv::GMat cv::gapi::wip::GOutputs::Priv::getGMat()
{
m_call->kernel().outShapes.push_back(cv::GShape::GMAT);
+ m_call->kernel().outKinds.push_back(cv::detail::OpaqueKind::CV_UNKNOWN);
// ...so _empty_ constructor is passed here.
m_call->kernel().outCtors.emplace_back(cv::util::monostate{});
return m_call->yield(output++);
@@ -282,6 +283,7 @@ cv::GMat cv::gapi::wip::GOutputs::Priv::getGMat()
cv::GScalar cv::gapi::wip::GOutputs::Priv::getGScalar()
{
m_call->kernel().outShapes.push_back(cv::GShape::GSCALAR);
+ m_call->kernel().outKinds.push_back(cv::detail::OpaqueKind::CV_UNKNOWN);
// ...so _empty_ constructor is passed here.
m_call->kernel().outCtors.emplace_back(cv::util::monostate{});
return m_call->yieldScalar(output++);
@@ -290,10 +292,14 @@ cv::GScalar cv::gapi::wip::GOutputs::Priv::getGScalar()
cv::GArrayT cv::gapi::wip::GOutputs::Priv::getGArray(cv::gapi::ArgType type)
{
m_call->kernel().outShapes.push_back(cv::GShape::GARRAY);
-#define HC(T, K) \
- case K: \
- m_call->kernel().outCtors.emplace_back(cv::detail::GObtainCtor>::get()); \
- return cv::GArrayT(m_call->yieldArray(output++)); \
+
+#define HC(T, K) \
+ case K: { \
+ const auto kind = cv::detail::GTypeTraits>::op_kind; \
+ m_call->kernel().outKinds.emplace_back(kind); \
+ m_call->kernel().outCtors.emplace_back(cv::detail::GObtainCtor>::get()); \
+ return cv::GArrayT(m_call->yieldArray(output++)); \
+ }
SWITCH(type, GARRAY_TYPE_LIST_G, HC)
#undef HC
@@ -302,10 +308,13 @@ cv::GArrayT cv::gapi::wip::GOutputs::Priv::getGArray(cv::gapi::ArgType type)
cv::GOpaqueT cv::gapi::wip::GOutputs::Priv::getGOpaque(cv::gapi::ArgType type)
{
m_call->kernel().outShapes.push_back(cv::GShape::GOPAQUE);
-#define HC(T, K) \
- case K: \
- m_call->kernel().outCtors.emplace_back(cv::detail::GObtainCtor>::get()); \
- return cv::GOpaqueT(m_call->yieldOpaque(output++)); \
+#define HC(T, K) \
+ case K: { \
+ const auto kind = cv::detail::GTypeTraits>::op_kind; \
+ m_call->kernel().outKinds.emplace_back(kind); \
+ m_call->kernel().outCtors.emplace_back(cv::detail::GObtainCtor>::get()); \
+ return cv::GOpaqueT(m_call->yieldOpaque(output++)); \
+ }
SWITCH(type, GOPAQUE_TYPE_LIST_G, HC)
#undef HC
diff --git a/modules/gapi/misc/python/test/test_gapi_sample_pipelines.py b/modules/gapi/misc/python/test/test_gapi_sample_pipelines.py
index 8e15d457d9..fbe9aafa54 100644
--- a/modules/gapi/misc/python/test/test_gapi_sample_pipelines.py
+++ b/modules/gapi/misc/python/test/test_gapi_sample_pipelines.py
@@ -207,7 +207,48 @@ try:
return Op
+ # NB: Just mock operation to test different kinds for output G-types.
+ @cv.gapi.op('custom.square_mean', in_types=[cv.GArray.Int], out_types=[cv.GOpaque.Float, cv.GArray.Int])
+ class GSquareMean:
+ @staticmethod
+ def outMeta(desc):
+ return cv.empty_gopaque_desc(), cv.empty_array_desc()
+
+
+ @cv.gapi.kernel(GSquareMean)
+ class GSquareMeanImpl:
+ @staticmethod
+ def run(arr):
+ squares = [val**2 for val in arr]
+ return sum(arr) / len(arr), squares
+
+ @cv.gapi.op('custom.squares', in_types=[cv.GArray.Int], out_types=[cv.GArray.Int])
+ class GSquare:
+ @staticmethod
+ def outMeta(desc):
+ return cv.empty_array_desc()
+
+
+ @cv.gapi.kernel(GSquare)
+ class GSquareImpl:
+ @staticmethod
+ def run(arr):
+ squares = [val**2 for val in arr]
+ return squares
+
+
class gapi_sample_pipelines(NewOpenCVTests):
+ def test_different_output_opaque_kinds(self):
+ g_in = cv.GArray.Int()
+ g_mean, g_squares = GSquareMean.on(g_in)
+ comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_mean, g_squares))
+
+ pkg = cv.gapi.kernels(GSquareMeanImpl)
+ mean, squares = comp.apply(cv.gin([1,2,3]), args=cv.gapi.compile_args(pkg))
+
+ self.assertEqual([1,4,9], list(squares))
+ self.assertEqual(2.0, mean)
+
def test_custom_op_add(self):
sz = (3, 3)
diff --git a/modules/gapi/src/backends/ie/giebackend.cpp b/modules/gapi/src/backends/ie/giebackend.cpp
index a257c21252..6026f29ae5 100644
--- a/modules/gapi/src/backends/ie/giebackend.cpp
+++ b/modules/gapi/src/backends/ie/giebackend.cpp
@@ -949,7 +949,11 @@ inline IE::Blob::Ptr extractBlob(IECallContext& ctx,
auto y_blob = ctx.uu.rctx->CreateBlob(blob_params->first.first, blob_params->first.second);
auto uv_blob = ctx.uu.rctx->CreateBlob(blob_params->second.first, blob_params->second.second);
-#if INF_ENGINE_RELEASE >= 2021010000
+#if INF_ENGINE_RELEASE > 2023000000
+ cv::util::throw_error(std::logic_error(
+ "IE Backend: NV12 feature has been deprecated in OpenVINO 1.0 API."
+ " The last version which supports this is 2023.0"));
+#elif INF_ENGINE_RELEASE >= 2021010000
return IE::make_shared_blob(y_blob, uv_blob);
#else
return IE::make_shared_blob(y_blob, uv_blob);
@@ -982,7 +986,14 @@ static void setBlob(InferenceEngine::InferRequest& req,
req.SetBlob(layer_name, blob);
} else {
GAPI_Assert(ctx.uu.params.kind == ParamDesc::Kind::Import);
+#if INF_ENGINE_RELEASE > 2023000000
+ // NB: SetBlob overload which accepts IE::PreProcessInfo
+ // has been deprecated - preprocessing can't be configured
+ // for "Import" networks anymore.
+ req.SetBlob(layer_name, blob);
+#else
req.SetBlob(layer_name, blob, ctx.uu.preproc_map.at(layer_name));
+#endif
}
}
@@ -1370,7 +1381,14 @@ static void cfgImagePreprocessing(const IE::InputInfo::Ptr &ii,
if (cv::util::holds_alternative(mm)) {
const auto &meta = util::get(mm);
if (meta.fmt == cv::MediaFormat::NV12) {
+#if INF_ENGINE_RELEASE > 2023000000
+ cv::util::throw_error(std::logic_error(
+ "IE Backend: cv::MediaFrame with NV12 format is no longer supported"
+ " because NV12 feature has been deprecated in OpenVINO 1.0 API."
+ " The last version which supports this is 2023.0"));
+#else
ii->getPreProcess().setColorFormat(IE::ColorFormat::NV12);
+#endif
}
}
}
@@ -1426,7 +1444,14 @@ static IE::PreProcessInfo createImagePreProcInfo(const cv::GMetaArg &mm,
if (cv::util::holds_alternative(mm)) {
const auto &meta = util::get(mm);
if (meta.fmt == cv::MediaFormat::NV12) {
+#if INF_ENGINE_RELEASE > 2023000000
+ cv::util::throw_error(std::logic_error(
+ "IE Backend: cv::MediaFrame with NV12 format is no longer supported"
+ " because NV12 feature has been deprecated in OpenVINO 1.0 API."
+ " The last version which supports this is 2023.0"));
+#else
info.setColorFormat(IE::ColorFormat::NV12);
+#endif
}
}
return info;
@@ -2299,7 +2324,11 @@ IE::Blob::Ptr cv::gapi::ie::util::to_ie(const cv::Mat &blob) {
IE::Blob::Ptr cv::gapi::ie::util::to_ie(const cv::Mat &y_plane, const cv::Mat &uv_plane) {
auto y_blob = wrapIE(y_plane, cv::gapi::ie::TraitAs::IMAGE);
auto uv_blob = wrapIE(uv_plane, cv::gapi::ie::TraitAs::IMAGE);
-#if INF_ENGINE_RELEASE >= 2021010000
+#if INF_ENGINE_RELEASE > 2023000000
+ cv::util::throw_error(std::logic_error(
+ "IE Backend: NV12 feature has been deprecated in OpenVINO 1.0 API."
+ " The last version which supports this is 2023.0"));
+#elif INF_ENGINE_RELEASE >= 2021010000
return IE::make_shared_blob(y_blob, uv_blob);
#else
return IE::make_shared_blob(y_blob, uv_blob);
diff --git a/modules/gapi/src/backends/onnx/bindings_onnx.cpp b/modules/gapi/src/backends/onnx/bindings_onnx.cpp
index c9c5fc58fa..6051c6bb4d 100644
--- a/modules/gapi/src/backends/onnx/bindings_onnx.cpp
+++ b/modules/gapi/src/backends/onnx/bindings_onnx.cpp
@@ -21,6 +21,24 @@ cv::gapi::onnx::PyParams& cv::gapi::onnx::PyParams::cfgNormalize(const std::stri
return *this;
}
+cv::gapi::onnx::PyParams&
+cv::gapi::onnx::PyParams::cfgAddExecutionProvider(cv::gapi::onnx::ep::OpenVINO ep) {
+ m_priv->cfgAddExecutionProvider(std::move(ep));
+ return *this;
+}
+
+cv::gapi::onnx::PyParams&
+cv::gapi::onnx::PyParams::cfgAddExecutionProvider(cv::gapi::onnx::ep::DirectML ep) {
+ m_priv->cfgAddExecutionProvider(std::move(ep));
+ return *this;
+}
+
+cv::gapi::onnx::PyParams&
+cv::gapi::onnx::PyParams::cfgDisableMemPattern() {
+ m_priv->cfgDisableMemPattern();
+ return *this;
+}
+
cv::gapi::GBackend cv::gapi::onnx::PyParams::backend() const {
return m_priv->backend();
}
diff --git a/modules/gapi/src/backends/onnx/dml_ep.cpp b/modules/gapi/src/backends/onnx/dml_ep.cpp
new file mode 100644
index 0000000000..7f59e1f3d6
--- /dev/null
+++ b/modules/gapi/src/backends/onnx/dml_ep.cpp
@@ -0,0 +1,40 @@
+// 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.
+//
+// Copyright (C) 2023 Intel Corporation
+
+#include "backends/onnx/dml_ep.hpp"
+#include "logger.hpp"
+
+#ifdef HAVE_ONNX
+#include
+
+#ifdef HAVE_ONNX_DML
+#include "../providers/dml/dml_provider_factory.h"
+
+void cv::gimpl::onnx::addDMLExecutionProvider(Ort::SessionOptions *session_options,
+ const cv::gapi::onnx::ep::DirectML &dml_ep) {
+ namespace ep = cv::gapi::onnx::ep;
+ GAPI_Assert(cv::util::holds_alternative(dml_ep.ddesc));
+ const int device_id = cv::util::get(dml_ep.ddesc);
+ try {
+ OrtSessionOptionsAppendExecutionProvider_DML(*session_options, device_id);
+ } catch (const std::exception &e) {
+ std::stringstream ss;
+ ss << "ONNX Backend: Failed to enable DirectML"
+ << " Execution Provider: " << e.what();
+ cv::util::throw_error(std::runtime_error(ss.str()));
+ }
+}
+
+#else // HAVE_ONNX_DML
+
+void cv::gimpl::onnx::addDMLExecutionProvider(Ort::SessionOptions*,
+ const cv::gapi::onnx::ep::DirectML&) {
+ util::throw_error(std::runtime_error("G-API has been compiled with ONNXRT"
+ " without DirectML support"));
+}
+
+#endif // HAVE_ONNX_DML
+#endif // HAVE_ONNX
diff --git a/modules/gapi/src/backends/onnx/dml_ep.hpp b/modules/gapi/src/backends/onnx/dml_ep.hpp
new file mode 100644
index 0000000000..d7e43dc888
--- /dev/null
+++ b/modules/gapi/src/backends/onnx/dml_ep.hpp
@@ -0,0 +1,23 @@
+// 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.
+//
+// Copyright (C) 2023 Intel Corporation
+
+#ifndef OPENCV_GAPI_DML_EP_HPP
+#define OPENCV_GAPI_DML_EP_HPP
+
+#include "opencv2/gapi/infer/onnx.hpp"
+#ifdef HAVE_ONNX
+
+#include
+
+namespace cv {
+namespace gimpl {
+namespace onnx {
+void addDMLExecutionProvider(Ort::SessionOptions *session_options,
+ const cv::gapi::onnx::ep::DirectML &dml_ep);
+}}}
+
+#endif // HAVE_ONNX
+#endif // OPENCV_GAPI_DML_EP_HPP
diff --git a/modules/gapi/src/backends/onnx/gonnxbackend.cpp b/modules/gapi/src/backends/onnx/gonnxbackend.cpp
index 1194caeeb3..b90d4d6974 100644
--- a/modules/gapi/src/backends/onnx/gonnxbackend.cpp
+++ b/modules/gapi/src/backends/onnx/gonnxbackend.cpp
@@ -9,6 +9,8 @@
#ifdef HAVE_ONNX
+#include "backends/onnx/dml_ep.hpp"
+
#include // any_of
#include
#include
@@ -143,6 +145,48 @@ public:
void run();
};
+static void addOpenVINOExecutionProvider(Ort::SessionOptions *session_options,
+ const cv::gapi::onnx::ep::OpenVINO &ov_ep) {
+ OrtOpenVINOProviderOptions options;
+ options.device_type = ov_ep.device_type.c_str();
+ options.cache_dir = ov_ep.cache_dir.c_str();
+ options.num_of_threads = ov_ep.num_of_threads;
+ options.enable_opencl_throttling = ov_ep.enable_opencl_throttling;
+ options.enable_dynamic_shapes = ov_ep.enable_dynamic_shapes;
+ options.context = nullptr;
+
+ try {
+ session_options->AppendExecutionProvider_OpenVINO(options);
+ } catch (const std::exception &e) {
+ std::stringstream ss;
+ ss << "ONNX Backend: Failed to enable OpenVINO"
+ << " Execution Provider: " << e.what();
+ cv::util::throw_error(std::runtime_error(ss.str()));
+ }
+}
+
+static void addExecutionProvider(Ort::SessionOptions *session_options,
+ const cv::gapi::onnx::ep::EP &execution_provider) {
+ namespace ep = cv::gapi::onnx::ep;
+ switch (execution_provider.index()) {
+ case ep::EP::index_of(): {
+ GAPI_LOG_INFO(NULL, "OpenVINO Execution Provider is added.");
+ const auto &ov_ep = cv::util::get(execution_provider);
+ addOpenVINOExecutionProvider(session_options, ov_ep);
+ break;
+ }
+ case ep::EP::index_of(): {
+ GAPI_LOG_INFO(NULL, "DirectML Execution Provider is added.");
+ const auto &dml_ep = cv::util::get(execution_provider);
+ addDMLExecutionProvider(session_options, dml_ep);
+ break;
+ }
+ default:
+ GAPI_LOG_INFO(NULL, "CPU Execution Provider is added.");
+ break;
+ }
+}
+
} // namespace onnx
} // namespace gimpl
} // namespace cv
@@ -592,9 +636,16 @@ ONNXCompiled::ONNXCompiled(const gapi::onnx::detail::ParamDesc &pp)
cv::util::throw_error(std::logic_error("Please specify output layer names for "
+ params.model_path));
}
-
// Create and initialize the ONNX session
Ort::SessionOptions session_options;
+ GAPI_LOG_INFO(NULL, "Adding Execution Providers for \"" << pp.model_path << "\"");
+ for (const auto &ep : pp.execution_providers) {
+ cv::gimpl::onnx::addExecutionProvider(&session_options, ep);
+ }
+
+ if (pp.disable_mem_pattern) {
+ session_options.DisableMemPattern();
+ }
this_env = Ort::Env(ORT_LOGGING_LEVEL_WARNING, "");
#ifndef _WIN32
this_session = Ort::Session(this_env, params.model_path.data(), session_options);
diff --git a/modules/gapi/src/backends/ov/govbackend.cpp b/modules/gapi/src/backends/ov/govbackend.cpp
index 46eccd2bbd..8384a9d188 100644
--- a/modules/gapi/src/backends/ov/govbackend.cpp
+++ b/modules/gapi/src/backends/ov/govbackend.cpp
@@ -18,6 +18,7 @@
#include
#include
+#include // getConfigurationParameterBool
#if defined(HAVE_TBB)
# include // FIXME: drop it from here!
@@ -37,11 +38,37 @@ template using QueueClass = cv::gapi::own::concurrent_bounded_queue<
using ParamDesc = cv::gapi::ov::detail::ParamDesc;
-static ov::Core getCore() {
+// NB: Some of OV plugins fail during ov::Core destroying in specific cases.
+// Solution is allocate ov::Core in heap and doesn't destroy it, which cause
+// leak, but fixes tests on CI. This behaviour is configurable by using
+// OPENCV_GAPI_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND=0
+static ov::Core create_OV_Core_pointer() {
+ // NB: 'delete' is never called
+ static ov::Core* core = new ov::Core();
+ return *core;
+}
+
+static ov::Core create_OV_Core_instance() {
static ov::Core core;
return core;
}
+ov::Core cv::gapi::ov::wrap::getCore() {
+ // NB: to make happy memory leak tools use:
+ // - OPENCV_GAPI_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND=0
+ static bool param_GAPI_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND =
+ utils::getConfigurationParameterBool(
+ "OPENCV_GAPI_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND",
+#if defined(_WIN32) || defined(__APPLE__)
+ true
+#else
+ false
+#endif
+ );
+ return param_GAPI_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND
+ ? create_OV_Core_pointer() : create_OV_Core_instance();
+}
+
static ov::AnyMap toOV(const ParamDesc::PluginConfigT &config) {
return {config.begin(), config.end()};
}
@@ -101,8 +128,8 @@ static int toCV(const ov::element::Type &type) {
static void copyFromOV(const ov::Tensor &tensor, cv::Mat &mat) {
const auto total = mat.total() * mat.channels();
- if (tensor.get_element_type() != toOV(mat.depth()) ||
- tensor.get_size() != total ) {
+ if (toCV(tensor.get_element_type()) != mat.depth() ||
+ tensor.get_size() != total ) {
std::stringstream ss;
ss << "Failed to copy data from ov::Tensor to cv::Mat."
<< " Data type or number of elements mismatch."
@@ -128,8 +155,8 @@ static void copyToOV(const cv::Mat &mat, ov::Tensor &tensor) {
// TODO: Ideally there should be check that mat and tensor
// dimensions are compatible.
const auto total = mat.total() * mat.channels();
- if (tensor.get_element_type() != toOV(mat.depth()) ||
- tensor.get_size() != total) {
+ if (toCV(tensor.get_element_type()) != mat.depth() ||
+ tensor.get_size() != total) {
std::stringstream ss;
ss << "Failed to copy data from cv::Mat to ov::Tensor."
<< " Data type or number of elements mismatch."
@@ -158,6 +185,14 @@ int cv::gapi::ov::util::to_ocv(const ::ov::element::Type &type) {
return toCV(type);
}
+void cv::gapi::ov::util::to_ov(const cv::Mat &mat, ::ov::Tensor &tensor) {
+ copyToOV(mat, tensor);
+}
+
+void cv::gapi::ov::util::to_ocv(const ::ov::Tensor &tensor, cv::Mat &mat) {
+ copyFromOV(tensor, mat);
+}
+
struct OVUnit {
static const char *name() { return "OVUnit"; }
@@ -167,7 +202,8 @@ struct OVUnit {
// FIXME: Can this logic be encapsulated to prevent checking every time?
if (cv::util::holds_alternative(params.kind)) {
const auto desc = cv::util::get(params.kind);
- model = getCore().read_model(desc.model_path, desc.bin_path);
+ model = cv::gapi::ov::wrap::getCore()
+ .read_model(desc.model_path, desc.bin_path);
GAPI_Assert(model);
if (params.num_in == 1u && params.input_names.empty()) {
@@ -182,9 +218,8 @@ struct OVUnit {
std::ifstream file(cv::util::get(params.kind).blob_path,
std::ios_base::in | std::ios_base::binary);
GAPI_Assert(file.is_open());
- compiled_model = getCore().import_model(file,
- params.device,
- toOV(params.config));
+ compiled_model = cv::gapi::ov::wrap::getCore()
+ .import_model(file, params.device, toOV(params.config));
if (params.num_in == 1u && params.input_names.empty()) {
params.input_names = { compiled_model.inputs().begin()->get_any_name() };
@@ -197,9 +232,8 @@ struct OVUnit {
cv::gimpl::ov::OVCompiled compile() {
if (cv::util::holds_alternative(params.kind)) {
- compiled_model = getCore().compile_model(model,
- params.device,
- toOV(params.config));
+ compiled_model = cv::gapi::ov::wrap::getCore()
+ .compile_model(model, params.device, toOV(params.config));
}
return {compiled_model};
}
@@ -343,6 +377,15 @@ cv::GArg OVCallContext::packArg(const cv::GArg &arg) {
switch (ref.shape)
{
case cv::GShape::GMAT: return cv::GArg(m_res.slot()[ref.id]);
+
+ // Note: .at() is intentional for GArray as object MUST be already there
+ // (and constructed by either bindIn/Out or resetInternal)
+ case cv::GShape::GARRAY: return cv::GArg(m_res.slot().at(ref.id));
+
+ // Note: .at() is intentional for GOpaque as object MUST be already there
+ // (and constructed by either bindIn/Out or resetInternal)
+ case cv::GShape::GOPAQUE: return cv::GArg(m_res.slot().at(ref.id));
+
default:
cv::util::throw_error(std::logic_error("Unsupported GShape type"));
break;
@@ -547,6 +590,62 @@ static void PostOutputs(::ov::InferRequest &infer_request,
}
}
+class PostOutputsList {
+public:
+ PostOutputsList(size_t size,
+ std::shared_ptr ctx);
+
+ void operator()(::ov::InferRequest &infer_request,
+ std::exception_ptr eptr,
+ size_t pos) const;
+
+private:
+ struct Priv {
+ std::atomic