add part of opencv

This commit is contained in:
Tang1705
2020-01-27 20:20:56 +08:00
parent 0c4ac1d8bb
commit a71fa47620
6518 changed files with 3122580 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
// 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>
/** \defgroup gapi G-API framework
@{
@defgroup gapi_main_classes G-API Main Classes
@defgroup gapi_data_objects G-API Data Types
@{
@defgroup gapi_meta_args G-API Metadata Descriptors
@}
@defgroup gapi_std_backends G-API Standard Backends
@defgroup gapi_compile_args G-API Graph Compilation Arguments
@}
*/
#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

View File

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

View File

@@ -0,0 +1,292 @@
// 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-2019 Intel Corporation
#ifndef OPENCV_GAPI_GCPUKERNEL_HPP
#define OPENCV_GAPI_GCPUKERNEL_HPP
#include <functional>
#include <unordered_map>
#include <utility>
#include <vector>
#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
#include <opencv2/gapi/util/util.hpp>
// FIXME: namespace scheme for backends?
namespace cv {
namespace gimpl
{
// Forward-declare an internal class
class GCPUExecutable;
namespace render
{
namespace ocv
{
class GRenderExecutable;
}
}
} // namespace gimpl
namespace gapi
{
namespace cpu
{
/**
* \addtogroup gapi_std_backends
* @{
*
* @brief G-API backends available in this OpenCV version
*
* G-API backends play a corner stone role in G-API execution
* stack. Every backend is hardware-oriented and thus can run its
* kernels efficiently on the target platform.
*
* Backends are usually "black boxes" for G-API users -- on the API
* side, all backends are represented as different objects of the
* same class cv::gapi::GBackend.
* User can manipulate with backends by specifying which kernels to use.
*
* @sa @ref gapi_hld
*/
/**
* @brief Get a reference to CPU (OpenCV) backend.
*
* This is the default backend in G-API at the moment, providing
* broader functional coverage but losing some graph model
* advantages. Provided mostly for reference and prototyping
* purposes.
*
* @sa gapi_std_backends
*/
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 representation 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;
friend class gimpl::render::ocv::GRenderExecutable;
};
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::GMatP>
{
static cv::Mat get(GCPUContext &ctx, int idx) { return get_in<cv::GMat>::get(ctx, 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>(); }
};
//FIXME(dm): GArray<Mat>/GArray<GMat> conversion should be done more gracefully in the system
template<> struct get_in<cv::GArray<cv::GMat> >: public get_in<cv::GArray<cv::Mat> >
{
};
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::GMatP>
{
static tracked_cv_mat get(GCPUContext &ctx, int idx)
{
return get_out<cv::GMat>::get(ctx, idx);
}
};
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 trying 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 cv::detail::OCVCallHelper<Impl, typename K::InArgs, typename K::OutArgs>,
public cv::detail::KernelTag
{
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

View File

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

View File

@@ -0,0 +1,20 @@
// 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_CORE_HPP
#define OPENCV_GAPI_FLUID_CORE_HPP
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
#include <opencv2/gapi/own/exports.hpp> // GAPI_EXPORTS
namespace cv { namespace gapi { namespace core { namespace fluid {
GAPI_EXPORTS GKernelPackage kernels();
}}}}
#endif // OPENCV_GAPI_FLUID_CORE_HPP

View File

@@ -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 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/own/mat.hpp>
#include <opencv2/gapi/gmat.hpp>
#include <opencv2/gapi/util/optional.hpp>
#include <opencv2/gapi/own/scalar.hpp>
#include <opencv2/gapi/own/mat.hpp>
namespace cv {
namespace gapi {
namespace fluid {
struct Border
{
#if !defined(GAPI_STANDALONE)
// This constructor is required to support existing kernels which are part of G-API
Border(int _type, cv::Scalar _val) : type(_type), value(to_own(_val)) {};
#endif // !defined(GAPI_STANDALONE)
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:
struct Cache
{
std::vector<const uint8_t*> m_linePtrs;
GMatDesc m_desc;
int m_border_size = 0;
inline const uint8_t* linePtr(int index) const
{
// "out_of_window" check:
// user must not request the lines which are outside of specified kernel window
GAPI_DbgAssert(index >= -m_border_size
&& index < -m_border_size + static_cast<int>(m_linePtrs.size()));
return m_linePtrs[index + m_border_size];
}
};
View() = default;
const inline uint8_t* InLineB(int index) const // -(w-1)/2...0...+(w-1)/2 for Filters
{
return m_cache->linePtr(index);
}
template<typename T> const inline T* InLine(int i) const
{
const uint8_t* ptr = this->InLineB(i);
return reinterpret_cast<const T*>(ptr);
}
inline operator bool() const { return m_priv != nullptr; }
bool ready() const;
inline int length() const { return m_cache->m_desc.size.width; }
int y() const;
inline const GMatDesc& meta() const { return m_cache->m_desc; }
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;
const Cache* m_cache;
};
class GAPI_EXPORTS Buffer
{
public:
struct Cache
{
std::vector<uint8_t*> m_linePtrs;
GMatDesc m_desc;
};
// 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::gapi::own::Mat &data, bool is_input);
inline uint8_t* OutLineB(int index = 0)
{
return m_cache->m_linePtrs[index];
}
template<typename T> inline 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;
inline int length() const { return m_cache->m_desc.size.width; }
int lpi() const; // LPI for WRITER
inline const GMatDesc& meta() const { return m_cache->m_desc; }
View mkView(int borderSize, 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;
const Cache* m_cache;
};
} // namespace cv::gapi::fluid
} // namespace cv::gapi
} // namespace cv
#endif // OPENCV_GAPI_FLUID_BUFFER_HPP

View File

@@ -0,0 +1,439 @@
// 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-2019 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
{
/**
* \addtogroup gapi_std_backends G-API Standard Backends
* @{
*/
/**
* @brief Get a reference to Fluid backend.
*
* @sa gapi_std_backends
*/
GAPI_EXPORTS cv::gapi::GBackend backend();
/** @} */
} // namespace flud
} // namespace gapi
class GAPI_EXPORTS GFluidKernel
{
public:
enum class Kind
{
Filter,
Resize,
YUV420toRGB //Color conversion of 4:2:0 chroma sub-sampling formats (NV12, I420 ..etc) to RGB
};
// 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&)>;
// This function is a generic "getWindow" callback (extracts window-related data from kernel's input parameters)
using GW = std::function<int(const GMetaArgs&, const GArgs&)>;
// FIXME: move implementations out of header file
GFluidKernel() {}
GFluidKernel(Kind k, int l, bool scratch, const F& f, const IS &is, const RS &rs, const B& b, const GW& win)
: m_kind(k)
, m_lpi(l)
, m_scratch(scratch)
, m_f(f)
, m_is(is)
, m_rs(rs)
, m_b(b)
, m_gw(win) {}
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;
const GW m_gw;
};
// FIXME!!!
// This is the temporary and experimental API
// which should be replaced by runtime roi-based scheduling
/** \addtogroup gapi_compile_args
* @{
*/
/**
* @brief This structure allows to control the output image region
* which Fluid backend will produce in the graph.
*
* This feature is useful for external tiling and parallelism, but
* will be deprecated in the future releases.
*/
struct GFluidOutputRois
{
std::vector<cv::gapi::own::Rect> rois;
};
/**
* @brief This structure forces Fluid backend to generate multiple
* parallel output regions in the graph. These regions execute in parallel.
*
* This feature may be deprecated in the future releases.
*/
struct GFluidParallelOutputRois
{
std::vector<GFluidOutputRois> parallel_rois;
};
/**
* @brief This structure allows to customize the way how Fluid executes
* parallel regions.
*
* For example, user can utilize his own threading runtime via this parameter.
* The `parallel_for` member functor is called by the Fluid runtime with the
* following arguments:
*
* @param size Size of the parallel range to process
* @param f A function which should be called for every integer index
* in this range by the specified parallel_for implementation.
*
* This feature may be deprecated in the future releases.
*/
struct GFluidParallelFor
{
//this function accepts:
// - size of the "parallel" range as the first argument
// - and a function to be called on the range items, designated by item index
std::function<void(std::size_t size, std::function<void(std::size_t index)>)> parallel_for;
};
/** @} gapi_compile_args */
namespace detail
{
template<> struct CompileArgTag<GFluidOutputRois>
{
static const char* tag() { return "gapi.fluid.outputRois"; }
};
template<> struct CompileArgTag<GFluidParallelFor>
{
static const char* tag() { return "gapi.fluid.parallelFor"; }
};
template<> struct CompileArgTag<GFluidParallelOutputRois>
{
static const char* tag() { return "gapi.fluid.parallelOutputRois"; }
};
} // 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].unsafe_get<cv::gapi::fluid::View>();
}
};
template<> struct fluid_get_in<cv::GScalar>
{
// FIXME: change to return by reference when moved to own::Scalar
#if !defined(GAPI_STANDALONE)
static const cv::Scalar get(const cv::GArgs &in_args, int idx)
{
return cv::gapi::own::to_ocv(in_args[idx].unsafe_get<cv::gapi::own::Scalar>());
}
#else
static const cv::gapi::own::Scalar get(const cv::GArgs &in_args, int idx)
{
return in_args[idx].get<cv::gapi::own::Scalar>();
}
#endif // !defined(GAPI_STANDALONE)
};
template<typename U> struct fluid_get_in<cv::GArray<U>>
{
static const std::vector<U>& get(const cv::GArgs &in_args, int idx)
{
return in_args.at(idx).unsafe_get<cv::detail::VectorRef>().rref<U>();
}
};
template<class T> struct fluid_get_in
{
static const T& get(const cv::GArgs &in_args, int idx)
{
return in_args[idx].unsafe_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<bool CallCustomGetWindow, typename, typename... Ins>
struct get_window_helper;
template<typename Impl, typename... Ins>
struct get_window_helper<true, Impl, Ins...>
{
template<int... IIs>
static int get_window_impl(const GMetaArgs &metas,
const cv::GArgs &in_args,
cv::detail::Seq<IIs...>)
{
return Impl::getWindow(cv::detail::get_in_meta<Ins>(metas, in_args, IIs)...);
}
static int help(const GMetaArgs &metas, const cv::GArgs &in_args)
{
return get_window_impl(metas, in_args, typename detail::MkSeq<sizeof...(Ins)>::type());
}
};
template<typename Impl, typename... Ins>
struct get_window_helper<false, Impl, Ins...>
{
static int help(const cv::GMetaArgs &,
const cv::GArgs &)
{
return Impl::Window;
}
};
template<typename C, typename T>
struct has_Window
{
private:
template<class U>
static constexpr auto Check(U*) -> typename std::is_same<decltype(U::Window), T>::type;
template<typename>
static constexpr std::false_type Check(...);
typedef decltype(Check<C>(0)) Result;
public:
static constexpr bool value = Result::value;
};
template<bool hasWindow, typename Impl>
struct callCustomGetBorder;
template<typename Impl>
struct callCustomGetBorder<true, Impl>
{
static constexpr bool value = (Impl::Window != 1);
};
template<typename Impl>
struct callCustomGetBorder<false, Impl>
{
static constexpr bool value = true;
};
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");
static_assert(contains<GMat, Ins...>::value, "input must contain at least one 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)
{
constexpr bool hasWindow = has_Window<Impl, const int>::value;
// User must provide "init" callback if Window != 1
// TODO: move to constexpr if when we enable C++17
return get_border_helper<callCustomGetBorder<hasWindow, Impl>::value, Impl, Ins...>::help(metas, in_args);
}
static int getWindow(const GMetaArgs &metas, const cv::GArgs &in_args)
{
constexpr bool callCustomGetWindow = !(has_Window<Impl, const int>::value);
return get_window_helper<callCustomGetWindow, Impl, Ins...>::help(metas, in_args);
}
};
} // namespace detail
template<class Impl, class K, bool UseScratch>
class GFluidKernelImpl : public cv::detail::KernelTag
{
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::Kind, Impl::LPI,
UseScratch,
&P::call, &P::init_scratch, &P::reset_scratch, &P::getBorder, &P::getWindow);
}
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

View File

@@ -0,0 +1,20 @@
// 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_IMGPROC_HPP
#define OPENCV_GAPI_FLUID_IMGPROC_HPP
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
#include <opencv2/gapi/own/exports.hpp> // GAPI_EXPORTS
namespace cv { namespace gapi { namespace imgproc { namespace fluid {
GAPI_EXPORTS GKernelPackage kernels();
}}}}
#endif // OPENCV_GAPI_FLUID_IMGPROC_HPP

View File

@@ -0,0 +1,147 @@
// 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>
#include <opencv2/gapi/streaming/source.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> inline T& get()
{
return util::any_cast<typename std::remove_reference<T>::type>(value);
}
template<typename T> inline const T& get() const
{
return util::any_cast<typename std::remove_reference<T>::type>(value);
}
template<typename T> inline T& unsafe_get()
{
return util::unsafe_any_cast<typename std::remove_reference<T>::type>(value);
}
template<typename T> inline const T& unsafe_get() const
{
return util::unsafe_any_cast<typename std::remove_reference<T>::type>(value);
}
detail::ArgKind kind = detail::ArgKind::OPAQUE_VAL;
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<
#if !defined(GAPI_STANDALONE)
cv::Mat,
cv::Scalar,
cv::UMat,
#endif // !defined(GAPI_STANDALONE)
cv::gapi::wip::IStreamSource::Ptr,
cv::gapi::own::Mat,
cv::gapi::own::Scalar,
cv::detail::VectorRef
>;
using GRunArgs = std::vector<GRunArg>;
namespace gapi
{
namespace wip
{
/**
* @brief This aggregate type represents all types which G-API can handle (via variant).
*
* It only exists to overcome C++ language limitations (where a `using`-defined class can't be forward-declared).
*/
struct Data: public GRunArg
{
using GRunArg::GRunArg;
template <typename T>
Data& operator= (const T& t) { GRunArg::operator=(t); return *this; }
template <typename T>
Data& operator= (T&& t) { GRunArg::operator=(std::move(t)); return *this; }
};
} // namespace wip
} // namespace gapi
using GRunArgP = util::variant<
#if !defined(GAPI_STANDALONE)
cv::Mat*,
cv::Scalar*,
cv::UMat*,
#endif // !defined(GAPI_STANDALONE)
cv::gapi::own::Mat*,
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

View File

@@ -0,0 +1,319 @@
// 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>
#include <opencv2/gapi/gmat.hpp> // flatten_g only!
#include <opencv2/gapi/gscalar.hpp> // flatten_g only!
namespace cv
{
// Forward declaration; GNode and GOrigin are an internal
// (user-inaccessible) classes.
class GNode;
struct GOrigin;
template<typename T> class GArray;
/**
* \addtogroup gapi_meta_args
* @{
*/
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 {};}
static 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 is the base struct for GArrayU type holder
struct TypeHintBase{virtual ~TypeHintBase() = default;};
// This class holds type of initial GArray to be checked from GArrayU
template <typename T>
struct TypeHint final : public TypeHintBase{};
// 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
template <typename T>
bool holds() const; // Check if was created from GArray<T>
GOrigin& priv(); // Internal use only
const GOrigin& priv() const; // Internal use only
protected:
GArrayU(); // Default constructor
template<class> friend class cv::GArray; // (available to GArray<T> only)
void setConstructFcn(ConstructVec &&cv); // Store T-aware constructor
template <typename T>
void specifyType(); // Store type of initial GArray<T>
std::shared_ptr<GOrigin> m_priv;
std::shared_ptr<TypeHintBase> m_hint;
};
template <typename T>
bool GArrayU::holds() const{
GAPI_Assert(m_hint != nullptr);
using U = typename std::decay<T>::type;
return dynamic_cast<TypeHint<U>*>(m_hint.get()) != nullptr;
};
template <typename T>
void GArrayU::specifyType(){
m_hint.reset(new TypeHint<typename std::decay<T>::type>);
};
// 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() {}
virtual void mov(BasicVectorRef &ref) = 0;
};
template<typename T> class VectorRefT final: 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"));
}
virtual void mov(BasicVectorRef &v) override {
VectorRefT<T> *tv = dynamic_cast<VectorRefT<T>*>(&v);
GAPI_Assert(tv != nullptr);
wref() = std::move(tv->wref());
}
};
// 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();
}
void mov(VectorRef &v)
{
m_ref->mov(*v.m_ref);
}
cv::GArrayDesc descr_of() const
{
return m_ref->m_desc;
}
};
// Helper (FIXME: work-around?)
// stripping G types to their host types
// like cv::GArray<GMat> would still map to std::vector<cv::Mat>
// but not to std::vector<cv::GMat>
#if defined(GAPI_STANDALONE)
# define FLATTEN_NS cv::gapi::own
#else
# define FLATTEN_NS cv
#endif
template<class T> struct flatten_g;
template<> struct flatten_g<cv::GMat> { using type = FLATTEN_NS::Mat; };
template<> struct flatten_g<cv::GScalar> { using type = FLATTEN_NS::Scalar; };
template<class T> struct flatten_g { using type = T; };
#undef FLATTEN_NS
// FIXME: the above mainly duplicates "ProtoToParam" thing from gtyped.hpp
// but I decided not to include gtyped here - probably worth moving that stuff
// to some common place? (DM)
} // namespace detail
/** \addtogroup gapi_data_objects
* @{
*/
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:
// Host type (or Flat type) - the type this GArray is actually
// specified to.
using HT = typename detail::flatten_g<typename std::decay<T>::type>::type;
static void VCTor(detail::VectorRef& vref) {
vref.reset<HT>();
}
void putDetails() {
m_ref.setConstructFcn(&VCTor);
m_ref.specifyType<HT>();
}
detail::GArrayU m_ref;
};
/** @} */
} // namespace cv
#endif // OPENCV_GAPI_GARRAY_HPP

View File

@@ -0,0 +1,56 @@
// 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) 2019 Intel Corporation
#ifndef OPENCV_GAPI_GASYNC_CONTEXT_HPP
#define OPENCV_GAPI_GASYNC_CONTEXT_HPP
#if !defined(GAPI_STANDALONE)
# include <opencv2/core/cvdef.h>
#else // Without OpenCV
# include <opencv2/gapi/own/cvdefs.hpp>
#endif // !defined(GAPI_STANDALONE)
#include <opencv2/gapi/own/exports.hpp>
namespace cv {
namespace gapi{
namespace wip {
/**
* @brief A class to group async requests to cancel them in a single shot.
*
* GAsyncContext is passed as an argument to async() and async_apply() functions
*/
class GAPI_EXPORTS GAsyncContext{
std::atomic<bool> cancelation_requested = {false};
public:
/**
* @brief Start cancellation process for an associated request.
*
* User still has to wait for each individual request (either via callback or according std::future object) to make sure it actually canceled.
*
* @return true if it was a first request to cancel the context
*/
bool cancel();
/**
* @brief Returns true if cancellation was requested for this context.
*
* @return true if cancellation was requested for this context
*/
bool isCanceled() const;
};
class GAPI_EXPORTS GAsyncCanceled : public std::exception {
public:
virtual const char* what() const noexcept CV_OVERRIDE;
};
} // namespace wip
} // namespace gapi
} // namespace cv
#endif //OPENCV_GAPI_GASYNC_CONTEXT_HPP

View File

@@ -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
#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);
GMatP yieldP (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

View File

@@ -0,0 +1,168 @@
// 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;
// These structures are tags which separate kernels and transformations
struct KernelTag
{};
struct TransformTag
{};
}
// 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?
/** \addtogroup gapi_compile_args
* @{
*
* @brief Compilation arguments: data structures controlling the
* compilation process
*
* G-API comes with a number of graph compilation options which can be
* passed to cv::GComputation::apply() or
* cv::GComputation::compile(). Known compilation options are listed
* in this page, while extra backends may introduce their own
* compilation options (G-API transparently accepts _everything_ which
* can be passed to cv::compile_args(), it depends on underlying
* backends if an option would be interpreted or not).
*
* For example, if an example computation is executed like this:
*
* @snippet modules/gapi/samples/api_ref_snippets.cpp graph_decl_apply
*
* Extra parameter specifying which kernels to compile with can be
* passed like this:
*
* @snippet modules/gapi/samples/api_ref_snippets.cpp apply_with_param
*/
/**
* @brief Represents an arbitrary compilation argument.
*
* Any value can be wrapped into cv::GCompileArg, but only known ones
* (to G-API or its backends) can be interpreted correctly.
*
* Normally objects of this class shouldn't be created manually, use
* cv::compile_args() function which automatically wraps everything
* passed in (a variadic template parameter pack) into a vector of
* cv::GCompileArg objects.
*/
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>;
/**
* Wraps a list of arguments (a parameter pack) into a vector of
* compilation arguments (cv::GCompileArg).
*/
template<typename... Ts> GCompileArgs compile_args(Ts&&... args)
{
return GCompileArgs{ GCompileArg(args)... };
}
/**
* @brief Ask G-API to dump compiled graph in Graphviz format under
* the given file name.
*
* Specifies a graph dump path (path to .dot file to be generated).
* G-API will dump a .dot file under specified path during a
* compilation process if this flag is passed.
*/
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

View File

@@ -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
#ifndef OPENCV_GAPI_GCOMPILED_HPP
#define OPENCV_GAPI_GCOMPILED_HPP
#include <vector>
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/own/assert.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).
/**
* \addtogroup gapi_main_classes
* @{
*/
/**
* @brief Represents a compiled computation (graph). Can only be used
* with image / data formats & resolutions it was compiled for, with
* some exceptions.
*
* This class represents a product of graph compilation (calling
* cv::GComputation::compile()). Objects of this class actually do
* data processing, and graph execution is incapsulated into objects
* of this class. Execution model itself depends on kernels and
* backends which were using during the compilation, see @ref
* gapi_compile_args for details.
*
* In a general case, GCompiled objects can be applied to data only in
* that formats/resolutions they were compiled for (see @ref
* gapi_meta_args). However, if the underlying backends allow, a
* compiled object can be _reshaped_ to handle data (images) of
* different resolution, though formats and types must remain the same.
*
* GCompiled is very similar to `std::function<>` in its semantics --
* running it looks like a function call in the user code.
*
* At the moment, GCompiled objects are not reentrant -- generally,
* the objects are stateful since graph execution itself is a stateful
* process and this state is now maintained in GCompiled's own memory
* (not on the process stack).
*
* At the same time, two different GCompiled objects produced from the
* single cv::GComputation are completely independent and can be used
* concurrently.
*
* @sa GStreamingCompiled
*/
class GAPI_EXPORTS GCompiled
{
public:
/// @private
class GAPI_EXPORTS Priv;
/**
* @brief Constructs an empty object
*/
GCompiled();
/**
* @brief Run the compiled computation, a generic version.
*
* @param ins vector of inputs to process.
* @param outs vector of outputs to produce.
*
* Input/output vectors must have the same number of elements as
* defined in the cv::GComputation protocol (at the moment of its
* construction). Shapes of elements also must conform to protocol
* (e.g. cv::Mat needs to be passed where cv::GMat has been
* declared as input, and so on). Run-time exception is generated
* otherwise.
*
* Objects in output vector may remain empty (like cv::Mat) --
* G-API will automatically initialize output objects to proper formats.
*
* @note Don't construct GRunArgs/GRunArgsP objects manually, use
* cv::gin()/cv::gout() wrappers instead.
*/
void operator() (GRunArgs &&ins, GRunArgsP &&outs); // Generic arg-to-arg
#if !defined(GAPI_STANDALONE)
/**
* @brief Execute an unary computation
*
* @overload
* @param in input cv::Mat for unary computation
* @param out output cv::Mat for unary computation
* process.
*/
void operator() (cv::Mat in, cv::Mat &out); // Unary overload
/**
* @brief Execute an unary computation
*
* @overload
* @param in input cv::Mat for unary computation
* @param out output cv::Scalar for unary computation
* process.
*/
void operator() (cv::Mat in, cv::Scalar &out); // Unary overload (scalar)
/**
* @brief Execute a binary computation
*
* @overload
* @param in1 first input cv::Mat for binary computation
* @param in2 second input cv::Mat for binary computation
* @param out output cv::Mat for binary computation
* process.
*/
void operator() (cv::Mat in1, cv::Mat in2, cv::Mat &out); // Binary overload
/**
* @brief Execute an binary computation
*
* @overload
* @param in1 first input cv::Mat for binary computation
* @param in2 second input cv::Mat for binary computation
* @param out output cv::Scalar for binary computation
* process.
*/
void operator() (cv::Mat in1, cv::Mat in2, cv::Scalar &out); // Binary overload (scalar)
/**
* @brief Execute a computation with arbitrary number of
* inputs/outputs.
*
* @overload
* @param ins vector of input cv::Mat objects to process by the
* computation.
* @param outs vector of output cv::Mat objects to produce by the
* computation.
*
* Numbers of elements in ins/outs vectos must match numbers of
* inputs/outputs which were used to define the source GComputation.
*/
void operator() (const std::vector<cv::Mat> &ins, // Compatibility overload
const std::vector<cv::Mat> &outs);
#endif // !defined(GAPI_STANDALONE)
/// @private
Priv& priv();
/**
* @brief Check if compiled object is valid (non-empty)
*
* @return true if the object is runnable (valid), false otherwise
*/
explicit operator bool () const;
/**
* @brief Vector of metadata this graph was compiled for.
*
* @return Unless _reshape_ is not supported, return value is the
* same vector which was passed to cv::GComputation::compile() to
* produce this compiled object. Otherwise, it is the latest
* metadata vector passed to reshape() (if that call was
* successful).
*/
const GMetaArgs& metas() const; // Meta passed to compile()
/**
* @brief Vector of metadata descriptions of graph outputs
*
* @return vector with formats/resolutions of graph's output
* objects, auto-inferred from input metadata vector by
* operations which form this computation.
*
* @note GCompiled objects produced from the same
* cv::GComputiation graph with different input metas may return
* different values in this vector.
*/
const GMetaArgs& outMetas() const;
/**
* @brief Check if the underlying backends support reshape or not.
*
* @return true if supported, false otherwise.
*/
bool canReshape() const;
/**
* @brief Reshape a compiled graph to support new image
* resolutions.
*
* Throws an exception if an error occurs.
*
* @param inMetas new metadata to reshape on. Vector size and
* metadata shapes must match the computation's protocol.
* @param args compilation arguments to use.
*/
// FIXME: Why it requires compile args?
void reshape(const GMetaArgs& inMetas, const GCompileArgs& args);
protected:
/// @private
std::shared_ptr<Priv> m_priv;
};
/** @} */
}
#endif // OPENCV_GAPI_GCOMPILED_HPP

View File

@@ -0,0 +1,73 @@
// 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) 2019 Intel Corporation
#ifndef OPENCV_GAPI_GCOMPILED_ASYNC_HPP
#define OPENCV_GAPI_GCOMPILED_ASYNC_HPP
#include <future> //for std::future
#include <exception> //for std::exception_ptr
#include <functional> //for std::function
#include <opencv2/gapi/garg.hpp>
#include <opencv2/gapi/own/exports.hpp>
namespace cv {
//fwd declaration
class GCompiled;
namespace gapi{
namespace wip {
class GAsyncContext;
/**
These functions asynchronously (i.e. probably on a separate thread of execution) call GCompiled::operator() member function of their first argument with copies of rest of arguments (except callback) passed in.
The difference between the function is the way to get the completion notification (via callback or a waiting on std::future object)
If exception is occurred during execution of apply it is transferred to the callback (via function parameter) or passed to future (and will be thrown on call to std::future::get)
N.B. :
Input arguments are copied on call to async function (actually on call to cv::gin) and thus do not have to outlive the actual completion of asynchronous activity.
While output arguments are "captured" by reference(pointer) and therefore _must_ outlive the asynchronous activity
(i.e. live at least until callback is called or future is unblocked)
@param gcmpld Compiled computation (graph) to start asynchronously
@param callback Callback to be called when execution of gcmpld is done
@param ins Input parameters for gcmpld
@param outs Output parameters for gcmpld
*/
GAPI_EXPORTS void async(GCompiled& gcmpld, std::function<void(std::exception_ptr)>&& callback, GRunArgs &&ins, GRunArgsP &&outs);
/** @overload
@param gcmpld Compiled computation (graph) to run asynchronously
@param callback Callback to be called when execution of gcmpld is done
@param ins Input parameters for gcmpld
@param outs Output parameters for gcmpld
@param ctx Context this request belongs to
@see async GAsyncContext
*/
GAPI_EXPORTS void async(GCompiled& gcmpld, std::function<void(std::exception_ptr)>&& callback, GRunArgs &&ins, GRunArgsP &&outs, GAsyncContext& ctx);
/** @overload
@param gcmpld Compiled computation (graph) to run asynchronously
@param ins Input parameters for gcmpld
@param outs Output parameters for gcmpld
@return std::future<void> object to wait for completion of async operation
@see async
*/
GAPI_EXPORTS std::future<void> async(GCompiled& gcmpld, GRunArgs &&ins, GRunArgsP &&outs);
/**
@param gcmpld Compiled computation (graph) to run asynchronously
@param ins Input parameters for gcmpld
@param outs Output parameters for gcmpld
@param ctx Context this request belongs to
@return std::future<void> object to wait for completion of async operation
@see async GAsyncContext
*/
GAPI_EXPORTS std::future<void> async(GCompiled& gcmpld, GRunArgs &&ins, GRunArgsP &&outs, GAsyncContext& ctx);
} // namespace wip
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_GCOMPILED_ASYNC_HPP

View File

@@ -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-2019 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;
}
};
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>,
public cv::detail::KernelTag
{
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
/**
* Declares a new compound kernel. See this
* [documentation chapter](@ref gapi_kernel_compound)
* on compound kernels for more details.
*
* @param Name type name for new kernel
* @param API the interface this kernel implements
*/
#define GAPI_COMPOUND_KERNEL(Name, API) \
struct Name: public cv::detail::GCompoundKernelImpl<Name, API>
} // namespace cv
#endif // OPENCV_GAPI_GCOMPOUNDKERNEL_HPP

View File

