2017-01-28 39 views
5

Bazı C++ sınıflarını ve işlevleri Cython'u kullanarak Python'a sarmayı deniyorum. Şimdiye kadar 2 sınıf sardım ve şimdi bir işlevi sarmak istiyorum.C++ işlevinden PyObject içeren karmaşık bir nesnenin döndürülmesi Cython

işlevin imza

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

olduğunu başarıyla CLNF ve FaceModelParameters sınıfları sarılmış ettim ve sorun bu analyze işlevi sarma yaşıyorum.

İşlev, PyObject* s ile ilgilenir çünkü opencv ile ilgilenir ve dilleri arasında kolayca geçiş yapmak isterim. cv::Point arasındaki python nesnelerine ve python Mat ile cv::Mat arasındaki döküm işlemini gerçekleştirmek için these functions kullanıyorum.

Bu

benim pyx dosyasıdır:

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)) 

Ama bunu derlemek çalışırken üzerine hata mesaj almak Maalesef

cevap

2

yapabilirsiniz (hattına map[string, vector[object]] analyze [...] atıfta)

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

Cython'un otomatik std::map ->dict ve std::vector ->list dönüşümlerini burada kullanmayın. Böyle bir dönüşümün yazılmasıyla ilgili temel mesele, Cython'un, C++ 'nın referans sayma ile ne yaptığını bilmediğidir, bu yüzden bu doğru güvenilirlik için mücadele eder. Bunun yerine, vektörü PyObject* olarak şablonlandırmanız ve kendi dönüştürme işlevlerinizi yazmanız gerekir. Orada PyObject* o çiftleşmiş Cython şaşırtmak gibi görünüyor hafif komplikasyon var ama bu bir typedef yuvarlak çalışılabilir: PyObject*<object> için döküm,

# 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 

Esasen, biz harita üzerinde yineleme ve içindeki vektörler üzerinde yineleme . Burada referans sayımı ile ilgili bir varsayımda bulunmuştum - C++ kodunuzun vektörlerdeki PyObject s referans sayısını asla azaltmadığını varsayıyorum (ve böylece vektörün yok edilmesini hesaba katmak için kendiniz azaltmalısınız). İkinci bir varsayım, PyObject*'un NULL olmadığıdır.

(Bu, Cython'da derlenmek üzere sınanmıştır, ancak C++'da derlediğini veya düzgün çalıştığını sınamanın hiçbir yolu yoktur).


Düzenleme: Ben şimdi düzeltilmelidir referans sayımında hafif hata yapmış olduğunu fark etti.