gapi_streaming_tests.cpp 83 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685
  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) 2019-2021 Intel Corporation
  6. #include "../test_precomp.hpp"
  7. #include "../common/gapi_streaming_tests_common.hpp"
  8. #include <thread> // sleep_for (Delay)
  9. #include <opencv2/gapi/cpu/core.hpp>
  10. #include <opencv2/gapi/cpu/imgproc.hpp>
  11. #include <opencv2/gapi/fluid/core.hpp>
  12. #include <opencv2/gapi/fluid/imgproc.hpp>
  13. #include <opencv2/gapi/fluid/gfluidkernel.hpp>
  14. #include <opencv2/gapi/ocl/core.hpp>
  15. #include <opencv2/gapi/ocl/imgproc.hpp>
  16. #include <opencv2/gapi/streaming/cap.hpp>
  17. #include <opencv2/gapi/streaming/desync.hpp>
  18. #include <opencv2/gapi/streaming/format.hpp>
  19. #include <opencv2/gapi/gstreaming.hpp>
  20. namespace opencv_test
  21. {
  22. namespace
  23. {
  24. enum class KernelPackage: int
  25. {
  26. OCV,
  27. OCV_FLUID,
  28. OCL,
  29. OCL_FLUID,
  30. };
  31. std::ostream& operator<< (std::ostream &os, const KernelPackage &e)
  32. {
  33. switch (e)
  34. {
  35. #define _C(X) case KernelPackage::X: os << #X; break
  36. _C(OCV);
  37. _C(OCV_FLUID);
  38. _C(OCL);
  39. _C(OCL_FLUID);
  40. #undef _C
  41. default: GAPI_Error("InternalError");
  42. }
  43. return os;
  44. }
  45. struct GAPI_Streaming: public ::testing::TestWithParam<std::tuple<KernelPackage,
  46. cv::optional<size_t>>> {
  47. GAPI_Streaming() {
  48. KernelPackage pkg_kind;
  49. std::tie(pkg_kind, cap) = GetParam();
  50. pkg = getKernelPackage(pkg_kind);
  51. }
  52. const cv::optional<size_t>& getQueueCapacity()
  53. {
  54. return cap;
  55. }
  56. cv::GKernelPackage getKernelPackage(KernelPackage pkg_kind)
  57. {
  58. using namespace cv::gapi;
  59. switch (pkg_kind)
  60. {
  61. case KernelPackage::OCV:
  62. return cv::gapi::combine(core::cpu::kernels(),
  63. imgproc::cpu::kernels());
  64. break;
  65. case KernelPackage::OCV_FLUID:
  66. return cv::gapi::combine(core::cpu::kernels(),
  67. imgproc::cpu::kernels(),
  68. core::fluid::kernels());
  69. break;
  70. // FIXME: OpenCL backend seem to work fine with Streaming
  71. // however the results are not very bit exact with CPU
  72. // It may be a problem but may be just implementation innacuracy.
  73. // Need to customize the comparison function in tests where OpenCL
  74. // is involved.
  75. case KernelPackage::OCL:
  76. return cv::gapi::combine(core::ocl::kernels(),
  77. imgproc::ocl::kernels());
  78. break;
  79. case KernelPackage::OCL_FLUID:
  80. return cv::gapi::combine(core::ocl::kernels(),
  81. imgproc::ocl::kernels(),
  82. core::fluid::kernels());
  83. break;
  84. }
  85. throw std::logic_error("Unknown package");
  86. }
  87. cv::GCompileArgs getCompileArgs() {
  88. using namespace cv::gapi;
  89. auto args = cv::compile_args(use_only{pkg});
  90. if (cap) {
  91. args += cv::compile_args(cv::gapi::streaming::queue_capacity{cap.value()});
  92. }
  93. return args;
  94. }
  95. cv::GKernelPackage pkg;
  96. cv::optional<size_t> cap;
  97. };
  98. G_API_OP(Delay, <cv::GMat(cv::GMat, int)>, "org.opencv.test.delay") {
  99. static cv::GMatDesc outMeta(const cv::GMatDesc &in, int) { return in; }
  100. };
  101. GAPI_OCV_KERNEL(OCVDelay, Delay) {
  102. static void run(const cv::Mat &in, int ms, cv::Mat &out) {
  103. std::this_thread::sleep_for(std::chrono::milliseconds{ms});
  104. in.copyTo(out);
  105. }
  106. };
  107. class TestMediaBGR final: public cv::MediaFrame::IAdapter {
  108. cv::Mat m_mat;
  109. using Cb = cv::MediaFrame::View::Callback;
  110. Cb m_cb;
  111. public:
  112. explicit TestMediaBGR(cv::Mat m, Cb cb = [](){})
  113. : m_mat(m), m_cb(cb) {
  114. }
  115. cv::GFrameDesc meta() const override {
  116. return cv::GFrameDesc{cv::MediaFormat::BGR, cv::Size(m_mat.cols, m_mat.rows)};
  117. }
  118. cv::MediaFrame::View access(cv::MediaFrame::Access) override {
  119. cv::MediaFrame::View::Ptrs pp = { m_mat.ptr(), nullptr, nullptr, nullptr };
  120. cv::MediaFrame::View::Strides ss = { m_mat.step, 0u, 0u, 0u };
  121. return cv::MediaFrame::View(std::move(pp), std::move(ss), Cb{m_cb});
  122. }
  123. };
  124. class TestMediaNV12 final: public cv::MediaFrame::IAdapter {
  125. cv::Mat m_y;
  126. cv::Mat m_uv;
  127. public:
  128. TestMediaNV12(cv::Mat y, cv::Mat uv) : m_y(y), m_uv(uv) {
  129. }
  130. cv::GFrameDesc meta() const override {
  131. return cv::GFrameDesc{cv::MediaFormat::NV12, m_y.size()};
  132. }
  133. cv::MediaFrame::View access(cv::MediaFrame::Access) override {
  134. cv::MediaFrame::View::Ptrs pp = {
  135. m_y.ptr(), m_uv.ptr(), nullptr, nullptr
  136. };
  137. cv::MediaFrame::View::Strides ss = {
  138. m_y.step, m_uv.step, 0u, 0u
  139. };
  140. return cv::MediaFrame::View(std::move(pp), std::move(ss));
  141. }
  142. };
  143. class TestMediaGRAY final : public cv::MediaFrame::IAdapter {
  144. cv::Mat m_mat;
  145. using Cb = cv::MediaFrame::View::Callback;
  146. Cb m_cb;
  147. public:
  148. explicit TestMediaGRAY(cv::Mat m, Cb cb = []() {})
  149. : m_mat(m), m_cb(cb) {
  150. }
  151. cv::GFrameDesc meta() const override {
  152. return cv::GFrameDesc{ cv::MediaFormat::GRAY, cv::Size(m_mat.cols, m_mat.rows) };
  153. }
  154. cv::MediaFrame::View access(cv::MediaFrame::Access) override {
  155. cv::MediaFrame::View::Ptrs pp = { m_mat.ptr(), nullptr, nullptr, nullptr };
  156. cv::MediaFrame::View::Strides ss = { m_mat.step, 0u, 0u, 0u };
  157. return cv::MediaFrame::View(std::move(pp), std::move(ss), Cb{ m_cb });
  158. }
  159. };
  160. class BGRSource : public cv::gapi::wip::GCaptureSource {
  161. public:
  162. explicit BGRSource(const std::string& pipeline)
  163. : cv::gapi::wip::GCaptureSource(pipeline) {
  164. }
  165. bool pull(cv::gapi::wip::Data& data) override {
  166. if (cv::gapi::wip::GCaptureSource::pull(data)) {
  167. data = cv::MediaFrame::Create<TestMediaBGR>(cv::util::get<cv::Mat>(data));
  168. return true;
  169. }
  170. return false;
  171. }
  172. GMetaArg descr_of() const override {
  173. return cv::GMetaArg{cv::GFrameDesc{cv::MediaFormat::BGR,
  174. cv::util::get<cv::GMatDesc>(
  175. cv::gapi::wip::GCaptureSource::descr_of()).size}};
  176. }
  177. };
  178. void cvtBGR2NV12(const cv::Mat& bgr, cv::Mat& y, cv::Mat& uv) {
  179. cv::Size frame_sz = bgr.size();
  180. cv::Size half_sz = frame_sz / 2;
  181. cv::Mat yuv;
  182. cv::cvtColor(bgr, yuv, cv::COLOR_BGR2YUV_I420);
  183. // Copy Y plane
  184. yuv.rowRange(0, frame_sz.height).copyTo(y);
  185. // Merge sampled U and V planes
  186. std::vector<int> dims = {half_sz.height, half_sz.width};
  187. auto start = frame_sz.height;
  188. auto range_h = half_sz.height/2;
  189. std::vector<cv::Mat> uv_planes = {
  190. yuv.rowRange(start, start + range_h) .reshape(0, dims),
  191. yuv.rowRange(start + range_h, start + range_h*2).reshape(0, dims)
  192. };
  193. cv::merge(uv_planes, uv);
  194. }
  195. class NV12Source : public cv::gapi::wip::GCaptureSource {
  196. public:
  197. explicit NV12Source(const std::string& pipeline)
  198. : cv::gapi::wip::GCaptureSource(pipeline) {
  199. }
  200. bool pull(cv::gapi::wip::Data& data) override {
  201. if (cv::gapi::wip::GCaptureSource::pull(data)) {
  202. cv::Mat bgr = cv::util::get<cv::Mat>(data);
  203. cv::Mat y, uv;
  204. cvtBGR2NV12(bgr, y, uv);
  205. data = cv::MediaFrame::Create<TestMediaNV12>(y, uv);
  206. return true;
  207. }
  208. return false;
  209. }
  210. GMetaArg descr_of() const override {
  211. return cv::GMetaArg{cv::GFrameDesc{cv::MediaFormat::NV12,
  212. cv::util::get<cv::GMatDesc>(
  213. cv::gapi::wip::GCaptureSource::descr_of()).size}};
  214. }
  215. };
  216. class GRAYSource : public cv::gapi::wip::GCaptureSource {
  217. public:
  218. explicit GRAYSource(const std::string& pipeline)
  219. : cv::gapi::wip::GCaptureSource(pipeline) {
  220. }
  221. bool pull(cv::gapi::wip::Data& data) override {
  222. if (cv::gapi::wip::GCaptureSource::pull(data)) {
  223. cv::Mat bgr = cv::util::get<cv::Mat>(data);
  224. cv::Mat gray;
  225. cvtColor(bgr, gray, cv::COLOR_BGR2GRAY);
  226. data = cv::MediaFrame::Create<TestMediaGRAY>(gray);
  227. return true;
  228. }
  229. return false;
  230. }
  231. GMetaArg descr_of() const override {
  232. return cv::GMetaArg{ cv::GFrameDesc{cv::MediaFormat::GRAY,
  233. cv::util::get<cv::GMatDesc>(
  234. cv::gapi::wip::GCaptureSource::descr_of()).size} };
  235. }
  236. };
  237. void checkPullOverload(const cv::Mat& ref,
  238. const bool has_output,
  239. cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>& args) {
  240. EXPECT_TRUE(has_output);
  241. using runArgs = cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>;
  242. cv::Mat out_mat;
  243. switch (args.index()) {
  244. case runArgs::index_of<cv::GRunArgs>():
  245. {
  246. auto outputs = util::get<cv::GRunArgs>(args);
  247. EXPECT_EQ(1u, outputs.size());
  248. out_mat = cv::util::get<cv::Mat>(outputs[0]);
  249. break;
  250. }
  251. case runArgs::index_of<cv::GOptRunArgs>():
  252. {
  253. auto outputs = util::get<cv::GOptRunArgs>(args);
  254. EXPECT_EQ(1u, outputs.size());
  255. auto opt_mat = cv::util::get<cv::optional<cv::Mat>>(outputs[0]);
  256. ASSERT_TRUE(opt_mat.has_value());
  257. out_mat = *opt_mat;
  258. break;
  259. }
  260. default: GAPI_Error("Incorrect type of Args");
  261. }
  262. EXPECT_EQ(0., cv::norm(ref, out_mat, cv::NORM_INF));
  263. }
  264. class InvalidSource : public cv::gapi::wip::IStreamSource {
  265. public:
  266. InvalidSource(const size_t throw_every_nth_frame,
  267. const size_t num_frames)
  268. : m_throw_every_nth_frame(throw_every_nth_frame),
  269. m_curr_frame_id(0u),
  270. m_num_frames(num_frames),
  271. m_mat(1, 1, CV_8U) {
  272. }
  273. static std::string exception_msg()
  274. {
  275. return "InvalidSource successfully failed!";
  276. }
  277. bool pull(cv::gapi::wip::Data& d) override {
  278. ++m_curr_frame_id;
  279. if (m_curr_frame_id > m_num_frames) {
  280. return false;
  281. }
  282. if (m_curr_frame_id % m_throw_every_nth_frame == 0) {
  283. throw std::logic_error(InvalidSource::exception_msg());
  284. } else {
  285. d = cv::Mat(m_mat);
  286. }
  287. return true;
  288. }
  289. cv::GMetaArg descr_of() const override {
  290. return cv::GMetaArg{cv::descr_of(m_mat)};
  291. }
  292. private:
  293. size_t m_throw_every_nth_frame;
  294. size_t m_curr_frame_id;
  295. size_t m_num_frames;
  296. cv::Mat m_mat;
  297. };
  298. G_TYPED_KERNEL(GThrowExceptionOp, <GMat(GMat)>, "org.opencv.test.throw_error_op")
  299. {
  300. static GMatDesc outMeta(GMatDesc in) { return in; }
  301. };
  302. GAPI_OCV_KERNEL(GThrowExceptionKernel, GThrowExceptionOp)
  303. {
  304. static std::string exception_msg()
  305. {
  306. return "GThrowExceptionKernel successfully failed";
  307. }
  308. static void run(const cv::Mat&, cv::Mat&)
  309. {
  310. throw std::logic_error(GThrowExceptionKernel::exception_msg());
  311. }
  312. };
  313. } // anonymous namespace
  314. TEST_P(GAPI_Streaming, SmokeTest_ConstInput_GMat)
  315. {
  316. // This graph models the following use-case:
  317. // Canny here is used as some "feature detector"
  318. //
  319. // Island/device layout may be different given the contents
  320. // of the passed kernel package.
  321. //
  322. // The expectation is that we get as much islands in the
  323. // graph as backends the GKernelPackage contains.
  324. //
  325. // [Capture] --> Crop --> Resize --> Canny --> [out]
  326. const auto crop_rc = cv::Rect(13, 75, 377, 269);
  327. const auto resample_sz = cv::Size(224, 224);
  328. const auto thr_lo = 64.;
  329. const auto thr_hi = 192.;
  330. cv::GMat in;
  331. auto roi = cv::gapi::crop(in, crop_rc);
  332. auto res = cv::gapi::resize(roi, resample_sz);
  333. auto out = cv::gapi::Canny(res, thr_lo, thr_hi);
  334. cv::GComputation c(in, out);
  335. // Input data
  336. cv::Mat in_mat = cv::imread(findDataFile("cv/edgefilter/kodim23.png"));
  337. cv::Mat out_mat_gapi;
  338. // OpenCV reference image
  339. cv::Mat out_mat_ocv;
  340. {
  341. cv::Mat tmp;
  342. cv::resize(in_mat(crop_rc), tmp, resample_sz);
  343. cv::Canny(tmp, out_mat_ocv, thr_lo, thr_hi);
  344. }
  345. // Compilation & testing
  346. auto ccomp = c.compileStreaming(cv::descr_of(in_mat), getCompileArgs());
  347. EXPECT_TRUE(ccomp);
  348. EXPECT_FALSE(ccomp.running());
  349. ccomp.setSource(cv::gin(in_mat));
  350. ccomp.start();
  351. EXPECT_TRUE(ccomp.running());
  352. // Fetch the result 15 times
  353. for (int i = 0; i < 15; i++) {
  354. // With constant inputs, the stream is endless so
  355. // the blocking pull() should never return `false`.
  356. EXPECT_TRUE(ccomp.pull(cv::gout(out_mat_gapi)));
  357. // Fluid's and OpenCV's Resizes aren't bit exact.
  358. // So 1% is here because it is max difference between them.
  359. EXPECT_TRUE(AbsSimilarPoints(0, 1).to_compare_f()(out_mat_gapi, out_mat_ocv));
  360. }
  361. EXPECT_TRUE(ccomp.running());
  362. ccomp.stop();
  363. EXPECT_FALSE(ccomp.running());
  364. }
  365. TEST_P(GAPI_Streaming, SmokeTest_VideoInput_GMat)
  366. {
  367. const auto crop_rc = cv::Rect(13, 75, 377, 269);
  368. const auto resample_sz = cv::Size(224, 224);
  369. const auto thr_lo = 64.;
  370. const auto thr_hi = 192.;
  371. cv::GMat in;
  372. auto roi = cv::gapi::crop(in, crop_rc);
  373. auto res = cv::gapi::resize(roi, resample_sz);
  374. auto out = cv::gapi::Canny(res, thr_lo, thr_hi);
  375. cv::GComputation c(cv::GIn(in), cv::GOut(cv::gapi::copy(in), out));
  376. // OpenCV reference image code
  377. auto opencv_ref = [&](const cv::Mat &in_mat, cv::Mat &out_mat) {
  378. cv::Mat tmp;
  379. cv::resize(in_mat(crop_rc), tmp, resample_sz);
  380. cv::Canny(tmp, out_mat, thr_lo, thr_hi);
  381. };
  382. // Compilation & testing
  383. auto ccomp = c.compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{768,576}},
  384. getCompileArgs());
  385. EXPECT_TRUE(ccomp);
  386. EXPECT_FALSE(ccomp.running());
  387. auto path = findDataFile("cv/video/768x576.avi");
  388. try {
  389. ccomp.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path));
  390. } catch(...) {
  391. throw SkipTestException("Video file can not be opened");
  392. }
  393. ccomp.start();
  394. EXPECT_TRUE(ccomp.running());
  395. // Process the full video
  396. cv::Mat in_mat_gapi, out_mat_gapi;
  397. std::size_t frames = 0u;
  398. while (ccomp.pull(cv::gout(in_mat_gapi, out_mat_gapi))) {
  399. frames++;
  400. cv::Mat out_mat_ocv;
  401. opencv_ref(in_mat_gapi, out_mat_ocv);
  402. // Fluid's and OpenCV's Resizes aren't bit exact.
  403. // So 1% is here because it is max difference between them.
  404. EXPECT_TRUE(AbsSimilarPoints(0, 1).to_compare_f()(out_mat_gapi, out_mat_ocv));
  405. }
  406. EXPECT_LT(0u, frames);
  407. EXPECT_FALSE(ccomp.running());
  408. // Stop can be called at any time (even if the pipeline is not running)
  409. ccomp.stop();
  410. EXPECT_FALSE(ccomp.running());
  411. }
  412. TEST_P(GAPI_Streaming, Regression_CompileTimeScalar)
  413. {
  414. // There was a bug with compile-time GScalars. Compile-time
  415. // GScalars generate their own DATA nodes at GModel/GIslandModel
  416. // level, resulting in an extra link at the GIslandModel level, so
  417. // GStreamingExecutor automatically assigned an input queue to
  418. // such edges. Since there were no in-graph producer for that
  419. // data, no data were pushed to such queue what lead to a
  420. // deadlock.
  421. cv::GMat in;
  422. cv::GMat tmp = cv::gapi::copy(in);
  423. for (int i = 0; i < 3; i++) {
  424. tmp = tmp & cv::gapi::blur(in, cv::Size(3,3));
  425. }
  426. cv::GComputation c(cv::GIn(in), cv::GOut(tmp, tmp + 1));
  427. auto ccomp = c.compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{768,512}},
  428. getCompileArgs());
  429. cv::Mat in_mat = cv::imread(findDataFile("cv/edgefilter/kodim23.png"));
  430. cv::Mat out_mat1, out_mat2;
  431. // Fetch the result 15 times
  432. ccomp.setSource(cv::gin(in_mat));
  433. ccomp.start();
  434. for (int i = 0; i < 15; i++) {
  435. EXPECT_TRUE(ccomp.pull(cv::gout(out_mat1, out_mat2)));
  436. }
  437. ccomp.stop();
  438. }
  439. TEST_P(GAPI_Streaming, SmokeTest_StartRestart)
  440. {
  441. cv::GMat in;
  442. auto res = cv::gapi::resize(in, cv::Size{300,200});
  443. auto out = cv::gapi::Canny(res, 95, 220);
  444. cv::GComputation c(cv::GIn(in), cv::GOut(cv::gapi::copy(in), out));
  445. auto ccomp = c.compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{768,576}},
  446. getCompileArgs());
  447. EXPECT_TRUE(ccomp);
  448. EXPECT_FALSE(ccomp.running());
  449. // Run 1
  450. auto path = findDataFile("cv/video/768x576.avi");
  451. std::size_t num_frames1 = 0u;
  452. try {
  453. ccomp.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path));
  454. } catch(...) {
  455. throw SkipTestException("Video file can not be opened");
  456. }
  457. ccomp.start();
  458. EXPECT_TRUE(ccomp.running());
  459. cv::Mat out1, out2;
  460. while (ccomp.pull(cv::gout(out1, out2))) num_frames1++;
  461. EXPECT_FALSE(ccomp.running());
  462. // Run 2
  463. std::size_t num_frames2 = 0u;
  464. try {
  465. ccomp.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path));
  466. } catch(...) {
  467. throw SkipTestException("Video file can not be opened");
  468. }
  469. ccomp.start();
  470. EXPECT_TRUE(ccomp.running());
  471. while (ccomp.pull(cv::gout(out1, out2))) num_frames2++;
  472. EXPECT_FALSE(ccomp.running());
  473. EXPECT_LT(0u, num_frames1);
  474. EXPECT_LT(0u, num_frames2);
  475. EXPECT_EQ(num_frames1, num_frames2);
  476. }
  477. TEST_P(GAPI_Streaming, SmokeTest_VideoConstSource_NoHang)
  478. {
  479. // A video source is a finite one, while const source is not.
  480. // Check that pipeline completes when a video source completes.
  481. auto refc = cv::GComputation([](){
  482. cv::GMat in;
  483. return cv::GComputation(in, cv::gapi::copy(in));
  484. }).compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{768,576}}, getCompileArgs());
  485. auto path = findDataFile("cv/video/768x576.avi");
  486. try {
  487. refc.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path));
  488. } catch(...) {
  489. throw SkipTestException("Video file can not be opened");
  490. }
  491. refc.start();
  492. std::size_t ref_frames = 0u;
  493. cv::Mat tmp;
  494. while (refc.pull(cv::gout(tmp))) ref_frames++;
  495. EXPECT_EQ(100u, ref_frames);
  496. cv::GMat in;
  497. cv::GMat in2;
  498. cv::GMat roi = cv::gapi::crop(in2, cv::Rect{1,1,256,256});
  499. cv::GMat blr = cv::gapi::blur(roi, cv::Size(3,3));
  500. cv::GMat out = blr - in;
  501. auto testc = cv::GComputation(cv::GIn(in, in2), cv::GOut(out))
  502. .compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{256,256}},
  503. cv::GMatDesc{CV_8U,3,cv::Size{768,576}},
  504. getCompileArgs());
  505. cv::Mat in_const = cv::Mat::eye(cv::Size(256,256), CV_8UC3);
  506. testc.setSource(cv::gin(in_const,
  507. gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path)));
  508. testc.start();
  509. std::size_t test_frames = 0u;
  510. while (testc.pull(cv::gout(tmp))) test_frames++;
  511. EXPECT_EQ(ref_frames, test_frames);
  512. }
  513. TEST_P(GAPI_Streaming, SmokeTest_AutoMeta)
  514. {
  515. cv::GMat in;
  516. cv::GMat in2;
  517. cv::GMat roi = cv::gapi::crop(in2, cv::Rect{1,1,256,256});
  518. cv::GMat blr = cv::gapi::blur(roi, cv::Size(3,3));
  519. cv::GMat out = blr - in;
  520. auto testc = cv::GComputation(cv::GIn(in, in2), cv::GOut(out))
  521. .compileStreaming(getCompileArgs());
  522. cv::Mat in_const = cv::Mat::eye(cv::Size(256,256), CV_8UC3);
  523. cv::Mat tmp;
  524. // Test with one video source
  525. auto path = findDataFile("cv/video/768x576.avi");
  526. try {
  527. testc.setSource(cv::gin(in_const, gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path)));
  528. } catch(...) {
  529. throw SkipTestException("Video file can not be opened");
  530. }
  531. testc.start();
  532. std::size_t test_frames = 0u;
  533. while (testc.pull(cv::gout(tmp))) test_frames++;
  534. EXPECT_EQ(100u, test_frames);
  535. // Now test with another one
  536. path = findDataFile("cv/video/1920x1080.avi");
  537. try {
  538. testc.setSource(cv::gin(in_const, gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path)));
  539. } catch(...) {
  540. throw SkipTestException("Video file can not be opened");
  541. }
  542. testc.start();
  543. test_frames = 0u;
  544. while (testc.pull(cv::gout(tmp))) test_frames++;
  545. EXPECT_EQ(165u, test_frames);
  546. }
  547. TEST_P(GAPI_Streaming, SmokeTest_AutoMeta_2xConstMat)
  548. {
  549. cv::GMat in;
  550. cv::GMat in2;
  551. cv::GMat roi = cv::gapi::crop(in2, cv::Rect{1,1,256,256});
  552. cv::GMat blr = cv::gapi::blur(roi, cv::Size(3,3));
  553. cv::GMat out = blr - in;
  554. auto testc = cv::GComputation(cv::GIn(in, in2), cv::GOut(out))
  555. .compileStreaming(getCompileArgs());
  556. cv::Mat in_const = cv::Mat::eye(cv::Size(256,256), CV_8UC3);
  557. cv::Mat tmp;
  558. // Test with first image
  559. auto in_src = cv::imread(findDataFile("cv/edgefilter/statue.png"));
  560. testc.setSource(cv::gin(in_const, in_src));
  561. testc.start();
  562. ASSERT_TRUE(testc.pull(cv::gout(tmp)));
  563. testc.stop();
  564. // Now test with second image
  565. in_src = cv::imread(findDataFile("cv/edgefilter/kodim23.png"));
  566. testc.setSource(cv::gin(in_const, in_src));
  567. testc.start();
  568. ASSERT_TRUE(testc.pull(cv::gout(tmp)));
  569. testc.stop();
  570. }
  571. TEST_P(GAPI_Streaming, SmokeTest_AutoMeta_VideoScalar)
  572. {
  573. cv::GMat in_m;
  574. cv::GScalar in_s;
  575. cv::GMat out_m = in_m * in_s;
  576. auto testc = cv::GComputation(cv::GIn(in_m, in_s), cv::GOut(out_m))
  577. .compileStreaming(getCompileArgs());
  578. cv::Mat tmp;
  579. // Test with one video source and scalar
  580. auto path = findDataFile("cv/video/768x576.avi");
  581. try {
  582. testc.setSource(cv::gin(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path), cv::Scalar{1.25}));
  583. } catch(...) {
  584. throw SkipTestException("Video file can not be opened");
  585. }
  586. testc.start();
  587. std::size_t test_frames = 0u;
  588. while (testc.pull(cv::gout(tmp))) test_frames++;
  589. EXPECT_EQ(100u, test_frames);
  590. // Now test with another one video source and scalar
  591. path = findDataFile("cv/video/1920x1080.avi");
  592. try {
  593. testc.setSource(cv::gin(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path), cv::Scalar{0.75}));
  594. } catch(...) {
  595. throw SkipTestException("Video file can not be opened");
  596. }
  597. testc.start();
  598. test_frames = 0u;
  599. while (testc.pull(cv::gout(tmp))) test_frames++;
  600. EXPECT_EQ(165u, test_frames);
  601. }
  602. // Instantiate tests with different backends, but default queue capacity
  603. INSTANTIATE_TEST_CASE_P(TestStreaming, GAPI_Streaming,
  604. Combine(Values( KernelPackage::OCV
  605. , KernelPackage::OCV_FLUID),
  606. Values(cv::optional<size_t>{})));
  607. // Instantiate tests with the same backend but various queue capacity
  608. INSTANTIATE_TEST_CASE_P(TestStreaming_QC, GAPI_Streaming,
  609. Combine(Values(KernelPackage::OCV_FLUID),
  610. Values(1u, 4u)));
  611. namespace TypesTest
  612. {
  613. G_API_OP(SumV, <cv::GArray<int>(cv::GMat)>, "test.gapi.sumv") {
  614. static cv::GArrayDesc outMeta(const cv::GMatDesc &) {
  615. return cv::empty_array_desc();
  616. }
  617. };
  618. G_API_OP(AddV, <cv::GMat(cv::GMat,cv::GArray<int>)>, "test.gapi.addv") {
  619. static cv::GMatDesc outMeta(const cv::GMatDesc &in, const cv::GArrayDesc &) {
  620. return in;
  621. }
  622. };
  623. GAPI_OCV_KERNEL(OCVSumV, SumV) {
  624. static void run(const cv::Mat &in, std::vector<int> &out) {
  625. CV_Assert(in.depth() == CV_8U);
  626. const auto length = in.cols * in.channels();
  627. out.resize(length);
  628. const uchar *ptr = in.ptr(0);
  629. for (int c = 0; c < length; c++) {
  630. out[c] = ptr[c];
  631. }
  632. for (int r = 1; r < in.rows; r++) {
  633. ptr = in.ptr(r);
  634. for (int c = 0; c < length; c++) {
  635. out[c] += ptr[c];
  636. }
  637. }
  638. }
  639. };
  640. GAPI_OCV_KERNEL(OCVAddV, AddV) {
  641. static void run(const cv::Mat &in, const std::vector<int> &inv, cv::Mat &out) {
  642. CV_Assert(in.depth() == CV_8U);
  643. const auto length = in.cols * in.channels();
  644. CV_Assert(length == static_cast<int>(inv.size()));
  645. for (int r = 0; r < in.rows; r++) {
  646. const uchar *in_ptr = in.ptr(r);
  647. uchar *out_ptr = out.ptr(r);
  648. for (int c = 0; c < length; c++) {
  649. out_ptr[c] = cv::saturate_cast<uchar>(in_ptr[c] + inv[c]);
  650. }
  651. }
  652. }
  653. };
  654. GAPI_FLUID_KERNEL(FluidAddV, AddV, false) {
  655. static const int Window = 1;
  656. static void run(const cv::gapi::fluid::View &in,
  657. const std::vector<int> &inv,
  658. cv::gapi::fluid::Buffer &out) {
  659. const uchar *in_ptr = in.InLineB(0);
  660. uchar *out_ptr = out.OutLineB(0);
  661. const auto length = in.meta().size.width * in.meta().chan;
  662. CV_Assert(length == static_cast<int>(inv.size()));
  663. for (int c = 0; c < length; c++) {
  664. out_ptr[c] = cv::saturate_cast<uchar>(in_ptr[c] + inv[c]);
  665. }
  666. }
  667. };
  668. } // namespace TypesTest
  669. TEST_P(GAPI_Streaming, SmokeTest_AutoMeta_VideoArray)
  670. {
  671. cv::GMat in_m;
  672. cv::GArray<int> in_v;
  673. cv::GMat out_m = TypesTest::AddV::on(in_m, in_v) - in_m;
  674. // Run pipeline
  675. auto args = cv::compile_args(cv::gapi::kernels<TypesTest::OCVAddV>());
  676. auto capacity = getQueueCapacity();
  677. if (capacity)
  678. {
  679. args += cv::compile_args(
  680. cv::gapi::streaming::queue_capacity{capacity.value()});
  681. }
  682. auto testc = cv::GComputation(cv::GIn(in_m, in_v), cv::GOut(out_m))
  683. .compileStreaming(std::move(args));
  684. cv::Mat tmp;
  685. // Test with one video source and vector
  686. auto path = findDataFile("cv/video/768x576.avi");
  687. std::vector<int> first_in_vec(768*3, 1);
  688. try {
  689. testc.setSource(cv::gin(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path), first_in_vec));
  690. } catch(...) {
  691. throw SkipTestException("Video file can not be opened");
  692. }
  693. testc.start();
  694. std::size_t test_frames = 0u;
  695. while (testc.pull(cv::gout(tmp))) test_frames++;
  696. EXPECT_EQ(100u, test_frames);
  697. // Now test with another one
  698. path = findDataFile("cv/video/1920x1080.avi");
  699. std::vector<int> second_in_vec(1920*3, 1);
  700. try {
  701. testc.setSource(cv::gin(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path), second_in_vec));
  702. } catch(...) {
  703. throw SkipTestException("Video file can not be opened");
  704. }
  705. testc.start();
  706. test_frames = 0u;
  707. while (testc.pull(cv::gout(tmp))) test_frames++;
  708. EXPECT_EQ(165u, test_frames);
  709. }
  710. TEST(GAPI_Streaming_Types, InputScalar)
  711. {
  712. // This test verifies if Streaming works with Scalar data @ input.
  713. cv::GMat in_m;
  714. cv::GScalar in_s;
  715. cv::GMat out_m = in_m * in_s;
  716. cv::GComputation c(cv::GIn(in_m, in_s), cv::GOut(out_m));
  717. // Input data
  718. cv::Mat in_mat = cv::Mat::eye(256, 256, CV_8UC1);
  719. cv::Scalar in_scl = 32;
  720. // Run pipeline
  721. auto sc = c.compileStreaming(cv::descr_of(in_mat), cv::descr_of(in_scl));
  722. sc.setSource(cv::gin(in_mat, in_scl));
  723. sc.start();
  724. for (int i = 0; i < 10; i++)
  725. {
  726. cv::Mat out;
  727. EXPECT_TRUE(sc.pull(cv::gout(out)));
  728. EXPECT_EQ(0., cv::norm(out, in_mat.mul(in_scl), cv::NORM_INF));
  729. }
  730. }
  731. TEST(GAPI_Streaming_Types, InputVector)
  732. {
  733. // This test verifies if Streaming works with Vector data @ input.
  734. cv::GMat in_m;
  735. cv::GArray<int> in_v;
  736. cv::GMat out_m = TypesTest::AddV::on(in_m, in_v) - in_m;
  737. cv::GComputation c(cv::GIn(in_m, in_v), cv::GOut(out_m));
  738. // Input data
  739. cv::Mat in_mat = cv::Mat::eye(256, 256, CV_8UC1);
  740. std::vector<int> in_vec;
  741. TypesTest::OCVSumV::run(in_mat, in_vec);
  742. EXPECT_EQ(std::vector<int>(256,1), in_vec); // self-sanity-check
  743. auto opencv_ref = [&](const cv::Mat &in, const std::vector<int> &inv, cv::Mat &out) {
  744. cv::Mat tmp = in_mat.clone(); // allocate the same amount of memory as graph does
  745. TypesTest::OCVAddV::run(in, inv, tmp);
  746. out = tmp - in;
  747. };
  748. // Run pipeline
  749. auto sc = c.compileStreaming(cv::descr_of(in_mat),
  750. cv::descr_of(in_vec),
  751. cv::compile_args(cv::gapi::kernels<TypesTest::OCVAddV>()));
  752. sc.setSource(cv::gin(in_mat, in_vec));
  753. sc.start();
  754. for (int i = 0; i < 10; i++)
  755. {
  756. cv::Mat out_mat;
  757. EXPECT_TRUE(sc.pull(cv::gout(out_mat)));
  758. cv::Mat ref_mat;
  759. opencv_ref(in_mat, in_vec, ref_mat);
  760. EXPECT_EQ(0., cv::norm(ref_mat, out_mat, cv::NORM_INF));
  761. }
  762. }
  763. TEST(GAPI_Streaming_Types, XChangeScalar)
  764. {
  765. // This test verifies if Streaming works when pipeline steps
  766. // (islands) exchange Scalar data.
  767. cv::GMat in;
  768. cv::GScalar m = cv::gapi::mean(in);
  769. cv::GMat tmp = cv::gapi::convertTo(in, CV_32F) - m;
  770. cv::GMat out = cv::gapi::blur(tmp, cv::Size(3,3));
  771. cv::GComputation c(cv::GIn(in), cv::GOut(cv::gapi::copy(in),
  772. cv::gapi::convertTo(out, CV_8U)));
  773. auto ocv_ref = [](const cv::Mat &in_mat, cv::Mat &out_mat) {
  774. cv::Scalar ocv_m = cv::mean(in_mat);
  775. cv::Mat ocv_tmp;
  776. in_mat.convertTo(ocv_tmp, CV_32F);
  777. ocv_tmp -= ocv_m;
  778. cv::blur(ocv_tmp, ocv_tmp, cv::Size(3,3));
  779. ocv_tmp.convertTo(out_mat, CV_8U);
  780. };
  781. // Here we want mean & convertTo run on OCV
  782. // and subC & blur3x3 on Fluid.
  783. // FIXME: With the current API it looks quite awful:
  784. auto ocv_kernels = cv::gapi::core::cpu::kernels(); // convertTo
  785. ocv_kernels.remove<cv::gapi::core::GSubC>();
  786. auto fluid_kernels = cv::gapi::combine(cv::gapi::core::fluid::kernels(), // subC
  787. cv::gapi::imgproc::fluid::kernels()); // box3x3
  788. fluid_kernels.remove<cv::gapi::core::GConvertTo>();
  789. fluid_kernels.remove<cv::gapi::core::GMean>();
  790. // FIXME: Now
  791. // - fluid kernels take over ocv kernels (including Copy, SubC, & Box3x3)
  792. // - selected kernels (which were removed from the fluid package) remain in OCV
  793. // (ConvertTo + some others)
  794. // FIXME: This is completely awful. User should easily pick up specific kernels
  795. // to an empty kernel package to craft his own but not do it via exclusion.
  796. // Need to expose kernel declarations to public headers to enable kernels<..>()
  797. // on user side.
  798. auto kernels = cv::gapi::combine(ocv_kernels, fluid_kernels);
  799. // Compile streaming pipeline
  800. auto sc = c.compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{768,576}},
  801. cv::compile_args(cv::gapi::use_only{kernels}));
  802. auto path = findDataFile("cv/video/768x576.avi");
  803. try {
  804. sc.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path));
  805. } catch(...) {
  806. throw SkipTestException("Video file can not be opened");
  807. }
  808. sc.start();
  809. cv::Mat in_frame;
  810. cv::Mat out_mat_gapi;
  811. cv::Mat out_mat_ref;
  812. std::size_t num_frames = 0u;
  813. while (sc.pull(cv::gout(in_frame, out_mat_gapi))) {
  814. num_frames++;
  815. ocv_ref(in_frame, out_mat_ref);
  816. EXPECT_EQ(0., cv::norm(out_mat_gapi, out_mat_ref, cv::NORM_INF));
  817. }
  818. EXPECT_LT(0u, num_frames);
  819. }
  820. TEST(GAPI_Streaming_Types, XChangeVector)
  821. {
  822. // This test verifies if Streaming works when pipeline steps
  823. // (islands) exchange Vector data.
  824. cv::GMat in1, in2;
  825. cv::GMat in = cv::gapi::crop(in1, cv::Rect{0,0,576,576});
  826. cv::GScalar m = cv::gapi::mean(in);
  827. cv::GArray<int> s = TypesTest::SumV::on(in2); // (in2 = eye, so s = [1,0,0,1,..])
  828. cv::GMat out = TypesTest::AddV::on(in - m, s);
  829. cv::GComputation c(cv::GIn(in1, in2), cv::GOut(cv::gapi::copy(in), out));
  830. auto ocv_ref = [](const cv::Mat &in_mat1, const cv::Mat &in_mat2, cv::Mat &out_mat) {
  831. cv::Mat in_roi = in_mat1(cv::Rect{0,0,576,576});
  832. cv::Scalar ocv_m = cv::mean(in_roi);
  833. std::vector<int> ocv_v;
  834. TypesTest::OCVSumV::run(in_mat2, ocv_v);
  835. out_mat.create(cv::Size(576,576), CV_8UC3);
  836. cv::Mat in_tmp = in_roi - ocv_m;
  837. TypesTest::OCVAddV::run(in_tmp, ocv_v, out_mat);
  838. };
  839. // Let crop/mean/sumV be calculated via OCV,
  840. // and AddV/subC be calculated via Fluid
  841. auto ocv_kernels = cv::gapi::core::cpu::kernels();
  842. ocv_kernels.remove<cv::gapi::core::GSubC>();
  843. ocv_kernels.include<TypesTest::OCVSumV>();
  844. auto fluid_kernels = cv::gapi::core::fluid::kernels();
  845. fluid_kernels.include<TypesTest::FluidAddV>();
  846. // Here OCV takes precedense over Fluid, with SubC & SumV remaining
  847. // in Fluid.
  848. auto kernels = cv::gapi::combine(fluid_kernels, ocv_kernels);
  849. // Compile streaming pipeline
  850. cv::Mat in_eye = cv::Mat::eye(cv::Size(576, 576), CV_8UC3);
  851. auto sc = c.compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{768,576}},
  852. cv::GMatDesc{CV_8U,3,cv::Size{576,576}},
  853. cv::compile_args(cv::gapi::use_only{kernels}));
  854. auto path = findDataFile("cv/video/768x576.avi");
  855. try {
  856. sc.setSource(cv::gin(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path),
  857. in_eye));
  858. } catch(...) {
  859. throw SkipTestException("Video file can not be opened");
  860. }
  861. sc.start();
  862. cv::Mat in_frame;
  863. cv::Mat out_mat_gapi;
  864. cv::Mat out_mat_ref;
  865. std::size_t num_frames = 0u;
  866. while (sc.pull(cv::gout(in_frame, out_mat_gapi))) {
  867. num_frames++;
  868. ocv_ref(in_frame, in_eye, out_mat_ref);
  869. EXPECT_EQ(0., cv::norm(out_mat_gapi, out_mat_ref, cv::NORM_INF));
  870. }
  871. EXPECT_LT(0u, num_frames);
  872. }
  873. TEST(GAPI_Streaming_Types, OutputScalar)
  874. {
  875. // This test verifies if Streaming works when pipeline
  876. // produces scalar data only
  877. cv::GMat in;
  878. cv::GScalar out = cv::gapi::mean(in);
  879. auto sc = cv::GComputation(cv::GIn(in), cv::GOut(out))
  880. .compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{768,576}});
  881. std::string video_path;
  882. video_path = findDataFile("cv/video/768x576.avi");
  883. try {
  884. sc.setSource(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(video_path));
  885. } catch(...) {
  886. throw SkipTestException("Video file can not be opened");
  887. }
  888. sc.start();
  889. cv::VideoCapture cap;
  890. cap.open(video_path);
  891. if (!cap.isOpened())
  892. throw SkipTestException("Video file can not be opened");
  893. cv::Mat tmp;
  894. cv::Scalar out_scl;
  895. std::size_t num_frames = 0u;
  896. while (sc.pull(cv::gout(out_scl)))
  897. {
  898. num_frames++;
  899. cap >> tmp;
  900. cv::Scalar out_ref = cv::mean(tmp);
  901. EXPECT_EQ(out_ref, out_scl);
  902. }
  903. EXPECT_LT(0u, num_frames);
  904. }
  905. TEST(GAPI_Streaming_Types, OutputVector)
  906. {
  907. // This test verifies if Streaming works when pipeline
  908. // produces vector data only
  909. auto pkg = cv::gapi::kernels<TypesTest::OCVSumV>();
  910. cv::GMat in1, in2;
  911. cv::GMat roi = cv::gapi::crop(in2, cv::Rect(3,3,256,256));
  912. cv::GArray<int> out = TypesTest::SumV::on(cv::gapi::mul(roi, in1));
  913. auto sc = cv::GComputation(cv::GIn(in1, in2), cv::GOut(out))
  914. .compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{256,256}},
  915. cv::GMatDesc{CV_8U,3,cv::Size{768,576}},
  916. cv::compile_args(pkg));
  917. auto ocv_ref = [](const cv::Mat &ocv_in1,
  918. const cv::Mat &ocv_in2,
  919. std::vector<int> &ocv_out) {
  920. auto ocv_roi = ocv_in2(cv::Rect{3,3,256,256});
  921. TypesTest::OCVSumV::run(ocv_roi.mul(ocv_in1), ocv_out);
  922. };
  923. cv::Mat in_eye = cv::Mat::eye(cv::Size(256, 256), CV_8UC3);
  924. std::string video_path;
  925. video_path = findDataFile("cv/video/768x576.avi");
  926. try {
  927. sc.setSource(cv::gin(in_eye, gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(video_path)));
  928. } catch(...) {
  929. throw SkipTestException("Video file can not be opened");
  930. }
  931. sc.start();
  932. cv::VideoCapture cap;
  933. cap.open(video_path);
  934. if (!cap.isOpened())
  935. throw SkipTestException("Video file can not be opened");
  936. cv::Mat tmp;
  937. std::vector<int> ref_vec;
  938. std::vector<int> out_vec;
  939. std::size_t num_frames = 0u;
  940. while (sc.pull(cv::gout(out_vec)))
  941. {
  942. num_frames++;
  943. cap >> tmp;
  944. ref_vec.clear();
  945. ocv_ref(in_eye, tmp, ref_vec);
  946. EXPECT_EQ(ref_vec, out_vec);
  947. }
  948. EXPECT_LT(0u, num_frames);
  949. }
  950. G_API_OP(DimsChans,
  951. <std::tuple<cv::GArray<int>, cv::GOpaque<int>>(cv::GMat)>,
  952. "test.streaming.dims_chans") {
  953. static std::tuple<cv::GArrayDesc, cv::GOpaqueDesc> outMeta(const cv::GMatDesc &) {
  954. return std::make_tuple(cv::empty_array_desc(),
  955. cv::empty_gopaque_desc());
  956. }
  957. };
  958. GAPI_OCV_KERNEL(OCVDimsChans, DimsChans) {
  959. static void run(const cv::Mat &in, std::vector<int> &ov, int &oi) {
  960. ov = {in.cols, in.rows};
  961. oi = in.channels();
  962. }
  963. };
  964. struct GAPI_Streaming_TemplateTypes: ::testing::Test {
  965. // There was a problem in GStreamingExecutor
  966. // when outputs were formally not used by the graph
  967. // but still should be in place as operation need
  968. // to produce them, and host data type constructors
  969. // were missing for GArray and GOpaque in this case.
  970. // This test tests exactly this.
  971. GAPI_Streaming_TemplateTypes() {
  972. // Prepare everything for the test:
  973. // Graph itself
  974. blur = cv::gapi::boxFilter(in, -1, cv::Size(3,3));
  975. cv::GMat blur_d = cv::gapi::streaming::desync(blur);
  976. std::tie(vec, opq) = DimsChans::on(blur_d);
  977. // Kernel package
  978. pkg = cv::gapi::kernels<OCVDimsChans>();
  979. // Input mat
  980. in_mat = cv::Mat::eye(cv::Size(320,240), CV_8UC3);
  981. }
  982. cv::GMat in;
  983. cv::GMat blur;
  984. cv::GArray<int> vec;
  985. cv::GOpaque<int> opq;
  986. cv::GKernelPackage pkg;
  987. cv::Mat in_mat;
  988. };
  989. TEST_F(GAPI_Streaming_TemplateTypes, UnusedVectorIsOK)
  990. {
  991. // Declare graph without listing vec as output
  992. auto sc = cv::GComputation(cv::GIn(in), cv::GOut(blur, opq))
  993. .compileStreaming(cv::compile_args(pkg));
  994. sc.setSource(cv::gin(in_mat));
  995. sc.start();
  996. cv::optional<cv::Mat> out_mat;
  997. cv::optional<int> out_int;
  998. int counter = 0;
  999. while (sc.pull(cv::gout(out_mat, out_int))) {
  1000. if (counter++ == 10) {
  1001. // Stop the test after 10 iterations
  1002. sc.stop();
  1003. break;
  1004. }
  1005. GAPI_Assert(out_mat || out_int);
  1006. if (out_int) {
  1007. EXPECT_EQ(3, out_int.value());
  1008. }
  1009. }
  1010. }
  1011. TEST_F(GAPI_Streaming_TemplateTypes, UnusedOpaqueIsOK)
  1012. {
  1013. // Declare graph without listing opq as output
  1014. auto sc = cv::GComputation(cv::GIn(in), cv::GOut(blur, vec))
  1015. .compileStreaming(cv::compile_args(pkg));
  1016. sc.setSource(cv::gin(in_mat));
  1017. sc.start();
  1018. cv::optional<cv::Mat> out_mat;
  1019. cv::optional<std::vector<int> > out_vec;
  1020. int counter = 0;
  1021. while (sc.pull(cv::gout(out_mat, out_vec))) {
  1022. if (counter++ == 10) {
  1023. // Stop the test after 10 iterations
  1024. sc.stop();
  1025. break;
  1026. }
  1027. GAPI_Assert(out_mat || out_vec);
  1028. if (out_vec) {
  1029. EXPECT_EQ(320, out_vec.value()[0]);
  1030. EXPECT_EQ(240, out_vec.value()[1]);
  1031. }
  1032. }
  1033. }
  1034. struct GAPI_Streaming_Unit: public ::testing::Test {
  1035. cv::Mat m;
  1036. cv::GComputation cc;
  1037. cv::GStreamingCompiled sc;
  1038. cv::GCompiled ref;
  1039. GAPI_Streaming_Unit()
  1040. : m(cv::Mat::ones(224,224,CV_8UC3))
  1041. , cc([]{
  1042. cv::GMat a, b;
  1043. cv::GMat c = a + b*2;
  1044. return cv::GComputation(cv::GIn(a, b), cv::GOut(c));
  1045. })
  1046. {
  1047. const auto a_desc = cv::descr_of(m);
  1048. const auto b_desc = cv::descr_of(m);
  1049. sc = cc.compileStreaming(a_desc, b_desc);
  1050. ref = cc.compile(a_desc, b_desc);
  1051. }
  1052. };
  1053. // FIXME: (GAPI_Streaming_Types, InputOpaque) test is missing here!
  1054. // FIXME: (GAPI_Streaming_Types, XChangeOpaque) test is missing here!
  1055. // FIXME: (GAPI_Streaming_Types, OutputOpaque) test is missing here!
  1056. TEST(GAPI_Streaming, TestTwoVideosDifferentLength)
  1057. {
  1058. auto desc = cv::GMatDesc{CV_8U,3,{768,576}};
  1059. auto path1 = findDataFile("cv/video/768x576.avi");
  1060. auto path2 = findDataFile("highgui/video/big_buck_bunny.avi");
  1061. cv::GMat in1, in2;
  1062. auto out = in1 + cv::gapi::resize(in2, desc.size);
  1063. cv::GComputation cc(cv::GIn(in1, in2), cv::GOut(out));
  1064. auto sc = cc.compileStreaming();
  1065. try {
  1066. sc.setSource(cv::gin(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path1),
  1067. gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path2)));
  1068. } catch(...) {
  1069. throw SkipTestException("Video file can not be found");
  1070. }
  1071. sc.start();
  1072. cv::Mat out_mat;
  1073. std::size_t frames = 0u;
  1074. while(sc.pull(cv::gout(out_mat))) {
  1075. frames++;
  1076. }
  1077. // big_buck_bunny.avi has 125 frames, 768x576.avi - 100 frames,
  1078. // expect framework to stop after 100 frames
  1079. EXPECT_EQ(100u, frames);
  1080. }
  1081. TEST_F(GAPI_Streaming_Unit, TestStartWithoutnSetSource)
  1082. {
  1083. EXPECT_ANY_THROW(sc.start());
  1084. }
  1085. TEST_F(GAPI_Streaming_Unit, TestStopWithoutStart1)
  1086. {
  1087. // It is ok!
  1088. EXPECT_NO_THROW(sc.stop());
  1089. }
  1090. TEST_F(GAPI_Streaming_Unit, TestStopWithoutStart2)
  1091. {
  1092. // It should be ok as well
  1093. sc.setSource(cv::gin(m, m));
  1094. EXPECT_NO_THROW(sc.stop());
  1095. }
  1096. TEST_F(GAPI_Streaming_Unit, StopStartStop)
  1097. {
  1098. cv::Mat out;
  1099. EXPECT_NO_THROW(sc.stop());
  1100. EXPECT_NO_THROW(sc.setSource(cv::gin(m, m)));
  1101. EXPECT_NO_THROW(sc.start());
  1102. std::size_t i = 0u;
  1103. while (i++ < 10u) {EXPECT_TRUE(sc.pull(cv::gout(out)));};
  1104. EXPECT_NO_THROW(sc.stop());
  1105. }
  1106. TEST_F(GAPI_Streaming_Unit, ImplicitStop)
  1107. {
  1108. EXPECT_NO_THROW(sc.setSource(cv::gin(m, m)));
  1109. EXPECT_NO_THROW(sc.start());
  1110. // No explicit stop here - pipeline stops successfully at the test exit
  1111. }
  1112. TEST_F(GAPI_Streaming_Unit, StartStopStart_NoSetSource)
  1113. {
  1114. EXPECT_NO_THROW(sc.setSource(cv::gin(m, m)));
  1115. EXPECT_NO_THROW(sc.start());
  1116. EXPECT_NO_THROW(sc.stop());
  1117. EXPECT_ANY_THROW(sc.start()); // Should fail since setSource was not called
  1118. }
  1119. TEST_F(GAPI_Streaming_Unit, StartStopStress_Const)
  1120. {
  1121. // Runs 100 times with no deadlock - assumed stable (robust) enough
  1122. for (int i = 0; i < 100; i++)
  1123. {
  1124. sc.stop();
  1125. sc.setSource(cv::gin(m, m));
  1126. sc.start();
  1127. cv::Mat out;
  1128. for (int j = 0; j < 5; j++) EXPECT_TRUE(sc.pull(cv::gout(out)));
  1129. }
  1130. }
  1131. TEST_F(GAPI_Streaming_Unit, StartStopStress_Video)
  1132. {
  1133. // Runs 100 times with no deadlock - assumed stable (robust) enough
  1134. sc = cc.compileStreaming(cv::GMatDesc{CV_8U,3,cv::Size{768,576}},
  1135. cv::GMatDesc{CV_8U,3,cv::Size{768,576}});
  1136. m = cv::Mat::eye(cv::Size{768,576}, CV_8UC3);
  1137. auto path = findDataFile("cv/video/768x576.avi");
  1138. for (int i = 0; i < 100; i++)
  1139. {
  1140. sc.stop();
  1141. try {
  1142. sc.setSource(cv::gin(cv::gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path), m));
  1143. } catch(...) {
  1144. throw SkipTestException("Video file can not be opened");
  1145. }
  1146. sc.start();
  1147. cv::Mat out;
  1148. for (int j = 0; j < 5; j++) EXPECT_TRUE(sc.pull(cv::gout(out)));
  1149. }
  1150. }
  1151. TEST_F(GAPI_Streaming_Unit, PullNoStart)
  1152. {
  1153. sc.setSource(cv::gin(m, m));
  1154. cv::Mat out;
  1155. EXPECT_ANY_THROW(sc.pull(cv::gout(out)));
  1156. }
  1157. TEST_F(GAPI_Streaming_Unit, SetSource_Multi_BeforeStart)
  1158. {
  1159. cv::Mat eye = cv::Mat::eye (224, 224, CV_8UC3);
  1160. cv::Mat zrs = cv::Mat::zeros(224, 224, CV_8UC3);
  1161. // Call setSource two times, data specified last time
  1162. // should be actually processed.
  1163. sc.setSource(cv::gin(zrs, zrs));
  1164. sc.setSource(cv::gin(eye, eye));
  1165. // Run the pipeline, acquire result once
  1166. sc.start();
  1167. cv::Mat out, out_ref;
  1168. EXPECT_TRUE(sc.pull(cv::gout(out)));
  1169. sc.stop();
  1170. // Pipeline should process `eye` mat, not `zrs`
  1171. ref(cv::gin(eye, eye), cv::gout(out_ref));
  1172. EXPECT_EQ(0., cv::norm(out, out_ref, cv::NORM_INF));
  1173. }
  1174. TEST_F(GAPI_Streaming_Unit, SetSource_During_Execution)
  1175. {
  1176. cv::Mat zrs = cv::Mat::zeros(224, 224, CV_8UC3);
  1177. sc.setSource(cv::gin(m, m));
  1178. sc.start();
  1179. EXPECT_ANY_THROW(sc.setSource(cv::gin(zrs, zrs)));
  1180. EXPECT_ANY_THROW(sc.setSource(cv::gin(zrs, zrs)));
  1181. EXPECT_ANY_THROW(sc.setSource(cv::gin(zrs, zrs)));
  1182. sc.stop();
  1183. }
  1184. TEST_F(GAPI_Streaming_Unit, SetSource_After_Completion)
  1185. {
  1186. sc.setSource(cv::gin(m, m));
  1187. // Test pipeline with `m` input
  1188. sc.start();
  1189. cv::Mat out, out_ref;
  1190. EXPECT_TRUE(sc.pull(cv::gout(out)));
  1191. sc.stop();
  1192. // Test against ref
  1193. ref(cv::gin(m, m), cv::gout(out_ref));
  1194. EXPECT_EQ(0., cv::norm(out, out_ref, cv::NORM_INF));
  1195. // Now set another source
  1196. cv::Mat eye = cv::Mat::eye(224, 224, CV_8UC3);
  1197. sc.setSource(cv::gin(eye, m));
  1198. sc.start();
  1199. EXPECT_TRUE(sc.pull(cv::gout(out)));
  1200. sc.stop();
  1201. // Test against new ref
  1202. ref(cv::gin(eye, m), cv::gout(out_ref));
  1203. EXPECT_EQ(0., cv::norm(out, out_ref, cv::NORM_INF));
  1204. }
  1205. // NB: Check pull overload for python
  1206. TEST(Streaming, Python_Pull_Overload)
  1207. {
  1208. cv::GMat in;
  1209. auto out = cv::gapi::copy(in);
  1210. cv::GComputation c(in, out);
  1211. cv::Size sz(3,3);
  1212. cv::Mat in_mat(sz, CV_8UC3);
  1213. cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar(255));
  1214. auto ccomp = c.compileStreaming();
  1215. EXPECT_TRUE(ccomp);
  1216. EXPECT_FALSE(ccomp.running());
  1217. ccomp.setSource(cv::gin(in_mat));
  1218. ccomp.start();
  1219. EXPECT_TRUE(ccomp.running());
  1220. bool has_output;
  1221. cv::GRunArgs outputs;
  1222. using RunArgs = cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>;
  1223. RunArgs args;
  1224. std::tie(has_output, args) = ccomp.pull();
  1225. checkPullOverload(in_mat, has_output, args);
  1226. ccomp.stop();
  1227. EXPECT_FALSE(ccomp.running());
  1228. }
  1229. TEST(GAPI_Streaming_Desync, Python_Pull_Overload)
  1230. {
  1231. cv::GMat in;
  1232. cv::GMat out = cv::gapi::streaming::desync(in);
  1233. cv::GComputation c(in, out);
  1234. cv::Size sz(3,3);
  1235. cv::Mat in_mat(sz, CV_8UC3);
  1236. cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar(255));
  1237. auto ccomp = c.compileStreaming();
  1238. EXPECT_TRUE(ccomp);
  1239. EXPECT_FALSE(ccomp.running());
  1240. ccomp.setSource(cv::gin(in_mat));
  1241. ccomp.start();
  1242. EXPECT_TRUE(ccomp.running());
  1243. bool has_output;
  1244. cv::GRunArgs outputs;
  1245. using RunArgs = cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>;
  1246. RunArgs args;
  1247. std::tie(has_output, args) = ccomp.pull();
  1248. checkPullOverload(in_mat, has_output, args);
  1249. ccomp.stop();
  1250. EXPECT_FALSE(ccomp.running());
  1251. }
  1252. TEST(GAPI_Streaming_Desync, SmokeTest_Regular)
  1253. {
  1254. cv::GMat in;
  1255. cv::GMat tmp1 = cv::gapi::boxFilter(in, -1, cv::Size(3,3));
  1256. cv::GMat out1 = cv::gapi::Canny(tmp1, 32, 128, 3);
  1257. // FIXME: Unary desync should not require tie!
  1258. cv::GMat tmp2 = cv::gapi::streaming::desync(tmp1);
  1259. cv::GMat out2 = tmp2 / cv::gapi::Sobel(tmp2, CV_8U, 1, 1);;
  1260. cv::Mat test_in = cv::Mat::eye(cv::Size(32,32), CV_8UC3);
  1261. cv::Mat test_out1, test_out2;
  1262. cv::GComputation(cv::GIn(in), cv::GOut(out1, out2))
  1263. .apply(cv::gin(test_in), cv::gout(test_out1, test_out2));
  1264. }
  1265. TEST(GAPI_Streaming_Desync, SmokeTest_Streaming)
  1266. {
  1267. cv::GMat in;
  1268. cv::GMat tmp1 = cv::gapi::boxFilter(in, -1, cv::Size(3,3));
  1269. cv::GMat out1 = cv::gapi::Canny(tmp1, 32, 128, 3);
  1270. cv::GMat tmp2 = cv::gapi::streaming::desync(tmp1);
  1271. cv::GMat out2 = Delay::on(tmp2,10) / cv::gapi::Sobel(tmp2, CV_8U, 1, 1);
  1272. auto sc = cv::GComputation(cv::GIn(in), cv::GOut(out1, out2))
  1273. .compileStreaming(cv::compile_args(cv::gapi::kernels<OCVDelay>()));
  1274. auto path = findDataFile("cv/video/768x576.avi");
  1275. try {
  1276. sc.setSource(cv::gin(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path)));
  1277. } catch(...) {
  1278. throw SkipTestException("Video file can not be opened");
  1279. }
  1280. sc.start();
  1281. std::size_t out1_hits = 0u;
  1282. std::size_t out2_hits = 0u;
  1283. cv::optional<cv::Mat> test_out1, test_out2;
  1284. while (sc.pull(cv::gout(test_out1, test_out2))) {
  1285. GAPI_Assert(test_out1 || test_out2);
  1286. if (test_out1) out1_hits++;
  1287. if (test_out2) out2_hits++;
  1288. }
  1289. EXPECT_EQ(100u, out1_hits); // out1 must be available for all frames
  1290. EXPECT_LE(out2_hits, out1_hits); // out2 must appear less times than out1
  1291. }
  1292. TEST(GAPI_Streaming_Desync, SmokeTest_Streaming_TwoParts)
  1293. {
  1294. cv::GMat in;
  1295. cv::GMat tmp1 = cv::gapi::boxFilter(in, -1, cv::Size(3,3));
  1296. cv::GMat out1 = cv::gapi::Canny(tmp1, 32, 128, 3);
  1297. // Desynchronized path 1
  1298. cv::GMat tmp2 = cv::gapi::streaming::desync(tmp1);
  1299. cv::GMat out2 = tmp2 / cv::gapi::Sobel(tmp2, CV_8U, 1, 1);
  1300. // Desynchronized path 2
  1301. cv::GMat tmp3 = cv::gapi::streaming::desync(tmp1);
  1302. cv::GMat out3 = 0.5*tmp3 + 0.5*cv::gapi::medianBlur(tmp3, 7);
  1303. // The code should compile and execute well (desynchronized parts don't cross)
  1304. auto sc = cv::GComputation(cv::GIn(in), cv::GOut(out1, out2, out3))
  1305. .compileStreaming();
  1306. auto path = findDataFile("cv/video/768x576.avi");
  1307. try {
  1308. sc.setSource(cv::gin(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path)));
  1309. } catch(...) {
  1310. throw SkipTestException("Video file can not be opened");
  1311. }
  1312. sc.start();
  1313. std::size_t test_frames = 0u;
  1314. cv::optional<cv::Mat> test_out1, test_out2, test_out3;
  1315. while (sc.pull(cv::gout(test_out1, test_out2, test_out3))) {
  1316. GAPI_Assert(test_out1 || test_out2 || test_out3);
  1317. if (test_out1) {
  1318. // count frames only for synchronized output
  1319. test_frames++;
  1320. }
  1321. }
  1322. EXPECT_EQ(100u, test_frames);
  1323. }
  1324. TEST(GAPI_Streaming_Desync, Negative_NestedDesync_Tier0)
  1325. {
  1326. cv::GMat in;
  1327. cv::GMat tmp1 = cv::gapi::boxFilter(in, -1, cv::Size(3,3));
  1328. // Desynchronized path 1
  1329. cv::GMat tmp2 = cv::gapi::streaming::desync(tmp1);
  1330. cv::GMat out1 = cv::gapi::medianBlur(tmp2, 3);
  1331. // Desynchronized path 2, nested from 1 (directly from desync)
  1332. cv::GMat tmp3 = cv::gapi::streaming::desync(tmp2);
  1333. cv::GMat out2 = 0.5*tmp3;
  1334. // This shouldn't compile
  1335. EXPECT_ANY_THROW(cv::GComputation(cv::GIn(in), cv::GOut(out1, out2))
  1336. .compileStreaming());
  1337. }
  1338. TEST(GAPI_Streaming_Desync, Negative_NestedDesync_Tier1)
  1339. {
  1340. cv::GMat in;
  1341. cv::GMat tmp1 = cv::gapi::boxFilter(in, -1, cv::Size(3,3));
  1342. // Desynchronized path 1
  1343. cv::GMat tmp2 = cv::gapi::streaming::desync(tmp1);
  1344. cv::GMat out1 = cv::gapi::medianBlur(tmp2, 3);
  1345. // Desynchronized path 2, nested from 1 (indirectly from desync)
  1346. cv::GMat tmp3 = cv::gapi::streaming::desync(out1);
  1347. cv::GMat out2 = 0.5*tmp3;
  1348. // This shouldn't compile
  1349. EXPECT_ANY_THROW(cv::GComputation(cv::GIn(in), cv::GOut(out1, out2))
  1350. .compileStreaming());
  1351. }
  1352. TEST(GAPI_Streaming_Desync, Negative_CrossMainPart_Tier0)
  1353. {
  1354. cv::GMat in;
  1355. cv::GMat tmp1 = cv::gapi::boxFilter(in, -1, cv::Size(3,3));
  1356. // Desynchronized path: depends on both tmp1 and tmp2
  1357. cv::GMat tmp2 = cv::gapi::streaming::desync(tmp1);
  1358. cv::GMat out1 = 0.5*tmp1 + 0.5*tmp2;
  1359. // This shouldn't compile
  1360. EXPECT_ANY_THROW(cv::GComputation(in, out1).compileStreaming());
  1361. }
  1362. TEST(GAPI_Streaming_Desync, Negative_CrossMainPart_Tier1)
  1363. {
  1364. cv::GMat in;
  1365. cv::GMat tmp1 = cv::gapi::boxFilter(in, -1, cv::Size(3,3));
  1366. // Desynchronized path: depends on both tmp1 and tmp2
  1367. cv::GMat tmp2 = cv::gapi::streaming::desync(tmp1);
  1368. cv::GMat out1 = 0.5*tmp1 + 0.5*cv::gapi::medianBlur(tmp2, 3);
  1369. // This shouldn't compile
  1370. EXPECT_ANY_THROW(cv::GComputation(in, out1).compileStreaming());
  1371. }
  1372. TEST(GAPI_Streaming_Desync, Negative_CrossOtherDesync_Tier0)
  1373. {
  1374. cv::GMat in;
  1375. cv::GMat tmp1 = cv::gapi::boxFilter(in, -1, cv::Size(3,3));
  1376. // Desynchronized path 1
  1377. cv::GMat tmp2 = cv::gapi::streaming::desync(tmp1);
  1378. cv::GMat out1 = 0.5*tmp2;
  1379. // Desynchronized path 2 (depends on 1)
  1380. cv::GMat tmp3 = cv::gapi::streaming::desync(tmp1);
  1381. cv::GMat out2 = 0.5*tmp3 + tmp2;
  1382. // This shouldn't compile
  1383. EXPECT_ANY_THROW(cv::GComputation(cv::GIn(in), cv::GOut(out1, out2))
  1384. .compileStreaming());
  1385. }
  1386. TEST(GAPI_Streaming_Desync, Negative_CrossOtherDesync_Tier1)
  1387. {
  1388. cv::GMat in;
  1389. cv::GMat tmp1 = cv::gapi::boxFilter(in, -1, cv::Size(3,3));
  1390. // Desynchronized path 1
  1391. cv::GMat tmp2 = cv::gapi::streaming::desync(tmp1);
  1392. cv::GMat out1 = 0.5*tmp2;
  1393. // Desynchronized path 2 (depends on 1)
  1394. cv::GMat tmp3 = cv::gapi::streaming::desync(tmp1);
  1395. cv::GMat out2 = 0.5*cv::gapi::medianBlur(tmp3,3) + 1.0*tmp2;
  1396. // This shouldn't compile
  1397. EXPECT_ANY_THROW(cv::GComputation(cv::GIn(in), cv::GOut(out1, out2))
  1398. .compileStreaming());
  1399. }
  1400. TEST(GAPI_Streaming_Desync, Negative_SynchronizedPull)
  1401. {
  1402. cv::GMat in;
  1403. cv::GMat out1 = cv::gapi::boxFilter(in, -1, cv::Size(3,3));
  1404. cv::GMat tmp1 = cv::gapi::streaming::desync(out1);
  1405. cv::GMat out2 = 0.5*tmp1;
  1406. auto sc = cv::GComputation(cv::GIn(in), cv::GOut(out1, out2))
  1407. .compileStreaming();
  1408. auto path = findDataFile("cv/video/768x576.avi");
  1409. try {
  1410. sc.setSource(cv::gin(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path)));
  1411. } catch(...) {
  1412. throw SkipTestException("Video file can not be opened");
  1413. }
  1414. sc.start();
  1415. cv::Mat o1, o2;
  1416. EXPECT_ANY_THROW(sc.pull(cv::gout(o1, o2)));
  1417. }
  1418. TEST(GAPI_Streaming_Desync, UseSpecialPull)
  1419. {
  1420. cv::GMat in;
  1421. cv::GMat out1 = cv::gapi::boxFilter(in, -1, cv::Size(3,3));
  1422. cv::GMat tmp1 = cv::gapi::streaming::desync(out1);
  1423. cv::GMat out2 = 0.5*tmp1;
  1424. auto sc = cv::GComputation(cv::GIn(in), cv::GOut(out1, out2))
  1425. .compileStreaming();
  1426. auto path = findDataFile("cv/video/768x576.avi");
  1427. try {
  1428. sc.setSource(cv::gin(gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path)));
  1429. } catch(...) {
  1430. throw SkipTestException("Video file can not be opened");
  1431. }
  1432. sc.start();
  1433. cv::optional<cv::Mat> o1, o2;
  1434. std::size_t num_frames = 0u;
  1435. while (sc.pull(cv::gout(o1, o2))) {
  1436. if (o1) num_frames++;
  1437. }
  1438. EXPECT_EQ(100u, num_frames);
  1439. }
  1440. G_API_OP(ProduceVector, <cv::GArray<int>(cv::GMat)>, "test.desync.vector") {
  1441. static cv::GArrayDesc outMeta(const cv::GMatDesc &) {
  1442. return cv::empty_array_desc();
  1443. }
  1444. };
  1445. G_API_OP(ProduceOpaque, <cv::GOpaque<int>(cv::GMat)>, "test.desync.opaque") {
  1446. static cv::GOpaqueDesc outMeta(const cv::GMatDesc &) {
  1447. return cv::empty_gopaque_desc();
  1448. }
  1449. };
  1450. GAPI_OCV_KERNEL(OCVVector, ProduceVector) {
  1451. static void run(const cv::Mat& in, std::vector<int> &out) {
  1452. out = {in.cols, in.rows};
  1453. }
  1454. };
  1455. GAPI_OCV_KERNEL(OCVOpaque, ProduceOpaque) {
  1456. static void run(const cv::Mat &in, int &v) {
  1457. v = in.channels();
  1458. }
  1459. };
  1460. namespace {
  1461. cv::GStreamingCompiled desyncTestObject() {
  1462. cv::GMat in;
  1463. cv::GMat blur = cv::gapi::boxFilter(in, -1, cv::Size(3,3));
  1464. cv::GMat blur_d = cv::gapi::copy(cv::gapi::streaming::desync(blur));
  1465. cv::GMat d1 = Delay::on(blur_d, 10);
  1466. cv::GMat d2 = Delay::on(blur_d, 30);
  1467. cv::GArray<int> vec = ProduceVector::on(d1);
  1468. cv::GOpaque<int> opq = ProduceOpaque::on(d2);
  1469. auto pkg = cv::gapi::kernels<OCVDelay, OCVVector, OCVOpaque>();
  1470. return cv::GComputation(cv::GIn(in), cv::GOut(blur, vec, opq))
  1471. .compileStreaming(cv::compile_args(pkg));
  1472. }
  1473. } // anonymous namespace
  1474. TEST(GAPI_Streaming_Desync, MultipleDesyncOutputs_1) {
  1475. auto sc = desyncTestObject();
  1476. const cv::Mat in_mat = cv::Mat::eye(cv::Size(320,240), CV_8UC3);
  1477. sc.setSource(cv::gin(in_mat));
  1478. sc.start();
  1479. cv::optional<cv::Mat> out_mat;
  1480. cv::optional<std::vector<int> > out_vec;
  1481. cv::optional<int> out_int;
  1482. int counter = 0;
  1483. while (sc.pull(cv::gout(out_mat, out_vec, out_int))) {
  1484. if (counter++ == 1000) {
  1485. // Stop the test after 1000 iterations
  1486. sc.stop();
  1487. break;
  1488. }
  1489. GAPI_Assert(out_mat || out_vec || out_int);
  1490. // out_vec and out_int are on the same desynchronized path
  1491. // they MUST arrive together. If one is available, the other
  1492. // also must be available.
  1493. if (out_vec) { ASSERT_TRUE(out_int.has_value()); }
  1494. if (out_int) { ASSERT_TRUE(out_vec.has_value()); }
  1495. if (out_vec || out_int) {
  1496. EXPECT_EQ(320, out_vec.value()[0]);
  1497. EXPECT_EQ(240, out_vec.value()[1]);
  1498. EXPECT_EQ(3, out_int.value());
  1499. }
  1500. }
  1501. }
  1502. TEST(GAPI_Streaming_Desync, StartStop_Stress) {
  1503. auto sc = desyncTestObject();
  1504. const cv::Mat in_mat = cv::Mat::eye(cv::Size(320,240), CV_8UC3);
  1505. cv::optional<cv::Mat> out_mat;
  1506. cv::optional<std::vector<int> > out_vec;
  1507. cv::optional<int> out_int;
  1508. for (int i = 0; i < 10; i++) {
  1509. sc.setSource(cv::gin(in_mat));
  1510. sc.start();
  1511. int counter = 0;
  1512. while (counter++ < 100) {
  1513. sc.pull(cv::gout(out_mat, out_vec, out_int));
  1514. GAPI_Assert(out_mat || out_vec || out_int);
  1515. if (out_vec) { ASSERT_TRUE(out_int.has_value()); }
  1516. if (out_int) { ASSERT_TRUE(out_vec.has_value()); }
  1517. }
  1518. sc.stop();
  1519. }
  1520. }
  1521. TEST(GAPI_Streaming_Desync, DesyncObjectConsumedByTwoIslandsViaSeparateDesync) {
  1522. // See comment in the implementation of cv::gapi::streaming::desync (.cpp)
  1523. cv::GMat in;
  1524. cv::GMat tmp = cv::gapi::boxFilter(in, -1, cv::Size(3,3));
  1525. cv::GMat tmp1 = cv::gapi::streaming::desync(tmp);
  1526. cv::GMat out1 = cv::gapi::copy(tmp1); // ran via Streaming backend
  1527. cv::GMat tmp2 = cv::gapi::streaming::desync(tmp);
  1528. cv::GMat out2 = tmp2 * 0.5; // ran via OCV backend
  1529. auto c = cv::GComputation(cv::GIn(in), cv::GOut(out1, out2));
  1530. EXPECT_NO_THROW(c.compileStreaming());
  1531. }
  1532. TEST(GAPI_Streaming_Desync, DesyncObjectConsumedByTwoIslandsViaSameDesync) {
  1533. // See comment in the implementation of cv::gapi::streaming::desync (.cpp)
  1534. cv::GMat in;
  1535. cv::GMat tmp = cv::gapi::boxFilter(in, -1, cv::Size(3,3));
  1536. cv::GMat tmp1 = cv::gapi::streaming::desync(tmp);
  1537. cv::GMat out1 = cv::gapi::copy(tmp1); // ran via Streaming backend
  1538. cv::GMat out2 = out1 - 0.5*tmp1; // ran via OCV backend
  1539. auto c = cv::GComputation(cv::GIn(in), cv::GOut(out1, out2));
  1540. EXPECT_NO_THROW(c.compileStreaming());
  1541. }
  1542. TEST(GAPI_Streaming, CopyFrame)
  1543. {
  1544. std::string filepath = findDataFile("cv/video/768x576.avi");
  1545. cv::GFrame in;
  1546. auto out = cv::gapi::copy(in);
  1547. cv::GComputation comp(cv::GIn(in), cv::GOut(out));
  1548. auto cc = comp.compileStreaming();
  1549. try {
  1550. cc.setSource<BGRSource>(filepath);
  1551. } catch(...) {
  1552. throw SkipTestException("Video file can not be opened");
  1553. }
  1554. cv::VideoCapture cap;
  1555. cap.open(filepath);
  1556. if (!cap.isOpened())
  1557. throw SkipTestException("Video file can not be opened");
  1558. cv::MediaFrame frame;
  1559. cv::Mat ocv_mat;
  1560. std::size_t num_frames = 0u;
  1561. std::size_t max_frames = 10u;
  1562. cc.start();
  1563. while (cc.pull(cv::gout(frame)) && num_frames < max_frames)
  1564. {
  1565. auto view = frame.access(cv::MediaFrame::Access::R);
  1566. cv::Mat gapi_mat(frame.desc().size, CV_8UC3, view.ptr[0]);
  1567. num_frames++;
  1568. cap >> ocv_mat;
  1569. EXPECT_EQ(0, cvtest::norm(ocv_mat, gapi_mat, NORM_INF));
  1570. }
  1571. }
  1572. TEST(GAPI_Streaming, CopyFrameGray)
  1573. {
  1574. std::string filepath = findDataFile("cv/video/768x576.avi");
  1575. cv::GFrame in;
  1576. auto out = cv::gapi::copy(in);
  1577. cv::GComputation comp(cv::GIn(in), cv::GOut(out));
  1578. auto cc = comp.compileStreaming();
  1579. try {
  1580. cc.setSource<GRAYSource>(filepath);
  1581. }
  1582. catch (...) {
  1583. throw SkipTestException("Video file can not be opened");
  1584. }
  1585. cv::VideoCapture cap;
  1586. cap.open(filepath);
  1587. if (!cap.isOpened())
  1588. throw SkipTestException("Video file can not be opened");
  1589. cv::MediaFrame frame;
  1590. cv::Mat ocv_mat;
  1591. std::size_t num_frames = 0u;
  1592. std::size_t max_frames = 10u;
  1593. cc.start();
  1594. while (cc.pull(cv::gout(frame)) && num_frames < max_frames)
  1595. {
  1596. auto view = frame.access(cv::MediaFrame::Access::R);
  1597. cv::Mat gapi_mat(frame.desc().size, CV_8UC1, view.ptr[0]);
  1598. num_frames++;
  1599. cap >> ocv_mat;
  1600. cv::Mat gray;
  1601. cvtColor(ocv_mat, gray, cv::COLOR_BGR2GRAY);
  1602. EXPECT_EQ(0, cvtest::norm(gray, gapi_mat, NORM_INF));
  1603. }
  1604. }
  1605. TEST(GAPI_Streaming, CopyMat)
  1606. {
  1607. std::string filepath = findDataFile("cv/video/768x576.avi");
  1608. cv::GMat in;
  1609. auto out = cv::gapi::copy(in);
  1610. cv::GComputation comp(cv::GIn(in), cv::GOut(out));
  1611. auto cc = comp.compileStreaming();
  1612. try {
  1613. cc.setSource<cv::gapi::wip::GCaptureSource>(filepath);
  1614. } catch(...) {
  1615. throw SkipTestException("Video file can not be opened");
  1616. }
  1617. cv::VideoCapture cap;
  1618. cap.open(filepath);
  1619. if (!cap.isOpened())
  1620. throw SkipTestException("Video file can not be opened");
  1621. cv::Mat out_mat;
  1622. cv::Mat ocv_mat;
  1623. std::size_t num_frames = 0u;
  1624. std::size_t max_frames = 10u;
  1625. cc.start();
  1626. while (cc.pull(cv::gout(out_mat)) && num_frames < max_frames)
  1627. {
  1628. num_frames++;
  1629. cap >> ocv_mat;
  1630. EXPECT_EQ(0, cvtest::norm(ocv_mat, out_mat, NORM_INF));
  1631. }
  1632. }
  1633. TEST(GAPI_Streaming, Reshape)
  1634. {
  1635. std::string filepath = findDataFile("cv/video/768x576.avi");
  1636. cv::GFrame in;
  1637. auto out = cv::gapi::copy(in);
  1638. cv::GComputation comp(cv::GIn(in), cv::GOut(out));
  1639. auto cc = comp.compileStreaming();
  1640. try {
  1641. cc.setSource<BGRSource>(filepath);
  1642. } catch(...) {
  1643. throw SkipTestException("Video file can not be opened");
  1644. }
  1645. cv::VideoCapture cap;
  1646. cap.open(filepath);
  1647. if (!cap.isOpened())
  1648. throw SkipTestException("Video file can not be opened");
  1649. cv::MediaFrame frame;
  1650. cv::Mat ocv_mat;
  1651. std::size_t num_frames = 0u;
  1652. std::size_t max_frames = 10u;
  1653. cc.start();
  1654. while (cc.pull(cv::gout(frame)) && num_frames < max_frames)
  1655. {
  1656. auto view = frame.access(cv::MediaFrame::Access::R);
  1657. cv::Mat gapi_mat(frame.desc().size, CV_8UC3, view.ptr[0]);
  1658. num_frames++;
  1659. cap >> ocv_mat;
  1660. EXPECT_EQ(0, cvtest::norm(ocv_mat, gapi_mat, NORM_INF));
  1661. }
  1662. // Reshape the graph meta
  1663. filepath = findDataFile("cv/video/1920x1080.avi");
  1664. cc.stop();
  1665. try {
  1666. cc.setSource<BGRSource>(filepath);
  1667. } catch(...) {
  1668. throw SkipTestException("Video file can not be opened");
  1669. }
  1670. cap.open(filepath);
  1671. if (!cap.isOpened())
  1672. throw SkipTestException("Video file can not be opened");
  1673. cv::MediaFrame frame2;
  1674. cv::Mat ocv_mat2;
  1675. num_frames = 0u;
  1676. cc.start();
  1677. while (cc.pull(cv::gout(frame2)) && num_frames < max_frames)
  1678. {
  1679. auto view = frame2.access(cv::MediaFrame::Access::R);
  1680. cv::Mat gapi_mat(frame2.desc().size, CV_8UC3, view.ptr[0]);
  1681. num_frames++;
  1682. cap >> ocv_mat2;
  1683. EXPECT_EQ(0, cvtest::norm(ocv_mat2, gapi_mat, NORM_INF));
  1684. }
  1685. }
  1686. TEST(GAPI_Streaming, ReshapeGray)
  1687. {
  1688. std::string filepath = findDataFile("cv/video/768x576.avi");
  1689. cv::GFrame in;
  1690. auto out = cv::gapi::copy(in);
  1691. cv::GComputation comp(cv::GIn(in), cv::GOut(out));
  1692. auto cc = comp.compileStreaming();
  1693. try {
  1694. cc.setSource<GRAYSource>(filepath);
  1695. }
  1696. catch (...) {
  1697. throw SkipTestException("Video file can not be opened");
  1698. }
  1699. cv::VideoCapture cap;
  1700. cap.open(filepath);
  1701. if (!cap.isOpened())
  1702. throw SkipTestException("Video file can not be opened");
  1703. cv::MediaFrame frame;
  1704. cv::Mat ocv_mat;
  1705. std::size_t num_frames = 0u;
  1706. std::size_t max_frames = 10u;
  1707. cc.start();
  1708. while (cc.pull(cv::gout(frame)) && num_frames < max_frames)
  1709. {
  1710. auto view = frame.access(cv::MediaFrame::Access::R);
  1711. cv::Mat gapi_mat(frame.desc().size, CV_8UC1, view.ptr[0]);
  1712. num_frames++;
  1713. cap >> ocv_mat;
  1714. cv::Mat gray;
  1715. cvtColor(ocv_mat, gray, cv::COLOR_BGR2GRAY);
  1716. EXPECT_EQ(0, cvtest::norm(gray, gapi_mat, NORM_INF));
  1717. }
  1718. // Reshape the graph meta
  1719. filepath = findDataFile("cv/video/1920x1080.avi");
  1720. cc.stop();
  1721. try {
  1722. cc.setSource<GRAYSource>(filepath);
  1723. }
  1724. catch (...) {
  1725. throw SkipTestException("Video file can not be opened");
  1726. }
  1727. cap.open(filepath);
  1728. if (!cap.isOpened())
  1729. throw SkipTestException("Video file can not be opened");
  1730. cv::MediaFrame frame2;
  1731. cv::Mat ocv_mat2;
  1732. num_frames = 0u;
  1733. cc.start();
  1734. while (cc.pull(cv::gout(frame2)) && num_frames < max_frames)
  1735. {
  1736. auto view = frame2.access(cv::MediaFrame::Access::R);
  1737. cv::Mat gapi_mat(frame2.desc().size, CV_8UC1, view.ptr[0]);
  1738. num_frames++;
  1739. cap >> ocv_mat2;
  1740. cv::Mat gray;
  1741. cvtColor(ocv_mat2, gray, cv::COLOR_BGR2GRAY);
  1742. EXPECT_EQ(0, cvtest::norm(gray, gapi_mat, NORM_INF));
  1743. }
  1744. }
  1745. namespace {
  1746. enum class TestSourceType {
  1747. BGR,
  1748. NV12,
  1749. GRAY
  1750. };
  1751. std::ostream& operator<<(std::ostream& os, TestSourceType a) {
  1752. os << "Source:";
  1753. switch (a) {
  1754. case TestSourceType::BGR: return os << "BGR";
  1755. case TestSourceType::NV12: return os << "NV12";
  1756. case TestSourceType::GRAY: return os << "GRAY";
  1757. default: CV_Assert(false && "unknown TestSourceType");
  1758. }
  1759. }
  1760. cv::gapi::wip::IStreamSource::Ptr createTestSource(TestSourceType sourceType,
  1761. const std::string& pipeline) {
  1762. assert(sourceType == TestSourceType::BGR || sourceType == TestSourceType::NV12 || sourceType == TestSourceType::GRAY);
  1763. cv::gapi::wip::IStreamSource::Ptr ptr { };
  1764. switch (sourceType) {
  1765. case TestSourceType::BGR: {
  1766. try {
  1767. ptr = cv::gapi::wip::make_src<BGRSource>(pipeline);
  1768. }
  1769. catch(...) {
  1770. throw SkipTestException(std::string("BGRSource for '") + pipeline +
  1771. "' couldn't be created!");
  1772. }
  1773. break;
  1774. }
  1775. case TestSourceType::NV12: {
  1776. try {
  1777. ptr = cv::gapi::wip::make_src<NV12Source>(pipeline);
  1778. }
  1779. catch(...) {
  1780. throw SkipTestException(std::string("NV12Source for '") + pipeline +
  1781. "' couldn't be created!");
  1782. }
  1783. break;
  1784. }
  1785. case TestSourceType::GRAY: {
  1786. try {
  1787. ptr = cv::gapi::wip::make_src<GRAYSource>(pipeline);
  1788. }
  1789. catch (...) {
  1790. throw SkipTestException(std::string("GRAYSource for '") + pipeline +
  1791. "' couldn't be created!");
  1792. }
  1793. break;
  1794. }
  1795. default: {
  1796. throw SkipTestException("Incorrect type of source! "
  1797. "Something went wrong in the test!");
  1798. }
  1799. }
  1800. return ptr;
  1801. }
  1802. enum class TestAccessType {
  1803. BGR,
  1804. Y,
  1805. UV
  1806. };
  1807. std::ostream& operator<<(std::ostream& os, TestAccessType a) {
  1808. os << "Accessor:";
  1809. switch (a) {
  1810. case TestAccessType::BGR: return os << "BGR";
  1811. case TestAccessType::Y: return os << "Y";
  1812. case TestAccessType::UV: return os << "UV";
  1813. default: CV_Assert(false && "unknown TestAccessType");
  1814. }
  1815. }
  1816. using GapiFunction = std::function<cv::GMat(const cv::GFrame&)>;
  1817. static std::map<TestAccessType, GapiFunction> gapi_functions = {
  1818. { TestAccessType::BGR, cv::gapi::streaming::BGR },
  1819. { TestAccessType::Y, cv::gapi::streaming::Y },
  1820. { TestAccessType::UV, cv::gapi::streaming::UV }
  1821. };
  1822. using RefFunction = std::function<cv::Mat(const cv::Mat&)>;
  1823. static std::map<std::pair<TestSourceType,TestAccessType>, RefFunction> ref_functions = {
  1824. { std::make_pair(TestSourceType::BGR, TestAccessType::BGR),
  1825. [](const cv::Mat& bgr) { return bgr; } },
  1826. { std::make_pair(TestSourceType::BGR, TestAccessType::Y),
  1827. [](const cv::Mat& bgr) {
  1828. cv::Mat y, uv;
  1829. cvtBGR2NV12(bgr, y, uv);
  1830. return y;
  1831. } },
  1832. { std::make_pair(TestSourceType::BGR, TestAccessType::UV),
  1833. [](const cv::Mat& bgr) {
  1834. cv::Mat y, uv;
  1835. cvtBGR2NV12(bgr, y, uv);
  1836. return uv;
  1837. } },
  1838. { std::make_pair(TestSourceType::NV12, TestAccessType::BGR),
  1839. [](const cv::Mat& bgr) {
  1840. cv::Mat y, uv, out_bgr;
  1841. cvtBGR2NV12(bgr, y, uv);
  1842. cv::cvtColorTwoPlane(y, uv, out_bgr,
  1843. cv::COLOR_YUV2BGR_NV12);
  1844. return out_bgr;
  1845. } },
  1846. { std::make_pair(TestSourceType::NV12, TestAccessType::Y),
  1847. [](const cv::Mat& bgr) {
  1848. cv::Mat y, uv;
  1849. cvtBGR2NV12(bgr, y, uv);
  1850. return y;
  1851. } },
  1852. { std::make_pair(TestSourceType::NV12, TestAccessType::UV),
  1853. [](const cv::Mat& bgr) {
  1854. cv::Mat y, uv;
  1855. cvtBGR2NV12(bgr, y, uv);
  1856. return uv;
  1857. } },
  1858. { std::make_pair(TestSourceType::GRAY, TestAccessType::BGR),
  1859. [](const cv::Mat& bgr) {
  1860. cv::Mat gray;
  1861. cv::cvtColor(bgr, gray, cv::COLOR_BGR2GRAY);
  1862. cv::Mat out_bgr;
  1863. cv::cvtColor(gray, out_bgr, cv::COLOR_GRAY2BGR);
  1864. return out_bgr;
  1865. } },
  1866. { std::make_pair(TestSourceType::GRAY, TestAccessType::Y),
  1867. [](const cv::Mat& bgr) {
  1868. cv::Mat gray;
  1869. cv::cvtColor(bgr, gray, cv::COLOR_BGR2GRAY);
  1870. return gray;
  1871. } },
  1872. { std::make_pair(TestSourceType::GRAY, TestAccessType::UV),
  1873. [](const cv::Mat& bgr) {
  1874. cv::Mat uv(bgr.size() / 2, CV_8UC2, cv::Scalar::all(127));
  1875. return uv;
  1876. } },
  1877. };
  1878. } // anonymous namespace
  1879. struct GAPI_Accessors_In_Streaming : public TestWithParam<
  1880. std::tuple<std::string,TestSourceType,TestAccessType>>
  1881. { };
  1882. TEST_P(GAPI_Accessors_In_Streaming, AccuracyTest)
  1883. {
  1884. std::string filepath{};
  1885. TestSourceType sourceType = TestSourceType::BGR;
  1886. TestAccessType accessType = TestAccessType::BGR;
  1887. std::tie(filepath, sourceType, accessType) = GetParam();
  1888. auto accessor = gapi_functions[accessType];
  1889. auto fromBGR = ref_functions[std::make_pair(sourceType, accessType)];
  1890. const std::string& absFilePath = findDataFile(filepath);
  1891. cv::GFrame in;
  1892. cv::GMat out = accessor(in);
  1893. cv::GComputation comp(cv::GIn(in), cv::GOut(out));
  1894. auto cc = comp.compileStreaming();
  1895. auto src = createTestSource(sourceType, absFilePath);
  1896. cc.setSource(src);
  1897. cv::VideoCapture cap;
  1898. cap.open(absFilePath);
  1899. if (!cap.isOpened())
  1900. throw SkipTestException("Video file can not be opened");
  1901. cv::Mat cap_mat, ocv_mat, gapi_mat;
  1902. std::size_t num_frames = 0u;
  1903. std::size_t max_frames = 10u;
  1904. cc.start();
  1905. while (num_frames < max_frames && cc.pull(cv::gout(gapi_mat)))
  1906. {
  1907. num_frames++;
  1908. cap >> cap_mat;
  1909. ocv_mat = fromBGR(cap_mat);
  1910. EXPECT_EQ(0, cvtest::norm(ocv_mat, gapi_mat, NORM_INF));
  1911. }
  1912. cc.stop();
  1913. }
  1914. INSTANTIATE_TEST_CASE_P(TestAccessor, GAPI_Accessors_In_Streaming,
  1915. Combine(Values("cv/video/768x576.avi"),
  1916. Values(TestSourceType::BGR, TestSourceType::NV12, TestSourceType::GRAY),
  1917. Values(TestAccessType::BGR, TestAccessType::Y, TestAccessType::UV)
  1918. ));
  1919. struct GAPI_Accessors_Meta_In_Streaming : public TestWithParam<
  1920. std::tuple<std::string,TestSourceType,TestAccessType>>
  1921. { };
  1922. TEST_P(GAPI_Accessors_Meta_In_Streaming, AccuracyTest)
  1923. {
  1924. std::string filepath{};
  1925. TestSourceType sourceType = TestSourceType::BGR;
  1926. TestAccessType accessType = TestAccessType::BGR;
  1927. std::tie(filepath, sourceType, accessType) = GetParam();
  1928. auto accessor = gapi_functions[accessType];
  1929. auto fromBGR = ref_functions[std::make_pair(sourceType, accessType)];
  1930. const std::string& absFilePath = findDataFile(filepath);
  1931. cv::GFrame in;
  1932. cv::GMat gmat = accessor(in);
  1933. cv::GMat resized = cv::gapi::resize(gmat, cv::Size(1920, 1080));
  1934. cv::GOpaque<int64_t> outId = cv::gapi::streaming::seq_id(resized);
  1935. cv::GOpaque<int64_t> outTs = cv::gapi::streaming::timestamp(resized);
  1936. cv::GComputation comp(cv::GIn(in), cv::GOut(resized, outId, outTs));
  1937. auto cc = comp.compileStreaming();
  1938. auto src = createTestSource(sourceType, absFilePath);
  1939. cc.setSource(src);
  1940. cv::VideoCapture cap;
  1941. cap.open(absFilePath);
  1942. if (!cap.isOpened())
  1943. throw SkipTestException("Video file can not be opened");
  1944. cv::Mat cap_mat, req_mat, ocv_mat, gapi_mat;
  1945. int64_t seq_id = 0, timestamp = 0;
  1946. std::set<int64_t> all_seq_ids;
  1947. std::vector<int64_t> all_timestamps;
  1948. std::size_t num_frames = 0u;
  1949. std::size_t max_frames = 10u;
  1950. cc.start();
  1951. while (num_frames < max_frames && cc.pull(cv::gout(gapi_mat, seq_id, timestamp)))
  1952. {
  1953. num_frames++;
  1954. cap >> cap_mat;
  1955. req_mat = fromBGR(cap_mat);
  1956. cv::resize(req_mat, ocv_mat, cv::Size(1920, 1080));
  1957. EXPECT_EQ(0, cvtest::norm(ocv_mat, gapi_mat, NORM_INF));
  1958. all_seq_ids.insert(seq_id);
  1959. all_timestamps.push_back(timestamp);
  1960. }
  1961. cc.stop();
  1962. EXPECT_EQ(all_seq_ids.begin(), all_seq_ids.find(0L));
  1963. auto last_elem_it = --all_seq_ids.end();
  1964. EXPECT_EQ(last_elem_it, all_seq_ids.find(int64_t(max_frames - 1L)));
  1965. EXPECT_EQ(max_frames, all_seq_ids.size());
  1966. EXPECT_EQ(max_frames, all_timestamps.size());
  1967. EXPECT_TRUE(std::is_sorted(all_timestamps.begin(), all_timestamps.end()));
  1968. }
  1969. INSTANTIATE_TEST_CASE_P(AccessorMeta, GAPI_Accessors_Meta_In_Streaming,
  1970. Combine(Values("cv/video/768x576.avi"),
  1971. Values(TestSourceType::BGR, TestSourceType::NV12, TestSourceType::GRAY),
  1972. Values(TestAccessType::BGR, TestAccessType::Y, TestAccessType::UV)
  1973. ));
  1974. TEST(GAPI_Streaming, TestPythonAPI)
  1975. {
  1976. cv::Size sz(200, 200);
  1977. cv::Mat in_mat(sz, CV_8UC3);
  1978. cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar(255));
  1979. const auto crop_rc = cv::Rect(13, 75, 100, 100);
  1980. // OpenCV reference image
  1981. cv::Mat ocv_mat;
  1982. {
  1983. ocv_mat = in_mat(crop_rc);
  1984. }
  1985. cv::GMat in;
  1986. auto roi = cv::gapi::crop(in, crop_rc);
  1987. cv::GComputation comp(cv::GIn(in), cv::GOut(roi));
  1988. // NB: Used by python bridge
  1989. auto cc = comp.compileStreaming(cv::detail::ExtractMetaCallback{[&](const cv::GTypesInfo& info)
  1990. {
  1991. GAPI_Assert(info.size() == 1u);
  1992. GAPI_Assert(info[0].shape == cv::GShape::GMAT);
  1993. return cv::GMetaArgs{cv::GMetaArg{cv::descr_of(in_mat)}};
  1994. }});
  1995. // NB: Used by python bridge
  1996. cc.setSource(cv::detail::ExtractArgsCallback{[&](const cv::GTypesInfo& info)
  1997. {
  1998. GAPI_Assert(info.size() == 1u);
  1999. GAPI_Assert(info[0].shape == cv::GShape::GMAT);
  2000. return cv::GRunArgs{in_mat};
  2001. }});
  2002. cc.start();
  2003. bool is_over = false;
  2004. cv::GRunArgs out_args;
  2005. using RunArgs = cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>;
  2006. RunArgs args;
  2007. // NB: Used by python bridge
  2008. std::tie(is_over, args) = cc.pull();
  2009. switch (args.index()) {
  2010. case RunArgs::index_of<cv::GRunArgs>():
  2011. out_args = util::get<cv::GRunArgs>(args); break;
  2012. default: GAPI_Error("Incorrect type of return value");
  2013. }
  2014. ASSERT_EQ(1u, out_args.size());
  2015. ASSERT_TRUE(cv::util::holds_alternative<cv::Mat>(out_args[0]));
  2016. EXPECT_EQ(0, cvtest::norm(ocv_mat, cv::util::get<cv::Mat>(out_args[0]), NORM_INF));
  2017. EXPECT_TRUE(is_over);
  2018. cc.stop();
  2019. }
  2020. #ifdef HAVE_ONEVPL
  2021. TEST(OneVPL_Source, Init)
  2022. {
  2023. using CfgParam = cv::gapi::wip::onevpl::CfgParam;
  2024. std::vector<CfgParam> src_params;
  2025. src_params.push_back(CfgParam::create_implementation(MFX_IMPL_TYPE_HARDWARE));
  2026. #ifdef _WIN32
  2027. src_params.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_D3D11));
  2028. #elif defined(__linux__)
  2029. src_params.push_back(CfgParam::create_acceleration_mode(MFX_ACCEL_MODE_VIA_VAAPI));
  2030. #endif
  2031. src_params.push_back(CfgParam::create_decoder_id(MFX_CODEC_HEVC));
  2032. std::stringstream stream(std::ios_base::in | std::ios_base::out | std::ios_base::binary);
  2033. EXPECT_TRUE(stream.write(reinterpret_cast<char*>(const_cast<unsigned char *>(streaming::onevpl::hevc_header)),
  2034. sizeof(streaming::onevpl::hevc_header)));
  2035. std::shared_ptr<cv::gapi::wip::onevpl::IDataProvider> stream_data_provider =
  2036. std::make_shared<streaming::onevpl::StreamDataProvider>(stream);
  2037. cv::Ptr<cv::gapi::wip::IStreamSource> cap;
  2038. bool cap_created = false;
  2039. try {
  2040. cap = cv::gapi::wip::make_onevpl_src(stream_data_provider, src_params);
  2041. cap_created = true;
  2042. } catch (const std::exception&) {
  2043. }
  2044. ASSERT_TRUE(cap_created);
  2045. cv::gapi::wip::Data out;
  2046. while (cap->pull(out)) {
  2047. (void)out;
  2048. }
  2049. EXPECT_TRUE(stream_data_provider->empty());
  2050. }
  2051. #endif // HAVE_ONEVPL
  2052. TEST(GAPI_Streaming, TestDesyncRMat) {
  2053. cv::GMat in;
  2054. auto blurred = cv::gapi::blur(in, cv::Size{3,3});
  2055. auto desynced = cv::gapi::streaming::desync(blurred);
  2056. auto out = in - blurred;
  2057. auto pipe = cv::GComputation(cv::GIn(in), cv::GOut(desynced, out)).compileStreaming();
  2058. cv::Size sz(32,32);
  2059. cv::Mat in_mat(sz, CV_8UC3);
  2060. cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar(255));
  2061. pipe.setSource(cv::gin(in_mat));
  2062. pipe.start();
  2063. cv::optional<cv::RMat> out_desync;
  2064. cv::optional<cv::RMat> out_rmat;
  2065. while (true) {
  2066. // Initially it threw "bad variant access" since there was
  2067. // no RMat handling in wrap_opt_arg
  2068. EXPECT_NO_THROW(pipe.pull(cv::gout(out_desync, out_rmat)));
  2069. if (out_rmat) break;
  2070. }
  2071. }
  2072. G_API_OP(GTestBlur, <GFrame(GFrame)>, "test.blur") {
  2073. static GFrameDesc outMeta(GFrameDesc d) { return d; }
  2074. };
  2075. GAPI_OCV_KERNEL(GOcvTestBlur, GTestBlur) {
  2076. static void run(const cv::MediaFrame& in, cv::MediaFrame& out) {
  2077. auto d = in.desc();
  2078. GAPI_Assert(d.fmt == cv::MediaFormat::BGR);
  2079. auto view = in.access(cv::MediaFrame::Access::R);
  2080. cv::Mat mat(d.size, CV_8UC3, view.ptr[0]);
  2081. cv::Mat blurred;
  2082. cv::blur(mat, blurred, cv::Size{3,3});
  2083. out = cv::MediaFrame::Create<TestMediaBGR>(blurred);
  2084. }
  2085. };
  2086. TEST(GAPI_Streaming, TestDesyncMediaFrame) {
  2087. cv::GFrame in;
  2088. auto blurred = GTestBlur::on(in);
  2089. auto desynced = cv::gapi::streaming::desync(blurred);
  2090. auto out = GTestBlur::on(blurred);
  2091. auto pipe = cv::GComputation(cv::GIn(in), cv::GOut(desynced, out))
  2092. .compileStreaming(cv::compile_args(cv::gapi::kernels<GOcvTestBlur>()));
  2093. std::string filepath = findDataFile("cv/video/768x576.avi");
  2094. try {
  2095. pipe.setSource<BGRSource>(filepath);
  2096. } catch(...) {
  2097. throw SkipTestException("Video file can not be opened");
  2098. }
  2099. pipe.start();
  2100. cv::optional<cv::MediaFrame> out_desync;
  2101. cv::optional<cv::MediaFrame> out_frame;
  2102. while (true) {
  2103. // Initially it threw "bad variant access" since there was
  2104. // no MediaFrame handling in wrap_opt_arg
  2105. EXPECT_NO_THROW(pipe.pull(cv::gout(out_desync, out_frame)));
  2106. if (out_frame) break;
  2107. }
  2108. }
  2109. G_API_OP(GTestBlurGray, <GFrame(GFrame)>, "test.blur_gray") {
  2110. static GFrameDesc outMeta(GFrameDesc d) { return d; }
  2111. };
  2112. GAPI_OCV_KERNEL(GOcvTestBlurGray, GTestBlurGray) {
  2113. static void run(const cv::MediaFrame & in, cv::MediaFrame & out) {
  2114. auto d = in.desc();
  2115. GAPI_Assert(d.fmt == cv::MediaFormat::GRAY);
  2116. auto view = in.access(cv::MediaFrame::Access::R);
  2117. cv::Mat mat(d.size, CV_8UC1, view.ptr[0]);
  2118. cv::Mat blurred;
  2119. cv::blur(mat, blurred, cv::Size{ 3,3 });
  2120. out = cv::MediaFrame::Create<TestMediaGRAY>(blurred);
  2121. }
  2122. };
  2123. TEST(GAPI_Streaming, TestDesyncMediaFrameGray) {
  2124. cv::GFrame in;
  2125. auto blurred = GTestBlurGray::on(in);
  2126. auto desynced = cv::gapi::streaming::desync(blurred);
  2127. auto out = GTestBlurGray::on(blurred);
  2128. auto pipe = cv::GComputation(cv::GIn(in), cv::GOut(desynced, out))
  2129. .compileStreaming(cv::compile_args(cv::gapi::kernels<GOcvTestBlurGray>()));
  2130. std::string filepath = findDataFile("cv/video/768x576.avi");
  2131. try {
  2132. pipe.setSource<GRAYSource>(filepath);
  2133. }
  2134. catch (...) {
  2135. throw SkipTestException("Video file can not be opened");
  2136. }
  2137. pipe.start();
  2138. cv::optional<cv::MediaFrame> out_desync;
  2139. cv::optional<cv::MediaFrame> out_frame;
  2140. while (true) {
  2141. // Initially it threw "bad variant access" since there was
  2142. // no MediaFrame handling in wrap_opt_arg
  2143. EXPECT_NO_THROW(pipe.pull(cv::gout(out_desync, out_frame)));
  2144. if (out_frame) break;
  2145. }
  2146. }
  2147. TEST(GAPI_Streaming_Exception, SingleKernelThrow) {
  2148. cv::GMat in;
  2149. auto pipeline = cv::GComputation(in, GThrowExceptionOp::on(in))
  2150. .compileStreaming(cv::compile_args(cv::gapi::kernels<GThrowExceptionKernel>()));
  2151. cv::Mat in_mat(cv::Size(300, 300), CV_8UC3);
  2152. cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar::all(255));
  2153. pipeline.setSource(cv::gin(in_mat));
  2154. pipeline.start();
  2155. EXPECT_THROW(
  2156. try {
  2157. cv::Mat out_mat;
  2158. pipeline.pull(cv::gout(out_mat));
  2159. } catch (const std::logic_error& e) {
  2160. EXPECT_EQ(GThrowExceptionKernel::exception_msg(), e.what());
  2161. throw;
  2162. }, std::logic_error);
  2163. }
  2164. TEST(GAPI_Streaming_Exception, StreamingBackendExceptionAsInput) {
  2165. cv::GMat in;
  2166. auto pipeline = cv::GComputation(in,
  2167. cv::gapi::copy(GThrowExceptionOp::on(in)))
  2168. .compileStreaming(cv::compile_args(cv::gapi::kernels<GThrowExceptionKernel>()));
  2169. cv::Mat in_mat(cv::Size(300, 300), CV_8UC3);
  2170. cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar::all(255));
  2171. pipeline.setSource(cv::gin(in_mat));
  2172. pipeline.start();
  2173. EXPECT_THROW(
  2174. try {
  2175. cv::Mat out_mat;
  2176. pipeline.pull(cv::gout(out_mat));
  2177. } catch (const std::logic_error& e) {
  2178. EXPECT_EQ(GThrowExceptionKernel::exception_msg(), e.what());
  2179. throw;
  2180. }, std::logic_error);
  2181. }
  2182. TEST(GAPI_Streaming_Exception, RegularBacckendsExceptionAsInput) {
  2183. cv::GMat in;
  2184. auto pipeline = cv::GComputation(in,
  2185. cv::gapi::add(GThrowExceptionOp::on(in), GThrowExceptionOp::on(in)))
  2186. .compileStreaming(cv::compile_args(cv::gapi::kernels<GThrowExceptionKernel>()));
  2187. cv::Mat in_mat(cv::Size(300, 300), CV_8UC3);
  2188. cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar::all(255));
  2189. pipeline.setSource(cv::gin(in_mat));
  2190. pipeline.start();
  2191. EXPECT_THROW(
  2192. try {
  2193. cv::Mat out_mat;
  2194. pipeline.pull(cv::gout(out_mat));
  2195. } catch (const std::logic_error& e) {
  2196. EXPECT_EQ(GThrowExceptionKernel::exception_msg(), e.what());
  2197. throw;
  2198. }, std::logic_error);
  2199. }
  2200. TEST(GAPI_Streaming_Exception, SourceThrow) {
  2201. cv::GMat in;
  2202. auto pipeline = cv::GComputation(in, cv::gapi::copy(in)).compileStreaming();
  2203. pipeline.setSource(std::make_shared<InvalidSource>(1u, 1u));
  2204. pipeline.start();
  2205. EXPECT_THROW(
  2206. try {
  2207. cv::Mat out_mat;
  2208. pipeline.pull(cv::gout(out_mat));
  2209. } catch (const std::logic_error& e) {
  2210. EXPECT_EQ(InvalidSource::exception_msg(), e.what());
  2211. throw;
  2212. }, std::logic_error);
  2213. }
  2214. TEST(GAPI_Streaming_Exception, SourceThrowEverySecondFrame) {
  2215. constexpr size_t throw_every_nth_frame = 2u;
  2216. constexpr size_t num_frames = 10u;
  2217. size_t curr_frame = 0;
  2218. bool has_frame = true;
  2219. cv::Mat out_mat;
  2220. cv::GMat in;
  2221. auto pipeline = cv::GComputation(in, cv::gapi::copy(in)).compileStreaming();
  2222. pipeline.setSource(std::make_shared<InvalidSource>(throw_every_nth_frame, num_frames));
  2223. pipeline.start();
  2224. while (has_frame) {
  2225. ++curr_frame;
  2226. try {
  2227. has_frame = pipeline.pull(cv::gout(out_mat));
  2228. } catch (const std::exception& e) {
  2229. EXPECT_TRUE(curr_frame % throw_every_nth_frame == 0);
  2230. EXPECT_EQ(InvalidSource::exception_msg(), e.what());
  2231. }
  2232. }
  2233. // NB: Pull was called num_frames + 1(stop).
  2234. EXPECT_EQ(num_frames, curr_frame - 1);
  2235. }
  2236. } // namespace opencv_test