2017-10-01 7 views
1

Je suis en train d'appeler une fonction C dans Cython et l'en-tête ressemble à ceci:L'utilisation d'un struct à partir d'une autre bibliothèque dans Cython

#include <stdio.h> 
#include <stdint.h> 
#include <inttypes.h> 
#include <ctype.h> 
#include <unistd.h> 
#include <math.h> 

#include <apriltag.h> 
#include <tag36h11.h> 

#include <common/getopt.h> 
#include <common/image_u8.h> 
#include <common/image_u8x4.h> 
#include <common/pjpeg.h> 
#include <common/zarray.h> 

apriltag_detection_t* scan_frame(int width, int height, uint8_t* data); 

Comme vous pouvez le voir, je veux retourner un tableau de struct, qui sont définis comme étant apriltag_detection_t. Selon le documentation, afin de pouvoir l'utiliser dans Cython, je dois définir une sorte de fichier pxd qui est essentiellement une copie de l'en-tête. Cependant, apriltag_detection_t est un type déjà défini dans apriltag.h. En outre, apriltag_detection_t a des membres qui sont déjà définis dans apriltag.h. Dois-je redéfinir récursivement tous ces types (à la main) dans le fichier Cython avant de pouvoir utiliser cette bibliothèque? Où les écrirais-je?

Merci!

UPDATE 6

Enfin, à l'étape d'enroulement d'une fonction!

from libc.stdint cimport uint8_t 

cdef extern from "<apriltag.h>": 
    cdef struct apriltag_detection: 
     int id 
     double c[2] 
     double p[4][2] 

    ctypedef apriltag_detection apriltag_detection_t 

cdef extern from "tag36h11_detector/tag36h11_detector.h": 
    apriltag_detection_t* scan_frame(int width, int height, uint8_t* data); 

def detect(width, height, frame): 
    return scan_frame(width, height, frame) 

tag36h11_detector.pyx:15:21: Cannot convert 'apriltag_detection_t *' to Python object

apriltag_detection_t* est destiné à être un tableau de struct

MISE À JOUR 5 Cela semble avoir fonctionné.

from libc.stdint cimport uint8_t 

cdef extern from "<apriltag.h>": 
    cdef struct apriltag_detection: 
     int id 
     double c[2] 
     double p[4][2] 

    ctypedef apriltag_detection apriltag_detection_t 

cdef extern from "tag36h11_detector/tag36h11_detector.h": 
    apriltag_detection_t* scan_frame(int width, int height, uint8_t* data); 

MISE A JOUR 4 Résolu les numéros précédents en important les types nécessaires.

from libc.stdint cimport uint8_t 

cdef extern from "apriltag.h": 
    cdef struct apriltag_detection: 
     int id 
     double c[2] 
     double p[4][2] 

    ctypedef apriltag_detection apriltag_detection_t 

cdef extern from "tag36h11_detector.h": 
    apriltag_detection_t* scan_frame(int width, int height, uint8_t* data); 

tag36h11_detector.c:533:10: fatal error: 'apriltag.h' file not found

Je ne sais pas où cela vient parce que mon fichier d'en-tête, comme il est prévu dans le message original, nécessaire <apriltag.h> et non "apriltag.h". C'est à quoi ressemble mon setup.py.

from distutils.core import setup, Extension 
from Cython.Build import cythonize 

setup(ext_modules=cythonize(Extension(\ 
    name='tag36h11_detector', \ 
    sources=["tag36h11_detector.pyx", \ 
    "tag36h11_detector/tag36h11_detector.c"], \ 
    include_path=["/usr/local/include/apriltag"], \ 
    libraries=["apriltag"]))) 

MISE A JOUR 3

cdef extern from "apriltag.h": 
    cdef struct apriltag_detection: 
     int id 
     double c[2] 
     double p[4][2] 

    ctypedef apriltag_detection apriltag_detection_t 

cdef extern from "tag36h11_detector.h": 
    apriltag_detection_t* scan_frame(int width, int height, uint8_t* data); 

tag36h11_detector.pyx:10:60: 'uint8_t' is not a type identifier

MISE À JOUR 2

Ceci est mon code actuel et ce qui suit est l'erreur de compilation

// tag36h11_detector.pyx 
cdef extern from "apriltag.h": 
    ctypedef apriltag_detection_t: 
     int id 
     double c[2] 
     double p[4][2] 

cdef extern from "tag36h11_detector.h": 
    apriltag_detection_t* scan_frame(int width, int height, uint8_t* data); 

