Merge pull request #16118 from smirnov-alexey:as/gopaque

G-API: GOpaque implementation

* Stub initial copypasted solution

* Fix mov test and add a couple of others

* Fix warnings

* More code coverage and tests

* fix macos warning

* address review comments

* Address review comments and fix indentation

* Fix build on armv7
pull/16478/head
Alexey Smirnov 5 years ago committed by GitHub
parent 2ced568d34
commit 0d456f9111
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      modules/gapi/CMakeLists.txt
  2. 31
      modules/gapi/include/opencv2/gapi/cpu/gcpukernel.hpp
  3. 8
      modules/gapi/include/opencv2/gapi/fluid/gfluidkernel.hpp
  4. 7
      modules/gapi/include/opencv2/gapi/garg.hpp
  5. 9
      modules/gapi/include/opencv2/gapi/gcall.hpp
  6. 1
      modules/gapi/include/opencv2/gapi/gcommon.hpp
  7. 10
      modules/gapi/include/opencv2/gapi/gcompoundkernel.hpp
  8. 7
      modules/gapi/include/opencv2/gapi/gkernel.hpp
  9. 1
      modules/gapi/include/opencv2/gapi/gmat.hpp
  10. 3
      modules/gapi/include/opencv2/gapi/gmetaarg.hpp
  11. 289
      modules/gapi/include/opencv2/gapi/gopaque.hpp
  12. 4
      modules/gapi/include/opencv2/gapi/gproto.hpp
  13. 16
      modules/gapi/include/opencv2/gapi/gtype_traits.hpp
  14. 6
      modules/gapi/include/opencv2/gapi/gtyped.hpp
  15. 13
      modules/gapi/include/opencv2/gapi/ocl/goclkernel.hpp
  16. 29
      modules/gapi/src/api/gbackend.cpp
  17. 5
      modules/gapi/src/api/gcall.cpp
  18. 45
      modules/gapi/src/api/gopaque.cpp
  19. 15
      modules/gapi/src/api/gproto.cpp
  20. 4
      modules/gapi/src/backends/common/gbackend.hpp
  21. 6
      modules/gapi/src/backends/cpu/gcpubackend.cpp
  22. 5
      modules/gapi/src/backends/cpu/gcpukernel.cpp
  23. 8
      modules/gapi/src/backends/fluid/gfluidbackend.cpp
  24. 2
      modules/gapi/src/backends/fluid/gfluidbackend.hpp
  25. 5
      modules/gapi/src/backends/ie/giebackend.cpp
  26. 8
      modules/gapi/src/backends/ocl/goclbackend.cpp
  27. 3
      modules/gapi/src/backends/plaidml/gplaidmlbackend.cpp
  28. 3
      modules/gapi/src/compiler/gcompiler.cpp
  29. 3
      modules/gapi/src/compiler/gobjref.hpp
  30. 1
      modules/gapi/src/compiler/passes/dump_dot.cpp
  31. 197
      modules/gapi/test/gapi_opaque_tests.cpp
  32. 109
      modules/gapi/test/gapi_transform_tests.cpp
  33. 19
      modules/gapi/test/internal/gapi_int_garg_test.cpp

@ -44,6 +44,7 @@ set(gapi_srcs
src/api/gorigin.cpp
src/api/gmat.cpp
src/api/garray.cpp
src/api/gopaque.cpp
src/api/gscalar.cpp
src/api/gkernel.cpp
src/api/gbackend.cpp

@ -94,9 +94,14 @@ public:
{
return outVecRef(output).wref<T>();
}
template<typename T> T& outOpaqueR(int output) // FIXME: the same issue
{
return outOpaqueRef(output).wref<T>();
}
protected:
detail::VectorRef& outVecRef(int output);
detail::OpaqueRef& outOpaqueRef(int output);
std::vector<GArg> m_args;
@ -145,12 +150,31 @@ template<typename U> struct get_in<cv::GArray<U> >
{
static const std::vector<U>& get(GCPUContext &ctx, int idx) { return ctx.inArg<VectorRef>(idx).rref<U>(); }
};
template<typename U> struct get_in<cv::GOpaque<U> >
{
static const U& get(GCPUContext &ctx, int idx) { return ctx.inArg<OpaqueRef>(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> >
{
};
//FIXME(dm): GArray<Scalar>/GArray<GScalar> conversion should be done more gracefully in the system
template<> struct get_in<cv::GArray<cv::GScalar> >: public get_in<cv::GArray<cv::Scalar> >
{
};
//FIXME(dm): GOpaque<Mat>/GOpaque<GMat> conversion should be done more gracefully in the system
template<> struct get_in<cv::GOpaque<cv::GMat> >: public get_in<cv::GOpaque<cv::Mat> >
{
};
//FIXME(dm): GOpaque<Scalar>/GOpaque<GScalar> conversion should be done more gracefully in the system
template<> struct get_in<cv::GOpaque<cv::GScalar> >: public get_in<cv::GOpaque<cv::Mat> >
{
};
template<class T> struct get_in
{
static T get(GCPUContext &ctx, int idx) { return ctx.inArg<T>(idx); }
@ -229,6 +253,13 @@ template<typename U> struct get_out<cv::GArray<U>>
return ctx.outVecR<U>(idx);
}
};
template<typename U> struct get_out<cv::GOpaque<U>>
{
static U& get(GCPUContext &ctx, int idx)
{
return ctx.outOpaqueR<U>(idx);
}
};
template<typename, typename, typename>
struct OCVCallHelper;

@ -200,6 +200,14 @@ template<typename U> struct fluid_get_in<cv::GArray<U>>
}
};
template<typename U> struct fluid_get_in<cv::GOpaque<U>>
{
static const U& get(const cv::GArgs &in_args, int idx)
{
return in_args.at(idx).unsafe_get<cv::detail::OpaqueRef>().rref<U>();
}
};
template<class T> struct fluid_get_in
{
static const T& get(const cv::GArgs &in_args, int idx)

@ -20,6 +20,7 @@
#include <opencv2/gapi/gmat.hpp>
#include <opencv2/gapi/gscalar.hpp>
#include <opencv2/gapi/garray.hpp>
#include <opencv2/gapi/gopaque.hpp>
#include <opencv2/gapi/gtype_traits.hpp>
#include <opencv2/gapi/gmetaarg.hpp>
#include <opencv2/gapi/own/scalar.hpp>
@ -96,7 +97,8 @@ using GRunArg = util::variant<
cv::gapi::wip::IStreamSource::Ptr,
cv::gapi::own::Mat,
cv::gapi::own::Scalar,
cv::detail::VectorRef
cv::detail::VectorRef,
cv::detail::OpaqueRef
>;
using GRunArgs = std::vector<GRunArg>;
@ -128,7 +130,8 @@ using GRunArgP = util::variant<
#endif // !defined(GAPI_STANDALONE)
cv::gapi::own::Mat*,
cv::gapi::own::Scalar*,
cv::detail::VectorRef
cv::detail::VectorRef,
cv::detail::OpaqueRef
>;
using GRunArgsP = std::vector<GRunArgP>;

@ -12,6 +12,7 @@
#include <opencv2/gapi/gmat.hpp> // GMat
#include <opencv2/gapi/gscalar.hpp> // GScalar
#include <opencv2/gapi/garray.hpp> // GArray<T>
#include <opencv2/gapi/gopaque.hpp> // GOpaque<T>
namespace cv {
@ -46,6 +47,11 @@ public:
return GArray<T>(yieldArray(output));
}
template<class T> GOpaque<T> yieldOpaque(int output = 0)
{
return GOpaque<T>(yieldOpaque(output));
}
// Internal use only
Priv& priv();
const Priv& priv() const;
@ -55,8 +61,9 @@ protected:
void setArgs(std::vector<GArg> &&args);
// Public version returns a typed array, this one is implementation detail
// Public versions return a typed array or opaque, those are implementation details
detail::GArrayU yieldArray(int output = 0);
detail::GOpaqueU yieldOpaque(int output = 0);
};
} // namespace cv

@ -44,6 +44,7 @@ enum class GShape: int
GMAT,
GSCALAR,
GARRAY,
GOPAQUE,
};
struct GCompileArg;

@ -65,6 +65,16 @@ template<typename U> struct get_compound_in<cv::GArray<U>>
}
};
template<typename U> struct get_compound_in<cv::GOpaque<U>>
{
static cv::GOpaque<U> get(GCompoundContext &ctx, int idx)
{
auto opaq = cv::GOpaque<U>();
ctx.m_args[idx] = GArg(opaq);
return opaq;
}
};
template<typename, typename, typename>
struct GCompoundCallHelper;

@ -74,6 +74,10 @@ namespace detail
{
static inline cv::GArray<U> yield(cv::GCall &call, int i) { return call.yieldArray<U>(i); }
};
template<typename U> struct Yield<cv::GOpaque<U> >
{
static inline cv::GOpaque<U> yield(cv::GCall &call, int i) { return call.yieldOpaque<U>(i); }
};
} // anonymous namespace
////////////////////////////////////////////////////////////////////////////
@ -87,7 +91,8 @@ namespace detail
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 U> struct MetaType<cv::GArray<U> > { using type = GArrayDesc; };
template<typename U> struct MetaType<cv::GOpaque<U> > { using type = GOpaqueDesc; };
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

@ -46,6 +46,7 @@ struct GOrigin;
* cv::GMat | cv::Mat
* cv::GScalar | cv::Scalar
* `cv::GArray<T>` | std::vector<T>
* `cv::GOpaque<T>` | T
*/
class GAPI_EXPORTS GMat
{

@ -17,6 +17,7 @@
#include <opencv2/gapi/gmat.hpp>
#include <opencv2/gapi/gscalar.hpp>
#include <opencv2/gapi/garray.hpp>
#include <opencv2/gapi/gopaque.hpp>
namespace cv
{
@ -36,6 +37,7 @@ using GMetaArg = util::variant
, GMatDesc
, GScalarDesc
, GArrayDesc
, GOpaqueDesc
>;
GAPI_EXPORTS std::ostream& operator<<(std::ostream& os, const GMetaArg &);
@ -52,6 +54,7 @@ namespace detail
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<> struct is_meta_descr<GOpaqueDesc> : std::true_type {};
template<typename... Ts>
using are_meta_descrs = all_satisfy<is_meta_descr, Ts...>;

@ -0,0 +1,289 @@
// 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_GOPAQUE_HPP
#define OPENCV_GAPI_GOPAQUE_HPP
#include <functional>
#include <ostream>
#include <memory>
#include <opencv2/gapi/own/exports.hpp>
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/util/variant.hpp>
#include <opencv2/gapi/util/throw.hpp>
#include <opencv2/gapi/own/assert.hpp>
namespace cv
{
// Forward declaration; GNode and GOrigin are an internal
// (user-inaccessible) classes.
class GNode;
struct GOrigin;
template<typename T> class GOpaque;
/**
* \addtogroup gapi_meta_args
* @{
*/
struct GOpaqueDesc
{
// FIXME: Body
// FIXME: Also implement proper operator== then
bool operator== (const GOpaqueDesc&) const { return true; }
};
template<typename U> GOpaqueDesc descr_of(const U &) { return {};}
static inline GOpaqueDesc empty_gopaque_desc() {return {}; }
/** @} */
std::ostream& operator<<(std::ostream& os, const cv::GOpaqueDesc &desc);
namespace detail
{
// ConstructOpaque is a callback which stores information about T and is used by
// G-API runtime to construct an object in host memory (T remains opaque for G-API).
// ConstructOpaque is carried into G-API internals by GOpaqueU.
// Currently it is suitable for Host (CPU) plugins only, real offload may require
// more information for manual memory allocation on-device.
class OpaqueRef;
using ConstructOpaque = std::function<void(OpaqueRef&)>;
// FIXME: garray.hpp already contains hint classes (for actual T type verification),
// need to think where it can be moved (currently opaque uses it from garray)
// This class strips type information from GOpaque<T> and makes it usable
// in the G-API graph compiler (expression unrolling, graph generation, etc).
// Part of GProtoArg.
class GAPI_EXPORTS GOpaqueU
{
public:
GOpaqueU(const GNode &n, std::size_t out); // Operation result constructor
template <typename T>
bool holds() const; // Check if was created from GOpaque<T>
GOrigin& priv(); // Internal use only
const GOrigin& priv() const; // Internal use only
protected:
GOpaqueU(); // Default constructor
template<class> friend class cv::GOpaque; // (available for GOpaque<T> only)
void setConstructFcn(ConstructOpaque &&cv); // Store T-aware constructor
template <typename T>
void specifyType(); // Store type of initial GOpaque<T>
std::shared_ptr<GOrigin> m_priv;
std::shared_ptr<TypeHintBase> m_hint;
};
template <typename T>
bool GOpaqueU::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 GOpaqueU::specifyType(){
m_hint.reset(new TypeHint<typename std::decay<T>::type>);
};
// This class represents a typed object 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 BasicOpaqueRef
{
public:
cv::GOpaqueDesc m_desc;
virtual ~BasicOpaqueRef() {}
virtual void mov(BasicOpaqueRef &ref) = 0;
};
template<typename T> class OpaqueRefT final: public BasicOpaqueRef
{
using empty_t = util::monostate;
using ro_ext_t = const T *;
using rw_ext_t = T *;
using rw_own_t = 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 T* obj = nullptr)
{
if (obj) m_desc = cv::descr_of(*obj);
}
public:
OpaqueRefT() { init(); }
virtual ~OpaqueRefT() {}
explicit OpaqueRefT(const T& obj) : m_ref(&obj) { init(&obj); }
explicit OpaqueRefT( T& obj) : m_ref(&obj) { init(&obj); }
explicit OpaqueRefT( T&& obj) : m_ref(std::move(obj)) { init(&obj); }
// Reset a OpaqueRefT. Called only for objects instantiated
// internally in G-API (e.g. temporary GOpaque<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 OpaqueRefTs.
void reset()
{
if (isEmpty())
{
T empty_obj{};
m_desc = cv::descr_of(empty_obj);
m_ref = std::move(empty_obj);
GAPI_Assert(isRWOwn());
}
else if (isRWOwn())
{
util::get<rw_own_t>(m_ref) = {};
}
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
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 T& rref() const
{
// ANY object 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(BasicOpaqueRef &v) override {
OpaqueRefT<T> *tv = dynamic_cast<OpaqueRefT<T>*>(&v);
GAPI_Assert(tv != nullptr);
wref() = std::move(tv->wref());
}
};
// This class strips type information from OpaqueRefT<> 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 OpaqueRefT<T>.
// OpaqueRef maintains "reference" semantics so two copies of OpaqueRef refer
// to the same underlying object.
class OpaqueRef
{
std::shared_ptr<BasicOpaqueRef> m_ref;
template<typename T> inline void check() const
{
GAPI_DbgAssert(dynamic_cast<OpaqueRefT<T>*>(m_ref.get()) != nullptr);
}
public:
OpaqueRef() = default;
template<typename T> explicit OpaqueRef(T&& obj) :
m_ref(new OpaqueRefT<typename std::decay<T>::type>(std::forward<T>(obj))) {}
template<typename T> void reset()
{
if (!m_ref) m_ref.reset(new OpaqueRefT<T>());
check<T>();
static_cast<OpaqueRefT<T>&>(*m_ref).reset();
}
template<typename T> T& wref()
{
check<T>();
return static_cast<OpaqueRefT<T>&>(*m_ref).wref();
}
template<typename T> const T& rref() const
{
check<T>();
return static_cast<OpaqueRefT<T>&>(*m_ref).rref();
}
void mov(OpaqueRef &v)
{
m_ref->mov(*v.m_ref);
}
cv::GOpaqueDesc descr_of() const
{
return m_ref->m_desc;
}
};
} // namespace detail
/** \addtogroup gapi_data_objects
* @{
*/
template<typename T> class GOpaque
{
public:
GOpaque() { putDetails(); } // Empty constructor
explicit GOpaque(detail::GOpaqueU &&ref) // GOpaqueU-based constructor
: m_ref(ref) { putDetails(); } // (used by GCall, not for users)
detail::GOpaqueU strip() const { return m_ref; }
private:
// Host type (or Flat type) - the type this GOpaque is actually
// specified to.
using HT = typename detail::flatten_g<typename std::decay<T>::type>::type;
static void CTor(detail::OpaqueRef& ref) {
ref.reset<HT>();
}
void putDetails() {
m_ref.setConstructFcn(&CTor);
m_ref.specifyType<HT>();
}
detail::GOpaqueU m_ref;
};
/** @} */
} // namespace cv
#endif // OPENCV_GAPI_GOPAQUE_HPP

@ -17,6 +17,7 @@
#include <opencv2/gapi/gmat.hpp>
#include <opencv2/gapi/gscalar.hpp>
#include <opencv2/gapi/garray.hpp>
#include <opencv2/gapi/gopaque.hpp>
#include <opencv2/gapi/garg.hpp>
#include <opencv2/gapi/gmetaarg.hpp>
@ -36,7 +37,8 @@ using GProtoArg = util::variant
< GMat
, GMatP
, GScalar
, detail::GArrayU // instead of GArray<T>
, detail::GArrayU // instead of GArray<T>
, detail::GOpaqueU // instead of GOpaque<T>
>;
using GProtoArgs = std::vector<GProtoArg>;

@ -14,6 +14,7 @@
#include <opencv2/gapi/gmat.hpp>
#include <opencv2/gapi/gscalar.hpp>
#include <opencv2/gapi/garray.hpp>
#include <opencv2/gapi/gopaque.hpp>
#include <opencv2/gapi/streaming/source.hpp>
#include <opencv2/gapi/gcommon.hpp>
#include <opencv2/gapi/own/convert.hpp>
@ -36,7 +37,8 @@ namespace detail
GMAT, // a cv::GMat
GMATP, // a cv::GMatP
GSCALAR, // a cv::GScalar
GARRAY, // a cv::GArrayU (note - exactly GArrayU, not GArray<T>!)
GARRAY, // a cv::GArrayU (note - exactly GArrayU, not GArray<T>!)
GOPAQUE, // a cv::GOpaqueU (note - exactly GOpaqueU, not GOpaque<T>!)
};
// Describe G-API types (G-types) with traits. Mostly used by
@ -73,6 +75,16 @@ namespace detail
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); }
};
template<class T> struct GTypeTraits<cv::GOpaque<T> >
{
static constexpr const ArgKind kind = ArgKind::GOPAQUE;
static constexpr const GShape shape = GShape::GOPAQUE;
using host_type = T;
using strip_type = cv::detail::OpaqueRef;
static cv::detail::GOpaqueU wrap_value(const cv::GOpaque<T> &t) { return t.strip();}
static cv::detail::OpaqueRef wrap_in (const T &t) { return detail::OpaqueRef(t); }
static cv::detail::OpaqueRef wrap_out ( T &t) { return detail::OpaqueRef(t); }
};
// Tests if Trait for type T requires extra marshalling ("custom wrap") or not.
// If Traits<T> has wrap_value() defined, it does.
@ -100,6 +112,7 @@ namespace detail
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>; };
template<typename U> struct GTypeOf { using type = cv::GOpaque<U>;};
// FIXME: This is not quite correct since IStreamSource may produce not only Mat but also Scalar
// and vector data. TODO: Extend the type dispatching on these types too.
template<> struct GTypeOf<cv::gapi::wip::IStreamSource::Ptr> { using type = cv::GMat;};
@ -164,7 +177,6 @@ namespace detail
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

