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
pull/14832/head
Alexey Smirnov 5 years ago committed by Alexander Alekhin
parent 66d7956e67
commit 7f9a9f2a09
  1. 6
      modules/gapi/include/opencv2/gapi/cpu/gcpukernel.hpp
  2. 4
      modules/gapi/include/opencv2/gapi/fluid/gfluidkernel.hpp
  3. 6
      modules/gapi/include/opencv2/gapi/gcommon.hpp
  4. 21
      modules/gapi/include/opencv2/gapi/gcompoundkernel.hpp
  5. 89
      modules/gapi/include/opencv2/gapi/gkernel.hpp
  6. 98
      modules/gapi/include/opencv2/gapi/gtransform.hpp
  7. 5
      modules/gapi/include/opencv2/gapi/ocl/goclkernel.hpp
  8. 20
      modules/gapi/include/opencv2/gapi/util/util.hpp
  9. 10
      modules/gapi/src/api/gkernel.cpp
  10. 2
      modules/gapi/src/compiler/passes/kernels.cpp
  11. 183
      modules/gapi/test/gapi_transform_tests.cpp

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

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

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

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

@ -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
@ -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 {
@ -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...>)
@ -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...>;
@ -240,7 +241,7 @@ public:
#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
@ -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
@ -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().
@ -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
@ -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();
@ -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>();
}
/**
@ -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
*
@ -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
@ -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;

@ -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
// 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
@ -226,7 +226,8 @@ struct OCLCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> >
} // namespace detail
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>;

@ -2,13 +2,13 @@
// 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_UTIL_HPP
#define OPENCV_GAPI_UTIL_HPP
#include <utility> // std::tuple
#include <tuple>
// \cond HIDDEN_SYMBOLS
// This header file contains some generic utility functions which are
@ -97,6 +97,22 @@ namespace detail
template <typename T1, typename... Ts>
struct all_unique<T1, Ts...> : std::integral_constant<bool, !contains<T1, 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 cv

@ -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
#include "precomp.hpp"
@ -50,6 +50,11 @@ std::size_t cv::gapi::GKernelPackage::size() const
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,
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);
}
}
for (const auto &transforms : lhs.m_transformations){
result.m_transformations.push_back(transforms);
}
return result;
}

@ -35,7 +35,7 @@ namespace
// 1. Get GCompoundKernel implementation
// 2. Create 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
void expand(ade::Graph& g, ade::NodeHandle nh, const ImplInfo& impl_info)

@ -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…
Cancel
Save