mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 15:23:05 +04:00
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 tests
This commit is contained in:
committed by
Alexander Alekhin
parent
852f061b26
commit
29e88e50ff
@@ -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
Reference in New Issue
Block a user