// apriltag.h 
    ... 
    typedef struct apriltag_detector apriltag_detector_t; 
    ... 

tag36h11_detector.pyx:2:33: Syntax error in ctypedef statement

MISE À JOUR 1

Je suis en train de l'interface avec le fichier d'en-tête ci-dessus avec Python (que j'ai écrit et mis en œuvre) avec des types définis dans apriltag.h (à partir d'une bibliothèque).

cdef extern from "apriltag.h": 
    struct apriltag_detection: 
     int id 
     double c[2] 
     double p[4][2] 

cdef extern from "tag36h11_detector.h": 
    struct apriltag_detection* scan_frame(int width, int height, uint8_t* data); 

Lorsque je tente de compiler ce qui précède, je reçois

tag36h11_detector.pyx:8:29: Syntax error in struct or union definition

+0

Pour votre question mise à jour, avez-vous essayé de définir les struct comme 'ctypedef struct apriltag_detection' à la place dans votre fichier pxd? – CodeSurgeon

+0

@CodeSurgeon même erreur. Aussi, j'ai écrit tout ce qui précède sur un fichier '.pyx', comme l'indique la réponse ci-dessous. – Carpetfizz

+0

Je pense que vous n'avez pas besoin de "struct" avant "apriltag_detection" dans la dernière ligne Voir aussi la façon dont la fonction est importée dans l'exemple – ead

Répondre

3

Ceci est essentiellement couvert de this part of cython documentation, qui dit que vous avez seulement besoin d'importer des pièces, que vous utiliserez dans votre code cython.

Par exemple, nous allons jeter un oeil à l'interface C suivante:

#struct.h 
struct Needed{ 
    int a; 
}; 

struct NotNeeded{ 
    int b; 
}; 

struct Combined{ 
    struct Needed needed; 
    struct NotNeeded notneeded; 
}; 

struct Combined create(void); 

Vous souhaitez appeler la fonction create et utiliser la valeur a de la struct Needed, cela signifie que vous devez importer struct Needed et pièces de struct Combined mais pas NotNeeded dans votre code cython:

#struct_import.pyx 
cdef extern from "struct.h": 
    struct Needed: # use "ctypedef struct Needed" if defined with typedef in h-file! 
      int a 
    struct Combined: #NotNeeded is missing! 
      Needed needed 
    Combined create() 

def get_needed(): 
    return create().needed.a #should be 42! 

maintenant, en utilisant setup.py (son contenu peut être vu plus loin, la même chose pour le contenu de struct.c à) nous obtenons le résultat escompté:

[] python setup.py build_ext --inplace 
[] python -c "python -c "import struct_import as si; print si.get_needed()" 
    42 

Si vous utilisez cython pour coller du code C ensemble, il est possible, encore moins est nécessaire. Dans oour exemple, si nous avions une fonction C qui serait d'extraire la valeur nécessaire de la struct Combined:

#struct.h 
... 
int extract(struct Combined combined);//returns combined.needed.a 

Nous pourrions l'utiliser comme suit dans le ciboire fichier:

#struct_import.pyx 
cdef extern from "struct.h": 
    struct Combined: 
      pass #nothing imported! 
    Combined create() 
    int extract(Combined combined) 

def get_needed(): 
    return extract(create()) #should be 42! 

Et malgré nous n'avons pas importé la structure Needed, cela fonctionne aussi bien que la première version. Donc, si cela devient une corvée d'importer toutes ces structures, on pourrait étendre l'interface c pour le rendre inutile.


Pour l'exemple complet, voici les setup.py fichiers manquants et struct.c:

#setup.py: 
from distutils.core import setup, Extension 
from Cython.Build import cythonize 

setup(ext_modules=cythonize(Extension(
      name='struct_import', 
      sources = ["struct_import.pyx", "struct.c"] 
    ))) 

et

//struct.c 
#include "struct.h" 

struct Combined create(){ 
    struct Combined res; 
    res.needed.a=42; 
    res.notneeded.b=21; 
    return res; 
} 

int extract(struct Combined combined){ 
    return combined.needed.a; 
} 
+0

Merci beaucoup pour votre réponse, c'est beaucoup plus clair que les docs. J'ai posté une mise à jour dans mon OP – Carpetfizz

+0

En passant, je lisais [ces] docs (http://cython.readthedocs.io/en/latest/src/tutorial/clibraries.html). Comment sont-ils différents de ceux que vous avez référencés (dans le but) – Carpetfizz

+0

Je pense que je suis sur la dernière étape. Ayant quelques problèmes d'importation, j'ai mis à jour le OP – Carpetfizz