// 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 "test_precomp.hpp" #include // util::indexed #include "opencv2/gapi/gkernel.hpp" #include "compiler/gmodelbuilder.hpp" #include "compiler/gmodel.hpp" // RcDesc, GModel::init namespace opencv_test { namespace test { namespace { cv::GMat unaryOp(cv::GMat m) { return cv::GCall(cv::GKernel{"gapi.test.unaryop", nullptr, { GShape::GMAT } }).pass(m).yield(0); } cv::GMat binaryOp(cv::GMat m1, cv::GMat m2) { return cv::GCall(cv::GKernel{"gapi.test.binaryOp", nullptr, { GShape::GMAT } }).pass(m1, m2).yield(0); } std::vector collectOperations(const cv::gimpl::GModel::Graph& gr) { std::vector ops; for (const auto& nh : gr.nodes()) { if (gr.metadata(nh).get().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().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(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().t == cv::gimpl::NodeType::OP); ASSERT_TRUE(gm.metadata(mulC_nh).get().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(g.nodes().size())); // 6 data nodes (1 -input, 1 output, 2 constant, 2 temp) and 3 op nodes EXPECT_EQ(2u, static_cast(addC_nh->inNodes().size())); // in and 3 EXPECT_EQ(2u, static_cast(mulC_nh->inNodes().size())); // addC output and c_s EXPECT_EQ(3, (util::get(gm.metadata(s_3).get().arg))[0]); EXPECT_EQ(5, (util::get(gm.metadata(s_5).get().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(p.out_nhs.size())); EXPECT_EQ(0u, gm.metadata(p.out_nhs[0]->inEdges().front()).get().port); EXPECT_EQ(0u, gm.metadata(p.out_nhs[1]->inEdges().front()).get().port); EXPECT_EQ(1u, gm.metadata(p.out_nhs[2]->inEdges().front()).get().port); EXPECT_EQ(0u, gm.metadata(p.out_nhs[3]->inEdges().front()).get().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().t); EXPECT_EQ(GShape::GMAT, gm.metadata(out_nh).get().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(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(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(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().k.name); EXPECT_EQ(2u, static_cast(ops.front()->inEdges().size())); EXPECT_EQ(1u, static_cast(ops.front()->outEdges().size())); EXPECT_EQ(1u, static_cast(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().k.name); EXPECT_EQ(1u, static_cast(integral_nh->inEdges().size())); EXPECT_EQ(2u, static_cast(integral_nh->outEdges().size())); EXPECT_EQ(2u, static_cast(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(binaryOp_nh->inEdges().size())); EXPECT_EQ(1u, static_cast(binaryOp_nh->outEdges().size())); EXPECT_EQ(8u, static_cast(g.nodes().size())); } } // namespace opencv_test