mirror of https://github.com/opencv/opencv.git
Merge pull request #12608 from dmatveev:gapi
* G-API Initial code upload * Update G-API code base to Sep-24-2018 * The majority of OpenCV buildbot problems was addressed * Update G-API code base to 24-Sep-18 EOD * G-API code base update 25-Sep-2018 * Linux warnings should be resolved * Documentation build should become green * Number of Windows warnings should be reduced * Update G-API code base to 25-Sep-18 EOD * ARMv7 build issue should be resolved * ADE is bumped to latest version and should fix Clang builds for macOS/iOS * Remaining Windows warnings should be resolved * New Linux32 / ARMv7 warnings should be resolved * G-API code base update 25-Sep-2018-EOD2 * Final Windows warnings should be resolved now * G-API code base update 26-Sep-2018 * Fixed issues with precompiled headers in module and its testspull/12609/merge
parent
852f061b26
commit
29e88e50ff
166 changed files with 35254 additions and 0 deletions
@ -0,0 +1,94 @@ |
||||
# FIXME: Remove CXX11 check after complete switch to OpenCV 4 branch |
||||
# (CI, bundle, workloads, etc) |
||||
if (NOT HAVE_CXX11 OR NOT TARGET ade) |
||||
# can't build G-API because of the above reasons |
||||
ocv_module_disable(gapi) |
||||
return() |
||||
endif() |
||||
|
||||
set(the_description "OpenCV G-API Core Module") |
||||
ocv_add_module(gapi opencv_imgproc) |
||||
|
||||
file(GLOB gapi_ext_hdrs |
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/*.hpp" |
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/*.hpp" |
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/*.h" |
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/util/*.hpp" |
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/cpu/*.hpp" |
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/fluid/*.hpp" |
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/own/*.hpp" |
||||
) |
||||
|
||||
set(gapi_srcs |
||||
# Front-end part |
||||
src/api/gapi_priv.cpp |
||||
src/api/gmat.cpp |
||||
src/api/garray.cpp |
||||
src/api/gscalar.cpp |
||||
src/api/gkernel.cpp |
||||
src/api/gbackend.cpp |
||||
src/api/gproto.cpp |
||||
src/api/gnode.cpp |
||||
src/api/gcall.cpp |
||||
src/api/gcomputation.cpp |
||||
src/api/operators.cpp |
||||
src/api/kernels_core.cpp |
||||
src/api/kernels_imgproc.cpp |
||||
|
||||
# Compiler part |
||||
src/compiler/gmodel.cpp |
||||
src/compiler/gmodelbuilder.cpp |
||||
src/compiler/gislandmodel.cpp |
||||
src/compiler/gcompiler.cpp |
||||
src/compiler/gcompiled.cpp |
||||
src/compiler/passes/helpers.cpp |
||||
src/compiler/passes/dump_dot.cpp |
||||
src/compiler/passes/islands.cpp |
||||
src/compiler/passes/meta.cpp |
||||
src/compiler/passes/kernels.cpp |
||||
src/compiler/passes/exec.cpp |
||||
|
||||
# Executor |
||||
src/executor/gexecutor.cpp |
||||
|
||||
# CPU Backend (currently built-in) |
||||
src/backends/cpu/gcpubackend.cpp |
||||
src/backends/cpu/gcpukernel.cpp |
||||
src/backends/cpu/gcpuimgproc.cpp |
||||
src/backends/cpu/gcpucore.cpp |
||||
|
||||
# Fluid Backend (also built-in, FIXME:move away) |
||||
src/backends/fluid/gfluidbuffer.cpp |
||||
src/backends/fluid/gfluidbackend.cpp |
||||
src/backends/fluid/gfluidimgproc.cpp |
||||
src/backends/fluid/gfluidcore.cpp |
||||
|
||||
# Compound |
||||
src/backends/common/gcompoundbackend.cpp |
||||
src/backends/common/gcompoundkernel.cpp |
||||
) |
||||
|
||||
ocv_list_add_prefix(gapi_srcs "${CMAKE_CURRENT_LIST_DIR}/") |
||||
|
||||
# For IDE users |
||||
ocv_source_group("Src" FILES ${gapi_srcs}) |
||||
ocv_source_group("Include" FILES ${gapi_ext_hdrs}) |
||||
|
||||
ocv_set_module_sources(HEADERS ${gapi_ext_hdrs} SOURCES ${gapi_srcs}) |
||||
ocv_module_include_directories("${CMAKE_CURRENT_LIST_DIR}/src") |
||||
|
||||
# Note `ade` is not a module name but link dependency for ${the_module} |
||||
# (which is opencv_gapi) |
||||
ocv_create_module(ade) |
||||
|
||||
ocv_add_accuracy_tests() |
||||
# 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 (!) |
||||
# src/ is specified to include dirs for INTERNAL tests only. |
||||
if(TARGET opencv_test_gapi) |
||||
target_include_directories(opencv_test_gapi PRIVATE "${CMAKE_CURRENT_LIST_DIR}/src") |
||||
target_link_libraries(opencv_test_gapi PRIVATE ade) |
||||
endif() |
||||
|
||||
ocv_add_perf_tests() |
@ -0,0 +1,36 @@ |
||||
if(ANDROID) |
||||
# FIXME: Android build will be enabled separately |
||||
return() |
||||
endif() |
||||
|
||||
set(ade_src_dir "${OpenCV_BINARY_DIR}/3rdparty/ade") |
||||
set(ade_filename "v0.1.1c.zip") |
||||
set(ade_subdir "ade-0.1.1c") |
||||
set(ade_md5 "db7e6a260229ee562a1b2857df473af8") |
||||
ocv_download(FILENAME ${ade_filename} |
||||
HASH ${ade_md5} |
||||
URL |
||||
"${OPENCV_ADE_URL}" |
||||
"$ENV{OPENCV_ADE_URL}" |
||||
"https://github.com/opencv/ade/archive/" |
||||
DESTINATION_DIR ${ade_src_dir} |
||||
ID ADE |
||||
STATUS res |
||||
UNPACK RELATIVE_URL) |
||||
|
||||
if (NOT res) |
||||
return() |
||||
endif() |
||||
|
||||
set(ADE_root "${ade_src_dir}/${ade_subdir}/sources/ade") |
||||
file(GLOB_RECURSE ADE_sources "${ADE_root}/source/*.cpp") |
||||
file(GLOB_RECURSE ADE_include "${ADE_root}/include/ade/*.hpp") |
||||
add_library(ade STATIC ${ADE_include} ${ADE_sources}) |
||||
target_include_directories(ade PUBLIC $<BUILD_INTERFACE:${ADE_root}/include>) |
||||
set_target_properties(ade PROPERTIES POSITION_INDEPENDENT_CODE True) |
||||
|
||||
if(NOT BUILD_SHARED_LIBS) |
||||
ocv_install_target(ade EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev) |
||||
endif() |
||||
|
||||
ocv_install_3rdparty_licenses(ade "${ade_src_dir}/${ade_subdir}/LICENSE") |
@ -0,0 +1,11 @@ |
||||
if (ade_DIR) |
||||
# if ade_DIR is set, use ADE-supplied CMake script |
||||
# to set up variables to the prebuilt ADE |
||||
find_package(ade 0.1.0) |
||||
endif() |
||||
|
||||
if(NOT TARGET ade) |
||||
# if ade_DIR is not set, try to use automatically |
||||
# downloaded one (if there any) |
||||
include("${CMAKE_CURRENT_LIST_DIR}/DownloadADE.cmake") |
||||
endif() |
@ -0,0 +1,3 @@ |
||||
# Graph API {#gapi} |
||||
|
||||
Introduction to G-API (WIP). |
@ -0,0 +1,21 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_HPP |
||||
#define OPENCV_GAPI_HPP |
||||
|
||||
#include <memory> |
||||
|
||||
#include "opencv2/gapi/gmat.hpp" |
||||
#include "opencv2/gapi/garray.hpp" |
||||
#include "opencv2/gapi/gcomputation.hpp" |
||||
#include "opencv2/gapi/gcompiled.hpp" |
||||
#include "opencv2/gapi/gtyped.hpp" |
||||
#include "opencv2/gapi/gkernel.hpp" |
||||
#include "opencv2/gapi/operators.hpp" |
||||
|
||||
#endif // OPENCV_GAPI_HPP
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,27 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_CPU_CORE_API_HPP |
||||
#define OPENCV_GAPI_CPU_CORE_API_HPP |
||||
|
||||
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage |
||||
#include "opencv2/gapi/own/exports.hpp" // GAPI_EXPORTS |
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
namespace core { |
||||
namespace cpu { |
||||
|
||||
GAPI_EXPORTS GKernelPackage kernels(); |
||||
|
||||
} // namespace cpu
|
||||
} // namespace core
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
|
||||
#endif // OPENCV_GAPI_CPU_CORE_API_HPP
|
@ -0,0 +1,236 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GCPUKERNEL_HPP |
||||
#define OPENCV_GAPI_GCPUKERNEL_HPP |
||||
|
||||
#include <vector> |
||||
#include <functional> |
||||
#include <map> |
||||
#include <unordered_map> |
||||
|
||||
#include <opencv2/core/mat.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/util/compiler_hints.hpp> //suppress_unused_warning |
||||
|
||||
// FIXME: namespace scheme for backends?
|
||||
namespace cv { |
||||
|
||||
namespace gimpl |
||||
{ |
||||
// Forward-declare an internal class
|
||||
class GCPUExecutable; |
||||
} // namespace gimpl
|
||||
|
||||
namespace gapi |
||||
{ |
||||
namespace cpu |
||||
{ |
||||
GAPI_EXPORTS cv::gapi::GBackend backend(); |
||||
} // namespace cpu
|
||||
} // namespace gapi
|
||||
|
||||
// Represents arguments which are passed to a wrapped CPU function
|
||||
// FIXME: put into detail?
|
||||
class GAPI_EXPORTS GCPUContext |
||||
{ |
||||
public: |
||||
// Generic accessor API
|
||||
template<typename T> |
||||
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::gapi::own::Scalar& inVal(int input); |
||||
cv::gapi::own::Scalar& outValR(int output); // FIXME: Avoid cv::gapi::own::Scalar s = ctx.outValR()
|
||||
template<typename T> std::vector<T>& outVecR(int output) // FIXME: the same issue
|
||||
{ |
||||
return outVecRef(output).wref<T>(); |
||||
} |
||||
|
||||
protected: |
||||
detail::VectorRef& outVecRef(int output); |
||||
|
||||
std::vector<GArg> m_args; |
||||
|
||||
//FIXME: avoid conversion of arguments from internal representaion to OpenCV one on each call
|
||||
//to OCV kernel. (This can be achieved by a two single time conversions in GCPUExecutable::run,
|
||||
//once on enter for input and output arguments, and once before return for output arguments only
|
||||
std::unordered_map<std::size_t, GRunArgP> m_results; |
||||
|
||||
friend class gimpl::GCPUExecutable; |
||||
}; |
||||
|
||||
class GAPI_EXPORTS GCPUKernel |
||||
{ |
||||
public: |
||||
// This function is kernel's execution entry point (does the processing work)
|
||||
using F = std::function<void(GCPUContext &)>; |
||||
|
||||
GCPUKernel(); |
||||
explicit GCPUKernel(const F& f); |
||||
|
||||
void apply(GCPUContext &ctx); |
||||
|
||||
protected: |
||||
F m_f; |
||||
}; |
||||
|
||||
// FIXME: This is an ugly ad-hoc imlpementation. TODO: refactor
|
||||
|
||||
namespace detail |
||||
{ |
||||
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)); } |
||||
}; |
||||
template<> struct get_in<cv::GScalar> |
||||
{ |
||||
static cv::Scalar get(GCPUContext &ctx, int idx) { return to_ocv(ctx.inVal(idx)); } |
||||
}; |
||||
template<typename U> struct get_in<cv::GArray<U> > |
||||
{ |
||||
static const std::vector<U>& get(GCPUContext &ctx, int idx) { return ctx.inArg<VectorRef>(idx).rref<U>(); } |
||||
}; |
||||
template<class T> struct get_in |
||||
{ |
||||
static T get(GCPUContext &ctx, int idx) { return ctx.inArg<T>(idx); } |
||||
}; |
||||
|
||||
struct tracked_cv_mat{ |
||||
tracked_cv_mat(cv::gapi::own::Mat& m) : r{to_ocv(m)}, original_data{m.data} {} |
||||
cv::Mat r; |
||||
uchar* original_data; |
||||
|
||||
operator cv::Mat& (){ return r;} |
||||
void validate() const{ |
||||
if (r.data != original_data) |
||||
{ |
||||
util::throw_error |
||||
(std::logic_error |
||||
("OpenCV kernel output parameter was reallocated. \n" |
||||
"Incorrect meta data was provided ?")); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
struct scalar_wrapper |
||||
{ |
||||
scalar_wrapper(cv::gapi::own::Scalar& s) : m_s{cv::gapi::own::to_ocv(s)}, m_org_s(s) {}; |
||||
operator cv::Scalar& () { return m_s; } |
||||
void writeBack() const { m_org_s = to_own(m_s); } |
||||
|
||||
cv::Scalar m_s; |
||||
cv::gapi::own::Scalar& m_org_s; |
||||
}; |
||||
|
||||
template<typename... Outputs> |
||||
void postprocess(Outputs&... outs) |
||||
{ |
||||
struct
|
||||
{ |
||||
void operator()(tracked_cv_mat* bm) { bm->validate(); } |
||||
void operator()(scalar_wrapper* sw) { sw->writeBack(); } |
||||
void operator()(...) { } |
||||
|
||||
} validate; |
||||
//dummy array to unfold parameter pack
|
||||
int dummy[] = { 0, (validate(&outs), 0)... }; |
||||
cv::util::suppress_unused_warning(dummy); |
||||
} |
||||
|
||||
template<class T> struct get_out; |
||||
template<> struct get_out<cv::GMat> |
||||
{ |
||||
static tracked_cv_mat get(GCPUContext &ctx, int idx) |
||||
{ |
||||
auto& r = ctx.outMatR(idx); |
||||
return {r}; |
||||
} |
||||
}; |
||||
template<> struct get_out<cv::GScalar> |
||||
{ |
||||
static scalar_wrapper get(GCPUContext &ctx, int idx) |
||||
{ |
||||
auto& s = ctx.outValR(idx); |
||||
return {s}; |
||||
} |
||||
}; |
||||
template<typename U> struct get_out<cv::GArray<U>> |
||||
{ |
||||
static std::vector<U>& get(GCPUContext &ctx, int idx) |
||||
{ |
||||
return ctx.outVecR<U>(idx); |
||||
} |
||||
}; |
||||
|
||||
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...> > |
||||
{ |
||||
template<typename... Inputs> |
||||
struct call_and_postprocess |
||||
{ |
||||
template<typename... Outputs> |
||||
static void call(Inputs&&... ins, Outputs&&... outs) |
||||
{ |
||||
//not using a std::forward on outs is deliberate in order to
|
||||
//cause compilation error, by tring to bind rvalue references to lvalue references
|
||||
Impl::run(std::forward<Inputs>(ins)..., outs...); |
||||
|
||||
postprocess(outs...); |
||||
} |
||||
}; |
||||
|
||||
template<int... IIs, int... OIs> |
||||
static void call_impl(GCPUContext &ctx, detail::Seq<IIs...>, detail::Seq<OIs...>) |
||||
{ |
||||
//Make sure that OpenCV kernels do not reallocate memory for output parameters
|
||||
//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)...); |
||||
} |
||||
|
||||
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 detail::OCVCallHelper<Impl, typename K::InArgs, typename K::OutArgs> |
||||
{ |
||||
using P = 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); } |
||||
}; |
||||
|
||||
#define GAPI_OCV_KERNEL(Name, API) struct Name: public cv::GCPUKernelImpl<Name, API> |
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_GCPUKERNEL_HPP
|
@ -0,0 +1,27 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_CPU_IMGPROC_API_HPP |
||||
#define OPENCV_GAPI_CPU_IMGPROC_API_HPP |
||||
|
||||
#include <opencv2/core/cvdef.h> // GAPI_EXPORTS |
||||
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage |
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
namespace imgproc { |
||||
namespace cpu { |
||||
|
||||
GAPI_EXPORTS GKernelPackage kernels(); |
||||
|
||||
} // namespace cpu
|
||||
} // namespace imgproc
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
|
||||
#endif // OPENCV_GAPI_CPU_IMGPROC_API_HPP
|
@ -0,0 +1,120 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_FLUID_BUFFER_HPP |
||||
#define OPENCV_GAPI_FLUID_BUFFER_HPP |
||||
|
||||
#include <list> |
||||
#include <numeric> // accumulate |
||||
#include <ostream> // ostream |
||||
#include <cstdint> // uint8_t |
||||
|
||||
#include <opencv2/gapi/opencv_includes.hpp> |
||||
#include <opencv2/gapi/gmat.hpp> |
||||
|
||||
#include "opencv2/gapi/util/optional.hpp" |
||||
#include "opencv2/gapi/own/scalar.hpp" |
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
namespace fluid { |
||||
|
||||
struct Border |
||||
{ |
||||
#if 1 |
||||
Border(int _type, cv::Scalar _val) : type(_type), value(to_own(_val)) {}; |
||||
#endif |
||||
Border(int _type, cv::gapi::own::Scalar _val) : type(_type), value(_val) {}; |
||||
int type; |
||||
cv::gapi::own::Scalar value; |
||||
}; |
||||
|
||||
using BorderOpt = util::optional<Border>; |
||||
|
||||
bool operator == (const Border& b1, const Border& b2); |
||||
|
||||
class GAPI_EXPORTS Buffer; |
||||
|
||||
class GAPI_EXPORTS View |
||||
{ |
||||
public: |
||||
View() = default; |
||||
|
||||
const uint8_t* InLineB(int index) const; // -(w-1)/2...0...+(w-1)/2 for Filters
|
||||
template<typename T> const T* InLine(int i) const |
||||
{ |
||||
const uint8_t* ptr = this->InLineB(i); |
||||
return reinterpret_cast<const T*>(ptr); |
||||
} |
||||
|
||||
operator bool() const; |
||||
bool ready() const; |
||||
int length() const; |
||||
int y() const; |
||||
|
||||
GMatDesc meta() const; |
||||
|
||||
class GAPI_EXPORTS Priv; // internal use only
|
||||
Priv& priv(); // internal use only
|
||||
const Priv& priv() const; // internal use only
|
||||
|
||||
View(Priv* p); |
||||
|
||||
private: |
||||
std::shared_ptr<Priv> m_priv; |
||||
}; |
||||
|
||||
class GAPI_EXPORTS Buffer |
||||
{ |
||||
public: |
||||
// Default constructor (executable creation stage,
|
||||
// all following initialization performed in Priv::init())
|
||||
Buffer(); |
||||
// Scratch constructor (user kernels)
|
||||
Buffer(const cv::GMatDesc &desc); |
||||
|
||||
// Constructor for intermediate buffers (for tests)
|
||||
Buffer(const cv::GMatDesc &desc, |
||||
int max_line_consumption, int border_size, |
||||
int skew, |
||||
int wlpi, |
||||
BorderOpt border); |
||||
// Constructor for in/out buffers (for tests)
|
||||
Buffer(const cv::Mat &data, bool is_input); |
||||
|
||||
uint8_t* OutLineB(int index = 0); |
||||
template<typename T> T* OutLine(int index = 0) |
||||
{ |
||||
uint8_t* ptr = this->OutLineB(index); |
||||
return reinterpret_cast<T*>(ptr); |
||||
} |
||||
|
||||
int y() const; |
||||
|
||||
int linesReady() const; |
||||
void debug(std::ostream &os) const; |
||||
int length() const; |
||||
int lpi() const; // LPI for WRITER
|
||||
|
||||
GMatDesc meta() const; |
||||
|
||||
View mkView(int lineConsumption, int borderSize, BorderOpt border, bool ownStorage); |
||||
|
||||
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; |
||||
|
||||
}; |
||||
|
||||
} // namespace cv::gapi::fluid
|
||||
} // namespace cv::gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_FLUID_BUFFER_HPP
|
@ -0,0 +1,283 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_FLUID_KERNEL_HPP |
||||
#define OPENCV_GAPI_FLUID_KERNEL_HPP |
||||
|
||||
#include <vector> |
||||
#include <functional> |
||||
#include <map> |
||||
#include <unordered_map> |
||||
|
||||
#include <opencv2/gapi/opencv_includes.hpp> |
||||
#include <opencv2/gapi/gcommon.hpp> |
||||
#include <opencv2/gapi/gkernel.hpp> |
||||
#include <opencv2/gapi/garg.hpp> |
||||
#include <opencv2/gapi/own/types.hpp> |
||||
|
||||
#include <opencv2/gapi/fluid/gfluidbuffer.hpp> |
||||
|
||||
// FIXME: namespace scheme for backends?
|
||||
namespace cv { |
||||
|
||||
namespace gapi |
||||
{ |
||||
namespace fluid |
||||
{ |
||||
GAPI_EXPORTS cv::gapi::GBackend backend(); |
||||
} // namespace flud
|
||||
} // namespace gapi
|
||||
|
||||
class GAPI_EXPORTS GFluidKernel |
||||
{ |
||||
public: |
||||
enum class Kind |
||||
{ |
||||
Filter, |
||||
Resize |
||||
}; |
||||
|
||||
// This function is a generic "doWork" callback
|
||||
using F = std::function<void(const cv::GArgs&, const std::vector<gapi::fluid::Buffer*> &)>; |
||||
|
||||
// This function is a generic "initScratch" callback
|
||||
using IS = std::function<void(const cv::GMetaArgs &, const cv::GArgs&, gapi::fluid::Buffer &)>; |
||||
|
||||
// This function is a generic "resetScratch" callback
|
||||
using RS = std::function<void(gapi::fluid::Buffer &)>; |
||||
|
||||
// This function describes kernel metadata inference rule.
|
||||
using M = std::function<GMetaArgs(const GMetaArgs &, const GArgs &)>; |
||||
|
||||
// This function is a generic "getBorder" callback (extracts border-related data from kernel's input parameters)
|
||||
using B = std::function<gapi::fluid::BorderOpt(const GMetaArgs&, const GArgs&)>; |
||||
|
||||
// FIXME: move implementations out of header file
|
||||
GFluidKernel() {} |
||||
GFluidKernel(int w, Kind k, int l, bool scratch, const F& f, const IS &is, const RS &rs, const B& b) |
||||
: m_window(w) |
||||
, m_kind(k) |
||||
, m_lpi(l) |
||||
, m_scratch(scratch) |
||||
, m_f(f) |
||||
, m_is(is) |
||||
, m_rs(rs) |
||||
, m_b(b) {} |
||||
|
||||
int m_window = -1; |
||||
Kind m_kind; |
||||
const int m_lpi = -1; |
||||
const bool m_scratch = false; |
||||
|
||||
const F m_f; |
||||
const IS m_is; |
||||
const RS m_rs; |
||||
const B m_b; |
||||
}; |
||||
|
||||
// FIXME!!!
|
||||
// This is the temporary and experimental API
|
||||
// which should be replaced by runtime roi-based scheduling
|
||||
struct GFluidOutputRois |
||||
{ |
||||
std::vector<cv::gapi::own::Rect> rois; |
||||
}; |
||||
|
||||
namespace detail |
||||
{ |
||||
template<> struct CompileArgTag<GFluidOutputRois> |
||||
{ |
||||
static const char* tag() { return "gapi.fluid.outputRois"; } |
||||
}; |
||||
} // namespace detail
|
||||
|
||||
namespace detail |
||||
{ |
||||
template<class T> struct fluid_get_in; |
||||
template<> struct fluid_get_in<cv::GMat> |
||||
{ |
||||
static const cv::gapi::fluid::View& get(const cv::GArgs &in_args, int idx) |
||||
{ |
||||
return in_args[idx].get<cv::gapi::fluid::View>(); |
||||
} |
||||
}; |
||||
|
||||
template<> struct fluid_get_in<cv::GScalar> |
||||
{ |
||||
static const cv::Scalar get(const cv::GArgs &in_args, int idx) |
||||
{ |
||||
return cv::gapi::own::to_ocv(in_args[idx].get<cv::gapi::own::Scalar>()); |
||||
} |
||||
}; |
||||
template<class T> struct fluid_get_in |
||||
{ |
||||
static T get(const cv::GArgs &in_args, int idx) |
||||
{ |
||||
return in_args[idx].get<T>(); |
||||
} |
||||
}; |
||||
|
||||
template<bool, typename Impl, typename... Ins> |
||||
struct scratch_helper; |
||||
|
||||
template<typename Impl, typename... Ins> |
||||
struct scratch_helper<true, Impl, Ins...> |
||||
{ |
||||
// Init
|
||||
template<int... IIs> |
||||
static void help_init_impl(const cv::GMetaArgs &metas, |
||||
const cv::GArgs &in_args, |
||||
gapi::fluid::Buffer &scratch_buf, |
||||
detail::Seq<IIs...>) |
||||
{ |
||||
Impl::initScratch(get_in_meta<Ins>(metas, in_args, IIs)..., scratch_buf); |
||||
} |
||||
|
||||
static void help_init(const cv::GMetaArgs &metas, |
||||
const cv::GArgs &in_args, |
||||
gapi::fluid::Buffer &b) |
||||
{ |
||||
help_init_impl(metas, in_args, b, typename detail::MkSeq<sizeof...(Ins)>::type()); |
||||
} |
||||
|
||||
// Reset
|
||||
static void help_reset(gapi::fluid::Buffer &b) |
||||
{ |
||||
Impl::resetScratch(b); |
||||
} |
||||
}; |
||||
|
||||
template<typename Impl, typename... Ins> |
||||
struct scratch_helper<false, Impl, Ins...> |
||||
{ |
||||
static void help_init(const cv::GMetaArgs &, |
||||
const cv::GArgs &, |
||||
gapi::fluid::Buffer &) |
||||
{ |
||||
GAPI_Assert(false); |
||||
} |
||||
static void help_reset(gapi::fluid::Buffer &) |
||||
{ |
||||
GAPI_Assert(false); |
||||
} |
||||
}; |
||||
|
||||
template<typename T> struct is_gmat_type |
||||
{ |
||||
static const constexpr bool value = std::is_same<cv::GMat, T>::value; |
||||
}; |
||||
|
||||
template<bool CallCustomGetBorder, typename Impl, typename... Ins> |
||||
struct get_border_helper; |
||||
|
||||
template<typename Impl, typename... Ins> |
||||
struct get_border_helper<true, Impl, Ins...> |
||||
{ |
||||
template<int... IIs> |
||||
static gapi::fluid::BorderOpt get_border_impl(const GMetaArgs &metas, |
||||
const cv::GArgs &in_args, |
||||
cv::detail::Seq<IIs...>) |
||||
{ |
||||
return util::make_optional(Impl::getBorder(cv::detail::get_in_meta<Ins>(metas, in_args, IIs)...)); |
||||
} |
||||
|
||||
static gapi::fluid::BorderOpt help(const GMetaArgs &metas, |
||||
const cv::GArgs &in_args) |
||||
{ |
||||
return get_border_impl(metas, in_args, typename detail::MkSeq<sizeof...(Ins)>::type()); |
||||
} |
||||
}; |
||||
|
||||
template<typename Impl, typename... Ins> |
||||
struct get_border_helper<false, Impl, Ins...> |
||||
{ |
||||
static gapi::fluid::BorderOpt help(const cv::GMetaArgs &, |
||||
const cv::GArgs &) |
||||
{ |
||||
return {}; |
||||
} |
||||
}; |
||||
|
||||
template<typename, typename, typename, bool UseScratch> |
||||
struct FluidCallHelper; |
||||
|
||||
template<typename Impl, typename... Ins, typename... Outs, bool UseScratch> |
||||
struct FluidCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...>, UseScratch> |
||||
{ |
||||
static_assert(all_satisfy<is_gmat_type, Outs...>::value, "return type must be GMat"); |
||||
|
||||
// Execution dispatcher ////////////////////////////////////////////////////
|
||||
template<int... IIs, int... OIs> |
||||
static void call_impl(const cv::GArgs &in_args, |
||||
const std::vector<gapi::fluid::Buffer*> &out_bufs, |
||||
detail::Seq<IIs...>, |
||||
detail::Seq<OIs...>) |
||||
{ |
||||
Impl::run(fluid_get_in<Ins>::get(in_args, IIs)..., *out_bufs[OIs]...); |
||||
} |
||||
|
||||
static void call(const cv::GArgs &in_args, |
||||
const std::vector<gapi::fluid::Buffer*> &out_bufs) |
||||
{ |
||||
constexpr int numOuts = (sizeof...(Outs)) + (UseScratch ? 1 : 0); |
||||
call_impl(in_args, out_bufs, |
||||
typename detail::MkSeq<sizeof...(Ins)>::type(), |
||||
typename detail::MkSeq<numOuts>::type()); |
||||
} |
||||
|
||||
// Scratch buffer initialization dispatcher ////////////////////////////////
|
||||
static void init_scratch(const GMetaArgs &metas, |
||||
const cv::GArgs &in_args, |
||||
gapi::fluid::Buffer &b) |
||||
{ |
||||
scratch_helper<UseScratch, Impl, Ins...>::help_init(metas, in_args, b); |
||||
} |
||||
|
||||
// Scratch buffer reset dispatcher /////////////////////////////////////////
|
||||
static void reset_scratch(gapi::fluid::Buffer &scratch_buf) |
||||
{ |
||||
scratch_helper<UseScratch, Impl, Ins...>::help_reset(scratch_buf); |
||||
} |
||||
|
||||
static gapi::fluid::BorderOpt getBorder(const GMetaArgs &metas, const cv::GArgs &in_args) |
||||
{ |
||||
// User must provide "init" callback if Window != 1
|
||||
// TODO: move to constexpr if when we enable C++17
|
||||
constexpr bool callCustomGetBorder = (Impl::Window != 1); |
||||
return get_border_helper<callCustomGetBorder, Impl, Ins...>::help(metas, in_args); |
||||
} |
||||
}; |
||||
} // namespace detail
|
||||
|
||||
|
||||
template<class Impl, class K, bool UseScratch> |
||||
class GFluidKernelImpl |
||||
{ |
||||
static const int LPI = 1; |
||||
static const auto Kind = GFluidKernel::Kind::Filter; |
||||
using P = detail::FluidCallHelper<Impl, typename K::InArgs, typename K::OutArgs, UseScratch>; |
||||
|
||||
public: |
||||
using API = K; |
||||
|
||||
static GFluidKernel kernel() |
||||
{ |
||||
// FIXME: call() and getOutMeta() needs to be renamed so it is clear these
|
||||
// functions are internal wrappers, not user API
|
||||
return GFluidKernel(Impl::Window, Impl::Kind, Impl::LPI, |
||||
UseScratch, |
||||
&P::call, &P::init_scratch, &P::reset_scratch, &P::getBorder); |
||||
} |
||||
|
||||
static cv::gapi::GBackend backend() { return cv::gapi::fluid::backend(); } |
||||
}; |
||||
|
||||
#define GAPI_FLUID_KERNEL(Name, API, Scratch) struct Name: public cv::GFluidKernelImpl<Name, API, Scratch> |
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_GCPUKERNEL_HPP
|
@ -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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GARG_HPP |
||||
#define OPENCV_GAPI_GARG_HPP |
||||
|
||||
#include <vector> |
||||
#include <type_traits> |
||||
|
||||
#include <opencv2/gapi/opencv_includes.hpp> |
||||
#include "opencv2/gapi/own/mat.hpp" |
||||
|
||||
#include "opencv2/gapi/util/any.hpp" |
||||
#include "opencv2/gapi/util/variant.hpp" |
||||
|
||||
#include "opencv2/gapi/gmat.hpp" |
||||
#include "opencv2/gapi/gscalar.hpp" |
||||
#include "opencv2/gapi/garray.hpp" |
||||
#include "opencv2/gapi/gtype_traits.hpp" |
||||
#include "opencv2/gapi/gmetaarg.hpp" |
||||
#include "opencv2/gapi/own/scalar.hpp" |
||||
|
||||
namespace cv { |
||||
|
||||
class GArg; |
||||
|
||||
namespace detail { |
||||
template<typename T> |
||||
using is_garg = std::is_same<GArg, typename std::decay<T>::type>; |
||||
} |
||||
|
||||
// Parameter holder class for a node
|
||||
// Depending on platform capabilities, can either support arbitrary types
|
||||
// (as `boost::any`) or a limited number of types (as `boot::variant`).
|
||||
// FIXME: put into "details" as a user shouldn't use it in his code
|
||||
class GAPI_EXPORTS GArg |
||||
{ |
||||
public: |
||||
GArg() {} |
||||
|
||||
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) |
||||
, 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) |
||||
, value(detail::wrap_gapi_helper<T>::wrap(t)) |
||||
{ |
||||
} |
||||
|
||||
template<typename T> T& get() |
||||
{ |
||||
return util::any_cast<typename std::remove_reference<T>::type>(value); |
||||
} |
||||
|
||||
template<typename T> const T& get() const |
||||
{ |
||||
return util::any_cast<typename std::remove_reference<T>::type>(value); |
||||
} |
||||
|
||||
detail::ArgKind kind = detail::ArgKind::OPAQUE; |
||||
|
||||
protected: |
||||
util::any value; |
||||
}; |
||||
|
||||
using GArgs = std::vector<GArg>; |
||||
|
||||
// FIXME: Express as M<GProtoArg...>::type
|
||||
// FIXME: Move to a separate file!
|
||||
using GRunArg = util::variant<cv::Mat, cv::gapi::own::Mat, cv::Scalar, cv::gapi::own::Scalar, cv::detail::VectorRef>; |
||||
using GRunArgs = std::vector<GRunArg>; |
||||
|
||||
using GRunArgP = util::variant<cv::Mat*, cv::gapi::own::Mat*, cv::Scalar*, cv::gapi::own::Scalar*, cv::detail::VectorRef>; |
||||
using GRunArgsP = std::vector<GRunArgP>; |
||||
|
||||
|
||||
template<typename... Ts> inline GRunArgs gin(const Ts&... args) |
||||
{ |
||||
return GRunArgs{ GRunArg(detail::wrap_host_helper<Ts>::wrap_in(args))... }; |
||||
} |
||||
|
||||
template<typename... Ts> inline GRunArgsP gout(Ts&... args) |
||||
{ |
||||
return GRunArgsP{ GRunArgP(detail::wrap_host_helper<Ts>::wrap_out(args))... }; |
||||
} |
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_GARG_HPP
|
@ -0,0 +1,239 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GARRAY_HPP |
||||
#define OPENCV_GAPI_GARRAY_HPP |
||||
|
||||
#include <functional> |
||||
#include <ostream> |
||||
#include <vector> |
||||
#include <memory> |
||||
|
||||
#include <opencv2/gapi/own/exports.hpp> |
||||
#include <opencv2/gapi/opencv_includes.hpp> |
||||
|
||||
#include <opencv2/gapi/util/variant.hpp> |
||||
#include <opencv2/gapi/util/throw.hpp> |
||||
#include "opencv2/gapi/own/assert.hpp" |
||||
|
||||
namespace cv |
||||
{ |
||||
// Forward declaration; GNode and GOrigin are an internal
|
||||
// (user-inaccessible) classes.
|
||||
class GNode; |
||||
struct GOrigin; |
||||
|
||||
template<typename T> class GArray; |
||||
|
||||
struct GArrayDesc |
||||
{ |
||||
// FIXME: Body
|
||||
// FIXME: Also implement proper operator== then
|
||||
bool operator== (const GArrayDesc&) const { return true; } |
||||
}; |
||||
template<typename U> GArrayDesc descr_of(const std::vector<U> &) { return {};} |
||||
inline GArrayDesc empty_array_desc() {return {}; } |
||||
std::ostream& operator<<(std::ostream& os, const cv::GArrayDesc &desc); |
||||
|
||||
namespace detail |
||||
{ |
||||
// ConstructVec is a callback which stores information about T and is used by
|
||||
// G-API runtime to construct arrays in host memory (T remains opaque for G-API).
|
||||
// ConstructVec is carried into G-API internals by GArrayU.
|
||||
// Currently it is suitable for Host (CPU) plugins only, real offload may require
|
||||
// more information for manual memory allocation on-device.
|
||||
class VectorRef; |
||||
using ConstructVec = std::function<void(VectorRef&)>; |
||||
|
||||
|
||||
// This class strips type information from GArray<T> and makes it usable
|
||||
// in the G-API graph compiler (expression unrolling, graph generation, etc).
|
||||
// Part of GProtoArg.
|
||||
class GAPI_EXPORTS GArrayU |
||||
{ |
||||
public: |
||||
GArrayU(const GNode &n, std::size_t out); // Operation result constructor
|
||||
|
||||
GOrigin& priv(); // Internal use only
|
||||
const GOrigin& priv() const; // Internal use only
|
||||
|
||||
protected: |
||||
GArrayU(); // Default constructor
|
||||
template<class> friend class cv::GArray; // (avialable to GArray<T> only)
|
||||
|
||||
void setConstructFcn(ConstructVec &&cv); // Store T-aware constructor
|
||||
|
||||
std::shared_ptr<GOrigin> m_priv; |
||||
}; |
||||
|
||||
// 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
|
||||
// (be value holder).
|
||||
class BasicVectorRef |
||||
{ |
||||
public: |
||||
std::size_t m_elemSize = 0ul; |
||||
cv::GArrayDesc m_desc; |
||||
virtual ~BasicVectorRef() {} |
||||
}; |
||||
|
||||
template<typename T> class VectorRefT: public BasicVectorRef |
||||
{ |
||||
using empty_t = util::monostate; |
||||
using ro_ext_t = const std::vector<T> *; |
||||
using rw_ext_t = std::vector<T> *; |
||||
using rw_own_t = std::vector<T> ; |
||||
util::variant<empty_t, ro_ext_t, rw_ext_t, rw_own_t> m_ref; |
||||
|
||||
inline bool isEmpty() const { return util::holds_alternative<empty_t>(m_ref); } |
||||
inline bool isROExt() const { return util::holds_alternative<ro_ext_t>(m_ref); } |
||||
inline bool isRWExt() const { return util::holds_alternative<rw_ext_t>(m_ref); } |
||||
inline bool isRWOwn() const { return util::holds_alternative<rw_own_t>(m_ref); } |
||||
|
||||
void init(const std::vector<T>* vec = nullptr) |
||||
{ |
||||
m_elemSize = sizeof(T); |
||||
if (vec) m_desc = cv::descr_of(*vec); |
||||
} |
||||
|
||||
public: |
||||
VectorRefT() { init(); } |
||||
virtual ~VectorRefT() {} |
||||
|
||||
explicit VectorRefT(const std::vector<T>& vec) : m_ref(&vec) { init(&vec); } |
||||
explicit VectorRefT(std::vector<T>& vec) : m_ref(&vec) { init(&vec); } |
||||
explicit VectorRefT(std::vector<T>&& vec) : m_ref(std::move(vec)) { init(&vec); } |
||||
|
||||
// Reset a VectorRefT. Called only for objects instantiated
|
||||
// internally in G-API (e.g. temporary GArray<T>'s within a
|
||||
// computation). Reset here means both initialization
|
||||
// (creating an object) and reset (discarding its existing
|
||||
// content before the next execution). Must never be called
|
||||
// for external VectorRefTs.
|
||||
void reset() |
||||
{ |
||||
if (isEmpty()) |
||||
{ |
||||
std::vector<T> empty_vector; |
||||
m_desc = cv::descr_of(empty_vector); |
||||
m_ref = std::move(empty_vector); |
||||
GAPI_Assert(isRWOwn()); |
||||
} |
||||
else if (isRWOwn()) |
||||
{ |
||||
util::get<rw_own_t>(m_ref).clear(); |
||||
} |
||||
else GAPI_Assert(false); // shouldn't be called in *EXT modes
|
||||
} |
||||
|
||||
// Obtain a WRITE reference to underlying object
|
||||
// Used by CPU kernel API wrappers when a kernel execution frame
|
||||
// is created
|
||||
std::vector<T>& wref() |
||||
{ |
||||
GAPI_Assert(isRWExt() || isRWOwn()); |
||||
if (isRWExt()) return *util::get<rw_ext_t>(m_ref); |
||||
if (isRWOwn()) return util::get<rw_own_t>(m_ref); |
||||
util::throw_error(std::logic_error("Impossible happened")); |
||||
} |
||||
|
||||
// Obtain a READ reference to underlying object
|
||||
// Used by CPU kernel API wrappers when a kernel execution frame
|
||||
// is created
|
||||
const std::vector<T>& rref() const |
||||
{ |
||||
// ANY vector can be accessed for reading, even if it declared for
|
||||
// output. Example -- a GComputation from [in] to [out1,out2]
|
||||
// where [out2] is a result of operation applied to [out1]:
|
||||
//
|
||||
// GComputation boundary
|
||||
// . . . . . . .
|
||||
// . .
|
||||
// [in] ----> foo() ----> [out1]
|
||||
// . . :
|
||||
// . . . .:. . .
|
||||
// . V .
|
||||
// . bar() ---> [out2]
|
||||
// . . . . . . . . . . . .
|
||||
//
|
||||
if (isROExt()) return *util::get<ro_ext_t>(m_ref); |
||||
if (isRWExt()) return *util::get<rw_ext_t>(m_ref); |
||||
if (isRWOwn()) return util::get<rw_own_t>(m_ref); |
||||
util::throw_error(std::logic_error("Impossible happened")); |
||||
} |
||||
}; |
||||
|
||||
// This class strips type information from VectorRefT<> and makes it usable
|
||||
// in the G-API executables (carrying run-time data/information to kernels).
|
||||
// Part of GRunArg.
|
||||
// Its methods are typed proxies to VectorRefT<T>.
|
||||
// VectorRef maintains "reference" semantics so two copies of VectoRef refer
|
||||
// to the same underlying object.
|
||||
// FIXME: Put a good explanation on why cv::OutputArray doesn't fit this role
|
||||
class VectorRef |
||||
{ |
||||
std::shared_ptr<BasicVectorRef> m_ref; |
||||
|
||||
template<typename T> inline void check() const |
||||
{ |
||||
GAPI_DbgAssert(dynamic_cast<VectorRefT<T>*>(m_ref.get()) != nullptr); |
||||
GAPI_Assert(sizeof(T) == m_ref->m_elemSize); |
||||
} |
||||
|
||||
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> void reset() |
||||
{ |
||||
if (!m_ref) m_ref.reset(new VectorRefT<T>()); |
||||
|
||||
check<T>(); |
||||
static_cast<VectorRefT<T>&>(*m_ref).reset(); |
||||
} |
||||
|
||||
template<typename T> std::vector<T>& wref() |
||||
{ |
||||
check<T>(); |
||||
return static_cast<VectorRefT<T>&>(*m_ref).wref(); |
||||
} |
||||
|
||||
template<typename T> const std::vector<T>& rref() const |
||||
{ |
||||
check<T>(); |
||||
return static_cast<VectorRefT<T>&>(*m_ref).rref(); |
||||
} |
||||
|
||||
cv::GArrayDesc descr_of() const |
||||
{ |
||||
return m_ref->m_desc; |
||||
} |
||||
}; |
||||
} // namespace detail
|
||||
|
||||
template<typename T> class GArray |
||||
{ |
||||
public: |
||||
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: |
||||
static void VCTor(detail::VectorRef& vref) { vref.reset<T>(); } |
||||
void putDetails() {m_ref.setConstructFcn(&VCTor); } |
||||
|
||||
detail::GArrayU m_ref; |
||||
}; |
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_GARRAY_HPP
|
@ -0,0 +1,63 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GCALL_HPP |
||||
#define OPENCV_GAPI_GCALL_HPP |
||||
|
||||
#include "opencv2/gapi/garg.hpp" // GArg |
||||
#include "opencv2/gapi/gmat.hpp" // GMat |
||||
#include "opencv2/gapi/gscalar.hpp" // GScalar |
||||
#include "opencv2/gapi/garray.hpp" // GArray<T> |
||||
|
||||
namespace cv { |
||||
|
||||
struct GKernel; |
||||
|
||||
// The whole idea of this class is to represent an operation
|
||||
// which is applied to arguments. This is part of public API,
|
||||
// since it is what users should use to define kernel interfaces.
|
||||
|
||||
class GAPI_EXPORTS GCall final |
||||
{ |
||||
public: |
||||
class Priv; |
||||
|
||||
explicit GCall(const GKernel &k); |
||||
~GCall(); |
||||
|
||||
template<typename... Ts> |
||||
GCall& pass(Ts&&... args) |
||||
{ |
||||
setArgs({cv::GArg(std::move(args))...}); |
||||
return *this; |
||||
} |
||||
|
||||
// A generic yield method - obtain a link to operator's particular GMat output
|
||||
GMat yield (int output = 0); |
||||
GScalar yieldScalar(int output = 0); |
||||
|
||||
template<class T> GArray<T> yieldArray(int output = 0) |
||||
{ |
||||
return GArray<T>(yieldArray(output)); |
||||
} |
||||
|
||||
// Internal use only
|
||||
Priv& priv(); |
||||
const Priv& priv() const; |
||||
|
||||
protected: |
||||
std::shared_ptr<Priv> m_priv; |
||||
|
||||
void setArgs(std::vector<GArg> &&args); |
||||
|
||||
// Public version returns a typed array, this one is implementation detail
|
||||
detail::GArrayU yieldArray(int output = 0); |
||||
}; |
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_GCALL_HPP
|
@ -0,0 +1,118 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GCOMMON_HPP |
||||
#define OPENCV_GAPI_GCOMMON_HPP |
||||
|
||||
#include <functional> // std::hash |
||||
#include <vector> // std::vector |
||||
#include <type_traits> // decay |
||||
|
||||
#include <opencv2/gapi/opencv_includes.hpp> |
||||
|
||||
#include "opencv2/gapi/util/any.hpp" |
||||
#include "opencv2/gapi/own/exports.hpp" |
||||
#include "opencv2/gapi/own/assert.hpp" |
||||
|
||||
namespace cv { |
||||
|
||||
namespace detail |
||||
{ |
||||
// This is a trait-like structure to mark backend-specific compile arguments
|
||||
// with tags
|
||||
template<typename T> struct CompileArgTag; |
||||
template<typename T> struct CompileArgTag |
||||
{ |
||||
static const char* tag() { return ""; }; |
||||
}; |
||||
} |
||||
|
||||
// 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)
|
||||
// to components which are internal and operate on a lower-level entities
|
||||
// (e.g., compiler, backends).
|
||||
// FIXME: merge with ArgKind?
|
||||
// FIXME: replace with variant[format desc]?
|
||||
enum class GShape: int |
||||
{ |
||||
GMAT, |
||||
GSCALAR, |
||||
GARRAY, |
||||
}; |
||||
|
||||
struct GCompileArg; |
||||
|
||||
namespace detail { |
||||
template<typename T> |
||||
using is_compile_arg = std::is_same<GCompileArg, typename std::decay<T>::type>; |
||||
} |
||||
// CompileArg is an unified interface over backend-specific compilation
|
||||
// information
|
||||
// FIXME: Move to a separate file?
|
||||
struct GAPI_EXPORTS GCompileArg |
||||
{ |
||||
public: |
||||
std::string tag; |
||||
|
||||
// FIXME: use decay in GArg/other trait-based wrapper before leg is shot!
|
||||
template<typename T, typename std::enable_if<!detail::is_compile_arg<T>::value, int>::type = 0> |
||||
explicit GCompileArg(T &&t) |
||||
: tag(detail::CompileArgTag<typename std::decay<T>::type>::tag()) |
||||
, arg(t) |
||||
{ |
||||
} |
||||
|
||||
template<typename T> T& get() |
||||
{ |
||||
return util::any_cast<T>(arg); |
||||
} |
||||
|
||||
template<typename T> const T& get() const |
||||
{ |
||||
return util::any_cast<T>(arg); |
||||
} |
||||
|
||||
private: |
||||
util::any arg; |
||||
}; |
||||
|
||||
using GCompileArgs = std::vector<GCompileArg>; |
||||
|
||||
template<typename... Ts> GCompileArgs compile_args(Ts&&... args) |
||||
{ |
||||
return GCompileArgs{ GCompileArg(args)... }; |
||||
} |
||||
|
||||
struct graph_dump_path |
||||
{ |
||||
std::string m_dump_path; |
||||
}; |
||||
|
||||
namespace detail |
||||
{ |
||||
template<> struct CompileArgTag<cv::graph_dump_path> |
||||
{ |
||||
static const char* tag() { return "gapi.graph_dump_path"; } |
||||
}; |
||||
} |
||||
|
||||
} // namespace cv
|
||||
|
||||
// std::hash overload for GShape
|
||||
namespace std |
||||
{ |
||||
template<> struct hash<cv::GShape> |
||||
{ |
||||
size_t operator() (cv::GShape sh) const |
||||
{ |
||||
return std::hash<int>()(static_cast<int>(sh)); |
||||
} |
||||
}; |
||||
} // namespace std
|
||||
|
||||
|
||||
#endif // OPENCV_GAPI_GCOMMON_HPP
|
@ -0,0 +1,59 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GCOMPILED_HPP |
||||
#define OPENCV_GAPI_GCOMPILED_HPP |
||||
|
||||
#include <vector> |
||||
|
||||
#include "opencv2/gapi/own/assert.hpp" |
||||
#include "opencv2/core/mat.hpp" |
||||
|
||||
#include "opencv2/gapi/garg.hpp" |
||||
|
||||
namespace cv { |
||||
|
||||
// This class represents a compiled computation.
|
||||
// In theory (and ideally), it can be used w/o the rest of APIs.
|
||||
// In theory (and ideally), it can be serialized/deserialized.
|
||||
// It can enable scenarious like deployment to an autonomous devince, FuSa, etc.
|
||||
//
|
||||
// Currently GCompiled assumes all GMats you used to pass data to G-API
|
||||
// are valid and not destroyed while you use a GCompiled object.
|
||||
//
|
||||
// FIXME: In future, there should be a way to name I/O objects and specify it
|
||||
// to GCompiled externally (for example, when it is loaded on the target system).
|
||||
|
||||
class GAPI_EXPORTS GCompiled |
||||
{ |
||||
public: |
||||
class GAPI_EXPORTS Priv; |
||||
|
||||
GCompiled(); |
||||
|
||||
void operator() (GRunArgs &&ins, GRunArgsP &&outs); // Generic arg-to-arg
|
||||
void operator() (cv::Mat in, cv::Mat &out); // Unary overload
|
||||
void operator() (cv::Mat in, cv::Scalar &out); // Unary overload (scalar)
|
||||
void operator() (cv::Mat in1, cv::Mat in2, cv::Mat &out); // Binary overload
|
||||
void operator() (cv::Mat in1, cv::Mat in2, cv::Scalar &out); // Binary overload (scalar)
|
||||
void operator() (const std::vector<cv::Mat> &ins, // Compatibility overload
|
||||
const std::vector<cv::Mat> &outs); |
||||
|
||||
Priv& priv(); |
||||
|
||||
explicit operator bool () const; // Check if GCompiled is runnable or empty
|
||||
|
||||
const GMetaArgs& metas() const; // Meta passed to compile()
|
||||
const GMetaArgs& outMetas() const; // Inferred output metadata
|
||||
|
||||
protected: |
||||
std::shared_ptr<Priv> m_priv; |
||||
}; |
||||
|
||||
} |
||||
|
||||
#endif // OPENCV_GAPI_GCOMPILED_HPP
|
@ -0,0 +1,123 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GCOMPOUNDKERNEL_HPP |
||||
#define OPENCV_GAPI_GCOMPOUNDKERNEL_HPP |
||||
|
||||
#include <opencv2/gapi/opencv_includes.hpp> |
||||
#include <opencv2/gapi/gcommon.hpp> |
||||
#include <opencv2/gapi/gkernel.hpp> |
||||
#include <opencv2/gapi/garg.hpp> |
||||
|
||||
namespace cv { |
||||
namespace gapi |
||||
{ |
||||
namespace compound |
||||
{ |
||||
// FIXME User does not need to know about this function
|
||||
// Needs that user may define compound kernels(as cpu kernels)
|
||||
GAPI_EXPORTS cv::gapi::GBackend backend(); |
||||
} // namespace compound
|
||||
} // namespace gapi
|
||||
|
||||
namespace detail |
||||
{ |
||||
|
||||
struct GCompoundContext |
||||
{ |
||||
explicit GCompoundContext(const GArgs& in_args); |
||||
template<typename T> |
||||
const T& inArg(int input) { return m_args.at(input).get<T>(); } |
||||
|
||||
GArgs m_args; |
||||
GArgs m_results; |
||||
}; |
||||
|
||||
class GAPI_EXPORTS GCompoundKernel |
||||
{ |
||||
// Compound kernel must use all of it's inputs
|
||||
public: |
||||
using F = std::function<void(GCompoundContext& ctx)>; |
||||
|
||||
explicit GCompoundKernel(const F& f); |
||||
void apply(GCompoundContext& ctx); |
||||
|
||||
protected: |
||||
F m_f; |
||||
}; |
||||
|
||||
template<typename T> struct get_compound_in |
||||
{ |
||||
static T get(GCompoundContext &ctx, int idx) { return ctx.inArg<T>(idx); } |
||||
}; |
||||
|
||||
template<typename U> struct get_compound_in<cv::GArray<U>> |
||||
{ |
||||
static cv::GArray<U> get(GCompoundContext &ctx, int idx) |
||||
{ |
||||
auto array = cv::GArray<U>(); |
||||
ctx.m_args[idx] = GArg(array); |
||||
return array; |
||||
} |
||||
}; |
||||
|
||||
// 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 objs; } |
||||
}; |
||||
|
||||
template<typename, typename, typename> |
||||
struct GCompoundCallHelper; |
||||
|
||||
template<typename Impl, typename... Ins, typename... Outs> |
||||
struct GCompoundCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> > |
||||
{ |
||||
template<int... IIs, int... OIs> |
||||
static void expand_impl(GCompoundContext &ctx, detail::Seq<IIs...>, detail::Seq<OIs...>) |
||||
{ |
||||
auto result = Impl::expand(get_compound_in<Ins>::get(ctx, IIs)...); |
||||
auto tuple_return = tuple_wrap_helper<decltype(result)>::get(std::move(result)); |
||||
ctx.m_results = { cv::GArg(std::get<OIs>(tuple_return))... }; |
||||
} |
||||
|
||||
static void expand(GCompoundContext &ctx) |
||||
{ |
||||
expand_impl(ctx, |
||||
typename detail::MkSeq<sizeof...(Ins)>::type(), |
||||
typename detail::MkSeq<sizeof...(Outs)>::type()); |
||||
} |
||||
}; |
||||
|
||||
template<class Impl, class K> |
||||
class GCompoundKernelImpl: public cv::detail::GCompoundCallHelper<Impl, typename K::InArgs, typename K::OutArgs> |
||||
{ |
||||
using P = cv::detail::GCompoundCallHelper<Impl, typename K::InArgs, typename K::OutArgs>; |
||||
|
||||
public: |
||||
using API = K; |
||||
|
||||
static cv::gapi::GBackend backend() { return cv::gapi::compound::backend(); } |
||||
static GCompoundKernel kernel() { return GCompoundKernel(&P::expand); } |
||||
}; |
||||
|
||||
} // namespace detail
|
||||
#define GAPI_COMPOUND_KERNEL(Name, API) struct Name: public cv::detail::GCompoundKernelImpl<Name, API> |
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_GCOMPOUNDKERNEL_HPP
|
@ -0,0 +1,135 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GCOMPUTATION_HPP |
||||
#define OPENCV_GAPI_GCOMPUTATION_HPP |
||||
|
||||
#include <functional> |
||||
|
||||
#include "opencv2/gapi/util/util.hpp" |
||||
#include "opencv2/gapi/gcommon.hpp" |
||||
#include "opencv2/gapi/gproto.hpp" |
||||
#include "opencv2/gapi/garg.hpp" |
||||
#include "opencv2/gapi/gcompiled.hpp" |
||||
|
||||
namespace cv { |
||||
|
||||
namespace detail |
||||
{ |
||||
// FIXME: move to algorithm, cover with separate tests
|
||||
// FIXME: replace with O(1) version (both memory and compilation time)
|
||||
template<typename...> |
||||
struct last_type; |
||||
|
||||
template<typename T> |
||||
struct last_type<T> { using type = T;}; |
||||
|
||||
template<typename T, typename... Ts> |
||||
struct last_type<T, Ts...> { using type = typename last_type<Ts...>::type; }; |
||||
|
||||
template<typename... Ts> |
||||
using last_type_t = typename last_type<Ts...>::type; |
||||
} |
||||
|
||||
class GAPI_EXPORTS GComputation |
||||
{ |
||||
public: |
||||
class Priv; |
||||
typedef std::function<GComputation()> Generator; |
||||
|
||||
// Various constructors enable different ways to define a computation: /////
|
||||
// 1. Generic constructors
|
||||
GComputation(const Generator& gen); // Generator overload
|
||||
GComputation(GProtoInputArgs &&ins, |
||||
GProtoOutputArgs &&outs); // Arg-to-arg overload
|
||||
|
||||
// 2. Syntax sugar and compatibility overloads
|
||||
GComputation(GMat in, GMat out); // Unary overload
|
||||
GComputation(GMat in, GScalar out); // Unary overload (scalar)
|
||||
GComputation(GMat in1, GMat in2, GMat out); // Binary overload
|
||||
GComputation(GMat in1, GMat in2, GScalar out); // Binary overload (scalar)
|
||||
GComputation(const std::vector<GMat> &ins, // Compatibility overload
|
||||
const std::vector<GMat> &outs); |
||||
|
||||
// Various versions of apply(): ////////////////////////////////////////////
|
||||
// 1. Generic apply()
|
||||
void apply(GRunArgs &&ins, GRunArgsP &&outs, GCompileArgs &&args = {}); // Arg-to-arg overload
|
||||
|
||||
// 2. Syntax sugar and compatibility overloads
|
||||
void apply(cv::Mat in, cv::Mat &out, GCompileArgs &&args = {}); // Unary overload
|
||||
void apply(cv::Mat in, cv::Scalar &out, GCompileArgs &&args = {}); // Unary overload (scalar)
|
||||
void apply(cv::Mat in1, cv::Mat in2, cv::Mat &out, GCompileArgs &&args = {}); // Binary overload
|
||||
void apply(cv::Mat in1, cv::Mat in2, cv::Scalar &out, GCompileArgs &&args = {}); // Binary overload (scalar)
|
||||
void apply(const std::vector<cv::Mat>& ins, // Compatibility overload
|
||||
const std::vector<cv::Mat>& outs, |
||||
GCompileArgs &&args = {}); |
||||
|
||||
// Various versions of compile(): //////////////////////////////////////////
|
||||
// 1. Generic compile() - requires metas to be passed as vector
|
||||
GCompiled compile(GMetaArgs &&in_metas, GCompileArgs &&args = {}); |
||||
|
||||
// 2. Syntax sugar - variadic list of metas, no extra compile args
|
||||
template<typename... Ts> |
||||
auto compile(const Ts&... metas) -> |
||||
typename std::enable_if<detail::are_meta_descrs<Ts...>::value, GCompiled>::type |
||||
{ |
||||
return compile(GMetaArgs{GMetaArg(metas)...}, GCompileArgs()); |
||||
} |
||||
|
||||
// 3. Syntax sugar - variadic list of metas, extra compile args
|
||||
// (seems optional parameters don't work well when there's an variadic template
|
||||
// comes first)
|
||||
//
|
||||
// Ideally it should look like:
|
||||
//
|
||||
// template<typename... Ts>
|
||||
// GCompiled compile(const Ts&... metas, GCompileArgs &&args)
|
||||
//
|
||||
// But not all compilers can hande this (and seems they shouldn't be able to).
|
||||
template<typename... Ts> |
||||
auto compile(const Ts&... meta_and_compile_args) -> |
||||
typename std::enable_if<detail::are_meta_descrs_but_last<Ts...>::value |
||||
&& std::is_same<GCompileArgs, detail::last_type_t<Ts...> >::value, |
||||
GCompiled>::type |
||||
{ |
||||
//FIXME: wrapping meta_and_compile_args into a tuple to unwrap them inside a helper function is the overkill
|
||||
return compile(std::make_tuple(meta_and_compile_args...), |
||||
typename detail::MkSeq<sizeof...(Ts)-1>::type()); |
||||
} |
||||
|
||||
// Internal use only
|
||||
Priv& priv(); |
||||
const Priv& priv() const; |
||||
|
||||
protected: |
||||
|
||||
// 4. Helper method for (3)
|
||||
template<typename... Ts, int... IIs> |
||||
GCompiled compile(const std::tuple<Ts...> &meta_and_compile_args, detail::Seq<IIs...>) |
||||
{ |
||||
GMetaArgs meta_args = {GMetaArg(std::get<IIs>(meta_and_compile_args))...}; |
||||
GCompileArgs comp_args = std::get<sizeof...(Ts)-1>(meta_and_compile_args); |
||||
return compile(std::move(meta_args), std::move(comp_args)); |
||||
} |
||||
|
||||
std::shared_ptr<Priv> m_priv; |
||||
}; |
||||
|
||||
namespace gapi |
||||
{ |
||||
// Declare an Island tagged with `name` and defined from `ins` to `outs`
|
||||
// (exclusively, as ins/outs are data objects, and regioning is done on
|
||||
// operations level).
|
||||
// Throws if any operation between `ins` and `outs` are already assigned
|
||||
// to another island.
|
||||
void GAPI_EXPORTS island(const std::string &name, |
||||
GProtoInputArgs &&ins, |
||||
GProtoOutputArgs &&outs); |
||||
} // namespace gapi
|
||||
|
||||
} // namespace cv
|
||||
#endif // OPENCV_GAPI_GCOMPUTATION_HPP
|
@ -0,0 +1,409 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GKERNEL_HPP |
||||
#define OPENCV_GAPI_GKERNEL_HPP |
||||
|
||||
#include <functional> |
||||
#include <iostream> |
||||
#include <unordered_map> // map (for GKernelPackage) |
||||
#include <vector> // lookup order |
||||
#include <string> // string |
||||
#include <utility> // tuple |
||||
#include <type_traits> // false_type, true_type |
||||
|
||||
#include <opencv2/gapi/gcommon.hpp> // CompileArgTag |
||||
#include <opencv2/gapi/util/util.hpp> // Seq |
||||
#include <opencv2/gapi/gcall.hpp> |
||||
#include <opencv2/gapi/garg.hpp> // GArg |
||||
#include <opencv2/gapi/gmetaarg.hpp> // GMetaArg |
||||
#include <opencv2/gapi/gtype_traits.hpp> // GTypeTraits |
||||
#include <opencv2/gapi/util/compiler_hints.hpp> //suppress_unused_warning |
||||
|
||||
|
||||
namespace cv { |
||||
|
||||
using GShapes = std::vector<GShape>; |
||||
|
||||
// GKernel describes kernel API to the system
|
||||
// FIXME: add attributes of a kernel, (e.g. number and types
|
||||
// of inputs, etc)
|
||||
struct GAPI_EXPORTS GKernel |
||||
{ |
||||
using M = std::function<GMetaArgs(const GMetaArgs &, const GArgs &)>; |
||||
|
||||
const std::string name; // kernel ID, defined by its API (signature)
|
||||
const M outMeta; // generic adaptor to API::outMeta(...)
|
||||
const GShapes outShapes; // types (shapes) kernel's outputs
|
||||
}; |
||||
|
||||
// GKernelImpl describes particular kernel implementation to the system
|
||||
struct GAPI_EXPORTS GKernelImpl |
||||
{ |
||||
util::any opaque; // backend-specific opaque info
|
||||
}; |
||||
|
||||
template<typename, typename> class GKernelTypeM; |
||||
|
||||
namespace detail |
||||
{ |
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// yield() is used in graph construction time as a generic method to obtain
|
||||
// lazy "return value" of G-API operations
|
||||
//
|
||||
namespace |
||||
{ |
||||
|
||||
template<typename T> struct Yield; |
||||
template<> struct Yield<cv::GMat> |
||||
{ |
||||
static inline cv::GMat yield(cv::GCall &call, int i) { return call.yield(i); } |
||||
}; |
||||
template<> struct Yield<cv::GScalar> |
||||
{ |
||||
static inline cv::GScalar yield(cv::GCall &call, int i) { return call.yieldScalar(i); } |
||||
}; |
||||
template<typename U> struct Yield<cv::GArray<U> > |
||||
{ |
||||
static inline cv::GArray<U> yield(cv::GCall &call, int i) { return call.yieldArray<U>(i); } |
||||
}; |
||||
} // anonymous namespace
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Helper classes which brings outputMeta() marshalling to kernel
|
||||
// implementations
|
||||
//
|
||||
// 1. MetaType establishes G#Type -> G#Meta mapping between G-API dynamic
|
||||
// types and its metadata descriptor types.
|
||||
// This mapping is used to transform types to call outMeta() callback.
|
||||
template<typename T> struct MetaType; |
||||
template<> struct MetaType<cv::GMat> { using type = GMatDesc; }; |
||||
template<> struct MetaType<cv::GScalar> { using type = GScalarDesc; }; |
||||
template<typename U> struct MetaType<cv::GArray<U> > { using type = GArrayDesc; }; |
||||
template<typename T> struct MetaType { using type = T; }; // opaque args passed as-is
|
||||
|
||||
// 2. Hacky test based on MetaType to check if we operate on G-* type or not
|
||||
template<typename T> using is_nongapi_type = std::is_same<T, typename MetaType<T>::type>; |
||||
|
||||
// 3. Two ways to transform input arguments to its meta - for G-* and non-G* types:
|
||||
template<typename T> |
||||
typename std::enable_if<!is_nongapi_type<T>::value, typename MetaType<T>::type> |
||||
::type get_in_meta(const GMetaArgs &in_meta, const GArgs &, int idx) |
||||
{ |
||||
return util::get<typename MetaType<T>::type>(in_meta.at(idx)); |
||||
} |
||||
|
||||
template<typename T> |
||||
typename std::enable_if<is_nongapi_type<T>::value, T> |
||||
::type get_in_meta(const GMetaArgs &, const GArgs &in_args, int idx) |
||||
{ |
||||
return in_args.at(idx).template get<T>(); |
||||
} |
||||
|
||||
// 4. The MetaHelper itself: an entity which generates outMeta() call
|
||||
// based on kernel signature, with arguments properly substituted.
|
||||
// 4.1 - case for multiple return values
|
||||
// FIXME: probably can be simplified with std::apply or analogue.
|
||||
template<typename, typename, typename> |
||||
struct MetaHelper; |
||||
|
||||
template<typename K, typename... Ins, typename... Outs> |
||||
struct MetaHelper<K, std::tuple<Ins...>, std::tuple<Outs...> > |
||||
{ |
||||
template<int... IIs, int... OIs> |
||||
static GMetaArgs getOutMeta_impl(const GMetaArgs &in_meta, |
||||
const GArgs &in_args, |
||||
detail::Seq<IIs...>, |
||||
detail::Seq<OIs...>) |
||||
{ |
||||
// FIXME: decay?
|
||||
using R = std::tuple<typename MetaType<Outs>::type...>; |
||||
const R r = K::outMeta( get_in_meta<Ins>(in_meta, in_args, IIs)... ); |
||||
return GMetaArgs{ GMetaArg(std::get<OIs>(r))... }; |
||||
} |
||||
// FIXME: help users identify how outMeta must look like (via default impl w/static_assert?)
|
||||
|
||||
static GMetaArgs getOutMeta(const GMetaArgs &in_meta, |
||||
const GArgs &in_args) |
||||
{ |
||||
return getOutMeta_impl(in_meta, |
||||
in_args, |
||||
typename detail::MkSeq<sizeof...(Ins)>::type(), |
||||
typename detail::MkSeq<sizeof...(Outs)>::type()); |
||||
} |
||||
}; |
||||
|
||||
// 4.1 - case for a single return value
|
||||
// FIXME: How to avoid duplication here?
|
||||
template<typename K, typename... Ins, typename Out> |
||||
struct MetaHelper<K, std::tuple<Ins...>, Out > |
||||
{ |
||||
template<int... IIs> |
||||
static GMetaArgs getOutMeta_impl(const GMetaArgs &in_meta, |
||||
const GArgs &in_args, |
||||
detail::Seq<IIs...>) |
||||
{ |
||||
// FIXME: decay?
|
||||
using R = typename MetaType<Out>::type; |
||||
const R r = K::outMeta( get_in_meta<Ins>(in_meta, in_args, IIs)... ); |
||||
return GMetaArgs{ GMetaArg(r) }; |
||||
} |
||||
// FIXME: help users identify how outMeta must look like (via default impl w/static_assert?)
|
||||
|
||||
static GMetaArgs getOutMeta(const GMetaArgs &in_meta, |
||||
const GArgs &in_args) |
||||
{ |
||||
return getOutMeta_impl(in_meta, |
||||
in_args, |
||||
typename detail::MkSeq<sizeof...(Ins)>::type()); |
||||
} |
||||
}; |
||||
|
||||
} // 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
|
||||
// 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...> > |
||||
{ |
||||
template<int... IIs> |
||||
static std::tuple<R...> yield(cv::GCall &call, detail::Seq<IIs...>) |
||||
{ |
||||
return std::make_tuple(detail::Yield<R>::yield(call, IIs)...); |
||||
} |
||||
|
||||
public: |
||||
using InArgs = std::tuple<Args...>; |
||||
using OutArgs = std::tuple<R...>; |
||||
|
||||
static std::tuple<R...> on(Args... args) |
||||
{ |
||||
cv::GCall call(GKernel{K::id(), &K::getOutMeta, {detail::GTypeTraits<R>::shape...}}); |
||||
call.pass(args...); |
||||
return yield(call, typename detail::MkSeq<sizeof...(R)>::type()); |
||||
} |
||||
}; |
||||
|
||||
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: |
||||
using InArgs = std::tuple<Args...>; |
||||
using OutArgs = std::tuple<R>; |
||||
|
||||
static R on(Args... args) |
||||
{ |
||||
cv::GCall call(GKernel{K::id(), &K::getOutMeta, {detail::GTypeTraits<R>::shape}}); |
||||
call.pass(args...); |
||||
return detail::Yield<R>::yield(call, 0); |
||||
} |
||||
}; |
||||
|
||||
} // namespace cv
|
||||
|
||||
|
||||
// FIXME: I don't know a better way so far. Feel free to suggest one
|
||||
// The problem is that every typed kernel should have ::id() but body
|
||||
// of the class is defined by user (with outMeta, other stuff)
|
||||
|
||||
#define G_ID_HELPER_CLASS(Class) Class##IdHelper |
||||
|
||||
#define G_ID_HELPER_BODY(Class, Id) \ |
||||
namespace detail \
|
||||
{ \
|
||||
struct G_ID_HELPER_CLASS(Class) \
|
||||
{ \
|
||||
static constexpr const char * id() {return Id;}; \
|
||||
}; \
|
||||
} |
||||
|
||||
#define G_TYPED_KERNEL(Class, API, Id) \ |
||||
G_ID_HELPER_BODY(Class, Id) \
|
||||
struct Class final: public cv::GKernelType<Class, std::function API >, \
|
||||
public detail::G_ID_HELPER_CLASS(Class) |
||||
// {body} is to be defined by user
|
||||
|
||||
#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) \
|
||||
// {body} is to be defined by user
|
||||
|
||||
namespace cv |
||||
{ |
||||
// Declare <unite> in cv:: namespace
|
||||
enum class unite_policy |
||||
{ |
||||
REPLACE, |
||||
KEEP |
||||
}; |
||||
|
||||
namespace gapi |
||||
{ |
||||
// Prework: model "Device" API before it gets to G-API headers.
|
||||
// FIXME: Don't mix with internal Backends class!
|
||||
class GAPI_EXPORTS GBackend |
||||
{ |
||||
public: |
||||
class Priv; |
||||
|
||||
// TODO: make it template (call `new` within??)
|
||||
GBackend(); |
||||
explicit GBackend(std::shared_ptr<Priv> &&p); |
||||
|
||||
Priv& priv(); |
||||
const Priv& priv() const; |
||||
std::size_t hash() const; |
||||
|
||||
bool operator== (const GBackend &rhs) const; |
||||
|
||||
private: |
||||
std::shared_ptr<Priv> m_priv; |
||||
}; |
||||
|
||||
inline bool operator != (const GBackend &lhs, const GBackend &rhs) |
||||
{ |
||||
return !(lhs == rhs); |
||||
} |
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
namespace std |
||||
{ |
||||
template<> struct hash<cv::gapi::GBackend> |
||||
{ |
||||
std::size_t operator() (const cv::gapi::GBackend &b) const |
||||
{ |
||||
return b.hash(); |
||||
} |
||||
}; |
||||
} // namespace std
|
||||
|
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
// Lookup order is in fact a vector of Backends to traverse during look-up
|
||||
using GLookupOrder = std::vector<GBackend>; |
||||
inline GLookupOrder lookup_order(std::initializer_list<GBackend> &&list) |
||||
{ |
||||
return GLookupOrder(std::move(list)); |
||||
} |
||||
|
||||
// FIXME: Hide implementation
|
||||
class GAPI_EXPORTS GKernelPackage |
||||
{ |
||||
using S = std::unordered_map<std::string, GKernelImpl>; |
||||
using M = std::unordered_map<GBackend, S>; |
||||
M m_backend_kernels; |
||||
|
||||
protected: |
||||
// Check if package contains ANY implementation of a kernel API
|
||||
// by API textual id.
|
||||
bool includesAPI(const std::string &id) const; |
||||
|
||||
public: |
||||
// Return total number of kernels (accross all backends)
|
||||
std::size_t size() const; |
||||
|
||||
// Check if particular kernel implementation exist in the package.
|
||||
// The key word here is _particular_ - i.e., from the specific backend.
|
||||
template<typename KImpl> |
||||
bool includes() const |
||||
{ |
||||
const auto set_iter = m_backend_kernels.find(KImpl::backend()); |
||||
return (set_iter != m_backend_kernels.end()) |
||||
? (set_iter->second.count(KImpl::API::id()) > 0) |
||||
: false; |
||||
} |
||||
|
||||
// Removes all the kernels related to the given backend
|
||||
void remove(const GBackend& backend); |
||||
|
||||
// Check if package contains ANY implementation of a kernel API
|
||||
// by API type.
|
||||
template<typename KAPI> |
||||
bool includesAPI() const |
||||
{ |
||||
return includesAPI(KAPI::id()); |
||||
} |
||||
|
||||
// Lookup a kernel, given the look-up order. Returns Backend which
|
||||
// hosts kernel implementation. Throws if nothing found.
|
||||
//
|
||||
// If order is empty(), returns first suitable implementation.
|
||||
template<typename KAPI> |
||||
GBackend lookup(const GLookupOrder &order = {}) const |
||||
{ |
||||
return lookup(KAPI::id(), order).first; |
||||
} |
||||
|
||||
std::pair<cv::gapi::GBackend, cv::GKernelImpl> |
||||
lookup(const std::string &id, const GLookupOrder &order = {}) const; |
||||
|
||||
// Put a new kernel implementation into package
|
||||
// FIXME: No overwrites allowed?
|
||||
template<typename KImpl> void include() |
||||
{ |
||||
auto backend = KImpl::backend(); |
||||
auto kernel_id = KImpl::API::id(); |
||||
auto kernel_impl = GKernelImpl{KImpl::kernel()}; |
||||
m_backend_kernels[backend][kernel_id] = std::move(kernel_impl); |
||||
} |
||||
|
||||
// Lists all backends which are included into package
|
||||
std::vector<GBackend> backends() const; |
||||
|
||||
friend GAPI_EXPORTS GKernelPackage combine(const GKernelPackage &, |
||||
const GKernelPackage &, |
||||
const cv::unite_policy); |
||||
}; |
||||
|
||||
template<typename... KK> GKernelPackage kernels() |
||||
{ |
||||
GKernelPackage pkg; |
||||
|
||||
// For those who wonder - below is a trick to call a number of
|
||||
// methods based on parameter pack (zeroes just help hiding these
|
||||
// calls into a sequence which helps to expand this parameter pack).
|
||||
// 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<>()).
|
||||
|
||||
int unused[] = { 0, (pkg.include<KK>(), 0)... }; |
||||
cv::util::suppress_unused_warning(unused); |
||||
return pkg; |
||||
}; |
||||
|
||||
// Return a new package based on `lhs` and `rhs`,
|
||||
// with unity policy defined by `policy`.
|
||||
GAPI_EXPORTS GKernelPackage combine(const GKernelPackage &lhs, |
||||
const GKernelPackage &rhs, |
||||
const cv::unite_policy policy); |
||||
} // namespace gapi
|
||||
|
||||
namespace detail |
||||
{ |
||||
template<> struct CompileArgTag<cv::gapi::GKernelPackage> |
||||
{ |
||||
static const char* tag() { return "gapi.kernel_package"; } |
||||
}; |
||||
template<> struct CompileArgTag<cv::gapi::GLookupOrder> |
||||
{ |
||||
static const char* tag() { return "gapi.lookup_order"; } |
||||
}; |
||||
} // namespace detail
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_GKERNEL_HPP
|
@ -0,0 +1,131 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GMAT_HPP |
||||
#define OPENCV_GAPI_GMAT_HPP |
||||
|
||||
#include <ostream> |
||||
#include <memory> // std::shared_ptr |
||||
|
||||
#include <opencv2/gapi/opencv_includes.hpp> |
||||
#include <opencv2/gapi/gcommon.hpp> // GShape |
||||
|
||||
#include "opencv2/gapi/own/types.hpp" // cv::gapi::own::Size |
||||
#include "opencv2/gapi/own/convert.hpp" // to_own |
||||
#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; |
||||
|
||||
class GAPI_EXPORTS GMat |
||||
{ |
||||
public: |
||||
GMat(); // Empty constructor
|
||||
GMat(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; |
||||
}; |
||||
|
||||
struct GAPI_EXPORTS GMatDesc |
||||
{ |
||||
// FIXME: Default initializers in C++14
|
||||
int depth; |
||||
int chan; |
||||
cv::gapi::own::Size size; // NB.: no multi-dimensional cases covered yet
|
||||
|
||||
inline bool operator== (const GMatDesc &rhs) const |
||||
{ |
||||
return depth == rhs.depth && chan == rhs.chan && size == rhs.size; |
||||
} |
||||
|
||||
inline bool operator!= (const GMatDesc &rhs) const |
||||
{ |
||||
return !(*this == rhs); |
||||
} |
||||
|
||||
// Meta combinator: return a new GMatDesc which differs in size by delta
|
||||
// (all other fields are taken unchanged from this GMatDesc)
|
||||
// FIXME: a better name?
|
||||
GMatDesc withSizeDelta(cv::gapi::own::Size delta) const |
||||
{ |
||||
GMatDesc desc(*this); |
||||
desc.size += delta; |
||||
return desc; |
||||
} |
||||
|
||||
GMatDesc withSizeDelta(cv::Size delta) const |
||||
{ |
||||
return withSizeDelta(to_own(delta)); |
||||
} |
||||
|
||||
// Meta combinator: return a new GMatDesc which differs in size by delta
|
||||
// (all other fields are taken unchanged from this GMatDesc)
|
||||
//
|
||||
// This is an overload.
|
||||
GMatDesc withSizeDelta(int dx, int dy) const |
||||
{ |
||||
return withSizeDelta(cv::gapi::own::Size{dx,dy}); |
||||
} |
||||
|
||||
GMatDesc withSize(cv::gapi::own::Size sz) const |
||||
{ |
||||
GMatDesc desc(*this); |
||||
desc.size = sz; |
||||
return desc; |
||||
} |
||||
|
||||
GMatDesc withSize(cv::Size sz) const |
||||
{ |
||||
return withSize(to_own(sz)); |
||||
} |
||||
|
||||
// Meta combinator: return a new GMatDesc with specified data depth.
|
||||
// (all other fields are taken unchanged from this GMatDesc)
|
||||
GMatDesc withDepth(int ddepth) const |
||||
{ |
||||
GAPI_Assert(CV_MAT_CN(ddepth) == 1 || ddepth == -1); |
||||
GMatDesc desc(*this); |
||||
if (ddepth != -1) desc.depth = ddepth; |
||||
return desc; |
||||
} |
||||
|
||||
// Meta combinator: return a new GMatDesc with specified data depth
|
||||
// and number of channels.
|
||||
// (all other fields are taken unchanged from this GMatDesc)
|
||||
GMatDesc withType(int ddepth, int dchan) const |
||||
{ |
||||
GAPI_Assert(CV_MAT_CN(ddepth) == 1 || ddepth == -1); |
||||
GMatDesc desc = withDepth(ddepth); |
||||
desc.chan = dchan; |
||||
return desc; |
||||
} |
||||
}; |
||||
|
||||
static inline GMatDesc empty_gmat_desc() { return GMatDesc{-1,-1,{-1,-1}}; } |
||||
|
||||
class Mat; |
||||
GAPI_EXPORTS GMatDesc descr_of(const cv::Mat &mat); |
||||
|
||||
namespace gapi { namespace own { |
||||
class Mat; |
||||
CV_EXPORTS GMatDesc descr_of(const Mat &mat); |
||||
}}//gapi::own
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const cv::GMatDesc &desc); |
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_GMAT_HPP
|
@ -0,0 +1,66 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GMETAARG_HPP |
||||
#define OPENCV_GAPI_GMETAARG_HPP |
||||
|
||||
#include <vector> |
||||
#include <type_traits> |
||||
|
||||
#include "opencv2/gapi/util/util.hpp" |
||||
#include "opencv2/gapi/util/variant.hpp" |
||||
|
||||
#include "opencv2/gapi/gmat.hpp" |
||||
#include "opencv2/gapi/gscalar.hpp" |
||||
#include "opencv2/gapi/garray.hpp" |
||||
|
||||
namespace cv |
||||
{ |
||||
// FIXME: Rename to GMeta?
|
||||
// FIXME: user shouldn't deal with it - put to detail?
|
||||
// GMetaArg is an union type over descriptions of G-types which can serve as
|
||||
// GComputation's in/output slots.
|
||||
//
|
||||
// GMetaArg objects are passed as arguments to GComputation::compile()
|
||||
// to specify which data a compiled computation should be specialized on.
|
||||
// For manual compile(), user must supply this metadata, in case of apply()
|
||||
// this metadata is taken from arguments computation should operate on.
|
||||
//
|
||||
// The first type (monostate) is equal to "uninitialized"/"unresolved" meta.
|
||||
using GMetaArg = util::variant |
||||
< util::monostate |
||||
, GMatDesc |
||||
, GScalarDesc |
||||
, GArrayDesc |
||||
>; |
||||
std::ostream& operator<<(std::ostream& os, const GMetaArg &); |
||||
|
||||
using GMetaArgs = std::vector<GMetaArg>; |
||||
|
||||
namespace detail |
||||
{ |
||||
// These traits are used by GComputation::compile()
|
||||
|
||||
// FIXME: is_constructible<T> doesn't work as variant doesn't do any SFINAE
|
||||
// in its current template constructor
|
||||
|
||||
template<typename T> struct is_meta_descr : std::false_type {}; |
||||
template<> struct is_meta_descr<GMatDesc> : std::true_type {}; |
||||
template<> struct is_meta_descr<GScalarDesc> : std::true_type {}; |
||||
template<> struct is_meta_descr<GArrayDesc> : std::true_type {}; |
||||
|
||||
template<typename... Ts> |
||||
using are_meta_descrs = all_satisfy<is_meta_descr, Ts...>; |
||||
|
||||
template<typename... Ts> |
||||
using are_meta_descrs_but_last = all_satisfy<is_meta_descr, typename all_but_last<Ts...>::type>; |
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_GMETAARG_HPP
|
@ -0,0 +1,96 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GPROTO_HPP |
||||
#define OPENCV_GAPI_GPROTO_HPP |
||||
|
||||
#include <type_traits> |
||||
#include <vector> |
||||
#include <ostream> |
||||
|
||||
#include "opencv2/gapi/util/variant.hpp" |
||||
|
||||
#include "opencv2/gapi/gmat.hpp" |
||||
#include "opencv2/gapi/gscalar.hpp" |
||||
#include "opencv2/gapi/garray.hpp" |
||||
#include "opencv2/gapi/garg.hpp" |
||||
#include "opencv2/gapi/gmetaarg.hpp" |
||||
|
||||
namespace cv { |
||||
|
||||
// FIXME: user shouldn't deal with it - put to detail?
|
||||
// GProtoArg is an union type over G-types which can serve as
|
||||
// GComputation's in/output slots. In other words, GProtoArg
|
||||
// wraps any type which can serve as G-API exchange type.
|
||||
//
|
||||
// In Runtime, GProtoArgs are substituted with appropriate GRunArgs.
|
||||
//
|
||||
// GProtoArg objects are constructed in-place when user describes
|
||||
// (captures) computations, user doesn't interact with these types
|
||||
// directly.
|
||||
using GProtoArg = util::variant |
||||
< GMat |
||||
, GScalar |
||||
, detail::GArrayU // instead of GArray<T>
|
||||
>; |
||||
|
||||
using GProtoArgs = std::vector<GProtoArg>; |
||||
|
||||
namespace detail |
||||
{ |
||||
template<typename... Ts> inline GProtoArgs packArgs(Ts... args) |
||||
{ |
||||
return GProtoArgs{ GProtoArg(wrap_gapi_helper<Ts>::wrap(args))... }; |
||||
} |
||||
|
||||
} |
||||
|
||||
template<class Tag> |
||||
struct GIOProtoArgs |
||||
{ |
||||
public: |
||||
explicit GIOProtoArgs(const GProtoArgs& args) : m_args(args) {} |
||||
explicit GIOProtoArgs(GProtoArgs &&args) : m_args(std::move(args)) {} |
||||
|
||||
GProtoArgs m_args; |
||||
}; |
||||
|
||||
struct In_Tag{}; |
||||
struct Out_Tag{}; |
||||
|
||||
using GProtoInputArgs = GIOProtoArgs<In_Tag>; |
||||
using GProtoOutputArgs = GIOProtoArgs<Out_Tag>; |
||||
|
||||
// Perfect forwarding
|
||||
template<typename... Ts> inline GProtoInputArgs GIn(Ts&&... ts) |
||||
{ |
||||
return GProtoInputArgs(detail::packArgs(std::forward<Ts>(ts)...)); |
||||
} |
||||
|
||||
template<typename... Ts> inline GProtoOutputArgs GOut(Ts&&... ts) |
||||
{ |
||||
return GProtoOutputArgs(detail::packArgs(std::forward<Ts>(ts)...)); |
||||
} |
||||
|
||||
// Extract run-time arguments from node origin
|
||||
// Can be used to extract constant values associated with G-objects
|
||||
// (like GScalar) at graph construction time
|
||||
GRunArg value_of(const GOrigin &origin); |
||||
|
||||
// Transform run-time computation arguments into a collection of metadata
|
||||
// extracted from that arguments
|
||||
GMetaArg GAPI_EXPORTS descr_of(const GRunArg &arg ); |
||||
GMetaArgs GAPI_EXPORTS descr_of(const GRunArgs &args); |
||||
|
||||
// Transform run-time operation result argument into metadata extracted from that argument
|
||||
// Used to compare the metadata, which generated at compile time with the metadata result operation in run time
|
||||
GMetaArg GAPI_EXPORTS descr_of(const GRunArgP& argp); |
||||
|
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_GPROTO_HPP
|
@ -0,0 +1,68 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GSCALAR_HPP |
||||
#define OPENCV_GAPI_GSCALAR_HPP |
||||
|
||||
#include <ostream> |
||||
|
||||
#include <opencv2/gapi/opencv_includes.hpp> |
||||
#include <opencv2/gapi/gcommon.hpp> // GShape |
||||
#include <opencv2/gapi/util/optional.hpp> |
||||
#include "opencv2/gapi/own/scalar.hpp" |
||||
#include <opencv2/core/types.hpp> |
||||
|
||||
// TODO GAPI_EXPORTS or so
|
||||
namespace cv |
||||
{ |
||||
// Forward declaration; GNode and GOrigin are an internal
|
||||
// (user-inaccessible) classes.
|
||||
class GNode; |
||||
struct GOrigin; |
||||
|
||||
class GAPI_EXPORTS GScalar |
||||
{ |
||||
public: |
||||
GScalar(); // Empty constructor
|
||||
explicit GScalar(const cv::gapi::own::Scalar& s); // Constant value constructor from cv::gapi::own::Scalar
|
||||
explicit GScalar(cv::gapi::own::Scalar&& s); // Constant value move-constructor from cv::gapi::own::Scalar
|
||||
explicit GScalar(const cv::Scalar& s); // Constant value constructor from cv::Scalar
|
||||
GScalar(double v0); // Constant value constructor from double
|
||||
GScalar(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; |
||||
}; |
||||
|
||||
struct GScalarDesc |
||||
{ |
||||
// NB.: right now it is empty
|
||||
|
||||
inline bool operator== (const GScalarDesc &) const |
||||
{ |
||||
return true; // NB: implement this method if GScalar meta appears
|
||||
} |
||||
|
||||
inline bool operator!= (const GScalarDesc &rhs) const |
||||
{ |
||||
return !(*this == rhs); |
||||
} |
||||
}; |
||||
|
||||
static inline GScalarDesc empty_scalar_desc() { return GScalarDesc(); } |
||||
|
||||
GAPI_EXPORTS GScalarDesc descr_of(const cv::gapi::own::Scalar &scalar); |
||||
GAPI_EXPORTS GScalarDesc descr_of(const cv::Scalar &scalar); |
||||
|
||||
std::ostream& operator<<(std::ostream& os, const cv::GScalarDesc &desc); |
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_GSCALAR_HPP
|
@ -0,0 +1,150 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GTYPE_TRAITS_HPP |
||||
#define OPENCV_GAPI_GTYPE_TRAITS_HPP |
||||
|
||||
#include <vector> |
||||
#include <type_traits> |
||||
|
||||
#include <opencv2/gapi/gmat.hpp> |
||||
#include <opencv2/gapi/gscalar.hpp> |
||||
#include <opencv2/gapi/garray.hpp> |
||||
#include <opencv2/gapi/gcommon.hpp> |
||||
#include <opencv2/gapi/own/convert.hpp> |
||||
|
||||
namespace cv |
||||
{ |
||||
namespace detail |
||||
{ |
||||
// FIXME: These traits and enum and possible numerous switch(kind)
|
||||
// block may be replaced with a special Handler<T> object or with
|
||||
// a double dispatch
|
||||
enum class ArgKind: int |
||||
{ |
||||
OPAQUE, // Unknown, generic, opaque-to-GAPI data type - STATIC
|
||||
GOBJREF, // <internal> reference to object
|
||||
GMAT, // a cv::GMat
|
||||
GSCALAR, // a cv::GScalar
|
||||
GARRAY, // a cv::GArrayU (note - exactly GArrayU, not GArray<T>!)
|
||||
}; |
||||
|
||||
// Describe G-API types (G-types) with traits. Mostly used by
|
||||
// cv::GArg to store meta information about types passed into
|
||||
// operation arguments. Please note that cv::GComputation is
|
||||
// defined on GProtoArgs, not GArgs!
|
||||
template<typename T> struct GTypeTraits; |
||||
template<typename T> struct GTypeTraits |
||||
{ |
||||
static constexpr const ArgKind kind = ArgKind::OPAQUE; |
||||
}; |
||||
template<> struct GTypeTraits<cv::GMat> |
||||
{ |
||||
static constexpr const ArgKind kind = ArgKind::GMAT; |
||||
static constexpr const GShape shape = GShape::GMAT; |
||||
}; |
||||
template<> struct GTypeTraits<cv::GScalar> |
||||
{ |
||||
static constexpr const ArgKind kind = ArgKind::GSCALAR; |
||||
static constexpr const GShape shape = GShape::GSCALAR; |
||||
}; |
||||
template<class T> struct GTypeTraits<cv::GArray<T> > |
||||
{ |
||||
static constexpr const ArgKind kind = ArgKind::GARRAY; |
||||
static constexpr const GShape shape = GShape::GARRAY; |
||||
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 cv::detail::VectorRef wrap_in (const std::vector<T> &t) { return detail::VectorRef(t); } |
||||
static cv::detail::VectorRef wrap_out ( std::vector<T> &t) { return detail::VectorRef(t); } |
||||
}; |
||||
|
||||
// Tests if Trait for type T requires extra marshalling ("custom wrap") or not.
|
||||
// If Traits<T> has wrap_value() defined, it does.
|
||||
template<class T> struct has_custom_wrap |
||||
{ |
||||
template<class,class> class check; |
||||
template<typename C> static std::true_type test(check<C, decltype(>ypeTraits<C>::wrap_value)> *); |
||||
template<typename C> static std::false_type test(...); |
||||
using type = decltype(test<T>(nullptr)); |
||||
static const constexpr bool value = std::is_same<std::true_type, decltype(test<T>(nullptr))>::value; |
||||
}; |
||||
|
||||
// Resolve a Host type back to its associated G-Type.
|
||||
// FIXME: Probably it can be avoided
|
||||
template<typename T> struct GTypeOf; |
||||
template<> struct GTypeOf<cv::Mat> { using type = cv::GMat; }; |
||||
template<> struct GTypeOf<cv::gapi::own::Mat> { using type = cv::GMat; }; |
||||
template<> struct GTypeOf<cv::Scalar> { using type = cv::GScalar; }; |
||||
template<> struct GTypeOf<cv::gapi::own::Scalar> { using type = cv::GScalar; }; |
||||
template<typename U> struct GTypeOf<std::vector<U> > { using type = cv::GArray<U>; }; |
||||
template<class T> using g_type_of_t = typename GTypeOf<T>::type; |
||||
|
||||
// Marshalling helper for G-types and its Host types. Helps G-API
|
||||
// to store G types in internal generic containers for further
|
||||
// processing. Implements the following callbacks:
|
||||
//
|
||||
// * wrap() - converts user-facing G-type into an internal one
|
||||
// for internal storage.
|
||||
// Used when G-API operation is instantiated (G<Kernel>::on(),
|
||||
// etc) during expressing a pipeline. Mostly returns input
|
||||
// value "as is" except the case when G-type is a template. For
|
||||
// template G-classes, calls custom wrap() from Traits.
|
||||
// The value returned by wrap() is then wrapped into GArg() and
|
||||
// stored in G-API metadata.
|
||||
//
|
||||
// Example:
|
||||
// - cv::GMat arguments are passed as-is.
|
||||
// - integers, pointers, STL containers, user types are passed as-is.
|
||||
// - cv::GArray<T> is converted to cv::GArrayU.
|
||||
//
|
||||
// * wrap_in() / wrap_out() - convert Host type associated with
|
||||
// G-type to internal representation type.
|
||||
//
|
||||
// - For "simple" (non-template) G-types, returns value as-is.
|
||||
// Example: cv::GMat has host type cv::Mat, when user passes a
|
||||
// cv::Mat, system stores it internally as cv::Mat.
|
||||
//
|
||||
// - For "complex" (template) G-types, utilizes custom
|
||||
// wrap_in()/wrap_out() as described in Traits.
|
||||
// Example: cv::GArray<T> has host type std::vector<T>, when
|
||||
// user passes a std::vector<T>, system stores it
|
||||
// internally as VectorRef (with <T> stripped away).
|
||||
template<typename T, class Custom = void> struct WrapValue |
||||
{ |
||||
static auto wrap(const T& t) -> |
||||
typename std::remove_reference<T>::type |
||||
{ |
||||
return static_cast<typename std::remove_reference<T>::type>(t); |
||||
} |
||||
|
||||
template<typename U> static U wrap_in (const U &u) { return u; } |
||||
template<typename U> static U* wrap_out(U &u) { return &u; } |
||||
}; |
||||
template<typename T> struct WrapValue<T, typename std::enable_if<has_custom_wrap<T>::value>::type> |
||||
{ |
||||
static auto wrap(const T& t) -> decltype(GTypeTraits<T>::wrap_value(t)) |
||||
{ |
||||
return GTypeTraits<T>::wrap_value(t); |
||||
} |
||||
template<typename U> static auto wrap_in (const U &u) -> typename GTypeTraits<T>::strip_type |
||||
{ |
||||
return GTypeTraits<T>::wrap_in(u); |
||||
} |
||||
template<typename U> static auto wrap_out(U &u) -> typename GTypeTraits<T>::strip_type |
||||
{ |
||||
return GTypeTraits<T>::wrap_out(u); |
||||
} |
||||
}; |
||||
|
||||
template<typename T> using wrap_gapi_helper = WrapValue<typename std::decay<T>::type>; |
||||
template<typename T> using wrap_host_helper = WrapValue<typename std::decay<g_type_of_t<T> >::type>; |
||||
|
||||
} // namespace detail
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_GTYPE_TRAITS_HPP
|
@ -0,0 +1,186 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GTYPED_HPP |
||||
#define OPENCV_GAPI_GTYPED_HPP |
||||
|
||||
#include <vector> |
||||
|
||||
#include "opencv2/gapi/gcomputation.hpp" |
||||
#include "opencv2/gapi/gcompiled.hpp" |
||||
#include "opencv2/gapi/gproto.hpp" |
||||
#include "opencv2/gapi/gcommon.hpp" |
||||
|
||||
namespace cv { |
||||
|
||||
namespace detail |
||||
{ |
||||
// FIXME: How to prevent coolhackers from extending it by their own types?
|
||||
// FIXME: ...Should we care?
|
||||
template<typename T> struct ProtoToParam; |
||||
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<typename T> using ProtoToParamT = typename ProtoToParam<T>::type; |
||||
|
||||
template<typename T> struct ProtoToMeta; |
||||
template<> struct ProtoToMeta<cv::GMat> { using type = cv::GMatDesc; }; |
||||
template<> struct ProtoToMeta<cv::GScalar> { using type = cv::GScalarDesc; }; |
||||
template<typename U> struct ProtoToMeta<cv::GArray<U> > { using type = cv::GArrayDesc; }; |
||||
template<typename T> using ProtoToMetaT = typename ProtoToMeta<T>::type; |
||||
|
||||
//workaround for MSVC 19.0 bug
|
||||
template <typename T> |
||||
auto make_default()->decltype(T{}) {return {};} |
||||
}; // detail
|
||||
|
||||
template<typename> class GComputationT; |
||||
|
||||
// Single return value implementation
|
||||
template<typename R, typename... Args> class GComputationT<R(Args...)> |
||||
{ |
||||
public: |
||||
typedef std::function<R(Args...)> Gen; |
||||
|
||||
class GCompiledT |
||||
{ |
||||
private: |
||||
friend class GComputationT<R(Args...)>; |
||||
|
||||
cv::GCompiled m_comp; |
||||
|
||||
explicit GCompiledT(const cv::GCompiled &comp) : m_comp(comp) {} |
||||
|
||||
public: |
||||
GCompiledT() {} |
||||
|
||||
void operator()(detail::ProtoToParamT<Args>... inArgs, |
||||
detail::ProtoToParamT<R> &outArg) |
||||
{ |
||||
m_comp(cv::gin(inArgs...), cv::gout(outArg)); |
||||
} |
||||
|
||||
explicit operator bool() const |
||||
{ |
||||
return static_cast<bool>(m_comp); |
||||
} |
||||
}; |
||||
|
||||
private: |
||||
typedef std::pair<R, GProtoInputArgs > Captured; |
||||
|
||||
Captured capture(const Gen& g, Args... args) |
||||
{ |
||||
return Captured(g(args...), cv::GIn(args...)); |
||||
} |
||||
|
||||
Captured m_capture; |
||||
cv::GComputation m_comp; |
||||
|
||||
public: |
||||
GComputationT(const Gen &generator) |
||||
: m_capture(capture(generator, detail::make_default<Args>()...)) |
||||
, m_comp(cv::GProtoInputArgs(std::move(m_capture.second)), |
||||
cv::GOut(m_capture.first)) |
||||
{ |
||||
} |
||||
|
||||
void apply(detail::ProtoToParamT<Args>... inArgs, |
||||
detail::ProtoToParamT<R> &outArg) |
||||
{ |
||||
m_comp.apply(cv::gin(inArgs...), cv::gout(outArg)); |
||||
} |
||||
|
||||
GCompiledT compile(detail::ProtoToMetaT<Args>... inDescs) |
||||
{ |
||||
GMetaArgs inMetas = { GMetaArg(inDescs)... }; |
||||
return GCompiledT(m_comp.compile(std::move(inMetas), GCompileArgs())); |
||||
} |
||||
|
||||
GCompiledT compile(detail::ProtoToMetaT<Args>... inDescs, GCompileArgs &&args) |
||||
{ |
||||
GMetaArgs inMetas = { GMetaArg(inDescs)... }; |
||||
return GCompiledT(m_comp.compile(std::move(inMetas), std::move(args))); |
||||
} |
||||
}; |
||||
|
||||
// Multiple (fixed) return value implementation. FIXME: How to avoid copy-paste?
|
||||
template<typename... R, typename... Args> class GComputationT<std::tuple<R...>(Args...)> |
||||
{ |
||||
public: |
||||
typedef std::function<std::tuple<R...>(Args...)> Gen; |
||||
|
||||
class GCompiledT |
||||
{ |
||||
private: |
||||
friend class GComputationT<std::tuple<R...>(Args...)>; |
||||
|
||||
cv::GCompiled m_comp; |
||||
explicit GCompiledT(const cv::GCompiled &comp) : m_comp(comp) {} |
||||
|
||||
public: |
||||
GCompiledT() {} |
||||
|
||||
void operator()(detail::ProtoToParamT<Args>... inArgs, |
||||
detail::ProtoToParamT<R>&... outArgs) |
||||
{ |
||||
m_comp(cv::gin(inArgs...), cv::gout(outArgs...)); |
||||
} |
||||
|
||||
explicit operator bool() const |
||||
{ |
||||
return static_cast<bool>(m_comp); |
||||
} |
||||
}; |
||||
|
||||
private: |
||||
typedef std::pair<GProtoArgs, GProtoArgs> Captured; |
||||
|
||||
template<int... IIs> |
||||
Captured capture(GProtoArgs &&args, const std::tuple<R...> &rr, detail::Seq<IIs...>) |
||||
{ |
||||
return Captured(cv::GOut(std::get<IIs>(rr)...).m_args, args); |
||||
} |
||||
|
||||
Captured capture(const Gen& g, Args... args) |
||||
{ |
||||
return capture(cv::GIn(args...).m_args, g(args...), typename detail::MkSeq<sizeof...(R)>::type()); |
||||
} |
||||
|
||||
Captured m_capture; |
||||
cv::GComputation m_comp; |
||||
|
||||
public: |
||||
GComputationT(const Gen &generator) |
||||
: m_capture(capture(generator, detail::make_default<Args>()...)) |
||||
, m_comp(cv::GProtoInputArgs(std::move(m_capture.second)), |
||||
cv::GProtoOutputArgs(std::move(m_capture.first))) |
||||
{ |
||||
} |
||||
|
||||
void apply(detail::ProtoToParamT<Args>... inArgs, |
||||
detail::ProtoToParamT<R>&... outArgs) |
||||
{ |
||||
m_comp.apply(cv::gin(inArgs...), cv::gout(outArgs...)); |
||||
} |
||||
|
||||
GCompiledT compile(detail::ProtoToMetaT<Args>... inDescs) |
||||
{ |
||||
GMetaArgs inMetas = { GMetaArg(inDescs)... }; |
||||
return GCompiledT(m_comp.compile(std::move(inMetas), GCompileArgs())); |
||||
} |
||||
|
||||
GCompiledT compile(detail::ProtoToMetaT<Args>... inDescs, GCompileArgs &&args) |
||||
{ |
||||
GMetaArgs inMetas = { GMetaArg(inDescs)... }; |
||||
return GCompiledT(m_comp.compile(std::move(inMetas), std::move(args))); |
||||
} |
||||
}; |
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_GTYPED_HPP
|
@ -0,0 +1,677 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_IMGPROC_HPP |
||||
#define OPENCV_GAPI_IMGPROC_HPP |
||||
|
||||
#include "opencv2/imgproc.hpp" |
||||
|
||||
#include <utility> // std::tuple |
||||
|
||||
#include "opencv2/gapi/gkernel.hpp" |
||||
#include "opencv2/gapi/gmat.hpp" |
||||
#include "opencv2/gapi/gscalar.hpp" |
||||
|
||||
|
||||
/** \defgroup gapi_imgproc G-API image processing functionality
|
||||
@{ |
||||
@defgroup gapi_filters Graph API: Image filters |
||||
@defgroup gapi_colorconvert Graph API: Converting image from one color space to another |
||||
@} |
||||
*/ |
||||
|
||||
namespace cv { namespace gapi { |
||||
|
||||
namespace imgproc { |
||||
using GMat3 = std::tuple<GMat,GMat,GMat>; // FIXME: how to avoid this?
|
||||
|
||||
G_TYPED_KERNEL(GFilter2D, <GMat(GMat,int,Mat,Point,Scalar,int,Scalar)>,"org.opencv.imgproc.filters.filter2D") { |
||||
static GMatDesc outMeta(GMatDesc in, int ddepth, Mat, Point, Scalar, int, Scalar) { |
||||
return in.withDepth(ddepth); |
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GSepFilter, <GMat(GMat,int,Mat,Mat,Point,Scalar,int,Scalar)>, "org.opencv.imgproc.filters.sepfilter") { |
||||
static GMatDesc outMeta(GMatDesc in, int ddepth, Mat, Mat, Point, Scalar, int, Scalar) { |
||||
return in.withDepth(ddepth); |
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GBoxFilter, <GMat(GMat,int,Size,Point,bool,int,Scalar)>, "org.opencv.imgproc.filters.boxfilter") { |
||||
static GMatDesc outMeta(GMatDesc in, int ddepth, Size, Point, bool, int, Scalar) { |
||||
return in.withDepth(ddepth); |
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GBlur, <GMat(GMat,Size,Point,int,Scalar)>, "org.opencv.imgproc.filters.blur"){ |
||||
static GMatDesc outMeta(GMatDesc in, Size, Point, int, Scalar) { |
||||
return in; |
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GGaussBlur, <GMat(GMat,Size,double,double,int,Scalar)>, "org.opencv.imgproc.filters.gaussianBlur") { |
||||
static GMatDesc outMeta(GMatDesc in, Size, double, double, int, Scalar) { |
||||
return in; |
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GMedianBlur, <GMat(GMat,int)>, "org.opencv.imgproc.filters.medianBlur") { |
||||
static GMatDesc outMeta(GMatDesc in, int) { |
||||
return in; |
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GErode, <GMat(GMat,Mat,Point,int,int,Scalar)>, "org.opencv.imgproc.filters.erode") { |
||||
static GMatDesc outMeta(GMatDesc in, Mat, Point, int, int, Scalar) { |
||||
return in; |
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GDilate, <GMat(GMat,Mat,Point,int,int,Scalar)>, "org.opencv.imgproc.filters.dilate") { |
||||
static GMatDesc outMeta(GMatDesc in, Mat, Point, int, int, Scalar) { |
||||
return in; |
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GSobel, <GMat(GMat,int,int,int,int,double,double,int,Scalar)>, "org.opencv.imgproc.filters.sobel") { |
||||
static GMatDesc outMeta(GMatDesc in, int ddepth, int, int, int, double, double, int, Scalar) { |
||||
return in.withDepth(ddepth); |
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GEqHist, <GMat(GMat)>, "org.opencv.imgproc.equalizeHist"){ |
||||
static GMatDesc outMeta(GMatDesc in) { |
||||
return in.withType(CV_8U, 1); |
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GCanny, <GMat(GMat,double,double,int,bool)>, "org.opencv.imgproc.canny"){ |
||||
static GMatDesc outMeta(GMatDesc in, double, double, int, bool) { |
||||
return in.withType(CV_8U, 1); |
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GRGB2YUV, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.rgb2yuv") { |
||||
static GMatDesc outMeta(GMatDesc in) { |
||||
return in; // type still remains CV_8UC3;
|
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GYUV2RGB, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.yuv2rgb") { |
||||
static GMatDesc outMeta(GMatDesc in) { |
||||
return in; // type still remains CV_8UC3;
|
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GRGB2Lab, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.rgb2lab") { |
||||
static GMatDesc outMeta(GMatDesc in) { |
||||
return in; // type still remains CV_8UC3;
|
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GBGR2LUV, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.bgr2luv") { |
||||
static GMatDesc outMeta(GMatDesc in) { |
||||
return in; // type still remains CV_8UC3;
|
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GLUV2BGR, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.luv2bgr") { |
||||
static GMatDesc outMeta(GMatDesc in) { |
||||
return in; // type still remains CV_8UC3;
|
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GYUV2BGR, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.yuv2bgr") { |
||||
static GMatDesc outMeta(GMatDesc in) { |
||||
return in; // type still remains CV_8UC3;
|
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GBGR2YUV, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.bgr2yuv") { |
||||
static GMatDesc outMeta(GMatDesc in) { |
||||
return in; // type still remains CV_8UC3;
|
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GRGB2Gray, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.rgb2gray") { |
||||
static GMatDesc outMeta(GMatDesc in) { |
||||
return in.withType(CV_8U, 1); |
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GRGB2GrayCustom, <GMat(GMat,float,float,float)>, "org.opencv.imgproc.colorconvert.rgb2graycustom") { |
||||
static GMatDesc outMeta(GMatDesc in, float, float, float) { |
||||
return in.withType(CV_8U, 1); |
||||
} |
||||
}; |
||||
|
||||
G_TYPED_KERNEL(GBGR2Gray, <GMat(GMat)>, "org.opencv.imgproc.colorconvert.bgr2gray") { |
||||
static GMatDesc outMeta(GMatDesc in) { |
||||
return in.withType(CV_8U, 1); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
|
||||
//! @addtogroup gapi_filters
|
||||
//! @{
|
||||
/** @brief Applies a separable linear filter to a matrix(image).
|
||||
|
||||
The function applies a separable linear filter to the matrix. That is, first, every row of src is |
||||
filtered with the 1D kernel kernelX. Then, every column of the result is filtered with the 1D |
||||
kernel kernelY. The final result is returned. |
||||
|
||||
Supported 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. |
||||
@note In case of floating-point computation, rounding to nearest even is procedeed |
||||
if hardware supports it (if not - to nearest value). |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.filters.sepfilter" |
||||
@param src Source image. |
||||
@param ddepth desired depth of the destination image (the following combinations of src.depth() and ddepth are supported: |
||||
|
||||
src.depth() = CV_8U, ddepth = -1/CV_16S/CV_32F/CV_64F |
||||
src.depth() = CV_16U/CV_16S, ddepth = -1/CV_32F/CV_64F |
||||
src.depth() = CV_32F, ddepth = -1/CV_32F/CV_64F |
||||
src.depth() = CV_64F, ddepth = -1/CV_64F |
||||
|
||||
when ddepth=-1, the output image will have the same depth as the source) |
||||
@param kernelX Coefficients for filtering each row. |
||||
@param kernelY Coefficients for filtering each column. |
||||
@param anchor Anchor position within the kernel. The default value \f$(-1,-1)\f$ means that the anchor |
||||
is at the kernel center. |
||||
@param delta Value added to the filtered results before storing them. |
||||
@param borderType Pixel extrapolation method, see cv::BorderTypes |
||||
@param borderValue border value in case of constant border type |
||||
@sa boxFilter, gaussianBlur, medianBlur |
||||
*/ |
||||
GAPI_EXPORTS GMat sepFilter(const GMat& src, int ddepth, const Mat& kernelX, const Mat& kernelY, const Point& anchor /*FIXME: = Point(-1,-1)*/, |
||||
const Scalar& delta /*FIXME = GScalar(0)*/, int borderType = BORDER_DEFAULT, |
||||
const Scalar& borderValue = Scalar(0)); |
||||
|
||||
/** @brief Convolves an image with the kernel.
|
||||
|
||||
The function applies an arbitrary linear filter to an image. When |
||||
the aperture is partially outside the image, the function interpolates outlier pixel values |
||||
according to the specified border mode. |
||||
|
||||
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] |
||||
|
||||
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 - |
||||
anchor.y - 1)`. |
||||
|
||||
Supported 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 size and number of channels an input image. |
||||
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest. |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.filters.filter2D" |
||||
|
||||
@param src input image. |
||||
@param ddepth desired depth of the destination image |
||||
@param kernel convolution kernel (or rather a correlation kernel), a single-channel floating point |
||||
matrix; if you want to apply different kernels to different channels, split the image into |
||||
separate color planes using split and process them individually. |
||||
@param anchor anchor of the kernel that indicates the relative position of a filtered point within |
||||
the kernel; the anchor should lie within the kernel; default value (-1,-1) means that the anchor |
||||
is at the kernel center. |
||||
@param delta optional value added to the filtered pixels before storing them in dst. |
||||
@param borderType pixel extrapolation method, see cv::BorderTypes |
||||
@param borderValue border value in case of constant border type |
||||
@sa sepFilter |
||||
*/ |
||||
GAPI_EXPORTS GMat filter2D(const GMat& src, int ddepth, const Mat& kernel, const Point& anchor = Point(-1,-1), const Scalar& delta = Scalar(0), |
||||
int borderType = BORDER_DEFAULT, const Scalar& borderValue = Scalar(0)); |
||||
|
||||
|
||||
/** @brief Blurs an image using the box filter.
|
||||
|
||||
The function smooths an image using the kernel: |
||||
|
||||
\f[\texttt{K} = \alpha \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] |
||||
|
||||
where |
||||
|
||||
\f[\alpha = \fork{\frac{1}{\texttt{ksize.width*ksize.height}}}{when \texttt{normalize=true}}{1}{otherwise}\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 |
||||
algorithms, and so on). If you need to compute pixel sums over variable-size windows, use cv::integral. |
||||
|
||||
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. |
||||
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest. |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.filters.boxfilter" |
||||
|
||||
@param src Source image. |
||||
@param dtype the output image depth (-1 to set the input image data type). |
||||
@param ksize blurring kernel size. |
||||
@param anchor Anchor position within the kernel. The default value \f$(-1,-1)\f$ means that the anchor |
||||
is at the kernel center. |
||||
@param normalize flag, specifying whether the kernel is normalized by its area or not. |
||||
@param borderType Pixel extrapolation method, see cv::BorderTypes |
||||
@param borderValue border value in case of constant border type |
||||
@sa sepFilter, gaussianBlur, medianBlur, integral |
||||
*/ |
||||
GAPI_EXPORTS GMat boxFilter(const GMat& src, int dtype, const Size& ksize, const Point& anchor = Point(-1,-1), |
||||
bool normalize = true, int borderType = BORDER_DEFAULT, |
||||
const Scalar& borderValue = Scalar(0)); |
||||
|
||||
/** @brief Blurs an image using the normalized box filter.
|
||||
|
||||
The function smooths an image using the kernel: |
||||
|
||||
\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)`. |
||||
|
||||
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. |
||||
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest. |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.filters.blur" |
||||
|
||||
@param src Source image. |
||||
@param ksize blurring kernel size. |
||||
@param anchor anchor point; default value Point(-1,-1) means that the anchor is at the kernel |
||||
center. |
||||
@param borderType border mode used to extrapolate pixels outside of the image, see cv::BorderTypes |
||||
@param borderValue border value in case of constant border type |
||||
@sa boxFilter, bilateralFilter, GaussianBlur, medianBlur |
||||
*/ |
||||
GAPI_EXPORTS GMat blur(const GMat& src, const Size& ksize, const Point& anchor = Point(-1,-1), |
||||
int borderType = BORDER_DEFAULT, const Scalar& borderValue = Scalar(0)); |
||||
|
||||
|
||||
//GAPI_EXPORTS_W void blur( InputArray src, OutputArray dst,
|
||||
// Size ksize, Point anchor = Point(-1,-1),
|
||||
// int borderType = BORDER_DEFAULT );
|
||||
|
||||
|
||||
/** @brief Blurs an image using a Gaussian filter.
|
||||
|
||||
The function filter2Ds the source image with the specified Gaussian kernel. |
||||
Output image must have the same type and number of channels an input image. |
||||
|
||||
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. |
||||
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest. |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.filters.gaussianBlur" |
||||
|
||||
@param src input image; |
||||
@param ksize Gaussian kernel size. ksize.width and ksize.height can differ but they both must be |
||||
positive and odd. Or, they can be zero's and then they are computed from sigma. |
||||
@param sigmaX Gaussian kernel standard deviation in X direction. |
||||
@param sigmaY Gaussian kernel standard deviation in Y direction; if sigmaY is zero, it is set to be |
||||
equal to sigmaX, if both sigmas are zeros, they are computed from ksize.width and ksize.height, |
||||
respectively (see cv::getGaussianKernel for details); to fully control the result regardless of |
||||
possible future modifications of all this semantics, it is recommended to specify all of ksize, |
||||
sigmaX, and sigmaY. |
||||
@param borderType pixel extrapolation method, see cv::BorderTypes |
||||
@param borderValue border value in case of constant border type |
||||
@sa sepFilter, boxFilter, medianBlur |
||||
*/ |
||||
GAPI_EXPORTS GMat gaussianBlur(const GMat& src, const Size& ksize, double sigmaX, double sigmaY = 0, |
||||
int borderType = BORDER_DEFAULT, const Scalar& borderValue = Scalar(0)); |
||||
|
||||
/** @brief Blurs an image using the median filter.
|
||||
|
||||
The function smoothes an image using the median filter with the \f$\texttt{ksize} \times |
||||
\texttt{ksize}\f$ aperture. Each channel of a multi-channel image is processed independently. |
||||
Output image must have the same type, size, and number of channels as the input image. |
||||
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest. |
||||
The median filter uses cv::BORDER_REPLICATE internally to cope with border pixels, see cv::BorderTypes |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.filters.medianBlur" |
||||
|
||||
@param src input matrix (image) |
||||
@param ksize aperture linear size; it must be odd and greater than 1, for example: 3, 5, 7 ... |
||||
@sa boxFilter, gaussianBlur |
||||
*/ |
||||
GAPI_EXPORTS GMat medianBlur(const GMat& src, int ksize); |
||||
|
||||
/** @brief Erodes an image by using a specific structuring element.
|
||||
|
||||
The function erodes the source image using the specified structuring element that determines the |
||||
shape of a pixel neighborhood over which the minimum is taken: |
||||
|
||||
\f[\texttt{dst} (x,y) = \min _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f] |
||||
|
||||
Erosion can be applied several (iterations) times. In case of multi-channel images, each channel is processed independently. |
||||
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, and @ref CV_32FC1. |
||||
Output image must have the same type, size, and number of channels as the input image. |
||||
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest. |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.filters.erode" |
||||
|
||||
@param src input image |
||||
@param kernel structuring element used for erosion; if `element=Mat()`, a `3 x 3` rectangular |
||||
structuring element is used. Kernel can be created using getStructuringElement. |
||||
@param anchor position of the anchor within the element; default value (-1, -1) means that the |
||||
anchor is at the element center. |
||||
@param iterations number of times erosion is applied. |
||||
@param borderType pixel extrapolation method, see cv::BorderTypes |
||||
@param borderValue border value in case of a constant border |
||||
@sa dilate |
||||
*/ |
||||
GAPI_EXPORTS GMat erode(const GMat& src, const Mat& kernel, const Point& anchor = Point(-1,-1), int iterations = 1, |
||||
int borderType = BORDER_CONSTANT, |
||||
const Scalar& borderValue = morphologyDefaultBorderValue()); |
||||
|
||||
/** @brief Erodes an image by using 3 by 3 rectangular structuring element.
|
||||
|
||||
The function erodes the source image using the rectangular structuring element with rectangle center as an anchor. |
||||
Erosion can be applied several (iterations) times. In case of multi-channel images, each channel is processed independently. |
||||
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, and @ref CV_32FC1. |
||||
Output image must have the same type, size, and number of channels as the input image. |
||||
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest. |
||||
|
||||
@param src input image |
||||
@param iterations number of times erosion is applied. |
||||
@param borderType pixel extrapolation method, see cv::BorderTypes |
||||
@param borderValue border value in case of a constant border |
||||
@sa erode, dilate3x3 |
||||
*/ |
||||
GAPI_EXPORTS GMat erode3x3(const GMat& src, int iterations = 1, |
||||
int borderType = BORDER_CONSTANT, |
||||
const Scalar& borderValue = morphologyDefaultBorderValue()); |
||||
|
||||
/** @brief Dilates an image by using a specific structuring element.
|
||||
|
||||
The function dilates the source image using the specified structuring element that determines the |
||||
shape of a pixel neighborhood over which the maximum is taken: |
||||
\f[\texttt{dst} (x,y) = \max _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f] |
||||
|
||||
Dilation can be applied several (iterations) times. In case of multi-channel images, each channel is processed independently. |
||||
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, and @ref CV_32FC1. |
||||
Output image must have the same type, size, and number of channels as the input image. |
||||
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest. |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.filters.dilate" |
||||
|
||||
@param src input image. |
||||
@param kernel structuring element used for dilation; if elemenat=Mat(), a 3 x 3 rectangular |
||||
structuring element is used. Kernel can be created using getStructuringElement |
||||
@param anchor position of the anchor within the element; default value (-1, -1) means that the |
||||
anchor is at the element center. |
||||
@param iterations number of times dilation is applied. |
||||
@param borderType pixel extrapolation method, see cv::BorderTypes |
||||
@param borderValue border value in case of a constant border |
||||
@sa erode, morphologyEx, getStructuringElement |
||||
*/ |
||||
GAPI_EXPORTS GMat dilate(const GMat& src, const Mat& kernel, const Point& anchor = Point(-1,-1), int iterations = 1, |
||||
int borderType = BORDER_CONSTANT, |
||||
const Scalar& borderValue = morphologyDefaultBorderValue()); |
||||
|
||||
/** @brief Dilates an image by using 3 by 3 rectangular structuring element.
|
||||
|
||||
The function dilates the source image using the specified structuring element that determines the |
||||
shape of a pixel neighborhood over which the maximum is taken: |
||||
\f[\texttt{dst} (x,y) = \max _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f] |
||||
|
||||
Dilation can be applied several (iterations) times. In case of multi-channel images, each channel is processed independently. |
||||
Supported input matrix data types are @ref CV_8UC1, @ref CV_8UC3, @ref CV_16UC1, @ref CV_16SC1, and @ref CV_32FC1. |
||||
Output image must have the same type, size, and number of channels as the input image. |
||||
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest. |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.filters.dilate" |
||||
|
||||
@param src input image. |
||||
@param iterations number of times dilation is applied. |
||||
@param borderType pixel extrapolation method, see cv::BorderTypes |
||||
@param borderValue border value in case of a constant border |
||||
@sa dilate, erode3x3 |
||||
*/ |
||||
|
||||
GAPI_EXPORTS GMat dilate3x3(const GMat& src, int iterations = 1, |
||||
int borderType = BORDER_CONSTANT, |
||||
const Scalar& borderValue = morphologyDefaultBorderValue()); |
||||
|
||||
/** @brief Calculates the first, second, third, or mixed image derivatives using an extended Sobel operator.
|
||||
|
||||
In all cases except one, the \f$\texttt{ksize} \times \texttt{ksize}\f$ separable kernel is used to |
||||
calculate the derivative. When \f$\texttt{ksize = 1}\f$, the \f$3 \times 1\f$ or \f$1 \times 3\f$ |
||||
kernel is used (that is, no Gaussian smoothing is done). `ksize = 1` can only be used for the first |
||||
or the second x- or y- derivatives. |
||||
|
||||
There is also the special value `ksize = CV_SCHARR (-1)` that corresponds to the \f$3\times3\f$ Scharr |
||||
filter that may give more accurate results than the \f$3\times3\f$ Sobel. The Scharr aperture is |
||||
|
||||
\f[\vecthreethree{-3}{0}{3}{-10}{0}{10}{-3}{0}{3}\f] |
||||
|
||||
for the x-derivative, or transposed for the y-derivative. |
||||
|
||||
The function calculates an image derivative by convolving the image with the appropriate kernel: |
||||
|
||||
\f[\texttt{dst} = \frac{\partial^{xorder+yorder} \texttt{src}}{\partial x^{xorder} \partial y^{yorder}}\f] |
||||
|
||||
The Sobel operators combine Gaussian smoothing and differentiation, so the result is more or less |
||||
resistant to the noise. Most often, the function is called with ( xorder = 1, yorder = 0, ksize = 3) |
||||
or ( xorder = 0, yorder = 1, ksize = 3) to calculate the first x- or y- image derivative. The first |
||||
case corresponds to a kernel of: |
||||
|
||||
\f[\vecthreethree{-1}{0}{1}{-2}{0}{2}{-1}{0}{1}\f] |
||||
|
||||
The second case corresponds to a kernel of: |
||||
|
||||
\f[\vecthreethree{-1}{-2}{-1}{0}{0}{0}{1}{2}{1}\f] |
||||
|
||||
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest. |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.filters.sobel" |
||||
|
||||
@param src input image. |
||||
@param ddepth output image depth, see @ref filter_depths "combinations"; in the case of |
||||
8-bit input images it will result in truncated derivatives. |
||||
@param dx order of the derivative x. |
||||
@param dy order of the derivative y. |
||||
@param ksize size of the extended Sobel kernel; it must be odd. |
||||
@param scale optional scale factor for the computed derivative values; by default, no scaling is |
||||
applied (see cv::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 cv::BorderTypes |
||||
@param borderValue border value in case of constant border type |
||||
@sa filter2D, gaussianBlur, cartToPolar |
||||
*/ |
||||
GAPI_EXPORTS GMat sobel(const GMat& src, int ddepth, int dx, int dy, int ksize = 3, |
||||
double scale = 1, double delta = 0, |
||||
int borderType = BORDER_DEFAULT, |
||||
const Scalar& borderValue = Scalar(0)); |
||||
|
||||
/** @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 |
||||
Canny algorithm. The smallest value between threshold1 and threshold2 is used for edge linking. The |
||||
largest value is used to find initial segments of strong edges. See |
||||
<http://en.wikipedia.org/wiki/Canny_edge_detector>
|
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.filters.canny" |
||||
|
||||
@param image 8-bit input image. |
||||
@param threshold1 first threshold for the hysteresis procedure. |
||||
@param threshold2 second threshold for the hysteresis procedure. |
||||
@param apertureSize aperture size for the Sobel operator. |
||||
@param L2gradient a flag, indicating whether a more accurate \f$L_2\f$ norm |
||||
\f$=\sqrt{(dI/dx)^2 + (dI/dy)^2}\f$ should be used to calculate the image gradient magnitude ( |
||||
L2gradient=true ), or whether the default \f$L_1\f$ norm \f$=|dI/dx|+|dI/dy|\f$ is enough ( |
||||
L2gradient=false ). |
||||
*/ |
||||
GAPI_EXPORTS GMat Canny(const GMat& image, double threshold1, double threshold2, |
||||
int apertureSize = 3, bool L2gradient = false); |
||||
|
||||
/** @brief Equalizes the histogram of a grayscale image.
|
||||
|
||||
The function equalizes the histogram of the input image using the following algorithm: |
||||
|
||||
- Calculate the histogram \f$H\f$ for src . |
||||
- Normalize the histogram so that the sum of histogram bins is 255. |
||||
- Compute the integral of the histogram: |
||||
\f[H'_i = \sum _{0 \le j < i} H(j)\f] |
||||
- Transform the image using \f$H'\f$ as a look-up table: \f$\texttt{dst}(x,y) = H'(\texttt{src}(x,y))\f$ |
||||
|
||||
The algorithm normalizes the brightness and increases the contrast of the image. |
||||
@note The returned image is of the same size and type as input. |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.equalizeHist" |
||||
|
||||
@param src Source 8-bit single channel image. |
||||
*/ |
||||
GAPI_EXPORTS GMat equalizeHist(const GMat& src); |
||||
|
||||
//! @} gapi_filters
|
||||
|
||||
//! @addtogroup gapi_colorconvert
|
||||
//! @{
|
||||
/** @brief Converts an image from RGB color space to gray-scaled.
|
||||
The conventional ranges for R, G, and B channel values are 0 to 255. |
||||
Resulting gray color value computed as |
||||
\f[\texttt{dst} (I)= \texttt{0.299} * \texttt{src}(I).R + \texttt{0.587} * \texttt{src}(I).G + \texttt{0.114} * \texttt{src}(I).B \f] |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.colorconvert.rgb2gray" |
||||
|
||||
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC1. |
||||
@sa RGB2YUV |
||||
*/ |
||||
GAPI_EXPORTS GMat RGB2Gray(const GMat& src); |
||||
|
||||
/** @overload
|
||||
Resulting gray color value computed as |
||||
\f[\texttt{dst} (I)= \texttt{rY} * \texttt{src}(I).R + \texttt{gY} * \texttt{src}(I).G + \texttt{bY} * \texttt{src}(I).B \f] |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.colorconvert.rgb2graycustom" |
||||
|
||||
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC1. |
||||
@param rY float multiplier for R channel. |
||||
@param gY float multiplier for G channel. |
||||
@param bY float multiplier for B channel. |
||||
@sa RGB2YUV |
||||
*/ |
||||
GAPI_EXPORTS GMat RGB2Gray(const GMat& src, float rY, float gY, float bY); |
||||
|
||||
/** @brief Converts an image from BGR color space to gray-scaled.
|
||||
The conventional ranges for B, G, and R channel values are 0 to 255. |
||||
Resulting gray color value computed as |
||||
\f[\texttt{dst} (I)= \texttt{0.114} * \texttt{src}(I).B + \texttt{0.587} * \texttt{src}(I).G + \texttt{0.299} * \texttt{src}(I).R \f] |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.colorconvert.bgr2gray" |
||||
|
||||
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC1. |
||||
@sa BGR2LUV |
||||
*/ |
||||
GAPI_EXPORTS GMat BGR2Gray(const GMat& src); |
||||
|
||||
/** @brief Converts an image from RGB color space to YUV color space.
|
||||
|
||||
The function converts an input image from RGB color space to YUV. |
||||
The conventional ranges for R, G, and B channel values are 0 to 255. |
||||
|
||||
In case of linear transformations, the range does not matter. But in case of a non-linear |
||||
transformation, an input RGB image should be normalized to the proper value range to get the correct |
||||
results, like here, at RGB \f$\rightarrow\f$ Y\*u\*v\* transformation. |
||||
Output image must be 8-bit unsigned 3-channel image @ref CV_8UC3. |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.colorconvert.rgb2yuv" |
||||
|
||||
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3. |
||||
@sa YUV2RGB, RGB2Lab |
||||
*/ |
||||
GAPI_EXPORTS GMat RGB2YUV(const GMat& src); |
||||
|
||||
/** @brief Converts an image from BGR color space to LUV color space.
|
||||
|
||||
The function converts an input image from BGR color space to LUV. |
||||
The conventional ranges for B, G, and R channel values are 0 to 255. |
||||
|
||||
Output image must be 8-bit unsigned 3-channel image @ref CV_8UC3. |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.colorconvert.bgr2luv" |
||||
|
||||
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3. |
||||
@sa RGB2Lab, RGB2LUV |
||||
*/ |
||||
GAPI_EXPORTS GMat BGR2LUV(const GMat& src); |
||||
|
||||
/** @brief Converts an image from LUV color space to BGR color space.
|
||||
|
||||
The function converts an input image from LUV color space to BGR. |
||||
The conventional ranges for B, G, and R channel values are 0 to 255. |
||||
|
||||
Output image must be 8-bit unsigned 3-channel image @ref CV_8UC3. |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.colorconvert.luv2bgr" |
||||
|
||||
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3. |
||||
@sa BGR2LUV |
||||
*/ |
||||
GAPI_EXPORTS GMat LUV2BGR(const GMat& src); |
||||
|
||||
/** @brief Converts an image from YUV color space to BGR color space.
|
||||
|
||||
The function converts an input image from YUV color space to BGR. |
||||
The conventional ranges for B, G, and R channel values are 0 to 255. |
||||
|
||||
Output image must be 8-bit unsigned 3-channel image @ref CV_8UC3. |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.colorconvert.yuv2bgr" |
||||
|
||||
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3. |
||||
@sa BGR2YUV |
||||
*/ |
||||
GAPI_EXPORTS GMat YUV2BGR(const GMat& src); |
||||
|
||||
/** @brief Converts an image from BGR color space to YUV color space.
|
||||
|
||||
The function converts an input image from BGR color space to YUV. |
||||
The conventional ranges for B, G, and R channel values are 0 to 255. |
||||
|
||||
Output image must be 8-bit unsigned 3-channel image @ref CV_8UC3. |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.colorconvert.bgr2yuv" |
||||
|
||||
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3. |
||||
@sa YUV2BGR |
||||
*/ |
||||
GAPI_EXPORTS GMat BGR2YUV(const GMat& src); |
||||
|
||||
/** @brief Converts an image from RGB color space to Lab color space.
|
||||
|
||||
The function converts an input image from BGR color space to Lab. |
||||
The conventional ranges for R, G, and B channel values are 0 to 255. |
||||
|
||||
Output image must be 8-bit unsigned 3-channel image @ref CV_8UC1. |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.colorconvert.rgb2lab" |
||||
|
||||
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC1. |
||||
@sa RGB2YUV, RGB2LUV |
||||
*/ |
||||
GAPI_EXPORTS GMat RGB2Lab(const GMat& src); |
||||
|
||||
/** @brief Converts an image from YUV color space to RGB.
|
||||
The function converts an input image from YUV color space to RGB. |
||||
The conventional ranges for Y, U, and V channel values are 0 to 255. |
||||
|
||||
Output image must be 8-bit unsigned 3-channel image @ref CV_8UC3. |
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.colorconvert.yuv2rgb" |
||||
|
||||
@param src input image: 8-bit unsigned 3-channel image @ref CV_8UC3. |
||||
|
||||
@sa RGB2Lab, RGB2YUV |
||||
*/ |
||||
GAPI_EXPORTS GMat YUV2RGB(const GMat& src); |
||||
|
||||
//! @} gapi_colorconvert
|
||||
} //namespace gapi
|
||||
} //namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_IMGPROC_HPP
|
@ -0,0 +1,16 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_OPENCV_INCLUDES_HPP |
||||
#define OPENCV_GAPI_OPENCV_INCLUDES_HPP |
||||
|
||||
#include <opencv2/core/mat.hpp> |
||||
#include <opencv2/core/cvdef.h> |
||||
#include <opencv2/core/types.hpp> |
||||
#include <opencv2/core/base.hpp> |
||||
|
||||
#endif // OPENCV_GAPI_OPENCV_INCLUDES_HPP
|
@ -0,0 +1,69 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_OPERATORS_HPP |
||||
#define OPENCV_GAPI_OPERATORS_HPP |
||||
|
||||
#include "opencv2/gapi/gmat.hpp" |
||||
#include "opencv2/gapi/gscalar.hpp" |
||||
|
||||
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::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::GMat& lhs, float rhs); |
||||
GAPI_EXPORTS cv::GMat operator*(float 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::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::GMat& lhs, const cv::GMat& rhs); |
||||
|
||||
GAPI_EXPORTS cv::GMat operator&(const cv::GMat& lhs, const cv::GMat& rhs); |
||||
GAPI_EXPORTS cv::GMat operator|(const cv::GMat& lhs, const cv::GMat& rhs); |
||||
GAPI_EXPORTS cv::GMat operator^(const cv::GMat& lhs, const cv::GMat& rhs); |
||||
GAPI_EXPORTS cv::GMat operator~(const cv::GMat& lhs); |
||||
|
||||
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); |
||||
|
||||
GAPI_EXPORTS cv::GMat operator&(const cv::GMat& lhs, const cv::GScalar& rhs); |
||||
GAPI_EXPORTS cv::GMat operator|(const cv::GMat& lhs, const cv::GScalar& rhs); |
||||
GAPI_EXPORTS cv::GMat operator^(const cv::GMat& lhs, const cv::GScalar& rhs); |
||||
|
||||
GAPI_EXPORTS cv::GMat operator>(const cv::GMat& lhs, const cv::GMat& rhs); |
||||
GAPI_EXPORTS cv::GMat operator>=(const cv::GMat& lhs, const cv::GMat& rhs); |
||||
GAPI_EXPORTS cv::GMat operator<(const cv::GMat& lhs, const cv::GMat& rhs); |
||||
GAPI_EXPORTS cv::GMat operator<=(const cv::GMat& lhs, const cv::GMat& rhs); |
||||
GAPI_EXPORTS cv::GMat operator==(const cv::GMat& lhs, const cv::GMat& rhs); |
||||
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::GMat& lhs, const cv::GScalar& rhs); |
||||
GAPI_EXPORTS cv::GMat operator<(const cv::GMat& lhs, const cv::GScalar& rhs); |
||||
GAPI_EXPORTS cv::GMat operator<=(const cv::GMat& lhs, const cv::GScalar& rhs); |
||||
GAPI_EXPORTS cv::GMat operator==(const cv::GMat& lhs, const cv::GScalar& 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); |
||||
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); |
||||
|
||||
|
||||
|
||||
#endif // OPENCV_GAPI_OPERATORS_HPP
|
@ -0,0 +1,41 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_OWN_ASSERT_HPP |
||||
#define OPENCV_GAPI_OWN_ASSERT_HPP |
||||
|
||||
#if 0 |
||||
#include <opencv2/core/base.hpp> |
||||
#define GAPI_Assert(expr) CV_Assert(expr) |
||||
|
||||
#else |
||||
#include <stdexcept> |
||||
#include <sstream> |
||||
#include "opencv2/gapi/util/throw.hpp" |
||||
|
||||
namespace detail |
||||
{ |
||||
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"; |
||||
cv::util::throw_error(std::logic_error(ss.str())); |
||||
} |
||||
} |
||||
|
||||
#define GAPI_Assert(expr) \ |
||||
{ if (!(expr)) ::detail::assert_abort(#expr, __LINE__, __FILE__, __func__); } |
||||
|
||||
#endif |
||||
|
||||
#ifdef _DEBUG |
||||
# define GAPI_DbgAssert(expr) GAPI_Assert(expr) |
||||
#else |
||||
# define GAPI_DbgAssert(expr) |
||||
#endif |
||||
|
||||
#endif // OPENCV_GAPI_OWN_ASSERT_HPP
|
@ -0,0 +1,47 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_OWN_CONVERT_HPP |
||||
#define OPENCV_GAPI_OWN_CONVERT_HPP |
||||
|
||||
#include <opencv2/core/types.hpp> |
||||
#include <opencv2/core/mat.hpp> |
||||
#include <opencv2/gapi/own/types.hpp> |
||||
#include <opencv2/gapi/own/mat.hpp> |
||||
#include "opencv2/gapi/own/scalar.hpp" |
||||
|
||||
namespace cv |
||||
{ |
||||
inline cv::gapi::own::Mat to_own(Mat const& m) { return {m.rows, m.cols, m.type(), m.data, m.step};}; |
||||
cv::gapi::own::Mat to_own(Mat&&) = delete; |
||||
|
||||
inline cv::gapi::own::Scalar to_own(const cv::Scalar& s) { return {s[0], s[1], s[2], s[3]}; }; |
||||
|
||||
inline cv::gapi::own::Size to_own (const Size& s) { return {s.width, s.height}; }; |
||||
|
||||
inline cv::gapi::own::Rect to_own (const Rect& r) { return {r.x, r.y, r.width, r.height}; }; |
||||
|
||||
|
||||
|
||||
namespace gapi |
||||
{ |
||||
namespace own |
||||
{ |
||||
inline cv::Mat to_ocv(Mat const& m) { return {m.rows, m.cols, m.type(), m.data, m.step};}; |
||||
cv::Mat to_ocv(Mat&&) = delete; |
||||
|
||||
inline cv::Scalar to_ocv(const Scalar& s) { return {s[0], s[1], s[2], s[3]}; }; |
||||
|
||||
inline cv::Size to_ocv (const Size& s) { return cv::Size(s.width, s.height); }; |
||||
|
||||
inline cv::Rect to_ocv (const Rect& r) { return cv::Rect(r.x, r.y, r.width, r.height); }; |
||||
|
||||
} // namespace own
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_OWN_CONVERT_HPP
|
@ -0,0 +1,28 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_OWN_TYPES_HPP |
||||
#define OPENCV_GAPI_OWN_TYPES_HPP |
||||
|
||||
# if 0 |
||||
# include <opencv2/core/base.hpp> |
||||
# define GAPI_EXPORTS CV_EXPORTS |
||||
|
||||
# else |
||||
# if defined _WIN32 |
||||
# define GAPI_EXPORTS __declspec(dllexport) |
||||
# elif defined __GNUC__ && __GNUC__ >= 4 |
||||
# define GAPI_EXPORTS __attribute__ ((visibility ("default"))) |
||||
# endif |
||||
|
||||
# ifndef GAPI_EXPORTS |
||||
# define GAPI_EXPORTS |
||||
# endif |
||||
|
||||
# endif |
||||
|
||||
#endif // OPENCV_GAPI_OWN_TYPES_HPP
|
@ -0,0 +1,142 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef INCLUDE_OPENCV2_GAPI_OWN_MAT_HPP |
||||
#define INCLUDE_OPENCV2_GAPI_OWN_MAT_HPP |
||||
|
||||
#include "opencv2/core/cvdef.h" |
||||
#include "opencv2/gapi/own/types.hpp" |
||||
#include <memory> //std::shared_ptr |
||||
|
||||
namespace cv { namespace gapi { namespace own { |
||||
namespace detail { |
||||
inline size_t default_step(int type, int cols) |
||||
{ |
||||
return CV_ELEM_SIZE(type) * cols; |
||||
} |
||||
//Matrix header, i.e. fields that are unique to each Mat object.
|
||||
//Devoted class is needed to implement custom behavior on move (erasing state of moved from object)
|
||||
struct MatHeader{ |
||||
enum { AUTO_STEP = 0}; |
||||
enum { TYPE_MASK = 0x00000FFF }; |
||||
|
||||
MatHeader() = default; |
||||
|
||||
MatHeader(int _rows, int _cols, int type, void* _data, size_t _step) |
||||
: flags((type & TYPE_MASK)), rows(_rows), cols(_cols), data((uchar*)_data), step(_step == AUTO_STEP ? detail::default_step(type, _cols) : _step) |
||||
{} |
||||
|
||||
MatHeader(const MatHeader& ) = default; |
||||
MatHeader(MatHeader&& src) : MatHeader(src) // reuse copy constructor here
|
||||
{ |
||||
MatHeader empty; //give it a name to call copy(not move) assignment below
|
||||
src = empty; |
||||
} |
||||
MatHeader& operator=(const MatHeader& ) = default; |
||||
MatHeader& operator=(MatHeader&& src) |
||||
{ |
||||
*this = src; //calling a copy assignment here, not move one
|
||||
MatHeader empty; //give it a name to call copy(not move) assignment below
|
||||
src = empty; |
||||
return *this; |
||||
} |
||||
/*! includes several bit-fields:
|
||||
- depth |
||||
- number of channels |
||||
*/ |
||||
int flags = 0; |
||||
|
||||
//! the number of rows and columns or (-1, -1) when the matrix has more than 2 dimensions
|
||||
int rows = 0, cols = 0; |
||||
//! pointer to the data
|
||||
uchar* data = nullptr; |
||||
size_t step = 0; |
||||
}; |
||||
} |
||||
//concise version of cv::Mat suitable for GAPI needs (used when no dependence on OpenCV is required)
|
||||
class Mat : public detail::MatHeader{ |
||||
public: |
||||
|
||||
Mat() = default; |
||||
|
||||
/** @overload
|
||||
@param _rows Number of rows in a 2D array. |
||||
@param _cols Number of columns in a 2D array. |
||||
@param _type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or |
||||
CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices. |
||||
@param _data Pointer to the user data. Matrix constructors that take data and step parameters do not |
||||
allocate matrix data. Instead, they just initialize the matrix header that points to the specified |
||||
data, which means that no data is copied. This operation is very efficient and can be used to |
||||
process external data using OpenCV functions. The external data is not automatically deallocated, so |
||||
you should take care of it. |
||||
@param _step Number of bytes each matrix row occupies. The value should include the padding bytes at |
||||
the end of each row, if any. If the parameter is missing (set to AUTO_STEP ), no padding is assumed |
||||
and the actual step is calculated as cols*elemSize(). See Mat::elemSize. |
||||
*/ |
||||
Mat(int _rows, int _cols, int _type, void* _data, size_t _step = AUTO_STEP) |
||||
: MatHeader (_rows, _cols, _type, _data, _step) |
||||
{} |
||||
|
||||
Mat(Mat const& src) = default; |
||||
Mat(Mat&& src) = default; |
||||
|
||||
Mat& operator=(Mat const& src) = default; |
||||
Mat& operator=(Mat&& src) = default; |
||||
|
||||
/** @brief Returns the type of a matrix element.
|
||||
|
||||
The method returns a matrix element type. This is an identifier compatible with the CvMat type |
||||
system, like CV_16SC3 or 16-bit signed 3-channel array, and so on. |
||||
*/ |
||||
int type() const {return CV_MAT_TYPE(flags);} |
||||
|
||||
/** @brief Returns the depth of a matrix element.
|
||||
|
||||
The method returns the identifier of the matrix element depth (the type of each individual channel). |
||||
For example, for a 16-bit signed element array, the method returns CV_16S . A complete list of |
||||
matrix types contains the following values: |
||||
- CV_8U - 8-bit unsigned integers ( 0..255 ) |
||||
- CV_8S - 8-bit signed integers ( -128..127 ) |
||||
- CV_16U - 16-bit unsigned integers ( 0..65535 ) |
||||
- CV_16S - 16-bit signed integers ( -32768..32767 ) |
||||
- CV_32S - 32-bit signed integers ( -2147483648..2147483647 ) |
||||
- CV_32F - 32-bit floating-point numbers ( -FLT_MAX..FLT_MAX, INF, NAN ) |
||||
- CV_64F - 64-bit floating-point numbers ( -DBL_MAX..DBL_MAX, INF, NAN ) |
||||
*/ |
||||
int depth() const {return CV_MAT_DEPTH(flags);} |
||||
|
||||
/** @brief Returns the number of matrix channels.
|
||||
|
||||
The method returns the number of matrix channels. |
||||
*/ |
||||
int channels() const {return CV_MAT_CN(flags);} |
||||
|
||||
/** @overload
|
||||
@param _size Alternative new matrix size specification: Size(cols, rows) |
||||
@param _type New matrix type. |
||||
*/ |
||||
void create(cv::gapi::own::Size _size, int _type) |
||||
{ |
||||
if (_size != cv::gapi::own::Size{cols, rows} ) |
||||
{ |
||||
Mat tmp{_size.height, _size.width, _type, nullptr}; |
||||
tmp.memory.reset(new uchar[ tmp.step * tmp.rows], [](uchar * p){delete[] p;}); |
||||
tmp.data = tmp.memory.get(); |
||||
|
||||
*this = std::move(tmp); |
||||
} |
||||
} |
||||
private: |
||||
//actual memory allocated for storage, or nullptr if object is non owning view to over memory
|
||||
std::shared_ptr<uchar> memory; |
||||
}; |
||||
|
||||
} //namespace own
|
||||
} //namespace gapi
|
||||
} //namespace cv
|
||||
|
||||
#endif /* INCLUDE_OPENCV2_GAPI_OWN_MAT_HPP */ |
@ -0,0 +1,45 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GAPI_OWN_SCALAR_HPP |
||||
#define OPENCV_GAPI_GAPI_OWN_SCALAR_HPP |
||||
|
||||
namespace cv |
||||
{ |
||||
namespace gapi |
||||
{ |
||||
namespace own |
||||
{ |
||||
|
||||
class CV_EXPORTS Scalar |
||||
{ |
||||
public: |
||||
Scalar() = default; |
||||
explicit Scalar(double v0) { val[0] = v0; }; |
||||
Scalar(double v0, double v1, double v2 = 0, double v3 = 0) |
||||
: val{v0, v1, v2, v3} |
||||
{ |
||||
} |
||||
|
||||
const double& operator[](int i) const { return val[i]; } |
||||
double& operator[](int i) { return val[i]; } |
||||
|
||||
static Scalar all(double v0) { return Scalar(v0, v0, v0, v0); } |
||||
|
||||
double val[4] = {0}; |
||||
}; |
||||
|
||||
inline bool operator==(const Scalar& lhs, const Scalar& rhs) |
||||
{ |
||||
return std::equal(std::begin(lhs.val), std::end(lhs.val), std::begin(rhs.val)); |
||||
} |
||||
|
||||
} // namespace own
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_GAPI_OWN_SCALAR_HPP
|
@ -0,0 +1,137 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_TYPES_HPP |
||||
#define OPENCV_GAPI_TYPES_HPP |
||||
|
||||
#include <algorithm> // std::max, std::min |
||||
|
||||
#include "opencv2/core/base.hpp" //for CV_DbgAssert |
||||
#include "opencv2/gapi/own/assert.hpp" |
||||
|
||||
namespace cv |
||||
{ |
||||
namespace gapi |
||||
{ |
||||
namespace own |
||||
{ |
||||
|
||||
class Point |
||||
{ |
||||
public: |
||||
Point() = default; |
||||
Point(int _x, int _y) : x(_x), y(_y) {}; |
||||
|
||||
int x = 0; |
||||
int y = 0; |
||||
}; |
||||
|
||||
class Rect |
||||
{ |
||||
public: |
||||
Rect() = default; |
||||
Rect(int _x, int _y, int _width, int _height) : x(_x), y(_y), width(_width), height(_height) {}; |
||||
#if 1 |
||||
Rect(const cv::Rect& other) : x(other.x), y(other.y), width(other.width), height(other.height) {}; |
||||
inline Rect& operator=(const cv::Rect& other) |
||||
{ |
||||
x = other.x; |
||||
y = other.x; |
||||
width = other.width; |
||||
height = other.height; |
||||
return *this; |
||||
} |
||||
#endif |
||||
|
||||
int x = 0; //!< x coordinate of the top-left corner
|
||||
int y = 0; //!< y coordinate of the top-left corner
|
||||
int width = 0; //!< width of the rectangle
|
||||
int height = 0; //!< height of the rectangle
|
||||
}; |
||||
|
||||
inline bool operator==(const Rect& lhs, const Rect& rhs) |
||||
{ |
||||
return lhs.x == rhs.x && lhs.y == rhs.y && lhs.width == rhs.width && lhs.height == rhs.height; |
||||
} |
||||
|
||||
inline bool operator!=(const Rect& lhs, const Rect& rhs) |
||||
{ |
||||
return !(lhs == rhs); |
||||
} |
||||
|
||||
inline Rect& operator&=(Rect& lhs, const Rect& rhs) |
||||
{ |
||||
int x1 = std::max(lhs.x, rhs.x); |
||||
int y1 = std::max(lhs.y, rhs.y); |
||||
lhs.width = std::min(lhs.x + lhs.width, rhs.x + rhs.width) - x1; |
||||
lhs.height = std::min(lhs.y + lhs.height, rhs.y + rhs.height) - y1; |
||||
lhs.x = x1; |
||||
lhs.y = y1; |
||||
if( lhs.width <= 0 || lhs.height <= 0 ) |
||||
lhs = Rect(); |
||||
return lhs; |
||||
} |
||||
|
||||
inline const Rect operator&(const Rect& lhs, const Rect& rhs) |
||||
{ |
||||
Rect result = lhs; |
||||
return result &= rhs; |
||||
} |
||||
|
||||
inline std::ostream& operator<<(std::ostream& o, const Rect& rect) |
||||
{ |
||||
return o << "[" << rect.width << " x " << rect.height << " from (" << rect.x << ", " << rect.y << ")]"; |
||||
} |
||||
|
||||
class Size |
||||
{ |
||||
public: |
||||
Size() = default; |
||||
Size(int _width, int _height) : width(_width), height(_height) {}; |
||||
#if 1 |
||||
Size(const cv::Size& other) : width(other.width), height(other.height) {}; |
||||
inline Size& operator=(const cv::Size& rhs) |
||||
{ |
||||
width = rhs.width; |
||||
height = rhs.height; |
||||
return *this; |
||||
} |
||||
#endif |
||||
|
||||
int width = 0; |
||||
int height = 0; |
||||
}; |
||||
|
||||
inline Size& operator+=(Size& lhs, const Size& rhs) |
||||
{ |
||||
lhs.width += rhs.width; |
||||
lhs.height += rhs.height; |
||||
return lhs; |
||||
} |
||||
|
||||
inline bool operator==(const Size& lhs, const Size& rhs) |
||||
{ |
||||
return lhs.width == rhs.width && lhs.height == rhs.height; |
||||
} |
||||
|
||||
inline bool operator!=(const Size& lhs, const Size& rhs) |
||||
{ |
||||
return !(lhs == rhs); |
||||
} |
||||
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& o, const Size& s) |
||||
{ |
||||
o << "[" << s.width << " x " << s.height << "]"; |
||||
return o; |
||||
} |
||||
|
||||
} // namespace own
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_TYPES_HPP
|
@ -0,0 +1,159 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_UTIL_ANY_HPP |
||||
#define OPENCV_GAPI_UTIL_ANY_HPP |
||||
|
||||
#include <memory> |
||||
#include <type_traits> |
||||
#include <typeinfo> |
||||
#include <utility> |
||||
|
||||
#include "opencv2/gapi/util/throw.hpp" |
||||
|
||||
#if defined(_MSC_VER) |
||||
// disable MSVC warning on "multiple copy constructors specified"
|
||||
# pragma warning(disable: 4521) |
||||
#endif |
||||
|
||||
namespace cv |
||||
{ |
||||
|
||||
namespace internal |
||||
{ |
||||
template <class T, class Source> |
||||
T down_cast(Source operand) |
||||
{ |
||||
#if defined(__GXX_RTTI) || defined(_CPPRTTI) |
||||
return dynamic_cast<T>(operand); |
||||
#else |
||||
#warning used static cast instead of dynamic because RTTI is disabled |
||||
return static_cast<T>(operand); |
||||
#endif |
||||
} |
||||
} |
||||
|
||||
namespace util |
||||
{ |
||||
class bad_any_cast : public std::bad_cast |
||||
{ |
||||
public: |
||||
virtual const char* what() const noexcept override |
||||
{ |
||||
return "Bad any cast"; |
||||
} |
||||
}; |
||||
|
||||
//modeled against C++17 std::any
|
||||
|
||||
class any |
||||
{ |
||||
private: |
||||
struct holder; |
||||
using holder_ptr = std::unique_ptr<holder>; |
||||
struct holder |
||||
{ |
||||
virtual holder_ptr clone() = 0; |
||||
virtual ~holder() = default; |
||||
}; |
||||
|
||||
template <typename value_t> |
||||
struct holder_impl : holder |
||||
{ |
||||
value_t v; |
||||
template<typename arg_t> |
||||
holder_impl(arg_t&& a) : v(std::forward<arg_t>(a)) {} |
||||
holder_ptr clone() override { return holder_ptr(new holder_impl (v));} |
||||
}; |
||||
|
||||
holder_ptr hldr; |
||||
public: |
||||
template<class value_t> |
||||
any(value_t&& arg) : hldr(new holder_impl<typename std::decay<value_t>::type>( std::forward<value_t>(arg))) {} |
||||
|
||||
any(any const& src) : hldr( src.hldr ? src.hldr->clone() : nullptr) {} |
||||
//simple hack in order not to write enable_if<not any> for the template constructor
|
||||
any(any & src) : any (const_cast<any const&>(src)) {} |
||||
|
||||
any() = default; |
||||
any(any&& ) = default; |
||||
|
||||
any& operator=(any&&) = default; |
||||
|
||||
any& operator=(any const& src) |
||||
{ |
||||
any copy(src); |
||||
swap(*this, copy); |
||||
return *this; |
||||
} |
||||
|
||||
template<class value_t> |
||||
friend value_t* any_cast(any* operand); |
||||
|
||||
template<class value_t> |
||||
friend const value_t* any_cast(const any* operand); |
||||
|
||||
friend void swap(any & lhs, any& rhs) |
||||
{ |
||||
swap(lhs.hldr, rhs.hldr); |
||||
} |
||||
|
||||
}; |
||||
|
||||
template<class value_t> |
||||
value_t* any_cast(any* operand) |
||||
{ |
||||
auto casted = internal::down_cast<any::holder_impl<typename std::decay<value_t>::type> *>(operand->hldr.get()); |
||||
if (casted){ |
||||
return & (casted->v); |
||||
} |
||||
return nullptr; |
||||
} |
||||
|
||||
template<class value_t> |
||||
const value_t* any_cast(const any* operand) |
||||
{ |
||||
auto casted = internal::down_cast<any::holder_impl<typename std::decay<value_t>::type> *>(operand->hldr.get()); |
||||
if (casted){ |
||||
return & (casted->v); |
||||
} |
||||
return nullptr; |
||||
} |
||||
|
||||
template<class value_t> |
||||
value_t& any_cast(any& operand) |
||||
{ |
||||
auto ptr = any_cast<value_t>(&operand); |
||||
if (ptr) |
||||
{ |
||||
return *ptr; |
||||
} |
||||
|
||||
throw_error(bad_any_cast()); |
||||
} |
||||
|
||||
|
||||
template<class value_t> |
||||
const value_t& any_cast(const any& operand) |
||||
{ |
||||
auto ptr = any_cast<value_t>(&operand); |
||||
if (ptr) |
||||
{ |
||||
return *ptr; |
||||
} |
||||
|
||||
throw_error(bad_any_cast()); |
||||
} |
||||
} // namespace util
|
||||
} // namespace cv
|
||||
|
||||
#if defined(_MSC_VER) |
||||
// Enable "multiple copy constructors specified" back
|
||||
# pragma warning(default: 4521) |
||||
#endif |
||||
|
||||
#endif // OPENCV_GAPI_UTIL_ANY_HPP
|
@ -0,0 +1,21 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_UTIL_COMPILER_HINTS_HPP |
||||
#define OPENCV_GAPI_UTIL_COMPILER_HINTS_HPP |
||||
|
||||
namespace cv |
||||
{ |
||||
namespace util |
||||
{ |
||||
//! Utility template function to prevent "unused" warnings by various compilers.
|
||||
template<typename T> void suppress_unused_warning( const T& ) {} |
||||
} // namespace util
|
||||
} // namespace cv
|
||||
|
||||
#define UNUSED(x) cv::util::suppress_unused_warning(x) |
||||
|
||||
#endif /* OPENCV_GAPI_UTIL_COMPILER_HINTS_HPP */ |
@ -0,0 +1,178 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_UTIL_OPTIONAL_HPP |
||||
#define OPENCV_GAPI_UTIL_OPTIONAL_HPP |
||||
|
||||
#include "opencv2/gapi/util/variant.hpp" |
||||
|
||||
// A poor man's `optional` implementation, incompletely modeled against C++17 spec.
|
||||
namespace cv |
||||
{ |
||||
namespace util |
||||
{ |
||||
class bad_optional_access: public std::exception |
||||
{ |
||||
public: |
||||
virtual const char *what() const noexcept override |
||||
{ |
||||
return "Bad optional access"; |
||||
} |
||||
}; |
||||
|
||||
// TODO: nullopt_t
|
||||
|
||||
// Interface ///////////////////////////////////////////////////////////////
|
||||
template<typename T> class optional |
||||
{ |
||||
public: |
||||
// Constructors
|
||||
// NB.: there were issues with Clang 3.8 when =default() was used
|
||||
// instead {}
|
||||
optional() {}; |
||||
optional(const optional&) = default; |
||||
explicit optional(T &&value) noexcept; |
||||
explicit optional(const T &value) noexcept; |
||||
optional(optional &&) noexcept; |
||||
// TODO: optional(nullopt_t) noexcept;
|
||||
// TODO: optional(const optional<U> &)
|
||||
// TODO: optional(optional<U> &&)
|
||||
// TODO: optional(Args&&...)
|
||||
// TODO: optional(initializer_list<U>)
|
||||
// TODO: optional(U&& value);
|
||||
|
||||
// Assignment
|
||||
optional& operator=(const optional& rhs) = default; |
||||
optional& operator=(optional&& rhs); |
||||
|
||||
// Observers
|
||||
T* operator-> (); |
||||
const T* operator-> () const; |
||||
T& operator* (); |
||||
const T& operator* () const; |
||||
// TODO: && versions
|
||||
|
||||
operator bool() const noexcept; |
||||
bool has_value() const noexcept; |
||||
|
||||
T& value(); |
||||
const T& value() const; |
||||
// TODO: && versions
|
||||
|
||||
template<class U> |
||||
T value_or(U &&default_value) const; |
||||
|
||||
void swap(optional &other) noexcept; |
||||
void reset() noexcept; |
||||
// TODO: emplace
|
||||
|
||||
// TODO: operator==, !=, <, <=, >, >=
|
||||
|
||||
private: |
||||
struct nothing {}; |
||||
util::variant<nothing, T> m_holder; |
||||
}; |
||||
|
||||
template<class T> |
||||
optional<typename std::decay<T>::type> make_optional(T&& value); |
||||
|
||||
// TODO: Args... and initializer_list versions
|
||||
|
||||
// Implementation //////////////////////////////////////////////////////////
|
||||
template<class T> optional<T>::optional(T &&v) noexcept |
||||
: m_holder(v) |
||||
{ |
||||
} |
||||
|
||||
template<class T> optional<T>::optional(const T &v) noexcept |
||||
: m_holder(v) |
||||
{ |
||||
} |
||||
|
||||
template<class T> optional<T>::optional(optional&& rhs) noexcept |
||||
: m_holder(std::move(rhs.m_holder)) |
||||
{ |
||||
rhs.reset(); |
||||
} |
||||
|
||||
template<class T> optional<T>& optional<T>::operator=(optional&& rhs) |
||||
{ |
||||
m_holder = std::move(rhs.m_holder); |
||||
rhs.reset(); |
||||
return *this; |
||||
} |
||||
|
||||
template<class T> T* optional<T>::operator-> () |
||||
{ |
||||
return & *(*this); |
||||
} |
||||
|
||||
template<class T> const T* optional<T>::operator-> () const |
||||
{ |
||||
return & *(*this); |
||||
} |
||||
|
||||
template<class T> T& optional<T>::operator* () |
||||
{ |
||||
return this->value(); |
||||
} |
||||
|
||||
template<class T> const T& optional<T>::operator* () const |
||||
{ |
||||
return this->value(); |
||||
} |
||||
|
||||
template<class T> optional<T>::operator bool() const noexcept |
||||
{ |
||||
return this->has_value(); |
||||
} |
||||
|
||||
template<class T> bool optional<T>::has_value() const noexcept |
||||
{ |
||||
return util::holds_alternative<T>(m_holder); |
||||
} |
||||
|
||||
template<class T> T& optional<T>::value() |
||||
{ |
||||
if (!this->has_value()) |
||||
throw_error(bad_optional_access()); |
||||
return util::get<T>(m_holder); |
||||
} |
||||
|
||||
template<class T> const T& optional<T>::value() const |
||||
{ |
||||
if (!this->has_value()) |
||||
throw_error(bad_optional_access()); |
||||
return util::get<T>(m_holder); |
||||
} |
||||
|
||||
template<class T> |
||||
template<class U> T optional<T>::value_or(U &&default_value) const |
||||
{ |
||||
return (this->has_value() ? this->value() : T(default_value)); |
||||
} |
||||
|
||||
template<class T> void optional<T>::swap(optional<T> &other) noexcept |
||||
{ |
||||
m_holder.swap(other.m_holder); |
||||
} |
||||
|
||||
template<class T> void optional<T>::reset() noexcept |
||||
{ |
||||
if (this->has_value()) |
||||
m_holder = nothing{}; |
||||
} |
||||
|
||||
template<class T> |
||||
optional<typename std::decay<T>::type> make_optional(T&& value) |
||||
{ |
||||
return optional<typename std::decay<T>::type>(std::forward<T>(value)); |
||||
} |
||||
} // namespace util
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_UTIL_OPTIONAL_HPP
|
@ -0,0 +1,36 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_UTIL_THROW_HPP |
||||
#define OPENCV_GAPI_UTIL_THROW_HPP |
||||
|
||||
#include <utility> // std::forward |
||||
|
||||
#if !defined(__EXCEPTIONS) |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#endif |
||||
|
||||
namespace cv |
||||
{ |
||||
namespace util |
||||
{ |
||||
template <class ExceptionType> |
||||
[[noreturn]] void throw_error(ExceptionType &&e) |
||||
{ |
||||
#if defined(__EXCEPTIONS) || defined(_CPPUNWIND) |
||||
throw std::forward<ExceptionType>(e); |
||||
#else |
||||
fprintf(stderr, "An exception thrown! %s\n" , e.what()); |
||||
fflush(stderr); |
||||
abort(); |
||||
#endif |
||||
} |
||||
} // namespace util
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_UTIL_THROW_HPP
|
@ -0,0 +1,92 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_UTIL_HPP |
||||
#define OPENCV_GAPI_UTIL_HPP |
||||
|
||||
#include <utility> // std::tuple |
||||
|
||||
// \cond HIDDEN_SYMBOLS
|
||||
// This header file contains some generic utility functions which are
|
||||
// used in other G-API Public API headers.
|
||||
//
|
||||
// PLEASE don't put any stuff here if it is NOT used in public API headers!
|
||||
|
||||
namespace cv |
||||
{ |
||||
namespace detail |
||||
{ |
||||
// Recursive integer sequence type, useful for enumerating elements of
|
||||
// template parameter packs.
|
||||
template<int... I> struct Seq { using next = Seq<I..., sizeof...(I)>; }; |
||||
template<int Sz> struct MkSeq { using type = typename MkSeq<Sz-1>::type::next; }; |
||||
template<> struct MkSeq<0>{ using type = Seq<>; }; |
||||
|
||||
// Checks if elements of variadic template satisfy the given Predicate.
|
||||
// Implemented via tuple, with an interface to accept plain type lists
|
||||
template<template<class> class, typename, typename...> struct all_satisfy; |
||||
|
||||
template<template<class> class F, typename T, typename... Ts> |
||||
struct all_satisfy<F, std::tuple<T, Ts...> > |
||||
{ |
||||
static const constexpr bool value = F<T>::value |
||||
&& all_satisfy<F, std::tuple<Ts...> >::value; |
||||
}; |
||||
template<template<class> class F, typename T> |
||||
struct all_satisfy<F, std::tuple<T> > |
||||
{ |
||||
static const constexpr bool value = F<T>::value; |
||||
}; |
||||
|
||||
template<template<class> class F, typename T, typename... Ts> |
||||
struct all_satisfy: public all_satisfy<F, std::tuple<T, Ts...> > {}; |
||||
|
||||
// Permute given tuple type C with given integer sequence II
|
||||
// Sequence may be less than tuple C size.
|
||||
template<class, class> struct permute_tuple; |
||||
|
||||
template<class C, int... IIs> |
||||
struct permute_tuple<C, Seq<IIs...> > |
||||
{ |
||||
using type = std::tuple< typename std::tuple_element<IIs, C>::type... >; |
||||
}; |
||||
|
||||
// Given T..., generates a type sequence of sizeof...(T)-1 elements
|
||||
// which is T... without its last element
|
||||
// Implemented via tuple, with an interface to accept plain type lists
|
||||
template<typename T, typename... Ts> struct all_but_last; |
||||
|
||||
template<typename T, typename... Ts> |
||||
struct all_but_last<std::tuple<T, Ts...> > |
||||
{ |
||||
using C = std::tuple<T, Ts...>; |
||||
using S = typename MkSeq<std::tuple_size<C>::value - 1>::type; |
||||
using type = typename permute_tuple<C, S>::type; |
||||
}; |
||||
|
||||
template<typename T, typename... Ts> |
||||
struct all_but_last: public all_but_last<std::tuple<T, Ts...> > {}; |
||||
|
||||
template<typename... Ts> |
||||
using all_but_last_t = typename all_but_last<Ts...>::type; |
||||
|
||||
// NB.: This is here because there's no constexpr std::max in C++11
|
||||
template<std::size_t S0, std::size_t... SS> struct max_of_t |
||||
{ |
||||
static constexpr const std::size_t rest = max_of_t<SS...>::value; |
||||
static constexpr const std::size_t value = rest > S0 ? rest : S0; |
||||
}; |
||||
template<std::size_t S> struct max_of_t<S> |
||||
{ |
||||
static constexpr const std::size_t value = S; |
||||
}; |
||||
} // namespace detail
|
||||
} // namespace cv
|
||||
|
||||
// \endcond
|
||||
|
||||
#endif // OPENCV_GAPI_UTIL_HPP
|
@ -0,0 +1,377 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_UTIL_VARIANT_HPP |
||||
#define OPENCV_GAPI_UTIL_VARIANT_HPP |
||||
|
||||
#include <array> |
||||
#include <type_traits> |
||||
|
||||
#include "opencv2/gapi/util/throw.hpp" |
||||
#include "opencv2/gapi/util/util.hpp" // max_of_t |
||||
|
||||
// A poor man's `variant` implementation, incompletely modeled against C++17 spec.
|
||||
namespace cv |
||||
{ |
||||
namespace util |
||||
{ |
||||
namespace detail |
||||
{ |
||||
template<std::size_t I, typename Target, typename First, typename... Remaining> |
||||
struct type_list_index_helper |
||||
{ |
||||
static const constexpr bool is_same = std::is_same<Target, First>::value; |
||||
static const constexpr std::size_t value = |
||||
std::conditional<is_same, std::integral_constant<std::size_t, I>, type_list_index_helper<I + 1, Target, Remaining...>>::type::value; |
||||
}; |
||||
|
||||
template<std::size_t I, typename Target, typename First> |
||||
struct type_list_index_helper<I, Target, First> |
||||
{ |
||||
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> |
||||
struct type_list_index |
||||
{ |
||||
static const constexpr std::size_t value = detail::type_list_index_helper<0, Target, Types...>::value; |
||||
}; |
||||
|
||||
class bad_variant_access: public std::exception |
||||
{ |
||||
public: |
||||
virtual const char *what() const noexcept override |
||||
{ |
||||
return "Bad variant access"; |
||||
} |
||||
}; |
||||
|
||||
// Interface ///////////////////////////////////////////////////////////////
|
||||
struct monostate {}; |
||||
inline bool operator==(const util::monostate&, const util::monostate&) |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
template<typename... Ts> // FIXME: no references, arrays, and void
|
||||
class variant |
||||
{ |
||||
// FIXME: Replace with std::aligned_union after gcc4.8 support is dropped
|
||||
static constexpr const std::size_t S = cv::detail::max_of_t<sizeof(Ts)...>::value; |
||||
static constexpr const std::size_t A = cv::detail::max_of_t<alignof(Ts)...>::value; |
||||
using Memory = typename std::aligned_storage<S, A>::type[1]; |
||||
|
||||
template<typename T> struct cctr_h { |
||||
static void help(Memory memory, const Memory from) { |
||||
new (memory) T(*reinterpret_cast<const T*>(from)); |
||||
} |
||||
}; |
||||
|
||||
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))); |
||||
} |
||||
}; |
||||
|
||||
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)); |
||||
} |
||||
}; |
||||
|
||||
template<typename T> struct swap_h { |
||||
static void help(Memory to, Memory from) { |
||||
std::swap(*reinterpret_cast<T*>(to), *reinterpret_cast<T*>(from)); |
||||
} |
||||
}; |
||||
|
||||
template<typename T> struct dtor_h { |
||||
static void help(Memory memory) { |
||||
(void) memory; // MSCV warning
|
||||
reinterpret_cast<T*>(memory)->~T(); |
||||
} |
||||
}; |
||||
|
||||
template<typename T> struct equal_h { |
||||
static bool help(const Memory lhs, const Memory rhs) { |
||||
const T& t_lhs = *reinterpret_cast<const T*>(lhs); |
||||
const T& t_rhs = *reinterpret_cast<const T*>(rhs); |
||||
return t_lhs == t_rhs; |
||||
} |
||||
}; |
||||
|
||||
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 (*Swap) (Memory, Memory); // Swap
|
||||
typedef void (*Dtor) (Memory); // Destructor
|
||||
|
||||
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)...}};} |
||||
|
||||
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... Us> friend bool operator==(const variant<Us...> &lhs, |
||||
const variant<Us...> &rhs); |
||||
Memory memory; |
||||
|
||||
public: |
||||
// Constructors
|
||||
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
|
||||
// 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); |
||||
// template<class T, class... Args> explicit variant(Args&&... args);
|
||||
// FIXME: other constructors
|
||||
|
||||
// Destructor
|
||||
~variant(); |
||||
|
||||
// Assignment
|
||||
variant& operator=(const variant& rhs); |
||||
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; |
||||
|
||||
// Observers
|
||||
std::size_t index() const noexcept; |
||||
// FIXME: valueless_by_exception()
|
||||
|
||||
// Modifiers
|
||||
// FIXME: emplace()
|
||||
void swap(variant &rhs) noexcept; |
||||
|
||||
// Non-C++17x!
|
||||
template<typename T> static constexpr std::size_t index_of(); |
||||
}; |
||||
|
||||
// FIMXE: visit
|
||||
|
||||
template<typename T, typename... Types> |
||||
T& get(util::variant<Types...> &v); |
||||
|
||||
template<typename T, typename... Types> |
||||
const T& get(const util::variant<Types...> &v); |
||||
|
||||
template<typename T, typename... Types> |
||||
bool holds_alternative(const util::variant<Types...> &v) noexcept; |
||||
|
||||
// FIXME: T&&, const TT&& versions.
|
||||
|
||||
// Implementation //////////////////////////////////////////////////////////
|
||||
template<typename... Ts> |
||||
variant<Ts...>::variant() noexcept |
||||
{ |
||||
typedef typename std::tuple_element<0, std::tuple<Ts...> >::type TFirst; |
||||
new (memory) TFirst(); |
||||
} |
||||
|
||||
template<typename... Ts> |
||||
variant<Ts...>::variant(const variant &other) |
||||
: m_index(other.m_index) |
||||
{ |
||||
(cctrs()[m_index])(memory, other.memory); |
||||
} |
||||
|
||||
template<typename... Ts> |
||||
variant<Ts...>::variant(variant &&other) noexcept |
||||
: m_index(other.m_index) |
||||
{ |
||||
(mctrs()[m_index])(memory, other.memory); |
||||
} |
||||
|
||||
template<typename... Ts> |
||||
template<class T> |
||||
variant<Ts...>::variant(const T& t) |
||||
: m_index(util::type_list_index<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); |
||||
} |
||||
|
||||
template<typename... Ts> |
||||
variant<Ts...>::~variant() |
||||
{ |
||||
(dtors()[m_index])(memory); |
||||
} |
||||
|
||||
template<typename... Ts> |
||||
variant<Ts...>& variant<Ts...>::operator=(const variant<Ts...> &rhs) |
||||
{ |
||||
if (m_index != rhs.m_index) |
||||
{ |
||||
(dtors()[ m_index])(memory); |
||||
(cctrs()[rhs.m_index])(memory, rhs.memory); |
||||
m_index = rhs.m_index; |
||||
} |
||||
else |
||||
{ |
||||
(cpyrs()[rhs.m_index])(memory, rhs.memory); |
||||
} |
||||
return *this; |
||||
} |
||||
|
||||
template<typename... Ts> |
||||
variant<Ts...>& variant<Ts...>::operator=(variant<Ts...> &&rhs) noexcept |
||||
{ |
||||
if (m_index != rhs.m_index) |
||||
{ |
||||
(dtors()[ m_index])(memory); |
||||
(mctrs()[rhs.m_index])(memory, rhs.memory); |
||||
m_index = rhs.m_index; |
||||
} |
||||
else |
||||
{ |
||||
(mvers()[rhs.m_index])(memory, rhs.memory); |
||||
} |
||||
return *this; |
||||
} |
||||
|
||||
template<typename... Ts> |
||||
template<class T> typename detail::are_different<variant<Ts...>, T, variant<Ts...>&> |
||||
::type variant<Ts...>::operator=(T&& t) noexcept |
||||
{ |
||||
// FIXME: No version with implicit type conversion available!
|
||||
static const constexpr std::size_t t_index = |
||||
util::type_list_index<T, Ts...>::value; |
||||
|
||||
if (t_index == m_index) |
||||
{ |
||||
util::get<T>(*this) = std::move(t); |
||||
return *this; |
||||
} |
||||
else return (*this = variant(std::move(t))); |
||||
} |
||||
|
||||
template<typename... Ts> |
||||
std::size_t util::variant<Ts...>::index() const noexcept |
||||
{ |
||||
return m_index; |
||||
} |
||||
|
||||
template<typename... Ts> |
||||
void variant<Ts...>::swap(variant<Ts...> &rhs) noexcept |
||||
{ |
||||
if (m_index == rhs.index()) |
||||
{ |
||||
(swprs()[m_index](memory, rhs.memory)); |
||||
} |
||||
else |
||||
{ |
||||
variant<Ts...> tmp(std::move(*this)); |
||||
*this = std::move(rhs); |
||||
rhs = std::move(tmp); |
||||
} |
||||
} |
||||
|
||||
template<typename... Ts> |
||||
template<typename T> |
||||
constexpr std::size_t variant<Ts...>::index_of() |
||||
{ |
||||
return util::type_list_index<T, Ts...>::value; // FIXME: tests!
|
||||
} |
||||
|
||||
template<typename T, typename... Types> |
||||
T& get(util::variant<Types...> &v) |
||||
{ |
||||
const constexpr std::size_t t_index = |
||||
util::type_list_index<T, Types...>::value; |
||||
|
||||
if (v.index() == t_index) |
||||
return reinterpret_cast<T&>(v.memory); |
||||
else |
||||
throw_error(bad_variant_access()); |
||||
} |
||||
|
||||
template<typename T, typename... Types> |
||||
const T& get(const util::variant<Types...> &v) |
||||
{ |
||||
const constexpr std::size_t t_index = |
||||
util::type_list_index<T, Types...>::value; |
||||
|
||||
if (v.index() == t_index) |
||||
return reinterpret_cast<const T&>(v.memory); |
||||
else |
||||
throw_error(bad_variant_access()); |
||||
} |
||||
|
||||
template<typename T, typename... Types> |
||||
bool holds_alternative(const util::variant<Types...> &v) noexcept |
||||
{ |
||||
return v.index() == util::variant<Types...>::template index_of<T>(); |
||||
} |
||||
|
||||
template<typename... Us> bool operator==(const variant<Us...> &lhs, |
||||
const variant<Us...> &rhs) |
||||
{ |
||||
using V = variant<Us...>; |
||||
|
||||
// Instantiate table only here since it requires operator== for <Us...>
|
||||
// <Us...> should have operator== only if this one is used, not in general
|
||||
static const std::array<typename V::Equal, sizeof...(Us)> eqs = { |
||||
{(&V::template equal_h<Us>::help)...} |
||||
}; |
||||
if (lhs.index() != rhs.index()) |
||||
return false; |
||||
return (eqs[lhs.index()])(lhs.memory, rhs.memory); |
||||
} |
||||
|
||||
template<typename... Us> bool operator!=(const variant<Us...> &lhs, |
||||
const variant<Us...> &rhs) |
||||
{ |
||||
return !(lhs == rhs); |
||||
} |
||||
} // namespace cv
|
||||
} // namespace util
|
||||
|
||||
#endif // OPENCV_GAPI_UTIL_VARIANT_HPP
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,882 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include "../../test/common/gapi_tests_common.hpp" |
||||
#include "opencv2/gapi/imgproc.hpp" |
||||
|
||||
namespace opencv_test |
||||
{ |
||||
|
||||
using namespace perf; |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class SepFilterPerfTest : public TestPerfParams<tuple<MatType, int, cv::Size, int>> {}; |
||||
PERF_TEST_P_(SepFilterPerfTest, TestPerformance) |
||||
{ |
||||
MatType type = 0; |
||||
int kernSize = 0, dtype = 0; |
||||
cv::Size sz; |
||||
std::tie(type, kernSize, sz, dtype) = GetParam(); |
||||
|
||||
cv::Mat kernelX(kernSize, 1, CV_32F); |
||||
cv::Mat kernelY(kernSize, 1, CV_32F); |
||||
randu(kernelX, -1, 1); |
||||
randu(kernelY, -1, 1); |
||||
initMatsRandN(type, sz, dtype, false); |
||||
|
||||
cv::Point anchor = cv::Point(-1, -1); |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::sepFilter2D(in_mat1, out_mat_ocv, dtype, kernelX, kernelY ); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::sepFilter(in, dtype, kernelX, kernelY, anchor, cv::Scalar() ); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class Filter2DPerfTest : public TestPerfParams<tuple<MatType,int,cv::Size,int,int>> {}; |
||||
PERF_TEST_P_(Filter2DPerfTest, TestPerformance) |
||||
{ |
||||
MatType type = 0; |
||||
int kernSize = 0, borderType = 0, dtype = 0; |
||||
cv::Size sz; |
||||
std::tie(type, kernSize, sz, borderType, dtype) = GetParam(); |
||||
|
||||
initMatsRandN(type, sz, dtype, false); |
||||
|
||||
cv::Point anchor = {-1, -1}; |
||||
double delta = 0; |
||||
|
||||
cv::Mat kernel = cv::Mat(kernSize, kernSize, CV_32FC1 ); |
||||
cv::Scalar kernMean = cv::Scalar::all(1.0); |
||||
cv::Scalar kernStddev = cv::Scalar::all(2.0/3); |
||||
randn(kernel, kernMean, kernStddev); |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::filter2D(in_mat1, out_mat_ocv, dtype, kernel, anchor, delta, borderType); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::filter2D(in, dtype, kernel, anchor, delta, borderType); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
|
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class BoxFilterPerfTest : public TestPerfParams<tuple<MatType,int,cv::Size,int,int,double>> {}; |
||||
PERF_TEST_P_(BoxFilterPerfTest, TestPerformance) |
||||
{ |
||||
MatType type = 0; |
||||
int filterSize = 0, borderType = 0, dtype = 0; |
||||
cv::Size sz; |
||||
double tolerance = 0.0; |
||||
std::tie(type, filterSize, sz, borderType, dtype, tolerance) = GetParam(); |
||||
|
||||
initMatsRandN(type, sz, dtype, false); |
||||
|
||||
cv::Point anchor = {-1, -1}; |
||||
bool normalize = true; |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::boxFilter(in_mat1, out_mat_ocv, dtype, cv::Size(filterSize, filterSize), anchor, normalize, borderType); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::boxFilter(in, dtype, cv::Size(filterSize, filterSize), anchor, normalize, borderType); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::Mat absDiff; |
||||
cv::absdiff(out_mat_gapi, out_mat_ocv, absDiff); |
||||
EXPECT_EQ(0, cv::countNonZero(absDiff > tolerance)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
|
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class BlurPerfTest : public TestPerfParams<tuple<MatType,int,cv::Size,int,double>> {}; |
||||
PERF_TEST_P_(BlurPerfTest, TestPerformance) |
||||
{ |
||||
MatType type = 0; |
||||
int filterSize = 0, borderType = 0; |
||||
cv::Size sz; |
||||
double tolerance = 0.0; |
||||
std::tie(type, filterSize, sz, borderType, tolerance) = GetParam(); |
||||
|
||||
initMatsRandN(type, sz, type, false); |
||||
|
||||
cv::Point anchor = {-1, -1}; |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::blur(in_mat1, out_mat_ocv, cv::Size(filterSize, filterSize), anchor, borderType); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::blur(in, cv::Size(filterSize, filterSize), anchor, borderType); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::Mat absDiff; |
||||
cv::absdiff(out_mat_gapi, out_mat_ocv, absDiff); |
||||
EXPECT_EQ(0, cv::countNonZero(absDiff > tolerance)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
|
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class GaussianBlurPerfTest : public TestPerfParams<tuple<MatType, int, cv::Size>> {}; |
||||
PERF_TEST_P_(GaussianBlurPerfTest, TestPerformance) |
||||
{ |
||||
MatType type = 0; |
||||
int kernSize = 0; |
||||
cv::Size sz; |
||||
std::tie(type, kernSize, sz) = GetParam(); |
||||
|
||||
cv::Size kSize = cv::Size(kernSize, kernSize); |
||||
auto& rng = cv::theRNG(); |
||||
double sigmaX = rng(); |
||||
initMatsRandN(type, sz, type, false); |
||||
|
||||
// OpenCV code ///////////////////////////////////////////////////////////
|
||||
cv::GaussianBlur(in_mat1, out_mat_ocv, kSize, sigmaX); |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::gaussianBlur(in, kSize, sigmaX); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison ////////////////////////////////////////////////////////////
|
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class MedianBlurPerfTest : public TestPerfParams<tuple<MatType,int,cv::Size>> {}; |
||||
PERF_TEST_P_(MedianBlurPerfTest, TestPerformance) |
||||
{ |
||||
MatType type = 0; |
||||
int kernSize = 0; |
||||
cv::Size sz; |
||||
std::tie(type, kernSize, sz) = GetParam(); |
||||
|
||||
initMatsRandN(type, sz, type, false); |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::medianBlur(in_mat1, out_mat_ocv, kernSize); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::medianBlur(in, kernSize); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
|
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ErodePerfTest : public TestPerfParams<tuple<MatType,int,cv::Size,int>> {}; |
||||
PERF_TEST_P_(ErodePerfTest, TestPerformance) |
||||
{ |
||||
MatType type = 0; |
||||
int kernSize = 0, kernType = 0; |
||||
cv::Size sz; |
||||
std::tie(type, kernSize, sz, kernType) = GetParam(); |
||||
|
||||
initMatsRandN(type, sz, type, false); |
||||
|
||||
cv::Mat kernel = cv::getStructuringElement(kernType, cv::Size(kernSize, kernSize)); |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::erode(in_mat1, out_mat_ocv, kernel); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::erode(in, kernel); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
|
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class Erode3x3PerfTest : public TestPerfParams<tuple<MatType,cv::Size,int>> {}; |
||||
PERF_TEST_P_(Erode3x3PerfTest, TestPerformance) |
||||
{ |
||||
MatType type = 0; |
||||
int numIters = 0; |
||||
cv::Size sz; |
||||
std::tie(type, sz, numIters) = GetParam(); |
||||
|
||||
initMatsRandN(type, sz, type, false); |
||||
|
||||
cv::Mat kernel = cv::getStructuringElement(cv::MorphShapes::MORPH_RECT, cv::Size(3, 3)); |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::erode(in_mat1, out_mat_ocv, kernel, cv::Point(-1, -1), numIters); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::erode3x3(in, numIters); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
|
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class DilatePerfTest : public TestPerfParams<tuple<MatType,int,cv::Size,int>> {}; |
||||
PERF_TEST_P_(DilatePerfTest, TestPerformance) |
||||
{ |
||||
MatType type = 0; |
||||
int kernSize = 0, kernType = 0; |
||||
cv::Size sz; |
||||
std::tie(type, kernSize, sz, kernType) = GetParam(); |
||||
|
||||
initMatsRandN(type, sz, type, false); |
||||
|
||||
cv::Mat kernel = cv::getStructuringElement(kernType, cv::Size(kernSize, kernSize)); |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::dilate(in_mat1, out_mat_ocv, kernel); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::dilate(in, kernel); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
|
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class Dilate3x3PerfTest : public TestPerfParams<tuple<MatType,cv::Size,int>> {}; |
||||
PERF_TEST_P_(Dilate3x3PerfTest, TestPerformance) |
||||
{ |
||||
MatType type = 0; |
||||
int numIters = 0; |
||||
cv::Size sz; |
||||
std::tie(type, sz, numIters) = GetParam(); |
||||
|
||||
initMatsRandN(type, sz, type, false); |
||||
|
||||
cv::Mat kernel = cv::getStructuringElement(cv::MorphShapes::MORPH_RECT, cv::Size(3, 3)); |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::dilate(in_mat1, out_mat_ocv, kernel, cv::Point(-1,-1), numIters); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::dilate3x3(in, numIters); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
|
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class SobelPerfTest : public TestPerfParams<tuple<MatType,int,cv::Size,int,int,int>> {}; |
||||
PERF_TEST_P_(SobelPerfTest, TestPerformance) |
||||
{ |
||||
MatType type = 0; |
||||
int kernSize = 0, dtype = 0, dx = 0, dy = 0; |
||||
cv::Size sz; |
||||
std::tie(type, kernSize, sz, dtype, dx, dy) = GetParam(); |
||||
|
||||
initMatsRandN(type, sz, dtype, false); |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::Sobel(in_mat1, out_mat_ocv, dtype, dx, dy, kernSize); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::sobel(in, dtype, dx, dy, kernSize ); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
|
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class CannyPerfTest : public TestPerfParams<tuple<MatType,cv::Size,double,double,int,bool>> {}; |
||||
PERF_TEST_P_(CannyPerfTest, TestPerformance) |
||||
{ |
||||
MatType type; |
||||
int apSize = 0; |
||||
double thrLow = 0.0, thrUp = 0.0; |
||||
cv::Size sz; |
||||
bool l2gr = false; |
||||
std::tie(type, sz, thrLow, thrUp, apSize, l2gr) = GetParam(); |
||||
|
||||
initMatsRandN(type, sz, CV_8UC1, false); |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::Canny(in_mat1, out_mat_ocv, thrLow, thrUp, apSize, l2gr); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::Canny(in, thrLow, thrUp, apSize, l2gr); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
|
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class EqHistPerfTest : public TestPerfParams<cv::Size> {}; |
||||
PERF_TEST_P_(EqHistPerfTest, TestPerformance) |
||||
{ |
||||
cv::Size sz = GetParam(); |
||||
|
||||
initMatsRandN(CV_8UC1, sz, CV_8UC1, false); |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::equalizeHist(in_mat1, out_mat_ocv); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::equalizeHist(in); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
|
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class RGB2GrayPerfTest : public TestPerfParams<cv::Size> {}; |
||||
PERF_TEST_P_(RGB2GrayPerfTest, TestPerformance) |
||||
{ |
||||
cv::Size sz = GetParam(); |
||||
|
||||
initMatsRandN(CV_8UC3, sz, CV_8UC1, false); |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_RGB2GRAY); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::RGB2Gray(in); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
|
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class BGR2GrayPerfTest : public TestPerfParams<cv::Size> {}; |
||||
PERF_TEST_P_(BGR2GrayPerfTest, TestPerformance) |
||||
{ |
||||
cv::Size sz = GetParam(); |
||||
|
||||
initMatsRandN(CV_8UC3, sz, CV_8UC1, false); |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_BGR2GRAY); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::BGR2Gray(in); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
|
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class RGB2YUVPerfTest : public TestPerfParams<cv::Size> {}; |
||||
PERF_TEST_P_(RGB2YUVPerfTest, TestPerformance) |
||||
{ |
||||
cv::Size sz = GetParam(); |
||||
|
||||
initMatsRandN(CV_8UC3, sz, CV_8UC3, false); |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_RGB2YUV); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::RGB2YUV(in); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
|
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class YUV2RGBPerfTest : public TestPerfParams<cv::Size> {}; |
||||
PERF_TEST_P_(YUV2RGBPerfTest, TestPerformance) |
||||
{ |
||||
cv::Size sz = GetParam(); |
||||
|
||||
initMatsRandN(CV_8UC3, sz, CV_8UC3, false); |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_YUV2RGB); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::YUV2RGB(in); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
|
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class RGB2LabPerfTest : public TestPerfParams<cv::Size> {}; |
||||
PERF_TEST_P_(RGB2LabPerfTest, TestPerformance) |
||||
{ |
||||
cv::Size sz = GetParam(); |
||||
|
||||
initMatsRandN(CV_8UC3, sz, CV_8UC3, false); |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_RGB2Lab); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::RGB2Lab(in); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
|
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class BGR2LUVPerfTest : public TestPerfParams<cv::Size> {}; |
||||
PERF_TEST_P_(BGR2LUVPerfTest, TestPerformance) |
||||
{ |
||||
cv::Size sz = GetParam(); |
||||
|
||||
initMatsRandN(CV_8UC3, sz, CV_8UC3, false); |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_BGR2Luv); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::BGR2LUV(in); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
|
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class LUV2BGRPerfTest : public TestPerfParams<cv::Size> {}; |
||||
PERF_TEST_P_(LUV2BGRPerfTest, TestPerformance) |
||||
{ |
||||
cv::Size sz = GetParam(); |
||||
|
||||
initMatsRandN(CV_8UC3, sz, CV_8UC3, false); |
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{ |
||||
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_Luv2BGR); |
||||
} |
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::LUV2BGR(in); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{ |
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
|
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class BGR2YUVPerfTest : public TestPerfParams<cv::Size> {}; |
||||
PERF_TEST_P_(BGR2YUVPerfTest, TestPerformance) |
||||
{ |
||||
cv::Size sz = GetParam(); |
||||
initMatsRandN(CV_8UC3, sz, CV_8UC3, false); |
||||
|
||||
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_BGR2YUV); |
||||
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::BGR2YUV(in); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class YUV2BGRPerfTest : public TestPerfParams<cv::Size> {}; |
||||
PERF_TEST_P_(YUV2BGRPerfTest, TestPerformance) |
||||
{ |
||||
cv::Size sz = GetParam(); |
||||
initMatsRandN(CV_8UC3, sz, CV_8UC3, false); |
||||
|
||||
cv::cvtColor(in_mat1, out_mat_ocv, cv::COLOR_YUV2BGR); |
||||
|
||||
cv::GMat in; |
||||
auto out = cv::gapi::YUV2BGR(in); |
||||
cv::GComputation c(in, out); |
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(in_mat1, out_mat_gapi); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
c.apply(in_mat1, out_mat_gapi); |
||||
} |
||||
|
||||
EXPECT_EQ(0, cv::countNonZero(out_mat_gapi != out_mat_ocv)); |
||||
EXPECT_EQ(out_mat_gapi.size(), sz); |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
} |
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
} |
@ -0,0 +1,219 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include "../common/gapi_core_perf_tests.hpp" |
||||
|
||||
namespace opencv_test |
||||
{ |
||||
|
||||
INSTANTIATE_TEST_CASE_P(AddPerfTestCPU, AddPerfTest, |
||||
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 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(AddCPerfTestCPU, 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 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(SubPerfTestCPU, SubPerfTest, |
||||
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 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(SubCPerfTestCPU, 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 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(SubRCPerfTestCPU, 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 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(MulPerfTestCPU, 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 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(MulDoublePerfTestCPU, 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 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(MulCPerfTestCPU, 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 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(DivPerfTestCPU, DivPerfTest, |
||||
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 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(DivCPerfTestCPU, 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 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(DivRCPerfTestCPU, DivRCPerfTest, |
||||
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 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(MaskPerfTestCPU, MaskPerfTest, |
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1, CV_16UC1, CV_16SC1))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(MeanPerfTestCPU, MeanPerfTest, |
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(Polar2CartPerfTestCPU, Polar2CartPerfTest, Values( szSmall128, szVGA, sz720p, sz1080p )); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(Cart2PolarPerfTestCPU, Cart2PolarPerfTest, Values( szSmall128, szVGA, sz720p, sz1080p )); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(CmpPerfTestCPU, 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 ))); |
||||
|
||||
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 ))); |
||||
|
||||
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))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(BitwiseNotPerfTestCPU, BitwiseNotPerfTest, |
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(SelectPerfTestCPU, SelectPerfTest, |
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(MinPerfTestCPU, MinPerfTest, |
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(MaxPerfTestCPU, MaxPerfTest, |
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(AbsDiffPerfTestCPU, AbsDiffPerfTest, |
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(AbsDiffCPerfTestCPU, AbsDiffCPerfTest, |
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(SumPerfTestCPU, SumPerfTest, |
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(AddWeightedPerfTestCPU, AddWeightedPerfTest, |
||||
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 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(NormPerfTestCPU, NormPerfTest, |
||||
Combine(Values(NORM_INF, NORM_L1, NORM_L2), |
||||
Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(IntegralPerfTestCPU, IntegralPerfTest, |
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1, CV_16UC1, CV_16SC1, CV_32FC1 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(ThresholdPerfTestCPU, 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))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(ThresholdPerfTestCPU, ThresholdOTPerfTest, |
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1 ), |
||||
Values(cv::THRESH_OTSU, cv::THRESH_TRIANGLE))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(InRangePerfTestCPU, InRangePerfTest, |
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(Split3PerfTestCPU, Split3PerfTest, Values( szSmall128, szVGA, sz720p, sz1080p )); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(Split4PerfTestCPU, Split4PerfTest, Values( szSmall128, szVGA, sz720p, sz1080p )); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(Merge3PerfTestCPU, Merge3PerfTest, Values( szSmall128, szVGA, sz720p, sz1080p )); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(Merge4PerfTestCPU, Merge4PerfTest, Values( szSmall128, szVGA, sz720p, sz1080p )); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(RemapPerfTestCPU, RemapPerfTest, |
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(FlipPerfTestCPU, FlipPerfTest, |
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ), |
||||
Values(0,1,-1))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(CropPerfTestCPU, 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)))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(ConcatHorPerfTestCPU, ConcatHorPerfTest, |
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(ConcatHorVecPerfTestCPU, ConcatHorVecPerfTest, |
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(ConcatVertPerfTestCPU, ConcatVertPerfTest, |
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(ConcatVertVecPerfTestCPU, ConcatVertVecPerfTest, |
||||
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ), |
||||
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(LUTPerfTestCPU, LUTPerfTest, |
||||
Combine(Values(CV_8UC1, CV_8UC3), |
||||
Values(CV_8UC1), |
||||
Values( szSmall128, szVGA, sz720p, sz1080p ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(LUTPerfTestCustomCPU, LUTPerfTest, |
||||
Combine(Values(CV_8UC3), |
||||
Values(CV_8UC3), |
||||
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 ))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(ResizePerfTestCPU, ResizePerfTest, |
||||
Combine(Values(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(0.0))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(ResizeFxFyPerfTestCPU, ResizeFxFyPerfTest, |
||||
Combine(Values(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(0.0))); |
||||
} |
@ -0,0 +1,119 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include "../common/gapi_imgproc_perf_tests.hpp" |
||||
|
||||
namespace opencv_test |
||||
{ |
||||
|
||||
INSTANTIATE_TEST_CASE_P(SepFilterPerfTestCPU_8U, SepFilterPerfTest, |
||||
Combine(Values(CV_8UC1, CV_8UC3), |
||||
Values(3), |
||||
Values(szVGA, sz720p, sz1080p), |
||||
Values(-1, CV_16S, CV_32F))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(SepFilterPerfTestCPU_other, SepFilterPerfTest, |
||||
Combine(Values(CV_16UC1, CV_16SC1, CV_32FC1), |
||||
Values(3), |
||||
Values(szVGA, sz720p, sz1080p), |
||||
Values(-1, CV_32F))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(Filter2DPerfTestCPU, Filter2DPerfTest, |
||||
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), |
||||
Values(3, 4, 5, 7), |
||||
Values(szVGA, sz720p, sz1080p), |
||||
Values(cv::BORDER_DEFAULT), |
||||
Values(-1, CV_32F))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(BoxFilterPerfTestCPU, BoxFilterPerfTest, |
||||
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), |
||||
Values(3,5), |
||||
Values(szVGA, sz720p, sz1080p), |
||||
Values(cv::BORDER_DEFAULT), |
||||
Values(-1, CV_32F), |
||||
Values(0.0))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(BlurPerfTestCPU, BlurPerfTest, |
||||
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), |
||||
Values(3, 5), |
||||
Values(szVGA, sz720p, sz1080p), |
||||
Values(cv::BORDER_DEFAULT), |
||||
Values(0.0))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(GaussianBlurPerfTestCPU, GaussianBlurPerfTest, |
||||
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), |
||||
Values(3, 5), |
||||
Values(szVGA, sz720p, sz1080p))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(MedianBlurPerfTestCPU, MedianBlurPerfTest, |
||||
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), |
||||
Values(3, 5), |
||||
Values(szVGA, sz720p, sz1080p))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(ErodePerfTestCPU, ErodePerfTest, |
||||
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), |
||||
Values(3, 5), |
||||
Values(szVGA, sz720p, sz1080p), |
||||
Values(cv::MorphShapes::MORPH_RECT, |
||||
cv::MorphShapes::MORPH_CROSS, |
||||
cv::MorphShapes::MORPH_ELLIPSE))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(Erode3x3PerfTestCPU, Erode3x3PerfTest, |
||||
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), |
||||
Values(szVGA, sz720p, sz1080p), |
||||
Values(1,2,4))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(DilatePerfTestCPU, DilatePerfTest, |
||||
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), |
||||
Values(3, 5), |
||||
Values(szVGA, sz720p, sz1080p), |
||||
Values(cv::MorphShapes::MORPH_RECT, |
||||
cv::MorphShapes::MORPH_CROSS, |
||||
cv::MorphShapes::MORPH_ELLIPSE))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(Dilate3x3PerfTestCPU, Dilate3x3PerfTest, |
||||
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), |
||||
Values(szVGA, sz720p, sz1080p), |
||||
Values(1,2,4))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(SobelPerfTestCPU, SobelPerfTest, |
||||
Combine(Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1), |
||||
Values(3, 5), |
||||
Values(szVGA, sz720p, sz1080p), |
||||
Values(-1, CV_32F), |
||||
Values(0, 1), |
||||
Values(1, 2))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(CannyPerfTestCPU, CannyPerfTest, |
||||
Combine(Values(CV_8UC1, CV_8UC3), |
||||
Values(szVGA, sz720p, sz1080p), |
||||
Values(3.0, 120.0), |
||||
Values(125.0, 240.0), |
||||
Values(3, 5), |
||||
Values(true, false))); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(EqHistPerfTestCPU, EqHistPerfTest, Values(szVGA, sz720p, sz1080p)); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(RGB2GrayPerfTestCPU, RGB2GrayPerfTest, Values(szVGA, sz720p, sz1080p)); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(BGR2GrayPerfTestCPU, BGR2GrayPerfTest, Values(szVGA, sz720p, sz1080p)); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(RGB2YUVPerfTestCPU, RGB2YUVPerfTest, Values(szVGA, sz720p, sz1080p)); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(YUV2RGBPerfTestCPU, YUV2RGBPerfTest, Values(szVGA, sz720p, sz1080p)); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(RGB2LabPerfTestCPU, RGB2LabPerfTest, Values(szVGA, sz720p, sz1080p)); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(BGR2LUVPerfTestCPU, BGR2LUVPerfTest, Values(szVGA, sz720p, sz1080p)); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(LUV2BGRPerfTestCPU, LUV2BGRPerfTest, Values(szVGA, sz720p, sz1080p)); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(BGR2YUVPerfTestCPU, BGR2YUVPerfTest, Values(szVGA, sz720p, sz1080p)); |
||||
|
||||
INSTANTIATE_TEST_CASE_P(YUV2BGRPerfTestCPU, YUV2BGRPerfTest, Values(szVGA, sz720p, sz1080p)); |
||||
|
||||
} |
@ -0,0 +1,46 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include "perf_precomp.hpp" |
||||
#include "../../test/common/gapi_tests_common.hpp" |
||||
#include "../../src/backends/fluid/gfluidcore.hpp" |
||||
|
||||
namespace opencv_test |
||||
{ |
||||
using namespace perf; |
||||
|
||||
class CompilerPerfTest : public TestPerfParams<tuple<cv::Size, MatType>> {}; |
||||
PERF_TEST_P_(CompilerPerfTest, TestPerformance) |
||||
{ |
||||
const auto params = GetParam(); |
||||
Size sz = get<0>(params); |
||||
MatType type = get<1>(params); |
||||
|
||||
initMatsRandU(type, sz, type, false); |
||||
|
||||
// G-API code ////////////////////////////////////////////////////////////
|
||||
cv::GMat in; |
||||
auto splitted = cv::gapi::split3(in); |
||||
auto add1 = cv::gapi::addC({1}, std::get<0>(splitted)); |
||||
auto add2 = cv::gapi::addC({2}, std::get<1>(splitted)); |
||||
auto add3 = cv::gapi::addC({3}, std::get<2>(splitted)); |
||||
auto out = cv::gapi::merge3(add1, add2, add3); |
||||
|
||||
TEST_CYCLE() |
||||
{ |
||||
cv::GComputation c(in, out); |
||||
c.apply(in_mat1, out_mat_gapi, cv::compile_args(cv::gapi::core::fluid::kernels())); |
||||
} |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
} |
||||
|
||||
INSTANTIATE_TEST_CASE_P(CompilerPerfTest, CompilerPerfTest, |
||||
Combine(Values(szSmall128, szVGA, sz720p, sz1080p), |
||||
Values(CV_8UC3))); |
||||
|
||||
} // namespace opencv_test
|
@ -0,0 +1,11 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include "perf_precomp.hpp" |
||||
//#include "../test/test_precomp.hpp"
|
||||
|
||||
CV_PERF_TEST_MAIN(gapi) |
@ -0,0 +1,21 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef __OPENCV_GAPI_PERF_PRECOMP_HPP__ |
||||
#define __OPENCV_GAPI_PERF_PRECOMP_HPP__ |
||||
|
||||
#include <cstdint> |
||||
#include <vector> |
||||
|
||||
#include "opencv2/ts.hpp" |
||||
#include "opencv2/gapi.hpp" |
||||
#include "opencv2/gapi/imgproc.hpp" |
||||
#include "opencv2/gapi/core.hpp" |
||||
#include "opencv2/gapi/cpu/gcpukernel.hpp" |
||||
#include "opencv2/gapi/operators.hpp" |
||||
|
||||
#endif |
@ -0,0 +1 @@ |
||||
This directory contains implementation of G-API frontend (public API classes). |
@ -0,0 +1,43 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include <ade/util/assert.hpp> |
||||
|
||||
#include "api/gapi_priv.hpp" |
||||
#include "api/gnode_priv.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) |
||||
{ |
||||
} |
||||
|
||||
cv::GOrigin::GOrigin(GShape s, cv::gimpl::ConstVal v) |
||||
: shape(s), node(cv::GNode::Const()), value(v), port(INVALID_PORT) |
||||
{ |
||||
} |
||||
|
||||
bool cv::detail::GOriginCmp::operator() (const cv::GOrigin &lhs, |
||||
const cv::GOrigin &rhs) const |
||||
{ |
||||
const GNode::Priv* lhs_p = &lhs.node.priv(); |
||||
const GNode::Priv* rhs_p = &rhs.node.priv(); |
||||
if (lhs_p == rhs_p) |
||||
{ |
||||
if (lhs.port == rhs.port) |
||||
{ |
||||
// A data Origin is uniquely identified by {node/port} pair.
|
||||
// The situation when there're two Origins with same {node/port}s
|
||||
// but with different shapes (data formats) is illegal!
|
||||
GAPI_Assert(lhs.shape == rhs.shape); |
||||
} |
||||
return lhs.port < rhs.port; |
||||
} |
||||
else return lhs_p < rhs_p; |
||||
} |
@ -0,0 +1,77 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_PRIV_HPP |
||||
#define OPENCV_GAPI_PRIV_HPP |
||||
|
||||
#include <set> // set |
||||
#include <map> // map |
||||
#include <limits> |
||||
|
||||
#include "opencv2/gapi/util/variant.hpp" // variant |
||||
#include "opencv2/gapi/garray.hpp" // ConstructVec |
||||
#include "opencv2/gapi/gscalar.hpp" |
||||
#include "opencv2/gapi/gcommon.hpp" |
||||
|
||||
#include "opencv2/gapi/opencv_includes.hpp" |
||||
|
||||
#include "api/gnode.hpp" |
||||
|
||||
namespace cv |
||||
{ |
||||
|
||||
namespace gimpl |
||||
{ |
||||
// Union type for various user-defined type constructors (GArray<T>, etc)
|
||||
// FIXME: Replace construct-only API with a more generic one
|
||||
// (probably with bits of introspection)
|
||||
// Not required for non-user-defined types (GMat, GScalar, etc)
|
||||
using HostCtor = util::variant |
||||
< util::monostate |
||||
, detail::ConstructVec |
||||
>; |
||||
|
||||
using ConstVal = util::variant |
||||
< util::monostate |
||||
, cv::gapi::own::Scalar |
||||
>; |
||||
} |
||||
|
||||
// TODO namespace gimpl?
|
||||
|
||||
struct GOrigin |
||||
{ |
||||
static constexpr const std::size_t INVALID_PORT = std::numeric_limits<std::size_t>::max(); |
||||
|
||||
GOrigin(GShape s, |
||||
const GNode& n, |
||||
std::size_t p = INVALID_PORT, |
||||
const gimpl::HostCtor h = {}); |
||||
GOrigin(GShape s, gimpl::ConstVal value); |
||||
|
||||
const GShape shape; // Shape of a produced object
|
||||
const GNode node; // a GNode which produces an 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?
|
||||
}; |
||||
|
||||
namespace detail |
||||
{ |
||||
struct GOriginCmp |
||||
{ |
||||
bool operator() (const GOrigin &lhs, const GOrigin &rhs) const; |
||||
}; |
||||
} // namespace cv::details
|
||||
|
||||
// TODO introduce a hash on GOrigin and define this via unordered_ ?
|
||||
using GOriginSet = std::set<GOrigin, detail::GOriginCmp>; |
||||
template<typename T> using GOriginMap = std::map<GOrigin, T, detail::GOriginCmp>; |
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_PRIV_HPP
|
@ -0,0 +1,44 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include "opencv2/gapi/garray.hpp" |
||||
#include "api/gapi_priv.hpp" // GOrigin |
||||
|
||||
// cv::detail::GArrayU public implementation ///////////////////////////////////
|
||||
cv::detail::GArrayU::GArrayU() |
||||
: m_priv(new GOrigin(GShape::GARRAY, cv::GNode::Param())) |
||||
{ |
||||
} |
||||
|
||||
cv::detail::GArrayU::GArrayU(const GNode &n, std::size_t out) |
||||
: m_priv(new GOrigin(GShape::GARRAY, n, out)) |
||||
{ |
||||
} |
||||
|
||||
cv::GOrigin& cv::detail::GArrayU::priv() |
||||
{ |
||||
return *m_priv; |
||||
} |
||||
|
||||
const cv::GOrigin& cv::detail::GArrayU::priv() const |
||||
{ |
||||
return *m_priv; |
||||
} |
||||
|
||||
void cv::detail::GArrayU::setConstructFcn(ConstructVec &&cv) |
||||
{ |
||||
m_priv->ctor = std::move(cv); |
||||
} |
||||
|
||||
namespace cv { |
||||
std::ostream& operator<<(std::ostream& os, const cv::GArrayDesc &) |
||||
{ |
||||
// FIXME: add type information here
|
||||
os << "(array)"; |
||||
return os; |
||||
} |
||||
} |
@ -0,0 +1,269 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include <memory> // unique_ptr |
||||
|
||||
#include "opencv2/gapi/gkernel.hpp" |
||||
#include "opencv2/gapi/own/convert.hpp" |
||||
|
||||
#include "api/gbackend_priv.hpp" |
||||
#include "backends/common/gbackend.hpp" |
||||
#include "compiler/gobjref.hpp" |
||||
#include "compiler/gislandmodel.hpp" |
||||
|
||||
|
||||
|
||||
// GBackend private implementation /////////////////////////////////////////////
|
||||
void cv::gapi::GBackend::Priv::unpackKernel(ade::Graph & /*graph */ , |
||||
const ade::NodeHandle & /*op_node*/ , |
||||
const GKernelImpl & /*impl */ ) |
||||
{ |
||||
// Default implementation is still there as Priv
|
||||
// is instantiated by some tests.
|
||||
// Priv is even instantiated as a mock object in a number of tests
|
||||
// as a backend and this method is called for mock objects (doing nothing).
|
||||
// FIXME: add a warning message here
|
||||
// FIXME: Do something with this! Ideally this function should be "=0";
|
||||
} |
||||
|
||||
std::unique_ptr<cv::gimpl::GIslandExecutable> |
||||
cv::gapi::GBackend::Priv::compile(const ade::Graph&, |
||||
const GCompileArgs&, |
||||
const std::vector<ade::NodeHandle> &) const |
||||
{ |
||||
// ...and this method is here for the same reason!
|
||||
GAPI_Assert(false); |
||||
return {}; |
||||
} |
||||
|
||||
void cv::gapi::GBackend::Priv::addBackendPasses(ade::ExecutionEngineSetupContext &) |
||||
{ |
||||
// Do nothing by default, plugins may override this to
|
||||
// add custom (backend-specific) graph transformations
|
||||
} |
||||
|
||||
// GBackend public implementation //////////////////////////////////////////////
|
||||
cv::gapi::GBackend::GBackend() |
||||
{ |
||||
} |
||||
|
||||
cv::gapi::GBackend::GBackend(std::shared_ptr<cv::gapi::GBackend::Priv> &&p) |
||||
: m_priv(std::move(p)) |
||||
{ |
||||
} |
||||
|
||||
cv::gapi::GBackend::Priv& cv::gapi::GBackend::priv() |
||||
{ |
||||
return *m_priv; |
||||
} |
||||
|
||||
const cv::gapi::GBackend::Priv& cv::gapi::GBackend::priv() const |
||||
{ |
||||
return *m_priv; |
||||
} |
||||
|
||||
std::size_t cv::gapi::GBackend::hash() const |
||||
{ |
||||
return std::hash<const cv::gapi::GBackend::Priv*>{}(m_priv.get()); |
||||
} |
||||
|
||||
bool cv::gapi::GBackend::operator== (const cv::gapi::GBackend &rhs) const |
||||
{ |
||||
return m_priv == rhs.m_priv; |
||||
} |
||||
|
||||
// Abstract Host-side data manipulation ////////////////////////////////////////
|
||||
// Reused between CPU backend and more generic GExecutor
|
||||
namespace cv { |
||||
namespace gimpl { |
||||
namespace magazine { |
||||
|
||||
// FIXME implement the below functions with visit()?
|
||||
|
||||
void bindInArg(Mag& mag, const RcDesc &rc, const GRunArg &arg) |
||||
{ |
||||
switch (rc.shape) |
||||
{ |
||||
case GShape::GMAT: |
||||
{ |
||||
auto& mag_mat = mag.template slot<cv::gapi::own::Mat>()[rc.id]; |
||||
switch (arg.index()) |
||||
{ |
||||
case GRunArg::index_of<cv::gapi::own::Mat>() : mag_mat = util::get<cv::gapi::own::Mat>(arg); break; |
||||
case GRunArg::index_of<cv::Mat>() : mag_mat = to_own(util::get<cv::Mat>(arg)); break; |
||||
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?")); |
||||
} |
||||
break; |
||||
} |
||||
|
||||
case GShape::GSCALAR: |
||||
{ |
||||
auto& mag_scalar = mag.template slot<cv::gapi::own::Scalar>()[rc.id]; |
||||
switch (arg.index()) |
||||
{ |
||||
case GRunArg::index_of<cv::gapi::own::Scalar>() : mag_scalar = util::get<cv::gapi::own::Scalar>(arg); break; |
||||
case GRunArg::index_of<cv::Scalar>() : mag_scalar = to_own(util::get<cv::Scalar>(arg)); break; |
||||
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?")); |
||||
} |
||||
break; |
||||
} |
||||
|
||||
case GShape::GARRAY: |
||||
mag.template slot<cv::detail::VectorRef>()[rc.id] = util::get<cv::detail::VectorRef>(arg); |
||||
break; |
||||
|
||||
default: |
||||
util::throw_error(std::logic_error("Unsupported GShape type")); |
||||
} |
||||
} |
||||
|
||||
void bindOutArg(Mag& mag, const RcDesc &rc, const GRunArgP &arg) |
||||
{ |
||||
switch (rc.shape) |
||||
{ |
||||
case GShape::GMAT: |
||||
{ |
||||
auto& mag_mat = mag.template slot<cv::gapi::own::Mat>()[rc.id]; |
||||
switch (arg.index()) |
||||
{ |
||||
case GRunArgP::index_of<cv::gapi::own::Mat*>() : mag_mat = * util::get<cv::gapi::own::Mat*>(arg); break; |
||||
case GRunArgP::index_of<cv::Mat*>() : mag_mat = to_own(* util::get<cv::Mat*>(arg)); break; |
||||
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?")); |
||||
} |
||||
break; |
||||
} |
||||
|
||||
case GShape::GSCALAR: |
||||
{ |
||||
auto& mag_scalar = mag.template slot<cv::gapi::own::Scalar>()[rc.id]; |
||||
switch (arg.index()) |
||||
{ |
||||
case GRunArgP::index_of<cv::gapi::own::Scalar*>() : mag_scalar = *util::get<cv::gapi::own::Scalar*>(arg); break; |
||||
case GRunArgP::index_of<cv::Scalar*>() : mag_scalar = to_own(*util::get<cv::Scalar*>(arg)); break; |
||||
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?")); |
||||
} |
||||
break; |
||||
} |
||||
case GShape::GARRAY: |
||||
mag.template slot<cv::detail::VectorRef>()[rc.id] = util::get<cv::detail::VectorRef>(arg); |
||||
break; |
||||
|
||||
default: |
||||
util::throw_error(std::logic_error("Unsupported GShape type")); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
void resetInternalData(Mag& mag, const Data &d) |
||||
{ |
||||
if (d.storage != Data::Storage::INTERNAL) |
||||
return; |
||||
|
||||
switch (d.shape) |
||||
{ |
||||
case GShape::GARRAY: |
||||
util::get<cv::detail::ConstructVec>(d.ctor) |
||||
(mag.template slot<cv::detail::VectorRef>()[d.rc]); |
||||
break; |
||||
|
||||
case GShape::GSCALAR: |
||||
mag.template slot<cv::gapi::own::Scalar>()[d.rc] = cv::gapi::own::Scalar(); |
||||
break; |
||||
|
||||
case GShape::GMAT: |
||||
// Do nothign here - FIXME unify with initInternalData?
|
||||
break; |
||||
|
||||
default: |
||||
util::throw_error(std::logic_error("Unsupported GShape type")); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
cv::GRunArg getArg(const Mag& mag, const RcDesc &ref) |
||||
{ |
||||
// 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::GSCALAR: return GRunArg(mag.template slot<cv::gapi::own::Scalar>().at(ref.id)); |
||||
// Note: .at() is intentional for GArray as object MUST be already there
|
||||
// (and constructed by either bindIn/Out or resetInternal)
|
||||
case GShape::GARRAY: return GRunArg(mag.template slot<cv::detail::VectorRef>().at(ref.id)); |
||||
default: |
||||
util::throw_error(std::logic_error("Unsupported GShape type")); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
cv::GRunArgP getObjPtr(Mag& mag, const RcDesc &rc) |
||||
{ |
||||
switch (rc.shape) |
||||
{ |
||||
case GShape::GMAT: return GRunArgP(&mag.template slot<cv::gapi::own::Mat>() [rc.id]); |
||||
case GShape::GSCALAR: return GRunArgP(&mag.template slot<cv::gapi::own::Scalar>()[rc.id]); |
||||
// Note: .at() is intentional for GArray as object MUST be already there
|
||||
// (and constructer by either bindIn/Out or resetInternal)
|
||||
case GShape::GARRAY: |
||||
// FIXME(DM): For some absolutely unknown to me reason, move
|
||||
// semantics is involved here without const_cast to const (and
|
||||
// value from map is moved into return value GRunArgP, leaving
|
||||
// map with broken value I've spent few late Friday hours
|
||||
// debugging this!!!1
|
||||
return GRunArgP(const_cast<const Mag&>(mag) |
||||
.template slot<cv::detail::VectorRef>().at(rc.id)); |
||||
default: |
||||
util::throw_error(std::logic_error("Unsupported GShape type")); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
void writeBack(const Mag& mag, const RcDesc &rc, GRunArgP &g_arg) |
||||
{ |
||||
switch (rc.shape) |
||||
{ |
||||
case GShape::GARRAY: |
||||
// Do nothing - should we really do anything here?
|
||||
break; |
||||
|
||||
case GShape::GMAT: |
||||
{ |
||||
//simply check that memory was not reallocated, i.e.
|
||||
//both instances of Mat pointing to the same memory
|
||||
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; |
||||
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?")); |
||||
} |
||||
|
||||
auto& in_mag = mag.template slot<cv::gapi::own::Mat>().at(rc.id); |
||||
GAPI_Assert((out_arg_data == in_mag.data) && " data for output parameters was reallocated ?"); |
||||
break; |
||||
} |
||||
|
||||
case GShape::GSCALAR: |
||||
{ |
||||
switch (g_arg.index()) |
||||
{ |
||||
case GRunArgP::index_of<cv::gapi::own::Scalar*>() : *util::get<cv::gapi::own::Scalar*>(g_arg) = mag.template slot<cv::gapi::own::Scalar>().at(rc.id); break; |
||||
case GRunArgP::index_of<cv::Scalar*>() : *util::get<cv::Scalar*>(g_arg) = cv::gapi::own::to_ocv(mag.template slot<cv::gapi::own::Scalar>().at(rc.id)); break; |
||||
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?")); |
||||
} |
||||
break; |
||||
} |
||||
|
||||
default: |
||||
util::throw_error(std::logic_error("Unsupported GShape type")); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
} // namespace magazine
|
||||
} // namespace gimpl
|
||||
} // namespace cv
|
@ -0,0 +1,53 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef GAPI_API_GBACKEND_PRIV_HPP |
||||
#define GAPI_API_GBACKEND_PRIV_HPP |
||||
|
||||
#include <memory> |
||||
#include <unordered_set> |
||||
|
||||
#include <ade/graph.hpp> |
||||
#include <ade/passes/pass_base.hpp> // passes::PassContext |
||||
#include <ade/execution_engine/execution_engine.hpp> // ..SetupContext |
||||
|
||||
#include "opencv2/gapi/gcommon.hpp" |
||||
#include "opencv2/gapi/gkernel.hpp" |
||||
|
||||
namespace cv |
||||
{ |
||||
namespace gimpl |
||||
{ |
||||
class GBackend; |
||||
class GIslandExecutable; |
||||
} // namespace gimpl
|
||||
} // namespace cv
|
||||
|
||||
// GAPI_EXPORTS is here to make tests build on Windows
|
||||
class GAPI_EXPORTS cv::gapi::GBackend::Priv |
||||
{ |
||||
public: |
||||
using EPtr = std::unique_ptr<cv::gimpl::GIslandExecutable>; |
||||
|
||||
virtual void unpackKernel(ade::Graph &graph, |
||||
const ade::NodeHandle &op_node, |
||||
const GKernelImpl &impl); |
||||
|
||||
// FIXME: since backends are not passed to ADE anymore,
|
||||
// there's no need in having both cv::gimpl::GBackend
|
||||
// and cv::gapi::GBackend - these two things can be unified
|
||||
// NOTE - nodes are guaranteed to be topologically sorted.
|
||||
virtual EPtr compile(const ade::Graph &graph, |
||||
const GCompileArgs &args, |
||||
const std::vector<ade::NodeHandle> &nodes) const; |
||||
|
||||
virtual void addBackendPasses(ade::ExecutionEngineSetupContext &); |
||||
|
||||
virtual ~Priv() = default; |
||||
}; |
||||
|
||||
#endif // GAPI_API_GBACKEND_PRIV_HPP
|
@ -0,0 +1,64 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include <cassert> |
||||
#include "opencv2/gapi/gcall.hpp" |
||||
#include "api/gcall_priv.hpp" |
||||
|
||||
// GCall private implementation ////////////////////////////////////////////////
|
||||
cv::GCall::Priv::Priv(const cv::GKernel &k) |
||||
: m_k(k) |
||||
{ |
||||
} |
||||
|
||||
// GCall public implementation /////////////////////////////////////////////////
|
||||
|
||||
cv::GCall::GCall(const cv::GKernel &k) |
||||
: m_priv(new Priv(k)) |
||||
{ |
||||
// Here we have a reference to GNode,
|
||||
// and GNode has a reference to us. Cycle! Now see destructor.
|
||||
m_priv->m_node = GNode::Call(*this); |
||||
} |
||||
|
||||
cv::GCall::~GCall() |
||||
{ |
||||
// When a GCall object is destroyed (and GCall::Priv is likely still alive,
|
||||
// as there might be other references), reset m_node to break cycle.
|
||||
m_priv->m_node = GNode(); |
||||
} |
||||
|
||||
void cv::GCall::setArgs(std::vector<GArg> &&args) |
||||
{ |
||||
// FIXME: Check if argument number is matching kernel prototype
|
||||
m_priv->m_args = std::move(args); |
||||
} |
||||
|
||||
cv::GMat cv::GCall::yield(int output) |
||||
{ |
||||
return cv::GMat(m_priv->m_node, output); |
||||
} |
||||
|
||||
cv::GScalar cv::GCall::yieldScalar(int output) |
||||
{ |
||||
return cv::GScalar(m_priv->m_node, output); |
||||
} |
||||
|
||||
cv::detail::GArrayU cv::GCall::yieldArray(int output) |
||||
{ |
||||
return cv::detail::GArrayU(m_priv->m_node, output); |
||||
} |
||||
|
||||
cv::GCall::Priv& cv::GCall::priv() |
||||
{ |
||||
return *m_priv; |
||||
} |
||||
|
||||
const cv::GCall::Priv& cv::GCall::priv() const |
||||
{ |
||||
return *m_priv; |
||||
} |
@ -0,0 +1,37 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GCALL_PRIV_HPP |
||||
#define OPENCV_GCALL_PRIV_HPP |
||||
|
||||
#include <vector> |
||||
#include <unordered_map> |
||||
|
||||
#include "opencv2/gapi/garg.hpp" |
||||
#include "opencv2/gapi/gcall.hpp" |
||||
#include "opencv2/gapi/gkernel.hpp" |
||||
|
||||
#include "api/gnode.hpp" |
||||
|
||||
namespace cv { |
||||
|
||||
class GCall::Priv |
||||
{ |
||||
public: |
||||
std::vector<GArg> m_args; |
||||
const GKernel m_k; |
||||
|
||||
// FIXME: Document that there's no recursion here.
|
||||
// TODO: Rename to "constructionNode" or smt to reflect its lifetime
|
||||
GNode m_node; |
||||
|
||||
explicit Priv(const GKernel &k); |
||||
}; |
||||
|
||||
} |
||||
|
||||
#endif // OPENCV_GCALL_PRIV_HPP
|
@ -0,0 +1,191 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include <algorithm> // remove_if |
||||
#include <cctype> // isspace (non-locale version) |
||||
#include <ade/util/algorithm.hpp> |
||||
|
||||
#include "opencv2/core/cvdef.h" |
||||
#include "logger.hpp" // GAPI_LOG |
||||
|
||||
#include "opencv2/gapi/gcomputation.hpp" |
||||
#include "opencv2/gapi/gkernel.hpp" |
||||
|
||||
#include "api/gcomputation_priv.hpp" |
||||
#include "api/gcall_priv.hpp" |
||||
#include "api/gnode_priv.hpp" |
||||
|
||||
#include "compiler/gmodelbuilder.hpp" |
||||
#include "compiler/gcompiler.hpp" |
||||
|
||||
// cv::GComputation private implementation /////////////////////////////////////
|
||||
// <none>
|
||||
|
||||
// cv::GComputation public implementation //////////////////////////////////////
|
||||
cv::GComputation::GComputation(const Generator& gen) |
||||
: m_priv(gen().m_priv) |
||||
{ |
||||
} |
||||
|
||||
cv::GComputation::GComputation(GMat in, GMat out) |
||||
: cv::GComputation(cv::GIn(in), cv::GOut(out)) |
||||
{ |
||||
} |
||||
|
||||
|
||||
cv::GComputation::GComputation(GMat in, GScalar out) |
||||
: cv::GComputation(cv::GIn(in), cv::GOut(out)) |
||||
{ |
||||
} |
||||
|
||||
cv::GComputation::GComputation(GMat in1, GMat in2, GMat out) |
||||
: cv::GComputation(cv::GIn(in1, in2), cv::GOut(out)) |
||||
{ |
||||
} |
||||
|
||||
cv::GComputation::GComputation(GMat in1, GMat in2, GScalar out) |
||||
: cv::GComputation(cv::GIn(in1, in2), cv::GOut(out)) |
||||
{ |
||||
} |
||||
|
||||
cv::GComputation::GComputation(const std::vector<GMat> &ins, |
||||
const std::vector<GMat> &outs) |
||||
: m_priv(new Priv()) |
||||
{ |
||||
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); |
||||
} |
||||
|
||||
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); |
||||
} |
||||
|
||||
cv::GCompiled cv::GComputation::compile(GMetaArgs &&metas, GCompileArgs &&args) |
||||
{ |
||||
// FIXME: Cache gcompiled per parameters here?
|
||||
cv::gimpl::GCompiler comp(*this, std::move(metas), std::move(args)); |
||||
return comp.compile(); |
||||
} |
||||
|
||||
void cv::GComputation::apply(GRunArgs &&ins, GRunArgsP &&outs, GCompileArgs &&args) |
||||
{ |
||||
const auto in_metas = descr_of(ins); |
||||
// FIXME Graph should be recompiled when GCompileArgs have changed
|
||||
if (m_priv->m_lastMetas != in_metas) |
||||
{ |
||||
// FIXME: Had to construct temporary object as compile() takes && (r-value)
|
||||
m_priv->m_lastCompiled = compile(GMetaArgs(in_metas), std::move(args)); |
||||
m_priv->m_lastMetas = in_metas; // Update only here, if compile() was ok
|
||||
} |
||||
m_priv->m_lastCompiled(std::move(ins), std::move(outs)); |
||||
} |
||||
|
||||
void cv::GComputation::apply(cv::Mat in, cv::Mat &out, GCompileArgs &&args) |
||||
{ |
||||
apply(cv::gin(in), cv::gout(out), std::move(args)); |
||||
// FIXME: The following doesn't work!
|
||||
// Operation result is not replicated into user's object
|
||||
// apply({GRunArg(in)}, {GRunArg(out)});
|
||||
} |
||||
|
||||
void cv::GComputation::apply(cv::Mat in, cv::Scalar &out, GCompileArgs &&args) |
||||
{ |
||||
apply(cv::gin(in), cv::gout(out), std::move(args)); |
||||
} |
||||
|
||||
void cv::GComputation::apply(cv::Mat in1, cv::Mat in2, cv::Mat &out, GCompileArgs &&args) |
||||
{ |
||||
apply(cv::gin(in1, in2), cv::gout(out), std::move(args)); |
||||
} |
||||
|
||||
void cv::GComputation::apply(cv::Mat in1, cv::Mat in2, cv::Scalar &out, GCompileArgs &&args) |
||||
{ |
||||
apply(cv::gin(in1, in2), cv::gout(out), std::move(args)); |
||||
} |
||||
|
||||
void cv::GComputation::apply(const std::vector<cv::Mat> &ins, |
||||
const std::vector<cv::Mat> &outs, |
||||
GCompileArgs &&args) |
||||
{ |
||||
GRunArgs call_ins; |
||||
GRunArgsP call_outs; |
||||
|
||||
// Make a temporary copy of vector outs - cv::Mats are copies anyway
|
||||
auto tmp = outs; |
||||
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)); |
||||
} |
||||
|
||||
cv::GComputation::Priv& cv::GComputation::priv() |
||||
{ |
||||
return *m_priv; |
||||
} |
||||
|
||||
const cv::GComputation::Priv& cv::GComputation::priv() const |
||||
{ |
||||
return *m_priv; |
||||
} |
||||
|
||||
// Islands /////////////////////////////////////////////////////////////////////
|
||||
|
||||
void cv::gapi::island(const std::string &name, |
||||
GProtoInputArgs &&ins, |
||||
GProtoOutputArgs &&outs) |
||||
{ |
||||
{ |
||||
// Island must have a printable name.
|
||||
// Forbid names which contain only spaces.
|
||||
GAPI_Assert(!name.empty()); |
||||
const auto first_printable_it = std::find_if_not(name.begin(), name.end(), isspace); |
||||
const bool likely_printable = first_printable_it != name.end(); |
||||
GAPI_Assert(likely_printable); |
||||
} |
||||
// Even if the name contains spaces, keep it unmodified as user will
|
||||
// then use this string to assign affinity, etc.
|
||||
|
||||
// First, set island tags on all operations from `ins` to `outs`
|
||||
auto island = cv::gimpl::unrollExpr(ins.m_args, outs.m_args); |
||||
if (island.all_ops.empty()) |
||||
{ |
||||
util::throw_error(std::logic_error("Operation range is empty")); |
||||
} |
||||
for (auto &op_expr_node : island.all_ops) |
||||
{ |
||||
auto &op_expr_node_p = op_expr_node.priv(); |
||||
|
||||
GAPI_Assert(op_expr_node.shape() == GNode::NodeShape::CALL); |
||||
const GCall& call = op_expr_node.call(); |
||||
const GCall::Priv& call_p = call.priv(); |
||||
|
||||
if (!op_expr_node_p.m_island.empty()) |
||||
{ |
||||
util::throw_error(std::logic_error |
||||
( "Operation " + call_p.m_k.name |
||||
+ " is already assigned to island \"" |
||||
+ op_expr_node_p.m_island + "\"")); |
||||
} |
||||
else |
||||
{ |
||||
op_expr_node_p.m_island = name; |
||||
GAPI_LOG_INFO(NULL, |
||||
"Assigned " << call_p.m_k.name << "_" << &call_p << |
||||
" to island \"" << name << "\""); |
||||
} |
||||
} |
||||
|
||||
// Note - this function only sets islands to all operations in
|
||||
// expression tree, it is just a first step.
|
||||
// The second step is assigning intermediate data objects to Islands,
|
||||
// see passes::initIslands for details.
|
||||
} |
@ -0,0 +1,29 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GCOMPUTATION_PRIV_HPP |
||||
#define OPENCV_GAPI_GCOMPUTATION_PRIV_HPP |
||||
|
||||
#include "opencv2/gapi.hpp" |
||||
#include "opencv2/gapi/gcall.hpp" |
||||
|
||||
#include "opencv2/gapi/util/variant.hpp" |
||||
|
||||
namespace cv { |
||||
|
||||
class GComputation::Priv |
||||
{ |
||||
public: |
||||
GCompiled m_lastCompiled; |
||||
GMetaArgs m_lastMetas; // TODO: make GCompiled remember its metas?
|
||||
GProtoArgs m_ins; |
||||
GProtoArgs m_outs; |
||||
}; |
||||
|
||||
} |
||||
|
||||
#endif // OPENCV_GAPI_GCOMPUTATION_PRIV_HPP
|
@ -0,0 +1,141 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include <iostream> // cerr |
||||
#include <functional> // hash |
||||
#include <numeric> // accumulate |
||||
|
||||
#include <ade/util/algorithm.hpp> |
||||
|
||||
#include "opencv2/core/cvdef.h" |
||||
#include "logger.hpp" |
||||
#include "opencv2/gapi/gkernel.hpp" |
||||
|
||||
#include "api/gbackend_priv.hpp" |
||||
|
||||
// GKernelPackage public implementation ////////////////////////////////////////
|
||||
void cv::gapi::GKernelPackage::remove(const cv::gapi::GBackend& backend) |
||||
{ |
||||
m_backend_kernels.erase(backend); |
||||
} |
||||
|
||||
bool cv::gapi::GKernelPackage::includesAPI(const std::string &id) const |
||||
{ |
||||
// In current form not very efficient (n * log n)
|
||||
auto it = std::find_if(m_backend_kernels.begin(), |
||||
m_backend_kernels.end(), |
||||
[&id](const M::value_type &p) { |
||||
return ade::util::contains(p.second, id); |
||||
}); |
||||
return (it != m_backend_kernels.end()); |
||||
} |
||||
|
||||
std::size_t cv::gapi::GKernelPackage::size() const |
||||
{ |
||||
return std::accumulate(m_backend_kernels.begin(), |
||||
m_backend_kernels.end(), |
||||
static_cast<std::size_t>(0u), |
||||
[](std::size_t acc, const M::value_type& v) { |
||||
return acc + v.second.size(); |
||||
}); |
||||
} |
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::combine(const GKernelPackage &lhs, |
||||
const GKernelPackage &rhs, |
||||
const cv::unite_policy policy) |
||||
{ |
||||
|
||||
if (policy == cv::unite_policy::REPLACE) |
||||
{ |
||||
// REPLACE policy: if there is a collision, prefer RHS
|
||||
// to LHS
|
||||
// since OTHER package has a prefernece, start with its copy
|
||||
GKernelPackage result(rhs); |
||||
// now iterate over LHS package and put kernel if and only
|
||||
// if there's no such one
|
||||
for (const auto &backend : lhs.m_backend_kernels) |
||||
{ |
||||
for (const auto &kimpl : backend.second) |
||||
{ |
||||
if (!result.includesAPI(kimpl.first)) |
||||
result.m_backend_kernels[backend.first].insert(kimpl); |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
else if (policy == cv::unite_policy::KEEP) |
||||
{ |
||||
// KEEP policy: if there is a collision, just keep two versions
|
||||
// of a kernel
|
||||
GKernelPackage result(lhs); |
||||
for (const auto &p : rhs.m_backend_kernels) |
||||
{ |
||||
result.m_backend_kernels[p.first].insert(p.second.begin(), |
||||
p.second.end()); |
||||
} |
||||
return result; |
||||
} |
||||
else GAPI_Assert(false); |
||||
return GKernelPackage(); |
||||
} |
||||
|
||||
std::pair<cv::gapi::GBackend, cv::GKernelImpl> |
||||
cv::gapi::GKernelPackage::lookup(const std::string &id, |
||||
const GLookupOrder &order) const |
||||
{ |
||||
if (order.empty()) |
||||
{ |
||||
// If order is empty, return what comes first
|
||||
auto it = std::find_if(m_backend_kernels.begin(), |
||||
m_backend_kernels.end(), |
||||
[&id](const M::value_type &p) { |
||||
return ade::util::contains(p.second, id); |
||||
}); |
||||
if (it != m_backend_kernels.end()) |
||||
{ |
||||
// FIXME: Two lookups!
|
||||
return std::make_pair(it->first, it->second.find(id)->second); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
// There is order, so:
|
||||
// 1. Limit search scope only to specified backends
|
||||
// FIXME: Currently it is not configurable if search can fall-back
|
||||
// to other backends (not listed in order) if kernel hasn't been found
|
||||
// in the look-up list
|
||||
// 2. Query backends in the specified order
|
||||
for (const auto &selected_backend : order) |
||||
{ |
||||
const auto kernels_it = m_backend_kernels.find(selected_backend); |
||||
if (kernels_it == m_backend_kernels.end()) |
||||
{ |
||||
GAPI_LOG_WARNING(NULL, |
||||
"Backend " |
||||
<< &selected_backend.priv() // FIXME: name instead
|
||||
<< " was listed in lookup list but was not found " |
||||
"in the package"); |
||||
continue; |
||||
} |
||||
if (ade::util::contains(kernels_it->second, id)) |
||||
{ |
||||
// FIXME: two lookups!
|
||||
return std::make_pair(selected_backend, kernels_it->second.find(id)->second); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// If reached here, kernel was not found among selected backends.
|
||||
util::throw_error(std::logic_error("Kernel " + id + " was not found")); |
||||
} |
||||
|
||||
std::vector<cv::gapi::GBackend> cv::gapi::GKernelPackage::backends() const |
||||
{ |
||||
std::vector<cv::gapi::GBackend> result; |
||||
for (const auto &p : m_backend_kernels) result.emplace_back(p.first); |
||||
return result; |
||||
} |
@ -0,0 +1,71 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include <opencv2/gapi/opencv_includes.hpp> |
||||
#include <opencv2/gapi/own/mat.hpp> //gapi::own::Mat |
||||
|
||||
#include "opencv2/gapi/gmat.hpp" |
||||
#include "api/gapi_priv.hpp" // GOrigin |
||||
|
||||
// cv::GMat public implementation //////////////////////////////////////////////
|
||||
cv::GMat::GMat() |
||||
: m_priv(new GOrigin(GShape::GMAT, GNode::Param())) |
||||
{ |
||||
} |
||||
|
||||
cv::GMat::GMat(const GNode &n, std::size_t out) |
||||
: m_priv(new GOrigin(GShape::GMAT, n, out)) |
||||
{ |
||||
} |
||||
|
||||
cv::GOrigin& cv::GMat::priv() |
||||
{ |
||||
return *m_priv; |
||||
} |
||||
|
||||
const cv::GOrigin& cv::GMat::priv() const |
||||
{ |
||||
return *m_priv; |
||||
} |
||||
|
||||
cv::GMatDesc cv::descr_of(const cv::Mat &mat) |
||||
{ |
||||
return GMatDesc{mat.depth(), mat.channels(), {mat.cols, mat.rows}}; |
||||
} |
||||
|
||||
cv::GMatDesc cv::gapi::own::descr_of(const cv::gapi::own::Mat &mat) |
||||
{ |
||||
return GMatDesc{mat.depth(), mat.channels(), {mat.cols, mat.rows}}; |
||||
} |
||||
|
||||
namespace cv { |
||||
std::ostream& operator<<(std::ostream& os, const cv::GMatDesc &desc) |
||||
{ |
||||
switch (desc.depth) |
||||
{ |
||||
#define TT(X) case CV_##X: os << #X; break; |
||||
TT(8U); |
||||
TT(8S); |
||||
TT(16U); |
||||
TT(16S); |
||||
TT(32S); |
||||
TT(32F); |
||||
TT(64F); |
||||
#undef TT |
||||
default: |
||||
os << "(user type " |
||||
<< std::hex << desc.depth << std::dec |
||||
<< ")"; |
||||
break; |
||||
} |
||||
|
||||
os << "C" << desc.chan << " "; |
||||
os << desc.size.width << "x" << desc.size.height; |
||||
|
||||
return os; |
||||
} |
||||
} |
@ -0,0 +1,88 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include <cassert> |
||||
|
||||
#include "api/gnode.hpp" |
||||
#include "api/gnode_priv.hpp" |
||||
|
||||
// GNode private implementation
|
||||
cv::GNode::Priv::Priv() |
||||
: m_shape(NodeShape::EMPTY) |
||||
{ |
||||
} |
||||
|
||||
cv::GNode::Priv::Priv(GCall c) |
||||
: m_shape(NodeShape::CALL), m_spec(c) |
||||
{ |
||||
} |
||||
|
||||
cv::GNode::Priv::Priv(ParamTag) |
||||
: m_shape(NodeShape::PARAM) |
||||
{ |
||||
} |
||||
|
||||
cv::GNode::Priv::Priv(ConstTag) |
||||
: m_shape(NodeShape::CONST_BOUNDED) |
||||
{ |
||||
} |
||||
|
||||
// GNode public implementation
|
||||
cv::GNode::GNode() |
||||
: m_priv(new Priv()) |
||||
{ |
||||
} |
||||
|
||||
cv::GNode::GNode(const GCall &c) |
||||
: m_priv(new Priv(c)) |
||||
{ |
||||
} |
||||
|
||||
cv::GNode::GNode(ParamTag) |
||||
: m_priv(new Priv(Priv::ParamTag())) |
||||
{ |
||||
} |
||||
|
||||
cv::GNode::GNode(ConstTag) |
||||
: m_priv(new Priv(Priv::ConstTag())) |
||||
{ |
||||
} |
||||
|
||||
cv::GNode cv::GNode::Call(const GCall &c) |
||||
{ |
||||
return GNode(c); |
||||
} |
||||
|
||||
cv::GNode cv::GNode::Param() |
||||
{ |
||||
return GNode(ParamTag()); |
||||
} |
||||
|
||||
cv::GNode cv::GNode::Const() |
||||
{ |
||||
return GNode(ConstTag()); |
||||
} |
||||
|
||||
cv::GNode::Priv& cv::GNode::priv() |
||||
{ |
||||
return *m_priv; |
||||
} |
||||
|
||||
const cv::GNode::Priv& cv::GNode::priv() const |
||||
{ |
||||
return *m_priv; |
||||
} |
||||
|
||||
const cv::GNode::NodeShape& cv::GNode::shape() const |
||||
{ |
||||
return m_priv->m_shape; |
||||
} |
||||
|
||||
const cv::GCall& cv::GNode::call() const |
||||
{ |
||||
return util::get<GCall>(m_priv->m_spec); |
||||
} |
@ -0,0 +1,58 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GNODE_HPP |
||||
#define OPENCV_GAPI_GNODE_HPP |
||||
|
||||
#include <memory> // std::shared_ptr |
||||
|
||||
namespace cv { |
||||
|
||||
class GCall; |
||||
|
||||
// TODO Move "internal" namespace
|
||||
// TODO Expose details?
|
||||
|
||||
// This class won't be public
|
||||
|
||||
// data GNode = Call Operation [GNode]
|
||||
// | Const <T>
|
||||
// | Param <GMat|GParam>
|
||||
|
||||
class GNode |
||||
{ |
||||
public: |
||||
class Priv; |
||||
|
||||
// Constructors
|
||||
GNode(); // Empty (invalid) constructor
|
||||
static GNode Call (const GCall &c); // Call constructor
|
||||
static GNode Param(); // Param constructor
|
||||
static GNode Const(); |
||||
|
||||
// Internal use only
|
||||
Priv& priv(); |
||||
const Priv& priv() const; |
||||
enum class NodeShape: unsigned int; |
||||
|
||||
const NodeShape& shape() const; |
||||
const GCall& call() const; |
||||
|
||||
protected: |
||||
struct ParamTag {}; |
||||
struct ConstTag {}; |
||||
|
||||
explicit GNode(const GCall &c); |
||||
explicit GNode(ParamTag unused); |
||||
explicit GNode(ConstTag unused); |
||||
|
||||
std::shared_ptr<Priv> m_priv; |
||||
}; |
||||
|
||||
} |
||||
|
||||
#endif // OPENCV_GAPI_GNODE_HPP
|
@ -0,0 +1,52 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GNODE_PRIV_HPP |
||||
#define OPENCV_GNODE_PRIV_HPP |
||||
|
||||
#include <string> |
||||
#include <vector> |
||||
#include <unordered_map> |
||||
|
||||
#include "opencv2/gapi/util/variant.hpp" |
||||
|
||||
#include "opencv2/gapi/gcall.hpp" |
||||
#include "opencv2/gapi/garg.hpp" |
||||
#include "opencv2/gapi/gkernel.hpp" |
||||
|
||||
#include "api/gnode.hpp" |
||||
|
||||
namespace cv { |
||||
|
||||
enum class GNode::NodeShape: unsigned int |
||||
{ |
||||
EMPTY, |
||||
CALL, |
||||
PARAM, |
||||
CONST_BOUNDED |
||||
}; |
||||
|
||||
class GNode::Priv |
||||
{ |
||||
public: |
||||
// TODO: replace with optional?
|
||||
typedef util::variant<util::monostate, GCall> NodeSpec; |
||||
const NodeShape m_shape; |
||||
const NodeSpec m_spec; |
||||
std::string m_island; // user-modifiable attribute
|
||||
struct ParamTag {}; |
||||
struct ConstTag {}; |
||||
|
||||
Priv(); // Empty (invalid) constructor
|
||||
explicit Priv(GCall c); // Call conctrustor
|
||||
explicit Priv(ParamTag u); // Param constructor
|
||||
explicit Priv(ConstTag u); // Param constructor
|
||||
}; |
||||
|
||||
} |
||||
|
||||
#endif // OPENCV_GNODE_PRIV_HPP
|
@ -0,0 +1,152 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include <ade/util/algorithm.hpp> |
||||
#include "opencv2/gapi/util/throw.hpp" |
||||
#include "opencv2/gapi/garg.hpp" |
||||
#include "opencv2/gapi/gproto.hpp" |
||||
|
||||
#include "api/gapi_priv.hpp" |
||||
#include "api/gproto_priv.hpp" |
||||
|
||||
// FIXME: it should be a visitor!
|
||||
// FIXME: Reimplement with traits?
|
||||
|
||||
const cv::GOrigin& cv::gimpl::proto::origin_of(const cv::GProtoArg &arg) |
||||
{ |
||||
switch (arg.index()) |
||||
{ |
||||
case cv::GProtoArg::index_of<cv::GMat>(): |
||||
return util::get<cv::GMat>(arg).priv(); |
||||
|
||||
case cv::GProtoArg::index_of<cv::GScalar>(): |
||||
return util::get<cv::GScalar>(arg).priv(); |
||||
|
||||
case cv::GProtoArg::index_of<cv::detail::GArrayU>(): |
||||
return util::get<cv::detail::GArrayU>(arg).priv(); |
||||
|
||||
default: |
||||
util::throw_error(std::logic_error("Unsupported GProtoArg type")); |
||||
} |
||||
} |
||||
|
||||
const cv::GOrigin& cv::gimpl::proto::origin_of(const cv::GArg &arg) |
||||
{ |
||||
// Generic, but not very efficient implementation
|
||||
// FIXME: Walking a thin line here!!! Here we rely that GArg and
|
||||
// GProtoArg share the same object and this is true while objects
|
||||
// are reference-counted, so return value is not a reference to a tmp.
|
||||
return origin_of(rewrap(arg)); |
||||
} |
||||
|
||||
bool cv::gimpl::proto::is_dynamic(const cv::GArg& arg) |
||||
{ |
||||
// FIXME: refactor this method to be auto-generated from
|
||||
// - GProtoArg variant parameter pack, and
|
||||
// - traits over every type
|
||||
switch (arg.kind) |
||||
{ |
||||
case detail::ArgKind::GMAT: |
||||
case detail::ArgKind::GSCALAR: |
||||
case detail::ArgKind::GARRAY: |
||||
return true; |
||||
|
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
cv::GRunArg cv::value_of(const cv::GOrigin &origin) |
||||
{ |
||||
switch (origin.shape) |
||||
{ |
||||
case GShape::GSCALAR: return GRunArg(util::get<cv::gapi::own::Scalar>(origin.value)); |
||||
default: util::throw_error(std::logic_error("Unsupported shape for constant")); |
||||
} |
||||
} |
||||
|
||||
cv::GProtoArg cv::gimpl::proto::rewrap(const cv::GArg &arg) |
||||
{ |
||||
// FIXME: replace with a more generic any->variant
|
||||
// (or variant<T> -> variant<U>) conversion?
|
||||
switch (arg.kind) |
||||
{ |
||||
case detail::ArgKind::GMAT: return GProtoArg(arg.get<cv::GMat>()); |
||||
case detail::ArgKind::GSCALAR: return GProtoArg(arg.get<cv::GScalar>()); |
||||
case detail::ArgKind::GARRAY: return GProtoArg(arg.get<cv::detail::GArrayU>()); |
||||
default: util::throw_error(std::logic_error("Unsupported GArg type")); |
||||
} |
||||
} |
||||
|
||||
cv::GMetaArg cv::descr_of(const cv::GRunArg &arg) |
||||
{ |
||||
switch (arg.index()) |
||||
{ |
||||
case GRunArg::index_of<cv::Mat>(): |
||||
return cv::GMetaArg(descr_of(util::get<cv::Mat>(arg))); |
||||
|
||||
case GRunArg::index_of<cv::Scalar>(): |
||||
return cv::GMetaArg(descr_of(util::get<cv::Scalar>(arg))); |
||||
|
||||
case GRunArg::index_of<cv::gapi::own::Scalar>(): |
||||
return cv::GMetaArg(descr_of(util::get<cv::gapi::own::Scalar>(arg))); |
||||
|
||||
case GRunArg::index_of<cv::detail::VectorRef>(): |
||||
return cv::GMetaArg(util::get<cv::detail::VectorRef>(arg).descr_of()); |
||||
|
||||
default: util::throw_error(std::logic_error("Unsupported GRunArg type")); |
||||
} |
||||
} |
||||
|
||||
cv::GMetaArgs cv::descr_of(const cv::GRunArgs &args) |
||||
{ |
||||
cv::GMetaArgs metas; |
||||
ade::util::transform(args, std::back_inserter(metas), [](const cv::GRunArg &arg){ return descr_of(arg); }); |
||||
return metas; |
||||
} |
||||
|
||||
cv::GMetaArg cv::descr_of(const cv::GRunArgP &argp) |
||||
{ |
||||
switch (argp.index()) |
||||
{ |
||||
case GRunArgP::index_of<cv::Mat*>(): return GMetaArg(descr_of(*util::get<cv::Mat*>(argp))); |
||||
case GRunArgP::index_of<cv::gapi::own::Mat*>(): return GMetaArg(descr_of(*util::get<cv::gapi::own::Mat*>(argp))); |
||||
case GRunArgP::index_of<cv::Scalar*>(): return GMetaArg(descr_of(*util::get<cv::Scalar*>(argp))); |
||||
case GRunArgP::index_of<cv::gapi::own::Scalar*>(): return GMetaArg(descr_of(*util::get<cv::gapi::own::Scalar*>(argp))); |
||||
case GRunArgP::index_of<cv::detail::VectorRef>(): return GMetaArg(util::get<cv::detail::VectorRef>(argp).descr_of()); |
||||
default: util::throw_error(std::logic_error("Unsupported GRunArgP type")); |
||||
} |
||||
} |
||||
|
||||
namespace cv { |
||||
std::ostream& operator<<(std::ostream& os, const cv::GMetaArg &arg) |
||||
{ |
||||
// FIXME: Implement via variant visitor
|
||||
switch (arg.index()) |
||||
{ |
||||
case cv::GMetaArg::index_of<util::monostate>(): |
||||
os << "(unresolved)"; |
||||
break; |
||||
|
||||
case cv::GMetaArg::index_of<cv::GMatDesc>(): |
||||
os << util::get<cv::GMatDesc>(arg); |
||||
break; |
||||
|
||||
case cv::GMetaArg::index_of<cv::GScalarDesc>(): |
||||
os << util::get<cv::GScalarDesc>(arg); |
||||
break; |
||||
|
||||
case cv::GMetaArg::index_of<cv::GArrayDesc>(): |
||||
os << util::get<cv::GArrayDesc>(arg); |
||||
break; |
||||
default: |
||||
GAPI_Assert(false); |
||||
} |
||||
|
||||
return os; |
||||
} |
||||
} |
@ -0,0 +1,35 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GPROTO_PRIV_HPP |
||||
#define OPENCV_GAPI_GPROTO_PRIV_HPP |
||||
|
||||
#include "opencv2/gapi/gproto.hpp" |
||||
#include "opencv2/gapi/garg.hpp" |
||||
|
||||
#include "api/gapi_priv.hpp" |
||||
|
||||
namespace cv { |
||||
namespace gimpl { |
||||
namespace proto { |
||||
|
||||
// These methods are used by GModelBuilder only
|
||||
// FIXME: Document semantics
|
||||
|
||||
// FIXME: GAPI_EXPORTS because of tests only!
|
||||
// FIXME: Possible dangling reference alert!!!
|
||||
GAPI_EXPORTS const GOrigin& origin_of (const GProtoArg &arg); |
||||
GAPI_EXPORTS const GOrigin& origin_of (const GArg &arg); |
||||
|
||||
bool is_dynamic(const GArg &arg); |
||||
GProtoArg rewrap (const GArg &arg); |
||||
|
||||
} // proto
|
||||
} // gimpl
|
||||
} // cv
|
||||
|
||||
#endif // OPENCV_GAPI_GPROTO_PRIV_HPP
|
@ -0,0 +1,69 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include "opencv2/gapi/gscalar.hpp" |
||||
#include "opencv2/gapi/own/convert.hpp" |
||||
#include "api/gapi_priv.hpp" // GOrigin |
||||
|
||||
// cv::GScalar public implementation ///////////////////////////////////////////
|
||||
cv::GScalar::GScalar() |
||||
: m_priv(new GOrigin(GShape::GSCALAR, cv::GNode::Param())) |
||||
{ |
||||
} |
||||
|
||||
cv::GScalar::GScalar(const GNode &n, std::size_t out) |
||||
: m_priv(new GOrigin(GShape::GSCALAR, n, out)) |
||||
{ |
||||
} |
||||
|
||||
cv::GScalar::GScalar(const cv::gapi::own::Scalar& s) |
||||
: m_priv(new GOrigin(GShape::GSCALAR, cv::gimpl::ConstVal(s))) |
||||
{ |
||||
} |
||||
|
||||
cv::GScalar::GScalar(cv::gapi::own::Scalar&& s) |
||||
: m_priv(new GOrigin(GShape::GSCALAR, cv::gimpl::ConstVal(std::move(s)))) |
||||
{ |
||||
} |
||||
|
||||
cv::GScalar::GScalar(const cv::Scalar& s) |
||||
: m_priv(new GOrigin(GShape::GSCALAR, cv::gimpl::ConstVal(to_own(s)))) |
||||
{ |
||||
} |
||||
|
||||
cv::GScalar::GScalar(double v0) |
||||
: m_priv(new GOrigin(GShape::GSCALAR, cv::gimpl::ConstVal(cv::gapi::own::Scalar(v0)))) |
||||
{ |
||||
} |
||||
|
||||
cv::GOrigin& cv::GScalar::priv() |
||||
{ |
||||
return *m_priv; |
||||
} |
||||
|
||||
const cv::GOrigin& cv::GScalar::priv() const |
||||
{ |
||||
return *m_priv; |
||||
} |
||||
|
||||
cv::GScalarDesc cv::descr_of(const cv::gapi::own::Scalar &) |
||||
{ |
||||
return empty_scalar_desc(); |
||||
} |
||||
|
||||
cv::GScalarDesc cv::descr_of(const cv::Scalar& s) |
||||
{ |
||||
return cv::descr_of(to_own(s)); |
||||
} |
||||
|
||||
namespace cv { |
||||
std::ostream& operator<<(std::ostream& os, const cv::GScalarDesc &) |
||||
{ |
||||
os << "(scalar)"; |
||||
return os; |
||||
} |
||||
} |
@ -0,0 +1,347 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include "opencv2/gapi/gcall.hpp" |
||||
#include "opencv2/gapi/gscalar.hpp" |
||||
#include "opencv2/gapi/gkernel.hpp" |
||||
#include "opencv2/gapi/core.hpp" |
||||
|
||||
#include <tuple> |
||||
#include <numeric> |
||||
|
||||
namespace cv { namespace gapi { |
||||
|
||||
GMat add(const GMat& src1, const GMat& src2, int dtype) |
||||
{ |
||||
return core::GAdd::on(src1, src2, dtype); |
||||
} |
||||
|
||||
GMat addC(const GMat& src1, const GScalar& c, int dtype) |
||||
{ |
||||
return core::GAddC::on(src1, c, dtype); |
||||
} |
||||
|
||||
GMat addC(const GScalar& c, const GMat& src1, int dtype) |
||||
{ |
||||
return core::GAddC::on(src1, c, dtype); |
||||
} |
||||
|
||||
GMat sub(const GMat& src1, const GMat& src2, int dtype) |
||||
{ |
||||
return core::GSub::on(src1, src2, dtype); |
||||
} |
||||
|
||||
GMat subC(const GMat& src1, const GScalar& c, int dtype) |
||||
{ |
||||
return core::GSubC::on(src1, c, dtype); |
||||
} |
||||
|
||||
GMat subRC(const GScalar& c, const GMat& src, int dtype) |
||||
{ |
||||
return core::GSubRC::on(c, src, dtype); |
||||
} |
||||
|
||||
GMat mul(const GMat& src1, const GMat& src2, double scale, int dtype) |
||||
{ |
||||
return core::GMul::on(src1, src2, scale, dtype); |
||||
} |
||||
|
||||
GMat mulC(const GMat& src, double scale, int dtype) |
||||
{ |
||||
return core::GMulCOld::on(src, scale, dtype); |
||||
} |
||||
|
||||
GMat mulC(const GMat& src, const GScalar& multiplier, int dtype) |
||||
{ |
||||
return core::GMulC::on(src, multiplier, dtype); |
||||
} |
||||
|
||||
GMat mulC(const GScalar& multiplier, const GMat& src, int dtype) |
||||
{ |
||||
return core::GMulC::on(src, multiplier, dtype); |
||||
} |
||||
|
||||
GMat div(const GMat& src1, const GMat& src2, double scale, int dtype) |
||||
{ |
||||
return core::GDiv::on(src1, src2, scale, dtype); |
||||
} |
||||
|
||||
GMat divC(const GMat& src, const GScalar& divisor, double scale, int dtype) |
||||
{ |
||||
return core::GDivC::on(src, divisor, scale, dtype); |
||||
} |
||||
|
||||
GMat divRC(const GScalar& divident, const GMat& src, double scale, int dtype) |
||||
{ |
||||
return core::GDivRC::on(divident, src, scale, dtype); |
||||
} |
||||
|
||||
GScalar mean(const GMat& src) |
||||
{ |
||||
return core::GMean::on(src); |
||||
} |
||||
|
||||
GMat mask(const GMat& src, const GMat& mask) |
||||
{ |
||||
return core::GMask::on(src, mask); |
||||
} |
||||
|
||||
std::tuple<GMat, GMat> polarToCart(const GMat& magnitude, const GMat& angle, |
||||
bool angleInDegrees) |
||||
{ |
||||
return core::GPolarToCart::on(magnitude, angle, angleInDegrees); |
||||
} |
||||
|
||||
std::tuple<GMat, GMat> cartToPolar(const GMat& x, const GMat& y, |
||||
bool angleInDegrees) |
||||
{ |
||||
return core::GCartToPolar::on(x, y, angleInDegrees); |
||||
} |
||||
|
||||
GMat cmpGT(const GMat& src1, const GMat& src2) |
||||
{ |
||||
return core::GCmpGT::on(src1, src2); |
||||
} |
||||
|
||||
GMat cmpLT(const GMat& src1, const GMat& src2) |
||||
{ |
||||
return core::GCmpLT::on(src1, src2); |
||||
} |
||||
|
||||
GMat cmpGE(const GMat& src1, const GMat& src2) |
||||
{ |
||||
return core::GCmpGE::on(src1, src2); |
||||
} |
||||
|
||||
GMat cmpLE(const GMat& src1, const GMat& src2) |
||||
{ |
||||
return core::GCmpLE::on(src1, src2); |
||||
} |
||||
|
||||
GMat cmpEQ(const GMat& src1, const GMat& src2) |
||||
{ |
||||
return core::GCmpEQ::on(src1, src2); |
||||
} |
||||
|
||||
GMat cmpNE(const GMat& src1, const GMat& src2) |
||||
{ |
||||
return core::GCmpNE::on(src1, src2); |
||||
} |
||||
|
||||
GMat cmpGT(const GMat& src1, const GScalar& src2) |
||||
{ |
||||
return core::GCmpGTScalar::on(src1, src2); |
||||
} |
||||
|
||||
GMat cmpLT(const GMat& src1, const GScalar& src2) |
||||
{ |
||||
return core::GCmpLTScalar::on(src1, src2); |
||||
} |
||||
|
||||
GMat cmpGE(const GMat& src1, const GScalar& src2) |
||||
{ |
||||
return core::GCmpGEScalar::on(src1, src2); |
||||
} |
||||
|
||||
GMat cmpLE(const GMat& src1, const GScalar& src2) |
||||
{ |
||||
return core::GCmpLEScalar::on(src1, src2); |
||||
} |
||||
|
||||
GMat cmpEQ(const GMat& src1, const GScalar& src2) |
||||
{ |
||||
return core::GCmpEQScalar::on(src1, src2); |
||||
} |
||||
|
||||
GMat cmpNE(const GMat& src1, const GScalar& src2) |
||||
{ |
||||
return core::GCmpNEScalar::on(src1, src2); |
||||
} |
||||
|
||||
GMat min(const GMat& src1, const GMat& src2) |
||||
{ |
||||
return core::GMin::on(src1, src2); |
||||
} |
||||
|
||||
GMat max(const GMat& src1, const GMat& src2) |
||||
{ |
||||
return core::GMax::on(src1, src2); |
||||
} |
||||
|
||||
GMat absDiff(const GMat& src1, const GMat& src2) |
||||
{ |
||||
return core::GAbsDiff::on(src1, src2); |
||||
} |
||||
|
||||
GMat absDiffC(const GMat& src, const GScalar& c) |
||||
{ |
||||
return core::GAbsDiffC::on(src, c); |
||||
} |
||||
|
||||
GMat bitwise_and(const GMat& src1, const GMat& src2) |
||||
{ |
||||
return core::GAnd::on(src1, src2); |
||||
} |
||||
|
||||
GMat bitwise_and(const GMat& src1, const GScalar& src2) |
||||
{ |
||||
return core::GAndS::on(src1, src2); |
||||
} |
||||
|
||||
GMat bitwise_or(const GMat& src1, const GMat& src2) |
||||
{ |
||||
return core::GOr::on(src1, src2); |
||||
} |
||||
|
||||
GMat bitwise_or(const GMat& src1, const GScalar& src2) |
||||
{ |
||||
return core::GOrS::on(src1, src2); |
||||
} |
||||
|
||||
GMat bitwise_xor(const GMat& src1, const GMat& src2) |
||||
{ |
||||
return core::GXor::on(src1, src2); |
||||
} |
||||
|
||||
GMat bitwise_xor(const GMat& src1, const GScalar& src2) |
||||
{ |
||||
return core::GXorS::on(src1, src2); |
||||
} |
||||
|
||||
GMat bitwise_not(const GMat& src1) |
||||
{ |
||||
return core::GNot::on(src1); |
||||
} |
||||
|
||||
GMat select(const GMat& src1, const GMat& src2, const GMat& mask) |
||||
{ |
||||
return core::GSelect::on(src1, src2, mask); |
||||
} |
||||
|
||||
GScalar sum(const GMat& src) |
||||
{ |
||||
return core::GSum::on(src); |
||||
} |
||||
|
||||
GMat addWeighted(const GMat& src1, double alpha, const GMat& src2, double beta, double gamma, int dtype) |
||||
{ |
||||
return core::GAddW::on(src1, alpha, src2, beta, gamma, dtype); |
||||
} |
||||
|
||||
GScalar normL1(const GMat& src) |
||||
{ |
||||
return core::GNormL1::on(src); |
||||
} |
||||
|
||||
GScalar normL2(const GMat& src) |
||||
{ |
||||
return core::GNormL2::on(src); |
||||
} |
||||
|
||||
GScalar normInf(const GMat& src) |
||||
{ |
||||
return core::GNormInf::on(src); |
||||
} |
||||
|
||||
std::tuple<GMat, GMat> integral(const GMat& src, int sdepth, int sqdepth) |
||||
{ |
||||
return core::GIntegral::on(src, sdepth, sqdepth); |
||||
} |
||||
|
||||
GMat threshold(const GMat& src, const GScalar& thresh, const GScalar& maxval, int type) |
||||
{ |
||||
GAPI_Assert(type != cv::THRESH_TRIANGLE && type != cv::THRESH_OTSU); |
||||
return core::GThreshold::on(src, thresh, maxval, type); |
||||
} |
||||
|
||||
std::tuple<GMat, GScalar> threshold(const GMat& src, const GScalar& maxval, int type) |
||||
{ |
||||
GAPI_Assert(type == cv::THRESH_TRIANGLE || type == cv::THRESH_OTSU); |
||||
return core::GThresholdOT::on(src, maxval, type); |
||||
} |
||||
|
||||
GMat inRange(const GMat& src, const GScalar& threshLow, const GScalar& threshUp) |
||||
{ |
||||
return core::GInRange::on(src, threshLow, threshUp); |
||||
} |
||||
|
||||
std::tuple<GMat, GMat, GMat> split3(const GMat& src) |
||||
{ |
||||
return core::GSplit3::on(src); |
||||
} |
||||
|
||||
std::tuple<GMat, GMat, GMat, GMat> split4(const GMat& src) |
||||
{ |
||||
return core::GSplit4::on(src); |
||||
} |
||||
|
||||
GMat merge3(const GMat& src1, const GMat& src2, const GMat& src3) |
||||
{ |
||||
return core::GMerge3::on(src1, src2, src3); |
||||
} |
||||
|
||||
GMat merge4(const GMat& src1, const GMat& src2, const GMat& src3, const GMat& src4) |
||||
{ |
||||
return core::GMerge4::on(src1, src2, src3, src4); |
||||
} |
||||
|
||||
GMat resize(const GMat& src, const Size& dsize, double fx, double fy, int interpolation) |
||||
{ |
||||
return core::GResize::on(src, dsize, fx, fy, interpolation); |
||||
} |
||||
|
||||
GMat remap(const GMat& src, const Mat& map1, const Mat& map2, |
||||
int interpolation, int borderMode, |
||||
const Scalar& borderValue) |
||||
{ |
||||
return core::GRemap::on(src, map1, map2, interpolation, borderMode, borderValue); |
||||
} |
||||
|
||||
GMat flip(const GMat& src, int flipCode) |
||||
{ |
||||
return core::GFlip::on(src, flipCode); |
||||
} |
||||
|
||||
GMat crop(const GMat& src, const Rect& rect) |
||||
{ |
||||
return core::GCrop::on(src, rect); |
||||
} |
||||
|
||||
GMat concatHor(const GMat& src1, const GMat& src2) |
||||
{ |
||||
return core::GConcatHor::on(src1, src2); |
||||
} |
||||
|
||||
GMat concatHor(const std::vector<GMat>& v) |
||||
{ |
||||
GAPI_Assert(v.size() >= 2); |
||||
return std::accumulate(v.begin()+1, v.end(), v[0], core::GConcatHor::on); |
||||
} |
||||
|
||||
GMat concatVert(const GMat& src1, const GMat& src2) |
||||
{ |
||||
return core::GConcatVert::on(src1, src2); |
||||
} |
||||
|
||||
GMat concatVert(const std::vector<GMat>& v) |
||||
{ |
||||
GAPI_Assert(v.size() >= 2); |
||||
return std::accumulate(v.begin()+1, v.end(), v[0], core::GConcatVert::on); |
||||
} |
||||
|
||||
GMat LUT(const GMat& src, const Mat& lut) |
||||
{ |
||||
return core::GLUT::on(src, lut); |
||||
} |
||||
|
||||
GMat convertTo(const GMat& m, int rtype, double alpha, double beta) |
||||
{ |
||||
return core::GConvertTo::on(m, rtype, alpha, beta); |
||||
} |
||||
|
||||
} //namespace gapi
|
||||
} //namespace cv
|
@ -0,0 +1,142 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include "opencv2/gapi/gscalar.hpp" |
||||
#include "opencv2/gapi/gcall.hpp" |
||||
#include "opencv2/gapi/gkernel.hpp" |
||||
#include "opencv2/gapi/imgproc.hpp" |
||||
|
||||
namespace cv { namespace gapi { |
||||
|
||||
GMat sepFilter(const GMat& src, int ddepth, const Mat& kernelX, const Mat& kernelY, const Point& anchor, |
||||
const Scalar& delta, int borderType, const Scalar& borderVal) |
||||
{ |
||||
return imgproc::GSepFilter::on(src, ddepth, kernelX, kernelY, anchor, delta, borderType, borderVal); |
||||
} |
||||
|
||||
GMat filter2D(const GMat& src, int ddepth, const Mat& kernel, const Point& anchor, const Scalar& delta, int borderType, |
||||
const Scalar& bordVal) |
||||
{ |
||||
return imgproc::GFilter2D::on(src, ddepth, kernel, anchor, delta, borderType, bordVal); |
||||
} |
||||
|
||||
GMat boxFilter(const GMat& src, int dtype, const Size& ksize, const Point& anchor, |
||||
bool normalize, int borderType, const Scalar& bordVal) |
||||
{ |
||||
return imgproc::GBoxFilter::on(src, dtype, ksize, anchor, normalize, borderType, bordVal); |
||||
} |
||||
|
||||
GMat blur(const GMat& src, const Size& ksize, const Point& anchor, |
||||
int borderType, const Scalar& bordVal) |
||||
{ |
||||
return imgproc::GBlur::on(src, ksize, anchor, borderType, bordVal); |
||||
} |
||||
|
||||
GMat gaussianBlur(const GMat& src, const Size& ksize, double sigmaX, double sigmaY, |
||||
int borderType, const Scalar& bordVal) |
||||
{ |
||||
return imgproc::GGaussBlur::on(src, ksize, sigmaX, sigmaY, borderType, bordVal); |
||||
} |
||||
|
||||
GMat medianBlur(const GMat& src, int ksize) |
||||
{ |
||||
return imgproc::GMedianBlur::on(src, ksize); |
||||
} |
||||
|
||||
GMat erode(const GMat& src, const Mat& kernel, const Point& anchor, int iterations, |
||||
int borderType, const Scalar& borderValue ) |
||||
{ |
||||
return imgproc::GErode::on(src, kernel, anchor, iterations, borderType, borderValue); |
||||
} |
||||
|
||||
GMat erode3x3(const GMat& src, int iterations, |
||||
int borderType, const Scalar& borderValue ) |
||||
{ |
||||
return erode(src, cv::Mat(), cv::Point(-1, -1), iterations, borderType, borderValue); |
||||
} |
||||
|
||||
GMat dilate(const GMat& src, const Mat& kernel, const Point& anchor, int iterations, |
||||
int borderType, const Scalar& borderValue) |
||||
{ |
||||
return imgproc::GDilate::on(src, kernel, anchor, iterations, borderType, borderValue); |
||||
} |
||||
|
||||
GMat dilate3x3(const GMat& src, int iterations, |
||||
int borderType, const Scalar& borderValue) |
||||
{ |
||||
return dilate(src, cv::Mat(), cv::Point(-1,-1), iterations, borderType, borderValue); |
||||
} |
||||
|
||||
GMat sobel(const GMat& src, int ddepth, int dx, int dy, int ksize, |
||||
double scale, double delta, |
||||
int borderType, const Scalar& bordVal) |
||||
{ |
||||
return imgproc::GSobel::on(src, ddepth, dx, dy, ksize, scale, delta, borderType, bordVal); |
||||
} |
||||
|
||||
GMat equalizeHist(const GMat& src) |
||||
{ |
||||
return imgproc::GEqHist::on(src); |
||||
} |
||||
|
||||
GMat Canny(const GMat& src, double thr1, double thr2, int apertureSize, bool l2gradient) |
||||
{ |
||||
return imgproc::GCanny::on(src, thr1, thr2, apertureSize, l2gradient); |
||||
} |
||||
|
||||
GMat RGB2Gray(const GMat& src) |
||||
{ |
||||
return imgproc::GRGB2Gray::on(src); |
||||
} |
||||
|
||||
GMat RGB2Gray(const GMat& src, float rY, float gY, float bY) |
||||
{ |
||||
return imgproc::GRGB2GrayCustom::on(src, rY, gY, bY); |
||||
} |
||||
|
||||
GMat BGR2Gray(const GMat& src) |
||||
{ |
||||
return imgproc::GBGR2Gray::on(src); |
||||
} |
||||
|
||||
GMat RGB2YUV(const GMat& src) |
||||
{ |
||||
return imgproc::GRGB2YUV::on(src); |
||||
} |
||||
|
||||
GMat BGR2LUV(const GMat& src) |
||||
{ |
||||
return imgproc::GBGR2LUV::on(src); |
||||
} |
||||
|
||||
GMat LUV2BGR(const GMat& src) |
||||
{ |
||||
return imgproc::GLUV2BGR::on(src); |
||||
} |
||||
|
||||
GMat BGR2YUV(const GMat& src) |
||||
{ |
||||
return imgproc::GBGR2YUV::on(src); |
||||
} |
||||
|
||||
GMat YUV2BGR(const GMat& src) |
||||
{ |
||||
return imgproc::GYUV2BGR::on(src); |
||||
} |
||||
|
||||
GMat YUV2RGB(const GMat& src) |
||||
{ |
||||
return imgproc::GYUV2RGB::on(src); |
||||
} |
||||
|
||||
GMat RGB2Lab(const GMat& src) |
||||
{ |
||||
return imgproc::GRGB2Lab::on(src); |
||||
} |
||||
|
||||
} //namespace gapi
|
||||
} //namespace cv
|
@ -0,0 +1,211 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include "opencv2/gapi/imgproc.hpp" |
||||
#include "opencv2/gapi/core.hpp" |
||||
#include "opencv2/gapi/gscalar.hpp" |
||||
#include "opencv2/gapi/operators.hpp" |
||||
|
||||
cv::GMat operator+(const cv::GMat& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::add(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator+(const cv::GMat& lhs, const cv::GScalar& rhs) |
||||
{ |
||||
return cv::gapi::addC(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator+(const cv::GScalar& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::addC(rhs, lhs); |
||||
} |
||||
|
||||
cv::GMat operator-(const cv::GMat& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::sub(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator-(const cv::GMat& lhs, const cv::GScalar& rhs) |
||||
{ |
||||
return cv::gapi::subC(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator-(const cv::GScalar& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::subRC(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator*(const cv::GMat& lhs, float rhs) |
||||
{ |
||||
return cv::gapi::mulC(lhs, static_cast<double>(rhs)); |
||||
} |
||||
|
||||
cv::GMat operator*(float lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::mulC(rhs, static_cast<double>(lhs)); |
||||
} |
||||
|
||||
cv::GMat operator*(const cv::GMat& lhs, const cv::GScalar& rhs) |
||||
{ |
||||
return cv::gapi::mulC(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator*(const cv::GScalar& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::mulC(rhs, lhs); |
||||
} |
||||
|
||||
cv::GMat operator/(const cv::GMat& lhs, const cv::GScalar& rhs) |
||||
{ |
||||
return cv::gapi::divC(lhs, rhs, 1.0); |
||||
} |
||||
|
||||
cv::GMat operator/(const cv::GMat& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::div(lhs, rhs, 1.0); |
||||
} |
||||
|
||||
cv::GMat operator/(const cv::GScalar& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::divRC(lhs, rhs, 1.0); |
||||
} |
||||
|
||||
cv::GMat operator&(const cv::GMat& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::bitwise_and(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator&(const cv::GMat& lhs, const cv::GScalar& rhs) |
||||
{ |
||||
return cv::gapi::bitwise_and(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator&(const cv::GScalar& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::bitwise_and(rhs, lhs); |
||||
} |
||||
|
||||
cv::GMat operator|(const cv::GMat& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::bitwise_or(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator|(const cv::GMat& lhs, const cv::GScalar& rhs) |
||||
{ |
||||
return cv::gapi::bitwise_or(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator|(const cv::GScalar& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::bitwise_or(rhs, lhs); |
||||
} |
||||
|
||||
cv::GMat operator^(const cv::GMat& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::bitwise_xor(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator^(const cv::GMat& lhs, const cv::GScalar& rhs) |
||||
{ |
||||
return cv::gapi::bitwise_xor(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator^(const cv::GScalar& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::bitwise_xor(rhs, lhs); |
||||
} |
||||
|
||||
cv::GMat operator~(const cv::GMat& lhs) |
||||
{ |
||||
return cv::gapi::bitwise_not(lhs); |
||||
} |
||||
|
||||
cv::GMat operator>(const cv::GMat& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::cmpGT(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator>=(const cv::GMat& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::cmpGE(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator<(const cv::GMat& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::cmpLT(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator<=(const cv::GMat& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::cmpLE(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator==(const cv::GMat& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::cmpEQ(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator!=(const cv::GMat& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::cmpNE(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator>(const cv::GMat& lhs, const cv::GScalar& rhs) |
||||
{ |
||||
return cv::gapi::cmpGT(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator>=(const cv::GMat& lhs, const cv::GScalar& rhs) |
||||
{ |
||||
return cv::gapi::cmpGE(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator<(const cv::GMat& lhs, const cv::GScalar& rhs) |
||||
{ |
||||
return cv::gapi::cmpLT(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator<=(const cv::GMat& lhs, const cv::GScalar& rhs) |
||||
{ |
||||
return cv::gapi::cmpLE(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator==(const cv::GMat& lhs, const cv::GScalar& rhs) |
||||
{ |
||||
return cv::gapi::cmpEQ(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator!=(const cv::GMat& lhs, const cv::GScalar& rhs) |
||||
{ |
||||
return cv::gapi::cmpNE(lhs, rhs); |
||||
} |
||||
|
||||
cv::GMat operator>(const cv::GScalar& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::cmpLT(rhs, lhs); |
||||
} |
||||
cv::GMat operator>=(const cv::GScalar& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::cmpLE(rhs, lhs); |
||||
} |
||||
cv::GMat operator<(const cv::GScalar& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::cmpGT(rhs, lhs); |
||||
} |
||||
cv::GMat operator<=(const cv::GScalar& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::cmpGE(rhs, lhs); |
||||
} |
||||
cv::GMat operator==(const cv::GScalar& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::cmpEQ(rhs, lhs); |
||||
} |
||||
cv::GMat operator!=(const cv::GScalar& lhs, const cv::GMat& rhs) |
||||
{ |
||||
return cv::gapi::cmpNE(rhs, lhs); |
||||
} |
@ -0,0 +1,2 @@ |
||||
This directory contains various G-API backends, which provide scheduling |
||||
logic and kernel implementations for specific targets. |
@ -0,0 +1,103 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GBACKEND_HPP |
||||
#define OPENCV_GAPI_GBACKEND_HPP |
||||
|
||||
#include <string> |
||||
#include <memory> |
||||
|
||||
#include <ade/node.hpp> |
||||
|
||||
#include "opencv2/gapi/garg.hpp" |
||||
#include "opencv2/gapi/own/mat.hpp" |
||||
|
||||
#include "opencv2/gapi/util/optional.hpp" |
||||
#include "opencv2/gapi/own/scalar.hpp" |
||||
|
||||
#include "compiler/gmodel.hpp" |
||||
|
||||
namespace cv { |
||||
namespace gimpl { |
||||
|
||||
// Forward declarations
|
||||
struct Data; |
||||
struct RcDesc; |
||||
|
||||
namespace magazine { |
||||
template<typename... Ts> struct Class |
||||
{ |
||||
template<typename T> using MapT = std::unordered_map<int, T>; |
||||
template<typename T> MapT<T>& slot() |
||||
{ |
||||
return std::get<ade::util::type_list_index<T, Ts...>::value>(slots); |
||||
} |
||||
template<typename T> const MapT<T>& slot() const |
||||
{ |
||||
return std::get<ade::util::type_list_index<T, Ts...>::value>(slots); |
||||
} |
||||
private: |
||||
std::tuple<MapT<Ts>...> slots; |
||||
}; |
||||
|
||||
} // namespace magazine
|
||||
|
||||
using Mag = magazine::Class<cv::gapi::own::Mat, cv::gapi::own::Scalar, cv::detail::VectorRef>; |
||||
|
||||
namespace magazine |
||||
{ |
||||
void bindInArg (Mag& mag, const RcDesc &rc, const GRunArg &arg); |
||||
void bindOutArg(Mag& mag, const RcDesc &rc, const GRunArgP &arg); |
||||
|
||||
void resetInternalData(Mag& mag, const Data &d); |
||||
cv::GRunArg getArg (const Mag& mag, const RcDesc &ref); |
||||
cv::GRunArgP getObjPtr ( Mag& mag, const RcDesc &rc); |
||||
void writeBack (const Mag& mag, const RcDesc &rc, GRunArgP &g_arg); |
||||
} // namespace magazine
|
||||
|
||||
namespace detail |
||||
{ |
||||
template<typename... Ts> struct magazine |
||||
{ |
||||
template<typename T> using MapT = std::unordered_map<int, T>; |
||||
template<typename T> MapT<T>& slot() |
||||
{ |
||||
return std::get<util::type_list_index<T, Ts...>::value>(slots); |
||||
} |
||||
template<typename T> const MapT<T>& slot() const |
||||
{ |
||||
return std::get<util::type_list_index<T, Ts...>::value>(slots); |
||||
} |
||||
private: |
||||
std::tuple<MapT<Ts>...> slots; |
||||
}; |
||||
} // namespace detail
|
||||
|
||||
struct GRuntimeArgs |
||||
{ |
||||
GRunArgs inObjs; |
||||
GRunArgsP outObjs; |
||||
}; |
||||
|
||||
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>(); |
||||
} |
||||
|
||||
|
||||
|
||||
}} // cv::gimpl
|
||||
|
||||
#endif // OPENCV_GAPI_GBACKEND_HPP
|
@ -0,0 +1,18 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include "opencv2/gapi/gcompoundkernel.hpp" // compound::backend() |
||||
|
||||
#include "api/gbackend_priv.hpp" |
||||
#include "compiler/gislandmodel.hpp" // GIslandExecutable |
||||
|
||||
cv::gapi::GBackend cv::gapi::compound::backend() |
||||
{ |
||||
// A pointer to dummy Priv is used to uniquely identify backends
|
||||
static cv::gapi::GBackend this_backend(std::make_shared<cv::gapi::GBackend::Priv>()); |
||||
return this_backend; |
||||
} |
@ -0,0 +1,45 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include <ade/util/zip_range.hpp> // util::indexed |
||||
#include "opencv2/gapi/gcompoundkernel.hpp" |
||||
#include "compiler/gobjref.hpp" |
||||
|
||||
// FIXME move to backends
|
||||
|
||||
cv::detail::GCompoundContext::GCompoundContext(const cv::GArgs& in_args) |
||||
{ |
||||
m_args.resize(in_args.size()); |
||||
for (const auto& it : ade::util::indexed(in_args)) |
||||
{ |
||||
const auto& i = ade::util::index(it); |
||||
const auto& in_arg = ade::util::value(it); |
||||
|
||||
if (in_arg.kind != cv::detail::ArgKind::GOBJREF) |
||||
{ |
||||
m_args[i] = in_arg; |
||||
} |
||||
else |
||||
{ |
||||
const cv::gimpl::RcDesc &ref = in_arg.get<cv::gimpl::RcDesc>(); |
||||
switch (ref.shape) |
||||
{ |
||||
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; |
||||
default: GAPI_Assert(false); |
||||
} |
||||
} |
||||
} |
||||
GAPI_Assert(m_args.size() == in_args.size()); |
||||
} |
||||
|
||||
cv::detail::GCompoundKernel::GCompoundKernel(const F& f) : m_f(f) |
||||
{ |
||||
} |
||||
|
||||
void cv::detail::GCompoundKernel::apply(cv::detail::GCompoundContext& ctx) { m_f(ctx); } |
@ -0,0 +1,227 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include <functional> |
||||
#include <unordered_set> |
||||
|
||||
#include <ade/util/algorithm.hpp> |
||||
|
||||
#include <ade/util/range.hpp> |
||||
#include <ade/util/zip_range.hpp> |
||||
#include <ade/util/chain_range.hpp> |
||||
|
||||
#include <ade/typed_graph.hpp> |
||||
|
||||
#include "opencv2/gapi/gcommon.hpp" |
||||
#include "opencv2/gapi/util/any.hpp" |
||||
#include "opencv2/gapi/gtype_traits.hpp" |
||||
|
||||
#include "compiler/gobjref.hpp" |
||||
#include "compiler/gmodel.hpp" |
||||
|
||||
#include "backends/cpu/gcpubackend.hpp" |
||||
#include "backends/cpu/gcpuimgproc.hpp" |
||||
#include "backends/cpu/gcpucore.hpp" |
||||
|
||||
#include "api/gbackend_priv.hpp" // FIXME: Make it part of Backend SDK! |
||||
|
||||
// FIXME: Is there a way to take a typed graph (our GModel),
|
||||
// and create a new typed graph _ATOP_ of that (by extending with a couple of
|
||||
// new types?).
|
||||
// Alternatively, is there a way to compose types graphs?
|
||||
//
|
||||
// If not, we need to introduce that!
|
||||
using GCPUModel = ade::TypedGraph |
||||
< cv::gimpl::Unit |
||||
, cv::gimpl::Protocol |
||||
>; |
||||
|
||||
// FIXME: Same issue with Typed and ConstTyped
|
||||
using GConstGCPUModel = ade::ConstTypedGraph |
||||
< cv::gimpl::Unit |
||||
, cv::gimpl::Protocol |
||||
>; |
||||
|
||||
namespace |
||||
{ |
||||
class GCPUBackendImpl final: public cv::gapi::GBackend::Priv |
||||
{ |
||||
virtual void unpackKernel(ade::Graph &graph, |
||||
const ade::NodeHandle &op_node, |
||||
const cv::GKernelImpl &impl) override |
||||
{ |
||||
GCPUModel gm(graph); |
||||
auto cpu_impl = cv::util::any_cast<cv::GCPUKernel>(impl.opaque); |
||||
gm.metadata(op_node).set(cv::gimpl::Unit{cpu_impl}); |
||||
} |
||||
|
||||
virtual EPtr compile(const ade::Graph &graph, |
||||
const cv::GCompileArgs &, |
||||
const std::vector<ade::NodeHandle> &nodes) const override |
||||
{ |
||||
return EPtr{new cv::gimpl::GCPUExecutable(graph, nodes)}; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
cv::gapi::GBackend cv::gapi::cpu::backend() |
||||
{ |
||||
static cv::gapi::GBackend this_backend(std::make_shared<GCPUBackendImpl>()); |
||||
return this_backend; |
||||
} |
||||
|
||||
// GCPUExcecutable implementation //////////////////////////////////////////////
|
||||
cv::gimpl::GCPUExecutable::GCPUExecutable(const ade::Graph &g, |
||||
const std::vector<ade::NodeHandle> &nodes) |
||||
: m_g(g), m_gm(m_g) |
||||
{ |
||||
// Convert list of operations (which is topologically sorted already)
|
||||
// into an execution script.
|
||||
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::DATA: |
||||
{ |
||||
m_dataNodes.push_back(nh); |
||||
const auto &desc = m_gm.metadata(nh).get<Data>(); |
||||
if (desc.storage == Data::Storage::CONST) |
||||
{ |
||||
auto rc = RcDesc{desc.rc, desc.shape, desc.ctor}; |
||||
magazine::bindInArg(m_res, rc, m_gm.metadata(nh).get<ConstValue>().arg); |
||||
} |
||||
//preallocate internal Mats in advance
|
||||
if (desc.storage == Data::Storage::INTERNAL && desc.shape == GShape::GMAT) |
||||
{ |
||||
const auto mat_desc = util::get<cv::GMatDesc>(desc.meta); |
||||
const auto type = CV_MAKETYPE(mat_desc.depth, mat_desc.chan); |
||||
m_res.slot<cv::gapi::own::Mat>()[desc.rc].create(mat_desc.size, type); |
||||
} |
||||
break; |
||||
} |
||||
default: util::throw_error(std::logic_error("Unsupported NodeType type")); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// FIXME: Document what it does
|
||||
cv::GArg cv::gimpl::GCPUExecutable::packArg(const GArg &arg) |
||||
{ |
||||
// No API placeholders allowed at this point
|
||||
// FIXME: this check has to be done somewhere in compilation stage.
|
||||
GAPI_Assert( arg.kind != cv::detail::ArgKind::GMAT |
||||
&& arg.kind != cv::detail::ArgKind::GSCALAR |
||||
&& arg.kind != cv::detail::ArgKind::GARRAY); |
||||
|
||||
if (arg.kind != cv::detail::ArgKind::GOBJREF) |
||||
{ |
||||
// All other cases - pass as-is, with no transformations to GArg contents.
|
||||
return arg; |
||||
} |
||||
GAPI_Assert(arg.kind == cv::detail::ArgKind::GOBJREF); |
||||
|
||||
// Wrap associated CPU object (either host or an internal one)
|
||||
// FIXME: object can be moved out!!! GExecutor faced that.
|
||||
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::GSCALAR: return GArg(m_res.slot<cv::gapi::own::Scalar>()[ref.id]); |
||||
// Note: .at() is intentional for GArray as object MUST be already there
|
||||
// (and constructed by either bindIn/Out or resetInternal)
|
||||
case GShape::GARRAY: return GArg(m_res.slot<cv::detail::VectorRef>().at(ref.id)); |
||||
default: |
||||
util::throw_error(std::logic_error("Unsupported GShape type")); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
void cv::gimpl::GCPUExecutable::run(std::vector<InObj> &&input_objs, |
||||
std::vector<OutObj> &&output_objs) |
||||
{ |
||||
// Update resources with run-time information - what this Island
|
||||
// has received from user (or from another Island, or mix...)
|
||||
// FIXME: Check input/output objects against GIsland protocol
|
||||
|
||||
for (auto& it : input_objs) magazine::bindInArg (m_res, it.first, it.second); |
||||
for (auto& it : output_objs) magazine::bindOutArg(m_res, it.first, it.second); |
||||
|
||||
// Initialize (reset) internal data nodes with user structures
|
||||
// before processing a frame (no need to do it for external data structures)
|
||||
GModel::ConstGraph gm(m_g); |
||||
for (auto nh : m_dataNodes) |
||||
{ |
||||
const auto &desc = gm.metadata(nh).get<Data>(); |
||||
|
||||
if ( desc.storage == Data::Storage::INTERNAL |
||||
&& !util::holds_alternative<util::monostate>(desc.ctor)) |
||||
{ |
||||
// FIXME: Note that compile-time constant data objects (like
|
||||
// a value-initialized GArray<T>) also satisfy this condition
|
||||
// and should be excluded, but now we just don't support it
|
||||
magazine::resetInternalData(m_res, desc); |
||||
} |
||||
} |
||||
|
||||
// OpenCV backend execution is not a rocket science at all.
|
||||
// Simply invoke our kernels in the proper order.
|
||||
GConstGCPUModel gcm(m_g); |
||||
for (auto &op_info : m_script) |
||||
{ |
||||
const auto &op = m_gm.metadata(op_info.nh).get<Op>(); |
||||
|
||||
// Obtain our real execution unit
|
||||
// TODO: Should kernels be copyable?
|
||||
GCPUKernel k = gcm.metadata(op_info.nh).get<Unit>().k; |
||||
|
||||
// Initialize kernel's execution context:
|
||||
// - Input parameters
|
||||
GCPUContext context; |
||||
context.m_args.reserve(op.args.size()); |
||||
|
||||
using namespace std::placeholders; |
||||
ade::util::transform(op.args, |
||||
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
|
||||
for (const auto &out_it : ade::util::indexed(op.outs)) |
||||
{ |
||||
// FIXME: Can the same GArg type resolution mechanism be reused here?
|
||||
const auto out_port = ade::util::index(out_it); |
||||
const auto out_desc = ade::util::value(out_it); |
||||
context.m_results[out_port] = magazine::getObjPtr(m_res, out_desc); |
||||
} |
||||
|
||||
// Now trigger the executable unit
|
||||
k.apply(context); |
||||
|
||||
//As Kernels are forbidden to allocate memory for (Mat) outputs,
|
||||
//this code seems redundant, at least for Mats
|
||||
//FIXME: unify with cv::detail::ensure_out_mats_not_reallocated
|
||||
for (const auto &out_it : ade::util::indexed(op_info.expected_out_metas)) |
||||
{ |
||||
const auto out_index = ade::util::index(out_it); |
||||
const auto expected_meta = ade::util::value(out_it); |
||||
const auto out_meta = descr_of(context.m_results[out_index]); |
||||
|
||||
if (expected_meta != out_meta) |
||||
{ |
||||
util::throw_error |
||||
(std::logic_error |
||||
("Output meta doesn't " |
||||
"coincide with the generated meta\n" |
||||
"Expected: " + ade::util::to_string(expected_meta) + "\n" |
||||
"Actual : " + ade::util::to_string(out_meta))); |
||||
} |
||||
} |
||||
} // for(m_script)
|
||||
|
||||
for (auto &it : output_objs) magazine::writeBack(m_res, it.first, it.second); |
||||
} |
@ -0,0 +1,63 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GCPUBACKEND_HPP |
||||
#define OPENCV_GAPI_GCPUBACKEND_HPP |
||||
|
||||
#include <map> // map |
||||
#include <unordered_map> // unordered_map |
||||
#include <tuple> // tuple |
||||
#include <ade/util/algorithm.hpp> // type_list_index |
||||
|
||||
#include "opencv2/gapi/garg.hpp" |
||||
#include "opencv2/gapi/gproto.hpp" |
||||
#include "opencv2/gapi/cpu/gcpukernel.hpp" |
||||
|
||||
|
||||
#include "api/gapi_priv.hpp" |
||||
#include "backends/common/gbackend.hpp" |
||||
#include "compiler/gislandmodel.hpp" |
||||
|
||||
namespace cv { namespace gimpl { |
||||
|
||||
struct Unit |
||||
{ |
||||
static const char *name() { return "HostKernel"; } |
||||
GCPUKernel k; |
||||
}; |
||||
|
||||
class GCPUExecutable final: public GIslandExecutable |
||||
{ |
||||
const ade::Graph &m_g; |
||||
GModel::ConstGraph m_gm; |
||||
|
||||
struct OperationInfo |
||||
{ |
||||
ade::NodeHandle nh; |
||||
GMetaArgs expected_out_metas; |
||||
}; |
||||
|
||||
// Execution script, currently absolutely naive
|
||||
std::vector<OperationInfo> m_script; |
||||
// 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; |
||||
GArg packArg(const GArg &arg); |
||||
|
||||
public: |
||||
GCPUExecutable(const ade::Graph &graph, |
||||
const std::vector<ade::NodeHandle> &nodes); |
||||
|
||||
virtual void run(std::vector<InObj> &&input_objs, |
||||
std::vector<OutObj> &&output_objs) override; |
||||
}; |
||||
|
||||
}} |
||||
|
||||
#endif // OPENCV_GAPI_GBACKEND_HPP
|
@ -0,0 +1,577 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include "precomp.hpp" |
||||
|
||||
#include "opencv2/gapi/core.hpp" |
||||
#include "opencv2/gapi/cpu/core.hpp" |
||||
#include "backends/cpu/gcpucore.hpp" |
||||
|
||||
GAPI_OCV_KERNEL(GCPUAdd, cv::gapi::core::GAdd) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Mat& b, int dtype, cv::Mat& out) |
||||
{ |
||||
cv::add(a, b, out, cv::noArray(), dtype); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUAddC, cv::gapi::core::GAddC) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Scalar& b, int dtype, cv::Mat& out) |
||||
{ |
||||
cv::add(a, b, out, cv::noArray(), dtype); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUSub, cv::gapi::core::GSub) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Mat& b, int dtype, cv::Mat& out) |
||||
{ |
||||
cv::subtract(a, b, out, cv::noArray(), dtype); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUSubC, cv::gapi::core::GSubC) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Scalar& b, int dtype, cv::Mat& out) |
||||
{ |
||||
cv::subtract(a, b, out, cv::noArray(), dtype); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUSubRC, cv::gapi::core::GSubRC) |
||||
{ |
||||
static void run(const cv::Scalar& a, const cv::Mat& b, int dtype, cv::Mat& out) |
||||
{ |
||||
cv::subtract(a, b, out, cv::noArray(), dtype); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUMul, cv::gapi::core::GMul) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Mat& b, double scale, int dtype, cv::Mat& out) |
||||
{ |
||||
cv::multiply(a, b, out, scale, dtype); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUMulCOld, cv::gapi::core::GMulCOld) |
||||
{ |
||||
static void run(const cv::Mat& a, double b, int dtype, cv::Mat& out) |
||||
{ |
||||
cv::multiply(a, b, out, 1, dtype); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUMulC, cv::gapi::core::GMulC) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Scalar& b, int dtype, cv::Mat& out) |
||||
{ |
||||
cv::multiply(a, b, out, 1, dtype); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUDiv, cv::gapi::core::GDiv) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Mat& b, double scale, int dtype, cv::Mat& out) |
||||
{ |
||||
cv::divide(a, b, out, scale, dtype); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUDivC, cv::gapi::core::GDivC) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Scalar& b, double scale, int dtype, cv::Mat& out) |
||||
{ |
||||
cv::divide(a, b, out, scale, dtype); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUDivRC, cv::gapi::core::GDivRC) |
||||
{ |
||||
static void run(const cv::Scalar& a, const cv::Mat& b, double scale, int dtype, cv::Mat& out) |
||||
{ |
||||
cv::divide(a, b, out, scale, dtype); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUMask, cv::gapi::core::GMask) |
||||
{ |
||||
static void run(const cv::Mat& in, const cv::Mat& mask, cv::Mat& out) |
||||
{ |
||||
out = cv::Mat::zeros(in.size(), in.type()); |
||||
in.copyTo(out, mask); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUMean, cv::gapi::core::GMean) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Scalar& out) |
||||
{ |
||||
out = cv::mean(in); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUPolarToCart, cv::gapi::core::GPolarToCart) |
||||
{ |
||||
static void run(const cv::Mat& magn, const cv::Mat& angle, bool angleInDegrees, cv::Mat& outx, cv::Mat& outy) |
||||
{ |
||||
cv::polarToCart(magn, angle, outx, outy, angleInDegrees); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUCartToPolar, cv::gapi::core::GCartToPolar) |
||||
{ |
||||
static void run(const cv::Mat& x, const cv::Mat& y, bool angleInDegrees, cv::Mat& outmagn, cv::Mat& outangle) |
||||
{ |
||||
cv::cartToPolar(x, y, outmagn, outangle, angleInDegrees); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUCmpGT, cv::gapi::core::GCmpGT) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Mat& b, cv::Mat& out) |
||||
{ |
||||
cv::compare(a, b, out, cv::CMP_GT); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUCmpGE, cv::gapi::core::GCmpGE) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Mat& b, cv::Mat& out) |
||||
{ |
||||
cv::compare(a, b, out, cv::CMP_GE); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUCmpLE, cv::gapi::core::GCmpLE) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Mat& b, cv::Mat& out) |
||||
{ |
||||
cv::compare(a, b, out, cv::CMP_LE); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUCmpLT, cv::gapi::core::GCmpLT) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Mat& b, cv::Mat& out) |
||||
{ |
||||
cv::compare(a, b, out, cv::CMP_LT); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUCmpEQ, cv::gapi::core::GCmpEQ) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Mat& b, cv::Mat& out) |
||||
{ |
||||
cv::compare(a, b, out, cv::CMP_EQ); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUCmpNE, cv::gapi::core::GCmpNE) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Mat& b, cv::Mat& out) |
||||
{ |
||||
cv::compare(a, b, out, cv::CMP_NE); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUCmpGTScalar, cv::gapi::core::GCmpGTScalar) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Scalar& b, cv::Mat& out) |
||||
{ |
||||
cv::compare(a, b, out, cv::CMP_GT); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUCmpGEScalar, cv::gapi::core::GCmpGEScalar) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Scalar& b, cv::Mat& out) |
||||
{ |
||||
cv::compare(a, b, out, cv::CMP_GE); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUCmpLEScalar, cv::gapi::core::GCmpLEScalar) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Scalar& b, cv::Mat& out) |
||||
{ |
||||
cv::compare(a, b, out, cv::CMP_LE); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUCmpLTScalar, cv::gapi::core::GCmpLTScalar) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Scalar& b, cv::Mat& out) |
||||
{ |
||||
cv::compare(a, b, out, cv::CMP_LT); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUCmpEQScalar, cv::gapi::core::GCmpEQScalar) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Scalar& b, cv::Mat& out) |
||||
{ |
||||
cv::compare(a, b, out, cv::CMP_EQ); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUCmpNEScalar, cv::gapi::core::GCmpNEScalar) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Scalar& b, cv::Mat& out) |
||||
{ |
||||
cv::compare(a, b, out, cv::CMP_NE); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUAnd, cv::gapi::core::GAnd) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Mat& b, cv::Mat& out) |
||||
{ |
||||
cv::bitwise_and(a, b, out); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUAndS, cv::gapi::core::GAndS) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Scalar& b, cv::Mat& out) |
||||
{ |
||||
cv::bitwise_and(a, b, out); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUOr, cv::gapi::core::GOr) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Mat& b, cv::Mat& out) |
||||
{ |
||||
cv::bitwise_or(a, b, out); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUOrS, cv::gapi::core::GOrS) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Scalar& b, cv::Mat& out) |
||||
{ |
||||
cv::bitwise_or(a, b, out); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUXor, cv::gapi::core::GXor) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Mat& b, cv::Mat& out) |
||||
{ |
||||
cv::bitwise_xor(a, b, out); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUXorS, cv::gapi::core::GXorS) |
||||
{ |
||||
static void run(const cv::Mat& a, const cv::Scalar& b, cv::Mat& out) |
||||
{ |
||||
cv::bitwise_xor(a, b, out); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUNot, cv::gapi::core::GNot) |
||||
{ |
||||
static void run(const cv::Mat& a, cv::Mat& out) |
||||
{ |
||||
cv::bitwise_not(a, out); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUSelect, cv::gapi::core::GSelect) |
||||
{ |
||||
static void run(const cv::Mat& src1, const cv::Mat& src2, const cv::Mat& mask, cv::Mat& out) |
||||
{ |
||||
src2.copyTo(out); |
||||
src1.copyTo(out, mask); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUMin, cv::gapi::core::GMin) |
||||
{ |
||||
static void run(const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out) |
||||
{ |
||||
out = cv::min(in1, in2); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUMax, cv::gapi::core::GMax) |
||||
{ |
||||
static void run(const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out) |
||||
{ |
||||
out = cv::max(in1, in2); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUAbsDiff, cv::gapi::core::GAbsDiff) |
||||
{ |
||||
static void run(const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out) |
||||
{ |
||||
cv::absdiff(in1, in2, out); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUAbsDiffC, cv::gapi::core::GAbsDiffC) |
||||
{ |
||||
static void run(const cv::Mat& in1, const cv::Scalar& in2, cv::Mat& out) |
||||
{ |
||||
cv::absdiff(in1, in2, out); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUSum, cv::gapi::core::GSum) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Scalar& out) |
||||
{ |
||||
out = cv::sum(in); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUAddW, cv::gapi::core::GAddW) |
||||
{ |
||||
static void run(const cv::Mat& in1, double alpha, const cv::Mat& in2, double beta, double gamma, int dtype, cv::Mat& out) |
||||
{ |
||||
cv::addWeighted(in1, alpha, in2, beta, gamma, out, dtype); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUNormL1, cv::gapi::core::GNormL1) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Scalar& out) |
||||
{ |
||||
out = cv::norm(in, cv::NORM_L1); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUNormL2, cv::gapi::core::GNormL2) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Scalar& out) |
||||
{ |
||||
out = cv::norm(in, cv::NORM_L2); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUNormInf, cv::gapi::core::GNormInf) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Scalar& out) |
||||
{ |
||||
out = cv::norm(in, cv::NORM_INF); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUIntegral, cv::gapi::core::GIntegral) |
||||
{ |
||||
static void run(const cv::Mat& in, int sdepth, int sqdepth, cv::Mat& out, cv::Mat& outSq) |
||||
{ |
||||
cv::integral(in, out, outSq, sdepth, sqdepth); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUThreshold, cv::gapi::core::GThreshold) |
||||
{ |
||||
static void run(const cv::Mat& in, const cv::Scalar& a, const cv::Scalar& b, int type, cv::Mat& out) |
||||
{ |
||||
cv::threshold(in, out, a.val[0], b.val[0], type); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUThresholdOT, cv::gapi::core::GThresholdOT) |
||||
{ |
||||
static void run(const cv::Mat& in, const cv::Scalar& b, int type, cv::Mat& out, cv::Scalar& outScalar) |
||||
{ |
||||
outScalar = cv::threshold(in, out, b.val[0], b.val[0], type); |
||||
} |
||||
}; |
||||
|
||||
|
||||
GAPI_OCV_KERNEL(GCPUInRange, cv::gapi::core::GInRange) |
||||
{ |
||||
static void run(const cv::Mat& in, const cv::Scalar& low, const cv::Scalar& up, cv::Mat& out) |
||||
{ |
||||
cv::inRange(in, low, up, out); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUSplit3, cv::gapi::core::GSplit3) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Mat &m1, cv::Mat &m2, cv::Mat &m3) |
||||
{ |
||||
std::vector<cv::Mat> outMats = {m1, m2, m3}; |
||||
cv::split(in, outMats); |
||||
|
||||
// Write back FIXME: Write a helper or avoid this nonsence completely!
|
||||
m1 = outMats[0]; |
||||
m2 = outMats[1]; |
||||
m3 = outMats[2]; |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUSplit4, cv::gapi::core::GSplit4) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Mat &m1, cv::Mat &m2, cv::Mat &m3, cv::Mat &m4) |
||||
{ |
||||
std::vector<cv::Mat> outMats = {m1, m2, m3, m4}; |
||||
cv::split(in, outMats); |
||||
|
||||
// Write back FIXME: Write a helper or avoid this nonsence completely!
|
||||
m1 = outMats[0]; |
||||
m2 = outMats[1]; |
||||
m3 = outMats[2]; |
||||
m4 = outMats[3]; |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUMerge3, cv::gapi::core::GMerge3) |
||||
{ |
||||
static void run(const cv::Mat& in1, const cv::Mat& in2, const cv::Mat& in3, cv::Mat &out) |
||||
{ |
||||
std::vector<cv::Mat> inMats = {in1, in2, in3}; |
||||
cv::merge(inMats, out); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUMerge4, cv::gapi::core::GMerge4) |
||||
{ |
||||
static void run(const cv::Mat& in1, const cv::Mat& in2, const cv::Mat& in3, const cv::Mat& in4, cv::Mat &out) |
||||
{ |
||||
std::vector<cv::Mat> inMats = {in1, in2, in3, in4}; |
||||
cv::merge(inMats, out); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUResize, cv::gapi::core::GResize) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Size sz, double fx, double fy, int interp, cv::Mat &out) |
||||
{ |
||||
cv::resize(in, out, sz, fx, fy, interp); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPURemap, cv::gapi::core::GRemap) |
||||
{ |
||||
static void run(const cv::Mat& in, const cv::Mat& x, const cv::Mat& y, int a, int b, cv::Scalar s, cv::Mat& out) |
||||
{ |
||||
cv::remap(in, out, x, y, a, b, s); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUFlip, cv::gapi::core::GFlip) |
||||
{ |
||||
static void run(const cv::Mat& in, int code, cv::Mat& out) |
||||
{ |
||||
cv::flip(in, out, code); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUCrop, cv::gapi::core::GCrop) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Rect rect, cv::Mat& out) |
||||
{ |
||||
cv::Mat(in, rect).copyTo(out); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUConcatHor, cv::gapi::core::GConcatHor) |
||||
{ |
||||
static void run(const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out) |
||||
{ |
||||
cv::hconcat(in1, in2, out); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUConcatVert, cv::gapi::core::GConcatVert) |
||||
{ |
||||
static void run(const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out) |
||||
{ |
||||
cv::vconcat(in1, in2, out); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPULUT, cv::gapi::core::GLUT) |
||||
{ |
||||
static void run(const cv::Mat& in, const cv::Mat& lut, cv::Mat& out) |
||||
{ |
||||
cv::LUT(in, lut, out); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUConvertTo, cv::gapi::core::GConvertTo) |
||||
{ |
||||
static void run(const cv::Mat& in, int rtype, double alpha, double beta, cv::Mat& out) |
||||
{ |
||||
in.convertTo(out, rtype, alpha, beta); |
||||
} |
||||
}; |
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::core::cpu::kernels() |
||||
{ |
||||
static auto pkg = cv::gapi::kernels |
||||
< GCPUAdd |
||||
, GCPUAddC |
||||
, GCPUSub |
||||
, GCPUSubC |
||||
, GCPUSubRC |
||||
, GCPUMul |
||||
, GCPUMulC |
||||
, GCPUMulCOld |
||||
, GCPUDiv |
||||
, GCPUDivC |
||||
, GCPUDivRC |
||||
, GCPUMean |
||||
, GCPUMask |
||||
, GCPUPolarToCart |
||||
, GCPUCartToPolar |
||||
, GCPUCmpGT |
||||
, GCPUCmpGE |
||||
, GCPUCmpLE |
||||
, GCPUCmpLT |
||||
, GCPUCmpEQ |
||||
, GCPUCmpNE |
||||
, GCPUCmpGTScalar |
||||
, GCPUCmpGEScalar |
||||
, GCPUCmpLEScalar |
||||
, GCPUCmpLTScalar |
||||
, GCPUCmpEQScalar |
||||
, GCPUCmpNEScalar |
||||
, GCPUAnd |
||||
, GCPUAndS |
||||
, GCPUOr |
||||
, GCPUOrS |
||||
, GCPUXor |
||||
, GCPUXorS |
||||
, GCPUNot |
||||
, GCPUSelect |
||||
, GCPUMin |
||||
, GCPUMax |
||||
, GCPUAbsDiff |
||||
, GCPUAbsDiffC |
||||
, GCPUSum |
||||
, GCPUAddW |
||||
, GCPUNormL1 |
||||
, GCPUNormL2 |
||||
, GCPUNormInf |
||||
, GCPUIntegral |
||||
, GCPUThreshold |
||||
, GCPUThresholdOT |
||||
, GCPUInRange |
||||
, GCPUSplit3 |
||||
, GCPUSplit4 |
||||
, GCPUResize |
||||
, GCPUMerge3 |
||||
, GCPUMerge4 |
||||
, GCPURemap |
||||
, GCPUFlip |
||||
, GCPUCrop |
||||
, GCPUConcatHor |
||||
, GCPUConcatVert |
||||
, GCPULUT |
||||
, GCPUConvertTo |
||||
>(); |
||||
return pkg; |
||||
} |
@ -0,0 +1,24 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GCPUCORE_HPP |
||||
#define OPENCV_GAPI_GCPUCORE_HPP |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
|
||||
#include "opencv2/gapi/cpu/gcpukernel.hpp" |
||||
|
||||
namespace cv { namespace gimpl { |
||||
|
||||
// NB: This is what a "Kernel Package" from the original Wiki doc should be.
|
||||
void loadCPUCore(std::map<std::string, cv::GCPUKernel> &kmap); |
||||
|
||||
} |
||||
} |
||||
|
||||
#endif // OPENCV_GAPI_GCPUCORE_HPP
|
@ -0,0 +1,273 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include "precomp.hpp" |
||||
|
||||
#include "opencv2/gapi/imgproc.hpp" |
||||
#include "opencv2/gapi/cpu/imgproc.hpp" |
||||
#include "backends/cpu/gcpuimgproc.hpp" |
||||
|
||||
GAPI_OCV_KERNEL(GCPUSepFilter, cv::gapi::imgproc::GSepFilter) |
||||
{ |
||||
static void run(const cv::Mat& in, int ddepth, const cv::Mat& kernX, const cv::Mat& kernY, const cv::Point& anchor, const cv::Scalar& delta, |
||||
int border, const cv::Scalar& bordVal, cv::Mat &out) |
||||
{ |
||||
if( border == cv::BORDER_CONSTANT ) |
||||
{ |
||||
cv::Mat temp_in; |
||||
int width_add = (kernY.cols - 1) / 2; |
||||
int height_add = (kernX.rows - 1) / 2; |
||||
cv::copyMakeBorder(in, temp_in, height_add, height_add, width_add, width_add, border, bordVal); |
||||
cv::Rect rect = cv::Rect(height_add, width_add, in.cols, in.rows); |
||||
cv::sepFilter2D(temp_in(rect), out, ddepth, kernX, kernY, anchor, delta.val[0], border); |
||||
} |
||||
else |
||||
cv::sepFilter2D(in, out, ddepth, kernX, kernY, anchor, delta.val[0], border); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUBoxFilter, cv::gapi::imgproc::GBoxFilter) |
||||
{ |
||||
static void run(const cv::Mat& in, int ddepth, const cv::Size& ksize, const cv::Point& anchor, bool normalize, int borderType, const cv::Scalar& bordVal, cv::Mat &out) |
||||
{ |
||||
if( borderType == cv::BORDER_CONSTANT ) |
||||
{ |
||||
cv::Mat temp_in; |
||||
int width_add = (ksize.width - 1) / 2; |
||||
int height_add = (ksize.height - 1) / 2; |
||||
cv::copyMakeBorder(in, temp_in, height_add, height_add, width_add, width_add, borderType, bordVal); |
||||
cv::Rect rect = cv::Rect(height_add, width_add, in.cols, in.rows); |
||||
cv::boxFilter(temp_in(rect), out, ddepth, ksize, anchor, normalize, borderType); |
||||
} |
||||
else |
||||
cv::boxFilter(in, out, ddepth, ksize, anchor, normalize, borderType); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUBlur, cv::gapi::imgproc::GBlur) |
||||
{ |
||||
static void run(const cv::Mat& in, const cv::Size& ksize, const cv::Point& anchor, int borderType, const cv::Scalar& bordVal, cv::Mat &out) |
||||
{ |
||||
if( borderType == cv::BORDER_CONSTANT ) |
||||
{ |
||||
cv::Mat temp_in; |
||||
int width_add = (ksize.width - 1) / 2; |
||||
int height_add = (ksize.height - 1) / 2; |
||||
cv::copyMakeBorder(in, temp_in, height_add, height_add, width_add, width_add, borderType, bordVal); |
||||
cv::Rect rect = cv::Rect(height_add, width_add, in.cols, in.rows); |
||||
cv::blur(temp_in(rect), out, ksize, anchor, borderType); |
||||
} |
||||
else |
||||
cv::blur(in, out, ksize, anchor, borderType); |
||||
} |
||||
}; |
||||
|
||||
|
||||
GAPI_OCV_KERNEL(GCPUFilter2D, cv::gapi::imgproc::GFilter2D) |
||||
{ |
||||
static void run(const cv::Mat& in, int ddepth, const cv::Mat& k, const cv::Point& anchor, const cv::Scalar& delta, int border, |
||||
const cv::Scalar& bordVal, cv::Mat &out) |
||||
{ |
||||
if( border == cv::BORDER_CONSTANT ) |
||||
{ |
||||
cv::Mat temp_in; |
||||
int width_add = (k.cols - 1) / 2; |
||||
int height_add = (k.rows - 1) / 2; |
||||
cv::copyMakeBorder(in, temp_in, height_add, height_add, width_add, width_add, border, bordVal ); |
||||
cv::Rect rect = cv::Rect(height_add, width_add, in.cols, in.rows); |
||||
cv::filter2D(temp_in(rect), out, ddepth, k, anchor, delta.val[0], border); |
||||
} |
||||
else |
||||
cv::filter2D(in, out, ddepth, k, anchor, delta.val[0], border); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUGaussBlur, cv::gapi::imgproc::GGaussBlur) |
||||
{ |
||||
static void run(const cv::Mat& in, const cv::Size& ksize, double sigmaX, double sigmaY, int borderType, const cv::Scalar& bordVal, cv::Mat &out) |
||||
{ |
||||
if( borderType == cv::BORDER_CONSTANT ) |
||||
{ |
||||
cv::Mat temp_in; |
||||
int width_add = (ksize.width - 1) / 2; |
||||
int height_add = (ksize.height - 1) / 2; |
||||
cv::copyMakeBorder(in, temp_in, height_add, height_add, width_add, width_add, borderType, bordVal ); |
||||
cv::Rect rect = cv::Rect(height_add, width_add, in.cols, in.rows); |
||||
cv::GaussianBlur(temp_in(rect), out, ksize, sigmaX, sigmaY, borderType); |
||||
} |
||||
else |
||||
cv::GaussianBlur(in, out, ksize, sigmaX, sigmaY, borderType); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUMedianBlur, cv::gapi::imgproc::GMedianBlur) |
||||
{ |
||||
static void run(const cv::Mat& in, int ksize, cv::Mat &out) |
||||
{ |
||||
cv::medianBlur(in, out, ksize); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUErode, cv::gapi::imgproc::GErode) |
||||
{ |
||||
static void run(const cv::Mat& in, const cv::Mat& kernel, const cv::Point& anchor, int iterations, int borderType, const cv::Scalar& borderValue, cv::Mat &out) |
||||
{ |
||||
cv::erode(in, out, kernel, anchor, iterations, borderType, borderValue); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUDilate, cv::gapi::imgproc::GDilate) |
||||
{ |
||||
static void run(const cv::Mat& in, const cv::Mat& kernel, const cv::Point& anchor, int iterations, int borderType, const cv::Scalar& borderValue, cv::Mat &out) |
||||
{ |
||||
cv::dilate(in, out, kernel, anchor, iterations, borderType, borderValue); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUSobel, cv::gapi::imgproc::GSobel) |
||||
{ |
||||
static void run(const cv::Mat& in, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType, |
||||
const cv::Scalar& bordVal, cv::Mat &out) |
||||
{ |
||||
if( borderType == cv::BORDER_CONSTANT ) |
||||
{ |
||||
cv::Mat temp_in; |
||||
int add = (ksize - 1) / 2; |
||||
cv::copyMakeBorder(in, temp_in, add, add, add, add, borderType, bordVal ); |
||||
cv::Rect rect = cv::Rect(add, add, in.cols, in.rows); |
||||
cv::Sobel(temp_in(rect), out, ddepth, dx, dy, ksize, scale, delta, borderType); |
||||
} |
||||
else |
||||
cv::Sobel(in, out, ddepth, dx, dy, ksize, scale, delta, borderType); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUEqualizeHist, cv::gapi::imgproc::GEqHist) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Mat &out) |
||||
{ |
||||
cv::equalizeHist(in, out); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUCanny, cv::gapi::imgproc::GCanny) |
||||
{ |
||||
static void run(const cv::Mat& in, double thr1, double thr2, int apSize, bool l2gradient, cv::Mat &out) |
||||
{ |
||||
cv::Canny(in, out, thr1, thr2, apSize, l2gradient); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPURGB2YUV, cv::gapi::imgproc::GRGB2YUV) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Mat &out) |
||||
{ |
||||
cv::cvtColor(in, out, cv::COLOR_RGB2YUV); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUYUV2RGB, cv::gapi::imgproc::GYUV2RGB) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Mat &out) |
||||
{ |
||||
cv::cvtColor(in, out, cv::COLOR_YUV2RGB); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPURGB2Lab, cv::gapi::imgproc::GRGB2Lab) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Mat &out) |
||||
{ |
||||
cv::cvtColor(in, out, cv::COLOR_RGB2Lab); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUBGR2LUV, cv::gapi::imgproc::GBGR2LUV) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Mat &out) |
||||
{ |
||||
cv::cvtColor(in, out, cv::COLOR_BGR2Luv); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUBGR2YUV, cv::gapi::imgproc::GBGR2YUV) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Mat &out) |
||||
{ |
||||
cv::cvtColor(in, out, cv::COLOR_BGR2YUV); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPULUV2BGR, cv::gapi::imgproc::GLUV2BGR) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Mat &out) |
||||
{ |
||||
cv::cvtColor(in, out, cv::COLOR_Luv2BGR); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUYUV2BGR, cv::gapi::imgproc::GYUV2BGR) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Mat &out) |
||||
{ |
||||
cv::cvtColor(in, out, cv::COLOR_YUV2BGR); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPURGB2Gray, cv::gapi::imgproc::GRGB2Gray) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Mat &out) |
||||
{ |
||||
cv::cvtColor(in, out, cv::COLOR_RGB2GRAY); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPUBGR2Gray, cv::gapi::imgproc::GBGR2Gray) |
||||
{ |
||||
static void run(const cv::Mat& in, cv::Mat &out) |
||||
{ |
||||
cv::cvtColor(in, out, cv::COLOR_BGR2GRAY); |
||||
} |
||||
}; |
||||
|
||||
GAPI_OCV_KERNEL(GCPURGB2GrayCustom, cv::gapi::imgproc::GRGB2GrayCustom) |
||||
{ |
||||
static void run(const cv::Mat& in, float rY, float bY, float gY, cv::Mat &out) |
||||
{ |
||||
cv::Mat planes[3]; |
||||
cv::split(in, planes); |
||||
out = planes[0]*rY + planes[1]*bY + planes[2]*gY; |
||||
} |
||||
}; |
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::imgproc::cpu::kernels() |
||||
{ |
||||
static auto pkg = cv::gapi::kernels |
||||
< GCPUFilter2D |
||||
, GCPUSepFilter |
||||
, GCPUBoxFilter |
||||
, GCPUBlur |
||||
, GCPUGaussBlur |
||||
, GCPUMedianBlur |
||||
, GCPUErode |
||||
, GCPUDilate |
||||
, GCPUSobel |
||||
, GCPUCanny |
||||
, GCPUEqualizeHist |
||||
, GCPURGB2YUV |
||||
, GCPUYUV2RGB |
||||
, GCPURGB2Lab |
||||
, GCPUBGR2LUV |
||||
, GCPUBGR2YUV |
||||
, GCPUYUV2BGR |
||||
, GCPULUV2BGR |
||||
, GCPUBGR2Gray |
||||
, GCPURGB2Gray |
||||
, GCPURGB2GrayCustom |
||||
>(); |
||||
return pkg; |
||||
} |
@ -0,0 +1,23 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GCPUIMGPROC_HPP |
||||
#define OPENCV_GAPI_GCPUIMGPROC_HPP |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
|
||||
#include "opencv2/gapi/cpu/gcpukernel.hpp" |
||||
|
||||
namespace cv { namespace gimpl { |
||||
|
||||
// NB: This is what a "Kernel Package" from the origianl Wiki doc should be.
|
||||
void loadCPUImgProc(std::map<std::string, cv::GCPUKernel> &kmap); |
||||
|
||||
}} |
||||
|
||||
#endif // OPENCV_GAPI_GCPUIMGPROC_HPP
|
@ -0,0 +1,50 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include <cassert> |
||||
|
||||
#include "opencv2/gapi/cpu/gcpukernel.hpp" |
||||
|
||||
const cv::gapi::own::Mat& cv::GCPUContext::inMat(int input) |
||||
{ |
||||
return inArg<cv::gapi::own::Mat>(input); |
||||
} |
||||
|
||||
cv::gapi::own::Mat& cv::GCPUContext::outMatR(int output) |
||||
{ |
||||
return *util::get<cv::gapi::own::Mat*>(m_results.at(output)); |
||||
} |
||||
|
||||
const cv::gapi::own::Scalar& cv::GCPUContext::inVal(int input) |
||||
{ |
||||
return inArg<cv::gapi::own::Scalar>(input); |
||||
} |
||||
|
||||
cv::gapi::own::Scalar& cv::GCPUContext::outValR(int output) |
||||
{ |
||||
return *util::get<cv::gapi::own::Scalar*>(m_results.at(output)); |
||||
} |
||||
|
||||
cv::detail::VectorRef& cv::GCPUContext::outVecRef(int output) |
||||
{ |
||||
return util::get<cv::detail::VectorRef>(m_results.at(output)); |
||||
} |
||||
|
||||
cv::GCPUKernel::GCPUKernel() |
||||
{ |
||||
} |
||||
|
||||
cv::GCPUKernel::GCPUKernel(const GCPUKernel::F &f) |
||||
: m_f(f) |
||||
{ |
||||
} |
||||
|
||||
void cv::GCPUKernel::apply(GCPUContext &ctx) |
||||
{ |
||||
GAPI_Assert(m_f); |
||||
m_f(ctx); |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,128 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_FLUID_BACKEND_HPP |
||||
#define OPENCV_GAPI_FLUID_BACKEND_HPP |
||||
|
||||
#include "opencv2/gapi/garg.hpp" |
||||
#include "opencv2/gapi/gproto.hpp" |
||||
#include "opencv2/gapi/fluid/gfluidkernel.hpp" |
||||
#include "opencv2/gapi/fluid/gfluidbuffer.hpp" |
||||
|
||||
// PRIVATE STUFF!
|
||||
#include "backends/common/gbackend.hpp" |
||||
#include "compiler/gislandmodel.hpp" |
||||
|
||||
namespace cv { namespace gimpl { |
||||
|
||||
struct FluidUnit |
||||
{ |
||||
static const char *name() { return "FluidKernel"; } |
||||
GFluidKernel k; |
||||
gapi::fluid::BorderOpt border; |
||||
int border_size; |
||||
int line_consumption; |
||||
double ratio; |
||||
}; |
||||
|
||||
struct FluidUseOwnBorderBuffer |
||||
{ |
||||
static const char *name() { return "FluidUseOwnBorderBuffer"; } |
||||
bool use; |
||||
}; |
||||
|
||||
struct FluidData |
||||
{ |
||||
static const char *name() { return "FluidData"; } |
||||
|
||||
// FIXME: This structure starts looking like "FluidBuffer" meta
|
||||
int latency = 0; |
||||
int skew = 0; |
||||
int max_consumption = 1; |
||||
int border_size = 0; |
||||
int lpi_write = 1; |
||||
gapi::fluid::BorderOpt border; |
||||
}; |
||||
|
||||
struct FluidAgent |
||||
{ |
||||
public: |
||||
virtual ~FluidAgent() = default; |
||||
FluidAgent(const ade::Graph &g, ade::NodeHandle nh); |
||||
|
||||
GFluidKernel k; |
||||
ade::NodeHandle op_handle; // FIXME: why it is here??//
|
||||
std::string op_name; |
||||
|
||||
// < 0 - not a buffer
|
||||
// >= 0 - a buffer with RcID
|
||||
std::vector<int> in_buffer_ids; |
||||
std::vector<int> out_buffer_ids; |
||||
|
||||
cv::GArgs in_args; |
||||
std::vector<cv::gapi::fluid::View> in_views; // sparce list of IN views
|
||||
std::vector<cv::gapi::fluid::Buffer*> out_buffers; |
||||
|
||||
// FIXME Current assumption is that outputs have EQUAL SIZES
|
||||
int m_outputLines = 0; |
||||
int m_producedLines = 0; |
||||
|
||||
double m_ratio = 0.0f; |
||||
|
||||
// Execution methods
|
||||
void reset(); |
||||
bool canWork() const; |
||||
bool canRead() const; |
||||
bool canWrite() const; |
||||
void doWork(); |
||||
bool done() const; |
||||
|
||||
void debug(std::ostream& os); |
||||
|
||||
private: |
||||
// FIXME!!!
|
||||
// move to another class
|
||||
virtual int firstWindow() const = 0; |
||||
virtual int nextWindow() const = 0; |
||||
virtual int linesRead() const = 0; |
||||
}; |
||||
|
||||
class GFluidExecutable final: public GIslandExecutable |
||||
{ |
||||
const ade::Graph &m_g; |
||||
GModel::ConstGraph m_gm; |
||||
|
||||
std::vector<std::unique_ptr<FluidAgent>> m_agents; |
||||
std::vector<cv::gapi::fluid::Buffer> m_buffers; |
||||
|
||||
using Magazine = detail::magazine<cv::gapi::own::Scalar>; |
||||
Magazine m_res; |
||||
|
||||
std::size_t m_num_int_buffers; // internal buffers counter (m_buffers - num_scratch)
|
||||
std::vector<std::size_t> m_scratch_users; |
||||
std::vector<cv::gapi::fluid::View> m_views; |
||||
|
||||
std::vector<cv::gapi::own::Rect> m_outputRois; |
||||
|
||||
std::unordered_map<int, std::size_t> m_id_map; // GMat id -> buffer idx map
|
||||
|
||||
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); |
||||
|
||||
public: |
||||
GFluidExecutable(const ade::Graph &g, |
||||
const std::vector<ade::NodeHandle> &nodes, |
||||
const std::vector<cv::gapi::own::Rect> &outputRois); |
||||
|
||||
virtual void run(std::vector<InObj> &&input_objs, |
||||
std::vector<OutObj> &&output_objs) override; |
||||
}; |
||||
}} // cv::gimpl
|
||||
|
||||
|
||||
#endif // OPENCV_GAPI_FLUID_BACKEND_HPP
|
@ -0,0 +1,746 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include <iomanip> // hex, dec (debug) |
||||
|
||||
#include "opencv2/gapi/own/convert.hpp" |
||||
|
||||
#include "opencv2/gapi/fluid/gfluidbuffer.hpp" |
||||
#include "backends/fluid/gfluidbuffer_priv.hpp" |
||||
#include "opencv2/gapi/opencv_includes.hpp" |
||||
|
||||
#include "backends/fluid/gfluidutils.hpp" // saturate |
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
|
||||
namespace fluid { |
||||
bool operator == (const fluid::Border& b1, const fluid::Border& b2) |
||||
{ |
||||
return b1.type == b2.type && b1.value == b2.value; |
||||
} |
||||
} // namespace fluid
|
||||
|
||||
// Fluid BorderHandler implementation /////////////////////////////////////////////////
|
||||
|
||||
namespace { |
||||
template<typename T> |
||||
// Expected inputs:
|
||||
// row - row buffer allocated with border in mind (have memory for both image and border pixels)
|
||||
// length - size of the buffer with left and right borders included
|
||||
void fillBorderReplicateRow(uint8_t* row, int length, int chan, int borderSize) |
||||
{ |
||||
auto leftBorder = reinterpret_cast<T*>(row); |
||||
auto rightBorder = leftBorder + (length - borderSize) * chan; |
||||
for (int b = 0; b < borderSize; b++) |
||||
{ |
||||
for (int c = 0; c < chan; c++) |
||||
{ |
||||
leftBorder [b*chan + c] = leftBorder [borderSize*chan + c]; |
||||
rightBorder[b*chan + c] = rightBorder[-chan + c]; |
||||
} |
||||
} |
||||
} |
||||
|
||||
template<typename T> |
||||
void fillBorderReflectRow(uint8_t* row, int length, int chan, int borderSize) |
||||
{ |
||||
auto leftBorder = reinterpret_cast<T*>(row); |
||||
auto rightBorder = leftBorder + (length - borderSize) * chan; |
||||
for (int b = 0; b < borderSize; b++) |
||||
{ |
||||
for (int c = 0; c < chan; c++) |
||||
{ |
||||
leftBorder [b*chan + c] = leftBorder [(2*borderSize - b)*chan + c]; |
||||
rightBorder[b*chan + c] = rightBorder[(-b - 2)*chan + c]; |
||||
} |
||||
} |
||||
} |
||||
|
||||
template<typename T> |
||||
void fillConstBorderRow(uint8_t* row, int length, int chan, int borderSize, cv::gapi::own::Scalar borderValue) |
||||
{ |
||||
GAPI_DbgAssert(chan > 0 && chan <= 4); |
||||
|
||||
auto leftBorder = reinterpret_cast<T*>(row); |
||||
auto rightBorder = leftBorder + (length - borderSize) * chan; |
||||
for (int b = 0; b < borderSize; b++) |
||||
{ |
||||
for (int c = 0; c < chan; c++) |
||||
{ |
||||
leftBorder [b*chan + c] = fluid::saturate<T>(borderValue[c], fluid::roundd); |
||||
rightBorder[b*chan + c] = fluid::saturate<T>(borderValue[c], fluid::roundd); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Fills const border pixels in the whole mat
|
||||
void fillBorderConstant(int borderSize, cv::gapi::own::Scalar borderValue, cv::Mat& mat) |
||||
{ |
||||
// cv::Scalar can contain maximum 4 chan
|
||||
GAPI_Assert(mat.channels() > 0 && mat.channels() <= 4); |
||||
|
||||
auto getFillBorderRowFunc = [&](int type) { |
||||
switch(type) |
||||
{ |
||||
case CV_8U: return &fillConstBorderRow< uint8_t>; break; |
||||
case CV_16S: return &fillConstBorderRow< int16_t>; break; |
||||
case CV_16U: return &fillConstBorderRow<uint16_t>; break; |
||||
case CV_32F: return &fillConstBorderRow< float >; break; |
||||
default: CV_Assert(false); return &fillConstBorderRow<uint8_t>; |
||||
} |
||||
}; |
||||
|
||||
auto fillBorderRow = getFillBorderRowFunc(mat.depth()); |
||||
for (int y = 0; y < mat.rows; y++) |
||||
{ |
||||
fillBorderRow(mat.ptr(y), mat.cols, mat.channels(), borderSize, borderValue); |
||||
} |
||||
} |
||||
} // anonymous namespace
|
||||
|
||||
fluid::BorderHandler::BorderHandler(int border_size) |
||||
{ |
||||
CV_Assert(border_size > 0); |
||||
m_border_size = border_size; |
||||
} |
||||
|
||||
template <int BorderType> |
||||
fluid::BorderHandlerT<BorderType>::BorderHandlerT(int border_size, int data_type) |
||||
: BorderHandler(border_size) |
||||
{ |
||||
auto getFillBorderRowFunc = [&](int border, int dataType) { |
||||
if (border == cv::BORDER_REPLICATE) |
||||
{ |
||||
switch(dataType) |
||||
{ |
||||
case CV_8U: return &fillBorderReplicateRow< uint8_t>; break; |
||||
case CV_16S: return &fillBorderReplicateRow< int16_t>; break; |
||||
case CV_16U: return &fillBorderReplicateRow<uint16_t>; break; |
||||
case CV_32F: return &fillBorderReplicateRow< float >; break; |
||||
default: CV_Assert(!"Unsupported data type"); return &fillBorderReplicateRow<uint8_t>; |
||||
} |
||||
} |
||||
else if (border == cv::BORDER_REFLECT_101) |
||||
{ |
||||
switch(dataType) |
||||
{ |
||||
case CV_8U: return &fillBorderReflectRow< uint8_t>; break; |
||||
case CV_16S: return &fillBorderReflectRow< int16_t>; break; |
||||
case CV_16U: return &fillBorderReflectRow<uint16_t>; break; |
||||
case CV_32F: return &fillBorderReflectRow< float >; break; |
||||
default: CV_Assert(!"Unsupported data type"); return &fillBorderReflectRow<uint8_t>; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
CV_Assert(!"Unsupported border type"); |
||||
return &fillBorderReflectRow<uint8_t>; |
||||
} |
||||
}; |
||||
|
||||
m_fill_border_row = getFillBorderRowFunc(BorderType, data_type); |
||||
} |
||||
|
||||
namespace { |
||||
template <int BorderType> int getBorderIdx(int log_idx, int desc_height); |
||||
|
||||
template<> int getBorderIdx<cv::BORDER_REPLICATE>(int log_idx, int desc_height) |
||||
{ |
||||
return log_idx < 0 ? 0 : desc_height - 1; |
||||
} |
||||
|
||||
template<> int getBorderIdx<cv::BORDER_REFLECT_101>(int log_idx, int desc_height) |
||||
{ |
||||
return log_idx < 0 ? -log_idx : 2*(desc_height - 1) - log_idx; |
||||
} |
||||
} // namespace
|
||||
|
||||
template <int BorderType> |
||||
const uint8_t* fluid::BorderHandlerT<BorderType>::inLineB(int log_idx, const BufferStorageWithBorder& data, int desc_height) const |
||||
{ |
||||
auto idx = getBorderIdx<BorderType>(log_idx, desc_height); |
||||
return data.ptr(idx); |
||||
} |
||||
|
||||
fluid::BorderHandlerT<cv::BORDER_CONSTANT>::BorderHandlerT(int border_size, cv::gapi::own::Scalar border_value, int data_type, int desc_width) |
||||
: BorderHandler(border_size), m_border_value(border_value) |
||||
{ |
||||
m_const_border.create(1, desc_width + 2*m_border_size, data_type); |
||||
m_const_border = cv::gapi::own::to_ocv(border_value); |
||||
} |
||||
|
||||
const uint8_t* fluid::BorderHandlerT<cv::BORDER_CONSTANT>::inLineB(int /*log_idx*/, const BufferStorageWithBorder& /*data*/, int /*desc_height*/) const |
||||
{ |
||||
return m_const_border.ptr(0, m_border_size); |
||||
} |
||||
|
||||
void fluid::BorderHandlerT<cv::BORDER_CONSTANT>::fillCompileTimeBorder(BufferStorageWithBorder& data) const |
||||
{ |
||||
cv::gapi::fillBorderConstant(m_border_size, m_border_value, data.data()); |
||||
} |
||||
|
||||
template <int BorderType> |
||||
void fluid::BorderHandlerT<BorderType>::updateBorderPixels(BufferStorageWithBorder &data, int startLine, int nLines) const |
||||
{ |
||||
auto& mat = data.data(); |
||||
auto length = mat.cols; |
||||
auto chan = mat.channels(); |
||||
|
||||
for (int l = startLine; l < startLine + nLines; l++) |
||||
{ |
||||
auto row = mat.ptr(data.physIdx(l)); |
||||
m_fill_border_row(row, length, chan, m_border_size); |
||||
} |
||||
} |
||||
|
||||
std::size_t fluid::BorderHandlerT<cv::BORDER_CONSTANT>::size() const |
||||
{ |
||||
return m_const_border.total() * m_const_border.elemSize(); |
||||
} |
||||
|
||||
// Fluid BufferStorage implementation //////////////////////////////////////////
|
||||
void fluid::BufferStorageWithBorder::create(int capacity, int desc_width, int dtype, int border_size, Border border) |
||||
{ |
||||
auto width = (desc_width + 2*border_size); |
||||
m_data.create(capacity, width, dtype); |
||||
|
||||
switch(border.type) |
||||
{ |
||||
case cv::BORDER_CONSTANT: |
||||
m_borderHandler.reset(new BorderHandlerT<cv::BORDER_CONSTANT>(border_size, border.value, dtype, desc_width)); break; |
||||
case cv::BORDER_REPLICATE: |
||||
m_borderHandler.reset(new BorderHandlerT<cv::BORDER_REPLICATE>(border_size, dtype)); break; |
||||
case cv::BORDER_REFLECT_101: |
||||
m_borderHandler.reset(new BorderHandlerT<cv::BORDER_REFLECT_101>(border_size, dtype)); break; |
||||
default: |
||||
CV_Assert(false); |
||||
} |
||||
|
||||
m_borderHandler->fillCompileTimeBorder(*this); |
||||
} |
||||
|
||||
void fluid::BufferStorageWithoutBorder::create(int capacity, int desc_width, int dtype) |
||||
{ |
||||
auto width = desc_width; |
||||
m_data.create(capacity, width, dtype); |
||||
|
||||
m_is_virtual = true; |
||||
} |
||||
|
||||
const uint8_t* fluid::BufferStorageWithBorder::inLineB(int log_idx, int desc_height) const |
||||
{ |
||||
if (log_idx < 0 || log_idx >= desc_height) |
||||
{ |
||||
return m_borderHandler->inLineB(log_idx, *this, desc_height); |
||||
} |
||||
else |
||||
{ |
||||
return ptr(log_idx); |
||||
} |
||||
} |
||||
|
||||
const uint8_t* fluid::BufferStorageWithoutBorder::inLineB(int log_idx, int /*desc_height*/) const |
||||
{ |
||||
return ptr(log_idx); |
||||
} |
||||
|
||||
static void copyWithoutBorder(const cv::Mat& src, int src_border_size, cv::Mat& dst, int dst_border_size, int startSrcLine, int startDstLine, int lpi) |
||||
{ |
||||
// FIXME use cv::gapi::own::Rect when implement cv::gapi::own::Mat
|
||||
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}); |
||||
|
||||
subSrc.copyTo(subDst); |
||||
} |
||||
|
||||
void fluid::BufferStorageWithoutBorder::copyTo(BufferStorageWithBorder &dst, int startLine, int nLines) const |
||||
{ |
||||
for (int l = startLine; l < startLine + nLines; l++) |
||||
{ |
||||
copyWithoutBorder(m_data, 0, dst.data(), dst.borderSize(), physIdx(l), dst.physIdx(l), 1); |
||||
} |
||||
} |
||||
|
||||
void fluid::BufferStorageWithBorder::copyTo(BufferStorageWithBorder &dst, int startLine, int nLines) const |
||||
{ |
||||
// Copy required lpi lines line by line (to avoid wrap if invoked for multiple lines)
|
||||
for (int l = startLine; l < startLine + nLines; l++) |
||||
{ |
||||
copyWithoutBorder(m_data, borderSize(), dst.data(), dst.borderSize(), physIdx(l), dst.physIdx(l), 1); |
||||
} |
||||
} |
||||
|
||||
// FIXME? remember parent and remove src parameter?
|
||||
void fluid::BufferStorageWithBorder::updateBeforeRead(int startLine, int nLines, const BufferStorage& src) |
||||
{ |
||||
// TODO:
|
||||
// Cover with tests!!
|
||||
// (Ensure that there are no redundant copies done
|
||||
// and only required (not fetched before) lines are copied)
|
||||
|
||||
GAPI_DbgAssert(startLine >= 0); |
||||
|
||||
src.copyTo(*this, startLine, nLines); |
||||
m_borderHandler->updateBorderPixels(*this, startLine, nLines); |
||||
} |
||||
|
||||
void fluid::BufferStorageWithoutBorder::updateBeforeRead(int /*startLine*/, int /*lpi*/, const BufferStorage& /*src*/) |
||||
{ |
||||
/* nothing */ |
||||
} |
||||
|
||||
void fluid::BufferStorageWithBorder::updateAfterWrite(int startLine, int nLines) |
||||
{ |
||||
// FIXME?
|
||||
// Actually startLine + nLines can be > logical height so
|
||||
// redundant end lines which will never be read
|
||||
// can be filled in the ring buffer
|
||||
m_borderHandler->updateBorderPixels(*this, startLine, nLines); |
||||
} |
||||
|
||||
void fluid::BufferStorageWithoutBorder::updateAfterWrite(int /*startLine*/, int /*lpi*/) |
||||
{ |
||||
/* nothing */ |
||||
} |
||||
|
||||
size_t fluid::BufferStorageWithBorder::size() const |
||||
{ |
||||
return m_data.total()*m_data.elemSize() + m_borderHandler->size(); |
||||
} |
||||
|
||||
size_t fluid::BufferStorageWithoutBorder::size() const |
||||
{ |
||||
return m_data.total()*m_data.elemSize(); |
||||
} |
||||
|
||||
namespace fluid { |
||||
namespace { |
||||
std::unique_ptr<fluid::BufferStorage> createStorage(int capacity, int desc_width, int type, |
||||
int border_size, fluid::BorderOpt border); |
||||
std::unique_ptr<fluid::BufferStorage> createStorage(int capacity, int desc_width, int type, |
||||
int border_size, fluid::BorderOpt border) |
||||
{ |
||||
if (border) |
||||
{ |
||||
std::unique_ptr<fluid::BufferStorageWithBorder> storage(new BufferStorageWithBorder); |
||||
storage->create(capacity, desc_width, type, border_size, border.value()); |
||||
return std::move(storage); |
||||
} |
||||
|
||||
std::unique_ptr<BufferStorageWithoutBorder> storage(new BufferStorageWithoutBorder); |
||||
storage->create(capacity, desc_width, type); |
||||
return std::move(storage); |
||||
} |
||||
|
||||
std::unique_ptr<BufferStorage> createStorage(const cv::Mat& data, cv::gapi::own::Rect roi); |
||||
std::unique_ptr<BufferStorage> createStorage(const cv::Mat& data, cv::gapi::own::Rect roi) |
||||
{ |
||||
std::unique_ptr<BufferStorageWithoutBorder> storage(new BufferStorageWithoutBorder); |
||||
storage->attach(data, roi); |
||||
return std::move(storage); |
||||
} |
||||
} // namespace
|
||||
} // namespace fluid
|
||||
|
||||
// Fluid View implementation ///////////////////////////////////////////////////
|
||||
|
||||
void fluid::View::Priv::reset(int linesForFirstIteration) |
||||
{ |
||||
GAPI_DbgAssert(m_p); |
||||
|
||||
m_lines_next_iter = linesForFirstIteration; |
||||
m_read_caret = m_p->priv().readStart(); |
||||
} |
||||
|
||||
void fluid::View::Priv::readDone(int linesRead, int linesForNextIteration) |
||||
{ |
||||
CV_DbgAssert(m_p); |
||||
m_read_caret += linesRead; |
||||
m_read_caret %= m_p->meta().size.height; |
||||
m_lines_next_iter = linesForNextIteration; |
||||
} |
||||
|
||||
bool fluid::View::Priv::ready() const |
||||
{ |
||||
auto lastWrittenLine = m_p->priv().writeStart() + m_p->linesReady(); |
||||
// + bottom border
|
||||
if (lastWrittenLine == m_p->meta().size.height) lastWrittenLine += m_border_size; |
||||
// + top border
|
||||
lastWrittenLine += m_border_size; |
||||
|
||||
auto lastRequiredLine = m_read_caret + m_lines_next_iter; |
||||
|
||||
return lastWrittenLine >= lastRequiredLine; |
||||
} |
||||
|
||||
fluid::ViewPrivWithoutOwnBorder::ViewPrivWithoutOwnBorder(const Buffer *parent, int borderSize) |
||||
{ |
||||
CV_Assert(parent); |
||||
m_p = parent; |
||||
m_border_size = borderSize; |
||||
} |
||||
|
||||
const uint8_t* fluid::ViewPrivWithoutOwnBorder::InLineB(int index) const |
||||
{ |
||||
GAPI_DbgAssert(m_p); |
||||
|
||||
const auto &p_priv = m_p->priv(); |
||||
|
||||
CV_Assert( index >= -m_border_size |
||||
&& index < -m_border_size + m_lines_next_iter); |
||||
|
||||
const int log_idx = m_read_caret + index; |
||||
|
||||
return p_priv.storage().inLineB(log_idx, m_p->meta().size.height); |
||||
} |
||||
|
||||
fluid::ViewPrivWithOwnBorder::ViewPrivWithOwnBorder(const Buffer *parent, int lineConsumption, int borderSize, Border border) |
||||
{ |
||||
GAPI_Assert(parent); |
||||
m_p = parent; |
||||
m_border_size = borderSize; |
||||
|
||||
auto desc = m_p->meta(); |
||||
int type = CV_MAKETYPE(desc.depth, desc.chan); |
||||
m_own_storage.create(lineConsumption, desc.size.width, type, borderSize, border); |
||||
} |
||||
|
||||
void fluid::ViewPrivWithOwnBorder::prepareToRead() |
||||
{ |
||||
int startLine = 0; |
||||
int nLines = 0; |
||||
|
||||
if (m_read_caret == m_p->priv().readStart()) |
||||
{ |
||||
// Need to fetch full window on the first iteration
|
||||
startLine = (m_read_caret > m_border_size) ? m_read_caret - m_border_size : 0; |
||||
nLines = m_lines_next_iter; |
||||
} |
||||
else |
||||
{ |
||||
startLine = m_read_caret + m_border_size; |
||||
nLines = m_lines_next_iter - 2*m_border_size; |
||||
} |
||||
|
||||
m_own_storage.updateBeforeRead(startLine, nLines, m_p->priv().storage()); |
||||
} |
||||
|
||||
std::size_t fluid::ViewPrivWithOwnBorder::size() const |
||||
{ |
||||
GAPI_DbgAssert(m_p); |
||||
return m_own_storage.size(); |
||||
} |
||||
|
||||
const uint8_t* fluid::ViewPrivWithOwnBorder::InLineB(int index) const |
||||
{ |
||||
GAPI_DbgAssert(m_p); |
||||
|
||||
GAPI_Assert( index >= -m_border_size |
||||
&& index < -m_border_size + m_lines_next_iter); |
||||
|
||||
const int log_idx = m_read_caret + index; |
||||
|
||||
return m_own_storage.inLineB(log_idx, m_p->meta().size.height); |
||||
} |
||||
|
||||
const uint8_t* fluid::View::InLineB(int index) const |
||||
{ |
||||
return m_priv->InLineB(index); |
||||
} |
||||
|
||||
fluid::View::operator bool() const |
||||
{ |
||||
return m_priv != nullptr && m_priv->m_p != nullptr; |
||||
} |
||||
|
||||
int fluid::View::length() const |
||||
{ |
||||
return m_priv->m_p->length(); |
||||
} |
||||
|
||||
bool fluid::View::ready() const |
||||
{ |
||||
return m_priv->ready(); |
||||
} |
||||
|
||||
int fluid::View::y() const |
||||
{ |
||||
return m_priv->m_read_caret - m_priv->m_border_size; |
||||
} |
||||
|
||||
cv::GMatDesc fluid::View::meta() const |
||||
{ |
||||
// FIXME: cover with test!
|
||||
return m_priv->m_p->meta(); |
||||
} |
||||
|
||||
fluid::View::Priv& fluid::View::priv() |
||||
{ |
||||
return *m_priv; |
||||
} |
||||
|
||||
const fluid::View::Priv& fluid::View::priv() const |
||||
{ |
||||
return *m_priv; |
||||
} |
||||
|
||||
// Fluid Buffer implementation /////////////////////////////////////////////////
|
||||
|
||||
fluid::Buffer::Priv::Priv(int read_start, cv::gapi::own::Rect roi) |
||||
: m_readStart(read_start) |
||||
, m_roi(roi) |
||||
{} |
||||
|
||||
void fluid::Buffer::Priv::init(const cv::GMatDesc &desc, |
||||
int line_consumption, |
||||
int border_size, |
||||
int skew, |
||||
int wlpi, |
||||
int readStartPos, |
||||
cv::gapi::own::Rect roi) |
||||
{ |
||||
GAPI_Assert(m_line_consumption == -1); |
||||
GAPI_Assert(line_consumption > 0); |
||||
|
||||
m_line_consumption = line_consumption; |
||||
m_border_size = border_size; |
||||
m_skew = skew; |
||||
m_writer_lpi = wlpi; |
||||
m_desc = desc; |
||||
m_readStart = readStartPos; |
||||
m_roi = roi; |
||||
} |
||||
|
||||
void fluid::Buffer::Priv::allocate(BorderOpt border) |
||||
{ |
||||
GAPI_Assert(!m_storage); |
||||
|
||||
// Init physical buffer
|
||||
|
||||
// FIXME? combine with skew?
|
||||
auto maxRead = m_line_consumption + m_skew; |
||||
auto maxWritten = m_writer_lpi; |
||||
|
||||
auto max = std::max(maxRead, maxWritten); |
||||
auto min = std::min(maxRead, maxWritten); |
||||
|
||||
// FIXME:
|
||||
// Fix the deadlock (completely)!!!
|
||||
auto data_height = static_cast<int>(std::ceil((double)max / min) * min); |
||||
|
||||
m_storage = createStorage(data_height, |
||||
m_desc.size.width, |
||||
CV_MAKETYPE(m_desc.depth, m_desc.chan), |
||||
m_border_size, |
||||
border); |
||||
|
||||
// Finally, initialize carets
|
||||
m_write_caret = 0; |
||||
} |
||||
|
||||
void fluid::Buffer::Priv::bindTo(const cv::Mat &data, bool is_input) |
||||
{ |
||||
// FIXME: move all these fields into a separate structure
|
||||
GAPI_Assert(m_skew == 0); |
||||
GAPI_Assert(m_desc == cv::descr_of(data)); |
||||
if ( is_input) CV_Assert(m_writer_lpi == 1); |
||||
|
||||
m_storage = createStorage(data, m_roi); |
||||
|
||||
m_is_input = is_input; |
||||
m_write_caret = is_input ? writeEnd(): writeStart(); |
||||
// NB: views remain the same!
|
||||
} |
||||
|
||||
bool fluid::Buffer::Priv::full() const |
||||
{ |
||||
int slowest_y = writeEnd(); |
||||
if (!m_views.empty()) |
||||
{ |
||||
// 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()); |
||||
} |
||||
|
||||
return m_write_caret + lpi() - slowest_y > m_storage->rows(); |
||||
} |
||||
|
||||
void fluid::Buffer::Priv::writeDone() |
||||
{ |
||||
// There are possible optimizations which can be done to fill a border values
|
||||
// in compile time of the graph (for example border is const),
|
||||
// so there is no need to update border values after each write.
|
||||
// If such optimizations weren't applied, fill border for lines
|
||||
// which have been just written
|
||||
m_storage->updateAfterWrite(m_write_caret, m_writer_lpi); |
||||
|
||||
// Final write may produce less LPI, so
|
||||
// write caret may exceed logical buffer size
|
||||
m_write_caret += m_writer_lpi; |
||||
// FIXME: add consistency check!
|
||||
} |
||||
|
||||
void fluid::Buffer::Priv::reset() |
||||
{ |
||||
m_write_caret = m_is_input ? writeEnd() : writeStart(); |
||||
} |
||||
|
||||
int fluid::Buffer::Priv::size() const |
||||
{ |
||||
std::size_t view_sz = 0; |
||||
for (const auto &v : m_views) view_sz += v.priv().size(); |
||||
|
||||
auto total = view_sz; |
||||
if (m_storage) total += m_storage->size(); |
||||
|
||||
// FIXME: Change API to return size_t!!!
|
||||
return static_cast<int>(total); |
||||
} |
||||
|
||||
int fluid::Buffer::Priv::linesReady() const |
||||
{ |
||||
if (m_is_input) |
||||
{ |
||||
return m_storage->rows(); |
||||
} |
||||
else |
||||
{ |
||||
const int writes = std::min(m_write_caret - writeStart(), outputLines()); |
||||
return writes; |
||||
} |
||||
} |
||||
|
||||
uint8_t* fluid::Buffer::Priv::OutLineB(int index) |
||||
{ |
||||
GAPI_Assert(index >= 0 && index < m_writer_lpi); |
||||
|
||||
return m_storage->ptr(m_write_caret + index); |
||||
} |
||||
|
||||
int fluid::Buffer::Priv::lpi() const |
||||
{ |
||||
// FIXME:
|
||||
// m_write_caret can be greater than m_writeRoi.y + m_writeRoi.height, so return value can be negative !!!
|
||||
return std::min(writeEnd() - m_write_caret, m_writer_lpi); |
||||
} |
||||
|
||||
fluid::Buffer::Buffer() |
||||
: m_priv(new Priv()) |
||||
{ |
||||
} |
||||
|
||||
fluid::Buffer::Buffer(const cv::GMatDesc &desc) |
||||
: m_priv(new Priv()) |
||||
{ |
||||
int lineConsumption = 1; |
||||
int border = 0, skew = 0, wlpi = 1, readStart = 0; |
||||
cv::gapi::own::Rect roi = {0, 0, desc.size.width, desc.size.height}; |
||||
m_priv->init(desc, lineConsumption, border, skew, wlpi, readStart, roi); |
||||
m_priv->allocate({}); |
||||
} |
||||
|
||||
fluid::Buffer::Buffer(const cv::GMatDesc &desc, |
||||
int max_line_consumption, |
||||
int border_size, |
||||
int skew, |
||||
int wlpi, |
||||
BorderOpt border) |
||||
: m_priv(new Priv()) |
||||
{ |
||||
int readStart = 0; |
||||
cv::gapi::own::Rect roi = {0, 0, desc.size.width, desc.size.height}; |
||||
m_priv->init(desc, max_line_consumption, border_size, skew, wlpi, readStart, roi); |
||||
m_priv->allocate(border); |
||||
} |
||||
|
||||
fluid::Buffer::Buffer(const cv::Mat &data, bool is_input) |
||||
: m_priv(new Priv()) |
||||
{ |
||||
int lineConsumption = 1; |
||||
int border = 0, skew = 0, wlpi = 1, readStart = 0; |
||||
cv::gapi::own::Rect roi{0, 0, data.cols, data.rows}; |
||||
m_priv->init(descr_of(data), lineConsumption, border, skew, wlpi, readStart, roi); |
||||
m_priv->bindTo(data, is_input); |
||||
} |
||||
|
||||
uint8_t* fluid::Buffer::Buffer::OutLineB(int index) |
||||
{ |
||||
return m_priv->OutLineB(index); |
||||
} |
||||
|
||||
int fluid::Buffer::linesReady() const |
||||
{ |
||||
return m_priv->linesReady(); |
||||
} |
||||
|
||||
int fluid::Buffer::length() const |
||||
{ |
||||
return meta().size.width; |
||||
} |
||||
|
||||
int fluid::Buffer::lpi() const |
||||
{ |
||||
return m_priv->lpi(); |
||||
} |
||||
|
||||
cv::GMatDesc fluid::Buffer::meta() const |
||||
{ |
||||
return m_priv->meta(); |
||||
} |
||||
|
||||
fluid::View::View(Priv* p) |
||||
: m_priv(p) |
||||
{ /* nothing */ } |
||||
|
||||
fluid::View fluid::Buffer::mkView(int lineConsumption, int borderSize, BorderOpt border, bool ownStorage) |
||||
{ |
||||
// FIXME: logic outside of Priv (because View takes pointer to Buffer)
|
||||
auto view = ownStorage ? View(new ViewPrivWithOwnBorder(this, lineConsumption, borderSize, border.value())) |
||||
: View(new ViewPrivWithoutOwnBorder(this, borderSize)); |
||||
m_priv->addView(view); |
||||
return view; |
||||
} |
||||
|
||||
void fluid::debugBufferPriv(const fluid::Buffer& buffer, std::ostream &os) |
||||
{ |
||||
// FIXME Use cv::gapi::own Size and Rect with operator<<, when merged ADE-285
|
||||
const auto& p = buffer.priv(); |
||||
os << "Fluid buffer " << std::hex << &buffer << std::dec |
||||
<< " " << p.m_desc.size.width << " x " << p.m_desc.size.height << "]" |
||||
<< " readStart:" << p.m_readStart |
||||
<< " roi:" << "[" << p.m_roi.width << " x " << p.m_roi.height << " from (" << p.m_roi.x << ", " << p.m_roi.y << ")]" |
||||
<<" (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() << " "; } |
||||
os << "], avail: " << buffer.linesReady() |
||||
<< std::endl; |
||||
} |
||||
|
||||
void fluid::Buffer::debug(std::ostream &os) const |
||||
{ |
||||
debugBufferPriv(*this, os); |
||||
} |
||||
|
||||
fluid::Buffer::Priv& fluid::Buffer::priv() |
||||
{ |
||||
return *m_priv; |
||||
} |
||||
|
||||
const fluid::Buffer::Priv& fluid::Buffer::priv() const |
||||
{ |
||||
return *m_priv; |
||||
} |
||||
|
||||
int fluid::Buffer::y() const |
||||
{ |
||||
return m_priv->y(); |
||||
} |
||||
|
||||
} // namespace cv::gapi
|
||||
} // namespace cv
|
@ -0,0 +1,298 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_FLUID_BUFFER_PRIV_HPP |
||||
#define OPENCV_GAPI_FLUID_BUFFER_PRIV_HPP |
||||
|
||||
#include <vector> |
||||
|
||||
#include "opencv2/gapi/fluid/gfluidbuffer.hpp" |
||||
#include "opencv2/gapi/own/convert.hpp" // cv::gapi::own::to_ocv |
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
namespace fluid { |
||||
|
||||
class BufferStorageWithBorder; |
||||
|
||||
class BorderHandler |
||||
{ |
||||
protected: |
||||
int m_border_size; |
||||
|
||||
public: |
||||
BorderHandler(int border_size); |
||||
virtual ~BorderHandler() = default; |
||||
virtual const uint8_t* inLineB(int log_idx, const BufferStorageWithBorder &data, int desc_height) const = 0; |
||||
|
||||
// Fills border pixels after buffer allocation (if possible (for const border))
|
||||
virtual void fillCompileTimeBorder(BufferStorageWithBorder &) const { /* nothing */ } |
||||
|
||||
// Fills required border lines
|
||||
virtual void updateBorderPixels(BufferStorageWithBorder& /*data*/, int /*startLine*/, int /*lpi*/) const { /* nothing */ } |
||||
|
||||
inline int borderSize() const { return m_border_size; } |
||||
virtual std::size_t size() const { return 0; } |
||||
}; |
||||
|
||||
template<int BorderType> |
||||
class BorderHandlerT : public BorderHandler |
||||
{ |
||||
std::function<void(uint8_t*,int,int,int)> m_fill_border_row; |
||||
public: |
||||
BorderHandlerT(int border_size, int data_type); |
||||
virtual void updateBorderPixels(BufferStorageWithBorder& data, int startLine, int lpi) const override; |
||||
virtual const uint8_t* inLineB(int log_idx, const BufferStorageWithBorder &data, int desc_height) const override; |
||||
}; |
||||
|
||||
template<> |
||||
class BorderHandlerT<cv::BORDER_CONSTANT> : public BorderHandler |
||||
{ |
||||
cv::gapi::own::Scalar m_border_value; |
||||
cv::Mat m_const_border; |
||||
|
||||
public: |
||||
BorderHandlerT(int border_size, cv::gapi::own::Scalar border_value, int data_type, int desc_width); |
||||
virtual const uint8_t* inLineB(int log_idx, const BufferStorageWithBorder &data, int desc_height) const override; |
||||
virtual void fillCompileTimeBorder(BufferStorageWithBorder &) const override; |
||||
virtual std::size_t size() const override; |
||||
}; |
||||
|
||||
class BufferStorage |
||||
{ |
||||
protected: |
||||
cv::Mat m_data; |
||||
|
||||
public: |
||||
virtual void copyTo(BufferStorageWithBorder &dst, int startLine, int nLines) const = 0; |
||||
|
||||
virtual ~BufferStorage() = default; |
||||
|
||||
virtual const uint8_t* ptr(int idx) const = 0; |
||||
virtual uint8_t* ptr(int idx) = 0; |
||||
|
||||
inline bool empty() const { return m_data.empty(); } |
||||
|
||||
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; } |
||||
inline int type() const { return m_data.type(); } |
||||
|
||||
virtual const uint8_t* inLineB(int log_idx, int desc_height) const = 0; |
||||
|
||||
// FIXME? remember parent and remove src parameter?
|
||||
virtual void updateBeforeRead(int startLine, int nLines, const BufferStorage& src) = 0; |
||||
virtual void updateAfterWrite(int startLine, int nLines) = 0; |
||||
|
||||
virtual int physIdx(int logIdx) const = 0; |
||||
|
||||
virtual size_t size() const = 0; |
||||
}; |
||||
|
||||
class BufferStorageWithoutBorder final : public BufferStorage |
||||
{ |
||||
bool m_is_virtual = true; |
||||
cv::gapi::own::Rect m_roi; |
||||
|
||||
public: |
||||
virtual void copyTo(BufferStorageWithBorder &dst, int startLine, int nLines) const override; |
||||
|
||||
inline virtual const uint8_t* ptr(int idx) const override |
||||
{ |
||||
GAPI_DbgAssert((m_is_virtual && m_roi == cv::gapi::own::Rect{}) || (!m_is_virtual && m_roi != cv::gapi::own::Rect{})); |
||||
return m_data.ptr(physIdx(idx), 0); |
||||
} |
||||
inline virtual uint8_t* ptr(int idx) override |
||||
{ |
||||
GAPI_DbgAssert((m_is_virtual && m_roi == cv::gapi::own::Rect{}) || (!m_is_virtual && m_roi != cv::gapi::own::Rect{})); |
||||
return m_data.ptr(physIdx(idx), 0); |
||||
} |
||||
|
||||
inline void attach(const cv::Mat& _data, const cv::gapi::own::Rect& _roi) |
||||
{ |
||||
m_data = _data(cv::gapi::own::to_ocv(_roi)); |
||||
m_roi = _roi; |
||||
m_is_virtual = false; |
||||
} |
||||
|
||||
void create(int capacity, int desc_width, int type); |
||||
|
||||
inline virtual const uint8_t* inLineB(int log_idx, int desc_height) const override; |
||||
|
||||
virtual void updateBeforeRead(int startLine, int nLines, const BufferStorage& src) override; |
||||
virtual void updateAfterWrite(int startLine, int nLines) override; |
||||
|
||||
inline virtual int physIdx(int logIdx) const override { return (logIdx - m_roi.y) % m_data.rows; } |
||||
|
||||
virtual size_t size() const override; |
||||
}; |
||||
|
||||
class BufferStorageWithBorder final: public BufferStorage |
||||
{ |
||||
std::unique_ptr<BorderHandler> m_borderHandler; |
||||
|
||||
public: |
||||
inline int borderSize() const { return m_borderHandler->borderSize(); } |
||||
|
||||
virtual void copyTo(BufferStorageWithBorder &dst, int startLine, int nLines) const override; |
||||
|
||||
inline virtual const uint8_t* ptr(int idx) const override |
||||
{ |
||||
return m_data.ptr(physIdx(idx), borderSize()); |
||||
} |
||||
inline virtual uint8_t* ptr(int idx) override |
||||
{ |
||||
return m_data.ptr(physIdx(idx), borderSize()); |
||||
} |
||||
|
||||
void create(int capacity, int desc_width, int type, int border_size, Border border); |
||||
|
||||
virtual const uint8_t* inLineB(int log_idx, int desc_height) const override; |
||||
|
||||
virtual void updateBeforeRead(int startLine, int nLines, const BufferStorage &src) override; |
||||
virtual void updateAfterWrite(int startLine, int nLines) override; |
||||
|
||||
inline virtual int physIdx(int logIdx) const override { return logIdx % m_data.rows; } |
||||
|
||||
virtual size_t size() const override; |
||||
}; |
||||
|
||||
// FIXME: GAPI_EXPORTS is used here only to access internal methods
|
||||
// like readDone/writeDone in low-level tests
|
||||
class GAPI_EXPORTS View::Priv |
||||
{ |
||||
friend class View; |
||||
protected: |
||||
const Buffer *m_p = nullptr; // FIXME replace with weak_ptr
|
||||
int m_read_caret = -1; |
||||
int m_lines_next_iter = -1; |
||||
int m_border_size = -1; |
||||
|
||||
public: |
||||
virtual ~Priv() = default; |
||||
// API used by actors/backend
|
||||
|
||||
virtual void prepareToRead() = 0; |
||||
|
||||
void readDone(int linesRead, int linesForNextIteration); |
||||
void reset(int linesForFirstIteration); |
||||
|
||||
virtual std::size_t size() const = 0; |
||||
|
||||
// Does the view have enough unread lines for next iteration
|
||||
bool ready() const; |
||||
|
||||
// API used (indirectly) by user code
|
||||
virtual const uint8_t* InLineB(int index) const = 0; |
||||
}; |
||||
|
||||
class ViewPrivWithoutOwnBorder final : public View::Priv |
||||
{ |
||||
public: |
||||
// API used by actors/backend
|
||||
ViewPrivWithoutOwnBorder(const Buffer *p, int borderSize); |
||||
|
||||
virtual void prepareToRead() override { /* nothing */ } |
||||
|
||||
virtual std::size_t size() const override { return 0; } |
||||
|
||||
// API used (indirectly) by user code
|
||||
virtual const uint8_t* InLineB(int index) const override; |
||||
}; |
||||
|
||||
class ViewPrivWithOwnBorder final : public View::Priv |
||||
{ |
||||
BufferStorageWithBorder m_own_storage; |
||||
|
||||
public: |
||||
// API used by actors/backend
|
||||
ViewPrivWithOwnBorder(const Buffer *p, int lineCapacity, int borderSize, Border border); |
||||
|
||||
virtual void prepareToRead() override; |
||||
virtual std::size_t size() const override; |
||||
|
||||
// API used (indirectly) by user code
|
||||
virtual const uint8_t* InLineB(int index) const override; |
||||
}; |
||||
|
||||
void debugBufferPriv(const Buffer& buffer, std::ostream &os); |
||||
|
||||
// FIXME: GAPI_EXPORTS is used here only to access internal methods
|
||||
// like readDone/writeDone in low-level tests
|
||||
class GAPI_EXPORTS Buffer::Priv |
||||
{ |
||||
int m_line_consumption = -1; |
||||
int m_border_size = -1; |
||||
int m_skew = -1; |
||||
int m_writer_lpi = 1; |
||||
|
||||
cv::GMatDesc m_desc = cv::GMatDesc{-1,-1,{-1,-1}}; |
||||
bool m_is_input = false; |
||||
|
||||
int m_write_caret = -1; |
||||
|
||||
std::vector<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; |
||||
cv::gapi::own::Rect m_roi; |
||||
|
||||
friend void debugBufferPriv(const Buffer& p, std::ostream &os); |
||||
|
||||
public: |
||||
Priv() = default; |
||||
Priv(int read_start, cv::gapi::own::Rect roi); |
||||
|
||||
inline const BufferStorage& storage() const { return *m_storage.get(); } |
||||
|
||||
// API used by actors/backend
|
||||
void init(const cv::GMatDesc &desc, |
||||
int line_consumption, |
||||
int border_size, |
||||
int skew, |
||||
int wlpi, |
||||
int readStart, |
||||
cv::gapi::own::Rect roi); |
||||
|
||||
void allocate(BorderOpt border); |
||||
void bindTo(const cv::Mat &data, bool is_input); |
||||
|
||||
void addView(const View& view) { m_views.push_back(view); } |
||||
|
||||
const GMatDesc meta() const { return m_desc; } |
||||
|
||||
bool full() const; |
||||
void writeDone(); |
||||
void reset(); |
||||
int size() const; |
||||
|
||||
int linesReady() const; |
||||
|
||||
inline int y() const { return m_write_caret; } |
||||
|
||||
inline int writer_lpi() const { return m_writer_lpi; } |
||||
|
||||
// API used (indirectly) by user code
|
||||
uint8_t* OutLineB(int index = 0); |
||||
int lpi() const; |
||||
|
||||
inline int readStart() const { return m_readStart; } |
||||
inline int writeStart() const { return m_roi.y; } |
||||
inline int writeEnd() const { return m_roi.y + m_roi.height; } |
||||
inline int outputLines() const { return m_roi.height; } |
||||
}; |
||||
|
||||
} // namespace cv::gapi::fluid
|
||||
} // namespace cv::gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_FLUID_BUFFER_PRIV_HPP
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,19 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GFLUIDCORE_HPP |
||||
#define OPENCV_GAPI_GFLUIDCORE_HPP |
||||
|
||||
#include "opencv2/gapi/fluid/gfluidkernel.hpp" |
||||
|
||||
namespace cv { namespace gapi { namespace core { namespace fluid { |
||||
|
||||
GAPI_EXPORTS GKernelPackage kernels(); |
||||
|
||||
}}}} |
||||
|
||||
#endif // OPENCV_GAPI_GFLUIDCORE_HPP
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,19 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GFLUIDIMGPROC_HPP |
||||
#define OPENCV_GAPI_GFLUIDIMGPROC_HPP |
||||
|
||||
#include "opencv2/gapi/fluid/gfluidkernel.hpp" |
||||
|
||||
namespace cv { namespace gapi { namespace imgproc { namespace fluid { |
||||
|
||||
GAPI_EXPORTS GKernelPackage kernels(); |
||||
|
||||
}}}} |
||||
|
||||
#endif // OPENCV_GAPI_GFLUIDIMGPROC_HPP
|
@ -0,0 +1,154 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef GFLUIDUTILS_HPP |
||||
#define GFLUIDUTILS_HPP |
||||
|
||||
#include <limits> |
||||
#include <type_traits> |
||||
#include <opencv2/gapi/util/compiler_hints.hpp> //UNUSED |
||||
|
||||
namespace cv { |
||||
namespace gapi { |
||||
namespace fluid { |
||||
|
||||
//-----------------------------
|
||||
//
|
||||
// Numeric cast with saturation
|
||||
//
|
||||
//-----------------------------
|
||||
|
||||
template<typename DST, typename SRC> |
||||
static inline DST saturate(SRC x) |
||||
{ |
||||
// only integral types please!
|
||||
GAPI_DbgAssert(std::is_integral<DST>::value && |
||||
std::is_integral<SRC>::value); |
||||
|
||||
if (std::is_same<DST, SRC>::value) |
||||
return static_cast<DST>(x); |
||||
|
||||
if (sizeof(DST) > sizeof(SRC)) |
||||
return static_cast<DST>(x); |
||||
|
||||
// compiler must recognize this saturation,
|
||||
// so compile saturate<s16>(a + b) with adds
|
||||
// instruction (e.g.: _mm_adds_epi16 if x86)
|
||||
return x < std::numeric_limits<DST>::min()? |
||||
std::numeric_limits<DST>::min(): |
||||
x > std::numeric_limits<DST>::max()? |
||||
std::numeric_limits<DST>::max(): |
||||
static_cast<DST>(x); |
||||
} |
||||
|
||||
// Note, that OpenCV rounds differently:
|
||||
// - like std::round() for add, subtract
|
||||
// - like std::rint() for multiply, divide
|
||||
template<typename DST, typename SRC, typename R> |
||||
static inline DST saturate(SRC x, R round) |
||||
{ |
||||
if (std::is_floating_point<DST>::value) |
||||
{ |
||||
return static_cast<DST>(x); |
||||
} |
||||
else if (std::is_integral<SRC>::value) |
||||
{ |
||||
GAPI_DbgAssert(std::is_integral<DST>::value && |
||||
std::is_integral<SRC>::value); |
||||
return saturate<DST>(x); |
||||
} |
||||
else |
||||
{ |
||||
GAPI_DbgAssert(std::is_integral<DST>::value && |
||||
std::is_floating_point<SRC>::value); |
||||
#ifdef _WIN32 |
||||
// Suppress warning about convering x to floating-point
|
||||
// Note that x is already floating-point at this point
|
||||
#pragma warning(disable: 4244) |
||||
#endif |
||||
int ix = static_cast<int>(round(x)); |
||||
#ifdef _WIN32 |
||||
#pragma warning(default: 4244) |
||||
#endif |
||||
return saturate<DST>(ix); |
||||
} |
||||
} |
||||
|
||||
// explicit suffix 'd' for double type
|
||||
static inline double ceild(double x) { return std::ceil(x); } |
||||
static inline double floord(double x) { return std::floor(x); } |
||||
static inline double roundd(double x) { return std::round(x); } |
||||
static inline double rintd(double x) { return std::rint(x); } |
||||
|
||||
//--------------------------------
|
||||
//
|
||||
// Macros for mappig of data types
|
||||
//
|
||||
//--------------------------------
|
||||
|
||||
#define UNARY_(DST, SRC, OP, ...) \ |
||||
if (cv::DataType<DST>::depth == dst.meta().depth && \
|
||||
cv::DataType<SRC>::depth == src.meta().depth) \
|
||||
{ \
|
||||
GAPI_DbgAssert(dst.length() == src.length()); \
|
||||
GAPI_DbgAssert(dst.meta().chan == src.meta().chan); \
|
||||
\
|
||||
OP<DST, SRC>(__VA_ARGS__); \
|
||||
return; \
|
||||
} |
||||
|
||||
// especial unary operation: dst is always 8UC1 image
|
||||
#define INRANGE_(DST, SRC, OP, ...) \ |
||||
if (cv::DataType<DST>::depth == dst.meta().depth && \
|
||||
cv::DataType<SRC>::depth == src.meta().depth) \
|
||||
{ \
|
||||
GAPI_DbgAssert(dst.length() == src.length()); \
|
||||
GAPI_DbgAssert(dst.meta().chan == 1); \
|
||||
\
|
||||
OP<DST, SRC>(__VA_ARGS__); \
|
||||
return; \
|
||||
} |
||||
|
||||
#define BINARY_(DST, SRC1, SRC2, OP, ...) \ |
||||
if (cv::DataType<DST>::depth == dst.meta().depth && \
|
||||
cv::DataType<SRC1>::depth == src1.meta().depth && \
|
||||
cv::DataType<SRC2>::depth == src2.meta().depth) \
|
||||
{ \
|
||||
GAPI_DbgAssert(dst.length() == src1.length()); \
|
||||
GAPI_DbgAssert(dst.length() == src2.length()); \
|
||||
\
|
||||
GAPI_DbgAssert(dst.meta().chan == src1.meta().chan); \
|
||||
GAPI_DbgAssert(dst.meta().chan == src2.meta().chan); \
|
||||
\
|
||||
OP<DST, SRC1, SRC2>(__VA_ARGS__); \
|
||||
return; \
|
||||
} |
||||
|
||||
// especial ternary operation: src3 has only one channel
|
||||
#define SELECT_(DST, SRC1, SRC2, SRC3, OP, ...) \ |
||||
if (cv::DataType<DST>::depth == dst.meta().depth && \
|
||||
cv::DataType<SRC1>::depth == src1.meta().depth && \
|
||||
cv::DataType<SRC2>::depth == src2.meta().depth && \
|
||||
cv::DataType<SRC3>::depth == src3.meta().depth) \
|
||||
{ \
|
||||
GAPI_DbgAssert(dst.length() == src1.length()); \
|
||||
GAPI_DbgAssert(dst.length() == src2.length()); \
|
||||
GAPI_DbgAssert(dst.length() == src3.length()); \
|
||||
\
|
||||
GAPI_DbgAssert(dst.meta().chan == src1.meta().chan); \
|
||||
GAPI_DbgAssert(dst.meta().chan == src2.meta().chan); \
|
||||
GAPI_DbgAssert( 1 == src3.meta().chan); \
|
||||
\
|
||||
OP<DST, SRC1, SRC2, SRC3>(__VA_ARGS__); \
|
||||
return; \
|
||||
} |
||||
|
||||
} // namespace fluid
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // GFLUIDUTILS_HPP
|
@ -0,0 +1 @@ |
||||
This directory contains G-API graph compiler logic. |
@ -0,0 +1,131 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include <ade/graph.hpp> |
||||
|
||||
#include "opencv2/gapi/gproto.hpp" // descr_of |
||||
#include "opencv2/gapi/gcompiled.hpp" |
||||
|
||||
#include "compiler/gcompiled_priv.hpp" |
||||
#include "backends/common/gbackend.hpp" |
||||
|
||||
// GCompiled private implementation ////////////////////////////////////////////
|
||||
void cv::GCompiled::Priv::setup(const GMetaArgs &_metaArgs, |
||||
const GMetaArgs &_outMetas, |
||||
std::unique_ptr<cv::gimpl::GExecutor> &&_pE) |
||||
{ |
||||
m_metas = _metaArgs; |
||||
m_outMetas = _outMetas; |
||||
m_exec = std::move(_pE); |
||||
} |
||||
|
||||
bool cv::GCompiled::Priv::isEmpty() const |
||||
{ |
||||
return !m_exec; |
||||
} |
||||
|
||||
void cv::GCompiled::Priv::run(cv::gimpl::GRuntimeArgs &&args) |
||||
{ |
||||
// Strip away types since ADE knows nothing about that
|
||||
// args will be taken by specific GBackendExecutables
|
||||
checkArgs(args); |
||||
m_exec->run(std::move(args)); |
||||
} |
||||
|
||||
const cv::GMetaArgs& cv::GCompiled::Priv::metas() const |
||||
{ |
||||
return m_metas; |
||||
} |
||||
|
||||
const cv::GMetaArgs& cv::GCompiled::Priv::outMetas() const |
||||
{ |
||||
return m_outMetas; |
||||
} |
||||
|
||||
void cv::GCompiled::Priv::checkArgs(const cv::gimpl::GRuntimeArgs &args) const |
||||
{ |
||||
const auto runtime_metas = descr_of(args.inObjs); |
||||
if (runtime_metas != m_metas) |
||||
{ |
||||
util::throw_error(std::logic_error("This object was compiled " |
||||
"for different metadata!")); |
||||
// FIXME: Add details on what is actually wrong
|
||||
} |
||||
} |
||||
|
||||
const cv::gimpl::GModel::Graph& cv::GCompiled::Priv::model() const |
||||
{ |
||||
GAPI_Assert(nullptr != m_exec); |
||||
return m_exec->model(); |
||||
} |
||||
|
||||
// GCompiled public implementation /////////////////////////////////////////////
|
||||
cv::GCompiled::GCompiled() |
||||
: m_priv(new Priv()) |
||||
{ |
||||
} |
||||
|
||||
cv::GCompiled::operator bool() const |
||||
{ |
||||
return !m_priv->isEmpty(); |
||||
} |
||||
|
||||
void cv::GCompiled::operator() (GRunArgs &&ins, GRunArgsP &&outs) |
||||
{ |
||||
// FIXME: Check that <outs> matches the protocol
|
||||
m_priv->run(cv::gimpl::GRuntimeArgs{std::move(ins),std::move(outs)}); |
||||
} |
||||
|
||||
void cv::GCompiled::operator ()(cv::Mat in, cv::Mat &out) |
||||
{ |
||||
(*this)(cv::gin(in), cv::gout(out)); |
||||
} |
||||
|
||||
void cv::GCompiled::operator() (cv::Mat in, cv::Scalar &out) |
||||
{ |
||||
(*this)(cv::gin(in), cv::gout(out)); |
||||
} |
||||
|
||||
void cv::GCompiled::operator() (cv::Mat in1, cv::Mat in2, cv::Mat &out) |
||||
{ |
||||
(*this)(cv::gin(in1, in2), cv::gout(out)); |
||||
} |
||||
|
||||
void cv::GCompiled::operator() (cv::Mat in1, cv::Mat in2, cv::Scalar &out) |
||||
{ |
||||
(*this)(cv::gin(in1, in2), cv::gout(out)); |
||||
} |
||||
|
||||
void cv::GCompiled::operator ()(const std::vector<cv::Mat> &ins, |
||||
const std::vector<cv::Mat> &outs) |
||||
{ |
||||
GRunArgs call_ins; |
||||
GRunArgsP call_outs; |
||||
|
||||
// Make a temporary copy of vector outs - cv::Mats are copies anyway
|
||||
auto tmp = outs; |
||||
for (const cv::Mat &m : ins) { call_ins.emplace_back(m); } |
||||
for ( cv::Mat &m : tmp) { call_outs.emplace_back(&m); } |
||||
|
||||
(*this)(std::move(call_ins), std::move(call_outs)); |
||||
} |
||||
|
||||
const cv::GMetaArgs& cv::GCompiled::metas() const |
||||
{ |
||||
return m_priv->metas(); |
||||
} |
||||
|
||||
const cv::GMetaArgs& cv::GCompiled::outMetas() const |
||||
{ |
||||
return m_priv->outMetas(); |
||||
} |
||||
|
||||
|
||||
cv::GCompiled::Priv& cv::GCompiled::priv() |
||||
{ |
||||
return *m_priv; |
||||
} |
@ -0,0 +1,58 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GCOMPILED_PRIV_HPP |
||||
#define OPENCV_GAPI_GCOMPILED_PRIV_HPP |
||||
|
||||
#include <memory> // unique_ptr |
||||
|
||||
#include "opencv2/gapi/util/optional.hpp" |
||||
#include "compiler/gmodel.hpp" |
||||
#include "executor/gexecutor.hpp" |
||||
|
||||
// NB: BTW, GCompiled is the only "public API" class which
|
||||
// private part (implementaion) is hosted in the "compiler/" module.
|
||||
//
|
||||
// This file is here just to keep ADE hidden from the top-level APIs.
|
||||
//
|
||||
// As the thing becomes more complex, appropriate API and implementation
|
||||
// part will be placed to api/ and compiler/ modules respectively.
|
||||
|
||||
namespace cv { |
||||
|
||||
namespace gimpl |
||||
{ |
||||
struct GRuntimeArgs; |
||||
}; |
||||
|
||||
// FIXME: GAPI_EXPORTS is here only due to tests and Windows linker issues
|
||||
class GAPI_EXPORTS GCompiled::Priv |
||||
{ |
||||
// NB: For now, a GCompiled keeps the original ade::Graph alive.
|
||||
// If we want to go autonomous, we might to do something with this.
|
||||
GMetaArgs m_metas; // passed by user
|
||||
GMetaArgs m_outMetas; // inferred by compiler
|
||||
std::unique_ptr<cv::gimpl::GExecutor> m_exec; |
||||
|
||||
void checkArgs(const cv::gimpl::GRuntimeArgs &args) const; |
||||
|
||||
public: |
||||
void setup(const GMetaArgs &metaArgs, |
||||
const GMetaArgs &outMetas, |
||||
std::unique_ptr<cv::gimpl::GExecutor> &&pE); |
||||
bool isEmpty() const; |
||||
|
||||
void run(cv::gimpl::GRuntimeArgs &&args); |
||||
const GMetaArgs& metas() const; |
||||
const GMetaArgs& outMetas() const; |
||||
|
||||
const cv::gimpl::GModel::Graph& model() const; |
||||
}; |
||||
|
||||
} |
||||
|
||||
#endif // OPENCV_GAPI_GCOMPILED_PRIV_HPP
|
@ -0,0 +1,273 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include <vector> |
||||
#include <stack> |
||||
#include <unordered_map> |
||||
|
||||
#include <ade/util/algorithm.hpp> // any_of |
||||
#include <ade/util/zip_range.hpp> // zip_range, indexed |
||||
|
||||
#include <ade/graph.hpp> |
||||
#include <ade/passes/check_cycles.hpp> |
||||
|
||||
#include "api/gcomputation_priv.hpp" |
||||
#include "api/gnode_priv.hpp" // FIXME: why it is here? |
||||
#include "api/gproto_priv.hpp" // FIXME: why it is here? |
||||
#include "api/gcall_priv.hpp" // FIXME: why it is here? |
||||
#include "api/gapi_priv.hpp" // FIXME: why it is here? |
||||
#include "api/gbackend_priv.hpp" // Backend basic API (newInstance, etc) |
||||
|
||||
#include "compiler/gmodel.hpp" |
||||
#include "compiler/gmodelbuilder.hpp" |
||||
#include "compiler/gcompiler.hpp" |
||||
#include "compiler/gcompiled_priv.hpp" |
||||
#include "compiler/passes/passes.hpp" |
||||
|
||||
#include "executor/gexecutor.hpp" |
||||
#include "backends/common/gbackend.hpp" |
||||
|
||||
// <FIXME:>
|
||||
#include "opencv2/gapi/cpu/core.hpp" // Also directly refer to Core |
||||
#include "opencv2/gapi/cpu/imgproc.hpp" // ...and Imgproc kernel implementations |
||||
// </FIXME:>
|
||||
|
||||
#include "opencv2/gapi/gcompoundkernel.hpp" // compound::backend() |
||||
|
||||
#include "opencv2/core/cvdef.h" |
||||
#include "logger.hpp" |
||||
|
||||
namespace |
||||
{ |
||||
cv::gapi::GKernelPackage getKernelPackage(cv::GCompileArgs &args) |
||||
{ |
||||
static auto ocv_pkg = combine(cv::gapi::core::cpu::kernels(), |
||||
cv::gapi::imgproc::cpu::kernels(), |
||||
cv::unite_policy::KEEP); |
||||
auto user_pkg = cv::gimpl::getCompileArg<cv::gapi::GKernelPackage>(args); |
||||
return combine(ocv_pkg, user_pkg.value_or(cv::gapi::GKernelPackage{}), cv::unite_policy::REPLACE); |
||||
} |
||||
|
||||
cv::util::optional<std::string> getGraphDumpDirectory(cv::GCompileArgs& args) |
||||
{ |
||||
auto dump_info = cv::gimpl::getCompileArg<cv::graph_dump_path>(args); |
||||
if (!dump_info.has_value()) |
||||
{ |
||||
const char* path = std::getenv("GRAPH_DUMP_PATH"); |
||||
return path |
||||
? cv::util::make_optional(std::string(path)) |
||||
: cv::util::optional<std::string>(); |
||||
} |
||||
else |
||||
{ |
||||
return cv::util::make_optional(dump_info.value().m_dump_path); |
||||
} |
||||
} |
||||
} // anonymous namespace
|
||||
|
||||
|
||||
// GCompiler implementation ////////////////////////////////////////////////////
|
||||
|
||||
cv::gimpl::GCompiler::GCompiler(const cv::GComputation &c, |
||||
GMetaArgs &&metas, |
||||
GCompileArgs &&args) |
||||
: m_c(c), m_metas(std::move(metas)), m_args(std::move(args)) |
||||
{ |
||||
using namespace std::placeholders; |
||||
m_all_kernels = getKernelPackage(m_args); |
||||
auto lookup_order = getCompileArg<gapi::GLookupOrder>(m_args).value_or(gapi::GLookupOrder()); |
||||
auto dump_path = getGraphDumpDirectory(m_args); |
||||
|
||||
m_e.addPassStage("init"); |
||||
m_e.addPass("init", "check_cycles", ade::passes::CheckCycles()); |
||||
m_e.addPass("init", "expand_kernels", std::bind(passes::expandKernels, _1, |
||||
m_all_kernels)); // NB: package is copied
|
||||
m_e.addPass("init", "topo_sort", ade::passes::TopologicalSort()); |
||||
m_e.addPass("init", "init_islands", passes::initIslands); |
||||
m_e.addPass("init", "check_islands", passes::checkIslands); |
||||
// TODO:
|
||||
// - Check basic graph validity (i.e., all inputs are connected)
|
||||
// - Complex dependencies (i.e. parent-child) unrolling
|
||||
// - etc, etc, etc
|
||||
|
||||
// Remove GCompoundBackend to avoid calling setupBackend() with it in the list
|
||||
m_all_kernels.remove(cv::gapi::compound::backend()); |
||||
m_e.addPass("init", "resolve_kernels", std::bind(passes::resolveKernels, _1, |
||||
std::ref(m_all_kernels), // NB: and not copied here
|
||||
lookup_order)); |
||||
|
||||
m_e.addPass("init", "check_islands_content", passes::checkIslandsContent); |
||||
m_e.addPassStage("meta"); |
||||
m_e.addPass("meta", "initialize", std::bind(passes::initMeta, _1, std::ref(m_metas))); |
||||
m_e.addPass("meta", "propagate", passes::inferMeta); |
||||
m_e.addPass("meta", "finalize", passes::storeResultingMeta); |
||||
// moved to another stage, FIXME: two dumps?
|
||||
// m_e.addPass("meta", "dump_dot", passes::dumpDotStdout);
|
||||
|
||||
// Special stage for backend-specific transformations
|
||||
// FIXME: document passes hierarchy and order for backend developers
|
||||
m_e.addPassStage("transform"); |
||||
|
||||
m_e.addPassStage("exec"); |
||||
m_e.addPass("exec", "fuse_islands", passes::fuseIslands); |
||||
m_e.addPass("exec", "sync_islands", passes::syncIslandTags); |
||||
|
||||
if (dump_path.has_value()) |
||||
{ |
||||
m_e.addPass("exec", "dump_dot", std::bind(passes::dumpGraph, _1, |
||||
dump_path.value())); |
||||
} |
||||
|
||||
// Process backends at the last moment (after all G-API passes are added).
|
||||
ade::ExecutionEngineSetupContext ectx(m_e); |
||||
auto backends = m_all_kernels.backends(); |
||||
for (auto &b : backends) |
||||
{ |
||||
b.priv().addBackendPasses(ectx); |
||||
} |
||||
} |
||||
|
||||
void cv::gimpl::GCompiler::validateInputMeta() |
||||
{ |
||||
if (m_metas.size() != m_c.priv().m_ins.size()) |
||||
{ |
||||
util::throw_error(std::logic_error |
||||
("COMPILE: GComputation interface / metadata mismatch! " |
||||
"(expected " + std::to_string(m_c.priv().m_ins.size()) + ", " |
||||
"got " + std::to_string(m_metas.size()) + " meta arguments)")); |
||||
} |
||||
|
||||
const auto meta_matches = [](const GMetaArg &meta, const GProtoArg &proto) { |
||||
switch (proto.index()) |
||||
{ |
||||
// FIXME: Auto-generate methods like this from traits:
|
||||
case GProtoArg::index_of<cv::GMat>(): |
||||
return util::holds_alternative<cv::GMatDesc>(meta); |
||||
|
||||
case GProtoArg::index_of<cv::GScalar>(): |
||||
return util::holds_alternative<cv::GScalarDesc>(meta); |
||||
|
||||
case GProtoArg::index_of<cv::detail::GArrayU>(): |
||||
return util::holds_alternative<cv::GArrayDesc>(meta); |
||||
|
||||
default: |
||||
GAPI_Assert(false); |
||||
} |
||||
return false; // should never happen
|
||||
}; |
||||
|
||||
for (const auto &meta_arg_idx : ade::util::indexed(ade::util::zip(m_metas, m_c.priv().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)); |
||||
|
||||
if (!meta_matches(meta, proto)) |
||||
{ |
||||
const auto index = ade::util::index(meta_arg_idx); |
||||
util::throw_error(std::logic_error |
||||
("GComputation object type / metadata descriptor mismatch " |
||||
"(argument " + std::to_string(index) + ")")); |
||||
// FIXME: report what we've got and what we've expected
|
||||
} |
||||
} |
||||
// All checks are ok
|
||||
} |
||||
|
||||
void cv::gimpl::GCompiler::validateOutProtoArgs() |
||||
{ |
||||
for (const auto &out_pos : ade::util::indexed(m_c.priv().m_outs)) |
||||
{ |
||||
const auto &node = proto::origin_of(ade::util::value(out_pos)).node; |
||||
if (node.shape() != cv::GNode::NodeShape::CALL) |
||||
{ |
||||
auto pos = ade::util::index(out_pos); |
||||
util::throw_error(std::logic_error |
||||
("Computation output " + std::to_string(pos) + |
||||
" is not a result of any operation")); |
||||
} |
||||
} |
||||
} |
||||
|
||||
cv::gimpl::GCompiler::GPtr cv::gimpl::GCompiler::generateGraph() |
||||
{ |
||||
validateInputMeta(); |
||||
validateOutProtoArgs(); |
||||
|
||||
// Generate ADE graph from expression-based computation
|
||||
std::unique_ptr<ade::Graph> pG(new ade::Graph); |
||||
ade::Graph& g = *pG; |
||||
|
||||
GModel::Graph gm(g); |
||||
cv::gimpl::GModel::init(gm); |
||||
cv::gimpl::GModelBuilder builder(g); |
||||
auto proto_slots = builder.put(m_c.priv().m_ins, m_c.priv().m_outs); |
||||
GAPI_LOG_INFO(NULL, "Generated graph: " << g.nodes().size() << " nodes" << std::endl); |
||||
|
||||
// Store Computation's protocol in metadata
|
||||
Protocol p; |
||||
std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots; |
||||
gm.metadata().set(p); |
||||
|
||||
return pG; |
||||
} |
||||
|
||||
void cv::gimpl::GCompiler::runPasses(ade::Graph &g) |
||||
{ |
||||
m_e.runPasses(g); |
||||
GAPI_LOG_INFO(NULL, "All compiler passes are successful"); |
||||
} |
||||
|
||||
void cv::gimpl::GCompiler::compileIslands(ade::Graph &g) |
||||
{ |
||||
GModel::Graph gm(g); |
||||
std::shared_ptr<ade::Graph> gptr(gm.metadata().get<IslandModel>().model); |
||||
GIslandModel::Graph gim(*gptr); |
||||
|
||||
// Run topological sort on GIslandModel first
|
||||
auto pass_ctx = ade::passes::PassContext{*gptr}; |
||||
ade::passes::TopologicalSort{}(pass_ctx); |
||||
|
||||
// Now compile islands
|
||||
GIslandModel::compileIslands(gim, g, m_args); |
||||
} |
||||
|
||||
cv::GCompiled cv::gimpl::GCompiler::produceCompiled(GPtr &&pg) |
||||
{ |
||||
// This is the final compilation step. Here:
|
||||
// - An instance of GExecutor is created. Depening on the platform,
|
||||
// build configuration, etc, a GExecutor may be:
|
||||
// - a naive single-thread graph interpreter;
|
||||
// - a std::thread-based thing
|
||||
// - a TBB-based thing, etc.
|
||||
// - All this stuff is wrapped into a GCompiled object and returned
|
||||
// to user.
|
||||
|
||||
// Note: this happens in the last pass ("compile_islands"):
|
||||
// - Each GIsland of GIslandModel instantiates its own,
|
||||
// backend-specific executable object
|
||||
// - Every backend gets a subgraph to execute, and builds
|
||||
// an execution plan for it (backend-specific execution)
|
||||
// ...before call to produceCompiled();
|
||||
|
||||
const auto &outMetas = GModel::ConstGraph(*pg).metadata() |
||||
.get<OutputMeta>().outMeta; |
||||
std::unique_ptr<GExecutor> pE(new GExecutor(std::move(pg))); |
||||
// FIXME: select which executor will be actually used,
|
||||
// make GExecutor abstract.
|
||||
|
||||
GCompiled compiled; |
||||
compiled.priv().setup(m_metas, outMetas, std::move(pE)); |
||||
return compiled; |
||||
} |
||||
|
||||
cv::GCompiled cv::gimpl::GCompiler::compile() |
||||
{ |
||||
std::unique_ptr<ade::Graph> pG = generateGraph(); |
||||
runPasses(*pG); |
||||
compileIslands(*pG); |
||||
return produceCompiled(std::move(pG)); |
||||
} |
@ -0,0 +1,51 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GCOMPILER_HPP |
||||
#define OPENCV_GAPI_GCOMPILER_HPP |
||||
|
||||
|
||||
#include "opencv2/gapi/gcommon.hpp" |
||||
#include "opencv2/gapi/gkernel.hpp" |
||||
#include "opencv2/gapi/gcomputation.hpp" |
||||
|
||||
#include <ade/execution_engine/execution_engine.hpp> |
||||
|
||||
namespace cv { namespace gimpl { |
||||
|
||||
// FIXME: exported for internal tests only!
|
||||
class GAPI_EXPORTS GCompiler |
||||
{ |
||||
const GComputation& m_c; |
||||
const GMetaArgs m_metas; |
||||
GCompileArgs m_args; |
||||
ade::ExecutionEngine m_e; |
||||
|
||||
cv::gapi::GKernelPackage m_all_kernels; |
||||
|
||||
void validateInputMeta(); |
||||
void validateOutProtoArgs(); |
||||
|
||||
public: |
||||
explicit GCompiler(const GComputation &c, |
||||
GMetaArgs &&metas, |
||||
GCompileArgs &&args); |
||||
|
||||
// The method which does everything...
|
||||
GCompiled compile(); |
||||
|
||||
// But is actually composed of this:
|
||||
using GPtr = std::unique_ptr<ade::Graph>; |
||||
GPtr generateGraph(); // Unroll GComputation into a GModel
|
||||
void runPasses(ade::Graph &g); // Apply all G-API passes on a GModel
|
||||
void compileIslands(ade::Graph &g); // Instantiate GIslandExecutables in GIslandModel
|
||||
GCompiled produceCompiled(GPtr &&pg); // Produce GCompiled from processed GModel
|
||||
}; |
||||
|
||||
}} |
||||
|
||||
#endif // OPENCV_GAPI_GCOMPILER_HPP
|
@ -0,0 +1,287 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include <sstream> |
||||
#include <unordered_set> |
||||
#include <unordered_map> |
||||
|
||||
#include <ade/util/checked_cast.hpp> |
||||
|
||||
#include "api/gbackend_priv.hpp" // GBackend::Priv().compile() |
||||
#include "compiler/gmodel.hpp" |
||||
#include "compiler/gislandmodel.hpp" |
||||
#include "logger.hpp" // GAPI_LOG |
||||
|
||||
namespace cv { namespace gimpl { |
||||
|
||||
GIsland::GIsland(const gapi::GBackend &bknd, |
||||
ade::NodeHandle op, |
||||
util::optional<std::string> &&user_tag) |
||||
: m_backend(bknd) |
||||
, m_user_tag(std::move(user_tag)) |
||||
{ |
||||
m_all.insert(op); |
||||
m_in_ops.insert(op); |
||||
m_out_ops.insert(op); |
||||
} |
||||
|
||||
// _ because of gcc4.8 wanings on ARM
|
||||
GIsland::GIsland(const gapi::GBackend &_bknd, |
||||
node_set &&_all, |
||||
node_set &&_in_ops, |
||||
node_set &&_out_ops, |
||||
util::optional<std::string> &&_user_tag) |
||||
: m_backend(_bknd) |
||||
, m_all(std::move(_all)) |
||||
, m_in_ops(std::move(_in_ops)) |
||||
, m_out_ops(std::move(_out_ops)) |
||||
, m_user_tag(std::move(_user_tag)) |
||||
{ |
||||
} |
||||
|
||||
const GIsland::node_set& GIsland::contents() const |
||||
{ |
||||
return m_all; |
||||
} |
||||
|
||||
const GIsland::node_set& GIsland::in_ops() const |
||||
{ |
||||
return m_in_ops; |
||||
} |
||||
|
||||
const GIsland::node_set& GIsland::out_ops() const |
||||
{ |
||||
return m_out_ops; |
||||
} |
||||
|
||||
gapi::GBackend GIsland::backend() const |
||||
{ |
||||
return m_backend; |
||||
} |
||||
|
||||
bool GIsland::is_user_specified() const |
||||
{ |
||||
return m_user_tag.has_value(); |
||||
} |
||||
|
||||
void GIsland::debug() const |
||||
{ |
||||
std::stringstream stream; |
||||
stream << name() << " {{\n input ops: "; |
||||
for (const auto& nh : m_in_ops) stream << nh << "; "; |
||||
stream << "\n output ops: "; |
||||
for (const auto& nh : m_out_ops) stream << nh << "; "; |
||||
stream << "\n contents: "; |
||||
for (const auto& nh : m_all) stream << nh << "; "; |
||||
stream << "\n}}" << std::endl; |
||||
GAPI_LOG_INFO(NULL, stream.str()); |
||||
} |
||||
|
||||
GIsland::node_set GIsland::consumers(const ade::Graph &g, |
||||
const ade::NodeHandle &slot_nh) const |
||||
{ |
||||
GIslandModel::ConstGraph gim(g); |
||||
auto data_nh = gim.metadata(slot_nh).get<DataSlot>().original_data_node; |
||||
GIsland::node_set result; |
||||
for (const auto& in_op : m_in_ops) |
||||
{ |
||||
auto it = std::find(in_op->inNodes().begin(), |
||||
in_op->inNodes().end(), |
||||
data_nh); |
||||
if (it != in_op->inNodes().end()) |
||||
result.insert(in_op); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
ade::NodeHandle GIsland::producer(const ade::Graph &g, |
||||
const ade::NodeHandle &slot_nh) const |
||||
{ |
||||
GIslandModel::ConstGraph gim(g); |
||||
auto data_nh = gim.metadata(slot_nh).get<DataSlot>().original_data_node; |
||||
for (const auto& out_op : m_out_ops) |
||||
{ |
||||
auto it = std::find(out_op->outNodes().begin(), |
||||
out_op->outNodes().end(), |
||||
data_nh); |
||||
if (it != out_op->outNodes().end()) |
||||
return out_op; |
||||
} |
||||
// 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(); |
||||
} |
||||
|
||||
std::string GIsland::name() const |
||||
{ |
||||
if (is_user_specified()) |
||||
return m_user_tag.value(); |
||||
|
||||
std::stringstream ss; |
||||
ss << "island_#" << std::hex << static_cast<const void*>(this); |
||||
return ss.str(); |
||||
} |
||||
|
||||
void GIslandModel::generateInitial(GIslandModel::Graph &g, |
||||
const ade::Graph &src_graph) |
||||
{ |
||||
const GModel::ConstGraph src_g(src_graph); |
||||
|
||||
// Initially GIslandModel is a 1:1 projection from GModel:
|
||||
// 1) Every GModel::OP becomes a separate GIslandModel::FusedIsland;
|
||||
// 2) Every GModel::DATA becomes GIslandModel::DataSlot;
|
||||
// 3) Single-operation FusedIslands are connected with DataSlots in the
|
||||
// same way as OPs and DATA (edges with the same metadata)
|
||||
|
||||
using node_set = std::unordered_set |
||||
< ade::NodeHandle |
||||
, ade::HandleHasher<ade::Node> |
||||
>; |
||||
using node_map = std::unordered_map |
||||
< ade::NodeHandle |
||||
, ade::NodeHandle |
||||
, ade::HandleHasher<ade::Node> |
||||
>; |
||||
|
||||
node_set all_operations; |
||||
node_map data_to_slot; |
||||
|
||||
// First, list all operations and build create DataSlots in <g>
|
||||
for (auto src_nh : src_g.nodes()) |
||||
{ |
||||
switch (src_g.metadata(src_nh).get<NodeType>().t) |
||||
{ |
||||
case NodeType::OP: all_operations.insert(src_nh); break; |
||||
case NodeType::DATA: data_to_slot[src_nh] = mkSlotNode(g, src_nh); break; |
||||
default: GAPI_Assert(false); break; |
||||
} |
||||
} // for (src_g.nodes)
|
||||
|
||||
// Now put single-op islands and connect it with DataSlots
|
||||
for (auto src_op_nh : all_operations) |
||||
{ |
||||
auto nh = mkIslandNode(g, src_g.metadata(src_op_nh).get<Op>().backend, src_op_nh, src_graph); |
||||
for (auto in_edge : src_op_nh->inEdges()) |
||||
{ |
||||
auto src_data_nh = in_edge->srcNode(); |
||||
auto isl_slot_nh = data_to_slot.at(src_data_nh); |
||||
g.link(isl_slot_nh, nh); // no other data stored yet
|
||||
} |
||||
for (auto out_edge : src_op_nh->outEdges()) |
||||
{ |
||||
auto dst_data_nh = out_edge->dstNode(); |
||||
auto isl_slot_nh = data_to_slot.at(dst_data_nh); |
||||
g.link(nh, isl_slot_nh); |
||||
} |
||||
} // for(all_operations)
|
||||
} |
||||
|
||||
ade::NodeHandle GIslandModel::mkSlotNode(Graph &g, const ade::NodeHandle &data_nh) |
||||
{ |
||||
auto nh = g.createNode(); |
||||
g.metadata(nh).set(DataSlot{data_nh}); |
||||
g.metadata(nh).set(NodeKind{NodeKind::SLOT}); |
||||
return nh; |
||||
} |
||||
|
||||
ade::NodeHandle GIslandModel::mkIslandNode(Graph &g, const gapi::GBackend& bknd, const ade::NodeHandle &op_nh, const ade::Graph &orig_g) |
||||
{ |
||||
const GModel::ConstGraph src_g(orig_g); |
||||
util::optional<std::string> user_tag; |
||||
if (src_g.metadata(op_nh).contains<Island>()) |
||||
{ |
||||
user_tag = util::make_optional(src_g.metadata(op_nh).get<Island>().island); |
||||
} |
||||
|
||||
auto nh = g.createNode(); |
||||
std::shared_ptr<GIsland> island(new GIsland(bknd, op_nh, std::move(user_tag))); |
||||
g.metadata(nh).set(FusedIsland{std::move(island)}); |
||||
g.metadata(nh).set(NodeKind{NodeKind::ISLAND}); |
||||
return nh; |
||||
} |
||||
|
||||
ade::NodeHandle GIslandModel::mkIslandNode(Graph &g, std::shared_ptr<GIsland>&& isl) |
||||
{ |
||||
ade::NodeHandle nh = g.createNode(); |
||||
g.metadata(nh).set(cv::gimpl::NodeKind{cv::gimpl::NodeKind::ISLAND}); |
||||
g.metadata(nh).set<cv::gimpl::FusedIsland>({std::move(isl)}); |
||||
return nh; |
||||
} |
||||
|
||||
void GIslandModel::syncIslandTags(Graph &g, ade::Graph &orig_g) |
||||
{ |
||||
GModel::Graph gm(orig_g); |
||||
for (auto nh : g.nodes()) |
||||
{ |
||||
if (NodeKind::ISLAND == g.metadata(nh).get<NodeKind>().k) |
||||
{ |
||||
auto island = g.metadata(nh).get<FusedIsland>().object; |
||||
auto isl_tag = island->name(); |
||||
for (const auto& orig_nh_inside : island->contents()) |
||||
{ |
||||
gm.metadata(orig_nh_inside).set(Island{isl_tag}); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
void GIslandModel::compileIslands(Graph &g, const ade::Graph &orig_g, const GCompileArgs &args) |
||||
{ |
||||
GModel::ConstGraph gm(orig_g); |
||||
|
||||
auto original_sorted = gm.metadata().get<ade::passes::TopologicalSortData>(); |
||||
for (auto nh : g.nodes()) |
||||
{ |
||||
if (NodeKind::ISLAND == g.metadata(nh).get<NodeKind>().k) |
||||
{ |
||||
auto island_obj = g.metadata(nh).get<FusedIsland>().object; |
||||
auto island_ops = island_obj->contents(); |
||||
|
||||
std::vector<ade::NodeHandle> topo_sorted_list; |
||||
ade::util::copy_if(original_sorted.nodes(), |
||||
std::back_inserter(topo_sorted_list), |
||||
[&](ade::NodeHandle sorted_nh) { |
||||
return ade::util::contains(island_ops, sorted_nh); |
||||
}); |
||||
|
||||
auto island_exe = island_obj->backend().priv() |
||||
.compile(orig_g, args, topo_sorted_list); |
||||
GAPI_Assert(nullptr != island_exe); |
||||
g.metadata(nh).set(IslandExec{std::move(island_exe)}); |
||||
} |
||||
} |
||||
} |
||||
|
||||
ade::NodeHandle GIslandModel::producerOf(const ConstGraph &g, ade::NodeHandle &data_nh) |
||||
{ |
||||
for (auto nh : g.nodes()) |
||||
{ |
||||
// find a data slot...
|
||||
if (NodeKind::SLOT == g.metadata(nh).get<NodeKind>().k) |
||||
{ |
||||
// which is associated with the given data object...
|
||||
if (data_nh == g.metadata(nh).get<DataSlot>().original_data_node) |
||||
{ |
||||
// which probably has a produrer...
|
||||
if (0u != nh->inNodes().size()) |
||||
{ |
||||
// ...then the answer is that producer
|
||||
return nh->inNodes().front(); |
||||
} |
||||
else return ade::NodeHandle(); // input data object?
|
||||
// return empty to break the cycle
|
||||
} |
||||
} |
||||
} |
||||
// No appropriate data slot found - probably, the object has been
|
||||
// optimized out during fusion
|
||||
return ade::NodeHandle(); |
||||
} |
||||
|
||||
} // namespace cv
|
||||
} // namespace gimpl
|
@ -0,0 +1,184 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GISLANDMODEL_HPP |
||||
#define OPENCV_GAPI_GISLANDMODEL_HPP |
||||
|
||||
#include <unordered_set> |
||||
#include <memory> // shared_ptr |
||||
|
||||
#include <ade/graph.hpp> |
||||
#include <ade/typed_graph.hpp> |
||||
#include <ade/passes/topological_sort.hpp> |
||||
|
||||
#include "opencv2/gapi/util/optional.hpp" |
||||
#include "opencv2/gapi/gkernel.hpp" |
||||
|
||||
#include "compiler/gobjref.hpp" |
||||
|
||||
namespace cv { namespace gimpl { |
||||
|
||||
|
||||
// FIXME: GAPI_EXPORTS only because of tests!
|
||||
class GAPI_EXPORTS GIsland |
||||
{ |
||||
public: |
||||
using node_set = std::unordered_set |
||||
< ade::NodeHandle |
||||
, ade::HandleHasher<ade::Node> |
||||
>; |
||||
|
||||
// Initial constructor (constructs a single-op Island)
|
||||
GIsland(const gapi::GBackend &bknd, |
||||
ade::NodeHandle op, |
||||
util::optional<std::string>&& user_tag); |
||||
|
||||
// Merged constructor
|
||||
GIsland(const gapi::GBackend &bknd, |
||||
node_set &&all, |
||||
node_set &&in_ops, |
||||
node_set &&out_ops, |
||||
util::optional<std::string>&& user_tag); |
||||
|
||||
const node_set& contents() const; |
||||
const node_set& in_ops() const; |
||||
const node_set& out_ops() const; |
||||
|
||||
std::string name() const; |
||||
gapi::GBackend backend() const; |
||||
|
||||
/**
|
||||
* Returns all GModel operation node handles which are _reading_ |
||||
* from a GModel data object associated (wrapped in) the given |
||||
* Slot object. |
||||
* |
||||
* @param g an ade::Graph with GIslandModel information inside |
||||
* @param slot_nh Slot object node handle of interest |
||||
* @return a set of GModel operation node handles |
||||
*/ |
||||
node_set consumers(const ade::Graph &g, |
||||
const ade::NodeHandle &slot_nh) const; |
||||
|
||||
/**
|
||||
* Returns a GModel operation node handle which is _writing_ |
||||
* to a GModel data object associated (wrapped in) the given |
||||
* Slot object. |
||||
* |
||||
* @param g an ade::Graph with GIslandModel information inside |
||||
* @param slot_nh Slot object node handle of interest |
||||
* @return a node handle of original GModel |
||||
*/ |
||||
ade::NodeHandle producer(const ade::Graph &g, |
||||
const ade::NodeHandle &slot_nh) const; |
||||
|
||||
void debug() const; |
||||
bool is_user_specified() const; |
||||
|
||||
protected: |
||||
gapi::GBackend m_backend; // backend which handles this Island execution
|
||||
|
||||
node_set m_all; // everything (data + operations) within an island
|
||||
node_set m_in_ops; // operations island begins with
|
||||
node_set m_out_ops; // operations island ends with
|
||||
|
||||
// has island name IF specified by user. Empty for internal (inferred) islands
|
||||
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 |
||||
{ |
||||
public: |
||||
using InObj = std::pair<RcDesc, cv::GRunArg>; |
||||
using OutObj = std::pair<RcDesc, cv::GRunArgP>; |
||||
|
||||
// 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
|
||||
virtual void run(std::vector<InObj> &&input_objs, |
||||
std::vector<OutObj> &&output_objs) = 0; |
||||
|
||||
virtual ~GIslandExecutable() = default; |
||||
}; |
||||
|
||||
|
||||
|
||||
// Couldn't reuse NodeType here - FIXME unify (move meta to a shared place)
|
||||
struct NodeKind |
||||
{ |
||||
static const char *name() { return "NodeKind"; } |
||||
enum { ISLAND, SLOT} k; |
||||
}; |
||||
|
||||
// FIXME: Rename to Island (as soon as current GModel::Island is renamed
|
||||
// to IslandTag).
|
||||
struct FusedIsland |
||||
{ |
||||
static const char *name() { return "FusedIsland"; } |
||||
std::shared_ptr<GIsland> object; |
||||
}; |
||||
|
||||
struct DataSlot |
||||
{ |
||||
static const char *name() { return "DataSlot"; } |
||||
ade::NodeHandle original_data_node; // direct link to GModel
|
||||
}; |
||||
|
||||
struct IslandExec |
||||
{ |
||||
static const char *name() { return "IslandExecutable"; } |
||||
std::shared_ptr<GIslandExecutable> object; |
||||
}; |
||||
|
||||
namespace GIslandModel |
||||
{ |
||||
using Graph = ade::TypedGraph |
||||
< NodeKind |
||||
, FusedIsland |
||||
, DataSlot |
||||
, IslandExec |
||||
, ade::passes::TopologicalSortData |
||||
>; |
||||
|
||||
// FIXME: derive from TypedGraph
|
||||
using ConstGraph = ade::ConstTypedGraph |
||||
< NodeKind |
||||
, FusedIsland |
||||
, DataSlot |
||||
, IslandExec |
||||
, ade::passes::TopologicalSortData |
||||
>; |
||||
|
||||
// Top-level function
|
||||
void generateInitial(Graph &g, const ade::Graph &src_g); |
||||
// "Building blocks"
|
||||
ade::NodeHandle mkSlotNode(Graph &g, const ade::NodeHandle &data_nh); |
||||
ade::NodeHandle mkIslandNode(Graph &g, const gapi::GBackend &bknd, const ade::NodeHandle &op_nh, const ade::Graph &orig_g); |
||||
ade::NodeHandle mkIslandNode(Graph &g, std::shared_ptr<GIsland>&& isl); |
||||
|
||||
// GIslandModel API
|
||||
void syncIslandTags(Graph &g, ade::Graph &orig_g); |
||||
void compileIslands(Graph &g, const ade::Graph &orig_g, const GCompileArgs &args); |
||||
|
||||
// Debug routines
|
||||
// producerOf - returns an Island handle which produces given data object
|
||||
// from the original model (! don't mix with DataSlot)
|
||||
// FIXME: GAPI_EXPORTS because of tests only!
|
||||
ade::NodeHandle GAPI_EXPORTS producerOf(const ConstGraph &g, ade::NodeHandle &data_nh); |
||||
|
||||
} // namespace GIslandModel
|
||||
|
||||
}} // namespace cv::gimpl
|
||||
|
||||
#endif // OPENCV_GAPI_GISLANDMODEL_HPP
|
@ -0,0 +1,245 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#include <string> |
||||
#include <sstream> // used in GModel::log |
||||
|
||||
|
||||
#include <ade/util/zip_range.hpp> // util::indexed |
||||
#include <ade/util/checked_cast.hpp> |
||||
|
||||
#include "opencv2/gapi/gproto.hpp" |
||||
#include "api/gnode_priv.hpp" |
||||
#include "compiler/gobjref.hpp" |
||||
#include "compiler/gmodel.hpp" |
||||
|
||||
namespace cv { namespace gimpl { |
||||
|
||||
ade::NodeHandle GModel::mkOpNode(GModel::Graph &g, const GKernel &k, const std::vector<GArg> &args, const std::string &island) |
||||
{ |
||||
ade::NodeHandle op_h = g.createNode(); |
||||
g.metadata(op_h).set(NodeType{NodeType::OP}); |
||||
//These extra empty {} are to please GCC (-Wmissing-field-initializers)
|
||||
g.metadata(op_h).set(Op{k, args, {}, {}, {}}); |
||||
if (!island.empty()) |
||||
g.metadata(op_h).set(Island{island}); |
||||
return op_h; |
||||
} |
||||
|
||||
ade::NodeHandle GModel::mkDataNode(GModel::Graph &g, const GOrigin& origin) |
||||
{ |
||||
ade::NodeHandle op_h = g.createNode(); |
||||
const auto id = g.metadata().get<DataObjectCounter>().GetNewId(origin.shape); |
||||
g.metadata(op_h).set(NodeType{NodeType::DATA}); |
||||
|
||||
GMetaArg meta; |
||||
Data::Storage storage = Data::Storage::INTERNAL; // By default, all objects are marked INTERNAL
|
||||
|
||||
if (origin.node.shape() == GNode::NodeShape::CONST_BOUNDED) |
||||
{ |
||||
auto value = value_of(origin); |
||||
meta = descr_of(value); |
||||
storage = Data::Storage::CONST; |
||||
g.metadata(op_h).set(ConstValue{value}); |
||||
} |
||||
g.metadata(op_h).set(Data{origin.shape, id, meta, origin.ctor, storage}); |
||||
return op_h; |
||||
} |
||||
|
||||
void GModel::linkIn(Graph &g, ade::NodeHandle opH, ade::NodeHandle objH, std::size_t in_port) |
||||
{ |
||||
// Check if input is already connected
|
||||
for (const auto& in_e : opH->inEdges()) |
||||
{ |
||||
GAPI_Assert(g.metadata(in_e).get<Input>().port != in_port); |
||||
} |
||||
|
||||
auto &op = g.metadata(opH).get<Op>(); |
||||
auto &gm = g.metadata(objH).get<Data>(); |
||||
|
||||
// FIXME: check validity using kernel prototype
|
||||
GAPI_Assert(in_port < op.args.size()); |
||||
|
||||
ade::EdgeHandle eh = g.link(objH, opH); |
||||
g.metadata(eh).set(Input{in_port}); |
||||
|
||||
// Replace an API object with a REF (G* -> GOBJREF)
|
||||
op.args[in_port] = cv::GArg(RcDesc{gm.rc, gm.shape, {}}); |
||||
} |
||||
|
||||
void GModel::linkOut(Graph &g, ade::NodeHandle opH, ade::NodeHandle objH, std::size_t out_port) |
||||
{ |
||||
// FIXME: check validity using kernel prototype
|
||||
|
||||
// Check if output is already connected
|
||||
for (const auto& out_e : opH->outEdges()) |
||||
{ |
||||
GAPI_Assert(g.metadata(out_e).get<Output>().port != out_port); |
||||
} |
||||
|
||||
auto &op = g.metadata(opH).get<Op>(); |
||||
auto &gm = g.metadata(objH).get<Data>(); |
||||
|
||||
GAPI_Assert(objH->inNodes().size() == 0u); |
||||
|
||||
ade::EdgeHandle eh = g.link(opH, objH); |
||||
g.metadata(eh).set(Output{out_port}); |
||||
|
||||
// TODO: outs must be allocated according to kernel protocol!
|
||||
const auto storage_with_port = ade::util::checked_cast<std::size_t>(out_port+1); |
||||
const auto min_out_size = std::max(op.outs.size(), storage_with_port); |
||||
op.outs.resize(min_out_size, RcDesc{-1,GShape::GMAT,{}}); // FIXME: Invalid shape instead?
|
||||
op.outs[out_port] = RcDesc{gm.rc, gm.shape, {}}; |
||||
} |
||||
|
||||
std::vector<ade::NodeHandle> GModel::orderedInputs(Graph &g, ade::NodeHandle nh) |
||||
{ |
||||
std::vector<ade::NodeHandle> sorted_in_nhs(nh->inEdges().size()); |
||||
for (const auto& in_eh : nh->inEdges()) |
||||
{ |
||||
const auto port = g.metadata(in_eh).get<cv::gimpl::Input>().port; |
||||
GAPI_Assert(port < sorted_in_nhs.size()); |
||||
sorted_in_nhs[port] = in_eh->srcNode(); |
||||
} |
||||
return sorted_in_nhs; |
||||
} |
||||
|
||||
std::vector<ade::NodeHandle> GModel::orderedOutputs(Graph &g, ade::NodeHandle nh) |
||||
{ |
||||
std::vector<ade::NodeHandle> sorted_out_nhs(nh->outEdges().size()); |
||||
for (const auto& out_eh : nh->outEdges()) |
||||
{ |
||||
const auto port = g.metadata(out_eh).get<cv::gimpl::Output>().port; |
||||
GAPI_Assert(port < sorted_out_nhs.size()); |
||||
sorted_out_nhs[port] = out_eh->dstNode(); |
||||
} |
||||
return sorted_out_nhs; |
||||
} |
||||
|
||||
void GModel::init(Graph& g) |
||||
{ |
||||
g.metadata().set(DataObjectCounter()); |
||||
} |
||||
|
||||
void GModel::log(Graph &g, ade::NodeHandle nh, std::string &&msg, ade::NodeHandle updater) |
||||
{ |
||||
std::string s = std::move(msg); |
||||
if (updater != nullptr) |
||||
{ |
||||
std::stringstream fmt; |
||||
fmt << " (via " << updater << ")"; |
||||
s += fmt.str(); |
||||
} |
||||
|
||||
if (g.metadata(nh).contains<Journal>()) |
||||
{ |
||||
g.metadata(nh).get<Journal>().messages.push_back(s); |
||||
} |
||||
else |
||||
{ |
||||
g.metadata(nh).set(Journal{{s}}); |
||||
} |
||||
} |
||||
|
||||
// FIXME:
|
||||
// Unify with GModel::log(.. ade::NodeHandle ..)
|
||||
void GModel::log(Graph &g, ade::EdgeHandle eh, std::string &&msg, ade::NodeHandle updater) |
||||
{ |
||||
std::string s = std::move(msg); |
||||
if (updater != nullptr) |
||||
{ |
||||
std::stringstream fmt; |
||||
fmt << " (via " << updater << ")"; |
||||
s += fmt.str(); |
||||
} |
||||
|
||||
if (g.metadata(eh).contains<Journal>()) |
||||
{ |
||||
g.metadata(eh).get<Journal>().messages.push_back(s); |
||||
} |
||||
else |
||||
{ |
||||
g.metadata(eh).set(Journal{{s}}); |
||||
} |
||||
} |
||||
|
||||
ade::NodeHandle GModel::detail::dataNodeOf(const ConstGraph &g, const GOrigin &origin) |
||||
{ |
||||
// FIXME: Does it still work with graph transformations, e.g. redirectWriter()??
|
||||
return g.metadata().get<Layout>().object_nodes.at(origin); |
||||
} |
||||
|
||||
void GModel::redirectReaders(Graph &g, ade::NodeHandle from, ade::NodeHandle to) |
||||
{ |
||||
std::vector<ade::EdgeHandle> ehh(from->outEdges().begin(), from->outEdges().end()); |
||||
for (auto e : ehh) |
||||
{ |
||||
auto dst = e->dstNode(); |
||||
auto input = g.metadata(e).get<Input>(); |
||||
g.erase(e); |
||||
linkIn(g, dst, to, input.port); |
||||
} |
||||
} |
||||
|
||||
void GModel::redirectWriter(Graph &g, ade::NodeHandle from, ade::NodeHandle to) |
||||
{ |
||||
GAPI_Assert(from->inEdges().size() == 1); |
||||
auto e = from->inEdges().front(); |
||||
auto op = e->srcNode(); |
||||
auto output = g.metadata(e).get<Output>(); |
||||
g.erase(e); |
||||
linkOut(g, op, to, output.port); |
||||
} |
||||
|
||||
GMetaArgs GModel::collectInputMeta(GModel::ConstGraph cg, ade::NodeHandle node) |
||||
{ |
||||
GAPI_Assert(cg.metadata(node).get<NodeType>().t == NodeType::OP); |
||||
GMetaArgs in_meta_args(cg.metadata(node).get<Op>().args.size()); |
||||
|
||||
for (const auto &e : node->inEdges()) |
||||
{ |
||||
const auto& in_data = cg.metadata(e->srcNode()).get<Data>(); |
||||
in_meta_args[cg.metadata(e).get<Input>().port] = in_data.meta; |
||||
} |
||||
|
||||
return in_meta_args; |
||||
} |
||||
|
||||
|
||||
ade::EdgeHandle GModel::getInEdgeByPort(const GModel::ConstGraph& cg, |
||||
const ade::NodeHandle& nh, |
||||
std::size_t in_port) |
||||
{ |
||||
auto inEdges = nh->inEdges(); |
||||
const auto& edge = ade::util::find_if(inEdges, [&](ade::EdgeHandle eh) { |
||||
return cg.metadata(eh).get<Input>().port == in_port; |
||||
}); |
||||
GAPI_Assert(edge != inEdges.end()); |
||||
return *edge; |
||||
} |
||||
|
||||
GMetaArgs GModel::collectOutputMeta(GModel::ConstGraph cg, ade::NodeHandle node) |
||||
{ |
||||
GAPI_Assert(cg.metadata(node).get<NodeType>().t == NodeType::OP); |
||||
GMetaArgs out_meta_args(cg.metadata(node).get<Op>().outs.size()); |
||||
|
||||
for (const auto &e : node->outEdges()) |
||||
{ |
||||
const auto& out_data = cg.metadata(e->dstNode()).get<Data>(); |
||||
out_meta_args[cg.metadata(e).get<Output>().port] = out_data.meta; |
||||
} |
||||
|
||||
return out_meta_args; |
||||
} |
||||
|
||||
bool GModel::isActive(const GModel::Graph &cg, const cv::gapi::GBackend &backend) |
||||
{ |
||||
return ade::util::contains(cg.metadata().get<ActiveBackends>().backends, |
||||
backend); |
||||
} |
||||
|
||||
}} // cv::gimpl
|
@ -0,0 +1,251 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GMODEL_HPP |
||||
#define OPENCV_GAPI_GMODEL_HPP |
||||
|
||||
#include <memory> // shared_ptr |
||||
#include <unordered_map> |
||||
#include <functional> // std::function |
||||
|
||||
#include <ade/graph.hpp> |
||||
#include <ade/typed_graph.hpp> |
||||
#include <ade/passes/topological_sort.hpp> |
||||
|
||||
// /!\ ATTENTION:
|
||||
//
|
||||
// No API includes like GMat, GNode, GCall here!
|
||||
// This part of the system is API-unaware by its design.
|
||||
//
|
||||
|
||||
#include "opencv2/gapi/garg.hpp" |
||||
#include "opencv2/gapi/gkernel.hpp" |
||||
#include "api/gapi_priv.hpp" // GShape |
||||
#include "api/gproto_priv.hpp" // origin_of |
||||
#include "backends/common/gbackend.hpp" |
||||
|
||||
#include "compiler/gobjref.hpp" |
||||
#include "compiler/gislandmodel.hpp" |
||||
|
||||
namespace cv { namespace gimpl { |
||||
|
||||
// TODO: Document all metadata types
|
||||
|
||||
struct NodeType |
||||
{ |
||||
static const char *name() { return "NodeType"; } |
||||
enum { OP, DATA } t; |
||||
}; |
||||
|
||||
struct Input |
||||
{ |
||||
static const char *name() { return "Input"; } |
||||
std::size_t port; |
||||
}; |
||||
|
||||
struct Output |
||||
{ |
||||
static const char *name() { return "Output"; } |
||||
std::size_t port; |
||||
}; |
||||
|
||||
struct Op |
||||
{ |
||||
static const char *name() { return "Op"; } |
||||
cv::GKernel k; |
||||
std::vector<GArg> args; // TODO: Introduce a new type for internal args?
|
||||
std::vector<RcDesc> outs; // TODO: Introduce a new type for resource references
|
||||
|
||||
cv::gapi::GBackend backend; |
||||
util::any opaque; |
||||
}; |
||||
|
||||
struct Data |
||||
{ |
||||
static const char *name() { return "Data"; } |
||||
|
||||
// FIXME: This is a _pure_ duplication of RcDesc now! (except storage)
|
||||
GShape shape; // FIXME: Probably to be replaced by GMetaArg?
|
||||
int rc; |
||||
GMetaArg meta; |
||||
HostCtor ctor; // T-specific helper to deal with unknown types in our code
|
||||
// FIXME: Why rc+shape+meta is not represented as RcDesc here?
|
||||
|
||||
enum class Storage |
||||
{ |
||||
INTERNAL, // data object is not listed in GComputation protocol
|
||||
INPUT, // data object is listed in GComputation protocol as Input
|
||||
OUTPUT, // data object is listed in GComputation protocol as Output
|
||||
CONST, // data object is constant
|
||||
}; |
||||
Storage storage; |
||||
}; |
||||
|
||||
struct ConstValue |
||||
{ |
||||
static const char *name() { return "ConstValue"; } |
||||
GRunArg arg; |
||||
}; |
||||
|
||||
// This metadata is valid for both DATA and OP kinds of nodes
|
||||
// FIXME: Rename to IslandTag
|
||||
struct Island |
||||
{ |
||||
static const char *name() { return "Island"; } |
||||
std::string island; // can be set by user, otherwise is set by fusion
|
||||
}; |
||||
|
||||
struct Protocol |
||||
{ |
||||
static const char *name() { return "Protocol"; } |
||||
// TODO: Replace the whole thing with a "Protocol" object
|
||||
std::vector<RcDesc> inputs; |
||||
std::vector<RcDesc> outputs; |
||||
|
||||
std::vector<ade::NodeHandle> in_nhs; |
||||
std::vector<ade::NodeHandle> out_nhs; |
||||
}; |
||||
|
||||
struct OutputMeta |
||||
{ |
||||
static const char *name() { return "OutputMeta"; } |
||||
GMetaArgs outMeta; |
||||
}; |
||||
|
||||
struct Journal |
||||
{ |
||||
static const char *name() { return "Journal"; } |
||||
std::vector<std::string> messages; |
||||
}; |
||||
|
||||
// The mapping between user-side GMat/GScalar/... objects
|
||||
// and its appropriate nodes. Can be stored in graph optionally
|
||||
// (NOT used by any compiler or backends, introspection purposes
|
||||
// only)
|
||||
struct Layout |
||||
{ |
||||
static const char *name() { return "Layout"; } |
||||
GOriginMap<ade::NodeHandle> object_nodes; |
||||
}; |
||||
|
||||
// Unique data object counter (per-type)
|
||||
class DataObjectCounter |
||||
{ |
||||
public: |
||||
static const char* name() { return "DataObjectCounter"; } |
||||
int GetNewId(GShape shape) { return m_next_data_id[shape]++; } |
||||
private: |
||||
std::unordered_map<cv::GShape, int> m_next_data_id; |
||||
}; |
||||
|
||||
// A projected graph of Islands (generated from graph of Operations)
|
||||
struct IslandModel |
||||
{ |
||||
static const char* name() { return "IslandModel"; } |
||||
std::shared_ptr<ade::Graph> model; |
||||
}; |
||||
|
||||
// List of backends selected for current graph execution
|
||||
struct ActiveBackends |
||||
{ |
||||
static const char *name() { return "ActiveBackends"; } |
||||
std::unordered_set<cv::gapi::GBackend> backends; |
||||
}; |
||||
|
||||
namespace GModel |
||||
{ |
||||
using Graph = ade::TypedGraph |
||||
< NodeType |
||||
, Input |
||||
, Output |
||||
, Op |
||||
, Data |
||||
, ConstValue |
||||
, Island |
||||
, Protocol |
||||
, OutputMeta |
||||
, Journal |
||||
, ade::passes::TopologicalSortData |
||||
, DataObjectCounter |
||||
, Layout |
||||
, IslandModel |
||||
, ActiveBackends |
||||
>; |
||||
|
||||
// FIXME: How to define it based on GModel???
|
||||
using ConstGraph = ade::ConstTypedGraph |
||||
< NodeType |
||||
, Input |
||||
, Output |
||||
, Op |
||||
, Data |
||||
, ConstValue |
||||
, Island |
||||
, Protocol |
||||
, OutputMeta |
||||
, Journal |
||||
, ade::passes::TopologicalSortData |
||||
, DataObjectCounter |
||||
, Layout |
||||
, IslandModel |
||||
, ActiveBackends |
||||
>; |
||||
|
||||
// User should initialize graph before using it
|
||||
// GAPI_EXPORTS for tests
|
||||
GAPI_EXPORTS void init (Graph& g); |
||||
|
||||
ade::NodeHandle mkOpNode(Graph &g, const GKernel &k, const std::vector<GArg>& args, const std::string &island); |
||||
|
||||
// FIXME: change it to take GMeta instead of GShape?
|
||||
ade::NodeHandle mkDataNode(Graph &g, const GOrigin& origin); |
||||
|
||||
// Adds a string message to a node. Any node can be subject of log, messages then
|
||||
// appear in the dumped .dot file.x
|
||||
void log(Graph &g, ade::NodeHandle op, std::string &&message, ade::NodeHandle updater = ade::NodeHandle()); |
||||
void log(Graph &g, ade::EdgeHandle op, std::string &&message, ade::NodeHandle updater = ade::NodeHandle()); |
||||
|
||||
void linkIn (Graph &g, ade::NodeHandle op, ade::NodeHandle obj, std::size_t in_port); |
||||
void linkOut (Graph &g, ade::NodeHandle op, ade::NodeHandle obj, std::size_t out_port); |
||||
|
||||
// FIXME: Align this GModel API properly, it is a mess now
|
||||
namespace detail |
||||
{ |
||||
// FIXME: GAPI_EXPORTS only because of tests!!!
|
||||
GAPI_EXPORTS ade::NodeHandle dataNodeOf(const ConstGraph& g, const GOrigin &origin); |
||||
} |
||||
template<typename T> inline ade::NodeHandle dataNodeOf(const ConstGraph& g, T &&t) |
||||
{ |
||||
return detail::dataNodeOf(g, cv::gimpl::proto::origin_of(GProtoArg{t})); |
||||
} |
||||
|
||||
void linkIn (Graph &g, ade::NodeHandle op, ade::NodeHandle obj, std::size_t in_port); |
||||
void linkOut (Graph &g, ade::NodeHandle op, ade::NodeHandle obj, std::size_t out_port); |
||||
|
||||
void redirectReaders(Graph &g, ade::NodeHandle from, ade::NodeHandle to); |
||||
void redirectWriter (Graph &g, ade::NodeHandle from, ade::NodeHandle to); |
||||
|
||||
std::vector<ade::NodeHandle> orderedInputs (Graph &g, ade::NodeHandle nh); |
||||
std::vector<ade::NodeHandle> orderedOutputs(Graph &g, ade::NodeHandle nh); |
||||
|
||||
// Returns input meta array for given op node
|
||||
// Array is sparse, as metadata for non-gapi input objects is empty
|
||||
// TODO:
|
||||
// Cover with tests!!
|
||||
GMetaArgs collectInputMeta(GModel::ConstGraph cg, ade::NodeHandle node); |
||||
GMetaArgs collectOutputMeta(GModel::ConstGraph cg, ade::NodeHandle node); |
||||
|
||||
ade::EdgeHandle getInEdgeByPort(const GModel::ConstGraph& cg, const ade::NodeHandle& nh, std::size_t in_port); |
||||
|
||||
// Returns true if the given backend participates in the execution
|
||||
bool isActive(const GModel::Graph &cg, const cv::gapi::GBackend &backend); |
||||
} // namespace GModel
|
||||
|
||||
|
||||
}} // namespace cv::gimpl
|
||||
|
||||
#endif // OPENCV_GAPI_GMODEL_HPP
|
@ -0,0 +1,303 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// FIXME: "I personally hate this file"
|
||||
// - Dmitry
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include <utility> // tuple |
||||
#include <stack> // stack |
||||
#include <vector> // vector |
||||
#include <unordered_set> // unordered_set |
||||
#include <type_traits> // is_same |
||||
|
||||
#include <ade/util/zip_range.hpp> // util::indexed |
||||
|
||||
#include "api/gapi_priv.hpp" // GOrigin |
||||
#include "api/gproto_priv.hpp" // descriptor_of and other GProtoArg-related |
||||
#include "api/gcall_priv.hpp" |
||||
#include "api/gnode_priv.hpp" |
||||
|
||||
#include "compiler/gmodelbuilder.hpp" |
||||
|
||||
namespace { |
||||
|
||||
|
||||
// TODO: move to helpers and cover with internal tests?
|
||||
template<typename T> struct GVisited |
||||
{ |
||||
typedef std::unordered_set<T> VTs; |
||||
|
||||
bool visited(const T& t) const { return m_visited.find(t) != m_visited.end(); } |
||||
void visit (const T& t) { m_visited.insert(t); } |
||||
const VTs& visited() const { return m_visited; } |
||||
|
||||
private: |
||||
VTs m_visited; |
||||
}; |
||||
|
||||
template<typename T, typename U = T> struct GVisitedTracker: protected GVisited<T> |
||||
{ |
||||
typedef std::vector<U> TUs; |
||||
|
||||
void visit(const T& t, const U& u) { GVisited<T>::visit(t); m_tracked.push_back(u); } |
||||
const TUs& tracked() const { return m_tracked; } |
||||
using GVisited<T>::visited; |
||||
|
||||
private: |
||||
TUs m_tracked; |
||||
}; |
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
cv::gimpl::Unrolled cv::gimpl::unrollExpr(const GProtoArgs &ins, |
||||
const GProtoArgs &outs) |
||||
{ |
||||
// FIXME: Who's gonna check if ins/outs are not EMPTY?
|
||||
// FIXME: operator== for GObjects? (test if the same object or not)
|
||||
using GObjId = const cv::GOrigin*; |
||||
|
||||
GVisitedTracker<const GNode::Priv*, cv::GNode> ops; |
||||
GVisited<GObjId> reached_sources; |
||||
cv::GOriginSet origins; |
||||
|
||||
// Cache input argument objects for a faster look-up
|
||||
// While the only reliable way to identify a Data object is Origin
|
||||
// (multiple data objects may refer to the same Origin as result of
|
||||
// multuple yield() calls), input objects can be uniquely identified
|
||||
// by its `priv` address. Here we rely on this to verify if the expression
|
||||
// we unroll actually matches the protocol specified to us by user.
|
||||
std::unordered_set<GObjId> in_objs_p; |
||||
for (const auto& in_obj : ins) |
||||
{ |
||||
// Objects are guarnateed to remain alive while this method
|
||||
// is working, so it is safe to keep pointers here and below
|
||||
in_objs_p.insert(&proto::origin_of(in_obj)); |
||||
} |
||||
|
||||
// Recursive expression traversal
|
||||
std::stack<cv::GProtoArg> data_objs(std::deque<cv::GProtoArg>(outs.begin(), outs.end())); |
||||
while (!data_objs.empty()) |
||||
{ |
||||
const auto obj = data_objs.top(); |
||||
const auto &obj_p = proto::origin_of(obj); |
||||
data_objs.pop(); |
||||
|
||||
const auto &origin = obj_p; |
||||
origins.insert(origin); // TODO: Put Object description here later on
|
||||
|
||||
// If this Object is listed in the protocol, don't dive deeper (even
|
||||
// if it is in fact a result of operation). Our computation is
|
||||
// bounded by this data slot, so terminate this recursion path early.
|
||||
if (in_objs_p.find(&obj_p) != in_objs_p.end()) |
||||
{ |
||||
reached_sources.visit(&obj_p); |
||||
continue; |
||||
} |
||||
|
||||
const cv::GNode &node = origin.node; |
||||
switch (node.shape()) |
||||
{ |
||||
case cv::GNode::NodeShape::EMPTY: |
||||
// TODO: Own exception type?
|
||||
util::throw_error(std::logic_error("Empty node reached!")); |
||||
break; |
||||
|
||||
case cv::GNode::NodeShape::PARAM: |
||||
case cv::GNode::NodeShape::CONST_BOUNDED: |
||||
// No preceding operation to this data object - so the data object is either a GComputation
|
||||
// parameter or a constant (compile-time) value
|
||||
// Record it to check if protocol matches expression tree later
|
||||
if (!reached_sources.visited(&obj_p)) |
||||
reached_sources.visit(&obj_p); |
||||
break; |
||||
|
||||
case cv::GNode::NodeShape::CALL: |
||||
if (!ops.visited(&node.priv())) |
||||
{ |
||||
// This operation hasn't been visited yet - mark it so,
|
||||
// then add its operands to stack to continue recursion.
|
||||
ops.visit(&node.priv(), node); |
||||
|
||||
const cv::GCall call = origin.node.call(); |
||||
const cv::GCall::Priv& call_p = call.priv(); |
||||
|
||||
// Put the outputs object description of the node
|
||||
// so that they are not lost if they are not consumed by other operations
|
||||
for (const auto &it : ade::util::indexed(call_p.m_k.outShapes)) |
||||
{ |
||||
std::size_t port = ade::util::index(it); |
||||
GShape shape = ade::util::value(it); |
||||
|
||||
GOrigin org { shape, node, port}; |
||||
origins.insert(org); |
||||
} |
||||
|
||||
for (const auto &arg : call_p.m_args) |
||||
{ |
||||
if (proto::is_dynamic(arg)) |
||||
{ |
||||
data_objs.push(proto::rewrap(arg)); // Dive deeper
|
||||
} |
||||
} |
||||
} |
||||
break; |
||||
|
||||
default: |
||||
// Unsupported node shape
|
||||
GAPI_Assert(false); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
// Check if protocol mentions data_objs which weren't reached during traversal
|
||||
const auto missing_reached_sources = [&reached_sources](GObjId p) { |
||||
return reached_sources.visited().find(p) == reached_sources.visited().end(); |
||||
}; |
||||
if (ade::util::any_of(in_objs_p, missing_reached_sources)) |
||||
{ |
||||
// TODO: Own exception type or a return code?
|
||||
util::throw_error(std::logic_error("Data object listed in Protocol " |
||||
"wasn\'t reached during unroll")); |
||||
} |
||||
|
||||
// Check if there endpoint (parameter) data_objs which are not listed in protocol
|
||||
const auto missing_in_proto = [&in_objs_p](GObjId p) { |
||||
return p->node.shape() != cv::GNode::NodeShape::CONST_BOUNDED && |
||||
in_objs_p.find(p) == in_objs_p.end(); |
||||
}; |
||||
if (ade::util::any_of(reached_sources.visited(), missing_in_proto)) |
||||
{ |
||||
// TODO: Own exception type or a return code?
|
||||
util::throw_error(std::logic_error("Data object reached during unroll " |
||||
"wasn\'t found in Protocol")); |
||||
} |
||||
|
||||
return cv::gimpl::Unrolled{ops.tracked(), origins}; |
||||
} |
||||
|
||||
|
||||
cv::gimpl::GModelBuilder::GModelBuilder(ade::Graph &g) |
||||
: m_g(g) |
||||
{ |
||||
} |
||||
|
||||
cv::gimpl::GModelBuilder::ProtoSlots |
||||
cv::gimpl::GModelBuilder::put(const GProtoArgs &ins, const GProtoArgs &outs) |
||||
{ |
||||
const auto unrolled = cv::gimpl::unrollExpr(ins, outs); |
||||
|
||||
// First, put all operations and its arguments into graph.
|
||||
for (const auto &op_expr_node : unrolled.all_ops) |
||||
{ |
||||
GAPI_Assert(op_expr_node.shape() == GNode::NodeShape::CALL); |
||||
const GCall& call = op_expr_node.call(); |
||||
const GCall::Priv& call_p = call.priv(); |
||||
ade::NodeHandle call_h = put_OpNode(op_expr_node); |
||||
|
||||
for (const auto &it : ade::util::indexed(call_p.m_args)) |
||||
{ |
||||
const auto in_port = ade::util::index(it); |
||||
const auto& in_arg = ade::util::value(it); |
||||
|
||||
if (proto::is_dynamic(in_arg)) |
||||
{ |
||||
ade::NodeHandle data_h = put_DataNode(proto::origin_of(in_arg)); |
||||
cv::gimpl::GModel::linkIn(m_g, call_h, data_h, in_port); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Then iterate via all "origins", instantiate (if not yet) Data graph nodes
|
||||
// and connect these nodes with their producers in graph
|
||||
for (const auto &origin : unrolled.all_data) |
||||
{ |
||||
const cv::GNode& prod = origin.node; |
||||
GAPI_Assert(prod.shape() != cv::GNode::NodeShape::EMPTY); |
||||
|
||||
ade::NodeHandle data_h = put_DataNode(origin); |
||||
if (prod.shape() == cv::GNode::NodeShape::CALL) |
||||
{ |
||||
ade::NodeHandle call_h = put_OpNode(prod); |
||||
cv::gimpl::GModel::linkOut(m_g, call_h, data_h, origin.port); |
||||
} |
||||
} |
||||
|
||||
// Mark graph data nodes as INPUTs and OUTPUTs respectively (according to the protocol)
|
||||
for (const auto &arg : ins) |
||||
{ |
||||
ade::NodeHandle nh = put_DataNode(proto::origin_of(arg)); |
||||
m_g.metadata(nh).get<Data>().storage = Data::Storage::INPUT; |
||||
} |
||||
for (const auto &arg : outs) |
||||
{ |
||||
ade::NodeHandle nh = put_DataNode(proto::origin_of(arg)); |
||||
m_g.metadata(nh).get<Data>().storage = Data::Storage::OUTPUT; |
||||
} |
||||
|
||||
// And, finally, store data object layout in meta
|
||||
m_g.metadata().set(Layout{m_graph_data}); |
||||
|
||||
// After graph is generated, specify which data objects are actually
|
||||
// computation entry/exit points.
|
||||
using NodeDescr = std::pair<std::vector<RcDesc>, |
||||
std::vector<ade::NodeHandle> >; |
||||
|
||||
const auto get_proto_slots = [&](const GProtoArgs &proto) -> NodeDescr |
||||
{ |
||||
NodeDescr slots; |
||||
|
||||
slots.first.reserve(proto.size()); |
||||
slots.second.reserve(proto.size()); |
||||
|
||||
for (const auto &arg : proto) |
||||
{ |
||||
ade::NodeHandle nh = put_DataNode(proto::origin_of(arg)); |
||||
const auto &desc = m_g.metadata(nh).get<Data>(); |
||||
//These extra empty {} are to please GCC (-Wmissing-field-initializers)
|
||||
slots.first.push_back(RcDesc{desc.rc, desc.shape, {}}); |
||||
slots.second.push_back(nh); |
||||
} |
||||
return slots; |
||||
}; |
||||
|
||||
auto in_slots = get_proto_slots(ins); |
||||
auto out_slots = get_proto_slots(outs); |
||||
return ProtoSlots{in_slots.first, out_slots.first, |
||||
in_slots.second, out_slots.second}; |
||||
} |
||||
|
||||
ade::NodeHandle cv::gimpl::GModelBuilder::put_OpNode(const cv::GNode &node) |
||||
{ |
||||
const auto& node_p = node.priv(); |
||||
const auto it = m_graph_ops.find(&node_p); |
||||
if (it == m_graph_ops.end()) |
||||
{ |
||||
GAPI_Assert(node.shape() == GNode::NodeShape::CALL); |
||||
const auto &call_p = node.call().priv(); |
||||
auto nh = cv::gimpl::GModel::mkOpNode(m_g, call_p.m_k, call_p.m_args, node_p.m_island); |
||||
m_graph_ops[&node_p] = nh; |
||||
return nh; |
||||
} |
||||
else return it->second; |
||||
} |
||||
|
||||
// FIXME: rename to get_DataNode (and same for Op)
|
||||
ade::NodeHandle cv::gimpl::GModelBuilder::put_DataNode(const GOrigin &origin) |
||||
{ |
||||
const auto it = m_graph_data.find(origin); |
||||
if (it == m_graph_data.end()) |
||||
{ |
||||
auto nh = cv::gimpl::GModel::mkDataNode(m_g, origin); |
||||
m_graph_data[origin] = nh; |
||||
return nh; |
||||
} |
||||
else return it->second; |
||||
} |
@ -0,0 +1,77 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GMODEL_BUILDER_HPP |
||||
#define OPENCV_GAPI_GMODEL_BUILDER_HPP |
||||
|
||||
#include <map> |
||||
#include <unordered_map> |
||||
|
||||
#include "opencv2/gapi/gproto.hpp" |
||||
#include "opencv2/gapi/gcall.hpp" |
||||
|
||||
#include "api/gapi_priv.hpp" |
||||
#include "api/gnode.hpp" |
||||
#include "compiler/gmodel.hpp" |
||||
|
||||
namespace cv { namespace gimpl { |
||||
|
||||
struct Unrolled |
||||
{ |
||||
std::vector<cv::GNode> all_ops; |
||||
GOriginSet all_data; |
||||
|
||||
// NB.: Right now, as G-API operates with GMats only and that
|
||||
// GMats have no type or dimensions (when a computation is built),
|
||||
// track only origins (data links) with no any additional meta.
|
||||
}; |
||||
|
||||
// FIXME: GAPI_EXPORTS only because of tests!!!
|
||||
GAPI_EXPORTS Unrolled unrollExpr(const GProtoArgs &ins, const GProtoArgs &outs); |
||||
|
||||
// This class generates an ADE graph with G-API specific metadata
|
||||
// to represent user-specified computation in terms of graph model
|
||||
//
|
||||
// Resulting graph is built according to the following rules:
|
||||
// - Every operation is a node
|
||||
// - Every dynamic object (GMat) is a node
|
||||
// - Edges between nodes represent producer/consumer relationships
|
||||
// between operations and data objects.
|
||||
// FIXME: GAPI_EXPORTS only because of tests!!!
|
||||
class GAPI_EXPORTS GModelBuilder |
||||
{ |
||||
GModel::Graph m_g; |
||||
|
||||
// Mappings of G-API user framework entities to ADE node handles
|
||||
std::unordered_map<const cv::GNode::Priv*, ade::NodeHandle> m_graph_ops; |
||||
GOriginMap<ade::NodeHandle> m_graph_data; |
||||
|
||||
// Internal methods for mapping APIs into ADE during put()
|
||||
ade::NodeHandle put_OpNode(const cv::GNode &node); |
||||
ade::NodeHandle put_DataNode(const cv::GOrigin &origin); |
||||
|
||||
public: |
||||
explicit GModelBuilder(ade::Graph &g); |
||||
|
||||
// TODO: replace GMat with a generic type
|
||||
// TODO: Cover with tests! (as the rest of internal stuff)
|
||||
// FIXME: Calling this method multiple times is currently UB
|
||||
// TODO: add a semantic link between "ints" returned and in-model data IDs.
|
||||
typedef std::tuple<std::vector<RcDesc>, |
||||
std::vector<RcDesc>, |
||||
std::vector<ade::NodeHandle>, |
||||
std::vector<ade::NodeHandle> > ProtoSlots; |
||||
|
||||
ProtoSlots put(const GProtoArgs &ins, const GProtoArgs &outs); |
||||
|
||||
protected: |
||||
ade::NodeHandle opNode(cv::GMat gmat); |
||||
}; |
||||
|
||||
}} |
||||
|
||||
#endif // OPENCV_GAPI_GMODEL_BUILDER_HPP
|
@ -0,0 +1,50 @@ |
||||
// 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) 2018 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GMATREF_HPP |
||||
#define OPENCV_GAPI_GMATREF_HPP |
||||
|
||||
#include "opencv2/gapi/util/variant.hpp" |
||||
#include "opencv2/gapi/garg.hpp" |
||||
|
||||
#include "api/gapi_priv.hpp" // GShape, HostCtor |
||||
|
||||
namespace cv |
||||
{ |
||||
|
||||
namespace gimpl |
||||
{ |
||||
struct RcDesc |
||||
{ |
||||
int id; // id is unique but local to shape
|
||||
GShape shape; // pair <id,shape> IS the unique ID
|
||||
HostCtor ctor; // FIXME: is it really used here? Or in <Data>?
|
||||
|
||||
bool operator==(const RcDesc &rhs) const |
||||
{ |
||||
// FIXME: ctor is not checked (should be?)
|
||||
return id == rhs.id && shape == rhs.shape; |
||||
} |
||||
|
||||
bool operator< (const RcDesc &rhs) const |
||||
{ |
||||
return (id == rhs.id) ? shape < rhs.shape : id < rhs.id; |
||||
} |
||||
}; |
||||
} // gimpl
|
||||
|
||||
namespace detail |
||||
{ |
||||
template<> struct GTypeTraits<cv::gimpl::RcDesc> |
||||
{ |
||||
static constexpr const ArgKind kind = ArgKind::GOBJREF; |
||||
}; |
||||
} |
||||
|
||||
} // cv
|
||||
|
||||
#endif // OPENCV_GAPI_GMATREF_HPP
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue