Merge pull request #19112 from rgarnov:rg/generic_copy_kernel

Generic copy kernel

* Moved RMat wrapping of cv::Mats to StreamingInput

* Generalized GCopy kernel

* Generic GCopy kernel: applied review comments
This commit is contained in:
Ruslan Garnov 2020-12-16 14:18:08 +03:00 committed by GitHub
parent 50baf76cc2
commit f7cab121fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 161 additions and 180 deletions

View File

@ -451,12 +451,6 @@ namespace core {
}
};
G_TYPED_KERNEL(GCopy, <GMat(GMat)>, "org.opencv.core.transform.copy") {
static GMatDesc outMeta(GMatDesc in) {
return in;
}
};
G_TYPED_KERNEL(GConcatHor, <GMat(GMat, GMat)>, "org.opencv.imgproc.transform.concatHor") {
static GMatDesc outMeta(GMatDesc l, GMatDesc r) {
return l.withSizeDelta(+r.size.width, 0);
@ -1667,19 +1661,6 @@ Output matrix must be of the same depth as input one, size is specified by given
*/
GAPI_EXPORTS GMat crop(const GMat& src, const Rect& rect);
/** @brief Copies a matrix.
Copies an input array. Works as a regular Mat::clone but happens in-graph.
Mainly is used to workaround some existing limitations (e.g. to forward an input frame to outputs
in the streaming mode). Will be deprecated and removed in the future.
@note Function textual ID is "org.opencv.core.transform.copy"
@param src input matrix.
@sa crop
*/
GAPI_EXPORTS GMat copy(const GMat& src);
/** @brief Applies horizontal concatenation to given matrices.
The function horizontally concatenates two GMat matrices (with the same number of rows).

View File

@ -15,26 +15,11 @@ namespace streaming {
GAPI_EXPORTS cv::gapi::GKernelPackage kernels();
// FIXME: Make a generic kernel
G_API_OP(GCopy, <GFrame(GFrame)>, "org.opencv.streaming.copy")
{
static GFrameDesc outMeta(const GFrameDesc& in) { return in; }
};
G_API_OP(GBGR, <GMat(GFrame)>, "org.opencv.streaming.BGR")
{
static GMatDesc outMeta(const GFrameDesc& in) { return GMatDesc{CV_8U, 3, in.size}; }
};
/** @brief Gets copy from the input frame
@note Function textual ID is "org.opencv.streaming.copy"
@param in Input frame
@return Copy of the input frame
*/
GAPI_EXPORTS cv::GFrame copy(const cv::GFrame& in);
/** @brief Gets bgr plane from input frame
@note Function textual ID is "org.opencv.streaming.BGR"
@ -42,9 +27,32 @@ GAPI_EXPORTS cv::GFrame copy(const cv::GFrame& in);
@param in Input frame
@return Image in BGR format
*/
GAPI_EXPORTS cv::GMat BGR (const cv::GFrame& in);
GAPI_EXPORTS cv::GMat BGR(const cv::GFrame& in);
} // namespace streaming
/** @brief Makes a copy of the input image. Note that this copy may be not real
(no actual data copied). Use this function to maintain graph contracts,
e.g when graph's input needs to be passed directly to output, like in Streaming mode.
@note Function textual ID is "org.opencv.streaming.copy"
@param in Input image
@return Copy of the input
*/
GAPI_EXPORTS cv::GMat copy(const cv::GMat& in);
/** @brief Makes a copy of the input frame. Note that this copy may be not real
(no actual data copied). Use this function to maintain graph contracts,
e.g when graph's input needs to be passed directly to output, like in Streaming mode.
@note Function textual ID is "org.opencv.streaming.copy"
@param in Input frame
@return Copy of the input
*/
GAPI_EXPORTS cv::GFrame copy(const cv::GFrame& in);
} // namespace gapi
} // namespace cv

View File

@ -233,11 +233,6 @@ INSTANTIATE_TEST_CASE_P(Split3PerfTestFluid, Split3PerfTest,
// Values(cv::Rect(10, 8, 20, 35), cv::Rect(4, 10, 37, 50)),
// Values(cv::compile_args(CORE_FLUID))));
// INSTANTIATE_TEST_CASE_P(CopyPerfTestFluid, CopyPerfTest,
// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
// Values(cv::compile_args(CORE_FLUID))));
// INSTANTIATE_TEST_CASE_P(ConcatHorPerfTestFluid, ConcatHorPerfTest,
// Combine(Values(szSmall128, szVGA, sz720p, sz1080p),
// Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),

View File

@ -232,11 +232,6 @@ INSTANTIATE_TEST_CASE_P(CropPerfTestGPU, CropPerfTest,
Values(cv::Rect(10, 8, 20, 35), cv::Rect(4, 10, 37, 50)),
Values(cv::compile_args(CORE_GPU))));
INSTANTIATE_TEST_CASE_P(CopyPerfTestGPU, CopyPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::compile_args(CORE_GPU))));
INSTANTIATE_TEST_CASE_P(ConcatHorPerfTestGPU, ConcatHorPerfTest,
Combine(Values( szSmall128, szVGA, sz720p, sz1080p ),
Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),

View File

@ -328,11 +328,6 @@ GMat crop(const GMat& src, const Rect& rect)
return core::GCrop::on(src, rect);
}
GMat copy(const GMat& src)
{
return core::GCopy::on(src);
}
GMat concatHor(const GMat& src1, const GMat& src2)
{
return core::GConcatHor::on(src1, src2);

View File

@ -75,10 +75,6 @@ cv::GMat cv::gapi::streaming::desync(const cv::GMat &g) {
// object will feed both branches of the streaming executable.
}
cv::GFrame cv::gapi::streaming::copy(const cv::GFrame& in) {
return cv::gapi::streaming::GCopy::on(in);
}
cv::GMat cv::gapi::streaming::BGR(const cv::GFrame& in) {
return cv::gapi::streaming::GBGR::on(in);
}

View File

@ -510,14 +510,6 @@ GAPI_OCV_KERNEL(GCPUCrop, cv::gapi::core::GCrop)
}
};
GAPI_OCV_KERNEL(GCPUCopy, cv::gapi::core::GCopy)
{
static void run(const cv::Mat& in, cv::Mat& out)
{
in.copyTo(out);
}
};
GAPI_OCV_KERNEL(GCPUConcatHor, cv::gapi::core::GConcatHor)
{
static void run(const cv::Mat& in1, const cv::Mat& in2, cv::Mat& out)
@ -762,7 +754,6 @@ cv::gapi::GKernelPackage cv::gapi::core::cpu::kernels()
, GCPURemap
, GCPUFlip
, GCPUCrop
, GCPUCopy
, GCPUConcatHor
, GCPUConcatVert
, GCPULUT

View File

@ -2675,40 +2675,6 @@ GAPI_FLUID_KERNEL(GFluidSqrt, cv::gapi::core::GSqrt, false)
}
};
GAPI_FLUID_KERNEL(GFluidCopy, cv::gapi::core::GCopy, false)
{
static const int Window = 1;
static void run(const View &src, Buffer &dst)
{
const auto *in = src.InLine<uchar>(0);
auto *out = dst.OutLine<uchar>();
GAPI_DbgAssert(dst.length() == src.length());
GAPI_DbgAssert(dst.meta().chan == src.meta().chan);
GAPI_DbgAssert(dst.meta().depth == src.meta().depth);
int width = src.length();
int elem_size = CV_ELEM_SIZE(CV_MAKETYPE(src.meta().depth, src.meta().chan));
int w = 0; // cycle counter
#if CV_SIMD128
for (; w <= width*elem_size-16; w+=16)
{
v_uint8x16 a;
a = v_load(&in[w]);
v_store(&out[w], a);
}
#endif
for (; w < width*elem_size; w++)
{
out[w] = in[w];
}
}
};
} // namespace fliud
} // namespace gapi
} // namespace cv
@ -2768,7 +2734,6 @@ cv::gapi::GKernelPackage cv::gapi::core::fluid::kernels()
,GFluidInRange
,GFluidResize
,GFluidSqrt
,GFluidCopy
#if 0
,GFluidMean -- not fluid
,GFluidSum -- not fluid

