mirror of
https://github.com/opencv/opencv.git
synced 2026-07-31 00:03:03 +04:00
Merge branch 4.x
This commit is contained in:
@@ -163,6 +163,22 @@ set(gapi_srcs
|
||||
src/backends/ie/bindings_ie.cpp
|
||||
src/backends/python/gpythonbackend.cpp
|
||||
|
||||
# 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/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
|
||||
|
||||
# Utils (ITT tracing)
|
||||
src/utils/itt.cpp
|
||||
)
|
||||
@@ -234,6 +250,20 @@ 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(WIN32)
|
||||
# Required for htonl/ntohl on Windows
|
||||
|
||||
@@ -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}/../")
|
||||
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -40,6 +40,10 @@ namespace gimpl
|
||||
|
||||
namespace gapi
|
||||
{
|
||||
/**
|
||||
* @brief This namespace contains G-API CPU backend functions,
|
||||
* structures, and symbols.
|
||||
*/
|
||||
namespace cpu
|
||||
{
|
||||
/**
|
||||
@@ -492,7 +496,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:
|
||||
|
||||
@@ -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 modules/gapi/samples/dynamic_graph.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 modules/gapi/samples/dynamic_graph.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 modules/gapi/samples/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 modules/gapi/samples/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)
|
||||
|
||||
@@ -340,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 {
|
||||
|
||||
@@ -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; };
|
||||
|
||||
@@ -437,11 +437,7 @@ public:
|
||||
*
|
||||
* @sa @ref gapi_compile_args
|
||||
*/
|
||||
GStreamingCompiled compileStreaming(GMetaArgs &&in_metas, GCompileArgs &&args = {});
|
||||
|
||||
/// @private -- Exclude this function from OpenCV documentation
|
||||
GAPI_WRAP GStreamingCompiled compileStreaming(const cv::detail::ExtractMetaCallback &callback,
|
||||
GCompileArgs &&args = {});
|
||||
GAPI_WRAP GStreamingCompiled compileStreaming(GMetaArgs &&in_metas, GCompileArgs &&args = {});
|
||||
|
||||
/**
|
||||
* @brief Compile the computation for streaming mode.
|
||||
@@ -464,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;
|
||||
|
||||
@@ -372,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:
|
||||
@@ -412,6 +413,7 @@ namespace std
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
/// @private
|
||||
class GFunctor
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -307,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 modules/gapi/samples/dynamic_graph.cpp GIOProtoArgs usage
|
||||
*
|
||||
*/
|
||||
template<typename Tg>
|
||||
|
||||
@@ -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 modules/gapi/samples/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:
|
||||
|
||||
@@ -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};
|
||||
}
|
||||
@@ -196,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
|
||||
@@ -255,7 +274,7 @@ public:
|
||||
|
||||
// NB: Used from python
|
||||
/// @private -- Exclude this function from OpenCV documentation
|
||||
GAPI_WRAP std::tuple<bool, cv::GRunArgs> pull();
|
||||
GAPI_WRAP std::tuple<bool, cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>> pull();
|
||||
|
||||
/**
|
||||
* @brief Get some next available data from the pipeline.
|
||||
@@ -372,6 +391,14 @@ 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.
|
||||
@@ -379,9 +406,11 @@ namespace streaming {
|
||||
* In the streaming mode the pipeline steps are connected with queues
|
||||
* and this compile argument controls every queue's size.
|
||||
*/
|
||||
struct GAPI_EXPORTS queue_capacity
|
||||
struct GAPI_EXPORTS_W_SIMPLE queue_capacity
|
||||
{
|
||||
GAPI_WRAP
|
||||
explicit queue_capacity(size_t cap = 1) : capacity(cap) { };
|
||||
GAPI_PROP_RW
|
||||
size_t capacity;
|
||||
};
|
||||
/** @} */
|
||||
|
||||
@@ -43,19 +43,6 @@ namespace detail
|
||||
GOPAQUE, // a cv::GOpaqueU (note - exactly GOpaqueU, not GOpaque<T>!)
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr const char* meta_to_string() noexcept;
|
||||
template<>
|
||||
constexpr const char* meta_to_string<cv::GMatDesc>() noexcept { return "GMatDesc"; }
|
||||
template<>
|
||||
constexpr const char* meta_to_string<cv::GScalarDesc>() noexcept { return "GScalarDesc"; }
|
||||
template<>
|
||||
constexpr const char* meta_to_string<cv::GArrayDesc>() noexcept { return "GArrayDesc"; }
|
||||
template<>
|
||||
constexpr const char* meta_to_string<cv::GOpaqueDesc>() noexcept { return "GOpaqueDesc"; }
|
||||
template<>
|
||||
constexpr const char* meta_to_string<cv::GFrameDesc>() noexcept { return "GFrameDesc";}
|
||||
|
||||
// Describe G-API types (G-types) with traits. Mostly used by
|
||||
// cv::GArg to store meta information about types passed into
|
||||
// operation arguments. Please note that cv::GComputation is
|
||||
|
||||
@@ -35,7 +35,6 @@ namespace detail
|
||||
template<> struct ProtoToMeta<cv::GScalar> { using type = cv::GScalarDesc; };
|
||||
template<typename U> struct ProtoToMeta<cv::GArray<U> > { using type = cv::GArrayDesc; };
|
||||
template<typename U> struct ProtoToMeta<cv::GOpaque<U> > { using type = cv::GOpaqueDesc; };
|
||||
template<> struct ProtoToMeta<cv::GFrame> { using type = cv::GFrameDesc; };
|
||||
template<typename T> using ProtoToMetaT = typename ProtoToMeta<T>::type;
|
||||
|
||||
//workaround for MSVC 19.0 bug
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -136,11 +136,12 @@ public:
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
void setInput(const std::string& name, U in)
|
||||
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...>;
|
||||
@@ -653,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
|
||||
@@ -664,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;
|
||||
|
||||
@@ -22,17 +22,28 @@ 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);
|
||||
|
||||
GBackend backend() const;
|
||||
std::string tag() const;
|
||||
cv::util::any params() const;
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
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();
|
||||
@@ -69,7 +74,11 @@ struct ParamDesc {
|
||||
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;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
@@ -110,7 +119,8 @@ public:
|
||||
, {}
|
||||
, {}
|
||||
, {}
|
||||
, 1u} {
|
||||
, 1u
|
||||
, {}} {
|
||||
};
|
||||
|
||||
/** @overload
|
||||
@@ -130,7 +140,8 @@ public:
|
||||
, {}
|
||||
, {}
|
||||
, {}
|
||||
, 1u} {
|
||||
, 1u
|
||||
, {}} {
|
||||
};
|
||||
|
||||
/** @brief Specifies sequence of network input layers names for inference.
|
||||
@@ -212,6 +223,30 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @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.
|
||||
@@ -313,7 +348,10 @@ public:
|
||||
const std::string &model,
|
||||
const std::string &weights,
|
||||
const std::string &device)
|
||||
: desc{ model, weights, device, {}, {}, {}, 0u, 0u, detail::ParamDesc::Kind::Load, true, {}, {}, {}, 1u}, m_tag(tag) {
|
||||
: desc{ model, weights, device, {}, {}, {}, 0u, 0u,
|
||||
detail::ParamDesc::Kind::Load, true, {}, {}, {}, 1u,
|
||||
{}},
|
||||
m_tag(tag) {
|
||||
};
|
||||
|
||||
/** @overload
|
||||
@@ -328,7 +366,10 @@ public:
|
||||
Params(const std::string &tag,
|
||||
const std::string &model,
|
||||
const std::string &device)
|
||||
: desc{ model, {}, device, {}, {}, {}, 0u, 0u, detail::ParamDesc::Kind::Import, true, {}, {}, {}, 1u}, m_tag(tag) {
|
||||
: desc{ model, {}, device, {}, {}, {}, 0u, 0u,
|
||||
detail::ParamDesc::Kind::Import, true, {}, {}, {}, 1u,
|
||||
{}},
|
||||
m_tag(tag) {
|
||||
};
|
||||
|
||||
/** @see ie::Params::pluginConfig. */
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -87,9 +88,9 @@ the larger side of the rectangle.
|
||||
*/
|
||||
GAPI_EXPORTS_W GArray<Rect> parseSSD(const GMat& in,
|
||||
const GOpaque<Size>& inSz,
|
||||
const float confidenceThreshold = 0.5f,
|
||||
const bool alignmentToSquare = false,
|
||||
const bool filterOutOfBounds = false);
|
||||
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
|
||||
|
||||
@@ -15,30 +15,119 @@
|
||||
#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;
|
||||
|
||||
// Cast underlying MediaFrame adapter to the particular adapter type,
|
||||
// return nullptr if underlying type is different
|
||||
template<typename T> T* get() 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();
|
||||
@@ -46,6 +135,16 @@ public:
|
||||
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;
|
||||
@@ -58,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;
|
||||
@@ -65,19 +201,38 @@ 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;
|
||||
@@ -86,7 +241,16 @@ public:
|
||||
// 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
|
||||
{
|
||||
/**
|
||||
|
||||
@@ -13,11 +13,13 @@
|
||||
# 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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -15,6 +15,11 @@ namespace cv
|
||||
{
|
||||
namespace gapi
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief This namespace contains G-API PlaidML backend functions,
|
||||
* structures, and symbols.
|
||||
*/
|
||||
namespace plaidml
|
||||
{
|
||||
|
||||
|
||||
@@ -13,6 +13,15 @@
|
||||
|
||||
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();
|
||||
|
||||
@@ -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,10 +92,10 @@ 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,
|
||||
const Prims& prims,
|
||||
cv::GCompileArgs&& args = {});
|
||||
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
|
||||
|
||||
@@ -139,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
|
||||
|
||||
@@ -150,9 +150,9 @@ 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
|
||||
|
||||
@@ -169,11 +169,15 @@ GAPI_EXPORTS GFrame renderFrame(const GFrame& m_frame,
|
||||
} // 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
|
||||
@@ -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:
|
||||
@@ -108,10 +111,12 @@ public:
|
||||
// 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::Adapter 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::Adapter does nothing by default. "
|
||||
"Please, implement it in derived class to properly deserialize the object.");
|
||||
}
|
||||
};
|
||||
using AdapterP = std::shared_ptr<Adapter>;
|
||||
@@ -146,6 +151,7 @@ private:
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
RMat make_rmat(Ts&&... args) { return { std::make_shared<T>(std::forward<Ts>(args)...) }; }
|
||||
/** @} */
|
||||
|
||||
} //namespace cv
|
||||
|
||||
|
||||
@@ -13,69 +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> &p);
|
||||
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&);
|
||||
GAPI_EXPORTS std::vector<char> serialize(const std::vector<std::string>&);
|
||||
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> &p) {
|
||||
return detail::getVectorOfStrings(p);
|
||||
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
|
||||
@@ -83,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:
|
||||
@@ -99,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;
|
||||
@@ -116,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
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -146,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>
|
||||
@@ -186,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());
|
||||
@@ -206,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());
|
||||
@@ -233,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) {
|
||||
@@ -254,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;
|
||||
@@ -268,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);
|
||||
@@ -298,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::Adapter, 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;
|
||||
@@ -350,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;
|
||||
|
||||
@@ -361,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 modules/gapi/samples/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
|
||||
|
||||
@@ -38,6 +38,11 @@ enum class StereoOutputFormat {
|
||||
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") {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -74,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,
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,74 @@
|
||||
// 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 <string>
|
||||
|
||||
#include <opencv2/gapi/own/exports.hpp> // GAPI_EXPORTS
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
|
||||
struct GAPI_EXPORTS DataProviderException : public std::exception {
|
||||
virtual ~DataProviderException() {};
|
||||
};
|
||||
|
||||
struct GAPI_EXPORTS DataProviderSystemErrorException : public DataProviderException {
|
||||
DataProviderSystemErrorException(int error_code, const std::string& desription = std::string());
|
||||
virtual ~DataProviderSystemErrorException();
|
||||
virtual const char* what() const noexcept override;
|
||||
|
||||
private:
|
||||
std::string reason;
|
||||
};
|
||||
|
||||
/**
|
||||
* @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>;
|
||||
|
||||
virtual ~IDataProvider() {};
|
||||
|
||||
/**
|
||||
* 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 0 in EOF which considered as not-fail case.
|
||||
*
|
||||
* @param out_data_bytes_size the available capacity of out_data buffer.
|
||||
* @param out_data the output consumer buffer with capacity out_data_bytes_size.
|
||||
* @return fetched bytes count.
|
||||
*/
|
||||
virtual size_t fetch_data(size_t out_data_bytes_size, void* out_data) = 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
|
||||
@@ -0,0 +1,64 @@
|
||||
// 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>
|
||||
|
||||
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(std::shared_ptr<IDataProvider> source,
|
||||
const CfgParams& cfg_params = CfgParams{});
|
||||
~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
|
||||
|
||||
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
|
||||
@@ -117,6 +117,65 @@ namespace detail
|
||||
static type get(std::tuple<Objs...>&& objs) { return std::forward<std::tuple<Objs...>>(objs); }
|
||||
};
|
||||
} // 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>;
|
||||
|
||||
@@ -11,6 +11,36 @@ def register(mname):
|
||||
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.
|
||||
@@ -54,6 +84,10 @@ class GOpaque():
|
||||
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)
|
||||
@@ -113,6 +147,10 @@ class GArray():
|
||||
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)
|
||||
@@ -134,6 +172,7 @@ def op(op_id, in_types, out_types):
|
||||
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
|
||||
}
|
||||
|
||||
@@ -149,22 +188,24 @@ def op(op_id, in_types, out_types):
|
||||
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_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
|
||||
@@ -244,3 +285,15 @@ def kernel(op_cls):
|
||||
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
|
||||
|
||||
@@ -11,12 +11,14 @@
|
||||
#include <opencv2/gapi/python/python.hpp>
|
||||
|
||||
// NB: Python wrapper replaces :: with _ for classes
|
||||
using gapi_GKernelPackage = cv::gapi::GKernelPackage;
|
||||
using gapi_GNetPackage = cv::gapi::GNetPackage;
|
||||
using gapi_ie_PyParams = cv::gapi::ie::PyParams;
|
||||
using gapi_wip_IStreamSource_Ptr = cv::Ptr<cv::gapi::wip::IStreamSource>;
|
||||
using detail_ExtractArgsCallback = cv::detail::ExtractArgsCallback;
|
||||
using detail_ExtractMetaCallback = cv::detail::ExtractMetaCallback;
|
||||
using gapi_GKernelPackage = cv::gapi::GKernelPackage;
|
||||
using gapi_GNetPackage = cv::gapi::GNetPackage;
|
||||
using gapi_ie_PyParams = cv::gapi::ie::PyParams;
|
||||
using gapi_wip_IStreamSource_Ptr = cv::Ptr<cv::gapi::wip::IStreamSource>;
|
||||
using detail_ExtractArgsCallback = cv::detail::ExtractArgsCallback;
|
||||
using detail_ExtractMetaCallback = cv::detail::ExtractMetaCallback;
|
||||
using vector_GNetParam = std::vector<cv::gapi::GNetParam>;
|
||||
using gapi_streaming_queue_capacity = cv::gapi::streaming::queue_capacity;
|
||||
|
||||
// NB: Python wrapper generate T_U for T<U>
|
||||
// This behavior is only observed for inputs
|
||||
@@ -42,6 +44,7 @@ using GArray_Rect = cv::GArray<cv::Rect>;
|
||||
using GArray_Scalar = cv::GArray<cv::Scalar>;
|
||||
using GArray_Mat = cv::GArray<cv::Mat>;
|
||||
using GArray_GMat = cv::GArray<cv::GMat>;
|
||||
using GArray_Prim = cv::GArray<cv::gapi::wip::draw::Prim>;
|
||||
|
||||
// FIXME: Python wrapper generate code without namespace std,
|
||||
// so it cause error: "string wasn't declared"
|
||||
@@ -124,6 +127,95 @@ PyObject* pyopencv_from(const cv::detail::PyObjectHolder& v)
|
||||
return o;
|
||||
}
|
||||
|
||||
// #FIXME: Is it possible to implement pyopencv_from/pyopencv_to for generic
|
||||
// cv::variant<Types...> ?
|
||||
template <>
|
||||
PyObject* pyopencv_from(const cv::gapi::wip::draw::Prim& prim)
|
||||
{
|
||||
switch (prim.index())
|
||||
{
|
||||
case cv::gapi::wip::draw::Prim::index_of<cv::gapi::wip::draw::Rect>():
|
||||
return pyopencv_from(cv::util::get<cv::gapi::wip::draw::Rect>(prim));
|
||||
case cv::gapi::wip::draw::Prim::index_of<cv::gapi::wip::draw::Text>():
|
||||
return pyopencv_from(cv::util::get<cv::gapi::wip::draw::Text>(prim));
|
||||
case cv::gapi::wip::draw::Prim::index_of<cv::gapi::wip::draw::Circle>():
|
||||
return pyopencv_from(cv::util::get<cv::gapi::wip::draw::Circle>(prim));
|
||||
case cv::gapi::wip::draw::Prim::index_of<cv::gapi::wip::draw::Line>():
|
||||
return pyopencv_from(cv::util::get<cv::gapi::wip::draw::Line>(prim));
|
||||
case cv::gapi::wip::draw::Prim::index_of<cv::gapi::wip::draw::Poly>():
|
||||
return pyopencv_from(cv::util::get<cv::gapi::wip::draw::Poly>(prim));
|
||||
case cv::gapi::wip::draw::Prim::index_of<cv::gapi::wip::draw::Mosaic>():
|
||||
return pyopencv_from(cv::util::get<cv::gapi::wip::draw::Mosaic>(prim));
|
||||
case cv::gapi::wip::draw::Prim::index_of<cv::gapi::wip::draw::Image>():
|
||||
return pyopencv_from(cv::util::get<cv::gapi::wip::draw::Image>(prim));
|
||||
}
|
||||
|
||||
util::throw_error(std::logic_error("Unsupported draw primitive type"));
|
||||
}
|
||||
|
||||
template <>
|
||||
PyObject* pyopencv_from(const cv::gapi::wip::draw::Prims& value)
|
||||
{
|
||||
return pyopencv_from_generic_vec(value);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool pyopencv_to(PyObject* obj, cv::gapi::wip::draw::Prim& value, const ArgInfo&)
|
||||
{
|
||||
#define TRY_EXTRACT(Prim) \
|
||||
if (PyObject_TypeCheck(obj, reinterpret_cast<PyTypeObject*>(pyopencv_gapi_wip_draw_##Prim##_TypePtr))) \
|
||||
{ \
|
||||
value = reinterpret_cast<pyopencv_gapi_wip_draw_##Prim##_t*>(obj)->v; \
|
||||
return true; \
|
||||
} \
|
||||
|
||||
TRY_EXTRACT(Rect)
|
||||
TRY_EXTRACT(Text)
|
||||
TRY_EXTRACT(Circle)
|
||||
TRY_EXTRACT(Line)
|
||||
TRY_EXTRACT(Mosaic)
|
||||
TRY_EXTRACT(Image)
|
||||
TRY_EXTRACT(Poly)
|
||||
#undef TRY_EXTRACT
|
||||
|
||||
failmsg("Unsupported primitive type");
|
||||
return false;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool pyopencv_to(PyObject* obj, cv::gapi::wip::draw::Prims& value, const ArgInfo& info)
|
||||
{
|
||||
return pyopencv_to_generic_vec(obj, value, info);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool pyopencv_to(PyObject* obj, cv::GMetaArg& value, const ArgInfo&)
|
||||
{
|
||||
#define TRY_EXTRACT(Meta) \
|
||||
if (PyObject_TypeCheck(obj, \
|
||||
reinterpret_cast<PyTypeObject*>(pyopencv_##Meta##_TypePtr))) \
|
||||
{ \
|
||||
value = reinterpret_cast<pyopencv_##Meta##_t*>(obj)->v; \
|
||||
return true; \
|
||||
} \
|
||||
|
||||
TRY_EXTRACT(GMatDesc)
|
||||
TRY_EXTRACT(GScalarDesc)
|
||||
TRY_EXTRACT(GArrayDesc)
|
||||
TRY_EXTRACT(GOpaqueDesc)
|
||||
#undef TRY_EXTRACT
|
||||
|
||||
failmsg("Unsupported cv::GMetaArg type");
|
||||
return false;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool pyopencv_to(PyObject* obj, cv::GMetaArgs& value, const ArgInfo& info)
|
||||
{
|
||||
return pyopencv_to_generic_vec(obj, value, info);
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
PyObject* pyopencv_from(const cv::GArg& value)
|
||||
{
|
||||
@@ -136,20 +228,21 @@ PyObject* pyopencv_from(const cv::GArg& value)
|
||||
#define UNSUPPORTED(T) case cv::detail::OpaqueKind::CV_##T: break
|
||||
switch (value.opaque_kind)
|
||||
{
|
||||
HANDLE_CASE(BOOL, bool);
|
||||
HANDLE_CASE(INT, int);
|
||||
HANDLE_CASE(DOUBLE, double);
|
||||
HANDLE_CASE(FLOAT, float);
|
||||
HANDLE_CASE(STRING, std::string);
|
||||
HANDLE_CASE(POINT, cv::Point);
|
||||
HANDLE_CASE(POINT2F, cv::Point2f);
|
||||
HANDLE_CASE(SIZE, cv::Size);
|
||||
HANDLE_CASE(RECT, cv::Rect);
|
||||
HANDLE_CASE(SCALAR, cv::Scalar);
|
||||
HANDLE_CASE(MAT, cv::Mat);
|
||||
HANDLE_CASE(UNKNOWN, cv::detail::PyObjectHolder);
|
||||
HANDLE_CASE(BOOL, bool);
|
||||
HANDLE_CASE(INT, int);
|
||||
HANDLE_CASE(INT64, int64_t);
|
||||
HANDLE_CASE(DOUBLE, double);
|
||||
HANDLE_CASE(FLOAT, float);
|
||||
HANDLE_CASE(STRING, std::string);
|
||||
HANDLE_CASE(POINT, cv::Point);
|
||||
HANDLE_CASE(POINT2F, cv::Point2f);
|
||||
HANDLE_CASE(SIZE, cv::Size);
|
||||
HANDLE_CASE(RECT, cv::Rect);
|
||||
HANDLE_CASE(SCALAR, cv::Scalar);
|
||||
HANDLE_CASE(MAT, cv::Mat);
|
||||
HANDLE_CASE(UNKNOWN, cv::detail::PyObjectHolder);
|
||||
HANDLE_CASE(DRAW_PRIM, cv::gapi::wip::draw::Prim);
|
||||
UNSUPPORTED(UINT64);
|
||||
UNSUPPORTED(DRAW_PRIM);
|
||||
#undef HANDLE_CASE
|
||||
#undef UNSUPPORTED
|
||||
}
|
||||
@@ -163,6 +256,18 @@ bool pyopencv_to(PyObject* obj, cv::GArg& value, const ArgInfo& info)
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool pyopencv_to(PyObject* obj, std::vector<cv::gapi::GNetParam>& value, const ArgInfo& info)
|
||||
{
|
||||
return pyopencv_to_generic_vec(obj, value, info);
|
||||
}
|
||||
|
||||
template <>
|
||||
PyObject* pyopencv_from(const std::vector<cv::gapi::GNetParam>& value)
|
||||
{
|
||||
return pyopencv_from_generic_vec(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool pyopencv_to(PyObject* obj, std::vector<GCompileArg>& value, const ArgInfo& info)
|
||||
{
|
||||
@@ -175,12 +280,6 @@ PyObject* pyopencv_from(const std::vector<GCompileArg>& value)
|
||||
return pyopencv_from_generic_vec(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool pyopencv_to(PyObject* obj, GRunArgs& value, const ArgInfo& info)
|
||||
{
|
||||
return pyopencv_to_generic_vec(obj, value, info);
|
||||
}
|
||||
|
||||
template<>
|
||||
PyObject* pyopencv_from(const cv::detail::OpaqueRef& o)
|
||||
{
|
||||
@@ -188,6 +287,7 @@ PyObject* pyopencv_from(const cv::detail::OpaqueRef& o)
|
||||
{
|
||||
case cv::detail::OpaqueKind::CV_BOOL : return pyopencv_from(o.rref<bool>());
|
||||
case cv::detail::OpaqueKind::CV_INT : return pyopencv_from(o.rref<int>());
|
||||
case cv::detail::OpaqueKind::CV_INT64 : return pyopencv_from(o.rref<int64_t>());
|
||||
case cv::detail::OpaqueKind::CV_DOUBLE : return pyopencv_from(o.rref<double>());
|
||||
case cv::detail::OpaqueKind::CV_FLOAT : return pyopencv_from(o.rref<float>());
|
||||
case cv::detail::OpaqueKind::CV_STRING : return pyopencv_from(o.rref<std::string>());
|
||||
@@ -196,10 +296,10 @@ PyObject* pyopencv_from(const cv::detail::OpaqueRef& o)
|
||||
case cv::detail::OpaqueKind::CV_SIZE : return pyopencv_from(o.rref<cv::Size>());
|
||||
case cv::detail::OpaqueKind::CV_RECT : return pyopencv_from(o.rref<cv::Rect>());
|
||||
case cv::detail::OpaqueKind::CV_UNKNOWN : return pyopencv_from(o.rref<cv::GArg>());
|
||||
case cv::detail::OpaqueKind::CV_DRAW_PRIM : return pyopencv_from(o.rref<cv::gapi::wip::draw::Prim>());
|
||||
case cv::detail::OpaqueKind::CV_UINT64 : break;
|
||||
case cv::detail::OpaqueKind::CV_SCALAR : break;
|
||||
case cv::detail::OpaqueKind::CV_MAT : break;
|
||||
case cv::detail::OpaqueKind::CV_DRAW_PRIM : break;
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "Unsupported GOpaque type");
|
||||
@@ -213,6 +313,7 @@ PyObject* pyopencv_from(const cv::detail::VectorRef& v)
|
||||
{
|
||||
case cv::detail::OpaqueKind::CV_BOOL : return pyopencv_from_generic_vec(v.rref<bool>());
|
||||
case cv::detail::OpaqueKind::CV_INT : return pyopencv_from_generic_vec(v.rref<int>());
|
||||
case cv::detail::OpaqueKind::CV_INT64 : return pyopencv_from_generic_vec(v.rref<int64_t>());
|
||||
case cv::detail::OpaqueKind::CV_DOUBLE : return pyopencv_from_generic_vec(v.rref<double>());
|
||||
case cv::detail::OpaqueKind::CV_FLOAT : return pyopencv_from_generic_vec(v.rref<float>());
|
||||
case cv::detail::OpaqueKind::CV_STRING : return pyopencv_from_generic_vec(v.rref<std::string>());
|
||||
@@ -223,8 +324,8 @@ PyObject* pyopencv_from(const cv::detail::VectorRef& v)
|
||||
case cv::detail::OpaqueKind::CV_SCALAR : return pyopencv_from_generic_vec(v.rref<cv::Scalar>());
|
||||
case cv::detail::OpaqueKind::CV_MAT : return pyopencv_from_generic_vec(v.rref<cv::Mat>());
|
||||
case cv::detail::OpaqueKind::CV_UNKNOWN : return pyopencv_from_generic_vec(v.rref<cv::GArg>());
|
||||
case cv::detail::OpaqueKind::CV_DRAW_PRIM : return pyopencv_from_generic_vec(v.rref<cv::gapi::wip::draw::Prim>());
|
||||
case cv::detail::OpaqueKind::CV_UINT64 : break;
|
||||
case cv::detail::OpaqueKind::CV_DRAW_PRIM : break;
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "Unsupported GArray type");
|
||||
@@ -249,52 +350,69 @@ PyObject* pyopencv_from(const GRunArg& v)
|
||||
return pyopencv_from(util::get<cv::detail::OpaqueRef>(v));
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "Failed to unpack GRunArgs");
|
||||
PyErr_SetString(PyExc_TypeError, "Failed to unpack GRunArgs. Index of variant is unknown");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
PyObject* pyopencv_from(const cv::optional<T>& opt)
|
||||
{
|
||||
if (!opt.has_value())
|
||||
{
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
return pyopencv_from(*opt);
|
||||
}
|
||||
|
||||
template <>
|
||||
PyObject* pyopencv_from(const GOptRunArg& v)
|
||||
{
|
||||
switch (v.index())
|
||||
{
|
||||
case GOptRunArg::index_of<cv::optional<cv::Mat>>():
|
||||
return pyopencv_from(util::get<cv::optional<cv::Mat>>(v));
|
||||
|
||||
case GOptRunArg::index_of<cv::optional<cv::Scalar>>():
|
||||
return pyopencv_from(util::get<cv::optional<cv::Scalar>>(v));
|
||||
|
||||
case GOptRunArg::index_of<optional<cv::detail::VectorRef>>():
|
||||
return pyopencv_from(util::get<optional<cv::detail::VectorRef>>(v));
|
||||
|
||||
case GOptRunArg::index_of<optional<cv::detail::OpaqueRef>>():
|
||||
return pyopencv_from(util::get<optional<cv::detail::OpaqueRef>>(v));
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "Failed to unpack GOptRunArg. Index of variant is unknown");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template<>
|
||||
PyObject* pyopencv_from(const GRunArgs& value)
|
||||
{
|
||||
size_t i, n = value.size();
|
||||
|
||||
// NB: It doesn't make sense to return list with a single element
|
||||
if (n == 1)
|
||||
{
|
||||
PyObject* item = pyopencv_from(value[0]);
|
||||
if(!item)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
PyObject* list = PyList_New(n);
|
||||
for(i = 0; i < n; ++i)
|
||||
{
|
||||
PyObject* item = pyopencv_from(value[i]);
|
||||
if(!item)
|
||||
{
|
||||
Py_DECREF(list);
|
||||
PyErr_SetString(PyExc_TypeError, "Failed to unpack GRunArgs");
|
||||
return NULL;
|
||||
}
|
||||
PyList_SetItem(list, i, item);
|
||||
}
|
||||
|
||||
return list;
|
||||
return value.size() == 1 ? pyopencv_from(value[0]) : pyopencv_from_generic_vec(value);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool pyopencv_to(PyObject* obj, GMetaArgs& value, const ArgInfo& info)
|
||||
PyObject* pyopencv_from(const GOptRunArgs& value)
|
||||
{
|
||||
return pyopencv_to_generic_vec(obj, value, info);
|
||||
return value.size() == 1 ? pyopencv_from(value[0]) : pyopencv_from_generic_vec(value);
|
||||
}
|
||||
|
||||
template<>
|
||||
PyObject* pyopencv_from(const GMetaArgs& value)
|
||||
// FIXME: cv::variant should be wrapped once for all types.
|
||||
template <>
|
||||
PyObject* pyopencv_from(const cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>& v)
|
||||
{
|
||||
return pyopencv_from_generic_vec(value);
|
||||
using RunArgs = cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>;
|
||||
switch (v.index())
|
||||
{
|
||||
case RunArgs::index_of<cv::GRunArgs>():
|
||||
return pyopencv_from(util::get<cv::GRunArgs>(v));
|
||||
case RunArgs::index_of<cv::GOptRunArgs>():
|
||||
return pyopencv_from(util::get<cv::GOptRunArgs>(v));
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "Failed to recognize kind of RunArgs. Index of variant is unknown");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -318,16 +436,16 @@ void pyopencv_to_generic_vec_with_check(PyObject* from,
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static PyObject* extract_proto_args(PyObject* py_args, PyObject* kw)
|
||||
static T extract_proto_args(PyObject* py_args)
|
||||
{
|
||||
using namespace cv;
|
||||
|
||||
GProtoArgs args;
|
||||
Py_ssize_t size = PyTuple_Size(py_args);
|
||||
Py_ssize_t size = PyList_Size(py_args);
|
||||
args.reserve(size);
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
PyObject* item = PyTuple_GetItem(py_args, i);
|
||||
PyObject* item = PyList_GetItem(py_args, i);
|
||||
if (PyObject_TypeCheck(item, reinterpret_cast<PyTypeObject*>(pyopencv_GScalar_TypePtr)))
|
||||
{
|
||||
args.emplace_back(reinterpret_cast<pyopencv_GScalar_t*>(item)->v);
|
||||
@@ -346,22 +464,11 @@ static PyObject* extract_proto_args(PyObject* py_args, PyObject* kw)
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "Unsupported type for cv.GIn()/cv.GOut()");
|
||||
return NULL;
|
||||
util::throw_error(std::logic_error("Unsupported type for GProtoArgs"));
|
||||
}
|
||||
}
|
||||
|
||||
return pyopencv_from<T>(T{std::move(args)});
|
||||
}
|
||||
|
||||
static PyObject* pyopencv_cv_GIn(PyObject* , PyObject* py_args, PyObject* kw)
|
||||
{
|
||||
return extract_proto_args<GProtoInputArgs>(py_args, kw);
|
||||
}
|
||||
|
||||
static PyObject* pyopencv_cv_GOut(PyObject* , PyObject* py_args, PyObject* kw)
|
||||
{
|
||||
return extract_proto_args<GProtoOutputArgs>(py_args, kw);
|
||||
return T(std::move(args));
|
||||
}
|
||||
|
||||
static cv::detail::OpaqueRef extract_opaque_ref(PyObject* from, cv::detail::OpaqueKind kind)
|
||||
@@ -386,6 +493,7 @@ static cv::detail::OpaqueRef extract_opaque_ref(PyObject* from, cv::detail::Opaq
|
||||
HANDLE_CASE(RECT, cv::Rect);
|
||||
HANDLE_CASE(UNKNOWN, cv::GArg);
|
||||
UNSUPPORTED(UINT64);
|
||||
UNSUPPORTED(INT64);
|
||||
UNSUPPORTED(SCALAR);
|
||||
UNSUPPORTED(MAT);
|
||||
UNSUPPORTED(DRAW_PRIM);
|
||||
@@ -406,20 +514,21 @@ static cv::detail::VectorRef extract_vector_ref(PyObject* from, cv::detail::Opaq
|
||||
#define UNSUPPORTED(T) case cv::detail::OpaqueKind::CV_##T: break
|
||||
switch (kind)
|
||||
{
|
||||
HANDLE_CASE(BOOL, bool);
|
||||
HANDLE_CASE(INT, int);
|
||||
HANDLE_CASE(DOUBLE, double);
|
||||
HANDLE_CASE(FLOAT, float);
|
||||
HANDLE_CASE(STRING, std::string);
|
||||
HANDLE_CASE(POINT, cv::Point);
|
||||
HANDLE_CASE(POINT2F, cv::Point2f);
|
||||
HANDLE_CASE(SIZE, cv::Size);
|
||||
HANDLE_CASE(RECT, cv::Rect);
|
||||
HANDLE_CASE(SCALAR, cv::Scalar);
|
||||
HANDLE_CASE(MAT, cv::Mat);
|
||||
HANDLE_CASE(UNKNOWN, cv::GArg);
|
||||
HANDLE_CASE(BOOL, bool);
|
||||
HANDLE_CASE(INT, int);
|
||||
HANDLE_CASE(DOUBLE, double);
|
||||
HANDLE_CASE(FLOAT, float);
|
||||
HANDLE_CASE(STRING, std::string);
|
||||
HANDLE_CASE(POINT, cv::Point);
|
||||
HANDLE_CASE(POINT2F, cv::Point2f);
|
||||
HANDLE_CASE(SIZE, cv::Size);
|
||||
HANDLE_CASE(RECT, cv::Rect);
|
||||
HANDLE_CASE(SCALAR, cv::Scalar);
|
||||
HANDLE_CASE(MAT, cv::Mat);
|
||||
HANDLE_CASE(UNKNOWN, cv::GArg);
|
||||
HANDLE_CASE(DRAW_PRIM, cv::gapi::wip::draw::Prim);
|
||||
UNSUPPORTED(UINT64);
|
||||
UNSUPPORTED(DRAW_PRIM);
|
||||
UNSUPPORTED(INT64);
|
||||
#undef HANDLE_CASE
|
||||
#undef UNSUPPORTED
|
||||
}
|
||||
@@ -470,13 +579,15 @@ static cv::GRunArg extract_run_arg(const cv::GTypeInfo& info, PyObject* item)
|
||||
|
||||
static cv::GRunArgs extract_run_args(const cv::GTypesInfo& info, PyObject* py_args)
|
||||
{
|
||||
cv::GRunArgs args;
|
||||
Py_ssize_t tuple_size = PyTuple_Size(py_args);
|
||||
args.reserve(tuple_size);
|
||||
GAPI_Assert(PyList_Check(py_args));
|
||||
|
||||
for (int i = 0; i < tuple_size; ++i)
|
||||
cv::GRunArgs args;
|
||||
Py_ssize_t list_size = PyList_Size(py_args);
|
||||
args.reserve(list_size);
|
||||
|
||||
for (int i = 0; i < list_size; ++i)
|
||||
{
|
||||
args.push_back(extract_run_arg(info[i], PyTuple_GetItem(py_args, i)));
|
||||
args.push_back(extract_run_arg(info[i], PyList_GetItem(py_args, i)));
|
||||
}
|
||||
|
||||
return args;
|
||||
@@ -517,13 +628,15 @@ static cv::GMetaArg extract_meta_arg(const cv::GTypeInfo& info, PyObject* item)
|
||||
|
||||
static cv::GMetaArgs extract_meta_args(const cv::GTypesInfo& info, PyObject* py_args)
|
||||
{
|
||||
cv::GMetaArgs metas;
|
||||
Py_ssize_t tuple_size = PyTuple_Size(py_args);
|
||||
metas.reserve(tuple_size);
|
||||
GAPI_Assert(PyList_Check(py_args));
|
||||
|
||||
for (int i = 0; i < tuple_size; ++i)
|
||||
cv::GMetaArgs metas;
|
||||
Py_ssize_t list_size = PyList_Size(py_args);
|
||||
metas.reserve(list_size);
|
||||
|
||||
for (int i = 0; i < list_size; ++i)
|
||||
{
|
||||
metas.push_back(extract_meta_arg(info[i], PyTuple_GetItem(py_args, i)));
|
||||
metas.push_back(extract_meta_arg(info[i], PyList_GetItem(py_args, i)));
|
||||
}
|
||||
|
||||
return metas;
|
||||
@@ -581,7 +694,8 @@ static cv::GRunArgs run_py_kernel(cv::detail::PyObjectHolder kernel,
|
||||
cv::detail::PyObjectHolder result(
|
||||
PyObject_CallObject(kernel.get(), args.get()), false);
|
||||
|
||||
if (PyErr_Occurred()) {
|
||||
if (PyErr_Occurred())
|
||||
{
|
||||
PyErr_PrintEx(0);
|
||||
PyErr_Clear();
|
||||
throw std::logic_error("Python kernel failed with error!");
|
||||
@@ -589,8 +703,27 @@ static cv::GRunArgs run_py_kernel(cv::detail::PyObjectHolder kernel,
|
||||
// NB: In fact it's impossible situation, becase errors were handled above.
|
||||
GAPI_Assert(result.get() && "Python kernel returned NULL!");
|
||||
|
||||
outs = out_info.size() == 1 ? cv::GRunArgs{extract_run_arg(out_info[0], result.get())}
|
||||
: extract_run_args(out_info, result.get());
|
||||
if (out_info.size() == 1)
|
||||
{
|
||||
outs = cv::GRunArgs{extract_run_arg(out_info[0], result.get())};
|
||||
}
|
||||
else if (out_info.size() > 1)
|
||||
{
|
||||
GAPI_Assert(PyTuple_Check(result.get()));
|
||||
|
||||
Py_ssize_t tuple_size = PyTuple_Size(result.get());
|
||||
outs.reserve(tuple_size);
|
||||
|
||||
for (int i = 0; i < tuple_size; ++i)
|
||||
{
|
||||
outs.push_back(extract_run_arg(out_info[i], PyTuple_GetItem(result.get(), i)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Seems to be impossible case.
|
||||
GAPI_Assert(false);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -604,30 +737,12 @@ static cv::GRunArgs run_py_kernel(cv::detail::PyObjectHolder kernel,
|
||||
|
||||
static GMetaArg get_meta_arg(PyObject* obj)
|
||||
{
|
||||
if (PyObject_TypeCheck(obj,
|
||||
reinterpret_cast<PyTypeObject*>(pyopencv_GMatDesc_TypePtr)))
|
||||
{
|
||||
return cv::GMetaArg{reinterpret_cast<pyopencv_GMatDesc_t*>(obj)->v};
|
||||
}
|
||||
else if (PyObject_TypeCheck(obj,
|
||||
reinterpret_cast<PyTypeObject*>(pyopencv_GScalarDesc_TypePtr)))
|
||||
{
|
||||
return cv::GMetaArg{reinterpret_cast<pyopencv_GScalarDesc_t*>(obj)->v};
|
||||
}
|
||||
else if (PyObject_TypeCheck(obj,
|
||||
reinterpret_cast<PyTypeObject*>(pyopencv_GArrayDesc_TypePtr)))
|
||||
{
|
||||
return cv::GMetaArg{reinterpret_cast<pyopencv_GArrayDesc_t*>(obj)->v};
|
||||
}
|
||||
else if (PyObject_TypeCheck(obj,
|
||||
reinterpret_cast<PyTypeObject*>(pyopencv_GOpaqueDesc_TypePtr)))
|
||||
{
|
||||
return cv::GMetaArg{reinterpret_cast<pyopencv_GOpaqueDesc_t*>(obj)->v};
|
||||
}
|
||||
else
|
||||
cv::GMetaArg arg;
|
||||
if (!pyopencv_to(obj, arg, ArgInfo("arg", false)))
|
||||
{
|
||||
util::throw_error(std::logic_error("Unsupported output meta type"));
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
static cv::GMetaArgs get_meta_args(PyObject* tuple)
|
||||
@@ -645,8 +760,9 @@ static cv::GMetaArgs get_meta_args(PyObject* tuple)
|
||||
}
|
||||
|
||||
static GMetaArgs run_py_meta(cv::detail::PyObjectHolder out_meta,
|
||||
const cv::GMetaArgs &meta,
|
||||
const cv::GArgs &gargs) {
|
||||
const cv::GMetaArgs &meta,
|
||||
const cv::GArgs &gargs)
|
||||
{
|
||||
PyGILState_STATE gstate;
|
||||
gstate = PyGILState_Ensure();
|
||||
|
||||
@@ -688,7 +804,8 @@ static GMetaArgs run_py_meta(cv::detail::PyObjectHolder out_meta,
|
||||
cv::detail::PyObjectHolder result(
|
||||
PyObject_CallObject(out_meta.get(), args.get()), false);
|
||||
|
||||
if (PyErr_Occurred()) {
|
||||
if (PyErr_Occurred())
|
||||
{
|
||||
PyErr_PrintEx(0);
|
||||
PyErr_Clear();
|
||||
throw std::logic_error("Python outMeta failed with error!");
|
||||
@@ -720,21 +837,24 @@ static PyObject* pyopencv_cv_gapi_kernels(PyObject* , PyObject* py_args, PyObjec
|
||||
PyObject* user_kernel = PyTuple_GetItem(py_args, i);
|
||||
|
||||
PyObject* id_obj = PyObject_GetAttrString(user_kernel, "id");
|
||||
if (!id_obj) {
|
||||
if (!id_obj)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Python kernel should contain id, please use cv.gapi.kernel to define kernel");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject* out_meta = PyObject_GetAttrString(user_kernel, "outMeta");
|
||||
if (!out_meta) {
|
||||
if (!out_meta)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Python kernel should contain outMeta, please use cv.gapi.kernel to define kernel");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject* run = PyObject_GetAttrString(user_kernel, "run");
|
||||
if (!run) {
|
||||
if (!run)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Python kernel should contain run, please use cv.gapi.kernel to define kernel");
|
||||
return NULL;
|
||||
@@ -756,23 +876,6 @@ static PyObject* pyopencv_cv_gapi_kernels(PyObject* , PyObject* py_args, PyObjec
|
||||
return pyopencv_from(pkg);
|
||||
}
|
||||
|
||||
static PyObject* pyopencv_cv_gapi_networks(PyObject*, PyObject* py_args, PyObject*)
|
||||
{
|
||||
using namespace cv;
|
||||
gapi::GNetPackage pkg;
|
||||
Py_ssize_t size = PyTuple_Size(py_args);
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
gapi_ie_PyParams params;
|
||||
PyObject* item = PyTuple_GetItem(py_args, i);
|
||||
if (pyopencv_to(item, params, ArgInfo("PyParams", false)))
|
||||
{
|
||||
pkg += gapi::networks(params);
|
||||
}
|
||||
}
|
||||
return pyopencv_from(pkg);
|
||||
}
|
||||
|
||||
static PyObject* pyopencv_cv_gapi_op(PyObject* , PyObject* py_args, PyObject*)
|
||||
{
|
||||
using namespace cv;
|
||||
@@ -834,53 +937,54 @@ static PyObject* pyopencv_cv_gapi_op(PyObject* , PyObject* py_args, PyObject*)
|
||||
return pyopencv_from(cv::gapi::wip::op(id, outMetaWrapper, std::move(args)));
|
||||
}
|
||||
|
||||
static PyObject* pyopencv_cv_gin(PyObject*, PyObject* py_args, PyObject*)
|
||||
template<>
|
||||
bool pyopencv_to(PyObject* obj, cv::detail::ExtractArgsCallback& value, const ArgInfo&)
|
||||
{
|
||||
cv::detail::PyObjectHolder holder{py_args};
|
||||
auto callback = cv::detail::ExtractArgsCallback{[=](const cv::GTypesInfo& info)
|
||||
cv::detail::PyObjectHolder holder{obj};
|
||||
value = cv::detail::ExtractArgsCallback{[=](const cv::GTypesInfo& info)
|
||||
{
|
||||
PyGILState_STATE gstate;
|
||||
gstate = PyGILState_Ensure();
|
||||
|
||||
cv::GRunArgs args;
|
||||
try
|
||||
{
|
||||
args = extract_run_args(info, holder.get());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
PyGILState_STATE gstate;
|
||||
gstate = PyGILState_Ensure();
|
||||
|
||||
cv::GRunArgs args;
|
||||
try
|
||||
{
|
||||
args = extract_run_args(info, holder.get());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
PyGILState_Release(gstate);
|
||||
throw;
|
||||
}
|
||||
PyGILState_Release(gstate);
|
||||
return args;
|
||||
}};
|
||||
|
||||
return pyopencv_from(callback);
|
||||
throw;
|
||||
}
|
||||
PyGILState_Release(gstate);
|
||||
return args;
|
||||
}};
|
||||
return true;
|
||||
}
|
||||
|
||||
static PyObject* pyopencv_cv_descr_of(PyObject*, PyObject* py_args, PyObject*)
|
||||
template<>
|
||||
bool pyopencv_to(PyObject* obj, cv::detail::ExtractMetaCallback& value, const ArgInfo&)
|
||||
{
|
||||
Py_INCREF(py_args);
|
||||
auto callback = cv::detail::ExtractMetaCallback{[=](const cv::GTypesInfo& info)
|
||||
{
|
||||
PyGILState_STATE gstate;
|
||||
gstate = PyGILState_Ensure();
|
||||
cv::detail::PyObjectHolder holder{obj};
|
||||
value = cv::detail::ExtractMetaCallback{[=](const cv::GTypesInfo& info)
|
||||
{
|
||||
PyGILState_STATE gstate;
|
||||
gstate = PyGILState_Ensure();
|
||||
|
||||
cv::GMetaArgs args;
|
||||
try
|
||||
{
|
||||
args = extract_meta_args(info, py_args);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
PyGILState_Release(gstate);
|
||||
throw;
|
||||
}
|
||||
cv::GMetaArgs args;
|
||||
try
|
||||
{
|
||||
args = extract_meta_args(info, holder.get());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
PyGILState_Release(gstate);
|
||||
return args;
|
||||
}};
|
||||
return pyopencv_from(callback);
|
||||
throw;
|
||||
}
|
||||
PyGILState_Release(gstate);
|
||||
return args;
|
||||
}};
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -895,9 +999,12 @@ struct PyOpenCV_Converter<cv::GArray<T>>
|
||||
if (PyObject_TypeCheck(obj, reinterpret_cast<PyTypeObject*>(pyopencv_GArrayT_TypePtr)))
|
||||
{
|
||||
auto& array = reinterpret_cast<pyopencv_GArrayT_t*>(obj)->v;
|
||||
try {
|
||||
try
|
||||
{
|
||||
value = cv::util::get<cv::GArray<T>>(array.arg());
|
||||
} catch (...) {
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -918,9 +1025,12 @@ struct PyOpenCV_Converter<cv::GOpaque<T>>
|
||||
if (PyObject_TypeCheck(obj, reinterpret_cast<PyTypeObject*>(pyopencv_GOpaqueT_TypePtr)))
|
||||
{
|
||||
auto& opaque = reinterpret_cast<pyopencv_GOpaqueT_t*>(obj)->v;
|
||||
try {
|
||||
try
|
||||
{
|
||||
value = cv::util::get<cv::GOpaque<T>>(opaque.arg());
|
||||
} catch (...) {
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -929,11 +1039,39 @@ struct PyOpenCV_Converter<cv::GOpaque<T>>
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
bool pyopencv_to(PyObject* obj, cv::GProtoInputArgs& value, const ArgInfo& info)
|
||||
{
|
||||
try
|
||||
{
|
||||
value = extract_proto_args<cv::GProtoInputArgs>(obj);
|
||||
return true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
failmsg("Can't parse cv::GProtoInputArgs");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
bool pyopencv_to(PyObject* obj, cv::GProtoOutputArgs& value, const ArgInfo& info)
|
||||
{
|
||||
try
|
||||
{
|
||||
value = extract_proto_args<cv::GProtoOutputArgs>(obj);
|
||||
return true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
failmsg("Can't parse cv::GProtoOutputArgs");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// extend cv.gapi methods
|
||||
#define PYOPENCV_EXTRA_METHODS_GAPI \
|
||||
{"kernels", CV_PY_FN_WITH_KW(pyopencv_cv_gapi_kernels), "kernels(...) -> GKernelPackage"}, \
|
||||
{"networks", CV_PY_FN_WITH_KW(pyopencv_cv_gapi_networks), "networks(...) -> GNetPackage"}, \
|
||||
{"__op", CV_PY_FN_WITH_KW(pyopencv_cv_gapi_op), "__op(...) -> retval\n"},
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#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),
|
||||
@@ -24,24 +25,29 @@
|
||||
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(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(cv::GArg , cv::gapi::ArgType::CV_ANY, G) \
|
||||
WRAP_ARGS(cv::GMat , cv::gapi::ArgType::CV_GMAT, 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) \
|
||||
@@ -58,6 +64,7 @@ namespace gapi {
|
||||
enum ArgType {
|
||||
CV_BOOL,
|
||||
CV_INT,
|
||||
CV_INT64,
|
||||
CV_DOUBLE,
|
||||
CV_FLOAT,
|
||||
CV_STRING,
|
||||
@@ -68,6 +75,7 @@ enum ArgType {
|
||||
CV_SCALAR,
|
||||
CV_MAT,
|
||||
CV_GMAT,
|
||||
CV_DRAW_PRIM,
|
||||
CV_ANY,
|
||||
};
|
||||
|
||||
|
||||
@@ -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,64 +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);
|
||||
GAPI_EXPORTS_W GCompileArgs compile_args(gapi::GKernelPackage kernels, gapi::GNetPackage nets);
|
||||
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 { GAPI_WRAP 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);
|
||||
};
|
||||
|
||||
using GProtoInputArgs = GIOProtoArgs<In_Tag>;
|
||||
using GProtoOutputArgs = GIOProtoArgs<Out_Tag>;
|
||||
class GAPI_EXPORTS_W_SIMPLE GInferOutputs
|
||||
{
|
||||
public:
|
||||
GAPI_WRAP GInferOutputs();
|
||||
GAPI_WRAP cv::GMat at(const std::string& name);
|
||||
};
|
||||
|
||||
class GAPI_EXPORTS_W_SIMPLE GInferInputs
|
||||
{
|
||||
public:
|
||||
GAPI_WRAP GInferInputs();
|
||||
GAPI_WRAP void setInput(const std::string& name, const cv::GMat& value);
|
||||
GAPI_WRAP void setInput(const std::string& name, const cv::GFrame& value);
|
||||
};
|
||||
class GAPI_EXPORTS_W_SIMPLE GInferListOutputs
|
||||
{
|
||||
public:
|
||||
GAPI_WRAP GInferListOutputs();
|
||||
GAPI_WRAP cv::GArray<cv::GMat> at(const std::string& name);
|
||||
};
|
||||
|
||||
class GAPI_EXPORTS_W_SIMPLE GInferListInputs
|
||||
{
|
||||
public:
|
||||
GAPI_WRAP GInferListInputs();
|
||||
GAPI_WRAP void setInput(const std::string& name, const cv::GArray<cv::GMat>& value);
|
||||
GAPI_WRAP void setInput(const std::string& name, const cv::GArray<cv::Rect>& value);
|
||||
};
|
||||
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);
|
||||
};
|
||||
|
||||
class GAPI_EXPORTS_W_SIMPLE GInferOutputs
|
||||
{
|
||||
public:
|
||||
GAPI_WRAP GInferOutputs();
|
||||
GAPI_WRAP cv::GMat at(const std::string& name);
|
||||
};
|
||||
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);
|
||||
|
||||
class GAPI_EXPORTS_W_SIMPLE GInferListOutputs
|
||||
{
|
||||
public:
|
||||
GAPI_WRAP GInferListOutputs();
|
||||
GAPI_WRAP cv::GArray<cv::GMat> at(const std::string& name);
|
||||
};
|
||||
GAPI_EXPORTS_W cv::GMat desync(const cv::GMat &g);
|
||||
} // namespace streaming
|
||||
} // namespace gapi
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct GAPI_EXPORTS_W_SIMPLE ExtractArgsCallback { };
|
||||
struct GAPI_EXPORTS_W_SIMPLE ExtractMetaCallback { };
|
||||
} // namespace detail
|
||||
|
||||
namespace gapi
|
||||
{
|
||||
namespace wip
|
||||
{
|
||||
class GAPI_EXPORTS_W IStreamSource { };
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
namespace detail
|
||||
{
|
||||
gapi::GNetParam GAPI_EXPORTS_W strip(gapi::ie::PyParams params);
|
||||
} // namespace detail
|
||||
} // namespace cv
|
||||
|
||||
@@ -3,187 +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')
|
||||
|
||||
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);
|
||||
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 generate_random_points(self, sz):
|
||||
arr = np.random.random(sz).astype(np.float32).T
|
||||
return list(zip(arr[0], arr[1]))
|
||||
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_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 = []
|
||||
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)
|
||||
|
||||
# G-API
|
||||
data = cv.GArrayT(cv.gapi.CV_POINT2F)
|
||||
best_labels = cv.GArrayT(cv.gapi.CV_INT)
|
||||
# OpenCV
|
||||
expected = cv.split(in_mat)
|
||||
|
||||
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));
|
||||
# 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))
|
||||
|
||||
compact, labels, centers = comp.apply(cv.gin(in_vector, in_labels));
|
||||
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')
|
||||
|
||||
# Assert
|
||||
self.assertTrue(compact >= 0)
|
||||
self.assertEqual(amount, len(labels))
|
||||
self.assertEqual(K, len(centers))
|
||||
|
||||
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,103 +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(),
|
||||
np.array(actual, dtype=np.float32).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 test_bounding_rect(self):
|
||||
sz = 1280
|
||||
fscale = 256
|
||||
|
||||
def sample_value(fscale):
|
||||
return np.random.uniform(0, 255 * fscale) / fscale
|
||||
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)
|
||||
points = np.array([(sample_value(fscale), sample_value(fscale)) for _ in range(1280)], np.float32)
|
||||
|
||||
# OpenCV
|
||||
expected = cv.boundingRect(points)
|
||||
# OpenCV
|
||||
expected = cv.boundingRect(points)
|
||||
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_out = cv.gapi.boundingRect(g_in)
|
||||
# G-API
|
||||
g_in = cv.GMat()
|
||||
g_out = cv.gapi.boundingRect(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(points), 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(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,318 +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 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)
|
||||
|
||||
blob = cv.dnn.blobFromImage(img)
|
||||
|
||||
net.setInput(blob)
|
||||
return net.forward(net.getUnconnectedOutLayersNames())
|
||||
if sys.version_info[:2] < (3, 0):
|
||||
raise unittest.SkipTest('Python 2.x is not supported')
|
||||
|
||||
|
||||
def make_roi(self, img, roi):
|
||||
return img[roi[1]:roi[1] + roi[3], roi[0]:roi[0] + roi[2], ...]
|
||||
class test_gapi_infer(NewOpenCVTests):
|
||||
|
||||
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)
|
||||
|
||||
blob = cv.dnn.blobFromImage(img)
|
||||
|
||||
net.setInput(blob)
|
||||
return net.forward(net.getUnconnectedOutLayersNames())
|
||||
|
||||
|
||||
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
|
||||
|
||||
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.resize(cv.imread(img_path), (62,62))
|
||||
|
||||
# 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.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 make_roi(self, img, roi):
|
||||
return img[roi[1]:roi[1] + roi[3], roi[0]:roi[0] + roi[2], ...]
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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'
|
||||
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)
|
||||
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))
|
||||
|
||||
# OpenCV DNN
|
||||
dnn_age, dnn_gender = self.infer_reference_network(model_path,
|
||||
# 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_roi = cv.GOpaqueT(cv.gapi.CV_RECT)
|
||||
inputs = cv.GInferInputs()
|
||||
inputs.setInput('data', g_in)
|
||||
# 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_roi, inputs)
|
||||
age_g = outputs.at("age_conv3")
|
||||
gender_g = outputs.at("prob")
|
||||
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_roi), cv.GOut(age_g, gender_g))
|
||||
pp = cv.gapi.ie.params("net", model_path, weights_path, device_id)
|
||||
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, gapi_gender = comp.apply(cv.gin(img, roi), args=cv.compile_args(cv.gapi.networks(pp)))
|
||||
gapi_age_list, gapi_gender_list = comp.apply(cv.gin(img, rois),
|
||||
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))
|
||||
# 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_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
|
||||
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'
|
||||
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)
|
||||
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 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)
|
||||
# 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.infer("net", g_rois, inputs)
|
||||
age_g = outputs.at("age_conv3")
|
||||
gender_g = outputs.at("prob")
|
||||
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)
|
||||
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.compile_args(cv.gapi.networks(pp)))
|
||||
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.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))
|
||||
# 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
|
||||
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))
|
||||
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)
|
||||
# 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)
|
||||
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))
|
||||
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
|
||||
return bboxes
|
||||
|
||||
net.setInput(blob)
|
||||
dnn_detections = net.forward()
|
||||
dnn_boxes = parseSSD(np.array(dnn_detections), img.shape[:2])
|
||||
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)
|
||||
# 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)
|
||||
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)
|
||||
comp = cv.GComputation(cv.GIn(g_in), cv.GOut(bboxes))
|
||||
pp = cv.gapi.ie.params("net", model_path, weights_path, device_id)
|
||||
|
||||
gapi_age, gapi_gender = comp.apply(cv.gin(img), args=cv.compile_args(cv.gapi.networks(pp)))
|
||||
gapi_boxes = comp.apply(cv.gin(img.astype(np.float32)),
|
||||
args=cv.gapi.compile_args(cv.gapi.networks(pp)))
|
||||
|
||||
gapi_boxes = comp.apply(cv.gin(img.astype(np.float32)),
|
||||
args=cv.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))
|
||||
# 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
|
||||
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))
|
||||
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)
|
||||
# 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)
|
||||
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))
|
||||
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
|
||||
return bboxes
|
||||
|
||||
net.setInput(blob)
|
||||
dnn_detections = net.forward()
|
||||
dnn_boxes = parseSSD(np.array(dnn_detections), img.shape[:2])
|
||||
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)
|
||||
# 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)
|
||||
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)
|
||||
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.compile_args(cv.gapi.networks(pp)))
|
||||
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))
|
||||
# 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()
|
||||
@@ -225,7 +225,7 @@ try:
|
||||
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.compile_args(pkg))
|
||||
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))
|
||||
|
||||
@@ -245,7 +245,7 @@ try:
|
||||
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.compile_args(pkg))
|
||||
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))
|
||||
@@ -266,7 +266,7 @@ try:
|
||||
comp = cv.GComputation(g_in, g_out)
|
||||
|
||||
pkg = cv.gapi.kernels(GMeanImpl)
|
||||
actual = comp.apply(cv.gin(in_mat), args=cv.compile_args(pkg))
|
||||
actual = comp.apply(cv.gin(in_mat), args=cv.gapi.compile_args(pkg))
|
||||
|
||||
# Comparison
|
||||
self.assertEqual(expected, actual)
|
||||
@@ -287,7 +287,7 @@ try:
|
||||
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.compile_args(pkg))
|
||||
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))
|
||||
|
||||
@@ -305,7 +305,7 @@ try:
|
||||
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.compile_args(pkg))
|
||||
actual = comp.apply(cv.gin(in_mat), args=cv.gapi.compile_args(pkg))
|
||||
|
||||
self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
|
||||
|
||||
@@ -322,7 +322,7 @@ try:
|
||||
comp = cv.GComputation(cv.GIn(g_r), cv.GOut(g_sz))
|
||||
|
||||
pkg = cv.gapi.kernels(GSizeRImpl)
|
||||
actual = comp.apply(cv.gin(roi), args=cv.compile_args(pkg))
|
||||
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))
|
||||
@@ -340,7 +340,7 @@ try:
|
||||
comp = cv.GComputation(cv.GIn(g_pts), cv.GOut(g_br))
|
||||
|
||||
pkg = cv.gapi.kernels(GBoundingRectImpl)
|
||||
actual = comp.apply(cv.gin(points), args=cv.compile_args(pkg))
|
||||
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))
|
||||
@@ -371,7 +371,7 @@ try:
|
||||
|
||||
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.compile_args(pkg))
|
||||
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)
|
||||
@@ -453,10 +453,10 @@ try:
|
||||
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.compile_args(cv.gapi.kernels(GSumImpl)))
|
||||
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.compile_args(cv.gapi.kernels(GSumImpl)))
|
||||
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)
|
||||
@@ -488,13 +488,13 @@ try:
|
||||
'tuple': (42, 42)
|
||||
}
|
||||
|
||||
out = comp.apply(cv.gin(table, 'int'), args=cv.compile_args(cv.gapi.kernels(GLookUpImpl)))
|
||||
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.compile_args(cv.gapi.kernels(GLookUpImpl)))
|
||||
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.compile_args(cv.gapi.kernels(GLookUpImpl)))
|
||||
out = comp.apply(cv.gin(table, 'tuple'), args=cv.gapi.compile_args(cv.gapi.kernels(GLookUpImpl)))
|
||||
self.assertEqual((42, 42), out)
|
||||
|
||||
|
||||
@@ -517,11 +517,11 @@ try:
|
||||
|
||||
comp = cv.GComputation(cv.GIn(g_arr0, g_arr1), cv.GOut(g_out))
|
||||
|
||||
arr0 = [(2, 2), 2.0]
|
||||
arr1 = [3, 'str']
|
||||
arr0 = ((2, 2), 2.0)
|
||||
arr1 = (3, 'str')
|
||||
|
||||
out = comp.apply(cv.gin(arr0, arr1),
|
||||
args=cv.compile_args(cv.gapi.kernels(GConcatImpl)))
|
||||
args=cv.gapi.compile_args(cv.gapi.kernels(GConcatImpl)))
|
||||
|
||||
self.assertEqual(arr0 + arr1, out)
|
||||
|
||||
@@ -550,7 +550,7 @@ try:
|
||||
img1 = np.array([1, 2, 3])
|
||||
|
||||
with self.assertRaises(Exception): comp.apply(cv.gin(img0, img1),
|
||||
args=cv.compile_args(
|
||||
args=cv.gapi.compile_args(
|
||||
cv.gapi.kernels(GAddImpl)))
|
||||
|
||||
|
||||
@@ -577,7 +577,7 @@ try:
|
||||
img1 = np.array([1, 2, 3])
|
||||
|
||||
with self.assertRaises(Exception): comp.apply(cv.gin(img0, img1),
|
||||
args=cv.compile_args(
|
||||
args=cv.gapi.compile_args(
|
||||
cv.gapi.kernels(GAddImpl)))
|
||||
|
||||
|
||||
@@ -607,7 +607,7 @@ try:
|
||||
# FIXME: Cause Bad variant access.
|
||||
# Need to provide more descriptive error messsage.
|
||||
with self.assertRaises(Exception): comp.apply(cv.gin(img0, img1),
|
||||
args=cv.compile_args(
|
||||
args=cv.gapi.compile_args(
|
||||
cv.gapi.kernels(GAddImpl)))
|
||||
|
||||
def test_pipeline_with_custom_kernels(self):
|
||||
@@ -657,7 +657,7 @@ try:
|
||||
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.compile_args(
|
||||
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))
|
||||
|
||||
@@ -3,201 +3,367 @@
|
||||
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(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(),
|
||||
np.array(a, np.float32).flatten(),
|
||||
cv.NORM_INF))
|
||||
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.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
|
||||
|
||||
proc_num_frames += 1
|
||||
if proc_num_frames == max_num_frames:
|
||||
break;
|
||||
|
||||
if __name__ == '__main__':
|
||||
NewOpenCVTests.bootstrap()
|
||||
|
||||
@@ -3,29 +3,51 @@
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
|
||||
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]
|
||||
try:
|
||||
|
||||
for t in types:
|
||||
g_array = cv.GArrayT(t)
|
||||
self.assertEqual(t, g_array.type())
|
||||
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]
|
||||
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())
|
||||
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__':
|
||||
|
||||
@@ -4,11 +4,23 @@
|
||||
#include <opencv2/gapi/core.hpp>
|
||||
#include <opencv2/gapi/imgproc.hpp>
|
||||
|
||||
#include <opencv2/gapi/s11n.hpp>
|
||||
#include <opencv2/gapi/garg.hpp>
|
||||
#include <opencv2/gapi/gcommon.hpp>
|
||||
|
||||
#include <opencv2/gapi/cpu/gcpukernel.hpp>
|
||||
|
||||
#include <opencv2/gapi/fluid/core.hpp>
|
||||
#include <opencv2/gapi/fluid/imgproc.hpp>
|
||||
|
||||
static void gscalar_example()
|
||||
{
|
||||
//! [gscalar_implicit]
|
||||
cv::GMat a;
|
||||
cv::GMat b = a + 1;
|
||||
//! [gscalar_implicit]
|
||||
}
|
||||
|
||||
static void typed_example()
|
||||
{
|
||||
const cv::Size sz(32, 32);
|
||||
@@ -47,6 +59,120 @@ static void typed_example()
|
||||
//! [Typed_Example]
|
||||
}
|
||||
|
||||
static void bind_serialization_example()
|
||||
{
|
||||
// ! [bind after deserialization]
|
||||
cv::GCompiled compd;
|
||||
std::vector<char> bytes;
|
||||
auto graph = cv::gapi::deserialize<cv::GComputation>(bytes);
|
||||
auto meta = cv::gapi::deserialize<cv::GMetaArgs>(bytes);
|
||||
|
||||
compd = graph.compile(std::move(meta), cv::compile_args());
|
||||
auto in_args = cv::gapi::deserialize<cv::GRunArgs>(bytes);
|
||||
auto out_args = cv::gapi::deserialize<cv::GRunArgs>(bytes);
|
||||
compd(std::move(in_args), cv::gapi::bind(out_args));
|
||||
// ! [bind after deserialization]
|
||||
}
|
||||
|
||||
static void bind_deserialization_example()
|
||||
{
|
||||
// ! [bind before serialization]
|
||||
std::vector<cv::GRunArgP> graph_outs;
|
||||
cv::GRunArgs out_args;
|
||||
|
||||
for (auto &&out : graph_outs) {
|
||||
out_args.emplace_back(cv::gapi::bind(out));
|
||||
}
|
||||
const auto sargsout = cv::gapi::serialize(out_args);
|
||||
// ! [bind before serialization]
|
||||
}
|
||||
|
||||
struct SimpleCustomType {
|
||||
bool val;
|
||||
bool operator==(const SimpleCustomType& other) const {
|
||||
return val == other.val;
|
||||
}
|
||||
};
|
||||
|
||||
struct SimpleCustomType2 {
|
||||
int val;
|
||||
std::string name;
|
||||
std::vector<float> vec;
|
||||
std::map<int, uint64_t> mmap;
|
||||
bool operator==(const SimpleCustomType2& other) const {
|
||||
return val == other.val && name == other.name &&
|
||||
vec == other.vec && mmap == other.mmap;
|
||||
}
|
||||
};
|
||||
|
||||
// ! [S11N usage]
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace s11n {
|
||||
namespace detail {
|
||||
template<> struct S11N<SimpleCustomType> {
|
||||
static void serialize(IOStream &os, const SimpleCustomType &p) {
|
||||
os << p.val;
|
||||
}
|
||||
static SimpleCustomType deserialize(IIStream &is) {
|
||||
SimpleCustomType p;
|
||||
is >> p.val;
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct S11N<SimpleCustomType2> {
|
||||
static void serialize(IOStream &os, const SimpleCustomType2 &p) {
|
||||
os << p.val << p.name << p.vec << p.mmap;
|
||||
}
|
||||
static SimpleCustomType2 deserialize(IIStream &is) {
|
||||
SimpleCustomType2 p;
|
||||
is >> p.val >> p.name >> p.vec >> p.mmap;
|
||||
return p;
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
} // namespace s11n
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
// ! [S11N usage]
|
||||
|
||||
namespace cv {
|
||||
namespace detail {
|
||||
template<> struct CompileArgTag<SimpleCustomType> {
|
||||
static const char* tag() {
|
||||
return "org.opencv.test.simple_custom_type";
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct CompileArgTag<SimpleCustomType2> {
|
||||
static const char* tag() {
|
||||
return "org.opencv.test.simple_custom_type_2";
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
} // namespace cv
|
||||
|
||||
static void s11n_example()
|
||||
{
|
||||
SimpleCustomType customVar1 { false };
|
||||
SimpleCustomType2 customVar2 { 1248, "World", {1280, 720, 640, 480},
|
||||
{ {5, 32434142342}, {7, 34242432} } };
|
||||
|
||||
std::vector<char> sArgs = cv::gapi::serialize(
|
||||
cv::compile_args(customVar1, customVar2));
|
||||
|
||||
cv::GCompileArgs dArgs = cv::gapi::deserialize<cv::GCompileArgs,
|
||||
SimpleCustomType,
|
||||
SimpleCustomType2>(sArgs);
|
||||
|
||||
SimpleCustomType dCustomVar1 = cv::gapi::getCompileArg<SimpleCustomType>(dArgs).value();
|
||||
SimpleCustomType2 dCustomVar2 = cv::gapi::getCompileArg<SimpleCustomType2>(dArgs).value();
|
||||
|
||||
(void) dCustomVar1;
|
||||
(void) dCustomVar2;
|
||||
}
|
||||
|
||||
G_TYPED_KERNEL(IAdd, <cv::GMat(cv::GMat)>, "test.custom.add") {
|
||||
static cv::GMatDesc outMeta(const cv::GMatDesc &in) { return in; }
|
||||
};
|
||||
@@ -116,7 +242,12 @@ int main(int argc, char *argv[])
|
||||
>();
|
||||
//! [kernels_snippet]
|
||||
|
||||
// Just call typed example with no input/output
|
||||
// Just call typed example with no input/output - avoid warnings about
|
||||
// unused functions
|
||||
typed_example();
|
||||
gscalar_example();
|
||||
bind_serialization_example();
|
||||
bind_deserialization_example();
|
||||
s11n_example();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -589,30 +589,23 @@ int main(int argc, char* argv[]) {
|
||||
//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 in_resized[MAX_PYRAMID_LEVELS];
|
||||
cv::GMat in_transposed[MAX_PYRAMID_LEVELS];
|
||||
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];
|
||||
cv::GArray<custom::Face> faces_init(std::vector<custom::Face>{});
|
||||
|
||||
//The very first PNet pyramid layer to init total_faces[0]
|
||||
in_resized[0] = cv::gapi::resize(in_originalRGB, level_size[0]);
|
||||
in_transposed[0] = cv::gapi::transpose(in_resized[0]);
|
||||
std::tie(regressions[0], scores[0]) = run_mtcnn_p(in_transposed[0], get_pnet_level_name(level_size[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);
|
||||
nms_p_faces[0] = custom::RunNMS::on(final_faces_pnet0, 0.5f, false);
|
||||
total_faces[0] = custom::AccumulatePyramidOutputs::on(faces_init, nms_p_faces[0]);
|
||||
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)
|
||||
{
|
||||
in_resized[i] = cv::gapi::resize(in_originalRGB, level_size[i]);
|
||||
in_transposed[i] = cv::gapi::transpose(in_resized[i]);
|
||||
std::tie(regressions[i], scores[i]) = run_mtcnn_p(in_transposed[i], get_pnet_level_name(level_size[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);
|
||||
@@ -626,8 +619,7 @@ int main(int argc, char* argv[]) {
|
||||
//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;
|
||||
cv::GMat in_originalRGB_transposed = cv::gapi::transpose(in_originalRGB);
|
||||
std::tie(regressionsRNet, scoresRNet) = cv::gapi::infer<custom::MTCNNRefinement>(faces_roi_pnet, in_originalRGB_transposed);
|
||||
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);
|
||||
@@ -638,7 +630,7 @@ int main(int argc, char* argv[]) {
|
||||
//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_originalRGB_transposed);
|
||||
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);
|
||||
|
||||
@@ -16,13 +16,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 {
|
||||
@@ -338,7 +338,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
cv::GMat in;
|
||||
cv::GMat faces = cv::gapi::infer<custom::Faces>(in);
|
||||
cv::GOpaque<cv::Size> sz = custom::Size::on(in); // FIXME
|
||||
cv::GOpaque<cv::Size> sz = cv::gapi::streaming::size(in);
|
||||
cv::GArray<cv::Rect> faces_rc = custom::ParseSSD::on(faces, sz, 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);
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <cctype>
|
||||
|
||||
#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/highgui.hpp> // CommandLineParser
|
||||
|
||||
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) }"
|
||||
"{ 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";
|
||||
}
|
||||
} // 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(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(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(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
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
auto kernels = cv::gapi::kernels
|
||||
< custom::OCVLocateROI
|
||||
, custom::OCVParseSSD
|
||||
, custom::OCVBBoxes>();
|
||||
auto networks = cv::gapi::networks(face_net);
|
||||
|
||||
// Create source
|
||||
cv::Ptr<cv::gapi::wip::IStreamSource> cap;
|
||||
try {
|
||||
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);
|
||||
auto rcs = custom::ParseSSD::on(blob, roi, size);
|
||||
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();
|
||||
|
||||
int framesCount = 0;
|
||||
cv::TickMeter t;
|
||||
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;
|
||||
t.start();
|
||||
while (pipeline.pull(cv::gout(outMat))) {
|
||||
cv::imshow("Out", outMat);
|
||||
cv::waitKey(1);
|
||||
if (!output.empty()) {
|
||||
writer << outMat;
|
||||
}
|
||||
framesCount++;
|
||||
}
|
||||
t.stop();
|
||||
std::cout << "Elapsed time: " << t.getTimeSec() << std::endl;
|
||||
std::cout << "FPS: " << framesCount / t.getTimeSec() << std::endl;
|
||||
std::cout << "framesCount: " << framesCount << 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);
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,53 @@ std::string get_weights_path(const std::string &model_path) {
|
||||
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 {
|
||||
@@ -57,25 +104,21 @@ G_API_OP(PostProcessing, <cv::GMat(cv::GMat, cv::GMat)>, "sample.custom.post_pro
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(OCVPostProcessing, PostProcessing) {
|
||||
static void run(const cv::Mat &in, const cv::Mat &detected_classes, cv::Mat &out) {
|
||||
// This kernel constructs output image by class table and colors vector
|
||||
|
||||
// The semantic-segmentation-adas-0001 output a blob with the shape
|
||||
// [B, C=1, H=1024, W=2048]
|
||||
const int outHeight = 1024;
|
||||
const int outWidth = 2048;
|
||||
cv::Mat maskImg(outHeight, outWidth, CV_8UC3);
|
||||
const int* const classes = detected_classes.ptr<int>();
|
||||
for (int rowId = 0; rowId < outHeight; ++rowId) {
|
||||
for (int colId = 0; colId < outWidth; ++colId) {
|
||||
size_t classId = static_cast<size_t>(classes[rowId * outWidth + colId]);
|
||||
maskImg.at<cv::Vec3b>(rowId, colId) =
|
||||
classId < colors.size()
|
||||
? colors[classId]
|
||||
: cv::Vec3b{0, 0, 0}; // sample detects 20 classes
|
||||
}
|
||||
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::resize(maskImg, out, in.size());
|
||||
|
||||
cv::Mat mask_img;
|
||||
classesToColors(classes, mask_img);
|
||||
|
||||
cv::resize(mask_img, out, in.size());
|
||||
const float blending = 0.3f;
|
||||
out = in * blending + out * (1 - blending);
|
||||
}
|
||||
@@ -104,8 +147,8 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
// Now build the graph
|
||||
cv::GMat in;
|
||||
cv::GMat detected_classes = cv::gapi::infer<SemSegmNet>(in);
|
||||
cv::GMat out = custom::PostProcessing::on(in, detected_classes);
|
||||
cv::GMat out_blob = cv::gapi::infer<SemSegmNet>(in);
|
||||
cv::GMat out = custom::PostProcessing::on(in, out_blob);
|
||||
|
||||
cv::GStreamingCompiled pipeline = cv::GComputation(cv::GIn(in), cv::GOut(out))
|
||||
.compileStreaming(cv::compile_args(kernels, networks));
|
||||
|
||||
@@ -15,6 +15,10 @@ 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);
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
#include "api/gorigin.hpp"
|
||||
#include "api/gproto_priv.hpp"
|
||||
#include "logger.hpp"
|
||||
|
||||
// FIXME: it should be a visitor!
|
||||
// FIXME: Reimplement with traits?
|
||||
@@ -277,13 +276,9 @@ void cv::validate_input_arg(const GRunArg& arg)
|
||||
|
||||
void cv::validate_input_args(const GRunArgs& args)
|
||||
{
|
||||
GAPI_LOG_DEBUG(nullptr, "Total count: " << args.size());
|
||||
size_t index = 0;
|
||||
for (const auto& arg : args)
|
||||
{
|
||||
GAPI_LOG_DEBUG(nullptr, "Process index: " << index);
|
||||
validate_input_arg(arg);
|
||||
index ++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
@@ -75,6 +75,11 @@ cv::GMat cv::gapi::streaming::desync(const cv::GMat &g) {
|
||||
// object will feed both branches of the streaming executable.
|
||||
}
|
||||
|
||||
// All notes from the above desync(GMat) are also applicable here
|
||||
cv::GFrame cv::gapi::streaming::desync(const cv::GFrame &f) {
|
||||
return cv::gapi::copy(detail::desync(f));
|
||||
}
|
||||
|
||||
cv::GMat cv::gapi::streaming::BGR(const cv::GFrame& in) {
|
||||
return cv::gapi::streaming::GBGR::on(in);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,10 @@ cv::MediaFrame::IAdapter* cv::MediaFrame::getAdapter() const {
|
||||
return m->adapter.get();
|
||||
}
|
||||
|
||||
void cv::MediaFrame::serialize(cv::gapi::s11n::IOStream& os) const {
|
||||
return m->adapter->serialize(os);
|
||||
}
|
||||
|
||||
cv::MediaFrame::View::View(Ptrs&& ptrs, Strides&& strs, Callback &&cb)
|
||||
: ptr (std::move(ptrs))
|
||||
, stride(std::move(strs))
|
||||
|
||||
@@ -159,7 +159,7 @@ void drawPrimitivesOCV(cv::Mat& in,
|
||||
{
|
||||
const auto& rp = cv::util::get<Rect>(p);
|
||||
const auto color = converter.cvtColor(rp.color);
|
||||
cv::rectangle(in, rp.rect, color , rp.thick);
|
||||
cv::rectangle(in, rp.rect, color, rp.thick, rp.lt, rp.shift);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ void drawPrimitivesOCV(cv::Mat& in,
|
||||
{
|
||||
const auto& cp = cv::util::get<Circle>(p);
|
||||
const auto color = converter.cvtColor(cp.color);
|
||||
cv::circle(in, cp.center, cp.radius, color, cp.thick);
|
||||
cv::circle(in, cp.center, cp.radius, color, cp.thick, cp.lt, cp.shift);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ void drawPrimitivesOCV(cv::Mat& in,
|
||||
{
|
||||
const auto& lp = cv::util::get<Line>(p);
|
||||
const auto color = converter.cvtColor(lp.color);
|
||||
cv::line(in, lp.pt1, lp.pt2, color, lp.thick);
|
||||
cv::line(in, lp.pt1, lp.pt2, color, lp.thick, lp.lt, lp.shift);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,25 +65,25 @@ std::vector<char> cv::gapi::serialize(const std::vector<std::string>& vs)
|
||||
|
||||
// FIXME: This function should move from S11N to GRunArg-related entities.
|
||||
// it has nothing to do with the S11N as it is
|
||||
cv::GRunArgsP cv::gapi::bind(cv::GRunArgs &results)
|
||||
cv::GRunArgsP cv::gapi::bind(cv::GRunArgs &out_args)
|
||||
{
|
||||
cv::GRunArgsP outputs;
|
||||
outputs.reserve(results.size());
|
||||
for (cv::GRunArg &res_obj : results)
|
||||
outputs.reserve(out_args.size());
|
||||
for (cv::GRunArg &res_obj : out_args)
|
||||
{
|
||||
using T = cv::GRunArg;
|
||||
switch (res_obj.index())
|
||||
{
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
case T::index_of<cv::UMat>() :
|
||||
outputs.emplace_back((cv::UMat*)(&(cv::util::get<cv::UMat>(res_obj))));
|
||||
outputs.emplace_back(&(cv::util::get<cv::UMat>(res_obj)));
|
||||
break;
|
||||
#endif
|
||||
case cv::GRunArg::index_of<cv::Mat>() :
|
||||
outputs.emplace_back((cv::Mat*)(&(cv::util::get<cv::Mat>(res_obj))));
|
||||
outputs.emplace_back(&(cv::util::get<cv::Mat>(res_obj)));
|
||||
break;
|
||||
case cv::GRunArg::index_of<cv::Scalar>() :
|
||||
outputs.emplace_back((cv::Scalar*)(&(cv::util::get<cv::Scalar>(res_obj))));
|
||||
outputs.emplace_back(&(cv::util::get<cv::Scalar>(res_obj)));
|
||||
break;
|
||||
case T::index_of<cv::detail::VectorRef>() :
|
||||
outputs.emplace_back(cv::util::get<cv::detail::VectorRef>(res_obj));
|
||||
@@ -92,7 +92,10 @@ cv::GRunArgsP cv::gapi::bind(cv::GRunArgs &results)
|
||||
outputs.emplace_back(cv::util::get<cv::detail::OpaqueRef>(res_obj));
|
||||
break;
|
||||
case cv::GRunArg::index_of<cv::RMat>() :
|
||||
outputs.emplace_back((cv::RMat*)(&(cv::util::get<cv::RMat>(res_obj))));
|
||||
outputs.emplace_back(&(cv::util::get<cv::RMat>(res_obj)));
|
||||
break;
|
||||
case cv::GRunArg::index_of<cv::MediaFrame>() :
|
||||
outputs.emplace_back(&(cv::util::get<cv::MediaFrame>(res_obj)));
|
||||
break;
|
||||
default:
|
||||
GAPI_Assert(false && "This value type is not supported!"); // ...maybe because of STANDALONE mode.
|
||||
@@ -130,6 +133,9 @@ cv::GRunArg cv::gapi::bind(cv::GRunArgP &out)
|
||||
case T::index_of<cv::RMat*>() :
|
||||
return cv::GRunArg(*cv::util::get<cv::RMat*>(out));
|
||||
|
||||
case T::index_of<cv::MediaFrame*>() :
|
||||
return cv::GRunArg(*cv::util::get<cv::MediaFrame*>(out));
|
||||
|
||||
default:
|
||||
// ...maybe our types were extended
|
||||
GAPI_Assert(false && "This value type is UNKNOWN!");
|
||||
|
||||
@@ -85,6 +85,19 @@ class GGraphMetaBackendImpl final: public cv::gapi::GBackend::Priv {
|
||||
const std::vector<cv::gimpl::Data>&) const override {
|
||||
return EPtr{new GraphMetaExecutable(graph, nodes)};
|
||||
}
|
||||
|
||||
virtual bool controlsMerge() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool allowsMerge(const cv::gimpl::GIslandModel::Graph &,
|
||||
const ade::NodeHandle &,
|
||||
const ade::NodeHandle &,
|
||||
const ade::NodeHandle &) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
cv::gapi::GBackend graph_meta_backend() {
|
||||
|
||||
@@ -32,6 +32,14 @@ void putData(GSerialized& s, const cv::gimpl::GModel::ConstGraph& cg, const ade:
|
||||
});
|
||||
if (s.m_datas.end() == it) {
|
||||
s.m_datas.push_back(gdata);
|
||||
|
||||
if (cg.metadata(nh).contains<gimpl::ConstValue>()) {
|
||||
size_t datas_num = s.m_datas.size() - 1;
|
||||
GAPI_DbgAssert(datas_num <= static_cast<size_t>(std::numeric_limits<GSerialized::data_tag_t>::max()));
|
||||
GSerialized::data_tag_t tag = static_cast<GSerialized::data_tag_t>(datas_num);
|
||||
s.m_const_datas.emplace(tag,
|
||||
cg.metadata(nh).get<gimpl::ConstValue>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,11 +50,20 @@ void putOp(GSerialized& s, const cv::gimpl::GModel::ConstGraph& cg, const ade::N
|
||||
s.m_ops.push_back(op);
|
||||
}
|
||||
|
||||
void mkDataNode(ade::Graph& g, const cv::gimpl::Data& data) {
|
||||
ade::NodeHandle mkDataNode(ade::Graph& g, const cv::gimpl::Data& data) {
|
||||
cv::gimpl::GModel::Graph gm(g);
|
||||
auto nh = gm.createNode();
|
||||
gm.metadata(nh).set(cv::gimpl::NodeType{cv::gimpl::NodeType::DATA});
|
||||
gm.metadata(nh).set(data);
|
||||
return nh;
|
||||
}
|
||||
|
||||
ade::NodeHandle mkConstDataNode(ade::Graph& g, const cv::gimpl::Data& data, const cv::gimpl::ConstValue& const_data) {
|
||||
auto nh = mkDataNode(g, data);
|
||||
|
||||
cv::gimpl::GModel::Graph gm(g);
|
||||
gm.metadata(nh).set(const_data);
|
||||
return nh;
|
||||
}
|
||||
|
||||
void mkOpNode(ade::Graph& g, const cv::gimpl::Op& op) {
|
||||
@@ -184,18 +201,20 @@ IOStream& operator<< (IOStream& os, const cv::RMat& mat) {
|
||||
return os;
|
||||
}
|
||||
IIStream& operator>> (IIStream& is, cv::RMat&) {
|
||||
util::throw_error(std::logic_error("operator>> for RMat should never be called"));
|
||||
util::throw_error(std::logic_error("operator>> for RMat should never be called. "
|
||||
"Instead, cv::gapi::deserialize<cv::GRunArgs, AdapterTypes...>() "
|
||||
"should be used"));
|
||||
return is;
|
||||
}
|
||||
|
||||
IOStream& operator<< (IOStream& os, const cv::MediaFrame &) {
|
||||
// Stub
|
||||
GAPI_Assert(false && "cv::MediaFrame serialization is not supported!");
|
||||
IOStream& operator<< (IOStream& os, const cv::MediaFrame &frame) {
|
||||
frame.serialize(os);
|
||||
return os;
|
||||
}
|
||||
IIStream& operator>> (IIStream& is, cv::MediaFrame &) {
|
||||
// Stub
|
||||
GAPI_Assert(false && "cv::MediaFrame serialization is not supported!");
|
||||
util::throw_error(std::logic_error("operator>> for MediaFrame should never be called. "
|
||||
"Instead, cv::gapi::deserialize<cv::GRunArgs, AdapterTypes...>() "
|
||||
"should be used"));
|
||||
return is;
|
||||
}
|
||||
|
||||
@@ -624,6 +643,10 @@ IOStream& operator<< (IOStream& os, const cv::gimpl::Data &d) {
|
||||
return os << d.shape << d.rc << d.meta << d.storage << d.kind;
|
||||
}
|
||||
|
||||
IOStream& operator<< (IOStream& os, const cv::gimpl::ConstValue &cd) {
|
||||
return os << cd.arg;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename Ref, typename T, typename... Ts>
|
||||
@@ -667,6 +690,9 @@ IIStream& operator>> (IIStream& is, cv::gimpl::Data &d) {
|
||||
return is;
|
||||
}
|
||||
|
||||
IIStream& operator>> (IIStream& is, cv::gimpl::ConstValue &cd) {
|
||||
return is >> cd.arg;
|
||||
}
|
||||
|
||||
IOStream& operator<< (IOStream& os, const cv::gimpl::DataObjectCounter &c) {
|
||||
return os << c.m_next_data_id;
|
||||
@@ -709,18 +735,34 @@ void serialize( IOStream& os
|
||||
}
|
||||
s.m_counter = cg.metadata().get<cv::gimpl::DataObjectCounter>();
|
||||
s.m_proto = p;
|
||||
os << s.m_ops << s.m_datas << s.m_counter << s.m_proto;
|
||||
os << s.m_ops << s.m_datas << s.m_counter << s.m_proto << s.m_const_datas;
|
||||
}
|
||||
|
||||
GSerialized deserialize(IIStream &is) {
|
||||
GSerialized s;
|
||||
is >> s.m_ops >> s.m_datas >> s.m_counter >> s.m_proto;
|
||||
is >> s.m_ops >> s.m_datas >> s.m_counter >> s.m_proto >> s.m_const_datas;
|
||||
return s;
|
||||
}
|
||||
|
||||
void reconstruct(const GSerialized &s, ade::Graph &g) {
|
||||
GAPI_Assert(g.nodes().empty());
|
||||
for (const auto& d : s.m_datas) cv::gapi::s11n::mkDataNode(g, d);
|
||||
|
||||
GSerialized::data_tag_t tag = 0;
|
||||
for (const auto& d : s.m_datas) {
|
||||
if (d.storage == gimpl::Data::Storage::CONST_VAL) {
|
||||
auto cit = s.m_const_datas.find(tag);
|
||||
if (cit == s.m_const_datas.end()) {
|
||||
util::throw_error(std::logic_error("Cannot reconstruct graph: Data::Storage::CONST_VAL by tag: " +
|
||||
std::to_string(tag) + " requires ConstValue"));
|
||||
}
|
||||
|
||||
mkConstDataNode(g, d, cit->second);
|
||||
} else {
|
||||
cv::gapi::s11n::mkDataNode(g, d);
|
||||
}
|
||||
|
||||
tag ++;
|
||||
}
|
||||
for (const auto& op : s.m_ops) cv::gapi::s11n::mkOpNode(g, op);
|
||||
cv::gapi::s11n::linkNodes(g);
|
||||
|
||||
|
||||
@@ -31,6 +31,9 @@ struct GSerialized {
|
||||
std::vector<cv::gimpl::Data> m_datas;
|
||||
cv::gimpl::DataObjectCounter m_counter;
|
||||
cv::gimpl::Protocol m_proto;
|
||||
|
||||
using data_tag_t = uint64_t;
|
||||
std::map<data_tag_t, cv::gimpl::ConstValue> m_const_datas;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -97,6 +100,9 @@ GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::gimpl::Op &op);
|
||||
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::gimpl::Data &op);
|
||||
GAPI_EXPORTS IIStream& operator>> (IIStream& is, cv::gimpl::Data &op);
|
||||
|
||||
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::gimpl::ConstValue &cd);
|
||||
GAPI_EXPORTS IIStream& operator>> (IIStream& os, cv::gimpl::ConstValue &cd);
|
||||
|
||||
// Render types ////////////////////////////////////////////////////////////////
|
||||
|
||||
GAPI_EXPORTS IOStream& operator<< (IOStream& os, const cv::gapi::wip::draw::Text &t);
|
||||
|
||||
@@ -652,7 +652,12 @@ GAPI_OCV_KERNEL(GCPUParseSSDBL, cv::gapi::nn::parsers::GParseSSDBL)
|
||||
std::vector<cv::Rect>& out_boxes,
|
||||
std::vector<int>& out_labels)
|
||||
{
|
||||
cv::parseSSDBL(in_ssd_result, in_size, confidence_threshold, filter_label, out_boxes, out_labels);
|
||||
cv::ParseSSD(in_ssd_result, in_size,
|
||||
confidence_threshold,
|
||||
filter_label,
|
||||
false,
|
||||
false,
|
||||
out_boxes, out_labels);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -665,7 +670,13 @@ GAPI_OCV_KERNEL(GOCVParseSSD, cv::gapi::nn::parsers::GParseSSD)
|
||||
const bool filter_out_of_bounds,
|
||||
std::vector<cv::Rect>& out_boxes)
|
||||
{
|
||||
cv::parseSSD(in_ssd_result, in_size, confidence_threshold, alignment_to_square, filter_out_of_bounds, out_boxes);
|
||||
std::vector<int> unused_labels;
|
||||
cv::ParseSSD(in_ssd_result, in_size,
|
||||
confidence_threshold,
|
||||
-1,
|
||||
alignment_to_square,
|
||||
filter_out_of_bounds,
|
||||
out_boxes, unused_labels);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -170,12 +170,14 @@ private:
|
||||
} // namespace nn
|
||||
} // namespace gapi
|
||||
|
||||
void parseSSDBL(const cv::Mat& in_ssd_result,
|
||||
const cv::Size& in_size,
|
||||
const float confidence_threshold,
|
||||
const int filter_label,
|
||||
std::vector<cv::Rect>& out_boxes,
|
||||
std::vector<int>& out_labels)
|
||||
void ParseSSD(const cv::Mat& in_ssd_result,
|
||||
const cv::Size& in_size,
|
||||
const float confidence_threshold,
|
||||
const int filter_label,
|
||||
const bool alignment_to_square,
|
||||
const bool filter_out_of_bounds,
|
||||
std::vector<cv::Rect>& out_boxes,
|
||||
std::vector<int>& out_labels)
|
||||
{
|
||||
cv::gapi::nn::SSDParser parser(in_ssd_result.size, in_size, in_ssd_result.ptr<float>());
|
||||
out_boxes.clear();
|
||||
@@ -188,38 +190,6 @@ void parseSSDBL(const cv::Mat& in_ssd_result,
|
||||
{
|
||||
std::tie(rc, image_id, confidence, label) = parser.extract(i);
|
||||
|
||||
if (image_id < 0.f)
|
||||
{
|
||||
break; // marks end-of-detections
|
||||
}
|
||||
|
||||
if (confidence < confidence_threshold ||
|
||||
(filter_label != -1 && label != filter_label))
|
||||
{
|
||||
continue; // filter out object classes if filter is specified
|
||||
} // and skip objects with low confidence
|
||||
out_boxes.emplace_back(rc & parser.getSurface());
|
||||
out_labels.emplace_back(label);
|
||||
}
|
||||
}
|
||||
|
||||
void parseSSD(const cv::Mat& in_ssd_result,
|
||||
const cv::Size& in_size,
|
||||
const float confidence_threshold,
|
||||
const bool alignment_to_square,
|
||||
const bool filter_out_of_bounds,
|
||||
std::vector<cv::Rect>& out_boxes)
|
||||
{
|
||||
cv::gapi::nn::SSDParser parser(in_ssd_result.size, in_size, in_ssd_result.ptr<float>());
|
||||
out_boxes.clear();
|
||||
cv::Rect rc;
|
||||
float image_id, confidence;
|
||||
int label;
|
||||
const size_t range = parser.getMaxProposals();
|
||||
for (size_t i = 0; i < range; ++i)
|
||||
{
|
||||
std::tie(rc, image_id, confidence, label) = parser.extract(i);
|
||||
|
||||
if (image_id < 0.f)
|
||||
{
|
||||
break; // marks end-of-detections
|
||||
@@ -228,12 +198,14 @@ void parseSSD(const cv::Mat& in_ssd_result,
|
||||
{
|
||||
continue; // skip objects with low confidence
|
||||
}
|
||||
|
||||
if((filter_label != -1) && (label != filter_label))
|
||||
{
|
||||
continue; // filter out object classes if filter is specified
|
||||
}
|
||||
if (alignment_to_square)
|
||||
{
|
||||
parser.adjustBoundingBox(rc);
|
||||
}
|
||||
|
||||
const auto clipped_rc = rc & parser.getSurface();
|
||||
if (filter_out_of_bounds)
|
||||
{
|
||||
@@ -243,6 +215,7 @@ void parseSSD(const cv::Mat& in_ssd_result,
|
||||
}
|
||||
}
|
||||
out_boxes.emplace_back(clipped_rc);
|
||||
out_labels.emplace_back(label);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,19 +11,14 @@
|
||||
|
||||
namespace cv
|
||||
{
|
||||
void parseSSDBL(const cv::Mat& in_ssd_result,
|
||||
const cv::Size& in_size,
|
||||
const float confidence_threshold,
|
||||
const int filter_label,
|
||||
std::vector<cv::Rect>& out_boxes,
|
||||
std::vector<int>& out_labels);
|
||||
|
||||
void parseSSD(const cv::Mat& in_ssd_result,
|
||||
void ParseSSD(const cv::Mat& in_ssd_result,
|
||||
const cv::Size& in_size,
|
||||
const float confidence_threshold,
|
||||
const int filter_label,
|
||||
const bool alignment_to_square,
|
||||
const bool filter_out_of_bounds,
|
||||
std::vector<cv::Rect>& out_boxes);
|
||||
std::vector<cv::Rect>& out_boxes,
|
||||
std::vector<int>& out_labels);
|
||||
|
||||
void parseYolo(const cv::Mat& in_yolo_result,
|
||||
const cv::Size& in_size,
|
||||
|
||||
@@ -37,3 +37,15 @@ cv::gapi::ie::PyParams cv::gapi::ie::params(const std::string &tag,
|
||||
const std::string &device) {
|
||||
return {tag, model, device};
|
||||
}
|
||||
|
||||
cv::gapi::ie::PyParams& cv::gapi::ie::PyParams::constInput(const std::string &layer_name,
|
||||
const cv::Mat &data,
|
||||
TraitAs hint) {
|
||||
m_priv->constInput(layer_name, data, hint);
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ie::PyParams& cv::gapi::ie::PyParams::cfgNumRequests(size_t nireq) {
|
||||
m_priv->cfgNumRequests(nireq);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -108,6 +108,7 @@ inline IE::Precision toIE(int depth) {
|
||||
case CV_8U: return IE::Precision::U8;
|
||||
case CV_32S: return IE::Precision::I32;
|
||||
case CV_32F: return IE::Precision::FP32;
|
||||
case CV_16F: return IE::Precision::FP16;
|
||||
default: GAPI_Assert(false && "IE. Unsupported data type");
|
||||
}
|
||||
return IE::Precision::UNSPECIFIED;
|
||||
@@ -161,6 +162,7 @@ inline IE::Blob::Ptr wrapIE(const cv::Mat &mat, cv::gapi::ie::TraitAs hint) {
|
||||
HANDLE(8U, uint8_t);
|
||||
HANDLE(32F, float);
|
||||
HANDLE(32S, int);
|
||||
HANDLE(16F, int16_t);
|
||||
#undef HANDLE
|
||||
default: GAPI_Assert(false && "IE. Unsupported data type");
|
||||
}
|
||||
@@ -222,8 +224,17 @@ struct IEUnit {
|
||||
IE::ExecutableNetwork this_network;
|
||||
cv::gimpl::ie::wrap::Plugin this_plugin;
|
||||
|
||||
InferenceEngine::RemoteContext::Ptr rctx = nullptr;
|
||||
|
||||
explicit IEUnit(const cv::gapi::ie::detail::ParamDesc &pp)
|
||||
: params(pp) {
|
||||
InferenceEngine::ParamMap* ctx_params =
|
||||
cv::util::any_cast<InferenceEngine::ParamMap>(¶ms.context_config);
|
||||
if (ctx_params != nullptr) {
|
||||
auto ie_core = cv::gimpl::ie::wrap::getCore();
|
||||
rctx = ie_core.CreateContext(params.device_id, *ctx_params);
|
||||
}
|
||||
|
||||
if (params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) {
|
||||
net = cv::gimpl::ie::wrap::readNetwork(params);
|
||||
inputs = net.getInputsInfo();
|
||||
@@ -231,11 +242,7 @@ struct IEUnit {
|
||||
} else if (params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import) {
|
||||
this_plugin = cv::gimpl::ie::wrap::getPlugin(params);
|
||||
this_plugin.SetConfig(params.config);
|
||||
this_network = cv::gimpl::ie::wrap::importNetwork(this_plugin, params);
|
||||
// FIXME: ICNNetwork returns InputsDataMap/OutputsDataMap,
|
||||
// but ExecutableNetwork returns ConstInputsDataMap/ConstOutputsDataMap
|
||||
inputs = cv::gimpl::ie::wrap::toInputsDataMap(this_network.GetInputsInfo());
|
||||
outputs = cv::gimpl::ie::wrap::toOutputsDataMap(this_network.GetOutputsInfo());
|
||||
this_network = cv::gimpl::ie::wrap::importNetwork(this_plugin, params, rctx);
|
||||
if (!params.reshape_table.empty() || !params.layer_names_to_reshape.empty()) {
|
||||
GAPI_LOG_WARNING(NULL, "Reshape isn't supported for imported network");
|
||||
}
|
||||
@@ -259,10 +266,18 @@ struct IEUnit {
|
||||
+ params.model_path));
|
||||
}
|
||||
if (params.num_in == 1u && params.input_names.empty()) {
|
||||
params.input_names = { inputs.begin()->first };
|
||||
if (params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) {
|
||||
params.input_names = { inputs.begin()->first };
|
||||
} else {
|
||||
params.input_names = { this_network.GetInputsInfo().begin()->first };
|
||||
}
|
||||
}
|
||||
if (params.num_out == 1u && params.output_names.empty()) {
|
||||
params.output_names = { outputs.begin()->first };
|
||||
if (params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) {
|
||||
params.output_names = { outputs.begin()->first };
|
||||
} else {
|
||||
params.output_names = { this_network.GetOutputsInfo().begin()->first };
|
||||
}
|
||||
}
|
||||
if (!params.reshape_table.empty()) {
|
||||
GAPI_Assert((params.reshape_table.size() + params.layer_names_to_reshape.size()) <=
|
||||
@@ -279,7 +294,8 @@ struct IEUnit {
|
||||
// for loadNetwork they can be obtained by using readNetwork
|
||||
non_const_this->this_plugin = cv::gimpl::ie::wrap::getPlugin(params);
|
||||
non_const_this->this_plugin.SetConfig(params.config);
|
||||
non_const_this->this_network = cv::gimpl::ie::wrap::loadNetwork(non_const_this->this_plugin, net, params);
|
||||
non_const_this->this_network = cv::gimpl::ie::wrap::loadNetwork(non_const_this->this_plugin,
|
||||
net, params, rctx);
|
||||
}
|
||||
|
||||
return {params, this_plugin, this_network};
|
||||
@@ -481,7 +497,32 @@ using GConstGIEModel = ade::ConstTypedGraph
|
||||
, IECallable
|
||||
>;
|
||||
|
||||
inline IE::Blob::Ptr extractRemoteBlob(IECallContext& ctx, std::size_t i) {
|
||||
GAPI_Assert(ctx.inShape(i) == cv::GShape::GFRAME &&
|
||||
"Remote blob is supported for MediaFrame only");
|
||||
|
||||
cv::util::any any_blob_params = ctx.inFrame(i).blobParams();
|
||||
auto ie_core = cv::gimpl::ie::wrap::getCore();
|
||||
|
||||
using ParamType = std::pair<InferenceEngine::TensorDesc,
|
||||
InferenceEngine::ParamMap>;
|
||||
|
||||
ParamType* blob_params = cv::util::any_cast<ParamType>(&any_blob_params);
|
||||
if (blob_params == nullptr) {
|
||||
GAPI_Assert(false && "Incorrect type of blobParams: "
|
||||
"expected std::pair<InferenceEngine::TensorDesc,"
|
||||
"InferenceEngine::ParamMap>");
|
||||
}
|
||||
|
||||
return ctx.uu.rctx->CreateBlob(blob_params->first,
|
||||
blob_params->second);
|
||||
}
|
||||
|
||||
inline IE::Blob::Ptr extractBlob(IECallContext& ctx, std::size_t i) {
|
||||
if (ctx.uu.rctx != nullptr) {
|
||||
return extractRemoteBlob(ctx, i);
|
||||
}
|
||||
|
||||
switch (ctx.inShape(i)) {
|
||||
case cv::GShape::GFRAME: {
|
||||
const auto& frame = ctx.inFrame(i);
|
||||
@@ -496,6 +537,24 @@ inline IE::Blob::Ptr extractBlob(IECallContext& ctx, std::size_t i) {
|
||||
}
|
||||
GAPI_Assert(false);
|
||||
}
|
||||
|
||||
|
||||
static void setBlob(InferenceEngine::InferRequest& req,
|
||||
cv::gapi::ie::detail::ParamDesc::Kind kind,
|
||||
const std::string& layer_name,
|
||||
IE::Blob::Ptr blob) {
|
||||
// NB: In case importNetwork preprocessing must be
|
||||
// passed as SetBlob argument.
|
||||
if (kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) {
|
||||
req.SetBlob(layer_name, blob);
|
||||
} else {
|
||||
GAPI_Assert(kind == cv::gapi::ie::detail::ParamDesc::Kind::Import);
|
||||
IE::PreProcessInfo info;
|
||||
info.setResizeAlgorithm(IE::RESIZE_BILINEAR);
|
||||
req.SetBlob(layer_name, blob, info);
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
std::vector<InferenceEngine::InferRequest> cv::gimpl::ie::IECompiled::createInferRequests() {
|
||||
@@ -571,6 +630,11 @@ void cv::gimpl::ie::RequestPool::callback(cv::gimpl::ie::RequestPool::Task task,
|
||||
InferenceEngine::InferRequest& request,
|
||||
size_t id) {
|
||||
task.callback(request);
|
||||
// NB: IE::InferRequest keeps the callback until the new one is set.
|
||||
// Since user's callback might keep resources that should be released,
|
||||
// need to destroy its after execution.
|
||||
// Let's set the empty one to cause the destruction of a callback.
|
||||
request.SetCompletionCallback([](){});
|
||||
m_idle_ids.push(id);
|
||||
}
|
||||
|
||||
@@ -772,7 +836,6 @@ static void PostOutputs(InferenceEngine::InferRequest &request,
|
||||
auto output = ctx->output(i);
|
||||
ctx->out.meta(output, ctx->input(0).meta);
|
||||
ctx->out.post(std::move(output));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -854,25 +917,30 @@ struct Infer: public cv::detail::KernelTag {
|
||||
// meta order.
|
||||
GAPI_Assert(uu.params.input_names.size() == in_metas.size()
|
||||
&& "Known input layers count doesn't match input meta count");
|
||||
for (auto &&it : ade::util::zip(ade::util::toRange(uu.params.input_names),
|
||||
ade::util::toRange(in_metas))) {
|
||||
const auto &input_name = std::get<0>(it);
|
||||
auto &&ii = uu.inputs.at(input_name);
|
||||
const auto & mm = std::get<1>(it);
|
||||
|
||||
configureInputInfo(ii, mm);
|
||||
if (uu.params.layer_names_to_reshape.find(input_name) !=
|
||||
uu.params.layer_names_to_reshape.end()) {
|
||||
configureInputReshapeByImage(ii, mm, input_reshape_table);
|
||||
// NB: Configuring input precision and network reshape must be done
|
||||
// only in the loadNetwork case.
|
||||
if (uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) {
|
||||
for (auto &&it : ade::util::zip(ade::util::toRange(uu.params.input_names),
|
||||
ade::util::toRange(in_metas))) {
|
||||
const auto &input_name = std::get<0>(it);
|
||||
auto &&ii = uu.inputs.at(input_name);
|
||||
const auto & mm = std::get<1>(it);
|
||||
|
||||
configureInputInfo(ii, mm);
|
||||
if (uu.params.layer_names_to_reshape.find(input_name) !=
|
||||
uu.params.layer_names_to_reshape.end()) {
|
||||
configureInputReshapeByImage(ii, mm, input_reshape_table);
|
||||
}
|
||||
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
|
||||
}
|
||||
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
|
||||
}
|
||||
|
||||
// FIXME: This isn't the best place to call reshape function.
|
||||
// Сorrect solution would be to do this in compile() method of network,
|
||||
// but now input meta isn't passed to compile() method.
|
||||
if (!input_reshape_table.empty()) {
|
||||
const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table);
|
||||
// FIXME: This isn't the best place to call reshape function.
|
||||
// Сorrect solution would be to do this in compile() method of network,
|
||||
// but now input meta isn't passed to compile() method.
|
||||
if (!input_reshape_table.empty()) {
|
||||
const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: It would be nice here to have an exact number of network's
|
||||
@@ -904,7 +972,10 @@ struct Infer: public cv::detail::KernelTag {
|
||||
// and redirect our data producers to this memory
|
||||
// (A memory dialog comes to the picture again)
|
||||
IE::Blob::Ptr this_blob = extractBlob(*ctx, i);
|
||||
req.SetBlob(ctx->uu.params.input_names[i], this_blob);
|
||||
setBlob(req,
|
||||
ctx->uu.params.kind,
|
||||
ctx->uu.params.input_names[i],
|
||||
this_blob);
|
||||
}
|
||||
// FIXME: Should it be done by kernel ?
|
||||
// What about to do that in RequestPool ?
|
||||
@@ -936,22 +1007,26 @@ struct InferROI: public cv::detail::KernelTag {
|
||||
GAPI_Assert(1u == uu.params.input_names.size());
|
||||
GAPI_Assert(2u == in_metas.size());
|
||||
|
||||
// 0th is ROI, 1st is input image
|
||||
const auto &input_name = uu.params.input_names.at(0);
|
||||
auto &&ii = uu.inputs.at(input_name);
|
||||
auto &&mm = in_metas.at(1u);
|
||||
configureInputInfo(ii, mm);
|
||||
if (uu.params.layer_names_to_reshape.find(input_name) !=
|
||||
uu.params.layer_names_to_reshape.end()) {
|
||||
configureInputReshapeByImage(ii, mm, input_reshape_table);
|
||||
}
|
||||
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
|
||||
// NB: Configuring input precision and network reshape must be done
|
||||
// only in the loadNetwork case.
|
||||
if (uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) {
|
||||
// 0th is ROI, 1st is input image
|
||||
const auto &input_name = uu.params.input_names.at(0);
|
||||
auto &&ii = uu.inputs.at(input_name);
|
||||
auto &&mm = in_metas.at(1u);
|
||||
configureInputInfo(ii, mm);
|
||||
if (uu.params.layer_names_to_reshape.find(input_name) !=
|
||||
uu.params.layer_names_to_reshape.end()) {
|
||||
configureInputReshapeByImage(ii, mm, input_reshape_table);
|
||||
}
|
||||
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
|
||||
|
||||
// FIXME: This isn't the best place to call reshape function.
|
||||
// Сorrect solution would be to do this in compile() method of network,
|
||||
// but now input meta isn't passed to compile() method.
|
||||
if (!input_reshape_table.empty()) {
|
||||
const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table);
|
||||
// FIXME: This isn't the best place to call reshape function.
|
||||
// Сorrect solution would be to do this in compile() method of network,
|
||||
// but now input meta isn't passed to compile() method.
|
||||
if (!input_reshape_table.empty()) {
|
||||
const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: It would be nice here to have an exact number of network's
|
||||
@@ -980,10 +1055,11 @@ struct InferROI: public cv::detail::KernelTag {
|
||||
auto&& this_roi = ctx->inArg<cv::detail::OpaqueRef>(0).rref<cv::Rect>();
|
||||
|
||||
IE::Blob::Ptr this_blob = extractBlob(*ctx, 1);
|
||||
|
||||
req.SetBlob(*(ctx->uu.params.input_names.begin()),
|
||||
IE::make_shared_blob(this_blob, toIE(this_roi)));
|
||||
|
||||
setBlob(req,
|
||||
ctx->uu.params.kind,
|
||||
*(ctx->uu.params.input_names.begin()),
|
||||
IE::make_shared_blob(this_blob,
|
||||
toIE(this_roi)));
|
||||
// FIXME: Should it be done by kernel ?
|
||||
// What about to do that in RequestPool ?
|
||||
req.StartAsync();
|
||||
@@ -1018,23 +1094,27 @@ struct InferList: public cv::detail::KernelTag {
|
||||
GAPI_Assert(uu.params.input_names.size() == (in_metas.size() - 1u)
|
||||
&& "Known input layers count doesn't match input meta count");
|
||||
|
||||
std::size_t idx = 1u;
|
||||
for (auto &&input_name : uu.params.input_names) {
|
||||
auto &&ii = uu.inputs.at(input_name);
|
||||
const auto & mm = in_metas[idx++];
|
||||
configureInputInfo(ii, mm);
|
||||
if (uu.params.layer_names_to_reshape.find(input_name) !=
|
||||
uu.params.layer_names_to_reshape.end()) {
|
||||
configureInputReshapeByImage(ii, mm, input_reshape_table);
|
||||
// NB: Configuring input precision and network reshape must be done
|
||||
// only in the loadNetwork case.
|
||||
if (uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) {
|
||||
std::size_t idx = 1u;
|
||||
for (auto &&input_name : uu.params.input_names) {
|
||||
auto &&ii = uu.inputs.at(input_name);
|
||||
const auto & mm = in_metas[idx++];
|
||||
configureInputInfo(ii, mm);
|
||||
if (uu.params.layer_names_to_reshape.find(input_name) !=
|
||||
uu.params.layer_names_to_reshape.end()) {
|
||||
configureInputReshapeByImage(ii, mm, input_reshape_table);
|
||||
}
|
||||
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
|
||||
}
|
||||
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
|
||||
}
|
||||
|
||||
// FIXME: This isn't the best place to call reshape function.
|
||||
// Сorrect solution would be to do this in compile() method of network,
|
||||
// but now input meta isn't passed to compile() method.
|
||||
if (!input_reshape_table.empty()) {
|
||||
const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table);
|
||||
// FIXME: This isn't the best place to call reshape function.
|
||||
// Сorrect solution would be to do this in compile() method of network,
|
||||
// but now input meta isn't passed to compile() method.
|
||||
if (!input_reshape_table.empty()) {
|
||||
const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table);
|
||||
}
|
||||
}
|
||||
|
||||
// roi-list version is much easier at the moment.
|
||||
@@ -1060,6 +1140,7 @@ struct InferList: public cv::detail::KernelTag {
|
||||
}
|
||||
|
||||
IE::Blob::Ptr this_blob = extractBlob(*ctx, 1);
|
||||
|
||||
std::vector<std::vector<int>> cached_dims(ctx->uu.params.num_out);
|
||||
for (auto i : ade::util::iota(ctx->uu.params.num_out)) {
|
||||
const IE::DataPtr& ie_out = ctx->uu.outputs.at(ctx->uu.params.output_names[i]);
|
||||
@@ -1079,7 +1160,10 @@ struct InferList: public cv::detail::KernelTag {
|
||||
cv::gimpl::ie::RequestPool::Task {
|
||||
[ctx, rc, this_blob](InferenceEngine::InferRequest &req) {
|
||||
IE::Blob::Ptr roi_blob = IE::make_shared_blob(this_blob, toIE(rc));
|
||||
req.SetBlob(ctx->uu.params.input_names[0u], roi_blob);
|
||||
setBlob(req,
|
||||
ctx->uu.params.kind,
|
||||
ctx->uu.params.input_names[0u],
|
||||
roi_blob);
|
||||
req.StartAsync();
|
||||
},
|
||||
std::bind(callback, std::placeholders::_1, pos)
|
||||
@@ -1153,19 +1237,23 @@ struct InferList2: public cv::detail::KernelTag {
|
||||
&& "Non-array inputs are not supported");
|
||||
|
||||
if (op.k.inKinds[idx] == cv::detail::OpaqueKind::CV_RECT) {
|
||||
// This is a cv::Rect -- configure the IE preprocessing
|
||||
configureInputInfo(ii, mm_0);
|
||||
if (uu.params.layer_names_to_reshape.find(input_name) !=
|
||||
uu.params.layer_names_to_reshape.end()) {
|
||||
configureInputReshapeByImage(ii, mm_0, input_reshape_table);
|
||||
}
|
||||
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
|
||||
// NB: Configuring input precision and network reshape must be done
|
||||
// only in the loadNetwork case.
|
||||
if (uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) {
|
||||
// This is a cv::Rect -- configure the IE preprocessing
|
||||
configureInputInfo(ii, mm_0);
|
||||
if (uu.params.layer_names_to_reshape.find(input_name) !=
|
||||
uu.params.layer_names_to_reshape.end()) {
|
||||
configureInputReshapeByImage(ii, mm_0, input_reshape_table);
|
||||
}
|
||||
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
|
||||
|
||||
// FIXME: This isn't the best place to call reshape function.
|
||||
// Сorrect solution would be to do this in compile() method of network,
|
||||
// but now input meta isn't passed to compile() method.
|
||||
if (!input_reshape_table.empty()) {
|
||||
const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table);
|
||||
// FIXME: This isn't the best place to call reshape function.
|
||||
// Сorrect solution would be to do this in compile() method of network,
|
||||
// but now input meta isn't passed to compile() method.
|
||||
if (!input_reshape_table.empty()) {
|
||||
const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// This is a cv::GMat (equals to: cv::Mat)
|
||||
@@ -1230,8 +1318,10 @@ struct InferList2: public cv::detail::KernelTag {
|
||||
GAPI_Assert(false &&
|
||||
"Only Rect and Mat types are supported for infer list 2!");
|
||||
}
|
||||
|
||||
req.SetBlob(ctx->uu.params.input_names[in_idx], this_blob);
|
||||
setBlob(req,
|
||||
ctx->uu.params.kind,
|
||||
ctx->uu.params.input_names[in_idx],
|
||||
this_blob);
|
||||
}
|
||||
req.StartAsync();
|
||||
},
|
||||
|
||||
@@ -22,24 +22,6 @@ namespace IE = InferenceEngine;
|
||||
namespace giewrap = cv::gimpl::ie::wrap;
|
||||
using GIEParam = cv::gapi::ie::detail::ParamDesc;
|
||||
|
||||
IE::InputsDataMap giewrap::toInputsDataMap (const IE::ConstInputsDataMap& inputs) {
|
||||
IE::InputsDataMap transformed;
|
||||
auto convert = [](const std::pair<std::string, IE::InputInfo::CPtr>& p) {
|
||||
return std::make_pair(p.first, std::const_pointer_cast<IE::InputInfo>(p.second));
|
||||
};
|
||||
std::transform(inputs.begin(), inputs.end(), std::inserter(transformed, transformed.end()), convert);
|
||||
return transformed;
|
||||
}
|
||||
|
||||
IE::OutputsDataMap giewrap::toOutputsDataMap (const IE::ConstOutputsDataMap& outputs) {
|
||||
IE::OutputsDataMap transformed;
|
||||
auto convert = [](const std::pair<std::string, IE::CDataPtr>& p) {
|
||||
return std::make_pair(p.first, std::const_pointer_cast<IE::Data>(p.second));
|
||||
};
|
||||
std::transform(outputs.begin(), outputs.end(), std::inserter(transformed, transformed.end()), convert);
|
||||
return transformed;
|
||||
}
|
||||
|
||||
#if INF_ENGINE_RELEASE < 2020000000 // < 2020.1
|
||||
// Load extensions (taken from DNN module)
|
||||
std::vector<std::string> giewrap::getExtensions(const GIEParam& params) {
|
||||
@@ -124,7 +106,11 @@ IE::Core giewrap::getPlugin(const GIEParam& params) {
|
||||
{
|
||||
try
|
||||
{
|
||||
#if INF_ENGINE_RELEASE >= 2021040000
|
||||
plugin.AddExtension(std::make_shared<IE::Extension>(extlib), params.device_id);
|
||||
#else
|
||||
plugin.AddExtension(IE::make_so_pointer<IE::IExtension>(extlib), params.device_id);
|
||||
#endif
|
||||
CV_LOG_INFO(NULL, "DNN-IE: Loaded extension plugin: " << extlib);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
#include "opencv2/gapi/infer/ie.hpp"
|
||||
|
||||
@@ -28,9 +29,6 @@ namespace wrap {
|
||||
GAPI_EXPORTS std::vector<std::string> getExtensions(const GIEParam& params);
|
||||
GAPI_EXPORTS IE::CNNNetwork readNetwork(const GIEParam& params);
|
||||
|
||||
IE::InputsDataMap toInputsDataMap (const IE::ConstInputsDataMap& inputs);
|
||||
IE::OutputsDataMap toOutputsDataMap(const IE::ConstOutputsDataMap& outputs);
|
||||
|
||||
#if INF_ENGINE_RELEASE < 2019020000 // < 2019.R2
|
||||
using Plugin = IE::InferencePlugin;
|
||||
GAPI_EXPORTS IE::InferencePlugin getPlugin(const GIEParam& params);
|
||||
@@ -50,12 +48,29 @@ GAPI_EXPORTS IE::Core getCore();
|
||||
GAPI_EXPORTS IE::Core getPlugin(const GIEParam& params);
|
||||
GAPI_EXPORTS inline IE::ExecutableNetwork loadNetwork( IE::Core& core,
|
||||
const IE::CNNNetwork& net,
|
||||
const GIEParam& params) {
|
||||
return core.LoadNetwork(net, params.device_id);
|
||||
const GIEParam& params,
|
||||
IE::RemoteContext::Ptr rctx = nullptr) {
|
||||
if (rctx != nullptr) {
|
||||
return core.LoadNetwork(net, rctx);
|
||||
} else {
|
||||
return core.LoadNetwork(net, params.device_id);
|
||||
}
|
||||
}
|
||||
GAPI_EXPORTS inline IE::ExecutableNetwork importNetwork( IE::Core& core,
|
||||
const GIEParam& param) {
|
||||
return core.ImportNetwork(param.model_path, param.device_id, {});
|
||||
const GIEParam& params,
|
||||
IE::RemoteContext::Ptr rctx = nullptr) {
|
||||
if (rctx != nullptr) {
|
||||
std::filebuf blobFile;
|
||||
if (!blobFile.open(params.model_path, std::ios::in | std::ios::binary))
|
||||
{
|
||||
blobFile.close();
|
||||
throw std::runtime_error("Could not open file");
|
||||
}
|
||||
std::istream graphBlob(&blobFile);
|
||||
return core.ImportNetwork(graphBlob, rctx);
|
||||
} else {
|
||||
return core.ImportNetwork(params.model_path, params.device_id, {});
|
||||
}
|
||||
}
|
||||
#endif // INF_ENGINE_RELEASE < 2019020000
|
||||
}}}}
|
||||
|
||||
@@ -75,6 +75,11 @@ bool cv::GStreamingCompiled::Priv::pull(cv::GOptRunArgsP &&outs)
|
||||
return m_exec->pull(std::move(outs));
|
||||
}
|
||||
|
||||
std::tuple<bool, cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>> cv::GStreamingCompiled::Priv::pull()
|
||||
{
|
||||
return m_exec->pull();
|
||||
}
|
||||
|
||||
bool cv::GStreamingCompiled::Priv::try_pull(cv::GRunArgsP &&outs)
|
||||
{
|
||||
return m_exec->try_pull(std::move(outs));
|
||||
@@ -123,18 +128,9 @@ bool cv::GStreamingCompiled::pull(cv::GRunArgsP &&outs)
|
||||
return m_priv->pull(std::move(outs));
|
||||
}
|
||||
|
||||
std::tuple<bool, cv::GRunArgs> cv::GStreamingCompiled::pull()
|
||||
std::tuple<bool, cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>> cv::GStreamingCompiled::pull()
|
||||
{
|
||||
GRunArgs run_args;
|
||||
GRunArgsP outs;
|
||||
const auto& out_info = m_priv->outInfo();
|
||||
run_args.reserve(out_info.size());
|
||||
outs.reserve(out_info.size());
|
||||
|
||||
cv::detail::constructGraphOutputs(m_priv->outInfo(), run_args, outs);
|
||||
|
||||
bool is_over = m_priv->pull(std::move(outs));
|
||||
return std::make_tuple(is_over, run_args);
|
||||
return m_priv->pull();
|
||||
}
|
||||
|
||||
bool cv::GStreamingCompiled::pull(cv::GOptRunArgsP &&outs)
|
||||
|
||||
@@ -46,6 +46,7 @@ public:
|
||||
void start();
|
||||
bool pull(cv::GRunArgsP &&outs);
|
||||
bool pull(cv::GOptRunArgsP &&outs);
|
||||
std::tuple<bool, cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>> pull();
|
||||
bool try_pull(cv::GRunArgsP &&outs);
|
||||
void stop();
|
||||
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <ade/util/zip_range.hpp>
|
||||
|
||||
#include <opencv2/gapi/opencv_includes.hpp>
|
||||
@@ -157,10 +155,14 @@ void writeBackExec(const Mag& mag, const RcDesc &rc, GRunArgP &g_arg)
|
||||
// FIXME:
|
||||
// Rework, find a better way to check if there should be
|
||||
// a real copy (add a pass to StreamingBackend?)
|
||||
// NB: In case RMat adapter not equal to "RMatAdapter" need to
|
||||
// copy data back to the host as well.
|
||||
// FIXME: Rename "RMatAdapter" to "OpenCVAdapter".
|
||||
auto& out_mat = *util::get<cv::Mat*>(g_arg);
|
||||
const auto& rmat = mag.template slot<cv::RMat>().at(rc.id);
|
||||
auto mag_data = rmat.get<RMatAdapter>()->data();
|
||||
if (out_mat.data != mag_data) {
|
||||
auto* adapter = rmat.get<RMatAdapter>();
|
||||
if ((adapter != nullptr && out_mat.data != adapter->data()) ||
|
||||
(adapter == nullptr)) {
|
||||
auto view = rmat.access(RMat::Access::R);
|
||||
asMat(view).copyTo(out_mat);
|
||||
}
|
||||
@@ -407,7 +409,8 @@ bool cv::gimpl::GExecutor::canReshape() const
|
||||
{
|
||||
// FIXME: Introduce proper reshaping support on GExecutor level
|
||||
// for all cases!
|
||||
return (m_ops.size() == 1) && m_ops[0].isl_exec->canReshape();
|
||||
return std::all_of(m_ops.begin(), m_ops.end(),
|
||||
[](const OpDesc& op) { return op.isl_exec->canReshape(); });
|
||||
}
|
||||
|
||||
void cv::gimpl::GExecutor::reshape(const GMetaArgs& inMetas, const GCompileArgs& args)
|
||||
@@ -417,7 +420,17 @@ void cv::gimpl::GExecutor::reshape(const GMetaArgs& inMetas, const GCompileArgs&
|
||||
ade::passes::PassContext ctx{g};
|
||||
passes::initMeta(ctx, inMetas);
|
||||
passes::inferMeta(ctx, true);
|
||||
m_ops[0].isl_exec->reshape(g, args);
|
||||
|
||||
// NB: Before reshape islands need to re-init resources for every slot.
|
||||
for (auto slot : m_slots)
|
||||
{
|
||||
initResource(slot.slot_nh, slot.data_nh);
|
||||
}
|
||||
|
||||
for (auto& op : m_ops)
|
||||
{
|
||||
op.isl_exec->reshape(g, args);
|
||||
}
|
||||
}
|
||||
|
||||
void cv::gimpl::GExecutor::prepareForNewStream()
|
||||
|
||||
@@ -186,8 +186,9 @@ void sync_data(cv::gimpl::stream::Result &r, cv::GOptRunArgsP &outputs)
|
||||
// FIXME: this conversion should be unified
|
||||
switch (out_obj.index())
|
||||
{
|
||||
HANDLE_CASE(cv::Scalar); break;
|
||||
HANDLE_CASE(cv::RMat); break;
|
||||
HANDLE_CASE(cv::Scalar); break;
|
||||
HANDLE_CASE(cv::RMat); break;
|
||||
HANDLE_CASE(cv::MediaFrame); break;
|
||||
|
||||
case T::index_of<O<cv::Mat>*>(): {
|
||||
// Mat: special handling.
|
||||
@@ -346,6 +347,10 @@ bool QueueReader::getInputVector(std::vector<Q*> &in_queues,
|
||||
cv::GRunArgs &in_constants,
|
||||
cv::GRunArgs &isl_inputs)
|
||||
{
|
||||
// NB: Need to release resources from the previous step, to fetch new ones.
|
||||
// On some systems it might be impossible to allocate new memory
|
||||
// until the old one is released.
|
||||
m_cmd.clear();
|
||||
// NOTE: in order to maintain the GRunArg's underlying object
|
||||
// lifetime, keep the whole cmd vector (of size == # of inputs)
|
||||
// in memory.
|
||||
@@ -1017,6 +1022,49 @@ void check_DesyncObjectConsumedByMultipleIslands(const cv::gimpl::GIslandModel::
|
||||
} // for(nodes)
|
||||
}
|
||||
|
||||
// NB: Construct GRunArgsP based on passed info and store the memory in passed cv::GRunArgs.
|
||||
// Needed for python bridge, because in case python user doesn't pass output arguments to apply.
|
||||
void constructOptGraphOutputs(const cv::GTypesInfo &out_info,
|
||||
cv::GOptRunArgs &args,
|
||||
cv::GOptRunArgsP &outs)
|
||||
{
|
||||
for (auto&& info : out_info)
|
||||
{
|
||||
switch (info.shape)
|
||||
{
|
||||
case cv::GShape::GMAT:
|
||||
{
|
||||
args.emplace_back(cv::optional<cv::Mat>{});
|
||||
outs.emplace_back(&cv::util::get<cv::optional<cv::Mat>>(args.back()));
|
||||
break;
|
||||
}
|
||||
case cv::GShape::GSCALAR:
|
||||
{
|
||||
args.emplace_back(cv::optional<cv::Scalar>{});
|
||||
outs.emplace_back(&cv::util::get<cv::optional<cv::Scalar>>(args.back()));
|
||||
break;
|
||||
}
|
||||
case cv::GShape::GARRAY:
|
||||
{
|
||||
cv::detail::VectorRef ref;
|
||||
cv::util::get<cv::detail::ConstructVec>(info.ctor)(ref);
|
||||
args.emplace_back(cv::util::make_optional(std::move(ref)));
|
||||
outs.emplace_back(wrap_opt_arg(cv::util::get<cv::optional<cv::detail::VectorRef>>(args.back())));
|
||||
break;
|
||||
}
|
||||
case cv::GShape::GOPAQUE:
|
||||
{
|
||||
cv::detail::OpaqueRef ref;
|
||||
cv::util::get<cv::detail::ConstructOpaque>(info.ctor)(ref);
|
||||
args.emplace_back(cv::util::make_optional(std::move(ref)));
|
||||
outs.emplace_back(wrap_opt_arg(cv::util::get<cv::optional<cv::detail::OpaqueRef>>(args.back())));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
cv::util::throw_error(std::logic_error("Unsupported optional output shape for Python"));
|
||||
}
|
||||
}
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
class cv::gimpl::GStreamingExecutor::Synchronizer final {
|
||||
@@ -1320,6 +1368,16 @@ cv::gimpl::GStreamingExecutor::GStreamingExecutor(std::unique_ptr<ade::Graph> &&
|
||||
// per the same input frame, so the output traffic multiplies)
|
||||
GAPI_Assert(m_collector_map.size() > 0u);
|
||||
m_out_queue.set_capacity(queue_capacity * m_collector_map.size());
|
||||
|
||||
// FIXME: The code duplicates logic of collectGraphInfo()
|
||||
cv::gimpl::GModel::ConstGraph cgr(*m_orig_graph);
|
||||
auto meta = cgr.metadata().get<cv::gimpl::Protocol>().out_nhs;
|
||||
out_info.reserve(meta.size());
|
||||
|
||||
ade::util::transform(meta, std::back_inserter(out_info), [&cgr](const ade::NodeHandle& nh) {
|
||||
const auto& data = cgr.metadata(nh).get<cv::gimpl::Data>();
|
||||
return cv::GTypeInfo{data.shape, data.kind, data.ctor};
|
||||
});
|
||||
}
|
||||
|
||||
cv::gimpl::GStreamingExecutor::~GStreamingExecutor()
|
||||
@@ -1653,6 +1711,31 @@ bool cv::gimpl::GStreamingExecutor::pull(cv::GOptRunArgsP &&outs)
|
||||
return true;
|
||||
}
|
||||
|
||||
std::tuple<bool, cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>> cv::gimpl::GStreamingExecutor::pull()
|
||||
{
|
||||
using RunArgs = cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>;
|
||||
bool is_over = false;
|
||||
|
||||
if (m_desync) {
|
||||
GOptRunArgs opt_run_args;
|
||||
GOptRunArgsP opt_outs;
|
||||
opt_outs.reserve(out_info.size());
|
||||
opt_run_args.reserve(out_info.size());
|
||||
|
||||
constructOptGraphOutputs(out_info, opt_run_args, opt_outs);
|
||||
is_over = pull(std::move(opt_outs));
|
||||
return std::make_tuple(is_over, RunArgs(opt_run_args));
|
||||
}
|
||||
|
||||
GRunArgs run_args;
|
||||
GRunArgsP outs;
|
||||
run_args.reserve(out_info.size());
|
||||
outs.reserve(out_info.size());
|
||||
|
||||
constructGraphOutputs(out_info, run_args, outs);
|
||||
is_over = pull(std::move(outs));
|
||||
return std::make_tuple(is_over, RunArgs(run_args));
|
||||
}
|
||||
|
||||
bool cv::gimpl::GStreamingExecutor::try_pull(cv::GRunArgsP &&outs)
|
||||
{
|
||||
|
||||
@@ -195,6 +195,8 @@ protected:
|
||||
|
||||
void wait_shutdown();
|
||||
|
||||
cv::GTypesInfo out_info;
|
||||
|
||||
public:
|
||||
explicit GStreamingExecutor(std::unique_ptr<ade::Graph> &&g_model,
|
||||
const cv::GCompileArgs &comp_args);
|
||||
@@ -203,6 +205,7 @@ public:
|
||||
void start();
|
||||
bool pull(cv::GRunArgsP &&outs);
|
||||
bool pull(cv::GOptRunArgsP &&outs);
|
||||
std::tuple<bool, cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>> pull();
|
||||
bool try_pull(cv::GRunArgsP &&outs);
|
||||
void stop();
|
||||
bool running() const;
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
// 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 <cstdlib>
|
||||
#include <exception>
|
||||
|
||||
#include "streaming/onevpl/accelerators/accel_policy_cpu.hpp"
|
||||
#include "streaming/onevpl/accelerators/surface/cpu_frame_adapter.hpp"
|
||||
#include "streaming/onevpl/accelerators/surface/surface.hpp"
|
||||
#include "logger.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <sysinfoapi.h>
|
||||
#endif
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
|
||||
VPLCPUAccelerationPolicy::VPLCPUAccelerationPolicy() {
|
||||
GAPI_LOG_INFO(nullptr, "created");
|
||||
}
|
||||
|
||||
VPLCPUAccelerationPolicy::~VPLCPUAccelerationPolicy() {
|
||||
for (auto& pair : pool_table) {
|
||||
pair.second.clear();
|
||||
// do not free key here: last surface will release it
|
||||
}
|
||||
GAPI_LOG_INFO(nullptr, "destroyed");
|
||||
}
|
||||
|
||||
void VPLCPUAccelerationPolicy::init(session_t session) {
|
||||
GAPI_LOG_INFO(nullptr, "initialize session: " << session);
|
||||
}
|
||||
|
||||
void VPLCPUAccelerationPolicy::deinit(session_t session) {
|
||||
GAPI_LOG_INFO(nullptr, "deinitialize session: " << session);
|
||||
}
|
||||
|
||||
VPLCPUAccelerationPolicy::pool_key_t
|
||||
VPLCPUAccelerationPolicy::create_surface_pool(size_t pool_size, size_t surface_size_bytes,
|
||||
surface_ptr_ctr_t creator) {
|
||||
GAPI_LOG_DEBUG(nullptr, "pool size: " << pool_size << ", surface size bytes: " << surface_size_bytes);
|
||||
|
||||
// create empty pool
|
||||
pool_t pool;
|
||||
pool.reserve(pool_size);
|
||||
|
||||
// allocate workplace memory area
|
||||
size_t preallocated_raw_bytes = pool_size * surface_size_bytes;
|
||||
size_t page_size_bytes = 4 * 1024;
|
||||
void *preallocated_pool_memory_ptr = nullptr;
|
||||
|
||||
#ifdef _WIN32
|
||||
SYSTEM_INFO sysInfo;
|
||||
GetSystemInfo(&sysInfo);
|
||||
page_size_bytes = sysInfo.dwPageSize;
|
||||
|
||||
GAPI_LOG_DEBUG(nullptr, "page size: " << page_size_bytes << ", preallocated_raw_bytes: " << preallocated_raw_bytes);
|
||||
preallocated_pool_memory_ptr = _aligned_malloc(preallocated_raw_bytes, page_size_bytes);
|
||||
#else
|
||||
GAPI_Assert(false && "Compatibility is not tested for systems differ than \"_WIN32\". "
|
||||
"Please feel free to set it up under OPENCV contribution policy");
|
||||
#endif
|
||||
|
||||
if (!preallocated_pool_memory_ptr) {
|
||||
throw std::runtime_error("VPLCPUAccelerationPolicy::create_surface_pool - failed: not enough memory."
|
||||
"Requested surface count: " + std::to_string(pool_size) +
|
||||
", surface bytes: " + std::to_string(surface_size_bytes));
|
||||
}
|
||||
|
||||
// fill pool with surfaces
|
||||
std::shared_ptr<void> workspace_mem_owner (preallocated_pool_memory_ptr, [] (void *ptr){
|
||||
GAPI_LOG_INFO(nullptr, "Free workspace memory: " << ptr);
|
||||
#ifdef _WIN32
|
||||
_aligned_free(ptr);
|
||||
GAPI_LOG_INFO(nullptr, "Released workspace memory: " << ptr);
|
||||
ptr = nullptr;
|
||||
#else
|
||||
GAPI_Assert(false && "Not implemented for systems differ than \"_WIN32\". "
|
||||
"Please feel free to set it up under OPENCV contribution policy");
|
||||
#endif
|
||||
|
||||
});
|
||||
size_t i = 0;
|
||||
try {
|
||||
for (; i < pool_size; i++) {
|
||||
size_t preallocated_mem_offset = static_cast<size_t>(i) * surface_size_bytes;
|
||||
|
||||
surface_ptr_t surf_ptr = creator(workspace_mem_owner,
|
||||
preallocated_mem_offset,
|
||||
preallocated_raw_bytes);
|
||||
pool.push_back(std::move(surf_ptr));
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
throw std::runtime_error(std::string("VPLCPUAccelerationPolicy::create_surface_pool - ") +
|
||||
"cannot construct surface index: " + std::to_string(i) + ", error: " +
|
||||
ex.what() +
|
||||
"Requested surface count: " + std::to_string(pool_size) +
|
||||
", surface bytes: " + std::to_string(surface_size_bytes));
|
||||
}
|
||||
|
||||
// remember pool by key
|
||||
GAPI_LOG_INFO(nullptr, "New pool allocated, key: " << preallocated_pool_memory_ptr <<
|
||||
", surface count: " << pool.size() <<
|
||||
", surface size bytes: " << surface_size_bytes);
|
||||
if (!pool_table.emplace(preallocated_pool_memory_ptr, std::move(pool)).second) {
|
||||
GAPI_LOG_WARNING(nullptr, "Cannot insert pool, table size: " + std::to_string(pool_table.size()) <<
|
||||
", key: " << preallocated_pool_memory_ptr << " exists");
|
||||
GAPI_Assert(false && "Cannot create pool in VPLCPUAccelerationPolicy");
|
||||
}
|
||||
|
||||
return preallocated_pool_memory_ptr;
|
||||
}
|
||||
|
||||
VPLCPUAccelerationPolicy::surface_weak_ptr_t VPLCPUAccelerationPolicy::get_free_surface(pool_key_t key) {
|
||||
auto pool_it = pool_table.find(key);
|
||||
if (pool_it == pool_table.end()) {
|
||||
throw std::runtime_error("VPLCPUAccelerationPolicy::get_free_surface - "
|
||||
"key is not found, table size: " +
|
||||
std::to_string(pool_table.size()));
|
||||
}
|
||||
|
||||
pool_t& requested_pool = pool_it->second;
|
||||
#ifdef TEST_PERF
|
||||
return requested_pool.find_free();
|
||||
#else // TEST_PERF
|
||||
auto it =
|
||||
std::find_if(requested_pool.begin(), requested_pool.end(),
|
||||
[](const surface_ptr_t& val) {
|
||||
GAPI_DbgAssert(val && "Pool contains empty surface");
|
||||
return !val->get_locks_count();
|
||||
});
|
||||
|
||||
// Limitation realloc pool might be a future extension
|
||||
if (it == requested_pool.end()) {
|
||||
std::stringstream ss;
|
||||
ss << "cannot get free surface from pool, key: " << key << ", size: " << requested_pool.size();
|
||||
const std::string& str = ss.str();
|
||||
GAPI_LOG_WARNING(nullptr, str);
|
||||
throw std::runtime_error(std::string(__FUNCTION__) + " - " + str);
|
||||
}
|
||||
|
||||
return *it;
|
||||
#endif // TEST_PERF
|
||||
}
|
||||
|
||||
size_t VPLCPUAccelerationPolicy::get_free_surface_count(pool_key_t key) const {
|
||||
auto pool_it = pool_table.find(key);
|
||||
if (pool_it == pool_table.end()) {
|
||||
GAPI_LOG_WARNING(nullptr, "key is not found: " << key <<
|
||||
", table size: " << pool_table.size());
|
||||
return 0;
|
||||
}
|
||||
#ifdef TEST_PERF
|
||||
return 0;
|
||||
#else // TEST_PERF
|
||||
const pool_t& requested_pool = pool_it->second;
|
||||
size_t free_surf_count =
|
||||
std::count_if(requested_pool.begin(), requested_pool.end(),
|
||||
[](const surface_ptr_t& val) {
|
||||
GAPI_Assert(val && "Pool contains empty surface");
|
||||
return !val->get_locks_count();
|
||||
});
|
||||
return free_surf_count;
|
||||
#endif // TEST_PERF
|
||||
}
|
||||
|
||||
size_t VPLCPUAccelerationPolicy::get_surface_count(pool_key_t key) const {
|
||||
auto pool_it = pool_table.find(key);
|
||||
if (pool_it == pool_table.end()) {
|
||||
GAPI_LOG_DEBUG(nullptr, "key is not found: " << key <<
|
||||
", table size: " << pool_table.size());
|
||||
return 0;
|
||||
}
|
||||
#ifdef TEST_PERF
|
||||
return 0;
|
||||
#else // TEST_PERF
|
||||
return pool_it->second.size();
|
||||
#endif // TEST_PERF
|
||||
}
|
||||
|
||||
cv::MediaFrame::AdapterPtr VPLCPUAccelerationPolicy::create_frame_adapter(pool_key_t key,
|
||||
mfxFrameSurface1* surface) {
|
||||
auto pool_it = pool_table.find(key);
|
||||
if (pool_it == pool_table.end()) {
|
||||
std::stringstream ss;
|
||||
ss << "key is not found: " << key << ", table size: " << pool_table.size();
|
||||
const std::string& str = ss.str();
|
||||
GAPI_LOG_WARNING(nullptr, str);
|
||||
throw std::runtime_error(std::string(__FUNCTION__) + " - " + str);
|
||||
}
|
||||
|
||||
pool_t& requested_pool = pool_it->second;
|
||||
#ifdef TEST_PERF
|
||||
return cv::MediaFrame::AdapterPtr{new VPLMediaFrameCPUAdapter(requested_pool.find_by_handle(surface))};
|
||||
#else // TEST_PERF
|
||||
auto it =
|
||||
std::find_if(requested_pool.begin(), requested_pool.end(),
|
||||
[surface](const surface_ptr_t& val) {
|
||||
GAPI_DbgAssert(val && "Pool contains empty surface");
|
||||
return val->get_handle() == surface;
|
||||
});
|
||||
|
||||
// Limitation realloc pool might be a future extension
|
||||
if (it == requested_pool.end()) {
|
||||
std::stringstream ss;
|
||||
ss << "cannot get requested surface from pool, key: " << key << ", surf: "
|
||||
<< surface << ", pool size: " << requested_pool.size();
|
||||
const std::string& str = ss.str();
|
||||
GAPI_LOG_WARNING(nullptr, str);
|
||||
throw std::runtime_error(std::string(__FUNCTION__) + " - " + str);
|
||||
}
|
||||
|
||||
return cv::MediaFrame::AdapterPtr{new VPLMediaFrameCPUAdapter(*it)};
|
||||
#endif // TEST_PERF
|
||||
}
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
#endif // HAVE_ONEVPL
|
||||
@@ -0,0 +1,57 @@
|
||||
// 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_ACCELERATORS_ACCEL_POLICY_CPU_HPP
|
||||
#define GAPI_STREAMING_ONEVPL_ACCELERATORS_ACCEL_POLICY_CPU_HPP
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
#include <vpl/mfxvideo.h>
|
||||
#include "streaming/onevpl/accelerators/accel_policy_interface.hpp"
|
||||
#ifdef TEST_PERF
|
||||
#include "streaming/onevpl/accelerators/surface/surface_pool.hpp"
|
||||
#endif // TEST_PERF
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
|
||||
// GAPI_EXPORTS for tests
|
||||
struct GAPI_EXPORTS VPLCPUAccelerationPolicy final : public VPLAccelerationPolicy
|
||||
{
|
||||
VPLCPUAccelerationPolicy();
|
||||
~VPLCPUAccelerationPolicy();
|
||||
#ifdef TEST_PERF
|
||||
using pool_t = CachedPool;
|
||||
#else // TEST_PERF
|
||||
using pool_t = std::vector<surface_ptr_t>;
|
||||
#endif // TEST_PERF
|
||||
|
||||
void init(session_t session) override;
|
||||
void deinit(session_t session) override;
|
||||
pool_key_t create_surface_pool(size_t pool_size, size_t surface_size_bytes, surface_ptr_ctr_t creator) override;
|
||||
surface_weak_ptr_t get_free_surface(pool_key_t key) override;
|
||||
size_t get_free_surface_count(pool_key_t key) const override;
|
||||
size_t get_surface_count(pool_key_t key) const override;
|
||||
|
||||
cv::MediaFrame::AdapterPtr create_frame_adapter(pool_key_t key,
|
||||
mfxFrameSurface1* surface) override;
|
||||
|
||||
private:
|
||||
std::map<pool_key_t, pool_t> pool_table;
|
||||
};
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // HAVE_ONEVPL
|
||||
#endif // GAPI_STREAMING_ONEVPL_ACCELERATORS_ACCEL_POLICY_CPU_HPP
|
||||
@@ -0,0 +1,119 @@
|
||||
// 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 "streaming/onevpl/accelerators/accel_policy_dx11.hpp"
|
||||
#include "streaming/onevpl/accelerators/surface/cpu_frame_adapter.hpp"
|
||||
#include "streaming/onevpl/accelerators/surface/surface.hpp"
|
||||
#include "streaming/onevpl/utils.hpp"
|
||||
#include "logger.hpp"
|
||||
|
||||
#ifdef HAVE_DIRECTX
|
||||
#ifdef HAVE_D3D11
|
||||
#pragma comment(lib,"d3d11.lib")
|
||||
|
||||
#define D3D11_NO_HELPERS
|
||||
#include <d3d11.h>
|
||||
#include <d3d11_4.h>
|
||||
#include <codecvt>
|
||||
#include "opencv2/core/directx.hpp"
|
||||
|
||||
#ifdef HAVE_OPENCL
|
||||
#include <CL/cl_d3d11.h>
|
||||
#endif
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
|
||||
VPLDX11AccelerationPolicy::VPLDX11AccelerationPolicy()
|
||||
{
|
||||
#ifdef CPU_ACCEL_ADAPTER
|
||||
adapter.reset(new VPLCPUAccelerationPolicy);
|
||||
#endif
|
||||
}
|
||||
|
||||
VPLDX11AccelerationPolicy::~VPLDX11AccelerationPolicy()
|
||||
{
|
||||
if (hw_handle)
|
||||
{
|
||||
GAPI_LOG_INFO(nullptr, "VPLDX11AccelerationPolicy release ID3D11Device");
|
||||
hw_handle->Release();
|
||||
}
|
||||
}
|
||||
|
||||
void VPLDX11AccelerationPolicy::init(session_t session) {
|
||||
mfxStatus sts = MFXVideoCORE_GetHandle(session, MFX_HANDLE_D3D11_DEVICE, reinterpret_cast<mfxHDL*>(&hw_handle));
|
||||
if (sts != MFX_ERR_NONE)
|
||||
{
|
||||
throw std::logic_error("Cannot create VPLDX11AccelerationPolicy, MFXVideoCORE_GetHandle error: " +
|
||||
mfxstatus_to_string(sts));
|
||||
}
|
||||
|
||||
GAPI_LOG_INFO(nullptr, "VPLDX11AccelerationPolicy initialized, session: " << session);
|
||||
}
|
||||
|
||||
void VPLDX11AccelerationPolicy::deinit(session_t session) {
|
||||
GAPI_LOG_INFO(nullptr, "deinitialize session: " << session);
|
||||
}
|
||||
|
||||
VPLDX11AccelerationPolicy::pool_key_t
|
||||
VPLDX11AccelerationPolicy::create_surface_pool(size_t pool_size, size_t surface_size_bytes,
|
||||
surface_ptr_ctr_t creator) {
|
||||
GAPI_LOG_DEBUG(nullptr, "pool size: " << pool_size << ", surface size bytes: " << surface_size_bytes);
|
||||
|
||||
#ifdef CPU_ACCEL_ADAPTER
|
||||
return adapter->create_surface_pool(pool_size, surface_size_bytes, creator);
|
||||
#endif
|
||||
(void)pool_size;
|
||||
(void)surface_size_bytes;
|
||||
(void)creator;
|
||||
throw std::runtime_error("VPLDX11AccelerationPolicy::create_surface_pool() is not implemented");
|
||||
}
|
||||
|
||||
VPLDX11AccelerationPolicy::surface_weak_ptr_t VPLDX11AccelerationPolicy::get_free_surface(pool_key_t key)
|
||||
{
|
||||
#ifdef CPU_ACCEL_ADAPTER
|
||||
return adapter->get_free_surface(key);
|
||||
#endif
|
||||
(void)key;
|
||||
throw std::runtime_error("VPLDX11AccelerationPolicy::get_free_surface() is not implemented");
|
||||
}
|
||||
|
||||
size_t VPLDX11AccelerationPolicy::get_free_surface_count(pool_key_t key) const {
|
||||
#ifdef CPU_ACCEL_ADAPTER
|
||||
return adapter->get_free_surface_count(key);
|
||||
#endif
|
||||
(void)key;
|
||||
throw std::runtime_error("get_free_surface_count() is not implemented");
|
||||
}
|
||||
|
||||
size_t VPLDX11AccelerationPolicy::get_surface_count(pool_key_t key) const {
|
||||
#ifdef CPU_ACCEL_ADAPTER
|
||||
return adapter->get_surface_count(key);
|
||||
#endif
|
||||
(void)key;
|
||||
throw std::runtime_error("VPLDX11AccelerationPolicy::get_surface_count() is not implemented");
|
||||
}
|
||||
|
||||
cv::MediaFrame::AdapterPtr VPLDX11AccelerationPolicy::create_frame_adapter(pool_key_t key,
|
||||
mfxFrameSurface1* surface) {
|
||||
|
||||
#ifdef CPU_ACCEL_ADAPTER
|
||||
return adapter->create_frame_adapter(key, surface);
|
||||
#endif
|
||||
(void)key;
|
||||
(void)surface;
|
||||
throw std::runtime_error("VPLDX11AccelerationPolicy::create_frame_adapter() is not implemented");
|
||||
}
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
#endif // HAVE_D3D11
|
||||
#endif // HAVE_DIRECTX
|
||||
#endif // HAVE_ONEVPL
|
||||
@@ -0,0 +1,69 @@
|
||||
// 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_ACCELERATORS_ACCEL_POLICY_DX11_HPP
|
||||
#define GAPI_STREAMING_ONEVPL_ACCELERATORS_ACCEL_POLICY_DX11_HPP
|
||||
|
||||
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
|
||||
//TODO Remove the next MACRO right after DX11 implementation
|
||||
#define CPU_ACCEL_ADAPTER
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
#include <vpl/mfxvideo.h>
|
||||
#include "streaming/onevpl/accelerators/accel_policy_interface.hpp"
|
||||
|
||||
#ifdef CPU_ACCEL_ADAPTER
|
||||
#include "streaming/onevpl/accelerators/accel_policy_cpu.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DIRECTX
|
||||
#ifdef HAVE_D3D11
|
||||
#define D3D11_NO_HELPERS
|
||||
#include <d3d11.h>
|
||||
#include <codecvt>
|
||||
#include "opencv2/core/directx.hpp"
|
||||
#ifdef HAVE_OPENCL
|
||||
#include <CL/cl_d3d11.h>
|
||||
#endif
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
|
||||
// GAPI_EXPORTS for tests
|
||||
struct GAPI_EXPORTS VPLDX11AccelerationPolicy final: public VPLAccelerationPolicy
|
||||
{
|
||||
// GAPI_EXPORTS for tests
|
||||
VPLDX11AccelerationPolicy();
|
||||
~VPLDX11AccelerationPolicy();
|
||||
|
||||
void init(session_t session) override;
|
||||
void deinit(session_t session) override;
|
||||
pool_key_t create_surface_pool(size_t pool_size, size_t surface_size_bytes, surface_ptr_ctr_t creator) override;
|
||||
surface_weak_ptr_t get_free_surface(pool_key_t key) override;
|
||||
size_t get_free_surface_count(pool_key_t key) const override;
|
||||
size_t get_surface_count(pool_key_t key) const override;
|
||||
|
||||
cv::MediaFrame::AdapterPtr create_frame_adapter(pool_key_t key,
|
||||
mfxFrameSurface1* surface) override;
|
||||
|
||||
private:
|
||||
ID3D11Device *hw_handle;
|
||||
|
||||
#ifdef CPU_ACCEL_ADAPTER
|
||||
std::unique_ptr<VPLCPUAccelerationPolicy> adapter;
|
||||
#endif
|
||||
};
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
#endif // HAVE_D3D11
|
||||
#endif // HAVE_DIRECTX
|
||||
|
||||
#endif // HAVE_ONEVPL
|
||||
#endif // GAPI_STREAMING_ONEVPL_ACCELERATORS_ACCEL_POLICY_DX11_HPP
|
||||
@@ -0,0 +1,61 @@
|
||||
// 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_ACCELERATORS_ACCEL_POLICY_INTERFACE_HPP
|
||||
#define GAPI_STREAMING_ONEVPL_ACCELERATORS_ACCEL_POLICY_INTERFACE_HPP
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include <opencv2/gapi/media.hpp>
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
#include <vpl/mfxvideo.h>
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
|
||||
class Surface;
|
||||
struct VPLAccelerationPolicy
|
||||
{
|
||||
virtual ~VPLAccelerationPolicy() {}
|
||||
|
||||
using pool_key_t = void*;
|
||||
|
||||
using session_t = mfxSession;
|
||||
using surface_t = Surface;
|
||||
using surface_ptr_t = std::shared_ptr<surface_t>;
|
||||
using surface_weak_ptr_t = std::weak_ptr<surface_t>;
|
||||
using surface_ptr_ctr_t = std::function<surface_ptr_t(std::shared_ptr<void> out_buf_ptr,
|
||||
size_t out_buf_ptr_offset,
|
||||
size_t out_buf_ptr_size)>;
|
||||
|
||||
virtual void init(session_t session) = 0;
|
||||
virtual void deinit(session_t session) = 0;
|
||||
|
||||
// Limitation: cannot give guarantee in succesful memory realloccation
|
||||
// for existing workspace in existing pool (see realloc)
|
||||
// thus it is not implemented,
|
||||
// PLEASE provide initial memory area large enough
|
||||
virtual pool_key_t create_surface_pool(size_t pool_size, size_t surface_size_bytes, surface_ptr_ctr_t creator) = 0;
|
||||
|
||||
virtual surface_weak_ptr_t get_free_surface(pool_key_t key) = 0;
|
||||
virtual size_t get_free_surface_count(pool_key_t key) const = 0;
|
||||
virtual size_t get_surface_count(pool_key_t key) const = 0;
|
||||
|
||||
virtual cv::MediaFrame::AdapterPtr create_frame_adapter(pool_key_t key,
|
||||
mfxFrameSurface1* surface) = 0;
|
||||
};
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // HAVE_ONEVPL
|
||||
#endif // GAPI_STREAMING_ONEVPL_ACCELERATORS_ACCEL_POLICY_INTERFACE_HPP
|
||||
@@ -0,0 +1,119 @@
|
||||
// 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
|
||||
|
||||
#include "streaming/onevpl/accelerators/surface/cpu_frame_adapter.hpp"
|
||||
#include "streaming/onevpl/accelerators/surface/surface.hpp"
|
||||
#include "logger.hpp"
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
|
||||
#if (MFX_VERSION >= 2000)
|
||||
#include <vpl/mfxdispatcher.h>
|
||||
#endif
|
||||
|
||||
#include <vpl/mfx.h>
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
|
||||
VPLMediaFrameCPUAdapter::VPLMediaFrameCPUAdapter(std::shared_ptr<Surface> surface):
|
||||
parent_surface_ptr(surface) {
|
||||
|
||||
GAPI_Assert(parent_surface_ptr && "Surface is nullptr");
|
||||
parent_surface_ptr->obtain_lock();
|
||||
|
||||
GAPI_LOG_DEBUG(nullptr, "surface: " << parent_surface_ptr->get_handle() <<
|
||||
", w: " << parent_surface_ptr->get_info().Width <<
|
||||
", h: " << parent_surface_ptr->get_info().Height <<
|
||||
", p: " << parent_surface_ptr->get_data().Pitch);
|
||||
}
|
||||
|
||||
VPLMediaFrameCPUAdapter::~VPLMediaFrameCPUAdapter() {
|
||||
|
||||
// Each VPLMediaFrameCPUAdapter releases mfx surface counter
|
||||
// The last VPLMediaFrameCPUAdapter releases shared Surface pointer
|
||||
// The last surface pointer releases workspace memory
|
||||
parent_surface_ptr->release_lock();
|
||||
}
|
||||
|
||||
cv::GFrameDesc VPLMediaFrameCPUAdapter::meta() const {
|
||||
GFrameDesc desc;
|
||||
const Surface::info_t& info = parent_surface_ptr->get_info();
|
||||
switch(info.FourCC)
|
||||
{
|
||||
case MFX_FOURCC_I420:
|
||||
throw std::runtime_error("MediaFrame doesn't support I420 type");
|
||||
break;
|
||||
case MFX_FOURCC_NV12:
|
||||
desc.fmt = MediaFormat::NV12;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("MediaFrame unknown 'fmt' type: " + std::to_string(info.FourCC));
|
||||
}
|
||||
|
||||
desc.size = cv::Size{info.Width, info.Height};
|
||||
return desc;
|
||||
}
|
||||
|
||||
MediaFrame::View VPLMediaFrameCPUAdapter::access(MediaFrame::Access) {
|
||||
const Surface::data_t& data = parent_surface_ptr->get_data();
|
||||
const Surface::info_t& info = parent_surface_ptr->get_info();
|
||||
using stride_t = typename cv::MediaFrame::View::Strides::value_type;
|
||||
|
||||
stride_t pitch = static_cast<stride_t>(data.Pitch);
|
||||
switch(info.FourCC) {
|
||||
case MFX_FOURCC_I420:
|
||||
{
|
||||
cv::MediaFrame::View::Ptrs pp = {
|
||||
data.Y,
|
||||
data.U,
|
||||
data.V,
|
||||
nullptr
|
||||
};
|
||||
cv::MediaFrame::View::Strides ss = {
|
||||
pitch,
|
||||
pitch / 2,
|
||||
pitch / 2, 0u
|
||||
};
|
||||
return cv::MediaFrame::View(std::move(pp), std::move(ss));
|
||||
}
|
||||
case MFX_FOURCC_NV12:
|
||||
{
|
||||
cv::MediaFrame::View::Ptrs pp = {
|
||||
data.Y,
|
||||
data.UV, nullptr, nullptr
|
||||
};
|
||||
cv::MediaFrame::View::Strides ss = {
|
||||
pitch,
|
||||
pitch, 0u, 0u
|
||||
};
|
||||
return cv::MediaFrame::View(std::move(pp), std::move(ss));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("MediaFrame unknown 'fmt' type: " + std::to_string(info.FourCC));
|
||||
}
|
||||
}
|
||||
|
||||
cv::util::any VPLMediaFrameCPUAdapter::blobParams() const {
|
||||
GAPI_Assert("VPLMediaFrameCPUAdapter::blobParams() is not implemented");
|
||||
return {};
|
||||
}
|
||||
|
||||
void VPLMediaFrameCPUAdapter::serialize(cv::gapi::s11n::IOStream&) {
|
||||
GAPI_Assert("VPLMediaFrameCPUAdapter::serialize() is not implemented");
|
||||
}
|
||||
|
||||
void VPLMediaFrameCPUAdapter::deserialize(cv::gapi::s11n::IIStream&) {
|
||||
GAPI_Assert("VPLMediaFrameCPUAdapter::deserialize() is not implemented");
|
||||
}
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
#endif // HAVE_ONEVPL
|
||||
@@ -0,0 +1,43 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
|
||||
#ifndef GAPI_STREAMING_ONEVPL_ACCELERATORS_SURFACE_CPU_FRAME_ADAPTER_HPP
|
||||
#define GAPI_STREAMING_ONEVPL_ACCELERATORS_SURFACE_CPU_FRAME_ADAPTER_HPP
|
||||
#include <memory>
|
||||
|
||||
#include <opencv2/gapi/media.hpp>
|
||||
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
|
||||
class Surface;
|
||||
class VPLMediaFrameCPUAdapter : public cv::MediaFrame::IAdapter {
|
||||
public:
|
||||
// GAPI_EXPORTS for tests
|
||||
GAPI_EXPORTS explicit VPLMediaFrameCPUAdapter(std::shared_ptr<Surface> assoc_surface);
|
||||
GAPI_EXPORTS ~VPLMediaFrameCPUAdapter();
|
||||
cv::GFrameDesc meta() const override;
|
||||
MediaFrame::View access(MediaFrame::Access) override;
|
||||
|
||||
// The default implementation does nothing
|
||||
cv::util::any blobParams() const override;
|
||||
void serialize(cv::gapi::s11n::IOStream&) override;
|
||||
void deserialize(cv::gapi::s11n::IIStream&) override;
|
||||
private:
|
||||
std::shared_ptr<Surface> parent_surface_ptr;
|
||||
};
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // HAVE_ONEVPL
|
||||
#endif // GAPI_STREAMING_ONEVPL_ACCELERATORS_SURFACE_CPU_FRAME_ADAPTER_HPP
|
||||
@@ -0,0 +1,78 @@
|
||||
// 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
|
||||
|
||||
#include "streaming/onevpl/accelerators/surface/surface.hpp"
|
||||
#include "logger.hpp"
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
|
||||
Surface::Surface(std::unique_ptr<handle_t>&& surf, std::shared_ptr<void> associated_memory) :
|
||||
workspace_memory_ptr(associated_memory),
|
||||
mfx_surface(std::move(surf)),
|
||||
mirrored_locked_count() {
|
||||
|
||||
GAPI_Assert(mfx_surface && "Surface is nullptr");
|
||||
mirrored_locked_count.store(mfx_surface->Data.Locked);
|
||||
GAPI_LOG_DEBUG(nullptr, "create surface: " << mfx_surface <<
|
||||
", locked count: " << mfx_surface->Data.Locked);
|
||||
}
|
||||
|
||||
Surface::~Surface() {
|
||||
GAPI_LOG_DEBUG(nullptr, "destroy surface: " << mfx_surface <<
|
||||
", worspace memory counter: " << workspace_memory_ptr.use_count());
|
||||
}
|
||||
|
||||
std::shared_ptr<Surface> Surface::create_surface(std::unique_ptr<handle_t>&& surf,
|
||||
std::shared_ptr<void> accociated_memory) {
|
||||
surface_ptr_t ret {new Surface(std::move(surf), accociated_memory)};
|
||||
return ret;
|
||||
}
|
||||
|
||||
Surface::handle_t* Surface::get_handle() const {
|
||||
return mfx_surface.get();
|
||||
}
|
||||
|
||||
const Surface::info_t& Surface::get_info() const {
|
||||
return mfx_surface->Info;
|
||||
}
|
||||
|
||||
const Surface::data_t& Surface::get_data() const {
|
||||
return mfx_surface->Data;
|
||||
}
|
||||
|
||||
size_t Surface::get_locks_count() const {
|
||||
return mirrored_locked_count.load();
|
||||
}
|
||||
|
||||
size_t Surface::obtain_lock() {
|
||||
size_t locked_count = mirrored_locked_count.fetch_add(1);
|
||||
GAPI_Assert(locked_count < std::numeric_limits<mfxU16>::max() && "Too many references ");
|
||||
mfx_surface->Data.Locked = static_cast<mfxU16>(locked_count + 1);
|
||||
GAPI_LOG_DEBUG(nullptr, "surface: " << mfx_surface.get() <<
|
||||
", locked times: " << locked_count + 1);
|
||||
return locked_count; // return preceding value
|
||||
}
|
||||
|
||||
size_t Surface::release_lock() {
|
||||
size_t locked_count = mirrored_locked_count.fetch_sub(1);
|
||||
GAPI_Assert(locked_count < std::numeric_limits<mfxU16>::max() && "Too many references ");
|
||||
GAPI_Assert(locked_count && "Surface lock counter is invalid");
|
||||
mfx_surface->Data.Locked = static_cast<mfxU16>(locked_count - 1);
|
||||
GAPI_LOG_DEBUG(nullptr, "surface: " << mfx_surface.get() <<
|
||||
", locked times: " << locked_count - 1);
|
||||
return locked_count; // return preceding value
|
||||
}
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // HAVE_ONEVPL
|
||||
@@ -0,0 +1,104 @@
|
||||
// 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_ACCELERATORS_SURFACE_HPP
|
||||
#define GAPI_STREAMING_ONEVPL_ACCELERATORS_SURFACE_HPP
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
#if (MFX_VERSION >= 2000)
|
||||
#include <vpl/mfxdispatcher.h>
|
||||
#endif
|
||||
|
||||
#include <vpl/mfx.h>
|
||||
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
|
||||
/**
|
||||
* @brief Inner class for managing oneVPL surface through interface `mfxFrameSurface1`.
|
||||
*
|
||||
* Surface has no own memory and shares accelerator allocated memory using reference counter semantics.
|
||||
* So it lives till a last memory consumer (surface/accelerator/media frame) lives.
|
||||
* This approach allows to support different scenarious in releasing allocated memory
|
||||
*
|
||||
* VPL surface `mfxFrameSurface1` support Lock-Free semantics and application MUST NOT operate with a
|
||||
* surface in locked state. But VPL inner counter is not threadsafe so it would be failed in any concurrent scenario.
|
||||
* std::atomic counter introduced in a way to overcome this problem.
|
||||
* But only few scenarious for concurrency are supported here because it is not assumed to implement entire Surface in
|
||||
* for a fully multithread approach.
|
||||
* Supported concurrency scenarios deal only with transaction pair: @ref Surface::get_locks_count() against
|
||||
* @ref Surface::release_lock() - which may be called from different threads. On the other hand @ref Surface::get_locks_count() against
|
||||
* @ref Surface::obtain_lock() happens in single thread only. Surface doesn't support shared ownership that
|
||||
* because it doesn't require thread safe guarantee between transactions:
|
||||
* - @ref Surface::obtain_lock() against @ref Surface::obtain_lock()
|
||||
* - @ref Surface::obtain_lock() against @ref Surface::release_lock()
|
||||
* - @ref Surface::release_lock() against @ref Surface::release_lock()
|
||||
*/
|
||||
class Surface {
|
||||
using handle_t = mfxFrameSurface1;
|
||||
|
||||
std::shared_ptr<void> workspace_memory_ptr;
|
||||
std::unique_ptr<handle_t> mfx_surface;
|
||||
std::atomic<size_t> mirrored_locked_count;
|
||||
public:
|
||||
using info_t = mfxFrameInfo;
|
||||
using data_t = mfxFrameData;
|
||||
|
||||
// GAPI_EXPORTS for tests
|
||||
GAPI_EXPORTS static std::shared_ptr<Surface> create_surface(std::unique_ptr<handle_t>&& surf,
|
||||
std::shared_ptr<void> accociated_memory);
|
||||
GAPI_EXPORTS ~Surface();
|
||||
|
||||
GAPI_EXPORTS handle_t* get_handle() const;
|
||||
GAPI_EXPORTS const info_t& get_info() const;
|
||||
GAPI_EXPORTS const data_t& get_data() const;
|
||||
|
||||
/**
|
||||
* Extract value thread-safe lock counter (see @ref Surface description).
|
||||
* It's usual situation that counter may be instantly decreased in other thread after this method called.
|
||||
* We need instantaneous value. This method syncronized in inter-threading way with @ref Surface::release_lock()
|
||||
*
|
||||
* @return fetched locks count.
|
||||
*/
|
||||
GAPI_EXPORTS size_t get_locks_count() const;
|
||||
|
||||
/**
|
||||
* Atomically increase value of thread-safe lock counter (see @ref Surface description).
|
||||
* This method is single-threaded happens-after @ref Surface::get_locks_count() and
|
||||
* multi-threaded happens-before @ref Surface::release_lock()
|
||||
*
|
||||
* @return locks count just before its increasing.
|
||||
*/
|
||||
GAPI_EXPORTS size_t obtain_lock();
|
||||
|
||||
/**
|
||||
* Atomically decrease value of thread-safe lock counter (see @ref Surface description).
|
||||
* This method is synchronized with @ref Surface::get_locks_count() and
|
||||
* multi-threaded happens-after @ref Surface::obtain_lock()
|
||||
*
|
||||
* @return locks count just before its decreasing.
|
||||
*/
|
||||
GAPI_EXPORTS size_t release_lock();
|
||||
private:
|
||||
Surface(std::unique_ptr<handle_t>&& surf, std::shared_ptr<void> accociated_memory);
|
||||
};
|
||||
|
||||
using surface_ptr_t = std::shared_ptr<Surface>;
|
||||
using surface_weak_ptr_t = std::weak_ptr<Surface>;
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
#endif // HAVE_ONEVPL
|
||||
#endif // GAPI_STREAMING_ONEVPL_ACCELERATORS_SURFACE_HPP
|
||||
@@ -0,0 +1,71 @@
|
||||
#include "streaming/onevpl/accelerators/surface/surface_pool.hpp"
|
||||
#include "streaming/onevpl/accelerators/surface/surface.hpp"
|
||||
#include "logger.hpp"
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
|
||||
void CachedPool::reserve(size_t size) {
|
||||
surfaces.reserve(size);
|
||||
}
|
||||
|
||||
size_t CachedPool::size() const {
|
||||
return surfaces.size();
|
||||
}
|
||||
|
||||
void CachedPool::clear() {
|
||||
surfaces.clear();
|
||||
next_free_it = surfaces.begin();
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
void CachedPool::push_back(surface_ptr_t &&surf) {
|
||||
cache.insert(std::make_pair(surf->get_handle(), surf));
|
||||
surfaces.push_back(std::move(surf));
|
||||
next_free_it = surfaces.begin();
|
||||
}
|
||||
|
||||
CachedPool::surface_ptr_t CachedPool::find_free() {
|
||||
auto it =
|
||||
std::find_if(next_free_it, surfaces.end(),
|
||||
[](const surface_ptr_t& val) {
|
||||
GAPI_DbgAssert(val && "Pool contains empty surface");
|
||||
return !val->get_locks_count();
|
||||
});
|
||||
|
||||
// Limitation realloc pool might be a future extension
|
||||
if (it == surfaces.end()) {
|
||||
it = std::find_if(surfaces.begin(), next_free_it,
|
||||
[](const surface_ptr_t& val) {
|
||||
GAPI_DbgAssert(val && "Pool contains empty surface");
|
||||
return !val->get_locks_count();
|
||||
});
|
||||
if (it == next_free_it) {
|
||||
std::stringstream ss;
|
||||
ss << "cannot get free surface from pool, size: " << surfaces.size();
|
||||
const std::string& str = ss.str();
|
||||
GAPI_LOG_WARNING(nullptr, str);
|
||||
throw std::runtime_error(std::string(__FUNCTION__) + " - " + str);
|
||||
}
|
||||
}
|
||||
|
||||
next_free_it = it;
|
||||
++next_free_it;
|
||||
|
||||
return *it;
|
||||
}
|
||||
|
||||
CachedPool::surface_ptr_t CachedPool::find_by_handle(mfxFrameSurface1* handle) {
|
||||
auto it = cache.find(handle);
|
||||
GAPI_Assert(it != cache.end() && "Cannot find cached surface from pool. Data corruption is possible");
|
||||
return it->second;
|
||||
}
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
#endif // HAVE_ONEVPL
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef GAPI_STREAMING_ONEVPL_SURFACE_SURFACE_POOL_HPP
|
||||
#define GAPI_STREAMING_ONEVPL_SURFACE_SURFACE_POOL_HPP
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
#if (MFX_VERSION >= 2000)
|
||||
#include <vpl/mfxdispatcher.h>
|
||||
#endif
|
||||
|
||||
#include <vpl/mfx.h>
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
|
||||
class Surface;
|
||||
// GAPI_EXPORTS for tests
|
||||
class GAPI_EXPORTS CachedPool {
|
||||
public:
|
||||
using surface_ptr_t = std::shared_ptr<Surface>;
|
||||
using surface_container_t = std::vector<surface_ptr_t>;
|
||||
using free_surface_iterator_t = typename surface_container_t::iterator;
|
||||
using cached_surface_container_t = std::map<mfxFrameSurface1*, surface_ptr_t>;
|
||||
|
||||
void push_back(surface_ptr_t &&surf);
|
||||
void reserve(size_t size);
|
||||
size_t size() const;
|
||||
void clear();
|
||||
surface_ptr_t find_free();
|
||||
surface_ptr_t find_by_handle(mfxFrameSurface1* handle);
|
||||
private:
|
||||
surface_container_t surfaces;
|
||||
free_surface_iterator_t next_free_it;
|
||||
cached_surface_container_t cache;
|
||||
};
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
#endif // HAVE_ONEVPL
|
||||
#endif // GAPI_STREAMING_ONEVPL_SURFACE_SURFACE_POOL_HPP
|
||||
@@ -0,0 +1,137 @@
|
||||
// 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
|
||||
|
||||
#include <opencv2/gapi/util/throw.hpp>
|
||||
|
||||
#include <opencv2/gapi/streaming/onevpl/cfg_params.hpp>
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
|
||||
namespace util {
|
||||
struct variant_comparator : cv::util::static_visitor<bool, variant_comparator> {
|
||||
variant_comparator(const CfgParam::value_t& rhs_value) :
|
||||
rhs(rhs_value) {}
|
||||
|
||||
template<typename ValueType>
|
||||
bool visit(const ValueType& lhs) const {
|
||||
return lhs < cv::util::get<ValueType>(rhs);
|
||||
}
|
||||
private:
|
||||
const CfgParam::value_t& rhs;
|
||||
};
|
||||
} // namespace util
|
||||
|
||||
struct CfgParam::Priv {
|
||||
Priv(const std::string& param_name, CfgParam::value_t&& param_value, bool is_major_param) :
|
||||
name(param_name), value(std::forward<value_t>(param_value)), major_flag(is_major_param) {
|
||||
}
|
||||
|
||||
const CfgParam::name_t& get_name_impl() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
const CfgParam::value_t& get_value_impl() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
bool is_major_impl() const {
|
||||
return major_flag;
|
||||
}
|
||||
|
||||
// comparison implementation
|
||||
bool operator< (const Priv& rhs) const {
|
||||
// implement default pair comparison
|
||||
if (get_name_impl() < rhs.get_name_impl()) {
|
||||
return true;
|
||||
} else if (get_name_impl() > rhs.get_name_impl()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//TODO implement operator < for cv::util::variant
|
||||
const CfgParam::value_t& lvar = get_value_impl();
|
||||
const CfgParam::value_t& rvar = rhs.get_value_impl();
|
||||
if (lvar.index() < rvar.index()) {
|
||||
return true;
|
||||
} else if (lvar.index() > rvar.index()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
util::variant_comparator comp(rvar);
|
||||
return cv::util::visit(comp, lvar);
|
||||
}
|
||||
|
||||
bool operator==(const Priv& rhs) const {
|
||||
return (get_name_impl() == rhs.get_name_impl())
|
||||
&& (get_value_impl() == rhs.get_value_impl());
|
||||
}
|
||||
|
||||
bool operator!=(const Priv& rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
CfgParam::name_t name;
|
||||
CfgParam::value_t value;
|
||||
bool major_flag;
|
||||
};
|
||||
|
||||
CfgParam::CfgParam (const std::string& param_name, value_t&& param_value, bool is_major_param) :
|
||||
m_priv(new Priv(param_name, std::move(param_value), is_major_param)) {
|
||||
}
|
||||
|
||||
CfgParam::~CfgParam() = default;
|
||||
|
||||
CfgParam& CfgParam::operator=(const CfgParam& src) {
|
||||
if (this != &src) {
|
||||
m_priv = src.m_priv;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CfgParam& CfgParam::operator=(CfgParam&& src) {
|
||||
if (this != &src) {
|
||||
m_priv = std::move(src.m_priv);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CfgParam::CfgParam(const CfgParam& src) :
|
||||
m_priv(src.m_priv) {
|
||||
}
|
||||
|
||||
CfgParam::CfgParam(CfgParam&& src) :
|
||||
m_priv(std::move(src.m_priv)) {
|
||||
}
|
||||
|
||||
const CfgParam::name_t& CfgParam::get_name() const {
|
||||
return m_priv->get_name_impl();
|
||||
}
|
||||
|
||||
const CfgParam::value_t& CfgParam::get_value() const {
|
||||
return m_priv->get_value_impl();
|
||||
}
|
||||
|
||||
bool CfgParam::is_major() const {
|
||||
return m_priv->is_major_impl();
|
||||
}
|
||||
|
||||
bool CfgParam::operator< (const CfgParam& rhs) const {
|
||||
return *m_priv < *rhs.m_priv;
|
||||
}
|
||||
|
||||
bool CfgParam::operator==(const CfgParam& rhs) const {
|
||||
return *m_priv == *rhs.m_priv;
|
||||
}
|
||||
|
||||
bool CfgParam::operator!=(const CfgParam& rhs) const {
|
||||
return *m_priv != *rhs.m_priv;
|
||||
}
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
@@ -0,0 +1,22 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <opencv2/gapi/streaming/onevpl/data_provider_interface.hpp>
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
DataProviderSystemErrorException::DataProviderSystemErrorException(int error_code, const std::string& desription) {
|
||||
reason = desription + ", error: " + std::to_string(error_code) + ", desctiption: " + strerror(error_code);
|
||||
}
|
||||
|
||||
DataProviderSystemErrorException::~DataProviderSystemErrorException() = default;
|
||||
|
||||
const char* DataProviderSystemErrorException::what() const noexcept {
|
||||
return reason.c_str();
|
||||
}
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
@@ -0,0 +1,310 @@
|
||||
// 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 <algorithm>
|
||||
#include <exception>
|
||||
|
||||
#include <opencv2/gapi/streaming/onevpl/data_provider_interface.hpp>
|
||||
|
||||
#include "streaming/onevpl/engine/decode/decode_engine_legacy.hpp"
|
||||
#include "streaming/onevpl/engine/decode/decode_session.hpp"
|
||||
#include "streaming/onevpl/accelerators/accel_policy_interface.hpp"
|
||||
#include "streaming/onevpl/accelerators/surface/surface.hpp"
|
||||
#include "streaming/onevpl/utils.hpp"
|
||||
#include "logger.hpp"
|
||||
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
/* UTILS */
|
||||
mfxU32 GetSurfaceSize(mfxU32 FourCC, mfxU32 width, mfxU32 height) {
|
||||
mfxU32 nbytes = 0;
|
||||
|
||||
mfxU32 half_width = width / 2;
|
||||
mfxU32 half_height = height / 2;
|
||||
switch (FourCC) {
|
||||
case MFX_FOURCC_I420:
|
||||
case MFX_FOURCC_NV12:
|
||||
nbytes = width * height + 2 * half_width * half_height;
|
||||
break;
|
||||
case MFX_FOURCC_I010:
|
||||
case MFX_FOURCC_P010:
|
||||
nbytes = width * height + 2 * half_width * half_height;
|
||||
nbytes *= 2;
|
||||
break;
|
||||
case MFX_FOURCC_RGB4:
|
||||
nbytes = width * height * 4;
|
||||
break;
|
||||
default:
|
||||
GAPI_LOG_WARNING(nullptr, "Unsupported FourCC requested: " << FourCC);
|
||||
GAPI_Assert(false && "Unsupported FourCC requested");
|
||||
break;
|
||||
}
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
surface_ptr_t create_surface_RGB4(mfxFrameInfo frameInfo,
|
||||
std::shared_ptr<void> out_buf_ptr,
|
||||
size_t out_buf_ptr_offset,
|
||||
size_t out_buf_size)
|
||||
{
|
||||
mfxU8* buf = reinterpret_cast<mfxU8*>(out_buf_ptr.get());
|
||||
mfxU16 surfW = frameInfo.Width * 4;
|
||||
mfxU16 surfH = frameInfo.Height;
|
||||
(void)surfH;
|
||||
|
||||
// TODO more intelligent check
|
||||
if (out_buf_size <= out_buf_ptr_offset) {
|
||||
throw std::runtime_error(std::string("Insufficient buffer size: ") +
|
||||
std::to_string(out_buf_size) + ", buffer offset: " +
|
||||
std::to_string(out_buf_ptr_offset) +
|
||||
", expected surface width: " + std::to_string(surfW) +
|
||||
", height: " + std::to_string(surfH));
|
||||
}
|
||||
|
||||
std::unique_ptr<mfxFrameSurface1> handle(new mfxFrameSurface1);
|
||||
memset(handle.get(), 0, sizeof(mfxFrameSurface1));
|
||||
|
||||
handle->Info = frameInfo;
|
||||
handle->Data.B = buf + out_buf_ptr_offset;
|
||||
handle->Data.G = handle->Data.B + 1;
|
||||
handle->Data.R = handle->Data.B + 2;
|
||||
handle->Data.A = handle->Data.B + 3;
|
||||
handle->Data.Pitch = surfW;
|
||||
|
||||
return Surface::create_surface(std::move(handle), out_buf_ptr);
|
||||
}
|
||||
|
||||
surface_ptr_t create_surface_other(mfxFrameInfo frameInfo,
|
||||
std::shared_ptr<void> out_buf_ptr,
|
||||
size_t out_buf_ptr_offset,
|
||||
size_t out_buf_size)
|
||||
{
|
||||
mfxU8* buf = reinterpret_cast<mfxU8*>(out_buf_ptr.get());
|
||||
mfxU16 surfH = frameInfo.Height;
|
||||
mfxU16 surfW = (frameInfo.FourCC == MFX_FOURCC_P010) ? frameInfo.Width * 2 : frameInfo.Width;
|
||||
|
||||
// TODO more intelligent check
|
||||
if (out_buf_size <=
|
||||
out_buf_ptr_offset + (surfW * surfH) + ((surfW / 2) * (surfH / 2))) {
|
||||
throw std::runtime_error(std::string("Insufficient buffer size: ") +
|
||||
std::to_string(out_buf_size) + ", buffer offset: " +
|
||||
std::to_string(out_buf_ptr_offset) +
|
||||
", expected surface width: " + std::to_string(surfW) +
|
||||
", height: " + std::to_string(surfH));
|
||||
}
|
||||
|
||||
std::unique_ptr<mfxFrameSurface1> handle(new mfxFrameSurface1);
|
||||
memset(handle.get(), 0, sizeof(mfxFrameSurface1));
|
||||
|
||||
handle->Info = frameInfo;
|
||||
handle->Data.Y = buf + out_buf_ptr_offset;
|
||||
handle->Data.U = buf + out_buf_ptr_offset + (surfW * surfH);
|
||||
handle->Data.V = handle->Data.U + ((surfW / 2) * (surfH / 2));
|
||||
handle->Data.Pitch = surfW;
|
||||
|
||||
return Surface::create_surface(std::move(handle), out_buf_ptr);
|
||||
}
|
||||
|
||||
VPLLegacyDecodeEngine::VPLLegacyDecodeEngine(std::unique_ptr<VPLAccelerationPolicy>&& accel)
|
||||
: ProcessingEngineBase(std::move(accel)) {
|
||||
|
||||
GAPI_LOG_INFO(nullptr, "Create Legacy Decode Engine");
|
||||
create_pipeline(
|
||||
// 1) Read File
|
||||
[this] (EngineSession& sess) -> ExecutionStatus
|
||||
{
|
||||
LegacyDecodeSession &my_sess = static_cast<LegacyDecodeSession&>(sess);
|
||||
my_sess.last_status = ReadEncodedStream(my_sess.stream, my_sess.data_provider);
|
||||
if (my_sess.last_status != MFX_ERR_NONE) {
|
||||
my_sess.data_provider.reset(); //close source
|
||||
}
|
||||
return ExecutionStatus::Continue;
|
||||
},
|
||||
// 2) enqueue ASYNC decode
|
||||
[this] (EngineSession& sess) -> ExecutionStatus
|
||||
{
|
||||
LegacyDecodeSession &my_sess = static_cast<LegacyDecodeSession&>(sess);
|
||||
|
||||
my_sess.last_status =
|
||||
MFXVideoDECODE_DecodeFrameAsync(my_sess.session,
|
||||
my_sess.last_status == MFX_ERR_NONE
|
||||
? &my_sess.stream
|
||||
: nullptr, /* No more data to read, start decode draining mode*/
|
||||
my_sess.procesing_surface_ptr.lock()->get_handle(),
|
||||
&my_sess.output_surface_ptr,
|
||||
&my_sess.sync);
|
||||
return ExecutionStatus::Continue;
|
||||
},
|
||||
// 3) Wait for ASYNC decode result
|
||||
[this] (EngineSession& sess) -> ExecutionStatus
|
||||
{
|
||||
if (sess.last_status == MFX_ERR_NONE) // Got 1 decoded frame
|
||||
{
|
||||
do {
|
||||
//TODO try to extract TIMESTAMP
|
||||
sess.last_status = MFXVideoCORE_SyncOperation(sess.session, sess.sync, 100);
|
||||
if (MFX_ERR_NONE == sess.last_status) {
|
||||
|
||||
LegacyDecodeSession& my_sess = static_cast<LegacyDecodeSession&>(sess);
|
||||
on_frame_ready(my_sess);
|
||||
}
|
||||
} while (sess.last_status == MFX_WRN_IN_EXECUTION);
|
||||
}
|
||||
return ExecutionStatus::Continue;
|
||||
},
|
||||
// 4) Falls back on generic status procesing
|
||||
[this] (EngineSession& sess) -> ExecutionStatus
|
||||
{
|
||||
return this->process_error(sess.last_status, static_cast<LegacyDecodeSession&>(sess));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void VPLLegacyDecodeEngine::initialize_session(mfxSession mfx_session,
|
||||
DecoderParams&& decoder_param,
|
||||
std::shared_ptr<onevpl::IDataProvider> provider)
|
||||
{
|
||||
mfxFrameAllocRequest decRequest = {};
|
||||
// Query number required surfaces for decoder
|
||||
MFXVideoDECODE_QueryIOSurf(mfx_session, &decoder_param.param, &decRequest);
|
||||
|
||||
// External (application) allocation of decode surfaces
|
||||
GAPI_LOG_DEBUG(nullptr, "Query IOSurf for session: " << mfx_session <<
|
||||
", mfxFrameAllocRequest.NumFrameSuggested: " << decRequest.NumFrameSuggested <<
|
||||
", mfxFrameAllocRequest.Type: " << decRequest.Type);
|
||||
|
||||
mfxU32 singleSurfaceSize = GetSurfaceSize(decoder_param.param.mfx.FrameInfo.FourCC,
|
||||
decoder_param.param.mfx.FrameInfo.Width,
|
||||
decoder_param.param.mfx.FrameInfo.Height);
|
||||
if (!singleSurfaceSize) {
|
||||
throw std::runtime_error("Cannot determine surface size for: fourCC" +
|
||||
std::to_string(decoder_param.param.mfx.FrameInfo.FourCC) +
|
||||
", width: " + std::to_string(decoder_param.param.mfx.FrameInfo.Width) +
|
||||
", height: " + std::to_string(decoder_param.param.mfx.FrameInfo.Height));
|
||||
}
|
||||
|
||||
const auto &frameInfo = decoder_param.param.mfx.FrameInfo;
|
||||
auto surface_creator =
|
||||
[&frameInfo] (std::shared_ptr<void> out_buf_ptr, size_t out_buf_ptr_offset,
|
||||
size_t out_buf_size) -> surface_ptr_t {
|
||||
return (frameInfo.FourCC == MFX_FOURCC_RGB4) ?
|
||||
create_surface_RGB4(frameInfo, out_buf_ptr, out_buf_ptr_offset,
|
||||
out_buf_size) :
|
||||
create_surface_other(frameInfo, out_buf_ptr, out_buf_ptr_offset,
|
||||
out_buf_size);};
|
||||
|
||||
//TODO Configure preallocation size (how many frames we can hold)
|
||||
const size_t preallocated_frames_count = 30;
|
||||
VPLAccelerationPolicy::pool_key_t decode_pool_key =
|
||||
acceleration_policy->create_surface_pool(decRequest.NumFrameSuggested * preallocated_frames_count,
|
||||
singleSurfaceSize,
|
||||
surface_creator);
|
||||
|
||||
// create session
|
||||
std::shared_ptr<LegacyDecodeSession> sess_ptr =
|
||||
register_session<LegacyDecodeSession>(mfx_session,
|
||||
std::move(decoder_param),
|
||||
provider);
|
||||
|
||||
sess_ptr->init_surface_pool(decode_pool_key);
|
||||
// prepare working decode surface
|
||||
sess_ptr->swap_surface(*this);
|
||||
}
|
||||
|
||||
ProcessingEngineBase::ExecutionStatus VPLLegacyDecodeEngine::execute_op(operation_t& op, EngineSession& sess) {
|
||||
return op(sess);
|
||||
}
|
||||
|
||||
void VPLLegacyDecodeEngine::on_frame_ready(LegacyDecodeSession& sess)
|
||||
{
|
||||
GAPI_LOG_DEBUG(nullptr, "[" << sess.session << "], frame ready");
|
||||
|
||||
// manage memory ownership rely on acceleration policy
|
||||
auto frame_adapter = acceleration_policy->create_frame_adapter(sess.decoder_pool_id,
|
||||
sess.output_surface_ptr);
|
||||
ready_frames.emplace(cv::MediaFrame(std::move(frame_adapter)), sess.generate_frame_meta());
|
||||
}
|
||||
|
||||
ProcessingEngineBase::ExecutionStatus VPLLegacyDecodeEngine::process_error(mfxStatus status, LegacyDecodeSession& sess)
|
||||
{
|
||||
GAPI_LOG_DEBUG(nullptr, "status: " << mfxstatus_to_string(status));
|
||||
|
||||
switch (status) {
|
||||
case MFX_ERR_NONE:
|
||||
return ExecutionStatus::Continue;
|
||||
case MFX_ERR_MORE_DATA: // The function requires more bitstream at input before decoding can proceed
|
||||
if (!sess.data_provider || sess.data_provider->empty()) {
|
||||
// No more data to drain from decoder, start encode draining mode
|
||||
return ExecutionStatus::Processed;
|
||||
}
|
||||
else
|
||||
return ExecutionStatus::Continue; // read more data
|
||||
break;
|
||||
case MFX_ERR_MORE_SURFACE:
|
||||
{
|
||||
// The function requires more frame surface at output before decoding can proceed.
|
||||
// This applies to external memory allocations and should not be expected for
|
||||
// a simple internal allocation case like this
|
||||
try {
|
||||
sess.swap_surface(*this);
|
||||
return ExecutionStatus::Continue;
|
||||
} catch (const std::exception& ex) {
|
||||
GAPI_LOG_WARNING(nullptr, "[" << sess.session << "] error: " << ex.what());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MFX_ERR_DEVICE_LOST:
|
||||
// For non-CPU implementations,
|
||||
// Cleanup if device is lost
|
||||
GAPI_DbgAssert(false && "VPLLegacyDecodeEngine::process_error - "
|
||||
"MFX_ERR_DEVICE_LOST is not processed");
|
||||
break;
|
||||
case MFX_WRN_DEVICE_BUSY:
|
||||
// For non-CPU implementations,
|
||||
// Wait a few milliseconds then try again
|
||||
GAPI_DbgAssert(false && "VPLLegacyDecodeEngine::process_error - "
|
||||
"MFX_WRN_DEVICE_BUSY is not processed");
|
||||
break;
|
||||
case MFX_WRN_VIDEO_PARAM_CHANGED:
|
||||
// The decoder detected a new sequence header in the bitstream.
|
||||
// Video parameters may have changed.
|
||||
// In external memory allocation case, might need to reallocate the output surface
|
||||
GAPI_DbgAssert(false && "VPLLegacyDecodeEngine::process_error - "
|
||||
"MFX_WRN_VIDEO_PARAM_CHANGED is not processed");
|
||||
break;
|
||||
case MFX_ERR_INCOMPATIBLE_VIDEO_PARAM:
|
||||
// The function detected that video parameters provided by the application
|
||||
// are incompatible with initialization parameters.
|
||||
// The application should close the component and then reinitialize it
|
||||
GAPI_DbgAssert(false && "VPLLegacyDecodeEngine::process_error - "
|
||||
"MFX_ERR_INCOMPATIBLE_VIDEO_PARAM is not processed");
|
||||
break;
|
||||
case MFX_ERR_REALLOC_SURFACE:
|
||||
// Bigger surface_work required. May be returned only if
|
||||
// mfxInfoMFX::EnableReallocRequest was set to ON during initialization.
|
||||
// This applies to external memory allocations and should not be expected for
|
||||
// a simple internal allocation case like this
|
||||
GAPI_DbgAssert(false && "VPLLegacyDecodeEngine::process_error - "
|
||||
"MFX_ERR_REALLOC_SURFACE is not processed");
|
||||
break;
|
||||
default:
|
||||
GAPI_LOG_WARNING(nullptr, "Unknown status code: " << mfxstatus_to_string(status));
|
||||
break;
|
||||
}
|
||||
|
||||
return ExecutionStatus::Failed;
|
||||
}
|
||||
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
#endif // HAVE_ONEVPL
|
||||
@@ -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 GAPI_STREAMING_ONVPL_DECODE_ENGINE_LEGACY_HPP
|
||||
#define GAPI_STREAMING_ONVPL_DECODE_ENGINE_LEGACY_HPP
|
||||
#include <stdio.h>
|
||||
#include <memory>
|
||||
|
||||
#include "streaming/onevpl/engine/processing_engine_base.hpp"
|
||||
|
||||
#ifdef HAVE_ONEVPL
|
||||
#if (MFX_VERSION >= 2000)
|
||||
#include <vpl/mfxdispatcher.h>
|
||||
#endif
|
||||
#include <vpl/mfx.h>
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace wip {
|
||||
namespace onevpl {
|
||||
|
||||
class LegacyDecodeSession;
|
||||
struct DecoderParams;
|
||||
struct IDataProvider;
|
||||
struct VPLAccelerationPolicy;
|
||||
|
||||
class VPLLegacyDecodeEngine : public ProcessingEngineBase {
|
||||
public:
|
||||
|
||||
VPLLegacyDecodeEngine(std::unique_ptr<VPLAccelerationPolicy>&& accel);
|
||||
void initialize_session(mfxSession mfx_session, DecoderParams&& decoder_param,
|
||||
std::shared_ptr<IDataProvider> provider) override;
|
||||
|
||||
private:
|
||||
ExecutionStatus execute_op(operation_t& op, EngineSession& sess) override;
|
||||
ExecutionStatus process_error(mfxStatus status, LegacyDecodeSession& sess);
|
||||
|
||||
void on_frame_ready(LegacyDecodeSession& sess);
|
||||
};
|
||||
} // namespace onevpl
|
||||
} // namespace wip
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
#endif // HAVE_ONEVPL
|
||||
#endif // GAPI_STREAMING_ONVPL_DECODE_ENGINE_LEGACY_HPP
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user