diff --git a/CMakeLists.txt b/CMakeLists.txt
index fc53066c82..4c9b98ef5d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -32,7 +32,7 @@ endif()
option(ENABLE_PIC "Generate position independent code (necessary for shared libraries)" TRUE)
set(CMAKE_POSITION_INDEPENDENT_CODE ${ENABLE_PIC})
-# Following block can break build in case of cross-compilng
+# Following block can break build in case of cross-compiling
# but CMAKE_CROSSCOMPILING variable will be set only on project(OpenCV) command
# so we will try to detect cross-compiling by the presence of CMAKE_TOOLCHAIN_FILE
if(NOT DEFINED CMAKE_INSTALL_PREFIX)
@@ -43,17 +43,17 @@ if(NOT DEFINED CMAKE_INSTALL_PREFIX)
else()
set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "Installation Directory")
endif()
- else(NOT CMAKE_TOOLCHAIN_FILE)
+ else()
#Android: set output folder to ${CMAKE_BINARY_DIR}
- set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_BINARY_DIR} CACHE PATH "root for library output, set this to change where android libs are compiled to" )
+ set(LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_BINARY_DIR} CACHE PATH "root for library output, set this to change where android libs are compiled to" )
# any cross-compiling
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE PATH "Installation Directory")
- endif(NOT CMAKE_TOOLCHAIN_FILE)
+ endif()
endif()
if(CMAKE_SYSTEM_NAME MATCHES WindowsPhone OR CMAKE_SYSTEM_NAME MATCHES WindowsStore)
set(WINRT TRUE)
-endif(CMAKE_SYSTEM_NAME MATCHES WindowsPhone OR CMAKE_SYSTEM_NAME MATCHES WindowsStore)
+endif()
if(WINRT)
add_definitions(-DWINRT -DNO_GETENV)
@@ -315,7 +315,7 @@ OCV_OPTION(INSTALL_TESTS "Install accuracy and performance test binar
# OpenCV build options
# ===================================================
OCV_OPTION(ENABLE_CCACHE "Use ccache" (UNIX AND NOT IOS AND (CMAKE_GENERATOR MATCHES "Makefile" OR CMAKE_GENERATOR MATCHES "Ninja")) )
-OCV_OPTION(ENABLE_PRECOMPILED_HEADERS "Use precompiled headers" ON IF (NOT IOS AND NOT CMAKE_CROSSCOMPILING) )
+OCV_OPTION(ENABLE_PRECOMPILED_HEADERS "Use precompiled headers" ON IF (MSVC OR (NOT IOS AND NOT CMAKE_CROSSCOMPILING) ) )
OCV_OPTION(ENABLE_SOLUTION_FOLDERS "Solution folder in Visual Studio or in other IDEs" (MSVC_IDE OR CMAKE_GENERATOR MATCHES Xcode) )
OCV_OPTION(ENABLE_PROFILING "Enable profiling in the GCC compiler (Add flags: -g -pg)" OFF IF CV_GCC )
OCV_OPTION(ENABLE_COVERAGE "Enable coverage collection with GCov" OFF IF CV_GCC )
@@ -339,8 +339,8 @@ OCV_OPTION(CV_ENABLE_INTRINSICS "Use intrinsic-based optimized code" ON )
OCV_OPTION(CV_DISABLE_OPTIMIZATION "Disable explicit optimized code (dispatched code/intrinsics/loop unrolling/etc)" OFF )
OCV_OPTION(CV_TRACE "Enable OpenCV code trace" ON)
-OCV_OPTION(ENABLE_PYLINT "Add target with Pylint checks" (${BUILD_DOCS} OR ${BUILD_EXAMPLES}) IF (NOT CMAKE_CROSSCOMPILING AND NOT APPLE_FRAMEWORK) )
-OCV_OPTION(ENABLE_FLAKE8 "Add target with Python flake8 checker" (${BUILD_DOCS} OR ${BUILD_EXAMPLES}) IF (NOT CMAKE_CROSSCOMPILING AND NOT APPLE_FRAMEWORK) )
+OCV_OPTION(ENABLE_PYLINT "Add target with Pylint checks" (BUILD_DOCS OR BUILD_EXAMPLES) IF (NOT CMAKE_CROSSCOMPILING AND NOT APPLE_FRAMEWORK) )
+OCV_OPTION(ENABLE_FLAKE8 "Add target with Python flake8 checker" (BUILD_DOCS OR BUILD_EXAMPLES) IF (NOT CMAKE_CROSSCOMPILING AND NOT APPLE_FRAMEWORK) )
if(ENABLE_IMPL_COLLECTION)
add_definitions(-DCV_COLLECT_IMPL_DATA)
@@ -1246,7 +1246,9 @@ if(WITH_1394 OR HAVE_DC1394)
endif()
if(WITH_FFMPEG OR HAVE_FFMPEG)
- if(WIN32)
+ if(OPENCV_FFMPEG_USE_FIND_PACKAGE)
+ status(" FFMPEG:" HAVE_FFMPEG THEN "YES (find_package)" ELSE "NO (find_package)")
+ elseif(WIN32)
status(" FFMPEG:" HAVE_FFMPEG THEN "YES (prebuilt binaries)" ELSE NO)
else()
status(" FFMPEG:" HAVE_FFMPEG THEN YES ELSE NO)
diff --git a/cmake/FindCUDA.cmake b/cmake/FindCUDA.cmake
index bbdfb91a07..632b8c8285 100644
--- a/cmake/FindCUDA.cmake
+++ b/cmake/FindCUDA.cmake
@@ -1042,7 +1042,7 @@ function(CUDA_COMPUTE_BUILD_PATH path build_path)
# Only deal with CMake style paths from here on out
file(TO_CMAKE_PATH "${path}" bpath)
if (IS_ABSOLUTE "${bpath}")
- # Absolute paths are generally unnessary, especially if something like
+ # Absolute paths are generally unnecessary, especially if something like
# file(GLOB_RECURSE) is used to pick up the files.
string(FIND "${bpath}" "${CMAKE_CURRENT_BINARY_DIR}" _binary_dir_pos)
@@ -1065,7 +1065,7 @@ function(CUDA_COMPUTE_BUILD_PATH path build_path)
# Avoid spaces
string(REPLACE " " "_" bpath "${bpath}")
- # Strip off the filename. I wait until here to do it, since removin the
+ # Strip off the filename. I wait until here to do it, since removing the
# basename can make a path that looked like path/../basename turn into
# path/.. (notice the trailing slash).
get_filename_component(bpath "${bpath}" PATH)
@@ -1362,7 +1362,7 @@ macro(CUDA_WRAP_SRCS cuda_target format generated_files)
# Bring in the dependencies. Creates a variable CUDA_NVCC_DEPEND #######
cuda_include_nvcc_dependencies(${cmake_dependency_file})
- # Convience string for output ###########################################
+ # Convenience string for output ###########################################
if(CUDA_BUILD_EMULATION)
set(cuda_build_type "Emulation")
else()
@@ -1563,7 +1563,7 @@ macro(CUDA_ADD_LIBRARY cuda_target)
${_cmake_options} ${_cuda_shared_flag}
OPTIONS ${_options} )
- # Compute the file name of the intermedate link file used for separable
+ # Compute the file name of the intermediate link file used for separable
# compilation.
CUDA_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME(link_file ${cuda_target} "${${cuda_target}_SEPARABLE_COMPILATION_OBJECTS}")
@@ -1607,7 +1607,7 @@ macro(CUDA_ADD_EXECUTABLE cuda_target)
# Create custom commands and targets for each file.
CUDA_WRAP_SRCS( ${cuda_target} OBJ _generated_files ${_sources} OPTIONS ${_options} )
- # Compute the file name of the intermedate link file used for separable
+ # Compute the file name of the intermediate link file used for separable
# compilation.
CUDA_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME(link_file ${cuda_target} "${${cuda_target}_SEPARABLE_COMPILATION_OBJECTS}")
@@ -1723,7 +1723,7 @@ endmacro()
###############################################################################
###############################################################################
macro(CUDA_BUILD_CLEAN_TARGET)
- # Call this after you add all your CUDA targets, and you will get a convience
+ # Call this after you add all your CUDA targets, and you will get a convenience
# target. You should also make clean after running this target to get the
# build system to generate all the code again.
diff --git a/cmake/OpenCVCompilerOptions.cmake b/cmake/OpenCVCompilerOptions.cmake
index d83777fe4b..30e4a00a3f 100644
--- a/cmake/OpenCVCompilerOptions.cmake
+++ b/cmake/OpenCVCompilerOptions.cmake
@@ -1,5 +1,5 @@
if("${CMAKE_CXX_COMPILER};${CMAKE_C_COMPILER};${CMAKE_CXX_COMPILER_LAUNCHER}" MATCHES "ccache")
- set(CMAKE_COMPILER_IS_CCACHE 1) # FIXIT Avoid setting of CMAKE_ variables
+ set(CMAKE_COMPILER_IS_CCACHE 1) # TODO: FIXIT Avoid setting of CMAKE_ variables
set(OPENCV_COMPILER_IS_CCACHE 1)
endif()
function(access_CMAKE_COMPILER_IS_CCACHE)
diff --git a/cmake/OpenCVDetectInferenceEngine.cmake b/cmake/OpenCVDetectInferenceEngine.cmake
index d33a8d966d..ae766a863a 100644
--- a/cmake/OpenCVDetectInferenceEngine.cmake
+++ b/cmake/OpenCVDetectInferenceEngine.cmake
@@ -38,8 +38,7 @@ set(INF_ENGINE_INCLUDE_DIRS "${INF_ENGINE_ROOT_DIR}/include" CACHE PATH "Path to
if(NOT INF_ENGINE_ROOT_DIR
OR NOT EXISTS "${INF_ENGINE_ROOT_DIR}"
- OR NOT EXISTS "${INF_ENGINE_INCLUDE_DIRS}"
- OR NOT EXISTS "${INF_ENGINE_INCLUDE_DIRS}/inference_engine.hpp"
+ OR NOT EXISTS "${INF_ENGINE_ROOT_DIR}/include/inference_engine.hpp"
)
ie_fail()
endif()
@@ -49,10 +48,7 @@ set(INF_ENGINE_LIBRARIES "")
set(ie_lib_list inference_engine)
link_directories(
- ${INTEL_CVSDK_DIR}/external/mklml_lnx/lib
- ${INTEL_CVSDK_DIR}/inference_engine/external/mklml_lnx/lib
${INTEL_CVSDK_DIR}/inference_engine/external/mkltiny_lnx/lib
- ${INTEL_CVSDK_DIR}/external/cldnn/lib
${INTEL_CVSDK_DIR}/inference_engine/external/cldnn/lib
)
diff --git a/cmake/OpenCVFindLibsPerf.cmake b/cmake/OpenCVFindLibsPerf.cmake
index e12a04656f..e3bd8384ab 100644
--- a/cmake/OpenCVFindLibsPerf.cmake
+++ b/cmake/OpenCVFindLibsPerf.cmake
@@ -43,7 +43,7 @@ endif(WITH_IPP_A)
if(WITH_CUDA)
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVDetectCUDA.cmake")
if(NOT HAVE_CUDA)
- message(WARNING "OpenCV is not able to find/confidure CUDA SDK (required by WITH_CUDA).
+ message(WARNING "OpenCV is not able to find/configure CUDA SDK (required by WITH_CUDA).
CUDA support will be disabled in OpenCV build.
To eliminate this warning remove WITH_CUDA=ON CMake configuration option.
")
diff --git a/cmake/OpenCVFindLibsVideo.cmake b/cmake/OpenCVFindLibsVideo.cmake
index 50dc12a482..fb1b92ec5f 100644
--- a/cmake/OpenCVFindLibsVideo.cmake
+++ b/cmake/OpenCVFindLibsVideo.cmake
@@ -212,12 +212,23 @@ endif(WITH_XIMEA)
# --- FFMPEG ---
ocv_clear_vars(HAVE_FFMPEG)
-if(WITH_FFMPEG)
- if(WIN32 AND NOT ARM)
+if(WITH_FFMPEG) # try FFmpeg autodetection
+ if(OPENCV_FFMPEG_USE_FIND_PACKAGE)
+ if(OPENCV_FFMPEG_USE_FIND_PACKAGE STREQUAL "1" OR OPENCV_FFMPEG_USE_FIND_PACKAGE STREQUAL "ON")
+ set(OPENCV_FFMPEG_USE_FIND_PACKAGE "FFMPEG")
+ endif()
+ find_package(${OPENCV_FFMPEG_USE_FIND_PACKAGE}) # Required components: AVCODEC AVFORMAT AVUTIL SWSCALE
+ if(FFMPEG_FOUND OR FFmpeg_FOUND)
+ set(HAVE_FFMPEG TRUE)
+ else()
+ message(STATUS "Can't find FFmpeg via find_package(${OPENCV_FFMPEG_USE_FIND_PACKAGE})")
+ endif()
+ elseif(WIN32 AND NOT ARM AND NOT OPENCV_FFMPEG_SKIP_DOWNLOAD)
include("${OpenCV_SOURCE_DIR}/3rdparty/ffmpeg/ffmpeg.cmake")
download_win_ffmpeg(FFMPEG_CMAKE_SCRIPT)
if(FFMPEG_CMAKE_SCRIPT)
set(HAVE_FFMPEG TRUE)
+ set(HAVE_FFMPEG_WRAPPER 1)
include("${FFMPEG_CMAKE_SCRIPT}")
endif()
elseif(PKG_CONFIG_FOUND)
@@ -226,27 +237,29 @@ if(WITH_FFMPEG)
if(FFMPEG_libavresample_FOUND)
ocv_append_build_options(FFMPEG FFMPEG_libavresample)
endif()
- if(HAVE_FFMPEG)
- try_compile(__VALID_FFMPEG
- "${OpenCV_BINARY_DIR}"
- "${OpenCV_SOURCE_DIR}/cmake/checks/ffmpeg_test.cpp"
- CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${FFMPEG_INCLUDE_DIRS}"
- "-DLINK_DIRECTORIES:STRING=${FFMPEG_LIBRARY_DIRS}"
- "-DLINK_LIBRARIES:STRING=${FFMPEG_LIBRARIES}"
- OUTPUT_VARIABLE TRY_OUT
- )
- if(NOT __VALID_FFMPEG)
- #message(FATAL_ERROR "FFMPEG: test check build log:\n${TRY_OUT}")
- message(STATUS "WARNING: Can't build ffmpeg test code")
- set(HAVE_FFMPEG FALSE)
- else()
- ocv_append_build_options(VIDEOIO FFMPEG)
- endif()
- endif()
else()
message(STATUS "Can't find ffmpeg - 'pkg-config' utility is missing")
endif()
-endif(WITH_FFMPEG)
+endif()
+if(HAVE_FFMPEG
+ AND NOT HAVE_FFMPEG_WRAPPER
+)
+ try_compile(__VALID_FFMPEG
+ "${OpenCV_BINARY_DIR}"
+ "${OpenCV_SOURCE_DIR}/cmake/checks/ffmpeg_test.cpp"
+ CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${FFMPEG_INCLUDE_DIRS}"
+ "-DLINK_DIRECTORIES:STRING=${FFMPEG_LIBRARY_DIRS}"
+ "-DLINK_LIBRARIES:STRING=${FFMPEG_LIBRARIES}"
+ OUTPUT_VARIABLE TRY_OUT
+ )
+ if(NOT __VALID_FFMPEG)
+ #message(FATAL_ERROR "FFMPEG: test check build log:\n${TRY_OUT}")
+ message(STATUS "WARNING: Can't build ffmpeg test code")
+ set(HAVE_FFMPEG FALSE)
+ else()
+ ocv_append_build_options(VIDEOIO FFMPEG)
+ endif()
+endif()
# --- VideoInput/DirectShow ---
if(WITH_DSHOW)
diff --git a/cmake/OpenCVModule.cmake b/cmake/OpenCVModule.cmake
index 93b6123eba..db439b3981 100644
--- a/cmake/OpenCVModule.cmake
+++ b/cmake/OpenCVModule.cmake
@@ -455,7 +455,7 @@ function(__ocv_sort_modules_by_deps __lst)
set(${__lst} "${result};${result_extra}" PARENT_SCOPE)
endfunction()
-# resolve dependensies
+# resolve dependencies
function(__ocv_resolve_dependencies)
foreach(m ${OPENCV_MODULES_DISABLED_USER})
set(HAVE_${m} OFF CACHE INTERNAL "Module ${m} will not be built in current configuration")
@@ -727,7 +727,7 @@ macro(ocv_set_module_sources)
endif()
endforeach()
- # the hacky way to embeed any files into the OpenCV without modification of its build system
+ # the hacky way to embed any files into the OpenCV without modification of its build system
if(COMMAND ocv_get_module_external_sources)
ocv_get_module_external_sources()
endif()
@@ -958,7 +958,7 @@ macro(_ocv_create_module)
target_compile_definitions(${the_module} PRIVATE CVAPI_EXPORTS)
endif()
- # For dynamic link numbering convenions
+ # For dynamic link numbering conventions
if(NOT ANDROID)
# Android SDK build scripts can include only .so files into final .apk
# As result we should not set version properties for Android
diff --git a/cmake/OpenCVPCHSupport.cmake b/cmake/OpenCVPCHSupport.cmake
index b1dd60e849..b4658c604b 100644
--- a/cmake/OpenCVPCHSupport.cmake
+++ b/cmake/OpenCVPCHSupport.cmake
@@ -383,7 +383,7 @@ MACRO(ADD_NATIVE_PRECOMPILED_HEADER _targetName _input)
# For Xcode, cmake needs my patch to process
# GCC_PREFIX_HEADER and GCC_PRECOMPILE_PREFIX_HEADER as target properties
- # When buiding out of the tree, precompiled may not be located
+ # When building out of the tree, precompiled may not be located
# Use full path instead.
GET_FILENAME_COMPONENT(fullPath ${_input} ABSOLUTE)
diff --git a/doc/opencv.bib b/doc/opencv.bib
index 1cb3d0b0af..edb7033e8d 100644
--- a/doc/opencv.bib
+++ b/doc/opencv.bib
@@ -20,6 +20,21 @@
volume = {34},
number = {7}
}
+@INPROCEEDINGS{Arandjelovic:2012:TTE:2354409.2355123,
+ author = {Arandjelovic, Relja},
+ title = {Three Things Everyone Should Know to Improve Object Retrieval},
+ booktitle = {Proceedings of the 2012 IEEE Conference on Computer Vision and Pattern Recognition (CVPR)},
+ series = {CVPR '12},
+ year = {2012},
+ isbn = {978-1-4673-1226-4},
+ pages = {2911--2918},
+ numpages = {8},
+ url = {http://dl.acm.org/citation.cfm?id=2354409.2355123},
+ acmid = {2355123},
+ publisher = {IEEE Computer Society},
+ address = {Washington, DC, USA},
+ keywords = {Vectors,Visualization,Kernel,Standards,Support vector machines,Indexes,Euclidean distance},
+}
@ARTICLE{BA83,
author = {Burt, Peter J and Adelson, Edward H},
title = {A multiresolution spline with application to image mosaics},
@@ -515,6 +530,25 @@
volume = {1},
organization = {IEEE}
}
+@ARTICLE{Lowe:2004:DIF:993451.996342,
+ author = {Lowe, David G.},
+ title = {Distinctive Image Features from Scale-Invariant Keypoints},
+ journal = {Int. J. Comput. Vision},
+ issue_date = {November 2004},
+ volume = {60},
+ number = {2},
+ month = nov,
+ year = {2004},
+ issn = {0920-5691},
+ pages = {91--110},
+ numpages = {20},
+ url = {https://doi.org/10.1023/B:VISI.0000029664.99615.94},
+ doi = {10.1023/B:VISI.0000029664.99615.94},
+ acmid = {996342},
+ publisher = {Kluwer Academic Publishers},
+ address = {Hingham, MA, USA},
+ keywords = {image matching, invariant features, object recognition, scale invariance},
+}
@INPROCEEDINGS{Lucas81,
author = {Lucas, Bruce D and Kanade, Takeo and others},
title = {An iterative image registration technique with an application to stereo vision.},
diff --git a/doc/tools/html_functions.py b/doc/tools/html_functions.py
index c3fd3bd8e9..b76639cea5 100644
--- a/doc/tools/html_functions.py
+++ b/doc/tools/html_functions.py
@@ -3,6 +3,7 @@ import sys
import logging
import os
+import re
from pprint import pprint
import traceback
@@ -17,12 +18,20 @@ except ImportError:
def load_html_file(file_dir):
""" Uses BeautifulSoup to load an html """
with open(file_dir, 'rb') as fp:
- soup = BeautifulSoup(fp, 'html.parser')
+ data = fp.read()
+ if os.name == 'nt' or sys.version_info[0] == 3:
+ data = data.decode(encoding='utf-8', errors='strict')
+ data = re.sub(r'(\>)([ ]+)', lambda match: match.group(1) + ('!space!' * len(match.group(2))), data)
+ data = re.sub(r'([ ]+)(\<)', lambda match: ('!space!' * len(match.group(1))) + match.group(2), data)
+ if os.name == 'nt' or sys.version_info[0] == 3:
+ data = data.encode('utf-8', 'ignore')
+ soup = BeautifulSoup(data, 'html.parser')
return soup
def update_html(file, soup):
s = str(soup)
- if os.name == 'nt' or sys.version_info[0] == 3: # if Windows
+ s = s.replace('!space!', ' ')
+ if os.name == 'nt' or sys.version_info[0] == 3:
s = s.encode('utf-8', 'ignore')
with open(file, 'wb') as f:
f.write(s)
diff --git a/doc/tutorials/features2d/feature_description/feature_description.markdown b/doc/tutorials/features2d/feature_description/feature_description.markdown
index eea5a29c1d..ec3cd0e4c5 100644
--- a/doc/tutorials/features2d/feature_description/feature_description.markdown
+++ b/doc/tutorials/features2d/feature_description/feature_description.markdown
@@ -10,74 +10,35 @@ In this tutorial you will learn how to:
to the keypoints. Specifically:
- Use cv::xfeatures2d::SURF and its function cv::xfeatures2d::SURF::compute to perform the
required calculations.
- - Use a @ref cv::BFMatcher to match the features vector
+ - Use a @ref cv::DescriptorMatcher to match the features vector
- Use the function @ref cv::drawMatches to draw the detected matches.
+\warning You need the OpenCV contrib modules to be able to use the SURF features
+(alternatives are ORB, KAZE, ... features).
+
Theory
------
Code
----
-This tutorial code's is shown lines below.
-@code{.cpp}
-#include
-#include
-#include "opencv2/core.hpp"
-#include "opencv2/features2d.hpp"
-#include "opencv2/highgui.hpp"
-#include "opencv2/xfeatures2d.hpp"
-
-using namespace cv;
-using namespace cv::xfeatures2d;
-
-void readme();
-
-/* @function main */
-int main( int argc, char** argv )
-{
- if( argc != 3 )
- { return -1; }
-
- Mat img_1 = imread( argv[1], IMREAD_GRAYSCALE );
- Mat img_2 = imread( argv[2], IMREAD_GRAYSCALE );
-
- if( !img_1.data || !img_2.data )
- { return -1; }
-
- //-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
- int minHessian = 400;
-
- Ptr detector = SURF::create();
- detector->setHessianThreshold(minHessian);
-
- std::vector keypoints_1, keypoints_2;
- Mat descriptors_1, descriptors_2;
-
- detector->detectAndCompute( img_1, Mat(), keypoints_1, descriptors_1 );
- detector->detectAndCompute( img_2, Mat(), keypoints_2, descriptors_2 );
-
- //-- Step 2: Matching descriptor vectors with a brute force matcher
- BFMatcher matcher(NORM_L2);
- std::vector< DMatch > matches;
- matcher.match( descriptors_1, descriptors_2, matches );
-
- //-- Draw matches
- Mat img_matches;
- drawMatches( img_1, keypoints_1, img_2, keypoints_2, matches, img_matches );
-
- //-- Show detected matches
- imshow("Matches", img_matches );
-
- waitKey(0);
-
- return 0;
- }
-
- /* @function readme */
- void readme()
- { std::cout << " Usage: ./SURF_descriptor " << std::endl; }
-@endcode
+@add_toggle_cpp
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/features2D/feature_description/SURF_matching_Demo.cpp)
+@include samples/cpp/tutorial_code/features2D/feature_description/SURF_matching_Demo.cpp
+@end_toggle
+
+@add_toggle_java
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/features2D/feature_description/SURFMatchingDemo.java)
+@include samples/java/tutorial_code/features2D/feature_description/SURFMatchingDemo.java
+@end_toggle
+
+@add_toggle_python
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/features2D/feature_description/SURF_matching_Demo.py)
+@include samples/python/tutorial_code/features2D/feature_description/SURF_matching_Demo.py
+@end_toggle
Explanation
-----------
diff --git a/doc/tutorials/features2d/feature_detection/feature_detection.markdown b/doc/tutorials/features2d/feature_detection/feature_detection.markdown
index 8b2f423ee2..d0996512ef 100644
--- a/doc/tutorials/features2d/feature_detection/feature_detection.markdown
+++ b/doc/tutorials/features2d/feature_detection/feature_detection.markdown
@@ -11,67 +11,32 @@ In this tutorial you will learn how to:
detection process
- Use the function @ref cv::drawKeypoints to draw the detected keypoints
+\warning You need the OpenCV contrib modules to be able to use the SURF features
+(alternatives are ORB, KAZE, ... features).
+
Theory
------
Code
----
-This tutorial code's is shown lines below.
-@code{.cpp}
-#include
-#include
-#include "opencv2/core.hpp"
-#include "opencv2/features2d.hpp"
-#include "opencv2/xfeatures2d.hpp"
-#include "opencv2/highgui.hpp"
-
-using namespace cv;
-using namespace cv::xfeatures2d;
-
-void readme();
-
-/* @function main */
-int main( int argc, char** argv )
-{
- if( argc != 3 )
- { readme(); return -1; }
-
- Mat img_1 = imread( argv[1], IMREAD_GRAYSCALE );
- Mat img_2 = imread( argv[2], IMREAD_GRAYSCALE );
-
- if( !img_1.data || !img_2.data )
- { std::cout<< " --(!) Error reading images " << std::endl; return -1; }
-
- //-- Step 1: Detect the keypoints using SURF Detector
- int minHessian = 400;
-
- Ptr detector = SURF::create( minHessian );
-
- std::vector keypoints_1, keypoints_2;
-
- detector->detect( img_1, keypoints_1 );
- detector->detect( img_2, keypoints_2 );
-
- //-- Draw keypoints
- Mat img_keypoints_1; Mat img_keypoints_2;
-
- drawKeypoints( img_1, keypoints_1, img_keypoints_1, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
- drawKeypoints( img_2, keypoints_2, img_keypoints_2, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
-
- //-- Show detected (drawn) keypoints
- imshow("Keypoints 1", img_keypoints_1 );
- imshow("Keypoints 2", img_keypoints_2 );
-
- waitKey(0);
+@add_toggle_cpp
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/features2D/feature_detection/SURF_detection_Demo.cpp)
+@include samples/cpp/tutorial_code/features2D/feature_detection/SURF_detection_Demo.cpp
+@end_toggle
- return 0;
- }
+@add_toggle_java
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/features2D/feature_detection/SURFDetectionDemo.java)
+@include samples/java/tutorial_code/features2D/feature_detection/SURFDetectionDemo.java
+@end_toggle
- /* @function readme */
- void readme()
- { std::cout << " Usage: ./SURF_detector " << std::endl; }
-@endcode
+@add_toggle_python
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/features2D/feature_detection/SURF_detection_Demo.py)
+@include samples/python/tutorial_code/features2D/feature_detection/SURF_detection_Demo.py
+@end_toggle
Explanation
-----------
@@ -79,10 +44,10 @@ Explanation
Result
------
--# Here is the result of the feature detection applied to the first image:
+-# Here is the result of the feature detection applied to the `box.png` image:

--# And here is the result for the second image:
+-# And here is the result for the `box_in_scene.png` image:

diff --git a/doc/tutorials/features2d/feature_flann_matcher/feature_flann_matcher.markdown b/doc/tutorials/features2d/feature_flann_matcher/feature_flann_matcher.markdown
index 8243b430a6..e7f865c3ce 100644
--- a/doc/tutorials/features2d/feature_flann_matcher/feature_flann_matcher.markdown
+++ b/doc/tutorials/features2d/feature_flann_matcher/feature_flann_matcher.markdown
@@ -9,114 +9,57 @@ In this tutorial you will learn how to:
- Use the @ref cv::FlannBasedMatcher interface in order to perform a quick and efficient matching
by using the @ref flann module
+\warning You need the OpenCV contrib modules to be able to use the SURF features
+(alternatives are ORB, KAZE, ... features).
+
Theory
------
+Classical feature descriptors (SIFT, SURF, ...) are usually compared and matched using the Euclidean distance (or L2-norm).
+Since SIFT and SURF descriptors represent the histogram of oriented gradient (of the Haar wavelet response for SURF)
+in a neighborhood, alternatives of the Euclidean distance are histogram-based metrics (\f$ \chi^{2} \f$, Earth Mover’s Distance (EMD), ...).
+
+Arandjelovic et al. proposed in @cite Arandjelovic:2012:TTE:2354409.2355123 to extend to the RootSIFT descriptor:
+> a square root (Hellinger) kernel instead of the standard Euclidean distance to measure the similarity between SIFT descriptors
+> leads to a dramatic performance boost in all stages of the pipeline.
+
+Binary descriptors (ORB, BRISK, ...) are matched using the Hamming distance.
+This distance is equivalent to count the number of different elements for binary strings (population count after applying a XOR operation):
+\f[ d_{hamming} \left ( a,b \right ) = \sum_{i=0}^{n-1} \left ( a_i \oplus b_i \right ) \f]
+
+To filter the matches, Lowe proposed in @cite Lowe:2004:DIF:993451.996342 to use a distance ratio test to try to eliminate false matches.
+The distance ratio between the two nearest matches of a considered keypoint is computed and it is a good match when this value is below
+a thresold. Indeed, this ratio allows helping to discriminate between ambiguous matches (distance ratio between the two nearest neighbors is
+close to one) and well discriminated matches. The figure below from the SIFT paper illustrates the probability that a match is correct
+based on the nearest-neighbor distance ratio test.
+
+
+
+Alternative or additional filterering tests are:
+- cross check test (good match \f$ \left( f_a, f_b \right) \f$ if feature \f$ f_b \f$ is the best match for \f$ f_a \f$ in \f$ I_b \f$
+ and feature \f$ f_a \f$ is the best match for \f$ f_b \f$ in \f$ I_a \f$)
+- geometric test (eliminate matches that do not fit to a geometric model, e.g. RANSAC or robust homography for planar objects)
+
Code
----
-This tutorial code's is shown lines below.
-@code{.cpp}
-/*
- * @file SURF_FlannMatcher
- * @brief SURF detector + descriptor + FLANN Matcher
- * @author A. Huaman
- */
-
-#include
-#include
-#include
-#include
-#include "opencv2/core.hpp"
-#include "opencv2/features2d.hpp"
-#include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui.hpp"
-#include "opencv2/xfeatures2d.hpp"
-
-using namespace std;
-using namespace cv;
-using namespace cv::xfeatures2d;
-
-void readme();
-
-/*
- * @function main
- * @brief Main function
- */
-int main( int argc, char** argv )
-{
- if( argc != 3 )
- { readme(); return -1; }
-
- Mat img_1 = imread( argv[1], IMREAD_GRAYSCALE );
- Mat img_2 = imread( argv[2], IMREAD_GRAYSCALE );
-
- if( !img_1.data || !img_2.data )
- { std::cout<< " --(!) Error reading images " << std::endl; return -1; }
-
- //-- Step 1: Detect the keypoints using SURF Detector, compute the descriptors
- int minHessian = 400;
-
- Ptr detector = SURF::create();
- detector->setHessianThreshold(minHessian);
-
- std::vector keypoints_1, keypoints_2;
- Mat descriptors_1, descriptors_2;
-
- detector->detectAndCompute( img_1, Mat(), keypoints_1, descriptors_1 );
- detector->detectAndCompute( img_2, Mat(), keypoints_2, descriptors_2 );
-
- //-- Step 2: Matching descriptor vectors using FLANN matcher
- FlannBasedMatcher matcher;
- std::vector< DMatch > matches;
- matcher.match( descriptors_1, descriptors_2, matches );
-
- double max_dist = 0; double min_dist = 100;
-
- //-- Quick calculation of max and min distances between keypoints
- for( int i = 0; i < descriptors_1.rows; i++ )
- { double dist = matches[i].distance;
- if( dist < min_dist ) min_dist = dist;
- if( dist > max_dist ) max_dist = dist;
- }
-
- printf("-- Max dist : %f \n", max_dist );
- printf("-- Min dist : %f \n", min_dist );
-
- //-- Draw only "good" matches (i.e. whose distance is less than 2*min_dist,
- //-- or a small arbitrary value ( 0.02 ) in the event that min_dist is very
- //-- small)
- //-- PS.- radiusMatch can also be used here.
- std::vector< DMatch > good_matches;
-
- for( int i = 0; i < descriptors_1.rows; i++ )
- { if( matches[i].distance <= max(2*min_dist, 0.02) )
- { good_matches.push_back( matches[i]); }
- }
-
- //-- Draw only "good" matches
- Mat img_matches;
- drawMatches( img_1, keypoints_1, img_2, keypoints_2,
- good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
- vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
-
- //-- Show detected matches
- imshow( "Good Matches", img_matches );
-
- for( int i = 0; i < (int)good_matches.size(); i++ )
- { printf( "-- Good Match [%d] Keypoint 1: %d -- Keypoint 2: %d \n", i, good_matches[i].queryIdx, good_matches[i].trainIdx ); }
-
- waitKey(0);
-
- return 0;
-}
-
-/*
- * @function readme
- */
-void readme()
-{ std::cout << " Usage: ./SURF_FlannMatcher " << std::endl; }
-@endcode
+@add_toggle_cpp
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.cpp)
+@include samples/cpp/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.cpp
+@end_toggle
+
+@add_toggle_java
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/features2D/feature_flann_matcher/SURFFLANNMatchingDemo.java)
+@include samples/java/tutorial_code/features2D/feature_flann_matcher/SURFFLANNMatchingDemo.java
+@end_toggle
+
+@add_toggle_python
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.py)
+@include samples/python/tutorial_code/features2D/feature_flann_matcher/SURF_FLANN_matching_Demo.py
+@end_toggle
Explanation
-----------
@@ -124,10 +67,6 @@ Explanation
Result
------
--# Here is the result of the feature detection applied to the first image:
-
- 
-
--# Additionally, we get as console output the keypoints filtered:
+- Here is the result of the SURF feature matching using the distance ratio test:
- 
+ 
diff --git a/doc/tutorials/features2d/feature_flann_matcher/images/Feature_FlannMatcher_Lowe_ratio_test.png b/doc/tutorials/features2d/feature_flann_matcher/images/Feature_FlannMatcher_Lowe_ratio_test.png
new file mode 100644
index 0000000000..f56a640b67
Binary files /dev/null and b/doc/tutorials/features2d/feature_flann_matcher/images/Feature_FlannMatcher_Lowe_ratio_test.png differ
diff --git a/doc/tutorials/features2d/feature_flann_matcher/images/Feature_FlannMatcher_Result_ratio_test.jpg b/doc/tutorials/features2d/feature_flann_matcher/images/Feature_FlannMatcher_Result_ratio_test.jpg
new file mode 100644
index 0000000000..e4a88d0020
Binary files /dev/null and b/doc/tutorials/features2d/feature_flann_matcher/images/Feature_FlannMatcher_Result_ratio_test.jpg differ
diff --git a/doc/tutorials/features2d/feature_homography/feature_homography.markdown b/doc/tutorials/features2d/feature_homography/feature_homography.markdown
index ec7913c330..c4f0c00e55 100644
--- a/doc/tutorials/features2d/feature_homography/feature_homography.markdown
+++ b/doc/tutorials/features2d/feature_homography/feature_homography.markdown
@@ -9,125 +9,40 @@ In this tutorial you will learn how to:
- Use the function @ref cv::findHomography to find the transform between matched keypoints.
- Use the function @ref cv::perspectiveTransform to map the points.
+\warning You need the OpenCV contrib modules to be able to use the SURF features
+(alternatives are ORB, KAZE, ... features).
+
Theory
------
Code
----
-This tutorial code's is shown lines below.
-@code{.cpp}
-#include
-#include
-#include "opencv2/core.hpp"
-#include "opencv2/imgproc.hpp"
-#include "opencv2/features2d.hpp"
-#include "opencv2/highgui.hpp"
-#include "opencv2/calib3d.hpp"
-#include "opencv2/xfeatures2d.hpp"
-
-using namespace cv;
-using namespace cv::xfeatures2d;
-
-void readme();
-
-/* @function main */
-int main( int argc, char** argv )
-{
- if( argc != 3 )
- { readme(); return -1; }
-
- Mat img_object = imread( argv[1], IMREAD_GRAYSCALE );
- Mat img_scene = imread( argv[2], IMREAD_GRAYSCALE );
-
- if( !img_object.data || !img_scene.data )
- { std::cout<< " --(!) Error reading images " << std::endl; return -1; }
-
- //-- Step 1: Detect the keypoints and extract descriptors using SURF
- int minHessian = 400;
-
- Ptr detector = SURF::create( minHessian );
-
- std::vector keypoints_object, keypoints_scene;
- Mat descriptors_object, descriptors_scene;
-
- detector->detectAndCompute( img_object, Mat(), keypoints_object, descriptors_object );
- detector->detectAndCompute( img_scene, Mat(), keypoints_scene, descriptors_scene );
-
- //-- Step 2: Matching descriptor vectors using FLANN matcher
- FlannBasedMatcher matcher;
- std::vector< DMatch > matches;
- matcher.match( descriptors_object, descriptors_scene, matches );
-
- double max_dist = 0; double min_dist = 100;
-
- //-- Quick calculation of max and min distances between keypoints
- for( int i = 0; i < descriptors_object.rows; i++ )
- { double dist = matches[i].distance;
- if( dist < min_dist ) min_dist = dist;
- if( dist > max_dist ) max_dist = dist;
- }
-
- printf("-- Max dist : %f \n", max_dist );
- printf("-- Min dist : %f \n", min_dist );
-
- //-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist )
- std::vector< DMatch > good_matches;
-
- for( int i = 0; i < descriptors_object.rows; i++ )
- { if( matches[i].distance <= 3*min_dist )
- { good_matches.push_back( matches[i]); }
- }
-
- Mat img_matches;
- drawMatches( img_object, keypoints_object, img_scene, keypoints_scene,
- good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
- std::vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
-
- //-- Localize the object
- std::vector obj;
- std::vector scene;
-
- for( size_t i = 0; i < good_matches.size(); i++ )
- {
- //-- Get the keypoints from the good matches
- obj.push_back( keypoints_object[ good_matches[i].queryIdx ].pt );
- scene.push_back( keypoints_scene[ good_matches[i].trainIdx ].pt );
- }
-
- Mat H = findHomography( obj, scene, RANSAC );
-
- //-- Get the corners from the image_1 ( the object to be "detected" )
- std::vector obj_corners(4);
- obj_corners[0] = cvPoint(0,0); obj_corners[1] = cvPoint( img_object.cols, 0 );
- obj_corners[2] = cvPoint( img_object.cols, img_object.rows ); obj_corners[3] = cvPoint( 0, img_object.rows );
- std::vector scene_corners(4);
-
- perspectiveTransform( obj_corners, scene_corners, H);
-
- //-- Draw lines between the corners (the mapped object in the scene - image_2 )
- line( img_matches, scene_corners[0] + Point2f( img_object.cols, 0), scene_corners[1] + Point2f( img_object.cols, 0), Scalar(0, 255, 0), 4 );
- line( img_matches, scene_corners[1] + Point2f( img_object.cols, 0), scene_corners[2] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
- line( img_matches, scene_corners[2] + Point2f( img_object.cols, 0), scene_corners[3] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
- line( img_matches, scene_corners[3] + Point2f( img_object.cols, 0), scene_corners[0] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
+@add_toggle_cpp
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/features2D/feature_homography/SURF_FLANN_matching_homography_Demo.cpp)
+@include samples/cpp/tutorial_code/features2D/feature_homography/SURF_FLANN_matching_homography_Demo.cpp
+@end_toggle
- //-- Show detected matches
- imshow( "Good Matches & Object detection", img_matches );
+@add_toggle_java
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/features2D/feature_homography/SURFFLANNMatchingHomographyDemo.java)
+@include samples/java/tutorial_code/features2D/feature_homography/SURFFLANNMatchingHomographyDemo.java
+@end_toggle
- waitKey(0);
- return 0;
- }
+@add_toggle_python
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/features2D/feature_homography/SURF_FLANN_matching_homography_Demo.py)
+@include samples/python/tutorial_code/features2D/feature_homography/SURF_FLANN_matching_homography_Demo.py
+@end_toggle
- /* @function readme */
- void readme()
- { std::cout << " Usage: ./SURF_descriptor " << std::endl; }
-@endcode
Explanation
-----------
Result
------
--# And here is the result for the detected object (highlighted in green)
+- And here is the result for the detected object (highlighted in green). Note that since the homography is estimated with a RANSAC approach,
+ detected false matches will not impact the homography calculation.

diff --git a/doc/tutorials/features2d/feature_homography/images/Feature_Homography_Result.jpg b/doc/tutorials/features2d/feature_homography/images/Feature_Homography_Result.jpg
index d043a5a6e9..35b1bb634c 100644
Binary files a/doc/tutorials/features2d/feature_homography/images/Feature_Homography_Result.jpg and b/doc/tutorials/features2d/feature_homography/images/Feature_Homography_Result.jpg differ
diff --git a/doc/tutorials/features2d/table_of_content_features2d.markdown b/doc/tutorials/features2d/table_of_content_features2d.markdown
index a5d5a91676..37e4e41a1d 100644
--- a/doc/tutorials/features2d/table_of_content_features2d.markdown
+++ b/doc/tutorials/features2d/table_of_content_features2d.markdown
@@ -6,39 +6,51 @@ OpenCV.
- @subpage tutorial_harris_detector
+ *Languages:* C++, Java, Python
+
*Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán
- Why is it a good idea to track corners? We learn to use the Harris method to detect
- corners
+ Why is it a good idea to track corners? We learn how to use the Harris method to detect
+ corners.
- @subpage tutorial_good_features_to_track
+ *Languages:* C++, Java, Python
+
*Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán
- Where we use an improved method to detect corners more accuratelyI
+ Where we use an improved method to detect corners more accurately.
- @subpage tutorial_generic_corner_detector
+ *Languages:* C++, Java, Python
+
*Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán
Here you will learn how to use OpenCV functions to make your personalized corner detector!
-- @subpage tutorial_corner_subpixeles
+ *Languages:* C++, Java, Python
+
+- @subpage tutorial_corner_subpixels
+
+ *Languages:* C++, Java, Python
*Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán
- Is pixel resolution enough? Here we learn a simple method to improve our accuracy.
+ Is pixel resolution enough? Here we learn a simple method to improve our corner location accuracy.
- @subpage tutorial_feature_detection
+ *Languages:* C++, Java, Python
+
*Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán
@@ -47,6 +59,8 @@ OpenCV.
- @subpage tutorial_feature_description
+ *Languages:* C++, Java, Python
+
*Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán
@@ -55,6 +69,8 @@ OpenCV.
- @subpage tutorial_feature_flann_matcher
+ *Languages:* C++, Java, Python
+
*Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán
@@ -63,6 +79,8 @@ OpenCV.
- @subpage tutorial_feature_homography
+ *Languages:* C++, Java, Python
+
*Compatibility:* \> OpenCV 2.0
*Author:* Ana Huamán
diff --git a/doc/tutorials/features2d/trackingmotion/corner_subpixeles/corner_subpixeles.markdown b/doc/tutorials/features2d/trackingmotion/corner_subpixeles/corner_subpixeles.markdown
deleted file mode 100644
index 946fd77b29..0000000000
--- a/doc/tutorials/features2d/trackingmotion/corner_subpixeles/corner_subpixeles.markdown
+++ /dev/null
@@ -1,32 +0,0 @@
-Detecting corners location in subpixeles {#tutorial_corner_subpixeles}
-========================================
-
-Goal
-----
-
-In this tutorial you will learn how to:
-
-- Use the OpenCV function @ref cv::cornerSubPix to find more exact corner positions (more exact
- than integer pixels).
-
-Theory
-------
-
-Code
-----
-
-This tutorial code's is shown lines below. You can also download it from
-[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/cornerSubPix_Demo.cpp)
-@include samples/cpp/tutorial_code/TrackingMotion/cornerSubPix_Demo.cpp
-
-Explanation
------------
-
-Result
-------
-
-
-
-Here is the result:
-
-
diff --git a/doc/tutorials/features2d/trackingmotion/corner_subpixels/corner_subpixels.markdown b/doc/tutorials/features2d/trackingmotion/corner_subpixels/corner_subpixels.markdown
new file mode 100644
index 0000000000..82b33dd256
--- /dev/null
+++ b/doc/tutorials/features2d/trackingmotion/corner_subpixels/corner_subpixels.markdown
@@ -0,0 +1,46 @@
+Detecting corners location in subpixels {#tutorial_corner_subpixels}
+=======================================
+
+Goal
+----
+
+In this tutorial you will learn how to:
+
+- Use the OpenCV function @ref cv::cornerSubPix to find more exact corner positions (more exact
+ than integer pixels).
+
+Theory
+------
+
+Code
+----
+
+@add_toggle_cpp
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/cornerSubPix_Demo.cpp)
+@include samples/cpp/tutorial_code/TrackingMotion/cornerSubPix_Demo.cpp
+@end_toggle
+
+@add_toggle_java
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/TrackingMotion/corner_subpixels/CornerSubPixDemo.java)
+@include samples/java/tutorial_code/TrackingMotion/corner_subpixels/CornerSubPixDemo.java
+@end_toggle
+
+@add_toggle_python
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/TrackingMotion/corner_subpixels/cornerSubPix_Demo.py)
+@include samples/python/tutorial_code/TrackingMotion/corner_subpixels/cornerSubPix_Demo.py
+@end_toggle
+
+Explanation
+-----------
+
+Result
+------
+
+
+
+Here is the result:
+
+
diff --git a/doc/tutorials/features2d/trackingmotion/corner_subpixeles/images/Corner_Subpixeles_Original_Image.jpg b/doc/tutorials/features2d/trackingmotion/corner_subpixels/images/Corner_Subpixels_Original_Image.jpg
similarity index 100%
rename from doc/tutorials/features2d/trackingmotion/corner_subpixeles/images/Corner_Subpixeles_Original_Image.jpg
rename to doc/tutorials/features2d/trackingmotion/corner_subpixels/images/Corner_Subpixels_Original_Image.jpg
diff --git a/doc/tutorials/features2d/trackingmotion/corner_subpixeles/images/Corner_Subpixeles_Result.jpg b/doc/tutorials/features2d/trackingmotion/corner_subpixels/images/Corner_Subpixels_Result.jpg
similarity index 100%
rename from doc/tutorials/features2d/trackingmotion/corner_subpixeles/images/Corner_Subpixeles_Result.jpg
rename to doc/tutorials/features2d/trackingmotion/corner_subpixels/images/Corner_Subpixels_Result.jpg
diff --git a/doc/tutorials/features2d/trackingmotion/generic_corner_detector/generic_corner_detector.markdown b/doc/tutorials/features2d/trackingmotion/generic_corner_detector/generic_corner_detector.markdown
index 7aba636746..f10d3efe4e 100644
--- a/doc/tutorials/features2d/trackingmotion/generic_corner_detector/generic_corner_detector.markdown
+++ b/doc/tutorials/features2d/trackingmotion/generic_corner_detector/generic_corner_detector.markdown
@@ -1,5 +1,5 @@
-Creating yor own corner detector {#tutorial_generic_corner_detector}
-================================
+Creating your own corner detector {#tutorial_generic_corner_detector}
+=================================
Goal
----
@@ -10,7 +10,7 @@ In this tutorial you will learn how to:
to determine if a pixel is a corner.
- Use the OpenCV function @ref cv::cornerMinEigenVal to find the minimum eigenvalues for corner
detection.
-- To implement our own version of the Harris detector as well as the Shi-Tomasi detector, by using
+- Implement our own version of the Harris detector as well as the Shi-Tomasi detector, by using
the two functions above.
Theory
@@ -19,10 +19,26 @@ Theory
Code
----
+@add_toggle_cpp
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/cornerDetector_Demo.cpp)
-@include cpp/tutorial_code/TrackingMotion/cornerDetector_Demo.cpp
+@include samples/cpp/tutorial_code/TrackingMotion/cornerDetector_Demo.cpp
+@end_toggle
+
+@add_toggle_java
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/TrackingMotion/generic_corner_detector/CornerDetectorDemo.java)
+
+@include samples/java/tutorial_code/TrackingMotion/generic_corner_detector/CornerDetectorDemo.java
+@end_toggle
+
+@add_toggle_python
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/TrackingMotion/generic_corner_detector/cornerDetector_Demo.py)
+
+@include samples/python/tutorial_code/TrackingMotion/generic_corner_detector/cornerDetector_Demo.py
+@end_toggle
Explanation
-----------
diff --git a/doc/tutorials/features2d/trackingmotion/good_features_to_track/good_features_to_track.markdown b/doc/tutorials/features2d/trackingmotion/good_features_to_track/good_features_to_track.markdown
index 7c48aa189a..70d25ab9e2 100644
--- a/doc/tutorials/features2d/trackingmotion/good_features_to_track/good_features_to_track.markdown
+++ b/doc/tutorials/features2d/trackingmotion/good_features_to_track/good_features_to_track.markdown
@@ -6,7 +6,7 @@ Goal
In this tutorial you will learn how to:
-- Use the function @ref cv::goodFeaturesToTrack to detect corners using the Shi-Tomasi method.
+- Use the function @ref cv::goodFeaturesToTrack to detect corners using the Shi-Tomasi method (@cite Shi94).
Theory
------
@@ -14,9 +14,23 @@ Theory
Code
----
+@add_toggle_cpp
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/goodFeaturesToTrack_Demo.cpp)
@include samples/cpp/tutorial_code/TrackingMotion/goodFeaturesToTrack_Demo.cpp
+@end_toggle
+
+@add_toggle_java
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/TrackingMotion/good_features_to_track/GoodFeaturesToTrackDemo.java)
+@include samples/java/tutorial_code/TrackingMotion/good_features_to_track/GoodFeaturesToTrackDemo.java
+@end_toggle
+
+@add_toggle_python
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/TrackingMotion/good_features_to_track/goodFeaturesToTrack_Demo.py)
+@include samples/python/tutorial_code/TrackingMotion/good_features_to_track/goodFeaturesToTrack_Demo.py
+@end_toggle
Explanation
-----------
@@ -24,4 +38,4 @@ Explanation
Result
------
-
+
diff --git a/doc/tutorials/features2d/trackingmotion/good_features_to_track/images/Feature_Detection_Result_a.jpg b/doc/tutorials/features2d/trackingmotion/good_features_to_track/images/Feature_Detection_Result_a.jpg
deleted file mode 100644
index cca9a2b438..0000000000
Binary files a/doc/tutorials/features2d/trackingmotion/good_features_to_track/images/Feature_Detection_Result_a.jpg and /dev/null differ
diff --git a/doc/tutorials/features2d/trackingmotion/good_features_to_track/images/Feature_Detection_Result_b.jpg b/doc/tutorials/features2d/trackingmotion/good_features_to_track/images/Feature_Detection_Result_b.jpg
deleted file mode 100644
index 129450eb4f..0000000000
Binary files a/doc/tutorials/features2d/trackingmotion/good_features_to_track/images/Feature_Detection_Result_b.jpg and /dev/null differ
diff --git a/doc/tutorials/features2d/trackingmotion/good_features_to_track/images/good_features_to_track_Shi_Tomasi.jpg b/doc/tutorials/features2d/trackingmotion/good_features_to_track/images/good_features_to_track_Shi_Tomasi.jpg
new file mode 100644
index 0000000000..007f09a203
Binary files /dev/null and b/doc/tutorials/features2d/trackingmotion/good_features_to_track/images/good_features_to_track_Shi_Tomasi.jpg differ
diff --git a/doc/tutorials/features2d/trackingmotion/harris_detector/harris_detector.markdown b/doc/tutorials/features2d/trackingmotion/harris_detector/harris_detector.markdown
index b1b8b67f1b..bbf4fdbd5b 100644
--- a/doc/tutorials/features2d/trackingmotion/harris_detector/harris_detector.markdown
+++ b/doc/tutorials/features2d/trackingmotion/harris_detector/harris_detector.markdown
@@ -118,9 +118,23 @@ In this tutorial we will study the *corner* features, specifically.
Code
----
+@add_toggle_cpp
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/cornerHarris_Demo.cpp)
@include samples/cpp/tutorial_code/TrackingMotion/cornerHarris_Demo.cpp
+@end_toggle
+
+@add_toggle_java
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/TrackingMotion/harris_detector/CornerHarrisDemo.java)
+@include samples/java/tutorial_code/TrackingMotion/harris_detector/CornerHarrisDemo.java
+@end_toggle
+
+@add_toggle_python
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/TrackingMotion/harris_detector/cornerHarris_Demo.py)
+@include samples/python/tutorial_code/TrackingMotion/harris_detector/cornerHarris_Demo.py
+@end_toggle
Explanation
-----------
diff --git a/doc/tutorials/viz/launching_viz/launching_viz.markdown b/doc/tutorials/viz/launching_viz/launching_viz.markdown
index 07719c67eb..d4ec97d49e 100644
--- a/doc/tutorials/viz/launching_viz/launching_viz.markdown
+++ b/doc/tutorials/viz/launching_viz/launching_viz.markdown
@@ -37,7 +37,7 @@ Here is the general structure of the program:
the same with **myWindow**. If the name does not exist, a new window is created.
@code{.cpp}
/// Access window via its name
- viz::Viz3d sameWindow = viz::get("Viz Demo");
+ viz::Viz3d sameWindow = viz::getWindowByName("Viz Demo");
@endcode
- Start a controlled event loop. Once it starts, **wasStopped** is set to false. Inside the while
loop, in each iteration, **spinOnce** is called to prevent event loop from completely stopping.
diff --git a/modules/calib3d/src/calibinit.cpp b/modules/calib3d/src/calibinit.cpp
index af7a3dd7bf..607c29e3cd 100644
--- a/modules/calib3d/src/calibinit.cpp
+++ b/modules/calib3d/src/calibinit.cpp
@@ -76,13 +76,17 @@
#include
#include
-using namespace cv;
-using namespace std;
+#include "opencv2/core/utility.hpp"
+#include
//#define ENABLE_TRIM_COL_ROW
//#define DEBUG_CHESSBOARD
+//#undef CV_LOG_STRIP_LEVEL
+//#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_VERBOSE + 1
+#include
+
#ifdef DEBUG_CHESSBOARD
static int PRINTF( const char* fmt, ... )
{
@@ -94,17 +98,34 @@ static int PRINTF( const char* fmt, ... )
#define PRINTF(...)
#endif
+using namespace cv;
+using namespace std;
+
//=====================================================================================
// Implementation for the enhanced calibration object detection
//=====================================================================================
#define MAX_CONTOUR_APPROX 7
+#define USE_CV_FINDCONTOURS // switch between cv::findContours() and legacy C API
+#ifdef USE_CV_FINDCONTOURS
+struct QuadCountour {
+ Point pt[4];
+ int parent_contour;
+
+ QuadCountour(const Point pt_[4], int parent_contour_) :
+ parent_contour(parent_contour_)
+ {
+ pt[0] = pt_[0]; pt[1] = pt_[1]; pt[2] = pt_[2]; pt[3] = pt_[3];
+ }
+};
+#else
struct CvContourEx
{
CV_CONTOUR_FIELDS()
int counter;
};
+#endif
//=====================================================================================
@@ -517,7 +538,11 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
int max_quad_buf_size = 0;
cvFree(&quads);
cvFree(&corners);
+#ifdef USE_CV_FINDCONTOURS
+ Mat binarized_img = thresh_img_new;
+#else
Mat binarized_img = thresh_img_new.clone(); // make clone because cvFindContours modifies the source image
+#endif
int quad_count = icvGenerateQuads( &quads, &corners, storage, binarized_img, flags, &max_quad_buf_size );
PRINTF("Quad count: %d/%d\n", quad_count, (pattern_size.width/2+1)*(pattern_size.height/2+1));
SHOW_QUADS("New quads", thresh_img_new, quads, quad_count);
@@ -583,7 +608,11 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
int max_quad_buf_size = 0;
cvFree(&quads);
cvFree(&corners);
+#ifdef USE_CV_FINDCONTOURS
+ Mat binarized_img = thresh_img;
+#else
Mat binarized_img = (useAdaptive) ? thresh_img : thresh_img.clone(); // make clone because cvFindContours modifies the source image
+#endif
int quad_count = icvGenerateQuads( &quads, &corners, storage, binarized_img, flags, &max_quad_buf_size);
PRINTF("Quad count: %d/%d\n", quad_count, (pattern_size.width/2+1)*(pattern_size.height/2+1));
SHOW_QUADS("Old quads", thresh_img, quads, quad_count);
@@ -1736,7 +1765,6 @@ static int
icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
CvMemStorage *storage, const cv::Mat & image_, int flags, int *max_quad_buf_size )
{
- CvMat image_old(image_), *image = &image_old;
int quad_count = 0;
cv::Ptr temp_storage;
@@ -1746,17 +1774,144 @@ icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
if( out_corners )
*out_corners = 0;
+ // empiric bound for minimal allowed perimeter for squares
+ int min_size = 25; //cvRound( image->cols * image->rows * .03 * 0.01 * 0.92 );
+
+ bool filterQuads = (flags & CALIB_CB_FILTER_QUADS) != 0;
+#ifdef USE_CV_FINDCONTOURS // use cv::findContours
+ CV_UNUSED(storage);
+
+ std::vector > contours;
+ std::vector hierarchy;
+
+ cv::findContours(image_, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
+
+ if (contours.empty())
+ {
+ CV_LOG_DEBUG(NULL, "calib3d(chessboard): cv::findContours() returns no contours");
+ *max_quad_buf_size = 0;
+ return 0;
+ }
+
+ std::vector contour_child_counter(contours.size(), 0);
+ int boardIdx = -1;
+
+ std::vector contour_quads;
+
+ for (int idx = (int)(contours.size() - 1); idx >= 0; --idx)
+ {
+ int parentIdx = hierarchy[idx][3];
+ if (hierarchy[idx][2] != -1 || parentIdx == -1) // holes only (no child contours and with parent)
+ continue;
+ const std::vector& contour = contours[idx];
+
+ Rect contour_rect = boundingRect(contour);
+ if (contour_rect.area() < min_size)
+ continue;
+
+ std::vector approx_contour;
+
+ const int min_approx_level = 1, max_approx_level = MAX_CONTOUR_APPROX;
+ for (int approx_level = min_approx_level; approx_level <= max_approx_level; approx_level++ )
+ {
+ approxPolyDP(contour, approx_contour, (float)approx_level, true);
+ if (approx_contour.size() == 4)
+ break;
+
+ // we call this again on its own output, because sometimes
+ // approxPoly() does not simplify as much as it should.
+ std::vector approx_contour_tmp;
+ std::swap(approx_contour, approx_contour_tmp);
+ approxPolyDP(approx_contour_tmp, approx_contour, (float)approx_level, true);
+ if (approx_contour.size() == 4)
+ break;
+ }
+
+ // reject non-quadrangles
+ if (approx_contour.size() != 4)
+ continue;
+ if (!cv::isContourConvex(approx_contour))
+ continue;
+
+ cv::Point pt[4];
+ for (int i = 0; i < 4; ++i)
+ pt[i] = approx_contour[i];
+ CV_LOG_VERBOSE(NULL, 9, "... contours(" << contour_quads.size() << " added):" << pt[0] << " " << pt[1] << " " << pt[2] << " " << pt[3]);
+
+ if (filterQuads)
+ {
+ double p = cv::arcLength(approx_contour, true);
+ double area = cv::contourArea(approx_contour, false);
+
+ double d1 = sqrt(normL2Sqr(pt[0] - pt[2]));
+ double d2 = sqrt(normL2Sqr(pt[1] - pt[3]));
+
+ // philipg. Only accept those quadrangles which are more square
+ // than rectangular and which are big enough
+ double d3 = sqrt(normL2Sqr(pt[0] - pt[1]));
+ double d4 = sqrt(normL2Sqr(pt[1] - pt[2]));
+ if (!(d3*4 > d4 && d4*4 > d3 && d3*d4 < area*1.5 && area > min_size &&
+ d1 >= 0.15 * p && d2 >= 0.15 * p))
+ continue;
+ }
+
+ contour_child_counter[parentIdx]++;
+ if (boardIdx != parentIdx && (boardIdx < 0 || contour_child_counter[boardIdx] < contour_child_counter[parentIdx]))
+ boardIdx = parentIdx;
+
+ contour_quads.push_back(QuadCountour(pt, parentIdx));
+ }
+
+ size_t total = contour_quads.size();
+ *max_quad_buf_size = (int)std::max((size_t)2, total * 3);
+ *out_quads = (CvCBQuad*)cvAlloc(*max_quad_buf_size * sizeof((*out_quads)[0]));
+ *out_corners = (CvCBCorner*)cvAlloc(*max_quad_buf_size * 4 * sizeof((*out_corners)[0]));
+
+ // Create array of quads structures
+ for(int idx = 0; idx < (int)contour_quads.size(); idx++ )
+ {
+ CvCBQuad* q = &(*out_quads)[quad_count];
+
+ QuadCountour& qc = contour_quads[idx];
+ if (filterQuads && qc.parent_contour != boardIdx)
+ continue;
+
+ // reset group ID
+ memset(q, 0, sizeof(*q));
+ q->group_idx = -1;
+ for (int i = 0; i < 4; ++i)
+ {
+ CvCBCorner* corner = &(*out_corners)[quad_count*4 + i];
+
+ memset(corner, 0, sizeof(*corner));
+ corner->pt = qc.pt[i];
+ q->corners[i] = corner;
+ }
+ q->edge_len = FLT_MAX;
+ for (int i = 0; i < 4; ++i)
+ {
+ // TODO simplify with normL2Sqr()
+ float dx = q->corners[i]->pt.x - q->corners[(i+1)&3]->pt.x;
+ float dy = q->corners[i]->pt.y - q->corners[(i+1)&3]->pt.y;
+ float d = dx*dx + dy*dy;
+ if (q->edge_len > d)
+ q->edge_len = d;
+ }
+ quad_count++;
+ }
+
+#else // use legacy API: cvStartFindContours / cvFindNextContour / cvEndFindContours
+
+ CvMat image_old(image_), *image = &image_old;
+
CvSeq *src_contour = 0;
CvSeq *root;
CvContourEx* board = 0;
CvContourScanner scanner;
- int i, idx, min_size;
+ int i, idx;
CV_Assert( out_corners && out_quads );
- // empiric bound for minimal allowed perimeter for squares
- min_size = 25; //cvRound( image->cols * image->rows * .03 * 0.01 * 0.92 );
-
// create temporary storage for contours and the sequence of pointers to found quadrangles
temp_storage.reset(cvCreateChildMemStorage( storage ));
root = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvSeq*), temp_storage );
@@ -1820,9 +1975,9 @@ icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
dx = pt[1].x - pt[2].x;
dy = pt[1].y - pt[2].y;
d4 = sqrt(dx*dx + dy*dy);
- if( !(flags & CV_CALIB_CB_FILTER_QUADS) ||
+ if (!filterQuads ||
(d3*4 > d4 && d4*4 > d3 && d3*d4 < area*1.5 && area > min_size &&
- d1 >= 0.15 * p && d2 >= 0.15 * p) )
+ d1 >= 0.15 * p && d2 >= 0.15 * p))
{
CvContourEx* parent = (CvContourEx*)(src_contour->v_prev);
parent->counter++;
@@ -1840,7 +1995,8 @@ icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
cvEndFindContours( &scanner );
// allocate quad & corner buffers
- *max_quad_buf_size = MAX(1, (root->total+root->total / 2)) * 2;
+ int total = root->total;
+ *max_quad_buf_size = MAX(1, (total + total / 2)) * 2;
*out_quads = (CvCBQuad*)cvAlloc(*max_quad_buf_size * sizeof((*out_quads)[0]));
*out_corners = (CvCBCorner*)cvAlloc(*max_quad_buf_size * 4 * sizeof((*out_corners)[0]));
@@ -1849,7 +2005,7 @@ icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
{
CvCBQuad* q = &(*out_quads)[quad_count];
src_contour = *(CvSeq**)cvGetSeqElem( root, idx );
- if( (flags & CV_CALIB_CB_FILTER_QUADS) && src_contour->v_prev != (CvSeq*)board )
+ if (filterQuads && src_contour->v_prev != (CvSeq*)board)
continue;
// reset group ID
@@ -1878,6 +2034,11 @@ icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
}
quad_count++;
}
+#endif
+
+ CV_LOG_VERBOSE(NULL, 3, "Total quad contours: " << total);
+ CV_LOG_VERBOSE(NULL, 3, "max_quad_buf_size=" << *max_quad_buf_size);
+ CV_LOG_VERBOSE(NULL, 3, "filtered quad_count=" << quad_count);
return quad_count;
}
diff --git a/modules/calib3d/src/ptsetreg.cpp b/modules/calib3d/src/ptsetreg.cpp
index e26e67dc3e..1ed98756ec 100644
--- a/modules/calib3d/src/ptsetreg.cpp
+++ b/modules/calib3d/src/ptsetreg.cpp
@@ -78,10 +78,7 @@ class RANSACPointSetRegistrator : public PointSetRegistrator
public:
RANSACPointSetRegistrator(const Ptr& _cb=Ptr(),
int _modelPoints=0, double _threshold=0, double _confidence=0.99, int _maxIters=1000)
- : cb(_cb), modelPoints(_modelPoints), threshold(_threshold), confidence(_confidence), maxIters(_maxIters)
- {
- checkPartialSubsets = false;
- }
+ : cb(_cb), modelPoints(_modelPoints), threshold(_threshold), confidence(_confidence), maxIters(_maxIters) {}
int findInliers( const Mat& m1, const Mat& m2, const Mat& model, Mat& err, Mat& mask, double thresh ) const
{
@@ -143,17 +140,9 @@ public:
ms1ptr[i*esz1 + k] = m1ptr[idx_i*esz1 + k];
for( k = 0; k < esz2; k++ )
ms2ptr[i*esz2 + k] = m2ptr[idx_i*esz2 + k];
- if( checkPartialSubsets && !cb->checkSubset( ms1, ms2, i+1 ))
- {
- // we may have selected some bad points;
- // so, let's remove some of them randomly
- i = rng.uniform(0, i+1);
- iters++;
- continue;
- }
i++;
}
- if( !checkPartialSubsets && i == modelPoints && !cb->checkSubset(ms1, ms2, i))
+ if( i == modelPoints && !cb->checkSubset(ms1, ms2, i) )
continue;
break;
}
@@ -261,7 +250,6 @@ public:
Ptr cb;
int modelPoints;
- bool checkPartialSubsets;
double threshold;
double confidence;
int maxIters;
diff --git a/modules/calib3d/src/stereobm.cpp b/modules/calib3d/src/stereobm.cpp
index b3498c66d1..7aa721dd3d 100644
--- a/modules/calib3d/src/stereobm.cpp
+++ b/modules/calib3d/src/stereobm.cpp
@@ -284,7 +284,39 @@ prefilterXSobel( const Mat& src, Mat& dst, int ftzero )
static const int DISPARITY_SHIFT_16S = 4;
static const int DISPARITY_SHIFT_32S = 8;
+template
+struct dispShiftTemplate
+{ };
+
+template<>
+struct dispShiftTemplate
+{
+ enum { value = DISPARITY_SHIFT_16S };
+};
+
+template<>
+struct dispShiftTemplate
+{
+ enum { value = DISPARITY_SHIFT_32S };
+};
+
+template
+inline T dispDescale(int /*v1*/, int /*v2*/, int /*d*/);
+
+template<>
+inline short dispDescale(int v1, int v2, int d)
+{
+ return (short)((v1*256 + (d != 0 ? v2*256/d : 0) + 15) >> 4);
+}
+
+template <>
+inline int dispDescale(int v1, int v2, int d)
+{
+ return (int)(v1*256 + (d != 0 ? v2*256/d : 0)); // no need to add 127, this will be converted to float
+}
+
#if CV_SIMD128
+template
static void findStereoCorrespondenceBM_SIMD( const Mat& left, const Mat& right,
Mat& disp, Mat& cost, StereoBMParams& state,
uchar* buf, int _dy0, int _dy1 )
@@ -302,7 +334,8 @@ static void findStereoCorrespondenceBM_SIMD( const Mat& left, const Mat& right,
int ftzero = state.preFilterCap;
int textureThreshold = state.textureThreshold;
int uniquenessRatio = state.uniquenessRatio;
- short FILTERED = (short)((mindisp - 1) << DISPARITY_SHIFT_16S);
+ const int disp_shift = dispShiftTemplate::value;
+ dType FILTERED = (dType)((mindisp - 1) << disp_shift);
ushort *sad, *hsad0, *hsad, *hsad_sub;
int *htext;
@@ -310,7 +343,7 @@ static void findStereoCorrespondenceBM_SIMD( const Mat& left, const Mat& right,
const uchar* lptr0 = left.ptr() + lofs;
const uchar* rptr0 = right.ptr() + rofs;
const uchar *lptr, *lptr_sub, *rptr;
- short* dptr = disp.ptr();
+ dType* dptr = disp.ptr();
int sstep = (int)left.step;
int dstep = (int)(disp.step/sizeof(dptr[0]));
int cstep = (height + dy0 + dy1)*ndisp;
@@ -527,10 +560,10 @@ static void findStereoCorrespondenceBM_SIMD( const Mat& left, const Mat& right,
{
int p = sad[mind+1], n = sad[mind-1];
d = p + n - 2*sad[mind] + std::abs(p - n);
- dptr[y*dstep] = (short)(((ndisp - mind - 1 + mindisp)*256 + (d != 0 ? (p-n)*256/d : 0) + 15) >> 4);
+ dptr[y*dstep] = dispDescale(ndisp - mind - 1 + mindisp, p-n, d);
}
else
- dptr[y*dstep] = (short)((ndisp - mind - 1 + mindisp)*16);
+ dptr[y*dstep] = dispDescale(ndisp - mind - 1 + mindisp, 0, 0);
costptr[y*coststep] = sad[mind];
}
}
@@ -540,8 +573,8 @@ static void findStereoCorrespondenceBM_SIMD( const Mat& left, const Mat& right,
template
static void
findStereoCorrespondenceBM( const Mat& left, const Mat& right,
- Mat& disp, Mat& cost, const StereoBMParams& state,
- uchar* buf, int _dy0, int _dy1, const int disp_shift )
+ Mat& disp, Mat& cost, const StereoBMParams& state,
+ uchar* buf, int _dy0, int _dy1 )
{
const int ALIGN = 16;
@@ -557,6 +590,7 @@ findStereoCorrespondenceBM( const Mat& left, const Mat& right,
int ftzero = state.preFilterCap;
int textureThreshold = state.textureThreshold;
int uniquenessRatio = state.uniquenessRatio;
+ const int disp_shift = dispShiftTemplate::value;
mType FILTERED = (mType)((mindisp - 1) << disp_shift);
#if CV_SIMD128
@@ -849,8 +883,8 @@ findStereoCorrespondenceBM( const Mat& left, const Mat& right,
sad[ndisp] = sad[ndisp-2];
int p = sad[mind+1], n = sad[mind-1];
d = p + n - 2*sad[mind] + std::abs(p - n);
- dptr[y*dstep] = (mType)(((ndisp - mind - 1 + mindisp)*256 + (d != 0 ? (p-n)*256/d : 0) + 15)
- >> (DISPARITY_SHIFT_32S - disp_shift));
+ dptr[y*dstep] = dispDescale(ndisp - mind - 1 + mindisp, p-n, d);
+
costptr[y*coststep] = sad[mind];
}
}
@@ -980,7 +1014,10 @@ struct FindStereoCorrespInvoker : public ParallelLoopBody
int _row0 = std::min(cvRound(range.start * rows / nstripes), rows);
int _row1 = std::min(cvRound(range.end * rows / nstripes), rows);
uchar *ptr = slidingSumBuf->ptr() + range.start * stripeBufSize;
- int FILTERED = (state->minDisparity - 1)*16;
+
+ int dispShift = disp->type() == CV_16S ? DISPARITY_SHIFT_16S :
+ DISPARITY_SHIFT_32S;
+ int FILTERED = (state->minDisparity - 1) << dispShift;
Rect roi = validDisparityRect & Rect(0, _row0, cols, _row1 - _row0);
if( roi.height == 0 )
@@ -1008,15 +1045,18 @@ struct FindStereoCorrespInvoker : public ParallelLoopBody
#if CV_SIMD128
if( useSIMD && useShorts )
{
- findStereoCorrespondenceBM_SIMD( left_i, right_i, disp_i, cost_i, *state, ptr, row0, rows - row1 );
+ if( disp_i.type() == CV_16S)
+ findStereoCorrespondenceBM_SIMD( left_i, right_i, disp_i, cost_i, *state, ptr, row0, rows - row1 );
+ else
+ findStereoCorrespondenceBM_SIMD( left_i, right_i, disp_i, cost_i, *state, ptr, row0, rows - row1);
}
else
#endif
{
if( disp_i.type() == CV_16S )
- findStereoCorrespondenceBM( left_i, right_i, disp_i, cost_i, *state, ptr, row0, rows - row1, DISPARITY_SHIFT_16S );
+ findStereoCorrespondenceBM( left_i, right_i, disp_i, cost_i, *state, ptr, row0, rows - row1 );
else
- findStereoCorrespondenceBM( left_i, right_i, disp_i, cost_i, *state, ptr, row0, rows - row1, DISPARITY_SHIFT_32S );
+ findStereoCorrespondenceBM( left_i, right_i, disp_i, cost_i, *state, ptr, row0, rows - row1 );
}
if( state->disp12MaxDiff >= 0 )
@@ -1104,7 +1144,6 @@ public:
else
disp_shift = DISPARITY_SHIFT_32S;
-
int FILTERED = (params.minDisparity - 1) << disp_shift;
#ifdef HAVE_OPENCL
@@ -1115,6 +1154,9 @@ public:
{
if(ocl_stereobm(left, right, disparr, ¶ms))
{
+ disp_shift = DISPARITY_SHIFT_16S;
+ FILTERED = (params.minDisparity - 1) << disp_shift;
+
if( params.speckleRange >= 0 && params.speckleWindowSize > 0 )
filterSpeckles(disparr.getMat(), FILTERED, params.speckleWindowSize, params.speckleRange, slidingSumBuf);
if (dtype == CV_32F)
diff --git a/modules/calib3d/test/test_stereomatching.cpp b/modules/calib3d/test/test_stereomatching.cpp
index 601e0cb93b..94fc9718cc 100644
--- a/modules/calib3d/test/test_stereomatching.cpp
+++ b/modules/calib3d/test/test_stereomatching.cpp
@@ -556,7 +556,7 @@ int CV_StereoMatchingTest::processStereoMatchingResults( FileStorage& fs, int ca
assert( fs.isOpened() );
assert( trueLeftDisp.type() == CV_32FC1 );
assert( trueRightDisp.empty() || trueRightDisp.type() == CV_32FC1 );
- assert( leftDisp.type() == CV_32FC1 && rightDisp.type() == CV_32FC1 );
+ assert( leftDisp.type() == CV_32FC1 && (rightDisp.empty() || rightDisp.type() == CV_32FC1) );
// get masks for unknown ground truth disparity values
Mat leftUnknMask, rightUnknMask;
@@ -791,6 +791,12 @@ protected:
bm->compute( leftImg, rightImg, tempDisp );
tempDisp.convertTo(leftDisp, CV_32F, 1./StereoMatcher::DISP_SCALE);
+ //check for fixed-type disparity data type
+ Mat_ fixedFloatDisp;
+ bm->compute( leftImg, rightImg, fixedFloatDisp );
+ EXPECT_LT(cvtest::norm(fixedFloatDisp, leftDisp, cv::NORM_L2 | cv::NORM_RELATIVE),
+ 0.005 + DBL_EPSILON);
+
if (params.mindisp != 0)
for (int y = 0; y < leftDisp.rows; y++)
for (int x = 0; x < leftDisp.cols; x++)
diff --git a/modules/core/include/opencv2/core.hpp b/modules/core/include/opencv2/core.hpp
index c0c6c178f8..a560ffc1d1 100644
--- a/modules/core/include/opencv2/core.hpp
+++ b/modules/core/include/opencv2/core.hpp
@@ -532,8 +532,9 @@ CV_EXPORTS_W void convertScaleAbs(InputArray src, OutputArray dst,
/** @brief Converts an array to half precision floating number.
-This function converts FP32 (single precision floating point) from/to FP16 (half precision floating point). The input array has to have type of CV_32F or
-CV_16S to represent the bit depth. If the input array is neither of them, the function will raise an error.
+This function converts FP32 (single precision floating point) from/to FP16 (half precision floating point). CV_16S format is used to represent FP16 data.
+There are two use modes (src -> dst): CV_32F -> CV_16S and CV_16S -> CV_32F. The input array has to have type of CV_32F or
+CV_16S to represent the bit depth. If the input array is neither of them, the function will raise an error.
The format of half precision floating point is defined in IEEE 754-2008.
@param src input array.
diff --git a/modules/core/include/opencv2/core/cvstd.inl.hpp b/modules/core/include/opencv2/core/cvstd.inl.hpp
index f1637c44f0..631fe94e1a 100644
--- a/modules/core/include/opencv2/core/cvstd.inl.hpp
+++ b/modules/core/include/opencv2/core/cvstd.inl.hpp
@@ -77,11 +77,8 @@ inline
String::String(const std::string& str)
: cstr_(0), len_(0)
{
- if (!str.empty())
- {
- size_t len = str.size();
- if (len) memcpy(allocate(len), str.c_str(), len);
- }
+ size_t len = str.size();
+ if (len) memcpy(allocate(len), str.c_str(), len);
}
inline
@@ -99,11 +96,8 @@ inline
String& String::operator = (const std::string& str)
{
deallocate();
- if (!str.empty())
- {
- size_t len = str.size();
- if (len) memcpy(allocate(len), str.c_str(), len);
- }
+ size_t len = str.size();
+ if (len) memcpy(allocate(len), str.c_str(), len);
return *this;
}
diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp
index fad989c0b2..be14227f47 100644
--- a/modules/core/include/opencv2/core/mat.inl.hpp
+++ b/modules/core/include/opencv2/core/mat.inl.hpp
@@ -1649,7 +1649,7 @@ Mat_<_Tp>& Mat_<_Tp>::operator = (const Mat& m)
{
return (*this = m.reshape(DataType<_Tp>::channels, m.dims, 0));
}
- CV_DbgAssert(DataType<_Tp>::channels == m.channels());
+ CV_Assert(DataType<_Tp>::channels == m.channels() || m.empty());
m.convertTo(*this, type());
return *this;
}
diff --git a/modules/core/include/opencv2/core/types.hpp b/modules/core/include/opencv2/core/types.hpp
index fdb52efe8e..c3644cbda0 100644
--- a/modules/core/include/opencv2/core/types.hpp
+++ b/modules/core/include/opencv2/core/types.hpp
@@ -1372,6 +1372,20 @@ Point_<_Tp> operator / (const Point_<_Tp>& a, double b)
}
+template static inline _AccTp normL2Sqr(const Point_& pt);
+template static inline _AccTp normL2Sqr(const Point_& pt);
+template static inline _AccTp normL2Sqr(const Point_& pt);
+template static inline _AccTp normL2Sqr(const Point_& pt);
+
+template<> inline int normL2Sqr(const Point_& pt) { return pt.dot(pt); }
+template<> inline int64 normL2Sqr(const Point_& pt) { return pt.dot(pt); }
+template<> inline float normL2Sqr(const Point_& pt) { return pt.dot(pt); }
+template<> inline double normL2Sqr(const Point_& pt) { return pt.dot(pt); }
+
+template<> inline double normL2Sqr(const Point_& pt) { return pt.ddot(pt); }
+template<> inline double normL2Sqr(const Point_& pt) { return pt.ddot(pt); }
+
+
//////////////////////////////// 3D Point ///////////////////////////////
diff --git a/modules/core/src/arithm.cpp b/modules/core/src/arithm.cpp
index 2d9f90e206..a3e6c46b2a 100644
--- a/modules/core/src/arithm.cpp
+++ b/modules/core/src/arithm.cpp
@@ -1180,6 +1180,12 @@ void cv::compare(InputArray _src1, InputArray _src2, OutputArray _dst, int op)
CV_Assert( op == CMP_LT || op == CMP_LE || op == CMP_EQ ||
op == CMP_NE || op == CMP_GE || op == CMP_GT );
+ if(_src1.empty() && _src2.empty())
+ {
+ _dst.release();
+ return;
+ }
+
bool haveScalar = false;
if ((_src1.isMatx() + _src2.isMatx()) == 1
diff --git a/modules/core/src/convert.cpp b/modules/core/src/convert.cpp
index 0fb1199987..481b86b4f1 100644
--- a/modules/core/src/convert.cpp
+++ b/modules/core/src/convert.cpp
@@ -1304,6 +1304,12 @@ void cv::Mat::convertTo(OutputArray _dst, int _type, double alpha, double beta)
{
CV_INSTRUMENT_REGION()
+ if( empty() )
+ {
+ _dst.release();
+ return;
+ }
+
bool noScale = fabs(alpha-1) < DBL_EPSILON && fabs(beta) < DBL_EPSILON;
if( _type < 0 )
diff --git a/modules/core/src/copy.cpp b/modules/core/src/copy.cpp
index f4f18cb740..5e7f4a879a 100644
--- a/modules/core/src/copy.cpp
+++ b/modules/core/src/copy.cpp
@@ -246,13 +246,14 @@ void Mat::copyTo( OutputArray _dst ) const
return;
}
+ if( empty() )
+ {
+ _dst.release();
+ return;
+ }
+
if( _dst.isUMat() )
{
- if( empty() )
- {
- _dst.release();
- return;
- }
_dst.create( dims, size.p, type() );
UMat dst = _dst.getUMat();
CV_Assert(dst.u != NULL);
diff --git a/modules/dnn/include/opencv2/dnn.hpp b/modules/dnn/include/opencv2/dnn.hpp
index 57a564bf11..af919005f6 100644
--- a/modules/dnn/include/opencv2/dnn.hpp
+++ b/modules/dnn/include/opencv2/dnn.hpp
@@ -42,7 +42,7 @@
#ifndef OPENCV_DNN_HPP
#define OPENCV_DNN_HPP
-// This is an umbrealla header to include into you project.
+// This is an umbrella header to include into you project.
// We are free to change headers layout in dnn subfolder, so please include
// this header for future compatibility
@@ -52,10 +52,10 @@
This module contains:
- API for new layers creation, layers are building bricks of neural networks;
- set of built-in most-useful Layers;
- - API to constuct and modify comprehensive neural networks from layers;
+ - API to construct and modify comprehensive neural networks from layers;
- functionality for loading serialized networks models from different frameworks.
- Functionality of this module is designed only for forward pass computations (i. e. network testing).
+ Functionality of this module is designed only for forward pass computations (i.e. network testing).
A network training is in principle not supported.
@}
*/
diff --git a/modules/dnn/include/opencv2/dnn/all_layers.hpp b/modules/dnn/include/opencv2/dnn/all_layers.hpp
index f2124dd516..cc8521586c 100644
--- a/modules/dnn/include/opencv2/dnn/all_layers.hpp
+++ b/modules/dnn/include/opencv2/dnn/all_layers.hpp
@@ -58,7 +58,7 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
You can use both API, but factory API is less convenient for native C++ programming and basically designed for use inside importers (see @ref readNetFromCaffe(), @ref readNetFromTorch(), @ref readNetFromTensorflow()).
Built-in layers partially reproduce functionality of corresponding Caffe and Torch7 layers.
- In partuclar, the following layers and Caffe importer were tested to reproduce Caffe functionality:
+ In particular, the following layers and Caffe importer were tested to reproduce Caffe functionality:
- Convolution
- Deconvolution
- Pooling
@@ -108,13 +108,13 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
@f$W_{x?} \in R^{N_h \times N_x}@f$, @f$W_{h?} \in R^{N_h \times N_h}@f$, @f$b_? \in R^{N_h}@f$.
For simplicity and performance purposes we use @f$ W_x = [W_{xi}; W_{xf}; W_{xo}, W_{xg}] @f$
- (i.e. @f$W_x@f$ is vertical contacentaion of @f$ W_{x?} @f$), @f$ W_x \in R^{4N_h \times N_x} @f$.
+ (i.e. @f$W_x@f$ is vertical concatenation of @f$ W_{x?} @f$), @f$ W_x \in R^{4N_h \times N_x} @f$.
The same for @f$ W_h = [W_{hi}; W_{hf}; W_{ho}, W_{hg}], W_h \in R^{4N_h \times N_h} @f$
and for @f$ b = [b_i; b_f, b_o, b_g]@f$, @f$b \in R^{4N_h} @f$.
- @param Wh is matrix defining how previous output is transformed to internal gates (i.e. according to abovemtioned notation is @f$ W_h @f$)
- @param Wx is matrix defining how current input is transformed to internal gates (i.e. according to abovemtioned notation is @f$ W_x @f$)
- @param b is bias vector (i.e. according to abovemtioned notation is @f$ b @f$)
+ @param Wh is matrix defining how previous output is transformed to internal gates (i.e. according to above mentioned notation is @f$ W_h @f$)
+ @param Wx is matrix defining how current input is transformed to internal gates (i.e. according to above mentioned notation is @f$ W_x @f$)
+ @param b is bias vector (i.e. according to above mentioned notation is @f$ b @f$)
*/
CV_DEPRECATED virtual void setWeights(const Mat &Wh, const Mat &Wx, const Mat &b) = 0;
@@ -148,7 +148,7 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
* If setUseTimstampsDim() is set to true then @p input[0] should has at least two dimensions with the following shape: [`T`, `N`, `[data dims]`],
* where `T` specifies number of timestamps, `N` is number of independent streams (i.e. @f$ x_{t_0 + t}^{stream} @f$ is stored inside @p input[0][t, stream, ...]).
*
- * If setUseTimstampsDim() is set to fase then @p input[0] should contain single timestamp, its shape should has form [`N`, `[data dims]`] with at least one dimension.
+ * If setUseTimstampsDim() is set to false then @p input[0] should contain single timestamp, its shape should has form [`N`, `[data dims]`] with at least one dimension.
* (i.e. @f$ x_{t}^{stream} @f$ is stored inside @p input[0][stream, ...]).
*/
@@ -550,7 +550,7 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
* dst(x, y, c) = \frac{ src(x, y, c) }{norm(c)}
* @f]
*
- * Where `x, y` - spatial cooridnates, `c` - channel.
+ * Where `x, y` - spatial coordinates, `c` - channel.
*
* An every sample in the batch is normalized separately. Optionally,
* output is scaled by the trained parameters.
@@ -565,7 +565,7 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
};
/**
- * @brief Resize input 4-dimensional blob by nearest neghbor strategy.
+ * @brief Resize input 4-dimensional blob by nearest neighbor strategy.
*
* Layer is used to support TensorFlow's resize_nearest_neighbor op.
*/
@@ -581,6 +581,12 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
static Ptr create(const LayerParams& params);
};
+ class CV_EXPORTS CropAndResizeLayer : public Layer
+ {
+ public:
+ static Ptr create(const LayerParams& params);
+ };
+
//! @}
//! @}
CV__DNN_EXPERIMENTAL_NS_END
diff --git a/modules/dnn/include/opencv2/dnn/dnn.hpp b/modules/dnn/include/opencv2/dnn/dnn.hpp
index 6ac2f1a7fe..2a1d68af7e 100644
--- a/modules/dnn/include/opencv2/dnn/dnn.hpp
+++ b/modules/dnn/include/opencv2/dnn/dnn.hpp
@@ -81,12 +81,13 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
{
DNN_TARGET_CPU,
DNN_TARGET_OPENCL,
- DNN_TARGET_OPENCL_FP16
+ DNN_TARGET_OPENCL_FP16,
+ DNN_TARGET_MYRIAD
};
/** @brief This class provides all data needed to initialize layer.
*
- * It includes dictionary with scalar params (which can be readed by using Dict interface),
+ * It includes dictionary with scalar params (which can be read by using Dict interface),
* blob params #blobs and optional meta information: #name and #type of layer instance.
*/
class CV_EXPORTS LayerParams : public Dict
@@ -137,7 +138,7 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
* Initialize wrapper from another one. It'll wrap the same host CPU
* memory and mustn't allocate memory on device(i.e. GPU). It might
* has different shape. Use in case of CPU memory reusing for reuse
- * associented memory on device too.
+ * associated memory on device too.
*/
BackendWrapper(const Ptr& base, const MatShape& shape);
@@ -345,7 +346,7 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
/** @brief Create a network from Intel's Model Optimizer intermediate representation.
* @param[in] xml XML configuration file with network's topology.
* @param[in] bin Binary file with trained weights.
- * Networks imported from Intel's Model Optimizer are lauched in Intel's Inference Engine
+ * Networks imported from Intel's Model Optimizer are launched in Intel's Inference Engine
* backend.
*/
CV_WRAP static Net readFromModelOptimizer(const String& xml, const String& bin);
@@ -401,8 +402,8 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
/** @brief Connects #@p outNum output of the first layer to #@p inNum input of the second layer.
* @param outLayerId identifier of the first layer
- * @param inpLayerId identifier of the second layer
* @param outNum number of the first layer output
+ * @param inpLayerId identifier of the second layer
* @param inpNum number of the second layer input
*/
void connect(int outLayerId, int outNum, int inpLayerId, int inpNum);
@@ -563,7 +564,7 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
*/
CV_WRAP int getLayersCount(const String& layerType) const;
- /** @brief Computes bytes number which are requered to store
+ /** @brief Computes bytes number which are required to store
* all weights and intermediate blobs for model.
* @param netInputShapes vector of shapes for all net inputs.
* @param weights output parameter to store resulting bytes for weights.
@@ -583,7 +584,7 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
const MatShape& netInputShape,
CV_OUT size_t& weights, CV_OUT size_t& blobs) const;
- /** @brief Computes bytes number which are requered to store
+ /** @brief Computes bytes number which are required to store
* all weights and intermediate blobs for each layer.
* @param netInputShapes vector of shapes for all net inputs.
* @param layerIds output vector to save layer IDs.
@@ -700,13 +701,13 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
* * `*.pb` (TensorFlow, https://www.tensorflow.org/)
* * `*.t7` | `*.net` (Torch, http://torch.ch/)
* * `*.weights` (Darknet, https://pjreddie.com/darknet/)
- * * `*.bin` (DLDT, https://software.seek.intel.com/deep-learning-deployment)
+ * * `*.bin` (DLDT, https://software.intel.com/openvino-toolkit)
* @param[in] config Text file contains network configuration. It could be a
* file with the following extensions:
* * `*.prototxt` (Caffe, http://caffe.berkeleyvision.org/)
* * `*.pbtxt` (TensorFlow, https://www.tensorflow.org/)
* * `*.cfg` (Darknet, https://pjreddie.com/darknet/)
- * * `*.xml` (DLDT, https://software.seek.intel.com/deep-learning-deployment)
+ * * `*.xml` (DLDT, https://software.intel.com/openvino-toolkit)
* @param[in] framework Explicit framework name tag to determine a format.
* @returns Net object.
*
@@ -726,7 +727,7 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
* @param[in] xml XML configuration file with network's topology.
* @param[in] bin Binary file with trained weights.
* @returns Net object.
- * Networks imported from Intel's Model Optimizer are lauched in Intel's Inference Engine
+ * Networks imported from Intel's Model Optimizer are launched in Intel's Inference Engine
* backend.
*/
CV_EXPORTS_W Net readNetFromModelOptimizer(const String &xml, const String &bin);
@@ -744,7 +745,7 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
* @details if @p crop is true, input image is resized so one side after resize is equal to corresponding
* dimension in @p size and another one is equal or larger. Then, crop from the center is performed.
* If @p crop is false, direct resize without cropping and preserving aspect ratio is performed.
- * @returns 4-dimansional Mat with NCHW dimensions order.
+ * @returns 4-dimensional Mat with NCHW dimensions order.
*/
CV_EXPORTS_W Mat blobFromImage(InputArray image, double scalefactor=1.0, const Size& size = Size(),
const Scalar& mean = Scalar(), bool swapRB=true, bool crop=true);
diff --git a/modules/dnn/misc/quantize_face_detector.py b/modules/dnn/misc/quantize_face_detector.py
index c66b735847..8a8b88d181 100644
--- a/modules/dnn/misc/quantize_face_detector.py
+++ b/modules/dnn/misc/quantize_face_detector.py
@@ -223,9 +223,9 @@ with tf.Session() as sess:
# By default, float16 weights are stored in repeated tensor's field called
# `half_val`. It has type int32 with leading zeros for unused bytes.
- # This type is encoded by Varint that means only 7 bits are used for value
+ # This type is encoded by Variant that means only 7 bits are used for value
# representation but the last one is indicated the end of encoding. This way
- # float16 might takes 1 or 2 or 3 bytes depends on value. To impove compression,
+ # float16 might takes 1 or 2 or 3 bytes depends on value. To improve compression,
# we replace all `half_val` values to `tensor_content` using only 2 bytes for everyone.
for node in graph_def.node:
if 'value' in node.attr:
diff --git a/modules/dnn/perf/perf_net.cpp b/modules/dnn/perf/perf_net.cpp
index c05a7088cd..aa4ac05881 100644
--- a/modules/dnn/perf/perf_net.cpp
+++ b/modules/dnn/perf/perf_net.cpp
@@ -13,7 +13,7 @@
namespace opencv_test {
CV_ENUM(DNNBackend, DNN_BACKEND_DEFAULT, DNN_BACKEND_HALIDE, DNN_BACKEND_INFERENCE_ENGINE)
-CV_ENUM(DNNTarget, DNN_TARGET_CPU, DNN_TARGET_OPENCL, DNN_TARGET_OPENCL_FP16)
+CV_ENUM(DNNTarget, DNN_TARGET_CPU, DNN_TARGET_OPENCL, DNN_TARGET_OPENCL_FP16, DNN_TARGET_MYRIAD)
class DNNTestNetwork : public ::perf::TestBaseWithParam< tuple >
{
@@ -29,6 +29,28 @@ public:
target = (dnn::Target)(int)get<1>(GetParam());
}
+ static bool checkMyriadTarget()
+ {
+#ifndef HAVE_INF_ENGINE
+ return false;
+#endif
+ cv::dnn::Net net;
+ cv::dnn::LayerParams lp;
+ net.addLayerToPrev("testLayer", "Identity", lp);
+ net.setPreferableBackend(cv::dnn::DNN_BACKEND_INFERENCE_ENGINE);
+ net.setPreferableTarget(cv::dnn::DNN_TARGET_MYRIAD);
+ net.setInput(cv::Mat::zeros(1, 1, CV_32FC1));
+ try
+ {
+ net.forward();
+ }
+ catch(...)
+ {
+ return false;
+ }
+ return true;
+ }
+
void processNet(std::string weights, std::string proto, std::string halide_scheduler,
const Mat& input, const std::string& outputLayer = "")
{
@@ -41,6 +63,13 @@ public:
throw cvtest::SkipTestException("OpenCL is not available/disabled in OpenCV");
}
}
+ if (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)
+ {
+ if (!checkMyriadTarget())
+ {
+ throw SkipTestException("Myriad is not available/disabled in OpenCV");
+ }
+ }
randu(input, 0.0f, 1.0f);
@@ -87,8 +116,6 @@ public:
PERF_TEST_P_(DNNTestNetwork, AlexNet)
{
- if (backend == DNN_BACKEND_INFERENCE_ENGINE && target != DNN_TARGET_CPU)
- throw SkipTestException("");
processNet("dnn/bvlc_alexnet.caffemodel", "dnn/bvlc_alexnet.prototxt",
"alexnet.yml", Mat(cv::Size(227, 227), CV_32FC3));
}
@@ -130,7 +157,6 @@ PERF_TEST_P_(DNNTestNetwork, ENet)
PERF_TEST_P_(DNNTestNetwork, SSD)
{
- if (backend == DNN_BACKEND_INFERENCE_ENGINE) throw SkipTestException("");
processNet("dnn/VGG_ILSVRC2016_SSD_300x300_iter_440000.caffemodel", "dnn/ssd_vgg16.prototxt", "disabled",
Mat(cv::Size(300, 300), CV_32FC3));
}
@@ -146,18 +172,17 @@ PERF_TEST_P_(DNNTestNetwork, OpenFace)
PERF_TEST_P_(DNNTestNetwork, MobileNet_SSD_Caffe)
{
- if (backend == DNN_BACKEND_HALIDE ||
- backend == DNN_BACKEND_INFERENCE_ENGINE && target != DNN_TARGET_CPU)
+ if (backend == DNN_BACKEND_HALIDE)
throw SkipTestException("");
processNet("dnn/MobileNetSSD_deploy.caffemodel", "dnn/MobileNetSSD_deploy.prototxt", "",
Mat(cv::Size(300, 300), CV_32FC3));
}
+// TODO: update MobileNet model.
PERF_TEST_P_(DNNTestNetwork, MobileNet_SSD_TensorFlow)
{
- if (backend == DNN_BACKEND_DEFAULT && target == DNN_TARGET_OPENCL ||
- backend == DNN_BACKEND_HALIDE ||
- backend == DNN_BACKEND_INFERENCE_ENGINE && target != DNN_TARGET_CPU)
+ if (backend == DNN_BACKEND_HALIDE ||
+ backend == DNN_BACKEND_INFERENCE_ENGINE)
throw SkipTestException("");
processNet("dnn/ssd_mobilenet_v1_coco.pb", "ssd_mobilenet_v1_coco.pbtxt", "",
Mat(cv::Size(300, 300), CV_32FC3));
@@ -166,7 +191,8 @@ PERF_TEST_P_(DNNTestNetwork, MobileNet_SSD_TensorFlow)
PERF_TEST_P_(DNNTestNetwork, DenseNet_121)
{
if (backend == DNN_BACKEND_HALIDE ||
- backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_OPENCL_FP16)
+ backend == DNN_BACKEND_INFERENCE_ENGINE && (target == DNN_TARGET_OPENCL_FP16 ||
+ target == DNN_TARGET_MYRIAD))
throw SkipTestException("");
processNet("dnn/DenseNet_121.caffemodel", "dnn/DenseNet_121.prototxt", "",
Mat(cv::Size(224, 224), CV_32FC3));
@@ -174,21 +200,27 @@ PERF_TEST_P_(DNNTestNetwork, DenseNet_121)
PERF_TEST_P_(DNNTestNetwork, OpenPose_pose_coco)
{
- if (backend == DNN_BACKEND_HALIDE) throw SkipTestException("");
+ if (backend == DNN_BACKEND_HALIDE ||
+ backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)
+ throw SkipTestException("");
processNet("dnn/openpose_pose_coco.caffemodel", "dnn/openpose_pose_coco.prototxt", "",
Mat(cv::Size(368, 368), CV_32FC3));
}
PERF_TEST_P_(DNNTestNetwork, OpenPose_pose_mpi)
{
- if (backend == DNN_BACKEND_HALIDE) throw SkipTestException("");
+ if (backend == DNN_BACKEND_HALIDE ||
+ backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)
+ throw SkipTestException("");
processNet("dnn/openpose_pose_mpi.caffemodel", "dnn/openpose_pose_mpi.prototxt", "",
Mat(cv::Size(368, 368), CV_32FC3));
}
PERF_TEST_P_(DNNTestNetwork, OpenPose_pose_mpi_faster_4_stages)
{
- if (backend == DNN_BACKEND_HALIDE) throw SkipTestException("");
+ if (backend == DNN_BACKEND_HALIDE ||
+ backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)
+ throw SkipTestException("");
// The same .caffemodel but modified .prototxt
// See https://github.com/CMU-Perceptual-Computing-Lab/openpose/blob/master/src/openpose/pose/poseParameters.cpp
processNet("dnn/openpose_pose_mpi.caffemodel", "dnn/openpose_pose_mpi_faster_4_stages.prototxt", "",
@@ -197,8 +229,7 @@ PERF_TEST_P_(DNNTestNetwork, OpenPose_pose_mpi_faster_4_stages)
PERF_TEST_P_(DNNTestNetwork, opencv_face_detector)
{
- if (backend == DNN_BACKEND_HALIDE ||
- backend == DNN_BACKEND_INFERENCE_ENGINE && target != DNN_TARGET_CPU)
+ if (backend == DNN_BACKEND_HALIDE)
throw SkipTestException("");
processNet("dnn/opencv_face_detector.caffemodel", "dnn/opencv_face_detector.prototxt", "",
Mat(cv::Size(300, 300), CV_32FC3));
@@ -207,7 +238,8 @@ PERF_TEST_P_(DNNTestNetwork, opencv_face_detector)
PERF_TEST_P_(DNNTestNetwork, Inception_v2_SSD_TensorFlow)
{
if (backend == DNN_BACKEND_HALIDE ||
- backend == DNN_BACKEND_INFERENCE_ENGINE && target != DNN_TARGET_CPU)
+ (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_OPENCL) ||
+ (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_OPENCL_FP16))
throw SkipTestException("");
processNet("dnn/ssd_inception_v2_coco_2017_11_17.pb", "ssd_inception_v2_coco_2017_11_17.pbtxt", "",
Mat(cv::Size(300, 300), CV_32FC3));
@@ -215,7 +247,8 @@ PERF_TEST_P_(DNNTestNetwork, Inception_v2_SSD_TensorFlow)
PERF_TEST_P_(DNNTestNetwork, YOLOv3)
{
- if (backend != DNN_BACKEND_DEFAULT)
+ if (backend == DNN_BACKEND_HALIDE ||
+ backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)
throw SkipTestException("");
Mat sample = imread(findDataFile("dnn/dog416.png", false));
Mat inp;
@@ -232,6 +265,7 @@ const tuple testCases[] = {
tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_CPU),
tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL),
tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL_FP16),
+ tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_MYRIAD),
#endif
tuple(DNN_BACKEND_DEFAULT, DNN_TARGET_CPU),
tuple(DNN_BACKEND_DEFAULT, DNN_TARGET_OPENCL),
diff --git a/modules/dnn/src/darknet/darknet_io.cpp b/modules/dnn/src/darknet/darknet_io.cpp
index 71f762a09d..707cc29095 100644
--- a/modules/dnn/src/darknet/darknet_io.cpp
+++ b/modules/dnn/src/darknet/darknet_io.cpp
@@ -288,7 +288,7 @@ namespace cv {
permute_params.set("order", paramOrder);
darknet::LayerParameter lp;
- std::string layer_name = cv::format("premute_%d", layer_id);
+ std::string layer_name = cv::format("permute_%d", layer_id);
lp.layer_name = layer_name;
lp.layer_type = permute_params.type;
lp.layerParams = permute_params;
diff --git a/modules/dnn/src/dnn.cpp b/modules/dnn/src/dnn.cpp
index 1a1002c794..6318863b58 100644
--- a/modules/dnn/src/dnn.cpp
+++ b/modules/dnn/src/dnn.cpp
@@ -541,7 +541,7 @@ public:
{
// if dst already has been allocated with total(shape) elements,
- // it won't be recrreated and pointer of dst.data remains the same.
+ // it won't be recreated and pointer of dst.data remains the same.
dst.create(shape, use_half ? CV_16S : CV_32F);
addHost(lp, dst);
}
@@ -1132,7 +1132,7 @@ struct Net::Impl
if (layerNet != ieInpNode->net)
{
// layerNet is empty or nodes are from different graphs.
- ieInpNode->net->addOutput(inpLd.name);
+ ieInpNode->net->addOutput(ieInpNode->layer->name);
}
}
}
@@ -1182,7 +1182,9 @@ struct Net::Impl
for (it = layers.begin(); it != layers.end(); ++it)
{
LayerData &ld = it->second;
- bool fused = ld.skip && ld.id != 0;
+ if (ld.id == 0)
+ continue;
+ bool fused = ld.skip;
Ptr layer = ld.layerInstance;
if (!layer->supportBackend(preferableBackend))
@@ -1259,7 +1261,7 @@ struct Net::Impl
CV_Assert(!ieNode.empty());
ieNode->net = net;
- if (preferableTarget == DNN_TARGET_OPENCL_FP16 && !fused)
+ if ((preferableTarget == DNN_TARGET_OPENCL_FP16 || preferableTarget == DNN_TARGET_MYRIAD) && !fused)
{
ieNode->layer->precision = InferenceEngine::Precision::FP16;
auto weightableLayer = std::dynamic_pointer_cast(ieNode->layer);
@@ -1518,7 +1520,7 @@ struct Net::Impl
}
}
- // fuse convlution layer followed by eltwise + relu
+ // fuse convolution layer followed by eltwise + relu
if ( IS_DNN_OPENCL_TARGET(preferableTarget) )
{
Ptr nextEltwiseLayer;
@@ -1647,7 +1649,7 @@ struct Net::Impl
// the optimization #3. if there is concat layer that concatenates channels
// from the inputs together (i.e. axis == 1) then we make the inputs of
- // the concat layer to write to the concatetion output buffer
+ // the concat layer to write to the concatenation output buffer
// (and so we eliminate the concatenation layer, because the channels
// are concatenated implicitly).
Ptr concatLayer = ld.layerInstance.dynamicCast();
diff --git a/modules/dnn/src/halide_scheduler.cpp b/modules/dnn/src/halide_scheduler.cpp
index a2cb410e7e..78335ddaf9 100644
--- a/modules/dnn/src/halide_scheduler.cpp
+++ b/modules/dnn/src/halide_scheduler.cpp
@@ -242,7 +242,7 @@ bool HalideScheduler::process(Ptr& node)
std::map funcsMap; // Scheduled functions.
// For every function, from top to bottom, we try to find a scheduling node.
// Scheduling is successful (return true) if for the first function (top)
- // node is respresented.
+ // node is represented.
CV_Assert(!node.empty());
std::vector& funcs = node.dynamicCast()->funcs;
for (int i = funcs.size() - 1; i >= 0; --i)
diff --git a/modules/dnn/src/init.cpp b/modules/dnn/src/init.cpp
index 28759daf2f..2bff16c4eb 100644
--- a/modules/dnn/src/init.cpp
+++ b/modules/dnn/src/init.cpp
@@ -84,6 +84,7 @@ void initializeLayerFactory()
CV_DNN_REGISTER_LAYER_CLASS(Reshape, ReshapeLayer);
CV_DNN_REGISTER_LAYER_CLASS(Flatten, FlattenLayer);
CV_DNN_REGISTER_LAYER_CLASS(ResizeNearestNeighbor, ResizeNearestNeighborLayer);
+ CV_DNN_REGISTER_LAYER_CLASS(CropAndResize, CropAndResizeLayer);
CV_DNN_REGISTER_LAYER_CLASS(Convolution, ConvolutionLayer);
CV_DNN_REGISTER_LAYER_CLASS(Deconvolution, DeconvolutionLayer);
diff --git a/modules/dnn/src/layers/convolution_layer.cpp b/modules/dnn/src/layers/convolution_layer.cpp
index 4e38606ca3..2352b35c15 100644
--- a/modules/dnn/src/layers/convolution_layer.cpp
+++ b/modules/dnn/src/layers/convolution_layer.cpp
@@ -676,7 +676,7 @@ public:
int j0 = std::max(0, (-in_j + dilation_w-1)/dilation_w);
int j1 = std::min(kernel_w, (width - in_j + dilation_w-1)/dilation_w);
- // here some non-continous sub-row of the row will not be
+ // here some non-continuous sub-row of the row will not be
// filled from the tensor; we need to make sure that the uncovered
// elements are explicitly set to 0's. the easiest way is to
// set all the elements to 0's before the loop.
@@ -966,8 +966,7 @@ public:
CV_TRACE_FUNCTION();
CV_TRACE_ARG_VALUE(name, "name", name.c_str());
- CV_OCL_RUN(IS_DNN_OPENCL_TARGET(preferableTarget) &&
- OCL_PERFORMANCE_CHECK(ocl::Device::getDefault().isIntel()),
+ CV_OCL_RUN(IS_DNN_OPENCL_TARGET(preferableTarget),
forward_ocl(inputs_arr, outputs_arr, internals_arr))
Layer::forward_fallback(inputs_arr, outputs_arr, internals_arr);
diff --git a/modules/dnn/src/layers/crop_and_resize_layer.cpp b/modules/dnn/src/layers/crop_and_resize_layer.cpp
new file mode 100644
index 0000000000..3f92a8488d
--- /dev/null
+++ b/modules/dnn/src/layers/crop_and_resize_layer.cpp
@@ -0,0 +1,108 @@
+#include "../precomp.hpp"
+#include "layers_common.hpp"
+
+namespace cv { namespace dnn {
+
+class CropAndResizeLayerImpl CV_FINAL : public CropAndResizeLayer
+{
+public:
+ CropAndResizeLayerImpl(const LayerParams& params)
+ {
+ CV_Assert(params.has("width"), params.has("height"));
+ outWidth = params.get("width");
+ outHeight = params.get("height");
+ }
+
+ bool getMemoryShapes(const std::vector &inputs,
+ const int requiredOutputs,
+ std::vector &outputs,
+ std::vector &internals) const CV_OVERRIDE
+ {
+ CV_Assert(inputs.size() == 2, inputs[0].size() == 4);
+ if (inputs[0][0] != 1)
+ CV_Error(Error::StsNotImplemented, "");
+ outputs.resize(1, MatShape(4));
+ outputs[0][0] = inputs[1][2]; // Number of bounding boxes.
+ outputs[0][1] = inputs[0][1]; // Number of channels.
+ outputs[0][2] = outHeight;
+ outputs[0][3] = outWidth;
+ return false;
+ }
+
+ void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE
+ {
+ CV_TRACE_FUNCTION();
+ CV_TRACE_ARG_VALUE(name, "name", name.c_str());
+
+ Layer::forward_fallback(inputs_arr, outputs_arr, internals_arr);
+ }
+
+ void forward(std::vector &inputs, std::vector &outputs, std::vector &internals) CV_OVERRIDE
+ {
+ CV_TRACE_FUNCTION();
+ CV_TRACE_ARG_VALUE(name, "name", name.c_str());
+
+ Mat& inp = *inputs[0];
+ Mat& out = outputs[0];
+ Mat boxes = inputs[1]->reshape(1, inputs[1]->total() / 7);
+ const int numChannels = inp.size[1];
+ const int inpHeight = inp.size[2];
+ const int inpWidth = inp.size[3];
+ const int inpSpatialSize = inpHeight * inpWidth;
+ const int outSpatialSize = outHeight * outWidth;
+ CV_Assert(inp.isContinuous(), out.isContinuous());
+
+ for (int b = 0; b < boxes.rows; ++b)
+ {
+ float* outDataBox = out.ptr(b);
+ float left = boxes.at(b, 3);
+ float top = boxes.at(b, 4);
+ float right = boxes.at(b, 5);
+ float bottom = boxes.at(b, 6);
+ float boxWidth = right - left;
+ float boxHeight = bottom - top;
+
+ float heightScale = boxHeight * static_cast(inpHeight - 1) / (outHeight - 1);
+ float widthScale = boxWidth * static_cast(inpWidth - 1) / (outWidth - 1);
+ for (int y = 0; y < outHeight; ++y)
+ {
+ float input_y = top * (inpHeight - 1) + y * heightScale;
+ int y0 = static_cast(input_y);
+ const float* inpData_row0 = (float*)inp.data + y0 * inpWidth;
+ const float* inpData_row1 = (y0 + 1 < inpHeight) ? (inpData_row0 + inpWidth) : inpData_row0;
+ for (int x = 0; x < outWidth; ++x)
+ {
+ float input_x = left * (inpWidth - 1) + x * widthScale;
+ int x0 = static_cast(input_x);
+ int x1 = std::min(x0 + 1, inpWidth - 1);
+
+ float* outData = outDataBox + y * outWidth + x;
+ const float* inpData_row0_c = inpData_row0;
+ const float* inpData_row1_c = inpData_row1;
+ for (int c = 0; c < numChannels; ++c)
+ {
+ *outData = inpData_row0_c[x0] +
+ (input_y - y0) * (inpData_row1_c[x0] - inpData_row0_c[x0]) +
+ (input_x - x0) * (inpData_row0_c[x1] - inpData_row0_c[x0] +
+ (input_y - y0) * (inpData_row1_c[x1] - inpData_row0_c[x1] - inpData_row1_c[x0] + inpData_row0_c[x0]));
+
+ inpData_row0_c += inpSpatialSize;
+ inpData_row1_c += inpSpatialSize;
+ outData += outSpatialSize;
+ }
+ }
+ }
+ }
+ }
+
+private:
+ int outWidth, outHeight;
+};
+
+Ptr CropAndResizeLayer::create(const LayerParams& params)
+{
+ return Ptr(new CropAndResizeLayerImpl(params));
+}
+
+} // namespace dnn
+} // namespace cv
diff --git a/modules/dnn/src/layers/detection_output_layer.cpp b/modules/dnn/src/layers/detection_output_layer.cpp
index 44f7b32853..e838bcd55f 100644
--- a/modules/dnn/src/layers/detection_output_layer.cpp
+++ b/modules/dnn/src/layers/detection_output_layer.cpp
@@ -110,7 +110,7 @@ public:
float _nmsThreshold;
int _topK;
- // Whenever predicted bounding boxes are respresented in YXHW instead of XYWH layout.
+ // Whenever predicted bounding boxes are represented in YXHW instead of XYWH layout.
bool _locPredTransposed;
// It's true whenever predicted bounding boxes and proposals are normalized to [0, 1].
bool _bboxesNormalized;
@@ -208,8 +208,9 @@ public:
CV_Assert(inputs[0][0] == inputs[1][0]);
int numPriors = inputs[2][2] / 4;
- CV_Assert((numPriors * _numLocClasses * 4) == inputs[0][1]);
- CV_Assert(int(numPriors * _numClasses) == inputs[1][1]);
+ CV_Assert((numPriors * _numLocClasses * 4) == total(inputs[0], 1));
+ CV_Assert(int(numPriors * _numClasses) == total(inputs[1], 1));
+ CV_Assert(inputs[2][1] == 1 + (int)(!_varianceEncodedInTarget));
// num() and channels() are 1.
// Since the number of bboxes to be kept is unknown before nms, we manually
diff --git a/modules/dnn/src/layers/elementwise_layers.cpp b/modules/dnn/src/layers/elementwise_layers.cpp
index a24b913ba4..32d39970ab 100644
--- a/modules/dnn/src/layers/elementwise_layers.cpp
+++ b/modules/dnn/src/layers/elementwise_layers.cpp
@@ -117,7 +117,7 @@ public:
{
return backendId == DNN_BACKEND_DEFAULT ||
backendId == DNN_BACKEND_HALIDE && haveHalide() ||
- backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine() && this->type != "Sigmoid";
+ backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine();
}
virtual Ptr tryAttach(const Ptr& node) CV_OVERRIDE
@@ -176,8 +176,7 @@ public:
{
CV_TRACE_FUNCTION();
- CV_OCL_RUN(IS_DNN_OPENCL_TARGET(this->preferableTarget) &&
- OCL_PERFORMANCE_CHECK(ocl::Device::getDefault().isIntel()),
+ CV_OCL_RUN(IS_DNN_OPENCL_TARGET(this->preferableTarget),
func.applyOCL(inputs_arr, outputs_arr, internals_arr))
Layer::forward_fallback(inputs_arr, outputs_arr, internals_arr);
@@ -335,6 +334,7 @@ struct ReLUFunctor
lp.type = "ReLU";
std::shared_ptr ieLayer(new InferenceEngine::ReLULayer(lp));
ieLayer->negative_slope = slope;
+ ieLayer->params["negative_slope"] = format("%f", slope);
return ieLayer;
}
#endif // HAVE_INF_ENGINE
@@ -432,6 +432,8 @@ struct ReLU6Functor
std::shared_ptr ieLayer(new InferenceEngine::ClampLayer(lp));
ieLayer->min_value = minValue;
ieLayer->max_value = maxValue;
+ ieLayer->params["min"] = format("%f", minValue);
+ ieLayer->params["max"] = format("%f", maxValue);
return ieLayer;
}
#endif // HAVE_INF_ENGINE
@@ -557,8 +559,9 @@ struct SigmoidFunctor
#ifdef HAVE_INF_ENGINE
InferenceEngine::CNNLayerPtr initInfEngine(InferenceEngine::LayerParams& lp)
{
- CV_Error(Error::StsNotImplemented, "Sigmoid");
- return InferenceEngine::CNNLayerPtr();
+ lp.type = "Sigmoid";
+ std::shared_ptr ieLayer(new InferenceEngine::CNNLayer(lp));
+ return ieLayer;
}
#endif // HAVE_INF_ENGINE
diff --git a/modules/dnn/src/layers/eltwise_layer.cpp b/modules/dnn/src/layers/eltwise_layer.cpp
index 39961abb5f..61a7d0950c 100644
--- a/modules/dnn/src/layers/eltwise_layer.cpp
+++ b/modules/dnn/src/layers/eltwise_layer.cpp
@@ -79,7 +79,7 @@ public:
else if (operation == "max")
op = MAX;
else
- CV_Error(cv::Error::StsBadArg, "Unknown operaticon type \"" + operation + "\"");
+ CV_Error(cv::Error::StsBadArg, "Unknown operation type \"" + operation + "\"");
}
if (params.has("coeff"))
diff --git a/modules/dnn/src/layers/mvn_layer.cpp b/modules/dnn/src/layers/mvn_layer.cpp
index 647308ae0a..9e4f0ac39c 100644
--- a/modules/dnn/src/layers/mvn_layer.cpp
+++ b/modules/dnn/src/layers/mvn_layer.cpp
@@ -73,7 +73,7 @@ public:
virtual bool tryFuse(Ptr& top) CV_OVERRIDE
{
- if (preferableTarget == DNN_TARGET_OPENCL && !fuse_batch_norm)
+ if (!fuse_batch_norm)
{
top->getScaleShift(scale, shift);
fuse_batch_norm = !scale.empty() || !shift.empty();
@@ -252,8 +252,7 @@ public:
CV_TRACE_FUNCTION();
CV_TRACE_ARG_VALUE(name, "name", name.c_str());
- CV_OCL_RUN(IS_DNN_OPENCL_TARGET(preferableTarget) &&
- OCL_PERFORMANCE_CHECK(ocl::Device::getDefault().isIntel()),
+ CV_OCL_RUN(IS_DNN_OPENCL_TARGET(preferableTarget),
forward_ocl(inputs_arr, outputs_arr, internals_arr))
Layer::forward_fallback(inputs_arr, outputs_arr, internals_arr);
@@ -274,25 +273,53 @@ public:
for( i = 0; i < splitDim; i++ )
newRows *= inpBlob.size[i];
- if (inpBlob.total() == newRows)
+ Mat inpMat = inpBlob.reshape(1, newRows);
+ Mat outMat = outBlob.reshape(1, newRows);
+
+ if ( inpBlob.total() == newRows )
{
// MVN is applied to single values at an every row.
- outBlob.setTo(0);
+ if (shift.empty())
+ {
+ outBlob.setTo(0);
+ }
+ else
+ {
+ for ( i = 0; i < newRows; i++ )
+ {
+ outMat.row(i).setTo(((float*)shift.data)[i]);
+ }
+ }
return;
}
- Mat inpMat = inpBlob.reshape(1, newRows);
- Mat outMat = outBlob.reshape(1, newRows);
-
Scalar mean, dev;
for ( i = 0; i < newRows; i++)
{
Mat inpRow = inpMat.row(i);
Mat outRow = outMat.row(i);
-
+ float weight = 1.f;
+ float bias = 0.f;
+ if (fuse_batch_norm)
+ {
+ weight = i < scale.cols ? ((float*)scale.data)[i] : weight;
+ bias = i < shift.cols ? ((float*)shift.data)[i] : bias;
+ }
cv::meanStdDev(inpRow, mean, (normVariance) ? dev : noArray());
double alpha = (normVariance) ? 1/(eps + dev[0]) : 1;
- inpRow.convertTo(outRow, outRow.type(), alpha, -mean[0] * alpha);
+ double normalizationScale = 1.0;
+ double normalizationShift = 0.0;
+ if (fuse_batch_norm)
+ {
+ normalizationScale = alpha * weight;
+ normalizationShift = -mean[0] * normalizationScale + bias;
+ }
+ else
+ {
+ normalizationScale = alpha;
+ normalizationShift = -mean[0] * alpha;
+ }
+ inpRow.convertTo(outRow, outRow.type(), normalizationScale, normalizationShift);
}
}
}
diff --git a/modules/dnn/src/layers/pooling_layer.cpp b/modules/dnn/src/layers/pooling_layer.cpp
index 2bcce1d91e..548cb8acdd 100644
--- a/modules/dnn/src/layers/pooling_layer.cpp
+++ b/modules/dnn/src/layers/pooling_layer.cpp
@@ -191,8 +191,7 @@ public:
CV_TRACE_FUNCTION();
CV_TRACE_ARG_VALUE(name, "name", name.c_str());
- CV_OCL_RUN(IS_DNN_OPENCL_TARGET(preferableTarget) &&
- OCL_PERFORMANCE_CHECK(ocl::Device::getDefault().isIntel()),
+ CV_OCL_RUN(IS_DNN_OPENCL_TARGET(preferableTarget),
forward_ocl(inputs_arr, outputs_arr, internals_arr))
Layer::forward_fallback(inputs_arr, outputs_arr, internals_arr);
diff --git a/modules/dnn/src/layers/prior_box_layer.cpp b/modules/dnn/src/layers/prior_box_layer.cpp
index b854c2602a..5e0e338429 100644
--- a/modules/dnn/src/layers/prior_box_layer.cpp
+++ b/modules/dnn/src/layers/prior_box_layer.cpp
@@ -271,7 +271,7 @@ public:
virtual bool supportBackend(int backendId) CV_OVERRIDE
{
return backendId == DNN_BACKEND_DEFAULT ||
- backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine() && !_explicitSizes;
+ backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine();
}
bool getMemoryShapes(const std::vector &inputs,
@@ -366,7 +366,7 @@ public:
kernel.set(13, (int)_imageWidth);
kernel.run(1, &nthreads, NULL, false);
- // clip the prior's coordidate such that it is within [0, 1]
+ // clip the prior's coordinate such that it is within [0, 1]
if (_clip)
{
Mat mat = outputs[0].getMat(ACCESS_READ);
@@ -442,7 +442,7 @@ public:
}
}
}
- // clip the prior's coordidate such that it is within [0, 1]
+ // clip the prior's coordinate such that it is within [0, 1]
if (_clip)
{
int _outChannelSize = _layerHeight * _layerWidth * _numPriors * 4;
@@ -484,18 +484,33 @@ public:
#ifdef HAVE_INF_ENGINE
InferenceEngine::LayerParams lp;
lp.name = name;
- lp.type = "PriorBox";
+ lp.type = _explicitSizes ? "PriorBoxClustered" : "PriorBox";
lp.precision = InferenceEngine::Precision::FP32;
std::shared_ptr ieLayer(new InferenceEngine::CNNLayer(lp));
- ieLayer->params["min_size"] = format("%f", _minSize);
- ieLayer->params["max_size"] = _maxSize > 0 ? format("%f", _maxSize) : "";
-
- if (!_aspectRatios.empty())
+ if (_explicitSizes)
+ {
+ CV_Assert(!_boxWidths.empty(), !_boxHeights.empty(),
+ _boxWidths.size() == _boxHeights.size());
+ ieLayer->params["width"] = format("%f", _boxWidths[0]);
+ ieLayer->params["height"] = format("%f", _boxHeights[0]);
+ for (int i = 1; i < _boxWidths.size(); ++i)
+ {
+ ieLayer->params["width"] += format(",%f", _boxWidths[i]);
+ ieLayer->params["height"] += format(",%f", _boxHeights[i]);
+ }
+ }
+ else
{
- ieLayer->params["aspect_ratio"] = format("%f", _aspectRatios[0]);
- for (int i = 1; i < _aspectRatios.size(); ++i)
- ieLayer->params["aspect_ratio"] += format(",%f", _aspectRatios[i]);
+ ieLayer->params["min_size"] = format("%f", _minSize);
+ ieLayer->params["max_size"] = _maxSize > 0 ? format("%f", _maxSize) : "";
+
+ if (!_aspectRatios.empty())
+ {
+ ieLayer->params["aspect_ratio"] = format("%f", _aspectRatios[0]);
+ for (int i = 1; i < _aspectRatios.size(); ++i)
+ ieLayer->params["aspect_ratio"] += format(",%f", _aspectRatios[i]);
+ }
}
ieLayer->params["flip"] = "0"; // We already flipped aspect ratios.
@@ -550,7 +565,7 @@ private:
std::vector _variance;
std::vector _offsetsX;
std::vector _offsetsY;
- // Precomputed final widhts and heights based on aspect ratios or explicit sizes.
+ // Precomputed final widths and heights based on aspect ratios or explicit sizes.
std::vector _boxWidths;
std::vector _boxHeights;
diff --git a/modules/dnn/src/layers/region_layer.cpp b/modules/dnn/src/layers/region_layer.cpp
index 125fa0d14d..50e68b2fa5 100644
--- a/modules/dnn/src/layers/region_layer.cpp
+++ b/modules/dnn/src/layers/region_layer.cpp
@@ -95,11 +95,6 @@ public:
return false;
}
- virtual bool supportBackend(int backendId) CV_OVERRIDE
- {
- return backendId == DNN_BACKEND_DEFAULT;
- }
-
float logistic_activate(float x) { return 1.F / (1.F + exp(-x)); }
void softmax_activate(const float* input, const int n, const float temp, float* output)
diff --git a/modules/dnn/src/layers/resize_nearest_neighbor_layer.cpp b/modules/dnn/src/layers/resize_nearest_neighbor_layer.cpp
index e9a966296e..448ea25ee4 100644
--- a/modules/dnn/src/layers/resize_nearest_neighbor_layer.cpp
+++ b/modules/dnn/src/layers/resize_nearest_neighbor_layer.cpp
@@ -6,6 +6,7 @@
// Third party copyrights are property of their respective owners.
#include "../precomp.hpp"
#include "layers_common.hpp"
+#include "../op_inf_engine.hpp"
#include
namespace cv { namespace dnn {
@@ -39,6 +40,12 @@ public:
return (outputs[0][2] == inputs[0][2]) && (outputs[0][3] == inputs[0][3]);
}
+ virtual bool supportBackend(int backendId) CV_OVERRIDE
+ {
+ return backendId == DNN_BACKEND_DEFAULT ||
+ backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine();
+ }
+
virtual void finalize(const std::vector& inputs, std::vector &outputs) CV_OVERRIDE
{
if (!outWidth && !outHeight)
@@ -75,6 +82,26 @@ public:
}
}
}
+
+ virtual Ptr initInfEngine(const std::vector >&) CV_OVERRIDE
+ {
+#ifdef HAVE_INF_ENGINE
+ InferenceEngine::LayerParams lp;
+ lp.name = name;
+ lp.type = "Resample";
+ lp.precision = InferenceEngine::Precision::FP32;
+
+ std::shared_ptr ieLayer(new InferenceEngine::CNNLayer(lp));
+ ieLayer->params["type"] = "caffe.ResampleParameter.NEAREST";
+ ieLayer->params["antialias"] = "0";
+ ieLayer->params["width"] = cv::format("%d", outWidth);
+ ieLayer->params["height"] = cv::format("%d", outHeight);
+
+ return Ptr(new InfEngineBackendNode(ieLayer));
+#endif // HAVE_INF_ENGINE
+ return Ptr();
+ }
+
private:
int outWidth, outHeight, zoomFactor;
bool alignCorners;
diff --git a/modules/dnn/src/ocl4dnn/src/ocl4dnn_conv_spatial.cpp b/modules/dnn/src/ocl4dnn/src/ocl4dnn_conv_spatial.cpp
index 44a622f1d4..159319425e 100644
--- a/modules/dnn/src/ocl4dnn/src/ocl4dnn_conv_spatial.cpp
+++ b/modules/dnn/src/ocl4dnn/src/ocl4dnn_conv_spatial.cpp
@@ -709,7 +709,7 @@ bool OCL4DNNConvSpatial::swizzleWeight(const UMat &weight,
return false;
}
} else {
- // assumption: kernel dimesion is 2
+ // assumption: kernel dimension is 2
Mat weightMat = weight.getMat(ACCESS_READ);
Dtype* cpu_weight = (Dtype *)weightMat.ptr();
Mat swizzledWeightMat;
diff --git a/modules/dnn/src/op_inf_engine.cpp b/modules/dnn/src/op_inf_engine.cpp
index c24b137107..b03a67d5f3 100644
--- a/modules/dnn/src/op_inf_engine.cpp
+++ b/modules/dnn/src/op_inf_engine.cpp
@@ -18,11 +18,6 @@ namespace cv { namespace dnn {
#ifdef HAVE_INF_ENGINE
-static int infEngineVersion()
-{
- return std::atoi(InferenceEngine::GetInferenceEngineVersion()->buildNumber);
-}
-
InfEngineBackendNode::InfEngineBackendNode(const InferenceEngine::CNNLayerPtr& _layer)
: BackendNode(DNN_BACKEND_INFERENCE_ENGINE), layer(_layer) {}
@@ -59,27 +54,23 @@ infEngineWrappers(const std::vector >& ptrs)
return wrappers;
}
+static InferenceEngine::Layout estimateLayout(const Mat& m)
+{
+ if (m.dims == 4)
+ return InferenceEngine::Layout::NCHW;
+ else if (m.dims == 2)
+ return InferenceEngine::Layout::NC;
+ else
+ return InferenceEngine::Layout::ANY;
+}
+
static InferenceEngine::DataPtr wrapToInfEngineDataNode(const Mat& m, const std::string& name = "")
{
std::vector reversedShape(&m.size[0], &m.size[0] + m.dims);
std::reverse(reversedShape.begin(), reversedShape.end());
- if (infEngineVersion() > 5855)
- {
- InferenceEngine::Layout l = InferenceEngine::Layout::ANY;
- if (m.dims == 4)
- l = InferenceEngine::Layout::NCHW;
- else if (m.dims == 2)
- l = InferenceEngine::Layout::NC;
- return InferenceEngine::DataPtr(
- new InferenceEngine::Data(name, reversedShape, InferenceEngine::Precision::FP32, l)
- );
- }
- else
- {
- return InferenceEngine::DataPtr(
- new InferenceEngine::Data(name, reversedShape, InferenceEngine::Precision::FP32)
- );
- }
+ return InferenceEngine::DataPtr(
+ new InferenceEngine::Data(name, reversedShape, InferenceEngine::Precision::FP32, estimateLayout(m))
+ );
}
InferenceEngine::TBlob::Ptr wrapToInfEngineBlob(const Mat& m, const std::vector& shape,
@@ -108,7 +99,7 @@ InfEngineBackendWrapper::InfEngineBackendWrapper(int targetId, const cv::Mat& m)
: BackendWrapper(DNN_BACKEND_INFERENCE_ENGINE, targetId)
{
dataPtr = wrapToInfEngineDataNode(m);
- blob = wrapToInfEngineBlob(m);
+ blob = wrapToInfEngineBlob(m, estimateLayout(m));
}
InfEngineBackendWrapper::~InfEngineBackendWrapper()
@@ -252,7 +243,8 @@ InfEngineBackendNet::getLayerByName(const char *layerName, InferenceEngine::CNNL
void InfEngineBackendNet::setTargetDevice(InferenceEngine::TargetDevice device) noexcept
{
if (device != InferenceEngine::TargetDevice::eCPU &&
- device != InferenceEngine::TargetDevice::eGPU)
+ device != InferenceEngine::TargetDevice::eGPU &&
+ device != InferenceEngine::TargetDevice::eMYRIAD)
CV_Error(Error::StsNotImplemented, "");
targetDevice = device;
}
@@ -296,7 +288,7 @@ void InfEngineBackendNet::init(int targetId)
}
for (const InferenceEngine::DataPtr& out : l->outData)
{
- // TODO: Replace to uniquness assertion.
+ // TODO: Replace to uniqueness assertion.
if (internalOutputs.find(out->name) == internalOutputs.end())
internalOutputs[out->name] = out;
}
@@ -313,7 +305,7 @@ void InfEngineBackendNet::init(int targetId)
// Add all outputs.
for (const InferenceEngine::DataPtr& out : l->outData)
{
- // TODO: Replace to uniquness assertion.
+ // TODO: Replace to uniqueness assertion.
if (unconnectedOuts.find(out->name) == unconnectedOuts.end())
unconnectedOuts[out->name] = out;
}
@@ -352,6 +344,11 @@ void InfEngineBackendNet::init(int targetId)
case DNN_TARGET_CPU: setTargetDevice(InferenceEngine::TargetDevice::eCPU); break;
case DNN_TARGET_OPENCL_FP16: setPrecision(InferenceEngine::Precision::FP16); // Fallback to the next.
case DNN_TARGET_OPENCL: setTargetDevice(InferenceEngine::TargetDevice::eGPU); break;
+ case DNN_TARGET_MYRIAD:
+ {
+ setPrecision(InferenceEngine::Precision::FP16);
+ setTargetDevice(InferenceEngine::TargetDevice::eMYRIAD); break;
+ }
default:
CV_Error(Error::StsError, format("Unknown target identifier: %d", targetId));
}
@@ -364,11 +361,21 @@ void InfEngineBackendNet::initPlugin(InferenceEngine::ICNNNetwork& net)
{
CV_Assert(!isInitialized());
- InferenceEngine::StatusCode status;
- InferenceEngine::ResponseDesc resp;
+ static std::map sharedPlugins;
+ std::string deviceName = InferenceEngine::getDeviceName(targetDevice);
+ auto pluginIt = sharedPlugins.find(deviceName);
+ if (pluginIt != sharedPlugins.end())
+ {
+ enginePtr = pluginIt->second;
+ }
+ else
+ {
+ enginePtr = InferenceEngine::PluginDispatcher({""}).getSuitablePlugin(targetDevice);
+ sharedPlugins[deviceName] = enginePtr;
+ }
+ plugin = InferenceEngine::InferencePlugin(enginePtr);
- plugin = InferenceEngine::PluginDispatcher({""}).getSuitablePlugin(targetDevice);
- if (infEngineVersion() > 5855 && targetDevice == InferenceEngine::TargetDevice::eCPU)
+ if (targetDevice == InferenceEngine::TargetDevice::eCPU)
{
#ifdef _WIN32
InferenceEngine::IExtensionPtr extension =
@@ -377,18 +384,17 @@ void InfEngineBackendNet::initPlugin(InferenceEngine::ICNNNetwork& net)
InferenceEngine::IExtensionPtr extension =
InferenceEngine::make_so_pointer("libcpu_extension.so");
#endif // _WIN32
- status = plugin->AddExtension(extension, &resp);
- if (status != InferenceEngine::StatusCode::OK)
- CV_Error(Error::StsAssert, resp.msg);
+ plugin.AddExtension(extension);
}
- status = plugin->LoadNetwork(net, &resp);
- if (status != InferenceEngine::StatusCode::OK)
- CV_Error(Error::StsAssert, resp.msg);
+ netExec = plugin.LoadNetwork(net, {});
+ infRequest = netExec.CreateInferRequest();
+ infRequest.SetInput(inpBlobs);
+ infRequest.SetOutput(outBlobs);
}
bool InfEngineBackendNet::isInitialized()
{
- return (bool)plugin;
+ return (bool)enginePtr;
}
void InfEngineBackendNet::addBlobs(const std::vector >& ptrs)
@@ -402,10 +408,7 @@ void InfEngineBackendNet::addBlobs(const std::vector >& ptrs
void InfEngineBackendNet::forward()
{
- InferenceEngine::ResponseDesc resp;
- InferenceEngine::StatusCode status = plugin->Infer(inpBlobs, outBlobs, &resp);
- if (status != InferenceEngine::StatusCode::OK)
- CV_Error(Error::StsAssert, resp.msg);
+ infRequest.Infer();
}
Mat infEngineBlobToMat(const InferenceEngine::Blob::Ptr& blob)
diff --git a/modules/dnn/src/op_inf_engine.hpp b/modules/dnn/src/op_inf_engine.hpp
index a61678cab2..075c1be849 100644
--- a/modules/dnn/src/op_inf_engine.hpp
+++ b/modules/dnn/src/op_inf_engine.hpp
@@ -89,7 +89,10 @@ private:
InferenceEngine::BlobMap allBlobs;
InferenceEngine::TargetDevice targetDevice;
InferenceEngine::Precision precision;
- InferenceEngine::InferenceEnginePluginPtr plugin;
+ InferenceEngine::InferenceEnginePluginPtr enginePtr;
+ InferenceEngine::InferencePlugin plugin;
+ InferenceEngine::ExecutableNetwork netExec;
+ InferenceEngine::InferRequest infRequest;
void initPlugin(InferenceEngine::ICNNNetwork& net);
};
diff --git a/modules/dnn/src/opencl/mvn.cl b/modules/dnn/src/opencl/mvn.cl
index 49a8ebbe64..ffc81a8704 100644
--- a/modules/dnn/src/opencl/mvn.cl
+++ b/modules/dnn/src/opencl/mvn.cl
@@ -89,7 +89,8 @@ __kernel void CALC_MEAN(__global const Dtype* src,
Dtype mean_val = mean[x];
vec_type src_vec = load(src, index);
- vec_type dst_vec = native_powr(src_vec - (vec_type)mean_val, 2);
+ vec_type dst_vec = src_vec - (vec_type)mean_val;
+ dst_vec = dst_vec * dst_vec;
store(dst_vec, dst, index);
}
@@ -197,10 +198,14 @@ __kernel void MEAN_FUSE(__global const T * A,
const T4 a2 = vload4(i, src0_read + 2 * A_col_size);
const T4 a3 = vload4(i, src0_read + 3 * A_col_size);
- dot0 = native_powr(convert_float4(a0) - (Dtype4)sum.x, 2);
- dot1 = native_powr(convert_float4(a1) - (Dtype4)sum.y, 2);
- dot2 = native_powr(convert_float4(a2) - (Dtype4)sum.z, 2);
- dot3 = native_powr(convert_float4(a3) - (Dtype4)sum.w, 2);
+ dot0 = convert_float4(a0) - (Dtype4)sum.x;
+ dot1 = convert_float4(a1) - (Dtype4)sum.y;
+ dot2 = convert_float4(a2) - (Dtype4)sum.z;
+ dot3 = convert_float4(a3) - (Dtype4)sum.w;
+ dot0 = dot0 * dot0;
+ dot1 = dot1 * dot1;
+ dot2 = dot2 * dot2;
+ dot3 = dot3 * dot3;
vstore4(dot0, i, dst0_read);
vstore4(dot1, i, dst0_read + A_col_size);
diff --git a/modules/dnn/src/tensorflow/graph.proto b/modules/dnn/src/tensorflow/graph.proto
index f945201399..478d35a9fe 100644
--- a/modules/dnn/src/tensorflow/graph.proto
+++ b/modules/dnn/src/tensorflow/graph.proto
@@ -86,7 +86,7 @@ message NodeDef {
// | ( ("gpu" | "cpu") ":" ([1-9][0-9]* | "*") )
//
// Valid values for this string include:
- // * "@other/node" (colocate with "other/node")
+ // * "@other/node" (collocate with "other/node")
// * "/job:worker/replica:0/task:1/gpu:3" (full specification)
// * "/job:worker/gpu:3" (partial specification)
// * "" (no specification)
diff --git a/modules/dnn/src/tensorflow/tf_graph_simplifier.cpp b/modules/dnn/src/tensorflow/tf_graph_simplifier.cpp
index 9208588e65..a537358a1f 100644
--- a/modules/dnn/src/tensorflow/tf_graph_simplifier.cpp
+++ b/modules/dnn/src/tensorflow/tf_graph_simplifier.cpp
@@ -5,6 +5,8 @@
// Copyright (C) 2018, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
+#include "../precomp.hpp"
+
#ifdef HAVE_PROTOBUF
#include "tf_graph_simplifier.hpp"
diff --git a/modules/dnn/src/tensorflow/tf_importer.cpp b/modules/dnn/src/tensorflow/tf_importer.cpp
index 195b516813..f19daf9cc6 100644
--- a/modules/dnn/src/tensorflow/tf_importer.cpp
+++ b/modules/dnn/src/tensorflow/tf_importer.cpp
@@ -644,8 +644,9 @@ void TFImporter::populateNet(Net dstNet)
CV_Assert(layer.input_size() == 3);
DictValue dilation = parseDims(getConstBlob(layer, value_id, 1));
- CV_Assert(dilation.size() == 2 && dilation.get(0) == dilation.get(1));
- layerParams.set("dilation", dilation.get(0));
+ CV_Assert(dilation.size() == 2);
+ layerParams.set("dilation_h", dilation.get(0));
+ layerParams.set("dilation_w", dilation.get(1));
Mat paddings;
parseTensor(getConstBlob(layer, value_id, 2), paddings);
@@ -655,6 +656,10 @@ void TFImporter::populateNet(Net dstNet)
layerParams.set("pad_w", paddings.at(2));
StrIntVector next_layers = getNextLayers(net, name, "Conv2D");
+ if (next_layers.empty())
+ {
+ next_layers = getNextLayers(net, name, "DepthwiseConv2dNative");
+ }
CV_Assert(next_layers.size() == 1);
layer = net.node(next_layers[0].second);
layers_to_ignore.insert(next_layers[0].first);
@@ -1089,9 +1094,9 @@ void TFImporter::populateNet(Net dstNet)
CV_Assert(!begins.empty(), !sizes.empty(), begins.type() == CV_32SC1,
sizes.type() == CV_32SC1);
- if (begins.total() == 4)
+ if (begins.total() == 4 && data_layouts[name] == DATA_LAYOUT_NHWC)
{
- // Perhabs, we have an NHWC order. Swap it to NCHW.
+ // Swap NHWC parameters' order to NCHW.
std::swap(*begins.ptr(0, 2), *begins.ptr(0, 3));
std::swap(*begins.ptr(0, 1), *begins.ptr(0, 2));
std::swap(*sizes.ptr(0, 2), *sizes.ptr(0, 3));
@@ -1171,6 +1176,9 @@ void TFImporter::populateNet(Net dstNet)
layers_to_ignore.insert(next_layers[0].first);
}
+ if (hasLayerAttr(layer, "axis"))
+ layerParams.set("axis", getLayerAttr(layer, "axis").i());
+
id = dstNet.addLayer(name, "Scale", layerParams);
}
layer_id[name] = id;
@@ -1542,6 +1550,10 @@ void TFImporter::populateNet(Net dstNet)
layerParams.set("confidence_threshold", getLayerAttr(layer, "confidence_threshold").f());
if (hasLayerAttr(layer, "loc_pred_transposed"))
layerParams.set("loc_pred_transposed", getLayerAttr(layer, "loc_pred_transposed").b());
+ if (hasLayerAttr(layer, "clip"))
+ layerParams.set("clip", getLayerAttr(layer, "clip").b());
+ if (hasLayerAttr(layer, "variance_encoded_in_target"))
+ layerParams.set("variance_encoded_in_target", getLayerAttr(layer, "variance_encoded_in_target").b());
int id = dstNet.addLayer(name, "DetectionOutput", layerParams);
layer_id[name] = id;
@@ -1558,6 +1570,26 @@ void TFImporter::populateNet(Net dstNet)
layer_id[name] = id;
connectToAllBlobs(layer_id, dstNet, parsePin(layer.input(0)), id, layer.input_size());
}
+ else if (type == "CropAndResize")
+ {
+ // op: "CropAndResize"
+ // input: "input"
+ // input: "boxes"
+ // input: "sizes"
+ CV_Assert(layer.input_size() == 3);
+
+ Mat cropSize = getTensorContent(getConstBlob(layer, value_id, 2));
+ CV_Assert(cropSize.type() == CV_32SC1, cropSize.total() == 2);
+
+ layerParams.set("height", cropSize.at(0));
+ layerParams.set("width", cropSize.at(1));
+
+ int id = dstNet.addLayer(name, "CropAndResize", layerParams);
+ layer_id[name] = id;
+
+ connect(layer_id, dstNet, parsePin(layer.input(0)), id, 0);
+ connect(layer_id, dstNet, parsePin(layer.input(1)), id, 1);
+ }
else if (type == "Mean")
{
Mat indices = getTensorContent(getConstBlob(layer, value_id, 1));
diff --git a/modules/dnn/src/torch/torch_importer.cpp b/modules/dnn/src/torch/torch_importer.cpp
index 813ee085cb..3607e6c08e 100644
--- a/modules/dnn/src/torch/torch_importer.cpp
+++ b/modules/dnn/src/torch/torch_importer.cpp
@@ -311,11 +311,11 @@ struct TorchImporter
int numModules = curModule->modules.size();
readTorchObject(index);
- if (tensors.count(index)) //tensor was readed
+ if (tensors.count(index)) //tensor was read
{
tensorParams.insert(std::make_pair(key, std::make_pair(index, tensors[index])));
}
- else if (storages.count(index)) //storage was readed
+ else if (storages.count(index)) //storage was read
{
Mat &matStorage = storages[index];
Mat matCasted;
@@ -399,7 +399,7 @@ struct TorchImporter
size_t requireElems = (size_t)offset + (size_t)steps[0] * (size_t)sizes[0];
size_t storageElems = storages[indexStorage].total();
if (requireElems > storageElems)
- CV_Error(Error::StsBadSize, "Storage has insufficent number of elemements for requested Tensor");
+ CV_Error(Error::StsBadSize, "Storage has insufficient number of elements for requested Tensor");
//convert sizes
AutoBuffer isizes(ndims);
diff --git a/modules/dnn/test/test_backends.cpp b/modules/dnn/test/test_backends.cpp
index 2bcd357e2e..8dd823e553 100644
--- a/modules/dnn/test/test_backends.cpp
+++ b/modules/dnn/test/test_backends.cpp
@@ -49,7 +49,14 @@ public:
throw SkipTestException("OpenCL is not available/disabled in OpenCV");
}
}
- if (target == DNN_TARGET_OPENCL_FP16)
+ if (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)
+ {
+ if (!checkMyriadTarget())
+ {
+ throw SkipTestException("Myriad is not available/disabled in OpenCV");
+ }
+ }
+ if (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD)
{
l1 = l1 == 0.0 ? 4e-3 : l1;
lInf = lInf == 0.0 ? 2e-2 : lInf;
@@ -80,10 +87,7 @@ public:
}
Mat out = net.forward(outputLayer).clone();
- if (outputLayer == "detection_out")
- normAssertDetections(outDefault, out, "First run", 0.2, l1, lInf);
- else
- normAssert(outDefault, out, "First run", l1, lInf);
+ check(outDefault, out, outputLayer, l1, lInf, "First run");
// Test 2: change input.
float* inpData = (float*)inp.data;
@@ -97,18 +101,33 @@ public:
net.setInput(inp);
outDefault = netDefault.forward(outputLayer).clone();
out = net.forward(outputLayer).clone();
+ check(outDefault, out, outputLayer, l1, lInf, "Second run");
+ }
+ void check(Mat& ref, Mat& out, const std::string& outputLayer, double l1, double lInf, const char* msg)
+ {
if (outputLayer == "detection_out")
- normAssertDetections(outDefault, out, "Second run", 0.2, l1, lInf);
+ {
+ if (backend == DNN_BACKEND_INFERENCE_ENGINE)
+ {
+ // Inference Engine produces detections terminated by a row which starts from -1.
+ out = out.reshape(1, out.total() / 7);
+ int numDetections = 0;
+ while (numDetections < out.rows && out.at(numDetections, 0) != -1)
+ {
+ numDetections += 1;
+ }
+ out = out.rowRange(0, numDetections);
+ }
+ normAssertDetections(ref, out, msg, 0.2, l1, lInf);
+ }
else
- normAssert(outDefault, out, "Second run", l1, lInf);
+ normAssert(ref, out, msg, l1, lInf);
}
};
TEST_P(DNNTestNetwork, AlexNet)
{
- if (backend == DNN_BACKEND_INFERENCE_ENGINE && target != DNN_TARGET_CPU)
- throw SkipTestException("");
processNet("dnn/bvlc_alexnet.caffemodel", "dnn/bvlc_alexnet.prototxt",
Size(227, 227), "prob",
target == DNN_TARGET_OPENCL ? "dnn/halide_scheduler_opencl_alexnet.yml" :
@@ -158,8 +177,7 @@ TEST_P(DNNTestNetwork, ENet)
TEST_P(DNNTestNetwork, MobileNet_SSD_Caffe)
{
- if (backend == DNN_BACKEND_HALIDE ||
- backend == DNN_BACKEND_INFERENCE_ENGINE && target != DNN_TARGET_CPU)
+ if (backend == DNN_BACKEND_HALIDE)
throw SkipTestException("");
Mat sample = imread(findDataFile("dnn/street.png", false));
Mat inp = blobFromImage(sample, 1.0f / 127.5, Size(300, 300), Scalar(127.5, 127.5, 127.5), false);
@@ -170,10 +188,11 @@ TEST_P(DNNTestNetwork, MobileNet_SSD_Caffe)
inp, "detection_out", "", l1, lInf);
}
+// TODO: update MobileNet model.
TEST_P(DNNTestNetwork, MobileNet_SSD_TensorFlow)
{
if (backend == DNN_BACKEND_HALIDE ||
- backend == DNN_BACKEND_INFERENCE_ENGINE && target != DNN_TARGET_CPU)
+ backend == DNN_BACKEND_INFERENCE_ENGINE)
throw SkipTestException("");
Mat sample = imread(findDataFile("dnn/street.png", false));
Mat inp = blobFromImage(sample, 1.0f / 127.5, Size(300, 300), Scalar(127.5, 127.5, 127.5), false);
@@ -185,31 +204,38 @@ TEST_P(DNNTestNetwork, MobileNet_SSD_TensorFlow)
TEST_P(DNNTestNetwork, SSD_VGG16)
{
- if ((backend == DNN_BACKEND_DEFAULT && target == DNN_TARGET_OPENCL_FP16) ||
- (backend == DNN_BACKEND_HALIDE && target == DNN_TARGET_CPU) ||
- (backend == DNN_BACKEND_INFERENCE_ENGINE && target != DNN_TARGET_CPU))
+ if (backend == DNN_BACKEND_HALIDE && target == DNN_TARGET_CPU)
throw SkipTestException("");
+ double scoreThreshold = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.0252 : 0.0;
+ Mat sample = imread(findDataFile("dnn/street.png", false));
+ Mat inp = blobFromImage(sample, 1.0f, Size(300, 300), Scalar(), false);
processNet("dnn/VGG_ILSVRC2016_SSD_300x300_iter_440000.caffemodel",
- "dnn/ssd_vgg16.prototxt", Size(300, 300), "detection_out");
+ "dnn/ssd_vgg16.prototxt", inp, "detection_out", "", scoreThreshold);
}
TEST_P(DNNTestNetwork, OpenPose_pose_coco)
{
- if (backend == DNN_BACKEND_HALIDE) throw SkipTestException("");
+ if (backend == DNN_BACKEND_HALIDE ||
+ backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)
+ throw SkipTestException("");
processNet("dnn/openpose_pose_coco.caffemodel", "dnn/openpose_pose_coco.prototxt",
Size(368, 368));
}
TEST_P(DNNTestNetwork, OpenPose_pose_mpi)
{
- if (backend == DNN_BACKEND_HALIDE) throw SkipTestException("");
+ if (backend == DNN_BACKEND_HALIDE ||
+ backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)
+ throw SkipTestException("");
processNet("dnn/openpose_pose_mpi.caffemodel", "dnn/openpose_pose_mpi.prototxt",
Size(368, 368));
}
TEST_P(DNNTestNetwork, OpenPose_pose_mpi_faster_4_stages)
{
- if (backend == DNN_BACKEND_HALIDE) throw SkipTestException("");
+ if (backend == DNN_BACKEND_HALIDE ||
+ backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)
+ throw SkipTestException("");
// The same .caffemodel but modified .prototxt
// See https://github.com/CMU-Perceptual-Computing-Lab/openpose/blob/master/src/openpose/pose/poseParameters.cpp
processNet("dnn/openpose_pose_mpi.caffemodel", "dnn/openpose_pose_mpi_faster_4_stages.prototxt",
@@ -226,11 +252,13 @@ TEST_P(DNNTestNetwork, OpenFace)
TEST_P(DNNTestNetwork, opencv_face_detector)
{
- if (backend == DNN_BACKEND_HALIDE ||
- backend == DNN_BACKEND_INFERENCE_ENGINE && target != DNN_TARGET_CPU)
+ if (backend == DNN_BACKEND_HALIDE)
throw SkipTestException("");
+ Size inpSize;
+ if (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)
+ inpSize = Size(300, 300);
Mat img = imread(findDataFile("gpu/lbpcascade/er.png", false));
- Mat inp = blobFromImage(img, 1.0, Size(), Scalar(104.0, 177.0, 123.0), false, false);
+ Mat inp = blobFromImage(img, 1.0, inpSize, Scalar(104.0, 177.0, 123.0), false, false);
processNet("dnn/opencv_face_detector.caffemodel", "dnn/opencv_face_detector.prototxt",
inp, "detection_out");
}
@@ -238,12 +266,13 @@ TEST_P(DNNTestNetwork, opencv_face_detector)
TEST_P(DNNTestNetwork, Inception_v2_SSD_TensorFlow)
{
if (backend == DNN_BACKEND_HALIDE ||
- backend == DNN_BACKEND_INFERENCE_ENGINE && target != DNN_TARGET_CPU)
+ (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_OPENCL) ||
+ (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_OPENCL_FP16))
throw SkipTestException("");
Mat sample = imread(findDataFile("dnn/street.png", false));
Mat inp = blobFromImage(sample, 1.0f / 127.5, Size(300, 300), Scalar(127.5, 127.5, 127.5), false);
- float l1 = (backend == DNN_BACKEND_DEFAULT && target == DNN_TARGET_OPENCL_FP16) ? 0.008 : 0.0;
- float lInf = (backend == DNN_BACKEND_DEFAULT && target == DNN_TARGET_OPENCL_FP16) ? 0.07 : 0.0;
+ float l1 = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.008 : 0.0;
+ float lInf = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.07 : 0.0;
processNet("dnn/ssd_inception_v2_coco_2017_11_17.pb", "dnn/ssd_inception_v2_coco_2017_11_17.pbtxt",
inp, "detection_out", "", l1, lInf);
}
@@ -252,7 +281,8 @@ TEST_P(DNNTestNetwork, DenseNet_121)
{
if ((backend == DNN_BACKEND_HALIDE) ||
(backend == DNN_BACKEND_DEFAULT && target == DNN_TARGET_OPENCL_FP16) ||
- (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_OPENCL_FP16))
+ (backend == DNN_BACKEND_INFERENCE_ENGINE && (target == DNN_TARGET_OPENCL_FP16 ||
+ target == DNN_TARGET_MYRIAD)))
throw SkipTestException("");
processNet("dnn/DenseNet_121.caffemodel", "dnn/DenseNet_121.prototxt", Size(224, 224), "", "caffe");
}
@@ -266,6 +296,7 @@ const tuple testCases[] = {
tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_CPU),
tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL),
tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL_FP16),
+ tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_MYRIAD),
#endif
tuple(DNN_BACKEND_DEFAULT, DNN_TARGET_OPENCL),
tuple(DNN_BACKEND_DEFAULT, DNN_TARGET_OPENCL_FP16)
diff --git a/modules/dnn/test/test_common.hpp b/modules/dnn/test/test_common.hpp
index 872d19dce4..8e8ea74d83 100644
--- a/modules/dnn/test/test_common.hpp
+++ b/modules/dnn/test/test_common.hpp
@@ -147,6 +147,28 @@ inline void normAssertDetections(cv::Mat ref, cv::Mat out, const char *comment =
testBoxes, comment, confThreshold, scores_diff, boxes_iou_diff);
}
+inline bool checkMyriadTarget()
+{
+#ifndef HAVE_INF_ENGINE
+ return false;
+#endif
+ cv::dnn::Net net;
+ cv::dnn::LayerParams lp;
+ net.addLayerToPrev("testLayer", "Identity", lp);
+ net.setPreferableBackend(cv::dnn::DNN_BACKEND_INFERENCE_ENGINE);
+ net.setPreferableTarget(cv::dnn::DNN_TARGET_MYRIAD);
+ net.setInput(cv::Mat::zeros(1, 1, CV_32FC1));
+ try
+ {
+ net.forward();
+ }
+ catch(...)
+ {
+ return false;
+ }
+ return true;
+}
+
inline bool readFileInMemory(const std::string& filename, std::string& content)
{
std::ios::openmode mode = std::ios::in | std::ios::binary;
diff --git a/modules/dnn/test/test_darknet_importer.cpp b/modules/dnn/test/test_darknet_importer.cpp
index a7679daf6f..17d33d7662 100644
--- a/modules/dnn/test/test_darknet_importer.cpp
+++ b/modules/dnn/test/test_darknet_importer.cpp
@@ -71,13 +71,31 @@ static void testDarknetModel(const std::string& cfg, const std::string& weights,
const std::vector& refClassIds,
const std::vector& refConfidences,
const std::vector& refBoxes,
- int targetId, float confThreshold = 0.24)
+ int backendId, int targetId, float scoreDiff = 0.0,
+ float iouDiff = 0.0, float confThreshold = 0.24)
{
+ if (backendId == DNN_BACKEND_DEFAULT && targetId == DNN_TARGET_OPENCL)
+ {
+ #ifdef HAVE_OPENCL
+ if (!cv::ocl::useOpenCL())
+ #endif
+ {
+ throw SkipTestException("OpenCL is not available/disabled in OpenCV");
+ }
+ }
+ if (backendId == DNN_BACKEND_INFERENCE_ENGINE && targetId == DNN_TARGET_MYRIAD)
+ {
+ if (!checkMyriadTarget())
+ {
+ throw SkipTestException("Myriad is not available/disabled in OpenCV");
+ }
+ }
Mat sample = imread(_tf("dog416.png"));
Mat inp = blobFromImage(sample, 1.0/255, Size(416, 416), Scalar(), true, false);
Net net = readNet(findDataFile("dnn/" + cfg, false),
findDataFile("dnn/" + weights, false));
+ net.setPreferableBackend(backendId);
net.setPreferableTarget(targetId);
net.setInput(inp);
std::vector outs;
@@ -108,42 +126,53 @@ static void testDarknetModel(const std::string& cfg, const std::string& weights,
}
}
normAssertDetections(refClassIds, refConfidences, refBoxes, classIds,
- confidences, boxes, "", confThreshold, 8e-5, 3e-5);
+ confidences, boxes, "", confThreshold, scoreDiff, iouDiff);
}
-typedef testing::TestWithParam Test_Darknet_nets;
+typedef testing::TestWithParam > Test_Darknet_nets;
TEST_P(Test_Darknet_nets, YoloVoc)
{
- int targetId = GetParam();
+ int backendId = get<0>(GetParam());
+ int targetId = get<1>(GetParam());
+ if (backendId == DNN_BACKEND_INFERENCE_ENGINE && targetId == DNN_TARGET_MYRIAD)
+ throw SkipTestException("");
std::vector outNames(1, "detection_out");
std::vector classIds(3);
std::vector confidences(3);
std::vector boxes(3);
classIds[0] = 6; confidences[0] = 0.750469f; boxes[0] = Rect2d(0.577374, 0.127391, 0.325575, 0.173418); // a car
- classIds[1] = 1; confidences[1] = 0.780879f; boxes[1] = Rect2d(0.270762, 0.264102, 0.461713, 0.48131); // a bycicle
+ classIds[1] = 1; confidences[1] = 0.780879f; boxes[1] = Rect2d(0.270762, 0.264102, 0.461713, 0.48131); // a bicycle
classIds[2] = 11; confidences[2] = 0.901615f; boxes[2] = Rect2d(0.1386, 0.338509, 0.282737, 0.60028); // a dog
+ double scoreDiff = (targetId == DNN_TARGET_OPENCL_FP16 || targetId == DNN_TARGET_MYRIAD) ? 7e-3 : 8e-5;
+ double iouDiff = (targetId == DNN_TARGET_OPENCL_FP16 || targetId == DNN_TARGET_MYRIAD) ? 0.013 : 3e-5;
testDarknetModel("yolo-voc.cfg", "yolo-voc.weights", outNames,
- classIds, confidences, boxes, targetId);
+ classIds, confidences, boxes, backendId, targetId, scoreDiff, iouDiff);
}
TEST_P(Test_Darknet_nets, TinyYoloVoc)
{
- int targetId = GetParam();
+ int backendId = get<0>(GetParam());
+ int targetId = get<1>(GetParam());
std::vector outNames(1, "detection_out");
std::vector classIds(2);
std::vector confidences(2);
std::vector boxes(2);
classIds[0] = 6; confidences[0] = 0.761967f; boxes[0] = Rect2d(0.579042, 0.159161, 0.31544, 0.160779); // a car
classIds[1] = 11; confidences[1] = 0.780595f; boxes[1] = Rect2d(0.129696, 0.386467, 0.315579, 0.534527); // a dog
+ double scoreDiff = (targetId == DNN_TARGET_OPENCL_FP16 || targetId == DNN_TARGET_MYRIAD) ? 8e-3 : 8e-5;
+ double iouDiff = (targetId == DNN_TARGET_OPENCL_FP16 || targetId == DNN_TARGET_MYRIAD) ? 8e-3 : 3e-5;
testDarknetModel("tiny-yolo-voc.cfg", "tiny-yolo-voc.weights", outNames,
- classIds, confidences, boxes, targetId);
+ classIds, confidences, boxes, backendId, targetId, scoreDiff, iouDiff);
}
TEST_P(Test_Darknet_nets, YOLOv3)
{
- int targetId = GetParam();
+ int backendId = get<0>(GetParam());
+ int targetId = get<1>(GetParam());
+ if (backendId == DNN_BACKEND_INFERENCE_ENGINE && targetId == DNN_TARGET_MYRIAD)
+ throw SkipTestException("");
std::vector outNames(3);
outNames[0] = "yolo_82";
outNames[1] = "yolo_94";
@@ -153,13 +182,27 @@ TEST_P(Test_Darknet_nets, YOLOv3)
std::vector confidences(3);
std::vector boxes(3);
classIds[0] = 7; confidences[0] = 0.952983f; boxes[0] = Rect2d(0.614622, 0.150257, 0.286747, 0.138994); // a truck
- classIds[1] = 1; confidences[1] = 0.987908f; boxes[1] = Rect2d(0.150913, 0.221933, 0.591342, 0.524327); // a bycicle
+ classIds[1] = 1; confidences[1] = 0.987908f; boxes[1] = Rect2d(0.150913, 0.221933, 0.591342, 0.524327); // a bicycle
classIds[2] = 16; confidences[2] = 0.998836f; boxes[2] = Rect2d(0.160024, 0.389964, 0.257861, 0.553752); // a dog (COCO)
+ double scoreDiff = (targetId == DNN_TARGET_OPENCL_FP16 || targetId == DNN_TARGET_MYRIAD) ? 4e-3 : 8e-5;
+ double iouDiff = (targetId == DNN_TARGET_OPENCL_FP16 || targetId == DNN_TARGET_MYRIAD) ? 0.011 : 3e-5;
testDarknetModel("yolov3.cfg", "yolov3.weights", outNames,
- classIds, confidences, boxes, targetId);
+ classIds, confidences, boxes, backendId, targetId, scoreDiff, iouDiff);
}
-INSTANTIATE_TEST_CASE_P(/**/, Test_Darknet_nets, availableDnnTargets());
+const tuple testCases[] = {
+#ifdef HAVE_INF_ENGINE
+ tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_CPU),
+ tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL),
+ tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL_FP16),
+ tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_MYRIAD),
+#endif
+ tuple(DNN_BACKEND_DEFAULT, DNN_TARGET_CPU),
+ tuple(DNN_BACKEND_DEFAULT, DNN_TARGET_OPENCL),
+ tuple(DNN_BACKEND_DEFAULT, DNN_TARGET_OPENCL_FP16)
+};
+
+INSTANTIATE_TEST_CASE_P(/**/, Test_Darknet_nets, testing::ValuesIn(testCases));
static void testDarknetLayer(const std::string& name, bool hasWeights = false)
{
diff --git a/modules/dnn/test/test_layers.cpp b/modules/dnn/test/test_layers.cpp
index 89c6ed8915..593864822c 100644
--- a/modules/dnn/test/test_layers.cpp
+++ b/modules/dnn/test/test_layers.cpp
@@ -834,6 +834,84 @@ TEST(Test_DLDT, two_inputs)
normAssert(out, firstInp + secondInp);
}
+
+class UnsupportedLayer : public Layer
+{
+public:
+ UnsupportedLayer(const LayerParams ¶ms) {}
+
+ static Ptr create(const LayerParams& params)
+ {
+ return Ptr(new UnsupportedLayer(params));
+ }
+
+ virtual bool supportBackend(int backendId) CV_OVERRIDE
+ {
+ return backendId == DNN_BACKEND_DEFAULT;
+ }
+
+ virtual void forward(std::vector &inputs, std::vector &outputs, std::vector &internals) CV_OVERRIDE {}
+
+ virtual void forward(cv::InputArrayOfArrays inputs, cv::OutputArrayOfArrays outputs, cv::OutputArrayOfArrays internals) CV_OVERRIDE {}
+};
+
+TEST(Test_DLDT, fused_output)
+{
+ static const int kNumChannels = 3;
+ CV_DNN_REGISTER_LAYER_CLASS(Unsupported, UnsupportedLayer);
+ Net net;
+ {
+ LayerParams lp;
+ lp.set("kernel_size", 1);
+ lp.set("num_output", 3);
+ lp.set("bias_term", false);
+ lp.type = "Convolution";
+ lp.name = "testConv";
+ lp.blobs.push_back(Mat({kNumChannels, 1, 1, 1}, CV_32F, Scalar(1)));
+ net.addLayerToPrev(lp.name, lp.type, lp);
+ }
+ {
+ LayerParams lp;
+ lp.set("bias_term", false);
+ lp.type = "Scale";
+ lp.name = "testScale";
+ lp.blobs.push_back(Mat({kNumChannels}, CV_32F, Scalar(1)));
+ net.addLayerToPrev(lp.name, lp.type, lp);
+ }
+ {
+ LayerParams lp;
+ net.addLayerToPrev("unsupported_layer", "Unsupported", lp);
+ }
+ net.setPreferableBackend(DNN_BACKEND_INFERENCE_ENGINE);
+ net.setInput(Mat({1, 1, 1, 1}, CV_32FC1, Scalar(1)));
+ ASSERT_NO_THROW(net.forward());
+ LayerFactory::unregisterLayer("Unsupported");
+}
+
+TEST(Test_DLDT, multiple_networks)
+{
+ Net nets[2];
+ for (int i = 0; i < 2; ++i)
+ {
+ nets[i].setInputsNames(std::vector(1, format("input_%d", i)));
+
+ LayerParams lp;
+ lp.set("kernel_size", 1);
+ lp.set("num_output", 1);
+ lp.set("bias_term", false);
+ lp.type = "Convolution";
+ lp.name = format("testConv_%d", i);
+ lp.blobs.push_back(Mat({1, 1, 1, 1}, CV_32F, Scalar(1 + i)));
+ nets[i].addLayerToPrev(lp.name, lp.type, lp);
+ nets[i].setPreferableBackend(DNN_BACKEND_INFERENCE_ENGINE);
+ nets[i].setInput(Mat({1, 1, 1, 1}, CV_32FC1, Scalar(1)));
+ }
+ Mat out_1 = nets[0].forward();
+ Mat out_2 = nets[1].forward();
+ // After the second model is initialized we try to receive an output from the first network again.
+ out_1 = nets[0].forward();
+ normAssert(2 * out_1, out_2);
+}
#endif // HAVE_INF_ENGINE
// Test a custom layer.
diff --git a/modules/dnn/test/test_precomp.hpp b/modules/dnn/test/test_precomp.hpp
index 54c9ce6c79..70b7b3d25e 100644
--- a/modules/dnn/test/test_precomp.hpp
+++ b/modules/dnn/test/test_precomp.hpp
@@ -49,11 +49,11 @@
#include "opencv2/dnn.hpp"
#include "test_common.hpp"
-namespace opencv_test {
+namespace opencv_test { namespace {
using namespace cv::dnn;
CV_ENUM(DNNBackend, DNN_BACKEND_DEFAULT, DNN_BACKEND_HALIDE, DNN_BACKEND_INFERENCE_ENGINE)
-CV_ENUM(DNNTarget, DNN_TARGET_CPU, DNN_TARGET_OPENCL, DNN_TARGET_OPENCL_FP16)
+CV_ENUM(DNNTarget, DNN_TARGET_CPU, DNN_TARGET_OPENCL, DNN_TARGET_OPENCL_FP16, DNN_TARGET_MYRIAD)
static testing::internal::ParamGenerator availableDnnTargets()
{
@@ -69,6 +69,6 @@ static testing::internal::ParamGenerator availableDnnTargets()
return testing::ValuesIn(targets);
}
-}
+}}
#endif
diff --git a/modules/dnn/test/test_tf_importer.cpp b/modules/dnn/test/test_tf_importer.cpp
index 3f02fb2220..84205f72fb 100644
--- a/modules/dnn/test/test_tf_importer.cpp
+++ b/modules/dnn/test/test_tf_importer.cpp
@@ -124,6 +124,7 @@ TEST_P(Test_TensorFlow_layers, conv)
runTensorFlowNet("atrous_conv2d_valid", targetId);
runTensorFlowNet("atrous_conv2d_same", targetId);
runTensorFlowNet("depthwise_conv2d", targetId);
+ runTensorFlowNet("keras_atrous_conv2d_same", targetId);
}
TEST_P(Test_TensorFlow_layers, padding)
@@ -160,10 +161,12 @@ TEST_P(Test_TensorFlow_layers, batch_norm)
TEST_P(Test_TensorFlow_layers, pooling)
{
int targetId = GetParam();
+ cv::ocl::Device d = cv::ocl::Device::getDefault();
+ bool loosenFlag = targetId == DNN_TARGET_OPENCL && d.isIntel() && d.type() == cv::ocl::Device::TYPE_CPU;
runTensorFlowNet("max_pool_even", targetId);
runTensorFlowNet("max_pool_odd_valid", targetId);
runTensorFlowNet("ave_pool_same", targetId);
- runTensorFlowNet("max_pool_odd_same", targetId);
+ runTensorFlowNet("max_pool_odd_same", targetId, false, loosenFlag ? 3e-5 : 1e-5, loosenFlag ? 3e-4 : 1e-4);
runTensorFlowNet("reduce_mean", targetId); // an average pooling over all spatial dimensions.
}
@@ -267,6 +270,22 @@ TEST_P(Test_TensorFlow_nets, Inception_v2_SSD)
normAssertDetections(ref, out, "", 0.5);
}
+TEST_P(Test_TensorFlow_nets, Inception_v2_Faster_RCNN)
+{
+ std::string proto = findDataFile("dnn/faster_rcnn_inception_v2_coco_2018_01_28.pbtxt", false);
+ std::string model = findDataFile("dnn/faster_rcnn_inception_v2_coco_2018_01_28.pb", false);
+
+ Net net = readNetFromTensorflow(model, proto);
+ Mat img = imread(findDataFile("dnn/dog416.png", false));
+ Mat blob = blobFromImage(img, 1.0f / 127.5, Size(800, 600), Scalar(127.5, 127.5, 127.5), true, false);
+
+ net.setInput(blob);
+ Mat out = net.forward();
+
+ Mat ref = blobFromNPY(findDataFile("dnn/tensorflow/faster_rcnn_inception_v2_coco_2018_01_28.detection_out.npy"));
+ normAssertDetections(ref, out, "", 0.3);
+}
+
TEST_P(Test_TensorFlow_nets, opencv_face_detector_uint8)
{
std::string proto = findDataFile("dnn/opencv_face_detector.pbtxt", false);
diff --git a/modules/dnn/test/test_torch_importer.cpp b/modules/dnn/test/test_torch_importer.cpp
index 33e0e94801..ab74b190af 100644
--- a/modules/dnn/test/test_torch_importer.cpp
+++ b/modules/dnn/test/test_torch_importer.cpp
@@ -250,7 +250,7 @@ TEST_P(Test_Torch_nets, ENet_accuracy)
Mat out = net.forward();
Mat ref = blobFromNPY(_tf("torch_enet_prob.npy", false));
// Due to numerical instability in Pooling-Unpooling layers (indexes jittering)
- // thresholds for ENet must be changed. Accuracy of resuults was checked on
+ // thresholds for ENet must be changed. Accuracy of results was checked on
// Cityscapes dataset and difference in mIOU with Torch is 10E-4%
normAssert(ref, out, "", 0.00044, 0.44);
diff --git a/modules/features2d/src/agast.cpp b/modules/features2d/src/agast.cpp
index ab01b67805..8b63234b29 100644
--- a/modules/features2d/src/agast.cpp
+++ b/modules/features2d/src/agast.cpp
@@ -7952,6 +7952,12 @@ public:
{
CV_INSTRUMENT_REGION()
+ if(_image.empty())
+ {
+ keypoints.clear();
+ return;
+ }
+
Mat mask = _mask.getMat(), grayImage;
UMat ugrayImage;
_InputArray gray = _image;
diff --git a/modules/features2d/src/fast.cpp b/modules/features2d/src/fast.cpp
index 5299e14ae5..b586d30a22 100644
--- a/modules/features2d/src/fast.cpp
+++ b/modules/features2d/src/fast.cpp
@@ -522,6 +522,12 @@ public:
{
CV_INSTRUMENT_REGION()
+ if(_image.empty())
+ {
+ keypoints.clear();
+ return;
+ }
+
Mat mask = _mask.getMat(), grayImage;
UMat ugrayImage;
_InputArray gray = _image;
diff --git a/modules/features2d/src/gftt.cpp b/modules/features2d/src/gftt.cpp
index 1b8010625b..e4a594a5c6 100644
--- a/modules/features2d/src/gftt.cpp
+++ b/modules/features2d/src/gftt.cpp
@@ -80,6 +80,12 @@ public:
{
CV_INSTRUMENT_REGION()
+ if(_image.empty())
+ {
+ keypoints.clear();
+ return;
+ }
+
std::vector corners;
if (_image.isUMat())
diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp
index f4cf3711d7..b03deba66b 100644
--- a/modules/imgproc/include/opencv2/imgproc.hpp
+++ b/modules/imgproc/include/opencv2/imgproc.hpp
@@ -159,40 +159,7 @@ In OpenCV you only need applyColorMap to apply a colormap on a given image. The
code reads the path to an image from command line, applies a Jet colormap on it and shows the
result:
-@code
-#include
-#include
-#include
-#include
-using namespace cv;
-
-#include
-using namespace std;
-
-int main(int argc, const char *argv[])
-{
- // We need an input image. (can be grayscale or color)
- if (argc < 2)
- {
- cerr << "We need an image to process here. Please run: colorMap [path_to_image]" << endl;
- return -1;
- }
- Mat img_in = imread(argv[1]);
- if(img_in.empty())
- {
- cerr << "Sample image (" << argv[1] << ") is empty. Please adjust your path, so it points to a valid input image!" << endl;
- return -1;
- }
- // Holds the colormap version of the image:
- Mat img_color;
- // Apply the colormap:
- applyColorMap(img_in, img_color, COLORMAP_JET);
- // Show the result:
- imshow("colorMap", img_color);
- waitKey(0);
- return 0;
-}
-@endcode
+@include snippets/imgproc_applyColorMap.cpp
@see #ColormapTypes
@@ -2007,58 +1974,7 @@ The function implements the probabilistic Hough transform algorithm for line det
in @cite Matas00
See the line detection example below:
-
-@code
- #include
- #include
-
- using namespace cv;
- using namespace std;
-
- int main(int argc, char** argv)
- {
- Mat src, dst, color_dst;
- if( argc != 2 || !(src=imread(argv[1], 0)).data)
- return -1;
-
- Canny( src, dst, 50, 200, 3 );
- cvtColor( dst, color_dst, COLOR_GRAY2BGR );
-
- #if 0
- vector lines;
- HoughLines( dst, lines, 1, CV_PI/180, 100 );
-
- for( size_t i = 0; i < lines.size(); i++ )
- {
- float rho = lines[i][0];
- float theta = lines[i][1];
- double a = cos(theta), b = sin(theta);
- double x0 = a*rho, y0 = b*rho;
- Point pt1(cvRound(x0 + 1000*(-b)),
- cvRound(y0 + 1000*(a)));
- Point pt2(cvRound(x0 - 1000*(-b)),
- cvRound(y0 - 1000*(a)));
- line( color_dst, pt1, pt2, Scalar(0,0,255), 3, 8 );
- }
- #else
- vector lines;
- HoughLinesP( dst, lines, 1, CV_PI/180, 80, 30, 10 );
- for( size_t i = 0; i < lines.size(); i++ )
- {
- line( color_dst, Point(lines[i][0], lines[i][1]),
- Point(lines[i][2], lines[i][3]), Scalar(0,0,255), 3, 8 );
- }
- #endif
- namedWindow( "Source", 1 );
- imshow( "Source", src );
-
- namedWindow( "Detected Lines", 1 );
- imshow( "Detected Lines", color_dst );
-
- waitKey(0);
- return 0;
- }
-@endcode
+@include snippets/imgproc_HoughLinesP.cpp
This is a sample picture the function parameters have been tuned for:

@@ -2114,41 +2030,7 @@ An example using the Hough circle detector
The function finds circles in a grayscale image using a modification of the Hough transform.
Example: :
-@code
- #include
- #include
- #include
-
- using namespace cv;
- using namespace std;
-
- int main(int argc, char** argv)
- {
- Mat img, gray;
- if( argc != 2 || !(img=imread(argv[1], 1)).data)
- return -1;
- cvtColor(img, gray, COLOR_BGR2GRAY);
- // smooth it, otherwise a lot of false circles may be detected
- GaussianBlur( gray, gray, Size(9, 9), 2, 2 );
- vector circles;
- HoughCircles(gray, circles, HOUGH_GRADIENT,
- 2, gray.rows/4, 200, 100 );
- for( size_t i = 0; i < circles.size(); i++ )
- {
- Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
- int radius = cvRound(circles[i][2]);
- // draw the circle center
- circle( img, center, 3, Scalar(0,255,0), -1, 8, 0 );
- // draw the circle outline
- circle( img, center, radius, Scalar(0,0,255), 3, 8, 0 );
- }
- namedWindow( "circles", 1 );
- imshow( "circles", img );
-
- waitKey(0);
- return 0;
- }
-@endcode
+@include snippets/imgproc_HoughLinesCircles.cpp
@note Usually the function detects the centers of circles well. However, it may fail to find correct
radii. You can assist to the function by specifying the radius range ( minRadius and maxRadius ) if
@@ -3247,63 +3129,7 @@ An example for creating histograms of an image
The function cv::calcHist calculates the histogram of one or more arrays. The elements of a tuple used
to increment a histogram bin are taken from the corresponding input arrays at the same location. The
sample below shows how to compute a 2D Hue-Saturation histogram for a color image. :
-@code
- #include
- #include
-
- using namespace cv;
-
- int main( int argc, char** argv )
- {
- Mat src, hsv;
- if( argc != 2 || !(src=imread(argv[1], 1)).data )
- return -1;
-
- cvtColor(src, hsv, COLOR_BGR2HSV);
-
- // Quantize the hue to 30 levels
- // and the saturation to 32 levels
- int hbins = 30, sbins = 32;
- int histSize[] = {hbins, sbins};
- // hue varies from 0 to 179, see cvtColor
- float hranges[] = { 0, 180 };
- // saturation varies from 0 (black-gray-white) to
- // 255 (pure spectrum color)
- float sranges[] = { 0, 256 };
- const float* ranges[] = { hranges, sranges };
- MatND hist;
- // we compute the histogram from the 0-th and 1-st channels
- int channels[] = {0, 1};
-
- calcHist( &hsv, 1, channels, Mat(), // do not use mask
- hist, 2, histSize, ranges,
- true, // the histogram is uniform
- false );
- double maxVal=0;
- minMaxLoc(hist, 0, &maxVal, 0, 0);
-
- int scale = 10;
- Mat histImg = Mat::zeros(sbins*scale, hbins*10, CV_8UC3);
-
- for( int h = 0; h < hbins; h++ )
- for( int s = 0; s < sbins; s++ )
- {
- float binVal = hist.at(h, s);
- int intensity = cvRound(binVal*255/maxVal);
- rectangle( histImg, Point(h*scale, s*scale),
- Point( (h+1)*scale - 1, (s+1)*scale - 1),
- Scalar::all(intensity),
- CV_FILLED );
- }
-
- namedWindow( "Source", 1 );
- imshow( "Source", src );
-
- namedWindow( "H-S Histogram", 1 );
- imshow( "H-S Histogram", histImg );
- waitKey();
- }
-@endcode
+@include snippets/imgproc_calcHist.cpp
@param images Source arrays. They all should have the same depth, CV_8U, CV_16U or CV_32F , and the same
size. Each of them can have an arbitrary number of channels.
@@ -4698,47 +4524,7 @@ An example using drawContours to clean up a background segmentation result
The function draws contour outlines in the image if \f$\texttt{thickness} \ge 0\f$ or fills the area
bounded by the contours if \f$\texttt{thickness}<0\f$ . The example below shows how to retrieve
connected components from the binary image and label them: :
-@code
- #include "opencv2/imgproc.hpp"
- #include "opencv2/highgui.hpp"
-
- using namespace cv;
- using namespace std;
-
- int main( int argc, char** argv )
- {
- Mat src;
- // the first command-line parameter must be a filename of the binary
- // (black-n-white) image
- if( argc != 2 || !(src=imread(argv[1], 0)).data)
- return -1;
-
- Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC3);
-
- src = src > 1;
- namedWindow( "Source", 1 );
- imshow( "Source", src );
-
- vector > contours;
- vector hierarchy;
-
- findContours( src, contours, hierarchy,
- RETR_CCOMP, CHAIN_APPROX_SIMPLE );
-
- // iterate through all the top-level contours,
- // draw each connected component with its own random color
- int idx = 0;
- for( ; idx >= 0; idx = hierarchy[idx][0] )
- {
- Scalar color( rand()&255, rand()&255, rand()&255 );
- drawContours( dst, contours, idx, color, FILLED, 8, hierarchy );
- }
-
- namedWindow( "Components", 1 );
- imshow( "Components", dst );
- waitKey(0);
- }
-@endcode
+@include snippets/imgproc_drawContours.cpp
@param image Destination image.
@param contours All the input contours. Each contour is stored as a point vector.
diff --git a/modules/imgproc/src/color_hsv.cpp b/modules/imgproc/src/color_hsv.cpp
index d5a41dfcec..94a36f1106 100644
--- a/modules/imgproc/src/color_hsv.cpp
+++ b/modules/imgproc/src/color_hsv.cpp
@@ -213,6 +213,91 @@ struct RGB2HSV_f
};
+#if CV_SIMD128
+inline void HSV2RGB_simd(v_float32x4& v_h, v_float32x4& v_s, v_float32x4& v_v, float hscale)
+{
+ v_h = v_h * v_setall_f32(hscale);
+ v_float32x4 v_pre_sector = v_cvt_f32(v_trunc(v_h));
+ v_h = v_h - v_pre_sector;
+ v_float32x4 v_tab0 = v_v;
+ v_float32x4 v_one = v_setall_f32(1.0f);
+ v_float32x4 v_tab1 = v_v * (v_one - v_s);
+ v_float32x4 v_tab2 = v_v * (v_one - (v_s * v_h));
+ v_float32x4 v_tab3 = v_v * (v_one - (v_s * (v_one - v_h)));
+
+ v_float32x4 v_one_sixth = v_setall_f32(1.0f / 6.0f);
+ v_float32x4 v_sector = v_pre_sector * v_one_sixth;
+ v_sector = v_cvt_f32(v_trunc(v_sector));
+ v_float32x4 v_six = v_setall_f32(6.0f);
+ v_sector = v_pre_sector - (v_sector * v_six);
+
+ v_float32x4 v_two = v_setall_f32(2.0f);
+ v_h = v_tab1 & (v_sector < v_two);
+ v_h = v_h | (v_tab3 & (v_sector == v_two));
+ v_float32x4 v_three = v_setall_f32(3.0f);
+ v_h = v_h | (v_tab0 & (v_sector == v_three));
+ v_float32x4 v_four = v_setall_f32(4.0f);
+ v_h = v_h | (v_tab0 & (v_sector == v_four));
+ v_h = v_h | (v_tab2 & (v_sector > v_four));
+
+ v_s = v_tab3 & (v_sector < v_one);
+ v_s = v_s | (v_tab0 & (v_sector == v_one));
+ v_s = v_s | (v_tab0 & (v_sector == v_two));
+ v_s = v_s | (v_tab2 & (v_sector == v_three));
+ v_s = v_s | (v_tab1 & (v_sector > v_three));
+
+ v_v = v_tab0 & (v_sector < v_one);
+ v_v = v_v | (v_tab2 & (v_sector == v_one));
+ v_v = v_v | (v_tab1 & (v_sector == v_two));
+ v_v = v_v | (v_tab1 & (v_sector == v_three));
+ v_v = v_v | (v_tab3 & (v_sector == v_four));
+ v_v = v_v | (v_tab0 & (v_sector > v_four));
+}
+#endif
+
+
+inline void HSV2RGB_native(const float* src, float* dst, const float hscale, const int bidx)
+{
+ float h = src[0], s = src[1], v = src[2];
+ float b, g, r;
+
+ if( s == 0 )
+ b = g = r = v;
+ else
+ {
+ static const int sector_data[][3]=
+ {{1,3,0}, {1,0,2}, {3,0,1}, {0,2,1}, {0,1,3}, {2,1,0}};
+ float tab[4];
+ int sector;
+ h *= hscale;
+ if( h < 0 )
+ do h += 6; while( h < 0 );
+ else if( h >= 6 )
+ do h -= 6; while( h >= 6 );
+ sector = cvFloor(h);
+ h -= sector;
+ if( (unsigned)sector >= 6u )
+ {
+ sector = 0;
+ h = 0.f;
+ }
+
+ tab[0] = v;
+ tab[1] = v*(1.f - s);
+ tab[2] = v*(1.f - s*h);
+ tab[3] = v*(1.f - s*(1.f - h));
+
+ b = tab[sector_data[sector][0]];
+ g = tab[sector_data[sector][1]];
+ r = tab[sector_data[sector][2]];
+ }
+
+ dst[bidx] = b;
+ dst[1] = g;
+ dst[bidx^2] = r;
+}
+
+
struct HSV2RGB_f
{
typedef float channel_type;
@@ -224,152 +309,49 @@ struct HSV2RGB_f
#endif
}
- #if CV_SIMD128
- inline void process(v_float32x4& v_h, v_float32x4& v_s,
- v_float32x4& v_v, v_float32x4& v_scale) const
- {
- v_h = v_h * v_scale;
- v_float32x4 v_pre_sector = v_cvt_f32(v_trunc(v_h));
- v_h = v_h - v_pre_sector;
- v_float32x4 v_tab0 = v_v;
- v_float32x4 v_one = v_setall_f32(1.0f);
- v_float32x4 v_tab1 = v_v * (v_one - v_s);
- v_float32x4 v_tab2 = v_v * (v_one - (v_s * v_h));
- v_float32x4 v_tab3 = v_v * (v_one - (v_s * (v_one - v_h)));
-
- v_float32x4 v_one_sixth = v_setall_f32(1.0f / 6.0f);
- v_float32x4 v_sector = v_pre_sector * v_one_sixth;
- v_sector = v_cvt_f32(v_trunc(v_sector));
- v_float32x4 v_six = v_setall_f32(6.0f);
- v_sector = v_pre_sector - (v_sector * v_six);
-
- v_float32x4 v_two = v_setall_f32(2.0f);
- v_h = v_tab1 & (v_sector < v_two);
- v_h = v_h | (v_tab3 & (v_sector == v_two));
- v_float32x4 v_three = v_setall_f32(3.0f);
- v_h = v_h | (v_tab0 & (v_sector == v_three));
- v_float32x4 v_four = v_setall_f32(4.0f);
- v_h = v_h | (v_tab0 & (v_sector == v_four));
- v_h = v_h | (v_tab2 & (v_sector > v_four));
-
- v_s = v_tab3 & (v_sector < v_one);
- v_s = v_s | (v_tab0 & (v_sector == v_one));
- v_s = v_s | (v_tab0 & (v_sector == v_two));
- v_s = v_s | (v_tab2 & (v_sector == v_three));
- v_s = v_s | (v_tab1 & (v_sector > v_three));
-
- v_v = v_tab0 & (v_sector < v_one);
- v_v = v_v | (v_tab2 & (v_sector == v_one));
- v_v = v_v | (v_tab1 & (v_sector == v_two));
- v_v = v_v | (v_tab1 & (v_sector == v_three));
- v_v = v_v | (v_tab3 & (v_sector == v_four));
- v_v = v_v | (v_tab0 & (v_sector > v_four));
- }
- #endif
-
void operator()(const float* src, float* dst, int n) const
{
int i = 0, bidx = blueIdx, dcn = dstcn;
- float alpha = ColorChannel::max();
n *= 3;
- #if CV_SIMD128
- if (hasSIMD)
+ if (dcn == 3)
{
- v_float32x4 v_scale = v_setall_f32(hscale);
- if (dcn == 3)
+ #if CV_SIMD128
+ if (hasSIMD)
{
- if (bidx)
- {
- for (; i <= n - 12; i += 12, dst += dcn * 4)
- {
- v_float32x4 v_h;
- v_float32x4 v_s;
- v_float32x4 v_v;
- v_load_deinterleave(src + i, v_h, v_s, v_v);
- process(v_h, v_s, v_v, v_scale);
- v_store_interleave(dst, v_v, v_s, v_h);
- }
- } else {
- for (; i <= n - 12; i += 12, dst += dcn * 4)
- {
- v_float32x4 v_h;
- v_float32x4 v_s;
- v_float32x4 v_v;
- v_load_deinterleave(src + i, v_h, v_s, v_v);
- process(v_h, v_s, v_v, v_scale);
- v_store_interleave(dst, v_h, v_s, v_v);
- }
- }
- } else { // dcn == 4
- v_float32x4 v_a = v_setall_f32(alpha);
- if (bidx)
+ for (; i <= n - 12; i += 12, dst += dcn * 4)
{
- for (; i <= n - 12; i += 12, dst += dcn * 4)
- {
- v_float32x4 v_h;
- v_float32x4 v_s;
- v_float32x4 v_v;
- v_load_deinterleave(src + i, v_h, v_s, v_v);
- process(v_h, v_s, v_v, v_scale);
- v_store_interleave(dst, v_v, v_s, v_h, v_a);
- }
- } else {
- for (; i <= n - 12; i += 12, dst += dcn * 4)
- {
- v_float32x4 v_h;
- v_float32x4 v_s;
- v_float32x4 v_v;
- v_load_deinterleave(src + i, v_h, v_s, v_v);
- process(v_h, v_s, v_v, v_scale);
- v_store_interleave(dst, v_h, v_s, v_v, v_a);
- }
+ v_float32x4 v_src[3];
+ v_load_deinterleave(src + i, v_src[0], v_src[1], v_src[2]);
+ HSV2RGB_simd(v_src[0], v_src[1], v_src[2], hscale);
+ v_store_interleave(dst, v_src[bidx], v_src[1], v_src[bidx^2]);
}
}
- }
- #endif
-
- for( ; i < n; i += 3, dst += dcn )
- {
- float h = src[i], s = src[i+1], v = src[i+2];
- float b, g, r;
-
- if( s == 0 )
- b = g = r = v;
- else
+ #endif
+ for( ; i < n; i += 3, dst += dcn )
{
- static const int sector_data[][3]=
- {{1,3,0}, {1,0,2}, {3,0,1}, {0,2,1}, {0,1,3}, {2,1,0}};
- float tab[4];
- int sector;
- h *= hscale;
- if( h < 0 )
- do h += 6; while( h < 0 );
- else if( h >= 6 )
- do h -= 6; while( h >= 6 );
- sector = cvFloor(h);
- h -= sector;
- if( (unsigned)sector >= 6u )
+ HSV2RGB_native(src + i, dst, hscale, bidx);
+ }
+ } else { // dcn == 4
+ float alpha = ColorChannel::max();
+ #if CV_SIMD128
+ if (hasSIMD)
+ {
+ for (; i <= n - 12; i += 12, dst += dcn * 4)
{
- sector = 0;
- h = 0.f;
+ v_float32x4 v_src[3];
+ v_load_deinterleave(src + i, v_src[0], v_src[1], v_src[2]);
+ HSV2RGB_simd(v_src[0], v_src[1], v_src[2], hscale);
+ v_float32x4 v_a = v_setall_f32(alpha);
+ v_store_interleave(dst, v_src[bidx], v_src[1], v_src[bidx^2], v_a);
}
-
- tab[0] = v;
- tab[1] = v*(1.f - s);
- tab[2] = v*(1.f - s*h);
- tab[3] = v*(1.f - s*(1.f - h));
-
- b = tab[sector_data[sector][0]];
- g = tab[sector_data[sector][1]];
- r = tab[sector_data[sector][2]];
}
-
- dst[bidx] = b;
- dst[1] = g;
- dst[bidx^2] = r;
- if( dcn == 4 )
+ #endif
+ for( ; i < n; i += 3, dst += dcn )
+ {
+ HSV2RGB_native(src + i, dst, hscale, bidx);
dst[3] = alpha;
+ }
}
}
@@ -386,216 +368,111 @@ struct HSV2RGB_b
typedef uchar channel_type;
HSV2RGB_b(int _dstcn, int _blueIdx, int _hrange)
- : dstcn(_dstcn), cvt(3, _blueIdx, (float)_hrange)
+ : dstcn(_dstcn), blueIdx(_blueIdx), hscale(6.0f / _hrange)
{
- #if CV_NEON
- v_scale_inv = vdupq_n_f32(1.f/255.f);
- v_scale = vdupq_n_f32(255.f);
- v_alpha = vdup_n_u8(ColorChannel::max());
- #elif CV_SSE2
- v_scale = _mm_set1_ps(255.0f);
- v_alpha = _mm_set1_ps(ColorChannel::max());
- v_zero = _mm_setzero_si128();
- haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
+ #if CV_SIMD128
+ hasSIMD = hasSIMD128();
#endif
}
- #if CV_SSE2
- void process(__m128i v_r, __m128i v_g, __m128i v_b,
- const __m128& v_coeffs_,
- float * buf) const
- {
- __m128 v_r0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(v_r, v_zero));
- __m128 v_g0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(v_g, v_zero));
- __m128 v_b0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(v_b, v_zero));
-
- __m128 v_r1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(v_r, v_zero));
- __m128 v_g1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(v_g, v_zero));
- __m128 v_b1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(v_b, v_zero));
-
- __m128 v_coeffs = v_coeffs_;
-
- v_r0 = _mm_mul_ps(v_r0, v_coeffs);
- v_g1 = _mm_mul_ps(v_g1, v_coeffs);
-
- v_coeffs = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_coeffs), 0x49));
-
- v_r1 = _mm_mul_ps(v_r1, v_coeffs);
- v_b0 = _mm_mul_ps(v_b0, v_coeffs);
-
- v_coeffs = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_coeffs), 0x49));
-
- v_g0 = _mm_mul_ps(v_g0, v_coeffs);
- v_b1 = _mm_mul_ps(v_b1, v_coeffs);
-
- _mm_store_ps(buf, v_r0);
- _mm_store_ps(buf + 4, v_r1);
- _mm_store_ps(buf + 8, v_g0);
- _mm_store_ps(buf + 12, v_g1);
- _mm_store_ps(buf + 16, v_b0);
- _mm_store_ps(buf + 20, v_b1);
- }
- #endif
-
void operator()(const uchar* src, uchar* dst, int n) const
{
- int i, j, dcn = dstcn;
+ int j = 0, dcn = dstcn;
uchar alpha = ColorChannel::max();
- float CV_DECL_ALIGNED(16) buf[3*BLOCK_SIZE];
- #if CV_SSE2
- __m128 v_coeffs = _mm_set_ps(1.f, 1.f/255.f, 1.f/255.f, 1.f);
- #endif
- for( i = 0; i < n; i += BLOCK_SIZE, src += BLOCK_SIZE*3 )
+ #if CV_SIMD128
+ if (hasSIMD)
{
- int dn = std::min(n - i, (int)BLOCK_SIZE);
- j = 0;
-
- #if CV_NEON
- for ( ; j <= (dn - 8) * 3; j += 24)
- {
- uint8x8x3_t v_src = vld3_u8(src + j);
- uint16x8_t v_t0 = vmovl_u8(v_src.val[0]),
- v_t1 = vmovl_u8(v_src.val[1]),
- v_t2 = vmovl_u8(v_src.val[2]);
-
- float32x4x3_t v_dst;
- v_dst.val[0] = vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_t0)));
- v_dst.val[1] = vmulq_f32(vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_t1))), v_scale_inv);
- v_dst.val[2] = vmulq_f32(vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_t2))), v_scale_inv);
- vst3q_f32(buf + j, v_dst);
-
- v_dst.val[0] = vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_t0)));
- v_dst.val[1] = vmulq_f32(vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_t1))), v_scale_inv);
- v_dst.val[2] = vmulq_f32(vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_t2))), v_scale_inv);
- vst3q_f32(buf + j + 12, v_dst);
- }
- #elif CV_SSE2
- if (haveSIMD)
+ for (j = 0; j <= (n - 16) * 3; j += 48, dst += dcn * 16)
{
- for ( ; j <= (dn - 8) * 3; j += 24)
+ v_uint8x16 h_b, s_b, v_b;
+ v_uint16x8 h_w[2], s_w[2], v_w[2];
+ v_uint32x4 h_u[4], s_u[4], v_u[4];
+ v_load_deinterleave(src + j, h_b, s_b, v_b);
+ v_expand(h_b, h_w[0], h_w[1]);
+ v_expand(s_b, s_w[0], s_w[1]);
+ v_expand(v_b, v_w[0], v_w[1]);
+ v_expand(h_w[0], h_u[0], h_u[1]);
+ v_expand(h_w[1], h_u[2], h_u[3]);
+ v_expand(s_w[0], s_u[0], s_u[1]);
+ v_expand(s_w[1], s_u[2], s_u[3]);
+ v_expand(v_w[0], v_u[0], v_u[1]);
+ v_expand(v_w[1], v_u[2], v_u[3]);
+
+ v_int32x4 b_i[4], g_i[4], r_i[4];
+ v_float32x4 v_coeff0 = v_setall_f32(1.0f / 255.0f);
+ v_float32x4 v_coeff1 = v_setall_f32(255.0f);
+
+ for( int k = 0; k < 4; k++ )
{
- __m128i v_src0 = _mm_loadu_si128((__m128i const *)(src + j));
- __m128i v_src1 = _mm_loadl_epi64((__m128i const *)(src + j + 16));
-
- process(_mm_unpacklo_epi8(v_src0, v_zero),
- _mm_unpackhi_epi8(v_src0, v_zero),
- _mm_unpacklo_epi8(v_src1, v_zero),
- v_coeffs,
- buf + j);
+ v_float32x4 v_src[3];
+ v_src[0] = v_cvt_f32(v_reinterpret_as_s32(h_u[k]));
+ v_src[1] = v_cvt_f32(v_reinterpret_as_s32(s_u[k]));
+ v_src[2] = v_cvt_f32(v_reinterpret_as_s32(v_u[k]));
+
+ v_src[1] *= v_coeff0;
+ v_src[2] *= v_coeff0;
+ HSV2RGB_simd(v_src[0], v_src[1], v_src[2], hscale);
+
+ v_src[0] *= v_coeff1;
+ v_src[1] *= v_coeff1;
+ v_src[2] *= v_coeff1;
+ b_i[k] = v_trunc(v_src[0]);
+ g_i[k] = v_trunc(v_src[1]);
+ r_i[k] = v_trunc(v_src[2]);
}
- }
- #endif
- for( ; j < dn*3; j += 3 )
- {
- buf[j] = src[j];
- buf[j+1] = src[j+1]*(1.f/255.f);
- buf[j+2] = src[j+2]*(1.f/255.f);
- }
- cvt(buf, buf, dn);
+ v_uint16x8 r_w[2], g_w[2], b_w[2];
+ v_uint8x16 r_b, g_b, b_b;
- j = 0;
- #if CV_NEON
- for ( ; j <= (dn - 8) * 3; j += 24, dst += dcn * 8)
- {
- float32x4x3_t v_src0 = vld3q_f32(buf + j), v_src1 = vld3q_f32(buf + j + 12);
- uint8x8_t v_dst0 = vqmovn_u16(vcombine_u16(vqmovn_u32(cv_vrndq_u32_f32(vmulq_f32(v_src0.val[0], v_scale))),
- vqmovn_u32(cv_vrndq_u32_f32(vmulq_f32(v_src1.val[0], v_scale)))));
- uint8x8_t v_dst1 = vqmovn_u16(vcombine_u16(vqmovn_u32(cv_vrndq_u32_f32(vmulq_f32(v_src0.val[1], v_scale))),
- vqmovn_u32(cv_vrndq_u32_f32(vmulq_f32(v_src1.val[1], v_scale)))));
- uint8x8_t v_dst2 = vqmovn_u16(vcombine_u16(vqmovn_u32(cv_vrndq_u32_f32(vmulq_f32(v_src0.val[2], v_scale))),
- vqmovn_u32(cv_vrndq_u32_f32(vmulq_f32(v_src1.val[2], v_scale)))));
+ r_w[0] = v_pack_u(r_i[0], r_i[1]);
+ r_w[1] = v_pack_u(r_i[2], r_i[3]);
+ r_b = v_pack(r_w[0], r_w[1]);
+ g_w[0] = v_pack_u(g_i[0], g_i[1]);
+ g_w[1] = v_pack_u(g_i[2], g_i[3]);
+ g_b = v_pack(g_w[0], g_w[1]);
+ b_w[0] = v_pack_u(b_i[0], b_i[1]);
+ b_w[1] = v_pack_u(b_i[2], b_i[3]);
+ b_b = v_pack(b_w[0], b_w[1]);
- if (dcn == 4)
+ if( dcn == 3 )
{
- uint8x8x4_t v_dst;
- v_dst.val[0] = v_dst0;
- v_dst.val[1] = v_dst1;
- v_dst.val[2] = v_dst2;
- v_dst.val[3] = v_alpha;
- vst4_u8(dst, v_dst);
+ if( blueIdx == 0 )
+ v_store_interleave(dst, b_b, g_b, r_b);
+ else
+ v_store_interleave(dst, r_b, g_b, b_b);
}
else
{
- uint8x8x3_t v_dst;
- v_dst.val[0] = v_dst0;
- v_dst.val[1] = v_dst1;
- v_dst.val[2] = v_dst2;
- vst3_u8(dst, v_dst);
+ v_uint8x16 alpha_b = v_setall_u8(alpha);
+ if( blueIdx == 0 )
+ v_store_interleave(dst, b_b, g_b, r_b, alpha_b);
+ else
+ v_store_interleave(dst, r_b, g_b, b_b, alpha_b);
}
}
- #elif CV_SSE2
- if (dcn == 3 && haveSIMD)
- {
- for ( ; j <= (dn * 3 - 16); j += 16, dst += 16)
- {
- __m128 v_src0 = _mm_mul_ps(_mm_load_ps(buf + j), v_scale);
- __m128 v_src1 = _mm_mul_ps(_mm_load_ps(buf + j + 4), v_scale);
- __m128 v_src2 = _mm_mul_ps(_mm_load_ps(buf + j + 8), v_scale);
- __m128 v_src3 = _mm_mul_ps(_mm_load_ps(buf + j + 12), v_scale);
-
- __m128i v_dst0 = _mm_packs_epi32(_mm_cvtps_epi32(v_src0),
- _mm_cvtps_epi32(v_src1));
- __m128i v_dst1 = _mm_packs_epi32(_mm_cvtps_epi32(v_src2),
- _mm_cvtps_epi32(v_src3));
-
- _mm_storeu_si128((__m128i *)dst, _mm_packus_epi16(v_dst0, v_dst1));
- }
-
- int jr = j % 3;
- if (jr)
- dst -= jr, j -= jr;
- }
- else if (dcn == 4 && haveSIMD)
- {
- for ( ; j <= (dn * 3 - 12); j += 12, dst += 16)
- {
- __m128 v_buf0 = _mm_mul_ps(_mm_load_ps(buf + j), v_scale);
- __m128 v_buf1 = _mm_mul_ps(_mm_load_ps(buf + j + 4), v_scale);
- __m128 v_buf2 = _mm_mul_ps(_mm_load_ps(buf + j + 8), v_scale);
-
- __m128 v_ba0 = _mm_unpackhi_ps(v_buf0, v_alpha);
- __m128 v_ba1 = _mm_unpacklo_ps(v_buf2, v_alpha);
-
- __m128i v_src0 = _mm_cvtps_epi32(_mm_shuffle_ps(v_buf0, v_ba0, 0x44));
- __m128i v_src1 = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_shuffle_ps(v_ba0, v_buf1, 0x4e)), 0x78);
- __m128i v_src2 = _mm_cvtps_epi32(_mm_shuffle_ps(v_buf1, v_ba1, 0x4e));
- __m128i v_src3 = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_shuffle_ps(v_ba1, v_buf2, 0xee)), 0x78);
-
- __m128i v_dst0 = _mm_packs_epi32(v_src0, v_src1);
- __m128i v_dst1 = _mm_packs_epi32(v_src2, v_src3);
-
- _mm_storeu_si128((__m128i *)dst, _mm_packus_epi16(v_dst0, v_dst1));
- }
-
- int jr = j % 3;
- if (jr)
- dst -= jr, j -= jr;
- }
- #endif
-
- for( ; j < dn*3; j += 3, dst += dcn )
- {
- dst[0] = saturate_cast(buf[j]*255.f);
- dst[1] = saturate_cast(buf[j+1]*255.f);
- dst[2] = saturate_cast(buf[j+2]*255.f);
- if( dcn == 4 )
- dst[3] = alpha;
- }
+ }
+ #endif
+ for( ; j < n * 3; j += 3, dst += dcn )
+ {
+ float buf[6];
+ buf[0] = src[j];
+ buf[1] = src[j+1] * (1.0f / 255.0f);
+ buf[2] = src[j+2] * (1.0f / 255.0f);
+ HSV2RGB_native(buf, buf + 3, hscale, blueIdx);
+ dst[0] = saturate_cast(buf[3] * 255.0f);
+ dst[1] = saturate_cast(buf[4] * 255.0f);
+ dst[2] = saturate_cast(buf[5] * 255.0f);
+ if( dcn == 4 )
+ dst[3] = alpha;
}
}
int dstcn;
- HSV2RGB_f cvt;
- #if CV_NEON
- float32x4_t v_scale, v_scale_inv;
- uint8x8_t v_alpha;
- #elif CV_SSE2
- __m128 v_scale;
- __m128 v_alpha;
- __m128i v_zero;
- bool haveSIMD;
+ int blueIdx;
+ float hscale;
+ #if CV_SIMD128
+ bool hasSIMD;
#endif
};
diff --git a/modules/imgproc/src/histogram.cpp b/modules/imgproc/src/histogram.cpp
index 9ff52e3bcc..f3ddeaf78c 100644
--- a/modules/imgproc/src/histogram.cpp
+++ b/modules/imgproc/src/histogram.cpp
@@ -821,6 +821,10 @@ static bool ipp_calchist(const Mat &image, Mat &hist, int histSize, const float*
return false;
#endif
+ // IPP_DISABLE_HISTOGRAM - https://github.com/opencv/opencv/issues/11544
+ if (uniform && (ranges[0][1] - ranges[0][0]) != histSize)
+ return false;
+
Mat ihist = hist;
if(accumulate)
ihist.create(1, &histSize, CV_32S);
diff --git a/modules/imgproc/src/hough.cpp b/modules/imgproc/src/hough.cpp
index ec05edf888..1f61146193 100644
--- a/modules/imgproc/src/hough.cpp
+++ b/modules/imgproc/src/hough.cpp
@@ -803,7 +803,7 @@ static bool ocl_HoughLines(InputArray _src, OutputArray _lines, double rho, doub
int total_points = counters.getMat(ACCESS_READ).at(0, 0);
if (total_points <= 0)
{
- _lines.assign(UMat(0,0,CV_32FC2));
+ _lines.release();
return true;
}
@@ -831,7 +831,7 @@ static bool ocl_HoughLines(InputArray _src, OutputArray _lines, double rho, doub
if (total_lines > 0)
_lines.assign(lines.rowRange(Range(0, total_lines)));
else
- _lines.assign(UMat(0,0,CV_32FC2));
+ _lines.release();
return true;
}
@@ -857,7 +857,7 @@ static bool ocl_HoughLinesP(InputArray _src, OutputArray _lines, double rho, dou
int total_points = counters.getMat(ACCESS_READ).at(0, 0);
if (total_points <= 0)
{
- _lines.assign(UMat(0,0,CV_32SC4));
+ _lines.release();
return true;
}
@@ -885,7 +885,7 @@ static bool ocl_HoughLinesP(InputArray _src, OutputArray _lines, double rho, dou
if (total_lines > 0)
_lines.assign(lines.rowRange(Range(0, total_lines)));
else
- _lines.assign(UMat(0,0,CV_32SC4));
+ _lines.release();
return true;
}
diff --git a/modules/imgproc/test/test_histograms.cpp b/modules/imgproc/test/test_histograms.cpp
index 10f74a3eb5..5386c29ac7 100644
--- a/modules/imgproc/test/test_histograms.cpp
+++ b/modules/imgproc/test/test_histograms.cpp
@@ -1918,5 +1918,35 @@ TEST(Imgproc_Hist_CalcBackProject, accuracy) { CV_CalcBackProjectTest test; test
TEST(Imgproc_Hist_CalcBackProjectPatch, accuracy) { CV_CalcBackProjectPatchTest test; test.safe_run(); }
TEST(Imgproc_Hist_BayesianProb, accuracy) { CV_BayesianProbTest test; test.safe_run(); }
+TEST(Imgproc_Hist_Calc, calcHist_regression_11544)
+{
+ cv::Mat1w m = cv::Mat1w::zeros(10, 10);
+ int n_images = 1;
+ int channels[] = { 0 };
+ cv::Mat mask;
+ cv::MatND hist1, hist2;
+ cv::MatND hist1_opt, hist2_opt;
+ int dims = 1;
+ int hist_size[] = { 1000 };
+ float range1[] = { 0, 900 };
+ float range2[] = { 0, 1000 };
+ const float* ranges1[] = { range1 };
+ const float* ranges2[] = { range2 };
+
+ setUseOptimized(false);
+ cv::calcHist(&m, n_images, channels, mask, hist1, dims, hist_size, ranges1);
+ cv::calcHist(&m, n_images, channels, mask, hist2, dims, hist_size, ranges2);
+
+ setUseOptimized(true);
+ cv::calcHist(&m, n_images, channels, mask, hist1_opt, dims, hist_size, ranges1);
+ cv::calcHist(&m, n_images, channels, mask, hist2_opt, dims, hist_size, ranges2);
+
+ for(int i = 0; i < 1000; i++)
+ {
+ EXPECT_EQ(hist1.at(i, 0), hist1_opt.at(i, 0)) << i;
+ EXPECT_EQ(hist2.at(i, 0), hist2_opt.at