Merge 025095ec80
into 6437f182af
commit
b9364c570c
25 changed files with 87998 additions and 0 deletions
@ -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 ¶ms) |
||||
{ |
||||
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 ¶ms) |
||||
{ |
||||
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 ¶ms, 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…
Reference in new issue