python - 在 Cython 中使用来自不同库的结构

标签 python c struct cython

我正在尝试在 Cython 中调用 C 函数, header 如下所示:

#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文件,本质上是 header 的副本。

然而,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: Cannot convert 'apriltag_detection_t *' to Python object

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: fatal error: 'apriltag.h' file not found

我不确定这是从哪里来的,因为我的头文件(如原始帖子中提供的那样)需要 <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' is not a type identifier

更新 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: Syntax error in ctypedef statement

更新 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: Syntax error in struct or union definition

最佳答案

这基本上涵盖在this part of cython documentation中,它表示您只需要导入将在您的 cython 代码中使用的部件。

例如让我们看一下下面的 C 接口(interface):

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

struct NotNeeded{
  int b;
};

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

struct Combined create(void);

您想调用函数 create 并使用 Needed 结构中的值 a,这意味着您必须导入 struct Needed 和部分 struct Combined 但不是 NotNeeded 在你的 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!

现在,使用setup.py(其内容见下文,struct.c的内容也是如此)我们得到了预期的结果:

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

如果你用cython把一些C代码粘合在一起,这是可能的,甚至更少。在我们的示例中,如果我们有一个 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 接口(interface)以使其变得不必要。


为了使示例完整,这里缺少 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;
}

关于python - 在 Cython 中使用来自不同库的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46509558/

相关文章:

python - 在哪里为 Django 项目设置 Python 环境属性?

c - 结构中的结构定义

c - 返回 C 中带有 const 数组的结构体

c - 为什么在文件范围内初始化枚举类型变量时出现错误?

c++ - 在模板中使用 typedef 结构

java - : "Python For Else Loop" in Java 的高效实现

java - 如何以与 setLength 属性类似的方式在 python 中设置字符串的固定长度 java

struct - 如何创建不同类型的结构体数组的数组?

Python 3 无法pickle lambda

c++ - 具有结构 vector 的类,其中包含相同的类