将一个numpy数组传递给Delphi dll

时间:2011-05-06 14:50:52

标签: python delphi dll multidimensional-array

我正在尝试在Python中实现图像分类算法。问题是python在循环数组时需要很长时间。这就是我决定编写执行数组处理的Delphi dll的原因。我的问题是我不知道如何将多维python数组传递给我的dll函数。

Delphi dll提取:(我只使用此功能进行测试)

type
    TImgArray = array of array of Integer;

function count(a: TImgArray): Integer; cdecl;
begin
    result:= high(a);
end;

相关的Python代码:

arraydll = cdll.LoadLibrary("C:\\ArrayFunctions.dll")

c_int_p = ctypes.POINTER(ctypes.c_int32)
data = valBD.ReadAsArray()
data = data.astype(np.int32)
data_p = data.ctypes.data_as(c_int_p)

print arraydll.count(data_p)

dll-function返回的值不是正确的值(它是2816而不是  7339)。这就是为什么我猜我的类型转换有些不对劲:( 提前致谢, 马里奥

2 个答案:

答案 0 :(得分:1)

你正在做的事情不起作用,也可能会破坏记忆。

Delphi动态数组作为一种数据结构实现,它包含有关数组的一些元数据,包括长度。但是你传递给它的是一个C风格的指针作为数组,它是一个指针,而不是Delphi动态数组数据结构。该结构特定于Delphi,您不能在其他语言中使用它。 (即使你确实设法用另一种语言实现完全相同的结构,你仍然无法将它传递给Delphi DLL并使其工作正常,因为Delphi的内存管理器涉及到底层。这样做就是问用于内存管理器引发的堆损坏和/或异常。)

如果要将C样式数组传递给DLL,则必须通过传递包含数组长度的第二个参数来执行C方式。你的Python代码应该已经知道了它的长度,它不应该花费任何时间来计算它。你绝对可以使用Delphi来加速图像处理。但是数组维度必须来自Python方面。你可以在这里找到捷径。

您的Delphi函数声明应如下所示:

type
  TImgArray = array[0..MAXINT] of Integer;
  PImgArray = ^TImgArray;

function ProcessSomething(a: PImgArray; size: integer): Integer; cdecl;

答案 1 :(得分:1)

普通Python数组通常称为“列表”。 Python中的numpy.array类型是一种特殊类型,它比普通Python浮点对象的普通Python列表更具内存效率。 Numpy.array包装一个标准的内存块,作为本机C数组类型访问。反过来,它不会干净地映射到Delphi数组类型。

正如大卫所说,如果你愿意使用C,这将更容易。如果你想使用Delphi并访问Numpy.array,我怀疑最简单的方法是找到一种方法来导出一些访问Numpy.array类型的简单C函数。在C中,我将导入numpy标头,然后编写我可以从Pascal调用的函数。然后我会从DLL导入这些函数:

function GetNumpyArrayValue( arrayObj:Pointer;  index:Integer):Double;

我有一段时间没有编写任何CPython包装器代码。如果您只想从Delphi访问CORE PYTHON类型,这将更容易。现有的Python-for-delphi包装器将为您提供帮助。将numpy与Delphi结合起来只需要做更多的工作。

由于你只是在编写一个DLL而不是整个应用程序,我会认真地建议你忘记Delphi并用简单的C编写这个小狗,这就是Python扩展(你正在编写的)真的应该是写的。

简而言之,既然你正在编写一个DLL,在Pascal中,你将需要至少另一个C中的小DLL,只是为了桥接Python扩展类型(numpy.array)和Python浮动之间的类型点值。即使这样,你也不会轻易(快速)获得一个你可以在Delphi中读取的数组值作为本机delphi数组类型。

我能想到的最快的访问机制是:

type
   PDouble = ^Double;

function GetNumpyArrayValue( arrayObj:Pointer; var doubleVector:PDouble; var doubleVectorLen:Integer):Boolean;

然后,您可以使用doubleVector(指针)类型数学来访问底层C数组内存类型。