Merge pull request #19310 from TolyaTalamanov:at/generic-infer-overloads
[G-API] Support generic infer overloads * Overloads for generic infer * Fix build * Refactoring * Fix docs * Put extra stuff to detail namespace * Add doc for usings * Remove uneccessary template in Priv
This commit is contained in:
committed by
GitHub
parent
3f52d0e46c
commit
50a264d832
@@ -2,7 +2,7 @@
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2019-2020 Intel Corporation
|
||||
// Copyright (C) 2019-2021 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_INFER_HPP
|
||||
@@ -76,6 +76,112 @@ struct valid_infer2_types< std::tuple<cv::GMat,Ns...>, std::tuple<T,Ts...> > {
|
||||
valid_infer2_types< std::tuple<cv::GMat>, std::tuple<T> >::value
|
||||
&& valid_infer2_types< std::tuple<Ns...>, std::tuple<Ts...> >::value;
|
||||
};
|
||||
|
||||
// Struct stores network input/output names.
|
||||
// Used by infer<Generic>
|
||||
struct InOutInfo
|
||||
{
|
||||
std::vector<std::string> in_names;
|
||||
std::vector<std::string> out_names;
|
||||
};
|
||||
|
||||
template <typename OutT>
|
||||
class GInferOutputsTyped
|
||||
{
|
||||
public:
|
||||
GInferOutputsTyped() = default;
|
||||
GInferOutputsTyped(std::shared_ptr<cv::GCall> call)
|
||||
: m_priv(std::make_shared<Priv>(std::move(call)))
|
||||
{
|
||||
}
|
||||
|
||||
OutT at(const std::string& name)
|
||||
{
|
||||
auto it = m_priv->blobs.find(name);
|
||||
if (it == m_priv->blobs.end()) {
|
||||
// FIXME: Avoid modifying GKernel
|
||||
auto shape = cv::detail::GTypeTraits<OutT>::shape;
|
||||
m_priv->call->kernel().outShapes.push_back(shape);
|
||||
m_priv->call->kernel().outCtors.emplace_back(cv::detail::GObtainCtor<OutT>::get());
|
||||
auto out_idx = static_cast<int>(m_priv->blobs.size());
|
||||
it = m_priv->blobs.emplace(name,
|
||||
cv::detail::Yield<OutT>::yield(*(m_priv->call), out_idx)).first;
|
||||
m_priv->info->out_names.push_back(name);
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
private:
|
||||
struct Priv
|
||||
{
|
||||
Priv(std::shared_ptr<cv::GCall> c)
|
||||
: call(std::move(c)), info(cv::util::any_cast<InOutInfo>(&call->params()))
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<cv::GCall> call;
|
||||
InOutInfo* info = nullptr;
|
||||
std::unordered_map<std::string, OutT> blobs;
|
||||
};
|
||||
|
||||
std::shared_ptr<Priv> m_priv;
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
class GInferInputsTyped
|
||||
{
|
||||
public:
|
||||
GInferInputsTyped()
|
||||
: m_priv(std::make_shared<Priv>())
|
||||
{
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
void setInput(const std::string& name, U in)
|
||||
{
|
||||
m_priv->blobs.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(name),
|
||||
std::forward_as_tuple(in));
|
||||
}
|
||||
|
||||
using StorageT = cv::util::variant<Ts...>;
|
||||
StorageT& operator[](const std::string& name) {
|
||||
return m_priv->blobs[name];
|
||||
}
|
||||
|
||||
using Map = std::unordered_map<std::string, StorageT>;
|
||||
const Map& getBlobs() const {
|
||||
return m_priv->blobs;
|
||||
}
|
||||
|
||||
private:
|
||||
struct Priv
|
||||
{
|
||||
std::unordered_map<std::string, StorageT> blobs;
|
||||
};
|
||||
|
||||
std::shared_ptr<Priv> m_priv;
|
||||
};
|
||||
|
||||
template<typename InferT>
|
||||
std::shared_ptr<cv::GCall> makeCall(const std::string &tag,
|
||||
std::vector<cv::GArg> &&args,
|
||||
std::vector<std::string> &&names,
|
||||
cv::GKinds &&kinds) {
|
||||
auto call = std::make_shared<cv::GCall>(GKernel{
|
||||
InferT::id(),
|
||||
tag,
|
||||
InferT::getOutMeta,
|
||||
{}, // outShape will be filled later
|
||||
std::move(kinds),
|
||||
{}, // outCtors will be filled later
|
||||
});
|
||||
|
||||
call->setArgs(std::move(args));
|
||||
call->params() = cv::detail::InOutInfo{std::move(names), {}};
|
||||
|
||||
return call;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// TODO: maybe tuple_wrap_helper from util.hpp may help with this.
|
||||
@@ -166,49 +272,6 @@ struct GInferBase {
|
||||
}
|
||||
};
|
||||
|
||||
// Struct stores network input/output names.
|
||||
// Used by infer<Generic>
|
||||
struct InOutInfo
|
||||
{
|
||||
std::vector<std::string> in_names;
|
||||
std::vector<std::string> out_names;
|
||||
};
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief G-API object used to collect network inputs
|
||||
*/
|
||||
class GAPI_EXPORTS_W_SIMPLE GInferInputs
|
||||
{
|
||||
using Map = std::unordered_map<std::string, GMat>;
|
||||
public:
|
||||
GAPI_WRAP GInferInputs();
|
||||
GAPI_WRAP void setInput(const std::string& name, const cv::GMat& value);
|
||||
|
||||
cv::GMat& operator[](const std::string& name);
|
||||
const Map& getBlobs() const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Map> in_blobs;
|
||||
};
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief G-API object used to collect network outputs
|
||||
*/
|
||||
struct GAPI_EXPORTS_W_SIMPLE GInferOutputs
|
||||
{
|
||||
public:
|
||||
GAPI_WRAP GInferOutputs() = default;
|
||||
GInferOutputs(std::shared_ptr<cv::GCall> call);
|
||||
GAPI_WRAP cv::GMat at(const std::string& name);
|
||||
|
||||
private:
|
||||
struct Priv;
|
||||
std::shared_ptr<Priv> m_priv;
|
||||
};
|
||||
/** @} */
|
||||
// Base "InferROI" kernel.
|
||||
// All notes from "Infer" kernel apply here as well.
|
||||
struct GInferROIBase {
|
||||
@@ -295,6 +358,90 @@ struct GInferList2 final
|
||||
static constexpr const char* tag() { return Net::tag(); }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief G-API object used to collect network inputs
|
||||
*/
|
||||
using GInferInputs = cv::detail::GInferInputsTyped<cv::GMat, cv::GFrame>;
|
||||
|
||||
/**
|
||||
* @brief G-API object used to collect the list of network inputs
|
||||
*/
|
||||
using GInferListInputs = cv::detail::GInferInputsTyped<cv::GArray<cv::GMat>, cv::GArray<cv::Rect>>;
|
||||
|
||||
/**
|
||||
* @brief G-API object used to collect network outputs
|
||||
*/
|
||||
using GInferOutputs = cv::detail::GInferOutputsTyped<cv::GMat>;
|
||||
|
||||
/**
|
||||
* @brief G-API object used to collect the list of network outputs
|
||||
*/
|
||||
using GInferListOutputs = cv::detail::GInferOutputsTyped<cv::GArray<cv::GMat>>;
|
||||
|
||||
namespace detail {
|
||||
void inline unpackBlobs(const cv::GInferInputs::Map& blobs,
|
||||
std::vector<cv::GArg>& args,
|
||||
std::vector<std::string>& names,
|
||||
cv::GKinds& kinds)
|
||||
{
|
||||
for (auto&& p : blobs) {
|
||||
names.emplace_back(p.first);
|
||||
switch (p.second.index()) {
|
||||
case cv::GInferInputs::StorageT::index_of<cv::GMat>():
|
||||
args.emplace_back(cv::util::get<cv::GMat>(p.second));
|
||||
kinds.emplace_back(cv::detail::OpaqueKind::CV_MAT);
|
||||
break;
|
||||
case cv::GInferInputs::StorageT::index_of<cv::GFrame>():
|
||||
args.emplace_back(cv::util::get<cv::GFrame>(p.second));
|
||||
kinds.emplace_back(cv::detail::OpaqueKind::CV_UNKNOWN);
|
||||
break;
|
||||
default:
|
||||
GAPI_Assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InferType>
|
||||
struct InferROITraits;
|
||||
|
||||
template <>
|
||||
struct InferROITraits<GInferROIBase>
|
||||
{
|
||||
using outType = cv::GInferOutputs;
|
||||
using inType = cv::GOpaque<cv::Rect>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct InferROITraits<GInferListBase>
|
||||
{
|
||||
using outType = cv::GInferListOutputs;
|
||||
using inType = cv::GArray<cv::Rect>;
|
||||
};
|
||||
|
||||
template<typename InferType>
|
||||
typename InferROITraits<InferType>::outType
|
||||
inferGenericROI(const std::string& tag,
|
||||
const typename InferROITraits<InferType>::inType& in,
|
||||
const cv::GInferInputs& inputs)
|
||||
{
|
||||
std::vector<cv::GArg> args;
|
||||
std::vector<std::string> names;
|
||||
cv::GKinds kinds;
|
||||
|
||||
args.emplace_back(in);
|
||||
kinds.emplace_back(cv::detail::OpaqueKind::CV_RECT);
|
||||
|
||||
unpackBlobs(inputs.getBlobs(), args, names, kinds);
|
||||
|
||||
auto call = cv::detail::makeCall<InferType>(tag,
|
||||
std::move(args),
|
||||
std::move(names),
|
||||
std::move(kinds));
|
||||
|
||||
return {std::move(call)};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace cv
|
||||
|
||||
// FIXME: Probably the <API> signature makes a function/tuple/function round-trip
|
||||
@@ -395,36 +542,101 @@ struct Generic { };
|
||||
* @param inputs networks's inputs
|
||||
* @return a GInferOutputs
|
||||
*/
|
||||
template<typename T = Generic> GInferOutputs
|
||||
infer(const std::string& tag, const GInferInputs& inputs)
|
||||
template<typename T = Generic> cv::GInferOutputs
|
||||
infer(const std::string& tag, const cv::GInferInputs& inputs)
|
||||
{
|
||||
std::vector<GArg> input_args;
|
||||
std::vector<std::string> input_names;
|
||||
std::vector<cv::GArg> args;
|
||||
std::vector<std::string> names;
|
||||
cv::GKinds kinds;
|
||||
|
||||
const auto& blobs = inputs.getBlobs();
|
||||
for (auto&& p : blobs)
|
||||
{
|
||||
input_names.push_back(p.first);
|
||||
input_args.emplace_back(p.second);
|
||||
}
|
||||
cv::detail::unpackBlobs(inputs.getBlobs(), args, names, kinds);
|
||||
|
||||
GKinds kinds(blobs.size(), cv::detail::OpaqueKind::CV_MAT);
|
||||
auto call = std::make_shared<cv::GCall>(GKernel{
|
||||
GInferBase::id(),
|
||||
tag,
|
||||
GInferBase::getOutMeta,
|
||||
{}, // outShape will be filled later
|
||||
std::move(kinds),
|
||||
{}, // outCtors will be filled later
|
||||
});
|
||||
auto call = cv::detail::makeCall<GInferBase>(tag,
|
||||
std::move(args),
|
||||
std::move(names),
|
||||
std::move(kinds));
|
||||
|
||||
call->setArgs(std::move(input_args));
|
||||
call->params() = InOutInfo{input_names, {}};
|
||||
|
||||
return GInferOutputs{std::move(call)};
|
||||
return cv::GInferOutputs{std::move(call)};
|
||||
}
|
||||
|
||||
GAPI_EXPORTS_W inline GInferOutputs infer(const String& name, const GInferInputs& inputs)
|
||||
/** @brief Calculates response for the generic network
|
||||
* for the specified region in the source image.
|
||||
* Currently expects a single-input network only.
|
||||
*
|
||||
* @param tag a network tag
|
||||
* @param roi a an object describing the region of interest
|
||||
* in the source image. May be calculated in the same graph dynamically.
|
||||
* @param inputs networks's inputs
|
||||
* @return a cv::GInferOutputs
|
||||
*/
|
||||
template<typename T = Generic> cv::GInferOutputs
|
||||
infer(const std::string& tag, const cv::GOpaque<cv::Rect>& roi, const cv::GInferInputs& inputs)
|
||||
{
|
||||
return cv::detail::inferGenericROI<GInferROIBase>(tag, roi, inputs);
|
||||
}
|
||||
|
||||
/** @brief Calculates responses for the specified network
|
||||
* for every region in the source image.
|
||||
*
|
||||
* @param tag a network tag
|
||||
* @param rois a list of rectangles describing regions of interest
|
||||
* in the source image. Usually an output of object detector or tracker.
|
||||
* @param inputs networks's inputs
|
||||
* @return a cv::GInferListOutputs
|
||||
*/
|
||||
template<typename T = Generic> cv::GInferListOutputs
|
||||
infer(const std::string& tag, const cv::GArray<cv::Rect>& rois, const cv::GInferInputs& inputs)
|
||||
{
|
||||
return cv::detail::inferGenericROI<GInferListBase>(tag, rois, inputs);
|
||||
}
|
||||
|
||||
/** @brief Calculates responses for the specified network
|
||||
* for every region in the source image, extended version.
|
||||
*
|
||||
* @param tag a network tag
|
||||
* @param in a source image containing regions of interest.
|
||||
* @param inputs networks's inputs
|
||||
* @return a cv::GInferListOutputs
|
||||
*/
|
||||
template<typename T = Generic, typename Input>
|
||||
typename std::enable_if<cv::detail::accepted_infer_types<Input>::value, cv::GInferListOutputs>::type
|
||||
infer2(const std::string& tag,
|
||||
const Input& in,
|
||||
const cv::GInferListInputs& inputs)
|
||||
{
|
||||
std::vector<cv::GArg> args;
|
||||
std::vector<std::string> names;
|
||||
cv::GKinds kinds;
|
||||
|
||||
args.emplace_back(in);
|
||||
auto k = cv::detail::GOpaqueTraits<Input>::kind;
|
||||
kinds.emplace_back(k);
|
||||
|
||||
for (auto&& p : inputs.getBlobs()) {
|
||||
names.emplace_back(p.first);
|
||||
switch (p.second.index()) {
|
||||
case cv::GInferListInputs::StorageT::index_of<cv::GArray<cv::GMat>>():
|
||||
args.emplace_back(cv::util::get<cv::GArray<cv::GMat>>(p.second));
|
||||
kinds.emplace_back(cv::detail::OpaqueKind::CV_MAT);
|
||||
break;
|
||||
case cv::GInferListInputs::StorageT::index_of<cv::GArray<cv::Rect>>():
|
||||
args.emplace_back(cv::util::get<cv::GArray<cv::Rect>>(p.second));
|
||||
kinds.emplace_back(cv::detail::OpaqueKind::CV_RECT);
|
||||
break;
|
||||
default:
|
||||
GAPI_Assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
auto call = cv::detail::makeCall<GInferList2Base>(tag,
|
||||
std::move(args),
|
||||
std::move(names),
|
||||
std::move(kinds));
|
||||
|
||||
return cv::GInferListOutputs{std::move(call)};
|
||||
}
|
||||
|
||||
GAPI_EXPORTS_W inline cv::GInferOutputs infer(const String& name, const cv::GInferInputs& inputs)
|
||||
{
|
||||
return infer<Generic>(name, inputs);
|
||||
}
|
||||
|
||||
@@ -222,6 +222,19 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
Params& constInput(const std::string &layer_name,
|
||||
const cv::Mat &data,
|
||||
TraitAs hint = TraitAs::TENSOR) {
|
||||
desc.const_inputs[layer_name] = {data, hint};
|
||||
return *this;
|
||||
}
|
||||
|
||||
Params& cfgNumRequests(size_t nireq) {
|
||||
GAPI_Assert(nireq > 0 && "Number of infer requests must be greater than zero!");
|
||||
desc.nireq = nireq;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// BEGIN(G-API's network parametrization API)
|
||||
GBackend backend() const { return cv::gapi::ie::backend(); }
|
||||
std::string tag() const { return m_tag; }
|
||||
|
||||
@@ -19,6 +19,21 @@ namespace cv
|
||||
using GProtoInputArgs = GIOProtoArgs<In_Tag>;
|
||||
using GProtoOutputArgs = GIOProtoArgs<Out_Tag>;
|
||||
|
||||
class GAPI_EXPORTS_W_SIMPLE GInferInputs
|
||||
{
|
||||
public:
|
||||
GAPI_WRAP GInferInputs();
|
||||
GAPI_WRAP void setInput(const std::string& name, const cv::GMat& value);
|
||||
GAPI_WRAP void setInput(const std::string& name, const cv::GFrame& value);
|
||||
};
|
||||
|
||||
class GAPI_EXPORTS_W_SIMPLE GInferOutputs
|
||||
{
|
||||
public:
|
||||
GAPI_WRAP GInferOutputs();
|
||||
GAPI_WRAP cv::GMat at(const std::string& name);
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct GAPI_EXPORTS_W_SIMPLE ExtractArgsCallback { };
|
||||
|
||||
@@ -7,15 +7,10 @@
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#include <functional> // hash
|
||||
#include <numeric> // accumulate
|
||||
#include <unordered_set>
|
||||
#include <iterator>
|
||||
|
||||
#include <ade/util/algorithm.hpp>
|
||||
|
||||
#include <opencv2/gapi/infer.hpp>
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
cv::gapi::GNetPackage::GNetPackage(std::initializer_list<GNetParam> ii)
|
||||
: networks(ii) {
|
||||
}
|
||||
@@ -25,59 +20,3 @@ std::vector<cv::gapi::GBackend> cv::gapi::GNetPackage::backends() const {
|
||||
for (const auto &nn : networks) unique_set.insert(nn.backend);
|
||||
return std::vector<cv::gapi::GBackend>(unique_set.begin(), unique_set.end());
|
||||
}
|
||||
|
||||
// FIXME: Inference API is currently only available in full mode
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
|
||||
cv::GInferInputs::GInferInputs()
|
||||
: in_blobs(std::make_shared<Map>())
|
||||
{
|
||||
}
|
||||
|
||||
cv::GMat& cv::GInferInputs::operator[](const std::string& name) {
|
||||
return (*in_blobs)[name];
|
||||
}
|
||||
|
||||
const cv::GInferInputs::Map& cv::GInferInputs::getBlobs() const {
|
||||
return *in_blobs;
|
||||
}
|
||||
|
||||
void cv::GInferInputs::setInput(const std::string& name, const cv::GMat& value) {
|
||||
in_blobs->emplace(name, value);
|
||||
}
|
||||
|
||||
struct cv::GInferOutputs::Priv
|
||||
{
|
||||
Priv(std::shared_ptr<cv::GCall>);
|
||||
|
||||
std::shared_ptr<cv::GCall> call;
|
||||
InOutInfo* info = nullptr;
|
||||
std::unordered_map<std::string, cv::GMat> out_blobs;
|
||||
};
|
||||
|
||||
cv::GInferOutputs::Priv::Priv(std::shared_ptr<cv::GCall> c)
|
||||
: call(std::move(c)), info(cv::util::any_cast<InOutInfo>(&call->params()))
|
||||
{
|
||||
}
|
||||
|
||||
cv::GInferOutputs::GInferOutputs(std::shared_ptr<cv::GCall> call)
|
||||
: m_priv(std::make_shared<cv::GInferOutputs::Priv>(std::move(call)))
|
||||
{
|
||||
}
|
||||
|
||||
cv::GMat cv::GInferOutputs::at(const std::string& name)
|
||||
{
|
||||
auto it = m_priv->out_blobs.find(name);
|
||||
if (it == m_priv->out_blobs.end()) {
|
||||
// FIXME: Avoid modifying GKernel
|
||||
// Expect output to be always GMat
|
||||
m_priv->call->kernel().outShapes.push_back(cv::GShape::GMAT);
|
||||
// ...so _empty_ constructor is passed here.
|
||||
m_priv->call->kernel().outCtors.emplace_back(cv::util::monostate{});
|
||||
int out_idx = static_cast<int>(m_priv->out_blobs.size());
|
||||
it = m_priv->out_blobs.emplace(name, m_priv->call->yield(out_idx)).first;
|
||||
m_priv->info->out_names.push_back(name);
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
#endif // GAPI_STANDALONE
|
||||
|
||||
@@ -1242,7 +1242,7 @@ namespace {
|
||||
// NB: In case generic infer, info about in/out names is stored in operation (op.params)
|
||||
if (pp.is_generic)
|
||||
{
|
||||
auto& info = cv::util::any_cast<cv::InOutInfo>(op.params);
|
||||
auto& info = cv::util::any_cast<cv::detail::InOutInfo>(op.params);
|
||||
pp.input_names = info.in_names;
|
||||
pp.output_names = info.out_names;
|
||||
pp.num_in = info.in_names.size();
|
||||
|
||||
@@ -489,6 +489,126 @@ struct ROIListNV12: public ::testing::Test {
|
||||
}
|
||||
};
|
||||
|
||||
struct SingleROI: public ::testing::Test {
|
||||
cv::gapi::ie::detail::ParamDesc params;
|
||||
|
||||
cv::Mat m_in_mat;
|
||||
cv::Rect m_roi;
|
||||
|
||||
cv::Mat m_out_gapi_age;
|
||||
cv::Mat m_out_gapi_gender;
|
||||
|
||||
cv::Mat m_out_ie_age;
|
||||
cv::Mat m_out_ie_gender;
|
||||
|
||||
void SetUp() {
|
||||
initDLDTDataPath();
|
||||
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";
|
||||
|
||||
// FIXME: it must be cv::imread(findDataFile("../dnn/grace_hopper_227.png", false));
|
||||
m_in_mat = cv::Mat(cv::Size(320, 240), CV_8UC3);
|
||||
cv::randu(m_in_mat, 0, 255);
|
||||
|
||||
m_roi = cv::Rect(cv::Point{64, 60}, cv::Size{96, 96});
|
||||
|
||||
// Load & run IE network
|
||||
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 this_network = cv::gimpl::ie::wrap::loadNetwork(plugin, net, params);
|
||||
auto infer_request = this_network.CreateInferRequest();
|
||||
|
||||
const auto ie_rc = IE::ROI {
|
||||
0u
|
||||
, static_cast<std::size_t>(m_roi.x)
|
||||
, static_cast<std::size_t>(m_roi.y)
|
||||
, static_cast<std::size_t>(m_roi.width)
|
||||
, static_cast<std::size_t>(m_roi.height)
|
||||
};
|
||||
|
||||
IE::Blob::Ptr roi_blob = IE::make_shared_blob(cv::gapi::ie::util::to_ie(m_in_mat), ie_rc);
|
||||
infer_request.SetBlob("data", roi_blob);
|
||||
infer_request.Infer();
|
||||
|
||||
using namespace cv::gapi::ie::util;
|
||||
m_out_ie_age = to_ocv(infer_request.GetBlob("age_conv3")).clone();
|
||||
m_out_ie_gender = to_ocv(infer_request.GetBlob("prob")).clone();
|
||||
}
|
||||
}
|
||||
|
||||
void validate() {
|
||||
// Validate with IE itself (avoid DNN module dependency here)
|
||||
normAssert(m_out_ie_age , m_out_gapi_age , "Test age output");
|
||||
normAssert(m_out_ie_gender, m_out_gapi_gender, "Test gender output");
|
||||
}
|
||||
};
|
||||
|
||||
struct SingleROINV12: public ::testing::Test {
|
||||
cv::gapi::ie::detail::ParamDesc params;
|
||||
|
||||
cv::Mat m_in_y;
|
||||
cv::Mat m_in_uv;
|
||||
cv::Rect m_roi;
|
||||
|
||||
cv::Mat m_out_gapi_age;
|
||||
cv::Mat m_out_gapi_gender;
|
||||
|
||||
cv::Mat m_out_ie_age;
|
||||
cv::Mat m_out_ie_gender;
|
||||
|
||||
void SetUp() {
|
||||
initDLDTDataPath();
|
||||
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";
|
||||
|
||||
cv::Size sz{320, 240};
|
||||
m_in_y = cv::Mat{sz, CV_8UC1};
|
||||
cv::randu(m_in_y, 0, 255);
|
||||
m_in_uv = cv::Mat{sz / 2, CV_8UC2};
|
||||
cv::randu(m_in_uv, 0, 255);
|
||||
|
||||
m_roi = cv::Rect(cv::Point{64, 60}, cv::Size{96, 96});
|
||||
|
||||
// Load & run IE network
|
||||
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, /* NV12 */ true);
|
||||
auto this_network = cv::gimpl::ie::wrap::loadNetwork(plugin, net, params);
|
||||
auto infer_request = this_network.CreateInferRequest();
|
||||
auto blob = cv::gapi::ie::util::to_ie(m_in_y, m_in_uv);
|
||||
|
||||
const auto ie_rc = IE::ROI {
|
||||
0u
|
||||
, static_cast<std::size_t>(m_roi.x)
|
||||
, static_cast<std::size_t>(m_roi.y)
|
||||
, static_cast<std::size_t>(m_roi.width)
|
||||
, static_cast<std::size_t>(m_roi.height)
|
||||
};
|
||||
|
||||
IE::Blob::Ptr roi_blob = IE::make_shared_blob(blob, ie_rc);
|
||||
infer_request.SetBlob("data", roi_blob);
|
||||
infer_request.Infer();
|
||||
|
||||
using namespace cv::gapi::ie::util;
|
||||
m_out_ie_age = to_ocv(infer_request.GetBlob("age_conv3")).clone();
|
||||
m_out_ie_gender = to_ocv(infer_request.GetBlob("prob")).clone();
|
||||
}
|
||||
}
|
||||
|
||||
void validate() {
|
||||
// Validate with IE itself (avoid DNN module dependency here)
|
||||
normAssert(m_out_ie_age , m_out_gapi_age , "Test age output");
|
||||
normAssert(m_out_ie_gender, m_out_gapi_gender, "Test gender output");
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ROIList, TestInfer)
|
||||
{
|
||||
cv::GArray<cv::Rect> rr;
|
||||
@@ -501,8 +621,8 @@ TEST_F(ROIList, TestInfer)
|
||||
params.model_path, params.weights_path, params.device_id
|
||||
}.cfgOutputLayers({ "age_conv3", "prob" });
|
||||
comp.apply(cv::gin(m_in_mat, m_roi_list),
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
validate();
|
||||
}
|
||||
|
||||
@@ -1062,6 +1182,234 @@ TEST_F(ROIListNV12, Infer2MediaInputNV12)
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST_F(SingleROI, GenericInfer)
|
||||
{
|
||||
// Configure & run G-API
|
||||
cv::GMat in;
|
||||
cv::GOpaque<cv::Rect> roi;
|
||||
cv::GInferInputs inputs;
|
||||
inputs["data"] = in;
|
||||
|
||||
auto outputs = cv::gapi::infer<cv::gapi::Generic>("age-gender-generic", roi, inputs);
|
||||
auto age = outputs.at("age_conv3");
|
||||
auto gender = outputs.at("prob");
|
||||
|
||||
cv::GComputation comp(cv::GIn(in, roi), cv::GOut(age, gender));
|
||||
|
||||
cv::gapi::ie::Params<cv::gapi::Generic> pp{
|
||||
"age-gender-generic", params.model_path, params.weights_path, params.device_id
|
||||
};
|
||||
pp.cfgNumRequests(2u);
|
||||
|
||||
comp.apply(cv::gin(m_in_mat, m_roi), cv::gout(m_out_gapi_age, m_out_gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST_F(SingleROI, GenericInferMediaBGR)
|
||||
{
|
||||
// Configure & run G-API
|
||||
cv::GFrame in;
|
||||
cv::GOpaque<cv::Rect> roi;
|
||||
cv::GInferInputs inputs;
|
||||
inputs["data"] = in;
|
||||
|
||||
auto outputs = cv::gapi::infer<cv::gapi::Generic>("age-gender-generic", roi, inputs);
|
||||
auto age = outputs.at("age_conv3");
|
||||
auto gender = outputs.at("prob");
|
||||
|
||||
cv::GComputation comp(cv::GIn(in, roi), cv::GOut(age, gender));
|
||||
|
||||
cv::gapi::ie::Params<cv::gapi::Generic> pp{
|
||||
"age-gender-generic", params.model_path, params.weights_path, params.device_id
|
||||
};
|
||||
pp.cfgNumRequests(2u);
|
||||
|
||||
auto frame = MediaFrame::Create<TestMediaBGR>(m_in_mat);
|
||||
comp.apply(cv::gin(frame, m_roi), cv::gout(m_out_gapi_age, m_out_gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST_F(SingleROINV12, GenericInferMediaNV12)
|
||||
{
|
||||
// Configure & run G-API
|
||||
cv::GFrame in;
|
||||
cv::GOpaque<cv::Rect> roi;
|
||||
cv::GInferInputs inputs;
|
||||
inputs["data"] = in;
|
||||
|
||||
auto outputs = cv::gapi::infer<cv::gapi::Generic>("age-gender-generic", roi, inputs);
|
||||
auto age = outputs.at("age_conv3");
|
||||
auto gender = outputs.at("prob");
|
||||
|
||||
cv::GComputation comp(cv::GIn(in, roi), cv::GOut(age, gender));
|
||||
|
||||
cv::gapi::ie::Params<cv::gapi::Generic> pp{
|
||||
"age-gender-generic", params.model_path, params.weights_path, params.device_id
|
||||
};
|
||||
pp.cfgNumRequests(2u);
|
||||
|
||||
auto frame = MediaFrame::Create<TestMediaNV12>(m_in_y, m_in_uv);
|
||||
comp.apply(cv::gin(frame, m_roi), cv::gout(m_out_gapi_age, m_out_gapi_gender),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST_F(ROIList, GenericInfer)
|
||||
{
|
||||
cv::GMat in;
|
||||
cv::GArray<cv::Rect> rr;
|
||||
cv::GInferInputs inputs;
|
||||
inputs["data"] = in;
|
||||
|
||||
auto outputs = cv::gapi::infer<cv::gapi::Generic>("age-gender-generic", rr, inputs);
|
||||
auto age = outputs.at("age_conv3");
|
||||
auto gender = outputs.at("prob");
|
||||
|
||||
cv::GComputation comp(cv::GIn(in, rr), cv::GOut(age, gender));
|
||||
|
||||
cv::gapi::ie::Params<cv::gapi::Generic> pp{
|
||||
"age-gender-generic", params.model_path, params.weights_path, params.device_id
|
||||
};
|
||||
pp.cfgNumRequests(2u);
|
||||
|
||||
comp.apply(cv::gin(m_in_mat, m_roi_list),
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST_F(ROIList, GenericInferMediaBGR)
|
||||
{
|
||||
cv::GFrame in;
|
||||
cv::GArray<cv::Rect> rr;
|
||||
cv::GInferInputs inputs;
|
||||
inputs["data"] = in;
|
||||
|
||||
auto outputs = cv::gapi::infer<cv::gapi::Generic>("age-gender-generic", rr, inputs);
|
||||
auto age = outputs.at("age_conv3");
|
||||
auto gender = outputs.at("prob");
|
||||
|
||||
cv::GComputation comp(cv::GIn(in, rr), cv::GOut(age, gender));
|
||||
|
||||
cv::gapi::ie::Params<cv::gapi::Generic> pp{
|
||||
"age-gender-generic", params.model_path, params.weights_path, params.device_id
|
||||
};
|
||||
pp.cfgNumRequests(2u);
|
||||
|
||||
auto frame = MediaFrame::Create<TestMediaBGR>(m_in_mat);
|
||||
comp.apply(cv::gin(frame, m_roi_list),
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST_F(ROIListNV12, GenericInferMediaNV12)
|
||||
{
|
||||
cv::GFrame in;
|
||||
cv::GArray<cv::Rect> rr;
|
||||
cv::GInferInputs inputs;
|
||||
inputs["data"] = in;
|
||||
|
||||
auto outputs = cv::gapi::infer<cv::gapi::Generic>("age-gender-generic", rr, inputs);
|
||||
auto age = outputs.at("age_conv3");
|
||||
auto gender = outputs.at("prob");
|
||||
|
||||
cv::GComputation comp(cv::GIn(in, rr), cv::GOut(age, gender));
|
||||
|
||||
cv::gapi::ie::Params<cv::gapi::Generic> pp{
|
||||
"age-gender-generic", params.model_path, params.weights_path, params.device_id
|
||||
};
|
||||
pp.cfgNumRequests(2u);
|
||||
|
||||
auto frame = MediaFrame::Create<TestMediaNV12>(m_in_y, m_in_uv);
|
||||
comp.apply(cv::gin(frame, m_roi_list),
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST_F(ROIList, GenericInfer2)
|
||||
{
|
||||
cv::GArray<cv::Rect> rr;
|
||||
cv::GMat in;
|
||||
GInferListInputs list;
|
||||
list["data"] = rr;
|
||||
|
||||
auto outputs = cv::gapi::infer2<cv::gapi::Generic>("age-gender-generic", in, list);
|
||||
auto age = outputs.at("age_conv3");
|
||||
auto gender = outputs.at("prob");
|
||||
|
||||
cv::GComputation comp(cv::GIn(in, rr), cv::GOut(age, gender));
|
||||
|
||||
cv::gapi::ie::Params<cv::gapi::Generic> pp{
|
||||
"age-gender-generic", params.model_path, params.weights_path, params.device_id
|
||||
};
|
||||
pp.cfgNumRequests(2u);
|
||||
|
||||
comp.apply(cv::gin(m_in_mat, m_roi_list),
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST_F(ROIList, GenericInfer2MediaInputBGR)
|
||||
{
|
||||
cv::GArray<cv::Rect> rr;
|
||||
cv::GFrame in;
|
||||
GInferListInputs inputs;
|
||||
inputs["data"] = rr;
|
||||
|
||||
auto outputs = cv::gapi::infer2<cv::gapi::Generic>("age-gender-generic", in, inputs);
|
||||
auto age = outputs.at("age_conv3");
|
||||
auto gender = outputs.at("prob");
|
||||
|
||||
cv::GComputation comp(cv::GIn(in, rr), cv::GOut(age, gender));
|
||||
|
||||
cv::gapi::ie::Params<cv::gapi::Generic> pp{
|
||||
"age-gender-generic", params.model_path, params.weights_path, params.device_id
|
||||
};
|
||||
pp.cfgNumRequests(2u);
|
||||
|
||||
auto frame = MediaFrame::Create<TestMediaBGR>(m_in_mat);
|
||||
comp.apply(cv::gin(frame, m_roi_list),
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST_F(ROIListNV12, GenericInfer2MediaInputNV12)
|
||||
{
|
||||
cv::GArray<cv::Rect> rr;
|
||||
cv::GFrame in;
|
||||
GInferListInputs inputs;
|
||||
inputs["data"] = rr;
|
||||
|
||||
auto outputs = cv::gapi::infer2<cv::gapi::Generic>("age-gender-generic", in, inputs);
|
||||
auto age = outputs.at("age_conv3");
|
||||
auto gender = outputs.at("prob");
|
||||
|
||||
cv::GComputation comp(cv::GIn(in, rr), cv::GOut(age, gender));
|
||||
|
||||
cv::gapi::ie::Params<cv::gapi::Generic> pp{
|
||||
"age-gender-generic", params.model_path, params.weights_path, params.device_id
|
||||
};
|
||||
pp.cfgNumRequests(2u);
|
||||
|
||||
auto frame = MediaFrame::Create<TestMediaNV12>(m_in_y, m_in_uv);
|
||||
comp.apply(cv::gin(frame, m_roi_list),
|
||||
cv::gout(m_out_gapi_ages, m_out_gapi_genders),
|
||||
cv::compile_args(cv::gapi::networks(pp)));
|
||||
validate();
|
||||
}
|
||||
|
||||
TEST(Infer, SetInvalidNumberOfRequests)
|
||||
{
|
||||
using AGInfo = std::tuple<cv::GMat, cv::GMat>;
|
||||
|
||||
Reference in New Issue
Block a user