1 #ifndef OPENCV_GAPI_PYOPENCV_GAPI_HPP
2 #define OPENCV_GAPI_PYOPENCV_GAPI_HPP
4 #ifdef HAVE_OPENCV_GAPI
7 #pragma warning(disable: 4503) // "decorated name length exceeded"
10 #include <opencv2/gapi/cpu/gcpukernel.hpp>
11 #include <opencv2/gapi/python/python.hpp>
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>;
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>;
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>;
48 // FIXME: Python wrapper generate code without namespace std,
49 // so it cause error: "string wasn't declared"
61 PyObjectHolder(PyObject* o, bool owner = true);
62 PyObject* get() const;
66 std::shared_ptr<Impl> m_impl;
72 class cv::detail::PyObjectHolder::Impl
75 Impl(PyObject* object, bool owner);
76 PyObject* get() const;
83 cv::detail::PyObjectHolder::Impl::Impl(PyObject* object, bool owner)
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.
91 // NB: Impossible take ownership if object is NULL.
97 cv::detail::PyObjectHolder::Impl::~Impl()
99 // NB: If NULL was set, don't decrease counter.
106 PyObject* cv::detail::PyObjectHolder::Impl::get() const
111 cv::detail::PyObjectHolder::PyObjectHolder(PyObject* object, bool owner)
112 : m_impl(new cv::detail::PyObjectHolder::Impl{object, owner})
116 PyObject* cv::detail::PyObjectHolder::get() const
118 return m_impl->get();
122 PyObject* pyopencv_from(const cv::detail::PyObjectHolder& v)
124 PyObject* o = cv::util::any_cast<cv::detail::PyObjectHolder>(v).get();
129 // #FIXME: Is it possible to implement pyopencv_from/pyopencv_to for generic
130 // cv::variant<Types...> ?
132 PyObject* pyopencv_from(const cv::gapi::wip::draw::Prim& prim)
134 switch (prim.index())
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));
152 util::throw_error(std::logic_error("Unsupported draw primitive type"));
156 PyObject* pyopencv_from(const cv::gapi::wip::draw::Prims& value)
158 return pyopencv_from_generic_vec(value);
162 bool pyopencv_to(PyObject* obj, cv::gapi::wip::draw::Prim& value, const ArgInfo& info)
164 #define TRY_EXTRACT(Prim) \
165 if (PyObject_TypeCheck(obj, reinterpret_cast<PyTypeObject*>(pyopencv_gapi_wip_draw_##Prim##_TypePtr))) \
167 value = reinterpret_cast<pyopencv_gapi_wip_draw_##Prim##_t*>(obj)->v; \
179 failmsg("Unsupported primitive type");
184 bool pyopencv_to(PyObject* obj, cv::gapi::wip::draw::Prims& value, const ArgInfo& info)
186 return pyopencv_to_generic_vec(obj, value, info);
190 PyObject* pyopencv_from(const cv::GArg& value)
192 GAPI_Assert(value.kind != cv::detail::ArgKind::GOBJREF);
193 #define HANDLE_CASE(T, O) case cv::detail::OpaqueKind::CV_##T: \
195 return pyopencv_from(value.get<O>()); \
198 #define UNSUPPORTED(T) case cv::detail::OpaqueKind::CV_##T: break
199 switch (value.opaque_kind)
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);
219 util::throw_error(std::logic_error("Unsupported kernel input type"));
223 bool pyopencv_to(PyObject* obj, cv::GArg& value, const ArgInfo& info)
225 value = cv::GArg(cv::detail::PyObjectHolder(obj));
230 bool pyopencv_to(PyObject* obj, std::vector<cv::gapi::GNetParam>& value, const ArgInfo& info)
232 return pyopencv_to_generic_vec(obj, value, info);
236 PyObject* pyopencv_from(const std::vector<cv::gapi::GNetParam>& value)
238 return pyopencv_from_generic_vec(value);
242 bool pyopencv_to(PyObject* obj, std::vector<GCompileArg>& value, const ArgInfo& info)
244 return pyopencv_to_generic_vec(obj, value, info);
248 PyObject* pyopencv_from(const std::vector<GCompileArg>& value)
250 return pyopencv_from_generic_vec(value);
254 PyObject* pyopencv_from(const cv::detail::OpaqueRef& o)
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;
275 PyErr_SetString(PyExc_TypeError, "Unsupported GOpaque type");
280 PyObject* pyopencv_from(const cv::detail::VectorRef& v)
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;
301 PyErr_SetString(PyExc_TypeError, "Unsupported GArray type");
306 PyObject* pyopencv_from(const GRunArg& v)
310 case GRunArg::index_of<cv::Mat>():
311 return pyopencv_from(util::get<cv::Mat>(v));
313 case GRunArg::index_of<cv::Scalar>():
314 return pyopencv_from(util::get<cv::Scalar>(v));
316 case GRunArg::index_of<cv::detail::VectorRef>():
317 return pyopencv_from(util::get<cv::detail::VectorRef>(v));
319 case GRunArg::index_of<cv::detail::OpaqueRef>():
320 return pyopencv_from(util::get<cv::detail::OpaqueRef>(v));
323 PyErr_SetString(PyExc_TypeError, "Failed to unpack GRunArgs. Index of variant is unknown");
327 template <typename T>
328 PyObject* pyopencv_from(const cv::optional<T>& opt)
330 if (!opt.has_value())
334 return pyopencv_from(*opt);
338 PyObject* pyopencv_from(const GOptRunArg& v)
342 case GOptRunArg::index_of<cv::optional<cv::Mat>>():
343 return pyopencv_from(util::get<cv::optional<cv::Mat>>(v));
345 case GOptRunArg::index_of<cv::optional<cv::Scalar>>():
346 return pyopencv_from(util::get<cv::optional<cv::Scalar>>(v));
348 case GOptRunArg::index_of<optional<cv::detail::VectorRef>>():
349 return pyopencv_from(util::get<optional<cv::detail::VectorRef>>(v));
351 case GOptRunArg::index_of<optional<cv::detail::OpaqueRef>>():
352 return pyopencv_from(util::get<optional<cv::detail::OpaqueRef>>(v));
355 PyErr_SetString(PyExc_TypeError, "Failed to unpack GOptRunArg. Index of variant is unknown");
360 PyObject* pyopencv_from(const GRunArgs& value)
362 return value.size() == 1 ? pyopencv_from(value[0]) : pyopencv_from_generic_vec(value);
366 PyObject* pyopencv_from(const GOptRunArgs& value)
368 return value.size() == 1 ? pyopencv_from(value[0]) : pyopencv_from_generic_vec(value);
371 // FIXME: cv::variant should be wrapped once for all types.
373 PyObject* pyopencv_from(const cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>& v)
375 using RunArgs = cv::util::variant<cv::GRunArgs, cv::GOptRunArgs>;
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));
384 PyErr_SetString(PyExc_TypeError, "Failed to recognize kind of RunArgs. Index of variant is unknown");
388 template <typename T>
389 void pyopencv_to_with_check(PyObject* from, T& to, const std::string& msg = "")
391 if (!pyopencv_to(from, to, ArgInfo("", false)))
393 cv::util::throw_error(std::logic_error(msg));
397 template <typename T>
398 void pyopencv_to_generic_vec_with_check(PyObject* from,
400 const std::string& msg = "")
402 if (!pyopencv_to_generic_vec(from, to, ArgInfo("", false)))
404 cv::util::throw_error(std::logic_error(msg));
408 template <typename T>
409 static T extract_proto_args(PyObject* py_args)
414 Py_ssize_t size = PyList_Size(py_args);
416 for (int i = 0; i < size; ++i)
418 PyObject* item = PyList_GetItem(py_args, i);
419 if (PyObject_TypeCheck(item, reinterpret_cast<PyTypeObject*>(pyopencv_GScalar_TypePtr)))
421 args.emplace_back(reinterpret_cast<pyopencv_GScalar_t*>(item)->v);
423 else if (PyObject_TypeCheck(item, reinterpret_cast<PyTypeObject*>(pyopencv_GMat_TypePtr)))
425 args.emplace_back(reinterpret_cast<pyopencv_GMat_t*>(item)->v);
427 else if (PyObject_TypeCheck(item, reinterpret_cast<PyTypeObject*>(pyopencv_GOpaqueT_TypePtr)))
429 args.emplace_back(reinterpret_cast<pyopencv_GOpaqueT_t*>(item)->v.strip());
431 else if (PyObject_TypeCheck(item, reinterpret_cast<PyTypeObject*>(pyopencv_GArrayT_TypePtr)))
433 args.emplace_back(reinterpret_cast<pyopencv_GArrayT_t*>(item)->v.strip());
437 util::throw_error(std::logic_error("Unsupported type for GProtoArgs"));
441 return T(std::move(args));
444 static cv::detail::OpaqueRef extract_opaque_ref(PyObject* from, cv::detail::OpaqueKind kind)
446 #define HANDLE_CASE(T, O) case cv::detail::OpaqueKind::CV_##T: \
449 pyopencv_to_with_check(from, obj, "Failed to obtain " # O); \
450 return cv::detail::OpaqueRef{std::move(obj)}; \
452 #define UNSUPPORTED(T) case cv::detail::OpaqueKind::CV_##T: break
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);
469 UNSUPPORTED(DRAW_PRIM);
473 util::throw_error(std::logic_error("Unsupported type for GOpaqueT"));
476 static cv::detail::VectorRef extract_vector_ref(PyObject* from, cv::detail::OpaqueKind kind)
478 #define HANDLE_CASE(T, O) case cv::detail::OpaqueKind::CV_##T: \
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)}; \
484 #define UNSUPPORTED(T) case cv::detail::OpaqueKind::CV_##T: break
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);
505 util::throw_error(std::logic_error("Unsupported type for GArrayT"));
508 static cv::GRunArg extract_run_arg(const cv::GTypeInfo& info, PyObject* item)
512 case cv::GShape::GMAT:
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)))
518 cv::gapi::wip::IStreamSource::Ptr source =
519 reinterpret_cast<pyopencv_gapi_wip_IStreamSource_t*>(item)->v;
523 pyopencv_to_with_check(item, obj, "Failed to obtain cv::Mat");
526 case cv::GShape::GSCALAR:
529 pyopencv_to_with_check(item, obj, "Failed to obtain cv::Scalar");
532 case cv::GShape::GOPAQUE:
534 return extract_opaque_ref(item, info.kind);
536 case cv::GShape::GARRAY:
538 return extract_vector_ref(item, info.kind);
540 case cv::GShape::GFRAME:
542 // NB: Isn't supported yet.
547 util::throw_error(std::logic_error("Unsupported output shape"));
550 static cv::GRunArgs extract_run_args(const cv::GTypesInfo& info, PyObject* py_args)
552 GAPI_Assert(PyList_Check(py_args));
555 Py_ssize_t list_size = PyList_Size(py_args);
556 args.reserve(list_size);
558 for (int i = 0; i < list_size; ++i)
560 args.push_back(extract_run_arg(info[i], PyList_GetItem(py_args, i)));
566 static cv::GMetaArg extract_meta_arg(const cv::GTypeInfo& info, PyObject* item)
570 case cv::GShape::GMAT:
573 pyopencv_to_with_check(item, obj, "Failed to obtain cv::Mat");
574 return cv::GMetaArg{cv::descr_of(obj)};
576 case cv::GShape::GSCALAR:
579 pyopencv_to_with_check(item, obj, "Failed to obtain cv::Scalar");
580 return cv::GMetaArg{cv::descr_of(obj)};
582 case cv::GShape::GARRAY:
584 return cv::GMetaArg{cv::empty_array_desc()};
586 case cv::GShape::GOPAQUE:
588 return cv::GMetaArg{cv::empty_gopaque_desc()};
590 case cv::GShape::GFRAME:
592 // NB: Isn't supported yet.
596 util::throw_error(std::logic_error("Unsupported output shape"));
599 static cv::GMetaArgs extract_meta_args(const cv::GTypesInfo& info, PyObject* py_args)
601 GAPI_Assert(PyList_Check(py_args));
604 Py_ssize_t list_size = PyList_Size(py_args);
605 metas.reserve(list_size);
607 for (int i = 0; i < list_size; ++i)
609 metas.push_back(extract_meta_arg(info[i], PyList_GetItem(py_args, i)));
615 static cv::GRunArgs run_py_kernel(cv::detail::PyObjectHolder kernel,
616 const cv::gapi::python::GPythonContext &ctx)
618 const auto& ins = ctx.ins;
619 const auto& in_metas = ctx.in_metas;
620 const auto& out_info = ctx.out_info;
622 PyGILState_STATE gstate;
623 gstate = PyGILState_Ensure();
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)
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]))
638 PyTuple_SetItem(args.get(), i, pyopencv_from(ins[i]));
642 switch (in_metas[i].index())
644 case cv::GMetaArg::index_of<cv::GMatDesc>():
645 PyTuple_SetItem(args.get(), i, pyopencv_from(ins[i].get<cv::Mat>()));
647 case cv::GMetaArg::index_of<cv::GScalarDesc>():
648 PyTuple_SetItem(args.get(), i, pyopencv_from(ins[i].get<cv::Scalar>()));
650 case cv::GMetaArg::index_of<cv::GOpaqueDesc>():
651 PyTuple_SetItem(args.get(), i, pyopencv_from(ins[i].get<cv::detail::OpaqueRef>()));
653 case cv::GMetaArg::index_of<cv::GArrayDesc>():
654 PyTuple_SetItem(args.get(), i, pyopencv_from(ins[i].get<cv::detail::VectorRef>()));
656 case cv::GMetaArg::index_of<cv::GFrameDesc>():
657 util::throw_error(std::logic_error("GFrame isn't supported for custom operation"));
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);
667 if (PyErr_Occurred())
671 throw std::logic_error("Python kernel failed with error!");
673 // NB: In fact it's impossible situation, becase errors were handled above.
674 GAPI_Assert(result.get() && "Python kernel returned NULL!");
676 if (out_info.size() == 1)
678 outs = cv::GRunArgs{extract_run_arg(out_info[0], result.get())};
680 else if (out_info.size() > 1)
682 GAPI_Assert(PyTuple_Check(result.get()));
684 Py_ssize_t tuple_size = PyTuple_Size(result.get());
685 outs.reserve(tuple_size);
687 for (int i = 0; i < tuple_size; ++i)
689 outs.push_back(extract_run_arg(out_info[i], PyTuple_GetItem(result.get(), i)));
694 // Seems to be impossible case.
700 PyGILState_Release(gstate);
703 PyGILState_Release(gstate);
708 static GMetaArg get_meta_arg(PyObject* obj)
710 if (PyObject_TypeCheck(obj,
711 reinterpret_cast<PyTypeObject*>(pyopencv_GMatDesc_TypePtr)))
713 return cv::GMetaArg{reinterpret_cast<pyopencv_GMatDesc_t*>(obj)->v};
715 else if (PyObject_TypeCheck(obj,
716 reinterpret_cast<PyTypeObject*>(pyopencv_GScalarDesc_TypePtr)))
718 return cv::GMetaArg{reinterpret_cast<pyopencv_GScalarDesc_t*>(obj)->v};
720 else if (PyObject_TypeCheck(obj,
721 reinterpret_cast<PyTypeObject*>(pyopencv_GArrayDesc_TypePtr)))
723 return cv::GMetaArg{reinterpret_cast<pyopencv_GArrayDesc_t*>(obj)->v};
725 else if (PyObject_TypeCheck(obj,
726 reinterpret_cast<PyTypeObject*>(pyopencv_GOpaqueDesc_TypePtr)))
728 return cv::GMetaArg{reinterpret_cast<pyopencv_GOpaqueDesc_t*>(obj)->v};
732 util::throw_error(std::logic_error("Unsupported output meta type"));
736 static cv::GMetaArgs get_meta_args(PyObject* tuple)
738 size_t size = PyTuple_Size(tuple);
742 for (size_t i = 0; i < size; ++i)
744 metas.push_back(get_meta_arg(PyTuple_GetItem(tuple, i)));
750 static GMetaArgs run_py_meta(cv::detail::PyObjectHolder out_meta,
751 const cv::GMetaArgs &meta,
752 const cv::GArgs &gargs)
754 PyGILState_STATE gstate;
755 gstate = PyGILState_Ensure();
757 cv::GMetaArgs out_metas;
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);
765 for (auto&& m : meta)
769 case cv::GMetaArg::index_of<cv::GMatDesc>():
770 PyTuple_SetItem(args.get(), idx, pyopencv_from(cv::util::get<cv::GMatDesc>(m)));
772 case cv::GMetaArg::index_of<cv::GScalarDesc>():
773 PyTuple_SetItem(args.get(), idx, pyopencv_from(cv::util::get<cv::GScalarDesc>(m)));
775 case cv::GMetaArg::index_of<cv::GArrayDesc>():
776 PyTuple_SetItem(args.get(), idx, pyopencv_from(cv::util::get<cv::GArrayDesc>(m)));
778 case cv::GMetaArg::index_of<cv::GOpaqueDesc>():
779 PyTuple_SetItem(args.get(), idx, pyopencv_from(cv::util::get<cv::GOpaqueDesc>(m)));
781 case cv::GMetaArg::index_of<cv::util::monostate>():
782 PyTuple_SetItem(args.get(), idx, pyopencv_from(gargs[idx]));
784 case cv::GMetaArg::index_of<cv::GFrameDesc>():
785 util::throw_error(std::logic_error("GFrame isn't supported for custom operation"));
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);
795 if (PyErr_Occurred())
799 throw std::logic_error("Python outMeta failed with error!");
801 // NB: In fact it's impossible situation, becase errors were handled above.
802 GAPI_Assert(result.get() && "Python outMeta returned NULL!");
804 out_metas = PyTuple_Check(result.get()) ? get_meta_args(result.get())
805 : cv::GMetaArgs{get_meta_arg(result.get())};
809 PyGILState_Release(gstate);
812 PyGILState_Release(gstate);
817 static PyObject* pyopencv_cv_gapi_kernels(PyObject* , PyObject* py_args, PyObject*)
820 gapi::GKernelPackage pkg;
821 Py_ssize_t size = PyTuple_Size(py_args);
823 for (int i = 0; i < size; ++i)
825 PyObject* user_kernel = PyTuple_GetItem(py_args, i);
827 PyObject* id_obj = PyObject_GetAttrString(user_kernel, "id");
830 PyErr_SetString(PyExc_TypeError,
831 "Python kernel should contain id, please use cv.gapi.kernel to define kernel");
835 PyObject* out_meta = PyObject_GetAttrString(user_kernel, "outMeta");
838 PyErr_SetString(PyExc_TypeError,
839 "Python kernel should contain outMeta, please use cv.gapi.kernel to define kernel");
843 PyObject* run = PyObject_GetAttrString(user_kernel, "run");
846 PyErr_SetString(PyExc_TypeError,
847 "Python kernel should contain run, please use cv.gapi.kernel to define kernel");
852 if (!pyopencv_to(id_obj, id, ArgInfo("id", false)))
854 PyErr_SetString(PyExc_TypeError, "Failed to obtain string");
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));
864 return pyopencv_from(pkg);
867 static PyObject* pyopencv_cv_gapi_op(PyObject* , PyObject* py_args, PyObject*)
870 Py_ssize_t size = PyTuple_Size(py_args);
872 if (!pyopencv_to(PyTuple_GetItem(py_args, 0), id, ArgInfo("id", false)))
874 PyErr_SetString(PyExc_TypeError, "Failed to obtain: operation id must be a string");
877 PyObject* outMeta = PyTuple_GetItem(py_args, 1);
880 for (int i = 2; i < size; i++)
882 PyObject* item = PyTuple_GetItem(py_args, i);
883 if (PyObject_TypeCheck(item,
884 reinterpret_cast<PyTypeObject*>(pyopencv_GMat_TypePtr)))
886 args.emplace_back(reinterpret_cast<pyopencv_GMat_t*>(item)->v);
888 else if (PyObject_TypeCheck(item,
889 reinterpret_cast<PyTypeObject*>(pyopencv_GScalar_TypePtr)))
891 args.emplace_back(reinterpret_cast<pyopencv_GScalar_t*>(item)->v);
893 else if (PyObject_TypeCheck(item,
894 reinterpret_cast<PyTypeObject*>(pyopencv_GOpaqueT_TypePtr)))
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)); \
901 SWITCH(arg.index(), GOPAQUE_TYPE_LIST_G, HC)
904 else if (PyObject_TypeCheck(item,
905 reinterpret_cast<PyTypeObject*>(pyopencv_GArrayT_TypePtr)))
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)); \
912 SWITCH(arg.index(), GARRAY_TYPE_LIST_G, HC)
917 args.emplace_back(cv::GArg(cv::detail::PyObjectHolder{item}));
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)));
929 bool pyopencv_to(PyObject* obj, cv::detail::ExtractArgsCallback& value, const ArgInfo&)
931 cv::detail::PyObjectHolder holder{obj};
932 value = cv::detail::ExtractArgsCallback{[=](const cv::GTypesInfo& info)
934 PyGILState_STATE gstate;
935 gstate = PyGILState_Ensure();
940 args = extract_run_args(info, holder.get());
944 PyGILState_Release(gstate);
947 PyGILState_Release(gstate);
954 bool pyopencv_to(PyObject* obj, cv::detail::ExtractMetaCallback& value, const ArgInfo&)
956 cv::detail::PyObjectHolder holder{obj};
957 value = cv::detail::ExtractMetaCallback{[=](const cv::GTypesInfo& info)
959 PyGILState_STATE gstate;
960 gstate = PyGILState_Ensure();
965 args = extract_meta_args(info, holder.get());
969 PyGILState_Release(gstate);
972 PyGILState_Release(gstate);
979 struct PyOpenCV_Converter<cv::GArray<T>>
981 static PyObject* from(const cv::GArray<T>& p)
983 return pyopencv_from(cv::GArrayT(p));
985 static bool to(PyObject *obj, cv::GArray<T>& value, const ArgInfo& info)
987 if (PyObject_TypeCheck(obj, reinterpret_cast<PyTypeObject*>(pyopencv_GArrayT_TypePtr)))
989 auto& array = reinterpret_cast<pyopencv_GArrayT_t*>(obj)->v;
992 value = cv::util::get<cv::GArray<T>>(array.arg());
1004 template<typename T>
1005 struct PyOpenCV_Converter<cv::GOpaque<T>>
1007 static PyObject* from(const cv::GOpaque<T>& p)
1009 return pyopencv_from(cv::GOpaqueT(p));
1011 static bool to(PyObject *obj, cv::GOpaque<T>& value, const ArgInfo& info)
1013 if (PyObject_TypeCheck(obj, reinterpret_cast<PyTypeObject*>(pyopencv_GOpaqueT_TypePtr)))
1015 auto& opaque = reinterpret_cast<pyopencv_GOpaqueT_t*>(obj)->v;
1018 value = cv::util::get<cv::GOpaque<T>>(opaque.arg());
1031 bool pyopencv_to(PyObject* obj, cv::GProtoInputArgs& value, const ArgInfo& info)
1035 value = extract_proto_args<cv::GProtoInputArgs>(obj);
1040 failmsg("Can't parse cv::GProtoInputArgs");
1046 bool pyopencv_to(PyObject* obj, cv::GProtoOutputArgs& value, const ArgInfo& info)
1050 value = extract_proto_args<cv::GProtoOutputArgs>(obj);
1055 failmsg("Can't parse cv::GProtoOutputArgs");
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"},
1066 #endif // HAVE_OPENCV_GAPI
1067 #endif // OPENCV_GAPI_PYOPENCV_GAPI_HPP