diff --git a/modules/gapi/src/backends/ie/giebackend.cpp b/modules/gapi/src/backends/ie/giebackend.cpp index c69302baca..a633431fd8 100644 --- a/modules/gapi/src/backends/ie/giebackend.cpp +++ b/modules/gapi/src/backends/ie/giebackend.cpp @@ -218,14 +218,18 @@ struct IEUnit { cv::gapi::ie::detail::ParamDesc params; IE::CNNNetwork net; - IE::InputsDataMap inputs; - IE::OutputsDataMap outputs; IE::ExecutableNetwork this_network; cv::gimpl::ie::wrap::Plugin this_plugin; InferenceEngine::RemoteContext::Ptr rctx = nullptr; + // FIXME: Unlike loadNetwork case, importNetwork requires that preprocessing + // should be passed as ExecutableNetwork::SetBlob method, so need to collect + // and store this information at the graph compilation stage (outMeta) and use in runtime. + using PreProcMap = std::unordered_map; + PreProcMap preproc_map; + explicit IEUnit(const cv::gapi::ie::detail::ParamDesc &pp) : params(pp) { InferenceEngine::ParamMap* ctx_params = @@ -238,11 +242,8 @@ struct IEUnit { if (params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) { net = cv::gimpl::ie::wrap::readNetwork(params); net.setBatchSize(params.batch_size); - inputs = net.getInputsInfo(); - outputs = net.getOutputsInfo(); } else if (params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import) { this_plugin = cv::gimpl::ie::wrap::getPlugin(params); - this_plugin.SetConfig(params.config); this_network = cv::gimpl::ie::wrap::importNetwork(this_plugin, params, rctx); if (!params.reshape_table.empty() || !params.layer_names_to_reshape.empty()) { GAPI_LOG_WARNING(NULL, "Reshape isn't supported for imported network"); @@ -268,14 +269,14 @@ struct IEUnit { } if (params.num_in == 1u && params.input_names.empty()) { if (params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) { - params.input_names = { inputs.begin()->first }; + params.input_names = { net.getInputsInfo().begin()->first }; } else { params.input_names = { this_network.GetInputsInfo().begin()->first }; } } if (params.num_out == 1u && params.output_names.empty()) { if (params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) { - params.output_names = { outputs.begin()->first }; + params.output_names = { net.getOutputsInfo().begin()->first }; } else { params.output_names = { this_network.GetOutputsInfo().begin()->first }; } @@ -290,11 +291,11 @@ struct IEUnit { // This method is [supposed to be] called at Island compilation stage cv::gimpl::ie::IECompiled compile() const { IEUnit* non_const_this = const_cast(this); + // FIXME: LoadNetwork must be called only after all necessary model + // inputs information is set, since it's done in outMeta and compile called after that, + // this place seems to be suitable, but consider another place not to break const agreements. if (params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) { - // FIXME: In case importNetwork for fill inputs/outputs need to obtain ExecutableNetwork, but - // for loadNetwork they can be obtained by using readNetwork non_const_this->this_plugin = cv::gimpl::ie::wrap::getPlugin(params); - non_const_this->this_plugin.SetConfig(params.config); non_const_this->this_network = cv::gimpl::ie::wrap::loadNetwork(non_const_this->this_plugin, net, params, rctx); } @@ -540,19 +541,16 @@ inline IE::Blob::Ptr extractBlob(IECallContext& ctx, std::size_t i) { } -static void setBlob(InferenceEngine::InferRequest& req, - cv::gapi::ie::detail::ParamDesc::Kind kind, - const std::string& layer_name, - IE::Blob::Ptr blob) { - // NB: In case importNetwork preprocessing must be - // passed as SetBlob argument. - if (kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) { +static void setBlob(InferenceEngine::InferRequest& req, + const std::string& layer_name, + const IE::Blob::Ptr& blob, + const IECallContext& ctx) { + using namespace cv::gapi::ie::detail; + if (ctx.uu.params.kind == ParamDesc::Kind::Load) { req.SetBlob(layer_name, blob); } else { - GAPI_Assert(kind == cv::gapi::ie::detail::ParamDesc::Kind::Import); - IE::PreProcessInfo info; - info.setResizeAlgorithm(IE::RESIZE_BILINEAR); - req.SetBlob(layer_name, blob, info); + GAPI_Assert(ctx.uu.params.kind == ParamDesc::Kind::Import); + req.SetBlob(layer_name, blob, ctx.uu.preproc_map.at(layer_name)); } } @@ -822,6 +820,23 @@ static void configureInputInfo(const IE::InputInfo::Ptr& ii, const cv::GMetaArg } } +static IE::PreProcessInfo configurePreProcInfo(const IE::InputInfo::CPtr& ii, + const cv::GMetaArg& mm) { + IE::PreProcessInfo info; + if (cv::util::holds_alternative(mm)) { + auto desc = cv::util::get(mm); + if (desc.fmt == cv::MediaFormat::NV12) { + info.setColorFormat(IE::ColorFormat::NV12); + } + } + const auto layout = ii->getTensorDesc().getLayout(); + if (layout == IE::Layout::NCHW || + layout == IE::Layout::NHWC) { + info.setResizeAlgorithm(IE::RESIZE_BILINEAR); + } + return info; +} + // NB: This is a callback used by async infer // to post outputs blobs (cv::GMat's). static void PostOutputs(InferenceEngine::InferRequest &request, @@ -921,11 +936,13 @@ struct Infer: public cv::detail::KernelTag { // NB: Configuring input precision and network reshape must be done // only in the loadNetwork case. - if (uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) { + using namespace cv::gapi::ie::detail; + if (uu.params.kind == ParamDesc::Kind::Load) { + auto inputs = uu.net.getInputsInfo(); for (auto &&it : ade::util::zip(ade::util::toRange(uu.params.input_names), ade::util::toRange(in_metas))) { const auto &input_name = std::get<0>(it); - auto &&ii = uu.inputs.at(input_name); + auto ii = inputs.at(input_name); const auto & mm = std::get<1>(it); configureInputInfo(ii, mm); @@ -942,6 +959,18 @@ struct Infer: public cv::detail::KernelTag { if (!input_reshape_table.empty()) { const_cast(&uu.net)->reshape(input_reshape_table); } + } else { + GAPI_Assert(uu.params.kind == ParamDesc::Kind::Import); + auto inputs = uu.this_network.GetInputsInfo(); + // FIXME: This isn't the best place to collect PreProcMap. + auto* non_const_prepm = const_cast(&uu.preproc_map); + for (auto &&it : ade::util::zip(ade::util::toRange(uu.params.input_names), + ade::util::toRange(in_metas))) { + const auto &input_name = std::get<0>(it); + auto ii = inputs.at(input_name); + const auto & mm = std::get<1>(it); + non_const_prepm->emplace(input_name, configurePreProcInfo(ii, mm)); + } } // FIXME: It would be nice here to have an exact number of network's @@ -950,11 +979,13 @@ struct Infer: public cv::detail::KernelTag { for (const auto &out_name : uu.params.output_names) { // NOTE: our output_names vector follows the API order // of this operation's outputs - const IE::DataPtr& ie_out = uu.outputs.at(out_name); - const IE::SizeVector dims = ie_out->getTensorDesc().getDims(); + const auto& desc = + uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load + ? uu.net.getOutputsInfo().at(out_name)->getTensorDesc() + : uu.this_network.GetOutputsInfo().at(out_name)->getTensorDesc(); - cv::GMatDesc outm(toCV(ie_out->getPrecision()), - toCV(ie_out->getTensorDesc().getDims())); + cv::GMatDesc outm(toCV(desc.getPrecision()), + toCV(desc.getDims())); result.emplace_back(outm); } return result; @@ -973,10 +1004,7 @@ struct Infer: public cv::detail::KernelTag { // and redirect our data producers to this memory // (A memory dialog comes to the picture again) IE::Blob::Ptr this_blob = extractBlob(*ctx, i); - setBlob(req, - ctx->uu.params.kind, - ctx->uu.params.input_names[i], - this_blob); + setBlob(req, ctx->uu.params.input_names[i], this_blob, *ctx); } // FIXME: Should it be done by kernel ? // What about to do that in RequestPool ? @@ -1008,13 +1036,13 @@ struct InferROI: public cv::detail::KernelTag { GAPI_Assert(1u == uu.params.input_names.size()); GAPI_Assert(2u == in_metas.size()); + const auto &input_name = uu.params.input_names.at(0); + auto &&mm = in_metas.at(1u); // NB: Configuring input precision and network reshape must be done // only in the loadNetwork case. if (uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) { // 0th is ROI, 1st is input image - const auto &input_name = uu.params.input_names.at(0); - auto &&ii = uu.inputs.at(input_name); - auto &&mm = in_metas.at(1u); + auto ii = uu.net.getInputsInfo().at(input_name); configureInputInfo(ii, mm); if (uu.params.layer_names_to_reshape.find(input_name) != uu.params.layer_names_to_reshape.end()) { @@ -1028,6 +1056,13 @@ struct InferROI: public cv::detail::KernelTag { if (!input_reshape_table.empty()) { const_cast(&uu.net)->reshape(input_reshape_table); } + } else { + GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import); + auto inputs = uu.this_network.GetInputsInfo(); + // FIXME: This isn't the best place to collect PreProcMap. + auto* non_const_prepm = const_cast(&uu.preproc_map); + auto ii = inputs.at(input_name); + non_const_prepm->emplace(input_name, configurePreProcInfo(ii, mm)); } // FIXME: It would be nice here to have an exact number of network's @@ -1036,11 +1071,13 @@ struct InferROI: public cv::detail::KernelTag { for (const auto &out_name : uu.params.output_names) { // NOTE: our output_names vector follows the API order // of this operation's outputs - const IE::DataPtr& ie_out = uu.outputs.at(out_name); - const IE::SizeVector dims = ie_out->getTensorDesc().getDims(); + const auto& desc = + uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load + ? uu.net.getOutputsInfo().at(out_name)->getTensorDesc() + : uu.this_network.GetOutputsInfo().at(out_name)->getTensorDesc(); - cv::GMatDesc outm(toCV(ie_out->getPrecision()), - toCV(ie_out->getTensorDesc().getDims())); + cv::GMatDesc outm(toCV(desc.getPrecision()), + toCV(desc.getDims())); result.emplace_back(outm); } return result; @@ -1057,10 +1094,9 @@ struct InferROI: public cv::detail::KernelTag { IE::Blob::Ptr this_blob = extractBlob(*ctx, 1); setBlob(req, - ctx->uu.params.kind, *(ctx->uu.params.input_names.begin()), - IE::make_shared_blob(this_blob, - toIE(this_roi))); + IE::make_shared_blob(this_blob, toIE(this_roi)), + *ctx); // FIXME: Should it be done by kernel ? // What about to do that in RequestPool ? req.StartAsync(); @@ -1099,8 +1135,9 @@ struct InferList: public cv::detail::KernelTag { // only in the loadNetwork case. if (uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) { std::size_t idx = 1u; + auto inputs = uu.net.getInputsInfo(); for (auto &&input_name : uu.params.input_names) { - auto &&ii = uu.inputs.at(input_name); + auto ii = inputs.at(input_name); const auto & mm = in_metas[idx++]; configureInputInfo(ii, mm); if (uu.params.layer_names_to_reshape.find(input_name) != @@ -1116,6 +1153,16 @@ struct InferList: public cv::detail::KernelTag { if (!input_reshape_table.empty()) { const_cast(&uu.net)->reshape(input_reshape_table); } + } else { + GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import); + std::size_t idx = 1u; + auto inputs = uu.this_network.GetInputsInfo(); + auto* non_const_prepm = const_cast(&uu.preproc_map); + for (auto &&input_name : uu.params.input_names) { + auto ii = inputs.at(input_name); + const auto & mm = in_metas[idx++]; + non_const_prepm->emplace(input_name, configurePreProcInfo(ii, mm)); + } } // roi-list version is much easier at the moment. @@ -1144,8 +1191,12 @@ struct InferList: public cv::detail::KernelTag { std::vector> cached_dims(ctx->uu.params.num_out); for (auto i : ade::util::iota(ctx->uu.params.num_out)) { - const IE::DataPtr& ie_out = ctx->uu.outputs.at(ctx->uu.params.output_names[i]); - cached_dims[i] = toCV(ie_out->getTensorDesc().getDims()); + const auto& out_name = ctx->uu.params.output_names[i]; + const auto& desc = + ctx->uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load + ? ctx->uu.net.getOutputsInfo().at(out_name)->getTensorDesc() + : ctx->uu.this_network.GetOutputsInfo().at(out_name)->getTensorDesc(); + cached_dims[i] = toCV(desc.getDims()); // FIXME: Isn't this should be done automatically // by some resetInternalData(), etc? (Probably at the GExecutor level) auto& out_vec = ctx->outVecR(i); @@ -1161,10 +1212,7 @@ struct InferList: public cv::detail::KernelTag { cv::gimpl::ie::RequestPool::Task { [ctx, rc, this_blob](InferenceEngine::InferRequest &req) { IE::Blob::Ptr roi_blob = IE::make_shared_blob(this_blob, toIE(rc)); - setBlob(req, - ctx->uu.params.kind, - ctx->uu.params.input_names[0u], - roi_blob); + setBlob(req, ctx->uu.params.input_names[0u], roi_blob, *ctx); req.StartAsync(); }, std::bind(callback, std::placeholders::_1, pos) @@ -1232,7 +1280,6 @@ struct InferList2: public cv::detail::KernelTag { std::size_t idx = 1u; for (auto &&input_name : uu.params.input_names) { - auto &ii = uu.inputs.at(input_name); const auto &mm = in_metas[idx]; GAPI_Assert(util::holds_alternative(mm) && "Non-array inputs are not supported"); @@ -1242,6 +1289,7 @@ struct InferList2: public cv::detail::KernelTag { // only in the loadNetwork case. if (uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load) { // This is a cv::Rect -- configure the IE preprocessing + auto ii = uu.net.getInputsInfo().at(input_name); configureInputInfo(ii, mm_0); if (uu.params.layer_names_to_reshape.find(input_name) != uu.params.layer_names_to_reshape.end()) { @@ -1255,6 +1303,12 @@ struct InferList2: public cv::detail::KernelTag { if (!input_reshape_table.empty()) { const_cast(&uu.net)->reshape(input_reshape_table); } + } else { + GAPI_Assert(uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Import); + auto inputs = uu.this_network.GetInputsInfo(); + auto* non_const_prepm = const_cast(&uu.preproc_map); + auto ii = inputs.at(input_name); + non_const_prepm->emplace(input_name, configurePreProcInfo(ii, mm_0)); } } else { // This is a cv::GMat (equals to: cv::Mat) @@ -1290,8 +1344,12 @@ struct InferList2: public cv::detail::KernelTag { // FIXME: This could be done ONCE at graph compile stage! std::vector< std::vector > cached_dims(ctx->uu.params.num_out); for (auto i : ade::util::iota(ctx->uu.params.num_out)) { - const IE::DataPtr& ie_out = ctx->uu.outputs.at(ctx->uu.params.output_names[i]); - cached_dims[i] = toCV(ie_out->getTensorDesc().getDims()); + const auto& out_name = ctx->uu.params.output_names[i]; + const auto& desc = + ctx->uu.params.kind == cv::gapi::ie::detail::ParamDesc::Kind::Load + ? ctx->uu.net.getOutputsInfo().at(out_name)->getTensorDesc() + : ctx->uu.this_network.GetOutputsInfo().at(out_name)->getTensorDesc(); + cached_dims[i] = toCV(desc.getDims()); // FIXME: Isn't this should be done automatically // by some resetInternalData(), etc? (Probably at the GExecutor level) auto& out_vec = ctx->outVecR(i); @@ -1319,10 +1377,7 @@ struct InferList2: public cv::detail::KernelTag { GAPI_Assert(false && "Only Rect and Mat types are supported for infer list 2!"); } - setBlob(req, - ctx->uu.params.kind, - ctx->uu.params.input_names[in_idx], - this_blob); + setBlob(req, ctx->uu.params.input_names[in_idx], this_blob, *ctx); } req.StartAsync(); }, diff --git a/modules/gapi/src/backends/ie/giebackend/giewrapper.cpp b/modules/gapi/src/backends/ie/giebackend/giewrapper.cpp index 1f9721dbf4..a185e7b8ce 100644 --- a/modules/gapi/src/backends/ie/giebackend/giewrapper.cpp +++ b/modules/gapi/src/backends/ie/giebackend/giewrapper.cpp @@ -18,6 +18,8 @@ #include #include +#include + namespace IE = InferenceEngine; namespace giewrap = cv::gimpl::ie::wrap; using GIEParam = cv::gapi::ie::detail::ParamDesc; @@ -93,11 +95,38 @@ IE::InferencePlugin giewrap::getPlugin(const GIEParam& params) { return plugin; } #else // >= 2019.R2 -IE::Core giewrap::getCore() { + +// NB: Some of IE plugins fail during IE::Core destroying in specific cases. +// Solution is allocate IE::Core in heap and doesn't destroy it, which cause +// leak, but fixes tests on CI. This behaviour is configurable by using +// OPENCV_GAPI_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND=0 +static IE::Core create_IE_Core_pointer() { + // NB: 'delete' is never called + static IE::Core* core = new IE::Core(); + return *core; +} + +static IE::Core create_IE_Core_instance() { static IE::Core core; return core; } +IE::Core giewrap::getCore() { + // NB: to make happy memory leak tools use: + // - OPENCV_GAPI_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND=0 + static bool param_GAPI_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND = + utils::getConfigurationParameterBool( + "OPENCV_GAPI_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND", +#if defined(_WIN32) || defined(__APPLE__) + true +#else + false +#endif + ); + return param_GAPI_INFERENCE_ENGINE_CORE_LIFETIME_WORKAROUND + ? create_IE_Core_pointer() : create_IE_Core_instance(); +} + IE::Core giewrap::getPlugin(const GIEParam& params) { auto plugin = giewrap::getCore(); if (params.device_id == "CPU" || params.device_id == "FPGA") diff --git a/modules/gapi/src/backends/ie/giebackend/giewrapper.hpp b/modules/gapi/src/backends/ie/giebackend/giewrapper.hpp index 2e4bac1270..5a8afeb34e 100644 --- a/modules/gapi/src/backends/ie/giebackend/giewrapper.hpp +++ b/modules/gapi/src/backends/ie/giebackend/giewrapper.hpp @@ -34,13 +34,12 @@ using Plugin = IE::InferencePlugin; GAPI_EXPORTS IE::InferencePlugin getPlugin(const GIEParam& params); GAPI_EXPORTS inline IE::ExecutableNetwork loadNetwork( IE::InferencePlugin& plugin, const IE::CNNNetwork& net, - const GIEParam&) { - return plugin.LoadNetwork(net, {}); // FIXME: 2nd parameter to be - // configurable via the API + const GIEParam& params) { + return plugin.LoadNetwork(net, params.config); } GAPI_EXPORTS inline IE::ExecutableNetwork importNetwork( IE::CNNNetwork& plugin, - const GIEParam& param) { - return plugin.ImportNetwork(param.model_path, param.device_id, {}); + const GIEParam& params) { + return plugin.ImportNetwork(param.model_path, param.device_id, params.config); } #else // >= 2019.R2 using Plugin = IE::Core; @@ -51,9 +50,9 @@ GAPI_EXPORTS inline IE::ExecutableNetwork loadNetwork( IE::Core& core const GIEParam& params, IE::RemoteContext::Ptr rctx = nullptr) { if (rctx != nullptr) { - return core.LoadNetwork(net, rctx); + return core.LoadNetwork(net, rctx, params.config); } else { - return core.LoadNetwork(net, params.device_id); + return core.LoadNetwork(net, params.device_id, params.config); } } GAPI_EXPORTS inline IE::ExecutableNetwork importNetwork( IE::Core& core, @@ -67,9 +66,9 @@ GAPI_EXPORTS inline IE::ExecutableNetwork importNetwork( IE::Core& core, throw std::runtime_error("Could not open file"); } std::istream graphBlob(&blobFile); - return core.ImportNetwork(graphBlob, rctx); + return core.ImportNetwork(graphBlob, rctx, params.config); } else { - return core.ImportNetwork(params.model_path, params.device_id, {}); + return core.ImportNetwork(params.model_path, params.device_id, params.config); } } #endif // INF_ENGINE_RELEASE < 2019020000 diff --git a/modules/gapi/test/infer/gapi_infer_ie_test.cpp b/modules/gapi/test/infer/gapi_infer_ie_test.cpp index 49cf47048e..80d27c0298 100644 --- a/modules/gapi/test/infer/gapi_infer_ie_test.cpp +++ b/modules/gapi/test/infer/gapi_infer_ie_test.cpp @@ -139,6 +139,48 @@ void setNetParameters(IE::CNNNetwork& net, bool is_nv12 = false) { } } +bool checkDeviceIsAvailable(const std::string& device) { + const static auto available_devices = [&](){ + auto devices = cv::gimpl::ie::wrap::getCore().GetAvailableDevices(); + return std::unordered_set{devices.begin(), devices.end()}; + }(); + return available_devices.find(device) != available_devices.end(); +} + +void skipIfDeviceNotAvailable(const std::string& device) { + if (!checkDeviceIsAvailable(device)) { + throw SkipTestException("Device: " + device + " isn't available!"); + } +} + +void compileBlob(const cv::gapi::ie::detail::ParamDesc& params, + const std::string& output, + const IE::Precision& ip) { + auto plugin = cv::gimpl::ie::wrap::getPlugin(params); + auto net = cv::gimpl::ie::wrap::readNetwork(params); + for (auto&& ii : net.getInputsInfo()) { + ii.second->setPrecision(ip); + } + auto this_network = cv::gimpl::ie::wrap::loadNetwork(plugin, net, params); + std::ofstream out_file{output, std::ios::out | std::ios::binary}; + GAPI_Assert(out_file.is_open()); + this_network.Export(out_file); +} + +std::string compileAgeGenderBlob(const std::string& device) { + const static std::string blob_path = [&](){ + cv::gapi::ie::detail::ParamDesc params; + const std::string model_name = "age-gender-recognition-retail-0013"; + const std::string output = model_name + ".blob"; + params.model_path = findDataFile(SUBDIR + model_name + ".xml"); + params.weights_path = findDataFile(SUBDIR + model_name + ".bin"); + params.device_id = device; + compileBlob(params, output, IE::Precision::U8); + return output; + }(); + return blob_path; +} + } // anonymous namespace // TODO: Probably DNN/IE part can be further parametrized with a template @@ -471,10 +513,10 @@ struct ROIListNV12: public ::testing::Test { for (auto &&rc : m_roi_list) { const auto ie_rc = IE::ROI { 0u - , static_cast(rc.x) - , static_cast(rc.y) - , static_cast(rc.width) - , static_cast(rc.height) + , static_cast(rc.x) + , static_cast(rc.y) + , static_cast(rc.width) + , static_cast(rc.height) }; infer_request.SetBlob("data", IE::make_shared_blob(frame_blob, ie_rc)); infer_request.Infer(); @@ -534,11 +576,11 @@ struct SingleROI: public ::testing::Test { 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) + 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); @@ -596,11 +638,11 @@ struct SingleROINV12: public ::testing::Test { 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) + 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); @@ -2065,7 +2107,7 @@ struct Sync { class GMockMediaAdapter final: public cv::MediaFrame::IAdapter { public: - explicit GMockMediaAdapter(cv::Mat m, Sync& sync) + explicit GMockMediaAdapter(cv::Mat m, std::shared_ptr sync) : m_mat(m), m_sync(sync) { } @@ -2081,15 +2123,15 @@ public: ~GMockMediaAdapter() { { - std::lock_guard lk{m_sync.m}; - m_sync.counter--; + std::lock_guard lk{m_sync->m}; + m_sync->counter--; } - m_sync.cv.notify_one(); + m_sync->cv.notify_one(); } private: - cv::Mat m_mat; - Sync& m_sync; + cv::Mat m_mat; + std::shared_ptr m_sync; }; // NB: This source is needed to simulate real @@ -2099,15 +2141,16 @@ private: class GMockSource : public cv::gapi::wip::IStreamSource { public: explicit GMockSource(int limit) - : m_limit(limit), m_mat(cv::Size(1920, 1080), CV_8UC3) { + : m_limit(limit), m_mat(cv::Size(1920, 1080), CV_8UC3), + m_sync(new Sync{}) { cv::randu(m_mat, cv::Scalar::all(0), cv::Scalar::all(255)); } bool pull(cv::gapi::wip::Data& data) { - std::unique_lock lk(m_sync.m); - m_sync.counter++; + std::unique_lock lk(m_sync->m); + m_sync->counter++; // NB: Can't produce new frames until old ones are released. - m_sync.cv.wait(lk, [this]{return m_sync.counter <= m_limit;}); + m_sync->cv.wait(lk, [this]{return m_sync->counter <= m_limit;}); data = cv::MediaFrame::Create(m_mat, m_sync); return true; @@ -2118,9 +2161,9 @@ public: } private: - int m_limit; - cv::Mat m_mat; - Sync m_sync; + int m_limit; + cv::Mat m_mat; + std::shared_ptr m_sync; }; struct LimitedSourceInfer: public ::testing::Test { @@ -2239,6 +2282,582 @@ TEST(TestAgeGenderIE, InferWithBatch) normAssert(cv::gapi::ie::util::to_ocv(ie_gender), gapi_gender, "Test gender output"); } +TEST(ImportNetwork, Infer) +{ + const std::string device = "MYRIAD"; + skipIfDeviceNotAvailable(device); + + initDLDTDataPath(); + + cv::gapi::ie::detail::ParamDesc params; + params.model_path = compileAgeGenderBlob(device); + params.device_id = device; + + cv::Mat in_mat(320, 240, CV_8UC3); + cv::randu(in_mat, 0, 255); + cv::Mat gapi_age, gapi_gender; + + // Load & run IE network + IE::Blob::Ptr ie_age, ie_gender; + { + auto plugin = cv::gimpl::ie::wrap::getPlugin(params); + auto this_network = cv::gimpl::ie::wrap::importNetwork(plugin, params); + auto infer_request = this_network.CreateInferRequest(); + IE::PreProcessInfo info; + info.setResizeAlgorithm(IE::RESIZE_BILINEAR); + infer_request.SetBlob("data", cv::gapi::ie::util::to_ie(in_mat), info); + infer_request.Infer(); + ie_age = infer_request.GetBlob("age_conv3"); + ie_gender = infer_request.GetBlob("prob"); + } + + // Configure & run G-API + using AGInfo = std::tuple; + G_API_NET(AgeGender, , "test-age-gender"); + + cv::GMat in; + cv::GMat age, gender; + std::tie(age, gender) = cv::gapi::infer(in); + cv::GComputation comp(cv::GIn(in), cv::GOut(age, gender)); + + auto pp = cv::gapi::ie::Params { + params.model_path, params.device_id + }.cfgOutputLayers({ "age_conv3", "prob" }); + + comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender), + cv::compile_args(cv::gapi::networks(pp))); + + // Validate with IE itself (avoid DNN module dependency here) + normAssert(cv::gapi::ie::util::to_ocv(ie_age), gapi_age, "Test age output" ); + normAssert(cv::gapi::ie::util::to_ocv(ie_gender), gapi_gender, "Test gender output"); +} + +TEST(ImportNetwork, InferNV12) +{ + const std::string device = "MYRIAD"; + skipIfDeviceNotAvailable(device); + + initDLDTDataPath(); + + cv::gapi::ie::detail::ParamDesc params; + params.model_path= compileAgeGenderBlob(device); + params.device_id = device; + + cv::Size sz{320, 240}; + cv::Mat in_y_mat(sz, CV_8UC1); + cv::randu(in_y_mat, 0, 255); + cv::Mat in_uv_mat(sz / 2, CV_8UC2); + cv::randu(in_uv_mat, 0, 255); + + cv::Mat gapi_age, gapi_gender; + + // Load & run IE network + IE::Blob::Ptr ie_age, ie_gender; + { + auto plugin = cv::gimpl::ie::wrap::getPlugin(params); + auto this_network = cv::gimpl::ie::wrap::importNetwork(plugin, params); + auto infer_request = this_network.CreateInferRequest(); + IE::PreProcessInfo info; + info.setResizeAlgorithm(IE::RESIZE_BILINEAR); + info.setColorFormat(IE::ColorFormat::NV12); + infer_request.SetBlob("data", cv::gapi::ie::util::to_ie(in_y_mat, in_uv_mat), info); + infer_request.Infer(); + ie_age = infer_request.GetBlob("age_conv3"); + ie_gender = infer_request.GetBlob("prob"); + } + + // Configure & run G-API + using AGInfo = std::tuple; + G_API_NET(AgeGender, , "test-age-gender"); + + cv::GFrame in; + cv::GMat age, gender; + std::tie(age, gender) = cv::gapi::infer(in); + cv::GComputation comp(cv::GIn(in), cv::GOut(age, gender)); + + auto frame = MediaFrame::Create(in_y_mat, in_uv_mat); + + auto pp = cv::gapi::ie::Params { + params.model_path, params.device_id + }.cfgOutputLayers({ "age_conv3", "prob" }); + comp.apply(cv::gin(frame), cv::gout(gapi_age, gapi_gender), + cv::compile_args(cv::gapi::networks(pp))); + + // Validate with IE itself (avoid DNN module dependency here) + normAssert(cv::gapi::ie::util::to_ocv(ie_age), gapi_age, "Test age output" ); + normAssert(cv::gapi::ie::util::to_ocv(ie_gender), gapi_gender, "Test gender output"); +} + +TEST(ImportNetwork, InferROI) +{ + const std::string device = "MYRIAD"; + skipIfDeviceNotAvailable(device); + + initDLDTDataPath(); + + cv::gapi::ie::detail::ParamDesc params; + params.model_path = compileAgeGenderBlob(device); + params.device_id = device; + + cv::Mat in_mat(320, 240, CV_8UC3); + cv::randu(in_mat, 0, 255); + cv::Mat gapi_age, gapi_gender; + cv::Rect 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 this_network = cv::gimpl::ie::wrap::importNetwork(plugin, params); + auto infer_request = this_network.CreateInferRequest(); + const auto ie_rc = IE::ROI { + 0u + , static_cast(rect.x) + , static_cast(rect.y) + , static_cast(rect.width) + , static_cast(rect.height) + }; + IE::Blob::Ptr roi_blob = IE::make_shared_blob(cv::gapi::ie::util::to_ie(in_mat), ie_rc); + IE::PreProcessInfo info; + info.setResizeAlgorithm(IE::RESIZE_BILINEAR); + infer_request.SetBlob("data", roi_blob, info); + infer_request.Infer(); + ie_age = infer_request.GetBlob("age_conv3"); + ie_gender = infer_request.GetBlob("prob"); + } + + using AGInfo = std::tuple; + G_API_NET(AgeGender, , "test-age-gender"); + + cv::GMat in; + cv::GOpaque roi; + cv::GMat age, gender; + std::tie(age, gender) = cv::gapi::infer(roi, in); + cv::GComputation comp(cv::GIn(in, roi), cv::GOut(age, gender)); + + auto pp = cv::gapi::ie::Params { + params.model_path, params.device_id + }.cfgOutputLayers({ "age_conv3", "prob" }); + + comp.apply(cv::gin(in_mat, rect), cv::gout(gapi_age, gapi_gender), + cv::compile_args(cv::gapi::networks(pp))); + + // Validate with IE itself (avoid DNN module dependency here) + normAssert(cv::gapi::ie::util::to_ocv(ie_age), gapi_age, "Test age output" ); + normAssert(cv::gapi::ie::util::to_ocv(ie_gender), gapi_gender, "Test gender output"); +} + +TEST(ImportNetwork, InferROINV12) +{ + const std::string device = "MYRIAD"; + skipIfDeviceNotAvailable(device); + + initDLDTDataPath(); + + cv::gapi::ie::detail::ParamDesc params; + params.model_path = compileAgeGenderBlob(device); + params.device_id = device; + + cv::Size sz{320, 240}; + cv::Mat in_y_mat(sz, CV_8UC1); + cv::randu(in_y_mat, 0, 255); + cv::Mat in_uv_mat(sz / 2, CV_8UC2); + cv::randu(in_uv_mat, 0, 255); + cv::Rect rect(cv::Point{64, 60}, cv::Size{96, 96}); + + cv::Mat gapi_age, gapi_gender; + + // Load & run IE network + IE::Blob::Ptr ie_age, ie_gender; + { + auto plugin = cv::gimpl::ie::wrap::getPlugin(params); + auto this_network = cv::gimpl::ie::wrap::importNetwork(plugin, params); + auto infer_request = this_network.CreateInferRequest(); + const auto ie_rc = IE::ROI { + 0u + , static_cast(rect.x) + , static_cast(rect.y) + , static_cast(rect.width) + , static_cast(rect.height) + }; + IE::Blob::Ptr roi_blob = + IE::make_shared_blob(cv::gapi::ie::util::to_ie(in_y_mat, in_uv_mat), ie_rc); + IE::PreProcessInfo info; + info.setResizeAlgorithm(IE::RESIZE_BILINEAR); + info.setColorFormat(IE::ColorFormat::NV12); + infer_request.SetBlob("data", roi_blob, info); + infer_request.Infer(); + ie_age = infer_request.GetBlob("age_conv3"); + ie_gender = infer_request.GetBlob("prob"); + } + + using AGInfo = std::tuple; + G_API_NET(AgeGender, , "test-age-gender"); + + cv::GFrame in; + cv::GOpaque roi; + cv::GMat age, gender; + std::tie(age, gender) = cv::gapi::infer(roi, in); + cv::GComputation comp(cv::GIn(in, roi), cv::GOut(age, gender)); + + auto frame = MediaFrame::Create(in_y_mat, in_uv_mat); + + auto pp = cv::gapi::ie::Params { + params.model_path, params.device_id + }.cfgOutputLayers({ "age_conv3", "prob" }); + + comp.apply(cv::gin(frame, rect), cv::gout(gapi_age, gapi_gender), + cv::compile_args(cv::gapi::networks(pp))); + + // Validate with IE itself (avoid DNN module dependency here) + normAssert(cv::gapi::ie::util::to_ocv(ie_age), gapi_age, "Test age output" ); + normAssert(cv::gapi::ie::util::to_ocv(ie_gender), gapi_gender, "Test gender output"); +} + +TEST(ImportNetwork, InferList) +{ + const std::string device = "MYRIAD"; + skipIfDeviceNotAvailable(device); + + initDLDTDataPath(); + + cv::gapi::ie::detail::ParamDesc params; + params.model_path = compileAgeGenderBlob(device); + params.device_id = device; + + cv::Mat in_mat(320, 240, CV_8UC3); + cv::randu(in_mat, 0, 255); + std::vector roi_list = { + cv::Rect(cv::Point{64, 60}, cv::Size{ 96, 96}), + cv::Rect(cv::Point{50, 32}, cv::Size{128, 160}), + }; + std::vector out_ie_ages, out_ie_genders, out_gapi_ages, out_gapi_genders; + + // Load & run IE network + { + auto plugin = cv::gimpl::ie::wrap::getPlugin(params); + auto this_network = cv::gimpl::ie::wrap::importNetwork(plugin, params); + auto infer_request = this_network.CreateInferRequest(); + for (auto &&rc : roi_list) { + const auto ie_rc = IE::ROI { + 0u + , static_cast(rc.x) + , static_cast(rc.y) + , static_cast(rc.width) + , static_cast(rc.height) + }; + IE::Blob::Ptr roi_blob = + IE::make_shared_blob(cv::gapi::ie::util::to_ie(in_mat), ie_rc); + IE::PreProcessInfo info; + info.setResizeAlgorithm(IE::RESIZE_BILINEAR); + infer_request.SetBlob("data", roi_blob, info); + infer_request.Infer(); + using namespace cv::gapi::ie::util; + out_ie_ages.push_back(to_ocv(infer_request.GetBlob("age_conv3")).clone()); + out_ie_genders.push_back(to_ocv(infer_request.GetBlob("prob")).clone()); + } + } + + // Configure & run G-API + using AGInfo = std::tuple; + G_API_NET(AgeGender, , "test-age-gender"); + + cv::GArray rr; + cv::GMat in; + cv::GArray age, gender; + std::tie(age, gender) = cv::gapi::infer(rr, in); + cv::GComputation comp(cv::GIn(in, rr), cv::GOut(age, gender)); + + auto pp = cv::gapi::ie::Params { + params.model_path, params.device_id + }.cfgOutputLayers({ "age_conv3", "prob" }); + + comp.apply(cv::gin(in_mat, roi_list), cv::gout(out_gapi_ages, out_gapi_genders), + cv::compile_args(cv::gapi::networks(pp))); + + // Validate with IE itself (avoid DNN module dependency here) + GAPI_Assert(!out_gapi_ages.empty()); + ASSERT_EQ(out_gapi_genders.size(), out_gapi_ages.size()); + ASSERT_EQ(out_gapi_ages.size(), out_ie_ages.size()); + ASSERT_EQ(out_gapi_genders.size(), out_ie_genders.size()); + + const size_t size = out_gapi_ages.size(); + for (size_t i = 0; i < size; ++i) { + normAssert(out_ie_ages [i], out_gapi_ages [i], "Test age output"); + normAssert(out_ie_genders[i], out_gapi_genders[i], "Test gender output"); + } +} + +TEST(ImportNetwork, InferListNV12) +{ + const std::string device = "MYRIAD"; + skipIfDeviceNotAvailable(device); + + initDLDTDataPath(); + + cv::gapi::ie::detail::ParamDesc params; + params.model_path = compileAgeGenderBlob(device); + params.device_id = device; + + cv::Size sz{320, 240}; + cv::Mat in_y_mat(sz, CV_8UC1); + cv::randu(in_y_mat, 0, 255); + cv::Mat in_uv_mat(sz / 2, CV_8UC2); + cv::randu(in_uv_mat, 0, 255); + std::vector roi_list = { + cv::Rect(cv::Point{64, 60}, cv::Size{ 96, 96}), + cv::Rect(cv::Point{50, 32}, cv::Size{128, 160}), + }; + std::vector out_ie_ages, out_ie_genders, out_gapi_ages, out_gapi_genders; + + // Load & run IE network + { + auto plugin = cv::gimpl::ie::wrap::getPlugin(params); + auto this_network = cv::gimpl::ie::wrap::importNetwork(plugin, params); + auto infer_request = this_network.CreateInferRequest(); + for (auto &&rc : roi_list) { + const auto ie_rc = IE::ROI { + 0u + , static_cast(rc.x) + , static_cast(rc.y) + , static_cast(rc.width) + , static_cast(rc.height) + }; + IE::Blob::Ptr roi_blob = + IE::make_shared_blob(cv::gapi::ie::util::to_ie(in_y_mat, in_uv_mat), ie_rc); + IE::PreProcessInfo info; + info.setResizeAlgorithm(IE::RESIZE_BILINEAR); + info.setColorFormat(IE::ColorFormat::NV12); + infer_request.SetBlob("data", roi_blob, info); + infer_request.Infer(); + using namespace cv::gapi::ie::util; + out_ie_ages.push_back(to_ocv(infer_request.GetBlob("age_conv3")).clone()); + out_ie_genders.push_back(to_ocv(infer_request.GetBlob("prob")).clone()); + } + } + + // Configure & run G-API + using AGInfo = std::tuple; + G_API_NET(AgeGender, , "test-age-gender"); + + cv::GArray rr; + cv::GFrame in; + cv::GArray age, gender; + std::tie(age, gender) = cv::gapi::infer(rr, in); + cv::GComputation comp(cv::GIn(in, rr), cv::GOut(age, gender)); + + auto pp = cv::gapi::ie::Params { + params.model_path, params.device_id + }.cfgOutputLayers({ "age_conv3", "prob" }); + + auto frame = MediaFrame::Create(in_y_mat, in_uv_mat); + + comp.apply(cv::gin(frame, roi_list), cv::gout(out_gapi_ages, out_gapi_genders), + cv::compile_args(cv::gapi::networks(pp))); + + // Validate with IE itself (avoid DNN module dependency here) + GAPI_Assert(!out_gapi_ages.empty()); + ASSERT_EQ(out_gapi_genders.size(), out_gapi_ages.size()); + ASSERT_EQ(out_gapi_ages.size(), out_ie_ages.size()); + ASSERT_EQ(out_gapi_genders.size(), out_ie_genders.size()); + + const size_t size = out_gapi_ages.size(); + for (size_t i = 0; i < size; ++i) { + normAssert(out_ie_ages [i], out_gapi_ages [i], "Test age output"); + normAssert(out_ie_genders[i], out_gapi_genders[i], "Test gender output"); + } +} + +TEST(ImportNetwork, InferList2) +{ + const std::string device = "MYRIAD"; + skipIfDeviceNotAvailable(device); + + initDLDTDataPath(); + + cv::gapi::ie::detail::ParamDesc params; + params.model_path = compileAgeGenderBlob(device); + params.device_id = device; + + cv::Mat in_mat(320, 240, CV_8UC3); + cv::randu(in_mat, 0, 255); + std::vector roi_list = { + cv::Rect(cv::Point{64, 60}, cv::Size{ 96, 96}), + cv::Rect(cv::Point{50, 32}, cv::Size{128, 160}), + }; + std::vector out_ie_ages, out_ie_genders, out_gapi_ages, out_gapi_genders; + + // Load & run IE network + { + auto plugin = cv::gimpl::ie::wrap::getPlugin(params); + auto this_network = cv::gimpl::ie::wrap::importNetwork(plugin, params); + auto infer_request = this_network.CreateInferRequest(); + for (auto &&rc : roi_list) { + const auto ie_rc = IE::ROI { + 0u + , static_cast(rc.x) + , static_cast(rc.y) + , static_cast(rc.width) + , static_cast(rc.height) + }; + IE::Blob::Ptr roi_blob = + IE::make_shared_blob(cv::gapi::ie::util::to_ie(in_mat), ie_rc); + IE::PreProcessInfo info; + info.setResizeAlgorithm(IE::RESIZE_BILINEAR); + infer_request.SetBlob("data", roi_blob, info); + infer_request.Infer(); + using namespace cv::gapi::ie::util; + out_ie_ages.push_back(to_ocv(infer_request.GetBlob("age_conv3")).clone()); + out_ie_genders.push_back(to_ocv(infer_request.GetBlob("prob")).clone()); + } + } + + // Configure & run G-API + using AGInfo = std::tuple; + G_API_NET(AgeGender, , "test-age-gender"); + + cv::GArray rr; + cv::GMat in; + cv::GArray age, gender; + std::tie(age, gender) = cv::gapi::infer2(in, rr); + cv::GComputation comp(cv::GIn(in, rr), cv::GOut(age, gender)); + + auto pp = cv::gapi::ie::Params { + params.model_path, params.device_id + }.cfgOutputLayers({ "age_conv3", "prob" }); + + comp.apply(cv::gin(in_mat, roi_list), cv::gout(out_gapi_ages, out_gapi_genders), + cv::compile_args(cv::gapi::networks(pp))); + + // Validate with IE itself (avoid DNN module dependency here) + GAPI_Assert(!out_gapi_ages.empty()); + ASSERT_EQ(out_gapi_genders.size(), out_gapi_ages.size()); + ASSERT_EQ(out_gapi_ages.size(), out_ie_ages.size()); + ASSERT_EQ(out_gapi_genders.size(), out_ie_genders.size()); + + const size_t size = out_gapi_ages.size(); + for (size_t i = 0; i < size; ++i) { + normAssert(out_ie_ages [i], out_gapi_ages [i], "Test age output"); + normAssert(out_ie_genders[i], out_gapi_genders[i], "Test gender output"); + } +} + +TEST(ImportNetwork, InferList2NV12) +{ + const std::string device = "MYRIAD"; + skipIfDeviceNotAvailable(device); + + initDLDTDataPath(); + + cv::gapi::ie::detail::ParamDesc params; + params.model_path = compileAgeGenderBlob(device); + params.device_id = device; + + cv::Size sz{320, 240}; + cv::Mat in_y_mat(sz, CV_8UC1); + cv::randu(in_y_mat, 0, 255); + cv::Mat in_uv_mat(sz / 2, CV_8UC2); + cv::randu(in_uv_mat, 0, 255); + std::vector roi_list = { + cv::Rect(cv::Point{64, 60}, cv::Size{ 96, 96}), + cv::Rect(cv::Point{50, 32}, cv::Size{128, 160}), + }; + std::vector out_ie_ages, out_ie_genders, out_gapi_ages, out_gapi_genders; + + // Load & run IE network + { + auto plugin = cv::gimpl::ie::wrap::getPlugin(params); + auto this_network = cv::gimpl::ie::wrap::importNetwork(plugin, params); + auto infer_request = this_network.CreateInferRequest(); + for (auto &&rc : roi_list) { + const auto ie_rc = IE::ROI { + 0u + , static_cast(rc.x) + , static_cast(rc.y) + , static_cast(rc.width) + , static_cast(rc.height) + }; + IE::Blob::Ptr roi_blob = + IE::make_shared_blob(cv::gapi::ie::util::to_ie(in_y_mat, in_uv_mat), ie_rc); + IE::PreProcessInfo info; + info.setResizeAlgorithm(IE::RESIZE_BILINEAR); + info.setColorFormat(IE::ColorFormat::NV12); + infer_request.SetBlob("data", roi_blob, info); + infer_request.Infer(); + using namespace cv::gapi::ie::util; + out_ie_ages.push_back(to_ocv(infer_request.GetBlob("age_conv3")).clone()); + out_ie_genders.push_back(to_ocv(infer_request.GetBlob("prob")).clone()); + } + } + + // Configure & run G-API + using AGInfo = std::tuple; + G_API_NET(AgeGender, , "test-age-gender"); + + cv::GArray rr; + cv::GFrame in; + cv::GArray age, gender; + std::tie(age, gender) = cv::gapi::infer2(in, rr); + cv::GComputation comp(cv::GIn(in, rr), cv::GOut(age, gender)); + + auto pp = cv::gapi::ie::Params { + params.model_path, params.device_id + }.cfgOutputLayers({ "age_conv3", "prob" }); + + auto frame = MediaFrame::Create(in_y_mat, in_uv_mat); + + comp.apply(cv::gin(frame, roi_list), cv::gout(out_gapi_ages, out_gapi_genders), + cv::compile_args(cv::gapi::networks(pp))); + + // Validate with IE itself (avoid DNN module dependency here) + GAPI_Assert(!out_gapi_ages.empty()); + ASSERT_EQ(out_gapi_genders.size(), out_gapi_ages.size()); + ASSERT_EQ(out_gapi_ages.size(), out_ie_ages.size()); + ASSERT_EQ(out_gapi_genders.size(), out_ie_genders.size()); + + const size_t size = out_gapi_ages.size(); + for (size_t i = 0; i < size; ++i) { + normAssert(out_ie_ages [i], out_gapi_ages [i], "Test age output"); + normAssert(out_ie_genders[i], out_gapi_genders[i], "Test gender output"); + } +} + +TEST(TestAgeGender, ThrowBlobAndInputPrecisionMismatch) +{ + const std::string device = "MYRIAD"; + skipIfDeviceNotAvailable(device); + + initDLDTDataPath(); + + cv::gapi::ie::detail::ParamDesc params; + // NB: Precision for inputs is U8. + params.model_path = compileAgeGenderBlob(device); + params.device_id = device; + + // Configure & run G-API + using AGInfo = std::tuple; + G_API_NET(AgeGender, , "test-age-gender"); + + cv::GMat in, age, gender; + std::tie(age, gender) = cv::gapi::infer(in); + cv::GComputation comp(cv::GIn(in), cv::GOut(age, gender)); + + auto pp = cv::gapi::ie::Params { + params.model_path, params.device_id + }.cfgOutputLayers({ "age_conv3", "prob" }); + + cv::Mat in_mat(320, 240, CV_32FC3); + cv::randu(in_mat, 0, 1); + cv::Mat gapi_age, gapi_gender; + + // NB: Blob precision is U8, but user pass FP32 data, so exception will be thrown. + // Now exception comes directly from IE, but since G-API has information + // about data precision at the compile stage, consider the possibility of + // throwing exception from there. + EXPECT_ANY_THROW(comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender), + cv::compile_args(cv::gapi::networks(pp)))); +} + } // namespace opencv_test #endif // HAVE_INF_ENGINE