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:
Dmitry Matveev
2019-08-05 17:56:34 +03:00
committed by Alexander Alekhin
parent 59b0314a0e
commit 0757a51e2b
32 changed files with 1974 additions and 85 deletions
+29 -2
View File
@@ -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;
+20 -7
View File
@@ -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)
*
+14 -1
View File
@@ -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
+231
View File
@@ -0,0 +1,231 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 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]}; };
+61 -14
View File
@@ -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.
*/