- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试在 Cython 中返回一个结构数组。
// .pyx
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);
cdef class Detection:
# how do I "link" this to the struct defined above?
def __cinit__(self):
pass
def __dealloc__(self):
pass
def detect(width, height, frame):
return scan_frame(width, height, frame)
理想情况下,我想在 Python 代码中调用 detect
函数,并获取 Detection
对象的列表,其中 Detection
是一个包装器C 结构 apriltag_detection
的类,类型定义为 apriltag_detection_t
。
我收到以下编译错误:
tag36h11_detector.pyx:22:21: Cannot convert 'apriltag_detection_t *' to Python object
我在文档的任何地方都找不到关于返回指向结构或结构数组的指针的引用。
更新 3
// .h
typedef struct detection_payload {
int size;
apriltag_detection_t** detections;
} detection_payload_t;
我正在尝试将上述结构转换为包含 size
的 Python 对象和包含 apriltag_detection_t
对象的 Python 列表。
// .pyx
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":
cdef struct detection_payload:
int size
apriltag_detection_t** detections
ctypedef detection_payload detection_payload_t
detection_payload* scan_frame(int width, int height, uint8_t* data)
...
cdef class Detection:
cdef apriltag_detection* _d
def __cinit__(self):
self._d = NULL
cdef _setup(self, apriltag_detection* d):
self._d = d
def __dealloc__(self):
self._d = NULL
property id:
def __get__(self):
return self._d.id
property c:
def __get__(self):
return self._d.c
property p:
def __get__(self):
return self._d.p
cdef Detection_create(apriltag_detection_t* d):
return Detection()._setup(d)
cdef class DetectionPayload:
cdef detection_payload* _p
def __cinit__(self):
self._p = NULL
cdef _setup(self, detection_payload* p):
self._p = p
self.size = p.size
self.detections = []
for i in range(0, self.size):
apriltag_detection_t* detection = self._p.detections[i]
d = Detection_create(detection)
self.detections+=[d]
def __dealloc__(self):
_p = NULL
property size:
def __get__(self):
return self.size
property detections:
def __get__(self):
return self.detections
我在线上遇到了几个语法错误:
apriltag_detection_t* detection = self._p.detections[I]
具体来说,在指针apriltag_detection_t*
更新 2
现在可以正常编译和导入了。阵列方面仍然没有进展
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);
cdef class Detection:
cdef apriltag_detection* _d
def __cinit__(self):
self._d = NULL
cdef _setup(self, apriltag_detection* d):
self._d = d
def __dealloc__(self):
self._d = NULL
property id:
def __get__(self):
return self._d.id
property c:
def __get__(self):
return self._d.c
property p:
def __get__(self):
return self._d.p
cdef Detection_create(apriltag_detection_t* d):
return Detection()._setup(d)
def detect(width, height, frame):
cdef apriltag_detection_t* detection = scan_frame(width, height, frame)
return Detection_create(detection)
更新 1
我尝试按照下面链接的帖子进行操作,这就是我目前所做的。
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);
cdef class Detection:
cdef apriltag_detection* _d;
def __cinit__(self):
self._d = NULL
def _setup(self, apriltag_detection* d):
self._d = d
def __dealloc__(self):
self._d = NULL
property id:
def __get__(self):
return self._t.id
property c:
def __get__(self):
return self._t.c
property p:
def __get__(self):
return self._t.p
cdef Detection_create(apriltag_detection_t* d):
return Detection()._setup(d)
def detect(width, height, frame):
return <Detection>scan_frame(width, height, frame)
虽然这比我以前更接近,但我仍然收到错误:
tag36h11_detector.pyx:33:30: Cannot convert 'apriltag_detection_t *' to Python object
在线
cdef Detection_create(apriltag_detection_t* d):
return Detection()._setup(d)
此外,我不知道如何返回 Python 列表...
最佳答案
看来你的问题已经解决了,但我还是想回答这个问题。首先是因为我想尝试一下,其次是因为我认为您在内存管理方面存在一些问题,我想指出来。
我们将包装以下简单的 C 接口(interface):
//creator.h
typedef struct {
int mult;
int add;
} Result;
typedef struct {
int size;
Result *arr;
} ResultArray;
ResultArray create(int size, int *input){
//whole file at the end of the answer
}
它处理输入数组并返回结构的 C 数组以及该数组中的元素数。
我们包装的 pyx 文件如下所示:
#result_import.pyx (verion 0)
cdef extern from "creator.h":
ctypedef struct Result:
int mult
int add
ctypedef struct ResultArray:
int size
Result *arr
ResultArray create(int size, int *input)
def create_structs(int[::1] input_vals):
pass
最值得注意的部分:我使用内存 View (int[::1]
) 来传递我的输入数组,这有两个优点:
numpy
、array
自 Python3),这比使用 numpy 数组更灵活[::1]
)输入是连续的在测试脚本中我使用了 numpy,但也可以使用内置数组:
#test.py
import result_import
import numpy as np
a=np.array([1,2,3],dtype='int32')
result=result_import.create_structs(a)
for i,el in enumerate(result):
print i, ": mult:", el.mult, " add:", el.add
现在还没有任何效果,但一切都已准备就绪。
第一种情况:我们只想拥有普通的 python 对象,没什么特别的!一种可能性是:
#result_import.pyx (verion 1)
#from cpython cimport array needed for array.array in Python2
from libc.stdlib cimport free
....
class PyResult:
def __init__(self, mult, add):
self.mult=mult
self.add=add
def create_structs(int[::1] input_vals):
cdef ResultArray res=create(len(input_vals), &input_vals[0])
try:
lst=[]
for i in range(res.size):
lst.append(PyResult(res.arr[i].mult, res.arr[i].add))
finally:
free(res.arr)
return lst
我将整个数据转换为 python 对象并使用一个简单的列表。很简单,但是有两点值得注意:
try...finally
来确保即使抛出异常也会发生。NULL
是不够的,我必须调用 free
函数。现在我们的 test.py
工作了 - 太棒了!
第二种情况:但是,如果我只需要一些元素并将它们全部转换 - 效率很低。此外,我将所有元素保存在内存中两次(至少一段时间)——这是天真的方法的缺点。所以我想在程序后面的某个地方按需创建 PyResult
对象。
让我们写一个包装列表:
#result_import.pyx (verion 2)
...
cdef class WrappingList:
cdef int size
cdef Result *arr
def __cinit__(self):
self.size=0
self.arr=NULL
def __dealloc__(self):
free(self.arr)
print "deallocated"#just a check
def __getitem__(self, index):
if index<0 or index>=self.size:
raise IndexError("list index out of range")
return PyResult(self.arr[index].mult, self.arr[index].add)
def create_structs(int[::1] input_vals):
cdef ResultArray res=create(len(input_vals), &input_vals[0])
lst=WrappingList()
lst.size, lst.arr=res.size, res.arr
return lst
因此 WrappingList
类的行为很像一个列表,保留整个 C 数组而不进行复制,并且仅在需要时创建 PyResult
对象。值得一提的事情:
__dealloc__
在 WrapperingList
对象被销毁时调用 - 这是我们释放 C 代码提供给我们的内存的地方。在 test.py
的末尾,我们应该看到“deallocated”,否则就会出错...__getitem__
用于迭代。 第三种情况:Python 代码不仅要读取结果还要更改结果,这样更改后的数据才能传回 C 代码。为此,让我们将 PyResult
设为代理:
#result_import.pyx (verion 3, last)
...
cdef class PyResult:
cdef Result *ptr #ptr to my element
def __init__(self):
self.ptr=NULL
@property
def mult(self):
return self.ptr.mult
@mult.setter
def mult(self, value):
self.ptr.mult = value
@property
def add(self):
return self.ptr.add
@add.setter
def add(self, value):
self.ptr.add = value
cdef class WrappingList:
...
def __getitem__(self, index):
if index>=self.size:
raise IndexError("list index out of range")
res=PyResult()
res.ptr=&self.arr[index]
return res
现在,PyResult
对象持有指向相应元素的指针,可以直接在 C 数组中更改它。但是,有一些陷阱,我应该提到:
PyResult
的生命周期不应长于父对象-WrappingList
。您可以通过在 PyResult
类中添加对 parent 的引用来修复它。add
或mult
)的成本很高,因为每次都必须创建、注册然后删除一个新的 Python 对象。 让我们更改测试脚本,以查看正在运行的代理:
#test.py(second version)
import result_import
import numpy as np
a=np.array([1,2,3],dtype='int32')
result=result_import.create_structs(a)
for i,el in enumerate(result):
print i, ": mult:", el.mult, " add:", el.add
el.mult, el.add=42*i,21*i
# now print changed values:
for i,el in enumerate(result):
print i, ": mult:", el.mult, " add:", el.add
还有很多需要改进的地方,但我想一个答案就足够了:)
附件:
草率的 creator.h
- 需要检查 malloc
的结果:
//creator.h
typedef struct {
int mult;
int add;
} Result;
typedef struct {
int size;
Result *arr;
} ResultArray;
ResultArray create(int size, int *input){
ResultArray res;
res.size=size;
res.arr=(Result *)malloc(size*sizeof(Result));//todo: check !=0
for(int i=0;i<size;i++){
res.arr[i].mult=2*input[i];
res.arr[i].add=2+input[i];
}
return res;
}
设置.py:
from distutils.core import setup, Extension
from Cython.Build import cythonize
setup(ext_modules=cythonize(Extension(
name='result_import',
sources = ["result_import.pyx"]
)))
关于python - 在 Cython 中返回一个结构数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46515782/
c 不做边界检查。那么cython是如何检查是否编译成c的呢? %%cython --annotate cimport cython @cython.boundscheck(True) cpdef m
可以直接声明用于 Cython 构造函数? 据我了解,这是可能的: # Cython cdef int[3] li = [1, 2, 3] # C++ int[3] li = {1, 2, 3} 但
所以,如果你有一个头文件。 %%file test.h struct mystruct{ int i; int j; }; 然后你将它包装在 Cython 中: cdef extern fr
我正在构建一个独立于平台的 cython 项目,我想根据正在使用的编译器传递编译器参数。我可以猜测基于平台的编译器,或者假设它与用于 Python 的编译器相同,但不能保证匹配。通常我注入(injec
我使用诗歌构建我的 cython 包。我在所有函数和类中都有 NumPy 风格的文档字符串。我现在要做的是添加 Sphinx 自动文档并发布在 Read the Docs。 我已阅读此主题 How d
赛通 libcpp模块包含 priority_queue 的模板,这很好,除了一件事:我不能通过自定义比较器(或者,至少,我不知道如何)。 我需要这个,因为我需要 priority_queue做一个a
以下代码定义了一个简单的 Cython 函数(为方便起见,使用 Ipython 魔法)。 %load_ext cython %%cython def f(float x, float y=2):
我正在尝试使用 cython 进行复数计算。在示例代码中,我想计算复数的复指数函数。问题是我不知道如何将我的整数乘以虚数单位。python的虚数单位1.0j乘以cython执行时报错。 这是我的代码:
在这里停留在一些基本的 Cython 上 - 在 Cython 中定义字符串数组的规范且有效的方法是什么? 具体来说,我想定义一个定长常量数组char . (请注意,此时我不想引入 NumPy。) 在
是否有可能,如果是,如何确定 Cython 中整数数据类型的大小(以位为单位)? 我正在尝试做这样的事情,以获得整数大小: cdef WORD_BITS = 0 IF sizeof(unsigned
我只是想打印 cython 变量的地址,但我无法绕过错误消息: cdef int myvar print &myvar 抛出 Cannot convert 'int *' to Python obje
我有一个 C 头文件,它在宏中定义了一个函数。我需要从 Cython 调用它。有没有办法在 Cython 中使用宏并使其完全扩展?我已经有了 C 类型的参数。 我尝试像使用函数一样使用 cdef,我认
令人惊讶的是,我似乎找不到通过名称获取结构体元素的单个示例(无论是在网络上还是在 cython 示例中)。 所以我收到了一个指向 C 函数结构体的指针,并且想要一一访问这些元素并将它们重新打包到 py
我尝试围绕 C++ 库编写一个 Cython 包装器 http://primesieve.org/ 它包装了一个函数count。到目前为止,它可以正确安装 python setup.py instal
我正在尝试将 cython 模块 data.pyx 导入另一个 cython 模块 user.pyx。一切都编译得很好,但是当我尝试在 python 模块中调用 user.pyx 时,我收到错误“Im
更新:内存 View 获胜。Cython 使用类型化内存 View :0.0253449 特别感谢 lothario,他指出了几个关键的变化。 荒谬。当然现在的问题是,似乎不能对它们做太多算术(加法和
我有一个使用 memoryview 数组的 cython 模块,即... double[:,:] foo 我想使用多处理并行运行这个模块。但是我得到了错误: PicklingError: Can't
我正在尝试使用 Cython 加速 PEP 484 类型的 python 脚本。我想保持一些语义和可读性。 之前,我有一个 Flags = int def difference(f1: Flags,
这个问题已经有答案了: Collapse multiple submodules to one Cython extension (5 个回答) 已关闭 3 年前。 我在一个包中有多个 .py 文件
我已经能够在我的 .pyx 脚本上使用 cython 在 linux 上创建一个 .so 文件。我也可以成功地在我的 python 解释器上进行导入。 我的问题是如何在不使用 cython 的情况下将
我是一名优秀的程序员,十分优秀!