繁体   English   中英

从c ++函数Cython返回包含PyObject的复杂对象

[英]Returning a complex object containing PyObject from c++ function Cython

我试图使用Cython将一些C ++类和函数包装到Python中。 到目前为止,我已经包装了2个类,现在我想要包装一个函数。

函数的签名是

std::map<std::string, std::vector<PyObject*>> analyze(PyObject* img, LandmarkDetector::CLNF& clnf_model, LandmarkDetector::FaceModelParameters& params);

我已经成功包装了CLNFFaceModelParameters类,并且我无法包装此analyze函数。

该函数处理PyObject*因为它处理opencv,我希望能够在语言之间轻松传递它们。 我正在使用这些函数来执行cv::Point到python对象之间以及python Mat到cv::Mat

这是我的pyx文件:

from libcpp.vector cimport vector
from libcpp.map cimport map
from libcpp.string cimport string
from cpython.ref cimport PyObject
from cython.operator cimport dereference as deref

cdef extern from "LandmarkDetectorModel.h" namespace "LandmarkDetector":
    cdef cppclass CLNF:
        CLNF(string) except +

cdef extern from "LandmarkDetectorParameters.h" namespace "LandmarkDetector":
    cdef cppclass FaceModelParameters:
        FaceModelParameters(vector[string] &) except +

cdef class PyCLNF:
    cdef CLNF *thisptr
    def __cinit__(self, arg):
        self.thisptr = new CLNF(<string> arg)

cdef class PyLandmarkDetectorParameters:
    cdef FaceModelParameters *thisptr
    def __cinit__(self, args):
        self.thisptr = new FaceModelParameters(args)

cdef extern from "FaceLandmarkVid.h":
    map[string, vector[object]] analyze(object, CLNF&, FaceModelParameters&)

cdef PyAnalyze(object img, PyCLNF clnf, PyLandmarkDetectorParameters facemodel):
    return analyze(img, deref(clnf.thisptr), deref(facemodel.thisptr))

但在尝试编译它时,我收到错误消息

landmarks.pyx:26:23: Python object type 'Python object' cannot be used as a template argument

(指的是线map[string, vector[object]] analyze [...]

不幸的是你不能在这里使用Cython的自动std::map - > dictstd::vector - > list conversions。 我认为编写这样一个转换的根本问题是Cython不知道C ++在引用计数方面做了什么,所以很难可靠地做到这一点。

相反,你必须将矢量模板化为PyObject*并编写自己的转换函数。 有一个轻微的复杂性,使用PyObject*进行模板化似乎会混淆Cython但是可以使用typedef进行循环:

# unchanged [...]
from cpython.ref cimport PyObject, Py_DECREF
from cython.operator cimport dereference as deref, preincrement
# unchanged [...]

ctypedef PyObject* PyObjectPtr # I run into a bug templaing vector otherwise

cdef extern from "FaceLandmarkVid.h":
    map[string, vector[PyObjectPtr]] analyze(object, CLNF&, FaceModelParameters&)

# an extra function to convert the vector to a list
cdef convertVector(vector[PyObjectPtr]& v):
    cdef vector[PyObjectPtr].iterator i = v.begin()
    cdef vector[PyObjectPtr].iterator end = v.end()

    cdef list out = []

    while i != end:
        out.append(<object>deref(i))
        # reduce reference count to account for destruction of the
        # vector at the end of the conversion process
        Py_DECREF(<object>deref(i))
        preincrement(i)

    return out

cdef PyAnalyze(object img, PyCLNF clnf, PyLandmarkDetectorParameters facemodel):
    cdef map[string, vector[PyObjectPtr]] res = analyze(img, deref(clnf.thisptr), deref(facemodel.thisptr))
    cdef map[string, vector[PyObjectPtr]].iterator i = res.begin()
    cdef map[string, vector[PyObjectPtr]].iterator end = res.end()

    cdef dict out = {}    

    while i!=end:

        out[deref(i).first] = convertVector(deref(i).second)
        preincrement(i)
    return out

本质上,我们遍历地图,并迭代其中的向量,将PyObject*<object> 我在这里做了一个关于引用计数的假设 - 我假设你的C ++代码永远不会减少向量中PyObject的引用计数(所以你需要自己减少它以解释向量的破坏)。 第二个假设是没有PyObject*为NULL。

(这是测试在Cython中编译但我无法测试它在C ++中编译或正确运行)。


编辑:我意识到我在引用计数方面犯了一个小错误,现在应该更正了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM