Python — возвращает сложный объект, содержащий PyObject, из функции c ++

Я пытаюсь обернуть некоторые классы и функции C ++ в Python, используя Cython.
Пока что я обернул 2 класса, и теперь я хочу обернуть функцию.

Подпись функции

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

Я успешно завернул CLNF а также FaceModelParameters классы, и у меня возникли проблемы с обертыванием этого 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 [...])

5

Решение

К сожалению, вы не можете использовать автоматический Cython std::map->dict а также std::vector->list преобразования здесь. Я думаю, что основная проблема при написании такого преобразования заключается в том, что 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 ++ никогда не уменьшает счетчик ссылок PyObjects в векторах (и поэтому вам нужно уменьшить его самостоятельно, чтобы учесть разрушение вектора). Второе предположение заключается в том, что ни один из PyObject* NULL.

(Это проверено для компиляции в Cython, но у меня нет способа проверить, что он компилируется в C ++ или работает правильно).


Редактировать: Я понял, что допустил небольшую ошибку в подсчете ссылок, которая теперь должна быть исправлена.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]