gapi_infer_onnx_test.cpp 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107
  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) 2020 Intel Corporation
  6. #include "../test_precomp.hpp"
  7. #ifdef HAVE_ONNX
  8. #include <stdexcept>
  9. #include <codecvt> // wstring_convert
  10. #include <onnxruntime_cxx_api.h>
  11. #include <ade/util/iota_range.hpp>
  12. #include <ade/util/algorithm.hpp>
  13. #include <opencv2/gapi/own/convert.hpp>
  14. #include <opencv2/gapi/infer/onnx.hpp>
  15. namespace {
  16. class TestMediaBGR final: public cv::MediaFrame::IAdapter {
  17. cv::Mat m_mat;
  18. using Cb = cv::MediaFrame::View::Callback;
  19. Cb m_cb;
  20. public:
  21. explicit TestMediaBGR(cv::Mat m, Cb cb = [](){})
  22. : m_mat(m), m_cb(cb) {
  23. }
  24. cv::GFrameDesc meta() const override {
  25. return cv::GFrameDesc{cv::MediaFormat::BGR, cv::Size(m_mat.cols, m_mat.rows)};
  26. }
  27. cv::MediaFrame::View access(cv::MediaFrame::Access) override {
  28. cv::MediaFrame::View::Ptrs pp = { m_mat.ptr(), nullptr, nullptr, nullptr };
  29. cv::MediaFrame::View::Strides ss = { m_mat.step, 0u, 0u, 0u };
  30. return cv::MediaFrame::View(std::move(pp), std::move(ss), Cb{m_cb});
  31. }
  32. };
  33. class TestMediaNV12 final: public cv::MediaFrame::IAdapter {
  34. cv::Mat m_y;
  35. cv::Mat m_uv;
  36. public:
  37. TestMediaNV12(cv::Mat y, cv::Mat uv) : m_y(y), m_uv(uv) {
  38. }
  39. cv::GFrameDesc meta() const override {
  40. return cv::GFrameDesc{cv::MediaFormat::NV12, cv::Size(m_y.cols, m_y.rows)};
  41. }
  42. cv::MediaFrame::View access(cv::MediaFrame::Access) override {
  43. cv::MediaFrame::View::Ptrs pp = {
  44. m_y.ptr(), m_uv.ptr(), nullptr, nullptr
  45. };
  46. cv::MediaFrame::View::Strides ss = {
  47. m_y.step, m_uv.step, 0u, 0u
  48. };
  49. return cv::MediaFrame::View(std::move(pp), std::move(ss));
  50. }
  51. };
  52. struct ONNXInitPath {
  53. ONNXInitPath() {
  54. const char* env_path = getenv("OPENCV_GAPI_ONNX_MODEL_PATH");
  55. if (env_path) {
  56. cvtest::addDataSearchPath(env_path);
  57. }
  58. }
  59. };
  60. static ONNXInitPath g_init_path;
  61. cv::Mat initMatrixRandU(const int type, const cv::Size& sz_in) {
  62. const cv::Mat in_mat = cv::Mat(sz_in, type);
  63. if (CV_MAT_DEPTH(type) < CV_32F) {
  64. cv::randu(in_mat, cv::Scalar::all(0), cv::Scalar::all(255));
  65. } else {
  66. const int fscale = 256; // avoid bits near ULP, generate stable test input
  67. cv::Mat in_mat32s(in_mat.size(), CV_MAKE_TYPE(CV_32S, CV_MAT_CN(type)));
  68. cv::randu(in_mat32s, cv::Scalar::all(0), cv::Scalar::all(255 * fscale));
  69. in_mat32s.convertTo(in_mat, type, 1.0f / fscale, 0);
  70. }
  71. return in_mat;
  72. }
  73. } // anonymous namespace
  74. namespace opencv_test
  75. {
  76. namespace {
  77. // FIXME: taken from the DNN module
  78. void normAssert(cv::InputArray& ref, cv::InputArray& test,
  79. const char *comment /*= ""*/,
  80. const double l1 = 0.00001, const double lInf = 0.0001) {
  81. const double normL1 = cvtest::norm(ref, test, cv::NORM_L1) / ref.getMat().total();
  82. EXPECT_LE(normL1, l1) << comment;
  83. const double normInf = cvtest::norm(ref, test, cv::NORM_INF);
  84. EXPECT_LE(normInf, lInf) << comment;
  85. }
  86. inline std::string findModel(const std::string &model_name) {
  87. return findDataFile("vision/" + model_name + ".onnx", false);
  88. }
  89. inline void toCHW(const cv::Mat& src, cv::Mat& dst) {
  90. dst.create(cv::Size(src.cols, src.rows * src.channels()), CV_32F);
  91. std::vector<cv::Mat> planes;
  92. for (int i = 0; i < src.channels(); ++i) {
  93. planes.push_back(dst.rowRange(i * src.rows, (i + 1) * src.rows));
  94. }
  95. cv::split(src, planes);
  96. }
  97. inline int toCV(ONNXTensorElementDataType prec) {
  98. switch (prec) {
  99. case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8: return CV_8U;
  100. case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT: return CV_32F;
  101. case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32: return CV_32S;
  102. case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64: return CV_32S;
  103. default: GAPI_Assert(false && "Unsupported data type");
  104. }
  105. return -1;
  106. }
  107. void copyFromONNX(Ort::Value &v, cv::Mat& mat) {
  108. const auto info = v.GetTensorTypeAndShapeInfo();
  109. const auto prec = info.GetElementType();
  110. const auto shape = info.GetShape();
  111. const std::vector<int> dims(shape.begin(), shape.end());
  112. mat.create(dims, toCV(prec));
  113. switch (prec) {
  114. #define HANDLE(E,T) \
  115. case E: std::copy_n(v.GetTensorMutableData<T>(), \
  116. mat.total(), \
  117. reinterpret_cast<T*>(mat.data)); \
  118. break;
  119. HANDLE(ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8, uint8_t);
  120. HANDLE(ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, float);
  121. HANDLE(ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32, int);
  122. #undef HANDLE
  123. case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64: {
  124. const auto o_ptr = v.GetTensorMutableData<int64_t>();
  125. const auto g_ptr = reinterpret_cast<int*>(mat.data);
  126. std::transform(o_ptr, o_ptr + mat.total(), g_ptr,
  127. [](int64_t el) { return static_cast<int>(el); });
  128. break;
  129. }
  130. default: GAPI_Assert(false && "ONNX. Unsupported data type");
  131. }
  132. }
  133. inline std::vector<int64_t> toORT(const cv::MatSize &sz) {
  134. return cv::to_own<int64_t>(sz);
  135. }
  136. inline std::vector<const char*> getCharNames(const std::vector<std::string>& names) {
  137. std::vector<const char*> out_ptrs;
  138. out_ptrs.reserve(names.size());
  139. ade::util::transform(names, std::back_inserter(out_ptrs),
  140. [](const std::string& name) { return name.c_str(); });
  141. return out_ptrs;
  142. }
  143. template<typename T>
  144. void copyToOut(const cv::Mat& onnx_out, const T end_mark, cv::Mat& gapi_out) {
  145. // This function is part of some remap__ function.
  146. // You can set graph output size (gapi_out) larger than real out from ONNX
  147. // so you have to add something for separate correct data and garbage.
  148. // For example, end of data can be marked with -1 (for positive values)
  149. // or you can put size of correct data at first/last element of output matrix.
  150. const size_t size = std::min(onnx_out.total(), gapi_out.total());
  151. std::copy(onnx_out.begin<T>(),
  152. onnx_out.begin<T>() + size,
  153. gapi_out.begin<T>());
  154. if (gapi_out.total() > onnx_out.total()) {
  155. T* gptr = gapi_out.ptr<T>();
  156. gptr[size] = end_mark;
  157. }
  158. }
  159. void remapYolo(const std::unordered_map<std::string, cv::Mat> &onnx,
  160. std::unordered_map<std::string, cv::Mat> &gapi) {
  161. GAPI_Assert(onnx.size() == 1u);
  162. GAPI_Assert(gapi.size() == 1u);
  163. // Result from Run method
  164. const cv::Mat& in = onnx.begin()->second;
  165. GAPI_Assert(in.depth() == CV_32F);
  166. // Configured output
  167. cv::Mat& out = gapi.begin()->second;
  168. // Simple copy
  169. copyToOut<float>(in, -1.f, out);
  170. }
  171. void remapYoloV3(const std::unordered_map<std::string, cv::Mat> &onnx,
  172. std::unordered_map<std::string, cv::Mat> &gapi) {
  173. // Simple copy for outputs
  174. const cv::Mat& in_boxes = onnx.at("yolonms_layer_1/ExpandDims_1:0");
  175. const cv::Mat& in_scores = onnx.at("yolonms_layer_1/ExpandDims_3:0");
  176. const cv::Mat& in_indices = onnx.at("yolonms_layer_1/concat_2:0");
  177. GAPI_Assert(in_boxes.depth() == CV_32F);
  178. GAPI_Assert(in_scores.depth() == CV_32F);
  179. GAPI_Assert(in_indices.depth() == CV_32S);
  180. cv::Mat& out_boxes = gapi.at("out1");
  181. cv::Mat& out_scores = gapi.at("out2");
  182. cv::Mat& out_indices = gapi.at("out3");
  183. copyToOut<float>(in_boxes, -1.f, out_boxes);
  184. copyToOut<float>(in_scores, -1.f, out_scores);
  185. copyToOut<int>(in_indices, -1, out_indices);
  186. }
  187. void remapToIESSDOut(const std::vector<cv::Mat> &detections,
  188. cv::Mat &ssd_output) {
  189. GAPI_Assert(detections.size() == 4u);
  190. for (const auto &det_el : detections) {
  191. GAPI_Assert(det_el.depth() == CV_32F);
  192. GAPI_Assert(!det_el.empty());
  193. }
  194. // SSD-MobilenetV1 structure check
  195. ASSERT_EQ(1u, detections[0].total());
  196. ASSERT_EQ(detections[2].total(), detections[0].total() * 100);
  197. ASSERT_EQ(detections[2].total(), detections[3].total());
  198. ASSERT_EQ((detections[2].total() * 4), detections[1].total());
  199. const int num_objects = static_cast<int>(detections[0].ptr<float>()[0]);
  200. GAPI_Assert(num_objects <= (ssd_output.size[2] - 1));
  201. const float *in_boxes = detections[1].ptr<float>();
  202. const float *in_scores = detections[2].ptr<float>();
  203. const float *in_classes = detections[3].ptr<float>();
  204. float *ptr = ssd_output.ptr<float>();
  205. for (int i = 0; i < num_objects; ++i) {
  206. ptr[0] = 0.f; // "image_id"
  207. ptr[1] = in_classes[i]; // "label"
  208. ptr[2] = in_scores[i]; // "confidence"
  209. ptr[3] = in_boxes[4 * i + 1]; // left
  210. ptr[4] = in_boxes[4 * i + 0]; // top
  211. ptr[5] = in_boxes[4 * i + 3]; // right
  212. ptr[6] = in_boxes[4 * i + 2]; // bottom
  213. ptr += 7;
  214. in_boxes += 4;
  215. }
  216. if (num_objects < ssd_output.size[2] - 1) {
  217. // put a -1 mark at the end of output blob if there is space left
  218. ptr[0] = -1.f;
  219. }
  220. }
  221. void remapSSDPorts(const std::unordered_map<std::string, cv::Mat> &onnx,
  222. std::unordered_map<std::string, cv::Mat> &gapi) {
  223. // Assemble ONNX-processed outputs back to a single 1x1x200x7 blob
  224. // to preserve compatibility with OpenVINO-based SSD pipeline
  225. const cv::Mat &num_detections = onnx.at("num_detections:0");
  226. const cv::Mat &detection_boxes = onnx.at("detection_boxes:0");
  227. const cv::Mat &detection_scores = onnx.at("detection_scores:0");
  228. const cv::Mat &detection_classes = onnx.at("detection_classes:0");
  229. cv::Mat &ssd_output = gapi.at("detection_output");
  230. remapToIESSDOut({num_detections, detection_boxes, detection_scores, detection_classes}, ssd_output);
  231. }
  232. void reallocSSDPort(const std::unordered_map<std::string, cv::Mat> &/*onnx*/,
  233. std::unordered_map<std::string, cv::Mat> &gapi) {
  234. gapi["detection_boxes"].create(1000, 3000, CV_32FC3);
  235. }
  236. void remapRCNNPortsC(const std::unordered_map<std::string, cv::Mat> &onnx,
  237. std::unordered_map<std::string, cv::Mat> &gapi) {
  238. // Simple copy for outputs
  239. const cv::Mat& in_boxes = onnx.at("6379");
  240. const cv::Mat& in_labels = onnx.at("6381");
  241. const cv::Mat& in_scores = onnx.at("6383");
  242. GAPI_Assert(in_boxes.depth() == CV_32F);
  243. GAPI_Assert(in_labels.depth() == CV_32S);
  244. GAPI_Assert(in_scores.depth() == CV_32F);
  245. cv::Mat& out_boxes = gapi.at("out1");
  246. cv::Mat& out_labels = gapi.at("out2");
  247. cv::Mat& out_scores = gapi.at("out3");
  248. copyToOut<float>(in_boxes, -1.f, out_boxes);
  249. copyToOut<int>(in_labels, -1, out_labels);
  250. copyToOut<float>(in_scores, -1.f, out_scores);
  251. }
  252. void remapRCNNPortsDO(const std::unordered_map<std::string, cv::Mat> &onnx,
  253. std::unordered_map<std::string, cv::Mat> &gapi) {
  254. // Simple copy for outputs
  255. const cv::Mat& in_boxes = onnx.at("6379");
  256. const cv::Mat& in_scores = onnx.at("6383");
  257. GAPI_Assert(in_boxes.depth() == CV_32F);
  258. GAPI_Assert(in_scores.depth() == CV_32F);
  259. cv::Mat& out_boxes = gapi.at("out1");
  260. cv::Mat& out_scores = gapi.at("out2");
  261. copyToOut<float>(in_boxes, -1.f, out_boxes);
  262. copyToOut<float>(in_scores, -1.f, out_scores);
  263. }
  264. class ONNXtest : public ::testing::Test {
  265. public:
  266. std::string model_path;
  267. size_t num_in, num_out;
  268. std::vector<cv::Mat> out_gapi;
  269. std::vector<cv::Mat> out_onnx;
  270. cv::Mat in_mat;
  271. ONNXtest() {
  272. env = Ort::Env(ORT_LOGGING_LEVEL_WARNING, "test");
  273. memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
  274. out_gapi.resize(1);
  275. }
  276. template<typename T>
  277. void infer(const std::vector<cv::Mat>& ins,
  278. std::vector<cv::Mat>& outs,
  279. std::vector<std::string>&& custom_out_names = {}) {
  280. // Prepare session
  281. #ifndef _WIN32
  282. session = Ort::Session(env, model_path.c_str(), session_options);
  283. #else
  284. std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
  285. std::wstring w_model_path = converter.from_bytes(model_path.c_str());
  286. session = Ort::Session(env, w_model_path.c_str(), session_options);
  287. #endif
  288. num_in = session.GetInputCount();
  289. num_out = session.GetOutputCount();
  290. GAPI_Assert(num_in == ins.size());
  291. in_node_names.clear();
  292. out_node_names.clear();
  293. // Inputs Run params
  294. std::vector<Ort::Value> in_tensors;
  295. for(size_t i = 0; i < num_in; ++i) {
  296. char* in_node_name_p = session.GetInputName(i, allocator);
  297. in_node_names.emplace_back(in_node_name_p);
  298. allocator.Free(in_node_name_p);
  299. in_node_dims = toORT(ins[i].size);
  300. in_tensors.emplace_back(Ort::Value::CreateTensor<T>(memory_info,
  301. const_cast<T*>(ins[i].ptr<T>()),
  302. ins[i].total(),
  303. in_node_dims.data(),
  304. in_node_dims.size()));
  305. }
  306. // Outputs Run params
  307. if (custom_out_names.empty()) {
  308. for(size_t i = 0; i < num_out; ++i) {
  309. char* out_node_name_p = session.GetOutputName(i, allocator);
  310. out_node_names.emplace_back(out_node_name_p);
  311. allocator.Free(out_node_name_p);
  312. }
  313. } else {
  314. out_node_names = std::move(custom_out_names);
  315. }
  316. // Input/output order by names
  317. const auto in_run_names = getCharNames(in_node_names);
  318. const auto out_run_names = getCharNames(out_node_names);
  319. num_out = out_run_names.size();
  320. // Run
  321. auto result = session.Run(Ort::RunOptions{nullptr},
  322. in_run_names.data(),
  323. &in_tensors.front(),
  324. num_in,
  325. out_run_names.data(),
  326. num_out);
  327. // Copy outputs
  328. GAPI_Assert(result.size() == num_out);
  329. for (size_t i = 0; i < num_out; ++i) {
  330. const auto info = result[i].GetTensorTypeAndShapeInfo();
  331. const auto shape = info.GetShape();
  332. const auto type = toCV(info.GetElementType());
  333. const std::vector<int> dims(shape.begin(), shape.end());
  334. outs.emplace_back(dims, type);
  335. copyFromONNX(result[i], outs.back());
  336. }
  337. }
  338. // One input/output overload
  339. template<typename T>
  340. void infer(const cv::Mat& in, cv::Mat& out) {
  341. std::vector<cv::Mat> result;
  342. infer<T>(std::vector<cv::Mat>{in}, result);
  343. GAPI_Assert(result.size() == 1u);
  344. out = result.front();
  345. }
  346. // One input overload
  347. template<typename T>
  348. void infer(const cv::Mat& in,
  349. std::vector<cv::Mat>& outs,
  350. std::vector<std::string>&& custom_out_names = {}) {
  351. infer<T>(std::vector<cv::Mat>{in}, outs, std::move(custom_out_names));
  352. }
  353. void validate() {
  354. GAPI_Assert(!out_gapi.empty() && !out_onnx.empty());
  355. ASSERT_EQ(out_gapi.size(), out_onnx.size());
  356. const auto size = out_gapi.size();
  357. for (size_t i = 0; i < size; ++i) {
  358. normAssert(out_onnx[i], out_gapi[i], "Test outputs");
  359. }
  360. }
  361. void useModel(const std::string& model_name) {
  362. model_path = findModel(model_name);
  363. }
  364. private:
  365. Ort::Env env{nullptr};
  366. Ort::MemoryInfo memory_info{nullptr};
  367. Ort::AllocatorWithDefaultOptions allocator;
  368. Ort::SessionOptions session_options;
  369. Ort::Session session{nullptr};
  370. std::vector<int64_t> in_node_dims;
  371. std::vector<std::string> in_node_names;
  372. std::vector<std::string> out_node_names;
  373. };
  374. class ONNXClassification : public ONNXtest {
  375. public:
  376. const cv::Scalar mean = { 0.485, 0.456, 0.406 };
  377. const cv::Scalar std = { 0.229, 0.224, 0.225 };
  378. // Rois for InferList, InferList2
  379. const std::vector<cv::Rect> rois = {
  380. cv::Rect(cv::Point{ 0, 0}, cv::Size{80, 120}),
  381. cv::Rect(cv::Point{50, 100}, cv::Size{250, 360})
  382. };
  383. void preprocess(const cv::Mat& src, cv::Mat& dst) {
  384. const int new_h = 224;
  385. const int new_w = 224;
  386. cv::Mat tmp, cvt, rsz;
  387. cv::resize(src, rsz, cv::Size(new_w, new_h));
  388. rsz.convertTo(cvt, CV_32F, 1.f / 255);
  389. tmp = (cvt - mean) / std;
  390. toCHW(tmp, dst);
  391. dst = dst.reshape(1, {1, 3, new_h, new_w});
  392. }
  393. };
  394. class ONNXMediaFrame : public ONNXClassification {
  395. public:
  396. const std::vector<cv::Rect> rois = {
  397. cv::Rect(cv::Point{ 0, 0}, cv::Size{80, 120}),
  398. cv::Rect(cv::Point{50, 100}, cv::Size{250, 360}),
  399. cv::Rect(cv::Point{70, 10}, cv::Size{20, 260}),
  400. cv::Rect(cv::Point{5, 15}, cv::Size{200, 160}),
  401. };
  402. const cv::Size sz{640, 480};
  403. const cv::Mat m_in_y = initMatrixRandU(CV_8UC1, sz);
  404. const cv::Mat m_in_uv = initMatrixRandU(CV_8UC2, sz / 2);
  405. };
  406. class ONNXGRayScale : public ONNXtest {
  407. public:
  408. void preprocess(const cv::Mat& src, cv::Mat& dst) {
  409. const int new_h = 64;
  410. const int new_w = 64;
  411. cv::Mat cvc, rsz, cvt;
  412. cv::cvtColor(src, cvc, cv::COLOR_BGR2GRAY);
  413. cv::resize(cvc, rsz, cv::Size(new_w, new_h));
  414. rsz.convertTo(cvt, CV_32F);
  415. toCHW(cvt, dst);
  416. dst = dst.reshape(1, {1, 1, new_h, new_w});
  417. }
  418. };
  419. class ONNXWithRemap : public ONNXtest {
  420. private:
  421. size_t step_by_outs = 0;
  422. public:
  423. // This function checks each next cv::Mat in out_gapi vector for next call.
  424. // end_mark is edge of correct data
  425. template <typename T>
  426. void validate(const T end_mark) {
  427. GAPI_Assert(!out_gapi.empty() && !out_onnx.empty());
  428. ASSERT_EQ(out_gapi.size(), out_onnx.size());
  429. GAPI_Assert(step_by_outs < out_gapi.size());
  430. const T* op = out_onnx.at(step_by_outs).ptr<T>();
  431. const T* gp = out_gapi.at(step_by_outs).ptr<T>();
  432. // Checking that graph output larger than onnx output
  433. const auto out_size = std::min(out_onnx.at(step_by_outs).total(), out_gapi.at(step_by_outs).total());
  434. GAPI_Assert(out_size != 0u);
  435. for (size_t d_idx = 0; d_idx < out_size; ++d_idx) {
  436. if (gp[d_idx] == end_mark) break;
  437. ASSERT_EQ(op[d_idx], gp[d_idx]);
  438. }
  439. ++step_by_outs;
  440. }
  441. };
  442. class ONNXRCNN : public ONNXWithRemap {
  443. private:
  444. const cv::Scalar rcnn_mean = { 102.9801, 115.9465, 122.7717 };
  445. const float range_max = 1333;
  446. const float range_min = 800;
  447. public:
  448. void preprocess(const cv::Mat& src, cv::Mat& dst) {
  449. cv::Mat rsz, cvt, chw, mn;
  450. const auto get_ratio = [&](const int dim) -> float {
  451. return ((dim > range_max) || (dim < range_min))
  452. ? dim > range_max
  453. ? range_max / dim
  454. : range_min / dim
  455. : 1.f;
  456. };
  457. const auto ratio_h = get_ratio(src.rows);
  458. const auto ratio_w = get_ratio(src.cols);
  459. const auto new_h = static_cast<int>(ratio_h * src.rows);
  460. const auto new_w = static_cast<int>(ratio_w * src.cols);
  461. cv::resize(src, rsz, cv::Size(new_w, new_h));
  462. rsz.convertTo(cvt, CV_32F, 1.f);
  463. toCHW(cvt, chw);
  464. mn = chw - rcnn_mean;
  465. const int padded_h = std::ceil(new_h / 32.f) * 32;
  466. const int padded_w = std::ceil(new_w / 32.f) * 32;
  467. cv::Mat pad_im(cv::Size(padded_w, 3 * padded_h), CV_32F, 0.f);
  468. pad_im(cv::Rect(0, 0, mn.cols, mn.rows)) += mn;
  469. dst = pad_im.reshape(1, {3, padded_h, padded_w});
  470. }
  471. };
  472. class ONNXYoloV3 : public ONNXWithRemap {
  473. public:
  474. std::vector<cv::Mat> ins;
  475. void constructYoloInputs(const cv::Mat& src) {
  476. const int yolo_in_h = 416;
  477. const int yolo_in_w = 416;
  478. cv::Mat yolov3_input, shape, prep_mat;
  479. cv::resize(src, yolov3_input, cv::Size(yolo_in_w, yolo_in_h));
  480. shape.create(cv::Size(2, 1), CV_32F);
  481. float* ptr = shape.ptr<float>();
  482. ptr[0] = src.cols;
  483. ptr[1] = src.rows;
  484. preprocess(yolov3_input, prep_mat);
  485. ins = {prep_mat, shape};
  486. }
  487. private:
  488. void preprocess(const cv::Mat& src, cv::Mat& dst) {
  489. cv::Mat cvt;
  490. src.convertTo(cvt, CV_32F, 1.f / 255.f);
  491. toCHW(cvt, dst);
  492. dst = dst.reshape(1, {1, 3, 416, 416});
  493. }
  494. };
  495. } // anonymous namespace
  496. TEST_F(ONNXClassification, Infer)
  497. {
  498. useModel("classification/squeezenet/model/squeezenet1.0-9");
  499. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  500. // ONNX_API code
  501. cv::Mat processed_mat;
  502. preprocess(in_mat, processed_mat);
  503. infer<float>(processed_mat, out_onnx);
  504. // G_API code
  505. G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
  506. cv::GMat in;
  507. cv::GMat out = cv::gapi::infer<SqueezNet>(in);
  508. cv::GComputation comp(cv::GIn(in), cv::GOut(out));
  509. // NOTE: We have to normalize U8 tensor
  510. // so cfgMeanStd() is here
  511. auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
  512. comp.apply(cv::gin(in_mat),
  513. cv::gout(out_gapi.front()),
  514. cv::compile_args(cv::gapi::networks(net)));
  515. // Validate
  516. validate();
  517. }
  518. TEST_F(ONNXClassification, InferTensor)
  519. {
  520. useModel("classification/squeezenet/model/squeezenet1.0-9");
  521. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  522. // Create tensor
  523. cv::Mat tensor;
  524. preprocess(in_mat, tensor);
  525. // ONNX_API code
  526. infer<float>(tensor, out_onnx);
  527. // G_API code
  528. G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
  529. cv::GMat in;
  530. cv::GMat out = cv::gapi::infer<SqueezNet>(in);
  531. cv::GComputation comp(cv::GIn(in), cv::GOut(out));
  532. auto net = cv::gapi::onnx::Params<SqueezNet> { model_path };
  533. comp.apply(cv::gin(tensor),
  534. cv::gout(out_gapi.front()),
  535. cv::compile_args(cv::gapi::networks(net)));
  536. // Validate
  537. validate();
  538. }
  539. TEST_F(ONNXClassification, InferROI)
  540. {
  541. useModel("classification/squeezenet/model/squeezenet1.0-9");
  542. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  543. const auto ROI = rois.at(0);
  544. // ONNX_API code
  545. cv::Mat roi_mat;
  546. preprocess(in_mat(ROI), roi_mat);
  547. infer<float>(roi_mat, out_onnx);
  548. // G_API code
  549. G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
  550. cv::GMat in;
  551. cv::GOpaque<cv::Rect> rect;
  552. cv::GMat out = cv::gapi::infer<SqueezNet>(rect, in);
  553. cv::GComputation comp(cv::GIn(in, rect), cv::GOut(out));
  554. // NOTE: We have to normalize U8 tensor
  555. // so cfgMeanStd() is here
  556. auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
  557. comp.apply(cv::gin(in_mat, ROI),
  558. cv::gout(out_gapi.front()),
  559. cv::compile_args(cv::gapi::networks(net)));
  560. // Validate
  561. validate();
  562. }
  563. TEST_F(ONNXClassification, InferROIList)
  564. {
  565. useModel("classification/squeezenet/model/squeezenet1.0-9");
  566. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  567. // ONNX_API code
  568. for (size_t i = 0; i < rois.size(); ++i) {
  569. cv::Mat roi_mat;
  570. preprocess(in_mat(rois[i]), roi_mat);
  571. infer<float>(roi_mat, out_onnx);
  572. }
  573. // G_API code
  574. G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
  575. cv::GMat in;
  576. cv::GArray<cv::Rect> rr;
  577. cv::GArray<cv::GMat> out = cv::gapi::infer<SqueezNet>(rr, in);
  578. cv::GComputation comp(cv::GIn(in, rr), cv::GOut(out));
  579. // NOTE: We have to normalize U8 tensor
  580. // so cfgMeanStd() is here
  581. auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
  582. comp.apply(cv::gin(in_mat, rois),
  583. cv::gout(out_gapi),
  584. cv::compile_args(cv::gapi::networks(net)));
  585. // Validate
  586. validate();
  587. }
  588. TEST_F(ONNXClassification, Infer2ROIList)
  589. {
  590. useModel("classification/squeezenet/model/squeezenet1.0-9");
  591. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  592. // ONNX_API code
  593. for (size_t i = 0; i < rois.size(); ++i) {
  594. cv::Mat roi_mat;
  595. preprocess(in_mat(rois[i]), roi_mat);
  596. infer<float>(roi_mat, out_onnx);
  597. }
  598. // G_API code
  599. G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
  600. cv::GMat in;
  601. cv::GArray<cv::Rect> rr;
  602. cv::GArray<cv::GMat> out = cv::gapi::infer2<SqueezNet>(in, rr);
  603. cv::GComputation comp(cv::GIn(in, rr), cv::GOut(out));
  604. // NOTE: We have to normalize U8 tensor
  605. // so cfgMeanStd() is here
  606. auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
  607. comp.apply(cv::gin(in_mat, rois),
  608. cv::gout(out_gapi),
  609. cv::compile_args(cv::gapi::networks(net)));
  610. // Validate
  611. validate();
  612. }
  613. TEST_F(ONNXWithRemap, InferDynamicInputTensor)
  614. {
  615. useModel("object_detection_segmentation/tiny-yolov2/model/tinyyolov2-8");
  616. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  617. // Create tensor
  618. cv::Mat cvt, rsz, tensor;
  619. cv::resize(in_mat, rsz, cv::Size{416, 416});
  620. rsz.convertTo(cvt, CV_32F, 1.f / 255.f);
  621. toCHW(cvt, tensor);
  622. tensor = tensor.reshape(1, {1, 3, 416, 416});
  623. // ONNX_API code
  624. infer<float>(tensor, out_onnx);
  625. // G_API code
  626. G_API_NET(YoloNet, <cv::GMat(cv::GMat)>, "YoloNet");
  627. cv::GMat in;
  628. cv::GMat out = cv::gapi::infer<YoloNet>(in);
  629. cv::GComputation comp(cv::GIn(in), cv::GOut(out));
  630. auto net = cv::gapi::onnx::Params<YoloNet>{ model_path }
  631. .cfgPostProc({cv::GMatDesc{CV_32F, {1, 125, 13, 13}}}, remapYolo)
  632. .cfgOutputLayers({"out"});
  633. comp.apply(cv::gin(tensor),
  634. cv::gout(out_gapi.front()),
  635. cv::compile_args(cv::gapi::networks(net)));
  636. // Validate
  637. validate<float>(-1.f);
  638. }
  639. TEST_F(ONNXGRayScale, InferImage)
  640. {
  641. useModel("body_analysis/emotion_ferplus/model/emotion-ferplus-8");
  642. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  643. // ONNX_API code
  644. cv::Mat prep_mat;
  645. preprocess(in_mat, prep_mat);
  646. infer<float>(prep_mat, out_onnx);
  647. // G_API code
  648. G_API_NET(EmotionNet, <cv::GMat(cv::GMat)>, "emotion-ferplus");
  649. cv::GMat in;
  650. cv::GMat out = cv::gapi::infer<EmotionNet>(in);
  651. cv::GComputation comp(cv::GIn(in), cv::GOut(out));
  652. auto net = cv::gapi::onnx::Params<EmotionNet> { model_path }
  653. .cfgNormalize({ false }); // model accepts 0..255 range in FP32;
  654. comp.apply(cv::gin(in_mat),
  655. cv::gout(out_gapi.front()),
  656. cv::compile_args(cv::gapi::networks(net)));
  657. // Validate
  658. validate();
  659. }
  660. TEST_F(ONNXWithRemap, InferMultiOutput)
  661. {
  662. useModel("object_detection_segmentation/ssd-mobilenetv1/model/ssd_mobilenet_v1_10");
  663. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  664. // ONNX_API code
  665. const auto prep_mat = in_mat.reshape(1, {1, in_mat.rows, in_mat.cols, in_mat.channels()});
  666. infer<uint8_t>(prep_mat, out_onnx);
  667. cv::Mat onnx_conv_out({1, 1, 200, 7}, CV_32F);
  668. remapToIESSDOut({out_onnx[3], out_onnx[0], out_onnx[2], out_onnx[1]}, onnx_conv_out);
  669. out_onnx.clear();
  670. out_onnx.push_back(onnx_conv_out);
  671. // G_API code
  672. G_API_NET(MobileNet, <cv::GMat(cv::GMat)>, "ssd_mobilenet");
  673. cv::GMat in;
  674. cv::GMat out = cv::gapi::infer<MobileNet>(in);
  675. cv::GComputation comp(cv::GIn(in), cv::GOut(out));
  676. auto net = cv::gapi::onnx::Params<MobileNet>{ model_path }
  677. .cfgOutputLayers({"detection_output"})
  678. .cfgPostProc({cv::GMatDesc{CV_32F, {1, 1, 200, 7}}}, remapSSDPorts);
  679. comp.apply(cv::gin(in_mat),
  680. cv::gout(out_gapi.front()),
  681. cv::compile_args(cv::gapi::networks(net)));
  682. // Validate
  683. validate<float>(-1.f);
  684. }
  685. TEST_F(ONNXMediaFrame, InferBGR)
  686. {
  687. useModel("classification/squeezenet/model/squeezenet1.0-9");
  688. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  689. // ONNX_API code
  690. cv::Mat processed_mat;
  691. preprocess(in_mat, processed_mat);
  692. infer<float>(processed_mat, out_onnx);
  693. // G_API code
  694. auto frame = MediaFrame::Create<TestMediaBGR>(in_mat);
  695. G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
  696. cv::GFrame in;
  697. cv::GMat out = cv::gapi::infer<SqueezNet>(in);
  698. cv::GComputation comp(cv::GIn(in), cv::GOut(out));
  699. // NOTE: We have to normalize U8 tensor
  700. // so cfgMeanStd() is here
  701. auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
  702. comp.apply(cv::gin(frame),
  703. cv::gout(out_gapi.front()),
  704. cv::compile_args(cv::gapi::networks(net)));
  705. // Validate
  706. validate();
  707. }
  708. TEST_F(ONNXMediaFrame, InferYUV)
  709. {
  710. useModel("classification/squeezenet/model/squeezenet1.0-9");
  711. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  712. const auto frame = MediaFrame::Create<TestMediaNV12>(m_in_y, m_in_uv);
  713. // ONNX_API code
  714. cv::Mat pp;
  715. cvtColorTwoPlane(m_in_y, m_in_uv, pp, cv::COLOR_YUV2BGR_NV12);
  716. cv::Mat processed_mat;
  717. preprocess(pp, processed_mat);
  718. infer<float>(processed_mat, out_onnx);
  719. // G_API code
  720. G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
  721. cv::GFrame in;
  722. cv::GMat out = cv::gapi::infer<SqueezNet>(in);
  723. cv::GComputation comp(cv::GIn(in), cv::GOut(out));
  724. // NOTE: We have to normalize U8 tensor
  725. // so cfgMeanStd() is here
  726. auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
  727. comp.apply(cv::gin(frame),
  728. cv::gout(out_gapi.front()),
  729. cv::compile_args(cv::gapi::networks(net)));
  730. // Validate
  731. validate();
  732. }
  733. TEST_F(ONNXMediaFrame, InferROIBGR)
  734. {
  735. useModel("classification/squeezenet/model/squeezenet1.0-9");
  736. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  737. auto frame = MediaFrame::Create<TestMediaBGR>(in_mat);
  738. // ONNX_API code
  739. cv::Mat roi_mat;
  740. preprocess(in_mat(rois.front()), roi_mat);
  741. infer<float>(roi_mat, out_onnx);
  742. // G_API code
  743. G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
  744. cv::GFrame in;
  745. cv::GOpaque<cv::Rect> rect;
  746. cv::GMat out = cv::gapi::infer<SqueezNet>(rect, in);
  747. cv::GComputation comp(cv::GIn(in, rect), cv::GOut(out));
  748. // NOTE: We have to normalize U8 tensor
  749. // so cfgMeanStd() is here
  750. auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
  751. comp.apply(cv::gin(frame, rois.front()),
  752. cv::gout(out_gapi.front()),
  753. cv::compile_args(cv::gapi::networks(net)));
  754. // Validate
  755. validate();
  756. }
  757. TEST_F(ONNXMediaFrame, InferROIYUV)
  758. {
  759. useModel("classification/squeezenet/model/squeezenet1.0-9");
  760. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  761. const auto frame = MediaFrame::Create<TestMediaNV12>(m_in_y, m_in_uv);
  762. // ONNX_API code
  763. cv::Mat pp;
  764. cvtColorTwoPlane(m_in_y, m_in_uv, pp, cv::COLOR_YUV2BGR_NV12);
  765. cv::Mat roi_mat;
  766. preprocess(pp(rois.front()), roi_mat);
  767. infer<float>(roi_mat, out_onnx);
  768. // G_API code
  769. G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
  770. cv::GFrame in;
  771. cv::GOpaque<cv::Rect> rect;
  772. cv::GMat out = cv::gapi::infer<SqueezNet>(rect, in);
  773. cv::GComputation comp(cv::GIn(in, rect), cv::GOut(out));
  774. // NOTE: We have to normalize U8 tensor
  775. // so cfgMeanStd() is here
  776. auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
  777. comp.apply(cv::gin(frame, rois.front()),
  778. cv::gout(out_gapi.front()),
  779. cv::compile_args(cv::gapi::networks(net)));
  780. // Validate
  781. validate();
  782. }
  783. TEST_F(ONNXMediaFrame, InferListBGR)
  784. {
  785. useModel("classification/squeezenet/model/squeezenet1.0-9");
  786. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  787. const auto frame = MediaFrame::Create<TestMediaBGR>(in_mat);
  788. // ONNX_API code
  789. for (size_t i = 0; i < rois.size(); ++i) {
  790. cv::Mat roi_mat;
  791. preprocess(in_mat(rois[i]), roi_mat);
  792. infer<float>(roi_mat, out_onnx);
  793. }
  794. // G_API code
  795. G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
  796. cv::GFrame in;
  797. cv::GArray<cv::Rect> rr;
  798. cv::GArray<cv::GMat> out = cv::gapi::infer<SqueezNet>(rr, in);
  799. cv::GComputation comp(cv::GIn(in, rr), cv::GOut(out));
  800. // NOTE: We have to normalize U8 tensor
  801. // so cfgMeanStd() is here
  802. auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
  803. comp.apply(cv::gin(frame, rois),
  804. cv::gout(out_gapi),
  805. cv::compile_args(cv::gapi::networks(net)));
  806. // Validate
  807. validate();
  808. }
  809. TEST_F(ONNXMediaFrame, InferListYUV)
  810. {
  811. useModel("classification/squeezenet/model/squeezenet1.0-9");
  812. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  813. const auto frame = MediaFrame::Create<TestMediaNV12>(m_in_y, m_in_uv);
  814. // ONNX_API code
  815. cv::Mat pp;
  816. cvtColorTwoPlane(m_in_y, m_in_uv, pp, cv::COLOR_YUV2BGR_NV12);
  817. for (size_t i = 0; i < rois.size(); ++i) {
  818. cv::Mat roi_mat;
  819. preprocess(pp(rois[i]), roi_mat);
  820. infer<float>(roi_mat, out_onnx);
  821. }
  822. // G_API code
  823. G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
  824. cv::GFrame in;
  825. cv::GArray<cv::Rect> rr;
  826. cv::GArray<cv::GMat> out = cv::gapi::infer<SqueezNet>(rr, in);
  827. cv::GComputation comp(cv::GIn(in, rr), cv::GOut(out));
  828. // NOTE: We have to normalize U8 tensor
  829. // so cfgMeanStd() is here
  830. auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
  831. comp.apply(cv::gin(frame, rois),
  832. cv::gout(out_gapi),
  833. cv::compile_args(cv::gapi::networks(net)));
  834. // Validate
  835. validate();
  836. }
  837. TEST_F(ONNXRCNN, InferWithDisabledOut)
  838. {
  839. useModel("object_detection_segmentation/faster-rcnn/model/FasterRCNN-10");
  840. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  841. cv::Mat pp;
  842. preprocess(in_mat, pp);
  843. // ONNX_API code
  844. infer<float>(pp, out_onnx, {"6379", "6383"});
  845. // G_API code
  846. using FRCNNOUT = std::tuple<cv::GMat, cv::GMat>;
  847. G_API_NET(FasterRCNN, <FRCNNOUT(cv::GMat)>, "FasterRCNN");
  848. auto net = cv::gapi::onnx::Params<FasterRCNN>{model_path}
  849. .cfgOutputLayers({"out1", "out2"})
  850. .cfgPostProc({cv::GMatDesc{CV_32F, {7,4}},
  851. cv::GMatDesc{CV_32F, {7}}}, remapRCNNPortsDO, {"6383", "6379"});
  852. cv::GMat in, out1, out2;
  853. std::tie(out1, out2) = cv::gapi::infer<FasterRCNN>(in);
  854. cv::GComputation comp(cv::GIn(in), cv::GOut(out1, out2));
  855. out_gapi.resize(num_out);
  856. comp.apply(cv::gin(pp),
  857. cv::gout(out_gapi[0], out_gapi[1]),
  858. cv::compile_args(cv::gapi::networks(net)));
  859. // Validate
  860. validate<float>(-1.f);
  861. validate<float>(-1.f);
  862. }
  863. TEST_F(ONNXMediaFrame, InferList2BGR)
  864. {
  865. useModel("classification/squeezenet/model/squeezenet1.0-9");
  866. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  867. const auto frame = MediaFrame::Create<TestMediaBGR>(in_mat);
  868. // ONNX_API code
  869. for (size_t i = 0; i < rois.size(); ++i) {
  870. cv::Mat roi_mat;
  871. preprocess(in_mat(rois[i]), roi_mat);
  872. infer<float>(roi_mat, out_onnx);
  873. }
  874. // G_API code
  875. G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
  876. cv::GFrame in;
  877. cv::GArray<cv::Rect> rr;
  878. cv::GArray<cv::GMat> out = cv::gapi::infer2<SqueezNet>(in, rr);
  879. cv::GComputation comp(cv::GIn(in, rr), cv::GOut(out));
  880. // NOTE: We have to normalize U8 tensor
  881. // so cfgMeanStd() is here
  882. auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
  883. comp.apply(cv::gin(frame, rois),
  884. cv::gout(out_gapi),
  885. cv::compile_args(cv::gapi::networks(net)));
  886. // Validate
  887. validate();
  888. }
  889. TEST_F(ONNXMediaFrame, InferList2YUV)
  890. {
  891. useModel("classification/squeezenet/model/squeezenet1.0-9");
  892. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  893. const auto frame = MediaFrame::Create<TestMediaNV12>(m_in_y, m_in_uv);
  894. // ONNX_API code
  895. cv::Mat pp;
  896. cvtColorTwoPlane(m_in_y, m_in_uv, pp, cv::COLOR_YUV2BGR_NV12);
  897. for (size_t i = 0; i < rois.size(); ++i) {
  898. cv::Mat roi_mat;
  899. preprocess(pp(rois[i]), roi_mat);
  900. infer<float>(roi_mat, out_onnx);
  901. }
  902. // G_API code
  903. G_API_NET(SqueezNet, <cv::GMat(cv::GMat)>, "squeeznet");
  904. cv::GFrame in;
  905. cv::GArray<cv::Rect> rr;
  906. cv::GArray<cv::GMat> out = cv::gapi::infer2<SqueezNet>(in, rr);
  907. cv::GComputation comp(cv::GIn(in, rr), cv::GOut(out));
  908. // NOTE: We have to normalize U8 tensor
  909. // so cfgMeanStd() is here
  910. auto net = cv::gapi::onnx::Params<SqueezNet> { model_path }.cfgMeanStd({ mean }, { std });
  911. comp.apply(cv::gin(frame, rois),
  912. cv::gout(out_gapi),
  913. cv::compile_args(cv::gapi::networks(net)));
  914. // Validate
  915. validate();
  916. }
  917. TEST_F(ONNXYoloV3, InferConstInput)
  918. {
  919. useModel("object_detection_segmentation/yolov3/model/yolov3-10");
  920. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  921. constructYoloInputs(in_mat);
  922. // ONNX_API code
  923. infer<float>(ins, out_onnx);
  924. // G_API code
  925. using OUT = std::tuple<cv::GMat, cv::GMat, cv::GMat>;
  926. G_API_NET(YoloNet, <OUT(cv::GMat)>, "yolov3");
  927. auto net = cv::gapi::onnx::Params<YoloNet>{model_path}
  928. .constInput("image_shape", ins[1])
  929. .cfgInputLayers({"input_1"})
  930. .cfgOutputLayers({"out1", "out2", "out3"})
  931. .cfgPostProc({cv::GMatDesc{CV_32F, {1, 10000, 4}},
  932. cv::GMatDesc{CV_32F, {1, 80, 10000}},
  933. cv::GMatDesc{CV_32S, {5, 3}}}, remapYoloV3);
  934. cv::GMat in, out1, out2, out3;
  935. std::tie(out1, out2, out3) = cv::gapi::infer<YoloNet>(in);
  936. cv::GComputation comp(cv::GIn(in), cv::GOut(out1, out2, out3));
  937. out_gapi.resize(num_out);
  938. comp.apply(cv::gin(ins[0]),
  939. cv::gout(out_gapi[0], out_gapi[1], out_gapi[2]),
  940. cv::compile_args(cv::gapi::networks(net)));
  941. // Validate
  942. validate<float>(-1.f);
  943. validate<float>(-1.f);
  944. validate<int>(-1);
  945. }
  946. TEST_F(ONNXYoloV3, InferBSConstInput)
  947. {
  948. // This test checks the case when a const input is used
  949. // and all input layer names are specified.
  950. // Const input has the advantage. It is expected behavior.
  951. useModel("object_detection_segmentation/yolov3/model/yolov3-10");
  952. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  953. constructYoloInputs(in_mat);
  954. // Tensor with incorrect image size
  955. // is used for check case when InputLayers and constInput have same names
  956. cv::Mat bad_shape;
  957. bad_shape.create(cv::Size(2, 1), CV_32F);
  958. float* ptr = bad_shape.ptr<float>();
  959. ptr[0] = 590;
  960. ptr[1] = 12;
  961. // ONNX_API code
  962. infer<float>(ins, out_onnx);
  963. // G_API code
  964. using OUT = std::tuple<cv::GMat, cv::GMat, cv::GMat>;
  965. G_API_NET(YoloNet, <OUT(cv::GMat, cv::GMat)>, "yolov3");
  966. auto net = cv::gapi::onnx::Params<YoloNet>{model_path}
  967. // Data from const input will be used to infer
  968. .constInput("image_shape", ins[1])
  969. // image_shape - const_input has same name
  970. .cfgInputLayers({"input_1", "image_shape"})
  971. .cfgOutputLayers({"out1", "out2", "out3"})
  972. .cfgPostProc({cv::GMatDesc{CV_32F, {1, 10000, 4}},
  973. cv::GMatDesc{CV_32F, {1, 80, 10000}},
  974. cv::GMatDesc{CV_32S, {5, 3}}}, remapYoloV3);
  975. cv::GMat in1, in2, out1, out2, out3;
  976. std::tie(out1, out2, out3) = cv::gapi::infer<YoloNet>(in1, in2);
  977. cv::GComputation comp(cv::GIn(in1, in2), cv::GOut(out1, out2, out3));
  978. out_gapi.resize(num_out);
  979. comp.apply(cv::gin(ins[0], bad_shape),
  980. cv::gout(out_gapi[0], out_gapi[1], out_gapi[2]),
  981. cv::compile_args(cv::gapi::networks(net)));
  982. // Validate
  983. validate<float>(-1.f);
  984. validate<float>(-1.f);
  985. validate<int>(-1);
  986. }
  987. TEST_F(ONNXRCNN, ConversionInt64to32)
  988. {
  989. useModel("object_detection_segmentation/faster-rcnn/model/FasterRCNN-10");
  990. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  991. cv::Mat dst;
  992. preprocess(in_mat, dst);
  993. // ONNX_API code
  994. infer<float>(dst, out_onnx);
  995. // G_API code
  996. using FRCNNOUT = std::tuple<cv::GMat,cv::GMat,cv::GMat>;
  997. G_API_NET(FasterRCNN, <FRCNNOUT(cv::GMat)>, "FasterRCNN");
  998. auto net = cv::gapi::onnx::Params<FasterRCNN>{model_path}
  999. .cfgOutputLayers({"out1", "out2", "out3"})
  1000. .cfgPostProc({cv::GMatDesc{CV_32F, {7,4}},
  1001. cv::GMatDesc{CV_32S, {7}},
  1002. cv::GMatDesc{CV_32F, {7}}}, remapRCNNPortsC);
  1003. cv::GMat in, out1, out2, out3;
  1004. std::tie(out1, out2, out3) = cv::gapi::infer<FasterRCNN>(in);
  1005. cv::GComputation comp(cv::GIn(in), cv::GOut(out1, out2, out3));
  1006. out_gapi.resize(num_out);
  1007. comp.apply(cv::gin(dst),
  1008. cv::gout(out_gapi[0], out_gapi[1], out_gapi[2]),
  1009. cv::compile_args(cv::gapi::networks(net)));
  1010. // Validate
  1011. validate<float>(-1.f);
  1012. validate<int>(-1);
  1013. validate<float>(-1.f);
  1014. }
  1015. TEST_F(ONNXWithRemap, InferOutReallocation)
  1016. {
  1017. useModel("object_detection_segmentation/ssd-mobilenetv1/model/ssd_mobilenet_v1_10");
  1018. in_mat = cv::imread(findDataFile("cv/dpm/cat.png", false));
  1019. // G_API code
  1020. G_API_NET(MobileNet, <cv::GMat(cv::GMat)>, "ssd_mobilenet");
  1021. auto net = cv::gapi::onnx::Params<MobileNet>{model_path}
  1022. .cfgOutputLayers({"detection_boxes"})
  1023. .cfgPostProc({cv::GMatDesc{CV_32F, {1,100,4}}}, reallocSSDPort);
  1024. cv::GMat in;
  1025. cv::GMat out1;
  1026. out1 = cv::gapi::infer<MobileNet>(in);
  1027. cv::GComputation comp(cv::GIn(in), cv::GOut(out1));
  1028. EXPECT_THROW(comp.apply(cv::gin(in_mat),
  1029. cv::gout(out_gapi[0]),
  1030. cv::compile_args(cv::gapi::networks(net))), std::exception);
  1031. }
  1032. } // namespace opencv_test
  1033. #endif // HAVE_ONNX