Merge branch 4.x

pull/24070/head
Alexander Smorkalov 2 years ago
commit 47188b7c7e
  1. 4
      .github/ISSUE_TEMPLATE/bug_report.yml
  2. 2
      .github/ISSUE_TEMPLATE/documentation.yml
  3. 10
      3rdparty/ffmpeg/ffmpeg.cmake
  4. 2
      3rdparty/libtiff/tif_dirread.c
  5. 2
      3rdparty/openjpeg/openjp2/ht_dec.c
  6. 1
      3rdparty/protobuf/CMakeLists.txt
  7. 12
      CMakeLists.txt
  8. 5
      apps/createsamples/utility.cpp
  9. 15
      cmake/FindONNX.cmake
  10. 7
      cmake/OpenCVCompilerOptions.cmake
  11. 45
      cmake/OpenCVFindCANN.cmake
  12. 4
      cmake/OpenCVPackaging.cmake
  13. 8
      cmake/OpenCVUtils.cmake
  14. 12
      cmake/copy_files.cmake
  15. 8
      doc/opencv.bib
  16. 45
      doc/tutorials/app/orbbec_astra.markdown
  17. 2
      doc/tutorials/introduction/config_reference/config_reference.markdown
  18. 345
      doc/tutorials/introduction/env_reference/env_reference.markdown
  19. 1
      doc/tutorials/introduction/table_of_content_introduction.markdown
  20. 2
      modules/3d/src/usac/essential_solver.cpp
  21. 2
      modules/3d/src/usac/ransac_solvers.cpp
  22. 8
      modules/3d/src/usac/sampler.cpp
  23. 2
      modules/3d/src/usac/termination.cpp
  24. 4
      modules/3d/test/test_solvepnp_ransac.cpp
  25. 308
      modules/calib3d/src/usac/bundle.cpp
  26. 4
      modules/core/include/opencv2/core/cuda.hpp
  27. 8
      modules/core/include/opencv2/core/fast_math.hpp
  28. 9
      modules/core/include/opencv2/core/hal/intrin_rvv_scalable.hpp
  29. 25
      modules/core/include/opencv2/core/mat.hpp
  30. 2
      modules/core/include/opencv2/core/mat.inl.hpp
  31. 5
      modules/core/include/opencv2/core/optim.hpp
  32. 19
      modules/core/include/opencv2/core/types.hpp
  33. 3
      modules/core/misc/java/src/java/core+Mat.java
  34. 10
      modules/core/misc/python/package/mat_wrapper/__init__.py
  35. 36
      modules/core/src/channels.cpp
  36. 20
      modules/core/src/lpsolver.cpp
  37. 8
      modules/core/src/matrix_transform.cpp
  38. 66
      modules/core/src/mean.simd.hpp
  39. 1
      modules/core/src/ocl.cpp
  40. 2
      modules/core/src/parallel.cpp
  41. 6
      modules/core/src/system.cpp
  42. 5
      modules/core/src/types.cpp
  43. 2
      modules/core/test/test_intrin_utils.hpp
  44. 14
      modules/core/test/test_lpsolver.cpp
  45. 23
      modules/core/test/test_mat.cpp
  46. 1
      modules/dnn/include/opencv2/dnn/dnn.hpp
  47. 2
      modules/dnn/include/opencv2/dnn/version.hpp
  48. 3
      modules/dnn/perf/perf_convolution.cpp
  49. 14
      modules/dnn/src/layers/cpu_kernels/conv_block.simd.hpp
  50. 2
      modules/dnn/src/layers/cpu_kernels/convolution.cpp
  51. 119
      modules/dnn/src/layers/elementwise_layers.cpp
  52. 18
      modules/dnn/src/layers/max_unpooling_layer.cpp
  53. 4
      modules/dnn/src/net_cann.cpp
  54. 16
      modules/dnn/src/net_impl.cpp
  55. 2
      modules/dnn/src/onnx/onnx_graph_simplifier.cpp
  56. 6
      modules/dnn/src/op_cann.hpp
  57. 15
      modules/dnn/src/opencl/activations.cl
  58. 23
      modules/dnn/src/tensorflow/tf_importer.cpp
  59. 105
      modules/dnn/src/tflite/tflite_importer.cpp
  60. 8
      modules/dnn/test/test_tf_importer.cpp
  61. 20
      modules/dnn/test/test_tflite_importer.cpp
  62. 4
      modules/dnn/test/test_torch_importer.cpp
  63. 29
      modules/flann/include/opencv2/flann/any.h
  64. 2
      modules/flann/include/opencv2/flann/general.h
  65. 3
      modules/flann/include/opencv2/flann/matrix.h
  66. 18
      modules/flann/include/opencv2/flann/params.h
  67. 3
      modules/flann/include/opencv2/flann/result_set.h
  68. 100
      modules/flann/misc/python/pyopencv_flann.hpp
  69. 30
      modules/flann/misc/python/test/test_flann_based_matcher.py
  70. 5
      modules/gapi/CMakeLists.txt
  71. 7
      modules/gapi/include/opencv2/gapi/gkernel.hpp
  72. 3
      modules/gapi/include/opencv2/gapi/infer.hpp
  73. 9
      modules/gapi/include/opencv2/gapi/infer/bindings_onnx.hpp
  74. 180
      modules/gapi/include/opencv2/gapi/infer/onnx.hpp
  75. 1
      modules/gapi/include/opencv2/gapi/streaming/desync.hpp
  76. 1
      modules/gapi/include/opencv2/gapi/streaming/meta.hpp
  77. 9
      modules/gapi/include/opencv2/gapi/util/variant.hpp
  78. 2
      modules/gapi/misc/python/pyopencv_gapi.hpp
  79. 27
      modules/gapi/misc/python/python_bridge.hpp
  80. 41
      modules/gapi/misc/python/test/test_gapi_sample_pipelines.py
  81. 33
      modules/gapi/src/backends/ie/giebackend.cpp
  82. 18
      modules/gapi/src/backends/onnx/bindings_onnx.cpp
  83. 40
      modules/gapi/src/backends/onnx/dml_ep.cpp
  84. 23
      modules/gapi/src/backends/onnx/dml_ep.hpp
  85. 53
      modules/gapi/src/backends/onnx/gonnxbackend.cpp
  86. 822
      modules/gapi/src/backends/ov/govbackend.cpp
  87. 12
      modules/gapi/src/backends/ov/util.hpp
  88. 18
      modules/gapi/src/compiler/gmodelbuilder.cpp
  89. 133
      modules/gapi/test/infer/gapi_infer_ie_test.cpp
  90. 470
      modules/gapi/test/infer/gapi_infer_ov_tests.cpp
  91. 6
      modules/gapi/test/internal/gapi_int_gmodel_builder_test.cpp
  92. 2
      modules/highgui/src/window_wayland.cpp
  93. 8
      modules/imgcodecs/include/opencv2/imgcodecs.hpp
  94. 9
      modules/imgcodecs/src/grfmt_avif.cpp
  95. 6
      modules/imgcodecs/src/grfmt_pxm.cpp
  96. 51
      modules/imgcodecs/src/loadsave.cpp
  97. 24
      modules/imgproc/src/demosaicing.cpp
  98. 31
      modules/imgproc/src/distransform.cpp
  99. 15
      modules/imgproc/src/drawing.cpp
  100. 7
      modules/imgproc/src/floodfill.cpp
  101. Some files were not shown because too many files have changed in this diff Show More

