Merge pull request #14648 from smirnov-alexey:as/gapi_transform
* Introduce GAPI_TRANSFORM initial interface Comes along with simple tests and kernel package changes * Fix documentation and adjust combine() function * Fix stuff after rebasing on master * Remove redundant functionality * Refactoring according to review feedback provided * Fixes according to review feedback * Reconsider transformations return and fix a warning * Fixes from code review * Add a new simple test * Cleanup, added tests on GScalar, GMatP, GArray
This commit is contained in:
parent
66d7956e67
commit
7f9a9f2a09
@ -2,7 +2,7 @@
|
|||||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
// 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.
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2018 Intel Corporation
|
// Copyright (C) 2018-2019 Intel Corporation
|
||||||
|
|
||||||
|
|
||||||
#ifndef OPENCV_GAPI_GCPUKERNEL_HPP
|
#ifndef OPENCV_GAPI_GCPUKERNEL_HPP
|
||||||
@ -19,6 +19,7 @@
|
|||||||
#include <opencv2/gapi/garg.hpp>
|
#include <opencv2/gapi/garg.hpp>
|
||||||
#include <opencv2/gapi/own/convert.hpp> //to_ocv
|
#include <opencv2/gapi/own/convert.hpp> //to_ocv
|
||||||
#include <opencv2/gapi/util/compiler_hints.hpp> //suppress_unused_warning
|
#include <opencv2/gapi/util/compiler_hints.hpp> //suppress_unused_warning
|
||||||
|
#include <opencv2/gapi/util/util.hpp>
|
||||||
|
|
||||||
// FIXME: namespace scheme for backends?
|
// FIXME: namespace scheme for backends?
|
||||||
namespace cv {
|
namespace cv {
|
||||||
@ -258,7 +259,8 @@ struct OCVCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> >
|
|||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template<class Impl, class K>
|
template<class Impl, class K>
|
||||||
class GCPUKernelImpl: public detail::OCVCallHelper<Impl, typename K::InArgs, typename K::OutArgs>
|
class GCPUKernelImpl: public cv::detail::OCVCallHelper<Impl, typename K::InArgs, typename K::OutArgs>,
|
||||||
|
public cv::detail::KernelTag
|
||||||
{
|
{
|
||||||
using P = detail::OCVCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
|
using P = detail::OCVCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
// 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.
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2018 Intel Corporation
|
// Copyright (C) 2018-2019 Intel Corporation
|
||||||
|
|
||||||
|
|
||||||
#ifndef OPENCV_GAPI_FLUID_KERNEL_HPP
|
#ifndef OPENCV_GAPI_FLUID_KERNEL_HPP
|
||||||
@ -275,7 +275,7 @@ struct FluidCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...>, UseScratch
|
|||||||
|
|
||||||
|
|
||||||
template<class Impl, class K, bool UseScratch>
|
template<class Impl, class K, bool UseScratch>
|
||||||
class GFluidKernelImpl
|
class GFluidKernelImpl : public cv::detail::KernelTag
|
||||||
{
|
{
|
||||||
static const int LPI = 1;
|
static const int LPI = 1;
|
||||||
static const auto Kind = GFluidKernel::Kind::Filter;
|
static const auto Kind = GFluidKernel::Kind::Filter;
|
||||||
|
|||||||
@ -29,6 +29,12 @@ namespace detail
|
|||||||
{
|
{
|
||||||
static const char* tag() { return ""; };
|
static const char* tag() { return ""; };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// These structures are tags which separate kernels and transformations
|
||||||
|
struct KernelTag
|
||||||
|
{};
|
||||||
|
struct TransformTag
|
||||||
|
{};
|
||||||
}
|
}
|
||||||
|
|
||||||
// This definition is here because it is reused by both public(?) and internal
|
// This definition is here because it is reused by both public(?) and internal
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
// 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.
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2018 Intel Corporation
|
// Copyright (C) 2018-2019 Intel Corporation
|
||||||
|
|
||||||
|
|
||||||
#ifndef OPENCV_GAPI_GCOMPOUNDKERNEL_HPP
|
#ifndef OPENCV_GAPI_GCOMPOUNDKERNEL_HPP
|
||||||
@ -65,22 +65,6 @@ template<typename U> struct get_compound_in<cv::GArray<U>>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Kernel may return one object(GMat, GScalar) or a tuple of objects.
|
|
||||||
// This helper is needed to cast return value to the same form(tuple)
|
|
||||||
template<typename>
|
|
||||||
struct tuple_wrap_helper;
|
|
||||||
|
|
||||||
template<typename T> struct tuple_wrap_helper
|
|
||||||
{
|
|
||||||
static std::tuple<T> get(T&& obj) { return std::make_tuple(std::move(obj)); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename... Objs>
|
|
||||||
struct tuple_wrap_helper<std::tuple<Objs...>>
|
|
||||||
{
|
|
||||||
static std::tuple<Objs...> get(std::tuple<Objs...>&& objs) { return std::forward<std::tuple<Objs...>>(objs); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename, typename, typename>
|
template<typename, typename, typename>
|
||||||
struct GCompoundCallHelper;
|
struct GCompoundCallHelper;
|
||||||
|
|
||||||
@ -104,7 +88,8 @@ struct GCompoundCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> >
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<class Impl, class K>
|
template<class Impl, class K>
|
||||||
class GCompoundKernelImpl: public cv::detail::GCompoundCallHelper<Impl, typename K::InArgs, typename K::OutArgs>
|
class GCompoundKernelImpl: public cv::detail::GCompoundCallHelper<Impl, typename K::InArgs, typename K::OutArgs>,
|
||||||
|
public cv::detail::KernelTag
|
||||||
{
|
{
|
||||||
using P = cv::detail::GCompoundCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
|
using P = cv::detail::GCompoundCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
// 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.
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2018 Intel Corporation
|
// Copyright (C) 2018-2019 Intel Corporation
|
||||||
|
|
||||||
|
|
||||||
#ifndef OPENCV_GAPI_GKERNEL_HPP
|
#ifndef OPENCV_GAPI_GKERNEL_HPP
|
||||||
@ -22,6 +22,7 @@
|
|||||||
#include <opencv2/gapi/gmetaarg.hpp> // GMetaArg
|
#include <opencv2/gapi/gmetaarg.hpp> // GMetaArg
|
||||||
#include <opencv2/gapi/gtype_traits.hpp> // GTypeTraits
|
#include <opencv2/gapi/gtype_traits.hpp> // GTypeTraits
|
||||||
#include <opencv2/gapi/util/compiler_hints.hpp> //suppress_unused_warning
|
#include <opencv2/gapi/util/compiler_hints.hpp> //suppress_unused_warning
|
||||||
|
#include <opencv2/gapi/gtransform.hpp>
|
||||||
|
|
||||||
namespace cv {
|
namespace cv {
|
||||||
|
|
||||||
@ -170,12 +171,12 @@ namespace detail
|
|||||||
// GKernelType and GKernelTypeM are base classes which implement typed ::on()
|
// GKernelType and GKernelTypeM are base classes which implement typed ::on()
|
||||||
// method based on kernel signature. GKernelTypeM stands for multiple-return-value kernels
|
// method based on kernel signature. GKernelTypeM stands for multiple-return-value kernels
|
||||||
//
|
//
|
||||||
// G_TYPED_KERNEL and G_TYPED_KERNEK_M macros inherit user classes from GKernelType and
|
// G_TYPED_KERNEL and G_TYPED_KERNEL_M macros inherit user classes from GKernelType and
|
||||||
// GKernelTypeM respectively.
|
// GKernelTypeM respectively.
|
||||||
|
|
||||||
template<typename K, typename... R, typename... Args>
|
template<typename K, typename... R, typename... Args>
|
||||||
class GKernelTypeM<K, std::function<std::tuple<R...>(Args...)> >:
|
class GKernelTypeM<K, std::function<std::tuple<R...>(Args...)> >:
|
||||||
public detail::MetaHelper<K, std::tuple<Args...>, std::tuple<R...> >
|
public detail::MetaHelper<K, std::tuple<Args...>, std::tuple<R...>>
|
||||||
{
|
{
|
||||||
template<int... IIs>
|
template<int... IIs>
|
||||||
static std::tuple<R...> yield(cv::GCall &call, detail::Seq<IIs...>)
|
static std::tuple<R...> yield(cv::GCall &call, detail::Seq<IIs...>)
|
||||||
@ -199,7 +200,7 @@ template<typename, typename> class GKernelType;
|
|||||||
|
|
||||||
template<typename K, typename R, typename... Args>
|
template<typename K, typename R, typename... Args>
|
||||||
class GKernelType<K, std::function<R(Args...)> >:
|
class GKernelType<K, std::function<R(Args...)> >:
|
||||||
public detail::MetaHelper<K, std::tuple<Args...>, R >
|
public detail::MetaHelper<K, std::tuple<Args...>, R>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using InArgs = std::tuple<Args...>;
|
using InArgs = std::tuple<Args...>;
|
||||||
@ -240,7 +241,7 @@ public:
|
|||||||
#define G_TYPED_KERNEL_M(Class, API, Id) \
|
#define G_TYPED_KERNEL_M(Class, API, Id) \
|
||||||
G_ID_HELPER_BODY(Class, Id) \
|
G_ID_HELPER_BODY(Class, Id) \
|
||||||
struct Class final: public cv::GKernelTypeM<Class, std::function API >, \
|
struct Class final: public cv::GKernelTypeM<Class, std::function API >, \
|
||||||
public detail::G_ID_HELPER_CLASS(Class) \
|
public detail::G_ID_HELPER_CLASS(Class)
|
||||||
// {body} is to be defined by user
|
// {body} is to be defined by user
|
||||||
|
|
||||||
namespace cv
|
namespace cv
|
||||||
@ -296,12 +297,13 @@ namespace gapi {
|
|||||||
// FIXME: Hide implementation
|
// FIXME: Hide implementation
|
||||||
/**
|
/**
|
||||||
* @brief A container class for heterogeneous kernel
|
* @brief A container class for heterogeneous kernel
|
||||||
* implementation collections.
|
* implementation collections and graph transformations.
|
||||||
*
|
*
|
||||||
* GKernelPackage is a special container class which stores kernel
|
* GKernelPackage is a special container class which stores kernel
|
||||||
* _implementations_. Objects of this class are created and passed
|
* _implementations_ and graph _transformations_. Objects of this class
|
||||||
* to cv::GComputation::compile() to specify which kernels to use
|
* are created and passed to cv::GComputation::compile() to specify
|
||||||
* in the compiled graph. GKernelPackage may contain kernels of
|
* which kernels to use and which transformations to apply in the
|
||||||
|
* compiled graph. GKernelPackage may contain kernels of
|
||||||
* different backends, e.g. be heterogeneous.
|
* different backends, e.g. be heterogeneous.
|
||||||
*
|
*
|
||||||
* The most easy way to create a kernel package is to use function
|
* The most easy way to create a kernel package is to use function
|
||||||
@ -313,7 +315,8 @@ namespace gapi {
|
|||||||
* with an empty package (created with the default constructor)
|
* with an empty package (created with the default constructor)
|
||||||
* and then by populating it with kernels via call to
|
* and then by populating it with kernels via call to
|
||||||
* GKernelPackage::include(). Note this method is also a template
|
* GKernelPackage::include(). Note this method is also a template
|
||||||
* one since G-API kernel implementations are _types_, not objects.
|
* one since G-API kernel and transformation implementations are _types_,
|
||||||
|
* not objects.
|
||||||
*
|
*
|
||||||
* Finally, two kernel packages can be combined into a new one
|
* Finally, two kernel packages can be combined into a new one
|
||||||
* with function cv::gapi::combine().
|
* with function cv::gapi::combine().
|
||||||
@ -327,6 +330,9 @@ namespace gapi {
|
|||||||
/// @private
|
/// @private
|
||||||
M m_id_kernels;
|
M m_id_kernels;
|
||||||
|
|
||||||
|
/// @private
|
||||||
|
std::vector<GTransform> m_transformations;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// @private
|
/// @private
|
||||||
// Check if package contains ANY implementation of a kernel API
|
// Check if package contains ANY implementation of a kernel API
|
||||||
@ -337,26 +343,61 @@ namespace gapi {
|
|||||||
// Remove ALL implementations of the given API (identified by ID)
|
// Remove ALL implementations of the given API (identified by ID)
|
||||||
void removeAPI(const std::string &id);
|
void removeAPI(const std::string &id);
|
||||||
|
|
||||||
|
/// @private
|
||||||
|
// Partial include() specialization for kernels
|
||||||
|
template <typename KImpl>
|
||||||
|
typename std::enable_if<(std::is_base_of<detail::KernelTag, KImpl>::value), void>::type
|
||||||
|
includeHelper()
|
||||||
|
{
|
||||||
|
auto backend = KImpl::backend();
|
||||||
|
auto kernel_id = KImpl::API::id();
|
||||||
|
auto kernel_impl = GKernelImpl{KImpl::kernel()};
|
||||||
|
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
|
||||||
|
includeHelper()
|
||||||
|
{
|
||||||
|
m_transformations.emplace_back(TImpl::transformation());
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Returns total number of kernels in the package
|
* @brief Returns total number of kernels
|
||||||
* (across all backends included)
|
* in the package (across all backends included)
|
||||||
*
|
*
|
||||||
* @return a number of kernels in the package
|
* @return a number of kernels in the package
|
||||||
*/
|
*/
|
||||||
std::size_t size() const;
|
std::size_t size() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns vector of transformations included in the package
|
||||||
|
*
|
||||||
|
* @return vector of transformations included in the package
|
||||||
|
*/
|
||||||
|
const std::vector<GTransform>& get_transformations() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Test if a particular kernel _implementation_ KImpl is
|
* @brief Test if a particular kernel _implementation_ KImpl is
|
||||||
* included in this kernel package.
|
* included in this kernel package.
|
||||||
*
|
*
|
||||||
* @sa includesAPI()
|
* @sa includesAPI()
|
||||||
*
|
*
|
||||||
|
* @note cannot be applied to transformations
|
||||||
|
*
|
||||||
* @return true if there is such kernel, false otherwise.
|
* @return true if there is such kernel, false otherwise.
|
||||||
*/
|
*/
|
||||||
template<typename KImpl>
|
template<typename KImpl>
|
||||||
bool includes() const
|
bool includes() const
|
||||||
{
|
{
|
||||||
|
static_assert(std::is_base_of<detail::KernelTag, KImpl>::value,
|
||||||
|
"includes() can be applied to kernels only");
|
||||||
|
|
||||||
auto kernel_it = m_id_kernels.find(KImpl::API::id());
|
auto kernel_it = m_id_kernels.find(KImpl::API::id());
|
||||||
return kernel_it != m_id_kernels.end() &&
|
return kernel_it != m_id_kernels.end() &&
|
||||||
kernel_it->second.first == KImpl::backend();
|
kernel_it->second.first == KImpl::backend();
|
||||||
@ -417,17 +458,13 @@ namespace gapi {
|
|||||||
|
|
||||||
// FIXME: No overwrites allowed?
|
// FIXME: No overwrites allowed?
|
||||||
/**
|
/**
|
||||||
* @brief Put a new kernel implementation KImpl into package.
|
* @brief Put a new kernel implementation or a new transformation
|
||||||
|
* KImpl into the package.
|
||||||
*/
|
*/
|
||||||
template<typename KImpl>
|
template<typename KImpl>
|
||||||
void include()
|
void include()
|
||||||
{
|
{
|
||||||
auto backend = KImpl::backend();
|
includeHelper<KImpl>();
|
||||||
auto kernel_id = KImpl::API::id();
|
|
||||||
auto kernel_impl = GKernelImpl{KImpl::kernel()};
|
|
||||||
removeAPI(kernel_id);
|
|
||||||
|
|
||||||
m_id_kernels[kernel_id] = std::make_pair(backend, kernel_impl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -452,15 +489,15 @@ namespace gapi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a kernel package object containing kernels
|
* @brief Create a kernel package object containing kernels
|
||||||
* specified in variadic template argument.
|
* and transformations specified in variadic template argument.
|
||||||
*
|
*
|
||||||
* In G-API, kernel implementations are _types_. Every backend has
|
* In G-API, kernel implementations and transformations are _types_.
|
||||||
* its own kernel API (like GAPI_OCV_KERNEL() and
|
* Every backend has its own kernel API (like GAPI_OCV_KERNEL() and
|
||||||
* GAPI_FLUID_KERNEL()) but all of that APIs define a new type for
|
* GAPI_FLUID_KERNEL()) but all of that APIs define a new type for
|
||||||
* each kernel implementation.
|
* each kernel implementation.
|
||||||
*
|
*
|
||||||
* Use this function to pass kernel implementations (defined in
|
* Use this function to pass kernel implementations (defined in
|
||||||
* either way) to the system. Example:
|
* either way) and transformations to the system. Example:
|
||||||
*
|
*
|
||||||
* @snippet modules/gapi/samples/api_ref_snippets.cpp kernels_snippet
|
* @snippet modules/gapi/samples/api_ref_snippets.cpp kernels_snippet
|
||||||
*
|
*
|
||||||
@ -470,6 +507,10 @@ namespace gapi {
|
|||||||
*/
|
*/
|
||||||
template<typename... KK> GKernelPackage kernels()
|
template<typename... KK> GKernelPackage kernels()
|
||||||
{
|
{
|
||||||
|
// 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");
|
||||||
|
|
||||||
GKernelPackage pkg;
|
GKernelPackage pkg;
|
||||||
|
|
||||||
// For those who wonder - below is a trick to call a number of
|
// For those who wonder - below is a trick to call a number of
|
||||||
@ -478,8 +519,6 @@ namespace gapi {
|
|||||||
// Just note that `f(),a` always equals to `a` (with f() called!)
|
// Just note that `f(),a` always equals to `a` (with f() called!)
|
||||||
// and parentheses are used to hide function call in the expanded sequence.
|
// and parentheses are used to hide function call in the expanded sequence.
|
||||||
// Leading 0 helps to handle case when KK is an empty list (kernels<>()).
|
// Leading 0 helps to handle case when KK is an empty list (kernels<>()).
|
||||||
|
|
||||||
static_assert(detail::all_unique<typename KK::API...>::value, "Kernels API must be unique");
|
|
||||||
int unused[] = { 0, (pkg.include<KK>(), 0)... };
|
int unused[] = { 0, (pkg.include<KK>(), 0)... };
|
||||||
cv::util::suppress_unused_warning(unused);
|
cv::util::suppress_unused_warning(unused);
|
||||||
return pkg;
|
return pkg;
|
||||||
|
|||||||
98
modules/gapi/include/opencv2/gapi/gtransform.hpp
Normal file
98
modules/gapi/include/opencv2/gapi/gtransform.hpp
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// This file is part of OpenCV project.
|
||||||
|
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||||
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2019 Intel Corporation
|
||||||
|
|
||||||
|
#ifndef OPENCV_GAPI_GTRANSFORM_HPP
|
||||||
|
#define OPENCV_GAPI_GTRANSFORM_HPP
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <opencv2/gapi/gcommon.hpp>
|
||||||
|
#include <opencv2/gapi/util/util.hpp>
|
||||||
|
#include <opencv2/gapi/garg.hpp>
|
||||||
|
#include <opencv2/gapi/gtype_traits.hpp>
|
||||||
|
#include <opencv2/gapi/util/compiler_hints.hpp>
|
||||||
|
|
||||||
|
namespace cv
|
||||||
|
{
|
||||||
|
|
||||||
|
struct GAPI_EXPORTS GTransform
|
||||||
|
{
|
||||||
|
using F = std::function<GArgs(const GArgs &)>;
|
||||||
|
|
||||||
|
std::string description;
|
||||||
|
F pattern;
|
||||||
|
F substitute;
|
||||||
|
|
||||||
|
GTransform(const std::string& d, const F &p, const F &s) : description(d), pattern(p), substitute(s){};
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename, typename, typename>
|
||||||
|
struct TransHelper;
|
||||||
|
|
||||||
|
template <typename K, typename... Ins, typename Out>
|
||||||
|
struct TransHelper<K, std::tuple<Ins...>, Out>
|
||||||
|
{
|
||||||
|
template <typename Callable, int... IIs, int... OIs>
|
||||||
|
static GArgs invoke(Callable f, const GArgs &in_args, Seq<IIs...>, Seq<OIs...>)
|
||||||
|
{
|
||||||
|
const auto r = tuple_wrap_helper<Out>::get(f(in_args.at(IIs).template get<Ins>()...));
|
||||||
|
return GArgs{GArg(std::get<OIs>(r))...};
|
||||||
|
}
|
||||||
|
|
||||||
|
static GArgs get_pattern(const GArgs &in_args)
|
||||||
|
{
|
||||||
|
return invoke(K::pattern, in_args, typename MkSeq<sizeof...(Ins)>::type(),
|
||||||
|
typename MkSeq<std::tuple_size<typename tuple_wrap_helper<Out>::type>::value>::type());
|
||||||
|
}
|
||||||
|
static GArgs get_substitute(const GArgs &in_args)
|
||||||
|
{
|
||||||
|
return invoke(K::substitute, in_args, typename MkSeq<sizeof...(Ins)>::type(),
|
||||||
|
typename MkSeq<std::tuple_size<typename tuple_wrap_helper<Out>::type>::value>::type());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template <typename, typename>
|
||||||
|
class GTransformImpl;
|
||||||
|
|
||||||
|
template <typename K, typename R, typename... Args>
|
||||||
|
class GTransformImpl<K, std::function<R(Args...)>> : public cv::detail::TransHelper<K, std::tuple<Args...>, R>,
|
||||||
|
public cv::detail::TransformTag
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// FIXME: currently there is no check that transformations' signatures are unique
|
||||||
|
// and won't be any intersection in graph compilation stage
|
||||||
|
using API = K;
|
||||||
|
|
||||||
|
static GTransform transformation()
|
||||||
|
{
|
||||||
|
return GTransform(K::descr(), &K::get_pattern, &K::get_substitute);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace cv
|
||||||
|
|
||||||
|
#define G_DESCR_HELPER_CLASS(Class) Class##DescrHelper
|
||||||
|
|
||||||
|
#define G_DESCR_HELPER_BODY(Class, Descr) \
|
||||||
|
namespace detail \
|
||||||
|
{ \
|
||||||
|
struct G_DESCR_HELPER_CLASS(Class) \
|
||||||
|
{ \
|
||||||
|
static constexpr const char *descr() { return Descr; }; \
|
||||||
|
}; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GAPI_TRANSFORM(Class, API, Descr) \
|
||||||
|
G_DESCR_HELPER_BODY(Class, Descr) \
|
||||||
|
struct Class final : public cv::GTransformImpl<Class, std::function API>, \
|
||||||
|
public detail::G_DESCR_HELPER_CLASS(Class)
|
||||||
|
|
||||||
|
#endif // OPENCV_GAPI_GTRANSFORM_HPP
|
||||||
@ -2,7 +2,7 @@
|
|||||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
// 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.
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2018 Intel Corporation
|
// Copyright (C) 2018-2019 Intel Corporation
|
||||||
|
|
||||||
|
|
||||||
#ifndef OPENCV_GAPI_GOCLKERNEL_HPP
|
#ifndef OPENCV_GAPI_GOCLKERNEL_HPP
|
||||||
@ -226,7 +226,8 @@ struct OCLCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> >
|
|||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template<class Impl, class K>
|
template<class Impl, class K>
|
||||||
class GOCLKernelImpl: public detail::OCLCallHelper<Impl, typename K::InArgs, typename K::OutArgs>
|
class GOCLKernelImpl: public cv::detail::OCLCallHelper<Impl, typename K::InArgs, typename K::OutArgs>,
|
||||||
|
public cv::detail::KernelTag
|
||||||
{
|
{
|
||||||
using P = detail::OCLCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
|
using P = detail::OCLCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
|
||||||
|
|
||||||
|
|||||||
@ -2,13 +2,13 @@
|
|||||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
// 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.
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2018 Intel Corporation
|
// Copyright (C) 2018-2019 Intel Corporation
|
||||||
|
|
||||||
|
|
||||||
#ifndef OPENCV_GAPI_UTIL_HPP
|
#ifndef OPENCV_GAPI_UTIL_HPP
|
||||||
#define OPENCV_GAPI_UTIL_HPP
|
#define OPENCV_GAPI_UTIL_HPP
|
||||||
|
|
||||||
#include <utility> // std::tuple
|
#include <tuple>
|
||||||
|
|
||||||
// \cond HIDDEN_SYMBOLS
|
// \cond HIDDEN_SYMBOLS
|
||||||
// This header file contains some generic utility functions which are
|
// This header file contains some generic utility functions which are
|
||||||
@ -97,6 +97,22 @@ namespace detail
|
|||||||
template <typename T1, typename... Ts>
|
template <typename T1, typename... Ts>
|
||||||
struct all_unique<T1, Ts...> : std::integral_constant<bool, !contains<T1, Ts...>::value &&
|
struct all_unique<T1, Ts...> : std::integral_constant<bool, !contains<T1, Ts...>::value &&
|
||||||
all_unique<Ts...>::value> {};
|
all_unique<Ts...>::value> {};
|
||||||
|
|
||||||
|
template<typename>
|
||||||
|
struct tuple_wrap_helper;
|
||||||
|
|
||||||
|
template<typename T> struct tuple_wrap_helper
|
||||||
|
{
|
||||||
|
using type = std::tuple<T>;
|
||||||
|
static type get(T&& obj) { return std::make_tuple(std::move(obj)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Objs>
|
||||||
|
struct tuple_wrap_helper<std::tuple<Objs...>>
|
||||||
|
{
|
||||||
|
using type = std::tuple<Objs...>;
|
||||||
|
static type get(std::tuple<Objs...>&& objs) { return std::forward<std::tuple<Objs...>>(objs); }
|
||||||
|
};
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace cv
|
} // namespace cv
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
// 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.
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2018 Intel Corporation
|
// Copyright (C) 2018-2019 Intel Corporation
|
||||||
|
|
||||||
|
|
||||||
#include "precomp.hpp"
|
#include "precomp.hpp"
|
||||||
@ -50,6 +50,11 @@ std::size_t cv::gapi::GKernelPackage::size() const
|
|||||||
return m_id_kernels.size();
|
return m_id_kernels.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<cv::GTransform> &cv::gapi::GKernelPackage::get_transformations() const
|
||||||
|
{
|
||||||
|
return m_transformations;
|
||||||
|
}
|
||||||
|
|
||||||
cv::gapi::GKernelPackage cv::gapi::combine(const GKernelPackage &lhs,
|
cv::gapi::GKernelPackage cv::gapi::combine(const GKernelPackage &lhs,
|
||||||
const GKernelPackage &rhs)
|
const GKernelPackage &rhs)
|
||||||
{
|
{
|
||||||
@ -66,6 +71,9 @@ cv::gapi::GKernelPackage cv::gapi::combine(const GKernelPackage &lhs,
|
|||||||
result.m_id_kernels.emplace(kernel.first, kernel.second);
|
result.m_id_kernels.emplace(kernel.first, kernel.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (const auto &transforms : lhs.m_transformations){
|
||||||
|
result.m_transformations.push_back(transforms);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -35,7 +35,7 @@ namespace
|
|||||||
// 1. Get GCompoundKernel implementation
|
// 1. Get GCompoundKernel implementation
|
||||||
// 2. Create GCompoundContext
|
// 2. Create GCompoundContext
|
||||||
// 3. Run GCompoundKernel with GCompoundContext
|
// 3. Run GCompoundKernel with GCompoundContext
|
||||||
// 4. Build subgraph from imputs/outputs GCompoundKernel
|
// 4. Build subgraph from inputs/outputs GCompoundKernel
|
||||||
// 5. Replace compound node to subgraph
|
// 5. Replace compound node to subgraph
|
||||||
|
|
||||||
void expand(ade::Graph& g, ade::NodeHandle nh, const ImplInfo& impl_info)
|
void expand(ade::Graph& g, ade::NodeHandle nh, const ImplInfo& impl_info)
|
||||||
|
|||||||
183
modules/gapi/test/gapi_transform_tests.cpp
Normal file
183
modules/gapi/test/gapi_transform_tests.cpp
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
// This file is part of OpenCV project.
|
||||||
|
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||||
|
// of this distribution and at http://opencv.org/license.html.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2019 Intel Corporation
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
#include "test_precomp.hpp"
|
||||||
|
#include "opencv2/gapi/gtransform.hpp"
|
||||||
|
|
||||||
|
namespace opencv_test
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using GMat = cv::GMat;
|
||||||
|
using GMat2 = std::tuple<GMat, GMat>;
|
||||||
|
using GMat3 = std::tuple<GMat, GMat, GMat>;
|
||||||
|
using GScalar = cv::GScalar;
|
||||||
|
template <typename T> using GArray = cv::GArray<T>;
|
||||||
|
|
||||||
|
GAPI_TRANSFORM(gmat_in_gmat_out, <GMat(GMat)>, "gmat_in_gmat_out")
|
||||||
|
{
|
||||||
|
static GMat pattern(GMat) { return {}; }
|
||||||
|
static GMat substitute(GMat) { return {}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
GAPI_TRANSFORM(gmat2_in_gmat_out, <GMat(GMat, GMat)>, "gmat2_in_gmat_out")
|
||||||
|
{
|
||||||
|
static GMat pattern(GMat, GMat) { return {}; }
|
||||||
|
static GMat substitute(GMat, GMat) { return {}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
GAPI_TRANSFORM(gmat2_in_gmat3_out, <GMat3(GMat, GMat)>, "gmat2_in_gmat3_out")
|
||||||
|
{
|
||||||
|
static GMat3 pattern(GMat, GMat) { return {}; }
|
||||||
|
static GMat3 substitute(GMat, GMat) { return {}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
GAPI_TRANSFORM(gmatp_in_gmatp_out, <GMatP(GMatP)>, "gmatp_in_gmatp_out")
|
||||||
|
{
|
||||||
|
static GMatP pattern(GMatP) { return {}; }
|
||||||
|
static GMatP substitute(GMatP) { return {}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
GAPI_TRANSFORM(gsc_in_gmat_out, <GMat(GScalar)>, "gsc_in_gmat_out")
|
||||||
|
{
|
||||||
|
static GMat pattern(GScalar) { return {}; }
|
||||||
|
static GMat substitute(GScalar) { return {}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
GAPI_TRANSFORM(gmat_in_gsc_out, <GScalar(GMat)>, "gmat_in_gsc_out")
|
||||||
|
{
|
||||||
|
static GScalar pattern(GMat) { return {}; }
|
||||||
|
static GScalar substitute(GMat) { return {}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
GAPI_TRANSFORM(garr_in_gmat_out, <GMat(GArray<int>)>, "garr_in_gmat_out")
|
||||||
|
{
|
||||||
|
static GMat pattern(GArray<int>) { return {}; }
|
||||||
|
static GMat substitute(GArray<int>) { return {}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
GAPI_TRANSFORM(gmat_in_garr_out, <GArray<int>(GMat)>, "gmat_in_garr_out")
|
||||||
|
{
|
||||||
|
static GArray<int> pattern(GMat) { return {}; }
|
||||||
|
static GArray<int> substitute(GMat) { return {}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
TEST(KernelPackageTransform, CreatePackage)
|
||||||
|
{
|
||||||
|
auto pkg = cv::gapi::kernels
|
||||||
|
< gmat_in_gmat_out
|
||||||
|
, gmat2_in_gmat_out
|
||||||
|
, gmat2_in_gmat3_out
|
||||||
|
, gsc_in_gmat_out
|
||||||
|
, gmat_in_gsc_out
|
||||||
|
>();
|
||||||
|
|
||||||
|
auto tr = pkg.get_transformations();
|
||||||
|
EXPECT_EQ(5u, tr.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(KernelPackageTransform, Include)
|
||||||
|
{
|
||||||
|
cv::gapi::GKernelPackage pkg;
|
||||||
|
pkg.include<gmat_in_gmat_out>();
|
||||||
|
pkg.include<gmat2_in_gmat_out>();
|
||||||
|
pkg.include<gmat2_in_gmat3_out>();
|
||||||
|
auto tr = pkg.get_transformations();
|
||||||
|
EXPECT_EQ(3u, tr.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(KernelPackageTransform, Combine)
|
||||||
|
{
|
||||||
|
auto pkg1 = cv::gapi::kernels<gmat_in_gmat_out>();
|
||||||
|
auto pkg2 = cv::gapi::kernels<gmat2_in_gmat_out>();
|
||||||
|
auto pkg_comb = cv::gapi::combine(pkg1, pkg2);
|
||||||
|
auto tr = pkg_comb.get_transformations();
|
||||||
|
EXPECT_EQ(2u, tr.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(KernelPackageTransform, Pattern)
|
||||||
|
{
|
||||||
|
auto tr = gmat2_in_gmat3_out::transformation();
|
||||||
|
GMat a, b;
|
||||||
|
auto pattern = tr.pattern({cv::GArg(a), cv::GArg(b)});
|
||||||
|
|
||||||
|
// return type of '2gmat_in_gmat3_out' is GMat3
|
||||||
|
EXPECT_EQ(3u, pattern.size());
|
||||||
|
for (const auto& p : pattern)
|
||||||
|
{
|
||||||
|
EXPECT_NO_THROW(p.get<GMat>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(KernelPackageTransform, Substitute)
|
||||||
|
{
|
||||||
|
auto tr = gmat2_in_gmat3_out::transformation();
|
||||||
|
GMat a, b;
|
||||||
|
auto subst = tr.substitute({cv::GArg(a), cv::GArg(b)});
|
||||||
|
|
||||||
|
EXPECT_EQ(3u, subst.size());
|
||||||
|
for (const auto& s : subst)
|
||||||
|
{
|
||||||
|
EXPECT_NO_THROW(s.get<GMat>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Transformation, typename InType, typename OutType>
|
||||||
|
static void transformTest()
|
||||||
|
{
|
||||||
|
auto tr = Transformation::transformation();
|
||||||
|
InType in;
|
||||||
|
auto pattern = tr.pattern({cv::GArg(in)});
|
||||||
|
auto subst = tr.substitute({cv::GArg(in)});
|
||||||
|
|
||||||
|
EXPECT_EQ(1u, pattern.size());
|
||||||
|
EXPECT_EQ(1u, subst.size());
|
||||||
|
|
||||||
|
auto checkOut = [](GArg& garg) {
|
||||||
|
EXPECT_TRUE(garg.kind == cv::detail::GTypeTraits<OutType>::kind);
|
||||||
|
EXPECT_NO_THROW(garg.get<OutType>());
|
||||||
|
};
|
||||||
|
|
||||||
|
checkOut(pattern[0]);
|
||||||
|
checkOut(subst[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(KernelPackageTransform, GMat)
|
||||||
|
{
|
||||||
|
transformTest<gmat_in_gmat_out, GMat, GMat>();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(KernelPackageTransform, GMatP)
|
||||||
|
{
|
||||||
|
transformTest<gmatp_in_gmatp_out, GMatP, GMatP>();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(KernelPackageTransform, GScalarIn)
|
||||||
|
{
|
||||||
|
transformTest<gsc_in_gmat_out, GScalar, GMat>();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(KernelPackageTransform, GScalarOut)
|
||||||
|
{
|
||||||
|
transformTest<gmat_in_gsc_out, GMat, GScalar>();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(KernelPackageTransform, DISABLED_GArrayIn)
|
||||||
|
{
|
||||||
|
transformTest<garr_in_gmat_out, GArray<int>, GMat>();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(KernelPackageTransform, DISABLED_GArrayOut)
|
||||||
|
{
|
||||||
|
transformTest<gmat_in_garr_out, GMat, GArray<int>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace opencv_test
|
||||||
Loading…
Reference in New Issue
Block a user