pull/3740/merge
Laurent Berger 1 month ago committed by GitHub
commit b9364c570c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 233
      modules/dnnlegacy/CMakeLists.txt
  2. 201
      modules/dnnlegacy/LICENSE
  3. 2
      modules/dnnlegacy/README.md
  4. 61
      modules/dnnlegacy/include/opencv2/dnnlegacy.hpp
  5. 137
      modules/dnnlegacy/include/opencv2/dnnlegacy/dnnlegacy.hpp
  6. 34120
      modules/dnnlegacy/misc/caffe/opencv-caffe.pb.cc
  7. 44945
      modules/dnnlegacy/misc/caffe/opencv-caffe.pb.h
  8. 619
      modules/dnnlegacy/src/caffe/caffe_importer.cpp
  9. 1254
      modules/dnnlegacy/src/caffe/caffe_io.cpp
  10. 129
      modules/dnnlegacy/src/caffe/caffe_io.hpp
  11. 77
      modules/dnnlegacy/src/caffe/caffe_shrinker.cpp
  12. 1649
      modules/dnnlegacy/src/caffe/opencv-caffe.proto
  13. 256
      modules/dnnlegacy/src/darknet/darknet_importer.cpp
  14. 1110
      modules/dnnlegacy/src/darknet/darknet_io.cpp
  15. 117
      modules/dnnlegacy/src/darknet/darknet_io.hpp
  16. 90
      modules/dnnlegacy/src/precomp.hpp
  17. 94
      modules/dnnlegacy/test/npy_blob.cpp
  18. 20
      modules/dnnlegacy/test/npy_blob.hpp
  19. 877
      modules/dnnlegacy/test/test_caffe_importer.cpp
  20. 6
      modules/dnnlegacy/test/test_common.cpp
  21. 246
      modules/dnnlegacy/test/test_common.hpp
  22. 540
      modules/dnnlegacy/test/test_common.impl.hpp
  23. 1157
      modules/dnnlegacy/test/test_darknet_importer.cpp
  24. 6
      modules/dnnlegacy/test/test_main.cpp
  25. 52
      modules/dnnlegacy/test/test_precomp.hpp

@ -0,0 +1,233 @@
if(WINRT)
ocv_module_disable(dnn)
endif()
set(the_description "Deep neural network legacy module. It allows to load models from frameworks caffe and darknet and to make forward pass using opencv5")
ocv_add_module(dnnlegacy opencv_core opencv_imgproc opencv_dnn WRAP python java objc js)
if(OPENCV_DNN_CUDA)
if(HAVE_CUDA AND HAVE_CUBLAS AND HAVE_CUDNN)
ocv_target_compile_definitions(${the_module} PRIVATE "CV_CUDA4DNN=1")
else()
if(NOT HAVE_CUDA)
message(SEND_ERROR "DNN: CUDA backend requires CUDA Toolkit. Please resolve dependency or disable OPENCV_DNN_CUDA=OFF")
elseif(NOT HAVE_CUBLAS)
message(SEND_ERROR "DNN: CUDA backend requires cuBLAS. Please resolve dependency or disable OPENCV_DNN_CUDA=OFF")
elseif(NOT HAVE_CUDNN)
message(SEND_ERROR "DNN: CUDA backend requires cuDNN. Please resolve dependency or disable OPENCV_DNN_CUDA=OFF")
endif()
endif()
endif()
if(MSVC)
add_definitions( -D_CRT_SECURE_NO_WARNINGS=1 )
ocv_target_compile_definitions(${the_module} PRIVATE cxx_std_17)
ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146
/wd4305 /wd4127 /wd4100 /wd4512 /wd4125 /wd4389 /wd4510 /wd4610
/wd4702 /wd4456 /wd4457 /wd4065 /wd4310 /wd4661 /wd4506
)
if(MSVC_VERSION LESS 1920) # MSVS 2015/2017, .pb.cc generated files
ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4309) # 'static_cast': truncation of constant value
endif()
if(MSVC_VERSION LESS 1920) # <MSVS2019, .pb.cc generated files
ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4189) # local variable is initialized but not referenced
ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4592) # symbol will be dynamically initialized (implementation limitation)
endif()
else()
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-deprecated -Wmissing-prototypes -Wmissing-declarations -Wshadow
-Wunused-parameter -Wsign-compare
)
endif()
if(HAVE_CUDA)
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef)
endif()
if(NOT HAVE_CXX11)
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-undef) # LANG_CXX11 from protobuf files
endif()
if(APPLE_FRAMEWORK)
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wshorten-64-to-32)
endif()
if(ANDROID)
add_definitions(-DDISABLE_POSIX_MEMALIGN -DTH_DISABLE_HEAP_TRACKING)
endif()
if(NOT BUILD_PROTOBUF)
ocv_target_compile_definitions(${the_module} PRIVATE "OPENCV_DNN_EXTERNAL_PROTOBUF=1")
endif()
#suppress warnings in autogenerated caffe.pb.* files
ocv_warnings_disable(CMAKE_CXX_FLAGS
/wd4125 /wd4267 /wd4127 /wd4244 /wd4512 /wd4702
/wd4456 /wd4510 /wd4610 /wd4800
/wd4701 /wd4703 # potentially uninitialized local/pointer variable 'value' used
/wd4505 # unreferenced local function has been removed
/wd4458 # declaration of 'x' hides class member. GCC still works, MSVC bug is here: https://developercommunity.visualstudio.com/content/problem/219311/c-c4458-declaration-hides-class-member-warning-iss.html
-wd858 -wd2196
-Winvalid-offsetof # Apple Clang (attr_value.pb.cc)
)
set(include_dirs "")
set(libs "")
if(HAVE_PROTOBUF)
ocv_target_compile_definitions(${the_module} PRIVATE "HAVE_PROTOBUF=1")
if(PROTOBUF_UPDATE_FILES)
file(GLOB proto_files "${CMAKE_CURRENT_LIST_DIR}/src/tensorflow/*.proto" "${CMAKE_CURRENT_LIST_DIR}/src/caffe/opencv-caffe.proto" "${CMAKE_CURRENT_LIST_DIR}/src/onnx/opencv-onnx.proto")
set(PROTOBUF_GENERATE_CPP_APPEND_PATH ON) # required for tensorflow
protobuf_generate_cpp(fw_srcs fw_hdrs ${proto_files})
else()
file(GLOB fw_srcs "${CMAKE_CURRENT_LIST_DIR}/misc/caffe/opencv-caffe.pb.cc" "${CMAKE_CURRENT_LIST_DIR}/misc/onnx/opencv-onnx.pb.cc")
file(GLOB fw_hdrs "${CMAKE_CURRENT_LIST_DIR}/misc/caffe/opencv-caffe.pb.h" "${CMAKE_CURRENT_LIST_DIR}/misc/onnx/opencv-onnx.pb.h")
set(fw_inc "${CMAKE_CURRENT_LIST_DIR}/misc/caffe" "${CMAKE_CURRENT_LIST_DIR}/misc/onnx")
endif()
endif()
list(APPEND include_dirs ${fw_inc})
list(APPEND libs ${Protobuf_LIBRARIES})
if(NOT BUILD_PROTOBUF)
list(APPEND include_dirs ${Protobuf_INCLUDE_DIRS})
endif()
set(sources_options "")
list(APPEND libs ${LAPACK_LIBRARIES})
if(OPENCV_DNN_OPENCL AND HAVE_OPENCL)
list(APPEND include_dirs ${OPENCL_INCLUDE_DIRS})
else()
set(sources_options EXCLUDE_OPENCL)
endif()
if(OPENCV_DNN_CUDA AND HAVE_CUDA AND HAVE_CUBLAS AND HAVE_CUDNN)
list(APPEND include_dirs ${CUDA_TOOLKIT_INCLUDE} ${CUDNN_INCLUDE_DIRS})
set(CC_LIST ${CUDA_ARCH_BIN})
separate_arguments(CC_LIST)
foreach(cc ${CC_LIST})
if(cc VERSION_LESS 3.0)
message(FATAL_ERROR "CUDA backend for DNN module requires CC 3.0 or higher. Please remove unsupported architectures from CUDA_ARCH_BIN option or disable OPENCV_DNN_CUDA=OFF.")
endif()
endforeach()
unset(CC_LIST)
if(ENABLE_CUDA_FIRST_CLASS_LANGUAGE)
list(APPEND libs ${CUDNN_LIBRARIES} CUDA::cublas${CUDA_LIB_EXT})
if(NOT CUDA_VERSION VERSION_LESS 10.1)
list(APPEND libs CUDA::cublasLt${CUDA_LIB_EXT})
endif()
endif()
else()
set(sources_options ${sources_options} EXCLUDE_CUDA)
endif()
if(HAVE_TIMVX)
list(APPEND include_dirs ${TIMVX_INCLUDE_DIR})
list(APPEND libs -Wl,--whole-archive ${TIMVX_LIBRARY} -Wl,--no-whole-archive)
endif()
if(HAVE_CANN)
list(APPEND include_dirs ${CANN_INCLUDE_DIRS})
list(APPEND libs -Wl,--whole-archive ${CANN_LIBRARIES} -Wl,--no-whole-archive)
endif()
set(webnn_srcs "")
if(NOT EMSCRIPTEN)
if(HAVE_WEBNN)
list(APPEND include_dirs ${WEBNN_HEADER_DIRS})
list(APPEND include_dirs ${WEBNN_INCLUDE_DIRS})
list(APPEND libs -Wl,--whole-archive ${WEBNN_LIBRARIES} -Wl,--no-whole-archive)
list(APPEND webnn_srcs $ENV{WEBNN_NATIVE_DIR}/gen/src/webnn/webnn_cpp.cpp)
endif()
endif()
ocv_module_include_directories(${include_dirs})
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
ocv_append_source_files_cxx_compiler_options(fw_srcs "-Wno-suggest-override") # GCC
ocv_append_source_files_cxx_compiler_options(fw_srcs "-Wno-array-bounds") # GCC 9.3.0 (Ubuntu 20.04)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
ocv_append_source_files_cxx_compiler_options(fw_srcs "-Wno-inconsistent-missing-override") # Clang
endif()
set(dnn_runtime_libs "")
file(GLOB_RECURSE dnn_srcs
"${CMAKE_CURRENT_LIST_DIR}/src/*.cpp"
)
file(GLOB_RECURSE dnn_int_hdrs
"${CMAKE_CURRENT_LIST_DIR}/src/*.hpp"
"${CMAKE_CURRENT_LIST_DIR}/src/*.h"
)
set(dnn_plugin_srcs ${dnn_srcs} ${dnn_int_hdrs})
ocv_list_filterout_ex(dnn_plugin_srcs
# importers
"/src/(caffe|darknet|onnx)/"
)
ocv_option(OPENCV_DNN_OPENVINO "Build with OpenVINO support (2021.4+)" (TARGET ocv.3rdparty.openvino))
if(TARGET ocv.3rdparty.openvino AND OPENCV_DNN_OPENVINO)
if(NOT HAVE_OPENVINO AND NOT HAVE_NGRAPH)
message(FATAL_ERROR "DNN: Inference Engine is not supported without enabled 'nGraph'. Check build configuration.")
endif()
if("openvino" IN_LIST DNN_PLUGIN_LIST OR DNN_PLUGIN_LIST STREQUAL "all")
# plugin doesn't support PCH, separate directory scope is necessary
# opencv_world requires absolute path
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/misc/plugin/openvino" "${CMAKE_CURRENT_BINARY_DIR}/dnn_plugin_openvino")
elseif(NOT OPENCV_DNN_BUILTIN_BACKEND)
list(APPEND dnn_runtime_libs ocv.3rdparty.openvino)
endif()
endif()
set(OPENCV_DNN_BACKEND_DEFAULT "" CACHE STRING "Default backend used by the DNN module (DNN_BACKEND_OPENCV if empty)")
if(OPENCV_DNN_BACKEND_DEFAULT)
ocv_append_source_file_compile_definitions("${CMAKE_CURRENT_LIST_DIR}/src/dnn_params.cpp" "OPENCV_DNN_BACKEND_DEFAULT=${OPENCV_DNN_BACKEND_DEFAULT}")
endif()
ocv_install_used_external_targets(${libs} ${dnn_runtime_libs})
ocv_glob_module_sources(${sources_options} SOURCES ${fw_srcs})
ocv_create_module(${libs} ${dnn_runtime_libs})
ocv_add_samples()
ocv_add_accuracy_tests(${dnn_runtime_libs})
if(NOT BUILD_PROTOBUF)
if(TARGET opencv_test_dnn)
ocv_target_compile_definitions(opencv_test_dnn PRIVATE "OPENCV_DNN_EXTERNAL_PROTOBUF=1")
endif()
endif()
set(perf_path "${CMAKE_CURRENT_LIST_DIR}/perf")
file(GLOB_RECURSE perf_srcs "${perf_path}/*.cpp")
file(GLOB_RECURSE perf_hdrs "${perf_path}/*.hpp" "${perf_path}/*.h")
ocv_add_perf_tests(${dnn_runtime_libs}
FILES test_common "${CMAKE_CURRENT_LIST_DIR}/test/test_common.hpp" "${CMAKE_CURRENT_LIST_DIR}/test/test_common.impl.hpp"
FILES Src ${perf_srcs}
FILES Include ${perf_hdrs}
)
ocv_option(OPENCV_DNN_PERF_CAFFE "Add performance tests of Caffe framework" OFF)
ocv_option(OPENCV_DNN_PERF_CLCAFFE "Add performance tests of clCaffe framework" OFF)
if(BUILD_PERF_TESTS)
if (OPENCV_DNN_PERF_CAFFE
OR ${the_module}_PERF_CAFFE # compatibility for deprecated option
)
find_package(Caffe QUIET)
if (Caffe_FOUND)
ocv_target_compile_definitions(opencv_perf_dnn PRIVATE "HAVE_CAFFE=1")
ocv_target_link_libraries(opencv_perf_dnn caffe)
endif()
elseif(OPENCV_DNN_PERF_CLCAFFE
OR ${the_module}_PERF_CAFFE # compatibility for deprecated option
)
find_package(Caffe QUIET)
if (Caffe_FOUND)
ocv_target_compile_definitions(opencv_perf_dnn PRIVATE "HAVE_CLCAFFE=1")
ocv_target_link_libraries(opencv_perf_dnn caffe)
endif()
endif()
endif()

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

@ -0,0 +1,2 @@
# dnnlegacy
opencv 5.0 caffe and darknet importer and onnx importer for model with dynamic shape. Shape are fixed after onnx file is loaded

@ -0,0 +1,61 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's 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.
//
// * The name of the copyright holders may not 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 the Intel Corporation or contributors 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.
//
//M*/
#ifndef OPENCV_DNNLEGACY_HPP
#define OPENCV_DNNLEGACY_HPP
// This is an umbrella header to include into you project.
// We are free to change headers layout in dnnlegacy subfolder, so please include
// this header for future compatibility
/** @defgroup dnnlegacy Deep Neural Network module function for Caffe and Darknet framework
@{
This module contains:
- API to read Caffe or Darknet models;
Functionality of this module is designed only for forward pass computations (i.e. network testing).
A network training is in principle not supported.
@}
*/
#include <opencv2/dnnlegacy/dnnlegacy.hpp>
#endif /* OPENCV_DNNLEGACY_HPP */

