Merge pull request #17584 from AsyaPronina:gapi_state_init_params_via_compile_args

pull/17665/head
Alexander Alekhin 5 years ago
commit 6044395986
  1. 52
      modules/gapi/include/opencv2/gapi/cpu/gcpukernel.hpp
  2. 32
      modules/gapi/include/opencv2/gapi/gcommon.hpp
  3. 2
      modules/gapi/include/opencv2/gapi/gcompiled.hpp
  4. 11
      modules/gapi/src/backends/common/gbackend.hpp
  5. 12
      modules/gapi/src/backends/cpu/gcpubackend.cpp
  6. 20
      modules/gapi/src/backends/cpu/gcpubackend.hpp
  7. 2
      modules/gapi/src/backends/cpu/gcpukernel.cpp
  8. 10
      modules/gapi/src/backends/fluid/gfluidbackend.cpp
  9. 2
      modules/gapi/src/backends/ocl/goclbackend.cpp
  10. 2
      modules/gapi/src/backends/ocl/goclbackend.hpp
  11. 4
      modules/gapi/src/backends/plaidml/gplaidmlbackend.cpp
  12. 4
      modules/gapi/src/backends/render/grenderocvbackend.cpp
  13. 2
      modules/gapi/src/compiler/gcompiled.cpp
  14. 2
      modules/gapi/src/compiler/gcompiled_priv.hpp
  15. 11
      modules/gapi/src/compiler/gcompiler.cpp
  16. 2
      modules/gapi/src/executor/gexecutor.cpp
  17. 2
      modules/gapi/src/executor/gexecutor.hpp
  18. 8
      modules/gapi/src/executor/gstreamingexecutor.cpp
  19. 5
      modules/gapi/src/executor/gstreamingexecutor.hpp
  20. 181
      modules/gapi/test/cpu/gapi_ocv_stateful_kernel_tests.cpp
  21. 75
      modules/gapi/test/gapi_compile_args_tests.cpp

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2018-2019 Intel Corporation // Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GCPUKERNEL_HPP #ifndef OPENCV_GAPI_GCPUKERNEL_HPP
@ -137,7 +137,8 @@ public:
// This function is a kernel's execution entry point (does the processing work) // This function is a kernel's execution entry point (does the processing work)
using RunF = std::function<void(GCPUContext &)>; using RunF = std::function<void(GCPUContext &)>;
// This function is a stateful kernel's setup routine (configures state) // This function is a stateful kernel's setup routine (configures state)
using SetupF = std::function<void(const GMetaArgs &, const GArgs &, GArg &)>; using SetupF = std::function<void(const GMetaArgs &, const GArgs &,
GArg &, const GCompileArgs &)>;
GCPUKernel(); GCPUKernel();
GCPUKernel(const RunF& runF, const SetupF& setupF = nullptr); GCPUKernel(const RunF& runF, const SetupF& setupF = nullptr);
@ -284,21 +285,56 @@ struct OCVSetupHelper;
template<typename Impl, typename... Ins> template<typename Impl, typename... Ins>
struct OCVSetupHelper<Impl, std::tuple<Ins...>> struct OCVSetupHelper<Impl, std::tuple<Ins...>>
{ {
// Using 'auto' return type and 'decltype' specifier in both 'setup_impl' versions
// to check existence of required 'Impl::setup' functions.
// While 'decltype' specifier accepts expression we pass expression with 'comma-operator'
// where first operand of comma-operator is call attempt to desired 'Impl::setup' and
// the second operand is 'void()' expression.
//
// SFINAE for 'Impl::setup' which accepts compile arguments.
template<int... IIs> template<int... IIs>
static void setup_impl(const GMetaArgs &metaArgs, const GArgs &args, GArg &state, static auto setup_impl(const GMetaArgs &metaArgs, const GArgs &args,
detail::Seq<IIs...>) GArg &state, const GCompileArgs &compileArgs,
detail::Seq<IIs...>) ->
decltype(Impl::setup(detail::get_in_meta<Ins>(metaArgs, args, IIs)...,
std::declval<typename std::add_lvalue_reference<
std::shared_ptr<typename Impl::State>
>::type
>(),
compileArgs)
, void())
{ {
// TODO: unique_ptr <-> shared_ptr conversion ? // TODO: unique_ptr <-> shared_ptr conversion ?
// To check: Conversion is possible only if the state which should be passed to // To check: Conversion is possible only if the state which should be passed to
// 'setup' user callback isn't required to have previous value // 'setup' user callback isn't required to have previous value
std::shared_ptr<typename Impl::State> stPtr; std::shared_ptr<typename Impl::State> stPtr;
Impl::setup(detail::get_in_meta<Ins>(metaArgs, args, IIs)..., stPtr, compileArgs);
state = GArg(stPtr);
}
// SFINAE for 'Impl::setup' which doesn't accept compile arguments.
template<int... IIs>
static auto setup_impl(const GMetaArgs &metaArgs, const GArgs &args,
GArg &state, const GCompileArgs &/* compileArgs */,
detail::Seq<IIs...>) ->
decltype(Impl::setup(detail::get_in_meta<Ins>(metaArgs, args, IIs)...,
std::declval<typename std::add_lvalue_reference<
std::shared_ptr<typename Impl::State>
>::type
>()
)
, void())
{
// The same comment as in 'setup' above.
std::shared_ptr<typename Impl::State> stPtr;
Impl::setup(detail::get_in_meta<Ins>(metaArgs, args, IIs)..., stPtr); Impl::setup(detail::get_in_meta<Ins>(metaArgs, args, IIs)..., stPtr);
state = GArg(stPtr); state = GArg(stPtr);
} }
static void setup(const GMetaArgs &metaArgs, const GArgs &args, GArg& state) static void setup(const GMetaArgs &metaArgs, const GArgs &args,
GArg& state, const GCompileArgs &compileArgs)
{ {
setup_impl(metaArgs, args, state, setup_impl(metaArgs, args, state, compileArgs,
typename detail::MkSeq<sizeof...(Ins)>::type()); typename detail::MkSeq<sizeof...(Ins)>::type());
} }
}; };
@ -435,8 +471,8 @@ public:
// TODO: Reuse Anatoliy's logic for support of types with commas in macro. // TODO: Reuse Anatoliy's logic for support of types with commas in macro.
// Retrieve the common part from Anatoliy's logic to the separate place. // Retrieve the common part from Anatoliy's logic to the separate place.
#define GAPI_OCV_KERNEL_ST(Name, API, State) \ #define GAPI_OCV_KERNEL_ST(Name, API, State) \
struct Name:public cv::GCPUStKernelImpl<Name, API, State> \ struct Name: public cv::GCPUStKernelImpl<Name, API, State> \
class gapi::cpu::GOCVFunctor : public gapi::GFunctor class gapi::cpu::GOCVFunctor : public gapi::GFunctor

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2018 Intel Corporation // Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GCOMMON_HPP #ifndef OPENCV_GAPI_GCOMMON_HPP
@ -15,6 +15,7 @@
#include <opencv2/gapi/opencv_includes.hpp> #include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/util/any.hpp> #include <opencv2/gapi/util/any.hpp>
#include <opencv2/gapi/util/optional.hpp>
#include <opencv2/gapi/own/exports.hpp> #include <opencv2/gapi/own/exports.hpp>
#include <opencv2/gapi/own/assert.hpp> #include <opencv2/gapi/own/assert.hpp>
@ -31,7 +32,7 @@ namespace detail
{}; {};
struct TransformTag struct TransformTag
{}; {};
} } // namespace detail
// This definition is here because it is reused by both public(?) and internal // This definition is here because it is reused by both public(?) and internal
// modules. Keeping it here wouldn't expose public details (e.g., API-level) // modules. Keeping it here wouldn't expose public details (e.g., API-level)
@ -52,7 +53,8 @@ struct GCompileArg;
namespace detail { namespace detail {
template<typename T> template<typename T>
using is_compile_arg = std::is_same<GCompileArg, typename std::decay<T>::type>; using is_compile_arg = std::is_same<GCompileArg, typename std::decay<T>::type>;
} } // namespace detail
// CompileArg is an unified interface over backend-specific compilation // CompileArg is an unified interface over backend-specific compilation
// information // information
// FIXME: Move to a separate file? // FIXME: Move to a separate file?
@ -121,14 +123,34 @@ private:
using GCompileArgs = std::vector<GCompileArg>; using GCompileArgs = std::vector<GCompileArg>;
/** /**
* Wraps a list of arguments (a parameter pack) into a vector of * @brief Wraps a list of arguments (a parameter pack) into a vector of
* compilation arguments (cv::GCompileArg). * compilation arguments (cv::GCompileArg).
*/ */
template<typename... Ts> GCompileArgs compile_args(Ts&&... args) template<typename... Ts> GCompileArgs compile_args(Ts&&... args)
{ {
return GCompileArgs{ GCompileArg(args)... }; return GCompileArgs{ GCompileArg(args)... };
} }
/**
* @brief Retrieves particular compilation argument by its type from
* cv::GCompileArgs
*/
namespace gapi
{
template<typename T>
inline cv::util::optional<T> getCompileArg(const cv::GCompileArgs &args)
{
for (auto &compile_arg : args)
{
if (compile_arg.tag == cv::detail::CompileArgTag<T>::tag())
{
return cv::util::optional<T>(compile_arg.get<T>());
}
}
return cv::util::optional<T>();
}
} // namespace gapi
/** /**
* @brief Ask G-API to dump compiled graph in Graphviz format under * @brief Ask G-API to dump compiled graph in Graphviz format under
* the given file name. * the given file name.

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2018 Intel Corporation // Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GCOMPILED_HPP #ifndef OPENCV_GAPI_GCOMPILED_HPP

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2018 Intel Corporation // Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GBACKEND_HPP #ifndef OPENCV_GAPI_GBACKEND_HPP
@ -87,14 +87,7 @@ struct GRuntimeArgs
template<typename T> template<typename T>
inline cv::util::optional<T> getCompileArg(const cv::GCompileArgs &args) inline cv::util::optional<T> getCompileArg(const cv::GCompileArgs &args)
{ {
for (auto &compile_arg : args) return cv::gapi::getCompileArg<T>(args);
{
if (compile_arg.tag == cv::detail::CompileArgTag<T>::tag())
{
return cv::util::optional<T>(compile_arg.get<T>());
}
}
return cv::util::optional<T>();
} }
void createMat(const cv::GMatDesc& desc, cv::Mat& mat); void createMat(const cv::GMatDesc& desc, cv::Mat& mat);

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2018 Intel Corporation // Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp" #include "precomp.hpp"
@ -57,10 +57,10 @@ namespace
} }
virtual EPtr compile(const ade::Graph &graph, virtual EPtr compile(const ade::Graph &graph,
const cv::GCompileArgs &, const cv::GCompileArgs &compileArgs,
const std::vector<ade::NodeHandle> &nodes) const override const std::vector<ade::NodeHandle> &nodes) const override
{ {
return EPtr{new cv::gimpl::GCPUExecutable(graph, nodes)}; return EPtr{new cv::gimpl::GCPUExecutable(graph, compileArgs, nodes)};
} }
}; };
} }
@ -73,8 +73,9 @@ cv::gapi::GBackend cv::gapi::cpu::backend()
// GCPUExecutable implementation ////////////////////////////////////////////// // GCPUExecutable implementation //////////////////////////////////////////////
cv::gimpl::GCPUExecutable::GCPUExecutable(const ade::Graph &g, cv::gimpl::GCPUExecutable::GCPUExecutable(const ade::Graph &g,
const cv::GCompileArgs &compileArgs,
const std::vector<ade::NodeHandle> &nodes) const std::vector<ade::NodeHandle> &nodes)
: m_g(g), m_gm(m_g) : m_g(g), m_gm(m_g), m_compileArgs(compileArgs)
{ {
// Convert list of operations (which is topologically sorted already) // Convert list of operations (which is topologically sorted already)
// into an execution script. // into an execution script.
@ -166,7 +167,8 @@ void cv::gimpl::GCPUExecutable::setupKernelStates()
const GCPUKernel& kernel = gcm.metadata(kernelNode).get<CPUUnit>().k; const GCPUKernel& kernel = gcm.metadata(kernelNode).get<CPUUnit>().k;
kernel.m_setupF(GModel::collectInputMeta(m_gm, kernelNode), kernel.m_setupF(GModel::collectInputMeta(m_gm, kernelNode),
m_gm.metadata(kernelNode).get<Op>().args, m_gm.metadata(kernelNode).get<Op>().args,
kernelState); kernelState,
m_compileArgs);
} }
} }

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2018 Intel Corporation // Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GCPUBACKEND_HPP #ifndef OPENCV_GAPI_GCPUBACKEND_HPP
@ -33,6 +33,7 @@ class GCPUExecutable final: public GIslandExecutable
{ {
const ade::Graph &m_g; const ade::Graph &m_g;
GModel::ConstGraph m_gm; GModel::ConstGraph m_gm;
const cv::GCompileArgs m_compileArgs;
struct OperationInfo struct OperationInfo
{ {
@ -42,22 +43,27 @@ class GCPUExecutable final: public GIslandExecutable
// Execution script, currently absolutely naive // Execution script, currently absolutely naive
std::vector<OperationInfo> m_script; std::vector<OperationInfo> m_script;
// TODO: Check that it is thread-safe
// Map of stateful kernel nodes to their kernels' states
std::unordered_map<ade::NodeHandle, GArg,
ade::HandleHasher<ade::Node>> m_nodesToStates;
// List of all resources in graph (both internal and external) // List of all resources in graph (both internal and external)
std::vector<ade::NodeHandle> m_dataNodes; std::vector<ade::NodeHandle> m_dataNodes;
// Actual data of all resources in graph (both internal and external) // Actual data of all resources in graph (both internal and external)
Mag m_res; Mag m_res;
GArg packArg(const GArg &arg);
void setupKernelStates();
// TODO: Check that it is thread-safe
std::unordered_map<ade::NodeHandle, GArg,
ade::HandleHasher<ade::Node>> m_nodesToStates;
// Flag which identifies if new stream was started
bool m_newStreamStarted = false; bool m_newStreamStarted = false;
GArg packArg(const GArg &arg);
void setupKernelStates();
public: public:
GCPUExecutable(const ade::Graph &graph, GCPUExecutable(const ade::Graph &graph,
const cv::GCompileArgs &compileArgs,
const std::vector<ade::NodeHandle> &nodes); const std::vector<ade::NodeHandle> &nodes);
virtual inline bool canReshape() const override { return false; } virtual inline bool canReshape() const override { return false; }

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2018 Intel Corporation // Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp" #include "precomp.hpp"

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2018 Intel Corporation // Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp" #include "precomp.hpp"
@ -86,15 +86,15 @@ namespace
return gim.metadata(nh).get<NodeKind>().k == NodeKind::ISLAND; return gim.metadata(nh).get<NodeKind>().k == NodeKind::ISLAND;
}); });
const auto out_rois = cv::gimpl::getCompileArg<cv::GFluidOutputRois>(args); const auto out_rois = cv::gapi::getCompileArg<cv::GFluidOutputRois>(args);
if (num_islands > 1 && out_rois.has_value()) if (num_islands > 1 && out_rois.has_value())
cv::util::throw_error(std::logic_error("GFluidOutputRois feature supports only one-island graphs")); cv::util::throw_error(std::logic_error("GFluidOutputRois feature supports only one-island graphs"));
auto rois = out_rois.value_or(cv::GFluidOutputRois()); auto rois = out_rois.value_or(cv::GFluidOutputRois());
auto graph_data = fluidExtractInputDataFromGraph(graph, nodes); auto graph_data = fluidExtractInputDataFromGraph(graph, nodes);
const auto parallel_out_rois = cv::gimpl::getCompileArg<cv::GFluidParallelOutputRois>(args); const auto parallel_out_rois = cv::gapi::getCompileArg<cv::GFluidParallelOutputRois>(args);
const auto gpfor = cv::gimpl::getCompileArg<cv::GFluidParallelFor>(args); const auto gpfor = cv::gapi::getCompileArg<cv::GFluidParallelFor>(args);
#if !defined(GAPI_STANDALONE) #if !defined(GAPI_STANDALONE)
auto default_pfor = [](std::size_t count, std::function<void(std::size_t)> f){ auto default_pfor = [](std::size_t count, std::function<void(std::size_t)> f){
@ -1236,7 +1236,7 @@ void cv::gimpl::GFluidExecutable::reshape(ade::Graph &g, const GCompileArgs &arg
initLineConsumption(g); initLineConsumption(g);
calcLatency(g); calcLatency(g);
calcSkew(g); calcSkew(g);
const auto out_rois = cv::gimpl::getCompileArg<cv::GFluidOutputRois>(args).value_or(cv::GFluidOutputRois()); const auto out_rois = cv::gapi::getCompileArg<cv::GFluidOutputRois>(args).value_or(cv::GFluidOutputRois());
makeReshape(out_rois.rois); makeReshape(out_rois.rois);
} }

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2018 Intel Corporation // Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp" #include "precomp.hpp"

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2018 Intel Corporation // Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GOCLBACKEND_HPP #ifndef OPENCV_GAPI_GOCLBACKEND_HPP

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2019 Intel Corporation // Copyright (C) 2019-2020 Intel Corporation
#ifdef HAVE_PLAIDML #ifdef HAVE_PLAIDML
@ -57,7 +57,7 @@ namespace
const std::vector<cv::gimpl::Data>& ins_data, const std::vector<cv::gimpl::Data>& ins_data,
const std::vector<cv::gimpl::Data>& outs_data) const override const std::vector<cv::gimpl::Data>& outs_data) const override
{ {
auto has_config = cv::gimpl::getCompileArg<cv::gapi::plaidml::config>(args); auto has_config = cv::gapi::getCompileArg<cv::gapi::plaidml::config>(args);
if (!has_config) if (!has_config)
{ {

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2018 Intel Corporation // Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp" #include "precomp.hpp"
@ -136,7 +136,7 @@ namespace {
const std::vector<ade::NodeHandle> &nodes) const override { const std::vector<ade::NodeHandle> &nodes) const override {
using namespace cv::gapi::wip::draw; using namespace cv::gapi::wip::draw;
auto has_freetype_font = cv::gimpl::getCompileArg<freetype_font>(args); auto has_freetype_font = cv::gapi::getCompileArg<freetype_font>(args);
std::unique_ptr<FTTextRender> ftpr; std::unique_ptr<FTTextRender> ftpr;
if (has_freetype_font) if (has_freetype_font)
{ {

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2018 Intel Corporation // Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp" #include "precomp.hpp"

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2018 Intel Corporation // Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GCOMPILED_PRIV_HPP #ifndef OPENCV_GAPI_GCOMPILED_PRIV_HPP

@ -61,7 +61,7 @@ namespace
return combine(pkg, aux_pkg); return combine(pkg, aux_pkg);
}; };
auto has_use_only = cv::gimpl::getCompileArg<cv::gapi::use_only>(args); auto has_use_only = cv::gapi::getCompileArg<cv::gapi::use_only>(args);
if (has_use_only) if (has_use_only)
return withAuxKernels(has_use_only.value().pkg); return withAuxKernels(has_use_only.value().pkg);
@ -75,20 +75,20 @@ namespace
cv::gapi::GKernelPackage(); cv::gapi::GKernelPackage();
#endif // !defined(GAPI_STANDALONE) #endif // !defined(GAPI_STANDALONE)
auto user_pkg = cv::gimpl::getCompileArg<cv::gapi::GKernelPackage>(args); auto user_pkg = cv::gapi::getCompileArg<cv::gapi::GKernelPackage>(args);
auto user_pkg_with_aux = withAuxKernels(user_pkg.value_or(cv::gapi::GKernelPackage{})); auto user_pkg_with_aux = withAuxKernels(user_pkg.value_or(cv::gapi::GKernelPackage{}));
return combine(ocv_pkg, user_pkg_with_aux); return combine(ocv_pkg, user_pkg_with_aux);
} }
cv::gapi::GNetPackage getNetworkPackage(cv::GCompileArgs &args) cv::gapi::GNetPackage getNetworkPackage(cv::GCompileArgs &args)
{ {
return cv::gimpl::getCompileArg<cv::gapi::GNetPackage>(args) return cv::gapi::getCompileArg<cv::gapi::GNetPackage>(args)
.value_or(cv::gapi::GNetPackage{}); .value_or(cv::gapi::GNetPackage{});
} }
cv::util::optional<std::string> getGraphDumpDirectory(cv::GCompileArgs& args) cv::util::optional<std::string> getGraphDumpDirectory(cv::GCompileArgs& args)
{ {
auto dump_info = cv::gimpl::getCompileArg<cv::graph_dump_path>(args); auto dump_info = cv::gapi::getCompileArg<cv::graph_dump_path>(args);
if (!dump_info.has_value()) if (!dump_info.has_value())
{ {
const char* path = std::getenv("GRAPH_DUMP_PATH"); const char* path = std::getenv("GRAPH_DUMP_PATH");
@ -452,7 +452,8 @@ cv::GStreamingCompiled cv::gimpl::GCompiler::produceStreamingCompiled(GPtr &&pg)
outMetas = GModel::ConstGraph(*pg).metadata().get<OutputMeta>().outMeta; outMetas = GModel::ConstGraph(*pg).metadata().get<OutputMeta>().outMeta;
} }
std::unique_ptr<GStreamingExecutor> pE(new GStreamingExecutor(std::move(pg))); std::unique_ptr<GStreamingExecutor> pE(new GStreamingExecutor(std::move(pg),
m_args));
if (!m_metas.empty() && !outMetas.empty()) if (!m_metas.empty() && !outMetas.empty())
{ {
compiled.priv().setup(m_metas, outMetas, std::move(pE)); compiled.priv().setup(m_metas, outMetas, std::move(pE));

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2018 Intel Corporation // Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp" #include "precomp.hpp"

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2018 Intel Corporation // Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GEXECUTOR_HPP #ifndef OPENCV_GAPI_GEXECUTOR_HPP

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2019 Intel Corporation // Copyright (C) 2019-2020 Intel Corporation
#include "precomp.hpp" #include "precomp.hpp"
@ -603,10 +603,14 @@ void collectorThread(std::vector<Q*> in_queues,
} }
} // anonymous namespace } // anonymous namespace
cv::gimpl::GStreamingExecutor::GStreamingExecutor(std::unique_ptr<ade::Graph> &&g_model) // GStreamingExecutor expects compile arguments as input to have possibility to do
// proper graph reshape and islands recompilation
cv::gimpl::GStreamingExecutor::GStreamingExecutor(std::unique_ptr<ade::Graph> &&g_model,
const GCompileArgs &comp_args)
: m_orig_graph(std::move(g_model)) : m_orig_graph(std::move(g_model))
, m_island_graph(GModel::Graph(*m_orig_graph).metadata() , m_island_graph(GModel::Graph(*m_orig_graph).metadata()
.get<IslandModel>().model) .get<IslandModel>().model)
, m_comp_args(comp_args)
, m_gim(*m_island_graph) , m_gim(*m_island_graph)
{ {
GModel::Graph gm(*m_orig_graph); GModel::Graph gm(*m_orig_graph);

@ -2,7 +2,7 @@
// It is subject to the license terms in the LICENSE file found in the top-level directory // 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. // of this distribution and at http://opencv.org/license.html.
// //
// Copyright (C) 2019 Intel Corporation // Copyright (C) 2019-2020 Intel Corporation
#ifndef OPENCV_GAPI_GSTREAMING_EXECUTOR_HPP #ifndef OPENCV_GAPI_GSTREAMING_EXECUTOR_HPP
#define OPENCV_GAPI_GSTREAMING_EXECUTOR_HPP #define OPENCV_GAPI_GSTREAMING_EXECUTOR_HPP
@ -126,7 +126,8 @@ protected:
void wait_shutdown(); void wait_shutdown();
public: public:
explicit GStreamingExecutor(std::unique_ptr<ade::Graph> &&g_model); explicit GStreamingExecutor(std::unique_ptr<ade::Graph> &&g_model,
const cv::GCompileArgs &comp_args);
~GStreamingExecutor(); ~GStreamingExecutor();
void setSource(GRunArgs &&args); void setSource(GRunArgs &&args);
void start(); void start();

@ -8,6 +8,33 @@
#include <opencv2/gapi/cpu/core.hpp> #include <opencv2/gapi/cpu/core.hpp>
#include <opencv2/gapi/streaming/cap.hpp> #include <opencv2/gapi/streaming/cap.hpp>
#include <opencv2/core.hpp>
#include <opencv2/core/cvstd.hpp>
#include <opencv2/video.hpp>
namespace opencv_test
{
struct BackSubStateParams
{
std::string method;
};
}
namespace cv
{
namespace detail
{
template<> struct CompileArgTag<opencv_test::BackSubStateParams>
{
static const char* tag()
{
return "org.opencv.test..background_substractor_state_params";
}
};
}
}
namespace opencv_test namespace opencv_test
{ {
//TODO: test OT, Background Subtractor, Kalman with 3rd version of API //TODO: test OT, Background Subtractor, Kalman with 3rd version of API
@ -56,8 +83,7 @@ namespace
GAPI_OCV_KERNEL_ST(GOCVIsStateUpToDate, GIsStateUpToDate, cv::Size) GAPI_OCV_KERNEL_ST(GOCVIsStateUpToDate, GIsStateUpToDate, cv::Size)
{ {
static void setup(const cv::GMatDesc &in, static void setup(const cv::GMatDesc &in, std::shared_ptr<cv::Size> &state)
std::shared_ptr<cv::Size> &state)
{ {
state.reset(new cv::Size(in.size)); state.reset(new cv::Size(in.size));
} }
@ -68,7 +94,8 @@ namespace
} }
}; };
G_TYPED_KERNEL(GStInvalidResize, <GMat(GMat,Size,double,double,int)>, "org.opencv.test.st_invalid_resize") G_TYPED_KERNEL(GStInvalidResize, <GMat(GMat,Size,double,double,int)>,
"org.opencv.test.st_invalid_resize")
{ {
static GMatDesc outMeta(GMatDesc in, Size, double, double, int) { return in; } static GMatDesc outMeta(GMatDesc in, Size, double, double, int) { return in; }
}; };
@ -85,6 +112,34 @@ namespace
cv::resize(in, out, sz, fx, fy, interp); cv::resize(in, out, sz, fx, fy, interp);
} }
}; };
G_TYPED_KERNEL(GBackSub, <GMat(GMat)>, "org.opencv.test.background_substractor")
{
static GMatDesc outMeta(GMatDesc in) { return in.withType(CV_8U, 1); }
};
GAPI_OCV_KERNEL_ST(GOCVBackSub, GBackSub, cv::BackgroundSubtractor)
{
static void setup(const cv::GMatDesc &/* desc */,
std::shared_ptr<BackgroundSubtractor> &state,
const cv::GCompileArgs &compileArgs)
{
auto sbParams = cv::gapi::getCompileArg<BackSubStateParams>(compileArgs)
.value_or(BackSubStateParams { });
if (sbParams.method == "knn")
state = createBackgroundSubtractorKNN();
else if (sbParams.method == "mog2")
state = createBackgroundSubtractorMOG2();
GAPI_Assert(state);
}
static void run(const cv::Mat& in, cv::Mat &out, BackgroundSubtractor& state)
{
state.apply(in, out, -1);
}
};
}; };
TEST(StatefulKernel, StateIsMutableInRuntime) TEST(StatefulKernel, StateIsMutableInRuntime)
@ -126,7 +181,7 @@ TEST(StatefulKernel, StateIsAutoResetForNewStream)
initTestDataPath(); initTestDataPath();
cv::GMat in; cv::GMat in;
GOpaque<bool> out = GIsStateUpToDate::on(in); cv::GOpaque<bool> out = GIsStateUpToDate::on(in);
cv::GComputation c(cv::GIn(in), cv::GOut(out)); cv::GComputation c(cv::GIn(in), cv::GOut(out));
const auto pkg = cv::gapi::kernels<GOCVIsStateUpToDate>(); const auto pkg = cv::gapi::kernels<GOCVIsStateUpToDate>();
@ -167,7 +222,123 @@ TEST(StatefulKernel, InvalidReallocatingKernel)
cv::GComputation comp(cv::GIn(in), cv::GOut(out)); cv::GComputation comp(cv::GIn(in), cv::GOut(out));
EXPECT_THROW(comp.apply(in_mat, out_mat, cv::compile_args(pkg)), std::logic_error); EXPECT_THROW(comp.apply(in_mat, out_mat, cv::compile_args(pkg)), std::logic_error);
}
namespace
{
void compareBackSubResults(const cv::Mat &actual, const cv::Mat &expected,
const int diffPercent)
{
GAPI_Assert(actual.size() == expected.size());
int allowedNumDiffPixels = actual.size().area() * diffPercent / 100;
cv::Mat diff;
cv::absdiff(actual, expected, diff);
cv::Mat hist(256, 1, CV_32FC1, cv::Scalar(0));
const float range[] { 0, 256 };
const float *histRange { range };
calcHist(&diff, 1, 0, Mat(), hist, 1, &hist.rows, &histRange, true, false);
for (int i = 2; i < hist.rows; ++i)
{
hist.at<float>(i) += hist.at<float>(i - 1);
}
int numDiffPixels = static_cast<int>(hist.at<float>(255));
EXPECT_GT(allowedNumDiffPixels, numDiffPixels);
}
} // anonymous namespace
TEST(StatefulKernel, StateIsInitViaCompArgs)
{
cv::Mat frame(1080, 1920, CV_8UC3),
gapiForeground,
ocvForeground;
cv::randu(frame, cv::Scalar(0, 0, 0), cv::Scalar(255, 255, 255));
// G-API code
cv::GMat in;
cv::GMat out = GBackSub::on(in);
cv::GComputation c(cv::GIn(in), cv::GOut(out));
const auto pkg = cv::gapi::kernels<GOCVBackSub>();
auto gapiBackSub = c.compile(cv::descr_of(frame),
cv::compile_args(pkg, BackSubStateParams { "knn" }));
gapiBackSub(cv::gin(frame), cv::gout(gapiForeground));
// OpenCV code
auto pOcvBackSub = createBackgroundSubtractorKNN();
pOcvBackSub->apply(frame, ocvForeground);
// Comparison
// Allowing 1% difference of all pixels between G-API and OpenCV results
compareBackSubResults(gapiForeground, ocvForeground, 1);
// Additionally, test the case where state is resetted
gapiBackSub.prepareForNewStream();
gapiBackSub(cv::gin(frame), cv::gout(gapiForeground));
pOcvBackSub->apply(frame, ocvForeground);
compareBackSubResults(gapiForeground, ocvForeground, 1);
}
namespace
{
void testBackSubInStreaming(cv::GStreamingCompiled gapiBackSub, const int diffPercent)
{
cv::Mat frame,
gapiForeground,
ocvForeground;
gapiBackSub.start();
EXPECT_TRUE(gapiBackSub.running());
// OpenCV reference substractor
auto pOCVBackSub = createBackgroundSubtractorKNN();
// Comparison of G-API and OpenCV substractors
std::size_t frames = 0u;
while (gapiBackSub.pull(cv::gout(frame, gapiForeground))) {
pOCVBackSub->apply(frame, ocvForeground, -1);
compareBackSubResults(gapiForeground, ocvForeground, diffPercent);
frames++;
}
EXPECT_LT(0u, frames);
EXPECT_FALSE(gapiBackSub.running());
}
} // anonymous namespace
TEST(StatefulKernel, StateIsInitViaCompArgsInStreaming)
{
initTestDataPath();
// G-API graph declaration
cv::GMat in;
cv::GMat out = GBackSub::on(in);
// Preserving 'in' in output to have possibility to compare with OpenCV reference
cv::GComputation c(cv::GIn(in), cv::GOut(cv::gapi::copy(in), out));
// G-API compilation of graph for streaming mode
const auto pkg = cv::gapi::kernels<GOCVBackSub>();
auto gapiBackSub = c.compileStreaming(
cv::compile_args(pkg, BackSubStateParams { "knn" }));
// Testing G-API Background Substractor in streaming mode
gapiBackSub.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>
(findDataFile("cv/video/768x576.avi")));
// Allowing 1% difference of all pixels between G-API and reference OpenCV results
testBackSubInStreaming(gapiBackSub, 1);
// Additionally, test the case when the new stream happens
gapiBackSub.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>
(findDataFile("cv/video/1920x1080.avi")));
// Allowing 5% difference of all pixels between G-API and reference OpenCV results
testBackSubInStreaming(gapiBackSub, 5);
} }
//------------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------
@ -179,7 +350,7 @@ template<typename Tuple>
struct SetupStateTypedTest : public ::testing::Test struct SetupStateTypedTest : public ::testing::Test
{ {
using StateT = typename std::tuple_element<0, Tuple>::type; using StateT = typename std::tuple_element<0, Tuple>::type;
using SetupT = typename std::tuple_element<1, Tuple>::type; using SetupT = typename std::tuple_element<1, Tuple>::type;
G_TYPED_KERNEL(GReturnState, <cv::GOpaque<StateT>(GMat)>, "org.opencv.test.return_state") G_TYPED_KERNEL(GReturnState, <cv::GOpaque<StateT>(GMat)>, "org.opencv.test.return_state")
{ {

@ -0,0 +1,75 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2020 Intel Corporation
#include "test_precomp.hpp"
namespace opencv_test
{
struct CustomArg
{
int number;
};
}
namespace cv
{
namespace detail
{
template<> struct CompileArgTag<opencv_test::CustomArg>
{
static const char* tag() { return "org.opencv.test.custom_arg"; }
};
}
}
namespace opencv_test
{
namespace
{
G_TYPED_KERNEL(GTestOp, <GMat(GMat)>, "org.opencv.test.test_op")
{
static GMatDesc outMeta(GMatDesc in) { return in; }
};
GAPI_OCV_KERNEL(GOCVTestOp, GTestOp)
{
static void run(const cv::Mat &/* in */, cv::Mat &/* out */) { }
};
} // anonymous namespace
TEST(GetCompileArgTest, PredefinedArgs)
{
cv::gapi::GKernelPackage pkg = cv::gapi::kernels<GOCVTestOp>();
cv::GCompileArg arg0 { pkg },
arg1 { cv::gapi::use_only { pkg } },
arg2 { cv::graph_dump_path { "fake_path" } };
GCompileArgs compArgs { arg0, arg1, arg2 };
auto kernelPkgOpt = cv::gapi::getCompileArg<cv::gapi::GKernelPackage>(compArgs);
GAPI_Assert(kernelPkgOpt.has_value());
EXPECT_NO_THROW(kernelPkgOpt.value().lookup("org.opencv.test.test_op"));
auto hasUseOnlyOpt = cv::gapi::getCompileArg<cv::gapi::use_only>(compArgs);
GAPI_Assert(hasUseOnlyOpt.has_value());
EXPECT_NO_THROW(hasUseOnlyOpt.value().pkg.lookup("org.opencv.test.test_op"));
auto dumpInfoOpt = cv::gapi::getCompileArg<cv::graph_dump_path>(compArgs);
GAPI_Assert(dumpInfoOpt.has_value());
EXPECT_EQ("fake_path", dumpInfoOpt.value().m_dump_path);
}
TEST(GetCompileArg, CustomArgs)
{;
cv::GCompileArgs compArgs{ GCompileArg { CustomArg { 7 } } };
auto customArgOpt = cv::gapi::getCompileArg<CustomArg>(compArgs);
GAPI_Assert(customArgOpt.has_value());
EXPECT_EQ(7, customArgOpt.value().number);
}
} // namespace opencv_test
Loading…
Cancel
Save