123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 |
- // 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-2020 Intel Corporation
- #include "../test_precomp.hpp"
- #include <ade/util/zip_range.hpp> // util::indexed
- #include <opencv2/gapi/gkernel.hpp>
- #include <opencv2/gapi/gcommon.hpp>
- #include "compiler/gmodelbuilder.hpp"
- #include "compiler/gmodel.hpp" // RcDesc, GModel::init
- namespace opencv_test
- {
- namespace test
- {
- namespace
- {
- namespace D = cv::detail;
- cv::GMat unaryOp(cv::GMat m)
- {
- return cv::GCall(cv::GKernel{ "gapi.test.unaryop"
- , ""
- , nullptr
- , { GShape::GMAT }
- , { D::OpaqueKind::CV_UNKNOWN }
- , { cv::detail::HostCtor{cv::util::monostate{}} }
- }).pass(m).yield(0);
- }
- cv::GMat binaryOp(cv::GMat m1, cv::GMat m2)
- {
- return cv::GCall(cv::GKernel{ "gapi.test.binaryOp"
- , ""
- , nullptr
- , { GShape::GMAT }
- , { D::OpaqueKind::CV_UNKNOWN, D::OpaqueKind::CV_UNKNOWN }
- , { cv::detail::HostCtor{cv::util::monostate{}} }
- }).pass(m1, m2).yield(0);
- }
- std::vector<ade::NodeHandle> collectOperations(const cv::gimpl::GModel::Graph& gr)
- {
- std::vector<ade::NodeHandle> ops;
- for (const auto& nh : gr.nodes())
- {
- if (gr.metadata(nh).get<cv::gimpl::NodeType>().t == cv::gimpl::NodeType::OP)
- ops.push_back(nh);
- }
- return ops;
- }
- ade::NodeHandle inputOf(cv::gimpl::GModel::Graph& gm, ade::NodeHandle nh, std::size_t port)
- {
- for (const auto& eh : nh->inEdges())
- {
- if (gm.metadata(eh).get<cv::gimpl::Input>().port == port)
- {
- return eh->srcNode();
- }
- }
- util::throw_error(std::logic_error("port " + std::to_string(port) + " not found"));
- }
- }
- }// namespace opencv_test::test
- TEST(GModelBuilder, Unroll_TestUnary)
- {
- cv::GMat in;
- cv::GMat out = test::unaryOp(in);
- auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out).m_args);
- EXPECT_EQ(1u, unrolled.all_ops.size()); // There is one operation
- EXPECT_EQ(2u, unrolled.all_data.size()); // And two data objects (in, out)
- // TODO check what the operation is, and so on, and so on
- }
- TEST(GModelBuilder, Unroll_TestUnaryOfUnary)
- {
- cv::GMat in;
- cv::GMat out = test::unaryOp(test::unaryOp(in));
- auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out).m_args);
- EXPECT_EQ(2u, unrolled.all_ops.size()); // There're two operations
- EXPECT_EQ(3u, unrolled.all_data.size()); // And three data objects (in, out)
- // TODO check what the operation is, and so on, and so on
- }
- TEST(GModelBuilder, Unroll_Not_All_Protocol_Inputs_Are_Reached)
- {
- cv::GMat in1, in2; // in1 -> unaryOp() -> u_op1 -> unaryOp() -> out
- auto u_op1 = test::unaryOp(in1); // in2 -> unaryOp() -> u_op2
- auto u_op2 = test::unaryOp(in2);
- auto out = test::unaryOp(u_op1);
- EXPECT_THROW(cv::gimpl::unrollExpr(cv::GIn(in1, in2).m_args, cv::GOut(out).m_args), std::logic_error);
- }
- TEST(GModelBuilder, Unroll_Parallel_Path)
- {
- cv::GMat in1, in2; // in1 -> unaryOp() -> out1
- auto out1 = test::unaryOp(in1); // in2 -> unaryOp() -> out2
- auto out2 = test::unaryOp(in2);
- auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in1, in2).m_args, cv::GOut(out1, out2).m_args);
- EXPECT_EQ(unrolled.all_ops.size(), 2u);
- EXPECT_EQ(unrolled.all_data.size(), 4u);
- }
- TEST(GModelBuilder, Unroll_WithBranch)
- {
- // in -> unaryOp() -> tmp -->unaryOp() -> out1
- // `---->unaryOp() -> out2
- GMat in;
- auto tmp = test::unaryOp(in);
- auto out1 = test::unaryOp(tmp);
- auto out2 = test::unaryOp(tmp);
- auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out1, out2).m_args);
- EXPECT_EQ(unrolled.all_ops.size(), 3u);
- EXPECT_EQ(unrolled.all_data.size(), 4u);
- }
- TEST(GModelBuilder, Build_Unary)
- {
- cv::GMat in;
- cv::GMat out = test::unaryOp(in);
- ade::Graph g;
- cv::gimpl::GModel::Graph gm(g);
- cv::gimpl::GModel::init(gm);
- cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(out).m_args);
- EXPECT_EQ(3u, static_cast<std::size_t>(g.nodes().size())); // Generated graph should have three nodes
- // TODO: Check what the nodes are
- }
- TEST(GModelBuilder, Constant_GScalar)
- {
- // in -> addC()-----(GMat)---->mulC()-----(GMat)---->unaryOp()----out
- // ^ ^
- // | |
- // 3-------` c_s-------'
- cv::GMat in;
- cv::GScalar c_s = 5;
- auto out = test::unaryOp((in + 3) * c_s); // 3 converted to GScalar
- ade::Graph g;
- cv::gimpl::GModel::Graph gm(g);
- cv::gimpl::GModel::init(gm);
- auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(out).m_args);
- cv::gimpl::Protocol p;
- std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
- auto in_nh = p.in_nhs.front();
- auto addC_nh = in_nh->outNodes().front();
- auto mulC_nh = addC_nh->outNodes().front()->outNodes().front();
- ASSERT_TRUE(gm.metadata(addC_nh).get<cv::gimpl::NodeType>().t == cv::gimpl::NodeType::OP);
- ASSERT_TRUE(gm.metadata(mulC_nh).get<cv::gimpl::NodeType>().t == cv::gimpl::NodeType::OP);
- auto s_3 = test::inputOf(gm, addC_nh, 1);
- auto s_5 = test::inputOf(gm, mulC_nh, 1);
- EXPECT_EQ(9u, static_cast<std::size_t>(g.nodes().size())); // 6 data nodes (1 -input, 1 output, 2 constant, 2 temp) and 3 op nodes
- EXPECT_EQ(2u, static_cast<std::size_t>(addC_nh->inNodes().size())); // in and 3
- EXPECT_EQ(2u, static_cast<std::size_t>(mulC_nh->inNodes().size())); // addC output and c_s
- EXPECT_EQ(3, (util::get<cv::Scalar>(gm.metadata(s_3).get<cv::gimpl::ConstValue>().arg))[0]);
- EXPECT_EQ(5, (util::get<cv::Scalar>(gm.metadata(s_5).get<cv::gimpl::ConstValue>().arg))[0]);
- }
- TEST(GModelBuilder, Check_Multiple_Outputs)
- {
- // ------------------------------> r
- // '
- // ' -----------> i_out1
- // ' '
- // in ----> split3() ---> g ---> integral()
- // ' '
- // ' -----------> i_out2
- // '
- // '---------> b ---> unaryOp() ---> u_out
- cv::GMat in, r, g, b, i_out1, i_out2, u_out;
- std::tie(r, g, b) = cv::gapi::split3(in);
- std::tie(i_out1, i_out2) = cv::gapi::integral(g, 1, 1);
- u_out = test::unaryOp(b);
- ade::Graph gr;
- cv::gimpl::GModel::Graph gm(gr);
- cv::gimpl::GModel::init(gm);
- auto proto_slots = cv::gimpl::GModelBuilder(gr).put(cv::GIn(in).m_args, cv::GOut(r, i_out1, i_out2, u_out).m_args);
- cv::gimpl::Protocol p;
- std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
- EXPECT_EQ(4u, static_cast<std::size_t>(p.out_nhs.size()));
- EXPECT_EQ(0u, gm.metadata(p.out_nhs[0]->inEdges().front()).get<cv::gimpl::Output>().port);
- EXPECT_EQ(0u, gm.metadata(p.out_nhs[1]->inEdges().front()).get<cv::gimpl::Output>().port);
- EXPECT_EQ(1u, gm.metadata(p.out_nhs[2]->inEdges().front()).get<cv::gimpl::Output>().port);
- EXPECT_EQ(0u, gm.metadata(p.out_nhs[3]->inEdges().front()).get<cv::gimpl::Output>().port);
- for (const auto it : ade::util::indexed(p.out_nhs))
- {
- const auto& out_nh = ade::util::value(it);
- EXPECT_EQ(cv::gimpl::NodeType::DATA, gm.metadata(out_nh).get<cv::gimpl::NodeType>().t);
- EXPECT_EQ(GShape::GMAT, gm.metadata(out_nh).get<cv::gimpl::Data>().shape);
- }
- }
- TEST(GModelBuilder, Unused_Outputs)
- {
- cv::GMat in;
- auto yuv_p = cv::gapi::split3(in);
- ade::Graph g;
- cv::gimpl::GModel::Graph gm(g);
- cv::gimpl::GModel::init(gm);
- cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(std::get<0>(yuv_p)).m_args);
- EXPECT_EQ(5u, static_cast<std::size_t>(g.nodes().size())); // 1 input, 1 operation, 3 outputs
- }
- TEST(GModelBuilder, Work_With_One_Channel_From_Split3)
- {
- cv::GMat in, y, u, v;
- std::tie(y, u, v) = cv::gapi::split3(in);
- auto y_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
- ade::Graph g;
- cv::gimpl::GModel::Graph gm(g);
- cv::gimpl::GModel::init(gm);
- cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(y_blur).m_args);
- EXPECT_EQ(7u, static_cast<std::size_t>(g.nodes().size())); // 1 input, 2 operation, 3 nodes from split3, 1 output
- }
- TEST(GModelBuilder, Add_Nodes_To_Unused_Nodes)
- {
- cv::GMat in, y, u, v;
- std::tie(y, u, v) = cv::gapi::split3(in);
- auto y_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
- // unused nodes
- auto u_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
- auto v_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
- ade::Graph g;
- cv::gimpl::GModel::Graph gm(g);
- cv::gimpl::GModel::init(gm);
- cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(y_blur).m_args);
- EXPECT_EQ(7u, static_cast<std::size_t>(g.nodes().size())); // 1 input, 2 operation, 3 nodes from split3, 1 output
- }
- TEST(GModelBuilder, Unlisted_Inputs)
- {
- // in1 -> binaryOp() -> out
- // ^
- // |
- // in2 ----'
- cv::GMat in1, in2;
- auto out = test::binaryOp(in1, in2);
- ade::Graph g;
- cv::gimpl::GModel::Graph gm(g);
- cv::gimpl::GModel::init(gm);
- // add required 2 inputs but pass 1
- EXPECT_THROW(cv::gimpl::GModelBuilder(g).put(cv::GIn(in1).m_args, cv::GOut(out).m_args), std::logic_error);
- }
- TEST(GModelBuilder, Unroll_No_Link_Between_In_And_Out)
- {
- // in -> unaryOp() -> u_op
- // other -> unaryOp() -> out
- cv::GMat in, other;
- auto u_op = test::unaryOp(in);
- auto out = test::unaryOp(other);
- EXPECT_THROW(cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out).m_args), std::logic_error);
- }
- TEST(GModel_builder, Check_Binary_Op)
- {
- // in1 -> binaryOp() -> out
- // ^
- // |
- // in2 -----'
- cv::GMat in1, in2;
- auto out = test::binaryOp(in1, in2);
- ade::Graph g;
- cv::gimpl::GModel::Graph gm(g);
- cv::gimpl::GModel::init(gm);
- auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in1, in2).m_args, cv::GOut(out).m_args);
- cv::gimpl::Protocol p;
- std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
- auto ops = test::collectOperations(g);
- EXPECT_EQ(1u, ops.size());
- EXPECT_EQ("gapi.test.binaryOp", gm.metadata(ops.front()).get<cv::gimpl::Op>().k.name);
- EXPECT_EQ(2u, static_cast<std::size_t>(ops.front()->inEdges().size()));
- EXPECT_EQ(1u, static_cast<std::size_t>(ops.front()->outEdges().size()));
- EXPECT_EQ(1u, static_cast<std::size_t>(ops.front()->outNodes().size()));
- }
- TEST(GModelBuilder, Add_Operation_With_Two_Out_One_Time)
- {
- // in -> integral() --> out_b1 -> unaryOp() -> out1
- // |
- // '-------> out_b2 -> unaryOp() -> out2
- cv::GMat in, out_b1, out_b2;
- std::tie(out_b1, out_b2) = cv::gapi::integral(in, 1, 1);
- auto out1 = test::unaryOp(out_b1);
- auto out2 = test::unaryOp(out_b1);
- ade::Graph g;
- cv::gimpl::GModel::Graph gm(g);
- cv::gimpl::GModel::init(gm);
- auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(out1, out2).m_args);
- auto ops = test::collectOperations(gm);
- cv::gimpl::Protocol p;
- std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
- auto integral_nh = p.in_nhs.front()->outNodes().front();
- EXPECT_EQ(3u, ops.size());
- EXPECT_EQ("org.opencv.core.matrixop.integral", gm.metadata(integral_nh).get<cv::gimpl::Op>().k.name);
- EXPECT_EQ(1u, static_cast<std::size_t>(integral_nh->inEdges().size()));
- EXPECT_EQ(2u, static_cast<std::size_t>(integral_nh->outEdges().size()));
- EXPECT_EQ(2u, static_cast<std::size_t>(integral_nh->outNodes().size()));
- }
- TEST(GModelBuilder, Add_Operation_With_One_Out_One_Time)
- {
- // in1 -> binaryOp() -> b_out -> unaryOp() -> out1
- // ^ |
- // | |
- // in2 ------- '----> unaryOp() -> out2
- cv::GMat in1, in2;
- auto b_out = test::binaryOp(in1, in2);
- auto out1 = test::unaryOp(b_out);
- auto out2 = test::unaryOp(b_out);
- ade::Graph g;
- cv::gimpl::GModel::Graph gm(g);
- cv::gimpl::GModel::init(gm);
- auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in1, in2).m_args, cv::GOut(out1, out2).m_args);
- cv::gimpl::Protocol p;
- std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
- cv::gimpl::GModel::Graph gr(g);
- auto binaryOp_nh = p.in_nhs.front()->outNodes().front();
- EXPECT_EQ(2u, static_cast<std::size_t>(binaryOp_nh->inEdges().size()));
- EXPECT_EQ(1u, static_cast<std::size_t>(binaryOp_nh->outEdges().size()));
- EXPECT_EQ(8u, static_cast<std::size_t>(g.nodes().size()));
- }
- } // namespace opencv_test
|