@ -0,0 +1,137 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's 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.
//
// * The name of the copyright holders may not 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 the Intel Corporation or contributors 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.
//
//M*/
#ifndef OPENCV_DNNLEGACY_HPP_HPP
#define OPENCV_DNNLEGACY_HPP_HPP
#include <vector>
#include <opencv2/core.hpp>
#include <opencv2/dnn.hpp>
#include "opencv2/core/async.hpp"
#include <opencv2/dnn/dict.hpp>
namespace cv {
namespace dnnlegacy {
template <typename Importer, typename ... Args>
cv::dnn::Net readNet(Args&& ... args)
{
cv::dnn::Net net;
Importer importer(net, std::forward<Args>(args)...);
return net;
}
//! @addtogroup dnnlegacy
//! @{
/** @brief Reads a network model stored in <a href="https://pjreddie.com/darknet/">Darknet</a> model files.
* @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.
*/
CV_EXPORTS_W cv::dnn::Net readNetFromDarknet(CV_WRAP_FILE_PATH const String &cfgFile, CV_WRAP_FILE_PATH const String &darknetModel = String());
/** @brief Reads a network model stored in <a href="https://pjreddie.com/darknet/">Darknet</a> model files.
* @param bufferCfg A buffer contains a content of .cfg file with text description of the network architecture.
* @param bufferModel A buffer contains a content of .weights file with learned network.
* @returns Net object.
*/
CV_EXPORTS_W cv::dnn::Net readNetFromDarknet(const std::vector<uchar>& bufferCfg,
const std::vector<uchar>& bufferModel = std::vector<uchar>());
/** @brief Reads a network model stored in <a href="https://pjreddie.com/darknet/">Darknet</a> model files.
* @param bufferCfg A buffer contains a content of .cfg file with text description of the network architecture.
* @param lenCfg Number of bytes to read from bufferCfg
* @param bufferModel A buffer contains a content of .weights file with learned network.
* @param lenModel Number of bytes to read from bufferModel
* @returns Net object.
*/
CV_EXPORTS cv::dnn::Net readNetFromDarknet(const char *bufferCfg, size_t lenCfg,
const char *bufferModel = NULL, size_t lenModel = 0);
/** @brief Reads a network model stored in <a href="http://caffe.berkeleyvision.org">Caffe</a> framework's format.
* @param prototxt path to the .prototxt file with text description of the network architecture.
* @param caffeModel path to the .caffemodel file with learned network.
* @returns Net object.
*/
CV_EXPORTS_W cv::dnn::Net readNetFromCaffe(CV_WRAP_FILE_PATH const String& prototxt, CV_WRAP_FILE_PATH const String& caffeModel = String());
/** @brief Reads a network model stored in Caffe model in memory.
* @param bufferProto buffer containing the content of the .prototxt file
* @param bufferModel buffer containing the content of the .caffemodel file
* @returns Net object.
*/
CV_EXPORTS_W cv::dnn::Net readNetFromCaffe(const std::vector<uchar>& bufferProto,
const std::vector<uchar>& bufferModel = std::vector<uchar>());
/** @brief Reads a network model stored in Caffe model in memory.
* @details This is an overloaded member function, provided for convenience.
* It differs from the above function only in what argument(s) it accepts.
* @param bufferProto buffer containing the content of the .prototxt file
* @param lenProto length of bufferProto
* @param bufferModel buffer containing the content of the .caffemodel file
* @param lenModel length of bufferModel
* @returns Net object.
*/
CV_EXPORTS cv::dnn::Net readNetFromCaffe(const char* bufferProto, size_t lenProto,
const char* bufferModel = NULL, size_t lenModel = 0);
/** @brief Convert all weights of Caffe network to half precision floating point.
* @param src Path to origin model from Caffe framework contains single
* precision floating point weights (usually has `.caffemodel` extension).
* @param dst Path to destination model with updated weights.
* @param layersTypes Set of layers types which parameters will be converted.
* By default, converts only Convolutional and Fully-Connected layers'
* weights.
*
* @note Shrinked model has no origin float32 weights so it can't be used
* in origin Caffe framework anymore. However the structure of data
* is taken from NVidia's Caffe fork: https://github.com/NVIDIA/caffe.
* So the resulting model may be used there.
*/
CV_EXPORTS_W void shrinkCaffeModel(CV_WRAP_FILE_PATH const String& src, CV_WRAP_FILE_PATH const String& dst,
const std::vector<String>& layersTypes = std::vector<String>());
//! @}
}
}
#
#endif /* OPENCV_DNNLEGACY_HPP_HPP */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,619 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's 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.
//
// * The name of the copyright holders may not 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 the Intel Corporation or contributors 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.
//
//M*/
#include "../precomp.hpp"
#ifdef HAVE_PROTOBUF
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <google/protobuf/message.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/reflection.h>
#include "caffe_io.hpp"
#endif
#include <opencv2/core.hpp>
#include <opencv2/dnnlegacy/dnnlegacy.hpp>
#include <opencv2/core/utils/fp_control_utils.hpp>
namespace cv {
namespace dnnlegacy {
#ifdef HAVE_PROTOBUF
using ::google::protobuf::RepeatedFieldRef;
using ::google::protobuf::Message;
using ::google::protobuf::Descriptor;
using ::google::protobuf::FieldDescriptor;
using ::google::protobuf::Reflection;
using namespace dnn;
namespace
{
template<typename T>
static cv::String toString(const T &v)
{
std::ostringstream ss;
ss << v;
return ss.str();
}
static inline
MatShape parseBlobShape(const caffe::BlobShape& _input_shape)
{
MatShape shape;
for (int i = 0; i < _input_shape.dim_size(); i++)
{
shape.push_back((int)_input_shape.dim(i));
}
return shape;
}
class CaffeImporter
{
FPDenormalsIgnoreHintScope fp_denormals_ignore_scope;
caffe::NetParameter net;
caffe::NetParameter netBinary;
public:
CaffeImporter(const char *prototxt, const char *caffeModel)
{
CV_TRACE_FUNCTION();
ReadNetParamsFromTextFileOrDie(prototxt, &net);
if (caffeModel && caffeModel[0])
ReadNetParamsFromBinaryFileOrDie(caffeModel, &netBinary);
}
CaffeImporter(const char *dataProto, size_t lenProto,
const char *dataModel, size_t lenModel)
{
CV_TRACE_FUNCTION();
ReadNetParamsFromTextBufferOrDie(dataProto, lenProto, &net);
if (dataModel != NULL && lenModel > 0)
ReadNetParamsFromBinaryBufferOrDie(dataModel, lenModel, &netBinary);
}
void extractCustomParams(const google::protobuf::UnknownFieldSet& unknownFields, cv::dnn::LayerParams &params)
{
const int numFields = unknownFields.field_count();
for (int i = 0; i < numFields; ++i)
{
const google::protobuf::UnknownField& field = unknownFields.field(i);
CV_Assert(field.type() == google::protobuf::UnknownField::TYPE_GROUP);
CV_CheckGE(field.group().field_count(), 2, "UnknownField should have at least 2 items: name and value");
std::string fieldName = field.group().field(0).length_delimited();
std::string fieldValue = field.group().field(1).length_delimited();
params.set(fieldName, fieldValue);
}
}
void addParam(const Message &msg, const FieldDescriptor *field, cv::dnn::LayerParams &params)
{
const Reflection *refl = msg.GetReflection();
int type = field->cpp_type();
bool isRepeated = field->is_repeated();
const std::string &name = field->name();
#define SET_UP_FILED(getter, arrayConstr, gtype) \
if (isRepeated) { \
const RepeatedFieldRef<gtype> v = refl->GetRepeatedFieldRef<gtype>(msg, field); \
params.set(name, DictValue::arrayConstr(v.begin(), (int)v.size())); \
} \
else { \
params.set(name, refl->getter(msg, field)); \
}
switch (type)
{
case FieldDescriptor::CPPTYPE_INT32:
SET_UP_FILED(GetInt32, arrayInt, ::google::protobuf::int32);
break;
case FieldDescriptor::CPPTYPE_UINT32:
SET_UP_FILED(GetUInt32, arrayInt, ::google::protobuf::uint32);
break;
case FieldDescriptor::CPPTYPE_INT64:
SET_UP_FILED(GetInt32, arrayInt, ::google::protobuf::int64);
break;
case FieldDescriptor::CPPTYPE_UINT64:
SET_UP_FILED(GetUInt32, arrayInt, ::google::protobuf::uint64);
break;
case FieldDescriptor::CPPTYPE_BOOL:
SET_UP_FILED(GetBool, arrayInt, bool);
break;
case FieldDescriptor::CPPTYPE_DOUBLE:
SET_UP_FILED(GetDouble, arrayReal, double);
break;
case FieldDescriptor::CPPTYPE_FLOAT:
SET_UP_FILED(GetFloat, arrayReal, float);
break;
case FieldDescriptor::CPPTYPE_STRING:
if (isRepeated) {
const RepeatedFieldRef<std::string> v = refl->GetRepeatedFieldRef<std::string>(msg, field);
params.set(name, DictValue::arrayString(v.begin(), (int)v.size()));
}
else {
params.set(name, refl->GetString(msg, field));
}
break;
case FieldDescriptor::CPPTYPE_ENUM:
if (isRepeated) {
int size = refl->FieldSize(msg, field);
std::vector<cv::String> buf(size);
for (int i = 0; i < size; i++)
buf[i] = refl->GetRepeatedEnum(msg, field, i)->name();
params.set(name, DictValue::arrayString(buf.begin(), size));
}
else {
params.set(name, refl->GetEnum(msg, field)->name());
}
break;
default:
CV_Error(Error::StsError, "Unknown type \"" + String(field->type_name()) + "\" in prototxt");
}
}
inline static bool ends_with_param(const std::string &str)
{
static const std::string _param("_param");
return (str.size() >= _param.size()) && str.compare(str.size() - _param.size(), _param.size(), _param) == 0;
}
void extractLayerParams(const Message &msg, cv::dnn::LayerParams &params, bool isInternal = false)
{
const Descriptor *msgDesc = msg.GetDescriptor();
const Reflection *msgRefl = msg.GetReflection();
for (int fieldId = 0; fieldId < msgDesc->field_count(); fieldId++)
{
const FieldDescriptor *fd = msgDesc->field(fieldId);
if (!isInternal && !ends_with_param(fd->name()))
continue;
const google::protobuf::UnknownFieldSet& unknownFields = msgRefl->GetUnknownFields(msg);
bool hasData = fd->is_required() ||
(fd->is_optional() && msgRefl->HasField(msg, fd)) ||
(fd->is_repeated() && msgRefl->FieldSize(msg, fd) > 0) ||
!unknownFields.empty();
if (!hasData)
continue;
extractCustomParams(unknownFields, params);
if (fd->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE)
{
if (fd->is_repeated()) //Extract only first item!
extractLayerParams(msgRefl->GetRepeatedMessage(msg, fd, 0), params, true);
else
extractLayerParams(msgRefl->GetMessage(msg, fd), params, true);
}
else
{
addParam(msg, fd, params);
}
}
}
void blobShapeFromProto(const caffe::BlobProto &pbBlob, MatShape& shape)
{
shape.clear();
if (pbBlob.has_num() || pbBlob.has_channels() || pbBlob.has_height() || pbBlob.has_width())
{
shape.push_back(pbBlob.num());
shape.push_back(pbBlob.channels());
shape.push_back(pbBlob.height());
shape.push_back(pbBlob.width());
}
else if (pbBlob.has_shape())
{
shape = parseBlobShape(pbBlob.shape());
}
else
shape.resize(1, 1); // Is a scalar.
}
void blobFromProto(const caffe::BlobProto &pbBlob, cv::Mat &dstBlob)
{
MatShape shape;
blobShapeFromProto(pbBlob, shape);
dstBlob.create((int)shape.size(), &shape[0], CV_32F);
if (pbBlob.data_size())
{
// Single precision floats.
CV_Assert(pbBlob.data_size() == (int)dstBlob.total());
CV_DbgAssert(pbBlob.GetDescriptor()->FindFieldByLowercaseName("data")->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT);
Mat(dstBlob.dims, &dstBlob.size[0], CV_32F, (void*)pbBlob.data().data()).copyTo(dstBlob);
}
else
{
CV_Assert(pbBlob.has_raw_data());
const std::string& raw_data = pbBlob.raw_data();
if (pbBlob.raw_data_type() == caffe::FLOAT16)
{
// Half precision floats.
CV_Assert(raw_data.size() / 2 == (int)dstBlob.total());
Mat halfs((int)shape.size(), &shape[0], CV_16FC1, (void*)raw_data.c_str());
halfs.convertTo(dstBlob, CV_32F);
}
else if (pbBlob.raw_data_type() == caffe::FLOAT)
{
CV_Assert(raw_data.size() / 4 == (int)dstBlob.total());
Mat((int)shape.size(), &shape[0], CV_32FC1, (void*)raw_data.c_str()).copyTo(dstBlob);
}
else
CV_Error(Error::StsNotImplemented, "Unexpected blob data type");
}
}
void extractBinaryLayerParams(const caffe::LayerParameter& layer, LayerParams& layerParams)
{
const std::string &name = layer.name();
int li;
for (li = 0; li != netBinary.layer_size(); li++)
{
const caffe::LayerParameter& binLayer = netBinary.layer(li);
// Break if the layer name is the same and the blobs are not cleared
if (binLayer.name() == name && binLayer.blobs_size() != 0)
break;
}
if (li == netBinary.layer_size())
return;
caffe::LayerParameter* binLayer = netBinary.mutable_layer(li);
const int numBlobs = binLayer->blobs_size();
std::vector<caffe::BlobProto*> blobs(numBlobs);
binLayer->mutable_blobs()->ExtractSubrange(0, numBlobs, blobs.data());
layerParams.blobs.resize(numBlobs);
for (int bi = 0; bi < numBlobs; bi++)
{
blobFromProto(*blobs[bi], layerParams.blobs[bi]);
delete blobs[bi];
}
}
struct BlobNote
{
BlobNote(const std::string &_name, int _layerId, int _outNum) :
name(_name), layerId(_layerId), outNum(_outNum) {}
std::string name;
int layerId, outNum;
};
std::vector<BlobNote> addedBlobs;
std::map<String, int> layerCounter;
void populateNet(Net dstNet)
{
CV_TRACE_FUNCTION();
int layersSize = net.layer_size();
layerCounter.clear();
addedBlobs.clear();
addedBlobs.reserve(layersSize + 1);
//setup input layer names
std::vector<String> netInputs(net.input_size());
std::vector<MatShape> inp_shapes;
{
int net_input_size = net.input_size();
for (int inNum = 0; inNum < net_input_size; inNum++)
{
addedBlobs.push_back(BlobNote(net.input(inNum), 0, inNum));
netInputs[inNum] = net.input(inNum);
}
if (net.input_dim_size() > 0) // deprecated in Caffe proto
{
int net_input_dim_size = net.input_dim_size();
CV_Check(net_input_dim_size, net_input_dim_size % 4 == 0, "");
CV_CheckEQ(net_input_dim_size, net_input_size * 4, "");
for (int inp_id = 0; inp_id < net_input_size; inp_id++)
{
int dim = inp_id * 4;
MatShape shape(4);
shape[0] = net.input_dim(dim);
shape[1] = net.input_dim(dim+1);
shape[2] = net.input_dim(dim+2);
shape[3] = net.input_dim(dim+3);
inp_shapes.push_back(shape);
}
}
else if (net.input_shape_size() > 0) // deprecated in Caffe proto
{
int net_input_shape_size = net.input_shape_size();
CV_CheckEQ(net_input_shape_size, net_input_size, "");
for (int inp_id = 0; inp_id < net_input_shape_size; inp_id++)
{
MatShape shape = parseBlobShape(net.input_shape(inp_id));
inp_shapes.push_back(shape);
}
}
else
{
for (int inp_id = 0; inp_id < net_input_size; inp_id++)
{
MatShape shape; // empty
inp_shapes.push_back(shape);
}
}
}
for (int li = 0; li < layersSize; li++)
{
const caffe::LayerParameter &layer = net.layer(li);
String name = layer.name();
String type = layer.type();
LayerParams layerParams;
extractLayerParams(layer, layerParams);
extractBinaryLayerParams(layer, layerParams);
int repetitions = layerCounter[name]++;
if (repetitions)
name += String("_") + toString(repetitions);
if (type == "Input")
{
for (int outNum = 0; outNum < layer.top_size(); outNum++)
{
addOutput(layer, 0, outNum);
addedBlobs.back().outNum = netInputs.size();
netInputs.push_back(addedBlobs.back().name);
}
if (layer.has_input_param())
{
const caffe::InputParameter &inputParameter = layer.input_param();
int input_shape_size = inputParameter.shape_size();
CV_CheckEQ(input_shape_size, layer.top_size(), "");
for (int inp_id = 0; inp_id < input_shape_size; inp_id++)
{
MatShape shape = parseBlobShape(inputParameter.shape(inp_id));
inp_shapes.push_back(shape);
}
}
continue;
}
else if (type == "BatchNorm")
{
if (!layerParams.get<bool>("use_global_stats", true))
{
CV_Assert_N(layer.bottom_size() == 1, layer.top_size() == 1);
LayerParams mvnParams;
mvnParams.set("eps", layerParams.get<float>("eps", 1e-5));
std::string mvnName = name + "/mvn";
int repetitions = layerCounter[mvnName]++;
if (repetitions)
mvnName += String("_") + toString(repetitions);
int mvnId = dstNet.addLayer(mvnName, "MVN", mvnParams);
addInput(layer.bottom(0), mvnId, 0, dstNet);
addOutput(layer, mvnId, 0);
net.mutable_layer(li)->set_bottom(0, layer.top(0));
layerParams.blobs[0].setTo(0); // mean
layerParams.blobs[1].setTo(1); // std
}
}
else if (type == "Axpy")
{
CV_Assert_N(layer.bottom_size() == 3, layer.top_size() == 1);
std::string scaleName = name + "/scale";
int repetitions = layerCounter[scaleName]++;
if (repetitions) {
scaleName += String("_") + toString(repetitions);
}
LayerParams scaleParams;
scaleParams.set("axis", 1);
scaleParams.set("has_bias", false);
int scaleId = dstNet.addLayer(scaleName, "Scale", scaleParams);
addInput(layer.bottom(2), scaleId, 0, dstNet);
addInput(layer.bottom(0), scaleId, 1, dstNet);
addOutput(layer, scaleId, 0);
net.mutable_layer(li)->set_bottom(0, layer.top(0));
net.mutable_layer(li)->mutable_bottom()->RemoveLast();
type = "Eltwise";
}
else if (type == "Resample")
{
CV_Assert(layer.bottom_size() == 1 || layer.bottom_size() == 2);
type = "Resize";
String interp = toLowerCase(layerParams.get<String>("type"));
layerParams.set("interpolation", interp == "linear" ? "bilinear" : interp);
if (layerParams.has("factor"))
{
float factor = layerParams.get<float>("factor");
CV_Assert(layer.bottom_size() != 2 || factor == 1.0);
layerParams.set("zoom_factor", factor);
if ((interp == "linear" && factor != 1.0) ||
(interp == "nearest" && factor < 1.0))
CV_Error(Error::StsNotImplemented, "Unsupported Resample mode");
}
}
else if ("Convolution" == type)
{
CV_Assert(layer.bottom_size() == layer.top_size());
for (int i = 0; i < layer.bottom_size(); i++)
{
int conv_id = dstNet.addLayer(layer.top(i), type, layerParams);
addInput(layer.bottom(i), conv_id, 0, dstNet);
addedBlobs.push_back(BlobNote(layer.top(i), conv_id, 0));
}
continue;
}
else if ("ConvolutionDepthwise" == type)
{
type = "Convolution";
}
else if (type == "Softmax"){
// set default axis to 1
if(!layerParams.has("axis"))
layerParams.set("axis", 1);
}
int id = dstNet.addLayer(name, type, layerParams);
for (int inNum = 0; inNum < layer.bottom_size(); inNum++)
addInput(layer.bottom(inNum), id, inNum, dstNet);
for (int outNum = 0; outNum < layer.top_size(); outNum++)
addOutput(layer, id, outNum);
}
dstNet.setInputsNames(netInputs);
if (inp_shapes.size() > 0)
{
CV_CheckEQ(inp_shapes.size(), netInputs.size(), "");
for (int inp_id = 0; inp_id < inp_shapes.size(); inp_id++)
dstNet.setInputShape(netInputs[inp_id], inp_shapes[inp_id]);
}
addedBlobs.clear();
}
void addOutput(const caffe::LayerParameter &layer, int layerId, int outNum)
{
const std::string &name = layer.top(outNum);
bool haveDups = false;
for (int idx = (int)addedBlobs.size() - 1; idx >= 0; idx--)
{
if (addedBlobs[idx].name == name)
{
haveDups = true;
break;
}
}
if (haveDups)
{
bool isInplace = layer.bottom_size() > outNum && layer.bottom(outNum) == name;
if (!isInplace)
CV_Error(Error::StsBadArg, "Duplicate blobs produced by multiple sources");
}
addedBlobs.push_back(BlobNote(name, layerId, outNum));
}
void addInput(const std::string &name, int layerId, int inNum, Net &dstNet)
{
int idx;
for (idx = (int)addedBlobs.size() - 1; idx >= 0; idx--)
{
if (addedBlobs[idx].name == name)
break;
}
if (idx < 0)
{
CV_Error(Error::StsObjectNotFound, "Can't find output blob \"" + name + "\"");
}
dstNet.connect(addedBlobs[idx].layerId, addedBlobs[idx].outNum, layerId, inNum);
}
};
}
Net readNetFromCaffe(const String &prototxt, const String &caffeModel /*= String()*/)
{
CaffeImporter caffeImporter(prototxt.c_str(), caffeModel.c_str());
Net net;
caffeImporter.populateNet(net);
return net;
}
Net readNetFromCaffe(const char *bufferProto, size_t lenProto,
const char *bufferModel, size_t lenModel)
{
CaffeImporter caffeImporter(bufferProto, lenProto, bufferModel, lenModel);
Net net;
caffeImporter.populateNet(net);
return net;
}
Net readNetFromCaffe(const std::vector<uchar>& bufferProto, const std::vector<uchar>& bufferModel)
{
const char* bufferProtoPtr = reinterpret_cast<const char*>(&bufferProto[0]);
const char* bufferModelPtr = bufferModel.empty() ? NULL :
reinterpret_cast<const char*>(&bufferModel[0]);
return readNetFromCaffe(bufferProtoPtr, bufferProto.size(),
bufferModelPtr, bufferModel.size());
}
#else // HAVE_PROTOBUF
#define DNN_PROTOBUF_UNSUPPORTED() CV_Error(Error::StsError, "DNN/Caffe: Build OpenCV with Protobuf to import Caffe models")
Net readNetFromCaffe(const String &, const String &) {
DNN_PROTOBUF_UNSUPPORTED();
}
Net readNetFromCaffe(const char *, size_t, const char *, size_t) {
DNN_PROTOBUF_UNSUPPORTED();
}
Net readNetFromCaffe(const std::vector<uchar>&, const std::vector<uchar>&) {
DNN_PROTOBUF_UNSUPPORTED();
}
#endif // HAVE_PROTOBUF
}} // namespace

