mirror of https://github.com/opencv/opencv.git
Merge pull request #15699 from TolyaTalamanov:at/graph-ocv-render-backend-skeleton
G-API: Implement OpenCV render backend * Implement render opencv backend * Fix comment to review * Add comment * Add wrappers for kernels * Fix comments to review * Fix comment to reviewpull/15735/head
parent
cc9b199ecb
commit
2ff12c4981
16 changed files with 483 additions and 126 deletions
@ -0,0 +1,81 @@ |
||||
#include <opencv2/imgproc.hpp> |
||||
|
||||
#include "api/render_ocv.hpp" |
||||
#include "backends/render/grenderocv.hpp" |
||||
|
||||
#include <opencv2/gapi/cpu/gcpukernel.hpp> |
||||
|
||||
GAPI_RENDER_OCV_KERNEL(RenderBGRImpl, cv::gapi::wip::draw::GRenderBGR) |
||||
{ |
||||
static void run(const cv::Mat& in, const cv::gapi::wip::draw::Prims& prims, cv::Mat& out) |
||||
{ |
||||
// NB: If in and out cv::Mats are the same object
|
||||
// we can avoid copy and render on out cv::Mat
|
||||
// It's work if this kernel is last operation in the graph
|
||||
if (in.data != out.data) { |
||||
in.copyTo(out); |
||||
} |
||||
|
||||
cv::gapi::wip::draw::drawPrimitivesOCVBGR(out, prims); |
||||
} |
||||
}; |
||||
|
||||
GAPI_RENDER_OCV_KERNEL(RenderNV12Impl, cv::gapi::wip::draw::GRenderNV12) |
||||
{ |
||||
static void run(const cv::Mat& in_y, |
||||
const cv::Mat& in_uv, |
||||
const cv::gapi::wip::draw::Prims& prims, |
||||
cv::Mat& out_y, |
||||
cv::Mat& out_uv) |
||||
{ |
||||
// NB: If in and out cv::Mats are the same object
|
||||
// we can avoid copy and render on out cv::Mat
|
||||
// It's work if this kernel is last operation in the graph
|
||||
if (in_y.data != out_y.data) { |
||||
in_y.copyTo(out_y); |
||||
} |
||||
|
||||
if (in_uv.data != out_uv.data) { |
||||
in_uv.copyTo(out_uv); |
||||
} |
||||
|
||||
/* FIXME How to render correctly on NV12 format ?
|
||||
* |
||||
* Rendering on NV12 via OpenCV looks like this: |
||||
* |
||||
* y --------> 1)(NV12 -> YUV) -> yuv -> 2)draw -> yuv -> 3)split -------> out_y |
||||
* ^ | |
||||
* | | |
||||
* uv -------------- `----------> out_uv |
||||
* |
||||
* |
||||
* 1) Collect yuv mat from two planes, uv plain in two times less than y plane |
||||
* so, upsample uv in tow times, with bilinear interpolation |
||||
* |
||||
* 2) Render primitives on YUV |
||||
* |
||||
* 3) Convert yuv to NV12 (using bilinear interpolation) |
||||
* |
||||
*/ |
||||
|
||||
// NV12 -> YUV
|
||||
cv::Mat upsample_uv, yuv; |
||||
cv::resize(in_uv, upsample_uv, in_uv.size() * 2, cv::INTER_LINEAR); |
||||
cv::merge(std::vector<cv::Mat>{in_y, upsample_uv}, yuv); |
||||
|
||||
cv::gapi::wip::draw::drawPrimitivesOCVYUV(yuv, prims); |
||||
|
||||
// YUV -> NV12
|
||||
cv::Mat out_u, out_v, uv_plane; |
||||
std::vector<cv::Mat> chs = {out_y, out_u, out_v}; |
||||
cv::split(yuv, chs); |
||||
cv::merge(std::vector<cv::Mat>{chs[1], chs[2]}, uv_plane); |
||||
cv::resize(uv_plane, out_uv, uv_plane.size() / 2, cv::INTER_LINEAR); |
||||
} |
||||
}; |
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::render::ocv::kernels() |
||||
{ |
||||
const static auto pkg = cv::gapi::kernels<RenderBGRImpl, RenderNV12Impl>(); |
||||
return pkg; |
||||
} |
@ -0,0 +1,55 @@ |
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2019 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_GRENDEROCV_HPP |
||||
#define OPENCV_GAPI_GRENDEROCV_HPP |
||||
|
||||
#include <opencv2/gapi/cpu/gcpukernel.hpp> |
||||
|
||||
namespace cv |
||||
{ |
||||
namespace gapi |
||||
{ |
||||
namespace render |
||||
{ |
||||
namespace ocv |
||||
{ |
||||
|
||||
GAPI_EXPORTS cv::gapi::GBackend backend(); |
||||
|
||||
template<typename, typename> |
||||
struct add_type_to_tuple; |
||||
|
||||
template<typename P, typename ...Ts> |
||||
struct add_type_to_tuple<P, std::tuple<Ts...>> |
||||
{ |
||||
using type = std::tuple<Ts..., P>; |
||||
}; |
||||
|
||||
template<class Impl, class K> |
||||
class GRenderKernelImpl: public cv::detail::OCVCallHelper<Impl, typename K::InArgs, typename K::OutArgs>, |
||||
public cv::detail::KernelTag |
||||
{ |
||||
// TODO Use this mechanism for adding new parameter to run method
|
||||
// using InArgs = typename add_type_to_tuple<IBitMaskCreator, typename K::InArgs>::type;
|
||||
using InArgs = typename K::InArgs; |
||||
using P = detail::OCVCallHelper<Impl, InArgs, typename K::OutArgs>; |
||||
|
||||
public: |
||||
using API = K; |
||||
|
||||
static cv::gapi::GBackend backend() { return cv::gapi::render::ocv::backend(); } |
||||
static cv::GCPUKernel kernel() { return GCPUKernel(&P::call); } |
||||
}; |
||||
|
||||
#define GAPI_RENDER_OCV_KERNEL(Name, API) struct Name: public cv::gapi::render::ocv::GRenderKernelImpl<Name, API> |
||||
|
||||
} // namespace ocv
|
||||
} // namespace render
|
||||
} // namespace gapi
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_GRENDEROCV_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 "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/garray.hpp> |
||||
#include <opencv2/gapi/util/any.hpp> |
||||
#include <opencv2/gapi/gtype_traits.hpp> |
||||
|
||||
#include "compiler/gobjref.hpp" |
||||
#include "compiler/gmodel.hpp" |
||||
|
||||
#include "api/gbackend_priv.hpp" // FIXME: Make it part of Backend SDK! |
||||
#include "api/render_ocv.hpp" |
||||
|
||||
#include "backends/render/grenderocvbackend.hpp" |
||||
|
||||
|
||||
using GRenderModel = ade::TypedGraph |
||||
< cv::gimpl::render::ocv::RenderUnit |
||||
>; |
||||
|
||||
// FIXME: Same issue with Typed and ConstTyped
|
||||
using GConstRenderModel = ade::ConstTypedGraph |
||||
< cv::gimpl::render::ocv::RenderUnit |
||||
>; |
||||
|
||||
cv::gimpl::render::ocv::GRenderExecutable::GRenderExecutable(const ade::Graph &g, |
||||
const std::vector<ade::NodeHandle> &nodes) |
||||
: m_g(g), m_gm(m_g) { |
||||
GConstRenderModel gcm(m_g); |
||||
|
||||
auto is_op = [&](ade::NodeHandle nh) { |
||||
return m_gm.metadata(nh).get<NodeType>().t == NodeType::OP; |
||||
}; |
||||
|
||||
auto it = ade::util::find_if(nodes, is_op); |
||||
|
||||
GAPI_Assert(it != nodes.end()); |
||||
this_nh = *it; |
||||
|
||||
if (!std::none_of(std::next(it), nodes.end(), is_op)) { |
||||
util::throw_error(std::logic_error("Multi-node rendering is not supported!")); |
||||
} |
||||
} |
||||
|
||||
void cv::gimpl::render::ocv::GRenderExecutable::run(std::vector<InObj> &&input_objs, |
||||
std::vector<OutObj> &&output_objs) { |
||||
GConstRenderModel gcm(m_g); |
||||
|
||||
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); |
||||
|
||||
const auto &op = m_gm.metadata(this_nh).get<Op>(); |
||||
|
||||
// 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(&GRenderExecutable::packArg, this, _1)); |
||||
|
||||
// - Output parameters.
|
||||
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); |
||||
} |
||||
|
||||
auto k = gcm.metadata(this_nh).get<RenderUnit>().k; |
||||
|
||||
k.apply(context); |
||||
|
||||
for (auto &it : output_objs) magazine::writeBack(m_res, it.first, it.second); |
||||
} |
||||
|
||||
cv::GArg cv::gimpl::render::ocv::GRenderExecutable::packArg(const cv::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) { |
||||
util::throw_error(std::logic_error("Render supports G-types ONLY!")); |
||||
} |
||||
GAPI_Assert(arg.kind == cv::detail::ArgKind::GOBJREF); |
||||
|
||||
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::GARRAY: return GArg(m_res.slot<cv::detail::VectorRef>().at(ref.id)); |
||||
default: |
||||
util::throw_error(std::logic_error("Unsupported GShape type")); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
namespace { |
||||
class GRenderBackendImpl final: public cv::gapi::GBackend::Priv { |
||||
virtual void unpackKernel(ade::Graph &gr, |
||||
const ade::NodeHandle &op_node, |
||||
const cv::GKernelImpl &impl) override { |
||||
GRenderModel rm(gr); |
||||
//auto render_impl = cv::util::any_cast<cv::gapi::render::ocv::KImpl>(impl.opaque);
|
||||
auto render_impl = cv::util::any_cast<cv::GCPUKernel>(impl.opaque); |
||||
rm.metadata(op_node).set(cv::gimpl::render::ocv::RenderUnit{render_impl}); |
||||
} |
||||
|
||||
virtual EPtr compile(const ade::Graph &graph, |
||||
const cv::GCompileArgs&, |
||||
const std::vector<ade::NodeHandle> &nodes) const override { |
||||
|
||||
return EPtr{new cv::gimpl::render::ocv::GRenderExecutable(graph, nodes)}; |
||||
} |
||||
|
||||
}; |
||||
} |
||||
|
||||
cv::gapi::GBackend cv::gapi::render::ocv::backend() { |
||||
static cv::gapi::GBackend this_backend(std::make_shared<GRenderBackendImpl>()); |
||||
return this_backend; |
||||
} |
@ -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) 2019 Intel Corporation
|
||||
|
||||
#ifndef OPENCV_GAPI_GRENDEROCVBACKEND_HPP |
||||
#define OPENCV_GAPI_GRENDEROCVBACKEND_HPP |
||||
|
||||
#include <opencv2/gapi/garg.hpp> |
||||
#include <opencv2/gapi/gproto.hpp> |
||||
#include <opencv2/gapi/render/render.hpp> |
||||
|
||||
#include "api/gorigin.hpp" |
||||
#include "backends/common/gbackend.hpp" |
||||
#include "compiler/gislandmodel.hpp" |
||||
|
||||
#include "backends/render/grenderocv.hpp" |
||||
|
||||
#include <opencv2/gapi/cpu/gcpukernel.hpp> |
||||
|
||||
namespace cv |
||||
{ |
||||
namespace gimpl |
||||
{ |
||||
namespace render |
||||
{ |
||||
namespace ocv |
||||
{ |
||||
|
||||
struct RenderUnit |
||||
{ |
||||
static const char *name() { return "RenderUnit"; } |
||||
GCPUKernel k; |
||||
}; |
||||
|
||||
class GRenderExecutable final: public GIslandExecutable |
||||
{ |
||||
const ade::Graph &m_g; |
||||
GModel::ConstGraph m_gm; |
||||
|
||||
// The only executable stuff in this graph
|
||||
// (assuming it is always single-op)
|
||||
ade::NodeHandle this_nh; |
||||
|
||||
//// Actual data of all resources in graph (both internal and external)
|
||||
Mag m_res; |
||||
|
||||
//// Execution helpers
|
||||
GArg packArg(const GArg &arg); |
||||
|
||||
public: |
||||
GRenderExecutable(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 { |
||||
GAPI_Assert(false); // Not implemented yet
|
||||
} |
||||
|
||||
virtual void run(std::vector<InObj> &&input_objs, |
||||
std::vector<OutObj> &&output_objs) override; |
||||
}; |
||||
|
||||
} // namespace ocv
|
||||
} // namespace render
|
||||
} // namespace gimpl
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_GRENDEROCVBACKEND_HPP
|
Loading…
Reference in new issue