From 50a264d832f6a8ba4107ee67e72ad7176d5701cd Mon Sep 17 00:00:00 2001 From: Anatoliy Talamanov Date: Fri, 19 Mar 2021 15:50:45 +0300 Subject: [PATCH] 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 --- modules/gapi/include/opencv2/gapi/infer.hpp | 348 +++++++++++++---- .../gapi/include/opencv2/gapi/infer/ie.hpp | 13 + modules/gapi/misc/python/shadow_gapi.hpp | 15 + modules/gapi/src/api/ginfer.cpp | 65 +--- modules/gapi/src/backends/ie/giebackend.cpp | 2 +- .../gapi/test/infer/gapi_infer_ie_test.cpp | 352 +++++++++++++++++- 6 files changed, 661 insertions(+), 134 deletions(-) diff --git a/modules/gapi/include/opencv2/gapi/infer.hpp b/modules/gapi/include/opencv2/gapi/infer.hpp index 8e3baedb79..68678e883c 100644 --- a/modules/gapi/include/opencv2/gapi/infer.hpp +++ b/modules/gapi/include/opencv2/gapi/infer.hpp @@ -2,7 +2,7 @@ // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. // -// Copyright (C) 2019-2020 Intel Corporation +// Copyright (C) 2019-2021 Intel Corporation #ifndef OPENCV_GAPI_INFER_HPP @@ -76,6 +76,112 @@ struct valid_infer2_types< std::tuple, std::tuple > { valid_infer2_types< std::tuple, std::tuple >::value && valid_infer2_types< std::tuple, std::tuple >::value; }; + +// Struct stores network input/output names. +// Used by infer +struct InOutInfo +{ + std::vector in_names; + std::vector out_names; +}; + +template +class GInferOutputsTyped +{ +public: + GInferOutputsTyped() = default; + GInferOutputsTyped(std::shared_ptr call) + : m_priv(std::make_shared(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::shape; + m_priv->call->kernel().outShapes.push_back(shape); + m_priv->call->kernel().outCtors.emplace_back(cv::detail::GObtainCtor::get()); + auto out_idx = static_cast(m_priv->blobs.size()); + it = m_priv->blobs.emplace(name, + cv::detail::Yield::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 c) + : call(std::move(c)), info(cv::util::any_cast(&call->params())) + { + } + + std::shared_ptr call; + InOutInfo* info = nullptr; + std::unordered_map blobs; + }; + + std::shared_ptr m_priv; +}; + +template +class GInferInputsTyped +{ +public: + GInferInputsTyped() + : m_priv(std::make_shared()) + { + } + + template + 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; + StorageT& operator[](const std::string& name) { + return m_priv->blobs[name]; + } + + using Map = std::unordered_map; + const Map& getBlobs() const { + return m_priv->blobs; + } + +private: + struct Priv + { + std::unordered_map blobs; + }; + + std::shared_ptr m_priv; +}; + +template +std::shared_ptr makeCall(const std::string &tag, + std::vector &&args, + std::vector &&names, + cv::GKinds &&kinds) { + auto call = std::make_shared(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 -struct InOutInfo -{ - std::vector in_names; - std::vector out_names; -}; - -/** - * @{ - * @brief G-API object used to collect network inputs - */ -class GAPI_EXPORTS_W_SIMPLE GInferInputs -{ -using Map = std::unordered_map; -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 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 call); - GAPI_WRAP cv::GMat at(const std::string& name); - -private: - struct Priv; - std::shared_ptr 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; + +/** + * @brief G-API object used to collect the list of network inputs + */ +using GInferListInputs = cv::detail::GInferInputsTyped, cv::GArray>; + +/** + * @brief G-API object used to collect network outputs + */ +using GInferOutputs = cv::detail::GInferOutputsTyped; + +/** + * @brief G-API object used to collect the list of network outputs + */ +using GInferListOutputs = cv::detail::GInferOutputsTyped>; + +namespace detail { +void inline unpackBlobs(const cv::GInferInputs::Map& blobs, + std::vector& args, + std::vector& names, + cv::GKinds& kinds) +{ + for (auto&& p : blobs) { + names.emplace_back(p.first); + switch (p.second.index()) { + case cv::GInferInputs::StorageT::index_of(): + args.emplace_back(cv::util::get(p.second)); + kinds.emplace_back(cv::detail::OpaqueKind::CV_MAT); + break; + case cv::GInferInputs::StorageT::index_of(): + args.emplace_back(cv::util::get(p.second)); + kinds.emplace_back(cv::detail::OpaqueKind::CV_UNKNOWN); + break; + default: + GAPI_Assert(false); + } + } +} + +template +struct InferROITraits; + +template <> +struct InferROITraits +{ + using outType = cv::GInferOutputs; + using inType = cv::GOpaque; +}; + +template <> +struct InferROITraits +{ + using outType = cv::GInferListOutputs; + using inType = cv::GArray; +}; + +template +typename InferROITraits::outType +inferGenericROI(const std::string& tag, + const typename InferROITraits::inType& in, + const cv::GInferInputs& inputs) +{ + std::vector args; + std::vector 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(tag, + std::move(args), + std::move(names), + std::move(kinds)); + + return {std::move(call)}; +} + +} // namespace detail } // namespace cv // FIXME: Probably the signature makes a function/tuple/function round-trip @@ -395,36 +542,101 @@ struct Generic { }; * @param inputs networks's inputs * @return a GInferOutputs */ -template GInferOutputs -infer(const std::string& tag, const GInferInputs& inputs) +template cv::GInferOutputs +infer(const std::string& tag, const cv::GInferInputs& inputs) { - std::vector input_args; - std::vector input_names; + std::vector args; + std::vector 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(GKernel{ - GInferBase::id(), - tag, - GInferBase::getOutMeta, - {}, // outShape will be filled later - std::move(kinds), - {}, // outCtors will be filled later - }); + auto call = cv::detail::makeCall(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 cv::GInferOutputs +infer(const std::string& tag, const cv::GOpaque& roi, const cv::GInferInputs& inputs) +{ + return cv::detail::inferGenericROI(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 cv::GInferListOutputs +infer(const std::string& tag, const cv::GArray& rois, const cv::GInferInputs& inputs) +{ + return cv::detail::inferGenericROI(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 std::enable_if::value, cv::GInferListOutputs>::type +infer2(const std::string& tag, + const Input& in, + const cv::GInferListInputs& inputs) +{ + std::vector args; + std::vector names; + cv::GKinds kinds; + + args.emplace_back(in); + auto k = cv::detail::GOpaqueTraits::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>(): + args.emplace_back(cv::util::get>(p.second)); + kinds.emplace_back(cv::detail::OpaqueKind::CV_MAT); + break; + case cv::GInferListInputs::StorageT::index_of>(): + args.emplace_back(cv::util::get>(p.second)); + kinds.emplace_back(cv::detail::OpaqueKind::CV_RECT); + break; + default: + GAPI_Assert(false); + } + } + + auto call = cv::detail::makeCall(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(name, inputs); } diff --git a/modules/gapi/include/opencv2/gapi/infer/ie.hpp b/modules/gapi/include/opencv2/gapi/infer/ie.hpp index 3f5c57f663..60137c960c 100644 --- a/modules/gapi/include/opencv2/gapi/infer/ie.hpp +++ b/modules/gapi/include/opencv2/gapi/infer/ie.hpp @@ -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; } diff --git a/modules/gapi/misc/python/shadow_gapi.hpp b/modules/gapi/misc/python/shadow_gapi.hpp index baf2138029..877a7c4c10 100644 --- a/modules/gapi/misc/python/shadow_gapi.hpp +++ b/modules/gapi/misc/python/shadow_gapi.hpp @@ -19,6 +19,21 @@ namespace cv using GProtoInputArgs = GIOProtoArgs; using GProtoOutputArgs = GIOProtoArgs; + 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 { }; diff --git a/modules/gapi/src/api/ginfer.cpp b/modules/gapi/src/api/ginfer.cpp index f4bd1c3abb..e3cc94041c 100644 --- a/modules/gapi/src/api/ginfer.cpp +++ b/modules/gapi/src/api/ginfer.cpp @@ -7,15 +7,10 @@ #include "precomp.hpp" -#include // hash -#include // accumulate -#include -#include - -#include - #include +#include + cv::gapi::GNetPackage::GNetPackage(std::initializer_list ii) : networks(ii) { } @@ -25,59 +20,3 @@ std::vector cv::gapi::GNetPackage::backends() const { for (const auto &nn : networks) unique_set.insert(nn.backend); return std::vector(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()) -{ -} - -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); - - std::shared_ptr call; - InOutInfo* info = nullptr; - std::unordered_map out_blobs; -}; - -cv::GInferOutputs::Priv::Priv(std::shared_ptr c) - : call(std::move(c)), info(cv::util::any_cast(&call->params())) -{ -} - -cv::GInferOutputs::GInferOutputs(std::shared_ptr call) - : m_priv(std::make_shared(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(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 diff --git a/modules/gapi/src/backends/ie/giebackend.cpp b/modules/gapi/src/backends/ie/giebackend.cpp index bbb7855737..ecf37cf360 100644 --- a/modules/gapi/src/backends/ie/giebackend.cpp +++ b/modules/gapi/src/backends/ie/giebackend.cpp @@ -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(op.params); + auto& info = cv::util::any_cast(op.params); pp.input_names = info.in_names; pp.output_names = info.out_names; pp.num_in = info.in_names.size(); diff --git a/modules/gapi/test/infer/gapi_infer_ie_test.cpp b/modules/gapi/test/infer/gapi_infer_ie_test.cpp index d81b80a4d8..366b7b18f2 100644 --- a/modules/gapi/test/infer/gapi_infer_ie_test.cpp +++ b/modules/gapi/test/infer/gapi_infer_ie_test.cpp @@ -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(m_roi.x) + , static_cast(m_roi.y) + , static_cast(m_roi.width) + , static_cast(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(m_roi.x) + , static_cast(m_roi.y) + , static_cast(m_roi.width) + , static_cast(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 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 roi; + cv::GInferInputs inputs; + inputs["data"] = in; + + auto outputs = cv::gapi::infer("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 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 roi; + cv::GInferInputs inputs; + inputs["data"] = in; + + auto outputs = cv::gapi::infer("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 pp{ + "age-gender-generic", params.model_path, params.weights_path, params.device_id + }; + pp.cfgNumRequests(2u); + + auto frame = MediaFrame::Create(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 roi; + cv::GInferInputs inputs; + inputs["data"] = in; + + auto outputs = cv::gapi::infer("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 pp{ + "age-gender-generic", params.model_path, params.weights_path, params.device_id + }; + pp.cfgNumRequests(2u); + + auto frame = MediaFrame::Create(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 rr; + cv::GInferInputs inputs; + inputs["data"] = in; + + auto outputs = cv::gapi::infer("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 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 rr; + cv::GInferInputs inputs; + inputs["data"] = in; + + auto outputs = cv::gapi::infer("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 pp{ + "age-gender-generic", params.model_path, params.weights_path, params.device_id + }; + pp.cfgNumRequests(2u); + + auto frame = MediaFrame::Create(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 rr; + cv::GInferInputs inputs; + inputs["data"] = in; + + auto outputs = cv::gapi::infer("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 pp{ + "age-gender-generic", params.model_path, params.weights_path, params.device_id + }; + pp.cfgNumRequests(2u); + + auto frame = MediaFrame::Create(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 rr; + cv::GMat in; + GInferListInputs list; + list["data"] = rr; + + auto outputs = cv::gapi::infer2("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 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 rr; + cv::GFrame in; + GInferListInputs inputs; + inputs["data"] = rr; + + auto outputs = cv::gapi::infer2("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 pp{ + "age-gender-generic", params.model_path, params.weights_path, params.device_id + }; + pp.cfgNumRequests(2u); + + auto frame = MediaFrame::Create(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 rr; + cv::GFrame in; + GInferListInputs inputs; + inputs["data"] = rr; + + auto outputs = cv::gapi::infer2("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 pp{ + "age-gender-generic", params.model_path, params.weights_path, params.device_id + }; + pp.cfgNumRequests(2u); + + auto frame = MediaFrame::Create(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;