File diff suppressed because it is too large Load Diff

@ -0,0 +1,129 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's 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.
//
// * The name of the copyright holders may not 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 the Intel Corporation or contributors 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.
//
//M*/
/*M///////////////////////////////////////////////////////////////////////////////////////
//COPYRIGHT
//
//All contributions by the University of California:
//Copyright (c) 2014, The Regents of the University of California (Regents)
//All rights reserved.
//
//All other contributions:
//Copyright (c) 2014, the respective contributors
//All rights reserved.
//
//Caffe uses a shared copyright model: each contributor holds copyright over
//their contributions to Caffe. The project versioning records all such
//contribution and copyright details. If a contributor wants to further mark
//their specific copyright on a particular contribution, they should indicate
//their copyright solely in the commit message of the change when it is
//committed.
//
//LICENSE
//
//Redistribution and use in source and binary forms, with or without
//modification, are permitted provided that the following conditions are met:
//
//1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//2. 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.
//
//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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
//
//CONTRIBUTION AGREEMENT
//
//By contributing to the BVLC/caffe repository through pull-request, comment,
//or otherwise, the contributor releases their content to the
//license and copyright terms herein.
//
//M*/
#ifndef __OPENCV_DNN_CAFFE_IO_HPP__
#define __OPENCV_DNN_CAFFE_IO_HPP__
#ifdef HAVE_PROTOBUF
#if defined(__GNUC__) && __GNUC__ >= 5
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsuggest-override"
#endif
#include "opencv-caffe.pb.h"
#if defined(__GNUC__) && __GNUC__ >= 5
#pragma GCC diagnostic pop
#endif
namespace caffe { using namespace opencv_caffe; } // avoid massive renames from caffe proto package
namespace cv {
namespace dnnlegacy {
// Read parameters from a file into a NetParameter proto message.
void ReadNetParamsFromTextFileOrDie(const char* param_file,
caffe::NetParameter* param);
void ReadNetParamsFromBinaryFileOrDie(const char* param_file,
caffe::NetParameter* param);
// Read parameters from a memory buffer into a NetParammeter proto message.
void ReadNetParamsFromBinaryBufferOrDie(const char* data, size_t len,
caffe::NetParameter* param);
void ReadNetParamsFromTextBufferOrDie(const char* data, size_t len,
caffe::NetParameter* param);
// Utility functions used internally by Caffe and TensorFlow loaders
bool ReadProtoFromTextFile(const char* filename, ::google::protobuf::Message* proto);
bool ReadProtoFromBinaryFile(const char* filename, ::google::protobuf::Message* proto);
bool ReadProtoFromTextBuffer(const char* data, size_t len, ::google::protobuf::Message* proto);
bool ReadProtoFromBinaryBuffer(const char* data, size_t len, ::google::protobuf::Message* proto);
}
}
#endif
#endif

@ -0,0 +1,77 @@
// 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) 2017, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
#include "../precomp.hpp"
#ifdef HAVE_PROTOBUF
#include <fstream>
#include "caffe_io.hpp"
#endif
namespace cv { namespace dnnlegacy {
#ifdef HAVE_PROTOBUF
void shrinkCaffeModel(const String& src, const String& dst, const std::vector<String>& layersTypes)
{
CV_TRACE_FUNCTION();
std::vector<String> types(layersTypes);
if (types.empty())
{
types.push_back("Convolution");
types.push_back("InnerProduct");
}
caffe::NetParameter net;
ReadNetParamsFromBinaryFileOrDie(src.c_str(), &net);
for (int i = 0; i < net.layer_size(); ++i)
{
caffe::LayerParameter* lp = net.mutable_layer(i);
if (std::find(types.begin(), types.end(), lp->type()) == types.end())
{
continue;
}
for (int j = 0; j < lp->blobs_size(); ++j)
{
caffe::BlobProto* blob = lp->mutable_blobs(j);
CV_Assert(blob->data_size() != 0); // float32 array.
Mat floats(1, blob->data_size(), CV_32FC1, (void*)blob->data().data());
Mat halfs(1, blob->data_size(), CV_16FC1);
floats.convertTo(halfs, CV_16F); // Convert to float16.
blob->clear_data(); // Clear float32 data.
// Set float16 data.
blob->set_raw_data(halfs.data, halfs.total() * halfs.elemSize());
blob->set_raw_data_type(caffe::FLOAT16);
}
}
#if GOOGLE_PROTOBUF_VERSION < 3005000
size_t msgSize = saturate_cast<size_t>(net.ByteSize());
#else
size_t msgSize = net.ByteSizeLong();
#endif
std::vector<uint8_t> output(msgSize);
net.SerializeWithCachedSizesToArray(&output[0]);
std::ofstream ofs(dst.c_str(), std::ios::binary);
ofs.write((const char*)&output[0], msgSize);
ofs.close();
}
#else
void shrinkCaffeModel(const String& src, const String& dst, const std::vector<String>& types)
{
CV_Error(cv::Error::StsNotImplemented, "libprotobuf required to import data from Caffe models");
}
#endif // HAVE_PROTOBUF
}} // namespace

File diff suppressed because it is too large Load Diff

@ -0,0 +1,256 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
// (3-clause BSD License)
//
// Copyright (C) 2017, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// 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 names of the copyright holders nor the names of the 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 holders or contributors 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.
//
//M*/
#include "../precomp.hpp"
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#include <map>
#include "darknet_io.hpp"
#include <opencv2/core/utils/fp_control_utils.hpp>
namespace cv {
namespace dnnlegacy {
using namespace dnn;
namespace
{
class DarknetImporter
{
FPDenormalsIgnoreHintScope fp_denormals_ignore_scope;
dnnlegacy::darknet::NetParameter net;
public:
DarknetImporter() {}
DarknetImporter(std::istream &cfgStream, std::istream &darknetModelStream)
{
CV_TRACE_FUNCTION();
dnnlegacy::ReadNetParamsFromCfgStreamOrDie(cfgStream, &net);
dnnlegacy::ReadNetParamsFromBinaryStreamOrDie(darknetModelStream, &net);
}
DarknetImporter(std::istream &cfgStream)
{
CV_TRACE_FUNCTION();
dnnlegacy::ReadNetParamsFromCfgStreamOrDie(cfgStream, &net);
}
struct BlobNote
{
BlobNote(const std::string &_name, int _layerId, int _outNum) :
name(_name), layerId(_layerId), outNum(_outNum) {}
std::string name;
int layerId, outNum;
};
std::vector<BlobNote> addedBlobs;
std::map<String, int> layerCounter;
void populateNet(cv::dnn::Net dstNet)
{
CV_TRACE_FUNCTION();
int layersSize = net.layer_size();
layerCounter.clear();
addedBlobs.clear();
addedBlobs.reserve(layersSize + 1);
//setup input layer names
{
std::vector<String> netInputs(net.input_size());
for (int inNum = 0; inNum < net.input_size(); inNum++)
{
addedBlobs.push_back(BlobNote(net.input(inNum), 0, inNum));
netInputs[inNum] = net.input(inNum);
}
dstNet.setInputsNames(netInputs);
}
for (int li = 0; li < layersSize; li++)
{
const dnnlegacy::darknet::LayerParameter &layer = net.layer(li);
String name = layer.name();
String type = layer.type();
cv::dnn::LayerParams layerParams = layer.getLayerParams();
int repetitions = layerCounter[name]++;
if (repetitions)
name += cv::format("_%d", repetitions);
int id = dstNet.addLayer(name, type, layerParams);
// iterate many bottoms layers (for example for: route -1, -4)
for (int inNum = 0; inNum < layer.bottom_size(); inNum++)
addInput(layer.bottom(inNum), id, inNum, dstNet, layer.name());
for (int outNum = 0; outNum < layer.top_size(); outNum++)
addOutput(layer, id, outNum);
}
addedBlobs.clear();
}
void addOutput(const dnnlegacy::darknet::LayerParameter &layer, int layerId, int outNum)
{
const std::string &name = layer.top(outNum);
bool haveDups = false;
for (int idx = (int)addedBlobs.size() - 1; idx >= 0; idx--)
{
if (addedBlobs[idx].name == name)
{
haveDups = true;
break;
}
}
if (haveDups)
{
bool isInplace = layer.bottom_size() > outNum && layer.bottom(outNum) == name;
if (!isInplace)
CV_Error(Error::StsBadArg, "Duplicate blobs produced by multiple sources");
}
addedBlobs.push_back(BlobNote(name, layerId, outNum));
}
void addInput(const std::string &name, int layerId, int inNum, cv::dnn::Net &dstNet, std::string nn)
{
int idx;
for (idx = (int)addedBlobs.size() - 1; idx >= 0; idx--)
{
if (addedBlobs[idx].name == name)
break;
}
if (idx < 0)
{
CV_Error(Error::StsObjectNotFound, "Can't find output blob \"" + name + "\"");
return;
}
dstNet.connect(addedBlobs[idx].layerId, addedBlobs[idx].outNum, layerId, inNum);
}
};
static Net readNetFromDarknet(std::istream &cfgFile, std::istream &darknetModel)
{
Net net;
DarknetImporter darknetImporter(cfgFile, darknetModel);
darknetImporter.populateNet(net);
return net;
}
static Net readNetFromDarknet(std::istream &cfgFile)
{
Net net;
DarknetImporter darknetImporter(cfgFile);
darknetImporter.populateNet(net);
return net;
}
}
Net readNetFromDarknet(const String &cfgFile, const String &darknetModel /*= String()*/)
{
std::ifstream cfgStream(cfgFile.c_str());
if (!cfgStream.is_open())
{
CV_Error(cv::Error::StsParseError, "Failed to open NetParameter file: " + std::string(cfgFile));
}
if (darknetModel != String())
{
std::ifstream darknetModelStream(darknetModel.c_str(), std::ios::binary);
if (!darknetModelStream.is_open())
{
CV_Error(cv::Error::StsParseError, "Failed to parse NetParameter file: " + std::string(darknetModel));
}
return readNetFromDarknet(cfgStream, darknetModelStream);
}
else
return readNetFromDarknet(cfgStream);
}
struct BufferStream : public std::streambuf
{
BufferStream(const char* s, std::size_t n)
{
char* ptr = const_cast<char*>(s);
setg(ptr, ptr, ptr + n);
}
};
Net readNetFromDarknet(const char *bufferCfg, size_t lenCfg, const char *bufferModel, size_t lenModel)
{
BufferStream cfgBufferStream(bufferCfg, lenCfg);
std::istream cfgStream(&cfgBufferStream);
if (lenModel)
{
BufferStream weightsBufferStream(bufferModel, lenModel);
std::istream weightsStream(&weightsBufferStream);
return readNetFromDarknet(cfgStream, weightsStream);
}
else
return readNetFromDarknet(cfgStream);
}
Net readNetFromDarknet(const std::vector<uchar>& bufferCfg, const std::vector<uchar>& bufferModel)
{
const char* bufferCfgPtr = reinterpret_cast<const char*>(&bufferCfg[0]);
const char* bufferModelPtr = bufferModel.empty() ? NULL :
reinterpret_cast<const char*>(&bufferModel[0]);
return readNetFromDarknet(bufferCfgPtr, bufferCfg.size(),
bufferModelPtr, bufferModel.size());
}
}} // namespace

