gpt4 book ai didi

python - 从 C++ 函数 Cython 返回包含 PyObject 的复杂对象

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:42:58 36 4
gpt4 key购买 nike

我正在尝试使用 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,我希望能够在语言之间轻松传递它们。我正在使用 these functions为了在 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这里的转换。我认为编写此类转换的根本问题是 Cython 不知道 C++ 在引用计数方面做了什么,因此很难可靠地做到这一点。

相反,您必须将 vector 模板化为 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

本质上,我们遍历 map ,并遍历其中的 vector ,转换 PyObject*<object> .我在这里做了一个关于引用计数的假设——我假设你的 C++ 代码永远不会减少 PyObject 的引用计数。 vector 中的 s(因此您需要自己减少它以说明 vector 的破坏)。第二个假设是 PyObject* 中没有一个是空的。

(经过测试可以在 Cython 中编译,但我无法测试它是否可以在 C++ 中编译或正确运行)。


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

关于python - 从 C++ 函数 Cython 返回包含 PyObject 的复杂对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41909486/

36 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com