@ -25,13 +25,15 @@ namespace detail
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 U> struct ProtoToParam<cv::GArray<U> > { using type = std::vector<U>; };
template<typename U> struct ProtoToParam<cv::GOpaque<U> > { using type = 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 U> struct ProtoToMeta<cv::GArray<U> > { using type = cv::GArrayDesc; };
template<typename U> struct ProtoToMeta<cv::GOpaque<U> > { using type = cv::GOpaqueDesc; };
template<typename T> using ProtoToMetaT = typename ProtoToMeta<T>::type;
//workaround for MSVC 19.0 bug

@ -68,9 +68,14 @@ public:
{
return outVecRef(output).wref<T>();
}
template<typename T> T& outOpaqueR(int output) // FIXME: the same issue
{
return outOpaqueRef(output).wref<T>();
}
protected:
detail::VectorRef& outVecRef(int output);
detail::VectorRef& outOpaqueRef(int output);
std::vector<GArg> m_args;
std::unordered_map<std::size_t, GRunArgP> m_results;
@ -111,6 +116,10 @@ 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<typename U> struct ocl_get_in<cv::GOpaque<U> >
{
static const U& get(GOCLContext &ctx, int idx) { return ctx.inArg<OpaqueRef>(idx).rref<U>(); }
};
template<class T> struct ocl_get_in
{
static T get(GOCLContext &ctx, int idx) { return ctx.inArg<T>(idx); }
@ -184,6 +193,10 @@ 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 U> struct ocl_get_out<cv::GOpaque<U> >
{
static U& get(GOCLContext &ctx, int idx) { return ctx.outOpaqueR<U>(idx); }
};
template<typename, typename, typename>
struct OCLCallHelper;

@ -168,6 +168,10 @@ void bindInArg(Mag& mag, const RcDesc &rc, const GRunArg &arg, bool is_umat)
mag.template slot<cv::detail::VectorRef>()[rc.id] = util::get<cv::detail::VectorRef>(arg);
break;
case GShape::GOPAQUE:
mag.template slot<cv::detail::OpaqueRef>()[rc.id] = util::get<cv::detail::OpaqueRef>(arg);
break;
default:
util::throw_error(std::logic_error("Unsupported GShape type"));
}
@ -233,6 +237,10 @@ void bindOutArg(Mag& mag, const RcDesc &rc, const GRunArgP &arg, bool is_umat)
mag.template slot<cv::detail::VectorRef>()[rc.id] = util::get<cv::detail::VectorRef>(arg);
break;
case GShape::GOPAQUE:
mag.template slot<cv::detail::OpaqueRef>()[rc.id] = util::get<cv::detail::OpaqueRef>(arg);
break;
default:
util::throw_error(std::logic_error("Unsupported GShape type"));
break;
@ -251,6 +259,11 @@ void resetInternalData(Mag& mag, const Data &d)
(mag.template slot<cv::detail::VectorRef>()[d.rc]);
break;
case GShape::GOPAQUE:
util::get<cv::detail::ConstructOpaque>(d.ctor)
(mag.template slot<cv::detail::OpaqueRef>()[d.rc]);
break;
case GShape::GSCALAR:
mag.template slot<cv::gapi::own::Scalar>()[d.rc] = cv::gapi::own::Scalar();
break;
@ -272,9 +285,10 @@ cv::GRunArg getArg(const Mag& mag, const RcDesc &ref)
{
case GShape::GMAT: return GRunArg(mag.template slot<cv::gapi::own::Mat>().at(ref.id));
case GShape::GSCALAR: return GRunArg(mag.template slot<cv::gapi::own::Scalar>().at(ref.id));
// Note: .at() is intentional for GArray as object MUST be already there
// Note: .at() is intentional for GArray and GOpaque as objects MUST be already there
// (and constructed by either bindIn/Out or resetInternal)
case GShape::GARRAY: return GRunArg(mag.template slot<cv::detail::VectorRef>().at(ref.id));
case GShape::GOPAQUE: return GRunArg(mag.template slot<cv::detail::OpaqueRef>().at(ref.id));
default:
util::throw_error(std::logic_error("Unsupported GShape type"));
break;
@ -297,7 +311,7 @@ cv::GRunArgP getObjPtr(Mag& mag, const RcDesc &rc, bool is_umat)
else
return GRunArgP(&mag.template slot<cv::gapi::own::Mat>()[rc.id]);
case GShape::GSCALAR: return GRunArgP(&mag.template slot<cv::gapi::own::Scalar>()[rc.id]);
// Note: .at() is intentional for GArray as object MUST be already there
// Note: .at() is intentional for GArray and GOpaque as objects MUST be already there
// (and constructor by either bindIn/Out or resetInternal)
case GShape::GARRAY:
// FIXME(DM): For some absolutely unknown to me reason, move
@ -307,6 +321,14 @@ cv::GRunArgP getObjPtr(Mag& mag, const RcDesc &rc, bool is_umat)
// debugging this!!!1
return GRunArgP(const_cast<const Mag&>(mag)
.template slot<cv::detail::VectorRef>().at(rc.id));
case GShape::GOPAQUE:
// FIXME(DM): For some absolutely unknown to me reason, move
// semantics is involved here without const_cast to const (and
// value from map is moved into return value GRunArgP, leaving
// map with broken value I've spent few late Friday hours
// debugging this!!!1
return GRunArgP(const_cast<const Mag&>(mag)
.template slot<cv::detail::OpaqueRef>().at(rc.id));
default:
util::throw_error(std::logic_error("Unsupported GShape type"));
break;
@ -320,6 +342,9 @@ void writeBack(const Mag& mag, const RcDesc &rc, GRunArgP &g_arg, bool is_umat)
case GShape::GARRAY:
// Do nothing - should we really do anything here?
break;
case GShape::GOPAQUE:
// Do nothing - should we really do anything here?
break;
case GShape::GMAT:
{

@ -64,6 +64,11 @@ cv::detail::GArrayU cv::GCall::yieldArray(int output)
return cv::detail::GArrayU(m_priv->m_node, output);
}
cv::detail::GOpaqueU cv::GCall::yieldOpaque(int output)
{
return cv::detail::GOpaqueU(m_priv->m_node, output);
}
cv::GCall::Priv& cv::GCall::priv()
{
return *m_priv;

@ -0,0 +1,45 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2019 Intel Corporation
#include "precomp.hpp"
#include <opencv2/gapi/gopaque.hpp>
#include "api/gorigin.hpp"
// cv::detail::GOpaqueU public implementation ///////////////////////////////////
cv::detail::GOpaqueU::GOpaqueU()
: m_priv(new GOrigin(GShape::GOPAQUE, cv::GNode::Param()))
{
}
cv::detail::GOpaqueU::GOpaqueU(const GNode &n, std::size_t out)
: m_priv(new GOrigin(GShape::GOPAQUE, n, out))
{
}
cv::GOrigin& cv::detail::GOpaqueU::priv()
{
return *m_priv;
}
const cv::GOrigin& cv::detail::GOpaqueU::priv() const
{
return *m_priv;
}
void cv::detail::GOpaqueU::setConstructFcn(ConstructOpaque &&co)
{
m_priv->ctor = std::move(co);
}
namespace cv {
std::ostream& operator<<(std::ostream& os, const cv::GOpaqueDesc &)
{
// FIXME: add type information here
os << "(Opaque)";
return os;
}
}

@ -34,6 +34,9 @@ const cv::GOrigin& cv::gimpl::proto::origin_of(const cv::GProtoArg &arg)
case cv::GProtoArg::index_of<cv::detail::GArrayU>():
return util::get<cv::detail::GArrayU>(arg).priv();
case cv::GProtoArg::index_of<cv::detail::GOpaqueU>():
return util::get<cv::detail::GOpaqueU>(arg).priv();
default:
util::throw_error(std::logic_error("Unsupported GProtoArg type"));
}
@ -59,6 +62,7 @@ bool cv::gimpl::proto::is_dynamic(const cv::GArg& arg)
case detail::ArgKind::GMATP:
case detail::ArgKind::GSCALAR:
case detail::ArgKind::GARRAY:
case detail::ArgKind::GOPAQUE:
return true;
default:
@ -85,6 +89,7 @@ cv::GProtoArg cv::gimpl::proto::rewrap(const cv::GArg &arg)
case detail::ArgKind::GMATP: return GProtoArg(arg.get<cv::GMatP>());
case detail::ArgKind::GSCALAR: return GProtoArg(arg.get<cv::GScalar>());
case detail::ArgKind::GARRAY: return GProtoArg(arg.get<cv::detail::GArrayU>());
case detail::ArgKind::GOPAQUE: return GProtoArg(arg.get<cv::detail::GOpaqueU>());
default: util::throw_error(std::logic_error("Unsupported GArg type"));
}
}
@ -110,6 +115,9 @@ cv::GMetaArg cv::descr_of(const cv::GRunArg &arg)
case GRunArg::index_of<cv::detail::VectorRef>():
return cv::GMetaArg(util::get<cv::detail::VectorRef>(arg).descr_of());
case GRunArg::index_of<cv::detail::OpaqueRef>():
return cv::GMetaArg(util::get<cv::detail::OpaqueRef>(arg).descr_of());
case GRunArg::index_of<cv::gapi::wip::IStreamSource::Ptr>():
return cv::util::get<cv::gapi::wip::IStreamSource::Ptr>(arg)->descr_of();
@ -136,6 +144,7 @@ cv::GMetaArg cv::descr_of(const cv::GRunArgP &argp)
case GRunArgP::index_of<cv::gapi::own::Mat*>(): return GMetaArg(descr_of(*util::get<cv::gapi::own::Mat*>(argp)));
case GRunArgP::index_of<cv::gapi::own::Scalar*>(): return GMetaArg(descr_of(*util::get<cv::gapi::own::Scalar*>(argp)));
case GRunArgP::index_of<cv::detail::VectorRef>(): return GMetaArg(util::get<cv::detail::VectorRef>(argp).descr_of());
case GRunArgP::index_of<cv::detail::OpaqueRef>(): return GMetaArg(util::get<cv::detail::OpaqueRef>(argp).descr_of());
default: util::throw_error(std::logic_error("Unsupported GRunArgP type"));
}
}
@ -154,6 +163,7 @@ bool cv::can_describe(const GMetaArg& meta, const GRunArgP& argp)
util::get<GMatDesc>(meta).canDescribe(*util::get<cv::gapi::own::Mat*>(argp));
case GRunArgP::index_of<cv::gapi::own::Scalar*>(): return meta == GMetaArg(descr_of(*util::get<cv::gapi::own::Scalar*>(argp)));
case GRunArgP::index_of<cv::detail::VectorRef>(): return meta == GMetaArg(util::get<cv::detail::VectorRef>(argp).descr_of());
case GRunArgP::index_of<cv::detail::OpaqueRef>(): return meta == GMetaArg(util::get<cv::detail::OpaqueRef>(argp).descr_of());
default: util::throw_error(std::logic_error("Unsupported GRunArgP type"));
}
}
@ -172,6 +182,7 @@ bool cv::can_describe(const GMetaArg& meta, const GRunArg& arg)
util::get<GMatDesc>(meta).canDescribe(util::get<cv::gapi::own::Mat>(arg));
case GRunArg::index_of<cv::gapi::own::Scalar>(): return meta == cv::GMetaArg(descr_of(util::get<cv::gapi::own::Scalar>(arg)));
case GRunArg::index_of<cv::detail::VectorRef>(): return meta == cv::GMetaArg(util::get<cv::detail::VectorRef>(arg).descr_of());
case GRunArg::index_of<cv::detail::OpaqueRef>(): return meta == cv::GMetaArg(util::get<cv::detail::OpaqueRef>(arg).descr_of());
case GRunArg::index_of<cv::gapi::wip::IStreamSource::Ptr>(): return util::holds_alternative<GMatDesc>(meta); // FIXME(?) may be not the best option
default: util::throw_error(std::logic_error("Unsupported GRunArg type"));
}
@ -207,6 +218,10 @@ std::ostream& operator<<(std::ostream& os, const cv::GMetaArg &arg)
case cv::GMetaArg::index_of<cv::GArrayDesc>():
os << util::get<cv::GArrayDesc>(arg);
break;
case cv::GMetaArg::index_of<cv::GOpaqueDesc>():
os << util::get<cv::GOpaqueDesc>(arg);
break;
default:
GAPI_Assert(false);
}

