1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 15:53:03 +04:00

Merge pull request #13008 from dbudniko:dbudniko/gpu_opencl_backend

G-API GPU-OpenCL backend (#13008)

* gpu/ocl backend core

* accuracy tests added and adjusted + license headers

* GPU perf. tests added; almost all adjusted to pass

* all tests adjusted and passed - ready for pull request

* missing license headers

* fix warning (workaround RGB2Gray)

* fix c++ magic

* precompiled header

* white spaces

* try to fix warning and blur test

* try to fix Blur perf tests

* more alignments with the latest cpu backend

* more gapi tests refactoring + 1 more UB issue fix + more informative tolerance exceed reports

* white space fix

* try workaround for SumTest

* GAPI_EXPORTS instead CV_EXPORTS
This commit is contained in:
Dmitry Budnikov
2018-11-08 22:14:53 +03:00
committed by Alexander Alekhin
parent ebc8015638
commit 5087ff0814
39 changed files with 3677 additions and 729 deletions
@@ -45,18 +45,21 @@ namespace magazine {
};
} // namespace magazine
#if !defined(GAPI_STANDALONE)
using Mag = magazine::Class<cv::gapi::own::Mat, cv::UMat, cv::gapi::own::Scalar, cv::detail::VectorRef>;
#else
using Mag = magazine::Class<cv::gapi::own::Mat, cv::gapi::own::Scalar, cv::detail::VectorRef>;
#endif
namespace magazine
{
void bindInArg (Mag& mag, const RcDesc &rc, const GRunArg &arg);
void bindOutArg(Mag& mag, const RcDesc &rc, const GRunArgP &arg);
void bindInArg (Mag& mag, const RcDesc &rc, const GRunArg &arg, bool is_umat = false);
void bindOutArg(Mag& mag, const RcDesc &rc, const GRunArgP &arg, bool is_umat = false);
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);
cv::GRunArgP getObjPtr ( Mag& mag, const RcDesc &rc, bool is_umat = false);
void writeBack (const Mag& mag, const RcDesc &rc, GRunArgP &g_arg, bool is_umat = false);
} // namespace magazine
namespace detail
@@ -0,0 +1,226 @@
// 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 <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/gpu/ggpubackend.hpp"
#include "backends/gpu/ggpuimgproc.hpp"
#include "backends/gpu/ggpucore.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 GGPUModel = ade::TypedGraph
< cv::gimpl::Unit
, cv::gimpl::Protocol
>;
// FIXME: Same issue with Typed and ConstTyped
using GConstGGPUModel = ade::ConstTypedGraph
< cv::gimpl::Unit
, cv::gimpl::Protocol
>;
namespace
{
class GGPUBackendImpl final: public cv::gapi::GBackend::Priv
{
virtual void unpackKernel(ade::Graph &graph,
const ade::NodeHandle &op_node,
const cv::GKernelImpl &impl) override
{
GGPUModel gm(graph);
auto gpu_impl = cv::util::any_cast<cv::GGPUKernel>(impl.opaque);
gm.metadata(op_node).set(cv::gimpl::Unit{gpu_impl});
}
virtual EPtr compile(const ade::Graph &graph,
const cv::GCompileArgs &,
const std::vector<ade::NodeHandle> &nodes) const override
{
return EPtr{new cv::gimpl::GGPUExecutable(graph, nodes)};
}
};
}
cv::gapi::GBackend cv::gapi::gpu::backend()
{
static cv::gapi::GBackend this_backend(std::make_shared<GGPUBackendImpl>());
return this_backend;
}
// GGPUExcecutable implementation //////////////////////////////////////////////
cv::gimpl::GGPUExecutable::GGPUExecutable(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::UMat>()[desc.rc].create(mat_desc.size.width, mat_desc.size.height, type);
}
break;
}
default: util::throw_error(std::logic_error("Unsupported NodeType type"));
}
}
}
// FIXME: Document what it does
cv::GArg cv::gimpl::GGPUExecutable::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::UMat>()[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::GGPUExecutable::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, true);
for (auto& it : output_objs) magazine::bindOutArg(m_res, it.first, it.second, true);
// 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.
GConstGGPUModel 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?
GGPUKernel k = gcm.metadata(op_info.nh).get<Unit>().k;
// Initialize kernel's execution context:
// - Input parameters
GGPUContext 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(&GGPUExecutable::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, true);
}
// Now trigger the executable unit
k.apply(context);
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, true);
}
@@ -0,0 +1,72 @@
// 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_GGPUBACKEND_HPP
#define OPENCV_GAPI_GGPUBACKEND_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/gpu/ggpukernel.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 "GPUKernel"; }
GGPUKernel k;
};
class GGPUExecutable 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:
GGPUExecutable(const ade::Graph &graph,
const std::vector<ade::NodeHandle> &nodes);
virtual inline bool canReshape() const override { return false; }
virtual inline void reshape(ade::Graph&, const GCompileArgs&) override
{
// FIXME: GPU plugin is in fact reshapeable (as it was initially,
// even before outMeta() has been introduced), so this limitation
// should be dropped.
util::throw_error(std::logic_error("GGPUExecutable::reshape() should never be called"));
}
virtual void run(std::vector<InObj> &&input_objs,
std::vector<OutObj> &&output_objs) override;
};
}}
#endif // OPENCV_GAPI_GGPUBACKEND_HPP
+582
View File
@@ -0,0 +1,582 @@
// 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/gpu/core.hpp"
#include "backends/gpu/ggpucore.hpp"
GAPI_GPU_KERNEL(GGPUAdd, cv::gapi::core::GAdd)
{
static void run(const cv::UMat& a, const cv::UMat& b, int dtype, cv::UMat& out)
{
cv::add(a, b, out, cv::noArray(), dtype);
}
};
GAPI_GPU_KERNEL(GGPUAddC, cv::gapi::core::GAddC)
{
static void run(const cv::UMat& a, const cv::Scalar& b, int dtype, cv::UMat& out)
{
cv::add(a, b, out, cv::noArray(), dtype);
}
};
GAPI_GPU_KERNEL(GGPUSub, cv::gapi::core::GSub)
{
static void run(const cv::UMat& a, const cv::UMat& b, int dtype, cv::UMat& out)
{
cv::subtract(a, b, out, cv::noArray(), dtype);
}
};
GAPI_GPU_KERNEL(GGPUSubC, cv::gapi::core::GSubC)
{
static void run(const cv::UMat& a, const cv::Scalar& b, int dtype, cv::UMat& out)
{
cv::subtract(a, b, out, cv::noArray(), dtype);
}
};
GAPI_GPU_KERNEL(GGPUSubRC, cv::gapi::core::GSubRC)
{
static void run(const cv::Scalar& a, const cv::UMat& b, int dtype, cv::UMat& out)
{
cv::subtract(a, b, out, cv::noArray(), dtype);
}
};
GAPI_GPU_KERNEL(GGPUMul, cv::gapi::core::GMul)
{
static void run(const cv::UMat& a, const cv::UMat& b, double scale, int dtype, cv::UMat& out)
{
cv::multiply(a, b, out, scale, dtype);
}
};
GAPI_GPU_KERNEL(GGPUMulCOld, cv::gapi::core::GMulCOld)
{
static void run(const cv::UMat& a, double b, int dtype, cv::UMat& out)
{
cv::multiply(a, b, out, 1, dtype);
}
};
GAPI_GPU_KERNEL(GGPUMulC, cv::gapi::core::GMulC)
{
static void run(const cv::UMat& a, const cv::Scalar& b, int dtype, cv::UMat& out)
{
cv::multiply(a, b, out, 1, dtype);
}
};
GAPI_GPU_KERNEL(GGPUDiv, cv::gapi::core::GDiv)
{
static void run(const cv::UMat& a, const cv::UMat& b, double scale, int dtype, cv::UMat& out)
{
cv::divide(a, b, out, scale, dtype);
}
};
GAPI_GPU_KERNEL(GGPUDivC, cv::gapi::core::GDivC)
{
static void run(const cv::UMat& a, const cv::Scalar& b, double scale, int dtype, cv::UMat& out)
{
cv::divide(a, b, out, scale, dtype);
}
};
GAPI_GPU_KERNEL(GGPUDivRC, cv::gapi::core::GDivRC)
{
static void run(const cv::Scalar& a, const cv::UMat& b, double scale, int dtype, cv::UMat& out)
{
cv::divide(a, b, out, scale, dtype);
}
};
GAPI_GPU_KERNEL(GGPUMask, cv::gapi::core::GMask)
{
static void run(const cv::UMat& in, const cv::UMat& mask, cv::UMat& out)
{
out = cv::UMat::zeros(in.size(), in.type());
in.copyTo(out, mask);
}
};
GAPI_GPU_KERNEL(GGPUMean, cv::gapi::core::GMean)
{
static void run(const cv::UMat& in, cv::Scalar& out)
{
out = cv::mean(in);
}
};
GAPI_GPU_KERNEL(GGPUPolarToCart, cv::gapi::core::GPolarToCart)
{
static void run(const cv::UMat& magn, const cv::UMat& angle, bool angleInDegrees, cv::UMat& outx, cv::UMat& outy)
{
cv::polarToCart(magn, angle, outx, outy, angleInDegrees);
}
};
GAPI_GPU_KERNEL(GGPUCartToPolar, cv::gapi::core::GCartToPolar)
{
static void run(const cv::UMat& x, const cv::UMat& y, bool angleInDegrees, cv::UMat& outmagn, cv::UMat& outangle)
{
cv::cartToPolar(x, y, outmagn, outangle, angleInDegrees);
}
};
GAPI_GPU_KERNEL(GGPUCmpGT, cv::gapi::core::GCmpGT)
{
static void run(const cv::UMat& a, const cv::UMat& b, cv::UMat& out)
{
cv::compare(a, b, out, cv::CMP_GT);
}
};
GAPI_GPU_KERNEL(GGPUCmpGE, cv::gapi::core::GCmpGE)
{
static void run(const cv::UMat& a, const cv::UMat& b, cv::UMat& out)
{
cv::compare(a, b, out, cv::CMP_GE);
}
};
GAPI_GPU_KERNEL(GGPUCmpLE, cv::gapi::core::GCmpLE)
{
static void run(const cv::UMat& a, const cv::UMat& b, cv::UMat& out)
{
cv::compare(a, b, out, cv::CMP_LE);
}
};
GAPI_GPU_KERNEL(GGPUCmpLT, cv::gapi::core::GCmpLT)
{
static void run(const cv::UMat& a, const cv::UMat& b, cv::UMat& out)
{
cv::compare(a, b, out, cv::CMP_LT);
}
};
GAPI_GPU_KERNEL(GGPUCmpEQ, cv::gapi::core::GCmpEQ)
{
static void run(const cv::UMat& a, const cv::UMat& b, cv::UMat& out)
{
cv::compare(a, b, out, cv::CMP_EQ);
}
};
GAPI_GPU_KERNEL(GGPUCmpNE, cv::gapi::core::GCmpNE)
{
static void run(const cv::UMat& a, const cv::UMat& b, cv::UMat& out)
{
cv::compare(a, b, out, cv::CMP_NE);
}
};
GAPI_GPU_KERNEL(GGPUCmpGTScalar, cv::gapi::core::GCmpGTScalar)
{
static void run(const cv::UMat& a, const cv::Scalar& b, cv::UMat& out)
{
cv::compare(a, b, out, cv::CMP_GT);
}
};
GAPI_GPU_KERNEL(GGPUCmpGEScalar, cv::gapi::core::GCmpGEScalar)
{
static void run(const cv::UMat& a, const cv::Scalar& b, cv::UMat& out)
{
cv::compare(a, b, out, cv::CMP_GE);
}
};
GAPI_GPU_KERNEL(GGPUCmpLEScalar, cv::gapi::core::GCmpLEScalar)
{
static void run(const cv::UMat& a, const cv::Scalar& b, cv::UMat& out)
{
cv::compare(a, b, out, cv::CMP_LE);
}
};
GAPI_GPU_KERNEL(GGPUCmpLTScalar, cv::gapi::core::GCmpLTScalar)
{
static void run(const cv::UMat& a, const cv::Scalar& b, cv::UMat& out)
{
cv::compare(a, b, out, cv::CMP_LT);
}
};
GAPI_GPU_KERNEL(GGPUCmpEQScalar, cv::gapi::core::GCmpEQScalar)
{
static void run(const cv::UMat& a, const cv::Scalar& b, cv::UMat& out)
{
cv::compare(a, b, out, cv::CMP_EQ);
}
};
GAPI_GPU_KERNEL(GGPUCmpNEScalar, cv::gapi::core::GCmpNEScalar)
{
static void run(const cv::UMat& a, const cv::Scalar& b, cv::UMat& out)
{
cv::compare(a, b, out, cv::CMP_NE);
}
};
GAPI_GPU_KERNEL(GGPUAnd, cv::gapi::core::GAnd)
{
static void run(const cv::UMat& a, const cv::UMat& b, cv::UMat& out)
{
cv::bitwise_and(a, b, out);
}
};
GAPI_GPU_KERNEL(GGPUAndS, cv::gapi::core::GAndS)
{
static void run(const cv::UMat& a, const cv::Scalar& b, cv::UMat& out)
{
cv::bitwise_and(a, b, out);
}
};
GAPI_GPU_KERNEL(GGPUOr, cv::gapi::core::GOr)
{
static void run(const cv::UMat& a, const cv::UMat& b, cv::UMat& out)
{
cv::bitwise_or(a, b, out);
}
};
GAPI_GPU_KERNEL(GGPUOrS, cv::gapi::core::GOrS)
{
static void run(const cv::UMat& a, const cv::Scalar& b, cv::UMat& out)
{
cv::bitwise_or(a, b, out);
}
};
GAPI_GPU_KERNEL(GGPUXor, cv::gapi::core::GXor)
{
static void run(const cv::UMat& a, const cv::UMat& b, cv::UMat& out)
{
cv::bitwise_xor(a, b, out);
}
};
GAPI_GPU_KERNEL(GGPUXorS, cv::gapi::core::GXorS)
{
static void run(const cv::UMat& a, const cv::Scalar& b, cv::UMat& out)
{
cv::bitwise_xor(a, b, out);
}
};
GAPI_GPU_KERNEL(GGPUNot, cv::gapi::core::GNot)
{
static void run(const cv::UMat& a, cv::UMat& out)
{
cv::bitwise_not(a, out);
}
};
GAPI_GPU_KERNEL(GGPUSelect, cv::gapi::core::GSelect)
{
static void run(const cv::UMat& src1, const cv::UMat& src2, const cv::UMat& mask, cv::UMat& out)
{
src2.copyTo(out);
src1.copyTo(out, mask);
}
};
////TODO: doesn't compiled with UMat
//GAPI_GPU_KERNEL(GGPUMin, cv::gapi::core::GMin)
//{
// static void run(const cv::UMat& in1, const cv::UMat& in2, cv::UMat& out)
// {
// out = cv::min(in1, in2);
// }
//};
//
////TODO: doesn't compiled with UMat
//GAPI_GPU_KERNEL(GGPUMax, cv::gapi::core::GMax)
//{
// static void run(const cv::UMat& in1, const cv::UMat& in2, cv::UMat& out)
// {
// out = cv::max(in1, in2);
// }
//};
GAPI_GPU_KERNEL(GGPUAbsDiff, cv::gapi::core::GAbsDiff)
{
static void run(const cv::UMat& in1, const cv::UMat& in2, cv::UMat& out)
{
cv::absdiff(in1, in2, out);
}
};
GAPI_GPU_KERNEL(GGPUAbsDiffC, cv::gapi::core::GAbsDiffC)
{
static void run(const cv::UMat& in1, const cv::Scalar& in2, cv::UMat& out)
{
cv::absdiff(in1, in2, out);
}
};
GAPI_GPU_KERNEL(GGPUSum, cv::gapi::core::GSum)
{
static void run(const cv::UMat& in, cv::Scalar& out)
{
out = cv::sum(in);
}
};
GAPI_GPU_KERNEL(GGPUAddW, cv::gapi::core::GAddW)
{
static void run(const cv::UMat& in1, double alpha, const cv::UMat& in2, double beta, double gamma, int dtype, cv::UMat& out)
{
cv::addWeighted(in1, alpha, in2, beta, gamma, out, dtype);
}
};
GAPI_GPU_KERNEL(GGPUNormL1, cv::gapi::core::GNormL1)
{
static void run(const cv::UMat& in, cv::Scalar& out)
{
out = cv::norm(in, cv::NORM_L1);
}
};
GAPI_GPU_KERNEL(GGPUNormL2, cv::gapi::core::GNormL2)
{
static void run(const cv::UMat& in, cv::Scalar& out)
{
out = cv::norm(in, cv::NORM_L2);
}
};
GAPI_GPU_KERNEL(GGPUNormInf, cv::gapi::core::GNormInf)
{
static void run(const cv::UMat& in, cv::Scalar& out)
{
out = cv::norm(in, cv::NORM_INF);
}
};
GAPI_GPU_KERNEL(GGPUIntegral, cv::gapi::core::GIntegral)
{
static void run(const cv::UMat& in, int sdepth, int sqdepth, cv::UMat& out, cv::UMat& outSq)
{
cv::integral(in, out, outSq, sdepth, sqdepth);
}
};
GAPI_GPU_KERNEL(GGPUThreshold, cv::gapi::core::GThreshold)
{
static void run(const cv::UMat& in, const cv::Scalar& a, const cv::Scalar& b, int type, cv::UMat& out)
{
cv::threshold(in, out, a.val[0], b.val[0], type);
}
};
GAPI_GPU_KERNEL(GGPUThresholdOT, cv::gapi::core::GThresholdOT)
{
static void run(const cv::UMat& in, const cv::Scalar& b, int type, cv::UMat& out, cv::Scalar& outScalar)
{
outScalar = cv::threshold(in, out, b.val[0], b.val[0], type);
}
};
GAPI_GPU_KERNEL(GGPUInRange, cv::gapi::core::GInRange)
{
static void run(const cv::UMat& in, const cv::Scalar& low, const cv::Scalar& up, cv::UMat& out)
{
cv::inRange(in, low, up, out);
}
};
GAPI_GPU_KERNEL(GGPUSplit3, cv::gapi::core::GSplit3)
{
static void run(const cv::UMat& in, cv::UMat &m1, cv::UMat &m2, cv::UMat &m3)
{
std::vector<cv::UMat> 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_GPU_KERNEL(GGPUSplit4, cv::gapi::core::GSplit4)
{
static void run(const cv::UMat& in, cv::UMat &m1, cv::UMat &m2, cv::UMat &m3, cv::UMat &m4)
{
std::vector<cv::UMat> 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_GPU_KERNEL(GGPUMerge3, cv::gapi::core::GMerge3)
{
static void run(const cv::UMat& in1, const cv::UMat& in2, const cv::UMat& in3, cv::UMat &out)
{
std::vector<cv::UMat> inMats = {in1, in2, in3};
cv::merge(inMats, out);
}
};
GAPI_GPU_KERNEL(GGPUMerge4, cv::gapi::core::GMerge4)
{
static void run(const cv::UMat& in1, const cv::UMat& in2, const cv::UMat& in3, const cv::UMat& in4, cv::UMat &out)
{
std::vector<cv::UMat> inMats = {in1, in2, in3, in4};
cv::merge(inMats, out);
}
};
GAPI_GPU_KERNEL(GGPUResize, cv::gapi::core::GResize)
{
static void run(const cv::UMat& in, cv::Size sz, double fx, double fy, int interp, cv::UMat &out)
{
cv::resize(in, out, sz, fx, fy, interp);
}
};
GAPI_GPU_KERNEL(GGPURemap, cv::gapi::core::GRemap)
{
static void run(const cv::UMat& in, const cv::Mat& x, const cv::Mat& y, int a, int b, cv::Scalar s, cv::UMat& out)
{
cv::remap(in, out, x, y, a, b, s);
}
};
GAPI_GPU_KERNEL(GGPUFlip, cv::gapi::core::GFlip)
{
static void run(const cv::UMat& in, int code, cv::UMat& out)
{
cv::flip(in, out, code);
}
};
GAPI_GPU_KERNEL(GGPUCrop, cv::gapi::core::GCrop)
{
static void run(const cv::UMat& in, cv::Rect rect, cv::UMat& out)
{
cv::UMat(in, rect).copyTo(out);
}
};
GAPI_GPU_KERNEL(GGPUConcatHor, cv::gapi::core::GConcatHor)
{
static void run(const cv::UMat& in1, const cv::UMat& in2, cv::UMat& out)
{
cv::hconcat(in1, in2, out);
}
};
GAPI_GPU_KERNEL(GGPUConcatVert, cv::gapi::core::GConcatVert)
{
static void run(const cv::UMat& in1, const cv::UMat& in2, cv::UMat& out)
{
cv::vconcat(in1, in2, out);
}
};
GAPI_GPU_KERNEL(GGPULUT, cv::gapi::core::GLUT)
{
static void run(const cv::UMat& in, const cv::Mat& lut, cv::UMat& out)
{
cv::LUT(in, lut, out);
}
};
GAPI_GPU_KERNEL(GGPUConvertTo, cv::gapi::core::GConvertTo)
{
static void run(const cv::UMat& in, int rtype, double alpha, double beta, cv::UMat& out)
{
in.convertTo(out, rtype, alpha, beta);
}
};
cv::gapi::GKernelPackage cv::gapi::core::gpu::kernels()
{
static auto pkg = cv::gapi::kernels
< GGPUAdd
, GGPUAddC
, GGPUSub
, GGPUSubC
, GGPUSubRC
, GGPUMul
, GGPUMulC
, GGPUMulCOld
, GGPUDiv
, GGPUDivC
, GGPUDivRC
, GGPUMean
, GGPUMask
, GGPUPolarToCart
, GGPUCartToPolar
, GGPUCmpGT
, GGPUCmpGE
, GGPUCmpLE
, GGPUCmpLT
, GGPUCmpEQ
, GGPUCmpNE
, GGPUCmpGTScalar
, GGPUCmpGEScalar
, GGPUCmpLEScalar
, GGPUCmpLTScalar
, GGPUCmpEQScalar
, GGPUCmpNEScalar
, GGPUAnd
, GGPUAndS
, GGPUOr
, GGPUOrS
, GGPUXor
, GGPUXorS
, GGPUNot
, GGPUSelect
//, GGPUMin
//, GGPUMax
, GGPUAbsDiff
, GGPUAbsDiffC
, GGPUSum
, GGPUAddW
, GGPUNormL1
, GGPUNormL2
, GGPUNormInf
, GGPUIntegral
, GGPUThreshold
, GGPUThresholdOT
, GGPUInRange
, GGPUSplit3
, GGPUSplit4
, GGPUResize
, GGPUMerge3
, GGPUMerge4
, GGPURemap
, GGPUFlip
, GGPUCrop
, GGPUConcatHor
, GGPUConcatVert
, GGPULUT
, GGPUConvertTo
>();
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_GGPUCORE_HPP
#define OPENCV_GAPI_GGPUCORE_HPP
#include <map>
#include <string>
#include "opencv2/gapi/gpu/ggpukernel.hpp"
namespace cv { namespace gimpl {
// NB: This is what a "Kernel Package" from the original Wiki doc should be.
void loadGPUCore(std::map<std::string, cv::GGPUKernel> &kmap);
}
}
#endif // OPENCV_GAPI_GGPUCORE_HPP
@@ -0,0 +1,277 @@
// 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/gpu/imgproc.hpp"
#include "backends/gpu/ggpuimgproc.hpp"
GAPI_GPU_KERNEL(GGPUSepFilter, cv::gapi::imgproc::GSepFilter)
{
static void run(const cv::UMat& 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::UMat &out)
{
if( border == cv::BORDER_CONSTANT )
{
cv::UMat 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_GPU_KERNEL(GGPUBoxFilter, cv::gapi::imgproc::GBoxFilter)
{
static void run(const cv::UMat& in, int ddepth, const cv::Size& ksize, const cv::Point& anchor, bool normalize, int borderType, const cv::Scalar& bordVal, cv::UMat &out)
{
if( borderType == cv::BORDER_CONSTANT )
{
cv::UMat 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_GPU_KERNEL(GGPUBlur, cv::gapi::imgproc::GBlur)
{
static void run(const cv::UMat& in, const cv::Size& ksize, const cv::Point& anchor, int borderType, const cv::Scalar& bordVal, cv::UMat &out)
{
if( borderType == cv::BORDER_CONSTANT )
{
cv::UMat 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_GPU_KERNEL(GGPUFilter2D, cv::gapi::imgproc::GFilter2D)
{
static void run(const cv::UMat& in, int ddepth, const cv::Mat& k, const cv::Point& anchor, const cv::Scalar& delta, int border,
const cv::Scalar& bordVal, cv::UMat &out)
{
if( border == cv::BORDER_CONSTANT )
{
cv::UMat 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_GPU_KERNEL(GGPUGaussBlur, cv::gapi::imgproc::GGaussBlur)
{
static void run(const cv::UMat& in, const cv::Size& ksize, double sigmaX, double sigmaY, int borderType, const cv::Scalar& bordVal, cv::UMat &out)
{
if( borderType == cv::BORDER_CONSTANT )
{
cv::UMat 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_GPU_KERNEL(GGPUMedianBlur, cv::gapi::imgproc::GMedianBlur)
{
static void run(const cv::UMat& in, int ksize, cv::UMat &out)
{
cv::medianBlur(in, out, ksize);
}
};
GAPI_GPU_KERNEL(GGPUErode, cv::gapi::imgproc::GErode)
{
static void run(const cv::UMat& in, const cv::Mat& kernel, const cv::Point& anchor, int iterations, int borderType, const cv::Scalar& borderValue, cv::UMat &out)
{
cv::erode(in, out, kernel, anchor, iterations, borderType, borderValue);
}
};
GAPI_GPU_KERNEL(GGPUDilate, cv::gapi::imgproc::GDilate)
{
static void run(const cv::UMat& in, const cv::Mat& kernel, const cv::Point& anchor, int iterations, int borderType, const cv::Scalar& borderValue, cv::UMat &out)
{
cv::dilate(in, out, kernel, anchor, iterations, borderType, borderValue);
}
};
GAPI_GPU_KERNEL(GGPUSobel, cv::gapi::imgproc::GSobel)
{
static void run(const cv::UMat& in, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType,
const cv::Scalar& bordVal, cv::UMat &out)
{
if( borderType == cv::BORDER_CONSTANT )
{
cv::UMat 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_GPU_KERNEL(GGPUEqualizeHist, cv::gapi::imgproc::GEqHist)
{
static void run(const cv::UMat& in, cv::UMat &out)
{
cv::equalizeHist(in, out);
}
};
GAPI_GPU_KERNEL(GGPUCanny, cv::gapi::imgproc::GCanny)
{
static void run(const cv::UMat& in, double thr1, double thr2, int apSize, bool l2gradient, cv::UMat &out)
{
cv::Canny(in, out, thr1, thr2, apSize, l2gradient);
}
};
GAPI_GPU_KERNEL(GGPURGB2YUV, cv::gapi::imgproc::GRGB2YUV)
{
static void run(const cv::UMat& in, cv::UMat &out)
{
cv::cvtColor(in, out, cv::COLOR_RGB2YUV);
}
};
GAPI_GPU_KERNEL(GGPUYUV2RGB, cv::gapi::imgproc::GYUV2RGB)
{
static void run(const cv::UMat& in, cv::UMat &out)
{
cv::cvtColor(in, out, cv::COLOR_YUV2RGB);
}
};
GAPI_GPU_KERNEL(GGPURGB2Lab, cv::gapi::imgproc::GRGB2Lab)
{
static void run(const cv::UMat& in, cv::UMat &out)
{
cv::cvtColor(in, out, cv::COLOR_RGB2Lab);
}
};
GAPI_GPU_KERNEL(GGPUBGR2LUV, cv::gapi::imgproc::GBGR2LUV)
{
static void run(const cv::UMat& in, cv::UMat &out)
{
cv::cvtColor(in, out, cv::COLOR_BGR2Luv);
}
};
GAPI_GPU_KERNEL(GGPUBGR2YUV, cv::gapi::imgproc::GBGR2YUV)
{
static void run(const cv::UMat& in, cv::UMat &out)
{
cv::cvtColor(in, out, cv::COLOR_BGR2YUV);
}
};
GAPI_GPU_KERNEL(GGPULUV2BGR, cv::gapi::imgproc::GLUV2BGR)
{
static void run(const cv::UMat& in, cv::UMat &out)
{
cv::cvtColor(in, out, cv::COLOR_Luv2BGR);
}
};
GAPI_GPU_KERNEL(GGPUYUV2BGR, cv::gapi::imgproc::GYUV2BGR)
{
static void run(const cv::UMat& in, cv::UMat &out)
{
cv::cvtColor(in, out, cv::COLOR_YUV2BGR);
}
};
GAPI_GPU_KERNEL(GGPURGB2Gray, cv::gapi::imgproc::GRGB2Gray)
{
static void run(const cv::UMat& in, cv::UMat &out)
{
cv::cvtColor(in, out, cv::COLOR_RGB2GRAY);
}
};
GAPI_GPU_KERNEL(GGPUBGR2Gray, cv::gapi::imgproc::GBGR2Gray)
{
static void run(const cv::UMat& in, cv::UMat &out)
{
cv::cvtColor(in, out, cv::COLOR_BGR2GRAY);
}
};
GAPI_GPU_KERNEL(GGPURGB2GrayCustom, cv::gapi::imgproc::GRGB2GrayCustom)
{
//TODO: avoid copy
static void run(const cv::UMat& in, float rY, float bY, float gY, cv::UMat &out)
{
cv::Mat planes[3];
cv::split(in.getMat(cv::ACCESS_READ), planes);
cv::Mat tmp_out = (planes[0]*rY + planes[1]*bY + planes[2]*gY);
tmp_out.copyTo(out);
}
};
cv::gapi::GKernelPackage cv::gapi::imgproc::gpu::kernels()
{
static auto pkg = cv::gapi::kernels
< GGPUFilter2D
, GGPUSepFilter
, GGPUBoxFilter
, GGPUBlur
, GGPUGaussBlur
, GGPUMedianBlur
, GGPUErode
, GGPUDilate
, GGPUSobel
, GGPUCanny
, GGPUEqualizeHist
, GGPURGB2YUV
, GGPUYUV2RGB
, GGPURGB2Lab
, GGPUBGR2LUV
, GGPUBGR2YUV
, GGPUYUV2BGR
, GGPULUV2BGR
, GGPUBGR2Gray
, GGPURGB2Gray
, GGPURGB2GrayCustom
>();
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_GGPUIMGPROC_HPP
#define OPENCV_GAPI_GGPUIMGPROC_HPP
#include <map>
#include <string>
#include "opencv2/gapi/gpu/ggpukernel.hpp"
namespace cv { namespace gimpl {
// NB: This is what a "Kernel Package" from the origianl Wiki doc should be.
void loadGPUImgProc(std::map<std::string, cv::GGPUKernel> &kmap);
}}
#endif // OPENCV_GAPI_GGPUIMGPROC_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/gpu/ggpukernel.hpp"
const cv::UMat& cv::GGPUContext::inMat(int input)
{
return (inArg<cv::UMat>(input));
}
cv::UMat& cv::GGPUContext::outMatR(int output)
{
return (*(util::get<cv::UMat*>(m_results.at(output))));
}
const cv::gapi::own::Scalar& cv::GGPUContext::inVal(int input)
{
return inArg<cv::gapi::own::Scalar>(input);
}
cv::gapi::own::Scalar& cv::GGPUContext::outValR(int output)
{
return *util::get<cv::gapi::own::Scalar*>(m_results.at(output));
}
cv::detail::VectorRef& cv::GGPUContext::outVecRef(int output)
{
return util::get<cv::detail::VectorRef>(m_results.at(output));
}
cv::GGPUKernel::GGPUKernel()
{
}
cv::GGPUKernel::GGPUKernel(const GGPUKernel::F &f)
: m_f(f)
{
}
void cv::GGPUKernel::apply(GGPUContext &ctx)
{
CV_Assert(m_f);
m_f(ctx);
}