From fdf033295428e6c7fa67335019d004f05f7a6080 Mon Sep 17 00:00:00 2001 From: Pierre Chatelier Date: Fri, 21 Nov 2025 06:41:12 +0100 Subject: [PATCH] Merge pull request #23913 from chacha21:GpuMatND_InputOutputArray make cuda::GpuMatND compatible with InputArray/OutputArray #23913 continuation of [PR#19259](https://github.com/opencv/opencv/pull/19259) Make cuda::GpuMatND wrappable in InputArray/OutputArray The goal for now is just wrapping, some functions are not supported (InputArray::size(), InputArray::convertTo(), InputArray::assign()...) No new feature for cuda::GpuMatND - [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 - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake --- modules/core/include/opencv2/core/base.hpp | 1 + modules/core/include/opencv2/core/mat.hpp | 11 +- modules/core/include/opencv2/core/mat.inl.hpp | 19 ++- modules/core/src/matrix_wrap.cpp | 138 ++++++++++++++++++ 4 files changed, 166 insertions(+), 3 deletions(-) diff --git a/modules/core/include/opencv2/core/base.hpp b/modules/core/include/opencv2/core/base.hpp index 63c0a01b50..e295a5f7e1 100644 --- a/modules/core/include/opencv2/core/base.hpp +++ b/modules/core/include/opencv2/core/base.hpp @@ -698,6 +698,7 @@ namespace ogl namespace cuda { class CV_EXPORTS GpuMat; + class CV_EXPORTS GpuMatND; class CV_EXPORTS HostMem; class CV_EXPORTS Stream; class CV_EXPORTS Event; diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index e8cb786e3f..7a260abe04 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -185,7 +185,8 @@ public: #if OPENCV_ABI_COMPATIBILITY < 500 STD_ARRAY =14 << KIND_SHIFT, //!< removed: https://github.com/opencv/opencv/issues/18897 #endif - STD_ARRAY_MAT =15 << KIND_SHIFT + STD_ARRAY_MAT =15 << KIND_SHIFT, + CUDA_GPU_MATND =16 << KIND_SHIFT }; _InputArray(); @@ -204,6 +205,7 @@ public: _InputArray(const double& val); _InputArray(const cuda::GpuMat& d_mat); _InputArray(const std::vector& d_mat_array); + _InputArray(const cuda::GpuMatND& d_mat); _InputArray(const ogl::Buffer& buf); _InputArray(const cuda::HostMem& cuda_mem); template _InputArray(const cudev::GpuMat_<_Tp>& m); @@ -223,6 +225,7 @@ public: void getUMatVector(std::vector& umv) const; void getGpuMatVector(std::vector& gpumv) const; cuda::GpuMat getGpuMat() const; + cuda::GpuMatND getGpuMatND() const; ogl::Buffer getOGlBuffer() const; int getFlags() const; @@ -255,6 +258,7 @@ public: bool isVector() const; bool isGpuMat() const; bool isGpuMatVector() const; + bool isGpuMatND() const; ~_InputArray(); protected: @@ -318,6 +322,7 @@ public: _OutputArray(std::vector& vec); _OutputArray(cuda::GpuMat& d_mat); _OutputArray(std::vector& d_mat); + _OutputArray(cuda::GpuMatND& d_mat); _OutputArray(ogl::Buffer& buf); _OutputArray(cuda::HostMem& cuda_mem); template _OutputArray(cudev::GpuMat_<_Tp>& m); @@ -336,6 +341,7 @@ public: _OutputArray(const std::vector& vec); _OutputArray(const cuda::GpuMat& d_mat); _OutputArray(const std::vector& d_mat); + _OutputArray(const cuda::GpuMatND& d_mat); _OutputArray(const ogl::Buffer& buf); _OutputArray(const cuda::HostMem& cuda_mem); template _OutputArray(const cudev::GpuMat_<_Tp>& m); @@ -363,6 +369,7 @@ public: UMat& getUMatRef(int i=-1) const; cuda::GpuMat& getGpuMatRef() const; std::vector& getGpuMatVecRef() const; + cuda::GpuMatND& getGpuMatNDRef() const; ogl::Buffer& getOGlBufferRef() const; cuda::HostMem& getHostMemRef() const; void create(Size sz, int type, int i=-1, bool allowTransposed=false, _OutputArray::DepthMask fixedDepthMask=static_cast<_OutputArray::DepthMask>(0)) const; @@ -393,6 +400,7 @@ public: _InputOutputArray(Mat& m); _InputOutputArray(std::vector& vec); _InputOutputArray(cuda::GpuMat& d_mat); + _InputOutputArray(cuda::GpuMatND& d_mat); _InputOutputArray(ogl::Buffer& buf); _InputOutputArray(cuda::HostMem& cuda_mem); template _InputOutputArray(cudev::GpuMat_<_Tp>& m); @@ -410,6 +418,7 @@ public: _InputOutputArray(const std::vector& vec); _InputOutputArray(const cuda::GpuMat& d_mat); _InputOutputArray(const std::vector& d_mat); + _InputOutputArray(const cuda::GpuMatND& d_mat); _InputOutputArray(const ogl::Buffer& buf); _InputOutputArray(const cuda::HostMem& cuda_mem); template _InputOutputArray(const cudev::GpuMat_<_Tp>& m); diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp index d11d5051e9..f034064351 100644 --- a/modules/core/include/opencv2/core/mat.inl.hpp +++ b/modules/core/include/opencv2/core/mat.inl.hpp @@ -151,7 +151,10 @@ inline _InputArray::_InputArray(const cuda::GpuMat& d_mat) { init(+CUDA_GPU_MAT + ACCESS_READ, &d_mat); } inline _InputArray::_InputArray(const std::vector& d_mat) -{ init(+STD_VECTOR_CUDA_GPU_MAT + ACCESS_READ, &d_mat);} +{ init(+STD_VECTOR_CUDA_GPU_MAT + ACCESS_READ, &d_mat);} + +inline _InputArray::_InputArray(const cuda::GpuMatND& d_mat) +{ init(+CUDA_GPU_MATND + ACCESS_READ, &d_mat); } inline _InputArray::_InputArray(const ogl::Buffer& buf) { init(+OPENGL_BUFFER + ACCESS_READ, &buf); } @@ -197,6 +200,7 @@ inline bool _InputArray::isVector() const { return kind() == _InputArray::STD_VE (kind() == _InputArray::MATX && (sz.width <= 1 || sz.height <= 1)); } inline bool _InputArray::isGpuMat() const { return kind() == _InputArray::CUDA_GPU_MAT; } inline bool _InputArray::isGpuMatVector() const { return kind() == _InputArray::STD_VECTOR_CUDA_GPU_MAT; } +inline bool _InputArray::isGpuMatND() const { return kind() == _InputArray::CUDA_GPU_MATND; } //////////////////////////////////////////////////////////////////////////////////////// @@ -275,7 +279,10 @@ inline _OutputArray::_OutputArray(cuda::GpuMat& d_mat) { init(+CUDA_GPU_MAT + ACCESS_WRITE, &d_mat); } inline _OutputArray::_OutputArray(std::vector& d_mat) -{ init(+STD_VECTOR_CUDA_GPU_MAT + ACCESS_WRITE, &d_mat);} +{ init(+STD_VECTOR_CUDA_GPU_MAT + ACCESS_WRITE, &d_mat);} + +inline _OutputArray::_OutputArray(cuda::GpuMatND& d_mat) +{ init(+CUDA_GPU_MATND + ACCESS_WRITE, &d_mat); } inline _OutputArray::_OutputArray(ogl::Buffer& buf) { init(+OPENGL_BUFFER + ACCESS_WRITE, &buf); } @@ -298,6 +305,8 @@ inline _OutputArray::_OutputArray(const std::vector& vec) inline _OutputArray::_OutputArray(const cuda::GpuMat& d_mat) { init(FIXED_TYPE + FIXED_SIZE + CUDA_GPU_MAT + ACCESS_WRITE, &d_mat); } +inline _OutputArray::_OutputArray(const cuda::GpuMatND& d_mat) +{ init(+FIXED_TYPE + FIXED_SIZE + CUDA_GPU_MATND + ACCESS_WRITE, &d_mat); } inline _OutputArray::_OutputArray(const ogl::Buffer& buf) { init(FIXED_TYPE + FIXED_SIZE + OPENGL_BUFFER + ACCESS_WRITE, &buf); } @@ -400,6 +409,9 @@ _InputOutputArray::_InputOutputArray(const _Tp* vec, int n) inline _InputOutputArray::_InputOutputArray(cuda::GpuMat& d_mat) { init(+CUDA_GPU_MAT + ACCESS_RW, &d_mat); } +inline _InputOutputArray::_InputOutputArray(cuda::GpuMatND& d_mat) +{ init(+CUDA_GPU_MATND + ACCESS_RW, &d_mat); } + inline _InputOutputArray::_InputOutputArray(ogl::Buffer& buf) { init(+OPENGL_BUFFER + ACCESS_RW, &buf); } @@ -427,6 +439,9 @@ inline _InputOutputArray::_InputOutputArray(const std::vector& d_m template<> inline _InputOutputArray::_InputOutputArray(std::vector& d_mat) { init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_CUDA_GPU_MAT + ACCESS_RW, &d_mat);} +inline _InputOutputArray::_InputOutputArray(const cuda::GpuMatND& d_mat) +{ init(+FIXED_TYPE + FIXED_SIZE + CUDA_GPU_MATND + ACCESS_RW, &d_mat); } + inline _InputOutputArray::_InputOutputArray(const ogl::Buffer& buf) { init(FIXED_TYPE + FIXED_SIZE + OPENGL_BUFFER + ACCESS_RW, &buf); } diff --git a/modules/core/src/matrix_wrap.cpp b/modules/core/src/matrix_wrap.cpp index 4ddb89f638..a8366a5f6c 100644 --- a/modules/core/src/matrix_wrap.cpp +++ b/modules/core/src/matrix_wrap.cpp @@ -111,6 +111,12 @@ Mat _InputArray::getMat_(int i) const CV_Error(cv::Error::StsNotImplemented, "You should explicitly call download method for cuda::GpuMat object"); } + if( k == CUDA_GPU_MATND ) + { + CV_Assert( i < 0 ); + CV_Error(cv::Error::StsNotImplemented, "You should explicitly call download method for cuda::GpuMatND object"); + } + if( k == CUDA_HOST_MEM ) { CV_Assert( i < 0 ); @@ -357,6 +363,22 @@ void _InputArray::getGpuMatVector(std::vector& gpumv) const CV_Error(Error::StsNotImplemented, "CUDA support is not enabled in this OpenCV build (missing HAVE_CUDA)"); #endif } +cuda::GpuMatND _InputArray::getGpuMatND() const +{ +#ifdef HAVE_CUDA + _InputArray::KindFlag k = kind(); + + if (k == CUDA_GPU_MATND) + { + const cuda::GpuMatND* d_mat = (const cuda::GpuMatND*)obj; + return *d_mat; + } + + CV_Error(cv::Error::StsNotImplemented, "getGpuMatND is available only for cuda::GpuMatND"); +#else + CV_Error(Error::StsNotImplemented, "CUDA support is not enabled in this OpenCV build (missing HAVE_CUDA)"); +#endif +} ogl::Buffer _InputArray::getOGlBuffer() const { _InputArray::KindFlag k = kind(); @@ -379,11 +401,29 @@ _InputArray::KindFlag _InputArray::kind() const int _InputArray::rows(int i) const { +#ifdef HAVE_CUDA + _InputArray::KindFlag k = kind(); + if (k == CUDA_GPU_MATND) + { + const cuda::GpuMatND& _gpuMatND = *(const cuda::GpuMatND*)obj; + return (_gpuMatND.dims < 1) ? 0 : _gpuMatND.size[0]; + } +#endif + return size(i).height; } int _InputArray::cols(int i) const { +#ifdef HAVE_CUDA + _InputArray::KindFlag k = kind(); + if (k == CUDA_GPU_MATND) + { + const cuda::GpuMatND& _gpuMatND = *(const cuda::GpuMatND*)obj; + return (_gpuMatND.dims < 2) ? 0 : _gpuMatND.size[1]; + } +#endif + return size(i).width; } @@ -604,8 +644,13 @@ bool _InputArray::sameSize(const _InputArray& arr) const return false; sz1 = m->size(); } + else if ( (k1 == CUDA_GPU_MATND) && (k2 == CUDA_GPU_MATND)) + { + return ((const cuda::GpuMatND*)obj)->size == ((const cuda::GpuMatND*)arr.obj)->size; + } else sz1 = size(); + if( arr.dims() > 2 ) return false; return sz1 == arr.size(); @@ -693,6 +738,12 @@ int _InputArray::dims(int i) const return 2; } + if( k == CUDA_GPU_MATND ) + { + CV_Assert( i < 0 ); + return ((const cuda::GpuMatND*)obj)->dims; + } + if( k == CUDA_HOST_MEM ) { CV_Assert( i < 0 ); @@ -748,6 +799,21 @@ size_t _InputArray::total(int i) const return vv[i].total(); } + if( k == CUDA_GPU_MATND ) + { + CV_Assert( i < 0 ); + size_t res = 0; + const cuda::GpuMatND& _gpuMatND = *((const cuda::GpuMatND*)obj); + if (_gpuMatND.dims > 0) + { + res = 1; + for(int d = 0 ; d<_gpuMatND.dims ; ++d) + res *= _gpuMatND.size[d]; + return res; + } + } + + return size(i).area(); } @@ -825,6 +891,9 @@ int _InputArray::type(int i) const if( k == CUDA_GPU_MAT ) return ((const cuda::GpuMat*)obj)->type(); + if( k == CUDA_GPU_MATND ) + return ((const cuda::GpuMatND*)obj)->type(); + if( k == CUDA_HOST_MEM ) return ((const cuda::HostMem*)obj)->type(); @@ -904,6 +973,9 @@ bool _InputArray::empty() const return vv.empty(); } + if( k == CUDA_GPU_MATND ) + return ((const cuda::GpuMatND*)obj)->empty(); + if( k == CUDA_HOST_MEM ) return ((const cuda::HostMem*)obj)->empty(); @@ -948,6 +1020,9 @@ bool _InputArray::isContinuous(int i) const if( k == CUDA_GPU_MAT ) return i < 0 ? ((const cuda::GpuMat*)obj)->isContinuous() : true; + if( k == CUDA_GPU_MATND ) + return i < 0 ? ((const cuda::GpuMatND*)obj)->isContinuous() : true; + CV_Error(cv::Error::StsNotImplemented, "Unknown/unsupported array type"); } @@ -986,6 +1061,11 @@ bool _InputArray::isSubmatrix(int i) const return vv[i].isSubmatrix(); } + if( k == CUDA_GPU_MATND ) + { + return ((const cuda::GpuMatND*)obj)->isSubmatrix(); + } + CV_Error(cv::Error::StsNotImplemented, ""); } @@ -1101,6 +1181,12 @@ size_t _InputArray::step(int i) const CV_Assert(i >= 0 && (size_t)i < vv.size()); return vv[i].step; } + if( k == CUDA_GPU_MATND ) + { + const cuda::GpuMatND& _gpuMatND = *(const cuda::GpuMatND*)obj; + CV_Assert( i >= _gpuMatND.dims ); + return _gpuMatND.step[i]; + } CV_Error(Error::StsNotImplemented, ""); } @@ -1183,6 +1269,18 @@ void _OutputArray::create(Size _sz, int mtype, int i, bool allowTransposed, _Out return; #else CV_Error(Error::StsNotImplemented, "CUDA support is not enabled in this OpenCV build (missing HAVE_CUDA)"); +#endif + } + if( k == CUDA_GPU_MATND && i < 0 && !allowTransposed && fixedDepthMask == 0 ) + { + CV_Assert(!fixedSize() || ((((cuda::GpuMatND*)obj)->dims == 2) && (((cuda::GpuMatND*)obj)->size[0] == _sz.height) && (((cuda::GpuMatND*)obj)->size[1] == _sz.width))); + CV_Assert(!fixedType() || ((cuda::GpuMatND*)obj)->type() == mtype); +#ifdef HAVE_CUDA + cuda::GpuMatND::SizeArray sizes = {_sz.height, _sz.width}; + ((cuda::GpuMatND*)obj)->create(sizes, mtype); + return; +#else + CV_Error(Error::StsNotImplemented, "CUDA support is not enabled in this OpenCV build (missing HAVE_CUDA)"); #endif } if( k == OPENGL_BUFFER && i < 0 && !allowTransposed && fixedDepthMask == 0 ) @@ -1237,6 +1335,18 @@ void _OutputArray::create(int _rows, int _cols, int mtype, int i, bool allowTran return; #else CV_Error(Error::StsNotImplemented, "CUDA support is not enabled in this OpenCV build (missing HAVE_CUDA)"); +#endif + } + if( k == CUDA_GPU_MATND && i < 0 && !allowTransposed && fixedDepthMask == 0 ) + { + CV_Assert(!fixedSize() || ((((cuda::GpuMatND*)obj)->dims == 2) && (((cuda::GpuMatND*)obj)->size[0] == _rows) && (((cuda::GpuMatND*)obj)->size[1] == _cols))); + CV_Assert(!fixedType() || ((cuda::GpuMatND*)obj)->type() == mtype); +#ifdef HAVE_CUDA + cuda::GpuMatND::SizeArray sizes = {_rows, _cols}; + ((cuda::GpuMatND*)obj)->create(sizes, mtype); + return; +#else + CV_Error(Error::StsNotImplemented, "CUDA support is not enabled in this OpenCV build (missing HAVE_CUDA)"); #endif } if( k == OPENGL_BUFFER && i < 0 && !allowTransposed && fixedDepthMask == 0 ) @@ -1653,6 +1763,18 @@ void _OutputArray::create(int d, const int* sizes, int mtype, int i, return; } + if( k == CUDA_GPU_MATND && d > 0 && i < 0 && !allowTransposed && fixedDepthMask == 0 ) + { +#ifdef HAVE_CUDA + cuda::GpuMatND::SizeArray sizeArray = cuda::GpuMatND::SizeArray(sizes, sizes+d); + ((cuda::GpuMatND*)obj)->create(sizeArray, mtype); + return; +#else + CV_Error(Error::StsNotImplemented, "CUDA support is not enabled in this OpenCV build (missing HAVE_CUDA)"); +#endif + } + + CV_Error(Error::StsNotImplemented, "Unknown/unsupported array type"); } @@ -1696,6 +1818,16 @@ void _OutputArray::release() const #endif } + if( k == CUDA_GPU_MATND ) + { +#ifdef HAVE_CUDA + ((cuda::GpuMatND*)obj)->release(); + return; +#else + CV_Error(Error::StsNotImplemented, "CUDA support is not enabled in this OpenCV build (missing HAVE_CUDA)"); +#endif + } + if( k == CUDA_HOST_MEM ) { #ifdef HAVE_CUDA @@ -1827,6 +1959,12 @@ std::vector& _OutputArray::getGpuMatVecRef() const CV_Assert(k == STD_VECTOR_CUDA_GPU_MAT); return *(std::vector*)obj; } +cuda::GpuMatND& _OutputArray::getGpuMatNDRef() const +{ + _InputArray::KindFlag k = kind(); + CV_Assert( k == CUDA_GPU_MATND ); + return *(cuda::GpuMatND*)obj; +} ogl::Buffer& _OutputArray::getOGlBufferRef() const {