pyopencv_gapi.hpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080
  1. #ifndef OPENCV_GAPI_PYOPENCV_GAPI_HPP
  2. #define OPENCV_GAPI_PYOPENCV_GAPI_HPP
  3. #ifdef HAVE_OPENCV_GAPI
  4. #ifdef _MSC_VER
  5. #pragma warning(disable: 4503) // "decorated name length exceeded"
  6. #endif
  7. #include <opencv2/gapi/cpu/gcpukernel.hpp>
  8. #include <opencv2/gapi/python/python.hpp>
  9. // NB: Python wrapper replaces :: with _ for classes
  10. using gapi_GKernelPackage = cv::GKernelPackage;
  11. using gapi_GNetPackage = cv::gapi::GNetPackage;
  12. using gapi_ie_PyParams = cv::gapi::ie::PyParams;
  13. using gapi_wip_IStreamSource_Ptr = cv::Ptr<cv::gapi::wip::IStreamSource>;
  14. using detail_ExtractArgsCallback = cv::detail::ExtractArgsCallback;
  15. using detail_ExtractMetaCallback = cv::detail::ExtractMetaCallback;
  16. using vector_GNetParam = std::vector<cv::gapi::GNetParam>;
  17. using gapi_streaming_queue_capacity = cv::gapi::streaming::queue_capacity;
  18. using GStreamerSource_OutputType = cv::gapi::wip::GStreamerSource::OutputType;
  19. // NB: Python wrapper generate T_U for T<U>
  20. // This behavior is only observed for inputs
  21. using GOpaque_bool = cv::GOpaque<bool>;
  22. using GOpaque_int = cv::GOpaque<int>;
  23. using GOpaque_double = cv::GOpaque<double>;
  24. using GOpaque_float = cv::GOpaque<double>;
  25. using GOpaque_string = cv::GOpaque<std::string>;
  26. using GOpaque_Point2i = cv::GOpaque<cv::Point>;
  27. using GOpaque_Point2f = cv::GOpaque<cv::Point2f>;
  28. using GOpaque_Size = cv::GOpaque<cv::Size>;
  29. using GOpaque_Rect = cv::GOpaque<cv::Rect>;
  30. using GArray_bool = cv::GArray<bool>;
  31. using GArray_int = cv::GArray<int>;
  32. using GArray_double = cv::GArray<double>;
  33. using GArray_float = cv::GArray<double>;
  34. using GArray_string = cv::GArray<std::string>;
  35. using GArray_Point2i = cv::GArray<cv::Point>;
  36. using GArray_Point2f = cv::GArray<cv::Point2f>;
  37. using GArray_Size = cv::GArray<cv::Size>;
  38. using GArray_Rect = cv::GArray<cv::Rect>;
  39. using GArray_Scalar = cv::GArray<cv::Scalar>;
  40. using GArray_Mat = cv::GArray<cv::Mat>;
  41. using GArray_GMat = cv::GArray<cv::GMat>;
  42. using GArray_Prim = cv::GArray<cv::gapi::wip::draw::Prim>;
  43. // FIXME: Python wrapper generate code without namespace std,
  44. // so it cause error: "string wasn't declared"
  45. // WA: Create using
  46. using std::string;
  47. namespace cv
  48. {
  49. namespace detail
  50. {
  51. class PyObjectHolder
  52. {
  53. public:
  54. PyObjectHolder(PyObject* o, bool owner = true);
  55. PyObject* get() const;
  56. private:
  57. class Impl;
  58. std::shared_ptr<Impl> m_impl;
  59. };
  60. } // namespace detail
  61. } // namespace cv
  62. class cv::detail::PyObjectHolder::Impl
  63. {
  64. public:
  65. Impl(PyObject* object, bool owner);
  66. PyObject* get() const;
  67. ~Impl();
  68. private:
  69. PyObject* m_object;
  70. };
  71. cv::detail::PyObjectHolder::Impl::Impl(PyObject* object, bool owner)
  72. : m_object(object)
  73. {
  74. // NB: Become an owner of that PyObject.
  75. // Need to store this and get access
  76. // after the caller which provide the object is out of range.
  77. if (owner)
  78. {
  79. // NB: Impossible take ownership if object is NULL.
  80. GAPI_Assert(object);
  81. Py_INCREF(m_object);
  82. }
  83. }
  84. cv::detail::PyObjectHolder::Impl::~Impl()
  85. {
  86. // NB: If NULL was set, don't decrease counter.
  87. if (m_object)
  88. {
  89. Py_DECREF(m_object);
  90. }
  91. }
  92. PyObject* cv::detail::PyObjectHolder::Impl::get() const
  93. {
  94. return m_object;
  95. }
  96. cv::detail::PyObjectHolder::PyObjectHolder(PyObject* object, bool owner)
  97. : m_impl(new cv::detail::PyObjectHolder::Impl{object, owner})
  98. {
  99. }
  100. PyObject* cv::detail::PyObjectHolder::get() const
  101. {
  102. return m_impl->get();
  103. }
  104. template<>
  105. PyObject* pyopencv_from(const cv::detail::PyObjectHolder& v)
  106. {
  107. PyObject* o = cv::util::any_cast<cv::detail::PyObjectHolder>(v).get();
  108. Py_INCREF(o);
  109. return o;
  110. }
  111. // #FIXME: Is it possible to implement pyopencv_from/pyopencv_to for generic
  112. // cv::variant<Types...> ?
  113. template <>
  114. PyObject* pyopencv_from(const cv::gapi::wip::draw::Prim& prim)
  115. {
  116. switch (prim.index())
  117. {
  118. case cv::gapi::wip::draw::Prim::index_of<cv::gapi::wip::draw::Rect>():
  119. return pyopencv_from(cv::util::get<cv::gapi::wip::draw::Rect>(prim));
  120. case cv::gapi::wip::draw::Prim::index_of<cv::gapi::wip::draw::Text>():
  121. return pyopencv_from(cv::util::get<cv::gapi::wip::draw::Text>(prim));
  122. case cv::gapi::wip::draw::Prim::index_of<cv::gapi::wip::draw::Circle>():
  123. return pyopencv_from(cv::util::get<cv::gapi::wip::draw::Circle>(prim));
  124. case cv::gapi::wip::draw::Prim::index_of<cv::gapi::wip::draw::Line>():
  125. return pyopencv_from(cv::util::get<cv::gapi::wip::draw::Line>(prim));
  126. case cv::gapi::wip::draw::Prim::index_of<cv::gapi::wip::draw::Poly>():
  127. return pyopencv_from(cv::util::get<cv::gapi::wip::draw::Poly>(prim));
  128. case cv::gapi::wip::draw::Prim::index_of<cv::gapi::wip::draw::Mosaic>():
  129. return pyopencv_from(cv::util::get<cv::gapi::wip::draw::Mosaic>(prim));
  130. case cv::gapi::wip::draw::Prim::index_of<cv::gapi::wip::draw::Image>():
  131. return pyopencv_from(cv::util::get<cv::gapi::wip::draw::Image>(prim));
  132. }
  133. util::throw_error(std::logic_error("Unsupported draw primitive type"));
  134. }
  135. template <>
  136. PyObject* pyopencv_from(const cv::gapi::wip::draw::Prims& value)
  137. {
  138. return pyopencv_from_generic_vec(value);
  139. }
  140. template<>
  141. bool pyopencv_to(PyObject* obj, cv::gapi::wip::draw::Prim& value, const ArgInfo&)
  142. {
  143. #define TRY_EXTRACT(Prim) \
  144. if (PyObject_TypeCheck(obj, reinterpret_cast<PyTypeObject*>(pyopencv_gapi_wip_draw_##Prim##_TypePtr))) \
  145. { \
  146. value = reinterpret_cast<pyopencv_gapi_wip_draw_##Prim##_t*>(obj)->v; \
  147. return true; \
  148. } \
  149. TRY_EXTRACT(Rect)
  150. TRY_EXTRACT(Text)
  151. TRY_EXTRACT(Circle)
  152. TRY_EXTRACT(Line)
  153. TRY_EXTRACT(Mosaic)
  154. TRY_EXTRACT(Image)
  155. TRY_EXTRACT(Poly)
  156. #undef TRY_EXTRACT
  157. failmsg("Unsupported primitive type");
  158. return false;
  159. }
  160. template <>
  161. bool pyopencv_to(PyObject* obj, cv::gapi::wip::draw::Prims& value, const ArgInfo& info)
  162. {
  163. return pyopencv_to_generic_vec(obj, value, info);
  164. }
  165. template <>
  166. bool pyopencv_to(PyObject* obj, cv::GMetaArg& value, const ArgInfo&)
  167. {
  168. #define TRY_EXTRACT(Meta) \
  169. if (PyObject_TypeCheck(obj, \
  170. reinterpret_cast<PyTypeObject*>(pyopencv_##Meta##_TypePtr))) \
  171. { \
  172. value = reinterpret_cast<pyopencv_##Meta##_t*>(obj)->v; \
  173. return true; \
  174. } \
  175. TRY_EXTRACT(GMatDesc)
  176. TRY_EXTRACT(GScalarDesc)
  177. TRY_EXTRACT(GArrayDesc)
  178. TRY_EXTRACT(GOpaqueDesc)
  179. #undef TRY_EXTRACT
  180. failmsg("Unsupported cv::GMetaArg type");
  181. return false;
  182. }
  183. template <>
  184. bool pyopencv_to(PyObject* obj, cv::GMetaArgs& value, const ArgInfo& info)
  185. {
  186. return pyopencv_to_generic_vec(obj, value, info);
  187. }
  188. template<>
  189. PyObject* pyopencv_from(const cv::GArg& value)
  190. {
  191. GAPI_Assert(value.kind != cv::detail::ArgKind::GOBJREF);
  192. #define HANDLE_CASE(T, O) case cv::detail::OpaqueKind::CV_##T: \
  193. { \
  194. return pyopencv_from(value.get<O>()); \
  195. }
  196. #define UNSUPPORTED(T) case cv::detail::OpaqueKind::CV_##T: break
  197. switch (value.opaque_kind)
  198. {
  199. HANDLE_CASE(BOOL, bool);
  200. HANDLE_CASE(INT, int);
  201. HANDLE_CASE(INT64, int64_t);
  202. HANDLE_CASE(DOUBLE, double);
  203. HANDLE_CASE(FLOAT, float);
  204. HANDLE_CASE(STRING, std::string);
  205. HANDLE_CASE(POINT, cv::Point);
  206. HANDLE_CASE(POINT2F, cv::Point2f);
  207. HANDLE_CASE(SIZE, cv::Size);
  208. HANDLE_CASE(RECT, cv::Rect);
  209. HANDLE_CASE(SCALAR, cv::Scalar);
  210. HANDLE_CASE(MAT, cv::Mat);
  211. HANDLE_CASE(UNKNOWN, cv::detail::PyObjectHolder);
  212. HANDLE_CASE(DRAW_PRIM, cv::gapi::wip::draw::Prim);
  213. UNSUPPORTED(UINT64);
  214. #undef HANDLE_CASE
  215. #undef UNSUPPORTED
  216. }
  217. util::throw_error(std::logic_error("Unsupported kernel input type"));
  218. }
  219. template<>
  220. bool pyopencv_to(PyObject* obj, cv::GArg& value, const ArgInfo& info)
  221. {
  222. value = cv::GArg(cv::detail::PyObjectHolder(obj));
  223. return true;
  224. }
  225. template <>
  226. bool pyopencv_to(PyObject* obj, std::vector<cv::gapi::GNetParam>& value, const ArgInfo& info)
  227. {
  228. return pyopencv_to_generic_vec(obj, value, info);
  229. }
  230. template <>
  231. PyObject* pyopencv_from(const std::vector<cv::gapi::GNetParam>& value)
  232. {
  233. return pyopencv_from_generic_vec(value);
  234. }
  235. template <>
  236. bool pyopencv_to(PyObject* obj, std::vector<GCompileArg>& value, const ArgInfo& info)
  237. {
  238. return pyopencv_to_generic_vec(obj, value, info);
  239. }
  240. template <>
  241. PyObject* pyopencv_from(const std::vector<GCompileArg>& value)
  242. {
  243. return pyopencv_from_generic_vec(value);
  244. }
  245. template<>
  246. PyObject* pyopencv_from(const cv::detail::OpaqueRef& o)
  247. {
  248. switch (o.getKind())
  249. {
  250. case cv::detail::OpaqueKind::CV_BOOL : return pyopencv_from(o.rref<bool>());
  251. case cv::detail::OpaqueKind::CV_INT : return pyopencv_from(o.rref<int>());
  252. case cv::detail::OpaqueKind::CV_INT64 : return pyopencv_from(o.rref<int64_t>());
  253. case cv::detail::OpaqueKind::CV_DOUBLE : return pyopencv_from(o.rref<double>());
  254. case cv::detail::OpaqueKind::CV_FLOAT : return pyopencv_from(o.rref<float>());
  255. case cv::detail::OpaqueKind::CV_STRING : return pyopencv_from(o.rref<std::string>());
  256. case cv::detail::OpaqueKind::CV_POINT : return pyopencv_from(o.rref<cv::Point>());
  257. case cv::detail::OpaqueKind::CV_POINT2F : return pyopencv_from(o.rref<cv::Point2f>());
  258. case cv::detail::OpaqueKind::CV_SIZE : return pyopencv_from(o.rref<cv::Size>());
  259. case cv::detail::OpaqueKind::CV_RECT : return pyopencv_from(o.rref<cv::Rect>());
  260. case cv::detail::OpaqueKind::CV_UNKNOWN : return pyopencv_from(o.rref<cv::GArg>());
  261. case cv::detail::OpaqueKind::CV_DRAW_PRIM : return pyopencv_from(o.rref<cv::gapi::wip::draw::Prim>());
  262. case cv::detail::OpaqueKind::CV_UINT64 : break;
  263. case cv::detail::OpaqueKind::CV_SCALAR : break;
  264. case cv::detail::OpaqueKind::CV_MAT : break;
  265. }
  266. PyErr_SetString(PyExc_TypeError, "Unsupported GOpaque type");
  267. return NULL;
  268. };
  269. template <>
  270. PyObject* pyopencv_from(const cv::detail::VectorRef& v)
  271. {
  272. switch (v.getKind())
  273. {
  274. case cv::detail::OpaqueKind::CV_BOOL : return pyopencv_from_generic_vec(v.rref<bool>());
  275. case cv::detail::OpaqueKind::CV_INT : return pyopencv_from_generic_vec(v.rref<int>());
  276. case cv::detail::OpaqueKind::CV_INT64 : return pyopencv_from_generic_vec(v.rref<int64_t>());
  277. case cv::detail::OpaqueKind::CV_DOUBLE : return pyopencv_from_generic_vec(v.rref<double>());
  278. case cv::detail::OpaqueKind::CV_FLOAT : return pyopencv_from_generic_vec(v.rref<float>());
  279. case cv::detail::OpaqueKind::CV_STRING : return pyopencv_from_generic_vec(v.rref<std::string>());
  280. case cv::detail::OpaqueKind::CV_POINT : return pyopencv_from_generic_vec(v.rref<cv::Point>());
  281. case cv::detail::OpaqueKind::CV_POINT2F : return pyopencv_from_generic_vec(v.rref<cv::Point2f>());
  282. case cv::detail::OpaqueKind::CV_SIZE : return pyopencv_from_generic_vec(v.rref<cv::Size>());
  283. case cv::detail::OpaqueKind::CV_RECT : return pyopencv_from_generic_vec(v.rref<cv::Rect>());
  284. case cv::detail::OpaqueKind::CV_SCALAR : return pyopencv_from_generic_vec(v.rref<cv::Scalar>());
  285. case cv::detail::OpaqueKind::CV_MAT : return pyopencv_from_generic_vec(v.rref<cv::Mat>());
  286. case cv::detail::OpaqueKind::CV_UNKNOWN : return pyopencv_from_generic_vec(v.rref<cv::GArg>());
  287. case cv::detail::OpaqueKind::CV_DRAW_PRIM : return pyopencv_from_generic_vec(v.rref<cv::gapi::wip::draw::Prim>());
  288. case cv::detail::OpaqueKind::CV_UINT64 : break;
  289. }
  290. PyErr_SetString(PyExc_TypeError, "Unsupported GArray type");
  291. return NULL;
  292. }
  293. template <>
  294. PyObject* pyopencv_from(const GRunArg& v)
  295. {
  296. switch (v.index())
  297. {
  298. case GRunArg::index_of<cv::Mat>():
  299. return pyopencv_from(util::get<cv::Mat>(v));
  300. case GRunArg::index_of<cv::Scalar>():
  301. return pyopencv_from(util::get<cv::Scalar>(v));
  302. case GRunArg::index_of<cv::detail::VectorRef>():
  303. return pyopencv_from(util::get<cv::detail::VectorRef>(v));
  304. case GRunArg::index_of<cv::detail::OpaqueRef>():
  305. return pyopencv_from(util::get<cv::detail::OpaqueRef>(v));
  306. }
  307. PyErr_SetString(PyExc_TypeError, "Failed to unpack GRunArgs. Index of variant is unknown");
  308. return NULL;
  309. }
  310. template <typename T>
  311. PyObject* pyopencv_from(const cv::optional<T>& opt)
  312. {
  313. if (!opt.has_value())
  314. {
  315. Py_RETURN_NONE;
  316. }
  317. return pyopencv_from(*opt);
  318. }
  319. template <>
  320. PyObject* pyopencv_from(const GOptRunArg& v)
  321. {
  322. switch (v.index())
  323. {
  324. case GOptRunArg::index_of<cv::optional<cv::Mat>>():
  325. return pyopencv_from(util::get<cv::optional<cv::Mat>>(v));
  326. case GOptRunArg::index_of<cv::optional<cv::Scalar>>():
  327. return pyopencv_from(util::get<cv::optional<cv::Scalar>>(v));
  328. case GOptRunArg::index_of<optional<cv::detail::VectorRef>>():
  329. return pyopencv_from(util::get<optional<cv::detail::VectorRef>>(v));
  330. case GOptRunArg::index_of<optional<cv::detail::OpaqueRef>>():
  331. return pyopencv_from(util::get<optional<cv::detail::OpaqueRef>>(v));
  332. }
  333. PyErr_SetString(PyExc_TypeError, "Failed to unpack GOptRunArg. Index of variant is unknown");
  334. return NULL;
  335. }
  336. template<>
  337. PyObject* pyopencv_from(const GRunArgs& value)
  338. {
  339. return value.size() == 1 ? pyopencv_from(value[0]) : pyopencv_from_generic_vec(value);
  340. }
  341. template<>
  342. PyObject* pyopencv_from(const GOptRunArgs& value)
  343. {
  344. return value.size() == 1 ? pyopencv_from(value[0]) : pyopencv_from_generic_vec(value);
  345. }
  346. // FIXME: cv::variant should be wrapped once for all types.
  347. template <>
  348. PyObject* pyopencv_from(const cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>& v)
  349. {
  350. using RunArgs = cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>;
  351. switch (v.index())
  352. {
  353. case RunArgs::index_of<cv::GRunArgs>():
  354. return pyopencv_from(util::get<cv::GRunArgs>(v));
  355. case RunArgs::index_of<cv::GOptRunArgs>():
  356. return pyopencv_from(util::get<cv::GOptRunArgs>(v));
  357. }
  358. PyErr_SetString(PyExc_TypeError, "Failed to recognize kind of RunArgs. Index of variant is unknown");
  359. return NULL;
  360. }
  361. template <typename T>
  362. void pyopencv_to_with_check(PyObject* from, T& to, const std::string& msg = "")
  363. {
  364. if (!pyopencv_to(from, to, ArgInfo("", false)))
  365. {
  366. cv::util::throw_error(std::logic_error(msg));
  367. }
  368. }
  369. template <typename T>
  370. void pyopencv_to_generic_vec_with_check(PyObject* from,
  371. std::vector<T>& to,
  372. const std::string& msg = "")
  373. {
  374. if (!pyopencv_to_generic_vec(from, to, ArgInfo("", false)))
  375. {
  376. cv::util::throw_error(std::logic_error(msg));
  377. }
  378. }
  379. template <typename T>
  380. static T extract_proto_args(PyObject* py_args)
  381. {
  382. using namespace cv;
  383. GProtoArgs args;
  384. Py_ssize_t size = PyList_Size(py_args);
  385. args.reserve(size);
  386. for (int i = 0; i < size; ++i)
  387. {
  388. PyObject* item = PyList_GetItem(py_args, i);
  389. if (PyObject_TypeCheck(item, reinterpret_cast<PyTypeObject*>(pyopencv_GScalar_TypePtr)))
  390. {
  391. args.emplace_back(reinterpret_cast<pyopencv_GScalar_t*>(item)->v);
  392. }
  393. else if (PyObject_TypeCheck(item, reinterpret_cast<PyTypeObject*>(pyopencv_GMat_TypePtr)))
  394. {
  395. args.emplace_back(reinterpret_cast<pyopencv_GMat_t*>(item)->v);
  396. }
  397. else if (PyObject_TypeCheck(item, reinterpret_cast<PyTypeObject*>(pyopencv_GOpaqueT_TypePtr)))
  398. {
  399. args.emplace_back(reinterpret_cast<pyopencv_GOpaqueT_t*>(item)->v.strip());
  400. }
  401. else if (PyObject_TypeCheck(item, reinterpret_cast<PyTypeObject*>(pyopencv_GArrayT_TypePtr)))
  402. {
  403. args.emplace_back(reinterpret_cast<pyopencv_GArrayT_t*>(item)->v.strip());
  404. }
  405. else
  406. {
  407. util::throw_error(std::logic_error("Unsupported type for GProtoArgs"));
  408. }
  409. }
  410. return T(std::move(args));
  411. }
  412. static cv::detail::OpaqueRef extract_opaque_ref(PyObject* from, cv::detail::OpaqueKind kind)
  413. {
  414. #define HANDLE_CASE(T, O) case cv::detail::OpaqueKind::CV_##T: \
  415. { \
  416. O obj{}; \
  417. pyopencv_to_with_check(from, obj, "Failed to obtain " # O); \
  418. return cv::detail::OpaqueRef{std::move(obj)}; \
  419. }
  420. #define UNSUPPORTED(T) case cv::detail::OpaqueKind::CV_##T: break
  421. switch (kind)
  422. {
  423. HANDLE_CASE(BOOL, bool);
  424. HANDLE_CASE(INT, int);
  425. HANDLE_CASE(DOUBLE, double);
  426. HANDLE_CASE(FLOAT, float);
  427. HANDLE_CASE(STRING, std::string);
  428. HANDLE_CASE(POINT, cv::Point);
  429. HANDLE_CASE(POINT2F, cv::Point2f);
  430. HANDLE_CASE(SIZE, cv::Size);
  431. HANDLE_CASE(RECT, cv::Rect);
  432. HANDLE_CASE(UNKNOWN, cv::GArg);
  433. UNSUPPORTED(UINT64);
  434. UNSUPPORTED(INT64);
  435. UNSUPPORTED(SCALAR);
  436. UNSUPPORTED(MAT);
  437. UNSUPPORTED(DRAW_PRIM);
  438. #undef HANDLE_CASE
  439. #undef UNSUPPORTED
  440. }
  441. util::throw_error(std::logic_error("Unsupported type for GOpaqueT"));
  442. }
  443. static cv::detail::VectorRef extract_vector_ref(PyObject* from, cv::detail::OpaqueKind kind)
  444. {
  445. #define HANDLE_CASE(T, O) case cv::detail::OpaqueKind::CV_##T: \
  446. { \
  447. std::vector<O> obj; \
  448. pyopencv_to_generic_vec_with_check(from, obj, "Failed to obtain vector of " # O); \
  449. return cv::detail::VectorRef{std::move(obj)}; \
  450. }
  451. #define UNSUPPORTED(T) case cv::detail::OpaqueKind::CV_##T: break
  452. switch (kind)
  453. {
  454. HANDLE_CASE(BOOL, bool);
  455. HANDLE_CASE(INT, int);
  456. HANDLE_CASE(DOUBLE, double);
  457. HANDLE_CASE(FLOAT, float);
  458. HANDLE_CASE(STRING, std::string);
  459. HANDLE_CASE(POINT, cv::Point);
  460. HANDLE_CASE(POINT2F, cv::Point2f);
  461. HANDLE_CASE(SIZE, cv::Size);
  462. HANDLE_CASE(RECT, cv::Rect);
  463. HANDLE_CASE(SCALAR, cv::Scalar);
  464. HANDLE_CASE(MAT, cv::Mat);
  465. HANDLE_CASE(UNKNOWN, cv::GArg);
  466. HANDLE_CASE(DRAW_PRIM, cv::gapi::wip::draw::Prim);
  467. UNSUPPORTED(UINT64);
  468. UNSUPPORTED(INT64);
  469. #undef HANDLE_CASE
  470. #undef UNSUPPORTED
  471. }
  472. util::throw_error(std::logic_error("Unsupported type for GArrayT"));
  473. }
  474. static cv::GRunArg extract_run_arg(const cv::GTypeInfo& info, PyObject* item)
  475. {
  476. switch (info.shape)
  477. {
  478. case cv::GShape::GMAT:
  479. {
  480. // NB: In case streaming it can be IStreamSource or cv::Mat
  481. if (PyObject_TypeCheck(item,
  482. reinterpret_cast<PyTypeObject*>(pyopencv_gapi_wip_IStreamSource_TypePtr)))
  483. {
  484. cv::gapi::wip::IStreamSource::Ptr source =
  485. reinterpret_cast<pyopencv_gapi_wip_IStreamSource_t*>(item)->v;
  486. return source;
  487. }
  488. cv::Mat obj;
  489. pyopencv_to_with_check(item, obj, "Failed to obtain cv::Mat");
  490. return obj;
  491. }
  492. case cv::GShape::GSCALAR:
  493. {
  494. cv::Scalar obj;
  495. pyopencv_to_with_check(item, obj, "Failed to obtain cv::Scalar");
  496. return obj;
  497. }
  498. case cv::GShape::GOPAQUE:
  499. {
  500. return extract_opaque_ref(item, info.kind);
  501. }
  502. case cv::GShape::GARRAY:
  503. {
  504. return extract_vector_ref(item, info.kind);
  505. }
  506. case cv::GShape::GFRAME:
  507. {
  508. // NB: Isn't supported yet.
  509. break;
  510. }
  511. }
  512. util::throw_error(std::logic_error("Unsupported output shape"));
  513. }
  514. static cv::GRunArgs extract_run_args(const cv::GTypesInfo& info, PyObject* py_args)
  515. {
  516. GAPI_Assert(PyList_Check(py_args));
  517. cv::GRunArgs args;
  518. Py_ssize_t list_size = PyList_Size(py_args);
  519. args.reserve(list_size);
  520. for (int i = 0; i < list_size; ++i)
  521. {
  522. args.push_back(extract_run_arg(info[i], PyList_GetItem(py_args, i)));
  523. }
  524. return args;
  525. }
  526. static cv::GMetaArg extract_meta_arg(const cv::GTypeInfo& info, PyObject* item)
  527. {
  528. switch (info.shape)
  529. {
  530. case cv::GShape::GMAT:
  531. {
  532. cv::Mat obj;
  533. pyopencv_to_with_check(item, obj, "Failed to obtain cv::Mat");
  534. return cv::GMetaArg{cv::descr_of(obj)};
  535. }
  536. case cv::GShape::GSCALAR:
  537. {
  538. cv::Scalar obj;
  539. pyopencv_to_with_check(item, obj, "Failed to obtain cv::Scalar");
  540. return cv::GMetaArg{cv::descr_of(obj)};
  541. }
  542. case cv::GShape::GARRAY:
  543. {
  544. return cv::GMetaArg{cv::empty_array_desc()};
  545. }
  546. case cv::GShape::GOPAQUE:
  547. {
  548. return cv::GMetaArg{cv::empty_gopaque_desc()};
  549. }
  550. case cv::GShape::GFRAME:
  551. {
  552. // NB: Isn't supported yet.
  553. break;
  554. }
  555. }
  556. util::throw_error(std::logic_error("Unsupported output shape"));
  557. }
  558. static cv::GMetaArgs extract_meta_args(const cv::GTypesInfo& info, PyObject* py_args)
  559. {
  560. GAPI_Assert(PyList_Check(py_args));
  561. cv::GMetaArgs metas;
  562. Py_ssize_t list_size = PyList_Size(py_args);
  563. metas.reserve(list_size);
  564. for (int i = 0; i < list_size; ++i)
  565. {
  566. metas.push_back(extract_meta_arg(info[i], PyList_GetItem(py_args, i)));
  567. }
  568. return metas;
  569. }
  570. static cv::GRunArgs run_py_kernel(cv::detail::PyObjectHolder kernel,
  571. const cv::gapi::python::GPythonContext &ctx)
  572. {
  573. const auto& ins = ctx.ins;
  574. const auto& in_metas = ctx.in_metas;
  575. const auto& out_info = ctx.out_info;
  576. PyGILState_STATE gstate;
  577. gstate = PyGILState_Ensure();
  578. cv::GRunArgs outs;
  579. try
  580. {
  581. int in_idx = 0;
  582. // NB: Doesn't increase reference counter (false),
  583. // because PyObject already have ownership.
  584. // In case exception decrement reference counter.
  585. cv::detail::PyObjectHolder args(PyTuple_New(ins.size()), false);
  586. for (size_t i = 0; i < ins.size(); ++i)
  587. {
  588. // NB: If meta is monostate then object isn't associated with G-TYPE.
  589. if (cv::util::holds_alternative<cv::util::monostate>(in_metas[i]))
  590. {
  591. PyTuple_SetItem(args.get(), i, pyopencv_from(ins[i]));
  592. continue;
  593. }
  594. switch (in_metas[i].index())
  595. {
  596. case cv::GMetaArg::index_of<cv::GMatDesc>():
  597. PyTuple_SetItem(args.get(), i, pyopencv_from(ins[i].get<cv::Mat>()));
  598. break;
  599. case cv::GMetaArg::index_of<cv::GScalarDesc>():
  600. PyTuple_SetItem(args.get(), i, pyopencv_from(ins[i].get<cv::Scalar>()));
  601. break;
  602. case cv::GMetaArg::index_of<cv::GOpaqueDesc>():
  603. PyTuple_SetItem(args.get(), i, pyopencv_from(ins[i].get<cv::detail::OpaqueRef>()));
  604. break;
  605. case cv::GMetaArg::index_of<cv::GArrayDesc>():
  606. PyTuple_SetItem(args.get(), i, pyopencv_from(ins[i].get<cv::detail::VectorRef>()));
  607. break;
  608. case cv::GMetaArg::index_of<cv::GFrameDesc>():
  609. util::throw_error(std::logic_error("GFrame isn't supported for custom operation"));
  610. break;
  611. }
  612. ++in_idx;
  613. }
  614. // NB: Doesn't increase reference counter (false).
  615. // In case PyObject_CallObject return NULL, do nothing in destructor.
  616. cv::detail::PyObjectHolder result(
  617. PyObject_CallObject(kernel.get(), args.get()), false);
  618. if (PyErr_Occurred())
  619. {
  620. PyErr_PrintEx(0);
  621. PyErr_Clear();
  622. throw std::logic_error("Python kernel failed with error!");
  623. }
  624. // NB: In fact it's impossible situation, becase errors were handled above.
  625. GAPI_Assert(result.get() && "Python kernel returned NULL!");
  626. if (out_info.size() == 1)
  627. {
  628. outs = cv::GRunArgs{extract_run_arg(out_info[0], result.get())};
  629. }
  630. else if (out_info.size() > 1)
  631. {
  632. GAPI_Assert(PyTuple_Check(result.get()));
  633. Py_ssize_t tuple_size = PyTuple_Size(result.get());
  634. outs.reserve(tuple_size);
  635. for (int i = 0; i < tuple_size; ++i)
  636. {
  637. outs.push_back(extract_run_arg(out_info[i], PyTuple_GetItem(result.get(), i)));
  638. }
  639. }
  640. else
  641. {
  642. // Seems to be impossible case.
  643. GAPI_Assert(false);
  644. }
  645. }
  646. catch (...)
  647. {
  648. PyGILState_Release(gstate);
  649. throw;
  650. }
  651. PyGILState_Release(gstate);
  652. return outs;
  653. }
  654. static GMetaArg get_meta_arg(PyObject* obj)
  655. {
  656. cv::GMetaArg arg;
  657. if (!pyopencv_to(obj, arg, ArgInfo("arg", false)))
  658. {
  659. util::throw_error(std::logic_error("Unsupported output meta type"));
  660. }
  661. return arg;
  662. }
  663. static cv::GMetaArgs get_meta_args(PyObject* tuple)
  664. {
  665. size_t size = PyTuple_Size(tuple);
  666. cv::GMetaArgs metas;
  667. metas.reserve(size);
  668. for (size_t i = 0; i < size; ++i)
  669. {
  670. metas.push_back(get_meta_arg(PyTuple_GetItem(tuple, i)));
  671. }
  672. return metas;
  673. }
  674. static GMetaArgs run_py_meta(cv::detail::PyObjectHolder out_meta,
  675. const cv::GMetaArgs &meta,
  676. const cv::GArgs &gargs)
  677. {
  678. PyGILState_STATE gstate;
  679. gstate = PyGILState_Ensure();
  680. cv::GMetaArgs out_metas;
  681. try
  682. {
  683. // NB: Doesn't increase reference counter (false),
  684. // because PyObject already have ownership.
  685. // In case exception decrement reference counter.
  686. cv::detail::PyObjectHolder args(PyTuple_New(meta.size()), false);
  687. size_t idx = 0;
  688. for (auto&& m : meta)
  689. {
  690. switch (m.index())
  691. {
  692. case cv::GMetaArg::index_of<cv::GMatDesc>():
  693. PyTuple_SetItem(args.get(), idx, pyopencv_from(cv::util::get<cv::GMatDesc>(m)));
  694. break;
  695. case cv::GMetaArg::index_of<cv::GScalarDesc>():
  696. PyTuple_SetItem(args.get(), idx, pyopencv_from(cv::util::get<cv::GScalarDesc>(m)));
  697. break;
  698. case cv::GMetaArg::index_of<cv::GArrayDesc>():
  699. PyTuple_SetItem(args.get(), idx, pyopencv_from(cv::util::get<cv::GArrayDesc>(m)));
  700. break;
  701. case cv::GMetaArg::index_of<cv::GOpaqueDesc>():
  702. PyTuple_SetItem(args.get(), idx, pyopencv_from(cv::util::get<cv::GOpaqueDesc>(m)));
  703. break;
  704. case cv::GMetaArg::index_of<cv::util::monostate>():
  705. PyTuple_SetItem(args.get(), idx, pyopencv_from(gargs[idx]));
  706. break;
  707. case cv::GMetaArg::index_of<cv::GFrameDesc>():
  708. util::throw_error(std::logic_error("GFrame isn't supported for custom operation"));
  709. break;
  710. }
  711. ++idx;
  712. }
  713. // NB: Doesn't increase reference counter (false).
  714. // In case PyObject_CallObject return NULL, do nothing in destructor.
  715. cv::detail::PyObjectHolder result(
  716. PyObject_CallObject(out_meta.get(), args.get()), false);
  717. if (PyErr_Occurred())
  718. {
  719. PyErr_PrintEx(0);
  720. PyErr_Clear();
  721. throw std::logic_error("Python outMeta failed with error!");
  722. }
  723. // NB: In fact it's impossible situation, becase errors were handled above.
  724. GAPI_Assert(result.get() && "Python outMeta returned NULL!");
  725. out_metas = PyTuple_Check(result.get()) ? get_meta_args(result.get())
  726. : cv::GMetaArgs{get_meta_arg(result.get())};
  727. }
  728. catch (...)
  729. {
  730. PyGILState_Release(gstate);
  731. throw;
  732. }
  733. PyGILState_Release(gstate);
  734. return out_metas;
  735. }
  736. static PyObject* pyopencv_cv_gapi_kernels(PyObject* , PyObject* py_args, PyObject*)
  737. {
  738. using namespace cv;
  739. GKernelPackage pkg;
  740. Py_ssize_t size = PyTuple_Size(py_args);
  741. for (int i = 0; i < size; ++i)
  742. {
  743. PyObject* user_kernel = PyTuple_GetItem(py_args, i);
  744. PyObject* id_obj = PyObject_GetAttrString(user_kernel, "id");
  745. if (!id_obj)
  746. {
  747. PyErr_SetString(PyExc_TypeError,
  748. "Python kernel should contain id, please use cv.gapi.kernel to define kernel");
  749. return NULL;
  750. }
  751. PyObject* out_meta = PyObject_GetAttrString(user_kernel, "outMeta");
  752. if (!out_meta)
  753. {
  754. PyErr_SetString(PyExc_TypeError,
  755. "Python kernel should contain outMeta, please use cv.gapi.kernel to define kernel");
  756. return NULL;
  757. }
  758. PyObject* run = PyObject_GetAttrString(user_kernel, "run");
  759. if (!run)
  760. {
  761. PyErr_SetString(PyExc_TypeError,
  762. "Python kernel should contain run, please use cv.gapi.kernel to define kernel");
  763. return NULL;
  764. }
  765. std::string id;
  766. if (!pyopencv_to(id_obj, id, ArgInfo("id", false)))
  767. {
  768. PyErr_SetString(PyExc_TypeError, "Failed to obtain string");
  769. return NULL;
  770. }
  771. using namespace std::placeholders;
  772. gapi::python::GPythonFunctor f(id.c_str(),
  773. std::bind(run_py_meta , cv::detail::PyObjectHolder{out_meta}, _1, _2),
  774. std::bind(run_py_kernel, cv::detail::PyObjectHolder{run} , _1));
  775. pkg.include(f);
  776. }
  777. return pyopencv_from(pkg);
  778. }
  779. static PyObject* pyopencv_cv_gapi_op(PyObject* , PyObject* py_args, PyObject*)
  780. {
  781. using namespace cv;
  782. Py_ssize_t size = PyTuple_Size(py_args);
  783. std::string id;
  784. if (!pyopencv_to(PyTuple_GetItem(py_args, 0), id, ArgInfo("id", false)))
  785. {
  786. PyErr_SetString(PyExc_TypeError, "Failed to obtain: operation id must be a string");
  787. return NULL;
  788. }
  789. PyObject* outMeta = PyTuple_GetItem(py_args, 1);
  790. cv::GArgs args;
  791. for (int i = 2; i < size; i++)
  792. {
  793. PyObject* item = PyTuple_GetItem(py_args, i);
  794. if (PyObject_TypeCheck(item,
  795. reinterpret_cast<PyTypeObject*>(pyopencv_GMat_TypePtr)))
  796. {
  797. args.emplace_back(reinterpret_cast<pyopencv_GMat_t*>(item)->v);
  798. }
  799. else if (PyObject_TypeCheck(item,
  800. reinterpret_cast<PyTypeObject*>(pyopencv_GScalar_TypePtr)))
  801. {
  802. args.emplace_back(reinterpret_cast<pyopencv_GScalar_t*>(item)->v);
  803. }
  804. else if (PyObject_TypeCheck(item,
  805. reinterpret_cast<PyTypeObject*>(pyopencv_GOpaqueT_TypePtr)))
  806. {
  807. auto&& arg = reinterpret_cast<pyopencv_GOpaqueT_t*>(item)->v.arg();
  808. #define HC(T, K) case cv::GOpaqueT::Storage:: index_of<cv::GOpaque<T>>(): \
  809. args.emplace_back(cv::util::get<cv::GOpaque<T>>(arg)); \
  810. break; \
  811. SWITCH(arg.index(), GOPAQUE_TYPE_LIST_G, HC)
  812. #undef HC
  813. }
  814. else if (PyObject_TypeCheck(item,
  815. reinterpret_cast<PyTypeObject*>(pyopencv_GArrayT_TypePtr)))
  816. {
  817. auto&& arg = reinterpret_cast<pyopencv_GArrayT_t*>(item)->v.arg();
  818. #define HC(T, K) case cv::GArrayT::Storage:: index_of<cv::GArray<T>>(): \
  819. args.emplace_back(cv::util::get<cv::GArray<T>>(arg)); \
  820. break; \
  821. SWITCH(arg.index(), GARRAY_TYPE_LIST_G, HC)
  822. #undef HC
  823. }
  824. else
  825. {
  826. args.emplace_back(cv::GArg(cv::detail::PyObjectHolder{item}));
  827. }
  828. }
  829. cv::GKernel::M outMetaWrapper = std::bind(run_py_meta,
  830. cv::detail::PyObjectHolder{outMeta},
  831. std::placeholders::_1,
  832. std::placeholders::_2);
  833. return pyopencv_from(cv::gapi::wip::op(id, outMetaWrapper, std::move(args)));
  834. }
  835. template<>
  836. bool pyopencv_to(PyObject* obj, cv::detail::ExtractArgsCallback& value, const ArgInfo&)
  837. {
  838. cv::detail::PyObjectHolder holder{obj};
  839. value = cv::detail::ExtractArgsCallback{[=](const cv::GTypesInfo& info)
  840. {
  841. PyGILState_STATE gstate;
  842. gstate = PyGILState_Ensure();
  843. cv::GRunArgs args;
  844. try
  845. {
  846. args = extract_run_args(info, holder.get());
  847. }
  848. catch (...)
  849. {
  850. PyGILState_Release(gstate);
  851. throw;
  852. }
  853. PyGILState_Release(gstate);
  854. return args;
  855. }};
  856. return true;
  857. }
  858. template<>
  859. bool pyopencv_to(PyObject* obj, cv::detail::ExtractMetaCallback& value, const ArgInfo&)
  860. {
  861. cv::detail::PyObjectHolder holder{obj};
  862. value = cv::detail::ExtractMetaCallback{[=](const cv::GTypesInfo& info)
  863. {
  864. PyGILState_STATE gstate;
  865. gstate = PyGILState_Ensure();
  866. cv::GMetaArgs args;
  867. try
  868. {
  869. args = extract_meta_args(info, holder.get());
  870. }
  871. catch (...)
  872. {
  873. PyGILState_Release(gstate);
  874. throw;
  875. }
  876. PyGILState_Release(gstate);
  877. return args;
  878. }};
  879. return true;
  880. }
  881. template<typename T>
  882. struct PyOpenCV_Converter<cv::GArray<T>>
  883. {
  884. static PyObject* from(const cv::GArray<T>& p)
  885. {
  886. return pyopencv_from(cv::GArrayT(p));
  887. }
  888. static bool to(PyObject *obj, cv::GArray<T>& value, const ArgInfo& info)
  889. {
  890. if (PyObject_TypeCheck(obj, reinterpret_cast<PyTypeObject*>(pyopencv_GArrayT_TypePtr)))
  891. {
  892. auto& array = reinterpret_cast<pyopencv_GArrayT_t*>(obj)->v;
  893. try
  894. {
  895. value = cv::util::get<cv::GArray<T>>(array.arg());
  896. }
  897. catch (...)
  898. {
  899. return false;
  900. }
  901. return true;
  902. }
  903. return false;
  904. }
  905. };
  906. template<typename T>
  907. struct PyOpenCV_Converter<cv::GOpaque<T>>
  908. {
  909. static PyObject* from(const cv::GOpaque<T>& p)
  910. {
  911. return pyopencv_from(cv::GOpaqueT(p));
  912. }
  913. static bool to(PyObject *obj, cv::GOpaque<T>& value, const ArgInfo& info)
  914. {
  915. if (PyObject_TypeCheck(obj, reinterpret_cast<PyTypeObject*>(pyopencv_GOpaqueT_TypePtr)))
  916. {
  917. auto& opaque = reinterpret_cast<pyopencv_GOpaqueT_t*>(obj)->v;
  918. try
  919. {
  920. value = cv::util::get<cv::GOpaque<T>>(opaque.arg());
  921. }
  922. catch (...)
  923. {
  924. return false;
  925. }
  926. return true;
  927. }
  928. return false;
  929. }
  930. };
  931. template<>
  932. bool pyopencv_to(PyObject* obj, cv::GProtoInputArgs& value, const ArgInfo& info)
  933. {
  934. try
  935. {
  936. value = extract_proto_args<cv::GProtoInputArgs>(obj);
  937. return true;
  938. }
  939. catch (...)
  940. {
  941. failmsg("Can't parse cv::GProtoInputArgs");
  942. return false;
  943. }
  944. }
  945. template<>
  946. bool pyopencv_to(PyObject* obj, cv::GProtoOutputArgs& value, const ArgInfo& info)
  947. {
  948. try
  949. {
  950. value = extract_proto_args<cv::GProtoOutputArgs>(obj);
  951. return true;
  952. }
  953. catch (...)
  954. {
  955. failmsg("Can't parse cv::GProtoOutputArgs");
  956. return false;
  957. }
  958. }
  959. // extend cv.gapi methods
  960. #define PYOPENCV_EXTRA_METHODS_GAPI \
  961. {"kernels", CV_PY_FN_WITH_KW(pyopencv_cv_gapi_kernels), "kernels(...) -> GKernelPackage"}, \
  962. {"__op", CV_PY_FN_WITH_KW(pyopencv_cv_gapi_op), "__op(...) -> retval\n"},
  963. #endif // HAVE_OPENCV_GAPI
  964. #endif // OPENCV_GAPI_PYOPENCV_GAPI_HPP