我试图在Cython中调用一个C函数,头看起来是这样的:

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

如您所见,我想返回一个结构数组,其类型定义为apriltag_detection_t。根据documentation,为了能够在Cython中使用它,我必须定义某种pxd文件,它本质上是头的副本。
但是,apriltag_detection_t是已经在apriltag.h中定义的类型。此外,apriltag_detection_t具有已在apriltag.h中定义的成员。在使用这个库之前,我必须递归地重新定义Cython文件中的所有这些类型吗?我要把它们写在哪里?
谢谢!
更新6
最后在包装函数的步骤!
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:无法将“aprltag_detection_t*”转换为Python对象
apriltag_detection_t*应该是一个结构数组
更新5
这似乎奏效了。
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);

更新4
通过导入必要的类型解决了前面的问题。
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:致命错误:找不到“apriltag.h”文件
我不确定这是从哪里来的,因为我的头文件,如在原始文章中提供的,需要<apriltag.h>而不是"apriltag.h"。这就是我的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"])))

更新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”不是类型标识符
更新2
这是我当前的代码,下面是编译错误
// 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:ctypedef语句语法错误
更新1
所以我试图用Python(我编写并实现的)和apriltag.h中定义的类型(从库中)来连接上面的头文件。
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);

当我尝试编译上面的代码时,我得到
tag36h11_detector.pyx:8:29:结构或联合定义中的语法错误

最佳答案

这基本上包含在this part of cython documentation中,它表示您只需要导入将在cython代码中使用的部件。
例如,让我们看看下面的C接口:

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

struct NotNeeded{
  int b;
};

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

struct Combined create(void);

您希望调用函数create并使用a结构中的值Needed,这意味着您必须在cython代码中导入struct Neededstruct Combined的一部分,而不是NotNeeded
#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!

现在,使用setup.py(其内容可以在下面进一步看到,对于struct.cto的内容也是如此)我们得到了预期的结果:
[] python setup.py build_ext --inplace
[] python -c "python -c "import struct_import as si; print si.get_needed()"
    42

如果你用cython把一些C代码粘在一起,这是可能的,甚至是不必要的。在oour示例中,如果我们有一个C函数,它将从Combined结构中提取所需的值:
#struct.h
...
int extract(struct Combined combined);//returns combined.needed.a

我们可以在pyx文件中按如下方式使用它:
#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!

尽管我们根本没有导入Needed结构,但它的工作原理与第一个版本一样好。
因此,如果导入所有这些结构成为一项繁重的工作,那么可以扩展c接口,使其成为不必要的。
为了使示例完整,这里缺少setup.py和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"]
    )))


//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;
}

09-28 11:43