mirror of
https://github.com/opencv/opencv.git
synced 2026-07-30 07:43:03 +04:00
Merge branch 4.x
This commit is contained in:
@@ -156,6 +156,10 @@ set(gapi_srcs
|
||||
src/backends/ie/giebackend.cpp
|
||||
src/backends/ie/giebackend/giewrapper.cpp
|
||||
|
||||
# OV Backend. FIXME: should be included by CMake
|
||||
# if and only if OV support is enabled
|
||||
src/backends/ov/govbackend.cpp
|
||||
|
||||
# ONNX backend
|
||||
src/backends/onnx/gonnxbackend.cpp
|
||||
|
||||
@@ -182,6 +186,7 @@ set(gapi_srcs
|
||||
# Python bridge
|
||||
src/backends/ie/bindings_ie.cpp
|
||||
src/backends/onnx/bindings_onnx.cpp
|
||||
src/backends/ov/bindings_ov.cpp
|
||||
src/backends/python/gpythonbackend.cpp
|
||||
|
||||
# OpenVPL Streaming source
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
// 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) 2023 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_INFER_BINDINGS_OV_HPP
|
||||
#define OPENCV_GAPI_INFER_BINDINGS_OV_HPP
|
||||
|
||||
#include <opencv2/gapi/util/any.hpp>
|
||||
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
|
||||
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
|
||||
#include <opencv2/gapi/infer/ov.hpp> // Params
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace ov {
|
||||
|
||||
// NB: Used by python wrapper
|
||||
// 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_path,
|
||||
const std::string &bin_path,
|
||||
const std::string &device);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams(const std::string &tag,
|
||||
const std::string &blob_path,
|
||||
const std::string &device);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgPluginConfig(
|
||||
const std::map<std::string, std::string> &config);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgInputTensorLayout(std::string tensor_layout);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgInputTensorLayout(
|
||||
std::map<std::string, std::string> layout_map);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgInputModelLayout(std::string tensor_layout);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgInputModelLayout(
|
||||
std::map<std::string, std::string> layout_map);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgOutputTensorLayout(std::string tensor_layout);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgOutputTensorLayout(
|
||||
std::map<std::string, std::string> layout_map);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgOutputModelLayout(std::string tensor_layout);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgOutputModelLayout(
|
||||
std::map<std::string, std::string> layout_map);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgOutputTensorPrecision(int precision);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgOutputTensorPrecision(
|
||||
std::map<std::string, int> precision_map);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgReshape(std::vector<size_t> new_shape);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgReshape(
|
||||
std::map<std::string, std::vector<size_t>> new_shape_map);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgNumRequests(const size_t nireq);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgMean(std::vector<float> mean_values);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgMean(
|
||||
std::map<std::string, std::vector<float>> mean_map);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgScale(std::vector<float> scale_values);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgScale(
|
||||
std::map<std::string, std::vector<float>> scale_map);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgResize(int interpolation);
|
||||
|
||||
GAPI_WRAP
|
||||
PyParams& cfgResize(std::map<std::string, int> interpolation);
|
||||
|
||||
GBackend backend() const;
|
||||
std::string tag() const;
|
||||
cv::util::any params() const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Params<cv::gapi::Generic>> m_priv;
|
||||
};
|
||||
|
||||
GAPI_EXPORTS_W PyParams params(const std::string &tag,
|
||||
const std::string &model_path,
|
||||
const std::string &weights,
|
||||
const std::string &device);
|
||||
|
||||
GAPI_EXPORTS_W PyParams params(const std::string &tag,
|
||||
const std::string &bin_path,
|
||||
const std::string &device);
|
||||
} // namespace ov
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_INFER_BINDINGS_OV_HPP
|
||||
@@ -2,7 +2,7 @@
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2019-2021 Intel Corporation
|
||||
// Copyright (C) 2019-2023 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_INFER_IE_HPP
|
||||
#define OPENCV_GAPI_INFER_IE_HPP
|
||||
@@ -55,6 +55,21 @@ using IEConfig = std::map<std::string, std::string>;
|
||||
enum InferMode {Sync, Async};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
using AttrMap = std::map<std::string, T>;
|
||||
// NB: This type is used to hold in/out layers
|
||||
// attributes such as precision, layout, shape etc.
|
||||
//
|
||||
// User can provide attributes either:
|
||||
// 1. cv::util::monostate - No value specified explicitly.
|
||||
// 2. Attr - value specified explicitly that should be broadcasted to all layers.
|
||||
// 3. AttrMap[str->T] - map specifies value for particular layer.
|
||||
template <typename Attr>
|
||||
using LayerVariantAttr = cv::util::variant< cv::util::monostate
|
||||
, AttrMap<Attr>
|
||||
, Attr>;
|
||||
|
||||
struct ParamDesc {
|
||||
std::string model_path;
|
||||
std::string weights_path;
|
||||
@@ -103,7 +118,11 @@ struct ParamDesc {
|
||||
using PrecisionVariantT = cv::util::variant<cv::util::monostate,
|
||||
PrecisionT,
|
||||
PrecisionMapT>;
|
||||
|
||||
PrecisionVariantT output_precision;
|
||||
LayerVariantAttr<std::string> input_layout;
|
||||
LayerVariantAttr<std::string> output_layout;
|
||||
LayerVariantAttr<int> interpolation;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
@@ -150,6 +169,9 @@ public:
|
||||
, {}
|
||||
, {}
|
||||
, InferMode::Async
|
||||
, {}
|
||||
, {}
|
||||
, {}
|
||||
, {} } {
|
||||
};
|
||||
|
||||
@@ -176,6 +198,9 @@ public:
|
||||
, {}
|
||||
, {}
|
||||
, InferMode::Async
|
||||
, {}
|
||||
, {}
|
||||
, {}
|
||||
, {} } {
|
||||
};
|
||||
|
||||
@@ -412,6 +437,80 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies the input layout for model.
|
||||
|
||||
The function is used to set an input layout for model.
|
||||
|
||||
@param layout Layout in string representation ("NCHW", "NHWC", etc)
|
||||
will be applied to all input layers.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgInputLayout(std::string layout) {
|
||||
desc.input_layout = std::move(layout);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
|
||||
@param layout_map Map of pairs: name of corresponding input layer
|
||||
and its layout in string representation ("NCHW", "NHWC", etc)
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>&
|
||||
cfgInputLayout(detail::AttrMap<std::string> layout_map) {
|
||||
desc.input_layout = std::move(layout_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies the output layout for model.
|
||||
|
||||
The function is used to set an output layout for model.
|
||||
|
||||
@param layout Layout in string representation ("NCHW", "NHWC", etc)
|
||||
will be applied to all output layers.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgOutputLayout(std::string layout) {
|
||||
desc.output_layout = std::move(layout);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
|
||||
@param layout_map Map of pairs: name of corresponding output layer
|
||||
and its layout in string representation ("NCHW", "NHWC", etc)
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>&
|
||||
cfgOutputLayout(detail::AttrMap<std::string> layout_map) {
|
||||
desc.output_layout = std::move(layout_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies resize interpolation algorithm.
|
||||
*
|
||||
The function is used to configure resize preprocessing for input layer.
|
||||
|
||||
@param interpolation Resize interpolation algorithm.
|
||||
Supported algorithms: #INTER_LINEAR, #INTER_AREA.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgResize(int interpolation) {
|
||||
desc.interpolation = interpolation;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
|
||||
@param interpolation Map of pairs: name of corresponding input layer
|
||||
and its resize algorithm.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgResize(detail::AttrMap<int> interpolation) {
|
||||
desc.interpolation = std::move(interpolation);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// BEGIN(G-API's network parametrization API)
|
||||
GBackend backend() const { return cv::gapi::ie::backend(); }
|
||||
std::string tag() const { return Net::tag(); }
|
||||
@@ -446,7 +545,7 @@ public:
|
||||
const std::string &device)
|
||||
: desc{ model, weights, device, {}, {}, {}, 0u, 0u,
|
||||
detail::ParamDesc::Kind::Load, true, {}, {}, {}, 1u,
|
||||
{}, {}, {}, {}, InferMode::Async, {} },
|
||||
{}, {}, {}, {}, InferMode::Async, {}, {}, {}, {} },
|
||||
m_tag(tag) {
|
||||
};
|
||||
|
||||
@@ -464,7 +563,7 @@ public:
|
||||
const std::string &device)
|
||||
: desc{ model, {}, device, {}, {}, {}, 0u, 0u,
|
||||
detail::ParamDesc::Kind::Import, true, {}, {}, {}, 1u,
|
||||
{}, {}, {}, {}, InferMode::Async, {} },
|
||||
{}, {}, {}, {}, InferMode::Async, {}, {}, {}, {} },
|
||||
m_tag(tag) {
|
||||
};
|
||||
|
||||
@@ -556,6 +655,44 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @see ie::Params::cfgInputLayout */
|
||||
Params& cfgInputLayout(std::string layout) {
|
||||
desc.input_layout = std::move(layout);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params&
|
||||
cfgInputLayout(detail::AttrMap<std::string> layout_map) {
|
||||
desc.input_layout = std::move(layout_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @see ie::Params::cfgOutputLayout */
|
||||
Params& cfgOutputLayout(std::string layout) {
|
||||
desc.output_layout = std::move(layout);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params&
|
||||
cfgOutputLayout(detail::AttrMap<std::string> layout_map) {
|
||||
desc.output_layout = std::move(layout_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @see ie::Params::cfgResize */
|
||||
Params& cfgResize(int interpolation) {
|
||||
desc.interpolation = interpolation;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params& cfgResize(detail::AttrMap<int> interpolation) {
|
||||
desc.interpolation = std::move(interpolation);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// BEGIN(G-API's network parametrization API)
|
||||
GBackend backend() const { return cv::gapi::ie::backend(); }
|
||||
std::string tag() const { return m_tag; }
|
||||
|
||||
@@ -0,0 +1,685 @@
|
||||
// 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) 2023 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_INFER_OV_HPP
|
||||
#define OPENCV_GAPI_INFER_OV_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <opencv2/gapi/util/any.hpp>
|
||||
#include <opencv2/gapi/own/exports.hpp> // GAPI_EXPORTS
|
||||
#include <opencv2/gapi/gkernel.hpp> // GKernelType[M], GBackend
|
||||
#include <opencv2/gapi/infer.hpp> // Generic
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
|
||||
/**
|
||||
* @brief This namespace contains G-API OpenVINO 2.0 backend functions,
|
||||
* structures, and symbols.
|
||||
*/
|
||||
namespace ov {
|
||||
|
||||
GAPI_EXPORTS cv::gapi::GBackend backend();
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
using AttrMap = std::map<std::string, T>;
|
||||
// NB: This type is supposed to be used to hold in/out layers
|
||||
// attributes such as precision, layout, shape etc.
|
||||
//
|
||||
// User can provide attributes either:
|
||||
// 1. cv::util::monostate - No value specified explicitly.
|
||||
// 2. Attr - value specified explicitly that should be broadcasted to all layers.
|
||||
// 3. AttrMap[str->T] - map specifies value for particular layer.
|
||||
template <typename Attr>
|
||||
using LayerVariantAttr = cv::util::variant< cv::util::monostate
|
||||
, AttrMap<Attr>
|
||||
, Attr>;
|
||||
|
||||
struct ParamDesc {
|
||||
struct Model {
|
||||
|
||||
Model(const std::string &model_path_,
|
||||
const std::string &bin_path_)
|
||||
: model_path(model_path_), bin_path(bin_path_) {
|
||||
}
|
||||
|
||||
std::string model_path;
|
||||
std::string bin_path;
|
||||
|
||||
LayerVariantAttr<std::string> input_tensor_layout;
|
||||
LayerVariantAttr<std::string> input_model_layout;
|
||||
LayerVariantAttr<std::string> output_tensor_layout;
|
||||
LayerVariantAttr<std::string> output_model_layout;
|
||||
LayerVariantAttr<int> output_tensor_precision;
|
||||
|
||||
LayerVariantAttr<std::vector<size_t>> new_shapes;
|
||||
|
||||
LayerVariantAttr<std::vector<float>> mean_values;
|
||||
LayerVariantAttr<std::vector<float>> scale_values;
|
||||
|
||||
LayerVariantAttr<int> interpolation;
|
||||
};
|
||||
|
||||
struct CompiledModel {
|
||||
std::string blob_path;
|
||||
};
|
||||
|
||||
using Kind = cv::util::variant<Model, CompiledModel>;
|
||||
|
||||
ParamDesc(Kind &&kind_,
|
||||
const std::string &device_,
|
||||
const bool is_generic_,
|
||||
const size_t num_in_,
|
||||
const size_t num_out_)
|
||||
: kind(std::move(kind_)), device(device_),
|
||||
is_generic(is_generic_),
|
||||
num_in(num_in_), num_out(num_out_) {
|
||||
}
|
||||
|
||||
Kind kind;
|
||||
|
||||
std::string device;
|
||||
bool is_generic;
|
||||
|
||||
std::size_t num_in;
|
||||
std::size_t num_out;
|
||||
|
||||
std::vector<std::string> input_names;
|
||||
std::vector<std::string> output_names;
|
||||
|
||||
using PluginConfigT = std::map<std::string, std::string>;
|
||||
PluginConfigT config;
|
||||
|
||||
size_t nireq = 1;
|
||||
};
|
||||
|
||||
// NB: Just helper to avoid code duplication.
|
||||
static detail::ParamDesc::Model&
|
||||
getModelToSetAttrOrThrow(detail::ParamDesc::Kind &kind,
|
||||
const std::string &attr_name) {
|
||||
if (cv::util::holds_alternative<detail::ParamDesc::CompiledModel>(kind)) {
|
||||
cv::util::throw_error(
|
||||
std::logic_error("Specifying " + attr_name + " isn't"
|
||||
" possible for compiled model."));
|
||||
}
|
||||
GAPI_Assert(cv::util::holds_alternative<detail::ParamDesc::Model>(kind));
|
||||
return cv::util::get<detail::ParamDesc::Model>(kind);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief This structure provides functions
|
||||
* that fill inference parameters for "OpenVINO Toolkit" model.
|
||||
*/
|
||||
template<typename Net> struct Params {
|
||||
public:
|
||||
/** @brief Class constructor.
|
||||
|
||||
Constructs Params based on model information and specifies default values for other
|
||||
inference description parameters. Model is loaded and compiled using "OpenVINO Toolkit".
|
||||
|
||||
@param model_path Path to a model.
|
||||
@param bin_path Path to a data file.
|
||||
For IR format (*.bin):
|
||||
If path is empty, will try to read a bin file with the same name as xml.
|
||||
If the bin file with the same name is not found, will load IR without weights.
|
||||
For PDPD (*.pdmodel) and ONNX (*.onnx) formats bin_path isn't used.
|
||||
@param device target device to use.
|
||||
*/
|
||||
Params(const std::string &model_path,
|
||||
const std::string &bin_path,
|
||||
const std::string &device)
|
||||
: m_desc( detail::ParamDesc::Kind{detail::ParamDesc::Model{model_path, bin_path}}
|
||||
, device
|
||||
, false /* is generic */
|
||||
, std::tuple_size<typename Net::InArgs>::value
|
||||
, std::tuple_size<typename Net::OutArgs>::value) {
|
||||
}
|
||||
|
||||
/** @overload
|
||||
Use this constructor to work with pre-compiled network.
|
||||
Model is imported from a pre-compiled blob.
|
||||
|
||||
@param blob_path path to the compiled model (*.blob).
|
||||
@param device target device to use.
|
||||
*/
|
||||
Params(const std::string &blob_path,
|
||||
const std::string &device)
|
||||
: m_desc( detail::ParamDesc::Kind{detail::ParamDesc::CompiledModel{blob_path}}
|
||||
, device
|
||||
, false /* is generic */
|
||||
, std::tuple_size<typename Net::InArgs>::value
|
||||
, std::tuple_size<typename Net::OutArgs>::value) {
|
||||
}
|
||||
|
||||
/** @brief Specifies sequence of network input layers names for inference.
|
||||
|
||||
The function is used to associate cv::gapi::infer<> inputs with the model inputs.
|
||||
Number of names has to match the number of network inputs as defined in G_API_NET().
|
||||
In case a network has only single input layer, there is no need to specify name manually.
|
||||
|
||||
@param layer_names std::array<std::string, N> where N is the number of inputs
|
||||
as defined in the @ref G_API_NET. Contains names of input layers.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgInputLayers(const std::vector<std::string> &layer_names) {
|
||||
m_desc.input_names = layer_names;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies sequence of network output layers names for inference.
|
||||
|
||||
The function is used to associate cv::gapi::infer<> outputs with the model outputs.
|
||||
Number of names has to match the number of network outputs as defined in G_API_NET().
|
||||
In case a network has only single output layer, there is no need to specify name manually.
|
||||
|
||||
@param layer_names std::array<std::string, N> where N is the number of outputs
|
||||
as defined in the @ref G_API_NET. Contains names of output layers.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgOutputLayers(const std::vector<std::string> &layer_names) {
|
||||
m_desc.output_names = layer_names;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies OpenVINO plugin configuration.
|
||||
|
||||
The function is used to set configuration for OpenVINO plugin. Some parameters
|
||||
can be different for each plugin. Please follow https://docs.openvinotoolkit.org/latest/index.html
|
||||
to check information about specific plugin.
|
||||
|
||||
@param config Map of pairs: (config parameter name, config parameter value).
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgPluginConfig(const detail::ParamDesc::PluginConfigT &config) {
|
||||
m_desc.config = config;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies tensor layout for an input layer.
|
||||
|
||||
The function is used to set tensor layout for an input layer.
|
||||
|
||||
@param layout Tensor layout ("NCHW", "NWHC", etc)
|
||||
will be applied to all input layers.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgInputTensorLayout(std::string layout) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "input tensor layout")
|
||||
.input_tensor_layout = std::move(layout);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
@param layout_map Map of pairs: name of corresponding input layer
|
||||
and its tensor layout represented in std::string ("NCHW", "NHWC", etc)
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>&
|
||||
cfgInputTensorLayout(detail::AttrMap<std::string> layout_map) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "input tensor layout")
|
||||
.input_tensor_layout = std::move(layout_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies model layout for an input layer.
|
||||
|
||||
The function is used to set model layout for an input layer.
|
||||
|
||||
@param layout Model layout ("NCHW", "NHWC", etc)
|
||||
will be applied to all input layers.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgInputModelLayout(std::string layout) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "input model layout")
|
||||
.input_model_layout = std::move(layout);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
@param layout_map Map of pairs: name of corresponding input layer
|
||||
and its model layout ("NCHW", "NHWC", etc)
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>&
|
||||
cfgInputModelLayout(detail::AttrMap<std::string> layout_map) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "input model layout")
|
||||
.input_model_layout = std::move(layout_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies tensor layout for an output layer.
|
||||
|
||||
The function is used to set tensor layout for an output layer.
|
||||
|
||||
@param layout Tensor layout ("NCHW", "NWHC", etc)
|
||||
will be applied to all output layers.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgOutputTensorLayout(std::string layout) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "output tensor layout")
|
||||
.output_tensor_layout = std::move(layout);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
@param layout_map Map of pairs: name of corresponding output layer
|
||||
and its tensor layout represented in std::string ("NCHW", "NHWC", etc)
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>&
|
||||
cfgOutputTensorLayout(detail::AttrMap<std::string> layout_map) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "output tensor layout")
|
||||
.output_tensor_layout = std::move(layout_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies model layout for an output layer.
|
||||
|
||||
The function is used to set model layout for an output layer.
|
||||
|
||||
@param layout Model layout ("NCHW", "NHWC", etc)
|
||||
will be applied to all output layers.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgOutputModelLayout(std::string layout) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "output model layout")
|
||||
.output_model_layout = std::move(layout);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
@param layout_map Map of pairs: name of corresponding output layer
|
||||
and its model layout ("NCHW", "NHWC", etc)
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>&
|
||||
cfgOutputModelLayout(detail::AttrMap<std::string> layout_map) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "output model layout")
|
||||
.output_model_layout = std::move(layout_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies tensor precision for an output layer.
|
||||
|
||||
The function is used to set tensor precision for an output layer..
|
||||
|
||||
@param precision Precision in OpenCV format (CV_8U, CV_32F, ...)
|
||||
will be applied to all output layers.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgOutputTensorPrecision(int precision) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "output tensor precision")
|
||||
.output_tensor_precision = precision;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
|
||||
@param precision_map Map of pairs: name of corresponding output layer
|
||||
and its precision in OpenCV format (CV_8U, CV_32F, ...)
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>&
|
||||
cfgOutputTensorPrecision(detail::AttrMap<int> precision_map) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "output tensor precision")
|
||||
.output_tensor_precision = std::move(precision_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies the new shape for input layers.
|
||||
|
||||
The function is used to set new shape for input layers.
|
||||
|
||||
@param new_shape New shape will be applied to all input layers.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>&
|
||||
cfgReshape(std::vector<size_t> new_shape) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "reshape")
|
||||
.new_shapes = std::move(new_shape);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
|
||||
@param new_shape_map Map of pairs: name of corresponding output layer
|
||||
and its new shape.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>&
|
||||
cfgReshape(detail::AttrMap<std::vector<size_t>> new_shape_map) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "reshape")
|
||||
.new_shapes = std::move(new_shape_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies number of asynchronous inference requests.
|
||||
|
||||
@param nireq Number of inference asynchronous requests.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgNumRequests(const size_t nireq) {
|
||||
if (nireq == 0) {
|
||||
cv::util::throw_error(
|
||||
std::logic_error("Number of inference requests"
|
||||
" must be greater than zero."));
|
||||
}
|
||||
m_desc.nireq = nireq;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies mean values for preprocessing.
|
||||
*
|
||||
The function is used to set mean values for input layer preprocessing.
|
||||
|
||||
@param mean_values Float vector contains mean values
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgMean(std::vector<float> mean_values) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "mean values")
|
||||
.mean_values = std::move(mean_values);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
|
||||
@param mean_map Map of pairs: name of corresponding input layer
|
||||
and its mean values.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgMean(detail::AttrMap<std::vector<float>> mean_map) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "mean values")
|
||||
.mean_values = std::move(mean_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies scale values for preprocessing.
|
||||
*
|
||||
The function is used to set scale values for input layer preprocessing.
|
||||
|
||||
@param scale_values Float vector contains scale values
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgScale(std::vector<float> scale_values) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "scale values")
|
||||
.scale_values = std::move(scale_values);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
|
||||
@param scale_map Map of pairs: name of corresponding input layer
|
||||
and its mean values.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgScale(detail::AttrMap<std::vector<float>> scale_map) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "scale values")
|
||||
.scale_values = std::move(scale_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Specifies resize interpolation algorithm.
|
||||
*
|
||||
The function is used to configure resize preprocessing for input layer.
|
||||
|
||||
@param interpolation Resize interpolation algorithm.
|
||||
Supported algorithms: #INTER_NEAREST, #INTER_LINEAR, #INTER_CUBIC.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgResize(int interpolation) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "resize preprocessing")
|
||||
.interpolation = std::move(interpolation);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload
|
||||
|
||||
@param interpolation Map of pairs: name of corresponding input layer
|
||||
and its resize algorithm.
|
||||
@return reference to this parameter structure.
|
||||
*/
|
||||
Params<Net>& cfgResize(detail::AttrMap<int> interpolation) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "resize preprocessing")
|
||||
.interpolation = std::move(interpolation);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// BEGIN(G-API's network parametrization API)
|
||||
GBackend backend() const { return cv::gapi::ov::backend(); }
|
||||
std::string tag() const { return Net::tag(); }
|
||||
cv::util::any params() const { return { m_desc }; }
|
||||
// END(G-API's network parametrization API)
|
||||
|
||||
protected:
|
||||
detail::ParamDesc m_desc;
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief This structure provides functions for generic network type that
|
||||
* fill inference parameters.
|
||||
* @see struct Generic
|
||||
*/
|
||||
template<>
|
||||
class Params<cv::gapi::Generic> {
|
||||
public:
|
||||
/** @brief Class constructor.
|
||||
|
||||
Constructs Params based on model information and specifies default values for other
|
||||
inference description parameters. Model is loaded and compiled using "OpenVINO Toolkit".
|
||||
|
||||
@param tag string tag of the network for which these parameters are intended.
|
||||
@param model_path Path to a model.
|
||||
@param bin_path Path to a data file.
|
||||
For IR format (*.bin):
|
||||
If path is empty, will try to read a bin file with the same name as xml.
|
||||
If the bin file with the same name is not found, will load IR without weights.
|
||||
For PDPD (*.pdmodel) and ONNX (*.onnx) formats bin_path isn't used.
|
||||
@param device target device to use.
|
||||
*/
|
||||
Params(const std::string &tag,
|
||||
const std::string &model_path,
|
||||
const std::string &bin_path,
|
||||
const std::string &device)
|
||||
: m_tag(tag),
|
||||
m_desc( detail::ParamDesc::Kind{detail::ParamDesc::Model{model_path, bin_path}}
|
||||
, device
|
||||
, true /* is generic */
|
||||
, 0u
|
||||
, 0u) {
|
||||
}
|
||||
|
||||
/** @overload
|
||||
|
||||
This constructor for pre-compiled networks. Model is imported from pre-compiled
|
||||
blob.
|
||||
|
||||
@param tag string tag of the network for which these parameters are intended.
|
||||
@param blob_path path to the compiled model (*.blob).
|
||||
@param device target device to use.
|
||||
*/
|
||||
Params(const std::string &tag,
|
||||
const std::string &blob_path,
|
||||
const std::string &device)
|
||||
: m_tag(tag),
|
||||
m_desc( detail::ParamDesc::Kind{detail::ParamDesc::CompiledModel{blob_path}}
|
||||
, device
|
||||
, true /* is generic */
|
||||
, 0u
|
||||
, 0u) {
|
||||
}
|
||||
|
||||
/** @see ov::Params::cfgPluginConfig. */
|
||||
Params& cfgPluginConfig(const detail::ParamDesc::PluginConfigT &config) {
|
||||
m_desc.config = config;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @see ov::Params::cfgInputTensorLayout. */
|
||||
Params& cfgInputTensorLayout(std::string layout) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "input tensor layout")
|
||||
.input_tensor_layout = std::move(layout);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params&
|
||||
cfgInputTensorLayout(detail::AttrMap<std::string> layout_map) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "input tensor layout")
|
||||
.input_tensor_layout = std::move(layout_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @see ov::Params::cfgInputModelLayout. */
|
||||
Params& cfgInputModelLayout(std::string layout) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "input model layout")
|
||||
.input_model_layout = std::move(layout);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params&
|
||||
cfgInputModelLayout(detail::AttrMap<std::string> layout_map) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "input model layout")
|
||||
.input_model_layout = std::move(layout_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @see ov::Params::cfgOutputTensorLayout. */
|
||||
Params& cfgOutputTensorLayout(std::string layout) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "output tensor layout")
|
||||
.output_tensor_layout = std::move(layout);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params&
|
||||
cfgOutputTensorLayout(detail::AttrMap<std::string> layout_map) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "output tensor layout")
|
||||
.output_tensor_layout = std::move(layout_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @see ov::Params::cfgOutputModelLayout. */
|
||||
Params& cfgOutputModelLayout(std::string layout) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "output model layout")
|
||||
.output_model_layout = std::move(layout);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params&
|
||||
cfgOutputModelLayout(detail::AttrMap<std::string> layout_map) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "output model layout")
|
||||
.output_model_layout = std::move(layout_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @see ov::Params::cfgOutputTensorPrecision. */
|
||||
Params& cfgOutputTensorPrecision(int precision) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "output tensor precision")
|
||||
.output_tensor_precision = precision;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params&
|
||||
cfgOutputTensorPrecision(detail::AttrMap<int> precision_map) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "output tensor precision")
|
||||
.output_tensor_precision = std::move(precision_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @see ov::Params::cfgReshape. */
|
||||
Params& cfgReshape(std::vector<size_t> new_shape) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "reshape")
|
||||
.new_shapes = std::move(new_shape);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params&
|
||||
cfgReshape(detail::AttrMap<std::vector<size_t>> new_shape_map) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "reshape")
|
||||
.new_shapes = std::move(new_shape_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @see ov::Params::cfgNumRequests. */
|
||||
Params& cfgNumRequests(const size_t nireq) {
|
||||
if (nireq == 0) {
|
||||
cv::util::throw_error(
|
||||
std::logic_error("Number of inference requests"
|
||||
" must be greater than zero."));
|
||||
}
|
||||
m_desc.nireq = nireq;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @see ov::Params::cfgMean. */
|
||||
Params& cfgMean(std::vector<float> mean_values) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "mean values")
|
||||
.mean_values = std::move(mean_values);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params& cfgMean(detail::AttrMap<std::vector<float>> mean_map) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "mean values")
|
||||
.mean_values = std::move(mean_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @see ov::Params::cfgScale. */
|
||||
Params& cfgScale(std::vector<float> scale_values) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "scale values")
|
||||
.scale_values = std::move(scale_values);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params& cfgScale(detail::AttrMap<std::vector<float>> scale_map) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "scale values")
|
||||
.scale_values = std::move(scale_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @see ov::Params::cfgResize. */
|
||||
Params& cfgResize(int interpolation) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "resize preprocessing")
|
||||
.interpolation = std::move(interpolation);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
Params& cfgResize(detail::AttrMap<int> interpolation) {
|
||||
detail::getModelToSetAttrOrThrow(m_desc.kind, "resize preprocessing")
|
||||
.interpolation = std::move(interpolation);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// BEGIN(G-API's network parametrization API)
|
||||
GBackend backend() const { return cv::gapi::ov::backend(); }
|
||||
std::string tag() const { return m_tag; }
|
||||
cv::util::any params() const { return { m_desc }; }
|
||||
// END(G-API's network parametrization API)
|
||||
|
||||
protected:
|
||||
std::string m_tag;
|
||||
detail::ParamDesc m_desc;
|
||||
};
|
||||
|
||||
} // namespace ov
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_INFER_OV_HPP
|
||||
@@ -22,6 +22,7 @@
|
||||
* because of this file.
|
||||
*/
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
|
||||
#include <opencv2/videoio.hpp>
|
||||
#include <opencv2/gapi/garg.hpp>
|
||||
@@ -47,8 +48,16 @@ namespace wip {
|
||||
class GCaptureSource: public IStreamSource
|
||||
{
|
||||
public:
|
||||
explicit GCaptureSource(int id) : cap(id) { prep(); }
|
||||
explicit GCaptureSource(const std::string &path) : cap(path) { prep(); }
|
||||
explicit GCaptureSource(int id, const std::map<int, double> &properties = {})
|
||||
: cap(id) { prep(properties); }
|
||||
|
||||
explicit GCaptureSource(const std::string &path,
|
||||
const std::map<int, double> &properties = {})
|
||||
: cap(path) { prep(properties); }
|
||||
|
||||
void set(int propid, double value) {
|
||||
cap.set(propid, value);
|
||||
}
|
||||
|
||||
// TODO: Add more constructor overloads to make it
|
||||
// fully compatible with VideoCapture's interface.
|
||||
@@ -59,8 +68,12 @@ protected:
|
||||
bool first_pulled = false;
|
||||
int64_t counter = 0;
|
||||
|
||||
void prep()
|
||||
void prep(const std::map<int, double> &properties)
|
||||
{
|
||||
for (const auto &it : properties) {
|
||||
cap.set(it.first, it.second);
|
||||
}
|
||||
|
||||
// Prepare first frame to report its meta to engine
|
||||
// when needed
|
||||
GAPI_Assert(first.empty());
|
||||
@@ -114,15 +127,19 @@ protected:
|
||||
};
|
||||
|
||||
// NB: Overload for using from python
|
||||
GAPI_EXPORTS_W cv::Ptr<IStreamSource> inline make_capture_src(const std::string& path)
|
||||
GAPI_EXPORTS_W cv::Ptr<IStreamSource>
|
||||
inline make_capture_src(const std::string& path,
|
||||
const std::map<int, double>& properties = {})
|
||||
{
|
||||
return make_src<GCaptureSource>(path);
|
||||
return make_src<GCaptureSource>(path, properties);
|
||||
}
|
||||
|
||||
// NB: Overload for using from python
|
||||
GAPI_EXPORTS_W cv::Ptr<IStreamSource> inline make_capture_src(const int id)
|
||||
GAPI_EXPORTS_W cv::Ptr<IStreamSource>
|
||||
inline make_capture_src(const int id,
|
||||
const std::map<int, double>& properties = {})
|
||||
{
|
||||
return make_src<GCaptureSource>(id);
|
||||
return make_src<GCaptureSource>(id, properties);
|
||||
}
|
||||
|
||||
} // namespace wip
|
||||
|
||||
@@ -15,6 +15,7 @@ using gapi_GKernelPackage = cv::GKernelPackage;
|
||||
using gapi_GNetPackage = cv::gapi::GNetPackage;
|
||||
using gapi_ie_PyParams = cv::gapi::ie::PyParams;
|
||||
using gapi_onnx_PyParams = cv::gapi::onnx::PyParams;
|
||||
using gapi_ov_PyParams = cv::gapi::ov::PyParams;
|
||||
using gapi_wip_IStreamSource_Ptr = cv::Ptr<cv::gapi::wip::IStreamSource>;
|
||||
using detail_ExtractArgsCallback = cv::detail::ExtractArgsCallback;
|
||||
using detail_ExtractMetaCallback = cv::detail::ExtractMetaCallback;
|
||||
@@ -22,6 +23,12 @@ using vector_GNetParam = std::vector<cv::gapi::GNetParam>;
|
||||
using vector_GMat = std::vector<cv::GMat>;
|
||||
using gapi_streaming_queue_capacity = cv::gapi::streaming::queue_capacity;
|
||||
using GStreamerSource_OutputType = cv::gapi::wip::GStreamerSource::OutputType;
|
||||
using map_string_and_int = std::map<std::string, int>;
|
||||
using map_string_and_string = std::map<std::string, std::string>;
|
||||
using map_string_and_string = std::map<std::string, std::string>;
|
||||
using map_string_and_vector_size_t = std::map<std::string, std::vector<size_t>>;
|
||||
using map_string_and_vector_float = std::map<std::string, std::vector<float>>;
|
||||
using map_int_and_double = std::map<int, double>;
|
||||
|
||||
// NB: Python wrapper generate T_U for T<U>
|
||||
// This behavior is only observed for inputs
|
||||
|
||||
@@ -80,5 +80,6 @@ namespace detail
|
||||
{
|
||||
gapi::GNetParam GAPI_EXPORTS_W strip(gapi::ie::PyParams params);
|
||||
gapi::GNetParam GAPI_EXPORTS_W strip(gapi::onnx::PyParams params);
|
||||
gapi::GNetParam GAPI_EXPORTS_W strip(gapi::ov::PyParams params);
|
||||
} // namespace detail
|
||||
} // namespace cv
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
#!/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')
|
||||
|
||||
|
||||
openvino_is_available = True
|
||||
try:
|
||||
from openvino.runtime import Core, Type, Layout, PartialShape
|
||||
from openvino.preprocess import ResizeAlgorithm, PrePostProcessor
|
||||
except ImportError:
|
||||
openvino_is_available = False
|
||||
|
||||
|
||||
def skip_if_openvino_not_available():
|
||||
if not openvino_is_available:
|
||||
raise unittest.SkipTest("OpenVINO isn't available from python.")
|
||||
|
||||
|
||||
class AgeGenderOV:
|
||||
def __init__(self, model_path, bin_path, device):
|
||||
self.device = device
|
||||
self.core = Core()
|
||||
self.model = self.core.read_model(model_path, bin_path)
|
||||
|
||||
|
||||
def reshape(self, new_shape):
|
||||
self.model.reshape(new_shape)
|
||||
|
||||
|
||||
def cfgPrePostProcessing(self, pp_callback):
|
||||
ppp = PrePostProcessor(self.model)
|
||||
pp_callback(ppp)
|
||||
self.model = ppp.build()
|
||||
|
||||
|
||||
def apply(self, in_data):
|
||||
compiled_model = self.core.compile_model(self.model, self.device)
|
||||
infer_request = compiled_model.create_infer_request()
|
||||
results = infer_request.infer(in_data)
|
||||
ov_age = results['age_conv3'].squeeze()
|
||||
ov_gender = results['prob'].squeeze()
|
||||
return ov_age, ov_gender
|
||||
|
||||
|
||||
class AgeGenderGAPI:
|
||||
tag = 'age-gender-net'
|
||||
|
||||
def __init__(self, model_path, bin_path, device):
|
||||
g_in = cv.GMat()
|
||||
inputs = cv.GInferInputs()
|
||||
inputs.setInput('data', g_in)
|
||||
# TODO: It'd be nice to pass dict instead.
|
||||
# E.g cv.gapi.infer("net", {'data': g_in})
|
||||
outputs = cv.gapi.infer(AgeGenderGAPI.tag, inputs)
|
||||
age_g = outputs.at("age_conv3")
|
||||
gender_g = outputs.at("prob")
|
||||
|
||||
self.comp = cv.GComputation(cv.GIn(g_in), cv.GOut(age_g, gender_g))
|
||||
self.pp = cv.gapi.ov.params(AgeGenderGAPI.tag, \
|
||||
model_path, bin_path, device)
|
||||
|
||||
|
||||
def apply(self, in_data):
|
||||
compile_args = cv.gapi.compile_args(cv.gapi.networks(self.pp))
|
||||
gapi_age, gapi_gender = self.comp.apply(cv.gin(in_data), compile_args)
|
||||
gapi_gender = gapi_gender.squeeze()
|
||||
gapi_age = gapi_age.squeeze()
|
||||
return gapi_age, gapi_gender
|
||||
|
||||
|
||||
class test_gapi_infer_ov(NewOpenCVTests):
|
||||
|
||||
def test_age_gender_infer_image(self):
|
||||
skip_if_openvino_not_available()
|
||||
|
||||
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')])
|
||||
bin_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)
|
||||
|
||||
# OpenVINO
|
||||
def preproc(ppp):
|
||||
ppp.input().model().set_layout(Layout("NCHW"))
|
||||
ppp.input().tensor().set_element_type(Type.u8) \
|
||||
.set_spatial_static_shape(img.shape[0], img.shape[1]) \
|
||||
.set_layout(Layout("NHWC"))
|
||||
ppp.input().preprocess().resize(ResizeAlgorithm.RESIZE_LINEAR)
|
||||
|
||||
|
||||
ref = AgeGenderOV(model_path, bin_path, device_id)
|
||||
ref.cfgPrePostProcessing(preproc)
|
||||
ov_age, ov_gender = ref.apply(np.expand_dims(img, 0))
|
||||
|
||||
# OpenCV G-API (No preproc required)
|
||||
comp = AgeGenderGAPI(model_path, bin_path, device_id)
|
||||
gapi_age, gapi_gender = comp.apply(img)
|
||||
|
||||
# Check
|
||||
self.assertEqual(0.0, cv.norm(ov_gender, gapi_gender, cv.NORM_INF))
|
||||
self.assertEqual(0.0, cv.norm(ov_age, gapi_age, cv.NORM_INF))
|
||||
|
||||
|
||||
def test_age_gender_infer_tensor(self):
|
||||
skip_if_openvino_not_available()
|
||||
|
||||
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')])
|
||||
bin_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)
|
||||
|
||||
# Prepare data manually
|
||||
tensor = cv.resize(img, (62, 62)).astype(np.float32)
|
||||
tensor = np.transpose(tensor, (2, 0, 1))
|
||||
tensor = np.expand_dims(tensor, 0)
|
||||
|
||||
# OpenVINO (No preproce required)
|
||||
ref = AgeGenderOV(model_path, bin_path, device_id)
|
||||
ov_age, ov_gender = ref.apply(tensor)
|
||||
|
||||
# OpenCV G-API (No preproc required)
|
||||
comp = AgeGenderGAPI(model_path, bin_path, device_id)
|
||||
gapi_age, gapi_gender = comp.apply(tensor)
|
||||
|
||||
# Check
|
||||
self.assertEqual(0.0, cv.norm(ov_gender, gapi_gender, cv.NORM_INF))
|
||||
self.assertEqual(0.0, cv.norm(ov_age, gapi_age, cv.NORM_INF))
|
||||
|
||||
|
||||
def test_age_gender_infer_batch(self):
|
||||
skip_if_openvino_not_available()
|
||||
|
||||
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')])
|
||||
bin_path = self.find_file(root_path + '.bin', [os.environ.get('OPENCV_DNN_TEST_DATA_PATH')])
|
||||
device_id = 'CPU'
|
||||
|
||||
img_path1 = self.find_file('cv/face/david1.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
img_path2 = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
|
||||
img1 = cv.imread(img_path1)
|
||||
img2 = cv.imread(img_path2)
|
||||
# img1 and img2 have the same size
|
||||
batch_img = np.array([img1, img2])
|
||||
|
||||
# OpenVINO
|
||||
def preproc(ppp):
|
||||
ppp.input().model().set_layout(Layout("NCHW"))
|
||||
ppp.input().tensor().set_element_type(Type.u8) \
|
||||
.set_spatial_static_shape(img1.shape[0], img2.shape[1]) \
|
||||
.set_layout(Layout("NHWC"))
|
||||
ppp.input().preprocess().resize(ResizeAlgorithm.RESIZE_LINEAR)
|
||||
|
||||
|
||||
ref = AgeGenderOV(model_path, bin_path, device_id)
|
||||
ref.reshape(PartialShape([2, 3, 62, 62]))
|
||||
ref.cfgPrePostProcessing(preproc)
|
||||
ov_age, ov_gender = ref.apply(batch_img)
|
||||
|
||||
# OpenCV G-API
|
||||
comp = AgeGenderGAPI(model_path, bin_path, device_id)
|
||||
comp.pp.cfgReshape([2, 3, 62, 62]) \
|
||||
.cfgInputModelLayout("NCHW") \
|
||||
.cfgInputTensorLayout("NHWC") \
|
||||
.cfgResize(cv.INTER_LINEAR)
|
||||
gapi_age, gapi_gender = comp.apply(batch_img)
|
||||
|
||||
# Check
|
||||
self.assertEqual(0.0, cv.norm(ov_gender, gapi_gender, cv.NORM_INF))
|
||||
self.assertEqual(0.0, cv.norm(ov_age, gapi_age, cv.NORM_INF))
|
||||
|
||||
|
||||
def test_age_gender_infer_planar(self):
|
||||
skip_if_openvino_not_available()
|
||||
|
||||
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')])
|
||||
bin_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)
|
||||
planar_img = np.transpose(img, (2, 0, 1))
|
||||
planar_img = np.expand_dims(planar_img, 0)
|
||||
|
||||
# OpenVINO
|
||||
def preproc(ppp):
|
||||
ppp.input().tensor().set_element_type(Type.u8) \
|
||||
.set_spatial_static_shape(img.shape[0], img.shape[1])
|
||||
ppp.input().preprocess().resize(ResizeAlgorithm.RESIZE_LINEAR)
|
||||
|
||||
|
||||
ref = AgeGenderOV(model_path, bin_path, device_id)
|
||||
ref.cfgPrePostProcessing(preproc)
|
||||
ov_age, ov_gender = ref.apply(planar_img)
|
||||
|
||||
# OpenCV G-API
|
||||
comp = AgeGenderGAPI(model_path, bin_path, device_id)
|
||||
comp.pp.cfgResize(cv.INTER_LINEAR)
|
||||
gapi_age, gapi_gender = comp.apply(planar_img)
|
||||
|
||||
# Check
|
||||
self.assertEqual(0.0, cv.norm(ov_gender, gapi_gender, cv.NORM_INF))
|
||||
self.assertEqual(0.0, cv.norm(ov_age, gapi_age, 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()
|
||||
@@ -62,7 +62,7 @@ namespace opencv_test
|
||||
class InRangePerfTest : public TestPerfParams<tuple<compare_f, cv::Size, MatType, cv::GCompileArgs>> {};
|
||||
class Split3PerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
|
||||
class Split4PerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
|
||||
class Merge3PerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
|
||||
class Merge3PerfTest : public TestPerfParams<tuple<compare_f, cv::Size, MatType, cv::GCompileArgs>> {};
|
||||
class Merge4PerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
|
||||
class RemapPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, MatType, cv::GCompileArgs>> {};
|
||||
class FlipPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, MatType, int, cv::GCompileArgs>> {};
|
||||
|
||||
@@ -1577,11 +1577,12 @@ PERF_TEST_P_(Merge3PerfTest, TestPerformance)
|
||||
{
|
||||
compare_f cmpF;
|
||||
cv::Size sz;
|
||||
MatType type = -1;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(cmpF, sz, compile_args) = GetParam();
|
||||
std::tie(cmpF, sz, type, compile_args) = GetParam();
|
||||
|
||||
initMatsRandU(CV_8UC1, sz, CV_8UC3);
|
||||
cv::Mat in_mat3(sz, CV_8UC1);
|
||||
initMatsRandU(type, sz, CV_MAKETYPE(type, 3));
|
||||
cv::Mat in_mat3(sz, type);
|
||||
cv::Scalar mean = cv::Scalar::all(127);
|
||||
cv::Scalar stddev = cv::Scalar::all(40.f);
|
||||
cv::randn(in_mat3, mean, stddev);
|
||||
|
||||
@@ -252,6 +252,7 @@ INSTANTIATE_TEST_CASE_P(Split4PerfTestCPU, Split4PerfTest,
|
||||
INSTANTIATE_TEST_CASE_P(Merge3PerfTestCPU, Merge3PerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(CV_8U),
|
||||
Values(cv::compile_args(CORE_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Merge4PerfTestCPU, Merge4PerfTest,
|
||||
|
||||
@@ -253,6 +253,7 @@ INSTANTIATE_TEST_CASE_P(Split4PerfTestFluid, Split4PerfTest,
|
||||
INSTANTIATE_TEST_CASE_P(Merge3PerfTestFluid, Merge3PerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(szSmall128, szVGA, sz720p, sz1080p),
|
||||
Values(CV_8U, CV_16S, CV_16U, CV_32F),
|
||||
Values(cv::compile_args(CORE_FLUID))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Merge4PerfTestFluid, Merge4PerfTest,
|
||||
|
||||
@@ -242,6 +242,7 @@ INSTANTIATE_TEST_CASE_P(Split4PerfTestGPU, Split4PerfTest,
|
||||
INSTANTIATE_TEST_CASE_P(Merge3PerfTestGPU, Merge3PerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values( szSmall128, szVGA, sz720p, sz1080p ),
|
||||
Values(CV_8U),
|
||||
Values(cv::compile_args(CORE_GPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Merge4PerfTestGPU, Merge4PerfTest,
|
||||
|
||||
@@ -5,34 +5,41 @@
|
||||
#include <opencv2/gapi/operators.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
|
||||
#include <opencv2/gapi/streaming/desync.hpp>
|
||||
#include <opencv2/gapi/streaming/format.hpp>
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
const std::string keys =
|
||||
"{ h help | | Print this help message }"
|
||||
"{ desync | false | Desynchronize inference }"
|
||||
"{ input | | Path to the input video file }"
|
||||
"{ output | | Path to the output video file }"
|
||||
"{ ssm | semantic-segmentation-adas-0001.xml | Path to OpenVINO IE semantic segmentation model (.xml) }";
|
||||
|
||||
// 20 colors for 20 classes of semantic-segmentation-adas-0001
|
||||
const std::vector<cv::Vec3b> colors = {
|
||||
{ 128, 64, 128 },
|
||||
{ 232, 35, 244 },
|
||||
{ 70, 70, 70 },
|
||||
{ 156, 102, 102 },
|
||||
{ 153, 153, 190 },
|
||||
{ 153, 153, 153 },
|
||||
{ 30, 170, 250 },
|
||||
{ 0, 220, 220 },
|
||||
{ 35, 142, 107 },
|
||||
{ 152, 251, 152 },
|
||||
{ 180, 130, 70 },
|
||||
{ 60, 20, 220 },
|
||||
{ 0, 0, 255 },
|
||||
{ 142, 0, 0 },
|
||||
{ 70, 0, 0 },
|
||||
{ 100, 60, 0 },
|
||||
{ 90, 0, 0 },
|
||||
{ 230, 0, 0 },
|
||||
{ 32, 11, 119 },
|
||||
{ 0, 74, 111 },
|
||||
static std::vector<cv::Vec3b> colors = {
|
||||
{ 0, 0, 0 },
|
||||
{ 0, 0, 128 },
|
||||
{ 0, 128, 0 },
|
||||
{ 0, 128, 128 },
|
||||
{ 128, 0, 0 },
|
||||
{ 128, 0, 128 },
|
||||
{ 128, 128, 0 },
|
||||
{ 128, 128, 128 },
|
||||
{ 0, 0, 64 },
|
||||
{ 0, 0, 192 },
|
||||
{ 0, 128, 64 },
|
||||
{ 0, 128, 192 },
|
||||
{ 128, 0, 64 },
|
||||
{ 128, 0, 192 },
|
||||
{ 128, 128, 64 },
|
||||
{ 128, 128, 192 },
|
||||
{ 0, 64, 0 },
|
||||
{ 0, 64, 128 },
|
||||
{ 0, 192, 0 },
|
||||
{ 0, 192, 128 },
|
||||
{ 128, 64, 0 }
|
||||
};
|
||||
|
||||
namespace {
|
||||
@@ -43,12 +50,23 @@ std::string get_weights_path(const std::string &model_path) {
|
||||
|
||||
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));
|
||||
});
|
||||
return static_cast<unsigned char>(std::tolower(c));
|
||||
});
|
||||
CV_Assert(ext == ".xml");
|
||||
return model_path.substr(0u, sz - EXT_LEN) + ".bin";
|
||||
}
|
||||
|
||||
bool isNumber(const std::string &str) {
|
||||
return !str.empty() && std::all_of(str.begin(), str.end(),
|
||||
[](unsigned char ch) { return std::isdigit(ch); });
|
||||
}
|
||||
|
||||
std::string toStr(double value) {
|
||||
std::stringstream ss;
|
||||
ss << std::fixed << std::setprecision(1) << value;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void classesToColors(const cv::Mat &out_blob,
|
||||
cv::Mat &mask_img) {
|
||||
const int H = out_blob.size[0];
|
||||
@@ -97,6 +115,25 @@ void probsToClasses(const cv::Mat& probs, cv::Mat& classes) {
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace vis {
|
||||
|
||||
static void putText(cv::Mat& mat, const cv::Point &position, const std::string &message) {
|
||||
auto fontFace = cv::FONT_HERSHEY_COMPLEX;
|
||||
int thickness = 2;
|
||||
cv::Scalar color = {200, 10, 10};
|
||||
double fontScale = 0.65;
|
||||
|
||||
cv::putText(mat, message, position, fontFace,
|
||||
fontScale, cv::Scalar(255, 255, 255), thickness + 1);
|
||||
cv::putText(mat, message, position, fontFace, fontScale, color, thickness);
|
||||
}
|
||||
|
||||
static void drawResults(cv::Mat &img, const cv::Mat &color_mask) {
|
||||
img = img / 2 + color_mask / 2;
|
||||
}
|
||||
|
||||
} // namespace vis
|
||||
|
||||
namespace custom {
|
||||
G_API_OP(PostProcessing, <cv::GMat(cv::GMat, cv::GMat)>, "sample.custom.post_processing") {
|
||||
static cv::GMatDesc outMeta(const cv::GMatDesc &in, const cv::GMatDesc &) {
|
||||
@@ -106,19 +143,34 @@ 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 &out_blob, cv::Mat &out) {
|
||||
int C = -1, H = -1, W = -1;
|
||||
if (out_blob.size.dims() == 4u) {
|
||||
C = 1; H = 2, W = 3;
|
||||
} else if (out_blob.size.dims() == 3u) {
|
||||
C = 0; H = 1, W = 2;
|
||||
} else {
|
||||
throw std::logic_error(
|
||||
"Number of dimmensions for model output must be 3 or 4!");
|
||||
}
|
||||
cv::Mat classes;
|
||||
// NB: If output has more than single plane, it contains probabilities
|
||||
// otherwise class id.
|
||||
if (out_blob.size[1] > 1) {
|
||||
if (out_blob.size[C] > 1) {
|
||||
probsToClasses(out_blob, classes);
|
||||
} else {
|
||||
out_blob.convertTo(classes, CV_8UC1);
|
||||
classes = classes.reshape(1, out_blob.size[2]);
|
||||
if (out_blob.depth() != CV_32S) {
|
||||
throw std::logic_error(
|
||||
"Single channel output must have integer precision!");
|
||||
}
|
||||
cv::Mat view(out_blob.size[H], // cols
|
||||
out_blob.size[W], // rows
|
||||
CV_32SC1,
|
||||
out_blob.data);
|
||||
view.convertTo(classes, CV_8UC1);
|
||||
}
|
||||
|
||||
cv::Mat mask_img;
|
||||
classesToColors(classes, mask_img);
|
||||
cv::resize(mask_img, out, in.size());
|
||||
cv::resize(mask_img, out, in.size(), 0, 0, cv::INTER_NEAREST);
|
||||
}
|
||||
};
|
||||
} // namespace custom
|
||||
@@ -134,6 +186,7 @@ int main(int argc, char *argv[]) {
|
||||
const std::string input = cmd.get<std::string>("input");
|
||||
const std::string output = cmd.get<std::string>("output");
|
||||
const auto model_path = cmd.get<std::string>("ssm");
|
||||
const bool desync = cmd.get<bool>("desync");
|
||||
const auto weights_path = get_weights_path(model_path);
|
||||
const auto device = "CPU";
|
||||
G_API_NET(SemSegmNet, <cv::GMat(cv::GMat)>, "semantic-segmentation");
|
||||
@@ -145,40 +198,87 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
// Now build the graph
|
||||
cv::GMat in;
|
||||
cv::GMat out_blob = cv::gapi::infer<SemSegmNet>(in);
|
||||
cv::GMat post_proc_out = custom::PostProcessing::on(in, out_blob);
|
||||
cv::GMat blending_in = in * 0.3f;
|
||||
cv::GMat blending_out = post_proc_out * 0.7f;
|
||||
cv::GMat out = blending_in + blending_out;
|
||||
cv::GMat bgr = cv::gapi::copy(in);
|
||||
cv::GMat frame = desync ? cv::gapi::streaming::desync(bgr) : bgr;
|
||||
cv::GMat out_blob = cv::gapi::infer<SemSegmNet>(frame);
|
||||
cv::GMat out = custom::PostProcessing::on(frame, out_blob);
|
||||
|
||||
cv::GStreamingCompiled pipeline = cv::GComputation(cv::GIn(in), cv::GOut(out))
|
||||
.compileStreaming(cv::compile_args(kernels, networks));
|
||||
auto inputs = cv::gin(cv::gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(input));
|
||||
cv::GStreamingCompiled pipeline = cv::GComputation(cv::GIn(in), cv::GOut(bgr, out))
|
||||
.compileStreaming(cv::compile_args(kernels, networks,
|
||||
cv::gapi::streaming::queue_capacity{1}));
|
||||
|
||||
std::shared_ptr<cv::gapi::wip::GCaptureSource> source;
|
||||
if (isNumber(input)) {
|
||||
source = std::make_shared<cv::gapi::wip::GCaptureSource>(
|
||||
std::stoi(input),
|
||||
std::map<int, double> {
|
||||
{cv::CAP_PROP_FRAME_WIDTH, 1280},
|
||||
{cv::CAP_PROP_FRAME_HEIGHT, 720},
|
||||
{cv::CAP_PROP_BUFFERSIZE, 1},
|
||||
{cv::CAP_PROP_AUTOFOCUS, true}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
source = std::make_shared<cv::gapi::wip::GCaptureSource>(input);
|
||||
}
|
||||
auto inputs = cv::gin(
|
||||
static_cast<cv::gapi::wip::IStreamSource::Ptr>(source));
|
||||
|
||||
// The execution part
|
||||
pipeline.setSource(std::move(inputs));
|
||||
|
||||
cv::VideoWriter writer;
|
||||
cv::TickMeter tm;
|
||||
cv::Mat outMat;
|
||||
cv::VideoWriter writer;
|
||||
|
||||
cv::util::optional<cv::Mat> color_mask;
|
||||
cv::util::optional<cv::Mat> image;
|
||||
cv::Mat last_image;
|
||||
cv::Mat last_color_mask;
|
||||
|
||||
pipeline.start();
|
||||
tm.start();
|
||||
|
||||
std::size_t frames = 0u;
|
||||
tm.start();
|
||||
pipeline.start();
|
||||
while (pipeline.pull(cv::gout(outMat))) {
|
||||
++frames;
|
||||
cv::imshow("Out", outMat);
|
||||
cv::waitKey(1);
|
||||
if (!output.empty()) {
|
||||
if (!writer.isOpened()) {
|
||||
const auto sz = cv::Size{outMat.cols, outMat.rows};
|
||||
writer.open(output, cv::VideoWriter::fourcc('M','J','P','G'), 25.0, sz);
|
||||
CV_Assert(writer.isOpened());
|
||||
std::size_t masks = 0u;
|
||||
while (pipeline.pull(cv::gout(image, color_mask))) {
|
||||
if (image.has_value()) {
|
||||
++frames;
|
||||
last_image = std::move(*image);
|
||||
}
|
||||
|
||||
if (color_mask.has_value()) {
|
||||
++masks;
|
||||
last_color_mask = std::move(*color_mask);
|
||||
}
|
||||
|
||||
if (!last_image.empty() && !last_color_mask.empty()) {
|
||||
tm.stop();
|
||||
|
||||
std::string stream_fps = "Stream FPS: " + toStr(frames / tm.getTimeSec());
|
||||
std::string inference_fps = "Inference FPS: " + toStr(masks / tm.getTimeSec());
|
||||
|
||||
cv::Mat tmp = last_image.clone();
|
||||
|
||||
vis::drawResults(tmp, last_color_mask);
|
||||
vis::putText(tmp, {10, 22}, stream_fps);
|
||||
vis::putText(tmp, {10, 22 + 30}, inference_fps);
|
||||
|
||||
cv::imshow("Out", tmp);
|
||||
cv::waitKey(1);
|
||||
if (!output.empty()) {
|
||||
if (!writer.isOpened()) {
|
||||
const auto sz = cv::Size{tmp.cols, tmp.rows};
|
||||
writer.open(output, cv::VideoWriter::fourcc('M','J','P','G'), 25.0, sz);
|
||||
CV_Assert(writer.isOpened());
|
||||
}
|
||||
writer << tmp;
|
||||
}
|
||||
writer << outMat;
|
||||
|
||||
tm.start();
|
||||
}
|
||||
}
|
||||
tm.stop();
|
||||
std::cout << "Processed " << frames << " frames" << " (" << frames / tm.getTimeSec() << " FPS)" << std::endl;
|
||||
std::cout << "Processed " << frames << " frames" << " ("
|
||||
<< frames / tm.getTimeSec()<< " FPS)" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -153,10 +153,18 @@ std::ostream& operator<<(std::ostream& os, const cv::GMatDesc &desc)
|
||||
break;
|
||||
}
|
||||
|
||||
os << "C" << desc.chan;
|
||||
if (desc.planar) os << "p";
|
||||
os << " ";
|
||||
os << desc.size.width << "x" << desc.size.height;
|
||||
if (desc.isND()) {
|
||||
os << " [";
|
||||
for (size_t i = 0; i < desc.dims.size() - 1; ++i) {
|
||||
os << desc.dims[i] << "x";
|
||||
}
|
||||
os << desc.dims.back() << "]";
|
||||
} else {
|
||||
os << "C" << desc.chan;
|
||||
if (desc.planar) os << "p";
|
||||
os << " ";
|
||||
os << desc.size.width << "x" << desc.size.height;
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
@@ -227,6 +227,12 @@ inline void convertInt64ToInt32(const int64_t* src, int* dst, size_t size)
|
||||
[](int64_t el) { return static_cast<int>(el); });
|
||||
}
|
||||
|
||||
inline void convertInt32ToInt64(const int* src, int64_t* dst, size_t size)
|
||||
{
|
||||
std::transform(src, src + size, dst,
|
||||
[](int el) { return static_cast<int64_t>(el); });
|
||||
}
|
||||
|
||||
}} // cv::gimpl
|
||||
|
||||
#endif // OPENCV_GAPI_GBACKEND_HPP
|
||||
|
||||
@@ -2320,12 +2320,15 @@ GAPI_FLUID_KERNEL(GFluidSplit3, cv::gapi::core::GSplit3, false)
|
||||
|
||||
static void run(const View &src, Buffer &dst1, Buffer &dst2, Buffer &dst3)
|
||||
{
|
||||
GAPI_Assert((src.meta().depth == CV_8U) && (dst1.meta().depth == CV_8U) &&
|
||||
(dst2.meta().depth == CV_8U) && (dst3.meta().depth == CV_8U) &&
|
||||
(3 == src.meta().chan));
|
||||
|
||||
const auto *in = src.InLine<uchar>(0);
|
||||
auto *out1 = dst1.OutLine<uchar>();
|
||||
auto *out2 = dst2.OutLine<uchar>();
|
||||
auto *out3 = dst3.OutLine<uchar>();
|
||||
|
||||
GAPI_Assert(3 == src.meta().chan);
|
||||
int width = src.length();
|
||||
int w = 0;
|
||||
|
||||
@@ -2348,13 +2351,16 @@ GAPI_FLUID_KERNEL(GFluidSplit4, cv::gapi::core::GSplit4, false)
|
||||
|
||||
static void run(const View &src, Buffer &dst1, Buffer &dst2, Buffer &dst3, Buffer &dst4)
|
||||
{
|
||||
GAPI_Assert((src.meta().depth == CV_8U) && (dst1.meta().depth == CV_8U) &&
|
||||
(dst2.meta().depth == CV_8U) && (dst3.meta().depth == CV_8U) &&
|
||||
(dst4.meta().depth == CV_8U) && (4 == src.meta().chan));
|
||||
|
||||
const auto *in = src.InLine<uchar>(0);
|
||||
auto *out1 = dst1.OutLine<uchar>();
|
||||
auto *out2 = dst2.OutLine<uchar>();
|
||||
auto *out3 = dst3.OutLine<uchar>();
|
||||
auto *out4 = dst4.OutLine<uchar>();
|
||||
|
||||
GAPI_Assert(4 == src.meta().chan);
|
||||
int width = src.length();
|
||||
int w = 0;
|
||||
|
||||
@@ -2372,31 +2378,46 @@ GAPI_FLUID_KERNEL(GFluidSplit4, cv::gapi::core::GSplit4, false)
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
CV_ALWAYS_INLINE void run_merge3(Buffer& dst, const View& src1, const View& src2, const View& src3)
|
||||
{
|
||||
const auto* in1 = src1.InLine<T>(0);
|
||||
const auto* in2 = src2.InLine<T>(0);
|
||||
const auto* in3 = src3.InLine<T>(0);
|
||||
auto* out = dst.OutLine<T>();
|
||||
|
||||
int width = dst.length();
|
||||
int w = 0;
|
||||
|
||||
#if CV_SIMD
|
||||
w = merge3_simd(in1, in2, in3, out, width);
|
||||
#endif
|
||||
|
||||
for (; w < width; w++)
|
||||
{
|
||||
out[3 * w] = in1[w];
|
||||
out[3 * w + 1] = in2[w];
|
||||
out[3 * w + 2] = in3[w];
|
||||
}
|
||||
}
|
||||
|
||||
GAPI_FLUID_KERNEL(GFluidMerge3, cv::gapi::core::GMerge3, false)
|
||||
{
|
||||
static const int Window = 1;
|
||||
|
||||
static void run(const View &src1, const View &src2, const View &src3, Buffer &dst)
|
||||
static void run(const View& src1, const View& src2, const View& src3, Buffer& dst)
|
||||
{
|
||||
const auto *in1 = src1.InLine<uchar>(0);
|
||||
const auto *in2 = src2.InLine<uchar>(0);
|
||||
const auto *in3 = src3.InLine<uchar>(0);
|
||||
auto *out = dst.OutLine<uchar>();
|
||||
GAPI_Assert((src1.meta().depth == dst.meta().depth) &&
|
||||
(src1.meta().depth == src2.meta().depth) &&
|
||||
(src1.meta().depth == src3.meta().depth));
|
||||
|
||||
GAPI_Assert(3 == dst.meta().chan);
|
||||
int width = dst.length();
|
||||
int w = 0;
|
||||
// SRC/DST TYPE OP __VA_ARGS__
|
||||
MERGE3_(uchar, run_merge3, dst, src1, src2, src3);
|
||||
MERGE3_(ushort, run_merge3, dst, src1, src2, src3);
|
||||
MERGE3_(short, run_merge3, dst, src1, src2, src3);
|
||||
MERGE3_(float, run_merge3, dst, src1, src2, src3);
|
||||
|
||||
#if CV_SIMD
|
||||
w = merge3_simd(in1, in2, in3, out, width);
|
||||
#endif
|
||||
|
||||
for (; w < width; w++)
|
||||
{
|
||||
out[3*w ] = in1[w];
|
||||
out[3*w + 1] = in2[w];
|
||||
out[3*w + 2] = in3[w];
|
||||
}
|
||||
CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2407,13 +2428,16 @@ GAPI_FLUID_KERNEL(GFluidMerge4, cv::gapi::core::GMerge4, false)
|
||||
static void run(const View &src1, const View &src2, const View &src3, const View &src4,
|
||||
Buffer &dst)
|
||||
{
|
||||
GAPI_Assert((dst.meta().depth == CV_8U) && (src1.meta().depth == CV_8U) &&
|
||||
(src2.meta().depth == CV_8U) && (src3.meta().depth == CV_8U) &&
|
||||
(4 == dst.meta().chan));
|
||||
|
||||
const auto *in1 = src1.InLine<uchar>(0);
|
||||
const auto *in2 = src2.InLine<uchar>(0);
|
||||
const auto *in3 = src3.InLine<uchar>(0);
|
||||
const auto *in4 = src4.InLine<uchar>(0);
|
||||
auto *out = dst.OutLine<uchar>();
|
||||
|
||||
GAPI_Assert(4 == dst.meta().chan);
|
||||
int width = dst.length();
|
||||
|
||||
int w = 0; // cycle counter
|
||||
|
||||
@@ -277,13 +277,21 @@ int split4_simd(const uchar in[], uchar out1[], uchar out2[],
|
||||
CV_CPU_DISPATCH_MODES_ALL);
|
||||
}
|
||||
|
||||
int merge3_simd(const uchar in1[], const uchar in2[], const uchar in3[],
|
||||
uchar out[], const int width)
|
||||
{
|
||||
CV_CPU_DISPATCH(merge3_simd, (in1, in2, in3, out, width),
|
||||
CV_CPU_DISPATCH_MODES_ALL);
|
||||
#define MERGE3_SIMD(T) \
|
||||
int merge3_simd(const T in1[], const T in2[], const T in3[], \
|
||||
T out[], const int width) \
|
||||
{ \
|
||||
CV_CPU_DISPATCH(merge3_simd, (in1, in2, in3, out, width), \
|
||||
CV_CPU_DISPATCH_MODES_ALL); \
|
||||
}
|
||||
|
||||
MERGE3_SIMD(uchar)
|
||||
MERGE3_SIMD(short)
|
||||
MERGE3_SIMD(ushort)
|
||||
MERGE3_SIMD(float)
|
||||
|
||||
#undef MERGE3_SIMD
|
||||
|
||||
int merge4_simd(const uchar in1[], const uchar in2[], const uchar in3[],
|
||||
const uchar in4[], uchar out[], const int width)
|
||||
{
|
||||
|
||||
@@ -216,8 +216,16 @@ int split3_simd(const uchar in[], uchar out1[], uchar out2[],
|
||||
int split4_simd(const uchar in[], uchar out1[], uchar out2[],
|
||||
uchar out3[], uchar out4[], const int width);
|
||||
|
||||
int merge3_simd(const uchar in1[], const uchar in2[], const uchar in3[],
|
||||
uchar out[], const int width);
|
||||
#define MERGE3_SIMD(T) \
|
||||
int merge3_simd(const T in1[], const T in2[], const T in3[], \
|
||||
T out[], const int width);
|
||||
|
||||
MERGE3_SIMD(uchar)
|
||||
MERGE3_SIMD(short)
|
||||
MERGE3_SIMD(ushort)
|
||||
MERGE3_SIMD(float)
|
||||
|
||||
#undef MERGE3_SIMD
|
||||
|
||||
int merge4_simd(const uchar in1[], const uchar in2[], const uchar in3[],
|
||||
const uchar in4[], uchar out[], const int width);
|
||||
|
||||
@@ -322,12 +322,21 @@ int split3_simd(const uchar in[], uchar out1[], uchar out2[],
|
||||
int split4_simd(const uchar in[], uchar out1[], uchar out2[],
|
||||
uchar out3[], uchar out4[], const int width);
|
||||
|
||||
int merge3_simd(const uchar in1[], const uchar in2[], const uchar in3[],
|
||||
uchar out[], const int width);
|
||||
#define MERGE3_SIMD(T) \
|
||||
int merge3_simd(const T in1[], const T in2[], const T in3[], \
|
||||
T out[], const int width);
|
||||
|
||||
MERGE3_SIMD(uchar)
|
||||
MERGE3_SIMD(short)
|
||||
MERGE3_SIMD(ushort)
|
||||
MERGE3_SIMD(float)
|
||||
|
||||
#undef MERGE3_SIMD
|
||||
|
||||
int merge4_simd(const uchar in1[], const uchar in2[], const uchar in3[],
|
||||
const uchar in4[], uchar out[], const int width);
|
||||
|
||||
|
||||
#ifndef CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
|
||||
|
||||
#define SRC_SHORT_OR_USHORT std::is_same<SRC, short>::value || std::is_same<SRC, ushort>::value
|
||||
@@ -2530,34 +2539,42 @@ int split4_simd(const uchar in[], uchar out1[], uchar out2[],
|
||||
//
|
||||
//-------------------------
|
||||
|
||||
int merge3_simd(const uchar in1[], const uchar in2[], const uchar in3[],
|
||||
uchar out[], const int width)
|
||||
{
|
||||
constexpr int nlanes = v_uint8::nlanes;
|
||||
if (width < nlanes)
|
||||
return 0;
|
||||
|
||||
int x = 0;
|
||||
for (;;)
|
||||
{
|
||||
for (; x <= width - nlanes; x += nlanes)
|
||||
{
|
||||
v_uint8 a, b, c;
|
||||
a = vx_load(&in1[x]);
|
||||
b = vx_load(&in2[x]);
|
||||
c = vx_load(&in3[x]);
|
||||
v_store_interleave(&out[3 * x], a, b, c);
|
||||
}
|
||||
if (x < width)
|
||||
{
|
||||
x = width - nlanes;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return x;
|
||||
#define MERGE3_SIMD(T) \
|
||||
int merge3_simd(const T in1[], const T in2[], const T in3[], \
|
||||
T out[], const int width) \
|
||||
{ \
|
||||
constexpr int nlanes = vector_type_of_t<T>::nlanes; \
|
||||
if (width < nlanes) \
|
||||
return 0; \
|
||||
\
|
||||
int x = 0; \
|
||||
for (;;) \
|
||||
{ \
|
||||
for (; x <= width - nlanes; x += nlanes) \
|
||||
{ \
|
||||
vector_type_of_t<T> a, b, c; \
|
||||
a = vx_load(&in1[x]); \
|
||||
b = vx_load(&in2[x]); \
|
||||
c = vx_load(&in3[x]); \
|
||||
v_store_interleave(&out[3 * x], a, b, c); \
|
||||
} \
|
||||
if (x < width) \
|
||||
{ \
|
||||
x = width - nlanes; \
|
||||
continue; \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
return x; \
|
||||
}
|
||||
|
||||
MERGE3_SIMD(uchar)
|
||||
MERGE3_SIMD(short)
|
||||
MERGE3_SIMD(ushort)
|
||||
MERGE3_SIMD(float)
|
||||
|
||||
#undef MERGE3_SIMD
|
||||
|
||||
//-------------------------
|
||||
//
|
||||
// Fluid kernels: Merge4
|
||||
@@ -2926,6 +2943,8 @@ CV_ALWAYS_INLINE void convertto_simd_nocoeff_impl(const SRC* inx, float* outx)
|
||||
int convertto_simd(const SRC in[], DST out[], const int length) \
|
||||
{ \
|
||||
constexpr int nlanes = vector_type_of_t<DST>::nlanes; \
|
||||
if (length < nlanes) \
|
||||
return 0; \
|
||||
\
|
||||
int x = 0; \
|
||||
for (;;) \
|
||||
@@ -3093,6 +3112,9 @@ int convertto_scaled_simd(const SRC in[], DST out[], const float alpha, \
|
||||
const float beta, const int length) \
|
||||
{ \
|
||||
constexpr int nlanes = vector_type_of_t<DST>::nlanes; \
|
||||
if (length < nlanes) \
|
||||
return 0; \
|
||||
\
|
||||
v_float32 v_alpha = vx_setall_f32(alpha); \
|
||||
v_float32 v_beta = vx_setall_f32(beta); \
|
||||
\
|
||||
|
||||
@@ -86,6 +86,23 @@ using cv::gapi::own::rintd;
|
||||
return; \
|
||||
}
|
||||
|
||||
#define MERGE3_(T, OP, ...) \
|
||||
if (cv::DataType<T>::depth == dst.meta().depth && \
|
||||
cv::DataType<T>::depth == src1.meta().depth) \
|
||||
{ \
|
||||
GAPI_DbgAssert(dst.length() == src1.length()); \
|
||||
GAPI_DbgAssert(dst.length() == src2.length()); \
|
||||
GAPI_DbgAssert(dst.length() == src3.length()); \
|
||||
\
|
||||
GAPI_DbgAssert(1 == src1.meta().chan); \
|
||||
GAPI_DbgAssert(1 == src2.meta().chan); \
|
||||
GAPI_DbgAssert(1 == src3.meta().chan); \
|
||||
GAPI_DbgAssert(3 == dst.meta().chan); \
|
||||
\
|
||||
OP<T>(__VA_ARGS__); \
|
||||
return; \
|
||||
}
|
||||
|
||||
} // namespace fluid
|
||||
} // 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) 2018-2022 Intel Corporation
|
||||
// Copyright (C) 2018-2023 Intel Corporation
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
@@ -71,6 +71,28 @@ namespace IE = InferenceEngine;
|
||||
|
||||
namespace {
|
||||
|
||||
IE::Layout toIE(const std::string &layout) {
|
||||
const std::unordered_map<std::string, IE::Layout> layouts = {
|
||||
{"NCDHW", IE::Layout::NCDHW},
|
||||
{"NDHWC", IE::Layout::NDHWC},
|
||||
{"NHWC" , IE::Layout::NHWC },
|
||||
{"NCHW" , IE::Layout::NCHW },
|
||||
{"CHW" , IE::Layout::CHW },
|
||||
{"HWC" , IE::Layout::HWC },
|
||||
{"HW" , IE::Layout::HW },
|
||||
{"NC" , IE::Layout::NC },
|
||||
{"CN" , IE::Layout::CN },
|
||||
{"C" , IE::Layout::C },
|
||||
};
|
||||
|
||||
const auto it = layouts.find(layout);
|
||||
if (it == layouts.end()) {
|
||||
cv::util::throw_error(
|
||||
std::logic_error("IE Backend: Unsupported layout: " + layout));
|
||||
}
|
||||
return it->second;
|
||||
};
|
||||
|
||||
inline IE::ROI toIE(const cv::Rect &rc) {
|
||||
return IE::ROI
|
||||
{ 0u
|
||||
@@ -130,11 +152,90 @@ inline int toCV(IE::Precision prec) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline IE::ResizeAlgorithm toIEInterp(int interpolation) {
|
||||
switch (interpolation) {
|
||||
case cv::INTER_LINEAR: return IE::RESIZE_BILINEAR;
|
||||
case cv::INTER_AREA: return IE::RESIZE_AREA;
|
||||
default: GAPI_Error("IE Backend: Unsupported resize algorithm");
|
||||
}
|
||||
// Unreachable code
|
||||
GAPI_Assert(false);
|
||||
}
|
||||
|
||||
template <typename Attr>
|
||||
using AttrMap = cv::gapi::ie::detail::AttrMap<Attr>;
|
||||
|
||||
template <typename Attr>
|
||||
using LayerVariantAttr = cv::gapi::ie::detail::LayerVariantAttr<Attr>;
|
||||
|
||||
template <typename Attr> AttrMap<Attr>
|
||||
broadcastLayerAttr(const LayerVariantAttr<Attr> &layer_attr,
|
||||
const std::vector<std::string> &layer_names) {
|
||||
AttrMap<Attr> map;
|
||||
if (cv::util::holds_alternative<AttrMap<Attr>>(layer_attr)) {
|
||||
map = cv::util::get<AttrMap<Attr>>(layer_attr);
|
||||
// NB: Validate map:
|
||||
std::unordered_set<std::string> existing_layers =
|
||||
{layer_names.begin(), layer_names.end()};
|
||||
|
||||
for (const auto &p : map) {
|
||||
const auto it = existing_layers.find(p.first);
|
||||
if (it == existing_layers.end()) {
|
||||
cv::util::throw_error(
|
||||
std::logic_error("IE Backend: Failed to"
|
||||
" find layer with name: " + p.first));
|
||||
}
|
||||
}
|
||||
} else if (cv::util::holds_alternative<Attr>(layer_attr)) {
|
||||
// NB: Broadcast value to all layers.
|
||||
auto elem = cv::util::get<Attr>(layer_attr);
|
||||
for (auto &&layer_name : layer_names) {
|
||||
map.emplace(layer_name, elem);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// TODO: Move it to some common place
|
||||
template <typename K, typename V>
|
||||
cv::optional<V> lookUp(const std::map<K, V> &map, const K& key) {
|
||||
const auto it = map.find(key);
|
||||
if (it == map.end()) {
|
||||
return {};
|
||||
}
|
||||
return cv::util::make_optional(std::move(it->second));
|
||||
}
|
||||
|
||||
static bool isImage(const cv::GMatDesc &desc,
|
||||
const IE::SizeVector &model_dims) {
|
||||
return (model_dims.size() == 4u) &&
|
||||
(!desc.isND()) /* dims == 2 */ &&
|
||||
(desc.chan == 1 || desc.chan == 3) &&
|
||||
(desc.size.height != 1 && desc.size.width != 1) &&
|
||||
(desc.depth == CV_8U);
|
||||
}
|
||||
|
||||
cv::gapi::ie::TraitAs clarifyTrait(const cv::GMatDesc &mat_desc,
|
||||
const IE::SizeVector &model_dims) {
|
||||
if (isImage(mat_desc, model_dims)) {
|
||||
return cv::gapi::ie::TraitAs::IMAGE;
|
||||
}
|
||||
return cv::gapi::ie::TraitAs::TENSOR;
|
||||
}
|
||||
|
||||
cv::gapi::ie::TraitAs clarifyTrait(const cv::GMetaArg &meta,
|
||||
const IE::SizeVector &model_dims) {
|
||||
// NB: All media formats: BGR, NV12, Gray
|
||||
// are traited as image.
|
||||
if (cv::util::holds_alternative<cv::GFrameDesc>(meta)) {
|
||||
return cv::gapi::ie::TraitAs::IMAGE;
|
||||
}
|
||||
GAPI_Assert(cv::util::holds_alternative<cv::GMatDesc>(meta));
|
||||
return clarifyTrait(cv::util::get<cv::GMatDesc>(meta), model_dims);
|
||||
}
|
||||
|
||||
inline IE::TensorDesc toIE(const cv::Mat &mat, cv::gapi::ie::TraitAs hint) {
|
||||
const auto &sz = mat.size;
|
||||
// NB: For some reason RGB image is 2D image
|
||||
// (since channel component is not counted here).
|
||||
// Note: regular 2D vectors also fall into this category
|
||||
if (sz.dims() == 2 && hint == cv::gapi::ie::TraitAs::IMAGE)
|
||||
{
|
||||
// NB: This logic is mainly taken from IE samples
|
||||
@@ -155,8 +256,72 @@ inline IE::TensorDesc toIE(const cv::Mat &mat, cv::gapi::ie::TraitAs hint) {
|
||||
return IE::TensorDesc(toIE(mat.depth()), toIE(sz), toIELayout(sz.dims()));
|
||||
}
|
||||
|
||||
inline IE::Blob::Ptr wrapIE(const cv::Mat &mat, cv::gapi::ie::TraitAs hint) {
|
||||
const auto tDesc = toIE(mat, hint);
|
||||
// NB: Inference dimmensions always follow NCDHW order
|
||||
// even though the real layout is different.
|
||||
// E.g if user provided Mat({1, 240, 320, 3}, CV_8U) + NHWC layout
|
||||
// need to create Blob(U8, {1, 3, 240, 320}, NHWC).
|
||||
inline IE::SizeVector toIEDims(const IE::SizeVector &dims,
|
||||
const IE::Layout layout) {
|
||||
switch (layout) {
|
||||
case IE::Layout::NDHWC: // NCDHW
|
||||
return {dims[0], dims[4], dims[1], dims[2], dims[3]};
|
||||
case IE::Layout::NHWC: // NCHW
|
||||
return {dims[0], dims[3], dims[1], dims[2]};
|
||||
case IE::Layout::HWC: // CHW
|
||||
return {dims[2], dims[0], dims[1]};
|
||||
default: return dims;
|
||||
}
|
||||
GAPI_Assert(false);
|
||||
}
|
||||
|
||||
// NB: Inference dimmensions always follow NCDHW order
|
||||
// even though the real layout is different.
|
||||
// E.g if U8 blob has {1, 3, 240, 320} dims and NHWC layout
|
||||
// need to create cv::Mat({1, 240, 320, 3}, CV_8U);
|
||||
inline std::vector<int> toCVDims(const std::vector<int> &dims,
|
||||
const IE::Layout layout) {
|
||||
switch (layout) {
|
||||
case IE::Layout::NDHWC: // NCDHW
|
||||
return {dims[0], dims[2], dims[3], dims[4], dims[1]};
|
||||
case IE::Layout::NHWC: // NCHW
|
||||
return {dims[0], dims[2], dims[3], dims[1]};
|
||||
case IE::Layout::HWC: // CHW
|
||||
return {dims[1], dims[2], dims[0]};
|
||||
default: return dims;
|
||||
}
|
||||
GAPI_Assert(false);
|
||||
}
|
||||
|
||||
inline IE::TensorDesc toIE(const cv::Mat &mat,
|
||||
const cv::gapi::ie::TraitAs hint,
|
||||
const IE::Layout layout) {
|
||||
const auto &sz = mat.size;
|
||||
if (sz.dims() == 2 && hint == cv::gapi::ie::TraitAs::IMAGE)
|
||||
{
|
||||
// NB: This logic is mainly taken from IE samples
|
||||
const size_t channels = mat.channels();
|
||||
const size_t height = mat.size().height;
|
||||
const size_t width = mat.size().width;
|
||||
|
||||
const size_t strideH = mat.step1();
|
||||
IE::BlockingDesc bdesc({1, height, width, channels} /* blocking dims */,
|
||||
{0, 2, 3, 1} /* order for NHWC */,
|
||||
0 /* offset */,
|
||||
{0, 0, 0, 0} /* offsets for dims */,
|
||||
{strideH * height, strideH, channels, 1} /* strides for dims */);
|
||||
|
||||
return IE::TensorDesc(toIE(mat.depth()),
|
||||
IE::SizeVector{1, channels, height, width}, bdesc);
|
||||
}
|
||||
return IE::TensorDesc(toIE(mat.depth()),
|
||||
toIEDims(toIE(sz), layout),
|
||||
layout);
|
||||
}
|
||||
|
||||
inline IE::Blob::Ptr wrapIE(const cv::Mat &mat,
|
||||
cv::gapi::ie::TraitAs hint,
|
||||
const IE::Layout layout = IE::Layout::ANY) {
|
||||
const auto tDesc = toIE(mat, hint, layout);
|
||||
switch (mat.depth()) {
|
||||
// NB: Seems there's no way to create an untyped (T-less) Blob::Ptr
|
||||
// in IE given only precision via TensorDesc. So we have to do this:
|
||||
@@ -303,6 +468,7 @@ struct IEUnit {
|
||||
};
|
||||
|
||||
InputFramesDesc net_input_params;
|
||||
std::unordered_map<std::string, cv::gapi::ie::TraitAs> inputs_type;
|
||||
|
||||
explicit IEUnit(const cv::gapi::ie::detail::ParamDesc &pp)
|
||||
: params(pp) {
|
||||
@@ -481,6 +647,8 @@ public:
|
||||
cv::GRunArgP output (std::size_t idx);
|
||||
cv::Mat& outMatR(std::size_t idx);
|
||||
|
||||
cv::gapi::ie::TraitAs getInputType(const std::string &layer_name) const;
|
||||
|
||||
const IEUnit &uu;
|
||||
cv::gimpl::GIslandExecutable::IOutput &out;
|
||||
|
||||
@@ -524,6 +692,9 @@ private:
|
||||
// keep alive preprocessed frames
|
||||
std::mutex keep_alive_frames_mutex;
|
||||
std::unordered_map<req_key_t, cv::MediaFrame> keep_alive_pp_frames;
|
||||
|
||||
// NB: Hint to wrap input data properly into IE::Blob (see: wrapIE)
|
||||
std::unordered_map<std::string, cv::gapi::ie::TraitAs> input_type;
|
||||
};
|
||||
|
||||
IECallContext::IECallContext(const IEUnit & unit,
|
||||
@@ -558,6 +729,16 @@ IECallContext::IECallContext(const IEUnit &
|
||||
}
|
||||
}
|
||||
|
||||
cv::gapi::ie::TraitAs
|
||||
IECallContext::getInputType(const std::string &layer_name) const {
|
||||
const auto it = uu.inputs_type.find(layer_name);
|
||||
if (it == uu.inputs_type.end()) {
|
||||
cv::util::throw_error(std::logic_error(
|
||||
"Failed to find input type for layer: \"" + layer_name + "\""));
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
const cv::GArgs& IECallContext::inArgs() const {
|
||||
return m_args;
|
||||
}
|
||||
@@ -732,7 +913,8 @@ cv::MediaFrame preprocess_frame_impl(cv::MediaFrame &&in_frame, const std::strin
|
||||
|
||||
inline IE::Blob::Ptr extractBlob(IECallContext& ctx,
|
||||
std::size_t i,
|
||||
cv::gapi::ie::TraitAs hint,
|
||||
const cv::gapi::ie::TraitAs hint,
|
||||
const IE::Layout &layout,
|
||||
const std::string& layer_name,
|
||||
const cv::util::optional<cv::Rect> &opt_roi,
|
||||
cv::MediaFrame* out_keep_alive_frame = nullptr,
|
||||
@@ -780,7 +962,7 @@ inline IE::Blob::Ptr extractBlob(IECallContext& ctx,
|
||||
return wrapIE(*(ctx.views.back()), frame.desc());
|
||||
}
|
||||
case cv::GShape::GMAT: {
|
||||
return wrapIE(ctx.inMat(i), hint);
|
||||
return wrapIE(ctx.inMat(i), hint, layout);
|
||||
}
|
||||
default:
|
||||
GAPI_Assert("Unsupported input shape for IE backend");
|
||||
@@ -788,7 +970,6 @@ inline IE::Blob::Ptr extractBlob(IECallContext& ctx,
|
||||
GAPI_Error("InternalError");
|
||||
}
|
||||
|
||||
|
||||
static void setBlob(InferenceEngine::InferRequest& req,
|
||||
const std::string& layer_name,
|
||||
const IE::Blob::Ptr& blob,
|
||||
@@ -1162,55 +1343,109 @@ static void configureInputReshapeByImage(const IE::InputInfo::Ptr& ii,
|
||||
input_reshape_table.emplace(layer_name, input_dims);
|
||||
}
|
||||
|
||||
static void configureInputInfo(const IE::InputInfo::Ptr& ii, const cv::GMetaArg mm) {
|
||||
static void cfgInputPrecision(const IE::InputInfo::Ptr& ii, const cv::GMetaArg mm) {
|
||||
switch (mm.index()) {
|
||||
case cv::GMetaArg::index_of<cv::GMatDesc>():
|
||||
{
|
||||
ii->setPrecision(toIE(util::get<cv::GMatDesc>(mm).depth));
|
||||
case cv::GMetaArg::index_of<cv::GMatDesc>(): {
|
||||
const auto &desc = util::get<cv::GMatDesc>(mm);
|
||||
ii->setPrecision(toIE(desc.depth));
|
||||
break;
|
||||
}
|
||||
case cv::GMetaArg::index_of<cv::GFrameDesc>():
|
||||
{
|
||||
const auto &meta = util::get<cv::GFrameDesc>(mm);
|
||||
switch (meta.fmt) {
|
||||
case cv::MediaFormat::NV12:
|
||||
ii->getPreProcess().setColorFormat(IE::ColorFormat::NV12);
|
||||
break;
|
||||
case cv::MediaFormat::BGR:
|
||||
// NB: Do nothing
|
||||
break;
|
||||
case cv::MediaFormat::GRAY:
|
||||
// NB: Do nothing
|
||||
break;
|
||||
default:
|
||||
GAPI_Error("Unsupported media format for IE backend");
|
||||
}
|
||||
ii->setPrecision(toIE(CV_8U));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
util::throw_error(std::runtime_error("Unsupported input meta for IE backend"));
|
||||
}
|
||||
}
|
||||
|
||||
static bool isApplicableForResize(const IE::TensorDesc& desc) {
|
||||
const auto layout = desc.getLayout();
|
||||
const auto prec = desc.getPrecision();
|
||||
return (layout == IE::Layout::NCHW || layout == IE::Layout::NHWC) &&
|
||||
(prec == IE::Precision::FP32 || prec == IE::Precision::U8);
|
||||
static void cfgImagePreprocessing(const IE::InputInfo::Ptr &ii,
|
||||
const cv::GMetaArg &mm,
|
||||
const IE::ResizeAlgorithm interp) {
|
||||
if (!cv::util::holds_alternative<cv::GMatDesc>(mm) &&
|
||||
!cv::util::holds_alternative<cv::GFrameDesc>(mm)) {
|
||||
util::throw_error(std::runtime_error("Unsupported input meta for IE backend"));
|
||||
}
|
||||
|
||||
ii->getPreProcess().setResizeAlgorithm(interp);
|
||||
if (cv::util::holds_alternative<cv::GFrameDesc>(mm)) {
|
||||
const auto &meta = util::get<cv::GFrameDesc>(mm);
|
||||
if (meta.fmt == cv::MediaFormat::NV12) {
|
||||
ii->getPreProcess().setColorFormat(IE::ColorFormat::NV12);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static IE::PreProcessInfo configurePreProcInfo(const IE::InputInfo::CPtr& ii,
|
||||
const cv::GMetaArg& mm) {
|
||||
// NB: This function is used in order to configure
|
||||
// preprocessing for "Load" case networks.
|
||||
static void cfgInputPreprocessing(const cv::gapi::ie::TraitAs trait,
|
||||
const IE::InputInfo::Ptr &ii,
|
||||
const cv::GMetaArg &mm,
|
||||
const std::string &layer_name,
|
||||
const AttrMap<std::string> &layout_map,
|
||||
const AttrMap<int> &interp_map) {
|
||||
cfgInputPrecision(ii, mm);
|
||||
const auto explicit_input_layout = lookUp(layout_map, layer_name);
|
||||
const auto explicit_resize = lookUp(interp_map, layer_name);
|
||||
if (trait == cv::gapi::ie::TraitAs::IMAGE) {
|
||||
// NB: Image case - preprocessing is configured automatically.
|
||||
GAPI_LOG_DEBUG(NULL, "IE Backend: Input: \"" <<
|
||||
layer_name << " " << mm << "\" is image.");
|
||||
// NB: BlockingDesc is used instead (see wrapIE)
|
||||
if (explicit_input_layout) {
|
||||
util::throw_error(std::logic_error("Input data provided for layer: \"" +
|
||||
layer_name + "\" is recognized as \"image\". Explicitly" +
|
||||
" specified layout is prohibited."));
|
||||
}
|
||||
const auto interp = explicit_resize ? toIEInterp(*explicit_resize)
|
||||
: IE::RESIZE_BILINEAR;
|
||||
cfgImagePreprocessing(ii, mm, interp);
|
||||
} else {
|
||||
// NB: Tensor case - preprocessing is configured only if user asked.
|
||||
GAPI_LOG_DEBUG(NULL, "IE Backend: Input: \"" <<
|
||||
layer_name << "\" " << mm << " is tensor.");
|
||||
if (explicit_input_layout) {
|
||||
GAPI_LOG_DEBUG(NULL, "IE Backend: Set input layout \"" <<
|
||||
*explicit_input_layout << "\" for layer \"" << layer_name << "\"");
|
||||
ii->setLayout(toIE(*explicit_input_layout));
|
||||
}
|
||||
if (explicit_resize) {
|
||||
GAPI_LOG_DEBUG(NULL, "IE Backend: Set resize for layer \"" << layer_name << "\"");
|
||||
ii->getPreProcess().setResizeAlgorithm(toIEInterp(*explicit_resize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static IE::PreProcessInfo createImagePreProcInfo(const cv::GMetaArg &mm,
|
||||
const IE::ResizeAlgorithm interp) {
|
||||
if (!cv::util::holds_alternative<cv::GMatDesc>(mm) &&
|
||||
!cv::util::holds_alternative<cv::GFrameDesc>(mm)) {
|
||||
util::throw_error(std::runtime_error("Unsupported input meta for IE backend"));
|
||||
}
|
||||
IE::PreProcessInfo info;
|
||||
info.setResizeAlgorithm(interp);
|
||||
if (cv::util::holds_alternative<cv::GFrameDesc>(mm)) {
|
||||
auto desc = cv::util::get<cv::GFrameDesc>(mm);
|
||||
if (desc.fmt == cv::MediaFormat::NV12) {
|
||||
const auto &meta = util::get<cv::GFrameDesc>(mm);
|
||||
if (meta.fmt == cv::MediaFormat::NV12) {
|
||||
info.setColorFormat(IE::ColorFormat::NV12);
|
||||
}
|
||||
}
|
||||
if (isApplicableForResize(ii->getTensorDesc())) {
|
||||
info.setResizeAlgorithm(IE::RESIZE_BILINEAR);
|
||||
return info;
|
||||
}
|
||||
|
||||
// NB: This function is used in order to create
|
||||
// preprocessing for "Import" case networks.
|
||||
static IE::PreProcessInfo createPreProcInfo(const cv::gapi::ie::TraitAs trait,
|
||||
const cv::GMetaArg& mm,
|
||||
const cv::optional<int> explicit_resize) {
|
||||
if (trait == cv::gapi::ie::TraitAs::IMAGE) {
|
||||
const auto interp = explicit_resize ? toIEInterp(*explicit_resize)
|
||||
: IE::RESIZE_BILINEAR;
|
||||
return createImagePreProcInfo(mm, interp);
|
||||
}
|
||||
// NB: In case "tensor" only resize can't be spefied for "import" models.
|
||||
IE::PreProcessInfo info;
|
||||
if (explicit_resize) {
|
||||
info.setResizeAlgorithm(toIEInterp(*explicit_resize));
|
||||
}
|
||||
return info;
|
||||
}
|
||||
@@ -1237,6 +1472,13 @@ static void configureOutputPrecision(const IE::OutputsDataMap &outputs
|
||||
);
|
||||
}
|
||||
|
||||
static void configureOutputLayout(const IE::OutputsDataMap &outputs_info,
|
||||
const AttrMap<std::string> &output_layout) {
|
||||
for (const auto it : output_layout) {
|
||||
outputs_info.at(it.first)->setLayout(toIE(it.second));
|
||||
}
|
||||
}
|
||||
|
||||
// NB: This is a callback used by async infer
|
||||
// to post outputs blobs (cv::GMat's).
|
||||
static void PostOutputs(InferenceEngine::InferRequest &request,
|
||||
@@ -1356,6 +1598,10 @@ struct Infer: public cv::detail::KernelTag {
|
||||
GAPI_Assert(uu.params.input_names.size() == in_metas.size()
|
||||
&& "Known input layers count doesn't match input meta count");
|
||||
|
||||
const auto input_layout = broadcastLayerAttr(uu.params.input_layout,
|
||||
uu.params.input_names);
|
||||
const auto interpolation = broadcastLayerAttr(uu.params.interpolation,
|
||||
uu.params.input_names);
|
||||
// NB: Configuring input/output precision and network reshape must be done
|
||||
// only in the loadNetwork case.
|
||||
using namespace cv::gapi::ie::detail;
|
||||
@@ -1365,25 +1611,24 @@ struct Infer: public cv::detail::KernelTag {
|
||||
ade::util::toRange(in_metas))) {
|
||||
const auto &input_name = std::get<0>(it);
|
||||
auto ii = inputs.at(input_name);
|
||||
const auto & mm = std::get<1>(it);
|
||||
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);
|
||||
}
|
||||
|
||||
if (isApplicableForResize(ii->getTensorDesc())) {
|
||||
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
|
||||
}
|
||||
|
||||
const auto trait = clarifyTrait(mm, ii->getTensorDesc().getDims());
|
||||
// FIXME: This is the only place where information about input type
|
||||
// can be stored for the futher execution.
|
||||
const_cast<IEUnit&>(uu).inputs_type.emplace(input_name, trait);
|
||||
cfgInputPreprocessing(trait, ii, mm, input_name,
|
||||
input_layout, interpolation);
|
||||
// NB: configure input param for further preproc
|
||||
if (uu.net_input_params.is_applicable(mm)) {
|
||||
const_cast<IEUnit::InputFramesDesc &>(uu.net_input_params)
|
||||
.set_param(input_name, ii->getTensorDesc());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &&p : uu.params.const_inputs) {
|
||||
const auto ii = inputs.at(p.first);
|
||||
ii->setPrecision(toIE(p.second.first.depth()));
|
||||
@@ -1395,6 +1640,10 @@ struct Infer: public cv::detail::KernelTag {
|
||||
if (!input_reshape_table.empty()) {
|
||||
const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table);
|
||||
}
|
||||
|
||||
const auto output_layout = broadcastLayerAttr(uu.params.output_layout,
|
||||
uu.params.output_names);
|
||||
configureOutputLayout(uu.net.getOutputsInfo(), output_layout);
|
||||
configureOutputPrecision(uu.net.getOutputsInfo(), uu.params.output_precision);
|
||||
} else {
|
||||
GAPI_Assert(uu.params.kind == ParamDesc::Kind::Import);
|
||||
@@ -1406,7 +1655,13 @@ struct Infer: public cv::detail::KernelTag {
|
||||
const auto &input_name = std::get<0>(it);
|
||||
auto ii = inputs.at(input_name);
|
||||
const auto & mm = std::get<1>(it);
|
||||
non_const_prepm->emplace(input_name, configurePreProcInfo(ii, mm));
|
||||
const auto trait = clarifyTrait(mm, ii->getTensorDesc().getDims());
|
||||
// FIXME: This is the only place where information about input type
|
||||
// can be stored for the futher execution.
|
||||
const_cast<IEUnit&>(uu).inputs_type.emplace(input_name, trait);
|
||||
const auto explicit_resize = lookUp(interpolation, input_name);
|
||||
non_const_prepm->emplace(
|
||||
input_name, createPreProcInfo(trait, mm, explicit_resize));
|
||||
|
||||
// NB: configure input param for further preproc
|
||||
if (uu.net_input_params.is_applicable(mm)) {
|
||||
@@ -1428,7 +1683,7 @@ struct Infer: public cv::detail::KernelTag {
|
||||
: uu.this_network.GetOutputsInfo().at(out_name)->getTensorDesc();
|
||||
|
||||
cv::GMatDesc outm(toCV(desc.getPrecision()),
|
||||
toCV(desc.getDims()));
|
||||
toCVDims(toCV(desc.getDims()), desc.getLayout()));
|
||||
result.emplace_back(outm);
|
||||
}
|
||||
return result;
|
||||
@@ -1444,15 +1699,10 @@ struct Infer: public cv::detail::KernelTag {
|
||||
// - assumes all inputs/outputs are always Mats
|
||||
for (auto i : ade::util::iota(ctx->uu.params.num_in)) {
|
||||
const auto& layer_name = ctx->uu.params.input_names[i];
|
||||
auto layout =
|
||||
ctx->uu.this_network.GetInputsInfo().
|
||||
at(layer_name)->getTensorDesc().getLayout();
|
||||
auto hint =
|
||||
(layout == IE::Layout::NCHW || layout == IE::Layout::NHWC)
|
||||
? cv::gapi::ie::TraitAs::IMAGE : cv::gapi::ie::TraitAs::TENSOR;
|
||||
|
||||
const auto hint = ctx->getInputType(layer_name);
|
||||
const auto layout = req.GetBlob(layer_name)->getTensorDesc().getLayout();
|
||||
IE::Blob::Ptr this_blob = extractBlob(*ctx, i, hint,
|
||||
layer_name,
|
||||
layout, layer_name,
|
||||
cv::util::optional<cv::Rect>{});
|
||||
setBlob(req, layer_name, this_blob, *ctx);
|
||||
}
|
||||
@@ -1485,20 +1735,43 @@ struct InferROI: public cv::detail::KernelTag {
|
||||
|
||||
const auto &input_name = uu.params.input_names.at(0);
|
||||
auto &&mm = in_metas.at(1u);
|
||||
const auto &tensor_desc =
|
||||
(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load)
|
||||
? uu.net.getInputsInfo().at(input_name)->getTensorDesc()
|
||||
: uu.this_network.GetInputsInfo().at(input_name)->getTensorDesc();
|
||||
|
||||
if (cv::util::holds_alternative<cv::GMatDesc>(mm) ||
|
||||
cv::util::holds_alternative<cv::GFrameDesc>(mm)) {
|
||||
const auto trait = clarifyTrait(mm, tensor_desc.getDims());
|
||||
if (trait != cv::gapi::ie::TraitAs::IMAGE) {
|
||||
util::throw_error(std::runtime_error(
|
||||
"IE Backend: Only image is supported"
|
||||
" as the 1th argument for InferROI"));
|
||||
}
|
||||
} else {
|
||||
util::throw_error(std::runtime_error(
|
||||
"IE Backend: Unsupported input meta for"
|
||||
" 1th argument for InferROI"));
|
||||
}
|
||||
|
||||
// NB: Configuring input precision and network reshape must be done
|
||||
// only in the loadNetwork case.
|
||||
const auto input_layout = broadcastLayerAttr(uu.params.input_layout,
|
||||
uu.params.input_names);
|
||||
const auto interpolation = broadcastLayerAttr(uu.params.interpolation,
|
||||
uu.params.input_names);
|
||||
const auto trait = cv::gapi::ie::TraitAs::IMAGE;
|
||||
if (uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) {
|
||||
// 0th is ROI, 1st is input image
|
||||
auto inputs = uu.net.getInputsInfo();
|
||||
auto ii = inputs.at(input_name);
|
||||
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);
|
||||
}
|
||||
if (isApplicableForResize(ii->getTensorDesc())) {
|
||||
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
|
||||
}
|
||||
cfgInputPreprocessing(trait, ii, mm, input_name,
|
||||
input_layout, interpolation);
|
||||
|
||||
// FIXME: This isn't the best place to call reshape function.
|
||||
// Сorrect solution would be to do this in compile() method of network,
|
||||
@@ -1517,6 +1790,9 @@ struct InferROI: public cv::detail::KernelTag {
|
||||
inputs.at(p.first)->setPrecision(toIE(p.second.first.depth()));
|
||||
}
|
||||
|
||||
const auto output_layout = broadcastLayerAttr(uu.params.output_layout,
|
||||
uu.params.output_names);
|
||||
configureOutputLayout(uu.net.getOutputsInfo(), output_layout);
|
||||
configureOutputPrecision(uu.net.getOutputsInfo(), uu.params.output_precision);
|
||||
} else {
|
||||
GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import);
|
||||
@@ -1524,7 +1800,9 @@ struct InferROI: public cv::detail::KernelTag {
|
||||
// FIXME: This isn't the best place to collect PreProcMap.
|
||||
auto* non_const_prepm = const_cast<IEUnit::PreProcMap*>(&uu.preproc_map);
|
||||
auto ii = inputs.at(input_name);
|
||||
non_const_prepm->emplace(input_name, configurePreProcInfo(ii, mm));
|
||||
const auto explicit_resize = lookUp(interpolation, input_name);
|
||||
non_const_prepm->emplace(
|
||||
input_name, createPreProcInfo(trait, mm, explicit_resize));
|
||||
|
||||
// NB: configure intput param for further preproc
|
||||
if (uu.net_input_params.is_applicable(mm)) {
|
||||
@@ -1545,7 +1823,7 @@ struct InferROI: public cv::detail::KernelTag {
|
||||
: uu.this_network.GetOutputsInfo().at(out_name)->getTensorDesc();
|
||||
|
||||
cv::GMatDesc outm(toCV(desc.getPrecision()),
|
||||
toCV(desc.getDims()));
|
||||
toCVDims(toCV(desc.getDims()), desc.getLayout()));
|
||||
result.emplace_back(outm);
|
||||
}
|
||||
return result;
|
||||
@@ -1568,6 +1846,7 @@ struct InferROI: public cv::detail::KernelTag {
|
||||
bool preprocessed = false;
|
||||
IE::Blob::Ptr this_blob =
|
||||
extractBlob(*ctx, 1, cv::gapi::ie::TraitAs::IMAGE,
|
||||
IE::Layout::ANY,
|
||||
*(ctx->uu.params.input_names.begin()),
|
||||
cv::util::make_optional(this_roi),
|
||||
slot_ptr, &preprocessed);
|
||||
@@ -1613,20 +1892,31 @@ struct InferList: public cv::detail::KernelTag {
|
||||
|
||||
// NB: Configuring input precision and network reshape must be done
|
||||
// only in the loadNetwork case.
|
||||
const auto input_layout = broadcastLayerAttr(uu.params.input_layout,
|
||||
uu.params.input_names);
|
||||
const auto interpolation = broadcastLayerAttr(uu.params.interpolation,
|
||||
uu.params.input_names);
|
||||
if (uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) {
|
||||
std::size_t idx = 1u;
|
||||
auto inputs = uu.net.getInputsInfo();
|
||||
for (auto &&input_name : uu.params.input_names) {
|
||||
auto ii = inputs.at(input_name);
|
||||
const auto & mm = in_metas[idx++];
|
||||
configureInputInfo(ii, mm);
|
||||
|
||||
// NB: InferList expects the input starts with index 1 wil be the images.
|
||||
const auto input_trait = clarifyTrait(mm, ii->getTensorDesc().getDims());
|
||||
if (input_trait != cv::gapi::ie::TraitAs::IMAGE) {
|
||||
util::throw_error(std::runtime_error(
|
||||
"IE Backend: Only image is supported"
|
||||
" as the " + std::to_string(idx) + "th argument for InferList"));
|
||||
}
|
||||
|
||||
if (uu.params.layer_names_to_reshape.find(input_name) !=
|
||||
uu.params.layer_names_to_reshape.end()) {
|
||||
configureInputReshapeByImage(ii, mm, input_reshape_table);
|
||||
}
|
||||
if (isApplicableForResize(ii->getTensorDesc())) {
|
||||
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
|
||||
}
|
||||
cfgInputPreprocessing(input_trait, ii, mm,
|
||||
input_name, input_layout, interpolation);
|
||||
}
|
||||
|
||||
// FIXME: This isn't the best place to call reshape function.
|
||||
@@ -1641,6 +1931,9 @@ struct InferList: public cv::detail::KernelTag {
|
||||
ii->setPrecision(toIE(p.second.first.depth()));
|
||||
}
|
||||
|
||||
const auto output_layout = broadcastLayerAttr(uu.params.output_layout,
|
||||
uu.params.output_names);
|
||||
configureOutputLayout(uu.net.getOutputsInfo(), output_layout);
|
||||
configureOutputPrecision(uu.net.getOutputsInfo(), uu.params.output_precision);
|
||||
} else {
|
||||
GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import);
|
||||
@@ -1650,7 +1943,18 @@ struct InferList: public cv::detail::KernelTag {
|
||||
for (auto &&input_name : uu.params.input_names) {
|
||||
auto ii = inputs.at(input_name);
|
||||
const auto & mm = in_metas[idx++];
|
||||
non_const_prepm->emplace(input_name, configurePreProcInfo(ii, mm));
|
||||
|
||||
// NB: InferList expects the input starts with index 1 wil be the images.
|
||||
const auto input_trait = clarifyTrait(mm, ii->getTensorDesc().getDims());
|
||||
if (input_trait != cv::gapi::ie::TraitAs::IMAGE) {
|
||||
util::throw_error(std::runtime_error(
|
||||
"IE Backend: Only image is supported"
|
||||
" as the " + std::to_string(idx) + "th argument for InferList"));
|
||||
}
|
||||
|
||||
const auto explicit_resize = lookUp(interpolation, input_name);
|
||||
non_const_prepm->emplace(
|
||||
input_name, createPreProcInfo(input_trait, mm, explicit_resize));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1678,6 +1982,7 @@ struct InferList: public cv::detail::KernelTag {
|
||||
// NB: This blob will be used to make roi from its, so
|
||||
// it should be treated as image
|
||||
IE::Blob::Ptr this_blob = extractBlob(*ctx, 1, cv::gapi::ie::TraitAs::IMAGE,
|
||||
IE::Layout::ANY,
|
||||
ctx->uu.params.input_names[0u],
|
||||
cv::util::optional<cv::Rect>{});
|
||||
|
||||
@@ -1688,7 +1993,7 @@ struct InferList: public cv::detail::KernelTag {
|
||||
ctx->uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load
|
||||
? ctx->uu.net.getOutputsInfo().at(out_name)->getTensorDesc()
|
||||
: ctx->uu.this_network.GetOutputsInfo().at(out_name)->getTensorDesc();
|
||||
cached_dims[i] = toCV(desc.getDims());
|
||||
cached_dims[i] = toCVDims(toCV(desc.getDims()), desc.getLayout());
|
||||
// FIXME: Isn't this should be done automatically
|
||||
// by some resetInternalData(), etc? (Probably at the GExecutor level)
|
||||
auto& out_vec = ctx->outVecR<cv::Mat>(i);
|
||||
@@ -1744,51 +2049,52 @@ struct InferList2: public cv::detail::KernelTag {
|
||||
// "blob"-based ones)
|
||||
// FIXME: this is filtering not done, actually! GArrayDesc has
|
||||
// no hint for its underlying type!
|
||||
const auto &mm_0 = in_metas[0u];
|
||||
switch (in_metas[0u].index()) {
|
||||
case cv::GMetaArg::index_of<cv::GMatDesc>(): {
|
||||
const auto &meta_0 = util::get<cv::GMatDesc>(mm_0);
|
||||
GAPI_Assert( !meta_0.isND()
|
||||
&& !meta_0.planar
|
||||
&& "Only images are supported as the 0th argument");
|
||||
break;
|
||||
}
|
||||
case cv::GMetaArg::index_of<cv::GFrameDesc>(): {
|
||||
// FIXME: Is there any validation for GFrame ?
|
||||
break;
|
||||
}
|
||||
default:
|
||||
util::throw_error(std::runtime_error("Unsupported input meta for IE backend"));
|
||||
}
|
||||
|
||||
if (util::holds_alternative<cv::GMatDesc>(mm_0)) {
|
||||
const auto &meta_0 = util::get<cv::GMatDesc>(mm_0);
|
||||
GAPI_Assert( !meta_0.isND()
|
||||
&& !meta_0.planar
|
||||
&& "Only images are supported as the 0th argument");
|
||||
const auto &input_name_0 = uu.params.input_names.front();
|
||||
const auto &mm_0 = in_metas[0u];
|
||||
const auto &tensor_desc_0 =
|
||||
(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load)
|
||||
? uu.net.getInputsInfo().at(input_name_0)->getTensorDesc()
|
||||
: uu.this_network.GetInputsInfo().at(input_name_0)->getTensorDesc();
|
||||
|
||||
if (cv::util::holds_alternative<cv::GMatDesc>(mm_0) ||
|
||||
cv::util::holds_alternative<cv::GFrameDesc>(mm_0)) {
|
||||
const auto trait = clarifyTrait(mm_0, tensor_desc_0.getDims());
|
||||
if (trait != cv::gapi::ie::TraitAs::IMAGE) {
|
||||
util::throw_error(std::runtime_error(
|
||||
"IE Backend: Only images is"
|
||||
" supported as the 0th argument"));
|
||||
}
|
||||
} else {
|
||||
util::throw_error(std::runtime_error(
|
||||
"IE Backend: Unsupported input meta"
|
||||
" for 0th argument in IE backend"));
|
||||
}
|
||||
|
||||
std::size_t idx = 1u;
|
||||
const auto input_layout = broadcastLayerAttr(uu.params.input_layout,
|
||||
uu.params.input_names);
|
||||
const auto interpolation = broadcastLayerAttr(uu.params.interpolation,
|
||||
uu.params.input_names);
|
||||
for (auto &&input_name : uu.params.input_names) {
|
||||
const auto &mm = in_metas[idx];
|
||||
GAPI_Assert(util::holds_alternative<cv::GArrayDesc>(mm)
|
||||
&& "Non-array inputs are not supported");
|
||||
|
||||
if (op.k.inKinds[idx] == cv::detail::OpaqueKind::CV_RECT) {
|
||||
const auto input_trait = cv::gapi::ie::TraitAs::IMAGE;
|
||||
// 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) {
|
||||
auto inputs = uu.net.getInputsInfo();
|
||||
// This is a cv::Rect -- configure the IE preprocessing
|
||||
auto ii = inputs.at(input_name);
|
||||
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);
|
||||
}
|
||||
if (isApplicableForResize(ii->getTensorDesc())) {
|
||||
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
|
||||
}
|
||||
cfgInputPreprocessing(input_trait, ii, mm_0,
|
||||
input_name, input_layout, interpolation);
|
||||
|
||||
for (auto &&p : uu.params.const_inputs) {
|
||||
inputs.at(p.first)->setPrecision(toIE(p.second.first.depth()));
|
||||
@@ -1800,19 +2106,32 @@ struct InferList2: public cv::detail::KernelTag {
|
||||
if (!input_reshape_table.empty()) {
|
||||
const_cast<IE::CNNNetwork *>(&uu.net)->reshape(input_reshape_table);
|
||||
}
|
||||
const auto output_layout = broadcastLayerAttr(uu.params.output_layout,
|
||||
uu.params.output_names);
|
||||
configureOutputLayout(uu.net.getOutputsInfo(), output_layout);
|
||||
configureOutputPrecision(uu.net.getOutputsInfo(), uu.params.output_precision);
|
||||
} else {
|
||||
GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import);
|
||||
auto inputs = uu.this_network.GetInputsInfo();
|
||||
auto* non_const_prepm = const_cast<IEUnit::PreProcMap*>(&uu.preproc_map);
|
||||
auto ii = inputs.at(input_name);
|
||||
non_const_prepm->emplace(input_name, configurePreProcInfo(ii, mm_0));
|
||||
const auto explicit_resize = lookUp(interpolation, input_name);
|
||||
non_const_prepm->emplace(
|
||||
input_name, createPreProcInfo(input_trait, mm_0, explicit_resize));
|
||||
}
|
||||
} else {
|
||||
// This is a cv::GMat (equals to: cv::Mat)
|
||||
// Just validate that it is really the type
|
||||
// (other types are prohibited here)
|
||||
GAPI_Assert(op.k.inKinds[idx] == cv::detail::OpaqueKind::CV_MAT);
|
||||
// NB: Well, it's even impossible to specify the precision since
|
||||
// there is not such info in GArray<cv::GMat>
|
||||
const auto explicit_resize = lookUp(interpolation, input_name);
|
||||
const auto explicit_layout = lookUp(input_layout , input_name);
|
||||
if (explicit_resize || explicit_layout) {
|
||||
util::throw_error(std::logic_error(
|
||||
"InferList2 doesn't support preprocessing for \"tensor\"'s arguments!"));
|
||||
}
|
||||
}
|
||||
idx++; // NB: Never forget to increment the counter
|
||||
}
|
||||
@@ -1832,6 +2151,7 @@ struct InferList2: public cv::detail::KernelTag {
|
||||
// NB: This blob will be used to make roi from its, so
|
||||
// it should be treated as image
|
||||
IE::Blob::Ptr blob_0 = extractBlob(*ctx, 0, cv::gapi::ie::TraitAs::IMAGE,
|
||||
IE::Layout::ANY,
|
||||
ctx->uu.params.input_names[0u],
|
||||
cv::util::optional<cv::Rect>{});
|
||||
const auto list_size = ctx->inArg<cv::detail::VectorRef>(1u).size();
|
||||
@@ -1851,7 +2171,7 @@ struct InferList2: public cv::detail::KernelTag {
|
||||
ctx->uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load
|
||||
? ctx->uu.net.getOutputsInfo().at(out_name)->getTensorDesc()
|
||||
: ctx->uu.this_network.GetOutputsInfo().at(out_name)->getTensorDesc();
|
||||
cached_dims[i] = toCV(desc.getDims());
|
||||
cached_dims[i] = toCVDims(toCV(desc.getDims()), desc.getLayout());
|
||||
// FIXME: Isn't this should be done automatically
|
||||
// by some resetInternalData(), etc? (Probably at the GExecutor level)
|
||||
auto& out_vec = ctx->outVecR<cv::Mat>(i);
|
||||
@@ -1874,8 +2194,10 @@ struct InferList2: public cv::detail::KernelTag {
|
||||
} else if (this_vec.getKind() == cv::detail::OpaqueKind::CV_MAT) {
|
||||
const auto &vec = this_vec.rref<cv::Mat>();
|
||||
const auto &mat = vec[list_idx];
|
||||
setBlob(req, ctx->uu.params.input_names[in_idx],
|
||||
wrapIE(mat, cv::gapi::ie::TraitAs::TENSOR),
|
||||
const auto layer_name = ctx->uu.params.input_names[in_idx];
|
||||
const auto layout = req.GetBlob(layer_name)->getTensorDesc().getLayout();
|
||||
setBlob(req, layer_name,
|
||||
wrapIE(mat, cv::gapi::ie::TraitAs::TENSOR, layout),
|
||||
*ctx);
|
||||
} else {
|
||||
GAPI_Assert(false &&
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
#include <opencv2/gapi/infer/bindings_ov.hpp>
|
||||
|
||||
cv::gapi::ov::PyParams::PyParams(const std::string &tag,
|
||||
const std::string &model_path,
|
||||
const std::string &bin_path,
|
||||
const std::string &device)
|
||||
: m_priv(std::make_shared<Params<cv::gapi::Generic>>(tag, model_path, bin_path, device)) {
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams::PyParams(const std::string &tag,
|
||||
const std::string &blob_path,
|
||||
const std::string &device)
|
||||
: m_priv(std::make_shared<Params<cv::gapi::Generic>>(tag, blob_path, device)) {
|
||||
}
|
||||
|
||||
cv::gapi::GBackend cv::gapi::ov::PyParams::backend() const {
|
||||
return m_priv->backend();
|
||||
}
|
||||
|
||||
std::string cv::gapi::ov::PyParams::tag() const {
|
||||
return m_priv->tag();
|
||||
}
|
||||
|
||||
cv::util::any cv::gapi::ov::PyParams::params() const {
|
||||
return m_priv->params();
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgPluginConfig(
|
||||
const std::map<std::string, std::string> &config) {
|
||||
m_priv->cfgPluginConfig(config);
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgInputTensorLayout(std::string tensor_layout) {
|
||||
m_priv->cfgInputTensorLayout(std::move(tensor_layout));
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgInputTensorLayout(
|
||||
std::map<std::string, std::string> layout_map) {
|
||||
m_priv->cfgInputTensorLayout(std::move(layout_map));
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgInputModelLayout(std::string tensor_layout) {
|
||||
m_priv->cfgInputModelLayout(std::move(tensor_layout));
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgInputModelLayout(
|
||||
std::map<std::string, std::string> layout_map) {
|
||||
m_priv->cfgInputModelLayout(std::move(layout_map));
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgOutputTensorLayout(std::string tensor_layout) {
|
||||
m_priv->cfgOutputTensorLayout(std::move(tensor_layout));
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgOutputTensorLayout(
|
||||
std::map<std::string, std::string> layout_map) {
|
||||
m_priv->cfgOutputTensorLayout(std::move(layout_map));
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgOutputModelLayout(std::string tensor_layout) {
|
||||
m_priv->cfgOutputModelLayout(std::move(tensor_layout));
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgOutputModelLayout(
|
||||
std::map<std::string, std::string> layout_map) {
|
||||
m_priv->cfgOutputModelLayout(std::move(layout_map));
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgOutputTensorPrecision(int precision) {
|
||||
m_priv->cfgOutputTensorPrecision(precision);
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgOutputTensorPrecision(
|
||||
std::map<std::string, int> precision_map) {
|
||||
m_priv->cfgOutputTensorPrecision(precision_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgReshape(std::vector<size_t> new_shape) {
|
||||
m_priv->cfgReshape(std::move(new_shape));
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgReshape(
|
||||
std::map<std::string, std::vector<size_t>> new_shape_map) {
|
||||
m_priv->cfgReshape(std::move(new_shape_map));
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgNumRequests(const size_t nireq) {
|
||||
m_priv->cfgNumRequests(nireq);
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgMean(std::vector<float> mean_values) {
|
||||
m_priv->cfgMean(std::move(mean_values));
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgMean(
|
||||
std::map<std::string, std::vector<float>> mean_map) {
|
||||
m_priv->cfgMean(std::move(mean_map));
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgScale(std::vector<float> scale_values) {
|
||||
m_priv->cfgScale(std::move(scale_values));
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgScale(
|
||||
std::map<std::string, std::vector<float>> scale_map) {
|
||||
m_priv->cfgScale(std::move(scale_map));
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgResize(int interpolation) {
|
||||
m_priv->cfgResize(interpolation);
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams&
|
||||
cv::gapi::ov::PyParams::cfgResize(std::map<std::string, int> interpolation) {
|
||||
m_priv->cfgResize(std::move(interpolation));
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams cv::gapi::ov::params(const std::string &tag,
|
||||
const std::string &model_path,
|
||||
const std::string &weights,
|
||||
const std::string &device) {
|
||||
return {tag, model_path, weights, device};
|
||||
}
|
||||
|
||||
cv::gapi::ov::PyParams cv::gapi::ov::params(const std::string &tag,
|
||||
const std::string &blob_path,
|
||||
const std::string &device) {
|
||||
return {tag, blob_path, device};
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,66 @@
|
||||
// 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) 2023 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_GOVBACKEND_HPP
|
||||
#define OPENCV_GAPI_GOVBACKEND_HPP
|
||||
|
||||
// Include anyway - cv::gapi::ov::backend() still needs to be defined
|
||||
#include "opencv2/gapi/infer/ov.hpp"
|
||||
|
||||
#if defined HAVE_INF_ENGINE && INF_ENGINE_RELEASE >= 2022010000
|
||||
|
||||
#include <openvino/openvino.hpp>
|
||||
|
||||
#include "backends/common/gbackend.hpp"
|
||||
|
||||
namespace cv {
|
||||
namespace gimpl {
|
||||
namespace ov {
|
||||
|
||||
struct OVCompiled {
|
||||
::ov::CompiledModel compiled_model;
|
||||
};
|
||||
|
||||
class RequestPool;
|
||||
|
||||
class GOVExecutable final: public GIslandExecutable
|
||||
{
|
||||
const ade::Graph &m_g;
|
||||
GModel::ConstGraph m_gm;
|
||||
|
||||
// The only executable stuff in this graph
|
||||
// (assuming it is always single-op)
|
||||
ade::NodeHandle this_nh;
|
||||
OVCompiled compiled;
|
||||
|
||||
// List of all resources in graph (both internal and external)
|
||||
std::vector<ade::NodeHandle> m_dataNodes;
|
||||
|
||||
// To manage multiple async requests
|
||||
std::unique_ptr<RequestPool> m_reqPool;
|
||||
|
||||
public:
|
||||
GOVExecutable(const ade::Graph &graph,
|
||||
const std::vector<ade::NodeHandle> &nodes);
|
||||
|
||||
virtual inline bool canReshape() const override { return false; }
|
||||
virtual inline void reshape(ade::Graph&, const GCompileArgs&) override {
|
||||
GAPI_Error("InternalError"); // Not implemented yet
|
||||
}
|
||||
|
||||
virtual void run(std::vector<InObj> &&,
|
||||
std::vector<OutObj> &&) override {
|
||||
GAPI_Error("Not implemented");
|
||||
}
|
||||
|
||||
virtual void run(GIslandExecutable::IInput &in,
|
||||
GIslandExecutable::IOutput &out) override;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif // HAVE_INF_ENGINE && INF_ENGINE_RELEASE >= 2022010000
|
||||
#endif // OPENCV_GAPI_GOVBACKEND_HPP
|
||||
@@ -0,0 +1,35 @@
|
||||
// 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) 2023 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_INFER_OV_UTIL_HPP
|
||||
#define OPENCV_GAPI_INFER_OV_UTIL_HPP
|
||||
|
||||
#if defined HAVE_INF_ENGINE && INF_ENGINE_RELEASE >= 2022010000
|
||||
|
||||
// NOTE: This file is not included by default in infer/ov.hpp
|
||||
// and won't be. infer/ov.hpp doesn't depend on OV headers itself.
|
||||
// This file does -- so needs to be included separately by those who care.
|
||||
|
||||
#include <openvino/openvino.hpp>
|
||||
|
||||
#include <opencv2/core/cvdef.h> // GAPI_EXPORTS
|
||||
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace ov {
|
||||
namespace util {
|
||||
|
||||
// NB: These functions are EXPORTed to make them accessible by the
|
||||
// test suite only.
|
||||
GAPI_EXPORTS std::vector<int> to_ocv(const ::ov::Shape &shape);
|
||||
GAPI_EXPORTS int to_ocv(const ::ov::element::Type &type);
|
||||
|
||||
}}}}
|
||||
|
||||
#endif // HAVE_INF_ENGINE && INF_ENGINE_RELEASE >= 2022010000
|
||||
|
||||
#endif // OPENCV_GAPI_INFER_OV_UTIL_HPP
|
||||
@@ -2,7 +2,7 @@
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2019-2021 Intel Corporation
|
||||
// Copyright (C) 2019-2023 Intel Corporation
|
||||
|
||||
#include "../test_precomp.hpp"
|
||||
|
||||
@@ -2238,7 +2238,7 @@ TEST(TestAgeGenderIE, InferWithBatch)
|
||||
params.weights_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
params.device_id = "CPU";
|
||||
|
||||
cv::Mat in_mat({batch_size, 3, 320, 240}, CV_8U);
|
||||
cv::Mat in_mat({batch_size, 3, 62, 62}, CV_8U);
|
||||
cv::randu(in_mat, 0, 255);
|
||||
|
||||
cv::Mat gapi_age, gapi_gender;
|
||||
@@ -2247,8 +2247,9 @@ TEST(TestAgeGenderIE, InferWithBatch)
|
||||
IE::Blob::Ptr ie_age, ie_gender;
|
||||
{
|
||||
auto plugin = cv::gimpl::ie::wrap::getPlugin(params);
|
||||
auto net = cv::gimpl::ie::wrap::readNetwork(params);
|
||||
setNetParameters(net);
|
||||
auto net = cv::gimpl::ie::wrap::readNetwork(params);
|
||||
auto ii = net.getInputsInfo().at("data");
|
||||
ii->setPrecision(IE::Precision::U8);
|
||||
net.setBatchSize(batch_size);
|
||||
auto this_network = cv::gimpl::ie::wrap::loadNetwork(plugin, net, params);
|
||||
auto infer_request = this_network.CreateInferRequest();
|
||||
@@ -3056,6 +3057,73 @@ TEST_F(AgeGenderInferTest, ChangeSpecificOutputPrecison) {
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST_F(AgeGenderInferTest, ThrowIfSetLayoutForImage) {
|
||||
auto pp = cv::gapi::ie::Params<AgeGender> {
|
||||
m_params.model_path, m_params.weights_path, m_params.device_id
|
||||
}.cfgOutputLayers({ "age_conv3", "prob" })
|
||||
.cfgOutputPrecision({{"prob", CV_8U}})
|
||||
.cfgInputLayout("NHWC");
|
||||
|
||||
EXPECT_ANY_THROW(buildGraph().apply(cv::gin(m_in_mat), cv::gout(m_gapi_age, m_gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp))));
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderIE, InferTensorWithPreproc) {
|
||||
initDLDTDataPath();
|
||||
|
||||
cv::gapi::ie::detail::ParamDesc params;
|
||||
params.model_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
params.weights_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
params.device_id = "CPU";
|
||||
|
||||
// Load IE network, initialize input data using that.
|
||||
cv::Mat in_mat({1, 240, 320, 3}, CV_8U);
|
||||
cv::randu(in_mat, 0, 255);
|
||||
cv::Mat gapi_age, gapi_gender;
|
||||
|
||||
IE::Blob::Ptr ie_age, ie_gender;
|
||||
{
|
||||
auto plugin = cv::gimpl::ie::wrap::getPlugin(params);
|
||||
auto net = cv::gimpl::ie::wrap::readNetwork(params);
|
||||
auto ii = net.getInputsInfo().at("data");
|
||||
|
||||
ii->setPrecision(IE::Precision::U8);
|
||||
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
|
||||
ii->setLayout(IE::Layout::NHWC);
|
||||
|
||||
auto this_network = cv::gimpl::ie::wrap::loadNetwork(plugin, net, params);
|
||||
auto infer_request = this_network.CreateInferRequest();
|
||||
IE::TensorDesc desc{IE::Precision::U8, {1, 3, 240, 320}, IE::Layout::NHWC};
|
||||
auto blob = IE::make_shared_blob<uint8_t>(desc, const_cast<uint8_t*>(in_mat.ptr<uint8_t>()));
|
||||
infer_request.SetBlob("data", blob);
|
||||
infer_request.Infer();
|
||||
ie_age = infer_request.GetBlob("age_conv3");
|
||||
ie_gender = infer_request.GetBlob("prob");
|
||||
}
|
||||
|
||||
// Configure & run G-API
|
||||
using AGInfo = std::tuple<cv::GMat, cv::GMat>;
|
||||
G_API_NET(AgeGender, <AGInfo(cv::GMat)>, "test-age-gender");
|
||||
|
||||
cv::GMat in;
|
||||
cv::GMat age, gender;
|
||||
std::tie(age, gender) = cv::gapi::infer<AgeGender>(in);
|
||||
cv::GComputation comp(cv::GIn(in), cv::GOut(age, gender));
|
||||
|
||||
auto pp = cv::gapi::ie::Params<AgeGender> {
|
||||
params.model_path, params.weights_path, params.device_id
|
||||
}.cfgOutputLayers({ "age_conv3", "prob" })
|
||||
.cfgResize(cv::INTER_LINEAR)
|
||||
.cfgInputLayout("NHWC");
|
||||
|
||||
comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Validate with IE itself (avoid DNN module dependency here)
|
||||
normAssert(cv::gapi::ie::util::to_ocv(ie_age), gapi_age, "Test age output" );
|
||||
normAssert(cv::gapi::ie::util::to_ocv(ie_gender), gapi_gender, "Test gender output");
|
||||
}
|
||||
|
||||
} // namespace opencv_test
|
||||
|
||||
#endif // HAVE_INF_ENGINE
|
||||
|
||||
@@ -0,0 +1,540 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2023 Intel Corporation
|
||||
|
||||
#if defined HAVE_INF_ENGINE && INF_ENGINE_RELEASE >= 2022010000
|
||||
|
||||
#include "../test_precomp.hpp"
|
||||
|
||||
#include "backends/ov/util.hpp"
|
||||
|
||||
#include <opencv2/gapi/infer/ov.hpp>
|
||||
|
||||
#include <openvino/openvino.hpp>
|
||||
|
||||
namespace opencv_test
|
||||
{
|
||||
|
||||
namespace {
|
||||
// FIXME: taken from DNN module
|
||||
void initDLDTDataPath()
|
||||
{
|
||||
#ifndef WINRT
|
||||
static bool initialized = false;
|
||||
if (!initialized)
|
||||
{
|
||||
const char* omzDataPath = getenv("OPENCV_OPEN_MODEL_ZOO_DATA_PATH");
|
||||
if (omzDataPath)
|
||||
cvtest::addDataSearchPath(omzDataPath);
|
||||
const char* dnnDataPath = getenv("OPENCV_DNN_TEST_DATA_PATH");
|
||||
if (dnnDataPath) {
|
||||
// Add the dnnDataPath itself - G-API is using some images there directly
|
||||
cvtest::addDataSearchPath(dnnDataPath);
|
||||
cvtest::addDataSearchPath(dnnDataPath + std::string("/omz_intel_models"));
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
#endif // WINRT
|
||||
}
|
||||
|
||||
static const std::string SUBDIR = "intel/age-gender-recognition-retail-0013/FP32/";
|
||||
|
||||
void copyFromOV(ov::Tensor &tensor, cv::Mat &mat) {
|
||||
GAPI_Assert(tensor.get_byte_size() == mat.total() * mat.elemSize());
|
||||
std::copy_n(reinterpret_cast<uint8_t*>(tensor.data()),
|
||||
tensor.get_byte_size(),
|
||||
mat.ptr<uint8_t>());
|
||||
}
|
||||
|
||||
void copyToOV(const cv::Mat &mat, ov::Tensor &tensor) {
|
||||
GAPI_Assert(tensor.get_byte_size() == mat.total() * mat.elemSize());
|
||||
std::copy_n(mat.ptr<uint8_t>(),
|
||||
tensor.get_byte_size(),
|
||||
reinterpret_cast<uint8_t*>(tensor.data()));
|
||||
}
|
||||
|
||||
// FIXME: taken from the DNN module
|
||||
void normAssert(cv::InputArray ref, cv::InputArray test,
|
||||
const char *comment /*= ""*/,
|
||||
double l1 = 0.00001, double lInf = 0.0001) {
|
||||
double normL1 = cvtest::norm(ref, test, cv::NORM_L1) / ref.getMat().total();
|
||||
EXPECT_LE(normL1, l1) << comment;
|
||||
|
||||
double normInf = cvtest::norm(ref, test, cv::NORM_INF);
|
||||
EXPECT_LE(normInf, lInf) << comment;
|
||||
}
|
||||
|
||||
ov::Core getCore() {
|
||||
static ov::Core core;
|
||||
return core;
|
||||
}
|
||||
|
||||
// TODO: AGNetGenComp, AGNetTypedComp, AGNetOVComp, AGNetOVCompiled
|
||||
// can be generalized to work with any model and used as parameters for tests.
|
||||
|
||||
struct AGNetGenComp {
|
||||
static constexpr const char* tag = "age-gender-generic";
|
||||
using Params = cv::gapi::ov::Params<cv::gapi::Generic>;
|
||||
|
||||
static Params params(const std::string &xml,
|
||||
const std::string &bin,
|
||||
const std::string &device) {
|
||||
return {tag, xml, bin, device};
|
||||
}
|
||||
|
||||
static Params params(const std::string &blob_path,
|
||||
const std::string &device) {
|
||||
return {tag, blob_path, device};
|
||||
}
|
||||
|
||||
static cv::GComputation create() {
|
||||
cv::GMat in;
|
||||
GInferInputs inputs;
|
||||
inputs["data"] = in;
|
||||
auto outputs = cv::gapi::infer<cv::gapi::Generic>(tag, inputs);
|
||||
auto age = outputs.at("age_conv3");
|
||||
auto gender = outputs.at("prob");
|
||||
return cv::GComputation{cv::GIn(in), cv::GOut(age, gender)};
|
||||
}
|
||||
};
|
||||
|
||||
struct AGNetTypedComp {
|
||||
using AGInfo = std::tuple<cv::GMat, cv::GMat>;
|
||||
G_API_NET(AgeGender, <AGInfo(cv::GMat)>, "typed-age-gender");
|
||||
using Params = cv::gapi::ov::Params<AgeGender>;
|
||||
|
||||
static Params params(const std::string &xml_path,
|
||||
const std::string &bin_path,
|
||||
const std::string &device) {
|
||||
return Params {
|
||||
xml_path, bin_path, device
|
||||
}.cfgOutputLayers({ "age_conv3", "prob" });
|
||||
}
|
||||
|
||||
static cv::GComputation create() {
|
||||
cv::GMat in;
|
||||
cv::GMat age, gender;
|
||||
std::tie(age, gender) = cv::gapi::infer<AgeGender>(in);
|
||||
return cv::GComputation{cv::GIn(in), cv::GOut(age, gender)};
|
||||
}
|
||||
};
|
||||
|
||||
class AGNetOVCompiled {
|
||||
public:
|
||||
AGNetOVCompiled(ov::CompiledModel &&compiled_model)
|
||||
: m_compiled_model(std::move(compiled_model)) {
|
||||
}
|
||||
|
||||
void operator()(const cv::Mat &in_mat,
|
||||
cv::Mat &age_mat,
|
||||
cv::Mat &gender_mat) {
|
||||
auto infer_request = m_compiled_model.create_infer_request();
|
||||
auto input_tensor = infer_request.get_input_tensor();
|
||||
copyToOV(in_mat, input_tensor);
|
||||
|
||||
infer_request.infer();
|
||||
|
||||
auto age_tensor = infer_request.get_tensor("age_conv3");
|
||||
age_mat.create(cv::gapi::ov::util::to_ocv(age_tensor.get_shape()),
|
||||
cv::gapi::ov::util::to_ocv(age_tensor.get_element_type()));
|
||||
copyFromOV(age_tensor, age_mat);
|
||||
|
||||
auto gender_tensor = infer_request.get_tensor("prob");
|
||||
gender_mat.create(cv::gapi::ov::util::to_ocv(gender_tensor.get_shape()),
|
||||
cv::gapi::ov::util::to_ocv(gender_tensor.get_element_type()));
|
||||
copyFromOV(gender_tensor, gender_mat);
|
||||
}
|
||||
|
||||
void export_model(const std::string &outpath) {
|
||||
std::ofstream file{outpath, std::ios::out | std::ios::binary};
|
||||
GAPI_Assert(file.is_open());
|
||||
m_compiled_model.export_model(file);
|
||||
}
|
||||
|
||||
private:
|
||||
ov::CompiledModel m_compiled_model;
|
||||
};
|
||||
|
||||
struct ImageInputPreproc {
|
||||
void operator()(ov::preprocess::PrePostProcessor &ppp) {
|
||||
ppp.input().tensor().set_layout(ov::Layout("NHWC"))
|
||||
.set_element_type(ov::element::u8)
|
||||
.set_shape({1, size.height, size.width, 3});
|
||||
ppp.input().model().set_layout(ov::Layout("NCHW"));
|
||||
ppp.input().preprocess().resize(::ov::preprocess::ResizeAlgorithm::RESIZE_LINEAR);
|
||||
}
|
||||
|
||||
cv::Size size;
|
||||
};
|
||||
|
||||
class AGNetOVComp {
|
||||
public:
|
||||
AGNetOVComp(const std::string &xml_path,
|
||||
const std::string &bin_path,
|
||||
const std::string &device)
|
||||
: m_device(device) {
|
||||
m_model = getCore().read_model(xml_path, bin_path);
|
||||
}
|
||||
|
||||
using PrePostProcessF = std::function<void(ov::preprocess::PrePostProcessor&)>;
|
||||
|
||||
void cfgPrePostProcessing(PrePostProcessF f) {
|
||||
ov::preprocess::PrePostProcessor ppp(m_model);
|
||||
f(ppp);
|
||||
m_model = ppp.build();
|
||||
}
|
||||
|
||||
AGNetOVCompiled compile() {
|
||||
auto compiled_model = getCore().compile_model(m_model, m_device);
|
||||
return {std::move(compiled_model)};
|
||||
}
|
||||
|
||||
void apply(const cv::Mat &in_mat,
|
||||
cv::Mat &age_mat,
|
||||
cv::Mat &gender_mat) {
|
||||
compile()(in_mat, age_mat, gender_mat);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_device;
|
||||
std::shared_ptr<ov::Model> m_model;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// TODO: Make all of tests below parmetrized to avoid code duplication
|
||||
TEST(TestAgeGenderOV, InferTypedTensor) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string device = "CPU";
|
||||
|
||||
cv::Mat in_mat({1, 3, 62, 62}, CV_32F);
|
||||
cv::randu(in_mat, -1, 1);
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
ref.apply(in_mat, ov_age, ov_gender);
|
||||
|
||||
// G-API
|
||||
auto comp = AGNetTypedComp::create();
|
||||
auto pp = AGNetTypedComp::params(xml_path, bin_path, device);
|
||||
comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, InferTypedImage) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string device = "CPU";
|
||||
|
||||
cv::Mat in_mat(300, 300, CV_8UC3);
|
||||
cv::randu(in_mat, 0, 255);
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
ref.cfgPrePostProcessing(ImageInputPreproc{in_mat.size()});
|
||||
ref.apply(in_mat, ov_age, ov_gender);
|
||||
|
||||
// G-API
|
||||
auto comp = AGNetTypedComp::create();
|
||||
auto pp = AGNetTypedComp::params(xml_path, bin_path, device);
|
||||
comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, InferGenericTensor) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string device = "CPU";
|
||||
|
||||
cv::Mat in_mat({1, 3, 62, 62}, CV_32F);
|
||||
cv::randu(in_mat, -1, 1);
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
ref.apply(in_mat, ov_age, ov_gender);
|
||||
|
||||
// G-API
|
||||
auto comp = AGNetGenComp::create();
|
||||
auto pp = AGNetGenComp::params(xml_path, bin_path, device);
|
||||
comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, InferGenericImage) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string device = "CPU";
|
||||
|
||||
cv::Mat in_mat(300, 300, CV_8UC3);
|
||||
cv::randu(in_mat, 0, 255);
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
ref.cfgPrePostProcessing(ImageInputPreproc{in_mat.size()});
|
||||
ref.apply(in_mat, ov_age, ov_gender);
|
||||
|
||||
// G-API
|
||||
auto comp = AGNetGenComp::create();
|
||||
auto pp = AGNetGenComp::params(xml_path, bin_path, device);
|
||||
comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, InferGenericImageBlob) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string blob_path = "age-gender-recognition-retail-0013.blob";
|
||||
const std::string device = "CPU";
|
||||
|
||||
cv::Mat in_mat(300, 300, CV_8UC3);
|
||||
cv::randu(in_mat, 0, 255);
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
ref.cfgPrePostProcessing(ImageInputPreproc{in_mat.size()});
|
||||
auto cc_ref = ref.compile();
|
||||
// NB: Output blob will contain preprocessing inside.
|
||||
cc_ref.export_model(blob_path);
|
||||
cc_ref(in_mat, ov_age, ov_gender);
|
||||
|
||||
// G-API
|
||||
auto comp = AGNetGenComp::create();
|
||||
auto pp = AGNetGenComp::params(blob_path, device);
|
||||
comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, InferGenericTensorBlob) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string blob_path = "age-gender-recognition-retail-0013.blob";
|
||||
const std::string device = "CPU";
|
||||
|
||||
cv::Mat in_mat({1, 3, 62, 62}, CV_32F);
|
||||
cv::randu(in_mat, -1, 1);
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
auto cc_ref = ref.compile();
|
||||
cc_ref.export_model(blob_path);
|
||||
cc_ref(in_mat, ov_age, ov_gender);
|
||||
|
||||
// G-API
|
||||
auto comp = AGNetGenComp::create();
|
||||
auto pp = AGNetGenComp::params(blob_path, device);
|
||||
comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, InferBothOutputsFP16) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string device = "CPU";
|
||||
|
||||
cv::Mat in_mat({1, 3, 62, 62}, CV_32F);
|
||||
cv::randu(in_mat, -1, 1);
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
ref.cfgPrePostProcessing([](ov::preprocess::PrePostProcessor &ppp){
|
||||
ppp.output(0).tensor().set_element_type(ov::element::f16);
|
||||
ppp.output(1).tensor().set_element_type(ov::element::f16);
|
||||
});
|
||||
ref.apply(in_mat, ov_age, ov_gender);
|
||||
|
||||
// G-API
|
||||
auto comp = AGNetGenComp::create();
|
||||
auto pp = AGNetGenComp::params(xml_path, bin_path, device);
|
||||
pp.cfgOutputTensorPrecision(CV_16F);
|
||||
|
||||
comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, InferOneOutputFP16) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string device = "CPU";
|
||||
|
||||
cv::Mat in_mat({1, 3, 62, 62}, CV_32F);
|
||||
cv::randu(in_mat, -1, 1);
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
|
||||
// OpenVINO
|
||||
const std::string fp16_output_name = "prob";
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
ref.cfgPrePostProcessing([&](ov::preprocess::PrePostProcessor &ppp){
|
||||
ppp.output(fp16_output_name).tensor().set_element_type(ov::element::f16);
|
||||
});
|
||||
ref.apply(in_mat, ov_age, ov_gender);
|
||||
|
||||
// G-API
|
||||
auto comp = AGNetGenComp::create();
|
||||
auto pp = AGNetGenComp::params(xml_path, bin_path, device);
|
||||
pp.cfgOutputTensorPrecision({{fp16_output_name, CV_16F}});
|
||||
|
||||
comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, ThrowCfgOutputPrecForBlob) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string blob_path = "age-gender-recognition-retail-0013.blob";
|
||||
const std::string device = "CPU";
|
||||
|
||||
// OpenVINO (Just for blob compilation)
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
auto cc_ref = ref.compile();
|
||||
cc_ref.export_model(blob_path);
|
||||
|
||||
// G-API
|
||||
auto comp = AGNetGenComp::create();
|
||||
auto pp = AGNetGenComp::params(blob_path, device);
|
||||
|
||||
EXPECT_ANY_THROW(pp.cfgOutputTensorPrecision(CV_16F));
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, ThrowInvalidConfigIR) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string device = "CPU";
|
||||
|
||||
// G-API
|
||||
auto comp = AGNetGenComp::create();
|
||||
auto pp = AGNetGenComp::params(xml_path, bin_path, device);
|
||||
pp.cfgPluginConfig({{"some_key", "some_value"}});
|
||||
|
||||
EXPECT_ANY_THROW(comp.compile(cv::GMatDesc{CV_8U,3,cv::Size{320, 240}},
|
||||
cv::compile_args(cv::gapi::networks(pp))));
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, ThrowInvalidConfigBlob) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string blob_path = "age-gender-recognition-retail-0013.blob";
|
||||
const std::string device = "CPU";
|
||||
|
||||
// OpenVINO (Just for blob compilation)
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
auto cc_ref = ref.compile();
|
||||
cc_ref.export_model(blob_path);
|
||||
|
||||
// G-API
|
||||
auto comp = AGNetGenComp::create();
|
||||
auto pp = AGNetGenComp::params(blob_path, device);
|
||||
pp.cfgPluginConfig({{"some_key", "some_value"}});
|
||||
|
||||
EXPECT_ANY_THROW(comp.compile(cv::GMatDesc{CV_8U,3,cv::Size{320, 240}},
|
||||
cv::compile_args(cv::gapi::networks(pp))));
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, ThrowInvalidImageLayout) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string device = "CPU";
|
||||
|
||||
// NB: This mat may only have "NHWC" layout.
|
||||
cv::Mat in_mat(300, 300, CV_8UC3);
|
||||
cv::randu(in_mat, 0, 255);
|
||||
cv::Mat gender, gapi_age, gapi_gender;
|
||||
auto comp = AGNetTypedComp::create();
|
||||
auto pp = AGNetTypedComp::params(xml_path, bin_path, device);
|
||||
|
||||
pp.cfgInputTensorLayout("NCHW");
|
||||
|
||||
EXPECT_ANY_THROW(comp.compile(cv::descr_of(in_mat),
|
||||
cv::compile_args(cv::gapi::networks(pp))));
|
||||
}
|
||||
|
||||
TEST(TestAgeGenderOV, InferTensorWithPreproc) {
|
||||
initDLDTDataPath();
|
||||
const std::string xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml");
|
||||
const std::string bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin");
|
||||
const std::string device = "CPU";
|
||||
|
||||
cv::Mat in_mat({1, 240, 320, 3}, CV_32F);
|
||||
cv::randu(in_mat, -1, 1);
|
||||
cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
|
||||
|
||||
// OpenVINO
|
||||
AGNetOVComp ref(xml_path, bin_path, device);
|
||||
ref.cfgPrePostProcessing([](ov::preprocess::PrePostProcessor &ppp) {
|
||||
auto& input = ppp.input();
|
||||
input.tensor().set_spatial_static_shape(240, 320)
|
||||
.set_layout("NHWC");
|
||||
input.preprocess().resize(ov::preprocess::ResizeAlgorithm::RESIZE_LINEAR);
|
||||
});
|
||||
ref.apply(in_mat, ov_age, ov_gender);
|
||||
|
||||
// G-API
|
||||
auto comp = AGNetTypedComp::create();
|
||||
auto pp = AGNetTypedComp::params(xml_path, bin_path, device);
|
||||
pp.cfgResize(cv::INTER_LINEAR)
|
||||
.cfgInputTensorLayout("NHWC");
|
||||
|
||||
comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
// Assert
|
||||
normAssert(ov_age, gapi_age, "Test age output" );
|
||||
normAssert(ov_gender, gapi_gender, "Test gender output");
|
||||
}
|
||||
|
||||
} // namespace opencv_test
|
||||
|
||||
#endif // HAVE_INF_ENGINE && INF_ENGINE_RELEASE >= 2022010000
|
||||
Reference in New Issue
Block a user