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