Opencv 如何使用Cython包装SparsePyrLKOpticalFlow的Cuda版本?

Opencv 如何使用Cython包装SparsePyrLKOpticalFlow的Cuda版本?,opencv,cython,wrapper,opticalflow,Opencv,Cython,Wrapper,Opticalflow,我正在尝试使用Cython包装Cuda版本的SparsePyrLKOpticalFlowOpenCV算法。到目前为止,我的代码主要基于答案中的修改。我想我必须初始化SparsePyrLKOpticalFlow类的一个实例,然后使用该类从SparseOpticalFlow继承的成员函数calc 以下是我目前掌握的情况: Corner_Tracker.pxd from libcpp cimport bool from cpython.ref cimport PyObject from libcpp.

我正在尝试使用Cython包装Cuda版本的
SparsePyrLKOpticalFlow
OpenCV算法。到目前为止,我的代码主要基于答案中的修改。我想我必须初始化
SparsePyrLKOpticalFlow
类的一个实例,然后使用该类从
SparseOpticalFlow
继承的成员函数
calc

以下是我目前掌握的情况:

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
当我运行
python setup.py build\u 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

根据错误消息,您的主要问题是名称空间声明

cdef extern from 'opencv2/cudaoptflow.hpp' namespace 'cv::cuda::SparsePyrLKOpticalFlow':
    cdef cppclass SparsePyrLKOpticalFlow(SparseOpticalFlow):
    # ...
编译器输出正在报告

错误:“cv::cuda::SparsePyrLKOpticalFlow::SparsePyrLKOpticalFlow”命名构造函数,而不是类型

因此,您希望将此类的命名空间更改为
'cv::cuda'


这不是bug,但是如果您将
pyopencv\u从/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
是抽象的,因此您只能创建它的派生类,而不能直接创建该类


如果从行
T&operator*()except+
中删除
except+
,则Cython不会创建错误检查代码,因此不需要临时代码。我怀疑这是正确的,
操作符*
实际上不能抛出异常,但如果可以,它有可能停止您的程序。

这两个建议似乎都奏效了!谢谢现在我又犯了一个错误。我会把它钉在我的文章的末尾。它被编译了!不知道我花了多长时间才能找到。非常感谢你!!别担心。(将来,如果您查看生成的.cpp文件,它会包含注释,向您显示与之匹配的Cython代码。这将有助于您缩小问题范围(如果不是解决方案的话)!谢谢
cdef object pyopencv_from(const Mat& m)
cdef bool pyopencv_to(object, Mat& m)
dereference(flow_tracker).calc(prevImgGpu, nextImgGpu, prevPtsGpu, nextPtsGpu, statusGpu)
SparsePyrLKOptical tmp_variable
try {
   tmp_variable = dereference(flow_tracker)
}
catch(...) {
   // handle errors
}
tmp_variable.calc(...)