mirror of
https://github.com/opencv/opencv.git
synced 2025-06-07 17:44:04 +08:00
Merge pull request #23595 from TolyaTalamanov:at/implement-openvino-backend
[G-API] Implement OpenVINO 2.0 backend #23595 ### Pull Request Readiness Checklist Implemented basic functionality for `OpenVINO` 2.0 G-API backend. #### Overview - [x] Implement `Infer` kernel with some of essential configurable parameters + IR/Blob models format support. - [ ] Implement the rest of kernels: `InferList`, `InferROI`, `Infer2` + other configurable params (e.g reshape) - [x] Asyncrhonous execution support - [ ] Remote context support See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [ ] The PR is proposed to the proper branch - [ ] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
parent
36d6ca529d
commit
5330112f05
@ -156,6 +156,10 @@ set(gapi_srcs
|
|||||||
src/backends/ie/giebackend.cpp
|
src/backends/ie/giebackend.cpp
|
||||||
src/backends/ie/giebackend/giewrapper.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
|
# ONNX backend
|
||||||
src/backends/onnx/gonnxbackend.cpp
|
src/backends/onnx/gonnxbackend.cpp
|
||||||
|
|
||||||
@ -182,6 +186,7 @@ set(gapi_srcs
|
|||||||
# Python bridge
|
# Python bridge
|
||||||
src/backends/ie/bindings_ie.cpp
|
src/backends/ie/bindings_ie.cpp
|
||||||
src/backends/onnx/bindings_onnx.cpp
|
src/backends/onnx/bindings_onnx.cpp
|
||||||
|
src/backends/ov/bindings_ov.cpp
|
||||||
src/backends/python/gpythonbackend.cpp
|
src/backends/python/gpythonbackend.cpp
|
||||||
|
|
||||||
# OpenVPL Streaming source
|
# OpenVPL Streaming source
|
||||||
|
128
modules/gapi/include/opencv2/gapi/infer/bindings_ov.hpp
Normal file
128
modules/gapi/include/opencv2/gapi/infer/bindings_ov.hpp
Normal file
@ -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
|
685
modules/gapi/include/opencv2/gapi/infer/ov.hpp
Normal file
685
modules/gapi/include/opencv2/gapi/infer/ov.hpp
Normal file
@ -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
|
@ -15,6 +15,7 @@ using gapi_GKernelPackage = cv::GKernelPackage;
|
|||||||
using gapi_GNetPackage = cv::gapi::GNetPackage;
|
using gapi_GNetPackage = cv::gapi::GNetPackage;
|
||||||
using gapi_ie_PyParams = cv::gapi::ie::PyParams;
|
using gapi_ie_PyParams = cv::gapi::ie::PyParams;
|
||||||
using gapi_onnx_PyParams = cv::gapi::onnx::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 gapi_wip_IStreamSource_Ptr = cv::Ptr<cv::gapi::wip::IStreamSource>;
|
||||||
using detail_ExtractArgsCallback = cv::detail::ExtractArgsCallback;
|
using detail_ExtractArgsCallback = cv::detail::ExtractArgsCallback;
|
||||||
using detail_ExtractMetaCallback = cv::detail::ExtractMetaCallback;
|
using detail_ExtractMetaCallback = cv::detail::ExtractMetaCallback;
|
||||||
@ -22,6 +23,11 @@ using vector_GNetParam = std::vector<cv::gapi::GNetParam>;
|
|||||||
using vector_GMat = std::vector<cv::GMat>;
|
using vector_GMat = std::vector<cv::GMat>;
|
||||||
using gapi_streaming_queue_capacity = cv::gapi::streaming::queue_capacity;
|
using gapi_streaming_queue_capacity = cv::gapi::streaming::queue_capacity;
|
||||||
using GStreamerSource_OutputType = cv::gapi::wip::GStreamerSource::OutputType;
|
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>>;
|
||||||
|
|
||||||
// NB: Python wrapper generate T_U for T<U>
|
// NB: Python wrapper generate T_U for T<U>
|
||||||
// This behavior is only observed for inputs
|
// 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::ie::PyParams params);
|
||||||
gapi::GNetParam GAPI_EXPORTS_W strip(gapi::onnx::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 detail
|
||||||
} // namespace cv
|
} // namespace cv
|
||||||
|
238
modules/gapi/misc/python/test/test_gapi_infer_ov.py
Normal file
238
modules/gapi/misc/python/test/test_gapi_infer_ov.py
Normal file
@ -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()
|
@ -153,10 +153,18 @@ std::ostream& operator<<(std::ostream& os, const cv::GMatDesc &desc)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
os << "C" << desc.chan;
|
||||||
if (desc.planar) os << "p";
|
if (desc.planar) os << "p";
|
||||||
os << " ";
|
os << " ";
|
||||||
os << desc.size.width << "x" << desc.size.height;
|
os << desc.size.width << "x" << desc.size.height;
|
||||||
|
}
|
||||||
|
|
||||||
return os;
|
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); });
|
[](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
|
}} // cv::gimpl
|
||||||
|
|
||||||
#endif // OPENCV_GAPI_GBACKEND_HPP
|
#endif // OPENCV_GAPI_GBACKEND_HPP
|
||||||
|
168
modules/gapi/src/backends/ov/bindings_ov.cpp
Normal file
168
modules/gapi/src/backends/ov/bindings_ov.cpp
Normal file
@ -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};
|
||||||
|
}
|
1001
modules/gapi/src/backends/ov/govbackend.cpp
Normal file
1001
modules/gapi/src/backends/ov/govbackend.cpp
Normal file
File diff suppressed because it is too large
Load Diff
66
modules/gapi/src/backends/ov/govbackend.hpp
Normal file
66
modules/gapi/src/backends/ov/govbackend.hpp
Normal file
@ -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"
|
||||||
|
|
||||||
|
#ifdef HAVE_INF_ENGINE
|
||||||
|
|
||||||
|
#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
|
||||||
|
#endif // OPENCV_GAPI_GOVBACKEND_HPP
|
35
modules/gapi/src/backends/ov/util.hpp
Normal file
35
modules/gapi/src/backends/ov/util.hpp
Normal file
@ -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
|
||||||
|
|
||||||
|
#ifdef HAVE_INF_ENGINE
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#endif // OPENCV_GAPI_INFER_OV_UTIL_HPP
|
540
modules/gapi/test/infer/gapi_infer_ov_tests.cpp
Normal file
540
modules/gapi/test/infer/gapi_infer_ov_tests.cpp
Normal file
@ -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
|
||||||
|
|
||||||
|
#ifdef HAVE_INF_ENGINE
|
||||||
|
|
||||||
|
#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
|
@ -6,6 +6,8 @@
|
|||||||
#include "cv2_numpy.hpp"
|
#include "cv2_numpy.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <map>
|
||||||
#include <type_traits> // std::enable_if
|
#include <type_traits> // std::enable_if
|
||||||
|
|
||||||
extern PyTypeObject* pyopencv_Mat_TypePtr;
|
extern PyTypeObject* pyopencv_Mat_TypePtr;
|
||||||
@ -263,6 +265,38 @@ PyObject* pyopencv_from(const std::vector<Tp>& value)
|
|||||||
return pyopencvVecConverter<Tp>::from(value);
|
return pyopencvVecConverter<Tp>::from(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename K, typename V>
|
||||||
|
bool pyopencv_to(PyObject *obj, std::map<K,V> &map, const ArgInfo& info)
|
||||||
|
{
|
||||||
|
PyObject* py_key = nullptr;
|
||||||
|
PyObject* py_value = nullptr;
|
||||||
|
Py_ssize_t pos = 0;
|
||||||
|
|
||||||
|
if (!PyDict_Check(obj)) {
|
||||||
|
failmsg("Can't parse '%s'. Input argument isn't dict or"
|
||||||
|
" an instance of subtype of the dict type", info.name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(PyDict_Next(obj, &pos, &py_key, &py_value))
|
||||||
|
{
|
||||||
|
K cpp_key;
|
||||||
|
if (!pyopencv_to(py_key, cpp_key, ArgInfo("key", false))) {
|
||||||
|
failmsg("Can't parse dict key. Key on position %lu has a wrong type", pos);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
V cpp_value;
|
||||||
|
if (!pyopencv_to(py_value, cpp_value, ArgInfo("value", false))) {
|
||||||
|
failmsg("Can't parse dict value. Value on position %lu has a wrong type", pos);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
map.emplace(cpp_key, cpp_value);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Tp>
|
template <typename Tp>
|
||||||
static bool pyopencv_to_generic_vec(PyObject* obj, std::vector<Tp>& value, const ArgInfo& info)
|
static bool pyopencv_to_generic_vec(PyObject* obj, std::vector<Tp>& value, const ArgInfo& info)
|
||||||
{
|
{
|
||||||
|
@ -190,6 +190,14 @@ _PREDEFINED_TYPES = (
|
|||||||
PrimitiveTypeNode.float_(),
|
PrimitiveTypeNode.float_(),
|
||||||
PrimitiveTypeNode.str_())
|
PrimitiveTypeNode.str_())
|
||||||
), export_name="SearchParams"),
|
), export_name="SearchParams"),
|
||||||
|
AliasTypeNode.dict_("map_string_and_string", PrimitiveTypeNode.str_("map_string_and_string::key"),
|
||||||
|
PrimitiveTypeNode.str_("map_string_and_string::key::value")),
|
||||||
|
AliasTypeNode.dict_("map_string_and_int", PrimitiveTypeNode.str_("map_string_and_int::key"),
|
||||||
|
PrimitiveTypeNode.int_("map_string_and_int::key::value")),
|
||||||
|
AliasTypeNode.dict_("map_string_and_vector_size_t", PrimitiveTypeNode.str_("map_string_and_vector_size_t::key"),
|
||||||
|
SequenceTypeNode("map_string_and_vector_size_t::key::value", PrimitiveTypeNode.int_("size_t"))),
|
||||||
|
AliasTypeNode.dict_("map_string_and_vector_float", PrimitiveTypeNode.str_("map_string_and_vector_float::key"),
|
||||||
|
SequenceTypeNode("map_string_and_vector_float::key::value", PrimitiveTypeNode.float_())),
|
||||||
)
|
)
|
||||||
|
|
||||||
PREDEFINED_TYPES = dict(zip((t.ctype_name for t in _PREDEFINED_TYPES), _PREDEFINED_TYPES))
|
PREDEFINED_TYPES = dict(zip((t.ctype_name for t in _PREDEFINED_TYPES), _PREDEFINED_TYPES))
|
||||||
|
Loading…
Reference in New Issue
Block a user