gapi_int_gmodel_builder_test.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  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.
  4. //
  5. // Copyright (C) 2018-2020 Intel Corporation
  6. #include "../test_precomp.hpp"
  7. #include <ade/util/zip_range.hpp> // util::indexed
  8. #include <opencv2/gapi/gkernel.hpp>
  9. #include <opencv2/gapi/gcommon.hpp>
  10. #include "compiler/gmodelbuilder.hpp"
  11. #include "compiler/gmodel.hpp" // RcDesc, GModel::init
  12. namespace opencv_test
  13. {
  14. namespace test
  15. {
  16. namespace
  17. {
  18. namespace D = cv::detail;
  19. cv::GMat unaryOp(cv::GMat m)
  20. {
  21. return cv::GCall(cv::GKernel{ "gapi.test.unaryop"
  22. , ""
  23. , nullptr
  24. , { GShape::GMAT }
  25. , { D::OpaqueKind::CV_UNKNOWN }
  26. , { cv::detail::HostCtor{cv::util::monostate{}} }
  27. }).pass(m).yield(0);
  28. }
  29. cv::GMat binaryOp(cv::GMat m1, cv::GMat m2)
  30. {
  31. return cv::GCall(cv::GKernel{ "gapi.test.binaryOp"
  32. , ""
  33. , nullptr
  34. , { GShape::GMAT }
  35. , { D::OpaqueKind::CV_UNKNOWN, D::OpaqueKind::CV_UNKNOWN }
  36. , { cv::detail::HostCtor{cv::util::monostate{}} }
  37. }).pass(m1, m2).yield(0);
  38. }
  39. std::vector<ade::NodeHandle> collectOperations(const cv::gimpl::GModel::Graph& gr)
  40. {
  41. std::vector<ade::NodeHandle> ops;
  42. for (const auto& nh : gr.nodes())
  43. {
  44. if (gr.metadata(nh).get<cv::gimpl::NodeType>().t == cv::gimpl::NodeType::OP)
  45. ops.push_back(nh);
  46. }
  47. return ops;
  48. }
  49. ade::NodeHandle inputOf(cv::gimpl::GModel::Graph& gm, ade::NodeHandle nh, std::size_t port)
  50. {
  51. for (const auto& eh : nh->inEdges())
  52. {
  53. if (gm.metadata(eh).get<cv::gimpl::Input>().port == port)
  54. {
  55. return eh->srcNode();
  56. }
  57. }
  58. util::throw_error(std::logic_error("port " + std::to_string(port) + " not found"));
  59. }
  60. }
  61. }// namespace opencv_test::test
  62. TEST(GModelBuilder, Unroll_TestUnary)
  63. {
  64. cv::GMat in;
  65. cv::GMat out = test::unaryOp(in);
  66. auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out).m_args);
  67. EXPECT_EQ(1u, unrolled.all_ops.size()); // There is one operation
  68. 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
  70. }
  71. TEST(GModelBuilder, Unroll_TestUnaryOfUnary)
  72. {
  73. cv::GMat in;
  74. cv::GMat out = test::unaryOp(test::unaryOp(in));
  75. auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out).m_args);
  76. EXPECT_EQ(2u, unrolled.all_ops.size()); // There're two operations
  77. EXPECT_EQ(3u, unrolled.all_data.size()); // And three data objects (in, out)
  78. // TODO check what the operation is, and so on, and so on
  79. }
  80. TEST(GModelBuilder, Unroll_Not_All_Protocol_Inputs_Are_Reached)
  81. {
  82. cv::GMat in1, in2; // in1 -> unaryOp() -> u_op1 -> unaryOp() -> out
  83. auto u_op1 = test::unaryOp(in1); // in2 -> unaryOp() -> u_op2
  84. auto u_op2 = test::unaryOp(in2);
  85. auto out = test::unaryOp(u_op1);
  86. EXPECT_THROW(cv::gimpl::unrollExpr(cv::GIn(in1, in2).m_args, cv::GOut(out).m_args), std::logic_error);
  87. }
  88. TEST(GModelBuilder, Unroll_Parallel_Path)
  89. {
  90. cv::GMat in1, in2; // in1 -> unaryOp() -> out1
  91. auto out1 = test::unaryOp(in1); // in2 -> unaryOp() -> out2
  92. auto out2 = test::unaryOp(in2);
  93. auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in1, in2).m_args, cv::GOut(out1, out2).m_args);
  94. EXPECT_EQ(unrolled.all_ops.size(), 2u);
  95. EXPECT_EQ(unrolled.all_data.size(), 4u);
  96. }
  97. TEST(GModelBuilder, Unroll_WithBranch)
  98. {
  99. // in -> unaryOp() -> tmp -->unaryOp() -> out1
  100. // `---->unaryOp() -> out2
  101. GMat in;
  102. auto tmp = test::unaryOp(in);
  103. auto out1 = test::unaryOp(tmp);
  104. auto out2 = test::unaryOp(tmp);
  105. auto unrolled = cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out1, out2).m_args);
  106. EXPECT_EQ(unrolled.all_ops.size(), 3u);
  107. EXPECT_EQ(unrolled.all_data.size(), 4u);
  108. }
  109. TEST(GModelBuilder, Build_Unary)
  110. {
  111. cv::GMat in;
  112. cv::GMat out = test::unaryOp(in);
  113. ade::Graph g;
  114. cv::gimpl::GModel::Graph gm(g);
  115. cv::gimpl::GModel::init(gm);
  116. cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(out).m_args);
  117. EXPECT_EQ(3u, static_cast<std::size_t>(g.nodes().size())); // Generated graph should have three nodes
  118. // TODO: Check what the nodes are
  119. }
  120. TEST(GModelBuilder, Constant_GScalar)
  121. {
  122. // in -> addC()-----(GMat)---->mulC()-----(GMat)---->unaryOp()----out
  123. // ^ ^
  124. // | |
  125. // 3-------` c_s-------'
  126. cv::GMat in;
  127. cv::GScalar c_s = 5;
  128. auto out = test::unaryOp((in + 3) * c_s); // 3 converted to GScalar
  129. ade::Graph g;
  130. cv::gimpl::GModel::Graph gm(g);
  131. cv::gimpl::GModel::init(gm);
  132. auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(out).m_args);
  133. cv::gimpl::Protocol p;
  134. std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
  135. auto in_nh = p.in_nhs.front();
  136. auto addC_nh = in_nh->outNodes().front();
  137. auto mulC_nh = addC_nh->outNodes().front()->outNodes().front();
  138. ASSERT_TRUE(gm.metadata(addC_nh).get<cv::gimpl::NodeType>().t == cv::gimpl::NodeType::OP);
  139. ASSERT_TRUE(gm.metadata(mulC_nh).get<cv::gimpl::NodeType>().t == cv::gimpl::NodeType::OP);
  140. auto s_3 = test::inputOf(gm, addC_nh, 1);
  141. auto s_5 = test::inputOf(gm, mulC_nh, 1);
  142. 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
  143. EXPECT_EQ(2u, static_cast<std::size_t>(addC_nh->inNodes().size())); // in and 3
  144. EXPECT_EQ(2u, static_cast<std::size_t>(mulC_nh->inNodes().size())); // addC output and c_s
  145. EXPECT_EQ(3, (util::get<cv::Scalar>(gm.metadata(s_3).get<cv::gimpl::ConstValue>().arg))[0]);
  146. EXPECT_EQ(5, (util::get<cv::Scalar>(gm.metadata(s_5).get<cv::gimpl::ConstValue>().arg))[0]);
  147. }
  148. TEST(GModelBuilder, Check_Multiple_Outputs)
  149. {
  150. // ------------------------------> r
  151. // '
  152. // ' -----------> i_out1
  153. // ' '
  154. // in ----> split3() ---> g ---> integral()
  155. // ' '
  156. // ' -----------> i_out2
  157. // '
  158. // '---------> b ---> unaryOp() ---> u_out
  159. cv::GMat in, r, g, b, i_out1, i_out2, u_out;
  160. std::tie(r, g, b) = cv::gapi::split3(in);
  161. std::tie(i_out1, i_out2) = cv::gapi::integral(g, 1, 1);
  162. u_out = test::unaryOp(b);
  163. ade::Graph gr;
  164. cv::gimpl::GModel::Graph gm(gr);
  165. cv::gimpl::GModel::init(gm);
  166. auto proto_slots = cv::gimpl::GModelBuilder(gr).put(cv::GIn(in).m_args, cv::GOut(r, i_out1, i_out2, u_out).m_args);
  167. cv::gimpl::Protocol p;
  168. std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
  169. EXPECT_EQ(4u, static_cast<std::size_t>(p.out_nhs.size()));
  170. EXPECT_EQ(0u, gm.metadata(p.out_nhs[0]->inEdges().front()).get<cv::gimpl::Output>().port);
  171. EXPECT_EQ(0u, gm.metadata(p.out_nhs[1]->inEdges().front()).get<cv::gimpl::Output>().port);
  172. EXPECT_EQ(1u, gm.metadata(p.out_nhs[2]->inEdges().front()).get<cv::gimpl::Output>().port);
  173. EXPECT_EQ(0u, gm.metadata(p.out_nhs[3]->inEdges().front()).get<cv::gimpl::Output>().port);
  174. for (const auto it : ade::util::indexed(p.out_nhs))
  175. {
  176. const auto& out_nh = ade::util::value(it);
  177. EXPECT_EQ(cv::gimpl::NodeType::DATA, gm.metadata(out_nh).get<cv::gimpl::NodeType>().t);
  178. EXPECT_EQ(GShape::GMAT, gm.metadata(out_nh).get<cv::gimpl::Data>().shape);
  179. }
  180. }
  181. TEST(GModelBuilder, Unused_Outputs)
  182. {
  183. cv::GMat in;
  184. auto yuv_p = cv::gapi::split3(in);
  185. ade::Graph g;
  186. cv::gimpl::GModel::Graph gm(g);
  187. cv::gimpl::GModel::init(gm);
  188. cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(std::get<0>(yuv_p)).m_args);
  189. EXPECT_EQ(5u, static_cast<std::size_t>(g.nodes().size())); // 1 input, 1 operation, 3 outputs
  190. }
  191. TEST(GModelBuilder, Work_With_One_Channel_From_Split3)
  192. {
  193. cv::GMat in, y, u, v;
  194. std::tie(y, u, v) = cv::gapi::split3(in);
  195. auto y_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
  196. ade::Graph g;
  197. cv::gimpl::GModel::Graph gm(g);
  198. cv::gimpl::GModel::init(gm);
  199. cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(y_blur).m_args);
  200. EXPECT_EQ(7u, static_cast<std::size_t>(g.nodes().size())); // 1 input, 2 operation, 3 nodes from split3, 1 output
  201. }
  202. TEST(GModelBuilder, Add_Nodes_To_Unused_Nodes)
  203. {
  204. cv::GMat in, y, u, v;
  205. std::tie(y, u, v) = cv::gapi::split3(in);
  206. auto y_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
  207. // unused nodes
  208. auto u_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
  209. auto v_blur = cv::gapi::gaussianBlur(y, cv::Size(3, 3), 1);
  210. ade::Graph g;
  211. cv::gimpl::GModel::Graph gm(g);
  212. cv::gimpl::GModel::init(gm);
  213. cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(y_blur).m_args);
  214. EXPECT_EQ(7u, static_cast<std::size_t>(g.nodes().size())); // 1 input, 2 operation, 3 nodes from split3, 1 output
  215. }
  216. TEST(GModelBuilder, Unlisted_Inputs)
  217. {
  218. // in1 -> binaryOp() -> out
  219. // ^
  220. // |
  221. // in2 ----'
  222. cv::GMat in1, in2;
  223. auto out = test::binaryOp(in1, in2);
  224. ade::Graph g;
  225. cv::gimpl::GModel::Graph gm(g);
  226. cv::gimpl::GModel::init(gm);
  227. // add required 2 inputs but pass 1
  228. EXPECT_THROW(cv::gimpl::GModelBuilder(g).put(cv::GIn(in1).m_args, cv::GOut(out).m_args), std::logic_error);
  229. }
  230. TEST(GModelBuilder, Unroll_No_Link_Between_In_And_Out)
  231. {
  232. // in -> unaryOp() -> u_op
  233. // other -> unaryOp() -> out
  234. cv::GMat in, other;
  235. auto u_op = test::unaryOp(in);
  236. auto out = test::unaryOp(other);
  237. EXPECT_THROW(cv::gimpl::unrollExpr(cv::GIn(in).m_args, cv::GOut(out).m_args), std::logic_error);
  238. }
  239. TEST(GModel_builder, Check_Binary_Op)
  240. {
  241. // in1 -> binaryOp() -> out
  242. // ^
  243. // |
  244. // in2 -----'
  245. cv::GMat in1, in2;
  246. auto out = test::binaryOp(in1, in2);
  247. ade::Graph g;
  248. cv::gimpl::GModel::Graph gm(g);
  249. cv::gimpl::GModel::init(gm);
  250. auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in1, in2).m_args, cv::GOut(out).m_args);
  251. cv::gimpl::Protocol p;
  252. std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
  253. auto ops = test::collectOperations(g);
  254. EXPECT_EQ(1u, ops.size());
  255. EXPECT_EQ("gapi.test.binaryOp", gm.metadata(ops.front()).get<cv::gimpl::Op>().k.name);
  256. EXPECT_EQ(2u, static_cast<std::size_t>(ops.front()->inEdges().size()));
  257. EXPECT_EQ(1u, static_cast<std::size_t>(ops.front()->outEdges().size()));
  258. EXPECT_EQ(1u, static_cast<std::size_t>(ops.front()->outNodes().size()));
  259. }
  260. TEST(GModelBuilder, Add_Operation_With_Two_Out_One_Time)
  261. {
  262. // in -> integral() --> out_b1 -> unaryOp() -> out1
  263. // |
  264. // '-------> out_b2 -> unaryOp() -> out2
  265. cv::GMat in, out_b1, out_b2;
  266. std::tie(out_b1, out_b2) = cv::gapi::integral(in, 1, 1);
  267. auto out1 = test::unaryOp(out_b1);
  268. auto out2 = test::unaryOp(out_b1);
  269. ade::Graph g;
  270. cv::gimpl::GModel::Graph gm(g);
  271. cv::gimpl::GModel::init(gm);
  272. auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in).m_args, cv::GOut(out1, out2).m_args);
  273. auto ops = test::collectOperations(gm);
  274. cv::gimpl::Protocol p;
  275. std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
  276. auto integral_nh = p.in_nhs.front()->outNodes().front();
  277. EXPECT_EQ(3u, ops.size());
  278. EXPECT_EQ("org.opencv.core.matrixop.integral", gm.metadata(integral_nh).get<cv::gimpl::Op>().k.name);
  279. EXPECT_EQ(1u, static_cast<std::size_t>(integral_nh->inEdges().size()));
  280. EXPECT_EQ(2u, static_cast<std::size_t>(integral_nh->outEdges().size()));
  281. EXPECT_EQ(2u, static_cast<std::size_t>(integral_nh->outNodes().size()));
  282. }
  283. TEST(GModelBuilder, Add_Operation_With_One_Out_One_Time)
  284. {
  285. // in1 -> binaryOp() -> b_out -> unaryOp() -> out1
  286. // ^ |
  287. // | |
  288. // in2 ------- '----> unaryOp() -> out2
  289. cv::GMat in1, in2;
  290. auto b_out = test::binaryOp(in1, in2);
  291. auto out1 = test::unaryOp(b_out);
  292. auto out2 = test::unaryOp(b_out);
  293. ade::Graph g;
  294. cv::gimpl::GModel::Graph gm(g);
  295. cv::gimpl::GModel::init(gm);
  296. auto proto_slots = cv::gimpl::GModelBuilder(g).put(cv::GIn(in1, in2).m_args, cv::GOut(out1, out2).m_args);
  297. cv::gimpl::Protocol p;
  298. std::tie(p.inputs, p.outputs, p.in_nhs, p.out_nhs) = proto_slots;
  299. cv::gimpl::GModel::Graph gr(g);
  300. auto binaryOp_nh = p.in_nhs.front()->outNodes().front();
  301. EXPECT_EQ(2u, static_cast<std::size_t>(binaryOp_nh->inEdges().size()));
  302. EXPECT_EQ(1u, static_cast<std::size_t>(binaryOp_nh->outEdges().size()));
  303. EXPECT_EQ(8u, static_cast<std::size_t>(g.nodes().size()));
  304. }
  305. } // namespace opencv_test