mirror of
https://github.com/opencv/opencv.git
synced 2026-07-21 19:33:03 +04:00
ba19416730
### Pull Request Readiness Checklist resolves #16295 ``` docker run --gpus 0 -v ~/opencv:/opencv -v ~/opencv_contrib:/opencv_contrib -it nvidia/cuda:12.8.1-cudnn-devel-ubuntu22.04 apt-get update && apt-get install -y cmake python3-dev python3-pip python3-venv && python3 -m venv .venv && source .venv/bin/activate && pip install -U pip && pip install -U numpy && pip install torch --index-url https://download.pytorch.org/whl/cu128 && cmake \ -DWITH_OPENCL=OFF \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_DOCS=OFF \ -DWITH_CUDA=ON \ -DOPENCV_DNN_CUDA=ON \ -DOPENCV_EXTRA_MODULES_PATH=/opencv_contrib/modules \ -DBUILD_LIST=ts,cudev,python3 \ -S /opencv -B /opencv_build && cmake --build /opencv_build -j16 export PYTHONPATH=/opencv_build/lib/python3/:$PYTHONPATH ``` 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
196 lines
6.8 KiB
C++
196 lines
6.8 KiB
C++
#ifdef HAVE_OPENCV_CORE
|
|
|
|
#include "opencv2/core/cuda.hpp"
|
|
|
|
typedef std::vector<cuda::GpuMat> vector_GpuMat;
|
|
typedef cuda::GpuMat::Allocator GpuMat_Allocator;
|
|
typedef cuda::HostMem::AllocType HostMem_AllocType;
|
|
typedef cuda::Event::CreateFlags Event_CreateFlags;
|
|
|
|
template<> struct pyopencvVecConverter<cuda::GpuMat>
|
|
{
|
|
static bool to(PyObject* obj, std::vector<cuda::GpuMat>& value, const ArgInfo& info)
|
|
{
|
|
return pyopencv_to_generic_vec(obj, value, info);
|
|
}
|
|
|
|
static PyObject* from(const std::vector<cuda::GpuMat>& value)
|
|
{
|
|
return pyopencv_from_generic_vec(value);
|
|
}
|
|
};
|
|
|
|
CV_PY_TO_CLASS(cuda::GpuMat)
|
|
CV_PY_TO_CLASS(cuda::GpuMatND)
|
|
CV_PY_TO_CLASS(cuda::Stream)
|
|
CV_PY_TO_CLASS(cuda::Event)
|
|
CV_PY_TO_CLASS(cuda::HostMem)
|
|
|
|
CV_PY_TO_CLASS_PTR(cuda::GpuMat)
|
|
CV_PY_TO_CLASS_PTR(cuda::GpuMatND)
|
|
CV_PY_TO_CLASS_PTR(cuda::GpuMat::Allocator)
|
|
|
|
CV_PY_FROM_CLASS(cuda::GpuMat)
|
|
CV_PY_FROM_CLASS(cuda::GpuMatND)
|
|
CV_PY_FROM_CLASS(cuda::Stream)
|
|
CV_PY_FROM_CLASS(cuda::HostMem)
|
|
|
|
CV_PY_FROM_CLASS_PTR(cuda::GpuMat::Allocator)
|
|
|
|
template<>
|
|
bool fillDLPackTensor(const Ptr<cv::cuda::GpuMat>& src, DLManagedTensor* tensor, const DLDevice& device)
|
|
{
|
|
if ((device.device_type != -1 && device.device_type != kDLCUDA) || device.device_id != 0)
|
|
{
|
|
PyErr_SetString(PyExc_BufferError, "GpuMat can be exported only on GPU:0");
|
|
return false;
|
|
}
|
|
tensor->dl_tensor.data = src->cudaPtr();
|
|
tensor->dl_tensor.device.device_type = kDLCUDA;
|
|
tensor->dl_tensor.device.device_id = 0;
|
|
tensor->dl_tensor.dtype = GetDLPackType(src->elemSize1(), src->depth());
|
|
tensor->dl_tensor.shape[0] = src->rows;
|
|
tensor->dl_tensor.shape[1] = src->cols;
|
|
tensor->dl_tensor.shape[2] = src->channels();
|
|
tensor->dl_tensor.strides[0] = src->step1();
|
|
tensor->dl_tensor.strides[1] = src->channels();
|
|
tensor->dl_tensor.strides[2] = 1;
|
|
tensor->dl_tensor.byte_offset = 0;
|
|
return true;
|
|
}
|
|
|
|
template<>
|
|
bool fillDLPackTensor(const Ptr<cv::cuda::GpuMatND>& src, DLManagedTensor* tensor, const DLDevice& device)
|
|
{
|
|
if ((device.device_type != -1 && device.device_type != kDLCUDA) || device.device_id != 0)
|
|
{
|
|
PyErr_SetString(PyExc_BufferError, "GpuMatND can be exported only on GPU:0");
|
|
return false;
|
|
}
|
|
tensor->dl_tensor.data = src->getDevicePtr();
|
|
tensor->dl_tensor.device.device_type = kDLCUDA;
|
|
tensor->dl_tensor.device.device_id = 0;
|
|
tensor->dl_tensor.dtype = GetDLPackType(src->elemSize1(), CV_MAT_DEPTH(src->flags));
|
|
for (int i = 0; i < src->dims; ++i)
|
|
tensor->dl_tensor.shape[i] = src->size[i];
|
|
for (int i = 0; i < src->dims; ++i)
|
|
tensor->dl_tensor.strides[i] = src->step[i];
|
|
tensor->dl_tensor.byte_offset = 0;
|
|
return true;
|
|
}
|
|
|
|
template<>
|
|
bool parseDLPackTensor(DLManagedTensor* tensor, cv::cuda::GpuMat& obj, bool copy)
|
|
{
|
|
if (tensor->dl_tensor.byte_offset != 0)
|
|
{
|
|
PyErr_SetString(PyExc_BufferError, "Unimplemented from_dlpack for GpuMat with memory offset");
|
|
return false;
|
|
}
|
|
if (tensor->dl_tensor.ndim != 3)
|
|
{
|
|
PyErr_SetString(PyExc_BufferError, "cuda_GpuMat.from_dlpack expects a 3D tensor. Use cuda_GpuMatND.from_dlpack instead");
|
|
return false;
|
|
}
|
|
if (tensor->dl_tensor.device.device_type != kDLCUDA)
|
|
{
|
|
PyErr_SetString(PyExc_BufferError, "cuda_GpuMat.from_dlpack expects a tensor on CUDA device");
|
|
return false;
|
|
}
|
|
if (tensor->dl_tensor.strides[1] != tensor->dl_tensor.shape[2] ||
|
|
tensor->dl_tensor.strides[2] != 1)
|
|
{
|
|
PyErr_SetString(PyExc_BufferError, "Unexpected strides for image. Try use GpuMatND");
|
|
return false;
|
|
}
|
|
int type = DLPackTypeToCVType(tensor->dl_tensor.dtype, (int)tensor->dl_tensor.shape[2]);
|
|
if (type == -1)
|
|
return false;
|
|
|
|
obj = cv::cuda::GpuMat(
|
|
static_cast<int>(tensor->dl_tensor.shape[0]),
|
|
static_cast<int>(tensor->dl_tensor.shape[1]),
|
|
type,
|
|
tensor->dl_tensor.data,
|
|
tensor->dl_tensor.strides[0] * tensor->dl_tensor.dtype.bits / 8
|
|
);
|
|
if (copy)
|
|
obj = obj.clone();
|
|
return true;
|
|
}
|
|
|
|
template<>
|
|
bool parseDLPackTensor(DLManagedTensor* tensor, cv::cuda::GpuMatND& obj, bool copy)
|
|
{
|
|
if (tensor->dl_tensor.byte_offset != 0)
|
|
{
|
|
PyErr_SetString(PyExc_BufferError, "Unimplemented from_dlpack for GpuMat with memory offset");
|
|
return false;
|
|
}
|
|
if (tensor->dl_tensor.device.device_type != kDLCUDA)
|
|
{
|
|
PyErr_SetString(PyExc_BufferError, "cuda_GpuMat.from_dlpack expects a tensor on CUDA device");
|
|
return false;
|
|
}
|
|
int type = DLPackTypeToCVType(tensor->dl_tensor.dtype, (int)tensor->dl_tensor.shape[2]);
|
|
if (type == -1)
|
|
return false;
|
|
|
|
std::vector<size_t> steps(tensor->dl_tensor.ndim - 1);
|
|
std::vector<int> sizes(tensor->dl_tensor.ndim);
|
|
for (int i = 0; i < tensor->dl_tensor.ndim - 1; ++i)
|
|
{
|
|
steps[i] = tensor->dl_tensor.strides[i] * tensor->dl_tensor.dtype.bits / 8;
|
|
sizes[i] = static_cast<int>(tensor->dl_tensor.shape[i]);
|
|
}
|
|
sizes.back() = static_cast<int>(tensor->dl_tensor.shape[tensor->dl_tensor.ndim - 1]);
|
|
obj = cv::cuda::GpuMatND(sizes, type, tensor->dl_tensor.data, steps);
|
|
if (copy)
|
|
obj = obj.clone();
|
|
return true;
|
|
}
|
|
|
|
template<>
|
|
int GetNumDims(const Ptr<cv::cuda::GpuMat>& src) { return 3; }
|
|
|
|
template<>
|
|
int GetNumDims(const Ptr<cv::cuda::GpuMatND>& src) { return src->dims; }
|
|
|
|
static PyObject* pyDLPackGpuMat(PyObject* self, PyObject* py_args, PyObject* kw) {
|
|
Ptr<cv::cuda::GpuMat> * self1 = 0;
|
|
if (!pyopencv_cuda_GpuMat_getp(self, self1))
|
|
return failmsgp("Incorrect type of self (must be 'cuda_GpuMat' or its derivative)");
|
|
return to_dlpack(*(self1), self, py_args, kw);
|
|
}
|
|
|
|
static PyObject* pyDLPackGpuMatND(PyObject* self, PyObject* py_args, PyObject* kw) {
|
|
Ptr<cv::cuda::GpuMatND> * self1 = 0;
|
|
if (!pyopencv_cuda_GpuMatND_getp(self, self1))
|
|
return failmsgp("Incorrect type of self (must be 'cuda_GpuMatND' or its derivative)");
|
|
return to_dlpack(*(self1), self, py_args, kw);
|
|
}
|
|
|
|
static PyObject* pyDLPackDeviceCUDA(PyObject*, PyObject*, PyObject*) {
|
|
return pyopencv_from(std::tuple<int, int>(kDLCUDA, 0));
|
|
}
|
|
|
|
static PyObject* pyGpuMatFromDLPack(PyObject*, PyObject* py_args, PyObject* kw) {
|
|
return from_dlpack<cv::cuda::GpuMat>(py_args, kw);
|
|
}
|
|
|
|
static PyObject* pyGpuMatNDFromDLPack(PyObject*, PyObject* py_args, PyObject* kw) {
|
|
return from_dlpack<cv::cuda::GpuMatND>(py_args, kw);
|
|
}
|
|
|
|
#define PYOPENCV_EXTRA_METHODS_cuda_GpuMat \
|
|
{"__dlpack__", CV_PY_FN_WITH_KW(pyDLPackGpuMat), ""}, \
|
|
{"__dlpack_device__", CV_PY_FN_WITH_KW(pyDLPackDeviceCUDA), ""}, \
|
|
{"from_dlpack", CV_PY_FN_WITH_KW_(pyGpuMatFromDLPack, METH_STATIC), ""}, \
|
|
|
|
#define PYOPENCV_EXTRA_METHODS_cuda_GpuMatND \
|
|
{"__dlpack__", CV_PY_FN_WITH_KW(pyDLPackGpuMatND), ""}, \
|
|
{"__dlpack_device__", CV_PY_FN_WITH_KW(pyDLPackDeviceCUDA), ""}, \
|
|
{"from_dlpack", CV_PY_FN_WITH_KW_(pyGpuMatNDFromDLPack, METH_STATIC), ""}, \
|
|
|
|
#endif
|