我正在尝试使用Cython包装SparsePyrLKOpticalFlow
OpenCV算法的Cuda版本。到目前为止,我的代码主要基于this post,并在其答案中进行了修改。我想我必须初始化SparsePyrLKOpticalFlow
类的实例,然后使用该类继承自calc
的成员函数SparseOpticalFlow
。
这是我到目前为止所拥有的:
Corner_Tracker.pxd
from libcpp cimport bool
from cpython.ref cimport PyObject
from libcpp.vector cimport vector
# References PyObject to OpenCV object conversion code borrowed from OpenCV's own conversion file, cv2.cpp
cdef extern from 'pyopencv_converter.cpp':
cdef void import_array()
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 cppclass Algorithm:
Algorithm() except +
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/core/cvstd.hpp' namespace 'cv':
cdef cppclass Ptr[T]:
Ptr() except +
Ptr(Ptr*) except +
T& operator* () except +
cdef extern from 'opencv2/cudaoptflow.hpp' namespace 'cv::cuda':
cdef cppclass SparseOpticalFlow:
void calc(GpuMat prevImg, GpuMat nextImg, GpuMat prevPts, GpuMat nextPts, GpuMat status) except +
cdef extern from 'opencv2/cudaoptflow.hpp' namespace 'cv::cuda::SparsePyrLKOpticalFlow':
cdef cppclass SparsePyrLKOpticalFlow(SparseOpticalFlow):
@staticmethod
Ptr[SparsePyrLKOpticalFlow] create(Size winSize, int maxLevel) except +
我怀疑我没有正确输入calc
参数类型,但我不确定还能做什么。
Corner_Tracker.pyx
import numpy as np
import cv2
cimport numpy as np
from cython.operator cimport dereference
def cudaCalcFlowWrapper(
np.ndarray[np.uint8_t, ndim=2] prevImg,
np.ndarray[np.uint8_t, ndim=2] nextImg,
np.ndarray[np.float32_t, ndim=2] prevPts):
np.import_array()
cdef Ptr[SparsePyrLKOpticalFlow] flow_tracker = SparsePyrLKOpticalFlow.create(Size(15,15), 2)
cdef Mat prevImgMat
cdef GpuMat prevImgGpu
pyopencv_to(<PyObject*> prevImg, prevImgMat)
prevImgGpu.upload(prevImgMat)
cdef Mat nextImgMat
cdef GpuMat nextImgGpu
pyopencv_to(<PyObject*> nextImg, nextImgMat)
nextImgGpu.upload(nextImgMat)
cdef Mat prevPtsMat = Mat()
cdef GpuMat prevPtsGpu
pyopencv_to(<PyObject*> prevPts, prevPtsMat)
prevPtsGpu.upload(prevPtsMat)
cdef Mat nextPtsMat
cdef Mat statusMat
cdef GpuMat nextPtsGpu
cdef GpuMat statusGpu
dereference(flow_tracker).calc(prevImgGpu, nextImgGpu, prevPtsGpu, nextPtsGpu, statusGpu)
nextPtsGpu.download(nextPtsMat)
statusGpu.download(statusMat)
cdef np.ndarray nextPts = <np.ndarray> pyopencv_from(nextPtsMat)
cdef np.ndarray status = <np.ndarray> pyopencv_from(statusMat)
return nextPts, status
setup.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
# 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('Corner_Tracker',
sources=[os.path.join(CUR_DIR, 'Corner_Tracker.pyx')],
language='c++',
include_dirs=[np.get_include()] + opencv_incs,
extra_link_args=opencv_libs)
]
setup(
cmdclass={'build_ext': build_ext},
name="Corner_Tracker",
ext_modules=cythonize(extensions)
)
当我运行python setup.py build_ext --inplace
时,我明白了:
Compiling Corner_Tracker.pyx because it changed.
[1/1] Cythonizing Corner_Tracker.pyx
running build_ext
building 'Corner_Tracker' extension
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -Wdate-time -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security -fPIC -I/home/sccarey/.virtualenvs/cv/local/lib/python2.7/site-packages/numpy/core/include -I-I/usr/local/include/opencv -I-I/usr/local/include -I/usr/include/python2.7 -c Corner_Tracker.cpp -o build/temp.linux-x86_64-2.7/Corner_Tracker.o
cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++
In file included from /home/sccarey/.virtualenvs/cv/local/lib/python2.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1816:0,
from /home/sccarey/.virtualenvs/cv/local/lib/python2.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:18,
from pyopencv_converter.cpp:2,
from Corner_Tracker.cpp:623:
/home/sccarey/.virtualenvs/cv/local/lib/python2.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:15:2: warning: #warning "Using deprecated NumPy API, disable it by " "#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION" [-Wcpp]
#warning "Using deprecated NumPy API, disable it by " \
^
Corner_Tracker.cpp: In function ‘PyObject* __pyx_pf_14Corner_Tracker_cudaCalcFlowWrapper(PyObject*, PyArrayObject*, PyArrayObject*, PyArrayObject*)’:
Corner_Tracker.cpp:1843:67: error: type/value mismatch at argument 1 in template parameter list for ‘template<class T> struct cv::Ptr’
cv::Ptr<cv::cuda::SparsePyrLKOpticalFlow::SparsePyrLKOpticalFlow> __pyx_v_flow_tracker;
^
Corner_Tracker.cpp:1843:67: note: expected a type, got ‘cv::cuda::SparsePyrLKOpticalFlow::SparsePyrLKOpticalFlow’
Corner_Tracker.cpp:1866:67: error: type/value mismatch at argument 1 in template parameter list for ‘template<class T> struct cv::Ptr’
cv::Ptr<cv::cuda::SparsePyrLKOpticalFlow::SparsePyrLKOpticalFlow> __pyx_t_3;
^
Corner_Tracker.cpp:1866:67: note: expected a type, got ‘cv::cuda::SparsePyrLKOpticalFlow::SparsePyrLKOpticalFlow’
Corner_Tracker.cpp:1868:3: error: ‘cv::cuda::SparsePyrLKOpticalFlow::SparsePyrLKOpticalFlow’ names the constructor, not the type
cv::cuda::SparsePyrLKOpticalFlow::SparsePyrLKOpticalFlow __pyx_t_5;
^
Corner_Tracker.cpp:1868:60: error: expected ‘;’ before ‘__pyx_t_5’
cv::cuda::SparsePyrLKOpticalFlow::SparsePyrLKOpticalFlow __pyx_t_5;
^
Corner_Tracker.cpp:1868:69: error: statement cannot resolve address of overloaded function
cv::cuda::SparsePyrLKOpticalFlow::SparsePyrLKOpticalFlow __pyx_t_5;
^
Corner_Tracker.cpp:1923:81: error: invalid user-defined conversion from ‘cv::Ptr<cv::cuda::SparsePyrLKOpticalFlow>’ to ‘int’ [-fpermissive]
__pyx_t_3 = cv::cuda::SparsePyrLKOpticalFlow::SparsePyrLKOpticalFlow::create(__pyx_t_2, 2);
^
In file included from /usr/local/include/opencv2/core/cvstd.hpp:1067:0,
from /usr/local/include/opencv2/core/base.hpp:56,
from /usr/local/include/opencv2/core.hpp:54,
from /usr/local/include/opencv2/core/core.hpp:48,
from pyopencv_converter.cpp:3,
from Corner_Tracker.cpp:623:
/usr/local/include/opencv2/core/ptr.inl.hpp:222:1: note: candidate is: cv::Ptr<T>::operator T*() const [with T = cv::cuda::SparsePyrLKOpticalFlow] <near match>
Ptr<T>::operator T* () const
^
/usr/local/include/opencv2/core/ptr.inl.hpp:222:1: note: no known conversion from ‘cv::cuda::SparsePyrLKOpticalFlow*’ to ‘int’
Corner_Tracker.cpp:2022:5: error: ‘__pyx_t_5’ was not declared in this scope
__pyx_t_5 = * __pyx_v_flow_tracker;
^
Corner_Tracker.cpp:2022:19: error: invalid type argument of unary ‘*’ (have ‘int’)
__pyx_t_5 = * __pyx_v_flow_tracker;
^
Corner_Tracker.cpp:2028:5: error: ‘__pyx_t_5’ was not declared in this scope
__pyx_t_5.calc(__pyx_v_prevImgGpu, __pyx_v_nextImgGpu, __pyx_v_prevPtsGpu, __pyx_v_nextPtsGpu, __pyx_v_statusGpu);
^
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1
我已经玩了几天,但我开始认为我只是在我的头上。 有人可以帮助我吗?
编辑:我通过用numpy数组替换包装器参数中的memoryviews来修复了一个不相关的错误。
编辑:应用@DavidW建议的更改后,我收到了这个新错误:
Corner_Tracker.cpp: In function ‘PyObject* __pyx_pf_14Corner_Tracker_cudaCalcFlowWrapper(PyObject*, PyArrayObject*, PyArrayObject*, PyArrayObject*)’:
Corner_Tracker.cpp:1868:36: error: cannot declare variable ‘__pyx_t_5’ to be of abstract type ‘cv::cuda::SparsePyrLKOpticalFlow’
cv::cuda::SparsePyrLKOpticalFlow __pyx_t_5;
^
In file included from Corner_Tracker.cpp:628:0:
/usr/local/include/opencv2/cudaoptflow.hpp:160:18: note: because the following virtual functions are pure within ‘cv::cuda::SparsePyrLKOpticalFlow’:
class CV_EXPORTS SparsePyrLKOpticalFlow : public SparseOpticalFlow
^
/usr/local/include/opencv2/cudaoptflow.hpp:99:18: note: virtual void cv::cuda::SparseOpticalFlow::calc(cv::InputArray, cv::InputArray, cv::InputArray, cv::InputOutputArray, cv::OutputArray, cv::OutputArray, cv::cuda::Stream&)
virtual void calc(InputArray prevImg, InputArray nextImg,
^
/usr/local/include/opencv2/cudaoptflow.hpp:163:18: note: virtual cv::Size cv::cuda::SparsePyrLKOpticalFlow::getWinSize() const
virtual Size getWinSize() const = 0;
^
/usr/local/include/opencv2/cudaoptflow.hpp:164:18: note: virtual void cv::cuda::SparsePyrLKOpticalFlow::setWinSize(cv::Size)
virtual void setWinSize(Size winSize) = 0;
^
/usr/local/include/opencv2/cudaoptflow.hpp:166:17: note: virtual int cv::cuda::SparsePyrLKOpticalFlow::getMaxLevel() const
virtual int getMaxLevel() const = 0;
^
/usr/local/include/opencv2/cudaoptflow.hpp:167:18: note: virtual void cv::cuda::SparsePyrLKOpticalFlow::setMaxLevel(int)
virtual void setMaxLevel(int maxLevel) = 0;
^
/usr/local/include/opencv2/cudaoptflow.hpp:169:17: note: virtual int cv::cuda::SparsePyrLKOpticalFlow::getNumIters() const
virtual int getNumIters() const = 0;
^
/usr/local/include/opencv2/cudaoptflow.hpp:170:18: note: virtual void cv::cuda::SparsePyrLKOpticalFlow::setNumIters(int)
virtual void setNumIters(int iters) = 0;
^
/usr/local/include/opencv2/cudaoptflow.hpp:172:18: note: virtual bool cv::cuda::SparsePyrLKOpticalFlow::getUseInitialFlow() const
virtual bool getUseInitialFlow() const = 0;
^
/usr/local/include/opencv2/cudaoptflow.hpp:173:18: note: virtual void cv::cuda::SparsePyrLKOpticalFlow::setUseInitialFlow(bool)
virtual void setUseInitialFlow(bool useInitialFlow) = 0;
^
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1
答案 0 :(得分:0)
根据错误消息,您的主要问题是命名空间声明
cdef extern from 'opencv2/cudaoptflow.hpp' namespace 'cv::cuda::SparsePyrLKOpticalFlow':
cdef cppclass SparsePyrLKOpticalFlow(SparseOpticalFlow):
# ...
编译器输出报告
错误:'cv :: cuda :: SparsePyrLKOpticalFlow :: SparsePyrLKOpticalFlow'命名构造函数,而不是类型
因此,您希望将此类的命名空间更改为'cv::cuda'
。
这不是错误,但如果您将pyopencv_from/to
声明为
cdef object pyopencv_from(const Mat& m)
cdef bool pyopencv_to(object, Mat& m)
然后您不必转发到PyObject*
您使用抽象变量的问题来自
行dereference(flow_tracker).calc(prevImgGpu, nextImgGpu, prevPtsGpu, nextPtsGpu, statusGpu)
这是因为它试图(粗略地):
SparsePyrLKOptical tmp_variable
try {
tmp_variable = dereference(flow_tracker)
}
catch(...) {
// handle errors
}
tmp_variable.calc(...)
由于SparsePyrLKOptical
是抽象的,你只能创建它的派生类,但实际上不能直接创建它。
如果从行except +
中删除T& operator* () except +
,则Cython不会创建错误检查代码,因此不需要临时代码。我怀疑这是正确的,operator*
实际上不会抛出异常,但如果可以,它有可能停止你的程序。