@ -46,9 +46,9 @@ namespace magazine {
} // namespace magazine
#if !defined(GAPI_STANDALONE)
using Mag = magazine::Class<cv::gapi::own::Mat, cv::UMat, cv::gapi::own::Scalar, cv::detail::VectorRef>;
using Mag = magazine::Class<cv::gapi::own::Mat, cv::UMat, cv::gapi::own::Scalar, cv::detail::VectorRef, cv::detail::OpaqueRef>;
#else
using Mag = magazine::Class<cv::gapi::own::Mat, cv::gapi::own::Scalar, cv::detail::VectorRef>;
using Mag = magazine::Class<cv::gapi::own::Mat, cv::gapi::own::Scalar, cv::detail::VectorRef, cv::detail::OpaqueRef>;
#endif
namespace magazine

@ -113,7 +113,8 @@ cv::GArg cv::gimpl::GCPUExecutable::packArg(const GArg &arg)
// FIXME: this check has to be done somewhere in compilation stage.
GAPI_Assert( arg.kind != cv::detail::ArgKind::GMAT
&& arg.kind != cv::detail::ArgKind::GSCALAR
&& arg.kind != cv::detail::ArgKind::GARRAY);
&& arg.kind != cv::detail::ArgKind::GARRAY
&& arg.kind != cv::detail::ArgKind::GOPAQUE);
if (arg.kind != cv::detail::ArgKind::GOBJREF)
{
@ -129,9 +130,10 @@ cv::GArg cv::gimpl::GCPUExecutable::packArg(const GArg &arg)
{
case GShape::GMAT: return GArg(m_res.slot<cv::gapi::own::Mat>() [ref.id]);
case GShape::GSCALAR: return GArg(m_res.slot<cv::gapi::own::Scalar>()[ref.id]);
// Note: .at() is intentional for GArray as object MUST be already there
// Note: .at() is intentional for GArray and GOpaque as objects MUST be already there
// (and constructed by either bindIn/Out or resetInternal)
case GShape::GARRAY: return GArg(m_res.slot<cv::detail::VectorRef>().at(ref.id));
case GShape::GOPAQUE: return GArg(m_res.slot<cv::detail::OpaqueRef>().at(ref.id));
default:
util::throw_error(std::logic_error("Unsupported GShape type"));
break;

@ -36,6 +36,11 @@ cv::detail::VectorRef& cv::GCPUContext::outVecRef(int output)
return util::get<cv::detail::VectorRef>(m_results.at(output));
}
cv::detail::OpaqueRef& cv::GCPUContext::outOpaqueRef(int output)
{
return util::get<cv::detail::OpaqueRef>(m_results.at(output));
}
cv::GCPUKernel::GCPUKernel()
{
}

@ -1250,6 +1250,7 @@ void cv::gimpl::GFluidExecutable::bindInArg(const cv::gimpl::RcDesc &rc, const G
case GShape::GMAT: m_buffers[m_id_map.at(rc.id)].priv().bindTo(util::get<cv::gapi::own::Mat>(arg), true); break;
case GShape::GSCALAR: m_res.slot<cv::gapi::own::Scalar>()[rc.id] = util::get<cv::gapi::own::Scalar>(arg); break;
case GShape::GARRAY: m_res.slot<cv::detail::VectorRef>()[rc.id] = util::get<cv::detail::VectorRef>(arg); break;
case GShape::GOPAQUE: m_res.slot<cv::detail::OpaqueRef>()[rc.id] = util::get<cv::detail::OpaqueRef>(arg); break;
}
}
@ -1292,7 +1293,8 @@ void cv::gimpl::GFluidExecutable::packArg(cv::GArg &in_arg, const cv::GArg &op_a
{
GAPI_Assert(op_arg.kind != cv::detail::ArgKind::GMAT
&& op_arg.kind != cv::detail::ArgKind::GSCALAR
&& op_arg.kind != cv::detail::ArgKind::GARRAY);
&& op_arg.kind != cv::detail::ArgKind::GARRAY
&& op_arg.kind != cv::detail::ArgKind::GOPAQUE);
if (op_arg.kind == cv::detail::ArgKind::GOBJREF)
{
@ -1305,6 +1307,10 @@ void cv::gimpl::GFluidExecutable::packArg(cv::GArg &in_arg, const cv::GArg &op_a
{
in_arg = GArg(m_res.slot<cv::detail::VectorRef>()[ref.id]);
}
else if (ref.shape == GShape::GOPAQUE)
{
in_arg = GArg(m_res.slot<cv::detail::OpaqueRef>()[ref.id]);
}
}
}

@ -129,7 +129,7 @@ class GFluidExecutable final: public GIslandExecutable
std::vector<FluidAgent*> m_script;
using Magazine = detail::magazine<cv::gapi::own::Scalar, cv::detail::VectorRef>;
using Magazine = detail::magazine<cv::gapi::own::Scalar, cv::detail::VectorRef, cv::detail::OpaqueRef>;
Magazine m_res;
std::size_t m_num_int_buffers; // internal buffers counter (m_buffers - num_scratch)

@ -31,6 +31,7 @@
#include <opencv2/gapi/gcommon.hpp>
#include <opencv2/gapi/garray.hpp>
#include <opencv2/gapi/gopaque.hpp>
#include <opencv2/gapi/util/any.hpp>
#include <opencv2/gapi/gtype_traits.hpp>
#include <opencv2/gapi/infer.hpp>
@ -396,6 +397,10 @@ cv::GArg cv::gimpl::ie::GIEExecutable::packArg(const cv::GArg &arg) {
// (and constructed by either bindIn/Out or resetInternal)
case GShape::GARRAY: return GArg(m_res.slot<cv::detail::VectorRef>().at(ref.id));
// Note: .at() is intentional for GOpaque as object MUST be already there
// (and constructed by either bindIn/Out or resetInternal)
case GShape::GOPAQUE: return GArg(m_res.slot<cv::detail::OpaqueRef>().at(ref.id));
default:
util::throw_error(std::logic_error("Unsupported GShape type"));
break;

@ -113,7 +113,8 @@ cv::GArg cv::gimpl::GOCLExecutable::packArg(const GArg &arg)
// FIXME: this check has to be done somewhere in compilation stage.
GAPI_Assert( arg.kind != cv::detail::ArgKind::GMAT
&& arg.kind != cv::detail::ArgKind::GSCALAR
&& arg.kind != cv::detail::ArgKind::GARRAY);
&& arg.kind != cv::detail::ArgKind::GARRAY
&& arg.kind != cv::detail::ArgKind::GOPAQUE);
if (arg.kind != cv::detail::ArgKind::GOBJREF)
{
@ -129,9 +130,12 @@ cv::GArg cv::gimpl::GOCLExecutable::packArg(const GArg &arg)
{
case GShape::GMAT: return GArg(m_res.slot<cv::UMat>()[ref.id]);
case GShape::GSCALAR: return GArg(m_res.slot<cv::gapi::own::Scalar>()[ref.id]);
// Note: .at() is intentional for GArray as object MUST be already there
// Note: .at() is intentional for GArray as object MUST be already there
// (and constructed by either bindIn/Out or resetInternal)
case GShape::GARRAY: return GArg(m_res.slot<cv::detail::VectorRef>().at(ref.id));
// Note: .at() is intentional for GOpaque as object MUST be already there
// (and constructed by either bindIn/Out or resetInternal)
case GShape::GOPAQUE: return GArg(m_res.slot<cv::detail::OpaqueRef>().at(ref.id));
default:
util::throw_error(std::logic_error("Unsupported GShape type"));
break;

@ -276,7 +276,8 @@ cv::GArg cv::gimpl::GPlaidMLExecutable::packArg(const GArg &arg)
{
GAPI_Assert( arg.kind != cv::detail::ArgKind::GMAT
&& arg.kind != cv::detail::ArgKind::GSCALAR
&& arg.kind != cv::detail::ArgKind::GARRAY);
&& arg.kind != cv::detail::ArgKind::GARRAY
&& arg.kind != cv::detail::ArgKind::GOPAQUE);
if (arg.kind != cv::detail::ArgKind::GOBJREF)
{

@ -332,6 +332,9 @@ void cv::gimpl::GCompiler::validateInputMeta()
case GProtoArg::index_of<cv::detail::GArrayU>():
return util::holds_alternative<cv::GArrayDesc>(meta);
case GProtoArg::index_of<cv::detail::GOpaqueU>():
return util::holds_alternative<cv::GOpaqueDesc>(meta);
default:
GAPI_Assert(false);
}

@ -16,13 +16,14 @@ namespace cv
namespace gimpl
{
// Union type for various user-defined type constructors (GArray<T>, etc)
// Union type for various user-defined type constructors (GArray<T>, GOpaque<T>, etc)
// FIXME: Replace construct-only API with a more generic one
// (probably with bits of introspection)
// Not required for non-user-defined types (GMat, GScalar, etc)
using HostCtor = util::variant
< util::monostate
, detail::ConstructVec
, detail::ConstructOpaque
>;
using ConstVal = util::variant

@ -32,6 +32,7 @@ void dumpDot(const ade::Graph &g, std::ostream& os)
{cv::GShape::GMAT, "GMat"},
{cv::GShape::GSCALAR, "GScalar"},
{cv::GShape::GARRAY, "GArray"},
{cv::GShape::GOPAQUE, "GOpaque"},
};
auto format_op_label = [&gr](ade::NodeHandle nh) -> std::string {

@ -0,0 +1,197 @@
// 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
#include "test_precomp.hpp"
#include <string>
#include <utility>
namespace opencv_test
{
namespace ThisTest
{
using GPointOpaque = cv::GOpaque<cv::Point>;
G_TYPED_KERNEL(GeneratePoint, <GPointOpaque(GMat)>, "test.opaque.gen_point")
{
static GOpaqueDesc outMeta(const GMatDesc&) { return empty_gopaque_desc(); }
};
G_TYPED_KERNEL(FillMat, <GMat(cv::GOpaque<int>, int, int, cv::Size)>, "test.opaque.fill_mat")
{
static GMatDesc outMeta(const GOpaqueDesc&, int depth, int chan, cv::Size size)
{
return cv::GMatDesc{depth, chan, size};
}
};
G_TYPED_KERNEL(PaintPoint, <GMat(GPointOpaque, int, int, cv::Size)>, "test.opaque.paint_point")
{
static GMatDesc outMeta(const GOpaqueDesc&, int depth, int chan, cv::Size size)
{
return cv::GMatDesc{depth, chan, size};
}
};
struct MyCustomType{
int num;
std::string s;
};
using GOpaq2 = std::tuple<GOpaque<MyCustomType>,GOpaque<MyCustomType>>;
G_TYPED_KERNEL_M(GenerateOpaque, <GOpaq2(GMat, GMat, std::string)>, "test.opaque.gen_point_multy")
{
static std::tuple<GOpaqueDesc, GOpaqueDesc> outMeta(const GMatDesc&, const GMatDesc&, std::string)
{
return std::make_tuple(empty_gopaque_desc(), empty_gopaque_desc());
}
};
} // namespace ThisTest
namespace
{
GAPI_OCV_KERNEL(OCVGeneratePoint, ThisTest::GeneratePoint)
{
static void run(const cv::Mat&, cv::Point& out)
{
out = cv::Point(42, 42);
}
};
GAPI_OCV_KERNEL(OCVFillMat, ThisTest::FillMat)
{
static void run(int a, int, int, cv::Size, cv::Mat& out)
{
out = cv::Scalar(a);
}
};
GAPI_OCV_KERNEL(OCVPaintPoint, ThisTest::PaintPoint)
{
static void run(cv::Point a, int, int, cv::Size, cv::Mat& out)
{
out.at<uint8_t>(a) = 77;
}
};
GAPI_OCV_KERNEL(OCVGenerateOpaque, ThisTest::GenerateOpaque)
{
static void run(const cv::Mat& a, const cv::Mat& b, const std::string& s,
ThisTest::MyCustomType &out1, ThisTest::MyCustomType &out2)
{
out1.num = a.size().width * a.size().height;
out1.s = s;
out2.num = b.size().width * b.size().height;
auto s2 = s;
std::reverse(s2.begin(), s2.end());
out2.s = s2;
}
};
} // (anonymous namespace)
TEST(GOpaque, TestOpaqueOut)
{
cv::Mat input = cv::Mat(52, 52, CV_8U);
cv::Point point;
cv::GMat in;
auto out = ThisTest::GeneratePoint::on(in);
cv::GComputation c(cv::GIn(in), cv::GOut(out));
c.apply(cv::gin(input), cv::gout(point), cv::compile_args(cv::gapi::kernels<OCVGeneratePoint>()));
EXPECT_TRUE(point == cv::Point(42, 42));
}
TEST(GOpaque, TestOpaqueIn)
{
cv::Size sz = {42, 42};
int depth = CV_8U;
int chan = 1;
cv::Mat mat = cv::Mat(sz, CV_MAKETYPE(depth, chan));
int fill = 0;
cv::GOpaque<int> in;
auto out = ThisTest::FillMat::on(in, depth, chan, sz);
cv::GComputation c(cv::GIn(in), cv::GOut(out));
c.apply(cv::gin(fill), cv::gout(mat), cv::compile_args(cv::gapi::kernels<OCVFillMat>()));
auto diff = cv::Mat(sz, CV_MAKETYPE(depth, chan), cv::Scalar(fill)) - mat;
EXPECT_EQ(cv::countNonZero(diff), 0);
}
TEST(GOpaque, TestOpaqueBetween)
{
cv::Size sz = {50, 50};
int depth = CV_8U;
int chan = 1;
cv::Mat mat_in = cv::Mat::zeros(sz, CV_MAKETYPE(depth, chan));
cv::Mat mat_out = cv::Mat::zeros(sz, CV_MAKETYPE(depth, chan));
cv::GMat in, out;
auto betw = ThisTest::GeneratePoint::on(in);
out = ThisTest::PaintPoint::on(betw, depth, chan, sz);
cv::GComputation c(cv::GIn(in), cv::GOut(out));
c.apply(cv::gin(mat_in), cv::gout(mat_out), cv::compile_args(cv::gapi::kernels<OCVGeneratePoint, OCVPaintPoint>()));
int painted = mat_out.at<uint8_t>(42, 42);
EXPECT_EQ(painted, 77);
}
TEST(GOpaque, TestOpaqueCustomOut2)
{
cv::Mat input1 = cv::Mat(52, 52, CV_8U);
cv::Mat input2 = cv::Mat(42, 42, CV_8U);
std::string str = "opaque";
std::string str2 = str;
std::reverse(str2.begin(), str2.end());
ThisTest::MyCustomType out1, out2;
cv::GMat in1, in2;
auto out = ThisTest::GenerateOpaque::on(in1, in2, str);
cv::GComputation c(cv::GIn(in1, in2), cv::GOut(std::get<0>(out), std::get<1>(out)));
c.apply(cv::gin(input1, input2), cv::gout(out1, out2), cv::compile_args(cv::gapi::kernels<OCVGenerateOpaque>()));
EXPECT_EQ(out1.num, input1.size().width * input1.size().height);
EXPECT_EQ(out1.s, str);
EXPECT_EQ(out2.num, input2.size().width * input2.size().height);
EXPECT_EQ(out2.s, str2);
}
TEST(GOpaque_OpaqueRef, TestMov)
{
// Warning: this test is testing some not-very-public APIs
// Test how OpaqueRef's mov() (aka poor man's move()) is working.
using I = std::string;
std::string str = "this string must be long due to short string optimization";
const I gold(str);
I test = gold;
const char* ptr = test.data();
cv::detail::OpaqueRef ref(test);
cv::detail::OpaqueRef mov;
mov.reset<I>();
EXPECT_EQ(gold, ref.rref<I>()); // ref = gold
mov.mov(ref);
EXPECT_EQ(gold, mov.rref<I>()); // mov obtained the data
EXPECT_EQ(ptr, mov.rref<I>().data()); // pointer is unchanged (same data)
EXPECT_EQ(test, ref.rref<I>()); // ref = test
EXPECT_NE(test, mov.rref<I>()); // ref lost the data
}
} // namespace opencv_test

@ -22,10 +22,27 @@ using GMat2 = std::tuple<GMat, GMat>;
using GMat3 = std::tuple<GMat, GMat, GMat>;
using GScalar = cv::GScalar;
template <typename T> using GArray = cv::GArray<T>;
template <typename T> using GOpaque = cv::GOpaque<T>;
using ArrayT = int;
using WrongArrayT = char;
struct CustomType{
cv::Mat mat;
int i;
void *v;
CustomType* next;
};
struct AnotherCustomType{
cv::Mat mat;
int i;
void *v;
};
using OpaqueT = CustomType;
using WrongOpaqueT = AnotherCustomType;
GAPI_TRANSFORM(gmat_in_gmat_out, <GMat(GMat)>, "gmat_in_gmat_out")
{
static GMat pattern(GMat) { return {}; }
@ -92,6 +109,36 @@ GAPI_TRANSFORM(gmat_gsc_garray_in_gmat2_out, <GMat2(GMat, GScalar, GArray<ArrayT
static GMat2 substitute(GMat, GScalar, GArray<ArrayT>) { return {}; }
};
GAPI_TRANSFORM(gop_in_gmat_out, <GMat(GOpaque<OpaqueT>)>, "gop_in_gmat_out")
{
static GMat pattern(GOpaque<OpaqueT>) { return {}; }
static GMat substitute(GOpaque<OpaqueT>) { return {}; }
};
GAPI_TRANSFORM(gmat_in_gop_out, <GOpaque<OpaqueT>(GMat)>, "gmat_in_gop_out")
{
static GOpaque<OpaqueT> pattern(GMat) { return {}; }
static GOpaque<OpaqueT> substitute(GMat) { return {}; }
};
GAPI_TRANSFORM(gop_in_gscalar_out, <GScalar(GOpaque<OpaqueT>)>, "gop_in_gscalar_out")
{
static GScalar pattern(GOpaque<OpaqueT>) { return {}; }
static GScalar substitute(GOpaque<OpaqueT>) { return {}; }
};
GAPI_TRANSFORM(gscalar_in_gop_out, <GOpaque<OpaqueT>(GScalar)>, "gscalar_in_gop_out")
{
static GOpaque<OpaqueT> pattern(GScalar) { return {}; }
static GOpaque<OpaqueT> substitute(GScalar) { return {}; }
};
GAPI_TRANSFORM(gmat_gsc_gopaque_in_gmat2_out, <GMat2(GMat, GScalar, GOpaque<OpaqueT>)>, "gmat_gsc_gopaque_in_gmat2_out")
{
static GMat2 pattern(GMat, GScalar, GOpaque<OpaqueT>) { return {}; }
static GMat2 substitute(GMat, GScalar, GOpaque<OpaqueT>) { return {}; }
};
} // anonymous namespace
TEST(KernelPackageTransform, CreatePackage)
@ -108,10 +155,15 @@ TEST(KernelPackageTransform, CreatePackage)
, garr_in_gscalar_out
, gscalar_in_garr_out
, gmat_gsc_garray_in_gmat2_out
, gop_in_gmat_out
, gmat_in_gop_out
, gop_in_gscalar_out
, gscalar_in_gop_out
, gmat_gsc_gopaque_in_gmat2_out
>();
auto tr = pkg.get_transformations();
EXPECT_EQ(11u, tr.size());
EXPECT_EQ(16u, tr.size());
}
TEST(KernelPackageTransform, Include)
@ -164,6 +216,29 @@ TEST(KernelPackageTransform, gmat_gsc_garray_in_gmat2_out)
check(tr.substitute());
}
TEST(KernelPackageTransform, gmat_gsc_gopaque_in_gmat2_out)
{
auto tr = gmat_gsc_gopaque_in_gmat2_out::transformation();
auto check = [](const cv::GComputation &comp){
const auto &p = comp.priv();
EXPECT_EQ(3u, p.m_ins.size());
EXPECT_EQ(2u, p.m_outs.size());
EXPECT_TRUE(ProtoContainsT<GMat>(p.m_ins[0]));
EXPECT_TRUE(ProtoContainsT<GScalar>(p.m_ins[1]));
EXPECT_TRUE(ProtoContainsT<cv::detail::GOpaqueU>(p.m_ins[2]));
EXPECT_TRUE(cv::util::get<cv::detail::GOpaqueU>(p.m_ins[2]).holds<OpaqueT>());
EXPECT_FALSE(cv::util::get<cv::detail::GOpaqueU>(p.m_ins[2]).holds<WrongOpaqueT>());
EXPECT_TRUE(ProtoContainsT<GMat>(p.m_outs[0]));
EXPECT_TRUE(ProtoContainsT<GMat>(p.m_outs[1]));
};
check(tr.pattern());
check(tr.substitute());
}
namespace
{
template<typename ArgT>
@ -176,7 +251,17 @@ namespace
}
template<typename ArgT>
typename std::enable_if<(cv::detail::GTypeTraits<ArgT>::kind != cv::detail::ArgKind::GARRAY), void>::type
typename std::enable_if<(cv::detail::GTypeTraits<ArgT>::kind == cv::detail::ArgKind::GOPAQUE), void>::type
arg_check(const cv::GProtoArg &arg)
{
EXPECT_TRUE(ProtoContainsT<cv::detail::GOpaqueU>(arg));
EXPECT_TRUE(cv::util::get<cv::detail::GOpaqueU>(arg).holds<OpaqueT>());
EXPECT_FALSE(cv::util::get<cv::detail::GOpaqueU>(arg).holds<WrongOpaqueT>());
}
template<typename ArgT>
typename std::enable_if<(cv::detail::GTypeTraits<ArgT>::kind != cv::detail::ArgKind::GARRAY &&
cv::detail::GTypeTraits<ArgT>::kind != cv::detail::ArgKind::GOPAQUE), void>::type
arg_check(const cv::GProtoArg &arg)
{
EXPECT_TRUE(ProtoContainsT<ArgT>(arg));
@ -242,4 +327,24 @@ TEST(KernelPackageTransform, gscalar_in_garr_out)
transformTest<gscalar_in_garr_out, GScalar, GArray<ArrayT>>();
}
TEST(KernelPackageTransform, gop_in_gmat_out)
{
transformTest<gop_in_gmat_out, GOpaque<OpaqueT>, GMat>();
}
TEST(KernelPackageTransform, gmat_in_gop_out)
{
transformTest<gmat_in_gop_out, GMat, GOpaque<OpaqueT>>();
}
TEST(KernelPackageTransform, gop_in_gscalar_out)
{
transformTest<gop_in_gscalar_out, GOpaque<OpaqueT>, GScalar>();
}
TEST(KernelPackageTransform, gscalar_in_gop_out)
{
transformTest<gscalar_in_gop_out, GScalar, GOpaque<OpaqueT>>();
}
} // namespace opencv_test

@ -37,6 +37,10 @@ using GArg_Test_Types = ::testing::Types
, Expected<cv::GArray<float>, cv::detail::ArgKind::GARRAY>
, Expected<cv::GArray<cv::Point>, cv::detail::ArgKind::GARRAY>
, Expected<cv::GArray<cv::Rect>, cv::detail::ArgKind::GARRAY>
, Expected<cv::GOpaque<int>, cv::detail::ArgKind::GOPAQUE>
, Expected<cv::GOpaque<float>, cv::detail::ArgKind::GOPAQUE>
, Expected<cv::GOpaque<cv::Point>, cv::detail::ArgKind::GOPAQUE>
, Expected<cv::GOpaque<cv::Rect>, cv::detail::ArgKind::GOPAQUE>
// Built-in types
, Expected<int, cv::detail::ArgKind::OPAQUE_VAL>
@ -85,6 +89,11 @@ TEST(GArg, HasWrap)
"GArray<int> has custom marshalling logic");
static_assert(cv::detail::has_custom_wrap<cv::GArray<std::string> >::value,
"GArray<int> has custom marshalling logic");
static_assert(cv::detail::has_custom_wrap<cv::GOpaque<int> >::value,
"GOpaque<int> has custom marshalling logic");
static_assert(cv::detail::has_custom_wrap<cv::GOpaque<std::string> >::value,
"GOpaque<int> has custom marshalling logic");
}
TEST(GArg, GArrayU)
@ -97,5 +106,15 @@ TEST(GArg, GArrayU)
EXPECT_NO_THROW(arg2.get<cv::detail::GArrayU>());
}
TEST(GArg, GOpaqueU)
{
// Placing a GOpaque<T> into GArg automatically strips it to GOpaqueU
cv::GArg arg1 = cv::GArg(cv::GOpaque<int>());
EXPECT_NO_THROW(arg1.get<cv::detail::GOpaqueU>());
cv::GArg arg2 = cv::GArg(cv::GOpaque<cv::Point>());
EXPECT_NO_THROW(arg2.get<cv::detail::GOpaqueU>());
}
} // namespace opencv_test

Loading…
Cancel
Save