Merge pull request #26026 from Abdurrahheem:ash/python_bool_binding

Add support for boolan input/outputs in python bindings #26026

This PR add support boolean input/output binding in python. The issue what mention in ticket https://github.com/opencv/opencv/issues/26024 and the PR soleves it. Data and models are located in [here](https://github.com/opencv/opencv_extra/pull/1201)

### 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
pull/26050/head
Abduragim Shtanchaev 5 months ago committed by GitHub
parent 7e8f2a1bc4
commit 45fd4d8217
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      modules/core/misc/python/pyopencv_core.hpp
  2. 19
      modules/dnn/misc/python/test/test_dnn.py
  3. 5
      modules/python/src2/cv2.cpp
  4. 4
      modules/python/src2/cv2_convert.cpp
  5. 2
      modules/python/src2/cv2_numpy.cpp
  6. 2
      modules/python/src2/typing_stubs_generation/api_refinement.py
  7. 6
      modules/python/test/test_misc.py

@ -29,7 +29,8 @@ static PyObject* pycvMakeTypeCh(PyObject*, PyObject *value) {
{"CV_32SC", (PyCFunction)(pycvMakeTypeCh<CV_32S>), METH_O, "CV_32SC(channels) -> retval"}, \
{"CV_32FC", (PyCFunction)(pycvMakeTypeCh<CV_32F>), METH_O, "CV_32FC(channels) -> retval"}, \
{"CV_64FC", (PyCFunction)(pycvMakeTypeCh<CV_64F>), METH_O, "CV_64FC(channels) -> retval"}, \
{"CV_16FC", (PyCFunction)(pycvMakeTypeCh<CV_16F>), METH_O, "CV_16FC(channels) -> retval"},
{"CV_16FC", (PyCFunction)(pycvMakeTypeCh<CV_16F>), METH_O, "CV_16FC(channels) -> retval"}, \
{"CV_BoolC", (PyCFunction)(pycvMakeTypeCh<CV_Bool>), METH_O, "CV_BoolC(channels) -> retval"},
#endif // HAVE_OPENCV_CORE
#endif // OPENCV_CORE_PYOPENCV_CORE_HPP

@ -546,5 +546,24 @@ class dnn_test(NewOpenCVTests):
out = net.forward()
self.assertEqual(out.shape, (1, 2, 3, 4))
def test_bool_operator(self):
n = self.find_dnn_file('dnn/onnx/models/and_op.onnx')
x = np.random.randint(0, 2, [5], dtype=np.bool_)
y = np.random.randint(0, 2, [5], dtype=np.bool_)
o = x & y
net = cv.dnn.readNet(n)
names = ["x", "y"]
net.setInputsNames(names)
net.setInput(x, names[0])
net.setInput(y, names[1])
out = net.forward()
self.assertTrue(np.all(out == o))
if __name__ == '__main__':
NewOpenCVTests.bootstrap()

@ -562,6 +562,11 @@ static bool init_body(PyObject * m)
PUBLISH(CV_16FC2);
PUBLISH(CV_16FC3);
PUBLISH(CV_16FC4);
PUBLISH(CV_Bool);
PUBLISH(CV_BoolC1);
PUBLISH(CV_BoolC2);
PUBLISH(CV_BoolC3);
PUBLISH(CV_BoolC4);
#undef PUBLISH_
#undef PUBLISH

@ -137,7 +137,9 @@ bool pyopencv_to(PyObject* o, Mat& m, const ArgInfo& info)
typenum == NPY_INT32 ? CV_32S :
typenum == NPY_HALF ? CV_16F :
typenum == NPY_FLOAT ? CV_32F :
typenum == NPY_DOUBLE ? CV_64F : -1;
typenum == NPY_DOUBLE ? CV_64F :
typenum == NPY_BOOL ? CV_Bool :
-1;
if( type < 0 )
{

@ -37,7 +37,7 @@ UMatData* NumpyAllocator::allocate(int dims0, const int* sizes, int type, void*
int typenum = depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE :
depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT :
depth == CV_32S ? NPY_INT : depth == CV_32F ? NPY_FLOAT :
depth == CV_64F ? NPY_DOUBLE : depth == CV_16F ? NPY_HALF : f*NPY_ULONGLONG + (f^1)*NPY_UINT;
depth == CV_64F ? NPY_DOUBLE : depth == CV_16F ? NPY_HALF : depth == CV_Bool ? NPY_BOOL : f*NPY_ULONGLONG + (f^1)*NPY_UINT;
int i, dims = dims0;
cv::AutoBuffer<npy_intp> _sizes(dims + 1);
for( i = 0; i < dims; i++ )

@ -56,7 +56,7 @@ def export_matrix_type_constants(root: NamespaceNode) -> None:
MAX_PREDEFINED_CHANNELS = 4
depth_names = ("CV_8U", "CV_8S", "CV_16U", "CV_16S", "CV_32S",
"CV_32F", "CV_64F", "CV_16F")
"CV_32F", "CV_64F", "CV_16F", "CV_Bool")
for depth_value, depth_name in enumerate(depth_names):
# Export depth constants
root.add_constant(depth_name, str(depth_value))

@ -234,6 +234,7 @@ class Bindings(NewOpenCVTests):
cv.CV_16UC2: [cv.CV_16U, 2, cv.CV_16UC],
cv.CV_32SC1: [cv.CV_32S, 1, cv.CV_32SC],
cv.CV_16FC3: [cv.CV_16F, 3, cv.CV_16FC],
cv.CV_BoolC1: [cv.CV_Bool, 1, cv.CV_BoolC],
}
for ref, (depth, channels, func) in data.items():
self.assertEqual(ref, cv.CV_MAKETYPE(depth, channels))
@ -277,6 +278,9 @@ class Arguments(NewOpenCVTests):
a = np.zeros((2,3,4,5), dtype='f')
res7 = cv.utils.dumpInputArray(a)
self.assertEqual(res7, "InputArray: empty()=false kind=0x00010000 flags=0x01010000 total(-1)=120 dims(-1)=4 size(-1)=[2 3 4 5] type(-1)=CV_32FC1")
a = np.array([0, 1, 0, 1], dtype=bool)
res8 = cv.utils.dumpInputArray(a)
self.assertEqual(res8, "InputArray: empty()=false kind=0x00010000 flags=0x01010000 total(-1)=4 dims(-1)=1 size(-1)=4x1 type(-1)=CV_BoolC1")
def test_InputArrayOfArrays(self):
res1 = cv.utils.dumpInputArrayOfArrays(None)
@ -339,7 +343,7 @@ class Arguments(NewOpenCVTests):
def test_parse_to_bool_not_convertible(self):
for not_convertible in (1.2, np.float32(2.3), 's', 'str', (1, 2), [1, 2], complex(1, 1),
complex(imag=2), complex(1.1), np.array([1, 0], dtype=bool)):
complex(imag=2), complex(1.1)):
with self.assertRaises((TypeError, OverflowError),
msg=get_no_exception_msg(not_convertible)):
_ = cv.utils.dumpBool(not_convertible)

Loading…
Cancel
Save