【发布时间】:2016-10-22 09:18:43
【问题描述】:
如何将 3D python 数组传递给 C 代码然后返回? 我研究过,
我尝试过 2D
test1.py
import numpy as np
import numpy.ctypeslib as npct
from numpy.ctypeslib import ndpointer
import ctypes
import sys
import time
_doublepp = ndpointer(dtype=np.uintp, ndim=2, flags='C')
_dll = ctypes.CDLL("foo_test.dll")
_foobar = _dll.foobar
_foobar.argtypes = [ctypes.c_int, ctypes.c_int, _doublepp, _doublepp]
_foobar.restype = None
def foobar(x):
y = np.zeros_like(x)
print x.__array_interface__
print x.shape[0]
print x.strides
xpp = (x.__array_interface__['data'][0]
+ np.arange(x.shape[0])*x.strides[0]).astype(np.uintp)
ypp = (y.__array_interface__['data'][0]
+ np.arange(y.shape[0])*y.strides[0]).astype(np.uintp)
print xpp
print ypp
m = ctypes.c_int(x.shape[0])
n = ctypes.c_int(x.shape[1])
o = ctypes.c_int(x.shape[2])
_foobar(m, n, o, xpp, ypp)
return y
if __name__ == '__main__':
n = sys.argv[1]
n = float(n)
dim = np.sqrt(n)
s1=time.clock()
x = np.arange(n).reshape((3,3,3))
# x = np.arange(9).reshape((3,3))
y = foobar(x)
f1 = time.clock()
print 'Execution Time is ', f1-s1, ' Second'
print y[:]
foo_test.c
#include <stdio.h>
#include <stdlib.h>
#ifdef FOO_DLL
#ifdef FOO_EXPORTS
#define FOO_API __declspec(dllexport)
#else
#define FOO_API __declspec(dllimport)
#endif //For FOO_Export
#else
#define FOO_API extern
#endif //for FOO_DLL
#ifdef __cplusplus
extern "C" {
#endif
// http://cboard.cprogramming.com/c-programming/61578-4-dimensional-array-contiguous-allocation.html#post438210
void* my_malloc(char *expr, size_t size)
{
void* result = malloc(size);
printf("Malloc (%s) is size %lu, resulting %p\n", expr, (unsigned long)size, result );
return result;
}
void my_free(void* ptr)
{
printf("Freeing : %p\n", ptr);
free(ptr);
}
#define MY_MALLOC(x) my_malloc(#x, x)
#define MY_FREE(x) my_free(x)
//Create float 2D
float **array2D(int dimx, int dimy)
{
float **allx = MY_MALLOC(dimx * sizeof *allx);
float *ally = MY_MALLOC(dimx * dimy * sizeof *ally);
float **result = allx;
int x;
for(x = 0; x < dimx ; x++, ally += dimy)
{
result[x] = ally;
}
return result;
}
//create float 3D
float ***array3D(int dimx, int dimy, int dimz)
{
float ***allx = MY_MALLOC(dimx * sizeof *allx);
float **ally = MY_MALLOC(dimx * dimy * sizeof *ally);
float *allz = MY_MALLOC(dimx * dimy * dimz * sizeof *allz);
float ***result = allx;
int x, y;
for(x = 0; x < dimx ; x++, ally += dimy)
{
result[x] = ally;
for (y = 0; y <dimy ; y++, allz += dimz)
{
result[x][y] = allz;
}
}
return result;
}
void foobar(const int m, const int n, const int o, const double*** x, double*** y)
{
float ***array3d;
// int x, y;
array3d = array3D(m,n,o);
size_t i,j,k;
for(i = 0; i< m; i++)
{
for(j = 0; j < n; j++)
{
for(k = 0; k < o; k++)
{
array3d[i][j][k] = 5.0;
y[i][j][k] = array3d[i][j][k];
}
}
}
}
#ifdef __cplusplus
}
#endif
错误说,
Traceback(最近一次调用最后一次):文件“test1.py”,第 40 行,在 y = foobar(x) 文件“test1.py”,第 30 行,在 foobar 中 _foobar(m, n, o, xpp, ypp) ctypes.ArgumentError: argument 3: : argument must be an ndarray
【问题讨论】:
-
您是否考虑过使用 Cython 通过 C 代码与您的 numpy 数组交互。参见例如this question。
-
昨天读过。它仅适用于二维数组。我不知道用它来传递 3D 数组,Evert。我是 Python 编程的新手。顺便说一句,感谢您的回复。
-
从
cdef np.ndarray[double,mode="c",ndim=2] array2d和&array2d[0,0]到使用np.ndarray[double,mode="c",ndim=3] array3d并通过&array3d[0,0,0]真的不会那么复杂。 -
还可以查看 cython Github wiki 上的 numpy pointer to C。
-
好的,我会试试的。我稍后会发布我的结果。