从 Python 访问 OpenCV CUDA 函数(无 PyCUDA)
Posted
技术标签:
【中文标题】从 Python 访问 OpenCV CUDA 函数(无 PyCUDA)【英文标题】:Accessing OpenCV CUDA Functions from Python (No PyCUDA) 【发布时间】:2017-06-26 18:38:56 【问题描述】:我正在编写一个 Python 应用程序,它使用 OpenCV 的 Python 绑定来进行标记检测和其他图像处理。我想使用 OpenCV 的 CUDA 模块来 CUDA 加速我的应用程序的某些部分,并在他们的 .hpp
文件中注意到他们似乎正在使用 Python 和 Java 的 OpenCV 导出宏。但是,我似乎无法访问那些 CUDA 功能,即使我正在构建 OpenCV WITH_CUDA=ON
。
是否需要使用诸如 PyCUDA 之类的包装器才能访问 GPU 功能,例如 cudaarithm 中的阈值?或者,如果我在 Python 代码中调用 cv2.threshold()(而不是常规的基于 CPU 的实现),这些 CUDA 加速函数是否已经在使用?
CV_EXPORTS double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type, Stream& stream = Stream::Null());
我看到的cv2
的子模块如下:
cv2.cuda
、cv2.gpu
和 cv2.cudaarithm
都返回 AttributeError
。
我正在运行的用于构建 OpenCV 的 CMake 指令如下:
cmake -DOPENCV_EXTRA_MODULES_PATH=/usr/local/lib/opencv_contrib/modules/ \
-D WITH_CUDA=ON -D CUDA_FAST_MATH=1 \
-D ENABLE_PRECOMPILED_HEADERS=OFF \
-D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=OFF -D BUILD_EXAMPLES=OFF \
-D BUILD_opencv_java=OFF \
-DBUILD_opencv_bgsegm=OFF -DBUILD_opencv_bioinspired=OFF -DBUILD_opencv_ccalib=OFF -DBUILD_opencv_cnn_3dobj=OFF -DBUILD_opencv_contrib_world=OFF -DBUILD_opencv_cvv=OFF -DBUILD_opencv_datasets=OFF -DBUILD_openc
v_dnn=OFF -DBUILD_opencv_dnns_easily_fooled=OFF -DBUILD_opencv_dpm=OFF -DBUILD_opencv_face=OFF -DBUILD_opencv_fuzzy=OFF -DBUILD_opencv_hdf=OFF -DBUILD_opencv_line_descriptor=OFF -DBUILD_opencv_matlab=OFF -DBUILD_o
pencv_optflow=OFF -DBUILD_opencv_plot=OFF -DBUILD_opencv_README.md=OFF -DBUILD_opencv_reg=OFF -DBUILD_opencv_rgbd=OFF -DBUILD_opencv_saliency=OFF -DBUILD_opencv_sfm=OFF -DBUILD_opencv_stereo=OFF -DBUILD_opencv_str
uctured_light=OFF -DBUILD_opencv_surface_matching=OFF -DBUILD_opencv_text=OFF -DBUILD_opencv_tracking=OFF -DBUILD_opencv_viz=OFF -DBUILD_opencv_xfeatures2d=OFF -DBUILD_opencv_ximgproc=OFF -DBUILD_opencv_xobjdetect
=OFF -DBUILD_opencv_xphoto=OFF ..
【问题讨论】:
如您所见,OpenCV 有自己的 python 绑定到 c++ 函数。据我所知,你不需要 pycuda。您使用的是哪个版本的 OpenCV?访问 OpenCV Cuda 函数应该很简单。 嘿@NAmorim,感谢您的评论!我正在使用 OpenCV 3.2.0-dev。但是,当我加载可用于 cv2 的模块时,我没有看到 CUDA 的子模块(请参阅更新的问题)。是否已经在 Python .so 中替换了具有 CUDA 加速对应项的函数? 从 OpenCV 4 开始,python 绑定到 CUDA 加速代码应该可以工作。这是一篇关于如何实现它的帖子:Accelerating OpenCV 4 – build with CUDA 10.0, Intel MKL + TBB and python bindings in Windows 【参考方案1】:正如@NAmorim 的回答和评论线程中所证实的那样,没有可访问的 Python 绑定到 OpenCV 的各种 CUDA 模块。
我能够通过使用 Cython 来访问我需要的 CUDA 函数并实现将我的 Python 对象(主要是 NumPy 数组)转换为 OpenCV C/C++ 的必要逻辑来绕过这个限制对象和背部。
工作代码
我首先编写了一个 Cython 定义文件,GpuWrapper.pxd
。这个文件的目的是引用外部的C/C++类和方法,比如我感兴趣的CUDA方法。
from libcpp cimport bool
from cpython.ref cimport PyObject
# References PyObject to OpenCV object conversion code borrowed from OpenCV's own conversion file, cv2.cpp
cdef extern from 'pyopencv_converter.cpp':
cdef PyObject* pyopencv_from(const Mat& m)
cdef bool pyopencv_to(PyObject* o, Mat& m)
cdef extern from 'opencv2/imgproc.hpp' namespace 'cv':
cdef enum InterpolationFlags:
INTER_NEAREST = 0
cdef enum ColorConversionCodes:
COLOR_BGR2GRAY
cdef extern from 'opencv2/core/core.hpp':
cdef int CV_8UC1
cdef int CV_32FC1
cdef extern from 'opencv2/core/core.hpp' namespace 'cv':
cdef cppclass Size_[T]:
Size_() except +
Size_(T width, T height) except +
T width
T height
ctypedef Size_[int] Size2i
ctypedef Size2i Size
cdef cppclass Scalar[T]:
Scalar() except +
Scalar(T v0) except +
cdef extern from 'opencv2/core/core.hpp' namespace 'cv':
cdef cppclass Mat:
Mat() except +
void create(int, int, int) except +
void* data
int rows
int cols
cdef extern from 'opencv2/core/cuda.hpp' namespace 'cv::cuda':
cdef cppclass GpuMat:
GpuMat() except +
void upload(Mat arr) except +
void download(Mat dst) const
cdef cppclass Stream:
Stream() except +
cdef extern from 'opencv2/cudawarping.hpp' namespace 'cv::cuda':
cdef void warpPerspective(GpuMat src, GpuMat dst, Mat M, Size dsize, int flags, int borderMode, Scalar borderValue, Stream& stream)
# Function using default values
cdef void warpPerspective(GpuMat src, GpuMat dst, Mat M, Size dsize, int flags)
我们还需要将 Python 对象转换为 OpenCV 对象的能力。我从 OpenCV 的modules/python/src2/cv2.cpp
复制了前几百行。您可以在附录中找到该代码。
我们终于可以编写 Cython 包装器方法来调用 OpenCV 的 CUDA 函数了!这是 Cython 实现文件的一部分,GpuWrapper.pyx
。
import numpy as np # Import Python functions, attributes, submodules of numpy
cimport numpy as np # Import numpy C/C++ API
def cudaWarpPerspectiveWrapper(np.ndarray[np.uint8_t, ndim=2] _src,
np.ndarray[np.float32_t, ndim=2] _M,
_size_tuple,
int _flags=INTER_NEAREST):
# Create GPU/device InputArray for src
cdef Mat src_mat
cdef GpuMat src_gpu
pyopencv_to(<PyObject*> _src, src_mat)
src_gpu.upload(src_mat)
# Create CPU/host InputArray for M
cdef Mat M_mat = Mat()
pyopencv_to(<PyObject*> _M, M_mat)
# Create Size object from size tuple
# Note that size/shape in Python is handled in row-major-order -- therefore, width is [1] and height is [0]
cdef Size size = Size(<int> _size_tuple[1], <int> _size_tuple[0])
# Create empty GPU/device OutputArray for dst
cdef GpuMat dst_gpu = GpuMat()
warpPerspective(src_gpu, dst_gpu, M_mat, size, INTER_NEAREST)
# Get result of dst
cdef Mat dst_host
dst_gpu.download(dst_host)
cdef np.ndarray out = <np.ndarray> pyopencv_from(dst_host)
return out
在运行设置脚本以 cythonize 并编译此代码后(见附录),我们可以将 GpuWrapper 作为 Python 模块导入并运行 cudaWarpPerspectiveWrapper
。这让我能够通过 CUDA 运行代码,只有 0.34722222222222854% 的不匹配——非常令人兴奋!
参考文献(最多只能发布 2 个)
What is the easiest way to convert ndarray into cv::Mat? Writing Python bindings for C++ code that use OpenCV附录
pyopencv_converter.cpp
#include <Python.h>
#include "numpy/ndarrayobject.h"
#include "opencv2/core/core.hpp"
static PyObject* opencv_error = 0;
// === FAIL MESSAGE ====================================================================================================
static int failmsg(const char *fmt, ...)
char str[1000];
va_list ap;
va_start(ap, fmt);
vsnprintf(str, sizeof(str), fmt, ap);
va_end(ap);
PyErr_SetString(PyExc_TypeError, str);
return 0;
struct ArgInfo
const char * name;
bool outputarg;
// more fields may be added if necessary
ArgInfo(const char * name_, bool outputarg_)
: name(name_)
, outputarg(outputarg_)
// to match with older pyopencv_to function signature
operator const char *() const return name;
;
// === THREADING =======================================================================================================
class PyAllowThreads
public:
PyAllowThreads() : _state(PyEval_SaveThread())
~PyAllowThreads()
PyEval_RestoreThread(_state);
private:
PyThreadState* _state;
;
class PyEnsureGIL
public:
PyEnsureGIL() : _state(PyGILState_Ensure())
~PyEnsureGIL()
PyGILState_Release(_state);
private:
PyGILState_STATE _state;
;
// === ERROR HANDLING ==================================================================================================
#define ERRWRAP2(expr) \
try \
\
PyAllowThreads allowThreads; \
expr; \
\
catch (const cv::Exception &e) \
\
PyErr_SetString(opencv_error, e.what()); \
return 0; \
// === USING NAMESPACE CV ==============================================================================================
using namespace cv;
// === NUMPY ALLOCATOR =================================================================================================
class NumpyAllocator : public MatAllocator
public:
NumpyAllocator() stdAllocator = Mat::getStdAllocator();
~NumpyAllocator()
UMatData* allocate(PyObject* o, int dims, const int* sizes, int type, size_t* step) const
UMatData* u = new UMatData(this);
u->data = u->origdata = (uchar*)PyArray_DATA((PyArrayObject*) o);
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];
u->userdata = o;
return u;
UMatData* allocate(int dims0, const int* sizes, int type, void* data, size_t* step, int flags, UMatUsageFlags usageFlags) const
if( data != 0 )
CV_Error(Error::StsAssert, "The data should normally be NULL!");
// probably this is safe to do in such extreme case
return stdAllocator->allocate(dims0, sizes, type, data, step, flags, usageFlags);
PyEnsureGIL gil;
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_32S ? NPY_INT : depth == CV_32F ? NPY_FLOAT :
depth == CV_64F ? NPY_DOUBLE : f*NPY_ULONGLONG + (f^1)*NPY_UINT;
int i, dims = dims0;
cv::AutoBuffer<npy_intp> _sizes(dims + 1);
for( i = 0; i < dims; i++ )
_sizes[i] = sizes[i];
if( cn > 1 )
_sizes[dims++] = cn;
PyObject* o = PyArray_SimpleNew(dims, _sizes, typenum);
if(!o)
CV_Error_(Error::StsError, ("The numpy array of typenum=%d, ndims=%d can not be created", typenum, dims));
return allocate(o, dims0, sizes, type, step);
bool allocate(UMatData* u, int accessFlags, UMatUsageFlags usageFlags) const
return stdAllocator->allocate(u, accessFlags, usageFlags);
void deallocate(UMatData* u) const
if(!u)
return;
PyEnsureGIL gil;
CV_Assert(u->urefcount >= 0);
CV_Assert(u->refcount >= 0);
if(u->refcount == 0)
PyObject* o = (PyObject*)u->userdata;
Py_XDECREF(o);
delete u;
const MatAllocator* stdAllocator;
;
// === ALLOCATOR INITIALIZATION ========================================================================================
NumpyAllocator g_numpyAllocator;
// === CONVERTOR FUNCTIONS =============================================================================================
template<typename T> static
bool pyopencv_to(PyObject* obj, T& p, const char* name = "<unknown>");
template<typename T> static
PyObject* pyopencv_from(const T& src);
enum ARG_NONE = 0, ARG_MAT = 1, ARG_SCALAR = 2 ;
// special case, when the convertor needs full ArgInfo structure
static bool pyopencv_to(PyObject* o, Mat& m, const ArgInfo info)
bool allowND = true;
if(!o || o == Py_None)
if( !m.data )
m.allocator = &g_numpyAllocator;
return true;
if( PyInt_Check(o) )
double v[] = static_cast<double>(PyInt_AsLong((PyObject*)o)), 0., 0., 0.;
m = Mat(4, 1, CV_64F, v).clone();
return true;
if( PyFloat_Check(o) )
double v[] = PyFloat_AsDouble((PyObject*)o), 0., 0., 0.;
m = Mat(4, 1, CV_64F, v).clone();
return true;
if( PyTuple_Check(o) )
int i, sz = (int)PyTuple_Size((PyObject*)o);
m = Mat(sz, 1, CV_64F);
for( i = 0; i < sz; i++ )
PyObject* oi = PyTuple_GET_ITEM(o, i);
if( PyInt_Check(oi) )
m.at<double>(i) = (double)PyInt_AsLong(oi);
else if( PyFloat_Check(oi) )
m.at<double>(i) = (double)PyFloat_AsDouble(oi);
else
failmsg("%s is not a numerical tuple", info.name);
m.release();
return false;
return true;
if( !PyArray_Check(o) )
failmsg("%s is not a numpy array, neither a scalar", info.name);
return false;
PyArrayObject* oarr = (PyArrayObject*) o;
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_INT32 ? CV_32S :
typenum == NPY_FLOAT ? CV_32F :
typenum == NPY_DOUBLE ? CV_64F : -1;
if( type < 0 )
if( typenum == NPY_INT64 || typenum == NPY_UINT64 || typenum == NPY_LONG )
needcopy = needcast = true;
new_typenum = NPY_INT;
type = CV_32S;
else
failmsg("%s data type = %d is not supported", info.name, typenum);
return false;
#ifndef CV_MAX_DIM
const int CV_MAX_DIM = 32;
#endif
int ndims = PyArray_NDIM(oarr);
if(ndims >= CV_MAX_DIM)
failmsg("%s dimensionality (=%d) is too high", info.name, ndims);
return false;
int size[CV_MAX_DIM+1];
size_t step[CV_MAX_DIM+1];
size_t elemsize = CV_ELEM_SIZE1(type);
const npy_intp* _sizes = PyArray_DIMS(oarr);
const npy_intp* _strides = PyArray_STRIDES(oarr);
bool ismultichannel = ndims == 3 && _sizes[2] <= CV_CN_MAX;
for( int i = ndims-1; i >= 0 && !needcopy; i-- )
// these checks handle cases of
// a) multi-dimensional (ndims > 2) arrays, as well as simpler 1- and 2-dimensional cases
// b) transposed arrays, where _strides[] elements go in non-descending order
// c) flipped arrays, where some of _strides[] elements are negative
// the _sizes[i] > 1 is needed to avoid spurious copies when NPY_RELAXED_STRIDES is set
if( (i == ndims-1 && _sizes[i] > 1 && (size_t)_strides[i] != elemsize) ||
(i < ndims-1 && _sizes[i] > 1 && _strides[i] < _strides[i+1]) )
needcopy = true;
if( ismultichannel && _strides[1] != (npy_intp)elemsize*_sizes[2] )
needcopy = true;
if (needcopy)
if (info.outputarg)
failmsg("Layout of the output array %s is incompatible with cv::Mat (step[ndims-1] != elemsize or step[1] != elemsize*nchannels)", info.name);
return false;
if( needcast )
o = PyArray_Cast(oarr, new_typenum);
oarr = (PyArrayObject*) o;
else
oarr = PyArray_GETCONTIGUOUS(oarr);
o = (PyObject*) oarr;
_strides = PyArray_STRIDES(oarr);
// Normalize strides in case NPY_RELAXED_STRIDES is set
size_t default_step = elemsize;
for ( int i = ndims - 1; i >= 0; --i )
size[i] = (int)_sizes[i];
if ( size[i] > 1 )
step[i] = (size_t)_strides[i];
default_step = step[i] * size[i];
else
step[i] = default_step;
default_step *= size[i];
// handle degenerate case
if( ndims == 0)
size[ndims] = 1;
step[ndims] = elemsize;
ndims++;
if( ismultichannel )
ndims--;
type |= CV_MAKETYPE(0, size[2]);
if( ndims > 2 && !allowND )
failmsg("%s has more than 2 dimensions", info.name);
return false;
m = Mat(ndims, size, type, PyArray_DATA(oarr), step);
m.u = g_numpyAllocator.allocate(o, ndims, size, type, step);
m.addref();
if( !needcopy )
Py_INCREF(o);
m.allocator = &g_numpyAllocator;
return true;
template<>
bool pyopencv_to(PyObject* o, Mat& m, const char* name)
return pyopencv_to(o, m, ArgInfo(name, 0));
template<>
PyObject* pyopencv_from(const Mat& m)
if( !m.data )
Py_RETURN_NONE;
Mat temp, *p = (Mat*)&m;
if(!p->u || p->allocator != &g_numpyAllocator)
temp.allocator = &g_numpyAllocator;
ERRWRAP2(m.copyTo(temp));
p = &temp;
PyObject* o = (PyObject*)p->u->userdata;
Py_INCREF(o);
return o;
setupGpuWrapper.py
import subprocess
import os
import numpy as np
from distutils.core import setup, Extension
from Cython.Build import cythonize
from Cython.Distutils import build_ext
"""
Run setup with the following command:
```
python setupGpuWrapper.py build_ext --inplace
```
"""
# Determine current directory of this setup file to find our module
CUR_DIR = os.path.dirname(__file__)
# Use pkg-config to determine library locations and include locations
opencv_libs_str = subprocess.check_output("pkg-config --libs opencv".split()).decode()
opencv_incs_str = subprocess.check_output("pkg-config --cflags opencv".split()).decode()
# Parse into usable format for Extension call
opencv_libs = [str(lib) for lib in opencv_libs_str.strip().split()]
opencv_incs = [str(inc) for inc in opencv_incs_str.strip().split()]
extensions = [
Extension('GpuWrapper',
sources=[os.path.join(CUR_DIR, 'GpuWrapper.pyx')],
language='c++',
include_dirs=[np.get_include()] + opencv_incs,
extra_link_args=opencv_libs)
]
setup(
cmdclass='build_ext': build_ext,
name="GpuWrapper",
ext_modules=cythonize(extensions)
)
【讨论】:
我按照您的描述进行操作,但是在应用 cudaWarpPerspectiveWrapper 函数时,出现Segmentation fault (core dumped)
错误,不知道哪里出错了。当我编译 cython 时,我收到了 2 个警告:cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++
warning: #warning "Using deprecated NumPy API, disable it by " "#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION" [-Wcpp]
这似乎很好。我正在使用 opencv 3.3、python 2.7 和 cython 0.26
嘿心瑶,我想我也收到了这些警告——它们应该是无害的。我想我使用的是 OpenCV 3.2、Python 3.2 和 Cython 0.25。 Python版本之间可能存在差异?与 numpy 相关的重要事情是调用 numpy.import_array() - 请参见此处:docs.scipy.org/doc/numpy-1.10.0/user/…。我记得忘记设置时会出现令人沮丧的段错误!
感谢您的回复!我尝试了不同的 python(3.5 和 2.7)和 opencv(3.1、3.2、3.3),但仍然无法正常工作。我认为这是由于没有调用 numpy.import_array() 引起的,因为在您提到之前我对此一无所知。我在这里发了一个问题:link 如果你有时间看看就好了。刚才在github上找到了另外一个代码,可以将numpy数组转成cv mat,但是如果你能提供一些可能的解决方案那就太好了。
我不知道在哪里包含 numpy.import_array(),它似乎不应该包含在我的 .py 文件中,因为 numpy 在 python 中没有属性 import_array。对这些东西太陌生了。
嗨,我尝试将 numpy.import_array() 放在 GpuWrapper.pyx 中,它现在就像一个魅力。感谢您的解决方案,非常感谢!【参考方案2】:
我使用 OpenCV 4.0.0 对此进行了一些测试。 @nchaumont 提到,从 OpenCV 4 开始,包含了 CUDA 的 Python 绑定。
至少从 Open CV 4.1.0 开始,可能更早,默认 Python 绑定包括 CUDA,前提是 Open CV 是在 CUDA 支持下构建的。
大部分功能都显示为cv2.cuda.thing
(例如cv2.cuda.cvtColor()
。)
目前,他们缺乏任何在线文档——例如,GPU Canny edge detector 没有提及 Python。不过,您可以使用 Python 的 REPL 中的 help
函数来查看 C++ 文档,这应该大部分是等效的。
【讨论】:
由于 OpenCV 4.4.0 cv::cuda::CascadeClassifier 应该回来了,但是我找不到 python 绑定。它不在 cv2.cuda.CascadeClassifier 下。其他人有没有机会发现这个? cv2.cuda_CascadeClassifier 给出分段错误..【参考方案3】:我使用以下方式在 Python 中访问 OpenCV 的 C++ CUDA 方法:
-
创建自定义 opencv_contrib 模块
编写 C++ 代码来包装 OpenCV CUDA 方法
使用 OpenCV python 绑定,公开您的自定义方法
使用 opencv_contrib 构建 opencv
运行python代码进行测试
我创建了一个小的github repo 来演示同样的内容
【讨论】:
【参考方案4】:或者,如果我在 Python 代码中调用 cv2.threshold()(而不是常规的、基于 CPU 的实现),这些 CUDA 加速函数是否已经在使用?
不,您必须从 GPU 加速模块显式调用它们。调用 cv2.threshold() 只会运行 CPU 版本。
由于 OpenCV 的 python API 包含 C++ 函数,因此检查 C++ API 通常会提供有关函数/模块所在位置的有用提示。
例如,通过this 转换指南,您可以看到从 OpenCV 2.X 到 3.X 的 API 更改。在这里,OpenCV 3.X 上的 GPU 模块可以通过以前版本的 cv2.cuda 和 cv2.gpu 访问。而3.X中的cuda模块又分为几个小块:
cuda - CUDA 加速的计算机视觉 cudaarithm - 矩阵运算 cudabgsegm - 背景分割 cudacodec - 视频编码/解码 cudafeatures2d - 特征检测和描述 cudafilters - 图像过滤 cudaimgproc - 图像处理 cudalegacy - 旧版支持 cudaoptflow - 光流 cudastereo - 立体声通信 cudawarping - 图像变形 cudev - 设备层
您应该在 cv2 中搜索这些模块。
【讨论】:
不幸的是,我找不到任何应该存在的模块:>>> cv2.cuda Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute 'cuda' >>> cv2.gpu Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute 'gpu' >>> cv2.cudaarithm Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute 'cudaarithm'
您是否让图书馆同时工作?您是否尝试检查构建 OpenCV + Cuda 是否成功?例如,如果你在 python 中运行 print cv2.getBuildInformation() 你应该得到所有被激活的 cmake 标志。有一行应该是 Use Cuda: Yes.
嘿@NAmorim,我确实启用了Use Cuda: Yes
。似乎 Python 没有与 CUDA 相关模块的任何绑定,因为 GpuArray 类型一开始就没有暴露给 Python。我目前正在研究的解决方案是使用 PyCUDA 和 ctypes 从调用 OpenCV CUDA 函数的 Python 调用我自己的 C++ 代码。我会看看这是否是一个好的解决方案,并尽量保持这篇文章的更新!
@ostrumvulpes 这对我来说是新的。我在 c++ 中使用过 Cuda,我认为 python 也会有绑定(好在 opencv python 文档几乎不存在......)。祝你好运!以上是关于从 Python 访问 OpenCV CUDA 函数(无 PyCUDA)的主要内容,如果未能解决你的问题,请参考以下文章
OpenCV Python Cuda CascadeClassifier错误
成功构建后,带有 Cuda 的 Python OpenCV 无法正常工作
Caffe搭建:Ubuntu14.04 + CUDA7.5 + opencv3.1+python3.5
ubuntu16.04+opencv2.4.13+cuda 8.0+python
使用 Qt 和 Cuda for Python 构建 OpenCV,在 build_all cmake 目标上运行到 LNK2019