Merge pull request #15090 from dmatveev:dm/ng-0001-g-api-inference-api
* G-API-NG/API: Introduced inference API and IE-based backend - Very quick-n-dirty implementation - OpenCV's own DNN module is not used - No tests so far * G-API-NG/IE: Refined IE backend, added more tests * G-API-NG/IE: Fixed various CI warnings & build issues + tests - Added tests on multi-dimensional own::Mat - Added tests on GMatDesc with dimensions - Documentation on infer.hpp - Fixed more warnings + added a ROI list test - Fix descr_of clash for vector<Mat> & standalone mode - Fix build issue with gcc-4.8x - Addressed review comments * G-API-NG/IE: Addressed review comments - Pass `false` to findDataFile() - Add deprecation warning suppression macros for IE
This commit is contained in:
committed by
Alexander Alekhin
parent
59b0314a0e
commit
0757a51e2b
@@ -20,6 +20,9 @@
|
||||
#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
|
||||
@@ -247,6 +250,24 @@ namespace detail
|
||||
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
|
||||
@@ -263,10 +284,16 @@ public:
|
||||
detail::GArrayU strip() const { return m_ref; }
|
||||
|
||||
private:
|
||||
static void VCTor(detail::VectorRef& vref) { vref.reset<T>(); }
|
||||
// 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<T>();
|
||||
m_ref.specifyType<HT>();
|
||||
}
|
||||
|
||||
detail::GArrayU m_ref;
|
||||
|
||||
@@ -36,8 +36,9 @@ 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
|
||||
const GShapes outShapes; // types (shapes) kernel's outputs
|
||||
};
|
||||
|
||||
// GKernelImpl describes particular kernel implementation to the system
|
||||
@@ -166,6 +167,12 @@ namespace detail
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 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()
|
||||
@@ -175,8 +182,9 @@ namespace detail
|
||||
// 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...>>
|
||||
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...>)
|
||||
@@ -190,7 +198,7 @@ public:
|
||||
|
||||
static std::tuple<R...> on(Args... args)
|
||||
{
|
||||
cv::GCall call(GKernel{K::id(), &K::getOutMeta, {detail::GTypeTraits<R>::shape...}});
|
||||
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());
|
||||
}
|
||||
@@ -199,8 +207,9 @@ public:
|
||||
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>
|
||||
class GKernelType<K, std::function<R(Args...)> >
|
||||
: public detail::MetaHelper<K, std::tuple<Args...>, R>
|
||||
, public detail::NoTag
|
||||
{
|
||||
public:
|
||||
using InArgs = std::tuple<Args...>;
|
||||
@@ -208,7 +217,7 @@ public:
|
||||
|
||||
static R on(Args... args)
|
||||
{
|
||||
cv::GCall call(GKernel{K::id(), &K::getOutMeta, {detail::GTypeTraits<R>::shape}});
|
||||
cv::GCall call(GKernel{K::id(), K::tag(), &K::getOutMeta, {detail::GTypeTraits<R>::shape}});
|
||||
call.pass(args...);
|
||||
return detail::Yield<R>::yield(call, 0);
|
||||
}
|
||||
@@ -244,6 +253,9 @@ public:
|
||||
public detail::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
|
||||
@@ -437,6 +449,7 @@ namespace gapi {
|
||||
return includesAPI(KAPI::id());
|
||||
}
|
||||
|
||||
// FIXME: The below comment is wrong, and who needs this function?
|
||||
/**
|
||||
* @brief Find a kernel (by its API)
|
||||
*
|
||||
|
||||
@@ -69,15 +69,26 @@ struct GAPI_EXPORTS GMatDesc
|
||||
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;
|
||||
return depth == rhs.depth
|
||||
&& chan == rhs.chan
|
||||
&& size == rhs.size
|
||||
&& planar == rhs.planar
|
||||
&& dims == rhs.dims;
|
||||
}
|
||||
|
||||
inline bool operator!= (const GMatDesc &rhs) const
|
||||
@@ -85,6 +96,8 @@ struct GAPI_EXPORTS GMatDesc
|
||||
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)
|
||||
|
||||
@@ -61,13 +61,15 @@ namespace detail
|
||||
|
||||
} // 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 descr_of(const std::vector<cv::Mat> &vec);
|
||||
GAPI_EXPORTS cv::GMetaArgs descr_of(const std::vector<cv::UMat> &vec);
|
||||
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 descr_of(const std::vector<Mat> &vec);
|
||||
GAPI_EXPORTS cv::GMetaArgs descrs_of(const std::vector<Mat> &vec);
|
||||
}} // namespace gapi::own
|
||||
|
||||
} // namespace cv
|
||||
|
||||
@@ -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) 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 apprpriate 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
|
||||
};
|
||||
|
||||
/**
|
||||
* @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 {
|
||||
explicit GNetPackage(std::initializer_list<GNetParam> &&ii = {});
|
||||
std::vector<GBackend> backends() const;
|
||||
std::vector<GNetParam> networks;
|
||||
};
|
||||
} // 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
|
||||
@@ -0,0 +1,106 @@
|
||||
// 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
|
||||
|
||||
#ifdef HAVE_INF_ENGINE
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <tuple> // tuple, tuple_size
|
||||
|
||||
#include <opencv2/gapi/opencv_includes.hpp>
|
||||
#include <opencv2/gapi/util/any.hpp>
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
// FIXME: introduce a new sub-namespace for NN?
|
||||
namespace ie {
|
||||
|
||||
GAPI_EXPORTS cv::gapi::GBackend backend();
|
||||
|
||||
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;
|
||||
|
||||
std::unordered_map<std::string, cv::Mat> 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) {
|
||||
desc.const_inputs[layer_name] = data;
|
||||
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 // HAVE_INF_ENGINE
|
||||
|
||||
#endif // OPENCV_GAPI_INFER_HPP
|
||||
@@ -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) 2019 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_INFER_IE_UTIL_HPP
|
||||
#define OPENCV_GAPI_INFER_IE_UTIL_HPP
|
||||
|
||||
#ifdef HAVE_INF_ENGINE
|
||||
|
||||
// NOTE: This file is not included by default in infer/ie.hpp
|
||||
// and won't be. infer/ie.hpp doesn't depend on IE headers itself.
|
||||
// This file does -- so needs to be included separately by those who care.
|
||||
|
||||
#include "inference_engine.hpp"
|
||||
|
||||
namespace cv {
|
||||
namespace gapi {
|
||||
namespace ie {
|
||||
namespace util {
|
||||
|
||||
GAPI_EXPORTS std::vector<int> to_ocv(const InferenceEngine::SizeVector &dims);
|
||||
|
||||
GAPI_EXPORTS cv::Mat to_ocv(InferenceEngine::Blob::Ptr blob);
|
||||
GAPI_EXPORTS InferenceEngine::Blob::Ptr to_ie(cv::Mat &blob);
|
||||
|
||||
}}}}
|
||||
|
||||
#endif // HAVE_INF_ENGINE
|
||||
#endif // OPENCV_GAPI_INFER_IE_UTIL_HPP
|
||||
@@ -17,8 +17,23 @@
|
||||
|
||||
namespace cv
|
||||
{
|
||||
inline cv::gapi::own::Mat to_own(Mat const& m) { return {m.rows, m.cols, m.type(), m.data, m.step};};
|
||||
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]}; };
|
||||
|
||||
@@ -32,7 +47,11 @@ namespace gapi
|
||||
{
|
||||
namespace own
|
||||
{
|
||||
inline cv::Mat to_ocv(Mat const& m) { return {m.rows, m.cols, m.type(), m.data, m.step};};
|
||||
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]}; };
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#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 {
|
||||
@@ -49,6 +50,10 @@ namespace cv { namespace gapi { namespace own {
|
||||
: 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
|
||||
{
|
||||
@@ -74,8 +79,10 @@ namespace cv { namespace gapi { namespace own {
|
||||
//! 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:
|
||||
@@ -100,6 +107,14 @@ namespace cv { namespace gapi { namespace own {
|
||||
: 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)
|
||||
{
|
||||
@@ -120,9 +135,6 @@ namespace cv { namespace gapi { namespace own {
|
||||
Mat& operator = (const Scalar& s)
|
||||
{
|
||||
constexpr unsigned max_channels = 4; //Scalar can't fit more than 4
|
||||
const auto channels = static_cast<unsigned int>(this->channels());
|
||||
GAPI_Assert(channels <= max_channels);
|
||||
|
||||
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>}
|
||||
@@ -145,10 +157,22 @@ namespace cv { namespace gapi { namespace own {
|
||||
const auto depth = static_cast<unsigned int>(this->depth());
|
||||
GAPI_Assert(depth < sizeof(func_tbl)/sizeof(func_tbl[0]));
|
||||
|
||||
for (int r = 0; r < rows; ++r)
|
||||
if (dims.empty())
|
||||
{
|
||||
auto* f = func_tbl[depth][channels -1];
|
||||
(*f)(static_cast<void *>(ptr(r)), cols, s );
|
||||
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;
|
||||
}
|
||||
@@ -187,8 +211,9 @@ namespace cv { namespace gapi { namespace own {
|
||||
/** @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 CV_MAT_CN(flags);}
|
||||
int channels() const {return dims.empty() ? CV_MAT_CN(flags) : -1;}
|
||||
|
||||
/**
|
||||
@param _rows New number of rows.
|
||||
@@ -197,7 +222,7 @@ namespace cv { namespace gapi { namespace own {
|
||||
*/
|
||||
void create(int _rows, int _cols, int _type)
|
||||
{
|
||||
create({_cols, _rows}, _type);
|
||||
create(Size{_cols, _rows}, _type);
|
||||
}
|
||||
/** @overload
|
||||
@param _size Alternative new matrix size specification: Size(cols, rows)
|
||||
@@ -215,6 +240,18 @@ namespace cv { namespace gapi { namespace own {
|
||||
}
|
||||
}
|
||||
|
||||
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 :
|
||||
@@ -227,10 +264,18 @@ namespace cv { namespace gapi { namespace own {
|
||||
*/
|
||||
void copyTo(Mat& dst) const
|
||||
{
|
||||
dst.create(rows, cols, type());
|
||||
for (int r = 0; r < rows; ++r)
|
||||
if (dims.empty())
|
||||
{
|
||||
std::copy_n(ptr(r), detail::default_step(type(),cols), dst.ptr(r));
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,10 +293,12 @@ namespace cv { namespace gapi { namespace own {
|
||||
*/
|
||||
size_t total() const
|
||||
{
|
||||
return static_cast<size_t>(rows * cols);
|
||||
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.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user