@@ -0,0 +1,559 @@
// 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>
#include <opencv2/gapi/gstreaming.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;
}
/**
* \addtogroup gapi_main_classes
* @{
*
* @brief G-API classes for constructed and compiled graphs.
*/
/**
* @brief GComputation class represents a captured computation
* graph. GComputation objects form boundaries for expression code
* user writes with G-API, allowing to compile and execute it.
*
* G-API computations are defined with input/output data
* objects. G-API will track automatically which operations connect
* specified outputs to the inputs, forming up a call graph to be
* executed. The below example expresses calculation of Sobel operator
* for edge detection (\f$G = \sqrt{G_x^2 + G_y^2}\f$):
*
* @snippet modules/gapi/samples/api_ref_snippets.cpp graph_def
*
* Full pipeline can be now captured with this object declaration:
*
* @snippet modules/gapi/samples/api_ref_snippets.cpp graph_cap_full
*
* Input/output data objects on which a call graph should be
* reconstructed are passed using special wrappers cv::GIn and
* cv::GOut. G-API will track automatically which operations form a
* path from inputs to outputs and build the execution graph appropriately.
*
* Note that cv::GComputation doesn't take ownership on data objects
* it is defined. Moreover, multiple GComputation objects may be
* defined on the same expressions, e.g. a smaller pipeline which
* expects that image gradients are already pre-calculated may be
* defined like this:
*
* @snippet modules/gapi/samples/api_ref_snippets.cpp graph_cap_sub
*
* The resulting graph would expect two inputs and produce one
* output. In this case, it doesn't matter if gx/gy data objects are
* results of cv::gapi::Sobel operators -- G-API will stop unrolling
* expressions and building the underlying graph one reaching this
* data objects.
*
* The way how GComputation is defined is important as its definition
* specifies graph _protocol_ -- the way how the graph should be
* used. Protocol is defined by number of inputs, number of outputs,
* and shapes of inputs and outputs.
*
* In the above example, sobelEdge expects one Mat on input and
* produces one Mat; while sobelEdgeSub expects two Mats on input and
* produces one Mat. GComputation's protocol defines how other
* computation methods should be used -- cv::GComputation::compile() and
* cv::GComputation::apply(). For example, if a graph is defined on
* two GMat inputs, two cv::Mat objects have to be passed to apply()
* for execution. GComputation checks protocol correctness in runtime
* so passing a different number of objects in apply() or passing
* cv::Scalar instead of cv::Mat there would compile well as a C++
* source but raise an exception in run-time. G-API also comes with a
* typed wrapper cv::GComputationT<> which introduces this type-checking in
* compile-time.
*
* cv::GComputation itself is a thin object which just captures what
* the graph is. The compiled graph (which actually process data) is
* represented by class GCompiled. Use compile() method to generate a
* compiled graph with given compile options. cv::GComputation can
* also be used to process data with implicit graph compilation
* on-the-fly, see apply() for details.
*
* GComputation is a reference-counted object -- once defined, all its
* copies will refer to the same instance.
*
* @sa GCompiled
*/
class GAPI_EXPORTS GComputation
{
public:
class Priv;
typedef std::function<GComputation()> Generator;
// Various constructors enable different ways to define a computation: /////
// 1. Generic constructors
/**
* @brief Define a computation using a generator function.
*
* Graph can be defined in-place directly at the moment of its
* construction with a lambda:
*
* @snippet modules/gapi/samples/api_ref_snippets.cpp graph_gen
*
* This may be useful since all temporary objects (cv::GMats) and
* namespaces can be localized to scope of lambda, without
* contaminating the parent scope with probably unnecessary objects
* and information.
*
* @param gen generator function which returns a cv::GComputation,
* see Generator.
*/
GComputation(const Generator& gen); // Generator
// overload
/**
* @brief Generic GComputation constructor.
*
* Constructs a new graph with a given protocol, specified as a
* flow of operations connecting input/output objects. Throws if
* the passed boundaries are invalid, e.g. if there's no
* functional dependency (path) between given outputs and inputs.
*
* @param ins Input data vector.
* @param outs Output data vector.
*
* @note Don't construct GProtoInputArgs/GProtoOutputArgs objects
* directly, use cv::GIn()/cv::GOut() wrapper functions instead.
*
* @sa @ref gapi_data_objects
*/
GComputation(GProtoInputArgs &&ins,
GProtoOutputArgs &&outs); // Arg-to-arg overload
// 2. Syntax sugar and compatibility overloads
/**
* @brief Defines an unary (one input -- one output) computation
*
* @overload
* @param in input GMat of the defined unary computation
* @param out output GMat of the defined unary computation
*/
GComputation(GMat in, GMat out); // Unary overload
/**
* @brief Defines an unary (one input -- one output) computation
*
* @overload
* @param in input GMat of the defined unary computation
* @param out output GScalar of the defined unary computation
*/
GComputation(GMat in, GScalar out); // Unary overload (scalar)
/**
* @brief Defines a binary (two inputs -- one output) computation
*
* @overload
* @param in1 first input GMat of the defined binary computation
* @param in2 second input GMat of the defined binary computation
* @param out output GMat of the defined binary computation
*/
GComputation(GMat in1, GMat in2, GMat out); // Binary overload
/**
* @brief Defines a binary (two inputs -- one output) computation
*
* @overload
* @param in1 first input GMat of the defined binary computation
* @param in2 second input GMat of the defined binary computation
* @param out output GScalar of the defined binary computation
*/
GComputation(GMat in1, GMat in2, GScalar out); // Binary
// overload
// (scalar)
/**
* @brief Defines a computation with arbitrary input/output number.
*
* @overload
* @param ins vector of inputs GMats for this computation
* @param outs vector of outputs GMats for this computation
*
* Use this overload for cases when number of computation
* inputs/outputs is not known in compile-time -- e.g. when graph
* is programmatically generated to build an image pyramid with
* the given number of levels, etc.
*/
GComputation(const std::vector<GMat> &ins, // Compatibility overload
const std::vector<GMat> &outs);
// Various versions of apply(): ////////////////////////////////////////////
// 1. Generic apply()
/**
* @brief Compile graph on-the-fly and immediately execute it on
* the inputs data vectors.
*
* Number of input/output data objects must match GComputation's
* protocol, also types of host data objects (cv::Mat, cv::Scalar)
* must match the shapes of data objects from protocol (cv::GMat,
* cv::GScalar). If there's a mismatch, a run-time exception will
* be generated.
*
* Internally, a cv::GCompiled object is created for the given
* input format configuration, which then is executed on the input
* data immediately. cv::GComputation caches compiled objects
* produced within apply() -- if this method would be called next
* time with the same input parameters (image formats, image
* resolution, etc), the underlying compiled graph will be reused
* without recompilation. If new metadata doesn't match the cached
* one, the underlying compiled graph is regenerated.
*
* @note compile() always triggers a compilation process and
* produces a new GCompiled object regardless if a similar one has
* been cached via apply() or not.
*
* @param ins vector of input data to process. Don't create
* GRunArgs object manually, use cv::gin() wrapper instead.
* @param outs vector of output data to fill results in. cv::Mat
* objects may be empty in this vector, G-API will automatically
* initialize it with the required format & dimensions. Don't
* create GRunArgsP object manually, use cv::gout() wrapper instead.
* @param args a list of compilation arguments to pass to the
* underlying compilation process. Don't create GCompileArgs
* object manually, use cv::compile_args() wrapper instead.
*
* @sa @ref gapi_data_objects, @ref gapi_compile_args
*/
void apply(GRunArgs &&ins, GRunArgsP &&outs, GCompileArgs &&args = {}); // Arg-to-arg overload
/// @private -- Exclude this function from OpenCV documentation
void apply(const std::vector<cv::gapi::own::Mat>& ins, // Compatibility overload
const std::vector<cv::gapi::own::Mat>& outs,
GCompileArgs &&args = {});
// 2. Syntax sugar and compatibility overloads
#if !defined(GAPI_STANDALONE)
/**
* @brief Execute an unary computation (with compilation on the fly)
*
* @overload
* @param in input cv::Mat for unary computation
* @param out output cv::Mat for unary computation
* @param args compilation arguments for underlying compilation
* process.
*/
void apply(cv::Mat in, cv::Mat &out, GCompileArgs &&args = {}); // Unary overload
/**
* @brief Execute an unary computation (with compilation on the fly)
*
* @overload
* @param in input cv::Mat for unary computation
* @param out output cv::Scalar for unary computation
* @param args compilation arguments for underlying compilation
* process.
*/
void apply(cv::Mat in, cv::Scalar &out, GCompileArgs &&args = {}); // Unary overload (scalar)
/**
* @brief Execute a binary computation (with compilation on the fly)
*
* @overload
* @param in1 first input cv::Mat for binary computation
* @param in2 second input cv::Mat for binary computation
* @param out output cv::Mat for binary computation
* @param args compilation arguments for underlying compilation
* process.
*/
void apply(cv::Mat in1, cv::Mat in2, cv::Mat &out, GCompileArgs &&args = {}); // Binary overload
/**
* @brief Execute an binary computation (with compilation on the fly)
*
* @overload
* @param in1 first input cv::Mat for binary computation
* @param in2 second input cv::Mat for binary computation
* @param out output cv::Scalar for binary computation
* @param args compilation arguments for underlying compilation
* process.
*/
void apply(cv::Mat in1, cv::Mat in2, cv::Scalar &out, GCompileArgs &&args = {}); // Binary overload (scalar)
/**
* @brief Execute a computation with arbitrary number of
* inputs/outputs (with compilation on-the-fly).
*
* @overload
* @param ins vector of input cv::Mat objects to process by the
* computation.
* @param outs vector of output cv::Mat objects to produce by the
* computation.
* @param args compilation arguments for underlying compilation
* process.
*
* Numbers of elements in ins/outs vectos must match numbers of
* inputs/outputs which were used to define this GComputation.
*/
void apply(const std::vector<cv::Mat>& ins, // Compatibility overload
std::vector<cv::Mat>& outs,
GCompileArgs &&args = {});
#endif // !defined(GAPI_STANDALONE)
// Various versions of compile(): //////////////////////////////////////////
// 1. Generic compile() - requires metas to be passed as vector
/**
* @brief Compile the computation for specific input format(s).
*
* This method triggers compilation process and produces a new
* GCompiled object which then can process data of the given
* format. Passing data with different format to the compiled
* computation will generate a run-time exception.
*
* @param in_metas vector of input metadata configuration. Grab
* metadata from real data objects (like cv::Mat or cv::Scalar)
* using cv::descr_of(), or create it on your own.
* @param args compilation arguments for this compilation
* process. Compilation arguments directly affect what kind of
* executable object would be produced, e.g. which kernels (and
* thus, devices) would be used to execute computation.
*
* @return GCompiled, an executable computation compiled
* specifically for the given input parameters.
*
* @sa @ref gapi_compile_args
*/
GCompiled compile(GMetaArgs &&in_metas, GCompileArgs &&args = {});
// 2. Syntax sugar - variadic list of metas, no extra compile args
// FIXME: SFINAE looks ugly in the generated documentation
/**
* @overload
*
* Takes a variadic parameter pack with metadata
* descriptors for which a compiled object needs to be produced.
*
* @return GCompiled, an executable computation compiled
* specifically for the given input parameters.
*/
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).
// FIXME: SFINAE looks ugly in the generated documentation
/**
* @overload
*
* Takes a variadic parameter pack with metadata
* descriptors for which a compiled object needs to be produced,
* followed by GCompileArgs object representing compilation
* arguments for this process.
*
* @return GCompiled, an executable computation compiled
* specifically for the given input parameters.
*/
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());
}
// FIXME: Document properly in the Doxygen format
// Video-oriented pipeline compilation:
// 1. A generic version
/**
* @brief Compile the computation for streaming mode.
*
* This method triggers compilation process and produces a new
* GStreamingCompiled object which then can process video stream
* data of the given format. Passing a stream in a different
* format to the compiled computation will generate a run-time
* exception.
*
* @param in_metas vector of input metadata configuration. Grab
* metadata from real data objects (like cv::Mat or cv::Scalar)
* using cv::descr_of(), or create it on your own.
*
* @param args compilation arguments for this compilation
* process. Compilation arguments directly affect what kind of
* executable object would be produced, e.g. which kernels (and
* thus, devices) would be used to execute computation.
*
* @return GStreamingCompiled, a streaming-oriented executable
* computation compiled specifically for the given input
* parameters.
*
* @sa @ref gapi_compile_args
*/
GStreamingCompiled compileStreaming(GMetaArgs &&in_metas, GCompileArgs &&args = {});
/**
* @brief Compile the computation for streaming mode.
*
* This method triggers compilation process and produces a new
* GStreamingCompiled object which then can process video stream
* data in any format. Underlying mechanisms will be adjusted to
* every new input video stream automatically, but please note that
* _not all_ existing backends support this (see reshape()).
*
* @param args compilation arguments for this compilation
* process. Compilation arguments directly affect what kind of
* executable object would be produced, e.g. which kernels (and
* thus, devices) would be used to execute computation.
*
* @return GStreamingCompiled, a streaming-oriented executable
* computation compiled for any input image format.
*
* @sa @ref gapi_compile_args
*/
GStreamingCompiled compileStreaming(GCompileArgs &&args = {});
// 2. Direct metadata version
/**
* @overload
*
* Takes a variadic parameter pack with metadata
* descriptors for which a compiled object needs to be produced.
*
* @return GStreamingCompiled, a streaming-oriented executable
* computation compiled specifically for the given input
* parameters.
*/
template<typename... Ts>
auto compileStreaming(const Ts&... metas) ->
typename std::enable_if<detail::are_meta_descrs<Ts...>::value, GStreamingCompiled>::type
{
return compileStreaming(GMetaArgs{GMetaArg(metas)...}, GCompileArgs());
}
// 2. Direct metadata + compile arguments version
/**
* @overload
*
* Takes a variadic parameter pack with metadata
* descriptors for which a compiled object needs to be produced,
* followed by GCompileArgs object representing compilation
* arguments for this process.
*
* @return GStreamingCompiled, a streaming-oriented executable
* computation compiled specifically for the given input
* parameters.
*/
template<typename... Ts>
auto compileStreaming(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,
GStreamingCompiled>::type
{
//FIXME: wrapping meta_and_compile_args into a tuple to unwrap them inside a helper function is the overkill
return compileStreaming(std::make_tuple(meta_and_compile_args...),
typename detail::MkSeq<sizeof...(Ts)-1>::type());
}
// Internal use only
/// @private
Priv& priv();
/// @private
const Priv& priv() const;
protected:
// 4. Helper methods for (3)
/// @private
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));
}
template<typename... Ts, int... IIs>
GStreamingCompiled compileStreaming(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 compileStreaming(std::move(meta_args), std::move(comp_args));
}
/// @private
std::shared_ptr<Priv> m_priv;
};
/** @} */
namespace gapi
{
// FIXME: all these standalone functions need to be added to some
// common documentation section
/**
* @brief Define an tagged island (subgraph) within a computation.
*
* 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.
*
* Islands allow to partition graph into subgraphs, fine-tuning
* the way it is scheduled by the underlying executor.
*
* @param name name of the Island to create
* @param ins vector of input data objects where the subgraph
* begins
* @param outs vector of output data objects where the subgraph
* ends.
*
* The way how an island is defined is similar to how
* cv::GComputation is defined on input/output data objects.
* Same rules apply here as well -- if there's no functional
* dependency between inputs and outputs or there's not enough
* input data objects were specified to properly calculate all
* outputs, an exception is thrown.
*
* Use cv::GIn() / cv::GOut() to specify input/output vectors.
*/
void GAPI_EXPORTS island(const std::string &name,
GProtoInputArgs &&ins,
GProtoOutputArgs &&outs);
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_GCOMPUTATION_HPP

View File

@@ -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) 2019 Intel Corporation
#ifndef OPENCV_GAPI_GCOMPUTATION_ASYNC_HPP
#define OPENCV_GAPI_GCOMPUTATION_ASYNC_HPP
#include <future> //for std::future
#include <exception> //for std::exception_ptr
#include <functional> //for std::function
#include <opencv2/gapi/garg.hpp> //for GRunArgs, GRunArgsP
#include <opencv2/gapi/gcommon.hpp> //for GCompileArgs
#include <opencv2/gapi/own/exports.hpp>
namespace cv {
//fwd declaration
class GComputation;
namespace gapi {
namespace wip {
class GAsyncContext;
/** In contrast to async() functions, these do call GComputation::apply() member function of the GComputation passed in.
@param gcomp Computation (graph) to run asynchronously
@param callback Callback to be called when execution of gcomp is done
@param ins Input parameters for gcomp
@param outs Output parameters for gcomp
@param args Compile arguments to pass to GComputation::apply()
@see async
*/
GAPI_EXPORTS void async_apply(GComputation& gcomp, std::function<void(std::exception_ptr)>&& callback, GRunArgs &&ins, GRunArgsP &&outs, GCompileArgs &&args = {});
/** @overload
@param gcomp Computation (graph) to run asynchronously
@param callback Callback to be called when execution of gcomp is done
@param ins Input parameters for gcomp
@param outs Output parameters for gcomp
@param args Compile arguments to pass to GComputation::apply()
@param ctx Context this request belongs to
@see async_apply async GAsyncContext
*/
GAPI_EXPORTS void async_apply(GComputation& gcomp, std::function<void(std::exception_ptr)>&& callback, GRunArgs &&ins, GRunArgsP &&outs, GCompileArgs &&args, GAsyncContext& ctx);
/** @overload
@param gcomp Computation (graph) to run asynchronously
@param ins Input parameters for gcomp
@param outs Output parameters for gcomp
@param args Compile arguments to pass to GComputation::apply()
@return std::future<void> object to wait for completion of async operation
@see async_apply async
*/
GAPI_EXPORTS std::future<void> async_apply(GComputation& gcomp, GRunArgs &&ins, GRunArgsP &&outs, GCompileArgs &&args = {});
/** @overload
@param gcomp Computation (graph) to run asynchronously
@param ins Input parameters for gcomp
@param outs Output parameters for gcomp
@param args Compile arguments to pass to GComputation::apply()
@param ctx Context this request belongs to
@return std::future<void> object to wait for completion of async operation
@see async_apply async GAsyncContext
*/
GAPI_EXPORTS std::future<void> async_apply(GComputation& gcomp, GRunArgs &&ins, GRunArgsP &&outs, GCompileArgs &&args, GAsyncContext& ctx);
} // namespace wip
} // namespace gapi
} // namespace cv
#endif //OPENCV_GAPI_GCOMPUTATION_ASYNC_HPP

View File

@@ -0,0 +1,609 @@
// 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-2019 Intel Corporation
#ifndef OPENCV_GAPI_GKERNEL_HPP
#define OPENCV_GAPI_GKERNEL_HPP
#include <functional>
#include <iostream>
#include <string> // string
#include <type_traits> // false_type, true_type
#include <unordered_map> // map (for GKernelPackage)
#include <utility> // tuple
#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
#include <opencv2/gapi/gtransform.hpp>
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 std::string tag; // some (implementation-specific) tag
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::GMatP>
{
static inline cv::GMatP yield(cv::GCall &call, int i) { return call.yieldP(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::GMatP> { 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());
}
};
////////////////////////////////////////////////////////////////////////////
// Helper class to introduce tags to calls. By default there's no tag
struct NoTag {
static constexpr const char *tag() { return ""; }
};
} // 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_KERNEL_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...>>
, public detail::NoTag
{
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::tag(), &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 detail::NoTag
{
public:
using InArgs = std::tuple<Args...>;
using OutArgs = std::tuple<R>;
static R on(Args... args)
{
cv::GCall call(GKernel{K::id(), K::tag(), &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)
//! @cond IGNORED
#define G_ID_HELPER_CLASS(Class) Class##IdHelper
#define G_ID_HELPER_BODY(Class, Id) \
struct G_ID_HELPER_CLASS(Class) \
{ \
static constexpr const char * id() {return Id;} \
}; \
//! @endcond
/**
* Declares a new G-API Operation. See [Kernel API](@ref gapi_kernel_api)
* for more details.
*
* @param Class type name for this operation.
* @param API an `std::function<>`-like signature for the operation;
* return type is a single value.
* @param Id string identifier for the operation. Must be unique.
*/
#define G_TYPED_KERNEL(Class, API, Id) \
G_ID_HELPER_BODY(Class, Id) \
struct Class final: public cv::GKernelType<Class, std::function API >, \
public G_ID_HELPER_CLASS(Class)
// {body} is to be defined by user
/**
* Declares a new G-API Operation. See [Kernel API](@ref gapi_kernel_api)
* for more details.
*
* @param Class type name for this operation.
* @param API an `std::function<>`-like signature for the operation;
* return type is a tuple of multiple values.
* @param Id string identifier for the operation. Must be unique.
*/
#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 G_ID_HELPER_CLASS(Class)
// {body} is to be defined by user
#define G_API_OP G_TYPED_KERNEL
#define G_API_OP_M G_TYPED_KERNEL_M
namespace cv
{
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 {
/** \addtogroup gapi_compile_args
* @{
*/
// FIXME: Hide implementation
/**
* @brief A container class for heterogeneous kernel
* implementation collections and graph transformations.
*
* GKernelPackage is a special container class which stores kernel
* _implementations_ and graph _transformations_. Objects of this class
* are created and passed to cv::GComputation::compile() to specify
* which kernels to use and which transformations to apply in the
* compiled graph. GKernelPackage may contain kernels of
* different backends, e.g. be heterogeneous.
*
* The most easy way to create a kernel package is to use function
* cv::gapi::kernels(). This template functions takes kernel
* implementations in form of type list (variadic template) and
* generates a kernel package atop of that.
*
* Kernel packages can be also generated programmatically, starting
* with an empty package (created with the default constructor)
* and then by populating it with kernels via call to
* GKernelPackage::include(). Note this method is also a template
* one since G-API kernel and transformation implementations are _types_,
* not objects.
*
* Finally, two kernel packages can be combined into a new one
* with function cv::gapi::combine().
*/
class GAPI_EXPORTS GKernelPackage
{
/// @private
using M = std::unordered_map<std::string, std::pair<GBackend, GKernelImpl>>;
/// @private
M m_id_kernels;
/// @private
std::vector<GTransform> m_transformations;
protected:
/// @private
// Check if package contains ANY implementation of a kernel API
// by API textual id.
bool includesAPI(const std::string &id) const;
/// @private
// Remove ALL implementations of the given API (identified by ID)
void removeAPI(const std::string &id);
/// @private
// Partial include() specialization for kernels
template <typename KImpl>
typename std::enable_if<(std::is_base_of<detail::KernelTag, KImpl>::value), void>::type
includeHelper()
{
auto backend = KImpl::backend();
auto kernel_id = KImpl::API::id();
auto kernel_impl = GKernelImpl{KImpl::kernel()};
removeAPI(kernel_id);
m_id_kernels[kernel_id] = std::make_pair(backend, kernel_impl);
}
/// @private
// Partial include() specialization for transformations
template <typename TImpl>
typename std::enable_if<(std::is_base_of<detail::TransformTag, TImpl>::value), void>::type
includeHelper()
{
m_transformations.emplace_back(TImpl::transformation());
}
public:
/**
* @brief Returns total number of kernels
* in the package (across all backends included)
*
* @return a number of kernels in the package
*/
std::size_t size() const;
/**
* @brief Returns vector of transformations included in the package
*
* @return vector of transformations included in the package
*/
const std::vector<GTransform>& get_transformations() const;
/**
* @brief Test if a particular kernel _implementation_ KImpl is
* included in this kernel package.
*
* @sa includesAPI()
*
* @note cannot be applied to transformations
*
* @return true if there is such kernel, false otherwise.
*/
template<typename KImpl>
bool includes() const
{
static_assert(std::is_base_of<detail::KernelTag, KImpl>::value,
"includes() can be applied to kernels only");
auto kernel_it = m_id_kernels.find(KImpl::API::id());
return kernel_it != m_id_kernels.end() &&
kernel_it->second.first == KImpl::backend();
}
/**
* @brief Remove all kernels associated with the given backend
* from the package.
*
* Does nothing if there's no kernels of this backend in the package.
*
* @param backend backend which kernels to remove
*/
void remove(const GBackend& backend);
/**
* @brief Remove all kernels implementing the given API from
* the package.
*
* Does nothing if there's no kernels implementing the given interface.
*/
template<typename KAPI>
void remove()
{
removeAPI(KAPI::id());
}
// FIXME: Rename to includes() and distinguish API/impl case by
// statically?
/**
* Check if package contains ANY implementation of a kernel API
* by API type.
*/
template<typename KAPI>
bool includesAPI() const
{
return includesAPI(KAPI::id());
}
// FIXME: The below comment is wrong, and who needs this function?
/**
* @brief Find a kernel (by its API)
*
* Returns implementation corresponding id.
* Throws if nothing found.
*
* @return Backend which hosts matching kernel implementation.
*
*/
template<typename KAPI>
GBackend lookup() const
{
return lookup(KAPI::id()).first;
}
/// @private
std::pair<cv::gapi::GBackend, cv::GKernelImpl>
lookup(const std::string &id) const;
// FIXME: No overwrites allowed?
/**
* @brief Put a new kernel implementation or a new transformation
* KImpl into the package.
*/
template<typename KImpl>
void include()
{
includeHelper<KImpl>();
}
/**
* @brief Lists all backends which are included into package
*
* @return vector of backends
*/
std::vector<GBackend> backends() const;
// TODO: Doxygen bug -- it wants me to place this comment
// here, not below.
/**
* @brief Create a new package based on `lhs` and `rhs`.
*
* @param lhs "Left-hand-side" package in the process
* @param rhs "Right-hand-side" package in the process
* @return a new kernel package.
*/
friend GAPI_EXPORTS GKernelPackage combine(const GKernelPackage &lhs,
const GKernelPackage &rhs);
};
/**
* @brief Create a kernel package object containing kernels
* and transformations specified in variadic template argument.
*
* In G-API, kernel implementations and transformations are _types_.
* Every backend has its own kernel API (like GAPI_OCV_KERNEL() and
* GAPI_FLUID_KERNEL()) but all of that APIs define a new type for
* each kernel implementation.
*
* Use this function to pass kernel implementations (defined in
* either way) and transformations to the system. Example:
*
* @snippet modules/gapi/samples/api_ref_snippets.cpp kernels_snippet
*
* Note that kernels() itself is a function returning object, not
* a type, so having `()` at the end is important -- it must be a
* function call.
*/
template<typename... KK> GKernelPackage kernels()
{
// FIXME: currently there is no check that transformations' signatures are unique
// and won't be any intersection in graph compilation stage
static_assert(detail::all_unique<typename KK::API...>::value, "Kernels API must be unique");
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;
};
/** @} */
// FYI - this function is already commented above
GAPI_EXPORTS GKernelPackage combine(const GKernelPackage &lhs,
const GKernelPackage &rhs);
/**
* @brief Combines multiple G-API kernel packages into one
*
* @overload
*
* This function successively combines the passed kernel packages using a right fold.
* Calling `combine(a, b, c)` is equal to `combine(a, combine(b, c))`.
*
* @return The resulting kernel package
*/
template<typename... Ps>
GKernelPackage combine(const GKernelPackage &a, const GKernelPackage &b, Ps&&... rest)
{
return combine(a, combine(b, rest...));
}
/** \addtogroup gapi_compile_args
* @{
*/
/**
* @brief cv::use_only() is a special combinator which hints G-API to use only
* kernels specified in cv::GComputation::compile() (and not to extend kernels available by
* default with that package).
*/
struct GAPI_EXPORTS use_only
{
GKernelPackage pkg;
};
/** @} */
} // namespace gapi
namespace detail
{
template<> struct CompileArgTag<cv::gapi::GKernelPackage>
{
static const char* tag() { return "gapi.kernel_package"; }
};
template<> struct CompileArgTag<cv::gapi::use_only>
{
static const char* tag() { return "gapi.use_only"; }
};
} // namespace detail
} // namespace cv
#endif // OPENCV_GAPI_GKERNEL_HPP

View File

@@ -0,0 +1,237 @@
// 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;
/** \addtogroup gapi_data_objects
* @{
*
* @brief G-API data objects used to build G-API expressions.
*
* These objects do not own any particular data (except compile-time
* associated values like with cv::GScalar) and are used to construct
* graphs.
*
* Every graph in G-API starts and ends with data objects.
*
* Once constructed and compiled, G-API operates with regular host-side
* data instead. Refer to the below table to find the mapping between
* G-API and regular data types.
*
* G-API data type | I/O data type
* ------------------ | -------------
* cv::GMat | cv::Mat
* cv::GScalar | cv::Scalar
* `cv::GArray<T>` | std::vector<T>
*/
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;
};
class GAPI_EXPORTS GMatP : public GMat
{
public:
using GMat::GMat;
};
namespace gapi { namespace own {
class Mat;
}}//gapi::own
/** @} */
/**
* \addtogroup gapi_meta_args
* @{
*/
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
bool planar;
std::vector<int> dims; // FIXME: Maybe it's real questionable to have it here
GMatDesc(int d, int c, cv::gapi::own::Size s, bool p = false)
: depth(d), chan(c), size(s), planar(p) {}
GMatDesc(int d, const std::vector<int> &dd)
: depth(d), chan(-1), size{-1,-1}, planar(false), dims(dd) {}
GMatDesc(int d, std::vector<int> &&dd)
: depth(d), chan(-1), size{-1,-1}, planar(false), dims(std::move(dd)) {}
GMatDesc() : GMatDesc(-1, -1, {-1,-1}) {}
inline bool operator== (const GMatDesc &rhs) const
{
return depth == rhs.depth
&& chan == rhs.chan
&& size == rhs.size
&& planar == rhs.planar
&& dims == rhs.dims;
}
inline bool operator!= (const GMatDesc &rhs) const
{
return !(*this == rhs);
}
bool isND() const { return !dims.empty(); }
// Checks if the passed mat can be described by this descriptor
// (it handles the case when
// 1-channel mat can be reinterpreted as is (1-channel mat)
// and as a 3-channel planar mat with height divided by 3)
bool canDescribe(const cv::gapi::own::Mat& mat) const;
// 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;
}
#if !defined(GAPI_STANDALONE)
GMatDesc withSizeDelta(cv::Size delta) const
{
return withSizeDelta(to_own(delta));
}
GMatDesc withSize(cv::Size sz) const
{
return withSize(to_own(sz));
}
bool canDescribe(const cv::Mat& mat) const;
#endif // !defined(GAPI_STANDALONE)
// 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;
}
// 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;
}
// Meta combinator: return a new GMatDesc with planar flag set
// (no size changes are performed, only channel interpretation is changed
// (interleaved -> planar)
GMatDesc asPlanar() const
{
GAPI_Assert(planar == false);
GMatDesc desc(*this);
desc.planar = true;
return desc;
}
// Meta combinator: return a new GMatDesc
// reinterpreting 1-channel input as planar image
// (size height is divided by plane number)
GMatDesc asPlanar(int planes) const
{
GAPI_Assert(planar == false);
GAPI_Assert(chan == 1);
GAPI_Assert(planes > 1);
GAPI_Assert(size.height % planes == 0);
GMatDesc desc(*this);
desc.size.height /= planes;
desc.chan = planes;
return desc.asPlanar();
}
// Meta combinator: return a new GMatDesc with planar flag set to false
// (no size changes are performed, only channel interpretation is changed
// (planar -> interleaved)
GMatDesc asInterleaved() const
{
GAPI_Assert(planar == true);
GMatDesc desc(*this);
desc.planar = false;
return desc;
}
};
static inline GMatDesc empty_gmat_desc() { return GMatDesc{-1,-1,{-1,-1}}; }
#if !defined(GAPI_STANDALONE)
class Mat;
GAPI_EXPORTS GMatDesc descr_of(const cv::Mat &mat);
GAPI_EXPORTS GMatDesc descr_of(const cv::UMat &mat);
#endif // !defined(GAPI_STANDALONE)
/** @} */
// FIXME: WHY??? WHY it is under different namespace?
namespace gapi { namespace own {
GAPI_EXPORTS GMatDesc descr_of(const Mat &mat);
}}//gapi::own
GAPI_EXPORTS std::ostream& operator<<(std::ostream& os, const cv::GMatDesc &desc);
} // namespace cv
#endif // OPENCV_GAPI_GMAT_HPP

