mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 07:13:02 +04:00
Merge branch 4.x
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
Vendored
+5
-5
@@ -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)
|
||||
|
||||
Vendored
+1
-1
@@ -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;
|
||||
|
||||
Vendored
+1
-1
@@ -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);
|
||||
|
||||
Vendored
+1
@@ -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)
|
||||
|
||||
+11
-1
@@ -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()
|
||||
|
||||
|
||||
@@ -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( ; ; )
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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},
|
||||
}
|
||||
|
||||
@@ -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 <https://orbbec3d.com/develop/>).
|
||||
-# Download the latest version of Orbbec OpenNI SDK (from here <https://orbbec3d.com/index/download.html>).
|
||||
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}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 `<Platform>:<CPU|GPU|ACCELERATOR|nothing=GPU/CPU>:<deviceName>`, 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 |
|
||||
@@ -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
|
||||
|
||||
@@ -142,7 +142,7 @@ public:
|
||||
}
|
||||
|
||||
std::vector<double> 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]);
|
||||
|
||||
@@ -322,7 +322,7 @@ void UniversalRANSAC::initialize (int state, Ptr<MinimalSolver> &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;
|
||||
|
||||
@@ -62,8 +62,8 @@ Ptr<UniformSampler> 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<UniformRandomGenerator> 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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1531,8 +1531,8 @@ TEST(Calib3d_SolvePnP, generic)
|
||||
}
|
||||
else
|
||||
{
|
||||
p3f = p3f_;
|
||||
p2f = p2f_;
|
||||
p3f = vector<Point3f>(p3f_.begin(), p3f_.end());
|
||||
p2f = vector<Point2f>(p2f_.begin(), p2f_.end());
|
||||
}
|
||||
|
||||
vector<double> reprojectionErrors;
|
||||
|
||||
@@ -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 <COPYRIGHT HOLDER> 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<int> &sample;
|
||||
const int sample_size;
|
||||
const MlesacLoss &loss_fn;
|
||||
const double *weights;
|
||||
|
||||
public:
|
||||
RelativePoseJacobianAccumulator(
|
||||
const Mat& correspondences_,
|
||||
const std::vector<int> &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<float>(E(0,0)), m12=static_cast<float>(E(0,1)), m13=static_cast<float>(E(0,2));
|
||||
const float m21=static_cast<float>(E(1,0)), m22=static_cast<float>(E(1,1)), m23=static_cast<float>(E(1,2));
|
||||
const float m31=static_cast<float>(E(2,0)), m32=static_cast<float>(E(2,1)), m33=static_cast<float>(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<double, 5, 5> &JtJ, Matx<double, 5, 1> &Jtr, Matx<double, 3, 2> &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<double, 9, 3> 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<double, 9, 2> 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<double, 1, 9> 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<double, 1, 5> 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<int> &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<double, 5, 5> JtJ;
|
||||
Matx<double, 5, 1> Jtr;
|
||||
Matx<double, 3, 2> 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<double, 5, 1> sol;
|
||||
Matx<double, 5, 5> 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;
|
||||
}
|
||||
}}
|
||||
@@ -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<void*>(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<void*>(cudaMemoryAddress), step);
|
||||
};
|
||||
}
|
||||
|
||||
/** @brief BufferPool for use with CUDA streams
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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<v_int64>::vlanes())));
|
||||
}
|
||||
|
||||
|
||||
//////////// SignMask ////////////
|
||||
|
||||
@@ -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<int> 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<int>& newshape) const;
|
||||
|
||||
/** @brief Transposes a matrix.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
//! @}
|
||||
|
||||
@@ -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<Point2f>& 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_<float> 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 >
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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++ )
|
||||
|
||||
@@ -90,7 +90,7 @@ static void swap_columns(Mat_<double>& 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_<double>& c, Mat_<double>& b,double& v,vector<int>& N,vector<int>& B,vector<unsigned int>& indexToRow){
|
||||
N.resize(c.cols);
|
||||
N[0]=0;
|
||||
@@ -255,7 +271,7 @@ static int initialize_simplex(Mat_<double>& c, Mat_<double>& b,double& v,vector<
|
||||
static int inner_simplex(Mat_<double>& c, Mat_<double>& b,double& v,vector<int>& N,vector<int>& B,vector<unsigned int>& indexToRow){
|
||||
|
||||
for(;;){
|
||||
static MatIterator_<double> pos_ptr;
|
||||
MatIterator_<double> 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++){
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -24,7 +24,7 @@ struct SumSqr_SIMD
|
||||
}
|
||||
};
|
||||
|
||||
#if CV_SIMD
|
||||
#if CV_SIMD || CV_SIMD_SCALABLE
|
||||
|
||||
template <>
|
||||
struct SumSqr_SIMD<uchar, int, int>
|
||||
@@ -39,37 +39,37 @@ struct SumSqr_SIMD<uchar, int, int>
|
||||
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<v_uint8>::vlanes();
|
||||
while(x < len0)
|
||||
{
|
||||
const int len_tmp = min(x + 256*v_uint16::nlanes, len0);
|
||||
const int len_tmp = min(x + 256*VTraits<v_uint16>::vlanes(), len0);
|
||||
v_uint16 v_sum16 = vx_setzero_u16();
|
||||
for ( ; x < len_tmp; x += v_uint8::nlanes)
|
||||
for ( ; x < len_tmp; x += VTraits<v_uint8>::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<v_uint16>::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<v_uint16>::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<v_uint16>::vlanes();
|
||||
}
|
||||
|
||||
if (cn == 1)
|
||||
@@ -79,13 +79,13 @@ struct SumSqr_SIMD<uchar, int, int>
|
||||
}
|
||||
else
|
||||
{
|
||||
int CV_DECL_ALIGNED(CV_SIMD_WIDTH) ar[2 * v_int32::nlanes];
|
||||
int CV_DECL_ALIGNED(CV_SIMD_WIDTH) ar[2 * VTraits<v_int32>::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<v_int32>::vlanes(), v_sqsum);
|
||||
for (int i = 0; i < VTraits<v_int32>::vlanes(); ++i)
|
||||
{
|
||||
sum[i % cn] += ar[i];
|
||||
sqsum[i % cn] += ar[v_int32::nlanes + i];
|
||||
sqsum[i % cn] += ar[VTraits<v_int32>::vlanes() + i];
|
||||
}
|
||||
}
|
||||
v_cleanup();
|
||||
@@ -106,37 +106,37 @@ struct SumSqr_SIMD<schar, int, int>
|
||||
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<v_int8>::vlanes();
|
||||
while (x < len0)
|
||||
{
|
||||
const int len_tmp = min(x + 256 * v_int16::nlanes, len0);
|
||||
const int len_tmp = min(x + 256 * VTraits<v_int16>::vlanes(), len0);
|
||||
v_int16 v_sum16 = vx_setzero_s16();
|
||||
for (; x < len_tmp; x += v_int8::nlanes)
|
||||
for (; x < len_tmp; x += VTraits<v_int8>::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<v_int16>::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<v_int16>::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<v_int16>::vlanes();
|
||||
}
|
||||
|
||||
if (cn == 1)
|
||||
@@ -146,13 +146,13 @@ struct SumSqr_SIMD<schar, int, int>
|
||||
}
|
||||
else
|
||||
{
|
||||
int CV_DECL_ALIGNED(CV_SIMD_WIDTH) ar[2 * v_int32::nlanes];
|
||||
int CV_DECL_ALIGNED(CV_SIMD_WIDTH) ar[2 * VTraits<v_int32>::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<v_int32>::vlanes(), v_sqsum);
|
||||
for (int i = 0; i < VTraits<v_int32>::vlanes(); ++i)
|
||||
{
|
||||
sum[i % cn] += ar[i];
|
||||
sqsum[i % cn] += ar[v_int32::nlanes + i];
|
||||
sqsum[i % cn] += ar[VTraits<v_int32>::vlanes() + i];
|
||||
}
|
||||
}
|
||||
v_cleanup();
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream> // std::cerr
|
||||
#include <fstream>
|
||||
#if !(defined _MSC_VER) || (defined _MSC_VER && _MSC_VER > 1700)
|
||||
#include <inttypes.h>
|
||||
|
||||
@@ -128,6 +128,8 @@
|
||||
#include <ppltasks.h>
|
||||
#elif defined HAVE_CONCURRENCY
|
||||
#include <ppl.h>
|
||||
#elif defined HAVE_PTHREADS_PF
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -186,6 +186,11 @@ void RotatedRect::points(Point2f pt[]) const
|
||||
pt[3].y = 2*center.y - pt[1].y;
|
||||
}
|
||||
|
||||
void RotatedRect::points(std::vector<Point2f>& pts) const {
|
||||
pts.resize(4);
|
||||
points(pts.data());
|
||||
}
|
||||
|
||||
Rect RotatedRect::boundingRect() const
|
||||
{
|
||||
Point2f pt[4];
|
||||
|
||||
@@ -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()
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
@@ -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_<double>(4, 1) << 3., 3., 3., 4.);
|
||||
Mat B = (cv::Mat_<double>(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
|
||||
|
||||
@@ -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<typename Pixel>
|
||||
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<typename Pixel>
|
||||
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<Mat>
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1290,7 +1290,7 @@ void runFastConv(InputArray _input, OutputArray _output, const Ptr<FastConv>& 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;
|
||||
|
||||
@@ -138,7 +138,7 @@ public:
|
||||
{
|
||||
const float* srcptr = src_->ptr<float>(i) + stripeStart;
|
||||
float* dstptr = dst_->ptr<float>(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 <class T>
|
||||
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<SigmoidFunctor>
|
||||
|
||||
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<float>();
|
||||
@@ -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<float>() + 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<ngraph::Node> initNgraphAPI(const std::shared_ptr<ngraph::Node>& node)
|
||||
{
|
||||
auto shape = getShape<size_t>(scale);
|
||||
auto slope = std::make_shared<ngraph::op::Constant>(ngraph::element::f32, shape, scale.ptr<float>());
|
||||
return std::make_shared<ngraph::op::PRelu>(node, slope);
|
||||
}
|
||||
#endif // HAVE_DNN_NGRAPH
|
||||
};
|
||||
|
||||
struct SignFunctor : public BaseDefaultFunctor<SignFunctor>
|
||||
{
|
||||
typedef SignLayer Layer;
|
||||
@@ -3033,13 +3115,26 @@ Ptr<ExpLayer> ExpLayer::create(const LayerParams& params)
|
||||
Ptr<Layer> 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<float>();
|
||||
if (scale.total() == 1 || countNonZero(scale != slope) == 0)
|
||||
{
|
||||
LayerParams reluParams = params;
|
||||
reluParams.set("negative_slope", *params.blobs[0].ptr<float>());
|
||||
reluParams.set("negative_slope", slope);
|
||||
return ReLULayer::create(reluParams);
|
||||
}
|
||||
Ptr<ChannelsPReLULayer> l(new ElementWiseLayer<ChannelsPReLUFunctor>(ChannelsPReLUFunctor(params.blobs[0])));
|
||||
|
||||
Ptr<Layer> 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>(PReLUFunctor(scale));
|
||||
}
|
||||
else
|
||||
{
|
||||
l = new ElementWiseLayer<ChannelsPReLUFunctor>(ChannelsPReLUFunctor(scale));
|
||||
}
|
||||
l->setParamsFrom(params);
|
||||
|
||||
return l;
|
||||
|
||||
@@ -14,6 +14,7 @@ Implementation of Batch Normalization layer.
|
||||
#include "../op_cuda.hpp"
|
||||
#include "../op_halide.hpp"
|
||||
#include <opencv2/dnn/shape_utils.hpp>
|
||||
#include <opencv2/core/utils/logger.hpp>
|
||||
|
||||
#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];
|
||||
|
||||
@@ -304,9 +304,9 @@ std::shared_ptr<ge::ModelBufferData> compileCannGraph(std::shared_ptr<ge::Graph>
|
||||
bool ok;
|
||||
if ((child=fork()) == 0)
|
||||
{
|
||||
// initialize engine
|
||||
// initialize engine Ascend310/Ascend310P3/Ascend910B/Ascend310B
|
||||
std::map<ge::AscendString, ge::AscendString> 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));
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, ...
|
||||
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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<int>& order, const std::string& permName, const std::pair<int, int>& inpId, int dtype);
|
||||
int addReshapeLayer(const std::vector<int>& shape, int axis, int num_axes,
|
||||
const std::string& name, const std::pair<int, int>& 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<int> 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<int> 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<int> 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<int*>(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<const PackOptions*>(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<int> op_inputs(op.inputs()->begin(), op.inputs()->end());
|
||||
std::map<int, std::pair<int, int> > originLayerIds;
|
||||
for (int inp : op_inputs) {
|
||||
auto inpId = layerIds[inp];
|
||||
int dims = modelTensors->Get(inp)->shape()->size();
|
||||
|
||||
std::vector<int> 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<int>& order, const std::st
|
||||
return permId;
|
||||
}
|
||||
|
||||
int TFLiteImporter::addReshapeLayer(const std::vector<int>& shape, int axis, int num_axes,
|
||||
const std::string& name, const std::pair<int, int>& inpId, int dtype)
|
||||
{
|
||||
LayerParams lp;
|
||||
lp.set("axis", axis);
|
||||
lp.set("dim", DictValue::arrayInt<const int*>(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<const uint32_t*>(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_<float> 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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -31,9 +31,8 @@ void testInputShapes(const Net& net, const std::vector<Mat>& 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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,16 +19,39 @@
|
||||
#include <ostream>
|
||||
#include <typeinfo>
|
||||
|
||||
#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<typename T>
|
||||
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<T*>(policy->get_value(&object));
|
||||
return *r;
|
||||
}
|
||||
@@ -280,7 +303,7 @@ public:
|
||||
template<typename T>
|
||||
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<const T*>(policy->get_value(&object));
|
||||
return *r;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "opencv2/core/cvdef.h"
|
||||
#include "opencv2/flann/defines.h"
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
|
||||
@@ -72,11 +72,16 @@ struct SearchParams : public IndexParams
|
||||
|
||||
|
||||
template<typename T>
|
||||
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<T>();
|
||||
try {
|
||||
return it->second.cast<T>();
|
||||
} 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<typename T>
|
||||
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<T>();
|
||||
try {
|
||||
return it->second.cast<T>();
|
||||
} 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"));
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "opencv2/core/base.hpp"
|
||||
#include "opencv2/core/cvdef.h"
|
||||
|
||||
namespace cvflann
|
||||
{
|
||||
|
||||
|
||||
@@ -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)) {
|
||||
while(PyDict_Next(o, &pos, &key, &item))
|
||||
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;
|
||||
|
||||
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<int64_t>(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);
|
||||
}
|
||||
else if( PyInt_Check(item) )
|
||||
{
|
||||
int value = (int)PyInt_AsLong(item);
|
||||
if( strcmp(k.c_str(), "algorithm") == 0 )
|
||||
p.setAlgorithm(value);
|
||||
else
|
||||
p.setInt(k, value);
|
||||
}
|
||||
else if( PyFloat_Check(item) )
|
||||
{
|
||||
double value = PyFloat_AsDouble(item);
|
||||
p.setDouble(k, value);
|
||||
p.setAlgorithm(int_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string val_str;
|
||||
if (!getUnicodeString(item, val_str))
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
p.setString(k, val_str);
|
||||
p.setInt(key, int_value);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
PyErr_Clear();
|
||||
|
||||
return ok && !PyErr_Occurred();
|
||||
double flt_value = 0.0;
|
||||
if (pyopencv_to(value_obj, flt_value, key_arg_info))
|
||||
{
|
||||
if (key == "eps")
|
||||
{
|
||||
p.setFloat(key, static_cast<float>(flt_value));
|
||||
}
|
||||
else
|
||||
{
|
||||
p.setDouble(key, flt_value);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
PyErr_Clear();
|
||||
|
||||
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<>
|
||||
|
||||
@@ -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()
|
||||
@@ -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})
|
||||
|
||||
@@ -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<R>::shape...}
|
||||
, {detail::GTypeTraits<Args>::op_kind...}
|
||||
, {detail::GObtainCtor<R>::get()...}});
|
||||
, {detail::GObtainCtor<R>::get()...}
|
||||
, {detail::GTypeTraits<R>::op_kind...}});
|
||||
call.pass(args...); // TODO: std::forward() here?
|
||||
return yield(call, typename detail::MkSeq<sizeof...(R)>::type());
|
||||
}
|
||||
@@ -251,7 +253,8 @@ public:
|
||||
, &K::getOutMeta
|
||||
, {detail::GTypeTraits<R>::shape}
|
||||
, {detail::GTypeTraits<Args>::op_kind...}
|
||||
, {detail::GObtainCtor<R>::get()}});
|
||||
, {detail::GObtainCtor<R>::get()}
|
||||
, {detail::GTypeTraits<R>::op_kind}});
|
||||
call.pass(args...);
|
||||
return detail::Yield<R>::yield(call, 0);
|
||||
}
|
||||
|
||||
@@ -101,8 +101,10 @@ public:
|
||||
if (it == m_priv->blobs.end()) {
|
||||
// FIXME: Avoid modifying GKernel
|
||||
auto shape = cv::detail::GTypeTraits<OutT>::shape;
|
||||
auto kind = cv::detail::GTypeTraits<OutT>::op_kind;
|
||||
m_priv->call->kernel().outShapes.push_back(shape);
|
||||
m_priv->call->kernel().outCtors.emplace_back(cv::detail::GObtainCtor<OutT>::get());
|
||||
m_priv->call->kernel().outKinds.emplace_back(kind);
|
||||
auto out_idx = static_cast<int>(m_priv->blobs.size());
|
||||
it = m_priv->blobs.emplace(name,
|
||||
cv::detail::Yield<OutT>::yield(*(m_priv->call), out_idx)).first;
|
||||
@@ -175,6 +177,7 @@ std::shared_ptr<cv::GCall> 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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<int>;
|
||||
DeviceDesc ddesc;
|
||||
};
|
||||
|
||||
using EP = cv::util::variant<cv::util::monostate, OpenVINO, DirectML>;
|
||||
|
||||
} // 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<std::string, std::pair<cv::Scalar, cv::Scalar> > generic_mstd;
|
||||
std::unordered_map<std::string, bool> generic_norm;
|
||||
|
||||
std::vector<cv::gapi::onnx::ep::EP> execution_providers;
|
||||
bool disable_mem_pattern;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
@@ -115,6 +238,7 @@ public:
|
||||
desc.num_in = std::tuple_size<typename Net::InArgs>::value;
|
||||
desc.num_out = std::tuple_size<typename Net::OutArgs>::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<Net>& 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<Net>& 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<Net>& 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; }
|
||||
|
||||
@@ -46,6 +46,7 @@ G desync(const G &g) {
|
||||
, {cv::detail::GTypeTraits<G>::shape} // output Shape
|
||||
, {cv::detail::GTypeTraits<G>::op_kind} // input data kinds
|
||||
, {cv::detail::GObtainCtor<G>::get()} // output template ctors
|
||||
, {cv::detail::GTypeTraits<G>::op_kind} // output data kinds
|
||||
};
|
||||
cv::GCall call(std::move(k));
|
||||
call.pass(g);
|
||||
|
||||
@@ -50,6 +50,7 @@ cv::GOpaque<T> meta(G g, const std::string &tag) {
|
||||
, {cv::detail::GTypeTraits<O>::shape} // output Shape
|
||||
, {cv::detail::GTypeTraits<G>::op_kind} // input data kinds
|
||||
, {cv::detail::GObtainCtor<O>::get()} // output template ctors
|
||||
, {cv::detail::GTypeTraits<O>::op_kind} // output data kind
|
||||
};
|
||||
cv::GCall call(std::move(k));
|
||||
call.pass(g);
|
||||
|
||||
@@ -509,6 +509,11 @@ namespace util
|
||||
return v.index() == util::variant<Types...>::template index_of<T>();
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ == 11 || __GNUC__ == 12)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#endif
|
||||
|
||||
template<typename... Us> bool operator==(const variant<Us...> &lhs,
|
||||
const variant<Us...> &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<typename... Us> bool operator!=(const variant<Us...> &lhs,
|
||||
const variant<Us...> &rhs)
|
||||
{
|
||||
|
||||
@@ -29,6 +29,8 @@ using map_string_and_string = std::map<std::string, std::string>;
|
||||
using map_string_and_vector_size_t = std::map<std::string, std::vector<size_t>>;
|
||||
using map_string_and_vector_float = std::map<std::string, std::vector<float>>;
|
||||
using map_int_and_double = std::map<int, double>;
|
||||
using ep_OpenVINO = cv::gapi::onnx::ep::OpenVINO;
|
||||
using ep_DirectML = cv::gapi::onnx::ep::DirectML;
|
||||
|
||||
// NB: Python wrapper generate T_U for T<U>
|
||||
// This behavior is only observed for inputs
|
||||
|
||||
@@ -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<cv::GArray<T>>::get()); \
|
||||
return cv::GArrayT(m_call->yieldArray<T>(output++)); \
|
||||
|
||||
#define HC(T, K) \
|
||||
case K: { \
|
||||
const auto kind = cv::detail::GTypeTraits<cv::GArray<T>>::op_kind; \
|
||||
m_call->kernel().outKinds.emplace_back(kind); \
|
||||
m_call->kernel().outCtors.emplace_back(cv::detail::GObtainCtor<cv::GArray<T>>::get()); \
|
||||
return cv::GArrayT(m_call->yieldArray<T>(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<cv::GOpaque<T>>::get()); \
|
||||
return cv::GOpaqueT(m_call->yieldOpaque<T>(output++)); \
|
||||
#define HC(T, K) \
|
||||
case K: { \
|
||||
const auto kind = cv::detail::GTypeTraits<cv::GOpaque<T>>::op_kind; \
|
||||
m_call->kernel().outKinds.emplace_back(kind); \
|
||||
m_call->kernel().outCtors.emplace_back(cv::detail::GObtainCtor<cv::GOpaque<T>>::get()); \
|
||||
return cv::GOpaqueT(m_call->yieldOpaque<T>(output++)); \
|
||||
}
|
||||
|
||||
SWITCH(type, GOPAQUE_TYPE_LIST_G, HC)
|
||||
#undef HC
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<IE::NV12Blob>(y_blob, uv_blob);
|
||||
#else
|
||||
return IE::make_shared_blob<InferenceEngine::NV12Blob>(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<cv::GFrameDesc>(mm)) {
|
||||
const auto &meta = util::get<cv::GFrameDesc>(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<cv::GFrameDesc>(mm)) {
|
||||
const auto &meta = util::get<cv::GFrameDesc>(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<IE::NV12Blob>(y_blob, uv_blob);
|
||||
#else
|
||||
return IE::make_shared_blob<InferenceEngine::NV12Blob>(y_blob, uv_blob);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 <onnxruntime_cxx_api.h>
|
||||
|
||||
#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<int>(dml_ep.ddesc));
|
||||
const int device_id = cv::util::get<int>(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
|
||||
@@ -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 <onnxruntime_cxx_api.h>
|
||||
|
||||
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
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#ifdef HAVE_ONNX
|
||||
|
||||
#include "backends/onnx/dml_ep.hpp"
|
||||
|
||||
#include <ade/util/algorithm.hpp> // any_of
|
||||
#include <ade/util/zip_range.hpp>
|
||||
#include <opencv2/gapi/infer.hpp>
|
||||
@@ -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<ep::OpenVINO>(): {
|
||||
GAPI_LOG_INFO(NULL, "OpenVINO Execution Provider is added.");
|
||||
const auto &ov_ep = cv::util::get<ep::OpenVINO>(execution_provider);
|
||||
addOpenVINOExecutionProvider(session_options, ov_ep);
|
||||
break;
|
||||
}
|
||||
case ep::EP::index_of<ep::DirectML>(): {
|
||||
GAPI_LOG_INFO(NULL, "DirectML Execution Provider is added.");
|
||||
const auto &dml_ep = cv::util::get<ep::DirectML>(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);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <opencv2/gapi/gcommon.hpp>
|
||||
#include <opencv2/gapi/infer/ov.hpp>
|
||||
#include <opencv2/core/utils/configuration.private.hpp> // getConfigurationParameterBool
|
||||
|
||||
#if defined(HAVE_TBB)
|
||||
# include <tbb/concurrent_queue.h> // FIXME: drop it from here!
|
||||
@@ -37,11 +38,37 @@ template<typename T> 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<ParamDesc::Model>(params.kind)) {
|
||||
const auto desc = cv::util::get<ParamDesc::Model>(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<ParamDesc::CompiledModel>(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<ParamDesc::Model>(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<cv::Mat>()[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<cv::detail::VectorRef>().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<cv::detail::OpaqueRef>().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<OVCallContext> ctx);
|
||||
|
||||
void operator()(::ov::InferRequest &infer_request,
|
||||
std::exception_ptr eptr,
|
||||
size_t pos) const;
|
||||
|
||||
private:
|
||||
struct Priv {
|
||||
std::atomic<size_t> finished{0u};
|
||||
size_t size;
|
||||
std::shared_ptr<OVCallContext> ctx;
|
||||
};
|
||||
std::shared_ptr<Priv> m_priv;
|
||||
};
|
||||
|
||||
PostOutputsList::PostOutputsList(size_t size,
|
||||
std::shared_ptr<OVCallContext> ctx)
|
||||
: m_priv(new Priv{}) {
|
||||
m_priv->size = size;
|
||||
m_priv->ctx = ctx;
|
||||
}
|
||||
|
||||
void PostOutputsList::operator()(::ov::InferRequest &infer_request,
|
||||
std::exception_ptr eptr,
|
||||
size_t pos) const {
|
||||
auto&& ctx = m_priv->ctx;
|
||||
auto&& finished = m_priv->finished;
|
||||
auto&& size = m_priv->size;
|
||||
|
||||
ctx->eptr = eptr;
|
||||
if (!ctx->eptr) {
|
||||
for (auto i : ade::util::iota(ctx->uu.params.num_out)) {
|
||||
std::vector<cv::Mat> &out_vec = ctx->outVecR<cv::Mat>(i);
|
||||
|
||||
const auto &out_name = ctx->uu.params.output_names[i];
|
||||
const auto &out_tensor = infer_request.get_tensor(out_name);
|
||||
|
||||
out_vec[pos].create(toCV(out_tensor.get_shape()),
|
||||
toCV(out_tensor.get_element_type()));
|
||||
copyFromOV(out_tensor, out_vec[pos]);
|
||||
}
|
||||
}
|
||||
++finished;
|
||||
|
||||
if (finished == size) {
|
||||
for (auto i : ade::util::iota(ctx->uu.params.num_out)) {
|
||||
auto output = ctx->output(i);
|
||||
ctx->out.meta(output, ctx->getMeta());
|
||||
ctx->out.post(std::move(output), ctx->eptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace cv {
|
||||
namespace gimpl {
|
||||
namespace ov {
|
||||
@@ -594,6 +693,34 @@ cv::optional<V> lookUp(const std::map<K, V> &map, const K& key) {
|
||||
return cv::util::make_optional(std::move(it->second));
|
||||
}
|
||||
|
||||
// NB: This function is used to preprocess input image
|
||||
// for InferROI, InferList, InferList2 kernels.
|
||||
static cv::Mat preprocess(const cv::Mat &in_mat,
|
||||
const cv::Rect &roi,
|
||||
const ::ov::Shape &model_shape) {
|
||||
cv::Mat out;
|
||||
// FIXME: Since there is no information about H and W positions
|
||||
// among tensor dimmensions assume that model layout is "NHWC".
|
||||
// (In fact "NHWC" is the only right layout for preprocessing because
|
||||
// it works only with images.
|
||||
GAPI_Assert(model_shape.size() == 4u);
|
||||
const auto H = model_shape[1];
|
||||
const auto W = model_shape[2];
|
||||
const auto C = model_shape[3];
|
||||
// NB: Soft check that at least number of channels matches.
|
||||
if (static_cast<int>(C) != in_mat.channels()) {
|
||||
std::stringstream ss;
|
||||
ss << "OV Backend: Failed to preprocess input data "
|
||||
" (Number of channels mismatch)."
|
||||
" Provided data: " << cv::descr_of(in_mat) <<
|
||||
" and Model shape: " << model_shape;
|
||||
util::throw_error(std::logic_error(ss.str()));
|
||||
}
|
||||
// NB: Crop roi and resize to model size.
|
||||
cv::resize(in_mat(roi), out, cv::Size(W, H));
|
||||
return out;
|
||||
}
|
||||
|
||||
static bool isImage(const cv::GMatDesc &desc,
|
||||
const ::ov::Shape &model_shape) {
|
||||
return (model_shape.size() == 4u) &&
|
||||
@@ -603,6 +730,203 @@ static bool isImage(const cv::GMatDesc &desc,
|
||||
(desc.depth == CV_8U);
|
||||
}
|
||||
|
||||
class PrePostProcWrapper {
|
||||
public:
|
||||
PrePostProcWrapper(std::shared_ptr<::ov::Model> &model,
|
||||
const ParamDesc::Model &model_info,
|
||||
const std::vector<std::string> &input_names,
|
||||
const std::vector<std::string> &output_names)
|
||||
: m_ppp(model),
|
||||
m_model(model),
|
||||
m_model_info(model_info),
|
||||
m_input_names(input_names),
|
||||
m_output_names(output_names) {
|
||||
// NB: Do Reshape right away since it must be the first step of model modification
|
||||
// and applicable for all infer kernels.
|
||||
const auto new_shapes = broadcastLayerAttr(model_info.new_shapes, input_names);
|
||||
m_model->reshape(toOV(new_shapes));
|
||||
|
||||
const auto &mi = m_model_info;
|
||||
m_input_tensor_layout = broadcastLayerAttr(mi.input_tensor_layout, m_input_names);
|
||||
m_input_model_layout = broadcastLayerAttr(mi.input_model_layout, m_input_names);
|
||||
m_interpolation = broadcastLayerAttr(mi.interpolation, m_input_names);
|
||||
m_mean_values = broadcastLayerAttr(mi.mean_values, m_input_names);
|
||||
m_scale_values = broadcastLayerAttr(mi.scale_values, m_input_names);
|
||||
m_interpolation = broadcastLayerAttr(mi.interpolation, m_input_names);
|
||||
|
||||
m_output_tensor_layout = broadcastLayerAttr(mi.output_tensor_layout, m_output_names);
|
||||
m_output_model_layout = broadcastLayerAttr(mi.output_model_layout, m_output_names);
|
||||
m_output_tensor_precision = broadcastLayerAttr(mi.output_tensor_precision, m_output_names);
|
||||
};
|
||||
|
||||
void cfgLayouts(const std::string &input_name) {
|
||||
auto &input_info = m_ppp.input(input_name);
|
||||
const auto explicit_in_model_layout = lookUp(m_input_model_layout, input_name);
|
||||
if (explicit_in_model_layout) {
|
||||
input_info.model().set_layout(::ov::Layout(*explicit_in_model_layout));
|
||||
} else if (m_model->input(input_name).get_shape().size() == 4u) {
|
||||
// NB: Back compatibility with IR's without any layout information.
|
||||
// Note that default is only applicable for 4D inputs in order to
|
||||
// support auto resize for image use cases.
|
||||
GAPI_LOG_WARNING(NULL, "Failed to find layout for input layer \""
|
||||
<< input_name << "\" - NCHW is set by default");
|
||||
const std::string default_layout = "NCHW";
|
||||
input_info.model().set_layout(::ov::Layout(default_layout));
|
||||
m_input_model_layout.emplace(input_name, default_layout);
|
||||
}
|
||||
const auto explicit_in_tensor_layout = lookUp(m_input_tensor_layout, input_name);
|
||||
if (explicit_in_tensor_layout) {
|
||||
input_info.tensor().set_layout(::ov::Layout(*explicit_in_tensor_layout));
|
||||
}
|
||||
}
|
||||
|
||||
void cfgScaleMean(const std::string &input_name) {
|
||||
auto &input_info = m_ppp.input(input_name);
|
||||
const auto mean_vec = lookUp(m_mean_values, input_name);
|
||||
if (mean_vec) {
|
||||
input_info.preprocess().mean(*mean_vec);
|
||||
}
|
||||
const auto scale_vec = lookUp(m_scale_values, input_name);
|
||||
if (scale_vec) {
|
||||
input_info.preprocess().scale(*scale_vec);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Decompose this...
|
||||
void cfgPreProcessing(const std::string &input_name,
|
||||
const cv::GMetaArg &input_meta,
|
||||
const bool disable_img_resize = false) {
|
||||
GAPI_Assert(cv::util::holds_alternative<cv::GMatDesc>(input_meta));
|
||||
const auto &matdesc = cv::util::get<cv::GMatDesc>(input_meta);
|
||||
|
||||
const auto explicit_in_tensor_layout = lookUp(m_input_tensor_layout, input_name);
|
||||
const auto explicit_in_model_layout = lookUp(m_input_model_layout, input_name);
|
||||
const auto explicit_resize = lookUp(m_interpolation, input_name);
|
||||
|
||||
if (disable_img_resize && explicit_resize.has_value()) {
|
||||
std::stringstream ss;
|
||||
util::throw_error(std::logic_error(
|
||||
"OV Backend: Resize for layer \"" + input_name + "\" will be performed"
|
||||
" on host via OpenCV so explicitly configured resize is prohibited."));
|
||||
}
|
||||
|
||||
const auto &input_shape = m_model->input(input_name).get_shape();
|
||||
auto &input_info = m_ppp.input(input_name);
|
||||
|
||||
m_ppp.input(input_name).tensor().set_element_type(toOV(matdesc.depth));
|
||||
if (isImage(matdesc, input_shape)) {
|
||||
// NB: Image case - all necessary preprocessng is configured automatically.
|
||||
GAPI_LOG_DEBUG(NULL, "OV Backend: Input: \"" << input_name << "\" is image.");
|
||||
if (explicit_in_tensor_layout &&
|
||||
*explicit_in_tensor_layout != "NHWC") {
|
||||
std::stringstream ss;
|
||||
ss << "OV Backend: Provided tensor layout " << *explicit_in_tensor_layout
|
||||
<< " is not compatible with input data " << matdesc << " for layer \""
|
||||
<< input_name << "\". Expecting NHWC";
|
||||
util::throw_error(std::logic_error(ss.str()));
|
||||
} else {
|
||||
input_info.tensor().set_layout(::ov::Layout("NHWC"));
|
||||
}
|
||||
|
||||
if (!disable_img_resize) {
|
||||
input_info.tensor().set_spatial_static_shape(matdesc.size.height,
|
||||
matdesc.size.width);
|
||||
// NB: Even though resize is automatically configured
|
||||
// user have an opportunity to specify the interpolation algorithm.
|
||||
auto interp = explicit_resize
|
||||
? toOVInterp(*explicit_resize)
|
||||
: ::ov::preprocess::ResizeAlgorithm::RESIZE_LINEAR;
|
||||
input_info.preprocess().resize(interp);
|
||||
}
|
||||
} else {
|
||||
// NB: Tensor case - resize or layout conversions must be explicitly specified.
|
||||
GAPI_LOG_DEBUG(NULL, "OV Backend: Input: \"" << input_name << "\" is tensor.");
|
||||
|
||||
if (explicit_resize) {
|
||||
if (matdesc.isND()) {
|
||||
// NB: ND case - need to obtain "H" and "W" positions
|
||||
// in order to configure resize.
|
||||
const auto model_layout = explicit_in_model_layout
|
||||
? ::ov::Layout(*explicit_in_model_layout)
|
||||
: ::ov::layout::get_layout(m_model->input(input_name));
|
||||
if (!explicit_in_tensor_layout && model_layout.empty()) {
|
||||
std::stringstream ss;
|
||||
ss << "Resize for input layer: " << input_name
|
||||
<< "can't be configured."
|
||||
<< " Failed to extract H and W positions from layout.";
|
||||
util::throw_error(std::logic_error(ss.str()));
|
||||
} else {
|
||||
const auto layout = explicit_in_tensor_layout
|
||||
? ::ov::Layout(*explicit_in_tensor_layout) : model_layout;
|
||||
auto H_idx = ::ov::layout::height_idx(layout);
|
||||
auto W_idx = ::ov::layout::width_idx(layout);
|
||||
// NB: If layout is "...HW", H position is -2.
|
||||
if (H_idx < 0) H_idx = matdesc.dims.size() + H_idx;
|
||||
if (W_idx < 0) W_idx = matdesc.dims.size() + W_idx;
|
||||
GAPI_Assert(H_idx >= 0 && H_idx < static_cast<int>(matdesc.dims.size()));
|
||||
GAPI_Assert(W_idx >= 0 && W_idx < static_cast<int>(matdesc.dims.size()));
|
||||
input_info.tensor().set_spatial_static_shape(matdesc.dims[H_idx],
|
||||
matdesc.dims[W_idx]);
|
||||
input_info.preprocess().resize(toOVInterp(*explicit_resize));
|
||||
}
|
||||
} else {
|
||||
// NB: 2D case - We know exactly where H and W...
|
||||
input_info.tensor().set_spatial_static_shape(matdesc.size.height,
|
||||
matdesc.size.width);
|
||||
input_info.preprocess().resize(toOVInterp(*explicit_resize));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cfgPostProcessing() {
|
||||
for (const auto &output_name : m_output_names) {
|
||||
const auto explicit_out_tensor_layout =
|
||||
lookUp(m_output_tensor_layout, output_name);
|
||||
if (explicit_out_tensor_layout) {
|
||||
m_ppp.output(output_name).tensor()
|
||||
.set_layout(::ov::Layout(*explicit_out_tensor_layout));
|
||||
}
|
||||
|
||||
const auto explicit_out_model_layout =
|
||||
lookUp(m_output_model_layout, output_name);
|
||||
if (explicit_out_model_layout) {
|
||||
m_ppp.output(output_name).model()
|
||||
.set_layout(::ov::Layout(*explicit_out_model_layout));
|
||||
}
|
||||
|
||||
const auto explicit_out_tensor_prec =
|
||||
lookUp(m_output_tensor_precision, output_name);
|
||||
if (explicit_out_tensor_prec) {
|
||||
m_ppp.output(output_name).tensor()
|
||||
.set_element_type(toOV(*explicit_out_tensor_prec));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void finalize() {
|
||||
GAPI_LOG_DEBUG(NULL, "OV Backend: PrePostProcessor: " << m_ppp);
|
||||
m_model = m_ppp.build();
|
||||
}
|
||||
|
||||
private:
|
||||
::ov::preprocess::PrePostProcessor m_ppp;
|
||||
|
||||
std::shared_ptr<::ov::Model> &m_model;
|
||||
const ParamDesc::Model &m_model_info;
|
||||
const std::vector<std::string> &m_input_names;
|
||||
const std::vector<std::string> &m_output_names;
|
||||
|
||||
cv::gimpl::ov::AttrMap<std::string> m_input_tensor_layout;
|
||||
cv::gimpl::ov::AttrMap<std::string> m_input_model_layout;
|
||||
cv::gimpl::ov::AttrMap<int> m_interpolation;
|
||||
cv::gimpl::ov::AttrMap<std::vector<float>> m_mean_values;
|
||||
cv::gimpl::ov::AttrMap<std::vector<float>> m_scale_values;
|
||||
cv::gimpl::ov::AttrMap<std::string> m_output_tensor_layout;
|
||||
cv::gimpl::ov::AttrMap<std::string> m_output_model_layout;
|
||||
cv::gimpl::ov::AttrMap<int> m_output_tensor_precision;
|
||||
};
|
||||
|
||||
struct Infer: public cv::detail::KernelTag {
|
||||
using API = cv::GInferBase;
|
||||
static cv::gapi::GBackend backend() { return cv::gapi::ov::backend(); }
|
||||
@@ -625,156 +949,21 @@ struct Infer: public cv::detail::KernelTag {
|
||||
// NB: Pre/Post processing configuration avaiable only for read models.
|
||||
if (cv::util::holds_alternative<ParamDesc::Model>(uu.params.kind)) {
|
||||
const auto &model_info = cv::util::get<ParamDesc::Model>(uu.params.kind);
|
||||
const auto new_shapes =
|
||||
broadcastLayerAttr(model_info.new_shapes,
|
||||
uu.params.input_names);
|
||||
const_cast<std::shared_ptr<::ov::Model>&>(uu.model)->reshape(toOV(new_shapes));
|
||||
auto& model = const_cast<std::shared_ptr<::ov::Model>&>(uu.model);
|
||||
PrePostProcWrapper ppp {model, model_info,
|
||||
uu.params.input_names, uu.params.output_names};
|
||||
|
||||
const auto input_tensor_layout =
|
||||
broadcastLayerAttr(model_info.input_tensor_layout,
|
||||
uu.params.input_names);
|
||||
const auto input_model_layout =
|
||||
broadcastLayerAttr(model_info.input_model_layout,
|
||||
uu.params.input_names);
|
||||
|
||||
const auto interpolation = broadcastLayerAttr(model_info.interpolation,
|
||||
uu.params.input_names);
|
||||
const auto mean_values = broadcastLayerAttr(model_info.mean_values,
|
||||
uu.params.input_names);
|
||||
const auto scale_values = broadcastLayerAttr(model_info.scale_values,
|
||||
uu.params.input_names);
|
||||
// FIXME: Pre/Post processing step shouldn't be configured in this method.
|
||||
::ov::preprocess::PrePostProcessor ppp(uu.model);
|
||||
for (auto &&it : ade::util::zip(ade::util::toRange(uu.params.input_names),
|
||||
ade::util::toRange(in_metas))) {
|
||||
const auto &mm = std::get<1>(it);
|
||||
GAPI_Assert(cv::util::holds_alternative<cv::GMatDesc>(mm));
|
||||
const auto &matdesc = cv::util::get<cv::GMatDesc>(mm);
|
||||
|
||||
const auto &input_name = std::get<0>(it);
|
||||
auto &input_info = ppp.input(input_name);
|
||||
input_info.tensor().set_element_type(toOV(matdesc.depth));
|
||||
const auto &mm = std::get<1>(it);
|
||||
|
||||
const auto explicit_in_model_layout = lookUp(input_model_layout, input_name);
|
||||
if (explicit_in_model_layout) {
|
||||
input_info.model().set_layout(::ov::Layout(*explicit_in_model_layout));
|
||||
}
|
||||
const auto explicit_in_tensor_layout = lookUp(input_tensor_layout, input_name);
|
||||
if (explicit_in_tensor_layout) {
|
||||
input_info.tensor().set_layout(::ov::Layout(*explicit_in_tensor_layout));
|
||||
}
|
||||
const auto explicit_resize = lookUp(interpolation, input_name);
|
||||
// NB: Note that model layout still can't be empty.
|
||||
// e.g If model converted to IRv11 without any additional
|
||||
// info about layout via Model Optimizer.
|
||||
const auto model_layout = ::ov::layout::get_layout(uu.model->input(input_name));
|
||||
const auto &input_shape = uu.model->input(input_name).get_shape();
|
||||
if (isImage(matdesc, input_shape)) {
|
||||
// NB: Image case - all necessary preprocessng is configured automatically.
|
||||
GAPI_LOG_DEBUG(NULL, "OV Backend: Input: \"" << input_name << "\" is image.");
|
||||
// NB: Layout is already set just double check that
|
||||
// user provided the correct one. In fact, there is only one correct for image.
|
||||
if (explicit_in_tensor_layout &&
|
||||
*explicit_in_tensor_layout != "NHWC") {
|
||||
std::stringstream ss;
|
||||
ss << "OV Backend: Provided tensor layout " << *explicit_in_tensor_layout
|
||||
<< " is not compatible with input data " << matdesc << " for layer \""
|
||||
<< input_name << "\". Expecting NHWC";
|
||||
util::throw_error(std::logic_error(ss.str()));
|
||||
}
|
||||
input_info.tensor().set_layout(::ov::Layout("NHWC"));
|
||||
input_info.tensor().set_spatial_static_shape(matdesc.size.height,
|
||||
matdesc.size.width);
|
||||
// NB: Even though resize is automatically configured
|
||||
// user have an opportunity to specify the interpolation algorithm.
|
||||
auto interp = explicit_resize
|
||||
? toOVInterp(*explicit_resize)
|
||||
: ::ov::preprocess::ResizeAlgorithm::RESIZE_LINEAR;
|
||||
input_info.preprocess().resize(interp);
|
||||
} else {
|
||||
// NB: Tensor case - resize or layout conversions must be explicitly specified.
|
||||
GAPI_LOG_DEBUG(NULL, "OV Backend: Input: \"" << input_name << "\" is tensor.");
|
||||
if (explicit_resize) {
|
||||
if (matdesc.isND()) {
|
||||
// NB: ND case - need to obtain "H" and "W" positions
|
||||
// in order to configure resize.
|
||||
if (!explicit_in_tensor_layout && model_layout.empty()) {
|
||||
std::stringstream ss;
|
||||
ss << "Resize for input layer: " << input_name
|
||||
<< "can't be configured."
|
||||
<< " Failed to extract H and W positions from layout.";
|
||||
util::throw_error(std::logic_error(ss.str()));
|
||||
} else {
|
||||
const auto layout = explicit_in_tensor_layout
|
||||
? ::ov::Layout(*explicit_in_tensor_layout) : model_layout;
|
||||
auto H_idx = ::ov::layout::height_idx(layout);
|
||||
auto W_idx = ::ov::layout::width_idx(layout);
|
||||
// NB: If layout is "...HW", H position is -2.
|
||||
if (H_idx < 0) H_idx = matdesc.dims.size() + H_idx;
|
||||
if (W_idx < 0) W_idx = matdesc.dims.size() + W_idx;
|
||||
GAPI_Assert(H_idx >= 0 && H_idx < static_cast<int>(matdesc.dims.size()));
|
||||
GAPI_Assert(W_idx >= 0 && W_idx < static_cast<int>(matdesc.dims.size()));
|
||||
input_info.tensor().set_spatial_static_shape(matdesc.dims[H_idx],
|
||||
matdesc.dims[W_idx]);
|
||||
input_info.preprocess().resize(toOVInterp(*explicit_resize));
|
||||
}
|
||||
} else {
|
||||
// NB: 2D case - We know exactly where H and W...
|
||||
input_info.tensor().set_spatial_static_shape(matdesc.size.height,
|
||||
matdesc.size.width);
|
||||
input_info.preprocess().resize(toOVInterp(*explicit_resize));
|
||||
}
|
||||
}
|
||||
}
|
||||
// NB: Apply mean/scale as the last step of the preprocessing.
|
||||
// Note that this can be applied to any input data if the
|
||||
// position of "C" dimension is known.
|
||||
const auto mean_vec = lookUp(mean_values, input_name);
|
||||
if (mean_vec) {
|
||||
input_info.preprocess().mean(*mean_vec);
|
||||
}
|
||||
|
||||
const auto scale_vec = lookUp(scale_values, input_name);
|
||||
if (scale_vec) {
|
||||
input_info.preprocess().scale(*scale_vec);
|
||||
}
|
||||
ppp.cfgLayouts(input_name);
|
||||
ppp.cfgPreProcessing(input_name, mm);
|
||||
ppp.cfgScaleMean(input_name);
|
||||
}
|
||||
|
||||
const auto output_tensor_layout =
|
||||
broadcastLayerAttr(model_info.output_tensor_layout,
|
||||
uu.params.output_names);
|
||||
const auto output_model_layout =
|
||||
broadcastLayerAttr(model_info.output_model_layout,
|
||||
uu.params.output_names);
|
||||
const auto output_tensor_precision =
|
||||
broadcastLayerAttr(model_info.output_tensor_precision,
|
||||
uu.params.output_names);
|
||||
|
||||
for (const auto &output_name : uu.params.output_names) {
|
||||
const auto explicit_out_tensor_layout =
|
||||
lookUp(output_tensor_layout, output_name);
|
||||
if (explicit_out_tensor_layout) {
|
||||
ppp.output(output_name).tensor()
|
||||
.set_layout(::ov::Layout(*explicit_out_tensor_layout));
|
||||
}
|
||||
|
||||
const auto explicit_out_model_layout =
|
||||
lookUp(output_model_layout, output_name);
|
||||
if (explicit_out_model_layout) {
|
||||
ppp.output(output_name).model()
|
||||
.set_layout(::ov::Layout(*explicit_out_model_layout));
|
||||
}
|
||||
|
||||
const auto explicit_out_tensor_prec =
|
||||
lookUp(output_tensor_precision, output_name);
|
||||
if (explicit_out_tensor_prec) {
|
||||
ppp.output(output_name).tensor()
|
||||
.set_element_type(toOV(*explicit_out_tensor_prec));
|
||||
}
|
||||
}
|
||||
|
||||
GAPI_LOG_DEBUG(NULL, "OV Backend: PrePostProcessor: " << ppp);
|
||||
const_cast<std::shared_ptr<::ov::Model>&>(uu.model) = ppp.build();
|
||||
ppp.cfgPostProcessing();
|
||||
ppp.finalize();
|
||||
}
|
||||
|
||||
for (const auto &out_name : uu.params.output_names) {
|
||||
@@ -815,6 +1004,313 @@ struct Infer: public cv::detail::KernelTag {
|
||||
}
|
||||
};
|
||||
|
||||
struct InferROI: public cv::detail::KernelTag {
|
||||
using API = cv::GInferROIBase;
|
||||
static cv::gapi::GBackend backend() { return cv::gapi::ov::backend(); }
|
||||
static KImpl kernel() { return KImpl{outMeta, run}; }
|
||||
|
||||
static cv::GMetaArgs outMeta(const ade::Graph &gr,
|
||||
const ade::NodeHandle &nh,
|
||||
const cv::GMetaArgs &in_metas,
|
||||
const cv::GArgs &/*in_args*/) {
|
||||
cv::GMetaArgs result;
|
||||
|
||||
GConstGOVModel gm(gr);
|
||||
const auto &uu = gm.metadata(nh).get<OVUnit>();
|
||||
// Initialize input information
|
||||
// FIXME: So far it is pretty limited
|
||||
GAPI_Assert(1u == uu.params.input_names.size());
|
||||
GAPI_Assert(2u == in_metas.size());
|
||||
|
||||
const auto &input_name = uu.params.input_names.at(0);
|
||||
const auto &mm = in_metas.at(1u);
|
||||
GAPI_Assert(cv::util::holds_alternative<cv::GMatDesc>(mm));
|
||||
const auto &matdesc = cv::util::get<cv::GMatDesc>(mm);
|
||||
|
||||
const bool is_model = cv::util::holds_alternative<ParamDesc::Model>(uu.params.kind);
|
||||
const auto &input_shape = is_model ? uu.model->input(input_name).get_shape()
|
||||
: uu.compiled_model.input(input_name).get_shape();
|
||||
if (!isImage(matdesc, input_shape)) {
|
||||
util::throw_error(std::runtime_error(
|
||||
"OV Backend: InferROI supports only image as the 1th argument"));
|
||||
}
|
||||
|
||||
if (is_model) {
|
||||
const auto &model_info = cv::util::get<ParamDesc::Model>(uu.params.kind);
|
||||
auto& model = const_cast<std::shared_ptr<::ov::Model>&>(uu.model);
|
||||
PrePostProcWrapper ppp {model, model_info,
|
||||
uu.params.input_names, uu.params.output_names};
|
||||
|
||||
ppp.cfgLayouts(input_name);
|
||||
ppp.cfgPreProcessing(input_name, mm, true /*disable_img_resize*/);
|
||||
ppp.cfgScaleMean(input_name);
|
||||
ppp.cfgPostProcessing();
|
||||
ppp.finalize();
|
||||
}
|
||||
|
||||
for (const auto &out_name : uu.params.output_names) {
|
||||
cv::GMatDesc outm;
|
||||
if (cv::util::holds_alternative<ParamDesc::Model>(uu.params.kind)) {
|
||||
const auto &out = uu.model->output(out_name);
|
||||
outm = cv::GMatDesc(toCV(out.get_element_type()),
|
||||
toCV(out.get_shape()));
|
||||
} else {
|
||||
GAPI_Assert(cv::util::holds_alternative<ParamDesc::CompiledModel>(uu.params.kind));
|
||||
const auto &out = uu.compiled_model.output(out_name);
|
||||
outm = cv::GMatDesc(toCV(out.get_element_type()),
|
||||
toCV(out.get_shape()));
|
||||
}
|
||||
result.emplace_back(std::move(outm));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void run(std::shared_ptr<OVCallContext> ctx,
|
||||
cv::gimpl::ov::RequestPool &reqPool) {
|
||||
using namespace std::placeholders;
|
||||
reqPool.getIdleRequest()->execute(
|
||||
IInferExecutor::Task {
|
||||
[ctx](::ov::InferRequest &infer_request) {
|
||||
GAPI_Assert(ctx->uu.params.num_in == 1);
|
||||
const auto &input_name = ctx->uu.params.input_names[0];
|
||||
auto input_tensor = infer_request.get_tensor(input_name);
|
||||
const auto &shape = input_tensor.get_shape();
|
||||
const auto &roi = ctx->inArg<cv::detail::OpaqueRef>(0).rref<cv::Rect>();
|
||||
const auto roi_mat = preprocess(ctx->inMat(1), roi, shape);
|
||||
copyToOV(roi_mat, input_tensor);
|
||||
},
|
||||
std::bind(PostOutputs, _1, _2, ctx)
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct InferList: public cv::detail::KernelTag {
|
||||
using API = cv::GInferListBase;
|
||||
static cv::gapi::GBackend backend() { return cv::gapi::ov::backend(); }
|
||||
static KImpl kernel() { return KImpl{outMeta, run}; }
|
||||
|
||||
static cv::GMetaArgs outMeta(const ade::Graph &gr,
|
||||
const ade::NodeHandle &nh,
|
||||
const cv::GMetaArgs &in_metas,
|
||||
const cv::GArgs &/*in_args*/) {
|
||||
GConstGOVModel gm(gr);
|
||||
const auto &uu = gm.metadata(nh).get<OVUnit>();
|
||||
// Initialize input information
|
||||
// Note our input layers list order matches the API order and so
|
||||
// meta order.
|
||||
GAPI_Assert(uu.params.input_names.size() == (in_metas.size() - 1u)
|
||||
&& "Known input layers count doesn't match input meta count");
|
||||
|
||||
// NB: Pre/Post processing configuration avaiable only for read models.
|
||||
if (cv::util::holds_alternative<ParamDesc::Model>(uu.params.kind)) {
|
||||
const auto &model_info = cv::util::get<ParamDesc::Model>(uu.params.kind);
|
||||
auto& model = const_cast<std::shared_ptr<::ov::Model>&>(uu.model);
|
||||
PrePostProcWrapper ppp {model, model_info,
|
||||
uu.params.input_names, uu.params.output_names};
|
||||
|
||||
size_t idx = 1u;
|
||||
for (auto &&input_name : uu.params.input_names) {
|
||||
const auto &mm = in_metas[idx++];
|
||||
GAPI_Assert(cv::util::holds_alternative<cv::GMatDesc>(mm));
|
||||
const auto &matdesc = cv::util::get<cv::GMatDesc>(mm);
|
||||
const auto &input_shape = uu.model->input(input_name).get_shape();
|
||||
|
||||
if (!isImage(matdesc, input_shape)) {
|
||||
util::throw_error(std::runtime_error(
|
||||
"OV Backend: Only image is supported"
|
||||
" as the " + std::to_string(idx) + "th argument for InferList"));
|
||||
}
|
||||
|
||||
ppp.cfgLayouts(input_name);
|
||||
ppp.cfgPreProcessing(input_name, mm, true /*disable_img_resize*/);
|
||||
ppp.cfgScaleMean(input_name);
|
||||
}
|
||||
ppp.cfgPostProcessing();
|
||||
ppp.finalize();
|
||||
}
|
||||
|
||||
// roi-list version is much easier at the moment.
|
||||
// All our outputs are vectors which don't have
|
||||
// metadata at the moment - so just create a vector of
|
||||
// "empty" array metadatas of the required size.
|
||||
return cv::GMetaArgs(uu.params.output_names.size(),
|
||||
cv::GMetaArg{cv::empty_array_desc()});
|
||||
}
|
||||
|
||||
static void run(std::shared_ptr<OVCallContext> ctx,
|
||||
cv::gimpl::ov::RequestPool &reqPool) {
|
||||
const auto& in_roi_vec = ctx->inArg<cv::detail::VectorRef>(0u).rref<cv::Rect>();
|
||||
// NB: In case there is no input data need to post output anyway
|
||||
if (in_roi_vec.empty()) {
|
||||
for (auto i : ade::util::iota(ctx->uu.params.num_out)) {
|
||||
auto output = ctx->output(i);
|
||||
ctx->out.meta(output, ctx->getMeta());
|
||||
ctx->out.post(std::move(output));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto i : ade::util::iota(ctx->uu.params.num_out)) {
|
||||
// FIXME: Isn't this should be done automatically
|
||||
// by some resetInternalData(), etc? (Probably at the GExecutor level)
|
||||
auto& out_vec = ctx->outVecR<cv::Mat>(i);
|
||||
out_vec.clear();
|
||||
out_vec.resize(in_roi_vec.size());
|
||||
}
|
||||
|
||||
PostOutputsList callback(in_roi_vec.size(), ctx);
|
||||
for (auto&& it : ade::util::indexed(in_roi_vec)) {
|
||||
const auto pos = ade::util::index(it);
|
||||
const auto &rc = ade::util::value(it);
|
||||
reqPool.getIdleRequest()->execute(
|
||||
IInferExecutor::Task {
|
||||
[ctx, rc](::ov::InferRequest &infer_request) {
|
||||
const auto &input_name = ctx->uu.params.input_names[0];
|
||||
auto input_tensor = infer_request.get_tensor(input_name);
|
||||
const auto &shape = input_tensor.get_shape();
|
||||
const auto roi_mat = preprocess(ctx->inMat(1), rc, shape);
|
||||
copyToOV(roi_mat, input_tensor);
|
||||
},
|
||||
std::bind(callback, std::placeholders::_1, std::placeholders::_2, pos)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct InferList2: public cv::detail::KernelTag {
|
||||
using API = cv::GInferList2Base;
|
||||
static cv::gapi::GBackend backend() { return cv::gapi::ov::backend(); }
|
||||
static KImpl kernel() { return KImpl{outMeta, run}; }
|
||||
|
||||
static cv::GMetaArgs outMeta(const ade::Graph &gr,
|
||||
const ade::NodeHandle &nh,
|
||||
const cv::GMetaArgs &in_metas,
|
||||
const cv::GArgs &/*in_args*/) {
|
||||
GConstGOVModel gm(gr);
|
||||
const auto &uu = gm.metadata(nh).get<OVUnit>();
|
||||
// Initialize input information
|
||||
// Note our input layers list order matches the API order and so
|
||||
// meta order.
|
||||
GAPI_Assert(uu.params.input_names.size() == (in_metas.size() - 1u)
|
||||
&& "Known input layers count doesn't match input meta count");
|
||||
|
||||
const auto &op = gm.metadata(nh).get<Op>();
|
||||
|
||||
// In contrast to InferList, the InferList2 has only one
|
||||
// "full-frame" image argument, and all the rest are arrays of
|
||||
// ether ROI or blobs. So here we set the 0th arg image format
|
||||
// to all inputs which are ROI-based (skipping the
|
||||
// "blob"-based ones)
|
||||
// FIXME: this is filtering not done, actually! GArrayDesc has
|
||||
// no hint for its underlying type!
|
||||
|
||||
const auto &input_name_0 = uu.params.input_names.front();
|
||||
const auto &mm_0 = in_metas[0u];
|
||||
const auto &matdesc = cv::util::get<cv::GMatDesc>(mm_0);
|
||||
|
||||
const bool is_model = cv::util::holds_alternative<ParamDesc::Model>(uu.params.kind);
|
||||
const auto &input_shape = is_model ? uu.model->input(input_name_0).get_shape()
|
||||
: uu.compiled_model.input(input_name_0).get_shape();
|
||||
if (!isImage(matdesc, input_shape)) {
|
||||
util::throw_error(std::runtime_error(
|
||||
"OV Backend: InferList2 supports only image as the 0th argument"));
|
||||
}
|
||||
|
||||
if (is_model) {
|
||||
const auto &model_info = cv::util::get<ParamDesc::Model>(uu.params.kind);
|
||||
auto& model = const_cast<std::shared_ptr<::ov::Model>&>(uu.model);
|
||||
PrePostProcWrapper ppp {model, model_info,
|
||||
uu.params.input_names, uu.params.output_names};
|
||||
|
||||
size_t idx = 1u;
|
||||
for (auto &&input_name : uu.params.input_names) {
|
||||
GAPI_Assert(util::holds_alternative<cv::GArrayDesc>(in_metas[idx])
|
||||
&& "Non-array inputs are not supported");
|
||||
|
||||
ppp.cfgLayouts(input_name);
|
||||
if (op.k.inKinds[idx] == cv::detail::OpaqueKind::CV_RECT) {
|
||||
ppp.cfgPreProcessing(input_name, mm_0, true /*disable_img_resize*/);
|
||||
} else {
|
||||
// This is a cv::GMat (equals to: cv::Mat)
|
||||
// Just validate that it is really the type
|
||||
// (other types are prohibited here)
|
||||
GAPI_Assert(op.k.inKinds[idx] == cv::detail::OpaqueKind::CV_MAT);
|
||||
}
|
||||
|
||||
ppp.cfgScaleMean(input_name);
|
||||
idx++; // NB: Never forget to increment the counter
|
||||
}
|
||||
ppp.cfgPostProcessing();
|
||||
ppp.finalize();
|
||||
}
|
||||
|
||||
// roi-list version is much easier at the moment.
|
||||
// All our outputs are vectors which don't have
|
||||
// metadata at the moment - so just create a vector of
|
||||
// "empty" array metadatas of the required size.
|
||||
return cv::GMetaArgs(uu.params.output_names.size(),
|
||||
cv::GMetaArg{cv::empty_array_desc()});
|
||||
}
|
||||
|
||||
static void run(std::shared_ptr<OVCallContext> ctx,
|
||||
cv::gimpl::ov::RequestPool &reqPool) {
|
||||
GAPI_Assert(ctx->inArgs().size() > 1u
|
||||
&& "This operation must have at least two arguments");
|
||||
// NB: This blob will be used to make roi from its, so
|
||||
// it should be treated as image
|
||||
const auto list_size = ctx->inArg<cv::detail::VectorRef>(1u).size();
|
||||
if (list_size == 0u) {
|
||||
for (auto i : ade::util::iota(ctx->uu.params.num_out)) {
|
||||
auto output = ctx->output(i);
|
||||
ctx->out.meta(output, ctx->getMeta());
|
||||
ctx->out.post(std::move(output));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto i : ade::util::iota(ctx->uu.params.num_out)) {
|
||||
// FIXME: Isn't this should be done automatically
|
||||
// by some resetInternalData(), etc? (Probably at the GExecutor level)
|
||||
auto& out_vec = ctx->outVecR<cv::Mat>(i);
|
||||
out_vec.clear();
|
||||
out_vec.resize(list_size);
|
||||
}
|
||||
|
||||
PostOutputsList callback(list_size, ctx);
|
||||
for (const auto &list_idx : ade::util::iota(list_size)) {
|
||||
reqPool.getIdleRequest()->execute(
|
||||
IInferExecutor::Task {
|
||||
[ctx, list_idx, list_size](::ov::InferRequest &infer_request) {
|
||||
for (auto in_idx : ade::util::iota(ctx->uu.params.num_in)) {
|
||||
const auto &this_vec = ctx->inArg<cv::detail::VectorRef>(in_idx+1u);
|
||||
GAPI_Assert(this_vec.size() == list_size);
|
||||
const auto &input_name = ctx->uu.params.input_names[in_idx];
|
||||
auto input_tensor = infer_request.get_tensor(input_name);
|
||||
const auto &shape = input_tensor.get_shape();
|
||||
if (this_vec.getKind() == cv::detail::OpaqueKind::CV_RECT) {
|
||||
const auto &vec = this_vec.rref<cv::Rect>();
|
||||
const auto roi_mat = preprocess(ctx->inMat(0), vec[list_idx], shape);
|
||||
copyToOV(roi_mat, input_tensor);
|
||||
} else if (this_vec.getKind() == cv::detail::OpaqueKind::CV_MAT) {
|
||||
const auto &vec = this_vec.rref<cv::Mat>();
|
||||
const auto &mat = vec[list_idx];
|
||||
copyToOV(mat, input_tensor);
|
||||
} else {
|
||||
GAPI_Assert(false &&
|
||||
"OV Backend: Only Rect and Mat types are supported for InferList2");
|
||||
}
|
||||
}
|
||||
},
|
||||
std::bind(callback, std::placeholders::_1, std::placeholders::_2, list_idx)
|
||||
} // task
|
||||
);
|
||||
} // for
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ov
|
||||
} // namespace gimpl
|
||||
} // namespace cv
|
||||
@@ -858,7 +1354,10 @@ class GOVBackendImpl final: public cv::gapi::GBackend::Priv {
|
||||
}
|
||||
|
||||
virtual cv::GKernelPackage auxiliaryKernels() const override {
|
||||
return cv::gapi::kernels< cv::gimpl::ov::Infer >();
|
||||
return cv::gapi::kernels< cv::gimpl::ov::Infer
|
||||
, cv::gimpl::ov::InferROI
|
||||
, cv::gimpl::ov::InferList
|
||||
, cv::gimpl::ov::InferList2 >();
|
||||
}
|
||||
|
||||
virtual bool controlsMerge() const override {
|
||||
@@ -904,8 +1403,10 @@ cv::gimpl::ov::GOVExecutable::GOVExecutable(const ade::Graph &g,
|
||||
case NodeType::OP:
|
||||
if (this_nh == nullptr) {
|
||||
this_nh = nh;
|
||||
compiled = const_cast<OVUnit&>(ovm.metadata(this_nh).get<OVUnit>()).compile();
|
||||
m_reqPool.reset(new RequestPool(createInferRequests(compiled.compiled_model, 1)));
|
||||
const auto &unit = ovm.metadata(this_nh).get<OVUnit>();
|
||||
compiled = const_cast<OVUnit&>(unit).compile();
|
||||
m_reqPool.reset(new RequestPool(createInferRequests(
|
||||
compiled.compiled_model, unit.params.nireq)));
|
||||
}
|
||||
else
|
||||
util::throw_error(std::logic_error("Multi-node inference is not supported!"));
|
||||
@@ -937,6 +1438,7 @@ void cv::gimpl::ov::GOVExecutable::run(cv::gimpl::GIslandExecutable::IInput &in
|
||||
|
||||
if (cv::util::holds_alternative<cv::gimpl::EndOfStream>(in_msg))
|
||||
{
|
||||
m_reqPool->waitAll();
|
||||
out.post(cv::gimpl::EndOfStream{});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -22,13 +22,19 @@ namespace cv {
|
||||
namespace gapi {
|
||||
namespace ov {
|
||||
namespace util {
|
||||
|
||||
// NB: These functions are EXPORTed to make them accessible by the
|
||||
// test suite only.
|
||||
GAPI_EXPORTS std::vector<int> to_ocv(const ::ov::Shape &shape);
|
||||
GAPI_EXPORTS int to_ocv(const ::ov::element::Type &type);
|
||||
|
||||
}}}}
|
||||
GAPI_EXPORTS void to_ov(const cv::Mat &mat, ::ov::Tensor &tensor);
|
||||
GAPI_EXPORTS void to_ocv(const ::ov::Tensor &tensor, cv::Mat &mat);
|
||||
} // namespace util
|
||||
namespace wrap {
|
||||
GAPI_EXPORTS ::ov::Core getCore();
|
||||
} // namespace wrap
|
||||
} // namespace ov
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // HAVE_INF_ENGINE && INF_ENGINE_RELEASE >= 2022010000
|
||||
|
||||
|
||||
@@ -59,7 +59,6 @@ private:
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
cv::gimpl::Unrolled cv::gimpl::unrollExpr(const GProtoArgs &ins,
|
||||
const GProtoArgs &outs)
|
||||
{
|
||||
@@ -135,18 +134,19 @@ cv::gimpl::Unrolled cv::gimpl::unrollExpr(const GProtoArgs &ins,
|
||||
// Put the outputs object description of the node
|
||||
// so that they are not lost if they are not consumed by other operations
|
||||
GAPI_Assert(call_p.m_k.outCtors.size() == call_p.m_k.outShapes.size());
|
||||
for (const auto it : ade::util::indexed(call_p.m_k.outShapes))
|
||||
for (const auto it : ade::util::indexed(ade::util::zip(call_p.m_k.outShapes,
|
||||
call_p.m_k.outCtors,
|
||||
call_p.m_k.outKinds)))
|
||||
{
|
||||
std::size_t port = ade::util::index(it);
|
||||
GShape shape = ade::util::value(it);
|
||||
|
||||
// FIXME: then use ZIP
|
||||
HostCtor ctor = call_p.m_k.outCtors[port];
|
||||
|
||||
auto port = ade::util::index(it);
|
||||
auto &val = ade::util::value(it);
|
||||
auto shape = std::get<0>(val);
|
||||
auto ctor = std::get<1>(val);
|
||||
auto kind = std::get<2>(val);
|
||||
// NB: Probably this fixes all other "missing host ctor"
|
||||
// problems.
|
||||
// TODO: Clean-up the old workarounds if it really is.
|
||||
GOrigin org {shape, node, port, std::move(ctor), origin.kind};
|
||||
GOrigin org {shape, node, port, std::move(ctor), kind};
|
||||
origins.insert(org);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,11 @@ public:
|
||||
return cv::MediaFrame::View(std::move(pp), std::move(ss), Cb{m_cb});
|
||||
}
|
||||
cv::util::any blobParams() const override {
|
||||
#if INF_ENGINE_RELEASE > 2023000000
|
||||
// NB: blobParams() shouldn't be used in tests
|
||||
// if OpenVINO versions is higher than 2023.0
|
||||
GAPI_Assert(false && "NV12 feature has been deprecated in OpenVINO 1.0 API.");
|
||||
#else
|
||||
return std::make_pair<InferenceEngine::TensorDesc,
|
||||
InferenceEngine::ParamMap>({IE::Precision::U8,
|
||||
{1, 3, 300, 300},
|
||||
@@ -69,6 +74,7 @@ public:
|
||||
{{"HELLO", 42},
|
||||
{"COLOR_FORMAT",
|
||||
InferenceEngine::ColorFormat::NV12}});
|
||||
#endif // INF_ENGINE_RELEASE > 2023000000
|
||||
}
|
||||
};
|
||||
|
||||
@@ -138,7 +144,13 @@ void setNetParameters(IE::CNNNetwork& net, bool is_nv12 = false) {
|
||||
ii->setPrecision(IE::Precision::U8);
|
||||
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
|
||||
if (is_nv12) {
|
||||
#if INF_ENGINE_RELEASE > 2023000000
|
||||
// NB: NV12 feature shouldn't be used in tests
|
||||
// if OpenVINO versions is higher than 2023.0
|
||||
GAPI_Assert(false && "NV12 feature has been deprecated in OpenVINO 1.0 API.");
|
||||
#else
|
||||
ii->getPreProcess().setColorFormat(IE::ColorFormat::NV12);
|
||||
#endif // INF_ENGINE_RELEASE > 2023000000
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,10 +404,14 @@ struct InferWithReshapeNV12: public InferWithReshape {
|
||||
cv::randu(m_in_y, 0, 255);
|
||||
m_in_uv = cv::Mat{sz / 2, CV_8UC2};
|
||||
cv::randu(m_in_uv, 0, 255);
|
||||
// NB: NV12 feature shouldn't be used in tests
|
||||
// if OpenVINO versions is higher than 2023.0
|
||||
#if INF_ENGINE_RELEASE <= 2023000000
|
||||
setNetParameters(net, true);
|
||||
net.reshape({{"data", reshape_dims}});
|
||||
auto frame_blob = cv::gapi::ie::util::to_ie(m_in_y, m_in_uv);
|
||||
inferROIs(frame_blob);
|
||||
#endif // INF_ENGINE_RELEASE <= 2023000000
|
||||
}
|
||||
};
|
||||
|
||||
@@ -505,8 +521,11 @@ struct ROIListNV12: public ::testing::Test {
|
||||
cv::Rect(cv::Point{50, 32}, cv::Size{128, 160}),
|
||||
};
|
||||
|
||||
// Load & run IE network
|
||||
// NB: NV12 feature shouldn't be used in tests
|
||||
// if OpenVINO versions is higher than 2023.0
|
||||
#if INF_ENGINE_RELEASE <= 2023000000
|
||||
{
|
||||
// Load & run IE network
|
||||
auto plugin = cv::gimpl::ie::wrap::getPlugin(params);
|
||||
auto net = cv::gimpl::ie::wrap::readNetwork(params);
|
||||
setNetParameters(net, true);
|
||||
@@ -530,9 +549,11 @@ struct ROIListNV12: public ::testing::Test {
|
||||
m_out_ie_genders.push_back(to_ocv(infer_request.GetBlob("prob")).clone());
|
||||
}
|
||||
} // namespace IE = ..
|
||||
#endif // INF_ENGINE_RELEASE <= 2023000000
|
||||
} // ROIList()
|
||||
|
||||
void validate() {
|
||||
#if INF_ENGINE_RELEASE <= 2023000000
|
||||
// Validate with IE itself (avoid DNN module dependency here)
|
||||
ASSERT_EQ(2u, m_out_ie_ages.size());
|
||||
ASSERT_EQ(2u, m_out_ie_genders.size());
|
||||
@@ -543,6 +564,10 @@ struct ROIListNV12: public ::testing::Test {
|
||||
normAssert(m_out_ie_genders[0], m_out_gapi_genders[0], "0: Test gender output");
|
||||
normAssert(m_out_ie_ages [1], m_out_gapi_ages [1], "1: Test age output");
|
||||
normAssert(m_out_ie_genders[1], m_out_gapi_genders[1], "1: Test gender output");
|
||||
#else
|
||||
GAPI_Assert(false && "Reference hasn't been calculated because"
|
||||
" NV12 feature has been deprecated.");
|
||||
#endif // INF_ENGINE_RELEASE <= 2023000000
|
||||
}
|
||||
};
|
||||
|
||||
@@ -631,6 +656,9 @@ struct SingleROINV12: public ::testing::Test {
|
||||
|
||||
m_roi = cv::Rect(cv::Point{64, 60}, cv::Size{96, 96});
|
||||
|
||||
// NB: NV12 feature shouldn't be used in tests
|
||||
// if OpenVINO versions is higher than 2023.0
|
||||
#if INF_ENGINE_RELEASE <= 2023000000
|
||||
// Load & run IE network
|
||||
IE::Blob::Ptr ie_age, ie_gender;
|
||||
{
|
||||
@@ -657,12 +685,18 @@ struct SingleROINV12: public ::testing::Test {
|
||||
m_out_ie_age = to_ocv(infer_request.GetBlob("age_conv3")).clone();
|
||||
m_out_ie_gender = to_ocv(infer_request.GetBlob("prob")).clone();
|
||||
}
|
||||
#endif // INF_ENGINE_RELEASE <= 2023000000
|
||||
}
|
||||
|
||||
void validate() {
|
||||
#if INF_ENGINE_RELEASE <= 2023000000
|
||||
// Validate with IE itself (avoid DNN module dependency here)
|
||||
normAssert(m_out_ie_age , m_out_gapi_age , "Test age output");
|
||||
normAssert(m_out_ie_gender, m_out_gapi_gender, "Test gender output");
|
||||
#else
|
||||
GAPI_Assert(false && "Reference hasn't been calculated because"
|
||||
" NV12 feature has been deprecated.");
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
@@ -962,11 +996,20 @@ TEST_F(ROIListNV12, MediaInputNV12)
|
||||
auto pp = cv::gapi::ie::Params<AgeGender> {
|
||||
params.model_path, params.weights_path, params.device_id
|
||||
}.cfgOutputLayers({ "age_conv3", "prob" });
|
||||
|
||||
// NB: NV12 feature has been deprecated in OpenVINO versions higher
|
||||
// than 2023.0 so G-API must throw error in that case.
|
||||
#if INF_ENGINE_RELEASE <= 2023000000
|
||||
comp.apply(cv::gin(frame, m_roi_list),
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
validate();
|
||||
#else
|
||||
EXPECT_ANY_THROW(comp.apply(cv::gin(frame, m_roi_list),
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp))));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderIE, MediaInputNV12)
|
||||
@@ -986,6 +1029,9 @@ TEST(TestAgeGenderIE, MediaInputNV12)
|
||||
|
||||
cv::Mat gapi_age, gapi_gender;
|
||||
|
||||
// NB: NV12 feature shouldn't be used in tests
|
||||
// if OpenVINO versions is higher than 2023.0
|
||||
#if INF_ENGINE_RELEASE <= 2023000000
|
||||
// Load & run IE network
|
||||
IE::Blob::Ptr ie_age, ie_gender;
|
||||
{
|
||||
@@ -999,6 +1045,7 @@ TEST(TestAgeGenderIE, MediaInputNV12)
|
||||
ie_age = infer_request.GetBlob("age_conv3");
|
||||
ie_gender = infer_request.GetBlob("prob");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Configure & run G-API
|
||||
using AGInfo = std::tuple<cv::GMat, cv::GMat>;
|
||||
@@ -1014,13 +1061,20 @@ TEST(TestAgeGenderIE, MediaInputNV12)
|
||||
auto pp = cv::gapi::ie::Params<AgeGender> {
|
||||
params.model_path, params.weights_path, params.device_id
|
||||
}.cfgOutputLayers({ "age_conv3", "prob" });
|
||||
|
||||
// NB: NV12 feature has been deprecated in OpenVINO versions higher
|
||||
// than 2023.0 so G-API must throw error in that case.
|
||||
#if INF_ENGINE_RELEASE <= 2023000000
|
||||
comp.apply(cv::gin(frame), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
|
||||
// Validate with IE itself (avoid DNN module dependency here)
|
||||
normAssert(cv::gapi::ie::util::to_ocv(ie_age), gapi_age, "Test age output" );
|
||||
normAssert(cv::gapi::ie::util::to_ocv(ie_gender), gapi_gender, "Test gender output");
|
||||
#else
|
||||
EXPECT_ANY_THROW(comp.apply(cv::gin(frame), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp))));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderIE, MediaInputBGR)
|
||||
@@ -1155,6 +1209,9 @@ TEST(InferROI, MediaInputNV12)
|
||||
cv::Mat gapi_age, gapi_gender;
|
||||
cv::Rect rect(cv::Point{64, 60}, cv::Size{96, 96});
|
||||
|
||||
// NB: NV12 feature shouldn't be used in tests
|
||||
// if OpenVINO versions is higher than 2023.0
|
||||
#if INF_ENGINE_RELEASE <= 2023000000
|
||||
// Load & run IE network
|
||||
IE::Blob::Ptr ie_age, ie_gender;
|
||||
{
|
||||
@@ -1176,6 +1233,7 @@ TEST(InferROI, MediaInputNV12)
|
||||
ie_age = infer_request.GetBlob("age_conv3");
|
||||
ie_gender = infer_request.GetBlob("prob");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Configure & run G-API
|
||||
using AGInfo = std::tuple<cv::GMat, cv::GMat>;
|
||||
@@ -1192,13 +1250,20 @@ TEST(InferROI, MediaInputNV12)
|
||||
auto pp = cv::gapi::ie::Params<AgeGender> {
|
||||
params.model_path, params.weights_path, params.device_id
|
||||
}.cfgOutputLayers({ "age_conv3", "prob" });
|
||||
|
||||
// NB: NV12 feature has been deprecated in OpenVINO versions higher
|
||||
// than 2023.0 so G-API must throw error in that case.
|
||||
#if INF_ENGINE_RELEASE <= 2023000000
|
||||
comp.apply(cv::gin(frame, rect), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
|
||||
// Validate with IE itself (avoid DNN module dependency here)
|
||||
normAssert(cv::gapi::ie::util::to_ocv(ie_age), gapi_age, "Test age output" );
|
||||
normAssert(cv::gapi::ie::util::to_ocv(ie_gender), gapi_gender, "Test gender output");
|
||||
#else
|
||||
EXPECT_ANY_THROW(comp.apply(cv::gin(frame, rect), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp))));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_F(ROIList, Infer2MediaInputBGR)
|
||||
@@ -1233,10 +1298,20 @@ TEST_F(ROIListNV12, Infer2MediaInputNV12)
|
||||
auto pp = cv::gapi::ie::Params<AgeGender> {
|
||||
params.model_path, params.weights_path, params.device_id
|
||||
}.cfgOutputLayers({ "age_conv3", "prob" });
|
||||
|
||||
// NB: NV12 feature has been deprecated in OpenVINO versions higher
|
||||
// than 2023.0 so G-API must throw error in that case.
|
||||
#if INF_ENGINE_RELEASE <= 2023000000
|
||||
comp.apply(cv::gin(frame, m_roi_list),
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
validate();
|
||||
#else
|
||||
EXPECT_ANY_THROW(comp.apply(cv::gin(frame, m_roi_list),
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp))));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_F(SingleROI, GenericInfer)
|
||||
@@ -1310,10 +1385,19 @@ TEST_F(SingleROINV12, GenericInferMediaNV12)
|
||||
pp.cfgNumRequests(2u);
|
||||
|
||||
auto frame = MediaFrame::Create<TestMediaNV12>(m_in_y, m_in_uv);
|
||||
|
||||
// NB: NV12 feature has been deprecated in OpenVINO versions higher
|
||||
// than 2023.0 so G-API must throw error in that case.
|
||||
#if INF_ENGINE_RELEASE <= 2023000000
|
||||
comp.apply(cv::gin(frame, m_roi), cv::gout(m_out_gapi_age, m_out_gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
validate();
|
||||
#else
|
||||
EXPECT_ANY_THROW(comp.apply(cv::gin(frame, m_roi),
|
||||
cv::gout(m_out_gapi_age, m_out_gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp))));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_F(ROIList, GenericInfer)
|
||||
@@ -1386,11 +1470,20 @@ TEST_F(ROIListNV12, GenericInferMediaNV12)
|
||||
pp.cfgNumRequests(2u);
|
||||
|
||||
auto frame = MediaFrame::Create<TestMediaNV12>(m_in_y, m_in_uv);
|
||||
|
||||
// NB: NV12 feature has been deprecated in OpenVINO versions higher
|
||||
// than 2023.0 so G-API must throw error in that case.
|
||||
#if INF_ENGINE_RELEASE <= 2023000000
|
||||
comp.apply(cv::gin(frame, m_roi_list),
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
validate();
|
||||
#else
|
||||
EXPECT_ANY_THROW(comp.apply(cv::gin(frame, m_roi_list),
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp))));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_F(ROIList, GenericInfer2)
|
||||
@@ -1461,10 +1554,20 @@ TEST_F(ROIListNV12, GenericInfer2MediaInputNV12)
|
||||
pp.cfgNumRequests(2u);
|
||||
|
||||
auto frame = MediaFrame::Create<TestMediaNV12>(m_in_y, m_in_uv);
|
||||
|
||||
// NB: NV12 feature has been deprecated in OpenVINO versions higher
|
||||
// than 2023.0 so G-API must throw error in that case.
|
||||
#if INF_ENGINE_RELEASE <= 2023000000
|
||||
comp.apply(cv::gin(frame, m_roi_list),
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
validate();
|
||||
#else
|
||||
EXPECT_ANY_THROW(comp.apply(cv::gin(frame, m_roi_list),
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp))));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(Infer, SetInvalidNumberOfRequests)
|
||||
@@ -2050,11 +2153,20 @@ TEST_F(InferWithReshapeNV12, TestInferListYUV)
|
||||
auto pp = cv::gapi::ie::Params<AgeGender> {
|
||||
params.model_path, params.weights_path, params.device_id
|
||||
}.cfgOutputLayers({ "age_conv3", "prob" }).cfgInputReshape({{"data", reshape_dims}});
|
||||
|
||||
// NB: NV12 feature has been deprecated in OpenVINO versions higher
|
||||
// than 2023.0 so G-API must throw error in that case.
|
||||
#if INF_ENGINE_RELEASE <= 2023000000
|
||||
comp.apply(cv::gin(frame, m_roi_list),
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
// Validate
|
||||
validate();
|
||||
#else
|
||||
EXPECT_ANY_THROW(comp.apply(cv::gin(frame, m_roi_list),
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp))));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_F(ROIList, CallInferMultipleTimes)
|
||||
@@ -2079,6 +2191,7 @@ TEST_F(ROIList, CallInferMultipleTimes)
|
||||
validate();
|
||||
}
|
||||
|
||||
#if INF_ENGINE_RELEASE <= 2023000000
|
||||
TEST(IEFrameAdapter, blobParams)
|
||||
{
|
||||
cv::Mat bgr = cv::Mat::eye(240, 320, CV_8UC3);
|
||||
@@ -2093,6 +2206,7 @@ TEST(IEFrameAdapter, blobParams)
|
||||
|
||||
EXPECT_EQ(expected, actual);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -2281,6 +2395,10 @@ TEST(TestAgeGenderIE, InferWithBatch)
|
||||
normAssert(cv::gapi::ie::util::to_ocv(ie_gender), gapi_gender, "Test gender output");
|
||||
}
|
||||
|
||||
// NB: All tests below use preprocessing for "Import" networks
|
||||
// passed as the last argument to SetBLob. This overload has
|
||||
// been deprecated in OpenVINO 1.0 API.
|
||||
#if INF_ENGINE_RELEASE <= 2023000000
|
||||
TEST(ImportNetwork, Infer)
|
||||
{
|
||||
const std::string device = "MYRIAD";
|
||||
@@ -2820,6 +2938,7 @@ TEST(ImportNetwork, InferList2NV12)
|
||||
normAssert(out_ie_genders[i], out_gapi_genders[i], "Test gender output");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(TestAgeGender, ThrowBlobAndInputPrecisionMismatch)
|
||||
{
|
||||
|
||||
@@ -41,20 +41,6 @@ void initDLDTDataPath()
|
||||
|
||||
static const std::string SUBDIR = "intel/age-gender-recognition-retail-0013/FP32/";
|
||||
|
||||
void copyFromOV(ov::Tensor &tensor, cv::Mat &mat) {
|
||||
GAPI_Assert(tensor.get_byte_size() == mat.total() * mat.elemSize());
|
||||
std::copy_n(reinterpret_cast<uint8_t*>(tensor.data()),
|
||||
tensor.get_byte_size(),
|
||||
mat.ptr<uint8_t>());
|
||||
}
|
||||
|
||||
void copyToOV(const cv::Mat &mat, ov::Tensor &tensor) {
|
||||
GAPI_Assert(tensor.get_byte_size() == mat.total() * mat.elemSize());
|
||||
std::copy_n(mat.ptr<uint8_t>(),
|
||||
tensor.get_byte_size(),
|
||||
reinterpret_cast<uint8_t*>(tensor.data()));
|
||||
}
|
||||
|
||||
// FIXME: taken from the DNN module
|
||||
void normAssert(cv::InputArray ref, cv::InputArray test,
|
||||
const char *comment /*= ""*/,
|
||||
@@ -66,15 +52,10 @@ void normAssert(cv::InputArray ref, cv::InputArray test,
|
||||
EXPECT_LE(normInf, lInf) << comment;
|
||||
}
|
||||
|
||||
ov::Core getCore() {
|
||||
static ov::Core core;
|
||||
return core;
|
||||
}
|
||||
|
||||
// TODO: AGNetGenComp, AGNetTypedComp, AGNetOVComp, AGNetOVCompiled
|
||||
// can be generalized to work with any model and used as parameters for tests.
|
||||
|
||||
struct AGNetGenComp {
|
||||
struct AGNetGenParams {
|
||||
static constexpr const char* tag = "age-gender-generic";
|
||||
using Params = cv::gapi::ov::Params<cv::gapi::Generic>;
|
||||
|
||||
@@ -88,19 +69,9 @@ struct AGNetGenComp {
|
||||
const std::string &device) {
|
||||
return {tag, blob_path, device};
|
||||
}
|
||||
|
||||
static cv::GComputation create() {
|
||||
cv::GMat in;
|
||||
GInferInputs inputs;
|
||||
inputs["data"] = in;
|
||||
auto outputs = cv::gapi::infer<cv::gapi::Generic>(tag, inputs);
|
||||
auto age = outputs.at("age_conv3");
|
||||
auto gender = outputs.at("prob");
|
||||
return cv::GComputation{cv::GIn(in), cv::GOut(age, gender)};
|
||||
}
|
||||
};
|
||||
|
||||
struct AGNetTypedComp {
|
||||
struct AGNetTypedParams {
|
||||
using AGInfo = std::tuple<cv::GMat, cv::GMat>;
|
||||
G_API_NET(AgeGender, <AGInfo(cv::GMat)>, "typed-age-gender");
|
||||
using Params = cv::gapi::ov::Params<AgeGender>;
|
||||
@@ -112,7 +83,9 @@ struct AGNetTypedComp {
|
||||
xml_path, bin_path, device
|
||||
}.cfgOutputLayers({ "age_conv3", "prob" });
|
||||
}
|
||||
};
|
||||
|
||||
struct AGNetTypedComp : AGNetTypedParams {
|
||||
static cv::GComputation create() {
|
||||
cv::GMat in;
|
||||
cv::GMat age, gender;
|
||||
@@ -121,30 +94,104 @@ struct AGNetTypedComp {
|
||||
}
|
||||
};
|
||||
|
||||
struct AGNetGenComp : public AGNetGenParams {
|
||||
static cv::GComputation create() {
|
||||
cv::GMat in;
|
||||
GInferInputs inputs;
|
||||
inputs["data"] = in;
|
||||
auto outputs = cv::gapi::infer<cv::gapi::Generic>(tag, inputs);
|
||||
auto age = outputs.at("age_conv3");
|
||||
auto gender = outputs.at("prob");
|
||||
return cv::GComputation{cv::GIn(in), cv::GOut(age, gender)};
|
||||
}
|
||||
};
|
||||
|
||||
struct AGNetROIGenComp : AGNetGenParams {
|
||||
static cv::GComputation create() {
|
||||
cv::GMat in;
|
||||
cv::GOpaque<cv::Rect> roi;
|
||||
GInferInputs inputs;
|
||||
inputs["data"] = in;
|
||||
auto outputs = cv::gapi::infer<cv::gapi::Generic>(tag, roi, inputs);
|
||||
auto age = outputs.at("age_conv3");
|
||||
auto gender = outputs.at("prob");
|
||||
return cv::GComputation{cv::GIn(in, roi), cv::GOut(age, gender)};
|
||||
}
|
||||
};
|
||||
|
||||
struct AGNetListGenComp : AGNetGenParams {
|
||||
static cv::GComputation create() {
|
||||
cv::GMat in;
|
||||
cv::GArray<cv::Rect> rois;
|
||||
GInferInputs inputs;
|
||||
inputs["data"] = in;
|
||||
auto outputs = cv::gapi::infer<cv::gapi::Generic>(tag, rois, inputs);
|
||||
auto age = outputs.at("age_conv3");
|
||||
auto gender = outputs.at("prob");
|
||||
return cv::GComputation{cv::GIn(in, rois), cv::GOut(age, gender)};
|
||||
}
|
||||
};
|
||||
|
||||
struct AGNetList2GenComp : AGNetGenParams {
|
||||
static cv::GComputation create() {
|
||||
cv::GMat in;
|
||||
cv::GArray<cv::Rect> rois;
|
||||
GInferListInputs list;
|
||||
list["data"] = rois;
|
||||
auto outputs = cv::gapi::infer2<cv::gapi::Generic>(tag, in, list);
|
||||
auto age = outputs.at("age_conv3");
|
||||
auto gender = outputs.at("prob");
|
||||
return cv::GComputation{cv::GIn(in, rois), cv::GOut(age, gender)};
|
||||
}
|
||||
};
|
||||
|
||||
class AGNetOVCompiled {
|
||||
public:
|
||||
AGNetOVCompiled(ov::CompiledModel &&compiled_model)
|
||||
: m_compiled_model(std::move(compiled_model)) {
|
||||
: m_compiled_model(std::move(compiled_model)),
|
||||
m_infer_request(m_compiled_model.create_infer_request()) {
|
||||
}
|
||||
|
||||
void operator()(const cv::Mat &in_mat,
|
||||
const cv::Rect &roi,
|
||||
cv::Mat &age_mat,
|
||||
cv::Mat &gender_mat) {
|
||||
// FIXME: W & H could be extracted from model shape
|
||||
// but it's anyway used only for Age Gender model.
|
||||
// (Well won't work in case of reshape)
|
||||
const int W = 62;
|
||||
const int H = 62;
|
||||
cv::Mat resized_roi;
|
||||
cv::resize(in_mat(roi), resized_roi, cv::Size(W, H));
|
||||
(*this)(resized_roi, age_mat, gender_mat);
|
||||
}
|
||||
|
||||
void operator()(const cv::Mat &in_mat,
|
||||
const std::vector<cv::Rect> &rois,
|
||||
std::vector<cv::Mat> &age_mats,
|
||||
std::vector<cv::Mat> &gender_mats) {
|
||||
for (size_t i = 0; i < rois.size(); ++i) {
|
||||
(*this)(in_mat, rois[i], age_mats[i], gender_mats[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(const cv::Mat &in_mat,
|
||||
cv::Mat &age_mat,
|
||||
cv::Mat &gender_mat) {
|
||||
auto infer_request = m_compiled_model.create_infer_request();
|
||||
auto input_tensor = infer_request.get_input_tensor();
|
||||
copyToOV(in_mat, input_tensor);
|
||||
auto input_tensor = m_infer_request.get_input_tensor();
|
||||
cv::gapi::ov::util::to_ov(in_mat, input_tensor);
|
||||
|
||||
infer_request.infer();
|
||||
m_infer_request.infer();
|
||||
|
||||
auto age_tensor = infer_request.get_tensor("age_conv3");
|
||||
auto age_tensor = m_infer_request.get_tensor("age_conv3");
|
||||
age_mat.create(cv::gapi::ov::util::to_ocv(age_tensor.get_shape()),
|
||||
cv::gapi::ov::util::to_ocv(age_tensor.get_element_type()));
|
||||
copyFromOV(age_tensor, age_mat);
|
||||
cv::gapi::ov::util::to_ocv(age_tensor, age_mat);
|
||||
|
||||
auto gender_tensor = infer_request.get_tensor("prob");
|
||||
auto gender_tensor = m_infer_request.get_tensor("prob");
|
||||
gender_mat.create(cv::gapi::ov::util::to_ocv(gender_tensor.get_shape()),
|
||||
cv::gapi::ov::util::to_ocv(gender_tensor.get_element_type()));
|
||||
copyFromOV(gender_tensor, gender_mat);
|
||||
cv::gapi::ov::util::to_ocv(gender_tensor, gender_mat);
|
||||
}
|
||||
|
||||
void export_model(const std::string &outpath) {
|
||||
@@ -155,6 +202,7 @@ public:
|
||||
|
||||
private:
|
||||
ov::CompiledModel m_compiled_model;
|
||||
ov::InferRequest m_infer_request;
|
||||
};
|
||||
|
||||
struct ImageInputPreproc {
|
||||
@@ -175,7 +223,8 @@ public:
|
||||
const std::string &bin_path,
|
||||
const std::string &device)
|
||||
: m_device(device) {
|
||||
m_model = getCore().read_model(xml_path, bin_path);
|
||||
m_model = cv::gapi::ov::wrap::getCore()
|
||||
.read_model(xml_path, bin_path);
|
||||
}
|
||||
|
||||
using PrePostProcessF = std::function<void(ov::preprocess::PrePostProcessor&)>;
|
||||
@@ -187,7 +236,8 @@ public:
|
||||
}
|
||||
|
||||
AGNetOVCompiled compile() {
|
||||
auto compiled_model = getCore().compile_model(m_model, m_device);
|
||||
auto compiled_model = cv::gapi::ov::wrap::getCore()
|
||||
.compile_model(m_model, m_device);
|
||||
return {std::move(compiled_model)};
|
||||
}
|
||||
|
||||
@@ -202,19 +252,78 @@ private:
|
||||
std::shared_ptr<ov::Model> m_model;
|
||||
};
|
||||
|
||||
struct BaseAgeGenderOV: public ::testing::Test {
|
||||
BaseAgeGenderOV() {
|
||||
initDLDTDataPath();
|
||||
xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
device = "CPU";
|
||||
blob_path = "age-gender-recognition-retail-0013.blob";
|
||||
}
|
||||
|
||||
cv::Mat getRandomImage(const cv::Size &sz) {
|
||||
cv::Mat image(sz, CV_8UC3);
|
||||
cv::randu(image, 0, 255);
|
||||
return image;
|
||||
}
|
||||
|
||||
cv::Mat getRandomTensor(const std::vector<int> &dims,
|
||||
const int depth) {
|
||||
cv::Mat tensor(dims, depth);
|
||||
cv::randu(tensor, -1, 1);
|
||||
return tensor;
|
||||
}
|
||||
|
||||
std::string xml_path;
|
||||
std::string bin_path;
|
||||
std::string blob_path;
|
||||
std::string device;
|
||||
|
||||
};
|
||||
|
||||
struct TestAgeGenderOV : public BaseAgeGenderOV {
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
|
||||
void validate() {
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
}
|
||||
};
|
||||
|
||||
struct TestAgeGenderListOV : public BaseAgeGenderOV {
|
||||
std::vector<cv::Mat> ov_age, ov_gender,
|
||||
gapi_age, gapi_gender;
|
||||
|
||||
std::vector<cv::Rect> roi_list = {
|
||||
cv::Rect(cv::Point{64, 60}, cv::Size{ 96, 96}),
|
||||
cv::Rect(cv::Point{50, 32}, cv::Size{128, 160}),
|
||||
};
|
||||
|
||||
TestAgeGenderListOV() {
|
||||
ov_age.resize(roi_list.size());
|
||||
ov_gender.resize(roi_list.size());
|
||||
gapi_age.resize(roi_list.size());
|
||||
gapi_gender.resize(roi_list.size());
|
||||
}
|
||||
|
||||
void validate() {
|
||||
ASSERT_EQ(ov_age.size(), ov_gender.size());
|
||||
|
||||
ASSERT_EQ(ov_age.size(), gapi_age.size());
|
||||
ASSERT_EQ(ov_gender.size(), gapi_gender.size());
|
||||
|
||||
for (size_t i = 0; i < ov_age.size(); ++i) {
|
||||
normAssert(ov_age[i], gapi_age[i], "Test age output");
|
||||
normAssert(ov_gender[i], gapi_gender[i], "Test gender output");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// TODO: Make all of tests below parmetrized to avoid code duplication
|
||||
TEST(TestAgeGenderOV, InferTypedTensor) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string device = "CPU";
|
||||
|
||||
cv::Mat in_mat({1, 3, 62, 62}, CV_32F);
|
||||
cv::randu(in_mat, -1, 1);
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
|
||||
TEST_F(TestAgeGenderOV, Infer_Tensor) {
|
||||
const auto in_mat = getRandomTensor({1, 3, 62, 62}, CV_32F);
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
ref.apply(in_mat, ov_age, ov_gender);
|
||||
@@ -226,19 +335,11 @@ TEST(TestAgeGenderOV, InferTypedTensor) {
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, InferTypedImage) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string device = "CPU";
|
||||
|
||||
cv::Mat in_mat(300, 300, CV_8UC3);
|
||||
cv::randu(in_mat, 0, 255);
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
TEST_F(TestAgeGenderOV, Infer_Image) {
|
||||
const auto in_mat = getRandomImage({300, 300});
|
||||
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
@@ -252,19 +353,11 @@ TEST(TestAgeGenderOV, InferTypedImage) {
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, InferGenericTensor) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string device = "CPU";
|
||||
|
||||
cv::Mat in_mat({1, 3, 62, 62}, CV_32F);
|
||||
cv::randu(in_mat, -1, 1);
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
TEST_F(TestAgeGenderOV, InferGeneric_Tensor) {
|
||||
const auto in_mat = getRandomTensor({1, 3, 62, 62}, CV_32F);
|
||||
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
@@ -277,19 +370,11 @@ TEST(TestAgeGenderOV, InferGenericTensor) {
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, InferGenericImage) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string device = "CPU";
|
||||
|
||||
cv::Mat in_mat(300, 300, CV_8UC3);
|
||||
cv::randu(in_mat, 0, 255);
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
TEST_F(TestAgeGenderOV, InferGenericImage) {
|
||||
const auto in_mat = getRandomImage({300, 300});
|
||||
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
@@ -303,20 +388,11 @@ TEST(TestAgeGenderOV, InferGenericImage) {
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, InferGenericImageBlob) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string blob_path = "age-gender-recognition-retail-0013.blob";
|
||||
const std::string device = "CPU";
|
||||
|
||||
cv::Mat in_mat(300, 300, CV_8UC3);
|
||||
cv::randu(in_mat, 0, 255);
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
TEST_F(TestAgeGenderOV, InferGeneric_ImageBlob) {
|
||||
const auto in_mat = getRandomImage({300, 300});
|
||||
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
@@ -333,20 +409,11 @@ TEST(TestAgeGenderOV, InferGenericImageBlob) {
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, InferGenericTensorBlob) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string blob_path = "age-gender-recognition-retail-0013.blob";
|
||||
const std::string device = "CPU";
|
||||
|
||||
cv::Mat in_mat({1, 3, 62, 62}, CV_32F);
|
||||
cv::randu(in_mat, -1, 1);
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
TEST_F(TestAgeGenderOV, InferGeneric_TensorBlob) {
|
||||
const auto in_mat = getRandomTensor({1, 3, 62, 62}, CV_32F);
|
||||
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
@@ -361,19 +428,11 @@ TEST(TestAgeGenderOV, InferGenericTensorBlob) {
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, InferBothOutputsFP16) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string device = "CPU";
|
||||
|
||||
cv::Mat in_mat({1, 3, 62, 62}, CV_32F);
|
||||
cv::randu(in_mat, -1, 1);
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
TEST_F(TestAgeGenderOV, InferGeneric_BothOutputsFP16) {
|
||||
const auto in_mat = getRandomTensor({1, 3, 62, 62}, CV_32F);
|
||||
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
@@ -392,19 +451,11 @@ TEST(TestAgeGenderOV, InferBothOutputsFP16) {
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, InferOneOutputFP16) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string device = "CPU";
|
||||
|
||||
cv::Mat in_mat({1, 3, 62, 62}, CV_32F);
|
||||
cv::randu(in_mat, -1, 1);
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
TEST_F(TestAgeGenderOV, InferGeneric_OneOutputFP16) {
|
||||
const auto in_mat = getRandomTensor({1, 3, 62, 62}, CV_32F);
|
||||
|
||||
// OpenVINO
|
||||
const std::string fp16_output_name = "prob";
|
||||
@@ -423,17 +474,10 @@ TEST(TestAgeGenderOV, InferOneOutputFP16) {
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, ThrowCfgOutputPrecForBlob) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string blob_path = "age-gender-recognition-retail-0013.blob";
|
||||
const std::string device = "CPU";
|
||||
|
||||
TEST_F(TestAgeGenderOV, InferGeneric_ThrowCfgOutputPrecForBlob) {
|
||||
// OpenVINO (Just for blob compilation)
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
auto cc_ref = ref.compile();
|
||||
@@ -446,12 +490,7 @@ TEST(TestAgeGenderOV, ThrowCfgOutputPrecForBlob) {
|
||||
EXPECT_ANY_THROW(pp.cfgOutputTensorPrecision(CV_16F));
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, ThrowInvalidConfigIR) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string device = "CPU";
|
||||
|
||||
TEST_F(TestAgeGenderOV, InferGeneric_ThrowInvalidConfigIR) {
|
||||
// G-API
|
||||
auto comp = AGNetGenComp::create();
|
||||
auto pp = AGNetGenComp::params(xml_path, bin_path, device);
|
||||
@@ -461,13 +500,7 @@ TEST(TestAgeGenderOV, ThrowInvalidConfigIR) {
|
||||
cv::compile_args(cv::gapi::networks(pp))));
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, ThrowInvalidConfigBlob) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string blob_path = "age-gender-recognition-retail-0013.blob";
|
||||
const std::string device = "CPU";
|
||||
|
||||
TEST_F(TestAgeGenderOV, InferGeneric_ThrowInvalidConfigBlob) {
|
||||
// OpenVINO (Just for blob compilation)
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
auto cc_ref = ref.compile();
|
||||
@@ -482,16 +515,8 @@ TEST(TestAgeGenderOV, ThrowInvalidConfigBlob) {
|
||||
cv::compile_args(cv::gapi::networks(pp))));
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, ThrowInvalidImageLayout) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string device = "CPU";
|
||||
|
||||
// NB: This mat may only have "NHWC" layout.
|
||||
cv::Mat in_mat(300, 300, CV_8UC3);
|
||||
cv::randu(in_mat, 0, 255);
|
||||
cv::Mat gender, gapi_age, gapi_gender;
|
||||
TEST_F(TestAgeGenderOV, Infer_ThrowInvalidImageLayout) {
|
||||
const auto in_mat = getRandomImage({300, 300});
|
||||
auto comp = AGNetTypedComp::create();
|
||||
auto pp = AGNetTypedComp::params(xml_path, bin_path, device);
|
||||
|
||||
@@ -501,15 +526,8 @@ TEST(TestAgeGenderOV, ThrowInvalidImageLayout) {
|
||||
cv::compile_args(cv::gapi::networks(pp))));
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, InferTensorWithPreproc) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string device = "CPU";
|
||||
|
||||
cv::Mat in_mat({1, 240, 320, 3}, CV_32F);
|
||||
cv::randu(in_mat, -1, 1);
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
TEST_F(TestAgeGenderOV, Infer_TensorWithPreproc) {
|
||||
const auto in_mat = getRandomTensor({1, 240, 320, 3}, CV_32F);
|
||||
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
@@ -531,8 +549,112 @@ TEST(TestAgeGenderOV, InferTensorWithPreproc) {
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST_F(TestAgeGenderOV, InferROIGeneric_Image) {
|
||||
const auto in_mat = getRandomImage({300, 300});
|
||||
cv::Rect roi(cv::Rect(cv::Point{64, 60}, cv::Size{96, 96}));
|
||||
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
ref.cfgPrePostProcessing([](ov::preprocess::PrePostProcessor &ppp) {
|
||||
ppp.input().tensor().set_element_type(ov::element::u8);
|
||||
ppp.input().tensor().set_layout("NHWC");
|
||||
});
|
||||
ref.compile()(in_mat, roi, ov_age, ov_gender);
|
||||
|
||||
// G-API
|
||||
auto comp = AGNetROIGenComp::create();
|
||||
auto pp = AGNetROIGenComp::params(xml_path, bin_path, device);
|
||||
|
||||
comp.apply(cv::gin(in_mat, roi), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST_F(TestAgeGenderOV, InferROIGeneric_ThrowIncorrectLayout) {
|
||||
const auto in_mat = getRandomImage({300, 300});
|
||||
cv::Rect roi(cv::Rect(cv::Point{64, 60}, cv::Size{96, 96}));
|
||||
|
||||
// G-API
|
||||
auto comp = AGNetROIGenComp::create();
|
||||
auto pp = AGNetROIGenComp::params(xml_path, bin_path, device);
|
||||
|
||||
pp.cfgInputTensorLayout("NCHW");
|
||||
EXPECT_ANY_THROW(comp.apply(cv::gin(in_mat, roi), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp))));
|
||||
}
|
||||
|
||||
TEST_F(TestAgeGenderOV, InferROIGeneric_ThrowTensorInput) {
|
||||
const auto in_mat = getRandomTensor({1, 3, 62, 62}, CV_32F);
|
||||
cv::Rect roi(cv::Rect(cv::Point{64, 60}, cv::Size{96, 96}));
|
||||
|
||||
// G-API
|
||||
auto comp = AGNetROIGenComp::create();
|
||||
auto pp = AGNetROIGenComp::params(xml_path, bin_path, device);
|
||||
|
||||
EXPECT_ANY_THROW(comp.apply(cv::gin(in_mat, roi), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp))));
|
||||
}
|
||||
|
||||
TEST_F(TestAgeGenderOV, InferROIGeneric_ThrowExplicitResize) {
|
||||
const auto in_mat = getRandomImage({300, 300});
|
||||
cv::Rect roi(cv::Rect(cv::Point{64, 60}, cv::Size{96, 96}));
|
||||
|
||||
// G-API
|
||||
auto comp = AGNetROIGenComp::create();
|
||||
auto pp = AGNetROIGenComp::params(xml_path, bin_path, device);
|
||||
|
||||
pp.cfgResize(cv::INTER_LINEAR);
|
||||
EXPECT_ANY_THROW(comp.apply(cv::gin(in_mat, roi), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp))));
|
||||
}
|
||||
|
||||
TEST_F(TestAgeGenderListOV, InferListGeneric_Image) {
|
||||
const auto in_mat = getRandomImage({300, 300});
|
||||
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
ref.cfgPrePostProcessing([](ov::preprocess::PrePostProcessor &ppp) {
|
||||
ppp.input().tensor().set_element_type(ov::element::u8);
|
||||
ppp.input().tensor().set_layout("NHWC");
|
||||
});
|
||||
ref.compile()(in_mat, roi_list, ov_age, ov_gender);
|
||||
|
||||
// G-API
|
||||
auto comp = AGNetListGenComp::create();
|
||||
auto pp = AGNetListGenComp::params(xml_path, bin_path, device);
|
||||
|
||||
comp.apply(cv::gin(in_mat, roi_list), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST_F(TestAgeGenderListOV, InferList2Generic_Image) {
|
||||
const auto in_mat = getRandomImage({300, 300});
|
||||
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
ref.cfgPrePostProcessing([](ov::preprocess::PrePostProcessor &ppp) {
|
||||
ppp.input().tensor().set_element_type(ov::element::u8);
|
||||
ppp.input().tensor().set_layout("NHWC");
|
||||
});
|
||||
ref.compile()(in_mat, roi_list, ov_age, ov_gender);
|
||||
|
||||
// G-API
|
||||
auto comp = AGNetList2GenComp::create();
|
||||
auto pp = AGNetList2GenComp::params(xml_path, bin_path, device);
|
||||
|
||||
comp.apply(cv::gin(in_mat, roi_list), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
validate();
|
||||
}
|
||||
|
||||
} // namespace opencv_test
|
||||
|
||||
@@ -30,7 +30,8 @@ namespace
|
||||
, nullptr
|
||||
, { GShape::GMAT }
|
||||
, { D::OpaqueKind::CV_UNKNOWN }
|
||||
, { cv::detail::HostCtor{cv::util::monostate{}} }
|
||||
, { D::HostCtor{cv::util::monostate{}} }
|
||||
, { D::OpaqueKind::CV_UNKNOWN }
|
||||
}).pass(m).yield(0);
|
||||
}
|
||||
|
||||
@@ -41,7 +42,8 @@ namespace
|
||||
, nullptr
|
||||
, { GShape::GMAT }
|
||||
, { D::OpaqueKind::CV_UNKNOWN, D::OpaqueKind::CV_UNKNOWN }
|
||||
, { cv::detail::HostCtor{cv::util::monostate{}} }
|
||||
, { D::HostCtor{cv::util::monostate{}} }
|
||||
, { D::OpaqueKind::CV_UNKNOWN}
|
||||
}).pass(m1, m2).yield(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -1055,7 +1055,7 @@ void cv_wl_keyboard::handle_kb_keymap(void *data, struct wl_keyboard *kb, uint32
|
||||
} catch (std::exception &e) {
|
||||
if (keyboard->xkb_.keymap)
|
||||
xkb_keymap_unref(keyboard->xkb_.keymap);
|
||||
std::cerr << "OpenCV Error: " << e.what() << std::endl;
|
||||
CV_LOG_ERROR(NULL, "OpenCV Error: " << e.what());
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
@@ -95,11 +95,11 @@ enum ImwriteFlags {
|
||||
IMWRITE_PNG_STRATEGY = 17, //!< One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_RLE.
|
||||
IMWRITE_PNG_BILEVEL = 18, //!< Binary level PNG, 0 or 1, default is 0.
|
||||
IMWRITE_PXM_BINARY = 32, //!< For PPM, PGM, or PBM, it can be a binary format flag, 0 or 1. Default value is 1.
|
||||
IMWRITE_EXR_TYPE = (3 << 4) + 0, /* 48 */ //!< override EXR storage type (FLOAT (FP32) is default)
|
||||
IMWRITE_EXR_COMPRESSION = (3 << 4) + 1, /* 49 */ //!< override EXR compression type (ZIP_COMPRESSION = 3 is default)
|
||||
IMWRITE_EXR_DWA_COMPRESSION_LEVEL = (3 << 4) + 2, /* 50 */ //!< override EXR DWA compression level (45 is default)
|
||||
IMWRITE_EXR_TYPE = (3 << 4) + 0 /* 48 */, //!< override EXR storage type (FLOAT (FP32) is default)
|
||||
IMWRITE_EXR_COMPRESSION = (3 << 4) + 1 /* 49 */, //!< override EXR compression type (ZIP_COMPRESSION = 3 is default)
|
||||
IMWRITE_EXR_DWA_COMPRESSION_LEVEL = (3 << 4) + 2 /* 50 */, //!< override EXR DWA compression level (45 is default)
|
||||
IMWRITE_WEBP_QUALITY = 64, //!< For WEBP, it can be a quality from 1 to 100 (the higher is the better). By default (without any parameter) and for quality above 100 the lossless compression is used.
|
||||
IMWRITE_HDR_COMPRESSION = (5 << 4) + 0, /* 80 */ //!< specify HDR compression
|
||||
IMWRITE_HDR_COMPRESSION = (5 << 4) + 0 /* 80 */, //!< specify HDR compression
|
||||
IMWRITE_PAM_TUPLETYPE = 128,//!< For PAM, sets the TUPLETYPE field to the corresponding string value that is defined for the format
|
||||
IMWRITE_TIFF_RESUNIT = 256,//!< For TIFF, use to specify which DPI resolution unit to set; see libtiff documentation for valid values
|
||||
IMWRITE_TIFF_XDPI = 257,//!< For TIFF, use to specify the X direction DPI
|
||||
|
||||
@@ -148,11 +148,14 @@ AvifDecoder::~AvifDecoder() {
|
||||
size_t AvifDecoder::signatureLength() const { return kAvifSignatureSize; }
|
||||
|
||||
bool AvifDecoder::checkSignature(const String &signature) const {
|
||||
avifDecoderSetIOMemory(decoder_,
|
||||
avifDecoder *decoder = avifDecoderCreate();
|
||||
if (!decoder) return false;
|
||||
avifDecoderSetIOMemory(decoder,
|
||||
reinterpret_cast<const uint8_t *>(signature.c_str()),
|
||||
signature.size());
|
||||
decoder_->io->sizeHint = 1e9;
|
||||
const avifResult status = avifDecoderParse(decoder_);
|
||||
decoder->io->sizeHint = 1e9;
|
||||
const avifResult status = avifDecoderParse(decoder);
|
||||
avifDecoderDestroy(decoder);
|
||||
return (status == AVIF_RESULT_OK || status == AVIF_RESULT_TRUNCATED_DATA);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
#include "precomp.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "grfmt_pxm.hpp"
|
||||
#include <iostream>
|
||||
#include <opencv2/core/utils/logger.hpp>
|
||||
|
||||
#ifdef HAVE_IMGCODEC_PXM
|
||||
|
||||
@@ -191,7 +191,7 @@ bool PxMDecoder::readHeader()
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "PXM::readHeader(): unknown C++ exception" << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "PXM::readHeader(): unknown C++ exception");
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -364,7 +364,7 @@ bool PxMDecoder::readData( Mat& img )
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "PXM::readData(): unknown exception" << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "PXM::readData(): unknown exception");
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
@@ -437,12 +437,12 @@ imread_( const String& filename, int flags, Mat& mat )
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
std::cerr << "imread_('" << filename << "'): can't read header: " << e.what() << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imread_('" << filename << "'): can't read header: " << e.what());
|
||||
return 0;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "imread_('" << filename << "'): can't read header: unknown exception" << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imread_('" << filename << "'): can't read header: unknown exception");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -475,11 +475,11 @@ imread_( const String& filename, int flags, Mat& mat )
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
std::cerr << "imread_('" << filename << "'): can't read data: " << e.what() << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imread_('" << filename << "'): can't read data: " << e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "imread_('" << filename << "'): can't read data: unknown exception" << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imread_('" << filename << "'): can't read data: unknown exception");
|
||||
}
|
||||
if (!success)
|
||||
{
|
||||
@@ -542,12 +542,12 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats, int star
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
std::cerr << "imreadmulti_('" << filename << "'): can't read header: " << e.what() << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imreadmulti_('" << filename << "'): can't read header: " << e.what());
|
||||
return 0;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "imreadmulti_('" << filename << "'): can't read header: unknown exception" << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imreadmulti_('" << filename << "'): can't read header: unknown exception");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -591,11 +591,11 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats, int star
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
std::cerr << "imreadmulti_('" << filename << "'): can't read data: " << e.what() << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imreadmulti_('" << filename << "'): can't read data: " << e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "imreadmulti_('" << filename << "'): can't read data: unknown exception" << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imreadmulti_('" << filename << "'): can't read data: unknown exception");
|
||||
}
|
||||
if (!success)
|
||||
break;
|
||||
@@ -672,7 +672,7 @@ size_t imcount_(const String& filename, int flags)
|
||||
return collection.size();
|
||||
} catch(cv::Exception const& e) {
|
||||
// Reading header or finding decoder for the filename is failed
|
||||
std::cerr << "imcount_('" << filename << "'): can't read header or can't find decoder: " << e.what() << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imcount_('" << filename << "'): can't read header or can't find decoder: " << e.what());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -750,14 +750,13 @@ static bool imwrite_( const String& filename, const std::vector<Mat>& img_vec,
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
std::cerr << "imwrite_('" << filename << "'): can't write data: " << e.what() << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imwrite_('" << filename << "'): can't write data: " << e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "imwrite_('" << filename << "'): can't write data: unknown exception" << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imwrite_('" << filename << "'): can't write data: unknown exception");
|
||||
}
|
||||
|
||||
// CV_Assert( code );
|
||||
return code;
|
||||
}
|
||||
|
||||
@@ -833,11 +832,11 @@ imdecode_( const Mat& buf, int flags, Mat& mat )
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
std::cerr << "imdecode_('" << filename << "'): can't read header: " << e.what() << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imdecode_('" << filename << "'): can't read header: " << e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "imdecode_('" << filename << "'): can't read header: unknown exception" << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imdecode_('" << filename << "'): can't read header: unknown exception");
|
||||
}
|
||||
if (!success)
|
||||
{
|
||||
@@ -846,7 +845,7 @@ imdecode_( const Mat& buf, int flags, Mat& mat )
|
||||
{
|
||||
if (0 != remove(filename.c_str()))
|
||||
{
|
||||
std::cerr << "unable to remove temporary file:" << filename << std::endl << std::flush;
|
||||
CV_LOG_WARNING(NULL, "unable to remove temporary file:" << filename);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -878,18 +877,18 @@ imdecode_( const Mat& buf, int flags, Mat& mat )
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
std::cerr << "imdecode_('" << filename << "'): can't read data: " << e.what() << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imdecode_('" << filename << "'): can't read data: " << e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "imdecode_('" << filename << "'): can't read data: unknown exception" << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imdecode_('" << filename << "'): can't read data: unknown exception");
|
||||
}
|
||||
|
||||
if (!filename.empty())
|
||||
{
|
||||
if (0 != remove(filename.c_str()))
|
||||
{
|
||||
std::cerr << "unable to remove temporary file:" << filename << std::endl << std::flush;
|
||||
CV_LOG_WARNING(NULL, "unable to remove temporary file: " << filename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -982,11 +981,11 @@ imdecodemulti_(const Mat& buf, int flags, std::vector<Mat>& mats, int start, int
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
std::cerr << "imreadmulti_('" << filename << "'): can't read header: " << e.what() << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imreadmulti_('" << filename << "'): can't read header: " << e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "imreadmulti_('" << filename << "'): can't read header: unknown exception" << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imreadmulti_('" << filename << "'): can't read header: unknown exception");
|
||||
}
|
||||
|
||||
int current = start;
|
||||
@@ -1007,7 +1006,7 @@ imdecodemulti_(const Mat& buf, int flags, std::vector<Mat>& mats, int start, int
|
||||
{
|
||||
if (0 != remove(filename.c_str()))
|
||||
{
|
||||
std::cerr << "unable to remove temporary file:" << filename << std::endl << std::flush;
|
||||
CV_LOG_WARNING(NULL, "unable to remove temporary file: " << filename);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -1042,11 +1041,11 @@ imdecodemulti_(const Mat& buf, int flags, std::vector<Mat>& mats, int start, int
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
std::cerr << "imreadmulti_('" << filename << "'): can't read data: " << e.what() << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imreadmulti_('" << filename << "'): can't read data: " << e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "imreadmulti_('" << filename << "'): can't read data: unknown exception" << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "imreadmulti_('" << filename << "'): can't read data: unknown exception");
|
||||
}
|
||||
if (!success)
|
||||
break;
|
||||
@@ -1069,7 +1068,7 @@ imdecodemulti_(const Mat& buf, int flags, std::vector<Mat>& mats, int start, int
|
||||
{
|
||||
if (0 != remove(filename.c_str()))
|
||||
{
|
||||
std::cerr << "unable to remove temporary file:" << filename << std::endl << std::flush;
|
||||
CV_LOG_WARNING(NULL, "unable to remove temporary file: " << filename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1280,10 +1279,10 @@ Mat ImageCollection::Impl::readData() {
|
||||
success = true;
|
||||
}
|
||||
catch (const cv::Exception &e) {
|
||||
std::cerr << "ImageCollection class: can't read data: " << e.what() << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "ImageCollection class: can't read data: " << e.what());
|
||||
}
|
||||
catch (...) {
|
||||
std::cerr << "ImageCollection class:: can't read data: unknown exception" << std::endl << std::flush;
|
||||
CV_LOG_ERROR(NULL, "ImageCollection class:: can't read data: unknown exception");
|
||||
}
|
||||
if (!success)
|
||||
return cv::Mat();
|
||||
|
||||
@@ -184,9 +184,9 @@ public:
|
||||
|
||||
for( ; bayer <= bayer_end - 18; bayer += 14, dst += 14 )
|
||||
{
|
||||
v_uint16x8 r0 = v_load((ushort*)bayer);
|
||||
v_uint16x8 r1 = v_load((ushort*)(bayer+bayer_step));
|
||||
v_uint16x8 r2 = v_load((ushort*)(bayer+bayer_step*2));
|
||||
v_uint16x8 r0 = v_reinterpret_as_u16(v_load(bayer));
|
||||
v_uint16x8 r1 = v_reinterpret_as_u16(v_load(bayer+bayer_step));
|
||||
v_uint16x8 r2 = v_reinterpret_as_u16(v_load(bayer+bayer_step*2));
|
||||
|
||||
v_uint16x8 b1 = ((r0 << 8) >> 7) + ((r2 << 8) >> 7);
|
||||
v_uint16x8 b0 = v_rotate_right<1>(b1) + b1;
|
||||
@@ -265,9 +265,9 @@ public:
|
||||
|
||||
for( ; bayer <= bayer_end - 18; bayer += 14, dst += 42 )
|
||||
{
|
||||
v_uint16x8 r0 = v_load((ushort*)bayer);
|
||||
v_uint16x8 r1 = v_load((ushort*)(bayer+bayer_step));
|
||||
v_uint16x8 r2 = v_load((ushort*)(bayer+bayer_step*2));
|
||||
v_uint16x8 r0 = v_reinterpret_as_u16(v_load(bayer));
|
||||
v_uint16x8 r1 = v_reinterpret_as_u16(v_load(bayer+bayer_step));
|
||||
v_uint16x8 r2 = v_reinterpret_as_u16(v_load(bayer+bayer_step*2));
|
||||
|
||||
v_uint16x8 b1 = (r0 & masklo) + (r2 & masklo);
|
||||
v_uint16x8 nextb1 = v_rotate_right<1>(b1);
|
||||
@@ -398,9 +398,9 @@ public:
|
||||
|
||||
for( ; bayer <= bayer_end - 18; bayer += 14, dst += 56 )
|
||||
{
|
||||
v_uint16x8 r0 = v_load((ushort*)bayer);
|
||||
v_uint16x8 r1 = v_load((ushort*)(bayer+bayer_step));
|
||||
v_uint16x8 r2 = v_load((ushort*)(bayer+bayer_step*2));
|
||||
v_uint16x8 r0 = v_reinterpret_as_u16(v_load(bayer));
|
||||
v_uint16x8 r1 = v_reinterpret_as_u16(v_load(bayer+bayer_step));
|
||||
v_uint16x8 r2 = v_reinterpret_as_u16(v_load(bayer+bayer_step*2));
|
||||
|
||||
v_uint16x8 b1 = (r0 & masklo) + (r2 & masklo);
|
||||
v_uint16x8 nextb1 = v_rotate_right<1>(b1);
|
||||
@@ -494,9 +494,9 @@ public:
|
||||
B G B G | B G B G | B G B G | B G B G
|
||||
*/
|
||||
|
||||
v_uint16x8 r0 = v_load((ushort*)bayer);
|
||||
v_uint16x8 r1 = v_load((ushort*)(bayer+bayer_step));
|
||||
v_uint16x8 r2 = v_load((ushort*)(bayer+bayer_step*2));
|
||||
v_uint16x8 r0 = v_reinterpret_as_u16(v_load(bayer));
|
||||
v_uint16x8 r1 = v_reinterpret_as_u16(v_load(bayer+bayer_step));
|
||||
v_uint16x8 r2 = v_reinterpret_as_u16(v_load(bayer+bayer_step*2));
|
||||
|
||||
v_uint16x8 b1 = (r0 & masklow) + (r2 & masklow);
|
||||
v_uint16x8 nextb1 = v_rotate_right<1>(b1);
|
||||
|
||||
@@ -448,7 +448,7 @@ static void getDistanceTransformMask( int maskType, float *metrics )
|
||||
|
||||
struct DTColumnInvoker : ParallelLoopBody
|
||||
{
|
||||
DTColumnInvoker( const Mat* _src, Mat* _dst, const int* _sat_tab, const float* _sqr_tab)
|
||||
DTColumnInvoker( const Mat* _src, Mat* _dst, const int* _sat_tab, const int* _sqr_tab)
|
||||
{
|
||||
src = _src;
|
||||
dst = _dst;
|
||||
@@ -481,7 +481,7 @@ struct DTColumnInvoker : ParallelLoopBody
|
||||
{
|
||||
dist = dist + 1 - sat_tab[dist - d[j]];
|
||||
d[j] = dist;
|
||||
dptr[0] = sqr_tab[dist];
|
||||
dptr[0] = (float)sqr_tab[dist];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -489,12 +489,12 @@ struct DTColumnInvoker : ParallelLoopBody
|
||||
const Mat* src;
|
||||
Mat* dst;
|
||||
const int* sat_tab;
|
||||
const float* sqr_tab;
|
||||
const int* sqr_tab;
|
||||
};
|
||||
|
||||
struct DTRowInvoker : ParallelLoopBody
|
||||
{
|
||||
DTRowInvoker( Mat* _dst, const float* _sqr_tab, const float* _inv_tab )
|
||||
DTRowInvoker( Mat* _dst, const int* _sqr_tab, const float* _inv_tab )
|
||||
{
|
||||
dst = _dst;
|
||||
sqr_tab = _sqr_tab;
|
||||
@@ -529,7 +529,7 @@ struct DTRowInvoker : ParallelLoopBody
|
||||
for(;;k--)
|
||||
{
|
||||
p = v[k];
|
||||
float s = (fq + sqr_tab[q] - d[p] - sqr_tab[p])*inv_tab[q - p];
|
||||
float s = (fq - d[p] + (sqr_tab[q]-sqr_tab[p]))*inv_tab[q - p];
|
||||
if( s > z[k] )
|
||||
{
|
||||
k++;
|
||||
@@ -552,28 +552,28 @@ struct DTRowInvoker : ParallelLoopBody
|
||||
}
|
||||
|
||||
Mat* dst;
|
||||
const float* sqr_tab;
|
||||
const int* sqr_tab;
|
||||
const float* inv_tab;
|
||||
};
|
||||
|
||||
static void
|
||||
trueDistTrans( const Mat& src, Mat& dst )
|
||||
{
|
||||
const float inf = 1e15f;
|
||||
const int inf = INT_MAX;
|
||||
|
||||
CV_Assert( src.size() == dst.size() );
|
||||
|
||||
CV_Assert( src.type() == CV_8UC1 && dst.type() == CV_32FC1 );
|
||||
int i, m = src.rows, n = src.cols;
|
||||
|
||||
cv::AutoBuffer<uchar> _buf(std::max(m*2*sizeof(float) + (m*3+1)*sizeof(int), n*2*sizeof(float)));
|
||||
cv::AutoBuffer<uchar> _buf(std::max(m*2*sizeof(int) + (m*3+1)*sizeof(int), n*2*sizeof(float)));
|
||||
// stage 1: compute 1d distance transform of each column
|
||||
float* sqr_tab = (float*)_buf.data();
|
||||
int* sqr_tab = (int*)_buf.data();
|
||||
int* sat_tab = cv::alignPtr((int*)(sqr_tab + m*2), sizeof(int));
|
||||
int shift = m*2;
|
||||
|
||||
for( i = 0; i < m; i++ )
|
||||
sqr_tab[i] = (float)(i*i);
|
||||
sqr_tab[i] = i*i;
|
||||
for( i = m; i < m*2; i++ )
|
||||
sqr_tab[i] = inf;
|
||||
for( i = 0; i < shift; i++ )
|
||||
@@ -584,13 +584,14 @@ trueDistTrans( const Mat& src, Mat& dst )
|
||||
cv::parallel_for_(cv::Range(0, n), cv::DTColumnInvoker(&src, &dst, sat_tab, sqr_tab), src.total()/(double)(1<<16));
|
||||
|
||||
// stage 2: compute modified distance transform for each row
|
||||
float* inv_tab = sqr_tab + n;
|
||||
float* inv_tab = (float*)sqr_tab + n;
|
||||
|
||||
inv_tab[0] = sqr_tab[0] = 0.f;
|
||||
inv_tab[0] = 0.f;
|
||||
sqr_tab[0] = 0;
|
||||
for( i = 1; i < n; i++ )
|
||||
{
|
||||
inv_tab[i] = (float)(0.5/i);
|
||||
sqr_tab[i] = (float)(i*i);
|
||||
sqr_tab[i] = i*i;
|
||||
}
|
||||
|
||||
cv::parallel_for_(cv::Range(0, m), cv::DTRowInvoker(&dst, sqr_tab, inv_tab));
|
||||
@@ -750,7 +751,9 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
|
||||
CV_IPP_CHECK()
|
||||
{
|
||||
#if IPP_DISABLE_PERF_TRUE_DIST_MT
|
||||
if(cv::getNumThreads()<=1 || (src.total()<(int)(1<<14)))
|
||||
// IPP uses floats, but 4097 cannot be squared into a float
|
||||
if((cv::getNumThreads()<=1 || (src.total()<(int)(1<<14))) &&
|
||||
src.rows < 4097 && src.cols < 4097)
|
||||
#endif
|
||||
{
|
||||
IppStatus status;
|
||||
|
||||
Executable → Regular
+8
-7
@@ -939,6 +939,7 @@ void ellipse2Poly( Point center, Size axes, int angle,
|
||||
}
|
||||
|
||||
// If there are no points, it's a zero-size polygon
|
||||
CV_Assert( !pts.empty() );
|
||||
if (pts.size() == 1) {
|
||||
pts.assign(2, center);
|
||||
}
|
||||
@@ -1001,6 +1002,7 @@ void ellipse2Poly( Point2d center, Size2d axes, int angle,
|
||||
}
|
||||
|
||||
// If there are no points, it's a zero-size polygon
|
||||
CV_Assert( !pts.empty() );
|
||||
if( pts.size() == 1) {
|
||||
pts.assign(2,center);
|
||||
}
|
||||
@@ -1021,7 +1023,6 @@ EllipseEx( Mat& img, Point2l center, Size2l axes,
|
||||
|
||||
std::vector<Point2l> v;
|
||||
Point2l prevPt(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF);
|
||||
v.resize(0);
|
||||
for (unsigned int i = 0; i < _v.size(); ++i)
|
||||
{
|
||||
Point2l pt;
|
||||
@@ -1036,7 +1037,7 @@ EllipseEx( Mat& img, Point2l center, Size2l axes,
|
||||
}
|
||||
|
||||
// If there are no points, it's a zero-size polygon
|
||||
if (v.size() == 1) {
|
||||
if (v.size() <= 1) {
|
||||
v.assign(2, center);
|
||||
}
|
||||
|
||||
@@ -1556,7 +1557,7 @@ Circle( Mat& img, Point center, int radius, const void* color, int fill )
|
||||
ICV_HLINE( tptr1, x21, x22, color, pix_size );
|
||||
}
|
||||
}
|
||||
else if( x11 < size.width && x12 >= 0 && y21 < size.height && y22 >= 0 )
|
||||
else if( x11 < size.width && x12 >= 0 && y21 < size.height && y22 >= 0)
|
||||
{
|
||||
if( fill )
|
||||
{
|
||||
@@ -1564,7 +1565,7 @@ Circle( Mat& img, Point center, int radius, const void* color, int fill )
|
||||
x12 = MIN( x12, size.width - 1 );
|
||||
}
|
||||
|
||||
if( (unsigned)y11 < (unsigned)size.height )
|
||||
if( y11 >= 0 && y11 < size.height )
|
||||
{
|
||||
uchar *tptr = ptr + y11 * step;
|
||||
|
||||
@@ -1579,7 +1580,7 @@ Circle( Mat& img, Point center, int radius, const void* color, int fill )
|
||||
ICV_HLINE( tptr, x11, x12, color, pix_size );
|
||||
}
|
||||
|
||||
if( (unsigned)y12 < (unsigned)size.height )
|
||||
if( y12 >= 0 && y12 < size.height )
|
||||
{
|
||||
uchar *tptr = ptr + y12 * step;
|
||||
|
||||
@@ -1602,7 +1603,7 @@ Circle( Mat& img, Point center, int radius, const void* color, int fill )
|
||||
x22 = MIN( x22, size.width - 1 );
|
||||
}
|
||||
|
||||
if( (unsigned)y21 < (unsigned)size.height )
|
||||
if( y21 >= 0 && y21 < size.height )
|
||||
{
|
||||
uchar *tptr = ptr + y21 * step;
|
||||
|
||||
@@ -1617,7 +1618,7 @@ Circle( Mat& img, Point center, int radius, const void* color, int fill )
|
||||
ICV_HLINE( tptr, x21, x22, color, pix_size );
|
||||
}
|
||||
|
||||
if( (unsigned)y22 < (unsigned)size.height )
|
||||
if( y22 >= 0 && y22 < size.height )
|
||||
{
|
||||
uchar *tptr = ptr + y22 * step;
|
||||
|
||||
|
||||
@@ -560,8 +560,15 @@ int cv::floodFill( InputOutputArray _image, InputOutputArray _mask,
|
||||
if( depth == CV_8U )
|
||||
for( i = 0; i < cn; i++ )
|
||||
{
|
||||
#if defined(__GNUC__) && (__GNUC__ == 12)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstringop-overflow"
|
||||
#endif
|
||||
ld_buf.b[i] = saturate_cast<uchar>(cvFloor(loDiff[i]));
|
||||
ud_buf.b[i] = saturate_cast<uchar>(cvFloor(upDiff[i]));
|
||||
#if defined(__GNUC__) && (__GNUC__ == 12)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
else if( depth == CV_32S )
|
||||
for( i = 0; i < cn; i++ )
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user