// 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 #if !defined(GAPI_STANDALONE) #include #include #include #include #include namespace cv { namespace detail { // FIXME: How to prevent coolhackers from extending it by their own types? // FIXME: ...Should we care? template struct ProtoToParam; template<> struct ProtoToParam { using type = cv::Mat; }; template<> struct ProtoToParam { using type = cv::Scalar; }; template struct ProtoToParam > { using type = std::vector; }; template using ProtoToParamT = typename ProtoToParam::type; template struct ProtoToMeta; template<> struct ProtoToMeta { using type = cv::GMatDesc; }; template<> struct ProtoToMeta { using type = cv::GScalarDesc; }; template struct ProtoToMeta > { using type = cv::GArrayDesc; }; template using ProtoToMetaT = typename ProtoToMeta::type; //workaround for MSVC 19.0 bug template auto make_default()->decltype(T{}) {return {};} }; // detail /** * @brief This class is a typed wrapper over a regular GComputation. * * `std::function<>`-like template parameter specifies the graph * signature so methods so the object's constructor, methods like * `apply()` and the derived `GCompiledT::operator()` also become * typed. * * There is no need to use cv::gin() or cv::gout() modifiers with * objects of this class. Instead, all input arguments are followed * by all output arguments in the order from the template argument * signature. * * Refer to the following example. Regular (untyped) code is written this way: * * @snippet modules/gapi/samples/api_ref_snippets.cpp Untyped_Example * * Here: * * - cv::GComputation object is created with a lambda constructor * where it is defined as a two-input, one-output graph. * * - Its method `apply()` in fact takes arbitrary number of arguments * (as vectors) so user can pass wrong number of inputs/outputs * here. C++ compiler wouldn't notice that since the cv::GComputation * API is polymorphic, and only a run-time error will be generated. * * Now the same code written with typed API: * * @snippet modules/gapi/samples/api_ref_snippets.cpp Typed_Example * * The key difference is: * * - Now the constructor lambda *must take* parameters and *must * return* values as defined in the `GComputationT<>` signature. * - Its method `apply()` does not require any extra specifiers to * separate input arguments from the output ones * - A `GCompiledT` (compilation product) takes input/output * arguments with no extra specifiers as well. */ template class GComputationT; // Single return value implementation template class GComputationT { public: typedef std::function Gen; class GCompiledT { private: friend class GComputationT; cv::GCompiled m_comp; explicit GCompiledT(const cv::GCompiled &comp) : m_comp(comp) {} public: GCompiledT() {} void operator()(detail::ProtoToParamT... inArgs, detail::ProtoToParamT &outArg) { m_comp(cv::gin(inArgs...), cv::gout(outArg)); } explicit operator bool() const { return static_cast(m_comp); } }; private: typedef std::pair 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()...)) , m_comp(cv::GProtoInputArgs(std::move(m_capture.second)), cv::GOut(m_capture.first)) { } void apply(detail::ProtoToParamT... inArgs, detail::ProtoToParamT &outArg) { m_comp.apply(cv::gin(inArgs...), cv::gout(outArg)); } GCompiledT compile(detail::ProtoToMetaT... inDescs) { GMetaArgs inMetas = { GMetaArg(inDescs)... }; return GCompiledT(m_comp.compile(std::move(inMetas), GCompileArgs())); } GCompiledT compile(detail::ProtoToMetaT... 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 class GComputationT(Args...)> { public: typedef std::function(Args...)> Gen; class GCompiledT { private: friend class GComputationT(Args...)>; cv::GCompiled m_comp; explicit GCompiledT(const cv::GCompiled &comp) : m_comp(comp) {} public: GCompiledT() {} void operator()(detail::ProtoToParamT... inArgs, detail::ProtoToParamT&... outArgs) { m_comp(cv::gin(inArgs...), cv::gout(outArgs...)); } explicit operator bool() const { return static_cast(m_comp); } }; private: typedef std::pair Captured; template Captured capture(GProtoArgs &&args, const std::tuple &rr, detail::Seq) { return Captured(cv::GOut(std::get(rr)...).m_args, args); } Captured capture(const Gen& g, Args... args) { return capture(cv::GIn(args...).m_args, g(args...), typename detail::MkSeq::type()); } Captured m_capture; cv::GComputation m_comp; public: GComputationT(const Gen &generator) : m_capture(capture(generator, detail::make_default()...)) , m_comp(cv::GProtoInputArgs(std::move(m_capture.second)), cv::GProtoOutputArgs(std::move(m_capture.first))) { } void apply(detail::ProtoToParamT... inArgs, detail::ProtoToParamT&... outArgs) { m_comp.apply(cv::gin(inArgs...), cv::gout(outArgs...)); } GCompiledT compile(detail::ProtoToMetaT... inDescs) { GMetaArgs inMetas = { GMetaArg(inDescs)... }; return GCompiledT(m_comp.compile(std::move(inMetas), GCompileArgs())); } GCompiledT compile(detail::ProtoToMetaT... inDescs, GCompileArgs &&args) { GMetaArgs inMetas = { GMetaArg(inDescs)... }; return GCompiledT(m_comp.compile(std::move(inMetas), std::move(args))); } }; } // namespace cv #endif // !defined(GAPI_STANDALONE) #endif // OPENCV_GAPI_GTYPED_HPP