File diff suppressed because it is too large Load Diff

@ -0,0 +1,117 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
// (3-clause BSD License)
//
// Copyright (C) 2017, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// 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 names of the copyright holders nor the names of the 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 holders or contributors 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.
//
//M*/
/*M///////////////////////////////////////////////////////////////////////////////////////
//MIT License
//
//Copyright (c) 2017 Joseph Redmon
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
//
//M*/
#ifndef __OPENCV_DNN_DARKNET_IO_HPP__
#define __OPENCV_DNN_DARKNET_IO_HPP__
#include <opencv2/dnnlegacy/dnnlegacy.hpp>
namespace cv {
namespace dnnlegacy {
namespace darknet {
class LayerParameter {
std::string layer_name, layer_type;
std::vector<std::string> bottom_indexes;
cv::dnn::LayerParams layerParams;
public:
friend class setLayersParams;
cv::dnn::LayerParams getLayerParams() const { return layerParams; }
std::string name() const { return layer_name; }
std::string type() const { return layer_type; }
int bottom_size() const { return bottom_indexes.size(); }
std::string bottom(const int index) const { return bottom_indexes.at(index); }
int top_size() const { return 1; }
std::string top(const int index) const { return layer_name; }
};
class NetParameter {
public:
int width, height, channels;
std::vector<LayerParameter> layers;
std::vector<int> out_channels_vec;
std::map<int, std::map<std::string, std::string> > layers_cfg;
std::map<std::string, std::string> net_cfg;
NetParameter() : width(0), height(0), channels(0) {}
int layer_size() const { return layers.size(); }
int input_size() const { return 1; }
std::string input(const int index) const { return "data"; }
LayerParameter layer(const int index) const { return layers.at(index); }
};
}
// Read parameters from a stream into a NetParameter message.
void ReadNetParamsFromCfgStreamOrDie(std::istream &ifile, darknet::NetParameter *net);
void ReadNetParamsFromBinaryStreamOrDie(std::istream &ifile, darknet::NetParameter *net);
}
}
#endif

@ -0,0 +1,90 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's 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.
//
// * The name of the copyright holders may not 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 the Intel Corporation or contributors 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.
//
//M*/
#if !defined(BUILD_PLUGIN)
#include "cvconfig.h"
#else
#include <opencv2/core/cvdef.h>
#undef __OPENCV_BUILD // allow public API only
#endif
#include <opencv2/core.hpp>
#ifndef CV_OCL4DNN
#define CV_OCL4DNN 0
#endif
#if CV_OCL4DNN
#ifndef HAVE_OPENCL
#error "Configuration error: re-run CMake from clean build directory"
#endif
#else
#undef HAVE_OPENCL
#endif
#ifndef CV_CUDA4DNN
#define CV_CUDA4DNN 0
#endif
#if CV_CUDA4DNN
#ifndef HAVE_CUDA
#error "Configuration error: re-run CMake from clean build directory"
#endif
#else
#undef HAVE_CUDA
#endif
#include <numeric>
#include <memory>
#include <algorithm>
#include <fstream>
#include <sstream>
#include <vector>
#include <set>
#include <iterator>
#include <opencv2/core/ocl.hpp>
#include <opencv2/core/opencl/ocl_defs.hpp>
#include <opencv2/core/utils/trace.hpp>
#include <opencv2/dnnlegacy.hpp>
//#include "dnn_common.hpp"

@ -0,0 +1,94 @@
// 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) 2017, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
#include "test_precomp.hpp"
#include "npy_blob.hpp"
namespace cv
{
static std::string getType(const std::string& header)
{
std::string field = "'descr':";
int idx = header.find(field);
CV_Assert(idx != -1);
int from = header.find('\'', idx + field.size()) + 1;
int to = header.find('\'', from);
return header.substr(from, to - from);
}
static std::string getFortranOrder(const std::string& header)
{
std::string field = "'fortran_order':";
int idx = header.find(field);
CV_Assert(idx != -1);
int from = header.find_last_of(' ', idx + field.size()) + 1;
int to = header.find(',', from);
return header.substr(from, to - from);
}
static std::vector<int> getShape(const std::string& header)
{
std::string field = "'shape':";
int idx = header.find(field);
CV_Assert(idx != -1);
int from = header.find('(', idx + field.size()) + 1;
int to = header.find(')', from);
std::string shapeStr = header.substr(from, to - from);
if (shapeStr.empty())
return std::vector<int>(1, 1);
// Remove all commas.
shapeStr.erase(std::remove(shapeStr.begin(), shapeStr.end(), ','),
shapeStr.end());
std::istringstream ss(shapeStr);
int value;
std::vector<int> shape;
while (ss >> value)
{
shape.push_back(value);
}
return shape;
}
Mat blobFromNPY(const std::string& path)
{
std::ifstream ifs(path.c_str(), std::ios::binary);
CV_Assert(ifs.is_open());
std::string magic(6, '*');
ifs.read(&magic[0], magic.size());
CV_Assert(magic == "\x93NUMPY");
ifs.ignore(1); // Skip major version byte.
ifs.ignore(1); // Skip minor version byte.
unsigned short headerSize;
ifs.read((char*)&headerSize, sizeof(headerSize));
std::string header(headerSize, '*');
ifs.read(&header[0], header.size());
// Extract data type.
CV_Assert(getType(header) == "<f4");
CV_Assert(getFortranOrder(header) == "False");
std::vector<int> shape = getShape(header);
Mat blob(shape, CV_32F);
ifs.read((char*)blob.data, blob.total() * blob.elemSize());
CV_Assert((size_t)ifs.gcount() == blob.total() * blob.elemSize());
return blob;
}
} // namespace cv

@ -0,0 +1,20 @@
// 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) 2017, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
#ifndef __OPENCV_DNNLEGACY_TEST_NPY_BLOB_HPP__
#define __OPENCV_DNNLEGACY_TEST_NPY_BLOB_HPP__
namespace cv
{
// Parse serialized NumPy array by np.save(...)
// Based on specification of .npy data format.
Mat blobFromNPY(const std::string& path);
}
#endif

