Merge pull request #22939 from stopmosk:21826-python-bindings-for-videocapturewaitany
authorSergei Shutov <48527749+stopmosk@users.noreply.github.com>
Wed, 14 Dec 2022 19:15:02 +0000 (21:15 +0200)
committerGitHub <noreply@github.com>
Wed, 14 Dec 2022 19:15:02 +0000 (22:15 +0300)
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

modules/core/include/opencv2/core/bindings_utils.hpp
modules/python/src2/cv2_convert.cpp
modules/python/src2/cv2_convert.hpp
modules/python/test/test_misc.py
modules/videoio/include/opencv2/videoio.hpp
modules/videoio/misc/python/pyopencv_videoio.hpp

index 76c9437a30e8bba0fe88f7aefcb3004a13014ac9..a0710134a917419e524bac2baeb234e6def46152 100644 (file)
@@ -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)
 {
index eb800b6ad5bed989ddd123235f66082ba5bde976..71e1cc05ee7faed9b13c11115176dc1f0c8c5feb 100644 (file)
@@ -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)
 {
index 700f29e3c59c8325ff3fb30fd8d449ed1caa99a7..eae20b2c986dddc1b5c0904402831270547b113a 100644 (file)
@@ -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".
index deabbd25aa03159b546afa99e52d9d411718680e..9b5ab0cf4935f908da20c29664d540dd0902f2cd 100644 (file)
@@ -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)
index 59f1fcb9b029c03c4c1dc43f6fb632c3968fc345..e05953a5d2443cad6e90e26299b790f827df31f3 100644 (file)
@@ -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<VideoCapture>& streams,
             CV_OUT std::vector<int>& readyIndex,
index 5fa2f9e221409fa84605231cb9e9b0fceb611c9f..e729c8631f858797f179222f57e741f8d7cc790c 100644 (file)
@@ -1,5 +1,6 @@
 #ifdef HAVE_OPENCV_VIDEOIO
 typedef std::vector<VideoCaptureAPIs> vector_VideoCaptureAPIs;
+typedef std::vector<VideoCapture> vector_VideoCapture;
 
 template<> struct pyopencvVecConverter<cv::VideoCaptureAPIs>
 {
@@ -20,4 +21,14 @@ bool pyopencv_to(PyObject *o, std::vector<cv::VideoCaptureAPIs>& apis, const Arg
   return pyopencvVecConverter<cv::VideoCaptureAPIs>::to(o, apis, info);
 }
 
+template<> bool pyopencv_to(PyObject* obj, cv::VideoCapture& stream, const ArgInfo& info)
+{
+    Ptr<VideoCapture> * 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