Merge remote-tracking branch 'upstream/3.4' into merge-3.4
Revert "documentation: avoid links to 'master' branch from 3.4 maintenance branch" This reverts commit9ba9358ecb
. Revert "documentation: avoid links to 'master' branch from 3.4 maintenance branch (2)" This reverts commitf185802489
.
@ -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)
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
)
|
||||
|
||||
|
@ -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.
|
||||
")
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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.},
|
||||
|
@ -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)
|
||||
|
@ -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 <a href="https://github.com/opencv/opencv_contrib">OpenCV contrib modules</a> 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 <stdio.h>
|
||||
#include <iostream>
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/features2d.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/xfeatures2d.hpp"
|
||||
@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
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::xfeatures2d;
|
||||
@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
|
||||
|
||||
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<SURF> detector = SURF::create();
|
||||
detector->setHessianThreshold(minHessian);
|
||||
|
||||
std::vector<KeyPoint> 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 <img1> <img2>" << 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_description/SURF_matching_Demo.py)
|
||||
@include samples/python/tutorial_code/features2D/feature_description/SURF_matching_Demo.py
|
||||
@end_toggle
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
|
@ -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 <a href="https://github.com/opencv/opencv_contrib">OpenCV contrib modules</a> 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 <stdio.h>
|
||||
#include <iostream>
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/features2d.hpp"
|
||||
#include "opencv2/xfeatures2d.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
@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
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::xfeatures2d;
|
||||
@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
|
||||
|
||||
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<SURF> detector = SURF::create( minHessian );
|
||||
|
||||
std::vector<KeyPoint> 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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* @function readme */
|
||||
void readme()
|
||||
{ std::cout << " Usage: ./SURF_detector <img1> <img2>" << 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:
|
||||
|
||||

|
||||
|
@ -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 <a href="https://github.com/opencv/opencv_contrib">OpenCV contrib modules</a> 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 <a href="https://en.wikipedia.org/wiki/Hamming_distance">Hamming distance</a>.
|
||||
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
|
||||
*/
|
||||
@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
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/features2d.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/xfeatures2d.hpp"
|
||||
@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
|
||||
|
||||
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<SURF> detector = SURF::create();
|
||||
detector->setHessianThreshold(minHessian);
|
||||
|
||||
std::vector<KeyPoint> 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<char>(), 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 <img1> <img2>" << 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_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:
|
||||
- Here is the result of the SURF feature matching using the distance ratio test:
|
||||
|
||||

|
||||
|
||||
-# Additionally, we get as console output the keypoints filtered:
|
||||
|
||||

|
||||

|
||||
|
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 79 KiB |
@ -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 <a href="https://github.com/opencv/opencv_contrib">OpenCV contrib modules</a> 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 <stdio.h>
|
||||
#include <iostream>
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/features2d.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/calib3d.hpp"
|
||||
#include "opencv2/xfeatures2d.hpp"
|
||||
@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
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::xfeatures2d;
|
||||
@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
|
||||
|
||||
void readme();
|
||||
@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 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<SURF> detector = SURF::create( minHessian );
|
||||
|
||||
std::vector<KeyPoint> 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<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
|
||||
|
||||
//-- Localize the object
|
||||
std::vector<Point2f> obj;
|
||||
std::vector<Point2f> 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<Point2f> 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<Point2f> 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 );
|
||||
|
||||
//-- Show detected matches
|
||||
imshow( "Good Matches & Object detection", img_matches );
|
||||
|
||||
waitKey(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* @function readme */
|
||||
void readme()
|
||||
{ std::cout << " Usage: ./SURF_descriptor <img1> <img2>" << 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.
|
||||
|
||||

|
||||
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 88 KiB |
@ -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
|
||||
|
@ -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:
|
||||
|
||||

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

|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@ -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
|
||||
-----------
|
||||
|
@ -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
|
||||
------
|
||||
|
||||

|
||||

|
||||
|
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 27 KiB |
@ -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
|
||||
-----------
|
||||
|
@ -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.
|
||||
|
@ -76,13 +76,17 @@
|
||||
#include <stdarg.h>
|
||||
#include <vector>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
#include "opencv2/core/utility.hpp"
|
||||
#include <opencv2/core/utils/logger.defines.hpp>
|
||||
|
||||
//#define ENABLE_TRIM_COL_ROW
|
||||
|
||||
//#define DEBUG_CHESSBOARD
|
||||
|
||||
//#undef CV_LOG_STRIP_LEVEL
|
||||
//#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_VERBOSE + 1
|
||||
#include <opencv2/core/utils/logger.hpp>
|
||||
|
||||
#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<CvMemStorage> 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<std::vector<Point> > contours;
|
||||
std::vector<Vec4i> 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<int> contour_child_counter(contours.size(), 0);
|
||||
int boardIdx = -1;
|
||||
|
||||
std::vector<QuadCountour> 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<Point>& contour = contours[idx];
|
||||
|
||||
Rect contour_rect = boundingRect(contour);
|
||||
if (contour_rect.area() < min_size)
|
||||
continue;
|
||||
|
||||
std::vector<Point> 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<Point> 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<double>(pt[0] - pt[2]));
|
||||
double d2 = sqrt(normL2Sqr<double>(pt[1] - pt[3]));
|
||||
|
||||
// philipg. Only accept those quadrangles which are more square
|
||||
// than rectangular and which are big enough
|
||||
double d3 = sqrt(normL2Sqr<double>(pt[0] - pt[1]));
|
||||
double d4 = sqrt(normL2Sqr<double>(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>()
|
||||
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;
|
||||
}
|
||||
|
@ -78,10 +78,7 @@ class RANSACPointSetRegistrator : public PointSetRegistrator
|
||||
public:
|
||||
RANSACPointSetRegistrator(const Ptr<PointSetRegistrator::Callback>& _cb=Ptr<PointSetRegistrator::Callback>(),
|
||||
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<PointSetRegistrator::Callback> cb;
|
||||
int modelPoints;
|
||||
bool checkPartialSubsets;
|
||||
double threshold;
|
||||
double confidence;
|
||||
int maxIters;
|
||||
|
@ -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 <typename T>
|
||||
struct dispShiftTemplate
|
||||
{ };
|
||||
|
||||
template<>
|
||||
struct dispShiftTemplate<short>
|
||||
{
|
||||
enum { value = DISPARITY_SHIFT_16S };
|
||||
};
|
||||
|
||||
template<>
|
||||
struct dispShiftTemplate<int>
|
||||
{
|
||||
enum { value = DISPARITY_SHIFT_32S };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
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 <typename dType>
|
||||
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<dType>::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<short>();
|
||||
dType* dptr = disp.ptr<dType>();
|
||||
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<dType>(ndisp - mind - 1 + mindisp, p-n, d);
|
||||
}
|
||||
else
|
||||
dptr[y*dstep] = (short)((ndisp - mind - 1 + mindisp)*16);
|
||||
dptr[y*dstep] = dispDescale<dType>(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 <typename mType>
|
||||
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<mType>::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<mType>(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<short>( left_i, right_i, disp_i, cost_i, *state, ptr, row0, rows - row1 );
|
||||
else
|
||||
findStereoCorrespondenceBM_SIMD<int>( left_i, right_i, disp_i, cost_i, *state, ptr, row0, rows - row1);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if( disp_i.type() == CV_16S )
|
||||
findStereoCorrespondenceBM<short>( left_i, right_i, disp_i, cost_i, *state, ptr, row0, rows - row1, DISPARITY_SHIFT_16S );
|
||||
findStereoCorrespondenceBM<short>( left_i, right_i, disp_i, cost_i, *state, ptr, row0, rows - row1 );
|
||||
else
|
||||
findStereoCorrespondenceBM<int>( left_i, right_i, disp_i, cost_i, *state, ptr, row0, rows - row1, DISPARITY_SHIFT_32S );
|
||||
findStereoCorrespondenceBM<int>( 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)
|
||||
|
@ -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_<float> 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++)
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -1372,6 +1372,20 @@ Point_<_Tp> operator / (const Point_<_Tp>& a, double b)
|
||||
}
|
||||
|
||||
|
||||
template<typename _AccTp> static inline _AccTp normL2Sqr(const Point_<int>& pt);
|
||||
template<typename _AccTp> static inline _AccTp normL2Sqr(const Point_<int64>& pt);
|
||||
template<typename _AccTp> static inline _AccTp normL2Sqr(const Point_<float>& pt);
|
||||
template<typename _AccTp> static inline _AccTp normL2Sqr(const Point_<double>& pt);
|
||||
|
||||
template<> inline int normL2Sqr<int>(const Point_<int>& pt) { return pt.dot(pt); }
|
||||
template<> inline int64 normL2Sqr<int64>(const Point_<int64>& pt) { return pt.dot(pt); }
|
||||
template<> inline float normL2Sqr<float>(const Point_<float>& pt) { return pt.dot(pt); }
|
||||
template<> inline double normL2Sqr<double>(const Point_<int>& pt) { return pt.dot(pt); }
|
||||
|
||||
template<> inline double normL2Sqr<double>(const Point_<float>& pt) { return pt.ddot(pt); }
|
||||
template<> inline double normL2Sqr<double>(const Point_<double>& pt) { return pt.ddot(pt); }
|
||||
|
||||
|
||||
|
||||
//////////////////////////////// 3D Point ///////////////////////////////
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 )
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
@}
|
||||
*/
|
||||
|
@ -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 <a href="http://caffe.berkeleyvision.org/tutorial/layers.html">Caffe</a> functionality:
|
||||
In particular, the following layers and Caffe importer were tested to reproduce <a href="http://caffe.berkeleyvision.org/tutorial/layers.html">Caffe</a> 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<ProposalLayer> create(const LayerParams& params);
|
||||
};
|
||||
|
||||
class CV_EXPORTS CropAndResizeLayer : public Layer
|
||||
{
|
||||
public:
|
||||
static Ptr<Layer> create(const LayerParams& params);
|
||||
};
|
||||
|
||||
//! @}
|
||||
//! @}
|
||||
CV__DNN_EXPERIMENTAL_NS_END
|
||||
|
@ -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<BackendWrapper>& 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);
|
||||
|
@ -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:
|
||||
|
@ -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<DNNBackend, DNNTarget> >
|
||||
{
|
||||
@ -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<DNNBackend, DNNTarget> testCases[] = {
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_CPU),
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL),
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL_FP16),
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_MYRIAD),
|
||||
#endif
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_DEFAULT, DNN_TARGET_CPU),
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_DEFAULT, DNN_TARGET_OPENCL),
|
||||
|
@ -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;
|
||||
|
@ -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> 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<InferenceEngine::WeightableLayer>(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<EltwiseLayer> 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> concatLayer = ld.layerInstance.dynamicCast<ConcatLayer>();
|
||||
|
@ -242,7 +242,7 @@ bool HalideScheduler::process(Ptr<BackendNode>& node)
|
||||
std::map<std::string, Halide::Func> 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<Halide::Func>& funcs = node.dynamicCast<HalideBackendNode>()->funcs;
|
||||
for (int i = funcs.size() - 1; i >= 0; --i)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
108
modules/dnn/src/layers/crop_and_resize_layer.cpp
Normal file
@ -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<float>("width");
|
||||
outHeight = params.get<float>("height");
|
||||
}
|
||||
|
||||
bool getMemoryShapes(const std::vector<MatShape> &inputs,
|
||||
const int requiredOutputs,
|
||||
std::vector<MatShape> &outputs,
|
||||
std::vector<MatShape> &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<Mat*> &inputs, std::vector<Mat> &outputs, std::vector<Mat> &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<float>(b);
|
||||
float left = boxes.at<float>(b, 3);
|
||||
float top = boxes.at<float>(b, 4);
|
||||
float right = boxes.at<float>(b, 5);
|
||||
float bottom = boxes.at<float>(b, 6);
|
||||
float boxWidth = right - left;
|
||||
float boxHeight = bottom - top;
|
||||
|
||||
float heightScale = boxHeight * static_cast<float>(inpHeight - 1) / (outHeight - 1);
|
||||
float widthScale = boxWidth * static_cast<float>(inpWidth - 1) / (outWidth - 1);
|
||||
for (int y = 0; y < outHeight; ++y)
|
||||
{
|
||||
float input_y = top * (inpHeight - 1) + y * heightScale;
|
||||
int y0 = static_cast<int>(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<int>(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<Layer> CropAndResizeLayer::create(const LayerParams& params)
|
||||
{
|
||||
return Ptr<CropAndResizeLayer>(new CropAndResizeLayerImpl(params));
|
||||
}
|
||||
|
||||
} // namespace dnn
|
||||
} // namespace cv
|
@ -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
|
||||
|
@ -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<BackendNode> tryAttach(const Ptr<BackendNode>& 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<InferenceEngine::ReLULayer> 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<InferenceEngine::ClampLayer> 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<InferenceEngine::CNNLayer> ieLayer(new InferenceEngine::CNNLayer(lp));
|
||||
return ieLayer;
|
||||
}
|
||||
#endif // HAVE_INF_ENGINE
|
||||
|
||||
|
@ -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"))
|
||||
|
@ -73,7 +73,7 @@ public:
|
||||
|
||||
virtual bool tryFuse(Ptr<Layer>& 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)
|
||||
{
|
||||
// MVN is applied to single values at an every row.
|
||||
outBlob.setTo(0);
|
||||
return;
|
||||
}
|
||||
|
||||
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.
|
||||
if (shift.empty())
|
||||
{
|
||||
outBlob.setTo(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( i = 0; i < newRows; i++ )
|
||||
{
|
||||
outMat.row(i).setTo(((float*)shift.data)[i]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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<MatShape> &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<InferenceEngine::CNNLayer> 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)
|
||||
{
|
||||
ieLayer->params["aspect_ratio"] = format("%f", _aspectRatios[0]);
|
||||
for (int i = 1; i < _aspectRatios.size(); ++i)
|
||||
ieLayer->params["aspect_ratio"] += format(",%f", _aspectRatios[i]);
|
||||
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["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<float> _variance;
|
||||
std::vector<float> _offsetsX;
|
||||
std::vector<float> _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<float> _boxWidths;
|
||||
std::vector<float> _boxHeights;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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 <opencv2/imgproc.hpp>
|
||||
|
||||
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<Mat*>& inputs, std::vector<Mat> &outputs) CV_OVERRIDE
|
||||
{
|
||||
if (!outWidth && !outHeight)
|
||||
@ -75,6 +82,26 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&) CV_OVERRIDE
|
||||
{
|
||||
#ifdef HAVE_INF_ENGINE
|
||||
InferenceEngine::LayerParams lp;
|
||||
lp.name = name;
|
||||
lp.type = "Resample";
|
||||
lp.precision = InferenceEngine::Precision::FP32;
|
||||
|
||||
std::shared_ptr<InferenceEngine::CNNLayer> 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<BackendNode>(new InfEngineBackendNode(ieLayer));
|
||||
#endif // HAVE_INF_ENGINE
|
||||
return Ptr<BackendNode>();
|
||||
}
|
||||
|
||||
private:
|
||||
int outWidth, outHeight, zoomFactor;
|
||||
bool alignCorners;
|
||||
|
@ -709,7 +709,7 @@ bool OCL4DNNConvSpatial<Dtype>::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<float>();
|
||||
Mat swizzledWeightMat;
|
||||
|
@ -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<Ptr<BackendWrapper> >& 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<size_t> 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<float>::Ptr wrapToInfEngineBlob(const Mat& m, const std::vector<size_t>& 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<std::string, InferenceEngine::InferenceEnginePluginPtr> 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<InferenceEngine::IExtension>("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<Ptr<BackendWrapper> >& ptrs)
|
||||
@ -402,10 +408,7 @@ void InfEngineBackendNet::addBlobs(const std::vector<Ptr<BackendWrapper> >& 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)
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -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<int>(0) == dilation.get<int>(1));
|
||||
layerParams.set("dilation", dilation.get<int>(0));
|
||||
CV_Assert(dilation.size() == 2);
|
||||
layerParams.set("dilation_h", dilation.get<int>(0));
|
||||
layerParams.set("dilation_w", dilation.get<int>(1));
|
||||
|
||||
Mat paddings;
|
||||
parseTensor<int>(getConstBlob(layer, value_id, 2), paddings);
|
||||
@ -655,6 +656,10 @@ void TFImporter::populateNet(Net dstNet)
|
||||
layerParams.set("pad_w", paddings.at<float>(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<int32_t>(0, 2), *begins.ptr<int32_t>(0, 3));
|
||||
std::swap(*begins.ptr<int32_t>(0, 1), *begins.ptr<int32_t>(0, 2));
|
||||
std::swap(*sizes.ptr<int32_t>(0, 2), *sizes.ptr<int32_t>(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<int>(0));
|
||||
layerParams.set("width", cropSize.at<int>(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));
|
||||
|
@ -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<int, 4> isizes(ndims);
|
||||
|
@ -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<float>(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<DNNBackend, DNNTarget> testCases[] = {
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_CPU),
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL),
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL_FP16),
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_MYRIAD),
|
||||
#endif
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_DEFAULT, DNN_TARGET_OPENCL),
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_DEFAULT, DNN_TARGET_OPENCL_FP16)
|
||||
|
@ -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;
|
||||
|
@ -71,13 +71,31 @@ static void testDarknetModel(const std::string& cfg, const std::string& weights,
|
||||
const std::vector<int>& refClassIds,
|
||||
const std::vector<float>& refConfidences,
|
||||
const std::vector<Rect2d>& 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<Mat> 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<DNNTarget> Test_Darknet_nets;
|
||||
typedef testing::TestWithParam<tuple<DNNBackend, DNNTarget> > 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<cv::String> outNames(1, "detection_out");
|
||||
|
||||
std::vector<int> classIds(3);
|
||||
std::vector<float> confidences(3);
|
||||
std::vector<Rect2d> 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<cv::String> outNames(1, "detection_out");
|
||||
std::vector<int> classIds(2);
|
||||
std::vector<float> confidences(2);
|
||||
std::vector<Rect2d> 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<cv::String> outNames(3);
|
||||
outNames[0] = "yolo_82";
|
||||
outNames[1] = "yolo_94";
|
||||
@ -153,13 +182,27 @@ TEST_P(Test_Darknet_nets, YOLOv3)
|
||||
std::vector<float> confidences(3);
|
||||
std::vector<Rect2d> 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<DNNBackend, DNNTarget> testCases[] = {
|
||||
#ifdef HAVE_INF_ENGINE
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_CPU),
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL),
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL_FP16),
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_MYRIAD),
|
||||
#endif
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_DEFAULT, DNN_TARGET_CPU),
|
||||
tuple<DNNBackend, DNNTarget>(DNN_BACKEND_DEFAULT, DNN_TARGET_OPENCL),
|
||||
tuple<DNNBackend, DNNTarget>(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)
|
||||
{
|
||||
|
@ -834,6 +834,84 @@ TEST(Test_DLDT, two_inputs)
|
||||
|
||||
normAssert(out, firstInp + secondInp);
|
||||
}
|
||||
|
||||
class UnsupportedLayer : public Layer
|
||||
{
|
||||
public:
|
||||
UnsupportedLayer(const LayerParams ¶ms) {}
|
||||
|
||||
static Ptr<Layer> create(const LayerParams& params)
|
||||
{
|
||||
return Ptr<Layer>(new UnsupportedLayer(params));
|
||||
}
|
||||
|
||||
virtual bool supportBackend(int backendId) CV_OVERRIDE
|
||||
{
|
||||
return backendId == DNN_BACKEND_DEFAULT;
|
||||
}
|
||||
|
||||
virtual void forward(std::vector<cv::Mat*> &inputs, std::vector<cv::Mat> &outputs, std::vector<cv::Mat> &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<String>(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.
|
||||
|
@ -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<DNNTarget> availableDnnTargets()
|
||||
{
|
||||
@ -69,6 +69,6 @@ static testing::internal::ParamGenerator<DNNTarget> availableDnnTargets()
|
||||
return testing::ValuesIn(targets);
|
||||
}
|
||||
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -7952,6 +7952,12 @@ public:
|
||||
{
|
||||
CV_INSTRUMENT_REGION()
|
||||
|
||||
if(_image.empty())
|
||||
{
|
||||
keypoints.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
Mat mask = _mask.getMat(), grayImage;
|
||||
UMat ugrayImage;
|
||||
_InputArray gray = _image;
|
||||
|
@ -522,6 +522,12 @@ public:
|
||||
{
|
||||
CV_INSTRUMENT_REGION()
|
||||
|
||||
if(_image.empty())
|
||||
{
|
||||
keypoints.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
Mat mask = _mask.getMat(), grayImage;
|
||||
UMat ugrayImage;
|
||||
_InputArray gray = _image;
|
||||
|
@ -80,6 +80,12 @@ public:
|
||||
{
|
||||
CV_INSTRUMENT_REGION()
|
||||
|
||||
if(_image.empty())
|
||||
{
|
||||
keypoints.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Point2f> corners;
|
||||
|
||||
if (_image.isUMat())
|
||||
|
@ -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 <opencv2/core.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/imgcodecs.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
using namespace cv;
|
||||
|
||||
#include <iostream>
|
||||
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 <opencv2/imgproc.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
|
||||
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<Vec2f> 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<Vec4i> 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 <opencv2/imgproc.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
#include <math.h>
|
||||
|
||||
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<Vec3f> 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 <opencv2/imgproc.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
|
||||
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<float>(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<vector<Point> > contours;
|
||||
vector<Vec4i> 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.
|
||||
|
@ -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<float>::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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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]];
|
||||
HSV2RGB_native(src + i, dst, hscale, bidx);
|
||||
}
|
||||
|
||||
dst[bidx] = b;
|
||||
dst[1] = g;
|
||||
dst[bidx^2] = r;
|
||||
if( dcn == 4 )
|
||||
} else { // dcn == 4
|
||||
float alpha = ColorChannel<float>::max();
|
||||
#if CV_SIMD128
|
||||
if (hasSIMD)
|
||||
{
|
||||
for (; i <= n - 12; i += 12, dst += dcn * 4)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
#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<uchar>::max());
|
||||
#elif CV_SSE2
|
||||
v_scale = _mm_set1_ps(255.0f);
|
||||
v_alpha = _mm_set1_ps(ColorChannel<uchar>::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<uchar>::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)
|
||||
for (j = 0; j <= (n - 16) * 3; j += 48, dst += dcn * 16)
|
||||
{
|
||||
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]);
|
||||
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]);
|
||||
|
||||
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_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);
|
||||
|
||||
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 <= (dn - 8) * 3; j += 24)
|
||||
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));
|
||||
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]));
|
||||
|
||||
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_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<uchar>(buf[j]*255.f);
|
||||
dst[1] = saturate_cast<uchar>(buf[j+1]*255.f);
|
||||
dst[2] = saturate_cast<uchar>(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<uchar>(buf[3] * 255.0f);
|
||||
dst[1] = saturate_cast<uchar>(buf[4] * 255.0f);
|
||||
dst[2] = saturate_cast<uchar>(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
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -803,7 +803,7 @@ static bool ocl_HoughLines(InputArray _src, OutputArray _lines, double rho, doub
|
||||
int total_points = counters.getMat(ACCESS_READ).at<int>(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<int>(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;
|
||||
}
|
||||
|
@ -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<float>(i, 0), hist1_opt.at<float>(i, 0)) << i;
|
||||
EXPECT_EQ(hist2.at<float>(i, 0), hist2_opt.at<float>(i, 0)) << i;
|
||||
}
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
/* End Of File */
|
||||
|
@ -10,6 +10,13 @@
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#define CV_PY_FN_WITH_KW_(fn, flags) (PyCFunction)(void*)(PyCFunctionWithKeywords)(fn), (flags) | METH_VARARGS | METH_KEYWORDS
|
||||
#define CV_PY_FN_NOARGS_(fn, flags) (PyCFunction)(fn), (flags) | METH_NOARGS
|
||||
|
||||
#define CV_PY_FN_WITH_KW(fn) CV_PY_FN_WITH_KW_(fn, 0)
|
||||
#define CV_PY_FN_NOARGS(fn) CV_PY_FN_NOARGS_(fn, 0)
|
||||
|
||||
|
||||
#define MODULESTR "cv2"
|
||||
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
|
||||
#include <numpy/ndarrayobject.h>
|
||||
@ -474,8 +481,14 @@ typedef struct {
|
||||
static bool PyObject_IsUMat(PyObject *o);
|
||||
|
||||
// UMatWrapper init - try to map arguments from python to UMat constructors
|
||||
static int UMatWrapper_init(cv2_UMatWrapperObject *self, PyObject *args, PyObject *kwds)
|
||||
static int UMatWrapper_init(PyObject* self_, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
cv2_UMatWrapperObject* self = (cv2_UMatWrapperObject*)self_;
|
||||
if (self == NULL)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "Internal error");
|
||||
return -1;
|
||||
}
|
||||
self->um = NULL;
|
||||
{
|
||||
// constructor ()
|
||||
@ -548,8 +561,11 @@ static void UMatWrapper_dealloc(cv2_UMatWrapperObject* self)
|
||||
|
||||
// UMatWrapper.get() - returns numpy array by transferring UMat data to Mat and than wrapping it to numpy array
|
||||
// (using numpy allocator - and so without unnecessary copy)
|
||||
static PyObject * UMatWrapper_get(cv2_UMatWrapperObject* self)
|
||||
static PyObject * UMatWrapper_get(PyObject* self_, PyObject * /*args*/)
|
||||
{
|
||||
cv2_UMatWrapperObject* self = (cv2_UMatWrapperObject*)self_;
|
||||
if (self == NULL)
|
||||
return failmsgp("Incorrect type of self (must be 'cv2_UMatWrapperObject')");
|
||||
Mat m;
|
||||
m.allocator = &g_numpyAllocator;
|
||||
self->um->copyTo(m);
|
||||
@ -558,8 +574,11 @@ static PyObject * UMatWrapper_get(cv2_UMatWrapperObject* self)
|
||||
}
|
||||
|
||||
// UMatWrapper.handle() - returns the OpenCL handle of the UMat object
|
||||
static PyObject * UMatWrapper_handle(cv2_UMatWrapperObject* self, PyObject *args, PyObject *kwds)
|
||||
static PyObject * UMatWrapper_handle(PyObject* self_, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
cv2_UMatWrapperObject* self = (cv2_UMatWrapperObject*)self_;
|
||||
if (self == NULL)
|
||||
return failmsgp("Incorrect type of self (must be 'cv2_UMatWrapperObject')");
|
||||
const char *kwlist[] = {"accessFlags", NULL};
|
||||
int accessFlags;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", (char**) kwlist, &accessFlags))
|
||||
@ -568,51 +587,60 @@ static PyObject * UMatWrapper_handle(cv2_UMatWrapperObject* self, PyObject *args
|
||||
}
|
||||
|
||||
// UMatWrapper.isContinuous() - returns true if the matrix data is continuous
|
||||
static PyObject * UMatWrapper_isContinuous(cv2_UMatWrapperObject* self)
|
||||
static PyObject * UMatWrapper_isContinuous(PyObject* self_, PyObject * /*args*/)
|
||||
{
|
||||
cv2_UMatWrapperObject* self = (cv2_UMatWrapperObject*)self_;
|
||||
if (self == NULL)
|
||||
return failmsgp("Incorrect type of self (must be 'cv2_UMatWrapperObject')");
|
||||
return PyBool_FromLong(self->um->isContinuous());
|
||||
}
|
||||
|
||||
// UMatWrapper.isContinuous() - returns true if the matrix is a submatrix of another matrix
|
||||
static PyObject * UMatWrapper_isSubmatrix(cv2_UMatWrapperObject* self)
|
||||
static PyObject * UMatWrapper_isSubmatrix(PyObject* self_, PyObject * /*args*/)
|
||||
{
|
||||
cv2_UMatWrapperObject* self = (cv2_UMatWrapperObject*)self_;
|
||||
if (self == NULL)
|
||||
return failmsgp("Incorrect type of self (must be 'cv2_UMatWrapperObject')");
|
||||
return PyBool_FromLong(self->um->isSubmatrix());
|
||||
}
|
||||
|
||||
// UMatWrapper.context() - returns the OpenCL context used by OpenCV UMat
|
||||
static PyObject * UMatWrapper_context(cv2_UMatWrapperObject*)
|
||||
static PyObject * UMatWrapper_context(PyObject* /*self_*/, PyObject * /*args*/)
|
||||
{
|
||||
return PyLong_FromVoidPtr(cv::ocl::Context::getDefault().ptr());
|
||||
}
|
||||
|
||||
// UMatWrapper.context() - returns the OpenCL queue used by OpenCV UMat
|
||||
static PyObject * UMatWrapper_queue(cv2_UMatWrapperObject*)
|
||||
static PyObject * UMatWrapper_queue(PyObject* /*self_*/, PyObject * /*args*/)
|
||||
{
|
||||
return PyLong_FromVoidPtr(cv::ocl::Queue::getDefault().ptr());
|
||||
}
|
||||
|
||||
static PyObject * UMatWrapper_offset_getter(cv2_UMatWrapperObject* self, void*)
|
||||
static PyObject * UMatWrapper_offset_getter(PyObject* self_, void*)
|
||||
{
|
||||
cv2_UMatWrapperObject* self = (cv2_UMatWrapperObject*)self_;
|
||||
if (self == NULL)
|
||||
return failmsgp("Incorrect type of self (must be 'cv2_UMatWrapperObject')");
|
||||
return PyLong_FromSsize_t(self->um->offset);
|
||||
}
|
||||
|
||||
static PyMethodDef UMatWrapper_methods[] = {
|
||||
{"get", (PyCFunction)UMatWrapper_get, METH_NOARGS,
|
||||
{"get", CV_PY_FN_NOARGS(UMatWrapper_get),
|
||||
"Returns numpy array"
|
||||
},
|
||||
{"handle", (PyCFunction)UMatWrapper_handle, METH_VARARGS | METH_KEYWORDS,
|
||||
{"handle", CV_PY_FN_WITH_KW(UMatWrapper_handle),
|
||||
"Returns UMat native handle"
|
||||
},
|
||||
{"isContinuous", (PyCFunction)UMatWrapper_isContinuous, METH_NOARGS,
|
||||
{"isContinuous", CV_PY_FN_NOARGS(UMatWrapper_isContinuous),
|
||||
"Returns true if the matrix data is continuous"
|
||||
},
|
||||
{"isSubmatrix", (PyCFunction)UMatWrapper_isSubmatrix, METH_NOARGS,
|
||||
{"isSubmatrix", CV_PY_FN_NOARGS(UMatWrapper_isSubmatrix),
|
||||
"Returns true if the matrix is a submatrix of another matrix"
|
||||
},
|
||||
{"context", (PyCFunction)UMatWrapper_context, METH_NOARGS | METH_STATIC,
|
||||
{"context", CV_PY_FN_NOARGS_(UMatWrapper_context, METH_STATIC),
|
||||
"Returns OpenCL context handle"
|
||||
},
|
||||
{"queue", (PyCFunction)UMatWrapper_queue, METH_NOARGS | METH_STATIC,
|
||||
{"queue", CV_PY_FN_NOARGS_(UMatWrapper_queue, METH_STATIC),
|
||||
"Returns OpenCL queue handle"
|
||||
},
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
@ -1778,15 +1806,15 @@ static int convert_to_char(PyObject *o, char *dst, const char *name = "no_name")
|
||||
#include "pyopencv_generated_funcs.h"
|
||||
|
||||
static PyMethodDef special_methods[] = {
|
||||
{"redirectError", (PyCFunction)pycvRedirectError, METH_VARARGS | METH_KEYWORDS, "redirectError(onError) -> None"},
|
||||
{"redirectError", CV_PY_FN_WITH_KW(pycvRedirectError), "redirectError(onError) -> None"},
|
||||
#ifdef HAVE_OPENCV_HIGHGUI
|
||||
{"createTrackbar", pycvCreateTrackbar, METH_VARARGS, "createTrackbar(trackbarName, windowName, value, count, onChange) -> None"},
|
||||
{"createButton", (PyCFunction)pycvCreateButton, METH_VARARGS | METH_KEYWORDS, "createButton(buttonName, onChange [, userData, buttonType, initialButtonState]) -> None"},
|
||||
{"setMouseCallback", (PyCFunction)pycvSetMouseCallback, METH_VARARGS | METH_KEYWORDS, "setMouseCallback(windowName, onMouse [, param]) -> None"},
|
||||
{"createTrackbar", (PyCFunction)pycvCreateTrackbar, METH_VARARGS, "createTrackbar(trackbarName, windowName, value, count, onChange) -> None"},
|
||||
{"createButton", CV_PY_FN_WITH_KW(pycvCreateButton), "createButton(buttonName, onChange [, userData, buttonType, initialButtonState]) -> None"},
|
||||
{"setMouseCallback", CV_PY_FN_WITH_KW(pycvSetMouseCallback), "setMouseCallback(windowName, onMouse [, param]) -> None"},
|
||||
#endif
|
||||
#ifdef HAVE_OPENCV_DNN
|
||||
{"dnn_registerLayer", (PyCFunction)pyopencv_cv_dnn_registerLayer, METH_VARARGS | METH_KEYWORDS, "registerLayer(type, class) -> None"},
|
||||
{"dnn_unregisterLayer", (PyCFunction)pyopencv_cv_dnn_unregisterLayer, METH_VARARGS | METH_KEYWORDS, "unregisterLayer(type) -> None"},
|
||||
{"dnn_registerLayer", CV_PY_FN_WITH_KW(pyopencv_cv_dnn_registerLayer), "registerLayer(type, class) -> None"},
|
||||
{"dnn_unregisterLayer", CV_PY_FN_WITH_KW(pyopencv_cv_dnn_unregisterLayer), "unregisterLayer(type) -> None"},
|
||||
#endif
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
@ -599,13 +599,9 @@ class FuncInfo(object):
|
||||
# Convert unicode chars to xml representation, but keep as string instead of bytes
|
||||
full_docstring = full_docstring.encode('ascii', errors='xmlcharrefreplace').decode()
|
||||
|
||||
flags = ["METH_VARARGS", "METH_KEYWORDS"]
|
||||
if self.isclassmethod:
|
||||
flags.append("METH_CLASS")
|
||||
|
||||
return Template(' {"$py_funcname", (PyCFunction)$wrap_funcname, $flags, "$py_docstring"},\n'
|
||||
return Template(' {"$py_funcname", CV_PY_FN_WITH_KW_($wrap_funcname, $flags), "$py_docstring"},\n'
|
||||
).substitute(py_funcname = self.variants[0].wname, wrap_funcname=self.get_wrapper_name(),
|
||||
flags = " | ".join(flags), py_docstring = full_docstring)
|
||||
flags = 'METH_CLASS' if self.isclassmethod else '0', py_docstring = full_docstring)
|
||||
|
||||
def gen_code(self, codegen):
|
||||
all_classes = codegen.classes
|
||||
|
@ -23,7 +23,7 @@ class Bindings(NewOpenCVTests):
|
||||
try:
|
||||
cv.imshow("", None) # This causes an assert
|
||||
self.assertEqual("Dead code", 0)
|
||||
except cv.error as e:
|
||||
except cv.error as _e:
|
||||
pass
|
||||
|
||||
handler_called = [False]
|
||||
@ -34,7 +34,7 @@ class Bindings(NewOpenCVTests):
|
||||
try:
|
||||
cv.imshow("", None) # This causes an assert
|
||||
self.assertEqual("Dead code", 0)
|
||||
except cv.error as e:
|
||||
except cv.error as _e:
|
||||
self.assertEqual(handler_called[0], True)
|
||||
pass
|
||||
|
||||
@ -42,7 +42,7 @@ class Bindings(NewOpenCVTests):
|
||||
try:
|
||||
cv.imshow("", None) # This causes an assert
|
||||
self.assertEqual("Dead code", 0)
|
||||
except cv.error as e:
|
||||
except cv.error as _e:
|
||||
pass
|
||||
|
||||
|
||||
|
@ -11539,12 +11539,15 @@ typename ParamNameGenFunc<ParamType>::Type *GetParamNameGen() {
|
||||
return DefaultParamName;
|
||||
}
|
||||
|
||||
} // namespace internal:: // fixes MacOS X issue with "friend class internal/*::anon*/::ParameterizedTestFactory;"
|
||||
namespace { // wrap into anynomous namespace to avoid build warnings like GCC's -Wsubobject-linkage
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Stores a parameter value and later creates tests parameterized with that
|
||||
// value.
|
||||
template <class TestClass>
|
||||
class ParameterizedTestFactory : public TestFactoryBase {
|
||||
class ParameterizedTestFactory : public internal::TestFactoryBase {
|
||||
public:
|
||||
typedef typename TestClass::ParamType ParamType;
|
||||
explicit ParameterizedTestFactory(ParamType parameter) :
|
||||
@ -11559,6 +11562,8 @@ class ParameterizedTestFactory : public TestFactoryBase {
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory);
|
||||
};
|
||||
} // namespace
|
||||
namespace internal {
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
@ -20405,6 +20410,12 @@ class GTEST_API_ AssertHelper {
|
||||
} // namespace internal
|
||||
|
||||
#if GTEST_HAS_PARAM_TEST
|
||||
|
||||
namespace internal {
|
||||
// Static value used for accessing test parameter during a test lifetime.
|
||||
extern void* g_parameter_;
|
||||
} // namespace internal
|
||||
|
||||
// The pure interface class that all value-parameterized tests inherit from.
|
||||
// A value-parameterized class must inherit from both ::testing::Test and
|
||||
// ::testing::WithParamInterface. In most cases that just means inheriting
|
||||
@ -20451,29 +20462,28 @@ class WithParamInterface {
|
||||
// like writing 'WithParamInterface<bool>::GetParam()' for a test that
|
||||
// uses a fixture whose parameter type is int.
|
||||
const ParamType& GetParam() const {
|
||||
GTEST_CHECK_(parameter_ != NULL)
|
||||
GTEST_CHECK_(GetParameterPtrRef_() != NULL)
|
||||
<< "GetParam() can only be called inside a value-parameterized test "
|
||||
<< "-- did you intend to write TEST_P instead of TEST_F?";
|
||||
return *parameter_;
|
||||
return *GetParameterPtrRef_();
|
||||
}
|
||||
|
||||
private:
|
||||
// Sets parameter value. The caller is responsible for making sure the value
|
||||
// remains alive and unchanged throughout the current test.
|
||||
static void SetParam(const ParamType* parameter) {
|
||||
parameter_ = parameter;
|
||||
GetParameterPtrRef_() = parameter;
|
||||
}
|
||||
|
||||
// Static value used for accessing parameter during a test lifetime.
|
||||
static const ParamType* parameter_;
|
||||
static const ParamType*& GetParameterPtrRef_()
|
||||
{
|
||||
return (const ParamType*&)internal::g_parameter_;
|
||||
}
|
||||
|
||||
// TestClass must be a subclass of WithParamInterface<T> and Test.
|
||||
template <class TestClass> friend class internal::ParameterizedTestFactory;
|
||||
template <class TestClass> friend class /*internal::*/ParameterizedTestFactory;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
const T* WithParamInterface<T>::parameter_ = NULL;
|
||||
|
||||
// Most value-parameterized classes can ignore the existence of
|
||||
// WithParamInterface, and can just inherit from ::testing::TestWithParam.
|
||||
|
||||
|
@ -10441,5 +10441,7 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames(
|
||||
|
||||
#endif // GTEST_HAS_TYPED_TEST_P
|
||||
|
||||
void* g_parameter_ = NULL;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
@ -20,6 +20,8 @@ set(videoio_hdrs
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/precomp.hpp
|
||||
)
|
||||
set(videoio_srcs
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/videoio_registry.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/videoio_c.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/cap.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/cap_images.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/cap_mjpeg_encoder.cpp
|
||||
@ -165,6 +167,9 @@ if(HAVE_FFMPEG)
|
||||
if(APPLE)
|
||||
list(APPEND VIDEOIO_LIBRARIES "-framework VideoDecodeAcceleration" bz2)
|
||||
endif()
|
||||
if(HAVE_FFMPEG_WRAPPER)
|
||||
add_definitions(-DHAVE_FFMPEG_WRAPPER=1)
|
||||
endif()
|
||||
endif(HAVE_FFMPEG)
|
||||
|
||||
if(HAVE_PVAPI)
|
||||
@ -234,12 +239,6 @@ if(IOS)
|
||||
list(APPEND VIDEOIO_LIBRARIES "-framework Accelerate" "-framework AVFoundation" "-framework CoreGraphics" "-framework CoreImage" "-framework CoreMedia" "-framework CoreVideo" "-framework QuartzCore" "-framework UIKit")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
link_directories("${OpenCV_SOURCE_DIR}/3rdparty/lib") # for ffmpeg wrapper only
|
||||
include_directories(AFTER SYSTEM "${OpenCV_SOURCE_DIR}/3rdparty/include") # for directshow in VS2005 and multi-monitor support on MinGW
|
||||
include_directories(AFTER SYSTEM "${OpenCV_SOURCE_DIR}/3rdparty/include/ffmpeg_") # for tests
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
#these variables are set by CHECK_MODULE macro
|
||||
foreach(P ${VIDEOIO_INCLUDE_DIRS})
|
||||
@ -272,7 +271,7 @@ endif()
|
||||
|
||||
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-deprecated-declarations)
|
||||
|
||||
if(WIN32 AND HAVE_FFMPEG)
|
||||
if(WIN32 AND HAVE_FFMPEG_WRAPPER)
|
||||
#copy ffmpeg dll to the output folder
|
||||
if(MSVC64 OR MINGW64)
|
||||
set(FFMPEG_SUFFIX _64)
|
||||
|
@ -40,40 +40,10 @@
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
#include "cap_intelperc.hpp"
|
||||
#include "cap_librealsense.hpp"
|
||||
#include "cap_dshow.hpp"
|
||||
|
||||
#ifdef HAVE_MFX
|
||||
#include "cap_mfx_reader.hpp"
|
||||
#include "cap_mfx_writer.hpp"
|
||||
#endif
|
||||
#include "videoio_registry.hpp"
|
||||
|
||||
// All WinRT versions older than 8.0 should provide classes used for video support
|
||||
#if defined(WINRT) && !defined(WINRT_8_0) && defined(__cplusplus_winrt)
|
||||
# include "cap_winrt_capture.hpp"
|
||||
# include "cap_winrt_bridge.hpp"
|
||||
# define WINRT_VIDEO
|
||||
#endif
|
||||
|
||||
#if defined _M_X64 && defined _MSC_VER && !defined CV_ICC
|
||||
#pragma optimize("",off)
|
||||
#pragma warning(disable: 4748)
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#endif
|
||||
#if defined(__GNUC__) && __GNUC__ >= 7
|
||||
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#endif
|
||||
|
||||
using namespace cv;
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace cv {
|
||||
|
||||
template<> void DefaultDeleter<CvCapture>::operator ()(CvCapture* obj) const
|
||||
{ cvReleaseCapture(&obj); }
|
||||
@ -81,536 +51,7 @@ template<> void DefaultDeleter<CvCapture>::operator ()(CvCapture* obj) const
|
||||
template<> void DefaultDeleter<CvVideoWriter>::operator ()(CvVideoWriter* obj) const
|
||||
{ cvReleaseVideoWriter(&obj); }
|
||||
|
||||
}
|
||||
|
||||
/************************* Reading AVIs & Camera data **************************/
|
||||
|
||||
static inline double icvGetCaptureProperty( const CvCapture* capture, int id )
|
||||
{
|
||||
return capture ? capture->getProperty(id) : 0;
|
||||
}
|
||||
|
||||
CV_IMPL void cvReleaseCapture( CvCapture** pcapture )
|
||||
{
|
||||
if( pcapture && *pcapture )
|
||||
{
|
||||
delete *pcapture;
|
||||
*pcapture = 0;
|
||||
}
|
||||
}
|
||||
|
||||
CV_IMPL IplImage* cvQueryFrame( CvCapture* capture )
|
||||
{
|
||||
if(!capture)
|
||||
return 0;
|
||||
if(!capture->grabFrame())
|
||||
return 0;
|
||||
return capture->retrieveFrame(0);
|
||||
}
|
||||
|
||||
|
||||
CV_IMPL int cvGrabFrame( CvCapture* capture )
|
||||
{
|
||||
return capture ? capture->grabFrame() : 0;
|
||||
}
|
||||
|
||||
CV_IMPL IplImage* cvRetrieveFrame( CvCapture* capture, int idx )
|
||||
{
|
||||
return capture ? capture->retrieveFrame(idx) : 0;
|
||||
}
|
||||
|
||||
CV_IMPL double cvGetCaptureProperty( CvCapture* capture, int id )
|
||||
{
|
||||
return icvGetCaptureProperty(capture, id);
|
||||
}
|
||||
|
||||
CV_IMPL int cvSetCaptureProperty( CvCapture* capture, int id, double value )
|
||||
{
|
||||
return capture ? capture->setProperty(id, value) : 0;
|
||||
}
|
||||
|
||||
CV_IMPL int cvGetCaptureDomain( CvCapture* capture)
|
||||
{
|
||||
return capture ? capture->getCaptureDomain() : 0;
|
||||
}
|
||||
|
||||
static bool get_capture_debug_flag()
|
||||
{
|
||||
static bool initialized = false;
|
||||
static bool flag = false;
|
||||
if (!initialized)
|
||||
{
|
||||
#ifndef NO_GETENV
|
||||
flag = getenv("OPENCV_VIDEOCAPTURE_DEBUG") ? true : false; // TODO Use getBoolParameter
|
||||
#endif
|
||||
initialized = true;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
#define TRY_OPEN(capture, backend_func) \
|
||||
{ \
|
||||
if (!capture) \
|
||||
CV_TRY { \
|
||||
if (get_capture_debug_flag()) fprintf(stderr, "VIDEOIO(%s): trying ...\n", #backend_func); \
|
||||
capture = backend_func; \
|
||||
if (get_capture_debug_flag()) fprintf(stderr, "VIDEOIO(%s): result=%p ...\n", #backend_func, capture); \
|
||||
} CV_CATCH (cv::Exception, e) { \
|
||||
fprintf(stderr, "VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", #backend_func, e.what()); \
|
||||
} CV_CATCH (std::exception, e) { \
|
||||
fprintf(stderr, "VIDEOIO(%s): raised C++ exception:\n\n%s\n", #backend_func, e.what()); \
|
||||
} CV_CATCH_ALL { \
|
||||
fprintf(stderr, "VIDEOIO(%s): raised unknown C++ exception!\n\n", #backend_func); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Camera dispatching method: index is the camera number.
|
||||
* If given an index from 0 to 99, it tries to find the first
|
||||
* API that can access a given camera index.
|
||||
* Add multiples of 100 to select an API.
|
||||
*/
|
||||
CV_IMPL CvCapture * cvCreateCameraCapture (int index)
|
||||
{
|
||||
// interpret preferred interface (0 = autodetect)
|
||||
int pref = (index / 100) * 100;
|
||||
|
||||
// remove pref from index
|
||||
index -= pref;
|
||||
|
||||
// local variable to memorize the captured device
|
||||
CvCapture *capture = 0;
|
||||
|
||||
switch (pref)
|
||||
{
|
||||
default:
|
||||
// user specified an API we do not know
|
||||
// bail out to let the user know that it is not available
|
||||
if (pref) break;
|
||||
|
||||
case CAP_VFW: // or CAP_V4L or CAP_V4L2
|
||||
#ifdef HAVE_VFW
|
||||
TRY_OPEN(capture, cvCreateCameraCapture_VFW(index))
|
||||
#endif
|
||||
|
||||
#if defined HAVE_LIBV4L || defined HAVE_CAMV4L || defined HAVE_CAMV4L2 || defined HAVE_VIDEOIO
|
||||
TRY_OPEN(capture, cvCreateCameraCapture_V4L(index))
|
||||
#endif
|
||||
|
||||
if (pref) break; // CAP_VFW or CAP_V4L or CAP_V4L2
|
||||
|
||||
case CAP_FIREWIRE:
|
||||
#ifdef HAVE_DC1394_2
|
||||
TRY_OPEN(capture, cvCreateCameraCapture_DC1394_2(index))
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DC1394
|
||||
TRY_OPEN(capture, cvCreateCameraCapture_DC1394(index))
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CMU1394
|
||||
TRY_OPEN(capture, cvCreateCameraCapture_CMU(index))
|
||||
#endif
|
||||
|
||||
if (pref) break; // CAP_FIREWIRE
|
||||
|
||||
#ifdef HAVE_MIL
|
||||
case CAP_MIL:
|
||||
TRY_OPEN(capture, cvCreateCameraCapture_MIL(index))
|
||||
if (pref) break;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT)
|
||||
case CAP_QT:
|
||||
TRY_OPEN(capture, cvCreateCameraCapture_QT(index))
|
||||
if (pref) break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNICAP
|
||||
case CAP_UNICAP:
|
||||
TRY_OPEN(capture, cvCreateCameraCapture_Unicap(index))
|
||||
if (pref) break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PVAPI
|
||||
case CAP_PVAPI:
|
||||
TRY_OPEN(capture, cvCreateCameraCapture_PvAPI(index))
|
||||
if (pref) break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENNI
|
||||
case CAP_OPENNI:
|
||||
TRY_OPEN(capture, cvCreateCameraCapture_OpenNI(index))
|
||||
if (pref) break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENNI2
|
||||
case CAP_OPENNI2:
|
||||
TRY_OPEN(capture, cvCreateCameraCapture_OpenNI2(index))
|
||||
if (pref) break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_XIMEA
|
||||
case CAP_XIAPI:
|
||||
TRY_OPEN(capture, cvCreateCameraCapture_XIMEA(index))
|
||||
if (pref) break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_AVFOUNDATION
|
||||
case CAP_AVFOUNDATION:
|
||||
TRY_OPEN(capture, cvCreateCameraCapture_AVFoundation(index))
|
||||
if (pref) break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GIGE_API
|
||||
case CAP_GIGANETIX:
|
||||
TRY_OPEN(capture, cvCreateCameraCapture_Giganetix(index))
|
||||
if (pref) break; // CAP_GIGANETIX
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARAVIS_API
|
||||
case CAP_ARAVIS:
|
||||
TRY_OPEN(capture, cvCreateCameraCapture_Aravis(index))
|
||||
if (pref) break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return capture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Videoreader dispatching method: it tries to find the first
|
||||
* API that can access a given filename.
|
||||
*/
|
||||
CV_IMPL CvCapture * cvCreateFileCaptureWithPreference (const char * filename, int apiPreference)
|
||||
{
|
||||
CvCapture * result = 0;
|
||||
|
||||
switch(apiPreference) {
|
||||
default:
|
||||
// user specified an API we do not know
|
||||
// bail out to let the user know that it is not available
|
||||
if (apiPreference) break;
|
||||
|
||||
#if defined HAVE_LIBV4L || defined HAVE_CAMV4L || defined HAVE_CAMV4L2 || defined HAVE_VIDEOIO
|
||||
case CAP_V4L:
|
||||
TRY_OPEN(result, cvCreateCameraCapture_V4L(filename))
|
||||
if (apiPreference) break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VFW
|
||||
case CAP_VFW:
|
||||
TRY_OPEN(result, cvCreateFileCapture_VFW (filename))
|
||||
if (apiPreference) break;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT)
|
||||
case CAP_QT:
|
||||
TRY_OPEN(result, cvCreateFileCapture_QT (filename))
|
||||
if (apiPreference) break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_AVFOUNDATION
|
||||
case CAP_AVFOUNDATION:
|
||||
TRY_OPEN(result, cvCreateFileCapture_AVFoundation (filename))
|
||||
if (apiPreference) break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENNI
|
||||
case CAP_OPENNI:
|
||||
TRY_OPEN(result, cvCreateFileCapture_OpenNI (filename))
|
||||
if (apiPreference) break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENNI2
|
||||
case CAP_OPENNI2:
|
||||
TRY_OPEN(result, cvCreateFileCapture_OpenNI2 (filename))
|
||||
if (apiPreference) break;
|
||||
#endif
|
||||
#ifdef HAVE_XIMEA
|
||||
case CAP_XIAPI:
|
||||
TRY_OPEN(result, cvCreateCameraCapture_XIMEA(filename))
|
||||
if (apiPreference) break;
|
||||
#endif
|
||||
case CAP_IMAGES:
|
||||
TRY_OPEN(result, cvCreateFileCapture_Images (filename))
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CV_IMPL CvCapture * cvCreateFileCapture (const char * filename)
|
||||
{
|
||||
return cvCreateFileCaptureWithPreference(filename, CAP_ANY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Videowriter dispatching method: it tries to find the first
|
||||
* API that can write a given stream.
|
||||
*/
|
||||
static CvVideoWriter* cvCreateVideoWriterWithPreference(const char* filename, int apiPreference, int fourcc,
|
||||
double fps, CvSize frameSize, int is_color )
|
||||
{
|
||||
CV_UNUSED(frameSize);
|
||||
CV_UNUSED(is_color);
|
||||
|
||||
CvVideoWriter *result = 0;
|
||||
|
||||
if(!fourcc || !fps)
|
||||
TRY_OPEN(result, cvCreateVideoWriter_Images(filename))
|
||||
|
||||
CV_Assert(result || fps != 0);
|
||||
|
||||
switch(apiPreference)
|
||||
{
|
||||
default:
|
||||
//exit if the specified API is unavaliable
|
||||
if (apiPreference != CAP_ANY) break;
|
||||
#ifdef HAVE_VFW
|
||||
case CAP_VFW:
|
||||
TRY_OPEN(result, cvCreateVideoWriter_VFW(filename, fourcc, fps, frameSize, is_color))
|
||||
if (apiPreference != CAP_ANY) break;
|
||||
#endif
|
||||
#ifdef HAVE_AVFOUNDATION
|
||||
case CAP_AVFOUNDATION:
|
||||
TRY_OPEN(result, cvCreateVideoWriter_AVFoundation(filename, fourcc, fps, frameSize, is_color))
|
||||
if (apiPreference != CAP_ANY) break;
|
||||
#endif
|
||||
#if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT)
|
||||
case(CAP_QT):
|
||||
TRY_OPEN(result, cvCreateVideoWriter_QT(filename, fourcc, fps, frameSize, is_color))
|
||||
if (apiPreference != CAP_ANY) break;
|
||||
#endif
|
||||
#ifdef HAVE_GSTREAMER
|
||||
case CAP_GSTREAMER:
|
||||
TRY_OPEN(result, cvCreateVideoWriter_GStreamer (filename, fourcc, fps, frameSize, is_color))
|
||||
if (apiPreference != CAP_ANY) break;
|
||||
#endif
|
||||
case CAP_IMAGES:
|
||||
TRY_OPEN(result, cvCreateVideoWriter_Images(filename))
|
||||
if (apiPreference != CAP_ANY) break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CV_IMPL CvVideoWriter* cvCreateVideoWriter( const char* filename, int fourcc,
|
||||
double fps, CvSize frameSize, int is_color )
|
||||
{
|
||||
return cvCreateVideoWriterWithPreference(filename, CAP_ANY, fourcc, fps, frameSize, is_color);
|
||||
}
|
||||
|
||||
CV_IMPL int cvWriteFrame( CvVideoWriter* writer, const IplImage* image )
|
||||
{
|
||||
return writer ? writer->writeFrame(image) : 0;
|
||||
}
|
||||
|
||||
CV_IMPL void cvReleaseVideoWriter( CvVideoWriter** pwriter )
|
||||
{
|
||||
if( pwriter && *pwriter )
|
||||
{
|
||||
delete *pwriter;
|
||||
*pwriter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
static Ptr<IVideoCapture> IVideoCapture_create(int index)
|
||||
{
|
||||
int domains[] =
|
||||
{
|
||||
#ifdef HAVE_GSTREAMER
|
||||
CAP_GSTREAMER,
|
||||
#endif
|
||||
#ifdef HAVE_MSMF
|
||||
CAP_MSMF,
|
||||
#endif
|
||||
#ifdef HAVE_DSHOW
|
||||
CAP_DSHOW,
|
||||
#endif
|
||||
#ifdef HAVE_INTELPERC
|
||||
CAP_INTELPERC,
|
||||
#endif
|
||||
#ifdef WINRT_VIDEO
|
||||
CAP_WINRT,
|
||||
#endif
|
||||
#ifdef HAVE_GPHOTO2
|
||||
CAP_GPHOTO2,
|
||||
#endif
|
||||
-1, -1
|
||||
};
|
||||
|
||||
// interpret preferred interface (0 = autodetect)
|
||||
int pref = (index / 100) * 100;
|
||||
if (pref)
|
||||
{
|
||||
domains[0]=pref;
|
||||
index %= 100;
|
||||
domains[1]=-1;
|
||||
}
|
||||
|
||||
// try every possibly installed camera API
|
||||
for (int i = 0; domains[i] >= 0; i++)
|
||||
{
|
||||
#if defined(HAVE_GSTREAMER) || \
|
||||
defined(HAVE_MSMF) || \
|
||||
defined(HAVE_DSHOW) || \
|
||||
defined(HAVE_INTELPERC) || \
|
||||
defined(HAVE_LIBREALSENSE) || \
|
||||
defined(WINRT_VIDEO) || \
|
||||
defined(HAVE_GPHOTO2) || \
|
||||
(0)
|
||||
Ptr<IVideoCapture> capture;
|
||||
|
||||
switch (domains[i])
|
||||
{
|
||||
#ifdef HAVE_GSTREAMER
|
||||
case CAP_GSTREAMER:
|
||||
capture = createGStreamerCapture(index);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_MSMF
|
||||
case CAP_MSMF:
|
||||
capture = cvCreateCapture_MSMF(index);
|
||||
break; // CAP_MSMF
|
||||
#endif
|
||||
#ifdef HAVE_DSHOW
|
||||
case CAP_DSHOW:
|
||||
capture = makePtr<VideoCapture_DShow>(index);
|
||||
break; // CAP_DSHOW
|
||||
#endif
|
||||
#ifdef HAVE_INTELPERC
|
||||
case CAP_INTELPERC:
|
||||
capture = makePtr<VideoCapture_IntelPerC>();
|
||||
break; // CAP_INTEL_PERC
|
||||
#elif defined(HAVE_LIBREALSENSE)
|
||||
case CAP_INTELPERC:
|
||||
capture = makePtr<VideoCapture_LibRealsense>(index);
|
||||
break;
|
||||
#endif
|
||||
#ifdef WINRT_VIDEO
|
||||
case CAP_WINRT:
|
||||
capture = Ptr<IVideoCapture>(new cv::VideoCapture_WinRT(index));
|
||||
if (capture)
|
||||
return capture;
|
||||
break; // CAP_WINRT
|
||||
#endif
|
||||
#ifdef HAVE_GPHOTO2
|
||||
case CAP_GPHOTO2:
|
||||
capture = createGPhoto2Capture(index);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
if (capture && capture->isOpened())
|
||||
return capture;
|
||||
#endif
|
||||
}
|
||||
|
||||
// failed open a camera
|
||||
return Ptr<IVideoCapture>();
|
||||
}
|
||||
|
||||
|
||||
static Ptr<IVideoCapture> IVideoCapture_create(const String& filename, int apiPreference)
|
||||
{
|
||||
bool useAny = (apiPreference == CAP_ANY);
|
||||
Ptr<IVideoCapture> capture;
|
||||
#ifdef HAVE_FFMPEG
|
||||
if (useAny || apiPreference == CAP_FFMPEG)
|
||||
{
|
||||
capture = cvCreateFileCapture_FFMPEG_proxy(filename);
|
||||
if (capture && capture->isOpened())
|
||||
return capture;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_GSTREAMER
|
||||
if (useAny || apiPreference == CAP_GSTREAMER)
|
||||
{
|
||||
capture = createGStreamerCapture(filename);
|
||||
if (capture && capture->isOpened())
|
||||
return capture;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_XINE
|
||||
if (useAny || apiPreference == CAP_XINE)
|
||||
{
|
||||
capture = createXINECapture(filename.c_str());
|
||||
if (capture && capture->isOpened())
|
||||
return capture;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_MSMF
|
||||
if (useAny || apiPreference == CAP_MSMF)
|
||||
{
|
||||
capture = cvCreateCapture_MSMF(filename);
|
||||
if (capture && capture->isOpened())
|
||||
return capture;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_GPHOTO2
|
||||
if (useAny || apiPreference == CAP_GPHOTO2)
|
||||
{
|
||||
capture = createGPhoto2Capture(filename);
|
||||
if (capture && capture->isOpened())
|
||||
return capture;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_MFX
|
||||
if (useAny || apiPreference == CAP_INTEL_MFX)
|
||||
{
|
||||
capture = makePtr<VideoCapture_IntelMFX>(filename);
|
||||
if (capture && capture->isOpened())
|
||||
return capture;
|
||||
}
|
||||
#endif
|
||||
if (useAny || apiPreference == CAP_OPENCV_MJPEG)
|
||||
{
|
||||
capture = createMotionJpegCapture(filename);
|
||||
if (capture && capture->isOpened())
|
||||
return capture;
|
||||
}
|
||||
if (capture && !capture->isOpened())
|
||||
capture.release();
|
||||
return capture;
|
||||
}
|
||||
|
||||
static Ptr<IVideoWriter> IVideoWriter_create(const String& filename, int apiPreference, int _fourcc, double fps, Size frameSize, bool isColor)
|
||||
{
|
||||
Ptr<IVideoWriter> iwriter;
|
||||
#ifdef HAVE_FFMPEG
|
||||
if (apiPreference == CAP_FFMPEG || apiPreference == CAP_ANY)
|
||||
{
|
||||
iwriter = cvCreateVideoWriter_FFMPEG_proxy(filename, _fourcc, fps, frameSize, isColor);
|
||||
if (!iwriter.empty())
|
||||
return iwriter;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_MSMF
|
||||
if (apiPreference == CAP_MSMF || apiPreference == CAP_ANY)
|
||||
{
|
||||
iwriter = cvCreateVideoWriter_MSMF(filename, _fourcc, fps, frameSize, isColor);
|
||||
if (!iwriter.empty())
|
||||
return iwriter;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_MFX
|
||||
if (apiPreference == CAP_INTEL_MFX || apiPreference == CAP_ANY)
|
||||
{
|
||||
iwriter = VideoWriter_IntelMFX::create(filename, _fourcc, fps, frameSize, isColor);
|
||||
if (!iwriter.empty())
|
||||
return iwriter;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( (apiPreference == CAP_OPENCV_MJPEG || apiPreference == CAP_ANY)
|
||||
&& _fourcc == CV_FOURCC('M', 'J', 'P', 'G') )
|
||||
iwriter = createMotionJpegWriter(filename, fps, frameSize, isColor);
|
||||
|
||||
return iwriter;
|
||||
}
|
||||
|
||||
VideoCapture::VideoCapture()
|
||||
{}
|
||||
@ -646,12 +87,30 @@ bool VideoCapture::open(const String& filename, int apiPreference)
|
||||
CV_TRACE_FUNCTION();
|
||||
|
||||
if (isOpened()) release();
|
||||
icap = IVideoCapture_create(filename, apiPreference);
|
||||
if (!icap.empty())
|
||||
return true;
|
||||
|
||||
cap.reset(cvCreateFileCaptureWithPreference(filename.c_str(), apiPreference));
|
||||
return isOpened();
|
||||
const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_CaptureByFilename();
|
||||
for (size_t i = 0; i < backends.size(); i++)
|
||||
{
|
||||
const VideoBackendInfo& info = backends[i];
|
||||
if (apiPreference == CAP_ANY || apiPreference == info.id)
|
||||
{
|
||||
CvCapture* capture = NULL;
|
||||
VideoCapture_create(capture, icap, info.id, filename);
|
||||
if (!icap.empty())
|
||||
{
|
||||
if (icap->isOpened())
|
||||
return true;
|
||||
icap.release();
|
||||
}
|
||||
if (capture)
|
||||
{
|
||||
cap.reset(capture);
|
||||
// assume it is opened
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VideoCapture::open(const String& filename)
|
||||
@ -661,28 +120,56 @@ bool VideoCapture::open(const String& filename)
|
||||
return open(filename, CAP_ANY);
|
||||
}
|
||||
|
||||
bool VideoCapture::open(int index)
|
||||
{
|
||||
CV_TRACE_FUNCTION();
|
||||
|
||||
if (isOpened()) release();
|
||||
icap = IVideoCapture_create(index);
|
||||
if (!icap.empty())
|
||||
return true;
|
||||
cap.reset(cvCreateCameraCapture(index));
|
||||
return isOpened();
|
||||
}
|
||||
bool VideoCapture::open(int cameraNum, int apiPreference)
|
||||
{
|
||||
CV_TRACE_FUNCTION();
|
||||
|
||||
cameraNum = cameraNum + apiPreference;
|
||||
return open(cameraNum);
|
||||
if (isOpened()) release();
|
||||
|
||||
const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_CaptureByIndex();
|
||||
for (size_t i = 0; i < backends.size(); i++)
|
||||
{
|
||||
const VideoBackendInfo& info = backends[i];
|
||||
if (apiPreference == CAP_ANY || apiPreference == info.id)
|
||||
{
|
||||
CvCapture* capture = NULL;
|
||||
VideoCapture_create(capture, icap, info.id, cameraNum);
|
||||
if (!icap.empty())
|
||||
{
|
||||
if (icap->isOpened())
|
||||
return true;
|
||||
icap.release();
|
||||
}
|
||||
if (capture)
|
||||
{
|
||||
cap.reset(capture);
|
||||
// assume it is opened
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VideoCapture::open(int index)
|
||||
{
|
||||
CV_TRACE_FUNCTION();
|
||||
|
||||
// interpret preferred interface (0 = autodetect)
|
||||
int backendID = (index / 100) * 100;
|
||||
if (backendID)
|
||||
{
|
||||
index %= 100;
|
||||
}
|
||||
|
||||
return open(index, backendID);
|
||||
}
|
||||
|
||||
bool VideoCapture::isOpened() const
|
||||
{
|
||||
return (!cap.empty() || !icap.empty());
|
||||
if (!icap.empty())
|
||||
return icap->isOpened();
|
||||
return !cap.empty(); // legacy interface doesn't support closed files
|
||||
}
|
||||
|
||||
void VideoCapture::release()
|
||||
@ -738,6 +225,7 @@ bool VideoCapture::read(OutputArray image)
|
||||
VideoCapture& VideoCapture::operator >> (Mat& image)
|
||||
{
|
||||
#ifdef WINRT_VIDEO
|
||||
// FIXIT grab/retrieve methods() should work too
|
||||
if (grab())
|
||||
{
|
||||
if (retrieve(image))
|
||||
@ -759,7 +247,6 @@ VideoCapture& VideoCapture::operator >> (Mat& image)
|
||||
#else
|
||||
read(image);
|
||||
#endif
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -782,10 +269,14 @@ double VideoCapture::get(int propId) const
|
||||
{
|
||||
if (!icap.empty())
|
||||
return icap->getProperty(propId);
|
||||
return icvGetCaptureProperty(cap, propId);
|
||||
return cap ? cap->getProperty(propId) : 0;
|
||||
}
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
|
||||
|
||||
VideoWriter::VideoWriter()
|
||||
{}
|
||||
|
||||
@ -821,11 +312,30 @@ bool VideoWriter::open(const String& filename, int apiPreference, int _fourcc, d
|
||||
CV_INSTRUMENT_REGION()
|
||||
|
||||
if (isOpened()) release();
|
||||
iwriter = IVideoWriter_create(filename, apiPreference, _fourcc, fps, frameSize, isColor);
|
||||
if (!iwriter.empty())
|
||||
return true;
|
||||
writer.reset(cvCreateVideoWriterWithPreference(filename.c_str(), apiPreference, _fourcc, fps, frameSize, isColor));
|
||||
return isOpened();
|
||||
|
||||
const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_Writer();
|
||||
for (size_t i = 0; i < backends.size(); i++)
|
||||
{
|
||||
const VideoBackendInfo& info = backends[i];
|
||||
if (apiPreference == CAP_ANY || apiPreference == info.id)
|
||||
{
|
||||
CvVideoWriter* writer_ = NULL;
|
||||
VideoWriter_create(writer_, iwriter, info.id, filename, _fourcc, fps, frameSize, isColor);
|
||||
if (!iwriter.empty())
|
||||
{
|
||||
if (iwriter->isOpened())
|
||||
return true;
|
||||
iwriter.release();
|
||||
}
|
||||
if (writer_)
|
||||
{
|
||||
// assume it is opened
|
||||
writer.reset(writer_);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VideoWriter::isOpened() const
|
||||
@ -869,9 +379,10 @@ VideoWriter& VideoWriter::operator << (const Mat& image)
|
||||
return *this;
|
||||
}
|
||||
|
||||
// FIXIT OpenCV 4.0: make inline
|
||||
int VideoWriter::fourcc(char c1, char c2, char c3, char c4)
|
||||
{
|
||||
return (c1 & 255) + ((c2 & 255) << 8) + ((c3 & 255) << 16) + ((c4 & 255) << 24);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
@ -41,13 +41,28 @@
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#if defined(HAVE_FFMPEG)
|
||||
|
||||
#include <string>
|
||||
|
||||
#if defined HAVE_FFMPEG && !defined _WIN32
|
||||
#if !defined(HAVE_FFMPEG_WRAPPER)
|
||||
#include "cap_ffmpeg_impl.hpp"
|
||||
|
||||
#define icvCreateFileCapture_FFMPEG_p cvCreateFileCapture_FFMPEG
|
||||
#define icvReleaseCapture_FFMPEG_p cvReleaseCapture_FFMPEG
|
||||
#define icvGrabFrame_FFMPEG_p cvGrabFrame_FFMPEG
|
||||
#define icvRetrieveFrame_FFMPEG_p cvRetrieveFrame_FFMPEG
|
||||
#define icvSetCaptureProperty_FFMPEG_p cvSetCaptureProperty_FFMPEG
|
||||
#define icvGetCaptureProperty_FFMPEG_p cvGetCaptureProperty_FFMPEG
|
||||
#define icvCreateVideoWriter_FFMPEG_p cvCreateVideoWriter_FFMPEG
|
||||
#define icvReleaseVideoWriter_FFMPEG_p cvReleaseVideoWriter_FFMPEG
|
||||
#define icvWriteFrame_FFMPEG_p cvWriteFrame_FFMPEG
|
||||
|
||||
#else
|
||||
|
||||
#include "cap_ffmpeg_api.hpp"
|
||||
#endif
|
||||
|
||||
namespace cv { namespace {
|
||||
|
||||
static CvCreateFileCapture_Plugin icvCreateFileCapture_FFMPEG_p = 0;
|
||||
static CvReleaseCapture_Plugin icvReleaseCapture_FFMPEG_p = 0;
|
||||
@ -99,7 +114,7 @@ private:
|
||||
|
||||
icvInitFFMPEG()
|
||||
{
|
||||
#if defined _WIN32
|
||||
#if defined _WIN32
|
||||
const wchar_t* module_name_ = L"opencv_ffmpeg"
|
||||
CVAUX_STRW(CV_MAJOR_VERSION) CVAUX_STRW(CV_MINOR_VERSION) CVAUX_STRW(CV_SUBMINOR_VERSION)
|
||||
#if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__)
|
||||
@ -161,7 +176,7 @@ private:
|
||||
(CvReleaseVideoWriter_Plugin)GetProcAddress(icvFFOpenCV, "cvReleaseVideoWriter_FFMPEG");
|
||||
icvWriteFrame_FFMPEG_p =
|
||||
(CvWriteFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvWriteFrame_FFMPEG");
|
||||
|
||||
# endif // _WIN32
|
||||
#if 0
|
||||
if( icvCreateFileCapture_FFMPEG_p != 0 &&
|
||||
icvReleaseCapture_FFMPEG_p != 0 &&
|
||||
@ -181,21 +196,18 @@ private:
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#elif defined HAVE_FFMPEG
|
||||
icvCreateFileCapture_FFMPEG_p = (CvCreateFileCapture_Plugin)cvCreateFileCapture_FFMPEG;
|
||||
icvReleaseCapture_FFMPEG_p = (CvReleaseCapture_Plugin)cvReleaseCapture_FFMPEG;
|
||||
icvGrabFrame_FFMPEG_p = (CvGrabFrame_Plugin)cvGrabFrame_FFMPEG;
|
||||
icvRetrieveFrame_FFMPEG_p = (CvRetrieveFrame_Plugin)cvRetrieveFrame_FFMPEG;
|
||||
icvSetCaptureProperty_FFMPEG_p = (CvSetCaptureProperty_Plugin)cvSetCaptureProperty_FFMPEG;
|
||||
icvGetCaptureProperty_FFMPEG_p = (CvGetCaptureProperty_Plugin)cvGetCaptureProperty_FFMPEG;
|
||||
icvCreateVideoWriter_FFMPEG_p = (CvCreateVideoWriter_Plugin)cvCreateVideoWriter_FFMPEG;
|
||||
icvReleaseVideoWriter_FFMPEG_p = (CvReleaseVideoWriter_Plugin)cvReleaseVideoWriter_FFMPEG;
|
||||
icvWriteFrame_FFMPEG_p = (CvWriteFrame_Plugin)cvWriteFrame_FFMPEG;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}} // namespace
|
||||
#endif // HAVE_FFMPEG_WRAPPER
|
||||
|
||||
|
||||
|
||||
namespace cv {
|
||||
namespace {
|
||||
|
||||
class CvCapture_FFMPEG_proxy CV_FINAL : public cv::IVideoCapture
|
||||
{
|
||||
public:
|
||||
@ -228,19 +240,20 @@ public:
|
||||
}
|
||||
virtual bool open( const cv::String& filename )
|
||||
{
|
||||
icvInitFFMPEG::Init();
|
||||
close();
|
||||
|
||||
if( !icvCreateFileCapture_FFMPEG_p )
|
||||
return false;
|
||||
ffmpegCapture = icvCreateFileCapture_FFMPEG_p( filename.c_str() );
|
||||
return ffmpegCapture != 0;
|
||||
}
|
||||
virtual void close()
|
||||
{
|
||||
if( ffmpegCapture && icvReleaseCapture_FFMPEG_p )
|
||||
if (ffmpegCapture
|
||||
#if defined(HAVE_FFMPEG_WRAPPER)
|
||||
&& icvReleaseCapture_FFMPEG_p
|
||||
#endif
|
||||
)
|
||||
icvReleaseCapture_FFMPEG_p( &ffmpegCapture );
|
||||
assert( ffmpegCapture == 0 );
|
||||
CV_Assert(ffmpegCapture == 0);
|
||||
ffmpegCapture = 0;
|
||||
}
|
||||
|
||||
@ -248,18 +261,26 @@ public:
|
||||
virtual int getCaptureDomain() CV_OVERRIDE { return CV_CAP_FFMPEG; }
|
||||
|
||||
protected:
|
||||
void* ffmpegCapture;
|
||||
CvCapture_FFMPEG* ffmpegCapture;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
cv::Ptr<cv::IVideoCapture> cv::cvCreateFileCapture_FFMPEG_proxy(const cv::String& filename)
|
||||
cv::Ptr<cv::IVideoCapture> cvCreateFileCapture_FFMPEG_proxy(const cv::String& filename)
|
||||
{
|
||||
#if defined(HAVE_FFMPEG_WRAPPER)
|
||||
icvInitFFMPEG::Init();
|
||||
if (!icvCreateFileCapture_FFMPEG_p)
|
||||
return cv::Ptr<cv::IVideoCapture>();
|
||||
#endif
|
||||
cv::Ptr<CvCapture_FFMPEG_proxy> capture = cv::makePtr<CvCapture_FFMPEG_proxy>(filename);
|
||||
if (capture && capture->isOpened())
|
||||
return capture;
|
||||
return cv::Ptr<cv::IVideoCapture>();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class CvVideoWriter_FFMPEG_proxy CV_FINAL :
|
||||
public cv::IVideoWriter
|
||||
{
|
||||
@ -278,19 +299,20 @@ public:
|
||||
}
|
||||
virtual bool open( const cv::String& filename, int fourcc, double fps, cv::Size frameSize, bool isColor )
|
||||
{
|
||||
icvInitFFMPEG::Init();
|
||||
close();
|
||||
if( !icvCreateVideoWriter_FFMPEG_p )
|
||||
return false;
|
||||
ffmpegWriter = icvCreateVideoWriter_FFMPEG_p( filename.c_str(), fourcc, fps, frameSize.width, frameSize.height, isColor );
|
||||
return ffmpegWriter != 0;
|
||||
}
|
||||
|
||||
virtual void close()
|
||||
{
|
||||
if( ffmpegWriter && icvReleaseVideoWriter_FFMPEG_p )
|
||||
if (ffmpegWriter
|
||||
#if defined(HAVE_FFMPEG_WRAPPER)
|
||||
&& icvReleaseVideoWriter_FFMPEG_p
|
||||
#endif
|
||||
)
|
||||
icvReleaseVideoWriter_FFMPEG_p( &ffmpegWriter );
|
||||
assert( ffmpegWriter == 0 );
|
||||
CV_Assert(ffmpegWriter == 0);
|
||||
ffmpegWriter = 0;
|
||||
}
|
||||
|
||||
@ -299,15 +321,25 @@ public:
|
||||
virtual bool isOpened() const CV_OVERRIDE { return ffmpegWriter != 0; }
|
||||
|
||||
protected:
|
||||
void* ffmpegWriter;
|
||||
CvVideoWriter_FFMPEG* ffmpegWriter;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
cv::Ptr<cv::IVideoWriter> cv::cvCreateVideoWriter_FFMPEG_proxy(const cv::String& filename, int fourcc,
|
||||
double fps, cv::Size frameSize, int isColor)
|
||||
cv::Ptr<cv::IVideoWriter> cvCreateVideoWriter_FFMPEG_proxy(const cv::String& filename, int fourcc,
|
||||
double fps, cv::Size frameSize, int isColor)
|
||||
{
|
||||
#if defined(HAVE_FFMPEG_WRAPPER)
|
||||
icvInitFFMPEG::Init();
|
||||
if (!icvCreateVideoWriter_FFMPEG_p)
|
||||
return cv::Ptr<cv::IVideoWriter>();
|
||||
#endif
|
||||
cv::Ptr<CvVideoWriter_FFMPEG_proxy> writer = cv::makePtr<CvVideoWriter_FFMPEG_proxy>(filename, fourcc, fps, frameSize, isColor != 0);
|
||||
if (writer && writer->isOpened())
|
||||
return writer;
|
||||
return cv::Ptr<cv::IVideoWriter>();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // defined(HAVE_FFMPEG)
|
||||
|
@ -28,6 +28,8 @@ enum
|
||||
CV_FFMPEG_CAP_PROP_SAR_DEN=41
|
||||
};
|
||||
|
||||
typedef struct CvCapture_FFMPEG CvCapture_FFMPEG;
|
||||
typedef struct CvVideoWriter_FFMPEG CvVideoWriter_FFMPEG;
|
||||
|
||||
OPENCV_FFMPEG_API struct CvCapture_FFMPEG* cvCreateFileCapture_FFMPEG(const char* filename);
|
||||
OPENCV_FFMPEG_API struct CvCapture_FFMPEG_2* cvCreateFileCapture_FFMPEG_2(const char* filename);
|
||||
@ -55,19 +57,19 @@ OPENCV_FFMPEG_API int cvWriteFrame_FFMPEG(struct CvVideoWriter_FFMPEG* writer, c
|
||||
|
||||
OPENCV_FFMPEG_API void cvReleaseVideoWriter_FFMPEG(struct CvVideoWriter_FFMPEG** writer);
|
||||
|
||||
typedef void* (*CvCreateFileCapture_Plugin)( const char* filename );
|
||||
typedef void* (*CvCreateCameraCapture_Plugin)( int index );
|
||||
typedef int (*CvGrabFrame_Plugin)( void* capture_handle );
|
||||
typedef int (*CvRetrieveFrame_Plugin)( void* capture_handle, unsigned char** data, int* step,
|
||||
typedef CvCapture_FFMPEG* (*CvCreateFileCapture_Plugin)( const char* filename );
|
||||
typedef CvCapture_FFMPEG* (*CvCreateCameraCapture_Plugin)( int index );
|
||||
typedef int (*CvGrabFrame_Plugin)( CvCapture_FFMPEG* capture_handle );
|
||||
typedef int (*CvRetrieveFrame_Plugin)( CvCapture_FFMPEG* capture_handle, unsigned char** data, int* step,
|
||||
int* width, int* height, int* cn );
|
||||
typedef int (*CvSetCaptureProperty_Plugin)( void* capture_handle, int prop_id, double value );
|
||||
typedef double (*CvGetCaptureProperty_Plugin)( void* capture_handle, int prop_id );
|
||||
typedef void (*CvReleaseCapture_Plugin)( void** capture_handle );
|
||||
typedef void* (*CvCreateVideoWriter_Plugin)( const char* filename, int fourcc,
|
||||
typedef int (*CvSetCaptureProperty_Plugin)( CvCapture_FFMPEG* capture_handle, int prop_id, double value );
|
||||
typedef double (*CvGetCaptureProperty_Plugin)( CvCapture_FFMPEG* capture_handle, int prop_id );
|
||||
typedef void (*CvReleaseCapture_Plugin)( CvCapture_FFMPEG** capture_handle );
|
||||
typedef CvVideoWriter_FFMPEG* (*CvCreateVideoWriter_Plugin)( const char* filename, int fourcc,
|
||||
double fps, int width, int height, int iscolor );
|
||||
typedef int (*CvWriteFrame_Plugin)( void* writer_handle, const unsigned char* data, int step,
|
||||
typedef int (*CvWriteFrame_Plugin)( CvVideoWriter_FFMPEG* writer_handle, const unsigned char* data, int step,
|
||||
int width, int height, int cn, int origin);
|
||||
typedef void (*CvReleaseVideoWriter_Plugin)( void** writer );
|
||||
typedef void (*CvReleaseVideoWriter_Plugin)( CvVideoWriter_FFMPEG** writer );
|
||||
|
||||
/*
|
||||
* For CUDA encoder
|
||||
|
@ -754,6 +754,17 @@ private:
|
||||
AutoLock& operator = (const AutoLock&); // disabled
|
||||
};
|
||||
|
||||
static void ffmpeg_log_callback(void *ptr, int level, const char *fmt, va_list vargs)
|
||||
{
|
||||
static bool skip_header = false;
|
||||
static int prev_level = -1;
|
||||
(void)ptr;
|
||||
if (!skip_header || level != prev_level) printf("[OPENCV:FFMPEG:%02d] ", level);
|
||||
vprintf(fmt, vargs);
|
||||
size_t fmt_len = strlen(fmt);
|
||||
skip_header = fmt_len > 0 && fmt[fmt_len - 1] != '\n';
|
||||
prev_level = level;
|
||||
}
|
||||
|
||||
class InternalFFMpegRegister
|
||||
{
|
||||
@ -773,7 +784,18 @@ public:
|
||||
/* register a callback function for synchronization */
|
||||
av_lockmgr_register(&LockCallBack);
|
||||
|
||||
av_log_set_level(AV_LOG_ERROR);
|
||||
#ifndef NO_GETENV
|
||||
char* debug_option = getenv("OPENCV_FFMPEG_DEBUG");
|
||||
if (debug_option != NULL)
|
||||
{
|
||||
av_log_set_level(AV_LOG_VERBOSE);
|
||||
av_log_set_callback(ffmpeg_log_callback);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
av_log_set_level(AV_LOG_ERROR);
|
||||
}
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
@ -1587,6 +1609,9 @@ static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc,
|
||||
#if LIBAVCODEC_BUILD >= CALC_FFMPEG_VERSION(52, 42, 0)
|
||||
st->avg_frame_rate = (AVRational){frame_rate, frame_rate_base};
|
||||
#endif
|
||||
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(55, 20, 0)
|
||||
st->time_base = c->time_base;
|
||||
#endif
|
||||
|
||||
return st;
|
||||
}
|
||||
|
@ -1530,8 +1530,11 @@ void MotionJpegWriter::writeFrameData( const uchar* data, int step, int colorspa
|
||||
|
||||
}
|
||||
|
||||
Ptr<IVideoWriter> createMotionJpegWriter( const String& filename, double fps, Size frameSize, bool iscolor )
|
||||
Ptr<IVideoWriter> createMotionJpegWriter(const String& filename, int fourcc, double fps, Size frameSize, bool iscolor)
|
||||
{
|
||||
if (fourcc != CV_FOURCC('M', 'J', 'P', 'G'))
|
||||
return Ptr<IVideoWriter>();
|
||||
|
||||
Ptr<IVideoWriter> iwriter = makePtr<mjpeg::MotionJpegWriter>(filename, fps, frameSize, iscolor);
|
||||
if( !iwriter->isOpened() )
|
||||
iwriter.release();
|
||||
|
@ -47,6 +47,9 @@
|
||||
#include "opencv2/core/utility.hpp"
|
||||
#include "opencv2/core/private.hpp"
|
||||
|
||||
#include <opencv2/core/utils/configuration.private.hpp>
|
||||
#include <opencv2/core/utils/logger.hpp>
|
||||
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
|
||||
#include "opencv2/imgproc.hpp"
|
||||
@ -59,7 +62,7 @@
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <assert.h> // FIXIT remove this
|
||||
|
||||
#if defined _WIN32 || defined WINCE
|
||||
#if !defined _WIN32_WINNT
|
||||
@ -178,7 +181,7 @@ namespace cv
|
||||
};
|
||||
|
||||
Ptr<IVideoCapture> createMotionJpegCapture(const String& filename);
|
||||
Ptr<IVideoWriter> createMotionJpegWriter( const String& filename, double fps, Size frameSize, bool iscolor );
|
||||
Ptr<IVideoWriter> createMotionJpegWriter(const String& filename, int fourcc, double fps, Size frameSize, bool iscolor);
|
||||
|
||||
Ptr<IVideoCapture> createGPhoto2Capture(int index);
|
||||
Ptr<IVideoCapture> createGPhoto2Capture(const String& deviceName);
|
||||
|
152
modules/videoio/src/videoio_c.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#include "videoio_registry.hpp"
|
||||
|
||||
using namespace cv;
|
||||
|
||||
// Legacy C-like API
|
||||
|
||||
CV_IMPL CvCapture* cvCreateCameraCapture(int index)
|
||||
{
|
||||
// interpret preferred interface (0 = autodetect)
|
||||
int apiPreference = (index / 100) * 100;
|
||||
if (apiPreference)
|
||||
{
|
||||
index %= 100;
|
||||
}
|
||||
|
||||
const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_CaptureByIndex();
|
||||
for (size_t i = 0; i < backends.size(); i++)
|
||||
{
|
||||
const VideoBackendInfo& info = backends[i];
|
||||
if (apiPreference == CAP_ANY || apiPreference == info.id)
|
||||
{
|
||||
CvCapture* capture = NULL;
|
||||
Ptr<IVideoCapture> icap; // unused
|
||||
VideoCapture_create(capture, icap, info.id, index);
|
||||
if (capture)
|
||||
{
|
||||
return capture;
|
||||
}
|
||||
if (!icap.empty())
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "cvCreateFileCaptureWithPreference: backend " << info.name << " doesn't support legacy API anymore.")
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CV_IMPL CvCapture* cvCreateFileCaptureWithPreference(const char* filename, int apiPreference)
|
||||
{
|
||||
const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_CaptureByFilename();
|
||||
for (size_t i = 0; i < backends.size(); i++)
|
||||
{
|
||||
const VideoBackendInfo& info = backends[i];
|
||||
if (apiPreference == CAP_ANY || apiPreference == info.id)
|
||||
{
|
||||
CvCapture* capture = NULL;
|
||||
Ptr<IVideoCapture> icap; // unused
|
||||
VideoCapture_create(capture, icap, info.id, filename);
|
||||
if (capture)
|
||||
{
|
||||
return capture;
|
||||
}
|
||||
if (!icap.empty())
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "cvCreateFileCaptureWithPreference: backend " << info.name << " doesn't support legacy API anymore.")
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CV_IMPL CvCapture* cvCreateFileCapture(const char * filename)
|
||||
{
|
||||
return cvCreateFileCaptureWithPreference(filename, CAP_ANY);
|
||||
}
|
||||
|
||||
CV_IMPL CvVideoWriter* cvCreateVideoWriter(const char* filename, int fourcc,
|
||||
double fps, CvSize frameSize, int is_color)
|
||||
{
|
||||
const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_Writer();
|
||||
for (size_t i = 0; i < backends.size(); i++)
|
||||
{
|
||||
const VideoBackendInfo& info = backends[i];
|
||||
{
|
||||
CvVideoWriter* writer_ = NULL;
|
||||
Ptr<IVideoWriter> iwriter; // unused
|
||||
VideoWriter_create(writer_, iwriter, info.id, filename, fourcc, fps, frameSize, is_color != 0);
|
||||
if (writer_)
|
||||
{
|
||||
return writer_;
|
||||
}
|
||||
if (!iwriter.empty())
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "cvCreateVideoWriter: backend " << info.name << " doesn't support legacy API anymore.")
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CV_IMPL int cvWriteFrame(CvVideoWriter* writer, const IplImage* image)
|
||||
{
|
||||
return writer ? writer->writeFrame(image) : 0;
|
||||
}
|
||||
|
||||
CV_IMPL void cvReleaseVideoWriter(CvVideoWriter** pwriter)
|
||||
{
|
||||
if( pwriter && *pwriter )
|
||||
{
|
||||
delete *pwriter;
|
||||
*pwriter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
CV_IMPL void cvReleaseCapture(CvCapture** pcapture)
|
||||
{
|
||||
if (pcapture && *pcapture)
|
||||
{
|
||||
delete *pcapture;
|
||||
*pcapture = 0;
|
||||
}
|
||||
}
|
||||
|
||||
CV_IMPL IplImage* cvQueryFrame(CvCapture* capture)
|
||||
{
|
||||
if (!capture)
|
||||
return 0;
|
||||
if (!capture->grabFrame())
|
||||
return 0;
|
||||
return capture->retrieveFrame(0);
|
||||
}
|
||||
|
||||
CV_IMPL int cvGrabFrame(CvCapture* capture)
|
||||
{
|
||||
return capture ? capture->grabFrame() : 0;
|
||||
}
|
||||
|
||||
CV_IMPL IplImage* cvRetrieveFrame(CvCapture* capture, int idx)
|
||||
{
|
||||
return capture ? capture->retrieveFrame(idx) : 0;
|
||||
}
|
||||
|
||||
CV_IMPL double cvGetCaptureProperty(CvCapture* capture, int id)
|
||||
{
|
||||
return capture ? capture->getProperty(id) : 0;
|
||||
}
|
||||
|
||||
CV_IMPL int cvSetCaptureProperty(CvCapture* capture, int id, double value)
|
||||
{
|
||||
return capture ? capture->setProperty(id, value) : 0;
|
||||
}
|
||||
|
||||
CV_IMPL int cvGetCaptureDomain(CvCapture* capture)
|
||||
{
|
||||
return capture ? capture->getCaptureDomain() : 0;
|
||||
}
|
644
modules/videoio/src/videoio_registry.cpp
Normal file
@ -0,0 +1,644 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#include "videoio_registry.hpp"
|
||||
|
||||
#include "cap_intelperc.hpp"
|
||||
#include "cap_librealsense.hpp"
|
||||
#include "cap_dshow.hpp"
|
||||
|
||||
#ifdef HAVE_MFX
|
||||
#include "cap_mfx_reader.hpp"
|
||||
#include "cap_mfx_writer.hpp"
|
||||
#endif
|
||||
|
||||
// All WinRT versions older than 8.0 should provide classes used for video support
|
||||
#if defined(WINRT) && !defined(WINRT_8_0) && defined(__cplusplus_winrt)
|
||||
# include "cap_winrt_capture.hpp"
|
||||
# include "cap_winrt_bridge.hpp"
|
||||
# define WINRT_VIDEO
|
||||
#endif
|
||||
|
||||
#if defined _M_X64 && defined _MSC_VER && !defined CV_ICC
|
||||
#pragma optimize("",off)
|
||||
#pragma warning(disable: 4748)
|
||||
#endif
|
||||
|
||||
using namespace cv;
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
static bool param_VIDEOIO_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOIO_DEBUG", false);
|
||||
static bool param_VIDEOCAPTURE_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOCAPTURE_DEBUG", false);
|
||||
static bool param_VIDEOWRITER_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOWRITER_DEBUG", false);
|
||||
|
||||
namespace {
|
||||
|
||||
#define DECLARE_BACKEND(cap, name, mode) { cap, (BackendMode)(mode), 1000, name }
|
||||
|
||||
/** Ordering guidelines:
|
||||
- modern optimized, multi-platform libraries: ffmpeg, gstreamer, Media SDK
|
||||
- platform specific universal SDK: WINRT, QTKIT/AVFOUNDATION, MSMF/VFW/DSHOW, V4L/V4L2
|
||||
- RGB-D: OpenNI/OpenNI2, INTELPERC/REALSENSE
|
||||
- special OpenCV (file-based): "images", "mjpeg"
|
||||
- special camera SDKs, including stereo: other special SDKs: FIREWIRE/1394, XIMEA/ARAVIS/GIGANETIX/PVAPI(GigE), UNICAP
|
||||
- other: XINE, gphoto2, etc
|
||||
*/
|
||||
static const struct VideoBackendInfo builtin_backends[] =
|
||||
{
|
||||
#ifdef HAVE_FFMPEG
|
||||
DECLARE_BACKEND(CAP_FFMPEG, "FFMPEG", MODE_CAPTURE_BY_FILENAME | MODE_WRITER),
|
||||
#endif
|
||||
#ifdef HAVE_GSTREAMER
|
||||
DECLARE_BACKEND(CAP_GSTREAMER, "GSTREAMER", MODE_CAPTURE_ALL | MODE_WRITER),
|
||||
#endif
|
||||
#ifdef HAVE_MFX // Media SDK
|
||||
DECLARE_BACKEND(CAP_INTEL_MFX, "INTEL_MFX", MODE_CAPTURE_BY_FILENAME | MODE_WRITER),
|
||||
#endif
|
||||
|
||||
|
||||
// Apple platform
|
||||
#if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT)
|
||||
DECLARE_BACKEND(CAP_QT, "QUICKTIME", MODE_CAPTURE_ALL | MODE_WRITER),
|
||||
#endif
|
||||
#ifdef HAVE_AVFOUNDATION
|
||||
DECLARE_BACKEND(CAP_AVFOUNDATION, "AVFOUNDATION", MODE_CAPTURE_ALL | MODE_WRITER),
|
||||
#endif
|
||||
|
||||
// Windows
|
||||
#ifdef WINRT_VIDEO
|
||||
DECLARE_BACKEND(CAP_WINRT, "WINRT", MODE_CAPTURE_BY_FILENAME),
|
||||
#endif
|
||||
#ifdef HAVE_MSMF
|
||||
DECLARE_BACKEND(CAP_MSMF, "MSMF", MODE_CAPTURE_ALL | MODE_WRITER),
|
||||
#endif
|
||||
#ifdef HAVE_VFW
|
||||
DECLARE_BACKEND(CAP_VFW, "VFW", MODE_CAPTURE_ALL | MODE_WRITER),
|
||||
#endif
|
||||
#ifdef HAVE_DSHOW
|
||||
DECLARE_BACKEND(CAP_DSHOW, "DSHOW", MODE_CAPTURE_ALL),
|
||||
#endif
|
||||
|
||||
// Linux, some Unix
|
||||
#if defined HAVE_CAMV4L2
|
||||
DECLARE_BACKEND(CAP_V4L2, "V4L2", MODE_CAPTURE_ALL),
|
||||
#elif defined HAVE_LIBV4L || defined HAVE_CAMV4L
|
||||
DECLARE_BACKEND(CAP_V4L, "V4L", MODE_CAPTURE_ALL),
|
||||
#endif
|
||||
|
||||
|
||||
// RGB-D universal
|
||||
#ifdef HAVE_OPENNI
|
||||
DECLARE_BACKEND(CAP_OPENNI, "OPENNI", MODE_CAPTURE_ALL),
|
||||
#endif
|
||||
#ifdef HAVE_OPENNI2
|
||||
DECLARE_BACKEND(CAP_OPENNI2, "OPENNI2", MODE_CAPTURE_ALL),
|
||||
#endif
|
||||
#ifdef HAVE_INTELPERC
|
||||
DECLARE_BACKEND(CAP_INTELPERC, "INTEL_PERC", MODE_CAPTURE_ALL),
|
||||
#elif defined(HAVE_LIBREALSENSE)
|
||||
DECLARE_BACKEND(CAP_INTELPERC, "INTEL_REALSENSE", MODE_CAPTURE_BY_INDEX),
|
||||
#endif
|
||||
|
||||
// OpenCV file-based only
|
||||
DECLARE_BACKEND(CAP_IMAGES, "CV_IMAGES", MODE_CAPTURE_BY_FILENAME | MODE_WRITER),
|
||||
DECLARE_BACKEND(CAP_OPENCV_MJPEG, "CV_MJPEG", MODE_CAPTURE_BY_FILENAME | MODE_WRITER),
|
||||
|
||||
// special interfaces / stereo cameras / other SDKs
|
||||
#if defined(HAVE_DC1394_2) || defined(HAVE_DC1394) || defined(HAVE_CMU1394)
|
||||
DECLARE_BACKEND(CAP_FIREWIRE, "FIREWIRE", MODE_CAPTURE_ALL),
|
||||
#endif
|
||||
// GigE
|
||||
#ifdef HAVE_PVAPI
|
||||
DECLARE_BACKEND(CAP_PVAPI, "PVAPI", MODE_CAPTURE_ALL),
|
||||
#endif
|
||||
#ifdef HAVE_XIMEA
|
||||
DECLARE_BACKEND(CAP_XIAPI, "XIMEA", MODE_CAPTURE_ALL),
|
||||
#endif
|
||||
#ifdef HAVE_GIGE_API
|
||||
DECLARE_BACKEND(CAP_GIGANETIX, "GIGANETIX", MODE_CAPTURE_ALL),
|
||||
#endif
|
||||
#ifdef HAVE_ARAVIS_API
|
||||
DECLARE_BACKEND(CAP_ARAVIS, "ARAVIS", MODE_CAPTURE_ALL),
|
||||
#endif
|
||||
#ifdef HAVE_UNICAP
|
||||
DECLARE_BACKEND(CAP_UNICAP, "UNICAP", MODE_CAPTURE_BY_FILENAME),
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GPHOTO2
|
||||
DECLARE_BACKEND(CAP_GPHOTO2, "GPHOTO2", MODE_CAPTURE_ALL),
|
||||
#endif
|
||||
#ifdef HAVE_XINE
|
||||
DECLARE_BACKEND(CAP_XINE, "XINE", MODE_CAPTURE_BY_FILENAME),
|
||||
#endif
|
||||
|
||||
// dropped backends: MIL, TYZX, Android
|
||||
};
|
||||
|
||||
bool sortByPriority(const VideoBackendInfo &lhs, const VideoBackendInfo &rhs)
|
||||
{
|
||||
return lhs.priority > rhs.priority;
|
||||
}
|
||||
|
||||
/** @brief Manages list of enabled backends
|
||||
*/
|
||||
class VideoBackendRegistry
|
||||
{
|
||||
protected:
|
||||
std::vector<VideoBackendInfo> enabledBackends;
|
||||
VideoBackendRegistry()
|
||||
{
|
||||
const int N = sizeof(builtin_backends)/sizeof(builtin_backends[0]);
|
||||
enabledBackends.assign(builtin_backends, builtin_backends + N);
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
VideoBackendInfo& info = enabledBackends[i];
|
||||
info.priority = 1000 - i * 10;
|
||||
}
|
||||
CV_LOG_DEBUG(NULL, "VIDEOIO: Builtin backends(" << N << "): " << dumpBackends());
|
||||
if (readPrioritySettings())
|
||||
{
|
||||
CV_LOG_INFO(NULL, "VIDEOIO: Updated backends priorities: " << dumpBackends());
|
||||
}
|
||||
int enabled = 0;
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
VideoBackendInfo& info = enabledBackends[enabled];
|
||||
if (enabled != i)
|
||||
info = enabledBackends[i];
|
||||
size_t param_priority = utils::getConfigurationParameterSizeT(cv::format("OPENCV_VIDEOIO_PRIORITY_%s", info.name).c_str(), (size_t)info.priority);
|
||||
CV_Assert(param_priority == (size_t)(int)param_priority); // overflow check
|
||||
if (param_priority > 0)
|
||||
{
|
||||
info.priority = (int)param_priority;
|
||||
enabled++;
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_LOG_INFO(NULL, "VIDEOIO: Disable backend: " << info.name);
|
||||
}
|
||||
}
|
||||
enabledBackends.resize(enabled);
|
||||
CV_LOG_DEBUG(NULL, "VIDEOIO: Available backends(" << enabled << "): " << dumpBackends());
|
||||
std::sort(enabledBackends.begin(), enabledBackends.end(), sortByPriority);
|
||||
CV_LOG_INFO(NULL, "VIDEOIO: Enabled backends(" << enabled << ", sorted by priority): " << dumpBackends());
|
||||
}
|
||||
|
||||
static std::vector<std::string> tokenize_string(const std::string& input, char token)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
std::string::size_type prev_pos = 0, pos = 0;
|
||||
while((pos = input.find(token, pos)) != std::string::npos)
|
||||
{
|
||||
result.push_back(input.substr(prev_pos, pos-prev_pos));
|
||||
prev_pos = ++pos;
|
||||
}
|
||||
result.push_back(input.substr(prev_pos));
|
||||
return result;
|
||||
}
|
||||
bool readPrioritySettings()
|
||||
{
|
||||
bool hasChanges = false;
|
||||
cv::String prioritized_backends = utils::getConfigurationParameterString("OPENCV_VIDEOIO_PRIORITY_LIST", NULL);
|
||||
if (prioritized_backends.empty())
|
||||
return hasChanges;
|
||||
CV_LOG_INFO(NULL, "VIDEOIO: Configured priority list (OPENCV_VIDEOIO_PRIORITY_LIST): " << prioritized_backends);
|
||||
const std::vector<std::string> names = tokenize_string(prioritized_backends, ',');
|
||||
for (size_t i = 0; i < names.size(); i++)
|
||||
{
|
||||
const std::string& name = names[i];
|
||||
bool found = false;
|
||||
for (size_t k = 0; k < enabledBackends.size(); k++)
|
||||
{
|
||||
VideoBackendInfo& info = enabledBackends[k];
|
||||
if (name == info.name)
|
||||
{
|
||||
info.priority = (int)(100000 + (names.size() - i) * 1000);
|
||||
CV_LOG_DEBUG(NULL, "VIDEOIO: New backend priority: '" << name << "' => " << info.priority);
|
||||
found = true;
|
||||
hasChanges = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "VIDEOIO: Can't prioritize unknown/unavailable backend: '" << name << "'");
|
||||
}
|
||||
}
|
||||
return hasChanges;
|
||||
}
|
||||
public:
|
||||
std::string dumpBackends() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
for (size_t i = 0; i < enabledBackends.size(); i++)
|
||||
{
|
||||
if (i > 0) os << "; ";
|
||||
const VideoBackendInfo& info = enabledBackends[i];
|
||||
os << info.name << '(' << info.priority << ')';
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
static VideoBackendRegistry& getInstance()
|
||||
{
|
||||
static VideoBackendRegistry g_instance;
|
||||
return g_instance;
|
||||
}
|
||||
|
||||
inline std::vector<VideoBackendInfo> getAvailableBackends_CaptureByIndex() const
|
||||
{
|
||||
std::vector<VideoBackendInfo> result;
|
||||
for (size_t i = 0; i < enabledBackends.size(); i++)
|
||||
{
|
||||
const VideoBackendInfo& info = enabledBackends[i];
|
||||
if (info.mode & MODE_CAPTURE_BY_INDEX)
|
||||
result.push_back(info);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
inline std::vector<VideoBackendInfo> getAvailableBackends_CaptureByFilename() const
|
||||
{
|
||||
std::vector<VideoBackendInfo> result;
|
||||
for (size_t i = 0; i < enabledBackends.size(); i++)
|
||||
{
|
||||
const VideoBackendInfo& info = enabledBackends[i];
|
||||
if (info.mode & MODE_CAPTURE_BY_FILENAME)
|
||||
result.push_back(info);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
inline std::vector<VideoBackendInfo> getAvailableBackends_Writer() const
|
||||
{
|
||||
std::vector<VideoBackendInfo> result;
|
||||
for (size_t i = 0; i < enabledBackends.size(); i++)
|
||||
{
|
||||
const VideoBackendInfo& info = enabledBackends[i];
|
||||
if (info.mode & MODE_WRITER)
|
||||
result.push_back(info);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace videoio_registry {
|
||||
|
||||
std::vector<VideoBackendInfo> getAvailableBackends_CaptureByIndex()
|
||||
{
|
||||
const std::vector<VideoBackendInfo> result = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByIndex();
|
||||
return result;
|
||||
}
|
||||
std::vector<VideoBackendInfo> getAvailableBackends_CaptureByFilename()
|
||||
{
|
||||
const std::vector<VideoBackendInfo> result = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByFilename();
|
||||
return result;
|
||||
}
|
||||
std::vector<VideoBackendInfo> getAvailableBackends_Writer()
|
||||
{
|
||||
const std::vector<VideoBackendInfo> result = VideoBackendRegistry::getInstance().getAvailableBackends_Writer();
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace registry
|
||||
|
||||
#define TRY_OPEN(backend_func) \
|
||||
{ \
|
||||
try { \
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG) \
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying ...\n", #backend_func)); \
|
||||
icap = backend_func; \
|
||||
if (param_VIDEOIO_DEBUG ||param_VIDEOCAPTURE_DEBUG) \
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): result=%p isOpened=%d ...\n", \
|
||||
#backend_func, icap.empty() ? NULL : icap.get(), icap.empty() ? -1: icap->isOpened())); \
|
||||
} catch(const cv::Exception& e) { \
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", #backend_func, e.what())); \
|
||||
} catch (const std::exception& e) { \
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", #backend_func, e.what())); \
|
||||
} catch(...) { \
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", #backend_func)); \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define TRY_OPEN_LEGACY(backend_func) \
|
||||
{ \
|
||||
try { \
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG) \
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying ...\n", #backend_func)); \
|
||||
capture = backend_func; \
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG) \
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): result=%p ...\n", #backend_func, capture)); \
|
||||
} catch(const cv::Exception& e) { \
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", #backend_func, e.what())); \
|
||||
} catch (const std::exception& e) { \
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", #backend_func, e.what())); \
|
||||
} catch(...) { \
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", #backend_func)); \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
|
||||
|
||||
void VideoCapture_create(CvCapture*& capture, Ptr<IVideoCapture>& icap, VideoCaptureAPIs api, int index)
|
||||
{
|
||||
CV_UNUSED(capture); CV_UNUSED(icap);
|
||||
switch (api)
|
||||
{
|
||||
default:
|
||||
CV_LOG_WARNING(NULL, "VideoCapture(index=" << index << ") was built without support of requested backendID=" << (int)api);
|
||||
break;
|
||||
#ifdef HAVE_GSTREAMER
|
||||
case CAP_GSTREAMER:
|
||||
TRY_OPEN(createGStreamerCapture(index));
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_MSMF
|
||||
case CAP_MSMF:
|
||||
TRY_OPEN(cvCreateCapture_MSMF(index));
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_DSHOW
|
||||
case CAP_DSHOW:
|
||||
TRY_OPEN(makePtr<VideoCapture_DShow>(index));
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_INTELPERC
|
||||
case CAP_INTELPERC:
|
||||
TRY_OPEN(makePtr<VideoCapture_IntelPerC>());
|
||||
break;
|
||||
#elif defined(HAVE_LIBREALSENSE)
|
||||
case CAP_INTELPERC:
|
||||
TRY_OPEN(makePtr<VideoCapture_LibRealsense>(index));
|
||||
break;
|
||||
#endif
|
||||
#ifdef WINRT_VIDEO
|
||||
case CAP_WINRT:
|
||||
TRY_OPEN(makePtr<cv::VideoCapture_WinRT>(index));
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_GPHOTO2
|
||||
case CAP_GPHOTO2:
|
||||
TRY_OPEN(createGPhoto2Capture(index));
|
||||
break;
|
||||
#endif
|
||||
case CAP_VFW: // or CAP_V4L or CAP_V4L2
|
||||
#ifdef HAVE_VFW
|
||||
TRY_OPEN_LEGACY(cvCreateCameraCapture_VFW(index))
|
||||
#endif
|
||||
#if defined HAVE_LIBV4L || defined HAVE_CAMV4L || defined HAVE_CAMV4L2 || defined HAVE_VIDEOIO
|
||||
TRY_OPEN_LEGACY(cvCreateCameraCapture_V4L(index))
|
||||
#endif
|
||||
break;
|
||||
case CAP_FIREWIRE:
|
||||
#ifdef HAVE_DC1394_2
|
||||
TRY_OPEN_LEGACY(cvCreateCameraCapture_DC1394_2(index))
|
||||
#endif
|
||||
#ifdef HAVE_DC1394
|
||||
TRY_OPEN_LEGACY(cvCreateCameraCapture_DC1394(index))
|
||||
#endif
|
||||
#ifdef HAVE_CMU1394
|
||||
TRY_OPEN_LEGACY(cvCreateCameraCapture_CMU(index))
|
||||
#endif
|
||||
break; // CAP_FIREWIRE
|
||||
#ifdef HAVE_MIL
|
||||
case CAP_MIL:
|
||||
TRY_OPEN_LEGACY(cvCreateCameraCapture_MIL(index))
|
||||
break;
|
||||
#endif
|
||||
#if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT)
|
||||
case CAP_QT:
|
||||
TRY_OPEN_LEGACY(cvCreateCameraCapture_QT(index))
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_UNICAP
|
||||
case CAP_UNICAP:
|
||||
TRY_OPEN_LEGACY(cvCreateCameraCapture_Unicap(index))
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_PVAPI
|
||||
case CAP_PVAPI:
|
||||
TRY_OPEN_LEGACY(cvCreateCameraCapture_PvAPI(index))
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_OPENNI
|
||||
case CAP_OPENNI:
|
||||
TRY_OPEN_LEGACY(cvCreateCameraCapture_OpenNI(index))
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_OPENNI2
|
||||
case CAP_OPENNI2:
|
||||
TRY_OPEN_LEGACY(cvCreateCameraCapture_OpenNI2(index))
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_XIMEA
|
||||
case CAP_XIAPI:
|
||||
TRY_OPEN_LEGACY(cvCreateCameraCapture_XIMEA(index))
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_AVFOUNDATION
|
||||
case CAP_AVFOUNDATION:
|
||||
TRY_OPEN_LEGACY(cvCreateCameraCapture_AVFoundation(index))
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GIGE_API
|
||||
case CAP_GIGANETIX:
|
||||
TRY_OPEN_LEGACY(cvCreateCameraCapture_Giganetix(index))
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARAVIS_API
|
||||
case CAP_ARAVIS:
|
||||
TRY_OPEN_LEGACY(cvCreateCameraCapture_Aravis(index))
|
||||
break;
|
||||
#endif
|
||||
} // switch (api)
|
||||
}
|
||||
|
||||
void VideoCapture_create(CvCapture*& capture, Ptr<IVideoCapture>& icap, VideoCaptureAPIs api, const cv::String& filename)
|
||||
{
|
||||
switch (api)
|
||||
{
|
||||
default:
|
||||
CV_LOG_WARNING(NULL, "VideoCapture(filename=" << filename << ") was built without support of requested backendID=" << (int)api);
|
||||
break;
|
||||
#if defined HAVE_LIBV4L || defined HAVE_CAMV4L || defined HAVE_CAMV4L2 || defined HAVE_VIDEOIO
|
||||
case CAP_V4L:
|
||||
TRY_OPEN_LEGACY(cvCreateCameraCapture_V4L(filename.c_str()))
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VFW
|
||||
case CAP_VFW:
|
||||
TRY_OPEN_LEGACY(cvCreateFileCapture_VFW(filename.c_str()))
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT)
|
||||
case CAP_QT:
|
||||
TRY_OPEN_LEGACY(cvCreateFileCapture_QT(filename.c_str()))
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_AVFOUNDATION
|
||||
case CAP_AVFOUNDATION:
|
||||
TRY_OPEN_LEGACY(cvCreateFileCapture_AVFoundation(filename.c_str()))
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENNI
|
||||
case CAP_OPENNI:
|
||||
TRY_OPEN_LEGACY(cvCreateFileCapture_OpenNI(filename.c_str()))
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENNI2
|
||||
case CAP_OPENNI2:
|
||||
TRY_OPEN_LEGACY(cvCreateFileCapture_OpenNI2(filename.c_str()))
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_XIMEA
|
||||
case CAP_XIAPI:
|
||||
TRY_OPEN_LEGACY(cvCreateCameraCapture_XIMEA(filename.c_str()))
|
||||
break;
|
||||
#endif
|
||||
case CAP_IMAGES:
|
||||
TRY_OPEN_LEGACY(cvCreateFileCapture_Images(filename.c_str()))
|
||||
break;
|
||||
#ifdef HAVE_FFMPEG
|
||||
case CAP_FFMPEG:
|
||||
TRY_OPEN(cvCreateFileCapture_FFMPEG_proxy(filename))
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_GSTREAMER
|
||||
case CAP_GSTREAMER:
|
||||
TRY_OPEN(createGStreamerCapture(filename))
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_XINE
|
||||
case CAP_XINE:
|
||||
TRY_OPEN(createXINECapture(filename.c_str()))
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_MSMF
|
||||
case CAP_MSMF:
|
||||
TRY_OPEN(cvCreateCapture_MSMF(filename))
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_GPHOTO2
|
||||
case CAP_GPHOTO2:
|
||||
TRY_OPEN(createGPhoto2Capture(filename))
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_MFX
|
||||
case CAP_INTEL_MFX:
|
||||
TRY_OPEN(makePtr<VideoCapture_IntelMFX>(filename))
|
||||
break;
|
||||
#endif
|
||||
case CAP_OPENCV_MJPEG:
|
||||
TRY_OPEN(createMotionJpegCapture(filename))
|
||||
break;
|
||||
} // switch
|
||||
}
|
||||
|
||||
|
||||
void VideoWriter_create(CvVideoWriter*& writer, Ptr<IVideoWriter>& iwriter, VideoCaptureAPIs api,
|
||||
const String& filename, int fourcc, double fps, const Size& frameSize, bool isColor)
|
||||
{
|
||||
#define CREATE_WRITER(backend_func) \
|
||||
{ \
|
||||
try { \
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG) \
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying ...\n", #backend_func)); \
|
||||
iwriter = backend_func; \
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG) \
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): result=%p isOpened=%d...\n", #backend_func, iwriter.empty() ? NULL : iwriter.get(), iwriter.empty() ? iwriter->isOpened() : -1)); \
|
||||
} catch(const cv::Exception& e) { \
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", #backend_func, e.what())); \
|
||||
} catch (const std::exception& e) { \
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", #backend_func, e.what())); \
|
||||
} catch(...) { \
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", #backend_func)); \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define CREATE_WRITER_LEGACY(backend_func) \
|
||||
{ \
|
||||
try { \
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG) \
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying ...\n", #backend_func)); \
|
||||
writer = backend_func; \
|
||||
if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG) \
|
||||
CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): result=%p...\n", #backend_func, writer)); \
|
||||
} catch(const cv::Exception& e) { \
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", #backend_func, e.what())); \
|
||||
} catch (const std::exception& e) { \
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", #backend_func, e.what())); \
|
||||
} catch(...) { \
|
||||
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", #backend_func)); \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
|
||||
switch (api)
|
||||
{
|
||||
default:
|
||||
CV_LOG_ERROR(NULL, "Unknown VideoWriter backend (check getBuildInformation()): " << (int)api);
|
||||
break;
|
||||
#ifdef HAVE_FFMPEG
|
||||
case CAP_FFMPEG:
|
||||
CREATE_WRITER(cvCreateVideoWriter_FFMPEG_proxy(filename, fourcc, fps, frameSize, isColor));
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_MSMF
|
||||
case CAP_MSMF:
|
||||
CREATE_WRITER(cvCreateVideoWriter_MSMF(filename, fourcc, fps, frameSize, isColor));
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_MFX
|
||||
case CAP_INTEL_MFX:
|
||||
CREATE_WRITER(VideoWriter_IntelMFX::create(filename, fourcc, fps, frameSize, isColor));
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_VFW
|
||||
case CAP_VFW:
|
||||
CREATE_WRITER_LEGACY(cvCreateVideoWriter_VFW(filename.c_str(), fourcc, fps, frameSize, isColor))
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_AVFOUNDATION
|
||||
case CAP_AVFOUNDATION:
|
||||
CREATE_WRITER_LEGACY(cvCreateVideoWriter_AVFoundation(filename.c_str(), fourcc, fps, frameSize, isColor))
|
||||
break;
|
||||
#endif
|
||||
#if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT)
|
||||
case(CAP_QT):
|
||||
CREATE_WRITER_LEGACY(cvCreateVideoWriter_QT(filename.c_str(), fourcc, fps, frameSize, isColor))
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_GSTREAMER
|
||||
case CAP_GSTREAMER:
|
||||
CREATE_WRITER_LEGACY(cvCreateVideoWriter_GStreamer (filename.c_str(), fourcc, fps, frameSize, isColor))
|
||||
break;
|
||||
#endif
|
||||
case CAP_OPENCV_MJPEG:
|
||||
CREATE_WRITER(createMotionJpegWriter(filename, fourcc, fps, frameSize, isColor));
|
||||
break;
|
||||
case CAP_IMAGES:
|
||||
if(!fourcc || !fps)
|
||||
{
|
||||
CREATE_WRITER_LEGACY(cvCreateVideoWriter_Images(filename.c_str()));
|
||||
}
|
||||
break;
|
||||
} // switch(api)
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
43
modules/videoio/src/videoio_registry.hpp
Normal file
@ -0,0 +1,43 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef __OPENCV_VIDEOIO_VIDEOIO_REGISTRY_HPP__
|
||||
#define __OPENCV_VIDEOIO_VIDEOIO_REGISTRY_HPP__
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
/** Capabilities bitmask */
|
||||
enum BackendMode {
|
||||
MODE_CAPTURE_BY_INDEX = 1 << 0, //!< device index
|
||||
MODE_CAPTURE_BY_FILENAME = 1 << 1, //!< filename or device path (v4l2)
|
||||
MODE_WRITER = 1 << 4, //!< writer
|
||||
|
||||
MODE_CAPTURE_ALL = MODE_CAPTURE_BY_INDEX + MODE_CAPTURE_BY_FILENAME,
|
||||
};
|
||||
|
||||
struct VideoBackendInfo {
|
||||
VideoCaptureAPIs id;
|
||||
BackendMode mode;
|
||||
int priority; // 1000-<index*10> - default builtin priority
|
||||
// 0 - disabled (OPENCV_VIDEOIO_PRIORITY_<name> = 0)
|
||||
// >10000 - prioritized list (OPENCV_VIDEOIO_PRIORITY_LIST)
|
||||
const char* name;
|
||||
};
|
||||
|
||||
namespace videoio_registry {
|
||||
|
||||
std::vector<VideoBackendInfo> getAvailableBackends_CaptureByIndex();
|
||||
std::vector<VideoBackendInfo> getAvailableBackends_CaptureByFilename();
|
||||
std::vector<VideoBackendInfo> getAvailableBackends_Writer();
|
||||
|
||||
} // namespace
|
||||
|
||||
void VideoCapture_create(CvCapture*& capture, Ptr<IVideoCapture>& icap, VideoCaptureAPIs api, int index);
|
||||
void VideoCapture_create(CvCapture*& capture, Ptr<IVideoCapture>& icap, VideoCaptureAPIs api, const cv::String& filename);
|
||||
void VideoWriter_create(CvVideoWriter*& writer, Ptr<IVideoWriter>& iwriter, VideoCaptureAPIs api,
|
||||
const String& filename, int fourcc, double fps, const Size& frameSize, bool isColor);
|
||||
|
||||
} // namespace
|
||||
#endif // __OPENCV_VIDEOIO_VIDEOIO_REGISTRY_HPP__
|
@ -228,7 +228,7 @@ public:
|
||||
static std::string TmpDirectory;
|
||||
|
||||
CreateVideoWriterInvoker(std::vector<VideoWriter*>& _writers, std::vector<std::string>& _files) :
|
||||
ParallelLoopBody(), writers(&_writers), files(&_files)
|
||||
writers(_writers), files(_files)
|
||||
{
|
||||
}
|
||||
|
||||
@ -240,16 +240,16 @@ public:
|
||||
stream << i << ".avi";
|
||||
std::string fileName = tempfile(stream.str().c_str());
|
||||
|
||||
files->operator[](i) = fileName;
|
||||
writers->operator[](i) = new VideoWriter(fileName, CAP_FFMPEG, VideoWriter::fourcc('X','V','I','D'), 25.0f, FrameSize);
|
||||
files[i] = fileName;
|
||||
writers[i] = new VideoWriter(fileName, CAP_FFMPEG, VideoWriter::fourcc('X','V','I','D'), 25.0f, FrameSize);
|
||||
|
||||
CV_Assert(writers->operator[](i)->isOpened());
|
||||
CV_Assert(writers[i]->isOpened());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<VideoWriter*>* writers;
|
||||
std::vector<std::string>* files;
|
||||
std::vector<VideoWriter*>& writers;
|
||||
std::vector<std::string>& files;
|
||||
};
|
||||
|
||||
std::string CreateVideoWriterInvoker::TmpDirectory;
|
||||
@ -357,6 +357,8 @@ public:
|
||||
|
||||
for (unsigned int i = 0; i < frameCount && next; ++i)
|
||||
{
|
||||
SCOPED_TRACE(cv::format("frame=%d/%d", (int)i, (int)frameCount));
|
||||
|
||||
Mat actual;
|
||||
(*capture) >> actual;
|
||||
|
||||
|
@ -19,7 +19,7 @@ if(NOT BUILD_SHARED_LIBS)
|
||||
endif()
|
||||
endforeach()
|
||||
if(_conflicts)
|
||||
message(STATUS "Disabling VIZ module due conflicts with VTK dependencies: ${_conflicts}")
|
||||
message(STATUS "Disabling VIZ module due to conflicts with VTK dependencies: ${_conflicts}")
|
||||
ocv_module_disable(viz)
|
||||
endif()
|
||||
endif()
|
||||
|