@ -0,0 +1,877 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's 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.
//
// * The name of the copyright holders may not 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 the Intel Corporation or contributors 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.
//
//M*/
#include <tuple>
#include "test_precomp.hpp"
#include <opencv2/dnnlegacy/dnnlegacy.hpp>
#include "npy_blob.hpp"
#include <opencv2/dnn/shape_utils.hpp>
using namespace cv;
namespace opencv_test {
namespace {
template<typename Tstring>
static std::string _tf(Tstring filename)
{
return cv::samples::findFile(std::string("dnn/") + filename);
}
class Test_Caffe_nets : public DNNlegacyTestLayer
{
public:
void testFaster(const std::string& proto, const std::string& model, const Mat& ref,
double scoreDiff = 0.0, double iouDiff = 0.0)
{
checkBackend();
cv::dnn::Net net = cv::dnnlegacy::readNetFromCaffe(cv::samples::findFile("dnn/" + proto),
cv::samples::findFile("dnn/" + model, false));
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
if (target == cv::dnn::DNN_TARGET_CPU_FP16)
net.enableWinograd(false);
Mat img = imread(cv::samples::findFile("dnn/dog416.png"));
resize(img, img, Size(800, 600));
Mat blob = cv::dnn::blobFromImage(img, 1.0, Size(), Scalar(102.9801, 115.9465, 122.7717), false, false);
Mat imInfo = (Mat_<float>(1, 3) << img.rows, img.cols, 1.6f);
net.setInput(blob, "data");
net.setInput(imInfo, "im_info");
// Output has shape 1x1xNx7 where N - number of detections.
// An every detection is a vector of values [id, classId, confidence, left, top, right, bottom]
Mat out = net.forward();
scoreDiff = scoreDiff ? scoreDiff : default_l1;
iouDiff = iouDiff ? iouDiff : default_lInf;
opencv_test::normAssertDetections(ref, out, ("model name: " + model).c_str(), 0.8, scoreDiff, iouDiff);
}
};
TEST(Test_Caffe, memory_read)
{
const std::string proto = cv::samples::findFile("dnn/bvlc_googlenet.prototxt");
const std::string model = cv::samples::findFile("dnn/bvlc_googlenet.caffemodel", false);
std::vector<char> dataProto;
readFileContent(proto, dataProto);
std::vector<char> dataModel;
readFileContent(model, dataModel);
cv::dnn::Net net = cv::dnnlegacy::readNetFromCaffe(dataProto.data(), dataProto.size());
net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
ASSERT_FALSE(net.empty());
cv::dnn::Net net2 = cv::dnnlegacy::readNetFromCaffe(dataProto.data(), dataProto.size(),
dataModel.data(), dataModel.size());
ASSERT_FALSE(net2.empty());
}
TEST(Test_Caffe, read_gtsrb)
{
cv::dnn::Net net = cv::dnnlegacy::readNetFromCaffe(_tf("gtsrb.prototxt"));
ASSERT_FALSE(net.empty());
}
TEST(Test_Caffe, read_googlenet)
{
cv::dnn::Net net = cv::dnnlegacy::readNetFromCaffe(_tf("bvlc_googlenet.prototxt"));
ASSERT_FALSE(net.empty());
}
TEST_P(Test_Caffe_nets, Axpy)
{
#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_LT(2021040000)
if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NN_BUILDER);
if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NGRAPH);
#endif
std::string proto = _tf("axpy.prototxt");
cv::dnn::Net net = cv::dnnlegacy::readNetFromCaffe(proto);
checkBackend();
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
int size[] = {1, 2, 3, 4};
int scale_size[] = {1, 2, 1, 1};
Mat scale(4, &scale_size[0], CV_32F);
Mat shift(4, &size[0], CV_32F);
Mat inp(4, &size[0], CV_32F);
randu(scale, -1.0f, 1.0f);
randu(shift, -1.0f, 1.0f);
randu(inp, -1.0f, 1.0f);
net.setInput(scale, "scale");
net.setInput(shift, "shift");
net.setInput(inp, "data");
Mat out = net.forward();
Mat ref(4, &size[0], inp.type());
for (int i = 0; i < inp.size[1]; i++) {
for (int h = 0; h < inp.size[2]; h++) {
for (int w = 0; w < inp.size[3]; w++) {
int idx[] = {0, i, h, w};
int scale_idx[] = {0, i, 0, 0};
ref.at<float>(idx) = inp.at<float>(idx) * scale.at<float>(scale_idx) +
shift.at<float>(idx);
}
}
}
float l1 = 1e-5, lInf = 1e-4;
if (target ==cv::dnn::DNN_TARGET_OPENCL_FP16 || target ==cv::dnn::DNN_TARGET_CPU_FP16)
{
l1 = 2e-4;
lInf = 1e-3;
}
if (target ==cv::dnn::DNN_TARGET_MYRIAD)
{
l1 = 0.001;
lInf = 0.001;
}
if(target ==cv::dnn::DNN_TARGET_CUDA_FP16)
{
l1 = 0.0002;
lInf = 0.0007;
}
normAssert(ref, out, "", l1, lInf);
}
typedef testing::TestWithParam<std::tuple<bool, cv::dnn::Target> > Reproducibility_AlexNet;
TEST_P(Reproducibility_AlexNet, Accuracy)
{
cv::dnn::Target targetId = get<1>(GetParam());
#if defined(OPENCV_32BIT_CONFIGURATION) && defined(HAVE_OPENCL)
applyTestTag(CV_TEST_TAG_MEMORY_2GB);
#else
applyTestTag(targetId == cv::dnn::DNN_TARGET_CPU ? CV_TEST_TAG_MEMORY_512MB : CV_TEST_TAG_MEMORY_1GB);
#endif
ASSERT_TRUE(ocl::useOpenCL() || targetId == cv::dnn::DNN_TARGET_CPU || targetId == cv::dnn::DNN_TARGET_CPU_FP16);
bool readFromMemory = get<0>(GetParam());
cv::dnn::Net net;
{
const std::string proto = cv::samples::findFile("dnn/bvlc_alexnet.prototxt");
const std::string model = cv::samples::findFile("dnn/bvlc_alexnet.caffemodel", false);
if (readFromMemory)
{
std::vector<char> dataProto;
readFileContent(proto, dataProto);
std::vector<char> dataModel;
readFileContent(model, dataModel);
net = cv::dnnlegacy::readNetFromCaffe(dataProto.data(), dataProto.size(),
dataModel.data(), dataModel.size());
}
else
net = cv::dnnlegacy::readNetFromCaffe(proto, model);
ASSERT_FALSE(net.empty());
}
// Test input layer size
/* CHANGE in getLayerShapes param in OPENCV 5
* TEST disable
std::vector<cv::dnn::MatShape> inLayerShapes;
std::vector<cv::dnn::MatShape> outLayerShapes;
net.getLayerShapes(cv::dnn::MatShape(), 0, inLayerShapes, outLayerShapes);
ASSERT_FALSE(inLayerShapes.empty());
ASSERT_EQ(inLayerShapes[0].size(), 4);
ASSERT_EQ(inLayerShapes[0][0], 1);
ASSERT_EQ(inLayerShapes[0][1], 3);
ASSERT_EQ(inLayerShapes[0][2], 227);
ASSERT_EQ(inLayerShapes[0][3], 227);
*/
const float l1 = 1e-5;
const float lInf = (targetId == cv::dnn::DNN_TARGET_OPENCL_FP16 || targetId == cv::dnn::DNN_TARGET_CPU_FP16) ? 4e-3 : 1e-4;
net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
net.setPreferableTarget(targetId);
if (targetId == cv::dnn::DNN_TARGET_CPU_FP16)
net.enableWinograd(false);
Mat sample = imread(_tf("grace_hopper_227.png"));
ASSERT_TRUE(!sample.empty());
net.setInput(cv::dnn::blobFromImage(sample, 1.0f, Size(227, 227), Scalar(), false), "data");
Mat out = net.forward("prob");
Mat ref = blobFromNPY(_tf("caffe_alexnet_prob.npy"));
normAssert(ref, out, "", l1, lInf);
}
INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_AlexNet, Combine(testing::Bool(),
testing::ValuesIn(getAvailableTargets(cv::dnn::DNN_BACKEND_OPENCV))));
TEST(Reproducibility_FCN, Accuracy)
{
applyTestTag(CV_TEST_TAG_LONG, CV_TEST_TAG_DEBUG_VERYLONG, CV_TEST_TAG_MEMORY_2GB);
cv::dnn::Net net;
{
const std::string proto = cv::samples::findFile("dnn/fcn8s-heavy-pascal.prototxt");
const std::string model = cv::samples::findFile("dnn/fcn8s-heavy-pascal.caffemodel", false);
net = dnnlegacy::readNetFromCaffe(proto, model);
ASSERT_FALSE(net.empty());
}
net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
Mat sample = imread(_tf("street.png"));
ASSERT_TRUE(!sample.empty());
std::vector<int> layerIds;
std::vector<size_t> weights, blobs;
/* CHANGE in getMemoryConsumption param in OPENCV 5
* TEST disable
net.getMemoryConsumption(cv::dnn::shape(1,3,227,227), layerIds, weights, blobs);
*/
net.setInput(cv::dnn::blobFromImage(sample, 1.0f, Size(500, 500), Scalar(), false), "data");
Mat out = net.forward("score");
Mat refData = imread(_tf("caffe_fcn8s_prob.png"), IMREAD_ANYDEPTH);
int shape[] = {1, 21, 500, 500};
Mat ref(4, shape, CV_32FC1, refData.data);
normAssert(ref, out);
}
TEST(Reproducibility_SSD, Accuracy)
{
applyTestTag(
CV_TEST_TAG_MEMORY_512MB,
CV_TEST_TAG_DEBUG_VERYLONG
);
cv::dnn::Net net;
{
const std::string proto = cv::samples::findFile("dnn/ssd_vgg16.prototxt");
const std::string model = cv::samples::findFile("dnn/VGG_ILSVRC2016_SSD_300x300_iter_440000.caffemodel", false);
net = cv::dnnlegacy::readNetFromCaffe(proto, model);
ASSERT_FALSE(net.empty());
}
net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
Mat sample = imread(_tf("street.png"));
ASSERT_TRUE(!sample.empty());
if (sample.channels() == 4)
cvtColor(sample, sample, COLOR_BGRA2BGR);
Mat in_blob = cv::dnn::blobFromImage(sample, 1.0f, Size(300, 300), Scalar(), false);
net.setInput(in_blob, "data");
Mat out = net.forward("detection_out");
Mat ref = blobFromNPY(_tf("ssd_out.npy"));
normAssertDetections(ref, out, "", 0.06);
}
typedef testing::TestWithParam<std::tuple<cv::dnn::Backend, cv::dnn::Target> > Reproducibility_MobileNet_SSD;
TEST_P(Reproducibility_MobileNet_SSD, Accuracy)
{
const std::string proto = cv::samples::findFile("dnn/MobileNetSSD_deploy_19e3ec3.prototxt", false);
const std::string model = cv::samples::findFile("dnn/MobileNetSSD_deploy_19e3ec3.caffemodel", false);
cv::dnn::Net net = cv::dnnlegacy::readNetFromCaffe(proto, model);
int backendId = get<0>(GetParam());
int targetId = get<1>(GetParam());
net.setPreferableBackend(backendId);
net.setPreferableTarget(targetId);
Mat sample = imread(_tf("street.png"));
Mat inp = cv::dnn::blobFromImage(sample, 1.0f / 127.5, Size(300, 300), Scalar(127.5, 127.5, 127.5), false);
net.setInput(inp);
Mat out = net.forward().clone();
ASSERT_EQ(out.size[2], 100);
float scores_diff = 1e-5, boxes_iou_diff = 1e-4;
if (targetId == cv::dnn::DNN_TARGET_OPENCL_FP16 || targetId == cv::dnn::DNN_TARGET_MYRIAD || targetId == cv::dnn::DNN_TARGET_CPU_FP16)
{
scores_diff = 1.5e-2;
boxes_iou_diff = 6.3e-2;
}
else if (targetId == cv::dnn::DNN_TARGET_CUDA_FP16)
{
scores_diff = 0.015;
boxes_iou_diff = 0.07;
}
Mat ref = blobFromNPY(_tf("mobilenet_ssd_caffe_out.npy"));
normAssertDetections(ref, out, "", FLT_MIN, scores_diff, boxes_iou_diff);
// Check that detections aren't preserved.
inp.setTo(0.0f);
net.setInput(inp);
Mat zerosOut = net.forward();
zerosOut = zerosOut.reshape(1, zerosOut.total() / 7);
const int numDetections = zerosOut.rows;
// TODO: fix it
if (targetId != cv::dnn::DNN_TARGET_MYRIAD ||
cv::dnn::getInferenceEngineVPUType() != CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X)
{
ASSERT_NE(numDetections, 0);
for (int i = 0; i < numDetections; ++i)
{
float confidence = zerosOut.ptr<float>(i)[2];
ASSERT_EQ(confidence, 0);
}
}
// There is something wrong with Reshape layer in Myriad plugin.
if (backendId == cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019
|| backendId == cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NGRAPH
)
{
if (targetId == cv::dnn::DNN_TARGET_MYRIAD || targetId == cv::dnn::DNN_TARGET_OPENCL_FP16)
return;
}
// Check batching mode.
inp = cv::dnn::blobFromImages(std::vector<Mat>(2, sample), 1.0f / 127.5, Size(300, 300), Scalar(127.5, 127.5, 127.5), false);
net.setInput(inp);
Mat outBatch = net.forward();
// Output blob has a shape 1x1x2Nx7 where N is a number of detection for
// a single sample in batch. The first numbers of detection vectors are batch id.
// For Inference Engine backend there is -1 delimiter which points the end of detections.
const int numRealDetections = ref.size[2];
EXPECT_EQ(outBatch.size[2], 2 * numDetections);
out = out.reshape(1, numDetections).rowRange(0, numRealDetections);
outBatch = outBatch.reshape(1, 2 * numDetections);
for (int i = 0; i < 2; ++i)
{
Mat pred = outBatch.rowRange(i * numRealDetections, (i + 1) * numRealDetections);
EXPECT_EQ(countNonZero(pred.col(0) != i), 0);
normAssert(pred.colRange(1, 7), out.colRange(1, 7));
}
}
INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_MobileNet_SSD, dnnBackendsAndTargets());
typedef testing::TestWithParam<cv::dnn::Target> Reproducibility_ResNet50;
TEST_P(Reproducibility_ResNet50, Accuracy)
{
cv::dnn::Target targetId = GetParam();
applyTestTag(targetId == cv::dnn::DNN_TARGET_CPU ? CV_TEST_TAG_MEMORY_512MB : CV_TEST_TAG_MEMORY_1GB);
ASSERT_TRUE(ocl::useOpenCL() || targetId ==cv::dnn::DNN_TARGET_CPU || targetId ==cv::dnn::DNN_TARGET_CPU_FP16);
cv::dnn::Net net = cv::dnnlegacy::readNetFromCaffe(cv::samples::findFile("dnn/ResNet-50-deploy.prototxt"),
cv::samples::findFile("dnn/ResNet-50-model.caffemodel", false));
net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
net.setPreferableTarget(targetId);
if (targetId == cv::dnn::DNN_TARGET_CPU_FP16)
net.enableWinograd(false);
float l1 = (targetId == cv::dnn::DNN_TARGET_OPENCL_FP16 || targetId == cv::dnn::DNN_TARGET_CPU_FP16) ? 3e-5 : 1e-5;
float lInf = (targetId == cv::dnn::DNN_TARGET_OPENCL_FP16 || targetId == cv::dnn::DNN_TARGET_CPU_FP16) ? 6e-3 : 1e-4;
Mat input = cv::dnn::blobFromImage(imread(_tf("googlenet_0.png")), 1.0f, Size(224,224), Scalar(), false);
ASSERT_TRUE(!input.empty());
net.setInput(input);
Mat out = net.forward();
Mat ref = blobFromNPY(_tf("resnet50_prob.npy"));
normAssert(ref, out, "", l1, lInf);
if (targetId == cv::dnn::DNN_TARGET_OPENCL || targetId == cv::dnn::DNN_TARGET_OPENCL_FP16)
{
UMat out_umat;
net.forward(out_umat);
normAssert(ref, out_umat, "out_umat", l1, lInf);
std::vector<UMat> out_umats;
net.forward(out_umats);
normAssert(ref, out_umats[0], "out_umat_vector", l1, lInf);
}
}
INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_ResNet50,
testing::ValuesIn(getAvailableTargets(cv::dnn::DNN_BACKEND_OPENCV)));
typedef testing::TestWithParam<cv::dnn::Target> Reproducibility_SqueezeNet_v1_1;
TEST_P(Reproducibility_SqueezeNet_v1_1, Accuracy)
{
int targetId = GetParam();
if(targetId == cv::dnn::DNN_TARGET_OPENCL_FP16)
applyTestTag(CV_TEST_TAG_DNN_SKIP_OPENCL_FP16);
if(targetId == cv::dnn::DNN_TARGET_CPU_FP16)
applyTestTag(CV_TEST_TAG_DNN_SKIP_CPU_FP16);
cv::dnn::Net net= cv::dnnlegacy::readNetFromCaffe(cv::samples::findFile("dnn/squeezenet_v1.1.prototxt"),
cv::samples::findFile("dnn/squeezenet_v1.1.caffemodel", false));
net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
net.setPreferableTarget(targetId);
Mat input = cv::dnn::blobFromImage(imread(_tf("googlenet_0.png")), 1.0f, Size(227,227), Scalar(), false, true);
ASSERT_TRUE(!input.empty());
Mat out;
if (targetId == cv::dnn::DNN_TARGET_OPENCL)
{
// Firstly set a wrong input blob and run the model to receive a wrong output.
// Then set a correct input blob to check CPU->GPU synchronization is working well.
net.setInput(input * 2.0f);
out = net.forward();
}
net.setInput(input);
out = net.forward();
Mat ref = blobFromNPY(_tf("squeezenet_v1.1_prob.npy"));
normAssert(ref, out);
}
INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_SqueezeNet_v1_1,
testing::ValuesIn(getAvailableTargets(cv::dnn::DNN_BACKEND_OPENCV)));
TEST(Reproducibility_AlexNet_fp16, Accuracy)
{
applyTestTag(CV_TEST_TAG_MEMORY_512MB);
const float l1 = 1e-5;
const float lInf = 3e-3;
const std::string proto = cv::samples::findFile("dnn/bvlc_alexnet.prototxt");
const std::string model = cv::samples::findFile("dnn/bvlc_alexnet.caffemodel", false);
cv::dnnlegacy::shrinkCaffeModel(model, "bvlc_alexnet.caffemodel_fp16");
cv::dnn::Net net = cv::dnnlegacy::readNetFromCaffe(proto, "bvlc_alexnet.caffemodel_fp16");
net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
Mat sample = imread(cv::samples::findFile("dnn/grace_hopper_227.png"));
net.setInput(cv::dnn::blobFromImage(sample, 1.0f, Size(227, 227), Scalar()));
Mat out = net.forward();
Mat ref = blobFromNPY(cv::samples::findFile("dnn/caffe_alexnet_prob.npy"));
normAssert(ref, out, "", l1, lInf);
}
TEST(Reproducibility_GoogLeNet_fp16, Accuracy)
{
const float l1 = 1e-5;
const float lInf = 3e-3;
const std::string proto = cv::samples::findFile("dnn/bvlc_googlenet.prototxt");
const std::string model = cv::samples::findFile("dnn/bvlc_googlenet.caffemodel", false);
shrinkCaffeModel(model, "bvlc_googlenet.caffemodel_fp16");
cv::dnn::Net net = cv::dnnlegacy::readNetFromCaffe(proto, "bvlc_googlenet.caffemodel_fp16");
net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
std::vector<Mat> inpMats;
inpMats.push_back( imread(_tf("googlenet_0.png")) );
inpMats.push_back( imread(_tf("googlenet_1.png")) );
ASSERT_TRUE(!inpMats[0].empty() && !inpMats[1].empty());
net.setInput(cv::dnn::blobFromImages(inpMats, 1.0f, Size(), Scalar(), false), "data");
Mat out = net.forward("prob");
Mat ref = blobFromNPY(_tf("googlenet_prob.npy"));
normAssert(out, ref, "", l1, lInf);
}
// https://github.com/richzhang/colorization
TEST_P(Test_Caffe_nets, Colorization)
{
applyTestTag(
target == cv::dnn::DNN_TARGET_CPU ? CV_TEST_TAG_MEMORY_512MB : CV_TEST_TAG_MEMORY_1GB,
CV_TEST_TAG_DEBUG_VERYLONG
);
checkBackend();
Mat inp = blobFromNPY(_tf("colorization_inp.npy"));
Mat ref = blobFromNPY(_tf("colorization_out.npy"));
Mat kernel = blobFromNPY(_tf("colorization_pts_in_hull.npy"));
const std::string proto = cv::samples::findFile("dnn/colorization_deploy_v2.prototxt", false);
const std::string model = cv::samples::findFile("dnn/colorization_release_v2.caffemodel", false);
cv::dnn::Net net = cv::dnnlegacy::readNetFromCaffe(proto, model);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
// This model has bad accuracy when the FP16 and Winograd are enable at same time.
if (target == cv::dnn::DNN_TARGET_CPU_FP16)
net.enableWinograd(false);
net.getLayer(net.getLayerId("class8_ab"))->blobs.push_back(kernel);
net.getLayer(net.getLayerId("conv8_313_rh"))->blobs.push_back(Mat(1, 313, CV_32F, 2.606));
net.setInput(inp);
Mat out = net.forward();
// Reference output values are in range [-29.1, 69.5]
double l1 = 4e-4, lInf = 3e-3;
if (target == cv::dnn::DNN_TARGET_OPENCL_FP16 || target == cv::dnn::DNN_TARGET_CPU_FP16)
{
l1 = 0.25;
lInf = 5.3;
}
else if (target == cv::dnn::DNN_TARGET_MYRIAD)
{
l1 = (cv::dnn::getInferenceEngineVPUType() == CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X) ? 0.5 : 0.25;
lInf = (cv::dnn::getInferenceEngineVPUType() == CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X) ? 11 : 5.3;
}
else if(target == cv::dnn::DNN_TARGET_CUDA_FP16)
{
l1 = 0.21;
lInf = 4.5;
}
#if defined(INF_ENGINE_RELEASE)
if (backend == cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target == cv::dnn::DNN_TARGET_OPENCL_FP16)
{
l1 = 0.3; lInf = 10;
}
#endif
normAssert(out, ref, "", l1, lInf);
expectNoFallbacksFromIE(net);
}
TEST_P(Test_Caffe_nets, DenseNet_121)
{
applyTestTag(CV_TEST_TAG_MEMORY_512MB);
checkBackend();
const std::string proto = cv::samples::findFile("dnn/DenseNet_121.prototxt", false);
const std::string weights = cv::samples::findFile("dnn/DenseNet_121.caffemodel", false);
Mat inp = imread(_tf("dog416.png"));
cv::dnn::Model model(proto, weights);
model.setInputScale(1.0 / 255).setInputSwapRB(true).setInputCrop(true);
std::vector<Mat> outs;
Mat ref = blobFromNPY(_tf("densenet_121_output.npy"));
model.setPreferableBackend(backend);
model.setPreferableTarget(target);
model.predict(inp, outs);
// Reference is an array of 1000 values from a range [-6.16, 7.9]
float l1 = default_l1, lInf = default_lInf;
if (target == cv::dnn::DNN_TARGET_OPENCL_FP16)
{
#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_GE(2019020000)
l1 = 0.05; lInf = 0.3;
#else
l1 = 0.017; lInf = 0.0795;
#endif
}
else if (target == cv::dnn::DNN_TARGET_MYRIAD)
{
l1 = 0.11; lInf = 0.5;
}
else if (target == cv::dnn::DNN_TARGET_CUDA_FP16)
{
l1 = 0.04; lInf = 0.2;
}
else if (target == cv::dnn::DNN_TARGET_CPU_FP16)
{
l1 = 0.06; lInf = 0.3;
}
normAssert(outs[0], ref, "", l1, lInf);
if (target != cv::dnn::DNN_TARGET_MYRIAD || cv::dnn::getInferenceEngineVPUType() != CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X)
expectNoFallbacksFromIE(model.getNetwork_());
}
TEST(Test_Caffe, multiple_inputs)
{
const std::string proto = cv::samples::findFile("dnn/layers/net_input.prototxt");
cv::dnn::Net net = cv::dnnlegacy::readNetFromCaffe(proto);
net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
Mat first_image(10, 11, CV_32FC3);
Mat second_image(10, 11, CV_32FC3);
randu(first_image, -1, 1);
randu(second_image, -1, 1);
first_image = cv::dnn::blobFromImage(first_image);
second_image = cv::dnn::blobFromImage(second_image);
Mat first_image_blue_green = cv::dnn::slice(first_image, Range::all(), Range(0, 2), Range::all(), Range::all());
Mat first_image_red = cv::dnn::slice(first_image, Range::all(), Range(2, 3), Range::all(), Range::all());
Mat second_image_blue_green = cv::dnn::slice(second_image, Range::all(), Range(0, 2), Range::all(), Range::all());
Mat second_image_red = cv::dnn::slice(second_image, Range::all(), Range(2, 3), Range::all(), Range::all());
net.setInput(first_image_blue_green, "old_style_input_blue_green");
net.setInput(first_image_red, "different_name_for_red");
net.setInput(second_image_blue_green, "input_layer_blue_green");
net.setInput(second_image_red, "old_style_input_red");
Mat out = net.forward();
normAssert(out, first_image + second_image);
}
TEST(Test_Caffe, shared_weights)
{
const std::string proto = cv::samples::findFile("dnn/layers/shared_weights.prototxt");
const std::string model = cv::samples::findFile("dnn/layers/shared_weights.caffemodel");
cv::dnn::Net net = cv::dnnlegacy::readNetFromCaffe(proto, model);
Mat input_1 = (Mat_<float>(2, 2) << 0., 2., 4., 6.);
Mat input_2 = (Mat_<float>(2, 2) << 1., 3., 5., 7.);
Mat blob_1 = cv::dnn::blobFromImage(input_1);
Mat blob_2 = cv::dnn::blobFromImage(input_2);
net.setInput(blob_1, "input_1");
net.setInput(blob_2, "input_2");
net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
Mat sum = net.forward();
EXPECT_EQ(sum.at<float>(0,0), 12.);
EXPECT_EQ(sum.at<float>(0,1), 16.);
}
typedef testing::TestWithParam<std::tuple<std::string, cv::dnn::Target> > opencv_face_detector;
TEST_P(opencv_face_detector, Accuracy)
{
std::string proto = cv::samples::findFile("dnn/opencv_face_detector.prototxt");
std::string model = cv::samples::findFile(get<0>(GetParam()), false);
cv::dnn::Target targetId = (cv::dnn::Target)(int)get<1>(GetParam());
if (targetId == cv::dnn::DNN_TARGET_OPENCL_FP16)
applyTestTag(CV_TEST_TAG_DNN_SKIP_OPENCL_FP16);
if (targetId == cv::dnn::DNN_TARGET_CPU_FP16)
applyTestTag(CV_TEST_TAG_DNN_SKIP_CPU_FP16);
cv::dnn::Net net = cv::dnnlegacy::readNetFromCaffe(proto, model);
Mat img = imread(cv::samples::findFile("gpu/lbpcascade/er.png"));
Mat blob = cv::dnn::blobFromImage(img, 1.0, Size(), Scalar(104.0, 177.0, 123.0), false, false);
net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
net.setPreferableTarget(targetId);
net.setInput(blob);
// Output has shape 1x1xNx7 where N - number of detections.
// An every detection is a vector of values [id, classId, confidence, left, top, right, bottom]
Mat out = net.forward();
Mat ref = (Mat_<float>(6, 7) << 0, 1, 0.99520785, 0.80997437, 0.16379407, 0.87996572, 0.26685631,
0, 1, 0.9934696, 0.2831718, 0.50738752, 0.345781, 0.5985168,
0, 1, 0.99096733, 0.13629119, 0.24892329, 0.19756334, 0.3310290,
0, 1, 0.98977017, 0.23901358, 0.09084064, 0.29902688, 0.1769477,
0, 1, 0.97203469, 0.67965847, 0.06876482, 0.73999709, 0.1513494,
0, 1, 0.95097077, 0.51901293, 0.45863652, 0.5777427, 0.5347801);
normAssertDetections(ref, out, "", 0.5, 1e-4, 2e-4);
}
// False positives bug for large faces: https://github.com/opencv/opencv/issues/15106
TEST_P(opencv_face_detector, issue_15106)
{
std::string proto = cv::samples::findFile("dnn/opencv_face_detector.prototxt");
std::string model = cv::samples::findFile(get<0>(GetParam()), false);
cv::dnn::Target targetId = (cv::dnn::Target)(int)get<1>(GetParam());
if (targetId == cv::dnn::DNN_TARGET_OPENCL_FP16)
applyTestTag(CV_TEST_TAG_DNN_SKIP_OPENCL_FP16);
if (targetId == cv::dnn::DNN_TARGET_CPU_FP16)
applyTestTag(CV_TEST_TAG_DNN_SKIP_CPU_FP16);
cv::dnn::Net net = cv::dnnlegacy::readNetFromCaffe(proto, model);
Mat img = imread(cv::samples::findFile("cv/shared/lena.png"));
img = img.rowRange(img.rows / 4, 3 * img.rows / 4).colRange(img.cols / 4, 3 * img.cols / 4);
Mat blob = cv::dnn::blobFromImage(img, 1.0, Size(300, 300), Scalar(104.0, 177.0, 123.0), false, false);
net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
net.setPreferableTarget(targetId);
net.setInput(blob);
// Output has shape 1x1xNx7 where N - number of detections.
// An every detection is a vector of values [id, classId, confidence, left, top, right, bottom]
Mat out = net.forward();
Mat ref = (Mat_<float>(1, 7) << 0, 1, 0.9149431, 0.30424616, 0.26964942, 0.88733053, 0.99815309);
normAssertDetections(ref, out, "", 0.89, 6e-5, 1e-4);
}
INSTANTIATE_TEST_CASE_P(Test_Caffe, opencv_face_detector,
Combine(
Values("dnn/opencv_face_detector.caffemodel",
"dnn/opencv_face_detector_fp16.caffemodel"),
testing::ValuesIn(getAvailableTargets(cv::dnn::DNN_BACKEND_OPENCV))
)
);
TEST_P(Test_Caffe_nets, FasterRCNN_vgg16)
{
applyTestTag(
#if defined(OPENCV_32BIT_CONFIGURATION) && defined(HAVE_OPENCL)
CV_TEST_TAG_MEMORY_2GB, // utilizes ~1Gb, but huge blobs may not be allocated on 32-bit systems due memory fragmentation
#else
CV_TEST_TAG_MEMORY_2GB,
#endif
CV_TEST_TAG_LONG,
CV_TEST_TAG_DEBUG_VERYLONG
);
#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_LT(2021040000)
if ((backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 || backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) && (target ==cv::dnn::DNN_TARGET_OPENCL || target ==cv::dnn::DNN_TARGET_OPENCL_FP16))
applyTestTag(target ==cv::dnn::DNN_TARGET_OPENCL ? CV_TEST_TAG_DNN_SKIP_IE_OPENCL : CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16);
if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION);
if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && target ==cv::dnn::DNN_TARGET_MYRIAD)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD);
#endif
#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021040000)
// IE exception: Ngraph operation Reshape with name rpn_cls_score_reshape has dynamic output shape on 0 port, but CPU plug-in supports only static shape
if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && (target ==cv::dnn::DNN_TARGET_OPENCL || target ==cv::dnn::DNN_TARGET_OPENCL_FP16))
applyTestTag(target ==cv::dnn::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
);
// Check 'backward_compatible_check || in_out_elements_equal' failed at core/src/op/reshape.cpp:390:
// While validating node 'v1::Reshape bbox_pred_reshape (bbox_pred[0]:f32{1,84}, Constant_241202[0]:i64{4}) -> (f32{?,?,?,?})' with friendly_name 'bbox_pred_reshape':
// Requested output shape {1,6300,4,1} is incompatible with input shape Shape{1, 84}
if (target ==cv::dnn::DNN_TARGET_MYRIAD)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION);
#endif
double scoreDiff = 0.0012, iouDiff = 0.03;
#if defined(INF_ENGINE_RELEASE)
if (target ==cv::dnn::DNN_TARGET_MYRIAD)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION);
if (backend == cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) {
iouDiff = 0.02;
if (target ==cv::dnn::DNN_TARGET_OPENCL || target ==cv::dnn::DNN_TARGET_OPENCL_FP16) {
scoreDiff = 0.04;
iouDiff = 0.06;
}
}
#endif
static Mat ref = (Mat_<float>(3, 7) << 0, 2, 0.949398, 99.2454, 210.141, 601.205, 462.849,
0, 7, 0.997022, 481.841, 92.3218, 722.685, 175.953,
0, 12, 0.993028, 133.221, 189.377, 350.994, 563.166);
testFaster("faster_rcnn_vgg16.prototxt", "VGG16_faster_rcnn_final.caffemodel", ref, scoreDiff, iouDiff);
}
TEST_P(Test_Caffe_nets, FasterRCNN_zf)
{
applyTestTag(
#if defined(OPENCV_32BIT_CONFIGURATION) && defined(HAVE_OPENCL)
CV_TEST_TAG_MEMORY_2GB,
#else
(target ==cv::dnn::DNN_TARGET_CPU ? CV_TEST_TAG_MEMORY_512MB : CV_TEST_TAG_MEMORY_1GB),
#endif
CV_TEST_TAG_DEBUG_VERYLONG
);
#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021040000)
// IE exception: Ngraph operation Reshape with name rpn_cls_score_reshape has dynamic output shape on 0 port, but CPU plug-in supports only static shape
if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && (target ==cv::dnn::DNN_TARGET_OPENCL || target ==cv::dnn::DNN_TARGET_OPENCL_FP16))
applyTestTag(target ==cv::dnn::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
);
#endif
if ((backend == cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 ||
backend == cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) && target ==cv::dnn::DNN_TARGET_MYRIAD)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD);
if (target ==cv::dnn::DNN_TARGET_CUDA_FP16)
applyTestTag(CV_TEST_TAG_DNN_SKIP_CUDA_FP16);
if (target ==cv::dnn::DNN_TARGET_CPU_FP16)
applyTestTag(CV_TEST_TAG_DNN_SKIP_CPU_FP16);
static Mat ref = (Mat_<float>(3, 7) << 0, 2, 0.90121, 120.407, 115.83, 570.586, 528.395,
0, 7, 0.988779, 469.849, 75.1756, 718.64, 186.762,
0, 12, 0.967198, 138.588, 206.843, 329.766, 553.176);
double scoreDiff = 0.003, iouDiff = 0.07;
if (backend == cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) {
scoreDiff = 0.02;
iouDiff = 0.13;
}
testFaster("faster_rcnn_zf.prototxt", "ZF_faster_rcnn_final.caffemodel", ref, scoreDiff, iouDiff);
}
TEST_P(Test_Caffe_nets, RFCN)
{
applyTestTag(
(target ==cv::dnn::DNN_TARGET_CPU ? CV_TEST_TAG_MEMORY_512MB : CV_TEST_TAG_MEMORY_2GB),
CV_TEST_TAG_LONG,
CV_TEST_TAG_DEBUG_VERYLONG
);
float scoreDiff = default_l1, iouDiff = default_lInf;
if (backend == cv::dnn::DNN_BACKEND_OPENCV && (target ==cv::dnn::DNN_TARGET_OPENCL_FP16 || target ==cv::dnn::DNN_TARGET_CPU_FP16))
{
scoreDiff = 4e-3;
iouDiff = 8e-2;
}
if (target ==cv::dnn::DNN_TARGET_CUDA_FP16)
{
scoreDiff = 0.0034;
iouDiff = 0.12;
}
#if defined(INF_ENGINE_RELEASE)
if (backend == cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
{
scoreDiff = 0.1f;
iouDiff = 0.2f;
}
// Check 'backward_compatible_check || in_out_elements_equal' failed at core/src/op/reshape.cpp:427:
// While validating node 'v1::Reshape bbox_pred_reshape (ave_bbox_pred_rois[0]:f32{1,8,1,1}, Constant_388[0]:i64{4}) -> (f32{?,?,?,?})' with friendly_name 'bbox_pred_reshape':
// Requested output shape {1,300,8,1} is incompatible with input shape {1, 8, 1, 1}
if (backend == cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target ==cv::dnn::DNN_TARGET_MYRIAD)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION);
#elif defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_EQ(2021040000)
// Exception: Function contains several inputs and outputs with one friendly name! (HETERO bug?)
if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && target !=cv::dnn::DNN_TARGET_CPU)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NGRAPH, CV_TEST_TAG_DNN_SKIP_IE_VERSION);
#elif defined(INF_ENGINE_RELEASE)
if ((backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 ||
backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) && target ==cv::dnn::DNN_TARGET_OPENCL_FP16)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16);
if ((backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 ||
backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) && target ==cv::dnn::DNN_TARGET_MYRIAD)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD);
#endif
static Mat ref = (Mat_<float>(2, 7) << 0, 7, 0.991359, 491.822, 81.1668, 702.573, 178.234,
0, 12, 0.94786, 132.093, 223.903, 338.077, 566.16);
testFaster("rfcn_pascal_voc_resnet50.prototxt", "resnet50_rfcn_final.caffemodel", ref, scoreDiff, iouDiff);
}
INSTANTIATE_TEST_CASE_P(/**/, Test_Caffe_nets, dnnBackendsAndTargets());
}} // namespace

