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
// 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
@ -137,7 +137,8 @@ public:
// This function is a kernel's execution entry point (does the processing work)
using RunF = std::function<void(GCPUContext &)>;
// 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(const RunF& runF, const SetupF& setupF = nullptr);
@ -284,21 +285,56 @@ struct OCVSetupHelper;
template<typename Impl, typename... 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>
static void setup_impl(const GMetaArgs &metaArgs, const GArgs &args, GArg &state,
detail::Seq<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
>(),
compileArgs)
, void())
{
// TODO: unique_ptr <-> shared_ptr conversion ?
// To check: Conversion is possible only if the state which should be passed to
// 'setup' user callback isn't required to have previous value
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);
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());
}
};
@ -435,8 +471,8 @@ public:
// 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.
#define GAPI_OCV_KERNEL_ST(Name, API, State) \
struct Name:public cv::GCPUStKernelImpl<Name, API, State> \
#define GAPI_OCV_KERNEL_ST(Name, API, State) \
struct Name: public cv::GCPUStKernelImpl<Name, API, State> \
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
// 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
@ -15,6 +15,7 @@
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/util/any.hpp>
#include <opencv2/gapi/util/optional.hpp>
#include <opencv2/gapi/own/exports.hpp>
#include <opencv2/gapi/own/assert.hpp>
@ -31,7 +32,7 @@ namespace detail
{};
struct TransformTag
{};
}
} // namespace detail
// 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)
@ -52,7 +53,8 @@ struct GCompileArg;
namespace detail {
template<typename T>
using is_compile_arg = std::is_same<GCompileArg, typename std::decay<T>::type>;
}
} // namespace detail
// CompileArg is an unified interface over backend-specific compilation
// information
// FIXME: Move to a separate file?
@ -121,14 +123,34 @@ private:
using GCompileArgs = std::vector<GCompileArg>;
/**
* Wraps a list of arguments (a parameter pack) into a vector of
* compilation arguments (cv::GCompileArg).
* @brief Wraps a list of arguments (a parameter pack) into a vector of
* compilation arguments (cv::GCompileArg).
*/
template<typename... Ts> GCompileArgs compile_args(Ts&&... 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
* 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
// 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

@ -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) 2018 Intel Corporation
// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GBACKEND_HPP
@ -87,14 +87,7 @@ struct GRuntimeArgs
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>();
return cv::gapi::getCompileArg<T>(args);
}
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
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
@ -57,10 +57,10 @@ namespace
}
virtual EPtr compile(const ade::Graph &graph,
const cv::GCompileArgs &,
const cv::GCompileArgs &compileArgs,
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 //////////////////////////////////////////////
cv::gimpl::GCPUExecutable::GCPUExecutable(const ade::Graph &g,
const cv::GCompileArgs &compileArgs,
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)
// into an execution script.
@ -166,7 +167,8 @@ void cv::gimpl::GCPUExecutable::setupKernelStates()
const GCPUKernel& kernel = gcm.metadata(kernelNode).get<CPUUnit>().k;
kernel.m_setupF(GModel::collectInputMeta(m_gm, kernelNode),
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
// 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
@ -33,6 +33,7 @@ class GCPUExecutable final: public GIslandExecutable
{
const ade::Graph &m_g;
GModel::ConstGraph m_gm;
const cv::GCompileArgs m_compileArgs;
struct OperationInfo
{
@ -42,22 +43,27 @@ class GCPUExecutable final: public GIslandExecutable
// Execution script, currently absolutely naive
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)
std::vector<ade::NodeHandle> m_dataNodes;
// Actual data of all resources in graph (both internal and external)
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;
GArg packArg(const GArg &arg);
void setupKernelStates();
public:
GCPUExecutable(const ade::Graph &graph,
const cv::GCompileArgs &compileArgs,
const std::vector<ade::NodeHandle> &nodes);
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
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.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) 2018 Intel Corporation
// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
@ -86,15 +86,15 @@ namespace
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())
cv::util::throw_error(std::logic_error("GFluidOutputRois feature supports only one-island graphs"));
auto rois = out_rois.value_or(cv::GFluidOutputRois());
auto graph_data = fluidExtractInputDataFromGraph(graph, nodes);
const auto parallel_out_rois = cv::gimpl::getCompileArg<cv::GFluidParallelOutputRois>(args);
const auto gpfor = cv::gimpl::getCompileArg<cv::GFluidParallelFor>(args);
const auto parallel_out_rois = cv::gapi::getCompileArg<cv::GFluidParallelOutputRois>(args);
const auto gpfor = cv::gapi::getCompileArg<cv::GFluidParallelFor>(args);
#if !defined(GAPI_STANDALONE)
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);
calcLatency(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);
}

@ -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) 2018 Intel Corporation
// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.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) 2018 Intel Corporation
// Copyright (C) 2018-2020 Intel Corporation
#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
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2019 Intel Corporation
// Copyright (C) 2019-2020 Intel Corporation
#ifdef HAVE_PLAIDML
@ -57,7 +57,7 @@ namespace
const std::vector<cv::gimpl::Data>& ins_data,
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)
{

@ -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) 2018 Intel Corporation
// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
@ -136,7 +136,7 @@ namespace {
const std::vector<ade::NodeHandle> &nodes) const override {
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;
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
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.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) 2018 Intel Corporation
// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GCOMPILED_PRIV_HPP

@ -61,7 +61,7 @@ namespace
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)
return withAuxKernels(has_use_only.value().pkg);
@ -75,20 +75,20 @@ namespace
cv::gapi::GKernelPackage();
#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{}));
return combine(ocv_pkg, user_pkg_with_aux);
}
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{});
}
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())
{
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;
}
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())
{
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
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018 Intel Corporation
// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.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) 2018 Intel Corporation
// Copyright (C) 2018-2020 Intel Corporation
#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
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2019 Intel Corporation
// Copyright (C) 2019-2020 Intel Corporation
#include "precomp.hpp"
@ -603,10 +603,14 @@ void collectorThread(std::vector<Q*> in_queues,
}
} // 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_island_graph(GModel::Graph(*m_orig_graph).metadata()
.get<IslandModel>().model)
, m_comp_args(comp_args)
, m_gim(*m_island_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
// 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
#define OPENCV_GAPI_GSTREAMING_EXECUTOR_HPP
@ -126,7 +126,8 @@ protected:
void wait_shutdown();
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();
void setSource(GRunArgs &&args);
void start();

@ -8,6 +8,33 @@
#include <opencv2/gapi/cpu/core.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
{
//TODO: test OT, Background Subtractor, Kalman with 3rd version of API
@ -56,8 +83,7 @@ namespace
GAPI_OCV_KERNEL_ST(GOCVIsStateUpToDate, GIsStateUpToDate, cv::Size)
{
static void setup(const cv::GMatDesc &in,
std::shared_ptr<cv::Size> &state)
static void setup(const cv::GMatDesc &in, std::shared_ptr<cv::Size> &state)
{
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; }
};
@ -85,6 +112,34 @@ namespace
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)
@ -126,7 +181,7 @@ TEST(StatefulKernel, StateIsAutoResetForNewStream)
initTestDataPath();
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));
const auto pkg = cv::gapi::kernels<GOCVIsStateUpToDate>();
@ -167,7 +222,123 @@ TEST(StatefulKernel, InvalidReallocatingKernel)
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
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
{
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")
{

@ -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