Merge pull request #12608 from dmatveev:gapi

* G-API Initial code upload

* Update G-API code base to Sep-24-2018

* The majority of OpenCV buildbot problems was addressed

* Update G-API code base to 24-Sep-18 EOD

* G-API code base update 25-Sep-2018

* Linux warnings should be resolved
* Documentation build should become green
* Number of Windows warnings should be reduced

* Update G-API code base to 25-Sep-18 EOD

* ARMv7 build issue should be resolved
* ADE is bumped to latest version and should fix Clang builds for macOS/iOS
* Remaining Windows warnings should be resolved
* New Linux32 / ARMv7 warnings should be resolved

* G-API code base update 25-Sep-2018-EOD2

* Final Windows warnings should be resolved now

* G-API code base update 26-Sep-2018

* Fixed issues with precompiled headers in module and its tests
pull/12609/merge
Dmitry Matveev 6 years ago committed by Alexander Alekhin
parent 852f061b26
commit 29e88e50ff
  1. 94
      modules/gapi/CMakeLists.txt
  2. 36
      modules/gapi/cmake/DownloadADE.cmake
  3. 11
      modules/gapi/cmake/init.cmake
  4. 3
      modules/gapi/doc/intro.markdown
  5. 21
      modules/gapi/include/opencv2/gapi.hpp
  6. 1559
      modules/gapi/include/opencv2/gapi/core.hpp
  7. 27
      modules/gapi/include/opencv2/gapi/cpu/core.hpp
  8. 236
      modules/gapi/include/opencv2/gapi/cpu/gcpukernel.hpp
  9. 27
      modules/gapi/include/opencv2/gapi/cpu/imgproc.hpp
  10. 120
      modules/gapi/include/opencv2/gapi/fluid/gfluidbuffer.hpp
  11. 283
      modules/gapi/include/opencv2/gapi/fluid/gfluidkernel.hpp
  12. 98
      modules/gapi/include/opencv2/gapi/garg.hpp
  13. 239
      modules/gapi/include/opencv2/gapi/garray.hpp
  14. 63
      modules/gapi/include/opencv2/gapi/gcall.hpp
  15. 118
      modules/gapi/include/opencv2/gapi/gcommon.hpp
  16. 59
      modules/gapi/include/opencv2/gapi/gcompiled.hpp
  17. 123
      modules/gapi/include/opencv2/gapi/gcompoundkernel.hpp
  18. 135
      modules/gapi/include/opencv2/gapi/gcomputation.hpp
  19. 409
      modules/gapi/include/opencv2/gapi/gkernel.hpp
  20. 131
      modules/gapi/include/opencv2/gapi/gmat.hpp
  21. 66
      modules/gapi/include/opencv2/gapi/gmetaarg.hpp
  22. 96
      modules/gapi/include/opencv2/gapi/gproto.hpp
  23. 68
      modules/gapi/include/opencv2/gapi/gscalar.hpp
  24. 150
      modules/gapi/include/opencv2/gapi/gtype_traits.hpp
  25. 186
      modules/gapi/include/opencv2/gapi/gtyped.hpp
  26. 677
      modules/gapi/include/opencv2/gapi/imgproc.hpp
  27. 16
      modules/gapi/include/opencv2/gapi/opencv_includes.hpp
  28. 69
      modules/gapi/include/opencv2/gapi/operators.hpp
  29. 41
      modules/gapi/include/opencv2/gapi/own/assert.hpp
  30. 47
      modules/gapi/include/opencv2/gapi/own/convert.hpp
  31. 28
      modules/gapi/include/opencv2/gapi/own/exports.hpp
  32. 142
      modules/gapi/include/opencv2/gapi/own/mat.hpp
  33. 45
      modules/gapi/include/opencv2/gapi/own/scalar.hpp
  34. 137
      modules/gapi/include/opencv2/gapi/own/types.hpp
  35. 159
      modules/gapi/include/opencv2/gapi/util/any.hpp
  36. 21
      modules/gapi/include/opencv2/gapi/util/compiler_hints.hpp
  37. 178
      modules/gapi/include/opencv2/gapi/util/optional.hpp
  38. 36
      modules/gapi/include/opencv2/gapi/util/throw.hpp
  39. 92
      modules/gapi/include/opencv2/gapi/util/util.hpp
  40. 377
      modules/gapi/include/opencv2/gapi/util/variant.hpp
  41. 1782
      modules/gapi/perf/common/gapi_core_perf_tests.hpp
  42. 882
      modules/gapi/perf/common/gapi_imgproc_perf_tests.hpp
  43. 219
      modules/gapi/perf/cpu/gapi_core_perf_tests_cpu.cpp
  44. 119
      modules/gapi/perf/cpu/gapi_imgproc_perf_tests_cpu.cpp
  45. 46
      modules/gapi/perf/internal/gapi_compiler_perf_tests.cpp
  46. 11
      modules/gapi/perf/perf_main.cpp
  47. 21
      modules/gapi/perf/perf_precomp.hpp
  48. 1
      modules/gapi/src/api/README.md
  49. 43
      modules/gapi/src/api/gapi_priv.cpp
  50. 77
      modules/gapi/src/api/gapi_priv.hpp
  51. 44
      modules/gapi/src/api/garray.cpp
  52. 269
      modules/gapi/src/api/gbackend.cpp
  53. 53
      modules/gapi/src/api/gbackend_priv.hpp
  54. 64
      modules/gapi/src/api/gcall.cpp
  55. 37
      modules/gapi/src/api/gcall_priv.hpp
  56. 191
      modules/gapi/src/api/gcomputation.cpp
  57. 29
      modules/gapi/src/api/gcomputation_priv.hpp
  58. 141
      modules/gapi/src/api/gkernel.cpp
  59. 71
      modules/gapi/src/api/gmat.cpp
  60. 88
      modules/gapi/src/api/gnode.cpp
  61. 58
      modules/gapi/src/api/gnode.hpp
  62. 52
      modules/gapi/src/api/gnode_priv.hpp
  63. 152
      modules/gapi/src/api/gproto.cpp
  64. 35
      modules/gapi/src/api/gproto_priv.hpp
  65. 69
      modules/gapi/src/api/gscalar.cpp
  66. 347
      modules/gapi/src/api/kernels_core.cpp
  67. 142
      modules/gapi/src/api/kernels_imgproc.cpp
  68. 211
      modules/gapi/src/api/operators.cpp
  69. 2
      modules/gapi/src/backends/README.md
  70. 103
      modules/gapi/src/backends/common/gbackend.hpp
  71. 18
      modules/gapi/src/backends/common/gcompoundbackend.cpp
  72. 45
      modules/gapi/src/backends/common/gcompoundkernel.cpp
  73. 227
      modules/gapi/src/backends/cpu/gcpubackend.cpp
  74. 63
      modules/gapi/src/backends/cpu/gcpubackend.hpp
  75. 577
      modules/gapi/src/backends/cpu/gcpucore.cpp
  76. 24
      modules/gapi/src/backends/cpu/gcpucore.hpp
  77. 273
      modules/gapi/src/backends/cpu/gcpuimgproc.cpp
  78. 23
      modules/gapi/src/backends/cpu/gcpuimgproc.hpp
  79. 50
      modules/gapi/src/backends/cpu/gcpukernel.cpp
  80. 1185
      modules/gapi/src/backends/fluid/gfluidbackend.cpp
  81. 128
      modules/gapi/src/backends/fluid/gfluidbackend.hpp
  82. 746
      modules/gapi/src/backends/fluid/gfluidbuffer.cpp
  83. 298
      modules/gapi/src/backends/fluid/gfluidbuffer_priv.hpp
  84. 2121
      modules/gapi/src/backends/fluid/gfluidcore.cpp
  85. 19
      modules/gapi/src/backends/fluid/gfluidcore.hpp
  86. 1325
      modules/gapi/src/backends/fluid/gfluidimgproc.cpp
  87. 19
      modules/gapi/src/backends/fluid/gfluidimgproc.hpp
  88. 154
      modules/gapi/src/backends/fluid/gfluidutils.hpp
  89. 1
      modules/gapi/src/compiler/README.md
  90. 131
      modules/gapi/src/compiler/gcompiled.cpp
  91. 58
      modules/gapi/src/compiler/gcompiled_priv.hpp
  92. 273
      modules/gapi/src/compiler/gcompiler.cpp
  93. 51
      modules/gapi/src/compiler/gcompiler.hpp
  94. 287
      modules/gapi/src/compiler/gislandmodel.cpp
  95. 184
      modules/gapi/src/compiler/gislandmodel.hpp
  96. 245
      modules/gapi/src/compiler/gmodel.cpp
  97. 251
      modules/gapi/src/compiler/gmodel.hpp
  98. 303
      modules/gapi/src/compiler/gmodelbuilder.cpp
  99. 77
      modules/gapi/src/compiler/gmodelbuilder.hpp
  100. 50
      modules/gapi/src/compiler/gobjref.hpp
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,94 @@
# FIXME: Remove CXX11 check after complete switch to OpenCV 4 branch
# (CI, bundle, workloads, etc)
if (NOT HAVE_CXX11 OR NOT TARGET ade)
# can't build G-API because of the above reasons
ocv_module_disable(gapi)
return()
endif()
set(the_description "OpenCV G-API Core Module")
ocv_add_module(gapi opencv_imgproc)
file(GLOB gapi_ext_hdrs
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/*.hpp"
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/*.hpp"
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/*.h"
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/util/*.hpp"
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/cpu/*.hpp"
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/fluid/*.hpp"
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/own/*.hpp"
)
set(gapi_srcs
# Front-end part
src/api/gapi_priv.cpp
src/api/gmat.cpp
src/api/garray.cpp
src/api/gscalar.cpp
src/api/gkernel.cpp
src/api/gbackend.cpp
src/api/gproto.cpp
src/api/gnode.cpp
src/api/gcall.cpp
src/api/gcomputation.cpp
src/api/operators.cpp
src/api/kernels_core.cpp
src/api/kernels_imgproc.cpp
# Compiler part
src/compiler/gmodel.cpp
src/compiler/gmodelbuilder.cpp
src/compiler/gislandmodel.cpp
src/compiler/gcompiler.cpp
src/compiler/gcompiled.cpp
src/compiler/passes/helpers.cpp
src/compiler/passes/dump_dot.cpp
src/compiler/passes/islands.cpp
src/compiler/passes/meta.cpp
src/compiler/passes/kernels.cpp
src/compiler/passes/exec.cpp
# Executor
src/executor/gexecutor.cpp
# CPU Backend (currently built-in)
src/backends/cpu/gcpubackend.cpp
src/backends/cpu/gcpukernel.cpp
src/backends/cpu/gcpuimgproc.cpp
src/backends/cpu/gcpucore.cpp
# Fluid Backend (also built-in, FIXME:move away)
src/backends/fluid/gfluidbuffer.cpp
src/backends/fluid/gfluidbackend.cpp
src/backends/fluid/gfluidimgproc.cpp
src/backends/fluid/gfluidcore.cpp
# Compound
src/backends/common/gcompoundbackend.cpp
src/backends/common/gcompoundkernel.cpp
)
ocv_list_add_prefix(gapi_srcs "${CMAKE_CURRENT_LIST_DIR}/")
# For IDE users
ocv_source_group("Src" FILES ${gapi_srcs})
ocv_source_group("Include" FILES ${gapi_ext_hdrs})
ocv_set_module_sources(HEADERS ${gapi_ext_hdrs} SOURCES ${gapi_srcs})
ocv_module_include_directories("${CMAKE_CURRENT_LIST_DIR}/src")
# Note `ade` is not a module name but link dependency for ${the_module}
# (which is opencv_gapi)
ocv_create_module(ade)
ocv_add_accuracy_tests()
# FIXME: test binary is linked with ADE directly since ADE symbols
# are not exported from libopencv_gapi.so in any form - thus
# there're two copies of ADE code in memory when tests run (!)
# src/ is specified to include dirs for INTERNAL tests only.
if(TARGET opencv_test_gapi)
target_include_directories(opencv_test_gapi PRIVATE "${CMAKE_CURRENT_LIST_DIR}/src")
target_link_libraries(opencv_test_gapi PRIVATE ade)
endif()
ocv_add_perf_tests()

@ -0,0 +1,36 @@
if(ANDROID)
# FIXME: Android build will be enabled separately
return()
endif()
set(ade_src_dir "${OpenCV_BINARY_DIR}/3rdparty/ade")
set(ade_filename "v0.1.1c.zip")
set(ade_subdir "ade-0.1.1c")
set(ade_md5 "db7e6a260229ee562a1b2857df473af8")
ocv_download(FILENAME ${ade_filename}
HASH ${ade_md5}
URL
"${OPENCV_ADE_URL}"
"$ENV{OPENCV_ADE_URL}"
"https://github.com/opencv/ade/archive/"
DESTINATION_DIR ${ade_src_dir}
ID ADE
STATUS res
UNPACK RELATIVE_URL)
if (NOT res)
return()
endif()
set(ADE_root "${ade_src_dir}/${ade_subdir}/sources/ade")
file(GLOB_RECURSE ADE_sources "${ADE_root}/source/*.cpp")
file(GLOB_RECURSE ADE_include "${ADE_root}/include/ade/*.hpp")
add_library(ade STATIC ${ADE_include} ${ADE_sources})
target_include_directories(ade PUBLIC $<BUILD_INTERFACE:${ADE_root}/include>)
set_target_properties(ade PROPERTIES POSITION_INDEPENDENT_CODE True)
if(NOT BUILD_SHARED_LIBS)
ocv_install_target(ade EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev)
endif()
ocv_install_3rdparty_licenses(ade "${ade_src_dir}/${ade_subdir}/LICENSE")

@ -0,0 +1,11 @@
if (ade_DIR)
# if ade_DIR is set, use ADE-supplied CMake script
# to set up variables to the prebuilt ADE
find_package(ade 0.1.0)
endif()
if(NOT TARGET ade)
# if ade_DIR is not set, try to use automatically
# downloaded one (if there any)
include("${CMAKE_CURRENT_LIST_DIR}/DownloadADE.cmake")
endif()

@ -0,0 +1,3 @@
# Graph API {#gapi}
Introduction to G-API (WIP).

@ -0,0 +1,21 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_HPP
#define OPENCV_GAPI_HPP
#include <memory>
#include "opencv2/gapi/gmat.hpp"
#include "opencv2/gapi/garray.hpp"
#include "opencv2/gapi/gcomputation.hpp"
#include "opencv2/gapi/gcompiled.hpp"
#include "opencv2/gapi/gtyped.hpp"
#include "opencv2/gapi/gkernel.hpp"
#include "opencv2/gapi/operators.hpp"
#endif // OPENCV_GAPI_HPP

File diff suppressed because it is too large Load Diff

@ -0,0 +1,27 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_CPU_CORE_API_HPP
#define OPENCV_GAPI_CPU_CORE_API_HPP
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS
namespace cv {
namespace gapi {
namespace core {
namespace cpu {
GAPI_EXPORTS GKernelPackage kernels();
} // namespace cpu
} // namespace core
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_CPU_CORE_API_HPP

@ -0,0 +1,236 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GCPUKERNEL_HPP
#define OPENCV_GAPI_GCPUKERNEL_HPP
#include <vector>
#include <functional>
#include <map>
#include <unordered_map>
#include <opencv2/core/mat.hpp>
#include <opencv2/gapi/gcommon.hpp>
#include <opencv2/gapi/gkernel.hpp>
#include <opencv2/gapi/garg.hpp>
#include <opencv2/gapi/own/convert.hpp> //to_ocv
#include <opencv2/gapi/util/compiler_hints.hpp> //suppress_unused_warning
// FIXME: namespace scheme for backends?
namespace cv {
namespace gimpl
{
// Forward-declare an internal class
class GCPUExecutable;
} // namespace gimpl
namespace gapi
{
namespace cpu
{
GAPI_EXPORTS cv::gapi::GBackend backend();
} // namespace cpu
} // namespace gapi
// Represents arguments which are passed to a wrapped CPU function
// FIXME: put into detail?
class GAPI_EXPORTS GCPUContext
{
public:
// Generic accessor API
template<typename T>
const T& inArg(int input) { return m_args.at(input).get<T>(); }
// Syntax sugar
const cv::gapi::own::Mat& inMat(int input);
cv::gapi::own::Mat& outMatR(int output); // FIXME: Avoid cv::gapi::own::Mat m = ctx.outMatR()
const cv::gapi::own::Scalar& inVal(int input);
cv::gapi::own::Scalar& outValR(int output); // FIXME: Avoid cv::gapi::own::Scalar s = ctx.outValR()
template<typename T> std::vector<T>& outVecR(int output) // FIXME: the same issue
{
return outVecRef(output).wref<T>();
}
protected:
detail::VectorRef& outVecRef(int output);
std::vector<GArg> m_args;
//FIXME: avoid conversion of arguments from internal representaion to OpenCV one on each call
//to OCV kernel. (This can be achieved by a two single time conversions in GCPUExecutable::run,
//once on enter for input and output arguments, and once before return for output arguments only
std::unordered_map<std::size_t, GRunArgP> m_results;
friend class gimpl::GCPUExecutable;
};
class GAPI_EXPORTS GCPUKernel
{
public:
// This function is kernel's execution entry point (does the processing work)
using F = std::function<void(GCPUContext &)>;
GCPUKernel();
explicit GCPUKernel(const F& f);
void apply(GCPUContext &ctx);
protected:
F m_f;
};
// FIXME: This is an ugly ad-hoc imlpementation. TODO: refactor
namespace detail
{
template<class T> struct get_in;
template<> struct get_in<cv::GMat>
{
static cv::Mat get(GCPUContext &ctx, int idx) { return to_ocv(ctx.inMat(idx)); }
};
template<> struct get_in<cv::GScalar>
{
static cv::Scalar get(GCPUContext &ctx, int idx) { return to_ocv(ctx.inVal(idx)); }
};
template<typename U> struct get_in<cv::GArray<U> >
{
static const std::vector<U>& get(GCPUContext &ctx, int idx) { return ctx.inArg<VectorRef>(idx).rref<U>(); }
};
template<class T> struct get_in
{
static T get(GCPUContext &ctx, int idx) { return ctx.inArg<T>(idx); }
};
struct tracked_cv_mat{
tracked_cv_mat(cv::gapi::own::Mat& m) : r{to_ocv(m)}, original_data{m.data} {}
cv::Mat r;
uchar* original_data;
operator cv::Mat& (){ return r;}
void validate() const{
if (r.data != original_data)
{
util::throw_error
(std::logic_error
("OpenCV kernel output parameter was reallocated. \n"
"Incorrect meta data was provided ?"));
}
}
};
struct scalar_wrapper
{
scalar_wrapper(cv::gapi::own::Scalar& s) : m_s{cv::gapi::own::to_ocv(s)}, m_org_s(s) {};
operator cv::Scalar& () { return m_s; }
void writeBack() const { m_org_s = to_own(m_s); }
cv::Scalar m_s;
cv::gapi::own::Scalar& m_org_s;
};
template<typename... Outputs>
void postprocess(Outputs&... outs)
{
struct
{
void operator()(tracked_cv_mat* bm) { bm->validate(); }
void operator()(scalar_wrapper* sw) { sw->writeBack(); }
void operator()(...) { }
} validate;
//dummy array to unfold parameter pack
int dummy[] = { 0, (validate(&outs), 0)... };
cv::util::suppress_unused_warning(dummy);
}
template<class T> struct get_out;
template<> struct get_out<cv::GMat>
{
static tracked_cv_mat get(GCPUContext &ctx, int idx)
{
auto& r = ctx.outMatR(idx);
return {r};
}
};
template<> struct get_out<cv::GScalar>
{
static scalar_wrapper get(GCPUContext &ctx, int idx)
{
auto& s = ctx.outValR(idx);
return {s};
}
};
template<typename U> struct get_out<cv::GArray<U>>
{
static std::vector<U>& get(GCPUContext &ctx, int idx)
{
return ctx.outVecR<U>(idx);
}
};
template<typename, typename, typename>
struct OCVCallHelper;
// FIXME: probably can be simplified with std::apply or analogue.
template<typename Impl, typename... Ins, typename... Outs>
struct OCVCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> >
{
template<typename... Inputs>
struct call_and_postprocess
{
template<typename... Outputs>
static void call(Inputs&&... ins, Outputs&&... outs)
{
//not using a std::forward on outs is deliberate in order to
//cause compilation error, by tring to bind rvalue references to lvalue references
Impl::run(std::forward<Inputs>(ins)..., outs...);
postprocess(outs...);
}
};
template<int... IIs, int... OIs>
static void call_impl(GCPUContext &ctx, detail::Seq<IIs...>, detail::Seq<OIs...>)
{
//Make sure that OpenCV kernels do not reallocate memory for output parameters
//by comparing it's state (data ptr) before and after the call.
//This is done by converting each output Mat into tracked_cv_mat object, and binding
//them to parameters of ad-hoc function
//Convert own::Scalar to cv::Scalar before call kernel and run kernel
//convert cv::Scalar to own::Scalar after call kernel and write back results
call_and_postprocess<decltype(get_in<Ins>::get(ctx, IIs))...>::call(get_in<Ins>::get(ctx, IIs)..., get_out<Outs>::get(ctx, OIs)...);
}
static void call(GCPUContext &ctx)
{
call_impl(ctx,
typename detail::MkSeq<sizeof...(Ins)>::type(),
typename detail::MkSeq<sizeof...(Outs)>::type());
}
};
} // namespace detail
template<class Impl, class K>
class GCPUKernelImpl: public detail::OCVCallHelper<Impl, typename K::InArgs, typename K::OutArgs>
{
using P = detail::OCVCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
public:
using API = K;
static cv::gapi::GBackend backend() { return cv::gapi::cpu::backend(); }
static cv::GCPUKernel kernel() { return GCPUKernel(&P::call); }
};
#define GAPI_OCV_KERNEL(Name, API) struct Name: public cv::GCPUKernelImpl<Name, API>
} // namespace cv
#endif // OPENCV_GAPI_GCPUKERNEL_HPP

@ -0,0 +1,27 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_CPU_IMGPROC_API_HPP
#define OPENCV_GAPI_CPU_IMGPROC_API_HPP
#include <opencv2/core/cvdef.h> // GAPI_EXPORTS
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
namespace cv {
namespace gapi {
namespace imgproc {
namespace cpu {
GAPI_EXPORTS GKernelPackage kernels();
} // namespace cpu
} // namespace imgproc
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_CPU_IMGPROC_API_HPP

@ -0,0 +1,120 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_FLUID_BUFFER_HPP
#define OPENCV_GAPI_FLUID_BUFFER_HPP
#include <list>
#include <numeric> // accumulate
#include <ostream> // ostream
#include <cstdint> // uint8_t
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/gmat.hpp>
#include "opencv2/gapi/util/optional.hpp"
#include "opencv2/gapi/own/scalar.hpp"
namespace cv {
namespace gapi {
namespace fluid {
struct Border
{
#if 1
Border(int _type, cv::Scalar _val) : type(_type), value(to_own(_val)) {};
#endif
Border(int _type, cv::gapi::own::Scalar _val) : type(_type), value(_val) {};
int type;
cv::gapi::own::Scalar value;
};
using BorderOpt = util::optional<Border>;
bool operator == (const Border& b1, const Border& b2);
class GAPI_EXPORTS Buffer;
class GAPI_EXPORTS View
{
public:
View() = default;
const uint8_t* InLineB(int index) const; // -(w-1)/2...0...+(w-1)/2 for Filters
template<typename T> const T* InLine(int i) const
{
const uint8_t* ptr = this->InLineB(i);
return reinterpret_cast<const T*>(ptr);
}
operator bool() const;
bool ready() const;
int length() const;
int y() const;
GMatDesc meta() const;
class GAPI_EXPORTS Priv; // internal use only
Priv& priv(); // internal use only
const Priv& priv() const; // internal use only
View(Priv* p);
private:
std::shared_ptr<Priv> m_priv;
};
class GAPI_EXPORTS Buffer
{
public:
// Default constructor (executable creation stage,
// all following initialization performed in Priv::init())
Buffer();
// Scratch constructor (user kernels)
Buffer(const cv::GMatDesc &desc);
// Constructor for intermediate buffers (for tests)
Buffer(const cv::GMatDesc &desc,
int max_line_consumption, int border_size,
int skew,
int wlpi,
BorderOpt border);
// Constructor for in/out buffers (for tests)
Buffer(const cv::Mat &data, bool is_input);
uint8_t* OutLineB(int index = 0);
template<typename T> T* OutLine(int index = 0)
{
uint8_t* ptr = this->OutLineB(index);
return reinterpret_cast<T*>(ptr);
}
int y() const;
int linesReady() const;
void debug(std::ostream &os) const;
int length() const;
int lpi() const; // LPI for WRITER
GMatDesc meta() const;
View mkView(int lineConsumption, int borderSize, BorderOpt border, bool ownStorage);
class GAPI_EXPORTS Priv; // internal use only
Priv& priv(); // internal use only
const Priv& priv() const; // internal use only
private:
std::shared_ptr<Priv> m_priv;
};
} // namespace cv::gapi::fluid
} // namespace cv::gapi
} // namespace cv
#endif // OPENCV_GAPI_FLUID_BUFFER_HPP

@ -0,0 +1,283 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_FLUID_KERNEL_HPP
#define OPENCV_GAPI_FLUID_KERNEL_HPP
#include <vector>
#include <functional>
#include <map>
#include <unordered_map>
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/gcommon.hpp>
#include <opencv2/gapi/gkernel.hpp>
#include <opencv2/gapi/garg.hpp>
#include <opencv2/gapi/own/types.hpp>
#include <opencv2/gapi/fluid/gfluidbuffer.hpp>
// FIXME: namespace scheme for backends?
namespace cv {
namespace gapi
{
namespace fluid
{
GAPI_EXPORTS cv::gapi::GBackend backend();
} // namespace flud
} // namespace gapi
class GAPI_EXPORTS GFluidKernel
{
public:
enum class Kind
{
Filter,
Resize
};
// This function is a generic "doWork" callback
using F = std::function<void(const cv::GArgs&, const std::vector<gapi::fluid::Buffer*> &)>;
// This function is a generic "initScratch" callback
using IS = std::function<void(const cv::GMetaArgs &, const cv::GArgs&, gapi::fluid::Buffer &)>;
// This function is a generic "resetScratch" callback
using RS = std::function<void(gapi::fluid::Buffer &)>;
// This function describes kernel metadata inference rule.
using M = std::function<GMetaArgs(const GMetaArgs &, const GArgs &)>;
// This function is a generic "getBorder" callback (extracts border-related data from kernel's input parameters)
using B = std::function<gapi::fluid::BorderOpt(const GMetaArgs&, const GArgs&)>;
// FIXME: move implementations out of header file
GFluidKernel() {}
GFluidKernel(int w, Kind k, int l, bool scratch, const F& f, const IS &is, const RS &rs, const B& b)
: m_window(w)
, m_kind(k)
, m_lpi(l)
, m_scratch(scratch)
, m_f(f)
, m_is(is)
, m_rs(rs)
, m_b(b) {}
int m_window = -1;
Kind m_kind;
const int m_lpi = -1;
const bool m_scratch = false;
const F m_f;
const IS m_is;
const RS m_rs;
const B m_b;
};
// FIXME!!!
// This is the temporary and experimental API
// which should be replaced by runtime roi-based scheduling
struct GFluidOutputRois
{
std::vector<cv::gapi::own::Rect> rois;
};
namespace detail
{
template<> struct CompileArgTag<GFluidOutputRois>
{
static const char* tag() { return "gapi.fluid.outputRois"; }
};
} // namespace detail
namespace detail
{
template<class T> struct fluid_get_in;
template<> struct fluid_get_in<cv::GMat>
{
static const cv::gapi::fluid::View& get(const cv::GArgs &in_args, int idx)
{
return in_args[idx].get<cv::gapi::fluid::View>();
}
};
template<> struct fluid_get_in<cv::GScalar>
{
static const cv::Scalar get(const cv::GArgs &in_args, int idx)
{
return cv::gapi::own::to_ocv(in_args[idx].get<cv::gapi::own::Scalar>());
}
};
template<class T> struct fluid_get_in
{
static T get(const cv::GArgs &in_args, int idx)
{
return in_args[idx].get<T>();
}
};
template<bool, typename Impl, typename... Ins>
struct scratch_helper;
template<typename Impl, typename... Ins>
struct scratch_helper<true, Impl, Ins...>
{
// Init
template<int... IIs>
static void help_init_impl(const cv::GMetaArgs &metas,
const cv::GArgs &in_args,
gapi::fluid::Buffer &scratch_buf,
detail::Seq<IIs...>)
{
Impl::initScratch(get_in_meta<Ins>(metas, in_args, IIs)..., scratch_buf);
}
static void help_init(const cv::GMetaArgs &metas,
const cv::GArgs &in_args,
gapi::fluid::Buffer &b)
{
help_init_impl(metas, in_args, b, typename detail::MkSeq<sizeof...(Ins)>::type());
}
// Reset
static void help_reset(gapi::fluid::Buffer &b)
{
Impl::resetScratch(b);
}
};
template<typename Impl, typename... Ins>
struct scratch_helper<false, Impl, Ins...>
{
static void help_init(const cv::GMetaArgs &,
const cv::GArgs &,
gapi::fluid::Buffer &)
{
GAPI_Assert(false);
}
static void help_reset(gapi::fluid::Buffer &)
{
GAPI_Assert(false);
}
};
template<typename T> struct is_gmat_type
{
static const constexpr bool value = std::is_same<cv::GMat, T>::value;
};
template<bool CallCustomGetBorder, typename Impl, typename... Ins>
struct get_border_helper;
template<typename Impl, typename... Ins>
struct get_border_helper<true, Impl, Ins...>
{
template<int... IIs>
static gapi::fluid::BorderOpt get_border_impl(const GMetaArgs &metas,
const cv::GArgs &in_args,
cv::detail::Seq<IIs...>)
{
return util::make_optional(Impl::getBorder(cv::detail::get_in_meta<Ins>(metas, in_args, IIs)...));
}
static gapi::fluid::BorderOpt help(const GMetaArgs &metas,
const cv::GArgs &in_args)
{
return get_border_impl(metas, in_args, typename detail::MkSeq<sizeof...(Ins)>::type());
}
};
template<typename Impl, typename... Ins>
struct get_border_helper<false, Impl, Ins...>
{
static gapi::fluid::BorderOpt help(const cv::GMetaArgs &,
const cv::GArgs &)
{
return {};
}
};
template<typename, typename, typename, bool UseScratch>
struct FluidCallHelper;
template<typename Impl, typename... Ins, typename... Outs, bool UseScratch>
struct FluidCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...>, UseScratch>
{
static_assert(all_satisfy<is_gmat_type, Outs...>::value, "return type must be GMat");
// Execution dispatcher ////////////////////////////////////////////////////
template<int... IIs, int... OIs>
static void call_impl(const cv::GArgs &in_args,
const std::vector<gapi::fluid::Buffer*> &out_bufs,
detail::Seq<IIs...>,
detail::Seq<OIs...>)
{
Impl::run(fluid_get_in<Ins>::get(in_args, IIs)..., *out_bufs[OIs]...);
}
static void call(const cv::GArgs &in_args,
const std::vector<gapi::fluid::Buffer*> &out_bufs)
{
constexpr int numOuts = (sizeof...(Outs)) + (UseScratch ? 1 : 0);
call_impl(in_args, out_bufs,
typename detail::MkSeq<sizeof...(Ins)>::type(),
typename detail::MkSeq<numOuts>::type());
}
// Scratch buffer initialization dispatcher ////////////////////////////////
static void init_scratch(const GMetaArgs &metas,
const cv::GArgs &in_args,
gapi::fluid::Buffer &b)
{
scratch_helper<UseScratch, Impl, Ins...>::help_init(metas, in_args, b);
}
// Scratch buffer reset dispatcher /////////////////////////////////////////
static void reset_scratch(gapi::fluid::Buffer &scratch_buf)
{
scratch_helper<UseScratch, Impl, Ins...>::help_reset(scratch_buf);
}
static gapi::fluid::BorderOpt getBorder(const GMetaArgs &metas, const cv::GArgs &in_args)
{
// User must provide "init" callback if Window != 1
// TODO: move to constexpr if when we enable C++17
constexpr bool callCustomGetBorder = (Impl::Window != 1);
return get_border_helper<callCustomGetBorder, Impl, Ins...>::help(metas, in_args);
}
};
} // namespace detail
template<class Impl, class K, bool UseScratch>
class GFluidKernelImpl
{
static const int LPI = 1;
static const auto Kind = GFluidKernel::Kind::Filter;
using P = detail::FluidCallHelper<Impl, typename K::InArgs, typename K::OutArgs, UseScratch>;
public:
using API = K;
static GFluidKernel kernel()
{
// FIXME: call() and getOutMeta() needs to be renamed so it is clear these
// functions are internal wrappers, not user API
return GFluidKernel(Impl::Window, Impl::Kind, Impl::LPI,
UseScratch,
&P::call, &P::init_scratch, &P::reset_scratch, &P::getBorder);
}
static cv::gapi::GBackend backend() { return cv::gapi::fluid::backend(); }
};
#define GAPI_FLUID_KERNEL(Name, API, Scratch) struct Name: public cv::GFluidKernelImpl<Name, API, Scratch>
} // namespace cv
#endif // OPENCV_GAPI_GCPUKERNEL_HPP

@ -0,0 +1,98 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GARG_HPP
#define OPENCV_GAPI_GARG_HPP
#include <vector>
#include <type_traits>
#include <opencv2/gapi/opencv_includes.hpp>
#include "opencv2/gapi/own/mat.hpp"
#include "opencv2/gapi/util/any.hpp"
#include "opencv2/gapi/util/variant.hpp"
#include "opencv2/gapi/gmat.hpp"
#include "opencv2/gapi/gscalar.hpp"
#include "opencv2/gapi/garray.hpp"
#include "opencv2/gapi/gtype_traits.hpp"
#include "opencv2/gapi/gmetaarg.hpp"
#include "opencv2/gapi/own/scalar.hpp"
namespace cv {
class GArg;
namespace detail {
template<typename T>
using is_garg = std::is_same<GArg, typename std::decay<T>::type>;
}
// Parameter holder class for a node
// Depending on platform capabilities, can either support arbitrary types
// (as `boost::any`) or a limited number of types (as `boot::variant`).
// FIXME: put into "details" as a user shouldn't use it in his code
class GAPI_EXPORTS GArg
{
public:
GArg() {}
template<typename T, typename std::enable_if<!detail::is_garg<T>::value, int>::type = 0>
explicit GArg(const T &t)
: kind(detail::GTypeTraits<T>::kind)
, value(detail::wrap_gapi_helper<T>::wrap(t))
{
}
template<typename T, typename std::enable_if<!detail::is_garg<T>::value, int>::type = 0>
explicit GArg(T &&t)
: kind(detail::GTypeTraits<typename std::decay<T>::type>::kind)
, value(detail::wrap_gapi_helper<T>::wrap(t))
{
}
template<typename T> T& get()
{
return util::any_cast<typename std::remove_reference<T>::type>(value);
}
template<typename T> const T& get() const
{
return util::any_cast<typename std::remove_reference<T>::type>(value);
}
detail::ArgKind kind = detail::ArgKind::OPAQUE;
protected:
util::any value;
};
using GArgs = std::vector<GArg>;
// FIXME: Express as M<GProtoArg...>::type
// FIXME: Move to a separate file!
using GRunArg = util::variant<cv::Mat, cv::gapi::own::Mat, cv::Scalar, cv::gapi::own::Scalar, cv::detail::VectorRef>;
using GRunArgs = std::vector<GRunArg>;
using GRunArgP = util::variant<cv::Mat*, cv::gapi::own::Mat*, cv::Scalar*, cv::gapi::own::Scalar*, cv::detail::VectorRef>;
using GRunArgsP = std::vector<GRunArgP>;
template<typename... Ts> inline GRunArgs gin(const Ts&... args)
{
return GRunArgs{ GRunArg(detail::wrap_host_helper<Ts>::wrap_in(args))... };
}
template<typename... Ts> inline GRunArgsP gout(Ts&... args)
{
return GRunArgsP{ GRunArgP(detail::wrap_host_helper<Ts>::wrap_out(args))... };
}
} // namespace cv
#endif // OPENCV_GAPI_GARG_HPP

@ -0,0 +1,239 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GARRAY_HPP
#define OPENCV_GAPI_GARRAY_HPP
#include <functional>
#include <ostream>
#include <vector>
#include <memory>
#include <opencv2/gapi/own/exports.hpp>
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/util/variant.hpp>
#include <opencv2/gapi/util/throw.hpp>
#include "opencv2/gapi/own/assert.hpp"
namespace cv
{
// Forward declaration; GNode and GOrigin are an internal
// (user-inaccessible) classes.
class GNode;
struct GOrigin;
template<typename T> class GArray;
struct GArrayDesc
{
// FIXME: Body
// FIXME: Also implement proper operator== then
bool operator== (const GArrayDesc&) const { return true; }
};
template<typename U> GArrayDesc descr_of(const std::vector<U> &) { return {};}
inline GArrayDesc empty_array_desc() {return {}; }
std::ostream& operator<<(std::ostream& os, const cv::GArrayDesc &desc);
namespace detail
{
// ConstructVec is a callback which stores information about T and is used by
// G-API runtime to construct arrays in host memory (T remains opaque for G-API).
// ConstructVec is carried into G-API internals by GArrayU.
// Currently it is suitable for Host (CPU) plugins only, real offload may require
// more information for manual memory allocation on-device.
class VectorRef;
using ConstructVec = std::function<void(VectorRef&)>;
// This class strips type information from GArray<T> and makes it usable
// in the G-API graph compiler (expression unrolling, graph generation, etc).
// Part of GProtoArg.
class GAPI_EXPORTS GArrayU
{
public:
GArrayU(const GNode &n, std::size_t out); // Operation result constructor
GOrigin& priv(); // Internal use only
const GOrigin& priv() const; // Internal use only
protected:
GArrayU(); // Default constructor
template<class> friend class cv::GArray; // (avialable to GArray<T> only)
void setConstructFcn(ConstructVec &&cv); // Store T-aware constructor
std::shared_ptr<GOrigin> m_priv;
};
// This class represents a typed STL vector reference.
// Depending on origins, this reference may be either "just a" reference to
// an object created externally, OR actually own the underlying object
// (be value holder).
class BasicVectorRef
{
public:
std::size_t m_elemSize = 0ul;
cv::GArrayDesc m_desc;
virtual ~BasicVectorRef() {}
};
template<typename T> class VectorRefT: public BasicVectorRef
{
using empty_t = util::monostate;
using ro_ext_t = const std::vector<T> *;
using rw_ext_t = std::vector<T> *;
using rw_own_t = std::vector<T> ;
util::variant<empty_t, ro_ext_t, rw_ext_t, rw_own_t> m_ref;
inline bool isEmpty() const { return util::holds_alternative<empty_t>(m_ref); }
inline bool isROExt() const { return util::holds_alternative<ro_ext_t>(m_ref); }
inline bool isRWExt() const { return util::holds_alternative<rw_ext_t>(m_ref); }
inline bool isRWOwn() const { return util::holds_alternative<rw_own_t>(m_ref); }
void init(const std::vector<T>* vec = nullptr)
{
m_elemSize = sizeof(T);
if (vec) m_desc = cv::descr_of(*vec);
}
public:
VectorRefT() { init(); }
virtual ~VectorRefT() {}
explicit VectorRefT(const std::vector<T>& vec) : m_ref(&vec) { init(&vec); }
explicit VectorRefT(std::vector<T>& vec) : m_ref(&vec) { init(&vec); }
explicit VectorRefT(std::vector<T>&& vec) : m_ref(std::move(vec)) { init(&vec); }
// Reset a VectorRefT. Called only for objects instantiated
// internally in G-API (e.g. temporary GArray<T>'s within a
// computation). Reset here means both initialization
// (creating an object) and reset (discarding its existing
// content before the next execution). Must never be called
// for external VectorRefTs.
void reset()
{
if (isEmpty())
{
std::vector<T> empty_vector;
m_desc = cv::descr_of(empty_vector);
m_ref = std::move(empty_vector);
GAPI_Assert(isRWOwn());
}
else if (isRWOwn())
{
util::get<rw_own_t>(m_ref).clear();
}
else GAPI_Assert(false); // shouldn't be called in *EXT modes
}
// Obtain a WRITE reference to underlying object
// Used by CPU kernel API wrappers when a kernel execution frame
// is created
std::vector<T>& wref()
{
GAPI_Assert(isRWExt() || isRWOwn());
if (isRWExt()) return *util::get<rw_ext_t>(m_ref);
if (isRWOwn()) return util::get<rw_own_t>(m_ref);
util::throw_error(std::logic_error("Impossible happened"));
}
// Obtain a READ reference to underlying object
// Used by CPU kernel API wrappers when a kernel execution frame
// is created
const std::vector<T>& rref() const
{
// ANY vector can be accessed for reading, even if it declared for
// output. Example -- a GComputation from [in] to [out1,out2]
// where [out2] is a result of operation applied to [out1]:
//
// GComputation boundary
// . . . . . . .
// . .
// [in] ----> foo() ----> [out1]
// . . :
// . . . .:. . .
// . V .
// . bar() ---> [out2]
// . . . . . . . . . . . .
//
if (isROExt()) return *util::get<ro_ext_t>(m_ref);
if (isRWExt()) return *util::get<rw_ext_t>(m_ref);
if (isRWOwn()) return util::get<rw_own_t>(m_ref);
util::throw_error(std::logic_error("Impossible happened"));
}
};
// This class strips type information from VectorRefT<> and makes it usable
// in the G-API executables (carrying run-time data/information to kernels).
// Part of GRunArg.
// Its methods are typed proxies to VectorRefT<T>.
// VectorRef maintains "reference" semantics so two copies of VectoRef refer
// to the same underlying object.
// FIXME: Put a good explanation on why cv::OutputArray doesn't fit this role
class VectorRef
{
std::shared_ptr<BasicVectorRef> m_ref;
template<typename T> inline void check() const
{
GAPI_DbgAssert(dynamic_cast<VectorRefT<T>*>(m_ref.get()) != nullptr);
GAPI_Assert(sizeof(T) == m_ref->m_elemSize);
}
public:
VectorRef() = default;
template<typename T> explicit VectorRef(const std::vector<T>& vec) : m_ref(new VectorRefT<T>(vec)) {}
template<typename T> explicit VectorRef(std::vector<T>& vec) : m_ref(new VectorRefT<T>(vec)) {}
template<typename T> explicit VectorRef(std::vector<T>&& vec) : m_ref(new VectorRefT<T>(vec)) {}
template<typename T> void reset()
{
if (!m_ref) m_ref.reset(new VectorRefT<T>());
check<T>();
static_cast<VectorRefT<T>&>(*m_ref).reset();
}
template<typename T> std::vector<T>& wref()
{
check<T>();
return static_cast<VectorRefT<T>&>(*m_ref).wref();
}
template<typename T> const std::vector<T>& rref() const
{
check<T>();
return static_cast<VectorRefT<T>&>(*m_ref).rref();
}
cv::GArrayDesc descr_of() const
{
return m_ref->m_desc;
}
};
} // namespace detail
template<typename T> class GArray
{
public:
GArray() { putDetails(); } // Empty constructor
explicit GArray(detail::GArrayU &&ref) // GArrayU-based constructor
: m_ref(ref) { putDetails(); } // (used by GCall, not for users)
detail::GArrayU strip() const { return m_ref; }
private:
static void VCTor(detail::VectorRef& vref) { vref.reset<T>(); }
void putDetails() {m_ref.setConstructFcn(&VCTor); }
detail::GArrayU m_ref;
};
} // namespace cv
#endif // OPENCV_GAPI_GARRAY_HPP

@ -0,0 +1,63 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GCALL_HPP
#define OPENCV_GAPI_GCALL_HPP
#include "opencv2/gapi/garg.hpp" // GArg
#include "opencv2/gapi/gmat.hpp" // GMat
#include "opencv2/gapi/gscalar.hpp" // GScalar
#include "opencv2/gapi/garray.hpp" // GArray<T>
namespace cv {
struct GKernel;
// The whole idea of this class is to represent an operation
// which is applied to arguments. This is part of public API,
// since it is what users should use to define kernel interfaces.
class GAPI_EXPORTS GCall final
{
public:
class Priv;
explicit GCall(const GKernel &k);
~GCall();
template<typename... Ts>
GCall& pass(Ts&&... args)
{
setArgs({cv::GArg(std::move(args))...});
return *this;
}
// A generic yield method - obtain a link to operator's particular GMat output
GMat yield (int output = 0);
GScalar yieldScalar(int output = 0);
template<class T> GArray<T> yieldArray(int output = 0)
{
return GArray<T>(yieldArray(output));
}
// Internal use only
Priv& priv();
const Priv& priv() const;
protected:
std::shared_ptr<Priv> m_priv;
void setArgs(std::vector<GArg> &&args);
// Public version returns a typed array, this one is implementation detail
detail::GArrayU yieldArray(int output = 0);
};
} // namespace cv
#endif // OPENCV_GAPI_GCALL_HPP

@ -0,0 +1,118 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GCOMMON_HPP
#define OPENCV_GAPI_GCOMMON_HPP
#include <functional> // std::hash
#include <vector> // std::vector
#include <type_traits> // decay
#include <opencv2/gapi/opencv_includes.hpp>
#include "opencv2/gapi/util/any.hpp"
#include "opencv2/gapi/own/exports.hpp"
#include "opencv2/gapi/own/assert.hpp"
namespace cv {
namespace detail
{
// This is a trait-like structure to mark backend-specific compile arguments
// with tags
template<typename T> struct CompileArgTag;
template<typename T> struct CompileArgTag
{
static const char* tag() { return ""; };
};
}
// 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)
// to components which are internal and operate on a lower-level entities
// (e.g., compiler, backends).
// FIXME: merge with ArgKind?
// FIXME: replace with variant[format desc]?
enum class GShape: int
{
GMAT,
GSCALAR,
GARRAY,
};
struct GCompileArg;
namespace detail {
template<typename T>
using is_compile_arg = std::is_same<GCompileArg, typename std::decay<T>::type>;
}
// CompileArg is an unified interface over backend-specific compilation
// information
// FIXME: Move to a separate file?
struct GAPI_EXPORTS GCompileArg
{
public:
std::string tag;
// FIXME: use decay in GArg/other trait-based wrapper before leg is shot!
template<typename T, typename std::enable_if<!detail::is_compile_arg<T>::value, int>::type = 0>
explicit GCompileArg(T &&t)
: tag(detail::CompileArgTag<typename std::decay<T>::type>::tag())
, arg(t)
{
}
template<typename T> T& get()
{
return util::any_cast<T>(arg);
}
template<typename T> const T& get() const
{
return util::any_cast<T>(arg);
}
private:
util::any arg;
};
using GCompileArgs = std::vector<GCompileArg>;
template<typename... Ts> GCompileArgs compile_args(Ts&&... args)
{
return GCompileArgs{ GCompileArg(args)... };
}
struct graph_dump_path
{
std::string m_dump_path;
};
namespace detail
{
template<> struct CompileArgTag<cv::graph_dump_path>
{
static const char* tag() { return "gapi.graph_dump_path"; }
};
}
} // namespace cv
// std::hash overload for GShape
namespace std
{
template<> struct hash<cv::GShape>
{
size_t operator() (cv::GShape sh) const
{
return std::hash<int>()(static_cast<int>(sh));
}
};
} // namespace std
#endif // OPENCV_GAPI_GCOMMON_HPP

@ -0,0 +1,59 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GCOMPILED_HPP
#define OPENCV_GAPI_GCOMPILED_HPP
#include <vector>
#include "opencv2/gapi/own/assert.hpp"
#include "opencv2/core/mat.hpp"
#include "opencv2/gapi/garg.hpp"
namespace cv {
// This class represents a compiled computation.
// In theory (and ideally), it can be used w/o the rest of APIs.
// In theory (and ideally), it can be serialized/deserialized.
// It can enable scenarious like deployment to an autonomous devince, FuSa, etc.
//
// Currently GCompiled assumes all GMats you used to pass data to G-API
// are valid and not destroyed while you use a GCompiled object.
//
// FIXME: In future, there should be a way to name I/O objects and specify it
// to GCompiled externally (for example, when it is loaded on the target system).
class GAPI_EXPORTS GCompiled
{
public:
class GAPI_EXPORTS Priv;
GCompiled();
void operator() (GRunArgs &&ins, GRunArgsP &&outs); // Generic arg-to-arg
void operator() (cv::Mat in, cv::Mat &out); // Unary overload
void operator() (cv::Mat in, cv::Scalar &out); // Unary overload (scalar)
void operator() (cv::Mat in1, cv::Mat in2, cv::Mat &out); // Binary overload
void operator() (cv::Mat in1, cv::Mat in2, cv::Scalar &out); // Binary overload (scalar)
void operator() (const std::vector<cv::Mat> &ins, // Compatibility overload
const std::vector<cv::Mat> &outs);
Priv& priv();
explicit operator bool () const; // Check if GCompiled is runnable or empty
const GMetaArgs& metas() const; // Meta passed to compile()
const GMetaArgs& outMetas() const; // Inferred output metadata
protected:
std::shared_ptr<Priv> m_priv;
};
}
#endif // OPENCV_GAPI_GCOMPILED_HPP

@ -0,0 +1,123 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GCOMPOUNDKERNEL_HPP
#define OPENCV_GAPI_GCOMPOUNDKERNEL_HPP
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/gcommon.hpp>
#include <opencv2/gapi/gkernel.hpp>
#include <opencv2/gapi/garg.hpp>
namespace cv {
namespace gapi
{
namespace compound
{
// FIXME User does not need to know about this function
// Needs that user may define compound kernels(as cpu kernels)
GAPI_EXPORTS cv::gapi::GBackend backend();
} // namespace compound
} // namespace gapi
namespace detail
{
struct GCompoundContext
{
explicit GCompoundContext(const GArgs& in_args);
template<typename T>
const T& inArg(int input) { return m_args.at(input).get<T>(); }
GArgs m_args;
GArgs m_results;
};
class GAPI_EXPORTS GCompoundKernel
{
// Compound kernel must use all of it's inputs
public:
using F = std::function<void(GCompoundContext& ctx)>;
explicit GCompoundKernel(const F& f);
void apply(GCompoundContext& ctx);
protected:
F m_f;
};
template<typename T> struct get_compound_in
{
static T get(GCompoundContext &ctx, int idx) { return ctx.inArg<T>(idx); }
};
template<typename U> struct get_compound_in<cv::GArray<U>>
{
static cv::GArray<U> get(GCompoundContext &ctx, int idx)
{
auto array = cv::GArray<U>();
ctx.m_args[idx] = GArg(array);
return array;
}
};
// Kernel may return one object(GMat, GScalar) or a tuple of objects.
// This helper is needed to cast return value to the same form(tuple)
template<typename>
struct tuple_wrap_helper;
template<typename T> struct tuple_wrap_helper
{
static std::tuple<T> get(T&& obj) { return std::make_tuple(std::move(obj)); }
};
template<typename... Objs>
struct tuple_wrap_helper<std::tuple<Objs...>>
{
static std::tuple<Objs...> get(std::tuple<Objs...>&& objs) { return objs; }
};
template<typename, typename, typename>
struct GCompoundCallHelper;
template<typename Impl, typename... Ins, typename... Outs>
struct GCompoundCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> >
{
template<int... IIs, int... OIs>
static void expand_impl(GCompoundContext &ctx, detail::Seq<IIs...>, detail::Seq<OIs...>)
{
auto result = Impl::expand(get_compound_in<Ins>::get(ctx, IIs)...);
auto tuple_return = tuple_wrap_helper<decltype(result)>::get(std::move(result));
ctx.m_results = { cv::GArg(std::get<OIs>(tuple_return))... };
}
static void expand(GCompoundContext &ctx)
{
expand_impl(ctx,
typename detail::MkSeq<sizeof...(Ins)>::type(),
typename detail::MkSeq<sizeof...(Outs)>::type());
}
};
template<class Impl, class K>
class GCompoundKernelImpl: public cv::detail::GCompoundCallHelper<Impl, typename K::InArgs, typename K::OutArgs>
{
using P = cv::detail::GCompoundCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
public:
using API = K;
static cv::gapi::GBackend backend() { return cv::gapi::compound::backend(); }
static GCompoundKernel kernel() { return GCompoundKernel(&P::expand); }
};
} // namespace detail
#define GAPI_COMPOUND_KERNEL(Name, API) struct Name: public cv::detail::GCompoundKernelImpl<Name, API>
} // namespace cv
#endif // OPENCV_GAPI_GCOMPOUNDKERNEL_HPP

@ -0,0 +1,135 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GCOMPUTATION_HPP
#define OPENCV_GAPI_GCOMPUTATION_HPP
#include <functional>
#include "opencv2/gapi/util/util.hpp"
#include "opencv2/gapi/gcommon.hpp"
#include "opencv2/gapi/gproto.hpp"
#include "opencv2/gapi/garg.hpp"
#include "opencv2/gapi/gcompiled.hpp"
namespace cv {
namespace detail
{
// FIXME: move to algorithm, cover with separate tests
// FIXME: replace with O(1) version (both memory and compilation time)
template<typename...>
struct last_type;
template<typename T>
struct last_type<T> { using type = T;};
template<typename T, typename... Ts>
struct last_type<T, Ts...> { using type = typename last_type<Ts...>::type; };
template<typename... Ts>
using last_type_t = typename last_type<Ts...>::type;
}
class GAPI_EXPORTS GComputation
{
public:
class Priv;
typedef std::function<GComputation()> Generator;
// Various constructors enable different ways to define a computation: /////
// 1. Generic constructors
GComputation(const Generator& gen); // Generator overload
GComputation(GProtoInputArgs &&ins,
GProtoOutputArgs &&outs); // Arg-to-arg overload
// 2. Syntax sugar and compatibility overloads
GComputation(GMat in, GMat out); // Unary overload
GComputation(GMat in, GScalar out); // Unary overload (scalar)
GComputation(GMat in1, GMat in2, GMat out); // Binary overload
GComputation(GMat in1, GMat in2, GScalar out); // Binary overload (scalar)
GComputation(const std::vector<GMat> &ins, // Compatibility overload
const std::vector<GMat> &outs);
// Various versions of apply(): ////////////////////////////////////////////
// 1. Generic apply()
void apply(GRunArgs &&ins, GRunArgsP &&outs, GCompileArgs &&args = {}); // Arg-to-arg overload
// 2. Syntax sugar and compatibility overloads
void apply(cv::Mat in, cv::Mat &out, GCompileArgs &&args = {}); // Unary overload
void apply(cv::Mat in, cv::Scalar &out, GCompileArgs &&args = {}); // Unary overload (scalar)
void apply(cv::Mat in1, cv::Mat in2, cv::Mat &out, GCompileArgs &&args = {}); // Binary overload
void apply(cv::Mat in1, cv::Mat in2, cv::Scalar &out, GCompileArgs &&args = {}); // Binary overload (scalar)
void apply(const std::vector<cv::Mat>& ins, // Compatibility overload
const std::vector<cv::Mat>& outs,
GCompileArgs &&args = {});
// Various versions of compile(): //////////////////////////////////////////
// 1. Generic compile() - requires metas to be passed as vector
GCompiled compile(GMetaArgs &&in_metas, GCompileArgs &&args = {});
// 2. Syntax sugar - variadic list of metas, no extra compile args
template<typename... Ts>
auto compile(const Ts&... metas) ->
typename std::enable_if<detail::are_meta_descrs<Ts...>::value, GCompiled>::type
{
return compile(GMetaArgs{GMetaArg(metas)...}, GCompileArgs());
}
// 3. Syntax sugar - variadic list of metas, extra compile args
// (seems optional parameters don't work well when there's an variadic template
// comes first)
//
// Ideally it should look like:
//
// template<typename... Ts>
// GCompiled compile(const Ts&... metas, GCompileArgs &&args)
//
// But not all compilers can hande this (and seems they shouldn't be able to).
template<typename... Ts>
auto compile(const Ts&... meta_and_compile_args) ->
typename std::enable_if<detail::are_meta_descrs_but_last<Ts...>::value
&& std::is_same<GCompileArgs, detail::last_type_t<Ts...> >::value,
GCompiled>::type
{
//FIXME: wrapping meta_and_compile_args into a tuple to unwrap them inside a helper function is the overkill
return compile(std::make_tuple(meta_and_compile_args...),
typename detail::MkSeq<sizeof...(Ts)-1>::type());
}
// Internal use only
Priv& priv();
const Priv& priv() const;
protected:
// 4. Helper method for (3)
template<typename... Ts, int... IIs>
GCompiled compile(const std::tuple<Ts...> &meta_and_compile_args, detail::Seq<IIs...>)
{
GMetaArgs meta_args = {GMetaArg(std::get<IIs>(meta_and_compile_args))...};
GCompileArgs comp_args = std::get<sizeof...(Ts)-1>(meta_and_compile_args);
return compile(std::move(meta_args), std::move(comp_args));
}
std::shared_ptr<Priv> m_priv;
};
namespace gapi
{
// Declare an Island tagged with `name` and defined from `ins` to `outs`
// (exclusively, as ins/outs are data objects, and regioning is done on
// operations level).
// Throws if any operation between `ins` and `outs` are already assigned
// to another island.
void GAPI_EXPORTS island(const std::string &name,
GProtoInputArgs &&ins,
GProtoOutputArgs &&outs);
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_GCOMPUTATION_HPP

@ -0,0 +1,409 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GKERNEL_HPP
#define OPENCV_GAPI_GKERNEL_HPP
#include <functional>
#include <iostream>
#include <unordered_map> // map (for GKernelPackage)
#include <vector> // lookup order
#include <string> // string
#include <utility> // tuple
#include <type_traits> // false_type, true_type
#include <opencv2/gapi/gcommon.hpp> // CompileArgTag
#include <opencv2/gapi/util/util.hpp> // Seq
#include <opencv2/gapi/gcall.hpp>
#include <opencv2/gapi/garg.hpp> // GArg
#include <opencv2/gapi/gmetaarg.hpp> // GMetaArg
#include <opencv2/gapi/gtype_traits.hpp> // GTypeTraits
#include <opencv2/gapi/util/compiler_hints.hpp> //suppress_unused_warning
namespace cv {
using GShapes = std::vector<GShape>;
// GKernel describes kernel API to the system
// FIXME: add attributes of a kernel, (e.g. number and types
// of inputs, etc)
struct GAPI_EXPORTS GKernel
{
using M = std::function<GMetaArgs(const GMetaArgs &, const GArgs &)>;
const std::string name; // kernel ID, defined by its API (signature)
const M outMeta; // generic adaptor to API::outMeta(...)
const GShapes outShapes; // types (shapes) kernel's outputs
};
// GKernelImpl describes particular kernel implementation to the system
struct GAPI_EXPORTS GKernelImpl
{
util::any opaque; // backend-specific opaque info
};
template<typename, typename> class GKernelTypeM;
namespace detail
{
////////////////////////////////////////////////////////////////////////////
// yield() is used in graph construction time as a generic method to obtain
// lazy "return value" of G-API operations
//
namespace
{
template<typename T> struct Yield;
template<> struct Yield<cv::GMat>
{
static inline cv::GMat yield(cv::GCall &call, int i) { return call.yield(i); }
};
template<> struct Yield<cv::GScalar>
{
static inline cv::GScalar yield(cv::GCall &call, int i) { return call.yieldScalar(i); }
};
template<typename U> struct Yield<cv::GArray<U> >
{
static inline cv::GArray<U> yield(cv::GCall &call, int i) { return call.yieldArray<U>(i); }
};
} // anonymous namespace
////////////////////////////////////////////////////////////////////////////
// Helper classes which brings outputMeta() marshalling to kernel
// implementations
//
// 1. MetaType establishes G#Type -> G#Meta mapping between G-API dynamic
// types and its metadata descriptor types.
// This mapping is used to transform types to call outMeta() callback.
template<typename T> struct MetaType;
template<> struct MetaType<cv::GMat> { using type = GMatDesc; };
template<> struct MetaType<cv::GScalar> { using type = GScalarDesc; };
template<typename U> struct MetaType<cv::GArray<U> > { using type = GArrayDesc; };
template<typename T> struct MetaType { using type = T; }; // opaque args passed as-is
// 2. Hacky test based on MetaType to check if we operate on G-* type or not
template<typename T> using is_nongapi_type = std::is_same<T, typename MetaType<T>::type>;
// 3. Two ways to transform input arguments to its meta - for G-* and non-G* types:
template<typename T>
typename std::enable_if<!is_nongapi_type<T>::value, typename MetaType<T>::type>
::type get_in_meta(const GMetaArgs &in_meta, const GArgs &, int idx)
{
return util::get<typename MetaType<T>::type>(in_meta.at(idx));
}
template<typename T>
typename std::enable_if<is_nongapi_type<T>::value, T>
::type get_in_meta(const GMetaArgs &, const GArgs &in_args, int idx)
{
return in_args.at(idx).template get<T>();
}
// 4. The MetaHelper itself: an entity which generates outMeta() call
// based on kernel signature, with arguments properly substituted.
// 4.1 - case for multiple return values
// FIXME: probably can be simplified with std::apply or analogue.
template<typename, typename, typename>
struct MetaHelper;
template<typename K, typename... Ins, typename... Outs>
struct MetaHelper<K, std::tuple<Ins...>, std::tuple<Outs...> >
{
template<int... IIs, int... OIs>
static GMetaArgs getOutMeta_impl(const GMetaArgs &in_meta,
const GArgs &in_args,
detail::Seq<IIs...>,
detail::Seq<OIs...>)
{
// FIXME: decay?
using R = std::tuple<typename MetaType<Outs>::type...>;
const R r = K::outMeta( get_in_meta<Ins>(in_meta, in_args, IIs)... );
return GMetaArgs{ GMetaArg(std::get<OIs>(r))... };
}
// FIXME: help users identify how outMeta must look like (via default impl w/static_assert?)
static GMetaArgs getOutMeta(const GMetaArgs &in_meta,
const GArgs &in_args)
{
return getOutMeta_impl(in_meta,
in_args,
typename detail::MkSeq<sizeof...(Ins)>::type(),
typename detail::MkSeq<sizeof...(Outs)>::type());
}
};
// 4.1 - case for a single return value
// FIXME: How to avoid duplication here?
template<typename K, typename... Ins, typename Out>
struct MetaHelper<K, std::tuple<Ins...>, Out >
{
template<int... IIs>
static GMetaArgs getOutMeta_impl(const GMetaArgs &in_meta,
const GArgs &in_args,
detail::Seq<IIs...>)
{
// FIXME: decay?
using R = typename MetaType<Out>::type;
const R r = K::outMeta( get_in_meta<Ins>(in_meta, in_args, IIs)... );
return GMetaArgs{ GMetaArg(r) };
}
// FIXME: help users identify how outMeta must look like (via default impl w/static_assert?)
static GMetaArgs getOutMeta(const GMetaArgs &in_meta,
const GArgs &in_args)
{
return getOutMeta_impl(in_meta,
in_args,
typename detail::MkSeq<sizeof...(Ins)>::type());
}
};
} // namespace detail
// GKernelType and GKernelTypeM are base classes which implement typed ::on()
// method based on kernel signature. GKernelTypeM stands for multiple-return-value kernels
//
// G_TYPED_KERNEL and G_TYPED_KERNEK_M macros inherit user classes from GKernelType and
// GKernelTypeM respectively.
template<typename K, typename... R, typename... Args>
class GKernelTypeM<K, std::function<std::tuple<R...>(Args...)> >:
public detail::MetaHelper<K, std::tuple<Args...>, std::tuple<R...> >
{
template<int... IIs>
static std::tuple<R...> yield(cv::GCall &call, detail::Seq<IIs...>)
{
return std::make_tuple(detail::Yield<R>::yield(call, IIs)...);
}
public:
using InArgs = std::tuple<Args...>;
using OutArgs = std::tuple<R...>;
static std::tuple<R...> on(Args... args)
{
cv::GCall call(GKernel{K::id(), &K::getOutMeta, {detail::GTypeTraits<R>::shape...}});
call.pass(args...);
return yield(call, typename detail::MkSeq<sizeof...(R)>::type());
}
};
template<typename, typename> class GKernelType;
template<typename K, typename R, typename... Args>
class GKernelType<K, std::function<R(Args...)> >:
public detail::MetaHelper<K, std::tuple<Args...>, R >
{
public:
using InArgs = std::tuple<Args...>;
using OutArgs = std::tuple<R>;
static R on(Args... args)
{
cv::GCall call(GKernel{K::id(), &K::getOutMeta, {detail::GTypeTraits<R>::shape}});
call.pass(args...);
return detail::Yield<R>::yield(call, 0);
}
};
} // namespace cv
// FIXME: I don't know a better way so far. Feel free to suggest one
// The problem is that every typed kernel should have ::id() but body
// of the class is defined by user (with outMeta, other stuff)
#define G_ID_HELPER_CLASS(Class) Class##IdHelper
#define G_ID_HELPER_BODY(Class, Id) \
namespace detail \
{ \
struct G_ID_HELPER_CLASS(Class) \
{ \
static constexpr const char * id() {return Id;}; \
}; \
}
#define G_TYPED_KERNEL(Class, API, Id) \
G_ID_HELPER_BODY(Class, Id) \
struct Class final: public cv::GKernelType<Class, std::function API >, \
public detail::G_ID_HELPER_CLASS(Class)
// {body} is to be defined by user
#define G_TYPED_KERNEL_M(Class, API, Id) \
G_ID_HELPER_BODY(Class, Id) \
struct Class final: public cv::GKernelTypeM<Class, std::function API >, \
public detail::G_ID_HELPER_CLASS(Class) \
// {body} is to be defined by user
namespace cv
{
// Declare <unite> in cv:: namespace
enum class unite_policy
{
REPLACE,
KEEP
};
namespace gapi
{
// Prework: model "Device" API before it gets to G-API headers.
// FIXME: Don't mix with internal Backends class!
class GAPI_EXPORTS GBackend
{
public:
class Priv;
// TODO: make it template (call `new` within??)
GBackend();
explicit GBackend(std::shared_ptr<Priv> &&p);
Priv& priv();
const Priv& priv() const;
std::size_t hash() const;
bool operator== (const GBackend &rhs) const;
private:
std::shared_ptr<Priv> m_priv;
};
inline bool operator != (const GBackend &lhs, const GBackend &rhs)
{
return !(lhs == rhs);
}
} // namespace gapi
} // namespace cv
namespace std
{
template<> struct hash<cv::gapi::GBackend>
{
std::size_t operator() (const cv::gapi::GBackend &b) const
{
return b.hash();
}
};
} // namespace std
namespace cv {
namespace gapi {
// Lookup order is in fact a vector of Backends to traverse during look-up
using GLookupOrder = std::vector<GBackend>;
inline GLookupOrder lookup_order(std::initializer_list<GBackend> &&list)
{
return GLookupOrder(std::move(list));
}
// FIXME: Hide implementation
class GAPI_EXPORTS GKernelPackage
{
using S = std::unordered_map<std::string, GKernelImpl>;
using M = std::unordered_map<GBackend, S>;
M m_backend_kernels;
protected:
// Check if package contains ANY implementation of a kernel API
// by API textual id.
bool includesAPI(const std::string &id) const;
public:
// Return total number of kernels (accross all backends)
std::size_t size() const;
// Check if particular kernel implementation exist in the package.
// The key word here is _particular_ - i.e., from the specific backend.
template<typename KImpl>
bool includes() const
{
const auto set_iter = m_backend_kernels.find(KImpl::backend());
return (set_iter != m_backend_kernels.end())
? (set_iter->second.count(KImpl::API::id()) > 0)
: false;
}
// Removes all the kernels related to the given backend
void remove(const GBackend& backend);
// Check if package contains ANY implementation of a kernel API
// by API type.
template<typename KAPI>
bool includesAPI() const
{
return includesAPI(KAPI::id());
}
// Lookup a kernel, given the look-up order. Returns Backend which
// hosts kernel implementation. Throws if nothing found.
//
// If order is empty(), returns first suitable implementation.
template<typename KAPI>
GBackend lookup(const GLookupOrder &order = {}) const
{
return lookup(KAPI::id(), order).first;
}
std::pair<cv::gapi::GBackend, cv::GKernelImpl>
lookup(const std::string &id, const GLookupOrder &order = {}) const;
// Put a new kernel implementation into package
// FIXME: No overwrites allowed?
template<typename KImpl> void include()
{
auto backend = KImpl::backend();
auto kernel_id = KImpl::API::id();
auto kernel_impl = GKernelImpl{KImpl::kernel()};
m_backend_kernels[backend][kernel_id] = std::move(kernel_impl);
}
// Lists all backends which are included into package
std::vector<GBackend> backends() const;
friend GAPI_EXPORTS GKernelPackage combine(const GKernelPackage &,
const GKernelPackage &,
const cv::unite_policy);
};
template<typename... KK> GKernelPackage kernels()
{
GKernelPackage pkg;
// For those who wonder - below is a trick to call a number of
// methods based on parameter pack (zeroes just help hiding these
// calls into a sequence which helps to expand this parameter pack).
// Just note that `f(),a` always equals to `a` (with f() called!)
// and parentheses are used to hide function call in the expanded sequence.
// Leading 0 helps to handle case when KK is an empty list (kernels<>()).
int unused[] = { 0, (pkg.include<KK>(), 0)... };
cv::util::suppress_unused_warning(unused);
return pkg;
};
// Return a new package based on `lhs` and `rhs`,
// with unity policy defined by `policy`.
GAPI_EXPORTS GKernelPackage combine(const GKernelPackage &lhs,
const GKernelPackage &rhs,
const cv::unite_policy policy);
} // namespace gapi
namespace detail
{
template<> struct CompileArgTag<cv::gapi::GKernelPackage>
{
static const char* tag() { return "gapi.kernel_package"; }
};
template<> struct CompileArgTag<cv::gapi::GLookupOrder>
{
static const char* tag() { return "gapi.lookup_order"; }
};
} // namespace detail
} // namespace cv
#endif // OPENCV_GAPI_GKERNEL_HPP

@ -0,0 +1,131 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GMAT_HPP
#define OPENCV_GAPI_GMAT_HPP
#include <ostream>
#include <memory> // std::shared_ptr
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/gcommon.hpp> // GShape
#include "opencv2/gapi/own/types.hpp" // cv::gapi::own::Size
#include "opencv2/gapi/own/convert.hpp" // to_own
#include "opencv2/gapi/own/assert.hpp"
// TODO GAPI_EXPORTS or so
namespace cv
{
// Forward declaration; GNode and GOrigin are an internal
// (user-inaccessible) classes.
class GNode;
struct GOrigin;
class GAPI_EXPORTS GMat
{
public:
GMat(); // Empty constructor
GMat(const GNode &n, std::size_t out); // Operation result constructor
GOrigin& priv(); // Internal use only
const GOrigin& priv() const; // Internal use only
private:
std::shared_ptr<GOrigin> m_priv;
};
struct GAPI_EXPORTS GMatDesc
{
// FIXME: Default initializers in C++14
int depth;
int chan;
cv::gapi::own::Size size; // NB.: no multi-dimensional cases covered yet
inline bool operator== (const GMatDesc &rhs) const
{
return depth == rhs.depth && chan == rhs.chan && size == rhs.size;
}
inline bool operator!= (const GMatDesc &rhs) const
{
return !(*this == rhs);
}
// Meta combinator: return a new GMatDesc which differs in size by delta
// (all other fields are taken unchanged from this GMatDesc)
// FIXME: a better name?
GMatDesc withSizeDelta(cv::gapi::own::Size delta) const
{
GMatDesc desc(*this);
desc.size += delta;
return desc;
}
GMatDesc withSizeDelta(cv::Size delta) const
{
return withSizeDelta(to_own(delta));
}
// Meta combinator: return a new GMatDesc which differs in size by delta
// (all other fields are taken unchanged from this GMatDesc)
//
// This is an overload.
GMatDesc withSizeDelta(int dx, int dy) const
{
return withSizeDelta(cv::gapi::own::Size{dx,dy});
}
GMatDesc withSize(cv::gapi::own::Size sz) const
{
GMatDesc desc(*this);
desc.size = sz;
return desc;
}
GMatDesc withSize(cv::Size sz) const
{
return withSize(to_own(sz));
}
// Meta combinator: return a new GMatDesc with specified data depth.
// (all other fields are taken unchanged from this GMatDesc)
GMatDesc withDepth(int ddepth) const
{
GAPI_Assert(CV_MAT_CN(ddepth) == 1 || ddepth == -1);
GMatDesc desc(*this);
if (ddepth != -1) desc.depth = ddepth;
return desc;
}
// Meta combinator: return a new GMatDesc with specified data depth
// and number of channels.
// (all other fields are taken unchanged from this GMatDesc)
GMatDesc withType(int ddepth, int dchan) const
{
GAPI_Assert(CV_MAT_CN(ddepth) == 1 || ddepth == -1);
GMatDesc desc = withDepth(ddepth);
desc.chan = dchan;
return desc;
}
};
static inline GMatDesc empty_gmat_desc() { return GMatDesc{-1,-1,{-1,-1}}; }
class Mat;
GAPI_EXPORTS GMatDesc descr_of(const cv::Mat &mat);
namespace gapi { namespace own {
class Mat;
CV_EXPORTS GMatDesc descr_of(const Mat &mat);
}}//gapi::own
std::ostream& operator<<(std::ostream& os, const cv::GMatDesc &desc);
} // namespace cv
#endif // OPENCV_GAPI_GMAT_HPP

@ -0,0 +1,66 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GMETAARG_HPP
#define OPENCV_GAPI_GMETAARG_HPP
#include <vector>
#include <type_traits>
#include "opencv2/gapi/util/util.hpp"
#include "opencv2/gapi/util/variant.hpp"
#include "opencv2/gapi/gmat.hpp"
#include "opencv2/gapi/gscalar.hpp"
#include "opencv2/gapi/garray.hpp"
namespace cv
{
// FIXME: Rename to GMeta?
// FIXME: user shouldn't deal with it - put to detail?
// GMetaArg is an union type over descriptions of G-types which can serve as
// GComputation's in/output slots.
//
// GMetaArg objects are passed as arguments to GComputation::compile()
// to specify which data a compiled computation should be specialized on.
// For manual compile(), user must supply this metadata, in case of apply()
// this metadata is taken from arguments computation should operate on.
//
// The first type (monostate) is equal to "uninitialized"/"unresolved" meta.
using GMetaArg = util::variant
< util::monostate
, GMatDesc
, GScalarDesc
, GArrayDesc
>;
std::ostream& operator<<(std::ostream& os, const GMetaArg &);
using GMetaArgs = std::vector<GMetaArg>;
namespace detail
{
// These traits are used by GComputation::compile()
// FIXME: is_constructible<T> doesn't work as variant doesn't do any SFINAE
// in its current template constructor
template<typename T> struct is_meta_descr : std::false_type {};
template<> struct is_meta_descr<GMatDesc> : std::true_type {};
template<> struct is_meta_descr<GScalarDesc> : std::true_type {};
template<> struct is_meta_descr<GArrayDesc> : std::true_type {};
template<typename... Ts>
using are_meta_descrs = all_satisfy<is_meta_descr, Ts...>;
template<typename... Ts>
using are_meta_descrs_but_last = all_satisfy<is_meta_descr, typename all_but_last<Ts...>::type>;
} // namespace detail
} // namespace cv
#endif // OPENCV_GAPI_GMETAARG_HPP

@ -0,0 +1,96 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GPROTO_HPP
#define OPENCV_GAPI_GPROTO_HPP
#include <type_traits>
#include <vector>
#include <ostream>
#include "opencv2/gapi/util/variant.hpp"
#include "opencv2/gapi/gmat.hpp"
#include "opencv2/gapi/gscalar.hpp"
#include "opencv2/gapi/garray.hpp"
#include "opencv2/gapi/garg.hpp"
#include "opencv2/gapi/gmetaarg.hpp"
namespace cv {
// FIXME: user shouldn't deal with it - put to detail?
// GProtoArg is an union type over G-types which can serve as
// GComputation's in/output slots. In other words, GProtoArg
// wraps any type which can serve as G-API exchange type.
//
// In Runtime, GProtoArgs are substituted with appropriate GRunArgs.
//
// GProtoArg objects are constructed in-place when user describes
// (captures) computations, user doesn't interact with these types
// directly.
using GProtoArg = util::variant
< GMat
, GScalar
, detail::GArrayU // instead of GArray<T>
>;
using GProtoArgs = std::vector<GProtoArg>;
namespace detail
{
template<typename... Ts> inline GProtoArgs packArgs(Ts... args)
{
return GProtoArgs{ GProtoArg(wrap_gapi_helper<Ts>::wrap(args))... };
}
}
template<class Tag>
struct GIOProtoArgs
{
public:
explicit GIOProtoArgs(const GProtoArgs& args) : m_args(args) {}
explicit GIOProtoArgs(GProtoArgs &&args) : m_args(std::move(args)) {}
GProtoArgs m_args;
};
struct In_Tag{};
struct Out_Tag{};
using GProtoInputArgs = GIOProtoArgs<In_Tag>;
using GProtoOutputArgs = GIOProtoArgs<Out_Tag>;
// Perfect forwarding
template<typename... Ts> inline GProtoInputArgs GIn(Ts&&... ts)
{
return GProtoInputArgs(detail::packArgs(std::forward<Ts>(ts)...));
}
template<typename... Ts> inline GProtoOutputArgs GOut(Ts&&... ts)
{
return GProtoOutputArgs(detail::packArgs(std::forward<Ts>(ts)...));
}
// Extract run-time arguments from node origin
// Can be used to extract constant values associated with G-objects
// (like GScalar) at graph construction time
GRunArg value_of(const GOrigin &origin);
// Transform run-time computation arguments into a collection of metadata
// extracted from that arguments
GMetaArg GAPI_EXPORTS descr_of(const GRunArg &arg );
GMetaArgs GAPI_EXPORTS descr_of(const GRunArgs &args);
// Transform run-time operation result argument into metadata extracted from that argument
// Used to compare the metadata, which generated at compile time with the metadata result operation in run time
GMetaArg GAPI_EXPORTS descr_of(const GRunArgP& argp);
} // namespace cv
#endif // OPENCV_GAPI_GPROTO_HPP

@ -0,0 +1,68 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GSCALAR_HPP
#define OPENCV_GAPI_GSCALAR_HPP
#include <ostream>
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/gcommon.hpp> // GShape
#include <opencv2/gapi/util/optional.hpp>
#include "opencv2/gapi/own/scalar.hpp"
#include <opencv2/core/types.hpp>
// TODO GAPI_EXPORTS or so
namespace cv
{
// Forward declaration; GNode and GOrigin are an internal
// (user-inaccessible) classes.
class GNode;
struct GOrigin;
class GAPI_EXPORTS GScalar
{
public:
GScalar(); // Empty constructor
explicit GScalar(const cv::gapi::own::Scalar& s); // Constant value constructor from cv::gapi::own::Scalar
explicit GScalar(cv::gapi::own::Scalar&& s); // Constant value move-constructor from cv::gapi::own::Scalar
explicit GScalar(const cv::Scalar& s); // Constant value constructor from cv::Scalar
GScalar(double v0); // Constant value constructor from double
GScalar(const GNode &n, std::size_t out); // Operation result constructor
GOrigin& priv(); // Internal use only
const GOrigin& priv() const; // Internal use only
private:
std::shared_ptr<GOrigin> m_priv;
};
struct GScalarDesc
{
// NB.: right now it is empty
inline bool operator== (const GScalarDesc &) const
{
return true; // NB: implement this method if GScalar meta appears
}
inline bool operator!= (const GScalarDesc &rhs) const
{
return !(*this == rhs);
}
};
static inline GScalarDesc empty_scalar_desc() { return GScalarDesc(); }
GAPI_EXPORTS GScalarDesc descr_of(const cv::gapi::own::Scalar &scalar);
GAPI_EXPORTS GScalarDesc descr_of(const cv::Scalar &scalar);
std::ostream& operator<<(std::ostream& os, const cv::GScalarDesc &desc);
} // namespace cv
#endif // OPENCV_GAPI_GSCALAR_HPP

@ -0,0 +1,150 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GTYPE_TRAITS_HPP
#define OPENCV_GAPI_GTYPE_TRAITS_HPP
#include <vector>
#include <type_traits>
#include <opencv2/gapi/gmat.hpp>
#include <opencv2/gapi/gscalar.hpp>
#include <opencv2/gapi/garray.hpp>
#include <opencv2/gapi/gcommon.hpp>
#include <opencv2/gapi/own/convert.hpp>
namespace cv
{
namespace detail
{
// FIXME: These traits and enum and possible numerous switch(kind)
// block may be replaced with a special Handler<T> object or with
// a double dispatch
enum class ArgKind: int
{
OPAQUE, // Unknown, generic, opaque-to-GAPI data type - STATIC
GOBJREF, // <internal> reference to object
GMAT, // a cv::GMat
GSCALAR, // a cv::GScalar
GARRAY, // a cv::GArrayU (note - exactly GArrayU, not GArray<T>!)
};
// Describe G-API types (G-types) with traits. Mostly used by
// cv::GArg to store meta information about types passed into
// operation arguments. Please note that cv::GComputation is
// defined on GProtoArgs, not GArgs!
template<typename T> struct GTypeTraits;
template<typename T> struct GTypeTraits
{
static constexpr const ArgKind kind = ArgKind::OPAQUE;
};
template<> struct GTypeTraits<cv::GMat>
{
static constexpr const ArgKind kind = ArgKind::GMAT;
static constexpr const GShape shape = GShape::GMAT;
};
template<> struct GTypeTraits<cv::GScalar>
{
static constexpr const ArgKind kind = ArgKind::GSCALAR;
static constexpr const GShape shape = GShape::GSCALAR;
};
template<class T> struct GTypeTraits<cv::GArray<T> >
{
static constexpr const ArgKind kind = ArgKind::GARRAY;
static constexpr const GShape shape = GShape::GARRAY;
using host_type = std::vector<T>;
using strip_type = cv::detail::VectorRef;
static cv::detail::GArrayU wrap_value(const cv::GArray<T> &t) { return t.strip();}
static cv::detail::VectorRef wrap_in (const std::vector<T> &t) { return detail::VectorRef(t); }
static cv::detail::VectorRef wrap_out ( std::vector<T> &t) { return detail::VectorRef(t); }
};
// Tests if Trait for type T requires extra marshalling ("custom wrap") or not.
// If Traits<T> has wrap_value() defined, it does.
template<class T> struct has_custom_wrap
{
template<class,class> class check;
template<typename C> static std::true_type test(check<C, decltype(&GTypeTraits<C>::wrap_value)> *);
template<typename C> static std::false_type test(...);
using type = decltype(test<T>(nullptr));
static const constexpr bool value = std::is_same<std::true_type, decltype(test<T>(nullptr))>::value;
};
// Resolve a Host type back to its associated G-Type.
// FIXME: Probably it can be avoided
template<typename T> struct GTypeOf;
template<> struct GTypeOf<cv::Mat> { using type = cv::GMat; };
template<> struct GTypeOf<cv::gapi::own::Mat> { using type = cv::GMat; };
template<> struct GTypeOf<cv::Scalar> { using type = cv::GScalar; };
template<> struct GTypeOf<cv::gapi::own::Scalar> { using type = cv::GScalar; };
template<typename U> struct GTypeOf<std::vector<U> > { using type = cv::GArray<U>; };
template<class T> using g_type_of_t = typename GTypeOf<T>::type;
// Marshalling helper for G-types and its Host types. Helps G-API
// to store G types in internal generic containers for further
// processing. Implements the following callbacks:
//
// * wrap() - converts user-facing G-type into an internal one
// for internal storage.
// Used when G-API operation is instantiated (G<Kernel>::on(),
// etc) during expressing a pipeline. Mostly returns input
// value "as is" except the case when G-type is a template. For
// template G-classes, calls custom wrap() from Traits.
// The value returned by wrap() is then wrapped into GArg() and
// stored in G-API metadata.
//
// Example:
// - cv::GMat arguments are passed as-is.
// - integers, pointers, STL containers, user types are passed as-is.
// - cv::GArray<T> is converted to cv::GArrayU.
//
// * wrap_in() / wrap_out() - convert Host type associated with
// G-type to internal representation type.
//
// - For "simple" (non-template) G-types, returns value as-is.
// Example: cv::GMat has host type cv::Mat, when user passes a
// cv::Mat, system stores it internally as cv::Mat.
//
// - For "complex" (template) G-types, utilizes custom
// wrap_in()/wrap_out() as described in Traits.
// Example: cv::GArray<T> has host type std::vector<T>, when
// user passes a std::vector<T>, system stores it
// internally as VectorRef (with <T> stripped away).
template<typename T, class Custom = void> struct WrapValue
{
static auto wrap(const T& t) ->
typename std::remove_reference<T>::type
{
return static_cast<typename std::remove_reference<T>::type>(t);
}
template<typename U> static U wrap_in (const U &u) { return u; }
template<typename U> static U* wrap_out(U &u) { return &u; }
};
template<typename T> struct WrapValue<T, typename std::enable_if<has_custom_wrap<T>::value>::type>
{
static auto wrap(const T& t) -> decltype(GTypeTraits<T>::wrap_value(t))
{
return GTypeTraits<T>::wrap_value(t);
}
template<typename U> static auto wrap_in (const U &u) -> typename GTypeTraits<T>::strip_type
{
return GTypeTraits<T>::wrap_in(u);
}
template<typename U> static auto wrap_out(U &u) -> typename GTypeTraits<T>::strip_type
{
return GTypeTraits<T>::wrap_out(u);
}
};
template<typename T> using wrap_gapi_helper = WrapValue<typename std::decay<T>::type>;
template<typename T> using wrap_host_helper = WrapValue<typename std::decay<g_type_of_t<T> >::type>;
} // namespace detail
} // namespace cv
#endif // OPENCV_GAPI_GTYPE_TRAITS_HPP

@ -0,0 +1,186 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GTYPED_HPP
#define OPENCV_GAPI_GTYPED_HPP
#include <vector>
#include "opencv2/gapi/gcomputation.hpp"
#include "opencv2/gapi/gcompiled.hpp"
#include "opencv2/gapi/gproto.hpp"
#include "opencv2/gapi/gcommon.hpp"
namespace cv {
namespace detail
{
// FIXME: How to prevent coolhackers from extending it by their own types?
// FIXME: ...Should we care?
template<typename T> struct ProtoToParam;
template<> struct ProtoToParam<cv::GMat> { using type = cv::Mat; };
template<> struct ProtoToParam<cv::GScalar> { using type = cv::Scalar; };
template<typename U> struct ProtoToParam<cv::GArray<U> > { using type = std::vector<U>; };
template<typename T> using ProtoToParamT = typename ProtoToParam<T>::type;
template<typename T> struct ProtoToMeta;
template<> struct ProtoToMeta<cv::GMat> { using type = cv::GMatDesc; };
template<> struct ProtoToMeta<cv::GScalar> { using type = cv::GScalarDesc; };
template<typename U> struct ProtoToMeta<cv::GArray<U> > { using type = cv::GArrayDesc; };
template<typename T> using ProtoToMetaT = typename ProtoToMeta<T>::type;
//workaround for MSVC 19.0 bug
template <typename T>
auto make_default()->decltype(T{}) {return {};}
}; // detail
template<typename> class GComputationT;
// Single return value implementation
template<typename R, typename... Args> class GComputationT<R(Args...)>
{
public:
typedef std::function<R(Args...)> Gen;
class GCompiledT
{
private:
friend class GComputationT<R(Args...)>;
cv::GCompiled m_comp;
explicit GCompiledT(const cv::GCompiled &comp) : m_comp(comp) {}
public:
GCompiledT() {}
void operator()(detail::ProtoToParamT<Args>... inArgs,
detail::ProtoToParamT<R> &outArg)
{
m_comp(cv::gin(inArgs...), cv::gout(outArg));
}
explicit operator bool() const
{
return static_cast<bool>(m_comp);
}
};
private:
typedef std::pair<R, GProtoInputArgs > Captured;
Captured capture(const Gen& g, Args... args)
{
return Captured(g(args...), cv::GIn(args...));
}
Captured m_capture;
cv::GComputation m_comp;
public:
GComputationT(const Gen &generator)
: m_capture(capture(generator, detail::make_default<Args>()...))
, m_comp(cv::GProtoInputArgs(std::move(m_capture.second)),
cv::GOut(m_capture.first))
{
}
void apply(detail::ProtoToParamT<Args>... inArgs,
detail::ProtoToParamT<R> &outArg)
{
m_comp.apply(cv::gin(inArgs...), cv::gout(outArg));
}
GCompiledT compile(detail::ProtoToMetaT<Args>... inDescs)
{
GMetaArgs inMetas = { GMetaArg(inDescs)... };
return GCompiledT(m_comp.compile(std::move(inMetas), GCompileArgs()));
}
GCompiledT compile(detail::ProtoToMetaT<Args>... inDescs, GCompileArgs &&args)
{
GMetaArgs inMetas = { GMetaArg(inDescs)... };
return GCompiledT(m_comp.compile(std::move(inMetas), std::move(args)));
}
};
// Multiple (fixed) return value implementation. FIXME: How to avoid copy-paste?
template<typename... R, typename... Args> class GComputationT<std::tuple<R...>(Args...)>
{
public:
typedef std::function<std::tuple<R...>(Args...)> Gen;
class GCompiledT
{
private:
friend class GComputationT<std::tuple<R...>(Args...)>;
cv::GCompiled m_comp;
explicit GCompiledT(const cv::GCompiled &comp) : m_comp(comp) {}
public:
GCompiledT() {}
void operator()(detail::ProtoToParamT<Args>... inArgs,
detail::ProtoToParamT<R>&... outArgs)
{
m_comp(cv::gin(inArgs...), cv::gout(outArgs...));
}
explicit operator bool() const
{
return static_cast<bool>(m_comp);
}
};
private:
typedef std::pair<GProtoArgs, GProtoArgs> Captured;
template<int... IIs>
Captured capture(GProtoArgs &&args, const std::tuple<R...> &rr, detail::Seq<IIs...>)
{
return Captured(cv::GOut(std::get<IIs>(rr)...).m_args, args);
}
Captured capture(const Gen& g, Args... args)
{
return capture(cv::GIn(args...).m_args, g(args...), typename detail::MkSeq<sizeof...(R)>::type());
}
Captured m_capture;
cv::GComputation m_comp;
public:
GComputationT(const Gen &generator)
: m_capture(capture(generator, detail::make_default<Args>()...))
, m_comp(cv::GProtoInputArgs(std::move(m_capture.second)),
cv::GProtoOutputArgs(std::move(m_capture.first)))
{
}
void apply(detail::ProtoToParamT<Args>... inArgs,
detail::ProtoToParamT<R>&... outArgs)
{
m_comp.apply(cv::gin(inArgs...), cv::gout(outArgs...));
}
GCompiledT compile(detail::ProtoToMetaT<Args>... inDescs)
{
GMetaArgs inMetas = { GMetaArg(inDescs)... };
return GCompiledT(m_comp.compile(std::move(inMetas), GCompileArgs()));
}
GCompiledT compile(detail::ProtoToMetaT<Args>... inDescs, GCompileArgs &&args)
{
GMetaArgs inMetas = { GMetaArg(inDescs)... };
return GCompiledT(m_comp.compile(std::move(inMetas), std::move(args)));
}
};
} // namespace cv
#endif // OPENCV_GAPI_GTYPED_HPP

@ -0,0 +1,677 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_IMGPROC_HPP
#define OPENCV_GAPI_IMGPROC_HPP
#include "opencv2/imgproc.hpp"
#include <utility> // std::tuple
#include "opencv2/gapi/gkernel.hpp"
#include "opencv2/gapi/gmat.hpp"
#include "opencv2/gapi/gscalar.hpp"
/** \defgroup gapi_imgproc G-API image processing functionality
@{
@defgroup gapi_filters Graph API: Image filters
@defgroup gapi_colorconvert Graph API: Converting image from one color space to another
@}
*/
namespace cv { namespace gapi {
namespace imgproc {
using GMat3 = std::tuple<GMat,GMat,GMat>; // FIXME: how to avoid this?
G_TYPED_KERNEL(GFilter2D, <GMat(GMat,int,Mat,Point,Scalar,int,Scalar)>,"org.opencv.imgproc.filters.filter2D") {
static GMatDesc outMeta(GMatDesc in, int ddepth, Mat, Point, Scalar, int, Scalar) {
return in.withDepth(ddepth);
}
};
G_TYPED_KERNEL(GSepFilter, <GMat(GMat,int,Mat,Mat,Point,Scalar,int,Scalar)>, "org.opencv.imgproc.filters.sepfilter") {
static GMatDesc outMeta(GMatDesc in, int ddepth, Mat, Mat, Point, Scalar, int, Scalar) {
return in.withDepth(ddepth);
}
};
G_TYPED_KERNEL(GBoxFilter, <GMat(GMat,int,Size,Point,bool,int,Scalar)>, "org.opencv.imgproc.filters.boxfilter") {
static GMatDesc outMeta(GMatDesc in, int ddepth, Size, Point, bool, int, Scalar) {
return in.withDepth(ddepth);
}
};
G_TYPED_KERNEL(GBlur, <GMat(GMat,Size,Point,int,Scalar)>, "org.opencv.imgproc.filters.blur"){
static GMatDesc outMeta(GMatDesc in, Size, Point, int, Scalar) {
return in;
}
};
G_TYPED_KERNEL(GGaussBlur, <GMat(GMat,Size,double,double,int,Scalar)>, "org.opencv.imgproc.filters.gaussianBlur") {
static GMatDesc outMeta(GMatDesc in, Size, double, double, int, Scalar) {
return in;
}
};
G_TYPED_KERNEL(GMedianBlur, <GMat(GMat,int)>, "org.opencv.imgproc.filters.medianBlur") {
static GMatDesc outMeta(GMatDesc in, int) {
return in;
}
};
G_TYPED_KERNEL(GErode, <GMat(GMat,Mat,Point,int,int,Scalar)>, "org.opencv.imgproc.filters.erode") {
static GMatDesc outMeta(GMatDesc in, Mat, Point, int, int, Scalar) {
return in;
}
};
G_TYPED_KERNEL(GDilate, <GMat(GMat,Mat,Point,int,int,Scalar)>, "org.opencv.imgproc.filters.dilate") {
static GMatDesc outMeta(GMatDesc in, Mat, Point, int, int, Scalar) {
return in;
}
};
G_TYPED_KERNEL(GSobel, <GMat(GMat,int,int,int,int,double,double,int,Scalar)>, "org.opencv.imgproc.filters.sobel") {
static GMatDesc outMeta(GMatDesc in, int ddepth, int, int, int, double, double, int, Scalar) {
return in.withDepth(ddepth);
}
};
G_TYPED_KERNEL(GEqHist, <GMat(GMat)>, "org.opencv.imgproc.equalizeHist"){
static GMatDesc outMeta(GMatDesc in) {
return in.withType(CV_8U, 1);
}
};
G_TYPED_KERNEL(GCanny, <GMat(GMat,double,double,int,bool)>, "org.opencv.imgproc.canny"){
static GMatDesc outMeta(GMatDesc in, double, double, int, bool) {
return in.withType(CV_8U, 1);
}
};
G_TYPED_KERNEL(GRGB2YUV, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.rgb2yuv") {
static GMatDesc outMeta(GMatDesc in) {
return in; // type still remains CV_8UC3;
}
};
G_TYPED_KERNEL(GYUV2RGB, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.yuv2rgb") {
static GMatDesc outMeta(GMatDesc in) {
return in; // type still remains CV_8UC3;
}
};
G_TYPED_KERNEL(GRGB2Lab, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.rgb2lab") {
static GMatDesc outMeta(GMatDesc in) {
return in; // type still remains CV_8UC3;
}
};
G_TYPED_KERNEL(GBGR2LUV, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.bgr2luv") {
static GMatDesc outMeta(GMatDesc in) {
return in; // type still remains CV_8UC3;
}
};
G_TYPED_KERNEL(GLUV2BGR, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.luv2bgr") {
static GMatDesc outMeta(GMatDesc in) {
return in; // type still remains CV_8UC3;
}
};
G_TYPED_KERNEL(GYUV2BGR, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.yuv2bgr") {
static GMatDesc outMeta(GMatDesc in) {
return in; // type still remains CV_8UC3;
}
};
G_TYPED_KERNEL(GBGR2YUV, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.bgr2yuv") {
static GMatDesc outMeta(GMatDesc in) {
return in; // type still remains CV_8UC3;
}
};
G_TYPED_KERNEL(GRGB2Gray, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.rgb2gray") {
static GMatDesc outMeta(GMatDesc in) {
return in.withType(CV_8U, 1);
}
};
G_TYPED_KERNEL(GRGB2GrayCustom, <GMat(GMat,float,float,float)>, "org.opencv.imgproc.colorconvert.rgb2graycustom") {
static GMatDesc outMeta(GMatDesc in, float, float, float) {
return in.withType(CV_8U, 1);
}
};
G_TYPED_KERNEL(GBGR2Gray, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.bgr2gray") {
static GMatDesc outMeta(GMatDesc in) {
return in.withType(CV_8U, 1);
}
};
}
//! @addtogroup gapi_filters
//! @{
/** @brief Applies a separable linear filter to a matrix(image).
The function applies a separable linear filter to the matrix. That is, first, every row of src is
filtered with the 1D kernel kernelX. Then, every column of the result is filtered with the 1D
kernel kernelY. The final result is returned.
Supported matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, @ref CV_32FC1.
Output image must have the same type, size, and number of channels as the input image.
@note In case of floating-point computation, rounding to nearest even is procedeed
if hardware supports it (if not - to nearest value).
@note Function textual ID is "org.opencv.imgproc.filters.sepfilter"
@param src Source image.
@param ddepth desired depth of the destination image (the following combinations of src.depth() and ddepth are supported:
src.depth() = CV_8U, ddepth = -1/CV_16S/CV_32F/CV_64F
src.depth() = CV_16U/CV_16S, ddepth = -1/CV_32F/CV_64F
src.depth() = CV_32F, ddepth = -1/CV_32F/CV_64F
src.depth() = CV_64F, ddepth = -1/CV_64F
when ddepth=-1, the output image will have the same depth as the source)
@param kernelX Coefficients for filtering each row.
@param kernelY Coefficients for filtering each column.
@param anchor Anchor position within the kernel. The default value \f$(-1,-1)\f$ means that the anchor
is at the kernel center.
@param delta Value added to the filtered results before storing them.
@param borderType Pixel extrapolation method, see cv::BorderTypes
@param borderValue border value in case of constant border type
@sa boxFilter, gaussianBlur, medianBlur
*/
GAPI_EXPORTS GMat sepFilter(const GMat& src, int ddepth, const Mat& kernelX, const Mat& kernelY, const Point& anchor /*FIXME: = Point(-1,-1)*/,
const Scalar& delta /*FIXME = GScalar(0)*/, int borderType = BORDER_DEFAULT,
const Scalar& borderValue = Scalar(0));
/** @brief Convolves an image with the kernel.
The function applies an arbitrary linear filter to an image. When
the aperture is partially outside the image, the function interpolates outlier pixel values
according to the specified border mode.
The function does actually compute correlation, not the convolution:
\f[\texttt{dst} (x,y) = \sum _{ \stackrel{0\leq x' < \texttt{kernel.cols},}{0\leq y' < \texttt{kernel.rows}} } \texttt{kernel} (x',y')* \texttt{src} (x+x'- \texttt{anchor.x} ,y+y'- \texttt{anchor.y} )\f]
That is, the kernel is not mirrored around the anchor point. If you need a real convolution, flip
the kernel using flip and set the new anchor to `(kernel.cols - anchor.x - 1, kernel.rows -
anchor.y - 1)`.
Supported matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, @ref CV_32FC1.
Output image must have the same size and number of channels an input image.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note Function textual ID is "org.opencv.imgproc.filters.filter2D"
@param src input image.
@param ddepth desired depth of the destination image
@param kernel convolution kernel (or rather a correlation kernel), a single-channel floating point
matrix; if you want to apply different kernels to different channels, split the image into
separate color planes using split and process them individually.
@param anchor anchor of the kernel that indicates the relative position of a filtered point within
the kernel; the anchor should lie within the kernel; default value (-1,-1) means that the anchor
is at the kernel center.
@param delta optional value added to the filtered pixels before storing them in dst.
@param borderType pixel extrapolation method, see cv::BorderTypes
@param borderValue border value in case of constant border type
@sa sepFilter
*/
GAPI_EXPORTS GMat filter2D(const GMat& src, int ddepth, const Mat& kernel, const Point& anchor = Point(-1,-1), const Scalar& delta = Scalar(0),
int borderType = BORDER_DEFAULT, const Scalar& borderValue = Scalar(0));
/** @brief Blurs an image using the box filter.
The function smooths an image using the kernel:
\f[\texttt{K} = \alpha \begin{bmatrix} 1 & 1 & 1 & \cdots & 1 & 1 \\ 1 & 1 & 1 & \cdots & 1 & 1 \\ \hdotsfor{6} \\ 1 & 1 & 1 & \cdots & 1 & 1 \end{bmatrix}\f]
where
\f[\alpha = \fork{\frac{1}{\texttt{ksize.width*ksize.height}}}{when \texttt{normalize=true}}{1}{otherwise}\f]
Unnormalized box filter is useful for computing various integral characteristics over each pixel
neighborhood, such as covariance matrices of image derivatives (used in dense optical flow
algorithms, and so on). If you need to compute pixel sums over variable-size windows, use cv::integral.
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, @ref CV_32FC1.
Output image must have the same type, size, and number of channels as the input image.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note Function textual ID is "org.opencv.imgproc.filters.boxfilter"
@param src Source image.
@param dtype the output image depth (-1 to set the input image data type).
@param ksize blurring kernel size.
@param anchor Anchor position within the kernel. The default value \f$(-1,-1)\f$ means that the anchor
is at the kernel center.
@param normalize flag, specifying whether the kernel is normalized by its area or not.
@param borderType Pixel extrapolation method, see cv::BorderTypes
@param borderValue border value in case of constant border type
@sa sepFilter, gaussianBlur, medianBlur, integral
*/
GAPI_EXPORTS GMat boxFilter(const GMat& src, int dtype, const Size& ksize, const Point& anchor = Point(-1,-1),
bool normalize = true, int borderType = BORDER_DEFAULT,
const Scalar& borderValue = Scalar(0));
/** @brief Blurs an image using the normalized box filter.
The function smooths an image using the kernel:
\f[\texttt{K} = \frac{1}{\texttt{ksize.width*ksize.height}} \begin{bmatrix} 1 & 1 & 1 & \cdots & 1 & 1 \\ 1 & 1 & 1 & \cdots & 1 & 1 \\ \hdotsfor{6} \\ 1 & 1 & 1 & \cdots & 1 & 1 \\ \end{bmatrix}\f]
The call `blur(src, dst, ksize, anchor, borderType)` is equivalent to `boxFilter(src, dst, src.type(),
anchor, true, borderType)`.
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, @ref CV_32FC1.
Output image must have the same type, size, and number of channels as the input image.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note Function textual ID is "org.opencv.imgproc.filters.blur"
@param src Source image.
@param ksize blurring kernel size.
@param anchor anchor point; default value Point(-1,-1) means that the anchor is at the kernel
center.
@param borderType border mode used to extrapolate pixels outside of the image, see cv::BorderTypes
@param borderValue border value in case of constant border type
@sa boxFilter, bilateralFilter, GaussianBlur, medianBlur
*/
GAPI_EXPORTS GMat blur(const GMat& src, const Size& ksize, const Point& anchor = Point(-1,-1),
int borderType = BORDER_DEFAULT, const Scalar& borderValue = Scalar(0));
//GAPI_EXPORTS_W void blur( InputArray src, OutputArray dst,
// Size ksize, Point anchor = Point(-1,-1),
// int borderType = BORDER_DEFAULT );
/** @brief Blurs an image using a Gaussian filter.
The function filter2Ds the source image with the specified Gaussian kernel.
Output image must have the same type and number of channels an input image.
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, @ref CV_32FC1.
Output image must have the same type, size, and number of channels as the input image.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note Function textual ID is "org.opencv.imgproc.filters.gaussianBlur"
@param src input image;
@param ksize Gaussian kernel size. ksize.width and ksize.height can differ but they both must be
positive and odd. Or, they can be zero's and then they are computed from sigma.
@param sigmaX Gaussian kernel standard deviation in X direction.
@param sigmaY Gaussian kernel standard deviation in Y direction; if sigmaY is zero, it is set to be
equal to sigmaX, if both sigmas are zeros, they are computed from ksize.width and ksize.height,
respectively (see cv::getGaussianKernel for details); to fully control the result regardless of
possible future modifications of all this semantics, it is recommended to specify all of ksize,
sigmaX, and sigmaY.
@param borderType pixel extrapolation method, see cv::BorderTypes
@param borderValue border value in case of constant border type
@sa sepFilter, boxFilter, medianBlur
*/
GAPI_EXPORTS GMat gaussianBlur(const GMat& src, const Size& ksize, double sigmaX, double sigmaY = 0,
int borderType = BORDER_DEFAULT, const Scalar& borderValue = Scalar(0));
/** @brief Blurs an image using the median filter.
The function smoothes an image using the median filter with the \f$\texttt{ksize} \times
\texttt{ksize}\f$ aperture. Each channel of a multi-channel image is processed independently.
Output image must have the same type, size, and number of channels as the input image.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
The median filter uses cv::BORDER_REPLICATE internally to cope with border pixels, see cv::BorderTypes
@note Function textual ID is "org.opencv.imgproc.filters.medianBlur"
@param src input matrix (image)
@param ksize aperture linear size; it must be odd and greater than 1, for example: 3, 5, 7 ...
@sa boxFilter, gaussianBlur
*/
GAPI_EXPORTS GMat medianBlur(const GMat& src, int ksize);
/** @brief Erodes an image by using a specific structuring element.
The function erodes the source image using the specified structuring element that determines the
shape of a pixel neighborhood over which the minimum is taken:
\f[\texttt{dst} (x,y) = \min _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f]
Erosion can be applied several (iterations) times. In case of multi-channel images, each channel is processed independently.
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, and @ref CV_32FC1.
Output image must have the same type, size, and number of channels as the input image.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note Function textual ID is "org.opencv.imgproc.filters.erode"
@param src input image
@param kernel structuring element used for erosion; if `element=Mat()`, a `3 x 3` rectangular
structuring element is used. Kernel can be created using getStructuringElement.
@param anchor position of the anchor within the element; default value (-1, -1) means that the
anchor is at the element center.
@param iterations number of times erosion is applied.
@param borderType pixel extrapolation method, see cv::BorderTypes
@param borderValue border value in case of a constant border
@sa dilate
*/
GAPI_EXPORTS GMat erode(const GMat& src, const Mat& kernel, const Point& anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue());
/** @brief Erodes an image by using 3 by 3 rectangular structuring element.
The function erodes the source image using the rectangular structuring element with rectangle center as an anchor.
Erosion can be applied several (iterations) times. In case of multi-channel images, each channel is processed independently.
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, and @ref CV_32FC1.
Output image must have the same type, size, and number of channels as the input image.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@param src input image
@param iterations number of times erosion is applied.
@param borderType pixel extrapolation method, see cv::BorderTypes
@param borderValue border value in case of a constant border
@sa erode, dilate3x3
*/
GAPI_EXPORTS GMat erode3x3(const GMat& src, int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue());
/** @brief Dilates an image by using a specific structuring element.
The function dilates the source image using the specified structuring element that determines the
shape of a pixel neighborhood over which the maximum is taken:
\f[\texttt{dst} (x,y) = \max _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f]
Dilation can be applied several (iterations) times. In case of multi-channel images, each channel is processed independently.
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, and @ref CV_32FC1.
Output image must have the same type, size, and number of channels as the input image.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note Function textual ID is "org.opencv.imgproc.filters.dilate"
@param src input image.
@param kernel structuring element used for dilation; if elemenat=Mat(), a 3 x 3 rectangular
structuring element is used. Kernel can be created using getStructuringElement
@param anchor position of the anchor within the element; default value (-1, -1) means that the
anchor is at the element center.
@param iterations number of times dilation is applied.
@param borderType pixel extrapolation method, see cv::BorderTypes
@param borderValue border value in case of a constant border
@sa erode, morphologyEx, getStructuringElement
*/
GAPI_EXPORTS GMat dilate(const GMat& src, const Mat& kernel, const Point& anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue());
/** @brief Dilates an image by using 3 by 3 rectangular structuring element.
The function dilates the source image using the specified structuring element that determines the
shape of a pixel neighborhood over which the maximum is taken:
\f[\texttt{dst} (x,y) = \max _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f]
Dilation can be applied several (iterations) times. In case of multi-channel images, each channel is processed independently.
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, and @ref CV_32FC1.
Output image must have the same type, size, and number of channels as the input image.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note Function textual ID is "org.opencv.imgproc.filters.dilate"
@param src input image.
@param iterations number of times dilation is applied.
@param borderType pixel extrapolation method, see cv::BorderTypes
@param borderValue border value in case of a constant border
@sa dilate, erode3x3
*/
GAPI_EXPORTS GMat dilate3x3(const GMat& src, int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue());
/** @brief Calculates the first, second, third, or mixed image derivatives using an extended Sobel operator.
In all cases except one, the \f$\texttt{ksize} \times \texttt{ksize}\f$ separable kernel is used to
calculate the derivative. When \f$\texttt{ksize = 1}\f$, the \f$3 \times 1\f$ or \f$1 \times 3\f$
kernel is used (that is, no Gaussian smoothing is done). `ksize = 1` can only be used for the first
or the second x- or y- derivatives.
There is also the special value `ksize = CV_SCHARR (-1)` that corresponds to the \f$3\times3\f$ Scharr
filter that may give more accurate results than the \f$3\times3\f$ Sobel. The Scharr aperture is
\f[\vecthreethree{-3}{0}{3}{-10}{0}{10}{-3}{0}{3}\f]
for the x-derivative, or transposed for the y-derivative.
The function calculates an image derivative by convolving the image with the appropriate kernel:
\f[\texttt{dst} = \frac{\partial^{xorder+yorder} \texttt{src}}{\partial x^{xorder} \partial y^{yorder}}\f]
The Sobel operators combine Gaussian smoothing and differentiation, so the result is more or less
resistant to the noise. Most often, the function is called with ( xorder = 1, yorder = 0, ksize = 3)
or ( xorder = 0, yorder = 1, ksize = 3) to calculate the first x- or y- image derivative. The first
case corresponds to a kernel of:
\f[\vecthreethree{-1}{0}{1}{-2}{0}{2}{-1}{0}{1}\f]
The second case corresponds to a kernel of:
\f[\vecthreethree{-1}{-2}{-1}{0}{0}{0}{1}{2}{1}\f]
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note Function textual ID is "org.opencv.imgproc.filters.sobel"
@param src input image.
@param ddepth output image depth, see @ref filter_depths "combinations"; in the case of
8-bit input images it will result in truncated derivatives.
@param dx order of the derivative x.
@param dy order of the derivative y.
@param ksize size of the extended Sobel kernel; it must be odd.
@param scale optional scale factor for the computed derivative values; by default, no scaling is
applied (see cv::getDerivKernels for details).
@param delta optional delta value that is added to the results prior to storing them in dst.
@param borderType pixel extrapolation method, see cv::BorderTypes
@param borderValue border value in case of constant border type
@sa filter2D, gaussianBlur, cartToPolar
*/
GAPI_EXPORTS GMat sobel(const GMat& src, int ddepth, int dx, int dy, int ksize = 3,
double scale = 1, double delta = 0,
int borderType = BORDER_DEFAULT,
const Scalar& borderValue = Scalar(0));
/** @brief Finds edges in an image using the Canny algorithm.
The function finds edges in the input image and marks them in the output map edges using the
Canny algorithm. The smallest value between threshold1 and threshold2 is used for edge linking. The
largest value is used to find initial segments of strong edges. See
<http://en.wikipedia.org/wiki/Canny_edge_detector>
@note Function textual ID is "org.opencv.imgproc.filters.canny"
@param image 8-bit input image.
@param threshold1 first threshold for the hysteresis procedure.
@param threshold2 second threshold for the hysteresis procedure.
@param apertureSize aperture size for the Sobel operator.
@param L2gradient a flag, indicating whether a more accurate \f$L_2\f$ norm
\f$=\sqrt{(dI/dx)^2 + (dI/dy)^2}\f$ should be used to calculate the image gradient magnitude (
L2gradient=true ), or whether the default \f$L_1\f$ norm \f$=|dI/dx|+|dI/dy|\f$ is enough (
L2gradient=false ).
*/
GAPI_EXPORTS GMat Canny(const GMat& image, double threshold1, double threshold2,
int apertureSize = 3, bool L2gradient = false);
/** @brief Equalizes the histogram of a grayscale image.
The function equalizes the histogram of the input image using the following algorithm:
- Calculate the histogram \f$H\f$ for src .
- Normalize the histogram so that the sum of histogram bins is 255.
- Compute the integral of the histogram:
\f[H'_i = \sum _{0 \le j < i} H(j)\f]
- Transform the image using \f$H'\f$ as a look-up table: \f$\texttt{dst}(x,y) = H'(\texttt{src}(x,y))\f$
The algorithm normalizes the brightness and increases the contrast of the image.
@note The returned image is of the same size and type as input.
@note Function textual ID is "org.opencv.imgproc.equalizeHist"
@param src Source 8-bit single channel image.
*/
GAPI_EXPORTS GMat equalizeHist(const GMat& src);
//! @} gapi_filters
//! @addtogroup gapi_colorconvert
//! @{
/** @brief Converts an image from RGB color space to gray-scaled.
The conventional ranges for R, G, and B channel values are 0 to 255.
Resulting gray color value computed as
\f[\texttt{dst} (I)= \texttt{0.299} * \texttt{src}(I).R + \texttt{0.587} * \texttt{src}(I).G + \texttt{0.114} * \texttt{src}(I).B \f]
@note Function textual ID is "org.opencv.imgproc.colorconvert.rgb2gray"
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC1.
@sa RGB2YUV
*/
GAPI_EXPORTS GMat RGB2Gray(const GMat& src);
/** @overload
Resulting gray color value computed as
\f[\texttt{dst} (I)= \texttt{rY} * \texttt{src}(I).R + \texttt{gY} * \texttt{src}(I).G + \texttt{bY} * \texttt{src}(I).B \f]
@note Function textual ID is "org.opencv.imgproc.colorconvert.rgb2graycustom"
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC1.
@param rY float multiplier for R channel.
@param gY float multiplier for G channel.
@param bY float multiplier for B channel.
@sa RGB2YUV
*/
GAPI_EXPORTS GMat RGB2Gray(const GMat& src, float rY, float gY, float bY);
/** @brief Converts an image from BGR color space to gray-scaled.
The conventional ranges for B, G, and R channel values are 0 to 255.
Resulting gray color value computed as
\f[\texttt{dst} (I)= \texttt{0.114} * \texttt{src}(I).B + \texttt{0.587} * \texttt{src}(I).G + \texttt{0.299} * \texttt{src}(I).R \f]
@note Function textual ID is "org.opencv.imgproc.colorconvert.bgr2gray"
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC1.
@sa BGR2LUV
*/
GAPI_EXPORTS GMat BGR2Gray(const GMat& src);
/** @brief Converts an image from RGB color space to YUV color space.
The function converts an input image from RGB color space to YUV.
The conventional ranges for R, G, and B channel values are 0 to 255.
In case of linear transformations, the range does not matter. But in case of a non-linear
transformation, an input RGB image should be normalized to the proper value range to get the correct
results, like here, at RGB \f$\rightarrow\f$ Y\*u\*v\* transformation.
Output image must be 8-bit unsigned 3-channel image @ref CV_8UC3.
@note Function textual ID is "org.opencv.imgproc.colorconvert.rgb2yuv"
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3.
@sa YUV2RGB, RGB2Lab
*/
GAPI_EXPORTS GMat RGB2YUV(const GMat& src);
/** @brief Converts an image from BGR color space to LUV color space.
The function converts an input image from BGR color space to LUV.
The conventional ranges for B, G, and R channel values are 0 to 255.
Output image must be 8-bit unsigned 3-channel image @ref CV_8UC3.
@note Function textual ID is "org.opencv.imgproc.colorconvert.bgr2luv"
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3.
@sa RGB2Lab, RGB2LUV
*/
GAPI_EXPORTS GMat BGR2LUV(const GMat& src);
/** @brief Converts an image from LUV color space to BGR color space.
The function converts an input image from LUV color space to BGR.
The conventional ranges for B, G, and R channel values are 0 to 255.
Output image must be 8-bit unsigned 3-channel image @ref CV_8UC3.
@note Function textual ID is "org.opencv.imgproc.colorconvert.luv2bgr"
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3.
@sa BGR2LUV
*/
GAPI_EXPORTS GMat LUV2BGR(const GMat& src);
/** @brief Converts an image from YUV color space to BGR color space.
The function converts an input image from YUV color space to BGR.
The conventional ranges for B, G, and R channel values are 0 to 255.
Output image must be 8-bit unsigned 3-channel image @ref CV_8UC3.
@note Function textual ID is "org.opencv.imgproc.colorconvert.yuv2bgr"
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3.
@sa BGR2YUV
*/
GAPI_EXPORTS GMat YUV2BGR(const GMat& src);
/** @brief Converts an image from BGR color space to YUV color space.
The function converts an input image from BGR color space to YUV.
The conventional ranges for B, G, and R channel values are 0 to 255.
Output image must be 8-bit unsigned 3-channel image @ref CV_8UC3.
@note Function textual ID is "org.opencv.imgproc.colorconvert.bgr2yuv"
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3.
@sa YUV2BGR
*/
GAPI_EXPORTS GMat BGR2YUV(const GMat& src);
/** @brief Converts an image from RGB color space to Lab color space.
The function converts an input image from BGR color space to Lab.
The conventional ranges for R, G, and B channel values are 0 to 255.
Output image must be 8-bit unsigned 3-channel image @ref CV_8UC1.
@note Function textual ID is "org.opencv.imgproc.colorconvert.rgb2lab"
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC1.
@sa RGB2YUV, RGB2LUV
*/
GAPI_EXPORTS GMat RGB2Lab(const GMat& src);
/** @brief Converts an image from YUV color space to RGB.
The function converts an input image from YUV color space to RGB.
The conventional ranges for Y, U, and V channel values are 0 to 255.
Output image must be 8-bit unsigned 3-channel image @ref CV_8UC3.
@note Function textual ID is "org.opencv.imgproc.colorconvert.yuv2rgb"
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3.
@sa RGB2Lab, RGB2YUV
*/
GAPI_EXPORTS GMat YUV2RGB(const GMat& src);
//! @} gapi_colorconvert
} //namespace gapi
} //namespace cv
#endif // OPENCV_GAPI_IMGPROC_HPP

@ -0,0 +1,16 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_OPENCV_INCLUDES_HPP
#define OPENCV_GAPI_OPENCV_INCLUDES_HPP
#include <opencv2/core/mat.hpp>
#include <opencv2/core/cvdef.h>
#include <opencv2/core/types.hpp>
#include <opencv2/core/base.hpp>
#endif // OPENCV_GAPI_OPENCV_INCLUDES_HPP

@ -0,0 +1,69 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_OPERATORS_HPP
#define OPENCV_GAPI_OPERATORS_HPP
#include "opencv2/gapi/gmat.hpp"
#include "opencv2/gapi/gscalar.hpp"
GAPI_EXPORTS cv::GMat operator+(const cv::GMat& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator+(const cv::GMat& lhs, const cv::GScalar& rhs);
GAPI_EXPORTS cv::GMat operator+(const cv::GScalar& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator-(const cv::GMat& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator-(const cv::GMat& lhs, const cv::GScalar& rhs);
GAPI_EXPORTS cv::GMat operator-(const cv::GScalar& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator*(const cv::GMat& lhs, float rhs);
GAPI_EXPORTS cv::GMat operator*(float lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator*(const cv::GMat& lhs, const cv::GScalar& rhs);
GAPI_EXPORTS cv::GMat operator*(const cv::GScalar& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator/(const cv::GMat& lhs, const cv::GScalar& rhs);
GAPI_EXPORTS cv::GMat operator/(const cv::GScalar& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator/(const cv::GMat& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator&(const cv::GMat& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator|(const cv::GMat& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator^(const cv::GMat& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator~(const cv::GMat& lhs);
GAPI_EXPORTS cv::GMat operator&(const cv::GScalar& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator|(const cv::GScalar& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator^(const cv::GScalar& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator&(const cv::GMat& lhs, const cv::GScalar& rhs);
GAPI_EXPORTS cv::GMat operator|(const cv::GMat& lhs, const cv::GScalar& rhs);
GAPI_EXPORTS cv::GMat operator^(const cv::GMat& lhs, const cv::GScalar& rhs);
GAPI_EXPORTS cv::GMat operator>(const cv::GMat& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator>=(const cv::GMat& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator<(const cv::GMat& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator<=(const cv::GMat& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator==(const cv::GMat& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator!=(const cv::GMat& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator>(const cv::GMat& lhs, const cv::GScalar& rhs);
GAPI_EXPORTS cv::GMat operator>=(const cv::GMat& lhs, const cv::GScalar& rhs);
GAPI_EXPORTS cv::GMat operator<(const cv::GMat& lhs, const cv::GScalar& rhs);
GAPI_EXPORTS cv::GMat operator<=(const cv::GMat& lhs, const cv::GScalar& rhs);
GAPI_EXPORTS cv::GMat operator==(const cv::GMat& lhs, const cv::GScalar& rhs);
GAPI_EXPORTS cv::GMat operator!=(const cv::GMat& lhs, const cv::GScalar& rhs);
GAPI_EXPORTS cv::GMat operator>(const cv::GScalar& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator>=(const cv::GScalar& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator<(const cv::GScalar& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator<=(const cv::GScalar& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator==(const cv::GScalar& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator!=(const cv::GScalar& lhs, const cv::GMat& rhs);
#endif // OPENCV_GAPI_OPERATORS_HPP

@ -0,0 +1,41 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_OWN_ASSERT_HPP
#define OPENCV_GAPI_OWN_ASSERT_HPP
#if 0
#include <opencv2/core/base.hpp>
#define GAPI_Assert(expr) CV_Assert(expr)
#else
#include <stdexcept>
#include <sstream>
#include "opencv2/gapi/util/throw.hpp"
namespace detail
{
inline void assert_abort(const char* str, int line, const char* file, const char* func)
{
std::stringstream ss;
ss << file << ":" << line << ": Assertion " << str << " in function " << func << " failed\n";
cv::util::throw_error(std::logic_error(ss.str()));
}
}
#define GAPI_Assert(expr) \
{ if (!(expr)) ::detail::assert_abort(#expr, __LINE__, __FILE__, __func__); }
#endif
#ifdef _DEBUG
# define GAPI_DbgAssert(expr) GAPI_Assert(expr)
#else
# define GAPI_DbgAssert(expr)
#endif
#endif // OPENCV_GAPI_OWN_ASSERT_HPP

@ -0,0 +1,47 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_OWN_CONVERT_HPP
#define OPENCV_GAPI_OWN_CONVERT_HPP
#include <opencv2/core/types.hpp>
#include <opencv2/core/mat.hpp>
#include <opencv2/gapi/own/types.hpp>
#include <opencv2/gapi/own/mat.hpp>
#include "opencv2/gapi/own/scalar.hpp"
namespace cv
{
inline cv::gapi::own::Mat to_own(Mat const& m) { return {m.rows, m.cols, m.type(), m.data, m.step};};
cv::gapi::own::Mat to_own(Mat&&) = delete;
inline cv::gapi::own::Scalar to_own(const cv::Scalar& s) { return {s[0], s[1], s[2], s[3]}; };
inline cv::gapi::own::Size to_own (const Size& s) { return {s.width, s.height}; };
inline cv::gapi::own::Rect to_own (const Rect& r) { return {r.x, r.y, r.width, r.height}; };
namespace gapi
{
namespace own
{
inline cv::Mat to_ocv(Mat const& m) { return {m.rows, m.cols, m.type(), m.data, m.step};};
cv::Mat to_ocv(Mat&&) = delete;
inline cv::Scalar to_ocv(const Scalar& s) { return {s[0], s[1], s[2], s[3]}; };
inline cv::Size to_ocv (const Size& s) { return cv::Size(s.width, s.height); };
inline cv::Rect to_ocv (const Rect& r) { return cv::Rect(r.x, r.y, r.width, r.height); };
} // namespace own
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_OWN_CONVERT_HPP

@ -0,0 +1,28 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_OWN_TYPES_HPP
#define OPENCV_GAPI_OWN_TYPES_HPP
# if 0
# include <opencv2/core/base.hpp>
# define GAPI_EXPORTS CV_EXPORTS
# else
# if defined _WIN32
# define GAPI_EXPORTS __declspec(dllexport)
# elif defined __GNUC__ && __GNUC__ >= 4
# define GAPI_EXPORTS __attribute__ ((visibility ("default")))
# endif
# ifndef GAPI_EXPORTS
# define GAPI_EXPORTS
# endif
# endif
#endif // OPENCV_GAPI_OWN_TYPES_HPP

@ -0,0 +1,142 @@
// 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) 2018 Intel Corporation
#ifndef INCLUDE_OPENCV2_GAPI_OWN_MAT_HPP
#define INCLUDE_OPENCV2_GAPI_OWN_MAT_HPP
#include "opencv2/core/cvdef.h"
#include "opencv2/gapi/own/types.hpp"
#include <memory> //std::shared_ptr
namespace cv { namespace gapi { namespace own {
namespace detail {
inline size_t default_step(int type, int cols)
{
return CV_ELEM_SIZE(type) * cols;
}
//Matrix header, i.e. fields that are unique to each Mat object.
//Devoted class is needed to implement custom behavior on move (erasing state of moved from object)
struct MatHeader{
enum { AUTO_STEP = 0};
enum { TYPE_MASK = 0x00000FFF };
MatHeader() = default;
MatHeader(int _rows, int _cols, int type, void* _data, size_t _step)
: flags((type & TYPE_MASK)), rows(_rows), cols(_cols), data((uchar*)_data), step(_step == AUTO_STEP ? detail::default_step(type, _cols) : _step)
{}
MatHeader(const MatHeader& ) = default;
MatHeader(MatHeader&& src) : MatHeader(src) // reuse copy constructor here
{
MatHeader empty; //give it a name to call copy(not move) assignment below
src = empty;
}
MatHeader& operator=(const MatHeader& ) = default;
MatHeader& operator=(MatHeader&& src)
{
*this = src; //calling a copy assignment here, not move one
MatHeader empty; //give it a name to call copy(not move) assignment below
src = empty;
return *this;
}
/*! includes several bit-fields:
- depth
- number of channels
*/
int flags = 0;
//! the number of rows and columns or (-1, -1) when the matrix has more than 2 dimensions
int rows = 0, cols = 0;
//! pointer to the data
uchar* data = nullptr;
size_t step = 0;
};
}
//concise version of cv::Mat suitable for GAPI needs (used when no dependence on OpenCV is required)
class Mat : public detail::MatHeader{
public:
Mat() = default;
/** @overload
@param _rows Number of rows in a 2D array.
@param _cols Number of columns in a 2D array.
@param _type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or
CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices.
@param _data Pointer to the user data. Matrix constructors that take data and step parameters do not
allocate matrix data. Instead, they just initialize the matrix header that points to the specified
data, which means that no data is copied. This operation is very efficient and can be used to
process external data using OpenCV functions. The external data is not automatically deallocated, so
you should take care of it.
@param _step Number of bytes each matrix row occupies. The value should include the padding bytes at
the end of each row, if any. If the parameter is missing (set to AUTO_STEP ), no padding is assumed
and the actual step is calculated as cols*elemSize(). See Mat::elemSize.
*/
Mat(int _rows, int _cols, int _type, void* _data, size_t _step = AUTO_STEP)
: MatHeader (_rows, _cols, _type, _data, _step)
{}
Mat(Mat const& src) = default;
Mat(Mat&& src) = default;
Mat& operator=(Mat const& src) = default;
Mat& operator=(Mat&& src) = default;
/** @brief Returns the type of a matrix element.
The method returns a matrix element type. This is an identifier compatible with the CvMat type
system, like CV_16SC3 or 16-bit signed 3-channel array, and so on.
*/
int type() const {return CV_MAT_TYPE(flags);}
/** @brief Returns the depth of a matrix element.
The method returns the identifier of the matrix element depth (the type of each individual channel).
For example, for a 16-bit signed element array, the method returns CV_16S . A complete list of
matrix types contains the following values:
- CV_8U - 8-bit unsigned integers ( 0..255 )
- CV_8S - 8-bit signed integers ( -128..127 )
- CV_16U - 16-bit unsigned integers ( 0..65535 )
- CV_16S - 16-bit signed integers ( -32768..32767 )
- CV_32S - 32-bit signed integers ( -2147483648..2147483647 )
- CV_32F - 32-bit floating-point numbers ( -FLT_MAX..FLT_MAX, INF, NAN )
- CV_64F - 64-bit floating-point numbers ( -DBL_MAX..DBL_MAX, INF, NAN )
*/
int depth() const {return CV_MAT_DEPTH(flags);}
/** @brief Returns the number of matrix channels.
The method returns the number of matrix channels.
*/
int channels() const {return CV_MAT_CN(flags);}
/** @overload
@param _size Alternative new matrix size specification: Size(cols, rows)
@param _type New matrix type.
*/
void create(cv::gapi::own::Size _size, int _type)
{
if (_size != cv::gapi::own::Size{cols, rows} )
{
Mat tmp{_size.height, _size.width, _type, nullptr};
tmp.memory.reset(new uchar[ tmp.step * tmp.rows], [](uchar * p){delete[] p;});
tmp.data = tmp.memory.get();
*this = std::move(tmp);
}
}
private:
//actual memory allocated for storage, or nullptr if object is non owning view to over memory
std::shared_ptr<uchar> memory;
};
} //namespace own
} //namespace gapi
} //namespace cv
#endif /* INCLUDE_OPENCV2_GAPI_OWN_MAT_HPP */

@ -0,0 +1,45 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GAPI_OWN_SCALAR_HPP
#define OPENCV_GAPI_GAPI_OWN_SCALAR_HPP
namespace cv
{
namespace gapi
{
namespace own
{
class CV_EXPORTS Scalar
{
public:
Scalar() = default;
explicit Scalar(double v0) { val[0] = v0; };
Scalar(double v0, double v1, double v2 = 0, double v3 = 0)
: val{v0, v1, v2, v3}
{
}
const double& operator[](int i) const { return val[i]; }
double& operator[](int i) { return val[i]; }
static Scalar all(double v0) { return Scalar(v0, v0, v0, v0); }
double val[4] = {0};
};
inline bool operator==(const Scalar& lhs, const Scalar& rhs)
{
return std::equal(std::begin(lhs.val), std::end(lhs.val), std::begin(rhs.val));
}
} // namespace own
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_GAPI_OWN_SCALAR_HPP

@ -0,0 +1,137 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_TYPES_HPP
#define OPENCV_GAPI_TYPES_HPP
#include <algorithm> // std::max, std::min
#include "opencv2/core/base.hpp" //for CV_DbgAssert
#include "opencv2/gapi/own/assert.hpp"
namespace cv
{
namespace gapi
{
namespace own
{
class Point
{
public:
Point() = default;
Point(int _x, int _y) : x(_x), y(_y) {};
int x = 0;
int y = 0;
};
class Rect
{
public:
Rect() = default;
Rect(int _x, int _y, int _width, int _height) : x(_x), y(_y), width(_width), height(_height) {};
#if 1
Rect(const cv::Rect& other) : x(other.x), y(other.y), width(other.width), height(other.height) {};
inline Rect& operator=(const cv::Rect& other)
{
x = other.x;
y = other.x;
width = other.width;
height = other.height;
return *this;
}
#endif
int x = 0; //!< x coordinate of the top-left corner
int y = 0; //!< y coordinate of the top-left corner
int width = 0; //!< width of the rectangle
int height = 0; //!< height of the rectangle
};
inline bool operator==(const Rect& lhs, const Rect& rhs)
{
return lhs.x == rhs.x && lhs.y == rhs.y && lhs.width == rhs.width && lhs.height == rhs.height;
}
inline bool operator!=(const Rect& lhs, const Rect& rhs)
{
return !(lhs == rhs);
}
inline Rect& operator&=(Rect& lhs, const Rect& rhs)
{
int x1 = std::max(lhs.x, rhs.x);
int y1 = std::max(lhs.y, rhs.y);
lhs.width = std::min(lhs.x + lhs.width, rhs.x + rhs.width) - x1;
lhs.height = std::min(lhs.y + lhs.height, rhs.y + rhs.height) - y1;
lhs.x = x1;
lhs.y = y1;
if( lhs.width <= 0 || lhs.height <= 0 )
lhs = Rect();
return lhs;
}
inline const Rect operator&(const Rect& lhs, const Rect& rhs)
{
Rect result = lhs;
return result &= rhs;
}
inline std::ostream& operator<<(std::ostream& o, const Rect& rect)
{
return o << "[" << rect.width << " x " << rect.height << " from (" << rect.x << ", " << rect.y << ")]";
}
class Size
{
public:
Size() = default;
Size(int _width, int _height) : width(_width), height(_height) {};
#if 1
Size(const cv::Size& other) : width(other.width), height(other.height) {};
inline Size& operator=(const cv::Size& rhs)
{
width = rhs.width;
height = rhs.height;
return *this;
}
#endif
int width = 0;
int height = 0;
};
inline Size& operator+=(Size& lhs, const Size& rhs)
{
lhs.width += rhs.width;
lhs.height += rhs.height;
return lhs;
}
inline bool operator==(const Size& lhs, const Size& rhs)
{
return lhs.width == rhs.width && lhs.height == rhs.height;
}
inline bool operator!=(const Size& lhs, const Size& rhs)
{
return !(lhs == rhs);
}
inline std::ostream& operator<<(std::ostream& o, const Size& s)
{
o << "[" << s.width << " x " << s.height << "]";
return o;
}
} // namespace own
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_TYPES_HPP

@ -0,0 +1,159 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_UTIL_ANY_HPP
#define OPENCV_GAPI_UTIL_ANY_HPP
#include <memory>
#include <type_traits>
#include <typeinfo>
#include <utility>
#include "opencv2/gapi/util/throw.hpp"
#if defined(_MSC_VER)
// disable MSVC warning on "multiple copy constructors specified"
# pragma warning(disable: 4521)
#endif
namespace cv
{
namespace internal
{
template <class T, class Source>
T down_cast(Source operand)
{
#if defined(__GXX_RTTI) || defined(_CPPRTTI)
return dynamic_cast<T>(operand);
#else
#warning used static cast instead of dynamic because RTTI is disabled
return static_cast<T>(operand);
#endif
}
}
namespace util
{
class bad_any_cast : public std::bad_cast
{
public:
virtual const char* what() const noexcept override
{
return "Bad any cast";
}
};
//modeled against C++17 std::any
class any
{
private:
struct holder;
using holder_ptr = std::unique_ptr<holder>;
struct holder
{
virtual holder_ptr clone() = 0;
virtual ~holder() = default;
};
template <typename value_t>
struct holder_impl : holder
{
value_t v;
template<typename arg_t>
holder_impl(arg_t&& a) : v(std::forward<arg_t>(a)) {}
holder_ptr clone() override { return holder_ptr(new holder_impl (v));}
};
holder_ptr hldr;
public:
template<class value_t>
any(value_t&& arg) : hldr(new holder_impl<typename std::decay<value_t>::type>( std::forward<value_t>(arg))) {}
any(any const& src) : hldr( src.hldr ? src.hldr->clone() : nullptr) {}
//simple hack in order not to write enable_if<not any> for the template constructor
any(any & src) : any (const_cast<any const&>(src)) {}
any() = default;
any(any&& ) = default;
any& operator=(any&&) = default;
any& operator=(any const& src)
{
any copy(src);
swap(*this, copy);
return *this;
}
template<class value_t>
friend value_t* any_cast(any* operand);
template<class value_t>
friend const value_t* any_cast(const any* operand);
friend void swap(any & lhs, any& rhs)
{
swap(lhs.hldr, rhs.hldr);
}
};
template<class value_t>
value_t* any_cast(any* operand)
{
auto casted = internal::down_cast<any::holder_impl<typename std::decay<value_t>::type> *>(operand->hldr.get());
if (casted){
return & (casted->v);
}
return nullptr;
}
template<class value_t>
const value_t* any_cast(const any* operand)
{
auto casted = internal::down_cast<any::holder_impl<typename std::decay<value_t>::type> *>(operand->hldr.get());
if (casted){
return & (casted->v);
}
return nullptr;
}
template<class value_t>
value_t& any_cast(any& operand)
{
auto ptr = any_cast<value_t>(&operand);
if (ptr)
{
return *ptr;
}
throw_error(bad_any_cast());
}
template<class value_t>
const value_t& any_cast(const any& operand)
{
auto ptr = any_cast<value_t>(&operand);
if (ptr)
{
return *ptr;
}
throw_error(bad_any_cast());
}
} // namespace util
} // namespace cv
#if defined(_MSC_VER)
// Enable "multiple copy constructors specified" back
# pragma warning(default: 4521)
#endif
#endif // OPENCV_GAPI_UTIL_ANY_HPP

@ -0,0 +1,21 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_UTIL_COMPILER_HINTS_HPP
#define OPENCV_GAPI_UTIL_COMPILER_HINTS_HPP
namespace cv
{
namespace util
{
//! Utility template function to prevent "unused" warnings by various compilers.
template<typename T> void suppress_unused_warning( const T& ) {}
} // namespace util
} // namespace cv
#define UNUSED(x) cv::util::suppress_unused_warning(x)
#endif /* OPENCV_GAPI_UTIL_COMPILER_HINTS_HPP */

@ -0,0 +1,178 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_UTIL_OPTIONAL_HPP
#define OPENCV_GAPI_UTIL_OPTIONAL_HPP
#include "opencv2/gapi/util/variant.hpp"
// A poor man's `optional` implementation, incompletely modeled against C++17 spec.
namespace cv
{
namespace util
{
class bad_optional_access: public std::exception
{
public:
virtual const char *what() const noexcept override
{
return "Bad optional access";
}
};
// TODO: nullopt_t
// Interface ///////////////////////////////////////////////////////////////
template<typename T> class optional
{
public:
// Constructors
// NB.: there were issues with Clang 3.8 when =default() was used
// instead {}
optional() {};
optional(const optional&) = default;
explicit optional(T &&value) noexcept;
explicit optional(const T &value) noexcept;
optional(optional &&) noexcept;
// TODO: optional(nullopt_t) noexcept;
// TODO: optional(const optional<U> &)
// TODO: optional(optional<U> &&)
// TODO: optional(Args&&...)
// TODO: optional(initializer_list<U>)
// TODO: optional(U&& value);
// Assignment
optional& operator=(const optional& rhs) = default;
optional& operator=(optional&& rhs);
// Observers
T* operator-> ();
const T* operator-> () const;
T& operator* ();
const T& operator* () const;
// TODO: && versions
operator bool() const noexcept;
bool has_value() const noexcept;
T& value();
const T& value() const;
// TODO: && versions
template<class U>
T value_or(U &&default_value) const;
void swap(optional &other) noexcept;
void reset() noexcept;
// TODO: emplace
// TODO: operator==, !=, <, <=, >, >=
private:
struct nothing {};
util::variant<nothing, T> m_holder;
};
template<class T>
optional<typename std::decay<T>::type> make_optional(T&& value);
// TODO: Args... and initializer_list versions
// Implementation //////////////////////////////////////////////////////////
template<class T> optional<T>::optional(T &&v) noexcept
: m_holder(v)
{
}
template<class T> optional<T>::optional(const T &v) noexcept
: m_holder(v)
{
}
template<class T> optional<T>::optional(optional&& rhs) noexcept
: m_holder(std::move(rhs.m_holder))
{
rhs.reset();
}
template<class T> optional<T>& optional<T>::operator=(optional&& rhs)
{
m_holder = std::move(rhs.m_holder);
rhs.reset();
return *this;
}
template<class T> T* optional<T>::operator-> ()
{
return & *(*this);
}
template<class T> const T* optional<T>::operator-> () const
{
return & *(*this);
}
template<class T> T& optional<T>::operator* ()
{
return this->value();
}
template<class T> const T& optional<T>::operator* () const
{
return this->value();
}
template<class T> optional<T>::operator bool() const noexcept
{
return this->has_value();
}
template<class T> bool optional<T>::has_value() const noexcept
{
return util::holds_alternative<T>(m_holder);
}
template<class T> T& optional<T>::value()
{
if (!this->has_value())
throw_error(bad_optional_access());
return util::get<T>(m_holder);
}
template<class T> const T& optional<T>::value() const
{
if (!this->has_value())
throw_error(bad_optional_access());
return util::get<T>(m_holder);
}
template<class T>
template<class U> T optional<T>::value_or(U &&default_value) const
{
return (this->has_value() ? this->value() : T(default_value));
}
template<class T> void optional<T>::swap(optional<T> &other) noexcept
{
m_holder.swap(other.m_holder);
}
template<class T> void optional<T>::reset() noexcept
{
if (this->has_value())
m_holder = nothing{};
}
template<class T>
optional<typename std::decay<T>::type> make_optional(T&& value)
{
return optional<typename std::decay<T>::type>(std::forward<T>(value));
}
} // namespace util
} // namespace cv
#endif // OPENCV_GAPI_UTIL_OPTIONAL_HPP

@ -0,0 +1,36 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_UTIL_THROW_HPP
#define OPENCV_GAPI_UTIL_THROW_HPP
#include <utility> // std::forward
#if !defined(__EXCEPTIONS)
#include <stdlib.h>
#include <stdio.h>
#endif
namespace cv
{
namespace util
{
template <class ExceptionType>
[[noreturn]] void throw_error(ExceptionType &&e)
{
#if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
throw std::forward<ExceptionType>(e);
#else
fprintf(stderr, "An exception thrown! %s\n" , e.what());
fflush(stderr);
abort();
#endif
}
} // namespace util
} // namespace cv
#endif // OPENCV_GAPI_UTIL_THROW_HPP

@ -0,0 +1,92 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_UTIL_HPP
#define OPENCV_GAPI_UTIL_HPP
#include <utility> // std::tuple
// \cond HIDDEN_SYMBOLS
// This header file contains some generic utility functions which are
// used in other G-API Public API headers.
//
// PLEASE don't put any stuff here if it is NOT used in public API headers!
namespace cv
{
namespace detail
{
// Recursive integer sequence type, useful for enumerating elements of
// template parameter packs.
template<int... I> struct Seq { using next = Seq<I..., sizeof...(I)>; };
template<int Sz> struct MkSeq { using type = typename MkSeq<Sz-1>::type::next; };
template<> struct MkSeq<0>{ using type = Seq<>; };
// Checks if elements of variadic template satisfy the given Predicate.
// Implemented via tuple, with an interface to accept plain type lists
template<template<class> class, typename, typename...> struct all_satisfy;
template<template<class> class F, typename T, typename... Ts>
struct all_satisfy<F, std::tuple<T, Ts...> >
{
static const constexpr bool value = F<T>::value
&& all_satisfy<F, std::tuple<Ts...> >::value;
};
template<template<class> class F, typename T>
struct all_satisfy<F, std::tuple<T> >
{
static const constexpr bool value = F<T>::value;
};
template<template<class> class F, typename T, typename... Ts>
struct all_satisfy: public all_satisfy<F, std::tuple<T, Ts...> > {};
// Permute given tuple type C with given integer sequence II
// Sequence may be less than tuple C size.
template<class, class> struct permute_tuple;
template<class C, int... IIs>
struct permute_tuple<C, Seq<IIs...> >
{
using type = std::tuple< typename std::tuple_element<IIs, C>::type... >;
};
// Given T..., generates a type sequence of sizeof...(T)-1 elements
// which is T... without its last element
// Implemented via tuple, with an interface to accept plain type lists
template<typename T, typename... Ts> struct all_but_last;
template<typename T, typename... Ts>
struct all_but_last<std::tuple<T, Ts...> >
{
using C = std::tuple<T, Ts...>;
using S = typename MkSeq<std::tuple_size<C>::value - 1>::type;
using type = typename permute_tuple<C, S>::type;
};
template<typename T, typename... Ts>
struct all_but_last: public all_but_last<std::tuple<T, Ts...> > {};
template<typename... Ts>
using all_but_last_t = typename all_but_last<Ts...>::type;
// NB.: This is here because there's no constexpr std::max in C++11
template<std::size_t S0, std::size_t... SS> struct max_of_t
{
static constexpr const std::size_t rest = max_of_t<SS...>::value;
static constexpr const std::size_t value = rest > S0 ? rest : S0;
};
template<std::size_t S> struct max_of_t<S>
{
static constexpr const std::size_t value = S;
};
} // namespace detail
} // namespace cv
// \endcond
#endif // OPENCV_GAPI_UTIL_HPP

@ -0,0 +1,377 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_UTIL_VARIANT_HPP
#define OPENCV_GAPI_UTIL_VARIANT_HPP
#include <array>
#include <type_traits>
#include "opencv2/gapi/util/throw.hpp"
#include "opencv2/gapi/util/util.hpp" // max_of_t
// A poor man's `variant` implementation, incompletely modeled against C++17 spec.
namespace cv
{
namespace util
{
namespace detail
{
template<std::size_t I, typename Target, typename First, typename... Remaining>
struct type_list_index_helper
{
static const constexpr bool is_same = std::is_same<Target, First>::value;
static const constexpr std::size_t value =
std::conditional<is_same, std::integral_constant<std::size_t, I>, type_list_index_helper<I + 1, Target, Remaining...>>::type::value;
};
template<std::size_t I, typename Target, typename First>
struct type_list_index_helper<I, Target, First>
{
static_assert(std::is_same<Target, First>::value, "Type not found");
static const constexpr std::size_t value = I;
};
template<class T, class U, class V> using are_different =
std::enable_if<!std::is_same<typename std::decay<T>::type,
typename std::decay<U>::type>::value,
V>;
}
template<typename Target, typename... Types>
struct type_list_index
{
static const constexpr std::size_t value = detail::type_list_index_helper<0, Target, Types...>::value;
};
class bad_variant_access: public std::exception
{
public:
virtual const char *what() const noexcept override
{
return "Bad variant access";
}
};
// Interface ///////////////////////////////////////////////////////////////
struct monostate {};
inline bool operator==(const util::monostate&, const util::monostate&)
{
return true;
}
template<typename... Ts> // FIXME: no references, arrays, and void
class variant
{
// FIXME: Replace with std::aligned_union after gcc4.8 support is dropped
static constexpr const std::size_t S = cv::detail::max_of_t<sizeof(Ts)...>::value;
static constexpr const std::size_t A = cv::detail::max_of_t<alignof(Ts)...>::value;
using Memory = typename std::aligned_storage<S, A>::type[1];
template<typename T> struct cctr_h {
static void help(Memory memory, const Memory from) {
new (memory) T(*reinterpret_cast<const T*>(from));
}
};
template<typename T> struct vctr_h {
static void help(Memory memory, const void* pval) {
new (memory) T(*reinterpret_cast<const T*>(pval));
}
};
template<typename T> struct mctr_h {
static void help(Memory memory, void *pval) {
new (memory) T(std::move(*reinterpret_cast<T*>(pval)));
}
};
template<typename T> struct copy_h {
static void help(Memory to, const Memory from) {
*reinterpret_cast<T*>(to) = *reinterpret_cast<const T*>(from);
}
};
template<typename T> struct move_h {
static void help(Memory to, const Memory from) {
*reinterpret_cast<T*>(to) = std::move(*reinterpret_cast<const T*>(from));
}
};
template<typename T> struct swap_h {
static void help(Memory to, Memory from) {
std::swap(*reinterpret_cast<T*>(to), *reinterpret_cast<T*>(from));
}
};
template<typename T> struct dtor_h {
static void help(Memory memory) {
(void) memory; // MSCV warning
reinterpret_cast<T*>(memory)->~T();
}
};
template<typename T> struct equal_h {
static bool help(const Memory lhs, const Memory rhs) {
const T& t_lhs = *reinterpret_cast<const T*>(lhs);
const T& t_rhs = *reinterpret_cast<const T*>(rhs);
return t_lhs == t_rhs;
}
};
typedef void (*CCtr) (Memory, const Memory); // Copy c-tor (variant)
typedef void (*VCtr) (Memory, const void*); // Copy c-tor (value)
typedef void (*MCtr) (Memory, void*); // Generic move c-tor
typedef void (*Copy) (Memory, const Memory); // Copy assignment
typedef void (*Move) (Memory, const Memory); // Move assignment
typedef void (*Swap) (Memory, Memory); // Swap
typedef void (*Dtor) (Memory); // Destructor
typedef bool (*Equal)(const Memory, const Memory); // Equality test (external)
static constexpr std::array<CCtr, sizeof...(Ts)> cctrs(){ return {{(&cctr_h<Ts>::help)...}};}
static constexpr std::array<VCtr, sizeof...(Ts)> vctrs(){ return {{(&vctr_h<Ts>::help)...}};}
static constexpr std::array<MCtr, sizeof...(Ts)> mctrs(){ return {{(&mctr_h<Ts>::help)...}};}
static constexpr std::array<Copy, sizeof...(Ts)> cpyrs(){ return {{(&copy_h<Ts>::help)...}};}
static constexpr std::array<Move, sizeof...(Ts)> mvers(){ return {{(&move_h<Ts>::help)...}};}
static constexpr std::array<Swap, sizeof...(Ts)> swprs(){ return {{(&swap_h<Ts>::help)...}};}
static constexpr std::array<Dtor, sizeof...(Ts)> dtors(){ return {{(&dtor_h<Ts>::help)...}};}
std::size_t m_index = 0;
protected:
template<typename T, typename... Us> friend T& get(variant<Us...> &v);
template<typename T, typename... Us> friend const T& get(const variant<Us...> &v);
template<typename... Us> friend bool operator==(const variant<Us...> &lhs,
const variant<Us...> &rhs);
Memory memory;
public:
// Constructors
variant() noexcept;
variant(const variant& other);
variant(variant&& other) noexcept;
template<typename T> explicit variant(const T& t);
// are_different is a SFINAE trick to avoid variant(T &&t) with T=variant
// for some reason, this version is called instead of variant(variant&& o) when
// variant is used in STL containers (examples: vector assignment)
template<typename T> explicit variant(T&& t, typename detail::are_different<variant, T, int>::type = 0);
// template<class T, class... Args> explicit variant(Args&&... args);
// FIXME: other constructors
// Destructor
~variant();
// Assignment
variant& operator=(const variant& rhs);
variant& operator=(variant &&rhs) noexcept;
// SFINAE trick to avoid operator=(T&&) with T=variant<>, see comment above
template<class T>
typename detail::are_different<variant, T, variant&>
::type operator=(T&& t) noexcept;
// Observers
std::size_t index() const noexcept;
// FIXME: valueless_by_exception()
// Modifiers
// FIXME: emplace()
void swap(variant &rhs) noexcept;
// Non-C++17x!
template<typename T> static constexpr std::size_t index_of();
};
// FIMXE: visit
template<typename T, typename... Types>
T& get(util::variant<Types...> &v);
template<typename T, typename... Types>
const T& get(const util::variant<Types...> &v);
template<typename T, typename... Types>
bool holds_alternative(const util::variant<Types...> &v) noexcept;
// FIXME: T&&, const TT&& versions.
// Implementation //////////////////////////////////////////////////////////
template<typename... Ts>
variant<Ts...>::variant() noexcept
{
typedef typename std::tuple_element<0, std::tuple<Ts...> >::type TFirst;
new (memory) TFirst();
}
template<typename... Ts>
variant<Ts...>::variant(const variant &other)
: m_index(other.m_index)
{
(cctrs()[m_index])(memory, other.memory);
}
template<typename... Ts>
variant<Ts...>::variant(variant &&other) noexcept
: m_index(other.m_index)
{
(mctrs()[m_index])(memory, other.memory);
}
template<typename... Ts>
template<class T>
variant<Ts...>::variant(const T& t)
: m_index(util::type_list_index<T, Ts...>::value)
{
(vctrs()[m_index])(memory, &t);
}
template<typename... Ts>
template<class T>
variant<Ts...>::variant(T&& t, typename detail::are_different<variant, T, int>::type)
: m_index(util::type_list_index<typename std::remove_reference<T>::type, Ts...>::value)
{
(mctrs()[m_index])(memory, &t);
}
template<typename... Ts>
variant<Ts...>::~variant()
{
(dtors()[m_index])(memory);
}
template<typename... Ts>
variant<Ts...>& variant<Ts...>::operator=(const variant<Ts...> &rhs)
{
if (m_index != rhs.m_index)
{
(dtors()[ m_index])(memory);
(cctrs()[rhs.m_index])(memory, rhs.memory);
m_index = rhs.m_index;
}
else
{
(cpyrs()[rhs.m_index])(memory, rhs.memory);
}
return *this;
}
template<typename... Ts>
variant<Ts...>& variant<Ts...>::operator=(variant<Ts...> &&rhs) noexcept
{
if (m_index != rhs.m_index)
{
(dtors()[ m_index])(memory);
(mctrs()[rhs.m_index])(memory, rhs.memory);
m_index = rhs.m_index;
}
else
{
(mvers()[rhs.m_index])(memory, rhs.memory);
}
return *this;
}
template<typename... Ts>
template<class T> typename detail::are_different<variant<Ts...>, T, variant<Ts...>&>
::type variant<Ts...>::operator=(T&& t) noexcept
{
// FIXME: No version with implicit type conversion available!
static const constexpr std::size_t t_index =
util::type_list_index<T, Ts...>::value;
if (t_index == m_index)
{
util::get<T>(*this) = std::move(t);
return *this;
}
else return (*this = variant(std::move(t)));
}
template<typename... Ts>
std::size_t util::variant<Ts...>::index() const noexcept
{
return m_index;
}
template<typename... Ts>
void variant<Ts...>::swap(variant<Ts...> &rhs) noexcept
{
if (m_index == rhs.index())
{
(swprs()[m_index](memory, rhs.memory));
}
else
{
variant<Ts...> tmp(std::move(*this));
*this = std::move(rhs);
rhs = std::move(tmp);
}
}
template<typename... Ts>
template<typename T>
constexpr std::size_t variant<Ts...>::index_of()
{
return util::type_list_index<T, Ts...>::value; // FIXME: tests!
}
template<typename T, typename... Types>
T& get(util::variant<Types...> &v)
{
const constexpr std::size_t t_index =
util::type_list_index<T, Types...>::value;
if (v.index() == t_index)
return reinterpret_cast<T&>(v.memory);
else
throw_error(bad_variant_access());
}
template<typename T, typename... Types>
const T& get(const util::variant<Types...> &v)
{
const constexpr std::size_t t_index =
util::type_list_index<T, Types...>::value;
if (v.index() == t_index)
return reinterpret_cast<const T&>(v.memory);
else
throw_error(bad_variant_access());
}
template<typename T, typename... Types>
bool holds_alternative(const util::variant<Types...> &v) noexcept
{
return v.index() == util::variant<Types...>::template index_of<T>();
}
template<typename... Us> bool operator==(const variant<Us...> &lhs,
const variant<Us...> &rhs)
{
using V = variant<Us...>;
// Instantiate table only here since it requires operator== for <Us...>
// <Us...> should have operator== only if this one is used, not in general
static const std::array<typename V::Equal, sizeof...(Us)> eqs = {
{(&V::template equal_h<Us>::help)...}
};
if (lhs.index() != rhs.index())
return false;
return (eqs[lhs.index()])(lhs.memory, rhs.memory);
}
template<typename... Us> bool operator!=(const variant<Us...> &lhs,
const variant<Us...> &rhs)
{
return !(lhs == rhs);
}
} // namespace cv
} // namespace util
#endif // OPENCV_GAPI_UTIL_VARIANT_HPP

File diff suppressed because it is too large Load Diff

@ -0,0 +1,882 @@
// 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) 2018 Intel Corporation
#include "../../test/common/gapi_tests_common.hpp"
#include "opencv2/gapi/imgproc.hpp"
namespace opencv_test
{
using namespace perf;
//------------------------------------------------------------------------------
class SepFilterPerfTest : public TestPerfParams<tuple<MatType, int, cv::Size, int>> {};
PERF_TEST_P_(SepFilterPerfTest, TestPerformance)
{
MatType type = 0;
int kernSize = 0, dtype = 0;
cv::Size sz;
std::tie(type, kernSize, sz, dtype) = GetParam();
cv::Mat kernelX(kernSize, 1, CV_32F);
cv::Mat kernelY(kernSize, 1, CV_32F);
randu(kernelX, -1, 1);
randu(kernelY, -1, 1);
initMatsRandN(type, sz, dtype, false);
cv::Point anchor = cv::Point(-1, -1);
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::sepFilter2D(in_mat1, out_mat_ocv, dtype, kernelX, kernelY );
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::sepFilter(in, dtype, kernelX, kernelY, anchor, cv::Scalar() );
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class Filter2DPerfTest : public TestPerfParams<tuple<MatType,int,cv::Size,int,int>> {};
PERF_TEST_P_(Filter2DPerfTest, TestPerformance)
{
MatType type = 0;
int kernSize = 0, borderType = 0, dtype = 0;
cv::Size sz;
std::tie(type, kernSize, sz, borderType, dtype) = GetParam();
initMatsRandN(type, sz, dtype, false);
cv::Point anchor = {-1, -1};
double delta = 0;
cv::Mat kernel = cv::Mat(kernSize, kernSize, CV_32FC1 );
cv::Scalar kernMean = cv::Scalar::all(1.0);
cv::Scalar kernStddev = cv::Scalar::all(2.0/3);
randn(kernel, kernMean, kernStddev);
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::filter2D(in_mat1, out_mat_ocv, dtype, kernel, anchor, delta, borderType);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::filter2D(in, dtype, kernel, anchor, delta, borderType);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class BoxFilterPerfTest : public TestPerfParams<tuple<MatType,int,cv::Size,int,int,double>> {};
PERF_TEST_P_(BoxFilterPerfTest, TestPerformance)
{
MatType type = 0;
int filterSize = 0, borderType = 0, dtype = 0;
cv::Size sz;
double tolerance = 0.0;
std::tie(type, filterSize, sz, borderType, dtype, tolerance) = GetParam();
initMatsRandN(type, sz, dtype, false);
cv::Point anchor = {-1, -1};
bool normalize = true;
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::boxFilter(in_mat1, out_mat_ocv, dtype, cv::Size(filterSize, filterSize), anchor, normalize, borderType);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::boxFilter(in, dtype, cv::Size(filterSize, filterSize), anchor, normalize, borderType);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
cv::Mat absDiff;
cv::absdiff(out_mat_gapi, out_mat_ocv, absDiff);
EXPECT_EQ(0, cv::countNonZero(absDiff > tolerance));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class BlurPerfTest : public TestPerfParams<tuple<MatType,int,cv::Size,int,double>> {};
PERF_TEST_P_(BlurPerfTest, TestPerformance)
{
MatType type = 0;
int filterSize = 0, borderType = 0;
cv::Size sz;
double tolerance = 0.0;
std::tie(type, filterSize, sz, borderType, tolerance) = GetParam();
initMatsRandN(type, sz, type, false);
cv::Point anchor = {-1, -1};
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::blur(in_mat1, out_mat_ocv, cv::Size(filterSize, filterSize), anchor, borderType);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::blur(in, cv::Size(filterSize, filterSize), anchor, borderType);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
cv::Mat absDiff;
cv::absdiff(out_mat_gapi, out_mat_ocv, absDiff);
EXPECT_EQ(0, cv::countNonZero(absDiff > tolerance));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class GaussianBlurPerfTest : public TestPerfParams<tuple<MatType, int, cv::Size>> {};
PERF_TEST_P_(GaussianBlurPerfTest, TestPerformance)
{
MatType type = 0;
int kernSize = 0;
cv::Size sz;
std::tie(type, kernSize, sz) = GetParam();
cv::Size kSize = cv::Size(kernSize, kernSize);
auto& rng = cv::theRNG();
double sigmaX = rng();
initMatsRandN(type, sz, type, false);
// OpenCV code ///////////////////////////////////////////////////////////
cv::GaussianBlur(in_mat1, out_mat_ocv, kSize, sigmaX);
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::gaussianBlur(in, kSize, sigmaX);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison ////////////////////////////////////////////////////////////
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class MedianBlurPerfTest : public TestPerfParams<tuple<MatType,int,cv::Size>> {};
PERF_TEST_P_(MedianBlurPerfTest, TestPerformance)
{
MatType type = 0;
int kernSize = 0;
cv::Size sz;
std::tie(type, kernSize, sz) = GetParam();
initMatsRandN(type, sz, type, false);
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::medianBlur(in_mat1, out_mat_ocv, kernSize);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::medianBlur(in, kernSize);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class ErodePerfTest : public TestPerfParams<tuple<MatType,int,cv::Size,int>> {};
PERF_TEST_P_(ErodePerfTest, TestPerformance)
{
MatType type = 0;
int kernSize = 0, kernType = 0;
cv::Size sz;
std::tie(type, kernSize, sz, kernType) = GetParam();
initMatsRandN(type, sz, type, false);
cv::Mat kernel = cv::getStructuringElement(kernType, cv::Size(kernSize, kernSize));
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::erode(in_mat1, out_mat_ocv, kernel);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::erode(in, kernel);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class Erode3x3PerfTest : public TestPerfParams<tuple<MatType,cv::Size,int>> {};
PERF_TEST_P_(Erode3x3PerfTest, TestPerformance)
{
MatType type = 0;
int numIters = 0;
cv::Size sz;
std::tie(type, sz, numIters) = GetParam();
initMatsRandN(type, sz, type, false);
cv::Mat kernel = cv::getStructuringElement(cv::MorphShapes::MORPH_RECT, cv::Size(3, 3));
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::erode(in_mat1, out_mat_ocv, kernel, cv::Point(-1, -1), numIters);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::erode3x3(in, numIters);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class DilatePerfTest : public TestPerfParams<tuple<MatType,int,cv::Size,int>> {};
PERF_TEST_P_(DilatePerfTest, TestPerformance)
{
MatType type = 0;
int kernSize = 0, kernType = 0;
cv::Size sz;
std::tie(type, kernSize, sz, kernType) = GetParam();
initMatsRandN(type, sz, type, false);
cv::Mat kernel = cv::getStructuringElement(kernType, cv::Size(kernSize, kernSize));
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::dilate(in_mat1, out_mat_ocv, kernel);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::dilate(in, kernel);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class Dilate3x3PerfTest : public TestPerfParams<tuple<MatType,cv::Size,int>> {};
PERF_TEST_P_(Dilate3x3PerfTest, TestPerformance)
{
MatType type = 0;
int numIters = 0;
cv::Size sz;
std::tie(type, sz, numIters) = GetParam();
initMatsRandN(type, sz, type, false);
cv::Mat kernel = cv::getStructuringElement(cv::MorphShapes::MORPH_RECT, cv::Size(3, 3));
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::dilate(in_mat1, out_mat_ocv, kernel, cv::Point(-1,-1), numIters);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::dilate3x3(in, numIters);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class SobelPerfTest : public TestPerfParams<tuple<MatType,int,cv::Size,int,int,int>> {};
PERF_TEST_P_(SobelPerfTest, TestPerformance)
{
MatType type = 0;
int kernSize = 0, dtype = 0, dx = 0, dy = 0;
cv::Size sz;
std::tie(type, kernSize, sz, dtype, dx, dy) = GetParam();
initMatsRandN(type, sz, dtype, false);
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::Sobel(in_mat1, out_mat_ocv, dtype, dx, dy, kernSize);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::sobel(in, dtype, dx, dy, kernSize );
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class CannyPerfTest : public TestPerfParams<tuple<MatType,cv::Size,double,double,int,bool>> {};
PERF_TEST_P_(CannyPerfTest, TestPerformance)
{
MatType type;
int apSize = 0;
double thrLow = 0.0, thrUp = 0.0;
cv::Size sz;
bool l2gr = false;
std::tie(type, sz, thrLow, thrUp, apSize, l2gr) = GetParam();
initMatsRandN(type, sz, CV_8UC1, false);
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::Canny(in_mat1, out_mat_ocv, thrLow, thrUp, apSize, l2gr);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::Canny(in, thrLow, thrUp, apSize, l2gr);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class EqHistPerfTest : public TestPerfParams<cv::Size> {};
PERF_TEST_P_(EqHistPerfTest, TestPerformance)
{
cv::Size sz = GetParam();
initMatsRandN(CV_8UC1, sz, CV_8UC1, false);
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::equalizeHist(in_mat1, out_mat_ocv);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::equalizeHist(in);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class RGB2GrayPerfTest : public TestPerfParams<cv::Size> {};
PERF_TEST_P_(RGB2GrayPerfTest, TestPerformance)
{
cv::Size sz = GetParam();
initMatsRandN(CV_8UC3, sz, CV_8UC1, false);
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_RGB2GRAY);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::RGB2Gray(in);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class BGR2GrayPerfTest : public TestPerfParams<cv::Size> {};
PERF_TEST_P_(BGR2GrayPerfTest, TestPerformance)
{
cv::Size sz = GetParam();
initMatsRandN(CV_8UC3, sz, CV_8UC1, false);
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_BGR2GRAY);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::BGR2Gray(in);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class RGB2YUVPerfTest : public TestPerfParams<cv::Size> {};
PERF_TEST_P_(RGB2YUVPerfTest, TestPerformance)
{
cv::Size sz = GetParam();
initMatsRandN(CV_8UC3, sz, CV_8UC3, false);
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_RGB2YUV);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::RGB2YUV(in);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class YUV2RGBPerfTest : public TestPerfParams<cv::Size> {};
PERF_TEST_P_(YUV2RGBPerfTest, TestPerformance)
{
cv::Size sz = GetParam();
initMatsRandN(CV_8UC3, sz, CV_8UC3, false);
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_YUV2RGB);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::YUV2RGB(in);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class RGB2LabPerfTest : public TestPerfParams<cv::Size> {};
PERF_TEST_P_(RGB2LabPerfTest, TestPerformance)
{
cv::Size sz = GetParam();
initMatsRandN(CV_8UC3, sz, CV_8UC3, false);
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_RGB2Lab);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::RGB2Lab(in);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class BGR2LUVPerfTest : public TestPerfParams<cv::Size> {};
PERF_TEST_P_(BGR2LUVPerfTest, TestPerformance)
{
cv::Size sz = GetParam();
initMatsRandN(CV_8UC3, sz, CV_8UC3, false);
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_BGR2Luv);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::BGR2LUV(in);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class LUV2BGRPerfTest : public TestPerfParams<cv::Size> {};
PERF_TEST_P_(LUV2BGRPerfTest, TestPerformance)
{
cv::Size sz = GetParam();
initMatsRandN(CV_8UC3, sz, CV_8UC3, false);
// OpenCV code /////////////////////////////////////////////////////////////
{
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_Luv2BGR);
}
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
auto out = cv::gapi::LUV2BGR(in);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
// Comparison //////////////////////////////////////////////////////////////
{
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
}
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class BGR2YUVPerfTest : public TestPerfParams<cv::Size> {};
PERF_TEST_P_(BGR2YUVPerfTest, TestPerformance)
{
cv::Size sz = GetParam();
initMatsRandN(CV_8UC3, sz, CV_8UC3, false);
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_BGR2YUV);
cv::GMat in;
auto out = cv::gapi::BGR2YUV(in);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
class YUV2BGRPerfTest : public TestPerfParams<cv::Size> {};
PERF_TEST_P_(YUV2BGRPerfTest, TestPerformance)
{
cv::Size sz = GetParam();
initMatsRandN(CV_8UC3, sz, CV_8UC3, false);
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_YUV2BGR);
cv::GMat in;
auto out = cv::gapi::YUV2BGR(in);
cv::GComputation c(in, out);
// Warm-up graph engine:
c.apply(in_mat1, out_mat_gapi);
TEST_CYCLE()
{
c.apply(in_mat1, out_mat_gapi);
}
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
SANITY_CHECK_NOTHING();
}
//------------------------------------------------------------------------------
}

@ -0,0 +1,219 @@
// 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) 2018 Intel Corporation
#include "../common/gapi_core_perf_tests.hpp"
namespace opencv_test
{
INSTANTIATE_TEST_CASE_P(AddPerfTestCPU, AddPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values( -1, CV_8U, CV_16U, CV_32F )));
INSTANTIATE_TEST_CASE_P(AddCPerfTestCPU, AddCPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values( -1, CV_8U, CV_16U, CV_32F )));
INSTANTIATE_TEST_CASE_P(SubPerfTestCPU, SubPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values( -1, CV_8U, CV_16U, CV_32F )));
INSTANTIATE_TEST_CASE_P(SubCPerfTestCPU, SubCPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values( -1, CV_8U, CV_16U, CV_32F )));
INSTANTIATE_TEST_CASE_P(SubRCPerfTestCPU, SubRCPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values( -1, CV_8U, CV_16U, CV_32F )));
INSTANTIATE_TEST_CASE_P(MulPerfTestCPU, MulPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values( -1, CV_8U, CV_16U, CV_32F )));
INSTANTIATE_TEST_CASE_P(MulDoublePerfTestCPU, MulDoublePerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values( -1, CV_8U, CV_16U, CV_32F )));
INSTANTIATE_TEST_CASE_P(MulCPerfTestCPU, MulCPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values( -1, CV_8U, CV_16U, CV_32F )));
INSTANTIATE_TEST_CASE_P(DivPerfTestCPU, DivPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values( -1, CV_8U, CV_16U, CV_32F )));
INSTANTIATE_TEST_CASE_P(DivCPerfTestCPU, DivCPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values( -1, CV_8U, CV_16U, CV_32F )));
INSTANTIATE_TEST_CASE_P(DivRCPerfTestCPU, DivRCPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values( -1, CV_8U, CV_16U, CV_32F )));
INSTANTIATE_TEST_CASE_P(MaskPerfTestCPU, MaskPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_16UC1, CV_16SC1)));
INSTANTIATE_TEST_CASE_P(MeanPerfTestCPU, MeanPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 )));
INSTANTIATE_TEST_CASE_P(Polar2CartPerfTestCPU, Polar2CartPerfTest, Values( szSmall128, szVGA, sz720p, sz1080p ));
INSTANTIATE_TEST_CASE_P(Cart2PolarPerfTestCPU, Cart2PolarPerfTest, Values( szSmall128, szVGA, sz720p, sz1080p ));
INSTANTIATE_TEST_CASE_P(CmpPerfTestCPU, CmpPerfTest,
Combine(Values(CMP_EQ, CMP_GE, CMP_NE, CMP_GT, CMP_LT, CMP_LE),
Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 )));
INSTANTIATE_TEST_CASE_P(CmpWithScalarPerfTestCPU, CmpWithScalarPerfTest,
Combine(Values(CMP_EQ, CMP_GE, CMP_NE, CMP_GT, CMP_LT, CMP_LE),
Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 )));
INSTANTIATE_TEST_CASE_P(BitwisePerfTestCPU, BitwisePerfTest,
Combine(Values(AND, OR, XOR),
Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1)));
INSTANTIATE_TEST_CASE_P(BitwiseNotPerfTestCPU, BitwiseNotPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 )));
INSTANTIATE_TEST_CASE_P(SelectPerfTestCPU, SelectPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 )));
INSTANTIATE_TEST_CASE_P(MinPerfTestCPU, MinPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 )));
INSTANTIATE_TEST_CASE_P(MaxPerfTestCPU, MaxPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 )));
INSTANTIATE_TEST_CASE_P(AbsDiffPerfTestCPU, AbsDiffPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 )));
INSTANTIATE_TEST_CASE_P(AbsDiffCPerfTestCPU, AbsDiffCPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 )));
INSTANTIATE_TEST_CASE_P(SumPerfTestCPU, SumPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 )));
INSTANTIATE_TEST_CASE_P(AddWeightedPerfTestCPU, AddWeightedPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values( -1, CV_8U, CV_16U, CV_32F )));
INSTANTIATE_TEST_CASE_P(NormPerfTestCPU, NormPerfTest,
Combine(Values(NORM_INF, NORM_L1, NORM_L2),
Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 )));
INSTANTIATE_TEST_CASE_P(IntegralPerfTestCPU, IntegralPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1 )));
INSTANTIATE_TEST_CASE_P(ThresholdPerfTestCPU, ThresholdPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::THRESH_BINARY, cv::THRESH_BINARY_INV, cv::THRESH_TRUNC, cv::THRESH_TOZERO, cv::THRESH_TOZERO_INV)));
INSTANTIATE_TEST_CASE_P(ThresholdPerfTestCPU, ThresholdOTPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1 ),
Values(cv::THRESH_OTSU, cv::THRESH_TRIANGLE)));
INSTANTIATE_TEST_CASE_P(InRangePerfTestCPU, InRangePerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1 )));
INSTANTIATE_TEST_CASE_P(Split3PerfTestCPU, Split3PerfTest, Values( szSmall128, szVGA, sz720p, sz1080p ));
INSTANTIATE_TEST_CASE_P(Split4PerfTestCPU, Split4PerfTest, Values( szSmall128, szVGA, sz720p, sz1080p ));
INSTANTIATE_TEST_CASE_P(Merge3PerfTestCPU, Merge3PerfTest, Values( szSmall128, szVGA, sz720p, sz1080p ));
INSTANTIATE_TEST_CASE_P(Merge4PerfTestCPU, Merge4PerfTest, Values( szSmall128, szVGA, sz720p, sz1080p ));
INSTANTIATE_TEST_CASE_P(RemapPerfTestCPU, RemapPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 )));
INSTANTIATE_TEST_CASE_P(FlipPerfTestCPU, FlipPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(0,1,-1)));
INSTANTIATE_TEST_CASE_P(CropPerfTestCPU, CropPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Rect(10, 8, 20, 35), cv::Rect(4, 10, 37, 50))));
INSTANTIATE_TEST_CASE_P(ConcatHorPerfTestCPU, ConcatHorPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 )));
INSTANTIATE_TEST_CASE_P(ConcatHorVecPerfTestCPU, ConcatHorVecPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 )));
INSTANTIATE_TEST_CASE_P(ConcatVertPerfTestCPU, ConcatVertPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 )));
INSTANTIATE_TEST_CASE_P(ConcatVertVecPerfTestCPU, ConcatVertVecPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 )));
INSTANTIATE_TEST_CASE_P(LUTPerfTestCPU, LUTPerfTest,
Combine(Values(CV_8UC1, CV_8UC3),
Values(CV_8UC1),
Values( szSmall128, szVGA, sz720p, sz1080p )));
INSTANTIATE_TEST_CASE_P(LUTPerfTestCustomCPU, LUTPerfTest,
Combine(Values(CV_8UC3),
Values(CV_8UC3),
Values( szSmall128, szVGA, sz720p, sz1080p )));
INSTANTIATE_TEST_CASE_P(ConvertToPerfTestCPU, ConvertToPerfTest,
Combine(Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_32FC1),
Values(CV_8U, CV_16U, CV_16S, CV_32F),
Values( szSmall128, szVGA, sz720p, sz1080p )));
INSTANTIATE_TEST_CASE_P(ResizePerfTestCPU, ResizePerfTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_AREA),
Values( szSmall128, szVGA, sz720p, sz1080p ),
Values(cv::Size(64,64),
cv::Size(30,30)),
Values(0.0)));
INSTANTIATE_TEST_CASE_P(ResizeFxFyPerfTestCPU, ResizeFxFyPerfTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_AREA),
Values( szSmall128, szVGA, sz720p, sz1080p ),
Values(0.5, 0.1),
Values(0.5, 0.1),
Values(0.0)));
}

@ -0,0 +1,119 @@
// 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) 2018 Intel Corporation
#include "../common/gapi_imgproc_perf_tests.hpp"
namespace opencv_test
{
INSTANTIATE_TEST_CASE_P(SepFilterPerfTestCPU_8U, SepFilterPerfTest,
Combine(Values(CV_8UC1, CV_8UC3),
Values(3),
Values(szVGA, sz720p, sz1080p),
Values(-1, CV_16S, CV_32F)));
INSTANTIATE_TEST_CASE_P(SepFilterPerfTestCPU_other, SepFilterPerfTest,
Combine(Values(CV_16UC1, CV_16SC1, CV_32FC1),
Values(3),
Values(szVGA, sz720p, sz1080p),
Values(-1, CV_32F)));
INSTANTIATE_TEST_CASE_P(Filter2DPerfTestCPU, Filter2DPerfTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(3, 4, 5, 7),
Values(szVGA, sz720p, sz1080p),
Values(cv::BORDER_DEFAULT),
Values(-1, CV_32F)));
INSTANTIATE_TEST_CASE_P(BoxFilterPerfTestCPU, BoxFilterPerfTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(3,5),
Values(szVGA, sz720p, sz1080p),
Values(cv::BORDER_DEFAULT),
Values(-1, CV_32F),
Values(0.0)));
INSTANTIATE_TEST_CASE_P(BlurPerfTestCPU, BlurPerfTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(3, 5),
Values(szVGA, sz720p, sz1080p),
Values(cv::BORDER_DEFAULT),
Values(0.0)));
INSTANTIATE_TEST_CASE_P(GaussianBlurPerfTestCPU, GaussianBlurPerfTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(3, 5),
Values(szVGA, sz720p, sz1080p)));
INSTANTIATE_TEST_CASE_P(MedianBlurPerfTestCPU, MedianBlurPerfTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(3, 5),
Values(szVGA, sz720p, sz1080p)));
INSTANTIATE_TEST_CASE_P(ErodePerfTestCPU, ErodePerfTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(3, 5),
Values(szVGA, sz720p, sz1080p),
Values(cv::MorphShapes::MORPH_RECT,
cv::MorphShapes::MORPH_CROSS,
cv::MorphShapes::MORPH_ELLIPSE)));
INSTANTIATE_TEST_CASE_P(Erode3x3PerfTestCPU, Erode3x3PerfTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(szVGA, sz720p, sz1080p),
Values(1,2,4)));
INSTANTIATE_TEST_CASE_P(DilatePerfTestCPU, DilatePerfTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(3, 5),
Values(szVGA, sz720p, sz1080p),
Values(cv::MorphShapes::MORPH_RECT,
cv::MorphShapes::MORPH_CROSS,
cv::MorphShapes::MORPH_ELLIPSE)));
INSTANTIATE_TEST_CASE_P(Dilate3x3PerfTestCPU, Dilate3x3PerfTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(szVGA, sz720p, sz1080p),
Values(1,2,4)));
INSTANTIATE_TEST_CASE_P(SobelPerfTestCPU, SobelPerfTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(3, 5),
Values(szVGA, sz720p, sz1080p),
Values(-1, CV_32F),
Values(0, 1),
Values(1, 2)));
INSTANTIATE_TEST_CASE_P(CannyPerfTestCPU, CannyPerfTest,
Combine(Values(CV_8UC1, CV_8UC3),
Values(szVGA, sz720p, sz1080p),
Values(3.0, 120.0),
Values(125.0, 240.0),
Values(3, 5),
Values(true, false)));
INSTANTIATE_TEST_CASE_P(EqHistPerfTestCPU, EqHistPerfTest, Values(szVGA, sz720p, sz1080p));
INSTANTIATE_TEST_CASE_P(RGB2GrayPerfTestCPU, RGB2GrayPerfTest, Values(szVGA, sz720p, sz1080p));
INSTANTIATE_TEST_CASE_P(BGR2GrayPerfTestCPU, BGR2GrayPerfTest, Values(szVGA, sz720p, sz1080p));
INSTANTIATE_TEST_CASE_P(RGB2YUVPerfTestCPU, RGB2YUVPerfTest, Values(szVGA, sz720p, sz1080p));
INSTANTIATE_TEST_CASE_P(YUV2RGBPerfTestCPU, YUV2RGBPerfTest, Values(szVGA, sz720p, sz1080p));
INSTANTIATE_TEST_CASE_P(RGB2LabPerfTestCPU, RGB2LabPerfTest, Values(szVGA, sz720p, sz1080p));
INSTANTIATE_TEST_CASE_P(BGR2LUVPerfTestCPU, BGR2LUVPerfTest, Values(szVGA, sz720p, sz1080p));
INSTANTIATE_TEST_CASE_P(LUV2BGRPerfTestCPU, LUV2BGRPerfTest, Values(szVGA, sz720p, sz1080p));
INSTANTIATE_TEST_CASE_P(BGR2YUVPerfTestCPU, BGR2YUVPerfTest, Values(szVGA, sz720p, sz1080p));
INSTANTIATE_TEST_CASE_P(YUV2BGRPerfTestCPU, YUV2BGRPerfTest, Values(szVGA, sz720p, sz1080p));
}

@ -0,0 +1,46 @@
// 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) 2018 Intel Corporation
#include "perf_precomp.hpp"
#include "../../test/common/gapi_tests_common.hpp"
#include "../../src/backends/fluid/gfluidcore.hpp"
namespace opencv_test
{
using namespace perf;
class CompilerPerfTest : public TestPerfParams<tuple<cv::Size, MatType>> {};
PERF_TEST_P_(CompilerPerfTest, TestPerformance)
{
const auto params = GetParam();
Size sz = get<0>(params);
MatType type = get<1>(params);
initMatsRandU(type, sz, type, false);
// G-API code ////////////////////////////////////////////////////////////
cv::GMat in;
auto splitted = cv::gapi::split3(in);
auto add1 = cv::gapi::addC({1}, std::get<0>(splitted));
auto add2 = cv::gapi::addC({2}, std::get<1>(splitted));
auto add3 = cv::gapi::addC({3}, std::get<2>(splitted));
auto out = cv::gapi::merge3(add1, add2, add3);
TEST_CYCLE()
{
cv::GComputation c(in, out);
c.apply(in_mat1, out_mat_gapi, cv::compile_args(cv::gapi::core::fluid::kernels()));
}
SANITY_CHECK_NOTHING();
}
INSTANTIATE_TEST_CASE_P(CompilerPerfTest, CompilerPerfTest,
Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
Values(CV_8UC3)));
} // namespace opencv_test

@ -0,0 +1,11 @@
// 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) 2018 Intel Corporation
#include "perf_precomp.hpp"
//#include "../test/test_precomp.hpp"
CV_PERF_TEST_MAIN(gapi)

@ -0,0 +1,21 @@
// 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) 2018 Intel Corporation
#ifndef __OPENCV_GAPI_PERF_PRECOMP_HPP__
#define __OPENCV_GAPI_PERF_PRECOMP_HPP__
#include <cstdint>
#include <vector>
#include "opencv2/ts.hpp"
#include "opencv2/gapi.hpp"
#include "opencv2/gapi/imgproc.hpp"
#include "opencv2/gapi/core.hpp"
#include "opencv2/gapi/cpu/gcpukernel.hpp"
#include "opencv2/gapi/operators.hpp"
#endif

@ -0,0 +1 @@
This directory contains implementation of G-API frontend (public API classes).

@ -0,0 +1,43 @@
// 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) 2018 Intel Corporation
#include <ade/util/assert.hpp>
#include "api/gapi_priv.hpp"
#include "api/gnode_priv.hpp"
cv::GOrigin::GOrigin(GShape s,
const cv::GNode& n,
std::size_t p,
const cv::gimpl::HostCtor c)
: shape(s), node(n), port(p), ctor(c)
{
}
cv::GOrigin::GOrigin(GShape s, cv::gimpl::ConstVal v)
: shape(s), node(cv::GNode::Const()), value(v), port(INVALID_PORT)
{
}
bool cv::detail::GOriginCmp::operator() (const cv::GOrigin &lhs,
const cv::GOrigin &rhs) const
{
const GNode::Priv* lhs_p = &lhs.node.priv();
const GNode::Priv* rhs_p = &rhs.node.priv();
if (lhs_p == rhs_p)
{
if (lhs.port == rhs.port)
{
// A data Origin is uniquely identified by {node/port} pair.
// The situation when there're two Origins with same {node/port}s
// but with different shapes (data formats) is illegal!
GAPI_Assert(lhs.shape == rhs.shape);
}
return lhs.port < rhs.port;
}
else return lhs_p < rhs_p;
}

@ -0,0 +1,77 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_PRIV_HPP
#define OPENCV_GAPI_PRIV_HPP
#include <set> // set
#include <map> // map
#include <limits>
#include "opencv2/gapi/util/variant.hpp" // variant
#include "opencv2/gapi/garray.hpp" // ConstructVec
#include "opencv2/gapi/gscalar.hpp"
#include "opencv2/gapi/gcommon.hpp"
#include "opencv2/gapi/opencv_includes.hpp"
#include "api/gnode.hpp"
namespace cv
{
namespace gimpl
{
// Union type for various user-defined type constructors (GArray<T>, etc)
// FIXME: Replace construct-only API with a more generic one
// (probably with bits of introspection)
// Not required for non-user-defined types (GMat, GScalar, etc)
using HostCtor = util::variant
< util::monostate
, detail::ConstructVec
>;
using ConstVal = util::variant
< util::monostate
, cv::gapi::own::Scalar
>;
}
// TODO namespace gimpl?
struct GOrigin
{
static constexpr const std::size_t INVALID_PORT = std::numeric_limits<std::size_t>::max();
GOrigin(GShape s,
const GNode& n,
std::size_t p = INVALID_PORT,
const gimpl::HostCtor h = {});
GOrigin(GShape s, gimpl::ConstVal value);
const GShape shape; // Shape of a produced object
const GNode node; // a GNode which produces an object
const gimpl::ConstVal value; // Node can have initial constant value, now only scalar is supported
const std::size_t port; // GNode's output number; FIXME: "= max_size" in C++14
gimpl::HostCtor ctor; // FIXME: replace with an interface?
};
namespace detail
{
struct GOriginCmp
{
bool operator() (const GOrigin &lhs, const GOrigin &rhs) const;
};
} // namespace cv::details
// TODO introduce a hash on GOrigin and define this via unordered_ ?
using GOriginSet = std::set<GOrigin, detail::GOriginCmp>;
template<typename T> using GOriginMap = std::map<GOrigin, T, detail::GOriginCmp>;
} // namespace cv
#endif // OPENCV_GAPI_PRIV_HPP

@ -0,0 +1,44 @@
// 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) 2018 Intel Corporation
#include "opencv2/gapi/garray.hpp"
#include "api/gapi_priv.hpp" // GOrigin
// cv::detail::GArrayU public implementation ///////////////////////////////////
cv::detail::GArrayU::GArrayU()
: m_priv(new GOrigin(GShape::GARRAY, cv::GNode::Param()))
{
}
cv::detail::GArrayU::GArrayU(const GNode &n, std::size_t out)
: m_priv(new GOrigin(GShape::GARRAY, n, out))
{
}
cv::GOrigin& cv::detail::GArrayU::priv()
{
return *m_priv;
}
const cv::GOrigin& cv::detail::GArrayU::priv() const
{
return *m_priv;
}
void cv::detail::GArrayU::setConstructFcn(ConstructVec &&cv)
{
m_priv->ctor = std::move(cv);
}
namespace cv {
std::ostream& operator<<(std::ostream& os, const cv::GArrayDesc &)
{
// FIXME: add type information here
os << "(array)";
return os;
}
}

@ -0,0 +1,269 @@
// 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) 2018 Intel Corporation
#include <memory> // unique_ptr
#include "opencv2/gapi/gkernel.hpp"
#include "opencv2/gapi/own/convert.hpp"
#include "api/gbackend_priv.hpp"
#include "backends/common/gbackend.hpp"
#include "compiler/gobjref.hpp"
#include "compiler/gislandmodel.hpp"
// GBackend private implementation /////////////////////////////////////////////
void cv::gapi::GBackend::Priv::unpackKernel(ade::Graph & /*graph */ ,
const ade::NodeHandle & /*op_node*/ ,
const GKernelImpl & /*impl */ )
{
// Default implementation is still there as Priv
// is instantiated by some tests.
// Priv is even instantiated as a mock object in a number of tests
// as a backend and this method is called for mock objects (doing nothing).
// FIXME: add a warning message here
// FIXME: Do something with this! Ideally this function should be "=0";
}
std::unique_ptr<cv::gimpl::GIslandExecutable>
cv::gapi::GBackend::Priv::compile(const ade::Graph&,
const GCompileArgs&,
const std::vector<ade::NodeHandle> &) const
{
// ...and this method is here for the same reason!
GAPI_Assert(false);
return {};
}
void cv::gapi::GBackend::Priv::addBackendPasses(ade::ExecutionEngineSetupContext &)
{
// Do nothing by default, plugins may override this to
// add custom (backend-specific) graph transformations
}
// GBackend public implementation //////////////////////////////////////////////
cv::gapi::GBackend::GBackend()
{
}
cv::gapi::GBackend::GBackend(std::shared_ptr<cv::gapi::GBackend::Priv> &&p)
: m_priv(std::move(p))
{
}
cv::gapi::GBackend::Priv& cv::gapi::GBackend::priv()
{
return *m_priv;
}
const cv::gapi::GBackend::Priv& cv::gapi::GBackend::priv() const
{
return *m_priv;
}
std::size_t cv::gapi::GBackend::hash() const
{
return std::hash<const cv::gapi::GBackend::Priv*>{}(m_priv.get());
}
bool cv::gapi::GBackend::operator== (const cv::gapi::GBackend &rhs) const
{
return m_priv == rhs.m_priv;
}
// Abstract Host-side data manipulation ////////////////////////////////////////
// Reused between CPU backend and more generic GExecutor
namespace cv {
namespace gimpl {
namespace magazine {
// FIXME implement the below functions with visit()?
void bindInArg(Mag& mag, const RcDesc &rc, const GRunArg &arg)
{
switch (rc.shape)
{
case GShape::GMAT:
{
auto& mag_mat = mag.template slot<cv::gapi::own::Mat>()[rc.id];
switch (arg.index())
{
case GRunArg::index_of<cv::gapi::own::Mat>() : mag_mat = util::get<cv::gapi::own::Mat>(arg); break;
case GRunArg::index_of<cv::Mat>() : mag_mat = to_own(util::get<cv::Mat>(arg)); break;
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
}
break;
}
case GShape::GSCALAR:
{
auto& mag_scalar = mag.template slot<cv::gapi::own::Scalar>()[rc.id];
switch (arg.index())
{
case GRunArg::index_of<cv::gapi::own::Scalar>() : mag_scalar = util::get<cv::gapi::own::Scalar>(arg); break;
case GRunArg::index_of<cv::Scalar>() : mag_scalar = to_own(util::get<cv::Scalar>(arg)); break;
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
}
break;
}
case GShape::GARRAY:
mag.template slot<cv::detail::VectorRef>()[rc.id] = util::get<cv::detail::VectorRef>(arg);
break;
default:
util::throw_error(std::logic_error("Unsupported GShape type"));
}
}
void bindOutArg(Mag& mag, const RcDesc &rc, const GRunArgP &arg)
{
switch (rc.shape)
{
case GShape::GMAT:
{
auto& mag_mat = mag.template slot<cv::gapi::own::Mat>()[rc.id];
switch (arg.index())
{
case GRunArgP::index_of<cv::gapi::own::Mat*>() : mag_mat = * util::get<cv::gapi::own::Mat*>(arg); break;
case GRunArgP::index_of<cv::Mat*>() : mag_mat = to_own(* util::get<cv::Mat*>(arg)); break;
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
}
break;
}
case GShape::GSCALAR:
{
auto& mag_scalar = mag.template slot<cv::gapi::own::Scalar>()[rc.id];
switch (arg.index())
{
case GRunArgP::index_of<cv::gapi::own::Scalar*>() : mag_scalar = *util::get<cv::gapi::own::Scalar*>(arg); break;
case GRunArgP::index_of<cv::Scalar*>() : mag_scalar = to_own(*util::get<cv::Scalar*>(arg)); break;
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
}
break;
}
case GShape::GARRAY:
mag.template slot<cv::detail::VectorRef>()[rc.id] = util::get<cv::detail::VectorRef>(arg);
break;
default:
util::throw_error(std::logic_error("Unsupported GShape type"));
break;
}
}
void resetInternalData(Mag& mag, const Data &d)
{
if (d.storage != Data::Storage::INTERNAL)
return;
switch (d.shape)
{
case GShape::GARRAY:
util::get<cv::detail::ConstructVec>(d.ctor)
(mag.template slot<cv::detail::VectorRef>()[d.rc]);
break;
case GShape::GSCALAR:
mag.template slot<cv::gapi::own::Scalar>()[d.rc] = cv::gapi::own::Scalar();
break;
case GShape::GMAT:
// Do nothign here - FIXME unify with initInternalData?
break;
default:
util::throw_error(std::logic_error("Unsupported GShape type"));
break;
}
}
cv::GRunArg getArg(const Mag& mag, const RcDesc &ref)
{
// Wrap associated CPU object (either host or an internal one)
switch (ref.shape)
{
case GShape::GMAT: return GRunArg(mag.template slot<cv::gapi::own::Mat>().at(ref.id));
case GShape::GSCALAR: return GRunArg(mag.template slot<cv::gapi::own::Scalar>().at(ref.id));
// Note: .at() is intentional for GArray as object MUST be already there
// (and constructed by either bindIn/Out or resetInternal)
case GShape::GARRAY: return GRunArg(mag.template slot<cv::detail::VectorRef>().at(ref.id));
default:
util::throw_error(std::logic_error("Unsupported GShape type"));
break;
}
}
cv::GRunArgP getObjPtr(Mag& mag, const RcDesc &rc)
{
switch (rc.shape)
{
case GShape::GMAT: return GRunArgP(&mag.template slot<cv::gapi::own::Mat>() [rc.id]);
case GShape::GSCALAR: return GRunArgP(&mag.template slot<cv::gapi::own::Scalar>()[rc.id]);
// Note: .at() is intentional for GArray as object MUST be already there
// (and constructer by either bindIn/Out or resetInternal)
case GShape::GARRAY:
// FIXME(DM): For some absolutely unknown to me reason, move
// semantics is involved here without const_cast to const (and
// value from map is moved into return value GRunArgP, leaving
// map with broken value I've spent few late Friday hours
// debugging this!!!1
return GRunArgP(const_cast<const Mag&>(mag)
.template slot<cv::detail::VectorRef>().at(rc.id));
default:
util::throw_error(std::logic_error("Unsupported GShape type"));
break;
}
}
void writeBack(const Mag& mag, const RcDesc &rc, GRunArgP &g_arg)
{
switch (rc.shape)
{
case GShape::GARRAY:
// Do nothing - should we really do anything here?
break;
case GShape::GMAT:
{
//simply check that memory was not reallocated, i.e.
//both instances of Mat pointing to the same memory
uchar* out_arg_data = nullptr;
switch (g_arg.index())
{
case GRunArgP::index_of<cv::gapi::own::Mat*>() : out_arg_data = util::get<cv::gapi::own::Mat*>(g_arg)->data; break;
case GRunArgP::index_of<cv::Mat*>() : out_arg_data = util::get<cv::Mat*>(g_arg)->data; break;
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
}
auto& in_mag = mag.template slot<cv::gapi::own::Mat>().at(rc.id);
GAPI_Assert((out_arg_data == in_mag.data) && " data for output parameters was reallocated ?");
break;
}
case GShape::GSCALAR:
{
switch (g_arg.index())
{
case GRunArgP::index_of<cv::gapi::own::Scalar*>() : *util::get<cv::gapi::own::Scalar*>(g_arg) = mag.template slot<cv::gapi::own::Scalar>().at(rc.id); break;
case GRunArgP::index_of<cv::Scalar*>() : *util::get<cv::Scalar*>(g_arg) = cv::gapi::own::to_ocv(mag.template slot<cv::gapi::own::Scalar>().at(rc.id)); break;
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
}
break;
}
default:
util::throw_error(std::logic_error("Unsupported GShape type"));
break;
}
}
} // namespace magazine
} // namespace gimpl
} // namespace cv

@ -0,0 +1,53 @@
// 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) 2018 Intel Corporation
#ifndef GAPI_API_GBACKEND_PRIV_HPP
#define GAPI_API_GBACKEND_PRIV_HPP
#include <memory>
#include <unordered_set>
#include <ade/graph.hpp>
#include <ade/passes/pass_base.hpp> // passes::PassContext
#include <ade/execution_engine/execution_engine.hpp> // ..SetupContext
#include "opencv2/gapi/gcommon.hpp"
#include "opencv2/gapi/gkernel.hpp"
namespace cv
{
namespace gimpl
{
class GBackend;
class GIslandExecutable;
} // namespace gimpl
} // namespace cv
// GAPI_EXPORTS is here to make tests build on Windows
class GAPI_EXPORTS cv::gapi::GBackend::Priv
{
public:
using EPtr = std::unique_ptr<cv::gimpl::GIslandExecutable>;
virtual void unpackKernel(ade::Graph &graph,
const ade::NodeHandle &op_node,
const GKernelImpl &impl);
// FIXME: since backends are not passed to ADE anymore,
// there's no need in having both cv::gimpl::GBackend
// and cv::gapi::GBackend - these two things can be unified
// NOTE - nodes are guaranteed to be topologically sorted.
virtual EPtr compile(const ade::Graph &graph,
const GCompileArgs &args,
const std::vector<ade::NodeHandle> &nodes) const;
virtual void addBackendPasses(ade::ExecutionEngineSetupContext &);
virtual ~Priv() = default;
};
#endif // GAPI_API_GBACKEND_PRIV_HPP

@ -0,0 +1,64 @@
// 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) 2018 Intel Corporation
#include <cassert>
#include "opencv2/gapi/gcall.hpp"
#include "api/gcall_priv.hpp"
// GCall private implementation ////////////////////////////////////////////////
cv::GCall::Priv::Priv(const cv::GKernel &k)
: m_k(k)
{
}
// GCall public implementation /////////////////////////////////////////////////
cv::GCall::GCall(const cv::GKernel &k)
: m_priv(new Priv(k))
{
// Here we have a reference to GNode,
// and GNode has a reference to us. Cycle! Now see destructor.
m_priv->m_node = GNode::Call(*this);
}
cv::GCall::~GCall()
{
// When a GCall object is destroyed (and GCall::Priv is likely still alive,
// as there might be other references), reset m_node to break cycle.
m_priv->m_node = GNode();
}
void cv::GCall::setArgs(std::vector<GArg> &&args)
{
// FIXME: Check if argument number is matching kernel prototype
m_priv->m_args = std::move(args);
}
cv::GMat cv::GCall::yield(int output)
{
return cv::GMat(m_priv->m_node, output);
}
cv::GScalar cv::GCall::yieldScalar(int output)
{
return cv::GScalar(m_priv->m_node, output);
}
cv::detail::GArrayU cv::GCall::yieldArray(int output)
{
return cv::detail::GArrayU(m_priv->m_node, output);
}
cv::GCall::Priv& cv::GCall::priv()
{
return *m_priv;
}
const cv::GCall::Priv& cv::GCall::priv() const
{
return *m_priv;
}

@ -0,0 +1,37 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GCALL_PRIV_HPP
#define OPENCV_GCALL_PRIV_HPP
#include <vector>
#include <unordered_map>
#include "opencv2/gapi/garg.hpp"
#include "opencv2/gapi/gcall.hpp"
#include "opencv2/gapi/gkernel.hpp"
#include "api/gnode.hpp"
namespace cv {
class GCall::Priv
{
public:
std::vector<GArg> m_args;
const GKernel m_k;
// FIXME: Document that there's no recursion here.
// TODO: Rename to "constructionNode" or smt to reflect its lifetime
GNode m_node;
explicit Priv(const GKernel &k);
};
}
#endif // OPENCV_GCALL_PRIV_HPP

@ -0,0 +1,191 @@
// 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) 2018 Intel Corporation
#include <algorithm> // remove_if
#include <cctype> // isspace (non-locale version)
#include <ade/util/algorithm.hpp>
#include "opencv2/core/cvdef.h"
#include "logger.hpp" // GAPI_LOG
#include "opencv2/gapi/gcomputation.hpp"
#include "opencv2/gapi/gkernel.hpp"
#include "api/gcomputation_priv.hpp"
#include "api/gcall_priv.hpp"
#include "api/gnode_priv.hpp"
#include "compiler/gmodelbuilder.hpp"
#include "compiler/gcompiler.hpp"
// cv::GComputation private implementation /////////////////////////////////////
// <none>
// cv::GComputation public implementation //////////////////////////////////////
cv::GComputation::GComputation(const Generator& gen)
: m_priv(gen().m_priv)
{
}
cv::GComputation::GComputation(GMat in, GMat out)
: cv::GComputation(cv::GIn(in), cv::GOut(out))
{
}
cv::GComputation::GComputation(GMat in, GScalar out)
: cv::GComputation(cv::GIn(in), cv::GOut(out))
{
}
cv::GComputation::GComputation(GMat in1, GMat in2, GMat out)
: cv::GComputation(cv::GIn(in1, in2), cv::GOut(out))
{
}
cv::GComputation::GComputation(GMat in1, GMat in2, GScalar out)
: cv::GComputation(cv::GIn(in1, in2), cv::GOut(out))
{
}
cv::GComputation::GComputation(const std::vector<GMat> &ins,
const std::vector<GMat> &outs)
: m_priv(new Priv())
{
const auto wrap = [](cv::GMat m) { return GProtoArg(m); };
ade::util::transform(ins, std::back_inserter(m_priv->m_ins), wrap);
ade::util::transform(outs, std::back_inserter(m_priv->m_outs), wrap);
}
cv::GComputation::GComputation(cv::GProtoInputArgs &&ins,
cv::GProtoOutputArgs &&outs)
: m_priv(new Priv())
{
m_priv->m_ins = std::move(ins.m_args);
m_priv->m_outs = std::move(outs.m_args);
}
cv::GCompiled cv::GComputation::compile(GMetaArgs &&metas, GCompileArgs &&args)
{
// FIXME: Cache gcompiled per parameters here?
cv::gimpl::GCompiler comp(*this, std::move(metas), std::move(args));
return comp.compile();
}
void cv::GComputation::apply(GRunArgs &&ins, GRunArgsP &&outs, GCompileArgs &&args)
{
const auto in_metas = descr_of(ins);
// FIXME Graph should be recompiled when GCompileArgs have changed
if (m_priv->m_lastMetas != in_metas)
{
// FIXME: Had to construct temporary object as compile() takes && (r-value)
m_priv->m_lastCompiled = compile(GMetaArgs(in_metas), std::move(args));
m_priv->m_lastMetas = in_metas; // Update only here, if compile() was ok
}
m_priv->m_lastCompiled(std::move(ins), std::move(outs));
}
void cv::GComputation::apply(cv::Mat in, cv::Mat &out, GCompileArgs &&args)
{
apply(cv::gin(in), cv::gout(out), std::move(args));
// FIXME: The following doesn't work!
// Operation result is not replicated into user's object
// apply({GRunArg(in)}, {GRunArg(out)});
}
void cv::GComputation::apply(cv::Mat in, cv::Scalar &out, GCompileArgs &&args)
{
apply(cv::gin(in), cv::gout(out), std::move(args));
}
void cv::GComputation::apply(cv::Mat in1, cv::Mat in2, cv::Mat &out, GCompileArgs &&args)
{
apply(cv::gin(in1, in2), cv::gout(out), std::move(args));
}
void cv::GComputation::apply(cv::Mat in1, cv::Mat in2, cv::Scalar &out, GCompileArgs &&args)
{
apply(cv::gin(in1, in2), cv::gout(out), std::move(args));
}
void cv::GComputation::apply(const std::vector<cv::Mat> &ins,
const std::vector<cv::Mat> &outs,
GCompileArgs &&args)
{
GRunArgs call_ins;
GRunArgsP call_outs;
// Make a temporary copy of vector outs - cv::Mats are copies anyway
auto tmp = outs;
for (const cv::Mat &m : ins) { call_ins.emplace_back(m); }
for ( cv::Mat &m : tmp) { call_outs.emplace_back(&m); }
apply(std::move(call_ins), std::move(call_outs), std::move(args));
}
cv::GComputation::Priv& cv::GComputation::priv()
{
return *m_priv;
}
const cv::GComputation::Priv& cv::GComputation::priv() const
{
return *m_priv;
}
// Islands /////////////////////////////////////////////////////////////////////
void cv::gapi::island(const std::string &name,
GProtoInputArgs &&ins,
GProtoOutputArgs &&outs)
{
{
// Island must have a printable name.
// Forbid names which contain only spaces.
GAPI_Assert(!name.empty());
const auto first_printable_it = std::find_if_not(name.begin(), name.end(), isspace);
const bool likely_printable = first_printable_it != name.end();
GAPI_Assert(likely_printable);
}
// Even if the name contains spaces, keep it unmodified as user will
// then use this string to assign affinity, etc.
// First, set island tags on all operations from `ins` to `outs`
auto island = cv::gimpl::unrollExpr(ins.m_args, outs.m_args);
if (island.all_ops.empty())
{
util::throw_error(std::logic_error("Operation range is empty"));
}
for (auto &op_expr_node : island.all_ops)
{
auto &op_expr_node_p = op_expr_node.priv();
GAPI_Assert(op_expr_node.shape() == GNode::NodeShape::CALL);
const GCall& call = op_expr_node.call();
const GCall::Priv& call_p = call.priv();
if (!op_expr_node_p.m_island.empty())
{
util::throw_error(std::logic_error
( "Operation " + call_p.m_k.name
+ " is already assigned to island \""
+ op_expr_node_p.m_island + "\""));
}
else
{
op_expr_node_p.m_island = name;
GAPI_LOG_INFO(NULL,
"Assigned " << call_p.m_k.name << "_" << &call_p <<
" to island \"" << name << "\"");
}
}
// Note - this function only sets islands to all operations in
// expression tree, it is just a first step.
// The second step is assigning intermediate data objects to Islands,
// see passes::initIslands for details.
}

@ -0,0 +1,29 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GCOMPUTATION_PRIV_HPP
#define OPENCV_GAPI_GCOMPUTATION_PRIV_HPP
#include "opencv2/gapi.hpp"
#include "opencv2/gapi/gcall.hpp"
#include "opencv2/gapi/util/variant.hpp"
namespace cv {
class GComputation::Priv
{
public:
GCompiled m_lastCompiled;
GMetaArgs m_lastMetas; // TODO: make GCompiled remember its metas?
GProtoArgs m_ins;
GProtoArgs m_outs;
};
}
#endif // OPENCV_GAPI_GCOMPUTATION_PRIV_HPP

@ -0,0 +1,141 @@
// 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) 2018 Intel Corporation
#include <iostream> // cerr
#include <functional> // hash
#include <numeric> // accumulate
#include <ade/util/algorithm.hpp>
#include "opencv2/core/cvdef.h"
#include "logger.hpp"
#include "opencv2/gapi/gkernel.hpp"
#include "api/gbackend_priv.hpp"
// GKernelPackage public implementation ////////////////////////////////////////
void cv::gapi::GKernelPackage::remove(const cv::gapi::GBackend& backend)
{
m_backend_kernels.erase(backend);
}
bool cv::gapi::GKernelPackage::includesAPI(const std::string &id) const
{
// In current form not very efficient (n * log n)
auto it = std::find_if(m_backend_kernels.begin(),
m_backend_kernels.end(),
[&id](const M::value_type &p) {
return ade::util::contains(p.second, id);
});
return (it != m_backend_kernels.end());
}
std::size_t cv::gapi::GKernelPackage::size() const
{
return std::accumulate(m_backend_kernels.begin(),
m_backend_kernels.end(),
static_cast<std::size_t>(0u),
[](std::size_t acc, const M::value_type& v) {
return acc + v.second.size();
});
}
cv::gapi::GKernelPackage cv::gapi::combine(const GKernelPackage &lhs,
const GKernelPackage &rhs,
const cv::unite_policy policy)
{
if (policy == cv::unite_policy::REPLACE)
{
// REPLACE policy: if there is a collision, prefer RHS
// to LHS
// since OTHER package has a prefernece, start with its copy
GKernelPackage result(rhs);
// now iterate over LHS package and put kernel if and only
// if there's no such one
for (const auto &backend : lhs.m_backend_kernels)
{
for (const auto &kimpl : backend.second)
{
if (!result.includesAPI(kimpl.first))
result.m_backend_kernels[backend.first].insert(kimpl);
}
}
return result;
}
else if (policy == cv::unite_policy::KEEP)
{
// KEEP policy: if there is a collision, just keep two versions
// of a kernel
GKernelPackage result(lhs);
for (const auto &p : rhs.m_backend_kernels)
{
result.m_backend_kernels[p.first].insert(p.second.begin(),
p.second.end());
}
return result;
}
else GAPI_Assert(false);
return GKernelPackage();
}
std::pair<cv::gapi::GBackend, cv::GKernelImpl>
cv::gapi::GKernelPackage::lookup(const std::string &id,
const GLookupOrder &order) const
{
if (order.empty())
{
// If order is empty, return what comes first
auto it = std::find_if(m_backend_kernels.begin(),
m_backend_kernels.end(),
[&id](const M::value_type &p) {
return ade::util::contains(p.second, id);
});
if (it != m_backend_kernels.end())
{
// FIXME: Two lookups!
return std::make_pair(it->first, it->second.find(id)->second);
}
}
else
{
// There is order, so:
// 1. Limit search scope only to specified backends
// FIXME: Currently it is not configurable if search can fall-back
// to other backends (not listed in order) if kernel hasn't been found
// in the look-up list
// 2. Query backends in the specified order
for (const auto &selected_backend : order)
{
const auto kernels_it = m_backend_kernels.find(selected_backend);
if (kernels_it == m_backend_kernels.end())
{
GAPI_LOG_WARNING(NULL,
"Backend "
<< &selected_backend.priv() // FIXME: name instead
<< " was listed in lookup list but was not found "
"in the package");
continue;
}
if (ade::util::contains(kernels_it->second, id))
{
// FIXME: two lookups!
return std::make_pair(selected_backend, kernels_it->second.find(id)->second);
}
}
}
// If reached here, kernel was not found among selected backends.
util::throw_error(std::logic_error("Kernel " + id + " was not found"));
}
std::vector<cv::gapi::GBackend> cv::gapi::GKernelPackage::backends() const
{
std::vector<cv::gapi::GBackend> result;
for (const auto &p : m_backend_kernels) result.emplace_back(p.first);
return result;
}

@ -0,0 +1,71 @@
// 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) 2018 Intel Corporation
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/own/mat.hpp> //gapi::own::Mat
#include "opencv2/gapi/gmat.hpp"
#include "api/gapi_priv.hpp" // GOrigin
// cv::GMat public implementation //////////////////////////////////////////////
cv::GMat::GMat()
: m_priv(new GOrigin(GShape::GMAT, GNode::Param()))
{
}
cv::GMat::GMat(const GNode &n, std::size_t out)
: m_priv(new GOrigin(GShape::GMAT, n, out))
{
}
cv::GOrigin& cv::GMat::priv()
{
return *m_priv;
}
const cv::GOrigin& cv::GMat::priv() const
{
return *m_priv;
}
cv::GMatDesc cv::descr_of(const cv::Mat &mat)
{
return GMatDesc{mat.depth(), mat.channels(), {mat.cols, mat.rows}};
}
cv::GMatDesc cv::gapi::own::descr_of(const cv::gapi::own::Mat &mat)
{
return GMatDesc{mat.depth(), mat.channels(), {mat.cols, mat.rows}};
}
namespace cv {
std::ostream& operator<<(std::ostream& os, const cv::GMatDesc &desc)
{
switch (desc.depth)
{
#define TT(X) case CV_##X: os << #X; break;
TT(8U);
TT(8S);
TT(16U);
TT(16S);
TT(32S);
TT(32F);
TT(64F);
#undef TT
default:
os << "(user type "
<< std::hex << desc.depth << std::dec
<< ")";
break;
}
os << "C" << desc.chan << " ";
os << desc.size.width << "x" << desc.size.height;
return os;
}
}

@ -0,0 +1,88 @@
// 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) 2018 Intel Corporation
#include <cassert>
#include "api/gnode.hpp"
#include "api/gnode_priv.hpp"
// GNode private implementation
cv::GNode::Priv::Priv()
: m_shape(NodeShape::EMPTY)
{
}
cv::GNode::Priv::Priv(GCall c)
: m_shape(NodeShape::CALL), m_spec(c)
{
}
cv::GNode::Priv::Priv(ParamTag)
: m_shape(NodeShape::PARAM)
{
}
cv::GNode::Priv::Priv(ConstTag)
: m_shape(NodeShape::CONST_BOUNDED)
{
}
// GNode public implementation
cv::GNode::GNode()
: m_priv(new Priv())
{
}
cv::GNode::GNode(const GCall &c)
: m_priv(new Priv(c))
{
}
cv::GNode::GNode(ParamTag)
: m_priv(new Priv(Priv::ParamTag()))
{
}
cv::GNode::GNode(ConstTag)
: m_priv(new Priv(Priv::ConstTag()))
{
}
cv::GNode cv::GNode::Call(const GCall &c)
{
return GNode(c);
}
cv::GNode cv::GNode::Param()
{
return GNode(ParamTag());
}
cv::GNode cv::GNode::Const()
{
return GNode(ConstTag());
}
cv::GNode::Priv& cv::GNode::priv()
{
return *m_priv;
}
const cv::GNode::Priv& cv::GNode::priv() const
{
return *m_priv;
}
const cv::GNode::NodeShape& cv::GNode::shape() const
{
return m_priv->m_shape;
}
const cv::GCall& cv::GNode::call() const
{
return util::get<GCall>(m_priv->m_spec);
}

@ -0,0 +1,58 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GNODE_HPP
#define OPENCV_GAPI_GNODE_HPP
#include <memory> // std::shared_ptr
namespace cv {
class GCall;
// TODO Move "internal" namespace
// TODO Expose details?
// This class won't be public
// data GNode = Call Operation [GNode]
// | Const <T>
// | Param <GMat|GParam>
class GNode
{
public:
class Priv;
// Constructors
GNode(); // Empty (invalid) constructor
static GNode Call (const GCall &c); // Call constructor
static GNode Param(); // Param constructor
static GNode Const();
// Internal use only
Priv& priv();
const Priv& priv() const;
enum class NodeShape: unsigned int;
const NodeShape& shape() const;
const GCall& call() const;
protected:
struct ParamTag {};
struct ConstTag {};
explicit GNode(const GCall &c);
explicit GNode(ParamTag unused);
explicit GNode(ConstTag unused);
std::shared_ptr<Priv> m_priv;
};
}
#endif // OPENCV_GAPI_GNODE_HPP

@ -0,0 +1,52 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GNODE_PRIV_HPP
#define OPENCV_GNODE_PRIV_HPP
#include <string>
#include <vector>
#include <unordered_map>
#include "opencv2/gapi/util/variant.hpp"
#include "opencv2/gapi/gcall.hpp"
#include "opencv2/gapi/garg.hpp"
#include "opencv2/gapi/gkernel.hpp"
#include "api/gnode.hpp"
namespace cv {
enum class GNode::NodeShape: unsigned int
{
EMPTY,
CALL,
PARAM,
CONST_BOUNDED
};
class GNode::Priv
{
public:
// TODO: replace with optional?
typedef util::variant<util::monostate, GCall> NodeSpec;
const NodeShape m_shape;
const NodeSpec m_spec;
std::string m_island; // user-modifiable attribute
struct ParamTag {};
struct ConstTag {};
Priv(); // Empty (invalid) constructor
explicit Priv(GCall c); // Call conctrustor
explicit Priv(ParamTag u); // Param constructor
explicit Priv(ConstTag u); // Param constructor
};
}
#endif // OPENCV_GNODE_PRIV_HPP

@ -0,0 +1,152 @@
// 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) 2018 Intel Corporation
#include <ade/util/algorithm.hpp>
#include "opencv2/gapi/util/throw.hpp"
#include "opencv2/gapi/garg.hpp"
#include "opencv2/gapi/gproto.hpp"
#include "api/gapi_priv.hpp"
#include "api/gproto_priv.hpp"
// FIXME: it should be a visitor!
// FIXME: Reimplement with traits?
const cv::GOrigin& cv::gimpl::proto::origin_of(const cv::GProtoArg &arg)
{
switch (arg.index())
{
case cv::GProtoArg::index_of<cv::GMat>():
return util::get<cv::GMat>(arg).priv();
case cv::GProtoArg::index_of<cv::GScalar>():
return util::get<cv::GScalar>(arg).priv();
case cv::GProtoArg::index_of<cv::detail::GArrayU>():
return util::get<cv::detail::GArrayU>(arg).priv();
default:
util::throw_error(std::logic_error("Unsupported GProtoArg type"));
}
}
const cv::GOrigin& cv::gimpl::proto::origin_of(const cv::GArg &arg)
{
// Generic, but not very efficient implementation
// FIXME: Walking a thin line here!!! Here we rely that GArg and
// GProtoArg share the same object and this is true while objects
// are reference-counted, so return value is not a reference to a tmp.
return origin_of(rewrap(arg));
}
bool cv::gimpl::proto::is_dynamic(const cv::GArg& arg)
{
// FIXME: refactor this method to be auto-generated from
// - GProtoArg variant parameter pack, and
// - traits over every type
switch (arg.kind)
{
case detail::ArgKind::GMAT:
case detail::ArgKind::GSCALAR:
case detail::ArgKind::GARRAY:
return true;
default:
return false;
}
}
cv::GRunArg cv::value_of(const cv::GOrigin &origin)
{
switch (origin.shape)
{
case GShape::GSCALAR: return GRunArg(util::get<cv::gapi::own::Scalar>(origin.value));
default: util::throw_error(std::logic_error("Unsupported shape for constant"));
}
}
cv::GProtoArg cv::gimpl::proto::rewrap(const cv::GArg &arg)
{
// FIXME: replace with a more generic any->variant
// (or variant<T> -> variant<U>) conversion?
switch (arg.kind)
{
case detail::ArgKind::GMAT: return GProtoArg(arg.get<cv::GMat>());
case detail::ArgKind::GSCALAR: return GProtoArg(arg.get<cv::GScalar>());
case detail::ArgKind::GARRAY: return GProtoArg(arg.get<cv::detail::GArrayU>());
default: util::throw_error(std::logic_error("Unsupported GArg type"));
}
}
cv::GMetaArg cv::descr_of(const cv::GRunArg &arg)
{
switch (arg.index())
{
case GRunArg::index_of<cv::Mat>():
return cv::GMetaArg(descr_of(util::get<cv::Mat>(arg)));
case GRunArg::index_of<cv::Scalar>():
return cv::GMetaArg(descr_of(util::get<cv::Scalar>(arg)));
case GRunArg::index_of<cv::gapi::own::Scalar>():
return cv::GMetaArg(descr_of(util::get<cv::gapi::own::Scalar>(arg)));
case GRunArg::index_of<cv::detail::VectorRef>():
return cv::GMetaArg(util::get<cv::detail::VectorRef>(arg).descr_of());
default: util::throw_error(std::logic_error("Unsupported GRunArg type"));
}
}
cv::GMetaArgs cv::descr_of(const cv::GRunArgs &args)
{
cv::GMetaArgs metas;
ade::util::transform(args, std::back_inserter(metas), [](const cv::GRunArg &arg){ return descr_of(arg); });
return metas;
}
cv::GMetaArg cv::descr_of(const cv::GRunArgP &argp)
{
switch (argp.index())
{
case GRunArgP::index_of<cv::Mat*>(): return GMetaArg(descr_of(*util::get<cv::Mat*>(argp)));
case GRunArgP::index_of<cv::gapi::own::Mat*>(): return GMetaArg(descr_of(*util::get<cv::gapi::own::Mat*>(argp)));
case GRunArgP::index_of<cv::Scalar*>(): return GMetaArg(descr_of(*util::get<cv::Scalar*>(argp)));
case GRunArgP::index_of<cv::gapi::own::Scalar*>(): return GMetaArg(descr_of(*util::get<cv::gapi::own::Scalar*>(argp)));
case GRunArgP::index_of<cv::detail::VectorRef>(): return GMetaArg(util::get<cv::detail::VectorRef>(argp).descr_of());
default: util::throw_error(std::logic_error("Unsupported GRunArgP type"));
}
}
namespace cv {
std::ostream& operator<<(std::ostream& os, const cv::GMetaArg &arg)
{
// FIXME: Implement via variant visitor
switch (arg.index())
{
case cv::GMetaArg::index_of<util::monostate>():
os << "(unresolved)";
break;
case cv::GMetaArg::index_of<cv::GMatDesc>():
os << util::get<cv::GMatDesc>(arg);
break;
case cv::GMetaArg::index_of<cv::GScalarDesc>():
os << util::get<cv::GScalarDesc>(arg);
break;
case cv::GMetaArg::index_of<cv::GArrayDesc>():
os << util::get<cv::GArrayDesc>(arg);
break;
default:
GAPI_Assert(false);
}
return os;
}
}

@ -0,0 +1,35 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GPROTO_PRIV_HPP
#define OPENCV_GAPI_GPROTO_PRIV_HPP
#include "opencv2/gapi/gproto.hpp"
#include "opencv2/gapi/garg.hpp"
#include "api/gapi_priv.hpp"
namespace cv {
namespace gimpl {
namespace proto {
// These methods are used by GModelBuilder only
// FIXME: Document semantics
// FIXME: GAPI_EXPORTS because of tests only!
// FIXME: Possible dangling reference alert!!!
GAPI_EXPORTS const GOrigin& origin_of (const GProtoArg &arg);
GAPI_EXPORTS const GOrigin& origin_of (const GArg &arg);
bool is_dynamic(const GArg &arg);
GProtoArg rewrap (const GArg &arg);
} // proto
} // gimpl
} // cv
#endif // OPENCV_GAPI_GPROTO_PRIV_HPP

@ -0,0 +1,69 @@
// 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) 2018 Intel Corporation
#include "opencv2/gapi/gscalar.hpp"
#include "opencv2/gapi/own/convert.hpp"
#include "api/gapi_priv.hpp" // GOrigin
// cv::GScalar public implementation ///////////////////////////////////////////
cv::GScalar::GScalar()
: m_priv(new GOrigin(GShape::GSCALAR, cv::GNode::Param()))
{
}
cv::GScalar::GScalar(const GNode &n, std::size_t out)
: m_priv(new GOrigin(GShape::GSCALAR, n, out))
{
}
cv::GScalar::GScalar(const cv::gapi::own::Scalar& s)
: m_priv(new GOrigin(GShape::GSCALAR, cv::gimpl::ConstVal(s)))
{
}
cv::GScalar::GScalar(cv::gapi::own::Scalar&& s)
: m_priv(new GOrigin(GShape::GSCALAR, cv::gimpl::ConstVal(std::move(s))))
{
}
cv::GScalar::GScalar(const cv::Scalar& s)
: m_priv(new GOrigin(GShape::GSCALAR, cv::gimpl::ConstVal(to_own(s))))
{
}
cv::GScalar::GScalar(double v0)
: m_priv(new GOrigin(GShape::GSCALAR, cv::gimpl::ConstVal(cv::gapi::own::Scalar(v0))))
{
}
cv::GOrigin& cv::GScalar::priv()
{
return *m_priv;
}
const cv::GOrigin& cv::GScalar::priv() const
{
return *m_priv;
}
cv::GScalarDesc cv::descr_of(const cv::gapi::own::Scalar &)
{
return empty_scalar_desc();
}
cv::GScalarDesc cv::descr_of(const cv::Scalar& s)
{
return cv::descr_of(to_own(s));
}
namespace cv {
std::ostream& operator<<(std::ostream& os, const cv::GScalarDesc &)
{
os << "(scalar)";
return os;
}
}

@ -0,0 +1,347 @@
// 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) 2018 Intel Corporation
#include "opencv2/gapi/gcall.hpp"
#include "opencv2/gapi/gscalar.hpp"
#include "opencv2/gapi/gkernel.hpp"
#include "opencv2/gapi/core.hpp"
#include <tuple>
#include <numeric>
namespace cv { namespace gapi {
GMat add(const GMat& src1, const GMat& src2, int dtype)
{
return core::GAdd::on(src1, src2, dtype);
}
GMat addC(const GMat& src1, const GScalar& c, int dtype)
{
return core::GAddC::on(src1, c, dtype);
}
GMat addC(const GScalar& c, const GMat& src1, int dtype)
{
return core::GAddC::on(src1, c, dtype);
}
GMat sub(const GMat& src1, const GMat& src2, int dtype)
{
return core::GSub::on(src1, src2, dtype);
}
GMat subC(const GMat& src1, const GScalar& c, int dtype)
{
return core::GSubC::on(src1, c, dtype);
}
GMat subRC(const GScalar& c, const GMat& src, int dtype)
{
return core::GSubRC::on(c, src, dtype);
}
GMat mul(const GMat& src1, const GMat& src2, double scale, int dtype)
{
return core::GMul::on(src1, src2, scale, dtype);
}
GMat mulC(const GMat& src, double scale, int dtype)
{
return core::GMulCOld::on(src, scale, dtype);
}
GMat mulC(const GMat& src, const GScalar& multiplier, int dtype)
{
return core::GMulC::on(src, multiplier, dtype);
}
GMat mulC(const GScalar& multiplier, const GMat& src, int dtype)
{
return core::GMulC::on(src, multiplier, dtype);
}
GMat div(const GMat& src1, const GMat& src2, double scale, int dtype)
{
return core::GDiv::on(src1, src2, scale, dtype);
}
GMat divC(const GMat& src, const GScalar& divisor, double scale, int dtype)
{
return core::GDivC::on(src, divisor, scale, dtype);
}
GMat divRC(const GScalar& divident, const GMat& src, double scale, int dtype)
{
return core::GDivRC::on(divident, src, scale, dtype);
}
GScalar mean(const GMat& src)
{
return core::GMean::on(src);
}
GMat mask(const GMat& src, const GMat& mask)
{
return core::GMask::on(src, mask);
}
std::tuple<GMat, GMat> polarToCart(const GMat& magnitude, const GMat& angle,
bool angleInDegrees)
{
return core::GPolarToCart::on(magnitude, angle, angleInDegrees);
}
std::tuple<GMat, GMat> cartToPolar(const GMat& x, const GMat& y,
bool angleInDegrees)
{
return core::GCartToPolar::on(x, y, angleInDegrees);
}
GMat cmpGT(const GMat& src1, const GMat& src2)
{
return core::GCmpGT::on(src1, src2);
}
GMat cmpLT(const GMat& src1, const GMat& src2)
{
return core::GCmpLT::on(src1, src2);
}
GMat cmpGE(const GMat& src1, const GMat& src2)
{
return core::GCmpGE::on(src1, src2);
}
GMat cmpLE(const GMat& src1, const GMat& src2)
{
return core::GCmpLE::on(src1, src2);
}
GMat cmpEQ(const GMat& src1, const GMat& src2)
{
return core::GCmpEQ::on(src1, src2);
}
GMat cmpNE(const GMat& src1, const GMat& src2)
{
return core::GCmpNE::on(src1, src2);
}
GMat cmpGT(const GMat& src1, const GScalar& src2)
{
return core::GCmpGTScalar::on(src1, src2);
}
GMat cmpLT(const GMat& src1, const GScalar& src2)
{
return core::GCmpLTScalar::on(src1, src2);
}
GMat cmpGE(const GMat& src1, const GScalar& src2)
{
return core::GCmpGEScalar::on(src1, src2);
}
GMat cmpLE(const GMat& src1, const GScalar& src2)
{
return core::GCmpLEScalar::on(src1, src2);
}
GMat cmpEQ(const GMat& src1, const GScalar& src2)
{
return core::GCmpEQScalar::on(src1, src2);
}
GMat cmpNE(const GMat& src1, const GScalar& src2)
{
return core::GCmpNEScalar::on(src1, src2);
}
GMat min(const GMat& src1, const GMat& src2)
{
return core::GMin::on(src1, src2);
}
GMat max(const GMat& src1, const GMat& src2)
{
return core::GMax::on(src1, src2);
}
GMat absDiff(const GMat& src1, const GMat& src2)
{
return core::GAbsDiff::on(src1, src2);
}
GMat absDiffC(const GMat& src, const GScalar& c)
{
return core::GAbsDiffC::on(src, c);
}
GMat bitwise_and(const GMat& src1, const GMat& src2)
{
return core::GAnd::on(src1, src2);
}
GMat bitwise_and(const GMat& src1, const GScalar& src2)
{
return core::GAndS::on(src1, src2);
}
GMat bitwise_or(const GMat& src1, const GMat& src2)
{
return core::GOr::on(src1, src2);
}
GMat bitwise_or(const GMat& src1, const GScalar& src2)
{
return core::GOrS::on(src1, src2);
}
GMat bitwise_xor(const GMat& src1, const GMat& src2)
{
return core::GXor::on(src1, src2);
}
GMat bitwise_xor(const GMat& src1, const GScalar& src2)
{
return core::GXorS::on(src1, src2);
}
GMat bitwise_not(const GMat& src1)
{
return core::GNot::on(src1);
}
GMat select(const GMat& src1, const GMat& src2, const GMat& mask)
{
return core::GSelect::on(src1, src2, mask);
}
GScalar sum(const GMat& src)
{
return core::GSum::on(src);
}
GMat addWeighted(const GMat& src1, double alpha, const GMat& src2, double beta, double gamma, int dtype)
{
return core::GAddW::on(src1, alpha, src2, beta, gamma, dtype);
}
GScalar normL1(const GMat& src)
{
return core::GNormL1::on(src);
}
GScalar normL2(const GMat& src)
{
return core::GNormL2::on(src);
}
GScalar normInf(const GMat& src)
{
return core::GNormInf::on(src);
}
std::tuple<GMat, GMat> integral(const GMat& src, int sdepth, int sqdepth)
{
return core::GIntegral::on(src, sdepth, sqdepth);
}
GMat threshold(const GMat& src, const GScalar& thresh, const GScalar& maxval, int type)
{
GAPI_Assert(type != cv::THRESH_TRIANGLE && type != cv::THRESH_OTSU);
return core::GThreshold::on(src, thresh, maxval, type);
}
std::tuple<GMat, GScalar> threshold(const GMat& src, const GScalar& maxval, int type)
{
GAPI_Assert(type == cv::THRESH_TRIANGLE || type == cv::THRESH_OTSU);
return core::GThresholdOT::on(src, maxval, type);
}
GMat inRange(const GMat& src, const GScalar& threshLow, const GScalar& threshUp)
{
return core::GInRange::on(src, threshLow, threshUp);
}
std::tuple<GMat, GMat, GMat> split3(const GMat& src)
{
return core::GSplit3::on(src);
}
std::tuple<GMat, GMat, GMat, GMat> split4(const GMat& src)
{
return core::GSplit4::on(src);
}
GMat merge3(const GMat& src1, const GMat& src2, const GMat& src3)
{
return core::GMerge3::on(src1, src2, src3);
}
GMat merge4(const GMat& src1, const GMat& src2, const GMat& src3, const GMat& src4)
{
return core::GMerge4::on(src1, src2, src3, src4);
}
GMat resize(const GMat& src, const Size& dsize, double fx, double fy, int interpolation)
{
return core::GResize::on(src, dsize, fx, fy, interpolation);
}
GMat remap(const GMat& src, const Mat& map1, const Mat& map2,
int interpolation, int borderMode,
const Scalar& borderValue)
{
return core::GRemap::on(src, map1, map2, interpolation, borderMode, borderValue);
}
GMat flip(const GMat& src, int flipCode)
{
return core::GFlip::on(src, flipCode);
}
GMat crop(const GMat& src, const Rect& rect)
{
return core::GCrop::on(src, rect);
}
GMat concatHor(const GMat& src1, const GMat& src2)
{
return core::GConcatHor::on(src1, src2);
}
GMat concatHor(const std::vector<GMat>& v)
{
GAPI_Assert(v.size() >= 2);
return std::accumulate(v.begin()+1, v.end(), v[0], core::GConcatHor::on);
}
GMat concatVert(const GMat& src1, const GMat& src2)
{
return core::GConcatVert::on(src1, src2);
}
GMat concatVert(const std::vector<GMat>& v)
{
GAPI_Assert(v.size() >= 2);
return std::accumulate(v.begin()+1, v.end(), v[0], core::GConcatVert::on);
}
GMat LUT(const GMat& src, const Mat& lut)
{
return core::GLUT::on(src, lut);
}
GMat convertTo(const GMat& m, int rtype, double alpha, double beta)
{
return core::GConvertTo::on(m, rtype, alpha, beta);
}
} //namespace gapi
} //namespace cv

@ -0,0 +1,142 @@
// 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) 2018 Intel Corporation
#include "opencv2/gapi/gscalar.hpp"
#include "opencv2/gapi/gcall.hpp"
#include "opencv2/gapi/gkernel.hpp"
#include "opencv2/gapi/imgproc.hpp"
namespace cv { namespace gapi {
GMat sepFilter(const GMat& src, int ddepth, const Mat& kernelX, const Mat& kernelY, const Point& anchor,
const Scalar& delta, int borderType, const Scalar& borderVal)
{
return imgproc::GSepFilter::on(src, ddepth, kernelX, kernelY, anchor, delta, borderType, borderVal);
}
GMat filter2D(const GMat& src, int ddepth, const Mat& kernel, const Point& anchor, const Scalar& delta, int borderType,
const Scalar& bordVal)
{
return imgproc::GFilter2D::on(src, ddepth, kernel, anchor, delta, borderType, bordVal);
}
GMat boxFilter(const GMat& src, int dtype, const Size& ksize, const Point& anchor,
bool normalize, int borderType, const Scalar& bordVal)
{
return imgproc::GBoxFilter::on(src, dtype, ksize, anchor, normalize, borderType, bordVal);
}
GMat blur(const GMat& src, const Size& ksize, const Point& anchor,
int borderType, const Scalar& bordVal)
{
return imgproc::GBlur::on(src, ksize, anchor, borderType, bordVal);
}
GMat gaussianBlur(const GMat& src, const Size& ksize, double sigmaX, double sigmaY,
int borderType, const Scalar& bordVal)
{
return imgproc::GGaussBlur::on(src, ksize, sigmaX, sigmaY, borderType, bordVal);
}
GMat medianBlur(const GMat& src, int ksize)
{
return imgproc::GMedianBlur::on(src, ksize);
}
GMat erode(const GMat& src, const Mat& kernel, const Point& anchor, int iterations,
int borderType, const Scalar& borderValue )
{
return imgproc::GErode::on(src, kernel, anchor, iterations, borderType, borderValue);
}
GMat erode3x3(const GMat& src, int iterations,
int borderType, const Scalar& borderValue )
{
return erode(src, cv::Mat(), cv::Point(-1, -1), iterations, borderType, borderValue);
}
GMat dilate(const GMat& src, const Mat& kernel, const Point& anchor, int iterations,
int borderType, const Scalar& borderValue)
{
return imgproc::GDilate::on(src, kernel, anchor, iterations, borderType, borderValue);
}
GMat dilate3x3(const GMat& src, int iterations,
int borderType, const Scalar& borderValue)
{
return dilate(src, cv::Mat(), cv::Point(-1,-1), iterations, borderType, borderValue);
}
GMat sobel(const GMat& src, int ddepth, int dx, int dy, int ksize,
double scale, double delta,
int borderType, const Scalar& bordVal)
{
return imgproc::GSobel::on(src, ddepth, dx, dy, ksize, scale, delta, borderType, bordVal);
}
GMat equalizeHist(const GMat& src)
{
return imgproc::GEqHist::on(src);
}
GMat Canny(const GMat& src, double thr1, double thr2, int apertureSize, bool l2gradient)
{
return imgproc::GCanny::on(src, thr1, thr2, apertureSize, l2gradient);
}
GMat RGB2Gray(const GMat& src)
{
return imgproc::GRGB2Gray::on(src);
}
GMat RGB2Gray(const GMat& src, float rY, float gY, float bY)
{
return imgproc::GRGB2GrayCustom::on(src, rY, gY, bY);
}
GMat BGR2Gray(const GMat& src)
{
return imgproc::GBGR2Gray::on(src);
}
GMat RGB2YUV(const GMat& src)
{
return imgproc::GRGB2YUV::on(src);
}
GMat BGR2LUV(const GMat& src)
{
return imgproc::GBGR2LUV::on(src);
}
GMat LUV2BGR(const GMat& src)
{
return imgproc::GLUV2BGR::on(src);
}
GMat BGR2YUV(const GMat& src)
{
return imgproc::GBGR2YUV::on(src);
}
GMat YUV2BGR(const GMat& src)
{
return imgproc::GYUV2BGR::on(src);
}
GMat YUV2RGB(const GMat& src)
{
return imgproc::GYUV2RGB::on(src);
}
GMat RGB2Lab(const GMat& src)
{
return imgproc::GRGB2Lab::on(src);
}
} //namespace gapi
} //namespace cv

@ -0,0 +1,211 @@
// 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) 2018 Intel Corporation
#include "opencv2/gapi/imgproc.hpp"
#include "opencv2/gapi/core.hpp"
#include "opencv2/gapi/gscalar.hpp"
#include "opencv2/gapi/operators.hpp"
cv::GMat operator+(const cv::GMat& lhs, const cv::GMat& rhs)
{
return cv::gapi::add(lhs, rhs);
}
cv::GMat operator+(const cv::GMat& lhs, const cv::GScalar& rhs)
{
return cv::gapi::addC(lhs, rhs);
}
cv::GMat operator+(const cv::GScalar& lhs, const cv::GMat& rhs)
{
return cv::gapi::addC(rhs, lhs);
}
cv::GMat operator-(const cv::GMat& lhs, const cv::GMat& rhs)
{
return cv::gapi::sub(lhs, rhs);
}
cv::GMat operator-(const cv::GMat& lhs, const cv::GScalar& rhs)
{
return cv::gapi::subC(lhs, rhs);
}
cv::GMat operator-(const cv::GScalar& lhs, const cv::GMat& rhs)
{
return cv::gapi::subRC(lhs, rhs);
}
cv::GMat operator*(const cv::GMat& lhs, float rhs)
{
return cv::gapi::mulC(lhs, static_cast<double>(rhs));
}
cv::GMat operator*(float lhs, const cv::GMat& rhs)
{
return cv::gapi::mulC(rhs, static_cast<double>(lhs));
}
cv::GMat operator*(const cv::GMat& lhs, const cv::GScalar& rhs)
{
return cv::gapi::mulC(lhs, rhs);
}
cv::GMat operator*(const cv::GScalar& lhs, const cv::GMat& rhs)
{
return cv::gapi::mulC(rhs, lhs);
}
cv::GMat operator/(const cv::GMat& lhs, const cv::GScalar& rhs)
{
return cv::gapi::divC(lhs, rhs, 1.0);
}
cv::GMat operator/(const cv::GMat& lhs, const cv::GMat& rhs)
{
return cv::gapi::div(lhs, rhs, 1.0);
}
cv::GMat operator/(const cv::GScalar& lhs, const cv::GMat& rhs)
{
return cv::gapi::divRC(lhs, rhs, 1.0);
}
cv::GMat operator&(const cv::GMat& lhs, const cv::GMat& rhs)
{
return cv::gapi::bitwise_and(lhs, rhs);
}
cv::GMat operator&(const cv::GMat& lhs, const cv::GScalar& rhs)
{
return cv::gapi::bitwise_and(lhs, rhs);
}
cv::GMat operator&(const cv::GScalar& lhs, const cv::GMat& rhs)
{
return cv::gapi::bitwise_and(rhs, lhs);
}
cv::GMat operator|(const cv::GMat& lhs, const cv::GMat& rhs)
{
return cv::gapi::bitwise_or(lhs, rhs);
}
cv::GMat operator|(const cv::GMat& lhs, const cv::GScalar& rhs)
{
return cv::gapi::bitwise_or(lhs, rhs);
}
cv::GMat operator|(const cv::GScalar& lhs, const cv::GMat& rhs)
{
return cv::gapi::bitwise_or(rhs, lhs);
}
cv::GMat operator^(const cv::GMat& lhs, const cv::GMat& rhs)
{
return cv::gapi::bitwise_xor(lhs, rhs);
}
cv::GMat operator^(const cv::GMat& lhs, const cv::GScalar& rhs)
{
return cv::gapi::bitwise_xor(lhs, rhs);
}
cv::GMat operator^(const cv::GScalar& lhs, const cv::GMat& rhs)
{
return cv::gapi::bitwise_xor(rhs, lhs);
}
cv::GMat operator~(const cv::GMat& lhs)
{
return cv::gapi::bitwise_not(lhs);
}
cv::GMat operator>(const cv::GMat& lhs, const cv::GMat& rhs)
{
return cv::gapi::cmpGT(lhs, rhs);
}
cv::GMat operator>=(const cv::GMat& lhs, const cv::GMat& rhs)
{
return cv::gapi::cmpGE(lhs, rhs);
}
cv::GMat operator<(const cv::GMat& lhs, const cv::GMat& rhs)
{
return cv::gapi::cmpLT(lhs, rhs);
}
cv::GMat operator<=(const cv::GMat& lhs, const cv::GMat& rhs)
{
return cv::gapi::cmpLE(lhs, rhs);
}
cv::GMat operator==(const cv::GMat& lhs, const cv::GMat& rhs)
{
return cv::gapi::cmpEQ(lhs, rhs);
}
cv::GMat operator!=(const cv::GMat& lhs, const cv::GMat& rhs)
{
return cv::gapi::cmpNE(lhs, rhs);
}
cv::GMat operator>(const cv::GMat& lhs, const cv::GScalar& rhs)
{
return cv::gapi::cmpGT(lhs, rhs);
}
cv::GMat operator>=(const cv::GMat& lhs, const cv::GScalar& rhs)
{
return cv::gapi::cmpGE(lhs, rhs);
}
cv::GMat operator<(const cv::GMat& lhs, const cv::GScalar& rhs)
{
return cv::gapi::cmpLT(lhs, rhs);
}
cv::GMat operator<=(const cv::GMat& lhs, const cv::GScalar& rhs)
{
return cv::gapi::cmpLE(lhs, rhs);
}
cv::GMat operator==(const cv::GMat& lhs, const cv::GScalar& rhs)
{
return cv::gapi::cmpEQ(lhs, rhs);
}
cv::GMat operator!=(const cv::GMat& lhs, const cv::GScalar& rhs)
{
return cv::gapi::cmpNE(lhs, rhs);
}
cv::GMat operator>(const cv::GScalar& lhs, const cv::GMat& rhs)
{
return cv::gapi::cmpLT(rhs, lhs);
}
cv::GMat operator>=(const cv::GScalar& lhs, const cv::GMat& rhs)
{
return cv::gapi::cmpLE(rhs, lhs);
}
cv::GMat operator<(const cv::GScalar& lhs, const cv::GMat& rhs)
{
return cv::gapi::cmpGT(rhs, lhs);
}
cv::GMat operator<=(const cv::GScalar& lhs, const cv::GMat& rhs)
{
return cv::gapi::cmpGE(rhs, lhs);
}
cv::GMat operator==(const cv::GScalar& lhs, const cv::GMat& rhs)
{
return cv::gapi::cmpEQ(rhs, lhs);
}
cv::GMat operator!=(const cv::GScalar& lhs, const cv::GMat& rhs)
{
return cv::gapi::cmpNE(rhs, lhs);
}

@ -0,0 +1,2 @@
This directory contains various G-API backends, which provide scheduling
logic and kernel implementations for specific targets.

@ -0,0 +1,103 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GBACKEND_HPP
#define OPENCV_GAPI_GBACKEND_HPP
#include <string>
#include <memory>
#include <ade/node.hpp>
#include "opencv2/gapi/garg.hpp"
#include "opencv2/gapi/own/mat.hpp"
#include "opencv2/gapi/util/optional.hpp"
#include "opencv2/gapi/own/scalar.hpp"
#include "compiler/gmodel.hpp"
namespace cv {
namespace gimpl {
// Forward declarations
struct Data;
struct RcDesc;
namespace magazine {
template<typename... Ts> struct Class
{
template<typename T> using MapT = std::unordered_map<int, T>;
template<typename T> MapT<T>& slot()
{
return std::get<ade::util::type_list_index<T, Ts...>::value>(slots);
}
template<typename T> const MapT<T>& slot() const
{
return std::get<ade::util::type_list_index<T, Ts...>::value>(slots);
}
private:
std::tuple<MapT<Ts>...> slots;
};
} // namespace magazine
using Mag = magazine::Class<cv::gapi::own::Mat, cv::gapi::own::Scalar, cv::detail::VectorRef>;
namespace magazine
{
void bindInArg (Mag& mag, const RcDesc &rc, const GRunArg &arg);
void bindOutArg(Mag& mag, const RcDesc &rc, const GRunArgP &arg);
void resetInternalData(Mag& mag, const Data &d);
cv::GRunArg getArg (const Mag& mag, const RcDesc &ref);
cv::GRunArgP getObjPtr ( Mag& mag, const RcDesc &rc);
void writeBack (const Mag& mag, const RcDesc &rc, GRunArgP &g_arg);
} // namespace magazine
namespace detail
{
template<typename... Ts> struct magazine
{
template<typename T> using MapT = std::unordered_map<int, T>;
template<typename T> MapT<T>& slot()
{
return std::get<util::type_list_index<T, Ts...>::value>(slots);
}
template<typename T> const MapT<T>& slot() const
{
return std::get<util::type_list_index<T, Ts...>::value>(slots);
}
private:
std::tuple<MapT<Ts>...> slots;
};
} // namespace detail
struct GRuntimeArgs
{
GRunArgs inObjs;
GRunArgsP outObjs;
};
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>();
}
}} // cv::gimpl
#endif // OPENCV_GAPI_GBACKEND_HPP

@ -0,0 +1,18 @@
// 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) 2018 Intel Corporation
#include "opencv2/gapi/gcompoundkernel.hpp" // compound::backend()
#include "api/gbackend_priv.hpp"
#include "compiler/gislandmodel.hpp" // GIslandExecutable
cv::gapi::GBackend cv::gapi::compound::backend()
{
// A pointer to dummy Priv is used to uniquely identify backends
static cv::gapi::GBackend this_backend(std::make_shared<cv::gapi::GBackend::Priv>());
return this_backend;
}

@ -0,0 +1,45 @@
// 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) 2018 Intel Corporation
#include <ade/util/zip_range.hpp> // util::indexed
#include "opencv2/gapi/gcompoundkernel.hpp"
#include "compiler/gobjref.hpp"
// FIXME move to backends
cv::detail::GCompoundContext::GCompoundContext(const cv::GArgs& in_args)
{
m_args.resize(in_args.size());
for (const auto& it : ade::util::indexed(in_args))
{
const auto& i = ade::util::index(it);
const auto& in_arg = ade::util::value(it);
if (in_arg.kind != cv::detail::ArgKind::GOBJREF)
{
m_args[i] = in_arg;
}
else
{
const cv::gimpl::RcDesc &ref = in_arg.get<cv::gimpl::RcDesc>();
switch (ref.shape)
{
case GShape::GMAT : m_args[i] = GArg(GMat()); break;
case GShape::GSCALAR: m_args[i] = GArg(GScalar()); break;
case GShape::GARRAY :/* do nothing - as handled in a special way, see gcompoundkernel.hpp for details */; break;
default: GAPI_Assert(false);
}
}
}
GAPI_Assert(m_args.size() == in_args.size());
}
cv::detail::GCompoundKernel::GCompoundKernel(const F& f) : m_f(f)
{
}
void cv::detail::GCompoundKernel::apply(cv::detail::GCompoundContext& ctx) { m_f(ctx); }

@ -0,0 +1,227 @@
// 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) 2018 Intel Corporation
#include <functional>
#include <unordered_set>
#include <ade/util/algorithm.hpp>
#include <ade/util/range.hpp>
#include <ade/util/zip_range.hpp>
#include <ade/util/chain_range.hpp>
#include <ade/typed_graph.hpp>
#include "opencv2/gapi/gcommon.hpp"
#include "opencv2/gapi/util/any.hpp"
#include "opencv2/gapi/gtype_traits.hpp"
#include "compiler/gobjref.hpp"
#include "compiler/gmodel.hpp"
#include "backends/cpu/gcpubackend.hpp"
#include "backends/cpu/gcpuimgproc.hpp"
#include "backends/cpu/gcpucore.hpp"
#include "api/gbackend_priv.hpp" // FIXME: Make it part of Backend SDK!
// FIXME: Is there a way to take a typed graph (our GModel),
// and create a new typed graph _ATOP_ of that (by extending with a couple of
// new types?).
// Alternatively, is there a way to compose types graphs?
//
// If not, we need to introduce that!
using GCPUModel = ade::TypedGraph
< cv::gimpl::Unit
, cv::gimpl::Protocol
>;
// FIXME: Same issue with Typed and ConstTyped
using GConstGCPUModel = ade::ConstTypedGraph
< cv::gimpl::Unit
, cv::gimpl::Protocol
>;
namespace
{
class GCPUBackendImpl final: public cv::gapi::GBackend::Priv
{
virtual void unpackKernel(ade::Graph &graph,
const ade::NodeHandle &op_node,
const cv::GKernelImpl &impl) override
{
GCPUModel gm(graph);
auto cpu_impl = cv::util::any_cast<cv::GCPUKernel>(impl.opaque);
gm.metadata(op_node).set(cv::gimpl::Unit{cpu_impl});
}
virtual EPtr compile(const ade::Graph &graph,
const cv::GCompileArgs &,
const std::vector<ade::NodeHandle> &nodes) const override
{
return EPtr{new cv::gimpl::GCPUExecutable(graph, nodes)};
}
};
}
cv::gapi::GBackend cv::gapi::cpu::backend()
{
static cv::gapi::GBackend this_backend(std::make_shared<GCPUBackendImpl>());
return this_backend;
}
// GCPUExcecutable implementation //////////////////////////////////////////////
cv::gimpl::GCPUExecutable::GCPUExecutable(const ade::Graph &g,
const std::vector<ade::NodeHandle> &nodes)
: m_g(g), m_gm(m_g)
{
// Convert list of operations (which is topologically sorted already)
// into an execution script.
for (auto &nh : nodes)
{
switch (m_gm.metadata(nh).get<NodeType>().t)
{
case NodeType::OP: m_script.push_back({nh, GModel::collectOutputMeta(m_gm, nh)}); break;
case NodeType::DATA:
{
m_dataNodes.push_back(nh);
const auto &desc = m_gm.metadata(nh).get<Data>();
if (desc.storage == Data::Storage::CONST)
{
auto rc = RcDesc{desc.rc, desc.shape, desc.ctor};
magazine::bindInArg(m_res, rc, m_gm.metadata(nh).get<ConstValue>().arg);
}
//preallocate internal Mats in advance
if (desc.storage == Data::Storage::INTERNAL && desc.shape == GShape::GMAT)
{
const auto mat_desc = util::get<cv::GMatDesc>(desc.meta);
const auto type = CV_MAKETYPE(mat_desc.depth, mat_desc.chan);
m_res.slot<cv::gapi::own::Mat>()[desc.rc].create(mat_desc.size, type);
}
break;
}
default: util::throw_error(std::logic_error("Unsupported NodeType type"));
}
}
}
// FIXME: Document what it does
cv::GArg cv::gimpl::GCPUExecutable::packArg(const GArg &arg)
{
// No API placeholders allowed at this point
// FIXME: this check has to be done somewhere in compilation stage.
GAPI_Assert( arg.kind != cv::detail::ArgKind::GMAT
&& arg.kind != cv::detail::ArgKind::GSCALAR
&& arg.kind != cv::detail::ArgKind::GARRAY);
if (arg.kind != cv::detail::ArgKind::GOBJREF)
{
// All other cases - pass as-is, with no transformations to GArg contents.
return arg;
}
GAPI_Assert(arg.kind == cv::detail::ArgKind::GOBJREF);
// Wrap associated CPU object (either host or an internal one)
// FIXME: object can be moved out!!! GExecutor faced that.
const cv::gimpl::RcDesc &ref = arg.get<cv::gimpl::RcDesc>();
switch (ref.shape)
{
case GShape::GMAT: return GArg(m_res.slot<cv::gapi::own::Mat>() [ref.id]);
case GShape::GSCALAR: return GArg(m_res.slot<cv::gapi::own::Scalar>()[ref.id]);
// Note: .at() is intentional for GArray as object MUST be already there
// (and constructed by either bindIn/Out or resetInternal)
case GShape::GARRAY: return GArg(m_res.slot<cv::detail::VectorRef>().at(ref.id));
default:
util::throw_error(std::logic_error("Unsupported GShape type"));
break;
}
}
void cv::gimpl::GCPUExecutable::run(std::vector<InObj> &&input_objs,
std::vector<OutObj> &&output_objs)
{
// Update resources with run-time information - what this Island
// has received from user (or from another Island, or mix...)
// FIXME: Check input/output objects against GIsland protocol
for (auto& it : input_objs) magazine::bindInArg (m_res, it.first, it.second);
for (auto& it : output_objs) magazine::bindOutArg(m_res, it.first, it.second);
// Initialize (reset) internal data nodes with user structures
// before processing a frame (no need to do it for external data structures)
GModel::ConstGraph gm(m_g);
for (auto nh : m_dataNodes)
{
const auto &desc = gm.metadata(nh).get<Data>();
if ( desc.storage == Data::Storage::INTERNAL
&& !util::holds_alternative<util::monostate>(desc.ctor))
{
// FIXME: Note that compile-time constant data objects (like
// a value-initialized GArray<T>) also satisfy this condition
// and should be excluded, but now we just don't support it
magazine::resetInternalData(m_res, desc);
}
}
// OpenCV backend execution is not a rocket science at all.
// Simply invoke our kernels in the proper order.
GConstGCPUModel gcm(m_g);
for (auto &op_info : m_script)
{
const auto &op = m_gm.metadata(op_info.nh).get<Op>();
// Obtain our real execution unit
// TODO: Should kernels be copyable?
GCPUKernel k = gcm.metadata(op_info.nh).get<Unit>().k;
// Initialize kernel's execution context:
// - Input parameters
GCPUContext context;
context.m_args.reserve(op.args.size());
using namespace std::placeholders;
ade::util::transform(op.args,
std::back_inserter(context.m_args),
std::bind(&GCPUExecutable::packArg, this, _1));
// - Output parameters.
// FIXME: pre-allocate internal Mats, etc, according to the known meta
for (const auto &out_it : ade::util::indexed(op.outs))
{
// FIXME: Can the same GArg type resolution mechanism be reused here?
const auto out_port = ade::util::index(out_it);
const auto out_desc = ade::util::value(out_it);
context.m_results[out_port] = magazine::getObjPtr(m_res, out_desc);
}
// Now trigger the executable unit
k.apply(context);
//As Kernels are forbidden to allocate memory for (Mat) outputs,
//this code seems redundant, at least for Mats
//FIXME: unify with cv::detail::ensure_out_mats_not_reallocated
for (const auto &out_it : ade::util::indexed(op_info.expected_out_metas))
{
const auto out_index = ade::util::index(out_it);
const auto expected_meta = ade::util::value(out_it);
const auto out_meta = descr_of(context.m_results[out_index]);
if (expected_meta != out_meta)
{
util::throw_error
(std::logic_error
("Output meta doesn't "
"coincide with the generated meta\n"
"Expected: " + ade::util::to_string(expected_meta) + "\n"
"Actual : " + ade::util::to_string(out_meta)));
}
}
} // for(m_script)
for (auto &it : output_objs) magazine::writeBack(m_res, it.first, it.second);
}

@ -0,0 +1,63 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GCPUBACKEND_HPP
#define OPENCV_GAPI_GCPUBACKEND_HPP
#include <map> // map
#include <unordered_map> // unordered_map
#include <tuple> // tuple
#include <ade/util/algorithm.hpp> // type_list_index
#include "opencv2/gapi/garg.hpp"
#include "opencv2/gapi/gproto.hpp"
#include "opencv2/gapi/cpu/gcpukernel.hpp"
#include "api/gapi_priv.hpp"
#include "backends/common/gbackend.hpp"
#include "compiler/gislandmodel.hpp"
namespace cv { namespace gimpl {
struct Unit
{
static const char *name() { return "HostKernel"; }
GCPUKernel k;
};
class GCPUExecutable final: public GIslandExecutable
{
const ade::Graph &m_g;
GModel::ConstGraph m_gm;
struct OperationInfo
{
ade::NodeHandle nh;
GMetaArgs expected_out_metas;
};
// Execution script, currently absolutely naive
std::vector<OperationInfo> m_script;
// 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);
public:
GCPUExecutable(const ade::Graph &graph,
const std::vector<ade::NodeHandle> &nodes);
virtual void run(std::vector<InObj> &&input_objs,
std::vector<OutObj> &&output_objs) override;
};
}}
#endif // OPENCV_GAPI_GBACKEND_HPP

@ -0,0 +1,577 @@
// 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) 2018 Intel Corporation
#include "precomp.hpp"
#include "opencv2/gapi/core.hpp"
#include "opencv2/gapi/cpu/core.hpp"
#include "backends/cpu/gcpucore.hpp"
GAPI_OCV_KERNEL(GCPUAdd, cv::gapi::core::GAdd)
{
static void run(const cv::Mat& a, const cv::Mat& b, int dtype, cv::Mat& out)
{
cv::add(a, b, out, cv::noArray(), dtype);
}
};
GAPI_OCV_KERNEL(GCPUAddC, cv::gapi::core::GAddC)
{
static void run(const cv::Mat& a, const cv::Scalar& b, int dtype, cv::Mat& out)
{
cv::add(a, b, out, cv::noArray(), dtype);
}
};
GAPI_OCV_KERNEL(GCPUSub, cv::gapi::core::GSub)
{
static void run(const cv::Mat& a, const cv::Mat& b, int dtype, cv::Mat& out)
{
cv::subtract(a, b, out, cv::noArray(), dtype);
}
};
GAPI_OCV_KERNEL(GCPUSubC, cv::gapi::core::GSubC)
{
static void run(const cv::Mat& a, const cv::Scalar& b, int dtype, cv::Mat& out)
{
cv::subtract(a, b, out, cv::noArray(), dtype);
}
};
GAPI_OCV_KERNEL(GCPUSubRC, cv::gapi::core::GSubRC)
{
static void run(const cv::Scalar& a, const cv::Mat& b, int dtype, cv::Mat& out)
{
cv::subtract(a, b, out, cv::noArray(), dtype);
}
};
GAPI_OCV_KERNEL(GCPUMul, cv::gapi::core::GMul)
{
static void run(const cv::Mat& a, const cv::Mat& b, double scale, int dtype, cv::Mat& out)
{
cv::multiply(a, b, out, scale, dtype);
}
};
GAPI_OCV_KERNEL(GCPUMulCOld, cv::gapi::core::GMulCOld)
{
static void run(const cv::Mat& a, double b, int dtype, cv::Mat& out)
{
cv::multiply(a, b, out, 1, dtype);
}
};
GAPI_OCV_KERNEL(GCPUMulC, cv::gapi::core::GMulC)
{
static void run(const cv::Mat& a, const cv::Scalar& b, int dtype, cv::Mat& out)
{
cv::multiply(a, b, out, 1, dtype);
}
};
GAPI_OCV_KERNEL(GCPUDiv, cv::gapi::core::GDiv)
{
static void run(const cv::Mat& a, const cv::Mat& b, double scale, int dtype, cv::Mat& out)
{
cv::divide(a, b, out, scale, dtype);
}
};
GAPI_OCV_KERNEL(GCPUDivC, cv::gapi::core::GDivC)
{
static void run(const cv::Mat& a, const cv::Scalar& b, double scale, int dtype, cv::Mat& out)
{
cv::divide(a, b, out, scale, dtype);
}
};
GAPI_OCV_KERNEL(GCPUDivRC, cv::gapi::core::GDivRC)
{
static void run(const cv::Scalar& a, const cv::Mat& b, double scale, int dtype, cv::Mat& out)
{
cv::divide(a, b, out, scale, dtype);
}
};
GAPI_OCV_KERNEL(GCPUMask, cv::gapi::core::GMask)
{
static void run(const cv::Mat& in, const cv::Mat& mask, cv::Mat& out)
{
out = cv::Mat::zeros(in.size(), in.type());
in.copyTo(out, mask);
}
};
GAPI_OCV_KERNEL(GCPUMean, cv::gapi::core::GMean)
{
static void run(const cv::Mat& in, cv::Scalar& out)
{
out = cv::mean(in);
}
};
GAPI_OCV_KERNEL(GCPUPolarToCart, cv::gapi::core::GPolarToCart)
{
static void run(const cv::Mat& magn, const cv::Mat& angle, bool angleInDegrees, cv::Mat& outx, cv::Mat& outy)
{
cv::polarToCart(magn, angle, outx, outy, angleInDegrees);
}
};
GAPI_OCV_KERNEL(GCPUCartToPolar, cv::gapi::core::GCartToPolar)
{
static void run(const cv::Mat& x, const cv::Mat& y, bool angleInDegrees, cv::Mat& outmagn, cv::Mat& outangle)
{
cv::cartToPolar(x, y, outmagn, outangle, angleInDegrees);
}
};
GAPI_OCV_KERNEL(GCPUCmpGT, cv::gapi::core::GCmpGT)
{
static void run(const cv::Mat& a, const cv::Mat& b, cv::Mat& out)
{
cv::compare(a, b, out, cv::CMP_GT);
}
};
GAPI_OCV_KERNEL(GCPUCmpGE, cv::gapi::core::GCmpGE)
{
static void run(const cv::Mat& a, const cv::Mat& b, cv::Mat& out)
{
cv::compare(a, b, out, cv::CMP_GE);
}
};
GAPI_OCV_KERNEL(GCPUCmpLE, cv::gapi::core::GCmpLE)
{
static void run(const cv::Mat& a, const cv::Mat& b, cv::Mat& out)
{
cv::compare(a, b, out, cv::CMP_LE);
}
};
GAPI_OCV_KERNEL(GCPUCmpLT, cv::gapi::core::GCmpLT)
{
static void run(const cv::Mat& a, const cv::Mat& b, cv::Mat& out)
{
cv::compare(a, b, out, cv::CMP_LT);
}
};
GAPI_OCV_KERNEL(GCPUCmpEQ, cv::gapi::core::GCmpEQ)
{
static void run(const cv::Mat& a, const cv::Mat& b, cv::Mat& out)
{
cv::compare(a, b, out, cv::CMP_EQ);
}
};
GAPI_OCV_KERNEL(GCPUCmpNE, cv::gapi::core::GCmpNE)
{
static void run(const cv::Mat& a, const cv::Mat& b, cv::Mat& out)
{
cv::compare(a, b, out, cv::CMP_NE);
}
};
GAPI_OCV_KERNEL(GCPUCmpGTScalar, cv::gapi::core::GCmpGTScalar)
{
static void run(const cv::Mat& a, const cv::Scalar& b, cv::Mat& out)
{
cv::compare(a, b, out, cv::CMP_GT);
}
};
GAPI_OCV_KERNEL(GCPUCmpGEScalar, cv::gapi::core::GCmpGEScalar)
{
static void run(const cv::Mat& a, const cv::Scalar& b, cv::Mat& out)
{
cv::compare(a, b, out, cv::CMP_GE);
}
};
GAPI_OCV_KERNEL(GCPUCmpLEScalar, cv::gapi::core::GCmpLEScalar)
{
static void run(const cv::Mat& a, const cv::Scalar& b, cv::Mat& out)
{
cv::compare(a, b, out, cv::CMP_LE);
}
};
GAPI_OCV_KERNEL(GCPUCmpLTScalar, cv::gapi::core::GCmpLTScalar)
{
static void run(const cv::Mat& a, const cv::Scalar& b, cv::Mat& out)
{
cv::compare(a, b, out, cv::CMP_LT);
}
};
GAPI_OCV_KERNEL(GCPUCmpEQScalar, cv::gapi::core::GCmpEQScalar)
{
static void run(const cv::Mat& a, const cv::Scalar& b, cv::Mat& out)
{
cv::compare(a, b, out, cv::CMP_EQ);
}
};
GAPI_OCV_KERNEL(GCPUCmpNEScalar, cv::gapi::core::GCmpNEScalar)
{
static void run(const cv::Mat& a, const cv::Scalar& b, cv::Mat& out)
{
cv::compare(a, b, out, cv::CMP_NE);
}
};
GAPI_OCV_KERNEL(GCPUAnd, cv::gapi::core::GAnd)
{
static void run(const cv::Mat& a, const cv::Mat& b, cv::Mat& out)
{
cv::bitwise_and(a, b, out);
}
};
GAPI_OCV_KERNEL(GCPUAndS, cv::gapi::core::GAndS)
{
static void run(const cv::Mat& a, const cv::Scalar& b, cv::Mat& out)
{
cv::bitwise_and(a, b, out);
}
};
GAPI_OCV_KERNEL(GCPUOr, cv::gapi::core::GOr)
{
static void run(const cv::Mat& a, const cv::Mat& b, cv::Mat& out)
{
cv::bitwise_or(a, b, out);
}
};
GAPI_OCV_KERNEL(GCPUOrS, cv::gapi::core::GOrS)
{
static void run(const cv::Mat& a, const cv::Scalar& b, cv::Mat& out)
{
cv::bitwise_or(a, b, out);
}
};
GAPI_OCV_KERNEL(GCPUXor, cv::gapi::core::GXor)
{
static void run(const cv::Mat& a, const cv::Mat& b, cv::Mat& out)
{
cv::bitwise_xor(a, b, out);
}
};
GAPI_OCV_KERNEL(GCPUXorS, cv::gapi::core::GXorS)
{
static void run(const cv::Mat& a, const cv::Scalar& b, cv::Mat& out)
{
cv::bitwise_xor(a, b, out);
}
};
GAPI_OCV_KERNEL(GCPUNot, cv::gapi::core::GNot)
{
static void run(const cv::Mat& a, cv::Mat& out)
{
cv::bitwise_not(a, out);
}
};
GAPI_OCV_KERNEL(GCPUSelect, cv::gapi::core::GSelect)
{
static void run(const cv::Mat& src1, const cv::Mat& src2, const cv::Mat& mask, cv::Mat& out)
{
src2.copyTo(out);
src1.copyTo(out, mask);
}
};
GAPI_OCV_KERNEL(GCPUMin, cv::gapi::core::GMin)
{
static void run(const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out)
{
out = cv::min(in1, in2);
}
};
GAPI_OCV_KERNEL(GCPUMax, cv::gapi::core::GMax)
{
static void run(const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out)
{
out = cv::max(in1, in2);
}
};
GAPI_OCV_KERNEL(GCPUAbsDiff, cv::gapi::core::GAbsDiff)
{
static void run(const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out)
{
cv::absdiff(in1, in2, out);
}
};
GAPI_OCV_KERNEL(GCPUAbsDiffC, cv::gapi::core::GAbsDiffC)
{
static void run(const cv::Mat& in1, const cv::Scalar& in2, cv::Mat& out)
{
cv::absdiff(in1, in2, out);
}
};
GAPI_OCV_KERNEL(GCPUSum, cv::gapi::core::GSum)
{
static void run(const cv::Mat& in, cv::Scalar& out)
{
out = cv::sum(in);
}
};
GAPI_OCV_KERNEL(GCPUAddW, cv::gapi::core::GAddW)
{
static void run(const cv::Mat& in1, double alpha, const cv::Mat& in2, double beta, double gamma, int dtype, cv::Mat& out)
{
cv::addWeighted(in1, alpha, in2, beta, gamma, out, dtype);
}
};
GAPI_OCV_KERNEL(GCPUNormL1, cv::gapi::core::GNormL1)
{
static void run(const cv::Mat& in, cv::Scalar& out)
{
out = cv::norm(in, cv::NORM_L1);
}
};
GAPI_OCV_KERNEL(GCPUNormL2, cv::gapi::core::GNormL2)
{
static void run(const cv::Mat& in, cv::Scalar& out)
{
out = cv::norm(in, cv::NORM_L2);
}
};
GAPI_OCV_KERNEL(GCPUNormInf, cv::gapi::core::GNormInf)
{
static void run(const cv::Mat& in, cv::Scalar& out)
{
out = cv::norm(in, cv::NORM_INF);
}
};
GAPI_OCV_KERNEL(GCPUIntegral, cv::gapi::core::GIntegral)
{
static void run(const cv::Mat& in, int sdepth, int sqdepth, cv::Mat& out, cv::Mat& outSq)
{
cv::integral(in, out, outSq, sdepth, sqdepth);
}
};
GAPI_OCV_KERNEL(GCPUThreshold, cv::gapi::core::GThreshold)
{
static void run(const cv::Mat& in, const cv::Scalar& a, const cv::Scalar& b, int type, cv::Mat& out)
{
cv::threshold(in, out, a.val[0], b.val[0], type);
}
};
GAPI_OCV_KERNEL(GCPUThresholdOT, cv::gapi::core::GThresholdOT)
{
static void run(const cv::Mat& in, const cv::Scalar& b, int type, cv::Mat& out, cv::Scalar& outScalar)
{
outScalar = cv::threshold(in, out, b.val[0], b.val[0], type);
}
};
GAPI_OCV_KERNEL(GCPUInRange, cv::gapi::core::GInRange)
{
static void run(const cv::Mat& in, const cv::Scalar& low, const cv::Scalar& up, cv::Mat& out)
{
cv::inRange(in, low, up, out);
}
};
GAPI_OCV_KERNEL(GCPUSplit3, cv::gapi::core::GSplit3)
{
static void run(const cv::Mat& in, cv::Mat &m1, cv::Mat &m2, cv::Mat &m3)
{
std::vector<cv::Mat> outMats = {m1, m2, m3};
cv::split(in, outMats);
// Write back FIXME: Write a helper or avoid this nonsence completely!
m1 = outMats[0];
m2 = outMats[1];
m3 = outMats[2];
}
};
GAPI_OCV_KERNEL(GCPUSplit4, cv::gapi::core::GSplit4)
{
static void run(const cv::Mat& in, cv::Mat &m1, cv::Mat &m2, cv::Mat &m3, cv::Mat &m4)
{
std::vector<cv::Mat> outMats = {m1, m2, m3, m4};
cv::split(in, outMats);
// Write back FIXME: Write a helper or avoid this nonsence completely!
m1 = outMats[0];
m2 = outMats[1];
m3 = outMats[2];
m4 = outMats[3];
}
};
GAPI_OCV_KERNEL(GCPUMerge3, cv::gapi::core::GMerge3)
{
static void run(const cv::Mat& in1, const cv::Mat& in2, const cv::Mat& in3, cv::Mat &out)
{
std::vector<cv::Mat> inMats = {in1, in2, in3};
cv::merge(inMats, out);
}
};
GAPI_OCV_KERNEL(GCPUMerge4, cv::gapi::core::GMerge4)
{
static void run(const cv::Mat& in1, const cv::Mat& in2, const cv::Mat& in3, const cv::Mat& in4, cv::Mat &out)
{
std::vector<cv::Mat> inMats = {in1, in2, in3, in4};
cv::merge(inMats, out);
}
};
GAPI_OCV_KERNEL(GCPUResize, cv::gapi::core::GResize)
{
static void run(const cv::Mat& in, cv::Size sz, double fx, double fy, int interp, cv::Mat &out)
{
cv::resize(in, out, sz, fx, fy, interp);
}
};
GAPI_OCV_KERNEL(GCPURemap, cv::gapi::core::GRemap)
{
static void run(const cv::Mat& in, const cv::Mat& x, const cv::Mat& y, int a, int b, cv::Scalar s, cv::Mat& out)
{
cv::remap(in, out, x, y, a, b, s);
}
};
GAPI_OCV_KERNEL(GCPUFlip, cv::gapi::core::GFlip)
{
static void run(const cv::Mat& in, int code, cv::Mat& out)
{
cv::flip(in, out, code);
}
};
GAPI_OCV_KERNEL(GCPUCrop, cv::gapi::core::GCrop)
{
static void run(const cv::Mat& in, cv::Rect rect, cv::Mat& out)
{
cv::Mat(in, rect).copyTo(out);
}
};
GAPI_OCV_KERNEL(GCPUConcatHor, cv::gapi::core::GConcatHor)
{
static void run(const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out)
{
cv::hconcat(in1, in2, out);
}
};
GAPI_OCV_KERNEL(GCPUConcatVert, cv::gapi::core::GConcatVert)
{
static void run(const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out)
{
cv::vconcat(in1, in2, out);
}
};
GAPI_OCV_KERNEL(GCPULUT, cv::gapi::core::GLUT)
{
static void run(const cv::Mat& in, const cv::Mat& lut, cv::Mat& out)
{
cv::LUT(in, lut, out);
}
};
GAPI_OCV_KERNEL(GCPUConvertTo, cv::gapi::core::GConvertTo)
{
static void run(const cv::Mat& in, int rtype, double alpha, double beta, cv::Mat& out)
{
in.convertTo(out, rtype, alpha, beta);
}
};
cv::gapi::GKernelPackage cv::gapi::core::cpu::kernels()
{
static auto pkg = cv::gapi::kernels
< GCPUAdd
, GCPUAddC
, GCPUSub
, GCPUSubC
, GCPUSubRC
, GCPUMul
, GCPUMulC
, GCPUMulCOld
, GCPUDiv
, GCPUDivC
, GCPUDivRC
, GCPUMean
, GCPUMask
, GCPUPolarToCart
, GCPUCartToPolar
, GCPUCmpGT
, GCPUCmpGE
, GCPUCmpLE
, GCPUCmpLT
, GCPUCmpEQ
, GCPUCmpNE
, GCPUCmpGTScalar
, GCPUCmpGEScalar
, GCPUCmpLEScalar
, GCPUCmpLTScalar
, GCPUCmpEQScalar
, GCPUCmpNEScalar
, GCPUAnd
, GCPUAndS
, GCPUOr
, GCPUOrS
, GCPUXor
, GCPUXorS
, GCPUNot
, GCPUSelect
, GCPUMin
, GCPUMax
, GCPUAbsDiff
, GCPUAbsDiffC
, GCPUSum
, GCPUAddW
, GCPUNormL1
, GCPUNormL2
, GCPUNormInf
, GCPUIntegral
, GCPUThreshold
, GCPUThresholdOT
, GCPUInRange
, GCPUSplit3
, GCPUSplit4
, GCPUResize
, GCPUMerge3
, GCPUMerge4
, GCPURemap
, GCPUFlip
, GCPUCrop
, GCPUConcatHor
, GCPUConcatVert
, GCPULUT
, GCPUConvertTo
>();
return pkg;
}

@ -0,0 +1,24 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GCPUCORE_HPP
#define OPENCV_GAPI_GCPUCORE_HPP
#include <map>
#include <string>
#include "opencv2/gapi/cpu/gcpukernel.hpp"
namespace cv { namespace gimpl {
// NB: This is what a "Kernel Package" from the original Wiki doc should be.
void loadCPUCore(std::map<std::string, cv::GCPUKernel> &kmap);
}
}
#endif // OPENCV_GAPI_GCPUCORE_HPP

@ -0,0 +1,273 @@
// 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) 2018 Intel Corporation
#include "precomp.hpp"
#include "opencv2/gapi/imgproc.hpp"
#include "opencv2/gapi/cpu/imgproc.hpp"
#include "backends/cpu/gcpuimgproc.hpp"
GAPI_OCV_KERNEL(GCPUSepFilter, cv::gapi::imgproc::GSepFilter)
{
static void run(const cv::Mat& in, int ddepth, const cv::Mat& kernX, const cv::Mat& kernY, const cv::Point& anchor, const cv::Scalar& delta,
int border, const cv::Scalar& bordVal, cv::Mat &out)
{
if( border == cv::BORDER_CONSTANT )
{
cv::Mat temp_in;
int width_add = (kernY.cols - 1) / 2;
int height_add = (kernX.rows - 1) / 2;
cv::copyMakeBorder(in, temp_in, height_add, height_add, width_add, width_add, border, bordVal);
cv::Rect rect = cv::Rect(height_add, width_add, in.cols, in.rows);
cv::sepFilter2D(temp_in(rect), out, ddepth, kernX, kernY, anchor, delta.val[0], border);
}
else
cv::sepFilter2D(in, out, ddepth, kernX, kernY, anchor, delta.val[0], border);
}
};
GAPI_OCV_KERNEL(GCPUBoxFilter, cv::gapi::imgproc::GBoxFilter)
{
static void run(const cv::Mat& in, int ddepth, const cv::Size& ksize, const cv::Point& anchor, bool normalize, int borderType, const cv::Scalar& bordVal, cv::Mat &out)
{
if( borderType == cv::BORDER_CONSTANT )
{
cv::Mat temp_in;
int width_add = (ksize.width - 1) / 2;
int height_add = (ksize.height - 1) / 2;
cv::copyMakeBorder(in, temp_in, height_add, height_add, width_add, width_add, borderType, bordVal);
cv::Rect rect = cv::Rect(height_add, width_add, in.cols, in.rows);
cv::boxFilter(temp_in(rect), out, ddepth, ksize, anchor, normalize, borderType);
}
else
cv::boxFilter(in, out, ddepth, ksize, anchor, normalize, borderType);
}
};
GAPI_OCV_KERNEL(GCPUBlur, cv::gapi::imgproc::GBlur)
{
static void run(const cv::Mat& in, const cv::Size& ksize, const cv::Point& anchor, int borderType, const cv::Scalar& bordVal, cv::Mat &out)
{
if( borderType == cv::BORDER_CONSTANT )
{
cv::Mat temp_in;
int width_add = (ksize.width - 1) / 2;
int height_add = (ksize.height - 1) / 2;
cv::copyMakeBorder(in, temp_in, height_add, height_add, width_add, width_add, borderType, bordVal);
cv::Rect rect = cv::Rect(height_add, width_add, in.cols, in.rows);
cv::blur(temp_in(rect), out, ksize, anchor, borderType);
}
else
cv::blur(in, out, ksize, anchor, borderType);
}
};
GAPI_OCV_KERNEL(GCPUFilter2D, cv::gapi::imgproc::GFilter2D)
{
static void run(const cv::Mat& in, int ddepth, const cv::Mat& k, const cv::Point& anchor, const cv::Scalar& delta, int border,
const cv::Scalar& bordVal, cv::Mat &out)
{
if( border == cv::BORDER_CONSTANT )
{
cv::Mat temp_in;
int width_add = (k.cols - 1) / 2;
int height_add = (k.rows - 1) / 2;
cv::copyMakeBorder(in, temp_in, height_add, height_add, width_add, width_add, border, bordVal );
cv::Rect rect = cv::Rect(height_add, width_add, in.cols, in.rows);
cv::filter2D(temp_in(rect), out, ddepth, k, anchor, delta.val[0], border);
}
else
cv::filter2D(in, out, ddepth, k, anchor, delta.val[0], border);
}
};
GAPI_OCV_KERNEL(GCPUGaussBlur, cv::gapi::imgproc::GGaussBlur)
{
static void run(const cv::Mat& in, const cv::Size& ksize, double sigmaX, double sigmaY, int borderType, const cv::Scalar& bordVal, cv::Mat &out)
{
if( borderType == cv::BORDER_CONSTANT )
{
cv::Mat temp_in;
int width_add = (ksize.width - 1) / 2;
int height_add = (ksize.height - 1) / 2;
cv::copyMakeBorder(in, temp_in, height_add, height_add, width_add, width_add, borderType, bordVal );
cv::Rect rect = cv::Rect(height_add, width_add, in.cols, in.rows);
cv::GaussianBlur(temp_in(rect), out, ksize, sigmaX, sigmaY, borderType);
}
else
cv::GaussianBlur(in, out, ksize, sigmaX, sigmaY, borderType);
}
};
GAPI_OCV_KERNEL(GCPUMedianBlur, cv::gapi::imgproc::GMedianBlur)
{
static void run(const cv::Mat& in, int ksize, cv::Mat &out)
{
cv::medianBlur(in, out, ksize);
}
};
GAPI_OCV_KERNEL(GCPUErode, cv::gapi::imgproc::GErode)
{
static void run(const cv::Mat& in, const cv::Mat& kernel, const cv::Point& anchor, int iterations, int borderType, const cv::Scalar& borderValue, cv::Mat &out)
{
cv::erode(in, out, kernel, anchor, iterations, borderType, borderValue);
}
};
GAPI_OCV_KERNEL(GCPUDilate, cv::gapi::imgproc::GDilate)
{
static void run(const cv::Mat& in, const cv::Mat& kernel, const cv::Point& anchor, int iterations, int borderType, const cv::Scalar& borderValue, cv::Mat &out)
{
cv::dilate(in, out, kernel, anchor, iterations, borderType, borderValue);
}
};
GAPI_OCV_KERNEL(GCPUSobel, cv::gapi::imgproc::GSobel)
{
static void run(const cv::Mat& in, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType,
const cv::Scalar& bordVal, cv::Mat &out)
{
if( borderType == cv::BORDER_CONSTANT )
{
cv::Mat temp_in;
int add = (ksize - 1) / 2;
cv::copyMakeBorder(in, temp_in, add, add, add, add, borderType, bordVal );
cv::Rect rect = cv::Rect(add, add, in.cols, in.rows);
cv::Sobel(temp_in(rect), out, ddepth, dx, dy, ksize, scale, delta, borderType);
}
else
cv::Sobel(in, out, ddepth, dx, dy, ksize, scale, delta, borderType);
}
};
GAPI_OCV_KERNEL(GCPUEqualizeHist, cv::gapi::imgproc::GEqHist)
{
static void run(const cv::Mat& in, cv::Mat &out)
{
cv::equalizeHist(in, out);
}
};
GAPI_OCV_KERNEL(GCPUCanny, cv::gapi::imgproc::GCanny)
{
static void run(const cv::Mat& in, double thr1, double thr2, int apSize, bool l2gradient, cv::Mat &out)
{
cv::Canny(in, out, thr1, thr2, apSize, l2gradient);
}
};
GAPI_OCV_KERNEL(GCPURGB2YUV, cv::gapi::imgproc::GRGB2YUV)
{
static void run(const cv::Mat& in, cv::Mat &out)
{
cv::cvtColor(in, out, cv::COLOR_RGB2YUV);
}
};
GAPI_OCV_KERNEL(GCPUYUV2RGB, cv::gapi::imgproc::GYUV2RGB)
{
static void run(const cv::Mat& in, cv::Mat &out)
{
cv::cvtColor(in, out, cv::COLOR_YUV2RGB);
}
};
GAPI_OCV_KERNEL(GCPURGB2Lab, cv::gapi::imgproc::GRGB2Lab)
{
static void run(const cv::Mat& in, cv::Mat &out)
{
cv::cvtColor(in, out, cv::COLOR_RGB2Lab);
}
};
GAPI_OCV_KERNEL(GCPUBGR2LUV, cv::gapi::imgproc::GBGR2LUV)
{
static void run(const cv::Mat& in, cv::Mat &out)
{
cv::cvtColor(in, out, cv::COLOR_BGR2Luv);
}
};
GAPI_OCV_KERNEL(GCPUBGR2YUV, cv::gapi::imgproc::GBGR2YUV)
{
static void run(const cv::Mat& in, cv::Mat &out)
{
cv::cvtColor(in, out, cv::COLOR_BGR2YUV);
}
};
GAPI_OCV_KERNEL(GCPULUV2BGR, cv::gapi::imgproc::GLUV2BGR)
{
static void run(const cv::Mat& in, cv::Mat &out)
{
cv::cvtColor(in, out, cv::COLOR_Luv2BGR);
}
};
GAPI_OCV_KERNEL(GCPUYUV2BGR, cv::gapi::imgproc::GYUV2BGR)
{
static void run(const cv::Mat& in, cv::Mat &out)
{
cv::cvtColor(in, out, cv::COLOR_YUV2BGR);
}
};
GAPI_OCV_KERNEL(GCPURGB2Gray, cv::gapi::imgproc::GRGB2Gray)
{
static void run(const cv::Mat& in, cv::Mat &out)
{
cv::cvtColor(in, out, cv::COLOR_RGB2GRAY);
}
};
GAPI_OCV_KERNEL(GCPUBGR2Gray, cv::gapi::imgproc::GBGR2Gray)
{
static void run(const cv::Mat& in, cv::Mat &out)
{
cv::cvtColor(in, out, cv::COLOR_BGR2GRAY);
}
};
GAPI_OCV_KERNEL(GCPURGB2GrayCustom, cv::gapi::imgproc::GRGB2GrayCustom)
{
static void run(const cv::Mat& in, float rY, float bY, float gY, cv::Mat &out)
{
cv::Mat planes[3];
cv::split(in, planes);
out = planes[0]*rY + planes[1]*bY + planes[2]*gY;
}
};
cv::gapi::GKernelPackage cv::gapi::imgproc::cpu::kernels()
{
static auto pkg = cv::gapi::kernels
< GCPUFilter2D
, GCPUSepFilter
, GCPUBoxFilter
, GCPUBlur
, GCPUGaussBlur
, GCPUMedianBlur
, GCPUErode
, GCPUDilate
, GCPUSobel
, GCPUCanny
, GCPUEqualizeHist
, GCPURGB2YUV
, GCPUYUV2RGB
, GCPURGB2Lab
, GCPUBGR2LUV
, GCPUBGR2YUV
, GCPUYUV2BGR
, GCPULUV2BGR
, GCPUBGR2Gray
, GCPURGB2Gray
, GCPURGB2GrayCustom
>();
return pkg;
}

@ -0,0 +1,23 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GCPUIMGPROC_HPP
#define OPENCV_GAPI_GCPUIMGPROC_HPP
#include <map>
#include <string>
#include "opencv2/gapi/cpu/gcpukernel.hpp"
namespace cv { namespace gimpl {
// NB: This is what a "Kernel Package" from the origianl Wiki doc should be.
void loadCPUImgProc(std::map<std::string, cv::GCPUKernel> &kmap);
}}
#endif // OPENCV_GAPI_GCPUIMGPROC_HPP

@ -0,0 +1,50 @@
// 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) 2018 Intel Corporation
#include <cassert>
#include "opencv2/gapi/cpu/gcpukernel.hpp"
const cv::gapi::own::Mat& cv::GCPUContext::inMat(int input)
{
return inArg<cv::gapi::own::Mat>(input);
}
cv::gapi::own::Mat& cv::GCPUContext::outMatR(int output)
{
return *util::get<cv::gapi::own::Mat*>(m_results.at(output));
}
const cv::gapi::own::Scalar& cv::GCPUContext::inVal(int input)
{
return inArg<cv::gapi::own::Scalar>(input);
}
cv::gapi::own::Scalar& cv::GCPUContext::outValR(int output)
{
return *util::get<cv::gapi::own::Scalar*>(m_results.at(output));
}
cv::detail::VectorRef& cv::GCPUContext::outVecRef(int output)
{
return util::get<cv::detail::VectorRef>(m_results.at(output));
}
cv::GCPUKernel::GCPUKernel()
{
}
cv::GCPUKernel::GCPUKernel(const GCPUKernel::F &f)
: m_f(f)
{
}
void cv::GCPUKernel::apply(GCPUContext &ctx)
{
GAPI_Assert(m_f);
m_f(ctx);
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,128 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_FLUID_BACKEND_HPP
#define OPENCV_GAPI_FLUID_BACKEND_HPP
#include "opencv2/gapi/garg.hpp"
#include "opencv2/gapi/gproto.hpp"
#include "opencv2/gapi/fluid/gfluidkernel.hpp"
#include "opencv2/gapi/fluid/gfluidbuffer.hpp"
// PRIVATE STUFF!
#include "backends/common/gbackend.hpp"
#include "compiler/gislandmodel.hpp"
namespace cv { namespace gimpl {
struct FluidUnit
{
static const char *name() { return "FluidKernel"; }
GFluidKernel k;
gapi::fluid::BorderOpt border;
int border_size;
int line_consumption;
double ratio;
};
struct FluidUseOwnBorderBuffer
{
static const char *name() { return "FluidUseOwnBorderBuffer"; }
bool use;
};
struct FluidData
{
static const char *name() { return "FluidData"; }
// FIXME: This structure starts looking like "FluidBuffer" meta
int latency = 0;
int skew = 0;
int max_consumption = 1;
int border_size = 0;
int lpi_write = 1;
gapi::fluid::BorderOpt border;
};
struct FluidAgent
{
public:
virtual ~FluidAgent() = default;
FluidAgent(const ade::Graph &g, ade::NodeHandle nh);
GFluidKernel k;
ade::NodeHandle op_handle; // FIXME: why it is here??//
std::string op_name;
// < 0 - not a buffer
// >= 0 - a buffer with RcID
std::vector<int> in_buffer_ids;
std::vector<int> out_buffer_ids;
cv::GArgs in_args;
std::vector<cv::gapi::fluid::View> in_views; // sparce list of IN views
std::vector<cv::gapi::fluid::Buffer*> out_buffers;
// FIXME Current assumption is that outputs have EQUAL SIZES
int m_outputLines = 0;
int m_producedLines = 0;
double m_ratio = 0.0f;
// Execution methods
void reset();
bool canWork() const;
bool canRead() const;
bool canWrite() const;
void doWork();
bool done() const;
void debug(std::ostream& os);
private:
// FIXME!!!
// move to another class
virtual int firstWindow() const = 0;
virtual int nextWindow() const = 0;
virtual int linesRead() const = 0;
};
class GFluidExecutable final: public GIslandExecutable
{
const ade::Graph &m_g;
GModel::ConstGraph m_gm;
std::vector<std::unique_ptr<FluidAgent>> m_agents;
std::vector<cv::gapi::fluid::Buffer> m_buffers;
using Magazine = detail::magazine<cv::gapi::own::Scalar>;
Magazine m_res;
std::size_t m_num_int_buffers; // internal buffers counter (m_buffers - num_scratch)
std::vector<std::size_t> m_scratch_users;
std::vector<cv::gapi::fluid::View> m_views;
std::vector<cv::gapi::own::Rect> m_outputRois;
std::unordered_map<int, std::size_t> m_id_map; // GMat id -> buffer idx map
void bindInArg (const RcDesc &rc, const GRunArg &arg);
void bindOutArg(const RcDesc &rc, const GRunArgP &arg);
void packArg (GArg &in_arg, const GArg &op_arg);
public:
GFluidExecutable(const ade::Graph &g,
const std::vector<ade::NodeHandle> &nodes,
const std::vector<cv::gapi::own::Rect> &outputRois);
virtual void run(std::vector<InObj> &&input_objs,
std::vector<OutObj> &&output_objs) override;
};
}} // cv::gimpl
#endif // OPENCV_GAPI_FLUID_BACKEND_HPP

@ -0,0 +1,746 @@
// 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) 2018 Intel Corporation
#include <iomanip> // hex, dec (debug)
#include "opencv2/gapi/own/convert.hpp"
#include "opencv2/gapi/fluid/gfluidbuffer.hpp"
#include "backends/fluid/gfluidbuffer_priv.hpp"
#include "opencv2/gapi/opencv_includes.hpp"
#include "backends/fluid/gfluidutils.hpp" // saturate
namespace cv {
namespace gapi {
namespace fluid {
bool operator == (const fluid::Border& b1, const fluid::Border& b2)
{
return b1.type == b2.type && b1.value == b2.value;
}
} // namespace fluid
// Fluid BorderHandler implementation /////////////////////////////////////////////////
namespace {
template<typename T>
// Expected inputs:
// row - row buffer allocated with border in mind (have memory for both image and border pixels)
// length - size of the buffer with left and right borders included
void fillBorderReplicateRow(uint8_t* row, int length, int chan, int borderSize)
{
auto leftBorder = reinterpret_cast<T*>(row);
auto rightBorder = leftBorder + (length - borderSize) * chan;
for (int b = 0; b < borderSize; b++)
{
for (int c = 0; c < chan; c++)
{
leftBorder [b*chan + c] = leftBorder [borderSize*chan + c];
rightBorder[b*chan + c] = rightBorder[-chan + c];
}
}
}
template<typename T>
void fillBorderReflectRow(uint8_t* row, int length, int chan, int borderSize)
{
auto leftBorder = reinterpret_cast<T*>(row);
auto rightBorder = leftBorder + (length - borderSize) * chan;
for (int b = 0; b < borderSize; b++)
{
for (int c = 0; c < chan; c++)
{
leftBorder [b*chan + c] = leftBorder [(2*borderSize - b)*chan + c];
rightBorder[b*chan + c] = rightBorder[(-b - 2)*chan + c];
}
}
}
template<typename T>
void fillConstBorderRow(uint8_t* row, int length, int chan, int borderSize, cv::gapi::own::Scalar borderValue)
{
GAPI_DbgAssert(chan > 0 && chan <= 4);
auto leftBorder = reinterpret_cast<T*>(row);
auto rightBorder = leftBorder + (length - borderSize) * chan;
for (int b = 0; b < borderSize; b++)
{
for (int c = 0; c < chan; c++)
{
leftBorder [b*chan + c] = fluid::saturate<T>(borderValue[c], fluid::roundd);
rightBorder[b*chan + c] = fluid::saturate<T>(borderValue[c], fluid::roundd);
}
}
}
// Fills const border pixels in the whole mat
void fillBorderConstant(int borderSize, cv::gapi::own::Scalar borderValue, cv::Mat& mat)
{
// cv::Scalar can contain maximum 4 chan
GAPI_Assert(mat.channels() > 0 && mat.channels() <= 4);
auto getFillBorderRowFunc = [&](int type) {
switch(type)
{
case CV_8U: return &fillConstBorderRow< uint8_t>; break;
case CV_16S: return &fillConstBorderRow< int16_t>; break;
case CV_16U: return &fillConstBorderRow<uint16_t>; break;
case CV_32F: return &fillConstBorderRow< float >; break;
default: CV_Assert(false); return &fillConstBorderRow<uint8_t>;
}
};
auto fillBorderRow = getFillBorderRowFunc(mat.depth());
for (int y = 0; y < mat.rows; y++)
{
fillBorderRow(mat.ptr(y), mat.cols, mat.channels(), borderSize, borderValue);
}
}
} // anonymous namespace
fluid::BorderHandler::BorderHandler(int border_size)
{
CV_Assert(border_size > 0);
m_border_size = border_size;
}
template <int BorderType>
fluid::BorderHandlerT<BorderType>::BorderHandlerT(int border_size, int data_type)
: BorderHandler(border_size)
{
auto getFillBorderRowFunc = [&](int border, int dataType) {
if (border == cv::BORDER_REPLICATE)
{
switch(dataType)
{
case CV_8U: return &fillBorderReplicateRow< uint8_t>; break;
case CV_16S: return &fillBorderReplicateRow< int16_t>; break;
case CV_16U: return &fillBorderReplicateRow<uint16_t>; break;
case CV_32F: return &fillBorderReplicateRow< float >; break;
default: CV_Assert(!"Unsupported data type"); return &fillBorderReplicateRow<uint8_t>;
}
}
else if (border == cv::BORDER_REFLECT_101)
{
switch(dataType)
{
case CV_8U: return &fillBorderReflectRow< uint8_t>; break;
case CV_16S: return &fillBorderReflectRow< int16_t>; break;
case CV_16U: return &fillBorderReflectRow<uint16_t>; break;
case CV_32F: return &fillBorderReflectRow< float >; break;
default: CV_Assert(!"Unsupported data type"); return &fillBorderReflectRow<uint8_t>;
}
}
else
{
CV_Assert(!"Unsupported border type");
return &fillBorderReflectRow<uint8_t>;
}
};
m_fill_border_row = getFillBorderRowFunc(BorderType, data_type);
}
namespace {
template <int BorderType> int getBorderIdx(int log_idx, int desc_height);
template<> int getBorderIdx<cv::BORDER_REPLICATE>(int log_idx, int desc_height)
{
return log_idx < 0 ? 0 : desc_height - 1;
}
template<> int getBorderIdx<cv::BORDER_REFLECT_101>(int log_idx, int desc_height)
{
return log_idx < 0 ? -log_idx : 2*(desc_height - 1) - log_idx;
}
} // namespace
template <int BorderType>
const uint8_t* fluid::BorderHandlerT<BorderType>::inLineB(int log_idx, const BufferStorageWithBorder& data, int desc_height) const
{
auto idx = getBorderIdx<BorderType>(log_idx, desc_height);
return data.ptr(idx);
}
fluid::BorderHandlerT<cv::BORDER_CONSTANT>::BorderHandlerT(int border_size, cv::gapi::own::Scalar border_value, int data_type, int desc_width)
: BorderHandler(border_size), m_border_value(border_value)
{
m_const_border.create(1, desc_width + 2*m_border_size, data_type);
m_const_border = cv::gapi::own::to_ocv(border_value);
}
const uint8_t* fluid::BorderHandlerT<cv::BORDER_CONSTANT>::inLineB(int /*log_idx*/, const BufferStorageWithBorder& /*data*/, int /*desc_height*/) const
{
return m_const_border.ptr(0, m_border_size);
}
void fluid::BorderHandlerT<cv::BORDER_CONSTANT>::fillCompileTimeBorder(BufferStorageWithBorder& data) const
{
cv::gapi::fillBorderConstant(m_border_size, m_border_value, data.data());
}
template <int BorderType>
void fluid::BorderHandlerT<BorderType>::updateBorderPixels(BufferStorageWithBorder &data, int startLine, int nLines) const
{
auto& mat = data.data();
auto length = mat.cols;
auto chan = mat.channels();
for (int l = startLine; l < startLine + nLines; l++)
{
auto row = mat.ptr(data.physIdx(l));
m_fill_border_row(row, length, chan, m_border_size);
}
}
std::size_t fluid::BorderHandlerT<cv::BORDER_CONSTANT>::size() const
{
return m_const_border.total() * m_const_border.elemSize();
}
// Fluid BufferStorage implementation //////////////////////////////////////////
void fluid::BufferStorageWithBorder::create(int capacity, int desc_width, int dtype, int border_size, Border border)
{
auto width = (desc_width + 2*border_size);
m_data.create(capacity, width, dtype);
switch(border.type)
{
case cv::BORDER_CONSTANT:
m_borderHandler.reset(new BorderHandlerT<cv::BORDER_CONSTANT>(border_size, border.value, dtype, desc_width)); break;
case cv::BORDER_REPLICATE:
m_borderHandler.reset(new BorderHandlerT<cv::BORDER_REPLICATE>(border_size, dtype)); break;
case cv::BORDER_REFLECT_101:
m_borderHandler.reset(new BorderHandlerT<cv::BORDER_REFLECT_101>(border_size, dtype)); break;
default:
CV_Assert(false);
}
m_borderHandler->fillCompileTimeBorder(*this);
}
void fluid::BufferStorageWithoutBorder::create(int capacity, int desc_width, int dtype)
{
auto width = desc_width;
m_data.create(capacity, width, dtype);
m_is_virtual = true;
}
const uint8_t* fluid::BufferStorageWithBorder::inLineB(int log_idx, int desc_height) const
{
if (log_idx < 0 || log_idx >= desc_height)
{
return m_borderHandler->inLineB(log_idx, *this, desc_height);
}
else
{
return ptr(log_idx);
}
}
const uint8_t* fluid::BufferStorageWithoutBorder::inLineB(int log_idx, int /*desc_height*/) const
{
return ptr(log_idx);
}
static void copyWithoutBorder(const cv::Mat& src, int src_border_size, cv::Mat& dst, int dst_border_size, int startSrcLine, int startDstLine, int lpi)
{
// FIXME use cv::gapi::own::Rect when implement cv::gapi::own::Mat
auto subSrc = src(cv::Rect{src_border_size, startSrcLine, src.cols - 2*src_border_size, lpi});
auto subDst = dst(cv::Rect{dst_border_size, startDstLine, dst.cols - 2*dst_border_size, lpi});
subSrc.copyTo(subDst);
}
void fluid::BufferStorageWithoutBorder::copyTo(BufferStorageWithBorder &dst, int startLine, int nLines) const
{
for (int l = startLine; l < startLine + nLines; l++)
{
copyWithoutBorder(m_data, 0, dst.data(), dst.borderSize(), physIdx(l), dst.physIdx(l), 1);
}
}
void fluid::BufferStorageWithBorder::copyTo(BufferStorageWithBorder &dst, int startLine, int nLines) const
{
// Copy required lpi lines line by line (to avoid wrap if invoked for multiple lines)
for (int l = startLine; l < startLine + nLines; l++)
{
copyWithoutBorder(m_data, borderSize(), dst.data(), dst.borderSize(), physIdx(l), dst.physIdx(l), 1);
}
}
// FIXME? remember parent and remove src parameter?
void fluid::BufferStorageWithBorder::updateBeforeRead(int startLine, int nLines, const BufferStorage& src)
{
// TODO:
// Cover with tests!!
// (Ensure that there are no redundant copies done
// and only required (not fetched before) lines are copied)
GAPI_DbgAssert(startLine >= 0);
src.copyTo(*this, startLine, nLines);
m_borderHandler->updateBorderPixels(*this, startLine, nLines);
}
void fluid::BufferStorageWithoutBorder::updateBeforeRead(int /*startLine*/, int /*lpi*/, const BufferStorage& /*src*/)
{
/* nothing */
}
void fluid::BufferStorageWithBorder::updateAfterWrite(int startLine, int nLines)
{
// FIXME?
// Actually startLine + nLines can be > logical height so
// redundant end lines which will never be read
// can be filled in the ring buffer
m_borderHandler->updateBorderPixels(*this, startLine, nLines);
}
void fluid::BufferStorageWithoutBorder::updateAfterWrite(int /*startLine*/, int /*lpi*/)
{
/* nothing */
}
size_t fluid::BufferStorageWithBorder::size() const
{
return m_data.total()*m_data.elemSize() + m_borderHandler->size();
}
size_t fluid::BufferStorageWithoutBorder::size() const
{
return m_data.total()*m_data.elemSize();
}
namespace fluid {
namespace {
std::unique_ptr<fluid::BufferStorage> createStorage(int capacity, int desc_width, int type,
int border_size, fluid::BorderOpt border);
std::unique_ptr<fluid::BufferStorage> createStorage(int capacity, int desc_width, int type,
int border_size, fluid::BorderOpt border)
{
if (border)
{
std::unique_ptr<fluid::BufferStorageWithBorder> storage(new BufferStorageWithBorder);
storage->create(capacity, desc_width, type, border_size, border.value());
return std::move(storage);
}
std::unique_ptr<BufferStorageWithoutBorder> storage(new BufferStorageWithoutBorder);
storage->create(capacity, desc_width, type);
return std::move(storage);
}
std::unique_ptr<BufferStorage> createStorage(const cv::Mat& data, cv::gapi::own::Rect roi);
std::unique_ptr<BufferStorage> createStorage(const cv::Mat& data, cv::gapi::own::Rect roi)
{
std::unique_ptr<BufferStorageWithoutBorder> storage(new BufferStorageWithoutBorder);
storage->attach(data, roi);
return std::move(storage);
}
} // namespace
} // namespace fluid
// Fluid View implementation ///////////////////////////////////////////////////
void fluid::View::Priv::reset(int linesForFirstIteration)
{
GAPI_DbgAssert(m_p);
m_lines_next_iter = linesForFirstIteration;
m_read_caret = m_p->priv().readStart();
}
void fluid::View::Priv::readDone(int linesRead, int linesForNextIteration)
{
CV_DbgAssert(m_p);
m_read_caret += linesRead;
m_read_caret %= m_p->meta().size.height;
m_lines_next_iter = linesForNextIteration;
}
bool fluid::View::Priv::ready() const
{
auto lastWrittenLine = m_p->priv().writeStart() + m_p->linesReady();
// + bottom border
if (lastWrittenLine == m_p->meta().size.height) lastWrittenLine += m_border_size;
// + top border
lastWrittenLine += m_border_size;
auto lastRequiredLine = m_read_caret + m_lines_next_iter;
return lastWrittenLine >= lastRequiredLine;
}
fluid::ViewPrivWithoutOwnBorder::ViewPrivWithoutOwnBorder(const Buffer *parent, int borderSize)
{
CV_Assert(parent);
m_p = parent;
m_border_size = borderSize;
}
const uint8_t* fluid::ViewPrivWithoutOwnBorder::InLineB(int index) const
{
GAPI_DbgAssert(m_p);
const auto &p_priv = m_p->priv();
CV_Assert( index >= -m_border_size
&& index < -m_border_size + m_lines_next_iter);
const int log_idx = m_read_caret + index;
return p_priv.storage().inLineB(log_idx, m_p->meta().size.height);
}
fluid::ViewPrivWithOwnBorder::ViewPrivWithOwnBorder(const Buffer *parent, int lineConsumption, int borderSize, Border border)
{
GAPI_Assert(parent);
m_p = parent;
m_border_size = borderSize;
auto desc = m_p->meta();
int type = CV_MAKETYPE(desc.depth, desc.chan);
m_own_storage.create(lineConsumption, desc.size.width, type, borderSize, border);
}
void fluid::ViewPrivWithOwnBorder::prepareToRead()
{
int startLine = 0;
int nLines = 0;
if (m_read_caret == m_p->priv().readStart())
{
// Need to fetch full window on the first iteration
startLine = (m_read_caret > m_border_size) ? m_read_caret - m_border_size : 0;
nLines = m_lines_next_iter;
}
else
{
startLine = m_read_caret + m_border_size;
nLines = m_lines_next_iter - 2*m_border_size;
}
m_own_storage.updateBeforeRead(startLine, nLines, m_p->priv().storage());
}
std::size_t fluid::ViewPrivWithOwnBorder::size() const
{
GAPI_DbgAssert(m_p);
return m_own_storage.size();
}
const uint8_t* fluid::ViewPrivWithOwnBorder::InLineB(int index) const
{
GAPI_DbgAssert(m_p);
GAPI_Assert( index >= -m_border_size
&& index < -m_border_size + m_lines_next_iter);
const int log_idx = m_read_caret + index;
return m_own_storage.inLineB(log_idx, m_p->meta().size.height);
}
const uint8_t* fluid::View::InLineB(int index) const
{
return m_priv->InLineB(index);
}
fluid::View::operator bool() const
{
return m_priv != nullptr && m_priv->m_p != nullptr;
}
int fluid::View::length() const
{
return m_priv->m_p->length();
}
bool fluid::View::ready() const
{
return m_priv->ready();
}
int fluid::View::y() const
{
return m_priv->m_read_caret - m_priv->m_border_size;
}
cv::GMatDesc fluid::View::meta() const
{
// FIXME: cover with test!
return m_priv->m_p->meta();
}
fluid::View::Priv& fluid::View::priv()
{
return *m_priv;
}
const fluid::View::Priv& fluid::View::priv() const
{
return *m_priv;
}
// Fluid Buffer implementation /////////////////////////////////////////////////
fluid::Buffer::Priv::Priv(int read_start, cv::gapi::own::Rect roi)
: m_readStart(read_start)
, m_roi(roi)
{}
void fluid::Buffer::Priv::init(const cv::GMatDesc &desc,
int line_consumption,
int border_size,
int skew,
int wlpi,
int readStartPos,
cv::gapi::own::Rect roi)
{
GAPI_Assert(m_line_consumption == -1);
GAPI_Assert(line_consumption > 0);
m_line_consumption = line_consumption;
m_border_size = border_size;
m_skew = skew;
m_writer_lpi = wlpi;
m_desc = desc;
m_readStart = readStartPos;
m_roi = roi;
}
void fluid::Buffer::Priv::allocate(BorderOpt border)
{
GAPI_Assert(!m_storage);
// Init physical buffer
// FIXME? combine with skew?
auto maxRead = m_line_consumption + m_skew;
auto maxWritten = m_writer_lpi;
auto max = std::max(maxRead, maxWritten);
auto min = std::min(maxRead, maxWritten);
// FIXME:
// Fix the deadlock (completely)!!!
auto data_height = static_cast<int>(std::ceil((double)max / min) * min);
m_storage = createStorage(data_height,
m_desc.size.width,
CV_MAKETYPE(m_desc.depth, m_desc.chan),
m_border_size,
border);
// Finally, initialize carets
m_write_caret = 0;
}
void fluid::Buffer::Priv::bindTo(const cv::Mat &data, bool is_input)
{
// FIXME: move all these fields into a separate structure
GAPI_Assert(m_skew == 0);
GAPI_Assert(m_desc == cv::descr_of(data));
if ( is_input) CV_Assert(m_writer_lpi == 1);
m_storage = createStorage(data, m_roi);
m_is_input = is_input;
m_write_caret = is_input ? writeEnd(): writeStart();
// NB: views remain the same!
}
bool fluid::Buffer::Priv::full() const
{
int slowest_y = writeEnd();
if (!m_views.empty())
{
// reset with maximum possible value and then find minimum
slowest_y = m_desc.size.height;
for (const auto &v : m_views) slowest_y = std::min(slowest_y, v.y());
}
return m_write_caret + lpi() - slowest_y > m_storage->rows();
}
void fluid::Buffer::Priv::writeDone()
{
// There are possible optimizations which can be done to fill a border values
// in compile time of the graph (for example border is const),
// so there is no need to update border values after each write.
// If such optimizations weren't applied, fill border for lines
// which have been just written
m_storage->updateAfterWrite(m_write_caret, m_writer_lpi);
// Final write may produce less LPI, so
// write caret may exceed logical buffer size
m_write_caret += m_writer_lpi;
// FIXME: add consistency check!
}
void fluid::Buffer::Priv::reset()
{
m_write_caret = m_is_input ? writeEnd() : writeStart();
}
int fluid::Buffer::Priv::size() const
{
std::size_t view_sz = 0;
for (const auto &v : m_views) view_sz += v.priv().size();
auto total = view_sz;
if (m_storage) total += m_storage->size();
// FIXME: Change API to return size_t!!!
return static_cast<int>(total);
}
int fluid::Buffer::Priv::linesReady() const
{
if (m_is_input)
{
return m_storage->rows();
}
else
{
const int writes = std::min(m_write_caret - writeStart(), outputLines());
return writes;
}
}
uint8_t* fluid::Buffer::Priv::OutLineB(int index)
{
GAPI_Assert(index >= 0 && index < m_writer_lpi);
return m_storage->ptr(m_write_caret + index);
}
int fluid::Buffer::Priv::lpi() const
{
// FIXME:
// m_write_caret can be greater than m_writeRoi.y + m_writeRoi.height, so return value can be negative !!!
return std::min(writeEnd() - m_write_caret, m_writer_lpi);
}
fluid::Buffer::Buffer()
: m_priv(new Priv())
{
}
fluid::Buffer::Buffer(const cv::GMatDesc &desc)
: m_priv(new Priv())
{
int lineConsumption = 1;
int border = 0, skew = 0, wlpi = 1, readStart = 0;
cv::gapi::own::Rect roi = {0, 0, desc.size.width, desc.size.height};
m_priv->init(desc, lineConsumption, border, skew, wlpi, readStart, roi);
m_priv->allocate({});
}
fluid::Buffer::Buffer(const cv::GMatDesc &desc,
int max_line_consumption,
int border_size,
int skew,
int wlpi,
BorderOpt border)
: m_priv(new Priv())
{
int readStart = 0;
cv::gapi::own::Rect roi = {0, 0, desc.size.width, desc.size.height};
m_priv->init(desc, max_line_consumption, border_size, skew, wlpi, readStart, roi);
m_priv->allocate(border);
}
fluid::Buffer::Buffer(const cv::Mat &data, bool is_input)
: m_priv(new Priv())
{
int lineConsumption = 1;
int border = 0, skew = 0, wlpi = 1, readStart = 0;
cv::gapi::own::Rect roi{0, 0, data.cols, data.rows};
m_priv->init(descr_of(data), lineConsumption, border, skew, wlpi, readStart, roi);
m_priv->bindTo(data, is_input);
}
uint8_t* fluid::Buffer::Buffer::OutLineB(int index)
{
return m_priv->OutLineB(index);
}
int fluid::Buffer::linesReady() const
{
return m_priv->linesReady();
}
int fluid::Buffer::length() const
{
return meta().size.width;
}
int fluid::Buffer::lpi() const
{
return m_priv->lpi();
}
cv::GMatDesc fluid::Buffer::meta() const
{
return m_priv->meta();
}
fluid::View::View(Priv* p)
: m_priv(p)
{ /* nothing */ }
fluid::View fluid::Buffer::mkView(int lineConsumption, int borderSize, BorderOpt border, bool ownStorage)
{
// FIXME: logic outside of Priv (because View takes pointer to Buffer)
auto view = ownStorage ? View(new ViewPrivWithOwnBorder(this, lineConsumption, borderSize, border.value()))
: View(new ViewPrivWithoutOwnBorder(this, borderSize));
m_priv->addView(view);
return view;
}
void fluid::debugBufferPriv(const fluid::Buffer& buffer, std::ostream &os)
{
// FIXME Use cv::gapi::own Size and Rect with operator<<, when merged ADE-285
const auto& p = buffer.priv();
os << "Fluid buffer " << std::hex << &buffer << std::dec
<< " " << p.m_desc.size.width << " x " << p.m_desc.size.height << "]"
<< " readStart:" << p.m_readStart
<< " roi:" << "[" << p.m_roi.width << " x " << p.m_roi.height << " from (" << p.m_roi.x << ", " << p.m_roi.y << ")]"
<<" (phys " << "[" << p.storage().cols() << " x " << p.storage().rows() << "]" << ") :"
<< " w: " << p.m_write_caret
<< ", r: [";
for (const auto &v : p.m_views) { os << &v.priv() << ":" << v.y() << " "; }
os << "], avail: " << buffer.linesReady()
<< std::endl;
}
void fluid::Buffer::debug(std::ostream &os) const
{
debugBufferPriv(*this, os);
}
fluid::Buffer::Priv& fluid::Buffer::priv()
{
return *m_priv;
}
const fluid::Buffer::Priv& fluid::Buffer::priv() const
{
return *m_priv;
}
int fluid::Buffer::y() const
{
return m_priv->y();
}
} // namespace cv::gapi
} // namespace cv

@ -0,0 +1,298 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_FLUID_BUFFER_PRIV_HPP
#define OPENCV_GAPI_FLUID_BUFFER_PRIV_HPP
#include <vector>
#include "opencv2/gapi/fluid/gfluidbuffer.hpp"
#include "opencv2/gapi/own/convert.hpp" // cv::gapi::own::to_ocv
namespace cv {
namespace gapi {
namespace fluid {
class BufferStorageWithBorder;
class BorderHandler
{
protected:
int m_border_size;
public:
BorderHandler(int border_size);
virtual ~BorderHandler() = default;
virtual const uint8_t* inLineB(int log_idx, const BufferStorageWithBorder &data, int desc_height) const = 0;
// Fills border pixels after buffer allocation (if possible (for const border))
virtual void fillCompileTimeBorder(BufferStorageWithBorder &) const { /* nothing */ }
// Fills required border lines
virtual void updateBorderPixels(BufferStorageWithBorder& /*data*/, int /*startLine*/, int /*lpi*/) const { /* nothing */ }
inline int borderSize() const { return m_border_size; }
virtual std::size_t size() const { return 0; }
};
template<int BorderType>
class BorderHandlerT : public BorderHandler
{
std::function<void(uint8_t*,int,int,int)> m_fill_border_row;
public:
BorderHandlerT(int border_size, int data_type);
virtual void updateBorderPixels(BufferStorageWithBorder& data, int startLine, int lpi) const override;
virtual const uint8_t* inLineB(int log_idx, const BufferStorageWithBorder &data, int desc_height) const override;
};
template<>
class BorderHandlerT<cv::BORDER_CONSTANT> : public BorderHandler
{
cv::gapi::own::Scalar m_border_value;
cv::Mat m_const_border;
public:
BorderHandlerT(int border_size, cv::gapi::own::Scalar border_value, int data_type, int desc_width);
virtual const uint8_t* inLineB(int log_idx, const BufferStorageWithBorder &data, int desc_height) const override;
virtual void fillCompileTimeBorder(BufferStorageWithBorder &) const override;
virtual std::size_t size() const override;
};
class BufferStorage
{
protected:
cv::Mat m_data;
public:
virtual void copyTo(BufferStorageWithBorder &dst, int startLine, int nLines) const = 0;
virtual ~BufferStorage() = default;
virtual const uint8_t* ptr(int idx) const = 0;
virtual uint8_t* ptr(int idx) = 0;
inline bool empty() const { return m_data.empty(); }
inline const cv::Mat& data() const { return m_data; }
inline cv::Mat& data() { return m_data; }
inline int rows() const { return m_data.rows; }
inline int cols() const { return m_data.cols; }
inline int type() const { return m_data.type(); }
virtual const uint8_t* inLineB(int log_idx, int desc_height) const = 0;
// FIXME? remember parent and remove src parameter?
virtual void updateBeforeRead(int startLine, int nLines, const BufferStorage& src) = 0;
virtual void updateAfterWrite(int startLine, int nLines) = 0;
virtual int physIdx(int logIdx) const = 0;
virtual size_t size() const = 0;
};
class BufferStorageWithoutBorder final : public BufferStorage
{
bool m_is_virtual = true;
cv::gapi::own::Rect m_roi;
public:
virtual void copyTo(BufferStorageWithBorder &dst, int startLine, int nLines) const override;
inline virtual const uint8_t* ptr(int idx) const override
{
GAPI_DbgAssert((m_is_virtual && m_roi == cv::gapi::own::Rect{}) || (!m_is_virtual && m_roi != cv::gapi::own::Rect{}));
return m_data.ptr(physIdx(idx), 0);
}
inline virtual uint8_t* ptr(int idx) override
{
GAPI_DbgAssert((m_is_virtual && m_roi == cv::gapi::own::Rect{}) || (!m_is_virtual && m_roi != cv::gapi::own::Rect{}));
return m_data.ptr(physIdx(idx), 0);
}
inline void attach(const cv::Mat& _data, const cv::gapi::own::Rect& _roi)
{
m_data = _data(cv::gapi::own::to_ocv(_roi));
m_roi = _roi;
m_is_virtual = false;
}
void create(int capacity, int desc_width, int type);
inline virtual const uint8_t* inLineB(int log_idx, int desc_height) const override;
virtual void updateBeforeRead(int startLine, int nLines, const BufferStorage& src) override;
virtual void updateAfterWrite(int startLine, int nLines) override;
inline virtual int physIdx(int logIdx) const override { return (logIdx - m_roi.y) % m_data.rows; }
virtual size_t size() const override;
};
class BufferStorageWithBorder final: public BufferStorage
{
std::unique_ptr<BorderHandler> m_borderHandler;
public:
inline int borderSize() const { return m_borderHandler->borderSize(); }
virtual void copyTo(BufferStorageWithBorder &dst, int startLine, int nLines) const override;
inline virtual const uint8_t* ptr(int idx) const override
{
return m_data.ptr(physIdx(idx), borderSize());
}
inline virtual uint8_t* ptr(int idx) override
{
return m_data.ptr(physIdx(idx), borderSize());
}
void create(int capacity, int desc_width, int type, int border_size, Border border);
virtual const uint8_t* inLineB(int log_idx, int desc_height) const override;
virtual void updateBeforeRead(int startLine, int nLines, const BufferStorage &src) override;
virtual void updateAfterWrite(int startLine, int nLines) override;
inline virtual int physIdx(int logIdx) const override { return logIdx % m_data.rows; }
virtual size_t size() const override;
};
// FIXME: GAPI_EXPORTS is used here only to access internal methods
// like readDone/writeDone in low-level tests
class GAPI_EXPORTS View::Priv
{
friend class View;
protected:
const Buffer *m_p = nullptr; // FIXME replace with weak_ptr
int m_read_caret = -1;
int m_lines_next_iter = -1;
int m_border_size = -1;
public:
virtual ~Priv() = default;
// API used by actors/backend
virtual void prepareToRead() = 0;
void readDone(int linesRead, int linesForNextIteration);
void reset(int linesForFirstIteration);
virtual std::size_t size() const = 0;
// Does the view have enough unread lines for next iteration
bool ready() const;
// API used (indirectly) by user code
virtual const uint8_t* InLineB(int index) const = 0;
};
class ViewPrivWithoutOwnBorder final : public View::Priv
{
public:
// API used by actors/backend
ViewPrivWithoutOwnBorder(const Buffer *p, int borderSize);
virtual void prepareToRead() override { /* nothing */ }
virtual std::size_t size() const override { return 0; }
// API used (indirectly) by user code
virtual const uint8_t* InLineB(int index) const override;
};
class ViewPrivWithOwnBorder final : public View::Priv
{
BufferStorageWithBorder m_own_storage;
public:
// API used by actors/backend
ViewPrivWithOwnBorder(const Buffer *p, int lineCapacity, int borderSize, Border border);
virtual void prepareToRead() override;
virtual std::size_t size() const override;
// API used (indirectly) by user code
virtual const uint8_t* InLineB(int index) const override;
};
void debugBufferPriv(const Buffer& buffer, std::ostream &os);
// FIXME: GAPI_EXPORTS is used here only to access internal methods
// like readDone/writeDone in low-level tests
class GAPI_EXPORTS Buffer::Priv
{
int m_line_consumption = -1;
int m_border_size = -1;
int m_skew = -1;
int m_writer_lpi = 1;
cv::GMatDesc m_desc = cv::GMatDesc{-1,-1,{-1,-1}};
bool m_is_input = false;
int m_write_caret = -1;
std::vector<View> m_views;
std::unique_ptr<BufferStorage> m_storage;
// Coordinate starting from which this buffer is assumed
// to be read (with border not being taken into account)
int m_readStart;
cv::gapi::own::Rect m_roi;
friend void debugBufferPriv(const Buffer& p, std::ostream &os);
public:
Priv() = default;
Priv(int read_start, cv::gapi::own::Rect roi);
inline const BufferStorage& storage() const { return *m_storage.get(); }
// API used by actors/backend
void init(const cv::GMatDesc &desc,
int line_consumption,
int border_size,
int skew,
int wlpi,
int readStart,
cv::gapi::own::Rect roi);
void allocate(BorderOpt border);
void bindTo(const cv::Mat &data, bool is_input);
void addView(const View& view) { m_views.push_back(view); }
const GMatDesc meta() const { return m_desc; }
bool full() const;
void writeDone();
void reset();
int size() const;
int linesReady() const;
inline int y() const { return m_write_caret; }
inline int writer_lpi() const { return m_writer_lpi; }
// API used (indirectly) by user code
uint8_t* OutLineB(int index = 0);
int lpi() const;
inline int readStart() const { return m_readStart; }
inline int writeStart() const { return m_roi.y; }
inline int writeEnd() const { return m_roi.y + m_roi.height; }
inline int outputLines() const { return m_roi.height; }
};
} // namespace cv::gapi::fluid
} // namespace cv::gapi
} // namespace cv
#endif // OPENCV_GAPI_FLUID_BUFFER_PRIV_HPP

File diff suppressed because it is too large Load Diff

@ -0,0 +1,19 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GFLUIDCORE_HPP
#define OPENCV_GAPI_GFLUIDCORE_HPP
#include "opencv2/gapi/fluid/gfluidkernel.hpp"
namespace cv { namespace gapi { namespace core { namespace fluid {
GAPI_EXPORTS GKernelPackage kernels();
}}}}
#endif // OPENCV_GAPI_GFLUIDCORE_HPP

File diff suppressed because it is too large Load Diff

@ -0,0 +1,19 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GFLUIDIMGPROC_HPP
#define OPENCV_GAPI_GFLUIDIMGPROC_HPP
#include "opencv2/gapi/fluid/gfluidkernel.hpp"
namespace cv { namespace gapi { namespace imgproc { namespace fluid {
GAPI_EXPORTS GKernelPackage kernels();
}}}}
#endif // OPENCV_GAPI_GFLUIDIMGPROC_HPP

@ -0,0 +1,154 @@
// 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) 2018 Intel Corporation
#ifndef GFLUIDUTILS_HPP
#define GFLUIDUTILS_HPP
#include <limits>
#include <type_traits>
#include <opencv2/gapi/util/compiler_hints.hpp> //UNUSED
namespace cv {
namespace gapi {
namespace fluid {
//-----------------------------
//
// Numeric cast with saturation
//
//-----------------------------
template<typename DST, typename SRC>
static inline DST saturate(SRC x)
{
// only integral types please!
GAPI_DbgAssert(std::is_integral<DST>::value &&
std::is_integral<SRC>::value);
if (std::is_same<DST, SRC>::value)
return static_cast<DST>(x);
if (sizeof(DST) > sizeof(SRC))
return static_cast<DST>(x);
// compiler must recognize this saturation,
// so compile saturate<s16>(a + b) with adds
// instruction (e.g.: _mm_adds_epi16 if x86)
return x < std::numeric_limits<DST>::min()?
std::numeric_limits<DST>::min():
x > std::numeric_limits<DST>::max()?
std::numeric_limits<DST>::max():
static_cast<DST>(x);
}
// Note, that OpenCV rounds differently:
// - like std::round() for add, subtract
// - like std::rint() for multiply, divide
template<typename DST, typename SRC, typename R>
static inline DST saturate(SRC x, R round)
{
if (std::is_floating_point<DST>::value)
{
return static_cast<DST>(x);
}
else if (std::is_integral<SRC>::value)
{
GAPI_DbgAssert(std::is_integral<DST>::value &&
std::is_integral<SRC>::value);
return saturate<DST>(x);
}
else
{
GAPI_DbgAssert(std::is_integral<DST>::value &&
std::is_floating_point<SRC>::value);
#ifdef _WIN32
// Suppress warning about convering x to floating-point
// Note that x is already floating-point at this point
#pragma warning(disable: 4244)
#endif
int ix = static_cast<int>(round(x));
#ifdef _WIN32
#pragma warning(default: 4244)
#endif
return saturate<DST>(ix);
}
}
// explicit suffix 'd' for double type
static inline double ceild(double x) { return std::ceil(x); }
static inline double floord(double x) { return std::floor(x); }
static inline double roundd(double x) { return std::round(x); }
static inline double rintd(double x) { return std::rint(x); }
//--------------------------------
//
// Macros for mappig of data types
//
//--------------------------------
#define UNARY_(DST, SRC, OP, ...) \
if (cv::DataType<DST>::depth == dst.meta().depth && \
cv::DataType<SRC>::depth == src.meta().depth) \
{ \
GAPI_DbgAssert(dst.length() == src.length()); \
GAPI_DbgAssert(dst.meta().chan == src.meta().chan); \
\
OP<DST, SRC>(__VA_ARGS__); \
return; \
}
// especial unary operation: dst is always 8UC1 image
#define INRANGE_(DST, SRC, OP, ...) \
if (cv::DataType<DST>::depth == dst.meta().depth && \
cv::DataType<SRC>::depth == src.meta().depth) \
{ \
GAPI_DbgAssert(dst.length() == src.length()); \
GAPI_DbgAssert(dst.meta().chan == 1); \
\
OP<DST, SRC>(__VA_ARGS__); \
return; \
}
#define BINARY_(DST, SRC1, SRC2, OP, ...) \
if (cv::DataType<DST>::depth == dst.meta().depth && \
cv::DataType<SRC1>::depth == src1.meta().depth && \
cv::DataType<SRC2>::depth == src2.meta().depth) \
{ \
GAPI_DbgAssert(dst.length() == src1.length()); \
GAPI_DbgAssert(dst.length() == src2.length()); \
\
GAPI_DbgAssert(dst.meta().chan == src1.meta().chan); \
GAPI_DbgAssert(dst.meta().chan == src2.meta().chan); \
\
OP<DST, SRC1, SRC2>(__VA_ARGS__); \
return; \
}
// especial ternary operation: src3 has only one channel
#define SELECT_(DST, SRC1, SRC2, SRC3, OP, ...) \
if (cv::DataType<DST>::depth == dst.meta().depth && \
cv::DataType<SRC1>::depth == src1.meta().depth && \
cv::DataType<SRC2>::depth == src2.meta().depth && \
cv::DataType<SRC3>::depth == src3.meta().depth) \
{ \
GAPI_DbgAssert(dst.length() == src1.length()); \
GAPI_DbgAssert(dst.length() == src2.length()); \
GAPI_DbgAssert(dst.length() == src3.length()); \
\
GAPI_DbgAssert(dst.meta().chan == src1.meta().chan); \
GAPI_DbgAssert(dst.meta().chan == src2.meta().chan); \
GAPI_DbgAssert( 1 == src3.meta().chan); \
\
OP<DST, SRC1, SRC2, SRC3>(__VA_ARGS__); \
return; \
}
} // namespace fluid
} // namespace gapi
} // namespace cv
#endif // GFLUIDUTILS_HPP

@ -0,0 +1 @@
This directory contains G-API graph compiler logic.

@ -0,0 +1,131 @@
// 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) 2018 Intel Corporation
#include <ade/graph.hpp>
#include "opencv2/gapi/gproto.hpp" // descr_of
#include "opencv2/gapi/gcompiled.hpp"
#include "compiler/gcompiled_priv.hpp"
#include "backends/common/gbackend.hpp"
// GCompiled private implementation ////////////////////////////////////////////
void cv::GCompiled::Priv::setup(const GMetaArgs &_metaArgs,
const GMetaArgs &_outMetas,
std::unique_ptr<cv::gimpl::GExecutor> &&_pE)
{
m_metas = _metaArgs;
m_outMetas = _outMetas;
m_exec = std::move(_pE);
}
bool cv::GCompiled::Priv::isEmpty() const
{
return !m_exec;
}
void cv::GCompiled::Priv::run(cv::gimpl::GRuntimeArgs &&args)
{
// Strip away types since ADE knows nothing about that
// args will be taken by specific GBackendExecutables
checkArgs(args);
m_exec->run(std::move(args));
}
const cv::GMetaArgs& cv::GCompiled::Priv::metas() const
{
return m_metas;
}
const cv::GMetaArgs& cv::GCompiled::Priv::outMetas() const
{
return m_outMetas;
}
void cv::GCompiled::Priv::checkArgs(const cv::gimpl::GRuntimeArgs &args) const
{
const auto runtime_metas = descr_of(args.inObjs);
if (runtime_metas != m_metas)
{
util::throw_error(std::logic_error("This object was compiled "
"for different metadata!"));
// FIXME: Add details on what is actually wrong
}
}
const cv::gimpl::GModel::Graph& cv::GCompiled::Priv::model() const
{
GAPI_Assert(nullptr != m_exec);
return m_exec->model();
}
// GCompiled public implementation /////////////////////////////////////////////
cv::GCompiled::GCompiled()
: m_priv(new Priv())
{
}
cv::GCompiled::operator bool() const
{
return !m_priv->isEmpty();
}
void cv::GCompiled::operator() (GRunArgs &&ins, GRunArgsP &&outs)
{
// FIXME: Check that <outs> matches the protocol
m_priv->run(cv::gimpl::GRuntimeArgs{std::move(ins),std::move(outs)});
}
void cv::GCompiled::operator ()(cv::Mat in, cv::Mat &out)
{
(*this)(cv::gin(in), cv::gout(out));
}
void cv::GCompiled::operator() (cv::Mat in, cv::Scalar &out)
{
(*this)(cv::gin(in), cv::gout(out));
}
void cv::GCompiled::operator() (cv::Mat in1, cv::Mat in2, cv::Mat &out)
{
(*this)(cv::gin(in1, in2), cv::gout(out));
}
void cv::GCompiled::operator() (cv::Mat in1, cv::Mat in2, cv::Scalar &out)
{
(*this)(cv::gin(in1, in2), cv::gout(out));
}
void cv::GCompiled::operator ()(const std::vector<cv::Mat> &ins,
const std::vector<cv::Mat> &outs)
{
GRunArgs call_ins;
GRunArgsP call_outs;
// Make a temporary copy of vector outs - cv::Mats are copies anyway
auto tmp = outs;
for (const cv::Mat &m : ins) { call_ins.emplace_back(m); }
for ( cv::Mat &m : tmp) { call_outs.emplace_back(&m); }
(*this)(std::move(call_ins), std::move(call_outs));
}
const cv::GMetaArgs& cv::GCompiled::metas() const
{
return m_priv->metas();
}
const cv::GMetaArgs& cv::GCompiled::outMetas() const
{
return m_priv->outMetas();
}
cv::GCompiled::Priv& cv::GCompiled::priv()
{
return *m_priv;
}

@ -0,0 +1,58 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GCOMPILED_PRIV_HPP
#define OPENCV_GAPI_GCOMPILED_PRIV_HPP
#include <memory> // unique_ptr
#include "opencv2/gapi/util/optional.hpp"
#include "compiler/gmodel.hpp"
#include "executor/gexecutor.hpp"
// NB: BTW, GCompiled is the only "public API" class which
// private part (implementaion) is hosted in the "compiler/" module.
//
// This file is here just to keep ADE hidden from the top-level APIs.
//
// As the thing becomes more complex, appropriate API and implementation
// part will be placed to api/ and compiler/ modules respectively.
namespace cv {
namespace gimpl
{
struct GRuntimeArgs;
};
// FIXME: GAPI_EXPORTS is here only due to tests and Windows linker issues
class GAPI_EXPORTS GCompiled::Priv
{
// NB: For now, a GCompiled keeps the original ade::Graph alive.
// If we want to go autonomous, we might to do something with this.
GMetaArgs m_metas; // passed by user
GMetaArgs m_outMetas; // inferred by compiler
std::unique_ptr<cv::gimpl::GExecutor> m_exec;
void checkArgs(const cv::gimpl::GRuntimeArgs &args) const;
public:
void setup(const GMetaArgs &metaArgs,
const GMetaArgs &outMetas,
std::unique_ptr<cv::gimpl::GExecutor> &&pE);
bool isEmpty() const;
void run(cv::gimpl::GRuntimeArgs &&args);
const GMetaArgs& metas() const;
const GMetaArgs& outMetas() const;
const cv::gimpl::GModel::Graph& model() const;
};
}
#endif // OPENCV_GAPI_GCOMPILED_PRIV_HPP

@ -0,0 +1,273 @@
// 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) 2018 Intel Corporation
#include <vector>
#include <stack>
#include <unordered_map>
#include <ade/util/algorithm.hpp> // any_of
#include <ade/util/zip_range.hpp> // zip_range, indexed
#include <ade/graph.hpp>
#include <ade/passes/check_cycles.hpp>
#include "api/gcomputation_priv.hpp"
#include "api/gnode_priv.hpp" // FIXME: why it is here?
#include "api/gproto_priv.hpp" // FIXME: why it is here?
#include "api/gcall_priv.hpp" // FIXME: why it is here?
#include "api/gapi_priv.hpp" // FIXME: why it is here?
#include "api/gbackend_priv.hpp" // Backend basic API (newInstance, etc)
#include "compiler/gmodel.hpp"
#include "compiler/gmodelbuilder.hpp"
#include "compiler/gcompiler.hpp"
#include "compiler/gcompiled_priv.hpp"
#include "compiler/passes/passes.hpp"
#include "executor/gexecutor.hpp"
#include "backends/common/gbackend.hpp"
// <FIXME:>
#include "opencv2/gapi/cpu/core.hpp" // Also directly refer to Core
#include "opencv2/gapi/cpu/imgproc.hpp" // ...and Imgproc kernel implementations
// </FIXME:>
#include "opencv2/gapi/gcompoundkernel.hpp" // compound::backend()
#include "opencv2/core/cvdef.h"
#include "logger.hpp"
namespace
{
cv::gapi::GKernelPackage getKernelPackage(cv::GCompileArgs &args)
{
static auto ocv_pkg = combine(cv::gapi::core::cpu::kernels(),
cv::gapi::imgproc::cpu::kernels(),
cv::unite_policy::KEEP);
auto user_pkg = cv::gimpl::getCompileArg<cv::gapi::GKernelPackage>(args);
return combine(ocv_pkg, user_pkg.value_or(cv::gapi::GKernelPackage{}), cv::unite_policy::REPLACE);
}
cv::util::optional<std::string> getGraphDumpDirectory(cv::GCompileArgs& args)
{
auto dump_info = cv::gimpl::getCompileArg<cv::graph_dump_path>(args);
if (!dump_info.has_value())
{
const char* path = std::getenv("GRAPH_DUMP_PATH");
return path
? cv::util::make_optional(std::string(path))
: cv::util::optional<std::string>();
}
else
{
return cv::util::make_optional(dump_info.value().m_dump_path);
}
}
} // anonymous namespace
// GCompiler implementation ////////////////////////////////////////////////////
cv::gimpl::GCompiler::GCompiler(const cv::GComputation &c,
GMetaArgs &&metas,
GCompileArgs &&args)
: m_c(c), m_metas(std::move(metas)), m_args(std::move(args))
{
using namespace std::placeholders;
m_all_kernels = getKernelPackage(m_args);
auto lookup_order = getCompileArg<gapi::GLookupOrder>(m_args).value_or(gapi::GLookupOrder());
auto dump_path = getGraphDumpDirectory(m_args);
m_e.addPassStage("init");
m_e.addPass("init", "check_cycles", ade::passes::CheckCycles());
m_e.addPass("init", "expand_kernels", std::bind(passes::expandKernels, _1,
m_all_kernels)); // NB: package is copied
m_e.addPass("init", "topo_sort", ade::passes::TopologicalSort());
m_e.addPass("init", "init_islands", passes::initIslands);
m_e.addPass("init", "check_islands", passes::checkIslands);
// TODO:
// - Check basic graph validity (i.e., all inputs are connected)
// - Complex dependencies (i.e. parent-child) unrolling
// - etc, etc, etc
// Remove GCompoundBackend to avoid calling setupBackend() with it in the list
m_all_kernels.remove(cv::gapi::compound::backend());
m_e.addPass("init", "resolve_kernels", std::bind(passes::resolveKernels, _1,
std::ref(m_all_kernels), // NB: and not copied here
lookup_order));
m_e.addPass("init", "check_islands_content", passes::checkIslandsContent);
m_e.addPassStage("meta");
m_e.addPass("meta", "initialize", std::bind(passes::initMeta, _1, std::ref(m_metas)));
m_e.addPass("meta", "propagate", passes::inferMeta);
m_e.addPass("meta", "finalize", passes::storeResultingMeta);
// moved to another stage, FIXME: two dumps?
// m_e.addPass("meta", "dump_dot", passes::dumpDotStdout);
// Special stage for backend-specific transformations
// FIXME: document passes hierarchy and order for backend developers
m_e.addPassStage("transform");
m_e.addPassStage("exec");
m_e.addPass("exec", "fuse_islands", passes::fuseIslands);
m_e.addPass("exec", "sync_islands", passes::syncIslandTags);
if (dump_path.has_value())
{
m_e.addPass("exec", "dump_dot", std::bind(passes::dumpGraph, _1,
dump_path.value()));
}
// Process backends at the last moment (after all G-API passes are added).
ade::ExecutionEngineSetupContext ectx(m_e);
auto backends = m_all_kernels.backends();
for (auto &b : backends)
{
b.priv().addBackendPasses(ectx);
}
}
void cv::gimpl::GCompiler::validateInputMeta()
{
if (m_metas.size() != m_c.priv().m_ins.size())
{
util::throw_error(std::logic_error
("COMPILE: GComputation interface / metadata mismatch! "
"(expected " + std::to_string(m_c.priv().m_ins.size()) + ", "
"got " + std::to_string(m_metas.size()) + " meta arguments)"));
}
const auto meta_matches = [](const GMetaArg &meta, const GProtoArg &proto) {
switch (proto.index())
{
// FIXME: Auto-generate methods like this from traits:
case GProtoArg::index_of<cv::GMat>():
return util::holds_alternative<cv::GMatDesc>(meta);
case GProtoArg::index_of<cv::GScalar>():
return util::holds_alternative<cv::GScalarDesc>(meta);
case GProtoArg::index_of<cv::detail::GArrayU>():
return util::holds_alternative<cv::GArrayDesc>(meta);
default:
GAPI_Assert(false);
}
return false; // should never happen
};
for (const auto &meta_arg_idx : ade::util::indexed(ade::util::zip(m_metas, m_c.priv().m_ins)))
{
const auto &meta = std::get<0>(ade::util::value(meta_arg_idx));
const auto &proto = std::get<1>(ade::util::value(meta_arg_idx));
if (!meta_matches(meta, proto))
{
const auto index = ade::util::index(meta_arg_idx);
util::throw_error(std::logic_error
("GComputation object type / metadata descriptor mismatch "
"(argument " + std::to_string(index) + ")"));
// FIXME: report what we've got and what we've expected
}
}
// All checks are ok
}
void cv::gimpl::GCompiler::validateOutProtoArgs()
{
for (const auto &out_pos : ade::util::indexed(m_c.priv().m_outs))
{
const auto &node = proto::origin_of(ade::util::value(out_pos)).node;
if (node.shape() != cv::GNode::NodeShape::CALL)
{
auto pos = ade::util::index(out_pos);
util::throw_error(std::logic_error
("Computation output " + std::to_string(pos) +
" is not a result of any operation"));
}
}
}
cv::gimpl::GCompiler::GPtr cv::gimpl::GCompiler::generateGraph()
{
validateInputMeta();
validateOutProtoArgs();
// Generate ADE graph from expression-based computation
std::unique_ptr<ade::Graph> pG(new ade::Graph);
ade::Graph& g = *pG;
GModel::Graph gm(g);
cv::gimpl::GModel::init(gm);
cv::gimpl::GModelBuilder builder(g);
auto proto_slots = builder.put(m_c.priv().m_ins, m_c.priv().m_outs);
GAPI_LOG_INFO(NULL, "Generated graph: " << g.nodes().size() << " nodes" << std::endl);
// Store Computation's protocol in metadata
Protocol p;
std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
gm.metadata().set(p);
return pG;
}
void cv::gimpl::GCompiler::runPasses(ade::Graph &g)
{
m_e.runPasses(g);
GAPI_LOG_INFO(NULL, "All compiler passes are successful");
}
void cv::gimpl::GCompiler::compileIslands(ade::Graph &g)
{
GModel::Graph gm(g);
std::shared_ptr<ade::Graph> gptr(gm.metadata().get<IslandModel>().model);
GIslandModel::Graph gim(*gptr);
// Run topological sort on GIslandModel first
auto pass_ctx = ade::passes::PassContext{*gptr};
ade::passes::TopologicalSort{}(pass_ctx);
// Now compile islands
GIslandModel::compileIslands(gim, g, m_args);
}
cv::GCompiled cv::gimpl::GCompiler::produceCompiled(GPtr &&pg)
{
// This is the final compilation step. Here:
// - An instance of GExecutor is created. Depening on the platform,
// build configuration, etc, a GExecutor may be:
// - a naive single-thread graph interpreter;
// - a std::thread-based thing
// - a TBB-based thing, etc.
// - All this stuff is wrapped into a GCompiled object and returned
// to user.
// Note: this happens in the last pass ("compile_islands"):
// - Each GIsland of GIslandModel instantiates its own,
// backend-specific executable object
// - Every backend gets a subgraph to execute, and builds
// an execution plan for it (backend-specific execution)
// ...before call to produceCompiled();
const auto &outMetas = GModel::ConstGraph(*pg).metadata()
.get<OutputMeta>().outMeta;
std::unique_ptr<GExecutor> pE(new GExecutor(std::move(pg)));
// FIXME: select which executor will be actually used,
// make GExecutor abstract.
GCompiled compiled;
compiled.priv().setup(m_metas, outMetas, std::move(pE));
return compiled;
}
cv::GCompiled cv::gimpl::GCompiler::compile()
{
std::unique_ptr<ade::Graph> pG = generateGraph();
runPasses(*pG);
compileIslands(*pG);
return produceCompiled(std::move(pG));
}

@ -0,0 +1,51 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GCOMPILER_HPP
#define OPENCV_GAPI_GCOMPILER_HPP
#include "opencv2/gapi/gcommon.hpp"
#include "opencv2/gapi/gkernel.hpp"
#include "opencv2/gapi/gcomputation.hpp"
#include <ade/execution_engine/execution_engine.hpp>
namespace cv { namespace gimpl {
// FIXME: exported for internal tests only!
class GAPI_EXPORTS GCompiler
{
const GComputation& m_c;
const GMetaArgs m_metas;
GCompileArgs m_args;
ade::ExecutionEngine m_e;
cv::gapi::GKernelPackage m_all_kernels;
void validateInputMeta();
void validateOutProtoArgs();
public:
explicit GCompiler(const GComputation &c,
GMetaArgs &&metas,
GCompileArgs &&args);
// The method which does everything...
GCompiled compile();
// But is actually composed of this:
using GPtr = std::unique_ptr<ade::Graph>;
GPtr generateGraph(); // Unroll GComputation into a GModel
void runPasses(ade::Graph &g); // Apply all G-API passes on a GModel
void compileIslands(ade::Graph &g); // Instantiate GIslandExecutables in GIslandModel
GCompiled produceCompiled(GPtr &&pg); // Produce GCompiled from processed GModel
};
}}
#endif // OPENCV_GAPI_GCOMPILER_HPP

@ -0,0 +1,287 @@
// 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) 2018 Intel Corporation
#include <sstream>
#include <unordered_set>
#include <unordered_map>
#include <ade/util/checked_cast.hpp>
#include "api/gbackend_priv.hpp" // GBackend::Priv().compile()
#include "compiler/gmodel.hpp"
#include "compiler/gislandmodel.hpp"
#include "logger.hpp" // GAPI_LOG
namespace cv { namespace gimpl {
GIsland::GIsland(const gapi::GBackend &bknd,
ade::NodeHandle op,
util::optional<std::string> &&user_tag)
: m_backend(bknd)
, m_user_tag(std::move(user_tag))
{
m_all.insert(op);
m_in_ops.insert(op);
m_out_ops.insert(op);
}
// _ because of gcc4.8 wanings on ARM
GIsland::GIsland(const gapi::GBackend &_bknd,
node_set &&_all,
node_set &&_in_ops,
node_set &&_out_ops,
util::optional<std::string> &&_user_tag)
: m_backend(_bknd)
, m_all(std::move(_all))
, m_in_ops(std::move(_in_ops))
, m_out_ops(std::move(_out_ops))
, m_user_tag(std::move(_user_tag))
{
}
const GIsland::node_set& GIsland::contents() const
{
return m_all;
}
const GIsland::node_set& GIsland::in_ops() const
{
return m_in_ops;
}
const GIsland::node_set& GIsland::out_ops() const
{
return m_out_ops;
}
gapi::GBackend GIsland::backend() const
{
return m_backend;
}
bool GIsland::is_user_specified() const
{
return m_user_tag.has_value();
}
void GIsland::debug() const
{
std::stringstream stream;
stream << name() << " {{\n input ops: ";
for (const auto& nh : m_in_ops) stream << nh << "; ";
stream << "\n output ops: ";
for (const auto& nh : m_out_ops) stream << nh << "; ";
stream << "\n contents: ";
for (const auto& nh : m_all) stream << nh << "; ";
stream << "\n}}" << std::endl;
GAPI_LOG_INFO(NULL, stream.str());
}
GIsland::node_set GIsland::consumers(const ade::Graph &g,
const ade::NodeHandle &slot_nh) const
{
GIslandModel::ConstGraph gim(g);
auto data_nh = gim.metadata(slot_nh).get<DataSlot>().original_data_node;
GIsland::node_set result;
for (const auto& in_op : m_in_ops)
{
auto it = std::find(in_op->inNodes().begin(),
in_op->inNodes().end(),
data_nh);
if (it != in_op->inNodes().end())
result.insert(in_op);
}
return result;
}
ade::NodeHandle GIsland::producer(const ade::Graph &g,
const ade::NodeHandle &slot_nh) const
{
GIslandModel::ConstGraph gim(g);
auto data_nh = gim.metadata(slot_nh).get<DataSlot>().original_data_node;
for (const auto& out_op : m_out_ops)
{
auto it = std::find(out_op->outNodes().begin(),
out_op->outNodes().end(),
data_nh);
if (it != out_op->outNodes().end())
return out_op;
}
// Consistency: A GIsland requested for producer() of slot_nh should
// always had the appropriate GModel node handle in its m_out_ops vector.
GAPI_Assert(false);
return ade::NodeHandle();
}
std::string GIsland::name() const
{
if (is_user_specified())
return m_user_tag.value();
std::stringstream ss;
ss << "island_#" << std::hex << static_cast<const void*>(this);
return ss.str();
}
void GIslandModel::generateInitial(GIslandModel::Graph &g,
const ade::Graph &src_graph)
{
const GModel::ConstGraph src_g(src_graph);
// Initially GIslandModel is a 1:1 projection from GModel:
// 1) Every GModel::OP becomes a separate GIslandModel::FusedIsland;
// 2) Every GModel::DATA becomes GIslandModel::DataSlot;
// 3) Single-operation FusedIslands are connected with DataSlots in the
// same way as OPs and DATA (edges with the same metadata)
using node_set = std::unordered_set
< ade::NodeHandle
, ade::HandleHasher<ade::Node>
>;
using node_map = std::unordered_map
< ade::NodeHandle
, ade::NodeHandle
, ade::HandleHasher<ade::Node>
>;
node_set all_operations;
node_map data_to_slot;
// First, list all operations and build create DataSlots in <g>
for (auto src_nh : src_g.nodes())
{
switch (src_g.metadata(src_nh).get<NodeType>().t)
{
case NodeType::OP: all_operations.insert(src_nh); break;
case NodeType::DATA: data_to_slot[src_nh] = mkSlotNode(g, src_nh); break;
default: GAPI_Assert(false); break;
}
} // for (src_g.nodes)
// Now put single-op islands and connect it with DataSlots
for (auto src_op_nh : all_operations)
{
auto nh = mkIslandNode(g, src_g.metadata(src_op_nh).get<Op>().backend, src_op_nh, src_graph);
for (auto in_edge : src_op_nh->inEdges())
{
auto src_data_nh = in_edge->srcNode();
auto isl_slot_nh = data_to_slot.at(src_data_nh);
g.link(isl_slot_nh, nh); // no other data stored yet
}
for (auto out_edge : src_op_nh->outEdges())
{
auto dst_data_nh = out_edge->dstNode();
auto isl_slot_nh = data_to_slot.at(dst_data_nh);
g.link(nh, isl_slot_nh);
}
} // for(all_operations)
}
ade::NodeHandle GIslandModel::mkSlotNode(Graph &g, const ade::NodeHandle &data_nh)
{
auto nh = g.createNode();
g.metadata(nh).set(DataSlot{data_nh});
g.metadata(nh).set(NodeKind{NodeKind::SLOT});
return nh;
}
ade::NodeHandle GIslandModel::mkIslandNode(Graph &g, const gapi::GBackend& bknd, const ade::NodeHandle &op_nh, const ade::Graph &orig_g)
{
const GModel::ConstGraph src_g(orig_g);
util::optional<std::string> user_tag;
if (src_g.metadata(op_nh).contains<Island>())
{
user_tag = util::make_optional(src_g.metadata(op_nh).get<Island>().island);
}
auto nh = g.createNode();
std::shared_ptr<GIsland> island(new GIsland(bknd, op_nh, std::move(user_tag)));
g.metadata(nh).set(FusedIsland{std::move(island)});
g.metadata(nh).set(NodeKind{NodeKind::ISLAND});
return nh;
}
ade::NodeHandle GIslandModel::mkIslandNode(Graph &g, std::shared_ptr<GIsland>&& isl)
{
ade::NodeHandle nh = g.createNode();
g.metadata(nh).set(cv::gimpl::NodeKind{cv::gimpl::NodeKind::ISLAND});
g.metadata(nh).set<cv::gimpl::FusedIsland>({std::move(isl)});
return nh;
}
void GIslandModel::syncIslandTags(Graph &g, ade::Graph &orig_g)
{
GModel::Graph gm(orig_g);
for (auto nh : g.nodes())
{
if (NodeKind::ISLAND == g.metadata(nh).get<NodeKind>().k)
{
auto island = g.metadata(nh).get<FusedIsland>().object;
auto isl_tag = island->name();
for (const auto& orig_nh_inside : island->contents())
{
gm.metadata(orig_nh_inside).set(Island{isl_tag});
}
}
}
}
void GIslandModel::compileIslands(Graph &g, const ade::Graph &orig_g, const GCompileArgs &args)
{
GModel::ConstGraph gm(orig_g);
auto original_sorted = gm.metadata().get<ade::passes::TopologicalSortData>();
for (auto nh : g.nodes())
{
if (NodeKind::ISLAND == g.metadata(nh).get<NodeKind>().k)
{
auto island_obj = g.metadata(nh).get<FusedIsland>().object;
auto island_ops = island_obj->contents();
std::vector<ade::NodeHandle> topo_sorted_list;
ade::util::copy_if(original_sorted.nodes(),
std::back_inserter(topo_sorted_list),
[&](ade::NodeHandle sorted_nh) {
return ade::util::contains(island_ops, sorted_nh);
});
auto island_exe = island_obj->backend().priv()
.compile(orig_g, args, topo_sorted_list);
GAPI_Assert(nullptr != island_exe);
g.metadata(nh).set(IslandExec{std::move(island_exe)});
}
}
}
ade::NodeHandle GIslandModel::producerOf(const ConstGraph &g, ade::NodeHandle &data_nh)
{
for (auto nh : g.nodes())
{
// find a data slot...
if (NodeKind::SLOT == g.metadata(nh).get<NodeKind>().k)
{
// which is associated with the given data object...
if (data_nh == g.metadata(nh).get<DataSlot>().original_data_node)
{
// which probably has a produrer...
if (0u != nh->inNodes().size())
{
// ...then the answer is that producer
return nh->inNodes().front();
}
else return ade::NodeHandle(); // input data object?
// return empty to break the cycle
}
}
}
// No appropriate data slot found - probably, the object has been
// optimized out during fusion
return ade::NodeHandle();
}
} // namespace cv
} // namespace gimpl

@ -0,0 +1,184 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GISLANDMODEL_HPP
#define OPENCV_GAPI_GISLANDMODEL_HPP
#include <unordered_set>
#include <memory> // shared_ptr
#include <ade/graph.hpp>
#include <ade/typed_graph.hpp>
#include <ade/passes/topological_sort.hpp>
#include "opencv2/gapi/util/optional.hpp"
#include "opencv2/gapi/gkernel.hpp"
#include "compiler/gobjref.hpp"
namespace cv { namespace gimpl {
// FIXME: GAPI_EXPORTS only because of tests!
class GAPI_EXPORTS GIsland
{
public:
using node_set = std::unordered_set
< ade::NodeHandle
, ade::HandleHasher<ade::Node>
>;
// Initial constructor (constructs a single-op Island)
GIsland(const gapi::GBackend &bknd,
ade::NodeHandle op,
util::optional<std::string>&& user_tag);
// Merged constructor
GIsland(const gapi::GBackend &bknd,
node_set &&all,
node_set &&in_ops,
node_set &&out_ops,
util::optional<std::string>&& user_tag);
const node_set& contents() const;
const node_set& in_ops() const;
const node_set& out_ops() const;
std::string name() const;
gapi::GBackend backend() const;
/**
* Returns all GModel operation node handles which are _reading_
* from a GModel data object associated (wrapped in) the given
* Slot object.
*
* @param g an ade::Graph with GIslandModel information inside
* @param slot_nh Slot object node handle of interest
* @return a set of GModel operation node handles
*/
node_set consumers(const ade::Graph &g,
const ade::NodeHandle &slot_nh) const;
/**
* Returns a GModel operation node handle which is _writing_
* to a GModel data object associated (wrapped in) the given
* Slot object.
*
* @param g an ade::Graph with GIslandModel information inside
* @param slot_nh Slot object node handle of interest
* @return a node handle of original GModel
*/
ade::NodeHandle producer(const ade::Graph &g,
const ade::NodeHandle &slot_nh) const;
void debug() const;
bool is_user_specified() const;
protected:
gapi::GBackend m_backend; // backend which handles this Island execution
node_set m_all; // everything (data + operations) within an island
node_set m_in_ops; // operations island begins with
node_set m_out_ops; // operations island ends with
// has island name IF specified by user. Empty for internal (inferred) islands
util::optional<std::string> m_user_tag;
};
// GIslandExecutable - a backend-specific thing which executes
// contents of an Island
// * Is instantiated by the last step of the Islands fusion procedure;
// * Is orchestrated by a GExecutor instance.
//
class GIslandExecutable
{
public:
using InObj = std::pair<RcDesc, cv::GRunArg>;
using OutObj = std::pair<RcDesc, cv::GRunArgP>;
// FIXME: now run() requires full input vector to be available.
// actually, parts of subgraph may execute even if there's no all data
// slots in place.
// TODO: Add partial execution capabilities
virtual void run(std::vector<InObj> &&input_objs,
std::vector<OutObj> &&output_objs) = 0;
virtual ~GIslandExecutable() = default;
};
// Couldn't reuse NodeType here - FIXME unify (move meta to a shared place)
struct NodeKind
{
static const char *name() { return "NodeKind"; }
enum { ISLAND, SLOT} k;
};
// FIXME: Rename to Island (as soon as current GModel::Island is renamed
// to IslandTag).
struct FusedIsland
{
static const char *name() { return "FusedIsland"; }
std::shared_ptr<GIsland> object;
};
struct DataSlot
{
static const char *name() { return "DataSlot"; }
ade::NodeHandle original_data_node; // direct link to GModel
};
struct IslandExec
{
static const char *name() { return "IslandExecutable"; }
std::shared_ptr<GIslandExecutable> object;
};
namespace GIslandModel
{
using Graph = ade::TypedGraph
< NodeKind
, FusedIsland
, DataSlot
, IslandExec
, ade::passes::TopologicalSortData
>;
// FIXME: derive from TypedGraph
using ConstGraph = ade::ConstTypedGraph
< NodeKind
, FusedIsland
, DataSlot
, IslandExec
, ade::passes::TopologicalSortData
>;
// Top-level function
void generateInitial(Graph &g, const ade::Graph &src_g);
// "Building blocks"
ade::NodeHandle mkSlotNode(Graph &g, const ade::NodeHandle &data_nh);
ade::NodeHandle mkIslandNode(Graph &g, const gapi::GBackend &bknd, const ade::NodeHandle &op_nh, const ade::Graph &orig_g);
ade::NodeHandle mkIslandNode(Graph &g, std::shared_ptr<GIsland>&& isl);
// GIslandModel API
void syncIslandTags(Graph &g, ade::Graph &orig_g);
void compileIslands(Graph &g, const ade::Graph &orig_g, const GCompileArgs &args);
// Debug routines
// producerOf - returns an Island handle which produces given data object
// from the original model (! don't mix with DataSlot)
// FIXME: GAPI_EXPORTS because of tests only!
ade::NodeHandle GAPI_EXPORTS producerOf(const ConstGraph &g, ade::NodeHandle &data_nh);
} // namespace GIslandModel
}} // namespace cv::gimpl
#endif // OPENCV_GAPI_GISLANDMODEL_HPP

@ -0,0 +1,245 @@
// 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) 2018 Intel Corporation
#include <string>
#include <sstream> // used in GModel::log
#include <ade/util/zip_range.hpp> // util::indexed
#include <ade/util/checked_cast.hpp>
#include "opencv2/gapi/gproto.hpp"
#include "api/gnode_priv.hpp"
#include "compiler/gobjref.hpp"
#include "compiler/gmodel.hpp"
namespace cv { namespace gimpl {
ade::NodeHandle GModel::mkOpNode(GModel::Graph &g, const GKernel &k, const std::vector<GArg> &args, const std::string &island)
{
ade::NodeHandle op_h = g.createNode();
g.metadata(op_h).set(NodeType{NodeType::OP});
//These extra empty {} are to please GCC (-Wmissing-field-initializers)
g.metadata(op_h).set(Op{k, args, {}, {}, {}});
if (!island.empty())
g.metadata(op_h).set(Island{island});
return op_h;
}
ade::NodeHandle GModel::mkDataNode(GModel::Graph &g, const GOrigin& origin)
{
ade::NodeHandle op_h = g.createNode();
const auto id = g.metadata().get<DataObjectCounter>().GetNewId(origin.shape);
g.metadata(op_h).set(NodeType{NodeType::DATA});
GMetaArg meta;
Data::Storage storage = Data::Storage::INTERNAL; // By default, all objects are marked INTERNAL
if (origin.node.shape() == GNode::NodeShape::CONST_BOUNDED)
{
auto value = value_of(origin);
meta = descr_of(value);
storage = Data::Storage::CONST;
g.metadata(op_h).set(ConstValue{value});
}
g.metadata(op_h).set(Data{origin.shape, id, meta, origin.ctor, storage});
return op_h;
}
void GModel::linkIn(Graph &g, ade::NodeHandle opH, ade::NodeHandle objH, std::size_t in_port)
{
// Check if input is already connected
for (const auto& in_e : opH->inEdges())
{
GAPI_Assert(g.metadata(in_e).get<Input>().port != in_port);
}
auto &op = g.metadata(opH).get<Op>();
auto &gm = g.metadata(objH).get<Data>();
// FIXME: check validity using kernel prototype
GAPI_Assert(in_port < op.args.size());
ade::EdgeHandle eh = g.link(objH, opH);
g.metadata(eh).set(Input{in_port});
// Replace an API object with a REF (G* -> GOBJREF)
op.args[in_port] = cv::GArg(RcDesc{gm.rc, gm.shape, {}});
}
void GModel::linkOut(Graph &g, ade::NodeHandle opH, ade::NodeHandle objH, std::size_t out_port)
{
// FIXME: check validity using kernel prototype
// Check if output is already connected
for (const auto& out_e : opH->outEdges())
{
GAPI_Assert(g.metadata(out_e).get<Output>().port != out_port);
}
auto &op = g.metadata(opH).get<Op>();
auto &gm = g.metadata(objH).get<Data>();
GAPI_Assert(objH->inNodes().size() == 0u);
ade::EdgeHandle eh = g.link(opH, objH);
g.metadata(eh).set(Output{out_port});
// TODO: outs must be allocated according to kernel protocol!
const auto storage_with_port = ade::util::checked_cast<std::size_t>(out_port+1);
const auto min_out_size = std::max(op.outs.size(), storage_with_port);
op.outs.resize(min_out_size, RcDesc{-1,GShape::GMAT,{}}); // FIXME: Invalid shape instead?
op.outs[out_port] = RcDesc{gm.rc, gm.shape, {}};
}
std::vector<ade::NodeHandle> GModel::orderedInputs(Graph &g, ade::NodeHandle nh)
{
std::vector<ade::NodeHandle> sorted_in_nhs(nh->inEdges().size());
for (const auto& in_eh : nh->inEdges())
{
const auto port = g.metadata(in_eh).get<cv::gimpl::Input>().port;
GAPI_Assert(port < sorted_in_nhs.size());
sorted_in_nhs[port] = in_eh->srcNode();
}
return sorted_in_nhs;
}
std::vector<ade::NodeHandle> GModel::orderedOutputs(Graph &g, ade::NodeHandle nh)
{
std::vector<ade::NodeHandle> sorted_out_nhs(nh->outEdges().size());
for (const auto& out_eh : nh->outEdges())
{
const auto port = g.metadata(out_eh).get<cv::gimpl::Output>().port;
GAPI_Assert(port < sorted_out_nhs.size());
sorted_out_nhs[port] = out_eh->dstNode();
}
return sorted_out_nhs;
}
void GModel::init(Graph& g)
{
g.metadata().set(DataObjectCounter());
}
void GModel::log(Graph &g, ade::NodeHandle nh, std::string &&msg, ade::NodeHandle updater)
{
std::string s = std::move(msg);
if (updater != nullptr)
{
std::stringstream fmt;
fmt << " (via " << updater << ")";
s += fmt.str();
}
if (g.metadata(nh).contains<Journal>())
{
g.metadata(nh).get<Journal>().messages.push_back(s);
}
else
{
g.metadata(nh).set(Journal{{s}});
}
}
// FIXME:
// Unify with GModel::log(.. ade::NodeHandle ..)
void GModel::log(Graph &g, ade::EdgeHandle eh, std::string &&msg, ade::NodeHandle updater)
{
std::string s = std::move(msg);
if (updater != nullptr)
{
std::stringstream fmt;
fmt << " (via " << updater << ")";
s += fmt.str();
}
if (g.metadata(eh).contains<Journal>())
{
g.metadata(eh).get<Journal>().messages.push_back(s);
}
else
{
g.metadata(eh).set(Journal{{s}});
}
}
ade::NodeHandle GModel::detail::dataNodeOf(const ConstGraph &g, const GOrigin &origin)
{
// FIXME: Does it still work with graph transformations, e.g. redirectWriter()??
return g.metadata().get<Layout>().object_nodes.at(origin);
}
void GModel::redirectReaders(Graph &g, ade::NodeHandle from, ade::NodeHandle to)
{
std::vector<ade::EdgeHandle> ehh(from->outEdges().begin(), from->outEdges().end());
for (auto e : ehh)
{
auto dst = e->dstNode();
auto input = g.metadata(e).get<Input>();
g.erase(e);
linkIn(g, dst, to, input.port);
}
}
void GModel::redirectWriter(Graph &g, ade::NodeHandle from, ade::NodeHandle to)
{
GAPI_Assert(from->inEdges().size() == 1);
auto e = from->inEdges().front();
auto op = e->srcNode();
auto output = g.metadata(e).get<Output>();
g.erase(e);
linkOut(g, op, to, output.port);
}
GMetaArgs GModel::collectInputMeta(GModel::ConstGraph cg, ade::NodeHandle node)
{
GAPI_Assert(cg.metadata(node).get<NodeType>().t == NodeType::OP);
GMetaArgs in_meta_args(cg.metadata(node).get<Op>().args.size());
for (const auto &e : node->inEdges())
{
const auto& in_data = cg.metadata(e->srcNode()).get<Data>();
in_meta_args[cg.metadata(e).get<Input>().port] = in_data.meta;
}
return in_meta_args;
}
ade::EdgeHandle GModel::getInEdgeByPort(const GModel::ConstGraph& cg,
const ade::NodeHandle& nh,
std::size_t in_port)
{
auto inEdges = nh->inEdges();
const auto& edge = ade::util::find_if(inEdges, [&](ade::EdgeHandle eh) {
return cg.metadata(eh).get<Input>().port == in_port;
});
GAPI_Assert(edge != inEdges.end());
return *edge;
}
GMetaArgs GModel::collectOutputMeta(GModel::ConstGraph cg, ade::NodeHandle node)
{
GAPI_Assert(cg.metadata(node).get<NodeType>().t == NodeType::OP);
GMetaArgs out_meta_args(cg.metadata(node).get<Op>().outs.size());
for (const auto &e : node->outEdges())
{
const auto& out_data = cg.metadata(e->dstNode()).get<Data>();
out_meta_args[cg.metadata(e).get<Output>().port] = out_data.meta;
}
return out_meta_args;
}
bool GModel::isActive(const GModel::Graph &cg, const cv::gapi::GBackend &backend)
{
return ade::util::contains(cg.metadata().get<ActiveBackends>().backends,
backend);
}
}} // cv::gimpl

@ -0,0 +1,251 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GMODEL_HPP
#define OPENCV_GAPI_GMODEL_HPP
#include <memory> // shared_ptr
#include <unordered_map>
#include <functional> // std::function
#include <ade/graph.hpp>
#include <ade/typed_graph.hpp>
#include <ade/passes/topological_sort.hpp>
// /!\ ATTENTION:
//
// No API includes like GMat, GNode, GCall here!
// This part of the system is API-unaware by its design.
//
#include "opencv2/gapi/garg.hpp"
#include "opencv2/gapi/gkernel.hpp"
#include "api/gapi_priv.hpp" // GShape
#include "api/gproto_priv.hpp" // origin_of
#include "backends/common/gbackend.hpp"
#include "compiler/gobjref.hpp"
#include "compiler/gislandmodel.hpp"
namespace cv { namespace gimpl {
// TODO: Document all metadata types
struct NodeType
{
static const char *name() { return "NodeType"; }
enum { OP, DATA } t;
};
struct Input
{
static const char *name() { return "Input"; }
std::size_t port;
};
struct Output
{
static const char *name() { return "Output"; }
std::size_t port;
};
struct Op
{
static const char *name() { return "Op"; }
cv::GKernel k;
std::vector<GArg> args; // TODO: Introduce a new type for internal args?
std::vector<RcDesc> outs; // TODO: Introduce a new type for resource references
cv::gapi::GBackend backend;
util::any opaque;
};
struct Data
{
static const char *name() { return "Data"; }
// FIXME: This is a _pure_ duplication of RcDesc now! (except storage)
GShape shape; // FIXME: Probably to be replaced by GMetaArg?
int rc;
GMetaArg meta;
HostCtor ctor; // T-specific helper to deal with unknown types in our code
// FIXME: Why rc+shape+meta is not represented as RcDesc here?
enum class Storage
{
INTERNAL, // data object is not listed in GComputation protocol
INPUT, // data object is listed in GComputation protocol as Input
OUTPUT, // data object is listed in GComputation protocol as Output
CONST, // data object is constant
};
Storage storage;
};
struct ConstValue
{
static const char *name() { return "ConstValue"; }
GRunArg arg;
};
// This metadata is valid for both DATA and OP kinds of nodes
// FIXME: Rename to IslandTag
struct Island
{
static const char *name() { return "Island"; }
std::string island; // can be set by user, otherwise is set by fusion
};
struct Protocol
{
static const char *name() { return "Protocol"; }
// TODO: Replace the whole thing with a "Protocol" object
std::vector<RcDesc> inputs;
std::vector<RcDesc> outputs;
std::vector<ade::NodeHandle> in_nhs;
std::vector<ade::NodeHandle> out_nhs;
};
struct OutputMeta
{
static const char *name() { return "OutputMeta"; }
GMetaArgs outMeta;
};
struct Journal
{
static const char *name() { return "Journal"; }
std::vector<std::string> messages;
};
// The mapping between user-side GMat/GScalar/... objects
// and its appropriate nodes. Can be stored in graph optionally
// (NOT used by any compiler or backends, introspection purposes
// only)
struct Layout
{
static const char *name() { return "Layout"; }
GOriginMap<ade::NodeHandle> object_nodes;
};
// Unique data object counter (per-type)
class DataObjectCounter
{
public:
static const char* name() { return "DataObjectCounter"; }
int GetNewId(GShape shape) { return m_next_data_id[shape]++; }
private:
std::unordered_map<cv::GShape, int> m_next_data_id;
};
// A projected graph of Islands (generated from graph of Operations)
struct IslandModel
{
static const char* name() { return "IslandModel"; }
std::shared_ptr<ade::Graph> model;
};
// List of backends selected for current graph execution
struct ActiveBackends
{
static const char *name() { return "ActiveBackends"; }
std::unordered_set<cv::gapi::GBackend> backends;
};
namespace GModel
{
using Graph = ade::TypedGraph
< NodeType
, Input
, Output
, Op
, Data
, ConstValue
, Island
, Protocol
, OutputMeta
, Journal
, ade::passes::TopologicalSortData
, DataObjectCounter
, Layout
, IslandModel
, ActiveBackends
>;
// FIXME: How to define it based on GModel???
using ConstGraph = ade::ConstTypedGraph
< NodeType
, Input
, Output
, Op
, Data
, ConstValue
, Island
, Protocol
, OutputMeta
, Journal
, ade::passes::TopologicalSortData
, DataObjectCounter
, Layout
, IslandModel
, ActiveBackends
>;
// User should initialize graph before using it
// GAPI_EXPORTS for tests
GAPI_EXPORTS void init (Graph& g);
ade::NodeHandle mkOpNode(Graph &g, const GKernel &k, const std::vector<GArg>& args, const std::string &island);
// FIXME: change it to take GMeta instead of GShape?
ade::NodeHandle mkDataNode(Graph &g, const GOrigin& origin);
// Adds a string message to a node. Any node can be subject of log, messages then
// appear in the dumped .dot file.x
void log(Graph &g, ade::NodeHandle op, std::string &&message, ade::NodeHandle updater = ade::NodeHandle());
void log(Graph &g, ade::EdgeHandle op, std::string &&message, ade::NodeHandle updater = ade::NodeHandle());
void linkIn (Graph &g, ade::NodeHandle op, ade::NodeHandle obj, std::size_t in_port);
void linkOut (Graph &g, ade::NodeHandle op, ade::NodeHandle obj, std::size_t out_port);
// FIXME: Align this GModel API properly, it is a mess now
namespace detail
{
// FIXME: GAPI_EXPORTS only because of tests!!!
GAPI_EXPORTS ade::NodeHandle dataNodeOf(const ConstGraph& g, const GOrigin &origin);
}
template<typename T> inline ade::NodeHandle dataNodeOf(const ConstGraph& g, T &&t)
{
return detail::dataNodeOf(g, cv::gimpl::proto::origin_of(GProtoArg{t}));
}
void linkIn (Graph &g, ade::NodeHandle op, ade::NodeHandle obj, std::size_t in_port);
void linkOut (Graph &g, ade::NodeHandle op, ade::NodeHandle obj, std::size_t out_port);
void redirectReaders(Graph &g, ade::NodeHandle from, ade::NodeHandle to);
void redirectWriter (Graph &g, ade::NodeHandle from, ade::NodeHandle to);
std::vector<ade::NodeHandle> orderedInputs (Graph &g, ade::NodeHandle nh);
std::vector<ade::NodeHandle> orderedOutputs(Graph &g, ade::NodeHandle nh);
// Returns input meta array for given op node
// Array is sparse, as metadata for non-gapi input objects is empty
// TODO:
// Cover with tests!!
GMetaArgs collectInputMeta(GModel::ConstGraph cg, ade::NodeHandle node);
GMetaArgs collectOutputMeta(GModel::ConstGraph cg, ade::NodeHandle node);
ade::EdgeHandle getInEdgeByPort(const GModel::ConstGraph& cg, const ade::NodeHandle& nh, std::size_t in_port);
// Returns true if the given backend participates in the execution
bool isActive(const GModel::Graph &cg, const cv::gapi::GBackend &backend);
} // namespace GModel
}} // namespace cv::gimpl
#endif // OPENCV_GAPI_GMODEL_HPP

@ -0,0 +1,303 @@
// 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) 2018 Intel Corporation
////////////////////////////////////////////////////////////////////////////////
//
// FIXME: "I personally hate this file"
// - Dmitry
//
////////////////////////////////////////////////////////////////////////////////
#include <utility> // tuple
#include <stack> // stack
#include <vector> // vector
#include <unordered_set> // unordered_set
#include <type_traits> // is_same
#include <ade/util/zip_range.hpp> // util::indexed
#include "api/gapi_priv.hpp" // GOrigin
#include "api/gproto_priv.hpp" // descriptor_of and other GProtoArg-related
#include "api/gcall_priv.hpp"
#include "api/gnode_priv.hpp"
#include "compiler/gmodelbuilder.hpp"
namespace {
// TODO: move to helpers and cover with internal tests?
template<typename T> struct GVisited
{
typedef std::unordered_set<T> VTs;
bool visited(const T& t) const { return m_visited.find(t) != m_visited.end(); }
void visit (const T& t) { m_visited.insert(t); }
const VTs& visited() const { return m_visited; }
private:
VTs m_visited;
};
template<typename T, typename U = T> struct GVisitedTracker: protected GVisited<T>
{
typedef std::vector<U> TUs;
void visit(const T& t, const U& u) { GVisited<T>::visit(t); m_tracked.push_back(u); }
const TUs& tracked() const { return m_tracked; }
using GVisited<T>::visited;
private:
TUs m_tracked;
};
} // namespace
cv::gimpl::Unrolled cv::gimpl::unrollExpr(const GProtoArgs &ins,
const GProtoArgs &outs)
{
// FIXME: Who's gonna check if ins/outs are not EMPTY?
// FIXME: operator== for GObjects? (test if the same object or not)
using GObjId = const cv::GOrigin*;
GVisitedTracker<const GNode::Priv*, cv::GNode> ops;
GVisited<GObjId> reached_sources;
cv::GOriginSet origins;
// Cache input argument objects for a faster look-up
// While the only reliable way to identify a Data object is Origin
// (multiple data objects may refer to the same Origin as result of
// multuple yield() calls), input objects can be uniquely identified
// by its `priv` address. Here we rely on this to verify if the expression
// we unroll actually matches the protocol specified to us by user.
std::unordered_set<GObjId> in_objs_p;
for (const auto& in_obj : ins)
{
// Objects are guarnateed to remain alive while this method
// is working, so it is safe to keep pointers here and below
in_objs_p.insert(&proto::origin_of(in_obj));
}
// Recursive expression traversal
std::stack<cv::GProtoArg> data_objs(std::deque<cv::GProtoArg>(outs.begin(), outs.end()));
while (!data_objs.empty())
{
const auto obj = data_objs.top();
const auto &obj_p = proto::origin_of(obj);
data_objs.pop();
const auto &origin = obj_p;
origins.insert(origin); // TODO: Put Object description here later on
// If this Object is listed in the protocol, don't dive deeper (even
// if it is in fact a result of operation). Our computation is
// bounded by this data slot, so terminate this recursion path early.
if (in_objs_p.find(&obj_p) != in_objs_p.end())
{
reached_sources.visit(&obj_p);
continue;
}
const cv::GNode &node = origin.node;
switch (node.shape())
{
case cv::GNode::NodeShape::EMPTY:
// TODO: Own exception type?
util::throw_error(std::logic_error("Empty node reached!"));
break;
case cv::GNode::NodeShape::PARAM:
case cv::GNode::NodeShape::CONST_BOUNDED:
// No preceding operation to this data object - so the data object is either a GComputation
// parameter or a constant (compile-time) value
// Record it to check if protocol matches expression tree later
if (!reached_sources.visited(&obj_p))
reached_sources.visit(&obj_p);
break;
case cv::GNode::NodeShape::CALL:
if (!ops.visited(&node.priv()))
{
// This operation hasn't been visited yet - mark it so,
// then add its operands to stack to continue recursion.
ops.visit(&node.priv(), node);
const cv::GCall call = origin.node.call();
const cv::GCall::Priv& call_p = call.priv();
// Put the outputs object description of the node
// so that they are not lost if they are not consumed by other operations
for (const auto &it : ade::util::indexed(call_p.m_k.outShapes))
{
std::size_t port = ade::util::index(it);
GShape shape = ade::util::value(it);
GOrigin org { shape, node, port};
origins.insert(org);
}
for (const auto &arg : call_p.m_args)
{
if (proto::is_dynamic(arg))
{
data_objs.push(proto::rewrap(arg)); // Dive deeper
}
}
}
break;
default:
// Unsupported node shape
GAPI_Assert(false);
break;
}
}
// Check if protocol mentions data_objs which weren't reached during traversal
const auto missing_reached_sources = [&reached_sources](GObjId p) {
return reached_sources.visited().find(p) == reached_sources.visited().end();
};
if (ade::util::any_of(in_objs_p, missing_reached_sources))
{
// TODO: Own exception type or a return code?
util::throw_error(std::logic_error("Data object listed in Protocol "
"wasn\'t reached during unroll"));
}
// Check if there endpoint (parameter) data_objs which are not listed in protocol
const auto missing_in_proto = [&in_objs_p](GObjId p) {
return p->node.shape() != cv::GNode::NodeShape::CONST_BOUNDED &&
in_objs_p.find(p) == in_objs_p.end();
};
if (ade::util::any_of(reached_sources.visited(), missing_in_proto))
{
// TODO: Own exception type or a return code?
util::throw_error(std::logic_error("Data object reached during unroll "
"wasn\'t found in Protocol"));
}
return cv::gimpl::Unrolled{ops.tracked(), origins};
}
cv::gimpl::GModelBuilder::GModelBuilder(ade::Graph &g)
: m_g(g)
{
}
cv::gimpl::GModelBuilder::ProtoSlots
cv::gimpl::GModelBuilder::put(const GProtoArgs &ins, const GProtoArgs &outs)
{
const auto unrolled = cv::gimpl::unrollExpr(ins, outs);
// First, put all operations and its arguments into graph.
for (const auto &op_expr_node : unrolled.all_ops)
{
GAPI_Assert(op_expr_node.shape() == GNode::NodeShape::CALL);
const GCall& call = op_expr_node.call();
const GCall::Priv& call_p = call.priv();
ade::NodeHandle call_h = put_OpNode(op_expr_node);
for (const auto &it : ade::util::indexed(call_p.m_args))
{
const auto in_port = ade::util::index(it);
const auto& in_arg = ade::util::value(it);
if (proto::is_dynamic(in_arg))
{
ade::NodeHandle data_h = put_DataNode(proto::origin_of(in_arg));
cv::gimpl::GModel::linkIn(m_g, call_h, data_h, in_port);
}
}
}
// Then iterate via all "origins", instantiate (if not yet) Data graph nodes
// and connect these nodes with their producers in graph
for (const auto &origin : unrolled.all_data)
{
const cv::GNode& prod = origin.node;
GAPI_Assert(prod.shape() != cv::GNode::NodeShape::EMPTY);
ade::NodeHandle data_h = put_DataNode(origin);
if (prod.shape() == cv::GNode::NodeShape::CALL)
{
ade::NodeHandle call_h = put_OpNode(prod);
cv::gimpl::GModel::linkOut(m_g, call_h, data_h, origin.port);
}
}
// Mark graph data nodes as INPUTs and OUTPUTs respectively (according to the protocol)
for (const auto &arg : ins)
{
ade::NodeHandle nh = put_DataNode(proto::origin_of(arg));
m_g.metadata(nh).get<Data>().storage = Data::Storage::INPUT;
}
for (const auto &arg : outs)
{
ade::NodeHandle nh = put_DataNode(proto::origin_of(arg));
m_g.metadata(nh).get<Data>().storage = Data::Storage::OUTPUT;
}
// And, finally, store data object layout in meta
m_g.metadata().set(Layout{m_graph_data});
// After graph is generated, specify which data objects are actually
// computation entry/exit points.
using NodeDescr = std::pair<std::vector<RcDesc>,
std::vector<ade::NodeHandle> >;
const auto get_proto_slots = [&](const GProtoArgs &proto) -> NodeDescr
{
NodeDescr slots;
slots.first.reserve(proto.size());
slots.second.reserve(proto.size());
for (const auto &arg : proto)
{
ade::NodeHandle nh = put_DataNode(proto::origin_of(arg));
const auto &desc = m_g.metadata(nh).get<Data>();
//These extra empty {} are to please GCC (-Wmissing-field-initializers)
slots.first.push_back(RcDesc{desc.rc, desc.shape, {}});
slots.second.push_back(nh);
}
return slots;
};
auto in_slots = get_proto_slots(ins);
auto out_slots = get_proto_slots(outs);
return ProtoSlots{in_slots.first, out_slots.first,
in_slots.second, out_slots.second};
}
ade::NodeHandle cv::gimpl::GModelBuilder::put_OpNode(const cv::GNode &node)
{
const auto& node_p = node.priv();
const auto it = m_graph_ops.find(&node_p);
if (it == m_graph_ops.end())
{
GAPI_Assert(node.shape() == GNode::NodeShape::CALL);
const auto &call_p = node.call().priv();
auto nh = cv::gimpl::GModel::mkOpNode(m_g, call_p.m_k, call_p.m_args, node_p.m_island);
m_graph_ops[&node_p] = nh;
return nh;
}
else return it->second;
}
// FIXME: rename to get_DataNode (and same for Op)
ade::NodeHandle cv::gimpl::GModelBuilder::put_DataNode(const GOrigin &origin)
{
const auto it = m_graph_data.find(origin);
if (it == m_graph_data.end())
{
auto nh = cv::gimpl::GModel::mkDataNode(m_g, origin);
m_graph_data[origin] = nh;
return nh;
}
else return it->second;
}

@ -0,0 +1,77 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GMODEL_BUILDER_HPP
#define OPENCV_GAPI_GMODEL_BUILDER_HPP
#include <map>
#include <unordered_map>
#include "opencv2/gapi/gproto.hpp"
#include "opencv2/gapi/gcall.hpp"
#include "api/gapi_priv.hpp"
#include "api/gnode.hpp"
#include "compiler/gmodel.hpp"
namespace cv { namespace gimpl {
struct Unrolled
{
std::vector<cv::GNode> all_ops;
GOriginSet all_data;
// NB.: Right now, as G-API operates with GMats only and that
// GMats have no type or dimensions (when a computation is built),
// track only origins (data links) with no any additional meta.
};
// FIXME: GAPI_EXPORTS only because of tests!!!
GAPI_EXPORTS Unrolled unrollExpr(const GProtoArgs &ins, const GProtoArgs &outs);
// This class generates an ADE graph with G-API specific metadata
// to represent user-specified computation in terms of graph model
//
// Resulting graph is built according to the following rules:
// - Every operation is a node
// - Every dynamic object (GMat) is a node
// - Edges between nodes represent producer/consumer relationships
// between operations and data objects.
// FIXME: GAPI_EXPORTS only because of tests!!!
class GAPI_EXPORTS GModelBuilder
{
GModel::Graph m_g;
// Mappings of G-API user framework entities to ADE node handles
std::unordered_map<const cv::GNode::Priv*, ade::NodeHandle> m_graph_ops;
GOriginMap<ade::NodeHandle> m_graph_data;
// Internal methods for mapping APIs into ADE during put()
ade::NodeHandle put_OpNode(const cv::GNode &node);
ade::NodeHandle put_DataNode(const cv::GOrigin &origin);
public:
explicit GModelBuilder(ade::Graph &g);
// TODO: replace GMat with a generic type
// TODO: Cover with tests! (as the rest of internal stuff)
// FIXME: Calling this method multiple times is currently UB
// TODO: add a semantic link between "ints" returned and in-model data IDs.
typedef std::tuple<std::vector<RcDesc>,
std::vector<RcDesc>,
std::vector<ade::NodeHandle>,
std::vector<ade::NodeHandle> > ProtoSlots;
ProtoSlots put(const GProtoArgs &ins, const GProtoArgs &outs);
protected:
ade::NodeHandle opNode(cv::GMat gmat);
};
}}
#endif // OPENCV_GAPI_GMODEL_BUILDER_HPP

@ -0,0 +1,50 @@
// 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) 2018 Intel Corporation
#ifndef OPENCV_GAPI_GMATREF_HPP
#define OPENCV_GAPI_GMATREF_HPP
#include "opencv2/gapi/util/variant.hpp"
#include "opencv2/gapi/garg.hpp"
#include "api/gapi_priv.hpp" // GShape, HostCtor
namespace cv
{
namespace gimpl
{
struct RcDesc
{
int id; // id is unique but local to shape
GShape shape; // pair <id,shape> IS the unique ID
HostCtor ctor; // FIXME: is it really used here? Or in <Data>?
bool operator==(const RcDesc &rhs) const
{
// FIXME: ctor is not checked (should be?)
return id == rhs.id && shape == rhs.shape;
}
bool operator< (const RcDesc &rhs) const
{
return (id == rhs.id) ? shape < rhs.shape : id < rhs.id;
}
};
} // gimpl
namespace detail
{
template<> struct GTypeTraits<cv::gimpl::RcDesc>
{
static constexpr const ArgKind kind = ArgKind::GOBJREF;
};
}
} // cv
#endif // OPENCV_GAPI_GMATREF_HPP

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save