gapi_infer_ov_tests.cpp 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007
  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) 2023 Intel Corporation
  6. #if defined HAVE_INF_ENGINE && INF_ENGINE_RELEASE >= 2022010000
  7. #include "../test_precomp.hpp"
  8. #include "backends/ov/util.hpp"
  9. #include <opencv2/gapi/infer/ov.hpp>
  10. #include <openvino/openvino.hpp>
  11. namespace opencv_test
  12. {
  13. namespace {
  14. // FIXME: taken from DNN module
  15. void initDLDTDataPath()
  16. {
  17. #ifndef WINRT
  18. static bool initialized = false;
  19. if (!initialized)
  20. {
  21. cvtest::addDataSearchEnv("OPENCV_OPEN_MODEL_ZOO_DATA_PATH");
  22. const std::string dnnDataPath = cv::utils::getConfigurationParameterString("OPENCV_DNN_TEST_DATA_PATH");
  23. if (!dnnDataPath.empty()) {
  24. // Add the dnnDataPath itself - G-API is using some images there directly
  25. cvtest::addDataSearchPath(dnnDataPath);
  26. cvtest::addDataSearchPath(dnnDataPath + std::string("/omz_intel_models"));
  27. }
  28. initialized = true;
  29. }
  30. #endif // WINRT
  31. }
  32. static const std::string SUBDIR = "intel/age-gender-recognition-retail-0013/FP32/";
  33. // FIXME: taken from the DNN module
  34. void normAssert(cv::InputArray ref, cv::InputArray test,
  35. const char *comment /*= ""*/,
  36. double l1 = 0.00001, double lInf = 0.0001) {
  37. double normL1 = cvtest::norm(ref, test, cv::NORM_L1) / ref.getMat().total();
  38. EXPECT_LE(normL1, l1) << comment;
  39. double normInf = cvtest::norm(ref, test, cv::NORM_INF);
  40. EXPECT_LE(normInf, lInf) << comment;
  41. }
  42. // TODO: AGNetGenComp, AGNetTypedComp, AGNetOVComp, AGNetOVCompiled
  43. // can be generalized to work with any model and used as parameters for tests.
  44. struct AGNetGenParams {
  45. static constexpr const char* tag = "age-gender-generic";
  46. using Params = cv::gapi::ov::Params<cv::gapi::Generic>;
  47. static Params params(const std::string &xml,
  48. const std::string &bin,
  49. const std::string &device) {
  50. return {tag, xml, bin, device};
  51. }
  52. static Params params(const std::string &blob_path,
  53. const std::string &device) {
  54. return {tag, blob_path, device};
  55. }
  56. };
  57. struct AGNetTypedParams {
  58. using AGInfo = std::tuple<cv::GMat, cv::GMat>;
  59. G_API_NET(AgeGender, <AGInfo(cv::GMat)>, "typed-age-gender");
  60. using Params = cv::gapi::ov::Params<AgeGender>;
  61. static Params params(const std::string &xml_path,
  62. const std::string &bin_path,
  63. const std::string &device) {
  64. return Params {
  65. xml_path, bin_path, device
  66. }.cfgOutputLayers({ "age_conv3", "prob" });
  67. }
  68. };
  69. struct AGNetTypedComp : AGNetTypedParams {
  70. static cv::GComputation create() {
  71. cv::GMat in;
  72. cv::GMat age, gender;
  73. std::tie(age, gender) = cv::gapi::infer<AgeGender>(in);
  74. return cv::GComputation{cv::GIn(in), cv::GOut(age, gender)};
  75. }
  76. };
  77. struct AGNetGenComp : public AGNetGenParams {
  78. static cv::GComputation create() {
  79. cv::GMat in;
  80. GInferInputs inputs;
  81. inputs["data"] = in;
  82. auto outputs = cv::gapi::infer<cv::gapi::Generic>(tag, inputs);
  83. auto age = outputs.at("age_conv3");
  84. auto gender = outputs.at("prob");
  85. return cv::GComputation{cv::GIn(in), cv::GOut(age, gender)};
  86. }
  87. };
  88. struct AGNetROIGenComp : AGNetGenParams {
  89. static cv::GComputation create() {
  90. cv::GMat in;
  91. cv::GOpaque<cv::Rect> roi;
  92. GInferInputs inputs;
  93. inputs["data"] = in;
  94. auto outputs = cv::gapi::infer<cv::gapi::Generic>(tag, roi, inputs);
  95. auto age = outputs.at("age_conv3");
  96. auto gender = outputs.at("prob");
  97. return cv::GComputation{cv::GIn(in, roi), cv::GOut(age, gender)};
  98. }
  99. };
  100. struct AGNetListGenComp : AGNetGenParams {
  101. static cv::GComputation create() {
  102. cv::GMat in;
  103. cv::GArray<cv::Rect> rois;
  104. GInferInputs inputs;
  105. inputs["data"] = in;
  106. auto outputs = cv::gapi::infer<cv::gapi::Generic>(tag, rois, inputs);
  107. auto age = outputs.at("age_conv3");
  108. auto gender = outputs.at("prob");
  109. return cv::GComputation{cv::GIn(in, rois), cv::GOut(age, gender)};
  110. }
  111. };
  112. struct AGNetList2GenComp : AGNetGenParams {
  113. static cv::GComputation create() {
  114. cv::GMat in;
  115. cv::GArray<cv::Rect> rois;
  116. GInferListInputs list;
  117. list["data"] = rois;
  118. auto outputs = cv::gapi::infer2<cv::gapi::Generic>(tag, in, list);
  119. auto age = outputs.at("age_conv3");
  120. auto gender = outputs.at("prob");
  121. return cv::GComputation{cv::GIn(in, rois), cv::GOut(age, gender)};
  122. }
  123. };
  124. class AGNetOVCompiled {
  125. public:
  126. AGNetOVCompiled(ov::CompiledModel &&compiled_model)
  127. : m_compiled_model(std::move(compiled_model)),
  128. m_infer_request(m_compiled_model.create_infer_request()) {
  129. }
  130. void operator()(const cv::Mat &in_mat,
  131. const cv::Rect &roi,
  132. cv::Mat &age_mat,
  133. cv::Mat &gender_mat) {
  134. // FIXME: W & H could be extracted from model shape
  135. // but it's anyway used only for Age Gender model.
  136. // (Well won't work in case of reshape)
  137. const int W = 62;
  138. const int H = 62;
  139. cv::Mat resized_roi;
  140. cv::resize(in_mat(roi), resized_roi, cv::Size(W, H));
  141. (*this)(resized_roi, age_mat, gender_mat);
  142. }
  143. void operator()(const cv::Mat &in_mat,
  144. const std::vector<cv::Rect> &rois,
  145. std::vector<cv::Mat> &age_mats,
  146. std::vector<cv::Mat> &gender_mats) {
  147. for (size_t i = 0; i < rois.size(); ++i) {
  148. (*this)(in_mat, rois[i], age_mats[i], gender_mats[i]);
  149. }
  150. }
  151. void operator()(const cv::Mat &in_mat,
  152. cv::Mat &age_mat,
  153. cv::Mat &gender_mat) {
  154. auto input_tensor = m_infer_request.get_input_tensor();
  155. cv::gapi::ov::util::to_ov(in_mat, input_tensor);
  156. m_infer_request.infer();
  157. auto age_tensor = m_infer_request.get_tensor("age_conv3");
  158. age_mat.create(cv::gapi::ov::util::to_ocv(age_tensor.get_shape()),
  159. cv::gapi::ov::util::to_ocv(age_tensor.get_element_type()));
  160. cv::gapi::ov::util::to_ocv(age_tensor, age_mat);
  161. auto gender_tensor = m_infer_request.get_tensor("prob");
  162. gender_mat.create(cv::gapi::ov::util::to_ocv(gender_tensor.get_shape()),
  163. cv::gapi::ov::util::to_ocv(gender_tensor.get_element_type()));
  164. cv::gapi::ov::util::to_ocv(gender_tensor, gender_mat);
  165. }
  166. void export_model(const std::string &outpath) {
  167. std::ofstream file{outpath, std::ios::out | std::ios::binary};
  168. GAPI_Assert(file.is_open());
  169. m_compiled_model.export_model(file);
  170. }
  171. private:
  172. ov::CompiledModel m_compiled_model;
  173. ov::InferRequest m_infer_request;
  174. };
  175. struct ImageInputPreproc {
  176. void operator()(ov::preprocess::PrePostProcessor &ppp) {
  177. ppp.input().tensor().set_layout(ov::Layout("NHWC"))
  178. .set_element_type(ov::element::u8)
  179. .set_shape({1, size.height, size.width, 3});
  180. ppp.input().model().set_layout(ov::Layout("NCHW"));
  181. ppp.input().preprocess().resize(::ov::preprocess::ResizeAlgorithm::RESIZE_LINEAR);
  182. }
  183. cv::Size size;
  184. };
  185. class AGNetOVComp {
  186. public:
  187. AGNetOVComp(const std::string &xml_path,
  188. const std::string &bin_path,
  189. const std::string &device)
  190. : m_device(device) {
  191. m_model = cv::gapi::ov::wrap::getCore()
  192. .read_model(xml_path, bin_path);
  193. }
  194. using PrePostProcessF = std::function<void(ov::preprocess::PrePostProcessor&)>;
  195. void cfgPrePostProcessing(PrePostProcessF f) {
  196. ov::preprocess::PrePostProcessor ppp(m_model);
  197. f(ppp);
  198. m_model = ppp.build();
  199. }
  200. AGNetOVCompiled compile() {
  201. auto compiled_model = cv::gapi::ov::wrap::getCore()
  202. .compile_model(m_model, m_device);
  203. return {std::move(compiled_model)};
  204. }
  205. void apply(const cv::Mat &in_mat,
  206. cv::Mat &age_mat,
  207. cv::Mat &gender_mat) {
  208. compile()(in_mat, age_mat, gender_mat);
  209. }
  210. private:
  211. std::string m_device;
  212. std::shared_ptr<ov::Model> m_model;
  213. };
  214. struct BaseAgeGenderOV: public ::testing::Test {
  215. BaseAgeGenderOV() {
  216. initDLDTDataPath();
  217. xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml", false);
  218. bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin", false);
  219. device = "CPU";
  220. blob_path = "age-gender-recognition-retail-0013.blob";
  221. }
  222. cv::Mat getRandomImage(const cv::Size &sz) {
  223. cv::Mat image(sz, CV_8UC3);
  224. cv::randu(image, 0, 255);
  225. return image;
  226. }
  227. cv::Mat getRandomTensor(const std::vector<int> &dims,
  228. const int depth) {
  229. cv::Mat tensor(dims, depth);
  230. cv::randu(tensor, -1, 1);
  231. return tensor;
  232. }
  233. std::string xml_path;
  234. std::string bin_path;
  235. std::string blob_path;
  236. std::string device;
  237. };
  238. struct TestAgeGenderOV : public BaseAgeGenderOV {
  239. cv::Mat ov_age, ov_gender, gapi_age, gapi_gender;
  240. void validate() {
  241. normAssert(ov_age, gapi_age, "Test age output" );
  242. normAssert(ov_gender, gapi_gender, "Test gender output");
  243. }
  244. };
  245. struct TestAgeGenderListOV : public BaseAgeGenderOV {
  246. std::vector<cv::Mat> ov_age, ov_gender,
  247. gapi_age, gapi_gender;
  248. std::vector<cv::Rect> roi_list = {
  249. cv::Rect(cv::Point{64, 60}, cv::Size{ 96, 96}),
  250. cv::Rect(cv::Point{50, 32}, cv::Size{128, 160}),
  251. };
  252. TestAgeGenderListOV() {
  253. ov_age.resize(roi_list.size());
  254. ov_gender.resize(roi_list.size());
  255. gapi_age.resize(roi_list.size());
  256. gapi_gender.resize(roi_list.size());
  257. }
  258. void validate() {
  259. ASSERT_EQ(ov_age.size(), ov_gender.size());
  260. ASSERT_EQ(ov_age.size(), gapi_age.size());
  261. ASSERT_EQ(ov_gender.size(), gapi_gender.size());
  262. for (size_t i = 0; i < ov_age.size(); ++i) {
  263. normAssert(ov_age[i], gapi_age[i], "Test age output");
  264. normAssert(ov_gender[i], gapi_gender[i], "Test gender output");
  265. }
  266. }
  267. };
  268. class TestMediaBGR final: public cv::MediaFrame::IAdapter {
  269. cv::Mat m_mat;
  270. using Cb = cv::MediaFrame::View::Callback;
  271. Cb m_cb;
  272. public:
  273. explicit TestMediaBGR(cv::Mat m, Cb cb = [](){})
  274. : m_mat(m), m_cb(cb) {
  275. }
  276. cv::GFrameDesc meta() const override {
  277. return cv::GFrameDesc{cv::MediaFormat::BGR, cv::Size(m_mat.cols, m_mat.rows)};
  278. }
  279. cv::MediaFrame::View access(cv::MediaFrame::Access) override {
  280. cv::MediaFrame::View::Ptrs pp = { m_mat.ptr(), nullptr, nullptr, nullptr };
  281. cv::MediaFrame::View::Strides ss = { m_mat.step, 0u, 0u, 0u };
  282. return cv::MediaFrame::View(std::move(pp), std::move(ss), Cb{m_cb});
  283. }
  284. };
  285. struct MediaFrameTestAgeGenderOV: public ::testing::Test {
  286. MediaFrameTestAgeGenderOV() {
  287. initDLDTDataPath();
  288. xml_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.xml", false);
  289. bin_path = findDataFile(SUBDIR + "age-gender-recognition-retail-0013.bin", false);
  290. device = "CPU";
  291. blob_path = "age-gender-recognition-retail-0013.blob";
  292. cv::Size sz{62, 62};
  293. m_in_mat = cv::Mat(sz, CV_8UC3);
  294. cv::resize(m_in_mat, m_in_mat, sz);
  295. m_in_y = cv::Mat{sz, CV_8UC1};
  296. cv::randu(m_in_y, 0, 255);
  297. m_in_uv = cv::Mat{sz / 2, CV_8UC2};
  298. cv::randu(m_in_uv, 0, 255);
  299. }
  300. cv::Mat m_in_y;
  301. cv::Mat m_in_uv;
  302. cv::Mat m_in_mat;
  303. cv::Mat m_out_ov_age;
  304. cv::Mat m_out_ov_gender;
  305. cv::Mat m_out_gapi_age;
  306. cv::Mat m_out_gapi_gender;
  307. std::string xml_path;
  308. std::string bin_path;
  309. std::string blob_path;
  310. std::string device;
  311. std::string image_path;
  312. using AGInfo = std::tuple<cv::GMat, cv::GMat>;
  313. G_API_NET(AgeGender, <AGInfo(cv::GMat)>, "typed-age-gender");
  314. void validate() {
  315. normAssert(m_out_ov_age, m_out_gapi_age, "0: Test age output");
  316. normAssert(m_out_ov_gender, m_out_gapi_gender, "0: Test gender output");
  317. }
  318. }; // MediaFrameTestAgeGenderOV
  319. } // anonymous namespace
  320. TEST_F(MediaFrameTestAgeGenderOV, InferMediaInputBGR)
  321. {
  322. // OpenVINO
  323. AGNetOVComp ref(xml_path, bin_path, device);
  324. ref.cfgPrePostProcessing([](ov::preprocess::PrePostProcessor &ppp) {
  325. ppp.input().tensor().set_element_type(ov::element::u8);
  326. ppp.input().tensor().set_layout("NHWC");
  327. });
  328. ref.compile()(m_in_mat, m_out_ov_age, m_out_ov_gender);
  329. // G-API
  330. cv::GFrame in;
  331. cv::GMat age, gender;
  332. std::tie(age, gender) = cv::gapi::infer<AgeGender>(in);
  333. cv::GComputation comp{cv::GIn(in), cv::GOut(age, gender)};
  334. auto frame = MediaFrame::Create<TestMediaBGR>(m_in_mat);
  335. auto pp = cv::gapi::ov::Params<AgeGender> {
  336. xml_path, bin_path, device
  337. }.cfgOutputLayers({ "age_conv3", "prob" });
  338. comp.apply(cv::gin(frame),
  339. cv::gout(m_out_gapi_age, m_out_gapi_gender),
  340. cv::compile_args(cv::gapi::networks(pp)));
  341. validate();
  342. }
  343. TEST_F(MediaFrameTestAgeGenderOV, InferROIGenericMediaInputBGR) {
  344. // OpenVINO
  345. cv::Rect roi(cv::Rect(cv::Point{20, 25}, cv::Size{16, 16}));
  346. auto frame = MediaFrame::Create<TestMediaBGR>(m_in_mat);
  347. static constexpr const char* tag = "age-gender-generic";
  348. // OpenVINO
  349. AGNetOVComp ref(xml_path, bin_path, device);
  350. ref.cfgPrePostProcessing([](ov::preprocess::PrePostProcessor &ppp) {
  351. ppp.input().tensor().set_element_type(ov::element::u8);
  352. ppp.input().tensor().set_layout("NHWC");
  353. });
  354. ref.compile()(m_in_mat, roi, m_out_ov_age, m_out_ov_gender);
  355. // G-API
  356. cv::GFrame in;
  357. cv::GOpaque<cv::Rect> rr;
  358. GInferInputs inputs;
  359. inputs["data"] = in;
  360. auto outputs = cv::gapi::infer<cv::gapi::Generic>(tag, rr, inputs);
  361. auto age = outputs.at("age_conv3");
  362. auto gender = outputs.at("prob");
  363. cv::GComputation comp{cv::GIn(in, rr), cv::GOut(age, gender)};
  364. auto pp = AGNetROIGenComp::params(xml_path, bin_path, device);
  365. comp.apply(cv::gin(frame, roi), cv::gout(m_out_gapi_age, m_out_gapi_gender),
  366. cv::compile_args(cv::gapi::networks(pp)));
  367. validate();
  368. }
  369. class TestMediaNV12 final: public cv::MediaFrame::IAdapter {
  370. cv::Mat m_y;
  371. cv::Mat m_uv;
  372. public:
  373. TestMediaNV12(cv::Mat y, cv::Mat uv) : m_y(y), m_uv(uv) {
  374. }
  375. cv::GFrameDesc meta() const override {
  376. return cv::GFrameDesc{cv::MediaFormat::NV12, cv::Size(m_y.cols, m_y.rows)};
  377. }
  378. cv::MediaFrame::View access(cv::MediaFrame::Access) override {
  379. cv::MediaFrame::View::Ptrs pp = {
  380. m_y.ptr(), m_uv.ptr(), nullptr, nullptr
  381. };
  382. cv::MediaFrame::View::Strides ss = {
  383. m_y.step, m_uv.step, 0u, 0u
  384. };
  385. return cv::MediaFrame::View(std::move(pp), std::move(ss));
  386. }
  387. };
  388. TEST_F(MediaFrameTestAgeGenderOV, TestMediaNV12AgeGenderOV)
  389. {
  390. cv::GFrame in;
  391. cv::GOpaque<cv::Rect> rr;
  392. GInferInputs inputs;
  393. inputs["data"] = in;
  394. static constexpr const char* tag = "age-gender-generic";
  395. auto outputs = cv::gapi::infer<cv::gapi::Generic>(tag, rr, inputs);
  396. auto age = outputs.at("age_conv3");
  397. auto gender = outputs.at("prob");
  398. cv::GComputation comp{cv::GIn(in, rr), cv::GOut(age, gender)};
  399. auto frame = MediaFrame::Create<TestMediaNV12>(m_in_y, m_in_uv);
  400. auto pp = AGNetROIGenComp::params(xml_path, bin_path, device);
  401. cv::Rect roi(cv::Rect(cv::Point{20, 25}, cv::Size{16, 16}));
  402. EXPECT_NO_THROW(comp.apply(cv::gin(frame, roi),
  403. cv::gout(m_out_gapi_age, m_out_gapi_gender),
  404. cv::compile_args(cv::gapi::networks(pp))));
  405. }
  406. // TODO: Make all of tests below parmetrized to avoid code duplication
  407. TEST_F(TestAgeGenderOV, Infer_Tensor) {
  408. const auto in_mat = getRandomTensor({1, 3, 62, 62}, CV_32F);
  409. // OpenVINO
  410. AGNetOVComp ref(xml_path, bin_path, device);
  411. ref.apply(in_mat, ov_age, ov_gender);
  412. // G-API
  413. auto comp = AGNetTypedComp::create();
  414. auto pp = AGNetTypedComp::params(xml_path, bin_path, device);
  415. comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
  416. cv::compile_args(cv::gapi::networks(pp)));
  417. // Assert
  418. validate();
  419. }
  420. TEST_F(TestAgeGenderOV, Infer_Image) {
  421. const auto in_mat = getRandomImage({300, 300});
  422. // OpenVINO
  423. AGNetOVComp ref(xml_path, bin_path, device);
  424. ref.cfgPrePostProcessing(ImageInputPreproc{in_mat.size()});
  425. ref.apply(in_mat, ov_age, ov_gender);
  426. // G-API
  427. auto comp = AGNetTypedComp::create();
  428. auto pp = AGNetTypedComp::params(xml_path, bin_path, device);
  429. comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
  430. cv::compile_args(cv::gapi::networks(pp)));
  431. // Assert
  432. validate();
  433. }
  434. TEST_F(TestAgeGenderOV, InferGeneric_Tensor) {
  435. const auto in_mat = getRandomTensor({1, 3, 62, 62}, CV_32F);
  436. // OpenVINO
  437. AGNetOVComp ref(xml_path, bin_path, device);
  438. ref.apply(in_mat, ov_age, ov_gender);
  439. // G-API
  440. auto comp = AGNetGenComp::create();
  441. auto pp = AGNetGenComp::params(xml_path, bin_path, device);
  442. comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
  443. cv::compile_args(cv::gapi::networks(pp)));
  444. // Assert
  445. validate();
  446. }
  447. TEST_F(TestAgeGenderOV, InferGenericImage) {
  448. const auto in_mat = getRandomImage({300, 300});
  449. // OpenVINO
  450. AGNetOVComp ref(xml_path, bin_path, device);
  451. ref.cfgPrePostProcessing(ImageInputPreproc{in_mat.size()});
  452. ref.apply(in_mat, ov_age, ov_gender);
  453. // G-API
  454. auto comp = AGNetGenComp::create();
  455. auto pp = AGNetGenComp::params(xml_path, bin_path, device);
  456. comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
  457. cv::compile_args(cv::gapi::networks(pp)));
  458. // Assert
  459. validate();
  460. }
  461. TEST_F(TestAgeGenderOV, InferGeneric_ImageBlob) {
  462. const auto in_mat = getRandomImage({300, 300});
  463. // OpenVINO
  464. AGNetOVComp ref(xml_path, bin_path, device);
  465. ref.cfgPrePostProcessing(ImageInputPreproc{in_mat.size()});
  466. auto cc_ref = ref.compile();
  467. // NB: Output blob will contain preprocessing inside.
  468. cc_ref.export_model(blob_path);
  469. cc_ref(in_mat, ov_age, ov_gender);
  470. // G-API
  471. auto comp = AGNetGenComp::create();
  472. auto pp = AGNetGenComp::params(blob_path, device);
  473. comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
  474. cv::compile_args(cv::gapi::networks(pp)));
  475. // Assert
  476. validate();
  477. }
  478. TEST_F(TestAgeGenderOV, InferGeneric_TensorBlob) {
  479. const auto in_mat = getRandomTensor({1, 3, 62, 62}, CV_32F);
  480. // OpenVINO
  481. AGNetOVComp ref(xml_path, bin_path, device);
  482. auto cc_ref = ref.compile();
  483. cc_ref.export_model(blob_path);
  484. cc_ref(in_mat, ov_age, ov_gender);
  485. // G-API
  486. auto comp = AGNetGenComp::create();
  487. auto pp = AGNetGenComp::params(blob_path, device);
  488. comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
  489. cv::compile_args(cv::gapi::networks(pp)));
  490. // Assert
  491. validate();
  492. }
  493. TEST_F(TestAgeGenderOV, InferGeneric_BothOutputsFP16) {
  494. const auto in_mat = getRandomTensor({1, 3, 62, 62}, CV_32F);
  495. // OpenVINO
  496. AGNetOVComp ref(xml_path, bin_path, device);
  497. ref.cfgPrePostProcessing([](ov::preprocess::PrePostProcessor &ppp){
  498. ppp.output(0).tensor().set_element_type(ov::element::f16);
  499. ppp.output(1).tensor().set_element_type(ov::element::f16);
  500. });
  501. ref.apply(in_mat, ov_age, ov_gender);
  502. // G-API
  503. auto comp = AGNetGenComp::create();
  504. auto pp = AGNetGenComp::params(xml_path, bin_path, device);
  505. pp.cfgOutputTensorPrecision(CV_16F);
  506. comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
  507. cv::compile_args(cv::gapi::networks(pp)));
  508. // Assert
  509. validate();
  510. }
  511. TEST_F(TestAgeGenderOV, InferGeneric_OneOutputFP16) {
  512. const auto in_mat = getRandomTensor({1, 3, 62, 62}, CV_32F);
  513. // OpenVINO
  514. const std::string fp16_output_name = "prob";
  515. AGNetOVComp ref(xml_path, bin_path, device);
  516. ref.cfgPrePostProcessing([&](ov::preprocess::PrePostProcessor &ppp){
  517. ppp.output(fp16_output_name).tensor().set_element_type(ov::element::f16);
  518. });
  519. ref.apply(in_mat, ov_age, ov_gender);
  520. // G-API
  521. auto comp = AGNetGenComp::create();
  522. auto pp = AGNetGenComp::params(xml_path, bin_path, device);
  523. pp.cfgOutputTensorPrecision({{fp16_output_name, CV_16F}});
  524. comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
  525. cv::compile_args(cv::gapi::networks(pp)));
  526. // Assert
  527. validate();
  528. }
  529. TEST_F(TestAgeGenderOV, InferGeneric_ThrowCfgOutputPrecForBlob) {
  530. // OpenVINO (Just for blob compilation)
  531. AGNetOVComp ref(xml_path, bin_path, device);
  532. auto cc_ref = ref.compile();
  533. cc_ref.export_model(blob_path);
  534. // G-API
  535. auto comp = AGNetGenComp::create();
  536. auto pp = AGNetGenComp::params(blob_path, device);
  537. EXPECT_ANY_THROW(pp.cfgOutputTensorPrecision(CV_16F));
  538. }
  539. TEST_F(TestAgeGenderOV, InferGeneric_ThrowInvalidConfigIR) {
  540. // G-API
  541. auto comp = AGNetGenComp::create();
  542. auto pp = AGNetGenComp::params(xml_path, bin_path, device);
  543. pp.cfgPluginConfig({{"some_key", "some_value"}});
  544. EXPECT_ANY_THROW(comp.compile(cv::GMatDesc{CV_8U,3,cv::Size{320, 240}},
  545. cv::compile_args(cv::gapi::networks(pp))));
  546. }
  547. TEST_F(TestAgeGenderOV, InferGeneric_ThrowInvalidConfigBlob) {
  548. // OpenVINO (Just for blob compilation)
  549. AGNetOVComp ref(xml_path, bin_path, device);
  550. auto cc_ref = ref.compile();
  551. cc_ref.export_model(blob_path);
  552. // G-API
  553. auto comp = AGNetGenComp::create();
  554. auto pp = AGNetGenComp::params(blob_path, device);
  555. pp.cfgPluginConfig({{"some_key", "some_value"}});
  556. EXPECT_ANY_THROW(comp.compile(cv::GMatDesc{CV_8U,3,cv::Size{320, 240}},
  557. cv::compile_args(cv::gapi::networks(pp))));
  558. }
  559. TEST_F(TestAgeGenderOV, Infer_ThrowInvalidImageLayout) {
  560. const auto in_mat = getRandomImage({300, 300});
  561. auto comp = AGNetTypedComp::create();
  562. auto pp = AGNetTypedComp::params(xml_path, bin_path, device);
  563. pp.cfgInputTensorLayout("NCHW");
  564. EXPECT_ANY_THROW(comp.compile(cv::descr_of(in_mat),
  565. cv::compile_args(cv::gapi::networks(pp))));
  566. }
  567. TEST_F(TestAgeGenderOV, Infer_TensorWithPreproc) {
  568. const auto in_mat = getRandomTensor({1, 240, 320, 3}, CV_32F);
  569. // OpenVINO
  570. AGNetOVComp ref(xml_path, bin_path, device);
  571. ref.cfgPrePostProcessing([](ov::preprocess::PrePostProcessor &ppp) {
  572. auto& input = ppp.input();
  573. input.tensor().set_spatial_static_shape(240, 320)
  574. .set_layout("NHWC");
  575. input.preprocess().resize(ov::preprocess::ResizeAlgorithm::RESIZE_LINEAR);
  576. });
  577. ref.apply(in_mat, ov_age, ov_gender);
  578. // G-API
  579. auto comp = AGNetTypedComp::create();
  580. auto pp = AGNetTypedComp::params(xml_path, bin_path, device);
  581. pp.cfgResize(cv::INTER_LINEAR)
  582. .cfgInputTensorLayout("NHWC");
  583. comp.apply(cv::gin(in_mat), cv::gout(gapi_age, gapi_gender),
  584. cv::compile_args(cv::gapi::networks(pp)));
  585. // Assert
  586. validate();
  587. }
  588. TEST_F(TestAgeGenderOV, InferROIGeneric_Image) {
  589. const auto in_mat = getRandomImage({300, 300});
  590. cv::Rect roi(cv::Rect(cv::Point{64, 60}, cv::Size{96, 96}));
  591. // OpenVINO
  592. AGNetOVComp ref(xml_path, bin_path, device);
  593. ref.cfgPrePostProcessing([](ov::preprocess::PrePostProcessor &ppp) {
  594. ppp.input().tensor().set_element_type(ov::element::u8);
  595. ppp.input().tensor().set_layout("NHWC");
  596. });
  597. ref.compile()(in_mat, roi, ov_age, ov_gender);
  598. // G-API
  599. auto comp = AGNetROIGenComp::create();
  600. auto pp = AGNetROIGenComp::params(xml_path, bin_path, device);
  601. comp.apply(cv::gin(in_mat, roi), cv::gout(gapi_age, gapi_gender),
  602. cv::compile_args(cv::gapi::networks(pp)));
  603. // Assert
  604. validate();
  605. }
  606. TEST_F(TestAgeGenderOV, InferROIGeneric_ThrowIncorrectLayout) {
  607. const auto in_mat = getRandomImage({300, 300});
  608. cv::Rect roi(cv::Rect(cv::Point{64, 60}, cv::Size{96, 96}));
  609. // G-API
  610. auto comp = AGNetROIGenComp::create();
  611. auto pp = AGNetROIGenComp::params(xml_path, bin_path, device);
  612. pp.cfgInputTensorLayout("NCHW");
  613. EXPECT_ANY_THROW(comp.apply(cv::gin(in_mat, roi), cv::gout(gapi_age, gapi_gender),
  614. cv::compile_args(cv::gapi::networks(pp))));
  615. }
  616. TEST_F(TestAgeGenderOV, InferROIGeneric_ThrowTensorInput) {
  617. const auto in_mat = getRandomTensor({1, 3, 62, 62}, CV_32F);
  618. cv::Rect roi(cv::Rect(cv::Point{64, 60}, cv::Size{96, 96}));
  619. // G-API
  620. auto comp = AGNetROIGenComp::create();
  621. auto pp = AGNetROIGenComp::params(xml_path, bin_path, device);
  622. EXPECT_ANY_THROW(comp.apply(cv::gin(in_mat, roi), cv::gout(gapi_age, gapi_gender),
  623. cv::compile_args(cv::gapi::networks(pp))));
  624. }
  625. TEST_F(TestAgeGenderOV, InferROIGeneric_ThrowExplicitResize) {
  626. const auto in_mat = getRandomImage({300, 300});
  627. cv::Rect roi(cv::Rect(cv::Point{64, 60}, cv::Size{96, 96}));
  628. // G-API
  629. auto comp = AGNetROIGenComp::create();
  630. auto pp = AGNetROIGenComp::params(xml_path, bin_path, device);
  631. pp.cfgResize(cv::INTER_LINEAR);
  632. EXPECT_ANY_THROW(comp.apply(cv::gin(in_mat, roi), cv::gout(gapi_age, gapi_gender),
  633. cv::compile_args(cv::gapi::networks(pp))));
  634. }
  635. TEST_F(TestAgeGenderListOV, InferListGeneric_Image) {
  636. const auto in_mat = getRandomImage({300, 300});
  637. // OpenVINO
  638. AGNetOVComp ref(xml_path, bin_path, device);
  639. ref.cfgPrePostProcessing([](ov::preprocess::PrePostProcessor &ppp) {
  640. ppp.input().tensor().set_element_type(ov::element::u8);
  641. ppp.input().tensor().set_layout("NHWC");
  642. });
  643. ref.compile()(in_mat, roi_list, ov_age, ov_gender);
  644. // G-API
  645. auto comp = AGNetListGenComp::create();
  646. auto pp = AGNetListGenComp::params(xml_path, bin_path, device);
  647. comp.apply(cv::gin(in_mat, roi_list), cv::gout(gapi_age, gapi_gender),
  648. cv::compile_args(cv::gapi::networks(pp)));
  649. // Assert
  650. validate();
  651. }
  652. TEST_F(TestAgeGenderListOV, InferList2Generic_Image) {
  653. const auto in_mat = getRandomImage({300, 300});
  654. // OpenVINO
  655. AGNetOVComp ref(xml_path, bin_path, device);
  656. ref.cfgPrePostProcessing([](ov::preprocess::PrePostProcessor &ppp) {
  657. ppp.input().tensor().set_element_type(ov::element::u8);
  658. ppp.input().tensor().set_layout("NHWC");
  659. });
  660. ref.compile()(in_mat, roi_list, ov_age, ov_gender);
  661. // G-API
  662. auto comp = AGNetList2GenComp::create();
  663. auto pp = AGNetList2GenComp::params(xml_path, bin_path, device);
  664. comp.apply(cv::gin(in_mat, roi_list), cv::gout(gapi_age, gapi_gender),
  665. cv::compile_args(cv::gapi::networks(pp)));
  666. // Assert
  667. validate();
  668. }
  669. static ov::element::Type toOV(int depth) {
  670. switch (depth) {
  671. case CV_8U: return ov::element::u8;
  672. case CV_32S: return ov::element::i32;
  673. case CV_32F: return ov::element::f32;
  674. case CV_16F: return ov::element::f16;
  675. default: GAPI_Error("OV Backend: Unsupported data type");
  676. }
  677. return ov::element::dynamic;
  678. }
  679. struct TestMeanScaleOV : public ::testing::TestWithParam<int>{
  680. G_API_NET(IdentityNet, <cv::GMat(cv::GMat)>, "test-identity-net");
  681. static cv::GComputation create() {
  682. cv::GMat in;
  683. cv::GMat out;
  684. out = cv::gapi::infer<IdentityNet>(in);
  685. return cv::GComputation{cv::GIn(in), cv::GOut(out)};
  686. }
  687. using Params = cv::gapi::ov::Params<IdentityNet>;
  688. static Params params(const std::string &xml_path,
  689. const std::string &bin_path,
  690. const std::string &device) {
  691. return Params {
  692. xml_path, bin_path, device
  693. }.cfgInputModelLayout("NHWC")
  694. .cfgOutputLayers({ "output" });
  695. }
  696. TestMeanScaleOV() {
  697. initDLDTDataPath();
  698. m_model_path = findDataFile("gapi/ov/identity_net_100x100.xml");
  699. m_weights_path = findDataFile("gapi/ov/identity_net_100x100.bin");
  700. m_device_id = "CPU";
  701. m_ov_model = cv::gapi::ov::wrap::getCore()
  702. .read_model(m_model_path, m_weights_path);
  703. auto input_depth = GetParam();
  704. auto input = cv::imread(findDataFile("gapi/gapi_logo.jpg"));
  705. input.convertTo(m_in_mat, input_depth);
  706. }
  707. void addPreprocToOV(
  708. std::function<void(ov::preprocess::PrePostProcessor&)> f) {
  709. auto input_depth = GetParam();
  710. ov::preprocess::PrePostProcessor ppp(m_ov_model);
  711. ppp.input().tensor().set_layout(ov::Layout("NHWC"))
  712. .set_element_type(toOV(input_depth))
  713. .set_shape({ 1, 100, 100, 3 });
  714. ppp.input().model().set_layout(ov::Layout("NHWC"));
  715. f(ppp);
  716. m_ov_model = ppp.build();
  717. }
  718. void runOV() {
  719. auto compiled_model = cv::gapi::ov::wrap::getCore()
  720. .compile_model(m_ov_model, m_device_id);
  721. auto infer_request = compiled_model.create_infer_request();
  722. auto input_tensor = infer_request.get_input_tensor();
  723. cv::gapi::ov::util::to_ov(m_in_mat, input_tensor);
  724. infer_request.infer();
  725. auto out_tensor = infer_request.get_tensor("output");
  726. m_out_mat_ov.create(cv::gapi::ov::util::to_ocv(out_tensor.get_shape()),
  727. cv::gapi::ov::util::to_ocv(out_tensor.get_element_type()));
  728. cv::gapi::ov::util::to_ocv(out_tensor, m_out_mat_ov);
  729. }
  730. std::string m_model_path;
  731. std::string m_weights_path;
  732. std::string m_device_id;
  733. std::shared_ptr<ov::Model> m_ov_model;
  734. cv::Mat m_in_mat;
  735. cv::Mat m_out_mat_gapi;
  736. cv::Mat m_out_mat_ov;
  737. };
  738. TEST_P(TestMeanScaleOV, Mean)
  739. {
  740. int input_depth = GetParam();
  741. std::vector<float> mean_values{ 220.1779, 218.9857, 217.8986 };
  742. // Run OV reference pipeline:
  743. {
  744. addPreprocToOV([&](ov::preprocess::PrePostProcessor& ppp) {
  745. if (input_depth == CV_8U || input_depth == CV_32S) {
  746. ppp.input().preprocess().convert_element_type(ov::element::f32);
  747. }
  748. ppp.input().preprocess().mean(mean_values);
  749. });
  750. runOV();
  751. }
  752. // Run G-API
  753. GComputation comp = create();
  754. auto pp = params(m_model_path, m_weights_path, m_device_id);
  755. pp.cfgMean(mean_values);
  756. comp.apply(cv::gin(m_in_mat), cv::gout(m_out_mat_gapi),
  757. cv::compile_args(cv::gapi::networks(pp)));
  758. // Validate OV results against G-API ones:
  759. normAssert(m_out_mat_ov, m_out_mat_gapi, "Test output");
  760. }
  761. TEST_P(TestMeanScaleOV, Scale)
  762. {
  763. int input_depth = GetParam();
  764. std::vector<float> scale_values{ 2., 2., 2. };
  765. // Run OV reference pipeline:
  766. {
  767. addPreprocToOV([&](ov::preprocess::PrePostProcessor& ppp) {
  768. if (input_depth == CV_8U || input_depth == CV_32S) {
  769. ppp.input().preprocess().convert_element_type(ov::element::f32);
  770. }
  771. ppp.input().preprocess().scale(scale_values);
  772. });
  773. runOV();
  774. }
  775. // Run G-API
  776. GComputation comp = create();
  777. auto pp = params(m_model_path, m_weights_path, m_device_id);
  778. pp.cfgScale(scale_values);
  779. comp.apply(cv::gin(m_in_mat), cv::gout(m_out_mat_gapi),
  780. cv::compile_args(cv::gapi::networks(pp)));
  781. // Validate OV results against G-API ones:
  782. normAssert(m_out_mat_ov, m_out_mat_gapi, "Test output");
  783. }
  784. TEST_P(TestMeanScaleOV, MeanAndScale)
  785. {
  786. int input_depth = GetParam();
  787. std::vector<float> mean_values{ 220.1779, 218.9857, 217.8986 };
  788. std::vector<float> scale_values{ 2., 2., 2. };
  789. // Run OV reference pipeline:
  790. {
  791. addPreprocToOV([&](ov::preprocess::PrePostProcessor& ppp) {
  792. if (input_depth == CV_8U || input_depth == CV_32S) {
  793. ppp.input().preprocess().convert_element_type(ov::element::f32);
  794. }
  795. ppp.input().preprocess().mean(mean_values);
  796. ppp.input().preprocess().scale(scale_values);
  797. });
  798. runOV();
  799. }
  800. // Run G-API
  801. GComputation comp = create();
  802. auto pp = params(m_model_path, m_weights_path, m_device_id);
  803. pp.cfgMean(mean_values);
  804. pp.cfgScale(scale_values);
  805. comp.apply(cv::gin(m_in_mat), cv::gout(m_out_mat_gapi),
  806. cv::compile_args(cv::gapi::networks(pp)));
  807. // Validate OV results against G-API ones:
  808. normAssert(m_out_mat_ov, m_out_mat_gapi, "Test output");
  809. }
  810. INSTANTIATE_TEST_CASE_P(Instantiation, TestMeanScaleOV,
  811. Values(CV_8U, CV_32S, CV_16F, CV_32F));
  812. } // namespace opencv_test
  813. #endif // HAVE_INF_ENGINE && INF_ENGINE_RELEASE >= 2022010000