View File

@@ -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_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
>;
GAPI_EXPORTS 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
// Note: descr_of(std::vector<..>) returns a GArrayDesc, while
// descrs_of(std::vector<..>) returns an array of Meta args!
class Mat;
class UMat;
GAPI_EXPORTS cv::GMetaArgs descrs_of(const std::vector<cv::Mat> &vec);
GAPI_EXPORTS cv::GMetaArgs descrs_of(const std::vector<cv::UMat> &vec);
namespace gapi { namespace own {
class Mat;
GAPI_EXPORTS cv::GMetaArgs descrs_of(const std::vector<Mat> &vec);
}} // namespace gapi::own
} // namespace cv
#endif // OPENCV_GAPI_GMETAARG_HPP

View File

@@ -0,0 +1,129 @@
// 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
, GMatP
, 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)...));
}
namespace detail
{
// Extract elements form tuple
// FIXME: Someday utilize a generic tuple_to_vec<> routine
template<typename... Ts, int... Indexes>
static GProtoOutputArgs getGOut_impl(const std::tuple<Ts...>& ts, detail::Seq<Indexes...>)
{
return GProtoOutputArgs{ detail::packArgs(std::get<Indexes>(ts)...)};
}
}
template<typename... Ts> inline GProtoOutputArgs GOut(const std::tuple<Ts...>& ts)
{
// TODO: think of std::forward(ts)
return detail::getGOut_impl(ts, typename detail::MkSeq<sizeof...(Ts)>::type());
}
// Takes rvalue as input arg
template<typename... Ts> inline GProtoOutputArgs GOut(std::tuple<Ts...>&& ts)
{
// TODO: think of std::forward(ts)
return detail::getGOut_impl(ts, typename detail::MkSeq<sizeof...(Ts)>::type());
}
// 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);
// Checks if run-time computation argument can be described by metadata
bool GAPI_EXPORTS can_describe(const GMetaArg& meta, const GRunArg& arg);
bool GAPI_EXPORTS can_describe(const GMetaArgs& metas, const GRunArgs& args);
// Checks if run-time computation result argument can be described by metadata.
// Used to check if the metadata generated at compile time
// coincides with output arguments passed to computation in cpu and ocl backends
bool GAPI_EXPORTS can_describe(const GMetaArg& meta, const GRunArgP& argp);
} // namespace cv
#endif // OPENCV_GAPI_GPROTO_HPP

View File