View File

@ -490,14 +490,6 @@ GAPI_OCL_KERNEL(GOCLCrop, cv::gapi::core::GCrop)
}
};
GAPI_OCL_KERNEL(GOCLCopy, cv::gapi::core::GCopy)
{
static void run(const cv::UMat& in, cv::UMat& out)
{
in.copyTo(out);
}
};
GAPI_OCL_KERNEL(GOCLConcatHor, cv::gapi::core::GConcatHor)
{
static void run(const cv::UMat& in1, const cv::UMat& in2, cv::UMat& out)
@ -590,7 +582,6 @@ cv::gapi::GKernelPackage cv::gapi::core::ocl::kernels()
, GOCLRemap
, GOCLFlip
, GOCLCrop
, GOCLCopy
, GOCLConcatHor
, GOCLConcatVert
, GOCLLUT

View File

@ -137,7 +137,12 @@ cv::gapi::GBackend cv::gapi::streaming::backend()
cv::gapi::GKernelPackage cv::gapi::streaming::kernels()
{
return cv::gapi::kernels<cv::gimpl::Copy, cv::gimpl::BGR>();
return cv::gapi::kernels<cv::gimpl::BGR>();
}
cv::gapi::GKernelPackage cv::gimpl::streaming::kernels()
{
return cv::gapi::kernels<cv::gimpl::Copy>();
}
void cv::gimpl::Copy::Actor::run(cv::gimpl::GIslandExecutable::IInput &in,
@ -153,8 +158,21 @@ void cv::gimpl::Copy::Actor::run(cv::gimpl::GIslandExecutable::IInput &in,
const cv::GRunArgs &in_args = cv::util::get<cv::GRunArgs>(in_msg);
GAPI_Assert(in_args.size() == 1u);
cv::GRunArgP out_arg = out.get(0);
*cv::util::get<cv::MediaFrame*>(out_arg) = cv::util::get<cv::MediaFrame>(in_args[0]);
const auto& in_arg = in_args[0];
auto out_arg = out.get(0);
using cv::util::get;
switch (in_arg.index()) {
case cv::GRunArg::index_of<cv::RMat>():
*get<cv::RMat*>(out_arg) = get<cv::RMat>(in_arg);
break;
case cv::GRunArg::index_of<cv::MediaFrame>():
*get<cv::MediaFrame*>(out_arg) = get<cv::MediaFrame>(in_arg);
break;
// FIXME: Add support for remaining types
default:
GAPI_Assert(false && "Copy: unsupported data type");
}
out.meta(out_arg, in_arg.meta);
out.post(std::move(out_arg));
}
@ -197,3 +215,11 @@ void cv::gimpl::BGR::Actor::run(cv::gimpl::GIslandExecutable::IInput &in,
}
out.post(std::move(out_arg));
}
cv::GMat cv::gapi::copy(const cv::GMat& in) {
return cv::gimpl::streaming::GCopy::on<cv::GMat>(in);
}
cv::GFrame cv::gapi::copy(const cv::GFrame& in) {
return cv::gimpl::streaming::GCopy::on<cv::GFrame>(in);
}

View File

@ -12,11 +12,37 @@
#include "gstreamingkernel.hpp"
namespace cv {
namespace gapi {
namespace streaming {
cv::gapi::GBackend backend();
}} // namespace gapi::streaming
namespace gimpl {
namespace streaming {
cv::gapi::GKernelPackage kernels();
struct GCopy final : public cv::detail::NoTag
{
static constexpr const char* id() { return "org.opencv.streaming.copy"; }
static GMetaArgs getOutMeta(const GMetaArgs &in_meta, const GArgs&) {
GAPI_Assert(in_meta.size() == 1u);
return in_meta;
}
template<typename T> static T on(const T& arg) {
return cv::GKernelType<GCopy, std::function<T(T)>>::on(arg);
}
};
} // namespace streaming
struct Copy: public cv::detail::KernelTag
{
using API = cv::gapi::streaming::GCopy;
using API = streaming::GCopy;
static gapi::GBackend backend() { return cv::gapi::streaming::backend(); }

View File

@ -36,6 +36,7 @@
#include "executor/gstreamingexecutor.hpp"
#include "backends/common/gbackend.hpp"
#include "backends/common/gmetabackend.hpp"
#include "backends/streaming/gstreamingbackend.hpp"
// <FIXME:>
#if !defined(GAPI_STANDALONE)
@ -60,8 +61,11 @@ namespace
for (const auto &b : pkg.backends()) {
aux_pkg = combine(aux_pkg, b.priv().auxiliaryKernels());
}
// Always include built-in meta<> implementation
return combine(pkg, aux_pkg, cv::gimpl::meta::kernels());
// Always include built-in meta<> and copy implementation
return combine(pkg,
aux_pkg,
cv::gimpl::meta::kernels(),
cv::gimpl::streaming::kernels());
};
auto has_use_only = cv::gapi::getCompileArg<cv::gapi::use_only>(args);

View File

@ -18,7 +18,6 @@
#include "compiler/gmodel.hpp"
#include "compiler/gislandmodel.hpp"
#include "compiler/gmodel.hpp"
#include "backends/common/gbackend.hpp" // RMatAdapter
#include "logger.hpp" // GAPI_LOG
@ -357,22 +356,7 @@ void GIslandExecutable::run(GIslandExecutable::IInput &in, GIslandExecutable::IO
for (auto &&it: ade::util::zip(ade::util::toRange(in_desc),
ade::util::toRange(in_vector)))
{
const cv::GRunArg& in_data_orig = std::get<1>(it);
cv::GRunArg in_data;
switch (in_data_orig.index())
{
case cv::GRunArg::index_of<cv::Mat>():
// FIXME: This whole construct is ugly, from
// its writing to a need in this in general
in_data = cv::GRunArg{ cv::make_rmat<cv::gimpl::RMatAdapter>(cv::util::get<cv::Mat>(in_data_orig))
, in_data_orig.meta
};
break;
default:
in_data = in_data_orig;
break;
}
in_objs.emplace_back(std::get<0>(it), std::move(in_data));
in_objs.emplace_back(std::get<0>(it), std::get<1>(it));
}
for (auto &&it: ade::util::indexed(ade::util::toRange(out_desc)))
{

View File

@ -146,16 +146,26 @@ void writeBackExec(const Mag& mag, const RcDesc &rc, GRunArgP &g_arg)
writeBack(mag, rc, g_arg);
return;
}
auto checkOutArgData = [&](const uchar* out_arg_data) {
//simply check that memory was not reallocated, i.e.
//both Mat and View pointing to the same memory
auto mag_data = mag.template slot<cv::RMat>().at(rc.id).get<RMatAdapter>()->data();
GAPI_Assert((out_arg_data == mag_data) && " data for output parameters was reallocated ?");
};
switch (g_arg.index())
{
case GRunArgP::index_of<cv::Mat*>() : checkOutArgData(util::get<cv::Mat*>(g_arg)->data); break;
case GRunArgP::index_of<cv::Mat*>() : {
// If there is a copy intrinsic at the end of the graph
// we need to actualy copy the data to the user buffer
// since output runarg was optimized to simply point
// to the input of the copy kernel
// FIXME:
// Rework, find a better way to check if there should be
// a real copy (add a pass to StreamingBackend?)
auto& out_mat = *util::get<cv::Mat*>(g_arg);
const auto& rmat = mag.template slot<cv::RMat>().at(rc.id);
auto mag_data = rmat.get<RMatAdapter>()->data();
if (out_mat.data != mag_data) {
auto view = rmat.access(RMat::Access::R);
asMat(view).copyTo(out_mat);
}
break;
}
case GRunArgP::index_of<cv::RMat*>() : /* do nothing */ break;
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
}

View File

@ -20,6 +20,7 @@
#include "api/gproto_priv.hpp" // ptr(GRunArgP)
#include "compiler/passes/passes.hpp"
#include "backends/common/gbackend.hpp" // createMat
#include "backends/streaming/gstreamingbackend.hpp" // GCopy
#include "compiler/gcompiler.hpp" // for compileIslands
#include "executor/gstreamingexecutor.hpp"
@ -535,6 +536,14 @@ class StreamingInput final: public cv::gimpl::GIslandExecutable::IInput
// Stop case
return cv::gimpl::StreamMsg{cv::gimpl::EndOfStream{}};
}
// Wrap all input cv::Mats with RMats
for (auto& arg : isl_input_args) {
if (arg.index() == cv::GRunArg::index_of<cv::Mat>()) {
arg = cv::GRunArg{ cv::make_rmat<cv::gimpl::RMatAdapter>(cv::util::get<cv::Mat>(arg))
, arg.meta
};
}
}
return cv::gimpl::StreamMsg{std::move(isl_input_args)};
}
virtual cv::gimpl::StreamMsg try_get() override
@ -1000,7 +1009,7 @@ cv::gimpl::GStreamingExecutor::GStreamingExecutor(std::unique_ptr<ade::Graph> &&
GAPI_Assert(GModel::Graph(*m_orig_graph)
.metadata(*isl->in_ops().begin())
.get<cv::gimpl::Op>()
.k.name == cv::gapi::core::GCopy::id());
.k.name == cv::gimpl::streaming::GCopy::id());
#endif // GAPI_STANDALONE
for (auto out_nh : nh->outNodes()) {
for (auto out_eh : out_nh->outEdges()) {

View File

@ -433,12 +433,4 @@ INSTANTIATE_TEST_CASE_P(ReInitOutTestFluid, ReInitOutTest,
Values(CORE_FLUID),
Values(cv::Size(640, 400),
cv::Size(10, 480))));
INSTANTIATE_TEST_CASE_P(CopyTestFluid, CopyTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_FLUID)));
}

