2017-01-28 7 views
5

Cythonを使ってPythonにいくつかのC++クラスと関数をラップしようとしています。 これまでは2つのクラスをラップしていましたが、今は関数をラップしたいと思います。Pythonを含む複雑なオブジェクトをC++関数から返すCython

関数のシグネチャは、私がCLNFFaceModelParametersクラスを成功裏に包まれている、と私はトラブルこのanalyze機能をラップを持っています

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

です。

この関数はopencvを扱うのでPyObject*を扱うので、それらの言語間で簡単に渡すことができます。 とpythonオブジェクトとの間、およびpython Matとcv::Matの間のキャストを実行するために私はthese functionsを使用しています。

これは私の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 [...]をいう)

答えて

2

残念ながら、あなたがすることができますCythonの自動std::map - >dictstd::vector - >listのコンバージョンを使用しないでください。私はそのような変換を書く際の根本的な問題は、Cythonが参照カウントで何をしているのか分からないことだと思います。

ベクトルをPyObject*としてテンプレートし、独自の変換関数を記述する必要があります。そこPyObject*でそのテンプレートがCythonを混同しているようだわずかな合併症だが、それはのtypedefでラウンドを働いたことができます。PyObject*<object>にキャストし、

# 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 

は基本的に、我々はマップを反復し、その中のベクトルを反復します。私はここで参照カウントについての前提を作った - あなたのC++コードがベクトル内のPyObjectの参照カウントを決して減少させないと仮定しています(そして、ベクトルの破壊のためにあなた自身でそれを減らす必要があります)。第2の仮定は、PyObject*のどれもがNULLでないということです。

(これはCythonでコンパイルするためにテストされていますが、C++でコンパイルされているか正しく動作しているかをテストする方法はありません。


編集:私は今、修正すべき参照カウントのわずかなミスを犯したのだということに気づきました。

関連する問題