@ -0,0 +1,6 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#include "test_common.impl.hpp" // shared with perf tests

@ -0,0 +1,246 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef __OPENCV_TEST_DNNLEGACY_COMMON_HPP__
#define __OPENCV_TEST_DNNLEGACY_COMMON_HPP__
#include <tuple>
#include "opencv2/dnn/utils/inference_engine.hpp"
#ifdef HAVE_OPENCL
#include "opencv2/core/ocl.hpp"
#endif
// src/op_inf_engine.hpp
#define INF_ENGINE_VER_MAJOR_GT(ver) (((INF_ENGINE_RELEASE) / 10000) > ((ver) / 10000))
#define INF_ENGINE_VER_MAJOR_GE(ver) (((INF_ENGINE_RELEASE) / 10000) >= ((ver) / 10000))
#define INF_ENGINE_VER_MAJOR_LT(ver) (((INF_ENGINE_RELEASE) / 10000) < ((ver) / 10000))
#define INF_ENGINE_VER_MAJOR_LE(ver) (((INF_ENGINE_RELEASE) / 10000) <= ((ver) / 10000))
#define INF_ENGINE_VER_MAJOR_EQ(ver) (((INF_ENGINE_RELEASE) / 10000) == ((ver) / 10000))
#define CV_TEST_TAG_DNN_SKIP_OPENCV_BACKEND "dnnlegacy_skip_opencv_backend"
#define CV_TEST_TAG_DNN_SKIP_HALIDE "dnnlegacy_skip_halide"
#define CV_TEST_TAG_DNN_SKIP_CPU "dnnlegacy_skip_cpu"
#define CV_TEST_TAG_DNN_SKIP_CPU_FP16 "dnnlegacy_skip_cpu_fp16"
#define CV_TEST_TAG_DNN_SKIP_OPENCL "dnnlegacy_skip_ocl"
#define CV_TEST_TAG_DNN_SKIP_OPENCL_FP16 "dnnlegacy_skip_ocl_fp16"
#define CV_TEST_TAG_DNN_SKIP_IE_NN_BUILDER "dnnlegacy_skip_ie_nn_builder"
#define CV_TEST_TAG_DNN_SKIP_IE_NGRAPH "dnnlegacy_skip_ie_ngraph"
#define CV_TEST_TAG_DNN_SKIP_IE "dnnlegacy_skip_ie"
#define CV_TEST_TAG_DNN_SKIP_IE_2018R5 "dnnlegacy_skip_ie_2018r5"
#define CV_TEST_TAG_DNN_SKIP_IE_2019R1 "dnnlegacy_skip_ie_2019r1"
#define CV_TEST_TAG_DNN_SKIP_IE_2019R1_1 "dnnlegacy_skip_ie_2019r1_1"
#define CV_TEST_TAG_DNN_SKIP_IE_2019R2 "dnnlegacy_skip_ie_2019r2"
#define CV_TEST_TAG_DNN_SKIP_IE_2019R3 "dnnlegacy_skip_ie_2019r3"
#define CV_TEST_TAG_DNN_SKIP_IE_CPU "dnnlegacy_skip_ie_cpu"
#define CV_TEST_TAG_DNN_SKIP_IE_OPENCL "dnnlegacy_skip_ie_ocl"
#define CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16 "dnnlegacy_skip_ie_ocl_fp16"
#define CV_TEST_TAG_DNN_SKIP_IE_MYRIAD_2 "dnnlegacy_skip_ie_myriad2"
#define CV_TEST_TAG_DNN_SKIP_IE_MYRIAD_X "dnnlegacy_skip_ie_myriadx"
#define CV_TEST_TAG_DNN_SKIP_IE_MYRIAD CV_TEST_TAG_DNN_SKIP_IE_MYRIAD_2, CV_TEST_TAG_DNN_SKIP_IE_MYRIAD_X
#define CV_TEST_TAG_DNN_SKIP_IE_ARM_CPU "dnnlegacy_skip_ie_arm_cpu"
#define CV_TEST_TAG_DNN_SKIP_VULKAN "dnnlegacy_skip_vulkan"
#define CV_TEST_TAG_DNN_SKIP_CUDA "dnnlegacy_skip_cuda"
#define CV_TEST_TAG_DNN_SKIP_CUDA_FP16 "dnnlegacy_skip_cuda_fp16"
#define CV_TEST_TAG_DNN_SKIP_CUDA_FP32 "dnnlegacy_skip_cuda_fp32"
#define CV_TEST_TAG_DNN_SKIP_ONNX_CONFORMANCE "dnnlegacy_skip_onnx_conformance"
#define CV_TEST_TAG_DNN_SKIP_PARSER "dnnlegacy_skip_parser"
#define CV_TEST_TAG_DNN_SKIP_GLOBAL "dnnlegacy_skip_global"
#define CV_TEST_TAG_DNN_SKIP_TIMVX "dnnlegacy_skip_timvx"
#define CV_TEST_TAG_DNN_SKIP_CANN "dnnlegacy_skip_cann"
#ifdef HAVE_INF_ENGINE
#if INF_ENGINE_VER_MAJOR_EQ(2018050000)
# define CV_TEST_TAG_DNN_SKIP_IE_VERSION CV_TEST_TAG_DNN_SKIP_IE, CV_TEST_TAG_DNN_SKIP_IE_2018R5
#elif INF_ENGINE_VER_MAJOR_EQ(2019010000)
# if INF_ENGINE_RELEASE < 2019010100
# define CV_TEST_TAG_DNN_SKIP_IE_VERSION CV_TEST_TAG_DNN_SKIP_IE, CV_TEST_TAG_DNN_SKIP_IE_2019R1
# else
# define CV_TEST_TAG_DNN_SKIP_IE_VERSION CV_TEST_TAG_DNN_SKIP_IE, CV_TEST_TAG_DNN_SKIP_IE_2019R1_1
# endif
#elif INF_ENGINE_VER_MAJOR_EQ(2019020000)
# define CV_TEST_TAG_DNN_SKIP_IE_VERSION CV_TEST_TAG_DNN_SKIP_IE, CV_TEST_TAG_DNN_SKIP_IE_2019R2
#elif INF_ENGINE_VER_MAJOR_EQ(2019030000)
# define CV_TEST_TAG_DNN_SKIP_IE_VERSION CV_TEST_TAG_DNN_SKIP_IE, CV_TEST_TAG_DNN_SKIP_IE_2019R3
#endif
#endif // HAVE_INF_ENGINE
#ifndef CV_TEST_TAG_DNN_SKIP_IE_VERSION
# define CV_TEST_TAG_DNN_SKIP_IE_VERSION CV_TEST_TAG_DNN_SKIP_IE
#endif
namespace cv { namespace dnnlegacy {
void PrintTo(const cv::dnn::Backend& v, std::ostream* os);
void PrintTo(const cv::dnn::Target& v, std::ostream* os);
using opencv_test::tuple;
using opencv_test::get;
void PrintTo(const tuple<cv::dnn::Backend, cv::dnn::Target> v, std::ostream* os);
}} // namespace cv::dnn
namespace opencv_test {
void initDNNTests();
using namespace cv::dnnlegacy;
static inline const std::string& getOpenCVExtraDir()
{
return cvtest::TS::ptr()->get_data_path();
}
void normAssert(
cv::InputArray ref, cv::InputArray test, const char* comment = "",
double l1 = 0.00001, double lInf = 0.0001);
std::vector<cv::Rect2d> matToBoxes(const cv::Mat& m);
void normAssertDetections(
const std::vector<int>& refClassIds,
const std::vector<float>& refScores,
const std::vector<cv::Rect2d>& refBoxes,
const std::vector<int>& testClassIds,
const std::vector<float>& testScores,
const std::vector<cv::Rect2d>& testBoxes,
const char* comment = "", double confThreshold = 0.0,
double scores_diff = 1e-5, double boxes_iou_diff = 1e-4);
// For SSD-based object detection networks which produce output of shape 1x1xNx7
// where N is a number of detections and an every detection is represented by
// a vector [batchId, classId, confidence, left, top, right, bottom].
void normAssertDetections(
cv::Mat ref, cv::Mat out, const char* comment = "",
double confThreshold = 0.0, double scores_diff = 1e-5,
double boxes_iou_diff = 1e-4);
// For text detection networks
// Curved text polygon is not supported in the current version.
// (concave polygon is invalid input to intersectConvexConvex)
void normAssertTextDetections(
const std::vector<std::vector<cv::Point>>& gtPolys,
const std::vector<std::vector<cv::Point>>& testPolys,
const char* comment = "", double boxes_iou_diff = 1e-4);
void readFileContent(const std::string& filename, CV_OUT std::vector<char>& content);
bool validateVPUType();
testing::internal::ParamGenerator< std::tuple<cv::dnn::Backend, cv::dnn::Target> > dnnBackendsAndTargets(
bool withInferenceEngine = true,
bool withHalide = false,
bool withCpuOCV = true,
bool withVkCom = true,
bool withCUDA = true,
bool withNgraph = true,
bool withWebnn = true,
bool withCann = true
);
testing::internal::ParamGenerator< std::tuple<cv::dnn::Backend, cv::dnn::Target> > dnnBackendsAndTargetsIE();
class DNNlegacyTestLayer : public TestWithParam< std::tuple<cv::dnn::Backend, cv::dnn::Target> >
{
public:
cv::dnn::Backend backend;
cv::dnn::Target target;
double default_l1, default_lInf;
DNNlegacyTestLayer()
{
backend = (cv::dnn::Backend)(int)get<0>(GetParam());
target = (cv::dnn::Target)(int)get<1>(GetParam());
getDefaultThresholds(backend, target, &default_l1, &default_lInf);
}
static void getDefaultThresholds(int backend, int target, double* l1, double* lInf)
{
if (target == cv::dnn::DNN_TARGET_CPU_FP16 || target == cv::dnn::DNN_TARGET_CUDA_FP16 || target == cv::dnn::DNN_TARGET_OPENCL_FP16 || target == cv::dnn::DNN_TARGET_MYRIAD)
{
*l1 = 4e-3;
*lInf = 2e-2;
}
else
{
*l1 = 1e-5;
*lInf = 1e-4;
}
}
static void checkBackend(int backend, int target, cv::Mat* inp = 0, cv::Mat* ref = 0)
{
CV_UNUSED(backend); CV_UNUSED(target); CV_UNUSED(inp); CV_UNUSED(ref);
#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_LT(2021000000)
if ((backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 || backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
&& target == DNN_TARGET_MYRIAD)
{
if (inp && ref && inp->dims == 4 && ref->dims == 4 &&
inp->size[0] != 1 && inp->size[0] != ref->size[0])
{
std::cout << "Inconsistent batch size of input and output blobs for Myriad plugin" << std::endl;
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD);
}
}
#endif
}
void expectNoFallbacks(cv::dnn::Net& net, bool raiseError = true)
{
// Check if all the layers are supported with current backend and target.
// Some layers might be fused so their timings equal to zero.
std::vector<double> timings;
net.getPerfProfile(timings);
std::vector<String> names = net.getLayerNames();
CV_Assert(names.size() == timings.size());
bool hasFallbacks = false;
for (int i = 0; i < names.size(); ++i)
{
Ptr<dnn::Layer> l = net.getLayer(net.getLayerId(names[i]));
bool fused = !timings[i];
if ((!l->supportBackend(backend) || l->preferableTarget != target) && !fused)
{
hasFallbacks = true;
std::cout << "FALLBACK: Layer [" << l->type << "]:[" << l->name << "] is expected to has backend implementation" << endl;
}
}
if (hasFallbacks && raiseError)
CV_Error(Error::StsNotImplemented, "Implementation fallbacks are not expected in this test");
}
void expectNoFallbacksFromIE(cv::dnn::Net& net)
{
if (backend == cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019)
expectNoFallbacks(net);
if (backend == cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
expectNoFallbacks(net, false);
}
void expectNoFallbacksFromCUDA(cv::dnn::Net& net)
{
if (backend == cv::dnn::DNN_BACKEND_CUDA)
expectNoFallbacks(net);
}
size_t getTopMemoryUsageMB();
protected:
void checkBackend(cv::Mat* inp = 0, cv::Mat* ref = 0)
{
checkBackend(backend, target, inp, ref);
}
};
} // namespace
#endif

@ -0,0 +1,540 @@
// 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.
// Used in accuracy and perf tests as a content of .cpp file
// Note: don't use "precomp.hpp" here
#include "opencv2/ts.hpp"
#include "opencv2/ts/ts_perf.hpp"
#include "opencv2/core/utility.hpp"
#include "opencv2/core/ocl.hpp"
#include "opencv2/dnnlegacy.hpp"
#include "test_common.hpp"
#include <opencv2/core/utils/configuration.private.hpp>
#include <opencv2/core/utils/logger.hpp>
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#include <psapi.h>
#endif // _WIN32
namespace cv { namespace dnnlegacy {
CV__DNN_INLINE_NS_BEGIN
void PrintTo(const cv::dnn::Backend& v, std::ostream* os)
{
switch (v) {
case cv::dnn::DNN_BACKEND_DEFAULT: *os << "DEFAULT"; return;
/* remove in opencv 5.0
case cv::dnn::DNN_BACKEND_HALIDE: *os << "HALIDE"; return;
*/
case cv::dnn::DNN_BACKEND_INFERENCE_ENGINE: *os << "DLIE*"; return;
case cv::dnn::DNN_BACKEND_VKCOM: *os << "VKCOM"; return;
case cv::dnn::DNN_BACKEND_OPENCV: *os << "OCV"; return;
case cv::dnn::DNN_BACKEND_CUDA: *os << "CUDA"; return;
case cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019: *os << "DLIE"; return;
case cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NGRAPH: *os << "NGRAPH"; return;
case cv::dnn::DNN_BACKEND_WEBNN: *os << "WEBNN"; return;
case cv::dnn::DNN_BACKEND_TIMVX: *os << "TIMVX"; return;
case cv::dnn::DNN_BACKEND_CANN: *os << "CANN"; return;
} // don't use "default:" to emit compiler warnings
*os << "cv::dnn::DNN_BACKEND_UNKNOWN(" << (int)v << ")";
}
void PrintTo(const cv::dnn::Target& v, std::ostream* os)
{
switch (v) {
case cv::dnn::DNN_TARGET_CPU: *os << "CPU"; return;
case cv::dnn::DNN_TARGET_OPENCL: *os << "OCL"; return;
case cv::dnn::DNN_TARGET_OPENCL_FP16: *os << "OCL_FP16"; return;
case cv::dnn::DNN_TARGET_MYRIAD: *os << "MYRIAD"; return;
case cv::dnn::DNN_TARGET_HDDL: *os << "HDDL"; return;
case cv::dnn::DNN_TARGET_VULKAN: *os << "VULKAN"; return;
case cv::dnn::DNN_TARGET_FPGA: *os << "FPGA"; return;
case cv::dnn::DNN_TARGET_CUDA: *os << "CUDA"; return;
case cv::dnn::DNN_TARGET_CUDA_FP16: *os << "CUDA_FP16"; return;
case cv::dnn::DNN_TARGET_NPU: *os << "NPU"; return;
case cv::dnn::DNN_TARGET_CPU_FP16: *os << "CPU_FP16"; return;
} // don't use "default:" to emit compiler warnings
*os << "cv::dnn::DNN_TARGET_UNKNOWN(" << (int)v << ")";
}
void PrintTo(const tuple<cv::dnn::Backend, cv::dnn::Target> v, std::ostream* os)
{
PrintTo(get<0>(v), os);
*os << "/";
PrintTo(get<1>(v), os);
}
CV__DNN_INLINE_NS_END
}} // namespace
namespace opencv_test {
void normAssert(
cv::InputArray ref, cv::InputArray test, const char *comment /*= ""*/,
double l1 /*= 0.00001*/, double lInf /*= 0.0001*/)
{
double normL1 = cvtest::norm(ref, test, cv::NORM_L1) / ref.getMat().total();
EXPECT_LE(normL1, l1) << comment << " |ref| = " << cvtest::norm(ref, cv::NORM_INF);
double normInf = cvtest::norm(ref, test, cv::NORM_INF);
EXPECT_LE(normInf, lInf) << comment << " |ref| = " << cvtest::norm(ref, cv::NORM_INF);
}
std::vector<cv::Rect2d> matToBoxes(const cv::Mat& m)
{
EXPECT_EQ(m.type(), CV_32FC1);
EXPECT_EQ(m.dims, 2);
EXPECT_EQ(m.cols, 4);
std::vector<cv::Rect2d> boxes(m.rows);
for (int i = 0; i < m.rows; ++i)
{
CV_Assert(m.row(i).isContinuous());
const float* data = m.ptr<float>(i);
double l = data[0], t = data[1], r = data[2], b = data[3];
boxes[i] = cv::Rect2d(l, t, r - l, b - t);
}
return boxes;
}
void normAssertDetections(
const std::vector<int>& refClassIds,
const std::vector<float>& refScores,
const std::vector<cv::Rect2d>& refBoxes,
const std::vector<int>& testClassIds,
const std::vector<float>& testScores,
const std::vector<cv::Rect2d>& testBoxes,
const char *comment /*= ""*/, double confThreshold /*= 0.0*/,
double scores_diff /*= 1e-5*/, double boxes_iou_diff /*= 1e-4*/)
{
ASSERT_FALSE(testClassIds.empty()) << "No detections";
std::vector<bool> matchedRefBoxes(refBoxes.size(), false);
std::vector<double> refBoxesIoUDiff(refBoxes.size(), 1.0);
for (int i = 0; i < testBoxes.size(); ++i)
{
//cout << "Test[i=" << i << "]: score=" << testScores[i] << " id=" << testClassIds[i] << " box " << testBoxes[i] << endl;
double testScore = testScores[i];
if (testScore < confThreshold)
continue;
int testClassId = testClassIds[i];
const cv::Rect2d& testBox = testBoxes[i];
bool matched = false;
double topIoU = 0;
for (int j = 0; j < refBoxes.size() && !matched; ++j)
{
if (!matchedRefBoxes[j] && testClassId == refClassIds[j] &&
std::abs(testScore - refScores[j]) < scores_diff)
{
double interArea = (testBox & refBoxes[j]).area();
double iou = interArea / (testBox.area() + refBoxes[j].area() - interArea);
topIoU = std::max(topIoU, iou);
refBoxesIoUDiff[j] = std::min(refBoxesIoUDiff[j], 1.0f - iou);
if (1.0 - iou < boxes_iou_diff)
{
matched = true;
matchedRefBoxes[j] = true;
}
}
}
if (!matched)
{
std::cout << cv::format("Unmatched prediction: class %d score %f box ",
testClassId, testScore) << testBox << std::endl;
std::cout << "Highest IoU: " << topIoU << std::endl;
}
EXPECT_TRUE(matched) << comment;
}
// Check unmatched reference detections.
for (int i = 0; i < refBoxes.size(); ++i)
{
if (!matchedRefBoxes[i] && refScores[i] > confThreshold)
{
std::cout << cv::format("Unmatched reference: class %d score %f box ",
refClassIds[i], refScores[i]) << refBoxes[i]
<< " IoU diff: " << refBoxesIoUDiff[i]
<< std::endl;
EXPECT_LE(refScores[i], confThreshold) << comment;
}
}
}
// For SSD-based object detection networks which produce output of shape 1x1xNx7
// where N is a number of detections and an every detection is represented by
// a vector [batchId, classId, confidence, left, top, right, bottom].
void normAssertDetections(
cv::Mat ref, cv::Mat out, const char *comment /*= ""*/,
double confThreshold /*= 0.0*/, double scores_diff /*= 1e-5*/,
double boxes_iou_diff /*= 1e-4*/)
{
CV_Assert(ref.total() % 7 == 0);
CV_Assert(out.total() % 7 == 0);
ref = ref.reshape(1, ref.total() / 7);
out = out.reshape(1, out.total() / 7);
cv::Mat refClassIds, testClassIds;
ref.col(1).convertTo(refClassIds, CV_32SC1);
out.col(1).convertTo(testClassIds, CV_32SC1);
std::vector<float> refScores(ref.col(2)), testScores(out.col(2));
std::vector<cv::Rect2d> refBoxes = matToBoxes(ref.colRange(3, 7));
std::vector<cv::Rect2d> testBoxes = matToBoxes(out.colRange(3, 7));
normAssertDetections(refClassIds, refScores, refBoxes, testClassIds, testScores,
testBoxes, comment, confThreshold, scores_diff, boxes_iou_diff);
}
// For text detection networks
// Curved text polygon is not supported in the current version.
// (concave polygon is invalid input to intersectConvexConvex)
void normAssertTextDetections(
const std::vector<std::vector<Point>>& gtPolys,
const std::vector<std::vector<Point>>& testPolys,
const char *comment /*= ""*/, double boxes_iou_diff /*= 1e-4*/)
{
std::vector<bool> matchedRefBoxes(gtPolys.size(), false);
for (uint i = 0; i < testPolys.size(); ++i)
{
const std::vector<Point>& testPoly = testPolys[i];
bool matched = false;
double topIoU = 0;
for (uint j = 0; j < gtPolys.size() && !matched; ++j)
{
if (!matchedRefBoxes[j])
{
std::vector<Point> intersectionPolygon;
float intersectArea = intersectConvexConvex(testPoly, gtPolys[j], intersectionPolygon, true);
double iou = intersectArea / (contourArea(testPoly) + contourArea(gtPolys[j]) - intersectArea);
topIoU = std::max(topIoU, iou);
if (1.0 - iou < boxes_iou_diff)
{
matched = true;
matchedRefBoxes[j] = true;
}
}
}
if (!matched) {
std::cout << cv::format("Unmatched-det:") << testPoly << std::endl;
std::cout << "Highest IoU: " << topIoU << std::endl;
}
EXPECT_TRUE(matched) << comment;
}
// Check unmatched groundtruth.
for (uint i = 0; i < gtPolys.size(); ++i)
{
if (!matchedRefBoxes[i]) {
std::cout << cv::format("Unmatched-gt:") << gtPolys[i] << std::endl;
}
EXPECT_TRUE(matchedRefBoxes[i]);
}
}
void readFileContent(const std::string& filename, CV_OUT std::vector<char>& content)
{
const std::ios::openmode mode = std::ios::in | std::ios::binary;
std::ifstream ifs(filename.c_str(), mode);
ASSERT_TRUE(ifs.is_open());
content.clear();
ifs.seekg(0, std::ios::end);
const size_t sz = ifs.tellg();
content.resize(sz);
ifs.seekg(0, std::ios::beg);
ifs.read((char*)content.data(), sz);
ASSERT_FALSE(ifs.fail());
}
testing::internal::ParamGenerator< tuple<cv::dnn::Backend, cv::dnn::Target> > dnnBackendsAndTargets(
bool withInferenceEngine /*= true*/,
bool withHalide /*= false*/,
bool withCpuOCV /*= true*/,
bool withVkCom /*= true*/,
bool withCUDA /*= true*/,
bool withNgraph /*= true*/,
bool withWebnn /*= false*/,
bool withCann /*= true*/
)
{
bool withVPU = validateVPUType();
std::vector< tuple<cv::dnn::Backend, cv::dnn::Target> > targets;
std::vector< cv::dnn::Target > available;
if (withHalide)
{
/* remove in opencv 5.0
available = getAvailableTargets(cv::dnn::DNN_BACKEND_HALIDE);
for (std::vector< Target >::const_iterator i = available.begin(); i != available.end(); ++i)
targets.push_back(make_tuple(cv::dnn::DNN_BACKEND_HALIDE, *i));
*/
}
if (withInferenceEngine)
{
available = getAvailableTargets(cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019);
for (std::vector< cv::dnn::Target >::const_iterator i = available.begin(); i != available.end(); ++i)
{
if ((*i == cv::dnn::DNN_TARGET_MYRIAD || *i == cv::dnn::DNN_TARGET_HDDL) && !withVPU)
continue;
targets.push_back(make_tuple(cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019, *i));
}
}
if (withNgraph)
{
available = getAvailableTargets(cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NGRAPH);
for (std::vector< cv::dnn::Target >::const_iterator i = available.begin(); i != available.end(); ++i)
{
if ((*i == cv::dnn::DNN_TARGET_MYRIAD || *i == cv::dnn::DNN_TARGET_HDDL) && !withVPU)
continue;
targets.push_back(make_tuple(cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NGRAPH, *i));
}
}
if (withVkCom)
{
available = getAvailableTargets(cv::dnn::DNN_BACKEND_VKCOM);
for (std::vector< cv::dnn::Target >::const_iterator i = available.begin(); i != available.end(); ++i)
targets.push_back(make_tuple(cv::dnn::DNN_BACKEND_VKCOM, *i));
}
#ifdef HAVE_CUDA
if(withCUDA)
{
for (auto target : getAvailableTargets(cv::dnn::DNN_BACKEND_CUDA))
targets.push_back(make_tuple(cv::dnn::DNN_BACKEND_CUDA, target));
}
#endif
#ifdef HAVE_WEBNN
if (withWebnn)
{
for (auto target : getAvailableTargets(cv::dnn::DNN_BACKEND_WEBNN)) {
targets.push_back(make_tuple(cv::dnn::DNN_BACKEND_WEBNN, target));
}
}
#else
CV_UNUSED(withWebnn);
#endif
#ifdef HAVE_CANN
if (withCann)
{
for (auto target : getAvailableTargets(cv::dnn::DNN_BACKEND_CANN))
targets.push_back(make_tuple(cv::dnn::DNN_BACKEND_CANN, target));
}
#else
CV_UNUSED(withCann);
#endif // HAVE_CANN
{
available = getAvailableTargets(cv::dnn::DNN_BACKEND_OPENCV);
for (std::vector< cv::dnn::Target >::const_iterator i = available.begin(); i != available.end(); ++i)
{
if (!withCpuOCV && *i == cv::dnn::DNN_TARGET_CPU)
continue;
targets.push_back(make_tuple(cv::dnn::DNN_BACKEND_OPENCV, *i));
}
}
if (targets.empty()) // validate at least CPU mode
targets.push_back(make_tuple(cv::dnn::DNN_BACKEND_OPENCV, cv::dnn::DNN_TARGET_CPU));
return testing::ValuesIn(targets);
}
testing::internal::ParamGenerator< tuple<cv::dnn::Backend, cv::dnn::Target> > dnnBackendsAndTargetsIE()
{
#ifdef HAVE_INF_ENGINE
bool withVPU = validateVPUType();
std::vector< tuple<cv::dnn::Backend, cv::dnn::Target> > targets;
std::vector< cv::dnn::Target > available;
{
available = getAvailableTargets(cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NGRAPH);
for (std::vector< cv::dnn::Target >::const_iterator i = available.begin(); i != available.end(); ++i)
{
if ((*i == cv::dnn::DNN_TARGET_MYRIAD || *i == cv::dnn::DNN_TARGET_HDDL) && !withVPU)
continue;
targets.push_back(make_tuple(cv::dnn::DNN_BACKEND_INFERENCE_ENGINE_NGRAPH, *i));
}
}
return testing::ValuesIn(targets);
#else
return testing::ValuesIn(std::vector< tuple<cv::dnn::Backend, cv::dnn::Target> >());
#endif
}
static std::string getTestInferenceEngineVPUType()
{
static std::string param_vpu_type = utils::getConfigurationParameterString("OPENCV_TEST_cv::dnn::DNN_IE_VPU_TYPE", "");
return param_vpu_type;
}
static bool validateVPUType_()
{
std::string test_vpu_type = getTestInferenceEngineVPUType();
if (test_vpu_type == "DISABLED" || test_vpu_type == "disabled")
{
return false;
}
std::vector<cv::dnn::Target> available = getAvailableTargets(cv::dnn::DNN_BACKEND_INFERENCE_ENGINE);
bool have_vpu_target = false;
for (std::vector<cv::dnn::Target>::const_iterator i = available.begin(); i != available.end(); ++i)
{
if (*i == cv::dnn::DNN_TARGET_MYRIAD || *i == cv::dnn::DNN_TARGET_HDDL)
{
have_vpu_target = true;
break;
}
}
if (test_vpu_type.empty())
{
if (have_vpu_target)
{
CV_LOG_INFO(NULL, "OpenCV-DNN-Test: VPU type for testing is not specified via 'OPENCV_TEST_cv::dnn::DNN_IE_VPU_TYPE' parameter.")
}
}
else
{
if (!have_vpu_target)
{
CV_LOG_FATAL(NULL, "OpenCV-DNN-Test: 'OPENCV_TEST_cv::dnn::DNN_IE_VPU_TYPE' parameter requires VPU of type = '" << test_vpu_type << "', but VPU is not detected. STOP.");
exit(1);
}
std::string dnn_vpu_type = cv::dnn::getInferenceEngineVPUType();
if (dnn_vpu_type != test_vpu_type)
{
CV_LOG_FATAL(NULL, "OpenCV-DNN-Test: 'testing' and 'detected' VPU types mismatch: '" << test_vpu_type << "' vs '" << dnn_vpu_type << "'. STOP.");
exit(1);
}
}
if (have_vpu_target)
{
std::string dnn_vpu_type = cv::dnn::getInferenceEngineVPUType();
if (dnn_vpu_type == CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_2)
registerGlobalSkipTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD_2);
if (dnn_vpu_type == CV_DNN_INFERENCE_ENGINE_VPU_TYPE_MYRIAD_X)
registerGlobalSkipTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD_X);
}
return true;
}
bool validateVPUType()
{
static bool result = validateVPUType_();
return result;
}
void initDNNTests()
{
const char* extraTestDataPath =
#ifdef WINRT
NULL;
#else
getenv("OPENCV_cv::dnn::DNN_TEST_DATA_PATH");
#endif
if (extraTestDataPath)
cvtest::addDataSearchPath(extraTestDataPath);
registerGlobalSkipTag(
CV_TEST_TAG_DNN_SKIP_OPENCV_BACKEND,
CV_TEST_TAG_DNN_SKIP_CPU, CV_TEST_TAG_DNN_SKIP_CPU_FP16,
CV_TEST_TAG_DNN_SKIP_OPENCL, CV_TEST_TAG_DNN_SKIP_OPENCL_FP16
);
#if defined(HAVE_HALIDE)
registerGlobalSkipTag(
CV_TEST_TAG_cv::dnn::DNN_SKIP_HALIDE
);
#endif
#if defined(INF_ENGINE_RELEASE)
registerGlobalSkipTag(
CV_TEST_TAG_DNN_SKIP_IE,
#if INF_ENGINE_VER_MAJOR_EQ(2018050000)
CV_TEST_TAG_cv::dnn::DNN_SKIP_IE_2018R5,
#elif INF_ENGINE_VER_MAJOR_EQ(2019010000)
CV_TEST_TAG_cv::dnn::DNN_SKIP_IE_2019R1,
# if INF_ENGINE_RELEASE == 2019010100
CV_TEST_TAG_cv::dnn::DNN_SKIP_IE_2019R1_1,
# endif
#elif INF_ENGINE_VER_MAJOR_EQ(2019020000)
CV_TEST_TAG_cv::dnn::DNN_SKIP_IE_2019R2,
#elif INF_ENGINE_VER_MAJOR_EQ(2019030000)
CV_TEST_TAG_cv::dnn::DNN_SKIP_IE_2019R3,
#endif
#ifdef HAVE_cv::dnn::DNN_NGRAPH
CV_TEST_TAG_cv::dnn::DNN_SKIP_IE_NGRAPH,
#endif
#ifdef HAVE_cv::dnn::DNN_IE_NN_BUILDER_2019
CV_TEST_TAG_cv::dnn::DNN_SKIP_IE_NN_BUILDER,
#endif
CV_TEST_TAG_DNN_SKIP_IE_CPU
);
registerGlobalSkipTag(
// see validateVPUType(): CV_TEST_TAG_cv::dnn::DNN_SKIP_IE_MYRIAD_2, CV_TEST_TAG_cv::dnn::DNN_SKIP_IE_MYRIAD_X
CV_TEST_TAG_DNN_SKIP_IE_OPENCL, CV_TEST_TAG_DNN_SKIP_IE_OPENCL_FP16
);
#endif
#ifdef HAVE_VULKAN
registerGlobalSkipTag(
CV_TEST_TAG_cv::dnn::DNN_SKIP_VULKAN
);
#endif
#ifdef HAVE_CUDA
registerGlobalSkipTag(
CV_TEST_TAG_DNN_SKIP_CUDA, CV_TEST_TAG_DNN_SKIP_CUDA_FP32, CV_TEST_TAG_DNN_SKIP_CUDA_FP16
);
#endif
#ifdef HAVE_TIMVX
registerGlobalSkipTag(
CV_TEST_TAG_cv::dnn::DNN_SKIP_TIMVX
);
#endif
#ifdef HAVE_CANN
registerGlobalSkipTag(
CV_TEST_TAG_cv::dnn::DNN_SKIP_CANN
);
#endif
registerGlobalSkipTag(
CV_TEST_TAG_DNN_SKIP_ONNX_CONFORMANCE,
CV_TEST_TAG_DNN_SKIP_PARSER
);
}
size_t DNNlegacyTestLayer::getTopMemoryUsageMB()
{
#ifdef _WIN32
PROCESS_MEMORY_COUNTERS proc;
GetProcessMemoryInfo(GetCurrentProcess(), &proc, sizeof(proc));
return proc.PeakWorkingSetSize / pow(1024, 2); // bytes to megabytes
#else
std::ifstream status("/proc/self/status");
std::string line, title;
while (std::getline(status, line))
{
std::istringstream iss(line);
iss >> title;
if (title == "VmHWM:")
{
size_t mem;
iss >> mem;
return mem / 1024;
}
}
return 0l;
#endif
}
} // namespace

File diff suppressed because it is too large Load Diff

@ -0,0 +1,6 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
CV_TEST_MAIN("cv")

@ -0,0 +1,52 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's 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.
//
// * The name of the copyright holders may not 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 the Intel Corporation or contributors 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.
//
//M*/
#ifndef __OPENCV_TEST_PRECOMP_HPP__
#define __OPENCV_TEST_PRECOMP_HPP__
#include "opencv2/ts.hpp"
#include "opencv2/ts/ts_perf.hpp"
#include "opencv2/core/utility.hpp"
#include "opencv2/core/ocl.hpp"
#include "opencv2/dnnlegacy.hpp"
#include "test_common.hpp"
#endif
Loading…
Cancel
Save