From 8bd17163c79231a4afbbdf978864cd2d0c6b1f67 Mon Sep 17 00:00:00 2001 From: Sergei Shutov <48527749+stopmosk@users.noreply.github.com> Date: Wed, 14 Dec 2022 21:15:02 +0200 Subject: [PATCH] Merge pull request #22939 from stopmosk:21826-python-bindings-for-videocapturewaitany Add Python bindings for VideoCapture::waitAny #21826 ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake --- .../include/opencv2/core/bindings_utils.hpp | 8 +++++++ modules/python/src2/cv2_convert.cpp | 24 +++++++++++++++++++ modules/python/src2/cv2_convert.hpp | 1 + modules/python/test/test_misc.py | 22 +++++++++++++++++ modules/videoio/include/opencv2/videoio.hpp | 2 +- .../videoio/misc/python/pyopencv_videoio.hpp | 11 +++++++++ 6 files changed, 67 insertions(+), 1 deletion(-) diff --git a/modules/core/include/opencv2/core/bindings_utils.hpp b/modules/core/include/opencv2/core/bindings_utils.hpp index 76c9437a30..a0710134a9 100644 --- a/modules/core/include/opencv2/core/bindings_utils.hpp +++ b/modules/core/include/opencv2/core/bindings_utils.hpp @@ -35,6 +35,14 @@ String dumpInt(int argument) return cv::format("Int: %d", argument); } +CV_WRAP static inline +String dumpInt64(int64 argument) +{ + std::ostringstream oss("Int64: ", std::ios::ate); + oss << argument; + return oss.str(); +} + CV_WRAP static inline String dumpSizeT(size_t argument) { diff --git a/modules/python/src2/cv2_convert.cpp b/modules/python/src2/cv2_convert.cpp index eb800b6ad5..71e1cc05ee 100644 --- a/modules/python/src2/cv2_convert.cpp +++ b/modules/python/src2/cv2_convert.cpp @@ -444,6 +444,30 @@ PyObject* pyopencv_from(const int& value) // --- int64 +template<> +bool pyopencv_to(PyObject* obj, int64& value, const ArgInfo& info) +{ + if (!obj || obj == Py_None) + { + return true; + } + if (isBool(obj)) + { + failmsg("Argument '%s' must be integer, not bool", info.name); + return false; + } + if (PyArray_IsIntegerScalar(obj)) + { + value = PyLong_AsLongLong(obj); + } + else + { + failmsg("Argument '%s' is required to be an integer", info.name); + return false; + } + return !CV_HAS_CONVERSION_ERROR(value); +} + template<> PyObject* pyopencv_from(const int64& value) { diff --git a/modules/python/src2/cv2_convert.hpp b/modules/python/src2/cv2_convert.hpp index 700f29e3c5..eae20b2c98 100644 --- a/modules/python/src2/cv2_convert.hpp +++ b/modules/python/src2/cv2_convert.hpp @@ -125,6 +125,7 @@ template<> bool pyopencv_to(PyObject* obj, int& value, const ArgInfo& info); template<> PyObject* pyopencv_from(const int& value); // --- int64 +template<> bool pyopencv_to(PyObject* obj, int64& value, const ArgInfo& info); template<> PyObject* pyopencv_from(const int64& value); // There is conflict between "size_t" and "unsigned int". diff --git a/modules/python/test/test_misc.py b/modules/python/test/test_misc.py index deabbd25aa..9b5ab0cf49 100644 --- a/modules/python/test/test_misc.py +++ b/modules/python/test/test_misc.py @@ -253,6 +253,28 @@ class Arguments(NewOpenCVTests): msg=get_no_exception_msg(not_convertible)): _ = cv.utils.dumpInt(not_convertible) + def test_parse_to_int64_convertible(self): + try_to_convert = partial(self._try_to_convert, cv.utils.dumpInt64) + min_int64, max_int64 = get_limits(ctypes.c_longlong) + for convertible in (-10, -1, 2, int(43.2), np.uint8(15), np.int8(33), np.int16(-13), + np.int32(4), np.int64(345), (23), min_int64, max_int64, np.int_(33)): + expected = 'int64: {0:d}'.format(convertible) + actual = try_to_convert(convertible) + self.assertEqual(expected, actual, + msg=get_conversion_error_msg(convertible, expected, actual)) + + def test_parse_to_int64_not_convertible(self): + min_int64, max_int64 = get_limits(ctypes.c_longlong) + for not_convertible in (1.2, np.float(4), float(3), np.double(45), 's', 'str', + np.array([1, 2]), (1,), [1, 2], min_int64 - 1, max_int64 + 1, + complex(1, 1), complex(imag=2), complex(1.1), np.bool_(True), + True, False, np.float32(2.3), np.array([3, ], dtype=int), + np.array([-2, ], dtype=np.int32), np.array([1, ], dtype=np.int), + np.array([11, ], dtype=np.uint8)): + with self.assertRaises((TypeError, OverflowError, ValueError), + msg=get_no_exception_msg(not_convertible)): + _ = cv.utils.dumpInt64(not_convertible) + def test_parse_to_size_t_convertible(self): try_to_convert = partial(self._try_to_convert, cv.utils.dumpSizeT) _, max_uint = get_limits(ctypes.c_uint) diff --git a/modules/videoio/include/opencv2/videoio.hpp b/modules/videoio/include/opencv2/videoio.hpp index 59f1fcb9b0..e05953a5d2 100644 --- a/modules/videoio/include/opencv2/videoio.hpp +++ b/modules/videoio/include/opencv2/videoio.hpp @@ -961,7 +961,7 @@ public: After this call use VideoCapture::retrieve() to decode and fetch frame data. */ - static /*CV_WRAP*/ + CV_WRAP static bool waitAny( const std::vector& streams, CV_OUT std::vector& readyIndex, diff --git a/modules/videoio/misc/python/pyopencv_videoio.hpp b/modules/videoio/misc/python/pyopencv_videoio.hpp index 5fa2f9e221..e729c8631f 100644 --- a/modules/videoio/misc/python/pyopencv_videoio.hpp +++ b/modules/videoio/misc/python/pyopencv_videoio.hpp @@ -1,5 +1,6 @@ #ifdef HAVE_OPENCV_VIDEOIO typedef std::vector vector_VideoCaptureAPIs; +typedef std::vector vector_VideoCapture; template<> struct pyopencvVecConverter { @@ -20,4 +21,14 @@ bool pyopencv_to(PyObject *o, std::vector& apis, const Arg return pyopencvVecConverter::to(o, apis, info); } +template<> bool pyopencv_to(PyObject* obj, cv::VideoCapture& stream, const ArgInfo& info) +{ + Ptr * obj_getp = nullptr; + if (!pyopencv_VideoCapture_getp(obj, obj_getp)) + return (failmsgp("Incorrect type of self (must be 'VideoCapture' or its derivative)") != nullptr); + + stream = **obj_getp; + return true; +} + #endif // HAVE_OPENCV_VIDEOIO