Update fluid (#9007)
This commit is contained in:
parent
97f6dbf1f2
commit
f734e7679b
|
|
@ -1 +1 @@
|
|||
91e7c0aaa00be504e8e6692d0b3b86c1
|
||||
52e7351a888ee42076be4db81d9ac992
|
||||
|
|
|
|||
|
|
@ -23,25 +23,20 @@ ocv_add_module(gapi
|
|||
REQUIRED
|
||||
opencv_imgproc
|
||||
OPTIONAL
|
||||
opencv_video
|
||||
opencv_video opencv_calib3d
|
||||
WRAP
|
||||
python
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
# Disable obsollete warning C4503 popping up on MSVC <<2017
|
||||
# https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4503?view=vs-2019
|
||||
ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4503)
|
||||
if (OPENCV_GAPI_INF_ENGINE AND NOT INF_ENGINE_RELEASE VERSION_GREATER "2021000000")
|
||||
# Disable IE deprecated code warning C4996 for releases < 2021.1
|
||||
ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4996)
|
||||
if(MSVC_VERSION LESS 1910)
|
||||
# Disable obsolete warning C4503 popping up on MSVC << 15 2017
|
||||
# https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4503?view=vs-2019
|
||||
# and IE deprecated code warning C4996
|
||||
ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4503 /wd4996)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") # don't add Clang here: issue should be investigated and fixed (workaround for Apple only)
|
||||
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wrange-loop-analysis) # https://github.com/opencv/opencv/issues/18928
|
||||
endif()
|
||||
|
||||
file(GLOB gapi_ext_hdrs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/*.hpp"
|
||||
|
|
@ -52,10 +47,13 @@ file(GLOB gapi_ext_hdrs
|
|||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/infer/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/ocl/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/own/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/plaidml/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/python/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/render/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/s11n/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/streaming/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/plaidml/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/streaming/gstreamer/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/streaming/onevpl/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/util/*.hpp"
|
||||
)
|
||||
|
||||
|
|
@ -80,6 +78,7 @@ set(gapi_srcs
|
|||
src/api/kernels_video.cpp
|
||||
src/api/kernels_nnparsers.cpp
|
||||
src/api/kernels_streaming.cpp
|
||||
src/api/kernels_stereo.cpp
|
||||
src/api/render.cpp
|
||||
src/api/render_ocv.cpp
|
||||
src/api/ginfer.cpp
|
||||
|
|
@ -115,6 +114,7 @@ set(gapi_srcs
|
|||
src/backends/cpu/gcpubackend.cpp
|
||||
src/backends/cpu/gcpukernel.cpp
|
||||
src/backends/cpu/gcpuimgproc.cpp
|
||||
src/backends/cpu/gcpustereo.cpp
|
||||
src/backends/cpu/gcpuvideo.cpp
|
||||
src/backends/cpu/gcpucore.cpp
|
||||
src/backends/cpu/gnnparsers.cpp
|
||||
|
|
@ -125,6 +125,7 @@ set(gapi_srcs
|
|||
src/backends/fluid/gfluidimgproc.cpp
|
||||
src/backends/fluid/gfluidimgproc_func.dispatch.cpp
|
||||
src/backends/fluid/gfluidcore.cpp
|
||||
src/backends/fluid/gfluidcore_func.dispatch.cpp
|
||||
|
||||
# OCL Backend (currently built-in)
|
||||
src/backends/ocl/goclbackend.cpp
|
||||
|
|
@ -162,9 +163,45 @@ set(gapi_srcs
|
|||
|
||||
# Python bridge
|
||||
src/backends/ie/bindings_ie.cpp
|
||||
src/backends/python/gpythonbackend.cpp
|
||||
|
||||
# OpenVPL Streaming source
|
||||
src/streaming/onevpl/source.cpp
|
||||
src/streaming/onevpl/source_priv.cpp
|
||||
src/streaming/onevpl/file_data_provider.cpp
|
||||
src/streaming/onevpl/cfg_params.cpp
|
||||
src/streaming/onevpl/cfg_params_parser.cpp
|
||||
src/streaming/onevpl/utils.cpp
|
||||
src/streaming/onevpl/data_provider_interface_exception.cpp
|
||||
src/streaming/onevpl/accelerators/surface/cpu_frame_adapter.cpp
|
||||
src/streaming/onevpl/accelerators/surface/surface.cpp
|
||||
src/streaming/onevpl/accelerators/surface/surface_pool.cpp
|
||||
src/streaming/onevpl/accelerators/accel_policy_cpu.cpp
|
||||
src/streaming/onevpl/accelerators/accel_policy_dx11.cpp
|
||||
src/streaming/onevpl/engine/engine_session.cpp
|
||||
src/streaming/onevpl/engine/processing_engine_base.cpp
|
||||
src/streaming/onevpl/engine/decode/decode_engine_legacy.cpp
|
||||
src/streaming/onevpl/engine/decode/decode_session.cpp
|
||||
src/streaming/onevpl/demux/async_mfp_demux_data_provider.cpp
|
||||
src/streaming/onevpl/data_provider_dispatcher.cpp
|
||||
|
||||
src/streaming/onevpl/cfg_param_device_selector.cpp
|
||||
src/streaming/onevpl/device_selector_interface.cpp
|
||||
|
||||
# GStreamer Streaming source
|
||||
src/streaming/gstreamer/gstreamer_pipeline_facade.cpp
|
||||
src/streaming/gstreamer/gstreamerpipeline.cpp
|
||||
src/streaming/gstreamer/gstreamersource.cpp
|
||||
src/streaming/gstreamer/gstreamer_buffer_utils.cpp
|
||||
src/streaming/gstreamer/gstreamer_media_adapter.cpp
|
||||
src/streaming/gstreamer/gstreamerenv.cpp
|
||||
|
||||
# Utils (ITT tracing)
|
||||
src/utils/itt.cpp
|
||||
)
|
||||
|
||||
ocv_add_dispatched_file(backends/fluid/gfluidimgproc_func SSE4_1 AVX2)
|
||||
ocv_add_dispatched_file(backends/fluid/gfluidcore_func SSE4_1 AVX2)
|
||||
|
||||
ocv_list_add_prefix(gapi_srcs "${CMAKE_CURRENT_LIST_DIR}/")
|
||||
|
||||
|
|
@ -178,17 +215,33 @@ ocv_module_include_directories("${CMAKE_CURRENT_LIST_DIR}/src")
|
|||
ocv_create_module()
|
||||
|
||||
ocv_target_link_libraries(${the_module} PRIVATE ade)
|
||||
|
||||
if(OPENCV_GAPI_INF_ENGINE)
|
||||
ocv_target_link_libraries(${the_module} PRIVATE ${INF_ENGINE_TARGET})
|
||||
endif()
|
||||
|
||||
if (HAVE_NGRAPH)
|
||||
ocv_target_link_libraries(${the_module} PRIVATE ngraph::ngraph)
|
||||
endif()
|
||||
|
||||
if(HAVE_TBB)
|
||||
ocv_target_link_libraries(${the_module} PRIVATE tbb)
|
||||
endif()
|
||||
|
||||
# TODO: Consider support of ITT in G-API standalone mode.
|
||||
if(CV_TRACE AND HAVE_ITT)
|
||||
ocv_target_compile_definitions(${the_module} PRIVATE -DOPENCV_WITH_ITT=1)
|
||||
ocv_module_include_directories(${ITT_INCLUDE_DIRS})
|
||||
ocv_target_link_libraries(${the_module} PRIVATE ${ITT_LIBRARIES})
|
||||
endif()
|
||||
|
||||
set(__test_extra_deps "")
|
||||
if(OPENCV_GAPI_INF_ENGINE)
|
||||
list(APPEND __test_extra_deps ${INF_ENGINE_TARGET})
|
||||
endif()
|
||||
if(HAVE_NGRAPH)
|
||||
list(APPEND __test_extra_deps ngraph::ngraph)
|
||||
endif()
|
||||
ocv_add_accuracy_tests(${__test_extra_deps})
|
||||
|
||||
# FIXME: test binary is linked with ADE directly since ADE symbols
|
||||
|
|
@ -198,6 +251,9 @@ ocv_add_accuracy_tests(${__test_extra_deps})
|
|||
if(TARGET opencv_test_gapi)
|
||||
target_include_directories(opencv_test_gapi PRIVATE "${CMAKE_CURRENT_LIST_DIR}/src")
|
||||
target_link_libraries(opencv_test_gapi PRIVATE ade)
|
||||
if (HAVE_NGRAPH)
|
||||
ocv_target_compile_definitions(opencv_test_gapi PRIVATE -DHAVE_NGRAPH)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(HAVE_TBB AND TARGET opencv_test_gapi)
|
||||
|
|
@ -222,6 +278,29 @@ if(HAVE_PLAIDML)
|
|||
ocv_target_include_directories(${the_module} SYSTEM PRIVATE ${PLAIDML_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
if(HAVE_GAPI_ONEVPL)
|
||||
if(TARGET opencv_test_gapi)
|
||||
ocv_target_compile_definitions(opencv_test_gapi PRIVATE -DHAVE_ONEVPL)
|
||||
ocv_target_link_libraries(opencv_test_gapi PRIVATE ${VPL_IMPORTED_TARGETS})
|
||||
if(HAVE_D3D11 AND HAVE_OPENCL)
|
||||
ocv_target_include_directories(opencv_test_gapi SYSTEM PRIVATE ${OPENCL_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif()
|
||||
ocv_target_compile_definitions(${the_module} PRIVATE -DHAVE_ONEVPL)
|
||||
ocv_target_link_libraries(${the_module} PRIVATE ${VPL_IMPORTED_TARGETS})
|
||||
if(HAVE_D3D11 AND HAVE_OPENCL)
|
||||
ocv_target_include_directories(${the_module} SYSTEM PRIVATE ${OPENCL_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(HAVE_GSTREAMER)
|
||||
if(TARGET opencv_test_gapi)
|
||||
ocv_target_compile_definitions(opencv_test_gapi PRIVATE -DHAVE_GSTREAMER)
|
||||
ocv_target_link_libraries(opencv_test_gapi PRIVATE ocv.3rdparty.gstreamer)
|
||||
endif()
|
||||
ocv_target_compile_definitions(${the_module} PRIVATE -DHAVE_GSTREAMER)
|
||||
ocv_target_link_libraries(${the_module} PRIVATE ocv.3rdparty.gstreamer)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
# Required for htonl/ntohl on Windows
|
||||
|
|
@ -239,3 +318,27 @@ endif()
|
|||
|
||||
ocv_add_perf_tests()
|
||||
ocv_add_samples()
|
||||
|
||||
|
||||
# Required for sample with inference on host
|
||||
if (TARGET example_gapi_onevpl_infer_single_roi)
|
||||
if(OPENCV_GAPI_INF_ENGINE)
|
||||
ocv_target_link_libraries(example_gapi_onevpl_infer_single_roi PRIVATE ${INF_ENGINE_TARGET})
|
||||
ocv_target_compile_definitions(example_gapi_onevpl_infer_single_roi PRIVATE -DHAVE_INF_ENGINE)
|
||||
endif()
|
||||
if(HAVE_D3D11 AND HAVE_OPENCL)
|
||||
ocv_target_include_directories(example_gapi_onevpl_infer_single_roi SYSTEM PRIVATE ${OPENCL_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# perf test dependencies postprocessing
|
||||
if(HAVE_GAPI_ONEVPL)
|
||||
# NB: TARGET opencv_perf_gapi doesn't exist before `ocv_add_perf_tests`
|
||||
if(TARGET opencv_perf_gapi)
|
||||
ocv_target_compile_definitions(opencv_perf_gapi PRIVATE -DHAVE_ONEVPL)
|
||||
ocv_target_link_libraries(opencv_perf_gapi PRIVATE ${VPL_IMPORTED_TARGETS})
|
||||
if(HAVE_D3D11 AND HAVE_OPENCL)
|
||||
ocv_target_include_directories(opencv_perf_gapi SYSTEM PRIVATE ${OPENCL_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -20,12 +20,26 @@ endif()
|
|||
set(ADE_root "${ade_src_dir}/${ade_subdir}/sources/ade")
|
||||
file(GLOB_RECURSE ADE_sources "${ADE_root}/source/*.cpp")
|
||||
file(GLOB_RECURSE ADE_include "${ADE_root}/include/ade/*.hpp")
|
||||
add_library(ade STATIC ${ADE_include} ${ADE_sources})
|
||||
add_library(ade STATIC ${OPENCV_3RDPARTY_EXCLUDE_FROM_ALL}
|
||||
${ADE_include}
|
||||
${ADE_sources}
|
||||
)
|
||||
target_include_directories(ade PUBLIC $<BUILD_INTERFACE:${ADE_root}/include>)
|
||||
set_target_properties(ade PROPERTIES POSITION_INDEPENDENT_CODE True)
|
||||
set_target_properties(ade PROPERTIES
|
||||
POSITION_INDEPENDENT_CODE True
|
||||
OUTPUT_NAME ade
|
||||
DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}"
|
||||
COMPILE_PDB_NAME ade
|
||||
COMPILE_PDB_NAME_DEBUG "ade${OPENCV_DEBUG_POSTFIX}"
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${3P_LIBRARY_OUTPUT_PATH}
|
||||
)
|
||||
|
||||
if(ENABLE_SOLUTION_FOLDERS)
|
||||
set_target_properties(ade PROPERTIES FOLDER "3rdparty")
|
||||
endif()
|
||||
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
ocv_install_target(ade EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev)
|
||||
ocv_install_target(ade EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev OPTIONAL)
|
||||
endif()
|
||||
|
||||
ocv_install_3rdparty_licenses(ade "${ade_src_dir}/${ade_subdir}/LICENSE")
|
||||
|
|
|
|||
|
|
@ -32,3 +32,10 @@ if(WITH_PLAIDML)
|
|||
set(HAVE_PLAIDML TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_GAPI_ONEVPL)
|
||||
find_package(VPL)
|
||||
if(VPL_FOUND)
|
||||
set(HAVE_GAPI_ONEVPL TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -6,6 +6,13 @@ if (NOT TARGET ade )
|
|||
find_package(ade 0.1.0 REQUIRED)
|
||||
endif()
|
||||
|
||||
if (WITH_GAPI_ONEVPL)
|
||||
find_package(VPL)
|
||||
if(VPL_FOUND)
|
||||
set(HAVE_GAPI_ONEVPL TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(FLUID_TARGET fluid)
|
||||
set(FLUID_ROOT "${CMAKE_CURRENT_LIST_DIR}/../")
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ an external parameter.
|
|||
G-API provides a macro to define a new kernel interface --
|
||||
G_TYPED_KERNEL():
|
||||
|
||||
@snippet modules/gapi/samples/kernel_api_snippets.cpp filter2d_api
|
||||
@snippet samples/cpp/tutorial_code/gapi/doc_snippets/kernel_api_snippets.cpp filter2d_api
|
||||
|
||||
This macro is a shortcut to a new type definition. It takes three
|
||||
arguments to register a new type, and requires type body to be present
|
||||
|
|
@ -81,18 +81,18 @@ Once a kernel is defined, it can be used in pipelines with special,
|
|||
G-API-supplied method "::on()". This method has the same signature as
|
||||
defined in kernel, so this code:
|
||||
|
||||
@snippet modules/gapi/samples/kernel_api_snippets.cpp filter2d_on
|
||||
@snippet samples/cpp/tutorial_code/gapi/doc_snippets/kernel_api_snippets.cpp filter2d_on
|
||||
|
||||
is a perfectly legal construction. This example has some verbosity,
|
||||
though, so usually a kernel declaration comes with a C++ function
|
||||
wrapper ("factory method") which enables optional parameters, more
|
||||
compact syntax, Doxygen comments, etc:
|
||||
|
||||
@snippet modules/gapi/samples/kernel_api_snippets.cpp filter2d_wrap
|
||||
@snippet samples/cpp/tutorial_code/gapi/doc_snippets/kernel_api_snippets.cpp filter2d_wrap
|
||||
|
||||
so now it can be used like:
|
||||
|
||||
@snippet modules/gapi/samples/kernel_api_snippets.cpp filter2d_wrap_call
|
||||
@snippet samples/cpp/tutorial_code/gapi/doc_snippets/kernel_api_snippets.cpp filter2d_wrap_call
|
||||
|
||||
# Extra information {#gapi_kernel_supp_info}
|
||||
|
||||
|
|
@ -143,7 +143,7 @@ For example, the aforementioned `Filter2D` is implemented in
|
|||
"reference" CPU (OpenCV) plugin this way (*NOTE* -- this is a
|
||||
simplified form with improper border handling):
|
||||
|
||||
@snippet modules/gapi/samples/kernel_api_snippets.cpp filter2d_ocv
|
||||
@snippet samples/cpp/tutorial_code/gapi/doc_snippets/kernel_api_snippets.cpp filter2d_ocv
|
||||
|
||||
Note how CPU (OpenCV) plugin has transformed the original kernel
|
||||
signature:
|
||||
|
|
@ -174,7 +174,7 @@ point extraction to an STL vector:
|
|||
A compound kernel _implementation_ can be defined using a generic
|
||||
macro GAPI_COMPOUND_KERNEL():
|
||||
|
||||
@snippet modules/gapi/samples/kernel_api_snippets.cpp compound
|
||||
@snippet samples/cpp/tutorial_code/gapi/doc_snippets/kernel_api_snippets.cpp compound
|
||||
|
||||
<!-- TODO: ADD on how Compound kernels may simplify dispatching -->
|
||||
<!-- TODO: Add details on when expand() is called! -->
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2018 Intel Corporation
|
||||
// Copyright (C) 2018-2021 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_HPP
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
@}
|
||||
@defgroup gapi_std_backends G-API Standard Backends
|
||||
@defgroup gapi_compile_args G-API Graph Compilation Arguments
|
||||
@defgroup gapi_serialization G-API Serialization functionality
|
||||
@}
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@
|
|||
*/
|
||||
|
||||
namespace cv { namespace gapi {
|
||||
/**
|
||||
* @brief This namespace contains G-API Operation Types for OpenCV
|
||||
* Core module functionality.
|
||||
*/
|
||||
namespace core {
|
||||
using GMat2 = std::tuple<GMat,GMat>;
|
||||
using GMat3 = std::tuple<GMat,GMat,GMat>; // FIXME: how to avoid this?
|
||||
|
|
@ -53,6 +57,7 @@ namespace core {
|
|||
|
||||
G_TYPED_KERNEL(GAddC, <GMat(GMat, GScalar, int)>, "org.opencv.core.math.addC") {
|
||||
static GMatDesc outMeta(GMatDesc a, GScalarDesc, int ddepth) {
|
||||
GAPI_Assert(a.chan <= 4);
|
||||
return a.withDepth(ddepth);
|
||||
}
|
||||
};
|
||||
|
|
@ -298,8 +303,8 @@ namespace core {
|
|||
}
|
||||
};
|
||||
|
||||
G_TYPED_KERNEL(GAbsDiffC, <GMat(GMat, GScalar)>, "org.opencv.core.matrixop.absdiffC") {
|
||||
static GMatDesc outMeta(GMatDesc a, GScalarDesc) {
|
||||
G_TYPED_KERNEL(GAbsDiffC, <GMat(GMat,GScalar)>, "org.opencv.core.matrixop.absdiffC") {
|
||||
static GMatDesc outMeta(const GMatDesc& a, const GScalarDesc&) {
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
|
@ -394,7 +399,7 @@ namespace core {
|
|||
};
|
||||
|
||||
G_TYPED_KERNEL(GResize, <GMat(GMat,Size,double,double,int)>, "org.opencv.core.transform.resize") {
|
||||
static GMatDesc outMeta(GMatDesc in, Size sz, double fx, double fy, int) {
|
||||
static GMatDesc outMeta(GMatDesc in, Size sz, double fx, double fy, int /*interp*/) {
|
||||
if (sz.width != 0 && sz.height != 0)
|
||||
{
|
||||
return in.withSize(sz);
|
||||
|
|
@ -575,6 +580,12 @@ namespace core {
|
|||
return std::make_tuple(empty_gopaque_desc(), empty_array_desc(), empty_array_desc());
|
||||
}
|
||||
};
|
||||
|
||||
G_TYPED_KERNEL(GTranspose, <GMat(GMat)>, "org.opencv.core.transpose") {
|
||||
static GMatDesc outMeta(GMatDesc in) {
|
||||
return in.withSize({in.size.height, in.size.width});
|
||||
}
|
||||
};
|
||||
} // namespace core
|
||||
|
||||
namespace streaming {
|
||||
|
|
@ -591,6 +602,12 @@ G_TYPED_KERNEL(GSizeR, <GOpaque<Size>(GOpaque<Rect>)>, "org.opencv.streaming.siz
|
|||
return empty_gopaque_desc();
|
||||
}
|
||||
};
|
||||
|
||||
G_TYPED_KERNEL(GSizeMF, <GOpaque<Size>(GFrame)>, "org.opencv.streaming.sizeMF") {
|
||||
static GOpaqueDesc outMeta(const GFrameDesc&) {
|
||||
return empty_gopaque_desc();
|
||||
}
|
||||
};
|
||||
} // namespace streaming
|
||||
|
||||
//! @addtogroup gapi_math
|
||||
|
|
@ -639,7 +656,7 @@ Supported matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref
|
|||
@param ddepth optional depth of the output matrix.
|
||||
@sa sub, addWeighted
|
||||
*/
|
||||
GAPI_EXPORTS GMat addC(const GMat& src1, const GScalar& c, int ddepth = -1);
|
||||
GAPI_EXPORTS_W GMat addC(const GMat& src1, const GScalar& c, int ddepth = -1);
|
||||
//! @overload
|
||||
GAPI_EXPORTS GMat addC(const GScalar& c, const GMat& src1, int ddepth = -1);
|
||||
|
||||
|
|
@ -754,7 +771,10 @@ GAPI_EXPORTS GMat mulC(const GScalar& multiplier, const GMat& src, int ddepth =
|
|||
The function divides one matrix by another:
|
||||
\f[\texttt{dst(I) = saturate(src1(I)*scale/src2(I))}\f]
|
||||
|
||||
When src2(I) is zero, dst(I) will also be zero. Different channels of
|
||||
For integer types when src2(I) is zero, dst(I) will also be zero.
|
||||
Floating point case returns Inf/NaN (according to IEEE).
|
||||
|
||||
Different channels of
|
||||
multi-channel matrices are processed independently.
|
||||
The matrices can be single or multi channel. Output matrix must have the same size and depth as src.
|
||||
|
||||
|
|
@ -1484,7 +1504,7 @@ enlarge an image, it will generally look best with cv::INTER_CUBIC (slow) or cv:
|
|||
|
||||
@sa warpAffine, warpPerspective, remap, resizeP
|
||||
*/
|
||||
GAPI_EXPORTS GMat resize(const GMat& src, const Size& dsize, double fx = 0, double fy = 0, int interpolation = INTER_LINEAR);
|
||||
GAPI_EXPORTS_W GMat resize(const GMat& src, const Size& dsize, double fx = 0, double fy = 0, int interpolation = INTER_LINEAR);
|
||||
|
||||
/** @brief Resizes a planar image.
|
||||
|
||||
|
|
@ -1903,14 +1923,14 @@ kmeans(const GMat& data, const int K, const GMat& bestLabels,
|
|||
- Function textual ID is "org.opencv.core.kmeansNDNoInit"
|
||||
- #KMEANS_USE_INITIAL_LABELS flag must not be set while using this overload.
|
||||
*/
|
||||
GAPI_EXPORTS std::tuple<GOpaque<double>,GMat,GMat>
|
||||
GAPI_EXPORTS_W std::tuple<GOpaque<double>,GMat,GMat>
|
||||
kmeans(const GMat& data, const int K, const TermCriteria& criteria, const int attempts,
|
||||
const KmeansFlags flags);
|
||||
|
||||
/** @overload
|
||||
@note Function textual ID is "org.opencv.core.kmeans2D"
|
||||
*/
|
||||
GAPI_EXPORTS std::tuple<GOpaque<double>,GArray<int>,GArray<Point2f>>
|
||||
GAPI_EXPORTS_W std::tuple<GOpaque<double>,GArray<int>,GArray<Point2f>>
|
||||
kmeans(const GArray<Point2f>& data, const int K, const GArray<int>& bestLabels,
|
||||
const TermCriteria& criteria, const int attempts, const KmeansFlags flags);
|
||||
|
||||
|
|
@ -1921,6 +1941,21 @@ GAPI_EXPORTS std::tuple<GOpaque<double>,GArray<int>,GArray<Point3f>>
|
|||
kmeans(const GArray<Point3f>& data, const int K, const GArray<int>& bestLabels,
|
||||
const TermCriteria& criteria, const int attempts, const KmeansFlags flags);
|
||||
|
||||
|
||||
/** @brief Transposes a matrix.
|
||||
|
||||
The function transposes the matrix:
|
||||
\f[\texttt{dst} (i,j) = \texttt{src} (j,i)\f]
|
||||
|
||||
@note
|
||||
- Function textual ID is "org.opencv.core.transpose"
|
||||
- No complex conjugation is done in case of a complex matrix. It should be done separately if needed.
|
||||
|
||||
@param src input array.
|
||||
*/
|
||||
GAPI_EXPORTS GMat transpose(const GMat& src);
|
||||
|
||||
|
||||
namespace streaming {
|
||||
/** @brief Gets dimensions from Mat.
|
||||
|
||||
|
|
@ -1929,7 +1964,7 @@ namespace streaming {
|
|||
@param src Input tensor
|
||||
@return Size (tensor dimensions).
|
||||
*/
|
||||
GAPI_EXPORTS GOpaque<Size> size(const GMat& src);
|
||||
GAPI_EXPORTS_W GOpaque<Size> size(const GMat& src);
|
||||
|
||||
/** @overload
|
||||
Gets dimensions from rectangle.
|
||||
|
|
@ -1939,7 +1974,16 @@ Gets dimensions from rectangle.
|
|||
@param r Input rectangle.
|
||||
@return Size (rectangle dimensions).
|
||||
*/
|
||||
GAPI_EXPORTS GOpaque<Size> size(const GOpaque<Rect>& r);
|
||||
GAPI_EXPORTS_W GOpaque<Size> size(const GOpaque<Rect>& r);
|
||||
|
||||
/** @brief Gets dimensions from MediaFrame.
|
||||
|
||||
@note Function textual ID is "org.opencv.streaming.sizeMF"
|
||||
|
||||
@param src Input frame
|
||||
@return Size (frame dimensions).
|
||||
*/
|
||||
GAPI_EXPORTS GOpaque<Size> size(const GFrame& src);
|
||||
} //namespace streaming
|
||||
} //namespace gapi
|
||||
} //namespace cv
|
||||
|
|
|
|||
|
|
@ -28,18 +28,14 @@ namespace gimpl
|
|||
{
|
||||
// Forward-declare an internal class
|
||||
class GCPUExecutable;
|
||||
|
||||
namespace render
|
||||
{
|
||||
namespace ocv
|
||||
{
|
||||
class GRenderExecutable;
|
||||
}
|
||||
}
|
||||
} // namespace gimpl
|
||||
|
||||
namespace gapi
|
||||
{
|
||||
/**
|
||||
* @brief This namespace contains G-API CPU backend functions,
|
||||
* structures, and symbols.
|
||||
*/
|
||||
namespace cpu
|
||||
{
|
||||
/**
|
||||
|
|
@ -129,7 +125,6 @@ protected:
|
|||
std::unordered_map<std::size_t, GRunArgP> m_results;
|
||||
|
||||
friend class gimpl::GCPUExecutable;
|
||||
friend class gimpl::render::ocv::GRenderExecutable;
|
||||
};
|
||||
|
||||
class GAPI_EXPORTS GCPUKernel
|
||||
|
|
@ -190,6 +185,11 @@ template<> struct get_in<cv::GArray<cv::GScalar> >: public get_in<cv::GArray<cv:
|
|||
{
|
||||
};
|
||||
|
||||
// FIXME(dm): GArray<vector<U>>/GArray<GArray<U>> conversion should be done more gracefully in the system
|
||||
template<typename U> struct get_in<cv::GArray<cv::GArray<U>> >: public get_in<cv::GArray<std::vector<U>> >
|
||||
{
|
||||
};
|
||||
|
||||
//FIXME(dm): GOpaque<Mat>/GOpaque<GMat> conversion should be done more gracefully in the system
|
||||
template<> struct get_in<cv::GOpaque<cv::GMat> >: public get_in<cv::GOpaque<cv::Mat> >
|
||||
{
|
||||
|
|
@ -487,7 +487,7 @@ public:
|
|||
#define GAPI_OCV_KERNEL_ST(Name, API, State) \
|
||||
struct Name: public cv::GCPUStKernelImpl<Name, API, State> \
|
||||
|
||||
|
||||
/// @private
|
||||
class gapi::cpu::GOCVFunctor : public gapi::GFunctor
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_CPU_STEREO_API_HPP
|
||||
#define OPENCV_GAPI_CPU_STEREO_API_HPP
|
||||
|
||||
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace calib3d {
|
||||
namespace cpu {
|
||||
|
||||
GAPI_EXPORTS GKernelPackage kernels();
|
||||
|
||||
/** @brief Structure for the Stereo operation initialization parameters.*/
|
||||
struct GAPI_EXPORTS StereoInitParam {
|
||||
StereoInitParam(int nD, int bS, double bL, double f):
|
||||
numDisparities(nD), blockSize(bS), baseline(bL), focus(f) {}
|
||||
|
||||
StereoInitParam() = default;
|
||||
|
||||
int numDisparities = 0;
|
||||
int blockSize = 21;
|
||||
double baseline = 63.5;
|
||||
double focus = 3.6;
|
||||
};
|
||||
|
||||
} // namespace cpu
|
||||
} // namespace calib3d
|
||||
} // namespace gapi
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<> struct CompileArgTag<cv::gapi::calib3d::cpu::StereoInitParam> {
|
||||
static const char* tag() {
|
||||
return "org.opencv.stereoInit";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace cv
|
||||
|
||||
|
||||
#endif // OPENCV_GAPI_CPU_STEREO_API_HPP
|
||||
|
|
@ -25,7 +25,7 @@ namespace fluid {
|
|||
struct Border
|
||||
{
|
||||
// This constructor is required to support existing kernels which are part of G-API
|
||||
Border(int _type, cv::Scalar _val) : type(_type), value(_val) {};
|
||||
Border(int _type, cv::Scalar _val) : type(_type), value(_val) {}
|
||||
|
||||
int type;
|
||||
cv::Scalar value;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ namespace cv {
|
|||
|
||||
namespace gapi
|
||||
{
|
||||
/**
|
||||
* @brief This namespace contains G-API Fluid backend functions, structures, and symbols.
|
||||
*/
|
||||
namespace fluid
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2018-2020 Intel Corporation
|
||||
// Copyright (C) 2018-2021 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GARG_HPP
|
||||
|
|
@ -171,7 +171,7 @@ using GRunArgs = std::vector<GRunArg>;
|
|||
* It's an ordinary overload of addition assignment operator.
|
||||
*
|
||||
* Example of usage:
|
||||
* @snippet dynamic_graph.cpp GRunArgs usage
|
||||
* @snippet samples/cpp/tutorial_code/gapi/doc_snippets/dynamic_graph_snippets.cpp GRunArgs usage
|
||||
*
|
||||
*/
|
||||
inline GRunArgs& operator += (GRunArgs &lhs, const GRunArgs &rhs)
|
||||
|
|
@ -223,7 +223,7 @@ using GRunArgsP = std::vector<GRunArgP>;
|
|||
* It's an ordinary overload of addition assignment operator.
|
||||
*
|
||||
* Example of usage:
|
||||
* @snippet dynamic_graph.cpp GRunArgsP usage
|
||||
* @snippet samples/cpp/tutorial_code/gapi/doc_snippets/dynamic_graph_snippets.cpp GRunArgsP usage
|
||||
*
|
||||
*/
|
||||
inline GRunArgsP& operator += (GRunArgsP &lhs, const GRunArgsP &rhs)
|
||||
|
|
@ -235,8 +235,39 @@ inline GRunArgsP& operator += (GRunArgsP &lhs, const GRunArgsP &rhs)
|
|||
|
||||
namespace gapi
|
||||
{
|
||||
GAPI_EXPORTS cv::GRunArgsP bind(cv::GRunArgs &results);
|
||||
GAPI_EXPORTS cv::GRunArg bind(cv::GRunArgP &out); // FIXME: think more about it
|
||||
/**
|
||||
* \addtogroup gapi_serialization
|
||||
* @{
|
||||
*
|
||||
* @brief G-API functions and classes for serialization and deserialization.
|
||||
*/
|
||||
/** @brief Wraps deserialized output GRunArgs to GRunArgsP which can be used by GCompiled.
|
||||
*
|
||||
* Since it's impossible to get modifiable output arguments from deserialization
|
||||
* it needs to be wrapped by this function.
|
||||
*
|
||||
* Example of usage:
|
||||
* @snippet samples/cpp/tutorial_code/gapi/doc_snippets/api_ref_snippets.cpp bind after deserialization
|
||||
*
|
||||
* @param out_args deserialized GRunArgs.
|
||||
* @return the same GRunArgs wrapped in GRunArgsP.
|
||||
* @see deserialize
|
||||
*/
|
||||
GAPI_EXPORTS cv::GRunArgsP bind(cv::GRunArgs &out_args);
|
||||
/** @brief Wraps output GRunArgsP available during graph execution to GRunArgs which can be serialized.
|
||||
*
|
||||
* GRunArgsP is pointer-to-value, so to be serialized they need to be binded to real values
|
||||
* which this function does.
|
||||
*
|
||||
* Example of usage:
|
||||
* @snippet samples/cpp/tutorial_code/gapi/doc_snippets/api_ref_snippets.cpp bind before serialization
|
||||
*
|
||||
* @param out output GRunArgsP available during graph execution.
|
||||
* @return the same GRunArgsP wrapped in serializable GRunArgs.
|
||||
* @see serialize
|
||||
*/
|
||||
GAPI_EXPORTS cv::GRunArg bind(cv::GRunArgP &out); // FIXME: think more about it
|
||||
/** @} */
|
||||
}
|
||||
|
||||
template<typename... Ts> inline GRunArgs gin(const Ts&... args)
|
||||
|
|
@ -249,6 +280,30 @@ template<typename... Ts> inline GRunArgsP gout(Ts&... args)
|
|||
return GRunArgsP{ GRunArgP(detail::wrap_host_helper<Ts>::wrap_out(args))... };
|
||||
}
|
||||
|
||||
struct GTypeInfo;
|
||||
using GTypesInfo = std::vector<GTypeInfo>;
|
||||
|
||||
// FIXME: Needed for python bridge, must be moved to more appropriate header
|
||||
namespace detail {
|
||||
struct ExtractArgsCallback
|
||||
{
|
||||
cv::GRunArgs operator()(const cv::GTypesInfo& info) const { return c(info); }
|
||||
using CallBackT = std::function<cv::GRunArgs(const cv::GTypesInfo& info)>;
|
||||
CallBackT c;
|
||||
};
|
||||
|
||||
struct ExtractMetaCallback
|
||||
{
|
||||
cv::GMetaArgs operator()(const cv::GTypesInfo& info) const { return c(info); }
|
||||
using CallBackT = std::function<cv::GMetaArgs(const cv::GTypesInfo& info)>;
|
||||
CallBackT c;
|
||||
};
|
||||
|
||||
void constructGraphOutputs(const cv::GTypesInfo &out_info,
|
||||
cv::GRunArgs &args,
|
||||
cv::GRunArgsP &outs);
|
||||
} // namespace detail
|
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_GARG_HPP
|
||||
|
|
|
|||
|
|
@ -35,14 +35,14 @@ template<typename T> class GArray;
|
|||
* \addtogroup gapi_meta_args
|
||||
* @{
|
||||
*/
|
||||
struct GArrayDesc
|
||||
struct GAPI_EXPORTS_W_SIMPLE GArrayDesc
|
||||
{
|
||||
// FIXME: Body
|
||||
// FIXME: Also implement proper operator== then
|
||||
bool operator== (const GArrayDesc&) const { return true; }
|
||||
};
|
||||
template<typename U> GArrayDesc descr_of(const std::vector<U> &) { return {};}
|
||||
static inline GArrayDesc empty_array_desc() {return {}; }
|
||||
GAPI_EXPORTS_W inline GArrayDesc empty_array_desc() {return {}; }
|
||||
/** @} */
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const cv::GArrayDesc &desc);
|
||||
|
|
@ -236,7 +236,7 @@ namespace detail
|
|||
class VectorRef
|
||||
{
|
||||
std::shared_ptr<BasicVectorRef> m_ref;
|
||||
cv::detail::OpaqueKind m_kind;
|
||||
cv::detail::OpaqueKind m_kind = cv::detail::OpaqueKind::CV_UNKNOWN;
|
||||
|
||||
template<typename T> inline void check() const
|
||||
{
|
||||
|
|
@ -246,12 +246,18 @@ namespace detail
|
|||
|
||||
public:
|
||||
VectorRef() = default;
|
||||
template<typename T> explicit VectorRef(const std::vector<T>& vec) :
|
||||
m_ref(new VectorRefT<T>(vec)), m_kind(GOpaqueTraits<T>::kind) {}
|
||||
template<typename T> explicit VectorRef(std::vector<T>& vec) :
|
||||
m_ref(new VectorRefT<T>(vec)), m_kind(GOpaqueTraits<T>::kind) {}
|
||||
template<typename T> explicit VectorRef(std::vector<T>&& vec) :
|
||||
m_ref(new VectorRefT<T>(std::move(vec))), m_kind(GOpaqueTraits<T>::kind) {}
|
||||
template<typename T> explicit VectorRef(const std::vector<T>& vec)
|
||||
: m_ref(new VectorRefT<T>(vec))
|
||||
, m_kind(GOpaqueTraits<T>::kind)
|
||||
{}
|
||||
template<typename T> explicit VectorRef(std::vector<T>& vec)
|
||||
: m_ref(new VectorRefT<T>(vec))
|
||||
, m_kind(GOpaqueTraits<T>::kind)
|
||||
{}
|
||||
template<typename T> explicit VectorRef(std::vector<T>&& vec)
|
||||
: m_ref(new VectorRefT<T>(std::move(vec)))
|
||||
, m_kind(GOpaqueTraits<T>::kind)
|
||||
{}
|
||||
|
||||
cv::detail::OpaqueKind getKind() const
|
||||
{
|
||||
|
|
@ -321,9 +327,10 @@ namespace detail
|
|||
# define FLATTEN_NS cv
|
||||
#endif
|
||||
template<class T> struct flatten_g;
|
||||
template<> struct flatten_g<cv::GMat> { using type = FLATTEN_NS::Mat; };
|
||||
template<> struct flatten_g<cv::GScalar> { using type = FLATTEN_NS::Scalar; };
|
||||
template<class T> struct flatten_g { using type = T; };
|
||||
template<> struct flatten_g<cv::GMat> { using type = FLATTEN_NS::Mat; };
|
||||
template<> struct flatten_g<cv::GScalar> { using type = FLATTEN_NS::Scalar; };
|
||||
template<class T> struct flatten_g<GArray<T>> { using type = std::vector<T>; };
|
||||
template<class T> struct flatten_g { using type = T; };
|
||||
#undef FLATTEN_NS
|
||||
// FIXME: the above mainly duplicates "ProtoToParam" thing from gtyped.hpp
|
||||
// but I decided not to include gtyped here - probably worth moving that stuff
|
||||
|
|
@ -333,21 +340,79 @@ namespace detail
|
|||
/** \addtogroup gapi_data_objects
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief `cv::GArray<T>` template class represents a list of objects
|
||||
* of class `T` in the graph.
|
||||
*
|
||||
* `cv::GArray<T>` describes a functional relationship between
|
||||
* operations consuming and producing arrays of objects of class
|
||||
* `T`. The primary purpose of `cv::GArray<T>` is to represent a
|
||||
* dynamic list of objects -- where the size of the list is not known
|
||||
* at the graph construction or compile time. Examples include: corner
|
||||
* and feature detectors (`cv::GArray<cv::Point>`), object detection
|
||||
* and tracking results (`cv::GArray<cv::Rect>`). Programmers can use
|
||||
* their own types with `cv::GArray<T>` in the custom operations.
|
||||
*
|
||||
* Similar to `cv::GScalar`, `cv::GArray<T>` may be value-initialized
|
||||
* -- in this case a graph-constant value is associated with the object.
|
||||
*
|
||||
* `GArray<T>` is a virtual counterpart of `std::vector<T>`, which is
|
||||
* usually used to represent the `GArray<T>` data in G-API during the
|
||||
* execution.
|
||||
*
|
||||
* @sa `cv::GOpaque<T>`
|
||||
*/
|
||||
template<typename T> class GArray
|
||||
{
|
||||
public:
|
||||
// Host type (or Flat type) - the type this GArray is actually
|
||||
// specified to.
|
||||
/// @private
|
||||
using HT = typename detail::flatten_g<typename std::decay<T>::type>::type;
|
||||
|
||||
/**
|
||||
* @brief Constructs a value-initialized `cv::GArray<T>`
|
||||
*
|
||||
* `cv::GArray<T>` objects may have their values
|
||||
* be associated at graph construction time. It is useful when
|
||||
* some operation has a `cv::GArray<T>` input which doesn't change during
|
||||
* the program execution, and is set only once. In this case,
|
||||
* there is no need to declare such `cv::GArray<T>` as a graph input.
|
||||
*
|
||||
* @note The value of `cv::GArray<T>` may be overwritten by assigning some
|
||||
* other `cv::GArray<T>` to the object using `operator=` -- on the
|
||||
* assigment, the old association or value is discarded.
|
||||
*
|
||||
* @param v a std::vector<T> to associate with this
|
||||
* `cv::GArray<T>` object. Vector data is copied into the
|
||||
* `cv::GArray<T>` (no reference to the passed data is held).
|
||||
*/
|
||||
explicit GArray(const std::vector<HT>& v) // Constant value constructor
|
||||
: m_ref(detail::GArrayU(detail::VectorRef(v))) { putDetails(); }
|
||||
|
||||
/**
|
||||
* @overload
|
||||
* @brief Constructs a value-initialized `cv::GArray<T>`
|
||||
*
|
||||
* @param v a std::vector<T> to associate with this
|
||||
* `cv::GArray<T>` object. Vector data is moved into the `cv::GArray<T>`.
|
||||
*/
|
||||
explicit GArray(std::vector<HT>&& v) // Move-constructor
|
||||
: m_ref(detail::GArrayU(detail::VectorRef(std::move(v)))) { putDetails(); }
|
||||
GArray() { putDetails(); } // Empty constructor
|
||||
explicit GArray(detail::GArrayU &&ref) // GArrayU-based constructor
|
||||
: m_ref(ref) { putDetails(); } // (used by GCall, not for users)
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty `cv::GArray<T>`
|
||||
*
|
||||
* Normally, empty G-API data objects denote a starting point of
|
||||
* the graph. When an empty `cv::GArray<T>` is assigned to a result
|
||||
* of some operation, it obtains a functional link to this
|
||||
* operation (and is not empty anymore).
|
||||
*/
|
||||
GArray() { putDetails(); } // Empty constructor
|
||||
|
||||
/// @private
|
||||
explicit GArray(detail::GArrayU &&ref) // GArrayU-based constructor
|
||||
: m_ref(ref) { putDetails(); } // (used by GCall, not for users)
|
||||
|
||||
/// @private
|
||||
detail::GArrayU strip() const {
|
||||
|
|
@ -368,8 +433,6 @@ private:
|
|||
detail::GArrayU m_ref;
|
||||
};
|
||||
|
||||
using GArrayP2f = GArray<cv::Point2f>;
|
||||
|
||||
/** @} */
|
||||
|
||||
} // namespace cv
|
||||
|
|
|
|||
|
|
@ -17,6 +17,13 @@
|
|||
|
||||
namespace cv {
|
||||
namespace gapi{
|
||||
|
||||
/**
|
||||
* @brief This namespace contains experimental G-API functionality,
|
||||
* functions or structures in this namespace are subjects to change or
|
||||
* removal in the future releases. This namespace also contains
|
||||
* functions which API is not stabilized yet.
|
||||
*/
|
||||
namespace wip {
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ namespace detail
|
|||
CV_UNKNOWN, // Unknown, generic, opaque-to-GAPI data type unsupported in graph seriallization
|
||||
CV_BOOL, // bool user G-API data
|
||||
CV_INT, // int user G-API data
|
||||
CV_INT64, // int64_t user G-API data
|
||||
CV_DOUBLE, // double user G-API data
|
||||
CV_FLOAT, // float user G-API data
|
||||
CV_UINT64, // uint64_t user G-API data
|
||||
|
|
@ -61,6 +62,7 @@ namespace detail
|
|||
template<typename T> struct GOpaqueTraits;
|
||||
template<typename T> struct GOpaqueTraits { static constexpr const OpaqueKind kind = OpaqueKind::CV_UNKNOWN; };
|
||||
template<> struct GOpaqueTraits<int> { static constexpr const OpaqueKind kind = OpaqueKind::CV_INT; };
|
||||
template<> struct GOpaqueTraits<int64_t> { static constexpr const OpaqueKind kind = OpaqueKind::CV_INT64; };
|
||||
template<> struct GOpaqueTraits<double> { static constexpr const OpaqueKind kind = OpaqueKind::CV_DOUBLE; };
|
||||
template<> struct GOpaqueTraits<float> { static constexpr const OpaqueKind kind = OpaqueKind::CV_FLOAT; };
|
||||
template<> struct GOpaqueTraits<uint64_t> { static constexpr const OpaqueKind kind = OpaqueKind::CV_UINT64; };
|
||||
|
|
@ -132,12 +134,12 @@ namespace detail {
|
|||
*
|
||||
* For example, if an example computation is executed like this:
|
||||
*
|
||||
* @snippet modules/gapi/samples/api_ref_snippets.cpp graph_decl_apply
|
||||
* @snippet samples/cpp/tutorial_code/gapi/doc_snippets/api_ref_snippets.cpp graph_decl_apply
|
||||
*
|
||||
* Extra parameter specifying which kernels to compile with can be
|
||||
* passed like this:
|
||||
*
|
||||
* @snippet modules/gapi/samples/api_ref_snippets.cpp apply_with_param
|
||||
* @snippet samples/cpp/tutorial_code/gapi/doc_snippets/api_ref_snippets.cpp apply_with_param
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
@ -195,6 +197,14 @@ private:
|
|||
|
||||
using GCompileArgs = std::vector<GCompileArg>;
|
||||
|
||||
inline cv::GCompileArgs& operator += ( cv::GCompileArgs &lhs,
|
||||
const cv::GCompileArgs &rhs)
|
||||
{
|
||||
lhs.reserve(lhs.size() + rhs.size());
|
||||
lhs.insert(lhs.end(), rhs.begin(), rhs.end());
|
||||
return lhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wraps a list of arguments (a parameter pack) into a vector of
|
||||
* compilation arguments (cv::GCompileArg).
|
||||
|
|
|
|||
|
|
@ -61,11 +61,11 @@ namespace s11n {
|
|||
* executed. The below example expresses calculation of Sobel operator
|
||||
* for edge detection (\f$G = \sqrt{G_x^2 + G_y^2}\f$):
|
||||
*
|
||||
* @snippet modules/gapi/samples/api_ref_snippets.cpp graph_def
|
||||
* @snippet samples/cpp/tutorial_code/gapi/doc_snippets/api_ref_snippets.cpp graph_def
|
||||
*
|
||||
* Full pipeline can be now captured with this object declaration:
|
||||
*
|
||||
* @snippet modules/gapi/samples/api_ref_snippets.cpp graph_cap_full
|
||||
* @snippet samples/cpp/tutorial_code/gapi/doc_snippets/api_ref_snippets.cpp graph_cap_full
|
||||
*
|
||||
* Input/output data objects on which a call graph should be
|
||||
* reconstructed are passed using special wrappers cv::GIn and
|
||||
|
|
@ -78,7 +78,7 @@ namespace s11n {
|
|||
* expects that image gradients are already pre-calculated may be
|
||||
* defined like this:
|
||||
*
|
||||
* @snippet modules/gapi/samples/api_ref_snippets.cpp graph_cap_sub
|
||||
* @snippet samples/cpp/tutorial_code/gapi/doc_snippets/api_ref_snippets.cpp graph_cap_sub
|
||||
*
|
||||
* The resulting graph would expect two inputs and produce one
|
||||
* output. In this case, it doesn't matter if gx/gy data objects are
|
||||
|
|
@ -130,7 +130,7 @@ public:
|
|||
* Graph can be defined in-place directly at the moment of its
|
||||
* construction with a lambda:
|
||||
*
|
||||
* @snippet modules/gapi/samples/api_ref_snippets.cpp graph_gen
|
||||
* @snippet samples/cpp/tutorial_code/gapi/doc_snippets/api_ref_snippets.cpp graph_gen
|
||||
*
|
||||
* This may be useful since all temporary objects (cv::GMats) and
|
||||
* namespaces can be localized to scope of lambda, without
|
||||
|
|
@ -258,7 +258,8 @@ public:
|
|||
void apply(GRunArgs &&ins, GRunArgsP &&outs, GCompileArgs &&args = {}); // Arg-to-arg overload
|
||||
|
||||
/// @private -- Exclude this function from OpenCV documentation
|
||||
GAPI_WRAP GRunArgs apply(GRunArgs &&ins, GCompileArgs &&args = {});
|
||||
GAPI_WRAP GRunArgs apply(const cv::detail::ExtractArgsCallback &callback,
|
||||
GCompileArgs &&args = {});
|
||||
|
||||
/// @private -- Exclude this function from OpenCV documentation
|
||||
void apply(const std::vector<cv::Mat>& ins, // Compatibility overload
|
||||
|
|
@ -459,6 +460,10 @@ public:
|
|||
*/
|
||||
GAPI_WRAP GStreamingCompiled compileStreaming(GCompileArgs &&args = {});
|
||||
|
||||
/// @private -- Exclude this function from OpenCV documentation
|
||||
GAPI_WRAP GStreamingCompiled compileStreaming(const cv::detail::ExtractMetaCallback &callback,
|
||||
GCompileArgs &&args = {});
|
||||
|
||||
// 2. Direct metadata version
|
||||
/**
|
||||
* @overload
|
||||
|
|
|
|||
|
|
@ -28,14 +28,54 @@ struct GOrigin;
|
|||
/** \addtogroup gapi_data_objects
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief GFrame class represents an image or media frame in the graph.
|
||||
*
|
||||
* GFrame doesn't store any data itself, instead it describes a
|
||||
* functional relationship between operations consuming and producing
|
||||
* GFrame objects.
|
||||
*
|
||||
* GFrame is introduced to handle various media formats (e.g., NV12 or
|
||||
* I420) under the same type. Various image formats may differ in the
|
||||
* number of planes (e.g. two for NV12, three for I420) and the pixel
|
||||
* layout inside. GFrame type allows to handle these media formats in
|
||||
* the graph uniformly -- the graph structure will not change if the
|
||||
* media format changes, e.g. a different camera or decoder is used
|
||||
* with the same graph. G-API provides a number of operations which
|
||||
* operate directly on GFrame, like `infer<>()` or
|
||||
* renderFrame(); these operations are expected to handle different
|
||||
* media formats inside. There is also a number of accessor
|
||||
* operations like BGR(), Y(), UV() -- these operations provide
|
||||
* access to frame's data in the familiar cv::GMat form, which can be
|
||||
* used with the majority of the existing G-API operations. These
|
||||
* accessor functions may perform color space converion on the fly if
|
||||
* the image format of the GFrame they are applied to differs from the
|
||||
* operation's semantic (e.g. the BGR() accessor is called on an NV12
|
||||
* image frame).
|
||||
*
|
||||
* GFrame is a virtual counterpart of cv::MediaFrame.
|
||||
*
|
||||
* @sa cv::MediaFrame, cv::GFrameDesc, BGR(), Y(), UV(), infer<>().
|
||||
*/
|
||||
class GAPI_EXPORTS_W_SIMPLE GFrame
|
||||
{
|
||||
public:
|
||||
GAPI_WRAP GFrame(); // Empty constructor
|
||||
GFrame(const GNode &n, std::size_t out); // Operation result constructor
|
||||
/**
|
||||
* @brief Constructs an empty GFrame
|
||||
*
|
||||
* Normally, empty G-API data objects denote a starting point of
|
||||
* the graph. When an empty GFrame is assigned to a result of some
|
||||
* operation, it obtains a functional link to this operation (and
|
||||
* is not empty anymore).
|
||||
*/
|
||||
GAPI_WRAP GFrame(); // Empty constructor
|
||||
|
||||
GOrigin& priv(); // Internal use only
|
||||
const GOrigin& priv() const; // Internal use only
|
||||
/// @private
|
||||
GFrame(const GNode &n, std::size_t out); // Operation result constructor
|
||||
/// @private
|
||||
GOrigin& priv(); // Internal use only
|
||||
/// @private
|
||||
const GOrigin& priv() const; // Internal use only
|
||||
|
||||
private:
|
||||
std::shared_ptr<GOrigin> m_priv;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2018-2020 Intel Corporation
|
||||
// Copyright (C) 2018-2021 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GKERNEL_HPP
|
||||
|
|
@ -30,6 +30,7 @@ struct GTypeInfo
|
|||
{
|
||||
GShape shape;
|
||||
cv::detail::OpaqueKind kind;
|
||||
detail::HostCtor ctor;
|
||||
};
|
||||
|
||||
using GShapes = std::vector<GShape>;
|
||||
|
|
@ -371,6 +372,7 @@ namespace gapi
|
|||
{
|
||||
// Prework: model "Device" API before it gets to G-API headers.
|
||||
// FIXME: Don't mix with internal Backends class!
|
||||
/// @private
|
||||
class GAPI_EXPORTS GBackend
|
||||
{
|
||||
public:
|
||||
|
|
@ -411,6 +413,7 @@ namespace std
|
|||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
/// @private
|
||||
class GFunctor
|
||||
{
|
||||
public:
|
||||
|
|
@ -516,6 +519,13 @@ namespace gapi {
|
|||
*/
|
||||
const std::vector<GTransform>& get_transformations() const;
|
||||
|
||||
/**
|
||||
* @brief Returns vector of kernel ids included in the package
|
||||
*
|
||||
* @return vector of kernel ids included in the package
|
||||
*/
|
||||
std::vector<std::string> get_kernel_ids() const;
|
||||
|
||||
/**
|
||||
* @brief Test if a particular kernel _implementation_ KImpl is
|
||||
* included in this kernel package.
|
||||
|
|
@ -605,6 +615,18 @@ namespace gapi {
|
|||
includeHelper<KImpl>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a new kernel based on it's backend and id into the kernel package
|
||||
*
|
||||
* @param backend backend associated with the kernel
|
||||
* @param kernel_id a name/id of the kernel
|
||||
*/
|
||||
void include(const cv::gapi::GBackend& backend, const std::string& kernel_id)
|
||||
{
|
||||
removeAPI(kernel_id);
|
||||
m_id_kernels[kernel_id] = std::make_pair(backend, GKernelImpl{{}, {}});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Lists all backends which are included into package
|
||||
*
|
||||
|
|
@ -637,7 +659,7 @@ namespace gapi {
|
|||
* Use this function to pass kernel implementations (defined in
|
||||
* either way) and transformations to the system. Example:
|
||||
*
|
||||
* @snippet modules/gapi/samples/api_ref_snippets.cpp kernels_snippet
|
||||
* @snippet samples/cpp/tutorial_code/gapi/doc_snippets/api_ref_snippets.cpp kernels_snippet
|
||||
*
|
||||
* Note that kernels() itself is a function returning object, not
|
||||
* a type, so having `()` at the end is important -- it must be a
|
||||
|
|
@ -697,7 +719,7 @@ namespace gapi {
|
|||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief cv::use_only() is a special combinator which hints G-API to use only
|
||||
* @brief cv::gapi::use_only() is a special combinator which hints G-API to use only
|
||||
* kernels specified in cv::GComputation::compile() (and not to extend kernels available by
|
||||
* default with that package).
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -30,29 +30,57 @@ struct GOrigin;
|
|||
* @brief G-API data objects used to build G-API expressions.
|
||||
*
|
||||
* These objects do not own any particular data (except compile-time
|
||||
* associated values like with cv::GScalar) and are used to construct
|
||||
* graphs.
|
||||
* associated values like with cv::GScalar or `cv::GArray<T>`) and are
|
||||
* used only to construct graphs.
|
||||
*
|
||||
* Every graph in G-API starts and ends with data objects.
|
||||
*
|
||||
* Once constructed and compiled, G-API operates with regular host-side
|
||||
* data instead. Refer to the below table to find the mapping between
|
||||
* G-API and regular data types.
|
||||
* G-API and regular data types when passing input and output data
|
||||
* structures to G-API:
|
||||
*
|
||||
* G-API data type | I/O data type
|
||||
* ------------------ | -------------
|
||||
* cv::GMat | cv::Mat
|
||||
* cv::GMat | cv::Mat, cv::UMat, cv::RMat
|
||||
* cv::GScalar | cv::Scalar
|
||||
* `cv::GArray<T>` | std::vector<T>
|
||||
* `cv::GOpaque<T>` | T
|
||||
* cv::GFrame | cv::MediaFrame
|
||||
*/
|
||||
/**
|
||||
* @brief GMat class represents image or tensor data in the
|
||||
* graph.
|
||||
*
|
||||
* GMat doesn't store any data itself, instead it describes a
|
||||
* functional relationship between operations consuming and producing
|
||||
* GMat objects.
|
||||
*
|
||||
* GMat is a virtual counterpart of Mat and UMat, but it
|
||||
* doesn't mean G-API use Mat or UMat objects internally to represent
|
||||
* GMat objects -- the internal data representation may be
|
||||
* backend-specific or optimized out at all.
|
||||
*
|
||||
* @sa Mat, GMatDesc
|
||||
*/
|
||||
class GAPI_EXPORTS_W_SIMPLE GMat
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs an empty GMat
|
||||
*
|
||||
* Normally, empty G-API data objects denote a starting point of
|
||||
* the graph. When an empty GMat is assigned to a result of some
|
||||
* operation, it obtains a functional link to this operation (and
|
||||
* is not empty anymore).
|
||||
*/
|
||||
GAPI_WRAP GMat(); // Empty constructor
|
||||
GMat(const GNode &n, std::size_t out); // Operation result constructor
|
||||
|
||||
/// @private
|
||||
GMat(const GNode &n, std::size_t out); // Operation result constructor
|
||||
/// @private
|
||||
GOrigin& priv(); // Internal use only
|
||||
/// @private
|
||||
const GOrigin& priv() const; // Internal use only
|
||||
|
||||
private:
|
||||
|
|
@ -73,25 +101,25 @@ class RMat;
|
|||
* \addtogroup gapi_meta_args
|
||||
* @{
|
||||
*/
|
||||
struct GAPI_EXPORTS GMatDesc
|
||||
struct GAPI_EXPORTS_W_SIMPLE GMatDesc
|
||||
{
|
||||
// FIXME: Default initializers in C++14
|
||||
int depth;
|
||||
int chan;
|
||||
cv::Size size; // NB.: no multi-dimensional cases covered yet
|
||||
bool planar;
|
||||
std::vector<int> dims; // FIXME: Maybe it's real questionable to have it here
|
||||
GAPI_PROP int depth;
|
||||
GAPI_PROP int chan;
|
||||
GAPI_PROP cv::Size size; // NB.: no multi-dimensional cases covered yet
|
||||
GAPI_PROP bool planar;
|
||||
GAPI_PROP std::vector<int> dims; // FIXME: Maybe it's real questionable to have it here
|
||||
|
||||
GMatDesc(int d, int c, cv::Size s, bool p = false)
|
||||
GAPI_WRAP GMatDesc(int d, int c, cv::Size s, bool p = false)
|
||||
: depth(d), chan(c), size(s), planar(p) {}
|
||||
|
||||
GMatDesc(int d, const std::vector<int> &dd)
|
||||
GAPI_WRAP GMatDesc(int d, const std::vector<int> &dd)
|
||||
: depth(d), chan(-1), size{-1,-1}, planar(false), dims(dd) {}
|
||||
|
||||
GMatDesc(int d, std::vector<int> &&dd)
|
||||
GAPI_WRAP GMatDesc(int d, std::vector<int> &&dd)
|
||||
: depth(d), chan(-1), size{-1,-1}, planar(false), dims(std::move(dd)) {}
|
||||
|
||||
GMatDesc() : GMatDesc(-1, -1, {-1,-1}) {}
|
||||
GAPI_WRAP GMatDesc() : GMatDesc(-1, -1, {-1,-1}) {}
|
||||
|
||||
inline bool operator== (const GMatDesc &rhs) const
|
||||
{
|
||||
|
|
@ -120,7 +148,7 @@ struct GAPI_EXPORTS GMatDesc
|
|||
// Meta combinator: return a new GMatDesc which differs in size by delta
|
||||
// (all other fields are taken unchanged from this GMatDesc)
|
||||
// FIXME: a better name?
|
||||
GMatDesc withSizeDelta(cv::Size delta) const
|
||||
GAPI_WRAP GMatDesc withSizeDelta(cv::Size delta) const
|
||||
{
|
||||
GMatDesc desc(*this);
|
||||
desc.size += delta;
|
||||
|
|
@ -130,12 +158,12 @@ struct GAPI_EXPORTS GMatDesc
|
|||
// (all other fields are taken unchanged from this GMatDesc)
|
||||
//
|
||||
// This is an overload.
|
||||
GMatDesc withSizeDelta(int dx, int dy) const
|
||||
GAPI_WRAP GMatDesc withSizeDelta(int dx, int dy) const
|
||||
{
|
||||
return withSizeDelta(cv::Size{dx,dy});
|
||||
}
|
||||
|
||||
GMatDesc withSize(cv::Size sz) const
|
||||
GAPI_WRAP GMatDesc withSize(cv::Size sz) const
|
||||
{
|
||||
GMatDesc desc(*this);
|
||||
desc.size = sz;
|
||||
|
|
@ -144,7 +172,7 @@ struct GAPI_EXPORTS GMatDesc
|
|||
|
||||
// Meta combinator: return a new GMatDesc with specified data depth.
|
||||
// (all other fields are taken unchanged from this GMatDesc)
|
||||
GMatDesc withDepth(int ddepth) const
|
||||
GAPI_WRAP GMatDesc withDepth(int ddepth) const
|
||||
{
|
||||
GAPI_Assert(CV_MAT_CN(ddepth) == 1 || ddepth == -1);
|
||||
GMatDesc desc(*this);
|
||||
|
|
@ -155,7 +183,7 @@ struct GAPI_EXPORTS GMatDesc
|
|||
// Meta combinator: return a new GMatDesc with specified data depth
|
||||
// and number of channels.
|
||||
// (all other fields are taken unchanged from this GMatDesc)
|
||||
GMatDesc withType(int ddepth, int dchan) const
|
||||
GAPI_WRAP GMatDesc withType(int ddepth, int dchan) const
|
||||
{
|
||||
GAPI_Assert(CV_MAT_CN(ddepth) == 1 || ddepth == -1);
|
||||
GMatDesc desc = withDepth(ddepth);
|
||||
|
|
@ -166,7 +194,7 @@ struct GAPI_EXPORTS GMatDesc
|
|||
// Meta combinator: return a new GMatDesc with planar flag set
|
||||
// (no size changes are performed, only channel interpretation is changed
|
||||
// (interleaved -> planar)
|
||||
GMatDesc asPlanar() const
|
||||
GAPI_WRAP GMatDesc asPlanar() const
|
||||
{
|
||||
GAPI_Assert(planar == false);
|
||||
GMatDesc desc(*this);
|
||||
|
|
@ -177,7 +205,7 @@ struct GAPI_EXPORTS GMatDesc
|
|||
// Meta combinator: return a new GMatDesc
|
||||
// reinterpreting 1-channel input as planar image
|
||||
// (size height is divided by plane number)
|
||||
GMatDesc asPlanar(int planes) const
|
||||
GAPI_WRAP GMatDesc asPlanar(int planes) const
|
||||
{
|
||||
GAPI_Assert(planar == false);
|
||||
GAPI_Assert(chan == 1);
|
||||
|
|
@ -192,7 +220,7 @@ struct GAPI_EXPORTS GMatDesc
|
|||
// Meta combinator: return a new GMatDesc with planar flag set to false
|
||||
// (no size changes are performed, only channel interpretation is changed
|
||||
// (planar -> interleaved)
|
||||
GMatDesc asInterleaved() const
|
||||
GAPI_WRAP GMatDesc asInterleaved() const
|
||||
{
|
||||
GAPI_Assert(planar == true);
|
||||
GMatDesc desc(*this);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@
|
|||
#include <opencv2/gapi/util/type_traits.hpp>
|
||||
#include <opencv2/gapi/own/assert.hpp>
|
||||
|
||||
#include <opencv2/gapi/gcommon.hpp> // OpaqueKind
|
||||
#include <opencv2/gapi/garray.hpp> // TypeHintBase
|
||||
|
||||
namespace cv
|
||||
{
|
||||
// Forward declaration; GNode and GOrigin are an internal
|
||||
|
|
@ -33,14 +36,14 @@ template<typename T> class GOpaque;
|
|||
* \addtogroup gapi_meta_args
|
||||
* @{
|
||||
*/
|
||||
struct GOpaqueDesc
|
||||
struct GAPI_EXPORTS_W_SIMPLE GOpaqueDesc
|
||||
{
|
||||
// FIXME: Body
|
||||
// FIXME: Also implement proper operator== then
|
||||
bool operator== (const GOpaqueDesc&) const { return true; }
|
||||
};
|
||||
template<typename U> GOpaqueDesc descr_of(const U &) { return {};}
|
||||
static inline GOpaqueDesc empty_gopaque_desc() {return {}; }
|
||||
GAPI_EXPORTS_W inline GOpaqueDesc empty_gopaque_desc() {return {}; }
|
||||
/** @} */
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const cv::GOpaqueDesc &desc);
|
||||
|
|
@ -229,7 +232,7 @@ namespace detail
|
|||
class OpaqueRef
|
||||
{
|
||||
std::shared_ptr<BasicOpaqueRef> m_ref;
|
||||
cv::detail::OpaqueKind m_kind;
|
||||
cv::detail::OpaqueKind m_kind = cv::detail::OpaqueKind::CV_UNKNOWN;
|
||||
|
||||
template<typename T> inline void check() const
|
||||
{
|
||||
|
|
@ -304,15 +307,40 @@ namespace detail
|
|||
/** \addtogroup gapi_data_objects
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief `cv::GOpaque<T>` template class represents an object of
|
||||
* class `T` in the graph.
|
||||
*
|
||||
* `cv::GOpaque<T>` describes a functional relationship between operations
|
||||
* consuming and producing object of class `T`. `cv::GOpaque<T>` is
|
||||
* designed to extend G-API with user-defined data types, which are
|
||||
* often required with user-defined operations. G-API can't apply any
|
||||
* optimizations to user-defined types since these types are opaque to
|
||||
* the framework. However, there is a number of G-API operations
|
||||
* declared with `cv::GOpaque<T>` as a return type,
|
||||
* e.g. cv::gapi::streaming::timestamp() or cv::gapi::streaming::size().
|
||||
*
|
||||
* @sa `cv::GArray<T>`
|
||||
*/
|
||||
template<typename T> class GOpaque
|
||||
{
|
||||
public:
|
||||
// Host type (or Flat type) - the type this GOpaque is actually
|
||||
// specified to.
|
||||
/// @private
|
||||
using HT = typename detail::flatten_g<util::decay_t<T>>::type;
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty `cv::GOpaque<T>`
|
||||
*
|
||||
* Normally, empty G-API data objects denote a starting point of
|
||||
* the graph. When an empty `cv::GOpaque<T>` is assigned to a result
|
||||
* of some operation, it obtains a functional link to this
|
||||
* operation (and is not empty anymore).
|
||||
*/
|
||||
GOpaque() { putDetails(); } // Empty constructor
|
||||
|
||||
/// @private
|
||||
explicit GOpaque(detail::GOpaqueU &&ref) // GOpaqueU-based constructor
|
||||
: m_ref(ref) { putDetails(); } // (used by GCall, not for users)
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ public:
|
|||
* It's an ordinary overload of addition assignment operator.
|
||||
*
|
||||
* Example of usage:
|
||||
* @snippet dynamic_graph.cpp GIOProtoArgs usage
|
||||
* @snippet samples/cpp/tutorial_code/gapi/doc_snippets/dynamic_graph_snippets.cpp GIOProtoArgs usage
|
||||
*
|
||||
*/
|
||||
template<typename Tg>
|
||||
|
|
@ -135,7 +135,7 @@ GRunArg value_of(const GOrigin &origin);
|
|||
// Transform run-time computation arguments into a collection of metadata
|
||||
// extracted from that arguments
|
||||
GMetaArg GAPI_EXPORTS descr_of(const GRunArg &arg );
|
||||
GMetaArgs GAPI_EXPORTS_W descr_of(const GRunArgs &args);
|
||||
GMetaArgs GAPI_EXPORTS descr_of(const GRunArgs &args);
|
||||
|
||||
// Transform run-time operation result argument into metadata extracted from that argument
|
||||
// Used to compare the metadata, which generated at compile time with the metadata result operation in run time
|
||||
|
|
|
|||
|
|
@ -25,18 +25,83 @@ struct GOrigin;
|
|||
/** \addtogroup gapi_data_objects
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief GScalar class represents cv::Scalar data in the graph.
|
||||
*
|
||||
* GScalar may be associated with a cv::Scalar value, which becomes
|
||||
* its constant value bound in graph compile time. cv::GScalar describes a
|
||||
* functional relationship between operations consuming and producing
|
||||
* GScalar objects.
|
||||
*
|
||||
* GScalar is a virtual counterpart of cv::Scalar, which is usually used
|
||||
* to represent the GScalar data in G-API during the execution.
|
||||
*
|
||||
* @sa Scalar
|
||||
*/
|
||||
class GAPI_EXPORTS_W_SIMPLE GScalar
|
||||
{
|
||||
public:
|
||||
GAPI_WRAP GScalar(); // Empty constructor
|
||||
explicit GScalar(const cv::Scalar& s); // Constant value constructor from cv::Scalar
|
||||
/**
|
||||
* @brief Constructs an empty GScalar
|
||||
*
|
||||
* Normally, empty G-API data objects denote a starting point of
|
||||
* the graph. When an empty GScalar is assigned to a result of some
|
||||
* operation, it obtains a functional link to this operation (and
|
||||
* is not empty anymore).
|
||||
*/
|
||||
GAPI_WRAP GScalar();
|
||||
|
||||
/**
|
||||
* @brief Constructs a value-initialized GScalar
|
||||
*
|
||||
* In contrast with GMat (which can be either an explicit graph input
|
||||
* or a result of some operation), GScalars may have their values
|
||||
* be associated at graph construction time. It is useful when
|
||||
* some operation has a GScalar input which doesn't change during
|
||||
* the program execution, and is set only once. In this case,
|
||||
* there is no need to declare such GScalar as a graph input.
|
||||
*
|
||||
* @note The value of GScalar may be overwritten by assigning some
|
||||
* other GScalar to the object using `operator=` -- on the
|
||||
* assigment, the old GScalar value is discarded.
|
||||
*
|
||||
* @param s a cv::Scalar value to associate with this GScalar object.
|
||||
*/
|
||||
explicit GScalar(const cv::Scalar& s);
|
||||
|
||||
/**
|
||||
* @overload
|
||||
* @brief Constructs a value-initialized GScalar
|
||||
*
|
||||
* @param s a cv::Scalar value to associate with this GScalar object.
|
||||
*/
|
||||
explicit GScalar(cv::Scalar&& s); // Constant value move-constructor from cv::Scalar
|
||||
|
||||
/**
|
||||
* @overload
|
||||
* @brief Constructs a value-initialized GScalar
|
||||
*
|
||||
* @param v0 A `double` value to associate with this GScalar. Note
|
||||
* that only the first component of a four-component cv::Scalar is
|
||||
* set to this value, with others remain zeros.
|
||||
*
|
||||
* This constructor overload is not marked `explicit` and can be
|
||||
* used in G-API expression code like this:
|
||||
*
|
||||
* @snippet samples/cpp/tutorial_code/gapi/doc_snippets/api_ref_snippets.cpp gscalar_implicit
|
||||
*
|
||||
* Here operator+(GMat,GScalar) is used to wrap cv::gapi::addC()
|
||||
* and a value-initialized GScalar is created on the fly.
|
||||
*
|
||||
* @overload
|
||||
*/
|
||||
GScalar(double v0); // Constant value constructor from double
|
||||
GScalar(const GNode &n, std::size_t out); // Operation result constructor
|
||||
|
||||
/// @private
|
||||
GScalar(const GNode &n, std::size_t out); // Operation result constructor
|
||||
/// @private
|
||||
GOrigin& priv(); // Internal use only
|
||||
/// @private
|
||||
const GOrigin& priv() const; // Internal use only
|
||||
|
||||
private:
|
||||
|
|
@ -49,7 +114,7 @@ private:
|
|||
* \addtogroup gapi_meta_args
|
||||
* @{
|
||||
*/
|
||||
struct GScalarDesc
|
||||
struct GAPI_EXPORTS_W_SIMPLE GScalarDesc
|
||||
{
|
||||
// NB.: right now it is empty
|
||||
|
||||
|
|
@ -64,9 +129,9 @@ struct GScalarDesc
|
|||
}
|
||||
};
|
||||
|
||||
static inline GScalarDesc empty_scalar_desc() { return GScalarDesc(); }
|
||||
GAPI_EXPORTS_W inline GScalarDesc empty_scalar_desc() { return GScalarDesc(); }
|
||||
|
||||
GAPI_EXPORTS GScalarDesc descr_of(const cv::Scalar &scalar);
|
||||
GAPI_EXPORTS GScalarDesc descr_of(const cv::Scalar &scalar);
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const cv::GScalarDesc &desc);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2018 Intel Corporation
|
||||
// Copyright (C) 2018-2021 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GSTREAMING_COMPILED_HPP
|
||||
|
|
@ -65,12 +65,23 @@ using OptionalOpaqueRef = OptRef<cv::detail::OpaqueRef>;
|
|||
using GOptRunArgP = util::variant<
|
||||
optional<cv::Mat>*,
|
||||
optional<cv::RMat>*,
|
||||
optional<cv::MediaFrame>*,
|
||||
optional<cv::Scalar>*,
|
||||
cv::detail::OptionalVectorRef,
|
||||
cv::detail::OptionalOpaqueRef
|
||||
>;
|
||||
using GOptRunArgsP = std::vector<GOptRunArgP>;
|
||||
|
||||
using GOptRunArg = util::variant<
|
||||
optional<cv::Mat>,
|
||||
optional<cv::RMat>,
|
||||
optional<cv::MediaFrame>,
|
||||
optional<cv::Scalar>,
|
||||
optional<cv::detail::VectorRef>,
|
||||
optional<cv::detail::OpaqueRef>
|
||||
>;
|
||||
using GOptRunArgs = std::vector<GOptRunArg>;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T> inline GOptRunArgP wrap_opt_arg(optional<T>& arg) {
|
||||
|
|
@ -86,6 +97,14 @@ template<> inline GOptRunArgP wrap_opt_arg(optional<cv::Mat> &m) {
|
|||
return GOptRunArgP{&m};
|
||||
}
|
||||
|
||||
template<> inline GOptRunArgP wrap_opt_arg(optional<cv::RMat> &m) {
|
||||
return GOptRunArgP{&m};
|
||||
}
|
||||
|
||||
template<> inline GOptRunArgP wrap_opt_arg(optional<cv::MediaFrame> &f) {
|
||||
return GOptRunArgP{&f};
|
||||
}
|
||||
|
||||
template<> inline GOptRunArgP wrap_opt_arg(optional<cv::Scalar> &s) {
|
||||
return GOptRunArgP{&s};
|
||||
}
|
||||
|
|
@ -180,7 +199,10 @@ public:
|
|||
* @param ins vector of inputs to process.
|
||||
* @sa gin
|
||||
*/
|
||||
GAPI_WRAP void setSource(GRunArgs &&ins);
|
||||
void setSource(GRunArgs &&ins);
|
||||
|
||||
/// @private -- Exclude this function from OpenCV documentation
|
||||
GAPI_WRAP void setSource(const cv::detail::ExtractArgsCallback& callback);
|
||||
|
||||
/**
|
||||
* @brief Specify an input video stream for a single-input
|
||||
|
|
@ -193,7 +215,7 @@ public:
|
|||
* @param s a shared pointer to IStreamSource representing the
|
||||
* input video stream.
|
||||
*/
|
||||
GAPI_WRAP void setSource(const gapi::wip::IStreamSource::Ptr& s);
|
||||
void setSource(const gapi::wip::IStreamSource::Ptr& s);
|
||||
|
||||
/**
|
||||
* @brief Constructs and specifies an input video stream for a
|
||||
|
|
@ -251,7 +273,8 @@ public:
|
|||
bool pull(cv::GRunArgsP &&outs);
|
||||
|
||||
// NB: Used from python
|
||||
GAPI_WRAP std::tuple<bool, cv::GRunArgs> pull();
|
||||
/// @private -- Exclude this function from OpenCV documentation
|
||||
GAPI_WRAP std::tuple<bool, cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>> pull();
|
||||
|
||||
/**
|
||||
* @brief Get some next available data from the pipeline.
|
||||
|
|
@ -367,6 +390,41 @@ protected:
|
|||
};
|
||||
/** @} */
|
||||
|
||||
namespace gapi {
|
||||
|
||||
/**
|
||||
* @brief This namespace contains G-API functions, structures, and
|
||||
* symbols related to the Streaming execution mode.
|
||||
*
|
||||
* Some of the operations defined in this namespace (e.g. size(),
|
||||
* BGR(), etc.) can be used in the traditional execution mode too.
|
||||
*/
|
||||
namespace streaming {
|
||||
/**
|
||||
* @brief Specify queue capacity for streaming execution.
|
||||
*
|
||||
* In the streaming mode the pipeline steps are connected with queues
|
||||
* and this compile argument controls every queue's size.
|
||||
*/
|
||||
struct GAPI_EXPORTS_W_SIMPLE queue_capacity
|
||||
{
|
||||
GAPI_WRAP
|
||||
explicit queue_capacity(size_t cap = 1) : capacity(cap) { };
|
||||
GAPI_PROP_RW
|
||||
size_t capacity;
|
||||
};
|
||||
/** @} */
|
||||
} // namespace streaming
|
||||
} // namespace gapi
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<> struct CompileArgTag<cv::gapi::streaming::queue_capacity>
|
||||
{
|
||||
static const char* tag() { return "gapi.queue_capacity"; }
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // OPENCV_GAPI_GSTREAMING_COMPILED_HPP
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ struct GAPI_EXPORTS GTransform
|
|||
F pattern;
|
||||
F substitute;
|
||||
|
||||
GTransform(const std::string& d, const F &p, const F &s) : description(d), pattern(p), substitute(s){};
|
||||
GTransform(const std::string& d, const F &p, const F &s) : description(d), pattern(p), substitute(s) {}
|
||||
};
|
||||
|
||||
namespace detail
|
||||
|
|
|
|||
|
|
@ -19,11 +19,25 @@
|
|||
#include <opencv2/gapi/streaming/source.hpp>
|
||||
#include <opencv2/gapi/media.hpp>
|
||||
#include <opencv2/gapi/gcommon.hpp>
|
||||
#include <opencv2/gapi/util/util.hpp>
|
||||
#include <opencv2/gapi/own/convert.hpp>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename, typename = void>
|
||||
struct contains_shape_field : std::false_type {};
|
||||
|
||||
template<typename TaggedTypeCandidate>
|
||||
struct contains_shape_field<TaggedTypeCandidate,
|
||||
void_t<decltype(TaggedTypeCandidate::shape)>> :
|
||||
std::is_same<typename std::decay<decltype(TaggedTypeCandidate::shape)>::type, GShape>
|
||||
{};
|
||||
|
||||
template<typename Type>
|
||||
struct has_gshape : contains_shape_field<Type> {};
|
||||
|
||||
// FIXME: These traits and enum and possible numerous switch(kind)
|
||||
// block may be replaced with a special Handler<T> object or with
|
||||
// a double dispatch
|
||||
|
|
@ -181,10 +195,16 @@ namespace detail
|
|||
}
|
||||
template<typename U> static auto wrap_in (const U &u) -> typename GTypeTraits<T>::strip_type
|
||||
{
|
||||
static_assert(!(cv::detail::has_gshape<GTypeTraits<U>>::value
|
||||
|| cv::detail::contains<typename std::decay<U>::type, GAPI_OWN_TYPES_LIST>::value),
|
||||
"gin/gout must not be used with G* classes or cv::gapi::own::*");
|
||||
return GTypeTraits<T>::wrap_in(u);
|
||||
}
|
||||
template<typename U> static auto wrap_out(U &u) -> typename GTypeTraits<T>::strip_type
|
||||
{
|
||||
static_assert(!(cv::detail::has_gshape<GTypeTraits<U>>::value
|
||||
|| cv::detail::contains<typename std::decay<U>::type, GAPI_OWN_TYPES_LIST>::value),
|
||||
"gin/gout must not be used with G* classses or cv::gapi::own::*");
|
||||
return GTypeTraits<T>::wrap_out(u);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ namespace detail
|
|||
*
|
||||
* Refer to the following example. Regular (untyped) code is written this way:
|
||||
*
|
||||
* @snippet modules/gapi/samples/api_ref_snippets.cpp Untyped_Example
|
||||
* @snippet samples/cpp/tutorial_code/gapi/doc_snippets/api_ref_snippets.cpp Untyped_Example
|
||||
*
|
||||
* Here:
|
||||
*
|
||||
|
|
@ -71,7 +71,7 @@ namespace detail
|
|||
*
|
||||
* Now the same code written with typed API:
|
||||
*
|
||||
* @snippet modules/gapi/samples/api_ref_snippets.cpp Typed_Example
|
||||
* @snippet samples/cpp/tutorial_code/gapi/doc_snippets/api_ref_snippets.cpp Typed_Example
|
||||
*
|
||||
* The key difference is:
|
||||
*
|
||||
|
|
|
|||
|
|
@ -47,6 +47,10 @@ void validateFindingContoursMeta(const int depth, const int chan, const int mode
|
|||
|
||||
namespace cv { namespace gapi {
|
||||
|
||||
/**
|
||||
* @brief This namespace contains G-API Operation Types for OpenCV
|
||||
* ImgProc module functionality.
|
||||
*/
|
||||
namespace imgproc {
|
||||
using GMat2 = std::tuple<GMat,GMat>;
|
||||
using GMat3 = std::tuple<GMat,GMat,GMat>; // FIXME: how to avoid this?
|
||||
|
|
@ -1158,7 +1162,7 @@ if there are 2 channels, or have 2 columns if there is a single channel. Mat sho
|
|||
@param src Input gray-scale image @ref CV_8UC1; or input set of @ref CV_32S or @ref CV_32F
|
||||
2D points stored in Mat.
|
||||
*/
|
||||
GAPI_EXPORTS GOpaque<Rect> boundingRect(const GMat& src);
|
||||
GAPI_EXPORTS_W GOpaque<Rect> boundingRect(const GMat& src);
|
||||
|
||||
/** @overload
|
||||
|
||||
|
|
@ -1168,7 +1172,7 @@ Calculates the up-right bounding rectangle of a point set.
|
|||
|
||||
@param src Input 2D point set, stored in std::vector<cv::Point2i>.
|
||||
*/
|
||||
GAPI_EXPORTS GOpaque<Rect> boundingRect(const GArray<Point2i>& src);
|
||||
GAPI_EXPORTS_W GOpaque<Rect> boundingRect(const GArray<Point2i>& src);
|
||||
|
||||
/** @overload
|
||||
|
||||
|
|
@ -1341,7 +1345,7 @@ Output image is 8-bit unsigned 3-channel image @ref CV_8UC3.
|
|||
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3.
|
||||
@sa RGB2BGR
|
||||
*/
|
||||
GAPI_EXPORTS GMat BGR2RGB(const GMat& src);
|
||||
GAPI_EXPORTS_W GMat BGR2RGB(const GMat& src);
|
||||
|
||||
/** @brief Converts an image from RGB color space to gray-scaled.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2019-2020 Intel Corporation
|
||||
// Copyright (C) 2019-2021 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_INFER_HPP
|
||||
|
|
@ -76,6 +76,113 @@ struct valid_infer2_types< std::tuple<cv::GMat,Ns...>, std::tuple<T,Ts...> > {
|
|||
valid_infer2_types< std::tuple<cv::GMat>, std::tuple<T> >::value
|
||||
&& valid_infer2_types< std::tuple<Ns...>, std::tuple<Ts...> >::value;
|
||||
};
|
||||
|
||||
// Struct stores network input/output names.
|
||||
// Used by infer<Generic>
|
||||
struct InOutInfo
|
||||
{
|
||||
std::vector<std::string> in_names;
|
||||
std::vector<std::string> out_names;
|
||||
};
|
||||
|
||||
template <typename OutT>
|
||||
class GInferOutputsTyped
|
||||
{
|
||||
public:
|
||||
GInferOutputsTyped() = default;
|
||||
GInferOutputsTyped(std::shared_ptr<cv::GCall> call)
|
||||
: m_priv(std::make_shared<Priv>(std::move(call)))
|
||||
{
|
||||
}
|
||||
|
||||
OutT at(const std::string& name)
|
||||
{
|
||||
auto it = m_priv->blobs.find(name);
|
||||
if (it == m_priv->blobs.end()) {
|
||||
// FIXME: Avoid modifying GKernel
|
||||
auto shape = cv::detail::GTypeTraits<OutT>::shape;
|
||||
m_priv->call->kernel().outShapes.push_back(shape);
|
||||
m_priv->call->kernel().outCtors.emplace_back(cv::detail::GObtainCtor<OutT>::get());
|
||||
auto out_idx = static_cast<int>(m_priv->blobs.size());
|
||||
it = m_priv->blobs.emplace(name,
|
||||
cv::detail::Yield<OutT>::yield(*(m_priv->call), out_idx)).first;
|
||||
m_priv->info->out_names.push_back(name);
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
private:
|
||||
struct Priv
|
||||
{
|
||||
Priv(std::shared_ptr<cv::GCall> c)
|
||||
: call(std::move(c)), info(cv::util::any_cast<InOutInfo>(&call->params()))
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<cv::GCall> call;
|
||||
InOutInfo* info = nullptr;
|
||||
std::unordered_map<std::string, OutT> blobs;
|
||||
};
|
||||
|
||||
std::shared_ptr<Priv> m_priv;
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
class GInferInputsTyped
|
||||
{
|
||||
public:
|
||||
GInferInputsTyped()
|
||||
: m_priv(std::make_shared<Priv>())
|
||||
{
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
GInferInputsTyped<Ts...>& setInput(const std::string& name, U in)
|
||||
{
|
||||
m_priv->blobs.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(name),
|
||||
std::forward_as_tuple(in));
|
||||
return *this;
|
||||
}
|
||||
|
||||
using StorageT = cv::util::variant<Ts...>;
|
||||
StorageT& operator[](const std::string& name) {
|
||||
return m_priv->blobs[name];
|
||||
}
|
||||
|
||||
using Map = std::unordered_map<std::string, StorageT>;
|
||||
const Map& getBlobs() const {
|
||||
return m_priv->blobs;
|
||||
}
|
||||
|
||||
private:
|
||||
struct Priv
|
||||
{
|
||||
std::unordered_map<std::string, StorageT> blobs;
|
||||
};
|
||||
|
||||
std::shared_ptr<Priv> m_priv;
|
||||
};
|
||||
|
||||
template<typename InferT>
|
||||
std::shared_ptr<cv::GCall> makeCall(const std::string &tag,
|
||||
std::vector<cv::GArg> &&args,
|
||||
std::vector<std::string> &&names,
|
||||
cv::GKinds &&kinds) {
|
||||
auto call = std::make_shared<cv::GCall>(GKernel{
|
||||
InferT::id(),
|
||||
tag,
|
||||
InferT::getOutMeta,
|
||||
{}, // outShape will be filled later
|
||||
std::move(kinds),
|
||||
{}, // outCtors will be filled later
|
||||
});
|
||||
|
||||
call->setArgs(std::move(args));
|
||||
call->params() = cv::detail::InOutInfo{std::move(names), {}};
|
||||
|
||||
return call;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// TODO: maybe tuple_wrap_helper from util.hpp may help with this.
|
||||
|
|
@ -166,49 +273,6 @@ struct GInferBase {
|
|||
}
|
||||
};
|
||||
|
||||
// Struct stores network input/output names.
|
||||
// Used by infer<Generic>
|
||||
struct InOutInfo
|
||||
{
|
||||
std::vector<std::string> in_names;
|
||||
std::vector<std::string> out_names;
|
||||
};
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief G-API object used to collect network inputs
|
||||
*/
|
||||
class GAPI_EXPORTS_W_SIMPLE GInferInputs
|
||||
{
|
||||
using Map = std::unordered_map<std::string, GMat>;
|
||||
public:
|
||||
GAPI_WRAP GInferInputs();
|
||||
GAPI_WRAP void setInput(const std::string& name, const cv::GMat& value);
|
||||
|
||||
cv::GMat& operator[](const std::string& name);
|
||||
const Map& getBlobs() const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Map> in_blobs;
|
||||
};
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief G-API object used to collect network outputs
|
||||
*/
|
||||
struct GAPI_EXPORTS_W_SIMPLE GInferOutputs
|
||||
{
|
||||
public:
|
||||
GAPI_WRAP GInferOutputs() = default;
|
||||
GInferOutputs(std::shared_ptr<cv::GCall> call);
|
||||
GAPI_WRAP cv::GMat at(const std::string& name);
|
||||
|
||||
private:
|
||||
struct Priv;
|
||||
std::shared_ptr<Priv> m_priv;
|
||||
};
|
||||
/** @} */
|
||||
// Base "InferROI" kernel.
|
||||
// All notes from "Infer" kernel apply here as well.
|
||||
struct GInferROIBase {
|
||||
|
|
@ -295,6 +359,90 @@ struct GInferList2 final
|
|||
static constexpr const char* tag() { return Net::tag(); }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief G-API object used to collect network inputs
|
||||
*/
|
||||
using GInferInputs = cv::detail::GInferInputsTyped<cv::GMat, cv::GFrame>;
|
||||
|
||||
/**
|
||||
* @brief G-API object used to collect the list of network inputs
|
||||
*/
|
||||
using GInferListInputs = cv::detail::GInferInputsTyped<cv::GArray<cv::GMat>, cv::GArray<cv::Rect>>;
|
||||
|
||||
/**
|
||||
* @brief G-API object used to collect network outputs
|
||||
*/
|
||||
using GInferOutputs = cv::detail::GInferOutputsTyped<cv::GMat>;
|
||||
|
||||
/**
|
||||
* @brief G-API object used to collect the list of network outputs
|
||||
*/
|
||||
using GInferListOutputs = cv::detail::GInferOutputsTyped<cv::GArray<cv::GMat>>;
|
||||
|
||||
namespace detail {
|
||||
void inline unpackBlobs(const cv::GInferInputs::Map& blobs,
|
||||
std::vector<cv::GArg>& args,
|
||||
std::vector<std::string>& names,
|
||||
cv::GKinds& kinds)
|
||||
{
|
||||
for (auto&& p : blobs) {
|
||||
names.emplace_back(p.first);
|
||||
switch (p.second.index()) {
|
||||
case cv::GInferInputs::StorageT::index_of<cv::GMat>():
|
||||
args.emplace_back(cv::util::get<cv::GMat>(p.second));
|
||||
kinds.emplace_back(cv::detail::OpaqueKind::CV_MAT);
|
||||
break;
|
||||
case cv::GInferInputs::StorageT::index_of<cv::GFrame>():
|
||||
args.emplace_back(cv::util::get<cv::GFrame>(p.second));
|
||||
kinds.emplace_back(cv::detail::OpaqueKind::CV_UNKNOWN);
|
||||
break;
|
||||
default:
|
||||
GAPI_Assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InferType>
|
||||
struct InferROITraits;
|
||||
|
||||
template <>
|
||||
struct InferROITraits<GInferROIBase>
|
||||
{
|
||||
using outType = cv::GInferOutputs;
|
||||
using inType = cv::GOpaque<cv::Rect>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct InferROITraits<GInferListBase>
|
||||
{
|
||||
using outType = cv::GInferListOutputs;
|
||||
using inType = cv::GArray<cv::Rect>;
|
||||
};
|
||||
|
||||
template<typename InferType>
|
||||
typename InferROITraits<InferType>::outType
|
||||
inferGenericROI(const std::string& tag,
|
||||
const typename InferROITraits<InferType>::inType& in,
|
||||
const cv::GInferInputs& inputs)
|
||||
{
|
||||
std::vector<cv::GArg> args;
|
||||
std::vector<std::string> names;
|
||||
cv::GKinds kinds;
|
||||
|
||||
args.emplace_back(in);
|
||||
kinds.emplace_back(cv::detail::OpaqueKind::CV_RECT);
|
||||
|
||||
unpackBlobs(inputs.getBlobs(), args, names, kinds);
|
||||
|
||||
auto call = cv::detail::makeCall<InferType>(tag,
|
||||
std::move(args),
|
||||
std::move(names),
|
||||
std::move(kinds));
|
||||
|
||||
return {std::move(call)};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace cv
|
||||
|
||||
// FIXME: Probably the <API> signature makes a function/tuple/function round-trip
|
||||
|
|
@ -384,7 +532,11 @@ typename Net::Result infer(Args&&... args) {
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Special network type
|
||||
* @brief Generic network type: input and output layers are configured dynamically at runtime
|
||||
*
|
||||
* Unlike the network types defined with G_API_NET macro, this one
|
||||
* doesn't fix number of network inputs and outputs at the compilation stage
|
||||
* thus providing user with an opportunity to program them in runtime.
|
||||
*/
|
||||
struct Generic { };
|
||||
|
||||
|
|
@ -395,38 +547,98 @@ struct Generic { };
|
|||
* @param inputs networks's inputs
|
||||
* @return a GInferOutputs
|
||||
*/
|
||||
template<typename T = Generic> GInferOutputs
|
||||
infer(const std::string& tag, const GInferInputs& inputs)
|
||||
template<typename T = Generic> cv::GInferOutputs
|
||||
infer(const std::string& tag, const cv::GInferInputs& inputs)
|
||||
{
|
||||
std::vector<GArg> input_args;
|
||||
std::vector<std::string> input_names;
|
||||
std::vector<cv::GArg> args;
|
||||
std::vector<std::string> names;
|
||||
cv::GKinds kinds;
|
||||
|
||||
const auto& blobs = inputs.getBlobs();
|
||||
for (auto&& p : blobs)
|
||||
{
|
||||
input_names.push_back(p.first);
|
||||
input_args.emplace_back(p.second);
|
||||
}
|
||||
cv::detail::unpackBlobs(inputs.getBlobs(), args, names, kinds);
|
||||
|
||||
GKinds kinds(blobs.size(), cv::detail::OpaqueKind::CV_MAT);
|
||||
auto call = std::make_shared<cv::GCall>(GKernel{
|
||||
GInferBase::id(),
|
||||
tag,
|
||||
GInferBase::getOutMeta,
|
||||
{}, // outShape will be filled later
|
||||
std::move(kinds),
|
||||
{}, // outCtors will be filled later
|
||||
});
|
||||
auto call = cv::detail::makeCall<GInferBase>(tag,
|
||||
std::move(args),
|
||||
std::move(names),
|
||||
std::move(kinds));
|
||||
|
||||
call->setArgs(std::move(input_args));
|
||||
call->params() = InOutInfo{input_names, {}};
|
||||
|
||||
return GInferOutputs{std::move(call)};
|
||||
return cv::GInferOutputs{std::move(call)};
|
||||
}
|
||||
|
||||
GAPI_EXPORTS_W inline GInferOutputs infer(const String& name, const GInferInputs& inputs)
|
||||
/** @brief Calculates response for the generic network
|
||||
* for the specified region in the source image.
|
||||
* Currently expects a single-input network only.
|
||||
*
|
||||
* @param tag a network tag
|
||||
* @param roi a an object describing the region of interest
|
||||
* in the source image. May be calculated in the same graph dynamically.
|
||||
* @param inputs networks's inputs
|
||||
* @return a cv::GInferOutputs
|
||||
*/
|
||||
template<typename T = Generic> cv::GInferOutputs
|
||||
infer(const std::string& tag, const cv::GOpaque<cv::Rect>& roi, const cv::GInferInputs& inputs)
|
||||
{
|
||||
return infer<Generic>(name, inputs);
|
||||
return cv::detail::inferGenericROI<GInferROIBase>(tag, roi, inputs);
|
||||
}
|
||||
|
||||
/** @brief Calculates responses for the specified network
|
||||
* for every region in the source image.
|
||||
*
|
||||
* @param tag a network tag
|
||||
* @param rois a list of rectangles describing regions of interest
|
||||
* in the source image. Usually an output of object detector or tracker.
|
||||
* @param inputs networks's inputs
|
||||
* @return a cv::GInferListOutputs
|
||||
*/
|
||||
template<typename T = Generic> cv::GInferListOutputs
|
||||
infer(const std::string& tag, const cv::GArray<cv::Rect>& rois, const cv::GInferInputs& inputs)
|
||||
{
|
||||
return cv::detail::inferGenericROI<GInferListBase>(tag, rois, inputs);
|
||||
}
|
||||
|
||||
/** @brief Calculates responses for the specified network
|
||||
* for every region in the source image, extended version.
|
||||
*
|
||||
* @param tag a network tag
|
||||
* @param in a source image containing regions of interest.
|
||||
* @param inputs networks's inputs
|
||||
* @return a cv::GInferListOutputs
|
||||
*/
|
||||
template<typename T = Generic, typename Input>
|
||||
typename std::enable_if<cv::detail::accepted_infer_types<Input>::value, cv::GInferListOutputs>::type
|
||||
infer2(const std::string& tag,
|
||||
const Input& in,
|
||||
const cv::GInferListInputs& inputs)
|
||||
{
|
||||
std::vector<cv::GArg> args;
|
||||
std::vector<std::string> names;
|
||||
cv::GKinds kinds;
|
||||
|
||||
args.emplace_back(in);
|
||||
auto k = cv::detail::GOpaqueTraits<Input>::kind;
|
||||
kinds.emplace_back(k);
|
||||
|
||||
for (auto&& p : inputs.getBlobs()) {
|
||||
names.emplace_back(p.first);
|
||||
switch (p.second.index()) {
|
||||
case cv::GInferListInputs::StorageT::index_of<cv::GArray<cv::GMat>>():
|
||||
args.emplace_back(cv::util::get<cv::GArray<cv::GMat>>(p.second));
|
||||
kinds.emplace_back(cv::detail::OpaqueKind::CV_MAT);
|
||||
break;
|
||||
case cv::GInferListInputs::StorageT::index_of<cv::GArray<cv::Rect>>():
|
||||
args.emplace_back(cv::util::get<cv::GArray<cv::Rect>>(p.second));
|
||||
kinds.emplace_back(cv::detail::OpaqueKind::CV_RECT);
|
||||
break;
|
||||
default:
|
||||
GAPI_Assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
auto call = cv::detail::makeCall<GInferList2Base>(tag,
|
||||
std::move(args),
|
||||
std::move(names),
|
||||
std::move(kinds));
|
||||
|
||||
return cv::GInferListOutputs{std::move(call)};
|
||||
}
|
||||
|
||||
} // namespace gapi
|
||||
|
|
@ -442,7 +654,8 @@ namespace gapi {
|
|||
|
||||
// A type-erased form of network parameters.
|
||||
// Similar to how a type-erased GKernel is represented and used.
|
||||
struct GAPI_EXPORTS GNetParam {
|
||||
/// @private
|
||||
struct GAPI_EXPORTS_W_SIMPLE GNetParam {
|
||||
std::string tag; // FIXME: const?
|
||||
GBackend backend; // Specifies the execution model
|
||||
util::any params; // Backend-interpreted parameter structure
|
||||
|
|
@ -453,12 +666,13 @@ struct GAPI_EXPORTS GNetParam {
|
|||
*/
|
||||
/**
|
||||
* @brief A container class for network configurations. Similar to
|
||||
* GKernelPackage.Use cv::gapi::networks() to construct this object.
|
||||
* GKernelPackage. Use cv::gapi::networks() to construct this object.
|
||||
*
|
||||
* @sa cv::gapi::networks
|
||||
*/
|
||||
struct GAPI_EXPORTS_W_SIMPLE GNetPackage {
|
||||
GAPI_WRAP GNetPackage() = default;
|
||||
GAPI_WRAP explicit GNetPackage(std::vector<GNetParam> nets);
|
||||
explicit GNetPackage(std::initializer_list<GNetParam> ii);
|
||||
std::vector<GBackend> backends() const;
|
||||
std::vector<GNetParam> networks;
|
||||
|
|
@ -486,6 +700,14 @@ template<typename... Args>
|
|||
cv::gapi::GNetPackage networks(Args&&... args) {
|
||||
return cv::gapi::GNetPackage({ cv::detail::strip(args)... });
|
||||
}
|
||||
|
||||
inline cv::gapi::GNetPackage& operator += ( cv::gapi::GNetPackage& lhs,
|
||||
const cv::gapi::GNetPackage& rhs) {
|
||||
lhs.networks.reserve(lhs.networks.size() + rhs.networks.size());
|
||||
lhs.networks.insert(lhs.networks.end(), rhs.networks.begin(), rhs.networks.end());
|
||||
return lhs;
|
||||
}
|
||||
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
|
|
|
|||
|
|
@ -22,17 +22,31 @@ namespace ie {
|
|||
// This class can be marked as SIMPLE, because it's implemented as pimpl
|
||||
class GAPI_EXPORTS_W_SIMPLE PyParams {
|
||||
public:
|
||||
GAPI_WRAP
|
||||
PyParams() = default;
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams(const std::string &tag,
|
||||
const std::string &model,
|
||||
const std::string &weights,
|
||||
const std::string &device);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams(const std::string &tag,
|
||||
const std::string &model,
|
||||
const std::string &device);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& constInput(const std::string &layer_name,
|
||||
const cv::Mat &data,
|
||||
TraitAs hint = TraitAs::TENSOR);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgNumRequests(size_t nireq);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgBatchSize(const size_t size);
|
||||
|
||||
GBackend backend() const;
|
||||
std::string tag() const;
|
||||
cv::util::any params() const;
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@
|
|||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2019 Intel Corporation
|
||||
// Copyright (C) 2019-2021 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_INFER_IE_HPP
|
||||
#define OPENCV_GAPI_INFER_IE_HPP
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <tuple> // tuple, tuple_size
|
||||
|
|
@ -23,12 +24,17 @@
|
|||
namespace cv {
|
||||
namespace gapi {
|
||||
// FIXME: introduce a new sub-namespace for NN?
|
||||
|
||||
/**
|
||||
* @brief This namespace contains G-API OpenVINO backend functions,
|
||||
* structures, and symbols.
|
||||
*/
|
||||
namespace ie {
|
||||
|
||||
GAPI_EXPORTS cv::gapi::GBackend backend();
|
||||
|
||||
/**
|
||||
* Specify how G-API and IE should trait input data
|
||||
* Specifies how G-API and IE should trait input data
|
||||
*
|
||||
* In OpenCV, the same cv::Mat is used to represent both
|
||||
* image and tensor data. Sometimes those are hardly distinguishable,
|
||||
|
|
@ -46,28 +52,39 @@ enum class TraitAs: int
|
|||
using IEConfig = std::map<std::string, std::string>;
|
||||
|
||||
namespace detail {
|
||||
struct ParamDesc {
|
||||
std::string model_path;
|
||||
std::string weights_path;
|
||||
std::string device_id;
|
||||
struct ParamDesc {
|
||||
std::string model_path;
|
||||
std::string weights_path;
|
||||
std::string device_id;
|
||||
|
||||
// NB: Here order follows the `Net` API
|
||||
std::vector<std::string> input_names;
|
||||
std::vector<std::string> output_names;
|
||||
std::vector<std::string> input_names;
|
||||
std::vector<std::string> output_names;
|
||||
|
||||
using ConstInput = std::pair<cv::Mat, TraitAs>;
|
||||
std::unordered_map<std::string, ConstInput> const_inputs;
|
||||
using ConstInput = std::pair<cv::Mat, TraitAs>;
|
||||
std::unordered_map<std::string, ConstInput> const_inputs;
|
||||
|
||||
// NB: nun_* may differ from topology's real input/output port numbers
|
||||
// (e.g. topology's partial execution)
|
||||
std::size_t num_in; // How many inputs are defined in the operation
|
||||
std::size_t num_out; // How many outputs are defined in the operation
|
||||
std::size_t num_in;
|
||||
std::size_t num_out;
|
||||
|
||||
enum class Kind { Load, Import };
|
||||
Kind kind;
|
||||
bool is_generic;
|
||||
IEConfig config;
|
||||
};
|
||||
enum class Kind {Load, Import};
|
||||
Kind kind;
|
||||
bool is_generic;
|
||||
IEConfig config;
|
||||
|
||||
std::map<std::string, std::vector<std::size_t>> reshape_table;
|
||||
std::unordered_set<std::string> layer_names_to_reshape;
|
||||
|
||||
// NB: Number of asyncrhonious infer requests
|
||||
size_t nireq;
|
||||
|
||||
// NB: An optional config to setup RemoteContext for IE
|
||||
cv::util::any context_config;
|
||||
|
||||
// NB: batch_size can't be equal to 1 by default, because some of models
|
||||
// have 2D (Layout::NC) input and if the first dimension not equal to 1
|
||||
// net.setBatchSize(1) will overwrite it.
|
||||
cv::optional<size_t> batch_size;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
// FIXME: this is probably a shared (reusable) thing
|
||||
|
|
@ -81,8 +98,21 @@ struct PortCfg {
|
|||
, std::tuple_size<typename Net::OutArgs>::value >;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This structure provides functions
|
||||
* that fill inference parameters for "OpenVINO Toolkit" model.
|
||||
*/
|
||||
template<typename Net> class Params {
|
||||
public:
|
||||
/** @brief Class constructor.
|
||||
|
||||
Constructs Params based on model information and specifies default values for other
|
||||
inference description parameters. Model is loaded and compiled using "OpenVINO Toolkit".
|
||||
|
||||
@param model Path to topology IR (.xml file).
|
||||
@param weights Path to weights (.bin file).
|
||||
@param device target device to use.
|
||||
*/
|
||||
Params(const std::string &model,
|
||||
const std::string &weights,
|
||||
const std::string &device)
|
||||
|
|
@ -91,9 +121,21 @@ public:
|
|||
, std::tuple_size<typename Net::OutArgs>::value // num_out
|
||||
, detail::ParamDesc::Kind::Load
|
||||
, false
|
||||
, {}
|
||||
, {}
|
||||
, {}
|
||||
, 1u
|
||||
, {}
|
||||
, {}} {
|
||||
};
|
||||
|
||||
/** @overload
|
||||
Use this constructor to work with pre-compiled network.
|
||||
Model is imported from a pre-compiled blob.
|
||||
|
||||
@param model Path to model.
|
||||
@param device target device to use.
|
||||
*/
|
||||
Params(const std::string &model,
|
||||
const std::string &device)
|
||||
: desc{ model, {}, device, {}, {}, {}
|
||||
|
|
@ -101,25 +143,61 @@ public:
|
|||
, std::tuple_size<typename Net::OutArgs>::value // num_out
|
||||
, detail::ParamDesc::Kind::Import
|
||||
, false
|
||||
, {}
|
||||
, {}
|
||||
, {}
|
||||
, 1u
|
||||
, {}
|
||||
, {}} {
|
||||
};
|
||||
|
||||
Params<Net>& cfgInputLayers(const typename PortCfg<Net>::In &ll) {
|
||||
/** @brief Specifies sequence of network input layers names for inference.
|
||||
|
||||
The function is used to associate cv::gapi::infer<> inputs with the model inputs.
|
||||
Number of names has to match the number of network inputs as defined in G_API_NET().
|
||||
In case a network has only single input layer, there is no need to specify name manually.
|
||||
|
||||
@param layer_names std::array<std::string, N> where N is the number of inputs
|
||||
as defined in the @ref G_API_NET. Contains names of input layers.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgInputLayers(const typename PortCfg<Net>::In &layer_names) {
|
||||
desc.input_names.clear();
|
||||
desc.input_names.reserve(ll.size());
|
||||
std::copy(ll.begin(), ll.end(),
|
||||
desc.input_names.reserve(layer_names.size());
|
||||
std::copy(layer_names.begin(), layer_names.end(),
|
||||
std::back_inserter(desc.input_names));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Params<Net>& cfgOutputLayers(const typename PortCfg<Net>::Out &ll) {
|
||||
/** @brief Specifies sequence of network output layers names for inference.
|
||||
|
||||
The function is used to associate cv::gapi::infer<> outputs with the model outputs.
|
||||
Number of names has to match the number of network outputs as defined in G_API_NET().
|
||||
In case a network has only single output layer, there is no need to specify name manually.
|
||||
|
||||
@param layer_names std::array<std::string, N> where N is the number of outputs
|
||||
as defined in the @ref G_API_NET. Contains names of output layers.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgOutputLayers(const typename PortCfg<Net>::Out &layer_names) {
|
||||
desc.output_names.clear();
|
||||
desc.output_names.reserve(ll.size());
|
||||
std::copy(ll.begin(), ll.end(),
|
||||
desc.output_names.reserve(layer_names.size());
|
||||
std::copy(layer_names.begin(), layer_names.end(),
|
||||
std::back_inserter(desc.output_names));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies a constant input.
|
||||
|
||||
The function is used to set a constant input. This input has to be
|
||||
a preprocessed tensor if its type is TENSOR. Need to provide name of the
|
||||
network layer which will receive provided data.
|
||||
|
||||
@param layer_name Name of network layer.
|
||||
@param data cv::Mat that contains data which will be associated with network layer.
|
||||
@param hint Input type @sa cv::gapi::ie::TraitAs.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& constInput(const std::string &layer_name,
|
||||
const cv::Mat &data,
|
||||
TraitAs hint = TraitAs::TENSOR) {
|
||||
|
|
@ -127,13 +205,134 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies OpenVINO plugin configuration.
|
||||
|
||||
The function is used to set configuration for OpenVINO plugin. Some parameters
|
||||
can be different for each plugin. Please follow https://docs.openvinotoolkit.org/latest/index.html
|
||||
to check information about specific plugin.
|
||||
|
||||
@param cfg Map of pairs: (config parameter name, config parameter value).
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params& pluginConfig(const IEConfig& cfg) {
|
||||
desc.config = cfg;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
Function with a rvalue parameter.
|
||||
|
||||
@param cfg rvalue map of pairs: (config parameter name, config parameter value).
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params& pluginConfig(IEConfig&& cfg) {
|
||||
desc.config = std::move(cfg);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Params& pluginConfig(const IEConfig& cfg) {
|
||||
desc.config = cfg;
|
||||
/** @brief Specifies configuration for RemoteContext in InferenceEngine.
|
||||
|
||||
When RemoteContext is configured the backend imports the networks using the context.
|
||||
It also expects cv::MediaFrames to be actually remote, to operate with blobs via the context.
|
||||
|
||||
@param ctx_cfg cv::util::any value which holds InferenceEngine::ParamMap.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params& cfgContextParams(const cv::util::any& ctx_cfg) {
|
||||
desc.context_config = ctx_cfg;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
Function with an rvalue parameter.
|
||||
|
||||
@param ctx_cfg cv::util::any value which holds InferenceEngine::ParamMap.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params& cfgContextParams(cv::util::any&& ctx_cfg) {
|
||||
desc.context_config = std::move(ctx_cfg);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies number of asynchronous inference requests.
|
||||
|
||||
@param nireq Number of inference asynchronous requests.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params& cfgNumRequests(size_t nireq) {
|
||||
GAPI_Assert(nireq > 0 && "Number of infer requests must be greater than zero!");
|
||||
desc.nireq = nireq;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies new input shapes for the network inputs.
|
||||
|
||||
The function is used to specify new input shapes for the network inputs.
|
||||
Follow https://docs.openvinotoolkit.org/latest/classInferenceEngine_1_1networkNetwork.html
|
||||
for additional information.
|
||||
|
||||
@param reshape_table Map of pairs: name of corresponding data and its dimension.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgInputReshape(const std::map<std::string, std::vector<std::size_t>>& reshape_table) {
|
||||
desc.reshape_table = reshape_table;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params<Net>& cfgInputReshape(std::map<std::string, std::vector<std::size_t>>&& reshape_table) {
|
||||
desc.reshape_table = std::move(reshape_table);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
|
||||
@param layer_name Name of layer.
|
||||
@param layer_dims New dimensions for this layer.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgInputReshape(const std::string& layer_name, const std::vector<size_t>& layer_dims) {
|
||||
desc.reshape_table.emplace(layer_name, layer_dims);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params<Net>& cfgInputReshape(std::string&& layer_name, std::vector<size_t>&& layer_dims) {
|
||||
desc.reshape_table.emplace(layer_name, layer_dims);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
|
||||
@param layer_names set of names of network layers that will be used for network reshape.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgInputReshape(const std::unordered_set<std::string>& layer_names) {
|
||||
desc.layer_names_to_reshape = layer_names;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
|
||||
@param layer_names rvalue set of the selected layers will be reshaped automatically
|
||||
its input image size.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgInputReshape(std::unordered_set<std::string>&& layer_names) {
|
||||
desc.layer_names_to_reshape = std::move(layer_names);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies the inference batch size.
|
||||
|
||||
The function is used to specify inference batch size.
|
||||
Follow https://docs.openvinotoolkit.org/latest/classInferenceEngine_1_1CNNNetwork.html#a8e9d19270a48aab50cb5b1c43eecb8e9 for additional information
|
||||
|
||||
@param size batch size which will be used.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgBatchSize(const size_t size) {
|
||||
desc.batch_size = cv::util::make_optional(size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -147,29 +346,118 @@ protected:
|
|||
detail::ParamDesc desc;
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief This structure provides functions for generic network type that
|
||||
* fill inference parameters.
|
||||
* @see struct Generic
|
||||
*/
|
||||
template<>
|
||||
class Params<cv::gapi::Generic> {
|
||||
public:
|
||||
/** @brief Class constructor.
|
||||
|
||||
Constructs Params based on model information and sets default values for other
|
||||
inference description parameters. Model is loaded and compiled using OpenVINO Toolkit.
|
||||
|
||||
@param tag string tag of the network for which these parameters are intended.
|
||||
@param model path to topology IR (.xml file).
|
||||
@param weights path to weights (.bin file).
|
||||
@param device target device to use.
|
||||
*/
|
||||
Params(const std::string &tag,
|
||||
const std::string &model,
|
||||
const std::string &weights,
|
||||
const std::string &device)
|
||||
: desc{ model, weights, device, {}, {}, {}, 0u, 0u, detail::ParamDesc::Kind::Load, true, {}}, m_tag(tag) {
|
||||
: desc{ model, weights, device, {}, {}, {}, 0u, 0u,
|
||||
detail::ParamDesc::Kind::Load, true, {}, {}, {}, 1u,
|
||||
{}, {}},
|
||||
m_tag(tag) {
|
||||
};
|
||||
|
||||
/** @overload
|
||||
|
||||
This constructor for pre-compiled networks. Model is imported from pre-compiled
|
||||
blob.
|
||||
|
||||
@param tag string tag of the network for which these parameters are intended.
|
||||
@param model path to model.
|
||||
@param device target device to use.
|
||||
*/
|
||||
Params(const std::string &tag,
|
||||
const std::string &model,
|
||||
const std::string &device)
|
||||
: desc{ model, {}, device, {}, {}, {}, 0u, 0u, detail::ParamDesc::Kind::Import, true, {}}, m_tag(tag) {
|
||||
: desc{ model, {}, device, {}, {}, {}, 0u, 0u,
|
||||
detail::ParamDesc::Kind::Import, true, {}, {}, {}, 1u,
|
||||
{}, {}},
|
||||
m_tag(tag) {
|
||||
};
|
||||
|
||||
/** @see ie::Params::pluginConfig. */
|
||||
Params& pluginConfig(const IEConfig& cfg) {
|
||||
desc.config = cfg;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params& pluginConfig(IEConfig&& cfg) {
|
||||
desc.config = std::move(cfg);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Params& pluginConfig(const IEConfig& cfg) {
|
||||
desc.config = cfg;
|
||||
/** @see ie::Params::constInput. */
|
||||
Params& constInput(const std::string &layer_name,
|
||||
const cv::Mat &data,
|
||||
TraitAs hint = TraitAs::TENSOR) {
|
||||
desc.const_inputs[layer_name] = {data, hint};
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @see ie::Params::cfgNumRequests. */
|
||||
Params& cfgNumRequests(size_t nireq) {
|
||||
GAPI_Assert(nireq > 0 && "Number of infer requests must be greater than zero!");
|
||||
desc.nireq = nireq;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @see ie::Params::cfgInputReshape */
|
||||
Params& cfgInputReshape(const std::map<std::string, std::vector<std::size_t>>&reshape_table) {
|
||||
desc.reshape_table = reshape_table;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params& cfgInputReshape(std::map<std::string, std::vector<std::size_t>> && reshape_table) {
|
||||
desc.reshape_table = std::move(reshape_table);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params& cfgInputReshape(std::string && layer_name, std::vector<size_t> && layer_dims) {
|
||||
desc.reshape_table.emplace(layer_name, layer_dims);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params& cfgInputReshape(const std::string & layer_name, const std::vector<size_t>&layer_dims) {
|
||||
desc.reshape_table.emplace(layer_name, layer_dims);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params& cfgInputReshape(std::unordered_set<std::string> && layer_names) {
|
||||
desc.layer_names_to_reshape = std::move(layer_names);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params& cfgInputReshape(const std::unordered_set<std::string>&layer_names) {
|
||||
desc.layer_names_to_reshape = layer_names;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @see ie::Params::cfgBatchSize */
|
||||
Params& cfgBatchSize(const size_t size) {
|
||||
desc.batch_size = cv::util::make_optional(size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
// Copyright (C) 2020-2021 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_INFER_ONNX_HPP
|
||||
#define OPENCV_GAPI_INFER_ONNX_HPP
|
||||
|
|
@ -20,6 +20,10 @@
|
|||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
|
||||
/**
|
||||
* @brief This namespace contains G-API ONNX Runtime backend functions, structures, and symbols.
|
||||
*/
|
||||
namespace onnx {
|
||||
|
||||
GAPI_EXPORTS cv::gapi::GBackend backend();
|
||||
|
|
@ -34,30 +38,35 @@ enum class TraitAs: int {
|
|||
using PostProc = std::function<void(const std::unordered_map<std::string, cv::Mat> &,
|
||||
std::unordered_map<std::string, cv::Mat> &)>;
|
||||
|
||||
|
||||
namespace detail {
|
||||
/**
|
||||
* @brief This structure contains description of inference parameters
|
||||
* which is specific to ONNX models.
|
||||
*/
|
||||
struct ParamDesc {
|
||||
std::string model_path;
|
||||
std::string model_path; //!< Path to model.
|
||||
|
||||
// NB: nun_* may differ from topology's real input/output port numbers
|
||||
// (e.g. topology's partial execution)
|
||||
std::size_t num_in; // How many inputs are defined in the operation
|
||||
std::size_t num_out; // How many outputs are defined in the operation
|
||||
std::size_t num_in; //!< How many inputs are defined in the operation
|
||||
std::size_t num_out; //!< How many outputs are defined in the operation
|
||||
|
||||
// NB: Here order follows the `Net` API
|
||||
std::vector<std::string> input_names;
|
||||
std::vector<std::string> output_names;
|
||||
std::vector<std::string> input_names; //!< Names of input network layers.
|
||||
std::vector<std::string> output_names; //!< Names of output network layers.
|
||||
|
||||
using ConstInput = std::pair<cv::Mat, TraitAs>;
|
||||
std::unordered_map<std::string, ConstInput> const_inputs;
|
||||
std::unordered_map<std::string, ConstInput> const_inputs; //!< Map with pair of name of network layer and ConstInput which will be associated with this.
|
||||
|
||||
std::vector<cv::Scalar> mean;
|
||||
std::vector<cv::Scalar> stdev;
|
||||
std::vector<cv::Scalar> mean; //!< Mean values for preprocessing.
|
||||
std::vector<cv::Scalar> stdev; //!< Standard deviation values for preprocessing.
|
||||
|
||||
std::vector<cv::GMatDesc> out_metas;
|
||||
PostProc custom_post_proc;
|
||||
std::vector<cv::GMatDesc> out_metas; //!< Out meta information about your output (type, dimension).
|
||||
PostProc custom_post_proc; //!< Post processing function.
|
||||
|
||||
std::vector<bool> normalize;
|
||||
std::vector<bool> normalize; //!< Vector of bool values that enabled or disabled normalize of input data.
|
||||
|
||||
std::vector<std::string> names_to_remap; //!< Names of output layers that will be processed in PostProc function.
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
|
|
@ -77,30 +86,71 @@ struct PortCfg {
|
|||
, std::tuple_size<typename Net::InArgs>::value >;
|
||||
};
|
||||
|
||||
/**
|
||||
* Contains description of inference parameters and kit of functions that
|
||||
* fill this parameters.
|
||||
*/
|
||||
template<typename Net> class Params {
|
||||
public:
|
||||
/** @brief Class constructor.
|
||||
|
||||
Constructs Params based on model information and sets default values for other
|
||||
inference description parameters.
|
||||
|
||||
@param model Path to model (.onnx file).
|
||||
*/
|
||||
Params(const std::string &model) {
|
||||
desc.model_path = model;
|
||||
desc.num_in = std::tuple_size<typename Net::InArgs>::value;
|
||||
desc.num_out = std::tuple_size<typename Net::OutArgs>::value;
|
||||
};
|
||||
|
||||
// BEGIN(G-API's network parametrization API)
|
||||
GBackend backend() const { return cv::gapi::onnx::backend(); }
|
||||
std::string tag() const { return Net::tag(); }
|
||||
cv::util::any params() const { return { desc }; }
|
||||
// END(G-API's network parametrization API)
|
||||
/** @brief Specifies sequence of network input layers names for inference.
|
||||
|
||||
Params<Net>& cfgInputLayers(const typename PortCfg<Net>::In &ll) {
|
||||
desc.input_names.assign(ll.begin(), ll.end());
|
||||
The function is used to associate data of graph inputs with input layers of
|
||||
network topology. Number of names has to match the number of network inputs. If a network
|
||||
has only one input layer, there is no need to call it as the layer is
|
||||
associated with input automatically but this doesn't prevent you from
|
||||
doing it yourself. Count of names has to match to number of network inputs.
|
||||
|
||||
@param layer_names std::array<std::string, N> where N is the number of inputs
|
||||
as defined in the @ref G_API_NET. Contains names of input layers.
|
||||
@return the reference on modified object.
|
||||
*/
|
||||
Params<Net>& cfgInputLayers(const typename PortCfg<Net>::In &layer_names) {
|
||||
desc.input_names.assign(layer_names.begin(), layer_names.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
Params<Net>& cfgOutputLayers(const typename PortCfg<Net>::Out &ll) {
|
||||
desc.output_names.assign(ll.begin(), ll.end());
|
||||
/** @brief Specifies sequence of output layers names for inference.
|
||||
|
||||
The function is used to associate data of graph outputs with output layers of
|
||||
network topology. If a network has only one output layer, there is no need to call it
|
||||
as the layer is associated with ouput automatically but this doesn't prevent
|
||||
you from doing it yourself. Count of names has to match to number of network
|
||||
outputs or you can set your own output but for this case you have to
|
||||
additionally use @ref cfgPostProc function.
|
||||
|
||||
@param layer_names std::array<std::string, N> where N is the number of outputs
|
||||
as defined in the @ref G_API_NET. Contains names of output layers.
|
||||
@return the reference on modified object.
|
||||
*/
|
||||
Params<Net>& cfgOutputLayers(const typename PortCfg<Net>::Out &layer_names) {
|
||||
desc.output_names.assign(layer_names.begin(), layer_names.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Sets a constant input.
|
||||
|
||||
The function is used to set constant input. This input has to be
|
||||
a prepared tensor since preprocessing is disabled for this case. You should
|
||||
provide name of network layer which will receive provided data.
|
||||
|
||||
@param layer_name Name of network layer.
|
||||
@param data cv::Mat that contains data which will be associated with network layer.
|
||||
@param hint Type of input (TENSOR).
|
||||
@return the reference on modified object.
|
||||
*/
|
||||
Params<Net>& constInput(const std::string &layer_name,
|
||||
const cv::Mat &data,
|
||||
TraitAs hint = TraitAs::TENSOR) {
|
||||
|
|
@ -108,6 +158,17 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies mean value and standard deviation for preprocessing.
|
||||
|
||||
The function is used to set mean value and standard deviation for preprocessing
|
||||
of input data.
|
||||
|
||||
@param m std::array<cv::Scalar, N> where N is the number of inputs
|
||||
as defined in the @ref G_API_NET. Contains mean values.
|
||||
@param s std::array<cv::Scalar, N> where N is the number of inputs
|
||||
as defined in the @ref G_API_NET. Contains standard deviation values.
|
||||
@return the reference on modified object.
|
||||
*/
|
||||
Params<Net>& cfgMeanStd(const typename PortCfg<Net>::NormCoefs &m,
|
||||
const typename PortCfg<Net>::NormCoefs &s) {
|
||||
desc.mean.assign(m.begin(), m.end());
|
||||
|
|
@ -115,18 +176,103 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
Params<Net>& cfgPostProc(const std::vector<cv::GMatDesc> &outs,
|
||||
const PostProc &pp) {
|
||||
desc.out_metas = outs;
|
||||
desc.custom_post_proc = pp;
|
||||
/** @brief Configures graph output and provides the post processing function from user.
|
||||
|
||||
The function is used when you work with networks with dynamic outputs.
|
||||
Since we can't know dimensions of inference result needs provide them for
|
||||
construction of graph output. This dimensions can differ from inference result.
|
||||
So you have to provide @ref PostProc function that gets information from inference
|
||||
result and fill output which is constructed by dimensions from out_metas.
|
||||
|
||||
@param out_metas Out meta information about your output (type, dimension).
|
||||
@param remap_function Post processing function, which has two parameters. First is onnx
|
||||
result, second is graph output. Both parameters is std::map that contain pair of
|
||||
layer's name and cv::Mat.
|
||||
@return the reference on modified object.
|
||||
*/
|
||||
Params<Net>& cfgPostProc(const std::vector<cv::GMatDesc> &out_metas,
|
||||
const PostProc &remap_function) {
|
||||
desc.out_metas = out_metas;
|
||||
desc.custom_post_proc = remap_function;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Params<Net>& cfgNormalize(const typename PortCfg<Net>::Normalize &n) {
|
||||
desc.normalize.assign(n.begin(), n.end());
|
||||
/** @overload
|
||||
Function with a rvalue parameters.
|
||||
|
||||
@param out_metas rvalue out meta information about your output (type, dimension).
|
||||
@param remap_function rvalue post processing function, which has two parameters. First is onnx
|
||||
result, second is graph output. Both parameters is std::map that contain pair of
|
||||
layer's name and cv::Mat.
|
||||
@return the reference on modified object.
|
||||
*/
|
||||
Params<Net>& cfgPostProc(std::vector<cv::GMatDesc> &&out_metas,
|
||||
PostProc &&remap_function) {
|
||||
desc.out_metas = std::move(out_metas);
|
||||
desc.custom_post_proc = std::move(remap_function);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
The function has additional parameter names_to_remap. This parameter provides
|
||||
information about output layers which will be used for inference and post
|
||||
processing function.
|
||||
|
||||
@param out_metas Out meta information.
|
||||
@param remap_function Post processing function.
|
||||
@param names_to_remap Names of output layers. network's inference will
|
||||
be done on these layers. Inference's result will be processed in post processing
|
||||
function using these names.
|
||||
@return the reference on modified object.
|
||||
*/
|
||||
Params<Net>& cfgPostProc(const std::vector<cv::GMatDesc> &out_metas,
|
||||
const PostProc &remap_function,
|
||||
const std::vector<std::string> &names_to_remap) {
|
||||
desc.out_metas = out_metas;
|
||||
desc.custom_post_proc = remap_function;
|
||||
desc.names_to_remap = names_to_remap;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
Function with a rvalue parameters and additional parameter names_to_remap.
|
||||
|
||||
@param out_metas rvalue out meta information.
|
||||
@param remap_function rvalue post processing function.
|
||||
@param names_to_remap rvalue names of output layers. network's inference will
|
||||
be done on these layers. Inference's result will be processed in post processing
|
||||
function using these names.
|
||||
@return the reference on modified object.
|
||||
*/
|
||||
Params<Net>& cfgPostProc(std::vector<cv::GMatDesc> &&out_metas,
|
||||
PostProc &&remap_function,
|
||||
std::vector<std::string> &&names_to_remap) {
|
||||
desc.out_metas = std::move(out_metas);
|
||||
desc.custom_post_proc = std::move(remap_function);
|
||||
desc.names_to_remap = std::move(names_to_remap);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies normalize parameter for preprocessing.
|
||||
|
||||
The function is used to set normalize parameter for preprocessing of input data.
|
||||
|
||||
@param normalizations std::array<cv::Scalar, N> where N is the number of inputs
|
||||
as defined in the @ref G_API_NET. Сontains bool values that enabled or disabled
|
||||
normalize of input data.
|
||||
@return the reference on modified object.
|
||||
*/
|
||||
Params<Net>& cfgNormalize(const typename PortCfg<Net>::Normalize &normalizations) {
|
||||
desc.normalize.assign(normalizations.begin(), normalizations.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// BEGIN(G-API's network parametrization API)
|
||||
GBackend backend() const { return cv::gapi::onnx::backend(); }
|
||||
std::string tag() const { return Net::tag(); }
|
||||
cv::util::any params() const { return { desc }; }
|
||||
// END(G-API's network parametrization API)
|
||||
|
||||
protected:
|
||||
detail::ParamDesc desc;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -64,12 +64,13 @@ detection is smaller than confidence threshold, detection is rejected.
|
|||
given label will get to the output.
|
||||
@return a tuple with a vector of detected boxes and a vector of appropriate labels.
|
||||
*/
|
||||
GAPI_EXPORTS std::tuple<GArray<Rect>, GArray<int>> parseSSD(const GMat& in,
|
||||
const GOpaque<Size>& inSz,
|
||||
const float confidenceThreshold = 0.5f,
|
||||
const int filterLabel = -1);
|
||||
GAPI_EXPORTS_W std::tuple<GArray<Rect>, GArray<int>> parseSSD(const GMat& in,
|
||||
const GOpaque<Size>& inSz,
|
||||
const float confidenceThreshold = 0.5f,
|
||||
const int filterLabel = -1);
|
||||
|
||||
/** @brief Parses output of SSD network.
|
||||
|
||||
/** @overload
|
||||
Extracts detection information (box, confidence) from SSD output and
|
||||
filters it by given confidence and by going out of bounds.
|
||||
|
||||
|
|
@ -85,11 +86,11 @@ the larger side of the rectangle.
|
|||
@param filterOutOfBounds If provided true, out-of-frame boxes are filtered.
|
||||
@return a vector of detected bounding boxes.
|
||||
*/
|
||||
GAPI_EXPORTS GArray<Rect> parseSSD(const GMat& in,
|
||||
const GOpaque<Size>& inSz,
|
||||
const float confidenceThreshold = 0.5f,
|
||||
const bool alignmentToSquare = false,
|
||||
const bool filterOutOfBounds = false);
|
||||
GAPI_EXPORTS_W GArray<Rect> parseSSD(const GMat& in,
|
||||
const GOpaque<Size>& inSz,
|
||||
const float confidenceThreshold,
|
||||
const bool alignmentToSquare,
|
||||
const bool filterOutOfBounds);
|
||||
|
||||
/** @brief Parses output of Yolo network.
|
||||
|
||||
|
|
@ -112,12 +113,12 @@ If 1.f, nms is not performed and no boxes are rejected.
|
|||
<a href="https://github.com/openvinotoolkit/open_model_zoo/blob/master/models/public/yolo-v2-tiny-tf/yolo-v2-tiny-tf.md">documentation</a>.
|
||||
@return a tuple with a vector of detected boxes and a vector of appropriate labels.
|
||||
*/
|
||||
GAPI_EXPORTS std::tuple<GArray<Rect>, GArray<int>> parseYolo(const GMat& in,
|
||||
const GOpaque<Size>& inSz,
|
||||
const float confidenceThreshold = 0.5f,
|
||||
const float nmsThreshold = 0.5f,
|
||||
const std::vector<float>& anchors
|
||||
= nn::parsers::GParseYolo::defaultAnchors());
|
||||
GAPI_EXPORTS_W std::tuple<GArray<Rect>, GArray<int>> parseYolo(const GMat& in,
|
||||
const GOpaque<Size>& inSz,
|
||||
const float confidenceThreshold = 0.5f,
|
||||
const float nmsThreshold = 0.5f,
|
||||
const std::vector<float>& anchors
|
||||
= nn::parsers::GParseYolo::defaultAnchors());
|
||||
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
|
|
|||
|
|
@ -13,26 +13,142 @@
|
|||
#include <utility> // forward<>()
|
||||
|
||||
#include <opencv2/gapi/gframe.hpp>
|
||||
#include <opencv2/gapi/util/any.hpp>
|
||||
|
||||
// Forward declaration
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace s11n {
|
||||
struct IOStream;
|
||||
struct IIStream;
|
||||
} // namespace s11n
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
namespace cv {
|
||||
|
||||
/** \addtogroup gapi_data_structures
|
||||
* @{
|
||||
*
|
||||
* @brief Extra G-API data structures used to pass input/output data
|
||||
* to the graph for processing.
|
||||
*/
|
||||
/**
|
||||
* @brief cv::MediaFrame class represents an image/media frame
|
||||
* obtained from an external source.
|
||||
*
|
||||
* cv::MediaFrame represents image data as specified in
|
||||
* cv::MediaFormat. cv::MediaFrame is designed to be a thin wrapper over some
|
||||
* external memory of buffer; the class itself provides an uniform
|
||||
* interface over such types of memory. cv::MediaFrame wraps data from
|
||||
* a camera driver or from a media codec and provides an abstraction
|
||||
* layer over this memory to G-API. MediaFrame defines a compact interface
|
||||
* to access and manage the underlying data; the implementation is
|
||||
* fully defined by the associated Adapter (which is usually
|
||||
* user-defined).
|
||||
*
|
||||
* @sa cv::RMat
|
||||
*/
|
||||
class GAPI_EXPORTS MediaFrame {
|
||||
public:
|
||||
enum class Access { R, W };
|
||||
/// This enum defines different types of cv::MediaFrame provided
|
||||
/// access to the underlying data. Note that different flags can't
|
||||
/// be combined in this version.
|
||||
enum class Access {
|
||||
R, ///< Access data for reading
|
||||
W, ///< Access data for writing
|
||||
};
|
||||
class IAdapter;
|
||||
class View;
|
||||
using AdapterPtr = std::unique_ptr<IAdapter>;
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty MediaFrame
|
||||
*
|
||||
* The constructed object has no any data associated with it.
|
||||
*/
|
||||
MediaFrame();
|
||||
explicit MediaFrame(AdapterPtr &&);
|
||||
template<class T, class... Args> static cv::MediaFrame Create(Args&&...);
|
||||
|
||||
View access(Access) const;
|
||||
/**
|
||||
* @brief Constructs a MediaFrame with the given
|
||||
* Adapter. MediaFrame takes ownership over the passed adapter.
|
||||
*
|
||||
* @param p an unique pointer to instance of IAdapter derived class.
|
||||
*/
|
||||
explicit MediaFrame(AdapterPtr &&p);
|
||||
|
||||
/**
|
||||
* @overload
|
||||
* @brief Constructs a MediaFrame with the given parameters for
|
||||
* the Adapter. The adapter of type `T` is costructed on the fly.
|
||||
*
|
||||
* @param args list of arguments to construct an adapter of type
|
||||
* `T`.
|
||||
*/
|
||||
template<class T, class... Args> static cv::MediaFrame Create(Args&&... args);
|
||||
|
||||
/**
|
||||
* @brief Obtain access to the underlying data with the given
|
||||
* mode.
|
||||
*
|
||||
* Depending on the associated Adapter and the data wrapped, this
|
||||
* method may be cheap (e.g., the underlying memory is local) or
|
||||
* costly (if the underlying memory is external or device
|
||||
* memory).
|
||||
*
|
||||
* @param mode an access mode flag
|
||||
* @return a MediaFrame::View object. The views should be handled
|
||||
* carefully, refer to the MediaFrame::View documentation for details.
|
||||
*/
|
||||
View access(Access mode) const;
|
||||
|
||||
/**
|
||||
* @brief Returns a media frame descriptor -- the information
|
||||
* about the media format, dimensions, etc.
|
||||
* @return a cv::GFrameDesc
|
||||
*/
|
||||
cv::GFrameDesc desc() const;
|
||||
|
||||
// FIXME: design a better solution
|
||||
// Should be used only if the actual adapter provides implementation
|
||||
/// @private -- exclude from the OpenCV documentation for now.
|
||||
cv::util::any blobParams() const;
|
||||
|
||||
/**
|
||||
* @brief Casts and returns the associated MediaFrame adapter to
|
||||
* the particular adapter type `T`, returns nullptr if the type is
|
||||
* different.
|
||||
*
|
||||
* This method may be useful if the adapter type is known by the
|
||||
* caller, and some lower level access to the memory is required.
|
||||
* Depending on the memory type, it may be more efficient than
|
||||
* access().
|
||||
*
|
||||
* @return a pointer to the adapter object, nullptr if the adapter
|
||||
* type is different.
|
||||
*/
|
||||
template<typename T> T* get() const {
|
||||
static_assert(std::is_base_of<IAdapter, T>::value,
|
||||
"T is not derived from cv::MediaFrame::IAdapter!");
|
||||
auto* adapter = getAdapter();
|
||||
GAPI_Assert(adapter != nullptr);
|
||||
return dynamic_cast<T*>(adapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serialize MediaFrame's data to a byte array.
|
||||
*
|
||||
* @note The actual logic is implemented by frame's adapter class.
|
||||
* Does nothing by default.
|
||||
*
|
||||
* @param os Bytestream to store serialized MediaFrame data in.
|
||||
*/
|
||||
void serialize(cv::gapi::s11n::IOStream& os) const;
|
||||
|
||||
private:
|
||||
struct Priv;
|
||||
std::shared_ptr<Priv> m;
|
||||
IAdapter* getAdapter() const;
|
||||
};
|
||||
|
||||
template<class T, class... Args>
|
||||
|
|
@ -41,6 +157,43 @@ inline cv::MediaFrame cv::MediaFrame::Create(Args&&... args) {
|
|||
return cv::MediaFrame(std::move(ptr));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Provides access to the MediaFrame's underlying data.
|
||||
*
|
||||
* This object contains the necessary information to access the pixel
|
||||
* data of the associated MediaFrame: arrays of pointers and strides
|
||||
* (distance between every plane row, in bytes) for every image
|
||||
* plane, as defined in cv::MediaFormat.
|
||||
* There may be up to four image planes in MediaFrame.
|
||||
*
|
||||
* Depending on the MediaFrame::Access flag passed in
|
||||
* MediaFrame::access(), a MediaFrame::View may be read- or
|
||||
* write-only.
|
||||
*
|
||||
* Depending on the MediaFrame::IAdapter implementation associated
|
||||
* with the parent MediaFrame, writing to memory with
|
||||
* MediaFrame::Access::R flag may have no effect or lead to
|
||||
* undefined behavior. Same applies to reading the memory with
|
||||
* MediaFrame::Access::W flag -- again, depending on the IAdapter
|
||||
* implementation, the host-side buffer the view provides access to
|
||||
* may have no current data stored in (so in-place editing of the
|
||||
* buffer contents may not be possible).
|
||||
*
|
||||
* MediaFrame::View objects must be handled carefully, as an external
|
||||
* resource associated with MediaFrame may be locked for the time the
|
||||
* MediaFrame::View object exists. Obtaining MediaFrame::View should
|
||||
* be seen as "map" and destroying it as "unmap" in the "map/unmap"
|
||||
* idiom (applicable to OpenCL, device memory, remote
|
||||
* memory).
|
||||
*
|
||||
* When a MediaFrame buffer is accessed for writing, and the memory
|
||||
* under MediaFrame::View::Ptrs is altered, the data synchronization
|
||||
* of a host-side and device/remote buffer is not guaranteed until the
|
||||
* MediaFrame::View is destroyed. In other words, the real data on the
|
||||
* device or in a remote target may be updated at the MediaFrame::View
|
||||
* destruction only -- but it depends on the associated
|
||||
* MediaFrame::IAdapter implementation.
|
||||
*/
|
||||
class GAPI_EXPORTS MediaFrame::View final {
|
||||
public:
|
||||
static constexpr const size_t MAX_PLANES = 4;
|
||||
|
|
@ -48,25 +201,56 @@ public:
|
|||
using Strides = std::array<std::size_t, MAX_PLANES>; // in bytes
|
||||
using Callback = std::function<void()>;
|
||||
|
||||
/// @private
|
||||
View(Ptrs&& ptrs, Strides&& strs, Callback &&cb = [](){});
|
||||
|
||||
/// @private
|
||||
View(const View&) = delete;
|
||||
|
||||
/// @private
|
||||
View(View&&) = default;
|
||||
|
||||
/// @private
|
||||
View& operator = (const View&) = delete;
|
||||
|
||||
~View();
|
||||
|
||||
Ptrs ptr;
|
||||
Strides stride;
|
||||
Ptrs ptr; ///< Array of image plane pointers
|
||||
Strides stride; ///< Array of image plane strides, in bytes.
|
||||
|
||||
private:
|
||||
Callback m_cb;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An interface class for MediaFrame data adapters.
|
||||
*
|
||||
* Implement this interface to wrap media data in the MediaFrame. It
|
||||
* makes sense to implement this class if there is a custom
|
||||
* cv::gapi::wip::IStreamSource defined -- in this case, a stream
|
||||
* source can produce MediaFrame objects with this adapter and the
|
||||
* media data may be passed to graph without any copy. For example, a
|
||||
* GStreamer-based stream source can implement an adapter over
|
||||
* `GstBuffer` and G-API will transparently use it in the graph.
|
||||
*/
|
||||
class GAPI_EXPORTS MediaFrame::IAdapter {
|
||||
public:
|
||||
virtual ~IAdapter() = 0;
|
||||
virtual cv::GFrameDesc meta() const = 0;
|
||||
virtual MediaFrame::View access(MediaFrame::Access) = 0;
|
||||
// FIXME: design a better solution
|
||||
// The default implementation does nothing
|
||||
virtual cv::util::any blobParams() const;
|
||||
virtual void serialize(cv::gapi::s11n::IOStream&) {
|
||||
GAPI_Assert(false && "Generic serialize method of MediaFrame::IAdapter does nothing by default. "
|
||||
"Please, implement it in derived class to properly serialize the object.");
|
||||
}
|
||||
virtual void deserialize(cv::gapi::s11n::IIStream&) {
|
||||
GAPI_Assert(false && "Generic deserialize method of MediaFrame::IAdapter does nothing by default. "
|
||||
"Please, implement it in derived class to properly deserialize the object.");
|
||||
}
|
||||
};
|
||||
/** @} */
|
||||
|
||||
} //namespace cv
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ namespace gimpl
|
|||
|
||||
namespace gapi
|
||||
{
|
||||
/**
|
||||
* @brief This namespace contains G-API OpenCL backend functions, structures, and symbols.
|
||||
*/
|
||||
namespace ocl
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -14,6 +14,12 @@
|
|||
# include <opencv2/core/cvdef.h>
|
||||
# include <opencv2/core/types.hpp>
|
||||
# include <opencv2/core/base.hpp>
|
||||
#define GAPI_OWN_TYPES_LIST cv::gapi::own::Rect, \
|
||||
cv::gapi::own::Size, \
|
||||
cv::gapi::own::Point, \
|
||||
cv::gapi::own::Point2f, \
|
||||
cv::gapi::own::Scalar, \
|
||||
cv::gapi::own::Mat
|
||||
#else // Without OpenCV
|
||||
# include <opencv2/gapi/own/cvdefs.hpp>
|
||||
# include <opencv2/gapi/own/types.hpp> // cv::gapi::own::Rect/Size/Point
|
||||
|
|
@ -28,6 +34,8 @@ namespace cv {
|
|||
using Scalar = gapi::own::Scalar;
|
||||
using Mat = gapi::own::Mat;
|
||||
} // namespace cv
|
||||
#define GAPI_OWN_TYPES_LIST cv::gapi::own::VoidType
|
||||
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
|
||||
#endif // OPENCV_GAPI_OPENCV_INCLUDES_HPP
|
||||
|
|
|
|||
|
|
@ -20,11 +20,12 @@ typedef char schar;
|
|||
|
||||
typedef unsigned short ushort;
|
||||
|
||||
#define CV_USRTYPE1 (void)"CV_USRTYPE1 support has been dropped in OpenCV 4.0"
|
||||
|
||||
#define CV_CN_MAX 512
|
||||
#define CV_CN_SHIFT 3
|
||||
#define CV_DEPTH_MAX (1 << CV_CN_SHIFT)
|
||||
|
||||
|
||||
#define CV_8U 0
|
||||
#define CV_8S 1
|
||||
#define CV_16U 2
|
||||
|
|
@ -33,7 +34,6 @@ typedef unsigned short ushort;
|
|||
#define CV_32F 5
|
||||
#define CV_64F 6
|
||||
#define CV_16F 7
|
||||
#define CV_USRTYPE1 8
|
||||
|
||||
#define CV_MAT_DEPTH_MASK (CV_DEPTH_MAX - 1)
|
||||
#define CV_MAT_DEPTH(flags) ((flags) & CV_MAT_DEPTH_MASK)
|
||||
|
|
@ -71,7 +71,6 @@ typedef unsigned short ushort;
|
|||
#define CV_32SC4 CV_MAKETYPE(CV_32S,4)
|
||||
#define CV_32SC(n) CV_MAKETYPE(CV_32S,(n))
|
||||
|
||||
|
||||
#define CV_16FC1 CV_MAKETYPE(CV_16F,1)
|
||||
#define CV_16FC2 CV_MAKETYPE(CV_16F,2)
|
||||
#define CV_16FC3 CV_MAKETYPE(CV_16F,3)
|
||||
|
|
@ -92,6 +91,16 @@ typedef unsigned short ushort;
|
|||
|
||||
// cvdef.h:
|
||||
|
||||
#ifndef CV_ALWAYS_INLINE
|
||||
# if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||
# define CV_ALWAYS_INLINE inline __attribute__((always_inline))
|
||||
# elif defined(_MSC_VER)
|
||||
# define CV_ALWAYS_INLINE __forceinline
|
||||
# else
|
||||
# define CV_ALWAYS_INLINE inline
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define CV_MAT_CN_MASK ((CV_CN_MAX - 1) << CV_CN_SHIFT)
|
||||
#define CV_MAT_CN(flags) ((((flags) & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1)
|
||||
#define CV_MAT_TYPE_MASK (CV_DEPTH_MAX*CV_CN_MAX - 1)
|
||||
|
|
|
|||
|
|
@ -12,10 +12,14 @@
|
|||
# include <opencv2/core/base.hpp>
|
||||
# define GAPI_EXPORTS CV_EXPORTS
|
||||
/* special informative macros for wrapper generators */
|
||||
# define GAPI_PROP CV_PROP
|
||||
# define GAPI_PROP_RW CV_PROP_RW
|
||||
# define GAPI_WRAP CV_WRAP
|
||||
# define GAPI_EXPORTS_W_SIMPLE CV_EXPORTS_W_SIMPLE
|
||||
# define GAPI_EXPORTS_W CV_EXPORTS_W
|
||||
# else
|
||||
# define GAPI_PROP
|
||||
# define GAPI_PROP_RW
|
||||
# define GAPI_WRAP
|
||||
# define GAPI_EXPORTS
|
||||
# define GAPI_EXPORTS_W_SIMPLE
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@
|
|||
#include <math.h>
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#include <opencv2/gapi/own/assert.hpp>
|
||||
#include <opencv2/gapi/util/type_traits.hpp>
|
||||
|
||||
namespace cv { namespace gapi { namespace own {
|
||||
//-----------------------------
|
||||
|
|
@ -22,16 +22,12 @@ namespace cv { namespace gapi { namespace own {
|
|||
//
|
||||
//-----------------------------
|
||||
|
||||
template<typename DST, typename SRC>
|
||||
static inline DST saturate(SRC x)
|
||||
template<typename DST, typename SRC,
|
||||
typename = cv::util::enable_if_t<!std::is_same<DST, SRC>::value &&
|
||||
std::is_integral<DST>::value &&
|
||||
std::is_integral<SRC>::value> >
|
||||
static CV_ALWAYS_INLINE DST saturate(SRC x)
|
||||
{
|
||||
// only integral types please!
|
||||
GAPI_DbgAssert(std::is_integral<DST>::value &&
|
||||
std::is_integral<SRC>::value);
|
||||
|
||||
if (std::is_same<DST, SRC>::value)
|
||||
return static_cast<DST>(x);
|
||||
|
||||
if (sizeof(DST) > sizeof(SRC))
|
||||
return static_cast<DST>(x);
|
||||
|
||||
|
|
@ -44,38 +40,35 @@ static inline DST saturate(SRC x)
|
|||
std::numeric_limits<DST>::max():
|
||||
static_cast<DST>(x);
|
||||
}
|
||||
template<typename T>
|
||||
static CV_ALWAYS_INLINE T saturate(T x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
template<typename DST, typename SRC, typename R,
|
||||
cv::util::enable_if_t<std::is_floating_point<DST>::value, bool> = true >
|
||||
static CV_ALWAYS_INLINE DST saturate(SRC x, R)
|
||||
{
|
||||
return static_cast<DST>(x);
|
||||
}
|
||||
template<typename DST, typename SRC, typename R,
|
||||
cv::util::enable_if_t<std::is_integral<DST>::value &&
|
||||
std::is_integral<SRC>::value , bool> = true >
|
||||
static CV_ALWAYS_INLINE DST saturate(SRC x, R)
|
||||
{
|
||||
return saturate<DST>(x);
|
||||
}
|
||||
// Note, that OpenCV rounds differently:
|
||||
// - like std::round() for add, subtract
|
||||
// - like std::rint() for multiply, divide
|
||||
template<typename DST, typename SRC, typename R>
|
||||
static inline DST saturate(SRC x, R round)
|
||||
template<typename DST, typename SRC, typename R,
|
||||
cv::util::enable_if_t<std::is_integral<DST>::value &&
|
||||
std::is_floating_point<SRC>::value, bool> = true >
|
||||
static CV_ALWAYS_INLINE DST saturate(SRC x, R round)
|
||||
{
|
||||
if (std::is_floating_point<DST>::value)
|
||||
{
|
||||
return static_cast<DST>(x);
|
||||
}
|
||||
else if (std::is_integral<SRC>::value)
|
||||
{
|
||||
GAPI_DbgAssert(std::is_integral<DST>::value &&
|
||||
std::is_integral<SRC>::value);
|
||||
return saturate<DST>(x);
|
||||
}
|
||||
else
|
||||
{
|
||||
GAPI_DbgAssert(std::is_integral<DST>::value &&
|
||||
std::is_floating_point<SRC>::value);
|
||||
#ifdef _WIN32
|
||||
// Suppress warning about converting x to floating-point
|
||||
// Note that x is already floating-point at this point
|
||||
#pragma warning(disable: 4244)
|
||||
#endif
|
||||
int ix = static_cast<int>(round(x));
|
||||
#ifdef _WIN32
|
||||
#pragma warning(default: 4244)
|
||||
#endif
|
||||
return saturate<DST>(ix);
|
||||
}
|
||||
int ix = static_cast<int>(round(x));
|
||||
return saturate<DST>(ix);
|
||||
}
|
||||
|
||||
// explicit suffix 'd' for double type
|
||||
|
|
|
|||
|
|
@ -15,6 +15,11 @@ namespace cv
|
|||
{
|
||||
namespace gapi
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief This namespace contains G-API own data structures used in
|
||||
* its standalone mode build.
|
||||
*/
|
||||
namespace own
|
||||
{
|
||||
|
||||
|
|
@ -22,7 +27,7 @@ class Point
|
|||
{
|
||||
public:
|
||||
Point() = default;
|
||||
Point(int _x, int _y) : x(_x), y(_y) {};
|
||||
Point(int _x, int _y) : x(_x), y(_y) {}
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
|
@ -32,7 +37,7 @@ class Point2f
|
|||
{
|
||||
public:
|
||||
Point2f() = default;
|
||||
Point2f(float _x, float _y) : x(_x), y(_y) {};
|
||||
Point2f(float _x, float _y) : x(_x), y(_y) {}
|
||||
|
||||
float x = 0.f;
|
||||
float y = 0.f;
|
||||
|
|
@ -42,9 +47,9 @@ class Rect
|
|||
{
|
||||
public:
|
||||
Rect() = default;
|
||||
Rect(int _x, int _y, int _width, int _height) : x(_x), y(_y), width(_width), height(_height) {};
|
||||
Rect(int _x, int _y, int _width, int _height) : x(_x), y(_y), width(_width), height(_height) {}
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
Rect(const cv::Rect& other) : x(other.x), y(other.y), width(other.width), height(other.height) {};
|
||||
Rect(const cv::Rect& other) : x(other.x), y(other.y), width(other.width), height(other.height) {}
|
||||
inline Rect& operator=(const cv::Rect& other)
|
||||
{
|
||||
x = other.x;
|
||||
|
|
@ -99,9 +104,9 @@ class Size
|
|||
{
|
||||
public:
|
||||
Size() = default;
|
||||
Size(int _width, int _height) : width(_width), height(_height) {};
|
||||
Size(int _width, int _height) : width(_width), height(_height) {}
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
Size(const cv::Size& other) : width(other.width), height(other.height) {};
|
||||
Size(const cv::Size& other) : width(other.width), height(other.height) {}
|
||||
inline Size& operator=(const cv::Size& rhs)
|
||||
{
|
||||
width = rhs.width;
|
||||
|
|
@ -138,6 +143,7 @@ inline std::ostream& operator<<(std::ostream& o, const Size& s)
|
|||
return o;
|
||||
}
|
||||
|
||||
struct VoidType {};
|
||||
} // namespace own
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ public:
|
|||
using F = std::function<void(GPlaidMLContext &)>;
|
||||
|
||||
GPlaidMLKernel() = default;
|
||||
explicit GPlaidMLKernel(const F& f) : m_f(f) {};
|
||||
explicit GPlaidMLKernel(const F& f) : m_f(f) {}
|
||||
|
||||
void apply(GPlaidMLContext &ctx) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,6 +15,11 @@ namespace cv
|
|||
{
|
||||
namespace gapi
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief This namespace contains G-API PlaidML backend functions,
|
||||
* structures, and symbols.
|
||||
*/
|
||||
namespace plaidml
|
||||
{
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_PYTHON_API_HPP
|
||||
#define OPENCV_GAPI_PYTHON_API_HPP
|
||||
|
||||
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
|
||||
#include <opencv2/gapi/own/exports.hpp> // GAPI_EXPORTS
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
|
||||
/**
|
||||
* @brief This namespace contains G-API Python backend functions,
|
||||
* structures, and symbols.
|
||||
*
|
||||
* This functionality is required to enable G-API custom operations
|
||||
* and kernels when using G-API from Python, no need to use it in the
|
||||
* C++ form.
|
||||
*/
|
||||
namespace python {
|
||||
|
||||
GAPI_EXPORTS cv::gapi::GBackend backend();
|
||||
|
||||
struct GPythonContext
|
||||
{
|
||||
const cv::GArgs &ins;
|
||||
const cv::GMetaArgs &in_metas;
|
||||
const cv::GTypesInfo &out_info;
|
||||
};
|
||||
|
||||
using Impl = std::function<cv::GRunArgs(const GPythonContext&)>;
|
||||
|
||||
class GAPI_EXPORTS GPythonKernel
|
||||
{
|
||||
public:
|
||||
GPythonKernel() = default;
|
||||
GPythonKernel(Impl run);
|
||||
|
||||
cv::GRunArgs operator()(const GPythonContext& ctx);
|
||||
private:
|
||||
Impl m_run;
|
||||
};
|
||||
|
||||
class GAPI_EXPORTS GPythonFunctor : public cv::gapi::GFunctor
|
||||
{
|
||||
public:
|
||||
using Meta = cv::GKernel::M;
|
||||
|
||||
GPythonFunctor(const char* id, const Meta &meta, const Impl& impl);
|
||||
|
||||
GKernelImpl impl() const override;
|
||||
gapi::GBackend backend() const override;
|
||||
|
||||
private:
|
||||
GKernelImpl impl_;
|
||||
};
|
||||
|
||||
} // namespace python
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_PYTHON_API_HPP
|
||||
|
|
@ -81,9 +81,9 @@ using GMatDesc2 = std::tuple<cv::GMatDesc,cv::GMatDesc>;
|
|||
@param prims vector of drawing primitivies
|
||||
@param args graph compile time parameters
|
||||
*/
|
||||
void GAPI_EXPORTS render(cv::Mat& bgr,
|
||||
const Prims& prims,
|
||||
cv::GCompileArgs&& args = {});
|
||||
void GAPI_EXPORTS_W render(cv::Mat& bgr,
|
||||
const Prims& prims,
|
||||
cv::GCompileArgs&& args = {});
|
||||
|
||||
/** @brief The function renders on two NV12 planes passed drawing primitivies
|
||||
|
||||
|
|
@ -92,11 +92,22 @@ void GAPI_EXPORTS render(cv::Mat& bgr,
|
|||
@param prims vector of drawing primitivies
|
||||
@param args graph compile time parameters
|
||||
*/
|
||||
void GAPI_EXPORTS render(cv::Mat& y_plane,
|
||||
cv::Mat& uv_plane,
|
||||
void GAPI_EXPORTS_W render(cv::Mat& y_plane,
|
||||
cv::Mat& uv_plane,
|
||||
const Prims& prims,
|
||||
cv::GCompileArgs&& args = {});
|
||||
|
||||
/** @brief The function renders on the input media frame passed drawing primitivies
|
||||
|
||||
@param frame input Media Frame : @ref cv::MediaFrame.
|
||||
@param prims vector of drawing primitivies
|
||||
@param args graph compile time parameters
|
||||
*/
|
||||
void GAPI_EXPORTS render(cv::MediaFrame& frame,
|
||||
const Prims& prims,
|
||||
cv::GCompileArgs&& args = {});
|
||||
|
||||
|
||||
G_TYPED_KERNEL_M(GRenderNV12, <GMat2(cv::GMat,cv::GMat,cv::GArray<wip::draw::Prim>)>, "org.opencv.render.nv12")
|
||||
{
|
||||
static GMatDesc2 outMeta(GMatDesc y_plane, GMatDesc uv_plane, GArrayDesc)
|
||||
|
|
@ -113,6 +124,14 @@ G_TYPED_KERNEL(GRenderBGR, <cv::GMat(cv::GMat,cv::GArray<wip::draw::Prim>)>, "or
|
|||
}
|
||||
};
|
||||
|
||||
G_TYPED_KERNEL(GRenderFrame, <cv::GFrame(cv::GFrame, cv::GArray<wip::draw::Prim>)>, "org.opencv.render.frame")
|
||||
{
|
||||
static GFrameDesc outMeta(GFrameDesc desc, GArrayDesc)
|
||||
{
|
||||
return desc;
|
||||
}
|
||||
};
|
||||
|
||||
/** @brief Renders on 3 channels input
|
||||
|
||||
Output image must be 8-bit unsigned planar 3-channel image
|
||||
|
|
@ -120,7 +139,7 @@ Output image must be 8-bit unsigned planar 3-channel image
|
|||
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3
|
||||
@param prims draw primitives
|
||||
*/
|
||||
GAPI_EXPORTS GMat render3ch(const GMat& src, const GArray<Prim>& prims);
|
||||
GAPI_EXPORTS_W GMat render3ch(const GMat& src, const GArray<Prim>& prims);
|
||||
|
||||
/** @brief Renders on two planes
|
||||
|
||||
|
|
@ -131,19 +150,34 @@ uv image must be 8-bit unsigned planar 2-channel image @ref CV_8UC2
|
|||
@param uv input image: 8-bit unsigned 2-channel image @ref CV_8UC2
|
||||
@param prims draw primitives
|
||||
*/
|
||||
GAPI_EXPORTS GMat2 renderNV12(const GMat& y,
|
||||
const GMat& uv,
|
||||
const GArray<Prim>& prims);
|
||||
GAPI_EXPORTS_W GMat2 renderNV12(const GMat& y,
|
||||
const GMat& uv,
|
||||
const GArray<Prim>& prims);
|
||||
|
||||
/** @brief Renders Media Frame
|
||||
|
||||
Output media frame frame cv::MediaFrame
|
||||
|
||||
@param m_frame input image: cv::MediaFrame @ref cv::MediaFrame
|
||||
@param prims draw primitives
|
||||
*/
|
||||
GAPI_EXPORTS GFrame renderFrame(const GFrame& m_frame,
|
||||
const GArray<Prim>& prims);
|
||||
|
||||
//! @} gapi_draw_api
|
||||
|
||||
} // namespace draw
|
||||
} // namespace wip
|
||||
|
||||
/**
|
||||
* @brief This namespace contains G-API CPU rendering backend functions,
|
||||
* structures, and symbols. See @ref gapi_draw for details.
|
||||
*/
|
||||
namespace render
|
||||
{
|
||||
namespace ocv
|
||||
{
|
||||
GAPI_EXPORTS cv::gapi::GKernelPackage kernels();
|
||||
GAPI_EXPORTS_W cv::gapi::GKernelPackage kernels();
|
||||
|
||||
} // namespace ocv
|
||||
} // namespace render
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ struct freetype_font
|
|||
*
|
||||
* Parameters match cv::putText().
|
||||
*/
|
||||
struct Text
|
||||
struct GAPI_EXPORTS_W_SIMPLE Text
|
||||
{
|
||||
/**
|
||||
* @brief Text constructor
|
||||
|
|
@ -55,6 +55,7 @@ struct Text
|
|||
* @param lt_ The line type. See #LineTypes
|
||||
* @param bottom_left_origin_ When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner
|
||||
*/
|
||||
GAPI_WRAP
|
||||
Text(const std::string& text_,
|
||||
const cv::Point& org_,
|
||||
int ff_,
|
||||
|
|
@ -68,17 +69,18 @@ struct Text
|
|||
{
|
||||
}
|
||||
|
||||
GAPI_WRAP
|
||||
Text() = default;
|
||||
|
||||
/*@{*/
|
||||
std::string text; //!< The text string to be drawn
|
||||
cv::Point org; //!< The bottom-left corner of the text string in the image
|
||||
int ff; //!< The font type, see #HersheyFonts
|
||||
double fs; //!< The font scale factor that is multiplied by the font-specific base size
|
||||
cv::Scalar color; //!< The text color
|
||||
int thick; //!< The thickness of the lines used to draw a text
|
||||
int lt; //!< The line type. See #LineTypes
|
||||
bool bottom_left_origin; //!< When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner
|
||||
GAPI_PROP_RW std::string text; //!< The text string to be drawn
|
||||
GAPI_PROP_RW cv::Point org; //!< The bottom-left corner of the text string in the image
|
||||
GAPI_PROP_RW int ff; //!< The font type, see #HersheyFonts
|
||||
GAPI_PROP_RW double fs; //!< The font scale factor that is multiplied by the font-specific base size
|
||||
GAPI_PROP_RW cv::Scalar color; //!< The text color
|
||||
GAPI_PROP_RW int thick; //!< The thickness of the lines used to draw a text
|
||||
GAPI_PROP_RW int lt; //!< The line type. See #LineTypes
|
||||
GAPI_PROP_RW bool bottom_left_origin; //!< When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner
|
||||
/*@{*/
|
||||
};
|
||||
|
||||
|
|
@ -122,7 +124,7 @@ struct FText
|
|||
*
|
||||
* Parameters match cv::rectangle().
|
||||
*/
|
||||
struct Rect
|
||||
struct GAPI_EXPORTS_W_SIMPLE Rect
|
||||
{
|
||||
/**
|
||||
* @brief Rect constructor
|
||||
|
|
@ -142,14 +144,15 @@ struct Rect
|
|||
{
|
||||
}
|
||||
|
||||
GAPI_WRAP
|
||||
Rect() = default;
|
||||
|
||||
/*@{*/
|
||||
cv::Rect rect; //!< Coordinates of the rectangle
|
||||
cv::Scalar color; //!< The rectangle color or brightness (grayscale image)
|
||||
int thick; //!< The thickness of lines that make up the rectangle. Negative values, like #FILLED, mean that the function has to draw a filled rectangle
|
||||
int lt; //!< The type of the line. See #LineTypes
|
||||
int shift; //!< The number of fractional bits in the point coordinates
|
||||
GAPI_PROP_RW cv::Rect rect; //!< Coordinates of the rectangle
|
||||
GAPI_PROP_RW cv::Scalar color; //!< The rectangle color or brightness (grayscale image)
|
||||
GAPI_PROP_RW int thick; //!< The thickness of lines that make up the rectangle. Negative values, like #FILLED, mean that the function has to draw a filled rectangle
|
||||
GAPI_PROP_RW int lt; //!< The type of the line. See #LineTypes
|
||||
GAPI_PROP_RW int shift; //!< The number of fractional bits in the point coordinates
|
||||
/*@{*/
|
||||
};
|
||||
|
||||
|
|
@ -158,7 +161,7 @@ struct Rect
|
|||
*
|
||||
* Parameters match cv::circle().
|
||||
*/
|
||||
struct Circle
|
||||
struct GAPI_EXPORTS_W_SIMPLE Circle
|
||||
{
|
||||
/**
|
||||
* @brief Circle constructor
|
||||
|
|
@ -170,6 +173,7 @@ struct Circle
|
|||
* @param lt_ The Type of the circle boundary. See #LineTypes
|
||||
* @param shift_ The Number of fractional bits in the coordinates of the center and in the radius value
|
||||
*/
|
||||
GAPI_WRAP
|
||||
Circle(const cv::Point& center_,
|
||||
int radius_,
|
||||
const cv::Scalar& color_,
|
||||
|
|
@ -180,15 +184,16 @@ struct Circle
|
|||
{
|
||||
}
|
||||
|
||||
GAPI_WRAP
|
||||
Circle() = default;
|
||||
|
||||
/*@{*/
|
||||
cv::Point center; //!< The center of the circle
|
||||
int radius; //!< The radius of the circle
|
||||
cv::Scalar color; //!< The color of the circle
|
||||
int thick; //!< The thickness of the circle outline, if positive. Negative values, like #FILLED, mean that a filled circle is to be drawn
|
||||
int lt; //!< The Type of the circle boundary. See #LineTypes
|
||||
int shift; //!< The Number of fractional bits in the coordinates of the center and in the radius value
|
||||
GAPI_PROP_RW cv::Point center; //!< The center of the circle
|
||||
GAPI_PROP_RW int radius; //!< The radius of the circle
|
||||
GAPI_PROP_RW cv::Scalar color; //!< The color of the circle
|
||||
GAPI_PROP_RW int thick; //!< The thickness of the circle outline, if positive. Negative values, like #FILLED, mean that a filled circle is to be drawn
|
||||
GAPI_PROP_RW int lt; //!< The Type of the circle boundary. See #LineTypes
|
||||
GAPI_PROP_RW int shift; //!< The Number of fractional bits in the coordinates of the center and in the radius value
|
||||
/*@{*/
|
||||
};
|
||||
|
||||
|
|
@ -197,7 +202,7 @@ struct Circle
|
|||
*
|
||||
* Parameters match cv::line().
|
||||
*/
|
||||
struct Line
|
||||
struct GAPI_EXPORTS_W_SIMPLE Line
|
||||
{
|
||||
/**
|
||||
* @brief Line constructor
|
||||
|
|
@ -209,6 +214,7 @@ struct Line
|
|||
* @param lt_ The Type of the line. See #LineTypes
|
||||
* @param shift_ The number of fractional bits in the point coordinates
|
||||
*/
|
||||
GAPI_WRAP
|
||||
Line(const cv::Point& pt1_,
|
||||
const cv::Point& pt2_,
|
||||
const cv::Scalar& color_,
|
||||
|
|
@ -219,15 +225,16 @@ struct Line
|
|||
{
|
||||
}
|
||||
|
||||
GAPI_WRAP
|
||||
Line() = default;
|
||||
|
||||
/*@{*/
|
||||
cv::Point pt1; //!< The first point of the line segment
|
||||
cv::Point pt2; //!< The second point of the line segment
|
||||
cv::Scalar color; //!< The line color
|
||||
int thick; //!< The thickness of line
|
||||
int lt; //!< The Type of the line. See #LineTypes
|
||||
int shift; //!< The number of fractional bits in the point coordinates
|
||||
GAPI_PROP_RW cv::Point pt1; //!< The first point of the line segment
|
||||
GAPI_PROP_RW cv::Point pt2; //!< The second point of the line segment
|
||||
GAPI_PROP_RW cv::Scalar color; //!< The line color
|
||||
GAPI_PROP_RW int thick; //!< The thickness of line
|
||||
GAPI_PROP_RW int lt; //!< The Type of the line. See #LineTypes
|
||||
GAPI_PROP_RW int shift; //!< The number of fractional bits in the point coordinates
|
||||
/*@{*/
|
||||
};
|
||||
|
||||
|
|
@ -236,7 +243,7 @@ struct Line
|
|||
*
|
||||
* Mosaicing is a very basic method to obfuscate regions in the image.
|
||||
*/
|
||||
struct Mosaic
|
||||
struct GAPI_EXPORTS_W_SIMPLE Mosaic
|
||||
{
|
||||
/**
|
||||
* @brief Mosaic constructor
|
||||
|
|
@ -252,12 +259,13 @@ struct Mosaic
|
|||
{
|
||||
}
|
||||
|
||||
GAPI_WRAP
|
||||
Mosaic() : cellSz(0), decim(0) {}
|
||||
|
||||
/*@{*/
|
||||
cv::Rect mos; //!< Coordinates of the mosaic
|
||||
int cellSz; //!< Cell size (same for X, Y)
|
||||
int decim; //!< Decimation (0 stands for no decimation)
|
||||
GAPI_PROP_RW cv::Rect mos; //!< Coordinates of the mosaic
|
||||
GAPI_PROP_RW int cellSz; //!< Cell size (same for X, Y)
|
||||
GAPI_PROP_RW int decim; //!< Decimation (0 stands for no decimation)
|
||||
/*@{*/
|
||||
};
|
||||
|
||||
|
|
@ -266,7 +274,7 @@ struct Mosaic
|
|||
*
|
||||
* Image is blended on a frame using the specified mask.
|
||||
*/
|
||||
struct Image
|
||||
struct GAPI_EXPORTS_W_SIMPLE Image
|
||||
{
|
||||
/**
|
||||
* @brief Mosaic constructor
|
||||
|
|
@ -275,6 +283,7 @@ struct Image
|
|||
* @param img_ Image to draw
|
||||
* @param alpha_ Alpha channel for image to draw (same size and number of channels)
|
||||
*/
|
||||
GAPI_WRAP
|
||||
Image(const cv::Point& org_,
|
||||
const cv::Mat& img_,
|
||||
const cv::Mat& alpha_) :
|
||||
|
|
@ -282,19 +291,20 @@ struct Image
|
|||
{
|
||||
}
|
||||
|
||||
GAPI_WRAP
|
||||
Image() = default;
|
||||
|
||||
/*@{*/
|
||||
cv::Point org; //!< The bottom-left corner of the image
|
||||
cv::Mat img; //!< Image to draw
|
||||
cv::Mat alpha; //!< Alpha channel for image to draw (same size and number of channels)
|
||||
GAPI_PROP_RW cv::Point org; //!< The bottom-left corner of the image
|
||||
GAPI_PROP_RW cv::Mat img; //!< Image to draw
|
||||
GAPI_PROP_RW cv::Mat alpha; //!< Alpha channel for image to draw (same size and number of channels)
|
||||
/*@{*/
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This structure represents a polygon to draw.
|
||||
*/
|
||||
struct Poly
|
||||
struct GAPI_EXPORTS_W_SIMPLE Poly
|
||||
{
|
||||
/**
|
||||
* @brief Mosaic constructor
|
||||
|
|
@ -305,6 +315,7 @@ struct Poly
|
|||
* @param lt_ The Type of the line. See #LineTypes
|
||||
* @param shift_ The number of fractional bits in the point coordinate
|
||||
*/
|
||||
GAPI_WRAP
|
||||
Poly(const std::vector<cv::Point>& points_,
|
||||
const cv::Scalar& color_,
|
||||
int thick_ = 1,
|
||||
|
|
@ -314,14 +325,15 @@ struct Poly
|
|||
{
|
||||
}
|
||||
|
||||
GAPI_WRAP
|
||||
Poly() = default;
|
||||
|
||||
/*@{*/
|
||||
std::vector<cv::Point> points; //!< Points to connect
|
||||
cv::Scalar color; //!< The line color
|
||||
int thick; //!< The thickness of line
|
||||
int lt; //!< The Type of the line. See #LineTypes
|
||||
int shift; //!< The number of fractional bits in the point coordinate
|
||||
GAPI_PROP_RW std::vector<cv::Point> points; //!< Points to connect
|
||||
GAPI_PROP_RW cv::Scalar color; //!< The line color
|
||||
GAPI_PROP_RW int thick; //!< The thickness of line
|
||||
GAPI_PROP_RW int lt; //!< The Type of the line. See #LineTypes
|
||||
GAPI_PROP_RW int shift; //!< The number of fractional bits in the point coordinate
|
||||
/*@{*/
|
||||
};
|
||||
|
||||
|
|
@ -336,7 +348,7 @@ using Prim = util::variant
|
|||
, Poly
|
||||
>;
|
||||
|
||||
using Prims = std::vector<Prim>;
|
||||
using Prims = std::vector<Prim>;
|
||||
//! @} gapi_draw_prims
|
||||
|
||||
} // namespace draw
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@
|
|||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace s11n {
|
||||
struct IOStream;
|
||||
struct IIStream;
|
||||
struct IOStream;
|
||||
struct IIStream;
|
||||
} // namespace s11n
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
|
@ -25,11 +25,11 @@ namespace cv {
|
|||
// "Remote Mat", a general class which provides an abstraction layer over the data
|
||||
// storage and placement (host, remote device etc) and allows to access this data.
|
||||
//
|
||||
// The device specific implementation is hidden in the RMat::Adapter class
|
||||
// The device specific implementation is hidden in the RMat::IAdapter class
|
||||
//
|
||||
// The basic flow is the following:
|
||||
// * Backend which is aware of the remote device:
|
||||
// - Implements own AdapterT class which is derived from RMat::Adapter
|
||||
// - Implements own AdapterT class which is derived from RMat::IAdapter
|
||||
// - Wraps device memory into RMat via make_rmat utility function:
|
||||
// cv::RMat rmat = cv::make_rmat<AdapterT>(args);
|
||||
//
|
||||
|
|
@ -42,6 +42,9 @@ namespace cv {
|
|||
// performCalculations(in_view, out_view);
|
||||
// // data from out_view is transferred to the device when out_view is destroyed
|
||||
// }
|
||||
/** \addtogroup gapi_data_structures
|
||||
* @{
|
||||
*/
|
||||
class GAPI_EXPORTS RMat
|
||||
{
|
||||
public:
|
||||
|
|
@ -98,23 +101,27 @@ public:
|
|||
};
|
||||
|
||||
enum class Access { R, W };
|
||||
class Adapter
|
||||
class IAdapter
|
||||
// Adapter class is going to be deleted and renamed as IAdapter
|
||||
{
|
||||
public:
|
||||
virtual ~Adapter() = default;
|
||||
virtual ~IAdapter() = default;
|
||||
virtual GMatDesc desc() const = 0;
|
||||
// Implementation is responsible for setting the appropriate callback to
|
||||
// the view when accessed for writing, to ensure that the data from the view
|
||||
// is transferred to the device when the view is destroyed
|
||||
virtual View access(Access) = 0;
|
||||
virtual void serialize(cv::gapi::s11n::IOStream&) {
|
||||
GAPI_Assert(false && "Generic serialize method should never be called for RMat adapter");
|
||||
GAPI_Assert(false && "Generic serialize method of RMat::IAdapter does nothing by default. "
|
||||
"Please, implement it in derived class to properly serialize the object.");
|
||||
}
|
||||
virtual void deserialize(cv::gapi::s11n::IIStream&) {
|
||||
GAPI_Assert(false && "Generic deserialize method should never be called for RMat adapter");
|
||||
GAPI_Assert(false && "Generic deserialize method of RMat::IAdapter does nothing by default. "
|
||||
"Please, implement it in derived class to properly deserialize the object.");
|
||||
}
|
||||
};
|
||||
using AdapterP = std::shared_ptr<Adapter>;
|
||||
using Adapter = IAdapter; // Keep backward compatibility
|
||||
using AdapterP = std::shared_ptr<IAdapter>;
|
||||
|
||||
RMat() = default;
|
||||
RMat(AdapterP&& a) : m_adapter(std::move(a)) {}
|
||||
|
|
@ -131,7 +138,7 @@ public:
|
|||
// return nullptr if underlying type is different
|
||||
template<typename T> T* get() const
|
||||
{
|
||||
static_assert(std::is_base_of<Adapter, T>::value, "T is not derived from Adapter!");
|
||||
static_assert(std::is_base_of<IAdapter, T>::value, "T is not derived from IAdapter!");
|
||||
GAPI_Assert(m_adapter != nullptr);
|
||||
return dynamic_cast<T*>(m_adapter.get());
|
||||
}
|
||||
|
|
@ -146,6 +153,7 @@ private:
|
|||
|
||||
template<typename T, typename... Ts>
|
||||
RMat make_rmat(Ts&&... args) { return { std::make_shared<T>(std::forward<Ts>(args)...) }; }
|
||||
/** @} */
|
||||
|
||||
} //namespace cv
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
// Copyright (C) 2020-2021 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_S11N_HPP
|
||||
#define OPENCV_GAPI_S11N_HPP
|
||||
|
|
@ -13,61 +13,145 @@
|
|||
#include <opencv2/gapi/s11n/base.hpp>
|
||||
#include <opencv2/gapi/gcomputation.hpp>
|
||||
#include <opencv2/gapi/rmat.hpp>
|
||||
#include <opencv2/gapi/media.hpp>
|
||||
#include <opencv2/gapi/util/util.hpp>
|
||||
|
||||
// FIXME: caused by deserialize_runarg
|
||||
#if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
|
||||
#pragma warning(disable: 4702)
|
||||
#endif
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
|
||||
/**
|
||||
* \addtogroup gapi_serialization
|
||||
* @{
|
||||
*/
|
||||
|
||||
namespace detail {
|
||||
GAPI_EXPORTS cv::GComputation getGraph(const std::vector<char> &p);
|
||||
GAPI_EXPORTS cv::GComputation getGraph(const std::vector<char> &bytes);
|
||||
|
||||
GAPI_EXPORTS cv::GMetaArgs getMetaArgs(const std::vector<char> &p);
|
||||
GAPI_EXPORTS cv::GMetaArgs getMetaArgs(const std::vector<char> &bytes);
|
||||
|
||||
GAPI_EXPORTS cv::GRunArgs getRunArgs(const std::vector<char> &p);
|
||||
GAPI_EXPORTS cv::GRunArgs getRunArgs(const std::vector<char> &bytes);
|
||||
|
||||
GAPI_EXPORTS std::vector<std::string> getVectorOfStrings(const std::vector<char> &bytes);
|
||||
|
||||
template<typename... Types>
|
||||
cv::GCompileArgs getCompileArgs(const std::vector<char> &p);
|
||||
cv::GCompileArgs getCompileArgs(const std::vector<char> &bytes);
|
||||
|
||||
template<typename RMatAdapterType>
|
||||
cv::GRunArgs getRunArgsWithRMats(const std::vector<char> &p);
|
||||
template<typename... AdapterType>
|
||||
cv::GRunArgs getRunArgsWithAdapters(const std::vector<char> &bytes);
|
||||
} // namespace detail
|
||||
|
||||
/** @brief Serialize a graph represented by GComputation into an array of bytes.
|
||||
*
|
||||
* Check different overloads for more examples.
|
||||
* @param c GComputation to serialize.
|
||||
* @return serialized vector of bytes.
|
||||
*/
|
||||
GAPI_EXPORTS std::vector<char> serialize(const cv::GComputation &c);
|
||||
//namespace{
|
||||
|
||||
/** @overload
|
||||
* @param ca GCompileArgs to serialize.
|
||||
*/
|
||||
GAPI_EXPORTS std::vector<char> serialize(const cv::GCompileArgs& ca);
|
||||
|
||||
/** @overload
|
||||
* @param ma GMetaArgs to serialize.
|
||||
*/
|
||||
GAPI_EXPORTS std::vector<char> serialize(const cv::GMetaArgs& ma);
|
||||
|
||||
/** @overload
|
||||
* @param ra GRunArgs to serialize.
|
||||
*/
|
||||
GAPI_EXPORTS std::vector<char> serialize(const cv::GRunArgs& ra);
|
||||
|
||||
/** @overload
|
||||
* @param vs std::vector<std::string> to serialize.
|
||||
*/
|
||||
GAPI_EXPORTS std::vector<char> serialize(const std::vector<std::string>& vs);
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
template<typename T> static inline
|
||||
T deserialize(const std::vector<char> &p);
|
||||
|
||||
//} //ananymous namespace
|
||||
|
||||
GAPI_EXPORTS std::vector<char> serialize(const cv::GCompileArgs&);
|
||||
GAPI_EXPORTS std::vector<char> serialize(const cv::GMetaArgs&);
|
||||
GAPI_EXPORTS std::vector<char> serialize(const cv::GRunArgs&);
|
||||
T deserialize(const std::vector<char> &bytes);
|
||||
|
||||
/** @brief Deserialize GComputation from a byte array.
|
||||
*
|
||||
* Check different overloads for more examples.
|
||||
* @param bytes serialized vector of bytes.
|
||||
* @return deserialized GComputation object.
|
||||
*/
|
||||
template<> inline
|
||||
cv::GComputation deserialize(const std::vector<char> &p) {
|
||||
return detail::getGraph(p);
|
||||
cv::GComputation deserialize(const std::vector<char> &bytes) {
|
||||
return detail::getGraph(bytes);
|
||||
}
|
||||
|
||||
/** @brief Deserialize GMetaArgs from a byte array.
|
||||
*
|
||||
* Check different overloads for more examples.
|
||||
* @param bytes serialized vector of bytes.
|
||||
* @return deserialized GMetaArgs object.
|
||||
*/
|
||||
template<> inline
|
||||
cv::GMetaArgs deserialize(const std::vector<char> &p) {
|
||||
return detail::getMetaArgs(p);
|
||||
cv::GMetaArgs deserialize(const std::vector<char> &bytes) {
|
||||
return detail::getMetaArgs(bytes);
|
||||
}
|
||||
|
||||
/** @brief Deserialize GRunArgs from a byte array.
|
||||
*
|
||||
* Check different overloads for more examples.
|
||||
* @param bytes serialized vector of bytes.
|
||||
* @return deserialized GRunArgs object.
|
||||
*/
|
||||
template<> inline
|
||||
cv::GRunArgs deserialize(const std::vector<char> &p) {
|
||||
return detail::getRunArgs(p);
|
||||
cv::GRunArgs deserialize(const std::vector<char> &bytes) {
|
||||
return detail::getRunArgs(bytes);
|
||||
}
|
||||
|
||||
/** @brief Deserialize std::vector<std::string> from a byte array.
|
||||
*
|
||||
* Check different overloads for more examples.
|
||||
* @param bytes serialized vector of bytes.
|
||||
* @return deserialized std::vector<std::string> object.
|
||||
*/
|
||||
template<> inline
|
||||
std::vector<std::string> deserialize(const std::vector<char> &bytes) {
|
||||
return detail::getVectorOfStrings(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deserialize GCompileArgs which types were specified in the template from a byte array.
|
||||
*
|
||||
* @note cv::gapi::s11n::detail::S11N template specialization must be provided to make a custom type
|
||||
* in GCompileArgs deserializable.
|
||||
*
|
||||
* @param bytes vector of bytes to deserialize GCompileArgs object from.
|
||||
* @return GCompileArgs object.
|
||||
* @see GCompileArgs cv::gapi::s11n::detail::S11N
|
||||
*/
|
||||
template<typename T, typename... Types> inline
|
||||
typename std::enable_if<std::is_same<T, GCompileArgs>::value, GCompileArgs>::
|
||||
type deserialize(const std::vector<char> &p) {
|
||||
return detail::getCompileArgs<Types...>(p);
|
||||
type deserialize(const std::vector<char> &bytes) {
|
||||
return detail::getCompileArgs<Types...>(bytes);
|
||||
}
|
||||
|
||||
template<typename T, typename RMatAdapterType> inline
|
||||
/**
|
||||
* @brief Deserialize GRunArgs including RMat and MediaFrame objects if any from a byte array.
|
||||
*
|
||||
* Adapter types are specified in the template.
|
||||
* @note To be used properly specified adapter types must overload their deserialize() method.
|
||||
* @param bytes vector of bytes to deserialize GRunArgs object from.
|
||||
* @return GRunArgs including RMat and MediaFrame objects if any.
|
||||
* @see RMat MediaFrame
|
||||
*/
|
||||
template<typename T, typename AtLeastOneAdapterT, typename... AdapterTypes> inline
|
||||
typename std::enable_if<std::is_same<T, GRunArgs>::value, GRunArgs>::
|
||||
type deserialize(const std::vector<char> &p) {
|
||||
return detail::getRunArgsWithRMats<RMatAdapterType>(p);
|
||||
type deserialize(const std::vector<char> &bytes) {
|
||||
return detail::getRunArgsWithAdapters<AtLeastOneAdapterT, AdapterTypes...>(bytes);
|
||||
}
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
|
@ -75,6 +159,17 @@ type deserialize(const std::vector<char> &p) {
|
|||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace s11n {
|
||||
|
||||
/** @brief This structure is an interface for serialization routines.
|
||||
*
|
||||
* It's main purpose is to provide multiple overloads for operator<<()
|
||||
* with basic C++ in addition to OpenCV/G-API types.
|
||||
*
|
||||
* This sctructure can be inherited and further extended with additional types.
|
||||
*
|
||||
* For example, it is utilized in cv::gapi::s11n::detail::S11N as input parameter
|
||||
* in serialize() method.
|
||||
*/
|
||||
struct GAPI_EXPORTS IOStream {
|
||||
virtual ~IOStream() = default;
|
||||
// Define the native support for basic C++ types at the API level:
|
||||
|
|
@ -91,6 +186,16 @@ struct GAPI_EXPORTS IOStream {
|
|||
virtual IOStream& operator<< (const std::string&) = 0;
|
||||
};
|
||||
|
||||
/** @brief This structure is an interface for deserialization routines.
|
||||
*
|
||||
* It's main purpose is to provide multiple overloads for operator>>()
|
||||
* with basic C++ in addition to OpenCV/G-API types.
|
||||
*
|
||||
* This structure can be inherited and further extended with additional types.
|
||||
*
|
||||
* For example, it is utilized in cv::gapi::s11n::detail::S11N as input parameter
|
||||
* in deserialize() method.
|
||||
*/
|
||||
struct GAPI_EXPORTS IIStream {
|
||||
virtual ~IIStream() = default;
|
||||
virtual IIStream& operator>> (bool &) = 0;
|
||||
|
|
@ -108,7 +213,7 @@ struct GAPI_EXPORTS IIStream {
|
|||
};
|
||||
|
||||
namespace detail {
|
||||
GAPI_EXPORTS std::unique_ptr<IIStream> getInStream(const std::vector<char> &p);
|
||||
GAPI_EXPORTS std::unique_ptr<IIStream> getInStream(const std::vector<char> &bytes);
|
||||
} // namespace detail
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -138,24 +243,26 @@ GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::Mat &m);
|
|||
|
||||
// FIXME: for GRunArgs serailization
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::UMat &);
|
||||
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::UMat &);
|
||||
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::UMat & um);
|
||||
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::UMat & um);
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
|
||||
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::RMat &r);
|
||||
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::RMat &r);
|
||||
|
||||
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::gapi::wip::IStreamSource::Ptr &);
|
||||
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::gapi::wip::IStreamSource::Ptr &);
|
||||
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::gapi::wip::IStreamSource::Ptr &issptr);
|
||||
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::gapi::wip::IStreamSource::Ptr &issptr);
|
||||
|
||||
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::detail::VectorRef &);
|
||||
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::detail::VectorRef &);
|
||||
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::detail::VectorRef &vr);
|
||||
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::detail::VectorRef &vr);
|
||||
|
||||
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::detail::OpaqueRef &);
|
||||
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::detail::OpaqueRef &);
|
||||
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::detail::OpaqueRef &opr);
|
||||
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::detail::OpaqueRef &opr);
|
||||
|
||||
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::MediaFrame &);
|
||||
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::MediaFrame &);
|
||||
/// @private -- Exclude this function from OpenCV documentation
|
||||
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::MediaFrame &mf);
|
||||
/// @private -- Exclude this function from OpenCV documentation
|
||||
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::MediaFrame &mf);
|
||||
|
||||
// Generic STL types ////////////////////////////////////////////////////////////////
|
||||
template<typename K, typename V>
|
||||
|
|
@ -178,6 +285,7 @@ IIStream& operator>> (IIStream& is, std::map<K, V> &m) {
|
|||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
template<typename K, typename V>
|
||||
IOStream& operator<< (IOStream& os, const std::unordered_map<K, V> &m) {
|
||||
const uint32_t sz = static_cast<uint32_t>(m.size());
|
||||
|
|
@ -198,6 +306,7 @@ IIStream& operator>> (IIStream& is, std::unordered_map<K, V> &m) {
|
|||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
IOStream& operator<< (IOStream& os, const std::vector<T> &ts) {
|
||||
const uint32_t sz = static_cast<uint32_t>(ts.size());
|
||||
|
|
@ -225,16 +334,19 @@ template<typename V>
|
|||
IOStream& put_v(IOStream&, const V&, std::size_t) {
|
||||
GAPI_Assert(false && "variant>>: requested index is invalid");
|
||||
};
|
||||
|
||||
template<typename V, typename X, typename... Xs>
|
||||
IOStream& put_v(IOStream& os, const V& v, std::size_t x) {
|
||||
return (x == 0u)
|
||||
? os << cv::util::get<X>(v)
|
||||
: put_v<V, Xs...>(os, v, x-1);
|
||||
}
|
||||
|
||||
template<typename V>
|
||||
IIStream& get_v(IIStream&, V&, std::size_t, std::size_t) {
|
||||
GAPI_Assert(false && "variant<<: requested index is invalid");
|
||||
}
|
||||
|
||||
template<typename V, typename X, typename... Xs>
|
||||
IIStream& get_v(IIStream& is, V& v, std::size_t i, std::size_t gi) {
|
||||
if (i == gi) {
|
||||
|
|
@ -246,11 +358,13 @@ IIStream& get_v(IIStream& is, V& v, std::size_t i, std::size_t gi) {
|
|||
}
|
||||
} // namespace detail
|
||||
|
||||
//! @overload
|
||||
template<typename... Ts>
|
||||
IOStream& operator<< (IOStream& os, const cv::util::variant<Ts...> &v) {
|
||||
os << static_cast<uint32_t>(v.index());
|
||||
return detail::put_v<cv::util::variant<Ts...>, Ts...>(os, v, v.index());
|
||||
}
|
||||
//! @overload
|
||||
template<typename... Ts>
|
||||
IIStream& operator>> (IIStream& is, cv::util::variant<Ts...> &v) {
|
||||
int idx = -1;
|
||||
|
|
@ -260,6 +374,7 @@ IIStream& operator>> (IIStream& is, cv::util::variant<Ts...> &v) {
|
|||
}
|
||||
|
||||
// FIXME: consider a better solution
|
||||
/// @private -- Exclude this function from OpenCV documentation
|
||||
template<typename... Ts>
|
||||
void getRunArgByIdx (IIStream& is, cv::util::variant<Ts...> &v, uint32_t idx) {
|
||||
is = detail::get_v<cv::util::variant<Ts...>, Ts...>(is, v, 0u, idx);
|
||||
|
|
@ -290,16 +405,39 @@ static cv::util::optional<GCompileArg> exec(const std::string& tag, cv::gapi::s1
|
|||
}
|
||||
};
|
||||
|
||||
template<typename T> struct deserialize_runarg;
|
||||
template<typename ...T>
|
||||
struct deserialize_arg_with_adapter;
|
||||
|
||||
template<typename RMatAdapterType>
|
||||
template<typename RA, typename TA>
|
||||
struct deserialize_arg_with_adapter<RA, TA> {
|
||||
static GRunArg exec(cv::gapi::s11n::IIStream& is) {
|
||||
std::unique_ptr<TA> ptr(new TA);
|
||||
ptr->deserialize(is);
|
||||
return GRunArg { RA(std::move(ptr)) };
|
||||
}
|
||||
};
|
||||
|
||||
template<typename RA>
|
||||
struct deserialize_arg_with_adapter<RA, void> {
|
||||
static GRunArg exec(cv::gapi::s11n::IIStream&) {
|
||||
GAPI_Assert(false && "No suitable adapter class found during RMat/MediaFrame deserialization. "
|
||||
"Please, make sure you've passed them in cv::gapi::deserialize() template");
|
||||
return GRunArg{};
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Types>
|
||||
struct deserialize_runarg {
|
||||
static GRunArg exec(cv::gapi::s11n::IIStream& is, uint32_t idx) {
|
||||
if (idx == GRunArg::index_of<RMat>()) {
|
||||
auto ptr = std::make_shared<RMatAdapterType>();
|
||||
ptr->deserialize(is);
|
||||
return GRunArg { RMat(std::move(ptr)) };
|
||||
} else { // non-RMat arg - use default deserialization
|
||||
// Type or void (if not found)
|
||||
using TA = typename cv::util::find_adapter_impl<RMat::IAdapter, Types...>::type;
|
||||
return deserialize_arg_with_adapter<RMat, TA>::exec(is);
|
||||
} else if (idx == GRunArg::index_of<MediaFrame>()) {
|
||||
// Type or void (if not found)
|
||||
using TA = typename cv::util::find_adapter_impl<MediaFrame::IAdapter, Types...>::type;
|
||||
return deserialize_arg_with_adapter<MediaFrame, TA>::exec(is);
|
||||
} else { // not an adapter holding type runarg - use default deserialization
|
||||
GRunArg arg;
|
||||
getRunArgByIdx(is, arg, idx);
|
||||
return arg;
|
||||
|
|
@ -342,9 +480,9 @@ cv::GCompileArgs getCompileArgs(const std::vector<char> &sArgs) {
|
|||
return args;
|
||||
}
|
||||
|
||||
template<typename RMatAdapterType>
|
||||
cv::GRunArgs getRunArgsWithRMats(const std::vector<char> &p) {
|
||||
std::unique_ptr<cv::gapi::s11n::IIStream> pIs = cv::gapi::s11n::detail::getInStream(p);
|
||||
template<typename... AdapterTypes>
|
||||
cv::GRunArgs getRunArgsWithAdapters(const std::vector<char> &bytes) {
|
||||
std::unique_ptr<cv::gapi::s11n::IIStream> pIs = cv::gapi::s11n::detail::getInStream(bytes);
|
||||
cv::gapi::s11n::IIStream& is = *pIs;
|
||||
cv::GRunArgs args;
|
||||
|
||||
|
|
@ -353,12 +491,14 @@ cv::GRunArgs getRunArgsWithRMats(const std::vector<char> &p) {
|
|||
for (uint32_t i = 0; i < sz; ++i) {
|
||||
uint32_t idx = 0;
|
||||
is >> idx;
|
||||
args.push_back(cv::gapi::detail::deserialize_runarg<RMatAdapterType>::exec(is, idx));
|
||||
args.push_back(cv::gapi::detail::deserialize_runarg<AdapterTypes...>::exec(is, idx));
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
} // namespace detail
|
||||
/** @} */
|
||||
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
// Copyright (C) 2020-2021 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_S11N_BASE_HPP
|
||||
#define OPENCV_GAPI_S11N_BASE_HPP
|
||||
|
|
@ -12,31 +12,65 @@
|
|||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
|
||||
/**
|
||||
* @brief This namespace contains G-API serialization and
|
||||
* deserialization functions and data structures.
|
||||
*/
|
||||
namespace s11n {
|
||||
struct IOStream;
|
||||
struct IIStream;
|
||||
|
||||
namespace detail {
|
||||
|
||||
//! @addtogroup gapi_serialization
|
||||
//! @{
|
||||
|
||||
struct NotImplemented {
|
||||
};
|
||||
|
||||
// The default S11N for custom types is NotImplemented
|
||||
// Don't! sublass from NotImplemented if you actually implement S11N.
|
||||
/** @brief This structure allows to implement serialization routines for custom types.
|
||||
*
|
||||
* The default S11N for custom types is not implemented.
|
||||
*
|
||||
* @note When providing an overloaded implementation for S11N with your type
|
||||
* don't inherit it from NotImplemented structure.
|
||||
*
|
||||
* @note There are lots of overloaded >> and << operators for basic and OpenCV/G-API types
|
||||
* which can be utilized when serializing a custom type.
|
||||
*
|
||||
* Example of usage:
|
||||
* @snippet samples/cpp/tutorial_code/gapi/doc_snippets/api_ref_snippets.cpp S11N usage
|
||||
*
|
||||
*/
|
||||
template<typename T>
|
||||
struct S11N: public NotImplemented {
|
||||
/**
|
||||
* @brief This function allows user to serialize their custom type.
|
||||
*
|
||||
* @note The default overload throws an exception if called. User need to
|
||||
* properly overload the function to use it.
|
||||
*/
|
||||
static void serialize(IOStream &, const T &) {
|
||||
GAPI_Assert(false && "No serialization routine is provided!");
|
||||
}
|
||||
/**
|
||||
* @brief This function allows user to deserialize their custom type.
|
||||
*
|
||||
* @note The default overload throws an exception if called. User need to
|
||||
* properly overload the function to use it.
|
||||
*/
|
||||
static T deserialize(IIStream &) {
|
||||
GAPI_Assert(false && "No deserialization routine is provided!");
|
||||
}
|
||||
};
|
||||
|
||||
/// @private -- Exclude this struct from OpenCV documentation
|
||||
template<typename T> struct has_S11N_spec {
|
||||
static constexpr bool value = !std::is_base_of<NotImplemented,
|
||||
S11N<typename std::decay<T>::type>>::value;
|
||||
};
|
||||
//! @} gapi_serialization
|
||||
|
||||
} // namespace detail
|
||||
} // namespace s11n
|
||||
|
|
|
|||
|
|
@ -0,0 +1,85 @@
|
|||
// 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 distereoibution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_STEREO_HPP
|
||||
#define OPENCV_GAPI_STEREO_HPP
|
||||
|
||||
#include <opencv2/gapi/gmat.hpp>
|
||||
#include <opencv2/gapi/gscalar.hpp>
|
||||
#include <opencv2/gapi/gkernel.hpp>
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
|
||||
/**
|
||||
* The enum specified format of result that you get from @ref cv::gapi::stereo.
|
||||
*/
|
||||
enum class StereoOutputFormat {
|
||||
DEPTH_FLOAT16, ///< Floating point 16 bit value, CV_16FC1.
|
||||
///< This identifier is deprecated, use DEPTH_16F instead.
|
||||
DEPTH_FLOAT32, ///< Floating point 32 bit value, CV_32FC1
|
||||
///< This identifier is deprecated, use DEPTH_16F instead.
|
||||
DISPARITY_FIXED16_11_5, ///< 16 bit signed: first bit for sign,
|
||||
///< 10 bits for integer part,
|
||||
///< 5 bits for fractional part.
|
||||
///< This identifier is deprecated,
|
||||
///< use DISPARITY_16Q_10_5 instead.
|
||||
DISPARITY_FIXED16_12_4, ///< 16 bit signed: first bit for sign,
|
||||
///< 11 bits for integer part,
|
||||
///< 4 bits for fractional part.
|
||||
///< This identifier is deprecated,
|
||||
///< use DISPARITY_16Q_11_4 instead.
|
||||
DEPTH_16F = DEPTH_FLOAT16, ///< Same as DEPTH_FLOAT16
|
||||
DEPTH_32F = DEPTH_FLOAT32, ///< Same as DEPTH_FLOAT32
|
||||
DISPARITY_16Q_10_5 = DISPARITY_FIXED16_11_5, ///< Same as DISPARITY_FIXED16_11_5
|
||||
DISPARITY_16Q_11_4 = DISPARITY_FIXED16_12_4 ///< Same as DISPARITY_FIXED16_12_4
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief This namespace contains G-API Operation Types for Stereo and
|
||||
* related functionality.
|
||||
*/
|
||||
namespace calib3d {
|
||||
|
||||
G_TYPED_KERNEL(GStereo, <GMat(GMat, GMat, const StereoOutputFormat)>, "org.opencv.stereo") {
|
||||
static GMatDesc outMeta(const GMatDesc &left, const GMatDesc &right, const StereoOutputFormat of) {
|
||||
GAPI_Assert(left.chan == 1);
|
||||
GAPI_Assert(left.depth == CV_8U);
|
||||
|
||||
GAPI_Assert(right.chan == 1);
|
||||
GAPI_Assert(right.depth == CV_8U);
|
||||
|
||||
switch(of) {
|
||||
case StereoOutputFormat::DEPTH_FLOAT16:
|
||||
return left.withDepth(CV_16FC1);
|
||||
case StereoOutputFormat::DEPTH_FLOAT32:
|
||||
return left.withDepth(CV_32FC1);
|
||||
case StereoOutputFormat::DISPARITY_FIXED16_11_5:
|
||||
case StereoOutputFormat::DISPARITY_FIXED16_12_4:
|
||||
return left.withDepth(CV_16SC1);
|
||||
default:
|
||||
GAPI_Assert(false && "Unknown output format!");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace calib3d
|
||||
|
||||
/** @brief Computes disparity/depth map for the specified stereo-pair.
|
||||
The function computes disparity or depth map depending on passed StereoOutputFormat argument.
|
||||
|
||||
@param left 8-bit single-channel left image of @ref CV_8UC1 type.
|
||||
@param right 8-bit single-channel right image of @ref CV_8UC1 type.
|
||||
@param of enum to specified output kind: depth or disparity and corresponding type
|
||||
*/
|
||||
GAPI_EXPORTS GMat stereo(const GMat& left,
|
||||
const GMat& right,
|
||||
const StereoOutputFormat of = StereoOutputFormat::DEPTH_FLOAT32);
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_STEREO_HPP
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
// Copyright (C) 2020-2021 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GSTREAMING_DESYNC_HPP
|
||||
|
|
@ -73,9 +73,10 @@ G desync(const G &g) {
|
|||
* which produces an array of cv::util::optional<> objects.
|
||||
*
|
||||
* @note This feature is highly experimental now and is currently
|
||||
* limited to a single GMat argument only.
|
||||
* limited to a single GMat/GFrame argument only.
|
||||
*/
|
||||
GAPI_EXPORTS GMat desync(const GMat &g);
|
||||
GAPI_EXPORTS GFrame desync(const GFrame &f);
|
||||
|
||||
} // namespace streaming
|
||||
} // namespace gapi
|
||||
|
|
|
|||
|
|
@ -20,6 +20,19 @@ G_API_OP(GBGR, <GMat(GFrame)>, "org.opencv.streaming.BGR")
|
|||
static GMatDesc outMeta(const GFrameDesc& in) { return GMatDesc{CV_8U, 3, in.size}; }
|
||||
};
|
||||
|
||||
G_API_OP(GY, <GMat(GFrame)>, "org.opencv.streaming.Y") {
|
||||
static GMatDesc outMeta(const GFrameDesc& frameDesc) {
|
||||
return GMatDesc { CV_8U, 1, frameDesc.size , false };
|
||||
}
|
||||
};
|
||||
|
||||
G_API_OP(GUV, <GMat(GFrame)>, "org.opencv.streaming.UV") {
|
||||
static GMatDesc outMeta(const GFrameDesc& frameDesc) {
|
||||
return GMatDesc { CV_8U, 2, cv::Size(frameDesc.size.width / 2, frameDesc.size.height / 2),
|
||||
false };
|
||||
}
|
||||
};
|
||||
|
||||
/** @brief Gets bgr plane from input frame
|
||||
|
||||
@note Function textual ID is "org.opencv.streaming.BGR"
|
||||
|
|
@ -29,6 +42,25 @@ G_API_OP(GBGR, <GMat(GFrame)>, "org.opencv.streaming.BGR")
|
|||
*/
|
||||
GAPI_EXPORTS cv::GMat BGR(const cv::GFrame& in);
|
||||
|
||||
/** @brief Extracts Y plane from media frame.
|
||||
|
||||
Output image is 8-bit 1-channel image of @ref CV_8UC1.
|
||||
|
||||
@note Function textual ID is "org.opencv.streaming.Y"
|
||||
|
||||
@param frame input media frame.
|
||||
*/
|
||||
GAPI_EXPORTS GMat Y(const cv::GFrame& frame);
|
||||
|
||||
/** @brief Extracts UV plane from media frame.
|
||||
|
||||
Output image is 8-bit 2-channel image of @ref CV_8UC2.
|
||||
|
||||
@note Function textual ID is "org.opencv.streaming.UV"
|
||||
|
||||
@param frame input media frame.
|
||||
*/
|
||||
GAPI_EXPORTS GMat UV(const cv::GFrame& frame);
|
||||
} // namespace streaming
|
||||
|
||||
//! @addtogroup gapi_transform
|
||||
|
|
@ -42,7 +74,7 @@ e.g when graph's input needs to be passed directly to output, like in Streaming
|
|||
@param in Input image
|
||||
@return Copy of the input
|
||||
*/
|
||||
GAPI_EXPORTS GMat copy(const GMat& in);
|
||||
GAPI_EXPORTS_W GMat copy(const GMat& in);
|
||||
|
||||
/** @brief Makes a copy of the input frame. Note that this copy may be not real
|
||||
(no actual data copied). Use this function to maintain graph contracts,
|
||||
|
|
|
|||
47
thirdparty/fluid/modules/gapi/include/opencv2/gapi/streaming/gstreamer/gstreamerpipeline.hpp
vendored
Normal file
47
thirdparty/fluid/modules/gapi/include/opencv2/gapi/streaming/gstreamer/gstreamerpipeline.hpp
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_STREAMING_GSTREAMER_GSTREAMERPIPELINE_HPP
|
||||
#define OPENCV_GAPI_STREAMING_GSTREAMER_GSTREAMERPIPELINE_HPP
|
||||
|
||||
#include <opencv2/gapi/streaming/gstreamer/gstreamersource.hpp>
|
||||
#include <opencv2/gapi/own/exports.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace gst {
|
||||
|
||||
class GAPI_EXPORTS GStreamerPipeline
|
||||
{
|
||||
public:
|
||||
class Priv;
|
||||
|
||||
explicit GStreamerPipeline(const std::string& pipeline);
|
||||
IStreamSource::Ptr getStreamingSource(const std::string& appsinkName,
|
||||
const GStreamerSource::OutputType outputType =
|
||||
GStreamerSource::OutputType::MAT);
|
||||
virtual ~GStreamerPipeline();
|
||||
|
||||
protected:
|
||||
explicit GStreamerPipeline(std::unique_ptr<Priv> priv);
|
||||
|
||||
std::unique_ptr<Priv> m_priv;
|
||||
};
|
||||
|
||||
} // namespace gst
|
||||
|
||||
using GStreamerPipeline = gst::GStreamerPipeline;
|
||||
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_STREAMING_GSTREAMER_GSTREAMERPIPELINE_HPP
|
||||
89
thirdparty/fluid/modules/gapi/include/opencv2/gapi/streaming/gstreamer/gstreamersource.hpp
vendored
Normal file
89
thirdparty/fluid/modules/gapi/include/opencv2/gapi/streaming/gstreamer/gstreamersource.hpp
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_STREAMING_GSTREAMER_GSTREAMERSOURCE_HPP
|
||||
#define OPENCV_GAPI_STREAMING_GSTREAMER_GSTREAMERSOURCE_HPP
|
||||
|
||||
#include <opencv2/gapi/streaming/source.hpp>
|
||||
#include <opencv2/gapi/garg.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace gst {
|
||||
|
||||
/**
|
||||
* @brief OpenCV's GStreamer streaming source.
|
||||
* Streams cv::Mat-s/cv::MediaFrame from passed GStreamer pipeline.
|
||||
*
|
||||
* This class implements IStreamSource interface.
|
||||
*
|
||||
* To create GStreamerSource instance you need to pass 'pipeline' and, optionally, 'outputType'
|
||||
* arguments into constructor.
|
||||
* 'pipeline' should represent GStreamer pipeline in form of textual description.
|
||||
* Almost any custom pipeline is supported which can be successfully ran via gst-launch.
|
||||
* The only two limitations are:
|
||||
* - there should be __one__ appsink element in the pipeline to pass data to OpenCV app.
|
||||
* Pipeline can actually contain many sink elements, but it must have one and only one
|
||||
* appsink among them.
|
||||
*
|
||||
* - data passed to appsink should be video-frame in NV12 format.
|
||||
*
|
||||
* 'outputType' is used to select type of output data to produce: 'cv::MediaFrame' or 'cv::Mat'.
|
||||
* To produce 'cv::MediaFrame'-s you need to pass 'GStreamerSource::OutputType::FRAME' and,
|
||||
* correspondingly, 'GStreamerSource::OutputType::MAT' to produce 'cv::Mat'-s.
|
||||
* Please note, that in the last case, output 'cv::Mat' will be of BGR format, internal conversion
|
||||
* from NV12 GStreamer data will happen.
|
||||
* Default value for 'outputType' is 'GStreamerSource::OutputType::MAT'.
|
||||
*
|
||||
* @note Stream sources are passed to G-API via shared pointers, so please use gapi::make_src<>
|
||||
* to create objects and ptr() to pass a GStreamerSource to cv::gin().
|
||||
*
|
||||
* @note You need to build OpenCV with GStreamer support to use this class.
|
||||
*/
|
||||
|
||||
class GStreamerPipelineFacade;
|
||||
|
||||
class GAPI_EXPORTS GStreamerSource : public IStreamSource
|
||||
{
|
||||
public:
|
||||
class Priv;
|
||||
|
||||
// Indicates what type of data should be produced by GStreamerSource: cv::MediaFrame or cv::Mat
|
||||
enum class OutputType {
|
||||
FRAME,
|
||||
MAT
|
||||
};
|
||||
|
||||
GStreamerSource(const std::string& pipeline,
|
||||
const GStreamerSource::OutputType outputType =
|
||||
GStreamerSource::OutputType::MAT);
|
||||
GStreamerSource(std::shared_ptr<GStreamerPipelineFacade> pipeline,
|
||||
const std::string& appsinkName,
|
||||
const GStreamerSource::OutputType outputType =
|
||||
GStreamerSource::OutputType::MAT);
|
||||
|
||||
bool pull(cv::gapi::wip::Data& data) override;
|
||||
GMetaArg descr_of() const override;
|
||||
~GStreamerSource() override;
|
||||
|
||||
protected:
|
||||
explicit GStreamerSource(std::unique_ptr<Priv> priv);
|
||||
|
||||
std::unique_ptr<Priv> m_priv;
|
||||
};
|
||||
|
||||
} // namespace gst
|
||||
|
||||
using GStreamerSource = gst::GStreamerSource;
|
||||
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_STREAMING_GSTREAMER_GSTREAMERSOURCE_HPP
|
||||
88
thirdparty/fluid/modules/gapi/include/opencv2/gapi/streaming/onevpl/cfg_params.hpp
vendored
Normal file
88
thirdparty/fluid/modules/gapi/include/opencv2/gapi/streaming/onevpl/cfg_params.hpp
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_STREAMING_ONEVPL_CFG_PARAMS_HPP
|
||||
#define OPENCV_GAPI_STREAMING_ONEVPL_CFG_PARAMS_HPP
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <opencv2/gapi/streaming/source.hpp>
|
||||
#include <opencv2/gapi/util/variant.hpp>
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
|
||||
/**
|
||||
* @brief Public class is using for creation of onevpl::GSource instances.
|
||||
*
|
||||
* Class members availaible through methods @ref CfgParam::get_name() and @ref CfgParam::get_value() are used by
|
||||
* onevpl::GSource inner logic to create or find oneVPL particular implementation
|
||||
* (software/hardware, specific API version and etc.).
|
||||
*
|
||||
* @note Because oneVPL may provide several implementations which are satisfying with multiple (or single one) @ref CfgParam
|
||||
* criteria therefore it is possible to configure `preferred` parameters. This kind of CfgParams are created
|
||||
* using `is_major = false` argument in @ref CfgParam::create method and are not used by creating oneVPL particular implementations.
|
||||
* Instead they fill out a "score table" to select preferrable implementation from available list. Implementation are satisfying
|
||||
* with most of these optional params would be chosen.
|
||||
* If no one optional CfgParam params were present then first of available oneVPL implementation would be applied.
|
||||
* Please get on https://spec.oneapi.io/versions/latest/elements/oneVPL/source/API_ref/VPL_disp_api_func.html?highlight=mfxcreateconfig#mfxsetconfigfilterproperty
|
||||
* for using OneVPL configuration. In this schema `mfxU8 *name` represents @ref CfgParam::get_name() and
|
||||
* `mfxVariant value` is @ref CfgParam::get_value()
|
||||
*/
|
||||
struct GAPI_EXPORTS CfgParam {
|
||||
using name_t = std::string;
|
||||
using value_t = cv::util::variant<uint8_t, int8_t,
|
||||
uint16_t, int16_t,
|
||||
uint32_t, int32_t,
|
||||
uint64_t, int64_t,
|
||||
float_t,
|
||||
double_t,
|
||||
void*,
|
||||
std::string>;
|
||||
|
||||
/**
|
||||
* Create onevp::GSource configuration parameter.
|
||||
*
|
||||
*@param name name of parameter.
|
||||
*@param value value of parameter.
|
||||
*@param is_major TRUE if parameter MUST be provided by OneVPL inner implementation, FALSE for optional (for resolve multiple available implementations).
|
||||
*
|
||||
*/
|
||||
template<typename ValueType>
|
||||
static CfgParam create(const std::string& name, ValueType&& value, bool is_major = true) {
|
||||
CfgParam param(name, CfgParam::value_t(std::forward<ValueType>(value)), is_major);
|
||||
return param;
|
||||
}
|
||||
|
||||
struct Priv;
|
||||
|
||||
const name_t& get_name() const;
|
||||
const value_t& get_value() const;
|
||||
bool is_major() const;
|
||||
bool operator==(const CfgParam& rhs) const;
|
||||
bool operator< (const CfgParam& rhs) const;
|
||||
bool operator!=(const CfgParam& rhs) const;
|
||||
|
||||
CfgParam& operator=(const CfgParam& src);
|
||||
CfgParam& operator=(CfgParam&& src);
|
||||
CfgParam(const CfgParam& src);
|
||||
CfgParam(CfgParam&& src);
|
||||
~CfgParam();
|
||||
private:
|
||||
CfgParam(const std::string& param_name, value_t&& param_value, bool is_major_param);
|
||||
std::shared_ptr<Priv> m_priv;
|
||||
};
|
||||
|
||||
} //namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_STREAMING_ONEVPL_CFG_PARAMS_HPP
|
||||
105
thirdparty/fluid/modules/gapi/include/opencv2/gapi/streaming/onevpl/data_provider_interface.hpp
vendored
Normal file
105
thirdparty/fluid/modules/gapi/include/opencv2/gapi/streaming/onevpl/data_provider_interface.hpp
vendored
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
|
||||
#ifndef GAPI_STREAMING_ONEVPL_ONEVPL_DATA_PROVIDER_INTERFACE_HPP
|
||||
#define GAPI_STREAMING_ONEVPL_ONEVPL_DATA_PROVIDER_INTERFACE_HPP
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <opencv2/gapi/own/exports.hpp> // GAPI_EXPORTS
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
|
||||
struct GAPI_EXPORTS DataProviderException : public std::exception {
|
||||
DataProviderException(const std::string& descr);
|
||||
DataProviderException(std::string&& descr);
|
||||
|
||||
virtual ~DataProviderException() = default;
|
||||
virtual const char* what() const noexcept override;
|
||||
private:
|
||||
std::string reason;
|
||||
};
|
||||
|
||||
struct GAPI_EXPORTS DataProviderSystemErrorException final : public DataProviderException {
|
||||
DataProviderSystemErrorException(int error_code, const std::string& desription = std::string());
|
||||
~DataProviderSystemErrorException() = default;
|
||||
};
|
||||
|
||||
struct GAPI_EXPORTS DataProviderUnsupportedException final : public DataProviderException {
|
||||
DataProviderUnsupportedException(const std::string& description);
|
||||
~DataProviderUnsupportedException() = default;
|
||||
};
|
||||
|
||||
struct GAPI_EXPORTS DataProviderImplementationException : public DataProviderException {
|
||||
DataProviderImplementationException(const std::string& description);
|
||||
~DataProviderImplementationException() = default;
|
||||
};
|
||||
/**
|
||||
* @brief Public interface allows to customize extraction of video stream data
|
||||
* used by onevpl::GSource instead of reading stream from file (by default).
|
||||
*
|
||||
* Interface implementation constructor MUST provide consistency and creates fully operable object.
|
||||
* If error happened implementation MUST throw `DataProviderException` kind exceptions
|
||||
*
|
||||
* @note Interface implementation MUST manage stream and other constructed resources by itself to avoid any kind of leak.
|
||||
* For simple interface implementation example please see `StreamDataProvider` in `tests/streaming/gapi_streaming_tests.cpp`
|
||||
*/
|
||||
struct GAPI_EXPORTS IDataProvider {
|
||||
using Ptr = std::shared_ptr<IDataProvider>;
|
||||
using mfx_codec_id_type = uint32_t;
|
||||
|
||||
/**
|
||||
* NB: here is supposed to be forward declaration of mfxBitstream
|
||||
* But according to current oneVPL implementation it is impossible to forward
|
||||
* declare untagged struct mfxBitstream.
|
||||
*
|
||||
* IDataProvider makes sense only for HAVE_VPL is ON and to keep IDataProvider
|
||||
* interface API/ABI compliant between core library and user application layer
|
||||
* let's introduce wrapper mfx_bitstream which inherits mfxBitstream in private
|
||||
* G-API code section and declare forward for wrapper mfx_bitstream here
|
||||
*/
|
||||
struct mfx_bitstream;
|
||||
|
||||
virtual ~IDataProvider() = default;
|
||||
|
||||
/**
|
||||
* The function is used by onevpl::GSource to extract codec id from data
|
||||
*
|
||||
*/
|
||||
virtual mfx_codec_id_type get_mfx_codec_id() const = 0;
|
||||
|
||||
/**
|
||||
* The function is used by onevpl::GSource to extract binary data stream from @ref IDataProvider
|
||||
* implementation.
|
||||
*
|
||||
* It MUST throw `DataProviderException` kind exceptions in fail cases.
|
||||
* It MUST return MFX_ERR_MORE_DATA in EOF which considered as not-fail case.
|
||||
*
|
||||
* @param in_out_bitsream the input-output reference on MFX bitstream buffer which MUST be empty at the first request
|
||||
* to allow implementation to allocate it by itself and to return back. Subsequent invocation of `fetch_bitstream_data`
|
||||
* MUST use the previously used in_out_bitsream to avoid skipping rest of frames which haven't been consumed
|
||||
* @return true for fetched data, false on EOF and throws exception on error
|
||||
*/
|
||||
virtual bool fetch_bitstream_data(std::shared_ptr<mfx_bitstream> &in_out_bitsream) = 0;
|
||||
|
||||
/**
|
||||
* The function is used by onevpl::GSource to check more binary data availability.
|
||||
*
|
||||
* It MUST return TRUE in case of EOF and NO_THROW exceptions.
|
||||
*
|
||||
* @return boolean value which detects end of stream
|
||||
*/
|
||||
virtual bool empty() const = 0;
|
||||
};
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // GAPI_STREAMING_ONEVPL_ONEVPL_DATA_PROVIDER_INTERFACE_HPP
|
||||
102
thirdparty/fluid/modules/gapi/include/opencv2/gapi/streaming/onevpl/device_selector_interface.hpp
vendored
Normal file
102
thirdparty/fluid/modules/gapi/include/opencv2/gapi/streaming/onevpl/device_selector_interface.hpp
vendored
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
|
||||
#ifndef GAPI_STREAMING_ONEVPL_DEVICE_SELECTOR_INTERFACE_HPP
|
||||
#define GAPI_STREAMING_ONEVPL_DEVICE_SELECTOR_INTERFACE_HPP
|
||||
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
|
||||
enum class AccelType: uint8_t {
|
||||
HOST,
|
||||
DX11,
|
||||
|
||||
LAST_VALUE = std::numeric_limits<uint8_t>::max()
|
||||
};
|
||||
|
||||
GAPI_EXPORTS const char* to_cstring(AccelType type);
|
||||
|
||||
struct IDeviceSelector;
|
||||
struct GAPI_EXPORTS Device {
|
||||
friend struct IDeviceSelector;
|
||||
using Ptr = void*;
|
||||
|
||||
~Device();
|
||||
const std::string& get_name() const;
|
||||
Ptr get_ptr() const;
|
||||
AccelType get_type() const;
|
||||
private:
|
||||
Device(Ptr device_ptr, const std::string& device_name,
|
||||
AccelType device_type);
|
||||
|
||||
std::string name;
|
||||
Ptr ptr;
|
||||
AccelType type;
|
||||
};
|
||||
|
||||
struct GAPI_EXPORTS Context {
|
||||
friend struct IDeviceSelector;
|
||||
using Ptr = void*;
|
||||
|
||||
~Context();
|
||||
Ptr get_ptr() const;
|
||||
AccelType get_type() const;
|
||||
private:
|
||||
Context(Ptr ctx_ptr, AccelType ctx_type);
|
||||
Ptr ptr;
|
||||
AccelType type;
|
||||
};
|
||||
|
||||
struct GAPI_EXPORTS IDeviceSelector {
|
||||
using Ptr = std::shared_ptr<IDeviceSelector>;
|
||||
|
||||
struct GAPI_EXPORTS Score {
|
||||
friend struct IDeviceSelector;
|
||||
using Type = int16_t;
|
||||
static constexpr Type MaxActivePriority = std::numeric_limits<Type>::max();
|
||||
static constexpr Type MinActivePriority = 0;
|
||||
static constexpr Type MaxPassivePriority = MinActivePriority - 1;
|
||||
static constexpr Type MinPassivePriority = std::numeric_limits<Type>::min();
|
||||
|
||||
Score(Type val);
|
||||
~Score();
|
||||
|
||||
operator Type () const;
|
||||
Type get() const;
|
||||
friend bool operator< (Score lhs, Score rhs) {
|
||||
return lhs.get() < rhs.get();
|
||||
}
|
||||
private:
|
||||
Type value;
|
||||
};
|
||||
|
||||
using DeviceScoreTable = std::map<Score, Device>;
|
||||
using DeviceContexts = std::vector<Context>;
|
||||
|
||||
virtual ~IDeviceSelector();
|
||||
virtual DeviceScoreTable select_devices() const = 0;
|
||||
virtual DeviceContexts select_context() = 0;
|
||||
protected:
|
||||
template<typename Entity, typename ...Args>
|
||||
static Entity create(Args &&...args) {
|
||||
return Entity(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // GAPI_STREAMING_ONEVPL_DEVICE_SELECTOR_INTERFACE_HPP
|
||||
90
thirdparty/fluid/modules/gapi/include/opencv2/gapi/streaming/onevpl/source.hpp
vendored
Normal file
90
thirdparty/fluid/modules/gapi/include/opencv2/gapi/streaming/onevpl/source.hpp
vendored
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_STREAMING_ONEVPL_ONEVPL_SOURCE_HPP
|
||||
#define OPENCV_GAPI_STREAMING_ONEVPL_ONEVPL_SOURCE_HPP
|
||||
|
||||
#include <opencv2/gapi/garg.hpp>
|
||||
#include <opencv2/gapi/streaming/meta.hpp>
|
||||
#include <opencv2/gapi/streaming/source.hpp>
|
||||
#include <opencv2/gapi/streaming/onevpl/cfg_params.hpp>
|
||||
#include <opencv2/gapi/streaming/onevpl/data_provider_interface.hpp>
|
||||
#include <opencv2/gapi/streaming/onevpl/device_selector_interface.hpp>
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
using CfgParams = std::vector<CfgParam>;
|
||||
|
||||
/**
|
||||
* @brief G-API streaming source based on OneVPL implementation.
|
||||
*
|
||||
* This class implements IStreamSource interface.
|
||||
* Its constructor takes source file path (in usual way) or @ref onevpl::IDataProvider
|
||||
* interface implementation (for not file-based sources). It also allows to pass-through
|
||||
* oneVPL configuration parameters by using several @ref onevpl::CfgParam.
|
||||
*
|
||||
* @note stream sources are passed to G-API via shared pointers, so
|
||||
* please gapi::make_onevpl_src<> to create objects and ptr() to pass a
|
||||
* GSource to cv::gin().
|
||||
*/
|
||||
class GAPI_EXPORTS GSource : public IStreamSource
|
||||
{
|
||||
public:
|
||||
struct Priv;
|
||||
|
||||
GSource(const std::string& filePath,
|
||||
const CfgParams& cfg_params = CfgParams{});
|
||||
|
||||
GSource(const std::string& filePath,
|
||||
const CfgParams& cfg_params,
|
||||
const std::string& device_id,
|
||||
void* accel_device_ptr,
|
||||
void* accel_ctx_ptr);
|
||||
|
||||
GSource(const std::string& filePath,
|
||||
const CfgParams& cfg_params,
|
||||
std::shared_ptr<IDeviceSelector> selector);
|
||||
|
||||
|
||||
GSource(std::shared_ptr<IDataProvider> source,
|
||||
const CfgParams& cfg_params = CfgParams{});
|
||||
|
||||
GSource(std::shared_ptr<IDataProvider> source,
|
||||
const CfgParams& cfg_params,
|
||||
const std::string& device_id,
|
||||
void* accel_device_ptr,
|
||||
void* accel_ctx_ptr);
|
||||
|
||||
GSource(std::shared_ptr<IDataProvider> source,
|
||||
const CfgParams& cfg_params,
|
||||
std::shared_ptr<IDeviceSelector> selector);
|
||||
|
||||
~GSource() override;
|
||||
|
||||
bool pull(cv::gapi::wip::Data& data) override;
|
||||
GMetaArg descr_of() const override;
|
||||
|
||||
private:
|
||||
explicit GSource(std::unique_ptr<Priv>&& impl);
|
||||
std::unique_ptr<Priv> m_priv;
|
||||
};
|
||||
} // namespace onevpl
|
||||
|
||||
using GVPLSource = onevpl::GSource;
|
||||
|
||||
template<class... Args>
|
||||
GAPI_EXPORTS_W cv::Ptr<IStreamSource> inline make_onevpl_src(Args&&... args)
|
||||
{
|
||||
return make_src<onevpl::GSource>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_STREAMING_ONEVPL_ONEVPL_SOURCE_HPP
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_STREAMING_SYNC_HPP
|
||||
#define OPENCV_GAPI_STREAMING_SYNC_HPP
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace streaming {
|
||||
|
||||
enum class sync_policy {
|
||||
dont_sync,
|
||||
drop
|
||||
};
|
||||
|
||||
} // namespace streaming
|
||||
} // namespace gapi
|
||||
|
||||
namespace detail {
|
||||
template<> struct CompileArgTag<gapi::streaming::sync_policy> {
|
||||
static const char* tag() { return "gapi.streaming.sync_policy"; }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_STREAMING_SYNC_HPP
|
||||
|
|
@ -31,7 +31,11 @@ namespace internal
|
|||
#if defined(__GXX_RTTI) || defined(_CPPRTTI)
|
||||
return dynamic_cast<T>(operand);
|
||||
#else
|
||||
#warning used static cast instead of dynamic because RTTI is disabled
|
||||
#ifdef __GNUC__
|
||||
#warning used static cast instead of dynamic because RTTI is disabled
|
||||
#else
|
||||
#pragma message("WARNING: used static cast instead of dynamic because RTTI is disabled")
|
||||
#endif
|
||||
return static_cast<T>(operand);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ namespace util
|
|||
// Constructors
|
||||
// NB.: there were issues with Clang 3.8 when =default() was used
|
||||
// instead {}
|
||||
optional() {};
|
||||
optional() {}
|
||||
optional(const optional&) = default;
|
||||
explicit optional(T&&) noexcept;
|
||||
explicit optional(const T&) noexcept;
|
||||
|
|
@ -84,7 +84,7 @@ namespace util
|
|||
|
||||
// Implementation //////////////////////////////////////////////////////////
|
||||
template<class T> optional<T>::optional(T &&v) noexcept
|
||||
: m_holder(v)
|
||||
: m_holder(std::move(v))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -116,7 +116,73 @@ namespace detail
|
|||
using type = std::tuple<Objs...>;
|
||||
static type get(std::tuple<Objs...>&& objs) { return std::forward<std::tuple<Objs...>>(objs); }
|
||||
};
|
||||
|
||||
template<typename... Ts>
|
||||
struct make_void { typedef void type;};
|
||||
|
||||
template<typename... Ts>
|
||||
using void_t = typename make_void<Ts...>::type;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace util
|
||||
{
|
||||
template<typename ...L>
|
||||
struct overload_lamba_set;
|
||||
|
||||
template<typename L1>
|
||||
struct overload_lamba_set<L1> : public L1
|
||||
{
|
||||
overload_lamba_set(L1&& lambda) : L1(std::move(lambda)) {}
|
||||
overload_lamba_set(const L1& lambda) : L1(lambda) {}
|
||||
|
||||
using L1::operator();
|
||||
};
|
||||
|
||||
template<typename L1, typename ...L>
|
||||
struct overload_lamba_set<L1, L...> : public L1, public overload_lamba_set<L...>
|
||||
{
|
||||
using base_type = overload_lamba_set<L...>;
|
||||
overload_lamba_set(L1 &&lambda1, L&& ...lambdas):
|
||||
L1(std::move(lambda1)),
|
||||
base_type(std::forward<L>(lambdas)...) {}
|
||||
|
||||
overload_lamba_set(const L1 &lambda1, L&& ...lambdas):
|
||||
L1(lambda1),
|
||||
base_type(std::forward<L>(lambdas)...) {}
|
||||
|
||||
using L1::operator();
|
||||
using base_type::operator();
|
||||
};
|
||||
|
||||
template<typename... L>
|
||||
overload_lamba_set<L...> overload_lambdas(L&& ...lambdas)
|
||||
{
|
||||
return overload_lamba_set<L...>(std::forward<L>(lambdas)...);
|
||||
}
|
||||
|
||||
template<typename ...T>
|
||||
struct find_adapter_impl;
|
||||
|
||||
template<typename AdapterT, typename T>
|
||||
struct find_adapter_impl<AdapterT, T>
|
||||
{
|
||||
using type = typename std::conditional<std::is_base_of<AdapterT, T>::value,
|
||||
T,
|
||||
void>::type;
|
||||
static constexpr bool found = std::is_base_of<AdapterT, T>::value;
|
||||
};
|
||||
|
||||
template<typename AdapterT, typename T, typename... Types>
|
||||
struct find_adapter_impl<AdapterT, T, Types...>
|
||||
{
|
||||
using type = typename std::conditional<std::is_base_of<AdapterT, T>::value,
|
||||
T,
|
||||
typename find_adapter_impl<AdapterT, Types...>::type>::type;
|
||||
static constexpr bool found = std::is_base_of<AdapterT, T>::value ||
|
||||
find_adapter_impl<AdapterT, Types...>::found;
|
||||
};
|
||||
} // namespace util
|
||||
} // namespace cv
|
||||
|
||||
// \endcond
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <array>
|
||||
#include <type_traits>
|
||||
|
||||
#include <opencv2/gapi/util/compiler_hints.hpp>
|
||||
#include <opencv2/gapi/util/throw.hpp>
|
||||
#include <opencv2/gapi/util/util.hpp> // max_of_t
|
||||
#include <opencv2/gapi/util/type_traits.hpp>
|
||||
|
|
@ -44,6 +45,12 @@ namespace util
|
|||
static const constexpr std::size_t value = detail::type_list_index_helper<0, Target, Types...>::value;
|
||||
};
|
||||
|
||||
template<std::size_t Index, class... Types >
|
||||
struct type_list_element
|
||||
{
|
||||
using type = typename std::tuple_element<Index, std::tuple<Types...> >::type;
|
||||
};
|
||||
|
||||
class bad_variant_access: public std::exception
|
||||
{
|
||||
public:
|
||||
|
|
@ -233,9 +240,87 @@ namespace util
|
|||
template<typename T, typename... Types>
|
||||
const T& get(const util::variant<Types...> &v);
|
||||
|
||||
template<std::size_t Index, typename... Types>
|
||||
typename util::type_list_element<Index, Types...>::type& get(util::variant<Types...> &v);
|
||||
|
||||
template<std::size_t Index, typename... Types>
|
||||
const typename util::type_list_element<Index, Types...>::type& get(const util::variant<Types...> &v);
|
||||
|
||||
template<typename T, typename... Types>
|
||||
bool holds_alternative(const util::variant<Types...> &v) noexcept;
|
||||
|
||||
|
||||
// Visitor
|
||||
namespace detail
|
||||
{
|
||||
struct visitor_interface {};
|
||||
|
||||
// Class `visitor_return_type_deduction_helper`
|
||||
// introduces solution for deduction `return_type` in `visit` function in common way
|
||||
// for both Lambda and class Visitor and keep one interface invocation point: `visit` only
|
||||
// his helper class is required to unify return_type deduction mechanism because
|
||||
// for Lambda it is possible to take type of `decltype(visitor(get<0>(var)))`
|
||||
// but for class Visitor there is no operator() in base case,
|
||||
// because it provides `operator() (std::size_t index, ...)`
|
||||
// So `visitor_return_type_deduction_helper` expose `operator()`
|
||||
// uses only for class Visitor only for deduction `return type` in visit()
|
||||
template<typename R>
|
||||
struct visitor_return_type_deduction_helper
|
||||
{
|
||||
using return_type = R;
|
||||
|
||||
// to be used in Lambda return type deduction context only
|
||||
template<typename T>
|
||||
return_type operator() (T&&);
|
||||
};
|
||||
}
|
||||
|
||||
// Special purpose `static_visitor` can receive additional arguments
|
||||
template<typename R, typename Impl>
|
||||
struct static_visitor : public detail::visitor_interface,
|
||||
public detail::visitor_return_type_deduction_helper<R> {
|
||||
|
||||
// assign responsibility for return type deduction to helper class
|
||||
using return_type = typename detail::visitor_return_type_deduction_helper<R>::return_type;
|
||||
using detail::visitor_return_type_deduction_helper<R>::operator();
|
||||
friend Impl;
|
||||
|
||||
template<typename VariantValue, typename ...Args>
|
||||
return_type operator() (std::size_t index, VariantValue&& value, Args&& ...args)
|
||||
{
|
||||
suppress_unused_warning(index);
|
||||
return static_cast<Impl*>(this)-> visit(
|
||||
std::forward<VariantValue>(value),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
// Special purpose `static_indexed_visitor` can receive additional arguments
|
||||
// And make forwarding current variant index as runtime function argument to its `Impl`
|
||||
template<typename R, typename Impl>
|
||||
struct static_indexed_visitor : public detail::visitor_interface,
|
||||
public detail::visitor_return_type_deduction_helper<R> {
|
||||
|
||||
// assign responsibility for return type deduction to helper class
|
||||
using return_type = typename detail::visitor_return_type_deduction_helper<R>::return_type;
|
||||
using detail::visitor_return_type_deduction_helper<R>::operator();
|
||||
friend Impl;
|
||||
|
||||
template<typename VariantValue, typename ...Args>
|
||||
return_type operator() (std::size_t Index, VariantValue&& value, Args&& ...args)
|
||||
{
|
||||
return static_cast<Impl*>(this)-> visit(Index,
|
||||
std::forward<VariantValue>(value),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct variant_size;
|
||||
|
||||
template <class... Types>
|
||||
struct variant_size<util::variant<Types...>>
|
||||
: std::integral_constant<std::size_t, sizeof...(Types)> { };
|
||||
// FIXME: T&&, const TT&& versions.
|
||||
|
||||
// Implementation //////////////////////////////////////////////////////////
|
||||
|
|
@ -402,6 +487,22 @@ namespace util
|
|||
throw_error(bad_variant_access());
|
||||
}
|
||||
|
||||
template<std::size_t Index, typename... Types>
|
||||
typename util::type_list_element<Index, Types...>::type& get(util::variant<Types...> &v)
|
||||
{
|
||||
using ReturnType = typename util::type_list_element<Index, Types...>::type;
|
||||
return const_cast<ReturnType&>(get<Index, Types...>(static_cast<const util::variant<Types...> &>(v)));
|
||||
}
|
||||
|
||||
template<std::size_t Index, typename... Types>
|
||||
const typename util::type_list_element<Index, Types...>::type& get(const util::variant<Types...> &v)
|
||||
{
|
||||
static_assert(Index < sizeof...(Types),
|
||||
"`Index` it out of bound of `util::variant` type list");
|
||||
using ReturnType = typename util::type_list_element<Index, Types...>::type;
|
||||
return get<ReturnType>(v);
|
||||
}
|
||||
|
||||
template<typename T, typename... Types>
|
||||
bool holds_alternative(const util::variant<Types...> &v) noexcept
|
||||
{
|
||||
|
|
@ -428,7 +529,130 @@ namespace util
|
|||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
} // namespace cv
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// terminate recursion implementation for `non-void` ReturnType
|
||||
template<typename ReturnType, std::size_t CurIndex, std::size_t ElemCount,
|
||||
typename Visitor, typename Variant, typename... VisitorArgs>
|
||||
ReturnType apply_visitor_impl(Visitor&&, Variant&,
|
||||
std::true_type, std::false_type,
|
||||
VisitorArgs&& ...)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
// terminate recursion implementation for `void` ReturnType
|
||||
template<typename ReturnType, std::size_t CurIndex, std::size_t ElemCount,
|
||||
typename Visitor, typename Variant, typename... VisitorArgs>
|
||||
void apply_visitor_impl(Visitor&&, Variant&,
|
||||
std::true_type, std::true_type,
|
||||
VisitorArgs&& ...)
|
||||
{
|
||||
}
|
||||
|
||||
// Intermediate resursion processor for Lambda Visitors
|
||||
template<typename ReturnType, std::size_t CurIndex, std::size_t ElemCount,
|
||||
typename Visitor, typename Variant, bool no_return_value, typename... VisitorArgs>
|
||||
typename std::enable_if<!std::is_base_of<visitor_interface, typename std::decay<Visitor>::type>::value, ReturnType>::type
|
||||
apply_visitor_impl(Visitor&& visitor, Variant&& v, std::false_type not_processed,
|
||||
std::integral_constant<bool, no_return_value> should_no_return,
|
||||
VisitorArgs&& ...args)
|
||||
{
|
||||
static_assert(std::is_same<ReturnType, decltype(visitor(get<CurIndex>(v)))>::value,
|
||||
"Different `ReturnType`s detected! All `Visitor::visit` or `overload_lamba_set`"
|
||||
" must return the same type");
|
||||
suppress_unused_warning(not_processed);
|
||||
if (v.index() == CurIndex)
|
||||
{
|
||||
return visitor.operator()(get<CurIndex>(v), std::forward<VisitorArgs>(args)... );
|
||||
}
|
||||
|
||||
using is_variant_processed_t = std::integral_constant<bool, CurIndex + 1 >= ElemCount>;
|
||||
return apply_visitor_impl<ReturnType, CurIndex +1, ElemCount>(
|
||||
std::forward<Visitor>(visitor),
|
||||
std::forward<Variant>(v),
|
||||
is_variant_processed_t{},
|
||||
should_no_return,
|
||||
std::forward<VisitorArgs>(args)...);
|
||||
}
|
||||
|
||||
//Visual Studio 2014 compilation fix: cast visitor to base class before invoke operator()
|
||||
template<std::size_t CurIndex, typename ReturnType, typename Visitor, class Value, typename... VisitorArgs>
|
||||
typename std::enable_if<std::is_base_of<static_visitor<ReturnType, typename std::decay<Visitor>::type>,
|
||||
typename std::decay<Visitor>::type>::value, ReturnType>::type
|
||||
invoke_class_visitor(Visitor& visitor, Value&& v, VisitorArgs&&...args)
|
||||
{
|
||||
return static_cast<static_visitor<ReturnType, typename std::decay<Visitor>::type>&>(visitor).operator() (CurIndex, std::forward<Value>(v), std::forward<VisitorArgs>(args)... );
|
||||
}
|
||||
|
||||
//Visual Studio 2014 compilation fix: cast visitor to base class before invoke operator()
|
||||
template<std::size_t CurIndex, typename ReturnType, typename Visitor, class Value, typename... VisitorArgs>
|
||||
typename std::enable_if<std::is_base_of<static_indexed_visitor<ReturnType, typename std::decay<Visitor>::type>,
|
||||
typename std::decay<Visitor>::type>::value, ReturnType>::type
|
||||
invoke_class_visitor(Visitor& visitor, Value&& v, VisitorArgs&&...args)
|
||||
{
|
||||
return static_cast<static_indexed_visitor<ReturnType, typename std::decay<Visitor>::type>&>(visitor).operator() (CurIndex, std::forward<Value>(v), std::forward<VisitorArgs>(args)... );
|
||||
}
|
||||
|
||||
// Intermediate recursion processor for special case `visitor_interface` derived Visitors
|
||||
template<typename ReturnType, std::size_t CurIndex, std::size_t ElemCount,
|
||||
typename Visitor, typename Variant, bool no_return_value, typename... VisitorArgs>
|
||||
typename std::enable_if<std::is_base_of<visitor_interface, typename std::decay<Visitor>::type>::value, ReturnType>::type
|
||||
apply_visitor_impl(Visitor&& visitor, Variant&& v, std::false_type not_processed,
|
||||
std::integral_constant<bool, no_return_value> should_no_return,
|
||||
VisitorArgs&& ...args)
|
||||
{
|
||||
static_assert(std::is_same<ReturnType, decltype(visitor(get<CurIndex>(v)))>::value,
|
||||
"Different `ReturnType`s detected! All `Visitor::visit` or `overload_lamba_set`"
|
||||
" must return the same type");
|
||||
suppress_unused_warning(not_processed);
|
||||
if (v.index() == CurIndex)
|
||||
{
|
||||
return invoke_class_visitor<CurIndex, ReturnType>(visitor, get<CurIndex>(v), std::forward<VisitorArgs>(args)... );
|
||||
}
|
||||
|
||||
using is_variant_processed_t = std::integral_constant<bool, CurIndex + 1 >= ElemCount>;
|
||||
return apply_visitor_impl<ReturnType, CurIndex +1, ElemCount>(
|
||||
std::forward<Visitor>(visitor),
|
||||
std::forward<Variant>(v),
|
||||
is_variant_processed_t{},
|
||||
should_no_return,
|
||||
std::forward<VisitorArgs>(args)...);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template<typename Visitor, typename Variant, typename... VisitorArg>
|
||||
auto visit(Visitor &visitor, const Variant& var, VisitorArg &&...args) -> decltype(visitor(get<0>(var)))
|
||||
{
|
||||
constexpr std::size_t varsize = util::variant_size<Variant>::value;
|
||||
static_assert(varsize != 0, "utils::variant must contains one type at least ");
|
||||
using is_variant_processed_t = std::false_type;
|
||||
|
||||
using ReturnType = decltype(visitor(get<0>(var)));
|
||||
using return_t = std::is_same<ReturnType, void>;
|
||||
return detail::apply_visitor_impl<ReturnType, 0, varsize, Visitor>(
|
||||
std::forward<Visitor>(visitor),
|
||||
var, is_variant_processed_t{},
|
||||
return_t{},
|
||||
std::forward<VisitorArg>(args)...);
|
||||
}
|
||||
|
||||
template<typename Visitor, typename Variant>
|
||||
auto visit(Visitor&& visitor, const Variant& var) -> decltype(visitor(get<0>(var)))
|
||||
{
|
||||
constexpr std::size_t varsize = util::variant_size<Variant>::value;
|
||||
static_assert(varsize != 0, "utils::variant must contains one type at least ");
|
||||
using is_variant_processed_t = std::false_type;
|
||||
|
||||
using ReturnType = decltype(visitor(get<0>(var)));
|
||||
using return_t = std::is_same<ReturnType, void>;
|
||||
return detail::apply_visitor_impl<ReturnType, 0, varsize, Visitor>(
|
||||
std::forward<Visitor>(visitor),
|
||||
var, is_variant_processed_t{},
|
||||
return_t{});
|
||||
}
|
||||
} // namespace util
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_UTIL_VARIANT_HPP
|
||||
|
|
|
|||
|
|
@ -42,6 +42,10 @@ struct GAPI_EXPORTS KalmanParams
|
|||
Mat controlMatrix;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This namespace contains G-API Operations and functions for
|
||||
* video-oriented algorithms, like optical flow and background subtraction.
|
||||
*/
|
||||
namespace video
|
||||
{
|
||||
using GBuildPyrOutput = std::tuple<GArray<GMat>, GScalar>;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,299 @@
|
|||
__all__ = ['op', 'kernel']
|
||||
|
||||
import sys
|
||||
import cv2 as cv
|
||||
|
||||
# NB: Register function in specific module
|
||||
def register(mname):
|
||||
def parameterized(func):
|
||||
sys.modules[mname].__dict__[func.__name__] = func
|
||||
return func
|
||||
return parameterized
|
||||
|
||||
|
||||
@register('cv2.gapi')
|
||||
def networks(*args):
|
||||
return cv.gapi_GNetPackage(list(map(cv.detail.strip, args)))
|
||||
|
||||
|
||||
@register('cv2.gapi')
|
||||
def compile_args(*args):
|
||||
return list(map(cv.GCompileArg, args))
|
||||
|
||||
|
||||
@register('cv2')
|
||||
def GIn(*args):
|
||||
return [*args]
|
||||
|
||||
|
||||
@register('cv2')
|
||||
def GOut(*args):
|
||||
return [*args]
|
||||
|
||||
|
||||
@register('cv2')
|
||||
def gin(*args):
|
||||
return [*args]
|
||||
|
||||
|
||||
@register('cv2.gapi')
|
||||
def descr_of(*args):
|
||||
return [*args]
|
||||
|
||||
|
||||
@register('cv2')
|
||||
class GOpaque():
|
||||
# NB: Inheritance from c++ class cause segfault.
|
||||
# So just aggregate cv.GOpaqueT instead of inheritance
|
||||
def __new__(cls, argtype):
|
||||
return cv.GOpaqueT(argtype)
|
||||
|
||||
class Bool():
|
||||
def __new__(self):
|
||||
return cv.GOpaqueT(cv.gapi.CV_BOOL)
|
||||
|
||||
class Int():
|
||||
def __new__(self):
|
||||
return cv.GOpaqueT(cv.gapi.CV_INT)
|
||||
|
||||
class Double():
|
||||
def __new__(self):
|
||||
return cv.GOpaqueT(cv.gapi.CV_DOUBLE)
|
||||
|
||||
class Float():
|
||||
def __new__(self):
|
||||
return cv.GOpaqueT(cv.gapi.CV_FLOAT)
|
||||
|
||||
class String():
|
||||
def __new__(self):
|
||||
return cv.GOpaqueT(cv.gapi.CV_STRING)
|
||||
|
||||
class Point():
|
||||
def __new__(self):
|
||||
return cv.GOpaqueT(cv.gapi.CV_POINT)
|
||||
|
||||
class Point2f():
|
||||
def __new__(self):
|
||||
return cv.GOpaqueT(cv.gapi.CV_POINT2F)
|
||||
|
||||
class Size():
|
||||
def __new__(self):
|
||||
return cv.GOpaqueT(cv.gapi.CV_SIZE)
|
||||
|
||||
class Rect():
|
||||
def __new__(self):
|
||||
return cv.GOpaqueT(cv.gapi.CV_RECT)
|
||||
|
||||
class Prim():
|
||||
def __new__(self):
|
||||
return cv.GOpaqueT(cv.gapi.CV_DRAW_PRIM)
|
||||
|
||||
class Any():
|
||||
def __new__(self):
|
||||
return cv.GOpaqueT(cv.gapi.CV_ANY)
|
||||
|
||||
@register('cv2')
|
||||
class GArray():
|
||||
# NB: Inheritance from c++ class cause segfault.
|
||||
# So just aggregate cv.GArrayT instead of inheritance
|
||||
def __new__(cls, argtype):
|
||||
return cv.GArrayT(argtype)
|
||||
|
||||
class Bool():
|
||||
def __new__(self):
|
||||
return cv.GArrayT(cv.gapi.CV_BOOL)
|
||||
|
||||
class Int():
|
||||
def __new__(self):
|
||||
return cv.GArrayT(cv.gapi.CV_INT)
|
||||
|
||||
class Double():
|
||||
def __new__(self):
|
||||
return cv.GArrayT(cv.gapi.CV_DOUBLE)
|
||||
|
||||
class Float():
|
||||
def __new__(self):
|
||||
return cv.GArrayT(cv.gapi.CV_FLOAT)
|
||||
|
||||
class String():
|
||||
def __new__(self):
|
||||
return cv.GArrayT(cv.gapi.CV_STRING)
|
||||
|
||||
class Point():
|
||||
def __new__(self):
|
||||
return cv.GArrayT(cv.gapi.CV_POINT)
|
||||
|
||||
class Point2f():
|
||||
def __new__(self):
|
||||
return cv.GArrayT(cv.gapi.CV_POINT2F)
|
||||
|
||||
class Size():
|
||||
def __new__(self):
|
||||
return cv.GArrayT(cv.gapi.CV_SIZE)
|
||||
|
||||
class Rect():
|
||||
def __new__(self):
|
||||
return cv.GArrayT(cv.gapi.CV_RECT)
|
||||
|
||||
class Scalar():
|
||||
def __new__(self):
|
||||
return cv.GArrayT(cv.gapi.CV_SCALAR)
|
||||
|
||||
class Mat():
|
||||
def __new__(self):
|
||||
return cv.GArrayT(cv.gapi.CV_MAT)
|
||||
|
||||
class GMat():
|
||||
def __new__(self):
|
||||
return cv.GArrayT(cv.gapi.CV_GMAT)
|
||||
|
||||
class Prim():
|
||||
def __new__(self):
|
||||
return cv.GArray(cv.gapi.CV_DRAW_PRIM)
|
||||
|
||||
class Any():
|
||||
def __new__(self):
|
||||
return cv.GArray(cv.gapi.CV_ANY)
|
||||
|
||||
|
||||
# NB: Top lvl decorator takes arguments
|
||||
def op(op_id, in_types, out_types):
|
||||
|
||||
garray_types= {
|
||||
cv.GArray.Bool: cv.gapi.CV_BOOL,
|
||||
cv.GArray.Int: cv.gapi.CV_INT,
|
||||
cv.GArray.Double: cv.gapi.CV_DOUBLE,
|
||||
cv.GArray.Float: cv.gapi.CV_FLOAT,
|
||||
cv.GArray.String: cv.gapi.CV_STRING,
|
||||
cv.GArray.Point: cv.gapi.CV_POINT,
|
||||
cv.GArray.Point2f: cv.gapi.CV_POINT2F,
|
||||
cv.GArray.Size: cv.gapi.CV_SIZE,
|
||||
cv.GArray.Rect: cv.gapi.CV_RECT,
|
||||
cv.GArray.Scalar: cv.gapi.CV_SCALAR,
|
||||
cv.GArray.Mat: cv.gapi.CV_MAT,
|
||||
cv.GArray.GMat: cv.gapi.CV_GMAT,
|
||||
cv.GArray.Prim: cv.gapi.CV_DRAW_PRIM,
|
||||
cv.GArray.Any: cv.gapi.CV_ANY
|
||||
}
|
||||
|
||||
gopaque_types= {
|
||||
cv.GOpaque.Size: cv.gapi.CV_SIZE,
|
||||
cv.GOpaque.Rect: cv.gapi.CV_RECT,
|
||||
cv.GOpaque.Bool: cv.gapi.CV_BOOL,
|
||||
cv.GOpaque.Int: cv.gapi.CV_INT,
|
||||
cv.GOpaque.Double: cv.gapi.CV_DOUBLE,
|
||||
cv.GOpaque.Float: cv.gapi.CV_FLOAT,
|
||||
cv.GOpaque.String: cv.gapi.CV_STRING,
|
||||
cv.GOpaque.Point: cv.gapi.CV_POINT,
|
||||
cv.GOpaque.Point2f: cv.gapi.CV_POINT2F,
|
||||
cv.GOpaque.Size: cv.gapi.CV_SIZE,
|
||||
cv.GOpaque.Rect: cv.gapi.CV_RECT,
|
||||
cv.GOpaque.Prim: cv.gapi.CV_DRAW_PRIM,
|
||||
cv.GOpaque.Any: cv.gapi.CV_ANY
|
||||
}
|
||||
|
||||
type2str = {
|
||||
cv.gapi.CV_BOOL: 'cv.gapi.CV_BOOL' ,
|
||||
cv.gapi.CV_INT: 'cv.gapi.CV_INT' ,
|
||||
cv.gapi.CV_DOUBLE: 'cv.gapi.CV_DOUBLE' ,
|
||||
cv.gapi.CV_FLOAT: 'cv.gapi.CV_FLOAT' ,
|
||||
cv.gapi.CV_STRING: 'cv.gapi.CV_STRING' ,
|
||||
cv.gapi.CV_POINT: 'cv.gapi.CV_POINT' ,
|
||||
cv.gapi.CV_POINT2F: 'cv.gapi.CV_POINT2F' ,
|
||||
cv.gapi.CV_SIZE: 'cv.gapi.CV_SIZE',
|
||||
cv.gapi.CV_RECT: 'cv.gapi.CV_RECT',
|
||||
cv.gapi.CV_SCALAR: 'cv.gapi.CV_SCALAR',
|
||||
cv.gapi.CV_MAT: 'cv.gapi.CV_MAT',
|
||||
cv.gapi.CV_GMAT: 'cv.gapi.CV_GMAT',
|
||||
cv.gapi.CV_DRAW_PRIM: 'cv.gapi.CV_DRAW_PRIM'
|
||||
}
|
||||
|
||||
# NB: Second lvl decorator takes class to decorate
|
||||
def op_with_params(cls):
|
||||
if not in_types:
|
||||
raise Exception('{} operation should have at least one input!'.format(cls.__name__))
|
||||
|
||||
if not out_types:
|
||||
raise Exception('{} operation should have at least one output!'.format(cls.__name__))
|
||||
|
||||
for i, t in enumerate(out_types):
|
||||
if t not in [cv.GMat, cv.GScalar, *garray_types, *gopaque_types]:
|
||||
raise Exception('{} unsupported output type: {} in possition: {}'
|
||||
.format(cls.__name__, t.__name__, i))
|
||||
|
||||
def on(*args):
|
||||
if len(in_types) != len(args):
|
||||
raise Exception('Invalid number of input elements!\nExpected: {}, Actual: {}'
|
||||
.format(len(in_types), len(args)))
|
||||
|
||||
for i, (t, a) in enumerate(zip(in_types, args)):
|
||||
if t in garray_types:
|
||||
if not isinstance(a, cv.GArrayT):
|
||||
raise Exception("{} invalid type for argument {}.\nExpected: {}, Actual: {}"
|
||||
.format(cls.__name__, i, cv.GArrayT.__name__, type(a).__name__))
|
||||
|
||||
elif a.type() != garray_types[t]:
|
||||
raise Exception("{} invalid GArrayT type for argument {}.\nExpected: {}, Actual: {}"
|
||||
.format(cls.__name__, i, type2str[garray_types[t]], type2str[a.type()]))
|
||||
|
||||
elif t in gopaque_types:
|
||||
if not isinstance(a, cv.GOpaqueT):
|
||||
raise Exception("{} invalid type for argument {}.\nExpected: {}, Actual: {}"
|
||||
.format(cls.__name__, i, cv.GOpaqueT.__name__, type(a).__name__))
|
||||
|
||||
elif a.type() != gopaque_types[t]:
|
||||
raise Exception("{} invalid GOpaque type for argument {}.\nExpected: {}, Actual: {}"
|
||||
.format(cls.__name__, i, type2str[gopaque_types[t]], type2str[a.type()]))
|
||||
|
||||
else:
|
||||
if t != type(a):
|
||||
raise Exception('{} invalid input type for argument {}.\nExpected: {}, Actual: {}'
|
||||
.format(cls.__name__, i, t.__name__, type(a).__name__))
|
||||
|
||||
op = cv.gapi.__op(op_id, cls.outMeta, *args)
|
||||
|
||||
out_protos = []
|
||||
for i, out_type in enumerate(out_types):
|
||||
if out_type == cv.GMat:
|
||||
out_protos.append(op.getGMat())
|
||||
elif out_type == cv.GScalar:
|
||||
out_protos.append(op.getGScalar())
|
||||
elif out_type in gopaque_types:
|
||||
out_protos.append(op.getGOpaque(gopaque_types[out_type]))
|
||||
elif out_type in garray_types:
|
||||
out_protos.append(op.getGArray(garray_types[out_type]))
|
||||
else:
|
||||
raise Exception("""In {}: G-API operation can't produce the output with type: {} in position: {}"""
|
||||
.format(cls.__name__, out_type.__name__, i))
|
||||
|
||||
return tuple(out_protos) if len(out_protos) != 1 else out_protos[0]
|
||||
|
||||
# NB: Extend operation class
|
||||
cls.id = op_id
|
||||
cls.on = staticmethod(on)
|
||||
return cls
|
||||
|
||||
return op_with_params
|
||||
|
||||
|
||||
def kernel(op_cls):
|
||||
# NB: Second lvl decorator takes class to decorate
|
||||
def kernel_with_params(cls):
|
||||
# NB: Add new members to kernel class
|
||||
cls.id = op_cls.id
|
||||
cls.outMeta = op_cls.outMeta
|
||||
return cls
|
||||
|
||||
return kernel_with_params
|
||||
|
||||
|
||||
# FIXME: On the c++ side every class is placed in cv2 module.
|
||||
cv.gapi.wip.draw.Rect = cv.gapi_wip_draw_Rect
|
||||
cv.gapi.wip.draw.Text = cv.gapi_wip_draw_Text
|
||||
cv.gapi.wip.draw.Circle = cv.gapi_wip_draw_Circle
|
||||
cv.gapi.wip.draw.Line = cv.gapi_wip_draw_Line
|
||||
cv.gapi.wip.draw.Mosaic = cv.gapi_wip_draw_Mosaic
|
||||
cv.gapi.wip.draw.Image = cv.gapi_wip_draw_Image
|
||||
cv.gapi.wip.draw.Poly = cv.gapi_wip_draw_Poly
|
||||
|
||||
cv.gapi.streaming.queue_capacity = cv.gapi_streaming_queue_capacity
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,338 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_PYTHON_BRIDGE_HPP
|
||||
#define OPENCV_GAPI_PYTHON_BRIDGE_HPP
|
||||
|
||||
#include <opencv2/gapi.hpp>
|
||||
#include <opencv2/gapi/garg.hpp>
|
||||
#include <opencv2/gapi/gopaque.hpp>
|
||||
#include <opencv2/gapi/render/render_types.hpp> // Prim
|
||||
|
||||
#define ID(T, E) T
|
||||
#define ID_(T, E) ID(T, E),
|
||||
|
||||
#define WRAP_ARGS(T, E, G) \
|
||||
G(T, E)
|
||||
|
||||
#define SWITCH(type, LIST_G, HC) \
|
||||
switch(type) { \
|
||||
LIST_G(HC, HC) \
|
||||
default: \
|
||||
GAPI_Assert(false && "Unsupported type"); \
|
||||
}
|
||||
|
||||
using cv::gapi::wip::draw::Prim;
|
||||
|
||||
#define GARRAY_TYPE_LIST_G(G, G2) \
|
||||
WRAP_ARGS(bool , cv::gapi::ArgType::CV_BOOL, G) \
|
||||
WRAP_ARGS(int , cv::gapi::ArgType::CV_INT, G) \
|
||||
WRAP_ARGS(int64_t , cv::gapi::ArgType::CV_INT64, G) \
|
||||
WRAP_ARGS(double , cv::gapi::ArgType::CV_DOUBLE, G) \
|
||||
WRAP_ARGS(float , cv::gapi::ArgType::CV_FLOAT, G) \
|
||||
WRAP_ARGS(std::string , cv::gapi::ArgType::CV_STRING, G) \
|
||||
WRAP_ARGS(cv::Point , cv::gapi::ArgType::CV_POINT, G) \
|
||||
WRAP_ARGS(cv::Point2f , cv::gapi::ArgType::CV_POINT2F, G) \
|
||||
WRAP_ARGS(cv::Size , cv::gapi::ArgType::CV_SIZE, G) \
|
||||
WRAP_ARGS(cv::Rect , cv::gapi::ArgType::CV_RECT, G) \
|
||||
WRAP_ARGS(cv::Scalar , cv::gapi::ArgType::CV_SCALAR, G) \
|
||||
WRAP_ARGS(cv::Mat , cv::gapi::ArgType::CV_MAT, G) \
|
||||
WRAP_ARGS(Prim , cv::gapi::ArgType::CV_DRAW_PRIM, G) \
|
||||
WRAP_ARGS(cv::GArg , cv::gapi::ArgType::CV_ANY, G) \
|
||||
WRAP_ARGS(cv::GMat , cv::gapi::ArgType::CV_GMAT, G2) \
|
||||
|
||||
#define GOPAQUE_TYPE_LIST_G(G, G2) \
|
||||
WRAP_ARGS(bool , cv::gapi::ArgType::CV_BOOL, G) \
|
||||
WRAP_ARGS(int , cv::gapi::ArgType::CV_INT, G) \
|
||||
WRAP_ARGS(int64_t , cv::gapi::ArgType::CV_INT64, G) \
|
||||
WRAP_ARGS(double , cv::gapi::ArgType::CV_DOUBLE, G) \
|
||||
WRAP_ARGS(float , cv::gapi::ArgType::CV_FLOAT, G) \
|
||||
WRAP_ARGS(std::string , cv::gapi::ArgType::CV_STRING, G) \
|
||||
WRAP_ARGS(cv::Point , cv::gapi::ArgType::CV_POINT, G) \
|
||||
WRAP_ARGS(cv::Point2f , cv::gapi::ArgType::CV_POINT2F, G) \
|
||||
WRAP_ARGS(cv::Size , cv::gapi::ArgType::CV_SIZE, G) \
|
||||
WRAP_ARGS(cv::GArg , cv::gapi::ArgType::CV_ANY, G) \
|
||||
WRAP_ARGS(cv::Rect , cv::gapi::ArgType::CV_RECT, G2) \
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
|
||||
// NB: cv.gapi.CV_BOOL in python
|
||||
enum ArgType {
|
||||
CV_BOOL,
|
||||
CV_INT,
|
||||
CV_INT64,
|
||||
CV_DOUBLE,
|
||||
CV_FLOAT,
|
||||
CV_STRING,
|
||||
CV_POINT,
|
||||
CV_POINT2F,
|
||||
CV_SIZE,
|
||||
CV_RECT,
|
||||
CV_SCALAR,
|
||||
CV_MAT,
|
||||
CV_GMAT,
|
||||
CV_DRAW_PRIM,
|
||||
CV_ANY,
|
||||
};
|
||||
|
||||
GAPI_EXPORTS_W inline cv::GInferOutputs infer(const String& name, const cv::GInferInputs& inputs)
|
||||
{
|
||||
return infer<Generic>(name, inputs);
|
||||
}
|
||||
|
||||
GAPI_EXPORTS_W inline GInferOutputs infer(const std::string& name,
|
||||
const cv::GOpaque<cv::Rect>& roi,
|
||||
const GInferInputs& inputs)
|
||||
{
|
||||
return infer<Generic>(name, roi, inputs);
|
||||
}
|
||||
|
||||
GAPI_EXPORTS_W inline GInferListOutputs infer(const std::string& name,
|
||||
const cv::GArray<cv::Rect>& rois,
|
||||
const GInferInputs& inputs)
|
||||
{
|
||||
return infer<Generic>(name, rois, inputs);
|
||||
}
|
||||
|
||||
GAPI_EXPORTS_W inline GInferListOutputs infer2(const std::string& name,
|
||||
const cv::GMat in,
|
||||
const GInferListInputs& inputs)
|
||||
{
|
||||
return infer2<Generic>(name, in, inputs);
|
||||
}
|
||||
|
||||
} // namespace gapi
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <template <typename> class Wrapper, typename T>
|
||||
struct WrapType { using type = Wrapper<T>; };
|
||||
|
||||
template <template <typename> class T, typename... Types>
|
||||
using MakeVariantType = cv::util::variant<typename WrapType<T, Types>::type...>;
|
||||
|
||||
template<typename T> struct ArgTypeTraits;
|
||||
|
||||
#define DEFINE_TYPE_TRAITS(T, E) \
|
||||
template <> \
|
||||
struct ArgTypeTraits<T> { \
|
||||
static constexpr const cv::gapi::ArgType type = E; \
|
||||
}; \
|
||||
|
||||
GARRAY_TYPE_LIST_G(DEFINE_TYPE_TRAITS, DEFINE_TYPE_TRAITS)
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class GAPI_EXPORTS_W_SIMPLE GOpaqueT
|
||||
{
|
||||
public:
|
||||
GOpaqueT() = default;
|
||||
using Storage = cv::detail::MakeVariantType<cv::GOpaque, GOPAQUE_TYPE_LIST_G(ID_, ID)>;
|
||||
|
||||
template<typename T>
|
||||
GOpaqueT(cv::GOpaque<T> arg) : m_type(cv::detail::ArgTypeTraits<T>::type), m_arg(arg) { };
|
||||
|
||||
GAPI_WRAP GOpaqueT(gapi::ArgType type) : m_type(type)
|
||||
{
|
||||
|
||||
#define HC(T, K) case K: \
|
||||
m_arg = cv::GOpaque<T>(); \
|
||||
break;
|
||||
|
||||
SWITCH(type, GOPAQUE_TYPE_LIST_G, HC)
|
||||
#undef HC
|
||||
}
|
||||
|
||||
cv::detail::GOpaqueU strip() {
|
||||
#define HC(T, K) case Storage:: index_of<cv::GOpaque<T>>(): \
|
||||
return cv::util::get<cv::GOpaque<T>>(m_arg).strip(); \
|
||||
|
||||
SWITCH(m_arg.index(), GOPAQUE_TYPE_LIST_G, HC)
|
||||
#undef HC
|
||||
|
||||
GAPI_Assert(false);
|
||||
}
|
||||
|
||||
GAPI_WRAP gapi::ArgType type() { return m_type; }
|
||||
const Storage& arg() const { return m_arg; }
|
||||
|
||||
private:
|
||||
gapi::ArgType m_type;
|
||||
Storage m_arg;
|
||||
};
|
||||
|
||||
class GAPI_EXPORTS_W_SIMPLE GArrayT
|
||||
{
|
||||
public:
|
||||
GArrayT() = default;
|
||||
using Storage = cv::detail::MakeVariantType<cv::GArray, GARRAY_TYPE_LIST_G(ID_, ID)>;
|
||||
|
||||
template<typename T>
|
||||
GArrayT(cv::GArray<T> arg) : m_type(cv::detail::ArgTypeTraits<T>::type), m_arg(arg) { };
|
||||
|
||||
GAPI_WRAP GArrayT(gapi::ArgType type) : m_type(type)
|
||||
{
|
||||
|
||||
#define HC(T, K) case K: \
|
||||
m_arg = cv::GArray<T>(); \
|
||||
break;
|
||||
|
||||
SWITCH(type, GARRAY_TYPE_LIST_G, HC)
|
||||
#undef HC
|
||||
}
|
||||
|
||||
cv::detail::GArrayU strip() {
|
||||
#define HC(T, K) case Storage:: index_of<cv::GArray<T>>(): \
|
||||
return cv::util::get<cv::GArray<T>>(m_arg).strip(); \
|
||||
|
||||
SWITCH(m_arg.index(), GARRAY_TYPE_LIST_G, HC)
|
||||
#undef HC
|
||||
|
||||
GAPI_Assert(false);
|
||||
}
|
||||
|
||||
GAPI_WRAP gapi::ArgType type() { return m_type; }
|
||||
const Storage& arg() const { return m_arg; }
|
||||
|
||||
private:
|
||||
gapi::ArgType m_type;
|
||||
Storage m_arg;
|
||||
};
|
||||
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
|
||||
class GAPI_EXPORTS_W_SIMPLE GOutputs
|
||||
{
|
||||
public:
|
||||
GOutputs() = default;
|
||||
GOutputs(const std::string& id, cv::GKernel::M outMeta, cv::GArgs &&ins);
|
||||
|
||||
GAPI_WRAP cv::GMat getGMat();
|
||||
GAPI_WRAP cv::GScalar getGScalar();
|
||||
GAPI_WRAP cv::GArrayT getGArray(cv::gapi::ArgType type);
|
||||
GAPI_WRAP cv::GOpaqueT getGOpaque(cv::gapi::ArgType type);
|
||||
|
||||
private:
|
||||
class Priv;
|
||||
std::shared_ptr<Priv> m_priv;
|
||||
};
|
||||
|
||||
GOutputs op(const std::string& id, cv::GKernel::M outMeta, cv::GArgs&& args);
|
||||
|
||||
template <typename... T>
|
||||
GOutputs op(const std::string& id, cv::GKernel::M outMeta, T&&... args)
|
||||
{
|
||||
return op(id, outMeta, cv::GArgs{cv::GArg(std::forward<T>(args))... });
|
||||
}
|
||||
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
cv::gapi::wip::GOutputs cv::gapi::wip::op(const std::string& id,
|
||||
cv::GKernel::M outMeta,
|
||||
cv::GArgs&& args)
|
||||
{
|
||||
cv::gapi::wip::GOutputs outputs{id, outMeta, std::move(args)};
|
||||
return outputs;
|
||||
}
|
||||
|
||||
class cv::gapi::wip::GOutputs::Priv
|
||||
{
|
||||
public:
|
||||
Priv(const std::string& id, cv::GKernel::M outMeta, cv::GArgs &&ins);
|
||||
|
||||
cv::GMat getGMat();
|
||||
cv::GScalar getGScalar();
|
||||
cv::GArrayT getGArray(cv::gapi::ArgType);
|
||||
cv::GOpaqueT getGOpaque(cv::gapi::ArgType);
|
||||
|
||||
private:
|
||||
int output = 0;
|
||||
std::unique_ptr<cv::GCall> m_call;
|
||||
};
|
||||
|
||||
cv::gapi::wip::GOutputs::Priv::Priv(const std::string& id, cv::GKernel::M outMeta, cv::GArgs &&args)
|
||||
{
|
||||
cv::GKinds kinds;
|
||||
kinds.reserve(args.size());
|
||||
std::transform(args.begin(), args.end(), std::back_inserter(kinds),
|
||||
[](const cv::GArg& arg) { return arg.opaque_kind; });
|
||||
|
||||
m_call.reset(new cv::GCall{cv::GKernel{id, {}, outMeta, {}, std::move(kinds), {}}});
|
||||
m_call->setArgs(std::move(args));
|
||||
}
|
||||
|
||||
cv::GMat cv::gapi::wip::GOutputs::Priv::getGMat()
|
||||
{
|
||||
m_call->kernel().outShapes.push_back(cv::GShape::GMAT);
|
||||
// ...so _empty_ constructor is passed here.
|
||||
m_call->kernel().outCtors.emplace_back(cv::util::monostate{});
|
||||
return m_call->yield(output++);
|
||||
}
|
||||
|
||||
cv::GScalar cv::gapi::wip::GOutputs::Priv::getGScalar()
|
||||
{
|
||||
m_call->kernel().outShapes.push_back(cv::GShape::GSCALAR);
|
||||
// ...so _empty_ constructor is passed here.
|
||||
m_call->kernel().outCtors.emplace_back(cv::util::monostate{});
|
||||
return m_call->yieldScalar(output++);
|
||||
}
|
||||
|
||||
cv::GArrayT cv::gapi::wip::GOutputs::Priv::getGArray(cv::gapi::ArgType type)
|
||||
{
|
||||
m_call->kernel().outShapes.push_back(cv::GShape::GARRAY);
|
||||
#define HC(T, K) \
|
||||
case K: \
|
||||
m_call->kernel().outCtors.emplace_back(cv::detail::GObtainCtor<cv::GArray<T>>::get()); \
|
||||
return cv::GArrayT(m_call->yieldArray<T>(output++)); \
|
||||
|
||||
SWITCH(type, GARRAY_TYPE_LIST_G, HC)
|
||||
#undef HC
|
||||
}
|
||||
|
||||
cv::GOpaqueT cv::gapi::wip::GOutputs::Priv::getGOpaque(cv::gapi::ArgType type)
|
||||
{
|
||||
m_call->kernel().outShapes.push_back(cv::GShape::GOPAQUE);
|
||||
#define HC(T, K) \
|
||||
case K: \
|
||||
m_call->kernel().outCtors.emplace_back(cv::detail::GObtainCtor<cv::GOpaque<T>>::get()); \
|
||||
return cv::GOpaqueT(m_call->yieldOpaque<T>(output++)); \
|
||||
|
||||
SWITCH(type, GOPAQUE_TYPE_LIST_G, HC)
|
||||
#undef HC
|
||||
}
|
||||
|
||||
cv::gapi::wip::GOutputs::GOutputs(const std::string& id,
|
||||
cv::GKernel::M outMeta,
|
||||
cv::GArgs &&ins) :
|
||||
m_priv(new cv::gapi::wip::GOutputs::Priv(id, outMeta, std::move(ins)))
|
||||
{
|
||||
}
|
||||
|
||||
cv::GMat cv::gapi::wip::GOutputs::getGMat()
|
||||
{
|
||||
return m_priv->getGMat();
|
||||
}
|
||||
|
||||
cv::GScalar cv::gapi::wip::GOutputs::getGScalar()
|
||||
{
|
||||
return m_priv->getGScalar();
|
||||
}
|
||||
|
||||
cv::GArrayT cv::gapi::wip::GOutputs::getGArray(cv::gapi::ArgType type)
|
||||
{
|
||||
return m_priv->getGArray(type);
|
||||
}
|
||||
|
||||
cv::GOpaqueT cv::gapi::wip::GOutputs::getGOpaque(cv::gapi::ArgType type)
|
||||
{
|
||||
return m_priv->getGOpaque(type);
|
||||
}
|
||||
|
||||
#endif // OPENCV_GAPI_PYTHON_BRIDGE_HPP
|
||||
|
|
@ -0,0 +1,458 @@
|
|||
import argparse
|
||||
import time
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
|
||||
# ------------------------Service operations------------------------
|
||||
def weight_path(model_path):
|
||||
""" Get path of weights based on path to IR
|
||||
|
||||
Params:
|
||||
model_path: the string contains path to IR file
|
||||
|
||||
Return:
|
||||
Path to weights file
|
||||
"""
|
||||
assert model_path.endswith('.xml'), "Wrong topology path was provided"
|
||||
return model_path[:-3] + 'bin'
|
||||
|
||||
|
||||
def build_argparser():
|
||||
""" Parse arguments from command line
|
||||
|
||||
Return:
|
||||
Pack of arguments from command line
|
||||
"""
|
||||
parser = argparse.ArgumentParser(description='This is an OpenCV-based version of Gaze Estimation example')
|
||||
|
||||
parser.add_argument('--input',
|
||||
help='Path to the input video file')
|
||||
parser.add_argument('--out',
|
||||
help='Path to the output video file')
|
||||
parser.add_argument('--facem',
|
||||
default='face-detection-retail-0005.xml',
|
||||
help='Path to OpenVINO face detection model (.xml)')
|
||||
parser.add_argument('--faced',
|
||||
default='CPU',
|
||||
help='Target device for the face detection' +
|
||||
'(e.g. CPU, GPU, VPU, ...)')
|
||||
parser.add_argument('--headm',
|
||||
default='head-pose-estimation-adas-0001.xml',
|
||||
help='Path to OpenVINO head pose estimation model (.xml)')
|
||||
parser.add_argument('--headd',
|
||||
default='CPU',
|
||||
help='Target device for the head pose estimation inference ' +
|
||||
'(e.g. CPU, GPU, VPU, ...)')
|
||||
parser.add_argument('--landm',
|
||||
default='facial-landmarks-35-adas-0002.xml',
|
||||
help='Path to OpenVINO landmarks detector model (.xml)')
|
||||
parser.add_argument('--landd',
|
||||
default='CPU',
|
||||
help='Target device for the landmarks detector (e.g. CPU, GPU, VPU, ...)')
|
||||
parser.add_argument('--gazem',
|
||||
default='gaze-estimation-adas-0002.xml',
|
||||
help='Path to OpenVINO gaze vector estimaiton model (.xml)')
|
||||
parser.add_argument('--gazed',
|
||||
default='CPU',
|
||||
help='Target device for the gaze vector estimation inference ' +
|
||||
'(e.g. CPU, GPU, VPU, ...)')
|
||||
parser.add_argument('--eyem',
|
||||
default='open-closed-eye-0001.xml',
|
||||
help='Path to OpenVINO open closed eye model (.xml)')
|
||||
parser.add_argument('--eyed',
|
||||
default='CPU',
|
||||
help='Target device for the eyes state inference (e.g. CPU, GPU, VPU, ...)')
|
||||
return parser
|
||||
|
||||
|
||||
# ------------------------Support functions for custom kernels------------------------
|
||||
def intersection(surface, rect):
|
||||
""" Remove zone of out of bound from ROI
|
||||
|
||||
Params:
|
||||
surface: image bounds is rect representation (top left coordinates and width and height)
|
||||
rect: region of interest is also has rect representation
|
||||
|
||||
Return:
|
||||
Modified ROI with correct bounds
|
||||
"""
|
||||
l_x = max(surface[0], rect[0])
|
||||
l_y = max(surface[1], rect[1])
|
||||
width = min(surface[0] + surface[2], rect[0] + rect[2]) - l_x
|
||||
height = min(surface[1] + surface[3], rect[1] + rect[3]) - l_y
|
||||
if width < 0 or height < 0:
|
||||
return (0, 0, 0, 0)
|
||||
return (l_x, l_y, width, height)
|
||||
|
||||
|
||||
def process_landmarks(r_x, r_y, r_w, r_h, landmarks):
|
||||
""" Create points from result of inference of facial-landmarks network and size of input image
|
||||
|
||||
Params:
|
||||
r_x: x coordinate of top left corner of input image
|
||||
r_y: y coordinate of top left corner of input image
|
||||
r_w: width of input image
|
||||
r_h: height of input image
|
||||
landmarks: result of inference of facial-landmarks network
|
||||
|
||||
Return:
|
||||
Array of landmarks points for one face
|
||||
"""
|
||||
lmrks = landmarks[0]
|
||||
raw_x = lmrks[::2] * r_w + r_x
|
||||
raw_y = lmrks[1::2] * r_h + r_y
|
||||
return np.array([[int(x), int(y)] for x, y in zip(raw_x, raw_y)])
|
||||
|
||||
|
||||
def eye_box(p_1, p_2, scale=1.8):
|
||||
""" Get bounding box of eye
|
||||
|
||||
Params:
|
||||
p_1: point of left edge of eye
|
||||
p_2: point of right edge of eye
|
||||
scale: change size of box with this value
|
||||
|
||||
Return:
|
||||
Bounding box of eye and its midpoint
|
||||
"""
|
||||
|
||||
size = np.linalg.norm(p_1 - p_2)
|
||||
midpoint = (p_1 + p_2) / 2
|
||||
width = scale * size
|
||||
height = width
|
||||
p_x = midpoint[0] - (width / 2)
|
||||
p_y = midpoint[1] - (height / 2)
|
||||
return (int(p_x), int(p_y), int(width), int(height)), list(map(int, midpoint))
|
||||
|
||||
|
||||
# ------------------------Custom graph operations------------------------
|
||||
@cv.gapi.op('custom.GProcessPoses',
|
||||
in_types=[cv.GArray.GMat, cv.GArray.GMat, cv.GArray.GMat],
|
||||
out_types=[cv.GArray.GMat])
|
||||
class GProcessPoses:
|
||||
@staticmethod
|
||||
def outMeta(arr_desc0, arr_desc1, arr_desc2):
|
||||
return cv.empty_array_desc()
|
||||
|
||||
|
||||
@cv.gapi.op('custom.GParseEyes',
|
||||
in_types=[cv.GArray.GMat, cv.GArray.Rect, cv.GOpaque.Size],
|
||||
out_types=[cv.GArray.Rect, cv.GArray.Rect, cv.GArray.Point, cv.GArray.Point])
|
||||
class GParseEyes:
|
||||
@staticmethod
|
||||
def outMeta(arr_desc0, arr_desc1, arr_desc2):
|
||||
return cv.empty_array_desc(), cv.empty_array_desc(), \
|
||||
cv.empty_array_desc(), cv.empty_array_desc()
|
||||
|
||||
|
||||
@cv.gapi.op('custom.GGetStates',
|
||||
in_types=[cv.GArray.GMat, cv.GArray.GMat],
|
||||
out_types=[cv.GArray.Int, cv.GArray.Int])
|
||||
class GGetStates:
|
||||
@staticmethod
|
||||
def outMeta(arr_desc0, arr_desc1):
|
||||
return cv.empty_array_desc(), cv.empty_array_desc()
|
||||
|
||||
|
||||
# ------------------------Custom kernels------------------------
|
||||
@cv.gapi.kernel(GProcessPoses)
|
||||
class GProcessPosesImpl:
|
||||
""" Custom kernel. Processed poses of heads
|
||||
"""
|
||||
@staticmethod
|
||||
def run(in_ys, in_ps, in_rs):
|
||||
""" Сustom kernel executable code
|
||||
|
||||
Params:
|
||||
in_ys: yaw angle of head
|
||||
in_ps: pitch angle of head
|
||||
in_rs: roll angle of head
|
||||
|
||||
Return:
|
||||
Arrays with heads poses
|
||||
"""
|
||||
return [np.array([ys[0], ps[0], rs[0]]).T for ys, ps, rs in zip(in_ys, in_ps, in_rs)]
|
||||
|
||||
|
||||
@cv.gapi.kernel(GParseEyes)
|
||||
class GParseEyesImpl:
|
||||
""" Custom kernel. Get information about eyes
|
||||
"""
|
||||
@staticmethod
|
||||
def run(in_landm_per_face, in_face_rcs, frame_size):
|
||||
""" Сustom kernel executable code
|
||||
|
||||
Params:
|
||||
in_landm_per_face: landmarks from inference of facial-landmarks network for each face
|
||||
in_face_rcs: bounding boxes for each face
|
||||
frame_size: size of input image
|
||||
|
||||
Return:
|
||||
Arrays of ROI for left and right eyes, array of midpoints and
|
||||
array of landmarks points
|
||||
"""
|
||||
left_eyes = []
|
||||
right_eyes = []
|
||||
midpoints = []
|
||||
lmarks = []
|
||||
surface = (0, 0, *frame_size)
|
||||
for landm_face, rect in zip(in_landm_per_face, in_face_rcs):
|
||||
points = process_landmarks(*rect, landm_face)
|
||||
lmarks.extend(points)
|
||||
|
||||
rect, midpoint_l = eye_box(points[0], points[1])
|
||||
left_eyes.append(intersection(surface, rect))
|
||||
|
||||
rect, midpoint_r = eye_box(points[2], points[3])
|
||||
right_eyes.append(intersection(surface, rect))
|
||||
|
||||
midpoints.append(midpoint_l)
|
||||
midpoints.append(midpoint_r)
|
||||
return left_eyes, right_eyes, midpoints, lmarks
|
||||
|
||||
|
||||
@cv.gapi.kernel(GGetStates)
|
||||
class GGetStatesImpl:
|
||||
""" Custom kernel. Get state of eye - open or closed
|
||||
"""
|
||||
@staticmethod
|
||||
def run(eyesl, eyesr):
|
||||
""" Сustom kernel executable code
|
||||
|
||||
Params:
|
||||
eyesl: result of inference of open-closed-eye network for left eye
|
||||
eyesr: result of inference of open-closed-eye network for right eye
|
||||
|
||||
Return:
|
||||
States of left eyes and states of right eyes
|
||||
"""
|
||||
out_l_st = [int(st) for eye_l in eyesl for st in (eye_l[:, 0] < eye_l[:, 1]).ravel()]
|
||||
out_r_st = [int(st) for eye_r in eyesr for st in (eye_r[:, 0] < eye_r[:, 1]).ravel()]
|
||||
return out_l_st, out_r_st
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ARGUMENTS = build_argparser().parse_args()
|
||||
|
||||
# ------------------------Demo's graph------------------------
|
||||
g_in = cv.GMat()
|
||||
|
||||
# Detect faces
|
||||
face_inputs = cv.GInferInputs()
|
||||
face_inputs.setInput('data', g_in)
|
||||
face_outputs = cv.gapi.infer('face-detection', face_inputs)
|
||||
faces = face_outputs.at('detection_out')
|
||||
|
||||
# Parse faces
|
||||
sz = cv.gapi.streaming.size(g_in)
|
||||
faces_rc = cv.gapi.parseSSD(faces, sz, 0.5, False, False)
|
||||
|
||||
# Detect poses
|
||||
head_inputs = cv.GInferInputs()
|
||||
head_inputs.setInput('data', g_in)
|
||||
face_outputs = cv.gapi.infer('head-pose', faces_rc, head_inputs)
|
||||
angles_y = face_outputs.at('angle_y_fc')
|
||||
angles_p = face_outputs.at('angle_p_fc')
|
||||
angles_r = face_outputs.at('angle_r_fc')
|
||||
|
||||
# Parse poses
|
||||
heads_pos = GProcessPoses.on(angles_y, angles_p, angles_r)
|
||||
|
||||
# Detect landmarks
|
||||
landmark_inputs = cv.GInferInputs()
|
||||
landmark_inputs.setInput('data', g_in)
|
||||
landmark_outputs = cv.gapi.infer('facial-landmarks', faces_rc,
|
||||
landmark_inputs)
|
||||
landmark = landmark_outputs.at('align_fc3')
|
||||
|
||||
# Parse landmarks
|
||||
left_eyes, right_eyes, mids, lmarks = GParseEyes.on(landmark, faces_rc, sz)
|
||||
|
||||
# Detect eyes
|
||||
eyes_inputs = cv.GInferInputs()
|
||||
eyes_inputs.setInput('input.1', g_in)
|
||||
eyesl_outputs = cv.gapi.infer('open-closed-eye', left_eyes, eyes_inputs)
|
||||
eyesr_outputs = cv.gapi.infer('open-closed-eye', right_eyes, eyes_inputs)
|
||||
eyesl = eyesl_outputs.at('19')
|
||||
eyesr = eyesr_outputs.at('19')
|
||||
|
||||
# Process eyes states
|
||||
l_eye_st, r_eye_st = GGetStates.on(eyesl, eyesr)
|
||||
|
||||
# Gaze estimation
|
||||
gaze_inputs = cv.GInferListInputs()
|
||||
gaze_inputs.setInput('left_eye_image', left_eyes)
|
||||
gaze_inputs.setInput('right_eye_image', right_eyes)
|
||||
gaze_inputs.setInput('head_pose_angles', heads_pos)
|
||||
gaze_outputs = cv.gapi.infer2('gaze-estimation', g_in, gaze_inputs)
|
||||
gaze_vectors = gaze_outputs.at('gaze_vector')
|
||||
|
||||
out = cv.gapi.copy(g_in)
|
||||
# ------------------------End of graph------------------------
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(out,
|
||||
faces_rc,
|
||||
left_eyes,
|
||||
right_eyes,
|
||||
gaze_vectors,
|
||||
angles_y,
|
||||
angles_p,
|
||||
angles_r,
|
||||
l_eye_st,
|
||||
r_eye_st,
|
||||
mids,
|
||||
lmarks))
|
||||
|
||||
# Networks
|
||||
face_net = cv.gapi.ie.params('face-detection', ARGUMENTS.facem,
|
||||
weight_path(ARGUMENTS.facem), ARGUMENTS.faced)
|
||||
head_pose_net = cv.gapi.ie.params('head-pose', ARGUMENTS.headm,
|
||||
weight_path(ARGUMENTS.headm), ARGUMENTS.headd)
|
||||
landmarks_net = cv.gapi.ie.params('facial-landmarks', ARGUMENTS.landm,
|
||||
weight_path(ARGUMENTS.landm), ARGUMENTS.landd)
|
||||
gaze_net = cv.gapi.ie.params('gaze-estimation', ARGUMENTS.gazem,
|
||||
weight_path(ARGUMENTS.gazem), ARGUMENTS.gazed)
|
||||
eye_net = cv.gapi.ie.params('open-closed-eye', ARGUMENTS.eyem,
|
||||
weight_path(ARGUMENTS.eyem), ARGUMENTS.eyed)
|
||||
|
||||
nets = cv.gapi.networks(face_net, head_pose_net, landmarks_net, gaze_net, eye_net)
|
||||
|
||||
# Kernels pack
|
||||
kernels = cv.gapi.kernels(GParseEyesImpl, GProcessPosesImpl, GGetStatesImpl)
|
||||
|
||||
# ------------------------Execution part------------------------
|
||||
ccomp = comp.compileStreaming(args=cv.gapi.compile_args(kernels, nets))
|
||||
source = cv.gapi.wip.make_capture_src(ARGUMENTS.input)
|
||||
ccomp.setSource(cv.gin(source))
|
||||
ccomp.start()
|
||||
|
||||
frames = 0
|
||||
fps = 0
|
||||
print('Processing')
|
||||
START_TIME = time.time()
|
||||
|
||||
while True:
|
||||
start_time_cycle = time.time()
|
||||
has_frame, (oimg,
|
||||
outr,
|
||||
l_eyes,
|
||||
r_eyes,
|
||||
outg,
|
||||
out_y,
|
||||
out_p,
|
||||
out_r,
|
||||
out_st_l,
|
||||
out_st_r,
|
||||
out_mids,
|
||||
outl) = ccomp.pull()
|
||||
|
||||
if not has_frame:
|
||||
break
|
||||
|
||||
# Draw
|
||||
GREEN = (0, 255, 0)
|
||||
RED = (0, 0, 255)
|
||||
WHITE = (255, 255, 255)
|
||||
BLUE = (255, 0, 0)
|
||||
PINK = (255, 0, 255)
|
||||
YELLOW = (0, 255, 255)
|
||||
|
||||
M_PI_180 = np.pi / 180
|
||||
M_PI_2 = np.pi / 2
|
||||
M_PI = np.pi
|
||||
|
||||
FACES_SIZE = len(outr)
|
||||
|
||||
for i, out_rect in enumerate(outr):
|
||||
# Face box
|
||||
cv.rectangle(oimg, out_rect, WHITE, 1)
|
||||
rx, ry, rwidth, rheight = out_rect
|
||||
|
||||
# Landmarks
|
||||
lm_radius = int(0.01 * rwidth + 1)
|
||||
lmsize = int(len(outl) / FACES_SIZE)
|
||||
for j in range(lmsize):
|
||||
cv.circle(oimg, outl[j + i * lmsize], lm_radius, YELLOW, -1)
|
||||
|
||||
# Headposes
|
||||
yaw = out_y[i]
|
||||
pitch = out_p[i]
|
||||
roll = out_r[i]
|
||||
sin_y = np.sin(yaw[:] * M_PI_180)
|
||||
sin_p = np.sin(pitch[:] * M_PI_180)
|
||||
sin_r = np.sin(roll[:] * M_PI_180)
|
||||
|
||||
cos_y = np.cos(yaw[:] * M_PI_180)
|
||||
cos_p = np.cos(pitch[:] * M_PI_180)
|
||||
cos_r = np.cos(roll[:] * M_PI_180)
|
||||
|
||||
axis_length = 0.4 * rwidth
|
||||
x_center = int(rx + rwidth / 2)
|
||||
y_center = int(ry + rheight / 2)
|
||||
|
||||
# center to right
|
||||
cv.line(oimg, [x_center, y_center],
|
||||
[int(x_center + axis_length * (cos_r * cos_y + sin_y * sin_p * sin_r)),
|
||||
int(y_center + axis_length * cos_p * sin_r)],
|
||||
RED, 2)
|
||||
|
||||
# center to top
|
||||
cv.line(oimg, [x_center, y_center],
|
||||
[int(x_center + axis_length * (cos_r * sin_y * sin_p + cos_y * sin_r)),
|
||||
int(y_center - axis_length * cos_p * cos_r)],
|
||||
GREEN, 2)
|
||||
|
||||
# center to forward
|
||||
cv.line(oimg, [x_center, y_center],
|
||||
[int(x_center + axis_length * sin_y * cos_p),
|
||||
int(y_center + axis_length * sin_p)],
|
||||
PINK, 2)
|
||||
|
||||
scale_box = 0.002 * rwidth
|
||||
cv.putText(oimg, "head pose: (y=%0.0f, p=%0.0f, r=%0.0f)" %
|
||||
(np.round(yaw), np.round(pitch), np.round(roll)),
|
||||
[int(rx), int(ry + rheight + 5 * rwidth / 100)],
|
||||
cv.FONT_HERSHEY_PLAIN, scale_box * 2, WHITE, 1)
|
||||
|
||||
# Eyes boxes
|
||||
color_l = GREEN if out_st_l[i] else RED
|
||||
cv.rectangle(oimg, l_eyes[i], color_l, 1)
|
||||
color_r = GREEN if out_st_r[i] else RED
|
||||
cv.rectangle(oimg, r_eyes[i], color_r, 1)
|
||||
|
||||
# Gaze vectors
|
||||
norm_gazes = np.linalg.norm(outg[i][0])
|
||||
gaze_vector = outg[i][0] / norm_gazes
|
||||
|
||||
arrow_length = 0.4 * rwidth
|
||||
gaze_arrow = [arrow_length * gaze_vector[0], -arrow_length * gaze_vector[1]]
|
||||
left_arrow = [int(a+b) for a, b in zip(out_mids[0 + i * 2], gaze_arrow)]
|
||||
right_arrow = [int(a+b) for a, b in zip(out_mids[1 + i * 2], gaze_arrow)]
|
||||
if out_st_l[i]:
|
||||
cv.arrowedLine(oimg, out_mids[0 + i * 2], left_arrow, BLUE, 2)
|
||||
if out_st_r[i]:
|
||||
cv.arrowedLine(oimg, out_mids[1 + i * 2], right_arrow, BLUE, 2)
|
||||
|
||||
v0, v1, v2 = outg[i][0]
|
||||
|
||||
gaze_angles = [180 / M_PI * (M_PI_2 + np.arctan2(v2, v0)),
|
||||
180 / M_PI * (M_PI_2 - np.arccos(v1 / norm_gazes))]
|
||||
cv.putText(oimg, "gaze angles: (h=%0.0f, v=%0.0f)" %
|
||||
(np.round(gaze_angles[0]), np.round(gaze_angles[1])),
|
||||
[int(rx), int(ry + rheight + 12 * rwidth / 100)],
|
||||
cv.FONT_HERSHEY_PLAIN, scale_box * 2, WHITE, 1)
|
||||
|
||||
# Add FPS value to frame
|
||||
cv.putText(oimg, "FPS: %0i" % (fps), [int(20), int(40)],
|
||||
cv.FONT_HERSHEY_PLAIN, 2, RED, 2)
|
||||
|
||||
# Show result
|
||||
cv.imshow('Gaze Estimation', oimg)
|
||||
cv.waitKey(1)
|
||||
|
||||
fps = int(1. / (time.time() - start_time_cycle))
|
||||
frames += 1
|
||||
EXECUTION_TIME = time.time() - START_TIME
|
||||
print('Execution successful')
|
||||
print('Mean FPS is ', int(frames / EXECUTION_TIME))
|
||||
|
|
@ -3,30 +3,81 @@
|
|||
|
||||
namespace cv
|
||||
{
|
||||
struct GAPI_EXPORTS_W_SIMPLE GCompileArg { };
|
||||
struct GAPI_EXPORTS_W_SIMPLE GCompileArg
|
||||
{
|
||||
GAPI_WRAP GCompileArg(gapi::GKernelPackage arg);
|
||||
GAPI_WRAP GCompileArg(gapi::GNetPackage arg);
|
||||
GAPI_WRAP GCompileArg(gapi::streaming::queue_capacity arg);
|
||||
};
|
||||
|
||||
GAPI_EXPORTS_W GCompileArgs compile_args(gapi::GKernelPackage pkg);
|
||||
GAPI_EXPORTS_W GCompileArgs compile_args(gapi::GNetPackage pkg);
|
||||
class GAPI_EXPORTS_W_SIMPLE GInferInputs
|
||||
{
|
||||
public:
|
||||
GAPI_WRAP GInferInputs();
|
||||
GAPI_WRAP GInferInputs& setInput(const std::string& name, const cv::GMat& value);
|
||||
GAPI_WRAP GInferInputs& setInput(const std::string& name, const cv::GFrame& value);
|
||||
};
|
||||
|
||||
// NB: This classes doesn't exist in *.so
|
||||
// HACK: Mark them as a class to force python wrapper generate code for this entities
|
||||
class GAPI_EXPORTS_W_SIMPLE GProtoArg { };
|
||||
class GAPI_EXPORTS_W_SIMPLE GProtoInputArgs { };
|
||||
class GAPI_EXPORTS_W_SIMPLE GProtoOutputArgs { };
|
||||
class GAPI_EXPORTS_W_SIMPLE GRunArg { };
|
||||
class GAPI_EXPORTS_W_SIMPLE GMetaArg { };
|
||||
class GAPI_EXPORTS_W_SIMPLE GInferListInputs
|
||||
{
|
||||
public:
|
||||
GAPI_WRAP GInferListInputs();
|
||||
GAPI_WRAP GInferListInputs setInput(const std::string& name, const cv::GArray<cv::GMat>& value);
|
||||
GAPI_WRAP GInferListInputs setInput(const std::string& name, const cv::GArray<cv::Rect>& value);
|
||||
};
|
||||
|
||||
class GAPI_EXPORTS_W_SIMPLE GArrayP2f { };
|
||||
class GAPI_EXPORTS_W_SIMPLE GInferOutputs
|
||||
{
|
||||
public:
|
||||
GAPI_WRAP GInferOutputs();
|
||||
GAPI_WRAP cv::GMat at(const std::string& name);
|
||||
};
|
||||
|
||||
using GProtoInputArgs = GIOProtoArgs<In_Tag>;
|
||||
using GProtoOutputArgs = GIOProtoArgs<Out_Tag>;
|
||||
class GAPI_EXPORTS_W_SIMPLE GInferListOutputs
|
||||
{
|
||||
public:
|
||||
GAPI_WRAP GInferListOutputs();
|
||||
GAPI_WRAP cv::GArray<cv::GMat> at(const std::string& name);
|
||||
};
|
||||
|
||||
namespace gapi
|
||||
{
|
||||
GAPI_EXPORTS_W gapi::GNetPackage networks(const cv::gapi::ie::PyParams& params);
|
||||
namespace wip
|
||||
{
|
||||
class GAPI_EXPORTS_W IStreamSource { };
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
namespace gapi
|
||||
{
|
||||
namespace wip
|
||||
{
|
||||
class GAPI_EXPORTS_W IStreamSource { };
|
||||
namespace draw
|
||||
{
|
||||
// NB: These render primitives are partially wrapped in shadow file
|
||||
// because cv::Rect conflicts with cv::gapi::wip::draw::Rect in python generator
|
||||
// and cv::Rect2i breaks standalone mode.
|
||||
struct Rect
|
||||
{
|
||||
GAPI_WRAP Rect(const cv::Rect2i& rect_,
|
||||
const cv::Scalar& color_,
|
||||
int thick_ = 1,
|
||||
int lt_ = 8,
|
||||
int shift_ = 0);
|
||||
};
|
||||
|
||||
struct Mosaic
|
||||
{
|
||||
GAPI_WRAP Mosaic(const cv::Rect2i& mos_, int cellSz_, int decim_);
|
||||
};
|
||||
} // namespace draw
|
||||
} // namespace wip
|
||||
namespace streaming
|
||||
{
|
||||
// FIXME: Extend to work with an arbitrary G-type.
|
||||
cv::GOpaque<int64_t> GAPI_EXPORTS_W timestamp(cv::GMat);
|
||||
cv::GOpaque<int64_t> GAPI_EXPORTS_W seqNo(cv::GMat);
|
||||
cv::GOpaque<int64_t> GAPI_EXPORTS_W seq_id(cv::GMat);
|
||||
|
||||
GAPI_EXPORTS_W cv::GMat desync(const cv::GMat &g);
|
||||
} // namespace streaming
|
||||
} // namespace gapi
|
||||
|
||||
namespace detail
|
||||
{
|
||||
gapi::GNetParam GAPI_EXPORTS_W strip(gapi::ie::PyParams params);
|
||||
} // namespace detail
|
||||
} // namespace cv
|
||||
|
|
|
|||
|
|
@ -3,129 +3,209 @@
|
|||
import numpy as np
|
||||
import cv2 as cv
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
|
||||
# Plaidml is an optional backend
|
||||
pkgs = [
|
||||
('ocl' , cv.gapi.core.ocl.kernels()),
|
||||
('cpu' , cv.gapi.core.cpu.kernels()),
|
||||
('fluid' , cv.gapi.core.fluid.kernels())
|
||||
# ('plaidml', cv.gapi.core.plaidml.kernels())
|
||||
]
|
||||
try:
|
||||
|
||||
if sys.version_info[:2] < (3, 0):
|
||||
raise unittest.SkipTest('Python 2.x is not supported')
|
||||
|
||||
# Plaidml is an optional backend
|
||||
pkgs = [
|
||||
('ocl' , cv.gapi.core.ocl.kernels()),
|
||||
('cpu' , cv.gapi.core.cpu.kernels()),
|
||||
('fluid' , cv.gapi.core.fluid.kernels())
|
||||
# ('plaidml', cv.gapi.core.plaidml.kernels())
|
||||
]
|
||||
|
||||
|
||||
class gapi_core_test(NewOpenCVTests):
|
||||
class gapi_core_test(NewOpenCVTests):
|
||||
|
||||
def test_add(self):
|
||||
# TODO: Extend to use any type and size here
|
||||
sz = (720, 1280)
|
||||
in1 = np.full(sz, 100)
|
||||
in2 = np.full(sz, 50)
|
||||
def test_add(self):
|
||||
# TODO: Extend to use any type and size here
|
||||
sz = (720, 1280)
|
||||
in1 = np.full(sz, 100)
|
||||
in2 = np.full(sz, 50)
|
||||
|
||||
# OpenCV
|
||||
expected = cv.add(in1, in2)
|
||||
# OpenCV
|
||||
expected = cv.add(in1, in2)
|
||||
|
||||
# G-API
|
||||
g_in1 = cv.GMat()
|
||||
g_in2 = cv.GMat()
|
||||
g_out = cv.gapi.add(g_in1, g_in2)
|
||||
comp = cv.GComputation(cv.GIn(g_in1, g_in2), cv.GOut(g_out))
|
||||
# G-API
|
||||
g_in1 = cv.GMat()
|
||||
g_in2 = cv.GMat()
|
||||
g_out = cv.gapi.add(g_in1, g_in2)
|
||||
comp = cv.GComputation(cv.GIn(g_in1, g_in2), cv.GOut(g_out))
|
||||
|
||||
for pkg_name, pkg in pkgs:
|
||||
actual = comp.apply(cv.gin(in1, in2), args=cv.compile_args(pkg))
|
||||
# Comparison
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF),
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
self.assertEqual(expected.dtype, actual.dtype, 'Failed on ' + pkg_name + ' backend')
|
||||
|
||||
|
||||
def test_add_uint8(self):
|
||||
sz = (720, 1280)
|
||||
in1 = np.full(sz, 100, dtype=np.uint8)
|
||||
in2 = np.full(sz, 50 , dtype=np.uint8)
|
||||
|
||||
# OpenCV
|
||||
expected = cv.add(in1, in2)
|
||||
|
||||
# G-API
|
||||
g_in1 = cv.GMat()
|
||||
g_in2 = cv.GMat()
|
||||
g_out = cv.gapi.add(g_in1, g_in2)
|
||||
comp = cv.GComputation(cv.GIn(g_in1, g_in2), cv.GOut(g_out))
|
||||
|
||||
for pkg_name, pkg in pkgs:
|
||||
actual = comp.apply(cv.gin(in1, in2), args=cv.compile_args(pkg))
|
||||
# Comparison
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF),
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
self.assertEqual(expected.dtype, actual.dtype, 'Failed on ' + pkg_name + ' backend')
|
||||
|
||||
|
||||
def test_mean(self):
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
in_mat = cv.imread(img_path)
|
||||
|
||||
# OpenCV
|
||||
expected = cv.mean(in_mat)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_out = cv.gapi.mean(g_in)
|
||||
comp = cv.GComputation(g_in, g_out)
|
||||
|
||||
for pkg_name, pkg in pkgs:
|
||||
actual = comp.apply(cv.gin(in_mat), args=cv.compile_args(pkg))
|
||||
# Comparison
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF),
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
|
||||
|
||||
def test_split3(self):
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
in_mat = cv.imread(img_path)
|
||||
|
||||
# OpenCV
|
||||
expected = cv.split(in_mat)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
b, g, r = cv.gapi.split3(g_in)
|
||||
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(b, g, r))
|
||||
|
||||
for pkg_name, pkg in pkgs:
|
||||
actual = comp.apply(cv.gin(in_mat), args=cv.compile_args(pkg))
|
||||
# Comparison
|
||||
for e, a in zip(expected, actual):
|
||||
self.assertEqual(0.0, cv.norm(e, a, cv.NORM_INF),
|
||||
for pkg_name, pkg in pkgs:
|
||||
actual = comp.apply(cv.gin(in1, in2), args=cv.gapi.compile_args(pkg))
|
||||
# Comparison
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF),
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
self.assertEqual(e.dtype, a.dtype, 'Failed on ' + pkg_name + ' backend')
|
||||
self.assertEqual(expected.dtype, actual.dtype, 'Failed on ' + pkg_name + ' backend')
|
||||
|
||||
|
||||
def test_threshold(self):
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
in_mat = cv.cvtColor(cv.imread(img_path), cv.COLOR_RGB2GRAY)
|
||||
maxv = (30, 30)
|
||||
def test_add_uint8(self):
|
||||
sz = (720, 1280)
|
||||
in1 = np.full(sz, 100, dtype=np.uint8)
|
||||
in2 = np.full(sz, 50 , dtype=np.uint8)
|
||||
|
||||
# OpenCV
|
||||
expected_thresh, expected_mat = cv.threshold(in_mat, maxv[0], maxv[0], cv.THRESH_TRIANGLE)
|
||||
# OpenCV
|
||||
expected = cv.add(in1, in2)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_sc = cv.GScalar()
|
||||
mat, threshold = cv.gapi.threshold(g_in, g_sc, cv.THRESH_TRIANGLE)
|
||||
comp = cv.GComputation(cv.GIn(g_in, g_sc), cv.GOut(mat, threshold))
|
||||
# G-API
|
||||
g_in1 = cv.GMat()
|
||||
g_in2 = cv.GMat()
|
||||
g_out = cv.gapi.add(g_in1, g_in2)
|
||||
comp = cv.GComputation(cv.GIn(g_in1, g_in2), cv.GOut(g_out))
|
||||
|
||||
for pkg_name, pkg in pkgs:
|
||||
actual_mat, actual_thresh = comp.apply(cv.gin(in_mat, maxv), args=cv.compile_args(pkg))
|
||||
# Comparison
|
||||
self.assertEqual(0.0, cv.norm(expected_mat, actual_mat, cv.NORM_INF),
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
self.assertEqual(expected_mat.dtype, actual_mat.dtype,
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
self.assertEqual(expected_thresh, actual_thresh[0],
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
for pkg_name, pkg in pkgs:
|
||||
actual = comp.apply(cv.gin(in1, in2), args=cv.gapi.compile_args(pkg))
|
||||
# Comparison
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF),
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
self.assertEqual(expected.dtype, actual.dtype, 'Failed on ' + pkg_name + ' backend')
|
||||
|
||||
|
||||
def test_mean(self):
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
in_mat = cv.imread(img_path)
|
||||
|
||||
# OpenCV
|
||||
expected = cv.mean(in_mat)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_out = cv.gapi.mean(g_in)
|
||||
comp = cv.GComputation(g_in, g_out)
|
||||
|
||||
for pkg_name, pkg in pkgs:
|
||||
actual = comp.apply(cv.gin(in_mat), args=cv.gapi.compile_args(pkg))
|
||||
# Comparison
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF),
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
|
||||
|
||||
def test_split3(self):
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
in_mat = cv.imread(img_path)
|
||||
|
||||
# OpenCV
|
||||
expected = cv.split(in_mat)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
b, g, r = cv.gapi.split3(g_in)
|
||||
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(b, g, r))
|
||||
|
||||
for pkg_name, pkg in pkgs:
|
||||
actual = comp.apply(cv.gin(in_mat), args=cv.gapi.compile_args(pkg))
|
||||
# Comparison
|
||||
for e, a in zip(expected, actual):
|
||||
self.assertEqual(0.0, cv.norm(e, a, cv.NORM_INF),
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
self.assertEqual(e.dtype, a.dtype, 'Failed on ' + pkg_name + ' backend')
|
||||
|
||||
|
||||
def test_threshold(self):
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
in_mat = cv.cvtColor(cv.imread(img_path), cv.COLOR_RGB2GRAY)
|
||||
maxv = (30, 30)
|
||||
|
||||
# OpenCV
|
||||
expected_thresh, expected_mat = cv.threshold(in_mat, maxv[0], maxv[0], cv.THRESH_TRIANGLE)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_sc = cv.GScalar()
|
||||
mat, threshold = cv.gapi.threshold(g_in, g_sc, cv.THRESH_TRIANGLE)
|
||||
comp = cv.GComputation(cv.GIn(g_in, g_sc), cv.GOut(mat, threshold))
|
||||
|
||||
for pkg_name, pkg in pkgs:
|
||||
actual_mat, actual_thresh = comp.apply(cv.gin(in_mat, maxv), args=cv.gapi.compile_args(pkg))
|
||||
# Comparison
|
||||
self.assertEqual(0.0, cv.norm(expected_mat, actual_mat, cv.NORM_INF),
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
self.assertEqual(expected_mat.dtype, actual_mat.dtype,
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
self.assertEqual(expected_thresh, actual_thresh[0],
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
|
||||
|
||||
def test_kmeans(self):
|
||||
# K-means params
|
||||
count = 100
|
||||
sz = (count, 2)
|
||||
in_mat = np.random.random(sz).astype(np.float32)
|
||||
K = 5
|
||||
flags = cv.KMEANS_RANDOM_CENTERS
|
||||
attempts = 1
|
||||
criteria = (cv.TERM_CRITERIA_MAX_ITER + cv.TERM_CRITERIA_EPS, 30, 0)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
compactness, out_labels, centers = cv.gapi.kmeans(g_in, K, criteria, attempts, flags)
|
||||
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(compactness, out_labels, centers))
|
||||
|
||||
compact, labels, centers = comp.apply(cv.gin(in_mat))
|
||||
|
||||
# Assert
|
||||
self.assertTrue(compact >= 0)
|
||||
self.assertEqual(sz[0], labels.shape[0])
|
||||
self.assertEqual(1, labels.shape[1])
|
||||
self.assertTrue(labels.size != 0)
|
||||
self.assertEqual(centers.shape[1], sz[1])
|
||||
self.assertEqual(centers.shape[0], K)
|
||||
self.assertTrue(centers.size != 0)
|
||||
|
||||
|
||||
def generate_random_points(self, sz):
|
||||
arr = np.random.random(sz).astype(np.float32).T
|
||||
return list(zip(arr[0], arr[1]))
|
||||
|
||||
|
||||
def test_kmeans_2d(self):
|
||||
# K-means 2D params
|
||||
count = 100
|
||||
sz = (count, 2)
|
||||
amount = sz[0]
|
||||
K = 5
|
||||
flags = cv.KMEANS_RANDOM_CENTERS
|
||||
attempts = 1
|
||||
criteria = (cv.TERM_CRITERIA_MAX_ITER + cv.TERM_CRITERIA_EPS, 30, 0)
|
||||
in_vector = self.generate_random_points(sz)
|
||||
in_labels = []
|
||||
|
||||
# G-API
|
||||
data = cv.GArrayT(cv.gapi.CV_POINT2F)
|
||||
best_labels = cv.GArrayT(cv.gapi.CV_INT)
|
||||
|
||||
compactness, out_labels, centers = cv.gapi.kmeans(data, K, best_labels, criteria, attempts, flags)
|
||||
comp = cv.GComputation(cv.GIn(data, best_labels), cv.GOut(compactness, out_labels, centers))
|
||||
|
||||
compact, labels, centers = comp.apply(cv.gin(in_vector, in_labels))
|
||||
|
||||
# Assert
|
||||
self.assertTrue(compact >= 0)
|
||||
self.assertEqual(amount, len(labels))
|
||||
self.assertEqual(K, len(centers))
|
||||
|
||||
|
||||
except unittest.SkipTest as e:
|
||||
|
||||
message = str(e)
|
||||
|
||||
class TestSkip(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.skipTest('Skip tests: ' + message)
|
||||
|
||||
def test_skip():
|
||||
pass
|
||||
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -3,76 +3,124 @@
|
|||
import numpy as np
|
||||
import cv2 as cv
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
|
||||
# Plaidml is an optional backend
|
||||
pkgs = [
|
||||
('ocl' , cv.gapi.core.ocl.kernels()),
|
||||
('cpu' , cv.gapi.core.cpu.kernels()),
|
||||
('fluid' , cv.gapi.core.fluid.kernels())
|
||||
# ('plaidml', cv.gapi.core.plaidml.kernels())
|
||||
]
|
||||
try:
|
||||
|
||||
if sys.version_info[:2] < (3, 0):
|
||||
raise unittest.SkipTest('Python 2.x is not supported')
|
||||
|
||||
# Plaidml is an optional backend
|
||||
pkgs = [
|
||||
('ocl' , cv.gapi.core.ocl.kernels()),
|
||||
('cpu' , cv.gapi.core.cpu.kernels()),
|
||||
('fluid' , cv.gapi.core.fluid.kernels())
|
||||
# ('plaidml', cv.gapi.core.plaidml.kernels())
|
||||
]
|
||||
|
||||
|
||||
class gapi_imgproc_test(NewOpenCVTests):
|
||||
class gapi_imgproc_test(NewOpenCVTests):
|
||||
|
||||
def test_good_features_to_track(self):
|
||||
# TODO: Extend to use any type and size here
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
in1 = cv.cvtColor(cv.imread(img_path), cv.COLOR_RGB2GRAY)
|
||||
def test_good_features_to_track(self):
|
||||
# TODO: Extend to use any type and size here
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
in1 = cv.cvtColor(cv.imread(img_path), cv.COLOR_RGB2GRAY)
|
||||
|
||||
# NB: goodFeaturesToTrack configuration
|
||||
max_corners = 50
|
||||
quality_lvl = 0.01
|
||||
min_distance = 10
|
||||
block_sz = 3
|
||||
use_harris_detector = True
|
||||
k = 0.04
|
||||
mask = None
|
||||
# NB: goodFeaturesToTrack configuration
|
||||
max_corners = 50
|
||||
quality_lvl = 0.01
|
||||
min_distance = 10
|
||||
block_sz = 3
|
||||
use_harris_detector = True
|
||||
k = 0.04
|
||||
mask = None
|
||||
|
||||
# OpenCV
|
||||
expected = cv.goodFeaturesToTrack(in1, max_corners, quality_lvl,
|
||||
min_distance, mask=mask,
|
||||
blockSize=block_sz, useHarrisDetector=use_harris_detector, k=k)
|
||||
# OpenCV
|
||||
expected = cv.goodFeaturesToTrack(in1, max_corners, quality_lvl,
|
||||
min_distance, mask=mask,
|
||||
blockSize=block_sz, useHarrisDetector=use_harris_detector, k=k)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_out = cv.gapi.goodFeaturesToTrack(g_in, max_corners, quality_lvl,
|
||||
min_distance, mask, block_sz, use_harris_detector, k)
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_out = cv.gapi.goodFeaturesToTrack(g_in, max_corners, quality_lvl,
|
||||
min_distance, mask, block_sz, use_harris_detector, k)
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_out))
|
||||
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_out))
|
||||
|
||||
for pkg_name, pkg in pkgs:
|
||||
actual = comp.apply(cv.gin(in1), args=cv.compile_args(pkg))
|
||||
# NB: OpenCV & G-API have different output shapes:
|
||||
# OpenCV - (num_points, 1, 2)
|
||||
# G-API - (num_points, 2)
|
||||
# Comparison
|
||||
self.assertEqual(0.0, cv.norm(expected.flatten(), actual.flatten(), cv.NORM_INF),
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
for pkg_name, pkg in pkgs:
|
||||
actual = comp.apply(cv.gin(in1), args=cv.gapi.compile_args(pkg))
|
||||
# NB: OpenCV & G-API have different output shapes:
|
||||
# OpenCV - (num_points, 1, 2)
|
||||
# G-API - (num_points, 2)
|
||||
# Comparison
|
||||
self.assertEqual(0.0, cv.norm(expected.flatten(),
|
||||
np.array(actual, dtype=np.float32).flatten(),
|
||||
cv.NORM_INF),
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
|
||||
|
||||
def test_rgb2gray(self):
|
||||
# TODO: Extend to use any type and size here
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
in1 = cv.imread(img_path)
|
||||
def test_rgb2gray(self):
|
||||
# TODO: Extend to use any type and size here
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
in1 = cv.imread(img_path)
|
||||
|
||||
# OpenCV
|
||||
expected = cv.cvtColor(in1, cv.COLOR_RGB2GRAY)
|
||||
# OpenCV
|
||||
expected = cv.cvtColor(in1, cv.COLOR_RGB2GRAY)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_out = cv.gapi.RGB2Gray(g_in)
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_out = cv.gapi.RGB2Gray(g_in)
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_out))
|
||||
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_out))
|
||||
|
||||
for pkg_name, pkg in pkgs:
|
||||
actual = comp.apply(cv.gin(in1), args=cv.compile_args(pkg))
|
||||
# Comparison
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF),
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
for pkg_name, pkg in pkgs:
|
||||
actual = comp.apply(cv.gin(in1), args=cv.gapi.compile_args(pkg))
|
||||
# Comparison
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF),
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
|
||||
|
||||
def test_bounding_rect(self):
|
||||
sz = 1280
|
||||
fscale = 256
|
||||
|
||||
def sample_value(fscale):
|
||||
return np.random.uniform(0, 255 * fscale) / fscale
|
||||
|
||||
points = np.array([(sample_value(fscale), sample_value(fscale)) for _ in range(1280)], np.float32)
|
||||
|
||||
# OpenCV
|
||||
expected = cv.boundingRect(points)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_out = cv.gapi.boundingRect(g_in)
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_out))
|
||||
|
||||
for pkg_name, pkg in pkgs:
|
||||
actual = comp.apply(cv.gin(points), args=cv.gapi.compile_args(pkg))
|
||||
# Comparison
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF),
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
|
||||
|
||||
except unittest.SkipTest as e:
|
||||
|
||||
message = str(e)
|
||||
|
||||
class TestSkip(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.skipTest('Skip tests: ' + message)
|
||||
|
||||
def test_skip():
|
||||
pass
|
||||
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -3,59 +3,338 @@
|
|||
import numpy as np
|
||||
import cv2 as cv
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
|
||||
class test_gapi_infer(NewOpenCVTests):
|
||||
try:
|
||||
|
||||
def test_getAvailableTargets(self):
|
||||
targets = cv.dnn.getAvailableTargets(cv.dnn.DNN_BACKEND_OPENCV)
|
||||
self.assertTrue(cv.dnn.DNN_TARGET_CPU in targets)
|
||||
if sys.version_info[:2] < (3, 0):
|
||||
raise unittest.SkipTest('Python 2.x is not supported')
|
||||
|
||||
|
||||
def test_age_gender_infer(self):
|
||||
class test_gapi_infer(NewOpenCVTests):
|
||||
|
||||
# NB: Check IE
|
||||
if not cv.dnn.DNN_TARGET_CPU in cv.dnn.getAvailableTargets(cv.dnn.DNN_BACKEND_INFERENCE_ENGINE):
|
||||
return
|
||||
def infer_reference_network(self, model_path, weights_path, img):
|
||||
net = cv.dnn.readNetFromModelOptimizer(model_path, weights_path)
|
||||
net.setPreferableBackend(cv.dnn.DNN_BACKEND_INFERENCE_ENGINE)
|
||||
net.setPreferableTarget(cv.dnn.DNN_TARGET_CPU)
|
||||
|
||||
root_path = '/omz_intel_models/intel/age-gender-recognition-retail-0013/FP32/age-gender-recognition-retail-0013'
|
||||
model_path = self.find_file(root_path + '.xml', [os.environ.get('OPENCV_DNN_TEST_DATA_PATH')])
|
||||
weights_path = self.find_file(root_path + '.bin', [os.environ.get('OPENCV_DNN_TEST_DATA_PATH')])
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
device_id = 'CPU'
|
||||
img = cv.resize(cv.imread(img_path), (62,62))
|
||||
blob = cv.dnn.blobFromImage(img)
|
||||
|
||||
# OpenCV DNN
|
||||
net = cv.dnn.readNetFromModelOptimizer(model_path, weights_path)
|
||||
net.setPreferableBackend(cv.dnn.DNN_BACKEND_INFERENCE_ENGINE)
|
||||
net.setPreferableTarget(cv.dnn.DNN_TARGET_CPU)
|
||||
net.setInput(blob)
|
||||
return net.forward(net.getUnconnectedOutLayersNames())
|
||||
|
||||
blob = cv.dnn.blobFromImage(img)
|
||||
|
||||
net.setInput(blob)
|
||||
dnn_age, dnn_gender = net.forward(net.getUnconnectedOutLayersNames())
|
||||
def make_roi(self, img, roi):
|
||||
return img[roi[1]:roi[1] + roi[3], roi[0]:roi[0] + roi[2], ...]
|
||||
|
||||
# OpenCV G-API
|
||||
g_in = cv.GMat()
|
||||
inputs = cv.GInferInputs()
|
||||
inputs.setInput('data', g_in)
|
||||
|
||||
outputs = cv.gapi.infer("net", inputs)
|
||||
age_g = outputs.at("age_conv3")
|
||||
gender_g = outputs.at("prob")
|
||||
def test_age_gender_infer(self):
|
||||
# NB: Check IE
|
||||
if not cv.dnn.DNN_TARGET_CPU in cv.dnn.getAvailableTargets(cv.dnn.DNN_BACKEND_INFERENCE_ENGINE):
|
||||
return
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(age_g, gender_g))
|
||||
pp = cv.gapi.ie.params("net", model_path, weights_path, device_id)
|
||||
root_path = '/omz_intel_models/intel/age-gender-recognition-retail-0013/FP32/age-gender-recognition-retail-0013'
|
||||
model_path = self.find_file(root_path + '.xml', [os.environ.get('OPENCV_DNN_TEST_DATA_PATH')])
|
||||
weights_path = self.find_file(root_path + '.bin', [os.environ.get('OPENCV_DNN_TEST_DATA_PATH')])
|
||||
device_id = 'CPU'
|
||||
|
||||
nets = cv.gapi.networks(pp)
|
||||
args = cv.compile_args(nets)
|
||||
gapi_age, gapi_gender = comp.apply(cv.gin(img), args=cv.compile_args(cv.gapi.networks(pp)))
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
img = cv.resize(cv.imread(img_path), (62,62))
|
||||
|
||||
# Check
|
||||
self.assertEqual(0.0, cv.norm(dnn_gender, gapi_gender, cv.NORM_INF))
|
||||
self.assertEqual(0.0, cv.norm(dnn_age, gapi_age, cv.NORM_INF))
|
||||
# OpenCV DNN
|
||||
dnn_age, dnn_gender = self.infer_reference_network(model_path, weights_path, img)
|
||||
|
||||
# OpenCV G-API
|
||||
g_in = cv.GMat()
|
||||
inputs = cv.GInferInputs()
|
||||
inputs.setInput('data', g_in)
|
||||
|
||||
outputs = cv.gapi.infer("net", inputs)
|
||||
age_g = outputs.at("age_conv3")
|
||||
gender_g = outputs.at("prob")
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(age_g, gender_g))
|
||||
pp = cv.gapi.ie.params("net", model_path, weights_path, device_id)
|
||||
|
||||
gapi_age, gapi_gender = comp.apply(cv.gin(img), args=cv.gapi.compile_args(cv.gapi.networks(pp)))
|
||||
|
||||
# Check
|
||||
self.assertEqual(0.0, cv.norm(dnn_gender, gapi_gender, cv.NORM_INF))
|
||||
self.assertEqual(0.0, cv.norm(dnn_age, gapi_age, cv.NORM_INF))
|
||||
|
||||
|
||||
def test_age_gender_infer_roi(self):
|
||||
# NB: Check IE
|
||||
if not cv.dnn.DNN_TARGET_CPU in cv.dnn.getAvailableTargets(cv.dnn.DNN_BACKEND_INFERENCE_ENGINE):
|
||||
return
|
||||
|
||||
root_path = '/omz_intel_models/intel/age-gender-recognition-retail-0013/FP32/age-gender-recognition-retail-0013'
|
||||
model_path = self.find_file(root_path + '.xml', [os.environ.get('OPENCV_DNN_TEST_DATA_PATH')])
|
||||
weights_path = self.find_file(root_path + '.bin', [os.environ.get('OPENCV_DNN_TEST_DATA_PATH')])
|
||||
device_id = 'CPU'
|
||||
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
img = cv.imread(img_path)
|
||||
roi = (10, 10, 62, 62)
|
||||
|
||||
# OpenCV DNN
|
||||
dnn_age, dnn_gender = self.infer_reference_network(model_path,
|
||||
weights_path,
|
||||
self.make_roi(img, roi))
|
||||
|
||||
# OpenCV G-API
|
||||
g_in = cv.GMat()
|
||||
g_roi = cv.GOpaqueT(cv.gapi.CV_RECT)
|
||||
inputs = cv.GInferInputs()
|
||||
inputs.setInput('data', g_in)
|
||||
|
||||
outputs = cv.gapi.infer("net", g_roi, inputs)
|
||||
age_g = outputs.at("age_conv3")
|
||||
gender_g = outputs.at("prob")
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_in, g_roi), cv.GOut(age_g, gender_g))
|
||||
pp = cv.gapi.ie.params("net", model_path, weights_path, device_id)
|
||||
|
||||
gapi_age, gapi_gender = comp.apply(cv.gin(img, roi), args=cv.gapi.compile_args(cv.gapi.networks(pp)))
|
||||
|
||||
# Check
|
||||
self.assertEqual(0.0, cv.norm(dnn_gender, gapi_gender, cv.NORM_INF))
|
||||
self.assertEqual(0.0, cv.norm(dnn_age, gapi_age, cv.NORM_INF))
|
||||
|
||||
|
||||
def test_age_gender_infer_roi_list(self):
|
||||
# NB: Check IE
|
||||
if not cv.dnn.DNN_TARGET_CPU in cv.dnn.getAvailableTargets(cv.dnn.DNN_BACKEND_INFERENCE_ENGINE):
|
||||
return
|
||||
|
||||
root_path = '/omz_intel_models/intel/age-gender-recognition-retail-0013/FP32/age-gender-recognition-retail-0013'
|
||||
model_path = self.find_file(root_path + '.xml', [os.environ.get('OPENCV_DNN_TEST_DATA_PATH')])
|
||||
weights_path = self.find_file(root_path + '.bin', [os.environ.get('OPENCV_DNN_TEST_DATA_PATH')])
|
||||
device_id = 'CPU'
|
||||
|
||||
rois = [(10, 15, 62, 62), (23, 50, 62, 62), (14, 100, 62, 62), (80, 50, 62, 62)]
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
img = cv.imread(img_path)
|
||||
|
||||
# OpenCV DNN
|
||||
dnn_age_list = []
|
||||
dnn_gender_list = []
|
||||
for roi in rois:
|
||||
age, gender = self.infer_reference_network(model_path,
|
||||
weights_path,
|
||||
self.make_roi(img, roi))
|
||||
dnn_age_list.append(age)
|
||||
dnn_gender_list.append(gender)
|
||||
|
||||
# OpenCV G-API
|
||||
g_in = cv.GMat()
|
||||
g_rois = cv.GArrayT(cv.gapi.CV_RECT)
|
||||
inputs = cv.GInferInputs()
|
||||
inputs.setInput('data', g_in)
|
||||
|
||||
outputs = cv.gapi.infer("net", g_rois, inputs)
|
||||
age_g = outputs.at("age_conv3")
|
||||
gender_g = outputs.at("prob")
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_in, g_rois), cv.GOut(age_g, gender_g))
|
||||
pp = cv.gapi.ie.params("net", model_path, weights_path, device_id)
|
||||
|
||||
gapi_age_list, gapi_gender_list = comp.apply(cv.gin(img, rois),
|
||||
args=cv.gapi.compile_args(cv.gapi.networks(pp)))
|
||||
|
||||
# Check
|
||||
for gapi_age, gapi_gender, dnn_age, dnn_gender in zip(gapi_age_list,
|
||||
gapi_gender_list,
|
||||
dnn_age_list,
|
||||
dnn_gender_list):
|
||||
self.assertEqual(0.0, cv.norm(dnn_gender, gapi_gender, cv.NORM_INF))
|
||||
self.assertEqual(0.0, cv.norm(dnn_age, gapi_age, cv.NORM_INF))
|
||||
|
||||
|
||||
def test_age_gender_infer2_roi(self):
|
||||
# NB: Check IE
|
||||
if not cv.dnn.DNN_TARGET_CPU in cv.dnn.getAvailableTargets(cv.dnn.DNN_BACKEND_INFERENCE_ENGINE):
|
||||
return
|
||||
|
||||
root_path = '/omz_intel_models/intel/age-gender-recognition-retail-0013/FP32/age-gender-recognition-retail-0013'
|
||||
model_path = self.find_file(root_path + '.xml', [os.environ.get('OPENCV_DNN_TEST_DATA_PATH')])
|
||||
weights_path = self.find_file(root_path + '.bin', [os.environ.get('OPENCV_DNN_TEST_DATA_PATH')])
|
||||
device_id = 'CPU'
|
||||
|
||||
rois = [(10, 15, 62, 62), (23, 50, 62, 62), (14, 100, 62, 62), (80, 50, 62, 62)]
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
img = cv.imread(img_path)
|
||||
|
||||
# OpenCV DNN
|
||||
dnn_age_list = []
|
||||
dnn_gender_list = []
|
||||
for roi in rois:
|
||||
age, gender = self.infer_reference_network(model_path,
|
||||
weights_path,
|
||||
self.make_roi(img, roi))
|
||||
dnn_age_list.append(age)
|
||||
dnn_gender_list.append(gender)
|
||||
|
||||
# OpenCV G-API
|
||||
g_in = cv.GMat()
|
||||
g_rois = cv.GArrayT(cv.gapi.CV_RECT)
|
||||
inputs = cv.GInferListInputs()
|
||||
inputs.setInput('data', g_rois)
|
||||
|
||||
outputs = cv.gapi.infer2("net", g_in, inputs)
|
||||
age_g = outputs.at("age_conv3")
|
||||
gender_g = outputs.at("prob")
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_in, g_rois), cv.GOut(age_g, gender_g))
|
||||
pp = cv.gapi.ie.params("net", model_path, weights_path, device_id)
|
||||
|
||||
gapi_age_list, gapi_gender_list = comp.apply(cv.gin(img, rois),
|
||||
args=cv.gapi.compile_args(cv.gapi.networks(pp)))
|
||||
|
||||
# Check
|
||||
for gapi_age, gapi_gender, dnn_age, dnn_gender in zip(gapi_age_list,
|
||||
gapi_gender_list,
|
||||
dnn_age_list,
|
||||
dnn_gender_list):
|
||||
self.assertEqual(0.0, cv.norm(dnn_gender, gapi_gender, cv.NORM_INF))
|
||||
self.assertEqual(0.0, cv.norm(dnn_age, gapi_age, cv.NORM_INF))
|
||||
|
||||
|
||||
|
||||
def test_person_detection_retail_0013(self):
|
||||
# NB: Check IE
|
||||
if not cv.dnn.DNN_TARGET_CPU in cv.dnn.getAvailableTargets(cv.dnn.DNN_BACKEND_INFERENCE_ENGINE):
|
||||
return
|
||||
|
||||
root_path = '/omz_intel_models/intel/person-detection-retail-0013/FP32/person-detection-retail-0013'
|
||||
model_path = self.find_file(root_path + '.xml', [os.environ.get('OPENCV_DNN_TEST_DATA_PATH')])
|
||||
weights_path = self.find_file(root_path + '.bin', [os.environ.get('OPENCV_DNN_TEST_DATA_PATH')])
|
||||
img_path = self.find_file('gpu/lbpcascade/er.png', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
device_id = 'CPU'
|
||||
img = cv.resize(cv.imread(img_path), (544, 320))
|
||||
|
||||
# OpenCV DNN
|
||||
net = cv.dnn.readNetFromModelOptimizer(model_path, weights_path)
|
||||
net.setPreferableBackend(cv.dnn.DNN_BACKEND_INFERENCE_ENGINE)
|
||||
net.setPreferableTarget(cv.dnn.DNN_TARGET_CPU)
|
||||
|
||||
blob = cv.dnn.blobFromImage(img)
|
||||
|
||||
def parseSSD(detections, size):
|
||||
h, w = size
|
||||
bboxes = []
|
||||
detections = detections.reshape(-1, 7)
|
||||
for sample_id, class_id, confidence, xmin, ymin, xmax, ymax in detections:
|
||||
if confidence >= 0.5:
|
||||
x = int(xmin * w)
|
||||
y = int(ymin * h)
|
||||
width = int(xmax * w - x)
|
||||
height = int(ymax * h - y)
|
||||
bboxes.append((x, y, width, height))
|
||||
|
||||
return bboxes
|
||||
|
||||
net.setInput(blob)
|
||||
dnn_detections = net.forward()
|
||||
dnn_boxes = parseSSD(np.array(dnn_detections), img.shape[:2])
|
||||
|
||||
# OpenCV G-API
|
||||
g_in = cv.GMat()
|
||||
inputs = cv.GInferInputs()
|
||||
inputs.setInput('data', g_in)
|
||||
|
||||
g_sz = cv.gapi.streaming.size(g_in)
|
||||
outputs = cv.gapi.infer("net", inputs)
|
||||
detections = outputs.at("detection_out")
|
||||
bboxes = cv.gapi.parseSSD(detections, g_sz, 0.5, False, False)
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(bboxes))
|
||||
pp = cv.gapi.ie.params("net", model_path, weights_path, device_id)
|
||||
|
||||
gapi_boxes = comp.apply(cv.gin(img.astype(np.float32)),
|
||||
args=cv.gapi.compile_args(cv.gapi.networks(pp)))
|
||||
|
||||
# Comparison
|
||||
self.assertEqual(0.0, cv.norm(np.array(dnn_boxes).flatten(),
|
||||
np.array(gapi_boxes).flatten(),
|
||||
cv.NORM_INF))
|
||||
|
||||
|
||||
def test_person_detection_retail_0013(self):
|
||||
# NB: Check IE
|
||||
if not cv.dnn.DNN_TARGET_CPU in cv.dnn.getAvailableTargets(cv.dnn.DNN_BACKEND_INFERENCE_ENGINE):
|
||||
return
|
||||
|
||||
root_path = '/omz_intel_models/intel/person-detection-retail-0013/FP32/person-detection-retail-0013'
|
||||
model_path = self.find_file(root_path + '.xml', [os.environ.get('OPENCV_DNN_TEST_DATA_PATH')])
|
||||
weights_path = self.find_file(root_path + '.bin', [os.environ.get('OPENCV_DNN_TEST_DATA_PATH')])
|
||||
img_path = self.find_file('gpu/lbpcascade/er.png', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
device_id = 'CPU'
|
||||
img = cv.resize(cv.imread(img_path), (544, 320))
|
||||
|
||||
# OpenCV DNN
|
||||
net = cv.dnn.readNetFromModelOptimizer(model_path, weights_path)
|
||||
net.setPreferableBackend(cv.dnn.DNN_BACKEND_INFERENCE_ENGINE)
|
||||
net.setPreferableTarget(cv.dnn.DNN_TARGET_CPU)
|
||||
|
||||
blob = cv.dnn.blobFromImage(img)
|
||||
|
||||
def parseSSD(detections, size):
|
||||
h, w = size
|
||||
bboxes = []
|
||||
detections = detections.reshape(-1, 7)
|
||||
for sample_id, class_id, confidence, xmin, ymin, xmax, ymax in detections:
|
||||
if confidence >= 0.5:
|
||||
x = int(xmin * w)
|
||||
y = int(ymin * h)
|
||||
width = int(xmax * w - x)
|
||||
height = int(ymax * h - y)
|
||||
bboxes.append((x, y, width, height))
|
||||
|
||||
return bboxes
|
||||
|
||||
net.setInput(blob)
|
||||
dnn_detections = net.forward()
|
||||
dnn_boxes = parseSSD(np.array(dnn_detections), img.shape[:2])
|
||||
|
||||
# OpenCV G-API
|
||||
g_in = cv.GMat()
|
||||
inputs = cv.GInferInputs()
|
||||
inputs.setInput('data', g_in)
|
||||
|
||||
g_sz = cv.gapi.streaming.size(g_in)
|
||||
outputs = cv.gapi.infer("net", inputs)
|
||||
detections = outputs.at("detection_out")
|
||||
bboxes = cv.gapi.parseSSD(detections, g_sz, 0.5, False, False)
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(bboxes))
|
||||
pp = cv.gapi.ie.params("net", model_path, weights_path, device_id)
|
||||
|
||||
gapi_boxes = comp.apply(cv.gin(img.astype(np.float32)),
|
||||
args=cv.gapi.compile_args(cv.gapi.networks(pp)))
|
||||
|
||||
# Comparison
|
||||
self.assertEqual(0.0, cv.norm(np.array(dnn_boxes).flatten(),
|
||||
np.array(gapi_boxes).flatten(),
|
||||
cv.NORM_INF))
|
||||
|
||||
|
||||
except unittest.SkipTest as e:
|
||||
|
||||
message = str(e)
|
||||
|
||||
class TestSkip(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.skipTest('Skip tests: ' + message)
|
||||
|
||||
def test_skip():
|
||||
pass
|
||||
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -0,0 +1,227 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
try:
|
||||
|
||||
if sys.version_info[:2] < (3, 0):
|
||||
raise unittest.SkipTest('Python 2.x is not supported')
|
||||
|
||||
# FIXME: FText isn't supported yet.
|
||||
class gapi_render_test(NewOpenCVTests):
|
||||
def __init__(self, *args):
|
||||
super().__init__(*args)
|
||||
|
||||
self.size = (300, 300, 3)
|
||||
|
||||
# Rect
|
||||
self.rect = (30, 30, 50, 50)
|
||||
self.rcolor = (0, 255, 0)
|
||||
self.rlt = cv.LINE_4
|
||||
self.rthick = 2
|
||||
self.rshift = 3
|
||||
|
||||
# Text
|
||||
self.text = 'Hello, world!'
|
||||
self.org = (100, 100)
|
||||
self.ff = cv.FONT_HERSHEY_SIMPLEX
|
||||
self.fs = 1.0
|
||||
self.tthick = 2
|
||||
self.tlt = cv.LINE_8
|
||||
self.tcolor = (255, 255, 255)
|
||||
self.blo = False
|
||||
|
||||
# Circle
|
||||
self.center = (200, 200)
|
||||
self.radius = 200
|
||||
self.ccolor = (255, 255, 0)
|
||||
self.cthick = 2
|
||||
self.clt = cv.LINE_4
|
||||
self.cshift = 1
|
||||
|
||||
# Line
|
||||
self.pt1 = (50, 50)
|
||||
self.pt2 = (200, 200)
|
||||
self.lcolor = (0, 255, 128)
|
||||
self.lthick = 5
|
||||
self.llt = cv.LINE_8
|
||||
self.lshift = 2
|
||||
|
||||
# Poly
|
||||
self.pts = [(50, 100), (100, 200), (25, 250)]
|
||||
self.pcolor = (0, 0, 255)
|
||||
self.pthick = 3
|
||||
self.plt = cv.LINE_4
|
||||
self.pshift = 1
|
||||
|
||||
# Image
|
||||
self.iorg = (150, 150)
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
self.img = cv.resize(cv.imread(img_path), (50, 50))
|
||||
self.alpha = np.full(self.img.shape[:2], 0.8, dtype=np.float32)
|
||||
|
||||
# Mosaic
|
||||
self.mos = (100, 100, 100, 100)
|
||||
self.cell_sz = 25
|
||||
self.decim = 0
|
||||
|
||||
# Render primitives
|
||||
self.prims = [cv.gapi.wip.draw.Rect(self.rect, self.rcolor, self.rthick, self.rlt, self.rshift),
|
||||
cv.gapi.wip.draw.Text(self.text, self.org, self.ff, self.fs, self.tcolor, self.tthick, self.tlt, self.blo),
|
||||
cv.gapi.wip.draw.Circle(self.center, self.radius, self.ccolor, self.cthick, self.clt, self.cshift),
|
||||
cv.gapi.wip.draw.Line(self.pt1, self.pt2, self.lcolor, self.lthick, self.llt, self.lshift),
|
||||
cv.gapi.wip.draw.Mosaic(self.mos, self.cell_sz, self.decim),
|
||||
cv.gapi.wip.draw.Image(self.iorg, self.img, self.alpha),
|
||||
cv.gapi.wip.draw.Poly(self.pts, self.pcolor, self.pthick, self.plt, self.pshift)]
|
||||
|
||||
def cvt_nv12_to_yuv(self, y, uv):
|
||||
h,w,_ = uv.shape
|
||||
upsample_uv = cv.resize(uv, (h * 2, w * 2))
|
||||
return cv.merge([y, upsample_uv])
|
||||
|
||||
def cvt_yuv_to_nv12(self, yuv, y_out, uv_out):
|
||||
chs = cv.split(yuv, [y_out, None, None])
|
||||
uv = cv.merge([chs[1], chs[2]])
|
||||
uv_out = cv.resize(uv, (uv.shape[0] // 2, uv.shape[1] // 2), dst=uv_out)
|
||||
return y_out, uv_out
|
||||
|
||||
def cvt_bgr_to_yuv_color(self, bgr):
|
||||
y = bgr[2] * 0.299000 + bgr[1] * 0.587000 + bgr[0] * 0.114000;
|
||||
u = bgr[2] * -0.168736 + bgr[1] * -0.331264 + bgr[0] * 0.500000 + 128;
|
||||
v = bgr[2] * 0.500000 + bgr[1] * -0.418688 + bgr[0] * -0.081312 + 128;
|
||||
return (y, u, v)
|
||||
|
||||
def blend_img(self, background, org, img, alpha):
|
||||
x, y = org
|
||||
h, w, _ = img.shape
|
||||
roi_img = background[x:x+w, y:y+h, :]
|
||||
img32f_w = cv.merge([alpha] * 3).astype(np.float32)
|
||||
roi32f_w = np.full(roi_img.shape, 1.0, dtype=np.float32)
|
||||
roi32f_w -= img32f_w
|
||||
img32f = (img / 255).astype(np.float32)
|
||||
roi32f = (roi_img / 255).astype(np.float32)
|
||||
cv.multiply(img32f, img32f_w, dst=img32f)
|
||||
cv.multiply(roi32f, roi32f_w, dst=roi32f)
|
||||
roi32f += img32f
|
||||
roi_img[...] = np.round(roi32f * 255)
|
||||
|
||||
# This is quite naive implementations used as a simple reference
|
||||
# doesn't consider corner cases.
|
||||
def draw_mosaic(self, img, mos, cell_sz, decim):
|
||||
x,y,w,h = mos
|
||||
mosaic_area = img[x:x+w, y:y+h, :]
|
||||
for i in range(0, mosaic_area.shape[0], cell_sz):
|
||||
for j in range(0, mosaic_area.shape[1], cell_sz):
|
||||
cell_roi = mosaic_area[j:j+cell_sz, i:i+cell_sz, :]
|
||||
s0, s1, s2 = cv.mean(cell_roi)[:3]
|
||||
mosaic_area[j:j+cell_sz, i:i+cell_sz] = (round(s0), round(s1), round(s2))
|
||||
|
||||
def render_primitives_bgr_ref(self, img):
|
||||
cv.rectangle(img, self.rect, self.rcolor, self.rthick, self.rlt, self.rshift)
|
||||
cv.putText(img, self.text, self.org, self.ff, self.fs, self.tcolor, self.tthick, self.tlt, self.blo)
|
||||
cv.circle(img, self.center, self.radius, self.ccolor, self.cthick, self.clt, self.cshift)
|
||||
cv.line(img, self.pt1, self.pt2, self.lcolor, self.lthick, self.llt, self.lshift)
|
||||
cv.fillPoly(img, np.expand_dims(np.array([self.pts]), axis=0), self.pcolor, self.plt, self.pshift)
|
||||
self.draw_mosaic(img, self.mos, self.cell_sz, self.decim)
|
||||
self.blend_img(img, self.iorg, self.img, self.alpha)
|
||||
|
||||
def render_primitives_nv12_ref(self, y_plane, uv_plane):
|
||||
yuv = self.cvt_nv12_to_yuv(y_plane, uv_plane)
|
||||
cv.rectangle(yuv, self.rect, self.cvt_bgr_to_yuv_color(self.rcolor), self.rthick, self.rlt, self.rshift)
|
||||
cv.putText(yuv, self.text, self.org, self.ff, self.fs, self.cvt_bgr_to_yuv_color(self.tcolor), self.tthick, self.tlt, self.blo)
|
||||
cv.circle(yuv, self.center, self.radius, self.cvt_bgr_to_yuv_color(self.ccolor), self.cthick, self.clt, self.cshift)
|
||||
cv.line(yuv, self.pt1, self.pt2, self.cvt_bgr_to_yuv_color(self.lcolor), self.lthick, self.llt, self.lshift)
|
||||
cv.fillPoly(yuv, np.expand_dims(np.array([self.pts]), axis=0), self.cvt_bgr_to_yuv_color(self.pcolor), self.plt, self.pshift)
|
||||
self.draw_mosaic(yuv, self.mos, self.cell_sz, self.decim)
|
||||
self.blend_img(yuv, self.iorg, cv.cvtColor(self.img, cv.COLOR_BGR2YUV), self.alpha)
|
||||
self.cvt_yuv_to_nv12(yuv, y_plane, uv_plane)
|
||||
|
||||
def test_render_primitives_on_bgr_graph(self):
|
||||
expected = np.zeros(self.size, dtype=np.uint8)
|
||||
actual = np.array(expected, copy=True)
|
||||
|
||||
# OpenCV
|
||||
self.render_primitives_bgr_ref(expected)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_prims = cv.GArray.Prim()
|
||||
g_out = cv.gapi.wip.draw.render3ch(g_in, g_prims)
|
||||
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_in, g_prims), cv.GOut(g_out))
|
||||
actual = comp.apply(cv.gin(actual, self.prims))
|
||||
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
|
||||
|
||||
def test_render_primitives_on_bgr_function(self):
|
||||
expected = np.zeros(self.size, dtype=np.uint8)
|
||||
actual = np.array(expected, copy=True)
|
||||
|
||||
# OpenCV
|
||||
self.render_primitives_bgr_ref(expected)
|
||||
|
||||
# G-API
|
||||
cv.gapi.wip.draw.render(actual, self.prims)
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
|
||||
|
||||
def test_render_primitives_on_nv12_graph(self):
|
||||
y_expected = np.zeros((self.size[0], self.size[1], 1), dtype=np.uint8)
|
||||
uv_expected = np.zeros((self.size[0] // 2, self.size[1] // 2, 2), dtype=np.uint8)
|
||||
|
||||
y_actual = np.array(y_expected, copy=True)
|
||||
uv_actual = np.array(uv_expected, copy=True)
|
||||
|
||||
# OpenCV
|
||||
self.render_primitives_nv12_ref(y_expected, uv_expected)
|
||||
|
||||
# G-API
|
||||
g_y = cv.GMat()
|
||||
g_uv = cv.GMat()
|
||||
g_prims = cv.GArray.Prim()
|
||||
g_out_y, g_out_uv = cv.gapi.wip.draw.renderNV12(g_y, g_uv, g_prims)
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_y, g_uv, g_prims), cv.GOut(g_out_y, g_out_uv))
|
||||
y_actual, uv_actual = comp.apply(cv.gin(y_actual, uv_actual, self.prims))
|
||||
|
||||
self.assertEqual(0.0, cv.norm(y_expected, y_actual, cv.NORM_INF))
|
||||
self.assertEqual(0.0, cv.norm(uv_expected, uv_actual, cv.NORM_INF))
|
||||
|
||||
def test_render_primitives_on_nv12_function(self):
|
||||
y_expected = np.zeros((self.size[0], self.size[1], 1), dtype=np.uint8)
|
||||
uv_expected = np.zeros((self.size[0] // 2, self.size[1] // 2, 2), dtype=np.uint8)
|
||||
|
||||
y_actual = np.array(y_expected, copy=True)
|
||||
uv_actual = np.array(uv_expected, copy=True)
|
||||
|
||||
# OpenCV
|
||||
self.render_primitives_nv12_ref(y_expected, uv_expected)
|
||||
|
||||
# G-API
|
||||
cv.gapi.wip.draw.render(y_actual, uv_actual, self.prims)
|
||||
|
||||
self.assertEqual(0.0, cv.norm(y_expected, y_actual, cv.NORM_INF))
|
||||
self.assertEqual(0.0, cv.norm(uv_expected, uv_actual, cv.NORM_INF))
|
||||
|
||||
|
||||
except unittest.SkipTest as e:
|
||||
|
||||
message = str(e)
|
||||
|
||||
class TestSkip(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.skipTest('Skip tests: ' + message)
|
||||
|
||||
def test_skip():
|
||||
pass
|
||||
|
||||
pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
NewOpenCVTests.bootstrap()
|
||||
|
|
@ -3,41 +3,678 @@
|
|||
import numpy as np
|
||||
import cv2 as cv
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
|
||||
# Plaidml is an optional backend
|
||||
pkgs = [
|
||||
('ocl' , cv.gapi.core.ocl.kernels()),
|
||||
('cpu' , cv.gapi.core.cpu.kernels()),
|
||||
('fluid' , cv.gapi.core.fluid.kernels())
|
||||
# ('plaidml', cv.gapi.core.plaidml.kernels())
|
||||
]
|
||||
try:
|
||||
|
||||
if sys.version_info[:2] < (3, 0):
|
||||
raise unittest.SkipTest('Python 2.x is not supported')
|
||||
|
||||
# Plaidml is an optional backend
|
||||
pkgs = [
|
||||
('ocl' , cv.gapi.core.ocl.kernels()),
|
||||
('cpu' , cv.gapi.core.cpu.kernels()),
|
||||
('fluid' , cv.gapi.core.fluid.kernels())
|
||||
# ('plaidml', cv.gapi.core.plaidml.kernels())
|
||||
]
|
||||
|
||||
|
||||
class gapi_sample_pipelines(NewOpenCVTests):
|
||||
@cv.gapi.op('custom.add', in_types=[cv.GMat, cv.GMat, int], out_types=[cv.GMat])
|
||||
class GAdd:
|
||||
"""Calculates sum of two matrices."""
|
||||
|
||||
# NB: This test check multiple outputs for operation
|
||||
def test_mean_over_r(self):
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
in_mat = cv.imread(img_path)
|
||||
@staticmethod
|
||||
def outMeta(desc1, desc2, depth):
|
||||
return desc1
|
||||
|
||||
# # OpenCV
|
||||
_, _, r_ch = cv.split(in_mat)
|
||||
expected = cv.mean(r_ch)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
b, g, r = cv.gapi.split3(g_in)
|
||||
g_out = cv.gapi.mean(r)
|
||||
comp = cv.GComputation(g_in, g_out)
|
||||
@cv.gapi.kernel(GAdd)
|
||||
class GAddImpl:
|
||||
"""Implementation for GAdd operation."""
|
||||
|
||||
@staticmethod
|
||||
def run(img1, img2, dtype):
|
||||
return cv.add(img1, img2)
|
||||
|
||||
|
||||
@cv.gapi.op('custom.split3', in_types=[cv.GMat], out_types=[cv.GMat, cv.GMat, cv.GMat])
|
||||
class GSplit3:
|
||||
"""Divides a 3-channel matrix into 3 single-channel matrices."""
|
||||
|
||||
@staticmethod
|
||||
def outMeta(desc):
|
||||
out_desc = desc.withType(desc.depth, 1)
|
||||
return out_desc, out_desc, out_desc
|
||||
|
||||
|
||||
@cv.gapi.kernel(GSplit3)
|
||||
class GSplit3Impl:
|
||||
"""Implementation for GSplit3 operation."""
|
||||
|
||||
@staticmethod
|
||||
def run(img):
|
||||
# NB: cv.split return list but g-api requires tuple in multiple output case
|
||||
return tuple(cv.split(img))
|
||||
|
||||
|
||||
@cv.gapi.op('custom.mean', in_types=[cv.GMat], out_types=[cv.GScalar])
|
||||
class GMean:
|
||||
"""Calculates the mean value M of matrix elements."""
|
||||
|
||||
@staticmethod
|
||||
def outMeta(desc):
|
||||
return cv.empty_scalar_desc()
|
||||
|
||||
|
||||
@cv.gapi.kernel(GMean)
|
||||
class GMeanImpl:
|
||||
"""Implementation for GMean operation."""
|
||||
|
||||
@staticmethod
|
||||
def run(img):
|
||||
# NB: cv.split return list but g-api requires tuple in multiple output case
|
||||
return cv.mean(img)
|
||||
|
||||
|
||||
@cv.gapi.op('custom.addC', in_types=[cv.GMat, cv.GScalar, int], out_types=[cv.GMat])
|
||||
class GAddC:
|
||||
"""Adds a given scalar value to each element of given matrix."""
|
||||
|
||||
@staticmethod
|
||||
def outMeta(mat_desc, scalar_desc, dtype):
|
||||
return mat_desc
|
||||
|
||||
|
||||
@cv.gapi.kernel(GAddC)
|
||||
class GAddCImpl:
|
||||
"""Implementation for GAddC operation."""
|
||||
|
||||
@staticmethod
|
||||
def run(img, sc, dtype):
|
||||
# NB: dtype is just ignored in this implementation.
|
||||
# Moreover from G-API kernel got scalar as tuples with 4 elements
|
||||
# where the last element is equal to zero, just cut him for broadcasting.
|
||||
return img + np.array(sc, dtype=np.uint8)[:-1]
|
||||
|
||||
|
||||
@cv.gapi.op('custom.size', in_types=[cv.GMat], out_types=[cv.GOpaque.Size])
|
||||
class GSize:
|
||||
"""Gets dimensions from input matrix."""
|
||||
|
||||
@staticmethod
|
||||
def outMeta(mat_desc):
|
||||
return cv.empty_gopaque_desc()
|
||||
|
||||
|
||||
@cv.gapi.kernel(GSize)
|
||||
class GSizeImpl:
|
||||
"""Implementation for GSize operation."""
|
||||
|
||||
@staticmethod
|
||||
def run(img):
|
||||
# NB: Take only H, W, because the operation should return cv::Size which is 2D.
|
||||
return img.shape[:2]
|
||||
|
||||
|
||||
@cv.gapi.op('custom.sizeR', in_types=[cv.GOpaque.Rect], out_types=[cv.GOpaque.Size])
|
||||
class GSizeR:
|
||||
"""Gets dimensions from rectangle."""
|
||||
|
||||
@staticmethod
|
||||
def outMeta(opaq_desc):
|
||||
return cv.empty_gopaque_desc()
|
||||
|
||||
|
||||
@cv.gapi.kernel(GSizeR)
|
||||
class GSizeRImpl:
|
||||
"""Implementation for GSizeR operation."""
|
||||
|
||||
@staticmethod
|
||||
def run(rect):
|
||||
# NB: rect - is tuple (x, y, h, w)
|
||||
return (rect[2], rect[3])
|
||||
|
||||
|
||||
@cv.gapi.op('custom.boundingRect', in_types=[cv.GArray.Point], out_types=[cv.GOpaque.Rect])
|
||||
class GBoundingRect:
|
||||
"""Calculates minimal up-right bounding rectangle for the specified
|
||||
9 point set or non-zero pixels of gray-scale image."""
|
||||
|
||||
@staticmethod
|
||||
def outMeta(arr_desc):
|
||||
return cv.empty_gopaque_desc()
|
||||
|
||||
|
||||
@cv.gapi.kernel(GBoundingRect)
|
||||
class GBoundingRectImpl:
|
||||
"""Implementation for GBoundingRect operation."""
|
||||
|
||||
@staticmethod
|
||||
def run(array):
|
||||
# NB: OpenCV - numpy array (n_points x 2).
|
||||
# G-API - array of tuples (n_points).
|
||||
return cv.boundingRect(np.array(array))
|
||||
|
||||
|
||||
@cv.gapi.op('custom.goodFeaturesToTrack',
|
||||
in_types=[cv.GMat, int, float, float, int, bool, float],
|
||||
out_types=[cv.GArray.Point2f])
|
||||
class GGoodFeatures:
|
||||
"""Finds the most prominent corners in the image
|
||||
or in the specified image region."""
|
||||
|
||||
@staticmethod
|
||||
def outMeta(desc, max_corners, quality_lvl,
|
||||
min_distance, block_sz,
|
||||
use_harris_detector, k):
|
||||
return cv.empty_array_desc()
|
||||
|
||||
|
||||
@cv.gapi.kernel(GGoodFeatures)
|
||||
class GGoodFeaturesImpl:
|
||||
"""Implementation for GGoodFeatures operation."""
|
||||
|
||||
@staticmethod
|
||||
def run(img, max_corners, quality_lvl,
|
||||
min_distance, block_sz,
|
||||
use_harris_detector, k):
|
||||
features = cv.goodFeaturesToTrack(img, max_corners, quality_lvl,
|
||||
min_distance, mask=None,
|
||||
blockSize=block_sz,
|
||||
useHarrisDetector=use_harris_detector, k=k)
|
||||
# NB: The operation output is cv::GArray<cv::Pointf>, so it should be mapped
|
||||
# to python paramaters like this: [(1.2, 3.4), (5.2, 3.2)], because the cv::Point2f
|
||||
# according to opencv rules mapped to the tuple and cv::GArray<> mapped to the list.
|
||||
# OpenCV returns np.array with shape (n_features, 1, 2), so let's to convert it to list
|
||||
# tuples with size == n_features.
|
||||
features = list(map(tuple, features.reshape(features.shape[0], -1)))
|
||||
return features
|
||||
|
||||
|
||||
# To validate invalid cases
|
||||
def create_op(in_types, out_types):
|
||||
@cv.gapi.op('custom.op', in_types=in_types, out_types=out_types)
|
||||
class Op:
|
||||
"""Custom operation for testing."""
|
||||
|
||||
@staticmethod
|
||||
def outMeta(desc):
|
||||
raise NotImplementedError("outMeta isn't imlemented")
|
||||
return Op
|
||||
|
||||
|
||||
class gapi_sample_pipelines(NewOpenCVTests):
|
||||
|
||||
def test_custom_op_add(self):
|
||||
sz = (3, 3)
|
||||
in_mat1 = np.full(sz, 45, dtype=np.uint8)
|
||||
in_mat2 = np.full(sz, 50, dtype=np.uint8)
|
||||
|
||||
# OpenCV
|
||||
expected = cv.add(in_mat1, in_mat2)
|
||||
|
||||
# G-API
|
||||
g_in1 = cv.GMat()
|
||||
g_in2 = cv.GMat()
|
||||
g_out = GAdd.on(g_in1, g_in2, cv.CV_8UC1)
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_in1, g_in2), cv.GOut(g_out))
|
||||
|
||||
pkg = cv.gapi.kernels(GAddImpl)
|
||||
actual = comp.apply(cv.gin(in_mat1, in_mat2), args=cv.gapi.compile_args(pkg))
|
||||
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
|
||||
|
||||
|
||||
def test_custom_op_split3(self):
|
||||
sz = (4, 4)
|
||||
in_ch1 = np.full(sz, 1, dtype=np.uint8)
|
||||
in_ch2 = np.full(sz, 2, dtype=np.uint8)
|
||||
in_ch3 = np.full(sz, 3, dtype=np.uint8)
|
||||
# H x W x C
|
||||
in_mat = np.stack((in_ch1, in_ch2, in_ch3), axis=2)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_ch1, g_ch2, g_ch3 = GSplit3.on(g_in)
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_ch1, g_ch2, g_ch3))
|
||||
|
||||
pkg = cv.gapi.kernels(GSplit3Impl)
|
||||
ch1, ch2, ch3 = comp.apply(cv.gin(in_mat), args=cv.gapi.compile_args(pkg))
|
||||
|
||||
self.assertEqual(0.0, cv.norm(in_ch1, ch1, cv.NORM_INF))
|
||||
self.assertEqual(0.0, cv.norm(in_ch2, ch2, cv.NORM_INF))
|
||||
self.assertEqual(0.0, cv.norm(in_ch3, ch3, cv.NORM_INF))
|
||||
|
||||
|
||||
def test_custom_op_mean(self):
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
in_mat = cv.imread(img_path)
|
||||
|
||||
# OpenCV
|
||||
expected = cv.mean(in_mat)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_out = GMean.on(g_in)
|
||||
|
||||
comp = cv.GComputation(g_in, g_out)
|
||||
|
||||
pkg = cv.gapi.kernels(GMeanImpl)
|
||||
actual = comp.apply(cv.gin(in_mat), args=cv.gapi.compile_args(pkg))
|
||||
|
||||
for pkg_name, pkg in pkgs:
|
||||
actual = comp.apply(cv.gin(in_mat), args=cv.compile_args(pkg))
|
||||
# Comparison
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF),
|
||||
'Failed on ' + pkg_name + ' backend')
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
|
||||
def test_custom_op_addC(self):
|
||||
sz = (3, 3, 3)
|
||||
in_mat = np.full(sz, 45, dtype=np.uint8)
|
||||
sc = (50, 10, 20)
|
||||
|
||||
# Numpy reference, make array from sc to keep uint8 dtype.
|
||||
expected = in_mat + np.array(sc, dtype=np.uint8)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_sc = cv.GScalar()
|
||||
g_out = GAddC.on(g_in, g_sc, cv.CV_8UC1)
|
||||
comp = cv.GComputation(cv.GIn(g_in, g_sc), cv.GOut(g_out))
|
||||
|
||||
pkg = cv.gapi.kernels(GAddCImpl)
|
||||
actual = comp.apply(cv.gin(in_mat, sc), args=cv.gapi.compile_args(pkg))
|
||||
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
|
||||
|
||||
|
||||
def test_custom_op_size(self):
|
||||
sz = (100, 150, 3)
|
||||
in_mat = np.full(sz, 45, dtype=np.uint8)
|
||||
|
||||
# Open_cV
|
||||
expected = (100, 150)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_sz = GSize.on(g_in)
|
||||
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_sz))
|
||||
|
||||
pkg = cv.gapi.kernels(GSizeImpl)
|
||||
actual = comp.apply(cv.gin(in_mat), args=cv.gapi.compile_args(pkg))
|
||||
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
|
||||
|
||||
|
||||
def test_custom_op_sizeR(self):
|
||||
# x, y, h, w
|
||||
roi = (10, 15, 100, 150)
|
||||
|
||||
expected = (100, 150)
|
||||
|
||||
# G-API
|
||||
g_r = cv.GOpaque.Rect()
|
||||
g_sz = GSizeR.on(g_r)
|
||||
comp = cv.GComputation(cv.GIn(g_r), cv.GOut(g_sz))
|
||||
|
||||
pkg = cv.gapi.kernels(GSizeRImpl)
|
||||
actual = comp.apply(cv.gin(roi), args=cv.gapi.compile_args(pkg))
|
||||
|
||||
# cv.norm works with tuples ?
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
|
||||
|
||||
|
||||
def test_custom_op_boundingRect(self):
|
||||
points = [(0,0), (0,1), (1,0), (1,1)]
|
||||
|
||||
# OpenCV
|
||||
expected = cv.boundingRect(np.array(points))
|
||||
|
||||
# G-API
|
||||
g_pts = cv.GArray.Point()
|
||||
g_br = GBoundingRect.on(g_pts)
|
||||
comp = cv.GComputation(cv.GIn(g_pts), cv.GOut(g_br))
|
||||
|
||||
pkg = cv.gapi.kernels(GBoundingRectImpl)
|
||||
actual = comp.apply(cv.gin(points), args=cv.gapi.compile_args(pkg))
|
||||
|
||||
# cv.norm works with tuples ?
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
|
||||
|
||||
|
||||
def test_custom_op_goodFeaturesToTrack(self):
|
||||
# G-API
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
in_mat = cv.cvtColor(cv.imread(img_path), cv.COLOR_RGB2GRAY)
|
||||
|
||||
# NB: goodFeaturesToTrack configuration
|
||||
max_corners = 50
|
||||
quality_lvl = 0.01
|
||||
min_distance = 10.0
|
||||
block_sz = 3
|
||||
use_harris_detector = True
|
||||
k = 0.04
|
||||
|
||||
# OpenCV
|
||||
expected = cv.goodFeaturesToTrack(in_mat, max_corners, quality_lvl,
|
||||
min_distance, mask=None,
|
||||
blockSize=block_sz, useHarrisDetector=use_harris_detector, k=k)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_out = GGoodFeatures.on(g_in, max_corners, quality_lvl,
|
||||
min_distance, block_sz, use_harris_detector, k)
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_out))
|
||||
pkg = cv.gapi.kernels(GGoodFeaturesImpl)
|
||||
actual = comp.apply(cv.gin(in_mat), args=cv.gapi.compile_args(pkg))
|
||||
|
||||
# NB: OpenCV & G-API have different output types.
|
||||
# OpenCV - numpy array with shape (num_points, 1, 2)
|
||||
# G-API - list of tuples with size - num_points
|
||||
# Comparison
|
||||
self.assertEqual(0.0, cv.norm(expected.flatten(),
|
||||
np.array(actual, dtype=np.float32).flatten(), cv.NORM_INF))
|
||||
|
||||
|
||||
def test_invalid_op(self):
|
||||
# NB: Empty input types list
|
||||
with self.assertRaises(Exception): create_op(in_types=[], out_types=[cv.GMat])
|
||||
# NB: Empty output types list
|
||||
with self.assertRaises(Exception): create_op(in_types=[cv.GMat], out_types=[])
|
||||
|
||||
# Invalid output types
|
||||
with self.assertRaises(Exception): create_op(in_types=[cv.GMat], out_types=[int])
|
||||
with self.assertRaises(Exception): create_op(in_types=[cv.GMat], out_types=[cv.GMat, int])
|
||||
with self.assertRaises(Exception): create_op(in_types=[cv.GMat], out_types=[str, cv.GScalar])
|
||||
|
||||
|
||||
def test_invalid_op_input(self):
|
||||
# NB: Check GMat/GScalar
|
||||
with self.assertRaises(Exception): create_op([cv.GMat] , [cv.GScalar]).on(cv.GScalar())
|
||||
with self.assertRaises(Exception): create_op([cv.GScalar], [cv.GScalar]).on(cv.GMat())
|
||||
|
||||
# NB: Check GOpaque
|
||||
op = create_op([cv.GOpaque.Rect], [cv.GMat])
|
||||
with self.assertRaises(Exception): op.on(cv.GOpaque.Bool())
|
||||
with self.assertRaises(Exception): op.on(cv.GOpaque.Int())
|
||||
with self.assertRaises(Exception): op.on(cv.GOpaque.Double())
|
||||
with self.assertRaises(Exception): op.on(cv.GOpaque.Float())
|
||||
with self.assertRaises(Exception): op.on(cv.GOpaque.String())
|
||||
with self.assertRaises(Exception): op.on(cv.GOpaque.Point())
|
||||
with self.assertRaises(Exception): op.on(cv.GOpaque.Point2f())
|
||||
with self.assertRaises(Exception): op.on(cv.GOpaque.Size())
|
||||
|
||||
# NB: Check GArray
|
||||
op = create_op([cv.GArray.Rect], [cv.GMat])
|
||||
with self.assertRaises(Exception): op.on(cv.GArray.Bool())
|
||||
with self.assertRaises(Exception): op.on(cv.GArray.Int())
|
||||
with self.assertRaises(Exception): op.on(cv.GArray.Double())
|
||||
with self.assertRaises(Exception): op.on(cv.GArray.Float())
|
||||
with self.assertRaises(Exception): op.on(cv.GArray.String())
|
||||
with self.assertRaises(Exception): op.on(cv.GArray.Point())
|
||||
with self.assertRaises(Exception): op.on(cv.GArray.Point2f())
|
||||
with self.assertRaises(Exception): op.on(cv.GArray.Size())
|
||||
|
||||
# Check other possible invalid options
|
||||
with self.assertRaises(Exception): op.on(cv.GMat())
|
||||
with self.assertRaises(Exception): op.on(cv.GScalar())
|
||||
|
||||
with self.assertRaises(Exception): op.on(1)
|
||||
with self.assertRaises(Exception): op.on('foo')
|
||||
with self.assertRaises(Exception): op.on(False)
|
||||
|
||||
with self.assertRaises(Exception): create_op([cv.GMat, int], [cv.GMat]).on(cv.GMat(), 'foo')
|
||||
with self.assertRaises(Exception): create_op([cv.GMat, int], [cv.GMat]).on(cv.GMat())
|
||||
|
||||
|
||||
def test_stateful_kernel(self):
|
||||
@cv.gapi.op('custom.sum', in_types=[cv.GArray.Int], out_types=[cv.GOpaque.Int])
|
||||
class GSum:
|
||||
@staticmethod
|
||||
def outMeta(arr_desc):
|
||||
return cv.empty_gopaque_desc()
|
||||
|
||||
|
||||
@cv.gapi.kernel(GSum)
|
||||
class GSumImpl:
|
||||
last_result = 0
|
||||
|
||||
@staticmethod
|
||||
def run(arr):
|
||||
GSumImpl.last_result = sum(arr)
|
||||
return GSumImpl.last_result
|
||||
|
||||
|
||||
g_in = cv.GArray.Int()
|
||||
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(GSum.on(g_in)))
|
||||
|
||||
s = comp.apply(cv.gin([1, 2, 3, 4]), args=cv.gapi.compile_args(cv.gapi.kernels(GSumImpl)))
|
||||
self.assertEqual(10, s)
|
||||
|
||||
s = comp.apply(cv.gin([1, 2, 8, 7]), args=cv.gapi.compile_args(cv.gapi.kernels(GSumImpl)))
|
||||
self.assertEqual(18, s)
|
||||
|
||||
self.assertEqual(18, GSumImpl.last_result)
|
||||
|
||||
|
||||
def test_opaq_with_custom_type(self):
|
||||
@cv.gapi.op('custom.op', in_types=[cv.GOpaque.Any, cv.GOpaque.String], out_types=[cv.GOpaque.Any])
|
||||
class GLookUp:
|
||||
@staticmethod
|
||||
def outMeta(opaq_desc0, opaq_desc1):
|
||||
return cv.empty_gopaque_desc()
|
||||
|
||||
@cv.gapi.kernel(GLookUp)
|
||||
class GLookUpImpl:
|
||||
@staticmethod
|
||||
def run(table, key):
|
||||
return table[key]
|
||||
|
||||
|
||||
g_table = cv.GOpaque.Any()
|
||||
g_key = cv.GOpaque.String()
|
||||
g_out = GLookUp.on(g_table, g_key)
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_table, g_key), cv.GOut(g_out))
|
||||
|
||||
table = {
|
||||
'int': 42,
|
||||
'str': 'hello, world!',
|
||||
'tuple': (42, 42)
|
||||
}
|
||||
|
||||
out = comp.apply(cv.gin(table, 'int'), args=cv.gapi.compile_args(cv.gapi.kernels(GLookUpImpl)))
|
||||
self.assertEqual(42, out)
|
||||
|
||||
out = comp.apply(cv.gin(table, 'str'), args=cv.gapi.compile_args(cv.gapi.kernels(GLookUpImpl)))
|
||||
self.assertEqual('hello, world!', out)
|
||||
|
||||
out = comp.apply(cv.gin(table, 'tuple'), args=cv.gapi.compile_args(cv.gapi.kernels(GLookUpImpl)))
|
||||
self.assertEqual((42, 42), out)
|
||||
|
||||
|
||||
def test_array_with_custom_type(self):
|
||||
@cv.gapi.op('custom.op', in_types=[cv.GArray.Any, cv.GArray.Any], out_types=[cv.GArray.Any])
|
||||
class GConcat:
|
||||
@staticmethod
|
||||
def outMeta(arr_desc0, arr_desc1):
|
||||
return cv.empty_array_desc()
|
||||
|
||||
@cv.gapi.kernel(GConcat)
|
||||
class GConcatImpl:
|
||||
@staticmethod
|
||||
def run(arr0, arr1):
|
||||
return arr0 + arr1
|
||||
|
||||
g_arr0 = cv.GArray.Any()
|
||||
g_arr1 = cv.GArray.Any()
|
||||
g_out = GConcat.on(g_arr0, g_arr1)
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_arr0, g_arr1), cv.GOut(g_out))
|
||||
|
||||
arr0 = ((2, 2), 2.0)
|
||||
arr1 = (3, 'str')
|
||||
|
||||
out = comp.apply(cv.gin(arr0, arr1),
|
||||
args=cv.gapi.compile_args(cv.gapi.kernels(GConcatImpl)))
|
||||
|
||||
self.assertEqual(arr0 + arr1, out)
|
||||
|
||||
|
||||
def test_raise_in_kernel(self):
|
||||
@cv.gapi.op('custom.op', in_types=[cv.GMat, cv.GMat], out_types=[cv.GMat])
|
||||
class GAdd:
|
||||
@staticmethod
|
||||
def outMeta(desc0, desc1):
|
||||
return desc0
|
||||
|
||||
@cv.gapi.kernel(GAdd)
|
||||
class GAddImpl:
|
||||
@staticmethod
|
||||
def run(img0, img1):
|
||||
raise Exception('Error')
|
||||
return img0 + img1
|
||||
|
||||
g_in0 = cv.GMat()
|
||||
g_in1 = cv.GMat()
|
||||
g_out = GAdd.on(g_in0, g_in1)
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_in0, g_in1), cv.GOut(g_out))
|
||||
|
||||
img0 = np.array([1, 2, 3])
|
||||
img1 = np.array([1, 2, 3])
|
||||
|
||||
with self.assertRaises(Exception): comp.apply(cv.gin(img0, img1),
|
||||
args=cv.gapi.compile_args(
|
||||
cv.gapi.kernels(GAddImpl)))
|
||||
|
||||
|
||||
def test_raise_in_outMeta(self):
|
||||
@cv.gapi.op('custom.op', in_types=[cv.GMat, cv.GMat], out_types=[cv.GMat])
|
||||
class GAdd:
|
||||
@staticmethod
|
||||
def outMeta(desc0, desc1):
|
||||
raise NotImplementedError("outMeta isn't implemented")
|
||||
|
||||
@cv.gapi.kernel(GAdd)
|
||||
class GAddImpl:
|
||||
@staticmethod
|
||||
def run(img0, img1):
|
||||
return img0 + img1
|
||||
|
||||
g_in0 = cv.GMat()
|
||||
g_in1 = cv.GMat()
|
||||
g_out = GAdd.on(g_in0, g_in1)
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_in0, g_in1), cv.GOut(g_out))
|
||||
|
||||
img0 = np.array([1, 2, 3])
|
||||
img1 = np.array([1, 2, 3])
|
||||
|
||||
with self.assertRaises(Exception): comp.apply(cv.gin(img0, img1),
|
||||
args=cv.gapi.compile_args(
|
||||
cv.gapi.kernels(GAddImpl)))
|
||||
|
||||
|
||||
def test_invalid_outMeta(self):
|
||||
@cv.gapi.op('custom.op', in_types=[cv.GMat, cv.GMat], out_types=[cv.GMat])
|
||||
class GAdd:
|
||||
@staticmethod
|
||||
def outMeta(desc0, desc1):
|
||||
# Invalid outMeta
|
||||
return cv.empty_gopaque_desc()
|
||||
|
||||
@cv.gapi.kernel(GAdd)
|
||||
class GAddImpl:
|
||||
@staticmethod
|
||||
def run(img0, img1):
|
||||
return img0 + img1
|
||||
|
||||
g_in0 = cv.GMat()
|
||||
g_in1 = cv.GMat()
|
||||
g_out = GAdd.on(g_in0, g_in1)
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_in0, g_in1), cv.GOut(g_out))
|
||||
|
||||
img0 = np.array([1, 2, 3])
|
||||
img1 = np.array([1, 2, 3])
|
||||
|
||||
# FIXME: Cause Bad variant access.
|
||||
# Need to provide more descriptive error messsage.
|
||||
with self.assertRaises(Exception): comp.apply(cv.gin(img0, img1),
|
||||
args=cv.gapi.compile_args(
|
||||
cv.gapi.kernels(GAddImpl)))
|
||||
|
||||
def test_pipeline_with_custom_kernels(self):
|
||||
@cv.gapi.op('custom.resize', in_types=[cv.GMat, tuple], out_types=[cv.GMat])
|
||||
class GResize:
|
||||
@staticmethod
|
||||
def outMeta(desc, size):
|
||||
return desc.withSize(size)
|
||||
|
||||
@cv.gapi.kernel(GResize)
|
||||
class GResizeImpl:
|
||||
@staticmethod
|
||||
def run(img, size):
|
||||
return cv.resize(img, size)
|
||||
|
||||
@cv.gapi.op('custom.transpose', in_types=[cv.GMat, tuple], out_types=[cv.GMat])
|
||||
class GTranspose:
|
||||
@staticmethod
|
||||
def outMeta(desc, order):
|
||||
return desc
|
||||
|
||||
@cv.gapi.kernel(GTranspose)
|
||||
class GTransposeImpl:
|
||||
@staticmethod
|
||||
def run(img, order):
|
||||
return np.transpose(img, order)
|
||||
|
||||
img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
img = cv.imread(img_path)
|
||||
size = (32, 32)
|
||||
order = (1, 0, 2)
|
||||
|
||||
# Dummy pipeline just to validate this case:
|
||||
# gapi -> custom -> custom -> gapi
|
||||
|
||||
# OpenCV
|
||||
expected = cv.cvtColor(img, cv.COLOR_BGR2RGB)
|
||||
expected = cv.resize(expected, size)
|
||||
expected = np.transpose(expected, order)
|
||||
expected = cv.mean(expected)
|
||||
|
||||
# G-API
|
||||
g_bgr = cv.GMat()
|
||||
g_rgb = cv.gapi.BGR2RGB(g_bgr)
|
||||
g_resized = GResize.on(g_rgb, size)
|
||||
g_transposed = GTranspose.on(g_resized, order)
|
||||
g_mean = cv.gapi.mean(g_transposed)
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_bgr), cv.GOut(g_mean))
|
||||
actual = comp.apply(cv.gin(img), args=cv.gapi.compile_args(
|
||||
cv.gapi.kernels(GResizeImpl, GTransposeImpl)))
|
||||
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
|
||||
|
||||
|
||||
except unittest.SkipTest as e:
|
||||
|
||||
message = str(e)
|
||||
|
||||
class TestSkip(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.skipTest('Skip tests: ' + message)
|
||||
|
||||
def test_skip():
|
||||
pass
|
||||
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -3,199 +3,366 @@
|
|||
import numpy as np
|
||||
import cv2 as cv
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
import time
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
class test_gapi_streaming(NewOpenCVTests):
|
||||
|
||||
def test_image_input(self):
|
||||
sz = (1280, 720)
|
||||
in_mat = np.random.randint(0, 100, sz).astype(np.uint8)
|
||||
|
||||
# OpenCV
|
||||
expected = cv.medianBlur(in_mat, 3)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_out = cv.gapi.medianBlur(g_in, 3)
|
||||
c = cv.GComputation(g_in, g_out)
|
||||
ccomp = c.compileStreaming(cv.descr_of(cv.gin(in_mat)))
|
||||
ccomp.setSource(cv.gin(in_mat))
|
||||
ccomp.start()
|
||||
|
||||
_, actual = ccomp.pull()
|
||||
|
||||
# Assert
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
|
||||
try:
|
||||
if sys.version_info[:2] < (3, 0):
|
||||
raise unittest.SkipTest('Python 2.x is not supported')
|
||||
|
||||
|
||||
def test_video_input(self):
|
||||
ksize = 3
|
||||
path = self.find_file('cv/video/768x576.avi', [os.environ['OPENCV_TEST_DATA_PATH']])
|
||||
@cv.gapi.op('custom.delay', in_types=[cv.GMat], out_types=[cv.GMat])
|
||||
class GDelay:
|
||||
"""Delay for 10 ms."""
|
||||
|
||||
# OpenCV
|
||||
cap = cv.VideoCapture(path)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_out = cv.gapi.medianBlur(g_in, ksize)
|
||||
c = cv.GComputation(g_in, g_out)
|
||||
|
||||
ccomp = c.compileStreaming()
|
||||
source = cv.gapi.wip.make_capture_src(path)
|
||||
ccomp.setSource(source)
|
||||
ccomp.start()
|
||||
|
||||
# Assert
|
||||
max_num_frames = 10
|
||||
proc_num_frames = 0
|
||||
while cap.isOpened():
|
||||
has_expected, expected = cap.read()
|
||||
has_actual, actual = ccomp.pull()
|
||||
|
||||
self.assertEqual(has_expected, has_actual)
|
||||
|
||||
if not has_actual:
|
||||
break
|
||||
|
||||
self.assertEqual(0.0, cv.norm(cv.medianBlur(expected, ksize), actual, cv.NORM_INF))
|
||||
|
||||
proc_num_frames += 1
|
||||
if proc_num_frames == max_num_frames:
|
||||
break;
|
||||
@staticmethod
|
||||
def outMeta(desc):
|
||||
return desc
|
||||
|
||||
|
||||
def test_video_split3(self):
|
||||
path = self.find_file('cv/video/768x576.avi', [os.environ['OPENCV_TEST_DATA_PATH']])
|
||||
@cv.gapi.kernel(GDelay)
|
||||
class GDelayImpl:
|
||||
"""Implementation for GDelay operation."""
|
||||
|
||||
# OpenCV
|
||||
cap = cv.VideoCapture(path)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
b, g, r = cv.gapi.split3(g_in)
|
||||
c = cv.GComputation(cv.GIn(g_in), cv.GOut(b, g, r))
|
||||
|
||||
ccomp = c.compileStreaming()
|
||||
source = cv.gapi.wip.make_capture_src(path)
|
||||
ccomp.setSource(source)
|
||||
ccomp.start()
|
||||
|
||||
# Assert
|
||||
max_num_frames = 10
|
||||
proc_num_frames = 0
|
||||
while cap.isOpened():
|
||||
has_expected, frame = cap.read()
|
||||
has_actual, actual = ccomp.pull()
|
||||
|
||||
self.assertEqual(has_expected, has_actual)
|
||||
|
||||
if not has_actual:
|
||||
break
|
||||
|
||||
expected = cv.split(frame)
|
||||
for e, a in zip(expected, actual):
|
||||
self.assertEqual(0.0, cv.norm(e, a, cv.NORM_INF))
|
||||
|
||||
proc_num_frames += 1
|
||||
if proc_num_frames == max_num_frames:
|
||||
break;
|
||||
@staticmethod
|
||||
def run(img):
|
||||
time.sleep(0.01)
|
||||
return img
|
||||
|
||||
|
||||
def test_video_add(self):
|
||||
sz = (576, 768, 3)
|
||||
in_mat = np.random.randint(0, 100, sz).astype(np.uint8)
|
||||
class test_gapi_streaming(NewOpenCVTests):
|
||||
|
||||
path = self.find_file('cv/video/768x576.avi', [os.environ['OPENCV_TEST_DATA_PATH']])
|
||||
|
||||
# OpenCV
|
||||
cap = cv.VideoCapture(path)
|
||||
|
||||
# G-API
|
||||
g_in1 = cv.GMat()
|
||||
g_in2 = cv.GMat()
|
||||
out = cv.gapi.add(g_in1, g_in2)
|
||||
c = cv.GComputation(cv.GIn(g_in1, g_in2), cv.GOut(out))
|
||||
|
||||
ccomp = c.compileStreaming()
|
||||
source = cv.gapi.wip.make_capture_src(path)
|
||||
ccomp.setSource(cv.gin(source, in_mat))
|
||||
ccomp.start()
|
||||
|
||||
# Assert
|
||||
max_num_frames = 10
|
||||
proc_num_frames = 0
|
||||
while cap.isOpened():
|
||||
has_expected, frame = cap.read()
|
||||
has_actual, actual = ccomp.pull()
|
||||
|
||||
self.assertEqual(has_expected, has_actual)
|
||||
|
||||
if not has_actual:
|
||||
break
|
||||
|
||||
expected = cv.add(frame, in_mat)
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
|
||||
|
||||
proc_num_frames += 1
|
||||
if proc_num_frames == max_num_frames:
|
||||
break;
|
||||
|
||||
|
||||
def test_video_good_features_to_track(self):
|
||||
path = self.find_file('cv/video/768x576.avi', [os.environ['OPENCV_TEST_DATA_PATH']])
|
||||
|
||||
# NB: goodFeaturesToTrack configuration
|
||||
max_corners = 50
|
||||
quality_lvl = 0.01
|
||||
min_distance = 10
|
||||
block_sz = 3
|
||||
use_harris_detector = True
|
||||
k = 0.04
|
||||
mask = None
|
||||
|
||||
# OpenCV
|
||||
cap = cv.VideoCapture(path)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_gray = cv.gapi.RGB2Gray(g_in)
|
||||
g_out = cv.gapi.goodFeaturesToTrack(g_gray, max_corners, quality_lvl,
|
||||
min_distance, mask, block_sz, use_harris_detector, k)
|
||||
|
||||
c = cv.GComputation(cv.GIn(g_in), cv.GOut(g_out))
|
||||
|
||||
ccomp = c.compileStreaming()
|
||||
source = cv.gapi.wip.make_capture_src(path)
|
||||
ccomp.setSource(source)
|
||||
ccomp.start()
|
||||
|
||||
# Assert
|
||||
max_num_frames = 10
|
||||
proc_num_frames = 0
|
||||
while cap.isOpened():
|
||||
has_expected, frame = cap.read()
|
||||
has_actual, actual = ccomp.pull()
|
||||
|
||||
self.assertEqual(has_expected, has_actual)
|
||||
|
||||
if not has_actual:
|
||||
break
|
||||
def test_image_input(self):
|
||||
sz = (1280, 720)
|
||||
in_mat = np.random.randint(0, 100, sz).astype(np.uint8)
|
||||
|
||||
# OpenCV
|
||||
frame = cv.cvtColor(frame, cv.COLOR_RGB2GRAY)
|
||||
expected = cv.goodFeaturesToTrack(frame, max_corners, quality_lvl,
|
||||
min_distance, mask=mask,
|
||||
blockSize=block_sz, useHarrisDetector=use_harris_detector, k=k)
|
||||
for e, a in zip(expected, actual):
|
||||
# NB: OpenCV & G-API have different output shapes:
|
||||
# OpenCV - (num_points, 1, 2)
|
||||
# G-API - (num_points, 2)
|
||||
self.assertEqual(0.0, cv.norm(e.flatten(), a.flatten(), cv.NORM_INF))
|
||||
expected = cv.medianBlur(in_mat, 3)
|
||||
|
||||
proc_num_frames += 1
|
||||
if proc_num_frames == max_num_frames:
|
||||
break;
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_out = cv.gapi.medianBlur(g_in, 3)
|
||||
c = cv.GComputation(g_in, g_out)
|
||||
ccomp = c.compileStreaming(cv.gapi.descr_of(in_mat))
|
||||
ccomp.setSource(cv.gin(in_mat))
|
||||
ccomp.start()
|
||||
|
||||
_, actual = ccomp.pull()
|
||||
|
||||
# Assert
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
|
||||
|
||||
|
||||
def test_video_input(self):
|
||||
ksize = 3
|
||||
path = self.find_file('cv/video/768x576.avi', [os.environ['OPENCV_TEST_DATA_PATH']])
|
||||
|
||||
# OpenCV
|
||||
cap = cv.VideoCapture(path)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_out = cv.gapi.medianBlur(g_in, ksize)
|
||||
c = cv.GComputation(g_in, g_out)
|
||||
|
||||
ccomp = c.compileStreaming()
|
||||
source = cv.gapi.wip.make_capture_src(path)
|
||||
ccomp.setSource(cv.gin(source))
|
||||
ccomp.start()
|
||||
|
||||
# Assert
|
||||
max_num_frames = 10
|
||||
proc_num_frames = 0
|
||||
while cap.isOpened():
|
||||
has_expected, expected = cap.read()
|
||||
has_actual, actual = ccomp.pull()
|
||||
|
||||
self.assertEqual(has_expected, has_actual)
|
||||
|
||||
if not has_actual:
|
||||
break
|
||||
|
||||
self.assertEqual(0.0, cv.norm(cv.medianBlur(expected, ksize), actual, cv.NORM_INF))
|
||||
|
||||
proc_num_frames += 1
|
||||
if proc_num_frames == max_num_frames:
|
||||
break
|
||||
|
||||
|
||||
def test_video_split3(self):
|
||||
path = self.find_file('cv/video/768x576.avi', [os.environ['OPENCV_TEST_DATA_PATH']])
|
||||
|
||||
# OpenCV
|
||||
cap = cv.VideoCapture(path)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
b, g, r = cv.gapi.split3(g_in)
|
||||
c = cv.GComputation(cv.GIn(g_in), cv.GOut(b, g, r))
|
||||
|
||||
ccomp = c.compileStreaming()
|
||||
source = cv.gapi.wip.make_capture_src(path)
|
||||
ccomp.setSource(cv.gin(source))
|
||||
ccomp.start()
|
||||
|
||||
# Assert
|
||||
max_num_frames = 10
|
||||
proc_num_frames = 0
|
||||
while cap.isOpened():
|
||||
has_expected, frame = cap.read()
|
||||
has_actual, actual = ccomp.pull()
|
||||
|
||||
self.assertEqual(has_expected, has_actual)
|
||||
|
||||
if not has_actual:
|
||||
break
|
||||
|
||||
expected = cv.split(frame)
|
||||
for e, a in zip(expected, actual):
|
||||
self.assertEqual(0.0, cv.norm(e, a, cv.NORM_INF))
|
||||
|
||||
proc_num_frames += 1
|
||||
if proc_num_frames == max_num_frames:
|
||||
break
|
||||
|
||||
|
||||
def test_video_add(self):
|
||||
sz = (576, 768, 3)
|
||||
in_mat = np.random.randint(0, 100, sz).astype(np.uint8)
|
||||
|
||||
path = self.find_file('cv/video/768x576.avi', [os.environ['OPENCV_TEST_DATA_PATH']])
|
||||
|
||||
# OpenCV
|
||||
cap = cv.VideoCapture(path)
|
||||
|
||||
# G-API
|
||||
g_in1 = cv.GMat()
|
||||
g_in2 = cv.GMat()
|
||||
out = cv.gapi.add(g_in1, g_in2)
|
||||
c = cv.GComputation(cv.GIn(g_in1, g_in2), cv.GOut(out))
|
||||
|
||||
ccomp = c.compileStreaming()
|
||||
source = cv.gapi.wip.make_capture_src(path)
|
||||
ccomp.setSource(cv.gin(source, in_mat))
|
||||
ccomp.start()
|
||||
|
||||
# Assert
|
||||
max_num_frames = 10
|
||||
proc_num_frames = 0
|
||||
while cap.isOpened():
|
||||
has_expected, frame = cap.read()
|
||||
has_actual, actual = ccomp.pull()
|
||||
|
||||
self.assertEqual(has_expected, has_actual)
|
||||
|
||||
if not has_actual:
|
||||
break
|
||||
|
||||
expected = cv.add(frame, in_mat)
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
|
||||
|
||||
proc_num_frames += 1
|
||||
if proc_num_frames == max_num_frames:
|
||||
break
|
||||
|
||||
|
||||
def test_video_good_features_to_track(self):
|
||||
path = self.find_file('cv/video/768x576.avi', [os.environ['OPENCV_TEST_DATA_PATH']])
|
||||
|
||||
# NB: goodFeaturesToTrack configuration
|
||||
max_corners = 50
|
||||
quality_lvl = 0.01
|
||||
min_distance = 10
|
||||
block_sz = 3
|
||||
use_harris_detector = True
|
||||
k = 0.04
|
||||
mask = None
|
||||
|
||||
# OpenCV
|
||||
cap = cv.VideoCapture(path)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_gray = cv.gapi.RGB2Gray(g_in)
|
||||
g_out = cv.gapi.goodFeaturesToTrack(g_gray, max_corners, quality_lvl,
|
||||
min_distance, mask, block_sz, use_harris_detector, k)
|
||||
|
||||
c = cv.GComputation(cv.GIn(g_in), cv.GOut(g_out))
|
||||
|
||||
ccomp = c.compileStreaming()
|
||||
source = cv.gapi.wip.make_capture_src(path)
|
||||
ccomp.setSource(cv.gin(source))
|
||||
ccomp.start()
|
||||
|
||||
# Assert
|
||||
max_num_frames = 10
|
||||
proc_num_frames = 0
|
||||
while cap.isOpened():
|
||||
has_expected, frame = cap.read()
|
||||
has_actual, actual = ccomp.pull()
|
||||
|
||||
self.assertEqual(has_expected, has_actual)
|
||||
|
||||
if not has_actual:
|
||||
break
|
||||
|
||||
# OpenCV
|
||||
frame = cv.cvtColor(frame, cv.COLOR_RGB2GRAY)
|
||||
expected = cv.goodFeaturesToTrack(frame, max_corners, quality_lvl,
|
||||
min_distance, mask=mask,
|
||||
blockSize=block_sz, useHarrisDetector=use_harris_detector, k=k)
|
||||
for e, a in zip(expected, actual):
|
||||
# NB: OpenCV & G-API have different output shapes:
|
||||
# OpenCV - (num_points, 1, 2)
|
||||
# G-API - (num_points, 2)
|
||||
self.assertEqual(0.0, cv.norm(e.flatten(),
|
||||
np.array(a, np.float32).flatten(),
|
||||
cv.NORM_INF))
|
||||
|
||||
proc_num_frames += 1
|
||||
if proc_num_frames == max_num_frames:
|
||||
break
|
||||
|
||||
|
||||
def test_gapi_streaming_meta(self):
|
||||
ksize = 3
|
||||
path = self.find_file('cv/video/768x576.avi', [os.environ['OPENCV_TEST_DATA_PATH']])
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_ts = cv.gapi.streaming.timestamp(g_in)
|
||||
g_seqno = cv.gapi.streaming.seqNo(g_in)
|
||||
g_seqid = cv.gapi.streaming.seq_id(g_in)
|
||||
|
||||
c = cv.GComputation(cv.GIn(g_in), cv.GOut(g_ts, g_seqno, g_seqid))
|
||||
|
||||
ccomp = c.compileStreaming()
|
||||
source = cv.gapi.wip.make_capture_src(path)
|
||||
ccomp.setSource(cv.gin(source))
|
||||
ccomp.start()
|
||||
|
||||
# Assert
|
||||
max_num_frames = 10
|
||||
curr_frame_number = 0
|
||||
while True:
|
||||
has_frame, (ts, seqno, seqid) = ccomp.pull()
|
||||
|
||||
if not has_frame:
|
||||
break
|
||||
|
||||
self.assertEqual(curr_frame_number, seqno)
|
||||
self.assertEqual(curr_frame_number, seqid)
|
||||
|
||||
curr_frame_number += 1
|
||||
if curr_frame_number == max_num_frames:
|
||||
break
|
||||
|
||||
|
||||
def test_desync(self):
|
||||
path = self.find_file('cv/video/768x576.avi', [os.environ['OPENCV_TEST_DATA_PATH']])
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_out1 = cv.gapi.copy(g_in)
|
||||
des = cv.gapi.streaming.desync(g_in)
|
||||
g_out2 = GDelay.on(des)
|
||||
|
||||
c = cv.GComputation(cv.GIn(g_in), cv.GOut(g_out1, g_out2))
|
||||
|
||||
kernels = cv.gapi.kernels(GDelayImpl)
|
||||
ccomp = c.compileStreaming(args=cv.gapi.compile_args(kernels))
|
||||
source = cv.gapi.wip.make_capture_src(path)
|
||||
ccomp.setSource(cv.gin(source))
|
||||
ccomp.start()
|
||||
|
||||
# Assert
|
||||
max_num_frames = 10
|
||||
proc_num_frames = 0
|
||||
|
||||
out_counter = 0
|
||||
desync_out_counter = 0
|
||||
none_counter = 0
|
||||
while True:
|
||||
has_frame, (out1, out2) = ccomp.pull()
|
||||
if not has_frame:
|
||||
break
|
||||
|
||||
if not out1 is None:
|
||||
out_counter += 1
|
||||
if not out2 is None:
|
||||
desync_out_counter += 1
|
||||
else:
|
||||
none_counter += 1
|
||||
|
||||
proc_num_frames += 1
|
||||
if proc_num_frames == max_num_frames:
|
||||
ccomp.stop()
|
||||
break
|
||||
|
||||
self.assertLess(0, proc_num_frames)
|
||||
self.assertLess(desync_out_counter, out_counter)
|
||||
self.assertLess(0, none_counter)
|
||||
|
||||
|
||||
def test_compile_streaming_empty(self):
|
||||
g_in = cv.GMat()
|
||||
comp = cv.GComputation(g_in, cv.gapi.medianBlur(g_in, 3))
|
||||
comp.compileStreaming()
|
||||
|
||||
|
||||
def test_compile_streaming_args(self):
|
||||
g_in = cv.GMat()
|
||||
comp = cv.GComputation(g_in, cv.gapi.medianBlur(g_in, 3))
|
||||
comp.compileStreaming(cv.gapi.compile_args(cv.gapi.streaming.queue_capacity(1)))
|
||||
|
||||
|
||||
def test_compile_streaming_descr_of(self):
|
||||
g_in = cv.GMat()
|
||||
comp = cv.GComputation(g_in, cv.gapi.medianBlur(g_in, 3))
|
||||
img = np.zeros((3,300,300), dtype=np.float32)
|
||||
comp.compileStreaming(cv.gapi.descr_of(img))
|
||||
|
||||
|
||||
def test_compile_streaming_descr_of_and_args(self):
|
||||
g_in = cv.GMat()
|
||||
comp = cv.GComputation(g_in, cv.gapi.medianBlur(g_in, 3))
|
||||
img = np.zeros((3,300,300), dtype=np.float32)
|
||||
comp.compileStreaming(cv.gapi.descr_of(img),
|
||||
cv.gapi.compile_args(cv.gapi.streaming.queue_capacity(1)))
|
||||
|
||||
|
||||
def test_compile_streaming_meta(self):
|
||||
g_in = cv.GMat()
|
||||
comp = cv.GComputation(g_in, cv.gapi.medianBlur(g_in, 3))
|
||||
img = np.zeros((3,300,300), dtype=np.float32)
|
||||
comp.compileStreaming([cv.GMatDesc(cv.CV_8U, 3, (300, 300))])
|
||||
|
||||
|
||||
def test_compile_streaming_meta_and_args(self):
|
||||
g_in = cv.GMat()
|
||||
comp = cv.GComputation(g_in, cv.gapi.medianBlur(g_in, 3))
|
||||
img = np.zeros((3,300,300), dtype=np.float32)
|
||||
comp.compileStreaming([cv.GMatDesc(cv.CV_8U, 3, (300, 300))],
|
||||
cv.gapi.compile_args(cv.gapi.streaming.queue_capacity(1)))
|
||||
|
||||
|
||||
|
||||
except unittest.SkipTest as e:
|
||||
|
||||
message = str(e)
|
||||
|
||||
class TestSkip(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.skipTest('Skip tests: ' + message)
|
||||
|
||||
def test_skip():
|
||||
pass
|
||||
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
|
||||
try:
|
||||
|
||||
if sys.version_info[:2] < (3, 0):
|
||||
raise unittest.SkipTest('Python 2.x is not supported')
|
||||
|
||||
class gapi_types_test(NewOpenCVTests):
|
||||
|
||||
def test_garray_type(self):
|
||||
types = [cv.gapi.CV_BOOL , cv.gapi.CV_INT , cv.gapi.CV_DOUBLE , cv.gapi.CV_FLOAT,
|
||||
cv.gapi.CV_STRING, cv.gapi.CV_POINT , cv.gapi.CV_POINT2F, cv.gapi.CV_SIZE ,
|
||||
cv.gapi.CV_RECT , cv.gapi.CV_SCALAR, cv.gapi.CV_MAT , cv.gapi.CV_GMAT]
|
||||
|
||||
for t in types:
|
||||
g_array = cv.GArrayT(t)
|
||||
self.assertEqual(t, g_array.type())
|
||||
|
||||
|
||||
def test_gopaque_type(self):
|
||||
types = [cv.gapi.CV_BOOL , cv.gapi.CV_INT , cv.gapi.CV_DOUBLE , cv.gapi.CV_FLOAT,
|
||||
cv.gapi.CV_STRING, cv.gapi.CV_POINT , cv.gapi.CV_POINT2F, cv.gapi.CV_SIZE ,
|
||||
cv.gapi.CV_RECT]
|
||||
|
||||
for t in types:
|
||||
g_opaque = cv.GOpaqueT(t)
|
||||
self.assertEqual(t, g_opaque.type())
|
||||
|
||||
|
||||
except unittest.SkipTest as e:
|
||||
|
||||
message = str(e)
|
||||
|
||||
class TestSkip(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.skipTest('Skip tests: ' + message)
|
||||
|
||||
def test_skip():
|
||||
pass
|
||||
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
NewOpenCVTests.bootstrap()
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2018-2020 Intel Corporation
|
||||
// Copyright (C) 2018-2021 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_CORE_PERF_TESTS_HPP
|
||||
|
|
@ -28,14 +28,14 @@ namespace opencv_test
|
|||
//------------------------------------------------------------------------------
|
||||
|
||||
class AddPerfTest : public TestPerfParams<tuple<cv::Size, MatType, int, cv::GCompileArgs>> {};
|
||||
class AddCPerfTest : public TestPerfParams<tuple<cv::Size, MatType, int, cv::GCompileArgs>> {};
|
||||
class AddCPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, MatType, int, cv::GCompileArgs>> {};
|
||||
class SubPerfTest : public TestPerfParams<tuple<cv::Size, MatType, int, cv::GCompileArgs>> {};
|
||||
class SubCPerfTest : public TestPerfParams<tuple<cv::Size, MatType, int, cv::GCompileArgs>> {};
|
||||
class SubCPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, MatType, int, cv::GCompileArgs>> {};
|
||||
class SubRCPerfTest : public TestPerfParams<tuple<cv::Size, MatType, int, cv::GCompileArgs>> {};
|
||||
class MulPerfTest : public TestPerfParams<tuple<cv::Size, MatType, int, cv::GCompileArgs>> {};
|
||||
class MulDoublePerfTest : public TestPerfParams<tuple<cv::Size, MatType, int, cv::GCompileArgs>> {};
|
||||
class MulCPerfTest : public TestPerfParams<tuple<cv::Size, MatType, int, cv::GCompileArgs>> {};
|
||||
class DivPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, MatType, int, cv::GCompileArgs>> {};
|
||||
class MulPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, MatType, int, double, cv::GCompileArgs>> {};
|
||||
class MulDoublePerfTest : public TestPerfParams<tuple<compare_f, cv::Size, MatType, int, cv::GCompileArgs>> {};
|
||||
class MulCPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, MatType, int, cv::GCompileArgs>> {};
|
||||
class DivPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, MatType, int, double, cv::GCompileArgs>> {};
|
||||
class DivCPerfTest : public TestPerfParams<tuple<cv::Size, MatType, int, cv::GCompileArgs>> {};
|
||||
class DivRCPerfTest : public TestPerfParams<tuple<compare_f,cv::Size, MatType, int, cv::GCompileArgs>> {};
|
||||
class MaskPerfTest : public TestPerfParams<tuple<cv::Size, MatType, cv::GCompileArgs>> {};
|
||||
|
|
@ -73,8 +73,17 @@ namespace opencv_test
|
|||
class ConcatVertVecPerfTest : public TestPerfParams<tuple<cv::Size, MatType, cv::GCompileArgs>> {};
|
||||
class LUTPerfTest : public TestPerfParams<tuple<MatType, MatType, cv::Size, cv::GCompileArgs>> {};
|
||||
class ConvertToPerfTest : public TestPerfParams<tuple<compare_f, MatType, int, cv::Size, double, double, cv::GCompileArgs>> {};
|
||||
class KMeansNDPerfTest : public TestPerfParams<tuple<cv::Size, CompareMats, int,
|
||||
cv::KmeansFlags, cv::GCompileArgs>> {};
|
||||
class KMeans2DPerfTest : public TestPerfParams<tuple<int, int, cv::KmeansFlags,
|
||||
cv::GCompileArgs>> {};
|
||||
class KMeans3DPerfTest : public TestPerfParams<tuple<int, int, cv::KmeansFlags,
|
||||
cv::GCompileArgs>> {};
|
||||
class TransposePerfTest : public TestPerfParams<tuple<compare_f, cv::Size, MatType, cv::GCompileArgs>> {};
|
||||
class ResizePerfTest : public TestPerfParams<tuple<compare_f, MatType, int, cv::Size, cv::Size, cv::GCompileArgs>> {};
|
||||
class BottleneckKernelsConstInputPerfTest : public TestPerfParams<tuple<compare_f, std::string, cv::GCompileArgs>> {};
|
||||
class ResizeFxFyPerfTest : public TestPerfParams<tuple<compare_f, MatType, int, cv::Size, double, double, cv::GCompileArgs>> {};
|
||||
class ResizeInSimpleGraphPerfTest : public TestPerfParams<tuple<compare_f, MatType, cv::Size, cv::GCompileArgs>> {};
|
||||
class ParseSSDBLPerfTest : public TestPerfParams<tuple<cv::Size, float, int, cv::GCompileArgs>>, public ParserSSDTest {};
|
||||
class ParseSSDPerfTest : public TestPerfParams<tuple<cv::Size, float, bool, bool, cv::GCompileArgs>>, public ParserSSDTest {};
|
||||
class ParseYoloPerfTest : public TestPerfParams<tuple<cv::Size, float, float, int, cv::GCompileArgs>>, public ParserYoloTest {};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2018-2020 Intel Corporation
|
||||
// Copyright (C) 2018-2021 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_CORE_PERF_TESTS_INL_HPP
|
||||
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#include "gapi_core_perf_tests.hpp"
|
||||
|
||||
#include "../../test/common/gapi_core_tests_common.hpp"
|
||||
|
||||
namespace opencv_test
|
||||
{
|
||||
using namespace perf;
|
||||
|
|
@ -59,10 +61,13 @@ PERF_TEST_P_(AddPerfTest, TestPerformance)
|
|||
|
||||
PERF_TEST_P_(AddCPerfTest, TestPerformance)
|
||||
{
|
||||
Size sz = get<0>(GetParam());
|
||||
MatType type = get<1>(GetParam());
|
||||
int dtype = get<2>(GetParam());
|
||||
cv::GCompileArgs compile_args = get<3>(GetParam());
|
||||
compare_f cmpF;
|
||||
cv::Size sz;
|
||||
MatType type = -1;
|
||||
int dtype = -1;
|
||||
cv::GCompileArgs compile_args;
|
||||
|
||||
std::tie(cmpF, sz, type, dtype, compile_args) = GetParam();
|
||||
|
||||
initMatsRandU(type, sz, dtype, false);
|
||||
|
||||
|
|
@ -86,8 +91,9 @@ PERF_TEST_P_(AddCPerfTest, TestPerformance)
|
|||
}
|
||||
|
||||
// Comparison ////////////////////////////////////////////////////////////
|
||||
// FIXIT unrealiable check: EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
|
||||
EXPECT_EQ(out_mat_gapi.size(), sz);
|
||||
{
|
||||
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
|
@ -132,10 +138,13 @@ PERF_TEST_P_(SubPerfTest, TestPerformance)
|
|||
|
||||
PERF_TEST_P_(SubCPerfTest, TestPerformance)
|
||||
{
|
||||
Size sz = get<0>(GetParam());
|
||||
MatType type = get<1>(GetParam());
|
||||
int dtype = get<2>(GetParam());
|
||||
cv::GCompileArgs compile_args = get<3>(GetParam());
|
||||
compare_f cmpF;
|
||||
cv::Size sz;
|
||||
MatType type = -1;
|
||||
int dtype = -1;
|
||||
cv::GCompileArgs compile_args;
|
||||
|
||||
std::tie(cmpF, sz, type, dtype, compile_args) = GetParam();
|
||||
|
||||
initMatsRandU(type, sz, dtype, false);
|
||||
|
||||
|
|
@ -159,8 +168,9 @@ PERF_TEST_P_(SubCPerfTest, TestPerformance)
|
|||
}
|
||||
|
||||
// Comparison ////////////////////////////////////////////////////////////
|
||||
// FIXIT unrealiable check: EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
|
||||
EXPECT_EQ(out_mat_gapi.size(), sz);
|
||||
{
|
||||
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
|
@ -206,19 +216,23 @@ PERF_TEST_P_(SubRCPerfTest, TestPerformance)
|
|||
|
||||
PERF_TEST_P_(MulPerfTest, TestPerformance)
|
||||
{
|
||||
Size sz = get<0>(GetParam());
|
||||
MatType type = get<1>(GetParam());
|
||||
int dtype = get<2>(GetParam());
|
||||
cv::GCompileArgs compile_args = get<3>(GetParam());
|
||||
compare_f cmpF;
|
||||
cv::Size sz;
|
||||
MatType type = -1;
|
||||
int dtype = -1;
|
||||
double scale = 1.0;
|
||||
cv::GCompileArgs compile_args;
|
||||
|
||||
std::tie(cmpF, sz, type, dtype, scale, compile_args) = GetParam();
|
||||
|
||||
initMatsRandU(type, sz, dtype, false);
|
||||
|
||||
// OpenCV code ///////////////////////////////////////////////////////////
|
||||
cv::multiply(in_mat1, in_mat2, out_mat_ocv, 1.0, dtype);
|
||||
cv::multiply(in_mat1, in_mat2, out_mat_ocv, scale, dtype);
|
||||
|
||||
// G-API code ////////////////////////////////////////////////////////////
|
||||
cv::GMat in1, in2, out;
|
||||
out = cv::gapi::mul(in1, in2, 1.0, dtype);
|
||||
out = cv::gapi::mul(in1, in2, scale, dtype);
|
||||
cv::GComputation c(GIn(in1, in2), GOut(out));
|
||||
|
||||
// Warm-up graph engine:
|
||||
|
|
@ -232,8 +246,9 @@ PERF_TEST_P_(MulPerfTest, TestPerformance)
|
|||
}
|
||||
|
||||
// Comparison ////////////////////////////////////////////////////////////
|
||||
// FIXIT unrealiable check: EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
|
||||
EXPECT_EQ(out_mat_gapi.size(), sz);
|
||||
{
|
||||
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
|
@ -242,17 +257,21 @@ PERF_TEST_P_(MulPerfTest, TestPerformance)
|
|||
|
||||
PERF_TEST_P_(MulDoublePerfTest, TestPerformance)
|
||||
{
|
||||
Size sz = get<0>(GetParam());
|
||||
MatType type = get<1>(GetParam());
|
||||
int dtype = get<2>(GetParam());
|
||||
cv::GCompileArgs compile_args = get<3>(GetParam());
|
||||
compare_f cmpF;
|
||||
cv::Size sz;
|
||||
MatType type = -1;
|
||||
int dtype = -1;
|
||||
double scale = 1.0;
|
||||
cv::GCompileArgs compile_args;
|
||||
|
||||
std::tie(cmpF, sz, type, dtype, compile_args) = GetParam();
|
||||
|
||||
auto& rng = cv::theRNG();
|
||||
double d = rng.uniform(0.0, 10.0);
|
||||
initMatrixRandU(type, sz, dtype, false);
|
||||
|
||||
// OpenCV code ///////////////////////////////////////////////////////////
|
||||
cv::multiply(in_mat1, d, out_mat_ocv, 1, dtype);
|
||||
cv::multiply(in_mat1, d, out_mat_ocv, scale, dtype);
|
||||
|
||||
// G-API code ////////////////////////////////////////////////////////////
|
||||
cv::GMat in1, out;
|
||||
|
|
@ -270,8 +289,9 @@ PERF_TEST_P_(MulDoublePerfTest, TestPerformance)
|
|||
}
|
||||
|
||||
// Comparison ////////////////////////////////////////////////////////////
|
||||
// FIXIT unrealiable check: EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
|
||||
EXPECT_EQ(out_mat_gapi.size(), sz);
|
||||
{
|
||||
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
|
@ -280,15 +300,19 @@ PERF_TEST_P_(MulDoublePerfTest, TestPerformance)
|
|||
|
||||
PERF_TEST_P_(MulCPerfTest, TestPerformance)
|
||||
{
|
||||
Size sz = get<0>(GetParam());
|
||||
MatType type = get<1>(GetParam());
|
||||
int dtype = get<2>(GetParam());
|
||||
cv::GCompileArgs compile_args = get<3>(GetParam());
|
||||
compare_f cmpF;
|
||||
cv::Size sz;
|
||||
MatType type = -1;
|
||||
int dtype = -1;
|
||||
double scale = 1.0;
|
||||
cv::GCompileArgs compile_args;
|
||||
|
||||
std::tie(cmpF, sz, type, dtype, compile_args) = GetParam();
|
||||
|
||||
initMatsRandU(type, sz, dtype, false);
|
||||
|
||||
// OpenCV code ///////////////////////////////////////////////////////////
|
||||
cv::multiply(in_mat1, sc, out_mat_ocv, 1, dtype);
|
||||
cv::multiply(in_mat1, sc, out_mat_ocv, scale, dtype);
|
||||
|
||||
// G-API code ////////////////////////////////////////////////////////////
|
||||
cv::GMat in1, out;
|
||||
|
|
@ -307,8 +331,9 @@ PERF_TEST_P_(MulCPerfTest, TestPerformance)
|
|||
}
|
||||
|
||||
// Comparison ////////////////////////////////////////////////////////////
|
||||
// FIXIT unrealiable check: EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
|
||||
EXPECT_EQ(out_mat_gapi.size(), sz);
|
||||
{
|
||||
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
|
@ -321,17 +346,23 @@ PERF_TEST_P_(DivPerfTest, TestPerformance)
|
|||
Size sz = get<1>(GetParam());
|
||||
MatType type = get<2>(GetParam());
|
||||
int dtype = get<3>(GetParam());
|
||||
cv::GCompileArgs compile_args = get<4>(GetParam());
|
||||
double scale = get<4>(GetParam());
|
||||
cv::GCompileArgs compile_args = get<5>(GetParam());
|
||||
|
||||
// FIXIT Unstable input data for divide
|
||||
initMatsRandU(type, sz, dtype, false);
|
||||
|
||||
//This condition need to workaround bug in OpenCV.
|
||||
//It reinitializes divider matrix without zero values.
|
||||
if (dtype == CV_16S && dtype != type)
|
||||
cv::randu(in_mat2, cv::Scalar::all(1), cv::Scalar::all(255));
|
||||
|
||||
// OpenCV code ///////////////////////////////////////////////////////////
|
||||
cv::divide(in_mat1, in_mat2, out_mat_ocv, dtype);
|
||||
cv::divide(in_mat1, in_mat2, out_mat_ocv, scale, dtype);
|
||||
|
||||
// G-API code ////////////////////////////////////////////////////////////
|
||||
cv::GMat in1, in2, out;
|
||||
out = cv::gapi::div(in1, in2, dtype);
|
||||
out = cv::gapi::div(in1, in2, scale, dtype);
|
||||
cv::GComputation c(GIn(in1, in2), GOut(out));
|
||||
|
||||
// Warm-up graph engine:
|
||||
|
|
@ -345,8 +376,9 @@ PERF_TEST_P_(DivPerfTest, TestPerformance)
|
|||
}
|
||||
|
||||
// Comparison ////////////////////////////////////////////////////////////
|
||||
// FIXIT unrealiable check: EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
|
||||
EXPECT_EQ(out_mat_gapi.size(), sz);
|
||||
{
|
||||
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
|
@ -1905,6 +1937,171 @@ PERF_TEST_P_(ConvertToPerfTest, TestPerformance)
|
|||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PERF_TEST_P_(KMeansNDPerfTest, TestPerformance)
|
||||
{
|
||||
cv::Size sz;
|
||||
CompareMats cmpF;
|
||||
int K = -1;
|
||||
cv::KmeansFlags flags = cv::KMEANS_RANDOM_CENTERS;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(sz, cmpF, K, flags, compile_args) = GetParam();
|
||||
|
||||
MatType2 type = CV_32FC1;
|
||||
initMatrixRandU(type, sz, -1, false);
|
||||
|
||||
double compact_gapi = -1.;
|
||||
cv::Mat labels_gapi, centers_gapi;
|
||||
if (flags & cv::KMEANS_USE_INITIAL_LABELS)
|
||||
{
|
||||
const int amount = sz.height;
|
||||
cv::Mat bestLabels(cv::Size{1, amount}, CV_32SC1);
|
||||
cv::randu(bestLabels, 0, K);
|
||||
|
||||
cv::GComputation c(kmeansTestGAPI(in_mat1, bestLabels, K, flags, std::move(compile_args),
|
||||
compact_gapi, labels_gapi, centers_gapi));
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_mat1, bestLabels),
|
||||
cv::gout(compact_gapi, labels_gapi, centers_gapi));
|
||||
}
|
||||
kmeansTestOpenCVCompare(in_mat1, bestLabels, K, flags, compact_gapi, labels_gapi,
|
||||
centers_gapi, cmpF);
|
||||
}
|
||||
else
|
||||
{
|
||||
cv::GComputation c(kmeansTestGAPI(in_mat1, K, flags, std::move(compile_args), compact_gapi,
|
||||
labels_gapi, centers_gapi));
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_mat1), cv::gout(compact_gapi, labels_gapi, centers_gapi));
|
||||
}
|
||||
kmeansTestValidate(sz, type, K, compact_gapi, labels_gapi, centers_gapi);
|
||||
}
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(KMeans2DPerfTest, TestPerformance)
|
||||
{
|
||||
int amount = -1;
|
||||
int K = -1;
|
||||
cv::KmeansFlags flags = cv::KMEANS_RANDOM_CENTERS;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(amount, K, flags, compile_args) = GetParam();
|
||||
|
||||
std::vector<cv::Point2f> in_vector{};
|
||||
initPointsVectorRandU(amount, in_vector);
|
||||
|
||||
double compact_gapi = -1.;
|
||||
std::vector<int> labels_gapi{};
|
||||
std::vector<cv::Point2f> centers_gapi{};
|
||||
if (flags & cv::KMEANS_USE_INITIAL_LABELS)
|
||||
{
|
||||
std::vector<int> bestLabels(amount);
|
||||
cv::randu(bestLabels, 0, K);
|
||||
|
||||
cv::GComputation c(kmeansTestGAPI(in_vector, bestLabels, K, flags, std::move(compile_args),
|
||||
compact_gapi, labels_gapi, centers_gapi));
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_vector, bestLabels),
|
||||
cv::gout(compact_gapi, labels_gapi, centers_gapi));
|
||||
}
|
||||
kmeansTestOpenCVCompare(in_vector, bestLabels, K, flags, compact_gapi, labels_gapi,
|
||||
centers_gapi);
|
||||
}
|
||||
else
|
||||
{
|
||||
cv::GComputation c(kmeansTestGAPI(in_vector, K, flags, std::move(compile_args),
|
||||
compact_gapi, labels_gapi, centers_gapi));
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_vector), cv::gout(compact_gapi, labels_gapi, centers_gapi));
|
||||
}
|
||||
kmeansTestValidate({-1, amount}, -1, K, compact_gapi, labels_gapi, centers_gapi);
|
||||
}
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(KMeans3DPerfTest, TestPerformance)
|
||||
{
|
||||
int amount = -1;
|
||||
int K = -1;
|
||||
cv::KmeansFlags flags = cv::KMEANS_RANDOM_CENTERS;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(amount, K, flags, compile_args) = GetParam();
|
||||
|
||||
std::vector<cv::Point3f> in_vector{};
|
||||
initPointsVectorRandU(amount, in_vector);
|
||||
|
||||
double compact_gapi = -1.;
|
||||
std::vector<int> labels_gapi;
|
||||
std::vector<cv::Point3f> centers_gapi;
|
||||
if (flags & cv::KMEANS_USE_INITIAL_LABELS)
|
||||
{
|
||||
std::vector<int> bestLabels(amount);
|
||||
cv::randu(bestLabels, 0, K);
|
||||
|
||||
cv::GComputation c(kmeansTestGAPI(in_vector, bestLabels, K, flags, std::move(compile_args),
|
||||
compact_gapi, labels_gapi, centers_gapi));
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_vector, bestLabels),
|
||||
cv::gout(compact_gapi, labels_gapi, centers_gapi));
|
||||
}
|
||||
kmeansTestOpenCVCompare(in_vector, bestLabels, K, flags, compact_gapi, labels_gapi,
|
||||
centers_gapi);
|
||||
}
|
||||
else
|
||||
{
|
||||
cv::GComputation c(kmeansTestGAPI(in_vector, K, flags, std::move(compile_args),
|
||||
compact_gapi, labels_gapi, centers_gapi));
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_vector), cv::gout(compact_gapi, labels_gapi, centers_gapi));
|
||||
}
|
||||
kmeansTestValidate({-1, amount}, -1, K, compact_gapi, labels_gapi, centers_gapi);
|
||||
}
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PERF_TEST_P_(TransposePerfTest, TestPerformance)
|
||||
{
|
||||
compare_f cmpF;
|
||||
cv::Size sz_in;
|
||||
MatType type = -1;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(cmpF, sz_in, type, compile_args) = GetParam();
|
||||
|
||||
initMatrixRandU(type, sz_in, type, false);
|
||||
|
||||
// OpenCV code ///////////////////////////////////////////////////////////
|
||||
cv::transpose(in_mat1, out_mat_ocv);
|
||||
|
||||
// G-API code ////////////////////////////////////////////////////////////
|
||||
cv::GMat in;
|
||||
auto out = cv::gapi::transpose(in);
|
||||
cv::GComputation c(cv::GIn(in), cv::GOut(out));
|
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(cv::gin(in_mat1), cv::gout(out_mat_gapi), std::move(compile_args));
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_mat1), cv::gout(out_mat_gapi));
|
||||
}
|
||||
|
||||
// Comparison ////////////////////////////////////////////////////////////
|
||||
{
|
||||
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PERF_TEST_P_(ResizePerfTest, TestPerformance)
|
||||
{
|
||||
compare_f cmpF = get<0>(GetParam());
|
||||
|
|
@ -1984,6 +2181,89 @@ PERF_TEST_P_(ResizeFxFyPerfTest, TestPerformance)
|
|||
{
|
||||
cc(gin(in_mat1), gout(out_mat_gapi));
|
||||
}
|
||||
// Comparison ////////////////////////////////////////////////////////////
|
||||
{
|
||||
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// This test cases were created to control performance result of test scenario mentioned here:
|
||||
// https://stackoverflow.com/questions/60629331/opencv-gapi-performance-not-good-as-expected
|
||||
|
||||
PERF_TEST_P_(BottleneckKernelsConstInputPerfTest, TestPerformance)
|
||||
{
|
||||
compare_f cmpF = get<0>(GetParam());
|
||||
std::string fileName = get<1>(GetParam());
|
||||
cv::GCompileArgs compile_args = get<2>(GetParam());
|
||||
|
||||
in_mat1 = cv::imread(findDataFile(fileName));
|
||||
|
||||
cv::Mat cvvga;
|
||||
cv::Mat cvgray;
|
||||
cv::Mat cvblurred;
|
||||
|
||||
cv::resize(in_mat1, cvvga, cv::Size(), 0.5, 0.5);
|
||||
cv::cvtColor(cvvga, cvgray, cv::COLOR_BGR2GRAY);
|
||||
cv::blur(cvgray, cvblurred, cv::Size(3, 3));
|
||||
cv::Canny(cvblurred, out_mat_ocv, 32, 128, 3);
|
||||
|
||||
cv::GMat in;
|
||||
cv::GMat vga = cv::gapi::resize(in, cv::Size(), 0.5, 0.5, INTER_LINEAR);
|
||||
cv::GMat gray = cv::gapi::BGR2Gray(vga);
|
||||
cv::GMat blurred = cv::gapi::blur(gray, cv::Size(3, 3));
|
||||
cv::GMat out = cv::gapi::Canny(blurred, 32, 128, 3);
|
||||
cv::GComputation ac(in, out);
|
||||
|
||||
auto cc = ac.compile(descr_of(gin(in_mat1)),
|
||||
std::move(compile_args));
|
||||
cc(gin(in_mat1), gout(out_mat_gapi));
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
cc(gin(in_mat1), gout(out_mat_gapi));
|
||||
}
|
||||
|
||||
// Comparison ////////////////////////////////////////////////////////////
|
||||
{
|
||||
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PERF_TEST_P_(ResizeInSimpleGraphPerfTest, TestPerformance)
|
||||
{
|
||||
compare_f cmpF = get<0>(GetParam());
|
||||
MatType type = get<1>(GetParam());
|
||||
cv::Size sz_in = get<2>(GetParam());
|
||||
cv::GCompileArgs compile_args = get<3>(GetParam());
|
||||
|
||||
initMatsRandU(type, sz_in, type, false);
|
||||
|
||||
cv::Mat add_res_ocv;
|
||||
|
||||
cv::add(in_mat1, in_mat2, add_res_ocv);
|
||||
cv::resize(add_res_ocv, out_mat_ocv, cv::Size(), 0.5, 0.5);
|
||||
|
||||
cv::GMat in1, in2;
|
||||
cv::GMat add_res_gapi = cv::gapi::add(in1, in2);
|
||||
cv::GMat out = cv::gapi::resize(add_res_gapi, cv::Size(), 0.5, 0.5, INTER_LINEAR);
|
||||
cv::GComputation ac(GIn(in1, in2), GOut(out));
|
||||
|
||||
auto cc = ac.compile(descr_of(gin(in_mat1, in_mat2)),
|
||||
std::move(compile_args));
|
||||
cc(gin(in_mat1, in_mat2), gout(out_mat_gapi));
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
cc(gin(in_mat1, in_mat2), gout(out_mat_gapi));
|
||||
}
|
||||
|
||||
// Comparison ////////////////////////////////////////////////////////////
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ class ErodePerfTest : public TestPerfParams<tuple<compare_f, MatType,i
|
|||
class Erode3x3PerfTest : public TestPerfParams<tuple<compare_f, MatType,cv::Size,int, cv::GCompileArgs>> {};
|
||||
class DilatePerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int, cv::GCompileArgs>> {};
|
||||
class Dilate3x3PerfTest : public TestPerfParams<tuple<compare_f, MatType,cv::Size,int, cv::GCompileArgs>> {};
|
||||
class MorphologyExPerfTest : public TestPerfParams<tuple<compare_f,MatType,cv::Size,
|
||||
cv::MorphTypes,cv::GCompileArgs>> {};
|
||||
class SobelPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int,int,int, cv::GCompileArgs>> {};
|
||||
class SobelXYPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int,int, cv::GCompileArgs>> {};
|
||||
class LaplacianPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int,
|
||||
|
|
@ -41,6 +43,44 @@ class CannyPerfTest : public TestPerfParams<tuple<compare_f, MatType,c
|
|||
class GoodFeaturesPerfTest : public TestPerfParams<tuple<compare_vector_f<cv::Point2f>, std::string,
|
||||
int,int,double,double,int,bool,
|
||||
cv::GCompileArgs>> {};
|
||||
class FindContoursPerfTest : public TestPerfParams<tuple<CompareMats, MatType,cv::Size,
|
||||
cv::RetrievalModes,
|
||||
cv::ContourApproximationModes,
|
||||
cv::GCompileArgs>> {};
|
||||
class FindContoursHPerfTest : public TestPerfParams<tuple<CompareMats, MatType,cv::Size,
|
||||
cv::RetrievalModes,
|
||||
cv::ContourApproximationModes,
|
||||
cv::GCompileArgs>> {};
|
||||
class BoundingRectMatPerfTest :
|
||||
public TestPerfParams<tuple<CompareRects, MatType,cv::Size,bool, cv::GCompileArgs>> {};
|
||||
class BoundingRectVector32SPerfTest :
|
||||
public TestPerfParams<tuple<CompareRects, cv::Size, cv::GCompileArgs>> {};
|
||||
class BoundingRectVector32FPerfTest :
|
||||
public TestPerfParams<tuple<CompareRects, cv::Size, cv::GCompileArgs>> {};
|
||||
class FitLine2DMatVectorPerfTest : public TestPerfParams<tuple<CompareVecs<float, 4>,
|
||||
MatType,cv::Size,cv::DistanceTypes,
|
||||
cv::GCompileArgs>> {};
|
||||
class FitLine2DVector32SPerfTest : public TestPerfParams<tuple<CompareVecs<float, 4>,
|
||||
cv::Size,cv::DistanceTypes,
|
||||
cv::GCompileArgs>> {};
|
||||
class FitLine2DVector32FPerfTest : public TestPerfParams<tuple<CompareVecs<float, 4>,
|
||||
cv::Size,cv::DistanceTypes,
|
||||
cv::GCompileArgs>> {};
|
||||
class FitLine2DVector64FPerfTest : public TestPerfParams<tuple<CompareVecs<float, 4>,
|
||||
cv::Size,cv::DistanceTypes,
|
||||
cv::GCompileArgs>> {};
|
||||
class FitLine3DMatVectorPerfTest : public TestPerfParams<tuple<CompareVecs<float, 6>,
|
||||
MatType,cv::Size,cv::DistanceTypes,
|
||||
cv::GCompileArgs>> {};
|
||||
class FitLine3DVector32SPerfTest : public TestPerfParams<tuple<CompareVecs<float, 6>,
|
||||
cv::Size,cv::DistanceTypes,
|
||||
cv::GCompileArgs>> {};
|
||||
class FitLine3DVector32FPerfTest : public TestPerfParams<tuple<CompareVecs<float, 6>,
|
||||
cv::Size,cv::DistanceTypes,
|
||||
cv::GCompileArgs>> {};
|
||||
class FitLine3DVector64FPerfTest : public TestPerfParams<tuple<CompareVecs<float, 6>,
|
||||
cv::Size,cv::DistanceTypes,
|
||||
cv::GCompileArgs>> {};
|
||||
class EqHistPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
|
||||
class BGR2RGBPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
|
||||
class RGB2GrayPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include "gapi_imgproc_perf_tests.hpp"
|
||||
|
||||
#include "../../test/common/gapi_imgproc_tests_common.hpp"
|
||||
|
||||
namespace opencv_test
|
||||
{
|
||||
|
||||
|
|
@ -491,6 +493,49 @@ PERF_TEST_P_(Dilate3x3PerfTest, TestPerformance)
|
|||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PERF_TEST_P_(MorphologyExPerfTest, TestPerformance)
|
||||
{
|
||||
compare_f cmpF;
|
||||
MatType type = 0;
|
||||
cv::MorphTypes op = cv::MORPH_ERODE;
|
||||
cv::Size sz;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(cmpF, type, sz, op, compile_args) = GetParam();
|
||||
|
||||
initMatrixRandN(type, sz, type, false);
|
||||
|
||||
cv::MorphShapes defShape = cv::MORPH_RECT;
|
||||
int defKernSize = 3;
|
||||
cv::Mat kernel = cv::getStructuringElement(defShape, cv::Size(defKernSize, defKernSize));
|
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{
|
||||
cv::morphologyEx(in_mat1, out_mat_ocv, op, kernel);
|
||||
}
|
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in;
|
||||
auto out = cv::gapi::morphologyEx(in, op, kernel);
|
||||
cv::GComputation c(in, out);
|
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi, std::move(compile_args));
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(in_mat1, out_mat_gapi);
|
||||
}
|
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{
|
||||
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
|
||||
EXPECT_EQ(out_mat_gapi.size(), sz);
|
||||
}
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PERF_TEST_P_(SobelPerfTest, TestPerformance)
|
||||
{
|
||||
compare_f cmpF;
|
||||
|
|
@ -750,6 +795,332 @@ PERF_TEST_P_(GoodFeaturesPerfTest, TestPerformance)
|
|||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PERF_TEST_P_(FindContoursPerfTest, TestPerformance)
|
||||
{
|
||||
CompareMats cmpF;
|
||||
MatType type;
|
||||
cv::Size sz;
|
||||
cv::RetrievalModes mode;
|
||||
cv::ContourApproximationModes method;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(cmpF, type, sz, mode, method, compile_args) = GetParam();
|
||||
|
||||
cv::Mat in;
|
||||
initMatForFindingContours(in, sz, type);
|
||||
cv::Point offset = cv::Point();
|
||||
std::vector<cv::Vec4i> out_hier_gapi = std::vector<cv::Vec4i>();
|
||||
|
||||
std::vector<std::vector<cv::Point>> out_cnts_gapi;
|
||||
cv::GComputation c(findContoursTestGAPI(in, mode, method, std::move(compile_args),
|
||||
out_cnts_gapi, out_hier_gapi, offset));
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(gin(in, offset), gout(out_cnts_gapi));
|
||||
}
|
||||
|
||||
findContoursTestOpenCVCompare(in, mode, method, out_cnts_gapi, out_hier_gapi, cmpF);
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(FindContoursHPerfTest, TestPerformance)
|
||||
{
|
||||
CompareMats cmpF;
|
||||
MatType type;
|
||||
cv::Size sz;
|
||||
cv::RetrievalModes mode;
|
||||
cv::ContourApproximationModes method;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(cmpF, type, sz, mode, method, compile_args) = GetParam();
|
||||
|
||||
cv::Mat in;
|
||||
initMatForFindingContours(in, sz, type);
|
||||
cv::Point offset = cv::Point();
|
||||
|
||||
std::vector<std::vector<cv::Point>> out_cnts_gapi;
|
||||
std::vector<cv::Vec4i> out_hier_gapi;
|
||||
cv::GComputation c(findContoursTestGAPI<HIERARCHY>(in, mode, method, std::move(compile_args),
|
||||
out_cnts_gapi, out_hier_gapi, offset));
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(gin(in, offset), gout(out_cnts_gapi, out_hier_gapi));
|
||||
}
|
||||
|
||||
findContoursTestOpenCVCompare<HIERARCHY>(in, mode, method, out_cnts_gapi, out_hier_gapi, cmpF);
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PERF_TEST_P_(BoundingRectMatPerfTest, TestPerformance)
|
||||
{
|
||||
CompareRects cmpF;
|
||||
cv::Size sz;
|
||||
MatType type;
|
||||
bool initByVector = false;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(cmpF, type, sz, initByVector, compile_args) = GetParam();
|
||||
|
||||
if (initByVector)
|
||||
{
|
||||
initMatByPointsVectorRandU<cv::Point_>(type, sz, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
initMatrixRandU(type, sz, -1, false);
|
||||
}
|
||||
|
||||
cv::Rect out_rect_gapi;
|
||||
cv::GComputation c(boundingRectTestGAPI(in_mat1, std::move(compile_args), out_rect_gapi));
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_mat1), cv::gout(out_rect_gapi));
|
||||
}
|
||||
|
||||
boundingRectTestOpenCVCompare(in_mat1, out_rect_gapi, cmpF);
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(BoundingRectVector32SPerfTest, TestPerformance)
|
||||
{
|
||||
CompareRects cmpF;
|
||||
cv::Size sz;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(cmpF, sz, compile_args) = GetParam();
|
||||
|
||||
std::vector<cv::Point2i> in_vector;
|
||||
initPointsVectorRandU(sz.width, in_vector);
|
||||
|
||||
cv::Rect out_rect_gapi;
|
||||
cv::GComputation c(boundingRectTestGAPI(in_vector, std::move(compile_args), out_rect_gapi));
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_vector), cv::gout(out_rect_gapi));
|
||||
}
|
||||
|
||||
boundingRectTestOpenCVCompare(in_vector, out_rect_gapi, cmpF);
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(BoundingRectVector32FPerfTest, TestPerformance)
|
||||
{
|
||||
CompareRects cmpF;
|
||||
cv::Size sz;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(cmpF, sz, compile_args) = GetParam();
|
||||
|
||||
std::vector<cv::Point2f> in_vector;
|
||||
initPointsVectorRandU(sz.width, in_vector);
|
||||
|
||||
cv::Rect out_rect_gapi;
|
||||
cv::GComputation c(boundingRectTestGAPI(in_vector, std::move(compile_args), out_rect_gapi));
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_vector), cv::gout(out_rect_gapi));
|
||||
}
|
||||
|
||||
boundingRectTestOpenCVCompare(in_vector, out_rect_gapi, cmpF);
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PERF_TEST_P_(FitLine2DMatVectorPerfTest, TestPerformance)
|
||||
{
|
||||
CompareVecs<float, 4> cmpF;
|
||||
cv::Size sz;
|
||||
MatType type;
|
||||
cv::DistanceTypes distType;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(cmpF, type, sz, distType, compile_args) = GetParam();
|
||||
|
||||
initMatByPointsVectorRandU<cv::Point_>(type, sz, -1);
|
||||
|
||||
cv::Vec4f out_vec_gapi;
|
||||
cv::GComputation c(fitLineTestGAPI(in_mat1, distType, std::move(compile_args), out_vec_gapi));
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_mat1), cv::gout(out_vec_gapi));
|
||||
}
|
||||
|
||||
fitLineTestOpenCVCompare(in_mat1, distType, out_vec_gapi, cmpF);
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(FitLine2DVector32SPerfTest, TestPerformance)
|
||||
{
|
||||
CompareVecs<float, 4> cmpF;
|
||||
cv::Size sz;
|
||||
cv::DistanceTypes distType;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(cmpF, sz, distType, compile_args) = GetParam();
|
||||
|
||||
std::vector<cv::Point2i> in_vector;
|
||||
initPointsVectorRandU(sz.width, in_vector);
|
||||
|
||||
cv::Vec4f out_vec_gapi;
|
||||
cv::GComputation c(fitLineTestGAPI(in_vector, distType, std::move(compile_args),
|
||||
out_vec_gapi));
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_vector), cv::gout(out_vec_gapi));
|
||||
}
|
||||
|
||||
fitLineTestOpenCVCompare(in_vector, distType, out_vec_gapi, cmpF);
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(FitLine2DVector32FPerfTest, TestPerformance)
|
||||
{
|
||||
CompareVecs<float, 4> cmpF;
|
||||
cv::Size sz;
|
||||
cv::DistanceTypes distType;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(cmpF, sz, distType, compile_args) = GetParam();
|
||||
|
||||
std::vector<cv::Point2f> in_vector;
|
||||
initPointsVectorRandU(sz.width, in_vector);
|
||||
|
||||
cv::Vec4f out_vec_gapi;
|
||||
cv::GComputation c(fitLineTestGAPI(in_vector, distType, std::move(compile_args),
|
||||
out_vec_gapi));
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_vector), cv::gout(out_vec_gapi));
|
||||
}
|
||||
|
||||
fitLineTestOpenCVCompare(in_vector, distType, out_vec_gapi, cmpF);
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(FitLine2DVector64FPerfTest, TestPerformance)
|
||||
{
|
||||
CompareVecs<float, 4> cmpF;
|
||||
cv::Size sz;
|
||||
cv::DistanceTypes distType;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(cmpF, sz, distType, compile_args) = GetParam();
|
||||
|
||||
std::vector<cv::Point2d> in_vector;
|
||||
initPointsVectorRandU(sz.width, in_vector);
|
||||
|
||||
cv::Vec4f out_vec_gapi;
|
||||
cv::GComputation c(fitLineTestGAPI(in_vector, distType, std::move(compile_args),
|
||||
out_vec_gapi));
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_vector), cv::gout(out_vec_gapi));
|
||||
}
|
||||
|
||||
fitLineTestOpenCVCompare(in_vector, distType, out_vec_gapi, cmpF);
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(FitLine3DMatVectorPerfTest, TestPerformance)
|
||||
{
|
||||
CompareVecs<float, 6> cmpF;
|
||||
cv::Size sz;
|
||||
MatType type;
|
||||
cv::DistanceTypes distType;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(cmpF, type, sz, distType, compile_args) = GetParam();
|
||||
|
||||
initMatByPointsVectorRandU<cv::Point3_>(type, sz, -1);
|
||||
|
||||
cv::Vec6f out_vec_gapi;
|
||||
cv::GComputation c(fitLineTestGAPI(in_mat1, distType, std::move(compile_args), out_vec_gapi));
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_mat1), cv::gout(out_vec_gapi));
|
||||
}
|
||||
|
||||
fitLineTestOpenCVCompare(in_mat1, distType, out_vec_gapi, cmpF);
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(FitLine3DVector32SPerfTest, TestPerformance)
|
||||
{
|
||||
CompareVecs<float, 6> cmpF;
|
||||
cv::Size sz;
|
||||
cv::DistanceTypes distType;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(cmpF, sz, distType, compile_args) = GetParam();
|
||||
|
||||
std::vector<cv::Point3i> in_vector;
|
||||
initPointsVectorRandU(sz.width, in_vector);
|
||||
|
||||
cv::Vec6f out_vec_gapi;
|
||||
cv::GComputation c(fitLineTestGAPI(in_vector, distType, std::move(compile_args),
|
||||
out_vec_gapi));
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_vector), cv::gout(out_vec_gapi));
|
||||
}
|
||||
|
||||
fitLineTestOpenCVCompare(in_vector, distType, out_vec_gapi, cmpF);
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(FitLine3DVector32FPerfTest, TestPerformance)
|
||||
{
|
||||
CompareVecs<float, 6> cmpF;
|
||||
cv::Size sz;
|
||||
cv::DistanceTypes distType;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(cmpF, sz, distType, compile_args) = GetParam();
|
||||
|
||||
std::vector<cv::Point3f> in_vector;
|
||||
initPointsVectorRandU(sz.width, in_vector);
|
||||
|
||||
cv::Vec6f out_vec_gapi;
|
||||
cv::GComputation c(fitLineTestGAPI(in_vector, distType, std::move(compile_args),
|
||||
out_vec_gapi));
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_vector), cv::gout(out_vec_gapi));
|
||||
}
|
||||
|
||||
fitLineTestOpenCVCompare(in_vector, distType, out_vec_gapi, cmpF);
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(FitLine3DVector64FPerfTest, TestPerformance)
|
||||
{
|
||||
CompareVecs<float, 6> cmpF;
|
||||
cv::Size sz;
|
||||
cv::DistanceTypes distType;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(cmpF, sz, distType, compile_args) = GetParam();
|
||||
|
||||
std::vector<cv::Point3d> in_vector;
|
||||
initPointsVectorRandU(sz.width, in_vector);
|
||||
|
||||
cv::Vec6f out_vec_gapi;
|
||||
cv::GComputation c(fitLineTestGAPI(in_vector, distType, std::move(compile_args),
|
||||
out_vec_gapi));
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_vector), cv::gout(out_vec_gapi));
|
||||
}
|
||||
|
||||
fitLineTestOpenCVCompare(in_vector, distType, out_vec_gapi, cmpF);
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PERF_TEST_P_(EqHistPerfTest, TestPerformance)
|
||||
{
|
||||
compare_f cmpF = get<0>(GetParam());
|
||||
|
|
|
|||
|
|
@ -26,6 +26,15 @@ class OptFlowLKForPyrPerfTest : public TestPerfParams<tuple<std::string,int,tupl
|
|||
class BuildPyr_CalcOptFlow_PipelinePerfTest : public TestPerfParams<tuple<std::string,int,int,bool,
|
||||
cv::GCompileArgs>> {};
|
||||
|
||||
class BackgroundSubtractorPerfTest:
|
||||
public TestPerfParams<tuple<cv::gapi::video::BackgroundSubtractorType, std::string,
|
||||
bool, double, std::size_t, cv::GCompileArgs, CompareMats>> {};
|
||||
|
||||
class KalmanFilterControlPerfTest :
|
||||
public TestPerfParams<tuple<MatType2, int, int, size_t, bool, cv::GCompileArgs>> {};
|
||||
class KalmanFilterNoControlPerfTest :
|
||||
public TestPerfParams<tuple<MatType2, int, int, size_t, bool, cv::GCompileArgs>> {};
|
||||
|
||||
} // opencv_test
|
||||
|
||||
#endif // OPENCV_GAPI_VIDEO_PERF_TESTS_HPP
|
||||
|
|
|
|||
|
|
@ -154,6 +154,244 @@ PERF_TEST_P_(BuildPyr_CalcOptFlow_PipelinePerfTest, TestPerformance)
|
|||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifdef HAVE_OPENCV_VIDEO
|
||||
|
||||
PERF_TEST_P_(BackgroundSubtractorPerfTest, TestPerformance)
|
||||
{
|
||||
namespace gvideo = cv::gapi::video;
|
||||
|
||||
gvideo::BackgroundSubtractorType opType;
|
||||
std::string filePath = "";
|
||||
bool detectShadows = false;
|
||||
double learningRate = -1.;
|
||||
std::size_t testNumFrames = 0;
|
||||
cv::GCompileArgs compileArgs;
|
||||
CompareMats cmpF;
|
||||
|
||||
std::tie(opType, filePath, detectShadows, learningRate, testNumFrames,
|
||||
compileArgs, cmpF) = GetParam();
|
||||
|
||||
const int histLength = 500;
|
||||
double thr = -1;
|
||||
switch (opType)
|
||||
{
|
||||
case gvideo::TYPE_BS_MOG2:
|
||||
{
|
||||
thr = 16.;
|
||||
break;
|
||||
}
|
||||
case gvideo::TYPE_BS_KNN:
|
||||
{
|
||||
thr = 400.;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
FAIL() << "unsupported type of BackgroundSubtractor";
|
||||
}
|
||||
const gvideo::BackgroundSubtractorParams bsp(opType, histLength, thr, detectShadows,
|
||||
learningRate);
|
||||
|
||||
// Retrieving frames
|
||||
std::vector<cv::Mat> frames;
|
||||
frames.reserve(testNumFrames);
|
||||
{
|
||||
cv::Mat frame;
|
||||
cv::VideoCapture cap;
|
||||
if (!cap.open(findDataFile(filePath)))
|
||||
throw SkipTestException("Video file can not be opened");
|
||||
for (std::size_t i = 0; i < testNumFrames && cap.read(frame); i++)
|
||||
{
|
||||
frames.push_back(frame);
|
||||
}
|
||||
}
|
||||
GAPI_Assert(testNumFrames == frames.size() && "Can't read required number of frames");
|
||||
|
||||
// G-API graph declaration
|
||||
cv::GMat in;
|
||||
cv::GMat out = cv::gapi::BackgroundSubtractor(in, bsp);
|
||||
cv::GComputation c(cv::GIn(in), cv::GOut(out));
|
||||
auto cc = c.compile(cv::descr_of(frames[0]), std::move(compileArgs));
|
||||
|
||||
cv::Mat gapiForeground;
|
||||
TEST_CYCLE()
|
||||
{
|
||||
cc.prepareForNewStream();
|
||||
for (size_t i = 0; i < testNumFrames; i++)
|
||||
{
|
||||
cc(cv::gin(frames[i]), cv::gout(gapiForeground));
|
||||
}
|
||||
}
|
||||
|
||||
// OpenCV Background Subtractor declaration
|
||||
cv::Ptr<cv::BackgroundSubtractor> pOCVBackSub;
|
||||
if (opType == gvideo::TYPE_BS_MOG2)
|
||||
pOCVBackSub = cv::createBackgroundSubtractorMOG2(histLength, thr, detectShadows);
|
||||
else if (opType == gvideo::TYPE_BS_KNN)
|
||||
pOCVBackSub = cv::createBackgroundSubtractorKNN(histLength, thr, detectShadows);
|
||||
cv::Mat ocvForeground;
|
||||
for (size_t i = 0; i < testNumFrames; i++)
|
||||
{
|
||||
pOCVBackSub->apply(frames[i], ocvForeground, learningRate);
|
||||
}
|
||||
// Validation
|
||||
EXPECT_TRUE(cmpF(gapiForeground, ocvForeground));
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline void generateInputKalman(const int mDim, const MatType2& type,
|
||||
const size_t testNumMeasurements, const bool receiveRandMeas,
|
||||
std::vector<bool>& haveMeasurements,
|
||||
std::vector<cv::Mat>& measurements)
|
||||
{
|
||||
cv::RNG& rng = cv::theRNG();
|
||||
measurements.clear();
|
||||
haveMeasurements = std::vector<bool>(testNumMeasurements, true);
|
||||
for (size_t i = 0; i < testNumMeasurements; i++)
|
||||
{
|
||||
if (receiveRandMeas)
|
||||
{
|
||||
haveMeasurements[i] = rng(2u) == 1; // returns 0 or 1 - whether we have measurement
|
||||
// at this iteration or not
|
||||
} // if not - testing the slowest case in which we have measurements at every iteration
|
||||
|
||||
cv::Mat measurement = cv::Mat::zeros(mDim, 1, type);
|
||||
if (haveMeasurements[i])
|
||||
{
|
||||
cv::randu(measurement, cv::Scalar::all(-1), cv::Scalar::all(1));
|
||||
}
|
||||
measurements.push_back(measurement.clone());
|
||||
}
|
||||
}
|
||||
|
||||
inline void generateInputKalman(const int mDim, const int cDim, const MatType2& type,
|
||||
const size_t testNumMeasurements, const bool receiveRandMeas,
|
||||
std::vector<bool>& haveMeasurements,
|
||||
std::vector<cv::Mat>& measurements,
|
||||
std::vector<cv::Mat>& ctrls)
|
||||
{
|
||||
generateInputKalman(mDim, type, testNumMeasurements, receiveRandMeas,
|
||||
haveMeasurements, measurements);
|
||||
ctrls.clear();
|
||||
cv::Mat ctrl(cDim, 1, type);
|
||||
for (size_t i = 0; i < testNumMeasurements; i++)
|
||||
{
|
||||
cv::randu(ctrl, cv::Scalar::all(-1), cv::Scalar::all(1));
|
||||
ctrls.push_back(ctrl.clone());
|
||||
}
|
||||
}
|
||||
|
||||
PERF_TEST_P_(KalmanFilterControlPerfTest, TestPerformance)
|
||||
{
|
||||
MatType2 type = -1;
|
||||
int dDim = -1, mDim = -1;
|
||||
size_t testNumMeasurements = 0;
|
||||
bool receiveRandMeas = true;
|
||||
cv::GCompileArgs compileArgs;
|
||||
std::tie(type, dDim, mDim, testNumMeasurements, receiveRandMeas, compileArgs) = GetParam();
|
||||
|
||||
const int cDim = 2;
|
||||
cv::gapi::KalmanParams kp;
|
||||
initKalmanParams(type, dDim, mDim, cDim, kp);
|
||||
|
||||
// Generating input
|
||||
std::vector<bool> haveMeasurements;
|
||||
std::vector<cv::Mat> measurements, ctrls;
|
||||
generateInputKalman(mDim, cDim, type, testNumMeasurements, receiveRandMeas,
|
||||
haveMeasurements, measurements, ctrls);
|
||||
|
||||
// G-API graph declaration
|
||||
cv::GMat m, ctrl;
|
||||
cv::GOpaque<bool> have_m;
|
||||
cv::GMat out = cv::gapi::KalmanFilter(m, have_m, ctrl, kp);
|
||||
cv::GComputation c(cv::GIn(m, have_m, ctrl), cv::GOut(out));
|
||||
auto cc = c.compile(
|
||||
cv::descr_of(cv::gin(cv::Mat(mDim, 1, type), true, cv::Mat(cDim, 1, type))),
|
||||
std::move(compileArgs));
|
||||
|
||||
cv::Mat gapiKState(dDim, 1, type);
|
||||
TEST_CYCLE()
|
||||
{
|
||||
cc.prepareForNewStream();
|
||||
for (size_t i = 0; i < testNumMeasurements; i++)
|
||||
{
|
||||
bool hvMeas = haveMeasurements[i];
|
||||
cc(cv::gin(measurements[i], hvMeas, ctrls[i]), cv::gout(gapiKState));
|
||||
}
|
||||
}
|
||||
|
||||
// OpenCV reference KalmanFilter initialization
|
||||
cv::KalmanFilter ocvKalman(dDim, mDim, cDim, type);
|
||||
initKalmanFilter(kp, true, ocvKalman);
|
||||
|
||||
cv::Mat ocvKState(dDim, 1, type);
|
||||
for (size_t i = 0; i < testNumMeasurements; i++)
|
||||
{
|
||||
ocvKState = ocvKalman.predict(ctrls[i]);
|
||||
if (haveMeasurements[i])
|
||||
ocvKState = ocvKalman.correct(measurements[i]);
|
||||
}
|
||||
// Validation
|
||||
EXPECT_TRUE(AbsExact().to_compare_f()(gapiKState, ocvKState));
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(KalmanFilterNoControlPerfTest, TestPerformance)
|
||||
{
|
||||
MatType2 type = -1;
|
||||
int dDim = -1, mDim = -1;
|
||||
size_t testNumMeasurements = 0;
|
||||
bool receiveRandMeas = true;
|
||||
cv::GCompileArgs compileArgs;
|
||||
std::tie(type, dDim, mDim, testNumMeasurements, receiveRandMeas, compileArgs) = GetParam();
|
||||
|
||||
const int cDim = 0;
|
||||
cv::gapi::KalmanParams kp;
|
||||
initKalmanParams(type, dDim, mDim, cDim, kp);
|
||||
|
||||
// Generating input
|
||||
std::vector<bool> haveMeasurements;
|
||||
std::vector<cv::Mat> measurements;
|
||||
generateInputKalman(mDim, type, testNumMeasurements, receiveRandMeas,
|
||||
haveMeasurements, measurements);
|
||||
|
||||
// G-API graph declaration
|
||||
cv::GMat m;
|
||||
cv::GOpaque<bool> have_m;
|
||||
cv::GMat out = cv::gapi::KalmanFilter(m, have_m, kp);
|
||||
cv::GComputation c(cv::GIn(m, have_m), cv::GOut(out));
|
||||
auto cc = c.compile(cv::descr_of(cv::gin(cv::Mat(mDim, 1, type), true)),
|
||||
std::move(compileArgs));
|
||||
|
||||
cv::Mat gapiKState(dDim, 1, type);
|
||||
TEST_CYCLE()
|
||||
{
|
||||
cc.prepareForNewStream();
|
||||
for (size_t i = 0; i < testNumMeasurements; i++)
|
||||
{
|
||||
bool hvMeas = haveMeasurements[i];
|
||||
cc(cv::gin(measurements[i], hvMeas), cv::gout(gapiKState));
|
||||
}
|
||||
}
|
||||
|
||||
// OpenCV reference KalmanFilter declaration
|
||||
cv::KalmanFilter ocvKalman(dDim, mDim, cDim, type);
|
||||
initKalmanFilter(kp, false, ocvKalman);
|
||||
|
||||
cv::Mat ocvKState(dDim, 1, type);
|
||||
for (size_t i = 0; i < testNumMeasurements; i++)
|
||||
{
|
||||
ocvKState = ocvKalman.predict();
|
||||
if (haveMeasurements[i])
|
||||
ocvKState = ocvKalman.correct(measurements[i]);
|
||||
}
|
||||
// Validation
|
||||
EXPECT_TRUE(AbsExact().to_compare_f()(gapiKState, ocvKState));
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
#endif // HAVE_OPENCV_VIDEO
|
||||
|
||||
} // opencv_test
|
||||
|
||||
#endif // OPENCV_GAPI_VIDEO_PERF_TESTS_INL_HPP
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2018-2020 Intel Corporation
|
||||
// Copyright (C) 2018-2021 Intel Corporation
|
||||
|
||||
|
||||
#include "../perf_precomp.hpp"
|
||||
|
|
@ -22,7 +22,8 @@ INSTANTIATE_TEST_CASE_P(AddPerfTestCPU, AddPerfTest,
|
|||
Values(cv::compile_args(CORE_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(AddCPerfTestCPU, AddCPerfTest,
|
||||
Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(-1, CV_8U, CV_16U, CV_32F),
|
||||
Values(cv::compile_args(CORE_CPU))));
|
||||
|
|
@ -34,7 +35,8 @@ INSTANTIATE_TEST_CASE_P(SubPerfTestCPU, SubPerfTest,
|
|||
Values(cv::compile_args(CORE_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SubCPerfTestCPU, SubCPerfTest,
|
||||
Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(-1, CV_8U, CV_16U, CV_32F),
|
||||
Values(cv::compile_args(CORE_CPU))));
|
||||
|
|
@ -46,19 +48,23 @@ INSTANTIATE_TEST_CASE_P(SubRCPerfTestCPU, SubRCPerfTest,
|
|||
Values(cv::compile_args(CORE_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(MulPerfTestCPU, MulPerfTest,
|
||||
Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(-1, CV_8U, CV_16U, CV_32F),
|
||||
Values(2.0),
|
||||
Values(cv::compile_args(CORE_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(MulDoublePerfTestCPU, MulDoublePerfTest,
|
||||
Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(-1, CV_8U, CV_16U, CV_32F),
|
||||
Values(cv::compile_args(CORE_CPU))));
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(-1, CV_8U, CV_16U, CV_32F),
|
||||
Values(cv::compile_args(CORE_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(MulCPerfTestCPU, MulCPerfTest,
|
||||
Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(-1, CV_8U, CV_16U, CV_32F),
|
||||
Values(cv::compile_args(CORE_CPU))));
|
||||
|
|
@ -67,7 +73,8 @@ INSTANTIATE_TEST_CASE_P(DivPerfTestCPU, DivPerfTest,
|
|||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(-1, CV_8U, CV_16U, CV_32F),
|
||||
Values(-1, CV_8U, CV_16U, CV_16S, CV_32F),
|
||||
Values(2.3),
|
||||
Values(cv::compile_args(CORE_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(DivCPerfTestCPU, DivCPerfTest,
|
||||
|
|
@ -282,18 +289,67 @@ INSTANTIATE_TEST_CASE_P(ConvertToPerfTestCPU, ConvertToPerfTest,
|
|||
Values(0.0),
|
||||
Values(cv::compile_args(CORE_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(KMeansNDPerfTestCPU, KMeansNDPerfTest,
|
||||
Combine(Values(cv::Size(1, 20),
|
||||
cv::Size(16, 4096)),
|
||||
Values(AbsTolerance(0.01).to_compare_obj()),
|
||||
Values(5, 15),
|
||||
Values(cv::KMEANS_RANDOM_CENTERS,
|
||||
cv::KMEANS_PP_CENTERS,
|
||||
cv::KMEANS_RANDOM_CENTERS | cv::KMEANS_USE_INITIAL_LABELS,
|
||||
cv::KMEANS_PP_CENTERS | cv::KMEANS_USE_INITIAL_LABELS),
|
||||
Values(cv::compile_args(CORE_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(KMeans2DPerfTestCPU, KMeans2DPerfTest,
|
||||
Combine(Values(20, 4096),
|
||||
Values(5, 15),
|
||||
Values(cv::KMEANS_RANDOM_CENTERS,
|
||||
cv::KMEANS_PP_CENTERS,
|
||||
cv::KMEANS_RANDOM_CENTERS | cv::KMEANS_USE_INITIAL_LABELS,
|
||||
cv::KMEANS_PP_CENTERS | cv::KMEANS_USE_INITIAL_LABELS),
|
||||
Values(cv::compile_args(CORE_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(KMeans3DPerfTestCPU, KMeans3DPerfTest,
|
||||
Combine(Values(20, 4096),
|
||||
Values(5, 15),
|
||||
Values(cv::KMEANS_RANDOM_CENTERS,
|
||||
cv::KMEANS_PP_CENTERS,
|
||||
cv::KMEANS_RANDOM_CENTERS | cv::KMEANS_USE_INITIAL_LABELS,
|
||||
cv::KMEANS_PP_CENTERS | cv::KMEANS_USE_INITIAL_LABELS),
|
||||
Values(cv::compile_args(CORE_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(TransposePerfTestCPU, TransposePerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1,
|
||||
CV_8UC2, CV_16UC2, CV_16SC2, CV_32FC2,
|
||||
CV_8UC3, CV_16UC3, CV_16SC3, CV_32FC3),
|
||||
Values(cv::compile_args(CORE_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ResizePerfTestCPU, ResizePerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(CV_8UC1, CV_16UC1, CV_16SC1),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
|
||||
Values(cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_AREA),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(cv::Size(64, 64),
|
||||
cv::Size(30, 30)),
|
||||
cv::Size(32, 32)),
|
||||
Values(cv::compile_args(CORE_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(BottleneckKernelsPerfTestCPU, BottleneckKernelsConstInputPerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values("cv/optflow/frames/1080p_00.png", "cv/optflow/frames/720p_00.png",
|
||||
"cv/optflow/frames/VGA_00.png", "cv/dnn_face/recognition/Aaron_Tippin_0001.jpg"),
|
||||
Values(cv::compile_args(CORE_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ResizeInSimpleGraphPerfTestCPU, ResizeInSimpleGraphPerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(CV_8UC3),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(cv::compile_args(CORE_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ResizeFxFyPerfTestCPU, ResizeFxFyPerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(CV_8UC1, CV_16UC1, CV_16SC1),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
|
||||
Values(cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_AREA),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(0.5, 0.1),
|
||||
|
|
|
|||
|
|
@ -18,11 +18,12 @@ INSTANTIATE_TEST_CASE_P(AddPerfTestFluid, AddPerfTest,
|
|||
Values(-1, CV_8U, CV_32F),
|
||||
Values(cv::compile_args(CORE_FLUID))));
|
||||
|
||||
// INSTANTIATE_TEST_CASE_P(AddCPerfTestFluid, AddCPerfTest,
|
||||
// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
// Values(-1, CV_8U, CV_16U, CV_32F),
|
||||
// Values(cv::compile_args(CORE_FLUID))));
|
||||
INSTANTIATE_TEST_CASE_P(AddCPerfTestFluid, AddCPerfTest,
|
||||
Combine(Values(Tolerance_FloatRel_IntAbs(1e-6, 1).to_compare_f()),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(-1, CV_8U, CV_16U, CV_16S, CV_32F),
|
||||
Values(cv::compile_args(CORE_FLUID))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SubPerfTestFluid, SubPerfTest,
|
||||
Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
|
|
@ -30,11 +31,12 @@ INSTANTIATE_TEST_CASE_P(SubPerfTestFluid, SubPerfTest,
|
|||
Values(-1, CV_8U, CV_32F),
|
||||
Values(cv::compile_args(CORE_FLUID))));
|
||||
|
||||
// INSTANTIATE_TEST_CASE_P(SubCPerfTestFluid, SubCPerfTest,
|
||||
// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
// Values(-1, CV_8U, CV_16U, CV_32F),
|
||||
// Values(cv::compile_args(CORE_FLUID))));
|
||||
INSTANTIATE_TEST_CASE_P(SubCPerfTestFluid, SubCPerfTest,
|
||||
Combine(Values(Tolerance_FloatRel_IntAbs(1e-6, 1).to_compare_f()),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(-1, CV_8U, CV_16U, CV_16S, CV_32F),
|
||||
Values(cv::compile_args(CORE_FLUID))));
|
||||
|
||||
// INSTANTIATE_TEST_CASE_P(SubRCPerfTestFluid, SubRCPerfTest,
|
||||
// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
|
|
@ -42,30 +44,35 @@ INSTANTIATE_TEST_CASE_P(SubPerfTestFluid, SubPerfTest,
|
|||
// Values(-1, CV_8U, CV_16U, CV_32F),
|
||||
// Values(cv::compile_args(CORE_FLUID))));
|
||||
|
||||
// INSTANTIATE_TEST_CASE_P(MulPerfTestFluid, MulPerfTest,
|
||||
// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
// Values(-1, CV_8U, CV_16U, CV_32F),
|
||||
// Values(cv::compile_args(CORE_FLUID))));
|
||||
INSTANTIATE_TEST_CASE_P(MulPerfTestFluid, MulPerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(-1, CV_8U, CV_16U, CV_16S, CV_32F),
|
||||
Values(2.0),
|
||||
Values(cv::compile_args(CORE_FLUID))));
|
||||
|
||||
// INSTANTIATE_TEST_CASE_P(MulDoublePerfTestFluid, MulDoublePerfTest,
|
||||
// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
// Values(-1, CV_8U, CV_16U, CV_32F),
|
||||
// Values(cv::compile_args(CORE_FLUID))));
|
||||
INSTANTIATE_TEST_CASE_P(MulDoublePerfTestFluid, MulDoublePerfTest,
|
||||
Combine(Values(Tolerance_FloatRel_IntAbs(1e-6, 1).to_compare_f()),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16SC1, CV_32FC1),
|
||||
Values(-1, CV_8U, CV_32F),
|
||||
Values(cv::compile_args(CORE_FLUID))));
|
||||
|
||||
// INSTANTIATE_TEST_CASE_P(MulCPerfTestFluid, MulCPerfTest,
|
||||
// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
// Values(-1, CV_8U, CV_16U, CV_32F),
|
||||
// Values(cv::compile_args(CORE_FLUID))));
|
||||
INSTANTIATE_TEST_CASE_P(MulCPerfTestFluid, MulCPerfTest,
|
||||
Combine(Values(Tolerance_FloatRel_IntAbs(1e-6, 1).to_compare_f()),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(-1, CV_8U, CV_16U, CV_16S, CV_32F),
|
||||
Values(cv::compile_args(CORE_FLUID))));
|
||||
|
||||
// INSTANTIATE_TEST_CASE_P(DivPerfTestFluid, DivPerfTest,
|
||||
// Combine(Values(AbsExact().to_compare_f()),
|
||||
// Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
// Values(-1, CV_8U, CV_16U, CV_32F),
|
||||
// Values(cv::compile_args(CORE_FLUID))));
|
||||
INSTANTIATE_TEST_CASE_P(DivPerfTestFluid, DivPerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(-1, CV_8U, CV_16U, CV_16S, CV_32F),
|
||||
Values(2.3),
|
||||
Values(cv::compile_args(CORE_FLUID))));
|
||||
|
||||
// INSTANTIATE_TEST_CASE_P(DivCPerfTestFluid, DivCPerfTest,
|
||||
// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
|
|
@ -147,7 +154,9 @@ INSTANTIATE_TEST_CASE_P(AbsDiffPerfTestFluid, AbsDiffPerfTest,
|
|||
|
||||
INSTANTIATE_TEST_CASE_P(AbsDiffCPerfTestFluid, AbsDiffCPerfTest,
|
||||
Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
|
||||
Values(CV_8UC1, CV_16UC1, CV_16SC1, CV_8UC2,
|
||||
CV_16UC2, CV_16SC2, CV_8UC3, CV_16UC3,
|
||||
CV_16SC3, CV_8UC4, CV_16UC4, CV_16SC4),
|
||||
Values(cv::compile_args(CORE_FLUID))));
|
||||
|
||||
// INSTANTIATE_TEST_CASE_P(SumPerfTestFluid, SumPerfTest,
|
||||
|
|
@ -275,18 +284,31 @@ INSTANTIATE_TEST_CASE_P(ConvertToPerfTestFluid, ConvertToPerfTest,
|
|||
Values(cv::compile_args(CORE_FLUID))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ResizePerfTestFluid, ResizePerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(CV_8UC3/*CV_8UC1, CV_16UC1, CV_16SC1*/),
|
||||
Values(/*cv::INTER_NEAREST,*/ cv::INTER_LINEAR/*, cv::INTER_AREA*/),
|
||||
Combine(Values(Tolerance_FloatRel_IntAbs(1e-5, 1).to_compare_f()),
|
||||
Values(CV_8UC3),
|
||||
Values(cv::INTER_LINEAR),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(cv::Size(64, 64),
|
||||
cv::Size(30, 30)),
|
||||
Values(cv::compile_args(CORE_FLUID))));
|
||||
|
||||
#define IMGPROC_FLUID cv::gapi::imgproc::fluid::kernels()
|
||||
INSTANTIATE_TEST_CASE_P(BottleneckKernelsPerfTestFluid, BottleneckKernelsConstInputPerfTest,
|
||||
Combine(Values(AbsSimilarPoints(0, 1).to_compare_f()),
|
||||
Values("cv/optflow/frames/1080p_00.png", "cv/optflow/frames/720p_00.png",
|
||||
"cv/optflow/frames/VGA_00.png", "cv/dnn_face/recognition/Aaron_Tippin_0001.jpg"),
|
||||
Values(cv::compile_args(CORE_FLUID, IMGPROC_FLUID))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ResizeInSimpleGraphPerfTestFluid, ResizeInSimpleGraphPerfTest,
|
||||
Combine(Values(Tolerance_FloatRel_IntAbs(1e-5, 1).to_compare_f()),
|
||||
Values(CV_8UC3),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(cv::compile_args(CORE_FLUID, IMGPROC_FLUID))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ResizeFxFyPerfTestFluid, ResizeFxFyPerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(CV_8UC3/*CV_8UC1, CV_16UC1, CV_16SC1*/),
|
||||
Values(/*cv::INTER_NEAREST,*/ cv::INTER_LINEAR/*, cv::INTER_AREA*/),
|
||||
Combine(Values(Tolerance_FloatRel_IntAbs(1e-5, 1).to_compare_f()),
|
||||
Values(CV_8UC3),
|
||||
Values(cv::INTER_LINEAR),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(0.5, 0.1),
|
||||
Values(0.5, 0.1),
|
||||
|
|
|
|||
|
|
@ -104,6 +104,26 @@ INSTANTIATE_TEST_CASE_P(Dilate3x3PerfTestCPU, Dilate3x3PerfTest,
|
|||
Values(1, 2, 4),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(MorphologyExPerfTestCPU, MorphologyExPerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(cv::MorphTypes::MORPH_ERODE,
|
||||
cv::MorphTypes::MORPH_DILATE,
|
||||
cv::MorphTypes::MORPH_OPEN,
|
||||
cv::MorphTypes::MORPH_CLOSE,
|
||||
cv::MorphTypes::MORPH_GRADIENT,
|
||||
cv::MorphTypes::MORPH_TOPHAT,
|
||||
cv::MorphTypes::MORPH_BLACKHAT),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(MorphologyExHitMissPerfTestCPU, MorphologyExPerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(CV_8UC1),
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(cv::MorphTypes::MORPH_HITMISS),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SobelPerfTestCPU, SobelPerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
|
||||
|
|
@ -174,6 +194,126 @@ INSTANTIATE_TEST_CASE_P(GoodFeaturesInternalPerfTestCPU, GoodFeaturesPerfTest,
|
|||
Values(true),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FindContoursPerfTestCPU, FindContoursPerfTest,
|
||||
Combine(Values(AbsExact().to_compare_obj()),
|
||||
Values(CV_8UC1),
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(RETR_EXTERNAL, RETR_LIST, RETR_CCOMP, RETR_TREE),
|
||||
Values(CHAIN_APPROX_NONE, CHAIN_APPROX_SIMPLE,
|
||||
CHAIN_APPROX_TC89_L1, CHAIN_APPROX_TC89_KCOS),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FindContours32SPerfTestCPU, FindContoursPerfTest,
|
||||
Combine(Values(AbsExact().to_compare_obj()),
|
||||
Values(CV_32SC1),
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(RETR_CCOMP, RETR_FLOODFILL),
|
||||
Values(CHAIN_APPROX_NONE, CHAIN_APPROX_SIMPLE,
|
||||
CHAIN_APPROX_TC89_L1, CHAIN_APPROX_TC89_KCOS),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FindContoursHPerfTestCPU, FindContoursHPerfTest,
|
||||
Combine(Values(AbsExact().to_compare_obj()),
|
||||
Values(CV_8UC1),
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(RETR_EXTERNAL, RETR_LIST, RETR_CCOMP, RETR_TREE),
|
||||
Values(CHAIN_APPROX_NONE, CHAIN_APPROX_SIMPLE,
|
||||
CHAIN_APPROX_TC89_L1, CHAIN_APPROX_TC89_KCOS),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FindContoursH32SPerfTestCPU, FindContoursHPerfTest,
|
||||
Combine(Values(AbsExact().to_compare_obj()),
|
||||
Values(CV_32SC1),
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(RETR_CCOMP, RETR_FLOODFILL),
|
||||
Values(CHAIN_APPROX_NONE, CHAIN_APPROX_SIMPLE,
|
||||
CHAIN_APPROX_TC89_L1, CHAIN_APPROX_TC89_KCOS),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(BoundingRectMatPerfTestCPU, BoundingRectMatPerfTest,
|
||||
Combine(Values(IoUToleranceRect(0).to_compare_obj()),
|
||||
Values(CV_8UC1),
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(false),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(BoundingRectMatVectorPerfTestCPU, BoundingRectMatPerfTest,
|
||||
Combine(Values(IoUToleranceRect(1e-5).to_compare_obj()),
|
||||
Values(CV_32S, CV_32F),
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(true),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(BoundingRectVector32SPerfTestCPU, BoundingRectVector32SPerfTest,
|
||||
Combine(Values(IoUToleranceRect(0).to_compare_obj()),
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(BoundingRectVector32FPerfTestCPU, BoundingRectVector32FPerfTest,
|
||||
Combine(Values(IoUToleranceRect(1e-5).to_compare_obj()),
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FitLine2DMatVectorPerfTestCPU, FitLine2DMatVectorPerfTest,
|
||||
Combine(Values(RelDiffToleranceVec<float, 4>(0.01).to_compare_obj()),
|
||||
Values(CV_8U, CV_8S, CV_16U, CV_16S,
|
||||
CV_32S, CV_32F, CV_64F),
|
||||
Values(cv::Size(8, 0), cv::Size(1024, 0)),
|
||||
Values(DIST_L1, DIST_L2, DIST_L12, DIST_FAIR,
|
||||
DIST_WELSCH, DIST_HUBER),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FitLine2DVector32SPerfTestCPU, FitLine2DVector32SPerfTest,
|
||||
Combine(Values(RelDiffToleranceVec<float, 4>(0.01).to_compare_obj()),
|
||||
Values(cv::Size(8, 0), cv::Size(1024, 0)),
|
||||
Values(DIST_L1, DIST_L2, DIST_L12, DIST_FAIR,
|
||||
DIST_WELSCH, DIST_HUBER),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FitLine2DVector32FPerfTestCPU, FitLine2DVector32FPerfTest,
|
||||
Combine(Values(RelDiffToleranceVec<float, 4>(0.01).to_compare_obj()),
|
||||
Values(cv::Size(8, 0), cv::Size(1024, 0)),
|
||||
Values(DIST_L1, DIST_L2, DIST_L12, DIST_FAIR,
|
||||
DIST_WELSCH, DIST_HUBER),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FitLine2DVector64FPerfTestCPU, FitLine2DVector64FPerfTest,
|
||||
Combine(Values(RelDiffToleranceVec<float, 4>(0.01).to_compare_obj()),
|
||||
Values(cv::Size(8, 0), cv::Size(1024, 0)),
|
||||
Values(DIST_L1, DIST_L2, DIST_L12, DIST_FAIR,
|
||||
DIST_WELSCH, DIST_HUBER),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FitLine3DMatVectorPerfTestCPU, FitLine3DMatVectorPerfTest,
|
||||
Combine(Values(RelDiffToleranceVec<float, 6>(0.01).to_compare_obj()),
|
||||
Values(CV_8U, CV_8S, CV_16U, CV_16S,
|
||||
CV_32S, CV_32F, CV_64F),
|
||||
Values(cv::Size(8, 0), cv::Size(1024, 0)),
|
||||
Values(DIST_L1, DIST_L2, DIST_L12, DIST_FAIR,
|
||||
DIST_WELSCH, DIST_HUBER),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FitLine3DVector32SPerfTestCPU, FitLine3DVector32SPerfTest,
|
||||
Combine(Values(RelDiffToleranceVec<float, 6>(0.01).to_compare_obj()),
|
||||
Values(cv::Size(8, 0), cv::Size(1024, 0)),
|
||||
Values(DIST_L1, DIST_L2, DIST_L12, DIST_FAIR,
|
||||
DIST_WELSCH, DIST_HUBER),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FitLine3DVector32FPerfTestCPU, FitLine3DVector32FPerfTest,
|
||||
Combine(Values(RelDiffToleranceVec<float, 6>(0.01).to_compare_obj()),
|
||||
Values(cv::Size(8, 0), cv::Size(1024, 0)),
|
||||
Values(DIST_L1, DIST_L2, DIST_L12, DIST_FAIR,
|
||||
DIST_WELSCH, DIST_HUBER),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FitLine3DVector64FPerfTestCPU, FitLine3DVector64FPerfTest,
|
||||
Combine(Values(RelDiffToleranceVec<float, 6>(0.01).to_compare_obj()),
|
||||
Values(cv::Size(8, 0), cv::Size(1024, 0)),
|
||||
Values(DIST_L1, DIST_L2, DIST_L12, DIST_FAIR,
|
||||
DIST_WELSCH, DIST_HUBER),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(EqHistPerfTestCPU, EqHistPerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(OptFlowLKForPyrPerfTestCPU), OptFlowLKF
|
|||
Values(cv::TermCriteria(cv::TermCriteria::COUNT |
|
||||
cv::TermCriteria::EPS,
|
||||
30, 0.01)),
|
||||
Values(true, false),
|
||||
testing::Bool(),
|
||||
Values(cv::compile_args(VIDEO_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(OptFlowLKInternalPerfTestCPU),
|
||||
|
|
@ -90,7 +90,7 @@ INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildPyr_CalcOptFlow_PipelinePerfTestCP
|
|||
Combine(Values("cv/optflow/frames/1080p_%02d.png"),
|
||||
Values(7, 11),
|
||||
Values(1000),
|
||||
Values(true, false),
|
||||
testing::Bool(),
|
||||
Values(cv::compile_args(VIDEO_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildPyr_CalcOptFlow_PipelineInternalTestPerfCPU),
|
||||
|
|
@ -100,4 +100,33 @@ INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildPyr_CalcOptFlow_PipelineInternalTe
|
|||
Values(3),
|
||||
Values(true),
|
||||
Values(cv::compile_args(VIDEO_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BackgroundSubtractorPerfTestCPU),
|
||||
BackgroundSubtractorPerfTest,
|
||||
Combine(Values(cv::gapi::video::TYPE_BS_MOG2,
|
||||
cv::gapi::video::TYPE_BS_KNN),
|
||||
Values("cv/video/768x576.avi", "cv/video/1920x1080.avi"),
|
||||
testing::Bool(),
|
||||
Values(0., 0.5, 1.),
|
||||
Values(5),
|
||||
Values(cv::compile_args(VIDEO_CPU)),
|
||||
Values(AbsExact().to_compare_obj())));
|
||||
|
||||
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(KalmanFilterControlPerfTestCPU),
|
||||
KalmanFilterControlPerfTest,
|
||||
Combine(Values(CV_32FC1, CV_64FC1),
|
||||
Values(2, 5),
|
||||
Values(2, 5),
|
||||
Values(5),
|
||||
testing::Bool(),
|
||||
Values(cv::compile_args(VIDEO_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(KalmanFilterNoControlPerfTestCPU),
|
||||
KalmanFilterNoControlPerfTest,
|
||||
Combine(Values(CV_32FC1, CV_64FC1),
|
||||
Values(2, 5),
|
||||
Values(2, 5),
|
||||
Values(5),
|
||||
testing::Bool(),
|
||||
Values(cv::compile_args(VIDEO_CPU))));
|
||||
} // opencv_test
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ INSTANTIATE_TEST_CASE_P(AddPerfTestGPU, AddPerfTest,
|
|||
Values(cv::compile_args(CORE_GPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(AddCPerfTestGPU, AddCPerfTest,
|
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values( szSmall128, szVGA, sz720p, sz1080p ),
|
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
|
||||
Values( -1, CV_8U, CV_16U, CV_32F ),
|
||||
Values(cv::compile_args(CORE_GPU))));
|
||||
|
|
@ -32,7 +33,8 @@ INSTANTIATE_TEST_CASE_P(SubPerfTestGPU, SubPerfTest,
|
|||
Values(cv::compile_args(CORE_GPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SubCPerfTestGPU, SubCPerfTest,
|
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values( szSmall128, szVGA, sz720p, sz1080p ),
|
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
|
||||
Values( -1, CV_8U, CV_16U, CV_32F ),
|
||||
Values(cv::compile_args(CORE_GPU))));
|
||||
|
|
@ -44,28 +46,33 @@ INSTANTIATE_TEST_CASE_P(SubRCPerfTestGPU, SubRCPerfTest,
|
|||
Values(cv::compile_args(CORE_GPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(MulPerfTestGPU, MulPerfTest,
|
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values( szSmall128, szVGA, sz720p, sz1080p ),
|
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
|
||||
Values( -1, CV_8U, CV_16U, CV_32F ),
|
||||
Values(2.0),
|
||||
Values(cv::compile_args(CORE_GPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(MulDoublePerfTestGPU, MulDoublePerfTest,
|
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
|
||||
Combine(Values(Tolerance_FloatRel_IntAbs(1e-5, 1).to_compare_f()),
|
||||
Values( szSmall128, szVGA, sz720p, sz1080p ),
|
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
|
||||
Values( -1, CV_8U, CV_16U, CV_32F ),
|
||||
Values(cv::compile_args(CORE_GPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(MulCPerfTestGPU, MulCPerfTest,
|
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
|
||||
Combine(Values(Tolerance_FloatRel_IntAbs(1e-5, 1).to_compare_f()),
|
||||
Values( szSmall128, szVGA, sz720p, sz1080p ),
|
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
|
||||
Values( -1, CV_8U, CV_16U, CV_32F ),
|
||||
Values(cv::compile_args(CORE_GPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(DivPerfTestGPU, DivPerfTest,
|
||||
Combine(Values(Tolerance_FloatRel_IntAbs(1e-5, 2).to_compare_f()),
|
||||
Combine(Values(AbsTolerance(2).to_compare_f()),
|
||||
Values( szSmall128, szVGA, sz720p, sz1080p ),
|
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
|
||||
Values( -1, CV_8U, CV_16U, CV_32F ),
|
||||
Values(2.3),
|
||||
Values(cv::compile_args(CORE_GPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(DivCPerfTestGPU, DivCPerfTest,
|
||||
|
|
@ -276,6 +283,14 @@ INSTANTIATE_TEST_CASE_P(ConvertToPerfTestGPU, ConvertToPerfTest,
|
|||
Values(0.0),
|
||||
Values(cv::compile_args(CORE_GPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(TransposePerfTestGPU, TransposePerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1,
|
||||
CV_8UC2, CV_16UC2, CV_16SC2, CV_32FC2,
|
||||
CV_8UC3, CV_16UC3, CV_16SC3, CV_32FC3),
|
||||
Values(cv::compile_args(CORE_GPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ResizePerfTestGPU, ResizePerfTest,
|
||||
Combine(Values(AbsSimilarPoints(2, 0.05).to_compare_f()),
|
||||
Values(CV_8UC1, CV_16UC1, CV_16SC1),
|
||||
|
|
|
|||
83
thirdparty/fluid/modules/gapi/perf/streaming/gapi_streaming_source_perf_tests.cpp
vendored
Normal file
83
thirdparty/fluid/modules/gapi/perf/streaming/gapi_streaming_source_perf_tests.cpp
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
|
||||
#include "../perf_precomp.hpp"
|
||||
#include "../../test/common/gapi_tests_common.hpp"
|
||||
#include <opencv2/gapi/streaming/onevpl/source.hpp>
|
||||
#include <opencv2/gapi/streaming/cap.hpp>
|
||||
|
||||
namespace opencv_test
|
||||
{
|
||||
using namespace perf;
|
||||
|
||||
const std::string files[] = {
|
||||
"highgui/video/big_buck_bunny.h265",
|
||||
"highgui/video/big_buck_bunny.h264",
|
||||
};
|
||||
|
||||
const std::string codec[] = {
|
||||
"MFX_CODEC_HEVC",
|
||||
"MFX_CODEC_AVC"
|
||||
};
|
||||
|
||||
using source_t = std::string;
|
||||
using codec_t = std::string;
|
||||
using source_description_t = std::tuple<source_t, codec_t>;
|
||||
|
||||
class OneVPLSourcePerfTest : public TestPerfParams<source_description_t> {};
|
||||
class VideoCapSourcePerfTest : public TestPerfParams<source_t> {};
|
||||
|
||||
PERF_TEST_P_(OneVPLSourcePerfTest, TestPerformance)
|
||||
{
|
||||
using namespace cv::gapi::wip::onevpl;
|
||||
|
||||
const auto params = GetParam();
|
||||
source_t src = findDataFile(get<0>(params));
|
||||
codec_t type = get<1>(params);
|
||||
|
||||
std::vector<CfgParam> cfg_params {
|
||||
CfgParam::create<std::string>("mfxImplDescription.Impl", "MFX_IMPL_TYPE_HARDWARE"),
|
||||
CfgParam::create("mfxImplDescription.mfxDecoderDescription.decoder.CodecID", type),
|
||||
};
|
||||
|
||||
auto source_ptr = cv::gapi::wip::make_onevpl_src(src, cfg_params);
|
||||
|
||||
cv::gapi::wip::Data out;
|
||||
TEST_CYCLE()
|
||||
{
|
||||
source_ptr->pull(out);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P_(VideoCapSourcePerfTest, TestPerformance)
|
||||
{
|
||||
using namespace cv::gapi::wip;
|
||||
|
||||
source_t src = findDataFile(GetParam());
|
||||
auto source_ptr = make_src<GCaptureSource>(src);
|
||||
Data out;
|
||||
TEST_CYCLE()
|
||||
{
|
||||
source_ptr->pull(out);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Streaming, OneVPLSourcePerfTest,
|
||||
Values(source_description_t(files[0], codec[0]),
|
||||
source_description_t(files[1], codec[1])));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Streaming, VideoCapSourcePerfTest,
|
||||
Values(files[0],
|
||||
files[1]));
|
||||
} // namespace opencv_test
|
||||
|
||||
#endif // HAVE_ONEVPL
|
||||
|
|
@ -0,0 +1,733 @@
|
|||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <opencv2/gapi.hpp>
|
||||
#include <opencv2/gapi/core.hpp>
|
||||
#include <opencv2/gapi/imgproc.hpp>
|
||||
#include <opencv2/gapi/cpu/gcpukernel.hpp>
|
||||
#include <opencv2/gapi/infer.hpp>
|
||||
#include <opencv2/gapi/infer/ie.hpp>
|
||||
#include <opencv2/gapi/streaming/cap.hpp>
|
||||
#include <opencv2/gapi/gopaque.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
|
||||
const std::string about =
|
||||
"This is an OpenCV-based version of OMZ MTCNN Face Detection example";
|
||||
const std::string keys =
|
||||
"{ h help | | Print this help message }"
|
||||
"{ input | | Path to the input video file }"
|
||||
"{ mtcnnpm | mtcnn-p.xml | Path to OpenVINO MTCNN P (Proposal) detection model (.xml)}"
|
||||
"{ mtcnnpd | CPU | Target device for the MTCNN P (e.g. CPU, GPU, VPU, ...) }"
|
||||
"{ mtcnnrm | mtcnn-r.xml | Path to OpenVINO MTCNN R (Refinement) detection model (.xml)}"
|
||||
"{ mtcnnrd | CPU | Target device for the MTCNN R (e.g. CPU, GPU, VPU, ...) }"
|
||||
"{ mtcnnom | mtcnn-o.xml | Path to OpenVINO MTCNN O (Output) detection model (.xml)}"
|
||||
"{ mtcnnod | CPU | Target device for the MTCNN O (e.g. CPU, GPU, VPU, ...) }"
|
||||
"{ thrp | 0.6 | MTCNN P confidence threshold}"
|
||||
"{ thrr | 0.7 | MTCNN R confidence threshold}"
|
||||
"{ thro | 0.7 | MTCNN O confidence threshold}"
|
||||
"{ half_scale | false | MTCNN P use half scale pyramid}"
|
||||
"{ queue_capacity | 1 | Streaming executor queue capacity. Calculated automaticaly if 0}"
|
||||
;
|
||||
|
||||
namespace {
|
||||
std::string weights_path(const std::string& model_path) {
|
||||
const auto EXT_LEN = 4u;
|
||||
const auto sz = model_path.size();
|
||||
CV_Assert(sz > EXT_LEN);
|
||||
|
||||
const auto ext = model_path.substr(sz - EXT_LEN);
|
||||
CV_Assert(cv::toLowerCase(ext) == ".xml");
|
||||
return model_path.substr(0u, sz - EXT_LEN) + ".bin";
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
} // anonymous namespace
|
||||
|
||||
namespace custom {
|
||||
namespace {
|
||||
|
||||
// Define custom structures and operations
|
||||
#define NUM_REGRESSIONS 4
|
||||
#define NUM_PTS 5
|
||||
|
||||
struct BBox {
|
||||
int x1;
|
||||
int y1;
|
||||
int x2;
|
||||
int y2;
|
||||
|
||||
cv::Rect getRect() const { return cv::Rect(x1,
|
||||
y1,
|
||||
x2 - x1,
|
||||
y2 - y1); }
|
||||
|
||||
BBox getSquare() const {
|
||||
BBox bbox;
|
||||
float bboxWidth = static_cast<float>(x2 - x1);
|
||||
float bboxHeight = static_cast<float>(y2 - y1);
|
||||
float side = std::max(bboxWidth, bboxHeight);
|
||||
bbox.x1 = static_cast<int>(static_cast<float>(x1) + (bboxWidth - side) * 0.5f);
|
||||
bbox.y1 = static_cast<int>(static_cast<float>(y1) + (bboxHeight - side) * 0.5f);
|
||||
bbox.x2 = static_cast<int>(static_cast<float>(bbox.x1) + side);
|
||||
bbox.y2 = static_cast<int>(static_cast<float>(bbox.y1) + side);
|
||||
return bbox;
|
||||
}
|
||||
};
|
||||
|
||||
struct Face {
|
||||
BBox bbox;
|
||||
float score;
|
||||
std::array<float, NUM_REGRESSIONS> regression;
|
||||
std::array<float, 2 * NUM_PTS> ptsCoords;
|
||||
|
||||
static void applyRegression(std::vector<Face>& faces, bool addOne = false) {
|
||||
for (auto& face : faces) {
|
||||
float bboxWidth =
|
||||
face.bbox.x2 - face.bbox.x1 + static_cast<float>(addOne);
|
||||
float bboxHeight =
|
||||
face.bbox.y2 - face.bbox.y1 + static_cast<float>(addOne);
|
||||
face.bbox.x1 = static_cast<int>(static_cast<float>(face.bbox.x1) + (face.regression[1] * bboxWidth));
|
||||
face.bbox.y1 = static_cast<int>(static_cast<float>(face.bbox.y1) + (face.regression[0] * bboxHeight));
|
||||
face.bbox.x2 = static_cast<int>(static_cast<float>(face.bbox.x2) + (face.regression[3] * bboxWidth));
|
||||
face.bbox.y2 = static_cast<int>(static_cast<float>(face.bbox.y2) + (face.regression[2] * bboxHeight));
|
||||
}
|
||||
}
|
||||
|
||||
static void bboxes2Squares(std::vector<Face>& faces) {
|
||||
for (auto& face : faces) {
|
||||
face.bbox = face.bbox.getSquare();
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<Face> runNMS(std::vector<Face>& faces, const float threshold,
|
||||
const bool useMin = false) {
|
||||
std::vector<Face> facesNMS;
|
||||
if (faces.empty()) {
|
||||
return facesNMS;
|
||||
}
|
||||
|
||||
std::sort(faces.begin(), faces.end(), [](const Face& f1, const Face& f2) {
|
||||
return f1.score > f2.score;
|
||||
});
|
||||
|
||||
std::vector<int> indices(faces.size());
|
||||
std::iota(indices.begin(), indices.end(), 0);
|
||||
|
||||
while (indices.size() > 0) {
|
||||
const int idx = indices[0];
|
||||
facesNMS.push_back(faces[idx]);
|
||||
std::vector<int> tmpIndices = indices;
|
||||
indices.clear();
|
||||
const float area1 = static_cast<float>(faces[idx].bbox.x2 - faces[idx].bbox.x1 + 1) *
|
||||
static_cast<float>(faces[idx].bbox.y2 - faces[idx].bbox.y1 + 1);
|
||||
for (size_t i = 1; i < tmpIndices.size(); ++i) {
|
||||
int tmpIdx = tmpIndices[i];
|
||||
const float interX1 = static_cast<float>(std::max(faces[idx].bbox.x1, faces[tmpIdx].bbox.x1));
|
||||
const float interY1 = static_cast<float>(std::max(faces[idx].bbox.y1, faces[tmpIdx].bbox.y1));
|
||||
const float interX2 = static_cast<float>(std::min(faces[idx].bbox.x2, faces[tmpIdx].bbox.x2));
|
||||
const float interY2 = static_cast<float>(std::min(faces[idx].bbox.y2, faces[tmpIdx].bbox.y2));
|
||||
|
||||
const float bboxWidth = std::max(0.0f, (interX2 - interX1 + 1));
|
||||
const float bboxHeight = std::max(0.0f, (interY2 - interY1 + 1));
|
||||
|
||||
const float interArea = bboxWidth * bboxHeight;
|
||||
const float area2 = static_cast<float>(faces[tmpIdx].bbox.x2 - faces[tmpIdx].bbox.x1 + 1) *
|
||||
static_cast<float>(faces[tmpIdx].bbox.y2 - faces[tmpIdx].bbox.y1 + 1);
|
||||
float overlap = 0.0;
|
||||
if (useMin) {
|
||||
overlap = interArea / std::min(area1, area2);
|
||||
} else {
|
||||
overlap = interArea / (area1 + area2 - interArea);
|
||||
}
|
||||
if (overlap <= threshold) {
|
||||
indices.push_back(tmpIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
return facesNMS;
|
||||
}
|
||||
};
|
||||
|
||||
const float P_NET_WINDOW_SIZE = 12.0f;
|
||||
|
||||
std::vector<Face> buildFaces(const cv::Mat& scores,
|
||||
const cv::Mat& regressions,
|
||||
const float scaleFactor,
|
||||
const float threshold) {
|
||||
|
||||
auto w = scores.size[3];
|
||||
auto h = scores.size[2];
|
||||
auto size = w * h;
|
||||
|
||||
const float* scores_data = scores.ptr<float>();
|
||||
scores_data += size;
|
||||
|
||||
const float* reg_data = regressions.ptr<float>();
|
||||
|
||||
auto out_side = std::max(h, w);
|
||||
auto in_side = 2 * out_side + 11;
|
||||
float stride = 0.0f;
|
||||
if (out_side != 1)
|
||||
{
|
||||
stride = static_cast<float>(in_side - P_NET_WINDOW_SIZE) / static_cast<float>(out_side - 1);
|
||||
}
|
||||
|
||||
std::vector<Face> boxes;
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (scores_data[i] >= (threshold)) {
|
||||
float y = static_cast<float>(i / w);
|
||||
float x = static_cast<float>(i - w * y);
|
||||
|
||||
Face faceInfo;
|
||||
BBox& faceBox = faceInfo.bbox;
|
||||
|
||||
faceBox.x1 = std::max(0, static_cast<int>((x * stride) / scaleFactor));
|
||||
faceBox.y1 = std::max(0, static_cast<int>((y * stride) / scaleFactor));
|
||||
faceBox.x2 = static_cast<int>((x * stride + P_NET_WINDOW_SIZE - 1.0f) / scaleFactor);
|
||||
faceBox.y2 = static_cast<int>((y * stride + P_NET_WINDOW_SIZE - 1.0f) / scaleFactor);
|
||||
faceInfo.regression[0] = reg_data[i];
|
||||
faceInfo.regression[1] = reg_data[i + size];
|
||||
faceInfo.regression[2] = reg_data[i + 2 * size];
|
||||
faceInfo.regression[3] = reg_data[i + 3 * size];
|
||||
faceInfo.score = scores_data[i];
|
||||
boxes.push_back(faceInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return boxes;
|
||||
}
|
||||
|
||||
// Define networks for this sample
|
||||
using GMat2 = std::tuple<cv::GMat, cv::GMat>;
|
||||
using GMat3 = std::tuple<cv::GMat, cv::GMat, cv::GMat>;
|
||||
using GMats = cv::GArray<cv::GMat>;
|
||||
using GRects = cv::GArray<cv::Rect>;
|
||||
using GSize = cv::GOpaque<cv::Size>;
|
||||
|
||||
G_API_NET(MTCNNRefinement,
|
||||
<GMat2(cv::GMat)>,
|
||||
"sample.custom.mtcnn_refinement");
|
||||
|
||||
G_API_NET(MTCNNOutput,
|
||||
<GMat3(cv::GMat)>,
|
||||
"sample.custom.mtcnn_output");
|
||||
|
||||
using GFaces = cv::GArray<Face>;
|
||||
G_API_OP(BuildFaces,
|
||||
<GFaces(cv::GMat, cv::GMat, float, float)>,
|
||||
"sample.custom.mtcnn.build_faces") {
|
||||
static cv::GArrayDesc outMeta(const cv::GMatDesc&,
|
||||
const cv::GMatDesc&,
|
||||
const float,
|
||||
const float) {
|
||||
return cv::empty_array_desc();
|
||||
}
|
||||
};
|
||||
|
||||
G_API_OP(RunNMS,
|
||||
<GFaces(GFaces, float, bool)>,
|
||||
"sample.custom.mtcnn.run_nms") {
|
||||
static cv::GArrayDesc outMeta(const cv::GArrayDesc&,
|
||||
const float, const bool) {
|
||||
return cv::empty_array_desc();
|
||||
}
|
||||
};
|
||||
|
||||
G_API_OP(AccumulatePyramidOutputs,
|
||||
<GFaces(GFaces, GFaces)>,
|
||||
"sample.custom.mtcnn.accumulate_pyramid_outputs") {
|
||||
static cv::GArrayDesc outMeta(const cv::GArrayDesc&,
|
||||
const cv::GArrayDesc&) {
|
||||
return cv::empty_array_desc();
|
||||
}
|
||||
};
|
||||
|
||||
G_API_OP(ApplyRegression,
|
||||
<GFaces(GFaces, bool)>,
|
||||
"sample.custom.mtcnn.apply_regression") {
|
||||
static cv::GArrayDesc outMeta(const cv::GArrayDesc&, const bool) {
|
||||
return cv::empty_array_desc();
|
||||
}
|
||||
};
|
||||
|
||||
G_API_OP(BBoxesToSquares,
|
||||
<GFaces(GFaces)>,
|
||||
"sample.custom.mtcnn.bboxes_to_squares") {
|
||||
static cv::GArrayDesc outMeta(const cv::GArrayDesc&) {
|
||||
return cv::empty_array_desc();
|
||||
}
|
||||
};
|
||||
|
||||
G_API_OP(R_O_NetPreProcGetROIs,
|
||||
<GRects(GFaces, GSize)>,
|
||||
"sample.custom.mtcnn.bboxes_r_o_net_preproc_get_rois") {
|
||||
static cv::GArrayDesc outMeta(const cv::GArrayDesc&, const cv::GOpaqueDesc&) {
|
||||
return cv::empty_array_desc();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
G_API_OP(RNetPostProc,
|
||||
<GFaces(GFaces, GMats, GMats, float)>,
|
||||
"sample.custom.mtcnn.rnet_postproc") {
|
||||
static cv::GArrayDesc outMeta(const cv::GArrayDesc&,
|
||||
const cv::GArrayDesc&,
|
||||
const cv::GArrayDesc&,
|
||||
const float) {
|
||||
return cv::empty_array_desc();
|
||||
}
|
||||
};
|
||||
|
||||
G_API_OP(ONetPostProc,
|
||||
<GFaces(GFaces, GMats, GMats, GMats, float)>,
|
||||
"sample.custom.mtcnn.onet_postproc") {
|
||||
static cv::GArrayDesc outMeta(const cv::GArrayDesc&,
|
||||
const cv::GArrayDesc&,
|
||||
const cv::GArrayDesc&,
|
||||
const cv::GArrayDesc&,
|
||||
const float) {
|
||||
return cv::empty_array_desc();
|
||||
}
|
||||
};
|
||||
|
||||
G_API_OP(SwapFaces,
|
||||
<GFaces(GFaces)>,
|
||||
"sample.custom.mtcnn.swap_faces") {
|
||||
static cv::GArrayDesc outMeta(const cv::GArrayDesc&) {
|
||||
return cv::empty_array_desc();
|
||||
}
|
||||
};
|
||||
|
||||
//Custom kernels implementation
|
||||
GAPI_OCV_KERNEL(OCVBuildFaces, BuildFaces) {
|
||||
static void run(const cv::Mat & in_scores,
|
||||
const cv::Mat & in_regresssions,
|
||||
const float scaleFactor,
|
||||
const float threshold,
|
||||
std::vector<Face> &out_faces) {
|
||||
out_faces = buildFaces(in_scores, in_regresssions, scaleFactor, threshold);
|
||||
}
|
||||
};// GAPI_OCV_KERNEL(BuildFaces)
|
||||
|
||||
GAPI_OCV_KERNEL(OCVRunNMS, RunNMS) {
|
||||
static void run(const std::vector<Face> &in_faces,
|
||||
const float threshold,
|
||||
const bool useMin,
|
||||
std::vector<Face> &out_faces) {
|
||||
std::vector<Face> in_faces_copy = in_faces;
|
||||
out_faces = Face::runNMS(in_faces_copy, threshold, useMin);
|
||||
}
|
||||
};// GAPI_OCV_KERNEL(RunNMS)
|
||||
|
||||
GAPI_OCV_KERNEL(OCVAccumulatePyramidOutputs, AccumulatePyramidOutputs) {
|
||||
static void run(const std::vector<Face> &total_faces,
|
||||
const std::vector<Face> &in_faces,
|
||||
std::vector<Face> &out_faces) {
|
||||
out_faces = total_faces;
|
||||
out_faces.insert(out_faces.end(), in_faces.begin(), in_faces.end());
|
||||
}
|
||||
};// GAPI_OCV_KERNEL(AccumulatePyramidOutputs)
|
||||
|
||||
GAPI_OCV_KERNEL(OCVApplyRegression, ApplyRegression) {
|
||||
static void run(const std::vector<Face> &in_faces,
|
||||
const bool addOne,
|
||||
std::vector<Face> &out_faces) {
|
||||
std::vector<Face> in_faces_copy = in_faces;
|
||||
Face::applyRegression(in_faces_copy, addOne);
|
||||
out_faces.clear();
|
||||
out_faces.insert(out_faces.end(), in_faces_copy.begin(), in_faces_copy.end());
|
||||
}
|
||||
};// GAPI_OCV_KERNEL(ApplyRegression)
|
||||
|
||||
GAPI_OCV_KERNEL(OCVBBoxesToSquares, BBoxesToSquares) {
|
||||
static void run(const std::vector<Face> &in_faces,
|
||||
std::vector<Face> &out_faces) {
|
||||
std::vector<Face> in_faces_copy = in_faces;
|
||||
Face::bboxes2Squares(in_faces_copy);
|
||||
out_faces.clear();
|
||||
out_faces.insert(out_faces.end(), in_faces_copy.begin(), in_faces_copy.end());
|
||||
}
|
||||
};// GAPI_OCV_KERNEL(BBoxesToSquares)
|
||||
|
||||
GAPI_OCV_KERNEL(OCVR_O_NetPreProcGetROIs, R_O_NetPreProcGetROIs) {
|
||||
static void run(const std::vector<Face> &in_faces,
|
||||
const cv::Size & in_image_size,
|
||||
std::vector<cv::Rect> &outs) {
|
||||
outs.clear();
|
||||
for (const auto& face : in_faces) {
|
||||
cv::Rect tmp_rect = face.bbox.getRect();
|
||||
//Compare to transposed sizes width<->height
|
||||
tmp_rect &= cv::Rect(tmp_rect.x, tmp_rect.y, in_image_size.height - tmp_rect.x, in_image_size.width - tmp_rect.y) &
|
||||
cv::Rect(0, 0, in_image_size.height, in_image_size.width);
|
||||
outs.push_back(tmp_rect);
|
||||
}
|
||||
}
|
||||
};// GAPI_OCV_KERNEL(R_O_NetPreProcGetROIs)
|
||||
|
||||
|
||||
GAPI_OCV_KERNEL(OCVRNetPostProc, RNetPostProc) {
|
||||
static void run(const std::vector<Face> &in_faces,
|
||||
const std::vector<cv::Mat> &in_scores,
|
||||
const std::vector<cv::Mat> &in_regresssions,
|
||||
const float threshold,
|
||||
std::vector<Face> &out_faces) {
|
||||
out_faces.clear();
|
||||
for (unsigned int k = 0; k < in_faces.size(); ++k) {
|
||||
const float* scores_data = in_scores[k].ptr<float>();
|
||||
const float* reg_data = in_regresssions[k].ptr<float>();
|
||||
if (scores_data[1] >= threshold) {
|
||||
Face info = in_faces[k];
|
||||
info.score = scores_data[1];
|
||||
std::copy_n(reg_data, NUM_REGRESSIONS, info.regression.begin());
|
||||
out_faces.push_back(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
};// GAPI_OCV_KERNEL(RNetPostProc)
|
||||
|
||||
GAPI_OCV_KERNEL(OCVONetPostProc, ONetPostProc) {
|
||||
static void run(const std::vector<Face> &in_faces,
|
||||
const std::vector<cv::Mat> &in_scores,
|
||||
const std::vector<cv::Mat> &in_regresssions,
|
||||
const std::vector<cv::Mat> &in_landmarks,
|
||||
const float threshold,
|
||||
std::vector<Face> &out_faces) {
|
||||
out_faces.clear();
|
||||
for (unsigned int k = 0; k < in_faces.size(); ++k) {
|
||||
const float* scores_data = in_scores[k].ptr<float>();
|
||||
const float* reg_data = in_regresssions[k].ptr<float>();
|
||||
const float* landmark_data = in_landmarks[k].ptr<float>();
|
||||
if (scores_data[1] >= threshold) {
|
||||
Face info = in_faces[k];
|
||||
info.score = scores_data[1];
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
info.regression[i] = reg_data[i];
|
||||
}
|
||||
float w = info.bbox.x2 - info.bbox.x1 + 1.0f;
|
||||
float h = info.bbox.y2 - info.bbox.y1 + 1.0f;
|
||||
|
||||
for (size_t p = 0; p < NUM_PTS; ++p) {
|
||||
info.ptsCoords[2 * p] =
|
||||
info.bbox.x1 + static_cast<float>(landmark_data[NUM_PTS + p]) * w - 1;
|
||||
info.ptsCoords[2 * p + 1] = info.bbox.y1 + static_cast<float>(landmark_data[p]) * h - 1;
|
||||
}
|
||||
|
||||
out_faces.push_back(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
};// GAPI_OCV_KERNEL(ONetPostProc)
|
||||
|
||||
GAPI_OCV_KERNEL(OCVSwapFaces, SwapFaces) {
|
||||
static void run(const std::vector<Face> &in_faces,
|
||||
std::vector<Face> &out_faces) {
|
||||
std::vector<Face> in_faces_copy = in_faces;
|
||||
out_faces.clear();
|
||||
if (!in_faces_copy.empty()) {
|
||||
for (size_t i = 0; i < in_faces_copy.size(); ++i) {
|
||||
std::swap(in_faces_copy[i].bbox.x1, in_faces_copy[i].bbox.y1);
|
||||
std::swap(in_faces_copy[i].bbox.x2, in_faces_copy[i].bbox.y2);
|
||||
for (size_t p = 0; p < NUM_PTS; ++p) {
|
||||
std::swap(in_faces_copy[i].ptsCoords[2 * p], in_faces_copy[i].ptsCoords[2 * p + 1]);
|
||||
}
|
||||
}
|
||||
out_faces = in_faces_copy;
|
||||
}
|
||||
}
|
||||
};// GAPI_OCV_KERNEL(SwapFaces)
|
||||
|
||||
} // anonymous namespace
|
||||
} // namespace custom
|
||||
|
||||
namespace vis {
|
||||
namespace {
|
||||
void bbox(const cv::Mat& m, const cv::Rect& rc) {
|
||||
cv::rectangle(m, rc, cv::Scalar{ 0,255,0 }, 2, cv::LINE_8, 0);
|
||||
};
|
||||
|
||||
using rectPoints = std::pair<cv::Rect, std::vector<cv::Point>>;
|
||||
|
||||
static cv::Mat drawRectsAndPoints(const cv::Mat& img,
|
||||
const std::vector<rectPoints> data) {
|
||||
cv::Mat outImg;
|
||||
img.copyTo(outImg);
|
||||
|
||||
for (const auto& el : data) {
|
||||
vis::bbox(outImg, el.first);
|
||||
auto pts = el.second;
|
||||
for (size_t i = 0; i < pts.size(); ++i) {
|
||||
cv::circle(outImg, pts[i], 3, cv::Scalar(0, 255, 255), 1);
|
||||
}
|
||||
}
|
||||
return outImg;
|
||||
}
|
||||
} // anonymous namespace
|
||||
} // namespace vis
|
||||
|
||||
|
||||
//Infer helper function
|
||||
namespace {
|
||||
static inline std::tuple<cv::GMat, cv::GMat> run_mtcnn_p(cv::GMat &in, const std::string &id) {
|
||||
cv::GInferInputs inputs;
|
||||
inputs["data"] = in;
|
||||
auto outputs = cv::gapi::infer<cv::gapi::Generic>(id, inputs);
|
||||
auto regressions = outputs.at("conv4-2");
|
||||
auto scores = outputs.at("prob1");
|
||||
return std::make_tuple(regressions, scores);
|
||||
}
|
||||
|
||||
static inline std::string get_pnet_level_name(const cv::Size &in_size) {
|
||||
return "MTCNNProposal_" + std::to_string(in_size.width) + "x" + std::to_string(in_size.height);
|
||||
}
|
||||
|
||||
int calculate_scales(const cv::Size &input_size, std::vector<double> &out_scales, std::vector<cv::Size> &out_sizes ) {
|
||||
//calculate multi - scale and limit the maxinum side to 1000
|
||||
//pr_scale: limit the maxinum side to 1000, < 1.0
|
||||
double pr_scale = 1.0;
|
||||
double h = static_cast<double>(input_size.height);
|
||||
double w = static_cast<double>(input_size.width);
|
||||
if (std::min(w, h) > 1000)
|
||||
{
|
||||
pr_scale = 1000.0 / std::min(h, w);
|
||||
w = w * pr_scale;
|
||||
h = h * pr_scale;
|
||||
}
|
||||
else if (std::max(w, h) < 1000)
|
||||
{
|
||||
w = w * pr_scale;
|
||||
h = h * pr_scale;
|
||||
}
|
||||
//multi - scale
|
||||
out_scales.clear();
|
||||
out_sizes.clear();
|
||||
const double factor = 0.709;
|
||||
int factor_count = 0;
|
||||
double minl = std::min(h, w);
|
||||
while (minl >= 12)
|
||||
{
|
||||
const double current_scale = pr_scale * std::pow(factor, factor_count);
|
||||
cv::Size current_size(static_cast<int>(static_cast<double>(input_size.width) * current_scale),
|
||||
static_cast<int>(static_cast<double>(input_size.height) * current_scale));
|
||||
out_scales.push_back(current_scale);
|
||||
out_sizes.push_back(current_size);
|
||||
minl *= factor;
|
||||
factor_count += 1;
|
||||
}
|
||||
return factor_count;
|
||||
}
|
||||
|
||||
int calculate_half_scales(const cv::Size &input_size, std::vector<double>& out_scales, std::vector<cv::Size>& out_sizes) {
|
||||
double pr_scale = 0.5;
|
||||
const double h = static_cast<double>(input_size.height);
|
||||
const double w = static_cast<double>(input_size.width);
|
||||
//multi - scale
|
||||
out_scales.clear();
|
||||
out_sizes.clear();
|
||||
const double factor = 0.5;
|
||||
int factor_count = 0;
|
||||
double minl = std::min(h, w);
|
||||
while (minl >= 12.0*2.0)
|
||||
{
|
||||
const double current_scale = pr_scale;
|
||||
cv::Size current_size(static_cast<int>(static_cast<double>(input_size.width) * current_scale),
|
||||
static_cast<int>(static_cast<double>(input_size.height) * current_scale));
|
||||
out_scales.push_back(current_scale);
|
||||
out_sizes.push_back(current_size);
|
||||
minl *= factor;
|
||||
factor_count += 1;
|
||||
pr_scale *= 0.5;
|
||||
}
|
||||
return factor_count;
|
||||
}
|
||||
|
||||
const int MAX_PYRAMID_LEVELS = 13;
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
} // anonymous namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
cv::CommandLineParser cmd(argc, argv, keys);
|
||||
cmd.about(about);
|
||||
if (cmd.has("help")) {
|
||||
cmd.printMessage();
|
||||
return 0;
|
||||
}
|
||||
const auto input_file_name = cmd.get<std::string>("input");
|
||||
const auto model_path_p = cmd.get<std::string>("mtcnnpm");
|
||||
const auto target_dev_p = cmd.get<std::string>("mtcnnpd");
|
||||
const auto conf_thresh_p = cmd.get<float>("thrp");
|
||||
const auto model_path_r = cmd.get<std::string>("mtcnnrm");
|
||||
const auto target_dev_r = cmd.get<std::string>("mtcnnrd");
|
||||
const auto conf_thresh_r = cmd.get<float>("thrr");
|
||||
const auto model_path_o = cmd.get<std::string>("mtcnnom");
|
||||
const auto target_dev_o = cmd.get<std::string>("mtcnnod");
|
||||
const auto conf_thresh_o = cmd.get<float>("thro");
|
||||
const auto use_half_scale = cmd.get<bool>("half_scale");
|
||||
const auto streaming_queue_capacity = cmd.get<unsigned int>("queue_capacity");
|
||||
|
||||
std::vector<cv::Size> level_size;
|
||||
std::vector<double> scales;
|
||||
//MTCNN input size
|
||||
cv::VideoCapture cap;
|
||||
cap.open(input_file_name);
|
||||
if (!cap.isOpened())
|
||||
CV_Assert(false);
|
||||
auto in_rsz = cv::Size{ static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH)),
|
||||
static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT)) };
|
||||
//Calculate scales, number of pyramid levels and sizes for PNet pyramid
|
||||
auto pyramid_levels = use_half_scale ? calculate_half_scales(in_rsz, scales, level_size) :
|
||||
calculate_scales(in_rsz, scales, level_size);
|
||||
CV_Assert(pyramid_levels <= MAX_PYRAMID_LEVELS);
|
||||
|
||||
//Proposal part of MTCNN graph
|
||||
//Preprocessing BGR2RGB + transpose (NCWH is expected instead of NCHW)
|
||||
cv::GMat in_original;
|
||||
cv::GMat in_originalRGB = cv::gapi::BGR2RGB(in_original);
|
||||
cv::GMat in_transposedRGB = cv::gapi::transpose(in_originalRGB);
|
||||
cv::GOpaque<cv::Size> in_sz = cv::gapi::streaming::size(in_original);
|
||||
cv::GMat regressions[MAX_PYRAMID_LEVELS];
|
||||
cv::GMat scores[MAX_PYRAMID_LEVELS];
|
||||
cv::GArray<custom::Face> nms_p_faces[MAX_PYRAMID_LEVELS];
|
||||
cv::GArray<custom::Face> total_faces[MAX_PYRAMID_LEVELS];
|
||||
|
||||
//The very first PNet pyramid layer to init total_faces[0]
|
||||
std::tie(regressions[0], scores[0]) = run_mtcnn_p(in_transposedRGB, get_pnet_level_name(level_size[0]));
|
||||
cv::GArray<custom::Face> faces0 = custom::BuildFaces::on(scores[0], regressions[0], static_cast<float>(scales[0]), conf_thresh_p);
|
||||
cv::GArray<custom::Face> final_p_faces_for_bb2squares = custom::ApplyRegression::on(faces0, true);
|
||||
cv::GArray<custom::Face> final_faces_pnet0 = custom::BBoxesToSquares::on(final_p_faces_for_bb2squares);
|
||||
total_faces[0] = custom::RunNMS::on(final_faces_pnet0, 0.5f, false);
|
||||
//The rest PNet pyramid layers to accumlate all layers result in total_faces[PYRAMID_LEVELS - 1]]
|
||||
for (int i = 1; i < pyramid_levels; ++i)
|
||||
{
|
||||
std::tie(regressions[i], scores[i]) = run_mtcnn_p(in_transposedRGB, get_pnet_level_name(level_size[i]));
|
||||
cv::GArray<custom::Face> faces = custom::BuildFaces::on(scores[i], regressions[i], static_cast<float>(scales[i]), conf_thresh_p);
|
||||
cv::GArray<custom::Face> final_p_faces_for_bb2squares_i = custom::ApplyRegression::on(faces, true);
|
||||
cv::GArray<custom::Face> final_faces_pnet_i = custom::BBoxesToSquares::on(final_p_faces_for_bb2squares_i);
|
||||
nms_p_faces[i] = custom::RunNMS::on(final_faces_pnet_i, 0.5f, false);
|
||||
total_faces[i] = custom::AccumulatePyramidOutputs::on(total_faces[i - 1], nms_p_faces[i]);
|
||||
}
|
||||
|
||||
//Proposal post-processing
|
||||
cv::GArray<custom::Face> final_faces_pnet = custom::RunNMS::on(total_faces[pyramid_levels - 1], 0.7f, true);
|
||||
|
||||
//Refinement part of MTCNN graph
|
||||
cv::GArray<cv::Rect> faces_roi_pnet = custom::R_O_NetPreProcGetROIs::on(final_faces_pnet, in_sz);
|
||||
cv::GArray<cv::GMat> regressionsRNet, scoresRNet;
|
||||
std::tie(regressionsRNet, scoresRNet) = cv::gapi::infer<custom::MTCNNRefinement>(faces_roi_pnet, in_transposedRGB);
|
||||
|
||||
//Refinement post-processing
|
||||
cv::GArray<custom::Face> rnet_post_proc_faces = custom::RNetPostProc::on(final_faces_pnet, scoresRNet, regressionsRNet, conf_thresh_r);
|
||||
cv::GArray<custom::Face> nms07_r_faces_total = custom::RunNMS::on(rnet_post_proc_faces, 0.7f, false);
|
||||
cv::GArray<custom::Face> final_r_faces_for_bb2squares = custom::ApplyRegression::on(nms07_r_faces_total, true);
|
||||
cv::GArray<custom::Face> final_faces_rnet = custom::BBoxesToSquares::on(final_r_faces_for_bb2squares);
|
||||
|
||||
//Output part of MTCNN graph
|
||||
cv::GArray<cv::Rect> faces_roi_rnet = custom::R_O_NetPreProcGetROIs::on(final_faces_rnet, in_sz);
|
||||
cv::GArray<cv::GMat> regressionsONet, scoresONet, landmarksONet;
|
||||
std::tie(regressionsONet, landmarksONet, scoresONet) = cv::gapi::infer<custom::MTCNNOutput>(faces_roi_rnet, in_transposedRGB);
|
||||
|
||||
//Output post-processing
|
||||
cv::GArray<custom::Face> onet_post_proc_faces = custom::ONetPostProc::on(final_faces_rnet, scoresONet, regressionsONet, landmarksONet, conf_thresh_o);
|
||||
cv::GArray<custom::Face> final_o_faces_for_nms07 = custom::ApplyRegression::on(onet_post_proc_faces, true);
|
||||
cv::GArray<custom::Face> nms07_o_faces_total = custom::RunNMS::on(final_o_faces_for_nms07, 0.7f, true);
|
||||
cv::GArray<custom::Face> final_faces_onet = custom::SwapFaces::on(nms07_o_faces_total);
|
||||
|
||||
cv::GComputation graph_mtcnn(cv::GIn(in_original), cv::GOut(cv::gapi::copy(in_original), final_faces_onet));
|
||||
|
||||
// MTCNN Refinement detection network
|
||||
auto mtcnnr_net = cv::gapi::ie::Params<custom::MTCNNRefinement>{
|
||||
model_path_r, // path to topology IR
|
||||
weights_path(model_path_r), // path to weights
|
||||
target_dev_r, // device specifier
|
||||
}.cfgOutputLayers({ "conv5-2", "prob1" }).cfgInputLayers({ "data" });
|
||||
|
||||
// MTCNN Output detection network
|
||||
auto mtcnno_net = cv::gapi::ie::Params<custom::MTCNNOutput>{
|
||||
model_path_o, // path to topology IR
|
||||
weights_path(model_path_o), // path to weights
|
||||
target_dev_o, // device specifier
|
||||
}.cfgOutputLayers({ "conv6-2", "conv6-3", "prob1" }).cfgInputLayers({ "data" });
|
||||
|
||||
auto networks_mtcnn = cv::gapi::networks(mtcnnr_net, mtcnno_net);
|
||||
|
||||
// MTCNN Proposal detection network
|
||||
for (int i = 0; i < pyramid_levels; ++i)
|
||||
{
|
||||
std::string net_id = get_pnet_level_name(level_size[i]);
|
||||
std::vector<size_t> reshape_dims = { 1, 3, (size_t)level_size[i].width, (size_t)level_size[i].height };
|
||||
cv::gapi::ie::Params<cv::gapi::Generic> mtcnnp_net{
|
||||
net_id, // tag
|
||||
model_path_p, // path to topology IR
|
||||
weights_path(model_path_p), // path to weights
|
||||
target_dev_p, // device specifier
|
||||
};
|
||||
mtcnnp_net.cfgInputReshape({ {"data", reshape_dims} });
|
||||
networks_mtcnn += cv::gapi::networks(mtcnnp_net);
|
||||
}
|
||||
|
||||
auto kernels_mtcnn = cv::gapi::kernels< custom::OCVBuildFaces
|
||||
, custom::OCVRunNMS
|
||||
, custom::OCVAccumulatePyramidOutputs
|
||||
, custom::OCVApplyRegression
|
||||
, custom::OCVBBoxesToSquares
|
||||
, custom::OCVR_O_NetPreProcGetROIs
|
||||
, custom::OCVRNetPostProc
|
||||
, custom::OCVONetPostProc
|
||||
, custom::OCVSwapFaces
|
||||
>();
|
||||
auto mtcnn_args = cv::compile_args(networks_mtcnn, kernels_mtcnn);
|
||||
if (streaming_queue_capacity != 0)
|
||||
mtcnn_args += cv::compile_args(cv::gapi::streaming::queue_capacity{ streaming_queue_capacity });
|
||||
auto pipeline_mtcnn = graph_mtcnn.compileStreaming(std::move(mtcnn_args));
|
||||
|
||||
std::cout << "Reading " << input_file_name << std::endl;
|
||||
// Input stream
|
||||
auto in_src = cv::gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(input_file_name);
|
||||
|
||||
// Set the pipeline source & start the pipeline
|
||||
pipeline_mtcnn.setSource(cv::gin(in_src));
|
||||
pipeline_mtcnn.start();
|
||||
|
||||
// Declare the output data & run the processing loop
|
||||
cv::TickMeter tm;
|
||||
cv::Mat image;
|
||||
std::vector<custom::Face> out_faces;
|
||||
|
||||
tm.start();
|
||||
int frames = 0;
|
||||
while (pipeline_mtcnn.pull(cv::gout(image, out_faces))) {
|
||||
frames++;
|
||||
std::cout << "Final Faces Size " << out_faces.size() << std::endl;
|
||||
std::vector<vis::rectPoints> data;
|
||||
// show the image with faces in it
|
||||
for (const auto& out_face : out_faces) {
|
||||
std::vector<cv::Point> pts;
|
||||
for (size_t p = 0; p < NUM_PTS; ++p) {
|
||||
pts.push_back(
|
||||
cv::Point(static_cast<int>(out_face.ptsCoords[2 * p]), static_cast<int>(out_face.ptsCoords[2 * p + 1])));
|
||||
}
|
||||
auto rect = out_face.bbox.getRect();
|
||||
auto d = std::make_pair(rect, pts);
|
||||
data.push_back(d);
|
||||
}
|
||||
// Visualize results on the frame
|
||||
auto resultImg = vis::drawRectsAndPoints(image, data);
|
||||
tm.stop();
|
||||
const auto fps_str = std::to_string(frames / tm.getTimeSec()) + " FPS";
|
||||
cv::putText(resultImg, fps_str, { 0,32 }, cv::FONT_HERSHEY_SIMPLEX, 1.0, { 0,255,0 }, 2);
|
||||
cv::imshow("Out", resultImg);
|
||||
cv::waitKey(1);
|
||||
out_faces.clear();
|
||||
tm.start();
|
||||
}
|
||||
tm.stop();
|
||||
std::cout << "Processed " << frames << " frames"
|
||||
<< " (" << frames / tm.getTimeSec() << " FPS)" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
#include <opencv2/gapi/streaming/cap.hpp>
|
||||
#include <opencv2/gapi/cpu/gcpukernel.hpp>
|
||||
#include <opencv2/highgui.hpp> // CommandLineParser
|
||||
#include <opencv2/gapi/infer/parsers.hpp>
|
||||
|
||||
const std::string about =
|
||||
"This is an OpenCV-based version of Gaze Estimation example";
|
||||
|
|
@ -16,13 +17,13 @@ const std::string keys =
|
|||
"{ h help | | Print this help message }"
|
||||
"{ input | | Path to the input video file }"
|
||||
"{ facem | face-detection-retail-0005.xml | Path to OpenVINO face detection model (.xml) }"
|
||||
"{ faced | CPU | Target device for the face detection (e.g. CPU, GPU, VPU, ...) }"
|
||||
"{ faced | CPU | Target device for the face detection (e.g. CPU, GPU, ...) }"
|
||||
"{ landm | facial-landmarks-35-adas-0002.xml | Path to OpenVINO landmarks detector model (.xml) }"
|
||||
"{ landd | CPU | Target device for the landmarks detector (e.g. CPU, GPU, VPU, ...) }"
|
||||
"{ landd | CPU | Target device for the landmarks detector (e.g. CPU, GPU, ...) }"
|
||||
"{ headm | head-pose-estimation-adas-0001.xml | Path to OpenVINO head pose estimation model (.xml) }"
|
||||
"{ headd | CPU | Target device for the head pose estimation inference (e.g. CPU, GPU, VPU, ...) }"
|
||||
"{ headd | CPU | Target device for the head pose estimation inference (e.g. CPU, GPU, ...) }"
|
||||
"{ gazem | gaze-estimation-adas-0002.xml | Path to OpenVINO gaze vector estimaiton model (.xml) }"
|
||||
"{ gazed | CPU | Target device for the gaze vector estimation inference (e.g. CPU, GPU, VPU, ...) }"
|
||||
"{ gazed | CPU | Target device for the gaze vector estimation inference (e.g. CPU, GPU, ...) }"
|
||||
;
|
||||
|
||||
namespace {
|
||||
|
|
@ -58,16 +59,6 @@ G_API_OP(Size, <GSize(cv::GMat)>, "custom.gapi.size") {
|
|||
}
|
||||
};
|
||||
|
||||
G_API_OP(ParseSSD,
|
||||
<GRects(cv::GMat, GSize, bool)>,
|
||||
"custom.gaze_estimation.parseSSD") {
|
||||
static cv::GArrayDesc outMeta( const cv::GMatDesc &
|
||||
, const cv::GOpaqueDesc &
|
||||
, bool) {
|
||||
return cv::empty_array_desc();
|
||||
}
|
||||
};
|
||||
|
||||
// Left/Right eye per every face
|
||||
G_API_OP(ParseEyes,
|
||||
<std::tuple<GRects, GRects>(GMats, GRects, GSize)>,
|
||||
|
|
@ -91,27 +82,6 @@ G_API_OP(ProcessPoses,
|
|||
}
|
||||
};
|
||||
|
||||
void adjustBoundingBox(cv::Rect& boundingBox) {
|
||||
auto w = boundingBox.width;
|
||||
auto h = boundingBox.height;
|
||||
|
||||
boundingBox.x -= static_cast<int>(0.067 * w);
|
||||
boundingBox.y -= static_cast<int>(0.028 * h);
|
||||
|
||||
boundingBox.width += static_cast<int>(0.15 * w);
|
||||
boundingBox.height += static_cast<int>(0.13 * h);
|
||||
|
||||
if (boundingBox.width < boundingBox.height) {
|
||||
auto dx = (boundingBox.height - boundingBox.width);
|
||||
boundingBox.x -= dx / 2;
|
||||
boundingBox.width += dx;
|
||||
} else {
|
||||
auto dy = (boundingBox.width - boundingBox.height);
|
||||
boundingBox.y -= dy / 2;
|
||||
boundingBox.height += dy;
|
||||
}
|
||||
}
|
||||
|
||||
void gazeVectorToGazeAngles(const cv::Point3f& gazeVector,
|
||||
cv::Point2f& gazeAngles) {
|
||||
auto r = cv::norm(gazeVector);
|
||||
|
|
@ -130,55 +100,6 @@ GAPI_OCV_KERNEL(OCVSize, Size) {
|
|||
}
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(OCVParseSSD, ParseSSD) {
|
||||
static void run(const cv::Mat &in_ssd_result,
|
||||
const cv::Size &upscale,
|
||||
const bool filter_out_of_bounds,
|
||||
std::vector<cv::Rect> &out_objects) {
|
||||
const auto &in_ssd_dims = in_ssd_result.size;
|
||||
CV_Assert(in_ssd_dims.dims() == 4u);
|
||||
|
||||
const int MAX_PROPOSALS = in_ssd_dims[2];
|
||||
const int OBJECT_SIZE = in_ssd_dims[3];
|
||||
CV_Assert(OBJECT_SIZE == 7); // fixed SSD object size
|
||||
|
||||
const cv::Rect surface({0,0}, upscale);
|
||||
out_objects.clear();
|
||||
|
||||
const float *data = in_ssd_result.ptr<float>();
|
||||
for (int i = 0; i < MAX_PROPOSALS; i++) {
|
||||
const float image_id = data[i * OBJECT_SIZE + 0];
|
||||
const float label = data[i * OBJECT_SIZE + 1];
|
||||
const float confidence = data[i * OBJECT_SIZE + 2];
|
||||
const float rc_left = data[i * OBJECT_SIZE + 3];
|
||||
const float rc_top = data[i * OBJECT_SIZE + 4];
|
||||
const float rc_right = data[i * OBJECT_SIZE + 5];
|
||||
const float rc_bottom = data[i * OBJECT_SIZE + 6];
|
||||
(void) label;
|
||||
if (image_id < 0.f) {
|
||||
break; // marks end-of-detections
|
||||
}
|
||||
if (confidence < 0.5f) {
|
||||
continue; // skip objects with low confidence
|
||||
}
|
||||
cv::Rect rc; // map relative coordinates to the original image scale
|
||||
rc.x = static_cast<int>(rc_left * upscale.width);
|
||||
rc.y = static_cast<int>(rc_top * upscale.height);
|
||||
rc.width = static_cast<int>(rc_right * upscale.width) - rc.x;
|
||||
rc.height = static_cast<int>(rc_bottom * upscale.height) - rc.y;
|
||||
adjustBoundingBox(rc); // TODO: new option?
|
||||
|
||||
const auto clipped_rc = rc & surface; // TODO: new option?
|
||||
if (filter_out_of_bounds) {
|
||||
if (clipped_rc.area() != rc.area()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
out_objects.emplace_back(clipped_rc);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cv::Rect eyeBox(const cv::Rect &face_rc,
|
||||
float p1_x, float p1_y, float p2_x, float p2_y,
|
||||
float scale = 1.8f) {
|
||||
|
|
@ -335,11 +256,10 @@ int main(int argc, char *argv[])
|
|||
cmd.printMessage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
cv::GMat in;
|
||||
cv::GMat faces = cv::gapi::infer<custom::Faces>(in);
|
||||
cv::GOpaque<cv::Size> sz = custom::Size::on(in); // FIXME
|
||||
cv::GArray<cv::Rect> faces_rc = custom::ParseSSD::on(faces, sz, true);
|
||||
cv::GOpaque<cv::Size> sz = cv::gapi::streaming::size(in);
|
||||
cv::GArray<cv::Rect> faces_rc = cv::gapi::parseSSD(faces, sz, 0.5f, true, true);
|
||||
cv::GArray<cv::GMat> angles_y, angles_p, angles_r;
|
||||
std::tie(angles_y, angles_p, angles_r) = cv::gapi::infer<custom::HeadPose>(faces_rc, in);
|
||||
cv::GArray<cv::GMat> heads_pos = custom::ProcessPoses::on(angles_y, angles_p, angles_r);
|
||||
|
|
@ -386,7 +306,6 @@ int main(int argc, char *argv[])
|
|||
}.cfgInputLayers({"left_eye_image", "right_eye_image", "head_pose_angles"});
|
||||
|
||||
auto kernels = cv::gapi::kernels< custom::OCVSize
|
||||
, custom::OCVParseSSD
|
||||
, custom::OCVParseEyes
|
||||
, custom::OCVProcessPoses>();
|
||||
auto networks = cv::gapi::networks(face_net, head_net, landmarks_net, gaze_net);
|
||||
|
|
|
|||
|
|
@ -156,7 +156,6 @@ int main(int argc, char *argv[])
|
|||
|
||||
auto in_src = cv::gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(input);
|
||||
pipeline.setSource(cv::gin(in_src));
|
||||
pipeline.start();
|
||||
|
||||
cv::util::optional<cv::Mat> out_frame;
|
||||
cv::util::optional<std::vector<cv::Rect>> out_faces;
|
||||
|
|
@ -167,8 +166,13 @@ int main(int argc, char *argv[])
|
|||
std::vector<cv::Mat> last_emotions;
|
||||
|
||||
cv::VideoWriter writer;
|
||||
cv::TickMeter tm;
|
||||
std::size_t frames = 0u;
|
||||
|
||||
tm.start();
|
||||
pipeline.start();
|
||||
while (pipeline.pull(cv::gout(out_frame, out_faces, out_emotions))) {
|
||||
++frames;
|
||||
if (out_faces && out_emotions) {
|
||||
last_faces = *out_faces;
|
||||
last_emotions = *out_emotions;
|
||||
|
|
@ -191,5 +195,7 @@ int main(int argc, char *argv[])
|
|||
cv::waitKey(1);
|
||||
}
|
||||
}
|
||||
tm.stop();
|
||||
std::cout << "Processed " << frames << " frames" << " (" << frames / tm.getTimeSec() << " FPS)" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <opencv2/gapi/cpu/gcpukernel.hpp>
|
||||
#include <opencv2/gapi/streaming/cap.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
#include <opencv2/gapi/infer/parsers.hpp>
|
||||
|
||||
const std::string keys =
|
||||
"{ h help | | Print this help message }"
|
||||
|
|
@ -69,36 +70,18 @@ using GRect = cv::GOpaque<cv::Rect>;
|
|||
using GSize = cv::GOpaque<cv::Size>;
|
||||
using GPrims = cv::GArray<cv::gapi::wip::draw::Prim>;
|
||||
|
||||
G_API_OP(GetSize, <GSize(cv::GMat)>, "sample.custom.get-size") {
|
||||
static cv::GOpaqueDesc outMeta(const cv::GMatDesc &) {
|
||||
return cv::empty_gopaque_desc();
|
||||
}
|
||||
};
|
||||
|
||||
G_API_OP(LocateROI, <GRect(cv::GMat)>, "sample.custom.locate-roi") {
|
||||
static cv::GOpaqueDesc outMeta(const cv::GMatDesc &) {
|
||||
return cv::empty_gopaque_desc();
|
||||
}
|
||||
};
|
||||
|
||||
G_API_OP(ParseSSD, <GDetections(cv::GMat, GRect, GSize)>, "sample.custom.parse-ssd") {
|
||||
static cv::GArrayDesc outMeta(const cv::GMatDesc &, const cv::GOpaqueDesc &, const cv::GOpaqueDesc &) {
|
||||
return cv::empty_array_desc();
|
||||
}
|
||||
};
|
||||
|
||||
G_API_OP(BBoxes, <GPrims(GDetections, GRect)>, "sample.custom.b-boxes") {
|
||||
static cv::GArrayDesc outMeta(const cv::GArrayDesc &, const cv::GOpaqueDesc &) {
|
||||
return cv::empty_array_desc();
|
||||
}
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(OCVGetSize, GetSize) {
|
||||
static void run(const cv::Mat &in, cv::Size &out) {
|
||||
out = {in.cols, in.rows};
|
||||
}
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(OCVLocateROI, LocateROI) {
|
||||
// This is the place where we can run extra analytics
|
||||
// on the input image frame and select the ROI (region
|
||||
|
|
@ -124,55 +107,6 @@ GAPI_OCV_KERNEL(OCVLocateROI, LocateROI) {
|
|||
}
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(OCVParseSSD, ParseSSD) {
|
||||
static void run(const cv::Mat &in_ssd_result,
|
||||
const cv::Rect &in_roi,
|
||||
const cv::Size &in_parent_size,
|
||||
std::vector<cv::Rect> &out_objects) {
|
||||
const auto &in_ssd_dims = in_ssd_result.size;
|
||||
CV_Assert(in_ssd_dims.dims() == 4u);
|
||||
|
||||
const int MAX_PROPOSALS = in_ssd_dims[2];
|
||||
const int OBJECT_SIZE = in_ssd_dims[3];
|
||||
CV_Assert(OBJECT_SIZE == 7); // fixed SSD object size
|
||||
|
||||
const cv::Size up_roi = in_roi.size();
|
||||
const cv::Rect surface({0,0}, in_parent_size);
|
||||
|
||||
out_objects.clear();
|
||||
|
||||
const float *data = in_ssd_result.ptr<float>();
|
||||
for (int i = 0; i < MAX_PROPOSALS; i++) {
|
||||
const float image_id = data[i * OBJECT_SIZE + 0];
|
||||
const float label = data[i * OBJECT_SIZE + 1];
|
||||
const float confidence = data[i * OBJECT_SIZE + 2];
|
||||
const float rc_left = data[i * OBJECT_SIZE + 3];
|
||||
const float rc_top = data[i * OBJECT_SIZE + 4];
|
||||
const float rc_right = data[i * OBJECT_SIZE + 5];
|
||||
const float rc_bottom = data[i * OBJECT_SIZE + 6];
|
||||
(void) label; // unused
|
||||
|
||||
if (image_id < 0.f) {
|
||||
break; // marks end-of-detections
|
||||
}
|
||||
if (confidence < 0.5f) {
|
||||
continue; // skip objects with low confidence
|
||||
}
|
||||
|
||||
// map relative coordinates to the original image scale
|
||||
// taking the ROI into account
|
||||
cv::Rect rc;
|
||||
rc.x = static_cast<int>(rc_left * up_roi.width);
|
||||
rc.y = static_cast<int>(rc_top * up_roi.height);
|
||||
rc.width = static_cast<int>(rc_right * up_roi.width) - rc.x;
|
||||
rc.height = static_cast<int>(rc_bottom * up_roi.height) - rc.y;
|
||||
rc.x += in_roi.x;
|
||||
rc.y += in_roi.y;
|
||||
out_objects.emplace_back(rc & surface);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(OCVBBoxes, BBoxes) {
|
||||
// This kernel converts the rectangles into G-API's
|
||||
// rendering primitives
|
||||
|
|
@ -211,9 +145,7 @@ int main(int argc, char *argv[])
|
|||
cmd.get<std::string>("faced"), // device specifier
|
||||
};
|
||||
auto kernels = cv::gapi::kernels
|
||||
< custom::OCVGetSize
|
||||
, custom::OCVLocateROI
|
||||
, custom::OCVParseSSD
|
||||
<custom::OCVLocateROI
|
||||
, custom::OCVBBoxes>();
|
||||
auto networks = cv::gapi::networks(face_net);
|
||||
|
||||
|
|
@ -222,16 +154,17 @@ int main(int argc, char *argv[])
|
|||
cv::GStreamingCompiled pipeline;
|
||||
auto inputs = cv::gin(cv::gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(input));
|
||||
|
||||
cv::GMat in;
|
||||
cv::GOpaque<cv::Size> sz = cv::gapi::streaming::size(in);
|
||||
if (opt_roi.has_value()) {
|
||||
// Use the value provided by user
|
||||
std::cout << "Will run inference for static region "
|
||||
<< opt_roi.value()
|
||||
<< " only"
|
||||
<< std::endl;
|
||||
cv::GMat in;
|
||||
cv::GOpaque<cv::Rect> in_roi;
|
||||
auto blob = cv::gapi::infer<custom::FaceDetector>(in_roi, in);
|
||||
auto rcs = custom::ParseSSD::on(blob, in_roi, custom::GetSize::on(in));
|
||||
cv::GArray<cv::Rect> rcs = cv::gapi::parseSSD(blob, sz, 0.5f, true, true);
|
||||
auto out = cv::gapi::wip::draw::render3ch(in, custom::BBoxes::on(rcs, in_roi));
|
||||
pipeline = cv::GComputation(cv::GIn(in, in_roi), cv::GOut(out))
|
||||
.compileStreaming(cv::compile_args(kernels, networks));
|
||||
|
|
@ -242,10 +175,9 @@ int main(int argc, char *argv[])
|
|||
// Automatically detect ROI to infer. Make it output parameter
|
||||
std::cout << "ROI is not set or invalid. Locating it automatically"
|
||||
<< std::endl;
|
||||
cv::GMat in;
|
||||
cv::GOpaque<cv::Rect> roi = custom::LocateROI::on(in);
|
||||
auto blob = cv::gapi::infer<custom::FaceDetector>(roi, in);
|
||||
auto rcs = custom::ParseSSD::on(blob, roi, custom::GetSize::on(in));
|
||||
cv::GArray<cv::Rect> rcs = cv::gapi::parseSSD(blob, sz, 0.5f, true, true);
|
||||
auto out = cv::gapi::wip::draw::render3ch(in, custom::BBoxes::on(rcs, roi));
|
||||
pipeline = cv::GComputation(cv::GIn(in), cv::GOut(out))
|
||||
.compileStreaming(cv::compile_args(kernels, networks));
|
||||
|
|
@ -256,9 +188,15 @@ int main(int argc, char *argv[])
|
|||
pipeline.start();
|
||||
|
||||
cv::Mat out;
|
||||
size_t frames = 0u;
|
||||
cv::TickMeter tm;
|
||||
tm.start();
|
||||
while (pipeline.pull(cv::gout(out))) {
|
||||
cv::imshow("Out", out);
|
||||
cv::waitKey(1);
|
||||
++frames;
|
||||
}
|
||||
tm.stop();
|
||||
std::cout << "Processed " << frames << " frames" << " (" << frames / tm.getTimeSec() << " FPS)" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <opencv2/gapi/cpu/gcpukernel.hpp>
|
||||
#include <opencv2/gapi/streaming/cap.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
#include <opencv2/gapi/infer/parsers.hpp>
|
||||
|
||||
namespace custom {
|
||||
|
||||
|
|
@ -23,71 +24,12 @@ using GDetections = cv::GArray<cv::Rect>;
|
|||
using GSize = cv::GOpaque<cv::Size>;
|
||||
using GPrims = cv::GArray<cv::gapi::wip::draw::Prim>;
|
||||
|
||||
G_API_OP(GetSize, <GSize(cv::GMat)>, "sample.custom.get-size") {
|
||||
static cv::GOpaqueDesc outMeta(const cv::GMatDesc &) {
|
||||
return cv::empty_gopaque_desc();
|
||||
}
|
||||
};
|
||||
G_API_OP(ParseSSD, <GDetections(cv::GMat, GSize)>, "sample.custom.parse-ssd") {
|
||||
static cv::GArrayDesc outMeta(const cv::GMatDesc &, const cv::GOpaqueDesc &) {
|
||||
return cv::empty_array_desc();
|
||||
}
|
||||
};
|
||||
G_API_OP(BBoxes, <GPrims(GDetections)>, "sample.custom.b-boxes") {
|
||||
static cv::GArrayDesc outMeta(const cv::GArrayDesc &) {
|
||||
return cv::empty_array_desc();
|
||||
}
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(OCVGetSize, GetSize) {
|
||||
static void run(const cv::Mat &in, cv::Size &out) {
|
||||
out = {in.cols, in.rows};
|
||||
}
|
||||
};
|
||||
GAPI_OCV_KERNEL(OCVParseSSD, ParseSSD) {
|
||||
static void run(const cv::Mat &in_ssd_result,
|
||||
const cv::Size &in_parent_size,
|
||||
std::vector<cv::Rect> &out_objects) {
|
||||
const auto &in_ssd_dims = in_ssd_result.size;
|
||||
CV_Assert(in_ssd_dims.dims() == 4u);
|
||||
|
||||
const int MAX_PROPOSALS = in_ssd_dims[2];
|
||||
const int OBJECT_SIZE = in_ssd_dims[3];
|
||||
|
||||
CV_Assert(OBJECT_SIZE == 7); // fixed SSD object size
|
||||
|
||||
const cv::Rect surface({0,0}, in_parent_size);
|
||||
|
||||
out_objects.clear();
|
||||
|
||||
const float *data = in_ssd_result.ptr<float>();
|
||||
for (int i = 0; i < MAX_PROPOSALS; i++) {
|
||||
const float image_id = data[i * OBJECT_SIZE + 0];
|
||||
const float label = data[i * OBJECT_SIZE + 1];
|
||||
const float confidence = data[i * OBJECT_SIZE + 2];
|
||||
const float rc_left = data[i * OBJECT_SIZE + 3];
|
||||
const float rc_top = data[i * OBJECT_SIZE + 4];
|
||||
const float rc_right = data[i * OBJECT_SIZE + 5];
|
||||
const float rc_bottom = data[i * OBJECT_SIZE + 6];
|
||||
(void) label; // unused
|
||||
|
||||
if (image_id < 0.f) {
|
||||
break; // marks end-of-detections
|
||||
}
|
||||
if (confidence < 0.5f) {
|
||||
continue; // skip objects with low confidence
|
||||
}
|
||||
|
||||
// map relative coordinates to the original image scale
|
||||
cv::Rect rc;
|
||||
rc.x = static_cast<int>(rc_left * in_parent_size.width);
|
||||
rc.y = static_cast<int>(rc_top * in_parent_size.height);
|
||||
rc.width = static_cast<int>(rc_right * in_parent_size.width) - rc.x;
|
||||
rc.height = static_cast<int>(rc_bottom * in_parent_size.height) - rc.y;
|
||||
out_objects.emplace_back(rc & surface);
|
||||
}
|
||||
}
|
||||
};
|
||||
GAPI_OCV_KERNEL(OCVBBoxes, BBoxes) {
|
||||
// This kernel converts the rectangles into G-API's
|
||||
// rendering primitives
|
||||
|
|
@ -151,7 +93,6 @@ void remap_ssd_ports(const std::unordered_map<std::string, cv::Mat> &onnx,
|
|||
}
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
const std::string keys =
|
||||
"{ h help | | Print this help message }"
|
||||
"{ input | | Path to the input video file }"
|
||||
|
|
@ -175,15 +116,14 @@ int main(int argc, char *argv[])
|
|||
auto obj_net = cv::gapi::onnx::Params<custom::ObjDetector>{obj_model_path}
|
||||
.cfgOutputLayers({"detection_output"})
|
||||
.cfgPostProc({cv::GMatDesc{CV_32F, {1,1,200,7}}}, remap_ssd_ports);
|
||||
auto kernels = cv::gapi::kernels< custom::OCVGetSize
|
||||
, custom::OCVParseSSD
|
||||
, custom::OCVBBoxes>();
|
||||
auto kernels = cv::gapi::kernels<custom::OCVBBoxes>();
|
||||
auto networks = cv::gapi::networks(obj_net);
|
||||
|
||||
// Now build the graph
|
||||
cv::GMat in;
|
||||
auto blob = cv::gapi::infer<custom::ObjDetector>(in);
|
||||
auto rcs = custom::ParseSSD::on(blob, custom::GetSize::on(in));
|
||||
cv::GArray<cv::Rect> rcs =
|
||||
cv::gapi::parseSSD(blob, cv::gapi::streaming::size(in), 0.5f, true, true);
|
||||
auto out = cv::gapi::wip::draw::render3ch(in, custom::BBoxes::on(rcs));
|
||||
cv::GStreamingCompiled pipeline = cv::GComputation(cv::GIn(in), cv::GOut(out))
|
||||
.compileStreaming(cv::compile_args(kernels, networks));
|
||||
|
|
@ -192,12 +132,16 @@ int main(int argc, char *argv[])
|
|||
|
||||
// The execution part
|
||||
pipeline.setSource(std::move(inputs));
|
||||
pipeline.start();
|
||||
|
||||
cv::TickMeter tm;
|
||||
cv::VideoWriter writer;
|
||||
|
||||
size_t frames = 0u;
|
||||
cv::Mat outMat;
|
||||
|
||||
tm.start();
|
||||
pipeline.start();
|
||||
while (pipeline.pull(cv::gout(outMat))) {
|
||||
++frames;
|
||||
cv::imshow("Out", outMat);
|
||||
cv::waitKey(1);
|
||||
if (!output.empty()) {
|
||||
|
|
@ -209,5 +153,7 @@ int main(int argc, char *argv[])
|
|||
writer << outMat;
|
||||
}
|
||||
}
|
||||
tm.stop();
|
||||
std::cout << "Processed " << frames << " frames" << " (" << frames / tm.getTimeSec() << " FPS)" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,390 @@
|
|||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <cctype>
|
||||
#include <tuple>
|
||||
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/gapi.hpp>
|
||||
#include <opencv2/gapi/core.hpp>
|
||||
#include <opencv2/gapi/cpu/gcpukernel.hpp>
|
||||
#include <opencv2/gapi/infer/ie.hpp>
|
||||
#include <opencv2/gapi/render.hpp>
|
||||
#include <opencv2/gapi/streaming/onevpl/source.hpp>
|
||||
#include <opencv2/gapi/streaming/onevpl/data_provider_interface.hpp>
|
||||
#include <opencv2/highgui.hpp> // CommandLineParser
|
||||
#include <opencv2/gapi/infer/parsers.hpp>
|
||||
|
||||
#ifdef HAVE_INF_ENGINE
|
||||
#include <inference_engine.hpp> // ParamMap
|
||||
|
||||
#ifdef HAVE_DIRECTX
|
||||
#ifdef HAVE_D3D11
|
||||
#pragma comment(lib,"d3d11.lib")
|
||||
|
||||
// get rid of generate macro max/min/etc from DX side
|
||||
#define D3D11_NO_HELPERS
|
||||
#define NOMINMAX
|
||||
#include <cldnn/cldnn_config.hpp>
|
||||
#include <d3d11.h>
|
||||
#pragma comment(lib, "dxgi")
|
||||
#undef NOMINMAX
|
||||
#undef D3D11_NO_HELPERS
|
||||
|
||||
#endif // HAVE_D3D11
|
||||
#endif // HAVE_DIRECTX
|
||||
#endif // HAVE_INF_ENGINE
|
||||
|
||||
const std::string about =
|
||||
"This is an OpenCV-based version of oneVPLSource decoder example";
|
||||
const std::string keys =
|
||||
"{ h help | | Print this help message }"
|
||||
"{ input | | Path to the input demultiplexed video file }"
|
||||
"{ output | | Path to the output RAW video file. Use .avi extension }"
|
||||
"{ facem | face-detection-adas-0001.xml | Path to OpenVINO IE face detection model (.xml) }"
|
||||
"{ faced | CPU | Target device for face detection model (e.g. CPU, GPU, VPU, ...) }"
|
||||
"{ cfg_params | <prop name>:<value>;<prop name>:<value> | Semicolon separated list of oneVPL mfxVariants which is used for configuring source (see `MFXSetConfigFilterProperty` by https://spec.oneapi.io/versions/latest/elements/oneVPL/source/index.html) }";
|
||||
|
||||
|
||||
namespace {
|
||||
std::string get_weights_path(const std::string &model_path) {
|
||||
const auto EXT_LEN = 4u;
|
||||
const auto sz = model_path.size();
|
||||
CV_Assert(sz > EXT_LEN);
|
||||
|
||||
auto ext = model_path.substr(sz - EXT_LEN);
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char c){
|
||||
return static_cast<unsigned char>(std::tolower(c));
|
||||
});
|
||||
CV_Assert(ext == ".xml");
|
||||
return model_path.substr(0u, sz - EXT_LEN) + ".bin";
|
||||
}
|
||||
|
||||
#ifdef HAVE_INF_ENGINE
|
||||
#ifdef HAVE_DIRECTX
|
||||
#ifdef HAVE_D3D11
|
||||
|
||||
// Since ATL headers might not be available on specific MSVS Build Tools
|
||||
// we use simple `CComPtr` implementation like as `ComPtrGuard`
|
||||
// which is not supposed to be the full functional replacement of `CComPtr`
|
||||
// and it uses as RAII to make sure utilization is correct
|
||||
template <typename COMNonManageableType>
|
||||
void release(COMNonManageableType *ptr) {
|
||||
if (ptr) {
|
||||
ptr->Release();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename COMNonManageableType>
|
||||
using ComPtrGuard = std::unique_ptr<COMNonManageableType, decltype(&release<COMNonManageableType>)>;
|
||||
|
||||
template <typename COMNonManageableType>
|
||||
ComPtrGuard<COMNonManageableType> createCOMPtrGuard(COMNonManageableType *ptr = nullptr) {
|
||||
return ComPtrGuard<COMNonManageableType> {ptr, &release<COMNonManageableType>};
|
||||
}
|
||||
|
||||
|
||||
using AccelParamsType = std::tuple<ComPtrGuard<ID3D11Device>, ComPtrGuard<ID3D11DeviceContext>>;
|
||||
|
||||
AccelParamsType create_device_with_ctx(IDXGIAdapter* adapter) {
|
||||
UINT flags = 0;
|
||||
D3D_FEATURE_LEVEL feature_levels[] = { D3D_FEATURE_LEVEL_11_1,
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
};
|
||||
D3D_FEATURE_LEVEL featureLevel;
|
||||
ID3D11Device* ret_device_ptr = nullptr;
|
||||
ID3D11DeviceContext* ret_ctx_ptr = nullptr;
|
||||
HRESULT err = D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN,
|
||||
nullptr, flags,
|
||||
feature_levels,
|
||||
ARRAYSIZE(feature_levels),
|
||||
D3D11_SDK_VERSION, &ret_device_ptr,
|
||||
&featureLevel, &ret_ctx_ptr);
|
||||
if (FAILED(err)) {
|
||||
throw std::runtime_error("Cannot create D3D11CreateDevice, error: " +
|
||||
std::to_string(HRESULT_CODE(err)));
|
||||
}
|
||||
|
||||
return std::make_tuple(createCOMPtrGuard(ret_device_ptr),
|
||||
createCOMPtrGuard(ret_ctx_ptr));
|
||||
}
|
||||
#endif // HAVE_D3D11
|
||||
#endif // HAVE_DIRECTX
|
||||
#endif // HAVE_INF_ENGINE
|
||||
} // anonymous namespace
|
||||
|
||||
namespace custom {
|
||||
G_API_NET(FaceDetector, <cv::GMat(cv::GMat)>, "face-detector");
|
||||
|
||||
using GDetections = cv::GArray<cv::Rect>;
|
||||
using GRect = cv::GOpaque<cv::Rect>;
|
||||
using GSize = cv::GOpaque<cv::Size>;
|
||||
using GPrims = cv::GArray<cv::gapi::wip::draw::Prim>;
|
||||
|
||||
G_API_OP(LocateROI, <GRect(GSize)>, "sample.custom.locate-roi") {
|
||||
static cv::GOpaqueDesc outMeta(const cv::GOpaqueDesc &) {
|
||||
return cv::empty_gopaque_desc();
|
||||
}
|
||||
};
|
||||
|
||||
G_API_OP(BBoxes, <GPrims(GDetections, GRect)>, "sample.custom.b-boxes") {
|
||||
static cv::GArrayDesc outMeta(const cv::GArrayDesc &, const cv::GOpaqueDesc &) {
|
||||
return cv::empty_array_desc();
|
||||
}
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(OCVLocateROI, LocateROI) {
|
||||
// This is the place where we can run extra analytics
|
||||
// on the input image frame and select the ROI (region
|
||||
// of interest) where we want to detect our objects (or
|
||||
// run any other inference).
|
||||
//
|
||||
// Currently it doesn't do anything intelligent,
|
||||
// but only crops the input image to square (this is
|
||||
// the most convenient aspect ratio for detectors to use)
|
||||
|
||||
static void run(const cv::Size& in_size, cv::Rect &out_rect) {
|
||||
|
||||
// Identify the central point & square size (- some padding)
|
||||
const auto center = cv::Point{in_size.width/2, in_size.height/2};
|
||||
auto sqside = std::min(in_size.width, in_size.height);
|
||||
|
||||
// Now build the central square ROI
|
||||
out_rect = cv::Rect{ center.x - sqside/2
|
||||
, center.y - sqside/2
|
||||
, sqside
|
||||
, sqside
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(OCVBBoxes, BBoxes) {
|
||||
// This kernel converts the rectangles into G-API's
|
||||
// rendering primitives
|
||||
static void run(const std::vector<cv::Rect> &in_face_rcs,
|
||||
const cv::Rect &in_roi,
|
||||
std::vector<cv::gapi::wip::draw::Prim> &out_prims) {
|
||||
out_prims.clear();
|
||||
const auto cvt = [](const cv::Rect &rc, const cv::Scalar &clr) {
|
||||
return cv::gapi::wip::draw::Rect(rc, clr, 2);
|
||||
};
|
||||
out_prims.emplace_back(cvt(in_roi, CV_RGB(0,255,255))); // cyan
|
||||
for (auto &&rc : in_face_rcs) {
|
||||
out_prims.emplace_back(cvt(rc, CV_RGB(0,255,0))); // green
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace custom
|
||||
|
||||
namespace cfg {
|
||||
typename cv::gapi::wip::onevpl::CfgParam create_from_string(const std::string &line);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
cv::CommandLineParser cmd(argc, argv, keys);
|
||||
cmd.about(about);
|
||||
if (cmd.has("help")) {
|
||||
cmd.printMessage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get file name
|
||||
std::string file_path = cmd.get<std::string>("input");
|
||||
const std::string output = cmd.get<std::string>("output");
|
||||
const auto face_model_path = cmd.get<std::string>("facem");
|
||||
|
||||
// check ouput file extension
|
||||
if (!output.empty()) {
|
||||
auto ext = output.find_last_of(".");
|
||||
if (ext == std::string::npos || (output.substr(ext + 1) != "avi")) {
|
||||
std::cerr << "Output file should have *.avi extension for output video" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// get oneVPL cfg params from cmd
|
||||
std::stringstream params_list(cmd.get<std::string>("cfg_params"));
|
||||
std::vector<cv::gapi::wip::onevpl::CfgParam> source_cfgs;
|
||||
try {
|
||||
std::string line;
|
||||
while (std::getline(params_list, line, ';')) {
|
||||
source_cfgs.push_back(cfg::create_from_string(line));
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
std::cerr << "Invalid cfg parameter: " << ex.what() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const std::string& device_id = cmd.get<std::string>("faced");
|
||||
auto face_net = cv::gapi::ie::Params<custom::FaceDetector> {
|
||||
face_model_path, // path to topology IR
|
||||
get_weights_path(face_model_path), // path to weights
|
||||
device_id
|
||||
};
|
||||
|
||||
// Create device_ptr & context_ptr using graphic API
|
||||
// InferenceEngine requires such device & context to create its own
|
||||
// remote shared context through InferenceEngine::ParamMap in
|
||||
// GAPI InferenceEngine backend to provide interoperability with onevpl::GSource
|
||||
// So GAPI InferenceEngine backend and onevpl::GSource MUST share the same
|
||||
// device and context
|
||||
void* accel_device_ptr = nullptr;
|
||||
void* accel_ctx_ptr = nullptr;
|
||||
|
||||
#ifdef HAVE_INF_ENGINE
|
||||
#ifdef HAVE_DIRECTX
|
||||
#ifdef HAVE_D3D11
|
||||
auto dx11_dev = createCOMPtrGuard<ID3D11Device>();
|
||||
auto dx11_ctx = createCOMPtrGuard<ID3D11DeviceContext>();
|
||||
|
||||
if (device_id.find("GPU") != std::string::npos) {
|
||||
auto adapter_factory = createCOMPtrGuard<IDXGIFactory>();
|
||||
{
|
||||
IDXGIFactory* out_factory = nullptr;
|
||||
HRESULT err = CreateDXGIFactory(__uuidof(IDXGIFactory),
|
||||
reinterpret_cast<void**>(&out_factory));
|
||||
if (FAILED(err)) {
|
||||
std::cerr << "Cannot create CreateDXGIFactory, error: " << HRESULT_CODE(err) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
adapter_factory = createCOMPtrGuard(out_factory);
|
||||
}
|
||||
|
||||
auto intel_adapter = createCOMPtrGuard<IDXGIAdapter>();
|
||||
UINT adapter_index = 0;
|
||||
const unsigned int refIntelVendorID = 0x8086;
|
||||
IDXGIAdapter* out_adapter = nullptr;
|
||||
|
||||
while (adapter_factory->EnumAdapters(adapter_index, &out_adapter) != DXGI_ERROR_NOT_FOUND) {
|
||||
DXGI_ADAPTER_DESC desc{};
|
||||
out_adapter->GetDesc(&desc);
|
||||
if (desc.VendorId == refIntelVendorID) {
|
||||
intel_adapter = createCOMPtrGuard(out_adapter);
|
||||
break;
|
||||
}
|
||||
++adapter_index;
|
||||
}
|
||||
|
||||
if (!intel_adapter) {
|
||||
std::cerr << "No Intel GPU adapter on aboard. Exit" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::tie(dx11_dev, dx11_ctx) = create_device_with_ctx(intel_adapter.get());
|
||||
accel_device_ptr = reinterpret_cast<void*>(dx11_dev.get());
|
||||
accel_ctx_ptr = reinterpret_cast<void*>(dx11_ctx.get());
|
||||
|
||||
// put accel type description for VPL source
|
||||
source_cfgs.push_back(cfg::create_from_string(
|
||||
"mfxImplDescription.AccelerationMode"
|
||||
":"
|
||||
"MFX_ACCEL_MODE_VIA_D3D11"));
|
||||
}
|
||||
|
||||
#endif // HAVE_D3D11
|
||||
#endif // HAVE_DIRECTX
|
||||
// set ctx_config for GPU device only - no need in case of CPU device type
|
||||
if (device_id.find("GPU") != std::string::npos) {
|
||||
InferenceEngine::ParamMap ctx_config({{"CONTEXT_TYPE", "VA_SHARED"},
|
||||
{"VA_DEVICE", accel_device_ptr} });
|
||||
|
||||
face_net.cfgContextParams(ctx_config);
|
||||
}
|
||||
#endif // HAVE_INF_ENGINE
|
||||
|
||||
auto kernels = cv::gapi::kernels
|
||||
< custom::OCVLocateROI
|
||||
, custom::OCVBBoxes>();
|
||||
auto networks = cv::gapi::networks(face_net);
|
||||
|
||||
// Create source
|
||||
cv::Ptr<cv::gapi::wip::IStreamSource> cap;
|
||||
try {
|
||||
if (device_id.find("GPU") != std::string::npos) {
|
||||
cap = cv::gapi::wip::make_onevpl_src(file_path, source_cfgs,
|
||||
device_id,
|
||||
accel_device_ptr,
|
||||
accel_ctx_ptr);
|
||||
} else {
|
||||
cap = cv::gapi::wip::make_onevpl_src(file_path, source_cfgs);
|
||||
}
|
||||
std::cout << "oneVPL source desription: " << cap->descr_of() << std::endl;
|
||||
} catch (const std::exception& ex) {
|
||||
std::cerr << "Cannot create source: " << ex.what() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
cv::GMetaArg descr = cap->descr_of();
|
||||
auto frame_descr = cv::util::get<cv::GFrameDesc>(descr);
|
||||
|
||||
// Now build the graph
|
||||
cv::GFrame in;
|
||||
auto size = cv::gapi::streaming::size(in);
|
||||
auto roi = custom::LocateROI::on(size);
|
||||
auto blob = cv::gapi::infer<custom::FaceDetector>(roi, in);
|
||||
cv::GArray<cv::Rect> rcs = cv::gapi::parseSSD(blob, size, 0.5f, true, true);
|
||||
auto out_frame = cv::gapi::wip::draw::renderFrame(in, custom::BBoxes::on(rcs, roi));
|
||||
auto out = cv::gapi::streaming::BGR(out_frame);
|
||||
|
||||
cv::GStreamingCompiled pipeline;
|
||||
try {
|
||||
pipeline = cv::GComputation(cv::GIn(in), cv::GOut(out))
|
||||
.compileStreaming(cv::compile_args(kernels, networks));
|
||||
} catch (const std::exception& ex) {
|
||||
std::cerr << "Exception occured during pipeline construction: " << ex.what() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
// The execution part
|
||||
|
||||
// TODO USE may set pool size from outside and set queue_capacity size,
|
||||
// compile arg: cv::gapi::streaming::queue_capacity
|
||||
pipeline.setSource(std::move(cap));
|
||||
pipeline.start();
|
||||
|
||||
size_t frames = 0u;
|
||||
cv::TickMeter tm;
|
||||
cv::VideoWriter writer;
|
||||
if (!output.empty() && !writer.isOpened()) {
|
||||
const auto sz = cv::Size{frame_descr.size.width, frame_descr.size.height};
|
||||
writer.open(output, cv::VideoWriter::fourcc('M','J','P','G'), 25.0, sz);
|
||||
CV_Assert(writer.isOpened());
|
||||
}
|
||||
|
||||
cv::Mat outMat;
|
||||
tm.start();
|
||||
while (pipeline.pull(cv::gout(outMat))) {
|
||||
cv::imshow("Out", outMat);
|
||||
cv::waitKey(1);
|
||||
if (!output.empty()) {
|
||||
writer << outMat;
|
||||
}
|
||||
++frames;
|
||||
}
|
||||
tm.stop();
|
||||
std::cout << "Processed " << frames << " frames" << " (" << frames / tm.getTimeSec() << " FPS)" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
namespace cfg {
|
||||
typename cv::gapi::wip::onevpl::CfgParam create_from_string(const std::string &line) {
|
||||
using namespace cv::gapi::wip;
|
||||
|
||||
if (line.empty()) {
|
||||
throw std::runtime_error("Cannot parse CfgParam from emply line");
|
||||
}
|
||||
|
||||
std::string::size_type name_endline_pos = line.find(':');
|
||||
if (name_endline_pos == std::string::npos) {
|
||||
throw std::runtime_error("Cannot parse CfgParam from: " + line +
|
||||
"\nExpected separator \":\"");
|
||||
}
|
||||
|
||||
std::string name = line.substr(0, name_endline_pos);
|
||||
std::string value = line.substr(name_endline_pos + 1);
|
||||
|
||||
return cv::gapi::wip::onevpl::CfgParam::create(name, value);
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
#include <opencv2/gapi/cpu/gcpukernel.hpp>
|
||||
#include <opencv2/gapi/streaming/cap.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
#include <opencv2/gapi/infer/parsers.hpp>
|
||||
|
||||
const std::string about =
|
||||
"This is an OpenCV-based version of Privacy Masking Camera example";
|
||||
|
|
@ -49,12 +50,6 @@ G_API_NET(FaceDetector, <cv::GMat(cv::GMat)>, "face-detector"
|
|||
|
||||
using GDetections = cv::GArray<cv::Rect>;
|
||||
|
||||
G_API_OP(ParseSSD, <GDetections(cv::GMat, cv::GMat, int)>, "custom.privacy_masking.postproc") {
|
||||
static cv::GArrayDesc outMeta(const cv::GMatDesc &, const cv::GMatDesc &, int) {
|
||||
return cv::empty_array_desc();
|
||||
}
|
||||
};
|
||||
|
||||
using GPrims = cv::GArray<cv::gapi::wip::draw::Prim>;
|
||||
|
||||
G_API_OP(ToMosaic, <GPrims(GDetections, GDetections)>, "custom.privacy_masking.to_mosaic") {
|
||||
|
|
@ -63,53 +58,6 @@ G_API_OP(ToMosaic, <GPrims(GDetections, GDetections)>, "custom.privacy_masking.t
|
|||
}
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(OCVParseSSD, ParseSSD) {
|
||||
static void run(const cv::Mat &in_ssd_result,
|
||||
const cv::Mat &in_frame,
|
||||
const int filter_label,
|
||||
std::vector<cv::Rect> &out_objects) {
|
||||
const auto &in_ssd_dims = in_ssd_result.size;
|
||||
CV_Assert(in_ssd_dims.dims() == 4u);
|
||||
|
||||
const int MAX_PROPOSALS = in_ssd_dims[2];
|
||||
const int OBJECT_SIZE = in_ssd_dims[3];
|
||||
CV_Assert(OBJECT_SIZE == 7); // fixed SSD object size
|
||||
|
||||
const cv::Size upscale = in_frame.size();
|
||||
const cv::Rect surface({0,0}, upscale);
|
||||
|
||||
out_objects.clear();
|
||||
|
||||
const float *data = in_ssd_result.ptr<float>();
|
||||
for (int i = 0; i < MAX_PROPOSALS; i++) {
|
||||
const float image_id = data[i * OBJECT_SIZE + 0];
|
||||
const float label = data[i * OBJECT_SIZE + 1];
|
||||
const float confidence = data[i * OBJECT_SIZE + 2];
|
||||
const float rc_left = data[i * OBJECT_SIZE + 3];
|
||||
const float rc_top = data[i * OBJECT_SIZE + 4];
|
||||
const float rc_right = data[i * OBJECT_SIZE + 5];
|
||||
const float rc_bottom = data[i * OBJECT_SIZE + 6];
|
||||
|
||||
if (image_id < 0.f) {
|
||||
break; // marks end-of-detections
|
||||
}
|
||||
if (confidence < 0.5f) {
|
||||
continue; // skip objects with low confidence
|
||||
}
|
||||
if (filter_label != -1 && static_cast<int>(label) != filter_label) {
|
||||
continue; // filter out object classes if filter is specified
|
||||
}
|
||||
|
||||
cv::Rect rc; // map relative coordinates to the original image scale
|
||||
rc.x = static_cast<int>(rc_left * upscale.width);
|
||||
rc.y = static_cast<int>(rc_top * upscale.height);
|
||||
rc.width = static_cast<int>(rc_right * upscale.width) - rc.x;
|
||||
rc.height = static_cast<int>(rc_bottom * upscale.height) - rc.y;
|
||||
out_objects.emplace_back(rc & surface);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(OCVToMosaic, ToMosaic) {
|
||||
static void run(const std::vector<cv::Rect> &in_plate_rcs,
|
||||
const std::vector<cv::Rect> &in_face_rcs,
|
||||
|
|
@ -150,10 +98,13 @@ int main(int argc, char *argv[])
|
|||
cv::GMat blob_faces = cv::gapi::infer<custom::FaceDetector>(in);
|
||||
// VehLicDetector from Open Model Zoo marks vehicles with label "1" and
|
||||
// license plates with label "2", filter out license plates only.
|
||||
cv::GArray<cv::Rect> rc_plates = custom::ParseSSD::on(blob_plates, in, 2);
|
||||
cv::GOpaque<cv::Size> sz = cv::gapi::streaming::size(in);
|
||||
cv::GArray<cv::Rect> rc_plates, rc_faces;
|
||||
cv::GArray<int> labels;
|
||||
std::tie(rc_plates, labels) = cv::gapi::parseSSD(blob_plates, sz, 0.5f, 2);
|
||||
// Face detector produces faces only so there's no need to filter by label,
|
||||
// pass "-1".
|
||||
cv::GArray<cv::Rect> rc_faces = custom::ParseSSD::on(blob_faces, in, -1);
|
||||
std::tie(rc_faces, labels) = cv::gapi::parseSSD(blob_faces, sz, 0.5f, -1);
|
||||
cv::GMat out = cv::gapi::wip::draw::render3ch(in, custom::ToMosaic::on(rc_plates, rc_faces));
|
||||
cv::GComputation graph(in, out);
|
||||
|
||||
|
|
@ -169,7 +120,7 @@ int main(int argc, char *argv[])
|
|||
weights_path(face_model_path), // path to weights
|
||||
cmd.get<std::string>("faced"), // device specifier
|
||||
};
|
||||
auto kernels = cv::gapi::kernels<custom::OCVParseSSD, custom::OCVToMosaic>();
|
||||
auto kernels = cv::gapi::kernels<custom::OCVToMosaic>();
|
||||
auto networks = cv::gapi::networks(plate_net, face_net);
|
||||
|
||||
cv::TickMeter tm;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,184 @@
|
|||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/gapi/infer/ie.hpp>
|
||||
#include <opencv2/gapi/cpu/gcpukernel.hpp>
|
||||
#include <opencv2/gapi/streaming/cap.hpp>
|
||||
#include <opencv2/gapi/operators.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
|
||||
const std::string keys =
|
||||
"{ h help | | Print this help message }"
|
||||
"{ input | | Path to the input video file }"
|
||||
"{ output | | Path to the output video file }"
|
||||
"{ ssm | semantic-segmentation-adas-0001.xml | Path to OpenVINO IE semantic segmentation model (.xml) }";
|
||||
|
||||
// 20 colors for 20 classes of semantic-segmentation-adas-0001
|
||||
const std::vector<cv::Vec3b> colors = {
|
||||
{ 128, 64, 128 },
|
||||
{ 232, 35, 244 },
|
||||
{ 70, 70, 70 },
|
||||
{ 156, 102, 102 },
|
||||
{ 153, 153, 190 },
|
||||
{ 153, 153, 153 },
|
||||
{ 30, 170, 250 },
|
||||
{ 0, 220, 220 },
|
||||
{ 35, 142, 107 },
|
||||
{ 152, 251, 152 },
|
||||
{ 180, 130, 70 },
|
||||
{ 60, 20, 220 },
|
||||
{ 0, 0, 255 },
|
||||
{ 142, 0, 0 },
|
||||
{ 70, 0, 0 },
|
||||
{ 100, 60, 0 },
|
||||
{ 90, 0, 0 },
|
||||
{ 230, 0, 0 },
|
||||
{ 32, 11, 119 },
|
||||
{ 0, 74, 111 },
|
||||
};
|
||||
|
||||
namespace {
|
||||
std::string get_weights_path(const std::string &model_path) {
|
||||
const auto EXT_LEN = 4u;
|
||||
const auto sz = model_path.size();
|
||||
CV_Assert(sz > EXT_LEN);
|
||||
|
||||
auto ext = model_path.substr(sz - EXT_LEN);
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char c){
|
||||
return static_cast<unsigned char>(std::tolower(c));
|
||||
});
|
||||
CV_Assert(ext == ".xml");
|
||||
return model_path.substr(0u, sz - EXT_LEN) + ".bin";
|
||||
}
|
||||
|
||||
void classesToColors(const cv::Mat &out_blob,
|
||||
cv::Mat &mask_img) {
|
||||
const int H = out_blob.size[0];
|
||||
const int W = out_blob.size[1];
|
||||
|
||||
mask_img.create(H, W, CV_8UC3);
|
||||
GAPI_Assert(out_blob.type() == CV_8UC1);
|
||||
const uint8_t* const classes = out_blob.ptr<uint8_t>();
|
||||
|
||||
for (int rowId = 0; rowId < H; ++rowId) {
|
||||
for (int colId = 0; colId < W; ++colId) {
|
||||
uint8_t class_id = classes[rowId * W + colId];
|
||||
mask_img.at<cv::Vec3b>(rowId, colId) =
|
||||
class_id < colors.size()
|
||||
? colors[class_id]
|
||||
: cv::Vec3b{0, 0, 0}; // NB: sample supports 20 classes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void probsToClasses(const cv::Mat& probs, cv::Mat& classes) {
|
||||
const int C = probs.size[1];
|
||||
const int H = probs.size[2];
|
||||
const int W = probs.size[3];
|
||||
|
||||
classes.create(H, W, CV_8UC1);
|
||||
GAPI_Assert(probs.depth() == CV_32F);
|
||||
float* out_p = reinterpret_cast<float*>(probs.data);
|
||||
uint8_t* classes_p = reinterpret_cast<uint8_t*>(classes.data);
|
||||
|
||||
for (int h = 0; h < H; ++h) {
|
||||
for (int w = 0; w < W; ++w) {
|
||||
double max = 0;
|
||||
int class_id = 0;
|
||||
for (int c = 0; c < C; ++c) {
|
||||
int idx = c * H * W + h * W + w;
|
||||
if (out_p[idx] > max) {
|
||||
max = out_p[idx];
|
||||
class_id = c;
|
||||
}
|
||||
}
|
||||
classes_p[h * W + w] = static_cast<uint8_t>(class_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace custom {
|
||||
G_API_OP(PostProcessing, <cv::GMat(cv::GMat, cv::GMat)>, "sample.custom.post_processing") {
|
||||
static cv::GMatDesc outMeta(const cv::GMatDesc &in, const cv::GMatDesc &) {
|
||||
return in;
|
||||
}
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(OCVPostProcessing, PostProcessing) {
|
||||
static void run(const cv::Mat &in, const cv::Mat &out_blob, cv::Mat &out) {
|
||||
cv::Mat classes;
|
||||
// NB: If output has more than single plane, it contains probabilities
|
||||
// otherwise class id.
|
||||
if (out_blob.size[1] > 1) {
|
||||
probsToClasses(out_blob, classes);
|
||||
} else {
|
||||
out_blob.convertTo(classes, CV_8UC1);
|
||||
classes = classes.reshape(1, out_blob.size[2]);
|
||||
}
|
||||
|
||||
cv::Mat mask_img;
|
||||
classesToColors(classes, mask_img);
|
||||
cv::resize(mask_img, out, in.size());
|
||||
}
|
||||
};
|
||||
} // namespace custom
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
cv::CommandLineParser cmd(argc, argv, keys);
|
||||
if (cmd.has("help")) {
|
||||
cmd.printMessage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Prepare parameters first
|
||||
const std::string input = cmd.get<std::string>("input");
|
||||
const std::string output = cmd.get<std::string>("output");
|
||||
const auto model_path = cmd.get<std::string>("ssm");
|
||||
const auto weights_path = get_weights_path(model_path);
|
||||
const auto device = "CPU";
|
||||
G_API_NET(SemSegmNet, <cv::GMat(cv::GMat)>, "semantic-segmentation");
|
||||
const auto net = cv::gapi::ie::Params<SemSegmNet> {
|
||||
model_path, weights_path, device
|
||||
};
|
||||
const auto kernels = cv::gapi::kernels<custom::OCVPostProcessing>();
|
||||
const auto networks = cv::gapi::networks(net);
|
||||
|
||||
// Now build the graph
|
||||
cv::GMat in;
|
||||
cv::GMat out_blob = cv::gapi::infer<SemSegmNet>(in);
|
||||
cv::GMat post_proc_out = custom::PostProcessing::on(in, out_blob);
|
||||
cv::GMat blending_in = in * 0.3f;
|
||||
cv::GMat blending_out = post_proc_out * 0.7f;
|
||||
cv::GMat out = blending_in + blending_out;
|
||||
|
||||
cv::GStreamingCompiled pipeline = cv::GComputation(cv::GIn(in), cv::GOut(out))
|
||||
.compileStreaming(cv::compile_args(kernels, networks));
|
||||
auto inputs = cv::gin(cv::gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(input));
|
||||
|
||||
// The execution part
|
||||
pipeline.setSource(std::move(inputs));
|
||||
|
||||
cv::VideoWriter writer;
|
||||
cv::TickMeter tm;
|
||||
cv::Mat outMat;
|
||||
|
||||
std::size_t frames = 0u;
|
||||
tm.start();
|
||||
pipeline.start();
|
||||
while (pipeline.pull(cv::gout(outMat))) {
|
||||
++frames;
|
||||
cv::imshow("Out", outMat);
|
||||
cv::waitKey(1);
|
||||
if (!output.empty()) {
|
||||
if (!writer.isOpened()) {
|
||||
const auto sz = cv::Size{outMat.cols, outMat.rows};
|
||||
writer.open(output, cv::VideoWriter::fourcc('M','J','P','G'), 25.0, sz);
|
||||
CV_Assert(writer.isOpened());
|
||||
}
|
||||
writer << outMat;
|
||||
}
|
||||
}
|
||||
tm.stop();
|
||||
std::cout << "Processed " << frames << " frames" << " (" << frames / tm.getTimeSec() << " FPS)" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -23,6 +23,31 @@
|
|||
#include "compiler/gmodelbuilder.hpp"
|
||||
#include "compiler/gcompiler.hpp"
|
||||
#include "compiler/gcompiled_priv.hpp"
|
||||
#include "compiler/gstreaming_priv.hpp"
|
||||
|
||||
static cv::GTypesInfo collectInfo(const cv::gimpl::GModel::ConstGraph& g,
|
||||
const std::vector<ade::NodeHandle>& nhs) {
|
||||
cv::GTypesInfo info;
|
||||
info.reserve(nhs.size());
|
||||
|
||||
ade::util::transform(nhs, std::back_inserter(info), [&g](const ade::NodeHandle& nh) {
|
||||
const auto& data = g.metadata(nh).get<cv::gimpl::Data>();
|
||||
return cv::GTypeInfo{data.shape, data.kind, data.ctor};
|
||||
});
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
// NB: This function is used to collect graph input/output info.
|
||||
// Needed for python bridge to unpack inputs and constructs outputs properly.
|
||||
static cv::GraphInfo::Ptr collectGraphInfo(const cv::GComputation::Priv& priv)
|
||||
{
|
||||
auto g = cv::gimpl::GCompiler::makeGraph(priv);
|
||||
cv::gimpl::GModel::ConstGraph cgr(*g);
|
||||
auto in_info = collectInfo(cgr, cgr.metadata().get<cv::gimpl::Protocol>().in_nhs);
|
||||
auto out_info = collectInfo(cgr, cgr.metadata().get<cv::gimpl::Protocol>().out_nhs);
|
||||
return cv::GraphInfo::Ptr(new cv::GraphInfo{std::move(in_info), std::move(out_info)});
|
||||
}
|
||||
|
||||
// cv::GComputation private implementation /////////////////////////////////////
|
||||
// <none>
|
||||
|
|
@ -105,8 +130,37 @@ cv::GStreamingCompiled cv::GComputation::compileStreaming(GMetaArgs &&metas, GCo
|
|||
|
||||
cv::GStreamingCompiled cv::GComputation::compileStreaming(GCompileArgs &&args)
|
||||
{
|
||||
// NB: Used by python bridge
|
||||
if (!m_priv->m_info)
|
||||
{
|
||||
m_priv->m_info = collectGraphInfo(*m_priv);
|
||||
}
|
||||
|
||||
cv::gimpl::GCompiler comp(*this, {}, std::move(args));
|
||||
return comp.compileStreaming();
|
||||
auto compiled = comp.compileStreaming();
|
||||
|
||||
compiled.priv().setInInfo(m_priv->m_info->inputs);
|
||||
compiled.priv().setOutInfo(m_priv->m_info->outputs);
|
||||
|
||||
return compiled;
|
||||
}
|
||||
|
||||
cv::GStreamingCompiled cv::GComputation::compileStreaming(const cv::detail::ExtractMetaCallback &callback,
|
||||
GCompileArgs &&args)
|
||||
{
|
||||
// NB: Used by python bridge
|
||||
if (!m_priv->m_info)
|
||||
{
|
||||
m_priv->m_info = collectGraphInfo(*m_priv);
|
||||
}
|
||||
|
||||
auto ins = callback(m_priv->m_info->inputs);
|
||||
cv::gimpl::GCompiler comp(*this, std::move(ins), std::move(args));
|
||||
auto compiled = comp.compileStreaming();
|
||||
compiled.priv().setInInfo(m_priv->m_info->inputs);
|
||||
compiled.priv().setOutInfo(m_priv->m_info->outputs);
|
||||
|
||||
return compiled;
|
||||
}
|
||||
|
||||
// FIXME: Introduce similar query/test method for GMetaArgs as a building block
|
||||
|
|
@ -172,50 +226,25 @@ void cv::GComputation::apply(const std::vector<cv::Mat> &ins,
|
|||
}
|
||||
|
||||
// NB: This overload is called from python code
|
||||
cv::GRunArgs cv::GComputation::apply(GRunArgs &&ins, GCompileArgs &&args)
|
||||
cv::GRunArgs cv::GComputation::apply(const cv::detail::ExtractArgsCallback &callback,
|
||||
GCompileArgs &&args)
|
||||
{
|
||||
recompile(descr_of(ins), std::move(args));
|
||||
// NB: Used by python bridge
|
||||
if (!m_priv->m_info)
|
||||
{
|
||||
m_priv->m_info = collectGraphInfo(*m_priv);
|
||||
}
|
||||
|
||||
const auto& out_info = m_priv->m_lastCompiled.priv().outInfo();
|
||||
auto ins = callback(m_priv->m_info->inputs);
|
||||
recompile(descr_of(ins), std::move(args));
|
||||
|
||||
GRunArgs run_args;
|
||||
GRunArgsP outs;
|
||||
run_args.reserve(out_info.size());
|
||||
outs.reserve(out_info.size());
|
||||
run_args.reserve(m_priv->m_info->outputs.size());
|
||||
outs.reserve(m_priv->m_info->outputs.size());
|
||||
|
||||
cv::detail::constructGraphOutputs(m_priv->m_info->outputs, run_args, outs);
|
||||
|
||||
for (auto&& info : out_info)
|
||||
{
|
||||
switch (info.shape)
|
||||
{
|
||||
case cv::GShape::GMAT:
|
||||
{
|
||||
run_args.emplace_back(cv::Mat{});
|
||||
outs.emplace_back(&cv::util::get<cv::Mat>(run_args.back()));
|
||||
break;
|
||||
}
|
||||
case cv::GShape::GSCALAR:
|
||||
{
|
||||
run_args.emplace_back(cv::Scalar{});
|
||||
outs.emplace_back(&cv::util::get<cv::Scalar>(run_args.back()));
|
||||
break;
|
||||
}
|
||||
case cv::GShape::GARRAY:
|
||||
{
|
||||
switch (info.kind)
|
||||
{
|
||||
case cv::detail::OpaqueKind::CV_POINT2F:
|
||||
run_args.emplace_back(cv::detail::VectorRef{std::vector<cv::Point2f>{}});
|
||||
outs.emplace_back(cv::util::get<cv::detail::VectorRef>(run_args.back()));
|
||||
break;
|
||||
default:
|
||||
util::throw_error(std::logic_error("Unsupported kind for GArray"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
util::throw_error(std::logic_error("Only cv::GMat and cv::GScalar are supported for python output"));
|
||||
}
|
||||
}
|
||||
m_priv->m_lastCompiled(std::move(ins), std::move(outs));
|
||||
return run_args;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,13 @@
|
|||
|
||||
namespace cv {
|
||||
|
||||
struct GraphInfo
|
||||
{
|
||||
using Ptr = std::shared_ptr<GraphInfo>;
|
||||
cv::GTypesInfo inputs;
|
||||
cv::GTypesInfo outputs;
|
||||
};
|
||||
|
||||
class GComputation::Priv
|
||||
{
|
||||
public:
|
||||
|
|
@ -36,9 +43,10 @@ public:
|
|||
, Dump // A deserialized graph
|
||||
>;
|
||||
|
||||
GCompiled m_lastCompiled;
|
||||
GMetaArgs m_lastMetas; // TODO: make GCompiled remember its metas?
|
||||
Shape m_shape;
|
||||
GCompiled m_lastCompiled;
|
||||
GMetaArgs m_lastMetas; // TODO: make GCompiled remember its metas?
|
||||
Shape m_shape;
|
||||
GraphInfo::Ptr m_info; // NB: Used by python bridge
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,77 +7,20 @@
|
|||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#include <functional> // hash
|
||||
#include <numeric> // accumulate
|
||||
#include <unordered_set>
|
||||
#include <iterator>
|
||||
|
||||
#include <ade/util/algorithm.hpp>
|
||||
|
||||
#include <opencv2/gapi/infer.hpp>
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
cv::gapi::GNetPackage::GNetPackage(std::initializer_list<GNetParam> ii)
|
||||
: networks(ii) {
|
||||
}
|
||||
|
||||
cv::gapi::GNetPackage::GNetPackage(std::vector<GNetParam> nets)
|
||||
: networks(nets) {
|
||||
}
|
||||
|
||||
std::vector<cv::gapi::GBackend> cv::gapi::GNetPackage::backends() const {
|
||||
std::unordered_set<cv::gapi::GBackend> unique_set;
|
||||
for (const auto &nn : networks) unique_set.insert(nn.backend);
|
||||
return std::vector<cv::gapi::GBackend>(unique_set.begin(), unique_set.end());
|
||||
}
|
||||
|
||||
// FIXME: Inference API is currently only available in full mode
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
|
||||
cv::GInferInputs::GInferInputs()
|
||||
: in_blobs(std::make_shared<Map>())
|
||||
{
|
||||
}
|
||||
|
||||
cv::GMat& cv::GInferInputs::operator[](const std::string& name) {
|
||||
return (*in_blobs)[name];
|
||||
}
|
||||
|
||||
const cv::GInferInputs::Map& cv::GInferInputs::getBlobs() const {
|
||||
return *in_blobs;
|
||||
}
|
||||
|
||||
void cv::GInferInputs::setInput(const std::string& name, const cv::GMat& value) {
|
||||
in_blobs->emplace(name, value);
|
||||
}
|
||||
|
||||
struct cv::GInferOutputs::Priv
|
||||
{
|
||||
Priv(std::shared_ptr<cv::GCall>);
|
||||
|
||||
std::shared_ptr<cv::GCall> call;
|
||||
InOutInfo* info = nullptr;
|
||||
std::unordered_map<std::string, cv::GMat> out_blobs;
|
||||
};
|
||||
|
||||
cv::GInferOutputs::Priv::Priv(std::shared_ptr<cv::GCall> c)
|
||||
: call(std::move(c)), info(cv::util::any_cast<InOutInfo>(&call->params()))
|
||||
{
|
||||
}
|
||||
|
||||
cv::GInferOutputs::GInferOutputs(std::shared_ptr<cv::GCall> call)
|
||||
: m_priv(std::make_shared<cv::GInferOutputs::Priv>(std::move(call)))
|
||||
{
|
||||
}
|
||||
|
||||
cv::GMat cv::GInferOutputs::at(const std::string& name)
|
||||
{
|
||||
auto it = m_priv->out_blobs.find(name);
|
||||
if (it == m_priv->out_blobs.end()) {
|
||||
// FIXME: Avoid modifying GKernel
|
||||
// Expect output to be always GMat
|
||||
m_priv->call->kernel().outShapes.push_back(cv::GShape::GMAT);
|
||||
// ...so _empty_ constructor is passed here.
|
||||
m_priv->call->kernel().outCtors.emplace_back(cv::util::monostate{});
|
||||
int out_idx = static_cast<int>(m_priv->out_blobs.size());
|
||||
it = m_priv->out_blobs.emplace(name, m_priv->call->yield(out_idx)).first;
|
||||
m_priv->info->out_names.push_back(name);
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
#endif // GAPI_STANDALONE
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2018-2019 Intel Corporation
|
||||
// Copyright (C) 2018-2021 Intel Corporation
|
||||
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
|
@ -55,6 +55,16 @@ const std::vector<cv::GTransform> &cv::gapi::GKernelPackage::get_transformations
|
|||
return m_transformations;
|
||||
}
|
||||
|
||||
std::vector<std::string> cv::gapi::GKernelPackage::get_kernel_ids() const
|
||||
{
|
||||
std::vector<std::string> ids;
|
||||
for (auto &&id : m_id_kernels)
|
||||
{
|
||||
ids.emplace_back(id.first);
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::combine(const GKernelPackage &lhs,
|
||||
const GKernelPackage &rhs)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -201,6 +201,52 @@ bool cv::can_describe(const GMetaArgs &metas, const GRunArgs &args)
|
|||
});
|
||||
}
|
||||
|
||||
void cv::gimpl::proto::validate_input_meta_arg(const cv::GMetaArg& meta)
|
||||
{
|
||||
switch (meta.index())
|
||||
{
|
||||
case cv::GMetaArg::index_of<cv::GMatDesc>():
|
||||
{
|
||||
cv::gimpl::proto::validate_input_meta(cv::util::get<GMatDesc>(meta)); //may throw
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cv::gimpl::proto::validate_input_meta(const cv::GMatDesc& meta)
|
||||
{
|
||||
if (meta.dims.empty())
|
||||
{
|
||||
if (!(meta.size.height > 0 && meta.size.width > 0))
|
||||
{
|
||||
cv::util::throw_error
|
||||
(std::logic_error(
|
||||
"Image format is invalid. Size must contain positive values"
|
||||
", got width: " + std::to_string(meta.size.width ) +
|
||||
(", height: ") + std::to_string(meta.size.height)));
|
||||
}
|
||||
|
||||
if (!(meta.chan > 0))
|
||||
{
|
||||
cv::util::throw_error
|
||||
(std::logic_error(
|
||||
"Image format is invalid. Channel mustn't be negative value, got channel: " +
|
||||
std::to_string(meta.chan)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!(meta.depth >= 0))
|
||||
{
|
||||
cv::util::throw_error
|
||||
(std::logic_error(
|
||||
"Image format is invalid. Depth must be positive value, got depth: " +
|
||||
std::to_string(meta.depth)));
|
||||
}
|
||||
// All checks are ok
|
||||
}
|
||||
|
||||
// FIXME: Is it tested for all types?
|
||||
// FIXME: Where does this validation happen??
|
||||
void cv::validate_input_arg(const GRunArg& arg)
|
||||
|
|
@ -212,13 +258,15 @@ void cv::validate_input_arg(const GRunArg& arg)
|
|||
case GRunArg::index_of<cv::UMat>():
|
||||
{
|
||||
const auto desc = cv::descr_of(util::get<cv::UMat>(arg));
|
||||
GAPI_Assert(desc.size.height != 0 && desc.size.width != 0 && "incorrect dimensions of cv::UMat!"); break;
|
||||
cv::gimpl::proto::validate_input_meta(desc); //may throw
|
||||
break;
|
||||
}
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
case GRunArg::index_of<cv::Mat>():
|
||||
{
|
||||
const auto desc = cv::descr_of(util::get<cv::Mat>(arg));
|
||||
GAPI_Assert(desc.size.height != 0 && desc.size.width != 0 && "incorrect dimensions of Mat!"); break;
|
||||
cv::gimpl::proto::validate_input_meta(desc); //may throw
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// No extra handling
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue