gapi_fluid_test.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  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 Intel Corporation
  6. #include "test_precomp.hpp"
  7. #include <opencv2/gapi/core.hpp>
  8. #include <opencv2/gapi/fluid/gfluidbuffer.hpp>
  9. #include <opencv2/gapi/fluid/gfluidkernel.hpp>
  10. // FIXME: move these tests with priv() to internal suite
  11. #include "backends/fluid/gfluidbuffer_priv.hpp"
  12. #include "gapi_fluid_test_kernels.hpp"
  13. #include "logger.hpp"
  14. namespace opencv_test
  15. {
  16. using namespace cv::gapi_test_kernels;
  17. namespace
  18. {
  19. void WriteFunction(uint8_t* row, int nr, int w) {
  20. for (int i = 0; i < w; i++)
  21. row[i] = static_cast<uint8_t>(nr+i);
  22. };
  23. void ReadFunction1x1(const uint8_t* row, int w) {
  24. for (int i = 0; i < w; i++)
  25. std::cout << std::setw(4) << static_cast<int>(row[i]) << " ";
  26. std::cout << "\n";
  27. };
  28. void ReadFunction3x3(const uint8_t* rows[3], int w) {
  29. for (int i = 0; i < 3; i++) {
  30. for (int j = -1; j < w+1; j++) {
  31. std::cout << std::setw(4) << static_cast<int>(rows[i][j]) << " ";
  32. }
  33. std::cout << "\n";
  34. }
  35. std::cout << "\n";
  36. };
  37. }
  38. TEST(FluidBuffer, InputTest)
  39. {
  40. const cv::Size buffer_size = {8,8};
  41. cv::Mat in_mat = cv::Mat::eye(buffer_size, CV_8U);
  42. cv::gapi::fluid::Buffer buffer(in_mat, true);
  43. cv::gapi::fluid::View view = buffer.mkView(0, false);
  44. view.priv().allocate(1, {});
  45. view.priv().reset(1);
  46. int this_y = 0;
  47. while (this_y < buffer_size.height)
  48. {
  49. view.priv().prepareToRead();
  50. const uint8_t* rrow = view.InLine<uint8_t>(0);
  51. ReadFunction1x1(rrow, buffer_size.width);
  52. view.priv().readDone(1,1);
  53. cv::Mat from_buffer(1, buffer_size.width, CV_8U, const_cast<uint8_t*>(rrow));
  54. EXPECT_EQ(0, cvtest::norm(in_mat.row(this_y), from_buffer, NORM_INF));
  55. this_y++;
  56. }
  57. }
  58. TEST(FluidBuffer, CircularTest)
  59. {
  60. const cv::Size buffer_size = {8,16};
  61. cv::gapi::fluid::Buffer buffer(cv::GMatDesc{CV_8U,1,buffer_size}, 3, 1, 0, 1,
  62. util::make_optional(cv::gapi::fluid::Border{cv::BORDER_CONSTANT, cv::Scalar(255)}));
  63. cv::gapi::fluid::View view = buffer.mkView(1, {});
  64. view.priv().reset(3);
  65. view.priv().allocate(3, {});
  66. buffer.debug(std::cout);
  67. const auto whole_line_is = [](const uint8_t *line, int len, int value)
  68. {
  69. return std::all_of(line, line+len, [&](const uint8_t v){return v == value;});
  70. };
  71. // Store all read/written data in separate Mats to compare with
  72. cv::Mat written_data(buffer_size, CV_8U);
  73. // Simulate write/read process
  74. int num_reads = 0, num_writes = 0;
  75. while (num_reads < buffer_size.height)
  76. {
  77. if (num_writes < buffer_size.height)
  78. {
  79. uint8_t* wrow = buffer.OutLine<uint8_t>();
  80. WriteFunction(wrow, num_writes, buffer_size.width);
  81. buffer.priv().writeDone();
  82. cv::Mat(1, buffer_size.width, CV_8U, wrow)
  83. .copyTo(written_data.row(num_writes));
  84. num_writes++;
  85. }
  86. buffer.debug(std::cout);
  87. if (view.ready())
  88. {
  89. view.priv().prepareToRead();
  90. const uint8_t* rrow[3] = {
  91. view.InLine<uint8_t>(-1),
  92. view.InLine<uint8_t>( 0),
  93. view.InLine<uint8_t>( 1),
  94. };
  95. ReadFunction3x3(rrow, buffer_size.width);
  96. view.priv().readDone(1,3);
  97. buffer.debug(std::cout);
  98. // Check borders right here
  99. EXPECT_EQ(255u, rrow[0][-1]);
  100. EXPECT_EQ(255u, rrow[0][buffer_size.width]);
  101. if (num_reads == 0)
  102. {
  103. EXPECT_TRUE(whole_line_is(rrow[0]-1, buffer_size.width+2, 255u));
  104. }
  105. if (num_reads == buffer_size.height-1)
  106. {
  107. EXPECT_TRUE(whole_line_is(rrow[2]-1, buffer_size.width+2, 255u));
  108. }
  109. // Check window (without borders)
  110. if (num_reads > 0 && num_reads < buffer_size.height-1)
  111. {
  112. // +1 everywhere since num_writes was just incremented above
  113. cv::Mat written_lastLine2 = written_data.row(num_writes - (2+1));
  114. cv::Mat written_lastLine1 = written_data.row(num_writes - (1+1));
  115. cv::Mat written_lastLine0 = written_data.row(num_writes - (0+1));
  116. cv::Mat read_prevLine(1, buffer_size.width, CV_8U, const_cast<uint8_t*>(rrow[0]));
  117. cv::Mat read_thisLine(1, buffer_size.width, CV_8U, const_cast<uint8_t*>(rrow[1]));
  118. cv::Mat read_nextLine(1, buffer_size.width, CV_8U, const_cast<uint8_t*>(rrow[2]));
  119. EXPECT_EQ(0, cvtest::norm(written_lastLine2, read_prevLine, NORM_INF));
  120. EXPECT_EQ(0, cvtest::norm(written_lastLine1, read_thisLine, NORM_INF));
  121. EXPECT_EQ(0, cvtest::norm(written_lastLine0, read_nextLine, NORM_INF));
  122. }
  123. num_reads++;
  124. }
  125. }
  126. }
  127. TEST(FluidBuffer, OutputTest)
  128. {
  129. const cv::Size buffer_size = {8,16};
  130. cv::Mat out_mat = cv::Mat(buffer_size, CV_8U);
  131. cv::gapi::fluid::Buffer buffer(out_mat, false);
  132. int num_writes = 0;
  133. while (num_writes < buffer_size.height)
  134. {
  135. uint8_t* wrow = buffer.OutLine<uint8_t>();
  136. WriteFunction(wrow, num_writes, buffer_size.width);
  137. buffer.priv().writeDone();
  138. num_writes++;
  139. }
  140. GAPI_LOG_INFO(NULL, "\n" << out_mat);
  141. // Validity check
  142. for (int r = 0; r < buffer_size.height; r++)
  143. {
  144. for (int c = 0; c < buffer_size.width; c++)
  145. {
  146. EXPECT_EQ(r+c, out_mat.at<uint8_t>(r, c));
  147. }
  148. }
  149. }
  150. TEST(Fluid, AddC_WithScalar)
  151. {
  152. cv::GMat in;
  153. cv::GScalar s;
  154. cv::GComputation c(cv::GIn(in, s), cv::GOut(TAddScalar::on(in, s)));
  155. cv::Mat in_mat = cv::Mat::eye(3, 3, CV_8UC1), out_mat(3, 3, CV_8UC1), ref_mat;
  156. cv::Scalar in_s(100);
  157. auto cc = c.compile(cv::descr_of(in_mat), cv::descr_of(in_s), cv::compile_args(fluidTestPackage));
  158. cc(cv::gin(in_mat, in_s), cv::gout(out_mat));
  159. ref_mat = in_mat + in_s;
  160. EXPECT_EQ(0, cvtest::norm(out_mat, ref_mat, NORM_INF));
  161. }
  162. TEST(Fluid, Scalar_In_Middle_Graph)
  163. {
  164. cv::GMat in;
  165. cv::GScalar s;
  166. cv::GComputation c(cv::GIn(in, s), cv::GOut(TAddScalar::on(TAddCSimple::on(in, 5), s)));
  167. cv::Mat in_mat = cv::Mat::eye(3, 3, CV_8UC1), out_mat(3, 3, CV_8UC1), ref_mat;
  168. cv::Scalar in_s(100);
  169. auto cc = c.compile(cv::descr_of(in_mat), cv::descr_of(in_s), cv::compile_args(fluidTestPackage));
  170. cc(cv::gin(in_mat, in_s), cv::gout(out_mat));
  171. ref_mat = (in_mat + 5) + in_s;
  172. EXPECT_EQ(0, cvtest::norm(out_mat, ref_mat, NORM_INF));
  173. }
  174. TEST(Fluid, Add_Scalar_To_Mat)
  175. {
  176. cv::GMat in;
  177. cv::GScalar s;
  178. cv::GComputation c(cv::GIn(s, in), cv::GOut(TAddScalarToMat::on(s, in)));
  179. cv::Mat in_mat = cv::Mat::eye(3, 3, CV_8UC1), out_mat(3, 3, CV_8UC1), ref_mat;
  180. cv::Scalar in_s(100);
  181. auto cc = c.compile(cv::descr_of(in_s), cv::descr_of(in_mat), cv::compile_args(fluidTestPackage));
  182. cc(cv::gin(in_s, in_mat), cv::gout(out_mat));
  183. ref_mat = in_mat + in_s;
  184. EXPECT_EQ(0, cvtest::norm(out_mat, ref_mat, NORM_INF));
  185. }
  186. TEST(Fluid, Sum_2_Mats_And_Scalar)
  187. {
  188. cv::GMat a, b;
  189. cv::GScalar s;
  190. cv::GComputation c(cv::GIn(a, s, b), cv::GOut(TSum2MatsAndScalar::on(a, s, b)));
  191. cv::Mat in_mat1 = cv::Mat::eye(3, 3, CV_8UC1),
  192. in_mat2 = cv::Mat::eye(3, 3, CV_8UC1),
  193. out_mat(3, 3, CV_8UC1),
  194. ref_mat;
  195. cv::Scalar in_s(100);
  196. auto cc = c.compile(cv::descr_of(in_mat1), cv::descr_of(in_s), cv::descr_of(in_mat2), cv::compile_args(fluidTestPackage));
  197. cc(cv::gin(in_mat1, in_s, in_mat2), cv::gout(out_mat));
  198. ref_mat = in_mat1 + in_mat2 + in_s;
  199. EXPECT_EQ(0, cvtest::norm(out_mat, ref_mat, NORM_INF));
  200. }
  201. TEST(Fluid, EqualizeHist)
  202. {
  203. cv::GMat in, out;
  204. cv::GComputation c(cv::GIn(in), cv::GOut(TEqualizeHist::on(in, TCalcHist::on(in))));
  205. cv::Mat in_mat(320, 480, CV_8UC1),
  206. out_mat(320, 480, CV_8UC1),
  207. ref_mat(320, 480, CV_8UC1);
  208. cv::randu(in_mat, 200, 240);
  209. auto cc = c.compile(cv::descr_of(in_mat), cv::compile_args(fluidTestPackage));
  210. cc(cv::gin(in_mat), cv::gout(out_mat));
  211. cv::equalizeHist(in_mat, ref_mat);
  212. EXPECT_EQ(0, cvtest::norm(out_mat, ref_mat, NORM_INF));
  213. }
  214. TEST(Fluid, Split3)
  215. {
  216. cv::GMat bgr;
  217. cv::GMat r,g,b;
  218. std::tie(b,g,r) = cv::gapi::split3(bgr);
  219. auto rr = TAddSimple::on(r, TId::on(b));
  220. auto rrr = TAddSimple::on(TId::on(rr), g);
  221. cv::GComputation c(bgr, TId::on(rrr));
  222. cv::Size sz(5120, 5120);
  223. cv::Mat eye_1 = cv::Mat::eye(sz, CV_8UC1);
  224. std::vector<cv::Mat> eyes = {eye_1, eye_1, eye_1};
  225. cv::Mat in_mat;
  226. cv::merge(eyes, in_mat);
  227. cv::Mat out_mat(sz, CV_8UC1);
  228. // G-API
  229. auto cc = c.compile(cv::descr_of(in_mat),
  230. cv::compile_args(fluidTestPackage));
  231. cc(in_mat, out_mat);
  232. // OCV
  233. std::vector<cv::Mat> chans;
  234. cv::split(in_mat, chans);
  235. // Compare
  236. EXPECT_EQ(0, cvtest::norm(out_mat, Mat(chans[2]*3), NORM_INF));
  237. }
  238. TEST(Fluid, ScratchTest)
  239. {
  240. cv::GMat in;
  241. cv::GMat out = TPlusRow0::on(TPlusRow0::on(in));
  242. cv::GComputation c(in, out);
  243. cv::Size sz(8, 8);
  244. cv::Mat in_mat = cv::Mat::eye(sz, CV_8UC1);
  245. cv::Mat out_mat(sz, CV_8UC1);
  246. // OpenCV (reference)
  247. cv::Mat ref;
  248. {
  249. cv::Mat first_row = cv::Mat::zeros(1, sz.width, CV_8U);
  250. cv::Mat remaining = cv::repeat(in_mat.row(0), sz.height-1, 1);
  251. cv::Mat operand;
  252. cv::vconcat(first_row, 2*remaining, operand);
  253. ref = in_mat + operand;
  254. }
  255. GAPI_LOG_INFO(NULL, "\n" << ref);
  256. // G-API
  257. auto cc = c.compile(cv::descr_of(in_mat),
  258. cv::compile_args(fluidTestPackage));
  259. cc(in_mat, out_mat);
  260. GAPI_LOG_INFO(NULL, "\n" << out_mat);
  261. EXPECT_EQ(0, cvtest::norm(ref, out_mat, NORM_INF));
  262. cc(in_mat, out_mat);
  263. GAPI_LOG_INFO(NULL, "\n" << out_mat);
  264. EXPECT_EQ(0, cvtest::norm(ref, out_mat, NORM_INF));
  265. }
  266. TEST(Fluid, MultipleOutRowsTest)
  267. {
  268. cv::GMat in;
  269. cv::GMat out = TAddCSimple::on(TAddCSimple::on(in, 1), 2);
  270. cv::GComputation c(in, out);
  271. cv::Size sz(4, 4);
  272. cv::Mat in_mat = cv::Mat::eye(sz, CV_8UC1);
  273. cv::Mat out_mat(sz, CV_8UC1);
  274. auto cc = c.compile(cv::descr_of(in_mat),
  275. cv::compile_args(fluidTestPackage));
  276. cc(in_mat, out_mat);
  277. std::cout << out_mat << std::endl;
  278. cv::Mat ocv_ref = in_mat + 1 + 2;
  279. EXPECT_EQ(0, cvtest::norm(ocv_ref, out_mat, NORM_INF));
  280. }
  281. TEST(Fluid, LPIWindow)
  282. {
  283. cv::GMat in;
  284. cv::GMat r,g,b;
  285. std::tie(r,g,b) = cv::gapi::split3(in);
  286. cv::GMat rr = TId7x7::on(r);
  287. cv::GMat tmp = TAddSimple::on(rr, g);
  288. cv::GMat out = TAddSimple::on(tmp, b);
  289. cv::GComputation c(in, out);
  290. cv::Size sz(8, 8);
  291. cv::Mat eye_1 = cv::Mat::eye(sz, CV_8UC1);
  292. std::vector<cv::Mat> eyes = {eye_1, eye_1, eye_1};
  293. cv::Mat in_mat;
  294. cv::merge(eyes, in_mat);
  295. cv::Mat out_mat(sz, CV_8U);
  296. auto cc = c.compile(cv::descr_of(in_mat), cv::compile_args(fluidTestPackage));
  297. cc(in_mat, out_mat);
  298. //std::cout << out_mat << std::endl;
  299. // OpenCV reference
  300. cv::Mat ocv_ref = eyes[0]+eyes[1]+eyes[2];
  301. EXPECT_EQ(0, cvtest::norm(ocv_ref, out_mat, NORM_INF));
  302. }
  303. TEST(Fluid, MultipleReaders_SameLatency)
  304. {
  305. // in -> AddC -> a -> AddC -> b -> Add -> out
  306. // '--> AddC -> c -'
  307. //
  308. // b and c have the same skew
  309. cv::GMat in;
  310. cv::GMat a = TAddCSimple::on(in, 1); // FIXME - align naming (G, non-G)
  311. cv::GMat b = TAddCSimple::on(a, 2);
  312. cv::GMat c = TAddCSimple::on(a, 3);
  313. cv::GMat out = TAddSimple::on(b, c);
  314. cv::GComputation comp(in, out);
  315. const auto sz = cv::Size(32, 32);
  316. cv::Mat in_mat = cv::Mat::eye(sz, CV_8UC1);
  317. cv::Mat out_mat_gapi(sz, CV_8UC1);
  318. cv::Mat out_mat_ocv (sz, CV_8UC1);
  319. // Run G-API
  320. auto cc = comp.compile(cv::descr_of(in_mat), cv::compile_args(fluidTestPackage));
  321. cc(in_mat, out_mat_gapi);
  322. // Check with OpenCV
  323. cv::Mat tmp = in_mat + 1;
  324. out_mat_ocv = (tmp+2) + (tmp+3);
  325. EXPECT_EQ(0, cvtest::norm(out_mat_gapi, out_mat_ocv, NORM_INF));
  326. }
  327. TEST(Fluid, MultipleReaders_DifferentLatency)
  328. {
  329. // in1 -> AddC -> a -> AddC -------------> b -> Add -> out
  330. // '--------------> Add --> c -'
  331. // '--> Id7x7-> d -'
  332. //
  333. // b and c have different skew (due to latency introduced by Id7x7)
  334. // a is ready by multiple views with different latency.
  335. cv::GMat in;
  336. cv::GMat a = TAddCSimple::on(in, 1); // FIXME - align naming (G, non-G)
  337. cv::GMat b = TAddCSimple::on(a, 2);
  338. cv::GMat d = TId7x7::on(a);
  339. cv::GMat c = TAddSimple::on(a, d);
  340. cv::GMat out = TAddSimple::on(b, c);
  341. cv::GComputation comp(in, out);
  342. const auto sz = cv::Size(32, 32);
  343. cv::Mat in_mat = cv::Mat::eye(sz, CV_8UC1);
  344. cv::Mat out_mat_gapi(sz, CV_8UC1);
  345. // Run G-API
  346. auto cc = comp.compile(cv::descr_of(in_mat), cv::compile_args(fluidTestPackage));
  347. cc(in_mat, out_mat_gapi);
  348. // Check with OpenCV
  349. cv::Mat ocv_a = in_mat + 1;
  350. cv::Mat ocv_b = ocv_a + 2;
  351. cv::Mat ocv_d = ocv_a;
  352. cv::Mat ocv_c = ocv_a + ocv_d;
  353. cv::Mat out_mat_ocv = ocv_b + ocv_c;
  354. EXPECT_EQ(0, cvtest::norm(out_mat_gapi, out_mat_ocv, NORM_INF));
  355. }
  356. TEST(Fluid, MultipleOutputs)
  357. {
  358. // in -> AddC -> a -> AddC ------------------> out1
  359. // `--> Id7x7 --> b --> AddC -> out2
  360. cv::GMat in;
  361. cv::GMat a = TAddCSimple::on(in, 1);
  362. cv::GMat b = TId7x7::on(a);
  363. cv::GMat out1 = TAddCSimple::on(a, 2);
  364. cv::GMat out2 = TAddCSimple::on(b, 7);
  365. cv::GComputation comp(cv::GIn(in), cv::GOut(out1, out2));
  366. const auto sz = cv::Size(32, 32);
  367. cv::Mat in_mat = cv::Mat::eye(sz, CV_8UC1);
  368. cv::Mat out_mat_gapi1(sz, CV_8UC1), out_mat_gapi2(sz, CV_8UC1);
  369. cv::Mat out_mat_ocv1(sz, CV_8UC1), out_mat_ocv2(sz, CV_8UC1);
  370. // Run G-API
  371. auto cc = comp.compile(cv::descr_of(in_mat), cv::compile_args(fluidTestPackage));
  372. cc(cv::gin(in_mat), cv::gout(out_mat_gapi1, out_mat_gapi2));
  373. // Check with OpenCV
  374. out_mat_ocv1 = in_mat + 1 + 2;
  375. out_mat_ocv2 = in_mat + 1 + 7;
  376. EXPECT_EQ(0, cvtest::norm(out_mat_gapi1, out_mat_ocv1, NORM_INF));
  377. EXPECT_EQ(0, cvtest::norm(out_mat_gapi2, out_mat_ocv2, NORM_INF));
  378. }
  379. TEST(Fluid, EmptyOutputMatTest)
  380. {
  381. cv::GMat in;
  382. cv::GMat out = TAddCSimple::on(in, 2);
  383. cv::GComputation c(in, out);
  384. cv::Mat in_mat = cv::Mat::eye(cv::Size(32, 24), CV_8UC1);
  385. cv::Mat out_mat;
  386. auto cc = c.compile(cv::descr_of(in_mat), cv::compile_args(fluidTestPackage));
  387. cc(in_mat, out_mat);
  388. EXPECT_EQ(CV_8UC1, out_mat.type());
  389. EXPECT_EQ(32, out_mat.cols);
  390. EXPECT_EQ(24, out_mat.rows);
  391. EXPECT_TRUE(out_mat.ptr() != nullptr);
  392. }
  393. struct LPISequenceTest : public TestWithParam<int>{};
  394. TEST_P(LPISequenceTest, LPISequenceTest)
  395. {
  396. // in -> AddC -> a -> Blur (2lpi) -> out
  397. int kernelSize = GetParam();
  398. cv::GMat in;
  399. cv::GMat a = TAddCSimple::on(in, 1);
  400. auto blur = kernelSize == 3 ? &TBlur3x3_2lpi::on : &TBlur5x5_2lpi::on;
  401. cv::GMat out = blur(a, cv::BORDER_CONSTANT, cv::Scalar(0));
  402. cv::GComputation comp(cv::GIn(in), cv::GOut(out));
  403. const auto sz = cv::Size(8, 10);
  404. cv::Mat in_mat = cv::Mat::eye(sz, CV_8UC1);
  405. cv::Mat out_mat_gapi(sz, CV_8UC1);
  406. cv::Mat out_mat_ocv(sz, CV_8UC1);
  407. // Run G-API
  408. auto cc = comp.compile(cv::descr_of(in_mat), cv::compile_args(fluidTestPackage));
  409. cc(cv::gin(in_mat), cv::gout(out_mat_gapi));
  410. // Check with OpenCV
  411. cv::blur(in_mat + 1, out_mat_ocv, {kernelSize,kernelSize}, {-1,-1}, cv::BORDER_CONSTANT);
  412. EXPECT_EQ(0, cvtest::norm(out_mat_gapi, out_mat_ocv, NORM_INF));
  413. }
  414. INSTANTIATE_TEST_CASE_P(Fluid, LPISequenceTest,
  415. Values(3, 5));
  416. struct InputImageBorderTest : public TestWithParam <std::tuple<int, int>> {};
  417. TEST_P(InputImageBorderTest, InputImageBorderTest)
  418. {
  419. cv::Size sz_in = { 320, 240 };
  420. int ks = 0;
  421. int borderType = 0;
  422. std::tie(ks, borderType) = GetParam();
  423. cv::Mat in_mat1(sz_in, CV_8UC1);
  424. cv::Scalar mean = cv::Scalar(127.0f);
  425. cv::Scalar stddev = cv::Scalar(40.f);
  426. cv::randn(in_mat1, mean, stddev);
  427. cv::Size kernelSize = {ks, ks};
  428. cv::Point anchor = {-1, -1};
  429. cv::Scalar borderValue(0);
  430. auto gblur = ks == 3 ? &TBlur3x3::on : &TBlur5x5::on;
  431. GMat in;
  432. auto out = gblur(in, borderType, borderValue);
  433. Mat out_mat_gapi = Mat::zeros(sz_in, CV_8UC1);
  434. GComputation c(GIn(in), GOut(out));
  435. auto cc = c.compile(descr_of(in_mat1), cv::compile_args(fluidTestPackage));
  436. cc(gin(in_mat1), gout(out_mat_gapi));
  437. cv::Mat out_mat_ocv = Mat::zeros(sz_in, CV_8UC1);
  438. cv::blur(in_mat1, out_mat_ocv, kernelSize, anchor, borderType);
  439. EXPECT_EQ(0, cvtest::norm(out_mat_ocv, out_mat_gapi, NORM_INF));
  440. }
  441. INSTANTIATE_TEST_CASE_P(Fluid, InputImageBorderTest,
  442. Combine(Values(3, 5),
  443. Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT_101)));
  444. struct SequenceOfBlursTest : public TestWithParam <std::tuple<int>> {};
  445. TEST_P(SequenceOfBlursTest, Test)
  446. {
  447. cv::Size sz_in = { 320, 240 };
  448. int borderType = 0;;
  449. std::tie(borderType) = GetParam();
  450. cv::Mat in_mat(sz_in, CV_8UC1);
  451. cv::Scalar mean = cv::Scalar(127.0f);
  452. cv::Scalar stddev = cv::Scalar(40.f);
  453. cv::randn(in_mat, mean, stddev);
  454. cv::Point anchor = {-1, -1};
  455. cv::Scalar borderValue(0);
  456. GMat in;
  457. auto mid = TBlur3x3::on(in, borderType, borderValue);
  458. auto out = TBlur5x5::on(mid, borderType, borderValue);
  459. Mat out_mat_gapi = Mat::zeros(sz_in, CV_8UC1);
  460. GComputation c(GIn(in), GOut(out));
  461. auto cc = c.compile(descr_of(in_mat), cv::compile_args(fluidTestPackage));
  462. cc(gin(in_mat), gout(out_mat_gapi));
  463. cv::Mat mid_mat_ocv = Mat::zeros(sz_in, CV_8UC1);
  464. cv::Mat out_mat_ocv = Mat::zeros(sz_in, CV_8UC1);
  465. cv::blur(in_mat, mid_mat_ocv, {3,3}, anchor, borderType);
  466. cv::blur(mid_mat_ocv, out_mat_ocv, {5,5}, anchor, borderType);
  467. EXPECT_EQ(0, cvtest::norm(out_mat_ocv, out_mat_gapi, NORM_INF));
  468. }
  469. INSTANTIATE_TEST_CASE_P(Fluid, SequenceOfBlursTest,
  470. Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT_101));
  471. struct TwoBlursTest : public TestWithParam <std::tuple<int, int, int, int, int, int, bool>> {};
  472. TEST_P(TwoBlursTest, Test)
  473. {
  474. cv::Size sz_in = { 320, 240 };
  475. int kernelSize1 = 0, kernelSize2 = 0;
  476. int borderType1 = -1, borderType2 = -1;
  477. cv::Scalar borderValue1{}, borderValue2{};
  478. bool readFromInput = false;
  479. std::tie(kernelSize1, borderType1, borderValue1, kernelSize2, borderType2, borderValue2, readFromInput) = GetParam();
  480. cv::Mat in_mat(sz_in, CV_8UC1);
  481. cv::Scalar mean = cv::Scalar(127.0f);
  482. cv::Scalar stddev = cv::Scalar(40.f);
  483. cv::randn(in_mat, mean, stddev);
  484. cv::Point anchor = {-1, -1};
  485. auto blur1 = kernelSize1 == 3 ? &TBlur3x3::on : TBlur5x5::on;
  486. auto blur2 = kernelSize2 == 3 ? &TBlur3x3::on : TBlur5x5::on;
  487. GMat in, out1, out2;
  488. if (readFromInput)
  489. {
  490. out1 = blur1(in, borderType1, borderValue1);
  491. out2 = blur2(in, borderType2, borderValue2);
  492. }
  493. else
  494. {
  495. auto mid = TAddCSimple::on(in, 0);
  496. out1 = blur1(mid, borderType1, borderValue1);
  497. out2 = blur2(mid, borderType2, borderValue2);
  498. }
  499. Mat out_mat_gapi1 = Mat::zeros(sz_in, CV_8UC1);
  500. Mat out_mat_gapi2 = Mat::zeros(sz_in, CV_8UC1);
  501. GComputation c(GIn(in), GOut(out1, out2));
  502. auto cc = c.compile(descr_of(in_mat), cv::compile_args(fluidTestPackage));
  503. cc(gin(in_mat), gout(out_mat_gapi1, out_mat_gapi2));
  504. cv::Mat out_mat_ocv1 = Mat::zeros(sz_in, CV_8UC1);
  505. cv::Mat out_mat_ocv2 = Mat::zeros(sz_in, CV_8UC1);
  506. cv::blur(in_mat, out_mat_ocv1, {kernelSize1, kernelSize1}, anchor, borderType1);
  507. cv::blur(in_mat, out_mat_ocv2, {kernelSize2, kernelSize2}, anchor, borderType2);
  508. EXPECT_EQ(0, cvtest::norm(out_mat_ocv1, out_mat_gapi1, NORM_INF));
  509. EXPECT_EQ(0, cvtest::norm(out_mat_ocv2, out_mat_gapi2, NORM_INF));
  510. }
  511. INSTANTIATE_TEST_CASE_P(Fluid, TwoBlursTest,
  512. Combine(Values(3, 5),
  513. Values(cv::BORDER_CONSTANT, cv::BORDER_REPLICATE, cv::BORDER_REFLECT_101),
  514. Values(0),
  515. Values(3, 5),
  516. Values(cv::BORDER_CONSTANT, cv::BORDER_REPLICATE, cv::BORDER_REFLECT_101),
  517. Values(0),
  518. testing::Bool())); // Read from input directly or place a copy node at start
  519. struct TwoReadersTest : public TestWithParam <std::tuple<int, int, int, bool>> {};
  520. TEST_P(TwoReadersTest, Test)
  521. {
  522. cv::Size sz_in = { 320, 240 };
  523. int kernelSize = 0;
  524. int borderType = -1;
  525. cv::Scalar borderValue;
  526. bool readFromInput = false;
  527. std::tie(kernelSize, borderType, borderValue, readFromInput) = GetParam();
  528. cv::Mat in_mat(sz_in, CV_8UC1);
  529. cv::Scalar mean = cv::Scalar(127.0f);
  530. cv::Scalar stddev = cv::Scalar(40.f);
  531. cv::randn(in_mat, mean, stddev);
  532. cv::Point anchor = {-1, -1};
  533. auto blur = kernelSize == 3 ? &TBlur3x3::on : TBlur5x5::on;
  534. GMat in, out1, out2;
  535. if (readFromInput)
  536. {
  537. out1 = TAddCSimple::on(in, 0);
  538. out2 = blur(in, borderType, borderValue);
  539. }
  540. else
  541. {
  542. auto mid = TAddCSimple::on(in, 0);
  543. out1 = TAddCSimple::on(mid, 0);
  544. out2 = blur(mid, borderType, borderValue);
  545. }
  546. Mat out_mat_gapi1 = Mat::zeros(sz_in, CV_8UC1);
  547. Mat out_mat_gapi2 = Mat::zeros(sz_in, CV_8UC1);
  548. GComputation c(GIn(in), GOut(out1, out2));
  549. auto cc = c.compile(descr_of(in_mat), cv::compile_args(fluidTestPackage));
  550. cc(gin(in_mat), gout(out_mat_gapi1, out_mat_gapi2));
  551. cv::Mat out_mat_ocv1 = Mat::zeros(sz_in, CV_8UC1);
  552. cv::Mat out_mat_ocv2 = Mat::zeros(sz_in, CV_8UC1);
  553. out_mat_ocv1 = in_mat;
  554. cv::blur(in_mat, out_mat_ocv2, {kernelSize, kernelSize}, anchor, borderType);
  555. EXPECT_EQ(0, cvtest::norm(out_mat_ocv1, out_mat_gapi1, NORM_INF));
  556. EXPECT_EQ(0, cvtest::norm(out_mat_ocv2, out_mat_gapi2, NORM_INF));
  557. }
  558. INSTANTIATE_TEST_CASE_P(Fluid, TwoReadersTest,
  559. Combine(Values(3, 5),
  560. Values(cv::BORDER_CONSTANT, cv::BORDER_REPLICATE, cv::BORDER_REFLECT_101),
  561. Values(0),
  562. testing::Bool())); // Read from input directly or place a copy node at start
  563. TEST(FluidTwoIslands, SanityTest)
  564. {
  565. cv::Size sz_in{8,8};
  566. GMat in1, in2;
  567. auto out1 = TAddScalar::on(in1, {0});
  568. auto out2 = TAddScalar::on(in2, {0});
  569. cv::Mat in_mat1(sz_in, CV_8UC1);
  570. cv::Mat in_mat2(sz_in, CV_8UC1);
  571. cv::Scalar mean = cv::Scalar(127.0f);
  572. cv::Scalar stddev = cv::Scalar(40.f);
  573. cv::randn(in_mat1, mean, stddev);
  574. cv::randn(in_mat2, mean, stddev);
  575. Mat out_mat1 = Mat::zeros(sz_in, CV_8UC1);
  576. Mat out_mat2 = Mat::zeros(sz_in, CV_8UC1);
  577. GComputation c(GIn(in1, in2), GOut(out1, out2));
  578. EXPECT_NO_THROW(c.apply(gin(in_mat1, in_mat2), gout(out_mat1, out_mat2), cv::compile_args(fluidTestPackage)));
  579. EXPECT_EQ(0, cvtest::norm(in_mat1, out_mat1, NORM_INF));
  580. EXPECT_EQ(0, cvtest::norm(in_mat2, out_mat2, NORM_INF));
  581. }
  582. struct NV12RoiTest : public TestWithParam <std::pair<cv::Size, cv::Rect>> {};
  583. TEST_P(NV12RoiTest, Test)
  584. {
  585. cv::Size y_sz;
  586. cv::Rect roi;
  587. std::tie(y_sz, roi) = GetParam();
  588. cv::Size uv_sz(y_sz.width / 2, y_sz.height / 2);
  589. cv::Size in_sz(y_sz.width, y_sz.height*3/2);
  590. cv::Mat in_mat = cv::Mat(in_sz, CV_8UC1);
  591. cv::Scalar mean = cv::Scalar(127.0f);
  592. cv::Scalar stddev = cv::Scalar(40.f);
  593. cv::randn(in_mat, mean, stddev);
  594. cv::Mat y_mat = cv::Mat(y_sz, CV_8UC1, in_mat.data);
  595. cv::Mat uv_mat = cv::Mat(uv_sz, CV_8UC2, in_mat.data + in_mat.step1() * y_sz.height);
  596. cv::Mat out_mat, out_mat_ocv;
  597. cv::GMat y, uv;
  598. auto rgb = cv::gapi::NV12toRGB(y, uv);
  599. cv::GComputation c(cv::GIn(y, uv), cv::GOut(rgb));
  600. c.apply(cv::gin(y_mat, uv_mat), cv::gout(out_mat), cv::compile_args(fluidTestPackage, cv::GFluidOutputRois{{roi}}));
  601. cv::cvtColor(in_mat, out_mat_ocv, cv::COLOR_YUV2RGB_NV12);
  602. EXPECT_EQ(0, cvtest::norm(out_mat(roi), out_mat_ocv(roi), NORM_INF));
  603. }
  604. INSTANTIATE_TEST_CASE_P(Fluid, NV12RoiTest,
  605. Values(std::make_pair(cv::Size{8, 8}, cv::Rect{0, 0, 8, 2})
  606. ,std::make_pair(cv::Size{8, 8}, cv::Rect{0, 2, 8, 2})
  607. ,std::make_pair(cv::Size{8, 8}, cv::Rect{0, 4, 8, 2})
  608. ,std::make_pair(cv::Size{8, 8}, cv::Rect{0, 6, 8, 2})
  609. ,std::make_pair(cv::Size{1920, 1080}, cv::Rect{0, 0, 1920, 270})
  610. ,std::make_pair(cv::Size{1920, 1080}, cv::Rect{0, 270, 1920, 270})
  611. ,std::make_pair(cv::Size{1920, 1080}, cv::Rect{0, 540, 1920, 270})
  612. ,std::make_pair(cv::Size{1920, 1080}, cv::Rect{0, 710, 1920, 270})
  613. ));
  614. TEST(Fluid, UnusedNodeOutputCompileTest)
  615. {
  616. cv::GMat in;
  617. cv::GMat a, b, c, d;
  618. std::tie(a, b, c, d) = cv::gapi::split4(in);
  619. cv::GMat out = cv::gapi::merge3(a, b, c);
  620. cv::Mat in_mat(cv::Size(8, 8), CV_8UC4);
  621. cv::Mat out_mat(cv::Size(8, 8), CV_8UC3);
  622. cv::GComputation comp(cv::GIn(in), cv::GOut(out));
  623. ASSERT_NO_THROW(comp.apply(cv::gin(in_mat), cv::gout(out_mat),
  624. cv::compile_args(cv::gapi::core::fluid::kernels())));
  625. }
  626. TEST(Fluid, UnusedNodeOutputReshapeTest)
  627. {
  628. const auto test_size = cv::Size(8, 8);
  629. const auto get_compile_args = [] () {
  630. return cv::compile_args(
  631. cv::gapi::combine(
  632. cv::gapi::core::fluid::kernels(),
  633. cv::gapi::imgproc::fluid::kernels()
  634. )
  635. );
  636. };
  637. cv::GMat in;
  638. cv::GMat a, b, c, d;
  639. std::tie(a, b, c, d) = cv::gapi::split4(in);
  640. cv::GMat out = cv::gapi::resize(cv::gapi::merge3(a, b, c), test_size, 0.0, 0.0,
  641. cv::INTER_LINEAR);
  642. cv::GComputation comp(cv::GIn(in), cv::GOut(out));
  643. cv::Mat in_mat(test_size, CV_8UC4);
  644. cv::Mat out_mat(test_size, CV_8UC3);
  645. cv::GCompiled compiled;
  646. ASSERT_NO_THROW(compiled = comp.compile(descr_of(in_mat), get_compile_args()));
  647. in_mat = cv::Mat(test_size * 2, CV_8UC4);
  648. ASSERT_TRUE(compiled.canReshape());
  649. ASSERT_NO_THROW(compiled.reshape(descr_of(gin(in_mat)), get_compile_args()));
  650. ASSERT_NO_THROW(compiled(in_mat, out_mat));
  651. }
  652. TEST(Fluid, InvalidROIs)
  653. {
  654. cv::GMat in;
  655. cv::GMat out = cv::gapi::add(in, in);
  656. cv::Mat in_mat(cv::Size(8, 8), CV_8UC3);
  657. cv::Mat out_mat = in_mat.clone();
  658. cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar::all(100));
  659. std::vector<cv::Rect> invalid_rois =
  660. {
  661. cv::Rect(1, 0, 0, 0),
  662. cv::Rect(0, 1, 0, 0),
  663. cv::Rect(0, 0, 1, 0),
  664. cv::Rect(0, 0, 0, 1),
  665. cv::Rect(0, 0, out_mat.cols, 0),
  666. cv::Rect(0, 0, 0, out_mat.rows),
  667. cv::Rect(0, out_mat.rows, out_mat.cols, out_mat.rows),
  668. cv::Rect(out_mat.cols, 0, out_mat.cols, out_mat.rows),
  669. };
  670. const auto compile_args = [] (cv::Rect roi) {
  671. return cv::compile_args(cv::gapi::core::fluid::kernels(), GFluidOutputRois{{roi}});
  672. };
  673. for (const auto& roi : invalid_rois)
  674. {
  675. cv::GComputation comp(cv::GIn(in), cv::GOut(out));
  676. EXPECT_THROW(comp.apply(cv::gin(in_mat), cv::gout(out_mat), compile_args(roi)),
  677. std::exception);
  678. }
  679. }
  680. namespace
  681. {
  682. #if defined(__linux__)
  683. uint64_t currMemoryConsumption()
  684. {
  685. // check self-state via /proc information
  686. constexpr const char stat_file_path[] = "/proc/self/statm";
  687. std::ifstream proc_stat(stat_file_path);
  688. if (!proc_stat.is_open() || !proc_stat.good())
  689. {
  690. CV_LOG_WARNING(NULL, "Failed to open stat file: " << stat_file_path);
  691. return static_cast<uint64_t>(0);
  692. }
  693. std::string stat_line;
  694. std::getline(proc_stat, stat_line);
  695. uint64_t unused, data_and_stack;
  696. std::istringstream(stat_line) >> unused >> unused >> unused >> unused >> unused
  697. >> data_and_stack;
  698. CV_Assert(data_and_stack != 0);
  699. return data_and_stack;
  700. }
  701. #else
  702. // FIXME: implement this part (at least for Windows?), right now it's enough to check Linux only
  703. uint64_t currMemoryConsumption() { return static_cast<uint64_t>(0); }
  704. #endif
  705. } // anonymous namespace
  706. TEST(Fluid, MemoryConsumptionDoesNotGrowOnReshape)
  707. {
  708. cv::GMat in;
  709. cv::GMat a, b, c;
  710. std::tie(a, b, c) = cv::gapi::split3(in);
  711. cv::GMat merged = cv::gapi::merge4(a, b, c, a);
  712. cv::GMat d, e, f, g;
  713. std::tie(d, e, f, g) = cv::gapi::split4(merged);
  714. cv::GMat out = cv::gapi::merge3(d, e, f);
  715. cv::Mat in_mat(cv::Size(8, 8), CV_8UC3);
  716. cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar::all(100));
  717. cv::Mat out_mat;
  718. const auto compile_args = [] () {
  719. return cv::compile_args(cv::gapi::core::fluid::kernels());
  720. };
  721. cv::GCompiled compiled = cv::GComputation(cv::GIn(in), cv::GOut(out)).compile(
  722. cv::descr_of(in_mat), compile_args());
  723. ASSERT_TRUE(compiled.canReshape());
  724. const auto mem_before = currMemoryConsumption();
  725. for (int _ = 0; _ < 1000; ++_) compiled.reshape(cv::descr_of(cv::gin(in_mat)), compile_args());
  726. const auto mem_after = currMemoryConsumption();
  727. ASSERT_GE(mem_before, mem_after);
  728. }
  729. } // namespace opencv_test