Skip to content

Commit

Permalink
Merge pull request opencv#14648 from smirnov-alexey:as/gapi_transform
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
smirnov-alexey authored and alalek committed Jun 17, 2019
1 parent 66d7956 commit 7f9a9f2
Show file tree
Hide file tree
Showing 11 changed files with 391 additions and 53 deletions.
6 changes: 4 additions & 2 deletions modules/gapi/include/opencv2/gapi/cpu/gcpukernel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// 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-2019 Intel Corporation


#ifndef OPENCV_GAPI_GCPUKERNEL_HPP
Expand All @@ -19,6 +19,7 @@
#include <opencv2/gapi/garg.hpp>
#include <opencv2/gapi/own/convert.hpp> //to_ocv
#include <opencv2/gapi/util/compiler_hints.hpp> //suppress_unused_warning
#include <opencv2/gapi/util/util.hpp>

// FIXME: namespace scheme for backends?
namespace cv {
Expand Down Expand Up @@ -258,7 +259,8 @@ struct OCVCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> >
} // namespace detail

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>;

Expand Down
4 changes: 2 additions & 2 deletions modules/gapi/include/opencv2/gapi/fluid/gfluidkernel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// 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-2019 Intel Corporation


#ifndef OPENCV_GAPI_FLUID_KERNEL_HPP
Expand Down Expand Up @@ -275,7 +275,7 @@ struct FluidCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...>, UseScratch


template<class Impl, class K, bool UseScratch>
class GFluidKernelImpl
class GFluidKernelImpl : public cv::detail::KernelTag
{
static const int LPI = 1;
static const auto Kind = GFluidKernel::Kind::Filter;
Expand Down
6 changes: 6 additions & 0 deletions modules/gapi/include/opencv2/gapi/gcommon.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ namespace detail
{
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
Expand Down
21 changes: 3 additions & 18 deletions modules/gapi/include/opencv2/gapi/gcompoundkernel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// 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-2019 Intel Corporation


#ifndef OPENCV_GAPI_GCOMPOUNDKERNEL_HPP
Expand Down Expand Up @@ -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>
struct GCompoundCallHelper;

Expand All @@ -104,7 +88,8 @@ struct GCompoundCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> >
};

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>;

Expand Down
89 changes: 64 additions & 25 deletions modules/gapi/include/opencv2/gapi/gkernel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// 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-2019 Intel Corporation


#ifndef OPENCV_GAPI_GKERNEL_HPP
Expand All @@ -22,6 +22,7 @@
#include <opencv2/gapi/gmetaarg.hpp> // GMetaArg
#include <opencv2/gapi/gtype_traits.hpp> // GTypeTraits
#include <opencv2/gapi/util/compiler_hints.hpp> //suppress_unused_warning
#include <opencv2/gapi/gtransform.hpp>

namespace cv {

Expand Down Expand Up @@ -170,12 +171,12 @@ namespace detail
// GKernelType and GKernelTypeM are base classes which implement typed ::on()
// 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.

template<typename K, typename... R, typename... Args>
class GKernelTypeM<K, std::function<std::tuple<R...>(Args...)> >:
public detail::MetaHelper<K, std::tuple<Args...>, std::tuple<R...> >
public detail::MetaHelper<K, std::tuple<Args...>, std::tuple<R...>>
{
template<int... IIs>
static std::tuple<R...> yield(cv::GCall &call, detail::Seq<IIs...>)
Expand All @@ -199,7 +200,7 @@ template<typename, typename> class GKernelType;

template<typename K, typename R, typename... Args>
class GKernelType<K, std::function<R(Args...)> >:
public detail::MetaHelper<K, std::tuple<Args...>, R >
public detail::MetaHelper<K, std::tuple<Args...>, R>
{
public:
using InArgs = std::tuple<Args...>;
Expand Down Expand Up @@ -240,7 +241,7 @@ class GKernelType<K, std::function<R(Args...)> >:
#define G_TYPED_KERNEL_M(Class, API, Id) \
G_ID_HELPER_BODY(Class, Id) \
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

namespace cv
Expand Down Expand Up @@ -296,12 +297,13 @@ namespace gapi {
// FIXME: Hide implementation
/**
* @brief A container class for heterogeneous kernel
* implementation collections.
* implementation collections and graph transformations.
*
* GKernelPackage is a special container class which stores kernel
* _implementations_. Objects of this class are created and passed
* to cv::GComputation::compile() to specify which kernels to use
* in the compiled graph. GKernelPackage may contain kernels of
* _implementations_ and graph _transformations_. Objects of this class
* are created and passed to cv::GComputation::compile() to specify
* which kernels to use and which transformations to apply in the
* compiled graph. GKernelPackage may contain kernels of
* different backends, e.g. be heterogeneous.
*
* The most easy way to create a kernel package is to use function
Expand All @@ -313,7 +315,8 @@ namespace gapi {
* with an empty package (created with the default constructor)
* and then by populating it with kernels via call to
* 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
* with function cv::gapi::combine().
Expand All @@ -327,6 +330,9 @@ namespace gapi {
/// @private
M m_id_kernels;

/// @private
std::vector<GTransform> m_transformations;

protected:
/// @private
// Check if package contains ANY implementation of a kernel API
Expand All @@ -337,26 +343,61 @@ namespace gapi {
// Remove ALL implementations of the given API (identified by 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:
/**
* @brief Returns total number of kernels in the package
* (across all backends included)
* @brief Returns total number of kernels
* in the package (across all backends included)
*
* @return a number of kernels in the package
*/
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
* included in this kernel package.
*
* @sa includesAPI()
*
* @note cannot be applied to transformations
*
* @return true if there is such kernel, false otherwise.
*/
template<typename KImpl>
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());
return kernel_it != m_id_kernels.end() &&
kernel_it->second.first == KImpl::backend();
Expand Down Expand Up @@ -417,17 +458,13 @@ namespace gapi {

// 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>
void include()
{
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);
includeHelper<KImpl>();
}

/**
Expand All @@ -452,15 +489,15 @@ namespace gapi {

/**
* @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
* its own kernel API (like GAPI_OCV_KERNEL() and
* In G-API, kernel implementations and transformations are _types_.
* 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
* each kernel implementation.
*
* 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
*
Expand All @@ -470,6 +507,10 @@ namespace gapi {
*/
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;

// For those who wonder - below is a trick to call a number of
Expand All @@ -478,8 +519,6 @@ namespace gapi {
// Just note that `f(),a` always equals to `a` (with f() called!)
// 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<>()).

static_assert(detail::all_unique<typename KK::API...>::value, "Kernels API must be unique");
int unused[] = { 0, (pkg.include<KK>(), 0)... };
cv::util::suppress_unused_warning(unused);
return pkg;
Expand Down
Loading

0 comments on commit 7f9a9f2

Please sign in to comment.