From 223b110c30eda9b876ec76a29fac8bd5138e747c Mon Sep 17 00:00:00 2001 From: Prasad Ayush Kumar <129419372+Prasadayus@users.noreply.github.com> Date: Tue, 12 May 2026 17:13:46 +0530 Subject: [PATCH] Merge pull request #28968 from Prasadayus:Identity_function_fix_for_0D Fixes the issue for Identity functions for 0D #28968 Closes https://github.com/opencv/opencv/issues/25763 ### 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/python/src2/cv2_convert.cpp | 36 ++++++++++++++--------------- modules/python/src2/cv2_numpy.cpp | 12 ++++------ modules/python/src2/cv2_util.cpp | 19 +++++++++++++++ modules/python/src2/cv2_util.hpp | 3 +++ modules/python/test/test_misc.py | 3 +++ 5 files changed, 47 insertions(+), 26 deletions(-) diff --git a/modules/python/src2/cv2_convert.cpp b/modules/python/src2/cv2_convert.cpp index c02a83a15e..01d48a362d 100644 --- a/modules/python/src2/cv2_convert.cpp +++ b/modules/python/src2/cv2_convert.cpp @@ -129,18 +129,7 @@ bool pyopencv_to(PyObject* o, Mat& m, const ArgInfo& info) bool needcopy = false, needcast = false; int typenum = PyArray_TYPE(oarr), new_typenum = typenum; - int type = typenum == NPY_UBYTE ? CV_8U : - typenum == NPY_BYTE ? CV_8S : - typenum == NPY_USHORT ? CV_16U : - typenum == NPY_SHORT ? CV_16S : - typenum == NPY_INT ? CV_32S : - typenum == NPY_UINT32 ? CV_32U : - typenum == NPY_INT32 ? CV_32S : - typenum == NPY_HALF ? CV_16F : - typenum == NPY_FLOAT ? CV_32F : - typenum == NPY_DOUBLE ? CV_64F : - typenum == NPY_BOOL ? CV_Bool : - -1; + int type = numpyTypeToCvDepth(typenum); if( type < 0 ) { @@ -296,12 +285,14 @@ bool pyopencv_to(PyObject* o, Mat& m, const ArgInfo& info) return filled; } - // handle degenerate case - // FIXIT: Don't force 1D for Scalars - if( ndims == 0) { - size[ndims] = 1; - step[ndims] = elemsize; - ndims++; + // 0D (scalar) tensor: allocate a proper scalar Mat and copy the value. + if (ndims == 0) + { + m.fit(0, nullptr, type); + memcpy(m.data, PyArray_DATA(oarr), CV_ELEM_SIZE(type)); + if (needcopy) + Py_DECREF(o); + return true; } #if 1 @@ -326,6 +317,15 @@ PyObject* pyopencv_from(const cv::Mat& m) { if( !m.data ) Py_RETURN_NONE; + // 0D (scalar) Mat: return a true 0D numpy array. + if( m.dims == 0 ) + { + int typenum = cvDepthToNumpyType(CV_MAT_DEPTH(m.type())); + PyObject* o = PyArray_SimpleNew(0, nullptr, typenum); + if( o ) + memcpy(PyArray_DATA((PyArrayObject*)o), m.data, CV_ELEM_SIZE(m.type())); + return o; + } cv::Mat temp, *p = (cv::Mat*)&m; if(!p->u || p->allocator != &GetNumpyAllocator()) { diff --git a/modules/python/src2/cv2_numpy.cpp b/modules/python/src2/cv2_numpy.cpp index 3c211830de..dfd94a3f92 100644 --- a/modules/python/src2/cv2_numpy.cpp +++ b/modules/python/src2/cv2_numpy.cpp @@ -15,8 +15,9 @@ UMatData* NumpyAllocator::allocate(PyObject* o, int dims, const int* sizes, int npy_intp* _strides = PyArray_STRIDES((PyArrayObject*) o); for( int i = 0; i < dims - 1; i++ ) step[i] = (size_t)_strides[i]; - step[dims-1] = CV_ELEM_SIZE(type); - u->size = sizes[0]*step[0]; + if( dims > 0 ) + step[dims-1] = CV_ELEM_SIZE(type); + u->size = dims > 0 ? sizes[0]*step[0] : CV_ELEM_SIZE(type); u->userdata = o; return u; } @@ -33,12 +34,7 @@ UMatData* NumpyAllocator::allocate(int dims0, const int* sizes, int type, void* int depth = CV_MAT_DEPTH(type); int cn = CV_MAT_CN(type); - const int f = (int)(sizeof(size_t)/8); - int typenum = depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE : - depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT : - depth == CV_32U ? NPY_UINT32 : depth == CV_32S ? NPY_INT32 : depth == CV_64S ? NPY_INT64 : - depth == CV_32F ? NPY_FLOAT : depth == CV_64F ? NPY_DOUBLE : depth == CV_16F ? NPY_HALF : - depth == CV_Bool ? NPY_BOOL : f*NPY_ULONGLONG + (f^1)*NPY_UINT; + int typenum = cvDepthToNumpyType(depth); int i, dims = dims0; cv::AutoBuffer _sizes(dims + 1); for( i = 0; i < dims; i++ ) diff --git a/modules/python/src2/cv2_util.cpp b/modules/python/src2/cv2_util.cpp index 817a4a8eff..625d071612 100644 --- a/modules/python/src2/cv2_util.cpp +++ b/modules/python/src2/cv2_util.cpp @@ -6,6 +6,25 @@ PyObject* opencv_error = NULL; cv::TLSData > conversionErrorsTLS; +int cvDepthToNumpyType(int depth) +{ + const int f = (int)(sizeof(size_t)/8); + return depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE : + depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT : + depth == CV_32U ? NPY_UINT32 : depth == CV_32S ? NPY_INT32 : depth == CV_64S ? NPY_INT64 : + depth == CV_32F ? NPY_FLOAT : depth == CV_64F ? NPY_DOUBLE : depth == CV_16F ? NPY_HALF : + depth == CV_Bool ? NPY_BOOL : f*NPY_ULONGLONG + (f^1)*NPY_UINT; +} + +int numpyTypeToCvDepth(int typenum) +{ + return typenum == NPY_UBYTE ? CV_8U : typenum == NPY_BYTE ? CV_8S : + typenum == NPY_USHORT ? CV_16U : typenum == NPY_SHORT ? CV_16S : + typenum == NPY_INT ? CV_32S : typenum == NPY_UINT32 ? CV_32U : typenum == NPY_INT32 ? CV_32S : + typenum == NPY_HALF ? CV_16F : typenum == NPY_FLOAT ? CV_32F : typenum == NPY_DOUBLE ? CV_64F : + typenum == NPY_BOOL ? CV_Bool : -1; +} + using namespace cv; //====================================================================================================================== diff --git a/modules/python/src2/cv2_util.hpp b/modules/python/src2/cv2_util.hpp index a7deb5b575..4c68094afa 100644 --- a/modules/python/src2/cv2_util.hpp +++ b/modules/python/src2/cv2_util.hpp @@ -14,6 +14,9 @@ void emit_failmsg(PyObject * exc, const char *msg); int failmsg(const char *fmt, ...); PyObject* failmsgp(const char *fmt, ...); +int cvDepthToNumpyType(int depth); +int numpyTypeToCvDepth(int typenum); + //====================================================================================================================== class PyAllowThreads diff --git a/modules/python/test/test_misc.py b/modules/python/test/test_misc.py index 7c7646e6c0..cd0c117f92 100644 --- a/modules/python/test/test_misc.py +++ b/modules/python/test/test_misc.py @@ -281,6 +281,9 @@ class Arguments(NewOpenCVTests): 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") + a = np.array(3.14, dtype=np.float32) + res9 = cv.utils.dumpInputArray(a) + self.assertEqual(res9, "InputArray: empty()=false kind=0x00010000 flags=0x01010000 total(-1)=1 dims(-1)=0 size(-1)=1x1 type(-1)=CV_32FC1") def test_InputArrayOfArrays(self): res1 = cv.utils.dumpInputArrayOfArrays(None)