mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
440 lines
16 KiB
440 lines
16 KiB
// 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-2020 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 GAPI_EXPORTS_W_SIMPLE 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 {};} |
|
GAPI_EXPORTS_W 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 |
|
GArrayU(const detail::VectorRef& vref); // Constant value 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> |
|
|
|
template <typename T> |
|
void storeKind(); |
|
|
|
void setKind(cv::detail::OpaqueKind); |
|
|
|
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>); |
|
}; |
|
|
|
template <typename T> |
|
void GArrayU::storeKind(){ |
|
setKind(cv::detail::GOpaqueTraits<T>::kind); |
|
}; |
|
|
|
// 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: |
|
// These fields are set by the derived class(es) |
|
std::size_t m_elemSize = 0ul; |
|
cv::GArrayDesc m_desc; |
|
virtual ~BasicVectorRef() {} |
|
|
|
virtual void mov(BasicVectorRef &ref) = 0; |
|
virtual const void* ptr() const = 0; |
|
virtual std::size_t size() const = 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_Error("InternalError"); // 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()); |
|
} |
|
|
|
virtual const void* ptr() const override { return &rref(); } |
|
virtual std::size_t size() const override { return rref().size(); } |
|
}; |
|
|
|
// 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; |
|
cv::detail::OpaqueKind m_kind = cv::detail::OpaqueKind::CV_UNKNOWN; |
|
|
|
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)) |
|
, m_kind(GOpaqueTraits<T>::kind) |
|
{} |
|
template<typename T> explicit VectorRef(std::vector<T>& vec) |
|
: m_ref(new VectorRefT<T>(vec)) |
|
, m_kind(GOpaqueTraits<T>::kind) |
|
{} |
|
template<typename T> explicit VectorRef(std::vector<T>&& vec) |
|
: m_ref(new VectorRefT<T>(std::move(vec))) |
|
, m_kind(GOpaqueTraits<T>::kind) |
|
{} |
|
|
|
cv::detail::OpaqueKind getKind() const |
|
{ |
|
return m_kind; |
|
} |
|
|
|
template<typename T> void reset() |
|
{ |
|
if (!m_ref) m_ref.reset(new VectorRefT<T>()); |
|
check<T>(); |
|
storeKind<T>(); |
|
static_cast<VectorRefT<T>&>(*m_ref).reset(); |
|
} |
|
|
|
template <typename T> |
|
void storeKind() |
|
{ |
|
m_kind = cv::detail::GOpaqueTraits<T>::kind; |
|
} |
|
|
|
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(); |
|
} |
|
|
|
// Check if was created for/from std::vector<T> |
|
template <typename T> bool holds() const |
|
{ |
|
if (!m_ref) return false; |
|
using U = typename std::decay<T>::type; |
|
return dynamic_cast<VectorRefT<U>*>(m_ref.get()) != nullptr; |
|
} |
|
|
|
void mov(VectorRef &v) |
|
{ |
|
m_ref->mov(*v.m_ref); |
|
} |
|
|
|
cv::GArrayDesc descr_of() const |
|
{ |
|
return m_ref->m_desc; |
|
} |
|
|
|
std::size_t size() const |
|
{ |
|
return m_ref->size(); |
|
} |
|
|
|
// May be used to uniquely identify this object internally |
|
const void *ptr() const { return m_ref->ptr(); } |
|
}; |
|
|
|
// 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<GArray<T>> { using type = std::vector<T>; }; |
|
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 |
|
* @{ |
|
*/ |
|
/** |
|
* @brief `cv::GArray<T>` template class represents a list of objects |
|
* of class `T` in the graph. |
|
* |
|
* `cv::GArray<T>` describes a functional relationship between |
|
* operations consuming and producing arrays of objects of class |
|
* `T`. The primary purpose of `cv::GArray<T>` is to represent a |
|
* dynamic list of objects -- where the size of the list is not known |
|
* at the graph construction or compile time. Examples include: corner |
|
* and feature detectors (`cv::GArray<cv::Point>`), object detection |
|
* and tracking results (`cv::GArray<cv::Rect>`). Programmers can use |
|
* their own types with `cv::GArray<T>` in the custom operations. |
|
* |
|
* Similar to `cv::GScalar`, `cv::GArray<T>` may be value-initialized |
|
* -- in this case a graph-constant value is associated with the object. |
|
* |
|
* `GArray<T>` is a virtual counterpart of `std::vector<T>`, which is |
|
* usually used to represent the `GArray<T>` data in G-API during the |
|
* execution. |
|
* |
|
* @sa `cv::GOpaque<T>` |
|
*/ |
|
template<typename T> class GArray |
|
{ |
|
public: |
|
// Host type (or Flat type) - the type this GArray is actually |
|
// specified to. |
|
/// @private |
|
using HT = typename detail::flatten_g<typename std::decay<T>::type>::type; |
|
|
|
/** |
|
* @brief Constructs a value-initialized `cv::GArray<T>` |
|
* |
|
* `cv::GArray<T>` objects may have their values |
|
* be associated at graph construction time. It is useful when |
|
* some operation has a `cv::GArray<T>` input which doesn't change during |
|
* the program execution, and is set only once. In this case, |
|
* there is no need to declare such `cv::GArray<T>` as a graph input. |
|
* |
|
* @note The value of `cv::GArray<T>` may be overwritten by assigning some |
|
* other `cv::GArray<T>` to the object using `operator=` -- on the |
|
* assignment, the old association or value is discarded. |
|
* |
|
* @param v a std::vector<T> to associate with this |
|
* `cv::GArray<T>` object. Vector data is copied into the |
|
* `cv::GArray<T>` (no reference to the passed data is held). |
|
*/ |
|
explicit GArray(const std::vector<HT>& v) // Constant value constructor |
|
: m_ref(detail::GArrayU(detail::VectorRef(v))) { putDetails(); } |
|
|
|
/** |
|
* @overload |
|
* @brief Constructs a value-initialized `cv::GArray<T>` |
|
* |
|
* @param v a std::vector<T> to associate with this |
|
* `cv::GArray<T>` object. Vector data is moved into the `cv::GArray<T>`. |
|
*/ |
|
explicit GArray(std::vector<HT>&& v) // Move-constructor |
|
: m_ref(detail::GArrayU(detail::VectorRef(std::move(v)))) { putDetails(); } |
|
|
|
/** |
|
* @brief Constructs an empty `cv::GArray<T>` |
|
* |
|
* Normally, empty G-API data objects denote a starting point of |
|
* the graph. When an empty `cv::GArray<T>` is assigned to a result |
|
* of some operation, it obtains a functional link to this |
|
* operation (and is not empty anymore). |
|
*/ |
|
GArray() { putDetails(); } // Empty constructor |
|
|
|
/// @private |
|
explicit GArray(detail::GArrayU &&ref) // GArrayU-based constructor |
|
: m_ref(ref) { putDetails(); } // (used by GCall, not for users) |
|
|
|
/// @private |
|
detail::GArrayU strip() const { |
|
return m_ref; |
|
} |
|
/// @private |
|
static void VCtor(detail::VectorRef& vref) { |
|
vref.reset<HT>(); |
|
} |
|
|
|
private: |
|
void putDetails() { |
|
m_ref.setConstructFcn(&VCtor); |
|
m_ref.specifyType<HT>(); // FIXME: to unify those 2 to avoid excessive dynamic_cast |
|
m_ref.storeKind<HT>(); // |
|
} |
|
|
|
detail::GArrayU m_ref; |
|
}; |
|
|
|
/** @} */ |
|
|
|
} // namespace cv |
|
|
|
#endif // OPENCV_GAPI_GARRAY_HPP
|
|
|