1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
5 // Copyright (C) 2018-2019 Intel Corporation
8 #include "test_precomp.hpp"
10 #include <ade/util/zip_range.hpp> // util::indexed
12 #include "opencv2/gapi/gkernel.hpp"
13 #include "compiler/gmodelbuilder.hpp"
14 #include "compiler/gmodel.hpp" // RcDesc, GModel::init
24 cv::GMat unaryOp(cv::GMat m)
26 return cv::GCall(cv::GKernel{"gapi.test.unaryop", nullptr, { GShape::GMAT } }).pass(m).yield(0);
29 cv::GMat binaryOp(cv::GMat m1, cv::GMat m2)
31 return cv::GCall(cv::GKernel{"gapi.test.binaryOp", nullptr, { GShape::GMAT } }).pass(m1, m2).yield(0);
34 std::vector<ade::NodeHandle> collectOperations(const cv::gimpl::GModel::Graph& gr)
36 std::vector<ade::NodeHandle> ops;
37 for (const auto& nh : gr.nodes())
39 if (gr.metadata(nh).get<cv::gimpl::NodeType>().t == cv::gimpl::NodeType::OP)
45 ade::NodeHandle inputOf(cv::gimpl::GModel::Graph& gm, ade::NodeHandle nh, std::size_t port)
47 for (const auto& eh : nh->inEdges())
49 if (gm.metadata(eh).get<cv::gimpl::Input>().port == port)
54 util::throw_error(std::logic_error("port " + std::to_string(port) + " not found"));
57 }// namespace opencv_test::test
59 TEST(GModelBuilder, Unroll_TestUnary)
62 cv::GMat out = test::unaryOp(in);
64 auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out).m_args);
66 EXPECT_EQ(1u, unrolled.all_ops.size()); // There is one operation
67 EXPECT_EQ(2u, unrolled.all_data.size()); // And two data objects (in, out)
69 // TODO check what the operation is, and so on, and so on
72 TEST(GModelBuilder, Unroll_TestUnaryOfUnary)
75 cv::GMat out = test::unaryOp(test::unaryOp(in));
77 auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out).m_args);
79 EXPECT_EQ(2u, unrolled.all_ops.size()); // There're two operations
80 EXPECT_EQ(3u, unrolled.all_data.size()); // And three data objects (in, out)
82 // TODO check what the operation is, and so on, and so on
85 TEST(GModelBuilder, Unroll_Not_All_Protocol_Inputs_Are_Reached)
87 cv::GMat in1, in2; // in1 -> unaryOp() -> u_op1 -> unaryOp() -> out
88 auto u_op1 = test::unaryOp(in1); // in2 -> unaryOp() -> u_op2
89 auto u_op2 = test::unaryOp(in2);
90 auto out = test::unaryOp(u_op1);
92 EXPECT_THROW(cv::gimpl::unrollExpr(cv::GIn(in1, in2).m_args, cv::GOut(out).m_args), std::logic_error);
95 TEST(GModelBuilder, Unroll_Parallel_Path)
97 cv::GMat in1, in2; // in1 -> unaryOp() -> out1
98 auto out1 = test::unaryOp(in1); // in2 -> unaryOp() -> out2
99 auto out2 = test::unaryOp(in2);
101 auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in1, in2).m_args, cv::GOut(out1, out2).m_args);
103 EXPECT_EQ(unrolled.all_ops.size(), 2u);
104 EXPECT_EQ(unrolled.all_data.size(), 4u);
107 TEST(GModelBuilder, Unroll_WithBranch)
109 // in -> unaryOp() -> tmp -->unaryOp() -> out1
110 // `---->unaryOp() -> out2
113 auto tmp = test::unaryOp(in);
114 auto out1 = test::unaryOp(tmp);
115 auto out2 = test::unaryOp(tmp);
117 auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out1, out2).m_args);
119 EXPECT_EQ(unrolled.all_ops.size(), 3u);
120 EXPECT_EQ(unrolled.all_data.size(), 4u);
123 TEST(GModelBuilder, Build_Unary)
126 cv::GMat out = test::unaryOp(in);
129 cv::gimpl::GModel::Graph gm(g);
130 cv::gimpl::GModel::init(gm);
131 cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(out).m_args);
133 EXPECT_EQ(3u, static_cast<std::size_t>(g.nodes().size())); // Generated graph should have three nodes
135 // TODO: Check what the nodes are
138 TEST(GModelBuilder, Constant_GScalar)
140 // in -> addC()-----(GMat)---->mulC()-----(GMat)---->unaryOp()----out
143 // 3-------` c_s-------'
147 auto out = test::unaryOp((in + 3) * c_s); // 3 converted to GScalar
150 cv::gimpl::GModel::Graph gm(g);
151 cv::gimpl::GModel::init(gm);
152 auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(out).m_args);
153 cv::gimpl::Protocol p;
154 std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
156 auto in_nh = p.in_nhs.front();
157 auto addC_nh = in_nh->outNodes().front();
158 auto mulC_nh = addC_nh->outNodes().front()->outNodes().front();
160 ASSERT_TRUE(gm.metadata(addC_nh).get<cv::gimpl::NodeType>().t == cv::gimpl::NodeType::OP);
161 ASSERT_TRUE(gm.metadata(mulC_nh).get<cv::gimpl::NodeType>().t == cv::gimpl::NodeType::OP);
163 auto s_3 = test::inputOf(gm, addC_nh, 1);
164 auto s_5 = test::inputOf(gm, mulC_nh, 1);
166 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
167 EXPECT_EQ(2u, static_cast<std::size_t>(addC_nh->inNodes().size())); // in and 3
168 EXPECT_EQ(2u, static_cast<std::size_t>(mulC_nh->inNodes().size())); // addC output and c_s
169 EXPECT_EQ(3, (util::get<cv::gapi::own::Scalar>(gm.metadata(s_3).get<cv::gimpl::ConstValue>().arg))[0]);
170 EXPECT_EQ(5, (util::get<cv::gapi::own::Scalar>(gm.metadata(s_5).get<cv::gimpl::ConstValue>().arg))[0]);
173 TEST(GModelBuilder, Check_Multiple_Outputs)
175 // ------------------------------> r
177 // ' -----------> i_out1
179 // in ----> split3() ---> g ---> integral()
181 // ' -----------> i_out2
183 // '---------> b ---> unaryOp() ---> u_out
185 cv::GMat in, r, g, b, i_out1, i_out2, u_out;
186 std::tie(r, g, b) = cv::gapi::split3(in);
187 std::tie(i_out1, i_out2) = cv::gapi::integral(g, 1, 1);
188 u_out = test::unaryOp(b);
191 cv::gimpl::GModel::Graph gm(gr);
192 cv::gimpl::GModel::init(gm);
193 auto proto_slots = cv::gimpl::GModelBuilder(gr).put(cv::GIn(in).m_args, cv::GOut(r, i_out1, i_out2, u_out).m_args);
194 cv::gimpl::Protocol p;
195 std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
197 EXPECT_EQ(4u, static_cast<std::size_t>(p.out_nhs.size()));
198 EXPECT_EQ(0u, gm.metadata(p.out_nhs[0]->inEdges().front()).get<cv::gimpl::Output>().port);
199 EXPECT_EQ(0u, gm.metadata(p.out_nhs[1]->inEdges().front()).get<cv::gimpl::Output>().port);
200 EXPECT_EQ(1u, gm.metadata(p.out_nhs[2]->inEdges().front()).get<cv::gimpl::Output>().port);
201 EXPECT_EQ(0u, gm.metadata(p.out_nhs[3]->inEdges().front()).get<cv::gimpl::Output>().port);
202 for (const auto& it : ade::util::indexed(p.out_nhs))
204 const auto& out_nh = ade::util::value(it);
206 EXPECT_EQ(cv::gimpl::NodeType::DATA, gm.metadata(out_nh).get<cv::gimpl::NodeType>().t);
207 EXPECT_EQ(GShape::GMAT, gm.metadata(out_nh).get<cv::gimpl::Data>().shape);
211 TEST(GModelBuilder, Unused_Outputs)
214 auto yuv_p = cv::gapi::split3(in);
217 cv::gimpl::GModel::Graph gm(g);
218 cv::gimpl::GModel::init(gm);
219 cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(std::get<0>(yuv_p)).m_args);
221 EXPECT_EQ(5u, static_cast<std::size_t>(g.nodes().size())); // 1 input, 1 operation, 3 outputs
224 TEST(GModelBuilder, Work_With_One_Channel_From_Split3)
226 cv::GMat in, y, u, v;
227 std::tie(y, u, v) = cv::gapi::split3(in);
228 auto y_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
231 cv::gimpl::GModel::Graph gm(g);
232 cv::gimpl::GModel::init(gm);
233 cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(y_blur).m_args);
235 EXPECT_EQ(7u, static_cast<std::size_t>(g.nodes().size())); // 1 input, 2 operation, 3 nodes from split3, 1 output
238 TEST(GModelBuilder, Add_Nodes_To_Unused_Nodes)
240 cv::GMat in, y, u, v;
241 std::tie(y, u, v) = cv::gapi::split3(in);
242 auto y_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
244 auto u_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
245 auto v_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
248 cv::gimpl::GModel::Graph gm(g);
249 cv::gimpl::GModel::init(gm);
250 cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(y_blur).m_args);
252 EXPECT_EQ(7u, static_cast<std::size_t>(g.nodes().size())); // 1 input, 2 operation, 3 nodes from split3, 1 output
255 TEST(GModelBuilder, Unlisted_Inputs)
257 // in1 -> binaryOp() -> out
263 auto out = test::binaryOp(in1, in2);
266 cv::gimpl::GModel::Graph gm(g);
267 cv::gimpl::GModel::init(gm);
268 // add required 2 inputs but pass 1
269 EXPECT_THROW(cv::gimpl::GModelBuilder(g).put(cv::GIn(in1).m_args, cv::GOut(out).m_args), std::logic_error);
272 TEST(GModelBuilder, Unroll_No_Link_Between_In_And_Out)
274 // in -> unaryOp() -> u_op
275 // other -> unaryOp() -> out
278 auto u_op = test::unaryOp(in);
279 auto out = test::unaryOp(other);
281 EXPECT_THROW(cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out).m_args), std::logic_error);
285 TEST(GModel_builder, Check_Binary_Op)
287 // in1 -> binaryOp() -> out
293 auto out = test::binaryOp(in1, in2);
296 cv::gimpl::GModel::Graph gm(g);
297 cv::gimpl::GModel::init(gm);
298 auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in1, in2).m_args, cv::GOut(out).m_args);
300 cv::gimpl::Protocol p;
301 std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
302 auto ops = test::collectOperations(g);
304 EXPECT_EQ(1u, ops.size());
305 EXPECT_EQ("gapi.test.binaryOp", gm.metadata(ops.front()).get<cv::gimpl::Op>().k.name);
306 EXPECT_EQ(2u, static_cast<std::size_t>(ops.front()->inEdges().size()));
307 EXPECT_EQ(1u, static_cast<std::size_t>(ops.front()->outEdges().size()));
308 EXPECT_EQ(1u, static_cast<std::size_t>(ops.front()->outNodes().size()));
311 TEST(GModelBuilder, Add_Operation_With_Two_Out_One_Time)
313 // in -> integral() --> out_b1 -> unaryOp() -> out1
315 // '-------> out_b2 -> unaryOp() -> out2
317 cv::GMat in, out_b1, out_b2;
318 std::tie(out_b1, out_b2) = cv::gapi::integral(in, 1, 1);
319 auto out1 = test::unaryOp(out_b1);
320 auto out2 = test::unaryOp(out_b1);
323 cv::gimpl::GModel::Graph gm(g);
324 cv::gimpl::GModel::init(gm);
325 auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(out1, out2).m_args);
327 auto ops = test::collectOperations(gm);
329 cv::gimpl::Protocol p;
330 std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
331 auto integral_nh = p.in_nhs.front()->outNodes().front();
333 EXPECT_EQ(3u, ops.size());
334 EXPECT_EQ("org.opencv.core.matrixop.integral", gm.metadata(integral_nh).get<cv::gimpl::Op>().k.name);
335 EXPECT_EQ(1u, static_cast<std::size_t>(integral_nh->inEdges().size()));
336 EXPECT_EQ(2u, static_cast<std::size_t>(integral_nh->outEdges().size()));
337 EXPECT_EQ(2u, static_cast<std::size_t>(integral_nh->outNodes().size()));
339 TEST(GModelBuilder, Add_Operation_With_One_Out_One_Time)
341 // in1 -> binaryOp() -> b_out -> unaryOp() -> out1
344 // in2 ------- '----> unaryOp() -> out2
347 auto b_out = test::binaryOp(in1, in2);
348 auto out1 = test::unaryOp(b_out);
349 auto out2 = test::unaryOp(b_out);
352 cv::gimpl::GModel::Graph gm(g);
353 cv::gimpl::GModel::init(gm);
354 auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in1, in2).m_args, cv::GOut(out1, out2).m_args);
355 cv::gimpl::Protocol p;
356 std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
357 cv::gimpl::GModel::Graph gr(g);
358 auto binaryOp_nh = p.in_nhs.front()->outNodes().front();
360 EXPECT_EQ(2u, static_cast<std::size_t>(binaryOp_nh->inEdges().size()));
361 EXPECT_EQ(1u, static_cast<std::size_t>(binaryOp_nh->outEdges().size()));
362 EXPECT_EQ(8u, static_cast<std::size_t>(g.nodes().size()));
364 } // namespace opencv_test