-72f63b276e710e3c626e0ab3c072fdfd
+d8947b3280c8644f9828fac2b36f5f5a
return()
endif()
+if(INF_ENGINE_TARGET)
+ ocv_option(OPENCV_GAPI_INF_ENGINE "Build GraphAPI module with Inference Engine support" ON)
+endif()
+
set(the_description "OpenCV G-API Core Module")
-ocv_add_module(gapi opencv_imgproc)
+ocv_add_module(gapi
+ REQUIRED
+ opencv_imgproc
+ OPTIONAL
+ opencv_video
+ WRAP
+ python
+)
if(MSVC)
# Disable obsollete warning C4503 popping up on MSVC <<2017
# https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4503?view=vs-2019
ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4503)
+ if (OPENCV_GAPI_INF_ENGINE AND NOT INF_ENGINE_RELEASE VERSION_GREATER "2021000000")
+ # Disable IE deprecated code warning C4996 for releases < 2021.1
+ ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4996)
+ endif()
endif()
file(GLOB gapi_ext_hdrs
src/api/garray.cpp
src/api/gopaque.cpp
src/api/gscalar.cpp
+ src/api/gframe.cpp
src/api/gkernel.cpp
src/api/gbackend.cpp
src/api/gproto.cpp
src/api/operators.cpp
src/api/kernels_core.cpp
src/api/kernels_imgproc.cpp
+ src/api/kernels_video.cpp
+ src/api/kernels_nnparsers.cpp
src/api/render.cpp
src/api/render_ocv.cpp
src/api/ginfer.cpp
src/backends/cpu/gcpubackend.cpp
src/backends/cpu/gcpukernel.cpp
src/backends/cpu/gcpuimgproc.cpp
+ src/backends/cpu/gcpuvideo.cpp
src/backends/cpu/gcpucore.cpp
+ src/backends/cpu/gnnparsers.cpp
# Fluid Backend (also built-in, FIXME:move away)
src/backends/fluid/gfluidbuffer.cpp
# IE Backend. FIXME: should be included by CMake
# if and only if IE support is enabled
src/backends/ie/giebackend.cpp
+ src/backends/ie/giebackend/giewrapper.cpp
# Render Backend.
src/backends/render/grenderocvbackend.cpp
# Compound
src/backends/common/gcompoundbackend.cpp
src/backends/common/gcompoundkernel.cpp
+
+ # Serialization API and routines
+ src/api/s11n.cpp
+ src/backends/common/serialization.cpp
)
ocv_add_dispatched_file(backends/fluid/gfluidimgproc_func SSE4_1 AVX2)
ocv_create_module()
-ocv_target_link_libraries(${the_module} PRIVATE ade ${INF_ENGINE_TARGET})
+ocv_target_link_libraries(${the_module} PRIVATE ade)
+if(OPENCV_GAPI_INF_ENGINE)
+ ocv_target_link_libraries(${the_module} PRIVATE ${INF_ENGINE_TARGET})
+endif()
if(HAVE_TBB)
ocv_target_link_libraries(${the_module} PRIVATE tbb)
endif()
-ocv_add_accuracy_tests(${INF_ENGINE_TARGET})
+set(__test_extra_deps "")
+if(OPENCV_GAPI_INF_ENGINE)
+ list(APPEND __test_extra_deps ${INF_ENGINE_TARGET})
+endif()
+ocv_add_accuracy_tests(${__test_extra_deps})
+
# FIXME: test binary is linked with ADE directly since ADE symbols
# are not exported from libopencv_gapi.so in any form - thus
# there're two copies of ADE code in memory when tests run (!)
ocv_target_include_directories(${the_module} SYSTEM PRIVATE ${PLAIDML_INCLUDE_DIRS})
endif()
+if(WIN32)
+ # Required for htonl/ntohl on Windows
+ ocv_target_link_libraries(${the_module} PRIVATE wsock32 ws2_32)
+endif()
+
ocv_add_perf_tests()
ocv_add_samples()
endif()
target_link_libraries(${FLUID_TARGET} PRIVATE ade)
+
+if(WIN32)
+ # Required for htonl/ntohl on Windows
+ target_link_libraries(${FLUID_TARGET} PRIVATE wsock32 ws2_32)
+endif()
using GMat2 = std::tuple<GMat,GMat>;
using GMat3 = std::tuple<GMat,GMat,GMat>; // FIXME: how to avoid this?
using GMat4 = std::tuple<GMat,GMat,GMat,GMat>;
- using GMatScalar = std::tuple<GMat, GScalar>;
+ using GMatScalar = std::tuple<GMat, GScalar>;
G_TYPED_KERNEL(GAdd, <GMat(GMat, GMat, int)>, "org.opencv.core.math.add") {
static GMatDesc outMeta(GMatDesc a, GMatDesc b, int ddepth) {
}
else
{
- GAPI_Assert(fx != 0. && fy != 0.);
- return in.withSize
- (Size(static_cast<int>(round(in.size.width * fx)),
- static_cast<int>(round(in.size.height * fy))));
+ int outSz_w = static_cast<int>(round(in.size.width * fx));
+ int outSz_h = static_cast<int>(round(in.size.height * fy));
+ GAPI_Assert(outSz_w > 0 && outSz_h > 0);
+ return in.withSize(Size(outSz_w, outSz_h));
}
}
};
return in.withType(in.depth, in.chan).withSize(dsize);
}
};
+
+ G_TYPED_KERNEL(GSize, <GOpaque<Size>(GMat)>, "org.opencv.core.size") {
+ static GOpaqueDesc outMeta(const GMatDesc&) {
+ return empty_gopaque_desc();
+ }
+ };
+
+ G_TYPED_KERNEL(GSizeR, <GOpaque<Size>(GOpaque<Rect>)>, "org.opencv.core.sizeR") {
+ static GOpaqueDesc outMeta(const GOpaqueDesc&) {
+ return empty_gopaque_desc();
+ }
+ };
}
//! @addtogroup gapi_math
@param ddepth optional depth of the output matrix.
@sa sub, addWeighted
*/
-GAPI_EXPORTS GMat add(const GMat& src1, const GMat& src2, int ddepth = -1);
+GAPI_EXPORTS_W GMat add(const GMat& src1, const GMat& src2, int ddepth = -1);
/** @brief Calculates the per-element sum of matrix and given scalar.
@note Function textual ID is "org.opencv.core.math.mean"
@param src input matrix.
*/
-GAPI_EXPORTS GScalar mean(const GMat& src);
+GAPI_EXPORTS_W GScalar mean(const GMat& src);
/** @brief Calculates x and y coordinates of 2D vectors from their magnitude and angle.
@sa merge3, merge4
*/
GAPI_EXPORTS std::tuple<GMat, GMat, GMat,GMat> split4(const GMat& src);
-GAPI_EXPORTS std::tuple<GMat, GMat, GMat> split3(const GMat& src);
+GAPI_EXPORTS_W std::tuple<GMat, GMat, GMat> split3(const GMat& src);
/** @brief Applies a generic geometrical transformation to an image.
int borderMode = cv::BORDER_CONSTANT, const Scalar& borderValue = Scalar());
//! @} gapi_transform
+/** @brief Gets dimensions from Mat.
+
+@note Function textual ID is "org.opencv.core.size"
+
+@param src Input tensor
+@return Size (tensor dimensions).
+*/
+GAPI_EXPORTS GOpaque<Size> size(const GMat& src);
+
+/** @overload
+Gets dimensions from rectangle.
+
+@note Function textual ID is "org.opencv.core.sizeR"
+
+@param r Input rectangle.
+@return Size (rectangle dimensions).
+*/
+GAPI_EXPORTS GOpaque<Size> size(const GOpaque<Rect>& r);
} //namespace gapi
} //namespace cv
namespace core {
namespace cpu {
-GAPI_EXPORTS GKernelPackage kernels();
+GAPI_EXPORTS_W cv::gapi::GKernelPackage kernels();
} // namespace cpu
} // namespace core
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018-2019 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GCPUKERNEL_HPP
#include <opencv2/gapi/gcommon.hpp>
#include <opencv2/gapi/gkernel.hpp>
#include <opencv2/gapi/garg.hpp>
-#include <opencv2/gapi/own/convert.hpp> //to_ocv
+#include <opencv2/gapi/gmetaarg.hpp>
#include <opencv2/gapi/util/compiler_hints.hpp> //suppress_unused_warning
#include <opencv2/gapi/util/util.hpp>
const T& inArg(int input) { return m_args.at(input).get<T>(); }
// Syntax sugar
- const cv::gapi::own::Mat& inMat(int input);
- cv::gapi::own::Mat& outMatR(int output); // FIXME: Avoid cv::gapi::own::Mat m = ctx.outMatR()
+ const cv::Mat& inMat(int input);
+ cv::Mat& outMatR(int output); // FIXME: Avoid cv::Mat m = ctx.outMatR()
const cv::Scalar& inVal(int input);
cv::Scalar& outValR(int output); // FIXME: Avoid cv::Scalar s = ctx.outValR()
return outOpaqueRef(output).wref<T>();
}
+ GArg state()
+ {
+ return m_state;
+ }
+
protected:
detail::VectorRef& outVecRef(int output);
detail::OpaqueRef& outOpaqueRef(int output);
std::vector<GArg> m_args;
+ GArg m_state;
//FIXME: avoid conversion of arguments from internal representation to OpenCV one on each call
//to OCV kernel. (This can be achieved by a two single time conversions in GCPUExecutable::run,
class GAPI_EXPORTS GCPUKernel
{
public:
- // This function is kernel's execution entry point (does the processing work)
- using F = std::function<void(GCPUContext &)>;
+ // This function is a kernel's execution entry point (does the processing work)
+ using RunF = std::function<void(GCPUContext &)>;
+ // This function is a stateful kernel's setup routine (configures state)
+ using SetupF = std::function<void(const GMetaArgs &, const GArgs &,
+ GArg &, const GCompileArgs &)>;
GCPUKernel();
- explicit GCPUKernel(const F& f);
+ GCPUKernel(const RunF& runF, const SetupF& setupF = nullptr);
- void apply(GCPUContext &ctx);
+ RunF m_runF = nullptr;
+ SetupF m_setupF = nullptr;
-protected:
- F m_f;
+ bool m_isStateful = false;
};
// FIXME: This is an ugly ad-hoc implementation. TODO: refactor
template<class T> struct get_in;
template<> struct get_in<cv::GMat>
{
- static cv::Mat get(GCPUContext &ctx, int idx) { return to_ocv(ctx.inMat(idx)); }
+ static cv::Mat get(GCPUContext &ctx, int idx) { return ctx.inMat(idx); }
};
template<> struct get_in<cv::GMatP>
{
static cv::Mat get(GCPUContext &ctx, int idx) { return get_in<cv::GMat>::get(ctx, idx); }
};
+template<> struct get_in<cv::GFrame>
+{
+ static cv::Mat get(GCPUContext &ctx, int idx) { return get_in<cv::GMat>::get(ctx, idx); }
+};
template<> struct get_in<cv::GScalar>
{
static cv::Scalar get(GCPUContext &ctx, int idx) { return ctx.inVal(idx); }
};
struct tracked_cv_mat{
- tracked_cv_mat(cv::gapi::own::Mat& m) : r{to_ocv(m)}, original_data{m.data} {}
+ tracked_cv_mat(cv::Mat& m) : r{m}, original_data{m.data} {}
cv::Mat r;
uchar* original_data;
return ctx.outVecR<U>(idx);
}
};
+
+//FIXME(dm): GArray<Mat>/GArray<GMat> conversion should be done more gracefully in the system
+template<> struct get_out<cv::GArray<cv::GMat> >: public get_out<cv::GArray<cv::Mat> >
+{
+};
+
template<typename U> struct get_out<cv::GOpaque<U>>
{
static U& get(GCPUContext &ctx, int idx)
}
};
+template<typename, typename>
+struct OCVSetupHelper;
+
+template<typename Impl, typename... Ins>
+struct OCVSetupHelper<Impl, std::tuple<Ins...>>
+{
+ // Using 'auto' return type and 'decltype' specifier in both 'setup_impl' versions
+ // to check existence of required 'Impl::setup' functions.
+ // While 'decltype' specifier accepts expression we pass expression with 'comma-operator'
+ // where first operand of comma-operator is call attempt to desired 'Impl::setup' and
+ // the second operand is 'void()' expression.
+ //
+ // SFINAE for 'Impl::setup' which accepts compile arguments.
+ template<int... IIs>
+ static auto setup_impl(const GMetaArgs &metaArgs, const GArgs &args,
+ GArg &state, const GCompileArgs &compileArgs,
+ detail::Seq<IIs...>) ->
+ decltype(Impl::setup(detail::get_in_meta<Ins>(metaArgs, args, IIs)...,
+ std::declval<typename std::add_lvalue_reference<
+ std::shared_ptr<typename Impl::State>
+ >::type
+ >(),
+ compileArgs)
+ , void())
+ {
+ // TODO: unique_ptr <-> shared_ptr conversion ?
+ // To check: Conversion is possible only if the state which should be passed to
+ // 'setup' user callback isn't required to have previous value
+ std::shared_ptr<typename Impl::State> stPtr;
+ Impl::setup(detail::get_in_meta<Ins>(metaArgs, args, IIs)..., stPtr, compileArgs);
+ state = GArg(stPtr);
+ }
+
+ // SFINAE for 'Impl::setup' which doesn't accept compile arguments.
+ template<int... IIs>
+ static auto setup_impl(const GMetaArgs &metaArgs, const GArgs &args,
+ GArg &state, const GCompileArgs &/* compileArgs */,
+ detail::Seq<IIs...>) ->
+ decltype(Impl::setup(detail::get_in_meta<Ins>(metaArgs, args, IIs)...,
+ std::declval<typename std::add_lvalue_reference<
+ std::shared_ptr<typename Impl::State>
+ >::type
+ >()
+ )
+ , void())
+ {
+ // The same comment as in 'setup' above.
+ std::shared_ptr<typename Impl::State> stPtr;
+ Impl::setup(detail::get_in_meta<Ins>(metaArgs, args, IIs)..., stPtr);
+ state = GArg(stPtr);
+ }
+
+ static void setup(const GMetaArgs &metaArgs, const GArgs &args,
+ GArg& state, const GCompileArgs &compileArgs)
+ {
+ setup_impl(metaArgs, args, state, compileArgs,
+ typename detail::MkSeq<sizeof...(Ins)>::type());
+ }
+};
+
+// OCVCallHelper is a helper class to call stateless OCV kernels and OCV kernel functors.
template<typename, typename, typename>
struct OCVCallHelper;
// FIXME: probably can be simplified with std::apply or analogue.
template<typename Impl, typename... Ins, typename... Outs>
-struct OCVCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> >
+struct OCVCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...>>
{
template<typename... Inputs>
struct call_and_postprocess
//by comparing it's state (data ptr) before and after the call.
//This is done by converting each output Mat into tracked_cv_mat object, and binding
//them to parameters of ad-hoc function
- //Convert own::Scalar to cv::Scalar before call kernel and run kernel
- //convert cv::Scalar to own::Scalar after call kernel and write back results
call_and_postprocess<decltype(get_in<Ins>::get(ctx, IIs))...>
- ::call(get_in<Ins>::get(ctx, IIs)...,
- get_out<Outs>::get(ctx, OIs)...);
+ ::call(get_in<Ins>::get(ctx, IIs)..., get_out<Outs>::get(ctx, OIs)...);
}
template<int... IIs, int... OIs>
- static void call_impl(cv::GCPUContext &ctx, Impl& impl, detail::Seq<IIs...>, detail::Seq<OIs...>)
+ static void call_impl(cv::GCPUContext &ctx, Impl& impl,
+ detail::Seq<IIs...>, detail::Seq<OIs...>)
{
- call_and_postprocess<decltype(cv::detail::get_in<Ins>::get(ctx, IIs))...>
- ::call(impl, cv::detail::get_in<Ins>::get(ctx, IIs)...,
- cv::detail::get_out<Outs>::get(ctx, OIs)...);
+ call_and_postprocess<decltype(get_in<Ins>::get(ctx, IIs))...>
+ ::call(impl, get_in<Ins>::get(ctx, IIs)..., get_out<Outs>::get(ctx, OIs)...);
}
static void call(GCPUContext &ctx)
}
};
+// OCVStCallHelper is a helper class to call stateful OCV kernels.
+template<typename, typename, typename>
+struct OCVStCallHelper;
+
+template<typename Impl, typename... Ins, typename... Outs>
+struct OCVStCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...>> :
+ OCVCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...>>
+{
+ template<typename... Inputs>
+ struct call_and_postprocess
+ {
+ template<typename... Outputs>
+ static void call(typename Impl::State& st, Inputs&&... ins, Outputs&&... outs)
+ {
+ Impl::run(std::forward<Inputs>(ins)..., outs..., st);
+ postprocess(outs...);
+ }
+ };
+
+ template<int... IIs, int... OIs>
+ static void call_impl(GCPUContext &ctx, detail::Seq<IIs...>, detail::Seq<OIs...>)
+ {
+ auto& st = *ctx.state().get<std::shared_ptr<typename Impl::State>>();
+ call_and_postprocess<decltype(get_in<Ins>::get(ctx, IIs))...>
+ ::call(st, get_in<Ins>::get(ctx, IIs)..., get_out<Outs>::get(ctx, OIs)...);
+ }
+
+ static void call(GCPUContext &ctx)
+ {
+ call_impl(ctx,
+ typename detail::MkSeq<sizeof...(Ins)>::type(),
+ typename detail::MkSeq<sizeof...(Outs)>::type());
+ }
+};
+
} // namespace detail
template<class Impl, class K>
-class GCPUKernelImpl: public cv::detail::OCVCallHelper<Impl, typename K::InArgs, typename K::OutArgs>,
- public cv::detail::KernelTag
+class GCPUKernelImpl: public cv::detail::KernelTag
{
- using P = detail::OCVCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
+ using CallHelper = detail::OCVCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
public:
using API = K;
- static cv::gapi::GBackend backend() { return cv::gapi::cpu::backend(); }
- static cv::GCPUKernel kernel() { return GCPUKernel(&P::call); }
+ static cv::gapi::GBackend backend() { return cv::gapi::cpu::backend(); }
+ static cv::GCPUKernel kernel() { return GCPUKernel(&CallHelper::call); }
+};
+
+template<class Impl, class K, class S>
+class GCPUStKernelImpl: public cv::detail::KernelTag
+{
+ using StSetupHelper = detail::OCVSetupHelper<Impl, typename K::InArgs>;
+ using StCallHelper = detail::OCVStCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
+
+public:
+ using API = K;
+ using State = S;
+
+ static cv::gapi::GBackend backend() { return cv::gapi::cpu::backend(); }
+ static cv::GCPUKernel kernel() { return GCPUKernel(&StCallHelper::call,
+ &StSetupHelper::setup); }
};
#define GAPI_OCV_KERNEL(Name, API) struct Name: public cv::GCPUKernelImpl<Name, API>
+// TODO: Reuse Anatoliy's logic for support of types with commas in macro.
+// Retrieve the common part from Anatoliy's logic to the separate place.
+#define GAPI_OCV_KERNEL_ST(Name, API, State) \
+ struct Name: public cv::GCPUStKernelImpl<Name, API, State> \
+
+
class gapi::cpu::GOCVFunctor : public gapi::GFunctor
{
public:
using Impl = std::function<void(GCPUContext &)>;
+ using Meta = cv::GKernel::M;
- GOCVFunctor(const char* id, const Impl& impl)
- : gapi::GFunctor(id), impl_{GCPUKernel(impl)}
+ GOCVFunctor(const char* id, const Meta &meta, const Impl& impl)
+ : gapi::GFunctor(id), impl_{GCPUKernel(impl), meta}
{
}
gapi::cpu::GOCVFunctor gapi::cpu::ocv_kernel(Callable& c)
{
using P = detail::OCVCallHelper<Callable, typename K::InArgs, typename K::OutArgs>;
- return GOCVFunctor(K::id(), std::bind(&P::callFunctor, std::placeholders::_1, std::ref(c)));
+ return GOCVFunctor{ K::id()
+ , &K::getOutMeta
+ , std::bind(&P::callFunctor, std::placeholders::_1, std::ref(c))
+ };
}
template<typename K, typename Callable>
gapi::cpu::GOCVFunctor gapi::cpu::ocv_kernel(const Callable& c)
{
using P = detail::OCVCallHelper<Callable, typename K::InArgs, typename K::OutArgs>;
- return GOCVFunctor(K::id(), std::bind(&P::callFunctor, std::placeholders::_1, c));
+ return GOCVFunctor{ K::id()
+ , &K::getOutMeta
+ , std::bind(&P::callFunctor, std::placeholders::_1, c)
+ };
}
//! @endcond
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#ifndef OPENCV_GAPI_CPU_VIDEO_API_HPP
+#define OPENCV_GAPI_CPU_VIDEO_API_HPP
+
+#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
+
+namespace cv {
+namespace gapi {
+namespace video {
+namespace cpu {
+
+GAPI_EXPORTS GKernelPackage kernels();
+
+} // namespace cpu
+} // namespace video
+} // namespace gapi
+} // namespace cv
+
+
+#endif // OPENCV_GAPI_CPU_VIDEO_API_HPP
namespace cv { namespace gapi { namespace core { namespace fluid {
-GAPI_EXPORTS GKernelPackage kernels();
+GAPI_EXPORTS_W cv::gapi::GKernelPackage kernels();
}}}}
#include <cstdint> // uint8_t
#include <opencv2/gapi/opencv_includes.hpp>
-#include <opencv2/gapi/own/mat.hpp>
#include <opencv2/gapi/gmat.hpp>
#include <opencv2/gapi/util/optional.hpp>
-#include <opencv2/gapi/own/mat.hpp>
namespace cv {
namespace gapi {
}
};
- View() = default;
-
const inline uint8_t* InLineB(int index) const // -(w-1)/2...0...+(w-1)/2 for Filters
{
return m_cache->linePtr(index);
Priv& priv(); // internal use only
const Priv& priv() const; // internal use only
- View(Priv* p);
+ View();
+ View(std::unique_ptr<Priv>&& p);
+ View(View&& v);
+ View& operator=(View&& v);
+ ~View();
private:
- std::shared_ptr<Priv> m_priv;
- const Cache* m_cache;
+ std::unique_ptr<Priv> m_priv;
+ const Cache* m_cache = nullptr;
};
class GAPI_EXPORTS Buffer
int wlpi,
BorderOpt border);
// Constructor for in/out buffers (for tests)
- Buffer(const cv::gapi::own::Mat &data, bool is_input);
+ Buffer(const cv::Mat &data, bool is_input);
+ ~Buffer();
+ Buffer& operator=(Buffer&&);
inline uint8_t* OutLineB(int index = 0)
{
inline const GMatDesc& meta() const { return m_cache->m_desc; }
View mkView(int borderSize, bool ownStorage);
+ void addView(const View* v);
class GAPI_EXPORTS Priv; // internal use only
Priv& priv(); // internal use only
const Priv& priv() const; // internal use only
private:
- std::shared_ptr<Priv> m_priv;
+ std::unique_ptr<Priv> m_priv;
const Cache* m_cache;
};
{
static const cv::gapi::fluid::View& get(const cv::GArgs &in_args, int idx)
{
- return in_args[idx].unsafe_get<cv::gapi::fluid::View>();
+ return *in_args[idx].unsafe_get<cv::gapi::fluid::View*>();
}
};
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GARG_HPP
template<typename T, typename std::enable_if<!detail::is_garg<T>::value, int>::type = 0>
explicit GArg(const T &t)
: kind(detail::GTypeTraits<T>::kind)
+ , opaque_kind(detail::GOpaqueTraits<T>::kind)
, value(detail::wrap_gapi_helper<T>::wrap(t))
{
}
template<typename T, typename std::enable_if<!detail::is_garg<T>::value, int>::type = 0>
explicit GArg(T &&t)
: kind(detail::GTypeTraits<typename std::decay<T>::type>::kind)
+ , opaque_kind(detail::GOpaqueTraits<typename std::decay<T>::type>::kind)
, value(detail::wrap_gapi_helper<T>::wrap(t))
{
}
}
detail::ArgKind kind = detail::ArgKind::OPAQUE_VAL;
+ detail::OpaqueKind opaque_kind = detail::OpaqueKind::CV_UNKNOWN;
protected:
util::any value;
// FIXME: Move to a separate file!
using GRunArg = util::variant<
#if !defined(GAPI_STANDALONE)
- cv::Mat,
cv::UMat,
#endif // !defined(GAPI_STANDALONE)
cv::gapi::wip::IStreamSource::Ptr,
- cv::gapi::own::Mat,
+ cv::Mat,
cv::Scalar,
cv::detail::VectorRef,
cv::detail::OpaqueRef
>;
using GRunArgs = std::vector<GRunArg>;
+// TODO: Think about the addition operator
+/**
+ * @brief This operator allows to complement the input vector at runtime.
+ *
+ * It's an ordinary overload of addition assignment operator.
+ *
+ * Example of usage:
+ * @snippet dynamic_graph.cpp GRunArgs usage
+ *
+ */
+inline GRunArgs& operator += (GRunArgs &lhs, const GRunArgs &rhs)
+{
+ lhs.reserve(lhs.size() + rhs.size());
+ lhs.insert(lhs.end(), rhs.begin(), rhs.end());
+ return lhs;
+}
+
namespace gapi
{
namespace wip
using GRunArgP = util::variant<
#if !defined(GAPI_STANDALONE)
- cv::Mat*,
cv::UMat*,
#endif // !defined(GAPI_STANDALONE)
- cv::gapi::own::Mat*,
+ cv::Mat*,
cv::Scalar*,
cv::detail::VectorRef,
cv::detail::OpaqueRef
>;
using GRunArgsP = std::vector<GRunArgP>;
+// TODO: Think about the addition operator
+/**
+ * @brief This operator allows to complement the output vector at runtime.
+ *
+ * It's an ordinary overload of addition assignment operator.
+ *
+ * Example of usage:
+ * @snippet dynamic_graph.cpp GRunArgsP usage
+ *
+ */
+inline GRunArgsP& operator += (GRunArgsP &lhs, const GRunArgsP &rhs)
+{
+ lhs.reserve(lhs.size() + rhs.size());
+ lhs.insert(lhs.end(), rhs.begin(), rhs.end());
+ return lhs;
+}
+
+namespace gapi
+{
+ GAPI_EXPORTS cv::GRunArgsP bind(cv::GRunArgs &results);
+ GAPI_EXPORTS cv::GRunArg bind(cv::GRunArgP &out); // FIXME: think more about it
+}
+
template<typename... Ts> inline GRunArgs gin(const Ts&... args)
{
return GRunArgs{ GRunArg(detail::wrap_host_helper<Ts>::wrap_in(args))... };
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GARRAY_HPP
// (user-inaccessible) classes.
class GNode;
struct GOrigin;
-
template<typename T> class GArray;
/**
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;
};
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
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
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
class VectorRef
{
std::shared_ptr<BasicVectorRef> m_ref;
+ cv::detail::OpaqueKind m_kind;
template<typename T> inline void check() const
{
public:
VectorRef() = default;
- template<typename T> explicit VectorRef(const std::vector<T>& vec) : m_ref(new VectorRefT<T>(vec)) {}
- template<typename T> explicit VectorRef(std::vector<T>& vec) : m_ref(new VectorRefT<T>(vec)) {}
- template<typename T> explicit VectorRef(std::vector<T>&& vec) : m_ref(new VectorRefT<T>(vec)) {}
+ template<typename T> 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 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?)
template<typename T> class GArray
{
public:
+ // 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;
+
+ explicit GArray(const std::vector<HT>& v) // Constant value constructor
+ : m_ref(detail::GArrayU(detail::VectorRef(v))) { putDetails(); }
+ explicit GArray(std::vector<HT>&& v) // Move-constructor
+ : m_ref(detail::GArrayU(detail::VectorRef(std::move(v)))) { putDetails(); }
GArray() { putDetails(); } // Empty constructor
explicit GArray(detail::GArrayU &&ref) // GArrayU-based constructor
: m_ref(ref) { putDetails(); } // (used by GCall, not for users)
detail::GArrayU strip() const { return m_ref; }
private:
- // Host type (or Flat type) - the type this GArray is actually
- // specified to.
- using HT = typename detail::flatten_g<typename std::decay<T>::type>::type;
-
static void VCTor(detail::VectorRef& vref) {
vref.reset<HT>();
+ vref.storeKind<HT>();
}
void putDetails() {
m_ref.setConstructFcn(&VCTor);
- m_ref.specifyType<HT>();
+ m_ref.specifyType<HT>(); // FIXME: to unify those 2 to avoid excessive dynamic_cast
+ m_ref.storeKind<HT>(); //
}
detail::GArrayU m_ref;
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GCOMMON_HPP
#include <opencv2/gapi/opencv_includes.hpp>
#include <opencv2/gapi/util/any.hpp>
+#include <opencv2/gapi/util/optional.hpp>
#include <opencv2/gapi/own/exports.hpp>
#include <opencv2/gapi/own/assert.hpp>
+#include <opencv2/gapi/render/render_types.hpp>
namespace cv {
+class GMat; // FIXME: forward declaration for GOpaqueTraits
+
namespace detail
{
// This is a trait-like structure to mark backend-specific compile arguments
{};
struct TransformTag
{};
-}
+
+ // This enum is utilized mostly by GArray and GOpaque to store and recognize their internal data
+ // types (aka Host type). Also it is widely used during serialization routine.
+ enum class OpaqueKind: int
+ {
+ CV_UNKNOWN, // Unknown, generic, opaque-to-GAPI data type unsupported in graph seriallization
+ CV_BOOL, // bool user G-API data
+ CV_INT, // int user G-API data
+ CV_DOUBLE, // double user G-API data
+ CV_POINT, // cv::Point user G-API data
+ CV_SIZE, // cv::Size user G-API data
+ CV_RECT, // cv::Rect user G-API data
+ CV_SCALAR, // cv::Scalar user G-API data
+ CV_MAT, // cv::Mat user G-API data
+ CV_PRIM, // cv::gapi::wip::draw::Prim user G-API data
+ };
+
+ // Type traits helper which simplifies the extraction of kind from type
+ template<typename T> struct GOpaqueTraits;
+ template<typename T> struct GOpaqueTraits { static constexpr const OpaqueKind kind = OpaqueKind::CV_UNKNOWN; };
+ template<> struct GOpaqueTraits<int> { static constexpr const OpaqueKind kind = OpaqueKind::CV_INT; };
+ template<> struct GOpaqueTraits<double> { static constexpr const OpaqueKind kind = OpaqueKind::CV_DOUBLE; };
+ template<> struct GOpaqueTraits<cv::Size> { static constexpr const OpaqueKind kind = OpaqueKind::CV_SIZE; };
+ template<> struct GOpaqueTraits<bool> { static constexpr const OpaqueKind kind = OpaqueKind::CV_BOOL; };
+ template<> struct GOpaqueTraits<cv::Scalar> { static constexpr const OpaqueKind kind = OpaqueKind::CV_SCALAR; };
+ template<> struct GOpaqueTraits<cv::Point> { static constexpr const OpaqueKind kind = OpaqueKind::CV_POINT; };
+ template<> struct GOpaqueTraits<cv::Mat> { static constexpr const OpaqueKind kind = OpaqueKind::CV_MAT; };
+ template<> struct GOpaqueTraits<cv::Rect> { static constexpr const OpaqueKind kind = OpaqueKind::CV_RECT; };
+ template<> struct GOpaqueTraits<cv::GMat> { static constexpr const OpaqueKind kind = OpaqueKind::CV_MAT; };
+ template<> struct GOpaqueTraits<cv::gapi::wip::draw::Prim>
+ { static constexpr const OpaqueKind kind = OpaqueKind::CV_PRIM; };
+ // GArray is not supporting bool type for now due to difference in std::vector<bool> implementation
+ using GOpaqueTraitsArrayTypes = std::tuple<int, double, cv::Size, cv::Scalar, cv::Point, cv::Mat, cv::Rect, cv::gapi::wip::draw::Prim>;
+ // GOpaque is not supporting cv::Mat and cv::Scalar since there are GScalar and GMat types
+ using GOpaqueTraitsOpaqueTypes = std::tuple<bool, int, double, cv::Size, cv::Point, cv::Rect, cv::gapi::wip::draw::Prim>;
+} // namespace detail
// This definition is here because it is reused by both public(?) and internal
// modules. Keeping it here wouldn't expose public details (e.g., API-level)
GSCALAR,
GARRAY,
GOPAQUE,
+ GFRAME,
};
struct GCompileArg;
namespace detail {
template<typename T>
using is_compile_arg = std::is_same<GCompileArg, typename std::decay<T>::type>;
-}
+} // namespace detail
+
// CompileArg is an unified interface over backend-specific compilation
// information
// FIXME: Move to a separate file?
* passed in (a variadic template parameter pack) into a vector of
* cv::GCompileArg objects.
*/
-struct GAPI_EXPORTS GCompileArg
+struct GAPI_EXPORTS_W_SIMPLE GCompileArg
{
public:
+ // NB: Required for pythnon bindings
+ GCompileArg() = default;
+
std::string tag;
// FIXME: use decay in GArg/other trait-based wrapper before leg is shot!
using GCompileArgs = std::vector<GCompileArg>;
/**
- * Wraps a list of arguments (a parameter pack) into a vector of
- * compilation arguments (cv::GCompileArg).
+ * @brief Wraps a list of arguments (a parameter pack) into a vector of
+ * compilation arguments (cv::GCompileArg).
*/
template<typename... Ts> GCompileArgs compile_args(Ts&&... args)
{
}
/**
+ * @brief Retrieves particular compilation argument by its type from
+ * cv::GCompileArgs
+ */
+namespace gapi
+{
+template<typename T>
+inline cv::util::optional<T> getCompileArg(const cv::GCompileArgs &args)
+{
+ for (auto &compile_arg : args)
+ {
+ if (compile_arg.tag == cv::detail::CompileArgTag<T>::tag())
+ {
+ return cv::util::optional<T>(compile_arg.get<T>());
+ }
+ }
+ return cv::util::optional<T>();
+}
+} // namespace gapi
+
+/**
* @brief Ask G-API to dump compiled graph in Graphviz format under
* the given file name.
*
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GCOMPILED_HPP
// FIXME: Why it requires compile args?
void reshape(const GMetaArgs& inMetas, const GCompileArgs& args);
+ /**
+ * @brief Prepare inner kernels states for a new video-stream.
+ *
+ * GCompiled objects may be used to process video streams frame by frame.
+ * In this case, a GCompiled is called on every image frame individually.
+ * Starting OpenCV 4.4, some kernels in the graph may have their internal
+ * states (see GAPI_OCV_KERNEL_ST for the OpenCV backend).
+ * In this case, if user starts processing another video stream with
+ * this GCompiled, this method needs to be called to let kernels re-initialize
+ * their internal states to a new video stream.
+ */
+ void prepareForNewStream();
+
protected:
/// @private
std::shared_ptr<Priv> m_priv;
}
};
+template<> struct get_compound_in<cv::GMatP>
+{
+ static cv::GMatP get(GCompoundContext &ctx, int idx)
+ {
+ auto mat = cv::GMatP();
+ ctx.m_args[idx] = GArg(mat);
+ return mat;
+ }
+};
+
template<typename, typename, typename>
struct GCompoundCallHelper;
using last_type_t = typename last_type<Ts...>::type;
}
+// Forward-declare the serialization objects
+namespace gimpl {
+namespace s11n {
+namespace I {
+ struct IStream;
+ struct OStream;
+} // namespace I
+} // namespace s11n
+} // namespace gimpl
+
/**
* \addtogroup gapi_main_classes
* @{
*
* @sa GCompiled
*/
-class GAPI_EXPORTS GComputation
+class GAPI_EXPORTS_W GComputation
{
public:
class Priv;
*
* @sa @ref gapi_data_objects
*/
- GComputation(GProtoInputArgs &&ins,
- GProtoOutputArgs &&outs); // Arg-to-arg overload
+ GAPI_WRAP GComputation(GProtoInputArgs &&ins,
+ GProtoOutputArgs &&outs); // Arg-to-arg overload
// 2. Syntax sugar and compatibility overloads
/**
* @param in input GMat of the defined unary computation
* @param out output GMat of the defined unary computation
*/
- GComputation(GMat in, GMat out); // Unary overload
+ GAPI_WRAP GComputation(GMat in, GMat out); // Unary overload
/**
* @brief Defines an unary (one input -- one output) computation
* @param in input GMat of the defined unary computation
* @param out output GScalar of the defined unary computation
*/
- GComputation(GMat in, GScalar out); // Unary overload (scalar)
+ GAPI_WRAP GComputation(GMat in, GScalar out); // Unary overload (scalar)
/**
* @brief Defines a binary (two inputs -- one output) computation
* @param in2 second input GMat of the defined binary computation
* @param out output GMat of the defined binary computation
*/
- GComputation(GMat in1, GMat in2, GMat out); // Binary overload
+ GAPI_WRAP GComputation(GMat in1, GMat in2, GMat out); // Binary overload
/**
* @brief Defines a binary (two inputs -- one output) computation
void apply(GRunArgs &&ins, GRunArgsP &&outs, GCompileArgs &&args = {}); // Arg-to-arg overload
/// @private -- Exclude this function from OpenCV documentation
- void apply(const std::vector<cv::gapi::own::Mat>& ins, // Compatibility overload
- const std::vector<cv::gapi::own::Mat>& outs,
+ void apply(const std::vector<cv::Mat>& ins, // Compatibility overload
+ const std::vector<cv::Mat>& outs,
GCompileArgs &&args = {});
// 2. Syntax sugar and compatibility overloads
* @param args compilation arguments for underlying compilation
* process.
*/
- void apply(cv::Mat in, cv::Mat &out, GCompileArgs &&args = {}); // Unary overload
+ void apply(cv::Mat in, cv::Mat &out, GCompileArgs &&args = {}); // Unary overload
/**
* @brief Execute an unary computation (with compilation on the fly)
* @param args compilation arguments for underlying compilation
* process.
*/
- void apply(cv::Mat in, cv::Scalar &out, GCompileArgs &&args = {}); // Unary overload (scalar)
+ GAPI_WRAP void apply(cv::Mat in, CV_OUT cv::Scalar &out, GCompileArgs &&args = {}); // Unary overload (scalar)
/**
* @brief Execute a binary computation (with compilation on the fly)
* @param args compilation arguments for underlying compilation
* process.
*/
- void apply(cv::Mat in1, cv::Mat in2, cv::Mat &out, GCompileArgs &&args = {}); // Binary overload
+ GAPI_WRAP void apply(cv::Mat in1, cv::Mat in2, CV_OUT cv::Mat &out, GCompileArgs &&args = {}); // Binary overload
/**
* @brief Execute an binary computation (with compilation on the fly)
Priv& priv();
/// @private
const Priv& priv() const;
+ /// @private
+ explicit GComputation(cv::gimpl::s11n::I::IStream &);
+ /// @private
+ void serialize(cv::gimpl::s11n::I::OStream &) const;
protected:
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#ifndef OPENCV_GAPI_GFRAME_HPP
+#define OPENCV_GAPI_GFRAME_HPP
+
+#include <ostream>
+#include <memory> // std::shared_ptr
+
+#include <opencv2/gapi/opencv_includes.hpp>
+#include <opencv2/gapi/gcommon.hpp> // GShape
+
+#include <opencv2/gapi/gmat.hpp>
+#include <opencv2/gapi/own/assert.hpp>
+
+// TODO GAPI_EXPORTS or so
+namespace cv
+{
+// Forward declaration; GNode and GOrigin are an internal
+// (user-inaccessible) classes.
+class GNode;
+struct GOrigin;
+
+/** \addtogroup gapi_data_objects
+ * @{
+ */
+class GAPI_EXPORTS_W_SIMPLE GFrame
+{
+public:
+ GAPI_WRAP GFrame(); // Empty constructor
+ GFrame(const GNode &n, std::size_t out); // Operation result constructor
+
+ GOrigin& priv(); // Internal use only
+ const GOrigin& priv() const; // Internal use only
+
+private:
+ std::shared_ptr<GOrigin> m_priv;
+};
+/** @} */
+
+/**
+ * \addtogroup gapi_meta_args
+ * @{
+ */
+struct GAPI_EXPORTS GFrameDesc
+{
+};
+static inline GFrameDesc empty_gframe_desc() { return GFrameDesc{}; }
+/** @} */
+
+GAPI_EXPORTS std::ostream& operator<<(std::ostream& os, const cv::GFrameDesc &desc);
+
+} // namespace cv
+
+#endif // OPENCV_GAPI_GFRAME_HPP
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018-2019 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GKERNEL_HPP
namespace cv {
using GShapes = std::vector<GShape>;
+using GKinds = std::vector<cv::detail::OpaqueKind>;
// GKernel describes kernel API to the system
// FIXME: add attributes of a kernel, (e.g. number and types
{
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
+ std::string name; // kernel ID, defined by its API (signature)
+ std::string tag; // some (implementation-specific) tag
+ M outMeta; // generic adaptor to API::outMeta(...)
+ GShapes outShapes; // types (shapes) kernel's outputs
+ GKinds inKinds; // kinds of kernel's inputs (fixme: below)
};
+// TODO: It's questionable if inKinds should really be here. Instead,
+// this information could come from meta.
// GKernelImpl describes particular kernel implementation to the system
struct GAPI_EXPORTS GKernelImpl
{
util::any opaque; // backend-specific opaque info
+ GKernel::M outMeta; // for deserialized graphs, the outMeta is taken here
};
template<typename, typename> class GKernelTypeM;
template<typename T> struct MetaType;
template<> struct MetaType<cv::GMat> { using type = GMatDesc; };
template<> struct MetaType<cv::GMatP> { using type = GMatDesc; };
+ template<> struct MetaType<cv::GFrame> { 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::GOpaque<U> > { using type = GOpaqueDesc; };
using InArgs = std::tuple<Args...>;
using OutArgs = std::tuple<R...>;
+ // TODO: Args&&... here?
static std::tuple<R...> on(Args... args)
{
- cv::GCall call(GKernel{K::id(), K::tag(), &K::getOutMeta, {detail::GTypeTraits<R>::shape...}});
- call.pass(args...);
+ cv::GCall call(GKernel{ K::id()
+ , K::tag()
+ , &K::getOutMeta
+ , {detail::GTypeTraits<R>::shape...}
+ , {detail::GTypeTraits<Args>::op_kind...}});
+ call.pass(args...); // TODO: std::forward() here?
return yield(call, typename detail::MkSeq<sizeof...(R)>::type());
}
};
using InArgs = std::tuple<Args...>;
using OutArgs = std::tuple<R>;
+ static_assert(!cv::detail::contains<GFrame, OutArgs>::value, "Values of GFrame type can't be used as operation outputs");
+
static R on(Args... args)
{
- cv::GCall call(GKernel{K::id(), K::tag(), &K::getOutMeta, {detail::GTypeTraits<R>::shape}});
+ cv::GCall call(GKernel{ K::id()
+ , K::tag()
+ , &K::getOutMeta
+ , {detail::GTypeTraits<R>::shape}
+ , {detail::GTypeTraits<Args>::op_kind...}});
call.pass(args...);
return detail::Yield<R>::yield(call, 0);
}
* Finally, two kernel packages can be combined into a new one
* with function cv::gapi::combine().
*/
- class GAPI_EXPORTS GKernelPackage
+ class GAPI_EXPORTS_W_SIMPLE GKernelPackage
{
/// @private
/// @private
// Partial include() specialization for kernels
template <typename KImpl>
- typename std::enable_if<(std::is_base_of<detail::KernelTag, KImpl>::value), void>::type
+ typename std::enable_if<(std::is_base_of<cv::detail::KernelTag, KImpl>::value), void>::type
includeHelper()
{
auto backend = KImpl::backend();
auto kernel_id = KImpl::API::id();
- auto kernel_impl = GKernelImpl{KImpl::kernel()};
+ auto kernel_impl = GKernelImpl{KImpl::kernel(), &KImpl::API::getOutMeta};
removeAPI(kernel_id);
m_id_kernels[kernel_id] = std::make_pair(backend, kernel_impl);
/// @private
// Partial include() specialization for transformations
template <typename TImpl>
- typename std::enable_if<(std::is_base_of<detail::TransformTag, TImpl>::value), void>::type
+ typename std::enable_if<(std::is_base_of<cv::detail::TransformTag, TImpl>::value), void>::type
includeHelper()
{
m_transformations.emplace_back(TImpl::transformation());
template<typename KImpl>
bool includes() const
{
- static_assert(std::is_base_of<detail::KernelTag, KImpl>::value,
+ static_assert(std::is_base_of<cv::detail::KernelTag, KImpl>::value,
"includes() can be applied to kernels only");
auto kernel_it = m_id_kernels.find(KImpl::API::id());
{
// FIXME: currently there is no check that transformations' signatures are unique
// and won't be any intersection in graph compilation stage
- static_assert(detail::all_unique<typename KK::API...>::value, "Kernels API must be unique");
+ static_assert(cv::detail::all_unique<typename KK::API...>::value, "Kernels API must be unique");
GKernelPackage pkg;
static const char* tag() { return "gapi.use_only"; }
};
} // namespace detail
+
} // namespace cv
#endif // OPENCV_GAPI_GKERNEL_HPP
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GMAT_HPP
* `cv::GArray<T>` | std::vector<T>
* `cv::GOpaque<T>` | T
*/
-class GAPI_EXPORTS GMat
+class GAPI_EXPORTS_W_SIMPLE GMat
{
public:
- GMat(); // Empty constructor
+ GAPI_WRAP GMat(); // Empty constructor
GMat(const GNode &n, std::size_t out); // Operation result constructor
GOrigin& priv(); // Internal use only
using GMat::GMat;
};
-namespace gapi { namespace own {
- class Mat;
-}}//gapi::own
-
/** @} */
/**
// (it handles the case when
// 1-channel mat can be reinterpreted as is (1-channel mat)
// and as a 3-channel planar mat with height divided by 3)
- bool canDescribe(const cv::gapi::own::Mat& mat) const;
+ bool canDescribe(const cv::Mat& mat) const;
// Meta combinator: return a new GMatDesc which differs in size by delta
// (all other fields are taken unchanged from this GMatDesc)
desc.size += delta;
return desc;
}
-#if !defined(GAPI_STANDALONE)
- bool canDescribe(const cv::Mat& mat) const;
-#endif // !defined(GAPI_STANDALONE)
// Meta combinator: return a new GMatDesc which differs in size by delta
// (all other fields are taken unchanged from this GMatDesc)
//
static inline GMatDesc empty_gmat_desc() { return GMatDesc{-1,-1,{-1,-1}}; }
#if !defined(GAPI_STANDALONE)
-class Mat;
-GAPI_EXPORTS GMatDesc descr_of(const cv::Mat &mat);
GAPI_EXPORTS GMatDesc descr_of(const cv::UMat &mat);
#endif // !defined(GAPI_STANDALONE)
-/** @} */
-
-// FIXME: WHY??? WHY it is under different namespace?
+//Fwd declarations
namespace gapi { namespace own {
+ class Mat;
GAPI_EXPORTS GMatDesc descr_of(const Mat &mat);
}}//gapi::own
+#if !defined(GAPI_STANDALONE)
+GAPI_EXPORTS GMatDesc descr_of(const cv::Mat &mat);
+#else
+using gapi::own::descr_of;
+#endif
+
+/** @} */
+
GAPI_EXPORTS std::ostream& operator<<(std::ostream& os, const cv::GMatDesc &desc);
} // namespace cv
// Note: descr_of(std::vector<..>) returns a GArrayDesc, while
// descrs_of(std::vector<..>) returns an array of Meta args!
-class Mat;
class UMat;
GAPI_EXPORTS cv::GMetaArgs descrs_of(const std::vector<cv::Mat> &vec);
GAPI_EXPORTS cv::GMetaArgs descrs_of(const std::vector<cv::UMat> &vec);
namespace gapi { namespace own {
- class Mat;
GAPI_EXPORTS cv::GMetaArgs descrs_of(const std::vector<Mat> &vec);
}} // namespace gapi::own
// 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
+// Copyright (C) 2019-2020 Intel Corporation
#ifndef OPENCV_GAPI_GOPAQUE_HPP
#include <opencv2/gapi/util/variant.hpp>
#include <opencv2/gapi/util/throw.hpp>
+#include <opencv2/gapi/util/type_traits.hpp>
#include <opencv2/gapi/own/assert.hpp>
namespace cv
// (user-inaccessible) classes.
class GNode;
struct GOrigin;
-
template<typename T> class GOpaque;
/**
template <typename T>
void specifyType(); // Store type of initial GOpaque<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 GOpaqueU::holds() const{
GAPI_Assert(m_hint != nullptr);
- using U = typename std::decay<T>::type;
+ using U = util::decay_t<T>;
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>);
+ m_hint.reset(new TypeHint<util::decay_t<T>>);
+ };
+
+ template <typename T>
+ void GOpaqueU::storeKind(){
+ // FIXME: Add assert here on cv::Mat and cv::Scalar?
+ setKind(cv::detail::GOpaqueTraits<T>::kind);
};
// This class represents a typed object reference.
virtual ~BasicOpaqueRef() {}
virtual void mov(BasicOpaqueRef &ref) = 0;
+ virtual const void* ptr() const = 0;
};
template<typename T> class OpaqueRefT final: public BasicOpaqueRef
GAPI_Assert(tv != nullptr);
wref() = std::move(tv->wref());
}
+
+ virtual const void* ptr() const override { return &rref(); }
};
// This class strips type information from OpaqueRefT<> and makes it usable
class OpaqueRef
{
std::shared_ptr<BasicOpaqueRef> m_ref;
+ cv::detail::OpaqueKind m_kind;
template<typename T> inline void check() const
{
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,
+ typename = util::are_different_t<OpaqueRef, T>
+ >
+ // FIXME: probably won't work with const object
+ explicit OpaqueRef(T&& obj) :
+ m_ref(new OpaqueRefT<util::decay_t<T>>(std::forward<T>(obj))),
+ 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 OpaqueRefT<T>());
-
check<T>();
+ storeKind<T>();
static_cast<OpaqueRefT<T>&>(*m_ref).reset();
}
+ template <typename T>
+ void storeKind()
+ {
+ m_kind = cv::detail::GOpaqueTraits<T>::kind;
+ }
+
template<typename T> T& wref()
{
check<T>();
{
return m_ref->m_desc;
}
+
+ // May be used to uniquely identify this object internally
+ const void *ptr() const { return m_ref->ptr(); }
};
} // namespace detail
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;
+ using HT = typename detail::flatten_g<util::decay_t<T>>::type;
static void CTor(detail::OpaqueRef& ref) {
ref.reset<HT>();
+ ref.storeKind<HT>();
}
void putDetails() {
m_ref.setConstructFcn(&CTor);
- m_ref.specifyType<HT>();
+ m_ref.specifyType<HT>(); // FIXME: to unify those 2 to avoid excessive dynamic_cast
+ m_ref.storeKind<HT>(); //
}
detail::GOpaqueU m_ref;
using GProtoArg = util::variant
< GMat
, GMatP
+ , GFrame
, GScalar
, detail::GArrayU // instead of GArray<T>
, detail::GOpaqueU // instead of GOpaque<T>
struct GIOProtoArgs
{
public:
+ // NB: Used by python wrapper
+ GIOProtoArgs() = default;
explicit GIOProtoArgs(const GProtoArgs& args) : m_args(args) {}
explicit GIOProtoArgs(GProtoArgs &&args) : m_args(std::move(args)) {}
GProtoArgs m_args;
+
+ // TODO: Think about the addition operator
+ /**
+ * @brief This operator allows to complement the proto vectors at runtime.
+ *
+ * It's an ordinary overload of addition assignment operator.
+ *
+ * Example of usage:
+ * @snippet dynamic_graph.cpp GIOProtoArgs usage
+ *
+ */
+ template<typename Tg>
+ friend GIOProtoArgs<Tg>& operator += (GIOProtoArgs<Tg> &lhs, const GIOProtoArgs<Tg> &rhs);
};
+template<typename Tg>
+cv::GIOProtoArgs<Tg>& operator += (cv::GIOProtoArgs<Tg> &lhs, const cv::GIOProtoArgs<Tg> &rhs)
+{
+ lhs.m_args.reserve(lhs.m_args.size() + rhs.m_args.size());
+ lhs.m_args.insert(lhs.m_args.end(), rhs.m_args.begin(), rhs.m_args.end());
+ return lhs;
+}
+
struct In_Tag{};
struct Out_Tag{};
* @{
*/
-class GAPI_EXPORTS GScalar
+class GAPI_EXPORTS_W_SIMPLE GScalar
{
public:
- GScalar(); // Empty constructor
+ GAPI_WRAP GScalar(); // Empty constructor
explicit GScalar(const cv::Scalar& s); // Constant value constructor from cv::Scalar
explicit GScalar(cv::Scalar&& s); // Constant value move-constructor from cv::Scalar
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GTYPE_TRAITS_HPP
#include <opencv2/gapi/gscalar.hpp>
#include <opencv2/gapi/garray.hpp>
#include <opencv2/gapi/gopaque.hpp>
+#include <opencv2/gapi/gframe.hpp>
#include <opencv2/gapi/streaming/source.hpp>
#include <opencv2/gapi/gcommon.hpp>
-#include <opencv2/gapi/own/convert.hpp>
namespace cv
{
GOBJREF, // <internal> reference to object
GMAT, // a cv::GMat
GMATP, // a cv::GMatP
+ GFRAME, // a cv::GFrame
GSCALAR, // a cv::GScalar
GARRAY, // a cv::GArrayU (note - exactly GArrayU, not GArray<T>!)
GOPAQUE, // a cv::GOpaqueU (note - exactly GOpaqueU, not GOpaque<T>!)
template<typename T> struct GTypeTraits
{
static constexpr const ArgKind kind = ArgKind::OPAQUE_VAL;
+ static constexpr const OpaqueKind op_kind = OpaqueKind::CV_UNKNOWN;
};
template<> struct GTypeTraits<cv::GMat>
{
static constexpr const ArgKind kind = ArgKind::GMAT;
static constexpr const GShape shape = GShape::GMAT;
+ static constexpr const OpaqueKind op_kind = OpaqueKind::CV_UNKNOWN;
};
template<> struct GTypeTraits<cv::GMatP>
{
static constexpr const ArgKind kind = ArgKind::GMATP;
static constexpr const GShape shape = GShape::GMAT;
+ static constexpr const OpaqueKind op_kind = OpaqueKind::CV_UNKNOWN;
+ };
+ template<> struct GTypeTraits<cv::GFrame>
+ {
+ static constexpr const ArgKind kind = ArgKind::GFRAME;
+ static constexpr const GShape shape = GShape::GMAT;
+ static constexpr const OpaqueKind op_kind = OpaqueKind::CV_UNKNOWN;
};
template<> struct GTypeTraits<cv::GScalar>
{
static constexpr const ArgKind kind = ArgKind::GSCALAR;
static constexpr const GShape shape = GShape::GSCALAR;
+ static constexpr const OpaqueKind op_kind = OpaqueKind::CV_UNKNOWN;
};
template<class T> struct GTypeTraits<cv::GArray<T> >
{
static constexpr const ArgKind kind = ArgKind::GARRAY;
static constexpr const GShape shape = GShape::GARRAY;
+ static constexpr const OpaqueKind op_kind = GOpaqueTraits<T>::kind;
using host_type = std::vector<T>;
using strip_type = cv::detail::VectorRef;
static cv::detail::GArrayU wrap_value(const cv::GArray<T> &t) { return t.strip();}
{
static constexpr const ArgKind kind = ArgKind::GOPAQUE;
static constexpr const GShape shape = GShape::GOPAQUE;
+ static constexpr const OpaqueKind op_kind = GOpaqueTraits<T>::kind;
using host_type = T;
using strip_type = cv::detail::OpaqueRef;
static cv::detail::GOpaqueU wrap_value(const cv::GOpaque<T> &t) { return t.strip();}
// and GMat behavior is correct for GMatP)
template<typename T> struct GTypeOf;
#if !defined(GAPI_STANDALONE)
- template<> struct GTypeOf<cv::Mat> { using type = cv::GMat; };
template<> struct GTypeOf<cv::UMat> { using type = cv::GMat; };
#endif // !defined(GAPI_STANDALONE)
- template<> struct GTypeOf<cv::gapi::own::Mat> { using type = cv::GMat; };
+ template<> struct GTypeOf<cv::Mat> { using type = cv::GMat; };
template<> struct GTypeOf<cv::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>;};
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<> struct ProtoToParam<cv::GArray<cv::GMat>> { using type = std::vector<cv::Mat>; };
template<typename U> struct ProtoToParam<cv::GOpaque<U> > { using type = U; };
template<typename T> using ProtoToParamT = typename ProtoToParam<T>::type;
}
void apply(detail::ProtoToParamT<Args>... inArgs,
+ detail::ProtoToParamT<R> &outArg,
+ GCompileArgs &&args)
+ {
+ m_comp.apply(cv::gin(inArgs...), cv::gout(outArg), std::move(args));
+ }
+
+ void apply(detail::ProtoToParamT<Args>... inArgs,
detail::ProtoToParamT<R> &outArg)
{
- m_comp.apply(cv::gin(inArgs...), cv::gout(outArg));
+ apply(inArgs..., outArg, GCompileArgs());
}
+
GCompiledT compile(detail::ProtoToMetaT<Args>... inDescs)
{
GMetaArgs inMetas = { GMetaArg(inDescs)... };
}
void apply(detail::ProtoToParamT<Args>... inArgs,
+ detail::ProtoToParamT<R>&... outArgs,
+ GCompileArgs &&args)
+ {
+ m_comp.apply(cv::gin(inArgs...), cv::gout(outArgs...), std::move(args));
+ }
+
+ void apply(detail::ProtoToParamT<Args>... inArgs,
detail::ProtoToParamT<R>&... outArgs)
{
- m_comp.apply(cv::gin(inArgs...), cv::gout(outArgs...));
+ apply(inArgs..., outArgs..., GCompileArgs());
}
+
GCompiledT compile(detail::ProtoToMetaT<Args>... inDescs)
{
GMetaArgs inMetas = { GMetaArg(inDescs)... };
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_IMGPROC_HPP
}
};
+ G_TYPED_KERNEL(GLaplacian, <GMat(GMat,int, int, double, double, int)>,
+ "org.opencv.imgproc.filters.laplacian") {
+ static GMatDesc outMeta(GMatDesc in, int ddepth, int, double, double, int) {
+ return in.withDepth(ddepth);
+ }
+ };
+
+ G_TYPED_KERNEL(GBilateralFilter, <GMat(GMat,int, double, double, int)>,
+ "org.opencv.imgproc.filters.bilateralfilter") {
+ static GMatDesc outMeta(GMatDesc in, int, double, double, int) {
+ return in;
+ }
+ };
+
G_TYPED_KERNEL(GEqHist, <GMat(GMat)>, "org.opencv.imgproc.equalizeHist"){
static GMatDesc outMeta(GMatDesc in) {
return in.withType(CV_8U, 1);
}
};
+ G_TYPED_KERNEL(GGoodFeatures,
+ <cv::GArray<cv::Point2f>(GMat,int,double,double,Mat,int,bool,double)>,
+ "org.opencv.imgproc.goodFeaturesToTrack") {
+ static GArrayDesc outMeta(GMatDesc, int, double, double, const Mat&, int, bool, double) {
+ return empty_array_desc();
+ }
+ };
+
G_TYPED_KERNEL(GRGB2YUV, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.rgb2yuv") {
static GMatDesc outMeta(GMatDesc in) {
return in; // type still remains CV_8UC3;
}
};
-}
-
+} //namespace imgproc
//! @addtogroup gapi_filters
//! @{
The function does actually compute correlation, not the convolution:
-\f[\texttt{dst} (x,y) = \sum _{ \stackrel{0\leq x' < \texttt{kernel.cols},}{0\leq y' < \texttt{kernel.rows}} } \texttt{kernel} (x',y')* \texttt{src} (x+x'- \texttt{anchor.x} ,y+y'- \texttt{anchor.y} )\f]
+\f[\texttt{dst} (x,y) = \sum _{ \substack{0\leq x' < \texttt{kernel.cols}\\{0\leq y' < \texttt{kernel.rows}}}} \texttt{kernel} (x',y')* \texttt{src} (x+x'- \texttt{anchor.x} ,y+y'- \texttt{anchor.y} )\f]
That is, the kernel is not mirrored around the anchor point. If you need a real convolution, flip
the kernel using flip and set the new anchor to `(kernel.cols - anchor.x - 1, kernel.rows -
where
-\f[\alpha = \fork{\frac{1}{\texttt{ksize.width*ksize.height}}}{when \texttt{normalize=true}}{1}{otherwise}\f]
+\f[\alpha = \begin{cases} \frac{1}{\texttt{ksize.width*ksize.height}} & \texttt{when } \texttt{normalize=true} \\1 & \texttt{otherwise} \end{cases}\f]
Unnormalized box filter is useful for computing various integral characteristics over each pixel
neighborhood, such as covariance matrices of image derivatives (used in dense optical flow
\f[\texttt{K} = \frac{1}{\texttt{ksize.width*ksize.height}} \begin{bmatrix} 1 & 1 & 1 & \cdots & 1 & 1 \\ 1 & 1 & 1 & \cdots & 1 & 1 \\ \hdotsfor{6} \\ 1 & 1 & 1 & \cdots & 1 & 1 \\ \end{bmatrix}\f]
-The call `blur(src, dst, ksize, anchor, borderType)` is equivalent to `boxFilter(src, dst, src.type(),
-anchor, true, borderType)`.
+The call `blur(src, ksize, anchor, borderType)` is equivalent to `boxFilter(src, src.type(), ksize, anchor,
+true, borderType)`.
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, @ref CV_32FC1.
Output image must have the same type, size, and number of channels as the input image.
int borderType = BORDER_DEFAULT,
const Scalar& borderValue = Scalar(0));
+/** @brief Calculates the Laplacian of an image.
+
+The function calculates the Laplacian of the source image by adding up the second x and y
+derivatives calculated using the Sobel operator:
+
+\f[\texttt{dst} = \Delta \texttt{src} = \frac{\partial^2 \texttt{src}}{\partial x^2} + \frac{\partial^2 \texttt{src}}{\partial y^2}\f]
+
+This is done when `ksize > 1`. When `ksize == 1`, the Laplacian is computed by filtering the image
+with the following \f$3 \times 3\f$ aperture:
+
+\f[\vecthreethree {0}{1}{0}{1}{-4}{1}{0}{1}{0}\f]
+
+@note Function textual ID is "org.opencv.imgproc.filters.laplacian"
+
+@param src Source image.
+@param ddepth Desired depth of the destination image.
+@param ksize Aperture size used to compute the second-derivative filters. See #getDerivKernels for
+details. The size must be positive and odd.
+@param scale Optional scale factor for the computed Laplacian values. By default, no scaling is
+applied. See #getDerivKernels for details.
+@param delta Optional delta value that is added to the results prior to storing them in dst .
+@param borderType Pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported.
+@return Destination image of the same size and the same number of channels as src.
+@sa Sobel, Scharr
+ */
+GAPI_EXPORTS GMat Laplacian(const GMat& src, int ddepth, int ksize = 1,
+ double scale = 1, double delta = 0, int borderType = BORDER_DEFAULT);
+
+/** @brief Applies the bilateral filter to an image.
+
+The function applies bilateral filtering to the input image, as described in
+http://www.dai.ed.ac.uk/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html
+bilateralFilter can reduce unwanted noise very well while keeping edges fairly sharp. However, it is
+very slow compared to most filters.
+
+_Sigma values_: For simplicity, you can set the 2 sigma values to be the same. If they are small (\<
+10), the filter will not have much effect, whereas if they are large (\> 150), they will have a very
+strong effect, making the image look "cartoonish".
+
+_Filter size_: Large filters (d \> 5) are very slow, so it is recommended to use d=5 for real-time
+applications, and perhaps d=9 for offline applications that need heavy noise filtering.
+
+This filter does not work inplace.
+
+@note Function textual ID is "org.opencv.imgproc.filters.bilateralfilter"
+
+@param src Source 8-bit or floating-point, 1-channel or 3-channel image.
+@param d Diameter of each pixel neighborhood that is used during filtering. If it is non-positive,
+it is computed from sigmaSpace.
+@param sigmaColor Filter sigma in the color space. A larger value of the parameter means that
+farther colors within the pixel neighborhood (see sigmaSpace) will be mixed together, resulting
+in larger areas of semi-equal color.
+@param sigmaSpace Filter sigma in the coordinate space. A larger value of the parameter means that
+farther pixels will influence each other as long as their colors are close enough (see sigmaColor
+). When d\>0, it specifies the neighborhood size regardless of sigmaSpace. Otherwise, d is
+proportional to sigmaSpace.
+@param borderType border mode used to extrapolate pixels outside of the image, see #BorderTypes
+@return Destination image of the same size and type as src.
+ */
+GAPI_EXPORTS GMat bilateralFilter(const GMat& src, int d, double sigmaColor, double sigmaSpace,
+ int borderType = BORDER_DEFAULT);
+
/** @brief Finds edges in an image using the Canny algorithm.
The function finds edges in the input image and marks them in the output map edges using the
GAPI_EXPORTS GMat Canny(const GMat& image, double threshold1, double threshold2,
int apertureSize = 3, bool L2gradient = false);
+/** @brief Determines strong corners on an image.
+
+The function finds the most prominent corners in the image or in the specified image region, as
+described in @cite Shi94
+
+- Function calculates the corner quality measure at every source image pixel using the
+ #cornerMinEigenVal or #cornerHarris .
+- Function performs a non-maximum suppression (the local maximums in *3 x 3* neighborhood are
+ retained).
+- The corners with the minimal eigenvalue less than
+ \f$\texttt{qualityLevel} \cdot \max_{x,y} qualityMeasureMap(x,y)\f$ are rejected.
+- The remaining corners are sorted by the quality measure in the descending order.
+- Function throws away each corner for which there is a stronger corner at a distance less than
+ maxDistance.
+
+The function can be used to initialize a point-based tracker of an object.
+
+@note If the function is called with different values A and B of the parameter qualityLevel , and
+A \> B, the vector of returned corners with qualityLevel=A will be the prefix of the output vector
+with qualityLevel=B .
+
+@note Function textual ID is "org.opencv.imgproc.goodFeaturesToTrack"
+
+@param image Input 8-bit or floating-point 32-bit, single-channel image.
+@param maxCorners Maximum number of corners to return. If there are more corners than are found,
+the strongest of them is returned. `maxCorners <= 0` implies that no limit on the maximum is set
+and all detected corners are returned.
+@param qualityLevel Parameter characterizing the minimal accepted quality of image corners. The
+parameter value is multiplied by the best corner quality measure, which is the minimal eigenvalue
+(see #cornerMinEigenVal ) or the Harris function response (see #cornerHarris ). The corners with the
+quality measure less than the product are rejected. For example, if the best corner has the
+quality measure = 1500, and the qualityLevel=0.01 , then all the corners with the quality measure
+less than 15 are rejected.
+@param minDistance Minimum possible Euclidean distance between the returned corners.
+@param mask Optional region of interest. If the image is not empty (it needs to have the type
+CV_8UC1 and the same size as image ), it specifies the region in which the corners are detected.
+@param blockSize Size of an average block for computing a derivative covariation matrix over each
+pixel neighborhood. See cornerEigenValsAndVecs .
+@param useHarrisDetector Parameter indicating whether to use a Harris detector (see #cornerHarris)
+or #cornerMinEigenVal.
+@param k Free parameter of the Harris detector.
+
+@return vector of detected corners.
+ */
+GAPI_EXPORTS GArray<Point2f> goodFeaturesToTrack(const GMat &image,
+ int maxCorners,
+ double qualityLevel,
+ double minDistance,
+ const Mat &mask = Mat(),
+ int blockSize = 3,
+ bool useHarrisDetector = false,
+ double k = 0.04);
+
/** @brief Equalizes the histogram of a grayscale image.
The function equalizes the histogram of the input image using the following algorithm:
#include <functional>
#include <string> // string
#include <utility> // tuple
+#include <type_traits> // is_same, false_type
#include <opencv2/gapi/util/any.hpp> // any<>
#include <opencv2/gapi/gkernel.hpp> // GKernelType[M], GBackend
template<typename, typename> class GNetworkType;
+namespace detail {
+ template<typename, typename>
+ struct valid_infer2_types;
+
+ // Terminal case 1 (50/50 success)
+ template<typename T>
+ struct valid_infer2_types< std::tuple<cv::GMat>, std::tuple<T> > {
+ // By default, Nets are limited to GMat argument types only
+ // for infer2, every GMat argument may translate to either
+ // GArray<GMat> or GArray<Rect>. GArray<> part is stripped
+ // already at this point.
+ static constexpr const auto value =
+ std::is_same<typename std::decay<T>::type, cv::GMat>::value
+ || std::is_same<typename std::decay<T>::type, cv::Rect>::value;
+ };
+
+ // Terminal case 2 (100% failure)
+ template<typename... Ts>
+ struct valid_infer2_types< std::tuple<>, std::tuple<Ts...> >
+ : public std::false_type {
+ };
+
+ // Terminal case 3 (100% failure)
+ template<typename... Ns>
+ struct valid_infer2_types< std::tuple<Ns...>, std::tuple<> >
+ : public std::false_type {
+ };
+
+ // Recursion -- generic
+ template<typename... Ns, typename T, typename...Ts>
+ struct valid_infer2_types< std::tuple<cv::GMat,Ns...>, std::tuple<T,Ts...> > {
+ static constexpr const auto value =
+ valid_infer2_types< std::tuple<cv::GMat>, std::tuple<T> >::value
+ && valid_infer2_types< std::tuple<Ns...>, std::tuple<Ts...> >::value;
+ };
+} // namespace detail
+
// 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>
using APIList = std::function<ResultL(cv::GArray<cv::Rect>, Args...)>;
};
+// APIList2 is also template to allow different calling options
+// (GArray<cv::Rect> vs GArray<cv::GMat> per input)
+template<class Net, class... Ts>
+struct InferAPIList2 {
+ using type = typename std::enable_if
+ < cv::detail::valid_infer2_types< typename Net::InArgs
+ , std::tuple<Ts...> >::value,
+ std::function<typename Net::ResultL(cv::GMat, cv::GArray<Ts>...)>
+ >::type;
+};
+
// 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)
// All notes from "Infer" kernel apply here as well.
struct GInferListBase {
static constexpr const char * id() {
- return "org.opencv.dnn.infer-roi"; // Universal stub
+ return "org.opencv.dnn.infer-roi"; // Universal stub
}
static GMetaArgs getOutMeta(const GMetaArgs &, const GArgs &) {
- return GMetaArgs{}; // One more universal stub
+ return GMetaArgs{}; // One more universal stub
+ }
+};
+
+// Base "Infer list 2" kernel.
+// All notes from "Infer" kernel apply here as well.
+struct GInferList2Base {
+ static constexpr const char * id() {
+ return "org.opencv.dnn.infer-roi-list"; // Universal stub
+ }
+ static GMetaArgs getOutMeta(const GMetaArgs &, const GArgs &) {
+ return GMetaArgs{}; // One more universal stub
}
};
static constexpr const char* tag() { return Net::tag(); }
};
+// An even more generic roi-list inference kernel. API (::on()) is
+// derived from the Net template parameter (see more in infer<>
+// overload).
+// Takes an extra variadic template list to reflect how this network
+// was called (with Rects or GMats as array parameters)
+template<typename Net, typename... Args>
+struct GInferList2 final
+ : public GInferList2Base
+ , public detail::KernelTypeMedium< GInferList2<Net, Args...>
+ , typename InferAPIList2<Net, Args...>::type > {
+ using GInferList2Base::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
return GInferList<Net>::on(roi, std::forward<Args>(args)...);
}
+/** @brief Calculates responses for the specified network (template
+ * parameter) for every region in the source image, extended version.
+ *
+ * @tparam A network type defined with G_API_NET() macro.
+ * @param image A source image containing regions of interest
+ * @param args GArray<> objects of cv::Rect or cv::GMat, one per every
+ * network input:
+ * - If a cv::GArray<cv::Rect> is passed, the appropriate
+ * regions are taken from `image` and preprocessed to this particular
+ * network input;
+ * - If a cv::GArray<cv::GMat> is passed, the underlying data traited
+ * as tensor (no automatic preprocessing happen).
+ * @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 infer2(cv::GMat image, cv::GArray<Args>... args) {
+ // FIXME: Declared as "2" because in the current form it steals
+ // overloads from the regular infer
+ return GInferList2<Net, Args...>::on(image, args...);
+}
+
/**
* @brief Calculates response for the specified network (template
* parameter) given the input data.
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
+ , std::tuple_size<typename Net::InArgs>::value // num_in
+ , std::tuple_size<typename Net::OutArgs>::value // num_out
} {
};
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#ifndef OPENCV_GAPI_PARSERS_HPP
+#define OPENCV_GAPI_PARSERS_HPP
+
+#include <utility> // std::tuple
+
+#include <opencv2/gapi/gmat.hpp>
+#include <opencv2/gapi/gkernel.hpp>
+
+namespace cv { namespace gapi {
+namespace nn {
+namespace parsers {
+ using GRects = GArray<Rect>;
+ using GDetections = std::tuple<GArray<Rect>, GArray<int>>;
+
+ G_TYPED_KERNEL(GParseSSDBL, <GDetections(GMat, GOpaque<Size>, float, int)>,
+ "org.opencv.nn.parsers.parseSSD_BL") {
+ static std::tuple<GArrayDesc,GArrayDesc> outMeta(const GMatDesc&, const GOpaqueDesc&, float, int) {
+ return std::make_tuple(empty_array_desc(), empty_array_desc());
+ }
+ };
+
+ G_TYPED_KERNEL(GParseSSD, <GRects(GMat, GOpaque<Size>, float, bool, bool)>,
+ "org.opencv.nn.parsers.parseSSD") {
+ static GArrayDesc outMeta(const GMatDesc&, const GOpaqueDesc&, float, bool, bool) {
+ return empty_array_desc();
+ }
+ };
+
+ G_TYPED_KERNEL(GParseYolo, <GDetections(GMat, GOpaque<Size>, float, float, std::vector<float>)>,
+ "org.opencv.nn.parsers.parseYolo") {
+ static std::tuple<GArrayDesc, GArrayDesc> outMeta(const GMatDesc&, const GOpaqueDesc&,
+ float, float, const std::vector<float>&) {
+ return std::make_tuple(empty_array_desc(), empty_array_desc());
+ }
+ static const std::vector<float>& defaultAnchors() {
+ static std::vector<float> anchors {
+ 0.57273f, 0.677385f, 1.87446f, 2.06253f, 3.33843f, 5.47434f, 7.88282f, 3.52778f, 9.77052f, 9.16828f
+ };
+ return anchors;
+ }
+ };
+} // namespace parsers
+} // namespace nn
+
+/** @brief Parses output of SSD network.
+
+Extracts detection information (box, confidence, label) from SSD output and
+filters it by given confidence and label.
+
+@note Function textual ID is "org.opencv.nn.parsers.parseSSD_BL"
+
+@param in Input CV_32F tensor with {1,1,N,7} dimensions.
+@param inSz Size to project detected boxes to (size of the input image).
+@param confidenceThreshold If confidence of the
+detection is smaller than confidence threshold, detection is rejected.
+@param filterLabel If provided (!= -1), only detections with
+given label will get to the output.
+@return a tuple with a vector of detected boxes and a vector of appropriate labels.
+*/
+GAPI_EXPORTS std::tuple<GArray<Rect>, GArray<int>> parseSSD(const GMat& in,
+ const GOpaque<Size>& inSz,
+ const float confidenceThreshold = 0.5f,
+ const int filterLabel = -1);
+
+/** @overload
+Extracts detection information (box, confidence) from SSD output and
+filters it by given confidence and by going out of bounds.
+
+@note Function textual ID is "org.opencv.nn.parsers.parseSSD"
+
+@param in Input CV_32F tensor with {1,1,N,7} dimensions.
+@param inSz Size to project detected boxes to (size of the input image).
+@param confidenceThreshold If confidence of the
+detection is smaller than confidence threshold, detection is rejected.
+@param alignmentToSquare If provided true, bounding boxes are extended to squares.
+The center of the rectangle remains unchanged, the side of the square is
+the larger side of the rectangle.
+@param filterOutOfBounds If provided true, out-of-frame boxes are filtered.
+@return a vector of detected bounding boxes.
+*/
+GAPI_EXPORTS GArray<Rect> parseSSD(const GMat& in,
+ const GOpaque<Size>& inSz,
+ const float confidenceThreshold = 0.5f,
+ const bool alignmentToSquare = false,
+ const bool filterOutOfBounds = false);
+
+/** @brief Parses output of Yolo network.
+
+Extracts detection information (box, confidence, label) from Yolo output,
+filters it by given confidence and performs non-maximum supression for overlapping boxes.
+
+@note Function textual ID is "org.opencv.nn.parsers.parseYolo"
+
+@param in Input CV_32F tensor with {1,13,13,N} dimensions, N should satisfy:
+\f[\texttt{N} = (\texttt{num_classes} + \texttt{5}) * \texttt{5},\f]
+where num_classes - a number of classes Yolo network was trained with.
+@param inSz Size to project detected boxes to (size of the input image).
+@param confidenceThreshold If confidence of the
+detection is smaller than confidence threshold, detection is rejected.
+@param nmsThreshold Non-maximum supression threshold which controls minimum
+relative box intersection area required for rejecting the box with a smaller confidence.
+If 1.f, nms is not performed and no boxes are rejected.
+@param anchors Anchors Yolo network was trained with.
+@note The default anchor values are taken from openvinotoolkit docs:
+https://docs.openvinotoolkit.org/latest/omz_models_intel_yolo_v2_tiny_vehicle_detection_0001_description_yolo_v2_tiny_vehicle_detection_0001.html#output.
+@return a tuple with a vector of detected boxes and a vector of appropriate labels.
+*/
+GAPI_EXPORTS std::tuple<GArray<Rect>, GArray<int>> parseYolo(const GMat& in,
+ const GOpaque<Size>& inSz,
+ const float confidenceThreshold = 0.5f,
+ const float nmsThreshold = 0.5f,
+ const std::vector<float>& anchors
+ = nn::parsers::GParseYolo::defaultAnchors());
+
+} // namespace gapi
+} // namespace cv
+
+#endif // OPENCV_GAPI_PARSERS_HPP
namespace core {
namespace ocl {
- GAPI_EXPORTS GKernelPackage kernels();
+ GAPI_EXPORTS_W cv::gapi::GKernelPackage kernels();
} // namespace ocl
} // namespace core
# include <opencv2/core/base.hpp>
#else // Without OpenCV
# include <opencv2/gapi/own/cvdefs.hpp>
+# include <opencv2/gapi/own/types.hpp> // cv::gapi::own::Rect/Size/Point
+# include <opencv2/gapi/own/scalar.hpp> // cv::gapi::own::Scalar
+# include <opencv2/gapi/own/mat.hpp>
+// replacement of cv's structures:
+namespace cv {
+ using Rect = gapi::own::Rect;
+ using Size = gapi::own::Size;
+ using Point = gapi::own::Point;
+ using Scalar = gapi::own::Scalar;
+ using Mat = gapi::own::Mat;
+} // namespace cv
#endif // !defined(GAPI_STANDALONE)
#endif // OPENCV_GAPI_OPENCV_INCLUDES_HPP
#include <opencv2/gapi/gmat.hpp>
#include <opencv2/gapi/gscalar.hpp>
+namespace cv
+{
GAPI_EXPORTS cv::GMat operator+(const cv::GMat& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator+(const cv::GMat& lhs, const cv::GScalar& rhs);
GAPI_EXPORTS cv::GMat operator<=(const cv::GScalar& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator==(const cv::GScalar& lhs, const cv::GMat& rhs);
GAPI_EXPORTS cv::GMat operator!=(const cv::GScalar& lhs, const cv::GMat& rhs);
-
-
+} // cv
#endif // OPENCV_GAPI_OPERATORS_HPP
namespace detail
{
- inline void assert_abort(const char* str, int line, const char* file, const char* func)
+ [[noreturn]] inline void assert_abort(const char* str, int line, const char* file, const char* func)
{
std::stringstream ss;
ss << file << ":" << line << ": Assertion " << str << " in function " << func << " failed\n";
return result;
}
- cv::gapi::own::Mat to_own(Mat&&) = delete;
+ 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};
};
+
namespace gapi
{
namespace own
{
+
inline cv::Mat to_ocv(Mat const& m) {
return m.dims.empty()
? cv::Mat{m.rows, m.cols, m.type(), m.data, m.step}
: cv::Mat{m.dims, m.type(), m.data};
}
- cv::Mat to_ocv(Mat&&) = delete;
+
+ cv::Mat to_ocv(Mat&&) = delete;
+
} // namespace own
} // namespace gapi
} // namespace cv
#define OPENCV_GAPI_CV_DEFS_HPP
#if defined(GAPI_STANDALONE)
-#include <opencv2/gapi/own/types.hpp> // cv::gapi::own::Rect/Size/Point
-#include <opencv2/gapi/own/scalar.hpp> // cv::gapi::own::Scalar
-
// Simulate OpenCV definitions taken from various
// OpenCV interface headers if G-API is built in a
// standalone mode.
INTER_LINEAR_EXACT = 5,
INTER_MAX = 7,
};
-// replacement of cv's structures:
-using Rect = gapi::own::Rect;
-using Size = gapi::own::Size;
-using Point = gapi::own::Point;
-using Scalar = gapi::own::Scalar;
} // namespace cv
static inline int cvFloor( double value )
# if defined(__OPENCV_BUILD)
# include <opencv2/core/base.hpp>
# define GAPI_EXPORTS CV_EXPORTS
+ /* special informative macros for wrapper generators */
+# define GAPI_WRAP CV_WRAP
+# define GAPI_EXPORTS_W_SIMPLE CV_EXPORTS_W_SIMPLE
+# define GAPI_EXPORTS_W CV_EXPORTS_W
# else
+# define GAPI_WRAP
# define GAPI_EXPORTS
+# define GAPI_EXPORTS_W_SIMPLE
+# define GAPI_EXPORTS_W
#if 0 // Note: the following version currently is not needed for non-OpenCV build
# if defined _WIN32
#include <memory> //std::shared_ptr
#include <cstring> //std::memcpy
#include <numeric> //std::accumulate
+#include <vector>
#include <opencv2/gapi/util/throw.hpp>
namespace cv { namespace gapi { namespace own {
data = ptr(roi.y, roi.x);
}
- Mat(Mat const& src) = default;
- Mat(Mat&& src) = default;
+ Mat(Mat const& ) = default;
+ Mat(Mat&& ) = default;
- Mat& operator=(Mat const& src) = default;
- Mat& operator=(Mat&& src) = default;
+ Mat& operator=(Mat const& ) = default;
+ Mat& operator=(Mat&& ) = default;
/** @brief Sets all or some of the array elements to the specified value.
@param s Assigned scalar converted to the actual array type.
namespace cv { namespace gapi { namespace core { namespace plaidml {
-GAPI_EXPORTS GKernelPackage kernels();
+GAPI_EXPORTS cv::gapi::GKernelPackage kernels();
}}}}
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018-2019 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_RENDER_HPP
#define OPENCV_GAPI_RENDER_HPP
-#include <string>
-#include <vector>
+#include <opencv2/gapi/render/render_types.hpp>
-#include <opencv2/imgproc.hpp>
#include <opencv2/gapi.hpp>
-#include <opencv2/gapi/opencv_includes.hpp>
-#include <opencv2/gapi/util/variant.hpp>
-#include <opencv2/gapi/own/exports.hpp>
-
-
/** \defgroup gapi_draw G-API Drawing and composition functionality
* @{
*
namespace draw
{
-/**
- * @brief This structure specifies which FreeType font to use by FText primitives.
- */
-struct freetype_font
-{
- /*@{*/
- std::string path; //!< The path to the font file (.ttf)
- /*@{*/
-};
-
-//! @addtogroup gapi_draw_prims
-//! @{
-/**
- * @brief This structure represents a text string to draw.
- *
- * Parameters match cv::putText().
- */
-struct Text
-{
- /**
- * @brief Text constructor
- *
- * @param text_ The text string to be drawn
- * @param org_ The bottom-left corner of the text string in the image
- * @param ff_ The font type, see #HersheyFonts
- * @param fs_ The font scale factor that is multiplied by the font-specific base size
- * @param color_ The text color
- * @param thick_ The thickness of the lines used to draw a text
- * @param lt_ The line type. See #LineTypes
- * @param bottom_left_origin_ When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner
- */
- Text(const std::string& text_,
- const cv::Point& org_,
- int ff_,
- double fs_,
- const cv::Scalar& color_,
- int thick_ = 1,
- int lt_ = cv::LINE_8,
- bool bottom_left_origin_ = false) :
- text(text_), org(org_), ff(ff_), fs(fs_),
- color(color_), thick(thick_), lt(lt_), bottom_left_origin(bottom_left_origin_)
- {
- }
-
- /*@{*/
- std::string text; //!< The text string to be drawn
- cv::Point org; //!< The bottom-left corner of the text string in the image
- int ff; //!< The font type, see #HersheyFonts
- double fs; //!< The font scale factor that is multiplied by the font-specific base size
- cv::Scalar color; //!< The text color
- int thick; //!< The thickness of the lines used to draw a text
- int lt; //!< The line type. See #LineTypes
- bool bottom_left_origin; //!< When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner
- /*@{*/
-};
-
-/**
- * @brief This structure represents a text string to draw using
- * FreeType renderer.
- *
- * If OpenCV is built without FreeType support, this primitive will
- * fail at the execution stage.
- */
-struct FText
-{
- /**
- * @brief FText constructor
- *
- * @param text_ The text string to be drawn
- * @param org_ The bottom-left corner of the text string in the image
- * @param fh_ The height of text
- * @param color_ The text color
- */
- FText(const std::wstring& text_,
- const cv::Point& org_,
- int fh_,
- const cv::Scalar& color_) :
- text(text_), org(org_), fh(fh_), color(color_)
- {
- }
-
- /*@{*/
- std::wstring text; //!< The text string to be drawn
- cv::Point org; //!< The bottom-left corner of the text string in the image
- int fh; //!< The height of text
- cv::Scalar color; //!< The text color
- /*@{*/
-};
-
-/**
- * @brief This structure represents a rectangle to draw.
- *
- * Parameters match cv::rectangle().
- */
-struct Rect
-{
- /**
- * @brief Rect constructor
- *
- * @param rect_ Coordinates of the rectangle
- * @param color_ The bottom-left corner of the text string in the image
- * @param thick_ The thickness of lines that make up the rectangle. Negative values, like #FILLED, mean that the function has to draw a filled rectangle
- * @param lt_ The type of the line. See #LineTypes
- * @param shift_ The number of fractional bits in the point coordinates
- */
- Rect(const cv::Rect& rect_,
- const cv::Scalar& color_,
- int thick_ = 1,
- int lt_ = cv::LINE_8,
- int shift_ = 0) :
- rect(rect_), color(color_), thick(thick_), lt(lt_), shift(shift_)
- {
- }
-
- /*@{*/
- cv::Rect rect; //!< Coordinates of the rectangle
- cv::Scalar color; //!< The rectangle color or brightness (grayscale image)
- int thick; //!< The thickness of lines that make up the rectangle. Negative values, like #FILLED, mean that the function has to draw a filled rectangle
- int lt; //!< The type of the line. See #LineTypes
- int shift; //!< The number of fractional bits in the point coordinates
- /*@{*/
-};
-
-/**
- * @brief This structure represents a circle to draw.
- *
- * Parameters match cv::circle().
- */
-struct Circle
-{
- /**
- * @brief Circle constructor
- *
- * @param center_ The center of the circle
- * @param radius_ The radius of the circle
- * @param color_ The color of the circle
- * @param thick_ The thickness of the circle outline, if positive. Negative values, like #FILLED, mean that a filled circle is to be drawn
- * @param lt_ The Type of the circle boundary. See #LineTypes
- * @param shift_ The Number of fractional bits in the coordinates of the center and in the radius value
- */
- Circle(const cv::Point& center_,
- int radius_,
- const cv::Scalar& color_,
- int thick_ = 1,
- int lt_ = cv::LINE_8,
- int shift_ = 0) :
- center(center_), radius(radius_), color(color_), thick(thick_), lt(lt_), shift(shift_)
- {
- }
-
- /*@{*/
- cv::Point center; //!< The center of the circle
- int radius; //!< The radius of the circle
- cv::Scalar color; //!< The color of the circle
- int thick; //!< The thickness of the circle outline, if positive. Negative values, like #FILLED, mean that a filled circle is to be drawn
- int lt; //!< The Type of the circle boundary. See #LineTypes
- int shift; //!< The Number of fractional bits in the coordinates of the center and in the radius value
- /*@{*/
-};
-
-/**
- * @brief This structure represents a line to draw.
- *
- * Parameters match cv::line().
- */
-struct Line
-{
- /**
- * @brief Line constructor
- *
- * @param pt1_ The first point of the line segment
- * @param pt2_ The second point of the line segment
- * @param color_ The line color
- * @param thick_ The thickness of line
- * @param lt_ The Type of the line. See #LineTypes
- * @param shift_ The number of fractional bits in the point coordinates
- */
- Line(const cv::Point& pt1_,
- const cv::Point& pt2_,
- const cv::Scalar& color_,
- int thick_ = 1,
- int lt_ = cv::LINE_8,
- int shift_ = 0) :
- pt1(pt1_), pt2(pt2_), color(color_), thick(thick_), lt(lt_), shift(shift_)
- {
- }
-
- /*@{*/
- cv::Point pt1; //!< The first point of the line segment
- cv::Point pt2; //!< The second point of the line segment
- cv::Scalar color; //!< The line color
- int thick; //!< The thickness of line
- int lt; //!< The Type of the line. See #LineTypes
- int shift; //!< The number of fractional bits in the point coordinates
- /*@{*/
-};
-
-/**
- * @brief This structure represents a mosaicing operation.
- *
- * Mosaicing is a very basic method to obfuscate regions in the image.
- */
-struct Mosaic
-{
- /**
- * @brief Mosaic constructor
- *
- * @param mos_ Coordinates of the mosaic
- * @param cellSz_ Cell size (same for X, Y)
- * @param decim_ Decimation (0 stands for no decimation)
- */
- Mosaic(const cv::Rect& mos_,
- int cellSz_,
- int decim_) :
- mos(mos_), cellSz(cellSz_), decim(decim_)
- {
- }
-
- /*@{*/
- cv::Rect mos; //!< Coordinates of the mosaic
- int cellSz; //!< Cell size (same for X, Y)
- int decim; //!< Decimation (0 stands for no decimation)
- /*@{*/
-};
-
-/**
- * @brief This structure represents an image to draw.
- *
- * Image is blended on a frame using the specified mask.
- */
-struct Image
-{
- /**
- * @brief Mosaic constructor
- *
- * @param org_ The bottom-left corner of the image
- * @param img_ Image to draw
- * @param alpha_ Alpha channel for image to draw (same size and number of channels)
- */
- Image(const cv::Point& org_,
- const cv::Mat& img_,
- const cv::Mat& alpha_) :
- org(org_), img(img_), alpha(alpha_)
- {
- }
-
- /*@{*/
- cv::Point org; //!< The bottom-left corner of the image
- cv::Mat img; //!< Image to draw
- cv::Mat alpha; //!< Alpha channel for image to draw (same size and number of channels)
- /*@{*/
-};
-
-/**
- * @brief This structure represents a polygon to draw.
- */
-struct Poly
-{
- /**
- * @brief Mosaic constructor
- *
- * @param points_ Points to connect
- * @param color_ The line color
- * @param thick_ The thickness of line
- * @param lt_ The Type of the line. See #LineTypes
- * @param shift_ The number of fractional bits in the point coordinate
- */
- Poly(const std::vector<cv::Point>& points_,
- const cv::Scalar& color_,
- int thick_ = 1,
- int lt_ = cv::LINE_8,
- int shift_ = 0) :
- points(points_), color(color_), thick(thick_), lt(lt_), shift(shift_)
- {
- }
-
- /*@{*/
- std::vector<cv::Point> points; //!< Points to connect
- cv::Scalar color; //!< The line color
- int thick; //!< The thickness of line
- int lt; //!< The Type of the line. See #LineTypes
- int shift; //!< The number of fractional bits in the point coordinate
- /*@{*/
-};
-
-using Prim = util::variant
- < Text
- , FText
- , Rect
- , Circle
- , Line
- , Mosaic
- , Image
- , Poly
- >;
-
-using Prims = std::vector<Prim>;
-//! @} gapi_draw_prims
-
using GMat2 = std::tuple<cv::GMat,cv::GMat>;
using GMatDesc2 = std::tuple<cv::GMatDesc,cv::GMatDesc>;
-
//! @addtogroup gapi_draw_api
//! @{
/** @brief The function renders on the input image passed drawing primitivies
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#ifndef OPENCV_GAPI_RENDER_TYPES_HPP
+#define OPENCV_GAPI_RENDER_TYPES_HPP
+
+#include <string>
+#include <vector>
+
+#include <opencv2/gapi/opencv_includes.hpp>
+#include <opencv2/gapi/util/variant.hpp>
+#include <opencv2/gapi/own/exports.hpp>
+
+namespace cv
+{
+namespace gapi
+{
+namespace wip
+{
+namespace draw
+{
+
+/**
+ * @brief This structure specifies which FreeType font to use by FText primitives.
+ */
+struct freetype_font
+{
+ /*@{*/
+ std::string path; //!< The path to the font file (.ttf)
+ /*@{*/
+};
+
+//! @addtogroup gapi_draw_prims
+//! @{
+/**
+ * @brief This structure represents a text string to draw.
+ *
+ * Parameters match cv::putText().
+ */
+struct Text
+{
+ /**
+ * @brief Text constructor
+ *
+ * @param text_ The text string to be drawn
+ * @param org_ The bottom-left corner of the text string in the image
+ * @param ff_ The font type, see #HersheyFonts
+ * @param fs_ The font scale factor that is multiplied by the font-specific base size
+ * @param color_ The text color
+ * @param thick_ The thickness of the lines used to draw a text
+ * @param lt_ The line type. See #LineTypes
+ * @param bottom_left_origin_ When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner
+ */
+ Text(const std::string& text_,
+ const cv::Point& org_,
+ int ff_,
+ double fs_,
+ const cv::Scalar& color_,
+ int thick_ = 1,
+ int lt_ = 8,
+ bool bottom_left_origin_ = false) :
+ text(text_), org(org_), ff(ff_), fs(fs_),
+ color(color_), thick(thick_), lt(lt_), bottom_left_origin(bottom_left_origin_)
+ {
+ }
+
+ Text() = default;
+
+ /*@{*/
+ std::string text; //!< The text string to be drawn
+ cv::Point org; //!< The bottom-left corner of the text string in the image
+ int ff; //!< The font type, see #HersheyFonts
+ double fs; //!< The font scale factor that is multiplied by the font-specific base size
+ cv::Scalar color; //!< The text color
+ int thick; //!< The thickness of the lines used to draw a text
+ int lt; //!< The line type. See #LineTypes
+ bool bottom_left_origin; //!< When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner
+ /*@{*/
+};
+
+/**
+ * @brief This structure represents a text string to draw using
+ * FreeType renderer.
+ *
+ * If OpenCV is built without FreeType support, this primitive will
+ * fail at the execution stage.
+ */
+struct FText
+{
+ /**
+ * @brief FText constructor
+ *
+ * @param text_ The text string to be drawn
+ * @param org_ The bottom-left corner of the text string in the image
+ * @param fh_ The height of text
+ * @param color_ The text color
+ */
+ FText(const std::wstring& text_,
+ const cv::Point& org_,
+ int fh_,
+ const cv::Scalar& color_) :
+ text(text_), org(org_), fh(fh_), color(color_)
+ {
+ }
+
+ FText() = default;
+
+ /*@{*/
+ std::wstring text; //!< The text string to be drawn
+ cv::Point org; //!< The bottom-left corner of the text string in the image
+ int fh; //!< The height of text
+ cv::Scalar color; //!< The text color
+ /*@{*/
+};
+
+/**
+ * @brief This structure represents a rectangle to draw.
+ *
+ * Parameters match cv::rectangle().
+ */
+struct Rect
+{
+ /**
+ * @brief Rect constructor
+ *
+ * @param rect_ Coordinates of the rectangle
+ * @param color_ The bottom-left corner of the text string in the image
+ * @param thick_ The thickness of lines that make up the rectangle. Negative values, like #FILLED, mean that the function has to draw a filled rectangle
+ * @param lt_ The type of the line. See #LineTypes
+ * @param shift_ The number of fractional bits in the point coordinates
+ */
+ Rect(const cv::Rect& rect_,
+ const cv::Scalar& color_,
+ int thick_ = 1,
+ int lt_ = 8,
+ int shift_ = 0) :
+ rect(rect_), color(color_), thick(thick_), lt(lt_), shift(shift_)
+ {
+ }
+
+ Rect() = default;
+
+ /*@{*/
+ cv::Rect rect; //!< Coordinates of the rectangle
+ cv::Scalar color; //!< The rectangle color or brightness (grayscale image)
+ int thick; //!< The thickness of lines that make up the rectangle. Negative values, like #FILLED, mean that the function has to draw a filled rectangle
+ int lt; //!< The type of the line. See #LineTypes
+ int shift; //!< The number of fractional bits in the point coordinates
+ /*@{*/
+};
+
+/**
+ * @brief This structure represents a circle to draw.
+ *
+ * Parameters match cv::circle().
+ */
+struct Circle
+{
+ /**
+ * @brief Circle constructor
+ *
+ * @param center_ The center of the circle
+ * @param radius_ The radius of the circle
+ * @param color_ The color of the circle
+ * @param thick_ The thickness of the circle outline, if positive. Negative values, like #FILLED, mean that a filled circle is to be drawn
+ * @param lt_ The Type of the circle boundary. See #LineTypes
+ * @param shift_ The Number of fractional bits in the coordinates of the center and in the radius value
+ */
+ Circle(const cv::Point& center_,
+ int radius_,
+ const cv::Scalar& color_,
+ int thick_ = 1,
+ int lt_ = 8,
+ int shift_ = 0) :
+ center(center_), radius(radius_), color(color_), thick(thick_), lt(lt_), shift(shift_)
+ {
+ }
+
+ Circle() = default;
+
+ /*@{*/
+ cv::Point center; //!< The center of the circle
+ int radius; //!< The radius of the circle
+ cv::Scalar color; //!< The color of the circle
+ int thick; //!< The thickness of the circle outline, if positive. Negative values, like #FILLED, mean that a filled circle is to be drawn
+ int lt; //!< The Type of the circle boundary. See #LineTypes
+ int shift; //!< The Number of fractional bits in the coordinates of the center and in the radius value
+ /*@{*/
+};
+
+/**
+ * @brief This structure represents a line to draw.
+ *
+ * Parameters match cv::line().
+ */
+struct Line
+{
+ /**
+ * @brief Line constructor
+ *
+ * @param pt1_ The first point of the line segment
+ * @param pt2_ The second point of the line segment
+ * @param color_ The line color
+ * @param thick_ The thickness of line
+ * @param lt_ The Type of the line. See #LineTypes
+ * @param shift_ The number of fractional bits in the point coordinates
+ */
+ Line(const cv::Point& pt1_,
+ const cv::Point& pt2_,
+ const cv::Scalar& color_,
+ int thick_ = 1,
+ int lt_ = 8,
+ int shift_ = 0) :
+ pt1(pt1_), pt2(pt2_), color(color_), thick(thick_), lt(lt_), shift(shift_)
+ {
+ }
+
+ Line() = default;
+
+ /*@{*/
+ cv::Point pt1; //!< The first point of the line segment
+ cv::Point pt2; //!< The second point of the line segment
+ cv::Scalar color; //!< The line color
+ int thick; //!< The thickness of line
+ int lt; //!< The Type of the line. See #LineTypes
+ int shift; //!< The number of fractional bits in the point coordinates
+ /*@{*/
+};
+
+/**
+ * @brief This structure represents a mosaicing operation.
+ *
+ * Mosaicing is a very basic method to obfuscate regions in the image.
+ */
+struct Mosaic
+{
+ /**
+ * @brief Mosaic constructor
+ *
+ * @param mos_ Coordinates of the mosaic
+ * @param cellSz_ Cell size (same for X, Y)
+ * @param decim_ Decimation (0 stands for no decimation)
+ */
+ Mosaic(const cv::Rect& mos_,
+ int cellSz_,
+ int decim_) :
+ mos(mos_), cellSz(cellSz_), decim(decim_)
+ {
+ }
+
+ Mosaic() = default;
+
+ /*@{*/
+ cv::Rect mos; //!< Coordinates of the mosaic
+ int cellSz; //!< Cell size (same for X, Y)
+ int decim; //!< Decimation (0 stands for no decimation)
+ /*@{*/
+};
+
+/**
+ * @brief This structure represents an image to draw.
+ *
+ * Image is blended on a frame using the specified mask.
+ */
+struct Image
+{
+ /**
+ * @brief Mosaic constructor
+ *
+ * @param org_ The bottom-left corner of the image
+ * @param img_ Image to draw
+ * @param alpha_ Alpha channel for image to draw (same size and number of channels)
+ */
+ Image(const cv::Point& org_,
+ const cv::Mat& img_,
+ const cv::Mat& alpha_) :
+ org(org_), img(img_), alpha(alpha_)
+ {
+ }
+
+ Image() = default;
+
+ /*@{*/
+ cv::Point org; //!< The bottom-left corner of the image
+ cv::Mat img; //!< Image to draw
+ cv::Mat alpha; //!< Alpha channel for image to draw (same size and number of channels)
+ /*@{*/
+};
+
+/**
+ * @brief This structure represents a polygon to draw.
+ */
+struct Poly
+{
+ /**
+ * @brief Mosaic constructor
+ *
+ * @param points_ Points to connect
+ * @param color_ The line color
+ * @param thick_ The thickness of line
+ * @param lt_ The Type of the line. See #LineTypes
+ * @param shift_ The number of fractional bits in the point coordinate
+ */
+ Poly(const std::vector<cv::Point>& points_,
+ const cv::Scalar& color_,
+ int thick_ = 1,
+ int lt_ = 8,
+ int shift_ = 0) :
+ points(points_), color(color_), thick(thick_), lt(lt_), shift(shift_)
+ {
+ }
+
+ Poly() = default;
+
+ /*@{*/
+ std::vector<cv::Point> points; //!< Points to connect
+ cv::Scalar color; //!< The line color
+ int thick; //!< The thickness of line
+ int lt; //!< The Type of the line. See #LineTypes
+ int shift; //!< The number of fractional bits in the point coordinate
+ /*@{*/
+};
+
+using Prim = util::variant
+ < Text
+ , FText
+ , Rect
+ , Circle
+ , Line
+ , Mosaic
+ , Image
+ , Poly
+ >;
+
+using Prims = std::vector<Prim>;
+//! @} gapi_draw_prims
+
+} // namespace draw
+} // namespace wip
+} // namespace gapi
+} // namespace cv
+
+#endif // OPENCV_GAPI_RENDER_TYPES_HPP
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#ifndef OPENCV_GAPI_RMAT_HPP
+#define OPENCV_GAPI_RMAT_HPP
+
+#include <opencv2/gapi/gmat.hpp>
+
+namespace cv {
+
+// "Remote Mat", a general class which provides an abstraction layer over the data
+// storage and placement (host, remote device etc) and allows to access this data.
+//
+// The device specific implementation is hidden in the RMat::Adapter class
+//
+// The basic flow is the following:
+// * Backend which is aware of the remote device:
+// - Implements own AdapterT class which is derived from RMat::Adapter
+// - Wraps device memory into RMat via make_rmat utility function:
+// cv::RMat rmat = cv::make_rmat<AdapterT>(args);
+//
+// * End user:
+// - Writes the code which works with RMats without any knowledge of the remote device:
+// void func(const cv::RMat& in_rmat, cv::RMat& out_rmat) {
+// // Fetch input data from the device, get mapped memory for output
+// cv::RMat::View in_view = in_rmat.access(Access::R);
+// cv::RMat::View out_view = out_rmat.access(Access::W);
+// performCalculations(in_view, out_view);
+// // data from out_view is transferred to the device when out_view is destroyed
+// }
+class RMat
+{
+public:
+ // A lightweight wrapper on image data:
+ // - Doesn't own the memory;
+ // - Doesn't implement copy semantics (it's assumed that a view is created each time
+ // wrapped data is being accessed);
+ // - Has an optional callback which is called when the view is destroyed.
+ class View
+ {
+ public:
+ using DestroyCallback = std::function<void()>;
+
+ View() = default;
+ View(const GMatDesc& desc, uchar* data, size_t step = 0u, DestroyCallback&& cb = nullptr)
+ : m_desc(desc), m_data(data), m_step(step == 0u ? elemSize()*cols() : step), m_cb(cb)
+ {}
+
+ View(const View&) = delete;
+ View(View&&) = default;
+ View& operator=(const View&) = delete;
+ View& operator=(View&&) = default;
+ ~View() { if (m_cb) m_cb(); }
+
+ cv::Size size() const { return m_desc.size; }
+ const std::vector<int>& dims() const { return m_desc.dims; }
+ int cols() const { return m_desc.size.width; }
+ int rows() const { return m_desc.size.height; }
+ int type() const { return CV_MAKE_TYPE(depth(), chan()); }
+ int depth() const { return m_desc.depth; }
+ int chan() const { return m_desc.chan; }
+ size_t elemSize() const { return CV_ELEM_SIZE(type()); }
+
+ template<typename T = uchar> T* ptr(int y = 0, int x = 0) {
+ return reinterpret_cast<T*>(m_data + m_step*y + x*CV_ELEM_SIZE(type()));
+ }
+ template<typename T = uchar> const T* ptr(int y = 0, int x = 0) const {
+ return reinterpret_cast<const T*>(m_data + m_step*y + x*CV_ELEM_SIZE(type()));
+ }
+ size_t step() const { return m_step; }
+
+ private:
+ GMatDesc m_desc;
+ uchar* m_data = nullptr;
+ size_t m_step = 0u;
+ DestroyCallback m_cb = nullptr;
+ };
+
+ enum class Access { R, W };
+ class Adapter
+ {
+ public:
+ virtual ~Adapter() = default;
+ virtual GMatDesc desc() const = 0;
+ // Implementation is responsible for setting the appropriate callback to
+ // the view when accessed for writing, to ensure that the data from the view
+ // is transferred to the device when the view is destroyed
+ virtual View access(Access) const = 0;
+ };
+ using AdapterP = std::shared_ptr<Adapter>;
+
+ RMat() = default;
+ RMat(AdapterP&& a) : m_adapter(std::move(a)) {}
+ GMatDesc desc() const { return m_adapter->desc(); }
+
+ // Note: When accessed for write there is no guarantee that returned view
+ // will contain actual snapshot of the mapped device memory
+ // (no guarantee that fetch from a device is performed). The only
+ // guaranty is that when the view is destroyed, its data will be
+ // transferred to the device
+ View access(Access a) const { return m_adapter->access(a); }
+
+ // Cast underlying RMat adapter to the particular adapter type,
+ // return nullptr if underlying type is different
+ template<typename T> T* get() const
+ {
+ static_assert(std::is_base_of<Adapter, T>::value, "T is not derived from Adapter!");
+ GAPI_Assert(m_adapter != nullptr);
+ return dynamic_cast<T*>(m_adapter.get());
+ }
+
+private:
+ AdapterP m_adapter = nullptr;
+};
+
+template<typename T, typename... Ts>
+RMat make_rmat(Ts&&... args) { return { std::make_shared<T>(std::forward<Ts>(args)...) }; }
+
+} //namespace cv
+
+#endif /* OPENCV_GAPI_RMAT_HPP */
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#ifndef OPENCV_GAPI_S11N_HPP
+#define OPENCV_GAPI_S11N_HPP
+
+#include <vector>
+#include <opencv2/gapi/gcomputation.hpp>
+
+namespace cv {
+namespace gapi {
+
+namespace detail {
+ GAPI_EXPORTS cv::GComputation getGraph(const std::vector<char> &p);
+} // namespace detail
+
+namespace detail {
+ GAPI_EXPORTS cv::GMetaArgs getMetaArgs(const std::vector<char> &p);
+} // namespace detail
+
+namespace detail {
+ GAPI_EXPORTS cv::GRunArgs getRunArgs(const std::vector<char> &p);
+} // namespace detail
+
+GAPI_EXPORTS std::vector<char> serialize(const cv::GComputation &c);
+//namespace{
+
+template<typename T> static inline
+T deserialize(const std::vector<char> &p);
+
+//} //ananymous namespace
+
+GAPI_EXPORTS std::vector<char> serialize(const cv::GMetaArgs&);
+GAPI_EXPORTS std::vector<char> serialize(const cv::GRunArgs&);
+
+template<> inline
+cv::GComputation deserialize(const std::vector<char> &p) {
+ return detail::getGraph(p);
+}
+
+template<> inline
+cv::GMetaArgs deserialize(const std::vector<char> &p) {
+ return detail::getMetaArgs(p);
+}
+
+template<> inline
+cv::GRunArgs deserialize(const std::vector<char> &p) {
+ return detail::getRunArgs(p);
+}
+
+
+} // namespace gapi
+} // namespace cv
+
+#endif // OPENCV_GAPI_S11N_HPP
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#ifndef OPENCV_GAPI_UTIL_TYPE_TRAITS_HPP
+#define OPENCV_GAPI_UTIL_TYPE_TRAITS_HPP
+
+#include <type_traits>
+
+namespace cv
+{
+namespace util
+{
+ //these are C++14 parts of type_traits :
+ template< bool B, class T = void >
+ using enable_if_t = typename std::enable_if<B,T>::type;
+
+ template<typename T>
+ using decay_t = typename std::decay<T>::type;
+
+ //this is not part of C++14 but still, of pretty common usage
+ template<class T, class U, class V = void>
+ using are_different_t = enable_if_t< !std::is_same<decay_t<T>, decay_t<U>>::value, V>;
+
+} // namespace cv
+} // namespace util
+
+#endif // OPENCV_GAPI_UTIL_TYPE_TRAITS_HPP
#include <opencv2/gapi/util/throw.hpp>
#include <opencv2/gapi/util/util.hpp> // max_of_t
+#include <opencv2/gapi/util/type_traits.hpp>
// A poor man's `variant` implementation, incompletely modeled against C++17 spec.
namespace cv
static_assert(std::is_same<Target, First>::value, "Type not found");
static const constexpr std::size_t value = I;
};
-
-
- template<class T, class U, class V> using are_different =
- std::enable_if<!std::is_same<typename std::decay<T>::type,
- typename std::decay<U>::type>::value,
- V>;
}
template<typename Target, typename... Types>
}
};
- template<typename T> struct vctr_h {
- static void help(Memory memory, const void* pval) {
- new (memory) T(*reinterpret_cast<const T*>(pval));
- }
- };
-
template<typename T> struct mctr_h {
static void help(Memory memory, void *pval) {
new (memory) T(std::move(*reinterpret_cast<T*>(pval)));
}
};
+ //FIXME: unify with cctr_h and mctr_h
+ template<typename T> struct cnvrt_ctor_h {
+ static void help(Memory memory, void* from) {
+ using util::decay_t;
+ new (memory) decay_t<T>(std::forward<T>(*reinterpret_cast<decay_t<T>*>(from)));
+ }
+ };
+
template<typename T> struct copy_h {
static void help(Memory to, const Memory from) {
*reinterpret_cast<T*>(to) = *reinterpret_cast<const T*>(from);
};
template<typename T> struct move_h {
- static void help(Memory to, const Memory from) {
- *reinterpret_cast<T*>(to) = std::move(*reinterpret_cast<const T*>(from));
+ static void help(Memory to, Memory from) {
+ *reinterpret_cast<T*>(to) = std::move(*reinterpret_cast<T*>(from));
+ }
+ };
+
+ //FIXME: unify with copy_h and move_h
+ template<typename T> struct cnvrt_assign_h {
+ static void help(Memory to, void* from) {
+ using util::decay_t;
+ *reinterpret_cast<decay_t<T>*>(to) = std::forward<T>(*reinterpret_cast<decay_t<T>*>(from));
}
};
};
typedef void (*CCtr) (Memory, const Memory); // Copy c-tor (variant)
- typedef void (*VCtr) (Memory, const void*); // Copy c-tor (value)
typedef void (*MCtr) (Memory, void*); // Generic move c-tor
typedef void (*Copy) (Memory, const Memory); // Copy assignment
- typedef void (*Move) (Memory, const Memory); // Move assignment
+ typedef void (*Move) (Memory, Memory); // Move assignment
+
typedef void (*Swap) (Memory, Memory); // Swap
typedef void (*Dtor) (Memory); // Destructor
+ using cnvrt_assgn_t = void (*) (Memory, void*); // Converting assignment (via std::forward)
+ using cnvrt_ctor_t = void (*) (Memory, void*); // Converting constructor (via std::forward)
+
typedef bool (*Equal)(const Memory, const Memory); // Equality test (external)
static constexpr std::array<CCtr, sizeof...(Ts)> cctrs(){ return {{(&cctr_h<Ts>::help)...}};}
- static constexpr std::array<VCtr, sizeof...(Ts)> vctrs(){ return {{(&vctr_h<Ts>::help)...}};}
static constexpr std::array<MCtr, sizeof...(Ts)> mctrs(){ return {{(&mctr_h<Ts>::help)...}};}
static constexpr std::array<Copy, sizeof...(Ts)> cpyrs(){ return {{(©_h<Ts>::help)...}};}
static constexpr std::array<Move, sizeof...(Ts)> mvers(){ return {{(&move_h<Ts>::help)...}};}
static constexpr std::array<Swap, sizeof...(Ts)> swprs(){ return {{(&swap_h<Ts>::help)...}};}
static constexpr std::array<Dtor, sizeof...(Ts)> dtors(){ return {{(&dtor_h<Ts>::help)...}};}
+ template<bool cond, typename T>
+ struct conditional_ref : std::conditional<cond, typename std::remove_reference<T>::type&, typename std::remove_reference<T>::type > {};
+
+ template<bool cond, typename T>
+ using conditional_ref_t = typename conditional_ref<cond, T>::type;
+
+
+ template<bool is_lvalue_arg>
+ static constexpr std::array<cnvrt_assgn_t, sizeof...(Ts)> cnvrt_assgnrs(){
+ return {{(&cnvrt_assign_h<conditional_ref_t<is_lvalue_arg,Ts>>::help)...}};
+ }
+
+ template<bool is_lvalue_arg>
+ static constexpr std::array<cnvrt_ctor_t, sizeof...(Ts)> cnvrt_ctors(){
+ return {{(&cnvrt_ctor_h<conditional_ref_t<is_lvalue_arg,Ts>>::help)...}};
+ }
+
std::size_t m_index = 0;
protected:
template<typename T, typename... Us> friend T& get(variant<Us...> &v);
template<typename T, typename... Us> friend const T& get(const variant<Us...> &v);
+ template<typename T, typename... Us> friend T* get_if(variant<Us...> *v) noexcept;
+ template<typename T, typename... Us> friend const T* get_if(const variant<Us...> *v) noexcept;
+
template<typename... Us> friend bool operator==(const variant<Us...> &lhs,
const variant<Us...> &rhs);
Memory memory;
variant() noexcept;
variant(const variant& other);
variant(variant&& other) noexcept;
- template<typename T> explicit variant(const T& t);
- // are_different is a SFINAE trick to avoid variant(T &&t) with T=variant
+ // are_different_t is a SFINAE trick to avoid variant(T &&t) with T=variant
// for some reason, this version is called instead of variant(variant&& o) when
- // variant is used in STL containers (examples: vector assignment)
- template<typename T> explicit variant(T&& t, typename detail::are_different<variant, T, int>::type = 0);
+ // variant is used in STL containers (examples: vector assignment).
+ template<
+ typename T,
+ typename = util::are_different_t<variant, T>
+ >
+ explicit variant(T&& t);
// template<class T, class... Args> explicit variant(Args&&... args);
// FIXME: other constructors
variant& operator=(variant &&rhs) noexcept;
// SFINAE trick to avoid operator=(T&&) with T=variant<>, see comment above
- template<class T>
- typename detail::are_different<variant, T, variant&>
- ::type operator=(T&& t) noexcept;
+ template<
+ typename T,
+ typename = util::are_different_t<variant, T>
+ >
+ variant& operator=(T&& t) noexcept;
// Observers
std::size_t index() const noexcept;
};
// FIMXE: visit
+ template<typename T, typename... Types>
+ T* get_if(util::variant<Types...>* v) noexcept;
+
+ template<typename T, typename... Types>
+ const T* get_if(const util::variant<Types...>* v) noexcept;
template<typename T, typename... Types>
T& get(util::variant<Types...> &v);
}
template<typename... Ts>
- template<class T>
- variant<Ts...>::variant(const T& t)
- : m_index(util::type_list_index<T, Ts...>::value)
+ template<class T, typename>
+ variant<Ts...>::variant(T&& t)
+ : m_index(util::type_list_index<util::decay_t<T>, Ts...>::value)
{
- (vctrs()[m_index])(memory, &t);
- }
-
- template<typename... Ts>
- template<class T>
- variant<Ts...>::variant(T&& t, typename detail::are_different<variant, T, int>::type)
- : m_index(util::type_list_index<typename std::remove_reference<T>::type, Ts...>::value)
- {
- (mctrs()[m_index])(memory, &t);
+ const constexpr bool is_lvalue_arg = std::is_lvalue_reference<T>::value;
+ (cnvrt_ctors<is_lvalue_arg>()[m_index])(memory, const_cast<util::decay_t<T> *>(&t));
}
template<typename... Ts>
}
template<typename... Ts>
- template<class T> typename detail::are_different<variant<Ts...>, T, variant<Ts...>&>
- ::type variant<Ts...>::operator=(T&& t) noexcept
+ template<typename T, typename>
+ variant<Ts...>& variant<Ts...>::operator=(T&& t) noexcept
{
- using decayed_t = typename std::decay<T>::type;
+ using decayed_t = util::decay_t<T>;
// FIXME: No version with implicit type conversion available!
- static const constexpr std::size_t t_index =
+ const constexpr std::size_t t_index =
util::type_list_index<decayed_t, Ts...>::value;
- if (t_index == m_index)
+ const constexpr bool is_lvalue_arg = std::is_lvalue_reference<T>::value;
+
+ if (t_index != m_index)
{
- util::get<decayed_t>(*this) = std::move(t);
- return *this;
+ (dtors()[m_index])(memory);
+ (cnvrt_ctors<is_lvalue_arg>()[t_index])(memory, &t);
+ m_index = t_index;
}
- else return (*this = variant(std::move(t)));
+ else
+ {
+ (cnvrt_assgnrs<is_lvalue_arg>()[m_index])(memory, &t);
+ }
+ return *this;
+
}
template<typename... Ts>
}
template<typename T, typename... Types>
- T& get(util::variant<Types...> &v)
+ T* get_if(util::variant<Types...>* v) noexcept
{
const constexpr std::size_t t_index =
util::type_list_index<T, Types...>::value;
- if (v.index() == t_index)
- return *(T*)(&v.memory); // workaround for ICC 2019
+ if (v && v->index() == t_index)
+ return (T*)(&v->memory); // workaround for ICC 2019
// original code: return reinterpret_cast<T&>(v.memory);
- else
- throw_error(bad_variant_access());
+ return nullptr;
}
template<typename T, typename... Types>
- const T& get(const util::variant<Types...> &v)
+ const T* get_if(const util::variant<Types...>* v) noexcept
{
const constexpr std::size_t t_index =
util::type_list_index<T, Types...>::value;
- if (v.index() == t_index)
- return *(const T*)(&v.memory); // workaround for ICC 2019
+ if (v && v->index() == t_index)
+ return (const T*)(&v->memory); // workaround for ICC 2019
// original code: return reinterpret_cast<const T&>(v.memory);
+ return nullptr;
+ }
+
+ template<typename T, typename... Types>
+ T& get(util::variant<Types...> &v)
+ {
+ if (auto* p = get_if<T>(&v))
+ return *p;
+ else
+ throw_error(bad_variant_access());
+ }
+
+ template<typename T, typename... Types>
+ const T& get(const util::variant<Types...> &v)
+ {
+ if (auto* p = get_if<T>(&v))
+ return *p;
else
throw_error(bad_variant_access());
}
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#ifndef OPENCV_GAPI_VIDEO_HPP
+#define OPENCV_GAPI_VIDEO_HPP
+
+#include <utility> // std::tuple
+
+#include <opencv2/gapi/gkernel.hpp>
+
+
+/** \defgroup gapi_video G-API Video processing functionality
+ */
+
+namespace cv { namespace gapi {
+namespace video
+{
+using GBuildPyrOutput = std::tuple<GArray<GMat>, GScalar>;
+
+using GOptFlowLKOutput = std::tuple<cv::GArray<cv::Point2f>,
+ cv::GArray<uchar>,
+ cv::GArray<float>>;
+
+G_TYPED_KERNEL(GBuildOptFlowPyramid, <GBuildPyrOutput(GMat,Size,GScalar,bool,int,int,bool)>,
+ "org.opencv.video.buildOpticalFlowPyramid")
+{
+ static std::tuple<GArrayDesc,GScalarDesc>
+ outMeta(GMatDesc,const Size&,GScalarDesc,bool,int,int,bool)
+ {
+ return std::make_tuple(empty_array_desc(), empty_scalar_desc());
+ }
+};
+
+G_TYPED_KERNEL(GCalcOptFlowLK,
+ <GOptFlowLKOutput(GMat,GMat,cv::GArray<cv::Point2f>,cv::GArray<cv::Point2f>,Size,
+ GScalar,TermCriteria,int,double)>,
+ "org.opencv.video.calcOpticalFlowPyrLK")
+{
+ static std::tuple<GArrayDesc,GArrayDesc,GArrayDesc> outMeta(GMatDesc,GMatDesc,GArrayDesc,
+ GArrayDesc,const Size&,GScalarDesc,
+ const TermCriteria&,int,double)
+ {
+ return std::make_tuple(empty_array_desc(), empty_array_desc(), empty_array_desc());
+ }
+
+};
+
+G_TYPED_KERNEL(GCalcOptFlowLKForPyr,
+ <GOptFlowLKOutput(cv::GArray<cv::GMat>,cv::GArray<cv::GMat>,
+ cv::GArray<cv::Point2f>,cv::GArray<cv::Point2f>,Size,GScalar,
+ TermCriteria,int,double)>,
+ "org.opencv.video.calcOpticalFlowPyrLKForPyr")
+{
+ static std::tuple<GArrayDesc,GArrayDesc,GArrayDesc> outMeta(GArrayDesc,GArrayDesc,
+ GArrayDesc,GArrayDesc,
+ const Size&,GScalarDesc,
+ const TermCriteria&,int,double)
+ {
+ return std::make_tuple(empty_array_desc(), empty_array_desc(), empty_array_desc());
+ }
+};
+} //namespace video
+
+//! @addtogroup gapi_video
+//! @{
+/** @brief Constructs the image pyramid which can be passed to calcOpticalFlowPyrLK.
+
+@note Function textual ID is "org.opencv.video.buildOpticalFlowPyramid"
+
+@param img 8-bit input image.
+@param winSize window size of optical flow algorithm. Must be not less than winSize
+ argument of calcOpticalFlowPyrLK. It is needed to calculate required
+ padding for pyramid levels.
+@param maxLevel 0-based maximal pyramid level number.
+@param withDerivatives set to precompute gradients for the every pyramid level. If pyramid is
+ constructed without the gradients then calcOpticalFlowPyrLK will calculate
+ them internally.
+@param pyrBorder the border mode for pyramid layers.
+@param derivBorder the border mode for gradients.
+@param tryReuseInputImage put ROI of input image into the pyramid if possible. You can pass false
+ to force data copying.
+
+@return output pyramid.
+@return number of levels in constructed pyramid. Can be less than maxLevel.
+ */
+GAPI_EXPORTS std::tuple<GArray<GMat>, GScalar>
+buildOpticalFlowPyramid(const GMat &img,
+ const Size &winSize,
+ const GScalar &maxLevel,
+ bool withDerivatives = true,
+ int pyrBorder = BORDER_REFLECT_101,
+ int derivBorder = BORDER_CONSTANT,
+ bool tryReuseInputImage = true);
+
+/** @brief Calculates an optical flow for a sparse feature set using the iterative Lucas-Kanade
+method with pyramids.
+
+See @cite Bouguet00 .
+
+@note Function textual ID is "org.opencv.video.calcOpticalFlowPyrLK"
+
+@param prevImg first 8-bit input image (GMat) or pyramid (GArray<GMat>) constructed by
+buildOpticalFlowPyramid.
+@param nextImg second input image (GMat) or pyramid (GArray<GMat>) of the same size and the same
+type as prevImg.
+@param prevPts GArray of 2D points for which the flow needs to be found; point coordinates must be
+single-precision floating-point numbers.
+@param predPts GArray of 2D points initial for the flow search; make sense only when
+OPTFLOW_USE_INITIAL_FLOW flag is passed; in that case the vector must have the same size as in
+the input.
+@param winSize size of the search window at each pyramid level.
+@param maxLevel 0-based maximal pyramid level number; if set to 0, pyramids are not used (single
+level), if set to 1, two levels are used, and so on; if pyramids are passed to input then
+algorithm will use as many levels as pyramids have but no more than maxLevel.
+@param criteria parameter, specifying the termination criteria of the iterative search algorithm
+(after the specified maximum number of iterations criteria.maxCount or when the search window
+moves by less than criteria.epsilon).
+@param flags operation flags:
+ - **OPTFLOW_USE_INITIAL_FLOW** uses initial estimations, stored in nextPts; if the flag is
+ not set, then prevPts is copied to nextPts and is considered the initial estimate.
+ - **OPTFLOW_LK_GET_MIN_EIGENVALS** use minimum eigen values as an error measure (see
+ minEigThreshold description); if the flag is not set, then L1 distance between patches
+ around the original and a moved point, divided by number of pixels in a window, is used as a
+ error measure.
+@param minEigThresh the algorithm calculates the minimum eigen value of a 2x2 normal matrix of
+optical flow equations (this matrix is called a spatial gradient matrix in @cite Bouguet00), divided
+by number of pixels in a window; if this value is less than minEigThreshold, then a corresponding
+feature is filtered out and its flow is not processed, so it allows to remove bad points and get a
+performance boost.
+
+@return GArray of 2D points (with single-precision floating-point coordinates)
+containing the calculated new positions of input features in the second image.
+@return status GArray (of unsigned chars); each element of the vector is set to 1 if
+the flow for the corresponding features has been found, otherwise, it is set to 0.
+@return GArray of errors (doubles); each element of the vector is set to an error for the
+corresponding feature, type of the error measure can be set in flags parameter; if the flow wasn't
+found then the error is not defined (use the status parameter to find such cases).
+ */
+GAPI_EXPORTS std::tuple<GArray<Point2f>, GArray<uchar>, GArray<float>>
+calcOpticalFlowPyrLK(const GMat &prevImg,
+ const GMat &nextImg,
+ const GArray<Point2f> &prevPts,
+ const GArray<Point2f> &predPts,
+ const Size &winSize = Size(21, 21),
+ const GScalar &maxLevel = 3,
+ const TermCriteria &criteria = TermCriteria(TermCriteria::COUNT |
+ TermCriteria::EPS,
+ 30, 0.01),
+ int flags = 0,
+ double minEigThresh = 1e-4);
+
+/**
+@overload
+@note Function textual ID is "org.opencv.video.calcOpticalFlowPyrLKForPyr"
+*/
+GAPI_EXPORTS std::tuple<GArray<Point2f>, GArray<uchar>, GArray<float>>
+calcOpticalFlowPyrLK(const GArray<GMat> &prevPyr,
+ const GArray<GMat> &nextPyr,
+ const GArray<Point2f> &prevPts,
+ const GArray<Point2f> &predPts,
+ const Size &winSize = Size(21, 21),
+ const GScalar &maxLevel = 3,
+ const TermCriteria &criteria = TermCriteria(TermCriteria::COUNT |
+ TermCriteria::EPS,
+ 30, 0.01),
+ int flags = 0,
+ double minEigThresh = 1e-4);
+
+//! @} gapi_video
+} //namespace gapi
+} //namespace cv
+
+#endif // OPENCV_GAPI_VIDEO_HPP
--- /dev/null
+using gapi_GKernelPackage = cv::gapi::GKernelPackage;
+
+template<>
+bool pyopencv_to(PyObject* obj, std::vector<GCompileArg>& value, const ArgInfo& info)
+{
+ return pyopencv_to_generic_vec(obj, value, info);
+}
+
+template<>
+PyObject* pyopencv_from(const std::vector<GCompileArg>& value)
+{
+ return pyopencv_from_generic_vec(value);
+}
+
+template <typename T>
+static PyObject* extract_proto_args(PyObject* py_args, PyObject* kw)
+{
+ using namespace cv;
+
+ GProtoArgs args;
+ Py_ssize_t size = PyTuple_Size(py_args);
+ for (int i = 0; i < size; ++i) {
+ PyObject* item = PyTuple_GetItem(py_args, i);
+ if (PyObject_TypeCheck(item, reinterpret_cast<PyTypeObject*>(pyopencv_GScalar_TypePtr))) {
+ args.emplace_back(reinterpret_cast<pyopencv_GScalar_t*>(item)->v);
+ } else if (PyObject_TypeCheck(item, reinterpret_cast<PyTypeObject*>(pyopencv_GMat_TypePtr))) {
+ args.emplace_back(reinterpret_cast<pyopencv_GMat_t*>(item)->v);
+ } else {
+ PyErr_SetString(PyExc_TypeError, "cv.GIn() supports only cv.GMat and cv.GScalar");
+ return NULL;
+ }
+ }
+
+ return pyopencv_from<T>(T{std::move(args)});
+}
+
+static PyObject* pyopencv_cv_GIn(PyObject* , PyObject* py_args, PyObject* kw)
+{
+ return extract_proto_args<GProtoInputArgs>(py_args, kw);
+}
+
+static PyObject* pyopencv_cv_GOut(PyObject* , PyObject* py_args, PyObject* kw)
+{
+ return extract_proto_args<GProtoOutputArgs>(py_args, kw);
+}
--- /dev/null
+#error This is a shadow header file, which is not intended for processing by any compiler. \
+ Only bindings parser should handle this file.
+
+namespace cv
+{
+ GAPI_EXPORTS_W GCompileArgs compile_args(gapi::GKernelPackage pkg);
+ class GAPI_EXPORTS_W_SIMPLE GProtoArg { };
+ class GAPI_EXPORTS_W_SIMPLE GProtoInputArgs { };
+ class GAPI_EXPORTS_W_SIMPLE GProtoOutputArgs { };
+
+ using GProtoInputArgs = GIOProtoArgs<In_Tag>;
+ using GProtoOutputArgs = GIOProtoArgs<Out_Tag>;
+} // namespace cv
--- /dev/null
+#!/usr/bin/env python
+
+import numpy as np
+import cv2 as cv
+
+from tests_common import NewOpenCVTests
+
+
+# Plaidml is an optional backend
+pkgs = [
+ cv.gapi.core.ocl.kernels(),
+ cv.gapi.core.cpu.kernels(),
+ cv.gapi.core.fluid.kernels()
+ # cv.gapi.core.plaidml.kernels()
+ ]
+
+
+class gapi_core_test(NewOpenCVTests):
+
+ def test_add(self):
+ # TODO: Extend to use any type and size here
+ sz = (1280, 720)
+ in1 = np.random.randint(0, 100, sz).astype(np.uint8)
+ in2 = np.random.randint(0, 100, sz).astype(np.uint8)
+
+ # OpenCV
+ expected = in1 + in2
+
+ # G-API
+ g_in1 = cv.GMat()
+ g_in2 = cv.GMat()
+ g_out = cv.gapi.add(g_in1, g_in2)
+ comp = cv.GComputation(cv.GIn(g_in1, g_in2), cv.GOut(g_out))
+
+ for pkg in pkgs:
+ actual = comp.apply(in1, in2, args=cv.compile_args(pkg))
+ # Comparison
+ self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
+
+
+ def test_mean(self):
+ sz = (1280, 720, 3)
+ in_mat = np.random.randint(0, 100, sz).astype(np.uint8)
+
+ # OpenCV
+ expected = cv.mean(in_mat)
+
+ # G-API
+ g_in = cv.GMat()
+ g_out = cv.gapi.mean(g_in)
+ comp = cv.GComputation(g_in, g_out)
+
+ for pkg in pkgs:
+ actual = comp.apply(in_mat, args=cv.compile_args(pkg))
+ # Comparison
+ self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
+
+
+if __name__ == '__main__':
+ NewOpenCVTests.bootstrap()
--- /dev/null
+#!/usr/bin/env python
+
+import numpy as np
+import cv2 as cv
+
+from tests_common import NewOpenCVTests
+
+
+# Plaidml is an optional backend
+pkgs = [
+ cv.gapi.core.ocl.kernels(),
+ cv.gapi.core.cpu.kernels(),
+ cv.gapi.core.fluid.kernels()
+ # cv.gapi.core.plaidml.kernels()
+ ]
+
+
+class gapi_sample_pipelines(NewOpenCVTests):
+
+ # NB: This test check multiple outputs for operation
+ def test_mean_over_r(self):
+ sz = (100, 100, 3)
+ in_mat = np.random.randint(0, 100, sz).astype(np.uint8)
+
+ # # OpenCV
+ _, _, r_ch = cv.split(in_mat)
+ expected = cv.mean(r_ch)
+
+ # G-API
+ g_in = cv.GMat()
+ b, g, r = cv.gapi.split3(g_in)
+ g_out = cv.gapi.mean(r)
+ comp = cv.GComputation(g_in, g_out)
+
+ for pkg in pkgs:
+ actual = comp.apply(in_mat, args=cv.compile_args(pkg))
+ # Comparison
+ self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
+
+
+if __name__ == '__main__':
+ NewOpenCVTests.bootstrap()
#include "../../test/common/gapi_tests_common.hpp"
+#include "../../test/common/gapi_parsers_tests_common.hpp"
#include <opencv2/gapi/core.hpp>
namespace opencv_test
class Polar2CartPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class Cart2PolarPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class CmpPerfTest : public TestPerfParams<tuple<CmpTypes, cv::Size, MatType, cv::GCompileArgs>> {};
- class CmpWithScalarPerfTest : public TestPerfParams<tuple<CmpTypes, cv::Size, MatType, cv::GCompileArgs>> {};
- class BitwisePerfTest : public TestPerfParams<tuple<bitwiseOp, cv::Size, MatType, cv::GCompileArgs>> {};
+ class CmpWithScalarPerfTest : public TestPerfParams<tuple<compare_f, CmpTypes, cv::Size, MatType, cv::GCompileArgs>> {};
+ class BitwisePerfTest : public TestPerfParams<tuple<bitwiseOp, bool, cv::Size, MatType, cv::GCompileArgs>> {};
class BitwiseNotPerfTest : public TestPerfParams<tuple<cv::Size, MatType, cv::GCompileArgs>> {};
class SelectPerfTest : public TestPerfParams<tuple<cv::Size, MatType, cv::GCompileArgs>> {};
class MinPerfTest : public TestPerfParams<tuple<cv::Size, MatType, cv::GCompileArgs>> {};
class ConcatVertPerfTest : public TestPerfParams<tuple<cv::Size, MatType, cv::GCompileArgs>> {};
class ConcatVertVecPerfTest : public TestPerfParams<tuple<cv::Size, MatType, cv::GCompileArgs>> {};
class LUTPerfTest : public TestPerfParams<tuple<MatType, MatType, cv::Size, cv::GCompileArgs>> {};
- class ConvertToPerfTest : public TestPerfParams<tuple<MatType, int, cv::Size, cv::GCompileArgs>> {};
+ class ConvertToPerfTest : public TestPerfParams<tuple<compare_f, MatType, int, cv::Size, double, double, cv::GCompileArgs>> {};
class ResizePerfTest : public TestPerfParams<tuple<compare_f, MatType, int, cv::Size, cv::Size, cv::GCompileArgs>> {};
class ResizeFxFyPerfTest : public TestPerfParams<tuple<compare_f, MatType, int, cv::Size, double, double, cv::GCompileArgs>> {};
+ class ParseSSDBLPerfTest : public TestPerfParams<tuple<cv::Size, float, int, cv::GCompileArgs>>, public ParserSSDTest {};
+ class ParseSSDPerfTest : public TestPerfParams<tuple<cv::Size, float, bool, bool, cv::GCompileArgs>>, public ParserSSDTest {};
+ class ParseYoloPerfTest : public TestPerfParams<tuple<cv::Size, float, float, int, cv::GCompileArgs>>, public ParserYoloTest {};
+ class SizePerfTest : public TestPerfParams<tuple<MatType, cv::Size, cv::GCompileArgs>> {};
+ class SizeRPerfTest : public TestPerfParams<tuple<cv::Size, cv::GCompileArgs>> {};
}
#endif // OPENCV_GAPI_CORE_PERF_TESTS_HPP
// FIXIT Unstable input data for divide
initMatsRandU(type, sz, dtype, false);
- // FIXIT Unstable input data for divide, don't process zeros
- sc += Scalar::all(1);
- in_mat1 += 1;
-
// OpenCV code ///////////////////////////////////////////////////////////
cv::divide(sc, in_mat1, out_mat_ocv, 1.0, dtype);
}
// Comparison ////////////////////////////////////////////////////////////
- EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
+ // FIXIT unrealiable check: EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz);
SANITY_CHECK_NOTHING();
PERF_TEST_P_(CmpWithScalarPerfTest, TestPerformance)
{
- CmpTypes opType = get<0>(GetParam());
- cv::Size sz = get<1>(GetParam());
- MatType type = get<2>(GetParam());
- cv::GCompileArgs compile_args = get<3>(GetParam());
+ MatType type = -1;
+ CmpTypes opType = CMP_EQ;
+ cv::Size sz;
+ compare_f cmpF;
+ cv::GCompileArgs compile_args;
+ std::tie(cmpF, opType, sz, type, compile_args) = GetParam();
initMatsRandU(type, sz, CV_8U, false);
}
// Comparison ////////////////////////////////////////////////////////////
- EXPECT_EQ(0, cvtest::norm(out_mat_gapi, out_mat_ocv, NORM_INF));
EXPECT_EQ(out_mat_gapi.size(), sz);
+ EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
SANITY_CHECK_NOTHING();
}
PERF_TEST_P_(BitwisePerfTest, TestPerformance)
{
- bitwiseOp opType = get<0>(GetParam());
- cv::Size sz = get<1>(GetParam());
- MatType type = get<2>(GetParam());
- cv::GCompileArgs compile_args = get<3>(GetParam());
+ MatType type = -1;
+ bitwiseOp opType = AND;
+ bool testWithScalar = false;
+ cv::Size sz;
+ cv::GCompileArgs compile_args;
+
+ std::tie(opType, testWithScalar, sz, type, compile_args) = GetParam();
initMatsRandU(type, sz, type, false);
// G-API code & corresponding OpenCV code ////////////////////////////////
cv::GMat in1, in2, out;
- switch (opType)
- {
- case AND:
- {
- out = cv::gapi::bitwise_and(in1, in2);
- cv::bitwise_and(in_mat1, in_mat2, out_mat_ocv);
- break;
- }
- case OR:
+ if( testWithScalar )
{
- out = cv::gapi::bitwise_or(in1, in2);
- cv::bitwise_or(in_mat1, in_mat2, out_mat_ocv);
- break;
+ cv::GScalar sc1;
+ switch (opType)
+ {
+ case AND:
+ out = cv::gapi::bitwise_and(in1, sc1);
+ cv::bitwise_and(in_mat1, sc, out_mat_ocv);
+ break;
+ case OR:
+ out = cv::gapi::bitwise_or(in1, sc1);
+ cv::bitwise_or(in_mat1, sc, out_mat_ocv);
+ break;
+ case XOR:
+ out = cv::gapi::bitwise_xor(in1, sc1);
+ cv::bitwise_xor(in_mat1, sc, out_mat_ocv);
+ break;
+ default:
+ FAIL() << "no such bitwise operation type!";
+ }
+ cv::GComputation c(GIn(in1, sc1), GOut(out));
+
+ // Warm-up graph engine:
+ c.apply(gin(in_mat1, sc), gout(out_mat_gapi), std::move(compile_args));
+
+ TEST_CYCLE()
+ {
+ c.apply(gin(in_mat1, sc), gout(out_mat_gapi));
+ }
}
- case XOR:
+ else
{
- out = cv::gapi::bitwise_xor(in1, in2);
- cv::bitwise_xor(in_mat1, in_mat2, out_mat_ocv);
- break;
- }
- default:
- {
- FAIL() << "no such bitwise operation type!";
- }
- }
- cv::GComputation c(GIn(in1, in2), GOut(out));
-
- // Warm-up graph engine:
- auto cc = c.compile(descr_of(gin(in_mat1, in_mat2)),
- std::move(compile_args));
- cc(gin(in_mat1, in_mat2), gout(out_mat_gapi));
-
- TEST_CYCLE()
- {
- cc(gin(in_mat1, in_mat2), gout(out_mat_gapi));
+ switch (opType)
+ {
+ case AND:
+ out = cv::gapi::bitwise_and(in1, in2);
+ cv::bitwise_and(in_mat1, in_mat2, out_mat_ocv);
+ break;
+ case OR:
+ out = cv::gapi::bitwise_or(in1, in2);
+ cv::bitwise_or(in_mat1, in_mat2, out_mat_ocv);
+ break;
+ case XOR:
+ out = cv::gapi::bitwise_xor(in1, in2);
+ cv::bitwise_xor(in_mat1, in_mat2, out_mat_ocv);
+ break;
+ default:
+ FAIL() << "no such bitwise operation type!";
+ }
+ cv::GComputation c(GIn(in1, in2), GOut(out));
+
+ // Warm-up graph engine:
+ c.apply(gin(in_mat1, in_mat2), gout(out_mat_gapi), std::move(compile_args));
+
+ TEST_CYCLE()
+ {
+ c.apply(gin(in_mat1, in_mat2), gout(out_mat_gapi));
+ }
}
// Comparison ////////////////////////////////////////////////////////////
PERF_TEST_P_(ConvertToPerfTest, TestPerformance)
{
- MatType type_mat = get<0>(GetParam());
- int depth_to = get<1>(GetParam());
- cv::Size sz_in = get<2>(GetParam());
- cv::GCompileArgs compile_args = get<3>(GetParam());
+ int depth_to = -1;
+ MatType type_mat = -1;
+ double alpha = 0., beta = 0.;
+ cv::Size sz_in;
+ compare_f cmpF;
+ cv::GCompileArgs compile_args;
+ std::tie(cmpF, type_mat, depth_to, sz_in, alpha, beta, compile_args) = GetParam();
MatType type_out = CV_MAKETYPE(depth_to, CV_MAT_CN(type_mat));
initMatrixRandU(type_mat, sz_in, type_out);
// OpenCV code ///////////////////////////////////////////////////////////
- in_mat1.convertTo(out_mat_ocv, depth_to);
+ in_mat1.convertTo(out_mat_ocv, depth_to, alpha, beta);
// G-API code //////////////////////////////////////////////////////////////
cv::GMat in;
- auto out = cv::gapi::convertTo(in, depth_to);
+ auto out = cv::gapi::convertTo(in, depth_to, alpha, beta);
cv::GComputation c(in, out);
// Warm-up graph engine:
}
// Comparison ////////////////////////////////////////////////////////////
- // FIXIT unrealiable check: EXPECT_EQ(0, cv::countNonZero(out_mat_ocv != out_mat_gapi));
+ EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
EXPECT_EQ(out_mat_gapi.size(), sz_in);
SANITY_CHECK_NOTHING();
//------------------------------------------------------------------------------
+PERF_TEST_P_(ParseSSDBLPerfTest, TestPerformance)
+{
+ cv::Size sz;
+ float confidence_threshold = 0.0f;
+ int filter_label = 0;
+ cv::GCompileArgs compile_args;
+ std::tie(sz, confidence_threshold, filter_label, compile_args) = GetParam();
+ cv::Mat in_mat = generateSSDoutput(sz);
+ std::vector<cv::Rect> boxes_gapi, boxes_ref;
+ std::vector<int> labels_gapi, labels_ref;
+
+ // Reference code //////////////////////////////////////////////////////////
+ parseSSDBLref(in_mat, sz, confidence_threshold, filter_label, boxes_ref, labels_ref);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::GMat in;
+ cv::GOpaque<cv::Size> op_sz;
+ auto out = cv::gapi::parseSSD(in, op_sz, confidence_threshold, filter_label);
+ cv::GComputation c(cv::GIn(in, op_sz), cv::GOut(std::get<0>(out), std::get<1>(out)));
+
+ // Warm-up graph engine:
+ auto cc = c.compile(descr_of(in_mat), descr_of(sz), std::move(compile_args));
+ cc(cv::gin(in_mat, sz), cv::gout(boxes_gapi, labels_gapi));
+
+ TEST_CYCLE()
+ {
+ cc(cv::gin(in_mat, sz), cv::gout(boxes_gapi, labels_gapi));
+ }
+
+ // Comparison ////////////////////////////////////////////////////////////
+ {
+ EXPECT_TRUE(boxes_gapi == boxes_ref);
+ EXPECT_TRUE(labels_gapi == labels_ref);
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+//------------------------------------------------------------------------------
+
+PERF_TEST_P_(ParseSSDPerfTest, TestPerformance)
+{
+ cv::Size sz;
+ float confidence_threshold = 0;
+ bool alignment_to_square = false, filter_out_of_bounds = false;
+ cv::GCompileArgs compile_args;
+ std::tie(sz, confidence_threshold, alignment_to_square, filter_out_of_bounds, compile_args) = GetParam();
+ cv::Mat in_mat = generateSSDoutput(sz);
+ std::vector<cv::Rect> boxes_gapi, boxes_ref;
+
+ // Reference code //////////////////////////////////////////////////////////
+ parseSSDref(in_mat, sz, confidence_threshold, alignment_to_square, filter_out_of_bounds, boxes_ref);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::GMat in;
+ cv::GOpaque<cv::Size> op_sz;
+ auto out = cv::gapi::parseSSD(in, op_sz, confidence_threshold, alignment_to_square, filter_out_of_bounds);
+ cv::GComputation c(cv::GIn(in, op_sz), cv::GOut(out));
+
+ // Warm-up graph engine:
+ auto cc = c.compile(descr_of(in_mat), descr_of(sz), std::move(compile_args));
+ cc(cv::gin(in_mat, sz), cv::gout(boxes_gapi));
+
+ TEST_CYCLE()
+ {
+ cc(cv::gin(in_mat, sz), cv::gout(boxes_gapi));
+ }
+
+ // Comparison ////////////////////////////////////////////////////////////
+ {
+ EXPECT_TRUE(boxes_gapi == boxes_ref);
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+//------------------------------------------------------------------------------
+
+PERF_TEST_P_(ParseYoloPerfTest, TestPerformance)
+{
+ cv::Size sz;
+ float confidence_threshold = 0.0f, nms_threshold = 0.0f;
+ int num_classes = 0;
+ cv::GCompileArgs compile_args;
+ std::tie(sz, confidence_threshold, nms_threshold, num_classes, compile_args) = GetParam();
+ cv::Mat in_mat = generateYoloOutput(num_classes);
+ auto anchors = cv::gapi::nn::parsers::GParseYolo::defaultAnchors();
+ std::vector<cv::Rect> boxes_gapi, boxes_ref;
+ std::vector<int> labels_gapi, labels_ref;
+
+ // Reference code //////////////////////////////////////////////////////////
+ parseYoloRef(in_mat, sz, confidence_threshold, nms_threshold, num_classes, anchors, boxes_ref, labels_ref);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::GMat in;
+ cv::GOpaque<cv::Size> op_sz;
+ auto out = cv::gapi::parseYolo(in, op_sz, confidence_threshold, nms_threshold, anchors);
+ cv::GComputation c(cv::GIn(in, op_sz), cv::GOut(std::get<0>(out), std::get<1>(out)));
+
+ // Warm-up graph engine:
+ auto cc = c.compile(descr_of(in_mat), descr_of(sz), std::move(compile_args));
+ cc(cv::gin(in_mat, sz), cv::gout(boxes_gapi, labels_gapi));
+
+ TEST_CYCLE()
+ {
+ cc(cv::gin(in_mat, sz), cv::gout(boxes_gapi, labels_gapi));
+ }
+
+ // Comparison ////////////////////////////////////////////////////////////
+ {
+ EXPECT_TRUE(boxes_gapi == boxes_ref);
+ EXPECT_TRUE(labels_gapi == labels_ref);
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+//------------------------------------------------------------------------------
+
+PERF_TEST_P_(SizePerfTest, TestPerformance)
+{
+ MatType type;
+ cv::Size sz;
+ cv::GCompileArgs compile_args;
+ std::tie(type, sz, compile_args) = GetParam();
+ in_mat1 = cv::Mat(sz, type);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::GMat in;
+ auto out = cv::gapi::size(in);
+ cv::GComputation c(cv::GIn(in), cv::GOut(out));
+ cv::Size out_sz;
+
+ // Warm-up graph engine:
+ auto cc = c.compile(descr_of(in_mat1), std::move(compile_args));
+ cc(cv::gin(in_mat1), cv::gout(out_sz));
+
+ TEST_CYCLE()
+ {
+ cc(cv::gin(in_mat1), cv::gout(out_sz));
+ }
+
+ // Comparison ////////////////////////////////////////////////////////////
+ {
+ EXPECT_EQ(out_sz, sz);
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+//------------------------------------------------------------------------------
+
+PERF_TEST_P_(SizeRPerfTest, TestPerformance)
+{
+ cv::Size sz;
+ cv::GCompileArgs compile_args;
+ std::tie(sz, compile_args) = GetParam();
+ cv::Rect rect(cv::Point(0,0), sz);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::GOpaque<cv::Rect> op_rect;
+ auto out = cv::gapi::size(op_rect);
+ cv::GComputation c(cv::GIn(op_rect), cv::GOut(out));
+ cv::Size out_sz;
+
+ // Warm-up graph engine:
+ auto cc = c.compile(descr_of(rect), std::move(compile_args));
+ cc(cv::gin(rect), cv::gout(out_sz));
+
+ TEST_CYCLE()
+ {
+ cc(cv::gin(rect), cv::gout(out_sz));
+ }
+
+ // Comparison ////////////////////////////////////////////////////////////
+ {
+ EXPECT_EQ(out_sz, sz);
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
}
#endif // OPENCV_GAPI_CORE_PERF_TESTS_INL_HPP
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_IMGPROC_PERF_TESTS_HPP
//------------------------------------------------------------------------------
-class SepFilterPerfTest : public TestPerfParams<tuple<compare_f, MatType, int, cv::Size, int, cv::GCompileArgs>> {};
-class Filter2DPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int,int, cv::GCompileArgs>> {};
-class BoxFilterPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int,int, cv::GCompileArgs>> {};
-class BlurPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int, cv::GCompileArgs>> {};
-class GaussianBlurPerfTest : public TestPerfParams<tuple<compare_f, MatType, int, cv::Size, cv::GCompileArgs>> {};
-class MedianBlurPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size, cv::GCompileArgs>> {};
-class ErodePerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int, cv::GCompileArgs>> {};
-class Erode3x3PerfTest : public TestPerfParams<tuple<compare_f, MatType, cv::Size, int, cv::GCompileArgs>> {};
-class DilatePerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int, cv::GCompileArgs>> {};
-class Dilate3x3PerfTest : public TestPerfParams<tuple<compare_f, MatType,cv::Size,int, cv::GCompileArgs>> {};
-class SobelPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int,int,int, cv::GCompileArgs>> {};
-class SobelXYPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int,int, cv::GCompileArgs>> {};
-class CannyPerfTest : public TestPerfParams<tuple<compare_f, MatType,cv::Size,double,double,int,bool, cv::GCompileArgs>> {};
-class EqHistPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs >> {};
-class RGB2GrayPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs >> {};
-class BGR2GrayPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs >> {};
-class RGB2YUVPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs >> {};
-class YUV2RGBPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs >> {};
-class RGB2LabPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
-class BGR2LUVPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
-class LUV2BGRPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
-class BGR2YUVPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
-class YUV2BGRPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
-class RGB2HSVPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
+class SepFilterPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int, cv::GCompileArgs>> {};
+class Filter2DPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int,int, cv::GCompileArgs>> {};
+class BoxFilterPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int,int, cv::GCompileArgs>> {};
+class BlurPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int, cv::GCompileArgs>> {};
+class GaussianBlurPerfTest : public TestPerfParams<tuple<compare_f, MatType,int, cv::Size, cv::GCompileArgs>> {};
+class MedianBlurPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size, cv::GCompileArgs>> {};
+class ErodePerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int, cv::GCompileArgs>> {};
+class Erode3x3PerfTest : public TestPerfParams<tuple<compare_f, MatType,cv::Size,int, cv::GCompileArgs>> {};
+class DilatePerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int, cv::GCompileArgs>> {};
+class Dilate3x3PerfTest : public TestPerfParams<tuple<compare_f, MatType,cv::Size,int, cv::GCompileArgs>> {};
+class SobelPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int,int,int, cv::GCompileArgs>> {};
+class SobelXYPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int,int, cv::GCompileArgs>> {};
+class LaplacianPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int,
+ cv::GCompileArgs>> {};
+class BilateralFilterPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int, double,double,
+ cv::GCompileArgs>> {};
+class CannyPerfTest : public TestPerfParams<tuple<compare_f, MatType,cv::Size,double,double,int,bool,
+ cv::GCompileArgs>> {};
+class GoodFeaturesPerfTest : public TestPerfParams<tuple<compare_vector_f<cv::Point2f>, std::string,
+ int,int,double,double,int,bool,
+ cv::GCompileArgs>> {};
+class EqHistPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
+class RGB2GrayPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
+class BGR2GrayPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
+class RGB2YUVPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
+class YUV2RGBPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
+class RGB2LabPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
+class BGR2LUVPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
+class LUV2BGRPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
+class BGR2YUVPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
+class YUV2BGRPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
+class RGB2HSVPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class BayerGR2RGBPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
class RGB2YUV422PerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs>> {};
-}
+} // opencv_test
+
#endif //OPENCV_GAPI_IMGPROC_PERF_TESTS_HPP
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018-2019 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_IMGPROC_PERF_TESTS_INL_HPP
#define OPENCV_GAPI_IMGPROC_PERF_TESTS_INL_HPP
-#include <iostream>
-
#include "gapi_imgproc_perf_tests.hpp"
namespace opencv_test
//------------------------------------------------------------------------------
+PERF_TEST_P_(LaplacianPerfTest, TestPerformance)
+{
+ compare_f cmpF;
+ MatType type = 0;
+ int kernSize = 0, dtype = 0;
+ cv::Size sz;
+ cv::GCompileArgs compile_args;
+ std::tie(cmpF, type, kernSize, sz, dtype, compile_args) = GetParam();
+
+ initMatrixRandN(type, sz, dtype, false);
+
+ // OpenCV code /////////////////////////////////////////////////////////////
+ {
+ cv::Laplacian(in_mat1, out_mat_ocv, dtype, kernSize);
+ }
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::GMat in;
+ auto out = cv::gapi::Laplacian(in, dtype, kernSize);
+ cv::GComputation c(in, out);
+
+ // Warm-up graph engine:
+ c.apply(in_mat1, out_mat_gapi, std::move(compile_args));
+
+ TEST_CYCLE()
+ {
+ c.apply(in_mat1, out_mat_gapi);
+ }
+
+ // Comparison //////////////////////////////////////////////////////////////
+ {
+ EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
+ EXPECT_EQ(out_mat_gapi.size(), sz);
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+//------------------------------------------------------------------------------
+
+PERF_TEST_P_(BilateralFilterPerfTest, TestPerformance)
+{
+ compare_f cmpF;
+ MatType type = 0;
+ int dtype = 0, d = 0, borderType = BORDER_DEFAULT;
+ double sigmaColor = 0, sigmaSpace = 0;
+ cv::Size sz;
+ cv::GCompileArgs compile_args;
+ std::tie(cmpF, type, dtype, sz, d, sigmaColor, sigmaSpace,
+ compile_args) = GetParam();
+
+ initMatrixRandN(type, sz, dtype, false);
+
+ // OpenCV code /////////////////////////////////////////////////////////////
+ {
+ cv::bilateralFilter(in_mat1, out_mat_ocv, d, sigmaColor, sigmaSpace, borderType);
+ }
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::GMat in;
+ auto out = cv::gapi::bilateralFilter(in, d, sigmaColor, sigmaSpace, borderType);
+ cv::GComputation c(in, out);
+
+ // Warm-up graph engine:
+ c.apply(in_mat1, out_mat_gapi, std::move(compile_args));
+
+ TEST_CYCLE()
+ {
+ c.apply(in_mat1, out_mat_gapi);
+ }
+
+ // Comparison //////////////////////////////////////////////////////////////
+ {
+ EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
+ EXPECT_EQ(out_mat_gapi.size(), sz);
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+//------------------------------------------------------------------------------
+
+
PERF_TEST_P_(CannyPerfTest, TestPerformance)
{
compare_f cmpF;
//------------------------------------------------------------------------------
+PERF_TEST_P_(GoodFeaturesPerfTest, TestPerformance)
+{
+ double k = 0.04;
+
+ compare_vector_f<cv::Point2f> cmpF;
+ std::string fileName = "";
+ int type = -1, maxCorners = -1, blockSize = -1;
+ double qualityLevel = 0.0, minDistance = 0.0;
+ bool useHarrisDetector = false;
+ cv::GCompileArgs compileArgs;
+ std::tie(cmpF, fileName, type, maxCorners, qualityLevel,
+ minDistance, blockSize, useHarrisDetector, compileArgs) = GetParam();
+
+ initMatFromImage(type, fileName);
+ std::vector<cv::Point2f> outVecOCV, outVecGAPI;
+
+ // OpenCV code /////////////////////////////////////////////////////////////
+ {
+ cv::goodFeaturesToTrack(in_mat1, outVecOCV, maxCorners, qualityLevel, minDistance,
+ cv::noArray(), blockSize, useHarrisDetector, k);
+ }
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::GMat in;
+ auto out = cv::gapi::goodFeaturesToTrack(in, maxCorners, qualityLevel, minDistance, cv::Mat(),
+ blockSize, useHarrisDetector, k);
+ cv::GComputation c(cv::GIn(in), cv::GOut(out));
+
+ // Warm-up graph engine:
+ c.apply(cv::gin(in_mat1), cv::gout(outVecGAPI), std::move(compileArgs));
+
+ TEST_CYCLE()
+ {
+ c.apply(cv::gin(in_mat1), cv::gout(outVecGAPI));
+ }
+
+ // Comparison //////////////////////////////////////////////////////////////
+ {
+ EXPECT_TRUE(cmpF(outVecGAPI, outVecOCV));
+ }
+
+ SANITY_CHECK_NOTHING();
+
+}
+
+//------------------------------------------------------------------------------
+
PERF_TEST_P_(EqHistPerfTest, TestPerformance)
{
compare_f cmpF = get<0>(GetParam());
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#include "../perf_precomp.hpp"
+#include "gapi_render_perf_tests_inl.hpp"
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#ifndef OPENCV_GAPI_RENDER_PERF_TESTS_HPP
+#define OPENCV_GAPI_RENDER_PERF_TESTS_HPP
+
+
+#include "../../test/common/gapi_tests_common.hpp"
+#include <opencv2/gapi/render/render.hpp>
+
+namespace opencv_test
+{
+
+using namespace perf;
+
+class RenderTestFTexts : public TestPerfParams<tuple<std::wstring, cv::Size, cv::Point,
+ int, cv::Scalar, cv::GCompileArgs>> {};
+class RenderTestTexts : public TestPerfParams<tuple<std::string, cv::Size, cv::Point,
+ int, cv::Scalar, int, int,
+ bool, cv::GCompileArgs>> {};
+class RenderTestRects : public TestPerfParams<tuple<cv::Size, cv::Rect, cv::Scalar,
+ int, int, int, cv::GCompileArgs>> {};
+class RenderTestCircles : public TestPerfParams<tuple<cv::Size, cv::Point, int,
+ cv::Scalar, int, int, int,
+ cv::GCompileArgs>> {};
+class RenderTestLines : public TestPerfParams<tuple<cv::Size, cv::Point, cv::Point,
+ cv::Scalar, int, int, int,
+ cv::GCompileArgs>> {};
+class RenderTestMosaics : public TestPerfParams<tuple<cv::Size, cv::Rect, int, int,
+ cv::GCompileArgs>> {};
+class RenderTestImages : public TestPerfParams<tuple<cv::Size, cv::Rect, cv::Scalar, double,
+ cv::GCompileArgs>> {};
+class RenderTestPolylines : public TestPerfParams<tuple<cv::Size, std::vector<cv::Point>,
+ cv::Scalar, int, int, int,
+ cv::GCompileArgs>> {};
+class RenderTestPolyItems : public TestPerfParams<tuple<cv::Size, int, int, int, cv::GCompileArgs>> {};
+
+}
+#endif //OPENCV_GAPI_RENDER_PERF_TESTS_HPP
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#include "gapi_render_perf_tests.hpp"
+
+namespace opencv_test
+{
+
+namespace {
+void create_rand_mats(const cv::Size &size, MatType type, cv::Mat &ref_mat, cv::Mat &gapi_mat)
+{
+ ref_mat.create(size, type);
+ cv::randu(ref_mat, cv::Scalar::all(0), cv::Scalar::all(255));
+ ref_mat.copyTo(gapi_mat);
+};
+
+} // namespace
+
+PERF_TEST_P_(RenderTestFTexts, RenderFTextsPerformanceBGROCVTest)
+{
+ std::wstring text;
+ cv::Size sz;
+ cv::Point org;
+ int fh = 0;
+ cv::Scalar color;
+ cv::GCompileArgs comp_args;
+ std::tie(text ,sz ,org ,fh ,color, comp_args) = GetParam();
+
+ MatType type = CV_8UC3;
+ cv::Mat gapi_mat, ref_mat;
+ create_rand_mats(sz, type, ref_mat, gapi_mat);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+ prims.emplace_back(cv::gapi::wip::draw::FText{text, org, fh, color});
+
+ cv::GMat in;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+
+ cv::GComputation comp(cv::GIn(in, arr),
+ cv::GOut(cv::gapi::wip::draw::render3ch(in, arr)));
+
+ // Warm-up graph engine:
+ comp.apply(gin(gapi_mat, prims), gout(gapi_mat), std::move(comp_args));
+
+ TEST_CYCLE()
+ {
+ comp.apply(gin(gapi_mat, prims), gout(gapi_mat));
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P_(RenderTestFTexts, RenderFTextsPerformanceNV12OCVTest)
+{
+ std::wstring text;
+ cv::Size sz;
+ cv::Point org;
+ int fh = 0;
+ cv::Scalar color;
+ cv::GCompileArgs comp_args;
+ std::tie(text ,sz ,org ,fh ,color, comp_args) = GetParam();
+
+ cv::Mat y_ref_mat, uv_ref_mat;
+
+ cv::Mat y_in_gapi_mat, uv_in_gapi_mat,
+ y_out_gapi_mat, uv_out_gapi_mat;
+
+ create_rand_mats(sz, CV_8UC1, y_ref_mat, y_in_gapi_mat);
+ create_rand_mats(sz / 2, CV_8UC2, uv_ref_mat, uv_in_gapi_mat);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+ prims.emplace_back(cv::gapi::wip::draw::FText{text, org, fh, color});
+
+ cv::GMat y_in, uv_in, y_out, uv_out;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+ std::tie(y_out, uv_out) = cv::gapi::wip::draw::renderNV12(y_in, uv_in, arr);
+
+ cv::GComputation comp(cv::GIn(y_in, uv_in, arr), cv::GOut(y_out, uv_out));
+
+ // Warm-up graph engine:
+ comp.apply(cv::gin(y_in_gapi_mat, uv_in_gapi_mat, prims),
+ cv::gout(y_out_gapi_mat, uv_out_gapi_mat), std::move(comp_args));
+
+ TEST_CYCLE()
+ {
+ comp.apply(cv::gin(y_in_gapi_mat, uv_in_gapi_mat, prims),
+ cv::gout(y_out_gapi_mat, uv_out_gapi_mat));
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P_(RenderTestTexts, RenderTextsPerformanceBGROCVTest)
+{
+ cv::Point org;
+ int ff = 0;
+ int thick = 0;
+ int lt = 0;
+ double fs = 2.0;
+ cv::Scalar color;
+ bool blo = false;
+ std::string text;
+ cv::Size sz;
+ cv::GCompileArgs comp_args;
+ std::tie(text, sz, org, ff, color, thick, lt, blo, comp_args) = GetParam();
+
+ MatType type = CV_8UC3;
+ cv::Mat gapi_mat, ref_mat;
+ create_rand_mats(sz, type, ref_mat, gapi_mat);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+ prims.emplace_back(cv::gapi::wip::draw::Text{text, org, ff, fs, color, thick, lt, blo});
+
+ cv::GMat in;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+
+ cv::GComputation comp(cv::GIn(in, arr),
+ cv::GOut(cv::gapi::wip::draw::render3ch(in, arr)));
+
+ // Warm-up graph engine:
+ comp.apply(gin(gapi_mat, prims), gout(gapi_mat), std::move(comp_args));
+
+ TEST_CYCLE()
+ {
+ comp.apply(gin(gapi_mat, prims), gout(gapi_mat));
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P_(RenderTestTexts, RenderTextsPerformanceNV12OCVTest)
+{
+ cv::Point org;
+ int ff = 0;
+ int thick = 0;
+ int lt = 0;
+ double fs = 2.0;
+ cv::Scalar color;
+ bool blo = false;
+ std::string text;
+ cv::Size sz;
+ cv::GCompileArgs comp_args;
+ std::tie(text, sz, org, ff, color, thick, lt, blo, comp_args) = GetParam();
+
+ cv::Mat y_ref_mat, uv_ref_mat;
+
+ cv::Mat y_in_gapi_mat, uv_in_gapi_mat,
+ y_out_gapi_mat, uv_out_gapi_mat;
+
+ create_rand_mats(sz, CV_8UC1, y_ref_mat, y_in_gapi_mat);
+ create_rand_mats(sz / 2, CV_8UC2, uv_ref_mat, uv_in_gapi_mat);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+ prims.emplace_back(cv::gapi::wip::draw::Text{text, org, ff, fs, color, thick, lt, blo});
+
+ cv::GMat y_in, uv_in, y_out, uv_out;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+ std::tie(y_out, uv_out) = cv::gapi::wip::draw::renderNV12(y_in, uv_in, arr);
+
+ cv::GComputation comp(cv::GIn(y_in, uv_in, arr), cv::GOut(y_out, uv_out));
+
+ // Warm-up graph engine:
+ comp.apply(cv::gin(y_in_gapi_mat, uv_in_gapi_mat, prims),
+ cv::gout(y_out_gapi_mat, uv_out_gapi_mat), std::move(comp_args));
+
+ TEST_CYCLE()
+ {
+ comp.apply(cv::gin(y_in_gapi_mat, uv_in_gapi_mat, prims),
+ cv::gout(y_out_gapi_mat, uv_out_gapi_mat));
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P_(RenderTestRects, RenderRectsPerformanceBGROCVTest)
+{
+ cv::Rect rect;
+ cv::Scalar color;
+ int thick = 0;
+ int lt = 0;
+ int shift = 0;
+ cv::Size sz;
+ cv::GCompileArgs comp_args;
+ std::tie(sz, rect, color, thick, lt, shift, comp_args) = GetParam();
+
+ MatType type = CV_8UC3;
+ cv::Mat gapi_mat, ref_mat;
+ create_rand_mats(sz, type, ref_mat, gapi_mat);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+ prims.emplace_back(cv::gapi::wip::draw::Rect{rect, color, thick, lt, shift});
+
+ cv::GMat in;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+
+ cv::GComputation comp(cv::GIn(in, arr),
+ cv::GOut(cv::gapi::wip::draw::render3ch(in, arr)));
+
+ // Warm-up graph engine:
+ comp.apply(gin(gapi_mat, prims), gout(gapi_mat), std::move(comp_args));
+
+ TEST_CYCLE()
+ {
+ comp.apply(gin(gapi_mat, prims), gout(gapi_mat));
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P_(RenderTestRects, RenderRectsPerformanceNV12OCVTest)
+{
+ cv::Rect rect;
+ cv::Scalar color;
+ int thick = 0;
+ int lt = 0;
+ int shift = 0;
+ cv::Size sz;
+ cv::GCompileArgs comp_args;
+ std::tie(sz, rect, color, thick, lt, shift, comp_args) = GetParam();
+
+ cv::Mat y_ref_mat, uv_ref_mat;
+
+ cv::Mat y_in_gapi_mat, uv_in_gapi_mat,
+ y_out_gapi_mat, uv_out_gapi_mat;
+
+ create_rand_mats(sz, CV_8UC1, y_ref_mat, y_in_gapi_mat);
+ create_rand_mats(sz / 2, CV_8UC2, uv_ref_mat, uv_in_gapi_mat);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+ prims.emplace_back(cv::gapi::wip::draw::Rect{rect, color, thick, lt, shift});
+
+ cv::GMat y_in, uv_in, y_out, uv_out;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+ std::tie(y_out, uv_out) = cv::gapi::wip::draw::renderNV12(y_in, uv_in, arr);
+
+ cv::GComputation comp(cv::GIn(y_in, uv_in, arr), cv::GOut(y_out, uv_out));
+
+ // Warm-up graph engine:
+ comp.apply(cv::gin(y_in_gapi_mat, uv_in_gapi_mat, prims),
+ cv::gout(y_out_gapi_mat, uv_out_gapi_mat), std::move(comp_args));
+
+ TEST_CYCLE()
+ {
+ comp.apply(cv::gin(y_in_gapi_mat, uv_in_gapi_mat, prims),
+ cv::gout(y_out_gapi_mat, uv_out_gapi_mat));
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P_(RenderTestCircles, RenderCirclesPerformanceBGROCVTest)
+{
+ cv::Point center;
+ int radius;
+ cv::Scalar color;
+ int thick = 0;
+ int lt = 0;
+ int shift = 0;
+
+ cv::Size sz;
+ cv::GCompileArgs comp_args;
+ std::tie(sz, center, radius, color, thick, lt, shift, comp_args) = GetParam();
+
+ MatType type = CV_8UC3;
+ cv::Mat gapi_mat, ref_mat;
+ create_rand_mats(sz, type, ref_mat, gapi_mat);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+ prims.emplace_back(cv::gapi::wip::draw::Circle{center, radius, color, thick, lt, shift});
+
+ cv::GMat in;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+
+ cv::GComputation comp(cv::GIn(in, arr),
+ cv::GOut(cv::gapi::wip::draw::render3ch(in, arr)));
+
+ // Warm-up graph engine:
+ comp.apply(gin(gapi_mat, prims), gout(gapi_mat), std::move(comp_args));
+
+ TEST_CYCLE()
+ {
+ comp.apply(gin(gapi_mat, prims), gout(gapi_mat));
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P_(RenderTestCircles, RenderCirclesPerformanceNV12OCVTest)
+{
+ cv::Point center;
+ int radius;
+ cv::Scalar color;
+ int thick = 0;
+ int lt = 0;
+ int shift = 0;
+
+ cv::Size sz;
+ cv::GCompileArgs comp_args;
+ std::tie(sz, center, radius, color, thick, lt, shift, comp_args) = GetParam();
+
+ cv::Mat y_ref_mat, uv_ref_mat;
+
+ cv::Mat y_in_gapi_mat, uv_in_gapi_mat,
+ y_out_gapi_mat, uv_out_gapi_mat;
+
+ create_rand_mats(sz, CV_8UC1, y_ref_mat, y_in_gapi_mat);
+ create_rand_mats(sz / 2, CV_8UC2, uv_ref_mat, uv_in_gapi_mat);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+ prims.emplace_back(cv::gapi::wip::draw::Circle{center, radius, color, thick, lt, shift});
+
+ cv::GMat y_in, uv_in, y_out, uv_out;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+ std::tie(y_out, uv_out) = cv::gapi::wip::draw::renderNV12(y_in, uv_in, arr);
+
+ cv::GComputation comp(cv::GIn(y_in, uv_in, arr), cv::GOut(y_out, uv_out));
+
+ // Warm-up graph engine:
+ comp.apply(cv::gin(y_in_gapi_mat, uv_in_gapi_mat, prims),
+ cv::gout(y_out_gapi_mat, uv_out_gapi_mat), std::move(comp_args));
+
+ TEST_CYCLE()
+ {
+ comp.apply(cv::gin(y_in_gapi_mat, uv_in_gapi_mat, prims),
+ cv::gout(y_out_gapi_mat, uv_out_gapi_mat));
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P_(RenderTestLines, RenderLinesPerformanceBGROCVTest)
+{
+ cv::Point pt1;
+ cv::Point pt2;
+ cv::Scalar color;
+ int thick = 0;
+ int lt = 0;
+ int shift = 0;
+
+ compare_f cmpF;
+ cv::Size sz;
+ cv::GCompileArgs comp_args;
+ std::tie(sz, pt1, pt2, color, thick, lt, shift, comp_args) = GetParam();
+
+ MatType type = CV_8UC3;
+ cv::Mat gapi_mat, ref_mat;
+ create_rand_mats(sz, type, ref_mat, gapi_mat);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+ prims.emplace_back(cv::gapi::wip::draw::Line{pt1, pt2, color, thick, lt, shift});
+
+ cv::GMat in;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+
+ cv::GComputation comp(cv::GIn(in, arr),
+ cv::GOut(cv::gapi::wip::draw::render3ch(in, arr)));
+
+ // Warm-up graph engine:
+ comp.apply(gin(gapi_mat, prims), gout(gapi_mat), std::move(comp_args));
+
+ TEST_CYCLE()
+ {
+ comp.apply(gin(gapi_mat, prims), gout(gapi_mat));
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P_(RenderTestLines, RenderLinesPerformanceNV12OCVTest)
+{
+ cv::Point pt1;
+ cv::Point pt2;
+ cv::Scalar color;
+ int thick = 0;
+ int lt = 0;
+ int shift = 0;
+
+ compare_f cmpF;
+ cv::Size sz;
+ cv::GCompileArgs comp_args;
+ std::tie(sz, pt1, pt2, color, thick, lt, shift, comp_args) = GetParam();
+
+ cv::Mat y_ref_mat, uv_ref_mat;
+
+ cv::Mat y_in_gapi_mat, uv_in_gapi_mat,
+ y_out_gapi_mat, uv_out_gapi_mat;
+
+ create_rand_mats(sz, CV_8UC1, y_ref_mat, y_in_gapi_mat);
+ create_rand_mats(sz / 2, CV_8UC2, uv_ref_mat, uv_in_gapi_mat);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+ prims.emplace_back(cv::gapi::wip::draw::Line{pt1, pt2, color, thick, lt, shift});
+
+ cv::GMat y_in, uv_in, y_out, uv_out;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+ std::tie(y_out, uv_out) = cv::gapi::wip::draw::renderNV12(y_in, uv_in, arr);
+
+ cv::GComputation comp(cv::GIn(y_in, uv_in, arr), cv::GOut(y_out, uv_out));
+
+ // Warm-up graph engine:
+ comp.apply(cv::gin(y_in_gapi_mat, uv_in_gapi_mat, prims),
+ cv::gout(y_out_gapi_mat, uv_out_gapi_mat), std::move(comp_args));
+
+ TEST_CYCLE()
+ {
+ comp.apply(cv::gin(y_in_gapi_mat, uv_in_gapi_mat, prims),
+ cv::gout(y_out_gapi_mat, uv_out_gapi_mat));
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P_(RenderTestMosaics, RenderMosaicsPerformanceBGROCVTest)
+{
+ cv::Rect mos;
+ int cellsz = 0;
+ int decim = 0;
+
+ cv::Size sz;
+ cv::GCompileArgs comp_args;
+ std::tie(sz, mos, cellsz, decim, comp_args) = GetParam();
+
+ MatType type = CV_8UC3;
+ cv::Mat gapi_mat, ref_mat;
+ create_rand_mats(sz, type, ref_mat, gapi_mat);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+ prims.emplace_back(cv::gapi::wip::draw::Mosaic{mos, cellsz, decim});
+
+ cv::GMat in;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+
+ cv::GComputation comp(cv::GIn(in, arr),
+ cv::GOut(cv::gapi::wip::draw::render3ch(in, arr)));
+
+ // Warm-up graph engine:
+ comp.apply(gin(gapi_mat, prims), gout(gapi_mat), std::move(comp_args));
+
+ TEST_CYCLE()
+ {
+ comp.apply(gin(gapi_mat, prims), gout(gapi_mat));
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+
+PERF_TEST_P_(RenderTestMosaics, RenderMosaicsPerformanceNV12OCVTest)
+{
+ cv::Rect mos;
+ int cellsz = 0;
+ int decim = 0;
+
+ cv::Size sz;
+ cv::GCompileArgs comp_args;
+ std::tie(sz, mos, cellsz, decim, comp_args) = GetParam();
+
+ cv::Mat y_ref_mat, uv_ref_mat;
+
+ cv::Mat y_in_gapi_mat, uv_in_gapi_mat,
+ y_out_gapi_mat, uv_out_gapi_mat;
+
+ create_rand_mats(sz, CV_8UC1, y_ref_mat, y_in_gapi_mat);
+ create_rand_mats(sz / 2, CV_8UC2, uv_ref_mat, uv_in_gapi_mat);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+ prims.emplace_back(cv::gapi::wip::draw::Mosaic{mos, cellsz, decim});
+
+ cv::GMat y_in, uv_in, y_out, uv_out;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+ std::tie(y_out, uv_out) = cv::gapi::wip::draw::renderNV12(y_in, uv_in, arr);
+
+ cv::GComputation comp(cv::GIn(y_in, uv_in, arr), cv::GOut(y_out, uv_out));
+
+ // Warm-up graph engine:
+ comp.apply(cv::gin(y_in_gapi_mat, uv_in_gapi_mat, prims),
+ cv::gout(y_out_gapi_mat, uv_out_gapi_mat), std::move(comp_args));
+
+ TEST_CYCLE()
+ {
+ comp.apply(cv::gin(y_in_gapi_mat, uv_in_gapi_mat, prims),
+ cv::gout(y_out_gapi_mat, uv_out_gapi_mat));
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P_(RenderTestImages, RenderImagesPerformanceBGROCVTest)
+{
+ cv::Rect rect;
+ cv::Scalar color;
+ double transparency = 0.0;
+
+ cv::Size sz;
+ cv::GCompileArgs comp_args;
+ std::tie(sz, rect, color, transparency, comp_args) = GetParam();
+
+ MatType type = CV_8UC3;
+ cv::Mat gapi_mat, ref_mat;
+ create_rand_mats(sz, type, ref_mat, gapi_mat);
+
+ cv::Mat img(rect.size(), CV_8UC3, color);
+ cv::Mat alpha(rect.size(), CV_32FC1, transparency);
+ auto tl = rect.tl();
+ cv::Point org = {tl.x, tl.y + rect.size().height};
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+ prims.emplace_back(cv::gapi::wip::draw::Image{org, img, alpha});
+ cv::gapi::wip::draw::render(gapi_mat, prims);
+
+ cv::GMat in;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+
+ cv::GComputation comp(cv::GIn(in, arr),
+ cv::GOut(cv::gapi::wip::draw::render3ch(in, arr)));
+
+ // Warm-up graph engine:
+ comp.apply(gin(gapi_mat, prims), gout(gapi_mat), std::move(comp_args));
+
+ TEST_CYCLE()
+ {
+ comp.apply(gin(gapi_mat, prims), gout(gapi_mat));
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P_(RenderTestImages, RenderImagesPerformanceNV12OCVTest)
+{
+ cv::Rect rect;
+ cv::Scalar color;
+ double transparency = 0.0;
+
+ cv::Size sz;
+ cv::GCompileArgs comp_args;
+ std::tie(sz, rect, color, transparency, comp_args) = GetParam();
+
+ cv::Mat y_ref_mat, uv_ref_mat;
+
+ cv::Mat y_in_gapi_mat, uv_in_gapi_mat,
+ y_out_gapi_mat, uv_out_gapi_mat;
+
+ create_rand_mats(sz, CV_8UC1, y_ref_mat, y_in_gapi_mat);
+ create_rand_mats(sz / 2, CV_8UC2, uv_ref_mat, uv_in_gapi_mat);
+
+ cv::Mat img(rect.size(), CV_8UC3, color);
+ cv::Mat alpha(rect.size(), CV_32FC1, transparency);
+ auto tl = rect.tl();
+ cv::Point org = {tl.x, tl.y + rect.size().height};
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+ prims.emplace_back(cv::gapi::wip::draw::Image{org, img, alpha});
+
+ cv::GMat y_in, uv_in, y_out, uv_out;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+ std::tie(y_out, uv_out) = cv::gapi::wip::draw::renderNV12(y_in, uv_in, arr);
+
+ cv::GComputation comp(cv::GIn(y_in, uv_in, arr), cv::GOut(y_out, uv_out));
+
+ // Warm-up graph engine:
+ comp.apply(cv::gin(y_in_gapi_mat, uv_in_gapi_mat, prims),
+ cv::gout(y_out_gapi_mat, uv_out_gapi_mat), std::move(comp_args));
+
+ TEST_CYCLE()
+ {
+ comp.apply(cv::gin(y_in_gapi_mat, uv_in_gapi_mat, prims),
+ cv::gout(y_out_gapi_mat, uv_out_gapi_mat));
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P_(RenderTestPolylines, RenderPolylinesPerformanceBGROCVTest)
+{
+ std::vector<cv::Point> points;
+ cv::Scalar color;
+ int thick = 0;
+ int lt = 0;
+ int shift = 0;
+
+ cv::Size sz;
+ cv::GCompileArgs comp_args;
+ std::tie(sz, points, color, thick, lt, shift, comp_args) = GetParam();
+
+ MatType type = CV_8UC3;
+ cv::Mat gapi_mat, ref_mat;
+ create_rand_mats(sz, type, ref_mat, gapi_mat);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+ prims.emplace_back(cv::gapi::wip::draw::Poly{points, color, thick, lt, shift});
+
+ cv::GMat in;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+
+ cv::GComputation comp(cv::GIn(in, arr),
+ cv::GOut(cv::gapi::wip::draw::render3ch(in, arr)));
+
+ // Warm-up graph engine:
+ comp.apply(gin(gapi_mat, prims), gout(gapi_mat), std::move(comp_args));
+
+ TEST_CYCLE()
+ {
+ comp.apply(gin(gapi_mat, prims), gout(gapi_mat));
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P_(RenderTestPolylines, RenderPolylinesPerformanceNV12OCVTest)
+{
+ std::vector<cv::Point> points;
+ cv::Scalar color;
+ int thick = 0;
+ int lt = 0;
+ int shift = 0;
+
+ cv::Size sz;
+ cv::GCompileArgs comp_args;
+ std::tie(sz, points, color, thick, lt, shift, comp_args) = GetParam();
+
+ cv::Mat y_ref_mat, uv_ref_mat;
+
+ cv::Mat y_in_gapi_mat, uv_in_gapi_mat,
+ y_out_gapi_mat, uv_out_gapi_mat;
+
+ create_rand_mats(sz, CV_8UC1, y_ref_mat, y_in_gapi_mat);
+ create_rand_mats(sz / 2, CV_8UC2, uv_ref_mat, uv_in_gapi_mat);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+ prims.emplace_back(cv::gapi::wip::draw::Poly{points, color, thick, lt, shift});
+
+ cv::GMat y_in, uv_in, y_out, uv_out;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+ std::tie(y_out, uv_out) = cv::gapi::wip::draw::renderNV12(y_in, uv_in, arr);
+
+ cv::GComputation comp(cv::GIn(y_in, uv_in, arr), cv::GOut(y_out, uv_out));
+
+ // Warm-up graph engine:
+ comp.apply(cv::gin(y_in_gapi_mat, uv_in_gapi_mat, prims),
+ cv::gout(y_out_gapi_mat, uv_out_gapi_mat), std::move(comp_args));
+
+ TEST_CYCLE()
+ {
+ comp.apply(cv::gin(y_in_gapi_mat, uv_in_gapi_mat, prims),
+ cv::gout(y_out_gapi_mat, uv_out_gapi_mat));
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P_(RenderTestPolyItems, RenderPolyItemsPerformanceBGROCVTest)
+{
+ cv::Size sz;
+ int rects_num = 0;
+ int text_num = 0;
+ int image_num = 0;
+ cv::GCompileArgs comp_args;
+ std::tie(sz, rects_num, text_num, image_num, comp_args) = GetParam();
+
+ int thick = 2;
+ int lt = LINE_8;
+ cv::Scalar color(100, 50, 150);
+
+ MatType type = CV_8UC3;
+ cv::Mat gapi_mat, ref_mat;
+ create_rand_mats(sz, type, ref_mat, gapi_mat);
+ cv::Mat gapi_out_mat(sz, type);
+ gapi_mat.copyTo(gapi_out_mat);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+
+ // Rects
+ int shift = 0;
+ for (int i = 0; i < rects_num; ++i) {
+ cv::Rect rect(200 + i, 200 + i, 200, 200);
+ prims.emplace_back(cv::gapi::wip::draw::Rect(rect, color, thick, lt, shift));
+ }
+
+ // Mosaic
+ int cellsz = 25;
+ int decim = 0;
+ for (int i = 0; i < rects_num; ++i) {
+ cv::Rect mos(200 + i, 200 + i, 200, 200);
+ prims.emplace_back(cv::gapi::wip::draw::Mosaic(mos, cellsz, decim));
+ }
+
+ // Text
+ std::string text = "Some text";
+ int ff = FONT_HERSHEY_SIMPLEX;
+ double fs = 2.0;
+ bool blo = false;
+ for (int i = 0; i < text_num; ++i) {
+ cv::Point org(200 + i, 200 + i);
+ prims.emplace_back(cv::gapi::wip::draw::Text(text, org, ff, fs, color, thick, lt, blo));
+ }
+
+ // Image
+ double transparency = 1.0;
+ cv::Rect rect_img(0 ,0 , 50, 50);
+ cv::Mat img(rect_img.size(), CV_8UC3, color);
+ cv::Mat alpha(rect_img.size(), CV_32FC1, transparency);
+ auto tl = rect_img.tl();
+ for (int i = 0; i < image_num; ++i) {
+ cv::Point org_img = {tl.x + i, tl.y + rect_img.size().height + i};
+
+ prims.emplace_back(cv::gapi::wip::draw::Image({org_img, img, alpha}));
+ }
+
+ cv::GMat in;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+
+ cv::GComputation comp(cv::GIn(in, arr),
+ cv::GOut(cv::gapi::wip::draw::render3ch(in, arr)));
+
+ // Warm-up graph engine:
+ comp.apply(gin(gapi_mat, prims), gout(gapi_out_mat), std::move(comp_args));
+
+ TEST_CYCLE()
+ {
+ comp.apply(gin(gapi_mat, prims), gout(gapi_out_mat));
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P_(RenderTestPolyItems, RenderPolyItemsPerformanceNV12OCVTest)
+{
+ cv::Size sz;
+ int rects_num = 0;
+ int text_num = 0;
+ int image_num = 0;
+ cv::GCompileArgs comp_args;
+ std::tie(sz, rects_num, text_num, image_num, comp_args) = GetParam();
+
+ int thick = 2;
+ int lt = LINE_8;
+ cv::Scalar color(100, 50, 150);
+
+ cv::Mat y_ref_mat, uv_ref_mat;
+
+ cv::Mat y_in_gapi_mat, uv_in_gapi_mat,
+ y_out_gapi_mat, uv_out_gapi_mat;
+
+ create_rand_mats(sz, CV_8UC1, y_ref_mat, y_in_gapi_mat);
+ create_rand_mats(sz / 2, CV_8UC2, uv_ref_mat, uv_in_gapi_mat);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+
+ // Rects
+ int shift = 0;
+ for (int i = 0; i < rects_num; ++i) {
+ cv::Rect rect(200 + i, 200 + i, 200, 200);
+ prims.emplace_back(cv::gapi::wip::draw::Rect(rect, color, thick, lt, shift));
+ }
+
+ // Mosaic
+ int cellsz = 25;
+ int decim = 0;
+ for (int i = 0; i < rects_num; ++i) {
+ cv::Rect mos(200 + i, 200 + i, 200, 200);
+ prims.emplace_back(cv::gapi::wip::draw::Mosaic(mos, cellsz, decim));
+ }
+
+ // Text
+ std::string text = "Some text";
+ int ff = FONT_HERSHEY_SIMPLEX;
+ double fs = 2.0;
+ bool blo = false;
+ for (int i = 0; i < text_num; ++i) {
+ cv::Point org(200 + i, 200 + i);
+ prims.emplace_back(cv::gapi::wip::draw::Text(text, org, ff, fs, color, thick, lt, blo));
+ }
+
+ // Image
+ double transparency = 1.0;
+ cv::Rect rect_img(0 ,0 , 50, 50);
+ cv::Mat img(rect_img.size(), CV_8UC3, color);
+ cv::Mat alpha(rect_img.size(), CV_32FC1, transparency);
+ auto tl = rect_img.tl();
+ for (int i = 0; i < image_num; ++i) {
+ cv::Point org_img = {tl.x + i, tl.y + rect_img.size().height + i};
+
+ prims.emplace_back(cv::gapi::wip::draw::Image({org_img, img, alpha}));
+ }
+
+ cv::GMat y_in, uv_in, y_out, uv_out;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+ std::tie(y_out, uv_out) = cv::gapi::wip::draw::renderNV12(y_in, uv_in, arr);
+
+ cv::GComputation comp(cv::GIn(y_in, uv_in, arr), cv::GOut(y_out, uv_out));
+
+ // Warm-up graph engine:
+ comp.apply(cv::gin(y_in_gapi_mat, uv_in_gapi_mat, prims),
+ cv::gout(y_out_gapi_mat, uv_out_gapi_mat), std::move(comp_args));
+
+ TEST_CYCLE()
+ {
+ comp.apply(cv::gin(y_in_gapi_mat, uv_in_gapi_mat, prims),
+ cv::gout(y_out_gapi_mat, uv_out_gapi_mat));
+ }
+
+ SANITY_CHECK_NOTHING();
+}
+
+} // namespace opencv_test
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#include "../perf_precomp.hpp"
+#include "gapi_video_perf_tests_inl.hpp"
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#ifndef OPENCV_GAPI_VIDEO_PERF_TESTS_HPP
+#define OPENCV_GAPI_VIDEO_PERF_TESTS_HPP
+
+#include "../../test/common/gapi_video_tests_common.hpp"
+
+namespace opencv_test
+{
+
+using namespace perf;
+
+//------------------------------------------------------------------------------
+
+class BuildOptFlowPyramidPerfTest : public TestPerfParams<tuple<std::string,int,int,bool,int,int,
+ bool,GCompileArgs>> {};
+class OptFlowLKPerfTest : public TestPerfParams<tuple<std::string,int,tuple<int,int>,int,
+ cv::TermCriteria,cv::GCompileArgs>> {};
+class OptFlowLKForPyrPerfTest : public TestPerfParams<tuple<std::string,int,tuple<int,int>,int,
+ cv::TermCriteria,bool,
+ cv::GCompileArgs>> {};
+class BuildPyr_CalcOptFlow_PipelinePerfTest : public TestPerfParams<tuple<std::string,int,int,bool,
+ cv::GCompileArgs>> {};
+
+} // opencv_test
+
+#endif // OPENCV_GAPI_VIDEO_PERF_TESTS_HPP
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#ifndef OPENCV_GAPI_VIDEO_PERF_TESTS_INL_HPP
+#define OPENCV_GAPI_VIDEO_PERF_TESTS_INL_HPP
+
+#include <iostream>
+
+#include "gapi_video_perf_tests.hpp"
+
+namespace opencv_test
+{
+
+ using namespace perf;
+
+//------------------------------------------------------------------------------
+
+PERF_TEST_P_(BuildOptFlowPyramidPerfTest, TestPerformance)
+{
+ std::vector<Mat> outPyrOCV, outPyrGAPI;
+ int outMaxLevelOCV = 0, outMaxLevelGAPI = 0;
+ Scalar outMaxLevelSc;
+
+ BuildOpticalFlowPyramidTestParams params;
+ std::tie(params.fileName, params.winSize,
+ params.maxLevel, params.withDerivatives,
+ params.pyrBorder, params.derivBorder,
+ params.tryReuseInputImage, params.compileArgs) = GetParam();
+
+ BuildOpticalFlowPyramidTestOutput outOCV { outPyrOCV, outMaxLevelOCV };
+ BuildOpticalFlowPyramidTestOutput outGAPI { outPyrGAPI, outMaxLevelGAPI };
+
+ GComputation c = runOCVnGAPIBuildOptFlowPyramid(*this, params, outOCV, outGAPI);
+
+ declare.in(in_mat1).out(outPyrGAPI);
+
+ TEST_CYCLE()
+ {
+ c.apply(cv::gin(in_mat1), cv::gout(outPyrGAPI, outMaxLevelSc));
+ }
+ outMaxLevelGAPI = static_cast<int>(outMaxLevelSc[0]);
+
+ // Comparison //////////////////////////////////////////////////////////////
+ compareOutputPyramids(outOCV, outGAPI);
+
+ SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P_(OptFlowLKPerfTest, TestPerformance)
+{
+ std::vector<cv::Point2f> outPtsOCV, outPtsGAPI, inPts;
+ std::vector<uchar> outStatusOCV, outStatusGAPI;
+ std::vector<float> outErrOCV, outErrGAPI;
+
+ OptFlowLKTestParams params;
+ std::tie(params.fileNamePattern, params.channels,
+ params.pointsNum, params.winSize, params.criteria,
+ params.compileArgs) = GetParam();
+
+ OptFlowLKTestOutput outOCV { outPtsOCV, outStatusOCV, outErrOCV };
+ OptFlowLKTestOutput outGAPI { outPtsGAPI, outStatusGAPI, outErrGAPI };
+
+ cv::GComputation c = runOCVnGAPIOptFlowLK(*this, inPts, params, outOCV, outGAPI);
+
+ declare.in(in_mat1, in_mat2, inPts).out(outPtsGAPI, outStatusGAPI, outErrGAPI);
+
+ TEST_CYCLE()
+ {
+ c.apply(cv::gin(in_mat1, in_mat2, inPts, std::vector<cv::Point2f>{ }),
+ cv::gout(outPtsGAPI, outStatusGAPI, outErrGAPI));
+ }
+
+ // Comparison //////////////////////////////////////////////////////////////
+ compareOutputsOptFlow(outOCV, outGAPI);
+
+ SANITY_CHECK_NOTHING();
+}
+
+//------------------------------------------------------------------------------
+
+PERF_TEST_P_(OptFlowLKForPyrPerfTest, TestPerformance)
+{
+ std::vector<cv::Mat> inPyr1, inPyr2;
+ std::vector<cv::Point2f> outPtsOCV, outPtsGAPI, inPts;
+ std::vector<uchar> outStatusOCV, outStatusGAPI;
+ std::vector<float> outErrOCV, outErrGAPI;
+
+ bool withDeriv = false;
+ OptFlowLKTestParams params;
+ std::tie(params.fileNamePattern, params.channels,
+ params.pointsNum, params.winSize, params.criteria,
+ withDeriv, params.compileArgs) = GetParam();
+
+ OptFlowLKTestInput<std::vector<cv::Mat>> in { inPyr1, inPyr2, inPts };
+ OptFlowLKTestOutput outOCV { outPtsOCV, outStatusOCV, outErrOCV };
+ OptFlowLKTestOutput outGAPI { outPtsGAPI, outStatusGAPI, outErrGAPI };
+
+ cv::GComputation c = runOCVnGAPIOptFlowLKForPyr(*this, in, params, withDeriv, outOCV, outGAPI);
+
+ declare.in(inPyr1, inPyr2, inPts).out(outPtsGAPI, outStatusGAPI, outErrGAPI);
+
+ TEST_CYCLE()
+ {
+ c.apply(cv::gin(inPyr1, inPyr2, inPts, std::vector<cv::Point2f>{ }),
+ cv::gout(outPtsGAPI, outStatusGAPI, outErrGAPI));
+ }
+
+ // Comparison //////////////////////////////////////////////////////////////
+ compareOutputsOptFlow(outOCV, outGAPI);
+
+ SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P_(BuildPyr_CalcOptFlow_PipelinePerfTest, TestPerformance)
+{
+ std::vector<Point2f> outPtsOCV, outPtsGAPI, inPts;
+ std::vector<uchar> outStatusOCV, outStatusGAPI;
+ std::vector<float> outErrOCV, outErrGAPI;
+
+ BuildOpticalFlowPyramidTestParams params;
+ params.pyrBorder = BORDER_DEFAULT;
+ params.derivBorder = BORDER_DEFAULT;
+ params.tryReuseInputImage = true;
+ std::tie(params.fileName, params.winSize,
+ params.maxLevel, params.withDerivatives,
+ params.compileArgs) = GetParam();
+
+ auto customKernel = gapi::kernels<GCPUMinScalar>();
+ auto kernels = gapi::combine(customKernel,
+ params.compileArgs[0].get<gapi::GKernelPackage>());
+ params.compileArgs = compile_args(kernels);
+
+ OptFlowLKTestOutput outOCV { outPtsOCV, outStatusOCV, outErrOCV };
+ OptFlowLKTestOutput outGAPI { outPtsGAPI, outStatusGAPI, outErrGAPI };
+
+ cv::GComputation c = runOCVnGAPIOptFlowPipeline(*this, params, outOCV, outGAPI, inPts);
+
+ declare.in(in_mat1, in_mat2, inPts).out(outPtsGAPI, outStatusGAPI, outErrGAPI);
+
+ TEST_CYCLE()
+ {
+ c.apply(cv::gin(in_mat1, in_mat2, inPts, std::vector<cv::Point2f>{ }),
+ cv::gout(outPtsGAPI, outStatusGAPI, outErrGAPI));
+ }
+
+ // Comparison //////////////////////////////////////////////////////////////
+ compareOutputsOptFlow(outOCV, outGAPI);
+
+ SANITY_CHECK_NOTHING();
+}
+
+//------------------------------------------------------------------------------
+
+} // opencv_test
+
+#endif // OPENCV_GAPI_VIDEO_PERF_TESTS_INL_HPP
Values(cv::compile_args(CORE_CPU))));
INSTANTIATE_TEST_CASE_P(CmpWithScalarPerfTestCPU, CmpWithScalarPerfTest,
- Combine(Values(CMP_EQ, CMP_GE, CMP_NE, CMP_GT, CMP_LT, CMP_LE),
- Values(szSmall128, szVGA, sz720p, sz1080p),
- Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
- Values(cv::compile_args(CORE_CPU))));
+ Combine(Values(AbsExact().to_compare_f()),
+ Values(CMP_EQ, CMP_GE, CMP_NE, CMP_GT, CMP_LT, CMP_LE),
+ Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+ Values(cv::compile_args(CORE_CPU))));
INSTANTIATE_TEST_CASE_P(BitwisePerfTestCPU, BitwisePerfTest,
Combine(Values(AND, OR, XOR),
- Values(szSmall128, szVGA, sz720p, sz1080p),
- Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
- Values(cv::compile_args(CORE_CPU))));
+ testing::Bool(),
+ Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
+ Values(cv::compile_args(CORE_CPU))));
INSTANTIATE_TEST_CASE_P(BitwiseNotPerfTestCPU, BitwiseNotPerfTest,
Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
INSTANTIATE_TEST_CASE_P(ConvertToPerfTestCPU, ConvertToPerfTest,
- Combine(Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_32FC1),
- Values(CV_8U, CV_16U, CV_16S, CV_32F),
- Values(szSmall128, szVGA, sz720p, sz1080p),
- Values(cv::compile_args(CORE_CPU))));
+ Combine(Values(AbsExact().to_compare_f()),
+ Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1),
+ Values(CV_8U, CV_16U, CV_16S, CV_32F),
+ Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(2.5, 1.0),
+ Values(0.0),
+ Values(cv::compile_args(CORE_CPU))));
INSTANTIATE_TEST_CASE_P(ResizePerfTestCPU, ResizePerfTest,
Combine(Values(AbsExact().to_compare_f()),
Values(0.5, 0.1),
Values(0.5, 0.1),
Values(cv::compile_args(CORE_CPU))));
+
+INSTANTIATE_TEST_CASE_P(ParseSSDBLPerfTestCPU, ParseSSDBLPerfTest,
+ Combine(Values(sz720p, sz1080p),
+ Values(0.3f, 0.7f),
+ Values(0, 1),
+ Values(cv::compile_args(CORE_CPU))));
+
+INSTANTIATE_TEST_CASE_P(ParseSSDPerfTestCPU, ParseSSDPerfTest,
+ Combine(Values(sz720p, sz1080p),
+ Values(0.3f, 0.7f),
+ testing::Bool(),
+ testing::Bool(),
+ Values(cv::compile_args(CORE_CPU))));
+
+INSTANTIATE_TEST_CASE_P(ParseYoloPerfTestCPU, ParseYoloPerfTest,
+ Combine(Values(sz720p, sz1080p),
+ Values(0.3f, 0.7f),
+ Values(0.5),
+ Values(7, 80),
+ Values(cv::compile_args(CORE_CPU))));
+
+INSTANTIATE_TEST_CASE_P(SizePerfTestCPU, SizePerfTest,
+ Combine(Values(CV_8UC1, CV_8UC3, CV_32FC1),
+ Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(cv::compile_args(CORE_CPU))));
+
+INSTANTIATE_TEST_CASE_P(SizeRPerfTestCPU, SizeRPerfTest,
+ Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(cv::compile_args(CORE_CPU))));
} // opencv_test
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#include "../perf_precomp.hpp"
+#include "../common/gapi_core_perf_tests.hpp"
+
+#define CORE_FLUID cv::gapi::core::fluid::kernels()
+
+namespace opencv_test
+{
+INSTANTIATE_TEST_CASE_P(AddPerfTestFluid, AddPerfTest,
+ Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(CV_8UC1, CV_8UC3, CV_16SC1, CV_32FC1),
+ Values(-1, CV_8U, CV_32F),
+ Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(AddCPerfTestFluid, AddCPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(-1, CV_8U, CV_16U, CV_32F),
+// Values(cv::compile_args(CORE_FLUID))));
+
+INSTANTIATE_TEST_CASE_P(SubPerfTestFluid, SubPerfTest,
+ Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(CV_8UC1, CV_8UC3, CV_16SC1, CV_32FC1),
+ Values(-1, CV_8U, CV_32F),
+ Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(SubCPerfTestFluid, SubCPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(-1, CV_8U, CV_16U, CV_32F),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(SubRCPerfTestFluid, SubRCPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(-1, CV_8U, CV_16U, CV_32F),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(MulPerfTestFluid, MulPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(-1, CV_8U, CV_16U, CV_32F),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(MulDoublePerfTestFluid, MulDoublePerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(-1, CV_8U, CV_16U, CV_32F),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(MulCPerfTestFluid, MulCPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(-1, CV_8U, CV_16U, CV_32F),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(DivPerfTestFluid, DivPerfTest,
+// Combine(Values(AbsExact().to_compare_f()),
+// Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(-1, CV_8U, CV_16U, CV_32F),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(DivCPerfTestFluid, DivCPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(-1, CV_8U, CV_16U, CV_32F),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(DivRCPerfTestFluid, DivRCPerfTest,
+// Combine(Values(AbsExact().to_compare_f()),
+// Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(-1, CV_8U, CV_16U, CV_32F),
+// Values(cv::compile_args(CORE_FLUID))));
+
+INSTANTIATE_TEST_CASE_P(MaskPerfTestFluid, MaskPerfTest,
+ Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(CV_8UC1, CV_16UC1, CV_16SC1),
+ Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(MeanPerfTestFluid, MeanPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(Polar2CartPerfTestFluid, Polar2CartPerfTest,
+// Combine(Values(AbsExact().to_compare_f()),
+// Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(Cart2PolarPerfTestFluid, Cart2PolarPerfTest,
+// Combine(Values(AbsExact().to_compare_f()),
+// Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(CmpPerfTestFluid, CmpPerfTest,
+// Combine(Values(CMP_EQ, CMP_GE, CMP_NE, CMP_GT, CMP_LT, CMP_LE),
+// Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(cv::compile_args(CORE_FLUID))));
+
+INSTANTIATE_TEST_CASE_P(CmpWithScalarPerfTestFluid, CmpWithScalarPerfTest,
+ Combine(Values(AbsSimilarPoints(1, 0.01).to_compare_f()),
+ Values(CMP_EQ, CMP_GE, CMP_NE, CMP_GT, CMP_LT, CMP_LE),
+ Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(CV_8UC1, CV_8UC3, CV_16SC1, CV_32FC1),
+ Values(cv::compile_args(CORE_FLUID))));
+
+INSTANTIATE_TEST_CASE_P(BitwisePerfTestFluid, BitwisePerfTest,
+ Combine(Values(AND, OR, XOR),
+ testing::Bool(),
+ Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
+ Values(cv::compile_args(CORE_FLUID))));
+
+INSTANTIATE_TEST_CASE_P(BitwiseNotPerfTestFluid, BitwiseNotPerfTest,
+ Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
+ Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(SelectPerfTestFluid, SelectPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(MinPerfTestFluid, MinPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(MaxPerfTestFluid, MaxPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(cv::compile_args(CORE_FLUID))));
+
+INSTANTIATE_TEST_CASE_P(AbsDiffPerfTestFluid, AbsDiffPerfTest,
+ Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+ Values(cv::compile_args(CORE_FLUID))));
+
+INSTANTIATE_TEST_CASE_P(AbsDiffCPerfTestFluid, AbsDiffCPerfTest,
+ Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
+ Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(SumPerfTestFluid, SumPerfTest,
+// Combine(Values(AbsToleranceScalar(0.0).to_compare_f()),
+// Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// //Values(0.0),
+// Values(cv::compile_args(CORE_FLUID))));
+
+INSTANTIATE_TEST_CASE_P(AddWeightedPerfTestFluid, AddWeightedPerfTest,
+ Combine(Values(Tolerance_FloatRel_IntAbs(1e-6, 1).to_compare_f()),
+ Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
+ Values(-1, CV_8U, CV_32F),
+ Values(cv::compile_args(CORE_FLUID))));
+
+INSTANTIATE_TEST_CASE_P(AddWeightedPerfTestFluid_short, AddWeightedPerfTest,
+ Combine(Values(Tolerance_FloatRel_IntAbs(1e-6, 1).to_compare_f()),
+ Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(CV_16UC1, CV_16SC1),
+ Values(-1),
+ Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(NormPerfTestFluid, NormPerfTest,
+// Combine(Values(AbsToleranceScalar(0.0).to_compare_f()),
+// Values(NORM_INF, NORM_L1, NORM_L2),
+// Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(IntegralPerfTestFluid, IntegralPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(ThresholdPerfTestFluid, ThresholdPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(cv::THRESH_BINARY, cv::THRESH_BINARY_INV, cv::THRESH_TRUNC, cv::THRESH_TOZERO, cv::THRESH_TOZERO_INV),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(ThresholdPerfTestFluid, ThresholdOTPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1),
+// Values(cv::THRESH_OTSU, cv::THRESH_TRIANGLE),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(InRangePerfTestFluid, InRangePerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1),
+// Values(cv::compile_args(CORE_FLUID))));
+
+INSTANTIATE_TEST_CASE_P(Split3PerfTestFluid, Split3PerfTest,
+ Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(Split4PerfTestFluid, Split4PerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(Merge3PerfTestFluid, Merge3PerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(Merge4PerfTestFluid, Merge4PerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(RemapPerfTestFluid, RemapPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(FlipPerfTestFluid, FlipPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(0, 1, -1),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(CropPerfTestFluid, CropPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(cv::Rect(10, 8, 20, 35), cv::Rect(4, 10, 37, 50)),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(CopyPerfTestFluid, CopyPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(ConcatHorPerfTestFluid, ConcatHorPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(ConcatHorVecPerfTestFluid, ConcatHorVecPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(ConcatVertPerfTestFluid, ConcatVertPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(ConcatVertVecPerfTestFluid, ConcatVertVecPerfTest,
+// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(LUTPerfTestFluid, LUTPerfTest,
+// Combine(Values(CV_8UC1, CV_8UC3),
+// Values(CV_8UC1),
+// Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(cv::compile_args(CORE_FLUID))));
+
+// INSTANTIATE_TEST_CASE_P(LUTPerfTestCustomFluid, LUTPerfTest,
+// Combine(Values(CV_8UC3),
+// Values(CV_8UC3),
+// Values(szSmall128, szVGA, sz720p, sz1080p),
+// Values(cv::compile_args(CORE_FLUID))));
+
+INSTANTIATE_TEST_CASE_P(ConvertToPerfTestFluid, ConvertToPerfTest,
+ Combine(Values(Tolerance_FloatRel_IntAbs(1e-5, 2).to_compare_f()),
+ Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1),
+ Values(CV_8U, CV_16U, CV_16S, CV_32F),
+ Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(2.5, 1.0),
+ Values(0.0),
+ Values(cv::compile_args(CORE_FLUID))));
+
+INSTANTIATE_TEST_CASE_P(ResizePerfTestFluid, ResizePerfTest,
+ Combine(Values(AbsExact().to_compare_f()),
+ Values(CV_8UC3/*CV_8UC1, CV_16UC1, CV_16SC1*/),
+ Values(/*cv::INTER_NEAREST,*/ cv::INTER_LINEAR/*, cv::INTER_AREA*/),
+ Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(cv::Size(64, 64),
+ cv::Size(30, 30)),
+ Values(cv::compile_args(CORE_FLUID))));
+
+INSTANTIATE_TEST_CASE_P(ResizeFxFyPerfTestFluid, ResizeFxFyPerfTest,
+ Combine(Values(AbsExact().to_compare_f()),
+ Values(CV_8UC3/*CV_8UC1, CV_16UC1, CV_16SC1*/),
+ Values(/*cv::INTER_NEAREST,*/ cv::INTER_LINEAR/*, cv::INTER_AREA*/),
+ Values(szSmall128, szVGA, sz720p, sz1080p),
+ Values(0.5, 0.1),
+ Values(0.5, 0.1),
+ Values(cv::compile_args(CORE_FLUID))));
+} // opencv_test
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#include "../perf_precomp.hpp"
Values(1, 2),
Values(cv::compile_args(IMGPROC_CPU))));
+INSTANTIATE_TEST_CASE_P(LaplacianPerfTestCPU, LaplacianPerfTest,
+ Combine(Values(AbsExact().to_compare_f()),
+ Values(CV_8UC1, CV_8UC3),
+ Values(3),
+ Values(szVGA, sz720p, sz1080p),
+ Values(-1),
+ Values(cv::compile_args(IMGPROC_CPU))));
+
+INSTANTIATE_TEST_CASE_P(BilateralFilterPerfTestCPU, BilateralFilterPerfTest,
+ Combine(Values(AbsExact().to_compare_f()),
+ Values(CV_32FC1, CV_32FC3),
+ Values(-1),
+ Values(szVGA, sz720p, sz1080p),
+ Values(3),
+ Values(20),
+ Values(10),
+ Values(cv::compile_args(IMGPROC_CPU))));
+
INSTANTIATE_TEST_CASE_P(CannyPerfTestCPU, CannyPerfTest,
Combine(Values(AbsExact().to_compare_f()),
Values(CV_8UC1, CV_8UC3),
Values(true, false),
Values(cv::compile_args(IMGPROC_CPU))));
+INSTANTIATE_TEST_CASE_P(GoodFeaturesPerfTestCPU, GoodFeaturesPerfTest,
+ Combine(Values(AbsExactVector<cv::Point2f>().to_compare_f()),
+ Values("cv/shared/pic5.png", "stitching/a1.png"),
+ Values(CV_32FC1, CV_8UC1),
+ Values(100, 500),
+ Values(0.1, 0.01),
+ Values(1.0),
+ Values(3, 5),
+ Values(true, false),
+ Values(cv::compile_args(IMGPROC_CPU))));
+
+INSTANTIATE_TEST_CASE_P(GoodFeaturesInternalPerfTestCPU, GoodFeaturesPerfTest,
+ Combine(Values(AbsExactVector<cv::Point2f>().to_compare_f()),
+ Values("cv/cascadeandhog/images/audrybt1.png"),
+ Values(CV_32FC1, CV_8UC1),
+ Values(100),
+ Values(0.0000001),
+ Values(5.0),
+ Values(3),
+ Values(true),
+ Values(cv::compile_args(IMGPROC_CPU))));
+
INSTANTIATE_TEST_CASE_P(EqHistPerfTestCPU, EqHistPerfTest,
Combine(Values(AbsExact().to_compare_f()),
Values(szVGA, sz720p, sz1080p),
Combine(Values(ToleranceColor(1e-3).to_compare_f()),
Values(szVGA, sz720p, sz1080p),
Values(cv::compile_args(IMGPROC_CPU))));
-}
+} // opencv_test
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#include "../perf_precomp.hpp"
+
+#include "../common/gapi_video_perf_tests.hpp"
+#include <opencv2/gapi/cpu/video.hpp>
+
+namespace
+{
+#define VIDEO_CPU cv::gapi::video::cpu::kernels()
+
+#ifdef HAVE_OPENCV_VIDEO
+#define WITH_VIDEO(X) X
+#else
+#define WITH_VIDEO(X) DISABLED_##X
+#endif // HAVE_OPENCV_VIDEO
+
+#define INSTANTIATE_TEST_CASE_MACRO_P(prefix, test_case_name, generator, ...) \
+ INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, __VA_ARGS__)
+} // namespace
+
+
+namespace opencv_test
+{
+INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildOptFlowPyramidPerfTestCPU),
+ BuildOptFlowPyramidPerfTest,
+ Combine(Values("cv/optflow/rock_1.bmp",
+ "cv/optflow/frames/1080p_01.png"),
+ Values(7, 11),
+ Values(1000),
+ testing::Bool(),
+ Values(BORDER_DEFAULT, BORDER_TRANSPARENT),
+ Values(BORDER_DEFAULT, BORDER_TRANSPARENT),
+ testing::Bool(),
+ Values(cv::compile_args(VIDEO_CPU))));
+
+INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildOptFlowPyramidInternalPerfTestCPU),
+ BuildOptFlowPyramidPerfTest,
+ Combine(Values("cv/optflow/rock_1.bmp"),
+ Values(15),
+ Values(3),
+ Values(true),
+ Values(BORDER_REFLECT_101),
+ Values(BORDER_CONSTANT),
+ Values(true),
+ Values(cv::compile_args(VIDEO_CPU))));
+
+INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(OptFlowLKPerfTestCPU), OptFlowLKPerfTest,
+ Combine(Values("cv/optflow/rock_%01d.bmp",
+ "cv/optflow/frames/1080p_%02d.png"),
+ Values(1, 3, 4),
+ Values(std::make_tuple(9, 9), std::make_tuple(15, 15)),
+ Values(7, 11),
+ Values(cv::TermCriteria(cv::TermCriteria::COUNT |
+ cv::TermCriteria::EPS,
+ 30, 0.01)),
+ Values(cv::compile_args(VIDEO_CPU))));
+
+INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(OptFlowLKForPyrPerfTestCPU), OptFlowLKForPyrPerfTest,
+ Combine(Values("cv/optflow/rock_%01d.bmp",
+ "cv/optflow/frames/1080p_%02d.png"),
+ Values(1, 3, 4),
+ Values(std::make_tuple(9, 9), std::make_tuple(15, 15)),
+ Values(7, 11),
+ Values(cv::TermCriteria(cv::TermCriteria::COUNT |
+ cv::TermCriteria::EPS,
+ 30, 0.01)),
+ Values(true, false),
+ Values(cv::compile_args(VIDEO_CPU))));
+
+INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(OptFlowLKInternalPerfTestCPU),
+ OptFlowLKForPyrPerfTest,
+ Combine(Values("cv/optflow/rock_%01d.bmp"),
+ Values(1),
+ Values(std::make_tuple(10, 10)),
+ Values(15),
+ Values(cv::TermCriteria(cv::TermCriteria::COUNT |
+ cv::TermCriteria::EPS,
+ 21, 0.05)),
+ Values(true),
+ Values(cv::compile_args(VIDEO_CPU))));
+
+INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildPyr_CalcOptFlow_PipelinePerfTestCPU),
+ BuildPyr_CalcOptFlow_PipelinePerfTest,
+ Combine(Values("cv/optflow/frames/1080p_%02d.png"),
+ Values(7, 11),
+ Values(1000),
+ Values(true, false),
+ Values(cv::compile_args(VIDEO_CPU))));
+
+INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildPyr_CalcOptFlow_PipelineInternalTestPerfCPU),
+ BuildPyr_CalcOptFlow_PipelinePerfTest,
+ Combine(Values("cv/optflow/rock_%01d.bmp"),
+ Values(15),
+ Values(3),
+ Values(true),
+ Values(cv::compile_args(VIDEO_CPU))));
+} // opencv_test
Values( -1, CV_8U, CV_16U, CV_32F ),
Values(cv::compile_args(CORE_GPU))));
//TODO: mask test doesn't work
-#if 0
-INSTANTIATE_TEST_CASE_P(MaskPerfTestGPU, MaskPerfTest,
+INSTANTIATE_TEST_CASE_P(DISABLED_MaskPerfTestGPU, MaskPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::compile_args(CORE_GPU))));
-#endif
INSTANTIATE_TEST_CASE_P(MeanPerfTestGPU, MeanPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values(cv::compile_args(CORE_GPU))));
INSTANTIATE_TEST_CASE_P(CmpWithScalarPerfTestGPU, CmpWithScalarPerfTest,
- Combine(Values(CMP_EQ, CMP_GE, CMP_NE, CMP_GT, CMP_LT, CMP_LE),
+ Combine(Values(AbsExact().to_compare_f()),
+ Values(CMP_EQ, CMP_GE, CMP_NE, CMP_GT, CMP_LT, CMP_LE),
Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::compile_args(CORE_GPU))));
INSTANTIATE_TEST_CASE_P(BitwisePerfTestGPU, BitwisePerfTest,
Combine(Values(AND, OR, XOR),
+ testing::Bool(),
Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
Values(cv::compile_args(CORE_GPU))));
Values(cv::compile_args(CORE_GPU))));
//TODO: fix this backend to allow ConcatVertVec ConcatHorVec
-#if 0
-INSTANTIATE_TEST_CASE_P(ConcatHorVecPerfTestGPU, ConcatHorVecPerfTest,
+INSTANTIATE_TEST_CASE_P(DISABLED_ConcatHorVecPerfTestGPU, ConcatHorVecPerfTest,
Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::compile_args(CORE_GPU))));
-INSTANTIATE_TEST_CASE_P(ConcatVertVecPerfTestGPU, ConcatVertVecPerfTest,
+INSTANTIATE_TEST_CASE_P(DISABLED_ConcatVertVecPerfTestGPU, ConcatVertVecPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::compile_args(CORE_GPU))));
-#endif
INSTANTIATE_TEST_CASE_P(LUTPerfTestGPU, LUTPerfTest,
Combine(Values(CV_8UC1, CV_8UC3),
INSTANTIATE_TEST_CASE_P(ConvertToPerfTestGPU, ConvertToPerfTest,
- Combine(Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_32FC1),
+ Combine(Values(AbsExact().to_compare_f()),
+ Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_32FC1),
Values(CV_8U, CV_16U, CV_16S, CV_32F),
Values( szSmall128, szVGA, sz720p, sz1080p ),
+ Values(2.5, 1.0),
+ Values(0.0),
Values(cv::compile_args(CORE_GPU))));
INSTANTIATE_TEST_CASE_P(ResizePerfTestGPU, ResizePerfTest,
Values(1, 2),
Values(cv::compile_args(IMGPROC_GPU))));
+INSTANTIATE_TEST_CASE_P(LaplacianPerfTestGPU, LaplacianPerfTest,
+ Combine(Values(ToleranceFilter(1e-4f, 0.01).to_compare_f()),
+ Values(CV_8UC1, CV_8UC3),
+ Values(5),
+ Values(szVGA, sz720p, sz1080p),
+ Values(-1),
+ Values(cv::compile_args(IMGPROC_GPU))));
+
+INSTANTIATE_TEST_CASE_P(BilateralFilterPerfTestGPU, BilateralFilterPerfTest,
+ Combine(Values(ToleranceFilter(1e-4f, 0.01).to_compare_f()),
+ Values(CV_32FC1, CV_32FC3),
+ Values(-1),
+ Values(szVGA, sz720p, sz1080p),
+ Values(5),
+ Values(100),
+ Values(40),
+ Values(cv::compile_args(IMGPROC_GPU))));
+
INSTANTIATE_TEST_CASE_P(CannyPerfTestGPU, CannyPerfTest,
Combine(Values(AbsSimilarPoints(1, 0.05).to_compare_f()),
Values(CV_8UC1, CV_8UC3),
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef __OPENCV_GAPI_PERF_PRECOMP_HPP__
#include <opencv2/ts.hpp>
#include <opencv2/gapi.hpp>
#include <opencv2/gapi/imgproc.hpp>
+#include <opencv2/gapi/video.hpp>
#include <opencv2/gapi/core.hpp>
#include <opencv2/gapi/cpu/gcpukernel.hpp>
#include <opencv2/gapi/gpu/ggpukernel.hpp>
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#include "../perf_precomp.hpp"
+#include "../common/gapi_render_perf_tests.hpp"
+
+#define RENDER_OCV cv::gapi::render::ocv::kernels()
+
+namespace opencv_test
+{
+
+#ifdef HAVE_FREETYPE
+INSTANTIATE_TEST_CASE_P(RenderTestFTexts, RenderTestFTexts,
+ Combine(Values(L"\xe4\xbd\xa0\xe5\xa5\xbd"),
+ Values(szVGA, sz720p, sz1080p),
+ Values(cv::Point(50, 50)),
+ Values(60),
+ Values(cv::Scalar(200, 100, 25)),
+ Values(cv::compile_args(RENDER_OCV))));
+#endif // HAVE_FREETYPE
+
+INSTANTIATE_TEST_CASE_P(RenderTestTexts, RenderTestTexts,
+ Combine(Values(std::string("Some text")),
+ Values(szVGA, sz720p, sz1080p),
+ Values(cv::Point(200, 200)),
+ Values(FONT_HERSHEY_SIMPLEX),
+ Values(cv::Scalar(0, 255, 0)),
+ Values(2),
+ Values(LINE_8),
+ Values(false),
+ Values(cv::compile_args(RENDER_OCV))));
+
+INSTANTIATE_TEST_CASE_P(RenderTestRects, RenderTestRects,
+ Combine(Values(szVGA, sz720p, sz1080p),
+ Values(cv::Rect(100, 100, 200, 200)),
+ Values(cv::Scalar(100, 50, 150)),
+ Values(2),
+ Values(LINE_8),
+ Values(0),
+ Values(cv::compile_args(RENDER_OCV))));
+
+INSTANTIATE_TEST_CASE_P(RenderTestCircles, RenderTestCircles,
+ Combine(Values(szVGA, sz720p, sz1080p),
+ Values(cv::Point(100, 100)),
+ Values(10),
+ Values(cv::Scalar(100, 50, 150)),
+ Values(2),
+ Values(LINE_8),
+ Values(0),
+ Values(cv::compile_args(RENDER_OCV))));
+
+INSTANTIATE_TEST_CASE_P(RenderTestLines, RenderTestLines,
+ Combine(Values(szVGA, sz720p, sz1080p),
+ Values(cv::Point(100, 100)),
+ Values(cv::Point(200, 200)),
+ Values(cv::Scalar(100, 50, 150)),
+ Values(2),
+ Values(LINE_8),
+ Values(0),
+ Values(cv::compile_args(RENDER_OCV))));
+
+INSTANTIATE_TEST_CASE_P(RenderTestMosaics, RenderTestMosaics,
+ Combine(Values(szVGA, sz720p, sz1080p),
+ Values(cv::Rect(100, 100, 200, 200)),
+ Values(25),
+ Values(0),
+ Values(cv::compile_args(RENDER_OCV))));
+
+INSTANTIATE_TEST_CASE_P(RenderTestImages, RenderTestImages,
+ Combine(Values(szVGA, sz720p, sz1080p),
+ Values(cv::Rect(50, 50, 100, 100)),
+ Values(cv::Scalar(100, 150, 60)),
+ Values(1.0),
+ Values(cv::compile_args(RENDER_OCV))));
+
+INSTANTIATE_TEST_CASE_P(RenderTestPolylines, RenderTestPolylines,
+ Combine(Values(szVGA, sz720p, sz1080p),
+ Values(std::vector<cv::Point>{{100, 100}, {200, 200}, {150, 300}, {400, 150}}),
+ Values(cv::Scalar(100, 150, 60)),
+ Values(2),
+ Values(LINE_8),
+ Values(0),
+ Values(cv::compile_args(RENDER_OCV))));
+
+INSTANTIATE_TEST_CASE_P(RenderTestPolyItems, RenderTestPolyItems,
+ Combine(Values(szVGA, sz720p, sz1080p),
+ Values(50),
+ Values(50),
+ Values(50),
+ Values(cv::compile_args(RENDER_OCV))));
+}
--- /dev/null
+#include <opencv2/gapi.hpp>
+#include <opencv2/gapi/core.hpp>
+#include <opencv2/gapi/cpu/core.hpp>
+
+int main(int argc, char *argv[])
+{
+ (void) argc;
+ (void) argv;
+
+ bool need_first_conversion = true;
+ bool need_second_conversion = false;
+
+ cv::Size szOut(4, 4);
+ cv::GComputation cc([&](){
+// ! [GIOProtoArgs usage]
+ auto ins = cv::GIn();
+ cv::GMat in1;
+ if (need_first_conversion)
+ ins += cv::GIn(in1);
+
+ cv::GMat in2;
+ if (need_second_conversion)
+ ins += cv::GIn(in2);
+
+ auto outs = cv::GOut();
+ cv::GMat out1 = cv::gapi::resize(in1, szOut);
+ if (need_first_conversion)
+ outs += cv::GOut(out1);
+
+ cv::GMat out2 = cv::gapi::resize(in2, szOut);
+ if (need_second_conversion)
+ outs += cv::GOut(out2);
+// ! [GIOProtoArgs usage]
+ return cv::GComputation(std::move(ins), std::move(outs));
+ });
+
+// ! [GRunArgs usage]
+ auto in_vector = cv::gin();
+
+ cv::Mat in_mat1( 8, 8, CV_8UC3);
+ cv::Mat in_mat2(16, 16, CV_8UC3);
+ cv::randu(in_mat1, cv::Scalar::all(0), cv::Scalar::all(255));
+ cv::randu(in_mat2, cv::Scalar::all(0), cv::Scalar::all(255));
+
+ if (need_first_conversion)
+ in_vector += cv::gin(in_mat1);
+ if (need_second_conversion)
+ in_vector += cv::gin(in_mat2);
+// ! [GRunArgs usage]
+
+// ! [GRunArgsP usage]
+ auto out_vector = cv::gout();
+ cv::Mat out_mat1, out_mat2;
+ if (need_first_conversion)
+ out_vector += cv::gout(out_mat1);
+ if (need_second_conversion)
+ out_vector += cv::gout(out_mat2);
+// ! [GRunArgsP usage]
+
+ auto stream = cc.compileStreaming(cv::compile_args(cv::gapi::core::cpu::kernels()));
+ stream.setSource(std::move(in_vector));
+
+ stream.start();
+ stream.pull(std::move(out_vector));
+ stream.stop();
+
+ return 0;
+}
--- /dev/null
+#include <algorithm>
+#include <iostream>
+#include <cctype>
+
+#include <opencv2/gapi.hpp>
+#include <opencv2/gapi/core.hpp>
+#include <opencv2/gapi/infer.hpp>
+#include <opencv2/gapi/infer/ie.hpp>
+#include <opencv2/gapi/streaming/cap.hpp>
+#include <opencv2/gapi/cpu/gcpukernel.hpp>
+#include <opencv2/highgui.hpp> // CommandLineParser
+
+const std::string about =
+ "This is an OpenCV-based version of Gaze Estimation example";
+const std::string keys =
+ "{ h help | | Print this help message }"
+ "{ input | | Path to the input video file }"
+ "{ facem | face-detection-retail-0005.xml | Path to OpenVINO face detection model (.xml) }"
+ "{ faced | CPU | Target device for the face detection (e.g. CPU, GPU, VPU, ...) }"
+ "{ landm | facial-landmarks-35-adas-0002.xml | Path to OpenVINO landmarks detector model (.xml) }"
+ "{ landd | CPU | Target device for the landmarks detector (e.g. CPU, GPU, VPU, ...) }"
+ "{ headm | head-pose-estimation-adas-0001.xml | Path to OpenVINO head pose estimation model (.xml) }"
+ "{ headd | CPU | Target device for the head pose estimation inference (e.g. CPU, GPU, VPU, ...) }"
+ "{ gazem | gaze-estimation-adas-0002.xml | Path to OpenVINO gaze vector estimaiton model (.xml) }"
+ "{ gazed | CPU | Target device for the gaze vector estimation inference (e.g. CPU, GPU, VPU, ...) }"
+ ;
+
+namespace {
+std::string weights_path(const std::string &model_path) {
+ const auto EXT_LEN = 4u;
+ const auto sz = model_path.size();
+ CV_Assert(sz > EXT_LEN);
+
+ auto ext = model_path.substr(sz - EXT_LEN);
+ auto lower = [](unsigned char c) {
+ return static_cast<unsigned char>(std::tolower(c));
+ };
+ std::transform(ext.begin(), ext.end(), ext.begin(), lower);
+ CV_Assert(ext == ".xml");
+ return model_path.substr(0u, sz - EXT_LEN) + ".bin";
+}
+} // anonymous namespace
+
+namespace custom {
+namespace {
+using GMat3 = std::tuple<cv::GMat,cv::GMat,cv::GMat>;
+using GMats = cv::GArray<cv::GMat>;
+using GRects = cv::GArray<cv::Rect>;
+using GSize = cv::GOpaque<cv::Size>;
+G_API_NET(Faces, <cv::GMat(cv::GMat)>, "face-detector" );
+G_API_NET(Landmarks, <cv::GMat(cv::GMat)>, "facial-landmarks");
+G_API_NET(HeadPose, < GMat3(cv::GMat)>, "head-pose");
+G_API_NET(Gaze, <cv::GMat(cv::GMat,cv::GMat,cv::GMat)>, "gaze-vector");
+
+G_API_OP(Size, <GSize(cv::GMat)>, "custom.gapi.size") {
+ static cv::GOpaqueDesc outMeta(const cv::GMatDesc &) {
+ return cv::empty_gopaque_desc();
+ }
+};
+
+G_API_OP(ParseSSD,
+ <GRects(cv::GMat, GSize, bool)>,
+ "custom.gaze_estimation.parseSSD") {
+ static cv::GArrayDesc outMeta( const cv::GMatDesc &
+ , const cv::GOpaqueDesc &
+ , bool) {
+ return cv::empty_array_desc();
+ }
+};
+
+// Left/Right eye per every face
+G_API_OP(ParseEyes,
+ <std::tuple<GRects, GRects>(GMats, GRects, GSize)>,
+ "custom.gaze_estimation.parseEyes") {
+ static std::tuple<cv::GArrayDesc, cv::GArrayDesc>
+ outMeta( const cv::GArrayDesc &
+ , const cv::GArrayDesc &
+ , const cv::GOpaqueDesc &) {
+ return std::make_tuple(cv::empty_array_desc(), cv::empty_array_desc());
+ }
+};
+
+// Combine three scalars into a 1x3 vector (per every face)
+G_API_OP(ProcessPoses,
+ <GMats(GMats, GMats, GMats)>,
+ "custom.gaze_estimation.processPoses") {
+ static cv::GArrayDesc outMeta( const cv::GArrayDesc &
+ , const cv::GArrayDesc &
+ , const cv::GArrayDesc &) {
+ return cv::empty_array_desc();
+ }
+};
+
+void adjustBoundingBox(cv::Rect& boundingBox) {
+ auto w = boundingBox.width;
+ auto h = boundingBox.height;
+
+ boundingBox.x -= static_cast<int>(0.067 * w);
+ boundingBox.y -= static_cast<int>(0.028 * h);
+
+ boundingBox.width += static_cast<int>(0.15 * w);
+ boundingBox.height += static_cast<int>(0.13 * h);
+
+ if (boundingBox.width < boundingBox.height) {
+ auto dx = (boundingBox.height - boundingBox.width);
+ boundingBox.x -= dx / 2;
+ boundingBox.width += dx;
+ } else {
+ auto dy = (boundingBox.width - boundingBox.height);
+ boundingBox.y -= dy / 2;
+ boundingBox.height += dy;
+ }
+}
+
+void gazeVectorToGazeAngles(const cv::Point3f& gazeVector,
+ cv::Point2f& gazeAngles) {
+ auto r = cv::norm(gazeVector);
+
+ double v0 = static_cast<double>(gazeVector.x);
+ double v1 = static_cast<double>(gazeVector.y);
+ double v2 = static_cast<double>(gazeVector.z);
+
+ gazeAngles.x = static_cast<float>(180.0 / M_PI * (M_PI_2 + std::atan2(v2, v0)));
+ gazeAngles.y = static_cast<float>(180.0 / M_PI * (M_PI_2 - std::acos(v1 / r)));
+}
+
+GAPI_OCV_KERNEL(OCVSize, Size) {
+ static void run(const cv::Mat &in, cv::Size &out) {
+ out = in.size();
+ }
+};
+
+GAPI_OCV_KERNEL(OCVParseSSD, ParseSSD) {
+ static void run(const cv::Mat &in_ssd_result,
+ const cv::Size &upscale,
+ const bool filter_out_of_bounds,
+ std::vector<cv::Rect> &out_objects) {
+ const auto &in_ssd_dims = in_ssd_result.size;
+ CV_Assert(in_ssd_dims.dims() == 4u);
+
+ const int MAX_PROPOSALS = in_ssd_dims[2];
+ const int OBJECT_SIZE = in_ssd_dims[3];
+ CV_Assert(OBJECT_SIZE == 7); // fixed SSD object size
+
+ const cv::Rect surface({0,0}, upscale);
+ out_objects.clear();
+
+ const float *data = in_ssd_result.ptr<float>();
+ for (int i = 0; i < MAX_PROPOSALS; i++) {
+ const float image_id = data[i * OBJECT_SIZE + 0];
+ const float label = data[i * OBJECT_SIZE + 1];
+ const float confidence = data[i * OBJECT_SIZE + 2];
+ const float rc_left = data[i * OBJECT_SIZE + 3];
+ const float rc_top = data[i * OBJECT_SIZE + 4];
+ const float rc_right = data[i * OBJECT_SIZE + 5];
+ const float rc_bottom = data[i * OBJECT_SIZE + 6];
+ (void) label;
+ if (image_id < 0.f) {
+ break; // marks end-of-detections
+ }
+ if (confidence < 0.5f) {
+ continue; // skip objects with low confidence
+ }
+ cv::Rect rc; // map relative coordinates to the original image scale
+ rc.x = static_cast<int>(rc_left * upscale.width);
+ rc.y = static_cast<int>(rc_top * upscale.height);
+ rc.width = static_cast<int>(rc_right * upscale.width) - rc.x;
+ rc.height = static_cast<int>(rc_bottom * upscale.height) - rc.y;
+ adjustBoundingBox(rc); // TODO: new option?
+
+ const auto clipped_rc = rc & surface; // TODO: new option?
+ if (filter_out_of_bounds) {
+ if (clipped_rc.area() != rc.area()) {
+ continue;
+ }
+ }
+ out_objects.emplace_back(clipped_rc);
+ }
+ }
+};
+
+cv::Rect eyeBox(const cv::Rect &face_rc,
+ float p1_x, float p1_y, float p2_x, float p2_y,
+ float scale = 1.8f) {
+ const auto &up = face_rc.size();
+ const cv::Point p1 = {
+ static_cast<int>(p1_x*up.width),
+ static_cast<int>(p1_y*up.height)
+ };
+ const cv::Point p2 = {
+ static_cast<int>(p2_x*up.width),
+ static_cast<int>(p2_y*up.height)
+ };
+ cv::Rect result;
+
+ const auto size = static_cast<float>(cv::norm(p1 - p2));
+ const auto midpoint = (p1 + p2) / 2;
+
+ result.width = static_cast<int>(scale * size);
+ result.height = result.width;
+ result.x = face_rc.x + midpoint.x - (result.width / 2);
+ result.y = face_rc.y + midpoint.y - (result.height / 2);
+ // Shift result to the original frame's absolute coordinates
+ return result;
+}
+
+GAPI_OCV_KERNEL(OCVParseEyes, ParseEyes) {
+ static void run(const std::vector<cv::Mat> &in_landmarks_per_face,
+ const std::vector<cv::Rect> &in_face_rcs,
+ const cv::Size &frame_size,
+ std::vector<cv::Rect> &out_left_eyes,
+ std::vector<cv::Rect> &out_right_eyes) {
+ const size_t numFaces = in_landmarks_per_face.size();
+ const cv::Rect surface(cv::Point(0,0), frame_size);
+ GAPI_Assert(numFaces == in_face_rcs.size());
+ out_left_eyes.clear();
+ out_right_eyes.clear();
+ out_left_eyes.reserve(numFaces);
+ out_right_eyes.reserve(numFaces);
+
+ for (std::size_t i = 0u; i < numFaces; i++) {
+ const auto &lm = in_landmarks_per_face[i];
+ const auto &rc = in_face_rcs[i];
+ // Left eye is defined by points 0/1 (x2),
+ // Right eye is defined by points 2/3 (x2)
+ const float *data = lm.ptr<float>();
+ out_left_eyes .push_back(surface & eyeBox(rc, data[0], data[1], data[2], data[3]));
+ out_right_eyes.push_back(surface & eyeBox(rc, data[4], data[5], data[6], data[7]));
+ }
+ }
+};
+
+GAPI_OCV_KERNEL(OCVProcessPoses, ProcessPoses) {
+ static void run(const std::vector<cv::Mat> &in_ys,
+ const std::vector<cv::Mat> &in_ps,
+ const std::vector<cv::Mat> &in_rs,
+ std::vector<cv::Mat> &out_poses) {
+ const std::size_t sz = in_ys.size();
+ GAPI_Assert(sz == in_ps.size() && sz == in_rs.size());
+ out_poses.clear();
+ for (std::size_t idx = 0u; idx < sz; idx++) {
+ cv::Mat pose(1, 3, CV_32FC1);
+ float *ptr = pose.ptr<float>();
+ ptr[0] = in_ys[idx].ptr<float>()[0];
+ ptr[1] = in_ps[idx].ptr<float>()[0];
+ ptr[2] = in_rs[idx].ptr<float>()[0];
+ out_poses.push_back(std::move(pose));
+ }
+ }
+};
+} // anonymous namespace
+} // namespace custom
+
+namespace vis {
+namespace {
+cv::Point2f midp(const cv::Rect &rc) {
+ return (rc.tl() + rc.br()) / 2;
+};
+void bbox(cv::Mat &m, const cv::Rect &rc) {
+ cv::rectangle(m, rc, cv::Scalar{0,255,0}, 2, cv::LINE_8, 0);
+};
+void pose(cv::Mat &m, const cv::Mat &p, const cv::Rect &face_rc) {
+ const auto *posePtr = p.ptr<float>();
+ const auto yaw = static_cast<double>(posePtr[0]);
+ const auto pitch = static_cast<double>(posePtr[1]);
+ const auto roll = static_cast<double>(posePtr[2]);
+
+ const auto sinY = std::sin(yaw * M_PI / 180.0);
+ const auto sinP = std::sin(pitch * M_PI / 180.0);
+ const auto sinR = std::sin(roll * M_PI / 180.0);
+
+ const auto cosY = std::cos(yaw * M_PI / 180.0);
+ const auto cosP = std::cos(pitch * M_PI / 180.0);
+ const auto cosR = std::cos(roll * M_PI / 180.0);
+
+ const auto axisLength = 0.4 * face_rc.width;
+ const auto xCenter = face_rc.x + face_rc.width / 2;
+ const auto yCenter = face_rc.y + face_rc.height / 2;
+
+ const auto center = cv::Point{xCenter, yCenter};
+ const auto axisln = cv::Point2d{axisLength, axisLength};
+ const auto ctr = cv::Matx<double,2,2>(cosR*cosY, sinY*sinP*sinR, 0.f, cosP*sinR);
+ const auto ctt = cv::Matx<double,2,2>(cosR*sinY*sinP, cosY*sinR, 0.f, -cosP*cosR);
+ const auto ctf = cv::Matx<double,2,2>(sinY*cosP, 0.f, 0.f, sinP);
+
+ // center to right
+ cv::line(m, center, center + static_cast<cv::Point>(ctr*axisln), cv::Scalar(0, 0, 255), 2);
+ // center to top
+ cv::line(m, center, center + static_cast<cv::Point>(ctt*axisln), cv::Scalar(0, 255, 0), 2);
+ // center to forward
+ cv::line(m, center, center + static_cast<cv::Point>(ctf*axisln), cv::Scalar(255, 0, 255), 2);
+}
+void vvec(cv::Mat &m, const cv::Mat &v, const cv::Rect &face_rc,
+ const cv::Rect &left_rc, const cv::Rect &right_rc) {
+ const auto scale = 0.002 * face_rc.width;
+
+ cv::Point3f gazeVector;
+ const auto *gazePtr = v.ptr<float>();
+ gazeVector.x = gazePtr[0];
+ gazeVector.y = gazePtr[1];
+ gazeVector.z = gazePtr[2];
+ gazeVector = gazeVector / cv::norm(gazeVector);
+
+ const double arrowLength = 0.4 * face_rc.width;
+ const auto left_mid = midp(left_rc);
+ const auto right_mid = midp(right_rc);
+
+ cv::Point2f gazeArrow;
+ gazeArrow.x = gazeVector.x;
+ gazeArrow.y = -gazeVector.y;
+ gazeArrow *= arrowLength;
+
+ cv::arrowedLine(m, left_mid, left_mid + gazeArrow, cv::Scalar(255, 0, 0), 2);
+ cv::arrowedLine(m, right_mid, right_mid + gazeArrow, cv::Scalar(255, 0, 0), 2);
+
+ cv::Point2f gazeAngles;
+ custom::gazeVectorToGazeAngles(gazeVector, gazeAngles);
+
+ cv::putText(m,
+ cv::format("gaze angles: (h=%0.0f, v=%0.0f)",
+ static_cast<double>(std::round(gazeAngles.x)),
+ static_cast<double>(std::round(gazeAngles.y))),
+ cv::Point(static_cast<int>(face_rc.tl().x),
+ static_cast<int>(face_rc.br().y + 12. * face_rc.width / 100.)),
+ cv::FONT_HERSHEY_PLAIN, scale * 2, cv::Scalar::all(255), 1);
+};
+} // anonymous namespace
+} // namespace vis
+
+int main(int argc, char *argv[])
+{
+ cv::CommandLineParser cmd(argc, argv, keys);
+ cmd.about(about);
+ if (cmd.has("help")) {
+ cmd.printMessage();
+ return 0;
+ }
+
+ cv::GMat in;
+ cv::GMat faces = cv::gapi::infer<custom::Faces>(in);
+ cv::GOpaque<cv::Size> sz = custom::Size::on(in); // FIXME
+ cv::GArray<cv::Rect> faces_rc = custom::ParseSSD::on(faces, sz, true);
+ cv::GArray<cv::GMat> angles_y, angles_p, angles_r;
+ std::tie(angles_y, angles_p, angles_r) = cv::gapi::infer<custom::HeadPose>(faces_rc, in);
+ cv::GArray<cv::GMat> heads_pos = custom::ProcessPoses::on(angles_y, angles_p, angles_r);
+ cv::GArray<cv::GMat> landmarks = cv::gapi::infer<custom::Landmarks>(faces_rc, in);
+ cv::GArray<cv::Rect> left_eyes, right_eyes;
+ std::tie(left_eyes, right_eyes) = custom::ParseEyes::on(landmarks, faces_rc, sz);
+ cv::GArray<cv::GMat> gaze_vectors = cv::gapi::infer2<custom::Gaze>( in
+ , left_eyes
+ , right_eyes
+ , heads_pos);
+ cv::GComputation graph(cv::GIn(in),
+ cv::GOut( cv::gapi::copy(in)
+ , faces_rc
+ , left_eyes
+ , right_eyes
+ , heads_pos
+ , gaze_vectors));
+
+ const auto input_file_name = cmd.get<std::string>("input");
+ const auto face_model_path = cmd.get<std::string>("facem");
+ const auto head_model_path = cmd.get<std::string>("headm");
+ const auto lmrk_model_path = cmd.get<std::string>("landm");
+ const auto gaze_model_path = cmd.get<std::string>("gazem");
+
+ auto face_net = cv::gapi::ie::Params<custom::Faces> {
+ face_model_path, // path to topology IR
+ weights_path(face_model_path), // path to weights
+ cmd.get<std::string>("faced"), /// device specifier
+ };
+ auto head_net = cv::gapi::ie::Params<custom::HeadPose> {
+ head_model_path, // path to topology IR
+ weights_path(head_model_path), // path to weights
+ cmd.get<std::string>("headd"), // device specifier
+ }.cfgOutputLayers({"angle_y_fc", "angle_p_fc", "angle_r_fc"});
+ auto landmarks_net = cv::gapi::ie::Params<custom::Landmarks> {
+ lmrk_model_path, // path to topology IR
+ weights_path(lmrk_model_path), // path to weights
+ cmd.get<std::string>("landd"), // device specifier
+ };
+ auto gaze_net = cv::gapi::ie::Params<custom::Gaze> {
+ gaze_model_path, // path to topology IR
+ weights_path(gaze_model_path), // path to weights
+ cmd.get<std::string>("gazed"), // device specifier
+ }.cfgInputLayers({"left_eye_image", "right_eye_image", "head_pose_angles"});
+
+ auto kernels = cv::gapi::kernels< custom::OCVSize
+ , custom::OCVParseSSD
+ , custom::OCVParseEyes
+ , custom::OCVProcessPoses>();
+ auto networks = cv::gapi::networks(face_net, head_net, landmarks_net, gaze_net);
+ auto pipeline = graph.compileStreaming(cv::compile_args(networks, kernels));
+
+ cv::TickMeter tm;
+ cv::Mat image;
+ std::vector<cv::Rect> out_faces, out_right_eyes, out_left_eyes;
+ std::vector<cv::Mat> out_poses;
+ std::vector<cv::Mat> out_gazes;
+ std::size_t frames = 0u;
+ std::cout << "Reading " << input_file_name << std::endl;
+
+ pipeline.setSource(cv::gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(input_file_name));
+ pipeline.start();
+ tm.start();
+ while (pipeline.pull(cv::gout( image
+ , out_faces
+ , out_left_eyes
+ , out_right_eyes
+ , out_poses
+ , out_gazes))) {
+ frames++;
+ // Visualize results on the frame
+ for (auto &&rc : out_faces) vis::bbox(image, rc);
+ for (auto &&rc : out_left_eyes) vis::bbox(image, rc);
+ for (auto &&rc : out_right_eyes) vis::bbox(image, rc);
+ for (std::size_t i = 0u; i < out_faces.size(); i++) {
+ vis::pose(image, out_poses[i], out_faces[i]);
+ vis::vvec(image, out_gazes[i], out_faces[i], out_left_eyes[i], out_right_eyes[i]);
+ }
+ tm.stop();
+ const auto fps_str = std::to_string(frames / tm.getTimeSec()) + " FPS";
+ cv::putText(image, fps_str, {0,32}, cv::FONT_HERSHEY_SIMPLEX, 1.0, {0,255,0}, 2);
+ cv::imshow("Out", image);
+ cv::waitKey(1);
+ tm.start();
+ }
+ tm.stop();
+ std::cout << "Processed " << frames << " frames"
+ << " (" << frames / tm.getTimeSec() << " FPS)" << std::endl;
+ return 0;
+}
"{ input | | Path to the input video file }"
"{ platm | vehicle-license-plate-detection-barrier-0106.xml | Path to OpenVINO IE vehicle/plate detection model (.xml) }"
"{ platd | CPU | Target device for vehicle/plate detection model (e.g. CPU, GPU, VPU, ...) }"
- "{ facem | face-detection-adas-0001.xml | Path to OpenVINO IE face detection model (.xml) }"
+ "{ facem | face-detection-retail-0005.xml | Path to OpenVINO IE face detection model (.xml) }"
"{ faced | CPU | Target device for face detection model (e.g. CPU, GPU, VPU, ...) }"
"{ trad | false | Run processing in a traditional (non-pipelined) way }"
"{ noshow | false | Don't display UI (improves performance) }";
--- /dev/null
+#!/usr/bin/env python3
+
+import sys
+import subprocess
+import re
+from enum import Enum
+
+## Helper functions ##################################################
+##
+def fmt_bool(x):
+ return ("true" if x else "false")
+
+def fmt_bin(base, prec, model):
+ return "%s/%s/%s/%s.xml" % (base, model, prec, model)
+
+## The script itself #################################################
+##
+if len(sys.argv) != 3:
+ print("Usage: %s /path/to/input/video /path/to/models" % sys.argv[0])
+ exit(1)
+
+input_file_path = sys.argv[1]
+intel_models_path = sys.argv[2]
+
+app = "bin/example_gapi_privacy_masking_camera"
+intel_fd_model = "face-detection-retail-0005"
+intel_lpd_model = "vehicle-license-plate-detection-barrier-0106"
+output_file = "out_results.csv"
+
+tgts = [ ("CPU", "INT8")
+ , ("CPU", "FP32")
+ , ("GPU", "FP16")
+ ]
+
+class Policy(Enum):
+ Traditional = 1
+ Streaming = 2
+
+# From mode to cmd arg
+mods = [ (Policy.Traditional, True)
+ , (Policy.Streaming, False)
+ ]
+
+class UI(Enum):
+ With = 1
+ Without = 2
+
+# From mode to cmd arg
+ui = [ (UI.With, False)
+ , (UI.Without, True)
+ ]
+
+fd_fmt_bin = lambda prec : fmt_bin(intel_models_path, prec, intel_fd_model)
+lpd_fmt_bin = lambda prec : fmt_bin(intel_models_path, prec, intel_lpd_model)
+
+# Performance comparison table
+table={}
+
+# Collect the performance data
+for m in mods: # Execution mode (trad/stream)
+ for u in ui: # UI mode (on/off)
+ for f in tgts: # FD model
+ for p in tgts: # LPD model
+ cmd = [ app
+ , ("--input=%s" % input_file_path) # input file
+ , ("--faced=%s" % f[0]) # FD device target
+ , ("--facem=%s" % fd_fmt_bin(f[1])) # FD model @ precision
+ , ("--platd=%s" % p[0]) # LPD device target
+ , ("--platm=%s" % lpd_fmt_bin(p[1])) # LPD model @ precision
+ , ("--trad=%s" % fmt_bool(m[1])) # Execution policy
+ , ("--noshow=%s" % fmt_bool(u[1])) # UI mode (show/no show)
+ ]
+ out = str(subprocess.check_output(cmd))
+ match = re.search('Processed [0-9]+ frames \(([0-9]+\.[0-9]+) FPS\)', out)
+ fps = float(match.group(1))
+ print(cmd, fps, "FPS")
+ table[m[0],u[0],f,p] = fps
+
+# Write the performance summary
+# Columns: all other components (mode, ui)
+with open(output_file, 'w') as csv:
+ # CSV header
+ csv.write("FD,LPD,Serial(UI),Serial(no-UI),Streaming(UI),Streaming(no-UI),Effect(UI),Effect(no-UI)\n")
+
+ for f in tgts: # FD model
+ for p in tgts: # LPD model
+ row = "%s/%s,%s/%s" % (f[0], f[1], p[0], p[1]) # FD precision, LPD precision
+ row += ",%f" % table[Policy.Traditional,UI.With, f,p] # Serial/UI
+ row += ",%f" % table[Policy.Traditional,UI.Without,f,p] # Serial/no UI
+ row += ",%f" % table[Policy.Streaming, UI.With, f,p] # Streaming/UI
+ row += ",%f" % table[Policy.Streaming, UI.Without,f,p] # Streaming/no UI
+
+ effect_ui = table[Policy.Streaming,UI.With, f,p] / table[Policy.Traditional,UI.With, f,p]
+ effect_noui = table[Policy.Streaming,UI.Without,f,p] / table[Policy.Traditional,UI.Without,f,p]
+ row += ",%f,%f" % (effect_ui,effect_noui)
+ row += "\n"
+ csv.write(row)
+
+print("DONE: ", output_file)
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
{
}
+cv::detail::GArrayU::GArrayU(const detail::VectorRef& vref)
+ : m_priv(new GOrigin(GShape::GARRAY, cv::gimpl::ConstVal(vref)))
+{
+}
+
cv::GOrigin& cv::detail::GArrayU::priv()
{
return *m_priv;
m_priv->ctor = std::move(cv);
}
+void cv::detail::GArrayU::setKind(cv::detail::OpaqueKind kind)
+{
+ m_priv->kind = kind;
+}
+
namespace cv {
std::ostream& operator<<(std::ostream& os, const cv::GArrayDesc &)
{
#include <functional> // multiplies
#include <opencv2/gapi/gkernel.hpp>
-#include <opencv2/gapi/own/convert.hpp>
#include "api/gbackend_priv.hpp"
#include "backends/common/gbackend.hpp"
{
switch (arg.index())
{
- case GRunArg::index_of<cv::gapi::own::Mat>() :
+ case GRunArg::index_of<cv::Mat>() :
if (is_umat)
{
#if !defined(GAPI_STANDALONE)
auto& mag_umat = mag.template slot<cv::UMat>()[rc.id];
- mag_umat = to_ocv(util::get<cv::gapi::own::Mat>(arg)).getUMat(ACCESS_READ);
+ mag_umat = util::get<cv::Mat>(arg).getUMat(ACCESS_READ);
#else
util::throw_error(std::logic_error("UMat is not supported in standalone build"));
#endif // !defined(GAPI_STANDALONE)
}
else
{
- auto& mag_mat = mag.template slot<cv::gapi::own::Mat>()[rc.id];
- mag_mat = util::get<cv::gapi::own::Mat>(arg);
+ auto& mag_mat = mag.template slot<cv::Mat>()[rc.id];
+ mag_mat = util::get<cv::Mat>(arg);
}
break;
-#if !defined(GAPI_STANDALONE)
- case GRunArg::index_of<cv::Mat>() :
- if (is_umat)
- {
- auto& mag_umat = mag.template slot<cv::UMat>()[rc.id];
- mag_umat = util::get<cv::Mat>(arg).getUMat(ACCESS_READ);
- }
- else
- {
- auto& mag_mat = mag.template slot<cv::gapi::own::Mat>()[rc.id];
- mag_mat = to_own(util::get<cv::Mat>(arg));
- }
- break;
-#endif // !defined(GAPI_STANDALONE)
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
}
break;
{
switch (arg.index())
{
- case GRunArgP::index_of<cv::gapi::own::Mat*>() :
+ case GRunArgP::index_of<cv::Mat*>() :
if (is_umat)
{
#if !defined(GAPI_STANDALONE)
auto& mag_umat = mag.template slot<cv::UMat>()[rc.id];
- mag_umat = to_ocv(*(util::get<cv::gapi::own::Mat*>(arg))).getUMat(ACCESS_RW);
+ mag_umat = util::get<cv::Mat*>(arg)->getUMat(ACCESS_RW);
#else
util::throw_error(std::logic_error("UMat is not supported in standalone build"));
#endif // !defined(GAPI_STANDALONE)
}
else
{
- auto& mag_mat = mag.template slot<cv::gapi::own::Mat>()[rc.id];
- mag_mat = *util::get<cv::gapi::own::Mat*>(arg);
+ auto& mag_mat = mag.template slot<cv::Mat>()[rc.id];
+ mag_mat = *util::get<cv::Mat*>(arg);
}
break;
-#if !defined(GAPI_STANDALONE)
- case GRunArgP::index_of<cv::Mat*>() :
- if (is_umat)
- {
- auto& mag_umat = mag.template slot<cv::UMat>()[rc.id];
- mag_umat = util::get<cv::Mat*>(arg)->getUMat(ACCESS_RW);
- }
- else
- {
- auto& mag_mat = mag.template slot<cv::gapi::own::Mat>()[rc.id];
- mag_mat = to_own(*util::get<cv::Mat*>(arg));
- }
- break;
-#endif // !defined(GAPI_STANDALONE)
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
}
break;
// Wrap associated CPU object (either host or an internal one)
switch (ref.shape)
{
- case GShape::GMAT: return GRunArg(mag.template slot<cv::gapi::own::Mat>().at(ref.id));
+ case GShape::GMAT: return GRunArg(mag.template slot<cv::Mat>().at(ref.id));
case GShape::GSCALAR: return GRunArg(mag.template slot<cv::Scalar>().at(ref.id));
// Note: .at() is intentional for GArray and GOpaque as objects MUST be already there
// (and constructed by either bindIn/Out or resetInternal)
#endif // !defined(GAPI_STANDALONE)
}
else
- return GRunArgP(&mag.template slot<cv::gapi::own::Mat>()[rc.id]);
+ return GRunArgP(&mag.template slot<cv::Mat>()[rc.id]);
case GShape::GSCALAR: return GRunArgP(&mag.template slot<cv::Scalar>()[rc.id]);
// Note: .at() is intentional for GArray and GOpaque as objects MUST be already there
// (and constructor by either bindIn/Out or resetInternal)
uchar* out_arg_data = nullptr;
switch (g_arg.index())
{
- case GRunArgP::index_of<cv::gapi::own::Mat*>() : out_arg_data = util::get<cv::gapi::own::Mat*>(g_arg)->data; break;
+ case GRunArgP::index_of<cv::Mat*>() : out_arg_data = util::get<cv::Mat*>(g_arg)->data; break;
#if !defined(GAPI_STANDALONE)
- case GRunArgP::index_of<cv::Mat*>() : out_arg_data = util::get<cv::Mat*>(g_arg)->data; break;
- case GRunArgP::index_of<cv::UMat*>() : out_arg_data = (util::get<cv::UMat*>(g_arg))->getMat(ACCESS_RW).data; break;
+ case GRunArgP::index_of<cv::UMat*>() : out_arg_data = (util::get<cv::UMat*>(g_arg))->getMat(ACCESS_RW).data; break;
#endif // !defined(GAPI_STANDALONE)
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
}
}
else
{
- auto& in_mag = mag.template slot<cv::gapi::own::Mat>().at(rc.id);
+ auto& in_mag = mag.template slot<cv::Mat>().at(rc.id);
GAPI_Assert((out_arg_data == in_mag.data) && " data for output parameters was reallocated ?");
}
break;
} // namespace magazine
-void createMat(const cv::GMatDesc &desc, cv::gapi::own::Mat& mat)
-{
- // FIXME: Refactor (probably start supporting N-Dimensional blobs natively
- if (desc.dims.empty())
- {
- const auto type = desc.planar ? desc.depth : CV_MAKETYPE(desc.depth, desc.chan);
- const auto size = desc.planar ? cv::Size{desc.size.width, desc.size.height*desc.chan}
- : desc.size;
- mat.create(size, type);
- }
- else
- {
- GAPI_Assert(!desc.planar);
- mat.create(desc.dims, desc.depth);
- }
-}
-
-#if !defined(GAPI_STANDALONE)
void createMat(const cv::GMatDesc &desc, cv::Mat& mat)
{
// FIXME: Refactor (probably start supporting N-Dimensional blobs natively
mat.create(desc.dims, desc.depth);
}
}
-#endif
} // namespace gimpl
} // namespace cv
const std::vector<GMat> &outs)
: m_priv(new Priv())
{
+ Priv::Expr e;
const auto wrap = [](cv::GMat m) { return GProtoArg(m); };
- ade::util::transform(ins, std::back_inserter(m_priv->m_ins), wrap);
- ade::util::transform(outs, std::back_inserter(m_priv->m_outs), wrap);
+ ade::util::transform(ins, std::back_inserter(e.m_ins), wrap);
+ ade::util::transform(outs, std::back_inserter(e.m_outs), wrap);
+ m_priv->m_shape = std::move(e);
}
cv::GComputation::GComputation(cv::GProtoInputArgs &&ins,
cv::GProtoOutputArgs &&outs)
: m_priv(new Priv())
{
- m_priv->m_ins = std::move(ins.m_args);
- m_priv->m_outs = std::move(outs.m_args);
+ m_priv->m_shape = Priv::Expr{
+ std::move(ins.m_args)
+ , std::move(outs.m_args)
+ };
}
+cv::GComputation::GComputation(cv::gimpl::s11n::I::IStream &is)
+ : m_priv(new Priv())
+{
+ m_priv->m_shape = gimpl::s11n::deserialize(is);
+}
+
+void cv::GComputation::serialize(cv::gimpl::s11n::I::OStream &os) const
+{
+ // Build a basic GModel and write the whole thing to the stream
+ auto pG = cv::gimpl::GCompiler::makeGraph(*m_priv);
+ std::vector<ade::NodeHandle> nhs(pG->nodes().begin(), pG->nodes().end());
+ gimpl::s11n::serialize(os, *pG, nhs);
+}
+
+
cv::GCompiled cv::GComputation::compile(GMetaArgs &&metas, GCompileArgs &&args)
{
// FIXME: Cache gcompiled per parameters here?
m_priv->m_lastCompiled(std::move(ins), std::move(outs));
}
-void cv::GComputation::apply(const std::vector<cv::gapi::own::Mat> &ins,
- const std::vector<cv::gapi::own::Mat> &outs,
+void cv::GComputation::apply(const std::vector<cv::Mat> &ins,
+ const std::vector<cv::Mat> &outs,
GCompileArgs &&args)
{
GRunArgs call_ins;
GRunArgsP call_outs;
auto tmp = outs;
- for (const cv::gapi::own::Mat &m : ins) { call_ins.emplace_back(m); }
- for ( cv::gapi::own::Mat &m : tmp) { call_outs.emplace_back(&m); }
+ for (const cv::Mat &m : ins) { call_ins.emplace_back(m); }
+ for ( cv::Mat &m : tmp) { call_outs.emplace_back(&m); }
apply(std::move(call_ins), std::move(call_outs), std::move(args));
}
#ifndef OPENCV_GAPI_GCOMPUTATION_PRIV_HPP
#define OPENCV_GAPI_GCOMPUTATION_PRIV_HPP
+#include <ade/graph.hpp>
+
+#include "opencv2/gapi/util/variant.hpp"
+
#include "opencv2/gapi.hpp"
#include "opencv2/gapi/gcall.hpp"
#include "opencv2/gapi/util/variant.hpp"
+#include "backends/common/serialization.hpp"
+
namespace cv {
class GComputation::Priv
{
public:
+ struct Expr {
+ cv::GProtoArgs m_ins;
+ cv::GProtoArgs m_outs;
+ };
+
+ using Dump = cv::gimpl::s11n::GSerialized;
+
+ using Shape = cv::util::variant
+ < Expr // An expression-based graph
+ , Dump // A deserialized graph
+ >;
+
GCompiled m_lastCompiled;
GMetaArgs m_lastMetas; // TODO: make GCompiled remember its metas?
- GProtoArgs m_ins;
- GProtoArgs m_outs;
+ Shape m_shape;
};
}
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#include "precomp.hpp"
+
+#include <opencv2/gapi/gframe.hpp>
+
+#include "api/gorigin.hpp"
+
+// cv::GFrame public implementation //////////////////////////////////////////////
+cv::GFrame::GFrame()
+ : m_priv(new GOrigin(GShape::GMAT, GNode::Param())) {
+ // N.B.: The shape here is still GMAT as currently cv::Mat is used
+ // as an underlying host type. Will be changed to GFRAME once
+ // GExecutor & GStreamingExecutor & selected backends will be extended
+ // to support cv::MediaFrame.
+}
+
+cv::GFrame::GFrame(const GNode &n, std::size_t out)
+ : m_priv(new GOrigin(GShape::GMAT, n, out)) {
+ // N.B.: GMAT is here for the same reason as above ^
+}
+
+cv::GOrigin& cv::GFrame::priv() {
+ return *m_priv;
+}
+
+const cv::GOrigin& cv::GFrame::priv() const {
+ return *m_priv;
+}
+
+namespace cv {
+std::ostream& operator<<(std::ostream& os, const cv::GFrameDesc &) {
+ return os;
+}
+
+} // namespace cv
}
}
-
#if !defined(GAPI_STANDALONE)
cv::GMatDesc cv::descr_of(const cv::Mat &mat)
{
}
return GMatDesc{mat.depth(), std::move(dims)};
}
+#endif
-cv::GMatDesc cv::descr_of(const cv::UMat &mat)
+cv::GMatDesc cv::gapi::own::descr_of(const Mat &mat)
{
- GAPI_Assert(mat.size.dims() == 2);
- return GMatDesc{ mat.depth(), mat.channels(),{ mat.cols, mat.rows } };
+ return (mat.dims.empty())
+ ? GMatDesc{mat.depth(), mat.channels(), {mat.cols, mat.rows}}
+ : GMatDesc{mat.depth(), mat.dims};
}
-cv::GMetaArgs cv::descrs_of(const std::vector<cv::Mat> &vec)
+#if !defined(GAPI_STANDALONE)
+cv::GMatDesc cv::descr_of(const cv::UMat &mat)
{
- return vec_descr_of(vec);
+ GAPI_Assert(mat.size.dims() == 2);
+ return GMatDesc{ mat.depth(), mat.channels(),{ mat.cols, mat.rows } };
}
cv::GMetaArgs cv::descrs_of(const std::vector<cv::UMat> &vec)
}
#endif
-cv::GMatDesc cv::gapi::own::descr_of(const cv::gapi::own::Mat &mat)
+cv::GMetaArgs cv::descrs_of(const std::vector<cv::Mat> &vec)
{
- return (mat.dims.empty())
- ? GMatDesc{mat.depth(), mat.channels(), {mat.cols, mat.rows}}
- : GMatDesc{mat.depth(), mat.dims};
+ return vec_descr_of(vec);
}
-cv::GMetaArgs cv::gapi::own::descrs_of(const std::vector<cv::gapi::own::Mat> &vec)
+cv::GMetaArgs cv::gapi::own::descrs_of(const std::vector<Mat> &vec)
{
return vec_descr_of(vec);
}
namespace {
template<typename M> inline bool canDescribeHelper(const GMatDesc& desc, const M& mat)
{
- const auto mat_desc = desc.planar ? descr_of(mat).asPlanar(desc.chan) : descr_of(mat);
+ const auto mat_desc = desc.planar ? cv::descr_of(mat).asPlanar(desc.chan) : cv::descr_of(mat);
return desc == mat_desc;
}
} // anonymous namespace
-bool GMatDesc::canDescribe(const cv::gapi::own::Mat& mat) const
-{
- return canDescribeHelper(*this, mat);
-}
-
-#if !defined(GAPI_STANDALONE)
bool GMatDesc::canDescribe(const cv::Mat& mat) const
{
return canDescribeHelper(*this, mat);
}
-#endif
}// namespace cv
// 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
+// Copyright (C) 2019-2020 Intel Corporation
#include "precomp.hpp"
m_priv->ctor = std::move(co);
}
+void cv::detail::GOpaqueU::setKind(cv::detail::OpaqueKind kind)
+{
+ m_priv->kind = kind;
+}
+
namespace cv {
std::ostream& operator<<(std::ostream& os, const cv::GOpaqueDesc &)
{
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
cv::GOrigin::GOrigin(GShape s,
const cv::GNode& n,
std::size_t p,
- const cv::gimpl::HostCtor c)
- : shape(s), node(n), port(p), ctor(c)
+ const cv::gimpl::HostCtor c,
+ cv::detail::OpaqueKind k)
+ : shape(s), node(n), port(p), ctor(c), kind(k)
{
}
cv::GOrigin::GOrigin(GShape s, cv::gimpl::ConstVal v)
- : shape(s), node(cv::GNode::Const()), value(v), port(INVALID_PORT)
+ : shape(s), node(cv::GNode::Const()), value(v), port(INVALID_PORT),
+ kind(util::holds_alternative<detail::VectorRef>(v)
+ ? util::get<detail::VectorRef>(v).getKind()
+ : cv::detail::OpaqueKind::CV_UNKNOWN)
{
}
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
-
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GORIGIN_HPP
#define OPENCV_GAPI_GORIGIN_HPP
GOrigin(GShape s,
const GNode& n,
std::size_t p = INVALID_PORT,
- const gimpl::HostCtor h = {});
+ const gimpl::HostCtor h = {},
+ cv::detail::OpaqueKind kind = cv::detail::OpaqueKind::CV_UNKNOWN);
GOrigin(GShape s, gimpl::ConstVal value);
const GShape shape; // Shape of a produced object
const gimpl::ConstVal value; // Node can have initial constant value, now only scalar is supported
const std::size_t port; // GNode's output number; FIXME: "= max_size" in C++14
gimpl::HostCtor ctor; // FIXME: replace with an interface?
+ detail::OpaqueKind kind; // primary is needed for GOpaque and GArray
};
namespace detail
case cv::GProtoArg::index_of<cv::GMatP>():
return util::get<cv::GMatP>(arg).priv();
+ case cv::GProtoArg::index_of<cv::GFrame>():
+ return util::get<cv::GFrame>(arg).priv();
+
case cv::GProtoArg::index_of<cv::GScalar>():
return util::get<cv::GScalar>(arg).priv();
{
case detail::ArgKind::GMAT:
case detail::ArgKind::GMATP:
+ case detail::ArgKind::GFRAME:
case detail::ArgKind::GSCALAR:
case detail::ArgKind::GARRAY:
case detail::ArgKind::GOPAQUE:
switch (origin.shape)
{
case GShape::GSCALAR: return GRunArg(util::get<cv::Scalar>(origin.value));
+ case GShape::GARRAY: return GRunArg(util::get<cv::detail::VectorRef>(origin.value));
default: util::throw_error(std::logic_error("Unsupported shape for constant"));
}
}
{
case detail::ArgKind::GMAT: return GProtoArg(arg.get<cv::GMat>());
case detail::ArgKind::GMATP: return GProtoArg(arg.get<cv::GMatP>());
+ case detail::ArgKind::GFRAME: return GProtoArg(arg.get<cv::GFrame>());
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>());
+ case detail::ArgKind::GOPAQUE: return GProtoArg(arg.get<cv::detail::GOpaqueU>());
default: util::throw_error(std::logic_error("Unsupported GArg type"));
}
}
{
switch (arg.index())
{
-#if !defined(GAPI_STANDALONE)
case GRunArg::index_of<cv::Mat>():
- return cv::GMetaArg(descr_of(util::get<cv::Mat>(arg)));
-
-#endif // !defined(GAPI_STANDALONE)
-
- case GRunArg::index_of<cv::gapi::own::Mat>():
- return cv::GMetaArg(descr_of(util::get<cv::gapi::own::Mat>(arg)));
+ return cv::GMetaArg(cv::descr_of(util::get<cv::Mat>(arg)));
case GRunArg::index_of<cv::Scalar>():
return cv::GMetaArg(descr_of(util::get<cv::Scalar>(arg)));
switch (argp.index())
{
#if !defined(GAPI_STANDALONE)
- case GRunArgP::index_of<cv::Mat*>(): return GMetaArg(descr_of(*util::get<cv::Mat*>(argp)));
- case GRunArgP::index_of<cv::UMat*>(): return GMetaArg(descr_of(*util::get<cv::UMat*>(argp)));
+ case GRunArgP::index_of<cv::UMat*>(): return GMetaArg(cv::descr_of(*util::get<cv::UMat*>(argp)));
#endif // !defined(GAPI_STANDALONE)
- case GRunArgP::index_of<cv::gapi::own::Mat*>(): return GMetaArg(descr_of(*util::get<cv::gapi::own::Mat*>(argp)));
+ case GRunArgP::index_of<cv::Mat*>(): return GMetaArg(cv::descr_of(*util::get<cv::Mat*>(argp)));
case GRunArgP::index_of<cv::Scalar*>(): return GMetaArg(descr_of(*util::get<cv::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());
switch (argp.index())
{
#if !defined(GAPI_STANDALONE)
+ case GRunArgP::index_of<cv::UMat*>(): return meta == GMetaArg(cv::descr_of(*util::get<cv::UMat*>(argp)));
+#endif // !defined(GAPI_STANDALONE)
case GRunArgP::index_of<cv::Mat*>(): return util::holds_alternative<GMatDesc>(meta) &&
util::get<GMatDesc>(meta).canDescribe(*util::get<cv::Mat*>(argp));
- case GRunArgP::index_of<cv::UMat*>(): return meta == GMetaArg(descr_of(*util::get<cv::UMat*>(argp)));
-#endif // !defined(GAPI_STANDALONE)
- case GRunArgP::index_of<cv::gapi::own::Mat*>(): return util::holds_alternative<GMatDesc>(meta) &&
- util::get<GMatDesc>(meta).canDescribe(*util::get<cv::gapi::own::Mat*>(argp));
- case GRunArgP::index_of<cv::Scalar*>(): return meta == GMetaArg(descr_of(*util::get<cv::Scalar*>(argp)));
+ case GRunArgP::index_of<cv::Scalar*>(): return meta == GMetaArg(cv::descr_of(*util::get<cv::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"));
switch (arg.index())
{
#if !defined(GAPI_STANDALONE)
- case GRunArg::index_of<cv::Mat>(): return util::holds_alternative<GMatDesc>(meta) &&
- util::get<GMatDesc>(meta).canDescribe(util::get<cv::Mat>(arg));
case GRunArg::index_of<cv::UMat>(): return meta == cv::GMetaArg(descr_of(util::get<cv::UMat>(arg)));
#endif // !defined(GAPI_STANDALONE)
- case GRunArg::index_of<cv::gapi::own::Mat>(): return util::holds_alternative<GMatDesc>(meta) &&
- util::get<GMatDesc>(meta).canDescribe(util::get<cv::gapi::own::Mat>(arg));
+ case GRunArg::index_of<cv::Mat>(): return util::holds_alternative<GMatDesc>(meta) &&
+ util::get<GMatDesc>(meta).canDescribe(util::get<cv::Mat>(arg));
case GRunArg::index_of<cv::Scalar>(): return meta == cv::GMetaArg(descr_of(util::get<cv::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());
switch (arg.index())
{
#if !defined(GAPI_STANDALONE)
- case GRunArg::index_of<cv::Mat>():
- {
- const auto desc = descr_of(util::get<cv::Mat>(arg));
- GAPI_Assert(desc.size.height != 0 && desc.size.width != 0 && "incorrect dimensions of cv::Mat!"); break;
- }
case GRunArg::index_of<cv::UMat>():
{
- const auto desc = descr_of(util::get<cv::UMat>(arg));
+ const auto desc = cv::descr_of(util::get<cv::UMat>(arg));
GAPI_Assert(desc.size.height != 0 && desc.size.width != 0 && "incorrect dimensions of cv::UMat!"); break;
}
#endif // !defined(GAPI_STANDALONE)
- case GRunArg::index_of<cv::gapi::own::Mat>():
+ case GRunArg::index_of<cv::Mat>():
{
- const auto desc = descr_of(util::get<cv::gapi::own::Mat>(arg));
- GAPI_Assert(desc.size.height != 0 && desc.size.width != 0 && "incorrect dimensions of own::Mat!"); break;
+ const auto desc = cv::descr_of(util::get<cv::Mat>(arg));
+ GAPI_Assert(desc.size.height != 0 && desc.size.width != 0 && "incorrect dimensions of Mat!"); break;
}
default:
// No extra handling
return os;
}
+} // namespace cv
+
+const void* cv::gimpl::proto::ptr(const GRunArgP &arg)
+{
+ switch (arg.index())
+ {
+#if !defined(GAPI_STANDALONE)
+ case GRunArgP::index_of<cv::UMat*>():
+ return static_cast<const void*>(cv::util::get<cv::UMat*>(arg));
+#endif
+ case GRunArgP::index_of<cv::Mat*>():
+ return static_cast<const void*>(cv::util::get<cv::Mat*>(arg));
+ case GRunArgP::index_of<cv::Scalar*>():
+ return static_cast<const void*>(cv::util::get<cv::Scalar*>(arg));
+ case GRunArgP::index_of<cv::detail::VectorRef>():
+ return cv::util::get<cv::detail::VectorRef>(arg).ptr();
+ case GRunArgP::index_of<cv::detail::OpaqueRef>():
+ return cv::util::get<cv::detail::OpaqueRef>(arg).ptr();
+ default:
+ util::throw_error(std::logic_error("Unknown GRunArgP type!"));
+ }
}
bool is_dynamic(const GArg &arg);
GProtoArg rewrap (const GArg &arg);
+// FIXME:: GAPI_EXPORTS because of tests only!!
+GAPI_EXPORTS const void* ptr (const GRunArgP &arg);
+
} // proto
} // gimpl
} // cv
+// FIXME: the gproto.cpp file has more functions that listed here
+// where those are declared??
+
#endif // OPENCV_GAPI_GPROTO_PRIV_HPP
#include "precomp.hpp"
#include <opencv2/gapi/gscalar.hpp>
-#include <opencv2/gapi/own/convert.hpp>
#include "api/gorigin.hpp"
// cv::GScalar public implementation ///////////////////////////////////////////
return *m_priv;
}
+//N.B. if we ever need more complicated logic for desc_of(cv::(gapi::own::)Scalar)
+//dispatching should be done in the same way as for cv::(gapi::own)::Mat
cv::GScalarDesc cv::descr_of(const cv::Scalar &)
{
return empty_scalar_desc();
return core::GWarpAffine::on(src, M, dsize, flags, borderMode, borderValue);
}
+GOpaque<Size> size(const GMat& src)
+{
+ return core::GSize::on(src);
+}
+
+GOpaque<Size> size(const GOpaque<Rect>& r)
+{
+ return core::GSizeR::on(r);
+}
+
} //namespace gapi
} //namespace cv
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
return imgproc::GSobelXY::on(src, ddepth, order, ksize, scale, delta, borderType, bordVal);
}
+GMat Laplacian(const GMat& src, int ddepth, int ksize, double scale, double delta, int borderType)
+{
+ return imgproc::GLaplacian::on(src, ddepth, ksize, scale, delta, borderType);
+}
+
+GMat bilateralFilter(const GMat& src, int d, double sigmaColor, double sigmaSpace, int borderType)
+{
+ return imgproc::GBilateralFilter::on(src, d, sigmaColor, sigmaSpace, borderType);
+}
+
GMat equalizeHist(const GMat& src)
{
return imgproc::GEqHist::on(src);
return imgproc::GCanny::on(src, thr1, thr2, apertureSize, l2gradient);
}
+cv::GArray<cv::Point2f> goodFeaturesToTrack(const GMat& image, int maxCorners, double qualityLevel,
+ double minDistance, const Mat& mask, int blockSize,
+ bool useHarrisDetector, double k)
+{
+ return imgproc::GGoodFeatures::on(image, maxCorners, qualityLevel, minDistance, mask, blockSize,
+ useHarrisDetector, k);
+}
+
GMat RGB2Gray(const GMat& src)
{
return imgproc::GRGB2Gray::on(src);
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#include "precomp.hpp"
+
+#include <opencv2/gapi/infer/parsers.hpp>
+
+#include <tuple>
+#include <numeric>
+
+namespace cv { namespace gapi {
+
+nn::parsers::GDetections parseSSD(const GMat& in,
+ const GOpaque<Size>& inSz,
+ const float confidenceThreshold,
+ const int filterLabel)
+{
+ return nn::parsers::GParseSSDBL::on(in, inSz, confidenceThreshold, filterLabel);
+}
+
+nn::parsers::GRects parseSSD(const GMat& in,
+ const GOpaque<Size>& inSz,
+ const float confidenceThreshold,
+ const bool alignmentToSquare,
+ const bool filterOutOfBounds)
+{
+ return nn::parsers::GParseSSD::on(in, inSz, confidenceThreshold, alignmentToSquare, filterOutOfBounds);
+}
+
+nn::parsers::GDetections parseYolo(const GMat& in,
+ const GOpaque<Size>& inSz,
+ const float confidenceThreshold,
+ const float nmsThreshold,
+ const std::vector<float>& anchors)
+{
+ return nn::parsers::GParseYolo::on(in, inSz, confidenceThreshold, nmsThreshold, anchors);
+}
+
+} //namespace gapi
+} //namespace cv
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#include "precomp.hpp"
+
+#include <opencv2/gapi/video.hpp>
+
+namespace cv { namespace gapi {
+using namespace video;
+
+GBuildPyrOutput buildOpticalFlowPyramid(const GMat &img,
+ const Size &winSize,
+ const GScalar &maxLevel,
+ bool withDerivatives,
+ int pyrBorder,
+ int derivBorder,
+ bool tryReuseInputImage)
+{
+ return GBuildOptFlowPyramid::on(img, winSize, maxLevel, withDerivatives, pyrBorder,
+ derivBorder, tryReuseInputImage);
+}
+
+GOptFlowLKOutput calcOpticalFlowPyrLK(const GMat &prevImg,
+ const GMat &nextImg,
+ const cv::GArray<cv::Point2f> &prevPts,
+ const cv::GArray<cv::Point2f> &predPts,
+ const Size &winSize,
+ const GScalar &maxLevel,
+ const TermCriteria &criteria,
+ int flags,
+ double minEigThresh)
+{
+ return GCalcOptFlowLK::on(prevImg, nextImg, prevPts, predPts, winSize, maxLevel,
+ criteria, flags, minEigThresh);
+}
+
+GOptFlowLKOutput calcOpticalFlowPyrLK(const cv::GArray<cv::GMat> &prevPyr,
+ const cv::GArray<cv::GMat> &nextPyr,
+ const cv::GArray<cv::Point2f> &prevPts,
+ const cv::GArray<cv::Point2f> &predPts,
+ const Size &winSize,
+ const GScalar &maxLevel,
+ const TermCriteria &criteria,
+ int flags,
+ double minEigThresh)
+{
+ return GCalcOptFlowLKForPyr::on(prevPyr, nextPyr, prevPts, predPts, winSize, maxLevel,
+ criteria, flags, minEigThresh);
+}
+
+} //namespace gapi
+} //namespace cv
#include <opencv2/gapi/gscalar.hpp>
#include <opencv2/gapi/operators.hpp>
+namespace cv
+{
cv::GMat operator+(const cv::GMat& lhs, const cv::GMat& rhs)
{
return cv::gapi::add(lhs, rhs);
{
return cv::gapi::cmpNE(rhs, lhs);
}
+} // cv
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#include <opencv2/gapi/s11n.hpp>
+#include <opencv2/gapi/garg.hpp>
+
+#include "backends/common/serialization.hpp"
+
+std::vector<char> cv::gapi::serialize(const cv::GComputation &c) {
+ cv::gimpl::s11n::ByteMemoryOutStream os;
+ c.serialize(os);
+ return os.data();
+}
+
+cv::GComputation cv::gapi::detail::getGraph(const std::vector<char> &p) {
+ cv::gimpl::s11n::ByteMemoryInStream is(p);
+ return cv::GComputation(is);
+}
+
+cv::GMetaArgs cv::gapi::detail::getMetaArgs(const std::vector<char> &p) {
+ cv::gimpl::s11n::ByteMemoryInStream is(p);
+ return meta_args_deserialize(is);
+}
+
+cv::GRunArgs cv::gapi::detail::getRunArgs(const std::vector<char> &p) {
+ cv::gimpl::s11n::ByteMemoryInStream is(p);
+ return run_args_deserialize(is);
+}
+
+std::vector<char> cv::gapi::serialize(const cv::GMetaArgs& ma)
+{
+ cv::gimpl::s11n::ByteMemoryOutStream os;
+ serialize(os, ma);
+ return os.data();
+}
+
+std::vector<char> cv::gapi::serialize(const cv::GRunArgs& ra)
+{
+ cv::gimpl::s11n::ByteMemoryOutStream os;
+ serialize(os, ra);
+ return os.data();
+}
+
+// FIXME: This function should move from S11N to GRunArg-related entities.
+// it has nothing to do with the S11N as it is
+cv::GRunArgsP cv::gapi::bind(cv::GRunArgs &results)
+{
+ cv::GRunArgsP outputs;
+ outputs.reserve(results.size());
+ for (cv::GRunArg &res_obj : results)
+ {
+ using T = cv::GRunArg;
+ switch (res_obj.index())
+ {
+#if !defined(GAPI_STANDALONE)
+ case T::index_of<cv::UMat>() :
+ outputs.emplace_back((cv::UMat*)(&(cv::util::get<cv::UMat>(res_obj))));
+ break;
+#endif
+ case cv::GRunArg::index_of<cv::Mat>() :
+ outputs.emplace_back((cv::Mat*)(&(cv::util::get<cv::Mat>(res_obj))));
+ break;
+ case cv::GRunArg::index_of<cv::Scalar>() :
+ outputs.emplace_back((cv::Scalar*)(&(cv::util::get<cv::Scalar>(res_obj))));
+ break;
+ case T::index_of<cv::detail::VectorRef>() :
+ outputs.emplace_back(cv::util::get<cv::detail::VectorRef>(res_obj));
+ break;
+ case T::index_of<cv::detail::OpaqueRef>() :
+ outputs.emplace_back(cv::util::get<cv::detail::OpaqueRef>(res_obj));
+ break;
+ default:
+ GAPI_Assert(false && "This value type is not supported!"); // ...maybe because of STANDALONE mode.
+ break;
+ }
+ }
+ return outputs;
+}
+
+// FIXME: move it out of s11n to api/
+// FIXME: don't we have such function already?
+cv::GRunArg cv::gapi::bind(cv::GRunArgP &out)
+{
+ using T = cv::GRunArgP;
+ switch (out.index())
+ {
+#if !defined(GAPI_STANDALONE)
+ case T::index_of<cv::UMat*>() :
+ GAPI_Assert(false && "Please implement this!");
+ break;
+#endif
+
+ case T::index_of<cv::detail::VectorRef>() :
+ return cv::GRunArg(cv::util::get<cv::detail::VectorRef>(out));
+
+ case T::index_of<cv::detail::OpaqueRef>() :
+ return cv::GRunArg(cv::util::get<cv::detail::OpaqueRef>(out));
+
+ case T::index_of<cv::Mat*>() :
+ return cv::GRunArg(*cv::util::get<cv::Mat*>(out));
+
+ case T::index_of<cv::Scalar*>() :
+ return cv::GRunArg(*cv::util::get<cv::Scalar*>(out));
+
+ default:
+ // ...maybe our types were extended
+ GAPI_Assert(false && "This value type is UNKNOWN!");
+ break;
+ }
+ return cv::GRunArg();
+}
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GBACKEND_HPP
#include <ade/node.hpp>
#include "opencv2/gapi/garg.hpp"
-#include "opencv2/gapi/own/mat.hpp"
#include "opencv2/gapi/util/optional.hpp"
} // namespace magazine
#if !defined(GAPI_STANDALONE)
-using Mag = magazine::Class<cv::gapi::own::Mat, cv::UMat, cv::Scalar, cv::detail::VectorRef, cv::detail::OpaqueRef>;
+using Mag = magazine::Class<cv::Mat, cv::UMat, cv::Scalar, cv::detail::VectorRef, cv::detail::OpaqueRef>;
#else
-using Mag = magazine::Class<cv::gapi::own::Mat, cv::Scalar, cv::detail::VectorRef, cv::detail::OpaqueRef>;
+using Mag = magazine::Class<cv::Mat, cv::Scalar, cv::detail::VectorRef, cv::detail::OpaqueRef>;
#endif
namespace magazine
template<typename T>
inline cv::util::optional<T> getCompileArg(const cv::GCompileArgs &args)
{
- for (auto &compile_arg : args)
- {
- if (compile_arg.tag == cv::detail::CompileArgTag<T>::tag())
- {
- return cv::util::optional<T>(compile_arg.get<T>());
- }
- }
- return cv::util::optional<T>();
+ return cv::gapi::getCompileArg<T>(args);
}
-void createMat(const cv::GMatDesc& desc, cv::gapi::own::Mat& mat);
-#if !defined(GAPI_STANDALONE)
void createMat(const cv::GMatDesc& desc, cv::Mat& mat);
-#endif
}} // cv::gimpl
{
case GShape::GMAT : m_args[i] = GArg(GMat()); break;
case GShape::GSCALAR: m_args[i] = GArg(GScalar()); break;
- case GShape::GARRAY :/* do nothing - as handled in a special way, see gcompoundkernel.hpp for details */; break;
+ case GShape::GARRAY :
+ case GShape::GOPAQUE:
+ // do nothing - as handled in a special way, see gcompoundkernel.hpp for details
+ // same applies to GMatP
+ break;
default: GAPI_Assert(false);
}
}
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#include <set> // set
+#include <map> // map
+#include <ade/util/zip_range.hpp> // indexed
+
+#define NOMINMAX
+
+#ifdef _WIN32
+#include <winsock.h> // htonl, ntohl
+#else
+#include <netinet/in.h> // htonl, ntohl
+#endif
+
+#include <opencv2/gapi/gtype_traits.hpp>
+
+#include "backends/common/serialization.hpp"
+
+namespace cv {
+namespace gimpl {
+namespace s11n {
+namespace {
+
+void putData(GSerialized& s, const GModel::ConstGraph& cg, const ade::NodeHandle &nh) {
+ const auto gdata = cg.metadata(nh).get<gimpl::Data>();
+ const auto it = ade::util::find_if(s.m_datas, [&gdata](const cv::gimpl::Data &cd) {
+ return cd.rc == gdata.rc && cd.shape == gdata.shape;
+ });
+ if (s.m_datas.end() == it) {
+ s.m_datas.push_back(gdata);
+ }
+}
+
+void putOp(GSerialized& s, const GModel::ConstGraph& cg, const ade::NodeHandle &nh) {
+ const auto& op = cg.metadata(nh).get<gimpl::Op>();
+ for (const auto &in_nh : nh->inNodes()) { putData(s, cg, in_nh); }
+ for (const auto &out_nh : nh->outNodes()) { putData(s, cg, out_nh); }
+ s.m_ops.push_back(op);
+}
+
+void mkDataNode(ade::Graph& g, const cv::gimpl::Data& data) {
+ GModel::Graph gm(g);
+ auto nh = gm.createNode();
+ gm.metadata(nh).set(NodeType{NodeType::DATA});
+ gm.metadata(nh).set(data);
+}
+
+void mkOpNode(ade::Graph& g, const cv::gimpl::Op& op) {
+ GModel::Graph gm(g);
+ auto nh = gm.createNode();
+ gm.metadata(nh).set(NodeType{NodeType::OP});
+ gm.metadata(nh).set(op);
+}
+
+void linkNodes(ade::Graph& g) {
+ std::map<cv::gimpl::RcDesc, ade::NodeHandle> dataNodes;
+ GModel::Graph gm(g);
+
+ for (const auto& nh : g.nodes()) {
+ if (gm.metadata(nh).get<NodeType>().t == NodeType::DATA) {
+ const auto &d = gm.metadata(nh).get<gimpl::Data>();
+ const auto rc = cv::gimpl::RcDesc{d.rc, d.shape, d.ctor};
+ dataNodes[rc] = nh;
+ }
+ }
+
+ for (const auto& nh : g.nodes()) {
+ if (gm.metadata(nh).get<NodeType>().t == NodeType::OP) {
+ const auto& op = gm.metadata(nh).get<gimpl::Op>();
+ for (const auto& in : ade::util::indexed(op.args)) {
+ const auto& arg = ade::util::value(in);
+ if (arg.kind == cv::detail::ArgKind::GOBJREF) {
+ const auto idx = ade::util::index(in);
+ const auto rc = arg.get<gimpl::RcDesc>();
+ const auto& in_nh = dataNodes.at(rc);
+ const auto& in_eh = g.link(in_nh, nh);
+ gm.metadata(in_eh).set(Input{idx});
+ }
+ }
+
+ for (const auto& out : ade::util::indexed(op.outs)) {
+ const auto idx = ade::util::index(out);
+ const auto rc = ade::util::value(out);
+ const auto& out_nh = dataNodes.at(rc);
+ const auto& out_eh = g.link(nh, out_nh);
+ gm.metadata(out_eh).set(Output{idx});
+ }
+ }
+ }
+}
+
+void relinkProto(ade::Graph& g) {
+ // identify which node handles map to the protocol
+ // input/output object in the reconstructed graph
+ using S = std::set<cv::gimpl::RcDesc>; // FIXME: use ...
+ using M = std::map<cv::gimpl::RcDesc, ade::NodeHandle>; // FIXME: unordered!
+
+ cv::gimpl::GModel::Graph gm(g);
+ auto &proto = gm.metadata().get<Protocol>();
+
+ const S set_in(proto.inputs.begin(), proto.inputs.end());
+ const S set_out(proto.outputs.begin(), proto.outputs.end());
+ M map_in, map_out;
+
+ // Associate the protocol node handles with their resource identifiers
+ for (auto &&nh : gm.nodes()) {
+ if (gm.metadata(nh).get<cv::gimpl::NodeType>().t == cv::gimpl::NodeType::DATA) {
+ const auto &d = gm.metadata(nh).get<cv::gimpl::Data>();
+ const auto rc = cv::gimpl::RcDesc{d.rc, d.shape, d.ctor};
+ if (set_in.count(rc) > 0) {
+ GAPI_DbgAssert(set_out.count(rc) == 0);
+ map_in[rc] = nh;
+ } else if (set_out.count(rc) > 0) {
+ GAPI_DbgAssert(set_in.count(rc) == 0);
+ map_out[rc] = nh;
+ }
+ }
+ }
+
+ // Reconstruct the protocol vectors, ordered
+ proto.in_nhs.reserve(proto.inputs.size());
+ proto.in_nhs.clear();
+ proto.out_nhs.reserve(proto.outputs.size());
+ proto.out_nhs.clear();
+ for (auto &rc : proto.inputs) { proto.in_nhs .push_back(map_in .at(rc)); }
+ for (auto &rc : proto.outputs) { proto.out_nhs.push_back(map_out.at(rc)); }
+}
+
+} // anonymous namespace
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// Graph dump operators
+
+// OpenCV types ////////////////////////////////////////////////////////////////
+
+I::OStream& operator<< (I::OStream& os, const cv::Point &pt) {
+ return os << pt.x << pt.y;
+}
+I::IStream& operator>> (I::IStream& is, cv::Point& pt) {
+ return is >> pt.x >> pt.y;
+}
+
+I::OStream& operator<< (I::OStream& os, const cv::Size &sz) {
+ return os << sz.width << sz.height;
+}
+I::IStream& operator>> (I::IStream& is, cv::Size& sz) {
+ return is >> sz.width >> sz.height;
+}
+
+I::OStream& operator<< (I::OStream& os, const cv::Rect &rc) {
+ return os << rc.x << rc.y << rc.width << rc.height;
+}
+I::IStream& operator>> (I::IStream& is, cv::Rect& rc) {
+ return is >> rc.x >> rc.y >> rc.width >> rc.height;
+}
+
+I::OStream& operator<< (I::OStream& os, const cv::Scalar &s) {
+ return os << s.val[0] << s.val[1] << s.val[2] << s.val[3];
+}
+I::IStream& operator>> (I::IStream& is, cv::Scalar& s) {
+ return is >> s.val[0] >> s.val[1] >> s.val[2] >> s.val[3];
+}
+
+namespace
+{
+
+#if !defined(GAPI_STANDALONE)
+template<typename T>
+ void write_plain(I::OStream &os, const T *arr, std::size_t sz) {
+ for (auto &&it : ade::util::iota(sz)) os << arr[it];
+}
+template<typename T>
+ void read_plain(I::IStream &is, T *arr, std::size_t sz) {
+ for (auto &&it : ade::util::iota(sz)) is >> arr[it];
+}
+template<typename T>
+void write_mat_data(I::OStream &os, const cv::Mat &m) {
+ // Write every row individually (handles the case when Mat is a view)
+ for (auto &&r : ade::util::iota(m.rows)) {
+ write_plain(os, m.ptr<T>(r), m.cols*m.channels());
+ }
+}
+template<typename T>
+void read_mat_data(I::IStream &is, cv::Mat &m) {
+ // Write every row individually (handles the case when Mat is aligned)
+ for (auto &&r : ade::util::iota(m.rows)) {
+ read_plain(is, m.ptr<T>(r), m.cols*m.channels());
+ }
+}
+#else
+void write_plain(I::OStream &os, const uchar *arr, std::size_t sz) {
+ for (auto &&it : ade::util::iota(sz)) os << arr[it];
+}
+void read_plain(I::IStream &is, uchar *arr, std::size_t sz) {
+ for (auto &&it : ade::util::iota(sz)) is >> arr[it];
+}
+template<typename T>
+void write_mat_data(I::OStream &os, const cv::Mat &m) {
+ // Write every row individually (handles the case when Mat is a view)
+ for (auto &&r : ade::util::iota(m.rows)) {
+ write_plain(os, m.ptr(r), m.cols*m.channels()*sizeof(T));
+ }
+}
+template<typename T>
+void read_mat_data(I::IStream &is, cv::Mat &m) {
+ // Write every row individually (handles the case when Mat is aligned)
+ for (auto &&r : ade::util::iota(m.rows)) {
+ read_plain(is, m.ptr(r), m.cols*m.channels()*sizeof(T));
+ }
+}
+#endif
+} // namespace
+
+I::OStream& operator<< (I::OStream& os, const cv::Mat &m) {
+#if !defined(GAPI_STANDALONE)
+ GAPI_Assert(m.size.dims() == 2 && "Only 2D images are supported now");
+#else
+ GAPI_Assert(m.dims.size() == 2 && "Only 2D images are supported now");
+#endif
+ os << m.rows << m.cols << m.type();
+ switch (m.depth()) {
+ case CV_8U: write_mat_data< uint8_t>(os, m); break;
+ case CV_8S: write_mat_data< char>(os, m); break;
+ case CV_16U: write_mat_data<uint16_t>(os, m); break;
+ case CV_16S: write_mat_data< int16_t>(os, m); break;
+ case CV_32S: write_mat_data< int32_t>(os, m); break;
+ case CV_32F: write_mat_data< float>(os, m); break;
+ case CV_64F: write_mat_data< double>(os, m); break;
+ default: GAPI_Assert(false && "Unsupported Mat depth");
+ }
+ return os;
+}
+I::IStream& operator>> (I::IStream& is, cv::Mat& m) {
+ int rows = -1, cols = -1, type = 0;
+ is >> rows >> cols >> type;
+ m.create(cv::Size(cols, rows), type);
+ switch (m.depth()) {
+ case CV_8U: read_mat_data< uint8_t>(is, m); break;
+ case CV_8S: read_mat_data< char>(is, m); break;
+ case CV_16U: read_mat_data<uint16_t>(is, m); break;
+ case CV_16S: read_mat_data< int16_t>(is, m); break;
+ case CV_32S: read_mat_data< int32_t>(is, m); break;
+ case CV_32F: read_mat_data< float>(is, m); break;
+ case CV_64F: read_mat_data< double>(is, m); break;
+ default: GAPI_Assert(false && "Unsupported Mat depth");
+ }
+ return is;
+}
+
+I::OStream& operator<< (I::OStream& os, const cv::gapi::wip::draw::Text &t) {
+ return os << t.bottom_left_origin << t.color << t.ff << t.fs << t.lt << t.org << t.text << t.thick;
+}
+I::IStream& operator>> (I::IStream& is, cv::gapi::wip::draw::Text &t) {
+ return is >> t.bottom_left_origin >> t.color >> t.ff >> t.fs >> t.lt >> t.org >> t.text >> t.thick;
+}
+
+I::OStream& operator<< (I::OStream&, const cv::gapi::wip::draw::FText &) {
+ GAPI_Assert(false && "Serialization: Unsupported << for FText");
+}
+I::IStream& operator>> (I::IStream&, cv::gapi::wip::draw::FText &) {
+ GAPI_Assert(false && "Serialization: Unsupported >> for FText");
+}
+
+I::OStream& operator<< (I::OStream& os, const cv::gapi::wip::draw::Circle &c) {
+ return os << c.center << c.color << c.lt << c.radius << c.shift << c.thick;
+}
+I::IStream& operator>> (I::IStream& is, cv::gapi::wip::draw::Circle &c) {
+ return is >> c.center >> c.color >> c.lt >> c.radius >> c.shift >> c.thick;
+}
+
+I::OStream& operator<< (I::OStream& os, const cv::gapi::wip::draw::Rect &r) {
+ return os << r.color << r.lt << r.rect << r.shift << r.thick;
+}
+I::IStream& operator>> (I::IStream& is, cv::gapi::wip::draw::Rect &r) {
+ return is >> r.color >> r.lt >> r.rect >> r.shift >> r.thick;
+}
+
+I::OStream& operator<< (I::OStream& os, const cv::gapi::wip::draw::Image &i) {
+ return os << i.org << i.alpha << i.img;
+}
+I::IStream& operator>> (I::IStream& is, cv::gapi::wip::draw::Image &i) {
+ return is >> i.org >> i.alpha >> i.img;
+}
+
+I::OStream& operator<< (I::OStream& os, const cv::gapi::wip::draw::Mosaic &m) {
+ return os << m.cellSz << m.decim << m.mos;
+}
+I::IStream& operator>> (I::IStream& is, cv::gapi::wip::draw::Mosaic &m) {
+ return is >> m.cellSz >> m.decim >> m.mos;
+}
+
+I::OStream& operator<< (I::OStream& os, const cv::gapi::wip::draw::Poly &p) {
+ return os << p.color << p.lt << p.points << p.shift << p.thick;
+}
+I::IStream& operator>> (I::IStream& is, cv::gapi::wip::draw::Poly &p) {
+ return is >> p.color >> p.lt >> p.points >> p.shift >> p.thick;
+}
+
+I::OStream& operator<< (I::OStream& os, const cv::gapi::wip::draw::Line &l) {
+ return os << l.color << l.lt << l.pt1 << l.pt2 << l.shift << l.thick;
+}
+I::IStream& operator>> (I::IStream& is, cv::gapi::wip::draw::Line &l) {
+ return is >> l.color >> l.lt >> l.pt1 >> l.pt2 >> l.shift >> l.thick;
+}
+
+// G-API types /////////////////////////////////////////////////////////////////
+
+// Stubs (empty types)
+
+I::OStream& operator<< (I::OStream& os, cv::util::monostate ) {return os;}
+I::IStream& operator>> (I::IStream& is, cv::util::monostate &) {return is;}
+
+I::OStream& operator<< (I::OStream& os, const cv::GScalarDesc &) {return os;}
+I::IStream& operator>> (I::IStream& is, cv::GScalarDesc &) {return is;}
+
+I::OStream& operator<< (I::OStream& os, const cv::GOpaqueDesc &) {return os;}
+I::IStream& operator>> (I::IStream& is, cv::GOpaqueDesc &) {return is;}
+
+I::OStream& operator<< (I::OStream& os, const cv::GArrayDesc &) {return os;}
+I::IStream& operator>> (I::IStream& is, cv::GArrayDesc &) {return is;}
+
+#if !defined(GAPI_STANDALONE)
+I::OStream& operator<< (I::OStream& os, const cv::UMat &)
+{
+ GAPI_Assert(false && "Serialization: Unsupported << for UMat");
+ return os;
+}
+I::IStream& operator >> (I::IStream& is, cv::UMat &)
+{
+ GAPI_Assert(false && "Serialization: Unsupported >> for UMat");
+ return is;
+}
+#endif // !defined(GAPI_STANDALONE)
+
+I::OStream& operator<< (I::OStream& os, const cv::gapi::wip::IStreamSource::Ptr &)
+{
+ GAPI_Assert(false && "Serialization: Unsupported << for IStreamSource::Ptr");
+ return os;
+}
+I::IStream& operator >> (I::IStream& is, cv::gapi::wip::IStreamSource::Ptr &)
+{
+ GAPI_Assert("Serialization: Unsupported >> for IStreamSource::Ptr");
+ return is;
+}
+
+namespace
+{
+template<typename Ref, typename T, typename... Ts>
+struct putToStream;
+
+template<typename Ref>
+struct putToStream<Ref, std::tuple<>>
+{
+ static void put(I::OStream&, const Ref &)
+ {
+ GAPI_Assert(false && "Unsupported type for GArray/GOpaque serialization");
+ }
+};
+
+template<typename Ref, typename T, typename... Ts>
+struct putToStream<Ref, std::tuple<T, Ts...>>
+{
+ static void put(I::OStream& os, const Ref &r)
+ {
+ if (r.getKind() == cv::detail::GOpaqueTraits<T>::kind) {
+ os << r.template rref<T>();
+ } else {
+ putToStream<Ref, std::tuple<Ts...> >::put(os, r);
+ }
+ }
+};
+
+template<typename Ref, typename T, typename... Ts>
+struct getFromStream;
+
+template<typename Ref>
+struct getFromStream<Ref, std::tuple<>>
+{
+ static void get(I::IStream&, Ref &, cv::detail::OpaqueKind)
+ {
+ GAPI_Assert(false && "Unsupported type for GArray/GOpaque deserialization");
+ }
+};
+
+template<typename Ref, typename T, typename... Ts>
+struct getFromStream<Ref, std::tuple<T, Ts...>>
+{
+ static void get(I::IStream& is, Ref &r, cv::detail::OpaqueKind kind) {
+ if (kind == cv::detail::GOpaqueTraits<T>::kind) {
+ r.template reset<T>();
+ auto& val = r.template wref<T>();
+ is >> val;
+ } else {
+ getFromStream<Ref, std::tuple<Ts...> >::get(is, r, kind);
+ }
+ }
+};
+}
+
+I::OStream& operator<< (I::OStream& os, const cv::detail::VectorRef& ref)
+{
+ os << ref.getKind();
+ putToStream<cv::detail::VectorRef, cv::detail::GOpaqueTraitsArrayTypes>::put(os, ref);
+ return os;
+}
+I::IStream& operator >> (I::IStream& is, cv::detail::VectorRef& ref)
+{
+ cv::detail::OpaqueKind kind;
+ is >> kind;
+ getFromStream<cv::detail::VectorRef, cv::detail::GOpaqueTraitsArrayTypes>::get(is, ref, kind);
+ return is;
+}
+
+I::OStream& operator<< (I::OStream& os, const cv::detail::OpaqueRef& ref)
+{
+ os << ref.getKind();
+ putToStream<cv::detail::OpaqueRef, cv::detail::GOpaqueTraitsOpaqueTypes>::put(os, ref);
+ return os;
+}
+I::IStream& operator >> (I::IStream& is, cv::detail::OpaqueRef& ref)
+{
+ cv::detail::OpaqueKind kind;
+ is >> kind;
+ getFromStream<cv::detail::OpaqueRef, cv::detail::GOpaqueTraitsOpaqueTypes>::get(is, ref, kind);
+ return is;
+}
+// Enums and structures
+
+namespace {
+template<typename E> I::OStream& put_enum(I::OStream& os, E e) {
+ return os << static_cast<int>(e);
+}
+template<typename E> I::IStream& get_enum(I::IStream& is, E &e) {
+ int x{}; is >> x; e = static_cast<E>(x);
+ return is;
+}
+} // anonymous namespace
+
+I::OStream& operator<< (I::OStream& os, cv::GShape sh) {
+ return put_enum(os, sh);
+}
+I::IStream& operator>> (I::IStream& is, cv::GShape &sh) {
+ return get_enum<cv::GShape>(is, sh);
+}
+I::OStream& operator<< (I::OStream& os, cv::detail::ArgKind k) {
+ return put_enum(os, k);
+}
+I::IStream& operator>> (I::IStream& is, cv::detail::ArgKind &k) {
+ return get_enum<cv::detail::ArgKind>(is, k);
+}
+I::OStream& operator<< (I::OStream& os, cv::detail::OpaqueKind k) {
+ return put_enum(os, k);
+}
+I::IStream& operator>> (I::IStream& is, cv::detail::OpaqueKind &k) {
+ return get_enum<cv::detail::OpaqueKind>(is, k);
+}
+I::OStream& operator<< (I::OStream& os, cv::gimpl::Data::Storage s) {
+ return put_enum(os, s);
+}
+I::IStream& operator>> (I::IStream& is, cv::gimpl::Data::Storage &s) {
+ return get_enum<cv::gimpl::Data::Storage>(is, s);
+}
+
+I::OStream& operator<< (I::OStream& os, const cv::GArg &arg) {
+ // Only GOBJREF and OPAQUE_VAL kinds can be serialized/deserialized
+ GAPI_Assert( arg.kind == cv::detail::ArgKind::OPAQUE_VAL
+ || arg.kind == cv::detail::ArgKind::GOBJREF);
+
+ os << arg.kind << arg.opaque_kind;
+ if (arg.kind == cv::detail::ArgKind::GOBJREF) {
+ os << arg.get<cv::gimpl::RcDesc>();
+ } else {
+ GAPI_Assert(arg.kind == cv::detail::ArgKind::OPAQUE_VAL);
+ GAPI_Assert(arg.opaque_kind != cv::detail::OpaqueKind::CV_UNKNOWN);
+ switch (arg.opaque_kind) {
+ case cv::detail::OpaqueKind::CV_BOOL: os << arg.get<bool>(); break;
+ case cv::detail::OpaqueKind::CV_INT: os << arg.get<int>(); break;
+ case cv::detail::OpaqueKind::CV_DOUBLE: os << arg.get<double>(); break;
+ case cv::detail::OpaqueKind::CV_POINT: os << arg.get<cv::Point>(); break;
+ case cv::detail::OpaqueKind::CV_SIZE: os << arg.get<cv::Size>(); break;
+ case cv::detail::OpaqueKind::CV_RECT: os << arg.get<cv::Rect>(); break;
+ case cv::detail::OpaqueKind::CV_SCALAR: os << arg.get<cv::Scalar>(); break;
+ case cv::detail::OpaqueKind::CV_MAT: os << arg.get<cv::Mat>(); break;
+ default: GAPI_Assert(false && "GArg: Unsupported (unknown?) opaque value type");
+ }
+ }
+ return os;
+}
+
+I::IStream& operator>> (I::IStream& is, cv::GArg &arg) {
+ is >> arg.kind >> arg.opaque_kind;
+
+ // Only GOBJREF and OPAQUE_VAL kinds can be serialized/deserialized
+ GAPI_Assert( arg.kind == cv::detail::ArgKind::OPAQUE_VAL
+ || arg.kind == cv::detail::ArgKind::GOBJREF);
+
+ if (arg.kind == cv::detail::ArgKind::GOBJREF) {
+ cv::gimpl::RcDesc rc;
+ is >> rc;
+ arg = (GArg(rc));
+ } else {
+ GAPI_Assert(arg.kind == cv::detail::ArgKind::OPAQUE_VAL);
+ GAPI_Assert(arg.opaque_kind != cv::detail::OpaqueKind::CV_UNKNOWN);
+ switch (arg.opaque_kind) {
+#define HANDLE_CASE(E,T) case cv::detail::OpaqueKind::CV_##E: \
+ { T t{}; is >> t; arg = (cv::GArg(t)); } break
+ HANDLE_CASE(BOOL , bool);
+ HANDLE_CASE(INT , int);
+ HANDLE_CASE(DOUBLE , double);
+ HANDLE_CASE(POINT , cv::Point);
+ HANDLE_CASE(SIZE , cv::Size);
+ HANDLE_CASE(RECT , cv::Rect);
+ HANDLE_CASE(SCALAR , cv::Scalar);
+ HANDLE_CASE(MAT , cv::Mat);
+#undef HANDLE_CASE
+ default: GAPI_Assert(false && "GArg: Unsupported (unknown?) opaque value type");
+ }
+ }
+ return is;
+}
+
+I::OStream& operator<< (I::OStream& os, const cv::GKernel &k) {
+ return os << k.name << k.tag << k.outShapes;
+}
+I::IStream& operator>> (I::IStream& is, cv::GKernel &k) {
+ return is >> const_cast<std::string&>(k.name)
+ >> const_cast<std::string&>(k.tag)
+ >> const_cast<cv::GShapes&>(k.outShapes);
+}
+
+
+I::OStream& operator<< (I::OStream& os, const cv::GMatDesc &d) {
+ return os << d.depth << d.chan << d.size << d.planar << d.dims;
+}
+I::IStream& operator>> (I::IStream& is, cv::GMatDesc &d) {
+ return is >> d.depth >> d.chan >> d.size >> d.planar >> d.dims;
+}
+
+
+I::OStream& operator<< (I::OStream& os, const cv::gimpl::RcDesc &rc) {
+ // FIXME: HostCtor is not serialized!
+ return os << rc.id << rc.shape;
+}
+I::IStream& operator>> (I::IStream& is, cv::gimpl::RcDesc &rc) {
+ // FIXME: HostCtor is not deserialized!
+ return is >> rc.id >> rc.shape;
+}
+
+
+I::OStream& operator<< (I::OStream& os, const cv::gimpl::Op &op) {
+ return os << op.k << op.args << op.outs;
+}
+I::IStream& operator>> (I::IStream& is, cv::gimpl::Op &op) {
+ return is >> op.k >> op.args >> op.outs;
+}
+
+
+I::OStream& operator<< (I::OStream& os, const cv::gimpl::Data &d) {
+ // FIXME: HostCtor is not stored here!!
+ // FIXME: Storage may be incorrect for subgraph-to-graph process
+ return os << d.shape << d.rc << d.meta << d.storage << d.kind;
+}
+
+namespace
+{
+template<typename Ref, typename T, typename... Ts>
+struct initCtor;
+
+template<typename Ref>
+struct initCtor<Ref, std::tuple<>>
+{
+ static void init(cv::gimpl::Data&)
+ {
+ GAPI_Assert(false && "Unsupported type for GArray/GOpaque deserialization");
+ }
+};
+
+template<typename Ref, typename T, typename... Ts>
+struct initCtor<Ref, std::tuple<T, Ts...>>
+{
+ static void init(cv::gimpl::Data& d) {
+ if (d.kind == cv::detail::GOpaqueTraits<T>::kind) {
+ static std::function<void(Ref&)> ctor = [](Ref& ref){ref.template reset<T>();};
+ d.ctor = ctor;
+ } else {
+ initCtor<Ref, std::tuple<Ts...> >::init(d);
+ }
+ }
+};
+} // anonymous namespace
+
+I::IStream& operator>> (I::IStream& is, cv::gimpl::Data &d) {
+ // FIXME: HostCtor is not stored here!!
+ // FIXME: Storage may be incorrect for subgraph-to-graph process
+ is >> d.shape >> d.rc >> d.meta >> d.storage >> d.kind;
+ if (d.shape == cv::GShape::GARRAY)
+ {
+ initCtor<cv::detail::VectorRef, cv::detail::GOpaqueTraitsArrayTypes>::init(d);
+ }
+ else if (d.shape == cv::GShape::GOPAQUE)
+ {
+ initCtor<cv::detail::OpaqueRef, cv::detail::GOpaqueTraitsOpaqueTypes>::init(d);
+ }
+ return is;
+}
+
+
+I::OStream& operator<< (I::OStream& os, const cv::gimpl::DataObjectCounter &c) {
+ return os << c.m_next_data_id;
+}
+I::IStream& operator>> (I::IStream& is, cv::gimpl::DataObjectCounter &c) {
+ return is >> c.m_next_data_id;
+}
+
+
+I::OStream& operator<< (I::OStream& os, const cv::gimpl::Protocol &p) {
+ // NB: in_nhs/out_nhs are not written!
+ return os << p.inputs << p.outputs;
+}
+I::IStream& operator>> (I::IStream& is, cv::gimpl::Protocol &p) {
+ // NB: in_nhs/out_nhs are reconstructed at a later phase
+ return is >> p.inputs >> p.outputs;
+}
+
+
+void serialize( I::OStream& os
+ , const ade::Graph &g
+ , const std::vector<ade::NodeHandle> &nodes) {
+ cv::gimpl::GModel::ConstGraph cg(g);
+ serialize(os, g, cg.metadata().get<cv::gimpl::Protocol>(), nodes);
+}
+
+void serialize( I::OStream& os
+ , const ade::Graph &g
+ , const cv::gimpl::Protocol &p
+ , const std::vector<ade::NodeHandle> &nodes) {
+ cv::gimpl::GModel::ConstGraph cg(g);
+ GSerialized s;
+ for (auto &nh : nodes) {
+ switch (cg.metadata(nh).get<NodeType>().t)
+ {
+ case NodeType::OP: putOp (s, cg, nh); break;
+ case NodeType::DATA: putData(s, cg, nh); break;
+ default: util::throw_error(std::logic_error("Unknown NodeType"));
+ }
+ }
+ s.m_counter = cg.metadata().get<cv::gimpl::DataObjectCounter>();
+ s.m_proto = p;
+ os << s.m_ops << s.m_datas << s.m_counter << s.m_proto;
+}
+
+GSerialized deserialize(I::IStream &is) {
+ GSerialized s;
+ is >> s.m_ops >> s.m_datas >> s.m_counter >> s.m_proto;
+ return s;
+}
+
+void reconstruct(const GSerialized &s, ade::Graph &g) {
+ GAPI_Assert(g.nodes().empty());
+ for (const auto& d : s.m_datas) cv::gimpl::s11n::mkDataNode(g, d);
+ for (const auto& op : s.m_ops) cv::gimpl::s11n::mkOpNode(g, op);
+ cv::gimpl::s11n::linkNodes(g);
+
+ cv::gimpl::GModel::Graph gm(g);
+ gm.metadata().set(s.m_counter);
+ gm.metadata().set(s.m_proto);
+ cv::gimpl::s11n::relinkProto(g);
+ gm.metadata().set(cv::gimpl::Deserialized{});
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Streams /////////////////////////////////////////////////////////////////////
+
+const std::vector<char>& ByteMemoryOutStream::data() const {
+ return m_storage;
+}
+I::OStream& ByteMemoryOutStream::operator<< (uint32_t atom) {
+ m_storage.push_back(0xFF & (atom));
+ m_storage.push_back(0xFF & (atom >> 8));
+ m_storage.push_back(0xFF & (atom >> 16));
+ m_storage.push_back(0xFF & (atom >> 24));
+ return *this;
+}
+I::OStream& ByteMemoryOutStream::operator<< (bool atom) {
+ m_storage.push_back(atom ? 1 : 0);
+ return *this;
+}
+I::OStream& ByteMemoryOutStream::operator<< (char atom) {
+ m_storage.push_back(atom);
+ return *this;
+}
+I::OStream& ByteMemoryOutStream::operator<< (unsigned char atom) {
+ return *this << static_cast<char>(atom);
+}
+I::OStream& ByteMemoryOutStream::operator<< (short atom) {
+ static_assert(sizeof(short) == 2, "Expecting sizeof(short) == 2");
+ m_storage.push_back(0xFF & (atom));
+ m_storage.push_back(0xFF & (atom >> 8));
+ return *this;
+}
+I::OStream& ByteMemoryOutStream::operator<< (unsigned short atom) {
+ return *this << static_cast<short>(atom);
+}
+I::OStream& ByteMemoryOutStream::operator<< (int atom) {
+ static_assert(sizeof(int) == 4, "Expecting sizeof(int) == 4");
+ return *this << static_cast<uint32_t>(atom);
+}
+//I::OStream& ByteMemoryOutStream::operator<< (std::size_t atom) {
+// // NB: type truncated!
+// return *this << static_cast<uint32_t>(atom);
+//}
+I::OStream& ByteMemoryOutStream::operator<< (float atom) {
+ static_assert(sizeof(float) == 4, "Expecting sizeof(float) == 4");
+ uint32_t tmp = 0u;
+ memcpy(&tmp, &atom, sizeof(float));
+ return *this << static_cast<uint32_t>(htonl(tmp));
+}
+I::OStream& ByteMemoryOutStream::operator<< (double atom) {
+ static_assert(sizeof(double) == 8, "Expecting sizeof(double) == 8");
+ uint32_t tmp[2] = {0u};
+ memcpy(tmp, &atom, sizeof(double));
+ *this << static_cast<uint32_t>(htonl(tmp[0]));
+ *this << static_cast<uint32_t>(htonl(tmp[1]));
+ return *this;
+}
+I::OStream& ByteMemoryOutStream::operator<< (const std::string &str) {
+ //*this << static_cast<std::size_t>(str.size()); // N.B. Put type explicitly
+ *this << static_cast<uint32_t>(str.size()); // N.B. Put type explicitly
+ for (auto c : str) *this << c;
+ return *this;
+}
+
+ByteMemoryInStream::ByteMemoryInStream(const std::vector<char> &data)
+ : m_storage(data) {
+}
+I::IStream& ByteMemoryInStream::operator>> (uint32_t &atom) {
+ check(sizeof(uint32_t));
+ uint8_t x[4];
+ x[0] = static_cast<uint8_t>(m_storage[m_idx++]);
+ x[1] = static_cast<uint8_t>(m_storage[m_idx++]);
+ x[2] = static_cast<uint8_t>(m_storage[m_idx++]);
+ x[3] = static_cast<uint8_t>(m_storage[m_idx++]);
+ atom = ((x[0]) | (x[1] << 8) | (x[2] << 16) | (x[3] << 24));
+ return *this;
+}
+I::IStream& ByteMemoryInStream::operator>> (bool& atom) {
+ check(sizeof(char));
+ atom = (m_storage[m_idx++] == 0) ? false : true;
+ return *this;
+}
+I::IStream& ByteMemoryInStream::operator>> (char &atom) {
+ check(sizeof(char));
+ atom = m_storage[m_idx++];
+ return *this;
+}
+I::IStream& ByteMemoryInStream::operator>> (unsigned char &atom) {
+ char c{};
+ *this >> c;
+ atom = static_cast<unsigned char>(c);
+ return *this;
+}
+I::IStream& ByteMemoryInStream::operator>> (short &atom) {
+ static_assert(sizeof(short) == 2, "Expecting sizeof(short) == 2");
+ check(sizeof(short));
+ uint8_t x[2];
+ x[0] = static_cast<uint8_t>(m_storage[m_idx++]);
+ x[1] = static_cast<uint8_t>(m_storage[m_idx++]);
+ atom = ((x[0]) | (x[1] << 8));
+ return *this;
+}
+I::IStream& ByteMemoryInStream::operator>> (unsigned short &atom) {
+ short s{};
+ *this >> s;
+ atom = static_cast<unsigned short>(s);
+ return *this;
+}
+I::IStream& ByteMemoryInStream::operator>> (int& atom) {
+ static_assert(sizeof(int) == 4, "Expecting sizeof(int) == 4");
+ atom = static_cast<int>(getU32());
+ return *this;
+}
+//I::IStream& ByteMemoryInStream::operator>> (std::size_t& atom) {
+// // NB. Type was truncated!
+// atom = static_cast<std::size_t>(getU32());
+// return *this;
+//}
+I::IStream& ByteMemoryInStream::operator>> (float& atom) {
+ static_assert(sizeof(float) == 4, "Expecting sizeof(float) == 4");
+ uint32_t tmp = ntohl(getU32());
+ memcpy(&atom, &tmp, sizeof(float));
+ return *this;
+}
+I::IStream& ByteMemoryInStream::operator>> (double& atom) {
+ static_assert(sizeof(double) == 8, "Expecting sizeof(double) == 8");
+ uint32_t tmp[2] = {ntohl(getU32()), ntohl(getU32())};
+ memcpy(&atom, tmp, sizeof(double));
+ return *this;
+}
+I::IStream& ByteMemoryInStream::operator>> (std::string& str) {
+ //std::size_t sz = 0u;
+ uint32_t sz = 0u;
+ *this >> sz;
+ if (sz == 0u) {
+ str.clear();
+ } else {
+ str.resize(sz);
+ for (auto &&i : ade::util::iota(sz)) { *this >> str[i]; }
+ }
+ return *this;
+}
+
+GAPI_EXPORTS void serialize(I::OStream& os, const cv::GMetaArgs &ma) {
+ os << ma;
+}
+GAPI_EXPORTS void serialize(I::OStream& os, const cv::GRunArgs &ra) {
+ os << ra;
+}
+GAPI_EXPORTS GMetaArgs meta_args_deserialize(I::IStream& is) {
+ GMetaArgs s;
+ is >> s;
+ return s;
+}
+GAPI_EXPORTS GRunArgs run_args_deserialize(I::IStream& is) {
+ GRunArgs s;
+ is >> s;
+ return s;
+}
+
+
+} // namespace s11n
+} // namespace gimpl
+} // namespace cv
--- /dev/null
+#ifndef OPENCV_GAPI_COMMON_SERIALIZATION_HPP
+#define OPENCV_GAPI_COMMON_SERIALIZATION_HPP
+
+// 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) 2020 Intel Corporation
+
+#include <iostream>
+#include <fstream>
+#include <string.h>
+
+#include <ade/util/iota_range.hpp> // used in the vector<</>>
+
+#include "compiler/gmodel.hpp"
+#include "opencv2/gapi/render/render_types.hpp"
+
+#if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
+#pragma warning(disable: 4702)
+#endif
+
+namespace cv {
+namespace gimpl {
+namespace s11n {
+
+struct GSerialized {
+ std::vector<cv::gimpl::Op> m_ops;
+ std::vector<cv::gimpl::Data> m_datas;
+ cv::gimpl::DataObjectCounter m_counter;
+ cv::gimpl::Protocol m_proto;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Stream interfaces, so far temporary
+namespace I {
+ struct GAPI_EXPORTS OStream {
+ virtual ~OStream() = default;
+
+ // Define the native support for basic C++ types at the API level:
+ virtual OStream& operator<< (bool) = 0;
+ virtual OStream& operator<< (char) = 0;
+ virtual OStream& operator<< (unsigned char) = 0;
+ virtual OStream& operator<< (short) = 0;
+ virtual OStream& operator<< (unsigned short) = 0;
+ virtual OStream& operator<< (int) = 0;
+ //virtual OStream& operator<< (std::size_t) = 0;
+ virtual OStream& operator<< (uint32_t) = 0;
+ virtual OStream& operator<< (float) = 0;
+ virtual OStream& operator<< (double) = 0;
+ virtual OStream& operator<< (const std::string&) = 0;
+ };
+
+ struct GAPI_EXPORTS IStream {
+ virtual ~IStream() = default;
+
+ virtual IStream& operator>> (bool &) = 0;
+ virtual IStream& operator>> (char &) = 0;
+ virtual IStream& operator>> (unsigned char &) = 0;
+ virtual IStream& operator>> (short &) = 0;
+ virtual IStream& operator>> (unsigned short &) = 0;
+ virtual IStream& operator>> (int &) = 0;
+ virtual IStream& operator>> (float &) = 0;
+ virtual IStream& operator>> (double &) = 0;
+ //virtual IStream& operator>> (std::size_t &) = 0;
+ virtual IStream& operator >> (uint32_t &) = 0;
+ virtual IStream& operator>> (std::string &) = 0;
+ };
+} // namespace I
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// S11N operators
+// Note: operators for basic types are defined in IStream/OStream
+
+// OpenCV types ////////////////////////////////////////////////////////////////
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::Point &pt);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::Point &pt);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::Size &sz);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::Size &sz);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::Rect &rc);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::Rect &rc);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::Scalar &s);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::Scalar &s);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::Mat &m);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::Mat &m);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::gapi::wip::draw::Text &t);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::gapi::wip::draw::Text &t);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream&, const cv::gapi::wip::draw::FText &);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream&, cv::gapi::wip::draw::FText &);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::gapi::wip::draw::Circle &c);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::gapi::wip::draw::Circle &c);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::gapi::wip::draw::Rect &r);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::gapi::wip::draw::Rect &r);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::gapi::wip::draw::Image &i);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::gapi::wip::draw::Image &i);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::gapi::wip::draw::Mosaic &m);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::gapi::wip::draw::Mosaic &m);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::gapi::wip::draw::Poly &p);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::gapi::wip::draw::Poly &p);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::gapi::wip::draw::Line &l);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::gapi::wip::draw::Line &l);
+
+// G-API types /////////////////////////////////////////////////////////////////
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, cv::util::monostate );
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::util::monostate &);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, cv::GShape shape);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::GShape &shape);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, cv::detail::ArgKind k);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::detail::ArgKind &k);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, cv::detail::OpaqueKind k);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::detail::OpaqueKind &k);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, cv::gimpl::Data::Storage s);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::gimpl::Data::Storage &s);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::gimpl::DataObjectCounter &c);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::gimpl::DataObjectCounter &c);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::gimpl::Protocol &p);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::gimpl::Protocol &p);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::GArg &arg);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::GArg &arg);
+
+//Forward declaration
+//I::OStream& operator<< (I::OStream& os, const cv::GRunArg &arg);
+//I::IStream& operator>> (I::IStream& is, cv::GRunArg &arg);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::GKernel &k);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::GKernel &k);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::GMatDesc &d);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::GMatDesc &d);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::GScalarDesc &);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::GScalarDesc &);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::GOpaqueDesc &);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::GOpaqueDesc &);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::GArrayDesc &);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::GArrayDesc &);
+
+#if !defined(GAPI_STANDALONE)
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::UMat &);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::UMat &);
+#endif // !defined(GAPI_STANDALONE)
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::gapi::wip::IStreamSource::Ptr &);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::gapi::wip::IStreamSource::Ptr &);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::detail::VectorRef &);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::detail::VectorRef &);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::detail::OpaqueRef &);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::detail::OpaqueRef &);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::gimpl::RcDesc &rc);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::gimpl::RcDesc &rc);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::gimpl::Op &op);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::gimpl::Op &op);
+
+GAPI_EXPORTS I::OStream& operator<< (I::OStream& os, const cv::gimpl::Data &op);
+GAPI_EXPORTS I::IStream& operator>> (I::IStream& is, cv::gimpl::Data &op);
+
+// The top-level serialization routine.
+// Note it is just a single function which takes a GModel and a list of nodes
+// and writes the data to the stream (recursively)
+GAPI_EXPORTS void serialize( I::OStream& os
+ , const ade::Graph &g
+ , const std::vector<ade::NodeHandle> &nodes);
+
+// The top-level serialization routine.
+// Note it is just a single function which takes a GModel and a list of nodes
+// and writes the data to the stream (recursively)
+GAPI_EXPORTS void serialize( I::OStream& os
+ , const ade::Graph &g
+ , const cv::gimpl::Protocol &p
+ , const std::vector<ade::NodeHandle> &nodes);
+
+// The top-level deserialization routineS.
+// Unfortunately the deserialization is a two-step process:
+// 1. First we decode a stream into some intermediate representation
+// (called "GSerialized");
+// 2. Then we produce an ade::Graph from this intermediate representation.
+//
+// An ade::Graph can't be produced from the stream immediately
+// since every GCompiled object has its own unique ade::Graph, so
+// we can't do it once and for all since every compilation process
+// is individual and _is_ altering the ade::Graph state (structure and metadata).
+// At the same time, we can't hold the reference to "is" within the GComputation
+// forever since this input stream may be associated with an external resource
+// and have side effects.
+//
+// Summarizing, the `deserialize()` happens *once per GComputation* immediately
+// during the cv::gapi::deserialize<GComputation>(), and `reconstruct()` happens
+// on every compilation process issued for this GComputation.
+GAPI_EXPORTS GSerialized deserialize(I::IStream& is);
+GAPI_EXPORTS void reconstruct(const GSerialized &s, ade::Graph &g);
+
+// Legacy //////////////////////////////////////////////////////////////////////
+// Generic: unordered_map serialization ////////////////////////////////////////
+template<typename K, typename V>
+I::OStream& operator<< (I::OStream& os, const std::unordered_map<K, V> &m) {
+ //const std::size_t sz = m.size(); // explicitly specify type
+ const uint32_t sz = (uint32_t)m.size(); // explicitly specify type
+ os << sz;
+ for (auto &&it : m) os << it.first << it.second;
+ return os;
+}
+template<typename K, typename V>
+I::IStream& operator>> (I::IStream& is, std::unordered_map<K, V> &m) {
+ m.clear();
+ //std::size_t sz = 0u;
+ uint32_t sz = 0u;
+ is >> sz;
+ if (sz != 0u) {
+ for (auto &&i : ade::util::iota(sz)) {
+ (void) i;
+ K k{};
+ V v{};
+ is >> k >> v;
+ m.insert({k,v});
+ }
+ GAPI_Assert(sz == m.size());
+ }
+ return is;
+}
+
+// Generic: variant serialization //////////////////////////////////////////////
+namespace detail { // FIXME: breaks old code
+template<typename V>
+I::OStream& put_v(I::OStream&, const V&, std::size_t) {
+ GAPI_Assert(false && "variant>>: requested index is invalid");
+};
+template<typename V, typename X, typename... Xs>
+I::OStream& put_v(I::OStream& os, const V& v, std::size_t x) {
+ return (x == 0u)
+ ? os << cv::util::get<X>(v)
+ : put_v<V, Xs...>(os, v, x-1);
+}
+template<typename V>
+I::IStream& get_v(I::IStream&, V&, std::size_t, std::size_t) {
+ GAPI_Assert(false && "variant<<: requested index is invalid");
+}
+template<typename V, typename X, typename... Xs>
+I::IStream& get_v(I::IStream& is, V& v, std::size_t i, std::size_t gi) {
+ if (i == gi) {
+ X x{};
+ is >> x;
+ v = std::move(x);
+ return is;
+ } else return get_v<V, Xs...>(is, v, i+1, gi);
+}
+} // namespace detail FIXME: breaks old code
+
+template<typename... Ts>
+I::OStream& operator<< (I::OStream& os, const cv::util::variant<Ts...> &v) {
+ os << (uint32_t)v.index();
+ return detail::put_v<cv::util::variant<Ts...>, Ts...>(os, v, v.index());
+}
+template<typename... Ts>
+I::IStream& operator>> (I::IStream& is, cv::util::variant<Ts...> &v) {
+ int idx = -1;
+ is >> idx;
+ GAPI_Assert(idx >= 0 && idx < (int)sizeof...(Ts));
+ return detail::get_v<cv::util::variant<Ts...>, Ts...>(is, v, 0u, idx);
+}
+
+// Generic: vector serialization ///////////////////////////////////////////////
+// Moved here to fix CLang issues https://clang.llvm.org/compatibility.html
+// Unqualified lookup in templates
+template<typename T>
+I::OStream& operator<< (I::OStream& os, const std::vector<T> &ts) {
+ //const std::size_t sz = ts.size(); // explicitly specify type
+ const uint32_t sz = (uint32_t)ts.size(); // explicitly specify type
+ os << sz;
+ for (auto &&v : ts) os << v;
+ return os;
+}
+template<typename T>
+I::IStream& operator >> (I::IStream& is, std::vector<T> &ts) {
+ //std::size_t sz = 0u;
+ uint32_t sz = 0u;
+ is >> sz;
+ if (sz == 0u) {
+ ts.clear();
+ }
+ else {
+ ts.resize(sz);
+ for (auto &&i : ade::util::iota(sz)) is >> ts[i];
+ }
+ return is;
+}
+
+// FIXME: Basic Stream implementaions //////////////////////////////////////////
+
+// Basic in-memory stream implementations.
+class GAPI_EXPORTS ByteMemoryOutStream final: public I::OStream {
+ std::vector<char> m_storage;
+
+ //virtual I::OStream& operator << (uint32_t) override;
+ //virtual I::OStream& operator<< (uint32_t) final;
+public:
+ const std::vector<char>& data() const;
+
+ virtual I::OStream& operator<< (bool) override;
+ virtual I::OStream& operator<< (char) override;
+ virtual I::OStream& operator<< (unsigned char) override;
+ virtual I::OStream& operator<< (short) override;
+ virtual I::OStream& operator<< (unsigned short) override;
+ virtual I::OStream& operator<< (int) override;
+ //virtual I::OStream& operator<< (std::size_t) override;
+ virtual I::OStream& operator<< (float) override;
+ virtual I::OStream& operator<< (double) override;
+ virtual I::OStream& operator<< (const std::string&) override;
+ virtual I::OStream& operator<< (uint32_t) override;
+};
+
+class GAPI_EXPORTS ByteMemoryInStream final: public I::IStream {
+ const std::vector<char>& m_storage;
+ size_t m_idx = 0u;
+
+ void check(std::size_t n) { (void) n; GAPI_DbgAssert(m_idx+n-1 < m_storage.size()); }
+ uint32_t getU32() { uint32_t v{}; *this >> v; return v; };
+
+ //virtual I::IStream& operator>> (uint32_t &) final;
+
+public:
+ explicit ByteMemoryInStream(const std::vector<char> &data);
+
+ virtual I::IStream& operator>> (bool &) override;
+ virtual I::IStream& operator>> (char &) override;
+ virtual I::IStream& operator>> (unsigned char &) override;
+ virtual I::IStream& operator>> (short &) override;
+ virtual I::IStream& operator>> (unsigned short &) override;
+ virtual I::IStream& operator>> (int &) override;
+ virtual I::IStream& operator>> (float &) override;
+ virtual I::IStream& operator>> (double &) override;
+ //virtual I::IStream& operator>> (std::size_t &) override;
+ virtual I::IStream& operator >> (uint32_t &) override;
+ virtual I::IStream& operator>> (std::string &) override;
+};
+
+GAPI_EXPORTS void serialize(I::OStream& os, const cv::GMetaArgs &ma);
+GAPI_EXPORTS void serialize(I::OStream& os, const cv::GRunArgs &ra);
+GAPI_EXPORTS GMetaArgs meta_args_deserialize(I::IStream& is);
+GAPI_EXPORTS GRunArgs run_args_deserialize(I::IStream& is);
+
+} // namespace s11n
+} // namespace gimpl
+} // namespace cv
+
+#endif // OPENCV_GAPI_COMMON_SERIALIZATION_HPP
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
//
// If not, we need to introduce that!
using GCPUModel = ade::TypedGraph
- < cv::gimpl::Unit
+ < cv::gimpl::CPUUnit
, cv::gimpl::Protocol
>;
// FIXME: Same issue with Typed and ConstTyped
using GConstGCPUModel = ade::ConstTypedGraph
- < cv::gimpl::Unit
+ < cv::gimpl::CPUUnit
, cv::gimpl::Protocol
>;
{
GCPUModel gm(graph);
auto cpu_impl = cv::util::any_cast<cv::GCPUKernel>(impl.opaque);
- gm.metadata(op_node).set(cv::gimpl::Unit{cpu_impl});
+ gm.metadata(op_node).set(cv::gimpl::CPUUnit{cpu_impl});
}
virtual EPtr compile(const ade::Graph &graph,
- const cv::GCompileArgs &,
+ const cv::GCompileArgs &compileArgs,
const std::vector<ade::NodeHandle> &nodes) const override
{
- return EPtr{new cv::gimpl::GCPUExecutable(graph, nodes)};
+ return EPtr{new cv::gimpl::GCPUExecutable(graph, compileArgs, nodes)};
}
};
}
// GCPUExecutable implementation //////////////////////////////////////////////
cv::gimpl::GCPUExecutable::GCPUExecutable(const ade::Graph &g,
+ const cv::GCompileArgs &compileArgs,
const std::vector<ade::NodeHandle> &nodes)
- : m_g(g), m_gm(m_g)
+ : m_g(g), m_gm(m_g), m_compileArgs(compileArgs)
{
// Convert list of operations (which is topologically sorted already)
// into an execution script.
+ GConstGCPUModel gcm(m_g);
for (auto &nh : nodes)
{
switch (m_gm.metadata(nh).get<NodeType>().t)
{
- case NodeType::OP: m_script.push_back({nh, GModel::collectOutputMeta(m_gm, nh)}); break;
+ case NodeType::OP:
+ {
+ m_script.push_back({nh, GModel::collectOutputMeta(m_gm, nh)});
+
+ // If kernel is stateful then prepare storage for its state.
+ GCPUKernel k = gcm.metadata(nh).get<CPUUnit>().k;
+ if (k.m_isStateful)
+ {
+ m_nodesToStates[nh] = GArg{ };
+ }
+ break;
+ }
case NodeType::DATA:
{
m_dataNodes.push_back(nh);
if (desc.storage == Data::Storage::INTERNAL && desc.shape == GShape::GMAT)
{
const auto mat_desc = util::get<cv::GMatDesc>(desc.meta);
- auto& mat = m_res.slot<cv::gapi::own::Mat>()[desc.rc];
+ auto& mat = m_res.slot<cv::Mat>()[desc.rc];
createMat(mat_desc, mat);
}
break;
default: util::throw_error(std::logic_error("Unsupported NodeType type"));
}
}
+
+ // For each stateful kernel call 'setup' user callback to initialize state.
+ setupKernelStates();
}
// FIXME: Document what it does
const cv::gimpl::RcDesc &ref = arg.get<cv::gimpl::RcDesc>();
switch (ref.shape)
{
- case GShape::GMAT: return GArg(m_res.slot<cv::gapi::own::Mat>() [ref.id]);
+ case GShape::GMAT: return GArg(m_res.slot<cv::Mat>() [ref.id]);
case GShape::GSCALAR: return GArg(m_res.slot<cv::Scalar>()[ref.id]);
// Note: .at() is intentional for GArray and GOpaque as objects MUST be already there
// (and constructed by either bindIn/Out or resetInternal)
}
}
+void cv::gimpl::GCPUExecutable::setupKernelStates()
+{
+ GConstGCPUModel gcm(m_g);
+ for (auto& nodeToState : m_nodesToStates)
+ {
+ auto& kernelNode = nodeToState.first;
+ auto& kernelState = nodeToState.second;
+
+ const GCPUKernel& kernel = gcm.metadata(kernelNode).get<CPUUnit>().k;
+ kernel.m_setupF(GModel::collectInputMeta(m_gm, kernelNode),
+ m_gm.metadata(kernelNode).get<Op>().args,
+ kernelState,
+ m_compileArgs);
+ }
+}
+
+void cv::gimpl::GCPUExecutable::handleNewStream()
+{
+ m_newStreamStarted = true;
+}
+
void cv::gimpl::GCPUExecutable::run(std::vector<InObj> &&input_objs,
std::vector<OutObj> &&output_objs)
{
{
const auto &desc = gm.metadata(nh).get<Data>();
- if ( desc.storage == Data::Storage::INTERNAL
+ if ( desc.storage == Data::Storage::INTERNAL // FIXME: to reconsider
&& !util::holds_alternative<util::monostate>(desc.ctor))
{
// FIXME: Note that compile-time constant data objects (like
}
}
+ // In case if new video-stream happens - for each stateful kernel
+ // call 'setup' user callback to re-initialize state.
+ if (m_newStreamStarted)
+ {
+ setupKernelStates();
+ m_newStreamStarted = false;
+ }
+
// OpenCV backend execution is not a rocket science at all.
// Simply invoke our kernels in the proper order.
GConstGCPUModel gcm(m_g);
// Obtain our real execution unit
// TODO: Should kernels be copyable?
- GCPUKernel k = gcm.metadata(op_info.nh).get<Unit>().k;
+ GCPUKernel k = gcm.metadata(op_info.nh).get<CPUUnit>().k;
// Initialize kernel's execution context:
// - Input parameters
using namespace std::placeholders;
ade::util::transform(op.args,
- std::back_inserter(context.m_args),
- std::bind(&GCPUExecutable::packArg, this, _1));
+ std::back_inserter(context.m_args),
+ std::bind(&GCPUExecutable::packArg, this, _1));
// - Output parameters.
// FIXME: pre-allocate internal Mats, etc, according to the known meta
context.m_results[out_port] = magazine::getObjPtr(m_res, out_desc);
}
+ // For stateful kernel add state to its execution context
+ if (k.m_isStateful)
+ {
+ context.m_state = m_nodesToStates.at(op_info.nh);
+ }
+
// Now trigger the executable unit
- k.apply(context);
+ k.m_runF(context);
//As Kernels are forbidden to allocate memory for (Mat) outputs,
//this code seems redundant, at least for Mats
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GCPUBACKEND_HPP
namespace cv { namespace gimpl {
-struct Unit
+struct CPUUnit
{
static const char *name() { return "HostKernel"; }
GCPUKernel k;
{
const ade::Graph &m_g;
GModel::ConstGraph m_gm;
+ const cv::GCompileArgs m_compileArgs;
struct OperationInfo
{
// Execution script, currently absolutely naive
std::vector<OperationInfo> m_script;
+
+ // TODO: Check that it is thread-safe
+ // Map of stateful kernel nodes to their kernels' states
+ std::unordered_map<ade::NodeHandle, GArg,
+ ade::HandleHasher<ade::Node>> m_nodesToStates;
+
// List of all resources in graph (both internal and external)
std::vector<ade::NodeHandle> m_dataNodes;
// Actual data of all resources in graph (both internal and external)
Mag m_res;
+
+ // Flag which identifies if new stream was started
+ bool m_newStreamStarted = false;
+
GArg packArg(const GArg &arg);
+ void setupKernelStates();
public:
GCPUExecutable(const ade::Graph &graph,
+ const cv::GCompileArgs &compileArgs,
const std::vector<ade::NodeHandle> &nodes);
virtual inline bool canReshape() const override { return false; }
util::throw_error(std::logic_error("GCPUExecutable::reshape() should never be called"));
}
+ virtual void handleNewStream() override;
+
virtual void run(std::vector<InObj> &&input_objs,
std::vector<OutObj> &&output_objs) override;
};
#include "precomp.hpp"
+#include "gnnparsers.hpp"
#include <opencv2/gapi/core.hpp>
#include <opencv2/gapi/cpu/core.hpp>
}
};
+GAPI_OCV_KERNEL(GCPUParseSSDBL, cv::gapi::nn::parsers::GParseSSDBL)
+{
+ static void run(const cv::Mat& in_ssd_result,
+ const cv::Size& in_size,
+ const float confidence_threshold,
+ const int filter_label,
+ std::vector<cv::Rect>& out_boxes,
+ std::vector<int>& out_labels)
+ {
+ cv::parseSSDBL(in_ssd_result, in_size, confidence_threshold, filter_label, out_boxes, out_labels);
+ }
+};
+
+GAPI_OCV_KERNEL(GOCVParseSSD, cv::gapi::nn::parsers::GParseSSD)
+{
+ static void run(const cv::Mat& in_ssd_result,
+ const cv::Size& in_size,
+ const float confidence_threshold,
+ const bool alignment_to_square,
+ const bool filter_out_of_bounds,
+ std::vector<cv::Rect>& out_boxes)
+ {
+ cv::parseSSD(in_ssd_result, in_size, confidence_threshold, alignment_to_square, filter_out_of_bounds, out_boxes);
+ }
+};
+
+GAPI_OCV_KERNEL(GCPUParseYolo, cv::gapi::nn::parsers::GParseYolo)
+{
+ static void run(const cv::Mat& in_yolo_result,
+ const cv::Size& in_size,
+ const float confidence_threshold,
+ const float nms_threshold,
+ const std::vector<float>& anchors,
+ std::vector<cv::Rect>& out_boxes,
+ std::vector<int>& out_labels)
+ {
+ cv::parseYolo(in_yolo_result, in_size, confidence_threshold, nms_threshold, anchors, out_boxes, out_labels);
+ }
+};
+
+GAPI_OCV_KERNEL(GCPUSize, cv::gapi::core::GSize)
+{
+ static void run(const cv::Mat& in, cv::Size& out)
+ {
+ out.width = in.cols;
+ out.height = in.rows;
+ }
+};
+
+GAPI_OCV_KERNEL(GCPUSizeR, cv::gapi::core::GSizeR)
+{
+ static void run(const cv::Rect& in, cv::Size& out)
+ {
+ out.width = in.width;
+ out.height = in.height;
+ }
+};
cv::gapi::GKernelPackage cv::gapi::core::cpu::kernels()
{
, GCPUNormalize
, GCPUWarpPerspective
, GCPUWarpAffine
+ , GCPUParseSSDBL
+ , GOCVParseSSD
+ , GCPUParseYolo
+ , GCPUSize
+ , GCPUSizeR
>();
return pkg;
}
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
}
};
+GAPI_OCV_KERNEL(GCPULaplacian, cv::gapi::imgproc::GLaplacian)
+{
+ static void run(const cv::Mat& in, int ddepth, int ksize, double scale,
+ double delta, int borderType, cv::Mat &out)
+ {
+ cv::Laplacian(in, out, ddepth, ksize, scale, delta, borderType);
+ }
+};
+
+GAPI_OCV_KERNEL(GCPUBilateralFilter, cv::gapi::imgproc::GBilateralFilter)
+{
+ static void run(const cv::Mat& in, int d, double sigmaColor,
+ double sigmaSpace, int borderType, cv::Mat &out)
+ {
+ cv::bilateralFilter(in, out, d, sigmaColor, sigmaSpace, borderType);
+ }
+};
+
GAPI_OCV_KERNEL(GCPUEqualizeHist, cv::gapi::imgproc::GEqHist)
{
static void run(const cv::Mat& in, cv::Mat &out)
}
};
+GAPI_OCV_KERNEL(GCPUGoodFeatures, cv::gapi::imgproc::GGoodFeatures)
+{
+ static void run(const cv::Mat& image, int maxCorners, double qualityLevel, double minDistance,
+ const cv::Mat& mask, int blockSize, bool useHarrisDetector, double k,
+ std::vector<cv::Point2f> &out)
+ {
+ cv::goodFeaturesToTrack(image, out, maxCorners, qualityLevel, minDistance,
+ mask, blockSize, useHarrisDetector, k);
+ }
+};
+
GAPI_OCV_KERNEL(GCPURGB2YUV, cv::gapi::imgproc::GRGB2YUV)
{
static void run(const cv::Mat& in, cv::Mat &out)
, GCPUDilate
, GCPUSobel
, GCPUSobelXY
+ , GCPULaplacian
+ , GCPUBilateralFilter
, GCPUCanny
+ , GCPUGoodFeatures
, GCPUEqualizeHist
, GCPURGB2YUV
, GCPUYUV2RGB
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
#include <opencv2/gapi/cpu/gcpukernel.hpp>
-const cv::gapi::own::Mat& cv::GCPUContext::inMat(int input)
+const cv::Mat& cv::GCPUContext::inMat(int input)
{
- return inArg<cv::gapi::own::Mat>(input);
+ return inArg<cv::Mat>(input);
}
-cv::gapi::own::Mat& cv::GCPUContext::outMatR(int output)
+cv::Mat& cv::GCPUContext::outMatR(int output)
{
- return *util::get<cv::gapi::own::Mat*>(m_results.at(output));
+ return *util::get<cv::Mat*>(m_results.at(output));
}
const cv::Scalar& cv::GCPUContext::inVal(int input)
{
}
-cv::GCPUKernel::GCPUKernel(const GCPUKernel::F &f)
- : m_f(f)
+cv::GCPUKernel::GCPUKernel(const GCPUKernel::RunF &runF, const GCPUKernel::SetupF &setupF)
+ : m_runF(runF), m_setupF(setupF), m_isStateful(m_setupF != nullptr)
{
}
-
-void cv::GCPUKernel::apply(GCPUContext &ctx)
-{
- GAPI_Assert(m_f);
- m_f(ctx);
-}
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#include "precomp.hpp"
+
+#include <opencv2/gapi/video.hpp>
+#include <opencv2/gapi/cpu/video.hpp>
+#include <opencv2/gapi/cpu/gcpukernel.hpp>
+
+#ifdef HAVE_OPENCV_VIDEO
+#include <opencv2/video.hpp>
+#endif // HAVE_OPENCV_VIDEO
+
+#ifdef HAVE_OPENCV_VIDEO
+
+GAPI_OCV_KERNEL(GCPUBuildOptFlowPyramid, cv::gapi::video::GBuildOptFlowPyramid)
+{
+ static void run(const cv::Mat &img,
+ const cv::Size &winSize,
+ const cv::Scalar &maxLevel,
+ bool withDerivatives,
+ int pyrBorder,
+ int derivBorder,
+ bool tryReuseInputImage,
+ std::vector<cv::Mat> &outPyr,
+ cv::Scalar &outMaxLevel)
+ {
+ outMaxLevel = cv::buildOpticalFlowPyramid(img, outPyr, winSize,
+ static_cast<int>(maxLevel[0]),
+ withDerivatives, pyrBorder,
+ derivBorder, tryReuseInputImage);
+ }
+};
+
+GAPI_OCV_KERNEL(GCPUCalcOptFlowLK, cv::gapi::video::GCalcOptFlowLK)
+{
+ static void run(const cv::Mat &prevImg,
+ const cv::Mat &nextImg,
+ const std::vector<cv::Point2f> &prevPts,
+ const std::vector<cv::Point2f> &predPts,
+ const cv::Size &winSize,
+ const cv::Scalar &maxLevel,
+ const cv::TermCriteria &criteria,
+ int flags,
+ double minEigThresh,
+ std::vector<cv::Point2f> &outPts,
+ std::vector<uchar> &status,
+ std::vector<float> &err)
+ {
+ if (flags & cv::OPTFLOW_USE_INITIAL_FLOW)
+ outPts = predPts;
+ cv::calcOpticalFlowPyrLK(prevImg, nextImg, prevPts, outPts, status, err, winSize,
+ static_cast<int>(maxLevel[0]), criteria, flags, minEigThresh);
+ }
+};
+
+GAPI_OCV_KERNEL(GCPUCalcOptFlowLKForPyr, cv::gapi::video::GCalcOptFlowLKForPyr)
+{
+ static void run(const std::vector<cv::Mat> &prevPyr,
+ const std::vector<cv::Mat> &nextPyr,
+ const std::vector<cv::Point2f> &prevPts,
+ const std::vector<cv::Point2f> &predPts,
+ const cv::Size &winSize,
+ const cv::Scalar &maxLevel,
+ const cv::TermCriteria &criteria,
+ int flags,
+ double minEigThresh,
+ std::vector<cv::Point2f> &outPts,
+ std::vector<uchar> &status,
+ std::vector<float> &err)
+ {
+ if (flags & cv::OPTFLOW_USE_INITIAL_FLOW)
+ outPts = predPts;
+ cv::calcOpticalFlowPyrLK(prevPyr, nextPyr, prevPts, outPts, status, err, winSize,
+ static_cast<int>(maxLevel[0]), criteria, flags, minEigThresh);
+ }
+};
+
+cv::gapi::GKernelPackage cv::gapi::video::cpu::kernels()
+{
+ static auto pkg = cv::gapi::kernels
+ < GCPUBuildOptFlowPyramid
+ , GCPUCalcOptFlowLK
+ , GCPUCalcOptFlowLKForPyr
+ >();
+ return pkg;
+}
+
+#else
+
+cv::gapi::GKernelPackage cv::gapi::video::cpu::kernels()
+{
+ return GKernelPackage();
+}
+
+#endif // HAVE_OPENCV_VIDEO
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#include "gnnparsers.hpp"
+
+namespace cv
+{
+namespace gapi
+{
+namespace nn
+{
+class YoloParser
+{
+public:
+ YoloParser(const float* out, const int side, const int lcoords, const int lclasses)
+ : m_out(out), m_side(side), m_lcoords(lcoords), m_lclasses(lclasses)
+ {}
+
+ float scale(const int i, const int b)
+ {
+ int obj_index = index(i, b, m_lcoords);
+ return m_out[obj_index];
+ }
+
+ double x(const int i, const int b)
+ {
+ int box_index = index(i, b, 0);
+ int col = i % m_side;
+ return (col + m_out[box_index]) / m_side;
+ }
+
+ double y(const int i, const int b)
+ {
+ int box_index = index(i, b, 0);
+ int row = i / m_side;
+ return (row + m_out[box_index + m_side * m_side]) / m_side;
+ }
+
+ double width(const int i, const int b, const float anchor)
+ {
+ int box_index = index(i, b, 0);
+ return std::exp(m_out[box_index + 2 * m_side * m_side]) * anchor / m_side;
+ }
+
+ double height(const int i, const int b, const float anchor)
+ {
+ int box_index = index(i, b, 0);
+ return std::exp(m_out[box_index + 3 * m_side * m_side]) * anchor / m_side;
+ }
+
+ float classConf(const int i, const int b, const int label)
+ {
+ int class_index = index(i, b, m_lcoords + 1 + label);
+ return m_out[class_index];
+ }
+
+ cv::Rect toBox(const double x, const double y, const double h, const double w, const cv::Size& in_sz)
+ {
+ auto h_scale = in_sz.height;
+ auto w_scale = in_sz.width;
+ cv::Rect r;
+ r.x = static_cast<int>((x - w / 2) * w_scale);
+ r.y = static_cast<int>((y - h / 2) * h_scale);
+ r.width = static_cast<int>(w * w_scale);
+ r.height = static_cast<int>(h * h_scale);
+ return r;
+ }
+
+private:
+ const float* m_out = nullptr;
+ int m_side = 0, m_lcoords = 0, m_lclasses = 0;
+
+ int index(const int i, const int b, const int entry)
+ {
+ return b * m_side * m_side * (m_lcoords + m_lclasses + 1) + entry * m_side * m_side + i;
+ }
+};
+
+struct YoloParams
+{
+ int num = 5;
+ int coords = 4;
+};
+
+struct Detection
+{
+ Detection(const cv::Rect& in_rect, const float in_conf, const int in_label)
+ : rect(in_rect), conf(in_conf), label(in_label)
+ {}
+ cv::Rect rect;
+ float conf = 0.0f;
+ int label = 0;
+};
+
+class SSDParser
+{
+public:
+ SSDParser(const cv::MatSize& in_ssd_dims, const cv::Size& in_size, const float* data)
+ : m_dims(in_ssd_dims), m_maxProp(in_ssd_dims[2]), m_objSize(in_ssd_dims[3]),
+ m_data(data), m_surface(cv::Rect({0,0}, in_size)), m_size(in_size)
+ {
+ GAPI_Assert(in_ssd_dims.dims() == 4u); // Fixed output layout
+ GAPI_Assert(m_objSize == 7); // Fixed SSD object size
+ }
+
+ void adjustBoundingBox(cv::Rect& boundingBox)
+ {
+ auto w = boundingBox.width;
+ auto h = boundingBox.height;
+
+ boundingBox.x -= static_cast<int>(0.067 * w);
+ boundingBox.y -= static_cast<int>(0.028 * h);
+
+ boundingBox.width += static_cast<int>(0.15 * w);
+ boundingBox.height += static_cast<int>(0.13 * h);
+
+ if (boundingBox.width < boundingBox.height)
+ {
+ auto dx = (boundingBox.height - boundingBox.width);
+ boundingBox.x -= dx / 2;
+ boundingBox.width += dx;
+ }
+ else
+ {
+ auto dy = (boundingBox.width - boundingBox.height);
+ boundingBox.y -= dy / 2;
+ boundingBox.height += dy;
+ }
+ }
+
+ std::tuple<cv::Rect, float, float, int> extract(const size_t step)
+ {
+ const float* it = m_data + step * m_objSize;
+ float image_id = it[0];
+ int label = static_cast<int>(it[1]);
+ float confidence = it[2];
+ float rc_left = it[3];
+ float rc_top = it[4];
+ float rc_right = it[5];
+ float rc_bottom = it[6];
+
+ cv::Rect rc; // Map relative coordinates to the original image scale
+ rc.x = static_cast<int>(rc_left * m_size.width);
+ rc.y = static_cast<int>(rc_top * m_size.height);
+ rc.width = static_cast<int>(rc_right * m_size.width) - rc.x;
+ rc.height = static_cast<int>(rc_bottom * m_size.height) - rc.y;
+ return std::make_tuple(rc, image_id, confidence, label);
+ }
+
+ int getMaxProposals()
+ {
+ return m_maxProp;
+ }
+
+ cv::Rect getSurface()
+ {
+ return m_surface;
+ }
+
+private:
+ const cv::MatSize m_dims;
+ int m_maxProp = 0, m_objSize = 0;
+ const float* m_data = nullptr;
+ const cv::Rect m_surface;
+ const cv::Size m_size;
+};
+} // namespace nn
+} // namespace gapi
+
+void parseSSDBL(const cv::Mat& in_ssd_result,
+ const cv::Size& in_size,
+ const float confidence_threshold,
+ const int filter_label,
+ std::vector<cv::Rect>& out_boxes,
+ std::vector<int>& out_labels)
+{
+ cv::gapi::nn::SSDParser parser(in_ssd_result.size, in_size, in_ssd_result.ptr<float>());
+ out_boxes.clear();
+ out_labels.clear();
+ cv::Rect rc;
+ float image_id, confidence;
+ int label;
+ const size_t range = parser.getMaxProposals();
+ for (size_t i = 0; i < range; ++i)
+ {
+ std::tie(rc, image_id, confidence, label) = parser.extract(i);
+
+ if (image_id < 0.f)
+ {
+ break; // marks end-of-detections
+ }
+
+ if (confidence < confidence_threshold ||
+ (filter_label != -1 && label != filter_label))
+ {
+ continue; // filter out object classes if filter is specified
+ } // and skip objects with low confidence
+ out_boxes.emplace_back(rc & parser.getSurface());
+ out_labels.emplace_back(label);
+ }
+}
+
+void parseSSD(const cv::Mat& in_ssd_result,
+ const cv::Size& in_size,
+ const float confidence_threshold,
+ const bool alignment_to_square,
+ const bool filter_out_of_bounds,
+ std::vector<cv::Rect>& out_boxes)
+{
+ cv::gapi::nn::SSDParser parser(in_ssd_result.size, in_size, in_ssd_result.ptr<float>());
+ out_boxes.clear();
+ cv::Rect rc;
+ float image_id, confidence;
+ int label;
+ const size_t range = parser.getMaxProposals();
+ for (size_t i = 0; i < range; ++i)
+ {
+ std::tie(rc, image_id, confidence, label) = parser.extract(i);
+
+ if (image_id < 0.f)
+ {
+ break; // marks end-of-detections
+ }
+ if (confidence < confidence_threshold)
+ {
+ continue; // skip objects with low confidence
+ }
+
+ if (alignment_to_square)
+ {
+ parser.adjustBoundingBox(rc);
+ }
+
+ const auto clipped_rc = rc & parser.getSurface();
+ if (filter_out_of_bounds)
+ {
+ if (clipped_rc.area() != rc.area())
+ {
+ continue;
+ }
+ }
+ out_boxes.emplace_back(clipped_rc);
+ }
+}
+
+void parseYolo(const cv::Mat& in_yolo_result,
+ const cv::Size& in_size,
+ const float confidence_threshold,
+ const float nms_threshold,
+ const std::vector<float>& anchors,
+ std::vector<cv::Rect>& out_boxes,
+ std::vector<int>& out_labels)
+{
+ const auto& dims = in_yolo_result.size;
+ GAPI_Assert(dims.dims() == 4);
+ GAPI_Assert(dims[0] == 1);
+ GAPI_Assert(dims[1] == 13);
+ GAPI_Assert(dims[2] == 13);
+ GAPI_Assert(dims[3] % 5 == 0); // 5 boxes
+ const auto num_classes = dims[3] / 5 - 5;
+ GAPI_Assert(num_classes > 0);
+ GAPI_Assert(0 < nms_threshold && nms_threshold <= 1);
+ out_boxes.clear();
+ out_labels.clear();
+ gapi::nn::YoloParams params;
+ constexpr auto side = 13;
+ constexpr auto side_square = side * side;
+ const auto output = in_yolo_result.ptr<float>();
+
+ gapi::nn::YoloParser parser(output, side, params.coords, num_classes);
+
+ std::vector<gapi::nn::Detection> detections;
+
+ for (int i = 0; i < side_square; ++i)
+ {
+ for (int b = 0; b < params.num; ++b)
+ {
+ float scale = parser.scale(i, b);
+ if (scale < confidence_threshold)
+ {
+ continue;
+ }
+ double x = parser.x(i, b);
+ double y = parser.y(i, b);
+ double height = parser.height(i, b, anchors[2 * b + 1]);
+ double width = parser.width(i, b, anchors[2 * b]);
+
+ for (int label = 0; label < num_classes; ++label)
+ {
+ float prob = scale * parser.classConf(i,b,label);
+ if (prob < confidence_threshold)
+ {
+ continue;
+ }
+ auto box = parser.toBox(x, y, height, width, in_size);
+ detections.emplace_back(gapi::nn::Detection(box, prob, label));
+ }
+ }
+ }
+ std::stable_sort(std::begin(detections), std::end(detections),
+ [](const gapi::nn::Detection& a, const gapi::nn::Detection& b)
+ {
+ return a.conf > b.conf;
+ });
+
+ if (nms_threshold < 1.0f)
+ {
+ for (const auto& d : detections)
+ {
+ // Reject boxes which overlap with previously pushed ones
+ // (They are sorted by confidence, so rejected box
+ // always has a smaller confidence
+ if (std::end(out_boxes) ==
+ std::find_if(std::begin(out_boxes), std::end(out_boxes),
+ [&d, nms_threshold](const cv::Rect& r)
+ {
+ float rectOverlap = 1.f - static_cast<float>(jaccardDistance(r, d.rect));
+ return rectOverlap > nms_threshold;
+ }))
+ {
+ out_boxes. emplace_back(d.rect);
+ out_labels.emplace_back(d.label);
+ }
+ }
+ }
+ else
+ {
+ for (const auto& d: detections)
+ {
+ out_boxes. emplace_back(d.rect);
+ out_labels.emplace_back(d.label);
+ }
+ }
+}
+} // namespace cv
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#include <opencv2/gapi/infer/parsers.hpp>
+
+#ifndef OPENCV_NNPARSERS_OCV_HPP
+#define OPENCV_NNPARSERS_OCV_HPP
+
+namespace cv
+{
+void parseSSDBL(const cv::Mat& in_ssd_result,
+ const cv::Size& in_size,
+ const float confidence_threshold,
+ const int filter_label,
+ std::vector<cv::Rect>& out_boxes,
+ std::vector<int>& out_labels);
+
+void parseSSD(const cv::Mat& in_ssd_result,
+ const cv::Size& in_size,
+ const float confidence_threshold,
+ const bool alignment_to_square,
+ const bool filter_out_of_bounds,
+ std::vector<cv::Rect>& out_boxes);
+
+void parseYolo(const cv::Mat& in_yolo_result,
+ const cv::Size& in_size,
+ const float confidence_threshold,
+ const float nms_threshold,
+ const std::vector<float>& anchors,
+ std::vector<cv::Rect>& out_boxes,
+ std::vector<int>& out_labels);
+}
+#endif // OPENCV_NNPARSERS_OCV_HPP
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
#include <opencv2/gapi/gcommon.hpp>
#include "logger.hpp"
-#include <opencv2/gapi/own/convert.hpp>
#include <opencv2/gapi/gmat.hpp> //for version of descr_of
// PRIVATE STUFF!
#include "compiler/gobjref.hpp"
return gim.metadata(nh).get<NodeKind>().k == NodeKind::ISLAND;
});
- const auto out_rois = cv::gimpl::getCompileArg<cv::GFluidOutputRois>(args);
+ const auto out_rois = cv::gapi::getCompileArg<cv::GFluidOutputRois>(args);
if (num_islands > 1 && out_rois.has_value())
cv::util::throw_error(std::logic_error("GFluidOutputRois feature supports only one-island graphs"));
auto rois = out_rois.value_or(cv::GFluidOutputRois());
auto graph_data = fluidExtractInputDataFromGraph(graph, nodes);
- const auto parallel_out_rois = cv::gimpl::getCompileArg<cv::GFluidParallelOutputRois>(args);
- const auto gpfor = cv::gimpl::getCompileArg<cv::GFluidParallelFor>(args);
+ const auto parallel_out_rois = cv::gapi::getCompileArg<cv::GFluidParallelOutputRois>(args);
+ const auto gpfor = cv::gapi::getCompileArg<cv::GFluidParallelFor>(args);
#if !defined(GAPI_STANDALONE)
auto default_pfor = [](std::size_t count, std::function<void(std::size_t)> f){
m_num_int_buffers (traverse_res.m_mat_count),
m_scratch_users (traverse_res.m_scratch_users),
m_id_map (traverse_res.m_id_map),
- m_all_gmat_ids (traverse_res.m_all_gmat_ids)
+ m_all_gmat_ids (traverse_res.m_all_gmat_ids),
+ m_buffers(m_num_int_buffers + m_scratch_users.size())
{
GConstFluidModel fg(m_g);
// Actually initialize Fluid buffers
GAPI_LOG_INFO(NULL, "Initializing " << m_num_int_buffers << " fluid buffer(s)" << std::endl);
- const std::size_t num_scratch = m_scratch_users.size();
- m_buffers.resize(m_num_int_buffers + num_scratch);
-
// After buffers are allocated, repack: ...
for (auto &agent : m_agents)
{
auto inEdge = GModel::getInEdgeByPort(m_g, agent->op_handle, in_idx);
auto ownStorage = fg.metadata(inEdge).get<FluidUseOwnBorderBuffer>().use;
- gapi::fluid::View view = buffer.mkView(fu.border_size, ownStorage);
// NB: It is safe to keep ptr as view lifetime is buffer lifetime
- agent->in_views[in_idx] = view;
- agent->in_args[in_idx] = GArg(view);
+ agent->in_views[in_idx] = buffer.mkView(fu.border_size, ownStorage);
+ agent->in_args[in_idx] = GArg(&agent->in_views[in_idx]);
+ buffer.addView(&agent->in_views[in_idx]);
}
else
{
}
// After parameters are there, initialize scratch buffers
+ const std::size_t num_scratch = m_scratch_users.size();
if (num_scratch)
{
GAPI_LOG_INFO(NULL, "Initializing " << num_scratch << " scratch buffer(s)" << std::endl);
for (const auto &i : ade::util::indexed(m_buffers))
{
// Check that all internal and scratch buffers are allocated
- const auto idx = ade::util::index(i);
- const auto b = ade::util::value(i);
+ const auto idx = ade::util::index(i);
+ const auto& b = ade::util::value(i);
if (idx >= m_num_int_buffers ||
fg.metadata(m_all_gmat_ids.at(idx)).get<FluidData>().internal == true)
{
initLineConsumption(g);
calcLatency(g);
calcSkew(g);
- const auto out_rois = cv::gimpl::getCompileArg<cv::GFluidOutputRois>(args).value_or(cv::GFluidOutputRois());
+ const auto out_rois = cv::gapi::getCompileArg<cv::GFluidOutputRois>(args).value_or(cv::GFluidOutputRois());
makeReshape(out_rois.rois);
}
{
switch (rc.shape)
{
- case GShape::GMAT: m_buffers[m_id_map.at(rc.id)].priv().bindTo(util::get<cv::gapi::own::Mat>(arg), true); break;
+ case GShape::GMAT: m_buffers[m_id_map.at(rc.id)].priv().bindTo(util::get<cv::Mat>(arg), true); break;
case GShape::GSCALAR: m_res.slot<cv::Scalar>()[rc.id] = util::get<cv::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;
+ default: util::throw_error(std::logic_error("Unsupported input GShape type"));
}
}
switch (arg.index()) {
// FIXME: See the bindInArg comment on Streaming-related changes
- case T::index_of<cv::gapi::own::Mat*>(): {
- auto &outMat = *util::get<cv::gapi::own::Mat*>(arg);
- GAPI_Assert(outMat.data != nullptr);
- GAPI_Assert(descr_of(outMat) == desc && "Output argument was not preallocated as it should be ?");
- bref.bindTo(outMat, false);
- } break;
-#if !defined(GAPI_STANDALONE)
case T::index_of<cv::Mat*>(): {
auto &outMat = *util::get<cv::Mat*>(arg);
GAPI_Assert(outMat.data != nullptr);
- GAPI_Assert(descr_of(outMat) == desc && "Output argument was not preallocated as it should be ?");
- bref.bindTo(cv::to_own(outMat), false);
+ GAPI_Assert(cv::descr_of(outMat) == desc && "Output argument was not preallocated as it should be ?");
+ bref.bindTo(outMat, false);
} break;
-#endif // GAPI_STANDALONE
default: GAPI_Assert(false);
} // switch(arg.index())
break;
GModel::ConstGraph m_gm;
std::vector<std::unique_ptr<FluidAgent>> m_agents;
- std::vector<cv::gapi::fluid::Buffer> m_buffers;
std::vector<FluidAgent*> m_script;
std::unordered_map<int, std::size_t> m_id_map; // GMat id -> buffer idx map
std::map<std::size_t, ade::NodeHandle> m_all_gmat_ids;
+ std::vector<cv::gapi::fluid::Buffer> m_buffers;
+
void bindInArg (const RcDesc &rc, const GRunArg &arg);
void bindOutArg(const RcDesc &rc, const GRunArgP &arg);
void packArg (GArg &in_arg, const GArg &op_arg);
virtual void run(std::vector<InObj> &&input_objs,
std::vector<OutObj> &&output_objs) override;
+ using GIslandExecutable::run; // (IInput&, IOutput&) version
+
void run(std::vector<InObj> &input_objs,
std::vector<OutObj> &output_objs);
}
// Fills const border pixels in the whole mat
-void fillBorderConstant(int borderSize, cv::Scalar borderValue, cv::gapi::own::Mat& mat)
+void fillBorderConstant(int borderSize, cv::Scalar borderValue, cv::Mat& mat)
{
// cv::Scalar can contain maximum 4 chan
GAPI_Assert(mat.channels() > 0 && mat.channels() <= 4);
void fluid::BorderHandlerT<cv::BORDER_CONSTANT>::fillCompileTimeBorder(BufferStorageWithBorder& data)
{
m_const_border.create(1, data.cols(), data.data().type());
- // FIXME: remove this crutch in deowned Mat
- m_const_border = {m_border_value[0], m_border_value[1],
- m_border_value[2], m_border_value[3]};
+ m_const_border = m_border_value;
cv::gapi::fillBorderConstant(m_border_size, m_border_value, data.data());
}
}
}
-static void copyWithoutBorder(const cv::gapi::own::Mat& src, int src_border_size, cv::gapi::own::Mat& dst, int dst_border_size, int startSrcLine, int startDstLine, int lpi)
+static void copyWithoutBorder(const cv::Mat& src, int src_border_size, cv::Mat& dst, int dst_border_size, int startSrcLine, int startDstLine, int lpi)
{
auto subSrc = src(cv::Rect{src_border_size, startSrcLine, src.cols - 2*src_border_size, lpi});
auto subDst = dst(cv::Rect{dst_border_size, startDstLine, dst.cols - 2*dst_border_size, lpi});
#endif
}
-std::unique_ptr<BufferStorage> createStorage(const cv::gapi::own::Mat& data, cv::Rect roi);
-std::unique_ptr<BufferStorage> createStorage(const cv::gapi::own::Mat& data, cv::Rect roi)
+std::unique_ptr<BufferStorage> createStorage(const cv::Mat& data, cv::Rect roi);
+std::unique_ptr<BufferStorage> createStorage(const cv::Mat& data, cv::Rect roi)
{
std::unique_ptr<BufferStorageWithoutBorder> storage(new BufferStorageWithoutBorder);
storage->attach(data, roi);
m_storage->updateOutCache(m_cache, m_write_caret, m_writer_lpi);
}
-void fluid::Buffer::Priv::bindTo(const cv::gapi::own::Mat &data, bool is_input)
+void fluid::Buffer::Priv::bindTo(const cv::Mat &data, bool is_input)
{
// FIXME: move all these fields into a separate structure
- GAPI_Assert(m_desc == descr_of(data));
+ GAPI_Assert(m_desc == cv::descr_of(data));
// Currently m_writer_lpi is obtained from metadata which is shared between islands
// and this assert can trigger for slot which connects two fluid islands.
{
// reset with maximum possible value and then find minimum
slowest_y = m_desc.size.height;
- for (const auto &v : m_views) slowest_y = std::min(slowest_y, v.y());
+ for (const auto &v : m_views) slowest_y = std::min(slowest_y, v->y());
}
return m_write_caret + lpi() - slowest_y > m_storage->rows();
int fluid::Buffer::Priv::size() const
{
std::size_t view_sz = 0;
- for (const auto &v : m_views) view_sz += v.priv().size();
+ for (const auto &v : m_views) view_sz += v->priv().size();
auto total = view_sz;
if (m_storage) total += m_storage->size();
m_priv->allocate(border, border_size, max_line_consumption, skew);
}
-fluid::Buffer::Buffer(const cv::gapi::own::Mat &data, bool is_input)
+fluid::Buffer::Buffer(const cv::Mat &data, bool is_input)
: m_priv(new Priv())
, m_cache(&m_priv->cache())
{
int wlpi = 1, readStart = 0;
cv::Rect roi{0, 0, data.cols, data.rows};
- m_priv->init(descr_of(data), wlpi, readStart, roi);
+ m_priv->init(cv::descr_of(data), wlpi, readStart, roi);
m_priv->bindTo(data, is_input);
}
+fluid::Buffer::~Buffer() = default;
+fluid::Buffer& fluid::Buffer::operator=(fluid::Buffer&&) = default;
+
int fluid::Buffer::linesReady() const
{
return m_priv->linesReady();
return m_priv->lpi();
}
-fluid::View::View(Priv* p)
- : m_priv(p), m_cache(&p->cache())
+fluid::View::View(std::unique_ptr<Priv>&& p)
+ : m_priv(std::move(p)), m_cache(&m_priv->cache())
{ /* nothing */ }
+
+fluid::View::View() = default;
+fluid::View::View(View&&) = default;
+fluid::View& fluid::View::operator=(View&&) = default;
+fluid::View::~View() = default;
+
fluid::View fluid::Buffer::mkView(int borderSize, bool ownStorage)
{
// FIXME: logic outside of Priv (because View takes pointer to Buffer)
- auto view = ownStorage ? View(new ViewPrivWithOwnBorder(this, borderSize))
- : View(new ViewPrivWithoutOwnBorder(this, borderSize));
- m_priv->addView(view);
- return view;
+ return ownStorage ? View(std::unique_ptr<ViewPrivWithOwnBorder>(new ViewPrivWithOwnBorder(this, borderSize)))
+ : View(std::unique_ptr<ViewPrivWithoutOwnBorder>(new ViewPrivWithoutOwnBorder(this, borderSize)));
+}
+
+void fluid::Buffer::addView(const View* v)
+{
+ m_priv->addView(v);
}
void fluid::debugBufferPriv(const fluid::Buffer& buffer, std::ostream &os)
<<" (phys " << "[" << p.storage().cols() << " x " << p.storage().rows() << "]" << ") :"
<< " w: " << p.m_write_caret
<< ", r: [";
- for (const auto &v : p.m_views) { os << &v.priv() << ":" << v.y() << " "; }
+ for (const auto &v : p.m_views) { os << &v->priv() << ":" << v->y() << " "; }
os << "], avail: " << buffer.linesReady()
<< std::endl;
}
class BorderHandlerT<cv::BORDER_CONSTANT> : public BorderHandler
{
cv::Scalar m_border_value;
- cv::gapi::own::Mat m_const_border;
+ cv::Mat m_const_border;
public:
BorderHandlerT(int border_size, cv::Scalar border_value);
class BufferStorage
{
protected:
- cv::gapi::own::Mat m_data;
+ cv::Mat m_data;
public:
void updateInCache(View::Cache& cache, int start_log_idx, int nLines) const;
inline bool empty() const { return m_data.empty(); }
- inline const cv::gapi::own::Mat& data() const { return m_data; }
- inline cv::gapi::own::Mat& data() { return m_data; }
+ inline const cv::Mat& data() const { return m_data; }
+ inline cv::Mat& data() { return m_data; }
inline int rows() const { return m_data.rows; }
inline int cols() const { return m_data.cols; }
return m_data.ptr(physIdx(idx), 0);
}
- inline void attach(const cv::gapi::own::Mat& _data, cv::Rect _roi)
+ inline void attach(const cv::Mat& _data, cv::Rect _roi)
{
m_data = _data(_roi);
m_roi = _roi;
int m_write_caret = -1;
- std::vector<View> m_views;
+ std::vector<const View*> m_views;
std::unique_ptr<BufferStorage> m_storage;
// Coordinate starting from which this buffer is assumed
// to be read (with border not being taken into account)
- int m_readStart;
+ int m_readStart = 0;
cv::Rect m_roi;
friend void debugBufferPriv(const Buffer& p, std::ostream &os);
cv::Rect roi);
void allocate(BorderOpt border, int border_size, int line_consumption, int skew);
- void bindTo(const cv::gapi::own::Mat &data, bool is_input);
+ void bindTo(const cv::Mat &data, bool is_input);
- inline void addView(const View& view) { m_views.push_back(view); }
+ inline void addView(const View* view) { m_views.emplace_back(view); }
inline const GMatDesc& meta() const { return m_desc; }
}
};
+//-------------------
+//
+// Fluid kernels: mask
+//
+//-------------------
+
+template<typename DST, typename SRC>
+static void run_mask(Buffer &dst, const View &src, const View &mask)
+{
+ static_assert(std::is_same<DST, SRC>::value,
+ "Input and output types must match");
+
+ int length = dst.length(); // dst, src and mask have the same size and are single-channel
+
+ const auto *in = src.InLine<SRC>(0);
+ const auto *in_mask = mask.InLine<uchar>(0);
+ auto *out = dst.OutLine<DST>();
+
+ for (int l=0; l < length; l++)
+ {
+ out[l] = in_mask[l] ? in[l] : 0;
+ }
+}
+
+GAPI_FLUID_KERNEL(GFluidMask, cv::gapi::core::GMask, false)
+{
+ static const int Window = 1;
+
+ static void run(const View &src, const View &mask, Buffer &dst)
+ {
+ if (src.meta().chan != 1 || dst.meta().chan != 1)
+ CV_Error(cv::Error::StsBadArg, "input and output must be single-channel");
+ if (mask.meta().chan != 1 || mask.meta().depth != CV_8U)
+ CV_Error(cv::Error::StsBadArg, "unsupported mask type");
+
+ // DST SRC OP __VA_ARGS__
+ UNARY_(uchar , uchar , run_mask, dst, src, mask);
+ UNARY_( short, short, run_mask, dst, src, mask);
+ UNARY_(ushort, ushort, run_mask, dst, src, mask);
+
+ CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
+ }
+};
+
//----------------------------
//
// Fluid math kernels: bitwise
enum Bitwise { BW_AND, BW_OR, BW_XOR, BW_NOT };
template<typename DST, typename SRC1, typename SRC2>
-static void run_bitwise2(Buffer &dst, const View &src1, const View &src2, Bitwise bitwise)
+static void run_bitwise2(Buffer &dst, const View &src1, const View &src2, Bitwise bitwise_op)
{
static_assert(std::is_same<DST, SRC1>::value, "wrong types");
static_assert(std::is_same<DST, SRC2>::value, "wrong types");
int chan = dst.meta().chan;
int length = width * chan;
- switch (bitwise)
+ switch (bitwise_op)
{
case BW_AND:
for (int l=0; l < length; l++)
}
template<typename DST, typename SRC>
-static void run_bitwise1(Buffer &dst, const View &src, Bitwise bitwise)
+static void run_bitwise1(Buffer &dst, const View &src, Bitwise bitwise_op)
{
static_assert(std::is_same<DST, SRC>::value, "wrong types");
int chan = dst.meta().chan;
int length = width * chan;
- switch (bitwise)
+ switch (bitwise_op)
{
case BW_NOT:
for (int l=0; l < length; l++)
}
};
+//--------------------------------------
+//
+// Fluid math kernels: bitwise with Scalar
+//
+//--------------------------------------
+
+static std::array<int,4> convertScalarForBitwise(const cv::Scalar &_scalar)
+{
+ std::array<int,4> scalarI = {
+ static_cast<int>(_scalar[0]),
+ static_cast<int>(_scalar[1]),
+ static_cast<int>(_scalar[2]),
+ static_cast<int>(_scalar[3])
+ };
+
+ if (!((_scalar[0] == scalarI[0]) && (_scalar[1] == scalarI[1]) &&
+ (_scalar[2] == scalarI[2]) && (_scalar[3] == scalarI[3])))
+ {
+ CV_Error(cv::Error::StsBadArg, "Bitwise operations make sense with integral types only");
+ }
+ return scalarI;
+}
+
+template<typename DST>
+static inline DST bw_andS(DST x, int y)
+{
+ return x & saturate<DST>(y);
+}
+
+template<typename DST>
+static inline DST bw_orS(DST x, int y)
+{
+ return x | saturate<DST>(y);
+}
+
+template<typename DST>
+static inline DST bw_xorS(DST x, int y)
+{
+ return x ^ saturate<DST>(y);
+}
+
+// manually unroll the inner cycle by channels
+// (reuse arithmetic function above of the same purpose)
+template<typename DST, typename FUNC>
+static inline void run_bitwise_s(DST out[], const DST in[], int width, int chan,
+ const int scalar[4], FUNC func)
+{
+ run_arithm_s(out, in, width, chan, scalar, func);
+}
+
+template<typename DST, typename SRC>
+static void run_bitwise_s(Buffer &dst, const View &src, const int scalar[4], Bitwise bitwise_op)
+{
+ static_assert(std::is_same<DST, SRC>::value, "wrong types");
+
+ const auto *in = src.InLine<SRC>(0);
+ auto *out = dst.OutLine<DST>();
+
+ int width = dst.length();
+ int chan = dst.meta().chan;
+
+ switch (bitwise_op)
+ {
+ case BW_AND:
+ run_bitwise_s(out, in, width, chan, scalar, bw_andS<DST>);
+ break;
+ case BW_OR:
+ run_bitwise_s(out, in, width, chan, scalar, bw_orS<DST>);
+ break;
+ case BW_XOR:
+ run_bitwise_s(out, in, width, chan, scalar, bw_xorS<DST>);
+ break;
+ default: CV_Error(cv::Error::StsBadArg, "unsupported bitwise operation");
+ }
+}
+
+GAPI_FLUID_KERNEL(GFluidAndS, cv::gapi::core::GAndS, false)
+{
+ static const int Window = 1;
+
+ static void run(const View &src, const cv::Scalar &_scalar, Buffer &dst)
+ {
+ std::array<int,4> scalar = convertScalarForBitwise(_scalar);
+
+ // DST SRC OP __VA_ARGS__
+ UNARY_(uchar , uchar , run_bitwise_s, dst, src, scalar.data(), BW_AND);
+ UNARY_(ushort, ushort, run_bitwise_s, dst, src, scalar.data(), BW_AND);
+ UNARY_( short, short, run_bitwise_s, dst, src, scalar.data(), BW_AND);
+
+ CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
+ }
+};
+
+GAPI_FLUID_KERNEL(GFluidOrS, cv::gapi::core::GOrS, false)
+{
+ static const int Window = 1;
+
+ static void run(const View &src, const cv::Scalar &_scalar, Buffer &dst)
+ {
+ std::array<int,4> scalar = convertScalarForBitwise(_scalar);
+
+ // DST SRC OP __VA_ARGS__
+ UNARY_(uchar , uchar , run_bitwise_s, dst, src, scalar.data(), BW_OR);
+ UNARY_(ushort, ushort, run_bitwise_s, dst, src, scalar.data(), BW_OR);
+ UNARY_( short, short, run_bitwise_s, dst, src, scalar.data(), BW_OR);
+
+ CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
+ }
+};
+
+GAPI_FLUID_KERNEL(GFluidXorS, cv::gapi::core::GXorS, false)
+{
+ static const int Window = 1;
+
+ static void run(const View &src, const cv::Scalar &_scalar, Buffer &dst)
+ {
+ std::array<int,4> scalar = convertScalarForBitwise(_scalar);
+
+ // DST SRC OP __VA_ARGS__
+ UNARY_(uchar , uchar , run_bitwise_s, dst, src, scalar.data(), BW_XOR);
+ UNARY_(ushort, ushort, run_bitwise_s, dst, src, scalar.data(), BW_XOR);
+ UNARY_( short, short, run_bitwise_s, dst, src, scalar.data(), BW_XOR);
+
+ CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
+ }
+};
+
//-------------------
//
// Fluid kernels: LUT
// DST SRC OP __VA_ARGS__
UNARY_(uchar , uchar , run_convertto, dst, src, alpha, beta);
UNARY_(uchar , ushort, run_convertto, dst, src, alpha, beta);
+ UNARY_(uchar , short, run_convertto, dst, src, alpha, beta);
UNARY_(uchar , float, run_convertto, dst, src, alpha, beta);
UNARY_(ushort, uchar , run_convertto, dst, src, alpha, beta);
UNARY_(ushort, ushort, run_convertto, dst, src, alpha, beta);
+ UNARY_(ushort, short, run_convertto, dst, src, alpha, beta);
UNARY_(ushort, float, run_convertto, dst, src, alpha, beta);
+ UNARY_( short, uchar , run_convertto, dst, src, alpha, beta);
+ UNARY_( short, ushort, run_convertto, dst, src, alpha, beta);
+ UNARY_( short, short, run_convertto, dst, src, alpha, beta);
+ UNARY_( short, float, run_convertto, dst, src, alpha, beta);
UNARY_( float, uchar , run_convertto, dst, src, alpha, beta);
UNARY_( float, ushort, run_convertto, dst, src, alpha, beta);
+ UNARY_( float, short, run_convertto, dst, src, alpha, beta);
UNARY_( float, float, run_convertto, dst, src, alpha, beta);
CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
}
static void initScratch(const cv::GMatDesc& in,
- cv::Size outSz, double /*fx*/, double /*fy*/, int /*interp*/,
+ cv::Size outSz, double fx, double fy, int /*interp*/,
cv::gapi::fluid::Buffer &scratch)
{
- CV_Assert(in.depth == CV_8U && in.chan == 3);
+ GAPI_Assert(in.depth == CV_8U && in.chan == 3);
+
+ if (outSz.area() == 0)
+ {
+ outSz.width = static_cast<int>(round(in.size.width * fx));
+ outSz.height = static_cast<int>(round(in.size.height * fy));
+ }
cv::Size scratch_size{static_cast<int>(outSz.width * sizeof(ResizeUnit)), 1};
,GFluidAnd
,GFluidOr
,GFluidXor
+ ,GFluidAndS
+ ,GFluidOrS
+ ,GFluidXorS
,GFluidMin
,GFluidMax
,GFluidCmpGT
,GFluidMulCOld
,GFluidDivC
,GFluidDivRC
+ ,GFluidMask
,GFluidAbsDiffC
,GFluidCmpGTScalar
,GFluidCmpGEScalar
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
#include <opencv2/gapi/util/any.hpp>
#include <opencv2/gapi/gtype_traits.hpp>
#include <opencv2/gapi/infer.hpp>
+#include <opencv2/gapi/own/convert.hpp>
#include "compiler/gobjref.hpp"
#include "compiler/gmodel.hpp"
#include "backends/ie/util.hpp"
+#include "backends/ie/giebackend/giewrapper.hpp"
#include "api/gbackend_priv.hpp" // FIXME: Make it part of Backend SDK!
explicit IEUnit(const cv::gapi::ie::detail::ParamDesc &pp)
: params(pp) {
-
- IE::CNNNetReader reader;
- reader.ReadNetwork(params.model_path);
- reader.ReadWeights(params.weights_path);
- net = reader.getNetwork();
- inputs = net.getInputsInfo();
+ net = cv::gimpl::ie::wrap::readNetwork(params);
+ inputs = net.getInputsInfo();
outputs = net.getOutputsInfo();
-
// The practice shows that not all inputs and not all outputs
// are mandatory to specify in IE model.
// So what we're concerned here about is:
}
// This method is [supposed to be] called at Island compilation stage
- // TODO: Move to a new OpenVINO Core API!
cv::gimpl::ie::IECompiled compile() const {
- auto this_plugin = IE::PluginDispatcher().getPluginByDevice(params.device_id);
-
- // Load extensions (taken from DNN module)
- if (params.device_id == "CPU" || params.device_id == "FPGA")
- {
- const std::string suffixes[] = { "_avx2", "_sse4", ""};
- const bool haveFeature[] = {
- cv::checkHardwareSupport(CPU_AVX2),
- cv::checkHardwareSupport(CPU_SSE4_2),
- true
- };
- std::vector<std::string> candidates;
- for (auto &&it : ade::util::zip(ade::util::toRange(suffixes),
- ade::util::toRange(haveFeature)))
- {
- std::string suffix;
- bool available = false;
- std::tie(suffix, available) = it;
- if (!available) continue;
-#ifdef _WIN32
- candidates.push_back("cpu_extension" + suffix + ".dll");
-#elif defined(__APPLE__)
- candidates.push_back("libcpu_extension" + suffix + ".so"); // built as loadable module
- candidates.push_back("libcpu_extension" + suffix + ".dylib"); // built as shared library
-#else
- candidates.push_back("libcpu_extension" + suffix + ".so");
-#endif // _WIN32
- }
- for (auto &&extlib : candidates)
- {
- try
- {
- this_plugin.AddExtension(IE::make_so_pointer<IE::IExtension>(extlib));
- CV_LOG_INFO(NULL, "DNN-IE: Loaded extension plugin: " << extlib);
- break;
- }
- catch(...)
- {
- CV_LOG_WARNING(NULL, "Failed to load IE extension " << extlib);
- }
- }
- }
-
- auto this_network = this_plugin.LoadNetwork(net, {}); // FIXME: 2nd parameter to be
- // configurable via the API
+ auto plugin = cv::gimpl::ie::wrap::getPlugin(params);
+ auto this_network = cv::gimpl::ie::wrap::loadNetwork(plugin, net, params);
auto this_request = this_network.CreateInferRequest();
// Bind const data to infer request
// Still, constant data is to set only once.
this_request.SetBlob(p.first, wrapIE(p.second.first, p.second.second));
}
-
- return {this_plugin, this_network, this_request};
+ return {plugin, this_network, this_request};
}
};
const T& inArg(std::size_t input) { return args.at(input).get<T>(); }
// Syntax sugar
- const cv::gapi::own::Mat& inMat(std::size_t input) {
- return inArg<cv::gapi::own::Mat>(input);
+ const cv::Mat& inMat(std::size_t input) {
+ return inArg<cv::Mat>(input);
}
- cv::gapi::own::Mat& outMatR(std::size_t output) {
- return *cv::util::get<cv::gapi::own::Mat*>(results.at(output));
+ cv::Mat& outMatR(std::size_t output) {
+ return *cv::util::get<cv::Mat*>(results.at(output));
}
template<typename T> std::vector<T>& outVecR(std::size_t output) { // FIXME: the same issue
const cv::gimpl::RcDesc &ref = arg.get<cv::gimpl::RcDesc>();
switch (ref.shape)
{
- case GShape::GMAT: return GArg(m_res.slot<cv::gapi::own::Mat>()[ref.id]);
+ case GShape::GMAT: return GArg(m_res.slot<cv::Mat>()[ref.id]);
// Note: .at() is intentional for GArray as object MUST be already there
// (and constructed by either bindIn/Out or resetInternal)
const auto &meta = util::get<cv::GMatDesc>(mm);
ii->setPrecision(toIE(meta.depth));
- ii->setLayout(meta.isND() ? IE::Layout::NCHW : IE::Layout::NHWC);
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
}
// and redirect our data producers to this memory
// (A memory dialog comes to the picture again)
- const cv::Mat this_mat = to_ocv(ctx.inMat(i));
+ const cv::Mat this_mat = ctx.inMat(i);
// FIXME: By default here we trait our inputs as images.
// May be we need to make some more intelligence here about it
IE::Blob::Ptr this_blob = wrapIE(this_mat, cv::gapi::ie::TraitAs::IMAGE);
// Not a <very> big deal for classifiers and detectors,
// but may be critical to segmentation.
- cv::gapi::own::Mat& out_mat = ctx.outMatR(i);
+ cv::Mat& out_mat = ctx.outMatR(i);
IE::Blob::Ptr this_blob = iec.this_request.GetBlob(uu.params.output_names[i]);
copyFromIE(this_blob, out_mat);
}
const auto &meta = util::get<cv::GMatDesc>(mm);
ii->setPrecision(toIE(meta.depth));
- ii->setLayout(meta.isND() ? IE::Layout::NCHW : IE::Layout::NHWC);
ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
}
GAPI_Assert(uu.params.num_in == 1); // roi list is not counted in net's inputs
const auto& in_roi_vec = ctx.inArg<cv::detail::VectorRef>(0u).rref<cv::Rect>();
- const cv::Mat this_mat = to_ocv(ctx.inMat(1u));
+ const cv::Mat this_mat = ctx.inMat(1u);
// Since we do a ROI list inference, always assume our input buffer is image
IE::Blob::Ptr this_blob = wrapIE(this_mat, cv::gapi::ie::TraitAs::IMAGE);
}
};
+struct InferList2: public cv::detail::KernelTag {
+ using API = cv::GInferList2Base;
+ static cv::gapi::GBackend backend() { return cv::gapi::ie::backend(); }
+ static KImpl kernel() { return KImpl{outMeta, run}; }
+
+ static cv::GMetaArgs outMeta(const ade::Graph &gr,
+ const ade::NodeHandle &nh,
+ const cv::GMetaArgs &in_metas,
+ const cv::GArgs &/*in_args*/) {
+ // Specify the input information to the IE from the framework
+ // NB: Have no clue if network's input [dimensions] may ever define
+ // its output dimensions. It seems possible with OpenCV DNN APIs
+
+ GConstGIEModel gm(gr);
+ const auto &uu = gm.metadata(nh).get<IEUnit>();
+
+ // Initialize input information
+ // Note our input layers list order matches the API order and so
+ // meta order.
+ GAPI_Assert(uu.params.input_names.size() == (in_metas.size() - 1u)
+ && "Known input layers count doesn't match input meta count");
+
+ const auto &op = gm.metadata(nh).get<Op>();
+
+ // In contrast to InferList, the InferList2 has only one
+ // "full-frame" image argument, and all the rest are arrays of
+ // ether ROI or blobs. So here we set the 0th arg image format
+ // to all inputs which are ROI-based (skipping the
+ // "blob"-based ones)
+ // FIXME: this is filtering not done, actually! GArrayDesc has
+ // no hint for its underlying type!
+ const auto &mm_0 = in_metas[0u];
+ const auto &meta_0 = util::get<cv::GMatDesc>(mm_0);
+ GAPI_Assert( !meta_0.isND()
+ && !meta_0.planar
+ && "Only images are supported as the 0th argument");
+ std::size_t idx = 1u;
+ for (auto &&input_name : uu.params.input_names) {
+ auto &ii = uu.inputs.at(input_name);
+ const auto &mm = in_metas[idx];
+ GAPI_Assert(util::holds_alternative<cv::GArrayDesc>(mm)
+ && "Non-array inputs are not supported");
+
+ if (op.k.inKinds[idx] == cv::detail::OpaqueKind::CV_RECT) {
+ // This is a cv::Rect -- configure the IE preprocessing
+ ii->setPrecision(toIE(meta_0.depth));
+ ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
+ } else {
+ // This is a cv::GMat (equals to: cv::Mat)
+ // Just validate that it is really the type
+ // (other types are prohibited here)
+ GAPI_Assert(op.k.inKinds[idx] == cv::detail::OpaqueKind::CV_MAT);
+ }
+ idx++; // NB: Never forget to increment the counter
+ }
+
+ // roi-list version is much easier at the moment.
+ // All our outputs are vectors which don't have
+ // metadata at the moment - so just create a vector of
+ // "empty" array metadatas of the required size.
+ return cv::GMetaArgs(uu.params.output_names.size(),
+ cv::GMetaArg{cv::empty_array_desc()});
+ }
+
+ static void run(IECompiled &iec, const IEUnit &uu, IECallContext &ctx) {
+ GAPI_Assert(ctx.args.size() > 1u
+ && "This operation must have at least two arguments");
+
+ // Since we do a ROI list inference, always assume our input buffer is image
+ const cv::Mat mat_0 = ctx.inMat(0u);
+ IE::Blob::Ptr blob_0 = wrapIE(mat_0, cv::gapi::ie::TraitAs::IMAGE);
+
+ // Take the next argument, which must be vector (of any kind).
+ // Use it only to obtain the ROI list size (sizes of all other
+ // vectors must be equal to this one)
+ const auto list_size = ctx.inArg<cv::detail::VectorRef>(1u).size();
+
+ // FIXME: This could be done ONCE at graph compile stage!
+ std::vector< std::vector<int> > cached_dims(uu.params.num_out);
+ for (auto i : ade::util::iota(uu.params.num_out)) {
+ const IE::DataPtr& ie_out = uu.outputs.at(uu.params.output_names[i]);
+ cached_dims[i] = toCV(ie_out->getTensorDesc().getDims());
+ ctx.outVecR<cv::Mat>(i).clear();
+ // FIXME: Isn't this should be done automatically
+ // by some resetInternalData(), etc? (Probably at the GExecutor level)
+ }
+
+ // For every ROI in the list {{{
+ for (const auto &list_idx : ade::util::iota(list_size)) {
+ // For every input of the net {{{
+ for (auto in_idx : ade::util::iota(uu.params.num_in)) {
+ const auto &this_vec = ctx.inArg<cv::detail::VectorRef>(in_idx+1u);
+ GAPI_Assert(this_vec.size() == list_size);
+ // Prepare input {{{
+ IE::Blob::Ptr this_blob;
+ if (this_vec.getKind() == cv::detail::OpaqueKind::CV_RECT) {
+ // ROI case - create an ROI blob
+ const auto &vec = this_vec.rref<cv::Rect>();
+ this_blob = IE::make_shared_blob(blob_0, toIE(vec[list_idx]));
+ } else if (this_vec.getKind() == cv::detail::OpaqueKind::CV_MAT) {
+ // Mat case - create a regular blob
+ // FIXME: NOW Assume Mats are always BLOBS (not
+ // images)
+ const auto &vec = this_vec.rref<cv::Mat>();
+ const auto &mat = vec[list_idx];
+ this_blob = wrapIE(mat, cv::gapi::ie::TraitAs::TENSOR);
+ } else {
+ GAPI_Assert(false && "Only Rect and Mat types are supported for infer list 2!");
+ }
+ iec.this_request.SetBlob(uu.params.input_names[in_idx], this_blob);
+ // }}} (Preapre input)
+ } // }}} (For every input of the net)
+
+ // Run infer request {{{
+ iec.this_request.Infer();
+ // }}} (Run infer request)
+
+ // For every output of the net {{{
+ for (auto i : ade::util::iota(uu.params.num_out)) {
+ // Push results to the list {{{
+ std::vector<cv::Mat> &out_vec = ctx.outVecR<cv::Mat>(i);
+ IE::Blob::Ptr out_blob = iec.this_request.GetBlob(uu.params.output_names[i]);
+ cv::Mat out_mat(cached_dims[i], toCV(out_blob->getTensorDesc().getPrecision()));
+ copyFromIE(out_blob, out_mat); // FIXME: Avoid data copy. Not sure if it is possible though
+ out_vec.push_back(std::move(out_mat));
+ // }}} (Push results to the list)
+ } // }}} (For every output of the net)
+ } // }}} (For every ROI in the list)
+ }
+};
+
} // namespace ie
} // namespace gapi
} // namespace cv
virtual cv::gapi::GKernelPackage auxiliaryKernels() const override {
return cv::gapi::kernels< cv::gimpl::ie::Infer
, cv::gimpl::ie::InferList
+ , cv::gimpl::ie::InferList2
>();
}
};
return this_backend;
}
-cv::Mat cv::gapi::ie::util::to_ocv(InferenceEngine::Blob::Ptr blob) {
+cv::Mat cv::gapi::ie::util::to_ocv(IE::Blob::Ptr blob) {
const auto& tdesc = blob->getTensorDesc();
return cv::Mat(toCV(tdesc.getDims()),
toCV(tdesc.getPrecision()),
blob->buffer().as<uint8_t*>());
}
-std::vector<int> cv::gapi::ie::util::to_ocv(const InferenceEngine::SizeVector &dims) {
+std::vector<int> cv::gapi::ie::util::to_ocv(const IE::SizeVector &dims) {
return toCV(dims);
}
-InferenceEngine::Blob::Ptr cv::gapi::ie::util::to_ie(cv::Mat &blob) {
+IE::Blob::Ptr cv::gapi::ie::util::to_ie(cv::Mat &blob) {
return wrapIE(blob, cv::gapi::ie::TraitAs::IMAGE);
}
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GIEBACKEND_HPP
#define OPENCV_GAPI_GIEBACKEND_HPP
#include <ade/util/algorithm.hpp> // type_list_index
-////////////////////////////////////////////////////////////////////////////////
-// FIXME: Suppress deprecation warnings for OpenVINO 2019R2+
-// BEGIN {{{
-#if defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-#ifdef _MSC_VER
-#pragma warning(disable: 4996) // was declared deprecated
-#endif
-
-#if defined(__GNUC__)
-#pragma GCC visibility push(default)
-#endif
-
#include <inference_engine.hpp>
-#if defined(__GNUC__)
-#pragma GCC visibility pop
-#endif
-// END }}}
-////////////////////////////////////////////////////////////////////////////////
-
#include <opencv2/gapi/garg.hpp>
#include <opencv2/gapi/gproto.hpp>
namespace ie {
struct IECompiled {
+#if INF_ENGINE_RELEASE < 2019020000 // < 2019.R2
InferenceEngine::InferencePlugin this_plugin;
+#else
+ InferenceEngine::Core this_core;
+#endif
InferenceEngine::ExecutableNetwork this_network;
InferenceEngine::InferRequest this_request;
};
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#ifdef HAVE_INF_ENGINE
+
+#include <vector>
+#include <string>
+#include <tuple>
+
+#include "backends/ie/giebackend/giewrapper.hpp"
+
+#include <ade/util/range.hpp>
+#include <ade/util/zip_range.hpp>
+
+#include <opencv2/core/utility.hpp>
+#include <opencv2/core/utils/logger.hpp>
+
+namespace IE = InferenceEngine;
+namespace giewrap = cv::gimpl::ie::wrap;
+using GIEParam = cv::gapi::ie::detail::ParamDesc;
+
+#if INF_ENGINE_RELEASE < 2020000000 // < 2020.1
+// Load extensions (taken from DNN module)
+std::vector<std::string> giewrap::getExtensions(const GIEParam& params) {
+ std::vector<std::string> candidates;
+ if (params.device_id == "CPU" || params.device_id == "FPGA")
+ {
+ const std::string suffixes[] = { "_avx2", "_sse4", ""};
+ const bool haveFeature[] = {
+ cv::checkHardwareSupport(CPU_AVX2),
+ cv::checkHardwareSupport(CPU_SSE4_2),
+ true
+ };
+ for (auto &&it : ade::util::zip(ade::util::toRange(suffixes),
+ ade::util::toRange(haveFeature)))
+ {
+ std::string suffix;
+ bool available = false;
+ std::tie(suffix, available) = it;
+ if (!available) continue;
+#ifdef _WIN32
+ candidates.push_back("cpu_extension" + suffix + ".dll");
+#elif defined(__APPLE__)
+ candidates.push_back("libcpu_extension" + suffix + ".so"); // built as loadable module
+ candidates.push_back("libcpu_extension" + suffix + ".dylib"); // built as shared library
+#else
+ candidates.push_back("libcpu_extension" + suffix + ".so");
+#endif // _WIN32
+ }
+ }
+ return candidates;
+}
+
+IE::CNNNetwork giewrap::readNetwork(const GIEParam& params) {
+ IE::CNNNetReader reader;
+ reader.ReadNetwork(params.model_path);
+ reader.ReadWeights(params.weights_path);
+ return reader.getNetwork();
+}
+#else // >= 2020.1
+std::vector<std::string> giewrap::getExtensions(const GIEParam&) {
+ return std::vector<std::string>();
+}
+
+IE::CNNNetwork giewrap::readNetwork(const GIEParam& params) {
+ auto core = giewrap::getCore();
+ return core.ReadNetwork(params.model_path, params.weights_path);
+}
+#endif // INF_ENGINE_RELEASE < 2020000000
+
+#if INF_ENGINE_RELEASE < 2019020000 // < 2019.R2
+IE::InferencePlugin giewrap::getPlugin(const GIEParam& params) {
+ auto plugin = IE::PluginDispatcher().getPluginByDevice(params.device_id);
+ if (params.device_id == "CPU" || params.device_id == "FPGA")
+ {
+ for (auto &&extlib : giewrap::getExtensions(params))
+ {
+ try
+ {
+ plugin.AddExtension(IE::make_so_pointer<IE::IExtension>(extlib));
+ CV_LOG_INFO(NULL, "DNN-IE: Loaded extension plugin: " << extlib);
+ break;
+ }
+ catch(...)
+ {
+ CV_LOG_INFO(NULL, "Failed to load IE extension: " << extlib);
+ }
+ }
+ }
+ return plugin;
+}
+#else // >= 2019.R2
+IE::Core giewrap::getCore() {
+ static IE::Core core;
+ return core;
+}
+
+IE::Core giewrap::getPlugin(const GIEParam& params) {
+ auto plugin = giewrap::getCore();
+ if (params.device_id == "CPU" || params.device_id == "FPGA")
+ {
+ for (auto &&extlib : giewrap::getExtensions(params))
+ {
+ try
+ {
+ plugin.AddExtension(IE::make_so_pointer<IE::IExtension>(extlib), params.device_id);
+ CV_LOG_INFO(NULL, "DNN-IE: Loaded extension plugin: " << extlib);
+ break;
+ }
+ catch(...)
+ {
+ CV_LOG_INFO(NULL, "Failed to load IE extension: " << extlib);
+ }
+ }
+ }
+ return plugin;
+}
+#endif // INF_ENGINE_RELEASE < 2019020000
+
+#endif //HAVE_INF_ENGINE
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#ifndef OPENCV_GAPI_IEWRAPPER_HPP
+#define OPENCV_GAPI_IEWRAPPER_HPP
+
+#ifdef HAVE_INF_ENGINE
+
+#include <inference_engine.hpp>
+
+#include <vector>
+#include <string>
+
+#include "opencv2/gapi/infer/ie.hpp"
+
+namespace IE = InferenceEngine;
+using GIEParam = cv::gapi::ie::detail::ParamDesc;
+
+namespace cv {
+namespace gimpl {
+namespace ie {
+namespace wrap {
+// NB: These functions are EXPORTed to make them accessible by the
+// test suite only.
+GAPI_EXPORTS std::vector<std::string> getExtensions(const GIEParam& params);
+GAPI_EXPORTS IE::CNNNetwork readNetwork(const GIEParam& params);
+
+#if INF_ENGINE_RELEASE < 2019020000 // < 2019.R2
+GAPI_EXPORTS IE::InferencePlugin getPlugin(const GIEParam& params);
+GAPI_EXPORTS inline IE::ExecutableNetwork loadNetwork( IE::InferencePlugin& plugin,
+ const IE::CNNNetwork& net,
+ const GIEParam&) {
+ return plugin.LoadNetwork(net, {}); // FIXME: 2nd parameter to be
+ // configurable via the API
+}
+#else // >= 2019.R2
+GAPI_EXPORTS IE::Core getCore();
+GAPI_EXPORTS IE::Core getPlugin(const GIEParam& params);
+GAPI_EXPORTS inline IE::ExecutableNetwork loadNetwork( IE::Core& core,
+ const IE::CNNNetwork& net,
+ const GIEParam& params) {
+ return core.LoadNetwork(net, params.device_id);
+}
+#endif // INF_ENGINE_RELEASE < 2019020000
+}}}}
+
+#endif //HAVE_INF_ENGINE
+#endif // OPENCV_GAPI_IEWRAPPER_HPP
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
//
// If not, we need to introduce that!
using GOCLModel = ade::TypedGraph
- < cv::gimpl::Unit
+ < cv::gimpl::OCLUnit
, cv::gimpl::Protocol
>;
// FIXME: Same issue with Typed and ConstTyped
using GConstGOCLModel = ade::ConstTypedGraph
- < cv::gimpl::Unit
+ < cv::gimpl::OCLUnit
, cv::gimpl::Protocol
>;
{
GOCLModel gm(graph);
auto ocl_impl = cv::util::any_cast<cv::GOCLKernel>(impl.opaque);
- gm.metadata(op_node).set(cv::gimpl::Unit{ocl_impl});
+ gm.metadata(op_node).set(cv::gimpl::OCLUnit{ocl_impl});
}
virtual EPtr compile(const ade::Graph &graph,
if (desc.storage == Data::Storage::INTERNAL && desc.shape == GShape::GMAT)
{
const auto mat_desc = util::get<cv::GMatDesc>(desc.meta);
- auto& mat = m_res.slot<cv::gapi::own::Mat>()[desc.rc];
+ auto& mat = m_res.slot<cv::Mat>()[desc.rc];
createMat(mat_desc, mat);
}
break;
// Obtain our real execution unit
// TODO: Should kernels be copyable?
- GOCLKernel k = gcm.metadata(op_info.nh).get<Unit>().k;
+ GOCLKernel k = gcm.metadata(op_info.nh).get<OCLUnit>().k;
// Initialize kernel's execution context:
// - Input parameters
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GOCLBACKEND_HPP
namespace cv { namespace gimpl {
-struct Unit
+struct OCLUnit
{
static const char *name() { return "OCLKernel"; }
GOCLKernel k;
}
};
+GAPI_OCL_KERNEL(GOCLLaplacian, cv::gapi::imgproc::GLaplacian)
+{
+ static void run(const cv::UMat& in, int ddepth, int ksize, double scale,
+ double delta, int borderType, cv::UMat &out)
+ {
+ cv::Laplacian(in, out, ddepth, ksize, scale, delta, borderType);
+ }
+};
+
+GAPI_OCL_KERNEL(GOCLBilateralFilter, cv::gapi::imgproc::GBilateralFilter)
+{
+ static void run(const cv::UMat& in, int ddepth, double sigmaColor,
+ double sigmaSpace, int borderType, cv::UMat &out)
+ {
+ cv::bilateralFilter(in, out, ddepth, sigmaColor, sigmaSpace, borderType);
+ }
+};
+
GAPI_OCL_KERNEL(GOCLEqualizeHist, cv::gapi::imgproc::GEqHist)
{
static void run(const cv::UMat& in, cv::UMat &out)
, GOCLErode
, GOCLDilate
, GOCLSobel
+ , GOCLLaplacian
+ , GOCLBilateralFilter
, GOCLCanny
, GOCLEqualizeHist
, GOCLRGB2YUV
// 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
+// Copyright (C) 2019-2020 Intel Corporation
#ifdef HAVE_PLAIDML
const std::vector<cv::gimpl::Data>& ins_data,
const std::vector<cv::gimpl::Data>& outs_data) const override
{
- auto has_config = cv::gimpl::getCompileArg<cv::gapi::plaidml::config>(args);
+ auto has_config = cv::gapi::getCompileArg<cv::gapi::plaidml::config>(args);
if (!has_config)
{
switch (arg.index())
{
- case GRunArg::index_of<cv::gapi::own::Mat>():
- {
- auto& arg_mat = util::get<cv::gapi::own::Mat>(arg);
- binder_->input(it->second).copy_from(arg_mat.data);
- }
- break;
-#if !defined(GAPI_STANDALONE)
case GRunArg::index_of<cv::Mat>() :
{
auto& arg_mat = util::get<cv::Mat>(arg);
binder_->input(it->second).copy_from(arg_mat.data);
}
break;
-#endif // !defined(GAPI_STANDALONE)
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
}
}
switch (arg.index())
{
- case GRunArgP::index_of<cv::gapi::own::Mat*>():
- {
- auto& arg_mat = *util::get<cv::gapi::own::Mat*>(arg);
- binder_->output(it->second).copy_into(arg_mat.data);
- }
- break;
-#if !defined(GAPI_STANDALONE)
case GRunArgP::index_of<cv::Mat*>() :
{
auto& arg_mat = *util::get<cv::Mat*>(arg);
binder_->output(it->second).copy_into(arg_mat.data);
}
break;
-#endif // !defined(GAPI_STANDALONE)
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
}
}
// Copyright (C) 2019 Intel Corporation
-#ifdef HAVE_PLAIDML
-
#include "precomp.hpp"
#include <opencv2/gapi/core.hpp>
+
#include <opencv2/gapi/plaidml/core.hpp>
+
+#ifdef HAVE_PLAIDML
+
#include <opencv2/gapi/plaidml/gplaidmlkernel.hpp>
#include <plaidml2/edsl/edsl.h>
return pkg;
}
-#endif // HACE_PLAIDML
+#else // HAVE_PLAIDML
+
+cv::gapi::GKernelPackage cv::gapi::core::plaidml::kernels()
+{
+ // Still provide this symbol to avoid linking issues
+ util::throw_error(std::runtime_error("G-API has been compiled without PlaidML2 support"));
+}
+
+#endif // HAVE_PLAIDML
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
context.m_args.emplace_back(m_ftpr.get());
- k.apply(context);
+ k.m_runF(context);
for (auto &it : output_objs) magazine::writeBack(m_res, it.first, it.second);
}
const cv::gimpl::RcDesc &ref = arg.get<cv::gimpl::RcDesc>();
switch (ref.shape)
{
- case GShape::GMAT: return GArg(m_res.slot<cv::gapi::own::Mat>()[ref.id]);
+ case GShape::GMAT: return GArg(m_res.slot<cv::Mat>()[ref.id]);
case GShape::GARRAY: return GArg(m_res.slot<cv::detail::VectorRef>().at(ref.id));
default:
util::throw_error(std::logic_error("Unsupported GShape type"));
const std::vector<ade::NodeHandle> &nodes) const override {
using namespace cv::gapi::wip::draw;
- auto has_freetype_font = cv::gimpl::getCompileArg<freetype_font>(args);
+ auto has_freetype_font = cv::gapi::getCompileArg<freetype_font>(args);
std::unique_ptr<FTTextRender> ftpr;
if (has_freetype_font)
{
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
m_metas = inMetas;
}
+void cv::GCompiled::Priv::prepareForNewStream()
+{
+ GAPI_Assert(m_exec);
+ m_exec->prepareForNewStream();
+}
+
const cv::gimpl::GModel::Graph& cv::GCompiled::Priv::model() const
{
GAPI_Assert(nullptr != m_exec);
{
m_priv->reshape(inMetas, args);
}
+
+void cv::GCompiled::prepareForNewStream()
+{
+ m_priv->prepareForNewStream();
+}
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GCOMPILED_PRIV_HPP
bool canReshape() const;
void reshape(const GMetaArgs& inMetas, const GCompileArgs &args);
+ void prepareForNewStream();
void run(cv::gimpl::GRuntimeArgs &&args);
const GMetaArgs& metas() const;
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
// <FIXME:>
#if !defined(GAPI_STANDALONE)
-#include <opencv2/gapi/cpu/core.hpp> // Also directly refer to Core
-#include <opencv2/gapi/cpu/imgproc.hpp> // ...and Imgproc kernel implementations
+#include <opencv2/gapi/cpu/core.hpp> // Also directly refer to Core,
+#include <opencv2/gapi/cpu/imgproc.hpp> // ...Imgproc
+#include <opencv2/gapi/cpu/video.hpp> // ...and Video kernel implementations
#include <opencv2/gapi/render/render.hpp> // render::ocv::backend()
#endif // !defined(GAPI_STANDALONE)
// </FIXME:>
return combine(pkg, aux_pkg);
};
- auto has_use_only = cv::gimpl::getCompileArg<cv::gapi::use_only>(args);
+ auto has_use_only = cv::gapi::getCompileArg<cv::gapi::use_only>(args);
if (has_use_only)
return withAuxKernels(has_use_only.value().pkg);
static auto ocv_pkg =
#if !defined(GAPI_STANDALONE)
- // FIXME add N-arg version combine
- combine(combine(cv::gapi::core::cpu::kernels(),
- cv::gapi::imgproc::cpu::kernels()),
+ combine(cv::gapi::core::cpu::kernels(),
+ cv::gapi::imgproc::cpu::kernels(),
+ cv::gapi::video::cpu::kernels(),
cv::gapi::render::ocv::kernels());
#else
cv::gapi::GKernelPackage();
#endif // !defined(GAPI_STANDALONE)
- auto user_pkg = cv::gimpl::getCompileArg<cv::gapi::GKernelPackage>(args);
+ auto user_pkg = cv::gapi::getCompileArg<cv::gapi::GKernelPackage>(args);
auto user_pkg_with_aux = withAuxKernels(user_pkg.value_or(cv::gapi::GKernelPackage{}));
return combine(ocv_pkg, user_pkg_with_aux);
}
cv::gapi::GNetPackage getNetworkPackage(cv::GCompileArgs &args)
{
- return cv::gimpl::getCompileArg<cv::gapi::GNetPackage>(args)
+ return cv::gapi::getCompileArg<cv::gapi::GNetPackage>(args)
.value_or(cv::gapi::GNetPackage{});
}
cv::util::optional<std::string> getGraphDumpDirectory(cv::GCompileArgs& args)
{
- auto dump_info = cv::gimpl::getCompileArg<cv::graph_dump_path>(args);
+ auto dump_info = cv::gapi::getCompileArg<cv::graph_dump_path>(args);
if (!dump_info.has_value())
{
const char* path = getenv("GRAPH_DUMP_PATH");
return result;
}
- // Creates ADE graph from input/output proto args
- std::unique_ptr<ade::Graph> makeGraph(const cv::GProtoArgs &ins, const cv::GProtoArgs &outs) {
- std::unique_ptr<ade::Graph> pG(new ade::Graph);
- ade::Graph& g = *pG;
-
- cv::gimpl::GModel::Graph gm(g);
- cv::gimpl::GModel::init(gm);
- cv::gimpl::GModelBuilder builder(g);
- auto proto_slots = builder.put(ins, outs);
-
- // Store Computation's protocol in metadata
- cv::gimpl::Protocol p;
- std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
- gm.metadata().set(p);
-
- return pG;
- }
-
using adeGraphs = std::vector<std::unique_ptr<ade::Graph>>;
// Creates ADE graphs (patterns and substitutes) from pkg's transformations
ade::util::toRange(patterns),
ade::util::toRange(substitutes))) {
const auto& t = std::get<0>(it);
- auto& p = std::get<1>(it);
- auto& s = std::get<2>(it);
-
- auto pattern_comp = t.pattern();
- p = makeGraph(pattern_comp.priv().m_ins, pattern_comp.priv().m_outs);
-
- auto substitute_comp = t.substitute();
- s = makeGraph(substitute_comp.priv().m_ins, substitute_comp.priv().m_outs);
+ auto& p = std::get<1>(it);
+ auto& s = std::get<2>(it);
+ p = cv::gimpl::GCompiler::makeGraph(t.pattern().priv());
+ s = cv::gimpl::GCompiler::makeGraph(t.substitute().priv());
}
}
void cv::gimpl::GCompiler::validateInputMeta()
{
- if (m_metas.size() != m_c.priv().m_ins.size())
+ // FIXME: implement testing/accessor methods at the Priv's API level?
+ if (!util::holds_alternative<GComputation::Priv::Expr>(m_c.priv().m_shape))
+ {
+ GAPI_LOG_WARNING(NULL, "Metadata validation is not implemented yet for"
+ " deserialized graphs!");
+ return;
+ }
+ const auto &c_expr = util::get<cv::GComputation::Priv::Expr>(m_c.priv().m_shape);
+ if (m_metas.size() != c_expr.m_ins.size())
{
util::throw_error(std::logic_error
("COMPILE: GComputation interface / metadata mismatch! "
- "(expected " + std::to_string(m_c.priv().m_ins.size()) + ", "
+ "(expected " + std::to_string(c_expr.m_ins.size()) + ", "
"got " + std::to_string(m_metas.size()) + " meta arguments)"));
}
// FIXME: Auto-generate methods like this from traits:
case GProtoArg::index_of<cv::GMat>():
case GProtoArg::index_of<cv::GMatP>():
+ case GProtoArg::index_of<cv::GFrame>():
return util::holds_alternative<cv::GMatDesc>(meta);
case GProtoArg::index_of<cv::GScalar>():
return false; // should never happen
};
- for (const auto &meta_arg_idx : ade::util::indexed(ade::util::zip(m_metas, m_c.priv().m_ins)))
+ for (const auto &meta_arg_idx : ade::util::indexed(ade::util::zip(m_metas, c_expr.m_ins)))
{
const auto &meta = std::get<0>(ade::util::value(meta_arg_idx));
const auto &proto = std::get<1>(ade::util::value(meta_arg_idx));
void cv::gimpl::GCompiler::validateOutProtoArgs()
{
- for (const auto &out_pos : ade::util::indexed(m_c.priv().m_outs))
+ // FIXME: implement testing/accessor methods at the Priv's API level?
+ if (!util::holds_alternative<GComputation::Priv::Expr>(m_c.priv().m_shape))
+ {
+ GAPI_LOG_WARNING(NULL, "Output parameter validation is not implemented yet for"
+ " deserialized graphs!");
+ return;
+ }
+ const auto &c_expr = util::get<cv::GComputation::Priv::Expr>(m_c.priv().m_shape);
+ for (const auto &out_pos : ade::util::indexed(c_expr.m_outs))
{
const auto &node = proto::origin_of(ade::util::value(out_pos)).node;
if (node.shape() != cv::GNode::NodeShape::CALL)
validateInputMeta();
}
validateOutProtoArgs();
- auto g = makeGraph(m_c.priv().m_ins, m_c.priv().m_outs);
+ auto g = makeGraph(m_c.priv());
if (!m_metas.empty())
{
GModel::Graph(*g).metadata().set(OriginalInputMeta{m_metas});
outMetas = GModel::ConstGraph(*pg).metadata().get<OutputMeta>().outMeta;
}
- std::unique_ptr<GStreamingExecutor> pE(new GStreamingExecutor(std::move(pg)));
+ std::unique_ptr<GStreamingExecutor> pE(new GStreamingExecutor(std::move(pg),
+ m_args));
if (!m_metas.empty() && !outMetas.empty())
{
compiled.priv().setup(m_metas, outMetas, std::move(pE));
}
engine.runPasses(g);
}
+
+// Creates ADE graph from input/output proto args OR from its
+// deserialized form
+cv::gimpl::GCompiler::GPtr cv::gimpl::GCompiler::makeGraph(const cv::GComputation::Priv &priv) {
+ std::unique_ptr<ade::Graph> pG(new ade::Graph);
+ ade::Graph& g = *pG;
+
+ if (cv::util::holds_alternative<cv::GComputation::Priv::Expr>(priv.m_shape)) {
+ auto c_expr = cv::util::get<cv::GComputation::Priv::Expr>(priv.m_shape);
+ cv::gimpl::GModel::Graph gm(g);
+ cv::gimpl::GModel::init(gm);
+ cv::gimpl::GModelBuilder builder(g);
+ auto proto_slots = builder.put(c_expr.m_ins, c_expr.m_outs);
+
+ // Store Computation's protocol in metadata
+ cv::gimpl::Protocol p;
+ std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
+ gm.metadata().set(p);
+ } else if (cv::util::holds_alternative<cv::GComputation::Priv::Dump>(priv.m_shape)) {
+ auto c_dump = cv::util::get<cv::GComputation::Priv::Dump>(priv.m_shape);
+ cv::gimpl::s11n::reconstruct(c_dump, g);
+ }
+ return pG;
+}
GCompiled produceCompiled(GPtr &&pg); // Produce GCompiled from processed GModel
GStreamingCompiled produceStreamingCompiled(GPtr &&pg); // Produce GStreamingCompiled from processed GMbodel
static void runMetaPasses(ade::Graph &g, const cv::GMetaArgs &metas);
+
+ static GPtr makeGraph(const cv::GComputation::Priv &);
};
}}
#include <unordered_map>
#include <ade/util/checked_cast.hpp>
+#include <ade/util/zip_range.hpp> // zip_range, indexed
#include "api/gbackend_priv.hpp" // GBackend::Priv().compile()
#include "compiler/gmodel.hpp"
}
// Consistency: A GIsland requested for producer() of slot_nh should
// always had the appropriate GModel node handle in its m_out_ops vector.
- GAPI_Assert(false);
- return ade::NodeHandle();
+ GAPI_Assert(false && "Broken GIslandModel ?.");
}
std::string GIsland::name() const
return ade::NodeHandle();
}
+void GIslandExecutable::run(GIslandExecutable::IInput &in, GIslandExecutable::IOutput &out)
+{
+ // Default implementation: just reuse the existing old-fashioned run
+ // Build a single synchronous execution frame for it.
+ std::vector<InObj> in_objs;
+ std::vector<OutObj> out_objs;
+ const auto &in_desc = in.desc();
+ const auto &out_desc = out.desc();
+ const auto in_msg = in.get();
+ if (cv::util::holds_alternative<cv::gimpl::EndOfStream>(in_msg))
+ {
+ out.post(cv::gimpl::EndOfStream{});
+ return;
+ }
+ GAPI_Assert(cv::util::holds_alternative<cv::GRunArgs>(in_msg));
+ const auto in_vector = cv::util::get<cv::GRunArgs>(in_msg);
+ in_objs.reserve(in_desc.size());
+ out_objs.reserve(out_desc.size());
+ for (auto &&it: ade::util::zip(ade::util::toRange(in_desc),
+ ade::util::toRange(in_vector)))
+ {
+ // FIXME: Not every Island expects a cv::Mat instead of own::Mat on input
+ // This kludge should go as a result of de-ownification
+ const cv::GRunArg& in_data_orig = std::get<1>(it);
+ cv::GRunArg in_data;
+#if !defined(GAPI_STANDALONE)
+ switch (in_data_orig.index())
+ {
+ case cv::GRunArg::index_of<cv::Mat>():
+ in_data = cv::GRunArg{cv::util::get<cv::Mat>(in_data_orig)};
+ break;
+ case cv::GRunArg::index_of<cv::Scalar>():
+ in_data = cv::GRunArg{(cv::util::get<cv::Scalar>(in_data_orig))};
+ break;
+ default:
+ in_data = in_data_orig;
+ break;
+ }
+#else
+ in_data = in_data_orig;
+#endif // GAPI_STANDALONE
+ in_objs.emplace_back(std::get<0>(it), std::move(in_data));
+ }
+ for (auto &&it: ade::util::indexed(ade::util::toRange(out_desc)))
+ {
+ out_objs.emplace_back(ade::util::value(it),
+ out.get(ade::util::checked_cast<int>(ade::util::index(it))));
+ }
+ run(std::move(in_objs), std::move(out_objs));
+ for (auto &&it: out_objs)
+ {
+ out.post(std::move(it.second)); // report output objects as "ready" to the executor
+ }
+}
+
} // namespace cv
} // namespace gimpl
util::optional<std::string> m_user_tag;
};
-
-
// GIslandExecutable - a backend-specific thing which executes
// contents of an Island
// * Is instantiated by the last step of the Islands fusion procedure;
// * Is orchestrated by a GExecutor instance.
//
-
-class GIslandExecutable
+// GAPI_EXPORTS is here since this class comes with the default
+// implementation to some methods and it needs to be exported to allow
+// it to use in the external (extra) backends.
+class GAPI_EXPORTS GIslandExecutable
{
public:
using InObj = std::pair<RcDesc, cv::GRunArg>;
using OutObj = std::pair<RcDesc, cv::GRunArgP>;
+ class IODesc;
+ struct IInput;
+ struct IOutput;
+
// FIXME: now run() requires full input vector to be available.
// actually, parts of subgraph may execute even if there's no all data
// slots in place.
// TODO: Add partial execution capabilities
+ // TODO: This method is now obsolette and is here for backwards
+ // compatibility only. Use (implement) the new run instead.
virtual void run(std::vector<InObj> &&input_objs,
std::vector<OutObj> &&output_objs) = 0;
+ // Let the island execute. I/O data is obtained from/submitted to
+ // in/out objects.
+ virtual void run(IInput &in, IOutput &out);
+
virtual bool canReshape() const = 0;
virtual void reshape(ade::Graph& g, const GCompileArgs& args) = 0;
+ // This method is called when the GStreamingCompiled gets a new
+ // input source to process. Normally this method is called once
+ // per stream execution.
+ //
+ // The idea of this method is to reset backend's stream-associated
+ // internal state, if there is any.
+ //
+ // The regular GCompiled invocation doesn't call this, there may
+ // be reset() introduced there but it is completely unnecessary at
+ // this moment.
+ //
+ // FIXME: The design on this and so-called "stateful" kernels is not
+ // closed yet.
+ // FIXME: This thing will likely break stuff once we introduce
+ // "multi-source streaming", a better design needs to be proposed
+ // at that stage.
+ virtual void handleNewStream() {}; // do nothing here by default
+
virtual ~GIslandExecutable() = default;
};
+class GIslandExecutable::IODesc {
+ std::vector<cv::gimpl::RcDesc> d;
+public:
+ void set(std::vector<cv::gimpl::RcDesc> &&newd) { d = std::move(newd); }
+ void set(const std::vector<cv::gimpl::RcDesc> &newd) { d = newd; }
+ const std::vector<cv::gimpl::RcDesc> &desc() const { return d; }
+};
+struct EndOfStream {};
+using StreamMsg = cv::util::variant<EndOfStream, cv::GRunArgs>;
+struct GIslandExecutable::IInput: public GIslandExecutable::IODesc {
+ virtual ~IInput() = default;
+ virtual StreamMsg get() = 0; // Get a new input vector (blocking)
+ virtual StreamMsg try_get() = 0; // Get a new input vector (non-blocking)
+};
+struct GIslandExecutable::IOutput: public GIslandExecutable::IODesc {
+ virtual ~IOutput() = default;
+ virtual GRunArgP get(int idx) = 0; // Allocate (wrap) a new data object for output idx
+ virtual void post(GRunArgP&&) = 0; // Release the object back to the framework (mark available)
+ virtual void post(EndOfStream&&) = 0; // Post end-of-stream marker back to the framework
+};
+
// GIslandEmitter - a backend-specific thing which feeds data into
// the pipeline. This one is just an interface, implementations are executor-defined.
class GIslandEmitter
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
// associated host-type constructor (e.g. when the array is
// somewhere in the middle of the graph).
auto ctor_copy = origin.ctor;
- g.metadata(data_h).set(Data{origin.shape, id, meta, ctor_copy, storage});
+ g.metadata(data_h).set(Data{origin.shape, id, meta, ctor_copy, origin.kind, storage});
return data_h;
}
GMetaArg meta;
HostCtor ctor;
Data::Storage storage = Data::Storage::INTERNAL; // By default, all objects are marked INTERNAL
+ cv::detail::OpaqueKind kind = cv::detail::OpaqueKind::CV_UNKNOWN;
- g.metadata(data_h).set(Data{shape, id, meta, ctor, storage});
+ g.metadata(data_h).set(Data{shape, id, meta, ctor, kind, storage});
return data_h;
}
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GMODEL_HPP
#include <opencv2/gapi/garg.hpp>
#include <opencv2/gapi/gkernel.hpp>
+#include <opencv2/gapi/gcommon.hpp>
#include "compiler/gobjref.hpp"
#include "compiler/gislandmodel.hpp"
int rc;
GMetaArg meta;
HostCtor ctor; // T-specific helper to deal with unknown types in our code
+ cv::detail::OpaqueKind kind; // FIXME: is needed to store GArray/GOpaque type
// FIXME: Why rc+shape+meta is not represented as RcDesc here?
- enum class Storage
+ enum class Storage: int
{
INTERNAL, // data object is not listed in GComputation protocol
INPUT, // data object is listed in GComputation protocol as Input
public:
static const char* name() { return "DataObjectCounter"; }
int GetNewId(GShape shape) { return m_next_data_id[shape]++; }
-private:
+
+ // NB: private!!! but used in the serialization
+ // couldn't get the `friend` stuff working correctly -- DM
std::unordered_map<cv::GShape, int> m_next_data_id;
};
static const char *name() { return "StreamingFlag"; }
};
+
+// This is a graph-global flag indicating this graph is compiled
+// after the deserialization. Some bits of information may be
+// unavailable (mainly callbacks) so let sensitive passes obtain
+// the required information in their special way.
+//
+// FIXME: Probably a better design can be suggested.
+struct Deserialized
+{
+ static const char *name() { return "DeserializedFlag"; }
+};
+
+
// Backend-specific inference parameters for a neural network.
// Since these parameters are set on compilation stage (not
// on a construction stage), these parameters are bound lately
, ActiveBackends
, CustomMetaFunction
, Streaming
+ , Deserialized
>;
// FIXME: How to define it based on GModel???
, ActiveBackends
, CustomMetaFunction
, Streaming
+ , Deserialized
>;
// FIXME:
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
////////////////////////////////////////////////////////////////////////////////
std::size_t port = ade::util::index(it);
GShape shape = ade::util::value(it);
- GOrigin org { shape, node, port};
+ GOrigin org { shape, node, port, {}, origin.kind };
origins.insert(org);
}
using ConstVal = util::variant
< util::monostate
, cv::Scalar
+ , cv::detail::VectorRef
>;
struct RcDesc
selected_backend.priv().unpackKernel(ctx.graph, nh, selected_impl);
op.backend = selected_backend;
active_backends.insert(selected_backend);
+
+ if (gr.metadata().contains<Deserialized>())
+ {
+ // Trick: in this case, the op.k.outMeta is by default
+ // missing. Take it from the resolved kernel
+ GAPI_Assert(op.k.outMeta == nullptr);
+ const_cast<cv::GKernel::M&>(op.k.outMeta) = selected_impl.outMeta;
+ } else {
+ // Sanity check: the metadata funciton must be present
+ GAPI_Assert(op.k.outMeta != nullptr);
+ }
}
}
gr.metadata().set(ActiveBackends{active_backends});
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
GAPI_Assert(gr.metadata(output_nh).get<NodeType>().t == NodeType::DATA);
auto &output_meta = gr.metadata(output_nh).get<Data>().meta;
- if (!meta_is_initialized && !util::holds_alternative<util::monostate>(output_meta))
- {
- GAPI_LOG_INFO(NULL,
- "!!! Output object has an initialized meta - "
- "how it is possible today?" << std::endl; );
- if (output_meta != out_metas.at(output_port))
- {
- util::throw_error(std::logic_error("Fatal: meta mismatch"));
- // FIXME: New exception type?
- // FIXME: More details!
- }
- }
+
+ cv::util::suppress_unused_warning(meta_is_initialized);
+ // FIXME: calling compile() with meta the second time when cannot reshape will lead to error below
+ //if (!meta_is_initialized && !util::holds_alternative<util::monostate>(output_meta))
+ //{
+ // GAPI_LOG_INFO(NULL,
+ // "!!! Output object has an initialized meta - "
+ // "how it is possible today?" << std::endl; );
+ // if (output_meta != out_metas.at(output_port))
+ // {
+ // util::throw_error(std::logic_error("Fatal: meta mismatch"));
+ // // FIXME: New exception type?
+ // // FIXME: More details!
+ // }
+ //}
// Store meta in graph
output_meta = out_metas.at(output_port);
}
// 2. build substitute graph inside the main graph
cv::gimpl::GModelBuilder builder(main);
- const auto& proto_slots = builder.put(substitute.priv().m_ins, substitute.priv().m_outs);
+ auto expr = cv::util::get<cv::GComputation::Priv::Expr>(substitute.priv().m_shape);
+ const auto& proto_slots = builder.put(expr.m_ins, expr.m_outs);
Protocol substituteP;
std::tie(substituteP.inputs, substituteP.outputs, substituteP.in_nhs, substituteP.out_nhs) =
proto_slots;
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#include "precomp.hpp"
case GShape::GMAT:
{
const auto desc = util::get<cv::GMatDesc>(d.meta);
- auto& mat = m_res.slot<cv::gapi::own::Mat>()[d.rc];
+ auto& mat = m_res.slot<cv::Mat>()[d.rc];
createMat(desc, mat);
}
break;
break;
case GShape::GARRAY:
+ if (d.storage == Data::Storage::CONST_VAL)
+ {
+ auto rc = RcDesc{d.rc, d.shape, d.ctor};
+ magazine::bindInArg(m_res, rc, m_gm.metadata(orig_nh).get<ConstValue>().arg);
+ }
+ break;
+ case GShape::GOPAQUE:
// Constructed on Reset, do nothing here
break;
}
}
+class cv::gimpl::GExecutor::Input final: public cv::gimpl::GIslandExecutable::IInput
+{
+ cv::gimpl::Mag &mag;
+ virtual StreamMsg get() override
+ {
+ cv::GRunArgs res;
+ for (const auto &rc : desc()) { res.emplace_back(magazine::getArg(mag, rc)); }
+ return StreamMsg{std::move(res)};
+ }
+ virtual StreamMsg try_get() override { return get(); }
+public:
+ Input(cv::gimpl::Mag &m, const std::vector<RcDesc> &rcs) : mag(m) { set(rcs); }
+};
+
+class cv::gimpl::GExecutor::Output final: public cv::gimpl::GIslandExecutable::IOutput
+{
+ cv::gimpl::Mag &mag;
+ virtual GRunArgP get(int idx) override { return magazine::getObjPtr(mag, desc()[idx]); }
+ virtual void post(GRunArgP&&) override { } // Do nothing here
+ virtual void post(EndOfStream&&) override {} // Do nothing here too
+public:
+ Output(cv::gimpl::Mag &m, const std::vector<RcDesc> &rcs) : mag(m) { set(rcs); }
+};
+
void cv::gimpl::GExecutor::run(cv::gimpl::GRuntimeArgs &&args)
{
// (2)
namespace util = ade::util;
- //ensure that output Mat parameters are correctly allocated
- for (auto index : util::iota(proto.out_nhs.size()) ) //FIXME: avoid copy of NodeHandle and GRunRsltComp ?
+ // ensure that output Mat parameters are correctly allocated
+ // FIXME: avoid copy of NodeHandle and GRunRsltComp ?
+ for (auto index : util::iota(proto.out_nhs.size()))
{
auto& nh = proto.out_nhs.at(index);
const Data &d = m_gm.metadata(nh).get<Data>();
auto check_own_mat = [&desc, &args, &index]()
{
- auto& out_mat = *get<cv::gapi::own::Mat*>(args.outObjs.at(index));
+ auto& out_mat = *get<cv::Mat*>(args.outObjs.at(index));
GAPI_Assert(out_mat.data != nullptr &&
desc.canDescribe(out_mat));
};
#if !defined(GAPI_STANDALONE)
- // Building as part of OpenCV - follow OpenCV behavior
- // In the case of cv::Mat if output buffer is not enough to hold the result, reallocate it
+ // Building as part of OpenCV - follow OpenCV behavior In
+ // the case of cv::Mat if output buffer is not enough to
+ // hold the result, reallocate it
if (cv::util::holds_alternative<cv::Mat*>(args.outObjs.at(index)))
{
auto& out_mat = *get<cv::Mat*>(args.outObjs.at(index));
for (auto &op : m_ops)
{
// (5)
- using InObj = GIslandExecutable::InObj;
- using OutObj = GIslandExecutable::OutObj;
- std::vector<InObj> in_objs;
- std::vector<OutObj> out_objs;
- in_objs.reserve (op.in_objects.size());
- out_objs.reserve(op.out_objects.size());
-
- for (const auto &rc : op.in_objects)
- {
- in_objs.emplace_back(InObj{rc, magazine::getArg(m_res, rc)});
- }
- for (const auto &rc : op.out_objects)
- {
- out_objs.emplace_back(OutObj{rc, magazine::getObjPtr(m_res, rc)});
- }
-
- // (6)
- op.isl_exec->run(std::move(in_objs), std::move(out_objs));
+ Input i{m_res, op.in_objects};
+ Output o{m_res, op.out_objects};
+ op.isl_exec->run(i, o);
}
// (7)
passes::inferMeta(ctx, true);
m_ops[0].isl_exec->reshape(g, args);
}
+
+void cv::gimpl::GExecutor::prepareForNewStream()
+{
+ for (auto &op : m_ops)
+ {
+ op.isl_exec->handleNewStream();
+ }
+}
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_GEXECUTOR_HPP
};
std::vector<DataDesc> m_slots;
+ class Input;
+ class Output;
+
Mag m_res;
void initResource(const ade::NodeHandle &orig_nh); // FIXME: shouldn't it be RcDesc?
bool canReshape() const;
void reshape(const GMetaArgs& inMetas, const GCompileArgs& args);
+ void prepareForNewStream();
+
const GModel::Graph& model() const; // FIXME: make it ConstGraph?
};
// 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
+// Copyright (C) 2019-2020 Intel Corporation
#include "precomp.hpp"
#include <opencv2/gapi/opencv_includes.hpp>
-#include "executor/gstreamingexecutor.hpp"
+#include "api/gproto_priv.hpp" // ptr(GRunArgP)
#include "compiler/passes/passes.hpp"
#include "backends/common/gbackend.hpp" // createMat
#include "compiler/gcompiler.hpp" // for compileIslands
+#include "executor/gstreamingexecutor.hpp"
+
namespace
{
using namespace cv::gimpl::stream;
void sync_data(cv::GRunArgs &results, cv::GRunArgsP &outputs)
{
- namespace own = cv::gapi::own;
-
for (auto && it : ade::util::zip(ade::util::toRange(outputs),
ade::util::toRange(results)))
{
using T = cv::GRunArgP;
switch (out_obj.index())
{
-#if !defined(GAPI_STANDALONE)
case T::index_of<cv::Mat*>():
*cv::util::get<cv::Mat*>(out_obj) = std::move(cv::util::get<cv::Mat>(res_obj));
break;
-#endif // !GAPI_STANDALONE
- case T::index_of<own::Mat*>():
- *cv::util::get<own::Mat*>(out_obj) = std::move(cv::util::get<own::Mat>(res_obj));
- break;
case T::index_of<cv::Scalar*>():
*cv::util::get<cv::Scalar*>(out_obj) = std::move(cv::util::get<cv::Scalar>(res_obj));
break;
case T::index_of<cv::detail::VectorRef>():
cv::util::get<cv::detail::VectorRef>(out_obj).mov(cv::util::get<cv::detail::VectorRef>(res_obj));
break;
+ case T::index_of<cv::detail::OpaqueRef>():
+ cv::util::get<cv::detail::OpaqueRef>(out_obj).mov(cv::util::get<cv::detail::OpaqueRef>(res_obj));
+ break;
default:
GAPI_Assert(false && "This value type is not supported!"); // ...maybe because of STANDALONE mode.
break;
}
}
+class StreamingInput final: public cv::gimpl::GIslandExecutable::IInput
+{
+ QueueReader &qr;
+ std::vector<Q*> &in_queues; // FIXME: This can be part of QueueReader
+ cv::GRunArgs &in_constants; // FIXME: This can be part of QueueReader
+
+ virtual cv::gimpl::StreamMsg get() override
+ {
+ cv::GRunArgs isl_input_args;
+ if (!qr.getInputVector(in_queues, in_constants, isl_input_args))
+ {
+ // Stop case
+ return cv::gimpl::StreamMsg{cv::gimpl::EndOfStream{}};
+ }
+ return cv::gimpl::StreamMsg{std::move(isl_input_args)};
+ }
+ virtual cv::gimpl::StreamMsg try_get() override
+ {
+ // FIXME: This is not very usable at the moment!
+ return get();
+ }
+ public:
+ explicit StreamingInput(QueueReader &rdr,
+ std::vector<Q*> &inq,
+ cv::GRunArgs &inc,
+ const std::vector<cv::gimpl::RcDesc> &in_descs)
+ : qr(rdr), in_queues(inq), in_constants(inc)
+ {
+ set(in_descs);
+ }
+};
+
+class StreamingOutput final: public cv::gimpl::GIslandExecutable::IOutput
+{
+ // These objects form an internal state of the StreamingOutput
+ struct Posting
+ {
+ using V = cv::util::variant<cv::GRunArg, cv::gimpl::EndOfStream>;
+ V data;
+ bool ready = false;
+ };
+ using PostingList = std::list<Posting>;
+ std::vector<PostingList> m_postings;
+ std::unordered_map< const void*
+ , std::pair<int, PostingList::iterator>
+ > m_postIdx;
+ std::size_t m_stops_sent = 0u;
+
+ // These objects are owned externally
+ const cv::GMetaArgs &m_metas;
+ std::vector< std::vector<Q*> > &m_out_queues;
+
+ // Allocate a new data object for output under idx
+ // Prepare this object for posting
+ virtual cv::GRunArgP get(int idx) override
+ {
+ using MatType = cv::Mat;
+ using SclType = cv::Scalar;
+
+ // Allocate a new posting first, then bind this GRunArgP to this item
+ auto iter = m_postings[idx].insert(m_postings[idx].end(), Posting{});
+ const auto r = desc()[idx];
+ cv::GRunArg& out_arg = cv::util::get<cv::GRunArg>(iter->data);
+ cv::GRunArgP ret_val;
+ switch (r.shape) {
+ // Allocate a data object based on its shape & meta, and put it into our vectors.
+ // Yes, first we put a cv::Mat GRunArg, and then specify _THAT_
+ // pointer as an output parameter - to make sure that after island completes,
+ // our GRunArg still has the right (up-to-date) value.
+ // Same applies to other types.
+ // FIXME: This is absolutely ugly but seem to work perfectly for its purpose.
+ case cv::GShape::GMAT:
+ {
+ MatType newMat;
+ cv::gimpl::createMat(cv::util::get<cv::GMatDesc>(m_metas[idx]), newMat);
+ out_arg = cv::GRunArg(std::move(newMat));
+ ret_val = cv::GRunArgP(&cv::util::get<MatType>(out_arg));
+ }
+ break;
+ case cv::GShape::GSCALAR:
+ {
+ SclType newScl;
+ out_arg = cv::GRunArg(std::move(newScl));
+ ret_val = cv::GRunArgP(&cv::util::get<SclType>(out_arg));
+ }
+ break;
+ case cv::GShape::GARRAY:
+ {
+ cv::detail::VectorRef newVec;
+ cv::util::get<cv::detail::ConstructVec>(r.ctor)(newVec);
+ out_arg = cv::GRunArg(std::move(newVec));
+ // VectorRef is implicitly shared so no pointer is taken here
+ // FIXME: that variant MOVE problem again
+ const auto &rr = cv::util::get<cv::detail::VectorRef>(out_arg);
+ ret_val = cv::GRunArgP(rr);
+ }
+ break;
+ case cv::GShape::GOPAQUE:
+ {
+ cv::detail::OpaqueRef newOpaque;
+ cv::util::get<cv::detail::ConstructOpaque>(r.ctor)(newOpaque);
+ out_arg = cv::GRunArg(std::move(newOpaque));
+ // OpaqueRef is implicitly shared so no pointer is taken here
+ // FIXME: that variant MOVE problem again
+ const auto &rr = cv::util::get<cv::detail::OpaqueRef>(out_arg);
+ ret_val = cv::GRunArgP(rr);
+ }
+ break;
+ default:
+ cv::util::throw_error(std::logic_error("Unsupported GShape"));
+ }
+ m_postIdx[cv::gimpl::proto::ptr(ret_val)] = std::make_pair(idx, iter);
+ return ret_val;
+ }
+ virtual void post(cv::GRunArgP&& argp) override
+ {
+ // Mark the output ready for posting. If it is the first in the line,
+ // actually post it and all its successors which are ready for posting too.
+ auto it = m_postIdx.find(cv::gimpl::proto::ptr(argp));
+ GAPI_Assert(it != m_postIdx.end());
+ const int out_idx = it->second.first;
+ const auto out_iter = it->second.second;
+ out_iter->ready = true;
+ m_postIdx.erase(it); // Drop the link from the cache anyway
+ if (out_iter != m_postings[out_idx].begin())
+ {
+ return; // There are some pending postings in the beginning, return
+ }
+
+ GAPI_Assert(out_iter == m_postings[out_idx].begin());
+ auto post_iter = m_postings[out_idx].begin();
+ while (post_iter != m_postings[out_idx].end() && post_iter->ready == true)
+ {
+ Cmd cmd;
+ if (cv::util::holds_alternative<cv::GRunArg>(post_iter->data))
+ {
+ // FIXME: That ugly VARIANT problem
+ cmd = Cmd{const_cast<const cv::GRunArg&>(cv::util::get<cv::GRunArg>(post_iter->data))};
+ }
+ else
+ {
+ GAPI_Assert(cv::util::holds_alternative<cv::gimpl::EndOfStream>(post_iter->data));
+ cmd = Cmd{Stop{}};
+ m_stops_sent++;
+ }
+ for (auto &&q : m_out_queues[out_idx])
+ {
+ // FIXME: This ugly VARIANT problem
+ q->push(const_cast<const Cmd&>(cmd));
+ }
+ post_iter = m_postings[out_idx].erase(post_iter);
+ }
+ }
+ virtual void post(cv::gimpl::EndOfStream&&) override
+ {
+ // If the posting list is empty, just broadcast the stop message.
+ // If it is not, enqueue the Stop message in the postings list.
+ for (auto &&it : ade::util::indexed(m_postings))
+ {
+ const auto idx = ade::util::index(it);
+ auto &lst = ade::util::value(it);
+ if (lst.empty())
+ {
+ for (auto &&q : m_out_queues[idx])
+ {
+ q->push(Cmd(Stop{}));
+ }
+ m_stops_sent++;
+ }
+ else
+ {
+ Posting p;
+ p.data = Posting::V{cv::gimpl::EndOfStream{}};
+ p.ready = true;
+ lst.push_back(std::move(p)); // FIXME: For some reason {}-ctor didn't work here
+ }
+ }
+ }
+public:
+ explicit StreamingOutput(const cv::GMetaArgs &metas,
+ std::vector< std::vector<Q*> > &out_queues,
+ const std::vector<cv::gimpl::RcDesc> &out_descs)
+ : m_metas(metas)
+ , m_out_queues(out_queues)
+ {
+ set(out_descs);
+ m_postings.resize(out_descs.size());
+ }
+
+ bool done() const
+ {
+ // The streaming actor work is considered DONE for this stream
+ // when it posted/resent all STOP messages to all its outputs.
+ return m_stops_sent == desc().size();
+ }
+};
+
// This thread is a plain dumb processing actor. What it do is just:
// - Reads input from the input queue(s), sleeps if there's nothing to read
// - Once a full input vector is obtained, passes it to the underlying island
GAPI_Assert(out_queues.size() == out_rcs.size());
GAPI_Assert(out_queues.size() == out_metas.size());
QueueReader qr;
- while (true)
+ StreamingInput input(qr, in_queues, in_constants, in_rcs);
+ StreamingOutput output(out_metas, out_queues, out_rcs);
+ while (!output.done())
{
- std::vector<cv::gimpl::GIslandExecutable::InObj> isl_inputs;
- isl_inputs.resize(in_rcs.size());
-
- cv::GRunArgs isl_input_args;
- if (!qr.getInputVector(in_queues, in_constants, isl_input_args))
- {
- // Stop received -- broadcast Stop down to the pipeline and quit
- for (auto &&out_qq : out_queues)
- {
- for (auto &&out_q : out_qq) out_q->push(Cmd{Stop{}});
- }
- return;
- }
- GAPI_Assert(isl_inputs.size() == isl_input_args.size());
- for (auto &&it : ade::util::indexed(ade::util::zip(ade::util::toRange(in_rcs),
- ade::util::toRange(isl_inputs),
- ade::util::toRange(isl_input_args))))
- {
- const auto &value = ade::util::value(it);
- const auto &in_rc = std::get<0>(value);
- auto &isl_input = std::get<1>(value);
- const auto &in_arg = std::get<2>(value); // FIXME: MOVE PROBLEM
- isl_input.first = in_rc;
-#if defined(GAPI_STANDALONE)
- // Standalone mode - simply store input argument in the vector as-is
- auto id = ade::util::index(it);
- isl_inputs[id].second = in_arg;
-#else
- // Make Islands operate on own:: data types (i.e. in the same
- // environment as GExecutor provides)
- // This way several backends (e.g. Fluid) remain OpenCV-independent.
- switch (in_arg.index()) {
- case cv::GRunArg::index_of<cv::Mat>():
- isl_input.second = cv::GRunArg{cv::to_own(cv::util::get<cv::Mat>(in_arg))};
- break;
- case cv::GRunArg::index_of<cv::Scalar>():
- isl_input.second = cv::GRunArg{cv::util::get<cv::Scalar>(in_arg)};
- break;
- default:
- isl_input.second = in_arg;
- break;
- }
-#endif // GAPI_STANDALONE
- }
- // Once the vector is obtained, prepare data for island execution
- // Note - we first allocate output vector via GRunArg!
- // Then it is converted to a GRunArgP.
- std::vector<cv::gimpl::GIslandExecutable::OutObj> isl_outputs;
- cv::GRunArgs out_data;
- isl_outputs.resize(out_rcs.size());
- out_data.resize(out_rcs.size());
- for (auto &&it : ade::util::indexed(out_rcs))
- {
- auto id = ade::util::index(it);
- auto &r = ade::util::value(it);
-
-#if !defined(GAPI_STANDALONE)
- using MatType = cv::Mat;
- using SclType = cv::Scalar;
-#else
- using MatType = cv::gapi::own::Mat;
- using SclType = cv::Scalar;
-#endif // GAPI_STANDALONE
-
- switch (r.shape) {
- // Allocate a data object based on its shape & meta, and put it into our vectors.
- // Yes, first we put a cv::Mat GRunArg, and then specify _THAT_
- // pointer as an output parameter - to make sure that after island completes,
- // our GRunArg still has the right (up-to-date) value.
- // Same applies to other types.
- // FIXME: This is absolutely ugly but seem to work perfectly for its purpose.
- case cv::GShape::GMAT:
- {
- MatType newMat;
- cv::gimpl::createMat(cv::util::get<cv::GMatDesc>(out_metas[id]), newMat);
- out_data[id] = cv::GRunArg(std::move(newMat));
- isl_outputs[id] = { r, cv::GRunArgP(&cv::util::get<MatType>(out_data[id])) };
- }
- break;
- case cv::GShape::GSCALAR:
- {
- SclType newScl;
- out_data[id] = cv::GRunArg(std::move(newScl));
- isl_outputs[id] = { r, cv::GRunArgP(&cv::util::get<SclType>(out_data[id])) };
- }
- break;
- case cv::GShape::GARRAY:
- {
- cv::detail::VectorRef newVec;
- cv::util::get<cv::detail::ConstructVec>(r.ctor)(newVec);
- out_data[id] = cv::GRunArg(std::move(newVec));
- // VectorRef is implicitly shared so no pointer is taken here
- const auto &rr = cv::util::get<cv::detail::VectorRef>(out_data[id]); // FIXME: that variant MOVE problem again
- isl_outputs[id] = { r, cv::GRunArgP(rr) };
- }
- break;
- default:
- cv::util::throw_error(std::logic_error("Unsupported GShape"));
- break;
- }
- }
- // Now ask Island to execute on this data
- island->run(std::move(isl_inputs), std::move(isl_outputs));
-
- // Once executed, dispatch our results down to the pipeline.
- for (auto &&it : ade::util::zip(ade::util::toRange(out_queues),
- ade::util::toRange(out_data)))
- {
- for (auto &&q : std::get<0>(it))
- {
- // FIXME: FATAL VARIANT ISSUE!!
- const auto tmp = std::get<1>(it);
- q->push(Cmd{tmp});
- }
- }
+ island->run(input, output);
}
}
}
} // anonymous namespace
-cv::gimpl::GStreamingExecutor::GStreamingExecutor(std::unique_ptr<ade::Graph> &&g_model)
+// GStreamingExecutor expects compile arguments as input to have possibility to do
+// proper graph reshape and islands recompilation
+cv::gimpl::GStreamingExecutor::GStreamingExecutor(std::unique_ptr<ade::Graph> &&g_model,
+ const GCompileArgs &comp_args)
: m_orig_graph(std::move(g_model))
, m_island_graph(GModel::Graph(*m_orig_graph).metadata()
.get<IslandModel>().model)
+ , m_comp_args(comp_args)
, m_gim(*m_island_graph)
{
GModel::Graph gm(*m_orig_graph);
}
}
};
+ bool islandsRecompiled = false;
const auto new_meta = cv::descr_of(ins); // 0
if (gm.metadata().contains<OriginalInputMeta>()) // (1)
{
}
update_int_metas(); // (7)
m_reshapable = util::make_optional(is_reshapable);
+
+ islandsRecompiled = true;
}
else // (8)
{
out_queues.push_back(reader_queues(*m_island_graph, out_eh));
}
+ // If Island Executable is recompiled, all its stuff including internal kernel states
+ // are recreated and re-initialized automatically.
+ // But if not, we should notify Island Executable about new started stream to let it update
+ // its internal variables.
+ if (!islandsRecompiled)
+ {
+ op.isl_exec->handleNewStream();
+ }
+
m_threads.emplace_back(islandActorThread,
op.in_objects,
op.out_objects,
// 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
+// Copyright (C) 2019-2020 Intel Corporation
#ifndef OPENCV_GAPI_GSTREAMING_EXECUTOR_HPP
#define OPENCV_GAPI_GSTREAMING_EXECUTOR_HPP
void wait_shutdown();
public:
- explicit GStreamingExecutor(std::unique_ptr<ade::Graph> &&g_model);
+ explicit GStreamingExecutor(std::unique_ptr<ade::Graph> &&g_model,
+ const cv::GCompileArgs &comp_args);
~GStreamingExecutor();
void setSource(GRunArgs &&args);
void start();
# include "opencv2/core/utils/logger.hpp"
# define GAPI_LOG_INFO(tag, ...) CV_LOG_INFO(tag, __VA_ARGS__)
# define GAPI_LOG_WARNING(tag, ...) CV_LOG_WARNING(tag, __VA_ARGS__)
+# define GAPI_LOG_DEBUG(tag, ...) CV_LOG_DEBUG(tag, __VA_ARGS__)
#else
# define GAPI_LOG_INFO(tag, ...)
# define GAPI_LOG_WARNING(tag, ...)
+# define GAPI_LOG_DEBUG(tag, ...)
#endif // !defined(GAPI_STANDALONE)
}
};
+ G_TYPED_KERNEL(GToInterleaved, <GMat(GMatP)>, "org.opencv.test.to_interleaved")
+ {
+ static GMatDesc outMeta(GMatDesc in)
+ {
+ GAPI_Assert(in.planar == true);
+ GAPI_Assert(in.chan == 3);
+ return in.asInterleaved();
+ }
+ };
+
+ G_TYPED_KERNEL(GToPlanar, <GMatP(GMat)>, "org.opencv.test.to_planar")
+ {
+ static GMatDesc outMeta(GMatDesc in)
+ {
+ GAPI_Assert(in.planar == false);
+ GAPI_Assert(in.chan == 3);
+ return in.asPlanar();
+ }
+ };
+
+ GAPI_OCV_KERNEL(GToInterleavedImpl, GToInterleaved)
+ {
+ static void run(const cv::Mat& in, cv::Mat& out)
+ {
+ constexpr int inPlanesCount = 3;
+ int inPlaneHeight = in.rows / inPlanesCount;
+
+ std::vector<cv::Mat> inPlanes(inPlanesCount);
+ for (int i = 0; i < inPlanesCount; ++i)
+ {
+ int startRow = i * inPlaneHeight;
+ int endRow = startRow + inPlaneHeight;
+ inPlanes[i] = in.rowRange(startRow, endRow);
+ }
+
+ cv::merge(inPlanes, out);
+ }
+ };
+
+ GAPI_OCV_KERNEL(GToPlanarImpl, GToPlanar)
+ {
+ static void run(const cv::Mat& in, cv::Mat& out)
+ {
+ std::vector<cv::Mat> inPlanes;
+ cv::split(in, inPlanes);
+ cv::vconcat(inPlanes, out);
+ }
+ };
+
+ G_TYPED_KERNEL(GCompoundToInterleavedToPlanar, <GMatP(GMatP)>,
+ "org.opencv.test.compound_to_interleaved_to_planar")
+ {
+ static GMatDesc outMeta(GMatDesc in)
+ {
+ GAPI_Assert(in.planar == true);
+ GAPI_Assert(in.chan == 3);
+ return in;
+ }
+ };
+
+ GAPI_COMPOUND_KERNEL(GCompoundToInterleavedToPlanarImpl, GCompoundToInterleavedToPlanar)
+ {
+ static GMatP expand(cv::GMatP in)
+ {
+ return GToPlanar::on(GToInterleaved::on(in));
+ }
+ };
} // namespace
// FIXME avoid cv::combine that use custom and default kernels together
EXPECT_EQ(0, cvtest::norm(out_mat, ref_mat, NORM_INF));
}
+
+TEST(GCompoundKernel, ToInterleavedToPlanar)
+{
+ cv::GMatP in;
+ cv::GMatP out = GCompoundToInterleavedToPlanar::on(in);
+ const auto pkg = cv::gapi::kernels<GCompoundToInterleavedToPlanarImpl,
+ GToInterleavedImpl,
+ GToPlanarImpl>();
+
+ cv::GComputation comp(cv::GIn(in), cv::GOut(out));
+
+ constexpr int numPlanes = 3;
+ cv::Mat in_mat(cv::Size(15, 15), CV_8UC1),
+ out_mat,
+ ref_mat;
+
+ cv::randu(in_mat, 0, 255);
+ ref_mat = in_mat;
+
+ comp.compile(cv::descr_of(in_mat).asPlanar(numPlanes), cv::compile_args(pkg))
+ (cv::gin(in_mat), cv::gout(out_mat));
+
+ EXPECT_EQ(0, cvtest::norm(out_mat, ref_mat, NORM_INF));
+
+}
} // opencv_test
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018-2019 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_CORE_TESTS_HPP
#include <iostream>
#include "gapi_tests_common.hpp"
+#include "gapi_parsers_tests_common.hpp"
namespace opencv_test
{
GAPI_TEST_FIXTURE(MaskTest, initMatrixRandU, <>, 0)
GAPI_TEST_FIXTURE(Polar2CartTest, initMatsRandU, <>, 0)
GAPI_TEST_FIXTURE(Cart2PolarTest, initMatsRandU, <>, 0)
-GAPI_TEST_FIXTURE(CmpTest, initMatsRandU, FIXTURE_API(CmpTypes,bool), 2, opType, testWithScalar)
-GAPI_TEST_FIXTURE(BitwiseTest, initMatsRandU, FIXTURE_API(bitwiseOp), 1, opType)
+GAPI_TEST_FIXTURE(CmpTest, initMatsRandU, FIXTURE_API(CmpTypes,bool,CompareMats), 3, opType, testWithScalar, cmpF)
+GAPI_TEST_FIXTURE(BitwiseTest, initMatsRandU, FIXTURE_API(bitwiseOp,bool), 2, opType, testWithScalar)
GAPI_TEST_FIXTURE(NotTest, initMatrixRandU, <>, 0)
GAPI_TEST_FIXTURE(SelectTest, initMatsRandU, <>, 0)
GAPI_TEST_FIXTURE(MinTest, initMatsRandU, <>, 0)
GAPI_TEST_FIXTURE(SqrtTest, initMatrixRandU, <>, 0)
GAPI_TEST_FIXTURE(NormalizeTest, initNothing, FIXTURE_API(CompareMats,double,double,int,MatType2), 5,
cmpF, a, b, norm_type, ddepth)
-struct BackendOutputAllocationTest : TestWithParamBase<>
+struct BackendOutputAllocationTest : TestWithParams<>
{
BackendOutputAllocationTest()
{
GAPI_TEST_FIXTURE(WarpAffineTest, initMatrixRandU,
FIXTURE_API(CompareMats, double , double, int, int, cv::Scalar),
6, cmpF, angle, scale, flags, border_mode, border_value)
+
+GAPI_TEST_EXT_BASE_FIXTURE(ParseSSDBLTest, ParserSSDTest, initNothing,
+ FIXTURE_API(float, int), 2, confidence_threshold, filter_label)
+GAPI_TEST_EXT_BASE_FIXTURE(ParseSSDTest, ParserSSDTest, initNothing,
+ FIXTURE_API(float, bool, bool), 3, confidence_threshold, alignment_to_square, filter_out_of_bounds)
+GAPI_TEST_EXT_BASE_FIXTURE(ParseYoloTest, ParserYoloTest, initNothing,
+ FIXTURE_API(float, float, int), 3, confidence_threshold, nms_threshold, num_classes)
+GAPI_TEST_FIXTURE(SizeTest, initMatrixRandU, <>, 0)
+GAPI_TEST_FIXTURE(SizeRTest, initNothing, <>, 0)
} // opencv_test
#endif //OPENCV_GAPI_CORE_TESTS_HPP
#define OPENCV_GAPI_CORE_TESTS_INL_HPP
#include <opencv2/gapi/core.hpp>
+#include <opencv2/gapi/infer/parsers.hpp>
#include "gapi_core_tests.hpp"
namespace opencv_test
{
if( doReverseOp )
{
- in_mat1.setTo(1, in_mat1 == 0); // avoid zeros in divide input data
+ in_mat1.setTo(1, in_mat1 == 0); // avoiding zeros in divide input data
out = cv::gapi::divRC(sc1, in1, scale, dtype);
cv::divide(sc, in_mat1, out_mat_ocv, scale, dtype);
break;
}
else
{
- sc += Scalar(1, 1, 1, 1); // avoid zeros in divide input data
+ sc += Scalar(sc[0] == 0, sc[1] == 0, sc[2] == 0, sc[3] == 0); // avoiding zeros in divide input data
out = cv::gapi::divC(in1, sc1, scale, dtype);
cv::divide(in_mat1, sc, out_mat_ocv, scale, dtype);
break;
}
case (DIV):
{
- in_mat2.setTo(1, in_mat2 == 0); // avoid zeros in divide input data
+ in_mat2.setTo(1, in_mat2 == 0); // avoiding zeros in divide input data
out = cv::gapi::div(in1, in2, scale, dtype);
cv::divide(in_mat1, in_mat2, out_mat_ocv, scale, dtype);
break;
// Comparison //////////////////////////////////////////////////////////////
{
ASSERT_EQ(out_mat_gapi.size(), sz);
- EXPECT_EQ(0, cvtest::norm(out_mat_gapi, out_mat_ocv, NORM_INF));
+ EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
}
}
{
// G-API code & corresponding OpenCV code ////////////////////////////////
cv::GMat in1, in2, out;
- switch(opType)
+ if( testWithScalar )
{
- case AND:
- {
- out = cv::gapi::bitwise_and(in1, in2);
- cv::bitwise_and(in_mat1, in_mat2, out_mat_ocv);
- break;
- }
- case OR:
- {
- out = cv::gapi::bitwise_or(in1, in2);
- cv::bitwise_or(in_mat1, in_mat2, out_mat_ocv);
- break;
- }
- case XOR:
+ cv::GScalar sc1;
+ switch(opType)
{
- out = cv::gapi::bitwise_xor(in1, in2);
- cv::bitwise_xor(in_mat1, in_mat2, out_mat_ocv);
- break;
+ case AND:
+ out = cv::gapi::bitwise_and(in1, sc1);
+ cv::bitwise_and(in_mat1, sc, out_mat_ocv);
+ break;
+ case OR:
+ out = cv::gapi::bitwise_or(in1, sc1);
+ cv::bitwise_or(in_mat1, sc, out_mat_ocv);
+ break;
+ case XOR:
+ out = cv::gapi::bitwise_xor(in1, sc1);
+ cv::bitwise_xor(in_mat1, sc, out_mat_ocv);
+ break;
+ default:
+ FAIL() << "no such bitwise operation type!";
}
- default:
+ cv::GComputation c(GIn(in1, sc1), GOut(out));
+ c.apply(gin(in_mat1, sc), gout(out_mat_gapi), getCompileArgs());
+ }
+ else
+ {
+ switch(opType)
{
- FAIL() << "no such bitwise operation type!";
+ case AND:
+ out = cv::gapi::bitwise_and(in1, in2);
+ cv::bitwise_and(in_mat1, in_mat2, out_mat_ocv);
+ break;
+ case OR:
+ out = cv::gapi::bitwise_or(in1, in2);
+ cv::bitwise_or(in_mat1, in_mat2, out_mat_ocv);
+ break;
+ case XOR:
+ out = cv::gapi::bitwise_xor(in1, in2);
+ cv::bitwise_xor(in_mat1, in_mat2, out_mat_ocv);
+ break;
+ default:
+ FAIL() << "no such bitwise operation type!";
}
+ cv::GComputation c(GIn(in1, in2), GOut(out));
+ c.apply(gin(in_mat1, in_mat2), gout(out_mat_gapi), getCompileArgs());
}
- cv::GComputation c(GIn(in1, in2), GOut(out));
- c.apply(gin(in_mat1, in_mat2), gout(out_mat_gapi), getCompileArgs());
+
// Comparison //////////////////////////////////////////////////////////////
{
run_and_compare();
}
+TEST_P(ParseSSDBLTest, ParseTest)
+{
+ cv::Mat in_mat = generateSSDoutput(sz);
+ std::vector<cv::Rect> boxes_gapi, boxes_ref;
+ std::vector<int> labels_gapi, labels_ref;
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::GMat in;
+ cv::GOpaque<cv::Size> op_sz;
+ auto out = cv::gapi::parseSSD(in, op_sz, confidence_threshold, filter_label);
+ cv::GComputation c(cv::GIn(in, op_sz), cv::GOut(std::get<0>(out), std::get<1>(out)));
+ c.apply(cv::gin(in_mat, sz), cv::gout(boxes_gapi, labels_gapi), getCompileArgs());
+
+ // Reference code //////////////////////////////////////////////////////////
+ parseSSDBLref(in_mat, sz, confidence_threshold, filter_label, boxes_ref, labels_ref);
+
+ // Comparison //////////////////////////////////////////////////////////////
+ EXPECT_TRUE(boxes_gapi == boxes_ref);
+ EXPECT_TRUE(labels_gapi == labels_ref);
+}
+
+TEST_P(ParseSSDTest, ParseTest)
+{
+ cv::Mat in_mat = generateSSDoutput(sz);
+ std::vector<cv::Rect> boxes_gapi, boxes_ref;
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::GMat in;
+ cv::GOpaque<cv::Size> op_sz;
+ auto out = cv::gapi::parseSSD(in, op_sz, confidence_threshold,
+ alignment_to_square, filter_out_of_bounds);
+ cv::GComputation c(cv::GIn(in, op_sz), cv::GOut(out));
+ c.apply(cv::gin(in_mat, sz), cv::gout(boxes_gapi), getCompileArgs());
+
+ // Reference code //////////////////////////////////////////////////////////
+ parseSSDref(in_mat, sz, confidence_threshold, alignment_to_square,
+ filter_out_of_bounds, boxes_ref);
+
+ // Comparison //////////////////////////////////////////////////////////////
+ EXPECT_TRUE(boxes_gapi == boxes_ref);
+}
+
+TEST_P(ParseYoloTest, ParseTest)
+{
+ cv::Mat in_mat = generateYoloOutput(num_classes);
+ auto anchors = cv::gapi::nn::parsers::GParseYolo::defaultAnchors();
+ std::vector<cv::Rect> boxes_gapi, boxes_ref;
+ std::vector<int> labels_gapi, labels_ref;
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::GMat in;
+ cv::GOpaque<cv::Size> op_sz;
+ auto out = cv::gapi::parseYolo(in, op_sz, confidence_threshold, nms_threshold, anchors);
+ cv::GComputation c(cv::GIn(in, op_sz), cv::GOut(std::get<0>(out), std::get<1>(out)));
+ c.apply(cv::gin(in_mat, sz), cv::gout(boxes_gapi, labels_gapi), getCompileArgs());
+
+ // Reference code //////////////////////////////////////////////////////////
+ parseYoloRef(in_mat, sz, confidence_threshold, nms_threshold, num_classes, anchors, boxes_ref, labels_ref);
+
+ // Comparison //////////////////////////////////////////////////////////////
+ EXPECT_TRUE(boxes_gapi == boxes_ref);
+ EXPECT_TRUE(labels_gapi == labels_ref);
+}
+
+TEST_P(SizeTest, ParseTest)
+{
+ cv::GMat in;
+ cv::Size out_sz;
+
+ auto out = cv::gapi::size(in);
+ cv::GComputation c(cv::GIn(in), cv::GOut(out));
+ c.apply(cv::gin(in_mat1), cv::gout(out_sz), getCompileArgs());
+
+ EXPECT_EQ(out_sz, sz);
+}
+
+TEST_P(SizeRTest, ParseTest)
+{
+ cv::Rect rect(cv::Point(0,0), sz);
+ cv::Size out_sz;
+
+ cv::GOpaque<cv::Rect> op_rect;
+ auto out = cv::gapi::size(op_rect);
+ cv::GComputation c(cv::GIn(op_rect), cv::GOut(out));
+ c.apply(cv::gin(rect), cv::gout(out_sz), getCompileArgs());
+
+ EXPECT_EQ(out_sz, sz);
+}
+
} // opencv_test
#endif //OPENCV_GAPI_CORE_TESTS_INL_HPP
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018-2019 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_IMGPROC_TESTS_HPP
namespace opencv_test
{
+
// Create new value-parameterized test fixture:
// Filter2DTest - fixture name
// initMatrixRandN - function that is used to initialize input/output data
cmpF, kernSize, dx, dy)
GAPI_TEST_FIXTURE(SobelXYTest, initMatrixRandN, FIXTURE_API(CompareMats,int,int,int,int), 5,
cmpF, kernSize, order, border_type, border_val)
+GAPI_TEST_FIXTURE(LaplacianTest, initMatrixRandN,
+ FIXTURE_API(CompareMats,int,double,int), 4,
+ cmpF, kernSize, scale, borderType)
+GAPI_TEST_FIXTURE(BilateralFilterTest, initMatrixRandN,
+ FIXTURE_API(CompareMats,int,double,double,int), 5,
+ cmpF, d, sigmaColor, sigmaSpace, borderType)
GAPI_TEST_FIXTURE(EqHistTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(CannyTest, initMatrixRandN, FIXTURE_API(CompareMats,double,double,int,bool), 5,
cmpF, thrLow, thrUp, apSize, l2gr)
+GAPI_TEST_FIXTURE_SPEC_PARAMS(GoodFeaturesTest,
+ FIXTURE_API(CompareVectors<cv::Point2f>,std::string,int,int,double,
+ double,int,bool),
+ 8, cmpF, fileName, type, maxCorners, qualityLevel, minDistance,
+ blockSize, useHarrisDetector)
GAPI_TEST_FIXTURE(RGB2GrayTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(BGR2GrayTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
GAPI_TEST_FIXTURE(RGB2YUVTest, initMatrixRandN, FIXTURE_API(CompareMats), 1, cmpF)
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018-2019 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_IMGPROC_TESTS_INL_HPP
}
}
+TEST_P(LaplacianTest, AccuracyTest)
+{
+ double delta = 10;
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::GMat in;
+ auto out = cv::gapi::Laplacian(in, dtype, kernSize, scale, delta, borderType);
+
+ cv::GComputation c(in, out);
+ c.apply(in_mat1, out_mat_gapi, getCompileArgs());
+ // OpenCV code /////////////////////////////////////////////////////////////
+ {
+ cv::Laplacian(in_mat1, out_mat_ocv, dtype, kernSize, scale, delta, borderType);
+ }
+ // Comparison //////////////////////////////////////////////////////////////
+ {
+ EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
+ EXPECT_EQ(out_mat_gapi.size(), sz);
+ }
+}
+
+TEST_P(BilateralFilterTest, AccuracyTest)
+{
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::GMat in;
+ auto out = cv::gapi::bilateralFilter(in, d, sigmaColor, sigmaSpace, borderType);
+
+ cv::GComputation c(in, out);
+ c.apply(in_mat1, out_mat_gapi, getCompileArgs());
+ // OpenCV code /////////////////////////////////////////////////////////////
+ {
+ cv::bilateralFilter(in_mat1, out_mat_ocv, d, sigmaColor, sigmaSpace, borderType);
+ }
+ // Comparison //////////////////////////////////////////////////////////////
+ {
+ EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
+ EXPECT_EQ(out_mat_gapi.size(), sz);
+ }
+}
+
TEST_P(EqHistTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
}
}
+TEST_P(GoodFeaturesTest, AccuracyTest)
+{
+ double k = 0.04;
+
+ initMatFromImage(type, fileName);
+
+ std::vector<cv::Point2f> outVecOCV, outVecGAPI;
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::GMat in;
+ auto out = cv::gapi::goodFeaturesToTrack(in, maxCorners, qualityLevel, minDistance, cv::Mat(),
+ blockSize, useHarrisDetector, k);
+
+ cv::GComputation c(cv::GIn(in), cv::GOut(out));
+ c.apply(cv::gin(in_mat1), cv::gout(outVecGAPI), getCompileArgs());
+
+ // OpenCV code /////////////////////////////////////////////////////////////
+ {
+ cv::goodFeaturesToTrack(in_mat1, outVecOCV, maxCorners, qualityLevel, minDistance,
+ cv::noArray(), blockSize, useHarrisDetector, k);
+ }
+
+ // Comparison //////////////////////////////////////////////////////////////
+ {
+ EXPECT_TRUE(cmpF(outVecGAPI, outVecOCV));
+ }
+}
+
TEST_P(RGB2GrayTest, AccuracyTest)
{
// G-API code //////////////////////////////////////////////////////////////
EXPECT_EQ(out_mat_gapi.size(), sz);
}
}
-
} // opencv_test
#endif //OPENCV_GAPI_IMGPROC_TESTS_INL_HPP
namespace opencv_test
{
+enum operation
+{
+ ADD, SUB, MUL, DIV,
+ ADDR, SUBR, MULR, DIVR,
+ GT, LT, GE, LE, EQ, NE,
+ GTR, LTR, GER, LER, EQR, NER,
+ AND, OR, XOR,
+ ANDR, ORR, XORR
+};
+
+// Note: namespace must match the namespace of the type of the printed object
+inline std::ostream& operator<<(std::ostream& os, operation op)
+{
+#define CASE(v) case operation::v: os << #v; break
+ switch (op)
+ {
+ CASE(ADD); CASE(SUB); CASE(MUL); CASE(DIV);
+ CASE(ADDR); CASE(SUBR); CASE(MULR); CASE(DIVR);
+ CASE(GT); CASE(LT); CASE(GE); CASE(LE); CASE(EQ); CASE(NE);
+ CASE(GTR); CASE(LTR); CASE(GER); CASE(LER); CASE(EQR); CASE(NER);
+ CASE(AND); CASE(OR); CASE(XOR);
+ CASE(ANDR); CASE(ORR); CASE(XORR);
+ default: GAPI_Assert(false && "unknown operation value");
+ }
+#undef CASE
+ return os;
+}
+
+namespace
+{
+// declare test cases for matrix and scalar operators
+auto opADD_gapi = [](cv::GMat in,cv::GScalar c){return in + c;};
+auto opADD_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::add(in, c, out);};
+
+auto opADDR_gapi = [](cv::GMat in,cv::GScalar c){return c + in;};
+auto opADDR_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::add(c, in, out);};
+
+auto opSUB_gapi = [](cv::GMat in,cv::GScalar c){return in - c;};
+auto opSUB_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::subtract(in, c, out);};
+
+auto opSUBR_gapi = [](cv::GMat in,cv::GScalar c){return c - in;};
+auto opSUBR_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::subtract(c, in, out);};
+
+auto opMUL_gapi = [](cv::GMat in,cv::GScalar c){return in * c;};
+auto opMUL_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::multiply(in, c, out);};
+
+auto opMULR_gapi = [](cv::GMat in,cv::GScalar c){return c * in;};
+auto opMULR_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::multiply(c, in, out);};
+
+auto opDIV_gapi = [](cv::GMat in,cv::GScalar c){return in / c;};
+auto opDIV_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::divide(in, c, out);};
+
+auto opDIVR_gapi = [](cv::GMat in,cv::GScalar c){return c / in;};
+auto opDIVR_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::divide(c, in, out);};
+
+
+auto opGT_gapi = [](cv::GMat in,cv::GScalar c){return in > c;};
+auto opGT_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(in, c, out,cv::CMP_GT);};
+
+auto opGTR_gapi = [](cv::GMat in,cv::GScalar c){return c > in;};
+auto opGTR_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(c, in, out,cv::CMP_GT);};
+
+auto opLT_gapi = [](cv::GMat in,cv::GScalar c){return in < c;};
+auto opLT_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(in, c, out,cv::CMP_LT);};
+
+auto opLTR_gapi = [](cv::GMat in,cv::GScalar c){return c < in;};
+auto opLTR_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(c, in, out,cv::CMP_LT);};
+
+auto opGE_gapi = [](cv::GMat in,cv::GScalar c){return in >= c;};
+auto opGE_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(in, c, out,cv::CMP_GE);};
+
+auto opGER_gapi = [](cv::GMat in,cv::GScalar c){return c >= in;};
+auto opGER_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(c, in, out,cv::CMP_GE);};
+
+auto opLE_gapi = [](cv::GMat in,cv::GScalar c){return in <= c;};
+auto opLE_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(in, c, out,cv::CMP_LE);};
+
+auto opLER_gapi = [](cv::GMat in,cv::GScalar c){return c <= in;};
+auto opLER_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(c, in, out,cv::CMP_LE);};
+
+auto opEQ_gapi = [](cv::GMat in,cv::GScalar c){return in == c;};
+auto opEQ_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(in, c, out,cv::CMP_EQ);};
+
+auto opEQR_gapi = [](cv::GMat in,cv::GScalar c){return c == in;};
+auto opEQR_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(c, in, out,cv::CMP_EQ);};
+
+auto opNE_gapi = [](cv::GMat in,cv::GScalar c){return in != c;};
+auto opNE_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(in, c, out,cv::CMP_NE);};
+
+auto opNER_gapi = [](cv::GMat in,cv::GScalar c){return c != in;};
+auto opNER_ocv = [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(c, in, out,cv::CMP_NE);};
+
+
+auto opAND_gapi = [](cv::GMat in,cv::GScalar c){return in & c;};
+auto opAND_ocv = [](const cv::Mat& in, const cv::Scalar& c, cv::Mat& out){cv::bitwise_and(in, c, out);};
+
+auto opOR_gapi = [](cv::GMat in,cv::GScalar c){return in | c;};
+auto opOR_ocv = [](const cv::Mat& in, const cv::Scalar& c, cv::Mat& out){cv::bitwise_or(in, c, out);};
+
+auto opXOR_gapi = [](cv::GMat in,cv::GScalar c){return in ^ c;};
+auto opXOR_ocv = [](const cv::Mat& in, const cv::Scalar& c, cv::Mat& out){cv::bitwise_xor(in, c, out);};
+
+auto opANDR_gapi = [](cv::GMat in,cv::GScalar c){return c & in;};
+auto opANDR_ocv = [](const cv::Mat& in, const cv::Scalar& c, cv::Mat& out){cv::bitwise_and(c, in, out);};
+
+auto opORR_gapi = [](cv::GMat in,cv::GScalar c){return c | in;};
+auto opORR_ocv = [](const cv::Mat& in, const cv::Scalar& c, cv::Mat& out){cv::bitwise_or(c, in, out);};
+
+auto opXORR_gapi = [](cv::GMat in,cv::GScalar c){return c ^ in;};
+auto opXORR_ocv = [](const cv::Mat& in, const cv::Scalar& c, cv::Mat& out){cv::bitwise_xor(c, in, out);};
+
+// declare test cases for matrix and matrix operators
+auto opADDM_gapi = [](cv::GMat in1,cv::GMat in2){return in1 + in2;};
+auto opADDM_ocv = [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::add(in1, in2, out);};
+
+auto opSUBM_gapi = [](cv::GMat in1,cv::GMat in2){return in1 - in2;};
+auto opSUBM_ocv = [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::subtract(in1, in2, out);};
+
+auto opDIVM_gapi = [](cv::GMat in1,cv::GMat in2){return in1 / in2;};
+auto opDIVM_ocv = [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::divide(in1, in2, out);};
+
+
+auto opGTM_gapi = [](cv::GMat in1,cv::GMat in2){return in1 > in2;};
+auto opGTM_ocv = [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::compare(in1, in2, out, cv::CMP_GT);};
+
+auto opGEM_gapi = [](cv::GMat in1,cv::GMat in2){return in1 >= in2;};
+auto opGEM_ocv = [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::compare(in1, in2, out, cv::CMP_GE);};
+
+auto opLTM_gapi = [](cv::GMat in1,cv::GMat in2){return in1 < in2;};
+auto opLTM_ocv = [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::compare(in1, in2, out, cv::CMP_LT);};
+
+auto opLEM_gapi = [](cv::GMat in1,cv::GMat in2){return in1 <= in2;};
+auto opLEM_ocv = [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::compare(in1, in2, out, cv::CMP_LE);};
+
+auto opEQM_gapi = [](cv::GMat in1,cv::GMat in2){return in1 == in2;};
+auto opEQM_ocv = [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::compare(in1, in2, out, cv::CMP_EQ);};
+
+auto opNEM_gapi = [](cv::GMat in1,cv::GMat in2){return in1 != in2;};
+auto opNEM_ocv = [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::compare(in1, in2, out, cv::CMP_NE);};
+
+
+auto opANDM_gapi = [](cv::GMat in1,cv::GMat in2){return in1 & in2;};
+auto opANDM_ocv = [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::bitwise_and(in1, in2, out);};
+
+auto opORM_gapi = [](cv::GMat in1,cv::GMat in2){return in1 | in2;};
+auto opORM_ocv = [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::bitwise_or(in1, in2, out);};
+
+auto opXORM_gapi = [](cv::GMat in1,cv::GMat in2){return in1 ^ in2;};
+auto opXORM_ocv = [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::bitwise_xor(in1, in2, out);};
+} // anonymous namespace
struct g_api_ocv_pair_mat_scalar {
using g_api_function_t = std::function<cv::GMat(cv::GMat,cv::GScalar)>;
using ocv_function_t = std::function<void(cv::Mat const&, cv::Scalar, cv::Mat&)>;
- std::string name;
g_api_function_t g_api_function;
ocv_function_t ocv_function;
-
- g_api_ocv_pair_mat_scalar(std::string const& n, g_api_function_t const& g, ocv_function_t const& o)
- : name(n), g_api_function(g), ocv_function(o) {}
-
g_api_ocv_pair_mat_scalar() = default;
- friend std::ostream& operator<<(std::ostream& o, const g_api_ocv_pair_mat_scalar& p)
+#define CASE(v) case operation::v: \
+ g_api_function = op##v##_gapi; \
+ ocv_function = op##v##_ocv; \
+ break
+
+ g_api_ocv_pair_mat_scalar(operation op)
{
- return o<<p.name;
+ switch (op)
+ {
+ CASE(ADD); CASE(SUB); CASE(MUL); CASE(DIV);
+ CASE(ADDR); CASE(SUBR); CASE(MULR); CASE(DIVR);
+ CASE(GT); CASE(LT); CASE(GE); CASE(LE); CASE(EQ); CASE(NE);
+ CASE(GTR); CASE(LTR); CASE(GER); CASE(LER); CASE(EQR); CASE(NER);
+ CASE(AND); CASE(OR); CASE(XOR);
+ CASE(ANDR); CASE(ORR); CASE(XORR);
+ default: GAPI_Assert(false && "unknown operation value");
+ }
}
+#undef CASE
};
struct g_api_ocv_pair_mat_mat {
using g_api_function_t = std::function<cv::GMat(cv::GMat,cv::GMat)>;
using ocv_function_t = std::function<void(cv::Mat const&, cv::Mat const&, cv::Mat&)>;
- std::string name;
g_api_function_t g_api_function;
ocv_function_t ocv_function;
-
- g_api_ocv_pair_mat_mat(std::string const& n, g_api_function_t const& g, ocv_function_t const& o)
- : name(n), g_api_function(g), ocv_function(o) {}
-
g_api_ocv_pair_mat_mat() = default;
- friend std::ostream& operator<<(std::ostream& o, const g_api_ocv_pair_mat_mat& p)
+#define CASE(v) case operation::v: \
+ g_api_function = op##v##M_gapi; \
+ ocv_function = op##v##M_ocv; \
+ break
+
+ g_api_ocv_pair_mat_mat(operation op)
{
- return o<<p.name;
+ switch (op)
+ {
+ CASE(ADD); CASE(SUB); CASE(DIV);
+ CASE(GT); CASE(LT); CASE(GE); CASE(LE); CASE(EQ); CASE(NE);
+ CASE(AND); CASE(OR); CASE(XOR);
+ default: GAPI_Assert(false && "unknown operation value");
+ }
}
+#undef CASE
};
-////////////////////////////////////////////////////////////////////////////////
-//
-// FIXME: Please refactor this test to a template test (T,U) with enum (OP)
-//
-////////////////////////////////////////////////////////////////////////////////
-namespace
-{
-
-//declare test cases for matrix and scalar operators
-g_api_ocv_pair_mat_scalar opPlus = {std::string{"operator+"},
- [](cv::GMat in,cv::GScalar c){return in+c;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::add(in, c, out);}};
-g_api_ocv_pair_mat_scalar opPlusR = {std::string{"rev_operator+"},
- [](cv::GMat in,cv::GScalar c){return c+in;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::add(c, in, out);}};
-g_api_ocv_pair_mat_scalar opMinus = {std::string{"operator-"},
- [](cv::GMat in,cv::GScalar c){return in-c;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::subtract(in, c, out);}};
-g_api_ocv_pair_mat_scalar opMinusR = {std::string{"rev_operator-"},
- [](cv::GMat in,cv::GScalar c){return c-in;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::subtract(c, in, out);}};
-g_api_ocv_pair_mat_scalar opMul = {std::string{"operator*"},
- [](cv::GMat in,cv::GScalar c){return in*c;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::multiply(in, c, out);}};
-g_api_ocv_pair_mat_scalar opMulR = {std::string{"rev_operator*"},
- [](cv::GMat in,cv::GScalar c){return c*in;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::multiply(c, in, out);}};
-g_api_ocv_pair_mat_scalar opDiv = {std::string{"operator/"},
- [](cv::GMat in,cv::GScalar c){return in/c;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::divide(in, c, out);}};
-g_api_ocv_pair_mat_scalar opDivR = {std::string{"rev_operator/"},
- [](cv::GMat in,cv::GScalar c){return c/in;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::divide(c, in, out);}};
-
-g_api_ocv_pair_mat_scalar opGT = {std::string{"operator>"},
- [](cv::GMat in,cv::GScalar c){return in>c;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(in, c, out,cv::CMP_GT);}};
-g_api_ocv_pair_mat_scalar opLT = {std::string{"operator<"},
- [](cv::GMat in,cv::GScalar c){return in<c;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(in, c, out,cv::CMP_LT);}};
-g_api_ocv_pair_mat_scalar opGE = {std::string{"operator>="},
- [](cv::GMat in,cv::GScalar c){return in>=c;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(in, c, out,cv::CMP_GE);}};
-g_api_ocv_pair_mat_scalar opLE = {std::string{"operator<="},
- [](cv::GMat in,cv::GScalar c){return in<=c;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(in, c, out,cv::CMP_LE);}};
-g_api_ocv_pair_mat_scalar opEQ = {std::string{"operator=="},
- [](cv::GMat in,cv::GScalar c){return in==c;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(in, c, out,cv::CMP_EQ);}};
-g_api_ocv_pair_mat_scalar opNE = {std::string{"operator!="},
- [](cv::GMat in,cv::GScalar c){return in!=c;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(in, c, out,cv::CMP_NE);}};
-g_api_ocv_pair_mat_scalar opGTR = {std::string{"rev_operator>"},
- [](cv::GMat in,cv::GScalar c){return c>in;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(c, in, out,cv::CMP_GT);}};
-g_api_ocv_pair_mat_scalar opLTR = {std::string{"rev_operator<"},
- [](cv::GMat in,cv::GScalar c){return c<in;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(c, in, out,cv::CMP_LT);}};
-g_api_ocv_pair_mat_scalar opGER = {std::string{"rev_operator>="},
- [](cv::GMat in,cv::GScalar c){return c>=in;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(c, in, out,cv::CMP_GE);}};
-g_api_ocv_pair_mat_scalar opLER = {std::string{"rev_operator<="},
- [](cv::GMat in,cv::GScalar c){return c<=in;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(c, in, out,cv::CMP_LE);}};
-g_api_ocv_pair_mat_scalar opEQR = {std::string{"rev_operator=="},
- [](cv::GMat in,cv::GScalar c){return c==in;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(c, in, out,cv::CMP_EQ);}};
-g_api_ocv_pair_mat_scalar opNER = {std::string{"rev_operator!="},
- [](cv::GMat in,cv::GScalar c){return c!=in;},
- [](const cv::Mat& in, cv::Scalar c, cv::Mat& out){cv::compare(c, in, out,cv::CMP_NE);}};
-
-g_api_ocv_pair_mat_scalar opAND = {std::string{"operator&"},
- [](cv::GMat in1,cv::GScalar in2){return in1&in2;},
- [](const cv::Mat& in1, const cv::Scalar& in2, cv::Mat& out){cv::bitwise_and(in1, in2, out);}};
-g_api_ocv_pair_mat_scalar opOR = {std::string{"operator|"},
- [](cv::GMat in1,cv::GScalar in2){return in1|in2;},
- [](const cv::Mat& in1, const cv::Scalar& in2, cv::Mat& out){cv::bitwise_or(in1, in2, out);}};
-g_api_ocv_pair_mat_scalar opXOR = {std::string{"operator^"},
- [](cv::GMat in1,cv::GScalar in2){return in1^in2;},
- [](const cv::Mat& in1, const cv::Scalar& in2, cv::Mat& out){cv::bitwise_xor(in1, in2, out);}};
-g_api_ocv_pair_mat_scalar opANDR = {std::string{"rev_operator&"},
- [](cv::GMat in1,cv::GScalar in2){return in2&in1;},
- [](const cv::Mat& in1, const cv::Scalar& in2, cv::Mat& out){cv::bitwise_and(in2, in1, out);}};
-g_api_ocv_pair_mat_scalar opORR = {std::string{"rev_operator|"},
- [](cv::GMat in1,cv::GScalar in2){return in2|in1;},
- [](const cv::Mat& in1, const cv::Scalar& in2, cv::Mat& out){cv::bitwise_or(in2, in1, out);}};
-g_api_ocv_pair_mat_scalar opXORR = {std::string{"rev_operator^"},
- [](cv::GMat in1,cv::GScalar in2){return in2^in1;},
- [](const cv::Mat& in1, const cv::Scalar& in2, cv::Mat& out){cv::bitwise_xor(in2, in1, out);}};
-
-// declare test cases for matrix and matrix operators
-g_api_ocv_pair_mat_mat opPlusM = {std::string{"operator+"},
- [](cv::GMat in1,cv::GMat in2){return in1+in2;},
- [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::add(in1, in2, out);}};
-g_api_ocv_pair_mat_mat opMinusM = {std::string{"operator-"},
- [](cv::GMat in,cv::GMat in2){return in-in2;},
- [](const cv::Mat& in, const cv::Mat& in2, cv::Mat& out){cv::subtract(in, in2, out);}};
-g_api_ocv_pair_mat_mat opDivM = {std::string{"operator/"},
- [](cv::GMat in,cv::GMat in2){return in/in2;},
- [](const cv::Mat& in, const cv::Mat& in2, cv::Mat& out){cv::divide(in, in2, out);}};
-g_api_ocv_pair_mat_mat opGreater = {std::string{"operator>"},
- [](cv::GMat in1,cv::GMat in2){return in1>in2;},
- [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::compare(in1, in2, out, cv::CMP_GT);}};
-g_api_ocv_pair_mat_mat opGreaterEq = {std::string{"operator>="},
- [](cv::GMat in1,cv::GMat in2){return in1>=in2;},
- [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::compare(in1, in2, out, cv::CMP_GE);}};
-g_api_ocv_pair_mat_mat opLess = {std::string{"operator<"},
- [](cv::GMat in1,cv::GMat in2){return in1<in2;},
- [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::compare(in1, in2, out, cv::CMP_LT);}};
-g_api_ocv_pair_mat_mat opLessEq = {std::string{"operator<="},
- [](cv::GMat in1,cv::GMat in2){return in1<=in2;},
- [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::compare(in1, in2, out, cv::CMP_LE);}};
-g_api_ocv_pair_mat_mat opEq = {std::string{"operator=="},
- [](cv::GMat in1,cv::GMat in2){return in1==in2;},
- [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::compare(in1, in2, out, cv::CMP_EQ);}};
-g_api_ocv_pair_mat_mat opNotEq = {std::string{"operator!="},
- [](cv::GMat in1,cv::GMat in2){return in1!=in2;},
- [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::compare(in1, in2, out, cv::CMP_NE);}};
-
-g_api_ocv_pair_mat_mat opAnd = {std::string{"operator&"},
- [](cv::GMat in1,cv::GMat in2){return in1&in2;},
- [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::bitwise_and(in1, in2, out);}};
-g_api_ocv_pair_mat_mat opOr = {std::string{"operator|"},
- [](cv::GMat in1,cv::GMat in2){return in1|in2;},
- [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::bitwise_or(in1, in2, out);}};
-g_api_ocv_pair_mat_mat opXor = {std::string{"operator^"},
- [](cv::GMat in1,cv::GMat in2){return in1^in2;},
- [](const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out){cv::bitwise_xor(in1, in2, out);}};
-
-} // anonymous namespace
-
// Create new value-parameterized test fixture:
// MathOperatorMatScalarTest - fixture name
// initMatsRandU - function that is used to initialize input/output data
// - available in test body
// Note: all parameter _values_ (e.g. type CV_8UC3) are set via INSTANTIATE_TEST_CASE_P macro
GAPI_TEST_FIXTURE(MathOperatorMatScalarTest, initMatsRandU,
- FIXTURE_API(CompareMats, g_api_ocv_pair_mat_scalar), 2, cmpF, op)
+ FIXTURE_API(CompareMats, operation), 2, cmpF, op)
GAPI_TEST_FIXTURE(MathOperatorMatMatTest, initMatsRandU,
- FIXTURE_API(CompareMats, g_api_ocv_pair_mat_mat), 2, cmpF, op)
+ FIXTURE_API(CompareMats, operation), 2, cmpF, op)
GAPI_TEST_FIXTURE(NotOperatorTest, initMatrixRandU, <>, 0)
} // opencv_test
{
TEST_P(MathOperatorMatScalarTest, OperatorAccuracyTest )
{
- auto fun_gapi = op.g_api_function;
- auto fun_ocv = op.ocv_function ;
+ g_api_ocv_pair_mat_scalar funcs(op);
+ auto fun_gapi = funcs.g_api_function;
+ auto fun_ocv = funcs.ocv_function;
+
+ if (op == DIVR)
+ in_mat1.setTo(1, in_mat1 == 0); // avoiding zeros in divide input data
+ if (op == DIV)
+ sc += Scalar(sc[0] == 0, sc[1] == 0, sc[2] == 0, sc[3] == 0); // avoiding zeros in divide input data
// G-API code & corresponding OpenCV code ////////////////////////////////
TEST_P(MathOperatorMatMatTest, OperatorAccuracyTest )
{
- auto fun_gapi = op.g_api_function;
- auto fun_ocv = op.ocv_function ;
+ g_api_ocv_pair_mat_mat funcs(op);
+ auto fun_gapi = funcs.g_api_function;
+ auto fun_ocv = funcs.ocv_function;
+
+ if (op == DIV)
+ in_mat2.setTo(1, in_mat2 == 0); // avoiding zeros in divide input data
// G-API code & corresponding OpenCV code ////////////////////////////////
EXPECT_EQ(0, cvtest::norm(out_mat_ocv, out_mat_gapi, NORM_INF));
}
}
+
+namespace for_test
+{
+class Foo {};
+
+inline int operator&(Foo, int) { return 1; }
+inline int operator|(Foo, int) { return 1; }
+inline int operator^(Foo, int) { return 1; }
+inline int operator~(Foo) { return 1; }
+
+inline int operator+(Foo, int) { return 1; }
+inline int operator-(Foo, int) { return 1; }
+inline int operator*(Foo, int) { return 1; }
+inline int operator/(Foo, int) { return 1; }
+
+inline int operator> (Foo, int) { return 1; }
+inline int operator>=(Foo, int) { return 1; }
+inline int operator< (Foo, int) { return 1; }
+inline int operator<=(Foo, int) { return 1; }
+inline int operator==(Foo, int) { return 1; }
+inline int operator!=(Foo, int) { return 1; }
+
+TEST(CVNamespaceOperatorsTest, OperatorCompilationTest)
+{
+ cv::GScalar sc;
+ cv::GMat mat_in1, mat_in2;
+
+ cv::GMat op_not = ~ mat_in1;
+
+ cv::GMat op_mat_mat1 = mat_in1 & mat_in2;
+ cv::GMat op_mat_mat2 = mat_in1 | mat_in2;
+ cv::GMat op_mat_mat3 = mat_in1 ^ mat_in2;
+ cv::GMat op_mat_mat4 = mat_in1 + mat_in2;
+ cv::GMat op_mat_mat5 = mat_in1 - mat_in2;
+ cv::GMat op_mat_mat6 = mat_in1 / mat_in2;
+ cv::GMat op_mat_mat7 = mat_in1 > mat_in2;
+ cv::GMat op_mat_mat8 = mat_in1 >= mat_in2;
+ cv::GMat op_mat_mat9 = mat_in1 < mat_in2;
+ cv::GMat op_mat_mat10 = mat_in1 <= mat_in2;
+ cv::GMat op_mat_mat11 = mat_in1 == mat_in2;
+ cv::GMat op_mat_mat12 = mat_in1 != mat_in2;
+
+ cv::GMat op_mat_sc1 = mat_in1 & sc;
+ cv::GMat op_mat_sc2 = mat_in1 | sc;
+ cv::GMat op_mat_sc3 = mat_in1 ^ sc;
+ cv::GMat op_mat_sc4 = mat_in1 + sc;
+ cv::GMat op_mat_sc5 = mat_in1 - sc;
+ cv::GMat op_mat_sc6 = mat_in1 * sc;
+ cv::GMat op_mat_sc7 = mat_in1 / sc;
+ cv::GMat op_mat_sc8 = mat_in1 > sc;
+ cv::GMat op_mat_sc9 = mat_in1 >= sc;
+ cv::GMat op_mat_sc10 = mat_in1 < sc;
+ cv::GMat op_mat_sc11 = mat_in1 <= sc;
+ cv::GMat op_mat_sc12 = mat_in1 == sc;
+ cv::GMat op_mat_sc13 = mat_in1 != sc;
+
+ cv::GMat op_sc_mat1 = sc & mat_in2;
+ cv::GMat op_sc_mat2 = sc | mat_in2;
+ cv::GMat op_sc_mat3 = sc ^ mat_in2;
+ cv::GMat op_sc_mat4 = sc + mat_in2;
+ cv::GMat op_sc_mat5 = sc - mat_in2;
+ cv::GMat op_sc_mat6 = sc * mat_in2;
+ cv::GMat op_sc_mat7 = sc / mat_in2;
+ cv::GMat op_sc_mat8 = sc > mat_in2;
+ cv::GMat op_sc_mat9 = sc >= mat_in2;
+ cv::GMat op_sc_mat10 = sc < mat_in2;
+ cv::GMat op_sc_mat11 = sc <= mat_in2;
+ cv::GMat op_sc_mat12 = sc == mat_in2;
+ cv::GMat op_sc_mat13 = sc != mat_in2;
+
+ cv::GMat mul_mat_float1 = mat_in1 * 1.0f;
+ cv::GMat mul_mat_float2 = 1.0f * mat_in2;
+ // No compilation errors expected
+}
+} // for_test
} // opencv_test
#endif // OPENCV_GAPI_OPERATOR_TESTS_INL_COMMON_HPP
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#ifndef OPENCV_GAPI_PARSERS_TESTS_COMMON_HPP
+#define OPENCV_GAPI_PARSERS_TESTS_COMMON_HPP
+
+#include "gapi_tests_common.hpp"
+#include "../../include/opencv2/gapi/infer/parsers.hpp"
+
+namespace opencv_test
+{
+class ParserSSDTest
+{
+public:
+ cv::Mat generateSSDoutput(const cv::Size& in_sz)
+ {
+ constexpr int maxN = 200;
+ constexpr int objSize = 7;
+ std::vector<int> dims{ 1, 1, maxN, objSize };
+ cv::Mat mat(dims, CV_32FC1);
+ auto data = mat.ptr<float>();
+
+ for (int i = 0; i < maxN; ++i)
+ {
+ float* it = data + i * objSize;
+ auto ssdIt = generateItem(i, in_sz);
+ it[0] = ssdIt.image_id;
+ it[1] = ssdIt.label;
+ it[2] = ssdIt.confidence;
+ it[3] = ssdIt.rc_left;
+ it[4] = ssdIt.rc_top;
+ it[5] = ssdIt.rc_right;
+ it[6] = ssdIt.rc_bottom;
+ }
+ return mat;
+ }
+
+ void parseSSDref(const cv::Mat& in_ssd_result,
+ const cv::Size& in_size,
+ const float confidence_threshold,
+ const bool alignment_to_square,
+ const bool filter_out_of_bounds,
+ std::vector<cv::Rect>& out_boxes)
+ {
+ out_boxes.clear();
+ const auto &in_ssd_dims = in_ssd_result.size;
+ CV_Assert(in_ssd_dims.dims() == 4u);
+
+ const int MAX_PROPOSALS = in_ssd_dims[2];
+ const int OBJECT_SIZE = in_ssd_dims[3];
+ CV_Assert(OBJECT_SIZE == 7); // fixed SSD object size
+
+ const float *data = in_ssd_result.ptr<float>();
+ cv::Rect surface({0,0}, in_size), rc;
+ float image_id, confidence;
+ int label;
+ for (int i = 0; i < MAX_PROPOSALS; ++i)
+ {
+ std::tie(rc, image_id, confidence, label)
+ = extract(data + i*OBJECT_SIZE, in_size);
+ if (image_id < 0.f)
+ {
+ break; // marks end-of-detections
+ }
+
+ if (confidence < confidence_threshold)
+ {
+ continue; // skip objects with low confidence
+ }
+
+ if (alignment_to_square)
+ {
+ adjustBoundingBox(rc);
+ }
+
+ const auto clipped_rc = rc & surface;
+ if (filter_out_of_bounds)
+ {
+ if (clipped_rc.area() != rc.area())
+ {
+ continue;
+ }
+ }
+ out_boxes.emplace_back(clipped_rc);
+ }
+ }
+
+ void parseSSDBLref(const cv::Mat& in_ssd_result,
+ const cv::Size& in_size,
+ const float confidence_threshold,
+ const int filter_label,
+ std::vector<cv::Rect>& out_boxes,
+ std::vector<int>& out_labels)
+ {
+ out_boxes.clear();
+ out_labels.clear();
+ const auto &in_ssd_dims = in_ssd_result.size;
+ CV_Assert(in_ssd_dims.dims() == 4u);
+
+ const int MAX_PROPOSALS = in_ssd_dims[2];
+ const int OBJECT_SIZE = in_ssd_dims[3];
+ CV_Assert(OBJECT_SIZE == 7); // fixed SSD object size
+ cv::Rect surface({0,0}, in_size), rc;
+ float image_id, confidence;
+ int label;
+ const float *data = in_ssd_result.ptr<float>();
+ for (int i = 0; i < MAX_PROPOSALS; i++)
+ {
+ std::tie(rc, image_id, confidence, label)
+ = extract(data + i*OBJECT_SIZE, in_size);
+ if (image_id < 0.f)
+ {
+ break; // marks end-of-detections
+ }
+
+ if (confidence < confidence_threshold ||
+ (filter_label != -1 && label != filter_label))
+ {
+ continue; // filter out object classes if filter is specified
+ }
+
+ out_boxes.emplace_back(rc & surface);
+ out_labels.emplace_back(label);
+ }
+ }
+
+private:
+ void adjustBoundingBox(cv::Rect& boundingBox)
+ {
+ auto w = boundingBox.width;
+ auto h = boundingBox.height;
+
+ boundingBox.x -= static_cast<int>(0.067 * w);
+ boundingBox.y -= static_cast<int>(0.028 * h);
+
+ boundingBox.width += static_cast<int>(0.15 * w);
+ boundingBox.height += static_cast<int>(0.13 * h);
+
+ if (boundingBox.width < boundingBox.height)
+ {
+ auto dx = (boundingBox.height - boundingBox.width);
+ boundingBox.x -= dx / 2;
+ boundingBox.width += dx;
+ }
+ else
+ {
+ auto dy = (boundingBox.width - boundingBox.height);
+ boundingBox.y -= dy / 2;
+ boundingBox.height += dy;
+ }
+ }
+
+ std::tuple<cv::Rect, float, float, int> extract(const float* it,
+ const cv::Size& in_size)
+ {
+ float image_id = it[0];
+ int label = static_cast<int>(it[1]);
+ float confidence = it[2];
+ float rc_left = it[3];
+ float rc_top = it[4];
+ float rc_right = it[5];
+ float rc_bottom = it[6];
+
+ cv::Rect rc; // map relative coordinates to the original image scale
+ rc.x = static_cast<int>(rc_left * in_size.width);
+ rc.y = static_cast<int>(rc_top * in_size.height);
+ rc.width = static_cast<int>(rc_right * in_size.width) - rc.x;
+ rc.height = static_cast<int>(rc_bottom * in_size.height) - rc.y;
+ return std::make_tuple(rc, image_id, confidence, label);
+ }
+
+ int randInRange(const int start, const int end)
+ {
+ GAPI_Assert(start <= end);
+ return start + std::rand() % (end - start + 1);
+ }
+
+ cv::Rect generateBox(const cv::Size& in_sz)
+ {
+ // Generated rectangle can reside outside of the initial image by border pixels
+ constexpr int border = 10;
+ constexpr int minW = 16;
+ constexpr int minH = 16;
+ cv::Rect box;
+ box.width = randInRange(minW, in_sz.width + 2*border);
+ box.height = randInRange(minH, in_sz.height + 2*border);
+ box.x = randInRange(-border, in_sz.width + border - box.width);
+ box.y = randInRange(-border, in_sz.height + border - box.height);
+ return box;
+ }
+
+ struct SSDitem
+ {
+ float image_id = 0.0f;
+ float label = 0.0f;
+ float confidence = 0.0f;
+ float rc_left = 0.0f;
+ float rc_top = 0.0f;
+ float rc_right = 0.0f;
+ float rc_bottom = 0.0f;
+ };
+
+ SSDitem generateItem(const int i, const cv::Size& in_sz)
+ {
+ const auto normalize = [](int v, int range) { return static_cast<float>(v) / range; };
+
+ SSDitem it;
+ it.image_id = static_cast<float>(i);
+ it.label = static_cast<float>(randInRange(0, 9));
+ it.confidence = static_cast<float>(std::rand()) / RAND_MAX;
+ auto box = generateBox(in_sz);
+ it.rc_left = normalize(box.x, in_sz.width);
+ it.rc_right = normalize(box.x + box.width, in_sz.width);
+ it.rc_top = normalize(box.y, in_sz.height);
+ it.rc_bottom = normalize(box.y + box.height, in_sz.height);
+
+ return it;
+ }
+};
+
+class ParserYoloTest
+{
+public:
+ cv::Mat generateYoloOutput(const int num_classes)
+ {
+ std::vector<int> dims = { 1, 13, 13, (num_classes + 5) * 5 };
+ cv::Mat mat(dims, CV_32FC1);
+ auto data = mat.ptr<float>();
+
+ const size_t range = dims[0] * dims[1] * dims[2] * dims[3];
+ for (size_t i = 0; i < range; ++i)
+ {
+ data[i] = static_cast<float>(std::rand()) / RAND_MAX;
+ }
+ return mat;
+ }
+
+ void parseYoloRef(const cv::Mat& in_yolo_result,
+ const cv::Size& in_size,
+ const float confidence_threshold,
+ const float nms_threshold,
+ const int num_classes,
+ const std::vector<float>& anchors,
+ std::vector<cv::Rect>& out_boxes,
+ std::vector<int>& out_labels)
+ {
+ YoloParams params;
+ constexpr auto side_square = 13 * 13;
+ this->m_out = in_yolo_result.ptr<float>();
+ this->m_side = 13;
+ this->m_lcoords = params.coords;
+ this->m_lclasses = num_classes;
+
+ std::vector<Detection> detections;
+
+ for (int i = 0; i < side_square; ++i)
+ {
+ for (int b = 0; b < params.num; ++b)
+ {
+ float scale = this->scale(i, b);
+ if (scale < confidence_threshold)
+ {
+ continue;
+ }
+ double x = this->x(i, b);
+ double y = this->y(i, b);
+ double height = this->height(i, b, anchors[2 * b + 1]);
+ double width = this->width(i, b, anchors[2 * b]);
+
+ for (int label = 0; label < num_classes; ++label)
+ {
+ float prob = scale * classConf(i,b,label);
+ if (prob < confidence_threshold)
+ {
+ continue;
+ }
+ auto box = toBox(x, y, height, width, in_size);
+ detections.emplace_back(Detection(box, prob, label));
+ }
+ }
+ }
+ std::stable_sort(std::begin(detections), std::end(detections),
+ [](const Detection& a, const Detection& b)
+ {
+ return a.conf > b.conf;
+ });
+
+ if (nms_threshold < 1.0f)
+ {
+ for (const auto& d : detections)
+ {
+ if (std::end(out_boxes) ==
+ std::find_if(std::begin(out_boxes), std::end(out_boxes),
+ [&d, nms_threshold](const cv::Rect& r)
+ {
+ float rectOverlap = 1.f - static_cast<float>(jaccardDistance(r, d.rect));
+ return rectOverlap > nms_threshold;
+ }))
+ {
+ out_boxes. emplace_back(d.rect);
+ out_labels.emplace_back(d.label);
+ }
+ }
+ }
+ else
+ {
+ for (const auto& d: detections)
+ {
+ out_boxes. emplace_back(d.rect);
+ out_labels.emplace_back(d.label);
+ }
+ }
+ }
+
+private:
+ struct Detection
+ {
+ Detection(const cv::Rect& in_rect, const float in_conf, const int in_label)
+ : rect(in_rect), conf(in_conf), label(in_label)
+ {}
+ cv::Rect rect;
+ float conf = 0.0f;
+ int label = 0;
+ };
+
+ struct YoloParams
+ {
+ int num = 5;
+ int coords = 4;
+ };
+
+ float scale(const int i, const int b)
+ {
+ int obj_index = index(i, b, m_lcoords);
+ return m_out[obj_index];
+ }
+
+ double x(const int i, const int b)
+ {
+ int box_index = index(i, b, 0);
+ int col = i % m_side;
+ return (col + m_out[box_index]) / m_side;
+ }
+
+ double y(const int i, const int b)
+ {
+ int box_index = index(i, b, 0);
+ int row = i / m_side;
+ return (row + m_out[box_index + m_side * m_side]) / m_side;
+ }
+
+ double width(const int i, const int b, const float anchor)
+ {
+ int box_index = index(i, b, 0);
+ return std::exp(m_out[box_index + 2 * m_side * m_side]) * anchor / m_side;
+ }
+
+ double height(const int i, const int b, const float anchor)
+ {
+ int box_index = index(i, b, 0);
+ return std::exp(m_out[box_index + 3 * m_side * m_side]) * anchor / m_side;
+ }
+
+ float classConf(const int i, const int b, const int label)
+ {
+ int class_index = index(i, b, m_lcoords + 1 + label);
+ return m_out[class_index];
+ }
+
+ cv::Rect toBox(const double x, const double y, const double h, const double w, const cv::Size& in_sz)
+ {
+ auto h_scale = in_sz.height;
+ auto w_scale = in_sz.width;
+ cv::Rect r;
+ r.x = static_cast<int>((x - w / 2) * w_scale);
+ r.y = static_cast<int>((y - h / 2) * h_scale);
+ r.width = static_cast<int>(w * w_scale);
+ r.height = static_cast<int>(h * h_scale);
+ return r;
+ }
+
+ int index(const int i, const int b, const int entry)
+ {
+ return b * m_side * m_side * (m_lcoords + m_lclasses + 1) + entry * m_side * m_side + i;
+ }
+
+ const float* m_out = nullptr;
+ int m_side = 0, m_lcoords = 0, m_lclasses = 0;
+};
+
+} // namespace opencv_test
+
+#endif // OPENCV_GAPI_PARSERS_TESTS_COMMON_HPP
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018-2019 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#ifndef OPENCV_GAPI_TESTS_COMMON_HPP
#define OPENCV_GAPI_TESTS_COMMON_HPP
#include <iostream>
#include <tuple>
#include <type_traits>
+#include <time.h>
#include <opencv2/ts.hpp>
#include <opencv2/gapi.hpp>
return o;
}
-}
+
+ inline void initTestDataPath()
+ {
+#ifndef WINRT
+ static bool initialized = false;
+ if (!initialized)
+ {
+ // Since G-API has no own test data (yet), it is taken from the common space
+ const char* testDataPath = getenv("OPENCV_TEST_DATA_PATH");
+ GAPI_Assert(testDataPath != nullptr &&
+ "OPENCV_TEST_DATA_PATH environment variable is either not set or set incorrectly.");
+
+ cvtest::addDataSearchPath(testDataPath);
+ initialized = true;
+ }
+#endif // WINRT
+ }
+} // namespace
namespace opencv_test
{
cv::Scalar sc;
+ // integral Scalar initialization
cv::Scalar initScalarRandU(unsigned upper)
{
- auto& rng = cv::theRNG();
- double s1 = rng(upper); // FIXIT: RNG result is 'int', not double
+ cv::RNG rng(time(nullptr));
+ double s1 = rng(upper);
double s2 = rng(upper);
double s3 = rng(upper);
double s4 = rng(upper);
return cv::Scalar(s1, s2, s3, s4);
}
+ // floating-point Scalar initialization (cv::core)
+ cv::Scalar initScalarRandU()
+ {
+ cv::RNG rng(time(nullptr));
+ double s1 = exp(rng.uniform(-1, 6) * 3.0 * CV_LOG2) * (rng.uniform(0, 2) ? 1. : -1.);
+ double s2 = exp(rng.uniform(-1, 6) * 3.0 * CV_LOG2) * (rng.uniform(0, 2) ? 1. : -1.);
+ double s3 = exp(rng.uniform(-1, 6) * 3.0 * CV_LOG2) * (rng.uniform(0, 2) ? 1. : -1.);
+ double s4 = exp(rng.uniform(-1, 6) * 3.0 * CV_LOG2) * (rng.uniform(0, 2) ? 1. : -1.);
+ return cv::Scalar(s1, s2, s3, s4);
+ }
+
void initOutMats(cv::Size sz_in, int dtype)
{
if (dtype != -1)
in_mat1 = cv::Mat(sz_in, type);
in_mat2 = cv::Mat(sz_in, type);
- sc = initScalarRandU(100);
+ int sdepth = CV_MAT_DEPTH(type);
+ int ddepth = (dtype >= 0) ? CV_MAT_DEPTH(dtype)
+ : sdepth; // dtype == -1 <=> dtype == SAME_TYPE
+
+ if ((sdepth >= CV_32F) || (ddepth >= CV_32F))
+ {
+ sc = initScalarRandU(); // initializing by floating-points
+ }
+ else
+ {
+ switch (sdepth)
+ {
+ case CV_8U:
+ sc = initScalarRandU(UCHAR_MAX + 1U);
+ break;
+ case CV_16U:
+ sc = initScalarRandU(USHRT_MAX + 1U);
+ break;
+ case CV_16S:
+ sc = initScalarRandU(SHRT_MAX + 1U);
+ break;
+ default:
+ sc = initScalarRandU(SCHAR_MAX + 1U);
+ break;
+ }
+ }
// Details: https://github.com/opencv/opencv/pull/16083
//if (CV_MAT_DEPTH(type) < CV_32F)
{
in_mat1 = cv::Mat(sz_in, type);
- sc = initScalarRandU(100);
+ int sdepth = CV_MAT_DEPTH(type);
+ int ddepth = (dtype >= 0) ? CV_MAT_DEPTH(dtype)
+ : sdepth; // dtype == -1 <=> dtype == SAME_TYPE
+
+ if ((sdepth >= CV_32F) || (ddepth >= CV_32F))
+ {
+ sc = initScalarRandU();
+ }
+ else
+ {
+ switch (sdepth)
+ {
+ case CV_8U:
+ sc = initScalarRandU(UCHAR_MAX + 1U);
+ break;
+ case CV_16U:
+ sc = initScalarRandU(USHRT_MAX + 1U);
+ break;
+ case CV_16S:
+ sc = initScalarRandU(SHRT_MAX + 1U);
+ break;
+ default:
+ sc = initScalarRandU(SCHAR_MAX + 1U);
+ break;
+ }
+ }
+
if (CV_MAT_DEPTH(type) < CV_32F)
{
cv::randu(in_mat1, cv::Scalar::all(0), cv::Scalar::all(255));
}
}
+ void initMatFromImage(int type, const std::string& fileName)
+ {
+ initTestDataPath();
+
+ int channels = (type >> CV_CN_SHIFT) + 1;
+ GAPI_Assert(channels == 1 || channels == 3 || channels == 4);
+ const int readFlags = (channels == 1) ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR;
+ cv::Mat mat = cv::imread(findDataFile(fileName), readFlags);
+ if (channels == 4)
+ {
+ cv::cvtColor(mat, in_mat1, cv::COLOR_BGR2BGRA);
+ }
+ else
+ {
+ in_mat1 = mat;
+ }
+
+ int depth = CV_MAT_DEPTH(type);
+ if (in_mat1.depth() != depth)
+ {
+ in_mat1.convertTo(in_mat1, depth);
+ }
+ }
+
+ void initMatsFromImages(int channels, const std::string& pattern, int imgNum)
+ {
+ initTestDataPath();
+ GAPI_Assert(channels == 1 || channels == 3 || channels == 4);
+ const int flags = (channels == 1) ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR;
+
+ cv::Mat m1 = cv::imread(findDataFile(cv::format(pattern.c_str(), imgNum)), flags);
+ cv::Mat m2 = cv::imread(findDataFile(cv::format(pattern.c_str(), imgNum + 1)), flags);
+ if (channels == 4)
+ {
+ cvtColor(m1, in_mat1, cv::COLOR_BGR2BGRA);
+ cvtColor(m2, in_mat2, cv::COLOR_BGR2BGRA);
+ }
+ else
+ {
+ std::tie(in_mat1, in_mat2) = std::make_tuple(m1, m2);
+ }
+ }
+
// empty function intended to show that nothing is to be initialized via TestFunctional methods
void initNothing(int, cv::Size, int, bool = true) {}
};
template<class T>
-class TestParams: public TestFunctional, public TestWithParam<T>{};
-
-template<class T>
class TestPerfParams: public TestFunctional, public perf::TestBaseWithParam<T>{};
-using compare_f = std::function<bool(const cv::Mat &a, const cv::Mat &b)>;
-
-using compare_scalar_f = std::function<bool(const cv::Scalar &a, const cv::Scalar &b)>;
-
// FIXME: re-use MatType. current problem: "special values" interpreted incorrectly (-1 is printed
// as 16FC512)
struct MatType2
};
// Universal parameter wrapper for common (pre-defined) and specific (user-defined) parameters
-template<typename ...SpecificParams>
-struct Params
+template<typename CommonParams, typename SpecificParams>
+struct ParamsBase;
+
+template<typename... CommonParams, typename... SpecificParams>
+struct ParamsBase<std::tuple<CommonParams...>, std::tuple<SpecificParams...>>
{
- using gcomp_args_function_t = cv::GCompileArgs(*)();
- using common_params_t = std::tuple<MatType2, cv::Size, MatType2, gcomp_args_function_t>;
+ using common_params_t = std::tuple<CommonParams...>;
using specific_params_t = std::tuple<SpecificParams...>;
- using params_t = std::tuple<MatType2, cv::Size, MatType2, gcomp_args_function_t, SpecificParams...>;
- static constexpr const size_t common_params_size = std::tuple_size<common_params_t>::value;
+ using params_t = std::tuple<CommonParams..., SpecificParams...>;
+ static constexpr const size_t common_params_size = std::tuple_size<common_params_t>::value;
static constexpr const size_t specific_params_size = std::tuple_size<specific_params_t>::value;
template<size_t I>
}
};
-// Base class for test fixtures
-template<typename ...SpecificParams>
-struct TestWithParamBase : TestFunctional,
- TestWithParam<typename Params<SpecificParams...>::params_t>
+template<typename... SpecificParams>
+struct Params : public ParamsBase<std::tuple<MatType2,cv::Size,MatType2,cv::GCompileArgs(*)()>,
+ std::tuple<SpecificParams...>>
{
- using AllParams = Params<SpecificParams...>;
+ static constexpr const size_t compile_args_num = 3;
+};
- MatType2 type = getCommonParam<0>();
- cv::Size sz = getCommonParam<1>();
- MatType2 dtype = getCommonParam<2>();
+template<typename ...SpecificParams>
+struct ParamsSpecific : public ParamsBase<std::tuple<cv::GCompileArgs(*)()>,
+ std::tuple<SpecificParams...>>
+{
+ static constexpr const size_t compile_args_num = 0;
+};
+// Base class for test fixtures
+template<typename AllParams>
+struct TestWithParamsBase : TestFunctional, TestWithParam<typename AllParams::params_t>
+{
// Get common (pre-defined) parameter value by index
template<size_t I>
inline auto getCommonParam() const
// Return G-API compile arguments specified for test fixture
inline cv::GCompileArgs getCompileArgs() const
{
- return getCommonParam<3>()();
+ return getCommonParam<AllParams::compile_args_num>()();
}
};
+template<typename... SpecificParams>
+struct TestWithParams : public TestWithParamsBase<Params<SpecificParams...>>
+{
+ using AllParams = Params<SpecificParams...>;
+
+ MatType2 type = this->template getCommonParam<0>();
+ cv::Size sz = this->template getCommonParam<1>();
+ MatType2 dtype = this->template getCommonParam<2>();
+};
+
+template<typename... SpecificParams>
+struct TestWithParamsSpecific : public TestWithParamsBase<ParamsSpecific<SpecificParams...>>
+{
+ using AllParams = ParamsSpecific<SpecificParams...>;
+};
+
+
/**
* @private
- * @brief Create G-API test fixture with TestWithParamBase base class
+ * @brief Create G-API test fixture with TestWithParams base class
* @param Fixture test fixture name
* @param InitF callable that will initialize default available members (from TestFunctional)
* @param API base class API. Specifies types of user-defined parameters. If there are no such
* must be empty.
*/
#define GAPI_TEST_FIXTURE(Fixture, InitF, API, Number, ...) \
- struct Fixture : public TestWithParamBase API { \
+ struct Fixture : public TestWithParams API { \
+ static_assert(Number == AllParams::specific_params_size, \
+ "Number of user-defined parameters doesn't match size of __VA_ARGS__"); \
+ __WRAP_VAARGS(DEFINE_SPECIFIC_PARAMS_##Number(__VA_ARGS__)) \
+ Fixture() { InitF(type, sz, dtype); } \
+ };
+
+/**
+ * @private
+ * @brief Create G-API test fixture with TestWithParams base class and additional base class.
+ * @param Fixture test fixture name.
+ @param ExtBase additional base class.
+ * @param InitF callable that will initialize default available members (from TestFunctional)
+ * @param API base class API. Specifies types of user-defined parameters. If there are no such
+ * parameters, empty angle brackets ("<>") must be specified.
+ * @param Number number of user-defined parameters (corresponds to the number of types in API).
+ * if there are no such parameters, 0 must be specified.
+ * @param ... list of names of user-defined parameters. if there are no parameters, the list
+ * must be empty.
+ */
+#define GAPI_TEST_EXT_BASE_FIXTURE(Fixture, ExtBase, InitF, API, Number, ...) \
+ struct Fixture : public TestWithParams API, public ExtBase { \
static_assert(Number == AllParams::specific_params_size, \
"Number of user-defined parameters doesn't match size of __VA_ARGS__"); \
__WRAP_VAARGS(DEFINE_SPECIFIC_PARAMS_##Number(__VA_ARGS__)) \
Fixture() { InitF(type, sz, dtype); } \
};
+/**
+ * @private
+ * @brief Create G-API test fixture with TestWithParamsSpecific base class
+ * This fixture has reduced number of common parameters and no initialization;
+ * it should be used if you don't need common parameters of GAPI_TEST_FIXTURE.
+ * @param Fixture test fixture name
+ * @param API base class API. Specifies types of user-defined parameters. If there are no such
+ * parameters, empty angle brackets ("<>") must be specified.
+ * @param Number number of user-defined parameters (corresponds to the number of types in API).
+ * if there are no such parameters, 0 must be specified.
+ * @param ... list of names of user-defined parameters. if there are no parameters, the list
+ * must be empty.
+ */
+#define GAPI_TEST_FIXTURE_SPEC_PARAMS(Fixture, API, Number, ...) \
+ struct Fixture : public TestWithParamsSpecific API { \
+ static_assert(Number == AllParams::specific_params_size, \
+ "Number of user-defined parameters doesn't match size of __VA_ARGS__"); \
+ __WRAP_VAARGS(DEFINE_SPECIFIC_PARAMS_##Number(__VA_ARGS__)) \
+ };
+
// Wrapper for test fixture API. Use to specify multiple types.
// Example: FIXTURE_API(int, bool) expands to <int, bool>
#define FIXTURE_API(...) <__VA_ARGS__>
+
+using compare_f = std::function<bool(const cv::Mat &a, const cv::Mat &b)>;
+using compare_scalar_f = std::function<bool(const cv::Scalar &a, const cv::Scalar &b)>;
+
+template<typename Elem>
+using compare_vector_f = std::function<bool(const std::vector<Elem> &a,
+ const std::vector<Elem> &b)>;
+
template<typename T1, typename T2>
struct CompareF
{
using CompareMats = CompareF<cv::Mat, cv::Mat>;
using CompareScalars = CompareF<cv::Scalar, cv::Scalar>;
+template<typename Elem>
+using CompareVectors = CompareF<std::vector<Elem>, std::vector<Elem>>;
+
template<typename T>
struct Wrappable
{
}
};
+template<typename T, typename Elem>
+struct WrappableVector
+{
+ compare_vector_f<Elem> to_compare_f()
+ {
+ T t = *static_cast<T* const>(this);
+ return [t](const std::vector<Elem>& a,
+ const std::vector<Elem>& b)
+ {
+ return t(a, b);
+ };
+ }
+
+ CompareVectors<Elem> to_compare_obj()
+ {
+ T t = *static_cast<T* const>(this);
+ std::stringstream ss;
+ ss << t;
+ return CompareVectors<Elem>(to_compare_f(), ss.str());
+ }
+};
+
class AbsExact : public Wrappable<AbsExact>
{
private:
double _tol;
};
+
+template<typename Elem>
+class AbsExactVector : public WrappableVector<AbsExactVector<Elem>, Elem>
+{
+public:
+ AbsExactVector() {}
+ bool operator() (const std::vector<Elem>& in1,
+ const std::vector<Elem>& in2) const
+ {
+ if (cv::norm(in1, in2, NORM_INF, cv::noArray()) != 0)
+ {
+ std::cout << "AbsExact error: G-API output and reference output vectors are not"
+ " bitexact equal." << std::endl;
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ friend std::ostream& operator<<(std::ostream& os, const AbsExactVector<Elem>&)
+ {
+ return os << "AbsExactVector()";
+ }
+};
} // namespace opencv_test
namespace
{
return os << "compare_scalar_f";
}
+
+template<typename Elem>
+inline std::ostream& operator<<(std::ostream& os, const opencv_test::compare_vector_f<Elem>&)
+{
+ return os << "compare_vector_f";
+}
} // anonymous namespace
// Note: namespace must match the namespace of the type of the printed object
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#include "../test_precomp.hpp"
+#include "gapi_video_tests_inl.hpp"
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#ifndef OPENCV_GAPI_VIDEO_TESTS_HPP
+#define OPENCV_GAPI_VIDEO_TESTS_HPP
+
+#include "gapi_video_tests_common.hpp"
+
+namespace opencv_test
+{
+GAPI_TEST_FIXTURE_SPEC_PARAMS(BuildOptFlowPyramidTest,
+ FIXTURE_API(std::string,int,int,bool,int,int,bool), 7,
+ fileName, winSize, maxLevel, withDerivatives, pyrBorder,
+ derivBorder, tryReuseInputImage)
+
+GAPI_TEST_FIXTURE_SPEC_PARAMS(OptFlowLKTest, FIXTURE_API(std::string,int,tuple<int,int>,int,
+ cv::TermCriteria),
+ 5, fileNamePattern, channels, pointsNum, winSize, criteria)
+
+GAPI_TEST_FIXTURE_SPEC_PARAMS(OptFlowLKTestForPyr, FIXTURE_API(std::string,int,tuple<int,int>,int,
+ cv::TermCriteria,bool),
+ 6, fileNamePattern, channels, pointsNum, winSize, criteria,withDeriv)
+
+GAPI_TEST_FIXTURE_SPEC_PARAMS(BuildPyr_CalcOptFlow_PipelineTest,
+ FIXTURE_API(std::string,int,int,bool), 4,
+ fileNamePattern, winSize, maxLevel, withDerivatives)
+
+} // opencv_test
+
+
+#endif // OPENCV_GAPI_VIDEO_TESTS_HPP
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#ifndef OPENCV_GAPI_VIDEO_TESTS_COMMON_HPP
+#define OPENCV_GAPI_VIDEO_TESTS_COMMON_HPP
+
+#include "gapi_tests_common.hpp"
+#include "../../include/opencv2/gapi/video.hpp"
+
+#ifdef HAVE_OPENCV_VIDEO
+#include <opencv2/video.hpp>
+#endif // HAVE_OPENCV_VIDEO
+
+
+
+namespace opencv_test
+{
+namespace
+{
+G_TYPED_KERNEL(GMinScalar, <GScalar(GScalar,GScalar)>, "custom.MinScalar") {
+ static GScalarDesc outMeta(GScalarDesc,GScalarDesc) { return empty_scalar_desc(); }
+};
+GAPI_OCV_KERNEL(GCPUMinScalar, GMinScalar) {
+ static void run(const Scalar &sc1, const Scalar &sc2, Scalar &scOut) {
+ scOut = Scalar(std::min(sc1[0], sc2[0]));
+ }
+};
+
+inline void initTrackingPointsArray(std::vector<cv::Point2f>& points, int width, int height,
+ int nPointsX, int nPointsY)
+{
+ if (nPointsX > width || nPointsY > height)
+ {
+ FAIL() << "Specified points number is too big";
+ }
+
+ int stepX = width / nPointsX;
+ int stepY = height / nPointsY;
+
+
+ points.clear();
+ GAPI_Assert((nPointsX >= 0) && (nPointsY) >= 0);
+ points.reserve(nPointsX * nPointsY);
+
+ for (int x = stepX / 2; x < width; x += stepX)
+ {
+ for (int y = stepY / 2; y < height; y += stepY)
+ {
+ Point2f pt(static_cast<float>(x), static_cast<float>(y));
+ points.push_back(pt);
+ }
+ }
+}
+
+struct BuildOpticalFlowPyramidTestOutput
+{
+ BuildOpticalFlowPyramidTestOutput(std::vector<Mat> &pyr, int maxLvl) :
+ pyramid(pyr), maxLevel(maxLvl) { }
+ std::vector<Mat> &pyramid;
+ int maxLevel = 0;
+};
+
+template<typename Type>
+struct OptFlowLKTestInput
+{
+ Type& prevData;
+ Type& nextData;
+ std::vector<cv::Point2f>& prevPoints;
+};
+
+struct OptFlowLKTestOutput
+{
+ std::vector<cv::Point2f> &nextPoints;
+ std::vector<uchar> &statuses;
+ std::vector<float> &errors;
+};
+
+struct BuildOpticalFlowPyramidTestParams
+{
+ BuildOpticalFlowPyramidTestParams() = default;
+
+ BuildOpticalFlowPyramidTestParams(const std::string& name, int winSz, int maxLvl,
+ bool withDeriv, int pBorder, int dBorder,
+ bool tryReuse, const GCompileArgs& compArgs):
+
+ fileName(name), winSize(winSz), maxLevel(maxLvl),
+ withDerivatives(withDeriv), pyrBorder(pBorder),
+ derivBorder(dBorder), tryReuseInputImage(tryReuse),
+ compileArgs(compArgs) { }
+
+ std::string fileName = "";
+ int winSize = -1;
+ int maxLevel = -1;
+ bool withDerivatives = false;
+ int pyrBorder = -1;
+ int derivBorder = -1;
+ bool tryReuseInputImage = false;
+ cv::GCompileArgs compileArgs;
+};
+
+struct OptFlowLKTestParams
+{
+ OptFlowLKTestParams(): fileNamePattern(""), format(1), channels(0), pointsNum{0, 0},
+ winSize(0), maxLevel(3), minEigThreshold(1e-4), flags(0) { }
+
+ OptFlowLKTestParams(const std::string& namePat, int chans,
+ const std::tuple<int,int>& ptsNum, int winSz,
+ const cv::TermCriteria& crit, const cv::GCompileArgs& compArgs,
+ int flgs = 0, int fmt = 1, int maxLvl = 3, double minEigThresh = 1e-4):
+
+ fileNamePattern(namePat), format(fmt), channels(chans),
+ pointsNum(ptsNum), winSize(winSz), maxLevel(maxLvl),
+ criteria(crit), minEigThreshold(minEigThresh), compileArgs(compArgs),
+ flags(flgs) { }
+
+ std::string fileNamePattern = "";
+ int format = 1;
+ int channels = 0;
+ std::tuple<int,int> pointsNum = std::make_tuple(0, 0);
+ int winSize = 0;
+ int maxLevel = 3;
+ cv::TermCriteria criteria;
+ double minEigThreshold = 1e-4;
+ cv::GCompileArgs compileArgs;
+ int flags = 0;
+};
+
+#ifdef HAVE_OPENCV_VIDEO
+
+inline GComputation runOCVnGAPIBuildOptFlowPyramid(TestFunctional& testInst,
+ const BuildOpticalFlowPyramidTestParams& params,
+ BuildOpticalFlowPyramidTestOutput& outOCV,
+ BuildOpticalFlowPyramidTestOutput& outGAPI)
+{
+ testInst.initMatFromImage(CV_8UC1, params.fileName);
+
+ // OpenCV code /////////////////////////////////////////////////////////////
+ {
+ outOCV.maxLevel = cv::buildOpticalFlowPyramid(testInst.in_mat1, outOCV.pyramid,
+ Size(params.winSize, params.winSize),
+ params.maxLevel, params.withDerivatives,
+ params.pyrBorder, params.derivBorder,
+ params.tryReuseInputImage);
+ }
+
+ // G-API code //////////////////////////////////////////////////////////////
+ GMat in;
+ GArray<GMat> out;
+ GScalar outMaxLevel;
+ std::tie(out, outMaxLevel) =
+ cv::gapi::buildOpticalFlowPyramid(in, Size(params.winSize, params.winSize),
+ params.maxLevel, params.withDerivatives,
+ params.pyrBorder, params.derivBorder,
+ params.tryReuseInputImage);
+
+ GComputation c(GIn(in), GOut(out, outMaxLevel));
+
+ Scalar outMaxLevelSc;
+ c.apply(gin(testInst.in_mat1), gout(outGAPI.pyramid, outMaxLevelSc),
+ std::move(const_cast<GCompileArgs&>(params.compileArgs)));
+ outGAPI.maxLevel = static_cast<int>(outMaxLevelSc[0]);
+
+ return c;
+}
+
+template<typename GType, typename Type>
+cv::GComputation runOCVnGAPIOptFlowLK(OptFlowLKTestInput<Type>& in,
+ int width, int height,
+ const OptFlowLKTestParams& params,
+ OptFlowLKTestOutput& ocvOut,
+ OptFlowLKTestOutput& gapiOut)
+{
+
+ int nPointsX = 0, nPointsY = 0;
+ std::tie(nPointsX, nPointsY) = params.pointsNum;
+
+ initTrackingPointsArray(in.prevPoints, width, height, nPointsX, nPointsY);
+
+ cv::Size winSize(params.winSize, params.winSize);
+
+ // OpenCV code /////////////////////////////////////////////////////////////
+ {
+ cv::calcOpticalFlowPyrLK(in.prevData, in.nextData, in.prevPoints,
+ ocvOut.nextPoints, ocvOut.statuses, ocvOut.errors,
+ winSize, params.maxLevel, params.criteria,
+ params.flags, params.minEigThreshold);
+ }
+
+ // G-API code //////////////////////////////////////////////////////////////
+ {
+ GType inPrev, inNext;
+ GArray<cv::Point2f> prevPts, predPts, nextPts;
+ GArray<uchar> statuses;
+ GArray<float> errors;
+ std::tie(nextPts, statuses, errors) = cv::gapi::calcOpticalFlowPyrLK(
+ inPrev, inNext,
+ prevPts, predPts, winSize,
+ params.maxLevel, params.criteria,
+ params.flags, params.minEigThreshold);
+
+ cv::GComputation c(cv::GIn(inPrev, inNext, prevPts, predPts),
+ cv::GOut(nextPts, statuses, errors));
+
+ c.apply(cv::gin(in.prevData, in.nextData, in.prevPoints, std::vector<cv::Point2f>{ }),
+ cv::gout(gapiOut.nextPoints, gapiOut.statuses, gapiOut.errors),
+ std::move(const_cast<cv::GCompileArgs&>(params.compileArgs)));
+
+ return c;
+ }
+}
+
+inline cv::GComputation runOCVnGAPIOptFlowLK(TestFunctional& testInst,
+ std::vector<cv::Point2f>& inPts,
+ const OptFlowLKTestParams& params,
+ OptFlowLKTestOutput& ocvOut,
+ OptFlowLKTestOutput& gapiOut)
+{
+ testInst.initMatsFromImages(params.channels,
+ params.fileNamePattern,
+ params.format);
+
+ OptFlowLKTestInput<cv::Mat> in{ testInst.in_mat1, testInst.in_mat2, inPts };
+
+ return runOCVnGAPIOptFlowLK<cv::GMat>(in,
+ testInst.in_mat1.cols,
+ testInst.in_mat1.rows,
+ params,
+ ocvOut,
+ gapiOut);
+}
+
+inline cv::GComputation runOCVnGAPIOptFlowLKForPyr(TestFunctional& testInst,
+ OptFlowLKTestInput<std::vector<cv::Mat>>& in,
+ const OptFlowLKTestParams& params,
+ bool withDeriv,
+ OptFlowLKTestOutput& ocvOut,
+ OptFlowLKTestOutput& gapiOut)
+{
+ testInst.initMatsFromImages(params.channels,
+ params.fileNamePattern,
+ params.format);
+
+ cv::Size winSize(params.winSize, params.winSize);
+
+ OptFlowLKTestParams updatedParams(params);
+ updatedParams.maxLevel = cv::buildOpticalFlowPyramid(testInst.in_mat1, in.prevData,
+ winSize, params.maxLevel, withDeriv);
+ updatedParams.maxLevel = cv::buildOpticalFlowPyramid(testInst.in_mat2, in.nextData,
+ winSize, params.maxLevel, withDeriv);
+
+
+ return runOCVnGAPIOptFlowLK<cv::GArray<cv::GMat>>(in,
+ testInst.in_mat1.cols,
+ testInst.in_mat1.rows,
+ updatedParams,
+ ocvOut,
+ gapiOut);
+}
+
+inline GComputation runOCVnGAPIOptFlowPipeline(TestFunctional& testInst,
+ const BuildOpticalFlowPyramidTestParams& params,
+ OptFlowLKTestOutput& outOCV,
+ OptFlowLKTestOutput& outGAPI,
+ std::vector<Point2f>& prevPoints)
+{
+ testInst.initMatsFromImages(3, params.fileName, 1);
+
+ initTrackingPointsArray(prevPoints, testInst.in_mat1.cols, testInst.in_mat1.rows, 15, 15);
+
+ Size winSize = Size(params.winSize, params.winSize);
+
+ // OpenCV code /////////////////////////////////////////////////////////////
+ {
+ std::vector<Mat> pyr1, pyr2;
+ int maxLevel1 = cv::buildOpticalFlowPyramid(testInst.in_mat1, pyr1, winSize,
+ params.maxLevel, params.withDerivatives,
+ params.pyrBorder, params.derivBorder,
+ params.tryReuseInputImage);
+ int maxLevel2 = cv::buildOpticalFlowPyramid(testInst.in_mat2, pyr2, winSize,
+ params.maxLevel, params.withDerivatives,
+ params.pyrBorder, params.derivBorder,
+ params.tryReuseInputImage);
+ cv::calcOpticalFlowPyrLK(pyr1, pyr2, prevPoints,
+ outOCV.nextPoints, outOCV.statuses, outOCV.errors,
+ winSize, std::min(maxLevel1, maxLevel2));
+ }
+
+ // G-API code //////////////////////////////////////////////////////////////
+ GMat in1, in2;
+ GArray<GMat> gpyr1, gpyr2;
+ GScalar gmaxLevel1, gmaxLevel2;
+ GArray<cv::Point2f> gprevPts, gpredPts, gnextPts;
+ GArray<uchar> gstatuses;
+ GArray<float> gerrors;
+
+ std::tie(gpyr1, gmaxLevel1) = cv::gapi::buildOpticalFlowPyramid(
+ in1, winSize, params.maxLevel,
+ params.withDerivatives, params.pyrBorder,
+ params.derivBorder, params.tryReuseInputImage);
+
+ std::tie(gpyr2, gmaxLevel2) = cv::gapi::buildOpticalFlowPyramid(
+ in2, winSize, params.maxLevel,
+ params.withDerivatives, params.pyrBorder,
+ params.derivBorder, params.tryReuseInputImage);
+
+ GScalar gmaxLevel = GMinScalar::on(gmaxLevel1, gmaxLevel2);
+
+ std::tie(gnextPts, gstatuses, gerrors) = cv::gapi::calcOpticalFlowPyrLK(
+ gpyr1, gpyr2, gprevPts, gpredPts, winSize,
+ gmaxLevel);
+
+ cv::GComputation c(GIn(in1, in2, gprevPts, gpredPts), cv::GOut(gnextPts, gstatuses, gerrors));
+
+ c.apply(cv::gin(testInst.in_mat1, testInst.in_mat2, prevPoints, std::vector<cv::Point2f>{ }),
+ cv::gout(outGAPI.nextPoints, outGAPI.statuses, outGAPI.errors),
+ std::move(const_cast<cv::GCompileArgs&>(params.compileArgs)));
+
+ return c;
+}
+
+#else // !HAVE_OPENCV_VIDEO
+
+inline cv::GComputation runOCVnGAPIBuildOptFlowPyramid(TestFunctional&,
+ const BuildOpticalFlowPyramidTestParams&,
+ BuildOpticalFlowPyramidTestOutput&,
+ BuildOpticalFlowPyramidTestOutput&)
+{
+ GAPI_Assert(0 && "This function shouldn't be called without opencv_video");
+}
+
+inline cv::GComputation runOCVnGAPIOptFlowLK(TestFunctional&,
+ std::vector<cv::Point2f>&,
+ const OptFlowLKTestParams&,
+ OptFlowLKTestOutput&,
+ OptFlowLKTestOutput&)
+{
+ GAPI_Assert(0 && "This function shouldn't be called without opencv_video");
+}
+
+inline cv::GComputation runOCVnGAPIOptFlowLKForPyr(TestFunctional&,
+ OptFlowLKTestInput<std::vector<cv::Mat>>&,
+ const OptFlowLKTestParams&,
+ bool,
+ OptFlowLKTestOutput&,
+ OptFlowLKTestOutput&)
+{
+ GAPI_Assert(0 && "This function shouldn't be called without opencv_video");
+}
+
+inline GComputation runOCVnGAPIOptFlowPipeline(TestFunctional&,
+ const BuildOpticalFlowPyramidTestParams&,
+ OptFlowLKTestOutput&,
+ OptFlowLKTestOutput&,
+ std::vector<Point2f>&)
+{
+ GAPI_Assert(0 && "This function shouldn't be called without opencv_video");
+}
+
+#endif // HAVE_OPENCV_VIDEO
+
+inline void compareOutputPyramids(const BuildOpticalFlowPyramidTestOutput& outOCV,
+ const BuildOpticalFlowPyramidTestOutput& outGAPI)
+{
+ GAPI_Assert(outGAPI.maxLevel == outOCV.maxLevel);
+ GAPI_Assert(outOCV.maxLevel >= 0);
+ size_t maxLevel = static_cast<size_t>(outOCV.maxLevel);
+ for (size_t i = 0; i <= maxLevel; i++)
+ {
+ EXPECT_TRUE(AbsExact().to_compare_f()(outOCV.pyramid[i], outGAPI.pyramid[i]));
+ }
+}
+
+template <typename Elem>
+inline bool compareVectorsAbsExactForOptFlow(std::vector<Elem> outOCV, std::vector<Elem> outGAPI)
+{
+ return AbsExactVector<Elem>().to_compare_f()(outOCV, outGAPI);
+}
+
+inline void compareOutputsOptFlow(const OptFlowLKTestOutput& outOCV,
+ const OptFlowLKTestOutput& outGAPI)
+{
+ EXPECT_TRUE(compareVectorsAbsExactForOptFlow(outGAPI.nextPoints, outOCV.nextPoints));
+ EXPECT_TRUE(compareVectorsAbsExactForOptFlow(outGAPI.statuses, outOCV.statuses));
+ EXPECT_TRUE(compareVectorsAbsExactForOptFlow(outGAPI.errors, outOCV.errors));
+}
+
+inline std::ostream& operator<<(std::ostream& os, const cv::TermCriteria& criteria)
+{
+ os << "{";
+ switch (criteria.type) {
+ case cv::TermCriteria::COUNT:
+ os << "COUNT; ";
+ break;
+ case cv::TermCriteria::EPS:
+ os << "EPS; ";
+ break;
+ case cv::TermCriteria::COUNT | cv::TermCriteria::EPS:
+ os << "COUNT | EPS; ";
+ break;
+ default:
+ os << "TypeUndefined; ";
+ break;
+ };
+
+ return os << criteria.maxCount << "; " << criteria.epsilon <<"}";
+}
+} // namespace
+} // namespace opencv_test
+
+
+#endif // OPENCV_GAPI_VIDEO_TESTS_COMMON_HPP
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#ifndef OPENCV_GAPI_VIDEO_TESTS_INL_HPP
+#define OPENCV_GAPI_VIDEO_TESTS_INL_HPP
+
+#include "gapi_video_tests.hpp"
+
+namespace opencv_test
+{
+
+TEST_P(BuildOptFlowPyramidTest, AccuracyTest)
+{
+ std::vector<Mat> outPyrOCV, outPyrGAPI;
+ int outMaxLevelOCV = 0, outMaxLevelGAPI = 0;
+
+ BuildOpticalFlowPyramidTestParams params { fileName, winSize, maxLevel,
+ withDerivatives, pyrBorder, derivBorder,
+ tryReuseInputImage, getCompileArgs() };
+
+ BuildOpticalFlowPyramidTestOutput outOCV { outPyrOCV, outMaxLevelOCV };
+ BuildOpticalFlowPyramidTestOutput outGAPI { outPyrGAPI, outMaxLevelGAPI };
+
+ runOCVnGAPIBuildOptFlowPyramid(*this, params, outOCV, outGAPI);
+
+ compareOutputPyramids(outOCV, outGAPI);
+}
+
+TEST_P(OptFlowLKTest, AccuracyTest)
+{
+ std::vector<cv::Point2f> outPtsOCV, outPtsGAPI, inPts;
+ std::vector<uchar> outStatusOCV, outStatusGAPI;
+ std::vector<float> outErrOCV, outErrGAPI;
+
+ OptFlowLKTestParams params { fileNamePattern, channels, pointsNum,
+ winSize, criteria, getCompileArgs() };
+
+ OptFlowLKTestOutput outOCV { outPtsOCV, outStatusOCV, outErrOCV };
+ OptFlowLKTestOutput outGAPI { outPtsGAPI, outStatusGAPI, outErrGAPI };
+
+ runOCVnGAPIOptFlowLK(*this, inPts, params, outOCV, outGAPI);
+
+ compareOutputsOptFlow(outOCV, outGAPI);
+}
+
+TEST_P(OptFlowLKTestForPyr, AccuracyTest)
+{
+ std::vector<cv::Mat> inPyr1, inPyr2;
+ std::vector<cv::Point2f> outPtsOCV, outPtsGAPI, inPts;
+ std::vector<uchar> outStatusOCV, outStatusGAPI;
+ std::vector<float> outErrOCV, outErrGAPI;
+
+ OptFlowLKTestParams params { fileNamePattern, channels, pointsNum,
+ winSize, criteria, getCompileArgs() };
+
+ OptFlowLKTestInput<std::vector<cv::Mat>> in { inPyr1, inPyr2, inPts };
+ OptFlowLKTestOutput outOCV { outPtsOCV, outStatusOCV, outErrOCV };
+ OptFlowLKTestOutput outGAPI { outPtsGAPI, outStatusGAPI, outErrGAPI };
+
+ runOCVnGAPIOptFlowLKForPyr(*this, in, params, withDeriv, outOCV, outGAPI);
+
+ compareOutputsOptFlow(outOCV, outGAPI);
+}
+
+TEST_P(BuildPyr_CalcOptFlow_PipelineTest, AccuracyTest)
+{
+ std::vector<Point2f> outPtsOCV, outPtsGAPI, inPts;
+ std::vector<uchar> outStatusOCV, outStatusGAPI;
+ std::vector<float> outErrOCV, outErrGAPI;
+
+ BuildOpticalFlowPyramidTestParams params { fileNamePattern, winSize, maxLevel,
+ withDerivatives, BORDER_DEFAULT, BORDER_DEFAULT,
+ true, getCompileArgs() };
+
+ auto customKernel = gapi::kernels<GCPUMinScalar>();
+ auto kernels = gapi::combine(customKernel,
+ params.compileArgs[0].get<gapi::GKernelPackage>());
+ params.compileArgs = compile_args(kernels);
+
+ OptFlowLKTestOutput outOCV { outPtsOCV, outStatusOCV, outErrOCV };
+ OptFlowLKTestOutput outGAPI { outPtsGAPI, outStatusGAPI, outErrGAPI };
+
+ runOCVnGAPIOptFlowPipeline(*this, params, outOCV, outGAPI, inPts);
+
+ compareOutputsOptFlow(outOCV, outGAPI);
+}
+
+} // opencv_test
+
+#endif // OPENCV_GAPI_VIDEO_TESTS_INL_HPP
namespace
{
-#define CORE_CPU [] () { return cv::compile_args(cv::gapi::core::cpu::kernels()); }
+#define CORE_CPU [] () { return cv::compile_args(cv::gapi::use_only{cv::gapi::core::cpu::kernels()}); }
} // anonymous namespace
namespace opencv_test
Values(CV_8U),
Values(CORE_CPU),
Values(CMP_EQ, CMP_GE, CMP_NE, CMP_GT, CMP_LT, CMP_LE),
- testing::Bool()));
+ testing::Bool(),
+ Values(AbsExact().to_compare_obj())));
INSTANTIATE_TEST_CASE_P(BitwiseTestCPU, BitwiseTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
cv::Size(128, 128)),
Values(-1),
Values(CORE_CPU),
- Values(AND, OR, XOR)));
+ Values(AND, OR, XOR),
+ testing::Bool()));
INSTANTIATE_TEST_CASE_P(BitwiseNotTestCPU, NotTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
Values(cv::Size(640, 400),
cv::Size(10, 480))));
+INSTANTIATE_TEST_CASE_P(ParseTestCPU, ParseSSDBLTest,
+ Combine(Values(CV_8UC1, CV_8UC3, CV_32FC1),
+ Values(cv::Size(1920, 1080)),
+ Values(-1),
+ Values(CORE_CPU),
+ Values(0.3f, 0.5f, 0.7f),
+ Values(-1, 0, 1)));
+
+INSTANTIATE_TEST_CASE_P(ParseTestCPU, ParseSSDTest,
+ Combine(Values(CV_8UC1, CV_8UC3, CV_32FC1),
+ Values(cv::Size(1920, 1080)),
+ Values(-1),
+ Values(CORE_CPU),
+ Values(0.3f, 0.5f, 0.7f),
+ testing::Bool(),
+ testing::Bool()));
+
+INSTANTIATE_TEST_CASE_P(ParseTestCPU, ParseYoloTest,
+ Combine(Values(CV_8UC1, CV_8UC3, CV_32FC1),
+ Values(cv::Size(1920, 1080)),
+ Values(-1),
+ Values(CORE_CPU),
+ Values(0.3f, 0.5f, 0.7f),
+ Values(0.5f, 1.0f),
+ Values(80, 7)));
+
+INSTANTIATE_TEST_CASE_P(SizeTestCPU, SizeTest,
+ Combine(Values(CV_8UC1, CV_8UC3, CV_32FC1),
+ Values(cv::Size(32, 32),
+ cv::Size(640, 320)),
+ Values(-1),
+ Values(CORE_CPU)));
+
+INSTANTIATE_TEST_CASE_P(SizeRTestCPU, SizeRTest,
+ Combine(Values(CV_8UC1, CV_8UC3, CV_32FC1),
+ Values(cv::Size(32, 32),
+ cv::Size(640, 320)),
+ Values(-1),
+ Values(CORE_CPU)));
}
namespace
{
-#define CORE_FLUID [] () { return cv::compile_args(cv::gapi::core::fluid::kernels()); }
+#define CORE_FLUID [] () { return cv::compile_args(cv::gapi::use_only{cv::gapi::core::fluid::kernels()}); }
} // anonymous namespace
namespace opencv_test
{
-
// FIXME: Windows accuracy problems after recent update!
INSTANTIATE_TEST_CASE_P(MathOpTestFluid, MathOpTest,
Combine(Values(CV_8UC3, CV_8UC1, CV_16SC1, CV_32FC1),
cv::Size(128, 128)),
Values(-1, CV_8U, CV_32F),
Values(CORE_FLUID),
- Values(ADD, SUB, DIV, MUL),
+ Values(DIV, MUL),
+ testing::Bool(),
+ Values(1.0),
+ testing::Bool()));
+
+// FIXME: Accuracy test for SUB math operation fails on FullHD and HD CV_16SC1 input cv::Mat,
+// double-presicion input cv::Scalar and CV_32FC1 output cv::Mat on Mac.
+// Accuracy test for ADD math operation fails on HD CV_16SC1 input cv::Mat,
+// double-presicion input cv::Scalar and CV_32FC1 output cv::Mat on Mac.
+// As failures are sporadic, disabling all instantiation cases for SUB and ADD.
+// Github ticket: https://github.com/opencv/opencv/issues/18373.
+INSTANTIATE_TEST_CASE_P(DISABLED_MathOpTestFluid, MathOpTest,
+ Combine(Values(CV_8UC3, CV_8UC1, CV_16SC1, CV_32FC1),
+ Values(cv::Size(1920, 1080),
+ cv::Size(1280, 720),
+ cv::Size(640, 480),
+ cv::Size(128, 128)),
+ Values(-1, CV_8U, CV_32F),
+ Values(CORE_FLUID),
+ Values(ADD, SUB),
testing::Bool(),
Values(1.0),
testing::Bool()));
+// FIXME: Accuracy test for SUB math operation fails on CV_16SC1 input cv::Mat, double-presicion
+// input cv::Scalar and CV_32FC1 output cv::Mat on Mac.
+// As failures are sporadic, disabling all instantiation cases for SUB operation.
+// Github ticket: https://github.com/opencv/opencv/issues/18373.
+INSTANTIATE_TEST_CASE_P(DISABLED_SubTestFluid, MathOpTest,
+ Combine(Values(CV_8UC1, CV_16SC1 , CV_32FC1),
+ Values(cv::Size(1280, 720),
+ cv::Size(640, 480),
+ cv::Size(128, 128)),
+ Values(-1, CV_8U, CV_32F),
+ Values(CORE_FLUID),
+ Values(SUB),
+ testing::Bool(),
+ Values (1.0),
+ testing::Bool()));
+
INSTANTIATE_TEST_CASE_P(MulSTestFluid, MulDoubleTest,
Combine(Values(CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
Values(CV_8U, CV_32F),
Values(CORE_FLUID)));
+INSTANTIATE_TEST_CASE_P(DISABLED_MeanTestFluid, MeanTest,
+ Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
+ Values(cv::Size(1280, 720),
+ cv::Size(640, 480),
+ cv::Size(128, 128)),
+ Values(-1),
+ Values(CORE_FLUID)));
+
+INSTANTIATE_TEST_CASE_P(MaskTestFluid, MaskTest,
+ Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
+ Values(cv::Size(1280, 720),
+ cv::Size(640, 480),
+ cv::Size(128, 128)),
+ Values(-1),
+ Values(CORE_FLUID)));
+
INSTANTIATE_TEST_CASE_P(AbsDiffTestFluid, AbsDiffTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(128, 128)),
Values(-1),
Values(CORE_FLUID),
- Values(AND, OR, XOR)));
+ Values(AND, OR, XOR),
+ testing::Bool()));
INSTANTIATE_TEST_CASE_P(BitwiseNotTestFluid, NotTest,
Combine(Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_16SC1),
Values(-1),
Values(CORE_FLUID)));
+INSTANTIATE_TEST_CASE_P(DISABLED_SumTestFluid, SumTest,
+ Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
+ Values(cv::Size(1280, 720),
+ cv::Size(640, 480),
+ cv::Size(128, 128)),
+ Values(-1),
+ Values(CORE_FLUID),
+ Values(AbsToleranceScalar(1e-5).to_compare_obj())));
+
INSTANTIATE_TEST_CASE_P(CompareTestFluid, CmpTest,
Combine(Values(CV_8UC3, CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1920, 1080),
Values(CV_8U),
Values(CORE_FLUID),
Values(CMP_EQ, CMP_GE, CMP_NE, CMP_GT, CMP_LT, CMP_LE),
- testing::Bool()));
+ Values(false),
+ Values(AbsExact().to_compare_obj())));
+
+// FIXME: solve comparison error to unite with the test above
+INSTANTIATE_TEST_CASE_P(CompareTestFluidScalar, CmpTest,
+ Combine(Values(CV_8UC3, CV_8UC1, CV_16SC1, CV_32FC1),
+ Values(cv::Size(1920, 1080),
+ cv::Size(1280, 720),
+ cv::Size(640, 480),
+ cv::Size(128, 128)),
+ Values(CV_8U),
+ Values(CORE_FLUID),
+ Values(CMP_EQ, CMP_GE, CMP_NE, CMP_GT, CMP_LT, CMP_LE),
+ Values(true),
+ Values(AbsSimilarPoints(1, 0.01).to_compare_obj())));
INSTANTIATE_TEST_CASE_P(AddWeightedTestFluid, AddWeightedTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(CORE_FLUID),
Values(Tolerance_FloatRel_IntAbs(1e-5, 2).to_compare_obj())));
+INSTANTIATE_TEST_CASE_P(DISABLED_NormTestFluid, NormTest,
+ Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
+ Values(cv::Size(1280, 720),
+ cv::Size(640, 480),
+ cv::Size(128, 128)),
+ Values(-1),
+ Values(CORE_FLUID),
+ Values(AbsToleranceScalar(1e-5).to_compare_obj()),
+ Values(NORM_INF, NORM_L1, NORM_L2)));
+
+INSTANTIATE_TEST_CASE_P(DISABLED_IntegralTestFluid, IntegralTest,
+ Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
+ Values(cv::Size(1280, 720),
+ cv::Size(640, 480),
+ cv::Size(128, 128)),
+ Values(-1),
+ Values(CORE_FLUID)));
+
INSTANTIATE_TEST_CASE_P(LUTTestFluid, LUTTest,
Combine(Values(CV_8UC1, CV_8UC3),
Values(cv::Size(1920, 1080),
Values(CORE_FLUID)));
INSTANTIATE_TEST_CASE_P(ConvertToFluid, ConvertToTest,
- Combine(Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_32FC1),
- Values(cv::Size(1920, 1080),
- cv::Size(1280, 720),
+ Combine(Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1),
+ Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
- Values(CV_8U, CV_16U, CV_32F),
+ Values(CV_8U, CV_16U, CV_16S, CV_32F),
Values(CORE_FLUID),
Values(Tolerance_FloatRel_IntAbs(1e-5, 2).to_compare_obj()),
Values(2.5, 1.0, -1.0),
Values(250.0, 0.0, -128.0)));
+INSTANTIATE_TEST_CASE_P(DISABLED_ConcatHorTestFluid, ConcatHorTest,
+ Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
+ Values(cv::Size(1280, 720),
+ cv::Size(640, 480),
+ cv::Size(128, 128)),
+ Values(-1),
+ Values(CORE_FLUID)));
+
+INSTANTIATE_TEST_CASE_P(DISABLED_ConcatVertTestFluid, ConcatVertTest,
+ Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
+ Values(cv::Size(1280, 720),
+ cv::Size(640, 480),
+ cv::Size(128, 128)),
+ Values(-1),
+ Values(CORE_FLUID)));
+
INSTANTIATE_TEST_CASE_P(Split3TestFluid, Split3Test,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
Values(CV_8UC4),
Values(CORE_FLUID)));
+INSTANTIATE_TEST_CASE_P(DISABLED_RemapTestFluid, RemapTest,
+ Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
+ Values(cv::Size(1280, 720),
+ cv::Size(640, 480),
+ cv::Size(128, 128)),
+ Values(-1),
+ Values(CORE_FLUID)));
+
+INSTANTIATE_TEST_CASE_P(DISABLED_FlipTestFluid, FlipTest,
+ Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
+ Values(cv::Size(1280, 720),
+ cv::Size(640, 480),
+ cv::Size(128, 128)),
+ Values(-1),
+ Values(CORE_FLUID),
+ Values(0,1,-1)));
+
+INSTANTIATE_TEST_CASE_P(DISABLED_CropTestFluid, CropTest,
+ Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
+ Values(cv::Size(1280, 720),
+ cv::Size(640, 480),
+ cv::Size(128, 128)),
+ Values(-1),
+ Values(CORE_FLUID),
+ Values(cv::Rect(10, 8, 20, 35), cv::Rect(4, 10, 37, 50))));
+
INSTANTIATE_TEST_CASE_P(SelectTestFluid, SelectTest,
Combine(Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1920, 1080),
cv::Scalar(100, 100, 100, 100),
cv::Scalar(255, 255, 255, 255))));
+INSTANTIATE_TEST_CASE_P(DISABLED_ThresholdTestFluid, ThresholdOTTest,
+ Combine(Values(CV_8UC1),
+ Values(cv::Size(1280, 720),
+ cv::Size(640, 480),
+ cv::Size(128, 128)),
+ Values(-1),
+ Values(CORE_FLUID),
+ Values(cv::THRESH_OTSU, cv::THRESH_TRIANGLE)));
+
INSTANTIATE_TEST_CASE_P(InRangeTestFluid, InRangeTest,
Combine(Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1920, 1080),
cv::Size(64, 64),
cv::Size(30, 30))));
+INSTANTIATE_TEST_CASE_P(ResizeTestFxFyFluid, ResizeTestFxFy,
+ Combine(Values(CV_8UC3/*CV_8UC1, CV_16UC1, CV_16SC1*/),
+ Values(cv::Size(1280, 720),
+ cv::Size(640, 480),
+ cv::Size(128, 128),
+ cv::Size(64, 64),
+ cv::Size(30, 30)),
+ Values(-1),
+ Values(CORE_FLUID),
+ Values(AbsExact().to_compare_obj()),
+ Values(/*cv::INTER_NEAREST,*/ cv::INTER_LINEAR/*, cv::INTER_AREA*/),
+ Values(0.5, 1, 2),
+ Values(0.5, 1, 2)));
+
INSTANTIATE_TEST_CASE_P(BackendOutputAllocationTestFluid, BackendOutputAllocationTest,
Combine(Values(CV_8UC3, CV_16SC2, CV_32FC1),
Values(cv::Size(50, 50)),
cv::Size(128, 128)),
Values(-1),
Values(CORE_FLUID)));
-
-//----------------------------------------------------------------------
-// FIXME: Clean-up test configurations which are enabled already
-#if 0
-INSTANTIATE_TEST_CASE_P(MathOpTestCPU, MathOpTest,
- Combine(Values(ADD, DIV, MUL),
- testing::Bool(),
- Values(CV_8UC1, CV_16SC1, CV_32FC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
- Values(-1, CV_8U, CV_32F),
-/*init output matrices or not*/ testing::Bool(),
- Values(false)));
-
-INSTANTIATE_TEST_CASE_P(SubTestCPU, MathOpTest,
- Combine(Values(SUB),
- testing::Bool(),
- Values(CV_8UC1, CV_16SC1 , CV_32FC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
- Values(-1, CV_8U, CV_32F),
-/*init output matrices or not*/ testing::Bool(),
- testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(MulSTestCPU, MulSTest,
- Combine(Values(CV_8UC1, CV_16SC1, CV_32FC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
-/*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(DivCTestCPU, DivCTest,
- Combine(Values(CV_8UC1, CV_16SC1, CV_32FC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
- Values(CV_8U, CV_32F),
-/*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(MeanTestCPU, MeanTest,
- Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
-/*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(SelectTestCPU, SelectTest,
- Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
-/*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(Polar2CartCPU, Polar2CartTest,
- Combine(Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
-/*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(Cart2PolarCPU, Cart2PolarTest,
- Combine(Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
-/*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(CompareTestCPU, CmpTest,
- Combine(Values(CMP_EQ, CMP_GE, CMP_NE, CMP_GT, CMP_LT, CMP_LE),
- testing::Bool(),
- Values(CV_8UC1, CV_16SC1, CV_32FC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
-/*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(BitwiseTestCPU, BitwiseTest,
- Combine(Values(AND, OR, XOR),
- Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
-/*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(BitwiseNotTestCPU, NotTest,
- Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
- /*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(MinTestCPU, MinTest,
- Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
-/*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(MaxTestCPU, MaxTest,
- Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
-/*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(SumTestCPU, SumTest,
- Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
-/*init output matrices or not*/ testing::Bool())
- Values(0.0),
- );
-
-INSTANTIATE_TEST_CASE_P(AbsDiffTestCPU, AbsDiffTest,
- Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
-/*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(AbsDiffCTestCPU, AbsDiffCTest,
- Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
-/*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(AddWeightedTestCPU, AddWeightedTest,
- Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
- Values(-1, CV_8U, CV_32F),
-/*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(NormTestCPU, NormTest,
- Combine(Values(NORM_INF, NORM_L1, NORM_L2),
- Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128))),
- Values(0.0));
-
-INSTANTIATE_TEST_CASE_P(IntegralTestCPU, IntegralTest,
- Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128))));
-
-INSTANTIATE_TEST_CASE_P(ThresholdTestCPU, ThresholdTest,
- Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
- Values(cv::THRESH_BINARY, cv::THRESH_BINARY_INV, cv::THRESH_TRUNC, cv::THRESH_TOZERO, cv::THRESH_TOZERO_INV),
-/*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(ThresholdTestCPU, ThresholdOTTest,
- Combine(Values(CV_8UC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
- Values(cv::THRESH_OTSU, cv::THRESH_TRIANGLE),
-/*init output matrices or not*/ testing::Bool()));
-
-
-INSTANTIATE_TEST_CASE_P(InRangeTestCPU, InRangeTest,
- Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
-/*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(Split3TestCPU, Split3Test,
- (Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128))));
-
-INSTANTIATE_TEST_CASE_P(Split4TestCPU, Split4Test,
- (Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128))));
-
-INSTANTIATE_TEST_CASE_P(Merge3TestCPU, Merge3Test,
- (Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128))));
-
-INSTANTIATE_TEST_CASE_P(Merge4TestCPU, Merge4Test,
- (Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128))));
-
-INSTANTIATE_TEST_CASE_P(RemapTestCPU, RemapTest,
- Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
-/*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(FlipTestCPU, FlipTest,
- Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(0,1,-1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
-/*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(CropTestCPU, CropTest,
- Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(cv::Rect(10, 8, 20, 35), cv::Rect(4, 10, 37, 50)),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
-/*init output matrices or not*/ testing::Bool()));
-
-INSTANTIATE_TEST_CASE_P(LUTTestCPU, LUTTest,
- Combine(Values(CV_8UC1, CV_8UC3),
- Values(CV_8UC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
-/*init output matrices or not*/ Values(true)));
-
-INSTANTIATE_TEST_CASE_P(LUTTestCustomCPU, LUTTest,
- Combine(Values(CV_8UC3),
- Values(CV_8UC3),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128)),
-/*init output matrices or not*/ Values(true)));
-
-// PLEASE DO NOT PUT NEW ACCURACY TESTS BELOW THIS POINT! //////////////////////
-
-INSTANTIATE_TEST_CASE_P(ConvertToCPU, ConvertToTest,
- Combine(Values(CV_8UC3, CV_8UC1, CV_16UC1, CV_32FC1),
- Values(CV_8U, CV_16U, CV_32F),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128))));
-
-INSTANTIATE_TEST_CASE_P(ConcatHorTestCPU, ConcatHorTest,
- Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128))));
-INSTANTIATE_TEST_CASE_P(ConcatVertTestCPU, ConcatVertTest,
- Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
- Values(cv::Size(1280, 720),
- cv::Size(640, 480),
- cv::Size(128, 128))));
-
-//----------------------------------------------------------------------
-#endif // 0
-
}
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018-2019 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
#include "../test_precomp.hpp"
namespace
{
-#define IMGPROC_CPU [] () { return cv::compile_args(cv::gapi::imgproc::cpu::kernels()); }
+#define IMGPROC_CPU [] () { return cv::compile_args(cv::gapi::use_only{cv::gapi::imgproc::cpu::kernels()}); }
} // anonymous namespace
namespace opencv_test
Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT),
Values(0, 1, 255)));
+INSTANTIATE_TEST_CASE_P(LaplacianTestCPU, LaplacianTest,
+ Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
+ Values(cv::Size(1280, 720),
+ cv::Size(640, 480)),
+ Values(-1),
+ Values(IMGPROC_CPU),
+ Values(AbsExact().to_compare_obj()),
+ Values(1, 3),
+ Values(0.2, 1.0),
+ Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT)));
+
+INSTANTIATE_TEST_CASE_P(BilateralFilterTestCPU, BilateralFilterTest,
+ Combine(Values(CV_32FC1, CV_32FC3, CV_8UC1, CV_8UC3),
+ Values(cv::Size(1280, 720),
+ cv::Size(640, 480)),
+ Values(-1),
+ Values(IMGPROC_CPU),
+ Values(AbsExact().to_compare_obj()),
+ Values(3, 5),
+ Values(20),
+ Values(10),
+ Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT)));
+
INSTANTIATE_TEST_CASE_P(EqHistTestCPU, EqHistTest,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
Values(3, 5),
testing::Bool()));
+INSTANTIATE_TEST_CASE_P(GoodFeaturesTestCPU, GoodFeaturesTest,
+ Combine(Values(IMGPROC_CPU),
+ Values(AbsExactVector<cv::Point2f>().to_compare_obj()),
+ Values("cv/shared/fruits.png"),
+ Values(CV_32FC1, CV_8UC1),
+ Values(50, 100),
+ Values(0.01),
+ Values(10.0),
+ Values(3),
+ testing::Bool()));
+
+INSTANTIATE_TEST_CASE_P(GoodFeaturesInternalTestCPU, GoodFeaturesTest,
+ Combine(Values(IMGPROC_CPU),
+ Values(AbsExactVector<cv::Point2f>().to_compare_obj()),
+ Values("cv/cascadeandhog/images/audrybt1.png"),
+ Values(CV_32FC1, CV_8UC1),
+ Values(100),
+ Values(0.0000001),
+ Values(5.0),
+ Values(3),
+ Values(true)));
+
+
INSTANTIATE_TEST_CASE_P(RGB2GrayTestCPU, RGB2GrayTest,
Combine(Values(CV_8UC3),
Values(cv::Size(1280, 720),
namespace
{
-#define IMGPROC_FLUID [] () { return cv::compile_args(cv::gapi::imgproc::fluid::kernels()); }
+#define IMGPROC_FLUID [] () { return cv::compile_args(cv::gapi::use_only{cv::gapi::imgproc::fluid::kernels()}); }
} // anonymous namespace
namespace opencv_test
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#ifndef OPENCV_GAPI_OCV_STATEFUL_KERNEL_TESTS_UTILS_HPP
+#define OPENCV_GAPI_OCV_STATEFUL_KERNEL_TESTS_UTILS_HPP
+
+#include "../test_precomp.hpp"
+
+// TODO: Reuse Anatoliy's logic for support of types with commas in macro.
+// Retrieve the common part from Anatoliy's logic to the separate place.
+#define DEFINE_INITIALIZER(Name, StateType, ...) \
+struct Name \
+{ \
+ static StateType value() \
+ { \
+ return __VA_ARGS__; \
+ } \
+} \
+
+namespace opencv_test
+{
+namespace
+{
+struct UserStruct
+{
+ UserStruct() = default;
+ UserStruct(short myShortVal, float myFloatVal):
+ _myShortVal(myShortVal),
+ _myFloatVal(myFloatVal) { }
+
+ bool operator==(const UserStruct& rhs) const
+ {
+ return ((_myShortVal == rhs._myShortVal) &&
+ (_myFloatVal == rhs._myFloatVal));
+ }
+
+private:
+ short _myShortVal;
+ float _myFloatVal;
+};
+} // anonymous namespace
+} // opencv_test
+
+#endif // OPENCV_GAPI_OCV_STATEFUL_KERNEL_TESTS_UTILS_HPP
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#include "gapi_ocv_stateful_kernel_test_utils.hpp"
+#include <opencv2/gapi/cpu/core.hpp>
+#include <opencv2/gapi/streaming/cap.hpp>
+
+#include <opencv2/core.hpp>
+#include <opencv2/core/cvstd.hpp>
+#include <opencv2/video.hpp>
+
+
+namespace opencv_test
+{
+ struct BackSubStateParams
+ {
+ std::string method;
+ };
+}
+
+namespace cv
+{
+ namespace detail
+ {
+ template<> struct CompileArgTag<opencv_test::BackSubStateParams>
+ {
+ static const char* tag()
+ {
+ return "org.opencv.test..background_substractor_state_params";
+ }
+ };
+ }
+}
+
+namespace opencv_test
+{
+//TODO: test OT, Background Subtractor, Kalman with 3rd version of API
+//----------------------------------------------- Simple tests ------------------------------------------------
+namespace
+{
+ inline void initTestDataPath()
+ {
+#ifndef WINRT
+ static bool initialized = false;
+ if (!initialized)
+ {
+ // Since G-API has no own test data (yet), it is taken from the common space
+ const char* testDataPath = getenv("OPENCV_TEST_DATA_PATH");
+ GAPI_Assert(testDataPath != nullptr);
+
+ cvtest::addDataSearchPath(testDataPath);
+ initialized = true;
+ }
+#endif // WINRT
+ }
+
+ G_TYPED_KERNEL(GCountCalls, <cv::GOpaque<int>(GMat)>, "org.opencv.test.count_calls")
+ {
+ static GOpaqueDesc outMeta(GMatDesc /* in */) { return empty_gopaque_desc(); }
+ };
+
+ GAPI_OCV_KERNEL_ST(GOCVCountCalls, GCountCalls, int)
+ {
+ static void setup(const cv::GMatDesc &/* in */, std::shared_ptr<int> &state)
+ {
+ state.reset(new int{ });
+ }
+
+ static void run(const cv::Mat &/* in */, int &out, int& state)
+ {
+ out = ++state;
+ }
+ };
+
+ G_TYPED_KERNEL(GIsStateUpToDate, <cv::GOpaque<bool>(GMat)>,
+ "org.opencv.test.is_state_up-to-date")
+ {
+ static GOpaqueDesc outMeta(GMatDesc /* in */) { return empty_gopaque_desc(); }
+ };
+
+ GAPI_OCV_KERNEL_ST(GOCVIsStateUpToDate, GIsStateUpToDate, cv::Size)
+ {
+ static void setup(const cv::GMatDesc &in, std::shared_ptr<cv::Size> &state)
+ {
+ state.reset(new cv::Size(in.size));
+ }
+
+ static void run(const cv::Mat &in , bool &out, cv::Size& state)
+ {
+ out = in.size() == state;
+ }
+ };
+
+ G_TYPED_KERNEL(GStInvalidResize, <GMat(GMat,Size,double,double,int)>,
+ "org.opencv.test.st_invalid_resize")
+ {
+ static GMatDesc outMeta(GMatDesc in, Size, double, double, int) { return in; }
+ };
+
+ GAPI_OCV_KERNEL_ST(GOCVStInvalidResize, GStInvalidResize, int)
+ {
+ static void setup(const cv::GMatDesc, cv::Size, double, double, int,
+ std::shared_ptr<int> &/* state */)
+ { }
+
+ static void run(const cv::Mat& in, cv::Size sz, double fx, double fy, int interp,
+ cv::Mat &out, int& /* state */)
+ {
+ cv::resize(in, out, sz, fx, fy, interp);
+ }
+ };
+
+ G_TYPED_KERNEL(GBackSub, <GMat(GMat)>, "org.opencv.test.background_substractor")
+ {
+ static GMatDesc outMeta(GMatDesc in) { return in.withType(CV_8U, 1); }
+ };
+
+ GAPI_OCV_KERNEL_ST(GOCVBackSub, GBackSub, cv::BackgroundSubtractor)
+ {
+ static void setup(const cv::GMatDesc &/* desc */,
+ std::shared_ptr<BackgroundSubtractor> &state,
+ const cv::GCompileArgs &compileArgs)
+ {
+ auto sbParams = cv::gapi::getCompileArg<BackSubStateParams>(compileArgs)
+ .value_or(BackSubStateParams { });
+
+ if (sbParams.method == "knn")
+ state = createBackgroundSubtractorKNN();
+ else if (sbParams.method == "mog2")
+ state = createBackgroundSubtractorMOG2();
+
+ GAPI_Assert(state);
+ }
+
+ static void run(const cv::Mat& in, cv::Mat &out, BackgroundSubtractor& state)
+ {
+ state.apply(in, out, -1);
+ }
+ };
+};
+
+TEST(StatefulKernel, StateIsMutableInRuntime)
+{
+ constexpr int expectedCallsCount = 10;
+
+ cv::Mat dummyIn { 1, 1, CV_8UC1 };
+ int actualCallsCount = 0;
+
+ // Declaration of G-API expression
+ GMat in;
+ GOpaque<int> out = GCountCalls::on(in);
+ cv::GComputation comp(cv::GIn(in), cv::GOut(out));
+
+ const auto pkg = cv::gapi::kernels<GOCVCountCalls>();
+
+ // Compilation of G-API expression
+ auto callsCounter = comp.compile(cv::descr_of(dummyIn), cv::compile_args(pkg));
+
+ // Simulating video stream: call GCompiled multiple times
+ for (int i = 0; i < expectedCallsCount; i++)
+ {
+ callsCounter(cv::gin(dummyIn), cv::gout(actualCallsCount));
+ EXPECT_EQ(i + 1, actualCallsCount);
+ }
+
+ // End of "video stream"
+ EXPECT_EQ(expectedCallsCount, actualCallsCount);
+
+ // User asks G-API to prepare for a new stream
+ callsCounter.prepareForNewStream();
+ callsCounter(cv::gin(dummyIn), cv::gout(actualCallsCount));
+ EXPECT_EQ(1, actualCallsCount);
+
+}
+
+TEST(StatefulKernel, StateIsAutoResetForNewStream)
+{
+ initTestDataPath();
+
+ cv::GMat in;
+ cv::GOpaque<bool> out = GIsStateUpToDate::on(in);
+ cv::GComputation c(cv::GIn(in), cv::GOut(out));
+
+ const auto pkg = cv::gapi::kernels<GOCVIsStateUpToDate>();
+
+ // Compilation & testing
+ auto ccomp = c.compileStreaming(cv::compile_args(pkg));
+
+ ccomp.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>
+ (findDataFile("cv/video/768x576.avi")));
+ ccomp.start();
+ EXPECT_TRUE(ccomp.running());
+
+ // Process the full video
+ bool isStateUpToDate = false;
+ while (ccomp.pull(cv::gout(isStateUpToDate))) {
+ EXPECT_TRUE(isStateUpToDate);
+ }
+ EXPECT_FALSE(ccomp.running());
+
+ ccomp.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>
+ (findDataFile("cv/video/1920x1080.avi")));
+ ccomp.start();
+ EXPECT_TRUE(ccomp.running());
+
+ while (ccomp.pull(cv::gout(isStateUpToDate))) {
+ EXPECT_TRUE(isStateUpToDate);
+ }
+ EXPECT_FALSE(ccomp.running());
+}
+
+TEST(StatefulKernel, InvalidReallocatingKernel)
+{
+ cv::GMat in, out;
+ cv::Mat in_mat(500, 500, CV_8UC1), out_mat;
+ out = GStInvalidResize::on(in, cv::Size(300, 300), 0.0, 0.0, cv::INTER_LINEAR);
+
+ const auto pkg = cv::gapi::kernels<GOCVStInvalidResize>();
+ cv::GComputation comp(cv::GIn(in), cv::GOut(out));
+
+ EXPECT_THROW(comp.apply(in_mat, out_mat, cv::compile_args(pkg)), std::logic_error);
+}
+
+namespace
+{
+ void compareBackSubResults(const cv::Mat &actual, const cv::Mat &expected,
+ const int diffPercent)
+ {
+ GAPI_Assert(actual.size() == expected.size());
+ int allowedNumDiffPixels = actual.size().area() * diffPercent / 100;
+
+ cv::Mat diff;
+ cv::absdiff(actual, expected, diff);
+
+ cv::Mat hist(256, 1, CV_32FC1, cv::Scalar(0));
+ const float range[] { 0, 256 };
+ const float *histRange { range };
+ calcHist(&diff, 1, 0, Mat(), hist, 1, &hist.rows, &histRange, true, false);
+ for (int i = 2; i < hist.rows; ++i)
+ {
+ hist.at<float>(i) += hist.at<float>(i - 1);
+ }
+
+ int numDiffPixels = static_cast<int>(hist.at<float>(255));
+
+ EXPECT_GT(allowedNumDiffPixels, numDiffPixels);
+ }
+} // anonymous namespace
+
+TEST(StatefulKernel, StateIsInitViaCompArgs)
+{
+ cv::Mat frame(1080, 1920, CV_8UC3),
+ gapiForeground,
+ ocvForeground;
+
+ cv::randu(frame, cv::Scalar(0, 0, 0), cv::Scalar(255, 255, 255));
+
+ // G-API code
+ cv::GMat in;
+ cv::GMat out = GBackSub::on(in);
+ cv::GComputation c(cv::GIn(in), cv::GOut(out));
+
+ const auto pkg = cv::gapi::kernels<GOCVBackSub>();
+
+ auto gapiBackSub = c.compile(cv::descr_of(frame),
+ cv::compile_args(pkg, BackSubStateParams { "knn" }));
+
+ gapiBackSub(cv::gin(frame), cv::gout(gapiForeground));
+
+ // OpenCV code
+ auto pOcvBackSub = createBackgroundSubtractorKNN();
+ pOcvBackSub->apply(frame, ocvForeground);
+
+ // Comparison
+ // Allowing 1% difference of all pixels between G-API and OpenCV results
+ compareBackSubResults(gapiForeground, ocvForeground, 1);
+
+ // Additionally, test the case where state is resetted
+ gapiBackSub.prepareForNewStream();
+ gapiBackSub(cv::gin(frame), cv::gout(gapiForeground));
+ pOcvBackSub->apply(frame, ocvForeground);
+ compareBackSubResults(gapiForeground, ocvForeground, 1);
+}
+
+namespace
+{
+ void testBackSubInStreaming(cv::GStreamingCompiled gapiBackSub, const int diffPercent)
+ {
+ cv::Mat frame,
+ gapiForeground,
+ ocvForeground;
+
+ gapiBackSub.start();
+ EXPECT_TRUE(gapiBackSub.running());
+
+ // OpenCV reference substractor
+ auto pOCVBackSub = createBackgroundSubtractorKNN();
+
+ // Comparison of G-API and OpenCV substractors
+ std::size_t frames = 0u;
+ while (gapiBackSub.pull(cv::gout(frame, gapiForeground))) {
+ pOCVBackSub->apply(frame, ocvForeground, -1);
+
+ compareBackSubResults(gapiForeground, ocvForeground, diffPercent);
+
+ frames++;
+ }
+ EXPECT_LT(0u, frames);
+ EXPECT_FALSE(gapiBackSub.running());
+ }
+} // anonymous namespace
+
+TEST(StatefulKernel, StateIsInitViaCompArgsInStreaming)
+{
+ initTestDataPath();
+
+ // G-API graph declaration
+ cv::GMat in;
+ cv::GMat out = GBackSub::on(in);
+ // Preserving 'in' in output to have possibility to compare with OpenCV reference
+ cv::GComputation c(cv::GIn(in), cv::GOut(cv::gapi::copy(in), out));
+
+ // G-API compilation of graph for streaming mode
+ const auto pkg = cv::gapi::kernels<GOCVBackSub>();
+ auto gapiBackSub = c.compileStreaming(
+ cv::compile_args(pkg, BackSubStateParams { "knn" }));
+
+ // Testing G-API Background Substractor in streaming mode
+ gapiBackSub.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>
+ (findDataFile("cv/video/768x576.avi")));
+ // Allowing 1% difference of all pixels between G-API and reference OpenCV results
+ testBackSubInStreaming(gapiBackSub, 1);
+
+ // Additionally, test the case when the new stream happens
+ gapiBackSub.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>
+ (findDataFile("cv/video/1920x1080.avi")));
+ // Allowing 5% difference of all pixels between G-API and reference OpenCV results
+ testBackSubInStreaming(gapiBackSub, 5);
+}
+//-------------------------------------------------------------------------------------------------------------
+
+
+//------------------------------------------- Typed tests on setup() ------------------------------------------
+namespace
+{
+template<typename Tuple>
+struct SetupStateTypedTest : public ::testing::Test
+{
+ using StateT = typename std::tuple_element<0, Tuple>::type;
+ using SetupT = typename std::tuple_element<1, Tuple>::type;
+
+ G_TYPED_KERNEL(GReturnState, <cv::GOpaque<StateT>(GMat)>, "org.opencv.test.return_state")
+ {
+ static GOpaqueDesc outMeta(GMatDesc /* in */) { return empty_gopaque_desc(); }
+ };
+
+ GAPI_OCV_KERNEL_ST(GOCVReturnState, GReturnState, StateT)
+ {
+ static void setup(const cv::GMatDesc &/* in */, std::shared_ptr<StateT> &state)
+ {
+ // Don't use input cv::GMatDesc intentionally
+ state.reset(new StateT(SetupT::value()));
+ }
+
+ static void run(const cv::Mat &/* in */, StateT &out, StateT& state)
+ {
+ out = state;
+ }
+ };
+};
+
+TYPED_TEST_CASE_P(SetupStateTypedTest);
+} // namespace
+
+
+TYPED_TEST_P(SetupStateTypedTest, ReturnInitializedState)
+{
+ using StateType = typename TestFixture::StateT;
+ using SetupType = typename TestFixture::SetupT;
+
+ cv::Mat dummyIn { 1, 1, CV_8UC1 };
+ StateType retState { };
+
+ GMat in;
+ auto out = TestFixture::GReturnState::on(in);
+ cv::GComputation comp(cv::GIn(in), cv::GOut(out));
+
+ const auto pkg = cv::gapi::kernels<typename TestFixture::GOCVReturnState>();
+ comp.apply(cv::gin(dummyIn), cv::gout(retState), cv::compile_args(pkg));
+
+ EXPECT_EQ(SetupType::value(), retState);
+}
+
+REGISTER_TYPED_TEST_CASE_P(SetupStateTypedTest,
+ ReturnInitializedState);
+
+
+DEFINE_INITIALIZER(CharValue, char, 'z');
+DEFINE_INITIALIZER(IntValue, int, 7);
+DEFINE_INITIALIZER(FloatValue, float, 42.f);
+DEFINE_INITIALIZER(UcharPtrValue, uchar*, nullptr);
+namespace
+{
+using Std3IntArray = std::array<int, 3>;
+}
+DEFINE_INITIALIZER(StdArrayValue, Std3IntArray, { 1, 2, 3 });
+DEFINE_INITIALIZER(UserValue, UserStruct, { 5, 7.f });
+
+using TypesToVerify = ::testing::Types<std::tuple<char, CharValue>,
+ std::tuple<int, IntValue>,
+ std::tuple<float, FloatValue>,
+ std::tuple<uchar*, UcharPtrValue>,
+ std::tuple<std::array<int, 3>, StdArrayValue>,
+ std::tuple<UserStruct, UserValue>>;
+
+INSTANTIATE_TYPED_TEST_CASE_P(SetupStateTypedInst, SetupStateTypedTest, TypesToVerify);
+//-------------------------------------------------------------------------------------------------------------
+
+} // opencv_test
namespace
{
-#define CORE_CPU [] () { return cv::compile_args(cv::gapi::core::cpu::kernels()); }
+#define CORE_CPU [] () { return cv::compile_args(cv::gapi::use_only{cv::gapi::core::cpu::kernels()}); }
} // anonymous namespace
namespace opencv_test
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
- Values(-1, CV_8U, CV_32F),
+ Values(-1),
Values(CORE_CPU),
Values(AbsExact().to_compare_obj()),
- Values( opPlusM, opMinusM, opDivM,
- opGreater, opLess, opGreaterEq, opLessEq, opEq, opNotEq)));
+ Values( ADD, SUB, DIV,
+ GT, LT, GE, LE, EQ, NE)));
INSTANTIATE_TEST_CASE_P(MathOperatorTestCPU, MathOperatorMatScalarTest,
Combine(Values(CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
- Values(-1, CV_8U, CV_32F),
+ Values(-1),
Values(CORE_CPU),
Values(AbsExact().to_compare_obj()),
- Values( opPlus, opPlusR, opMinus, opMinusR, opMul, opMulR, // FIXIT avoid division by values near zero: opDiv, opDivR,
- opGT, opLT, opGE, opLE, opEQ, opNE,
- opGTR, opLTR, opGER, opLER, opEQR, opNER)));
+ Values( ADD, SUB, MUL, DIV,
+ ADDR, SUBR, MULR, DIVR,
+ GT, LT, GE, LE, EQ, NE,
+ GTR, LTR, GER, LER, EQR, NER)));
INSTANTIATE_TEST_CASE_P(BitwiseOperatorTestCPU, MathOperatorMatMatTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(-1),
Values(CORE_CPU),
Values(AbsExact().to_compare_obj()),
- Values( opAnd, opOr, opXor )));
+ Values( AND, OR, XOR )));
INSTANTIATE_TEST_CASE_P(BitwiseOperatorTestCPU, MathOperatorMatScalarTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(-1),
Values(CORE_CPU),
Values(AbsExact().to_compare_obj()),
- Values( opAND, opOR, opXOR, opANDR, opORR, opXORR )));
+ Values( AND, OR, XOR,
+ ANDR, ORR, XORR )));
INSTANTIATE_TEST_CASE_P(BitwiseNotOperatorTestCPU, NotOperatorTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
namespace
{
-#define CORE_FLUID [] () { return cv::compile_args(cv::gapi::core::fluid::kernels()); }
+#define CORE_FLUID [] () { return cv::compile_args(cv::gapi::use_only{cv::gapi::core::fluid::kernels()}); }
} // anonymous namespace
namespace opencv_test
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
- Values(-1, CV_8U, CV_32F),
+ Values(-1),
Values(CORE_FLUID),
Values(AbsExact().to_compare_obj()),
- Values( opPlusM, opMinusM, opDivM,
- opGreater, opLess, opGreaterEq, opLessEq, opEq, opNotEq)));
+ Values( ADD, SUB, DIV,
+ GT, LT, GE, LE, EQ, NE)));
-//FIXME: Some Mat/Scalar Fluid kernels are not there yet!
-INSTANTIATE_TEST_CASE_P(DISABLED_MathOperatorTestFluid, MathOperatorMatScalarTest,
+INSTANTIATE_TEST_CASE_P(MathOperatorArithmeticTestFluid, MathOperatorMatScalarTest,
Combine(Values(CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
- Values(-1, CV_8U, CV_32F),
+ Values(-1),
Values(CORE_FLUID),
Values(AbsExact().to_compare_obj()),
- Values( opPlus, opPlusR, opMinus, opMinusR, opMul, opMulR, // FIXIT avoid division by values near zero: opDiv, opDivR,
- opGT, opLT, opGE, opLE, opEQ, opNE,
- opGTR, opLTR, opGER, opLER, opEQR, opNER)));
+ Values( ADD, SUB, MUL, DIV,
+ ADDR, SUBR, MULR, DIVR)));
+
+ // FIXME: solve comparison error
+INSTANTIATE_TEST_CASE_P(MathOperatorCompareTestFluid, MathOperatorMatScalarTest,
+ Combine(Values(CV_8UC1, CV_16SC1, CV_32FC1),
+ Values(cv::Size(1280, 720),
+ cv::Size(640, 480),
+ cv::Size(128, 128)),
+ Values(-1),
+ Values(CORE_FLUID),
+ Values(AbsSimilarPoints(1, 0.01).to_compare_obj()),
+ Values( GT, LT, GE, LE, EQ, NE,
+ GTR, LTR, GER, LER, EQR, NER)));
INSTANTIATE_TEST_CASE_P(BitwiseOperatorTestFluid, MathOperatorMatMatTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(-1),
Values(CORE_FLUID),
Values(AbsExact().to_compare_obj()),
- Values( opAnd, opOr, opXor )));
+ Values( AND, OR, XOR )));
-//FIXME: Some Mat/Scalar Fluid kernels are not there yet!
-INSTANTIATE_TEST_CASE_P(DISABLED_BitwiseOperatorTestFluid, MathOperatorMatScalarTest,
+INSTANTIATE_TEST_CASE_P(BitwiseOperatorTestFluid, MathOperatorMatScalarTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
Values(-1),
Values(CORE_FLUID),
Values(AbsExact().to_compare_obj()),
- Values( opAND, opOR, opXOR, opANDR, opORR, opXORR )));
+ Values( AND, OR, XOR,
+ ANDR, ORR, XORR )));
INSTANTIATE_TEST_CASE_P(BitwiseNotOperatorTestFluid, NotOperatorTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#include "../test_precomp.hpp"
+
+#include "../common/gapi_video_tests.hpp"
+#include <opencv2/gapi/cpu/video.hpp>
+
+namespace
+{
+#define VIDEO_CPU [] () { return cv::compile_args(cv::gapi::video::cpu::kernels()); }
+
+#ifdef HAVE_OPENCV_VIDEO
+#define WITH_VIDEO(X) X
+#else
+#define WITH_VIDEO(X) DISABLED_##X
+#endif // HAVE_OPENCV_VIDEO
+
+#define INSTANTIATE_TEST_CASE_MACRO_P(prefix, test_case_name, generator, ...) \
+ INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, __VA_ARGS__)
+} // anonymous namespace
+
+namespace opencv_test
+{
+INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildOptFlowPyramidTestCPU), BuildOptFlowPyramidTest,
+ Combine(Values(VIDEO_CPU),
+ Values("cv/optflow/rock_1.bmp",
+ "cv/optflow/frames/1080p_01.png"),
+ Values(7, 11),
+ Values(1000),
+ testing::Bool(),
+ Values(BORDER_DEFAULT, BORDER_TRANSPARENT),
+ Values(BORDER_DEFAULT, BORDER_TRANSPARENT),
+ testing::Bool()));
+
+INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildOptFlowPyramidInternalTestCPU),
+ BuildOptFlowPyramidTest,
+ Combine(Values(VIDEO_CPU),
+ Values("cv/optflow/rock_1.bmp"),
+ Values(15),
+ Values(3),
+ Values(true),
+ Values(BORDER_REFLECT_101),
+ Values(BORDER_CONSTANT),
+ Values(true)));
+
+INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(OptFlowLKTestCPU), OptFlowLKTest,
+ Combine(Values(VIDEO_CPU),
+ Values("cv/optflow/rock_%01d.bmp",
+ "cv/optflow/frames/1080p_%02d.png"),
+ Values(1, 3, 4),
+ Values(std::make_tuple(9, 9), std::make_tuple(15, 15)),
+ Values(7, 11),
+ Values(cv::TermCriteria(cv::TermCriteria::COUNT |
+ cv::TermCriteria::EPS,
+ 30, 0.01))));
+
+INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(OptFlowLKTestForPyrCPU), OptFlowLKTestForPyr,
+ Combine(Values(VIDEO_CPU),
+ Values("cv/optflow/rock_%01d.bmp",
+ "cv/optflow/frames/1080p_%02d.png"),
+ Values(1, 3, 4),
+ Values(std::make_tuple(9, 9), std::make_tuple(15, 15)),
+ Values(7, 11),
+ Values(cv::TermCriteria(cv::TermCriteria::COUNT |
+ cv::TermCriteria::EPS,
+ 30, 0.01)),
+ testing::Bool()));
+
+INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(OptFlowLKInternalTestCPU), OptFlowLKTestForPyr,
+ Combine(Values(VIDEO_CPU),
+ Values("cv/optflow/rock_%01d.bmp"),
+ Values(1),
+ Values(std::make_tuple(10, 10)),
+ Values(15),
+ Values(cv::TermCriteria(cv::TermCriteria::COUNT |
+ cv::TermCriteria::EPS,
+ 21, 0.05)),
+ Values(true)));
+
+INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildPyr_CalcOptFlow_PipelineTestCPU),
+ BuildPyr_CalcOptFlow_PipelineTest,
+ Combine(Values(VIDEO_CPU),
+ Values("cv/optflow/frames/1080p_%02d.png"),
+ Values(7, 11),
+ Values(1000),
+ testing::Bool()));
+
+INSTANTIATE_TEST_CASE_MACRO_P(WITH_VIDEO(BuildPyr_CalcOptFlow_PipelineInternalTestCPU),
+ BuildPyr_CalcOptFlow_PipelineTest,
+ Combine(Values(VIDEO_CPU),
+ Values("cv/optflow/rock_%01d.bmp"),
+ Values(15),
+ Values(3),
+ Values(true)));
+} // opencv_test
{
static GScalarDesc outMeta(const GArrayDesc &) { return empty_scalar_desc(); }
};
+G_TYPED_KERNEL(PointIncrement, <GPointArray(GMat, GPointArray)>, "test.point_increment")
+{
+ static GArrayDesc outMeta(const GMatDesc&, const GArrayDesc&) { return empty_array_desc(); }
+};
} // namespace ThisTest
namespace
}
};
+GAPI_OCV_KERNEL(OCVPointIncrement, ThisTest::PointIncrement)
+{
+ static void run(const cv::Mat&, const std::vector<cv::Point>& in, std::vector<cv::Point>& out)
+ {
+ for (const auto& el : in)
+ out.emplace_back(el + Point(1,1));
+ }
+};
+
cv::Mat cross(int w, int h)
{
cv::Mat mat = cv::Mat::eye(h, w, CV_8UC1)*255;
EXPECT_EQ(10, out_count[0]);
}
+TEST(GArray, GArrayConstValInitialization)
+{
+ std::vector<cv::Point> initial_vec {Point(0,0), Point(1,1), Point(2,2)};
+ std::vector<cv::Point> ref_vec {Point(1,1), Point(2,2), Point(3,3)};
+ std::vector<cv::Point> out_vec;
+ cv::Mat in_mat;
+
+ cv::GComputationT<ThisTest::GPointArray(cv::GMat)> c([&](cv::GMat in)
+ {
+ // Initialization
+ ThisTest::GPointArray test_garray(initial_vec);
+ return ThisTest::PointIncrement::on(in, test_garray);
+ });
+ auto cc = c.compile(cv::descr_of(in_mat),
+ cv::compile_args(cv::gapi::kernels<OCVPointIncrement>()));
+ cc(in_mat, out_vec);
+
+ EXPECT_EQ(ref_vec, out_vec);
+}
+
+TEST(GArray, GArrayRValInitialization)
+{
+ std::vector<cv::Point> ref_vec {Point(1,1), Point(2,2), Point(3,3)};
+ std::vector<cv::Point> out_vec;
+ cv::Mat in_mat;
+
+ cv::GComputationT<ThisTest::GPointArray(cv::GMat)> c([&](cv::GMat in)
+ {
+ // Rvalue initialization
+ ThisTest::GPointArray test_garray({Point(0,0), Point(1,1), Point(2,2)});
+ return ThisTest::PointIncrement::on(in, test_garray);
+ });
+ auto cc = c.compile(cv::descr_of(in_mat),
+ cv::compile_args(cv::gapi::kernels<OCVPointIncrement>()));
+ cc(in_mat, out_vec);
+
+ EXPECT_EQ(ref_vec, out_vec);
+}
+
TEST(GArray_VectorRef, TestMov)
{
// Warning: this test is testing some not-very-public APIs
EXPECT_EQ(V{}, vref.rref<I>());
EXPECT_EQ(V{}, vtest);
}
+
+TEST(GArray_VectorRef, Kind)
+{
+ cv::detail::VectorRef v1(std::vector<cv::Rect>{});
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_RECT, v1.getKind());
+
+ cv::detail::VectorRef v2(std::vector<cv::Mat>{});
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_MAT, v2.getKind());
+
+ cv::detail::VectorRef v3(std::vector<int>{});
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_INT, v3.getKind());
+
+ cv::detail::VectorRef v4(std::vector<double>{});
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_DOUBLE, v4.getKind());
+
+ cv::detail::VectorRef v5(std::vector<cv::Scalar>{});
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_SCALAR, v5.getKind());
+
+ cv::detail::VectorRef v6(std::vector<cv::Point>{});
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_POINT, v6.getKind());
+
+ cv::detail::VectorRef v7(std::vector<cv::Size>{});
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_SIZE, v7.getKind());
+
+ cv::detail::VectorRef v8(std::vector<std::string>{});
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_UNKNOWN, v8.getKind());
+}
+
+TEST(GArray_VectorRef, TestRvalue)
+{
+ // Warning: this test is testing some not-very-public APIs
+ cv::detail::VectorRef vref(std::vector<int>{3, 5, -4});
+ auto v = std::vector<int>{3, 5, -4};
+ EXPECT_EQ(vref.rref<int>(), v);
+}
+
+TEST(GArray_VectorRef, TestReset)
+{
+ // Warning: this test is testing some not-very-public APIs
+ cv::detail::VectorRef vref(std::vector<int>{3, 5, -4});
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_INT, vref.getKind());
+ vref.reset<int>();
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_INT, vref.getKind());
+}
} // namespace opencv_test
for (auto&& arg : args){
//FIXME: replace this switch with use of visit() on variant, when it will be available
switch (arg.index()){
- #if !defined(GAPI_STANDALONE)
- case GRunArgP::index_of<cv::Mat*>() : result.emplace_back(*util::get<cv::Mat*>(arg)); break;
case GRunArgP::index_of<cv::UMat*>() : result.emplace_back(*util::get<cv::UMat*>(arg)); break;
- #endif // !defined(GAPI_STANDALONE)
- case GRunArgP::index_of<cv::gapi::own::Mat*>() : result.emplace_back(*util::get<cv::gapi::own::Mat*> (arg)); break;
+ case GRunArgP::index_of<cv::Mat*>() : result.emplace_back(*util::get<cv::Mat*>(arg)); break;
case GRunArgP::index_of<cv::Scalar*>() : result.emplace_back(*util::get<cv::Scalar*> (arg)); break;
case GRunArgP::index_of<cv::detail::VectorRef>() : result.emplace_back(util::get<cv::detail::VectorRef> (arg)); break;
default : ;
GRunArgsP result; result.reserve(args.size());
for (auto&& arg : args){
switch (arg.index()){
- #if !defined(GAPI_STANDALONE)
case GRunArg::index_of<cv::Mat>() : result.emplace_back(&util::get<cv::Mat>(arg)); break;
case GRunArg::index_of<cv::UMat>() : result.emplace_back(&util::get<cv::UMat>(arg)); break;
- #endif // !defined(GAPI_STANDALONE)
- case GRunArg::index_of<cv::gapi::own::Mat>() : result.emplace_back(&util::get<cv::gapi::own::Mat> (arg)); break;
case GRunArg::index_of<cv::Scalar>() : result.emplace_back(&util::get<cv::Scalar> (arg)); break;
case GRunArg::index_of<cv::detail::VectorRef>() : result.emplace_back(util::get<cv::detail::VectorRef> (arg)); break;
default : ;
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#include "test_precomp.hpp"
+
+namespace opencv_test
+{
+ struct CustomArg
+ {
+ int number;
+ };
+}
+
+namespace cv
+{
+ namespace detail
+ {
+ template<> struct CompileArgTag<opencv_test::CustomArg>
+ {
+ static const char* tag() { return "org.opencv.test.custom_arg"; }
+ };
+ }
+}
+
+
+namespace opencv_test
+{
+namespace
+{
+G_TYPED_KERNEL(GTestOp, <GMat(GMat)>, "org.opencv.test.test_op")
+{
+ static GMatDesc outMeta(GMatDesc in) { return in; }
+};
+
+GAPI_OCV_KERNEL(GOCVTestOp, GTestOp)
+{
+ static void run(const cv::Mat &/* in */, cv::Mat &/* out */) { }
+};
+} // anonymous namespace
+
+TEST(GetCompileArgTest, PredefinedArgs)
+{
+ cv::gapi::GKernelPackage pkg = cv::gapi::kernels<GOCVTestOp>();
+ cv::GCompileArg arg0 { pkg },
+ arg1 { cv::gapi::use_only { pkg } },
+ arg2 { cv::graph_dump_path { "fake_path" } };
+
+ GCompileArgs compArgs { arg0, arg1, arg2 };
+
+ auto kernelPkgOpt = cv::gapi::getCompileArg<cv::gapi::GKernelPackage>(compArgs);
+ GAPI_Assert(kernelPkgOpt.has_value());
+ EXPECT_NO_THROW(kernelPkgOpt.value().lookup("org.opencv.test.test_op"));
+
+ auto hasUseOnlyOpt = cv::gapi::getCompileArg<cv::gapi::use_only>(compArgs);
+ GAPI_Assert(hasUseOnlyOpt.has_value());
+ EXPECT_NO_THROW(hasUseOnlyOpt.value().pkg.lookup("org.opencv.test.test_op"));
+
+ auto dumpInfoOpt = cv::gapi::getCompileArg<cv::graph_dump_path>(compArgs);
+ GAPI_Assert(dumpInfoOpt.has_value());
+ EXPECT_EQ("fake_path", dumpInfoOpt.value().m_dump_path);
+}
+
+TEST(GetCompileArg, CustomArgs)
+{;
+ cv::GCompileArgs compArgs{ GCompileArg { CustomArg { 7 } } };
+
+ auto customArgOpt = cv::gapi::getCompileArg<CustomArg>(compArgs);
+ GAPI_Assert(customArgOpt.has_value());
+ EXPECT_EQ(7, customArgOpt.value().number);
+}
+} // namespace opencv_test
};
}
-TEST(GAPI_MetaDesc, MatDesc)
-{
- cv::Mat m1(240, 320, CV_8U);
- const auto desc1 = cv::descr_of(m1);
- EXPECT_EQ(CV_8U, desc1.depth);
- EXPECT_EQ(1, desc1.chan);
- EXPECT_EQ(320, desc1.size.width);
- EXPECT_EQ(240, desc1.size.height);
- EXPECT_FALSE(desc1.isND());
-
- cv::Mat m2(480, 640, CV_8UC3);
- const auto desc2 = cv::descr_of(m2);
- EXPECT_EQ(CV_8U, desc2.depth);
- EXPECT_EQ(3, desc2.chan);
- EXPECT_EQ(640, desc2.size.width);
- EXPECT_EQ(480, desc2.size.height);
- EXPECT_FALSE(desc2.isND());
+TEST(GAPI_MetaDesc, MatDescOneCh)
+{
+ cv::Mat mat(240, 320, CV_8U);
+
+ const auto desc = cv::descr_of(mat);
+
+ EXPECT_EQ(CV_8U, desc.depth);
+ EXPECT_EQ(1, desc.chan);
+ EXPECT_EQ(320, desc.size.width);
+ EXPECT_EQ(240, desc.size.height);
+ EXPECT_FALSE(desc.isND());
+}
+
+TEST(GAPI_MetaDesc, MatDescThreeCh)
+{
+ cv::Mat mat(480, 640, CV_8UC3);
+
+ const auto desc = cv::descr_of(mat);
+
+ EXPECT_EQ(CV_8U, desc.depth);
+ EXPECT_EQ(3, desc.chan);
+ EXPECT_EQ(640, desc.size.width);
+ EXPECT_EQ(480, desc.size.height);
+ EXPECT_FALSE(desc.isND());
}
TEST(GAPI_MetaDesc, MatDescND)
EXPECT_EQ((GMatDesc{CV_8U, 3, {640, 480}}), get<GMatDesc>(desc2[0]));
}
+TEST(GAPI_MetaDesc, CanDescribe)
+{
+ constexpr int w = 15;
+ constexpr int h = 7;
+ cv::Mat m0(h, w, CV_8UC3);
+ cv::GMatDesc md0{CV_8U,3,{w,h},false};
+
+ cv::Mat m1(h*3, w, CV_8UC1);
+ cv::GMatDesc md10{CV_8U,3,{w,h},true};
+ cv::GMatDesc md11{CV_8U,1,{w,h*3},false};
+
+ EXPECT_TRUE (md0 .canDescribe(m0));
+ EXPECT_FALSE(md0 .canDescribe(m1));
+ EXPECT_TRUE (md10.canDescribe(m1));
+ EXPECT_TRUE (md11.canDescribe(m1));
+}
+
+TEST(GAPI_MetaDesc, OwnMatDescOneCh)
+{
+ cv::gapi::own::Mat mat(240, 320, CV_8U, nullptr);
+
+ const auto desc = cv::gapi::own::descr_of(mat);
+
+ EXPECT_EQ(CV_8U, desc.depth);
+ EXPECT_EQ(1, desc.chan);
+ EXPECT_EQ(320, desc.size.width);
+ EXPECT_EQ(240, desc.size.height);
+ EXPECT_FALSE(desc.isND());
+}
+
+TEST(GAPI_MetaDesc, OwnMatDescThreeCh)
+{
+ cv::gapi::own::Mat mat(480, 640, CV_8UC3, nullptr);
+
+ const auto desc = cv::gapi::own::descr_of(mat);
+
+ EXPECT_EQ(CV_8U, desc.depth);
+ EXPECT_EQ(3, desc.chan);
+ EXPECT_EQ(640, desc.size.width);
+ EXPECT_EQ(480, desc.size.height);
+ EXPECT_FALSE(desc.isND());
+}
+
+TEST(GAPI_MetaDesc, OwnMatDescND)
+{
+ std::vector<int> dims = {1,3,224,224};
+ cv::gapi::own::Mat m(dims, CV_32F, nullptr);
+
+ const auto desc = cv::gapi::own::descr_of(m);
+
+ EXPECT_EQ(CV_32F, desc.depth);
+ EXPECT_EQ(-1, desc.chan);
+ EXPECT_EQ(1, desc.dims[0]);
+ EXPECT_EQ(3, desc.dims[1]);
+ EXPECT_EQ(224, desc.dims[2]);
+ EXPECT_EQ(224, desc.dims[3]);
+ EXPECT_TRUE(desc.isND());
+}
+
TEST(GAPI_MetaDesc, VecOwnMatDesc)
{
std::vector<cv::gapi::own::Mat> vec = {
cv::gapi::own::Mat(480, 640, CV_8UC3, nullptr)};
const auto desc = cv::gapi::own::descrs_of(vec);
+
EXPECT_EQ((GMatDesc{CV_8U, 1, {320, 240}}), get<GMatDesc>(desc[0]));
EXPECT_EQ((GMatDesc{CV_8U, 3, {640, 480}}), get<GMatDesc>(desc[1]));
}
cv::gapi::own::Mat(480, 640, CV_8UC3, nullptr)};
const auto desc = descrs_of(vec);
+
EXPECT_EQ((GMatDesc{CV_8U, 1, {320, 240}}), get<GMatDesc>(desc[0]));
EXPECT_EQ((GMatDesc{CV_8U, 3, {640, 480}}), get<GMatDesc>(desc[1]));
}
EXPECT_TRUE(desc1.asPlanar(3) == desc0);
}
-TEST(GAPI_MetaDesc, CanDescribe)
-{
- constexpr int w = 15;
- constexpr int h = 7;
- cv::Mat m0(h, w, CV_8UC3);
- cv::GMatDesc md0{CV_8U,3,{w,h},false};
-
- cv::Mat m1(h*3, w, CV_8UC1);
- cv::GMatDesc md10{CV_8U,3,{w,h},true};
- cv::GMatDesc md11{CV_8U,1,{w,h*3},false};
-
- EXPECT_TRUE (md0 .canDescribe(m0));
- EXPECT_FALSE(md0 .canDescribe(m1));
- EXPECT_TRUE (md10.canDescribe(m1));
- EXPECT_TRUE (md11.canDescribe(m1));
-}
-
} // namespace opencv_test
const cv::Size buffer_size = {8,8};
cv::Mat in_mat = cv::Mat::eye(buffer_size, CV_8U);
- cv::gapi::fluid::Buffer buffer(to_own(in_mat), true);
+ cv::gapi::fluid::Buffer buffer(in_mat, true);
cv::gapi::fluid::View view = buffer.mkView(0, false);
view.priv().allocate(1, {});
view.priv().reset(1);
const cv::Size buffer_size = {8,16};
cv::Mat out_mat = cv::Mat(buffer_size, CV_8U);
- cv::gapi::fluid::Buffer buffer(to_own(out_mat), false);
+ cv::gapi::fluid::Buffer buffer(out_mat, false);
int num_writes = 0;
while (num_writes < buffer_size.height)
{
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#include "test_precomp.hpp"
+
+#include <opencv2/gapi/cpu/gcpukernel.hpp>
+
+namespace opencv_test
+{
+
+G_API_OP(GBlurFrame, <GMat(GFrame)>, "test.blur_frame") {
+ static GMatDesc outMeta(GMatDesc in) {
+ return in;
+ }
+};
+
+GAPI_OCV_KERNEL(OCVBlurFrame, GBlurFrame) {
+ static void run(const cv::Mat& in, cv::Mat& out) {
+ cv::blur(in, out, cv::Size{3,3});
+ }
+};
+
+struct GFrameTest : public ::testing::Test {
+ cv::Size sz{32,32};
+ cv::Mat in_mat;
+ cv::Mat out_mat;
+ cv::Mat out_mat_ocv;
+
+ GFrameTest()
+ : in_mat(cv::Mat(sz, CV_8UC1))
+ , out_mat(cv::Mat::zeros(sz, CV_8UC1))
+ , out_mat_ocv(cv::Mat::zeros(sz, CV_8UC1)) {
+ cv::randn(in_mat, cv::Scalar::all(127.0f), cv::Scalar::all(40.f));
+ cv::blur(in_mat, out_mat_ocv, cv::Size{3,3});
+ }
+
+ void check() {
+ EXPECT_EQ(0, cvtest::norm(out_mat, out_mat_ocv, NORM_INF));
+ }
+};
+
+TEST_F(GFrameTest, Input) {
+ cv::GFrame in;
+ auto out = GBlurFrame::on(in);
+ cv::GComputation c(cv::GIn(in), cv::GOut(out));
+
+ auto pkg = cv::gapi::kernels<OCVBlurFrame>();
+ c.apply(cv::gin(in_mat), cv::gout(out_mat), cv::compile_args(pkg));
+
+ check();
+}
+
+} // namespace opencv_test
GAPI_FLUID_KERNEL(GClone, I::GClone, false)
{
static const int Window = 1;
- static void run(const cv::gapi::fluid::View&, cv::gapi::fluid::Buffer)
+ static void run(const cv::gapi::fluid::View&, cv::gapi::fluid::Buffer&)
{
HeteroGraph::registerCallKernel(KernelTags::FLUID_CUSTOM_CLONE);
}
EXPECT_EQ(painted, 77);
}
+TEST(GOpaque, TestOpaqueBetweenIslands)
+{
+ 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::gapi::island("test", cv::GIn(in), cv::GOut(betw));
+ 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);
EXPECT_EQ(test, ref.rref<I>()); // ref = test
EXPECT_NE(test, mov.rref<I>()); // ref lost the data
}
+
+TEST(GOpaque_OpaqueRef, Kind)
+{
+ cv::detail::OpaqueRef v1(cv::Rect{});
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_RECT, v1.getKind());
+
+ cv::detail::OpaqueRef v3(int{});
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_INT, v3.getKind());
+
+ cv::detail::OpaqueRef v4(double{});
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_DOUBLE, v4.getKind());
+
+ cv::detail::OpaqueRef v6(cv::Point{});
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_POINT, v6.getKind());
+
+ cv::detail::OpaqueRef v7(cv::Size{});
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_SIZE, v7.getKind());
+
+ cv::detail::OpaqueRef v8(std::string{});
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_UNKNOWN, v8.getKind());
+}
+
+TEST(GOpaque_OpaqueRef, TestReset)
+{
+ // Warning: this test is testing some not-very-public APIs
+ cv::detail::OpaqueRef opref(int{42});
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_INT, opref.getKind());
+ opref.reset<int>();
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_INT, opref.getKind());
+}
} // namespace opencv_test
// Copyright (C) 2019 Intel Corporation
-#ifdef HAVE_PLAIDML
-
#include "test_precomp.hpp"
#include <stdexcept>
namespace opencv_test
{
+#ifdef HAVE_PLAIDML
+
inline cv::gapi::plaidml::config getConfig()
{
auto read_var_from_env = [](const char* env)
EXPECT_EQ(0, cv::norm(out_mat[1], ref_mat[1]));
}
-} // namespace opencv_test
+#else // HAVE_PLAIDML
+
+TEST(GAPI_PlaidML_Pipelines, ThrowIfPlaidMLNotFound)
+{
+ ASSERT_ANY_THROW(cv::gapi::core::plaidml::kernels());
+}
#endif // HAVE_PLAIDML
+
+} // namespace opencv_test
EXPECT_THROW(comp.apply(in_mat, out_mat, cv::compile_args(pkg)), std::logic_error);
}
-TEST(GAPI_Pipeline, CanUseOwnMatAsOutput)
-{
- cv::GMat in;
- cv::GComputation comp(in, cv::gapi::bitwise_not(in));
-
- cv::Mat in_mat(3, 3, CV_8UC1);
- cv::Mat out_mat(3, 3, CV_8UC1);
-
- cv::gapi::own::Mat in_own_mat(in_mat.rows, in_mat.cols, CV_8UC1, in_mat.data);
- cv::gapi::own::Mat out_own_mat(out_mat.rows, out_mat.cols, CV_8UC1, out_mat.data);
-
- // FIXME add overload for apply(cv::gapi::own::Mat in, cv::gapi::own::Mat& out)
- EXPECT_NO_THROW(comp.apply({in_own_mat}, {out_own_mat}));
-}
-
TEST(GAPI_Pipeline, CreateKernelImplFromLambda)
{
cv::Size size(300, 300);
auto tr = gmat_gsc_garray_in_gmat2_out::transformation();
auto check = [](const cv::GComputation &comp){
- const auto &p = comp.priv();
+ const auto &p = cv::util::get<cv::GComputation::Priv::Expr>(comp.priv().m_shape);
EXPECT_EQ(3u, p.m_ins.size());
EXPECT_EQ(2u, p.m_outs.size());
auto tr = gmat_gsc_gopaque_in_gmat2_out::transformation();
auto check = [](const cv::GComputation &comp){
- const auto &p = comp.priv();
+ const auto &p = cv::util::get<cv::GComputation::Priv::Expr>(comp.priv().m_shape);
EXPECT_EQ(3u, p.m_ins.size());
EXPECT_EQ(2u, p.m_outs.size());
template<typename InType, typename OutType>
void args_check(const cv::GComputation &comp)
{
- const auto &p = comp.priv();
+ const auto &p = cv::util::get<cv::GComputation::Priv::Expr>(comp.priv().m_shape);
EXPECT_EQ(1u, p.m_ins.size());
EXPECT_EQ(1u, p.m_outs.size());
arg_check<InType>(p.m_ins[0]);
#include "test_precomp.hpp"
+#include "common/gapi_tests_common.hpp"
+
+namespace custom
+{
+G_TYPED_KERNEL(GKernelForGArrayGMatOut, <cv::GArray<cv::GMat>(cv::GMat)>,
+ "custom.test.kernelForGArrayGMatOut")
+{
+ static cv::GArrayDesc outMeta(const cv::GMatDesc&)
+ {
+ return cv::empty_array_desc();
+ }
+};
+
+GAPI_OCV_KERNEL(GCPUKernelForGArrayGMatOut, custom::GKernelForGArrayGMatOut)
+{
+ static void run(const cv::Mat &src, std::vector<cv::Mat> &out)
+ {
+ out[0] = src.clone();
+ }
+};
+
+G_TYPED_KERNEL(GSizeOfVectorGMat, <cv::GOpaque<size_t>(cv::GArray<cv::GMat>)>,
+ "custom.test.sizeOfVectorGMat")
+{
+ static cv::GOpaqueDesc outMeta(const cv::GArrayDesc&)
+ {
+ return cv::empty_gopaque_desc();
+ }
+};
+
+GAPI_OCV_KERNEL(GCPUSizeOfVectorGMat, custom::GSizeOfVectorGMat)
+{
+ static void run(const std::vector<cv::Mat> &src, size_t &out)
+ {
+ out = src.size();
+ }
+};
+}
+
namespace opencv_test
{
EXPECT_EQ(0, cvtest::norm(out_mat_cv, out_mat_typed2, NORM_INF));
}
-
TEST(GAPI_Typed, MultipleOuts)
{
// Initialization //////////////////////////////////////////////////////////
EXPECT_EQ(0, cvtest::norm(out_mat_cv2, out_mat_comp2, NORM_INF));
}
+TEST(GAPI_Typed, GArrayGMatOut)
+{
+ // Initialization //////////////////////////////////////////////////////////
+ const cv::Size sz(32, 32);
+ cv::Mat in_mat(sz, CV_8UC3);
+ std::vector<cv::Mat> out_vec_mat_untyped(1),
+ out_vec_mat_typed1 (1),
+ out_vec_mat_typed2 (1),
+ out_vec_mat_cv (1);
+ cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar::all(255));
+
+ auto customKernel = cv::gapi::kernels<custom::GCPUKernelForGArrayGMatOut>();
+ auto absExactCompare = AbsExact().to_compare_f();
+
+ // Untyped G-API ///////////////////////////////////////////////////////////
+ cv::GComputation cptU([]()
+ {
+ cv::GMat in;
+ cv::GArray<cv::GMat> out = custom::GKernelForGArrayGMatOut::on(in);
+ return cv::GComputation(cv::GIn(in), cv::GOut(out));
+ });
+ cptU.apply(cv::gin(in_mat), cv::gout(out_vec_mat_untyped), cv::compile_args(customKernel));
+
+ // Typed G-API /////////////////////////////////////////////////////////////
+ cv::GComputationT<cv::GArray<cv::GMat> (cv::GMat)> cptT(custom::GKernelForGArrayGMatOut::on);
+ auto cplT = cptT.compile(cv::descr_of(in_mat), cv::compile_args(customKernel));
+
+ cptT.apply(in_mat, out_vec_mat_typed1, cv::compile_args(customKernel));
+ cplT(in_mat, out_vec_mat_typed2);
+
+ // Plain OpenCV ////////////////////////////////////////////////////////////
+ out_vec_mat_cv[0] = in_mat.clone();
+
+ // Comparison //////////////////////////////////////////////////////////////
+ EXPECT_TRUE(absExactCompare(out_vec_mat_cv[0], out_vec_mat_untyped[0]));
+ EXPECT_TRUE(absExactCompare(out_vec_mat_cv[0], out_vec_mat_typed1 [0]));
+ EXPECT_TRUE(absExactCompare(out_vec_mat_cv[0], out_vec_mat_typed2 [0]));
+}
+
+TEST(GAPI_Typed, GArrayGMatIn)
+{
+ // Initialization //////////////////////////////////////////////////////////
+ const cv::Size sz(32, 32);
+ size_t vectorSize = 5;
+
+ cv::Mat in_mat (sz, CV_8UC3);
+ size_t out_size_t_untyped, out_size_t_typed1, out_size_t_typed2, out_size_t_cv;
+
+ cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar::all(255));
+ std::vector<cv::Mat> in_vec(vectorSize);
+ for (size_t i = 0; i < vectorSize; i++)
+ in_vec[i] = in_mat.clone();
+
+ auto customKernel = cv::gapi::kernels<custom::GCPUSizeOfVectorGMat>();
+
+ // Untyped G-API ///////////////////////////////////////////////////////////
+ cv::GComputation cptU([]()
+ {
+ cv::GArray<cv::GMat> in;
+ cv::GOpaque<size_t> out = custom::GSizeOfVectorGMat::on(in);
+ return cv::GComputation(cv::GIn(in), cv::GOut(out));
+ });
+ cptU.apply(cv::gin(in_vec), cv::gout(out_size_t_untyped), cv::compile_args(customKernel));
+
+ // Typed G-API /////////////////////////////////////////////////////////////
+ cv::GComputationT<cv::GOpaque<size_t> (cv::GArray<cv::GMat>)> cptT(custom::GSizeOfVectorGMat::on);
+ auto cplT = cptT.compile(cv::descr_of(in_vec), cv::compile_args(customKernel));
+
+ cptT.apply(in_vec, out_size_t_typed1, cv::compile_args(customKernel));
+ cplT(in_vec, out_size_t_typed2);
+
+ // Plain OpenCV ////////////////////////////////////////////////////////////
+ out_size_t_cv = in_vec.size();
+
+ // Comparison //////////////////////////////////////////////////////////////
+ EXPECT_TRUE(out_size_t_cv == vectorSize);
+ EXPECT_TRUE(out_size_t_untyped == vectorSize);
+ EXPECT_TRUE(out_size_t_typed1 == vectorSize);
+ EXPECT_TRUE(out_size_t_typed2 == vectorSize);
+}
} // opencv_test
namespace
{
-#define CORE_GPU [] () { return cv::compile_args(cv::gapi::core::gpu::kernels()); }
+#define CORE_GPU [] () { return cv::compile_args(cv::gapi::use_only{cv::gapi::core::gpu::kernels()}); }
} // anonymous namespace
namespace opencv_test
Values (1.0),
testing::Bool()));
-INSTANTIATE_TEST_CASE_P(DivTestGPU, MathOpTest,
+// FIXME: Accuracy test for DIV math operation fails on CV_8UC3 HD input cv::Mat, double-presicion
+// input cv::Scalar and CV_16U output cv::Mat when we also test reverse operation on Mac.
+// Accuracy test for DIV math operation fails on CV_8UC3 VGA input cv::Mat, double-presicion
+// input cv::Scalar and output cv::Mat having the SAME depth as input one when we also test
+// reverse operation on Mac.
+// It is oddly, but test doesn't fail if we have VGA CV_8UC3 input cv::Mat, double-precision
+// input cv::Scalar and output cv::Mat having explicitly specified CV_8U depth when we also
+// test reverse operation on Mac.
+// As failures are sporadic, disabling all instantiation cases for DIV operation.
+// Github ticket: https://github.com/opencv/opencv/issues/18373.
+INSTANTIATE_TEST_CASE_P(DISABLED_DivTestGPU, MathOpTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
Values(CORE_GPU)));
//TODO: mask test doesn't work
-#if 0
-INSTANTIATE_TEST_CASE_P(MaskTestGPU, MaskTest,
+INSTANTIATE_TEST_CASE_P(DISABLED_MaskTestGPU, MaskTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
+ Values(-1),
Values(CORE_GPU)));
-#endif
INSTANTIATE_TEST_CASE_P(SelectTestGPU, SelectTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(CV_8U),
Values(CORE_GPU),
Values(CMP_EQ, CMP_GE, CMP_NE, CMP_GT, CMP_LT, CMP_LE),
- testing::Bool()));
+ testing::Bool(),
+ Values(AbsExact().to_compare_obj())));
INSTANTIATE_TEST_CASE_P(BitwiseTestGPU, BitwiseTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU),
- Values(AND, OR, XOR)));
+ Values(AND, OR, XOR),
+ testing::Bool()));
INSTANTIATE_TEST_CASE_P(BitwiseNotTestGPU, NotTest,
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
Values(-1),
Values(CORE_GPU)));
-INSTANTIATE_TEST_CASE_P(MinTestGPU, MinTest,
+INSTANTIATE_TEST_CASE_P(DISABLED_MinTestGPU, MinTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
Values(-1),
Values(CORE_GPU)));
-INSTANTIATE_TEST_CASE_P(MaxTestGPU, MaxTest,
+INSTANTIATE_TEST_CASE_P(DISABLED_MaxTestGPU, MaxTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(10, 480))));
//TODO: fix this backend to allow ConcatVertVec ConcatHorVec
-#if 0
-INSTANTIATE_TEST_CASE_P(ConcatVertVecTestGPU, ConcatVertVecTest,
+INSTANTIATE_TEST_CASE_P(DISABLED_ConcatVertVecTestGPU, ConcatVertVecTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
+ Values(-1),
Values(CORE_GPU)));
-INSTANTIATE_TEST_CASE_P(ConcatHorVecTestGPU, ConcatHorVecTest,
+INSTANTIATE_TEST_CASE_P(DISABLED_ConcatHorVecTestGPU, ConcatHorVecTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
+ Values(-1),
Values(CORE_GPU)));
-#endif
}
namespace
{
-#define IMGPROC_GPU [] () { return cv::compile_args(cv::gapi::imgproc::gpu::kernels()); }
+#define IMGPROC_GPU [] () { return cv::compile_args(cv::gapi::use_only{cv::gapi::imgproc::gpu::kernels()}); }
} // anonymous namespace
namespace opencv_test
Values(0, 1),
Values(1, 2)));
+INSTANTIATE_TEST_CASE_P(LaplacianTestGPU, LaplacianTest,
+ Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
+ Values(cv::Size(1280, 720),
+ cv::Size(640, 480)),
+ Values(-1),
+ Values(IMGPROC_GPU),
+ Values(Tolerance_FloatRel_IntAbs(1e-4, 2).to_compare_obj()),
+ Values(5),
+ Values(3.0),
+ Values(BORDER_DEFAULT)));
+
+INSTANTIATE_TEST_CASE_P(BilateralFilterTestGPU, BilateralFilterTest,
+ Combine(Values(CV_32FC1, CV_32FC3, CV_8UC1, CV_8UC3),
+ Values(cv::Size(1280, 720),
+ cv::Size(640, 480)),
+ Values(-1),
+ Values(IMGPROC_GPU),
+ Values(Tolerance_FloatRel_IntAbs(1e-4, 2).to_compare_obj()),
+ Values(9),
+ Values(100),
+ Values(40),
+ Values(BORDER_DEFAULT)));
+
INSTANTIATE_TEST_CASE_P(EqHistTestGPU, EqHistTest,
Combine(Values(CV_8UC1),
Values(cv::Size(1280, 720),
namespace
{
-#define CORE_GPU [] () { return cv::compile_args(cv::gapi::core::gpu::kernels()); }
+#define CORE_GPU [] () { return cv::compile_args(cv::gapi::use_only{cv::gapi::core::gpu::kernels()}); }
} // anonymous namespace
namespace opencv_test
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
- Values(-1, CV_8U, CV_32F),
+ Values(-1),
Values(CORE_GPU),
Values(Tolerance_FloatRel_IntAbs(1e-5, 2).to_compare_obj()),
- Values( opPlusM, opMinusM, opDivM,
- opGreater, opLess, opGreaterEq, opLessEq, opEq, opNotEq)));
+ Values( ADD, SUB, DIV,
+ GT, LT, GE, LE, EQ, NE)));
INSTANTIATE_TEST_CASE_P(MathOperatorTestGPU, MathOperatorMatScalarTest,
Combine(Values(CV_8UC1, CV_16SC1, CV_32FC1),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
- Values(-1, CV_8U, CV_32F),
+ Values(-1),
Values(CORE_GPU),
Values(Tolerance_FloatRel_IntAbs(1e-4, 2).to_compare_obj()),
- Values( opPlus, opPlusR, opMinus, opMinusR, opMul, opMulR, // FIXIT avoid division by values near zero: opDiv, opDivR,
- opGT, opLT, opGE, opLE, opEQ, opNE,
- opGTR, opLTR, opGER, opLER, opEQR, opNER)));
+ Values( ADD, SUB, MUL, DIV,
+ ADDR, SUBR, MULR, DIVR,
+ GT, LT, GE, LE, EQ, NE,
+ GTR, LTR, GER, LER, EQR, NER)));
INSTANTIATE_TEST_CASE_P(BitwiseOperatorTestGPU, MathOperatorMatMatTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(-1),
Values(CORE_GPU),
Values(AbsExact().to_compare_obj()),
- Values( opAnd, opOr, opXor )));
+ Values( AND, OR, XOR )));
INSTANTIATE_TEST_CASE_P(BitwiseOperatorTestGPU, MathOperatorMatScalarTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
Values(-1),
Values(CORE_GPU),
Values(AbsExact().to_compare_obj()),
- Values( opAND, opOR, opXOR, opANDR, opORR, opXORR )));
+ Values( AND, OR, XOR,
+ ANDR, ORR, XORR )));
INSTANTIATE_TEST_CASE_P(BitwiseNotOperatorTestGPU, NotOperatorTest,
Combine(Values(CV_8UC1, CV_16UC1, CV_16SC1),
// 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
+// Copyright (C) 2019-2020 Intel Corporation
#include "../test_precomp.hpp"
#include <stdexcept>
-////////////////////////////////////////////////////////////////////////////////
-// FIXME: Suppress deprecation warnings for OpenVINO 2019R2+
-// BEGIN {{{
-#if defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-#ifdef _MSC_VER
-#pragma warning(disable: 4996) // was declared deprecated
-#endif
-
-#if defined(__GNUC__)
-#pragma GCC visibility push(default)
-#endif
-
#include <inference_engine.hpp>
-#if defined(__GNUC__)
-#pragma GCC visibility pop
-#endif
-// END }}}
-////////////////////////////////////////////////////////////////////////////////
-
#include <ade/util/iota_range.hpp>
#include <opencv2/gapi/infer/ie.hpp>
#include "backends/ie/util.hpp"
+#include "backends/ie/giebackend/giewrapper.hpp"
namespace opencv_test
{
EXPECT_LE(normInf, lInf) << comment;
}
+std::vector<std::string> modelPathByName(const std::string &model_name) {
+ // Handle OMZ model layout changes among OpenVINO versions here
+ static const std::unordered_multimap<std::string, std::string> map = {
+#if INF_ENGINE_RELEASE >= 2019040000 // >= 2019.R4
+ {"age-gender-recognition-retail-0013",
+ "2020.3.0/intel/age-gender-recognition-retail-0013/FP32"},
+#endif // INF_ENGINE_RELEASE >= 2019040000
+ {"age-gender-recognition-retail-0013",
+ "Retail/object_attributes/age_gender/dldt"},
+ };
+ const auto range = map.equal_range(model_name);
+ std::vector<std::string> result;
+ for (auto it = range.first; it != range.second; ++it) {
+ result.emplace_back(it->second);
+ }
+ return result;
+}
+
+std::tuple<std::string, std::string> findModel(const std::string &model_name) {
+ const auto candidates = modelPathByName(model_name);
+ CV_Assert(!candidates.empty() && "No model path candidates found at all");
+
+ for (auto &&path : candidates) {
+ std::string model_xml, model_bin;
+ try {
+ model_xml = findDataFile(path + "/" + model_name + ".xml", false);
+ model_bin = findDataFile(path + "/" + model_name + ".bin", false);
+ // Return the first file which actually works
+ return std::make_tuple(model_xml, model_bin);
+ } catch (SkipTestException&) {
+ // This is quite ugly but it is a way for OpenCV to let us know
+ // this file wasn't found.
+ continue;
+ }
+ }
+
+ // Default behavior if reached here.
+ throw SkipTestException("Files for " + model_name + " were not found");
+}
+
+namespace IE = InferenceEngine;
+
+void setNetParameters(IE::CNNNetwork& net) {
+ auto &ii = net.getInputsInfo().at("data");
+ ii->setPrecision(IE::Precision::U8);
+ ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
+}
} // anonymous namespace
// TODO: Probably DNN/IE part can be further parametrized with a template
{
initDLDTDataPath();
- const std::string path = "Retail/object_attributes/age_gender/dldt/age-gender-recognition-retail-0013";
- const auto topology_path = findDataFile(path + ".xml", false);
- const auto weights_path = findDataFile(path + ".bin", false);
+ cv::gapi::ie::detail::ParamDesc params;
+ std::tie(params.model_path, params.weights_path) = findModel("age-gender-recognition-retail-0013");
+ params.device_id = "CPU";
// Load IE network, initialize input data using that.
- namespace IE = InferenceEngine;
cv::Mat in_mat;
cv::Mat gapi_age, gapi_gender;
IE::Blob::Ptr ie_age, ie_gender;
{
- IE::CNNNetReader reader;
- reader.ReadNetwork(topology_path);
- reader.ReadWeights(weights_path);
- auto net = reader.getNetwork();
+ auto plugin = cv::gimpl::ie::wrap::getPlugin(params);
+ auto net = cv::gimpl::ie::wrap::readNetwork(params);
+ auto this_network = cv::gimpl::ie::wrap::loadNetwork(plugin, net, params);
+ auto infer_request = this_network.CreateInferRequest();
const auto &iedims = net.getInputsInfo().begin()->second->getTensorDesc().getDims();
auto cvdims = cv::gapi::ie::util::to_ocv(iedims);
in_mat.create(cvdims, CV_32F);
cv::randu(in_mat, -1, 1);
- auto plugin = IE::PluginDispatcher().getPluginByDevice("CPU");
- auto plugin_net = plugin.LoadNetwork(net, {});
- auto infer_request = plugin_net.CreateInferRequest();
-
infer_request.SetBlob("data", cv::gapi::ie::util::to_ie(in_mat));
infer_request.Infer();
ie_age = infer_request.GetBlob("age_conv3");
cv::GComputation comp(cv::GIn(in), cv::GOut(age, gender));
auto pp = cv::gapi::ie::Params<AgeGender> {
- topology_path, weights_path, "CPU"
+ params.model_path, params.weights_path, params.device_id
}.cfgOutputLayers({ "age_conv3", "prob" });
comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
cv::compile_args(cv::gapi::networks(pp)));
{
initDLDTDataPath();
- const std::string path = "Retail/object_attributes/age_gender/dldt/age-gender-recognition-retail-0013";
- const auto topology_path = findDataFile(path + ".xml", false);
- const auto weights_path = findDataFile(path + ".bin", false);
+ cv::gapi::ie::detail::ParamDesc params;
+ std::tie(params.model_path, params.weights_path) = findModel("age-gender-recognition-retail-0013");
+ params.device_id = "CPU";
// FIXME: Ideally it should be an image from disk
// cv::Mat in_mat = cv::imread(findDataFile("grace_hopper_227.png"));
cv::Mat gapi_age, gapi_gender;
// Load & run IE network
- namespace IE = InferenceEngine;
IE::Blob::Ptr ie_age, ie_gender;
{
- IE::CNNNetReader reader;
- reader.ReadNetwork(topology_path);
- reader.ReadWeights(weights_path);
- auto net = reader.getNetwork();
- auto &ii = net.getInputsInfo().at("data");
- ii->setPrecision(IE::Precision::U8);
- ii->setLayout(IE::Layout::NHWC);
- ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
-
- auto plugin = IE::PluginDispatcher().getPluginByDevice("CPU");
- auto plugin_net = plugin.LoadNetwork(net, {});
- auto infer_request = plugin_net.CreateInferRequest();
-
+ auto plugin = cv::gimpl::ie::wrap::getPlugin(params);
+ auto net = cv::gimpl::ie::wrap::readNetwork(params);
+ setNetParameters(net);
+ auto this_network = cv::gimpl::ie::wrap::loadNetwork(plugin, net, params);
+ auto infer_request = this_network.CreateInferRequest();
infer_request.SetBlob("data", cv::gapi::ie::util::to_ie(in_mat));
infer_request.Infer();
ie_age = infer_request.GetBlob("age_conv3");
cv::GComputation comp(cv::GIn(in), cv::GOut(age, gender));
auto pp = cv::gapi::ie::Params<AgeGender> {
- topology_path, weights_path, "CPU"
+ params.model_path, params.weights_path, params.device_id
}.cfgOutputLayers({ "age_conv3", "prob" });
comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
cv::compile_args(cv::gapi::networks(pp)));
normAssert(cv::gapi::ie::util::to_ocv(ie_gender), gapi_gender, "Test gender output");
}
-TEST(TestAgeGenderIE, InferROIList)
+struct ROIList: public ::testing::Test {
+ cv::gapi::ie::detail::ParamDesc params;
+
+ cv::Mat m_in_mat;
+ std::vector<cv::Rect> m_roi_list;
+
+ std::vector<cv::Mat> m_out_ie_ages;
+ std::vector<cv::Mat> m_out_ie_genders;
+
+ std::vector<cv::Mat> m_out_gapi_ages;
+ std::vector<cv::Mat> m_out_gapi_genders;
+
+ using AGInfo = std::tuple<cv::GMat, cv::GMat>;
+ G_API_NET(AgeGender, <AGInfo(cv::GMat)>, "test-age-gender");
+
+ ROIList() {
+ initDLDTDataPath();
+ std::tie(params.model_path, params.weights_path) = findModel("age-gender-recognition-retail-0013");
+ params.device_id = "CPU";
+
+ // FIXME: it must be cv::imread(findDataFile("../dnn/grace_hopper_227.png", false));
+ m_in_mat = cv::Mat(cv::Size(320, 240), CV_8UC3);
+ cv::randu(m_in_mat, 0, 255);
+
+ // both ROIs point to the same face, with a slightly changed geometry
+ m_roi_list = {
+ cv::Rect(cv::Point{64, 60}, cv::Size{ 96, 96}),
+ cv::Rect(cv::Point{50, 32}, cv::Size{128, 160}),
+ };
+
+ // Load & run IE network
+ {
+ auto plugin = cv::gimpl::ie::wrap::getPlugin(params);
+ auto net = cv::gimpl::ie::wrap::readNetwork(params);
+ setNetParameters(net);
+ auto this_network = cv::gimpl::ie::wrap::loadNetwork(plugin, net, params);
+ auto infer_request = this_network.CreateInferRequest();
+ auto frame_blob = cv::gapi::ie::util::to_ie(m_in_mat);
+
+ for (auto &&rc : m_roi_list) {
+ const auto ie_rc = IE::ROI {
+ 0u
+ , static_cast<std::size_t>(rc.x)
+ , static_cast<std::size_t>(rc.y)
+ , static_cast<std::size_t>(rc.width)
+ , static_cast<std::size_t>(rc.height)
+ };
+ infer_request.SetBlob("data", IE::make_shared_blob(frame_blob, ie_rc));
+ infer_request.Infer();
+
+ using namespace cv::gapi::ie::util;
+ m_out_ie_ages.push_back(to_ocv(infer_request.GetBlob("age_conv3")).clone());
+ m_out_ie_genders.push_back(to_ocv(infer_request.GetBlob("prob")).clone());
+ }
+ } // namespace IE = ..
+ } // ROIList()
+
+ void validate() {
+ // Validate with IE itself (avoid DNN module dependency here)
+ ASSERT_EQ(2u, m_out_ie_ages.size());
+ ASSERT_EQ(2u, m_out_ie_genders.size());
+ ASSERT_EQ(2u, m_out_gapi_ages.size());
+ ASSERT_EQ(2u, m_out_gapi_genders.size());
+
+ normAssert(m_out_ie_ages [0], m_out_gapi_ages [0], "0: Test age output");
+ normAssert(m_out_ie_genders[0], m_out_gapi_genders[0], "0: Test gender output");
+ normAssert(m_out_ie_ages [1], m_out_gapi_ages [1], "1: Test age output");
+ normAssert(m_out_ie_genders[1], m_out_gapi_genders[1], "1: Test gender output");
+ }
+}; // ROIList
+
+TEST_F(ROIList, TestInfer)
+{
+ cv::GArray<cv::Rect> rr;
+ cv::GMat in;
+ cv::GArray<cv::GMat> age, gender;
+ std::tie(age, gender) = cv::gapi::infer<AgeGender>(rr, in);
+ cv::GComputation comp(cv::GIn(in, rr), cv::GOut(age, gender));
+
+ auto pp = cv::gapi::ie::Params<AgeGender> {
+ params.model_path, params.weights_path, params.device_id
+ }.cfgOutputLayers({ "age_conv3", "prob" });
+ comp.apply(cv::gin(m_in_mat, m_roi_list),
+ cv::gout(m_out_gapi_ages, m_out_gapi_genders),
+ cv::compile_args(cv::gapi::networks(pp)));
+ validate();
+}
+
+TEST_F(ROIList, TestInfer2)
+{
+ cv::GArray<cv::Rect> rr;
+ cv::GMat in;
+ cv::GArray<cv::GMat> age, gender;
+ std::tie(age, gender) = cv::gapi::infer2<AgeGender>(in, rr);
+ cv::GComputation comp(cv::GIn(in, rr), cv::GOut(age, gender));
+
+ auto pp = cv::gapi::ie::Params<AgeGender> {
+ params.model_path, params.weights_path, params.device_id
+ }.cfgOutputLayers({ "age_conv3", "prob" });
+ comp.apply(cv::gin(m_in_mat, m_roi_list),
+ cv::gout(m_out_gapi_ages, m_out_gapi_genders),
+ cv::compile_args(cv::gapi::networks(pp)));
+ validate();
+}
+
+TEST(DISABLED_TestTwoIENNPipeline, InferBasicImage)
{
initDLDTDataPath();
- const std::string path = "Retail/object_attributes/age_gender/dldt/age-gender-recognition-retail-0013";
- const auto topology_path = findDataFile(path + ".xml", false);
- const auto weights_path = findDataFile(path + ".bin", false);
+ cv::gapi::ie::detail::ParamDesc AGparams;
+ std::tie(AGparams.model_path, AGparams.weights_path) = findModel("age-gender-recognition-retail-0013");
+ AGparams.device_id = "MYRIAD";
// FIXME: Ideally it should be an image from disk
// cv::Mat in_mat = cv::imread(findDataFile("grace_hopper_227.png"));
- cv::Mat in_mat(cv::Size(640, 480), CV_8UC3);
+ cv::Mat in_mat(cv::Size(320, 240), CV_8UC3);
cv::randu(in_mat, 0, 255);
- std::vector<cv::Rect> rois = {
- cv::Rect(cv::Point{ 0, 0}, cv::Size{80, 120}),
- cv::Rect(cv::Point{50, 100}, cv::Size{96, 160}),
- };
-
- std::vector<cv::Mat> gapi_age, gapi_gender;
+ cv::Mat gapi_age1, gapi_gender1, gapi_age2, gapi_gender2;
// Load & run IE network
- namespace IE = InferenceEngine;
- std::vector<cv::Mat> ie_age, ie_gender;
+ IE::Blob::Ptr ie_age1, ie_gender1, ie_age2, ie_gender2;
{
- IE::CNNNetReader reader;
- reader.ReadNetwork(topology_path);
- reader.ReadWeights(weights_path);
- auto net = reader.getNetwork();
- auto &ii = net.getInputsInfo().at("data");
- ii->setPrecision(IE::Precision::U8);
- ii->setLayout(IE::Layout::NHWC);
- ii->getPreProcess().setResizeAlgorithm(IE::RESIZE_BILINEAR);
-
- auto plugin = IE::PluginDispatcher().getPluginByDevice("CPU");
- auto plugin_net = plugin.LoadNetwork(net, {});
- auto infer_request = plugin_net.CreateInferRequest();
- auto frame_blob = cv::gapi::ie::util::to_ie(in_mat);
-
- for (auto &&rc : rois) {
- const auto ie_rc = IE::ROI {
- 0u
- , static_cast<std::size_t>(rc.x)
- , static_cast<std::size_t>(rc.y)
- , static_cast<std::size_t>(rc.width)
- , static_cast<std::size_t>(rc.height)
- };
- infer_request.SetBlob("data", IE::make_shared_blob(frame_blob, ie_rc));
- infer_request.Infer();
-
- using namespace cv::gapi::ie::util;
- ie_age.push_back(to_ocv(infer_request.GetBlob("age_conv3")).clone());
- ie_gender.push_back(to_ocv(infer_request.GetBlob("prob")).clone());
- }
+ auto AGplugin1 = cv::gimpl::ie::wrap::getPlugin(AGparams);
+ auto AGnet1 = cv::gimpl::ie::wrap::readNetwork(AGparams);
+ setNetParameters(AGnet1);
+ auto AGplugin_network1 = cv::gimpl::ie::wrap::loadNetwork(AGplugin1, AGnet1, AGparams);
+ auto AGinfer_request1 = AGplugin_network1.CreateInferRequest();
+ AGinfer_request1.SetBlob("data", cv::gapi::ie::util::to_ie(in_mat));
+ AGinfer_request1.Infer();
+ ie_age1 = AGinfer_request1.GetBlob("age_conv3");
+ ie_gender1 = AGinfer_request1.GetBlob("prob");
+
+ auto AGplugin2 = cv::gimpl::ie::wrap::getPlugin(AGparams);
+ auto AGnet2 = cv::gimpl::ie::wrap::readNetwork(AGparams);
+ setNetParameters(AGnet2);
+ auto AGplugin_network2 = cv::gimpl::ie::wrap::loadNetwork(AGplugin2, AGnet2, AGparams);
+ auto AGinfer_request2 = AGplugin_network2.CreateInferRequest();
+ AGinfer_request2.SetBlob("data", cv::gapi::ie::util::to_ie(in_mat));
+ AGinfer_request2.Infer();
+ ie_age2 = AGinfer_request2.GetBlob("age_conv3");
+ ie_gender2 = AGinfer_request2.GetBlob("prob");
}
// Configure & run G-API
using AGInfo = std::tuple<cv::GMat, cv::GMat>;
- G_API_NET(AgeGender, <AGInfo(cv::GMat)>, "test-age-gender");
-
- cv::GArray<cv::Rect> rr;
+ G_API_NET(AgeGender1, <AGInfo(cv::GMat)>, "test-age-gender1");
+ G_API_NET(AgeGender2, <AGInfo(cv::GMat)>, "test-age-gender2");
cv::GMat in;
- cv::GArray<cv::GMat> age, gender;
- std::tie(age, gender) = cv::gapi::infer<AgeGender>(rr, in);
- cv::GComputation comp(cv::GIn(in, rr), cv::GOut(age, gender));
+ cv::GMat age1, gender1;
+ std::tie(age1, gender1) = cv::gapi::infer<AgeGender1>(in);
- auto pp = cv::gapi::ie::Params<AgeGender> {
- topology_path, weights_path, "CPU"
+ cv::GMat age2, gender2;
+ // FIXME: "Multi-node inference is not supported!", workarounded 'till enabling proper tools
+ std::tie(age2, gender2) = cv::gapi::infer<AgeGender2>(cv::gapi::copy(in));
+ cv::GComputation comp(cv::GIn(in), cv::GOut(age1, gender1, age2, gender2));
+
+ auto age_net1 = cv::gapi::ie::Params<AgeGender1> {
+ AGparams.model_path, AGparams.weights_path, AGparams.device_id
+ }.cfgOutputLayers({ "age_conv3", "prob" });
+ auto age_net2 = cv::gapi::ie::Params<AgeGender2> {
+ AGparams.model_path, AGparams.weights_path, AGparams.device_id
}.cfgOutputLayers({ "age_conv3", "prob" });
- comp.apply(cv::gin(in_mat, rois), cv::gout(gapi_age, gapi_gender),
- cv::compile_args(cv::gapi::networks(pp)));
+
+ comp.apply(cv::gin(in_mat), cv::gout(gapi_age1, gapi_gender1, gapi_age2, gapi_gender2),
+ cv::compile_args(cv::gapi::networks(age_net1, age_net2)));
// Validate with IE itself (avoid DNN module dependency here)
- ASSERT_EQ(2u, ie_age.size() );
- ASSERT_EQ(2u, ie_gender.size());
- ASSERT_EQ(2u, gapi_age.size() );
- ASSERT_EQ(2u, gapi_gender.size());
-
- normAssert(ie_age [0], gapi_age [0], "0: Test age output");
- normAssert(ie_gender[0], gapi_gender[0], "0: Test gender output");
- normAssert(ie_age [1], gapi_age [1], "1: Test age output");
- normAssert(ie_gender[1], gapi_gender[1], "1: Test gender output");
+ normAssert(cv::gapi::ie::util::to_ocv(ie_age1), gapi_age1, "Test age output 1");
+ normAssert(cv::gapi::ie::util::to_ocv(ie_gender1), gapi_gender1, "Test gender output 1");
+ normAssert(cv::gapi::ie::util::to_ocv(ie_age2), gapi_age2, "Test age output 2");
+ normAssert(cv::gapi::ie::util::to_ocv(ie_gender2), gapi_gender2, "Test gender output 2");
}
-
} // namespace opencv_test
#endif // HAVE_INF_ENGINE
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#include "../test_precomp.hpp"
+
+// These tests verify some parts of cv::gapi::infer<> API
+// regardless of the backend used
+
+namespace opencv_test {
+namespace {
+template<class A, class B> using Check = cv::detail::valid_infer2_types<A, B>;
+
+TEST(Infer, ValidInfer2Types)
+{
+ // Compiled == passed!
+
+ // Argument block 1
+ static_assert(Check< std::tuple<cv::GMat> // Net
+ , std::tuple<cv::GMat> > // Call
+ ::value == true, "Must work");
+
+ static_assert(Check< std::tuple<cv::GMat, cv::GMat> // Net
+ , std::tuple<cv::GMat, cv::GMat> > // Call
+ ::value == true, "Must work");
+
+ // Argument block 2
+ static_assert(Check< std::tuple<cv::GMat> // Net
+ , std::tuple<cv::Rect> > // Call
+ ::value == true, "Must work");
+
+ static_assert(Check< std::tuple<cv::GMat, cv::GMat> // Net
+ , std::tuple<cv::Rect, cv::Rect> > // Call
+ ::value == true, "Must work");
+
+ // Argument block 3 (mixed cases)
+ static_assert(Check< std::tuple<cv::GMat, cv::GMat> // Net
+ , std::tuple<cv::GMat, cv::Rect> > // Call
+ ::value == true, "Must work");
+
+ static_assert(Check< std::tuple<cv::GMat, cv::GMat> // Net
+ , std::tuple<cv::Rect, cv::GMat> > // Call
+ ::value == true, "Must work");
+
+ // Argument block 4 (super-mixed)
+ static_assert(Check< std::tuple<cv::GMat, cv::GMat, cv::GMat> // Net
+ , std::tuple<cv::Rect, cv::GMat, cv::Rect> > // Call
+ ::value == true, "Must work");
+
+ // Argument block 5 (mainly negative)
+ static_assert(Check< std::tuple<cv::GMat> // Net
+ , std::tuple<int> > // Call
+ ::value == false, "This type(s) shouldn't pass");
+
+ static_assert(Check< std::tuple<cv::GMat, cv::GMat> // Net
+ , std::tuple<int, cv::Rect> > // Call
+ ::value == false, "This type(s) shouldn't pass");
+
+ static_assert(Check< std::tuple<cv::GMat, cv::GMat> // Net
+ , std::tuple<cv::Rect, cv::Point> >// Call
+ ::value == false, "This type(s) shouldn't pass");
+
+ // Argument block 5 (wrong args length)
+ static_assert(Check< std::tuple<cv::GMat, cv::GMat> // Net
+ , std::tuple<cv::GMat> > // Call
+ ::value == false, "Should fail -- not enough args");
+
+ static_assert(Check< std::tuple<cv::GMat, cv::GMat> // Net
+ , std::tuple<cv::Rect> > // Call
+ ::value == false, "Should fail -- not enough args");
+
+ static_assert(Check< std::tuple<cv::GMat, cv::GMat> // Net
+ , std::tuple<cv::Rect, cv::Rect, cv::GMat> > // Call
+ ::value == false, "Should fail -- too much args");
+}
+} // anonymous namespace
+} // namespace opencv_test
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#include "../test_precomp.hpp"
+
+#include <opencv2/gapi/cpu/core.hpp>
+#include <opencv2/gapi/cpu/imgproc.hpp>
+
+namespace opencv_test
+{
+ typedef ::testing::Types<cv::GMat, cv::GMatP, cv::GFrame,
+ cv::GScalar, cv::GOpaque<int>,
+ cv::GArray<int>> VectorProtoTypes;
+
+ template<typename T> struct DynamicGraphProtoArgs: public ::testing::Test { using Type = T; };
+
+ TYPED_TEST_CASE(DynamicGraphProtoArgs, VectorProtoTypes);
+
+ TYPED_TEST(DynamicGraphProtoArgs, AddProtoInputArgsSmoke)
+ {
+ using T = typename TestFixture::Type;
+ auto ins = GIn();
+ T in;
+ EXPECT_NO_THROW(ins += GIn(in));
+ }
+
+ TYPED_TEST(DynamicGraphProtoArgs, AddProtoInputArgs)
+ {
+ using T = typename TestFixture::Type;
+ T in1, in2;
+
+ auto ins1 = GIn();
+ ins1 += GIn(in1);
+ ins1 += GIn(in2);
+
+ auto ins2 = GIn(in1, in2);
+
+ EXPECT_EQ(ins1.m_args.size(), ins2.m_args.size());
+ }
+
+ TYPED_TEST(DynamicGraphProtoArgs, AddProtoOutputArgsSmoke)
+ {
+ using T = typename TestFixture::Type;
+ auto outs = GOut();
+ T out;
+ EXPECT_NO_THROW(outs += GOut(out));
+ }
+
+ TYPED_TEST(DynamicGraphProtoArgs, AddProtoOutputArgs)
+ {
+ using T = typename TestFixture::Type;
+ T out1, out2;
+
+ auto outs1 = GOut();
+ outs1 += GOut(out1);
+ outs1 += GOut(out2);
+
+ auto outs2 = GOut(out1, out2);
+
+ EXPECT_EQ(outs1.m_args.size(), outs2.m_args.size());
+ }
+
+ typedef ::testing::Types<cv::Mat,
+#if !defined(GAPI_STANDALONE)
+ cv::UMat,
+#endif // !defined(GAPI_STANDALONE)
+ cv::Scalar,
+ cv::detail::VectorRef,
+ cv::detail::OpaqueRef> VectorRunTypes;
+
+ template<typename T> struct DynamicGraphRunArgs: public ::testing::Test { using Type = T; };
+
+ TYPED_TEST_CASE(DynamicGraphRunArgs, VectorRunTypes);
+
+ TYPED_TEST(DynamicGraphRunArgs, AddRunArgsSmoke)
+ {
+ auto in_vector = cv::gin();
+
+ using T = typename TestFixture::Type;
+ T in;
+ EXPECT_NO_THROW(in_vector += cv::gin(in));
+ }
+
+ TYPED_TEST(DynamicGraphRunArgs, AddRunArgs)
+ {
+ using T = typename TestFixture::Type;
+ T in1, in2;
+
+ auto in_vector1 = cv::gin();
+ in_vector1 += cv::gin(in1);
+ in_vector1 += cv::gin(in2);
+
+ auto in_vector2 = cv::gin(in1, in2);
+
+ EXPECT_EQ(in_vector1.size(), in_vector2.size());
+ }
+
+ TYPED_TEST(DynamicGraphRunArgs, AddRunArgsPSmoke)
+ {
+ auto out_vector = cv::gout();
+
+ using T = typename TestFixture::Type;
+ T out;
+ EXPECT_NO_THROW(out_vector += cv::gout(out));
+ }
+
+ TYPED_TEST(DynamicGraphRunArgs, AddRunArgsP)
+ {
+ using T = typename TestFixture::Type;
+ T out1, out2;
+
+ auto out_vector1 = cv::gout();
+ out_vector1 += cv::gout(out1);
+ out_vector1 += cv::gout(out2);
+
+ auto out_vector2 = cv::gout(out1, out2);
+
+ EXPECT_EQ(out_vector1.size(), out_vector2.size());
+ }
+
+ TEST(DynamicGraph, ProtoInputArgsExecute)
+ {
+ cv::GComputation cc([]() {
+ cv::GMat in1;
+ auto ins = GIn(in1);
+
+ cv::GMat in2;
+ ins += GIn(in2);
+
+ cv::GMat out = cv::gapi::copy(in1 + in2);
+
+ return cv::GComputation(std::move(ins), GOut(out));
+ });
+
+ cv::Mat in_mat1 = cv::Mat::eye(32, 32, CV_8UC1);
+ cv::Mat in_mat2 = cv::Mat::eye(32, 32, CV_8UC1);
+ cv::Mat out_mat;
+
+ EXPECT_NO_THROW(cc.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat)));
+ }
+
+ TEST(DynamicGraph, ProtoOutputArgsExecute)
+ {
+ cv::GComputation cc([]() {
+ cv::GMat in;
+ cv::GMat out1 = cv::gapi::copy(in);
+ auto outs = GOut(out1);
+
+ cv::GMat out2 = cv::gapi::copy(in);
+ outs += GOut(out2);
+
+ return cv::GComputation(cv::GIn(in), std::move(outs));
+ });
+
+ cv::Mat in_mat1 = cv::Mat::eye(32, 32, CV_8UC1);
+ cv::Mat out_mat1;
+ cv::Mat out_mat2;
+
+ EXPECT_NO_THROW(cc.apply(cv::gin(in_mat1), cv::gout(out_mat1, out_mat1)));
+ }
+
+ TEST(DynamicGraph, ProtoOutputInputArgsExecute)
+ {
+ cv::GComputation cc([]() {
+ cv::GMat in1;
+ auto ins = GIn(in1);
+
+ cv::GMat in2;
+ ins += GIn(in2);
+
+ cv::GMat out1 = cv::gapi::copy(in1 + in2);
+ auto outs = GOut(out1);
+
+ cv::GMat out2 = cv::gapi::copy(in1 + in2);
+ outs += GOut(out2);
+
+ return cv::GComputation(std::move(ins), std::move(outs));
+ });
+
+ cv::Mat in_mat1 = cv::Mat::eye(32, 32, CV_8UC1);
+ cv::Mat in_mat2 = cv::Mat::eye(32, 32, CV_8UC1);
+ cv::Mat out_mat1, out_mat2;
+
+ EXPECT_NO_THROW(cc.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat1, out_mat2)));
+ }
+
+ TEST(DynamicGraph, ProtoArgsExecute)
+ {
+ cv::GComputation cc([]() {
+ cv::GMat in1;
+ auto ins = GIn(in1);
+
+ cv::GMat in2;
+ ins += GIn(in2);
+
+ cv::GMat out1 = cv::gapi::copy(in1 + in2);
+ auto outs = GOut(out1);
+
+ cv::GMat out2 = cv::gapi::copy(in1 + in2);
+ outs += GOut(out2);
+
+ return cv::GComputation(std::move(ins), std::move(outs));
+ });
+
+ cv::Mat in_mat1 = cv::Mat::eye(32, 32, CV_8UC1);
+ cv::Mat in_mat2 = cv::Mat::eye(32, 32, CV_8UC1);
+ cv::Mat out_mat1, out_mat2;
+
+ EXPECT_NO_THROW(cc.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat1, out_mat2)));
+ }
+
+ TEST(DynamicGraph, ProtoOutputInputArgsAccuracy)
+ {
+ cv::Size szOut(4, 4);
+ cv::GComputation cc([&](){
+ cv::GMat in1;
+ auto ins = GIn(in1);
+
+ cv::GMat in2;
+ ins += GIn(in2);
+
+ cv::GMat out1 = cv::gapi::resize(in1, szOut);
+ auto outs = GOut(out1);
+
+ cv::GMat out2 = cv::gapi::resize(in2, szOut);
+ outs += GOut(out2);
+
+ return cv::GComputation(std::move(ins), std::move(outs));
+ });
+
+ // G-API test code
+ cv::Mat in_mat1( 8, 8, CV_8UC3);
+ cv::Mat in_mat2(16, 16, CV_8UC3);
+ cv::randu(in_mat1, cv::Scalar::all(0), cv::Scalar::all(255));
+ cv::randu(in_mat2, cv::Scalar::all(0), cv::Scalar::all(255));
+
+ auto in_vector = cv::gin();
+ in_vector += cv::gin(in_mat1);
+ in_vector += cv::gin(in_mat2);
+
+ cv::Mat out_mat1, out_mat2;
+ auto out_vector = cv::gout();
+ out_vector += cv::gout(out_mat1);
+ out_vector += cv::gout(out_mat2);
+
+ cc.apply(std::move(in_vector), std::move(out_vector));
+
+ // OCV ref code
+ cv::Mat cv_out_mat1, cv_out_mat2;
+ cv::resize(in_mat1, cv_out_mat1, szOut);
+ cv::resize(in_mat2, cv_out_mat2, szOut);
+
+ EXPECT_EQ(0, cvtest::norm(out_mat1, cv_out_mat1, NORM_INF));
+ EXPECT_EQ(0, cvtest::norm(out_mat2, cv_out_mat2, NORM_INF));
+ }
+
+ TEST(DynamicGraph, Streaming)
+ {
+ cv::GComputation cc([&](){
+ cv::Size szOut(4, 4);
+
+ cv::GMat in1;
+ auto ins = GIn(in1);
+
+ cv::GMat in2;
+ ins += GIn(in2);
+
+ cv::GMat out1 = cv::gapi::resize(in1, szOut);
+ auto outs = GOut(out1);
+
+ cv::GMat out2 = cv::gapi::resize(in2, szOut);
+ outs += GOut(out2);
+
+ return cv::GComputation(std::move(ins), std::move(outs));
+ });
+
+ EXPECT_NO_THROW(cc.compileStreaming(cv::compile_args(cv::gapi::core::cpu::kernels())));
+ }
+
+ TEST(DynamicGraph, StreamingAccuracy)
+ {
+ cv::Size szOut(4, 4);
+ cv::GComputation cc([&](){
+ cv::GMat in1;
+ auto ins = GIn(in1);
+
+ cv::GMat in2;
+ ins += GIn(in2);
+
+ cv::GMat out1 = cv::gapi::resize(in1, szOut);
+ cv::GProtoOutputArgs outs = GOut(out1);
+
+ cv::GMat out2 = cv::gapi::resize(in2, szOut);
+ outs += GOut(out2);
+ return cv::GComputation(std::move(ins), std::move(outs));
+ });
+
+ // G-API test code
+ cv::Mat in_mat1( 8, 8, CV_8UC3);
+ cv::Mat in_mat2(16, 16, CV_8UC3);
+ cv::randu(in_mat1, cv::Scalar::all(0), cv::Scalar::all(255));
+ cv::randu(in_mat2, cv::Scalar::all(0), cv::Scalar::all(255));
+
+ auto in_vector = cv::gin();
+ in_vector += cv::gin(in_mat1);
+ in_vector += cv::gin(in_mat2);
+
+ cv::Mat out_mat1, out_mat2;
+ auto out_vector = cv::gout();
+ out_vector += cv::gout(out_mat1);
+ out_vector += cv::gout(out_mat2);
+
+ auto stream = cc.compileStreaming(cv::compile_args(cv::gapi::core::cpu::kernels()));
+ stream.setSource(std::move(in_vector));
+
+ stream.start();
+ stream.pull(std::move(out_vector));
+ stream.stop();
+
+ // OCV ref code
+ cv::Mat cv_out_mat1, cv_out_mat2;
+ cv::resize(in_mat1, cv_out_mat1, szOut);
+ cv::resize(in_mat2, cv_out_mat2, szOut);
+
+ EXPECT_EQ(0, cvtest::norm(out_mat1, cv_out_mat1, NORM_INF));
+ EXPECT_EQ(0, cvtest::norm(out_mat2, cv_out_mat2, NORM_INF));
+ }
+} // namespace opencv_test
#include "../test_precomp.hpp"
namespace opencv_test {
-// Tests on T/Kind matching ////////////////////////////////////////////////////
+// Tests on T/Spec/Kind matching ///////////////////////////////////////////////
// {{
template<class T, cv::detail::ArgKind Exp>
// G-API types
Expected<cv::GMat, cv::detail::ArgKind::GMAT>
, Expected<cv::GMatP, cv::detail::ArgKind::GMATP>
+ , Expected<cv::GFrame, cv::detail::ArgKind::GFRAME>
, Expected<cv::GScalar, cv::detail::ArgKind::GSCALAR>
, Expected<cv::GArray<int>, cv::detail::ArgKind::GARRAY>
, Expected<cv::GArray<float>, cv::detail::ArgKind::GARRAY>
EXPECT_EQ(TestFixture::Kind, arg.kind);
}
-// }}
////////////////////////////////////////////////////////////////////////////////
TEST(GArg, HasWrap)
cv::GArg arg2 = cv::GArg(cv::GOpaque<cv::Point>());
EXPECT_NO_THROW(arg2.get<cv::detail::GOpaqueU>());
}
-
-
} // namespace opencv_test
#include <ade/util/zip_range.hpp> // util::indexed
#include <opencv2/gapi/gkernel.hpp>
+#include <opencv2/gapi/gcommon.hpp>
#include "compiler/gmodelbuilder.hpp"
#include "compiler/gmodel.hpp" // RcDesc, GModel::init
namespace
{
+ namespace D = cv::detail;
cv::GMat unaryOp(cv::GMat m)
{
- return cv::GCall(cv::GKernel{"gapi.test.unaryop", "", nullptr, { GShape::GMAT } }).pass(m).yield(0);
+ return cv::GCall(cv::GKernel{ "gapi.test.unaryop"
+ , ""
+ , nullptr
+ , { GShape::GMAT }
+ , { D::OpaqueKind::CV_UNKNOWN } }).pass(m).yield(0);
}
cv::GMat binaryOp(cv::GMat m1, cv::GMat m2)
{
- return cv::GCall(cv::GKernel{"gapi.test.binaryOp", "", nullptr, { GShape::GMAT } }).pass(m1, m2).yield(0);
+ return cv::GCall(cv::GKernel{ "gapi.test.binaryOp"
+ , ""
+ , nullptr
+ , { GShape::GMAT }
+ , { D::OpaqueKind::CV_UNKNOWN, D::OpaqueKind::CV_UNKNOWN } }).pass(m1, m2).yield(0);
}
std::vector<ade::NodeHandle> collectOperations(const cv::gimpl::GModel::Graph& gr)
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#include "../test_precomp.hpp"
+#include "../src/api/gproto_priv.hpp"
+
+namespace opencv_test {
+
+template<typename T>
+struct ProtoPtrTest : public ::testing::Test { using Type = T; };
+
+using ProtoPtrTestTypes = ::testing::Types< cv::Mat
+ , cv::UMat
+ , cv::gapi::own::Mat
+ , cv::Scalar
+ , std::vector<int>
+ , int
+ >;
+
+TYPED_TEST_CASE(ProtoPtrTest, ProtoPtrTestTypes);
+
+TYPED_TEST(ProtoPtrTest, NonZero)
+{
+ typename TestFixture::Type value;
+ const auto arg = cv::gout(value).front();
+ const auto ptr = cv::gimpl::proto::ptr(arg);
+ EXPECT_EQ(ptr, &value);
+}
+
+} // namespace opencv_test
"#endif\n"
"#define GET_A0(id, x, l_edge, a1) ((x) <= (l_edge + 2) ? GET_BORDER(a1) : (((const __global uchar*)(id))[-3]))\n"
"#define GET_A1(id, x, l_edge, a2) ((x) <= (l_edge + 1) ? GET_BORDER(a2) : (((const __global uchar*)(id))[-2]))\n"
-"#define GET_A2(id, x, l_edge, b) ((x) <= (l_edge) ? GET_BORDER(b[0]) : (((const __global uchar*)(id))[-1]))\n"
-"#define GET_C0(id, x, r_edge, b) ((x) >= (r_edge) ? GET_BORDER(b[8 - 1]) : (((const __global uchar*)(id))[8]))\n"
+"#define GET_A2(id, x, l_edge, b) ((x) <= (l_edge) ? GET_BORDER(b.s0) : (((const __global uchar*)(id))[-1]))\n"
+"#define GET_C0(id, x, r_edge, b) ((x) >= (r_edge) ? GET_BORDER(b.s7) : (((const __global uchar*)(id))[8]))\n"
"#define GET_C1(id, x, r_edge, c0) ((x) >= (r_edge - 1) ? GET_BORDER(c0) : (((const __global uchar*)(id))[8 + 1]))\n"
"#define GET_C2(id, x, r_edge, c1) ((x) >= (r_edge - 2) ? GET_BORDER(c1) : (((const __global uchar*)(id))[8 + 2]))\n"
"__kernel void symm_7x7_test(\n"
#include "../test_precomp.hpp"
#include <opencv2/gapi/own/mat.hpp>
+#include <opencv2/gapi/own/convert.hpp>
#include <opencv2/gapi/util/compiler_hints.hpp> //suppress_unused_warning
namespace opencv_test
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#include "../test_precomp.hpp"
+#include <opencv2/gapi/rmat.hpp>
+
+namespace opencv_test {
+namespace {
+class RMatAdapterRef : public RMat::Adapter {
+ cv::Mat& m_mat;
+ bool& m_callbackCalled;
+public:
+ RMatAdapterRef(cv::Mat& m, bool& callbackCalled)
+ : m_mat(m), m_callbackCalled(callbackCalled)
+ {}
+ virtual RMat::View access(RMat::Access access) const override {
+ if (access == RMat::Access::W) {
+ return RMat::View(cv::descr_of(m_mat), m_mat.data, m_mat.step,
+ [this](){
+ EXPECT_FALSE(m_callbackCalled);
+ m_callbackCalled = true;
+ });
+ } else {
+ return RMat::View(cv::descr_of(m_mat), m_mat.data, m_mat.step);
+ }
+ }
+ virtual cv::GMatDesc desc() const override { return cv::descr_of(m_mat); }
+};
+
+class RMatAdapterCopy : public RMat::Adapter {
+ cv::Mat& m_deviceMat;
+ cv::Mat m_hostMat;
+ bool& m_callbackCalled;
+
+public:
+ RMatAdapterCopy(cv::Mat& m, bool& callbackCalled)
+ : m_deviceMat(m), m_hostMat(m.clone()), m_callbackCalled(callbackCalled)
+ {}
+ virtual RMat::View access(RMat::Access access) const override {
+ if (access == RMat::Access::W) {
+ return RMat::View(cv::descr_of(m_hostMat), m_hostMat.data, m_hostMat.step,
+ [this](){
+ EXPECT_FALSE(m_callbackCalled);
+ m_callbackCalled = true;
+ m_hostMat.copyTo(m_deviceMat);
+ });
+ } else {
+ m_deviceMat.copyTo(m_hostMat);
+ return RMat::View(cv::descr_of(m_hostMat), m_hostMat.data, m_hostMat.step);
+ }
+ }
+ virtual cv::GMatDesc desc() const override { return cv::descr_of(m_hostMat); }
+};
+
+void randomizeMat(cv::Mat& m) {
+ auto ref = m.clone();
+ while (cv::norm(m, ref, cv::NORM_INF) == 0) {
+ cv::randu(m, cv::Scalar::all(127), cv::Scalar::all(40));
+ }
+}
+
+template <typename RMatAdapterT>
+struct RMatTest {
+ using AdapterT = RMatAdapterT;
+ RMatTest()
+ : m_deviceMat(8,8,CV_8UC1)
+ , m_rmat(make_rmat<RMatAdapterT>(m_deviceMat, m_callbackCalled)) {
+ randomizeMat(m_deviceMat);
+ expectNoCallbackCalled();
+ }
+
+ RMat& rmat() { return m_rmat; }
+ cv::Mat cloneDeviceMat() { return m_deviceMat.clone(); }
+ void expectCallbackCalled() { EXPECT_TRUE(m_callbackCalled); }
+ void expectNoCallbackCalled() { EXPECT_FALSE(m_callbackCalled); }
+
+ void expectDeviceDataEqual(const cv::Mat& mat) {
+ EXPECT_EQ(0, cv::norm(mat, m_deviceMat, NORM_INF));
+ }
+ void expectDeviceDataNotEqual(const cv::Mat& mat) {
+ EXPECT_NE(0, cv::norm(mat, m_deviceMat, NORM_INF));
+ }
+
+private:
+ cv::Mat m_deviceMat;
+ bool m_callbackCalled = false;
+ cv::RMat m_rmat;
+};
+} // anonymous namespace
+
+template<typename T>
+struct RMatTypedTest : public ::testing::Test, public T { using Type = T; };
+
+using RMatTestTypes = ::testing::Types< RMatTest<RMatAdapterRef>
+ , RMatTest<RMatAdapterCopy>
+ >;
+
+TYPED_TEST_CASE(RMatTypedTest, RMatTestTypes);
+
+TYPED_TEST(RMatTypedTest, Smoke) {
+ auto view = this->rmat().access(RMat::Access::R);
+ auto matFromDevice = cv::Mat(view.size(), view.type(), view.ptr());
+ EXPECT_TRUE(cv::descr_of(this->cloneDeviceMat()) == this->rmat().desc());
+ this->expectDeviceDataEqual(matFromDevice);
+}
+
+static Mat asMat(RMat::View& view) {
+ return Mat(view.size(), view.type(), view.ptr(), view.step());
+}
+
+TYPED_TEST(RMatTypedTest, BasicWorkflow) {
+ {
+ auto view = this->rmat().access(RMat::Access::R);
+ this->expectDeviceDataEqual(asMat(view));
+ }
+ this->expectNoCallbackCalled();
+
+ cv::Mat dataToWrite = this->cloneDeviceMat();
+ randomizeMat(dataToWrite);
+ this->expectDeviceDataNotEqual(dataToWrite);
+ {
+ auto view = this->rmat().access(RMat::Access::W);
+ dataToWrite.copyTo(asMat(view));
+ }
+ this->expectCallbackCalled();
+ this->expectDeviceDataEqual(dataToWrite);
+}
+
+TEST(RMat, TestEmptyAdapter) {
+ RMat rmat;
+ EXPECT_ANY_THROW(rmat.get<RMatAdapterCopy>());
+}
+
+TYPED_TEST(RMatTypedTest, CorrectAdapterCast) {
+ using T = typename TestFixture::Type::AdapterT;
+ EXPECT_NE(nullptr, this->rmat().template get<T>());
+}
+
+class DummyAdapter : public RMat::Adapter {
+ virtual RMat::View access(RMat::Access) const override { return {}; }
+ virtual cv::GMatDesc desc() const override { return {}; }
+};
+
+TYPED_TEST(RMatTypedTest, IncorrectAdapterCast) {
+ EXPECT_EQ(nullptr, this->rmat().template get<DummyAdapter>());
+}
+
+class RMatAdapterForBackend : public RMat::Adapter {
+ int m_i;
+public:
+ RMatAdapterForBackend(int i) : m_i(i) {}
+ virtual RMat::View access(RMat::Access) const override { return {}; }
+ virtual GMatDesc desc() const override { return {}; }
+ int deviceSpecificData() const { return m_i; }
+};
+
+// RMat's usage scenario in the backend:
+// we have some specific data hidden under RMat,
+// test that we can obtain it via RMat.as<T>() method
+TEST(RMat, UsageInBackend) {
+ int i = std::rand();
+ auto rmat = cv::make_rmat<RMatAdapterForBackend>(i);
+
+ auto adapter = rmat.get<RMatAdapterForBackend>();
+ EXPECT_NE(nullptr, adapter);
+ EXPECT_EQ(i, adapter->deviceSpecificData());
+}
+} // namespace opencv_test
--- /dev/null
+// 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) 2020 Intel Corporation
+
+#include "../test_precomp.hpp"
+#include <opencv2/gapi/rmat.hpp>
+
+#include <opencv2/gapi/util/compiler_hints.hpp>
+#include "../src/backends/common/gbackend.hpp"
+
+namespace opencv_test
+{
+using cv::GMatDesc;
+using View = cv::RMat::View;
+using cv::Mat;
+using namespace ::testing;
+
+static void expect_eq_desc(const View& view, const GMatDesc& desc) {
+ EXPECT_EQ(view.size(), desc.size);
+ EXPECT_EQ(view.dims(), desc.dims);
+ EXPECT_EQ(view.cols(), desc.size.width);
+ EXPECT_EQ(view.rows(), desc.size.height);
+ EXPECT_EQ(view.type(), CV_MAKE_TYPE(desc.depth,desc.chan));
+ EXPECT_EQ(view.depth(), desc.depth);
+ EXPECT_EQ(view.chan(), desc.chan);
+}
+
+TEST(RMatView, TestDefaultConstruction) {
+ View view;
+ GMatDesc desc{};
+ expect_eq_desc(view, desc);
+ EXPECT_EQ(view.ptr(), nullptr);
+ EXPECT_EQ(view.step(), 0u);
+}
+
+struct RMatViewTest : public TestWithParam<int /*dataType*/>{};
+TEST_P(RMatViewTest, ConstructionFromMat) {
+ auto type = GetParam();
+ Mat mat(8,8,type);
+ const auto desc = cv::descr_of(mat);
+ View view(cv::descr_of(mat), mat.ptr(), mat.step1());
+ expect_eq_desc(view, desc);
+ EXPECT_EQ(view.ptr(), mat.ptr());
+ EXPECT_EQ(view.step(), mat.step1());
+}
+
+TEST(RMatView, TestConstructionFromMatND) {
+ std::vector<int> dims(4, 8);
+ Mat mat(dims, CV_8UC1);
+ const auto desc = cv::descr_of(mat);
+ View view(cv::descr_of(mat), mat.ptr());
+ expect_eq_desc(view, desc);
+ EXPECT_EQ(view.ptr(), mat.ptr());
+}
+
+TEST_P(RMatViewTest, DefaultStep) {
+ auto type = GetParam();
+ GMatDesc desc;
+ desc.chan = CV_MAT_CN(type);
+ desc.depth = CV_MAT_DEPTH(type);
+ desc.size = {8,8};
+ std::vector<unsigned char> data(desc.size.width*desc.size.height*CV_ELEM_SIZE(type));
+ View view(desc, data.data());
+ EXPECT_EQ(view.step(), static_cast<size_t>(desc.size.width)*CV_ELEM_SIZE(type));
+}
+
+static Mat asMat(View& view) {
+ return Mat(view.size(), view.type(), view.ptr(), view.step());
+}
+
+TEST_P(RMatViewTest, NonDefaultStepInput) {
+ auto type = GetParam();
+ Mat bigMat(16,16,type);
+ cv::randn(bigMat, cv::Scalar::all(127), cv::Scalar::all(40));
+ Mat mat = bigMat(cv::Rect{4,4,8,8});
+ View view(cv::descr_of(mat), mat.data, mat.step);
+ const auto viewMat = asMat(view);
+ Mat ref, out;
+ cv::Size ksize{1,1};
+ cv::blur(viewMat, out, ksize);
+ cv::blur( mat, ref, ksize);
+ EXPECT_EQ(0, cvtest::norm(ref, out, NORM_INF));
+}
+
+TEST_P(RMatViewTest, NonDefaultStepOutput) {
+ auto type = GetParam();
+ Mat mat(8,8,type);
+ cv::randn(mat, cv::Scalar::all(127), cv::Scalar::all(40));
+ Mat bigMat = Mat::zeros(16,16,type);
+ Mat out = bigMat(cv::Rect{4,4,8,8});
+ View view(cv::descr_of(out), out.ptr(), out.step);
+ auto viewMat = asMat(view);
+ Mat ref;
+ cv::Size ksize{1,1};
+ cv::blur(mat, viewMat, ksize);
+ cv::blur(mat, ref, ksize);
+ EXPECT_EQ(0, cvtest::norm(ref, out, NORM_INF));
+}
+
+INSTANTIATE_TEST_CASE_P(Test, RMatViewTest,
+ Values(CV_8UC1, CV_8UC3, CV_32FC1));
+
+struct RMatViewCallbackTest : public ::testing::Test {
+ RMatViewCallbackTest()
+ : mat(8,8,CV_8UC1), view(cv::descr_of(mat), mat.ptr(), mat.step1(), [this](){ callbackCalls++; }) {
+ cv::randn(mat, cv::Scalar::all(127), cv::Scalar::all(40));
+ }
+ int callbackCalls = 0;
+ Mat mat;
+ View view;
+};
+
+TEST_F(RMatViewCallbackTest, MoveCopy) {
+ {
+ View copy(std::move(view));
+ cv::util::suppress_unused_warning(copy);
+ EXPECT_EQ(callbackCalls, 0);
+ }
+ EXPECT_EQ(callbackCalls, 1);
+}
+
+static int firstElement(const View& view) { return *view.ptr(); }
+static void setFirstElement(View& view, uchar value) { *view.ptr() = value; }
+
+TEST_F(RMatViewCallbackTest, MagazineInteraction) {
+ cv::gimpl::magazine::Class<View> mag;
+ constexpr int rc = 1;
+ constexpr uchar value = 11;
+ mag.slot<View>()[rc] = std::move(view);
+ {
+ auto& mag_view = mag.slot<View>()[rc];
+ setFirstElement(mag_view, value);
+ auto mag_el = firstElement(mag_view);
+ EXPECT_EQ(mag_el, value);
+ }
+ {
+ const auto& mag_view = mag.slot<View>()[rc];
+ auto mag_el = firstElement(mag_view);
+ EXPECT_EQ(mag_el, value);
+ }
+ EXPECT_EQ(callbackCalls, 0);
+ mag.slot<View>().erase(rc);
+ EXPECT_EQ(callbackCalls, 1);
+}
+} // namespace opencv_test
--- /dev/null
+#include "../test_precomp.hpp"
+
+#include "backends/common/serialization.hpp"
+
+namespace opencv_test {
+
+struct S11N_Basic: public ::testing::Test {
+ template<typename T> void put(T &&t) {
+ cv::gimpl::s11n::ByteMemoryOutStream os;
+ os << t;
+ m_buffer = os.data();
+ }
+
+ template<typename T> T get() {
+ // FIXME: This stream API needs a fix-up
+ cv::gimpl::s11n::ByteMemoryInStream is(m_buffer);
+ T t{};
+ is >> t;
+ return t;
+ }
+
+private:
+ std::vector<char> m_buffer;
+};
+
+namespace
+{
+ template<typename T>
+ bool operator==(const cv::detail::VectorRef& a, const cv::detail::VectorRef& b)
+ {
+ return a.rref<T>() == b.rref<T>();
+ }
+
+ template<typename T>
+ bool operator==(const cv::detail::OpaqueRef& a, const cv::detail::OpaqueRef& b)
+ {
+ return a.rref<T>() == b.rref<T>();
+ }
+}
+
+TEST_F(S11N_Basic, Test_int_pos) {
+ int x = 42;
+ put(x);
+ EXPECT_EQ(x, get<int>());
+}
+
+TEST_F(S11N_Basic, Test_int_neg) {
+ int x = -42;
+ put(x);
+ EXPECT_EQ(x, get<int>());
+}
+
+TEST_F(S11N_Basic, Test_fp32) {
+ float x = 3.14f;
+ put(x);
+ EXPECT_EQ(x, get<float>());
+}
+
+TEST_F(S11N_Basic, Test_fp64) {
+ double x = 3.14;
+ put(x);
+ EXPECT_EQ(x, get<double>());
+}
+
+TEST_F(S11N_Basic, Test_vector_int) {
+ std::vector<int> v = {1,2,3};
+ put(v);
+ EXPECT_EQ(v, get<std::vector<int> >());
+}
+
+TEST_F(S11N_Basic, Test_vector_cvSize) {
+ std::vector<cv::Size> v = {
+ cv::Size(640, 480),
+ cv::Size(1280, 1024),
+ };
+ put(v);
+ EXPECT_EQ(v, get<std::vector<cv::Size> >());
+}
+
+TEST_F(S11N_Basic, Test_vector_string) {
+ std::vector<std::string> v = {
+ "hello",
+ "world",
+ "ok!"
+ };
+ put(v);
+ EXPECT_EQ(v, get<std::vector<std::string> >());
+}
+
+TEST_F(S11N_Basic, Test_vector_empty) {
+ std::vector<char> v;
+ put(v);
+ EXPECT_EQ(v, get<std::vector<char> >());
+}
+
+TEST_F(S11N_Basic, Test_variant) {
+ using S = std::string;
+ using V = cv::util::variant<int,S>;
+ V v1{42}, v2{S{"hey"}};
+
+ put(v1);
+ EXPECT_EQ(v1, get<V>());
+
+ put(v2);
+ EXPECT_EQ(v2, get<V>());
+}
+
+TEST_F(S11N_Basic, Test_GArg_int) {
+ const int x = 42;
+ cv::GArg gs(x);
+ put(gs);
+
+ cv::GArg gd = get<cv::GArg>();
+ EXPECT_EQ(cv::detail::ArgKind::OPAQUE_VAL, gd.kind);
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_INT, gd.opaque_kind);
+ EXPECT_EQ(x, gs.get<int>());
+}
+
+TEST_F(S11N_Basic, Test_GArg_Point) {
+ const cv::Point pt{1,2};
+ cv::GArg gs(pt);
+ put(gs);
+
+ cv::GArg gd = get<cv::GArg>();
+ EXPECT_EQ(cv::detail::ArgKind::OPAQUE_VAL, gd.kind);
+ EXPECT_EQ(cv::detail::OpaqueKind::CV_POINT, gd.opaque_kind);
+ EXPECT_EQ(pt, gs.get<cv::Point>());
+}
+
+TEST_F(S11N_Basic, Test_Mat_full) {
+ auto mat = cv::Mat::eye(cv::Size(64,64), CV_8UC3);
+ put(mat);
+ EXPECT_EQ(0, cv::norm(mat, get<cv::Mat>(), cv::NORM_INF));
+}
+
+TEST_F(S11N_Basic, Test_Mat_view) {
+ auto mat = cv::Mat::eye(cv::Size(320,240), CV_8UC3);
+ auto view = mat(cv::Rect(10,15,123,70));
+ put(view);
+ EXPECT_EQ(0, cv::norm(view, get<cv::Mat>(), cv::NORM_INF));
+}
+
+TEST_F(S11N_Basic, Test_MatDesc) {
+ cv::GMatDesc v = { CV_8U, 1, {320,240} };
+ put(v);
+ EXPECT_EQ(v, get<cv::GMatDesc>());
+}
+
+TEST_F(S11N_Basic, Test_MetaArg_MatDesc) {
+ cv::GMatDesc desc = { CV_8U, 1,{ 320,240 } };
+ auto v = cv::GMetaArg{ desc };
+ put(v);
+ cv::GMetaArg out_v = get<cv::GMetaArg>();
+ cv::GMatDesc out_desc = cv::util::get<cv::GMatDesc>(out_v);
+ EXPECT_EQ(desc, out_desc);
+}
+
+TEST_F(S11N_Basic, Test_MetaArgs_MatDesc) {
+ cv::GMatDesc desc1 = { CV_8U, 1,{ 320,240 } };
+ cv::GMatDesc desc2 = { CV_8U, 1,{ 640,480 } };
+ GMetaArgs v;
+ v.resize(2);
+ v[0] = cv::GMetaArg{ desc1 };
+ v[1] = cv::GMetaArg{ desc2 };
+ put(v);
+ cv::GMetaArgs out_v = get<cv::GMetaArgs>();
+ cv::GMatDesc out_desc1 = cv::util::get<cv::GMatDesc>(out_v[0]);
+ cv::GMatDesc out_desc2 = cv::util::get<cv::GMatDesc>(out_v[1]);
+ EXPECT_EQ(desc1, out_desc1);
+ EXPECT_EQ(desc2, out_desc2);
+}
+
+TEST_F(S11N_Basic, Test_MetaArg_Monostate) {
+ GMetaArg v;
+ put(v);
+ cv::GMetaArg out_v = get<cv::GMetaArg>();
+ if (!util::holds_alternative<util::monostate>(out_v))
+ {
+ GTEST_FAIL();
+ }
+}
+
+TEST_F(S11N_Basic, Test_RunArg_Mat) {
+ cv::Mat mat = cv::Mat::eye(cv::Size(64, 64), CV_8UC3);
+ auto v = cv::GRunArg{ mat };
+ put(v);
+ cv::GRunArg out_v = get<cv::GRunArg>();
+ cv::Mat out_mat = cv::util::get<cv::Mat>(out_v);
+ EXPECT_EQ(0, cv::norm(mat, out_mat, cv::NORM_INF));
+}
+
+TEST_F(S11N_Basic, Test_RunArgs_Mat) {
+ cv::Mat mat1 = cv::Mat::eye(cv::Size(64, 64), CV_8UC3);
+ cv::Mat mat2 = cv::Mat::eye(cv::Size(128, 128), CV_8UC3);
+ GRunArgs v;
+ v.resize(2);
+ v[0] = cv::GRunArg{ mat1 };
+ v[1] = cv::GRunArg{ mat2 };
+ put(v);
+ cv::GRunArgs out_v = get<cv::GRunArgs>();
+ cv::Mat out_mat1 = cv::util::get<cv::Mat>(out_v[0]);
+ cv::Mat out_mat2 = cv::util::get<cv::Mat>(out_v[1]);
+ EXPECT_EQ(0, cv::norm(mat1, out_mat1, cv::NORM_INF));
+ EXPECT_EQ(0, cv::norm(mat2, out_mat2, cv::NORM_INF));
+}
+
+TEST_F(S11N_Basic, Test_RunArg_Scalar) {
+ cv::Scalar scalar = cv::Scalar(128, 33, 53);
+ auto v = cv::GRunArg{ scalar };
+ put(v);
+ cv::GRunArg out_v = get<cv::GRunArg>();
+ cv::Scalar out_scalar = cv::util::get<cv::Scalar>(out_v);
+ EXPECT_EQ(scalar, out_scalar);
+}
+
+TEST_F(S11N_Basic, Test_RunArgs_Scalar) {
+ cv::Scalar scalar1 = cv::Scalar(128, 33, 53);
+ cv::Scalar scalar2 = cv::Scalar(64, 15, 23);
+ GRunArgs v;
+ v.resize(2);
+ v[0] = cv::GRunArg{ scalar1 };
+ v[1] = cv::GRunArg{ scalar2 };
+ put(v);
+ cv::GRunArgs out_v = get<cv::GRunArgs>();
+ cv::Scalar out_scalar1 = cv::util::get<cv::Scalar>(out_v[0]);
+ cv::Scalar out_scalar2 = cv::util::get<cv::Scalar>(out_v[1]);
+ EXPECT_EQ(scalar1, out_scalar1);
+ EXPECT_EQ(scalar2, out_scalar2);
+}
+
+TEST_F(S11N_Basic, Test_RunArg_Opaque) {
+ auto op = cv::detail::OpaqueRef(42);
+ auto v = cv::GRunArg{ op };
+ put(v);
+ cv::GRunArg out_v = get<cv::GRunArg>();
+ cv::detail::OpaqueRef out_op = cv::util::get<cv::detail::OpaqueRef>(out_v);
+ EXPECT_TRUE(operator==<int>(op, out_op));
+}
+
+TEST_F(S11N_Basic, Test_RunArgs_Opaque) {
+ cv::detail::OpaqueRef op1 = cv::detail::OpaqueRef(cv::Point(1, 2));
+ cv::detail::OpaqueRef op2 = cv::detail::OpaqueRef(cv::Size(12, 21));
+ GRunArgs v;
+ v.resize(2);
+ v[0] = cv::GRunArg{ op1 };
+ v[1] = cv::GRunArg{ op2 };
+ put(v);
+ cv::GRunArgs out_v = get<cv::GRunArgs>();
+ cv::detail::OpaqueRef out_op1 = cv::util::get<cv::detail::OpaqueRef>(out_v[0]);
+ cv::detail::OpaqueRef out_op2 = cv::util::get<cv::detail::OpaqueRef>(out_v[1]);
+ EXPECT_TRUE(operator==<cv::Point>(op1, out_op1));
+ EXPECT_TRUE(operator==<cv::Size>(op2, out_op2));
+}
+
+TEST_F(S11N_Basic, Test_RunArg_Array) {
+ auto op = cv::detail::VectorRef(std::vector<cv::Mat>{cv::Mat::eye(3, 3, CV_8UC1), cv::Mat::zeros(5, 5, CV_8UC3)});
+
+ auto v = cv::GRunArg{ op };
+ put(v);
+ cv::GRunArg out_v = get<cv::GRunArg>();
+ cv::detail::VectorRef out_op = cv::util::get<cv::detail::VectorRef>(out_v);
+ auto vec1 = op.rref<cv::Mat>();
+ auto vec2 = out_op.rref<cv::Mat>();
+ EXPECT_EQ(0, cv::norm(vec1[0], vec2[0], cv::NORM_INF));
+ EXPECT_EQ(0, cv::norm(vec1[1], vec2[1], cv::NORM_INF));
+}
+
+TEST_F(S11N_Basic, Test_RunArgs_Array) {
+ auto vec_sc = std::vector<cv::Scalar>{cv::Scalar(11), cv::Scalar(31)};
+ auto vec_d = std::vector<double>{0.4, 1.0, 123.55, 22.08};
+ cv::detail::VectorRef op1 = cv::detail::VectorRef(vec_sc);
+ cv::detail::VectorRef op2 = cv::detail::VectorRef(vec_d);
+ GRunArgs v;
+ v.resize(2);
+ v[0] = cv::GRunArg{ op1 };
+ v[1] = cv::GRunArg{ op2 };
+ put(v);
+ cv::GRunArgs out_v = get<cv::GRunArgs>();
+ cv::detail::VectorRef out_op1 = cv::util::get<cv::detail::VectorRef>(out_v[0]);
+ cv::detail::VectorRef out_op2 = cv::util::get<cv::detail::VectorRef>(out_v[1]);
+ EXPECT_TRUE(operator==<cv::Scalar>(op1, out_op1));
+ EXPECT_TRUE(operator==<double>(op2, out_op2));
+}
+
+TEST_F(S11N_Basic, Test_RunArgs_MatScalar) {
+ cv::Mat mat = cv::Mat::eye(cv::Size(64, 64), CV_8UC3);
+ cv::Scalar scalar = cv::Scalar(128, 33, 53);
+ GRunArgs v;
+ v.resize(2);
+ v[0] = cv::GRunArg{ mat };
+ v[1] = cv::GRunArg{ scalar };
+ put(v);
+ cv::GRunArgs out_v = get<cv::GRunArgs>();
+ unsigned int i = 0;
+ for (auto it : out_v)
+ {
+ using T = cv::GRunArg;
+ switch (it.index())
+ {
+ case T::index_of<cv::Mat>() :
+ {
+ cv::Mat out_mat = cv::util::get<cv::Mat>(out_v[i]);
+ EXPECT_EQ(0, cv::norm(mat, out_mat, cv::NORM_INF));
+ } break;
+ case T::index_of<cv::Scalar>() :
+ {
+ cv::Scalar out_scalar = cv::util::get<cv::Scalar>(out_v[i]);
+ EXPECT_EQ(scalar, out_scalar);
+ } break;
+ default:
+ GAPI_Assert(false && "This value type is not supported!"); // ...maybe because of STANDALONE mode.
+ break;
+ }
+ i++;
+ }
+}
+
+TEST_F(S11N_Basic, Test_Bind_RunArgs_MatScalar) {
+ cv::Mat mat = cv::Mat::eye(cv::Size(128, 64), CV_8UC3);
+ cv::Scalar scalar = cv::Scalar(128, 33, 53);
+ GRunArgs v;
+ v.resize(2);
+ v[0] = cv::GRunArg{ mat };
+ v[1] = cv::GRunArg{ scalar };
+ GRunArgsP output = cv::gapi::bind(v);
+ unsigned int i = 0;
+ for (auto it : output)
+ {
+ using T = cv::GRunArgP;
+ switch (it.index())
+ {
+ case T::index_of<cv::Mat*>() :
+ {
+ cv::Mat* out_mat = cv::util::get<cv::Mat*>(it);
+ EXPECT_EQ(mat.size(), out_mat->size());
+ } break;
+ case T::index_of<cv::Scalar*>() :
+ {
+ cv::Scalar* out_scalar = cv::util::get<cv::Scalar*>(it);
+ EXPECT_EQ(out_scalar->val[0], scalar.val[0]);
+ EXPECT_EQ(out_scalar->val[1], scalar.val[1]);
+ EXPECT_EQ(out_scalar->val[2], scalar.val[2]);
+ } break;
+ default:
+ GAPI_Assert(false && "This value type is not supported!"); // ...maybe because of STANDALONE mode.
+ break;
+ }
+ i++;
+ }
+}
+} // namespace opencv_test
--- /dev/null
+// 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) 2020 Intel Corporation
+
+
+#include "../test_precomp.hpp"
+
+#include <ade/util/iota_range.hpp>
+#include <opencv2/gapi/s11n.hpp>
+#include "api/render_priv.hpp"
+#include "../common/gapi_render_tests.hpp"
+
+namespace opencv_test
+{
+
+TEST(S11N, Pipeline_Crop_Rect)
+{
+ cv::Rect rect_to{ 4,10,37,50 };
+ cv::Size sz_in = cv::Size(1920, 1080);
+ cv::Size sz_out = cv::Size(37, 50);
+ cv::Mat in_mat = cv::Mat::eye(sz_in, CV_8UC1);
+ cv::Mat out_mat_gapi(sz_out, CV_8UC1);
+ cv::Mat out_mat_ocv(sz_out, CV_8UC1);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::GMat in;
+ auto out = cv::gapi::crop(in, rect_to);
+ auto p = cv::gapi::serialize(cv::GComputation(in, out));
+ auto c = cv::gapi::deserialize<cv::GComputation>(p);
+ c.apply(in_mat, out_mat_gapi);
+
+ // OpenCV code /////////////////////////////////////////////////////////////
+ {
+ out_mat_ocv = in_mat(rect_to);
+ }
+ // Comparison //////////////////////////////////////////////////////////////
+ {
+ EXPECT_EQ(0, cvtest::norm(out_mat_ocv, out_mat_gapi, NORM_INF));
+ }
+}
+
+
+TEST(S11N, Pipeline_Canny_Bool)
+{
+ const cv::Size sz_in(1280, 720);
+ cv::GMat in;
+ double thrLow = 120.0;
+ double thrUp = 240.0;
+ int apSize = 5;
+ bool l2gr = true;
+ cv::Mat in_mat = cv::Mat::eye(1280, 720, CV_8UC1);
+ cv::Mat out_mat_gapi(sz_in, CV_8UC1);
+ cv::Mat out_mat_ocv(sz_in, CV_8UC1);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ auto out = cv::gapi::Canny(in, thrLow, thrUp, apSize, l2gr);
+ auto p = cv::gapi::serialize(cv::GComputation(in, out));
+ auto c = cv::gapi::deserialize<cv::GComputation>(p);
+ c.apply(in_mat, out_mat_gapi);
+
+ // OpenCV code /////////////////////////////////////////////////////////////
+ {
+ cv::Canny(in_mat, out_mat_ocv, thrLow, thrUp, apSize, l2gr);
+ }
+ // Comparison //////////////////////////////////////////////////////////////
+ EXPECT_EQ(0, cvtest::norm(out_mat_gapi, out_mat_ocv, NORM_INF));
+}
+
+TEST(S11N, Pipeline_Not)
+{
+ cv::GMat in;
+ auto p = cv::gapi::serialize(cv::GComputation(in, cv::gapi::bitwise_not(in)));
+ auto c = cv::gapi::deserialize<cv::GComputation>(p);
+
+ cv::Mat in_mat = cv::Mat::eye(32, 32, CV_8UC1);
+ cv::Mat ref_mat = ~in_mat;
+
+ cv::Mat out_mat;
+ c.apply(in_mat, out_mat);
+ EXPECT_EQ(0, cvtest::norm(out_mat, ref_mat, NORM_INF));
+
+ out_mat = cv::Mat();
+ auto cc = c.compile(cv::descr_of(in_mat));
+ cc(in_mat, out_mat);
+ EXPECT_EQ(0, cvtest::norm(out_mat, ref_mat, NORM_INF));
+}
+
+TEST(S11N, Pipeline_Sum_Scalar)
+{
+ cv::GMat in;
+ auto p = cv::gapi::serialize(cv::GComputation(in, cv::gapi::sum(in)));
+ auto c = cv::gapi::deserialize<cv::GComputation>(p);
+
+ cv::Mat in_mat = cv::Mat::eye(32, 32, CV_8UC1);
+ cv::Scalar ref_scl = cv::sum(in_mat);
+
+ cv::Scalar out_scl;
+ c.apply(in_mat, out_scl);
+ EXPECT_EQ(out_scl, ref_scl);
+
+ out_scl = cv::Scalar();
+ auto cc = c.compile(cv::descr_of(in_mat));
+ cc(in_mat, out_scl);
+ EXPECT_EQ(out_scl, ref_scl);
+}
+
+TEST(S11N, Pipeline_BinaryOp)
+{
+ cv::GMat a, b;
+ auto p = cv::gapi::serialize(cv::GComputation(a, b, cv::gapi::add(a, b)));
+ auto c = cv::gapi::deserialize<cv::GComputation>(p);
+
+ cv::Mat in_mat = cv::Mat::eye(32, 32, CV_8UC1);
+ cv::Mat ref_mat = (in_mat + in_mat);
+
+ cv::Mat out_mat;
+ c.apply(in_mat, in_mat, out_mat);
+ EXPECT_EQ(0, cvtest::norm(out_mat, ref_mat, NORM_INF));
+
+ out_mat = cv::Mat();
+ auto cc = c.compile(cv::descr_of(in_mat), cv::descr_of(in_mat));
+ cc(in_mat, in_mat, out_mat);
+ EXPECT_EQ(0, cvtest::norm(out_mat, ref_mat, NORM_INF));
+}
+
+TEST(S11N, Pipeline_Binary_Sum_Scalar)
+{
+ cv::GMat a, b;
+ auto p = cv::gapi::serialize(cv::GComputation(a, b, cv::gapi::sum(a + b)));
+ auto c = cv::gapi::deserialize<cv::GComputation>(p);
+
+ cv::Mat in_mat = cv::Mat::eye(32, 32, CV_8UC1);
+ cv::Scalar ref_scl = cv::sum(in_mat + in_mat);
+ cv::Scalar out_scl;
+ c.apply(in_mat, in_mat, out_scl);
+ EXPECT_EQ(out_scl, ref_scl);
+
+ out_scl = cv::Scalar();
+ auto cc = c.compile(cv::descr_of(in_mat), cv::descr_of(in_mat));
+ cc(in_mat, in_mat, out_scl);
+ EXPECT_EQ(out_scl, ref_scl);
+}
+
+TEST(S11N, Pipeline_Sharpen)
+{
+ const cv::Size sz_in (1280, 720);
+ const cv::Size sz_out( 640, 480);
+ cv::Mat in_mat (sz_in, CV_8UC3);
+ in_mat = cv::Scalar(128, 33, 53);
+
+ cv::Mat out_mat(sz_out, CV_8UC3);
+ cv::Mat out_mat_y;
+ cv::Mat out_mat_ocv(sz_out, CV_8UC3);
+
+ float sharpen_coeffs[] = {
+ 0.0f, -1.f, 0.0f,
+ -1.0f, 5.f, -1.0f,
+ 0.0f, -1.f, 0.0f
+ };
+ cv::Mat sharpen_kernel(3, 3, CV_32F, sharpen_coeffs);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::GMat in;
+ auto vga = cv::gapi::resize(in, sz_out);
+ auto yuv = cv::gapi::RGB2YUV(vga);
+ auto yuv_p = cv::gapi::split3(yuv);
+ auto y_sharp = cv::gapi::filter2D(std::get<0>(yuv_p), -1, sharpen_kernel);
+ auto yuv_new = cv::gapi::merge3(y_sharp, std::get<1>(yuv_p), std::get<2>(yuv_p));
+ auto out = cv::gapi::YUV2RGB(yuv_new);
+
+ auto p = cv::gapi::serialize(cv::GComputation(cv::GIn(in), cv::GOut(y_sharp, out)));
+ auto c = cv::gapi::deserialize<cv::GComputation>(p);
+ c.apply(cv::gin(in_mat), cv::gout(out_mat_y, out_mat));
+
+ // OpenCV code /////////////////////////////////////////////////////////////
+ {
+ cv::Mat smaller;
+ cv::resize(in_mat, smaller, sz_out);
+
+ cv::Mat yuv_mat;
+ cv::cvtColor(smaller, yuv_mat, cv::COLOR_RGB2YUV);
+ std::vector<cv::Mat> yuv_planar(3);
+ cv::split(yuv_mat, yuv_planar);
+ cv::filter2D(yuv_planar[0], yuv_planar[0], -1, sharpen_kernel);
+ cv::merge(yuv_planar, yuv_mat);
+ cv::cvtColor(yuv_mat, out_mat_ocv, cv::COLOR_YUV2RGB);
+ }
+
+ // Comparison //////////////////////////////////////////////////////////////
+ {
+ cv::Mat diff = out_mat_ocv != out_mat;
+ std::vector<cv::Mat> diffBGR(3);
+ cv::split(diff, diffBGR);
+ EXPECT_EQ(0, cvtest::norm(diffBGR[0], NORM_INF));
+ EXPECT_EQ(0, cvtest::norm(diffBGR[1], NORM_INF));
+ EXPECT_EQ(0, cvtest::norm(diffBGR[2], NORM_INF));
+ }
+
+ // Metadata check /////////////////////////////////////////////////////////
+ {
+ auto cc = c.compile(cv::descr_of(in_mat));
+ auto metas = cc.outMetas();
+ ASSERT_EQ(2u, metas.size());
+
+ auto out_y_meta = cv::util::get<cv::GMatDesc>(metas[0]);
+ auto out_meta = cv::util::get<cv::GMatDesc>(metas[1]);
+
+ // Y-output
+ EXPECT_EQ(CV_8U, out_y_meta.depth);
+ EXPECT_EQ(1, out_y_meta.chan);
+ EXPECT_EQ(640, out_y_meta.size.width);
+ EXPECT_EQ(480, out_y_meta.size.height);
+
+ // Final output
+ EXPECT_EQ(CV_8U, out_meta.depth);
+ EXPECT_EQ(3, out_meta.chan);
+ EXPECT_EQ(640, out_meta.size.width);
+ EXPECT_EQ(480, out_meta.size.height);
+ }
+}
+
+TEST(S11N, Pipeline_CustomRGB2YUV)
+{
+ const cv::Size sz(1280, 720);
+ const int INS = 3;
+ std::vector<cv::Mat> in_mats(INS);
+ for (auto i : ade::util::iota(INS))
+ {
+ in_mats[i].create(sz, CV_8U);
+ cv::randu(in_mats[i], cv::Scalar::all(0), cv::Scalar::all(255));
+ }
+
+ const int OUTS = 3;
+ std::vector<cv::Mat> out_mats_cv(OUTS);
+ std::vector<cv::Mat> out_mats_gapi(OUTS);
+ for (auto i : ade::util::iota(OUTS))
+ {
+ out_mats_cv[i].create(sz, CV_8U);
+ out_mats_gapi[i].create(sz, CV_8U);
+ }
+
+ // G-API code //////////////////////////////////////////////////////////////
+ {
+ cv::GMat r, g, b;
+ cv::GMat y = 0.299f*r + 0.587f*g + 0.114f*b;
+ cv::GMat u = 0.492f*(b - y);
+ cv::GMat v = 0.877f*(r - y);
+
+ auto p = cv::gapi::serialize(cv::GComputation({r, g, b}, {y, u, v}));
+ auto c = cv::gapi::deserialize<cv::GComputation>(p);
+ c.apply(in_mats, out_mats_gapi);
+ }
+
+ // OpenCV code /////////////////////////////////////////////////////////////
+ {
+ cv::Mat r = in_mats[0], g = in_mats[1], b = in_mats[2];
+ cv::Mat y = 0.299f*r + 0.587f*g + 0.114f*b;
+ cv::Mat u = 0.492f*(b - y);
+ cv::Mat v = 0.877f*(r - y);
+
+ out_mats_cv[0] = y;
+ out_mats_cv[1] = u;
+ out_mats_cv[2] = v;
+ }
+
+ // Comparison //////////////////////////////////////////////////////////////
+ {
+ const auto diff = [](cv::Mat m1, cv::Mat m2, int t) {
+ return cv::abs(m1 - m2) > t;
+ };
+
+ // FIXME: Not bit-accurate even now!
+ cv::Mat
+ diff_y = diff(out_mats_cv[0], out_mats_gapi[0], 2),
+ diff_u = diff(out_mats_cv[1], out_mats_gapi[1], 2),
+ diff_v = diff(out_mats_cv[2], out_mats_gapi[2], 2);
+
+ EXPECT_EQ(0, cvtest::norm(diff_y, NORM_INF));
+ EXPECT_EQ(0, cvtest::norm(diff_u, NORM_INF));
+ EXPECT_EQ(0, cvtest::norm(diff_v, NORM_INF));
+ }
+}
+
+namespace ThisTest
+{
+ using GOpBool = GOpaque<bool>;
+ using GOpInt = GOpaque<int>;
+ using GOpDouble = GOpaque<double>;
+ using GOpPoint = GOpaque<cv::Point>;
+ using GOpSize = GOpaque<cv::Size>;
+ using GOpRect = GOpaque<cv::Rect>;
+
+ using GOpOut = std::tuple<GOpPoint, GOpSize, GOpRect>;
+
+ G_TYPED_KERNEL_M(OpGenerate, <GOpOut(GOpBool, GOpInt, GOpDouble)>, "test.s11n.gopaque")
+ {
+ static std::tuple<GOpaqueDesc, GOpaqueDesc, GOpaqueDesc> outMeta(const GOpaqueDesc&, const GOpaqueDesc&, const GOpaqueDesc&) {
+ return std::make_tuple(empty_gopaque_desc(), empty_gopaque_desc(), empty_gopaque_desc());
+ }
+ };
+
+ GAPI_OCV_KERNEL(OCVOpGenerate, OpGenerate)
+ {
+ static void run(const bool& b, const int& i, const double& d,
+ cv::Point& p, cv::Size& s, cv::Rect& r)
+ {
+ p = cv::Point(i, i*2);
+ s = b ? cv::Size(42, 42) : cv::Size(7, 7);
+ int ii = static_cast<int>(d);
+ r = cv::Rect(ii, ii, ii, ii);
+ }
+ };
+
+ using GArrInt = GArray<int>;
+ using GArrDouble = GArray<double>;
+ using GArrPoint = GArray<cv::Point>;
+ using GArrSize = GArray<cv::Size>;
+ using GArrRect = GArray<cv::Rect>;
+ using GArrMat = GArray<cv::Mat>;
+ using GArrScalar = GArray<cv::Scalar>;
+
+ using GArrOut = std::tuple<GArrPoint, GArrSize, GArrRect, GArrMat>;
+
+ G_TYPED_KERNEL_M(ArrGenerate, <GArrOut(GArrInt, GArrInt, GArrDouble, GArrScalar)>, "test.s11n.garray")
+ {
+ static std::tuple<GArrayDesc, GArrayDesc, GArrayDesc, GArrayDesc> outMeta(const GArrayDesc&, const GArrayDesc&,
+ const GArrayDesc&, const GArrayDesc&) {
+ return std::make_tuple(empty_array_desc(), empty_array_desc(), empty_array_desc(), empty_array_desc());
+ }
+ };
+
+ GAPI_OCV_KERNEL(OCVArrGenerate, ArrGenerate)
+ {
+ static void run(const std::vector<int>& b, const std::vector<int>& i,
+ const std::vector<double>& d, const std::vector<cv::Scalar>& sc,
+ std::vector<cv::Point>& p, std::vector<cv::Size>& s,
+ std::vector<cv::Rect>& r, std::vector<cv::Mat>& m)
+ {
+ p.clear(); p.resize(b.size());
+ s.clear(); s.resize(b.size());
+ r.clear(); r.resize(b.size());
+ m.clear(); m.resize(b.size());
+
+ for (std::size_t idx = 0; idx < b.size(); ++idx)
+ {
+ p[idx] = cv::Point(i[idx], i[idx]*2);
+ s[idx] = b[idx] == 1 ? cv::Size(42, 42) : cv::Size(7, 7);
+ int ii = static_cast<int>(d[idx]);
+ r[idx] = cv::Rect(ii, ii, ii, ii);
+ m[idx] = cv::Mat(3, 3, CV_8UC1, sc[idx]);
+ }
+ }
+ };
+
+ G_TYPED_KERNEL_M(OpArrK1, <std::tuple<GArrInt,GOpSize>(GOpInt, GArrSize)>, "test.s11n.oparrk1")
+ {
+ static std::tuple<GArrayDesc, GOpaqueDesc> outMeta(const GOpaqueDesc&, const GArrayDesc&) {
+ return std::make_tuple(empty_array_desc(), empty_gopaque_desc());
+ }
+ };
+
+ GAPI_OCV_KERNEL(OCVOpArrK1, OpArrK1)
+ {
+ static void run(const int& i, const std::vector<cv::Size>& vs,
+ std::vector<int>& vi, cv::Size& s)
+ {
+ vi.clear(); vi.resize(vs.size());
+ s = cv::Size(i, i);
+ for (std::size_t idx = 0; idx < vs.size(); ++ idx)
+ vi[idx] = vs[idx].area();
+ }
+ };
+
+ G_TYPED_KERNEL_M(OpArrK2, <std::tuple<GOpDouble,GArrPoint>(GArrInt, GOpSize)>, "test.s11n.oparrk2")
+ {
+ static std::tuple<GOpaqueDesc, GArrayDesc> outMeta(const GArrayDesc&, const GOpaqueDesc&) {
+ return std::make_tuple(empty_gopaque_desc(), empty_array_desc());
+ }
+ };
+
+ GAPI_OCV_KERNEL(OCVOpArrK2, OpArrK2)
+ {
+ static void run(const std::vector<int>& vi, const cv::Size& s,
+ double& d, std::vector<cv::Point>& vp)
+ {
+ vp.clear(); vp.resize(vi.size());
+ d = s.area() * 1.5;
+ for (std::size_t idx = 0; idx < vi.size(); ++ idx)
+ vp[idx] = cv::Point(vi[idx], vi[idx]);
+ }
+ };
+} // namespace ThisTest
+
+TEST(S11N, Pipeline_GOpaque)
+{
+ using namespace ThisTest;
+ GOpBool in1;
+ GOpInt in2;
+ GOpDouble in3;
+
+ auto out = OpGenerate::on(in1, in2, in3);
+ cv::GComputation c(cv::GIn(in1, in2, in3), cv::GOut(std::get<0>(out), std::get<1>(out), std::get<2>(out)));
+
+ auto p = cv::gapi::serialize(c);
+ auto dc = cv::gapi::deserialize<cv::GComputation>(p);
+
+ bool b = true;
+ int i = 33;
+ double d = 128.7;
+ cv::Point pp;
+ cv::Size s;
+ cv::Rect r;
+ dc.apply(cv::gin(b, i, d), cv::gout(pp, s, r), cv::compile_args(cv::gapi::kernels<OCVOpGenerate>()));
+
+ EXPECT_EQ(pp, cv::Point(i, i*2));
+ EXPECT_EQ(s, cv::Size(42, 42));
+ int ii = static_cast<int>(d);
+ EXPECT_EQ(r, cv::Rect(ii, ii, ii, ii));
+}
+
+TEST(S11N, Pipeline_GArray)
+{
+ using namespace ThisTest;
+ GArrInt in1, in2;
+ GArrDouble in3;
+ GArrScalar in4;
+
+ auto out = ArrGenerate::on(in1, in2, in3, in4);
+ cv::GComputation c(cv::GIn(in1, in2, in3, in4),
+ cv::GOut(std::get<0>(out), std::get<1>(out),
+ std::get<2>(out), std::get<3>(out)));
+
+ auto p = cv::gapi::serialize(c);
+ auto dc = cv::gapi::deserialize<cv::GComputation>(p);
+
+ std::vector<int> b {1, 0, -1};
+ std::vector<int> i {3, 0 , 59};
+ std::vector<double> d {0.7, 120.5, 44.14};
+ std::vector<cv::Scalar> sc {cv::Scalar::all(10), cv::Scalar::all(15), cv::Scalar::all(99)};
+ std::vector<cv::Point> pp;
+ std::vector<cv::Size> s;
+ std::vector<cv::Rect> r;
+ std::vector<cv::Mat> m;
+ dc.apply(cv::gin(b, i, d, sc), cv::gout(pp, s, r, m), cv::compile_args(cv::gapi::kernels<OCVArrGenerate>()));
+
+ for (std::size_t idx = 0; idx < b.size(); ++idx)
+ {
+ EXPECT_EQ(pp[idx], cv::Point(i[idx], i[idx]*2));
+ EXPECT_EQ(s[idx], b[idx] == 1 ? cv::Size(42, 42) : cv::Size(7, 7));
+ int ii = static_cast<int>(d[idx]);
+ EXPECT_EQ(r[idx], cv::Rect(ii, ii, ii, ii));
+ }
+}
+
+TEST(S11N, Pipeline_GArray_GOpaque_Multinode)
+{
+ using namespace ThisTest;
+ GOpInt in1;
+ GArrSize in2;
+
+ auto tmp = OpArrK1::on(in1, in2);
+ auto out = OpArrK2::on(std::get<0>(tmp), std::get<1>(tmp));
+
+ cv::GComputation c(cv::GIn(in1, in2),
+ cv::GOut(std::get<0>(out), std::get<1>(out)));
+
+ auto p = cv::gapi::serialize(c);
+ auto dc = cv::gapi::deserialize<cv::GComputation>(p);
+
+ int i = 42;
+ std::vector<cv::Size> s{cv::Size(11, 22), cv::Size(13, 18)};
+ double d;
+ std::vector<cv::Point> pp;
+
+ dc.apply(cv::gin(i, s), cv::gout(d, pp), cv::compile_args(cv::gapi::kernels<OCVOpArrK1, OCVOpArrK2>()));
+
+ auto st = cv::Size(i ,i);
+ EXPECT_EQ(d, st.area() * 1.5);
+
+ for (std::size_t idx = 0; idx < s.size(); ++idx)
+ {
+ EXPECT_EQ(pp[idx], cv::Point(s[idx].area(), s[idx].area()));
+ }
+}
+
+TEST(S11N, Pipeline_Render_NV12)
+{
+ cv::Size sz (100, 200);
+ int rects_num = 10;
+ int text_num = 10;
+ int image_num = 10;
+
+ int thick = 2;
+ int lt = LINE_8;
+ cv::Scalar color(111, 222, 77);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+
+ // Rects
+ int shift = 0;
+ for (int i = 0; i < rects_num; ++i) {
+ cv::Rect rect(200 + i, 200 + i, 200, 200);
+ prims.emplace_back(cv::gapi::wip::draw::Rect(rect, color, thick, lt, shift));
+ }
+
+ // Mosaic
+ int cellsz = 50;
+ int decim = 0;
+ for (int i = 0; i < rects_num; ++i) {
+ cv::Rect mos(200 + i, 200 + i, 200, 200);
+ prims.emplace_back(cv::gapi::wip::draw::Mosaic(mos, cellsz, decim));
+ }
+
+ // Text
+ std::string text = "Some text";
+ int ff = FONT_HERSHEY_SIMPLEX;
+ double fs = 2.0;
+ bool blo = false;
+ for (int i = 0; i < text_num; ++i) {
+ cv::Point org(200 + i, 200 + i);
+ prims.emplace_back(cv::gapi::wip::draw::Text(text, org, ff, fs, color, thick, lt, blo));
+ }
+
+ // Image
+ double transparency = 1.0;
+ cv::Rect rect_img(0 ,0 , 50, 50);
+ cv::Mat img(rect_img.size(), CV_8UC3, color);
+ cv::Mat alpha(rect_img.size(), CV_32FC1, transparency);
+ auto tl = rect_img.tl();
+ for (int i = 0; i < image_num; ++i) {
+ cv::Point org_img = {tl.x + i, tl.y + rect_img.size().height + i};
+
+ prims.emplace_back(cv::gapi::wip::draw::Image({org_img, img, alpha}));
+ }
+
+ // Circle
+ cv::Point center(300, 400);
+ int rad = 25;
+ prims.emplace_back(cv::gapi::wip::draw::Circle({center, rad, color, thick, lt, shift}));
+
+ // Line
+ cv::Point point_next(300, 425);
+ prims.emplace_back(cv::gapi::wip::draw::Line({center, point_next, color, thick, lt, shift}));
+
+ // Poly
+ std::vector<cv::Point> points = {{300, 400}, {290, 450}, {348, 410}, {300, 400}};
+ prims.emplace_back(cv::gapi::wip::draw::Poly({points, color, thick, lt, shift}));
+
+ cv::GMat y_in, uv_in, y_out, uv_out;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+ std::tie(y_out, uv_out) = cv::gapi::wip::draw::renderNV12(y_in, uv_in, arr);
+ cv::GComputation comp(cv::GIn(y_in, uv_in, arr), cv::GOut(y_out, uv_out));
+
+ auto serialized = cv::gapi::serialize(comp);
+ auto dc = cv::gapi::deserialize<cv::GComputation>(serialized);
+
+ cv::Mat y(1920, 1080, CV_8UC1);
+ cv::Mat uv(960, 540, CV_8UC2);
+ cv::randu(y, cv::Scalar(0), cv::Scalar(255));
+ cv::randu(uv, cv::Scalar::all(0), cv::Scalar::all(255));
+ cv::Mat y_ref_mat = y.clone(), uv_ref_mat = uv.clone();
+ dc.apply(cv::gin(y, uv, prims), cv::gout(y, uv));
+
+ // OpenCV code //////////////////////////////////////////////////////////////
+ cv::Mat yuv;
+ cv::gapi::wip::draw::cvtNV12ToYUV(y_ref_mat, uv_ref_mat, yuv);
+
+ for (int i = 0; i < rects_num; ++i) {
+ cv::Rect rect(200 + i, 200 + i, 200, 200);
+ cv::rectangle(yuv, rect, cvtBGRToYUVC(color), thick, lt, shift);
+ }
+
+ for (int i = 0; i < rects_num; ++i) {
+ cv::Rect mos(200 + i, 200 + i, 200, 200);
+ drawMosaicRef(yuv, mos, cellsz);
+ }
+
+ for (int i = 0; i < text_num; ++i) {
+ cv::Point org(200 + i, 200 + i);
+ cv::putText(yuv, text, org, ff, fs, cvtBGRToYUVC(color), thick, lt, blo);
+ }
+
+ for (int i = 0; i < image_num; ++i) {
+ cv::Point org_img = {tl.x + i, tl.y + rect_img.size().height + i};
+ cv::Mat yuv_img;
+ cv::cvtColor(img, yuv_img, cv::COLOR_BGR2YUV);
+ blendImageRef(yuv, org_img, yuv_img, alpha);
+ }
+
+ cv::circle(yuv, center, rad, cvtBGRToYUVC(color), thick, lt, shift);
+ cv::line(yuv, center, point_next, cvtBGRToYUVC(color), thick, lt, shift);
+ std::vector<std::vector<cv::Point>> pp{points};
+ cv::fillPoly(yuv, pp, cvtBGRToYUVC(color), lt, shift);
+
+ // YUV -> NV12
+ cv::gapi::wip::draw::cvtYUVToNV12(yuv, y_ref_mat, uv_ref_mat);
+
+ EXPECT_EQ(cv::norm( y, y_ref_mat), 0);
+ EXPECT_EQ(cv::norm(uv, uv_ref_mat), 0);
+}
+
+TEST(S11N, Pipeline_Render_RGB)
+{
+ cv::Size sz (100, 200);
+ int rects_num = 10;
+ int text_num = 10;
+ int image_num = 10;
+
+ int thick = 2;
+ int lt = LINE_8;
+ cv::Scalar color(111, 222, 77);
+
+ // G-API code //////////////////////////////////////////////////////////////
+ cv::gapi::wip::draw::Prims prims;
+
+ // Rects
+ int shift = 0;
+ for (int i = 0; i < rects_num; ++i) {
+ cv::Rect rect(200 + i, 200 + i, 200, 200);
+ prims.emplace_back(cv::gapi::wip::draw::Rect(rect, color, thick, lt, shift));
+ }
+
+ // Mosaic
+ int cellsz = 50;
+ int decim = 0;
+ for (int i = 0; i < rects_num; ++i) {
+ cv::Rect mos(200 + i, 200 + i, 200, 200);
+ prims.emplace_back(cv::gapi::wip::draw::Mosaic(mos, cellsz, decim));
+ }
+
+ // Text
+ std::string text = "Some text";
+ int ff = FONT_HERSHEY_SIMPLEX;
+ double fs = 2.0;
+ bool blo = false;
+ for (int i = 0; i < text_num; ++i) {
+ cv::Point org(200 + i, 200 + i);
+ prims.emplace_back(cv::gapi::wip::draw::Text(text, org, ff, fs, color, thick, lt, blo));
+ }
+
+ // Image
+ double transparency = 1.0;
+ cv::Rect rect_img(0 ,0 , 50, 50);
+ cv::Mat img(rect_img.size(), CV_8UC3, color);
+ cv::Mat alpha(rect_img.size(), CV_32FC1, transparency);
+ auto tl = rect_img.tl();
+ for (int i = 0; i < image_num; ++i) {
+ cv::Point org_img = {tl.x + i, tl.y + rect_img.size().height + i};
+
+ prims.emplace_back(cv::gapi::wip::draw::Image({org_img, img, alpha}));
+ }
+
+ // Circle
+ cv::Point center(300, 400);
+ int rad = 25;
+ prims.emplace_back(cv::gapi::wip::draw::Circle({center, rad, color, thick, lt, shift}));
+
+ // Line
+ cv::Point point_next(300, 425);
+ prims.emplace_back(cv::gapi::wip::draw::Line({center, point_next, color, thick, lt, shift}));
+
+ // Poly
+ std::vector<cv::Point> points = {{300, 400}, {290, 450}, {348, 410}, {300, 400}};
+ prims.emplace_back(cv::gapi::wip::draw::Poly({points, color, thick, lt, shift}));
+
+ cv::GMat in, out;
+ cv::GArray<cv::gapi::wip::draw::Prim> arr;
+ out = cv::gapi::wip::draw::render3ch(in, arr);
+ cv::GComputation comp(cv::GIn(in, arr), cv::GOut(out));
+
+ auto serialized = cv::gapi::serialize(comp);
+ auto dc = cv::gapi::deserialize<cv::GComputation>(serialized);
+
+ cv::Mat input(1920, 1080, CV_8UC3);
+ cv::randu(input, cv::Scalar::all(0), cv::Scalar::all(255));
+ cv::Mat ref_mat = input.clone();
+ dc.apply(cv::gin(input, prims), cv::gout(input));
+
+ // OpenCV code //////////////////////////////////////////////////////////////
+ for (int i = 0; i < rects_num; ++i) {
+ cv::Rect rect(200 + i, 200 + i, 200, 200);
+ cv::rectangle(ref_mat, rect, color, thick, lt, shift);
+ }
+
+ for (int i = 0; i < rects_num; ++i) {
+ cv::Rect mos(200 + i, 200 + i, 200, 200);
+ drawMosaicRef(ref_mat, mos, cellsz);
+ }
+
+ for (int i = 0; i < text_num; ++i) {
+ cv::Point org(200 + i, 200 + i);
+ cv::putText(ref_mat, text, org, ff, fs, color, thick, lt, blo);
+ }
+
+ for (int i = 0; i < image_num; ++i) {
+ cv::Point org_img = {tl.x + i, tl.y + rect_img.size().height + i};
+ blendImageRef(ref_mat, org_img, img, alpha);
+ }
+
+ cv::circle(ref_mat, center, rad, color, thick, lt, shift);
+ cv::line(ref_mat, center, point_next, color, thick, lt, shift);
+ std::vector<std::vector<cv::Point>> pp{points};
+ cv::fillPoly(ref_mat, pp, color, lt, shift);
+
+ EXPECT_EQ(cv::norm(input, ref_mat), 0);
+}
+} // namespace opencv_test
cv::VideoCapture cap;
cap.open(video_path);
+ if (!cap.isOpened())
+ throw SkipTestException("Video file can not be opened");
cv::Mat tmp;
cv::Scalar out_scl;
cv::VideoCapture cap;
cap.open(video_path);
+ if (!cap.isOpened())
+ throw SkipTestException("Video file can not be opened");
cv::Mat tmp;
std::vector<int> ref_vec;
}
};
+// FIXME: (GAPI_Streaming_Types, InputOpaque) test is missing here!
+// FIXME: (GAPI_Streaming_Types, XChangeOpaque) test is missing here!
+// FIXME: (GAPI_Streaming_Types, OutputOpaque) test is missing here!
+
TEST_F(GAPI_Streaming_Unit, TestTwoVideoSourcesFail)
{
const auto c_ptr = gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(findDataFile("cv/video/768x576.avi"));
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
-// Copyright (C) 2018 Intel Corporation
+// Copyright (C) 2018-2020 Intel Corporation
// FIXME: OpenCV header
#include <opencv2/ts.hpp>
#include <opencv2/gapi.hpp>
-#include <opencv2/gapi/imgproc.hpp>
#include <opencv2/gapi/core.hpp>
+#include <opencv2/gapi/imgproc.hpp>
+#include <opencv2/gapi/video.hpp>
#include <opencv2/gapi/cpu/gcpukernel.hpp>
#include <opencv2/gapi/gpu/ggpukernel.hpp>
#include <opencv2/gapi/gpu/imgproc.hpp>
EXPECT_EQ("", util::get<std::string>(vsi));
}
-TEST(Variant, ValueMoveCTor)
+TEST(Variant, ConvertingCTorMove)
{
util::variant<int> vi(42);
EXPECT_EQ(0u, vi.index());
EXPECT_EQ(0u, vsi.index());
EXPECT_EQ("2017", util::get<std::string>(vsi));
+ std::string rvs("2017");
+ util::variant<std::string, int> vsi3(std::move(rvs));
+ EXPECT_EQ(0u, vsi3.index());
+ EXPECT_EQ("2017", util::get<std::string>(vsi3));
+ //C++ standard state that std::string instance that was moved from stays in valid, but unspecified state.
+ //So the best assumption we can made here is that s is not the same as it was before move.
+ EXPECT_NE("2017", rvs) <<"Rvalue source argument was not moved from while should?";
+
util::variant<std::string, int> vsi2(42);
EXPECT_EQ(1u, vsi2.index());
EXPECT_EQ(42, util::get<int>(vsi2));
}
-TEST(Variant, ValueCopyCTor)
+TEST(Variant, ConvertingCTorCopy)
{
const int i42 = 42;
const int i17 = 2017;
const std::string s17 = "2017";
+ std::string s17_lvref = s17;
util::variant<int> vi(i42);
EXPECT_EQ(0u, vi.index());
EXPECT_EQ(0u, vs.index());
EXPECT_EQ(s17, util::get<std::string>(vs));
+ util::variant<std::string> vs_lv(s17_lvref);
+ EXPECT_EQ(0u, vs_lv.index());
+ EXPECT_EQ(s17, s17_lvref);
+ EXPECT_EQ(s17_lvref, util::get<std::string>(vs_lv));
+
util::variant<std::string, int> vsi(s17);
EXPECT_EQ(0u, vsi.index());
EXPECT_EQ(s17, util::get<std::string>(vsi));
EXPECT_EQ("42", util::get<std::string>(vis));
}
+TEST(Variant, Assign_RValueRef_DiffType)
+{
+ TestVar vis(42);
+
+ EXPECT_EQ(0u, vis.index());
+ EXPECT_EQ(42, util::get<int>(vis));
+
+ std::string s("42");
+ vis = std::move(s);
+ EXPECT_EQ(1u, vis.index());
+ EXPECT_EQ("42", util::get<std::string>(vis));
+ //C++ standard state that std::string instance that was moved from stays in valid, but unspecified state.
+ //So the best assumption we can made here is that s is not the same as it was before move.
+ EXPECT_NE("42", s) << "right hand side argument of assignment operation was not moved from while should?";
+}
+
+TEST(Variant, Assign_RValueRef_SameType)
+{
+ TestVar vis(std::string("43"));
+
+ EXPECT_EQ(1u, vis.index());
+ EXPECT_EQ("43", util::get<std::string>(vis));
+
+ std::string s("42");
+ vis = std::move(s);
+ EXPECT_EQ(1u, vis.index());
+ EXPECT_EQ("42", util::get<std::string>(vis));
+ //C++ standard state that std::string instance that was moved from stays in valid, but unspecified state.
+ //So the best assumption we can made here is that s is not the same as it was before move.
+ EXPECT_NE("42", s) << "right hand side argument of assignment operation was not moved from while should?";
+}
+
TEST(Variant, Assign_LValueRef_DiffType)
{
TestVar vis(42);
vis = s;
EXPECT_EQ(1u, vis.index());
EXPECT_EQ("42", util::get<std::string>(vis));
+ EXPECT_EQ("42", s) << "right hand side argument of assignment operation was moved from while should not ?";
}
-TEST(Variant, Assign_ValueUpdate_Const)
+TEST(Variant, Assign_ValueUpdate_Const_Variant)
{
TestVar va(42);
const TestVar vb(43);
EXPECT_EQ(43, util::get<int>(va));
}
-TEST(Variant, Assign_ValueUpdate_Const_DiffType)
+TEST(Variant, Assign_ValueUpdate_Const_DiffType_Variant)
{
TestVar va(42);
const TestVar vb(std::string("42"));
EXPECT_EQ("42", util::get<std::string>(va));
}
-TEST(Variant, Assign_Move)
+TEST(Variant, Assign_Move_Variant)
{
TestVar va(42);
TestVar vb(std::string("42"));
+ TestVar vd(std::string("43"));
TestVar vc(43);
EXPECT_EQ(0u, va.index());
EXPECT_EQ(0u, vc.index());
EXPECT_EQ(43, util::get<int>(vc));
+ EXPECT_EQ(1u, vd.index());
+ EXPECT_EQ("43", util::get<std::string>(vd));
+
va = std::move(vb);
EXPECT_EQ(1u, va.index());
EXPECT_EQ("42", util::get<std::string>(va));
+ EXPECT_EQ(1u, vb.index());
+ EXPECT_EQ("", util::get<std::string>(vb));
+
+
+ vb = std::move(vd);
+ EXPECT_EQ(1u, vb.index());
+ EXPECT_EQ("43", util::get<std::string>(vb));
+
+ EXPECT_EQ(1u, vd.index());
+ EXPECT_EQ("", util::get<std::string>(vd));
+
va = std::move(vc);
EXPECT_EQ(0u, va.index());
EXPECT_EQ(43, util::get<int>(va));
EXPECT_EQ(3.14f, util::get<float>(tv1));
}
+TEST(Variant, GetIf)
+{
+ const TestVar cv(42);
+
+ // Test const& get_if()
+ EXPECT_EQ(nullptr, util::get_if<std::string>(&cv));
+ ASSERT_NE(nullptr, util::get_if<int>(&cv));
+ EXPECT_EQ(42, *util::get_if<int>(&cv));
+
+ // Test &get_if
+ TestVar cv2(std::string("42"));
+ EXPECT_EQ(nullptr, util::get_if<int>(&cv2));
+ ASSERT_NE(nullptr, util::get_if<std::string>(&cv2));
+ EXPECT_EQ("42", *util::get_if<std::string>(&cv2));
+}
+
TEST(Variant, Get)
{
const TestVar cv(42);
-4.3.0
+7c22cd49a7eb76ae1d9606672ee467fb52383de0