View File

@ -359,14 +359,6 @@ INSTANTIATE_TEST_CASE_P(CropTestGPU, CropTest,
Values(CORE_GPU),
Values(cv::Rect(10, 8, 20, 35), cv::Rect(4, 10, 37, 50))));
INSTANTIATE_TEST_CASE_P(CopyTestGPU, CopyTest,
Combine(Values( CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1 ),
Values(cv::Size(1280, 720),
cv::Size(640, 480),
cv::Size(128, 128)),
Values(-1),
Values(CORE_GPU)));
INSTANTIATE_TEST_CASE_P(LUTTestGPU, LUTTest,
Combine(Values(CV_8UC1, CV_8UC3),
Values(cv::Size(1280, 720),

View File

@ -527,6 +527,7 @@ TEST(IslandFusion, Test_Desync_NoFuse)
//////////////////////////////////////////////////////////////////
// Compile the graph in "regular" mode, it should produce a single island
// Note: with copy moved to a separate backend there is always 3 islands in this test
{
using namespace cv::gimpl;
@ -544,11 +545,12 @@ TEST(IslandFusion, Test_Desync_NoFuse)
const auto num_isl = std::count_if(gim.nodes().begin(),
gim.nodes().end(),
is_island);
EXPECT_EQ(1, num_isl);
EXPECT_EQ(3, num_isl);
}
//////////////////////////////////////////////////////////////////
// Now compile the graph in the streaming mode.
// It has to produce two islands
// Note: with copy moved to a separate backend there is always 3 islands in this test
{
using namespace cv::gimpl;
@ -567,7 +569,7 @@ TEST(IslandFusion, Test_Desync_NoFuse)
const auto num_isl = std::count_if(gim.nodes().begin(),
gim.nodes().end(),
is_island);
EXPECT_EQ(2, num_isl);
EXPECT_EQ(3, num_isl);
}
}

View File

@ -1645,37 +1645,20 @@ TEST(GAPI_Streaming_Desync, StartStop_Stress) {
}
}
GAPI_FLUID_KERNEL(FluidCopy, cv::gapi::core::GCopy, false) {
static const int Window = 1;
static void run(const cv::gapi::fluid::View &in,
cv::gapi::fluid::Buffer &out) {
const uint8_t *in_ptr = in.InLineB(0);
uint8_t *out_ptr = out.OutLineB(0);
const auto in_type = CV_MAKETYPE(in.meta().depth, in.meta().chan);
const auto out_type = CV_MAKETYPE(out.meta().depth, out.meta().chan);
GAPI_Assert(in_type == out_type);
std::copy_n(in_ptr, in.length()*CV_ELEM_SIZE(in_type), out_ptr);
}
};
TEST(GAPI_Streaming_Desync, DesyncObjectConsumedByTwoIslandsViaSeparateDesync) {
// See comment in the implementation of cv::gapi::streaming::desync (.cpp)
cv::GMat in;
cv::GMat tmp = cv::gapi::boxFilter(in, -1, cv::Size(3,3));
cv::GMat tmp1 = cv::gapi::streaming::desync(tmp);
cv::GMat out1 = cv::gapi::copy(tmp1); // ran via Fluid backend
cv::GMat out1 = cv::gapi::copy(tmp1); // ran via Streaming backend
cv::GMat tmp2 = cv::gapi::streaming::desync(tmp);
cv::GMat out2 = tmp2 * 0.5; // ran via OCV backend
auto c = cv::GComputation(cv::GIn(in), cv::GOut(out1, out2));
auto p = cv::gapi::kernels<FluidCopy>();
EXPECT_NO_THROW(c.compileStreaming(cv::compile_args(p)));
EXPECT_NO_THROW(c.compileStreaming());
}
TEST(GAPI_Streaming_Desync, DesyncObjectConsumedByTwoIslandsViaSameDesync) {
@ -1684,13 +1667,12 @@ TEST(GAPI_Streaming_Desync, DesyncObjectConsumedByTwoIslandsViaSameDesync) {
cv::GMat tmp = cv::gapi::boxFilter(in, -1, cv::Size(3,3));
cv::GMat tmp1 = cv::gapi::streaming::desync(tmp);
cv::GMat out1 = cv::gapi::copy(tmp1); // ran via Fluid backend
cv::GMat out1 = cv::gapi::copy(tmp1); // ran via Streaming backend
cv::GMat out2 = out1 - 0.5*tmp1; // ran via OCV backend
auto c = cv::GComputation(cv::GIn(in), cv::GOut(out1, out2));
auto p = cv::gapi::kernels<FluidCopy>();
EXPECT_NO_THROW(c.compileStreaming(cv::compile_args(p)));
EXPECT_NO_THROW(c.compileStreaming());
}
TEST(GAPI_Streaming, CopyFrame)
@ -1699,7 +1681,7 @@ TEST(GAPI_Streaming, CopyFrame)
std::string filepath = findDataFile("cv/video/768x576.avi");
cv::GFrame in;
auto out = cv::gapi::streaming::copy(in);
auto out = cv::gapi::copy(in);
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
@ -1732,13 +1714,50 @@ TEST(GAPI_Streaming, CopyFrame)
}
}
TEST(GAPI_Streaming, CopyMat)
{
initTestDataPath();
std::string filepath = findDataFile("cv/video/768x576.avi");
cv::GMat in;
auto out = cv::gapi::copy(in);
cv::GComputation comp(cv::GIn(in), cv::GOut(out));
auto cc = comp.compileStreaming();
try {
cc.setSource<cv::gapi::wip::GCaptureSource>(filepath);
} catch(...) {
throw SkipTestException("Video file can not be opened");
}
cv::VideoCapture cap;
cap.open(filepath);
if (!cap.isOpened())
throw SkipTestException("Video file can not be opened");
cv::Mat out_mat;
cv::Mat ocv_mat;
std::size_t num_frames = 0u;
std::size_t max_frames = 10u;
cc.start();
while (cc.pull(cv::gout(out_mat)) && num_frames < max_frames)
{
num_frames++;
cap >> ocv_mat;
EXPECT_EQ(0, cvtest::norm(ocv_mat, out_mat, NORM_INF));
}
}
TEST(GAPI_Streaming, Reshape)
{
initTestDataPath();
std::string filepath = findDataFile("cv/video/768x576.avi");
cv::GFrame in;
auto out = cv::gapi::streaming::copy(in);
auto out = cv::gapi::copy(in);
cv::GComputation comp(cv::GIn(in), cv::GOut(out));