@ -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.

@ -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)

@ -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;

@ -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);

@ -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)

@ -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*)&parameters["x_scale"];
float y_scale = *(float*)&parameters["y_scale"];
float w_scale = *(float*)&parameters["w_scale"];
float h_scale = *(float*)&parameters["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))
{
failmsg("Argument '%s' is not a dictionary", info.name);
return false;
}
PyObject* key_obj = NULL;
PyObject* value_obj = NULL;
Py_ssize_t key_pos = 0;
if(PyDict_Check(o)) {
while(PyDict_Next(o, &pos, &key, &item))
while(PyDict_Next(o, &key_pos, &key_obj, &value_obj))
{
// get key
std::string key;
if (!getUnicodeString(key_obj, key))
{
// get key
std::string k;
if (!getUnicodeString(key, k))
failmsg("Key at pos %lld is not a string", static_cast<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);
p.setAlgorithm(int_value);
}
else if( PyInt_Check(item) )
else
{
int value = (int)PyInt_AsLong(item);
if( strcmp(k.c_str(), "algorithm") == 0 )
p.setAlgorithm(value);
else
p.setInt(k, value);
p.setInt(key, int_value);
}
else if( PyFloat_Check(item) )
continue;
}
PyErr_Clear();
double flt_value = 0.0;
if (pyopencv_to(value_obj, flt_value, key_arg_info))
{
if (key == "eps")
{
double value = PyFloat_AsDouble(item);
p.setDouble(k, value);
p.setFloat(key, static_cast<float>(flt_value));
}
else
{
std::string val_str;
if (!getUnicodeString(item, val_str))
{
ok = false;
break;
}
p.setString(k, val_str);
p.setDouble(key, flt_value);
}
continue;
}
}
PyErr_Clear();
return ok && !PyErr_Occurred();
std::string str_value;
if (getUnicodeString(value_obj, str_value))
{
p.setString(key, str_value);
continue;
}
PyErr_Clear();
// All conversions are failed
failmsg("Failed to parse IndexParam with key '%s'. "
"Supported types: [bool, int, float, str]", key.c_str());
return false;
}
return true;
}
template<>

@ -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));
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);
auto& model = const_cast<std::shared_ptr<::ov::Model>&>(uu.model);
PrePostProcWrapper ppp {model, model_info,
uu.params.input_names, uu.params.output_names};
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 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);
}
}
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 &mm = std::get<1>(it);
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));
}
ppp.cfgLayouts(input_name);
ppp.cfgPreProcessing(input_name, mm);
ppp.cfgScaleMean(input_name);
}
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;
};
} // anonymous namespace
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";
}
// 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 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_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;

@ -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

Loading…
Cancel
Save