【问题标题】:Passing a numpy array to Delphi dll将一个numpy数组传递给Delphi dll
【发布时间】:2011-05-06 14:50:52
【问题描述】:

我正在尝试在 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 函数返回的值不正确(它是 2816 而不是 7339)。这就是为什么我猜我的类型转换有问题:( 提前致谢, 马里奥

【问题讨论】:

  • numpy 数据将是单个值数组。形状由其他元数据确定。试图将其直接映射到 Delphi 动态数组注定要失败。我认为在您的位置上,我会考虑使用 Cython,它可以让您以自然的方式使用 numpy 数组。
  • 简而言之,我同意大卫的观点,也就是说,用 C 语言编写它。我在回答中对大卫的观点进行了扩展。

标签: python delphi dll multidimensional-array


【解决方案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;

【讨论】:

  • 坦克很多。现在我对 Delphi 和 Arrays 有了更多的了解。不过,我会按照您的建议使用 C/C++ 进行尝试。这就是我在系统上安装 gcc 的原因。也许有人想给我一个提示如何以正确的方式去做(哪种 c 变量......)
  • @martwig:我并不是真的要在 C 中做这件事。只是您需要在 Delphi 代码中遵循 C 数组传递约定。 :P
【解决方案2】:

普通的 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 扩展(这是您正在编写的)真正应该的写的。

简而言之,由于您正在使用 Pascal 编写 DLL,因此您至少需要另一个 C 中的小 DLL,只是为了在 Python 扩展类型 (numpy.array) 和 Python 浮动类型之间架起桥梁点值。即使这样,您也不会轻易(快速)获得可以在 Delphi 中作为原生 delphi 数组类型读取的数组值。

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

type
   PDouble = ^Double;

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多