diff --git a/modules/gapi/include/opencv2/gapi/fluid/gfluidkernel.hpp b/modules/gapi/include/opencv2/gapi/fluid/gfluidkernel.hpp index 3235de791e..a0e6894e7b 100644 --- a/modules/gapi/include/opencv2/gapi/fluid/gfluidkernel.hpp +++ b/modules/gapi/include/opencv2/gapi/fluid/gfluidkernel.hpp @@ -68,19 +68,21 @@ public: // This function is a generic "getBorder" callback (extracts border-related data from kernel's input parameters) using B = std::function; + // This function is a generic "getWindow" callback (extracts window-related data from kernel's input parameters) + using GW = std::function; + // 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) + GFluidKernel(Kind k, int l, bool scratch, const F& f, const IS &is, const RS &rs, const B& b, const GW& win) + : m_kind(k) , m_lpi(l) , m_scratch(scratch) , m_f(f) , m_is(is) , m_rs(rs) - , m_b(b) {} + , m_b(b) + , m_gw(win) {} - int m_window = -1; Kind m_kind; const int m_lpi = -1; const bool m_scratch = false; @@ -89,6 +91,7 @@ public: const IS m_is; const RS m_rs; const B m_b; + const GW m_gw; }; // FIXME!!! @@ -255,6 +258,67 @@ struct get_border_helper } }; +template +struct get_window_helper; + +template +struct get_window_helper +{ + template + static int get_window_impl(const GMetaArgs &metas, + const cv::GArgs &in_args, + cv::detail::Seq) + { + return Impl::getWindow(cv::detail::get_in_meta(metas, in_args, IIs)...); + } + + static int help(const GMetaArgs &metas, const cv::GArgs &in_args) + { + return get_window_impl(metas, in_args, typename detail::MkSeq::type()); + } +}; + +template +struct get_window_helper +{ + static int help(const cv::GMetaArgs &, + const cv::GArgs &) + { + return Impl::Window; + } +}; + +template +struct has_Window +{ +private: + template + static constexpr auto Check(U*) -> typename std::is_same::type; + + template + static constexpr std::false_type Check(...); + + typedef decltype(Check(0)) Result; + +public: + static constexpr bool value = Result::value; +}; + +template +struct callCustomGetBorder; + +template +struct callCustomGetBorder +{ + static constexpr bool value = (Impl::Window != 1); +}; + +template +struct callCustomGetBorder +{ + static constexpr bool value = true; +}; + template struct FluidCallHelper; @@ -299,10 +363,17 @@ struct FluidCallHelper, std::tuple, UseScratch static gapi::fluid::BorderOpt getBorder(const GMetaArgs &metas, const cv::GArgs &in_args) { + constexpr bool hasWindow = has_Window::value; + // 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::help(metas, in_args); + return get_border_helper::value, Impl, Ins...>::help(metas, in_args); + } + + static int getWindow(const GMetaArgs &metas, const cv::GArgs &in_args) + { + constexpr bool callCustomGetWindow = !(has_Window::value); + return get_window_helper::help(metas, in_args); } }; } // namespace detail @@ -322,9 +393,9 @@ public: { // 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, + return GFluidKernel(Impl::Kind, Impl::LPI, UseScratch, - &P::call, &P::init_scratch, &P::reset_scratch, &P::getBorder); + &P::call, &P::init_scratch, &P::reset_scratch, &P::getBorder, &P::getWindow); } static cv::gapi::GBackend backend() { return cv::gapi::fluid::backend(); } diff --git a/modules/gapi/src/backends/fluid/gfluidbackend.cpp b/modules/gapi/src/backends/fluid/gfluidbackend.cpp index 1a8a3c8178..6f45b3dd00 100644 --- a/modules/gapi/src/backends/fluid/gfluidbackend.cpp +++ b/modules/gapi/src/backends/fluid/gfluidbackend.cpp @@ -69,7 +69,7 @@ namespace { GFluidModel fm(graph); auto fluid_impl = cv::util::any_cast(impl.opaque); - fm.metadata(op_node).set(cv::gimpl::FluidUnit{fluid_impl, {}, 0, {}, 0.0}); + fm.metadata(op_node).set(cv::gimpl::FluidUnit{fluid_impl, {}, 0, -1, {}, 0.0}); } virtual EPtr compile(const ade::Graph &graph, @@ -178,6 +178,12 @@ private: virtual void setRatio(double) override { /* nothing */ } public: using FluidAgent::FluidAgent; + int m_window; + + FluidFilterAgent(const ade::Graph &g, ade::NodeHandle nh) + : FluidAgent(g, nh) + , m_window(GConstFluidModel(g).metadata(nh).get().window) + {} }; struct FluidResizeAgent : public FluidAgent @@ -287,11 +293,11 @@ static int calcResizeWindow(int inH, int outH) } } -static int maxLineConsumption(const cv::GFluidKernel& k, int inH, int outH, int lpi, std::size_t inPort) +static int maxLineConsumption(const cv::GFluidKernel::Kind kind, int window, int inH, int outH, int lpi, std::size_t inPort) { - switch (k.m_kind) + switch (kind) { - case cv::GFluidKernel::Kind::Filter: return k.m_window + lpi - 1; break; + case cv::GFluidKernel::Kind::Filter: return window + lpi - 1; break; case cv::GFluidKernel::Kind::Resize: { if (inH >= outH) @@ -312,11 +318,11 @@ static int maxLineConsumption(const cv::GFluidKernel& k, int inH, int outH, int } } -static int borderSize(const cv::GFluidKernel& k) +static int borderSize(const cv::GFluidKernel::Kind kind, int window) { - switch (k.m_kind) + switch (kind) { - case cv::GFluidKernel::Kind::Filter: return (k.m_window - 1) / 2; break; + case cv::GFluidKernel::Kind::Filter: return (window - 1) / 2; break; // Resize never reads from border pixels case cv::GFluidKernel::Kind::Resize: return 0; break; case cv::GFluidKernel::Kind::NV12toRGB: return 0; break; @@ -406,13 +412,13 @@ std::pair cv::gimpl::FluidUpscaleMapper::linesReadAndNextWindow(int out int cv::gimpl::FluidFilterAgent::firstWindow(std::size_t) const { int lpi = std::min(k.m_lpi, m_outputLines - m_producedLines); - return k.m_window + lpi - 1; + return m_window + lpi - 1; } std::pair cv::gimpl::FluidFilterAgent::linesReadAndnextWindow(std::size_t) const { int lpi = std::min(k.m_lpi, m_outputLines - m_producedLines - k.m_lpi); - return std::make_pair(k.m_lpi, k.m_window - 1 + lpi); + return std::make_pair(k.m_lpi, m_window - 1 + lpi); } int cv::gimpl::FluidResizeAgent::firstWindow(std::size_t) const @@ -1016,14 +1022,14 @@ namespace if (d.shape == cv::GShape::GMAT) { auto port = g.metadata(in_edge).get().port; - fu.line_consumption[port] = maxLineConsumption(fu.k, in_h, out_h, fu.k.m_lpi, port); + fu.line_consumption[port] = maxLineConsumption(fu.k.m_kind, fu.window, in_h, out_h, fu.k.m_lpi, port); GModel::log(g, node, "Line consumption (port " + std::to_string(port) + "): " + std::to_string(fu.line_consumption[port])); } } - fu.border_size = borderSize(fu.k); + fu.border_size = borderSize(fu.k.m_kind, fu.window); GModel::log(g, node, "Border size: " + std::to_string(fu.border_size)); } } @@ -1489,7 +1495,7 @@ void GFluidBackendImpl::addBackendPasses(ade::ExecutionEngineSetupContext &ectx) // FIXME: // move to unpackKernel method // when https://gitlab-icv.inn.intel.com/G-API/g-api/merge_requests/66 is merged - ectx.addPass("exec", "init_fluid_unit_borders", [](ade::passes::PassContext &ctx) + ectx.addPass("exec", "init_fluid_unit_windows_and_borders", [](ade::passes::PassContext &ctx) { GModel::Graph g(ctx.graph); if (!GModel::isActive(g, cv::gapi::fluid::backend())) // FIXME: Rearchitect this! @@ -1505,9 +1511,13 @@ void GFluidBackendImpl::addBackendPasses(ade::ExecutionEngineSetupContext &ectx) // FIXME: check that op has only one data node on input auto &fu = fg.metadata(node).get(); const auto &op = g.metadata(node).get(); + auto inputMeta = GModel::collectInputMeta(fg, node); + + // Trigger user-defined "getWindow" callback + fu.window = fu.k.m_gw(inputMeta, op.args); // Trigger user-defined "getBorder" callback - fu.border = fu.k.m_b(GModel::collectInputMeta(fg, node), op.args); + fu.border = fu.k.m_b(inputMeta, op.args); } } }); diff --git a/modules/gapi/src/backends/fluid/gfluidbackend.hpp b/modules/gapi/src/backends/fluid/gfluidbackend.hpp index a2c853a961..c8598d7da8 100644 --- a/modules/gapi/src/backends/fluid/gfluidbackend.hpp +++ b/modules/gapi/src/backends/fluid/gfluidbackend.hpp @@ -27,6 +27,7 @@ struct FluidUnit GFluidKernel k; gapi::fluid::BorderOpt border; int border_size; + int window; std::vector line_consumption; double ratio; }; diff --git a/modules/gapi/src/backends/fluid/gfluidimgproc.cpp b/modules/gapi/src/backends/fluid/gfluidimgproc.cpp index dfbce1e9fc..1db0ba5b49 100644 --- a/modules/gapi/src/backends/fluid/gfluidimgproc.cpp +++ b/modules/gapi/src/backends/fluid/gfluidimgproc.cpp @@ -778,7 +778,6 @@ GAPI_FLUID_KERNEL(GFluidSepFilter, cv::gapi::imgproc::GSepFilter, true) GAPI_FLUID_KERNEL(GFluidGaussBlur, cv::gapi::imgproc::GGaussBlur, true) { // TODO: support kernel height 3, 5, 7, 9, ... - static const int Window = 3; static void run(const View & src, const cv::Size & ksize, @@ -828,6 +827,7 @@ GAPI_FLUID_KERNEL(GFluidGaussBlur, cv::gapi::imgproc::GGaussBlur, true) const cv::Scalar & /* borderValue */, Buffer & scratch) { + GAPI_Assert(ksize.height == ksize.width); int kxsize = ksize.width; int kysize = ksize.height; @@ -835,7 +835,7 @@ GAPI_FLUID_KERNEL(GFluidGaussBlur, cv::gapi::imgproc::GGaussBlur, true) int chan = in.chan; int buflen = kxsize + kysize + // x, y kernels - width * chan * Window; // work buffers + width * chan * ksize.height; // work buffers cv::gapi::own::Size bufsize(buflen, 1); GMatDesc bufdesc = {CV_32F, 1, bufsize}; @@ -876,6 +876,17 @@ GAPI_FLUID_KERNEL(GFluidGaussBlur, cv::gapi::imgproc::GGaussBlur, true) { return { borderType, borderValue}; } + + static int getWindow(const cv::GMatDesc& /* src */, + const cv::Size& ksize, + double /* sigmaX */, + double /* sigmaY */, + int /* borderType */, + const cv::Scalar& /* borderValue */) + { + GAPI_Assert(ksize.height == ksize.width); + return ksize.height; + } }; //--------------------- @@ -1688,8 +1699,8 @@ GAPI_FLUID_KERNEL(GFluidRGB2YUV422, cv::gapi::imgproc::GRGB2YUV422, false) static const int Window = 1; static const auto Kind = cv::GFluidKernel::Kind::Filter; - static void run(const cv::gapi::fluid::View& in, - cv::gapi::fluid::Buffer& out) + static void run(const cv::gapi::fluid::View& in, + cv::gapi::fluid::Buffer& out) { const auto *src = in.InLine(0); auto *dst = out.OutLine();