@@ -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_GPU_CORE_API_HPP
#define OPENCV_GAPI_GPU_CORE_API_HPP
/** @file
* @deprecated Use <opencv2/gapi/ocl/core.hpp> instead.
*/
#include <opencv2/gapi/ocl/core.hpp>
namespace cv {
namespace gapi {
namespace core {
namespace gpu {
using namespace ocl;
} // namespace gpu
} // namespace core
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_GPU_CORE_API_HPP

View File

@@ -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
#ifndef OPENCV_GAPI_GGPUKERNEL_HPP
#define OPENCV_GAPI_GGPUKERNEL_HPP
/** @file
* @deprecated Use <opencv2/gapi/ocl/goclkernel.hpp> instead.
*/
#include <opencv2/gapi/ocl/goclkernel.hpp>
#define GAPI_GPU_KERNEL GAPI_OCL_KERNEL
#endif // OPENCV_GAPI_GGPUKERNEL_HPP

View File

@@ -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_GPU_IMGPROC_API_HPP
#define OPENCV_GAPI_GPU_IMGPROC_API_HPP
/** @file
* @deprecated Use <opencv2/gapi/ocl/imgproc.hpp> instead.
*/
#include <opencv2/gapi/ocl/imgproc.hpp>
namespace cv {
namespace gapi {
namespace imgproc {
namespace gpu {
using namespace ocl;
} // namespace gpu
} // namespace imgproc
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_GPU_IMGPROC_API_HPP

View File

@@ -0,0 +1,83 @@
// 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>
namespace cv
{
// Forward declaration; GNode and GOrigin are an internal
// (user-inaccessible) classes.
class GNode;
struct GOrigin;
/** \addtogroup gapi_data_objects
* @{
*/
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
#if !defined(GAPI_STANDALONE)
explicit GScalar(const cv::Scalar& s); // Constant value constructor from cv::Scalar
#endif // !defined(GAPI_STANDALONE)
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;
};
/** @} */
/**
* \addtogroup gapi_meta_args
* @{
*/
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(); }
#if !defined(GAPI_STANDALONE)
GAPI_EXPORTS GScalarDesc descr_of(const cv::Scalar &scalar);
#endif // !defined(GAPI_STANDALONE)
/** @} */
GAPI_EXPORTS GScalarDesc descr_of(const cv::gapi::own::Scalar &scalar);
std::ostream& operator<<(std::ostream& os, const cv::GScalarDesc &desc);
} // namespace cv
#endif // OPENCV_GAPI_GSCALAR_HPP

View File

@@ -0,0 +1,231 @@
// 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_GSTREAMING_COMPILED_HPP
#define OPENCV_GAPI_GSTREAMING_COMPILED_HPP
#include <vector>
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/own/assert.hpp>
#include <opencv2/gapi/garg.hpp>
#include <opencv2/gapi/streaming/source.hpp>
namespace cv {
/**
* \addtogroup gapi_main_classes
* @{
*/
/**
* @brief Represents a computation (graph) compiled for streaming.
*
* This class represents a product of graph compilation (calling
* cv::GComputation::compileStreaming()). Objects of this class
* actually do stream processing, and the whole pipeline execution
* complexity is incapsulated into objects of this class. Execution
* model has two levels: at the very top, the execution of a
* heterogeneous graph is aggressively pipelined; at the very bottom
* the execution of every internal block is determined by its
* associated backend. Backends are selected based on kernel packages
* passed via compilation arguments ( see @ref gapi_compile_args,
* GNetworkPackage, GKernelPackage for details).
*
* GStreamingCompiled objects have a "player" semantics -- there are
* methods like start() and stop(). GStreamingCompiled has a full
* control over a videostream and so is stateful. You need to specify the
* input stream data using setSource() and then call start() to
* actually start processing. After that, use pull() or try_pull() to
* obtain next processed data frame from the graph in a blocking or
* non-blocking way, respectively.
*
* Currently a single GStreamingCompiled can process only one video
* streat at time. Produce multiple GStreamingCompiled objects to run the
* same graph on multiple video streams.
*
* @sa GCompiled
*/
class GAPI_EXPORTS GStreamingCompiled
{
public:
class GAPI_EXPORTS Priv;
GStreamingCompiled();
// FIXME: More overloads?
/**
* @brief Specify the input data to GStreamingCompiled for
* processing, a generic version.
*
* Use gin() to create an input parameter vector.
*
* Input vectors must have the same number of elements as defined
* in the cv::GComputation protocol (at the moment of its
* construction). Shapes of elements also must conform to protocol
* (e.g. cv::Mat needs to be passed where cv::GMat has been
* declared as input, and so on). Run-time exception is generated
* on type mismatch.
*
* In contrast with regular GCompiled, user can also pass an
* object of type GVideoCapture for a GMat parameter of the parent
* GComputation. The compiled pipeline will start fetching data
* from that GVideoCapture and feeding it into the
* pipeline. Pipeline stops when a GVideoCapture marks end of the
* stream (or when stop() is called).
*
* Passing a regular Mat for a GMat parameter makes it "infinite"
* source -- pipeline may run forever feeding with this Mat until
* stopped explicitly.
*
* Currently only a single GVideoCapture is supported as input. If
* the parent GComputation is declared with multiple input GMat's,
* one of those can be specified as GVideoCapture but all others
* must be regular Mat objects.
*
* Throws if pipeline is already running. Use stop() and then
* setSource() to run the graph on a new video stream.
*
* @note This method is not thread-safe (with respect to the user
* side) at the moment. Protect the access if
* start()/stop()/setSource() may be called on the same object in
* multiple threads in your application.
*
* @param ins vector of inputs to process.
* @sa gin
*/
void setSource(GRunArgs &&ins);
/**
* @brief Specify an input video stream for a single-input
* computation pipeline.
*
* Throws if pipeline is already running. Use stop() and then
* setSource() to run the graph on a new video stream.
*
* @overload
* @param s a shared pointer to IStreamSource representing the
* input video stream.
*/
void setSource(const gapi::wip::IStreamSource::Ptr& s);
/**
* @brief Start the pipeline execution.
*
* Use pull()/try_pull() to obtain data. Throws an exception if
* a video source was not specified.
*
* setSource() must be called first, even if the pipeline has been
* working already and then stopped (explicitly via stop() or due
* stream completion)
*
* @note This method is not thread-safe (with respect to the user
* side) at the moment. Protect the access if
* start()/stop()/setSource() may be called on the same object in
* multiple threads in your application.
*/
void start();
/**
* @brief Get the next processed frame from the pipeline.
*
* Use gout() to create an output parameter vector.
*
* Output vectors must have the same number of elements as defined
* in the cv::GComputation protocol (at the moment of its
* construction). Shapes of elements also must conform to protocol
* (e.g. cv::Mat needs to be passed where cv::GMat has been
* declared as output, and so on). Run-time exception is generated
* on type mismatch.
*
* This method writes new data into objects passed via output
* vector. If there is no data ready yet, this method blocks. Use
* try_pull() if you need a non-blocking version.
*
* @param outs vector of output parameters to obtain.
* @return true if next result has been obtained,
* false marks end of the stream.
*/
bool pull(cv::GRunArgsP &&outs);
/**
* @brief Try to get the next processed frame from the pipeline.
*
* Use gout() to create an output parameter vector.
*
* This method writes new data into objects passed via output
* vector. If there is no data ready yet, the output vector
* remains unchanged and false is returned.
*
* @return true if data has been obtained, and false if it was
* not. Note: false here doesn't mark the end of the stream.
*/
bool try_pull(cv::GRunArgsP &&outs);
/**
* @brief Stop (abort) processing the pipeline.
*
* Note - it is not pause but a complete stop. Calling start()
* will cause G-API to start processing the stream from the early beginning.
*
* Throws if the pipeline is not running.
*/
void stop();
/**
* @brief Test if the pipeline is running.
*
* @note This method is not thread-safe (with respect to the user
* side) at the moment. Protect the access if
* start()/stop()/setSource() may be called on the same object in
* multiple threads in your application.
*
* @return true if the current stream is not over yet.
*/
bool running() const;
/// @private
Priv& priv();
/**
* @brief Check if compiled object is valid (non-empty)
*
* @return true if the object is runnable (valid), false otherwise
*/
explicit operator bool () const;
/**
* @brief Vector of metadata this graph was compiled for.
*
* @return Unless _reshape_ is not supported, return value is the
* same vector which was passed to cv::GComputation::compile() to
* produce this compiled object. Otherwise, it is the latest
* metadata vector passed to reshape() (if that call was
* successful).
*/
const GMetaArgs& metas() const; // Meta passed to compile()
/**
* @brief Vector of metadata descriptions of graph outputs
*
* @return vector with formats/resolutions of graph's output
* objects, auto-inferred from input metadata vector by
* operations which form this computation.
*
* @note GCompiled objects produced from the same
* cv::GComputiation graph with different input metas may return
* different values in this vector.
*/
const GMetaArgs& outMetas() const;
protected:
/// @private
std::shared_ptr<Priv> m_priv;
};
/** @} */
}
#endif // OPENCV_GAPI_GSTREAMING_COMPILED_HPP

View File

@@ -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) 2019 Intel Corporation
#ifndef OPENCV_GAPI_GTRANSFORM_HPP
#define OPENCV_GAPI_GTRANSFORM_HPP
#include <functional>
#include <type_traits>
#include <utility>
#include <opencv2/gapi/gcommon.hpp>
#include <opencv2/gapi/util/util.hpp>
#include <opencv2/gapi/garg.hpp>
#include <opencv2/gapi/gtype_traits.hpp>
#include <opencv2/gapi/util/compiler_hints.hpp>
#include <opencv2/gapi/gcomputation.hpp>
namespace cv
{
struct GAPI_EXPORTS GTransform
{
// FIXME: consider another simplified
// class instead of GComputation
using F = std::function<GComputation()>;
std::string description;
F pattern;
F substitute;
GTransform(const std::string& d, const F &p, const F &s) : description(d), pattern(p), substitute(s){};
};
namespace detail
{
template <typename, typename, typename>
struct TransHelper;
template <typename K, typename... Ins, typename Out>
struct TransHelper<K, std::tuple<Ins...>, Out>
{
template <typename Callable, int... IIs, int... OIs>
static GComputation invoke(Callable f, Seq<IIs...>, Seq<OIs...>)
{
const std::tuple<Ins...> ins;
const auto r = tuple_wrap_helper<Out>::get(f(std::get<IIs>(ins)...));
return GComputation(cv::GIn(std::get<IIs>(ins)...),
cv::GOut(std::get<OIs>(r)...));
}
static GComputation get_pattern()
{
return invoke(K::pattern, typename MkSeq<sizeof...(Ins)>::type(),
typename MkSeq<std::tuple_size<typename tuple_wrap_helper<Out>::type>::value>::type());
}
static GComputation get_substitute()
{
return invoke(K::substitute, typename MkSeq<sizeof...(Ins)>::type(),
typename MkSeq<std::tuple_size<typename tuple_wrap_helper<Out>::type>::value>::type());
}
};
} // namespace detail
template <typename, typename>
class GTransformImpl;
template <typename K, typename R, typename... Args>
class GTransformImpl<K, std::function<R(Args...)>> : public cv::detail::TransHelper<K, std::tuple<Args...>, R>,
public cv::detail::TransformTag
{
public:
// FIXME: currently there is no check that transformations' signatures are unique
// and won't be any intersection in graph compilation stage
using API = K;
static GTransform transformation()
{
return GTransform(K::descr(), &K::get_pattern, &K::get_substitute);
}
};
} // namespace cv
#define G_DESCR_HELPER_CLASS(Class) Class##DescrHelper
#define G_DESCR_HELPER_BODY(Class, Descr) \
namespace detail \
{ \
struct G_DESCR_HELPER_CLASS(Class) \
{ \
static constexpr const char *descr() { return Descr; }; \
}; \
}
#define GAPI_TRANSFORM(Class, API, Descr) \
G_DESCR_HELPER_BODY(Class, Descr) \
struct Class final : public cv::GTransformImpl<Class, std::function API>, \
public detail::G_DESCR_HELPER_CLASS(Class)
#endif // OPENCV_GAPI_GTRANSFORM_HPP

View File

@@ -0,0 +1,171 @@
// 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/streaming/source.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_VAL, // Unknown, generic, opaque-to-GAPI data type - STATIC
// Note: OPAQUE is sometimes defined in Win sys headers
#if !defined(OPAQUE) && !defined(CV_DOXYGEN)
OPAQUE = OPAQUE_VAL, // deprecated value used for compatibility, use OPAQUE_VAL instead
#endif
GOBJREF, // <internal> reference to object
GMAT, // a cv::GMat
GMATP, // a cv::GMatP
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_VAL;
};
template<> struct GTypeTraits<cv::GMat>
{
static constexpr const ArgKind kind = ArgKind::GMAT;
static constexpr const GShape shape = GShape::GMAT;
};
template<> struct GTypeTraits<cv::GMatP>
{
static constexpr const ArgKind kind = ArgKind::GMATP;
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
// FIXME: GMatP is not present here.
// (Actually these traits is used only to check
// if associated G-type has custom wrap functions
// and GMat behavior is correct for GMatP)
template<typename T> struct GTypeOf;
#if !defined(GAPI_STANDALONE)
template<> struct GTypeOf<cv::Mat> { using type = cv::GMat; };
template<> struct GTypeOf<cv::UMat> { using type = cv::GMat; };
template<> struct GTypeOf<cv::Scalar> { using type = cv::GScalar; };
#endif // !defined(GAPI_STANDALONE)
template<> struct GTypeOf<cv::gapi::own::Mat> { using type = cv::GMat; };
template<> struct GTypeOf<cv::gapi::own::Scalar> { using type = cv::GScalar; };
template<typename U> struct GTypeOf<std::vector<U> > { using type = cv::GArray<U>; };
// FIXME: This is not quite correct since IStreamSource may produce not only Mat but also Scalar
// and vector data. TODO: Extend the type dispatchig on these types too.
template<> struct GTypeOf<cv::gapi::wip::IStreamSource::Ptr> { using type = cv::GMat;};
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

View File

@@ -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
#ifndef OPENCV_GAPI_GTYPED_HPP
#define OPENCV_GAPI_GTYPED_HPP
#if !defined(GAPI_STANDALONE)
#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
/**
* @brief This class is a typed wrapper over a regular GComputation.
*
* `std::function<>`-like template parameter specifies the graph
* signature so methods so the object's constructor, methods like
* `apply()` and the derived `GCompiledT::operator()` also become
* typed.
*
* There is no need to use cv::gin() or cv::gout() modifiers with
* objects of this class. Instead, all input arguments are followed
* by all output arguments in the order from the template argument
* signature.
*
* Refer to the following example. Regular (untyped) code is written this way:
*
* @snippet modules/gapi/samples/api_ref_snippets.cpp Untyped_Example
*
* Here:
*
* - cv::GComputation object is created with a lambda constructor
* where it is defined as a two-input, one-output graph.
*
* - Its method `apply()` in fact takes arbitrary number of arguments
* (as vectors) so user can pass wrong number of inputs/outputs
* here. C++ compiler wouldn't notice that since the cv::GComputation
* API is polymorphic, and only a run-time error will be generated.
*
* Now the same code written with typed API:
*
* @snippet modules/gapi/samples/api_ref_snippets.cpp Typed_Example
*
* The key difference is:
*
* - Now the constructor lambda *must take* parameters and *must
* return* values as defined in the `GComputationT<>` signature.
* - Its method `apply()` does not require any extra specifiers to
* separate input arguments from the output ones
* - A `GCompiledT` (compilation product) takes input/output
* arguments with no extra specifiers as well.
*/
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 // !defined(GAPI_STANDALONE)
#endif // OPENCV_GAPI_GTYPED_HPP

View File

@@ -0,0 +1,919 @@
// 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 GMat2 = std::tuple<GMat,GMat>;
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_M(GSobelXY, <GMat2(GMat,int,int,int,double,double,int,Scalar)>, "org.opencv.imgproc.filters.sobelxy") {
static std::tuple<GMatDesc, GMatDesc> outMeta(GMatDesc in, int ddepth, int, int, double, double, int, Scalar) {
return std::make_tuple(in.withDepth(ddepth), 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(GNV12toRGB, <GMat(GMat, GMat)>, "org.opencv.imgproc.colorconvert.nv12torgb") {
static GMatDesc outMeta(GMatDesc in_y, GMatDesc in_uv) {
GAPI_Assert(in_y.chan == 1);
GAPI_Assert(in_uv.chan == 2);
GAPI_Assert(in_y.depth == CV_8U);
GAPI_Assert(in_uv.depth == CV_8U);
// UV size should be aligned with Y
GAPI_Assert(in_y.size.width == 2 * in_uv.size.width);
GAPI_Assert(in_y.size.height == 2 * in_uv.size.height);
return in_y.withType(CV_8U, 3); // type will be CV_8UC3;
}
};
G_TYPED_KERNEL(GNV12toBGR, <GMat(GMat, GMat)>, "org.opencv.imgproc.colorconvert.nv12tobgr") {
static GMatDesc outMeta(GMatDesc in_y, GMatDesc in_uv) {
GAPI_Assert(in_y.chan == 1);
GAPI_Assert(in_uv.chan == 2);
GAPI_Assert(in_y.depth == CV_8U);
GAPI_Assert(in_uv.depth == CV_8U);
// UV size should be aligned with Y
GAPI_Assert(in_y.size.width == 2 * in_uv.size.width);
GAPI_Assert(in_y.size.height == 2 * in_uv.size.height);
return in_y.withType(CV_8U, 3); // type will be 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);
}
};
G_TYPED_KERNEL(GBayerGR2RGB, <cv::GMat(cv::GMat)>, "org.opencv.imgproc.colorconvert.bayergr2rgb") {
static cv::GMatDesc outMeta(cv::GMatDesc in) {
return in.withType(CV_8U, 3);
}
};
G_TYPED_KERNEL(GRGB2HSV, <cv::GMat(cv::GMat)>, "org.opencv.imgproc.colorconvert.rgb2hsv") {
static cv::GMatDesc outMeta(cv::GMatDesc in) {
return in;
}
};
G_TYPED_KERNEL(GRGB2YUV422, <cv::GMat(cv::GMat)>, "org.opencv.imgproc.colorconvert.rgb2yuv422") {
static cv::GMatDesc outMeta(cv::GMatDesc in) {
GAPI_Assert(in.depth == CV_8U);
GAPI_Assert(in.chan == 3);
return in.withType(in.depth, 2);
}
};
G_TYPED_KERNEL(GNV12toRGBp, <GMatP(GMat,GMat)>, "org.opencv.colorconvert.imgproc.nv12torgbp") {
static GMatDesc outMeta(GMatDesc inY, GMatDesc inUV) {
GAPI_Assert(inY.depth == CV_8U);
GAPI_Assert(inUV.depth == CV_8U);
GAPI_Assert(inY.chan == 1);
GAPI_Assert(inY.planar == false);
GAPI_Assert(inUV.chan == 2);
GAPI_Assert(inUV.planar == false);
GAPI_Assert(inY.size.width == 2 * inUV.size.width);
GAPI_Assert(inY.size.height == 2 * inUV.size.height);
return inY.withType(CV_8U, 3).asPlanar();
}
};
G_TYPED_KERNEL(GNV12toBGRp, <GMatP(GMat,GMat)>, "org.opencv.colorconvert.imgproc.nv12tobgrp") {
static GMatDesc outMeta(GMatDesc inY, GMatDesc inUV) {
GAPI_Assert(inY.depth == CV_8U);
GAPI_Assert(inUV.depth == CV_8U);
GAPI_Assert(inY.chan == 1);
GAPI_Assert(inY.planar == false);
GAPI_Assert(inUV.chan == 2);
GAPI_Assert(inUV.planar == false);
GAPI_Assert(inY.size.width == 2 * inUV.size.width);
GAPI_Assert(inY.size.height == 2 * inUV.size.height);
return inY.withType(CV_8U, 3).asPlanar();
}
};
}
//! @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 = FILTER_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 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 = FILTER_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 First returned matrix correspons to dx derivative while the second one to dy.
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
@note Function textual ID is "org.opencv.imgproc.filters.sobelxy"
@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 order order of the derivatives.
@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 std::tuple<GMat, GMat> SobelXY(const GMat& src, int ddepth, int order, 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);
/** @brief Converts an image from NV12 (YUV420p) color space to RGB.
The function converts an input image from NV12 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.nv12torgb"
@param src_y input image: 8-bit unsigned 1-channel image @ref CV_8UC1.
@param src_uv input image: 8-bit unsigned 2-channel image @ref CV_8UC2.
@sa YUV2RGB, NV12toBGR
*/
GAPI_EXPORTS GMat NV12toRGB(const GMat& src_y, const GMat& src_uv);
/** @brief Converts an image from NV12 (YUV420p) color space to BGR.
The function converts an input image from NV12 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.nv12tobgr"
@param src_y input image: 8-bit unsigned 1-channel image @ref CV_8UC1.
@param src_uv input image: 8-bit unsigned 2-channel image @ref CV_8UC2.
@sa YUV2BGR, NV12toRGB
*/
GAPI_EXPORTS GMat NV12toBGR(const GMat& src_y, const GMat& src_uv);
/** @brief Converts an image from BayerGR color space to RGB.
The function converts an input image from BayerGR color space to RGB.
The conventional ranges for G, R, and B 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.bayergr2rgb"
@param src_gr input image: 8-bit unsigned 1-channel image @ref CV_8UC1.
@sa YUV2BGR, NV12toRGB
*/
GAPI_EXPORTS GMat BayerGR2RGB(const GMat& src_gr);
/** @brief Converts an image from RGB color space to HSV.
The function converts an input image from RGB color space to HSV.
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_8UC3.
@note Function textual ID is "org.opencv.imgproc.colorconvert.rgb2hsv"
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3.
@sa YUV2BGR, NV12toRGB
*/
GAPI_EXPORTS GMat RGB2HSV(const GMat& src);
/** @brief Converts an image from RGB color space to YUV422.
The function converts an input image from RGB color space to YUV422.
The conventional ranges for R, G, and B channel values are 0 to 255.
Output image must be 8-bit unsigned 2-channel image @ref CV_8UC2.
@note Function textual ID is "org.opencv.imgproc.colorconvert.rgb2yuv422"
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3.
@sa YUV2BGR, NV12toRGB
*/
GAPI_EXPORTS GMat RGB2YUV422(const GMat& src);
/** @brief Converts an image from NV12 (YUV420p) color space to RGB.
The function converts an input image from NV12 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 planar 3-channel image @ref CV_8UC1.
Planar image memory layout is three planes laying in the memory contiguously,
so the image height should be plane_height*plane_number,
image type is @ref CV_8UC1.
@note Function textual ID is "org.opencv.imgproc.colorconvert.nv12torgbp"
@param src_y input image: 8-bit unsigned 1-channel image @ref CV_8UC1.
@param src_uv input image: 8-bit unsigned 2-channel image @ref CV_8UC2.
@sa YUV2RGB, NV12toBGRp, NV12toRGB
*/
GAPI_EXPORTS GMatP NV12toRGBp(const GMat &src_y, const GMat &src_uv);
/** @brief Converts an image from NV12 (YUV420p) color space to BGR.
The function converts an input image from NV12 color space to BGR.
The conventional ranges for Y, U, and V channel values are 0 to 255.
Output image must be 8-bit unsigned planar 3-channel image @ref CV_8UC1.
Planar image memory layout is three planes laying in the memory contiguously,
so the image height should be plane_height*plane_number,
image type is @ref CV_8UC1.
@note Function textual ID is "org.opencv.imgproc.colorconvert.nv12torgbp"
@param src_y input image: 8-bit unsigned 1-channel image @ref CV_8UC1.
@param src_uv input image: 8-bit unsigned 2-channel image @ref CV_8UC2.
@sa YUV2RGB, NV12toRGBp, NV12toBGR
*/
GAPI_EXPORTS GMatP NV12toBGRp(const GMat &src_y, const GMat &src_uv);
//! @} gapi_colorconvert
} //namespace gapi
} //namespace cv
#endif // OPENCV_GAPI_IMGPROC_HPP

View File

@@ -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) 2019 Intel Corporation
#ifndef OPENCV_GAPI_INFER_HPP
#define OPENCV_GAPI_INFER_HPP
// FIXME: Inference API is currently only available in full mode
#if !defined(GAPI_STANDALONE)
#include <functional>
#include <string> // string
#include <utility> // tuple
#include <opencv2/gapi/util/any.hpp> // any<>
#include <opencv2/gapi/gkernel.hpp> // GKernelType[M], GBackend
#include <opencv2/gapi/garg.hpp> // GArg
#include <opencv2/gapi/gcommon.hpp> // CompileArgTag
#include <opencv2/gapi/gmetaarg.hpp> // GMetaArg
namespace cv {
namespace detail {
// This tiny class eliminates the semantic difference between
// GKernelType and GKernelTypeM.
// FIXME: Something similar can be reused for regular kernels
template<typename, typename>
struct KernelTypeMedium;
template<class K, typename... R, typename... Args>
struct KernelTypeMedium<K, std::function<std::tuple<R...>(Args...)> >:
public GKernelTypeM<K, std::function<std::tuple<R...>(Args...)> > {};
template<class K, typename R, typename... Args>
struct KernelTypeMedium<K, std::function<R(Args...)> >:
public GKernelType<K, std::function<R(Args...)> > {};
} // namespace detail
template<typename, typename> class GNetworkType;
// TODO: maybe tuple_wrap_helper from util.hpp may help with this.
// Multiple-return-value network definition (specialized base class)
template<typename K, typename... R, typename... Args>
class GNetworkType<K, std::function<std::tuple<R...>(Args...)> >
{
public:
using InArgs = std::tuple<Args...>;
using OutArgs = std::tuple<R...>;
using Result = OutArgs;
using API = std::function<Result(Args...)>;
using ResultL = std::tuple< cv::GArray<R>... >;
using APIList = std::function<ResultL(cv::GArray<cv::Rect>, Args...)>;
};
// Single-return-value network definition (specialized base class)
template<typename K, typename R, typename... Args>
class GNetworkType<K, std::function<R(Args...)> >
{
public:
using InArgs = std::tuple<Args...>;
using OutArgs = std::tuple<R>;
using Result = R;
using API = std::function<R(Args...)>;
using ResultL = cv::GArray<R>;
using APIList = std::function<ResultL(cv::GArray<cv::Rect>, Args...)>;
};
// Base "Infer" kernel. Note - for whatever network, kernel ID
// is always the same. Different inference calls are distinguished by
// network _tag_ (an extra field in GCall)
//
// getOutMeta is a stub callback collected by G-API kernel subsystem
// automatically. This is a rare case when this callback is defined by
// a particular backend, not by a network itself.
struct GInferBase {
static constexpr const char * id() {
return "org.opencv.dnn.infer"; // Universal stub
}
static GMetaArgs getOutMeta(const GMetaArgs &, const GArgs &) {
return GMetaArgs{}; // One more universal stub
}
};
// Base "Infer list" kernel.
// All notes from "Infer" kernel apply here as well.
struct GInferListBase {
static constexpr const char * id() {
return "org.opencv.dnn.infer-roi"; // Universal stub
}
static GMetaArgs getOutMeta(const GMetaArgs &, const GArgs &) {
return GMetaArgs{}; // One more universal stub
}
};
// A generic inference kernel. API (::on()) is fully defined by the Net
// template parameter.
// Acts as a regular kernel in graph (via KernelTypeMedium).
template<typename Net>
struct GInfer final
: public GInferBase
, public detail::KernelTypeMedium< GInfer<Net>
, typename Net::API > {
using GInferBase::getOutMeta; // FIXME: name lookup conflict workaround?
static constexpr const char* tag() { return Net::tag(); }
};
// A generic roi-list inference kernel. API (::on()) is derived from
// the Net template parameter (see more in infer<> overload).
template<typename Net>
struct GInferList final
: public GInferListBase
, public detail::KernelTypeMedium< GInferList<Net>
, typename Net::APIList > {
using GInferListBase::getOutMeta; // FIXME: name lookup conflict workaround?
static constexpr const char* tag() { return Net::tag(); }
};
} // namespace cv
// FIXME: Probably the <API> signature makes a function/tuple/function round-trip
#define G_API_NET(Class, API, Tag) \
struct Class final: public cv::GNetworkType<Class, std::function API> { \
static constexpr const char * tag() { return Tag; } \
}
namespace cv {
namespace gapi {
/** @brief Calculates responses for the specified network (template
* parameter) for every region in the source image.
*
* @tparam A network type defined with G_API_NET() macro.
* @param roi a list of rectangles describing regions of interest
* in the source image. Usually an output of object detector or tracker.
* @param args network's input parameters as specified in G_API_NET() macro.
* NOTE: verified to work reliably with 1-input topologies only.
* @return a list of objects of return type as defined in G_API_NET().
* If a network has multiple return values (defined with a tuple), a tuple of
* GArray<> objects is returned with the appropriate types inside.
* @sa G_API_NET()
*/
template<typename Net, typename... Args>
typename Net::ResultL infer(cv::GArray<cv::Rect> roi, Args&&... args) {
return GInferList<Net>::on(roi, std::forward<Args>(args)...);
}
/**
* @brief Calculates response for the specified network (template
* parameter) given the input data.
*
* @tparam A network type defined with G_API_NET() macro.
* @param args network's input parameters as specified in G_API_NET() macro.
* @return an object of return type as defined in G_API_NET().
* If a network has multiple return values (defined with a tuple), a tuple of
* objects of appropriate type is returned.
* @sa G_API_NET()
*/
template<typename Net, typename... Args>
typename Net::Result infer(Args&&... args) {
return GInfer<Net>::on(std::forward<Args>(args)...);
}
} // namespace gapi
} // namespace cv
#endif // GAPI_STANDALONE
namespace cv {
namespace gapi {
// Note: the below code _is_ part of STANDALONE build,
// just to make our compiler code compileable.
// A type-erased form of network parameters.
// Similar to how a type-erased GKernel is represented and used.
struct GAPI_EXPORTS GNetParam {
std::string tag; // FIXME: const?
GBackend backend; // Specifies the execution model
util::any params; // Backend-interpreted parameter structure
};
/** \addtogroup gapi_compile_args
* @{
*/
/**
* @brief A container class for network configurations. Similar to
* GKernelPackage.Use cv::gapi::networks() to construct this object.
*
* @sa cv::gapi::networks
*/
struct GAPI_EXPORTS GNetPackage {
GNetPackage() : GNetPackage({}) {}
explicit GNetPackage(std::initializer_list<GNetParam> &&ii);
std::vector<GBackend> backends() const;
std::vector<GNetParam> networks;
};
/** @} gapi_compile_args */
} // namespace gapi
namespace detail {
template<typename T>
gapi::GNetParam strip(T&& t) {
return gapi::GNetParam { t.tag()
, t.backend()
, t.params()
};
}
template<> struct CompileArgTag<cv::gapi::GNetPackage> {
static const char* tag() { return "gapi.net_package"; }
};
} // namespace cv::detail
namespace gapi {
template<typename... Args>
cv::gapi::GNetPackage networks(Args&&... args) {
return cv::gapi::GNetPackage({ cv::detail::strip(args)... });
}
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_INFER_HPP

View File

@@ -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) 2019 Intel Corporation
#ifndef OPENCV_GAPI_INFER_IE_HPP
#define OPENCV_GAPI_INFER_IE_HPP
#include <unordered_map>
#include <string>
#include <array>
#include <tuple> // tuple, tuple_size
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/util/any.hpp>
#include <opencv2/core/cvdef.h> // GAPI_EXPORTS
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
namespace cv {
namespace gapi {
// FIXME: introduce a new sub-namespace for NN?
namespace ie {
GAPI_EXPORTS cv::gapi::GBackend backend();
/**
* Specify how G-API and IE should trait input data
*
* In OpenCV, the same cv::Mat is used to represent both
* image and tensor data. Sometimes those are hardly distinguishable,
* so this extra parameter is used to give G-API a hint.
*
* This hint controls how G-API reinterprets the data when converting
* it to IE Blob format (and which layout/etc is assigned to this data).
*/
enum class TraitAs: int
{
TENSOR, //!< G-API traits an associated cv::Mat as a raw tensor and passes dimensions as-is
IMAGE //!< G-API traits an associated cv::Mat as an image so creates an "image" blob (NCHW/NHWC, etc)
};
namespace detail {
struct ParamDesc {
std::string model_path;
std::string weights_path;
std::string device_id;
// NB: Here order follows the `Net` API
std::vector<std::string> input_names;
std::vector<std::string> output_names;
using ConstInput = std::pair<cv::Mat, TraitAs>;
std::unordered_map<std::string, ConstInput> const_inputs;
// NB: nun_* may differ from topology's real input/output port numbers
// (e.g. topology's partial execution)
std::size_t num_in; // How many inputs are defined in the operation
std::size_t num_out; // How many outputs are defined in the operation
};
} // namespace detail
// FIXME: this is probably a shared (reusable) thing
template<typename Net>
struct PortCfg {
using In = std::array
< std::string
, std::tuple_size<typename Net::InArgs>::value >;
using Out = std::array
< std::string
, std::tuple_size<typename Net::OutArgs>::value >;
};
template<typename Net> class Params {
public:
Params(const std::string &model,
const std::string &weights,
const std::string &device)
: desc{ model, weights, device, {}, {}, {}
, std::tuple_size<typename Net::InArgs>::value
, std::tuple_size<typename Net::OutArgs>::value
} {
};
Params<Net>& cfgInputLayers(const typename PortCfg<Net>::In &ll) {
desc.input_names.clear();
desc.input_names.reserve(ll.size());
std::copy(ll.begin(), ll.end(),
std::back_inserter(desc.input_names));
return *this;
}
Params<Net>& cfgOutputLayers(const typename PortCfg<Net>::Out &ll) {
desc.output_names.clear();
desc.output_names.reserve(ll.size());
std::copy(ll.begin(), ll.end(),
std::back_inserter(desc.output_names));
return *this;
}
Params<Net>& constInput(const std::string &layer_name,
const cv::Mat &data,
TraitAs hint = TraitAs::TENSOR) {
desc.const_inputs[layer_name] = {data, hint};
return *this;
}
// BEGIN(G-API's network parametrization API)
GBackend backend() const { return cv::gapi::ie::backend(); }
std::string tag() const { return Net::tag(); }
cv::util::any params() const { return { desc }; }
// END(G-API's network parametrization API)
protected:
detail::ParamDesc desc;
};
} // namespace ie
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_INFER_HPP

View File

@@ -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_OCL_CORE_API_HPP
#define OPENCV_GAPI_OCL_CORE_API_HPP
#include <opencv2/core/cvdef.h> // GAPI_EXPORTS
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
namespace cv {
namespace gapi {
namespace core {
namespace ocl {
GAPI_EXPORTS GKernelPackage kernels();
} // namespace ocl
} // namespace core
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_OCL_CORE_API_HPP

View File

@@ -0,0 +1,246 @@
// 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-2019 Intel Corporation
#ifndef OPENCV_GAPI_GOCLKERNEL_HPP
#define OPENCV_GAPI_GOCLKERNEL_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>
// FIXME: namespace scheme for backends?
namespace cv {
namespace gimpl
{
// Forward-declare an internal class
class GOCLExecutable;
} // namespace gimpl
namespace gapi
{
namespace ocl
{
/**
* \addtogroup gapi_std_backends G-API Standard Backends
* @{
*/
/**
* @brief Get a reference to OCL backend.
*
* At the moment, the OCL backend is built atop of OpenCV
* "Transparent API" (T-API), see cv::UMat for details.
*
* @sa gapi_std_backends
*/
GAPI_EXPORTS cv::gapi::GBackend backend();
/** @} */
} // namespace ocl
} // namespace gapi
// Represents arguments which are passed to a wrapped OCL function
// FIXME: put into detail?
class GAPI_EXPORTS GOCLContext
{
public:
// Generic accessor API
template<typename T>
const T& inArg(int input) { return m_args.at(input).get<T>(); }
// Syntax sugar
const cv::UMat& inMat(int input);
cv::UMat& outMatR(int output); // FIXME: Avoid cv::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;
std::unordered_map<std::size_t, GRunArgP> m_results;
friend class gimpl::GOCLExecutable;
};
class GAPI_EXPORTS GOCLKernel
{
public:
// This function is kernel's execution entry point (does the processing work)
using F = std::function<void(GOCLContext &)>;
GOCLKernel();
explicit GOCLKernel(const F& f);
void apply(GOCLContext &ctx);
protected:
F m_f;
};
// FIXME: This is an ugly ad-hoc imlpementation. TODO: refactor
namespace detail
{
template<class T> struct ocl_get_in;
template<> struct ocl_get_in<cv::GMat>
{
static cv::UMat get(GOCLContext &ctx, int idx) { return ctx.inMat(idx); }
};
template<> struct ocl_get_in<cv::GScalar>
{
static cv::Scalar get(GOCLContext &ctx, int idx) { return to_ocv(ctx.inVal(idx)); }
};
template<typename U> struct ocl_get_in<cv::GArray<U> >
{
static const std::vector<U>& get(GOCLContext &ctx, int idx) { return ctx.inArg<VectorRef>(idx).rref<U>(); }
};
template<class T> struct ocl_get_in
{
static T get(GOCLContext &ctx, int idx) { return ctx.inArg<T>(idx); }
};
struct tracked_cv_umat{
//TODO Think if T - API could reallocate UMat to a proper size - how do we handle this ?
//tracked_cv_umat(cv::UMat& m) : r{(m)}, original_data{m.getMat(ACCESS_RW).data} {}
tracked_cv_umat(cv::UMat& m) : r(m), original_data{ nullptr } {}
cv::UMat &r; // FIXME: It was a value (not a reference) before.
// Actually OCL backend should allocate its internal data!
uchar* original_data;
operator cv::UMat& (){ return r;}
void validate() const{
//if (r.getMat(ACCESS_RW).data != original_data)
//{
// util::throw_error
// (std::logic_error
// ("OpenCV kernel output parameter was reallocated. \n"
// "Incorrect meta data was provided ?"));
//}
}
};
struct scalar_wrapper_ocl
{
//FIXME reuse CPU (OpenCV) plugin code
scalar_wrapper_ocl(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_ocl(Outputs&... outs)
{
struct
{
void operator()(tracked_cv_umat* bm) { bm->validate(); }
void operator()(scalar_wrapper_ocl* 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 ocl_get_out;
template<> struct ocl_get_out<cv::GMat>
{
static tracked_cv_umat get(GOCLContext &ctx, int idx)
{
auto& r = ctx.outMatR(idx);
return{ r };
}
};
template<> struct ocl_get_out<cv::GScalar>
{
static scalar_wrapper_ocl get(GOCLContext &ctx, int idx)
{
auto& s = ctx.outValR(idx);
return{ s };
}
};
template<typename U> struct ocl_get_out<cv::GArray<U> >
{
static std::vector<U>& get(GOCLContext &ctx, int idx) { return ctx.outVecR<U>(idx); }
};
template<typename, typename, typename>
struct OCLCallHelper;
// FIXME: probably can be simplified with std::apply or analogue.
template<typename Impl, typename... Ins, typename... Outs>
struct OCLCallHelper<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 trying to bind rvalue references to lvalue references
Impl::run(std::forward<Inputs>(ins)..., outs...);
postprocess_ocl(outs...);
}
};
template<int... IIs, int... OIs>
static void call_impl(GOCLContext &ctx, detail::Seq<IIs...>, detail::Seq<OIs...>)
{
//TODO: Make sure that OpenCV kernels do not reallocate memory for output parameters
//by comparing it's state (data ptr) before and after the call.
//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(ocl_get_in<Ins>::get(ctx, IIs))...>::call(ocl_get_in<Ins>::get(ctx, IIs)..., ocl_get_out<Outs>::get(ctx, OIs)...);
}
static void call(GOCLContext &ctx)
{
call_impl(ctx,
typename detail::MkSeq<sizeof...(Ins)>::type(),
typename detail::MkSeq<sizeof...(Outs)>::type());
}
};
} // namespace detail
template<class Impl, class K>
class GOCLKernelImpl: public cv::detail::OCLCallHelper<Impl, typename K::InArgs, typename K::OutArgs>,
public cv::detail::KernelTag
{
using P = detail::OCLCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
public:
using API = K;
static cv::gapi::GBackend backend() { return cv::gapi::ocl::backend(); }
static cv::GOCLKernel kernel() { return GOCLKernel(&P::call); }
};
#define GAPI_OCL_KERNEL(Name, API) struct Name: public cv::GOCLKernelImpl<Name, API>
} // namespace cv
#endif // OPENCV_GAPI_GOCLKERNEL_HPP

View File

@@ -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_OCL_IMGPROC_API_HPP
#define OPENCV_GAPI_OCL_IMGPROC_API_HPP
#include <opencv2/core/cvdef.h> // GAPI_EXPORTS
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
namespace cv {
namespace gapi {
namespace imgproc {
namespace ocl {
GAPI_EXPORTS GKernelPackage kernels();
} // namespace ocl
} // namespace imgproc
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_OCL_IMGPROC_API_HPP

View File

@@ -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_OPENCV_INCLUDES_HPP
#define OPENCV_GAPI_OPENCV_INCLUDES_HPP
#if !defined(GAPI_STANDALONE)
# include <opencv2/core/mat.hpp>
# include <opencv2/core/cvdef.h>
# include <opencv2/core/types.hpp>
# include <opencv2/core/base.hpp>
#else // Without OpenCV
# include <opencv2/gapi/own/cvdefs.hpp>
#endif // !defined(GAPI_STANDALONE)
#endif // OPENCV_GAPI_OPENCV_INCLUDES_HPP

View File

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

View File

@@ -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
#ifndef OPENCV_GAPI_OWN_ASSERT_HPP
#define OPENCV_GAPI_OWN_ASSERT_HPP
#if !defined(GAPI_STANDALONE)
#include <opencv2/core/base.hpp>
#define GAPI_Assert CV_Assert
#define GAPI_DbgAssert CV_DbgAssert
#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__); }
#ifdef NDEBUG
# define GAPI_DbgAssert(expr)
#else
# define GAPI_DbgAssert(expr) GAPI_Assert(expr)
#endif
#endif // GAPI_STANDALONE
#endif // OPENCV_GAPI_OWN_ASSERT_HPP

View File

@@ -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_OWN_CONVERT_HPP
#define OPENCV_GAPI_OWN_CONVERT_HPP
#if !defined(GAPI_STANDALONE)
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/own/types.hpp>
#include <opencv2/gapi/own/mat.hpp>
#include <opencv2/gapi/own/scalar.hpp>
namespace cv
{
template<typename T>
std::vector<T> to_own(const cv::MatSize &sz) {
std::vector<T> result(sz.dims());
for (int i = 0; i < sz.dims(); i++) {
// Note: cv::MatSize is not iterable
result[i] = static_cast<T>(sz[i]);
}
return result;
}
cv::gapi::own::Mat to_own(Mat&&) = delete;
inline cv::gapi::own::Mat to_own(Mat const& m) {
return (m.dims == 2)
? cv::gapi::own::Mat{m.rows, m.cols, m.type(), m.data, m.step}
: cv::gapi::own::Mat{to_own<int>(m.size), m.type(), m.data};
};
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.dims.empty()
? cv::Mat{m.rows, m.cols, m.type(), m.data, m.step}
: cv::Mat{m.dims, m.type(), m.data};
}
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 // !defined(GAPI_STANDALONE)
#endif // OPENCV_GAPI_OWN_CONVERT_HPP

View File

@@ -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_CV_DEFS_HPP
#define OPENCV_GAPI_CV_DEFS_HPP
#if defined(GAPI_STANDALONE)
// Simulate OpenCV definitions taken from various
// OpenCV interface headers if G-API is built in a
// standalone mode.
// interface.h:
typedef unsigned char uchar;
typedef char schar;
typedef unsigned short ushort;
#define CV_CN_MAX 512
#define CV_CN_SHIFT 3
#define CV_DEPTH_MAX (1 << CV_CN_SHIFT)
#define CV_8U 0
#define CV_8S 1
#define CV_16U 2
#define CV_16S 3
#define CV_32S 4
#define CV_32F 5
#define CV_64F 6
#define CV_USRTYPE1 7
#define CV_MAT_DEPTH_MASK (CV_DEPTH_MAX - 1)
#define CV_MAT_DEPTH(flags) ((flags) & CV_MAT_DEPTH_MASK)
#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT))
#define CV_MAKE_TYPE CV_MAKETYPE
#define CV_8UC1 CV_MAKETYPE(CV_8U,1)
#define CV_8UC2 CV_MAKETYPE(CV_8U,2)
#define CV_8UC3 CV_MAKETYPE(CV_8U,3)
#define CV_8UC4 CV_MAKETYPE(CV_8U,4)
#define CV_8UC(n) CV_MAKETYPE(CV_8U,(n))
#define CV_8SC1 CV_MAKETYPE(CV_8S,1)
#define CV_8SC2 CV_MAKETYPE(CV_8S,2)
#define CV_8SC3 CV_MAKETYPE(CV_8S,3)
#define CV_8SC4 CV_MAKETYPE(CV_8S,4)
#define CV_8SC(n) CV_MAKETYPE(CV_8S,(n))
#define CV_16UC1 CV_MAKETYPE(CV_16U,1)
#define CV_16UC2 CV_MAKETYPE(CV_16U,2)
#define CV_16UC3 CV_MAKETYPE(CV_16U,3)
#define CV_16UC4 CV_MAKETYPE(CV_16U,4)
#define CV_16UC(n) CV_MAKETYPE(CV_16U,(n))
#define CV_16SC1 CV_MAKETYPE(CV_16S,1)
#define CV_16SC2 CV_MAKETYPE(CV_16S,2)
#define CV_16SC3 CV_MAKETYPE(CV_16S,3)
#define CV_16SC4 CV_MAKETYPE(CV_16S,4)
#define CV_16SC(n) CV_MAKETYPE(CV_16S,(n))
#define CV_32SC1 CV_MAKETYPE(CV_32S,1)
#define CV_32SC2 CV_MAKETYPE(CV_32S,2)
#define CV_32SC3 CV_MAKETYPE(CV_32S,3)
#define CV_32SC4 CV_MAKETYPE(CV_32S,4)
#define CV_32SC(n) CV_MAKETYPE(CV_32S,(n))
#define CV_32FC1 CV_MAKETYPE(CV_32F,1)
#define CV_32FC2 CV_MAKETYPE(CV_32F,2)
#define CV_32FC3 CV_MAKETYPE(CV_32F,3)
#define CV_32FC4 CV_MAKETYPE(CV_32F,4)
#define CV_32FC(n) CV_MAKETYPE(CV_32F,(n))
#define CV_64FC1 CV_MAKETYPE(CV_64F,1)
#define CV_64FC2 CV_MAKETYPE(CV_64F,2)
#define CV_64FC3 CV_MAKETYPE(CV_64F,3)
#define CV_64FC4 CV_MAKETYPE(CV_64F,4)
#define CV_64FC(n) CV_MAKETYPE(CV_64F,(n))
// cvdef.h:
#define CV_MAT_CN_MASK ((CV_CN_MAX - 1) << CV_CN_SHIFT)
#define CV_MAT_CN(flags) ((((flags) & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1)
#define CV_MAT_TYPE_MASK (CV_DEPTH_MAX*CV_CN_MAX - 1)
#define CV_MAT_TYPE(flags) ((flags) & CV_MAT_TYPE_MASK)
#define CV_MAT_CONT_FLAG_SHIFT 14
#define CV_MAT_CONT_FLAG (1 << CV_MAT_CONT_FLAG_SHIFT)
#define CV_IS_MAT_CONT(flags) ((flags) & CV_MAT_CONT_FLAG)
#define CV_IS_CONT_MAT CV_IS_MAT_CONT
#define CV_SUBMAT_FLAG_SHIFT 15
#define CV_SUBMAT_FLAG (1 << CV_SUBMAT_FLAG_SHIFT)
#define CV_IS_SUBMAT(flags) ((flags) & CV_MAT_SUBMAT_FLAG)
///** Size of each channel item,
// 0x8442211 = 1000 0100 0100 0010 0010 0001 0001 ~ array of sizeof(arr_type_elem) */
//#define CV_ELEM_SIZE1(type) \
// ((((sizeof(size_t)<<28)|0x8442211) >> CV_MAT_DEPTH(type)*4) & 15)
#define CV_MAT_TYPE(flags) ((flags) & CV_MAT_TYPE_MASK)
/** 0x3a50 = 11 10 10 01 01 00 00 ~ array of log2(sizeof(arr_type_elem)) */
#define CV_ELEM_SIZE(type) \
(CV_MAT_CN(type) << ((((sizeof(size_t)/4+1)*16384|0x3a50) >> CV_MAT_DEPTH(type)*2) & 3))
#ifndef CV_OVERRIDE
# define CV_OVERRIDE override
#endif
// base.h:
namespace cv
{
enum BorderTypes {
BORDER_CONSTANT = 0, //!< `iiiiii|abcdefgh|iiiiiii` with some specified `i`
BORDER_REPLICATE = 1, //!< `aaaaaa|abcdefgh|hhhhhhh`
BORDER_REFLECT = 2, //!< `fedcba|abcdefgh|hgfedcb`
BORDER_WRAP = 3, //!< `cdefgh|abcdefgh|abcdefg`
BORDER_REFLECT_101 = 4, //!< `gfedcb|abcdefgh|gfedcba`
BORDER_TRANSPARENT = 5, //!< `uvwxyz|abcdefgh|ijklmno`
BORDER_REFLECT101 = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101
BORDER_DEFAULT = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101
BORDER_ISOLATED = 16 //!< do not look outside of ROI
};
// imgproc.hpp:
enum InterpolationFlags{
INTER_NEAREST = 0,
INTER_LINEAR = 1,
INTER_CUBIC = 2,
INTER_AREA = 3,
INTER_LANCZOS4 = 4,
INTER_LINEAR_EXACT = 5,
INTER_MAX = 7,
};
} // namespace cv
static inline int cvFloor( double value )
{
int i = (int)value;
return i - (i > value);
}
#endif // defined(GAPI_STANDALONE)
#endif // OPENCV_GAPI_CV_DEFS_HPP

View File

@@ -0,0 +1,31 @@
// 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 defined(__OPENCV_BUILD)
# include <opencv2/core/base.hpp>
# define GAPI_EXPORTS CV_EXPORTS
# else
# define GAPI_EXPORTS
#if 0 // Note: the following version currently is not needed for non-OpenCV build
# 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
#endif // OPENCV_GAPI_OWN_TYPES_HPP

View File

@@ -0,0 +1,341 @@
// 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_MAT_HPP
#define OPENCV_GAPI_OWN_MAT_HPP
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/own/types.hpp>
#include <opencv2/gapi/own/scalar.hpp>
#include <opencv2/gapi/own/saturate.hpp>
#include <opencv2/gapi/own/assert.hpp>
#include <memory> //std::shared_ptr
#include <cstring> //std::memcpy
#include <numeric> //std::accumulate
#include <opencv2/gapi/util/throw.hpp>
namespace cv { namespace gapi { namespace own {
namespace detail {
template <typename T, unsigned char channels>
void assign_row(void* ptr, int cols, Scalar const& s)
{
auto p = static_cast<T*>(ptr);
for (int c = 0; c < cols; c++)
{
for (int ch = 0; ch < channels; ch++)
{
p[c * channels + ch] = saturate<T>(s[ch], roundd);
}
}
}
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 std::vector<int> &_dims, int type, void* _data)
: flags((type & TYPE_MASK)), data((uchar*)_data), step(0), dims(_dims)
{}
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;
//! dimensions (ND-case)
std::vector<int> dims;
};
} // namespace detail
//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(const std::vector<int> &_dims, int _type, void* _data)
: MatHeader (_dims, _type, _data)
{}
Mat(std::vector<int> &&_dims, int _type, void* _data)
: MatHeader (std::move(_dims), _type, _data)
{}
Mat(Mat const& src, const Rect& roi )
: Mat(src)
{
rows = roi.height;
cols = roi.width;
data = ptr(roi.y, roi.x);
}
Mat(Mat const& src) = default;
Mat(Mat&& src) = default;
Mat& operator=(Mat const& src) = default;
Mat& operator=(Mat&& src) = default;
/** @brief Sets all or some of the array elements to the specified value.
@param s Assigned scalar converted to the actual array type.
*/
Mat& operator = (const Scalar& s)
{
constexpr unsigned max_channels = 4; //Scalar can't fit more than 4
using func_p_t = void (*)(void*, int, Scalar const&);
using detail::assign_row;
#define TABLE_ENTRY(type) {assign_row<type, 1>, assign_row<type, 2>, assign_row<type, 3>, assign_row<type, 4>}
static constexpr func_p_t func_tbl[][max_channels] = {
TABLE_ENTRY(uchar),
TABLE_ENTRY(schar),
TABLE_ENTRY(ushort),
TABLE_ENTRY(short),
TABLE_ENTRY(int),
TABLE_ENTRY(float),
TABLE_ENTRY(double)
};
#undef TABLE_ENTRY
static_assert(CV_8U == 0 && CV_8S == 1 && CV_16U == 2 && CV_16S == 3
&& CV_32S == 4 && CV_32F == 5 && CV_64F == 6,
"OCV type ids used as indexes to array, thus exact numbers are important!"
);
const auto depth = static_cast<unsigned int>(this->depth());
GAPI_Assert(depth < sizeof(func_tbl)/sizeof(func_tbl[0]));
if (dims.empty())
{
const auto channels = static_cast<unsigned int>(this->channels());
GAPI_Assert(channels <= max_channels);
auto* f = func_tbl[depth][channels - 1];
for (int r = 0; r < rows; ++r)
{
(*f)(static_cast<void *>(ptr(r)), cols, s );
}
}
else
{
auto* f = func_tbl[depth][0];
// FIXME: better to refactor assign_row to use std::size_t by default
(*f)(static_cast<void *>(data), static_cast<int>(total()), s);
}
return *this;
}
/** @brief Returns the matrix element size in bytes.
The method returns the matrix element size in bytes. For example, if the matrix type is CV_16SC3 ,
the method returns 3\*sizeof(short) or 6.
*/
size_t elemSize() const
{
return CV_ELEM_SIZE(type());
}
/** @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.
If matrix is N-dimensional, -1 is returned.
*/
int channels() const {return dims.empty() ? CV_MAT_CN(flags) : -1;}
/**
@param _rows New number of rows.
@param _cols New number of columns.
@param _type New matrix type.
*/
void create(int _rows, int _cols, int _type)
{
create(Size{_cols, _rows}, _type);
}
/** @overload
@param _size Alternative new matrix size specification: Size(cols, rows)
@param _type New matrix type.
*/
void create(Size _size, int _type)
{
if (_size != 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);
}
}
void create(const std::vector<int> &_dims, int _type)
{
// FIXME: make a proper reallocation-on-demands
// WARNING: no tensor views, so no strides
Mat tmp{_dims, _type, nullptr};
// FIXME: this accumulate duplicates a lot
const auto sz = std::accumulate(_dims.begin(), _dims.end(), 1, std::multiplies<int>());
tmp.memory.reset(new uchar[CV_ELEM_SIZE(_type)*sz], [](uchar * p){delete[] p;});
tmp.data = tmp.memory.get();
*this = std::move(tmp);
}
/** @brief Copies the matrix to another one.
The method copies the matrix data to another matrix. Before copying the data, the method invokes :
@code
m.create(this->size(), this->type());
@endcode
so that the destination matrix is reallocated if needed. While m.copyTo(m); works flawlessly, the
function does not handle the case of a partial overlap between the source and the destination
matrices.
*/
void copyTo(Mat& dst) const
{
if (dims.empty())
{
dst.create(rows, cols, type());
for (int r = 0; r < rows; ++r)
{
std::copy_n(ptr(r), detail::default_step(type(),cols), dst.ptr(r));
}
}
else
{
dst.create(dims, depth());
std::copy_n(data, total()*elemSize(), data);
}
}
/** @brief Returns true if the array has no elements.
The method returns true if Mat::total() is 0 or if Mat::data is NULL. Because of pop_back() and
resize() methods `M.total() == 0` does not imply that `M.data == NULL`.
*/
bool empty() const
{
return data == 0 || total() == 0;
}
/** @brief Returns the total number of array elements.
The method returns the number of array elements (a number of pixels if the array represents an
image).
*/
size_t total() const
{
return static_cast<std::size_t>
(dims.empty()
? (rows * cols)
: std::accumulate(dims.begin(), dims.end(), 1, std::multiplies<int>()));
}
/** @overload
@param roi Extracted submatrix specified as a rectangle.
*/
Mat operator()( const Rect& roi ) const
{
return Mat{*this, roi};
}
/** @brief Returns a pointer to the specified matrix row.
The methods return `uchar*` or typed pointer to the specified matrix row. See the sample in
Mat::isContinuous to know how to use these methods.
@param row Index along the dimension 0
@param col Index along the dimension 1
*/
uchar* ptr(int row, int col = 0)
{
return const_cast<uchar*>(const_cast<const Mat*>(this)->ptr(row,col));
}
/** @overload */
const uchar* ptr(int row, int col = 0) const
{
return data + step * row + CV_ELEM_SIZE(type()) * col;
}
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 /* OPENCV_GAPI_OWN_MAT_HPP */

View File

@@ -0,0 +1,90 @@
// 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_SATURATE_HPP
#define OPENCV_GAPI_OWN_SATURATE_HPP
#include <math.h>
#include <limits>
#include <type_traits>
#include <opencv2/gapi/own/assert.hpp>
namespace cv { namespace gapi { namespace own {
//-----------------------------
//
// 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 converting 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
inline double ceild(double x) { return ceil(x); }
inline double floord(double x) { return floor(x); }
inline double roundd(double x) { return round(x); }
inline double rintd(double x) { return rint(x); }
} //namespace own
} //namespace gapi
} //namespace cv
#endif /* OPENCV_GAPI_OWN_SATURATE_HPP */

View File

@@ -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_GAPI_OWN_SCALAR_HPP
#define OPENCV_GAPI_GAPI_OWN_SCALAR_HPP
#include <opencv2/gapi/own/exports.hpp>
namespace cv
{
namespace gapi
{
namespace own
{
class GAPI_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

View File

@@ -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_TYPES_HPP
#define OPENCV_GAPI_TYPES_HPP
#include <algorithm> // std::max, std::min
#include <ostream>
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 !defined(GAPI_STANDALONE)
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 // !defined(GAPI_STANDALONE)
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 !defined(GAPI_STANDALONE)
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 // !defined(GAPI_STANDALONE)
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

View File

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

View File

@@ -0,0 +1,140 @@
// 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) 2019 Intel Corporation
//
#ifndef OPENCV_GAPI_GPLAIDMLKERNEL_HPP
#define OPENCV_GAPI_GPLAIDMLKERNEL_HPP
#include <opencv2/gapi/gkernel.hpp>
#include <opencv2/gapi/garg.hpp>
namespace plaidml
{
namespace edsl
{
class Tensor;
} // namespace edsl
} // namespace plaidml
namespace cv
{
namespace gapi
{
namespace plaidml
{
GAPI_EXPORTS cv::gapi::GBackend backend();
} // namespace plaidml
} // namespace gapi
struct GPlaidMLContext
{
// Generic accessor API
template<typename T>
const T& inArg(int input) { return m_args.at(input).get<T>(); }
// Syntax sugar
const plaidml::edsl::Tensor& inTensor(int input)
{
return inArg<plaidml::edsl::Tensor>(input);
}
plaidml::edsl::Tensor& outTensor(int output)
{
return *(m_results.at(output).get<plaidml::edsl::Tensor*>());
}
std::vector<GArg> m_args;
std::unordered_map<std::size_t, GArg> m_results;
};
class GAPI_EXPORTS GPlaidMLKernel
{
public:
using F = std::function<void(GPlaidMLContext &)>;
GPlaidMLKernel() = default;
explicit GPlaidMLKernel(const F& f) : m_f(f) {};
void apply(GPlaidMLContext &ctx) const
{
GAPI_Assert(m_f);
m_f(ctx);
}
protected:
F m_f;
};
namespace detail
{
template<class T> struct plaidml_get_in;
template<> struct plaidml_get_in<cv::GMat>
{
static const plaidml::edsl::Tensor& get(GPlaidMLContext& ctx, int idx)
{
return ctx.inTensor(idx);
}
};
template<class T> struct plaidml_get_in
{
static T get(GPlaidMLContext &ctx, int idx) { return ctx.inArg<T>(idx); }
};
template<class T> struct plaidml_get_out;
template<> struct plaidml_get_out<cv::GMat>
{
static plaidml::edsl::Tensor& get(GPlaidMLContext& ctx, int idx)
{
return ctx.outTensor(idx);
}
};
template<typename, typename, typename>
struct PlaidMLCallHelper;
template<typename Impl, typename... Ins, typename... Outs>
struct PlaidMLCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> >
{
template<int... IIs, int... OIs>
static void call_impl(GPlaidMLContext &ctx, detail::Seq<IIs...>, detail::Seq<OIs...>)
{
Impl::run(plaidml_get_in<Ins>::get(ctx, IIs)..., plaidml_get_out<Outs>::get(ctx, OIs)...);
}
static void call(GPlaidMLContext& ctx)
{
call_impl(ctx,
typename detail::MkSeq<sizeof...(Ins)>::type(),
typename detail::MkSeq<sizeof...(Outs)>::type());
}
};
} // namespace detail
template<class Impl, class K>
class GPlaidMLKernelImpl: public cv::detail::PlaidMLCallHelper<Impl, typename K::InArgs, typename K::OutArgs>,
public cv::detail::KernelTag
{
using P = detail::PlaidMLCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
public:
using API = K;
static cv::gapi::GBackend backend() { return cv::gapi::plaidml::backend(); }
static cv::GPlaidMLKernel kernel() { return GPlaidMLKernel(&P::call); }
};
#define GAPI_PLAIDML_KERNEL(Name, API) struct Name: public cv::GPlaidMLKernelImpl<Name, API>
} // namespace cv
#endif // OPENCV_GAPI_GPLAIDMLKERNEL_HPP

View File

@@ -0,0 +1,48 @@
// 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) 2019 Intel Corporation
#ifndef OPENCV_GAPI_PLAIDML_PLAIDML_HPP
#define OPENCV_GAPI_PLAIDML_PLAIDML_HPP
#include <string>
#include <opencv2/gapi/gcommon.hpp> // CompileArgTag
namespace cv
{
namespace gapi
{
namespace plaidml
{
/** \addtogroup gapi_compile_args
* @{
*/
/**
* @brief This structure represents the basic parameters for the experimental
* PlaidML backend.
*/
struct config
{
std::string dev_id; //!< Device ID. Refer to PlaidML documentation for details.
std::string trg_id; //!< Target ID. Refer to PlaidML documentation for details.
};
/** @} gapi_compile_args */
} // namespace plaidml
} // namespace gapi
namespace detail
{
template<> struct CompileArgTag<cv::gapi::plaidml::config>
{
static const char* tag() { return "gapi.plaidml.config"; }
};
} // namespace detail
} // namespace cv
#endif // OPENCV_GAPI_PLAIDML_PLAIDML_HPP

View File

@@ -0,0 +1,14 @@
// 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) 2019 Intel Corporation
#ifndef OPENCV_GAPI_RENDER_ROOT_HPP
#define OPENCV_GAPI_RENDER_ROOT_HPP
// This file is just a shortcut to render/render.hpp
#include <opencv2/gapi/render/render.hpp>
#endif // OPENCV_GAPI_RENDER_ROOT_HPP

View File

@@ -0,0 +1,470 @@
// 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-2019 Intel Corporation
#ifndef OPENCV_GAPI_RENDER_HPP
#define OPENCV_GAPI_RENDER_HPP
#include <string>
#include <vector>
#include <opencv2/imgproc.hpp>
#include <opencv2/gapi.hpp>
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/util/variant.hpp>
#include <opencv2/gapi/own/exports.hpp>
#include <opencv2/gapi/own/scalar.hpp>
/** \defgroup gapi_draw G-API Drawing and composition functionality
* @{
*
* @brief Functions for in-graph drawing.
*
* @note This is a Work in Progress functionality and APIs may
* change in the future releases.
*
* G-API can do some in-graph drawing with a generic operations and a
* set of [rendering primitives](@ref gapi_draw_prims).
* In contrast with traditional OpenCV, in G-API user need to form a
* *rendering list* of primitives to draw. This list can be built
* manually or generated within a graph. This list is passed to
* [special operations or functions](@ref gapi_draw_api) where all
* primitives are interpreted and applied to the image.
*
* For example, in a complex pipeline a list of detected objects
* can be translated in-graph to a list of cv::gapi::wip::draw::Rect
* primitives to highlight those with bounding boxes, or a list of
* detected faces can be translated in-graph to a list of
* cv::gapi::wip::draw::Mosaic primitives to hide sensitive content
* or protect privacy.
*
* Like any other operations, rendering in G-API can be reimplemented
* by different backends. Currently only an OpenCV-based backend is
* available.
*
* In addition to the graph-level operations, there are also regular
* (immediate) OpenCV-like functions are available -- see
* cv::gapi::wip::draw::render(). These functions are just wrappers
* over regular G-API and build the rendering graphs on the fly, so
* take compilation arguments as parameters.
*
* Currently this API is more machine-oriented than human-oriented.
* The main purpose is to translate a set of domain-specific objects
* to a list of primitives to draw. For example, in order to generate
* a picture like this:
*
* ![](modules/gapi/doc/pics/render_example.png)
*
* Rendering list needs to be generated as follows:
*
* @include modules/gapi/samples/draw_example.cpp
*
* @defgroup gapi_draw_prims Drawing primitives
* @defgroup gapi_draw_api Drawing operations and functions
* @}
*/
namespace cv
{
namespace gapi
{
namespace wip
{
namespace draw
{
/**
* @brief This structure specifies which FreeType font to use by FText primitives.
*/
struct freetype_font
{
/*@{*/
std::string path; //!< The path to the font file (.ttf)
/*@{*/
};
//! @addtogroup gapi_draw_prims
//! @{
/**
* @brief This structure represents a text string to draw.
*
* Parameters match cv::putText().
*/
struct Text
{
/**
* @brief Text constructor
*
* @param text_ The text string to be drawn
* @param org_ The bottom-left corner of the text string in the image
* @param ff_ The font type, see #HersheyFonts
* @param fs_ The font scale factor that is multiplied by the font-specific base size
* @param color_ The text color
* @param thick_ The thickness of the lines used to draw a text
* @param lt_ The line type. See #LineTypes
* @param bottom_left_origin_ When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner
*/
Text(const std::string& text_,
const cv::Point& org_,
int ff_,
double fs_,
const cv::Scalar& color_,
int thick_ = 1,
int lt_ = cv::LINE_8,
bool bottom_left_origin_ = false) :
text(text_), org(org_), ff(ff_), fs(fs_),
color(color_), thick(thick_), lt(lt_), bottom_left_origin(bottom_left_origin_)
{
}
/*@{*/
std::string text; //!< The text string to be drawn
cv::Point org; //!< The bottom-left corner of the text string in the image
int ff; //!< The font type, see #HersheyFonts
double fs; //!< The font scale factor that is multiplied by the font-specific base size
cv::Scalar color; //!< The text color
int thick; //!< The thickness of the lines used to draw a text
int lt; //!< The line type. See #LineTypes
bool bottom_left_origin; //!< When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner
/*@{*/
};
/**
* @brief This structure represents a text string to draw using
* FreeType renderer.
*
* If OpenCV is built without FreeType support, this primitive will
* fail at the execution stage.
*/
struct FText
{
/**
* @brief FText constructor
*
* @param text_ The text string to be drawn
* @param org_ The bottom-left corner of the text string in the image
* @param fh_ The height of text
* @param color_ The text color
*/
FText(const std::wstring& text_,
const cv::Point& org_,
int fh_,
const cv::Scalar& color_) :
text(text_), org(org_), fh(fh_), color(color_)
{
}
/*@{*/
std::wstring text; //!< The text string to be drawn
cv::Point org; //!< The bottom-left corner of the text string in the image
int fh; //!< The height of text
cv::Scalar color; //!< The text color
/*@{*/
};
/**
* @brief This structure represents a rectangle to draw.
*
* Parameters match cv::rectangle().
*/
struct Rect
{
/**
* @brief Rect constructor
*
* @param rect_ Coordinates of the rectangle
* @param color_ The bottom-left corner of the text string in the image
* @param thick_ The thickness of lines that make up the rectangle. Negative values, like #FILLED, mean that the function has to draw a filled rectangle
* @param lt_ The type of the line. See #LineTypes
* @param shift_ The number of fractional bits in the point coordinates
*/
Rect(const cv::Rect& rect_,
const cv::Scalar& color_,
int thick_ = 1,
int lt_ = cv::LINE_8,
int shift_ = 0) :
rect(rect_), color(color_), thick(thick_), lt(lt_), shift(shift_)
{
}
/*@{*/
cv::Rect rect; //!< Coordinates of the rectangle
cv::Scalar color; //!< The rectangle color or brightness (grayscale image)
int thick; //!< The thickness of lines that make up the rectangle. Negative values, like #FILLED, mean that the function has to draw a filled rectangle
int lt; //!< The type of the line. See #LineTypes
int shift; //!< The number of fractional bits in the point coordinates
/*@{*/
};
/**
* @brief This structure represents a circle to draw.
*
* Parameters match cv::circle().
*/
struct Circle
{
/**
* @brief Circle constructor
*
* @param center_ The center of the circle
* @param radius_ The radius of the circle
* @param color_ The color of the circle
* @param thick_ The thickness of the circle outline, if positive. Negative values, like #FILLED, mean that a filled circle is to be drawn
* @param lt_ The Type of the circle boundary. See #LineTypes
* @param shift_ The Number of fractional bits in the coordinates of the center and in the radius value
*/
Circle(const cv::Point& center_,
int radius_,
const cv::Scalar& color_,
int thick_ = 1,
int lt_ = cv::LINE_8,
int shift_ = 0) :
center(center_), radius(radius_), color(color_), thick(thick_), lt(lt_), shift(shift_)
{
}
/*@{*/
cv::Point center; //!< The center of the circle
int radius; //!< The radius of the circle
cv::Scalar color; //!< The color of the circle
int thick; //!< The thickness of the circle outline, if positive. Negative values, like #FILLED, mean that a filled circle is to be drawn
int lt; //!< The Type of the circle boundary. See #LineTypes
int shift; //!< The Number of fractional bits in the coordinates of the center and in the radius value
/*@{*/
};
/**
* @brief This structure represents a line to draw.
*
* Parameters match cv::line().
*/
struct Line
{
/**
* @brief Line constructor
*
* @param pt1_ The first point of the line segment
* @param pt2_ The second point of the line segment
* @param color_ The line color
* @param thick_ The thickness of line
* @param lt_ The Type of the line. See #LineTypes
* @param shift_ The number of fractional bits in the point coordinates
*/
Line(const cv::Point& pt1_,
const cv::Point& pt2_,
const cv::Scalar& color_,
int thick_ = 1,
int lt_ = cv::LINE_8,
int shift_ = 0) :
pt1(pt1_), pt2(pt2_), color(color_), thick(thick_), lt(lt_), shift(shift_)
{
}
/*@{*/
cv::Point pt1; //!< The first point of the line segment
cv::Point pt2; //!< The second point of the line segment
cv::Scalar color; //!< The line color
int thick; //!< The thickness of line
int lt; //!< The Type of the line. See #LineTypes
int shift; //!< The number of fractional bits in the point coordinates
/*@{*/
};
/**
* @brief This structure represents a mosaicing operation.
*
* Mosaicing is a very basic method to obfuscate regions in the image.
*/
struct Mosaic
{
/**
* @brief Mosaic constructor
*
* @param mos_ Coordinates of the mosaic
* @param cellSz_ Cell size (same for X, Y). Note: mos size must be multiple of cell size
* @param decim_ Decimation (0 stands for no decimation)
*/
Mosaic(const cv::Rect& mos_,
int cellSz_,
int decim_) :
mos(mos_), cellSz(cellSz_), decim(decim_)
{
}
/*@{*/
cv::Rect mos; //!< Coordinates of the mosaic
int cellSz; //!< Cell size (same for X, Y). Note: mosaic size must be a multiple of cell size
int decim; //!< Decimation (0 stands for no decimation)
/*@{*/
};
/**
* @brief This structure represents an image to draw.
*
* Image is blended on a frame using the specified mask.
*/
struct Image
{
/**
* @brief Mosaic constructor
*
* @param org_ The bottom-left corner of the image
* @param img_ Image to draw
* @param alpha_ Alpha channel for image to draw (same size and number of channels)
*/
Image(const cv::Point& org_,
const cv::Mat& img_,
const cv::Mat& alpha_) :
org(org_), img(img_), alpha(alpha_)
{
}
/*@{*/
cv::Point org; //!< The bottom-left corner of the image
cv::Mat img; //!< Image to draw
cv::Mat alpha; //!< Alpha channel for image to draw (same size and number of channels)
/*@{*/
};
/**
* @brief This structure represents a polygon to draw.
*/
struct Poly
{
/**
* @brief Mosaic constructor
*
* @param points_ Points to connect
* @param color_ The line color
* @param thick_ The thickness of line
* @param lt_ The Type of the line. See #LineTypes
* @param shift_ The number of fractional bits in the point coordinate
*/
Poly(const std::vector<cv::Point>& points_,
const cv::Scalar& color_,
int thick_ = 1,
int lt_ = cv::LINE_8,
int shift_ = 0) :
points(points_), color(color_), thick(thick_), lt(lt_), shift(shift_)
{
}
/*@{*/
std::vector<cv::Point> points; //!< Points to connect
cv::Scalar color; //!< The line color
int thick; //!< The thickness of line
int lt; //!< The Type of the line. See #LineTypes
int shift; //!< The number of fractional bits in the point coordinate
/*@{*/
};
using Prim = util::variant
< Text
, FText
, Rect
, Circle
, Line
, Mosaic
, Image
, Poly
>;
using Prims = std::vector<Prim>;
//! @} gapi_draw_prims
using GMat2 = std::tuple<cv::GMat,cv::GMat>;
using GMatDesc2 = std::tuple<cv::GMatDesc,cv::GMatDesc>;
//! @addtogroup gapi_draw_api
//! @{
/** @brief The function renders on the input image passed drawing primitivies
@param bgr input image: 8-bit unsigned 3-channel image @ref CV_8UC3.
@param prims vector of drawing primitivies
@param args graph compile time parameters
*/
void GAPI_EXPORTS render(cv::Mat& bgr,
const Prims& prims,
cv::GCompileArgs&& args = {});
/** @brief The function renders on two NV12 planes passed drawing primitivies
@param y_plane input image: 8-bit unsigned 1-channel image @ref CV_8UC1.
@param uv_plane input image: 8-bit unsigned 2-channel image @ref CV_8UC2.
@param prims vector of drawing primitivies
@param args graph compile time parameters
*/
void GAPI_EXPORTS render(cv::Mat& y_plane,
cv::Mat& uv_plane,
const Prims& prims,
cv::GCompileArgs&& args = {});
G_TYPED_KERNEL_M(GRenderNV12, <GMat2(cv::GMat,cv::GMat,cv::GArray<wip::draw::Prim>)>, "org.opencv.render.nv12")
{
static GMatDesc2 outMeta(GMatDesc y_plane, GMatDesc uv_plane, GArrayDesc)
{
return std::make_tuple(y_plane, uv_plane);
}
};
G_TYPED_KERNEL(GRenderBGR, <cv::GMat(cv::GMat,cv::GArray<wip::draw::Prim>)>, "org.opencv.render.bgr")
{
static GMatDesc outMeta(GMatDesc bgr, GArrayDesc)
{
return bgr;
}
};
/** @brief Renders on 3 channels input
Output image must be 8-bit unsigned planar 3-channel image
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3
@param prims draw primitives
*/
GAPI_EXPORTS GMat render3ch(const GMat& src, const GArray<Prim>& prims);
/** @brief Renders on two planes
Output y image must be 8-bit unsigned planar 1-channel image @ref CV_8UC1
uv image must be 8-bit unsigned planar 2-channel image @ref CV_8UC2
@param y input image: 8-bit unsigned 1-channel image @ref CV_8UC1
@param uv input image: 8-bit unsigned 2-channel image @ref CV_8UC2
@param prims draw primitives
*/
GAPI_EXPORTS GMat2 renderNV12(const GMat& y,
const GMat& uv,
const GArray<Prim>& prims);
//! @} gapi_draw_api
} // namespace draw
} // namespace wip
namespace render
{
namespace ocv
{
GAPI_EXPORTS cv::gapi::GKernelPackage kernels();
} // namespace ocv
} // namespace render
} // namespace gapi
namespace detail
{
template<> struct CompileArgTag<cv::gapi::wip::draw::freetype_font>
{
static const char* tag() { return "gapi.freetype_font"; }
};
} // namespace detail
} // namespace cv
#endif // OPENCV_GAPI_RENDER_HPP

View File

@@ -0,0 +1,110 @@
// 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) 2019 Intel Corporation
#ifndef OPENCV_GAPI_STREAMING_CAP_HPP
#define OPENCV_GAPI_STREAMING_CAP_HPP
/**
* YOUR ATTENTION PLEASE!
*
* This is a header-only implementation of cv::VideoCapture-based
* Stream source. It is not built by default with G-API as G-API
* doesn't depend on videoio module.
*
* If you want to use it in your application, please make sure
* videioio is available in your OpenCV package and is linked to your
* application.
*
* Note for developers: please don't put videoio dependency in G-API
* because of this file.
*/
#include <opencv2/videoio.hpp>
#include <opencv2/gapi/garg.hpp>
namespace cv {
namespace gapi {
namespace wip {
/**
* @brief OpenCV's VideoCapture-based streaming source.
*
* This class implements IStreamSource interface.
* Its constructor takes the same parameters as cv::VideoCapture does.
*
* Please make sure that videoio OpenCV module is avaiable before using
* this in your application (G-API doesn't depend on it directly).
*
* @note stream sources are passed to G-API via shared pointers, so
* please gapi::make_src<> to create objects and ptr() to pass a
* GCaptureSource to cv::gin().
*/
class GCaptureSource: public IStreamSource
{
public:
explicit GCaptureSource(int id) : cap(id) { prep(); }
explicit GCaptureSource(const std::string &path) : cap(path) { prep(); }
// TODO: Add more constructor overloads to make it
// fully compatible with VideoCapture's interface.
protected:
cv::VideoCapture cap;
cv::Mat first;
bool first_pulled = false;
void prep()
{
// Prepare first frame to report its meta to engine
// when needed
GAPI_Assert(first.empty());
cv::Mat tmp;
if (!cap.read(tmp))
{
GAPI_Assert(false && "Couldn't grab the very first frame");
}
// NOTE: Some decode/media VideoCapture backends continue
// owning the video buffer under cv::Mat so in order to
// process it safely in a highly concurrent pipeline, clone()
// is the only right way.
first = tmp.clone();
}
virtual bool pull(cv::gapi::wip::Data &data) override
{
if (!first_pulled)
{
GAPI_Assert(!first.empty());
first_pulled = true;
data = first; // no need to clone here since it was cloned already
return true;
}
if (!cap.isOpened()) return false;
cv::Mat frame;
if (!cap.read(frame))
{
// end-of-stream happened
return false;
}
// Same reason to clone as in prep()
data = frame.clone();
return true;
}
virtual GMetaArg descr_of() const override
{
GAPI_Assert(!first.empty());
return cv::GMetaArg{cv::descr_of(first)};
}
};
} // namespace wip
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_STREAMING_CAP_HPP

View File

@@ -0,0 +1,62 @@
// 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) 2019 Intel Corporation
#ifndef OPENCV_GAPI_STREAMING_SOURCE_HPP
#define OPENCV_GAPI_STREAMING_SOURCE_HPP
#include <memory> // shared_ptr
#include <type_traits> // is_base_of
#include <opencv2/gapi/gmetaarg.hpp> // GMetaArg
namespace cv {
namespace gapi {
namespace wip {
struct Data; // "forward-declaration" of GRunArg
/**
* @brief Abstract streaming pipeline source.
*
* Implement this interface if you want customize the way how data is
* streaming into GStreamingCompiled.
*
* Objects implementing this interface can be passed to
* GStreamingCompiled using setSource() with cv::gin(). Regular
* compiled graphs (GCompiled) don't support input objects of this
* type.
*
* Default cv::VideoCapture-based implementation is available, see
* cv::gapi::wip::GCaptureSource.
*
* @note stream sources are passed to G-API via shared pointers, so
* please use ptr() when passing a IStreamSource implementation to
* cv::gin().
*/
class IStreamSource: public std::enable_shared_from_this<IStreamSource>
{
public:
using Ptr = std::shared_ptr<IStreamSource>;
Ptr ptr() { return shared_from_this(); }
virtual bool pull(Data &data) = 0;
virtual GMetaArg descr_of() const = 0;
virtual ~IStreamSource() = default;
};
template<class T, class... Args>
IStreamSource::Ptr inline make_src(Args&&... args)
{
static_assert(std::is_base_of<IStreamSource, T>::value,
"T must implement the cv::gapi::IStreamSource interface!");
auto src_ptr = std::make_shared<T>(std::forward<Args>(args)...);
return src_ptr->ptr();
}
} // namespace wip
} // namespace gapi
} // namespace cv
#endif // OPENCV_GAPI_STREAMING_SOURCE_HPP

View File

@@ -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_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);
template<class value_t>
friend value_t& unsafe_any_cast(any& operand);
template<class value_t>
friend const value_t& unsafe_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());
}
template<class value_t>
inline value_t& unsafe_any_cast(any& operand)
{
#ifdef DEBUG
return any_cast<value_t>(operand);
#else
return static_cast<any::holder_impl<typename std::decay<value_t>::type> *>(operand.hldr.get())->v;
#endif
}
template<class value_t>
inline const value_t& unsafe_any_cast(const any& operand)
{
#ifdef DEBUG
return any_cast<value_t>(operand);
#else
return static_cast<any::holder_impl<typename std::decay<value_t>::type> *>(operand.hldr.get())->v;
#endif
}
} // 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

View File

@@ -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_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
#endif /* OPENCV_GAPI_UTIL_COMPILER_HINTS_HPP */

View File

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

View File

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

View File

@@ -0,0 +1,124 @@
// 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-2019 Intel Corporation
#ifndef OPENCV_GAPI_UTIL_HPP
#define OPENCV_GAPI_UTIL_HPP
#include <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;
};
template <typename...>
struct contains : std::false_type{};
template <typename T1, typename T2, typename... Ts>
struct contains<T1, T2, Ts...> : std::integral_constant<bool, std::is_same<T1, T2>::value ||
contains<T1, Ts...>::value> {};
template<typename T, typename... Types>
struct contains<T, std::tuple<Types...>> : std::integral_constant<bool, contains<T, Types...>::value> {};
template <typename...>
struct all_unique : std::true_type{};
template <typename T1, typename... Ts>
struct all_unique<T1, Ts...> : std::integral_constant<bool, !contains<T1, Ts...>::value &&
all_unique<Ts...>::value> {};
template<typename>
struct tuple_wrap_helper;
template<typename T> struct tuple_wrap_helper
{
using type = std::tuple<T>;
static type get(T&& obj) { return std::make_tuple(std::move(obj)); }
};
template<typename... Objs>
struct tuple_wrap_helper<std::tuple<Objs...>>
{
using type = std::tuple<Objs...>;
static type get(std::tuple<Objs...>&& objs) { return std::forward<std::tuple<Objs...>>(objs); }
};
} // namespace detail
} // namespace cv
// \endcond
#endif // OPENCV_GAPI_UTIL_HPP

View File

@@ -0,0 +1,379 @@
// 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 *(T*)(&v.memory); // workaround for ICC 2019
// original code: 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 *(const T*)(&v.memory); // workaround for ICC 2019
// original code: 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